From 375af57fcacff30f3052bd02d2b7b6163bda1213 Mon Sep 17 00:00:00 2001 From: tombuildsstuff Date: Thu, 15 Mar 2018 21:02:27 -0500 Subject: [PATCH 1/3] Adding support for Geographic Traffic Routing --- .../resource_arm_traffic_manager_profile.go | 3 +- ...source_arm_traffic_manager_profile_test.go | 47 +++++++++++++++++++ .../r/traffic_manager_profile.html.markdown | 14 +++--- 3 files changed, 56 insertions(+), 8 deletions(-) diff --git a/azurerm/resource_arm_traffic_manager_profile.go b/azurerm/resource_arm_traffic_manager_profile.go index f80c45d12b84..bc04ff5a43d3 100644 --- a/azurerm/resource_arm_traffic_manager_profile.go +++ b/azurerm/resource_arm_traffic_manager_profile.go @@ -47,8 +47,9 @@ func resourceArmTrafficManagerProfile() *schema.Resource { Type: schema.TypeString, Required: true, ValidateFunc: validation.StringInSlice([]string{ - string(trafficmanager.Performance), + string(trafficmanager.Geographic), string(trafficmanager.Weighted), + string(trafficmanager.Performance), string(trafficmanager.Priority), }, false), }, diff --git a/azurerm/resource_arm_traffic_manager_profile_test.go b/azurerm/resource_arm_traffic_manager_profile_test.go index 644202e3d7e0..e251fe18f5c0 100644 --- a/azurerm/resource_arm_traffic_manager_profile_test.go +++ b/azurerm/resource_arm_traffic_manager_profile_test.go @@ -20,6 +20,27 @@ func getTrafficManagerFQDN(hostname string) (string, error) { return fmt.Sprintf("%s.%s", hostname, dnsSuffix), nil } +func TestAccAzureRMTrafficManagerProfile_geographic(t *testing.T) { + resourceName := "azurerm_traffic_manager_profile.test" + ri := acctest.RandInt() + config := testAccAzureRMTrafficManagerProfile_geographic(ri, testLocation()) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testCheckAzureRMTrafficManagerProfileDestroy, + Steps: []resource.TestStep{ + { + Config: config, + Check: resource.ComposeTestCheckFunc( + testCheckAzureRMTrafficManagerProfileExists(resourceName), + resource.TestCheckResourceAttr(resourceName, "traffic_routing_method", "Geographic"), + ), + }, + }, + }) +} + func TestAccAzureRMTrafficManagerProfile_weighted(t *testing.T) { resourceName := "azurerm_traffic_manager_profile.test" ri := acctest.RandInt() @@ -216,6 +237,32 @@ func testCheckAzureRMTrafficManagerProfileDestroy(s *terraform.State) error { return nil } +func testAccAzureRMTrafficManagerProfile_geographic(rInt int, location string) string { + return fmt.Sprintf(` +resource "azurerm_resource_group" "test" { + name = "acctestRG-%d" + location = "%s" +} + +resource "azurerm_traffic_manager_profile" "test" { + name = "acctesttmp%d" + resource_group_name = "${azurerm_resource_group.test.name}" + traffic_routing_method = "Geographic" + + dns_config { + relative_name = "acctesttmp%d" + ttl = 30 + } + + monitor_config { + protocol = "https" + port = 443 + path = "/" + } +} +`, rInt, location, rInt, rInt) +} + func testAccAzureRMTrafficManagerProfile_weighted(rInt int, location string) string { return fmt.Sprintf(` resource "azurerm_resource_group" "test" { diff --git a/website/docs/r/traffic_manager_profile.html.markdown b/website/docs/r/traffic_manager_profile.html.markdown index ca5d52196c8a..967d655f0a91 100644 --- a/website/docs/r/traffic_manager_profile.html.markdown +++ b/website/docs/r/traffic_manager_profile.html.markdown @@ -4,9 +4,10 @@ page_title: "Azure Resource Manager: azurerm_traffic_manager_profile" sidebar_current: "docs-azurerm-resource-network-traffic-manager-profile" description: |- Creates a Traffic Manager Profile. + --- -# azurerm\_traffic\_manager\_profile +# azurerm_traffic_manager_profile Creates a Traffic Manager Profile to which multiple endpoints can be attached. @@ -63,11 +64,10 @@ The following arguments are supported: * `traffic_routing_method` - (Required) Specifies the algorithm used to route traffic, possible values are: - - `Performance`- Traffic is routed via the User's closest Endpoint - - `Weighted` - Traffic is spread across Endpoints proportional to their - `weight` value. - - `Priority` - Traffic is routed to the Endpoint with the lowest - `priority` value. + - `Geographic` - Traffic is routed based on Geographic regions specified in the Endpoint. + - `Performance` - Traffic is routed via the User's closest Endpoint + - `Weighted` - Traffic is spread across Endpoints proportional to their `weight` value. + - `Priority` - Traffic is routed to the Endpoint with the lowest `priority` value. * `dns_config` - (Required) This block specifies the DNS configuration of the Profile, it supports the fields documented below. @@ -89,7 +89,7 @@ The `dns_config` block supports: The `monitor_config` block supports: * `protocol` - (Required) The protocol used by the monitoring checks, supported - values are `HTTP`, `HTTPS` and `TCP``. + values are `HTTP`, `HTTPS` and `TCP`. * `port` - (Required) The port number used by the monitoring checks. From de272d78a553acf21823d3673ced28edb81761fd Mon Sep 17 00:00:00 2001 From: tombuildsstuff Date: Thu, 15 Mar 2018 22:09:40 -0500 Subject: [PATCH 2/3] Adding support for geo mappings ``` $ acctests azurerm TestAccAzureRMTrafficManagerEndpoint_withGeoMappings === RUN TestAccAzureRMTrafficManagerEndpoint_withGeoMappings --- PASS: TestAccAzureRMTrafficManagerEndpoint_withGeoMappings (89.34s) PASS ok github.com/terraform-providers/terraform-provider-azurerm/azurerm 89.373s ``` --- .../resource_arm_traffic_manager_endpoint.go | 91 +++++++------- ...ource_arm_traffic_manager_endpoint_test.go | 112 ++++++++++++++++++ .../r/traffic_manager_endpoint.html.markdown | 6 +- 3 files changed, 167 insertions(+), 42 deletions(-) diff --git a/azurerm/resource_arm_traffic_manager_endpoint.go b/azurerm/resource_arm_traffic_manager_endpoint.go index a59a398a891f..5f0e43c4d4b2 100644 --- a/azurerm/resource_arm_traffic_manager_endpoint.go +++ b/azurerm/resource_arm_traffic_manager_endpoint.go @@ -28,6 +28,14 @@ func resourceArmTrafficManagerEndpoint() *schema.Resource { ForceNew: true, }, + "profile_name": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + }, + + "resource_group_name": resourceGroupNameDiffSuppressSchema(), + "type": { Type: schema.TypeString, Required: true, @@ -39,12 +47,6 @@ func resourceArmTrafficManagerEndpoint() *schema.Resource { }, false), }, - "profile_name": { - Type: schema.TypeString, - Required: true, - ForceNew: true, - }, - "target": { Type: schema.TypeString, Optional: true, @@ -96,7 +98,11 @@ func resourceArmTrafficManagerEndpoint() *schema.Resource { Optional: true, }, - "resource_group_name": resourceGroupNameDiffSuppressSchema(), + "geo_mappings": { + Type: schema.TypeList, + Elem: &schema.Schema{Type: schema.TypeString}, + Optional: true, + }, }, } } @@ -104,13 +110,13 @@ func resourceArmTrafficManagerEndpoint() *schema.Resource { func resourceArmTrafficManagerEndpointCreate(d *schema.ResourceData, meta interface{}) error { client := meta.(*ArmClient).trafficManagerEndpointsClient - log.Printf("[INFO] preparing arguments for ARM TrafficManager Endpoint creation.") + log.Printf("[INFO] preparing arguments for TrafficManager Endpoint creation.") name := d.Get("name").(string) endpointType := d.Get("type").(string) fullEndpointType := fmt.Sprintf("Microsoft.Network/TrafficManagerProfiles/%s", endpointType) profileName := d.Get("profile_name").(string) - resGroup := d.Get("resource_group_name").(string) + resourceGroup := d.Get("resource_group_name").(string) params := trafficmanager.Endpoint{ Name: &name, @@ -119,17 +125,17 @@ func resourceArmTrafficManagerEndpointCreate(d *schema.ResourceData, meta interf } ctx := meta.(*ArmClient).StopContext - _, err := client.CreateOrUpdate(ctx, resGroup, profileName, endpointType, name, params) + _, err := client.CreateOrUpdate(ctx, resourceGroup, profileName, endpointType, name, params) if err != nil { return err } - read, err := client.Get(ctx, resGroup, profileName, endpointType, name) + read, err := client.Get(ctx, resourceGroup, profileName, endpointType, name) if err != nil { return err } if read.ID == nil { - return fmt.Errorf("Cannot read TrafficManager endpoint %s (resource group %s) ID", name, resGroup) + return fmt.Errorf("Cannot read Traffic Manager Endpoint %q (Resource Group %q) ID", name, resourceGroup) } d.SetId(*read.ID) @@ -155,8 +161,6 @@ func resourceArmTrafficManagerEndpointRead(d *schema.ResourceData, meta interfac } } profileName := id.Path["trafficManagerProfiles"] - - // endpoint name is keyed by endpoint type in ARM ID name := id.Path[endpointType] ctx := meta.(*ArmClient).StopContext @@ -166,23 +170,25 @@ func resourceArmTrafficManagerEndpointRead(d *schema.ResourceData, meta interfac d.SetId("") return nil } - return fmt.Errorf("Error making Read request on TrafficManager Endpoint %s: %+v", name, err) + return fmt.Errorf("Error making Read request on TrafficManager Endpoint %q (Resource Group %q): %+v", name, resGroup, err) } - endpoint := *resp.EndpointProperties - d.Set("resource_group_name", resGroup) d.Set("name", resp.Name) d.Set("type", endpointType) d.Set("profile_name", profileName) - d.Set("endpoint_status", string(endpoint.EndpointStatus)) - d.Set("target_resource_id", endpoint.TargetResourceID) - d.Set("target", endpoint.Target) - d.Set("weight", endpoint.Weight) - d.Set("priority", endpoint.Priority) - d.Set("endpoint_location", endpoint.EndpointLocation) - d.Set("endpoint_monitor_status", endpoint.EndpointMonitorStatus) - d.Set("min_child_endpoints", endpoint.MinChildEndpoints) + + if props := resp.EndpointProperties; props != nil { + d.Set("endpoint_status", string(props.EndpointStatus)) + d.Set("target_resource_id", props.TargetResourceID) + d.Set("target", props.Target) + d.Set("weight", props.Weight) + d.Set("priority", props.Priority) + d.Set("endpoint_location", props.EndpointLocation) + d.Set("endpoint_monitor_status", props.EndpointMonitorStatus) + d.Set("min_child_endpoints", props.MinChildEndpoints) + d.Set("geo_mappings", props.GeoMapping) + } return nil } @@ -214,32 +220,37 @@ func resourceArmTrafficManagerEndpointDelete(d *schema.ResourceData, meta interf } func getArmTrafficManagerEndpointProperties(d *schema.ResourceData) *trafficmanager.EndpointProperties { - var endpointProps trafficmanager.EndpointProperties + target := d.Get("target").(string) + status := d.Get("endpoint_status").(string) - if targetResID := d.Get("target_resource_id").(string); targetResID != "" { - endpointProps.TargetResourceID = &targetResID + endpointProps := trafficmanager.EndpointProperties{ + Target: &target, + EndpointStatus: trafficmanager.EndpointStatus(status), } - if target := d.Get("target").(string); target != "" { - endpointProps.Target = &target + if resourceId := d.Get("target_resource_id").(string); resourceId != "" { + endpointProps.TargetResourceID = utils.String(resourceId) } - if status := d.Get("endpoint_status").(string); status != "" { - endpointProps.EndpointStatus = trafficmanager.EndpointStatus(status) + if location := d.Get("endpoint_location").(string); location != "" { + endpointProps.EndpointLocation = utils.String(location) } - if weight := d.Get("weight").(int); weight != 0 { - w64 := int64(weight) - endpointProps.Weight = &w64 + inputMappings := d.Get("geo_mappings").([]interface{}) + geoMappings := make([]string, 0) + for _, v := range inputMappings { + geoMappings = append(geoMappings, v.(string)) + } + if len(geoMappings) > 0 { + endpointProps.GeoMapping = &geoMappings } - if priority := d.Get("priority").(int); priority != 0 { - p64 := int64(priority) - endpointProps.Priority = &p64 + if weight := d.Get("weight").(int); weight != 0 { + endpointProps.Weight = utils.Int64(int64(weight)) } - if location := d.Get("endpoint_location").(string); location != "" { - endpointProps.EndpointLocation = &location + if priority := d.Get("priority").(int); priority != 0 { + endpointProps.Priority = utils.Int64(int64(priority)) } if minChildEndpoints := d.Get("min_child_endpoints").(int); minChildEndpoints != 0 { diff --git a/azurerm/resource_arm_traffic_manager_endpoint_test.go b/azurerm/resource_arm_traffic_manager_endpoint_test.go index 56a521087185..2b2ed6a42afc 100644 --- a/azurerm/resource_arm_traffic_manager_endpoint_test.go +++ b/azurerm/resource_arm_traffic_manager_endpoint_test.go @@ -217,6 +217,40 @@ func TestAccAzureRMTrafficManagerEndpoint_location(t *testing.T) { }) } +func TestAccAzureRMTrafficManagerEndpoint_withGeoMappings(t *testing.T) { + resourceName := "azurerm_traffic_manager_endpoint.test" + ri := acctest.RandInt() + location := testLocation() + first := testAccAzureRMTrafficManagerEndpoint_geoMappings(ri, location) + second := testAccAzureRMTrafficManagerEndpoint_geoMappingsUpdated(ri, location) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testCheckAzureRMTrafficManagerEndpointDestroy, + Steps: []resource.TestStep{ + { + Config: first, + Check: resource.ComposeTestCheckFunc( + testCheckAzureRMTrafficManagerEndpointExists(resourceName), + resource.TestCheckResourceAttr(resourceName, "geo_mappings.#", "2"), + resource.TestCheckResourceAttr(resourceName, "geo_mappings.0", "GB"), + resource.TestCheckResourceAttr(resourceName, "geo_mappings.1", "FR"), + ), + }, + { + Config: second, + Check: resource.ComposeTestCheckFunc( + testCheckAzureRMTrafficManagerEndpointExists(resourceName), + resource.TestCheckResourceAttr(resourceName, "geo_mappings.#", "2"), + resource.TestCheckResourceAttr(resourceName, "geo_mappings.0", "FR"), + resource.TestCheckResourceAttr(resourceName, "geo_mappings.1", "DE"), + ), + }, + }, + }) +} + func testCheckAzureRMTrafficManagerEndpointExists(name string) resource.TestCheckFunc { return func(s *terraform.State) error { // Ensure we have enough information in state to look up in API @@ -716,3 +750,81 @@ resource "azurerm_traffic_manager_endpoint" "test" { } `, rInt, location, rInt, rInt, rInt) } + +func testAccAzureRMTrafficManagerEndpoint_geoMappings(rInt int, location string) string { + return fmt.Sprintf(` +resource "azurerm_resource_group" "test" { + name = "acctestrg-%d" + location = "%s" +} + +resource "azurerm_traffic_manager_profile" "test" { + name = "acctesttmp%d" + resource_group_name = "${azurerm_resource_group.test.name}" + traffic_routing_method = "Geographic" + + dns_config { + relative_name = "acctesttmp%d" + ttl = 100 + } + + monitor_config { + protocol = "http" + port = 80 + path = "/" + } + + tags { + environment = "Production" + } +} + +resource "azurerm_traffic_manager_endpoint" "test" { + name = "example.com" + resource_group_name = "${azurerm_resource_group.test.name}" + profile_name = "${azurerm_traffic_manager_profile.test.name}" + target = "example.com" + type = "externalEndpoints" + geo_mappings = ["GB", "FR"] +} +`, rInt, location, rInt, rInt) +} + +func testAccAzureRMTrafficManagerEndpoint_geoMappingsUpdated(rInt int, location string) string { + return fmt.Sprintf(` +resource "azurerm_resource_group" "test" { + name = "acctestrg-%d" + location = "%s" +} + +resource "azurerm_traffic_manager_profile" "test" { + name = "acctesttmp%d" + resource_group_name = "${azurerm_resource_group.test.name}" + traffic_routing_method = "Geographic" + + dns_config { + relative_name = "acctesttmp%d" + ttl = 100 + } + + monitor_config { + protocol = "http" + port = 80 + path = "/" + } + + tags { + environment = "Production" + } +} + +resource "azurerm_traffic_manager_endpoint" "test" { + name = "example.com" + resource_group_name = "${azurerm_resource_group.test.name}" + profile_name = "${azurerm_traffic_manager_profile.test.name}" + target = "example.com" + type = "externalEndpoints" + geo_mappings = ["FR", "DE"] +} +`, rInt, location, rInt, rInt) +} diff --git a/website/docs/r/traffic_manager_endpoint.html.markdown b/website/docs/r/traffic_manager_endpoint.html.markdown index 128bc4c1636e..f8f6492a5200 100644 --- a/website/docs/r/traffic_manager_endpoint.html.markdown +++ b/website/docs/r/traffic_manager_endpoint.html.markdown @@ -6,7 +6,7 @@ description: |- Creates a Traffic Manager Endpoint. --- -# azurerm\_traffic\_manager\_endpoint +# azurerm_traffic_manager_endpoint Creates a Traffic Manager Endpoint. @@ -28,7 +28,7 @@ resource "azurerm_resource_group" "test" { resource "azurerm_traffic_manager_profile" "test" { name = "${random_id.server.hex}" resource_group_name = "${azurerm_resource_group.test.name}" - + traffic_routing_method = "Weighted" dns_config { @@ -107,6 +107,8 @@ The following arguments are supported: profile. This argument only applies to Endpoints of type `nestedEndpoints` and defaults to `1`. +* `geo_mappings` - (Optional) A list of Geographic Regions used to distribute traffic, such as `WORLD`, `UK` or `DE`. The same location can't be specified in two endpoints. [See the Geographic Hierarchies documentation for more information](https://docs.microsoft.com/en-us/rest/api/trafficmanager/geographichierarchies/getdefault). + ## Attributes Reference The following attributes are exported: From 8f3242f3fbac98c262a46fc0cc3e2dba93234302 Mon Sep 17 00:00:00 2001 From: tombuildsstuff Date: Thu, 15 Mar 2018 22:19:09 -0500 Subject: [PATCH 3/3] Exposing the `endpoint_monitor_status` field --- azurerm/resource_arm_traffic_manager_endpoint.go | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/azurerm/resource_arm_traffic_manager_endpoint.go b/azurerm/resource_arm_traffic_manager_endpoint.go index 5f0e43c4d4b2..de846ccfbdc6 100644 --- a/azurerm/resource_arm_traffic_manager_endpoint.go +++ b/azurerm/resource_arm_traffic_manager_endpoint.go @@ -103,6 +103,11 @@ func resourceArmTrafficManagerEndpoint() *schema.Resource { Elem: &schema.Schema{Type: schema.TypeString}, Optional: true, }, + + "endpoint_monitor_status": { + Type: schema.TypeString, + Computed: true, + }, }, } }