From c90c75967e7dda0335bf4876a17109c542cc6a64 Mon Sep 17 00:00:00 2001 From: Jeffrey Cline <20408400+WodansSon@users.noreply.github.com> Date: Thu, 5 Mar 2020 19:23:14 -0800 Subject: [PATCH 1/4] Fix for upcoming RP change --- azurerm/internal/services/frontdoor/helper.go | 138 ---------- .../frontdoor/resource_arm_frontdoor.go | 114 +++++---- .../resource_arm_frontdoor_firewall_policy.go | 5 +- .../tests/resource_arm_front_door_test.go | 26 +- .../internal/services/frontdoor/validate.go | 100 -------- .../services/frontdoor/validate/validate.go | 239 ++++++++++++++++++ website/docs/r/frontdoor.html.markdown | 3 - 7 files changed, 319 insertions(+), 306 deletions(-) delete mode 100644 azurerm/internal/services/frontdoor/validate.go create mode 100644 azurerm/internal/services/frontdoor/validate/validate.go diff --git a/azurerm/internal/services/frontdoor/helper.go b/azurerm/internal/services/frontdoor/helper.go index ba647771590d..576c41f70bff 100644 --- a/azurerm/internal/services/frontdoor/helper.go +++ b/azurerm/internal/services/frontdoor/helper.go @@ -2,44 +2,10 @@ package frontdoor import ( "fmt" - "strings" "github.com/Azure/azure-sdk-for-go/services/frontdoor/mgmt/2019-11-01/frontdoor" ) -func VerifyBackendPoolExists(backendPoolName string, backendPools []interface{}) error { - if backendPoolName == "" { - return fmt.Errorf(`"backend_pool_name" cannot be empty`) - } - - for _, bps := range backendPools { - backendPool := bps.(map[string]interface{}) - if backendPool["name"].(string) == backendPoolName { - return nil - } - } - - return fmt.Errorf(`unable to locate "backend_pool_name":%q in configuration file`, backendPoolName) -} - -func AzureKeyVaultCertificateHasValues(customHttpsConfiguration map[string]interface{}, MatchAllKeys bool) bool { - certificateSecretName := customHttpsConfiguration["azure_key_vault_certificate_secret_name"] - certificateSecretVersion := customHttpsConfiguration["azure_key_vault_certificate_secret_version"] - certificateVaultId := customHttpsConfiguration["azure_key_vault_certificate_vault_id"] - - if MatchAllKeys { - if strings.TrimSpace(certificateSecretName.(string)) != "" && strings.TrimSpace(certificateSecretVersion.(string)) != "" && strings.TrimSpace(certificateVaultId.(string)) != "" { - return true - } - } else { - if strings.TrimSpace(certificateSecretName.(string)) != "" || strings.TrimSpace(certificateSecretVersion.(string)) != "" || strings.TrimSpace(certificateVaultId.(string)) != "" { - return true - } - } - - return false -} - func IsFrontDoorFrontendEndpointConfigurable(currentState frontdoor.CustomHTTPSProvisioningState, customHttpsProvisioningEnabled bool, frontendEndpointName string, resourceGroup string) error { action := "disable" if customHttpsProvisioningEnabled { @@ -76,110 +42,6 @@ func GetFrontDoorBasicRouteConfigurationType(i interface{}) string { } } -func VerifyRoutingRuleFrontendEndpoints(routingRuleFrontends []interface{}, configFrontendEndpoints []interface{}) error { - for _, routingRuleFrontend := range routingRuleFrontends { - // Get the name of the frontend defined in the routing rule - routingRulefrontendName := routingRuleFrontend.(string) - found := false - - // Loop over all of the defined frontend endpoints in the config - // seeing if we find the routing rule frontend in the list - for _, configFrontendEndpoint := range configFrontendEndpoints { - configFrontend := configFrontendEndpoint.(map[string]interface{}) - configFrontendName := configFrontend["name"] - if routingRulefrontendName == configFrontendName { - found = true - break - } - } - - if !found { - return fmt.Errorf(`"frontend_endpoints":%q was not found in the configuration file. verify you have the "frontend_endpoint":%q defined in the configuration file`, routingRulefrontendName, routingRulefrontendName) - } - } - - return nil -} - -func VerifyLoadBalancingAndHealthProbeSettings(backendPools []interface{}, loadBalancingSettings []interface{}, healthProbeSettings []interface{}) error { - for _, bps := range backendPools { - backendPool := bps.(map[string]interface{}) - backendPoolName := backendPool["name"] - backendPoolLoadBalancingName := backendPool["load_balancing_name"] - backendPoolHealthProbeName := backendPool["health_probe_name"] - found := false - - // Verify backend pool load balancing settings name exists - if len(loadBalancingSettings) > 0 { - for _, lbs := range loadBalancingSettings { - loadBalancing := lbs.(map[string]interface{}) - loadBalancingName := loadBalancing["name"] - - if loadBalancingName == backendPoolLoadBalancingName { - found = true - break - } - } - - if !found { - return fmt.Errorf(`"backend_pool":%q "load_balancing_name":%q was not found in the configuration file. verify you have the "backend_pool_load_balancing":%q defined in the configuration file`, backendPoolName, backendPoolLoadBalancingName, backendPoolLoadBalancingName) - } - } - - found = false - - // Verify health probe settings name exists - if len(healthProbeSettings) > 0 { - for _, hps := range healthProbeSettings { - healthProbe := hps.(map[string]interface{}) - healthProbeName := healthProbe["name"] - - if healthProbeName == backendPoolHealthProbeName { - found = true - break - } - } - - if !found { - return fmt.Errorf(`"backend_pool":%q "health_probe_name":%q was not found in the configuration file. verify you have the "backend_pool_health_probe":%q defined in the configuration file`, backendPoolName, backendPoolHealthProbeName, backendPoolHealthProbeName) - } - } - } - - return nil -} - -func VerifyCustomHttpsConfiguration(configFrontendEndpoints []interface{}) error { - for _, configFrontendEndpoint := range configFrontendEndpoints { - if configFrontend := configFrontendEndpoint.(map[string]interface{}); len(configFrontend) > 0 { - FrontendName := configFrontend["name"] - customHttpsEnabled := configFrontend["custom_https_provisioning_enabled"].(bool) - - if chc := configFrontend["custom_https_configuration"].([]interface{}); len(chc) > 0 { - if !customHttpsEnabled { - return fmt.Errorf(`"frontend_endpoint":%q "custom_https_configuration" is invalid because "custom_https_provisioning_enabled" is set to "false". please remove the "custom_https_configuration" block from the configuration file`, FrontendName) - } - - customHttpsConfiguration := chc[0].(map[string]interface{}) - certificateSource := customHttpsConfiguration["certificate_source"] - if certificateSource == string(frontdoor.CertificateSourceAzureKeyVault) { - if !AzureKeyVaultCertificateHasValues(customHttpsConfiguration, true) { - return fmt.Errorf(`"frontend_endpoint":%q "custom_https_configuration" is invalid, all of the following keys must have values in the "custom_https_configuration" block: "azure_key_vault_certificate_secret_name", "azure_key_vault_certificate_secret_version", and "azure_key_vault_certificate_vault_id"`, FrontendName) - } - } else { - if AzureKeyVaultCertificateHasValues(customHttpsConfiguration, false) { - return fmt.Errorf(`"frontend_endpoint":%q "custom_https_configuration" is invalid, all of the following keys must be removed from the "custom_https_configuration" block: "azure_key_vault_certificate_secret_name", "azure_key_vault_certificate_secret_version", and "azure_key_vault_certificate_vault_id"`, FrontendName) - } - } - } else if customHttpsEnabled { - return fmt.Errorf(`"frontend_endpoint":%q configuration is invalid because "custom_https_provisioning_enabled" is set to "true" and the "custom_https_configuration" block is undefined. please add the "custom_https_configuration" block to the configuration file`, FrontendName) - } - } - } - - return nil -} - func FlattenTransformSlice(input *[]frontdoor.TransformType) []interface{} { result := make([]interface{}, 0) diff --git a/azurerm/internal/services/frontdoor/resource_arm_frontdoor.go b/azurerm/internal/services/frontdoor/resource_arm_frontdoor.go index b8348e880534..c36808536dc1 100644 --- a/azurerm/internal/services/frontdoor/resource_arm_frontdoor.go +++ b/azurerm/internal/services/frontdoor/resource_arm_frontdoor.go @@ -14,6 +14,7 @@ import ( "github.com/terraform-providers/terraform-provider-azurerm/azurerm/helpers/tf" "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/clients" "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/features" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/services/frontdoor/validate" "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/tags" "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/timeouts" "github.com/terraform-providers/terraform-provider-azurerm/azurerm/utils" @@ -42,7 +43,7 @@ func resourceArmFrontDoor() *schema.Resource { Type: schema.TypeString, Required: true, ForceNew: true, - ValidateFunc: ValidateFrontDoorName, + ValidateFunc: validate.FrontDoorName, }, "cname": { @@ -66,7 +67,12 @@ func resourceArmFrontDoor() *schema.Resource { Required: true, }, - "location": azure.SchemaLocation(), + "location": { + Type: schema.TypeString, + Optional: true, + Computed: true, + Deprecated: "per resource provider change, 'location' is no longer valid and will always be set to 'Global', however if the Front Door service was created prior to the v2.1.0 release of the provider it may continue to exist in its current location", + }, "resource_group_name": azure.SchemaResourceGroupName(), @@ -83,7 +89,7 @@ func resourceArmFrontDoor() *schema.Resource { "name": { Type: schema.TypeString, Required: true, - ValidateFunc: ValidateBackendPoolRoutingRuleName, + ValidateFunc: validate.FrontDoorBackendPoolRoutingRuleName, }, "enabled": { Type: schema.TypeBool, @@ -171,7 +177,7 @@ func resourceArmFrontDoor() *schema.Resource { "backend_pool_name": { Type: schema.TypeString, Required: true, - ValidateFunc: ValidateBackendPoolRoutingRuleName, + ValidateFunc: validate.FrontDoorBackendPoolRoutingRuleName, }, "cache_enabled": { Type: schema.TypeBool, @@ -226,7 +232,7 @@ func resourceArmFrontDoor() *schema.Resource { "name": { Type: schema.TypeString, Required: true, - ValidateFunc: ValidateBackendPoolRoutingRuleName, + ValidateFunc: validate.FrontDoorBackendPoolRoutingRuleName, }, "sample_size": { Type: schema.TypeInt, @@ -260,7 +266,7 @@ func resourceArmFrontDoor() *schema.Resource { "name": { Type: schema.TypeString, Required: true, - ValidateFunc: ValidateBackendPoolRoutingRuleName, + ValidateFunc: validate.FrontDoorBackendPoolRoutingRuleName, }, "enabled": { Type: schema.TypeBool, @@ -356,7 +362,7 @@ func resourceArmFrontDoor() *schema.Resource { "name": { Type: schema.TypeString, Required: true, - ValidateFunc: ValidateBackendPoolRoutingRuleName, + ValidateFunc: validate.FrontDoorBackendPoolRoutingRuleName, }, "health_probe_name": { Type: schema.TypeString, @@ -383,7 +389,7 @@ func resourceArmFrontDoor() *schema.Resource { "name": { Type: schema.TypeString, Required: true, - ValidateFunc: ValidateBackendPoolRoutingRuleName, + ValidateFunc: validate.FrontDoorBackendPoolRoutingRuleName, }, "host_name": { Type: schema.TypeString, @@ -459,8 +465,8 @@ func resourceArmFrontDoor() *schema.Resource { }, CustomizeDiff: func(d *schema.ResourceDiff, v interface{}) error { - if err := ValidateFrontdoorSettings(d); err != nil { - return fmt.Errorf("Error creating Front Door %q (Resource Group %q): %+v", d.Get("name").(string), d.Get("resource_group_name").(string), err) + if err := validate.FrontdoorSettings(d); err != nil { + return fmt.Errorf("creating Front Door %q (Resource Group %q): %+v", d.Get("name").(string), d.Get("resource_group_name").(string), err) } return nil @@ -481,7 +487,7 @@ func resourceArmFrontDoorCreateUpdate(d *schema.ResourceData, meta interface{}) resp, err := client.Get(ctx, resourceGroup, name) if err != nil { if !utils.ResponseWasNotFound(resp.Response) { - return fmt.Errorf("Error checking for present of existing Front Door %q (Resource Group %q): %+v", name, resourceGroup, err) + return fmt.Errorf("checking for present of existing Front Door %q (Resource Group %q): %+v", name, resourceGroup, err) } } if !utils.ResponseWasNotFound(resp.Response) { @@ -489,8 +495,29 @@ func resourceArmFrontDoorCreateUpdate(d *schema.ResourceData, meta interface{}) } } + // due to a change in the RP, if a Frontdoor exists in a location other than 'Global' it may continue to + // exist in that location, if this is a brand new Frontdoor it must be created in the 'Global' location + location := "Global" + preExists := false + cfgLocation, hasLocation := d.GetOk("location") + + exists, err := client.Get(ctx, resourceGroup, name) + if err != nil { + if !utils.ResponseWasNotFound(exists.Response) { + return fmt.Errorf("locating Front Door %q (Resource Group %q): %+v", name, resourceGroup, err) + } + } else { + preExists = true + location = azure.NormalizeLocation(*exists.Location) + } + + if hasLocation && preExists { + if location != azure.NormalizeLocation(cfgLocation) { + return fmt.Errorf("the Front Door %q (Resource Group %q) already exists in %q and cannot be moved to the %q location", name, resourceGroup, location, cfgLocation) + } + } + frontDoorPath := fmt.Sprintf("/subscriptions/%s/resourcegroups/%s/providers/Microsoft.Network/Frontdoors/%s", subscriptionId, resourceGroup, name) - location := azure.NormalizeLocation(d.Get("location").(string)) friendlyName := d.Get("friendly_name").(string) routingRules := d.Get("routing_rule").([]interface{}) loadBalancingSettings := d.Get("backend_pool_load_balancing").([]interface{}) @@ -519,39 +546,39 @@ func resourceArmFrontDoorCreateUpdate(d *schema.ResourceData, meta interface{}) future, err := client.CreateOrUpdate(ctx, resourceGroup, name, frontDoorParameters) if err != nil { - return fmt.Errorf("Error creating Front Door %q (Resource Group %q): %+v", name, resourceGroup, err) + return fmt.Errorf("creating Front Door %q (Resource Group %q): %+v", name, resourceGroup, err) } if err = future.WaitForCompletionRef(ctx, client.Client); err != nil { - return fmt.Errorf("Error waiting for creation of Front Door %q (Resource Group %q): %+v", name, resourceGroup, err) + return fmt.Errorf("waiting for creation of Front Door %q (Resource Group %q): %+v", name, resourceGroup, err) } resp, err := client.Get(ctx, resourceGroup, name) if err != nil { - return fmt.Errorf("Error retrieving Front Door %q (Resource Group %q): %+v", name, resourceGroup, err) + return fmt.Errorf("retrieving Front Door %q (Resource Group %q): %+v", name, resourceGroup, err) } if resp.ID == nil { - return fmt.Errorf("Cannot read Front Door %q (Resource Group %q) ID", name, resourceGroup) + return fmt.Errorf("cannot read Front Door %q (Resource Group %q) ID", name, resourceGroup) } d.SetId(*resp.ID) // Now loop through the FrontendEndpoints and enable/disable Custom Domain HTTPS // on each individual Frontend Endpoint if required + feClient := meta.(*clients.Client).Frontdoor.FrontDoorsFrontendClient + feCtx, feCancel := timeouts.ForRead(meta.(*clients.Client).StopContext, d) + defer feCancel() + for _, v := range frontendEndpoints { frontendEndpoint := v.(map[string]interface{}) customHttpsProvisioningEnabled := frontendEndpoint["custom_https_provisioning_enabled"].(bool) frontendEndpointName := frontendEndpoint["name"].(string) // Get current state of endpoint from Azure - client := meta.(*clients.Client).Frontdoor.FrontDoorsFrontendClient - ctx, cancel := timeouts.ForRead(meta.(*clients.Client).StopContext, d) - defer cancel() - - resp, err := client.Get(ctx, resourceGroup, name, frontendEndpointName) + resp, err := feClient.Get(feCtx, resourceGroup, name, frontendEndpointName) if err != nil { - return fmt.Errorf("Error retrieving Front Door Frontend Endpoint %q (Resource Group %q): %+v", frontendEndpointName, resourceGroup, err) + return fmt.Errorf("retrieving Front Door Frontend Endpoint %q (Resource Group %q): %+v", frontendEndpointName, resourceGroup, err) } if resp.ID == nil { - return fmt.Errorf("Cannot read Front Door Frontend Endpoint %q (Resource Group %q) ID", frontendEndpointName, resourceGroup) + return fmt.Errorf("cannot read Front Door Frontend Endpoint %q (Resource Group %q) ID", frontendEndpointName, resourceGroup) } if properties := resp.FrontendEndpointProperties; properties != nil { @@ -600,19 +627,19 @@ func resourceArmFrontDoorFrontendEndpointEnableHttpsProvisioning(d *schema.Resou future, err := client.EnableHTTPS(ctx, resourceGroup, frontDoorName, frontendEndpointName, customHTTPSConfiguration) if err != nil { - return fmt.Errorf("Error enabling Custom Domain HTTPS for Frontend Endpoint: %+v", err) + return fmt.Errorf("enabling Custom Domain HTTPS for Frontend Endpoint: %+v", err) } if err = future.WaitForCompletionRef(ctx, client.Client); err != nil { - return fmt.Errorf("Error waiting to enable Custom Domain HTTPS for Frontend Endpoint: %+v", err) + return fmt.Errorf("waiting to enable Custom Domain HTTPS for Frontend Endpoint: %+v", err) } } else { future, err := client.DisableHTTPS(ctx, resourceGroup, frontDoorName, frontendEndpointName) if err != nil { - return fmt.Errorf("Error disabling Custom Domain HTTPS for Frontend Endpoint: %+v", err) + return fmt.Errorf("disabling Custom Domain HTTPS for Frontend Endpoint: %+v", err) } if err = future.WaitForCompletionRef(ctx, client.Client); err != nil { - return fmt.Errorf("Error waiting to disable Custom Domain HTTPS for Frontend Endpoint: %+v", err) + return fmt.Errorf("waiting to disable Custom Domain HTTPS for Frontend Endpoint: %+v", err) } } @@ -642,23 +669,20 @@ func resourceArmFrontDoorRead(d *schema.ResourceData, meta interface{}) error { d.SetId("") return nil } - return fmt.Errorf("Error reading Front Door %q (Resource Group %q): %+v", name, resourceGroup, err) + return fmt.Errorf("reading Front Door %q (Resource Group %q): %+v", name, resourceGroup, err) } d.Set("name", resp.Name) d.Set("resource_group_name", resourceGroup) - - if location := resp.Location; location != nil { - d.Set("location", azure.NormalizeLocation(*location)) - } + d.Set("location", "") if properties := resp.Properties; properties != nil { if err := d.Set("backend_pool", flattenArmFrontDoorBackendPools(properties.BackendPools)); err != nil { - return fmt.Errorf("Error setting `backend_pool`: %+v", err) + return fmt.Errorf("setting `backend_pool`: %+v", err) } if err := d.Set("enforce_backend_pools_certificate_name_check", flattenArmFrontDoorBackendPoolsSettings(properties.BackendPoolsSettings)); err != nil { - return fmt.Errorf("Error setting `enforce_backend_pools_certificate_name_check`: %+v", err) + return fmt.Errorf("setting `enforce_backend_pools_certificate_name_check`: %+v", err) } d.Set("cname", properties.Cname) @@ -669,26 +693,26 @@ func resourceArmFrontDoorRead(d *schema.ResourceData, meta interface{}) error { if resp.Name != nil { if frontDoorFrontendEndpoints, err := flattenArmFrontDoorFrontendEndpoint(d, frontendEndpoints, resourceGroup, *resp.Name, meta); frontDoorFrontendEndpoints != nil { if err := d.Set("frontend_endpoint", frontDoorFrontendEndpoints); err != nil { - return fmt.Errorf("Error setting `frontend_endpoint`: %+v", err) + return fmt.Errorf("setting `frontend_endpoint`: %+v", err) } } else { - return fmt.Errorf("Error flattening `frontend_endpoint`: %+v", err) + return fmt.Errorf("flattening `frontend_endpoint`: %+v", err) } } else { - return fmt.Errorf("Error flattening `frontend_endpoint`: Unable to read Frontdoor Name") + return fmt.Errorf("flattening `frontend_endpoint`: Unable to read Frontdoor Name") } } if err := d.Set("backend_pool_health_probe", flattenArmFrontDoorHealthProbeSettingsModel(properties.HealthProbeSettings)); err != nil { - return fmt.Errorf("Error setting `backend_pool_health_probe`: %+v", err) + return fmt.Errorf("setting `backend_pool_health_probe`: %+v", err) } if err := d.Set("backend_pool_load_balancing", flattenArmFrontDoorLoadBalancingSettingsModel(properties.LoadBalancingSettings)); err != nil { - return fmt.Errorf("Error setting `backend_pool_load_balancing`: %+v", err) + return fmt.Errorf("setting `backend_pool_load_balancing`: %+v", err) } if err := d.Set("routing_rule", flattenArmFrontDoorRoutingRule(properties.RoutingRules, d.Get("routing_rule"))); err != nil { - return fmt.Errorf("Error setting `routing_rules`: %+v", err) + return fmt.Errorf("setting `routing_rules`: %+v", err) } } @@ -716,12 +740,12 @@ func resourceArmFrontDoorDelete(d *schema.ResourceData, meta interface{}) error if response.WasNotFound(future.Response()) { return nil } - return fmt.Errorf("Error deleting Front Door %q (Resource Group %q): %+v", name, resourceGroup, err) + return fmt.Errorf("deleting Front Door %q (Resource Group %q): %+v", name, resourceGroup, err) } if err = future.WaitForCompletionRef(ctx, client.Client); err != nil { if !response.WasNotFound(future.Response()) { - return fmt.Errorf("Error waiting for deleting Front Door %q (Resource Group %q): %+v", name, resourceGroup, err) + return fmt.Errorf("waiting for deleting Front Door %q (Resource Group %q): %+v", name, resourceGroup, err) } } @@ -1213,7 +1237,7 @@ func flattenArmFrontDoorBackend(input *[]frontdoor.Backend) []interface{} { func flattenArmFrontDoorFrontendEndpoint(d *schema.ResourceData, input *[]frontdoor.FrontendEndpoint, resourceGroup string, frontDoorName string, meta interface{}) ([]interface{}, error) { if input == nil { - return make([]interface{}, 0), fmt.Errorf("Cannot read Front Door Frontend Endpoint (Resource Group %q): slice is empty", resourceGroup) + return make([]interface{}, 0), fmt.Errorf("cannot read Front Door Frontend Endpoint (Resource Group %q): slice is empty", resourceGroup) } output := make([]interface{}, 0) @@ -1234,10 +1258,10 @@ func flattenArmFrontDoorFrontendEndpoint(d *schema.ResourceData, input *[]frontd resp, err := client.Get(ctx, resourceGroup, frontDoorName, *name) if err != nil { - return make([]interface{}, 0), fmt.Errorf("Error retrieving Front Door Frontend Endpoint Custom HTTPS Configuration %q (Resource Group %q): %+v", *name, resourceGroup, err) + return make([]interface{}, 0), fmt.Errorf("retrieving Front Door Frontend Endpoint Custom HTTPS Configuration %q (Resource Group %q): %+v", *name, resourceGroup, err) } if resp.ID == nil { - return make([]interface{}, 0), fmt.Errorf("Cannot read Front Door Frontend Endpoint Custom HTTPS Configuration %q (Resource Group %q) ID", *name, resourceGroup) + return make([]interface{}, 0), fmt.Errorf("cannot read Front Door Frontend Endpoint Custom HTTPS Configuration %q (Resource Group %q) ID", *name, resourceGroup) } result["id"] = resp.ID diff --git a/azurerm/internal/services/frontdoor/resource_arm_frontdoor_firewall_policy.go b/azurerm/internal/services/frontdoor/resource_arm_frontdoor_firewall_policy.go index 2337cf55cee7..c1f3bb2f9d29 100644 --- a/azurerm/internal/services/frontdoor/resource_arm_frontdoor_firewall_policy.go +++ b/azurerm/internal/services/frontdoor/resource_arm_frontdoor_firewall_policy.go @@ -13,6 +13,7 @@ import ( "github.com/terraform-providers/terraform-provider-azurerm/azurerm/helpers/tf" "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/clients" "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/features" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/services/frontdoor/validate" "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/tags" "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/timeouts" "github.com/terraform-providers/terraform-provider-azurerm/azurerm/utils" @@ -41,7 +42,7 @@ func resourceArmFrontDoorFirewallPolicy() *schema.Resource { Type: schema.TypeString, Required: true, ForceNew: true, - ValidateFunc: ValidateFrontDoorWAFName, + ValidateFunc: validate.FrontDoorWAFName, }, "location": azure.SchemaLocationForDataSource(), @@ -85,7 +86,7 @@ func resourceArmFrontDoorFirewallPolicy() *schema.Resource { "custom_block_response_body": { Type: schema.TypeString, Optional: true, - ValidateFunc: ValidateCustomBlockResponseBody, + ValidateFunc: validate.FrontdoorCustomBlockResponseBody, }, "custom_rule": { diff --git a/azurerm/internal/services/frontdoor/tests/resource_arm_front_door_test.go b/azurerm/internal/services/frontdoor/tests/resource_arm_front_door_test.go index dc6d15add6ba..706231d494a4 100644 --- a/azurerm/internal/services/frontdoor/tests/resource_arm_front_door_test.go +++ b/azurerm/internal/services/frontdoor/tests/resource_arm_front_door_test.go @@ -290,7 +290,6 @@ locals { resource "azurerm_frontdoor" "test" { name = "acctest-FD-%d" - location = azurerm_resource_group.test.location resource_group_name = azurerm_resource_group.test.name enforce_backend_pools_certificate_name_check = false @@ -332,7 +331,7 @@ resource "azurerm_frontdoor" "test" { custom_https_provisioning_enabled = false } } -`, data.RandomInteger, data.Locations.Primary, data.RandomInteger, data.RandomInteger) +`, data.RandomInteger, data.RandomInteger, data.RandomInteger) } func testAccAzureRMFrontDoor_basicDisabled(data acceptance.TestData) string { @@ -355,7 +354,6 @@ locals { resource "azurerm_frontdoor" "test" { name = "acctest-FD-%d" - location = azurerm_resource_group.test.location resource_group_name = azurerm_resource_group.test.name enforce_backend_pools_certificate_name_check = false @@ -399,7 +397,7 @@ resource "azurerm_frontdoor" "test" { custom_https_provisioning_enabled = false } } -`, data.RandomInteger, data.Locations.Primary, data.RandomInteger, data.RandomInteger) +`, data.RandomInteger, data.RandomInteger, data.RandomInteger) } func testAccAzureRMFrontDoor_requiresImport(data acceptance.TestData) string { @@ -409,7 +407,6 @@ func testAccAzureRMFrontDoor_requiresImport(data acceptance.TestData) string { resource "azurerm_frontdoor" "import" { name = azurerm_frontdoor.test.name - location = azurerm_frontdoor.test.location resource_group_name = azurerm_frontdoor.test.resource_group_name enforce_backend_pools_certificate_name_check = azurerm_frontdoor.test.enforce_backend_pools_certificate_name_check @@ -474,7 +471,6 @@ locals { resource "azurerm_frontdoor" "test" { name = "acctest-FD-%d" - location = azurerm_resource_group.test.location resource_group_name = azurerm_resource_group.test.name enforce_backend_pools_certificate_name_check = false @@ -516,7 +512,7 @@ resource "azurerm_frontdoor" "test" { custom_https_provisioning_enabled = false } } -`, data.RandomInteger, data.Locations.Primary, data.RandomInteger, data.RandomInteger) +`, data.RandomInteger, data.RandomInteger, data.RandomInteger) } func testAccAzureRMFrontDoor_waf(data acceptance.TestData) string { @@ -545,7 +541,6 @@ resource "azurerm_frontdoor_firewall_policy" "test" { resource "azurerm_frontdoor" "test" { name = "acctest-FD-%d" - location = azurerm_resource_group.test.location resource_group_name = azurerm_resource_group.test.name enforce_backend_pools_certificate_name_check = false @@ -588,7 +583,7 @@ resource "azurerm_frontdoor" "test" { web_application_firewall_policy_link_id = azurerm_frontdoor_firewall_policy.test.id } } -`, data.RandomInteger, data.Locations.Primary, data.RandomInteger, data.RandomInteger, data.RandomInteger) +`, data.RandomInteger, data.RandomInteger, data.RandomInteger, data.RandomInteger) } func testAccAzureRMFrontDoor_DisableCache(data acceptance.TestData) string { @@ -611,7 +606,6 @@ locals { resource "azurerm_frontdoor" "test" { name = "acctest-FD-%d" - location = azurerm_resource_group.test.location resource_group_name = azurerm_resource_group.test.name enforce_backend_pools_certificate_name_check = false @@ -653,7 +647,7 @@ resource "azurerm_frontdoor" "test" { custom_https_provisioning_enabled = false } } -`, data.RandomInteger, data.Locations.Primary, data.RandomInteger, data.RandomInteger) +`, data.RandomInteger, data.RandomInteger, data.RandomInteger) } func testAccAzureRMFrontDoor_EnableCache(data acceptance.TestData) string { @@ -676,7 +670,6 @@ locals { resource "azurerm_frontdoor" "test" { name = "acctest-FD-%d" - location = azurerm_resource_group.test.location resource_group_name = azurerm_resource_group.test.name enforce_backend_pools_certificate_name_check = false @@ -720,7 +713,7 @@ resource "azurerm_frontdoor" "test" { custom_https_provisioning_enabled = false } } -`, data.RandomInteger, data.Locations.Primary, data.RandomInteger, data.RandomInteger) +`, data.RandomInteger, data.RandomInteger, data.RandomInteger) } func testAccAzureRMFrontDoor_CustomHttpsEnabled(data acceptance.TestData) string { @@ -743,7 +736,6 @@ locals { resource "azurerm_frontdoor" "test" { name = "acctest-FD-%d" - location = azurerm_resource_group.test.location resource_group_name = azurerm_resource_group.test.name enforce_backend_pools_certificate_name_check = false @@ -789,7 +781,7 @@ resource "azurerm_frontdoor" "test" { } } } -`, data.RandomInteger, data.Locations.Primary, data.RandomInteger, data.RandomInteger) +`, data.RandomInteger, data.RandomInteger, data.RandomInteger) } func testAccAzureRMFrontDoor_CustomHttpsDisabled(data acceptance.TestData) string { @@ -812,7 +804,6 @@ locals { resource "azurerm_frontdoor" "test" { name = "acctest-FD-%d" - location = azurerm_resource_group.test.location resource_group_name = azurerm_resource_group.test.name enforce_backend_pools_certificate_name_check = false @@ -855,7 +846,7 @@ resource "azurerm_frontdoor" "test" { custom_https_provisioning_enabled = false } } -`, data.RandomInteger, data.Locations.Primary, data.RandomInteger, data.RandomInteger) +`, data.RandomInteger, data.RandomInteger, data.RandomInteger) } func testAccAzureRMFrontDoor_multiplePools(data acceptance.TestData) string { @@ -871,7 +862,6 @@ resource "azurerm_resource_group" "test" { resource "azurerm_frontdoor" "test" { name = "acctest-FD-%[1]d" - location = azurerm_resource_group.test.location resource_group_name = azurerm_resource_group.test.name enforce_backend_pools_certificate_name_check = false diff --git a/azurerm/internal/services/frontdoor/validate.go b/azurerm/internal/services/frontdoor/validate.go deleted file mode 100644 index 872bd54f09ae..000000000000 --- a/azurerm/internal/services/frontdoor/validate.go +++ /dev/null @@ -1,100 +0,0 @@ -package frontdoor - -import ( - "fmt" - - "github.com/hashicorp/terraform-plugin-sdk/helper/schema" - "github.com/terraform-providers/terraform-provider-azurerm/azurerm/helpers/validate" -) - -func ValidateFrontDoorName(i interface{}, k string) (_ []string, errors []error) { - if m, regexErrs := validate.RegExHelper(i, k, `(^[\da-zA-Z])([-\da-zA-Z]{3,61})([\da-zA-Z]$)`); !m { - errors = append(regexErrs, fmt.Errorf(`%q must be between 5 and 63 characters in length and begin with a letter or number, end with a letter or number and may contain only letters, numbers or hyphens.`, k)) - } - - return nil, errors -} - -func ValidateFrontDoorWAFName(i interface{}, k string) (_ []string, errors []error) { - if m, regexErrs := validate.RegExHelper(i, k, `(^[a-zA-Z])([\da-zA-Z]{0,127})$`); !m { - errors = append(regexErrs, fmt.Errorf(`%q must be between 1 and 128 characters in length, must begin with a letter and may only contain letters and numbers.`, k)) - } - - return nil, errors -} - -func ValidateBackendPoolRoutingRuleName(i interface{}, k string) (_ []string, errors []error) { - if m, regexErrs := validate.RegExHelper(i, k, `(^[\da-zA-Z])([-\da-zA-Z]{1,88})([\da-zA-Z]$)`); !m { - errors = append(regexErrs, fmt.Errorf(`%q must be between 1 and 90 characters in length and begin with a letter or number, end with a letter or number and may contain only letters, numbers or hyphens.`, k)) - } - - return nil, errors -} - -func ValidateCustomBlockResponseBody(i interface{}, k string) (_ []string, errors []error) { - if m, regexErrs := validate.RegExHelper(i, k, `^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=|[A-Za-z0-9+/]{4})$`); !m { - errors = append(regexErrs, fmt.Errorf(`%q contains invalid characters, %q must contain only alphanumeric and equals sign characters.`, k, k)) - } - - return nil, errors -} - -func ValidateFrontdoorSettings(d *schema.ResourceDiff) error { - routingRules := d.Get("routing_rule").([]interface{}) - configFrontendEndpoints := d.Get("frontend_endpoint").([]interface{}) - backendPools := d.Get("backend_pool").([]interface{}) - loadBalancingSettings := d.Get("backend_pool_load_balancing").([]interface{}) - healthProbeSettings := d.Get("backend_pool_health_probe").([]interface{}) - - if len(configFrontendEndpoints) == 0 { - return fmt.Errorf(`"frontend_endpoint": must have at least one "frontend_endpoint" defined, found 0`) - } - - // Loop over all of the Routing Rules and validate that only one type of configuration is defined per Routing Rule - for _, rr := range routingRules { - routingRule := rr.(map[string]interface{}) - routingRuleName := routingRule["name"] - redirectConfig := routingRule["redirect_configuration"].([]interface{}) - forwardConfig := routingRule["forwarding_configuration"].([]interface{}) - - // Check 0. validate that at least one routing configuration exists per routing rule - if len(redirectConfig) == 0 && len(forwardConfig) == 0 { - return fmt.Errorf(`routing_rule %s block is invalid. you must have either a "redirect_configuration" or a "forwarding_configuration" defined for the routing_rule %s`, routingRuleName, routingRuleName) - } - - // Check 1. validate that only one configuration type is defined per routing rule - if len(redirectConfig) == 1 && len(forwardConfig) == 1 { - return fmt.Errorf(`routing_rule %s block is invalid. "redirect_configuration" conflicts with "forwarding_configuration". You can only have one configuration type per each routing rule`, routingRuleName) - } - - // Check 2. routing rule is a forwarding_configuration type make sure the backend_pool_name exists in the configuration file - if len(forwardConfig) > 0 { - fc := forwardConfig[0].(map[string]interface{}) - - if err := VerifyBackendPoolExists(fc["backend_pool_name"].(string), backendPools); err != nil { - return fmt.Errorf(`routing_rule %s is invalid. %+v`, routingRuleName, err) - } - } - - // Check 3. validate that each routing rule frontend_endpoints are actually defined in the resource schema - if routingRuleFrontends := routingRule["frontend_endpoints"].([]interface{}); len(routingRuleFrontends) > 0 { - if err := VerifyRoutingRuleFrontendEndpoints(routingRuleFrontends, configFrontendEndpoints); err != nil { - return fmt.Errorf(`"routing_rule":%q %+v`, routingRuleName, err) - } - } else { - return fmt.Errorf(`"routing_rule": %q must have at least one "frontend_endpoints" defined`, routingRuleName) - } - } - - // Verify backend pool load balancing settings and health probe settings are defined in the resource schema - if err := VerifyLoadBalancingAndHealthProbeSettings(backendPools, loadBalancingSettings, healthProbeSettings); err != nil { - return fmt.Errorf(`%+v`, err) - } - - // Verify frontend endpoints custom https configuration is valid if defined - if err := VerifyCustomHttpsConfiguration(configFrontendEndpoints); err != nil { - return fmt.Errorf(`%+v`, err) - } - - return nil -} diff --git a/azurerm/internal/services/frontdoor/validate/validate.go b/azurerm/internal/services/frontdoor/validate/validate.go new file mode 100644 index 000000000000..8514fa78401e --- /dev/null +++ b/azurerm/internal/services/frontdoor/validate/validate.go @@ -0,0 +1,239 @@ +package validate + +import ( + "fmt" + "strings" + + "github.com/Azure/azure-sdk-for-go/services/frontdoor/mgmt/2019-11-01/frontdoor" + "github.com/hashicorp/terraform-plugin-sdk/helper/schema" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/helpers/validate" +) + +func FrontDoorName(i interface{}, k string) (_ []string, errors []error) { + if m, regexErrs := validate.RegExHelper(i, k, `(^[\da-zA-Z])([-\da-zA-Z]{3,61})([\da-zA-Z]$)`); !m { + errors = append(regexErrs, fmt.Errorf(`%q must be between 5 and 63 characters in length and begin with a letter or number, end with a letter or number and may contain only letters, numbers or hyphens.`, k)) + } + + return nil, errors +} + +func FrontDoorWAFName(i interface{}, k string) (_ []string, errors []error) { + if m, regexErrs := validate.RegExHelper(i, k, `(^[a-zA-Z])([\da-zA-Z]{0,127})$`); !m { + errors = append(regexErrs, fmt.Errorf(`%q must be between 1 and 128 characters in length, must begin with a letter and may only contain letters and numbers.`, k)) + } + + return nil, errors +} + +func FrontDoorBackendPoolRoutingRuleName(i interface{}, k string) (_ []string, errors []error) { + if m, regexErrs := validate.RegExHelper(i, k, `(^[\da-zA-Z])([-\da-zA-Z]{1,88})([\da-zA-Z]$)`); !m { + errors = append(regexErrs, fmt.Errorf(`%q must be between 1 and 90 characters in length and begin with a letter or number, end with a letter or number and may contain only letters, numbers or hyphens.`, k)) + } + + return nil, errors +} + +func FrontdoorCustomBlockResponseBody(i interface{}, k string) (_ []string, errors []error) { + if m, regexErrs := validate.RegExHelper(i, k, `^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=|[A-Za-z0-9+/]{4})$`); !m { + errors = append(regexErrs, fmt.Errorf(`%q contains invalid characters, %q must contain only alphanumeric and equals sign characters.`, k, k)) + } + + return nil, errors +} + +func FrontdoorSettings(d *schema.ResourceDiff) error { + routingRules := d.Get("routing_rule").([]interface{}) + configFrontendEndpoints := d.Get("frontend_endpoint").([]interface{}) + backendPools := d.Get("backend_pool").([]interface{}) + loadBalancingSettings := d.Get("backend_pool_load_balancing").([]interface{}) + healthProbeSettings := d.Get("backend_pool_health_probe").([]interface{}) + + if len(configFrontendEndpoints) == 0 { + return fmt.Errorf(`"frontend_endpoint": must have at least one "frontend_endpoint" defined, found 0`) + } + + // Loop over all of the Routing Rules and validate that only one type of configuration is defined per Routing Rule + for _, rr := range routingRules { + routingRule := rr.(map[string]interface{}) + routingRuleName := routingRule["name"] + redirectConfig := routingRule["redirect_configuration"].([]interface{}) + forwardConfig := routingRule["forwarding_configuration"].([]interface{}) + + // Check 0. validate that at least one routing configuration exists per routing rule + if len(redirectConfig) == 0 && len(forwardConfig) == 0 { + return fmt.Errorf(`routing_rule %s block is invalid. you must have either a "redirect_configuration" or a "forwarding_configuration" defined for the routing_rule %s`, routingRuleName, routingRuleName) + } + + // Check 1. validate that only one configuration type is defined per routing rule + if len(redirectConfig) == 1 && len(forwardConfig) == 1 { + return fmt.Errorf(`routing_rule %s block is invalid. "redirect_configuration" conflicts with "forwarding_configuration". You can only have one configuration type per each routing rule`, routingRuleName) + } + + // Check 2. routing rule is a forwarding_configuration type make sure the backend_pool_name exists in the configuration file + if len(forwardConfig) > 0 { + fc := forwardConfig[0].(map[string]interface{}) + + if err := verifyBackendPoolExists(fc["backend_pool_name"].(string), backendPools); err != nil { + return fmt.Errorf(`routing_rule %s is invalid. %+v`, routingRuleName, err) + } + } + + // Check 3. validate that each routing rule frontend_endpoints are actually defined in the resource schema + if routingRuleFrontends := routingRule["frontend_endpoints"].([]interface{}); len(routingRuleFrontends) > 0 { + if err := verifyRoutingRuleFrontendEndpoints(routingRuleFrontends, configFrontendEndpoints); err != nil { + return fmt.Errorf(`"routing_rule":%q %+v`, routingRuleName, err) + } + } else { + return fmt.Errorf(`"routing_rule": %q must have at least one "frontend_endpoints" defined`, routingRuleName) + } + } + + // Verify backend pool load balancing settings and health probe settings are defined in the resource schema + if err := verifyLoadBalancingAndHealthProbeSettings(backendPools, loadBalancingSettings, healthProbeSettings); err != nil { + return fmt.Errorf(`%+v`, err) + } + + // Verify frontend endpoints custom https configuration is valid if defined + if err := verifyCustomHttpsConfiguration(configFrontendEndpoints); err != nil { + return fmt.Errorf(`%+v`, err) + } + + return nil +} + +func verifyBackendPoolExists(backendPoolName string, backendPools []interface{}) error { + if backendPoolName == "" { + return fmt.Errorf(`"backend_pool_name" cannot be empty`) + } + + for _, bps := range backendPools { + backendPool := bps.(map[string]interface{}) + if backendPool["name"].(string) == backendPoolName { + return nil + } + } + + return fmt.Errorf(`unable to locate "backend_pool_name":%q in configuration file`, backendPoolName) +} + +func verifyRoutingRuleFrontendEndpoints(routingRuleFrontends []interface{}, configFrontendEndpoints []interface{}) error { + for _, routingRuleFrontend := range routingRuleFrontends { + // Get the name of the frontend defined in the routing rule + routingRulefrontendName := routingRuleFrontend.(string) + found := false + + // Loop over all of the defined frontend endpoints in the config + // seeing if we find the routing rule frontend in the list + for _, configFrontendEndpoint := range configFrontendEndpoints { + configFrontend := configFrontendEndpoint.(map[string]interface{}) + configFrontendName := configFrontend["name"] + if routingRulefrontendName == configFrontendName { + found = true + break + } + } + + if !found { + return fmt.Errorf(`"frontend_endpoints":%q was not found in the configuration file. verify you have the "frontend_endpoint":%q defined in the configuration file`, routingRulefrontendName, routingRulefrontendName) + } + } + + return nil +} + +func verifyLoadBalancingAndHealthProbeSettings(backendPools []interface{}, loadBalancingSettings []interface{}, healthProbeSettings []interface{}) error { + for _, bps := range backendPools { + backendPool := bps.(map[string]interface{}) + backendPoolName := backendPool["name"] + backendPoolLoadBalancingName := backendPool["load_balancing_name"] + backendPoolHealthProbeName := backendPool["health_probe_name"] + found := false + + // Verify backend pool load balancing settings name exists + if len(loadBalancingSettings) > 0 { + for _, lbs := range loadBalancingSettings { + loadBalancing := lbs.(map[string]interface{}) + loadBalancingName := loadBalancing["name"] + + if loadBalancingName == backendPoolLoadBalancingName { + found = true + break + } + } + + if !found { + return fmt.Errorf(`"backend_pool":%q "load_balancing_name":%q was not found in the configuration file. verify you have the "backend_pool_load_balancing":%q defined in the configuration file`, backendPoolName, backendPoolLoadBalancingName, backendPoolLoadBalancingName) + } + } + + found = false + + // Verify health probe settings name exists + if len(healthProbeSettings) > 0 { + for _, hps := range healthProbeSettings { + healthProbe := hps.(map[string]interface{}) + healthProbeName := healthProbe["name"] + + if healthProbeName == backendPoolHealthProbeName { + found = true + break + } + } + + if !found { + return fmt.Errorf(`"backend_pool":%q "health_probe_name":%q was not found in the configuration file. verify you have the "backend_pool_health_probe":%q defined in the configuration file`, backendPoolName, backendPoolHealthProbeName, backendPoolHealthProbeName) + } + } + } + + return nil +} + +func verifyCustomHttpsConfiguration(configFrontendEndpoints []interface{}) error { + for _, configFrontendEndpoint := range configFrontendEndpoints { + if configFrontend := configFrontendEndpoint.(map[string]interface{}); len(configFrontend) > 0 { + FrontendName := configFrontend["name"] + customHttpsEnabled := configFrontend["custom_https_provisioning_enabled"].(bool) + + if chc := configFrontend["custom_https_configuration"].([]interface{}); len(chc) > 0 { + if !customHttpsEnabled { + return fmt.Errorf(`"frontend_endpoint":%q "custom_https_configuration" is invalid because "custom_https_provisioning_enabled" is set to "false". please remove the "custom_https_configuration" block from the configuration file`, FrontendName) + } + + customHttpsConfiguration := chc[0].(map[string]interface{}) + certificateSource := customHttpsConfiguration["certificate_source"] + if certificateSource == string(frontdoor.CertificateSourceAzureKeyVault) { + if !azureKeyVaultCertificateHasValues(customHttpsConfiguration, true) { + return fmt.Errorf(`"frontend_endpoint":%q "custom_https_configuration" is invalid, all of the following keys must have values in the "custom_https_configuration" block: "azure_key_vault_certificate_secret_name", "azure_key_vault_certificate_secret_version", and "azure_key_vault_certificate_vault_id"`, FrontendName) + } + } else { + if azureKeyVaultCertificateHasValues(customHttpsConfiguration, false) { + return fmt.Errorf(`"frontend_endpoint":%q "custom_https_configuration" is invalid, all of the following keys must be removed from the "custom_https_configuration" block: "azure_key_vault_certificate_secret_name", "azure_key_vault_certificate_secret_version", and "azure_key_vault_certificate_vault_id"`, FrontendName) + } + } + } else if customHttpsEnabled { + return fmt.Errorf(`"frontend_endpoint":%q configuration is invalid because "custom_https_provisioning_enabled" is set to "true" and the "custom_https_configuration" block is undefined. please add the "custom_https_configuration" block to the configuration file`, FrontendName) + } + } + } + + return nil +} + +func azureKeyVaultCertificateHasValues(customHttpsConfiguration map[string]interface{}, MatchAllKeys bool) bool { + certificateSecretName := customHttpsConfiguration["azure_key_vault_certificate_secret_name"] + certificateSecretVersion := customHttpsConfiguration["azure_key_vault_certificate_secret_version"] + certificateVaultId := customHttpsConfiguration["azure_key_vault_certificate_vault_id"] + + if MatchAllKeys { + if strings.TrimSpace(certificateSecretName.(string)) != "" && strings.TrimSpace(certificateSecretVersion.(string)) != "" && strings.TrimSpace(certificateVaultId.(string)) != "" { + return true + } + } else { + if strings.TrimSpace(certificateSecretName.(string)) != "" || strings.TrimSpace(certificateSecretVersion.(string)) != "" || strings.TrimSpace(certificateVaultId.(string)) != "" { + return true + } + } + + return false +} \ No newline at end of file diff --git a/website/docs/r/frontdoor.html.markdown b/website/docs/r/frontdoor.html.markdown index 1ae7b267ac51..cbc7e53cab14 100644 --- a/website/docs/r/frontdoor.html.markdown +++ b/website/docs/r/frontdoor.html.markdown @@ -27,7 +27,6 @@ resource "azurerm_resource_group" "example" { resource "azurerm_frontdoor" "example" { name = "example-FrontDoor" - location = azurerm_resource_group.example.location resource_group_name = azurerm_resource_group.example.name enforce_backend_pools_certificate_name_check = false @@ -79,8 +78,6 @@ The following arguments are supported: * `resource_group_name` - (Required) Specifies the name of the Resource Group in which the Front Door service should exist. Changing this forces a new resource to be created. -* `location` - (Required) Specifies the supported Azure location where the resource exists. Changing this forces a new resource to be created. - * `backend_pool` - (Required) A `backend_pool` block as defined below. * `backend_pool_health_probe` - (Required) A `backend_pool_health_probe` block as defined below. From 7dbeb81d4c3506e446787c96e3d9059438fc0d6e Mon Sep 17 00:00:00 2001 From: Jeffrey Cline <20408400+WodansSon@users.noreply.github.com> Date: Fri, 6 Mar 2020 12:20:53 -0800 Subject: [PATCH 2/4] Fix linting errors --- ...source_arm_front_door_firewall_policy_test.go | 4 ++-- .../tests/resource_arm_front_door_test.go | 16 ++++++++-------- .../services/frontdoor/validate/validate.go | 2 +- 3 files changed, 11 insertions(+), 11 deletions(-) diff --git a/azurerm/internal/services/frontdoor/tests/resource_arm_front_door_firewall_policy_test.go b/azurerm/internal/services/frontdoor/tests/resource_arm_front_door_firewall_policy_test.go index fb0cc3e425ca..bfff7b91c1f4 100644 --- a/azurerm/internal/services/frontdoor/tests/resource_arm_front_door_firewall_policy_test.go +++ b/azurerm/internal/services/frontdoor/tests/resource_arm_front_door_firewall_policy_test.go @@ -9,7 +9,7 @@ import ( "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/acceptance" "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/clients" "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/features" - "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/services/frontdoor" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/services/frontdoor/validate" "github.com/terraform-providers/terraform-provider-azurerm/azurerm/utils" ) @@ -87,7 +87,7 @@ func TestAccAzureRMFrontDoorFirewallPolicy_validateName(t *testing.T) { } for _, tc := range cases { - _, errors := frontdoor.ValidateFrontDoorWAFName(tc.Input, tc.Name) + _, errors := validate.FrontDoorWAFName(tc.Input, tc.Name) hasError := len(errors) > 0 diff --git a/azurerm/internal/services/frontdoor/tests/resource_arm_front_door_test.go b/azurerm/internal/services/frontdoor/tests/resource_arm_front_door_test.go index 706231d494a4..06c53b43f70d 100644 --- a/azurerm/internal/services/frontdoor/tests/resource_arm_front_door_test.go +++ b/azurerm/internal/services/frontdoor/tests/resource_arm_front_door_test.go @@ -331,7 +331,7 @@ resource "azurerm_frontdoor" "test" { custom_https_provisioning_enabled = false } } -`, data.RandomInteger, data.RandomInteger, data.RandomInteger) +`, data.RandomInteger, data.Locations.Primary, data.RandomInteger, data.RandomInteger) } func testAccAzureRMFrontDoor_basicDisabled(data acceptance.TestData) string { @@ -397,7 +397,7 @@ resource "azurerm_frontdoor" "test" { custom_https_provisioning_enabled = false } } -`, data.RandomInteger, data.RandomInteger, data.RandomInteger) +`, data.RandomInteger, data.Locations.Primary, data.RandomInteger, data.RandomInteger) } func testAccAzureRMFrontDoor_requiresImport(data acceptance.TestData) string { @@ -512,7 +512,7 @@ resource "azurerm_frontdoor" "test" { custom_https_provisioning_enabled = false } } -`, data.RandomInteger, data.RandomInteger, data.RandomInteger) +`, data.RandomInteger, data.Locations.Primary, data.RandomInteger, data.RandomInteger) } func testAccAzureRMFrontDoor_waf(data acceptance.TestData) string { @@ -583,7 +583,7 @@ resource "azurerm_frontdoor" "test" { web_application_firewall_policy_link_id = azurerm_frontdoor_firewall_policy.test.id } } -`, data.RandomInteger, data.RandomInteger, data.RandomInteger, data.RandomInteger) +`, data.RandomInteger, data.Locations.Primary, data.RandomInteger, data.RandomInteger, data.RandomInteger) } func testAccAzureRMFrontDoor_DisableCache(data acceptance.TestData) string { @@ -647,7 +647,7 @@ resource "azurerm_frontdoor" "test" { custom_https_provisioning_enabled = false } } -`, data.RandomInteger, data.RandomInteger, data.RandomInteger) +`, data.RandomInteger, data.Locations.Primary, data.RandomInteger, data.RandomInteger) } func testAccAzureRMFrontDoor_EnableCache(data acceptance.TestData) string { @@ -713,7 +713,7 @@ resource "azurerm_frontdoor" "test" { custom_https_provisioning_enabled = false } } -`, data.RandomInteger, data.RandomInteger, data.RandomInteger) +`, data.RandomInteger, data.Locations.Primary, data.RandomInteger, data.RandomInteger) } func testAccAzureRMFrontDoor_CustomHttpsEnabled(data acceptance.TestData) string { @@ -781,7 +781,7 @@ resource "azurerm_frontdoor" "test" { } } } -`, data.RandomInteger, data.RandomInteger, data.RandomInteger) +`, data.RandomInteger, data.Locations.Primary, data.RandomInteger, data.RandomInteger) } func testAccAzureRMFrontDoor_CustomHttpsDisabled(data acceptance.TestData) string { @@ -846,7 +846,7 @@ resource "azurerm_frontdoor" "test" { custom_https_provisioning_enabled = false } } -`, data.RandomInteger, data.RandomInteger, data.RandomInteger) +`, data.RandomInteger, data.Locations.Primary, data.RandomInteger, data.RandomInteger) } func testAccAzureRMFrontDoor_multiplePools(data acceptance.TestData) string { diff --git a/azurerm/internal/services/frontdoor/validate/validate.go b/azurerm/internal/services/frontdoor/validate/validate.go index 8514fa78401e..0121faade00b 100644 --- a/azurerm/internal/services/frontdoor/validate/validate.go +++ b/azurerm/internal/services/frontdoor/validate/validate.go @@ -236,4 +236,4 @@ func azureKeyVaultCertificateHasValues(customHttpsConfiguration map[string]inter } return false -} \ No newline at end of file +} From 922b97abcdde4e918989ab61acbc89bbdf6a2eb8 Mon Sep 17 00:00:00 2001 From: WS <20408400+WodansSon@users.noreply.github.com> Date: Mon, 9 Mar 2020 15:00:23 -0700 Subject: [PATCH 3/4] Update azurerm/internal/services/frontdoor/resource_arm_frontdoor.go Co-Authored-By: kt --- azurerm/internal/services/frontdoor/resource_arm_frontdoor.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/azurerm/internal/services/frontdoor/resource_arm_frontdoor.go b/azurerm/internal/services/frontdoor/resource_arm_frontdoor.go index c36808536dc1..03c24369e1ef 100644 --- a/azurerm/internal/services/frontdoor/resource_arm_frontdoor.go +++ b/azurerm/internal/services/frontdoor/resource_arm_frontdoor.go @@ -71,7 +71,7 @@ func resourceArmFrontDoor() *schema.Resource { Type: schema.TypeString, Optional: true, Computed: true, - Deprecated: "per resource provider change, 'location' is no longer valid and will always be set to 'Global', however if the Front Door service was created prior to the v2.1.0 release of the provider it may continue to exist in its current location", + Deprecated: "Due to the service's API changing 'location' must now always be set to 'Global' for new resources, however if the Front Door service was created prior 2020/03/10 it may continue to exist in a specific current location", }, "resource_group_name": azure.SchemaResourceGroupName(), From ef438b9a01b82d47b0fa167e9b86cf305ee61445 Mon Sep 17 00:00:00 2001 From: Jeffrey Cline <20408400+WodansSon@users.noreply.github.com> Date: Mon, 9 Mar 2020 17:18:56 -0700 Subject: [PATCH 4/4] Add default global test --- .../frontdoor/resource_arm_frontdoor.go | 4 +- .../tests/resource_arm_front_door_test.go | 87 +++++++++++++++++++ 2 files changed, 90 insertions(+), 1 deletion(-) diff --git a/azurerm/internal/services/frontdoor/resource_arm_frontdoor.go b/azurerm/internal/services/frontdoor/resource_arm_frontdoor.go index 03c24369e1ef..754b2d07c43c 100644 --- a/azurerm/internal/services/frontdoor/resource_arm_frontdoor.go +++ b/azurerm/internal/services/frontdoor/resource_arm_frontdoor.go @@ -67,6 +67,7 @@ func resourceArmFrontDoor() *schema.Resource { Required: true, }, + // remove in 3.0 "location": { Type: schema.TypeString, Optional: true, @@ -495,6 +496,7 @@ func resourceArmFrontDoorCreateUpdate(d *schema.ResourceData, meta interface{}) } } + // remove in 3.0 // due to a change in the RP, if a Frontdoor exists in a location other than 'Global' it may continue to // exist in that location, if this is a brand new Frontdoor it must be created in the 'Global' location location := "Global" @@ -674,7 +676,7 @@ func resourceArmFrontDoorRead(d *schema.ResourceData, meta interface{}) error { d.Set("name", resp.Name) d.Set("resource_group_name", resourceGroup) - d.Set("location", "") + d.Set("location", azure.NormalizeLocation(*resp.Location)) if properties := resp.Properties; properties != nil { if err := d.Set("backend_pool", flattenArmFrontDoorBackendPools(properties.BackendPools)); err != nil { diff --git a/azurerm/internal/services/frontdoor/tests/resource_arm_front_door_test.go b/azurerm/internal/services/frontdoor/tests/resource_arm_front_door_test.go index 06c53b43f70d..9f1a6459711d 100644 --- a/azurerm/internal/services/frontdoor/tests/resource_arm_front_door_test.go +++ b/azurerm/internal/services/frontdoor/tests/resource_arm_front_door_test.go @@ -40,6 +40,27 @@ func TestAccAzureRMFrontDoor_basic(t *testing.T) { }) } +// remove in 3.0 +func TestAccAzureRMFrontDoor_global(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_frontdoor", "test") + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { acceptance.PreCheck(t) }, + Providers: acceptance.SupportedProviders, + CheckDestroy: testCheckAzureRMFrontDoorDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAzureRMFrontDoor_global(data), + Check: resource.ComposeTestCheckFunc( + testCheckAzureRMFrontDoorExists(data.ResourceName), + resource.TestCheckResourceAttr(data.ResourceName, "location", "global"), + ), + ExpectNonEmptyPlan: true, + }, + data.ImportStep(), + }, + }) +} + func TestAccAzureRMFrontDoor_requiresImport(t *testing.T) { if !features.ShouldResourcesBeImported() { t.Skip("Skipping since resources aren't required to be imported") @@ -400,6 +421,72 @@ resource "azurerm_frontdoor" "test" { `, data.RandomInteger, data.Locations.Primary, data.RandomInteger, data.RandomInteger) } +// remove in 3.0 +func testAccAzureRMFrontDoor_global(data acceptance.TestData) string { + return fmt.Sprintf(` +provider "azurerm" { + features {} +} + +resource "azurerm_resource_group" "test" { + name = "acctestRG-frontdoor-%d" + location = "%s" +} + +locals { + backend_name = "backend-bing" + endpoint_name = "frontend-endpoint" + health_probe_name = "health-probe" + load_balancing_name = "load-balancing-setting" +} + +resource "azurerm_frontdoor" "test" { + name = "acctest-FD-%d" + resource_group_name = azurerm_resource_group.test.name + location = "%s" + enforce_backend_pools_certificate_name_check = false + + routing_rule { + name = "routing-rule" + accepted_protocols = ["Http", "Https"] + patterns_to_match = ["/*"] + frontend_endpoints = [local.endpoint_name] + forwarding_configuration { + forwarding_protocol = "MatchRequest" + backend_pool_name = local.backend_name + } + } + + backend_pool_load_balancing { + name = local.load_balancing_name + } + + backend_pool_health_probe { + name = local.health_probe_name + } + + backend_pool { + name = local.backend_name + backend { + host_header = "www.bing.com" + address = "www.bing.com" + http_port = 80 + https_port = 443 + } + + load_balancing_name = local.load_balancing_name + health_probe_name = local.health_probe_name + } + + frontend_endpoint { + name = local.endpoint_name + host_name = "acctest-FD-%d.azurefd.net" + custom_https_provisioning_enabled = false + } +} +`, data.RandomInteger, data.Locations.Primary, data.RandomInteger, data.Locations.Primary, data.RandomInteger) +} + func testAccAzureRMFrontDoor_requiresImport(data acceptance.TestData) string { template := testAccAzureRMFrontDoor_basic(data) return fmt.Sprintf(`