From 1e94b76a2afd58f65ac416c5dd0abfe588162dde Mon Sep 17 00:00:00 2001 From: tombuildsstuff Date: Wed, 12 Aug 2020 11:53:16 +0200 Subject: [PATCH 01/41] internal/resourceid: adding an interface for Resource ID Rewriting --- azurerm/internal/resourceid/interface.go | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 azurerm/internal/resourceid/interface.go diff --git a/azurerm/internal/resourceid/interface.go b/azurerm/internal/resourceid/interface.go new file mode 100644 index 000000000000..4f6a793f6a5e --- /dev/null +++ b/azurerm/internal/resourceid/interface.go @@ -0,0 +1,5 @@ +package resourceid + +type Formatter interface { + ID(subscriptionId string) string +} From ed3992f002cc4326f5d8d0f8835a296c39123f04 Mon Sep 17 00:00:00 2001 From: tombuildsstuff Date: Wed, 12 Aug 2020 11:54:41 +0200 Subject: [PATCH 02/41] r/frontdoor: adding parsing functions --- .../services/frontdoor/parse/frontdoor.go | 63 +++++++++++++++++++ .../parse/frontdoor_frontend_endpoint.go | 46 ++++++++++++++ .../parse/frontdoor_frontend_endpoint_test.go | 5 ++ .../frontdoor/parse/frontdoor_test.go | 5 ++ 4 files changed, 119 insertions(+) create mode 100644 azurerm/internal/services/frontdoor/parse/frontdoor.go create mode 100644 azurerm/internal/services/frontdoor/parse/frontdoor_frontend_endpoint.go create mode 100644 azurerm/internal/services/frontdoor/parse/frontdoor_frontend_endpoint_test.go create mode 100644 azurerm/internal/services/frontdoor/parse/frontdoor_test.go diff --git a/azurerm/internal/services/frontdoor/parse/frontdoor.go b/azurerm/internal/services/frontdoor/parse/frontdoor.go new file mode 100644 index 000000000000..b4d714624b8a --- /dev/null +++ b/azurerm/internal/services/frontdoor/parse/frontdoor.go @@ -0,0 +1,63 @@ +package parse + +import ( + "fmt" + + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/helpers/azure" +) + +// TODO: tests + +type FrontDoorId struct { + Name string + ResourceGroup string +} + +func NewFrontDoorID(resourceGroup, name string) FrontDoorId { + return FrontDoorId{ + Name: name, + ResourceGroup: resourceGroup, + } +} + +func FrontDoorID(input string) (*FrontDoorId, error) { + frontDoorId, id, err := parseFrontDoorChildResourceId(input) + if err != nil { + return nil, fmt.Errorf("[ERROR] Unable to parse FrontDoor ID %q: %+v", input, err) + } + + if err := id.ValidateNoEmptySegments(input); err != nil { + return nil, err + } + + return frontDoorId, nil +} + +func (id FrontDoorId) ID(subscriptionId string) string { + return fmt.Sprintf("/subscriptions/%s/resourceGroups/%s/providers/Microsoft.Network/frontdoors/%s", subscriptionId, id.ResourceGroup, id.Name) +} + +func parseFrontDoorChildResourceId(input string) (*FrontDoorId, *azure.ResourceID, error) { + id, err := azure.ParseAzureResourceID(input) + if err != nil { + return nil, nil, err + } + + frontdoor := FrontDoorId{ + ResourceGroup: id.ResourceGroup, + } + + // TODO: ensure this is Normalized, presumably to frontdoor + // resourceGroup := id.ResourceGroup + // name := id.Path["frontdoors"] + // // Link to issue: https://github.com/Azure/azure-sdk-for-go/issues/6762 + // if name == "" { + // name = id.Path["Frontdoors"] + // } + + if frontdoor.Name, err = id.PopSegment("frontdoors"); err != nil { + return nil, nil, err + } + + return &frontdoor, id, nil +} diff --git a/azurerm/internal/services/frontdoor/parse/frontdoor_frontend_endpoint.go b/azurerm/internal/services/frontdoor/parse/frontdoor_frontend_endpoint.go new file mode 100644 index 000000000000..16f7792995aa --- /dev/null +++ b/azurerm/internal/services/frontdoor/parse/frontdoor_frontend_endpoint.go @@ -0,0 +1,46 @@ +package parse + +import "fmt" + +type FrontDoorFrontendEndpointId struct { + ResourceGroup string + FrontDoorName string + Name string +} + +func NewFrontDoorFrontendEndpointID(id FrontDoorId, name string) FrontDoorFrontendEndpointId { + return FrontDoorFrontendEndpointId{ + ResourceGroup: id.ResourceGroup, + FrontDoorName: id.Name, + Name: name, + } +} + +func (id FrontDoorFrontendEndpointId) ID(subscriptionId string) string { + base := NewFrontDoorID(id.ResourceGroup, id.Name).ID(subscriptionId) + return fmt.Sprintf("%s/frontendEndpoints/%s", base, id.Name) +} + +func FrontDoorFrontendEndpointID(input string) (*FrontDoorFrontendEndpointId, error) { + frontDoorId, id, err := parseFrontDoorChildResourceId(input) + if err != nil { + return nil, fmt.Errorf("parsing FrontDoor Frontend Endpoint ID %q: %+v", input, err) + } + + endpointId := FrontDoorFrontendEndpointId{ + ResourceGroup: frontDoorId.ResourceGroup, + FrontDoorName: frontDoorId.Name, + } + + // TODO: handle this being case-insensitive + // https://github.com/Azure/azure-sdk-for-go/issues/6762 + if endpointId.Name, err = id.PopSegment("frontendEndpoints"); err != nil { + return nil, err + } + + if err := id.ValidateNoEmptySegments(input); err != nil { + return nil, err + } + + return nil, nil +} diff --git a/azurerm/internal/services/frontdoor/parse/frontdoor_frontend_endpoint_test.go b/azurerm/internal/services/frontdoor/parse/frontdoor_frontend_endpoint_test.go new file mode 100644 index 000000000000..4d2dc609d753 --- /dev/null +++ b/azurerm/internal/services/frontdoor/parse/frontdoor_frontend_endpoint_test.go @@ -0,0 +1,5 @@ +package parse + +import "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/resourceid" + +var _ resourceid.Formatter = FrontDoorFrontendEndpointId{} diff --git a/azurerm/internal/services/frontdoor/parse/frontdoor_test.go b/azurerm/internal/services/frontdoor/parse/frontdoor_test.go new file mode 100644 index 000000000000..6656662c0e50 --- /dev/null +++ b/azurerm/internal/services/frontdoor/parse/frontdoor_test.go @@ -0,0 +1,5 @@ +package parse + +import "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/resourceid" + +var _ resourceid.Formatter = FrontDoorId{} From c1aa99601d6b930b4cf9f3e6e9588b935358764d Mon Sep 17 00:00:00 2001 From: tombuildsstuff Date: Wed, 12 Aug 2020 11:54:50 +0200 Subject: [PATCH 03/41] r/frontdoor: switching the frontendEndpoints to use the custom parsers Also fixing issues where fields aren't set into the state to ensure that fields always have a value --- .../frontdoor_custom_https_configuration.go | 84 ++++--- ...oor_custom_https_configuration_resource.go | 10 +- .../services/frontdoor/frontdoor_resource.go | 222 ++++++++++-------- 3 files changed, 174 insertions(+), 142 deletions(-) diff --git a/azurerm/helpers/azure/frontdoor_custom_https_configuration.go b/azurerm/helpers/azure/frontdoor_custom_https_configuration.go index 0715272a3db1..09de1fe595c9 100644 --- a/azurerm/helpers/azure/frontdoor_custom_https_configuration.go +++ b/azurerm/helpers/azure/frontdoor_custom_https_configuration.go @@ -1,8 +1,6 @@ package azure import ( - "fmt" - "github.com/Azure/azure-sdk-for-go/services/frontdoor/mgmt/2020-01-01/frontdoor" "github.com/hashicorp/terraform-plugin-sdk/helper/schema" "github.com/hashicorp/terraform-plugin-sdk/helper/validation" @@ -48,47 +46,65 @@ func SchemaFrontdoorCustomHttpsConfiguration() map[string]*schema.Schema { } } -func FlattenArmFrontDoorCustomHttpsConfiguration(input *frontdoor.FrontendEndpoint, output map[string]interface{}, resourceGroup string) error { - if input == nil { - return fmt.Errorf("cannot read Front Door Frontend Endpoint (Resource Group %q): endpoint is empty", resourceGroup) - } +type FlattenedCustomHttpsConfiguration struct { + CustomHTTPSConfiguration []interface{} + CustomHTTPSProvisioningEnabled bool +} - customHttpsConfiguration := make([]interface{}, 0) - chc := make(map[string]interface{}) +func FlattenArmFrontDoorCustomHttpsConfiguration(properties frontdoor.FrontendEndpointProperties) FlattenedCustomHttpsConfiguration { + customHttpsConfig := make([]interface{}, 0) + customHttpsProvisioningEnabled := false - if properties := input.FrontendEndpointProperties; properties != nil { - if properties.CustomHTTPSConfiguration != nil { - customHTTPSConfiguration := properties.CustomHTTPSConfiguration - if customHTTPSConfiguration.CertificateSource == frontdoor.CertificateSourceAzureKeyVault { - if kvcsp := customHTTPSConfiguration.KeyVaultCertificateSourceParameters; kvcsp != nil { - chc["certificate_source"] = string(frontdoor.CertificateSourceAzureKeyVault) - chc["azure_key_vault_certificate_vault_id"] = *kvcsp.Vault.ID - chc["azure_key_vault_certificate_secret_name"] = *kvcsp.SecretName - chc["azure_key_vault_certificate_secret_version"] = *kvcsp.SecretVersion - } - } else { - chc["certificate_source"] = string(frontdoor.CertificateSourceFrontDoor) - } + if config := properties.CustomHTTPSConfiguration; config != nil { + certificateSource := string(frontdoor.CertificateSourceFrontDoor) + + keyVaultCertificateVaultId := "" + keyVaultCertificateSecretName := "" + keyVaultCertificateSecretVersion := "" + if config.CertificateSource == frontdoor.CertificateSourceAzureKeyVault { + if vault := config.KeyVaultCertificateSourceParameters; vault != nil { + certificateSource = string(frontdoor.CertificateSourceAzureKeyVault) - chc["minimum_tls_version"] = string(customHTTPSConfiguration.MinimumTLSVersion) + if vault.Vault != nil && vault.Vault.ID != nil { + keyVaultCertificateVaultId = *vault.Vault.ID + } - if provisioningState := properties.CustomHTTPSProvisioningState; provisioningState != "" { - chc["provisioning_state"] = provisioningState - if provisioningState == frontdoor.CustomHTTPSProvisioningStateEnabled || provisioningState == frontdoor.CustomHTTPSProvisioningStateEnabling { - output["custom_https_provisioning_enabled"] = true + if vault.SecretName != nil { + keyVaultCertificateSecretName = *vault.SecretName + } - if provisioningSubstate := properties.CustomHTTPSProvisioningSubstate; provisioningSubstate != "" { - chc["provisioning_substate"] = provisioningSubstate - } - } else { - output["custom_https_provisioning_enabled"] = false + if vault.SecretVersion != nil { + keyVaultCertificateSecretVersion = *vault.SecretVersion } + } + } + + provisioningState := "" + provisioningSubstate := "" + if properties.CustomHTTPSProvisioningState != "" { + provisioningState = string(properties.CustomHTTPSProvisioningState) + if properties.CustomHTTPSProvisioningState == frontdoor.CustomHTTPSProvisioningStateEnabled || properties.CustomHTTPSProvisioningState == frontdoor.CustomHTTPSProvisioningStateEnabling { + customHttpsProvisioningEnabled = true - customHttpsConfiguration = append(customHttpsConfiguration, chc) - output["custom_https_configuration"] = customHttpsConfiguration + if properties.CustomHTTPSProvisioningSubstate != "" { + provisioningSubstate = string(properties.CustomHTTPSProvisioningSubstate) + } } + + customHttpsConfig = append(customHttpsConfig, map[string]interface{}{ + "azure_key_vault_certificate_vault_id": keyVaultCertificateVaultId, + "azure_key_vault_certificate_secret_name": keyVaultCertificateSecretName, + "azure_key_vault_certificate_secret_version": keyVaultCertificateSecretVersion, + "certificate_source": certificateSource, + "minimum_tls_version": string(config.MinimumTLSVersion), + "provisioning_state": provisioningState, + "provisioning_substate": provisioningSubstate, + }) } } - return nil + return FlattenedCustomHttpsConfiguration{ + CustomHTTPSConfiguration: customHttpsConfig, + CustomHTTPSProvisioningEnabled: customHttpsProvisioningEnabled, + } } diff --git a/azurerm/internal/services/frontdoor/frontdoor_custom_https_configuration_resource.go b/azurerm/internal/services/frontdoor/frontdoor_custom_https_configuration_resource.go index d60e14848c89..2a578ad8ac59 100644 --- a/azurerm/internal/services/frontdoor/frontdoor_custom_https_configuration_resource.go +++ b/azurerm/internal/services/frontdoor/frontdoor_custom_https_configuration_resource.go @@ -140,14 +140,12 @@ func resourceArmFrontDoorCustomHttpsConfigurationRead(d *schema.ResourceData, me d.Set("frontend_endpoint_id", resp.ID) if resp.Name != nil { - output := make(map[string]interface{}) - if err := azure.FlattenArmFrontDoorCustomHttpsConfiguration(&resp, output, *resp.Name); err != nil { - return fmt.Errorf("flattening `frontend_endpoint/custom_https_configuration`: %s", *resp.Name) - } - if err := d.Set("custom_https_configuration", output["custom_https_configuration"]); err != nil { + + flattenedHttpsConfig := azure.FlattenArmFrontDoorCustomHttpsConfiguration(*resp.FrontendEndpointProperties) + if err := d.Set("custom_https_configuration", flattenedHttpsConfig.CustomHTTPSConfiguration); err != nil { return fmt.Errorf("setting `custom_https_configuration`: %+v", err) } - if err := d.Set("custom_https_provisioning_enabled", output["custom_https_provisioning_enabled"]); err != nil { + if err := d.Set("custom_https_provisioning_enabled", flattenedHttpsConfig.CustomHTTPSProvisioningEnabled); err != nil { return fmt.Errorf("setting `custom_https_provisioning_enabled`: %+v", err) } } else { diff --git a/azurerm/internal/services/frontdoor/frontdoor_resource.go b/azurerm/internal/services/frontdoor/frontdoor_resource.go index 0bd1fc298e38..33c4cb647856 100644 --- a/azurerm/internal/services/frontdoor/frontdoor_resource.go +++ b/azurerm/internal/services/frontdoor/frontdoor_resource.go @@ -15,12 +15,15 @@ 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/parse" "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" ) +// TODO: a state migration to patch the ID's + func resourceArmFrontDoor() *schema.Resource { return &schema.Resource{ Create: resourceArmFrontDoorCreateUpdate, @@ -505,7 +508,11 @@ func resourceArmFrontDoorCreateUpdate(d *schema.ResourceData, meta interface{}) } } - frontDoorPath := fmt.Sprintf("/subscriptions/%s/resourcegroups/%s/providers/Microsoft.Network/Frontdoors/%s", subscriptionId, resourceGroup, name) + frontDoorId := parse.NewFrontDoorID(resourceGroup, name) + + // TODO: pass in ID directly then remove this + frontDoorPath := frontDoorId.ID(subscriptionId) + friendlyName := d.Get("friendly_name").(string) routingRules := d.Get("routing_rule").([]interface{}) loadBalancingSettings := d.Get("backend_pool_load_balancing").([]interface{}) @@ -525,7 +532,7 @@ func resourceArmFrontDoorCreateUpdate(d *schema.ResourceData, meta interface{}) RoutingRules: expandArmFrontDoorRoutingRule(routingRules, frontDoorPath), BackendPools: expandArmFrontDoorBackendPools(backendPools, frontDoorPath), BackendPoolsSettings: expandArmFrontDoorBackendPoolsSettings(backendPoolsSettings, backendPoolsSendReceiveTimeoutSeconds), - FrontendEndpoints: expandArmFrontDoorFrontendEndpoint(frontendEndpoints, frontDoorPath), + FrontendEndpoints: expandArmFrontDoorFrontendEndpoint(frontendEndpoints, frontDoorId, subscriptionId), HealthProbeSettings: expandArmFrontDoorHealthProbeSettingsModel(healthProbeSettings, frontDoorPath), LoadBalancingSettings: expandArmFrontDoorLoadBalancingSettingsModel(loadBalancingSettings, frontDoorPath), EnabledState: expandArmFrontDoorEnabledState(enabledState), @@ -541,14 +548,7 @@ func resourceArmFrontDoorCreateUpdate(d *schema.ResourceData, meta interface{}) 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("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) - } - d.SetId(*resp.ID) + d.SetId(frontDoorId.ID(subscriptionId)) // Now loop through the FrontendEndpoints and enable/disable Custom Domain HTTPS // on each individual Frontend Endpoint if required @@ -587,37 +587,31 @@ func resourceArmFrontDoorRead(d *schema.ResourceData, meta interface{}) error { ctx, cancel := timeouts.ForRead(meta.(*clients.Client).StopContext, d) defer cancel() - id, err := azure.ParseAzureResourceID(d.Id()) + id, err := parse.FrontDoorID(d.Id()) if err != nil { return err } - resourceGroup := id.ResourceGroup - name := id.Path["frontdoors"] - // Link to issue: https://github.com/Azure/azure-sdk-for-go/issues/6762 - if name == "" { - name = id.Path["Frontdoors"] - } - resp, err := client.Get(ctx, resourceGroup, name) + resp, err := client.Get(ctx, id.ResourceGroup, id.Name) if err != nil { if utils.ResponseWasNotFound(resp.Response) { log.Printf("[INFO] Front Door %q does not exist - removing from state", d.Id()) d.SetId("") return nil } - return fmt.Errorf("reading Front Door %q (Resource Group %q): %+v", name, resourceGroup, err) + return fmt.Errorf("reading Front Door %q (Resource Group %q): %+v", id.Name, id.ResourceGroup, err) } - d.Set("name", resp.Name) - d.Set("resource_group_name", resourceGroup) + d.Set("name", id.Name) + d.Set("resource_group_name", id.ResourceGroup) d.Set("location", azure.NormalizeLocation(*resp.Location)) - if properties := resp.Properties; properties != nil { - if err := d.Set("backend_pool", flattenArmFrontDoorBackendPools(properties.BackendPools)); err != nil { + if props := resp.Properties; props != nil { + if err := d.Set("backend_pool", flattenArmFrontDoorBackendPools(props.BackendPools)); err != nil { return fmt.Errorf("setting `backend_pool`: %+v", err) } - backendPoolSettings := flattenArmFrontDoorBackendPoolsSettings(properties.BackendPoolsSettings) + backendPoolSettings := flattenArmFrontDoorBackendPoolsSettings(props.BackendPoolsSettings) if err := d.Set("enforce_backend_pools_certificate_name_check", backendPoolSettings["enforce_backend_pools_certificate_name_check"].(bool)); err != nil { return fmt.Errorf("setting `enforce_backend_pools_certificate_name_check`: %+v", err) @@ -627,34 +621,39 @@ func resourceArmFrontDoorRead(d *schema.ResourceData, meta interface{}) error { return fmt.Errorf("setting `backend_pools_send_receive_timeout_seconds`: %+v", err) } - d.Set("cname", properties.Cname) - d.Set("header_frontdoor_id", properties.FrontdoorID) - d.Set("load_balancer_enabled", properties.EnabledState == frontdoor.EnabledStateEnabled) - d.Set("friendly_name", properties.FriendlyName) + d.Set("cname", props.Cname) + d.Set("header_frontdoor_id", props.FrontdoorID) + d.Set("load_balancer_enabled", props.EnabledState == frontdoor.EnabledStateEnabled) + d.Set("friendly_name", props.FriendlyName) - if frontendEndpoints := properties.FrontendEndpoints; frontendEndpoints != nil { - if resp.Name != nil { - if frontDoorFrontendEndpoints, err := flattenArmFrontDoorFrontendEndpoints(ctx, frontendEndpoints, resourceGroup, *resp.Name, meta); frontDoorFrontendEndpoints != nil { - if err := d.Set("frontend_endpoint", frontDoorFrontendEndpoints); err != nil { - return fmt.Errorf("setting `frontend_endpoint`: %+v", err) - } - } else { - return fmt.Errorf("flattening `frontend_endpoint`: %+v", err) - } - } else { - return fmt.Errorf("flattening `frontend_endpoint`: Unable to read Frontdoor Name") - } + // Need to call frontEndEndpointClient here to get custom(HTTPS)Configuration information from that client + // because the information is hidden from the main frontDoorClient "by design"... + frontEndEndpointsClient := meta.(*clients.Client).Frontdoor.FrontDoorsFrontendClient + frontEndEndpointInfo, err := retrieveFrontEndEndpointInformation(ctx, frontEndEndpointsClient, *id, props.FrontendEndpoints) + if err != nil { + return fmt.Errorf("retrieving FrontEnd Endpoint Custom HTTPS Information: %+v", err) + } + frontDoorFrontendEndpoints, err := flattenFrontEndEndpoints(frontEndEndpointInfo) + if err != nil { + return fmt.Errorf("flattening `frontend_endpoint`: %+v", err) + } + if err := d.Set("frontend_endpoint", frontDoorFrontendEndpoints); err != nil { + return fmt.Errorf("setting `frontend_endpoint`: %+v", err) } - if err := d.Set("backend_pool_health_probe", flattenArmFrontDoorHealthProbeSettingsModel(properties.HealthProbeSettings)); err != nil { + if err := d.Set("backend_pool_health_probe", flattenArmFrontDoorHealthProbeSettingsModel(props.HealthProbeSettings)); err != nil { return fmt.Errorf("setting `backend_pool_health_probe`: %+v", err) } - if err := d.Set("backend_pool_load_balancing", flattenArmFrontDoorLoadBalancingSettingsModel(properties.LoadBalancingSettings)); err != nil { + if err := d.Set("backend_pool_load_balancing", flattenArmFrontDoorLoadBalancingSettingsModel(props.LoadBalancingSettings)); err != nil { 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 { + flattenedRoutingRules, err := flattenArmFrontDoorRoutingRule(props.RoutingRules, d.Get("routing_rule")) + if err != nil { + return fmt.Errorf("flattening `routing_rules`: %+v", err) + } + if err := d.Set("routing_rule", flattenedRoutingRules); err != nil { return fmt.Errorf("setting `routing_rules`: %+v", err) } } @@ -788,7 +787,7 @@ func expandArmFrontDoorBackendPoolsSettings(enforceCertificateNameCheck bool, ba return &result } -func expandArmFrontDoorFrontendEndpoint(input []interface{}, frontDoorPath string) *[]frontdoor.FrontendEndpoint { +func expandArmFrontDoorFrontendEndpoint(input []interface{}, frontDoorId parse.FrontDoorId, subscriptionId string) *[]frontdoor.FrontendEndpoint { if len(input) == 0 { return &[]frontdoor.FrontendEndpoint{} } @@ -803,7 +802,7 @@ func expandArmFrontDoorFrontendEndpoint(input []interface{}, frontDoorPath strin sessionAffinityTtlSeconds := int32(frontendEndpoint["session_affinity_ttl_seconds"].(int)) waf := frontendEndpoint["web_application_firewall_policy_link_id"].(string) name := frontendEndpoint["name"].(string) - id := utils.String(frontDoorPath + "/FrontendEndpoints/" + name) + id := parse.NewFrontDoorFrontendEndpointID(frontDoorId, name).ID(subscriptionId) sessionAffinityEnabled := frontdoor.SessionAffinityEnabledStateDisabled if isSessionAffinityEnabled { @@ -811,7 +810,7 @@ func expandArmFrontDoorFrontendEndpoint(input []interface{}, frontDoorPath strin } result := frontdoor.FrontendEndpoint{ - ID: id, + ID: utils.String(id), Name: utils.String(name), FrontendEndpointProperties: &frontdoor.FrontendEndpointProperties{ HostName: utils.String(hostName), @@ -1187,75 +1186,86 @@ func flattenArmFrontDoorBackend(input *[]frontdoor.Backend) []interface{} { return output } -func flattenArmFrontDoorFrontendEndpoints(ctx context.Context, 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) +func retrieveFrontEndEndpointInformation(ctx context.Context, client *frontdoor.FrontendEndpointsClient, frontDoorId parse.FrontDoorId, endpoints *[]frontdoor.FrontendEndpoint) (*[]frontdoor.FrontendEndpoint, interface{}) { + output := make([]frontdoor.FrontendEndpoint, 0) + if endpoints == nil { + return &output, nil } - output := make([]interface{}, 0) + for _, endpoint := range *endpoints { + if endpoint.Name == nil { + continue + } - for _, v := range *input { - result, err := flattenArmFrontDoorFrontendEndpoint(ctx, &v, resourceGroup, frontDoorName, meta) + name := *endpoint.Name + resp, err := client.Get(ctx, frontDoorId.ResourceGroup, frontDoorId.Name, name) if err != nil { - return make([]interface{}, 0), fmt.Errorf("retrieving Front Door Frontend Endpoint Custom HTTPS Configuration %q (Resource Group %q): %+v", *v.Name, resourceGroup, err) + return nil, fmt.Errorf("retrieving Custom HTTPS Configuration for Frontend Endpoint %q (FrontDoor %q / Resource Group %q): %+v", name, frontDoorId.Name, frontDoorId.ResourceGroup, err) } - output = append(output, result) + output = append(output, resp) } - return output, nil + return &output, nil } -func flattenArmFrontDoorFrontendEndpoint(ctx context.Context, input *frontdoor.FrontendEndpoint, resourceGroup string, frontDoorName string, meta interface{}) (map[string]interface{}, error) { +func flattenFrontEndEndpoints(input *[]frontdoor.FrontendEndpoint) (*[]interface{}, error) { + results := make([]interface{}, 0) if input == nil { - return make(map[string]interface{}), fmt.Errorf("cannot read Front Door Frontend Endpoint (Resource Group %q): endpoint is empty", resourceGroup) + return &results, nil } - output := make(map[string]interface{}) - - if name := input.Name; name != nil { - output["name"] = *name - - // Need to call frontEndEndpointClient here to get customConfiguration information from that client - // because the information is hidden from the main frontDoorClient "by design"... - client := meta.(*clients.Client).Frontdoor.FrontDoorsFrontendClient - - resp, err := client.Get(ctx, resourceGroup, frontDoorName, *name) - if err != nil { - return make(map[string]interface{}), fmt.Errorf("retrieving Front Door Frontend Endpoint Custom HTTPS Configuration %q (Resource Group %q): %+v", *name, resourceGroup, err) + for _, item := range *input { + id := "" + if item.ID != nil { + id = *item.ID } - if resp.ID == nil { - return make(map[string]interface{}), fmt.Errorf("cannot read Front Door Frontend Endpoint Custom HTTPS Configuration %q (Resource Group %q) ID", *name, resourceGroup) + name := "" + if item.Name != nil { + name = *item.Name } - output["id"] = resp.ID - - if props := resp.FrontendEndpointProperties; props != nil { - if hostName := props.HostName; hostName != nil { - output["host_name"] = *hostName + customHTTPSConfiguration := make([]interface{}, 0) + customHttpsProvisioningEnabled := false + hostName := "" + sessionAffinityEnabled := false + sessionAffinityTlsSeconds := 0 + webApplicationFirewallPolicyLinkId := "" + if props := item.FrontendEndpointProperties; props != nil { + if props.HostName != nil { + hostName = *props.HostName } - if sessionAffinityEnabled := props.SessionAffinityEnabledState; sessionAffinityEnabled != "" { - output["session_affinity_enabled"] = sessionAffinityEnabled == frontdoor.SessionAffinityEnabledStateEnabled + if props.SessionAffinityEnabledState != "" { + sessionAffinityEnabled = props.SessionAffinityEnabledState == frontdoor.SessionAffinityEnabledStateEnabled } - if sessionAffinityTtlSeconds := props.SessionAffinityTTLSeconds; sessionAffinityTtlSeconds != nil { - output["session_affinity_ttl_seconds"] = *sessionAffinityTtlSeconds + if props.SessionAffinityTTLSeconds != nil { + sessionAffinityTlsSeconds = int(*props.SessionAffinityTTLSeconds) } - if waf := props.WebApplicationFirewallPolicyLink; waf != nil { - output["web_application_firewall_policy_link_id"] = *waf.ID + if waf := props.WebApplicationFirewallPolicyLink; waf != nil && waf.ID != nil { + webApplicationFirewallPolicyLinkId = *waf.ID } - if props.CustomHTTPSConfiguration != nil { - if err := azure.FlattenArmFrontDoorCustomHttpsConfiguration(&resp, output, *name); err != nil { - return nil, fmt.Errorf("setting `custom_https_configuration`: %+v", err) - } - } + flattenedHttpsConfig := azure.FlattenArmFrontDoorCustomHttpsConfiguration(*props) + customHTTPSConfiguration = flattenedHttpsConfig.CustomHTTPSConfiguration + customHttpsProvisioningEnabled = flattenedHttpsConfig.CustomHTTPSProvisioningEnabled } + + results = append(results, map[string]interface{}{ + "custom_https_configuration": customHTTPSConfiguration, + "custom_https_provisioning_enabled": customHttpsProvisioningEnabled, + "host_name": hostName, + "id": id, + "name": name, + "session_affinity_enabled": sessionAffinityEnabled, + "session_affinity_ttl_seconds": sessionAffinityTlsSeconds, + "web_application_firewall_policy_link_id": webApplicationFirewallPolicyLinkId, + }) } - return output, nil + return &results, nil } func flattenArmFrontDoorHealthProbeSettingsModel(input *[]frontdoor.HealthProbeSettingsModel) []interface{} { @@ -1328,9 +1338,9 @@ func flattenArmFrontDoorLoadBalancingSettingsModel(input *[]frontdoor.LoadBalanc return results } -func flattenArmFrontDoorRoutingRule(input *[]frontdoor.RoutingRule, oldBlocks interface{}) []interface{} { +func flattenArmFrontDoorRoutingRule(input *[]frontdoor.RoutingRule, oldBlocks interface{}) (*[]interface{}, error) { if input == nil { - return make([]interface{}, 0) + return &[]interface{}{}, nil } oldByName := map[string]map[string]interface{}{} @@ -1357,7 +1367,11 @@ func flattenArmFrontDoorRoutingRule(input *[]frontdoor.RoutingRule, oldBlocks in if properties := v.RoutingRuleProperties; properties != nil { result["accepted_protocols"] = flattenArmFrontDoorAcceptedProtocol(properties.AcceptedProtocols) result["enabled"] = properties.EnabledState == frontdoor.RoutingRuleEnabledStateEnabled - result["frontend_endpoints"] = flattenArmFrontDoorFrontendEndpointsSubResources(properties.FrontendEndpoints) + frontendEndpoints, err := flattenArmFrontDoorFrontendEndpointsSubResources(properties.FrontendEndpoints) + if err != nil { + return nil, err + } + result["frontend_endpoints"] = frontendEndpoints if patternsToMatch := properties.PatternsToMatch; patternsToMatch != nil { result["patterns_to_match"] = *patternsToMatch } @@ -1429,7 +1443,7 @@ func flattenArmFrontDoorRoutingRule(input *[]frontdoor.RoutingRule, oldBlocks in output = append(output, result) } - return output + return &output, nil } func flattenArmFrontDoorAcceptedProtocol(input *[]frontdoor.Protocol) []string { @@ -1463,21 +1477,25 @@ func flattenArmFrontDoorSubResource(input *frontdoor.SubResource, resourceType s return name } -func flattenArmFrontDoorFrontendEndpointsSubResources(input *[]frontdoor.SubResource) []string { +func flattenArmFrontDoorFrontendEndpointsSubResources(input *[]frontdoor.SubResource) (*[]string, error) { + output := make([]string, 0) + if input == nil { - return make([]string, 0) + return &output, nil } - output := make([]string, 0) - for _, v := range *input { - name := flattenArmFrontDoorSubResource(&v, "FrontendEndpoints") - // Link to issue: https://github.com/Azure/azure-sdk-for-go/issues/6762 - if name == "" { - name = flattenArmFrontDoorSubResource(&v, "frontendEndpoints") + if v.ID == nil { + continue } - output = append(output, name) + + id, err := parse.FrontDoorFrontendEndpointID(*v.ID) + if err != nil { + return nil, err + } + + output = append(output, id.Name) } - return output + return &output, nil } From 536a5edb2810c8caba0b6bf97612babb443b7361 Mon Sep 17 00:00:00 2001 From: tombuildsstuff Date: Wed, 12 Aug 2020 12:48:58 +0200 Subject: [PATCH 04/41] r/frontdoor: refactoring the backendpool flatten methods --- .../services/frontdoor/frontdoor_resource.go | 215 +++++++++++------- azurerm/internal/services/frontdoor/helper.go | 13 -- .../frontdoor/parse/frontdoor_backend_pool.go | 46 ++++ 3 files changed, 182 insertions(+), 92 deletions(-) create mode 100644 azurerm/internal/services/frontdoor/parse/frontdoor_backend_pool.go diff --git a/azurerm/internal/services/frontdoor/frontdoor_resource.go b/azurerm/internal/services/frontdoor/frontdoor_resource.go index 33c4cb647856..106115adb642 100644 --- a/azurerm/internal/services/frontdoor/frontdoor_resource.go +++ b/azurerm/internal/services/frontdoor/frontdoor_resource.go @@ -1343,107 +1343,164 @@ func flattenArmFrontDoorRoutingRule(input *[]frontdoor.RoutingRule, oldBlocks in return &[]interface{}{}, nil } - oldByName := map[string]map[string]interface{}{} - - for _, i := range oldBlocks.([]interface{}) { - v := i.(map[string]interface{}) - - oldByName[v["name"].(string)] = v - } - output := make([]interface{}, 0) for _, v := range *input { - result := make(map[string]interface{}) - - if id := v.ID; id != nil { - result["id"] = *id + id := "" + if v.ID != nil { + id = *v.ID } - name := v.Name - if name != nil { - result["name"] = *name + name := "" + if v.Name != nil { + name = *v.Name } - if properties := v.RoutingRuleProperties; properties != nil { - result["accepted_protocols"] = flattenArmFrontDoorAcceptedProtocol(properties.AcceptedProtocols) - result["enabled"] = properties.EnabledState == frontdoor.RoutingRuleEnabledStateEnabled - frontendEndpoints, err := flattenArmFrontDoorFrontendEndpointsSubResources(properties.FrontendEndpoints) + acceptedProtocols := make([]string, 0) + enabled := false + forwardingConfiguration := make([]interface{}, 0) + frontEndEndpoints := make([]string, 0) + patternsToMatch := make([]string, 0) + redirectConfiguration := make([]interface{}, 0) + if props := v.RoutingRuleProperties; props != nil { + acceptedProtocols = flattenArmFrontDoorAcceptedProtocol(props.AcceptedProtocols) + enabled = props.EnabledState == frontdoor.RoutingRuleEnabledStateEnabled + + forwardConfiguration, err := flattenRoutingRuleForwardingConfiguration(props.RouteConfiguration, oldBlocks) + if err != nil { + return nil, err + } + forwardingConfiguration = *forwardConfiguration + + frontendEndpoints, err := flattenArmFrontDoorFrontendEndpointsSubResources(props.FrontendEndpoints) if err != nil { return nil, err } - result["frontend_endpoints"] = frontendEndpoints - if patternsToMatch := properties.PatternsToMatch; patternsToMatch != nil { - result["patterns_to_match"] = *patternsToMatch + frontEndEndpoints = *frontendEndpoints + + if props.PatternsToMatch != nil { + patternsToMatch = *props.PatternsToMatch } + redirectConfiguration = flattenRoutingRuleRedirectConfiguration(props.RouteConfiguration) + } - brc := properties.RouteConfiguration - if routeConfigType := GetFrontDoorBasicRouteConfigurationType(brc.(interface{})); routeConfigType != "" { - rc := make([]interface{}, 0) - c := make(map[string]interface{}) + output = append(output, map[string]interface{}{ + "accepted_protocols": acceptedProtocols, + "enabled": enabled, + "forwarding_configuration": forwardingConfiguration, + "frontend_endpoints": frontEndEndpoints, + "id": id, + "name": name, + "patterns_to_match": patternsToMatch, + "redirect_configuration": redirectConfiguration, + }) + } - // there are only two types of Route Configuration - if routeConfigType == "ForwardingConfiguration" { - v := brc.(frontdoor.ForwardingConfiguration) + return &output, nil +} - c["backend_pool_name"] = flattenArmFrontDoorSubResource(v.BackendPool, "BackendPools") - // Link to issue: https://github.com/Azure/azure-sdk-for-go/issues/6762 - if c["backend_pool_name"] == "" { - c["backend_pool_name"] = flattenArmFrontDoorSubResource(v.BackendPool, "backendPools") - } - c["custom_forwarding_path"] = v.CustomForwardingPath - c["forwarding_protocol"] = string(v.ForwardingProtocol) - - if cacheConfiguration := v.CacheConfiguration; cacheConfiguration != nil { - c["cache_enabled"] = true - if stripDirective := cacheConfiguration.QueryParameterStripDirective; stripDirective != "" { - c["cache_query_parameter_strip_directive"] = string(stripDirective) - } else { - // Default value if not set - c["cache_query_parameter_strip_directive"] = string(frontdoor.StripAll) - } +func flattenRoutingRuleForwardingConfiguration(config frontdoor.BasicRouteConfiguration, oldConfig interface{}) (*[]interface{}, error) { + v, ok := config.(frontdoor.ForwardingConfiguration) + if !ok { + return &[]interface{}{}, nil + } - if dynamicCompression := cacheConfiguration.DynamicCompression; dynamicCompression != "" { - c["cache_use_dynamic_compression"] = string(dynamicCompression) == string(frontdoor.DynamicCompressionEnabledEnabled) - } - } else { - // if the cache is disabled, set the default values or revert to what they were in the previous plan - c["cache_enabled"] = false - c["cache_query_parameter_strip_directive"] = string(frontdoor.StripAll) - - if name != nil { - // get `forwarding_configuration` - if o, ok := oldByName[*name]; ok { - ofcs := o["forwarding_configuration"].([]interface{}) - if len(ofcs) > 0 { - ofc := ofcs[0].(map[string]interface{}) - c["cache_query_parameter_strip_directive"] = ofc["cache_query_parameter_strip_directive"] - c["cache_use_dynamic_compression"] = ofc["cache_use_dynamic_compression"] - } - } + name := "" + if v.BackendPool != nil && v.BackendPool.ID != nil { + backendPoolId, err := parse.FrontDoorBackendPoolID(*v.BackendPool.ID) + if err != nil { + return nil, err + } + + name = backendPoolId.Name + } + + customForwardingPath := "" + if v.CustomForwardingPath != nil { + customForwardingPath = *v.CustomForwardingPath + } + + cacheEnabled := false + cacheQueryParameterStripDirective := string(frontdoor.StripAll) + cacheUseDynamicCompression := false + + if cacheConfiguration := v.CacheConfiguration; cacheConfiguration != nil { + cacheEnabled = true + if stripDirective := cacheConfiguration.QueryParameterStripDirective; stripDirective != "" { + cacheQueryParameterStripDirective = string(stripDirective) + } + + if dynamicCompression := cacheConfiguration.DynamicCompression; dynamicCompression != "" { + cacheUseDynamicCompression = string(dynamicCompression) == string(frontdoor.DynamicCompressionEnabledEnabled) + } + } else { + // if the cache is disabled, use the default values or revert to what they were in the previous plan + old, ok := oldConfig.([]interface{}) + if ok { + for _, oldValue := range old { + oldVal, ok := oldValue.(map[string]interface{}) + if ok { + thisName := oldVal["name"].(string) + if name == thisName { + oldConfigs := oldVal["forwarding_configuration"].([]interface{}) + if len(oldConfigs) > 0 { + ofc := oldConfigs[0].(map[string]interface{}) + cacheQueryParameterStripDirective = ofc["cache_query_parameter_strip_directive"].(string) + cacheUseDynamicCompression = ofc["cache_use_dynamic_compression"].(bool) } } - - rc = append(rc, c) - result["forwarding_configuration"] = rc - } else { - v := brc.(frontdoor.RedirectConfiguration) - c["custom_fragment"] = v.CustomFragment - c["custom_host"] = v.CustomHost - c["custom_path"] = v.CustomPath - c["custom_query_string"] = v.CustomQueryString - c["redirect_protocol"] = string(v.RedirectProtocol) - c["redirect_type"] = string(v.RedirectType) - - rc = append(rc, c) - result["redirect_configuration"] = rc } } } + } - output = append(output, result) + return &[]interface{}{ + map[string]interface{}{ + "backend_pool_name": "name", + "custom_forwarding_path": customForwardingPath, + "forwarding_protocol": string(v.ForwardingProtocol), + "cache_enabled": cacheEnabled, + "cache_query_parameter_strip_directive": cacheQueryParameterStripDirective, + "cache_use_dynamic_compression": cacheUseDynamicCompression, + }, + }, nil +} + +func flattenRoutingRuleRedirectConfiguration(config frontdoor.BasicRouteConfiguration) []interface{} { + v, ok := config.(frontdoor.RedirectConfiguration) + if !ok { + return []interface{}{} } - return &output, nil + customFragment := "" + if v.CustomFragment != nil { + customFragment = *v.CustomFragment + } + + customHost := "" + if v.CustomHost != nil { + customHost = *v.CustomHost + } + + customQueryString := "" + if v.CustomQueryString != nil { + customQueryString = *v.CustomQueryString + } + + customPath := "" + if v.CustomPath != nil { + customPath = *v.CustomPath + } + + return []interface{}{ + map[string]interface{}{ + "custom_host": customHost, + "custom_fragment": customFragment, + "custom_query_string": customQueryString, + "custom_path": customPath, + "redirect_protocol": string(v.RedirectProtocol), + "redirect_type": string(v.RedirectType), + }, + } } func flattenArmFrontDoorAcceptedProtocol(input *[]frontdoor.Protocol) []string { diff --git a/azurerm/internal/services/frontdoor/helper.go b/azurerm/internal/services/frontdoor/helper.go index 6917603a530e..deb3d9963b16 100644 --- a/azurerm/internal/services/frontdoor/helper.go +++ b/azurerm/internal/services/frontdoor/helper.go @@ -29,19 +29,6 @@ func NormalizeCustomHTTPSProvisioningStateToBool(provisioningState frontdoor.Cus return isEnabled } -func GetFrontDoorBasicRouteConfigurationType(i interface{}) string { - _, ok := i.(frontdoor.ForwardingConfiguration) - if !ok { - _, ok := i.(frontdoor.RedirectConfiguration) - if !ok { - return "" - } - return "RedirectConfiguration" - } else { - return "ForwardingConfiguration" - } -} - func FlattenTransformSlice(input *[]frontdoor.TransformType) []interface{} { result := make([]interface{}, 0) diff --git a/azurerm/internal/services/frontdoor/parse/frontdoor_backend_pool.go b/azurerm/internal/services/frontdoor/parse/frontdoor_backend_pool.go new file mode 100644 index 000000000000..a98a5de228a0 --- /dev/null +++ b/azurerm/internal/services/frontdoor/parse/frontdoor_backend_pool.go @@ -0,0 +1,46 @@ +package parse + +import "fmt" + +type FrontDoorBackendPoolId struct { + ResourceGroup string + FrontDoorName string + Name string +} + +func NewFrontDoorBackendPoolID(id FrontDoorId, name string) FrontDoorBackendPoolId { + return FrontDoorBackendPoolId{ + ResourceGroup: id.ResourceGroup, + FrontDoorName: id.Name, + Name: name, + } +} + +func (id FrontDoorBackendPoolId) ID(subscriptionId string) string { + base := NewFrontDoorID(id.ResourceGroup, id.Name).ID(subscriptionId) + return fmt.Sprintf("%s/backendPools/%s", base, id.Name) +} + +func FrontDoorBackendPoolID(input string) (*FrontDoorBackendPoolId, error) { + frontDoorId, id, err := parseFrontDoorChildResourceId(input) + if err != nil { + return nil, fmt.Errorf("parsing FrontDoor Backend Pool ID %q: %+v", input, err) + } + + endpointId := FrontDoorBackendPoolId{ + ResourceGroup: frontDoorId.ResourceGroup, + FrontDoorName: frontDoorId.Name, + } + + // TODO: handle this being case-insensitive + // https://github.com/Azure/azure-sdk-for-go/issues/6762 + if endpointId.Name, err = id.PopSegment("backendPools"); err != nil { + return nil, err + } + + if err := id.ValidateNoEmptySegments(input); err != nil { + return nil, err + } + + return nil, nil +} From 49ac731924d78e71dacbc982148c8378a499cd51 Mon Sep 17 00:00:00 2001 From: tombuildsstuff Date: Wed, 12 Aug 2020 12:51:50 +0200 Subject: [PATCH 05/41] refactor: moving the frontdoor helpers into the frontdoor package --- .../frontdoor}/frontdoor_custom_https_configuration.go | 2 +- .../frontdoor_custom_https_configuration_resource.go | 4 ++-- azurerm/internal/services/frontdoor/frontdoor_resource.go | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) rename azurerm/{helpers/azure => internal/services/frontdoor}/frontdoor_custom_https_configuration.go (99%) diff --git a/azurerm/helpers/azure/frontdoor_custom_https_configuration.go b/azurerm/internal/services/frontdoor/frontdoor_custom_https_configuration.go similarity index 99% rename from azurerm/helpers/azure/frontdoor_custom_https_configuration.go rename to azurerm/internal/services/frontdoor/frontdoor_custom_https_configuration.go index 09de1fe595c9..4f77ce1bf434 100644 --- a/azurerm/helpers/azure/frontdoor_custom_https_configuration.go +++ b/azurerm/internal/services/frontdoor/frontdoor_custom_https_configuration.go @@ -1,4 +1,4 @@ -package azure +package frontdoor import ( "github.com/Azure/azure-sdk-for-go/services/frontdoor/mgmt/2020-01-01/frontdoor" diff --git a/azurerm/internal/services/frontdoor/frontdoor_custom_https_configuration_resource.go b/azurerm/internal/services/frontdoor/frontdoor_custom_https_configuration_resource.go index 2a578ad8ac59..76c6b132ae8a 100644 --- a/azurerm/internal/services/frontdoor/frontdoor_custom_https_configuration_resource.go +++ b/azurerm/internal/services/frontdoor/frontdoor_custom_https_configuration_resource.go @@ -54,7 +54,7 @@ func resourceArmFrontDoorCustomHttpsConfiguration() *schema.Resource { Optional: true, MaxItems: 1, Elem: &schema.Resource{ - Schema: azure.SchemaFrontdoorCustomHttpsConfiguration(), + Schema: SchemaFrontdoorCustomHttpsConfiguration(), }, }, }, @@ -141,7 +141,7 @@ func resourceArmFrontDoorCustomHttpsConfigurationRead(d *schema.ResourceData, me if resp.Name != nil { - flattenedHttpsConfig := azure.FlattenArmFrontDoorCustomHttpsConfiguration(*resp.FrontendEndpointProperties) + flattenedHttpsConfig := FlattenArmFrontDoorCustomHttpsConfiguration(*resp.FrontendEndpointProperties) if err := d.Set("custom_https_configuration", flattenedHttpsConfig.CustomHTTPSConfiguration); err != nil { return fmt.Errorf("setting `custom_https_configuration`: %+v", err) } diff --git a/azurerm/internal/services/frontdoor/frontdoor_resource.go b/azurerm/internal/services/frontdoor/frontdoor_resource.go index 106115adb642..44a23c72798c 100644 --- a/azurerm/internal/services/frontdoor/frontdoor_resource.go +++ b/azurerm/internal/services/frontdoor/frontdoor_resource.go @@ -444,7 +444,7 @@ func resourceArmFrontDoor() *schema.Resource { MaxItems: 1, Deprecated: "Deprecated in favour of `azurerm_frontdoor_custom_https_configuration` resource", Elem: &schema.Resource{ - Schema: azure.SchemaFrontdoorCustomHttpsConfiguration(), + Schema: SchemaFrontdoorCustomHttpsConfiguration(), }, }, }, @@ -1248,7 +1248,7 @@ func flattenFrontEndEndpoints(input *[]frontdoor.FrontendEndpoint) (*[]interface webApplicationFirewallPolicyLinkId = *waf.ID } - flattenedHttpsConfig := azure.FlattenArmFrontDoorCustomHttpsConfiguration(*props) + flattenedHttpsConfig := FlattenArmFrontDoorCustomHttpsConfiguration(*props) customHTTPSConfiguration = flattenedHttpsConfig.CustomHTTPSConfiguration customHttpsProvisioningEnabled = flattenedHttpsConfig.CustomHTTPSProvisioningEnabled } From b560532556953ece8a92ab53a2966e986cd97379 Mon Sep 17 00:00:00 2001 From: tombuildsstuff Date: Wed, 12 Aug 2020 13:04:18 +0200 Subject: [PATCH 06/41] r/frontdoor: refactoring the backend pool method --- .../services/frontdoor/frontdoor_resource.go | 66 ++++++++++++------- .../frontdoor/parse/frontdoor_backend_pool.go | 6 +- .../parse/frontdoor_frontend_endpoint.go | 2 +- .../services/frontdoor/parse/health_probe.go | 46 +++++++++++++ .../frontdoor/parse/load_balancing.go | 46 +++++++++++++ 5 files changed, 139 insertions(+), 27 deletions(-) create mode 100644 azurerm/internal/services/frontdoor/parse/health_probe.go create mode 100644 azurerm/internal/services/frontdoor/parse/load_balancing.go diff --git a/azurerm/internal/services/frontdoor/frontdoor_resource.go b/azurerm/internal/services/frontdoor/frontdoor_resource.go index 44a23c72798c..0ad5b840e9c1 100644 --- a/azurerm/internal/services/frontdoor/frontdoor_resource.go +++ b/azurerm/internal/services/frontdoor/frontdoor_resource.go @@ -607,7 +607,11 @@ func resourceArmFrontDoorRead(d *schema.ResourceData, meta interface{}) error { d.Set("location", azure.NormalizeLocation(*resp.Location)) if props := resp.Properties; props != nil { - if err := d.Set("backend_pool", flattenArmFrontDoorBackendPools(props.BackendPools)); err != nil { + flattenedBackendPools, err := flattenArmFrontDoorBackendPools(props.BackendPools) + if err != nil { + return fmt.Errorf("flattening `backend_pool`: %+v", err) + } + if err := d.Set("backend_pool", flattenedBackendPools); err != nil { return fmt.Errorf("setting `backend_pool`: %+v", err) } @@ -1083,42 +1087,58 @@ func expandArmFrontDoorForwardingConfiguration(input []interface{}, frontDoorPat return forwardingConfiguration } -func flattenArmFrontDoorBackendPools(input *[]frontdoor.BackendPool) []map[string]interface{} { +func flattenArmFrontDoorBackendPools(input *[]frontdoor.BackendPool) (*[]interface{}, error) { if input == nil { - return make([]map[string]interface{}, 0) + return &[]interface{}{}, nil } - output := make([]map[string]interface{}, 0) - + output := make([]interface{}, 0) for _, v := range *input { - result := make(map[string]interface{}) - - if id := v.ID; id != nil { - result["id"] = *id + id := "" + if v.ID != nil { + id = *v.ID } - if name := v.Name; name != nil { - result["name"] = *name + name := "" + if v.Name != nil { + name = *v.Name } - if properties := v.BackendPoolProperties; properties != nil { - result["backend"] = flattenArmFrontDoorBackend(properties.Backends) - result["health_probe_name"] = flattenArmFrontDoorSubResource(properties.HealthProbeSettings, "HealthProbeSettings") - // Link to issue: https://github.com/Azure/azure-sdk-for-go/issues/6762 - if result["health_probe_name"] == "" { - result["health_probe_name"] = flattenArmFrontDoorSubResource(properties.HealthProbeSettings, "healthProbeSettings") + backend := make([]interface{}, 0) + healthProbeName := "" + loadBalancingName := "" + + if props := v.BackendPoolProperties; props != nil { + backend = flattenArmFrontDoorBackend(props.Backends) + + if props.HealthProbeSettings != nil && props.HealthProbeSettings.ID != nil { + name, err := parse.HealthProbeID(*props.HealthProbeSettings.ID) + if err != nil { + return nil, err + } + + healthProbeName = name.Name } - result["load_balancing_name"] = flattenArmFrontDoorSubResource(properties.LoadBalancingSettings, "LoadBalancingSettings") - // Link to issue: https://github.com/Azure/azure-sdk-for-go/issues/6762 - if result["load_balancing_name"] == "" { - result["load_balancing_name"] = flattenArmFrontDoorSubResource(properties.LoadBalancingSettings, "loadBalancingSettings") + if props.LoadBalancingSettings != nil && props.LoadBalancingSettings.ID != nil { + name, err := parse.LoadBalancingID(*props.LoadBalancingSettings.ID) + if err != nil { + return nil, err + } + + loadBalancingName = name.Name } } - output = append(output, result) + output = append(output, map[string]interface{}{ + "backend": backend, + "health_probe_name": healthProbeName, + "id": id, + "load_balancing_name": loadBalancingName, + "name": name, + }) } - return output + return &output, nil } func flattenArmFrontDoorBackendPoolsSettings(input *frontdoor.BackendPoolsSettings) map[string]interface{} { diff --git a/azurerm/internal/services/frontdoor/parse/frontdoor_backend_pool.go b/azurerm/internal/services/frontdoor/parse/frontdoor_backend_pool.go index a98a5de228a0..788b50d8b517 100644 --- a/azurerm/internal/services/frontdoor/parse/frontdoor_backend_pool.go +++ b/azurerm/internal/services/frontdoor/parse/frontdoor_backend_pool.go @@ -27,14 +27,14 @@ func FrontDoorBackendPoolID(input string) (*FrontDoorBackendPoolId, error) { return nil, fmt.Errorf("parsing FrontDoor Backend Pool ID %q: %+v", input, err) } - endpointId := FrontDoorBackendPoolId{ + poolId := FrontDoorBackendPoolId{ ResourceGroup: frontDoorId.ResourceGroup, FrontDoorName: frontDoorId.Name, } // TODO: handle this being case-insensitive // https://github.com/Azure/azure-sdk-for-go/issues/6762 - if endpointId.Name, err = id.PopSegment("backendPools"); err != nil { + if poolId.Name, err = id.PopSegment("backendPools"); err != nil { return nil, err } @@ -42,5 +42,5 @@ func FrontDoorBackendPoolID(input string) (*FrontDoorBackendPoolId, error) { return nil, err } - return nil, nil + return &poolId, nil } diff --git a/azurerm/internal/services/frontdoor/parse/frontdoor_frontend_endpoint.go b/azurerm/internal/services/frontdoor/parse/frontdoor_frontend_endpoint.go index 16f7792995aa..11a5a3d7c5ab 100644 --- a/azurerm/internal/services/frontdoor/parse/frontdoor_frontend_endpoint.go +++ b/azurerm/internal/services/frontdoor/parse/frontdoor_frontend_endpoint.go @@ -42,5 +42,5 @@ func FrontDoorFrontendEndpointID(input string) (*FrontDoorFrontendEndpointId, er return nil, err } - return nil, nil + return &endpointId, nil } diff --git a/azurerm/internal/services/frontdoor/parse/health_probe.go b/azurerm/internal/services/frontdoor/parse/health_probe.go new file mode 100644 index 000000000000..067fbe5775ce --- /dev/null +++ b/azurerm/internal/services/frontdoor/parse/health_probe.go @@ -0,0 +1,46 @@ +package parse + +import "fmt" + +type HealthProbeId struct { + ResourceGroup string + FrontDoorName string + Name string +} + +func NewHealthProbeID(id FrontDoorId, name string) HealthProbeId { + return HealthProbeId{ + ResourceGroup: id.ResourceGroup, + FrontDoorName: id.Name, + Name: name, + } +} + +func (id HealthProbeId) ID(subscriptionId string) string { + base := NewFrontDoorID(id.ResourceGroup, id.Name).ID(subscriptionId) + return fmt.Sprintf("%s/healthProbeSettings/%s", base, id.Name) +} + +func HealthProbeID(input string) (*HealthProbeId, error) { + frontDoorId, id, err := parseFrontDoorChildResourceId(input) + if err != nil { + return nil, fmt.Errorf("parsing FrontDoor Health Probe ID %q: %+v", input, err) + } + + probeId := HealthProbeId{ + ResourceGroup: frontDoorId.ResourceGroup, + FrontDoorName: frontDoorId.Name, + } + + // TODO: handle this being case-insensitive + // https://github.com/Azure/azure-sdk-for-go/issues/6762 + if probeId.Name, err = id.PopSegment("healthProbeSettings"); err != nil { + return nil, err + } + + if err := id.ValidateNoEmptySegments(input); err != nil { + return nil, err + } + + return &probeId, nil +} diff --git a/azurerm/internal/services/frontdoor/parse/load_balancing.go b/azurerm/internal/services/frontdoor/parse/load_balancing.go new file mode 100644 index 000000000000..6509101808c2 --- /dev/null +++ b/azurerm/internal/services/frontdoor/parse/load_balancing.go @@ -0,0 +1,46 @@ +package parse + +import "fmt" + +type LoadBalancingId struct { + ResourceGroup string + FrontDoorName string + Name string +} + +func NewLoadBalancingID(id FrontDoorId, name string) LoadBalancingId { + return LoadBalancingId{ + ResourceGroup: id.ResourceGroup, + FrontDoorName: id.Name, + Name: name, + } +} + +func (id LoadBalancingId) ID(subscriptionId string) string { + base := NewFrontDoorID(id.ResourceGroup, id.Name).ID(subscriptionId) + return fmt.Sprintf("%s/loadBalancingSettings/%s", base, id.Name) +} + +func LoadBalancingID(input string) (*LoadBalancingId, error) { + frontDoorId, id, err := parseFrontDoorChildResourceId(input) + if err != nil { + return nil, fmt.Errorf("parsing FrontDoor Load Balancing ID %q: %+v", input, err) + } + + loadBalancingId := LoadBalancingId{ + ResourceGroup: frontDoorId.ResourceGroup, + FrontDoorName: frontDoorId.Name, + } + + // TODO: handle this being case-insensitive + // https://github.com/Azure/azure-sdk-for-go/issues/6762 + if loadBalancingId.Name, err = id.PopSegment("loadBalancingSettings"); err != nil { + return nil, err + } + + if err := id.ValidateNoEmptySegments(input); err != nil { + return nil, err + } + + return &loadBalancingId, nil +} From dcc75c308dad1db0912773da3dff43ffcbec5749 Mon Sep 17 00:00:00 2001 From: tombuildsstuff Date: Wed, 12 Aug 2020 13:04:42 +0200 Subject: [PATCH 07/41] r/frontdoor: removing dead code --- .../services/frontdoor/frontdoor_resource.go | 18 ------------------ 1 file changed, 18 deletions(-) diff --git a/azurerm/internal/services/frontdoor/frontdoor_resource.go b/azurerm/internal/services/frontdoor/frontdoor_resource.go index 0ad5b840e9c1..3f36988dfda4 100644 --- a/azurerm/internal/services/frontdoor/frontdoor_resource.go +++ b/azurerm/internal/services/frontdoor/frontdoor_resource.go @@ -1536,24 +1536,6 @@ func flattenArmFrontDoorAcceptedProtocol(input *[]frontdoor.Protocol) []string { return output } -func flattenArmFrontDoorSubResource(input *frontdoor.SubResource, resourceType string) string { - if input == nil { - return "" - } - - name := "" - - if id := input.ID; id != nil { - aid, err := azure.ParseAzureResourceID(*id) - if err != nil { - return "" - } - name = aid.Path[resourceType] - } - - return name -} - func flattenArmFrontDoorFrontendEndpointsSubResources(input *[]frontdoor.SubResource) (*[]string, error) { output := make([]string, 0) From f47771de7fbef2cdf05caa8803fb91a19ada499a Mon Sep 17 00:00:00 2001 From: tombuildsstuff Date: Wed, 12 Aug 2020 13:07:55 +0200 Subject: [PATCH 08/41] refactor: ditching the frontdoor prefix --- .../services/frontdoor/frontdoor_resource.go | 6 +++--- .../{frontdoor_backend_pool.go => backend_pool.go} | 14 +++++++------- ...r_frontend_endpoint.go => frontend_endpoint.go} | 14 +++++++------- ..._endpoint_test.go => frontend_endpoint_test.go} | 2 +- .../services/frontdoor/parse/health_probe_test.go | 5 +++++ .../frontdoor/parse/load_balancing_test.go | 5 +++++ 6 files changed, 28 insertions(+), 18 deletions(-) rename azurerm/internal/services/frontdoor/parse/{frontdoor_backend_pool.go => backend_pool.go} (65%) rename azurerm/internal/services/frontdoor/parse/{frontdoor_frontend_endpoint.go => frontend_endpoint.go} (63%) rename azurerm/internal/services/frontdoor/parse/{frontdoor_frontend_endpoint_test.go => frontend_endpoint_test.go} (65%) create mode 100644 azurerm/internal/services/frontdoor/parse/health_probe_test.go create mode 100644 azurerm/internal/services/frontdoor/parse/load_balancing_test.go diff --git a/azurerm/internal/services/frontdoor/frontdoor_resource.go b/azurerm/internal/services/frontdoor/frontdoor_resource.go index 3f36988dfda4..7095af34a3dd 100644 --- a/azurerm/internal/services/frontdoor/frontdoor_resource.go +++ b/azurerm/internal/services/frontdoor/frontdoor_resource.go @@ -806,7 +806,7 @@ func expandArmFrontDoorFrontendEndpoint(input []interface{}, frontDoorId parse.F sessionAffinityTtlSeconds := int32(frontendEndpoint["session_affinity_ttl_seconds"].(int)) waf := frontendEndpoint["web_application_firewall_policy_link_id"].(string) name := frontendEndpoint["name"].(string) - id := parse.NewFrontDoorFrontendEndpointID(frontDoorId, name).ID(subscriptionId) + id := parse.NewFrontendEndpointID(frontDoorId, name).ID(subscriptionId) sessionAffinityEnabled := frontdoor.SessionAffinityEnabledStateDisabled if isSessionAffinityEnabled { @@ -1206,7 +1206,7 @@ func flattenArmFrontDoorBackend(input *[]frontdoor.Backend) []interface{} { return output } -func retrieveFrontEndEndpointInformation(ctx context.Context, client *frontdoor.FrontendEndpointsClient, frontDoorId parse.FrontDoorId, endpoints *[]frontdoor.FrontendEndpoint) (*[]frontdoor.FrontendEndpoint, interface{}) { +func retrieveFrontEndEndpointInformation(ctx context.Context, client *frontdoor.FrontendEndpointsClient, frontDoorId parse.FrontDoorId, endpoints *[]frontdoor.FrontendEndpoint) (*[]frontdoor.FrontendEndpoint, error) { output := make([]frontdoor.FrontendEndpoint, 0) if endpoints == nil { return &output, nil @@ -1426,7 +1426,7 @@ func flattenRoutingRuleForwardingConfiguration(config frontdoor.BasicRouteConfig name := "" if v.BackendPool != nil && v.BackendPool.ID != nil { - backendPoolId, err := parse.FrontDoorBackendPoolID(*v.BackendPool.ID) + backendPoolId, err := parse.BackendPoolID(*v.BackendPool.ID) if err != nil { return nil, err } diff --git a/azurerm/internal/services/frontdoor/parse/frontdoor_backend_pool.go b/azurerm/internal/services/frontdoor/parse/backend_pool.go similarity index 65% rename from azurerm/internal/services/frontdoor/parse/frontdoor_backend_pool.go rename to azurerm/internal/services/frontdoor/parse/backend_pool.go index 788b50d8b517..b59d6e24e054 100644 --- a/azurerm/internal/services/frontdoor/parse/frontdoor_backend_pool.go +++ b/azurerm/internal/services/frontdoor/parse/backend_pool.go @@ -2,32 +2,32 @@ package parse import "fmt" -type FrontDoorBackendPoolId struct { +type BackendPoolId struct { ResourceGroup string FrontDoorName string Name string } -func NewFrontDoorBackendPoolID(id FrontDoorId, name string) FrontDoorBackendPoolId { - return FrontDoorBackendPoolId{ +func NewBackendPoolID(id FrontDoorId, name string) BackendPoolId { + return BackendPoolId{ ResourceGroup: id.ResourceGroup, FrontDoorName: id.Name, Name: name, } } -func (id FrontDoorBackendPoolId) ID(subscriptionId string) string { +func (id BackendPoolId) ID(subscriptionId string) string { base := NewFrontDoorID(id.ResourceGroup, id.Name).ID(subscriptionId) return fmt.Sprintf("%s/backendPools/%s", base, id.Name) } -func FrontDoorBackendPoolID(input string) (*FrontDoorBackendPoolId, error) { +func BackendPoolID(input string) (*BackendPoolId, error) { frontDoorId, id, err := parseFrontDoorChildResourceId(input) if err != nil { - return nil, fmt.Errorf("parsing FrontDoor Backend Pool ID %q: %+v", input, err) + return nil, fmt.Errorf("parsing Backend Pool ID %q: %+v", input, err) } - poolId := FrontDoorBackendPoolId{ + poolId := BackendPoolId{ ResourceGroup: frontDoorId.ResourceGroup, FrontDoorName: frontDoorId.Name, } diff --git a/azurerm/internal/services/frontdoor/parse/frontdoor_frontend_endpoint.go b/azurerm/internal/services/frontdoor/parse/frontend_endpoint.go similarity index 63% rename from azurerm/internal/services/frontdoor/parse/frontdoor_frontend_endpoint.go rename to azurerm/internal/services/frontdoor/parse/frontend_endpoint.go index 11a5a3d7c5ab..a8b4663f3718 100644 --- a/azurerm/internal/services/frontdoor/parse/frontdoor_frontend_endpoint.go +++ b/azurerm/internal/services/frontdoor/parse/frontend_endpoint.go @@ -2,32 +2,32 @@ package parse import "fmt" -type FrontDoorFrontendEndpointId struct { +type FrontendEndpointId struct { ResourceGroup string FrontDoorName string Name string } -func NewFrontDoorFrontendEndpointID(id FrontDoorId, name string) FrontDoorFrontendEndpointId { - return FrontDoorFrontendEndpointId{ +func NewFrontendEndpointID(id FrontDoorId, name string) FrontendEndpointId { + return FrontendEndpointId{ ResourceGroup: id.ResourceGroup, FrontDoorName: id.Name, Name: name, } } -func (id FrontDoorFrontendEndpointId) ID(subscriptionId string) string { +func (id FrontendEndpointId) ID(subscriptionId string) string { base := NewFrontDoorID(id.ResourceGroup, id.Name).ID(subscriptionId) return fmt.Sprintf("%s/frontendEndpoints/%s", base, id.Name) } -func FrontDoorFrontendEndpointID(input string) (*FrontDoorFrontendEndpointId, error) { +func FrontDoorFrontendEndpointID(input string) (*FrontendEndpointId, error) { frontDoorId, id, err := parseFrontDoorChildResourceId(input) if err != nil { - return nil, fmt.Errorf("parsing FrontDoor Frontend Endpoint ID %q: %+v", input, err) + return nil, fmt.Errorf("parsing Frontend Endpoint ID %q: %+v", input, err) } - endpointId := FrontDoorFrontendEndpointId{ + endpointId := FrontendEndpointId{ ResourceGroup: frontDoorId.ResourceGroup, FrontDoorName: frontDoorId.Name, } diff --git a/azurerm/internal/services/frontdoor/parse/frontdoor_frontend_endpoint_test.go b/azurerm/internal/services/frontdoor/parse/frontend_endpoint_test.go similarity index 65% rename from azurerm/internal/services/frontdoor/parse/frontdoor_frontend_endpoint_test.go rename to azurerm/internal/services/frontdoor/parse/frontend_endpoint_test.go index 4d2dc609d753..957cb692cdf7 100644 --- a/azurerm/internal/services/frontdoor/parse/frontdoor_frontend_endpoint_test.go +++ b/azurerm/internal/services/frontdoor/parse/frontend_endpoint_test.go @@ -2,4 +2,4 @@ package parse import "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/resourceid" -var _ resourceid.Formatter = FrontDoorFrontendEndpointId{} +var _ resourceid.Formatter = FrontendEndpointId{} diff --git a/azurerm/internal/services/frontdoor/parse/health_probe_test.go b/azurerm/internal/services/frontdoor/parse/health_probe_test.go new file mode 100644 index 000000000000..b5a764e7dccf --- /dev/null +++ b/azurerm/internal/services/frontdoor/parse/health_probe_test.go @@ -0,0 +1,5 @@ +package parse + +import "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/resourceid" + +var _ resourceid.Formatter = HealthProbeId{} diff --git a/azurerm/internal/services/frontdoor/parse/load_balancing_test.go b/azurerm/internal/services/frontdoor/parse/load_balancing_test.go new file mode 100644 index 000000000000..7f523828d24e --- /dev/null +++ b/azurerm/internal/services/frontdoor/parse/load_balancing_test.go @@ -0,0 +1,5 @@ +package parse + +import "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/resourceid" + +var _ resourceid.Formatter = LoadBalancingId{} From 4bbf894b66d57f03d9e7c6b003aaf3e7455f2316 Mon Sep 17 00:00:00 2001 From: tombuildsstuff Date: Wed, 12 Aug 2020 13:14:35 +0200 Subject: [PATCH 09/41] r/frontdoor: refactoring to use the ID parsers/formatters --- .../services/frontdoor/frontdoor_resource.go | 59 ++++++++++--------- 1 file changed, 31 insertions(+), 28 deletions(-) diff --git a/azurerm/internal/services/frontdoor/frontdoor_resource.go b/azurerm/internal/services/frontdoor/frontdoor_resource.go index 7095af34a3dd..638592e39e21 100644 --- a/azurerm/internal/services/frontdoor/frontdoor_resource.go +++ b/azurerm/internal/services/frontdoor/frontdoor_resource.go @@ -510,9 +510,6 @@ func resourceArmFrontDoorCreateUpdate(d *schema.ResourceData, meta interface{}) frontDoorId := parse.NewFrontDoorID(resourceGroup, name) - // TODO: pass in ID directly then remove this - frontDoorPath := frontDoorId.ID(subscriptionId) - friendlyName := d.Get("friendly_name").(string) routingRules := d.Get("routing_rule").([]interface{}) loadBalancingSettings := d.Get("backend_pool_load_balancing").([]interface{}) @@ -522,19 +519,18 @@ func resourceArmFrontDoorCreateUpdate(d *schema.ResourceData, meta interface{}) backendPoolsSettings := d.Get("enforce_backend_pools_certificate_name_check").(bool) backendPoolsSendReceiveTimeoutSeconds := int32(d.Get("backend_pools_send_receive_timeout_seconds").(int)) enabledState := d.Get("load_balancer_enabled").(bool) - t := d.Get("tags").(map[string]interface{}) frontDoorParameters := frontdoor.FrontDoor{ Location: utils.String(location), Properties: &frontdoor.Properties{ FriendlyName: utils.String(friendlyName), - RoutingRules: expandArmFrontDoorRoutingRule(routingRules, frontDoorPath), - BackendPools: expandArmFrontDoorBackendPools(backendPools, frontDoorPath), + RoutingRules: expandArmFrontDoorRoutingRule(routingRules, frontDoorId, subscriptionId), + BackendPools: expandArmFrontDoorBackendPools(backendPools, frontDoorId, subscriptionId), BackendPoolsSettings: expandArmFrontDoorBackendPoolsSettings(backendPoolsSettings, backendPoolsSendReceiveTimeoutSeconds), FrontendEndpoints: expandArmFrontDoorFrontendEndpoint(frontendEndpoints, frontDoorId, subscriptionId), - HealthProbeSettings: expandArmFrontDoorHealthProbeSettingsModel(healthProbeSettings, frontDoorPath), - LoadBalancingSettings: expandArmFrontDoorLoadBalancingSettingsModel(loadBalancingSettings, frontDoorPath), + HealthProbeSettings: expandArmFrontDoorHealthProbeSettingsModel(healthProbeSettings, frontDoorId, subscriptionId), + LoadBalancingSettings: expandArmFrontDoorLoadBalancingSettingsModel(loadBalancingSettings, frontDoorId, subscriptionId), EnabledState: expandArmFrontDoorEnabledState(enabledState), }, Tags: tags.Expand(t), @@ -698,7 +694,7 @@ func resourceArmFrontDoorDelete(d *schema.ResourceData, meta interface{}) error return nil } -func expandArmFrontDoorBackendPools(input []interface{}, frontDoorPath string) *[]frontdoor.BackendPool { +func expandArmFrontDoorBackendPools(input []interface{}, frontDoorId parse.FrontDoorId, subscriptionId string) *[]frontdoor.BackendPool { if len(input) == 0 { return &[]frontdoor.BackendPool{} } @@ -714,16 +710,20 @@ func expandArmFrontDoorBackendPools(input []interface{}, frontDoorPath string) * backends := backendPool["backend"].([]interface{}) + backendPoolId := parse.NewBackendPoolID(frontDoorId, backendPoolName).ID(subscriptionId) + healthProbeId := parse.NewHealthProbeID(frontDoorId, backendPoolHealthProbeName).ID(subscriptionId) + loadBalancingId := parse.NewLoadBalancingID(frontDoorId, backendPoolLoadBalancingName).ID(subscriptionId) + result := frontdoor.BackendPool{ - ID: utils.String(frontDoorPath + "/BackendPools/" + backendPoolName), + ID: utils.String(backendPoolId), Name: utils.String(backendPoolName), BackendPoolProperties: &frontdoor.BackendPoolProperties{ Backends: expandArmFrontDoorBackend(backends), - LoadBalancingSettings: &frontdoor.SubResource{ - ID: utils.String(frontDoorPath + "/LoadBalancingSettings/" + backendPoolLoadBalancingName), - }, HealthProbeSettings: &frontdoor.SubResource{ - ID: utils.String(frontDoorPath + "/HealthProbeSettings/" + backendPoolHealthProbeName), + ID: utils.String(healthProbeId), + }, + LoadBalancingSettings: &frontdoor.SubResource{ + ID: utils.String(loadBalancingId), }, }, } @@ -835,7 +835,7 @@ func expandArmFrontDoorFrontendEndpoint(input []interface{}, frontDoorId parse.F return &output } -func expandArmFrontDoorHealthProbeSettingsModel(input []interface{}, frontDoorPath string) *[]frontdoor.HealthProbeSettingsModel { +func expandArmFrontDoorHealthProbeSettingsModel(input []interface{}, frontDoorId parse.FrontDoorId, subscriptionId string) *[]frontdoor.HealthProbeSettingsModel { if len(input) == 0 { return &[]frontdoor.HealthProbeSettingsModel{} } @@ -856,8 +856,10 @@ func expandArmFrontDoorHealthProbeSettingsModel(input []interface{}, frontDoorPa healthProbeEnabled = frontdoor.HealthProbeEnabledDisabled } + healthProbeId := parse.NewHealthProbeID(frontDoorId, name).ID(subscriptionId) + result := frontdoor.HealthProbeSettingsModel{ - ID: utils.String(frontDoorPath + "/HealthProbeSettings/" + name), + ID: utils.String(healthProbeId), Name: utils.String(name), HealthProbeSettingsProperties: &frontdoor.HealthProbeSettingsProperties{ IntervalInSeconds: utils.Int32(intervalInSeconds), @@ -874,7 +876,7 @@ func expandArmFrontDoorHealthProbeSettingsModel(input []interface{}, frontDoorPa return &output } -func expandArmFrontDoorLoadBalancingSettingsModel(input []interface{}, frontDoorPath string) *[]frontdoor.LoadBalancingSettingsModel { +func expandArmFrontDoorLoadBalancingSettingsModel(input []interface{}, frontDoorId parse.FrontDoorId, subscriptionId string) *[]frontdoor.LoadBalancingSettingsModel { if len(input) == 0 { return &[]frontdoor.LoadBalancingSettingsModel{} } @@ -888,10 +890,10 @@ func expandArmFrontDoorLoadBalancingSettingsModel(input []interface{}, frontDoor sampleSize := int32(loadBalanceSetting["sample_size"].(int)) successfulSamplesRequired := int32(loadBalanceSetting["successful_samples_required"].(int)) additionalLatencyMilliseconds := int32(loadBalanceSetting["additional_latency_milliseconds"].(int)) - id := utils.String(frontDoorPath + "/LoadBalancingSettings/" + name) + loadBalancingId := parse.NewLoadBalancingID(frontDoorId, name).ID(subscriptionId) result := frontdoor.LoadBalancingSettingsModel{ - ID: id, + ID: utils.String(loadBalancingId), Name: utils.String(name), LoadBalancingSettingsProperties: &frontdoor.LoadBalancingSettingsProperties{ SampleSize: utils.Int32(sampleSize), @@ -906,7 +908,7 @@ func expandArmFrontDoorLoadBalancingSettingsModel(input []interface{}, frontDoor return &output } -func expandArmFrontDoorRoutingRule(input []interface{}, frontDoorPath string) *[]frontdoor.RoutingRule { +func expandArmFrontDoorRoutingRule(input []interface{}, frontDoorId parse.FrontDoorId, subscriptionId string) *[]frontdoor.RoutingRule { if len(input) == 0 { return nil } @@ -934,14 +936,14 @@ func expandArmFrontDoorRoutingRule(input []interface{}, frontDoorPath string) *[ if rc := routingRule["redirect_configuration"].([]interface{}); len(rc) != 0 { routingConfiguration = expandArmFrontDoorRedirectConfiguration(rc) } else if fc := routingRule["forwarding_configuration"].([]interface{}); len(fc) != 0 { - routingConfiguration = expandArmFrontDoorForwardingConfiguration(fc, frontDoorPath) + routingConfiguration = expandArmFrontDoorForwardingConfiguration(fc, frontDoorId, subscriptionId) } currentRoutingRule := frontdoor.RoutingRule{ ID: utils.String(id), Name: utils.String(name), RoutingRuleProperties: &frontdoor.RoutingRuleProperties{ - FrontendEndpoints: expandArmFrontDoorFrontEndEndpoints(frontendEndpoints, frontDoorPath), + FrontendEndpoints: expandArmFrontDoorFrontEndEndpoints(frontendEndpoints, frontDoorId, subscriptionId), AcceptedProtocols: expandArmFrontDoorAcceptedProtocols(acceptedProtocols), PatternsToMatch: &patternsToMatch, EnabledState: frontdoor.RoutingRuleEnabledState(expandArmFrontDoorEnabledState(enabled)), @@ -974,16 +976,16 @@ func expandArmFrontDoorAcceptedProtocols(input []interface{}) *[]frontdoor.Proto return &output } -func expandArmFrontDoorFrontEndEndpoints(input []interface{}, frontDoorPath string) *[]frontdoor.SubResource { +func expandArmFrontDoorFrontEndEndpoints(input []interface{}, frontDoorId parse.FrontDoorId, subscriptionId string) *[]frontdoor.SubResource { if len(input) == 0 { return &[]frontdoor.SubResource{} } output := make([]frontdoor.SubResource, 0) - - for _, SubResource := range input { + for _, name := range input { + frontendEndpointId := parse.NewFrontendEndpointID(frontDoorId, name.(string)).ID(subscriptionId) result := frontdoor.SubResource{ - ID: utils.String(frontDoorPath + "/FrontendEndpoints/" + SubResource.(string)), + ID: utils.String(frontendEndpointId), } output = append(output, result) } @@ -1037,7 +1039,7 @@ func expandArmFrontDoorRedirectConfiguration(input []interface{}) frontdoor.Redi return redirectConfiguration } -func expandArmFrontDoorForwardingConfiguration(input []interface{}, frontDoorPath string) frontdoor.ForwardingConfiguration { +func expandArmFrontDoorForwardingConfiguration(input []interface{}, frontDoorId parse.FrontDoorId, subscriptionId string) frontdoor.ForwardingConfiguration { if len(input) == 0 { return frontdoor.ForwardingConfiguration{} } @@ -1050,8 +1052,9 @@ func expandArmFrontDoorForwardingConfiguration(input []interface{}, frontDoorPat cacheQueryParameterStripDirective := v["cache_query_parameter_strip_directive"].(string) cacheEnabled := v["cache_enabled"].(bool) + backendPoolId := parse.NewBackendPoolID(frontDoorId, backendPoolName).ID(subscriptionId) backend := &frontdoor.SubResource{ - ID: utils.String(frontDoorPath + "/BackendPools/" + backendPoolName), + ID: utils.String(backendPoolId), } forwardingConfiguration := frontdoor.ForwardingConfiguration{ From 90080603bcf4bee3cf5fc6b683d2010d8df2d2f2 Mon Sep 17 00:00:00 2001 From: tombuildsstuff Date: Wed, 12 Aug 2020 13:17:34 +0200 Subject: [PATCH 10/41] r/frontdoor: switching to use the parser method for read/delete --- .../services/frontdoor/frontdoor_resource.go | 18 +++++------------- 1 file changed, 5 insertions(+), 13 deletions(-) diff --git a/azurerm/internal/services/frontdoor/frontdoor_resource.go b/azurerm/internal/services/frontdoor/frontdoor_resource.go index 638592e39e21..ae9aff704f04 100644 --- a/azurerm/internal/services/frontdoor/frontdoor_resource.go +++ b/azurerm/internal/services/frontdoor/frontdoor_resource.go @@ -549,8 +549,6 @@ func resourceArmFrontDoorCreateUpdate(d *schema.ResourceData, meta interface{}) // 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{}) @@ -558,7 +556,7 @@ func resourceArmFrontDoorCreateUpdate(d *schema.ResourceData, meta interface{}) frontendEndpointName := frontendEndpoint["name"].(string) // Get current state of endpoint from Azure - resp, err := feClient.Get(feCtx, resourceGroup, name, frontendEndpointName) + resp, err := feClient.Get(ctx, resourceGroup, name, frontendEndpointName) if err != nil { return fmt.Errorf("retrieving Front Door Frontend Endpoint %q (Resource Group %q): %+v", frontendEndpointName, resourceGroup, err) } @@ -666,28 +664,22 @@ func resourceArmFrontDoorDelete(d *schema.ResourceData, meta interface{}) error ctx, cancel := timeouts.ForDelete(meta.(*clients.Client).StopContext, d) defer cancel() - id, err := azure.ParseAzureResourceID(d.Id()) + id, err := parse.FrontDoorID(d.Id()) if err != nil { return err } - resourceGroup := id.ResourceGroup - name := id.Path["frontdoors"] - // Link to issue: https://github.com/Azure/azure-sdk-for-go/issues/6762 - if name == "" { - name = id.Path["Frontdoors"] - } - future, err := client.Delete(ctx, resourceGroup, name) + future, err := client.Delete(ctx, id.ResourceGroup, id.Name) if err != nil { if response.WasNotFound(future.Response()) { return nil } - return fmt.Errorf("deleting Front Door %q (Resource Group %q): %+v", name, resourceGroup, err) + return fmt.Errorf("deleting Front Door %q (Resource Group %q): %+v", id.Name, id.ResourceGroup, err) } if err = future.WaitForCompletionRef(ctx, client.Client); err != nil { if !response.WasNotFound(future.Response()) { - return fmt.Errorf("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", id.Name, id.ResourceGroup, err) } } From 45fdddc73c62eca55976c22214ff7b801351ef97 Mon Sep 17 00:00:00 2001 From: tombuildsstuff Date: Wed, 12 Aug 2020 13:17:54 +0200 Subject: [PATCH 11/41] r/frontdoor: fixing an issue where the checkdestroy function was checking the wrong resource name --- .../services/frontdoor/tests/front_door_resource_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/azurerm/internal/services/frontdoor/tests/front_door_resource_test.go b/azurerm/internal/services/frontdoor/tests/front_door_resource_test.go index a8793ad37554..669e1ffa8c3c 100644 --- a/azurerm/internal/services/frontdoor/tests/front_door_resource_test.go +++ b/azurerm/internal/services/frontdoor/tests/front_door_resource_test.go @@ -267,7 +267,7 @@ func testCheckAzureRMFrontDoorDestroy(s *terraform.State) error { ctx := acceptance.AzureProvider.Meta().(*clients.Client).StopContext for _, rs := range s.RootModule().Resources { - if rs.Type != "azurerm_front_door" { + if rs.Type != "azurerm_frontdoor" { continue } From d707f349cc4f06226c346337f3076f385e1b7d42 Mon Sep 17 00:00:00 2001 From: tombuildsstuff Date: Wed, 12 Aug 2020 13:33:37 +0200 Subject: [PATCH 12/41] r/frontdoor_firewall_policy: switching to use a consistent id formatter --- .../frontdoor_firewall_policy_resource.go | 39 +++++++--------- .../services/frontdoor/frontdoor_resource.go | 2 +- .../frontdoor/parse/frontend_endpoint.go | 2 +- .../parse/web_application_firewall_policy.go | 44 +++++++++++++++++++ .../r/frontdoor_firewall_policy.html.markdown | 2 +- 5 files changed, 63 insertions(+), 26 deletions(-) create mode 100644 azurerm/internal/services/frontdoor/parse/web_application_firewall_policy.go diff --git a/azurerm/internal/services/frontdoor/frontdoor_firewall_policy_resource.go b/azurerm/internal/services/frontdoor/frontdoor_firewall_policy_resource.go index 017cc8bd4993..c0fa7e22ade2 100644 --- a/azurerm/internal/services/frontdoor/frontdoor_firewall_policy_resource.go +++ b/azurerm/internal/services/frontdoor/frontdoor_firewall_policy_resource.go @@ -13,12 +13,15 @@ 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/parse" "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" ) +// TODO: a state migration to patch the ID's + func resourceArmFrontDoorFirewallPolicy() *schema.Resource { return &schema.Resource{ Create: resourceArmFrontDoorFirewallPolicyCreateUpdate, @@ -421,6 +424,7 @@ func resourceArmFrontDoorFirewallPolicy() *schema.Resource { func resourceArmFrontDoorFirewallPolicyCreateUpdate(d *schema.ResourceData, meta interface{}) error { client := meta.(*clients.Client).Frontdoor.FrontDoorsPolicyClient + subscriptionId := meta.(*clients.Client).Account.SubscriptionId ctx, cancel := timeouts.ForCreateUpdate(meta.(*clients.Client).StopContext, d) defer cancel() @@ -428,6 +432,7 @@ func resourceArmFrontDoorFirewallPolicyCreateUpdate(d *schema.ResourceData, meta name := d.Get("name").(string) resourceGroup := d.Get("resource_group_name").(string) + id := parse.NewWebApplicationFirewallPolicyID(resourceGroup, name).ID(subscriptionId) if features.ShouldResourcesBeImported() && d.IsNewResource() { existing, err := client.Get(ctx, resourceGroup, name) @@ -437,7 +442,7 @@ func resourceArmFrontDoorFirewallPolicyCreateUpdate(d *schema.ResourceData, meta } } if existing.ID != nil && *existing.ID != "" { - return tf.ImportAsExistsError("azurerm_frontdoor_firewall_policy", *existing.ID) + return tf.ImportAsExistsError("azurerm_frontdoor_firewall_policy", id) } } @@ -487,15 +492,7 @@ func resourceArmFrontDoorFirewallPolicyCreateUpdate(d *schema.ResourceData, meta return fmt.Errorf("Error waiting for creation of Front Door Firewall %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 Firewall %q (Resource Group %q): %+v", name, resourceGroup, err) - } - if resp.ID == nil { - return fmt.Errorf("Cannot read Front Door Firewall %q (Resource Group %q) ID", name, resourceGroup) - } - d.SetId(*resp.ID) - + d.SetId(id) return resourceArmFrontDoorFirewallPolicyRead(d, meta) } @@ -504,25 +501,23 @@ func resourceArmFrontDoorFirewallPolicyRead(d *schema.ResourceData, meta interfa ctx, cancel := timeouts.ForRead(meta.(*clients.Client).StopContext, d) defer cancel() - id, err := azure.ParseAzureResourceID(d.Id()) + id, err := parse.WebApplicationFirewallPolicyID(d.Id()) if err != nil { return err } - resourceGroup := id.ResourceGroup - name := id.Path["frontdoorwebapplicationfirewallpolicies"] - resp, err := client.Get(ctx, resourceGroup, name) + resp, err := client.Get(ctx, id.ResourceGroup, id.Name) if err != nil { if utils.ResponseWasNotFound(resp.Response) { log.Printf("[INFO] Front Door Firewall Policy %q does not exist - removing from state", d.Id()) d.SetId("") return nil } - return fmt.Errorf("Error reading Front Door Firewall Policy %q (Resource Group %q): %+v", name, resourceGroup, err) + return fmt.Errorf("Error reading Front Door Firewall Policy %q (Resource Group %q): %+v", id.Name, id.ResourceGroup, err) } - d.Set("name", resp.Name) - d.Set("resource_group_name", resourceGroup) + d.Set("name", id.Name) + d.Set("resource_group_name", id.ResourceGroup) if location := resp.Location; location != nil { d.Set("location", azure.NormalizeLocation(*location)) @@ -558,24 +553,22 @@ func resourceArmFrontDoorFirewallPolicyDelete(d *schema.ResourceData, meta inter ctx, cancel := timeouts.ForDelete(meta.(*clients.Client).StopContext, d) defer cancel() - id, err := azure.ParseAzureResourceID(d.Id()) + id, err := parse.WebApplicationFirewallPolicyID(d.Id()) if err != nil { return err } - resourceGroup := id.ResourceGroup - name := id.Path["frontdoorwebapplicationfirewallpolicies"] - future, err := client.Delete(ctx, resourceGroup, name) + future, err := client.Delete(ctx, id.ResourceGroup, id.Name) if err != nil { if response.WasNotFound(future.Response()) { return nil } - return fmt.Errorf("Error deleting Front Door Firewall %q (Resource Group %q): %+v", name, resourceGroup, err) + return fmt.Errorf("Error deleting Front Door Firewall %q (Resource Group %q): %+v", id.Name, id.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 Firewall %q (Resource Group %q): %+v", name, resourceGroup, err) + return fmt.Errorf("Error waiting for deleting Front Door Firewall %q (Resource Group %q): %+v", id.Name, id.ResourceGroup, err) } } diff --git a/azurerm/internal/services/frontdoor/frontdoor_resource.go b/azurerm/internal/services/frontdoor/frontdoor_resource.go index ae9aff704f04..f412879abb85 100644 --- a/azurerm/internal/services/frontdoor/frontdoor_resource.go +++ b/azurerm/internal/services/frontdoor/frontdoor_resource.go @@ -1543,7 +1543,7 @@ func flattenArmFrontDoorFrontendEndpointsSubResources(input *[]frontdoor.SubReso continue } - id, err := parse.FrontDoorFrontendEndpointID(*v.ID) + id, err := parse.FrontendEndpointID(*v.ID) if err != nil { return nil, err } diff --git a/azurerm/internal/services/frontdoor/parse/frontend_endpoint.go b/azurerm/internal/services/frontdoor/parse/frontend_endpoint.go index a8b4663f3718..275467c07b32 100644 --- a/azurerm/internal/services/frontdoor/parse/frontend_endpoint.go +++ b/azurerm/internal/services/frontdoor/parse/frontend_endpoint.go @@ -21,7 +21,7 @@ func (id FrontendEndpointId) ID(subscriptionId string) string { return fmt.Sprintf("%s/frontendEndpoints/%s", base, id.Name) } -func FrontDoorFrontendEndpointID(input string) (*FrontendEndpointId, error) { +func FrontendEndpointID(input string) (*FrontendEndpointId, error) { frontDoorId, id, err := parseFrontDoorChildResourceId(input) if err != nil { return nil, fmt.Errorf("parsing Frontend Endpoint ID %q: %+v", input, err) diff --git a/azurerm/internal/services/frontdoor/parse/web_application_firewall_policy.go b/azurerm/internal/services/frontdoor/parse/web_application_firewall_policy.go new file mode 100644 index 000000000000..5a320251078e --- /dev/null +++ b/azurerm/internal/services/frontdoor/parse/web_application_firewall_policy.go @@ -0,0 +1,44 @@ +package parse + +import ( + "fmt" + + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/helpers/azure" +) + +type WebApplicationFirewallPolicyId struct { + ResourceGroup string + Name string +} + +func NewWebApplicationFirewallPolicyID(resourceGroup, name string) WebApplicationFirewallPolicyId { + return WebApplicationFirewallPolicyId{ + ResourceGroup: resourceGroup, + Name: name, + } +} + +func (id WebApplicationFirewallPolicyId) ID(subscriptionId string) string { + return fmt.Sprintf("/subscriptions/%s/resourceGroups/%s/providers/Microsoft.Network/frontDoorWebApplicationFirewallPolicies/%s", subscriptionId, id.ResourceGroup, id.Name) +} + +func WebApplicationFirewallPolicyID(input string) (*WebApplicationFirewallPolicyId, error) { + id, err := azure.ParseAzureResourceID(input) + if err != nil { + return nil, fmt.Errorf("parsing Web Application Firewall Policy ID %q: %+v", input, err) + } + + policy := WebApplicationFirewallPolicyId{ + ResourceGroup: id.ResourceGroup, + } + + if policy.Name, err = id.PopSegment("frontDoorWebApplicationFirewallPolicies"); err != nil { + return nil, err + } + + if err := id.ValidateNoEmptySegments(input); err != nil { + return nil, err + } + + return &policy, nil +} diff --git a/website/docs/r/frontdoor_firewall_policy.html.markdown b/website/docs/r/frontdoor_firewall_policy.html.markdown index c750b029d230..ba57ecdaa802 100644 --- a/website/docs/r/frontdoor_firewall_policy.html.markdown +++ b/website/docs/r/frontdoor_firewall_policy.html.markdown @@ -249,5 +249,5 @@ The `timeouts` block allows you to specify [timeouts](https://www.terraform.io/d FrontDoor Web Application Firewall Policy can be imported using the `resource id`, e.g. ```shell -$ terraform import azurerm_frontdoor_firewall_policy.example /subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/example-rg/providers/Microsoft.Network/frontdoorwebapplicationfirewallpolicies/example-fdwafpolicy +$ terraform import azurerm_frontdoor_firewall_policy.example /subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/example-rg/providers/Microsoft.Network/frontDoorWebApplicationFirewallPolicies/example-fdwafpolicy ``` From be9d0e28949421c13a382019716bb847ea7c7bb6 Mon Sep 17 00:00:00 2001 From: tombuildsstuff Date: Wed, 12 Aug 2020 13:35:04 +0200 Subject: [PATCH 13/41] refactor: making the helper methods private now this is within the package --- .../frontdoor/frontdoor_custom_https_configuration.go | 8 ++++---- .../frontdoor_custom_https_configuration_resource.go | 4 ++-- azurerm/internal/services/frontdoor/frontdoor_resource.go | 4 ++-- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/azurerm/internal/services/frontdoor/frontdoor_custom_https_configuration.go b/azurerm/internal/services/frontdoor/frontdoor_custom_https_configuration.go index 4f77ce1bf434..08a2e265d202 100644 --- a/azurerm/internal/services/frontdoor/frontdoor_custom_https_configuration.go +++ b/azurerm/internal/services/frontdoor/frontdoor_custom_https_configuration.go @@ -6,7 +6,7 @@ import ( "github.com/hashicorp/terraform-plugin-sdk/helper/validation" ) -func SchemaFrontdoorCustomHttpsConfiguration() map[string]*schema.Schema { +func schemaCustomHttpsConfiguration() map[string]*schema.Schema { return map[string]*schema.Schema{ "certificate_source": { Type: schema.TypeString, @@ -46,12 +46,12 @@ func SchemaFrontdoorCustomHttpsConfiguration() map[string]*schema.Schema { } } -type FlattenedCustomHttpsConfiguration struct { +type flattenedCustomHttpsConfiguration struct { CustomHTTPSConfiguration []interface{} CustomHTTPSProvisioningEnabled bool } -func FlattenArmFrontDoorCustomHttpsConfiguration(properties frontdoor.FrontendEndpointProperties) FlattenedCustomHttpsConfiguration { +func flattenCustomHttpsConfiguration(properties frontdoor.FrontendEndpointProperties) flattenedCustomHttpsConfiguration { customHttpsConfig := make([]interface{}, 0) customHttpsProvisioningEnabled := false @@ -103,7 +103,7 @@ func FlattenArmFrontDoorCustomHttpsConfiguration(properties frontdoor.FrontendEn } } - return FlattenedCustomHttpsConfiguration{ + return flattenedCustomHttpsConfiguration{ CustomHTTPSConfiguration: customHttpsConfig, CustomHTTPSProvisioningEnabled: customHttpsProvisioningEnabled, } diff --git a/azurerm/internal/services/frontdoor/frontdoor_custom_https_configuration_resource.go b/azurerm/internal/services/frontdoor/frontdoor_custom_https_configuration_resource.go index 76c6b132ae8a..ccca546e0516 100644 --- a/azurerm/internal/services/frontdoor/frontdoor_custom_https_configuration_resource.go +++ b/azurerm/internal/services/frontdoor/frontdoor_custom_https_configuration_resource.go @@ -54,7 +54,7 @@ func resourceArmFrontDoorCustomHttpsConfiguration() *schema.Resource { Optional: true, MaxItems: 1, Elem: &schema.Resource{ - Schema: SchemaFrontdoorCustomHttpsConfiguration(), + Schema: schemaCustomHttpsConfiguration(), }, }, }, @@ -141,7 +141,7 @@ func resourceArmFrontDoorCustomHttpsConfigurationRead(d *schema.ResourceData, me if resp.Name != nil { - flattenedHttpsConfig := FlattenArmFrontDoorCustomHttpsConfiguration(*resp.FrontendEndpointProperties) + flattenedHttpsConfig := flattenCustomHttpsConfiguration(*resp.FrontendEndpointProperties) if err := d.Set("custom_https_configuration", flattenedHttpsConfig.CustomHTTPSConfiguration); err != nil { return fmt.Errorf("setting `custom_https_configuration`: %+v", err) } diff --git a/azurerm/internal/services/frontdoor/frontdoor_resource.go b/azurerm/internal/services/frontdoor/frontdoor_resource.go index f412879abb85..61fc96d53f37 100644 --- a/azurerm/internal/services/frontdoor/frontdoor_resource.go +++ b/azurerm/internal/services/frontdoor/frontdoor_resource.go @@ -444,7 +444,7 @@ func resourceArmFrontDoor() *schema.Resource { MaxItems: 1, Deprecated: "Deprecated in favour of `azurerm_frontdoor_custom_https_configuration` resource", Elem: &schema.Resource{ - Schema: SchemaFrontdoorCustomHttpsConfiguration(), + Schema: schemaCustomHttpsConfiguration(), }, }, }, @@ -1263,7 +1263,7 @@ func flattenFrontEndEndpoints(input *[]frontdoor.FrontendEndpoint) (*[]interface webApplicationFirewallPolicyLinkId = *waf.ID } - flattenedHttpsConfig := FlattenArmFrontDoorCustomHttpsConfiguration(*props) + flattenedHttpsConfig := flattenCustomHttpsConfiguration(*props) customHTTPSConfiguration = flattenedHttpsConfig.CustomHTTPSConfiguration customHttpsProvisioningEnabled = flattenedHttpsConfig.CustomHTTPSProvisioningEnabled } From 365663cd009ab2b89e6326a14e7e8f7d8c6a5a9f Mon Sep 17 00:00:00 2001 From: tombuildsstuff Date: Wed, 12 Aug 2020 13:36:02 +0200 Subject: [PATCH 14/41] firewall: placeholders to check the implementations are valid --- .../internal/services/frontdoor/parse/backend_pool_test.go | 5 +++++ .../frontdoor/parse/web_application_firewall_policy_test.go | 5 +++++ 2 files changed, 10 insertions(+) create mode 100644 azurerm/internal/services/frontdoor/parse/backend_pool_test.go create mode 100644 azurerm/internal/services/frontdoor/parse/web_application_firewall_policy_test.go diff --git a/azurerm/internal/services/frontdoor/parse/backend_pool_test.go b/azurerm/internal/services/frontdoor/parse/backend_pool_test.go new file mode 100644 index 000000000000..59e0ffe620c2 --- /dev/null +++ b/azurerm/internal/services/frontdoor/parse/backend_pool_test.go @@ -0,0 +1,5 @@ +package parse + +import "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/resourceid" + +var _ resourceid.Formatter = BackendPoolId{} diff --git a/azurerm/internal/services/frontdoor/parse/web_application_firewall_policy_test.go b/azurerm/internal/services/frontdoor/parse/web_application_firewall_policy_test.go new file mode 100644 index 000000000000..c3eefcfac047 --- /dev/null +++ b/azurerm/internal/services/frontdoor/parse/web_application_firewall_policy_test.go @@ -0,0 +1,5 @@ +package parse + +import "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/resourceid" + +var _ resourceid.Formatter = WebApplicationFirewallPolicyId{} From 2e5a17dcef63e1f2c054365947cd7f4cb753dadc Mon Sep 17 00:00:00 2001 From: tombuildsstuff Date: Thu, 13 Aug 2020 11:49:30 +0200 Subject: [PATCH 15/41] r/frontdoor_custom_https_configuration: fixing the id parsing --- .../frontdoor_custom_https_configuration.go | 20 +- ...oor_custom_https_configuration_resource.go | 232 ++++++++---------- .../services/frontdoor/frontdoor_resource.go | 26 +- azurerm/internal/services/frontdoor/helper.go | 16 +- 4 files changed, 144 insertions(+), 150 deletions(-) diff --git a/azurerm/internal/services/frontdoor/frontdoor_custom_https_configuration.go b/azurerm/internal/services/frontdoor/frontdoor_custom_https_configuration.go index 08a2e265d202..acdf64ddad5e 100644 --- a/azurerm/internal/services/frontdoor/frontdoor_custom_https_configuration.go +++ b/azurerm/internal/services/frontdoor/frontdoor_custom_https_configuration.go @@ -51,9 +51,14 @@ type flattenedCustomHttpsConfiguration struct { CustomHTTPSProvisioningEnabled bool } -func flattenCustomHttpsConfiguration(properties frontdoor.FrontendEndpointProperties) flattenedCustomHttpsConfiguration { - customHttpsConfig := make([]interface{}, 0) - customHttpsProvisioningEnabled := false +func flattenCustomHttpsConfiguration(properties *frontdoor.FrontendEndpointProperties) flattenedCustomHttpsConfiguration { + result := flattenedCustomHttpsConfiguration{ + CustomHTTPSConfiguration: make([]interface{}, 0), + CustomHTTPSProvisioningEnabled: false, + } + if properties == nil { + return result + } if config := properties.CustomHTTPSConfiguration; config != nil { certificateSource := string(frontdoor.CertificateSourceFrontDoor) @@ -84,14 +89,14 @@ func flattenCustomHttpsConfiguration(properties frontdoor.FrontendEndpointProper if properties.CustomHTTPSProvisioningState != "" { provisioningState = string(properties.CustomHTTPSProvisioningState) if properties.CustomHTTPSProvisioningState == frontdoor.CustomHTTPSProvisioningStateEnabled || properties.CustomHTTPSProvisioningState == frontdoor.CustomHTTPSProvisioningStateEnabling { - customHttpsProvisioningEnabled = true + result.CustomHTTPSProvisioningEnabled = true if properties.CustomHTTPSProvisioningSubstate != "" { provisioningSubstate = string(properties.CustomHTTPSProvisioningSubstate) } } - customHttpsConfig = append(customHttpsConfig, map[string]interface{}{ + result.CustomHTTPSConfiguration = append(result.CustomHTTPSConfiguration, map[string]interface{}{ "azure_key_vault_certificate_vault_id": keyVaultCertificateVaultId, "azure_key_vault_certificate_secret_name": keyVaultCertificateSecretName, "azure_key_vault_certificate_secret_version": keyVaultCertificateSecretVersion, @@ -103,8 +108,5 @@ func flattenCustomHttpsConfiguration(properties frontdoor.FrontendEndpointProper } } - return flattenedCustomHttpsConfiguration{ - CustomHTTPSConfiguration: customHttpsConfig, - CustomHTTPSProvisioningEnabled: customHttpsProvisioningEnabled, - } + return result } diff --git a/azurerm/internal/services/frontdoor/frontdoor_custom_https_configuration_resource.go b/azurerm/internal/services/frontdoor/frontdoor_custom_https_configuration_resource.go index ccca546e0516..0024d04d7d4c 100644 --- a/azurerm/internal/services/frontdoor/frontdoor_custom_https_configuration_resource.go +++ b/azurerm/internal/services/frontdoor/frontdoor_custom_https_configuration_resource.go @@ -11,11 +11,15 @@ import ( "github.com/terraform-providers/terraform-provider-azurerm/azurerm/helpers/azure" "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/clients" "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/locks" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/services/frontdoor/parse" "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/services/frontdoor/validate" "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/timeouts" "github.com/terraform-providers/terraform-provider-azurerm/azurerm/utils" ) +// TODO: switch to using the Frontend Endpoint ID here with a state migration +// this was: `resourceId = fmt.Sprintf("%s/customHttpsConfiguration/%s", *id, frontendEndpointName)` + func resourceArmFrontDoorCustomHttpsConfiguration() *schema.Resource { return &schema.Resource{ Create: resourceArmFrontDoorCustomHttpsConfigurationCreateUpdate, @@ -71,47 +75,41 @@ func resourceArmFrontDoorCustomHttpsConfiguration() *schema.Resource { func resourceArmFrontDoorCustomHttpsConfigurationCreateUpdate(d *schema.ResourceData, meta interface{}) error { client := meta.(*clients.Client).Frontdoor.FrontDoorsFrontendClient + subscriptionId := meta.(*clients.Client).Account.SubscriptionId ctx, cancel := timeouts.ForCreateUpdate(meta.(*clients.Client).StopContext, d) defer cancel() - err, resourceGroup, frontDoorName, frontendEndpointName := frontDoorFrontendEndpointReadProps(d) + id, err := parse.FrontendEndpointID(d.Get("frontend_endpoint_id").(string)) if err != nil { return err } - resp, err := client.Get(ctx, resourceGroup, frontDoorName, frontendEndpointName) - if err != nil { - return fmt.Errorf("reading Front Door Endpoint %q (Resource Group %q): %+v", frontendEndpointName, resourceGroup, err) - } - - // This is because azure doesn't have an 'id' for a custom https configuration - // In order to compensate for this and allow importing of this resource we are artificially - // creating an identity for a custom https configuration object - var resourceId string - if id := resp.ID; id != nil && *id != "" { - resourceId = fmt.Sprintf("%s/customHttpsConfiguration/%s", *id, frontendEndpointName) - } else { - return fmt.Errorf("unable to retrieve Front Door Endpoint %q (Resource Group %q) ID", frontendEndpointName, resourceGroup) - } + // TODO: Requires Import support - customHttpsProvisioningEnabled := d.Get("custom_https_provisioning_enabled").(bool) - customHttpsConfigurationNew := d.Get("custom_https_configuration").([]interface{}) - err = resourceArmFrontDoorFrontendEndpointCustomHttpsConfigurationUpdate(ctx, *resp.ID, customHttpsProvisioningEnabled, frontDoorName, frontendEndpointName, resourceGroup, resp.CustomHTTPSProvisioningState, resp.CustomHTTPSConfiguration, customHttpsConfigurationNew, meta) + resp, err := client.Get(ctx, id.ResourceGroup, id.FrontDoorName, id.Name) if err != nil { - return fmt.Errorf("unable to update Custom HTTPS configuration for Frontend Endpoint %q (Resource Group %q): %+v", frontendEndpointName, resourceGroup, err) + return fmt.Errorf("reading Front Door Endpoint %q (Resource Group %q): %+v", id.Name, id.FrontDoorName, id.ResourceGroup, err) } - resp, err = client.Get(ctx, resourceGroup, frontDoorName, frontendEndpointName) - if err != nil { - return fmt.Errorf("retreving Front Door Endpoint %q (Resource Group %q): %+v", frontendEndpointName, resourceGroup, err) + if resp.FrontendEndpointProperties == nil { + return fmt.Errorf("reading Front Door Endpoint %q (Resource Group %q): `properties` was nil", id.Name, id.FrontDoorName, id.ResourceGroup) } - - if resp.ID == nil { - return fmt.Errorf("cannot read Front Door Endpoint %q (Resource Group %q) ID", frontendEndpointName, resourceGroup) + props := *resp.FrontendEndpointProperties + + input := customHttpsConfigurationUpdateInput{ + customHttpsConfigurationCurrent: props.CustomHTTPSConfiguration, + customHttpsConfigurationNew: d.Get("custom_https_configuration").([]interface{}), + customHttpsProvisioningEnabled: d.Get("custom_https_provisioning_enabled").(bool), + frontendEndpointId: *id, + provisioningState: props.CustomHTTPSProvisioningState, + subscriptionId: subscriptionId, + } + if err := updateCustomHttpsConfiguration(ctx, client, input); err != nil { + return fmt.Errorf("updating Custom HTTPS configuration for Frontend Endpoint %q (Front Door %q / Resource Group %q): %+v", id.Name, id.FrontDoorName, id.ResourceGroup, err) } if d.IsNewResource() { - d.SetId(resourceId) + d.SetId(id.ID(subscriptionId)) } return nil @@ -122,34 +120,30 @@ func resourceArmFrontDoorCustomHttpsConfigurationRead(d *schema.ResourceData, me ctx, cancel := timeouts.ForRead(meta.(*clients.Client).StopContext, d) defer cancel() - err, resourceGroup, frontDoorName, frontendEndpointName := frontDoorCustomHttpsConfigurationReadProps(d) + id, err := parse.FrontendEndpointID(d.Id()) if err != nil { return err } - resp, err := client.Get(ctx, resourceGroup, frontDoorName, frontendEndpointName) + resp, err := client.Get(ctx, id.ResourceGroup, id.FrontDoorName, id.Name) if err != nil { if utils.ResponseWasNotFound(resp.Response) { log.Printf("[INFO] Front Door Endpoint %q does not exist - removing from state", d.Id()) d.SetId("") return nil } - return fmt.Errorf("reading Front Door Endpoint %q (Resource Group %q): %+v", frontendEndpointName, resourceGroup, err) + + return fmt.Errorf("reading Front Door Endpoint %q (Resource Group %q): %+v", id.Name, id.ResourceGroup, err) } d.Set("frontend_endpoint_id", resp.ID) - if resp.Name != nil { - - flattenedHttpsConfig := flattenCustomHttpsConfiguration(*resp.FrontendEndpointProperties) - if err := d.Set("custom_https_configuration", flattenedHttpsConfig.CustomHTTPSConfiguration); err != nil { - return fmt.Errorf("setting `custom_https_configuration`: %+v", err) - } - if err := d.Set("custom_https_provisioning_enabled", flattenedHttpsConfig.CustomHTTPSProvisioningEnabled); err != nil { - return fmt.Errorf("setting `custom_https_provisioning_enabled`: %+v", err) - } - } else { - return fmt.Errorf("flattening `frontend_endpoint` `custom_https_configuration`: Unable to read Frontend Endpoint Name") + flattenedHttpsConfig := flattenCustomHttpsConfiguration(resp.FrontendEndpointProperties) + if err := d.Set("custom_https_configuration", flattenedHttpsConfig.CustomHTTPSConfiguration); err != nil { + return fmt.Errorf("setting `custom_https_configuration`: %+v", err) + } + if err := d.Set("custom_https_provisioning_enabled", flattenedHttpsConfig.CustomHTTPSProvisioningEnabled); err != nil { + return fmt.Errorf("setting `custom_https_provisioning_enabled`: %+v", err) } return nil @@ -157,132 +151,124 @@ func resourceArmFrontDoorCustomHttpsConfigurationRead(d *schema.ResourceData, me func resourceArmFrontDoorCustomHttpsConfigurationDelete(d *schema.ResourceData, meta interface{}) error { client := meta.(*clients.Client).Frontdoor.FrontDoorsFrontendClient + subscriptionId := meta.(*clients.Client).Account.SubscriptionId ctx, cancel := timeouts.ForDelete(meta.(*clients.Client).StopContext, d) defer cancel() - err, resourceGroup, frontDoorName, frontendEndpointName := frontDoorCustomHttpsConfigurationReadProps(d) + id, err := parse.FrontendEndpointID(d.Id()) if err != nil { return err } - resp, err := client.Get(ctx, resourceGroup, frontDoorName, frontendEndpointName) + resp, err := client.Get(ctx, id.ResourceGroup, id.FrontDoorName, id.Name) if err != nil { if utils.ResponseWasNotFound(resp.Response) { return nil } - return fmt.Errorf("reading Front Door Endpoint %q (Resource Group %q): %+v", frontendEndpointName, resourceGroup, err) + return fmt.Errorf("reading Frontend Endpoint %q (Front Door %q / Resource Group %q): %+v", id.Name, id.FrontDoorName, id.ResourceGroup, err) } - customHttpsConfigurationNew := make([]interface{}, 0) - err = resourceArmFrontDoorFrontendEndpointCustomHttpsConfigurationUpdate(ctx, *resp.ID, false, frontDoorName, frontendEndpointName, resourceGroup, resp.CustomHTTPSProvisioningState, resp.CustomHTTPSConfiguration, customHttpsConfigurationNew, meta) - if err != nil { - return fmt.Errorf("unable to disable Custom HTTPS configuration for Frontend Endpoint %q (Resource Group %q): %+v", frontendEndpointName, resourceGroup, err) + if resp.FrontendEndpointProperties == nil { + return fmt.Errorf("reading Frontend Endpoint %q (Front Door %q / Resource Group %q): `properties` was nil", id.Name, id.FrontDoorName, id.ResourceGroup) + } + props := *resp.FrontendEndpointProperties + + input := customHttpsConfigurationUpdateInput{ + customHttpsConfigurationCurrent: props.CustomHTTPSConfiguration, + customHttpsConfigurationNew: make([]interface{}, 0), + customHttpsProvisioningEnabled: false, + frontendEndpointId: *id, + provisioningState: props.CustomHTTPSProvisioningState, + subscriptionId: subscriptionId, + } + if err := updateCustomHttpsConfiguration(ctx, client, input); err != nil { + return fmt.Errorf("disabling Custom HTTPS configuration for Frontend Endpoint %q (Front Door %q / Resource Group %q): %+v", id.Name, id.FrontDoorName, id.ResourceGroup, err) } return nil } -func frontDoorFrontendEndpointReadProps(d *schema.ResourceData) (err error, resourceGroup string, frontDoorName string, frontendEndpointName string) { - id, err := azure.ParseAzureResourceID(d.Get("frontend_endpoint_id").(string)) - if err != nil { - return err, "", "", "" - } - return frontDoorReadPropsFromId(id) +type customHttpsConfigurationUpdateInput struct { + customHttpsConfigurationCurrent *frontdoor.CustomHTTPSConfiguration + customHttpsConfigurationNew []interface{} + customHttpsProvisioningEnabled bool + frontendEndpointId parse.FrontendEndpointId + provisioningState frontdoor.CustomHTTPSProvisioningState + subscriptionId string } -func frontDoorCustomHttpsConfigurationReadProps(d *schema.ResourceData) (err error, resourceGroup string, frontDoorName string, frontendEndpointName string) { - id, err := azure.ParseAzureResourceID(d.Id()) - if err != nil { - return err, "", "", "" - } - return frontDoorReadPropsFromId(id) -} +func updateCustomHttpsConfiguration(ctx context.Context, client *frontdoor.FrontendEndpointsClient, input customHttpsConfigurationUpdateInput) error { + // Locking to prevent parallel changes causing issues + frontendEndpointResourceId := input.frontendEndpointId.ID(input.subscriptionId) + locks.ByID(frontendEndpointResourceId) + defer locks.UnlockByID(frontendEndpointResourceId) -func frontDoorReadPropsFromId(id *azure.ResourceID) (err error, resourceGroup string, frontDoorName string, frontendEndpointName string) { - resourceGroup = id.ResourceGroup - frontDoorName = id.Path["frontdoors"] - // Link to issue: https://github.com/Azure/azure-sdk-for-go/issues/6762 - if frontDoorName == "" { - frontDoorName = id.Path["Frontdoors"] - } - frontendEndpointName = id.Path["frontendendpoints"] - if frontendEndpointName == "" { - frontDoorName = id.Path["FrontendEndpoints"] + if input.provisioningState == "" { + return nil } - return nil, resourceGroup, frontDoorName, frontendEndpointName -} - -func resourceArmFrontDoorFrontendEndpointCustomHttpsConfigurationUpdate(ctx context.Context, frontendEndpointId string, customHttpsProvisioningEnabled bool, frontDoorName string, frontendEndpointName string, resourceGroup string, provisioningState frontdoor.CustomHTTPSProvisioningState, customHTTPSConfigurationCurrent *frontdoor.CustomHTTPSConfiguration, customHttpsConfigurationNew []interface{}, meta interface{}) error { - // Locking to prevent parallel changes causing issues - locks.ByID(frontendEndpointId) - defer locks.UnlockByID(frontendEndpointId) - - if provisioningState != "" { - // Check to see if we are going to change the CustomHTTPSProvisioningState, if so check to - // see if its current state is configurable, if not return an error... - if customHttpsProvisioningEnabled != NormalizeCustomHTTPSProvisioningStateToBool(provisioningState) { - if err := IsFrontDoorFrontendEndpointConfigurable(provisioningState, customHttpsProvisioningEnabled, frontendEndpointName, resourceGroup); err != nil { - return err - } + // Check to see if we are going to change the CustomHTTPSProvisioningState, if so check to + // see if its current state is configurable, if not return an error... + if input.customHttpsProvisioningEnabled != NormalizeCustomHTTPSProvisioningStateToBool(input.provisioningState) { + if err := isFrontDoorFrontendEndpointConfigurable(input.provisioningState, input.customHttpsProvisioningEnabled, input.frontendEndpointId); err != nil { + return err } + } - if customHttpsProvisioningEnabled { - // Build a custom Https configuration based off the config file to send to the enable call - // NOTE: I do not need to check to see if this exists since I already do that in the validation code - customHTTPSConfiguration := customHttpsConfigurationNew[0].(map[string]interface{}) - minTLSVersion := frontdoor.OneFullStopTwo // Default to TLS 1.2 - if httpsConfig := customHTTPSConfigurationCurrent; httpsConfig != nil { - minTLSVersion = httpsConfig.MinimumTLSVersion - } - customHTTPSConfigurationUpdate := makeCustomHttpsConfiguration(customHTTPSConfiguration, minTLSVersion) - if provisioningState == frontdoor.CustomHTTPSProvisioningStateDisabled || customHTTPSConfigurationUpdate != *customHTTPSConfigurationCurrent { - // Enable Custom Domain HTTPS for the Frontend Endpoint - if err := resourceArmFrontDoorFrontendEndpointEnableHttpsProvisioning(ctx, true, frontDoorName, frontendEndpointName, resourceGroup, customHTTPSConfigurationUpdate, meta); err != nil { - return fmt.Errorf("unable to enable/update Custom Domain HTTPS for Frontend Endpoint %q (Resource Group %q): %+v", frontendEndpointName, resourceGroup, err) - } - } - } else if !customHttpsProvisioningEnabled && provisioningState == frontdoor.CustomHTTPSProvisioningStateEnabled { - // Disable Custom Domain HTTPS for the Frontend Endpoint - if err := resourceArmFrontDoorFrontendEndpointEnableHttpsProvisioning(ctx, false, frontDoorName, frontendEndpointName, resourceGroup, frontdoor.CustomHTTPSConfiguration{}, meta); err != nil { - return fmt.Errorf("unable to disable Custom Domain HTTPS for Frontend Endpoint %q (Resource Group %q): %+v", frontendEndpointName, resourceGroup, err) + if input.customHttpsProvisioningEnabled { + // Build a custom Https configuration based off the config file to send to the enable call + // NOTE: I do not need to check to see if this exists since I already do that in the validation code + customHTTPSConfiguration := input.customHttpsConfigurationNew[0].(map[string]interface{}) + minTLSVersion := frontdoor.OneFullStopTwo // Default to TLS 1.2 + if httpsConfig := input.customHttpsConfigurationCurrent; httpsConfig != nil { + minTLSVersion = httpsConfig.MinimumTLSVersion + } + customHTTPSConfigurationUpdate := makeCustomHttpsConfiguration(customHTTPSConfiguration, minTLSVersion) + if input.provisioningState == frontdoor.CustomHTTPSProvisioningStateDisabled || customHTTPSConfigurationUpdate != *input.customHttpsConfigurationCurrent { + // Enable Custom Domain HTTPS for the Frontend Endpoint + if err := resourceArmFrontDoorFrontendEndpointEnableHttpsProvisioning(ctx, client, input.frontendEndpointId, true, customHTTPSConfigurationUpdate); err != nil { + return fmt.Errorf("unable to enable/update Custom Domain HTTPS for Frontend Endpoint %q (Resource Group %q): %+v", input.frontendEndpointId.Name, input.frontendEndpointId.ResourceGroup, err) } } + } else if !input.customHttpsProvisioningEnabled && input.provisioningState == frontdoor.CustomHTTPSProvisioningStateEnabled { + // Disable Custom Domain HTTPS for the Frontend Endpoint + if err := resourceArmFrontDoorFrontendEndpointEnableHttpsProvisioning(ctx, client, input.frontendEndpointId, false, frontdoor.CustomHTTPSConfiguration{}); err != nil { + return fmt.Errorf("unable to disable Custom Domain HTTPS for Frontend Endpoint %q (Resource Group %q): %+v", input.frontendEndpointId.Name, input.frontendEndpointId.ResourceGroup, err) + } } return nil } -func resourceArmFrontDoorFrontendEndpointEnableHttpsProvisioning(ctx context.Context, enableCustomHttpsProvisioning bool, frontDoorName string, frontendEndpointName string, resourceGroup string, customHTTPSConfiguration frontdoor.CustomHTTPSConfiguration, meta interface{}) error { - client := meta.(*clients.Client).Frontdoor.FrontDoorsFrontendClient - +func resourceArmFrontDoorFrontendEndpointEnableHttpsProvisioning(ctx context.Context, client *frontdoor.FrontendEndpointsClient, id parse.FrontendEndpointId, enableCustomHttpsProvisioning bool, customHTTPSConfiguration frontdoor.CustomHTTPSConfiguration) error { if enableCustomHttpsProvisioning { - future, err := client.EnableHTTPS(ctx, resourceGroup, frontDoorName, frontendEndpointName, customHTTPSConfiguration) - + future, err := client.EnableHTTPS(ctx, id.ResourceGroup, id.FrontDoorName, id.Name, customHTTPSConfiguration) if err != nil { return fmt.Errorf("enabling Custom Domain HTTPS for Frontend Endpoint: %+v", err) } if err = future.WaitForCompletionRef(ctx, client.Client); err != nil { return fmt.Errorf("waiting to enable Custom Domain HTTPS for Frontend Endpoint: %+v", err) } - } else { - future, err := client.DisableHTTPS(ctx, resourceGroup, frontDoorName, frontendEndpointName) + return nil + } + + future, err := client.DisableHTTPS(ctx, id.ResourceGroup, id.FrontDoorName, id.Name) + + if err != nil { + return fmt.Errorf("disabling Custom Domain HTTPS for Frontend Endpoint: %+v", err) + } + if err = future.WaitForCompletionRef(ctx, client.Client); err != nil { + // If the endpoint does not exist but this is not a new resource, the custom https + // configuration which previously existed was deleted with the endpoint, so reflect + // that in state. + resp, err := client.Get(ctx, id.ResourceGroup, id.FrontDoorName, id.Name) if err != nil { - return fmt.Errorf("disabling Custom Domain HTTPS for Frontend Endpoint: %+v", err) - } - if err = future.WaitForCompletionRef(ctx, client.Client); err != nil { - // If the endpoint does not exist but this is not a new resource, the custom https - // configuration which previously existed was deleted with the endpoint, so reflect - // that in state. - resp, err := client.Get(ctx, resourceGroup, frontDoorName, frontendEndpointName) - if err != nil { - if utils.ResponseWasNotFound(resp.Response) { - return nil - } + if utils.ResponseWasNotFound(resp.Response) { + return nil } - return fmt.Errorf("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) } return nil diff --git a/azurerm/internal/services/frontdoor/frontdoor_resource.go b/azurerm/internal/services/frontdoor/frontdoor_resource.go index 61fc96d53f37..2fc4133c4962 100644 --- a/azurerm/internal/services/frontdoor/frontdoor_resource.go +++ b/azurerm/internal/services/frontdoor/frontdoor_resource.go @@ -553,22 +553,28 @@ func resourceArmFrontDoorCreateUpdate(d *schema.ResourceData, meta interface{}) for _, v := range frontendEndpoints { frontendEndpoint := v.(map[string]interface{}) customHttpsProvisioningEnabled := frontendEndpoint["custom_https_provisioning_enabled"].(bool) - frontendEndpointName := frontendEndpoint["name"].(string) + endpointName := frontendEndpoint["name"].(string) // Get current state of endpoint from Azure - resp, err := feClient.Get(ctx, resourceGroup, name, frontendEndpointName) + resp, err := feClient.Get(ctx, resourceGroup, name, endpointName) if err != nil { - 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("retrieving Front Door Frontend Endpoint %q (Resource Group %q): %+v", endpointName, resourceGroup, err) } if properties := resp.FrontendEndpointProperties; properties != nil { + frontendClient := meta.(*clients.Client).Frontdoor.FrontDoorsFrontendClient customHttpsConfigurationNew := frontendEndpoint["custom_https_configuration"].([]interface{}) - err := resourceArmFrontDoorFrontendEndpointCustomHttpsConfigurationUpdate(ctx, *resp.ID, customHttpsProvisioningEnabled, name, frontendEndpointName, resourceGroup, properties.CustomHTTPSProvisioningState, properties.CustomHTTPSConfiguration, customHttpsConfigurationNew, meta) - if err != nil { - return fmt.Errorf("unable to update Custom HTTPS configuration for Frontend Endpoint %q (Resource Group %q): %+v", frontendEndpointName, resourceGroup, err) + frontendInputId := parse.NewFrontendEndpointID(frontDoorId, endpointName) + input := customHttpsConfigurationUpdateInput{ + customHttpsConfigurationCurrent: properties.CustomHTTPSConfiguration, + customHttpsConfigurationNew: customHttpsConfigurationNew, + customHttpsProvisioningEnabled: customHttpsProvisioningEnabled, + frontendEndpointId: frontendInputId, + provisioningState: properties.CustomHTTPSProvisioningState, + subscriptionId: subscriptionId, + } + if err := updateCustomHttpsConfiguration(ctx, frontendClient, input); err != nil { + return fmt.Errorf("updating Custom HTTPS configuration for Frontend Endpoint %q (Front Door %q / Resource Group %q): %+v", endpointName, name, resourceGroup, err) } } } @@ -1263,7 +1269,7 @@ func flattenFrontEndEndpoints(input *[]frontdoor.FrontendEndpoint) (*[]interface webApplicationFirewallPolicyLinkId = *waf.ID } - flattenedHttpsConfig := flattenCustomHttpsConfiguration(*props) + flattenedHttpsConfig := flattenCustomHttpsConfiguration(props) customHTTPSConfiguration = flattenedHttpsConfig.CustomHTTPSConfiguration customHttpsProvisioningEnabled = flattenedHttpsConfig.CustomHTTPSProvisioningEnabled } diff --git a/azurerm/internal/services/frontdoor/helper.go b/azurerm/internal/services/frontdoor/helper.go index deb3d9963b16..d001b7a85966 100644 --- a/azurerm/internal/services/frontdoor/helper.go +++ b/azurerm/internal/services/frontdoor/helper.go @@ -4,9 +4,10 @@ import ( "fmt" "github.com/Azure/azure-sdk-for-go/services/frontdoor/mgmt/2020-01-01/frontdoor" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/services/frontdoor/parse" ) -func IsFrontDoorFrontendEndpointConfigurable(currentState frontdoor.CustomHTTPSProvisioningState, customHttpsProvisioningEnabled bool, frontendEndpointName string, resourceGroup string) error { +func isFrontDoorFrontendEndpointConfigurable(currentState frontdoor.CustomHTTPSProvisioningState, customHttpsProvisioningEnabled bool, frontendEndpointId parse.FrontendEndpointId) error { action := "disable" if customHttpsProvisioningEnabled { action = "enable" @@ -14,19 +15,14 @@ func IsFrontDoorFrontendEndpointConfigurable(currentState frontdoor.CustomHTTPSP switch currentState { case frontdoor.CustomHTTPSProvisioningStateDisabling, frontdoor.CustomHTTPSProvisioningStateEnabling, frontdoor.CustomHTTPSProvisioningStateFailed: - return fmt.Errorf("Unable to %s the Front Door Frontend Endpoint %q (Resource Group %q) Custom Domain HTTPS state because the Frontend Endpoint is currently in the %q state", action, frontendEndpointName, resourceGroup, currentState) + return fmt.Errorf("Unable to %s the Front Door Frontend Endpoint %q (Resource Group %q) Custom Domain HTTPS state because the Frontend Endpoint is currently in the %q state", action, frontendEndpointId.Name, frontendEndpointId.ResourceGroup, currentState) default: return nil } } func NormalizeCustomHTTPSProvisioningStateToBool(provisioningState frontdoor.CustomHTTPSProvisioningState) bool { - isEnabled := false - if provisioningState == frontdoor.CustomHTTPSProvisioningStateEnabled || provisioningState == frontdoor.CustomHTTPSProvisioningStateEnabling { - isEnabled = true - } - - return isEnabled + return provisioningState == frontdoor.CustomHTTPSProvisioningStateEnabled || provisioningState == frontdoor.CustomHTTPSProvisioningStateEnabling } func FlattenTransformSlice(input *[]frontdoor.TransformType) []interface{} { @@ -45,6 +41,10 @@ func FlattenFrontendEndpointLinkSlice(input *[]frontdoor.FrontendEndpointLink) [ if input != nil { for _, item := range *input { + if item.ID == nil { + continue + } + result = append(result, *item.ID) } } From 6b29cbf96850c87d08feb3b45f36b2b137dcfc70 Mon Sep 17 00:00:00 2001 From: tombuildsstuff Date: Thu, 13 Aug 2020 12:14:08 +0200 Subject: [PATCH 16/41] r/frontdoor*: adding import-time validators to check the ID is in the correct format --- .../frontdoor_custom_https_configuration_resource.go | 8 +++++--- .../frontdoor/frontdoor_firewall_policy_resource.go | 8 +++++--- azurerm/internal/services/frontdoor/frontdoor_resource.go | 8 +++++--- 3 files changed, 15 insertions(+), 9 deletions(-) diff --git a/azurerm/internal/services/frontdoor/frontdoor_custom_https_configuration_resource.go b/azurerm/internal/services/frontdoor/frontdoor_custom_https_configuration_resource.go index 0024d04d7d4c..89a10e2d94f3 100644 --- a/azurerm/internal/services/frontdoor/frontdoor_custom_https_configuration_resource.go +++ b/azurerm/internal/services/frontdoor/frontdoor_custom_https_configuration_resource.go @@ -13,6 +13,7 @@ import ( "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/locks" "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/services/frontdoor/parse" "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/services/frontdoor/validate" + azSchema "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/tf/schema" "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/timeouts" "github.com/terraform-providers/terraform-provider-azurerm/azurerm/utils" ) @@ -27,9 +28,10 @@ func resourceArmFrontDoorCustomHttpsConfiguration() *schema.Resource { Update: resourceArmFrontDoorCustomHttpsConfigurationCreateUpdate, Delete: resourceArmFrontDoorCustomHttpsConfigurationDelete, - Importer: &schema.ResourceImporter{ - State: schema.ImportStatePassthrough, - }, + Importer: azSchema.ValidateResourceIDPriorToImport(func(id string) error { + _, err := parse.FrontendEndpointID(id) + return err + }), Timeouts: &schema.ResourceTimeout{ Create: schema.DefaultTimeout(6 * time.Hour), diff --git a/azurerm/internal/services/frontdoor/frontdoor_firewall_policy_resource.go b/azurerm/internal/services/frontdoor/frontdoor_firewall_policy_resource.go index c0fa7e22ade2..6fd8fb1b1a37 100644 --- a/azurerm/internal/services/frontdoor/frontdoor_firewall_policy_resource.go +++ b/azurerm/internal/services/frontdoor/frontdoor_firewall_policy_resource.go @@ -16,6 +16,7 @@ import ( "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/services/frontdoor/parse" "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/services/frontdoor/validate" "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/tags" + azSchema "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/tf/schema" "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/timeouts" "github.com/terraform-providers/terraform-provider-azurerm/azurerm/utils" ) @@ -29,9 +30,10 @@ func resourceArmFrontDoorFirewallPolicy() *schema.Resource { Update: resourceArmFrontDoorFirewallPolicyCreateUpdate, Delete: resourceArmFrontDoorFirewallPolicyDelete, - Importer: &schema.ResourceImporter{ - State: schema.ImportStatePassthrough, - }, + Importer: azSchema.ValidateResourceIDPriorToImport(func(id string) error { + _, err := parse.WebApplicationFirewallPolicyID(id) + return err + }), Timeouts: &schema.ResourceTimeout{ Create: schema.DefaultTimeout(30 * time.Minute), diff --git a/azurerm/internal/services/frontdoor/frontdoor_resource.go b/azurerm/internal/services/frontdoor/frontdoor_resource.go index 2fc4133c4962..3d167e56ba41 100644 --- a/azurerm/internal/services/frontdoor/frontdoor_resource.go +++ b/azurerm/internal/services/frontdoor/frontdoor_resource.go @@ -18,6 +18,7 @@ import ( "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/services/frontdoor/parse" "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/services/frontdoor/validate" "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/tags" + azSchema "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/tf/schema" "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/timeouts" "github.com/terraform-providers/terraform-provider-azurerm/azurerm/utils" ) @@ -31,9 +32,10 @@ func resourceArmFrontDoor() *schema.Resource { Update: resourceArmFrontDoorCreateUpdate, Delete: resourceArmFrontDoorDelete, - Importer: &schema.ResourceImporter{ - State: schema.ImportStatePassthrough, - }, + Importer: azSchema.ValidateResourceIDPriorToImport(func(id string) error { + _, err := parse.FrontDoorID(id) + return err + }), SchemaVersion: 1, From 6320275a9975374cb837b3a7e701eec228c518a0 Mon Sep 17 00:00:00 2001 From: tombuildsstuff Date: Thu, 13 Aug 2020 12:24:22 +0200 Subject: [PATCH 17/41] r/frontdoor_firewall_policy: refactoring --- .../frontdoor_firewall_policy_resource.go | 25 +++++++++---------- 1 file changed, 12 insertions(+), 13 deletions(-) diff --git a/azurerm/internal/services/frontdoor/frontdoor_firewall_policy_resource.go b/azurerm/internal/services/frontdoor/frontdoor_firewall_policy_resource.go index 6fd8fb1b1a37..f24e956bea27 100644 --- a/azurerm/internal/services/frontdoor/frontdoor_firewall_policy_resource.go +++ b/azurerm/internal/services/frontdoor/frontdoor_firewall_policy_resource.go @@ -12,7 +12,6 @@ import ( "github.com/terraform-providers/terraform-provider-azurerm/azurerm/helpers/azure" "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/parse" "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/services/frontdoor/validate" "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/tags" @@ -436,11 +435,11 @@ func resourceArmFrontDoorFirewallPolicyCreateUpdate(d *schema.ResourceData, meta resourceGroup := d.Get("resource_group_name").(string) id := parse.NewWebApplicationFirewallPolicyID(resourceGroup, name).ID(subscriptionId) - if features.ShouldResourcesBeImported() && d.IsNewResource() { + if d.IsNewResource() { existing, err := client.Get(ctx, resourceGroup, name) if err != nil { if !utils.ResponseWasNotFound(existing.Response) { - return fmt.Errorf("Error checking for present of existing Front Door Firewall Policy %q (Resource Group %q): %+v", name, resourceGroup, err) + return fmt.Errorf("checking for existing Front Door Firewall Policy %q (Resource Group %q): %+v", name, resourceGroup, err) } } if existing.ID != nil && *existing.ID != "" { @@ -488,10 +487,10 @@ func resourceArmFrontDoorFirewallPolicyCreateUpdate(d *schema.ResourceData, meta future, err := client.CreateOrUpdate(ctx, resourceGroup, name, frontdoorWebApplicationFirewallPolicy) if err != nil { - return fmt.Errorf("Error creating Front Door Firewall policy %q (Resource Group %q): %+v", name, resourceGroup, err) + return fmt.Errorf("creating Front Door Firewall Policy %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 Firewall %q (Resource Group %q): %+v", name, resourceGroup, err) + return fmt.Errorf("waiting for creation of Front Door Firewall Policy %q (Resource Group %q): %+v", name, resourceGroup, err) } d.SetId(id) @@ -515,7 +514,7 @@ func resourceArmFrontDoorFirewallPolicyRead(d *schema.ResourceData, meta interfa d.SetId("") return nil } - return fmt.Errorf("Error reading Front Door Firewall Policy %q (Resource Group %q): %+v", id.Name, id.ResourceGroup, err) + return fmt.Errorf("retrieving Front Door Firewall Policy %q (Resource Group %q): %+v", id.Name, id.ResourceGroup, err) } d.Set("name", id.Name) @@ -535,15 +534,15 @@ func resourceArmFrontDoorFirewallPolicyRead(d *schema.ResourceData, meta interfa } if err := d.Set("custom_rule", flattenArmFrontDoorFirewallCustomRules(properties.CustomRules)); err != nil { - return fmt.Errorf("Error flattening `custom_rule`: %+v", err) + return fmt.Errorf("flattening `custom_rule`: %+v", err) } - if err := d.Set("managed_rule", flattenArmFrontDoorFirewallManagedRules(properties.ManagedRules)); err != nil { - return fmt.Errorf("Error flattening `managed_rule`: %+v", err) + if err := d.Set("frontend_endpoint_ids", FlattenFrontendEndpointLinkSlice(properties.FrontendEndpointLinks)); err != nil { + return fmt.Errorf("flattening `frontend_endpoint_ids`: %+v", err) } - if err := d.Set("frontend_endpoint_ids", FlattenFrontendEndpointLinkSlice(properties.FrontendEndpointLinks)); err != nil { - return fmt.Errorf("Error flattening `frontend_endpoint_ids`: %+v", err) + if err := d.Set("managed_rule", flattenArmFrontDoorFirewallManagedRules(properties.ManagedRules)); err != nil { + return fmt.Errorf("flattening `managed_rule`: %+v", err) } } @@ -565,12 +564,12 @@ func resourceArmFrontDoorFirewallPolicyDelete(d *schema.ResourceData, meta inter if response.WasNotFound(future.Response()) { return nil } - return fmt.Errorf("Error deleting Front Door Firewall %q (Resource Group %q): %+v", id.Name, id.ResourceGroup, err) + return fmt.Errorf("deleting Front Door Firewall %q (Resource Group %q): %+v", id.Name, id.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 Firewall %q (Resource Group %q): %+v", id.Name, id.ResourceGroup, err) + return fmt.Errorf("waiting for deleting Front Door Firewall %q (Resource Group %q): %+v", id.Name, id.ResourceGroup, err) } } From 0b8a1aad92979c66e0b3e91cbcb2c227d7a38743 Mon Sep 17 00:00:00 2001 From: tombuildsstuff Date: Thu, 13 Aug 2020 12:28:26 +0200 Subject: [PATCH 18/41] r/frontdoor_custom_https_configuration: ensuring CU calls Read and deprecating `resource_group_name` --- azurerm/helpers/azure/resource_group.go | 10 ++++++++++ ...oor_custom_https_configuration_resource.go | 20 +++++++++++++------ 2 files changed, 24 insertions(+), 6 deletions(-) diff --git a/azurerm/helpers/azure/resource_group.go b/azurerm/helpers/azure/resource_group.go index 9e171683fb14..27c2053e81c5 100644 --- a/azurerm/helpers/azure/resource_group.go +++ b/azurerm/helpers/azure/resource_group.go @@ -18,6 +18,16 @@ func SchemaResourceGroupName() *schema.Schema { } } +func SchemaResourceGroupNameDeprecated() *schema.Schema { + return &schema.Schema{ + Type: schema.TypeString, + Optional: true, + ForceNew: true, + ValidateFunc: validateResourceGroupName, + Deprecated: "This field is no longer used and will be removed in the next major verrsion of the Azure Provider", + } +} + func SchemaResourceGroupNameDiffSuppress() *schema.Schema { return &schema.Schema{ Type: schema.TypeString, diff --git a/azurerm/internal/services/frontdoor/frontdoor_custom_https_configuration_resource.go b/azurerm/internal/services/frontdoor/frontdoor_custom_https_configuration_resource.go index 89a10e2d94f3..2d46ee4cc03f 100644 --- a/azurerm/internal/services/frontdoor/frontdoor_custom_https_configuration_resource.go +++ b/azurerm/internal/services/frontdoor/frontdoor_custom_https_configuration_resource.go @@ -53,7 +53,8 @@ func resourceArmFrontDoorCustomHttpsConfiguration() *schema.Resource { Required: true, }, - "resource_group_name": azure.SchemaResourceGroupName(), + // TODO: finish deprecating and remove this since it's unused + "resource_group_name": azure.SchemaResourceGroupNameDeprecated(), "custom_https_configuration": { Type: schema.TypeList, @@ -66,8 +67,15 @@ func resourceArmFrontDoorCustomHttpsConfiguration() *schema.Resource { }, CustomizeDiff: func(d *schema.ResourceDiff, v interface{}) error { - if err := validate.FrontdoorCustomHttpsSettings(d); err != nil { - return fmt.Errorf("creating Front Door Custom Https Configuration for endpoint %q (Resource Group %q): %+v", d.Get("frontend_endpoint_id").(string), d.Get("resource_group_name").(string), err) + if v, ok := d.GetOk("frontend_endpoint_id"); ok && v.(string) != "" { + id, err := parse.FrontendEndpointID(v.(string)) + if err != nil { + return err + } + + if err := validate.FrontdoorCustomHttpsSettings(d); err != nil { + return fmt.Errorf("validating Front Door Custom Https Configuration for Endpoint %q (Front Door %q / Resource Group %q): %+v", id.Name, id.FrontDoorName, id.ResourceGroup, err) + } } return nil @@ -90,11 +98,11 @@ func resourceArmFrontDoorCustomHttpsConfigurationCreateUpdate(d *schema.Resource resp, err := client.Get(ctx, id.ResourceGroup, id.FrontDoorName, id.Name) if err != nil { - return fmt.Errorf("reading Front Door Endpoint %q (Resource Group %q): %+v", id.Name, id.FrontDoorName, id.ResourceGroup, err) + return fmt.Errorf("reading Endpoint %q (Front Door %q / Resource Group %q): %+v", id.Name, id.FrontDoorName, id.ResourceGroup, err) } if resp.FrontendEndpointProperties == nil { - return fmt.Errorf("reading Front Door Endpoint %q (Resource Group %q): `properties` was nil", id.Name, id.FrontDoorName, id.ResourceGroup) + return fmt.Errorf("reading Endpoint %q (Front Door %q / Resource Group %q): `properties` was nil", id.Name, id.FrontDoorName, id.ResourceGroup) } props := *resp.FrontendEndpointProperties @@ -114,7 +122,7 @@ func resourceArmFrontDoorCustomHttpsConfigurationCreateUpdate(d *schema.Resource d.SetId(id.ID(subscriptionId)) } - return nil + return resourceArmFrontDoorCustomHttpsConfigurationRead(d, meta) } func resourceArmFrontDoorCustomHttpsConfigurationRead(d *schema.ResourceData, meta interface{}) error { From 56162c3adb0f6666d35204a75dce5672ce3f8f9b Mon Sep 17 00:00:00 2001 From: tombuildsstuff Date: Thu, 13 Aug 2020 12:37:09 +0200 Subject: [PATCH 19/41] r/frontdoor_custom_https_configuration: fixing the docs --- ...r_custom_https_configuration.html.markdown | 23 ++++++++----------- 1 file changed, 9 insertions(+), 14 deletions(-) diff --git a/website/docs/r/frontdoor_custom_https_configuration.html.markdown b/website/docs/r/frontdoor_custom_https_configuration.html.markdown index 9689644289a0..caf3e03dfaff 100644 --- a/website/docs/r/frontdoor_custom_https_configuration.html.markdown +++ b/website/docs/r/frontdoor_custom_https_configuration.html.markdown @@ -10,7 +10,7 @@ description: |- Manages the Custom Https Configuration for an Azure Front Door Frontend Endpoint.. -~> **NOTE:** Custom https configurations for a Front Door Frontened Endpoint can be defined both within [the `azurerm_frontdoor` resource](frontdoor.html) via the `custom_https_configuration` block and by using a separate resource, as described in the following sections. +~> **NOTE:** Custom https configurations for a Front Door Frontend Endpoint can be defined both within [the `azurerm_frontdoor` resource](frontdoor.html) via the `custom_https_configuration` block and by using a separate resource, as described in the following sections. -> **NOTE:** Defining custom https configurations using a separate `azurerm_frontdoor_custom_https_configuration` resource allows for parallel creation/update. @@ -76,13 +76,11 @@ resource "azurerm_frontdoor" "example" { resource "azurerm_frontdoor_custom_https_configuration" "example_custom_https_0" { frontend_endpoint_id = azurerm_frontdoor.example.frontend_endpoint[0].id - resource_group_name = azurerm_resource_group.example.name custom_https_provisioning_enabled = false } resource "azurerm_frontdoor_custom_https_configuration" "example_custom_https_1" { frontend_endpoint_id = azurerm_frontdoor.example.frontend_endpoint[1].id - resource_group_name = azurerm_resource_group.example.name custom_https_provisioning_enabled = true custom_https_configuration { @@ -98,9 +96,10 @@ resource "azurerm_frontdoor_custom_https_configuration" "example_custom_https_1" The `custom_https_configuration` block is also valid inside an `azurerm_frontdoor_custom_https_configuration`, which supports the following arguments: -* `frontend_endpoint_id` - (Required) Id of the Front Door Frontend endpoint this configuration refers to. -* `resource_group_name` - (Required) Specifies the name of the Resource Group in which the Front Door exists +* `frontend_endpoint_id` - (Required) The ID of the FrontDoor Frontend Endpoint which this configuration refers to. + * `custom_https_provisioning_enabled` - (Required) Should the HTTPS protocol be enabled for this custom domain associated with the Front Door? + * `custom_https_configuration` - (Optional) A `custom_https_configuration` block as defined above. --- @@ -119,21 +118,17 @@ The following attributes are only valid if `certificate_source` is set to `Azure ~> **Note:** In order to enable the use of your own custom `HTTPS certificate` you must grant `Azure Front Door Service` access to your key vault. For instuctions on how to configure your `Key Vault` correctly please refer to the [product documentation](https://docs.microsoft.com/en-us/azure/frontdoor/front-door-custom-domain-https#option-2-use-your-own-certificate). ---- - ## Attributes Reference -`azurerm_frontdoor_custom_https_configuration` exports the following attributes: - -* `id` - The Resource ID of the Azure Front Door Custom https configuration. +* `id` - The ID of the Azure Front Door Custom Https Configuration. +* `custom_https_configuration` - A `custom_https_configuration` block as defined below. -`custom_https_configuration` exports the following: +The `custom_https_configuration` block exports the following: * `minimum_tls_version` - Minimum client TLS version supported. - ## Timeouts The `timeouts` block allows you to specify [timeouts](https://www.terraform.io/docs/configuration/resources.html#timeouts) for certain actions: @@ -145,8 +140,8 @@ The `timeouts` block allows you to specify [timeouts](https://www.terraform.io/d ## Import -Front Door Custom Https Configurations can be imported using the `Frontend endpoint name`, e.g. +Front Door Custom Https Configurations can be imported using the `resource id` of the Frontend Endpoint, e.g. ```shell -terraform import azurerm_frontdoor_custom_https_configuration.example_custom_https_1 /subscriptions/00000000-0000-0000-0000-000000000000/resourcegroups/mygroup1/providers/Microsoft.Network/frontdoors/frontdoor1/frontendendpoints/exampleFrontendEndpoint2/customHttpsConfiguration/exampleFrontendEndpoint2 +terraform import azurerm_frontdoor_custom_https_configuration.example_custom_https_1 /subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/mygroup1/providers/Microsoft.Network/frontdoors/frontdoor1/frontendEndpoints/endpoint1 ``` From 345952ad9d7d397fc8c3d4b3be9add82a64ef1da Mon Sep 17 00:00:00 2001 From: tombuildsstuff Date: Thu, 13 Aug 2020 14:09:10 +0200 Subject: [PATCH 20/41] r/frontdoor_custom_https_configuration: adding a state migration to patch the ID --- ...oor_custom_https_configuration_resource.go | 19 ++- .../migration/custom_https_configuration.go | 112 ++++++++++++++++++ .../custom_https_configuration_test.go | 60 ++++++++++ 3 files changed, 185 insertions(+), 6 deletions(-) create mode 100644 azurerm/internal/services/frontdoor/migration/custom_https_configuration.go create mode 100644 azurerm/internal/services/frontdoor/migration/custom_https_configuration_test.go diff --git a/azurerm/internal/services/frontdoor/frontdoor_custom_https_configuration_resource.go b/azurerm/internal/services/frontdoor/frontdoor_custom_https_configuration_resource.go index 2d46ee4cc03f..e56caf3edcb2 100644 --- a/azurerm/internal/services/frontdoor/frontdoor_custom_https_configuration_resource.go +++ b/azurerm/internal/services/frontdoor/frontdoor_custom_https_configuration_resource.go @@ -11,6 +11,7 @@ import ( "github.com/terraform-providers/terraform-provider-azurerm/azurerm/helpers/azure" "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/clients" "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/locks" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/services/frontdoor/migration" "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/services/frontdoor/parse" "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/services/frontdoor/validate" azSchema "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/tf/schema" @@ -18,9 +19,6 @@ import ( "github.com/terraform-providers/terraform-provider-azurerm/azurerm/utils" ) -// TODO: switch to using the Frontend Endpoint ID here with a state migration -// this was: `resourceId = fmt.Sprintf("%s/customHttpsConfiguration/%s", *id, frontendEndpointName)` - func resourceArmFrontDoorCustomHttpsConfiguration() *schema.Resource { return &schema.Resource{ Create: resourceArmFrontDoorCustomHttpsConfigurationCreateUpdate, @@ -53,9 +51,6 @@ func resourceArmFrontDoorCustomHttpsConfiguration() *schema.Resource { Required: true, }, - // TODO: finish deprecating and remove this since it's unused - "resource_group_name": azure.SchemaResourceGroupNameDeprecated(), - "custom_https_configuration": { Type: schema.TypeList, Optional: true, @@ -64,6 +59,9 @@ func resourceArmFrontDoorCustomHttpsConfiguration() *schema.Resource { Schema: schemaCustomHttpsConfiguration(), }, }, + + // TODO: remove in 3.0 + "resource_group_name": azure.SchemaResourceGroupNameDeprecated(), }, CustomizeDiff: func(d *schema.ResourceDiff, v interface{}) error { @@ -80,6 +78,15 @@ func resourceArmFrontDoorCustomHttpsConfiguration() *schema.Resource { return nil }, + + SchemaVersion: 1, + StateUpgraders: []schema.StateUpgrader{ + { + Type: migration.CustomHttpsConfigurationV0Schema().CoreConfigSchema().ImpliedType(), + Upgrade: migration.CustomHttpsConfigurationV0ToV1, + Version: 0, + }, + }, } } diff --git a/azurerm/internal/services/frontdoor/migration/custom_https_configuration.go b/azurerm/internal/services/frontdoor/migration/custom_https_configuration.go new file mode 100644 index 000000000000..615d45e6710b --- /dev/null +++ b/azurerm/internal/services/frontdoor/migration/custom_https_configuration.go @@ -0,0 +1,112 @@ +package migration + +import ( + "fmt" + "log" + "strings" + + "github.com/hashicorp/terraform-plugin-sdk/helper/schema" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/helpers/azure" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/services/frontdoor/parse" +) + +func CustomHttpsConfigurationV0Schema() *schema.Resource { + return &schema.Resource{ + Schema: map[string]*schema.Schema{ + "frontend_endpoint_id": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + }, + + "custom_https_provisioning_enabled": { + Type: schema.TypeBool, + Required: true, + }, + + "custom_https_configuration": { + Type: schema.TypeList, + Optional: true, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "certificate_source": { + Type: schema.TypeString, + Optional: true, + }, + "minimum_tls_version": { + Type: schema.TypeString, + Computed: true, + }, + "provisioning_state": { + Type: schema.TypeString, + Computed: true, + }, + "provisioning_substate": { + Type: schema.TypeString, + Computed: true, + }, + "azure_key_vault_certificate_secret_name": { + Type: schema.TypeString, + Optional: true, + }, + "azure_key_vault_certificate_secret_version": { + Type: schema.TypeString, + Optional: true, + }, + "azure_key_vault_certificate_vault_id": { + Type: schema.TypeString, + Optional: true, + }, + }, + }, + }, + + "resource_group_name": { + Type: schema.TypeString, + Required: true, + }, + }, + } +} + +func CustomHttpsConfigurationV0ToV1(rawState map[string]interface{}, _ interface{}) (map[string]interface{}, error) { + // this was: fmt.Sprintf("%s/customHttpsConfiguration/%s", frontEndEndpointId, frontendEndpointName + oldId := rawState["id"].(string) + oldParsedId, err := azure.ParseAzureResourceID(oldId) + if err != nil { + return rawState, err + } + + resourceGroup := oldParsedId.ResourceGroup + frontdoorName := "" + frontendEndpointName := "" + for key, value := range oldParsedId.Path { + if strings.EqualFold(key, "frontdoors") { + frontdoorName = value + continue + } + + if strings.EqualFold(key, "frontendEndpoints") { + frontendEndpointName = value + continue + } + } + + if frontdoorName == "" { + return rawState, fmt.Errorf("couldn't find the `frontdoors` segment in the old resource id %q", oldId) + } + + if frontendEndpointName == "" { + return rawState, fmt.Errorf("couldn't find the `frontendEndpoints` segment in the old resource id %q", oldId) + } + + newId := parse.NewFrontendEndpointID(parse.NewFrontDoorID(resourceGroup, frontdoorName), frontendEndpointName) + newIdStr := newId.ID(oldParsedId.SubscriptionID) + + log.Printf("[DEBUG] Updating ID from %q to %q", oldId, newIdStr) + + rawState["id"] = newIdStr + + return rawState, nil +} diff --git a/azurerm/internal/services/frontdoor/migration/custom_https_configuration_test.go b/azurerm/internal/services/frontdoor/migration/custom_https_configuration_test.go new file mode 100644 index 000000000000..b3ec11363300 --- /dev/null +++ b/azurerm/internal/services/frontdoor/migration/custom_https_configuration_test.go @@ -0,0 +1,60 @@ +package migration + +import ( + "testing" + + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/utils" +) + +func TestCustomHttpsConfigurationV0ToV1(t *testing.T) { + testData := []struct { + name string + input map[string]interface{} + expected *string + }{ + { + name: "missing id", + input: map[string]interface{}{ + "id": "", + }, + expected: nil, + }, + { + name: "old id", + input: map[string]interface{}{ + "id": "/subscriptions/12345678-1234-5678-1234-123456789012/resourcegroups/mygroup1/providers/Microsoft.Network/frontdoors/frontdoor1/frontendendpoints/exampleFrontendEndpoint2/customHttpsConfiguration/exampleFrontendEndpoint2", + }, + expected: utils.String("/subscriptions/12345678-1234-5678-1234-123456789012/resourceGroups/mygroup1/providers/Microsoft.Network/frontdoors/frontdoor1/frontendEndpoints/exampleFrontendEndpoint2"), + }, + { + name: "old id - mixed case", + input: map[string]interface{}{ + "id": "/subscriptions/12345678-1234-5678-1234-123456789012/resourcegroups/mygroup1/providers/Microsoft.Network/Frontdoors/frontdoor1/frontendEndpoints/exampleFrontendEndpoint2/customHttpsConfiguration/exampleFrontendEndpoint2", + }, + expected: utils.String("/subscriptions/12345678-1234-5678-1234-123456789012/resourceGroups/mygroup1/providers/Microsoft.Network/frontdoors/frontdoor1/frontendEndpoints/exampleFrontendEndpoint2"), + }, + { + name: "new id", + input: map[string]interface{}{ + "id": "/subscriptions/12345678-1234-5678-1234-123456789012/resourceGroups/mygroup1/providers/Microsoft.Network/frontdoors/frontdoor1/frontendEndpoints/exampleFrontendEndpoint2", + }, + expected: utils.String("/subscriptions/12345678-1234-5678-1234-123456789012/resourceGroups/mygroup1/providers/Microsoft.Network/frontdoors/frontdoor1/frontendEndpoints/exampleFrontendEndpoint2"), + }, + } + for _, test := range testData { + t.Logf("Testing %q..", test.name) + result, err := CustomHttpsConfigurationV0ToV1(test.input, nil) + if err != nil && test.expected == nil { + continue + } else if err == nil && test.expected == nil { + t.Fatalf("Expected an error but didn't get one") + } else if err != nil && test.expected != nil { + t.Fatalf("Expected no error but got: %+v", err) + } + + actualId := result["id"].(string) + if *test.expected != actualId { + t.Fatalf("expected %q but got %q!", *test.expected, actualId) + } + } +} From 8d23d6f0fdc2453a0b34cdebe0f97d6757c8bfa2 Mon Sep 17 00:00:00 2001 From: tombuildsstuff Date: Thu, 13 Aug 2020 14:09:32 +0200 Subject: [PATCH 21/41] r/frontdoor: fixing a bug in the id formatters --- azurerm/internal/services/frontdoor/parse/backend_pool.go | 2 +- azurerm/internal/services/frontdoor/parse/frontend_endpoint.go | 2 +- azurerm/internal/services/frontdoor/parse/health_probe.go | 2 +- azurerm/internal/services/frontdoor/parse/load_balancing.go | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/azurerm/internal/services/frontdoor/parse/backend_pool.go b/azurerm/internal/services/frontdoor/parse/backend_pool.go index b59d6e24e054..ae0ced2742a1 100644 --- a/azurerm/internal/services/frontdoor/parse/backend_pool.go +++ b/azurerm/internal/services/frontdoor/parse/backend_pool.go @@ -17,7 +17,7 @@ func NewBackendPoolID(id FrontDoorId, name string) BackendPoolId { } func (id BackendPoolId) ID(subscriptionId string) string { - base := NewFrontDoorID(id.ResourceGroup, id.Name).ID(subscriptionId) + base := NewFrontDoorID(id.ResourceGroup, id.FrontDoorName).ID(subscriptionId) return fmt.Sprintf("%s/backendPools/%s", base, id.Name) } diff --git a/azurerm/internal/services/frontdoor/parse/frontend_endpoint.go b/azurerm/internal/services/frontdoor/parse/frontend_endpoint.go index 275467c07b32..5b741c67eb64 100644 --- a/azurerm/internal/services/frontdoor/parse/frontend_endpoint.go +++ b/azurerm/internal/services/frontdoor/parse/frontend_endpoint.go @@ -17,7 +17,7 @@ func NewFrontendEndpointID(id FrontDoorId, name string) FrontendEndpointId { } func (id FrontendEndpointId) ID(subscriptionId string) string { - base := NewFrontDoorID(id.ResourceGroup, id.Name).ID(subscriptionId) + base := NewFrontDoorID(id.ResourceGroup, id.FrontDoorName).ID(subscriptionId) return fmt.Sprintf("%s/frontendEndpoints/%s", base, id.Name) } diff --git a/azurerm/internal/services/frontdoor/parse/health_probe.go b/azurerm/internal/services/frontdoor/parse/health_probe.go index 067fbe5775ce..f924dffffd4b 100644 --- a/azurerm/internal/services/frontdoor/parse/health_probe.go +++ b/azurerm/internal/services/frontdoor/parse/health_probe.go @@ -17,7 +17,7 @@ func NewHealthProbeID(id FrontDoorId, name string) HealthProbeId { } func (id HealthProbeId) ID(subscriptionId string) string { - base := NewFrontDoorID(id.ResourceGroup, id.Name).ID(subscriptionId) + base := NewFrontDoorID(id.ResourceGroup, id.FrontDoorName).ID(subscriptionId) return fmt.Sprintf("%s/healthProbeSettings/%s", base, id.Name) } diff --git a/azurerm/internal/services/frontdoor/parse/load_balancing.go b/azurerm/internal/services/frontdoor/parse/load_balancing.go index 6509101808c2..724c36f34a90 100644 --- a/azurerm/internal/services/frontdoor/parse/load_balancing.go +++ b/azurerm/internal/services/frontdoor/parse/load_balancing.go @@ -17,7 +17,7 @@ func NewLoadBalancingID(id FrontDoorId, name string) LoadBalancingId { } func (id LoadBalancingId) ID(subscriptionId string) string { - base := NewFrontDoorID(id.ResourceGroup, id.Name).ID(subscriptionId) + base := NewFrontDoorID(id.ResourceGroup, id.FrontDoorName).ID(subscriptionId) return fmt.Sprintf("%s/loadBalancingSettings/%s", base, id.Name) } From 62262eb0a49ef985118f23f7f07f14f1b4db6a27 Mon Sep 17 00:00:00 2001 From: tombuildsstuff Date: Thu, 13 Aug 2020 14:16:59 +0200 Subject: [PATCH 22/41] r/frontdoor: exposing the correct resource id during a requires import error --- azurerm/internal/services/frontdoor/frontdoor_resource.go | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/azurerm/internal/services/frontdoor/frontdoor_resource.go b/azurerm/internal/services/frontdoor/frontdoor_resource.go index 3d167e56ba41..f15c5dc83522 100644 --- a/azurerm/internal/services/frontdoor/frontdoor_resource.go +++ b/azurerm/internal/services/frontdoor/frontdoor_resource.go @@ -474,6 +474,7 @@ func resourceArmFrontDoorCreateUpdate(d *schema.ResourceData, meta interface{}) name := d.Get("name").(string) resourceGroup := d.Get("resource_group_name").(string) subscriptionId := meta.(*clients.Client).Account.SubscriptionId + frontDoorId := parse.NewFrontDoorID(resourceGroup, name) if features.ShouldResourcesBeImported() && d.IsNewResource() { resp, err := client.Get(ctx, resourceGroup, name) @@ -483,7 +484,7 @@ func resourceArmFrontDoorCreateUpdate(d *schema.ResourceData, meta interface{}) } } if !utils.ResponseWasNotFound(resp.Response) { - return tf.ImportAsExistsError("azurerm_frontdoor", *resp.ID) + return tf.ImportAsExistsError("azurerm_frontdoor", frontDoorId.ID(subscriptionId)) } } @@ -510,8 +511,6 @@ func resourceArmFrontDoorCreateUpdate(d *schema.ResourceData, meta interface{}) } } - frontDoorId := parse.NewFrontDoorID(resourceGroup, name) - friendlyName := d.Get("friendly_name").(string) routingRules := d.Get("routing_rule").([]interface{}) loadBalancingSettings := d.Get("backend_pool_load_balancing").([]interface{}) From d2d002642b8c1aa06645c22537bcce7e72caac6a Mon Sep 17 00:00:00 2001 From: tombuildsstuff Date: Thu, 13 Aug 2020 14:17:27 +0200 Subject: [PATCH 23/41] resource-group: deprecated shouldn't be forcenew --- azurerm/helpers/azure/resource_group.go | 1 - 1 file changed, 1 deletion(-) diff --git a/azurerm/helpers/azure/resource_group.go b/azurerm/helpers/azure/resource_group.go index 27c2053e81c5..1d0feb59b670 100644 --- a/azurerm/helpers/azure/resource_group.go +++ b/azurerm/helpers/azure/resource_group.go @@ -22,7 +22,6 @@ func SchemaResourceGroupNameDeprecated() *schema.Schema { return &schema.Schema{ Type: schema.TypeString, Optional: true, - ForceNew: true, ValidateFunc: validateResourceGroupName, Deprecated: "This field is no longer used and will be removed in the next major verrsion of the Azure Provider", } From 6bc28d328518b4cc09b0b8c9177378c418a05ceb Mon Sep 17 00:00:00 2001 From: tombuildsstuff Date: Thu, 13 Aug 2020 16:13:53 +0200 Subject: [PATCH 24/41] r/frontdoor_firewall_policy: adding a state migration for the ID --- .../frontdoor_firewall_policy_resource.go | 12 +- .../services/frontdoor/frontdoor_resource.go | 1 + .../web_application_firewall_policy.go | 316 ++++++++++++++++++ .../web_application_firewall_policy_test.go | 60 ++++ 4 files changed, 388 insertions(+), 1 deletion(-) create mode 100644 azurerm/internal/services/frontdoor/migration/web_application_firewall_policy.go create mode 100644 azurerm/internal/services/frontdoor/migration/web_application_firewall_policy_test.go diff --git a/azurerm/internal/services/frontdoor/frontdoor_firewall_policy_resource.go b/azurerm/internal/services/frontdoor/frontdoor_firewall_policy_resource.go index f24e956bea27..160860c37758 100644 --- a/azurerm/internal/services/frontdoor/frontdoor_firewall_policy_resource.go +++ b/azurerm/internal/services/frontdoor/frontdoor_firewall_policy_resource.go @@ -12,6 +12,7 @@ import ( "github.com/terraform-providers/terraform-provider-azurerm/azurerm/helpers/azure" "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/services/frontdoor/migration" "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/services/frontdoor/parse" "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/services/frontdoor/validate" "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/tags" @@ -49,7 +50,7 @@ func resourceArmFrontDoorFirewallPolicy() *schema.Resource { ValidateFunc: validate.FrontDoorWAFName, }, - "location": azure.SchemaLocationForDataSource(), + "location": azure.SchemaLocationOptional(), "resource_group_name": azure.SchemaResourceGroupName(), @@ -420,6 +421,15 @@ func resourceArmFrontDoorFirewallPolicy() *schema.Resource { "tags": tags.Schema(), }, + + SchemaVersion: 1, + StateUpgraders: []schema.StateUpgrader{ + { + Type: migration.WebApplicationFirewallPolicyV0Schema().CoreConfigSchema().ImpliedType(), + Upgrade: migration.WebApplicationFirewallPolicyV0ToV1, + Version: 0, + }, + }, } } diff --git a/azurerm/internal/services/frontdoor/frontdoor_resource.go b/azurerm/internal/services/frontdoor/frontdoor_resource.go index f15c5dc83522..8503dc602e59 100644 --- a/azurerm/internal/services/frontdoor/frontdoor_resource.go +++ b/azurerm/internal/services/frontdoor/frontdoor_resource.go @@ -438,6 +438,7 @@ func resourceArmFrontDoor() *schema.Resource { "web_application_firewall_policy_link_id": { Type: schema.TypeString, Optional: true, + // TODO: validation that this is a resource id }, "custom_https_configuration": { Type: schema.TypeList, diff --git a/azurerm/internal/services/frontdoor/migration/web_application_firewall_policy.go b/azurerm/internal/services/frontdoor/migration/web_application_firewall_policy.go new file mode 100644 index 000000000000..2d0c765e8d27 --- /dev/null +++ b/azurerm/internal/services/frontdoor/migration/web_application_firewall_policy.go @@ -0,0 +1,316 @@ +package migration + +import ( + "fmt" + "log" + "strings" + + "github.com/hashicorp/terraform-plugin-sdk/helper/schema" + "github.com/hashicorp/terraform-plugin-sdk/helper/validation" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/helpers/azure" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/services/frontdoor/parse" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/tags" +) + +func WebApplicationFirewallPolicyV0Schema() *schema.Resource { + return &schema.Resource{ + Schema: map[string]*schema.Schema{ + "name": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + }, + + "location": { + Type: schema.TypeString, + Optional: true, + }, + + "resource_group_name": { + Type: schema.TypeString, + Required: true, + }, + + "enabled": { + Type: schema.TypeBool, + Optional: true, + }, + + "mode": { + Type: schema.TypeString, + Optional: true, + }, + + "redirect_url": { + Type: schema.TypeString, + Optional: true, + }, + + "custom_block_response_status_code": { + Type: schema.TypeInt, + Optional: true, + }, + + "custom_block_response_body": { + Type: schema.TypeString, + Optional: true, + }, + + "custom_rule": { + Type: schema.TypeList, + MaxItems: 100, + Optional: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "name": { + Type: schema.TypeString, + Required: true, + }, + + "enabled": { + Type: schema.TypeBool, + Optional: true, + }, + + "priority": { + Type: schema.TypeInt, + Optional: true, + }, + + "type": { + Type: schema.TypeString, + Required: true, + }, + + "rate_limit_duration_in_minutes": { + Type: schema.TypeInt, + Optional: true, + }, + + "rate_limit_threshold": { + Type: schema.TypeInt, + Optional: true, + }, + + "action": { + Type: schema.TypeString, + Required: true, + }, + + "match_condition": { + Type: schema.TypeList, + Optional: true, + MaxItems: 100, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "match_variable": { + Type: schema.TypeString, + Required: true, + }, + + "match_values": { + Type: schema.TypeList, + Required: true, + }, + + "operator": { + Type: schema.TypeString, + Required: true, + }, + + "selector": { + Type: schema.TypeString, + Optional: true, + ValidateFunc: validation.StringIsNotEmpty, + }, + + "negation_condition": { + Type: schema.TypeBool, + Optional: true, + Default: false, + }, + + "transforms": { + Type: schema.TypeList, + Optional: true, + MaxItems: 5, + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + }, + }, + }, + }, + }, + }, + + "managed_rule": { + Type: schema.TypeList, + MaxItems: 100, + Optional: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "type": { + Type: schema.TypeString, + Required: true, + }, + + "version": { + Type: schema.TypeString, + Required: true, + }, + + "exclusion": { + Type: schema.TypeList, + MaxItems: 100, + Optional: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "match_variable": { + Type: schema.TypeString, + Required: true, + }, + "operator": { + Type: schema.TypeString, + Required: true, + }, + "selector": { + Type: schema.TypeString, + Required: true, + }, + }, + }, + }, + + "override": { + Type: schema.TypeList, + MaxItems: 100, + Optional: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "rule_group_name": { + Type: schema.TypeString, + Required: true, + }, + + "exclusion": { + Type: schema.TypeList, + MaxItems: 100, + Optional: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "match_variable": { + Type: schema.TypeString, + Required: true, + }, + "operator": { + Type: schema.TypeString, + Required: true, + }, + "selector": { + Type: schema.TypeString, + Required: true, + }, + }, + }, + }, + + "rule": { + Type: schema.TypeList, + MaxItems: 1000, + Optional: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "rule_id": { + Type: schema.TypeString, + Required: true, + }, + + "enabled": { + Type: schema.TypeBool, + Optional: true, + }, + + "exclusion": { + Type: schema.TypeList, + MaxItems: 100, + Optional: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "match_variable": { + Type: schema.TypeString, + Required: true, + }, + "operator": { + Type: schema.TypeString, + Required: true, + }, + "selector": { + Type: schema.TypeString, + Required: true, + }, + }, + }, + }, + + "action": { + Type: schema.TypeString, + Required: true, + }, + }, + }, + }, + }, + }, + }, + }, + }, + }, + + "frontend_endpoint_ids": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + + "tags": tags.Schema(), + }, + } +} + +func WebApplicationFirewallPolicyV0ToV1(rawState map[string]interface{}, _ interface{}) (map[string]interface{}, error) { + // old + // /subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.Network/frontdoorwebapplicationfirewallpolicies/{policyName} + // new: + // /subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.Network/frontDoorWebApplicationFirewallPolicies/{policyName} + oldId := rawState["id"].(string) + oldParsedId, err := azure.ParseAzureResourceID(oldId) + if err != nil { + return rawState, err + } + + resourceGroup := oldParsedId.ResourceGroup + policyName := "" + for key, value := range oldParsedId.Path { + if strings.EqualFold(key, "frontDoorWebApplicationFirewallPolicies") { + policyName = value + break + } + } + + if policyName == "" { + return rawState, fmt.Errorf("couldn't find the `frontDoorWebApplicationFirewallPolicies` segment in the old resource id %q", oldId) + } + + newId := parse.NewWebApplicationFirewallPolicyID(resourceGroup, policyName) + newIdStr := newId.ID(oldParsedId.SubscriptionID) + + log.Printf("[DEBUG] Updating ID from %q to %q", oldId, newIdStr) + + rawState["id"] = newIdStr + + return rawState, nil +} diff --git a/azurerm/internal/services/frontdoor/migration/web_application_firewall_policy_test.go b/azurerm/internal/services/frontdoor/migration/web_application_firewall_policy_test.go new file mode 100644 index 000000000000..a71fa7fd4853 --- /dev/null +++ b/azurerm/internal/services/frontdoor/migration/web_application_firewall_policy_test.go @@ -0,0 +1,60 @@ +package migration + +import ( + "testing" + + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/utils" +) + +func TestWebApplicationFirewallPolicyV0ToV1(t *testing.T) { + testData := []struct { + name string + input map[string]interface{} + expected *string + }{ + { + name: "missing id", + input: map[string]interface{}{ + "id": "", + }, + expected: nil, + }, + { + name: "old id", + input: map[string]interface{}{ + "id": "/subscriptions/12345678-1234-5678-1234-123456789012/resourcegroups/group1/providers/Microsoft.Network/frontdoorwebapplicationfirewallpolicies/policy1", + }, + expected: utils.String("/subscriptions/12345678-1234-5678-1234-123456789012/resourceGroups/group1/providers/Microsoft.Network/frontDoorWebApplicationFirewallPolicies/policy1"), + }, + { + name: "old id - mixed case", + input: map[string]interface{}{ + "id": "/subscriptions/12345678-1234-5678-1234-123456789012/resourcegroups/group1/providers/Microsoft.Network/FrontDoorWebApplicationFirewallPolicies/policy1", + }, + expected: utils.String("/subscriptions/12345678-1234-5678-1234-123456789012/resourceGroups/group1/providers/Microsoft.Network/frontDoorWebApplicationFirewallPolicies/policy1"), + }, + { + name: "new id", + input: map[string]interface{}{ + "id": "/subscriptions/12345678-1234-5678-1234-123456789012/resourceGroups/group1/providers/Microsoft.Network/frontDoorWebApplicationFirewallPolicies/policy1", + }, + expected: utils.String("/subscriptions/12345678-1234-5678-1234-123456789012/resourceGroups/group1/providers/Microsoft.Network/frontDoorWebApplicationFirewallPolicies/policy1"), + }, + } + for _, test := range testData { + t.Logf("Testing %q..", test.name) + result, err := WebApplicationFirewallPolicyV0ToV1(test.input, nil) + if err != nil && test.expected == nil { + continue + } else if err == nil && test.expected == nil { + t.Fatalf("Expected an error but didn't get one") + } else if err != nil && test.expected != nil { + t.Fatalf("Expected no error but got: %+v", err) + } + + actualId := result["id"].(string) + if *test.expected != actualId { + t.Fatalf("expected %q but got %q!", *test.expected, actualId) + } + } +} From a14dfffe0ced645772c58f7e723ff09ee3a17a98 Mon Sep 17 00:00:00 2001 From: tombuildsstuff Date: Thu, 13 Aug 2020 16:42:26 +0200 Subject: [PATCH 25/41] r/frontdoor: adding a state migration to fix the I --- .../services/frontdoor/frontdoor_resource.go | 21 +- .../services/frontdoor/migration/frontdoor.go | 422 ++++++++++++++++++ .../frontdoor/migration/frontdoor_test.go | 67 +++ .../services/frontdoor/parse/frontdoor.go | 2 +- 4 files changed, 508 insertions(+), 4 deletions(-) create mode 100644 azurerm/internal/services/frontdoor/migration/frontdoor.go create mode 100644 azurerm/internal/services/frontdoor/migration/frontdoor_test.go diff --git a/azurerm/internal/services/frontdoor/frontdoor_resource.go b/azurerm/internal/services/frontdoor/frontdoor_resource.go index 8503dc602e59..3cc544e6b486 100644 --- a/azurerm/internal/services/frontdoor/frontdoor_resource.go +++ b/azurerm/internal/services/frontdoor/frontdoor_resource.go @@ -15,6 +15,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/migration" "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/services/frontdoor/parse" "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/services/frontdoor/validate" "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/tags" @@ -23,8 +24,6 @@ import ( "github.com/terraform-providers/terraform-provider-azurerm/azurerm/utils" ) -// TODO: a state migration to patch the ID's - func resourceArmFrontDoor() *schema.Resource { return &schema.Resource{ Create: resourceArmFrontDoorCreateUpdate, @@ -37,7 +36,23 @@ func resourceArmFrontDoor() *schema.Resource { return err }), - SchemaVersion: 1, + SchemaVersion: 2, + StateUpgraders: []schema.StateUpgrader{ + { + // this resource was set to "schema version 1" unintentionally.. so we're adding + // a "fake" upgrade here to account for it + Type: migration.FrontDoorV0V1Schema().CoreConfigSchema().ImpliedType(), + Upgrade: func(rawState map[string]interface{}, _ interface{}) (map[string]interface{}, error) { + return rawState, nil + }, + Version: 0, + }, + { + Type: migration.FrontDoorV0V1Schema().CoreConfigSchema().ImpliedType(), + Upgrade: migration.FrontDoorV1ToV2, + Version: 1, + }, + }, Timeouts: &schema.ResourceTimeout{ Create: schema.DefaultTimeout(6 * time.Hour), diff --git a/azurerm/internal/services/frontdoor/migration/frontdoor.go b/azurerm/internal/services/frontdoor/migration/frontdoor.go new file mode 100644 index 000000000000..03c3da93f5cc --- /dev/null +++ b/azurerm/internal/services/frontdoor/migration/frontdoor.go @@ -0,0 +1,422 @@ +package migration + +import ( + "fmt" + "log" + "strings" + + "github.com/hashicorp/terraform-plugin-sdk/helper/schema" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/helpers/azure" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/services/frontdoor/parse" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/tags" +) + +func FrontDoorV0V1Schema() *schema.Resource { + return &schema.Resource{ + Schema: map[string]*schema.Schema{ + "name": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + }, + + "cname": { + Type: schema.TypeString, + Computed: true, + }, + + "header_frontdoor_id": { + Type: schema.TypeString, + Computed: true, + }, + + "friendly_name": { + Type: schema.TypeString, + Optional: true, + }, + + "load_balancer_enabled": { + Type: schema.TypeBool, + Optional: true, + }, + + "enforce_backend_pools_certificate_name_check": { + Type: schema.TypeBool, + Required: true, + }, + + "backend_pools_send_receive_timeout_seconds": { + Type: schema.TypeInt, + Optional: true, + }, + + "location": { + Type: schema.TypeString, + Optional: true, + Computed: true, + }, + + "resource_group_name": { + Type: schema.TypeString, + Required: true, + }, + + "routing_rule": { + Type: schema.TypeList, + MaxItems: 100, + Required: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "id": { + Type: schema.TypeString, + Computed: true, + }, + "name": { + Type: schema.TypeString, + Required: true, + }, + "enabled": { + Type: schema.TypeBool, + Optional: true, + }, + "accepted_protocols": { + Type: schema.TypeList, + Required: true, + MaxItems: 2, + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + "patterns_to_match": { + Type: schema.TypeList, + Required: true, + MaxItems: 25, + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + "frontend_endpoints": { + Type: schema.TypeList, + Required: true, + MaxItems: 100, + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + "redirect_configuration": { + Type: schema.TypeList, + Optional: true, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "custom_fragment": { + Type: schema.TypeString, + Optional: true, + }, + "custom_host": { + Type: schema.TypeString, + Optional: true, + }, + "custom_path": { + Type: schema.TypeString, + Optional: true, + }, + "custom_query_string": { + Type: schema.TypeString, + Optional: true, + }, + "redirect_protocol": { + Type: schema.TypeString, + Required: true, + }, + "redirect_type": { + Type: schema.TypeString, + Required: true, + }, + }, + }, + }, + "forwarding_configuration": { + Type: schema.TypeList, + Optional: true, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "backend_pool_name": { + Type: schema.TypeString, + Required: true, + }, + "cache_enabled": { + Type: schema.TypeBool, + Optional: true, + }, + "cache_use_dynamic_compression": { + Type: schema.TypeBool, + Optional: true, + }, + "cache_query_parameter_strip_directive": { + Type: schema.TypeString, + Optional: true, + }, + "custom_forwarding_path": { + Type: schema.TypeString, + Optional: true, + }, + "forwarding_protocol": { + Type: schema.TypeString, + Optional: true, + }, + }, + }, + }, + }, + }, + }, + + "backend_pool_load_balancing": { + Type: schema.TypeList, + MaxItems: 5000, + Required: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "id": { + Type: schema.TypeString, + Computed: true, + }, + "name": { + Type: schema.TypeString, + Required: true, + }, + "sample_size": { + Type: schema.TypeInt, + Optional: true, + }, + "successful_samples_required": { + Type: schema.TypeInt, + Optional: true, + }, + "additional_latency_milliseconds": { + Type: schema.TypeInt, + Optional: true, + }, + }, + }, + }, + + "backend_pool_health_probe": { + Type: schema.TypeList, + MaxItems: 5000, + Required: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "id": { + Type: schema.TypeString, + Computed: true, + }, + "name": { + Type: schema.TypeString, + Required: true, + }, + "enabled": { + Type: schema.TypeBool, + Optional: true, + }, + "path": { + Type: schema.TypeString, + Optional: true, + }, + "protocol": { + Type: schema.TypeString, + Optional: true, + }, + "probe_method": { + Type: schema.TypeString, + Optional: true, + }, + "interval_in_seconds": { + Type: schema.TypeInt, + Optional: true, + }, + }, + }, + }, + + "backend_pool": { + Type: schema.TypeList, + MaxItems: 50, + Required: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "backend": { + Type: schema.TypeList, + MaxItems: 100, + Required: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "enabled": { + Type: schema.TypeBool, + Optional: true, + Default: true, + }, + "address": { + Type: schema.TypeString, + Required: true, + }, + "http_port": { + Type: schema.TypeInt, + Required: true, + }, + "https_port": { + Type: schema.TypeInt, + Required: true, + }, + "weight": { + Type: schema.TypeInt, + Optional: true, + }, + "priority": { + Type: schema.TypeInt, + Optional: true, + }, + "host_header": { + Type: schema.TypeString, + Required: true, + }, + }, + }, + }, + "id": { + Type: schema.TypeString, + Computed: true, + }, + "name": { + Type: schema.TypeString, + Required: true, + }, + "health_probe_name": { + Type: schema.TypeString, + Required: true, + }, + "load_balancing_name": { + Type: schema.TypeString, + Required: true, + }, + }, + }, + }, + + "frontend_endpoint": { + Type: schema.TypeList, + MaxItems: 100, + Required: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "id": { + Type: schema.TypeString, + Computed: true, + }, + "name": { + Type: schema.TypeString, + Required: true, + }, + "host_name": { + Type: schema.TypeString, + Required: true, + }, + "session_affinity_enabled": { + Type: schema.TypeBool, + Optional: true, + }, + "session_affinity_ttl_seconds": { + Type: schema.TypeInt, + Optional: true, + }, + "custom_https_provisioning_enabled": { + Type: schema.TypeBool, + Optional: true, + Computed: true, + }, + "web_application_firewall_policy_link_id": { + Type: schema.TypeString, + Optional: true, + }, + "custom_https_configuration": { + Type: schema.TypeList, + Optional: true, + Computed: true, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "certificate_source": { + Type: schema.TypeString, + Optional: true, + }, + "minimum_tls_version": { + Type: schema.TypeString, + Computed: true, + }, + "provisioning_state": { + Type: schema.TypeString, + Computed: true, + }, + "provisioning_substate": { + Type: schema.TypeString, + Computed: true, + }, + "azure_key_vault_certificate_secret_name": { + Type: schema.TypeString, + Optional: true, + }, + "azure_key_vault_certificate_secret_version": { + Type: schema.TypeString, + Optional: true, + }, + "azure_key_vault_certificate_vault_id": { + Type: schema.TypeString, + Optional: true, + }, + }, + }, + }, + }, + }, + }, + + "tags": tags.Schema(), + }, + } +} + +func FrontDoorV1ToV2(rawState map[string]interface{}, _ interface{}) (map[string]interface{}, error) { + // old + // /subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.Network/frontdoors/{frontDoorName} + // new: + // /subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.Network/frontDoors/{frontDoorName} + oldId := rawState["id"].(string) + oldParsedId, err := azure.ParseAzureResourceID(oldId) + if err != nil { + return rawState, err + } + + resourceGroup := oldParsedId.ResourceGroup + frontDoorName := "" + for key, value := range oldParsedId.Path { + if strings.EqualFold(key, "frontDoors") { + frontDoorName = value + break + } + } + + if frontDoorName == "" { + return rawState, fmt.Errorf("couldn't find the `frontDoors` segment in the old resource id %q", oldId) + } + + newId := parse.NewFrontDoorID(resourceGroup, frontDoorName) + newIdStr := newId.ID(oldParsedId.SubscriptionID) + + log.Printf("[DEBUG] Updating ID from %q to %q", oldId, newIdStr) + + rawState["id"] = newIdStr + + return rawState, nil +} diff --git a/azurerm/internal/services/frontdoor/migration/frontdoor_test.go b/azurerm/internal/services/frontdoor/migration/frontdoor_test.go new file mode 100644 index 000000000000..17a6242a0c16 --- /dev/null +++ b/azurerm/internal/services/frontdoor/migration/frontdoor_test.go @@ -0,0 +1,67 @@ +package migration + +import ( + "testing" + + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/utils" +) + +func TestFrontDoorV1ToV2(t *testing.T) { + testData := []struct { + name string + input map[string]interface{} + expected *string + }{ + { + name: "missing id", + input: map[string]interface{}{ + "id": "", + }, + expected: nil, + }, + { + name: "old id", + input: map[string]interface{}{ + "id": "/subscriptions/12345678-1234-5678-1234-123456789012/resourcegroups/group1/providers/Microsoft.Network/frontdoors/frontdoor1", + }, + expected: utils.String("/subscriptions/12345678-1234-5678-1234-123456789012/resourceGroups/group1/providers/Microsoft.Network/frontDoors/frontdoor1"), + }, + { + name: "old id - lower case", + input: map[string]interface{}{ + "id": "/subscriptions/12345678-1234-5678-1234-123456789012/resourcegroups/group1/providers/Microsoft.Network/frontdoors/frontdoor1", + }, + expected: utils.String("/subscriptions/12345678-1234-5678-1234-123456789012/resourceGroups/group1/providers/Microsoft.Network/frontDoors/frontdoor1"), + }, + { + name: "old id - mixed case", + input: map[string]interface{}{ + "id": "/subscriptions/12345678-1234-5678-1234-123456789012/resourcegroups/group1/providers/Microsoft.Network/FrontDoors/frontdoor1", + }, + expected: utils.String("/subscriptions/12345678-1234-5678-1234-123456789012/resourceGroups/group1/providers/Microsoft.Network/frontDoors/frontdoor1"), + }, + { + name: "new id", + input: map[string]interface{}{ + "id": "/subscriptions/12345678-1234-5678-1234-123456789012/resourceGroups/group1/providers/Microsoft.Network/frontDoors/frontdoor1", + }, + expected: utils.String("/subscriptions/12345678-1234-5678-1234-123456789012/resourceGroups/group1/providers/Microsoft.Network/frontDoors/frontdoor1"), + }, + } + for _, test := range testData { + t.Logf("Testing %q..", test.name) + result, err := FrontDoorV1ToV2(test.input, nil) + if err != nil && test.expected == nil { + continue + } else if err == nil && test.expected == nil { + t.Fatalf("Expected an error but didn't get one") + } else if err != nil && test.expected != nil { + t.Fatalf("Expected no error but got: %+v", err) + } + + actualId := result["id"].(string) + if *test.expected != actualId { + t.Fatalf("expected %q but got %q!", *test.expected, actualId) + } + } +} diff --git a/azurerm/internal/services/frontdoor/parse/frontdoor.go b/azurerm/internal/services/frontdoor/parse/frontdoor.go index b4d714624b8a..862030c3bcb3 100644 --- a/azurerm/internal/services/frontdoor/parse/frontdoor.go +++ b/azurerm/internal/services/frontdoor/parse/frontdoor.go @@ -34,7 +34,7 @@ func FrontDoorID(input string) (*FrontDoorId, error) { } func (id FrontDoorId) ID(subscriptionId string) string { - return fmt.Sprintf("/subscriptions/%s/resourceGroups/%s/providers/Microsoft.Network/frontdoors/%s", subscriptionId, id.ResourceGroup, id.Name) + return fmt.Sprintf("/subscriptions/%s/resourceGroups/%s/providers/Microsoft.Network/frontDoors/%s", subscriptionId, id.ResourceGroup, id.Name) } func parseFrontDoorChildResourceId(input string) (*FrontDoorId, *azure.ResourceID, error) { From 0176557b7468932c339866455ef315551ab783bf Mon Sep 17 00:00:00 2001 From: tombuildsstuff Date: Fri, 14 Aug 2020 18:11:25 +0200 Subject: [PATCH 26/41] WIP --- .../custom_https_configuration_test.go | 6 +- .../services/frontdoor/parse/backend_pool.go | 7 +- .../frontdoor/parse/backend_pool_test.go | 83 ++++++++++++++++++- .../services/frontdoor/parse/frontdoor.go | 23 +++-- .../frontdoor/parse/frontdoor_test.go | 74 ++++++++++++++++- 5 files changed, 173 insertions(+), 20 deletions(-) diff --git a/azurerm/internal/services/frontdoor/migration/custom_https_configuration_test.go b/azurerm/internal/services/frontdoor/migration/custom_https_configuration_test.go index b3ec11363300..3869cd283e5f 100644 --- a/azurerm/internal/services/frontdoor/migration/custom_https_configuration_test.go +++ b/azurerm/internal/services/frontdoor/migration/custom_https_configuration_test.go @@ -24,21 +24,21 @@ func TestCustomHttpsConfigurationV0ToV1(t *testing.T) { input: map[string]interface{}{ "id": "/subscriptions/12345678-1234-5678-1234-123456789012/resourcegroups/mygroup1/providers/Microsoft.Network/frontdoors/frontdoor1/frontendendpoints/exampleFrontendEndpoint2/customHttpsConfiguration/exampleFrontendEndpoint2", }, - expected: utils.String("/subscriptions/12345678-1234-5678-1234-123456789012/resourceGroups/mygroup1/providers/Microsoft.Network/frontdoors/frontdoor1/frontendEndpoints/exampleFrontendEndpoint2"), + expected: utils.String("/subscriptions/12345678-1234-5678-1234-123456789012/resourceGroups/mygroup1/providers/Microsoft.Network/frontDoors/frontdoor1/frontendEndpoints/exampleFrontendEndpoint2"), }, { name: "old id - mixed case", input: map[string]interface{}{ "id": "/subscriptions/12345678-1234-5678-1234-123456789012/resourcegroups/mygroup1/providers/Microsoft.Network/Frontdoors/frontdoor1/frontendEndpoints/exampleFrontendEndpoint2/customHttpsConfiguration/exampleFrontendEndpoint2", }, - expected: utils.String("/subscriptions/12345678-1234-5678-1234-123456789012/resourceGroups/mygroup1/providers/Microsoft.Network/frontdoors/frontdoor1/frontendEndpoints/exampleFrontendEndpoint2"), + expected: utils.String("/subscriptions/12345678-1234-5678-1234-123456789012/resourceGroups/mygroup1/providers/Microsoft.Network/frontDoors/frontdoor1/frontendEndpoints/exampleFrontendEndpoint2"), }, { name: "new id", input: map[string]interface{}{ "id": "/subscriptions/12345678-1234-5678-1234-123456789012/resourceGroups/mygroup1/providers/Microsoft.Network/frontdoors/frontdoor1/frontendEndpoints/exampleFrontendEndpoint2", }, - expected: utils.String("/subscriptions/12345678-1234-5678-1234-123456789012/resourceGroups/mygroup1/providers/Microsoft.Network/frontdoors/frontdoor1/frontendEndpoints/exampleFrontendEndpoint2"), + expected: utils.String("/subscriptions/12345678-1234-5678-1234-123456789012/resourceGroups/mygroup1/providers/Microsoft.Network/frontDoors/frontdoor1/frontendEndpoints/exampleFrontendEndpoint2"), }, } for _, test := range testData { diff --git a/azurerm/internal/services/frontdoor/parse/backend_pool.go b/azurerm/internal/services/frontdoor/parse/backend_pool.go index ae0ced2742a1..1bc6c7aa259f 100644 --- a/azurerm/internal/services/frontdoor/parse/backend_pool.go +++ b/azurerm/internal/services/frontdoor/parse/backend_pool.go @@ -32,10 +32,11 @@ func BackendPoolID(input string) (*BackendPoolId, error) { FrontDoorName: frontDoorId.Name, } - // TODO: handle this being case-insensitive - // https://github.com/Azure/azure-sdk-for-go/issues/6762 + // API is broken - https://github.com/Azure/azure-sdk-for-go/issues/6762 if poolId.Name, err = id.PopSegment("backendPools"); err != nil { - return nil, err + if poolId.Name, err = id.PopSegment("backendpools"); err != nil { + return nil, err + } } if err := id.ValidateNoEmptySegments(input); err != nil { diff --git a/azurerm/internal/services/frontdoor/parse/backend_pool_test.go b/azurerm/internal/services/frontdoor/parse/backend_pool_test.go index 59e0ffe620c2..c0814204c6c7 100644 --- a/azurerm/internal/services/frontdoor/parse/backend_pool_test.go +++ b/azurerm/internal/services/frontdoor/parse/backend_pool_test.go @@ -1,5 +1,86 @@ package parse -import "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/resourceid" +import ( + "testing" + + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/resourceid" +) var _ resourceid.Formatter = BackendPoolId{} + +func TestBackendPoolIDFormatter(t *testing.T) { + subscriptionId := "12345678-1234-5678-1234-123456789012" + frontDoorId := NewFrontDoorID("group1", "frontdoor1") + actual := NewBackendPoolID(frontDoorId, "pool1").ID(subscriptionId) + expected := "/subscriptions/12345678-1234-5678-1234-123456789012/resourceGroups/group1/providers/Microsoft.Network/frontDoors/frontdoor1/backendPools/pool1" + if actual != expected { + t.Fatalf("Expected %q but got %q", expected, actual) + } +} + +func TestBackendPoolIDParser(t *testing.T) { + testData := []struct { + input string + expected *BackendPoolId + }{ + { + // lower case + input: "/subscriptions/12345678-1234-5678-1234-123456789012/resourceGroups/group1/providers/Microsoft.Network/frontdoors/frontDoor1/backendpools/pool1", + expected: &BackendPoolId{ + ResourceGroup: "group1", + FrontDoorName: "frontDoor1", + Name: "pool1", + }, + }, + { + // camel case + input: "/subscriptions/12345678-1234-5678-1234-123456789012/resourceGroups/group1/providers/Microsoft.Network/frontDoors/frontDoor1/backendPools/pool1", + expected: &BackendPoolId{ + ResourceGroup: "group1", + FrontDoorName: "frontDoor1", + Name: "pool1", + }, + }, + { + // title case + input: "/subscriptions/12345678-1234-5678-1234-123456789012/resourceGroups/group1/providers/Microsoft.Network/Frontdoors/frontDoor1/backendPools/pool1", + expected: &BackendPoolId{ + ResourceGroup: "group1", + FrontDoorName: "frontDoor1", + Name: "pool1", + }, + }, + { + // pascal case + input: "/subscriptions/12345678-1234-5678-1234-123456789012/resourceGroups/group1/providers/Microsoft.Network/FrontDoors/frontDoor1/backendPools/pool1", + expected: &BackendPoolId{ + ResourceGroup: "group1", + FrontDoorName: "frontDoor1", + Name: "pool1", + }, + }, + } + for _, test := range testData { + t.Logf("Testing %q..", test.input) + actual, err := BackendPoolID(test.input) + if err != nil && test.expected == nil { + continue + } else if err == nil && test.expected == nil { + t.Fatalf("Expected an error but didn't get one") + } else if err != nil && test.expected != nil { + t.Fatalf("Expected no error but got: %+v", err) + } + + if actual.ResourceGroup != test.expected.ResourceGroup { + t.Fatalf("Expected ResourceGroup to be %q but was %q", test.expected.ResourceGroup, actual.ResourceGroup) + } + + if actual.FrontDoorName != test.expected.FrontDoorName { + t.Fatalf("Expected FrontDoorName to be %q but was %q", test.expected.FrontDoorName, actual.FrontDoorName) + } + + if actual.Name != test.expected.Name { + t.Fatalf("Expected name to be %q but was %q", test.expected.Name, actual.Name) + } + } +} diff --git a/azurerm/internal/services/frontdoor/parse/frontdoor.go b/azurerm/internal/services/frontdoor/parse/frontdoor.go index 862030c3bcb3..93ecd692620a 100644 --- a/azurerm/internal/services/frontdoor/parse/frontdoor.go +++ b/azurerm/internal/services/frontdoor/parse/frontdoor.go @@ -2,12 +2,11 @@ package parse import ( "fmt" + "strings" "github.com/terraform-providers/terraform-provider-azurerm/azurerm/helpers/azure" ) -// TODO: tests - type FrontDoorId struct { Name string ResourceGroup string @@ -47,16 +46,16 @@ func parseFrontDoorChildResourceId(input string) (*FrontDoorId, *azure.ResourceI ResourceGroup: id.ResourceGroup, } - // TODO: ensure this is Normalized, presumably to frontdoor - // resourceGroup := id.ResourceGroup - // name := id.Path["frontdoors"] - // // Link to issue: https://github.com/Azure/azure-sdk-for-go/issues/6762 - // if name == "" { - // name = id.Path["Frontdoors"] - // } - - if frontdoor.Name, err = id.PopSegment("frontdoors"); err != nil { - return nil, nil, err + for key, value := range id.Path { + // In Azure API's should follow Postel's Law - where URI's should be insensitive for requests, + // but case-sensitive when referencing URI's in responses. Unfortunately the Networking API's + // treat both as case-insensitive - so until these API's follow the spec we need to identify + // the correct casing here. + if strings.EqualFold(key, "frontDoors") { + frontdoor.Name = value + delete(id.Path, key) + break + } } return &frontdoor, id, nil diff --git a/azurerm/internal/services/frontdoor/parse/frontdoor_test.go b/azurerm/internal/services/frontdoor/parse/frontdoor_test.go index 6656662c0e50..a48f41aef592 100644 --- a/azurerm/internal/services/frontdoor/parse/frontdoor_test.go +++ b/azurerm/internal/services/frontdoor/parse/frontdoor_test.go @@ -1,5 +1,77 @@ package parse -import "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/resourceid" +import ( + "testing" + + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/resourceid" +) var _ resourceid.Formatter = FrontDoorId{} + +func TestFrontDoorIDFormatter(t *testing.T) { + subscriptionId := "12345678-1234-5678-1234-123456789012" + actual := NewFrontDoorID("group1", "frontDoor1").ID(subscriptionId) + expected := "/subscriptions/12345678-1234-5678-1234-123456789012/resourceGroups/group1/providers/Microsoft.Network/frontDoors/frontDoor1" + if actual != expected { + t.Fatalf("Expected %q but got %q", expected, actual) + } +} + +func TestFrontDoorIDParser(t *testing.T) { + testData := []struct { + input string + expected *FrontDoorId + }{ + { + // lower case + input: "/subscriptions/12345678-1234-5678-1234-123456789012/resourceGroups/group1/providers/Microsoft.Network/frontdoors/frontDoor1", + expected: &FrontDoorId{ + ResourceGroup: "group1", + Name: "frontDoor1", + }, + }, + { + // camel case + input: "/subscriptions/12345678-1234-5678-1234-123456789012/resourceGroups/group1/providers/Microsoft.Network/frontDoors/frontDoor1", + expected: &FrontDoorId{ + ResourceGroup: "group1", + Name: "frontDoor1", + }, + }, + { + // title case + input: "/subscriptions/12345678-1234-5678-1234-123456789012/resourceGroups/group1/providers/Microsoft.Network/Frontdoors/frontDoor1", + expected: &FrontDoorId{ + ResourceGroup: "group1", + Name: "frontDoor1", + }, + }, + { + // pascal case + input: "/subscriptions/12345678-1234-5678-1234-123456789012/resourceGroups/group1/providers/Microsoft.Network/FrontDoors/frontDoor1", + expected: &FrontDoorId{ + ResourceGroup: "group1", + Name: "frontDoor1", + }, + }, + } + for _, test := range testData { + t.Logf("Testing %q..", test.input) + actual, err := FrontDoorID(test.input) + if err != nil && test.expected == nil { + continue + } else if err == nil && test.expected == nil { + t.Fatalf("Expected an error but didn't get one") + } else if err != nil && test.expected != nil { + t.Fatalf("Expected no error but got: %+v", err) + } + + if actual.ResourceGroup != test.expected.ResourceGroup { + t.Fatalf("Expected ResourceGroup to be %q but was %q", test.expected.ResourceGroup, actual.ResourceGroup) + } + + if actual.Name != test.expected.Name { + t.Fatalf("Expected name to be %q but was %q", test.expected.Name, actual.Name) + } + } +} From 19544cc6103a8ca8ceeebd94182b1aaaa8edb642 Mon Sep 17 00:00:00 2001 From: tombuildsstuff Date: Mon, 17 Aug 2020 10:19:58 +0200 Subject: [PATCH 27/41] r/frontdoor: helps if you set the field --- azurerm/internal/services/frontdoor/frontdoor_resource.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/azurerm/internal/services/frontdoor/frontdoor_resource.go b/azurerm/internal/services/frontdoor/frontdoor_resource.go index 3cc544e6b486..3f96b13689f0 100644 --- a/azurerm/internal/services/frontdoor/frontdoor_resource.go +++ b/azurerm/internal/services/frontdoor/frontdoor_resource.go @@ -1493,7 +1493,7 @@ func flattenRoutingRuleForwardingConfiguration(config frontdoor.BasicRouteConfig return &[]interface{}{ map[string]interface{}{ - "backend_pool_name": "name", + "backend_pool_name": name, "custom_forwarding_path": customForwardingPath, "forwarding_protocol": string(v.ForwardingProtocol), "cache_enabled": cacheEnabled, From 3462bf584a9d0bf67a7666a53e82b20b086a87d2 Mon Sep 17 00:00:00 2001 From: tombuildsstuff Date: Mon, 17 Aug 2020 10:20:05 +0200 Subject: [PATCH 28/41] r/frontdoor: renaming the test files to match the resources --- ...esource_test.go => frontdoor_firewall_policy_resource_test.go} | 0 .../{front_door_resource_test.go => frontdoor_resource_test.go} | 0 2 files changed, 0 insertions(+), 0 deletions(-) rename azurerm/internal/services/frontdoor/tests/{front_door_firewall_policy_resource_test.go => frontdoor_firewall_policy_resource_test.go} (100%) rename azurerm/internal/services/frontdoor/tests/{front_door_resource_test.go => frontdoor_resource_test.go} (100%) diff --git a/azurerm/internal/services/frontdoor/tests/front_door_firewall_policy_resource_test.go b/azurerm/internal/services/frontdoor/tests/frontdoor_firewall_policy_resource_test.go similarity index 100% rename from azurerm/internal/services/frontdoor/tests/front_door_firewall_policy_resource_test.go rename to azurerm/internal/services/frontdoor/tests/frontdoor_firewall_policy_resource_test.go diff --git a/azurerm/internal/services/frontdoor/tests/front_door_resource_test.go b/azurerm/internal/services/frontdoor/tests/frontdoor_resource_test.go similarity index 100% rename from azurerm/internal/services/frontdoor/tests/front_door_resource_test.go rename to azurerm/internal/services/frontdoor/tests/frontdoor_resource_test.go From 59ce804db9f5fced4b2861d1dba07b9fbcec9cc2 Mon Sep 17 00:00:00 2001 From: tombuildsstuff Date: Mon, 17 Aug 2020 10:24:39 +0200 Subject: [PATCH 29/41] r/frontdoor_firewall_policy: location is computed --- .../services/frontdoor/frontdoor_firewall_policy_resource.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/azurerm/internal/services/frontdoor/frontdoor_firewall_policy_resource.go b/azurerm/internal/services/frontdoor/frontdoor_firewall_policy_resource.go index 160860c37758..c48856fb3607 100644 --- a/azurerm/internal/services/frontdoor/frontdoor_firewall_policy_resource.go +++ b/azurerm/internal/services/frontdoor/frontdoor_firewall_policy_resource.go @@ -12,6 +12,7 @@ import ( "github.com/terraform-providers/terraform-provider-azurerm/azurerm/helpers/azure" "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/location" "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/services/frontdoor/migration" "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/services/frontdoor/parse" "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/services/frontdoor/validate" @@ -50,7 +51,7 @@ func resourceArmFrontDoorFirewallPolicy() *schema.Resource { ValidateFunc: validate.FrontDoorWAFName, }, - "location": azure.SchemaLocationOptional(), + "location": location.SchemaComputed(), "resource_group_name": azure.SchemaResourceGroupName(), From 3a7a074db1f695657826ef92583fa966cf61dfa4 Mon Sep 17 00:00:00 2001 From: tombuildsstuff Date: Mon, 17 Aug 2020 10:27:06 +0200 Subject: [PATCH 30/41] docs: removing conflicting terms --- website/docs/r/frontdoor_firewall_policy.html.markdown | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/website/docs/r/frontdoor_firewall_policy.html.markdown b/website/docs/r/frontdoor_firewall_policy.html.markdown index ba57ecdaa802..129a3785910a 100644 --- a/website/docs/r/frontdoor_firewall_policy.html.markdown +++ b/website/docs/r/frontdoor_firewall_policy.html.markdown @@ -227,16 +227,14 @@ The `exclusion` block supports the following: The following attributes are exported: -* `id` - Resource ID. +* `id` - The ID of the FrontDoor Firewall Policy. -* `location` - Resource location. +* `location` - The Azure Region where this FrontDoor Firewall Policy exists. -* `frontend_endpoint_ids` - the Frontend Endpoints associated with this Front Door Web Application Firewall policy. +* `frontend_endpoint_ids` - The Frontend Endpoints associated with this Front Door Web Application Firewall policy. ## Timeouts - - The `timeouts` block allows you to specify [timeouts](https://www.terraform.io/docs/configuration/resources.html#timeouts) for certain actions: * `create` - (Defaults to 30 minutes) Used when creating the FrontDoor Web Application Firewall Policy. From a5c8b47de7c0c7936c905c48260b07a7863ab432 Mon Sep 17 00:00:00 2001 From: tombuildsstuff Date: Mon, 17 Aug 2020 12:03:41 +0200 Subject: [PATCH 31/41] r/frontdoor_firewall_policy: moving the validation tests over --- ...frontdoor_firewall_policy_resource_test.go | 85 ------------------ .../services/frontdoor/validate/name.go | 22 +++++ .../services/frontdoor/validate/name_test.go | 89 +++++++++++++++++++ .../services/frontdoor/validate/validate.go | 16 +--- 4 files changed, 112 insertions(+), 100 deletions(-) create mode 100644 azurerm/internal/services/frontdoor/validate/name.go create mode 100644 azurerm/internal/services/frontdoor/validate/name_test.go diff --git a/azurerm/internal/services/frontdoor/tests/frontdoor_firewall_policy_resource_test.go b/azurerm/internal/services/frontdoor/tests/frontdoor_firewall_policy_resource_test.go index e9b8c6d8277b..91cc7327aad7 100644 --- a/azurerm/internal/services/frontdoor/tests/frontdoor_firewall_policy_resource_test.go +++ b/azurerm/internal/services/frontdoor/tests/frontdoor_firewall_policy_resource_test.go @@ -8,94 +8,9 @@ import ( "github.com/hashicorp/terraform-plugin-sdk/terraform" "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/services/frontdoor/validate" "github.com/terraform-providers/terraform-provider-azurerm/azurerm/utils" ) -func TestAccAzureRMFrontDoorFirewallPolicy_validateName(t *testing.T) { - cases := []struct { - Name string - Input string - ExpectError bool - }{ - { - Name: "Empty String", - Input: "", - ExpectError: true, - }, - { - Name: "Starst with Numeric", - Input: "1WellThisIsAllWrong", - ExpectError: true, - }, - { - Name: "Has Spaces", - Input: "What part of no spaces do you not understand", - ExpectError: true, - }, - { - Name: "Has Hyphens", - Input: "What-part-of-no-hyphens-do-you-not-understand", - ExpectError: true, - }, - { - Name: "Special Characters", - Input: "WellArn`tTheseSpecialCharacters?!", - ExpectError: true, - }, - { - Name: "Mixed Case Alpha and Numeric", - Input: "ThisNameIsAPerfectlyFine1", - ExpectError: false, - }, - { - Name: "Too Long", - Input: "OhMyLordyThisNameIsWayToLooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooog", - ExpectError: true, - }, - { - Name: "Max Length", - Input: "NowThisNameIsThePerfectLengthForAFrontdoorFireWallPolicyDontYouThinkAnyLongerWouldBeJustWayToLoooooooooooooooooooongDontYouThink", - ExpectError: false, - }, - { - Name: "Minimum Length Upper", - Input: "A", - ExpectError: false, - }, - { - Name: "Minimum Length Lower", - Input: "a", - ExpectError: false, - }, - { - Name: "Mixed Case Alpha no Numeric", - Input: "LookMomNoNumbers", - ExpectError: false, - }, - { - Name: "All Upper Alpha with Numeric", - Input: "OU812", - ExpectError: false, - }, - { - Name: "All lower no Numeric", - Input: "heythisisalllowercase", - ExpectError: false, - }, - } - - for _, tc := range cases { - _, errors := validate.FrontDoorWAFName(tc.Input, tc.Name) - - hasError := len(errors) > 0 - - if tc.ExpectError && !hasError { - t.Fatalf("Expected the FrontDoor WAF Name to trigger a validation error for '%s'", tc.Name) - } - } -} - func TestAccAzureRMFrontDoorFirewallPolicy_basic(t *testing.T) { data := acceptance.BuildTestData(t, "azurerm_frontdoor_firewall_policy", "test") resource.ParallelTest(t, resource.TestCase{ diff --git a/azurerm/internal/services/frontdoor/validate/name.go b/azurerm/internal/services/frontdoor/validate/name.go new file mode 100644 index 000000000000..32698767bf9f --- /dev/null +++ b/azurerm/internal/services/frontdoor/validate/name.go @@ -0,0 +1,22 @@ +package validate + +import ( + "fmt" + + "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 { + return nil, 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, nil +} + +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 { + return nil, 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, nil +} diff --git a/azurerm/internal/services/frontdoor/validate/name_test.go b/azurerm/internal/services/frontdoor/validate/name_test.go new file mode 100644 index 000000000000..3bc09001a655 --- /dev/null +++ b/azurerm/internal/services/frontdoor/validate/name_test.go @@ -0,0 +1,89 @@ +package validate + +import ( + "testing" +) + +func TestAccAzureRMFrontDoorFirewallPolicy_validateName(t *testing.T) { + cases := []struct { + Name string + Input string + ExpectError bool + }{ + { + Name: "Empty String", + Input: "", + ExpectError: true, + }, + { + Name: "Starst with Numeric", + Input: "1WellThisIsAllWrong", + ExpectError: true, + }, + { + Name: "Has Spaces", + Input: "What part of no spaces do you not understand", + ExpectError: true, + }, + { + Name: "Has Hyphens", + Input: "What-part-of-no-hyphens-do-you-not-understand", + ExpectError: true, + }, + { + Name: "Special Characters", + Input: "WellArn`tTheseSpecialCharacters?!", + ExpectError: true, + }, + { + Name: "Mixed Case Alpha and Numeric", + Input: "ThisNameIsAPerfectlyFine1", + ExpectError: false, + }, + { + Name: "Too Long", + Input: "OhMyLordyThisNameIsWayToLooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooog", + ExpectError: true, + }, + { + Name: "Max Length", + Input: "NowThisNameIsThePerfectLengthForAFrontdoorFireWallPolicyDontYouThinkAnyLongerWouldBeJustWayToLoooooooooooooooooooongDontYouThink", + ExpectError: false, + }, + { + Name: "Minimum Length Upper", + Input: "A", + ExpectError: false, + }, + { + Name: "Minimum Length Lower", + Input: "a", + ExpectError: false, + }, + { + Name: "Mixed Case Alpha no Numeric", + Input: "LookMomNoNumbers", + ExpectError: false, + }, + { + Name: "All Upper Alpha with Numeric", + Input: "OU812", + ExpectError: false, + }, + { + Name: "All lower no Numeric", + Input: "heythisisalllowercase", + ExpectError: false, + }, + } + + for _, tc := range cases { + _, errors := FrontDoorWAFName(tc.Input, tc.Name) + + hasError := len(errors) > 0 + + if tc.ExpectError && !hasError { + t.Fatalf("Expected the FrontDoor WAF Name to trigger a validation error for '%s'", tc.Name) + } + } +} diff --git a/azurerm/internal/services/frontdoor/validate/validate.go b/azurerm/internal/services/frontdoor/validate/validate.go index b4aedd8017db..4a0b1e00c2ae 100644 --- a/azurerm/internal/services/frontdoor/validate/validate.go +++ b/azurerm/internal/services/frontdoor/validate/validate.go @@ -9,21 +9,6 @@ import ( "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 { - return nil, 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, nil -} - -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 { - return nil, 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, nil -} - 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 { return nil, 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)) @@ -41,6 +26,7 @@ func FrontdoorCustomBlockResponseBody(i interface{}, k string) (_ []string, erro } func FrontdoorSettings(d *schema.ResourceDiff) error { + // TODO: move this out of here - this package should only be taking parsed objects routingRules := d.Get("routing_rule").([]interface{}) configFrontendEndpoints := d.Get("frontend_endpoint").([]interface{}) backendPools := d.Get("backend_pool").([]interface{}) From 1c38f16bf811721b99f6ed6f65623da238cfb239 Mon Sep 17 00:00:00 2001 From: tombuildsstuff Date: Mon, 17 Aug 2020 12:11:27 +0200 Subject: [PATCH 32/41] r/frontdoor: rewriting the ID's to ensure they're consistent --- .../services/frontdoor/frontdoor_resource.go | 175 ++++++++++-------- 1 file changed, 100 insertions(+), 75 deletions(-) diff --git a/azurerm/internal/services/frontdoor/frontdoor_resource.go b/azurerm/internal/services/frontdoor/frontdoor_resource.go index 3f96b13689f0..36b81b081153 100644 --- a/azurerm/internal/services/frontdoor/frontdoor_resource.go +++ b/azurerm/internal/services/frontdoor/frontdoor_resource.go @@ -601,6 +601,7 @@ func resourceArmFrontDoorCreateUpdate(d *schema.ResourceData, meta interface{}) func resourceArmFrontDoorRead(d *schema.ResourceData, meta interface{}) error { client := meta.(*clients.Client).Frontdoor.FrontDoorsClient + subscriptionId := meta.(*clients.Client).Account.SubscriptionId ctx, cancel := timeouts.ForRead(meta.(*clients.Client).StopContext, d) defer cancel() @@ -624,7 +625,7 @@ func resourceArmFrontDoorRead(d *schema.ResourceData, meta interface{}) error { d.Set("location", azure.NormalizeLocation(*resp.Location)) if props := resp.Properties; props != nil { - flattenedBackendPools, err := flattenArmFrontDoorBackendPools(props.BackendPools) + flattenedBackendPools, err := flattenArmFrontDoorBackendPools(props.BackendPools, *id, subscriptionId) if err != nil { return fmt.Errorf("flattening `backend_pool`: %+v", err) } @@ -633,14 +634,8 @@ func resourceArmFrontDoorRead(d *schema.ResourceData, meta interface{}) error { } backendPoolSettings := flattenArmFrontDoorBackendPoolsSettings(props.BackendPoolsSettings) - - if err := d.Set("enforce_backend_pools_certificate_name_check", backendPoolSettings["enforce_backend_pools_certificate_name_check"].(bool)); err != nil { - return fmt.Errorf("setting `enforce_backend_pools_certificate_name_check`: %+v", err) - } - - if err := d.Set("backend_pools_send_receive_timeout_seconds", backendPoolSettings["backend_pools_send_receive_timeout_seconds"].(int32)); err != nil { - return fmt.Errorf("setting `backend_pools_send_receive_timeout_seconds`: %+v", err) - } + d.Set("enforce_backend_pools_certificate_name_check", backendPoolSettings.enforceBackendPoolsCertificateNameCheck) + d.Set("backend_pools_send_receive_timeout_seconds", backendPoolSettings.backendPoolsSendReceiveTimeoutSeconds) d.Set("cname", props.Cname) d.Set("header_frontdoor_id", props.FrontdoorID) @@ -654,7 +649,7 @@ func resourceArmFrontDoorRead(d *schema.ResourceData, meta interface{}) error { if err != nil { return fmt.Errorf("retrieving FrontEnd Endpoint Custom HTTPS Information: %+v", err) } - frontDoorFrontendEndpoints, err := flattenFrontEndEndpoints(frontEndEndpointInfo) + frontDoorFrontendEndpoints, err := flattenFrontEndEndpoints(frontEndEndpointInfo, *id, subscriptionId) if err != nil { return fmt.Errorf("flattening `frontend_endpoint`: %+v", err) } @@ -662,15 +657,15 @@ func resourceArmFrontDoorRead(d *schema.ResourceData, meta interface{}) error { return fmt.Errorf("setting `frontend_endpoint`: %+v", err) } - if err := d.Set("backend_pool_health_probe", flattenArmFrontDoorHealthProbeSettingsModel(props.HealthProbeSettings)); err != nil { + if err := d.Set("backend_pool_health_probe", flattenArmFrontDoorHealthProbeSettingsModel(props.HealthProbeSettings, *id, subscriptionId)); err != nil { return fmt.Errorf("setting `backend_pool_health_probe`: %+v", err) } - if err := d.Set("backend_pool_load_balancing", flattenArmFrontDoorLoadBalancingSettingsModel(props.LoadBalancingSettings)); err != nil { + if err := d.Set("backend_pool_load_balancing", flattenArmFrontDoorLoadBalancingSettingsModel(props.LoadBalancingSettings, *id, subscriptionId)); err != nil { return fmt.Errorf("setting `backend_pool_load_balancing`: %+v", err) } - flattenedRoutingRules, err := flattenArmFrontDoorRoutingRule(props.RoutingRules, d.Get("routing_rule")) + flattenedRoutingRules, err := flattenArmFrontDoorRoutingRule(props.RoutingRules, d.Get("routing_rule"), *id, subscriptionId) if err != nil { return fmt.Errorf("flattening `routing_rules`: %+v", err) } @@ -1105,7 +1100,7 @@ func expandArmFrontDoorForwardingConfiguration(input []interface{}, frontDoorId return forwardingConfiguration } -func flattenArmFrontDoorBackendPools(input *[]frontdoor.BackendPool) (*[]interface{}, error) { +func flattenArmFrontDoorBackendPools(input *[]frontdoor.BackendPool, frontDoorId parse.FrontDoorId, subscriptionId string) (*[]interface{}, error) { if input == nil { return &[]interface{}{}, nil } @@ -1113,12 +1108,10 @@ func flattenArmFrontDoorBackendPools(input *[]frontdoor.BackendPool) (*[]interfa output := make([]interface{}, 0) for _, v := range *input { id := "" - if v.ID != nil { - id = *v.ID - } - name := "" if v.Name != nil { + // rewrite the ID to ensure it's consistent + id = parse.NewBackendPoolID(frontDoorId, *v.Name).ID(subscriptionId) name = *v.Name } @@ -1159,28 +1152,33 @@ func flattenArmFrontDoorBackendPools(input *[]frontdoor.BackendPool) (*[]interfa return &output, nil } -func flattenArmFrontDoorBackendPoolsSettings(input *frontdoor.BackendPoolsSettings) map[string]interface{} { - result := make(map[string]interface{}) - - // Set default values - result["enforce_backend_pools_certificate_name_check"] = true - result["backend_pools_send_receive_timeout_seconds"] = int32(60) +type flattenedBackendPoolSettings struct { + enforceBackendPoolsCertificateNameCheck bool + backendPoolsSendReceiveTimeoutSeconds int +} +func flattenArmFrontDoorBackendPoolsSettings(input *frontdoor.BackendPoolsSettings) flattenedBackendPoolSettings { if input == nil { - return result + return flattenedBackendPoolSettings{ + enforceBackendPoolsCertificateNameCheck: true, + backendPoolsSendReceiveTimeoutSeconds: 60, + } } - result["enforce_backend_pools_certificate_name_check"] = false - - if enforceCertificateNameCheck := input.EnforceCertificateNameCheck; enforceCertificateNameCheck != "" && enforceCertificateNameCheck == frontdoor.EnforceCertificateNameCheckEnabledStateEnabled { - result["enforce_backend_pools_certificate_name_check"] = true + enforceCertificateNameCheck := false + if input.EnforceCertificateNameCheck != "" && input.EnforceCertificateNameCheck == frontdoor.EnforceCertificateNameCheckEnabledStateEnabled { + enforceCertificateNameCheck = true } - if sendRecvTimeoutSeconds := input.SendRecvTimeoutSeconds; sendRecvTimeoutSeconds != nil { - result["backend_pools_send_receive_timeout_seconds"] = *sendRecvTimeoutSeconds + sendReceiveTimeoutSeconds := 0 + if input.SendRecvTimeoutSeconds != nil { + sendReceiveTimeoutSeconds = int(*input.SendRecvTimeoutSeconds) } - return result + return flattenedBackendPoolSettings{ + enforceBackendPoolsCertificateNameCheck: enforceCertificateNameCheck, + backendPoolsSendReceiveTimeoutSeconds: sendReceiveTimeoutSeconds, + } } func flattenArmFrontDoorBackend(input *[]frontdoor.Backend) []interface{} { @@ -1247,7 +1245,7 @@ func retrieveFrontEndEndpointInformation(ctx context.Context, client *frontdoor. return &output, nil } -func flattenFrontEndEndpoints(input *[]frontdoor.FrontendEndpoint) (*[]interface{}, error) { +func flattenFrontEndEndpoints(input *[]frontdoor.FrontendEndpoint, frontDoorId parse.FrontDoorId, subscriptionId string) (*[]interface{}, error) { results := make([]interface{}, 0) if input == nil { return &results, nil @@ -1255,11 +1253,10 @@ func flattenFrontEndEndpoints(input *[]frontdoor.FrontendEndpoint) (*[]interface for _, item := range *input { id := "" - if item.ID != nil { - id = *item.ID - } name := "" if item.Name != nil { + // rewrite the ID to ensure it's consistent + id = parse.NewFrontendEndpointID(frontDoorId, *item.Name).ID(subscriptionId) name = *item.Name } @@ -1283,7 +1280,13 @@ func flattenFrontEndEndpoints(input *[]frontdoor.FrontendEndpoint) (*[]interface } if waf := props.WebApplicationFirewallPolicyLink; waf != nil && waf.ID != nil { - webApplicationFirewallPolicyLinkId = *waf.ID + // rewrite the ID to ensure it's consistent + parsed, err := parse.WebApplicationFirewallPolicyID(*waf.ID) + if err != nil { + return nil, err + } + + webApplicationFirewallPolicyLinkId = parsed.ID(subscriptionId) } flattenedHttpsConfig := flattenCustomHttpsConfiguration(props) @@ -1306,77 +1309,101 @@ func flattenFrontEndEndpoints(input *[]frontdoor.FrontendEndpoint) (*[]interface return &results, nil } -func flattenArmFrontDoorHealthProbeSettingsModel(input *[]frontdoor.HealthProbeSettingsModel) []interface{} { +func flattenArmFrontDoorHealthProbeSettingsModel(input *[]frontdoor.HealthProbeSettingsModel, frontDoorId parse.FrontDoorId, subscriptionId string) []interface{} { results := make([]interface{}, 0) if input == nil { return results } for _, v := range *input { - result := make(map[string]interface{}) - if id := v.ID; id != nil { - result["id"] = *id - } - if name := v.Name; name != nil { - result["name"] = *name + id := "" + name := "" + if v.Name != nil { + // rewrite the ID to ensure it's consistent + id = parse.NewHealthProbeID(frontDoorId, *v.Name).ID(subscriptionId) + name = *v.Name } + + enabled := false + intervalInSeconds := 0 + path := "" + probeMethod := "" + protocol := "" if properties := v.HealthProbeSettingsProperties; properties != nil { - if intervalInSeconds := properties.IntervalInSeconds; intervalInSeconds != nil { - result["interval_in_seconds"] = *intervalInSeconds + if properties.IntervalInSeconds != nil { + intervalInSeconds = int(*properties.IntervalInSeconds) } - if path := properties.Path; path != nil { - result["path"] = *path + if properties.Path != nil { + path = *properties.Path } if healthProbeMethod := properties.HealthProbeMethod; healthProbeMethod != "" { - // I have to upper this as the frontdoor.GET and frondoor.HEAD types are uppercased + // I have to upper this as the frontdoor.GET and frontdoor.HEAD types are uppercased // but Azure stores them in the resource as pascal cased (e.g. "Get" and "Head") - result["probe_method"] = strings.ToUpper(string(healthProbeMethod)) + probeMethod = strings.ToUpper(string(healthProbeMethod)) } - if enabled := properties.EnabledState; enabled != "" { - result["enabled"] = enabled == frontdoor.HealthProbeEnabledEnabled + if properties.EnabledState != "" { + enabled = properties.EnabledState == frontdoor.HealthProbeEnabledEnabled } - result["protocol"] = string(properties.Protocol) + protocol = string(properties.Protocol) } - results = append(results, result) + results = append(results, map[string]interface{}{ + "enabled": enabled, + "id": id, + "name": name, + "protocol": protocol, + "interval_in_seconds": intervalInSeconds, + "path": path, + "probe_method": probeMethod, + }) } return results } -func flattenArmFrontDoorLoadBalancingSettingsModel(input *[]frontdoor.LoadBalancingSettingsModel) []interface{} { +func flattenArmFrontDoorLoadBalancingSettingsModel(input *[]frontdoor.LoadBalancingSettingsModel, frontDoorId parse.FrontDoorId, subscriptionId string) []interface{} { results := make([]interface{}, 0) if input == nil { return results } for _, v := range *input { - result := make(map[string]interface{}) - if id := v.ID; id != nil { - result["id"] = *id - } - if name := v.Name; name != nil { - result["name"] = *name + id := "" + name := "" + if v.Name != nil { + // rewrite the ID to ensure it's consistent + id = parse.NewLoadBalancingID(frontDoorId, *v.Name).ID(subscriptionId) + name = *v.Name } + + additionalLatencyMilliseconds := 0 + sampleSize := 0 + successfulSamplesRequired := 0 if properties := v.LoadBalancingSettingsProperties; properties != nil { - if additionalLatencyMilliseconds := properties.AdditionalLatencyMilliseconds; additionalLatencyMilliseconds != nil { - result["additional_latency_milliseconds"] = *additionalLatencyMilliseconds + if properties.AdditionalLatencyMilliseconds != nil { + additionalLatencyMilliseconds = int(*properties.AdditionalLatencyMilliseconds) } - if sampleSize := properties.SampleSize; sampleSize != nil { - result["sample_size"] = *sampleSize + if properties.SampleSize != nil { + sampleSize = int(*properties.SampleSize) } - if successfulSamplesRequired := properties.SuccessfulSamplesRequired; successfulSamplesRequired != nil { - result["successful_samples_required"] = *successfulSamplesRequired + if properties.SuccessfulSamplesRequired != nil { + successfulSamplesRequired = int(*properties.SuccessfulSamplesRequired) } } - results = append(results, result) + results = append(results, map[string]interface{}{ + "additional_latency_milliseconds": additionalLatencyMilliseconds, + "id": id, + "name": name, + "sample_size": sampleSize, + "successful_samples_required": successfulSamplesRequired, + }) } return results } -func flattenArmFrontDoorRoutingRule(input *[]frontdoor.RoutingRule, oldBlocks interface{}) (*[]interface{}, error) { +func flattenArmFrontDoorRoutingRule(input *[]frontdoor.RoutingRule, oldBlocks interface{}, frontDoorId parse.FrontDoorId, subscriptionId string) (*[]interface{}, error) { if input == nil { return &[]interface{}{}, nil } @@ -1384,12 +1411,10 @@ func flattenArmFrontDoorRoutingRule(input *[]frontdoor.RoutingRule, oldBlocks in output := make([]interface{}, 0) for _, v := range *input { id := "" - if v.ID != nil { - id = *v.ID - } - name := "" if v.Name != nil { + // rewrite the ID to ensure it's consistent + id = parse.NewRoutingRuleID(frontDoorId, *v.Name).ID(subscriptionId) name = *v.Name } @@ -1405,13 +1430,13 @@ func flattenArmFrontDoorRoutingRule(input *[]frontdoor.RoutingRule, oldBlocks in forwardConfiguration, err := flattenRoutingRuleForwardingConfiguration(props.RouteConfiguration, oldBlocks) if err != nil { - return nil, err + return nil, fmt.Errorf("flattening `forward_configuration`: %+v", err) } forwardingConfiguration = *forwardConfiguration frontendEndpoints, err := flattenArmFrontDoorFrontendEndpointsSubResources(props.FrontendEndpoints) if err != nil { - return nil, err + return nil, fmt.Errorf("flattening `frontend_endpoints`: %+v", err) } frontEndEndpoints = *frontendEndpoints From ef7e5ba6506543c34d7b093be1ca20ed332c5b41 Mon Sep 17 00:00:00 2001 From: tombuildsstuff Date: Mon, 17 Aug 2020 12:28:35 +0200 Subject: [PATCH 33/41] frontdoor: tests for the ID Parsers --- .../services/frontdoor/parse/backend_pool.go | 9 ++- .../frontdoor/parse/backend_pool_test.go | 10 +-- .../frontdoor/parse/frontend_endpoint.go | 8 +- .../frontdoor/parse/frontend_endpoint_test.go | 75 +++++++++++++++++- .../services/frontdoor/parse/health_probe.go | 8 +- .../frontdoor/parse/health_probe_test.go | 75 +++++++++++++++++- .../frontdoor/parse/load_balancing.go | 8 +- .../frontdoor/parse/load_balancing_test.go | 75 +++++++++++++++++- .../services/frontdoor/parse/routing_rule.go | 48 ++++++++++++ .../frontdoor/parse/routing_rule_test.go | 78 +++++++++++++++++++ .../web_application_firewall_policy_test.go | 65 +++++++++++++++- 11 files changed, 436 insertions(+), 23 deletions(-) create mode 100644 azurerm/internal/services/frontdoor/parse/routing_rule.go create mode 100644 azurerm/internal/services/frontdoor/parse/routing_rule_test.go diff --git a/azurerm/internal/services/frontdoor/parse/backend_pool.go b/azurerm/internal/services/frontdoor/parse/backend_pool.go index 1bc6c7aa259f..7d333ef569c7 100644 --- a/azurerm/internal/services/frontdoor/parse/backend_pool.go +++ b/azurerm/internal/services/frontdoor/parse/backend_pool.go @@ -33,9 +33,12 @@ func BackendPoolID(input string) (*BackendPoolId, error) { } // API is broken - https://github.com/Azure/azure-sdk-for-go/issues/6762 - if poolId.Name, err = id.PopSegment("backendPools"); err != nil { - if poolId.Name, err = id.PopSegment("backendpools"); err != nil { - return nil, err + // note: the ordering is important since the defined case (we want to error with) is backendPools + if poolId.Name, err = id.PopSegment("backendpools"); err != nil { + if poolId.Name, err = id.PopSegment("BackendPools"); err != nil { + if poolId.Name, err = id.PopSegment("backendPools"); err != nil { + return nil, err + } } } diff --git a/azurerm/internal/services/frontdoor/parse/backend_pool_test.go b/azurerm/internal/services/frontdoor/parse/backend_pool_test.go index c0814204c6c7..6d7a28458cb9 100644 --- a/azurerm/internal/services/frontdoor/parse/backend_pool_test.go +++ b/azurerm/internal/services/frontdoor/parse/backend_pool_test.go @@ -43,7 +43,7 @@ func TestBackendPoolIDParser(t *testing.T) { }, { // title case - input: "/subscriptions/12345678-1234-5678-1234-123456789012/resourceGroups/group1/providers/Microsoft.Network/Frontdoors/frontDoor1/backendPools/pool1", + input: "/subscriptions/12345678-1234-5678-1234-123456789012/resourceGroups/group1/providers/Microsoft.Network/Frontdoors/frontDoor1/BackendPools/pool1", expected: &BackendPoolId{ ResourceGroup: "group1", FrontDoorName: "frontDoor1", @@ -52,12 +52,8 @@ func TestBackendPoolIDParser(t *testing.T) { }, { // pascal case - input: "/subscriptions/12345678-1234-5678-1234-123456789012/resourceGroups/group1/providers/Microsoft.Network/FrontDoors/frontDoor1/backendPools/pool1", - expected: &BackendPoolId{ - ResourceGroup: "group1", - FrontDoorName: "frontDoor1", - Name: "pool1", - }, + input: "/subscriptions/12345678-1234-5678-1234-123456789012/resourceGroups/group1/providers/Microsoft.Network/FrontDoors/frontDoor1/Backendpools/pool1", + expected: nil, }, } for _, test := range testData { diff --git a/azurerm/internal/services/frontdoor/parse/frontend_endpoint.go b/azurerm/internal/services/frontdoor/parse/frontend_endpoint.go index 5b741c67eb64..0c893fefaf38 100644 --- a/azurerm/internal/services/frontdoor/parse/frontend_endpoint.go +++ b/azurerm/internal/services/frontdoor/parse/frontend_endpoint.go @@ -32,10 +32,12 @@ func FrontendEndpointID(input string) (*FrontendEndpointId, error) { FrontDoorName: frontDoorId.Name, } - // TODO: handle this being case-insensitive // https://github.com/Azure/azure-sdk-for-go/issues/6762 - if endpointId.Name, err = id.PopSegment("frontendEndpoints"); err != nil { - return nil, err + // note: the ordering is important since the defined case (we want to error with) is frontendEndpoints + if endpointId.Name, err = id.PopSegment("FrontendEndpoints"); err != nil { + if endpointId.Name, err = id.PopSegment("frontendEndpoints"); err != nil { + return nil, err + } } if err := id.ValidateNoEmptySegments(input); err != nil { diff --git a/azurerm/internal/services/frontdoor/parse/frontend_endpoint_test.go b/azurerm/internal/services/frontdoor/parse/frontend_endpoint_test.go index 957cb692cdf7..d8f849d54a29 100644 --- a/azurerm/internal/services/frontdoor/parse/frontend_endpoint_test.go +++ b/azurerm/internal/services/frontdoor/parse/frontend_endpoint_test.go @@ -1,5 +1,78 @@ package parse -import "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/resourceid" +import ( + "testing" + + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/resourceid" +) var _ resourceid.Formatter = FrontendEndpointId{} + +func TestFrontendEndpointIDFormatter(t *testing.T) { + subscriptionId := "12345678-1234-5678-1234-123456789012" + frontDoorId := NewFrontDoorID("group1", "frontdoor1") + actual := NewFrontendEndpointID(frontDoorId, "endpoint1").ID(subscriptionId) + expected := "/subscriptions/12345678-1234-5678-1234-123456789012/resourceGroups/group1/providers/Microsoft.Network/frontDoors/frontdoor1/frontendEndpoints/endpoint1" + if actual != expected { + t.Fatalf("Expected %q but got %q", expected, actual) + } +} + +func TestFrontendEndpointIDParser(t *testing.T) { + testData := []struct { + input string + expected *FrontendEndpointId + }{ + { + // lower case + input: "/subscriptions/12345678-1234-5678-1234-123456789012/resourceGroups/group1/providers/Microsoft.Network/frontdoors/frontDoor1/frontendendpoints/endpoint1", + expected: nil, + }, + { + // camel case + input: "/subscriptions/12345678-1234-5678-1234-123456789012/resourceGroups/group1/providers/Microsoft.Network/frontDoors/frontDoor1/frontendEndpoints/endpoint1", + expected: &FrontendEndpointId{ + ResourceGroup: "group1", + FrontDoorName: "frontDoor1", + Name: "endpoint1", + }, + }, + { + // title case + input: "/subscriptions/12345678-1234-5678-1234-123456789012/resourceGroups/group1/providers/Microsoft.Network/Frontdoors/frontDoor1/FrontendEndpoints/endpoint1", + expected: &FrontendEndpointId{ + ResourceGroup: "group1", + FrontDoorName: "frontDoor1", + Name: "endpoint1", + }, + }, + { + // pascal case + input: "/subscriptions/12345678-1234-5678-1234-123456789012/resourceGroups/group1/providers/Microsoft.Network/FrontDoors/frontDoor1/Frontendendpoints/endpoint1", + expected: nil, + }, + } + for _, test := range testData { + t.Logf("Testing %q..", test.input) + actual, err := FrontendEndpointID(test.input) + if err != nil && test.expected == nil { + continue + } else if err == nil && test.expected == nil { + t.Fatalf("Expected an error but didn't get one") + } else if err != nil && test.expected != nil { + t.Fatalf("Expected no error but got: %+v", err) + } + + if actual.ResourceGroup != test.expected.ResourceGroup { + t.Fatalf("Expected ResourceGroup to be %q but was %q", test.expected.ResourceGroup, actual.ResourceGroup) + } + + if actual.FrontDoorName != test.expected.FrontDoorName { + t.Fatalf("Expected FrontDoorName to be %q but was %q", test.expected.FrontDoorName, actual.FrontDoorName) + } + + if actual.Name != test.expected.Name { + t.Fatalf("Expected name to be %q but was %q", test.expected.Name, actual.Name) + } + } +} diff --git a/azurerm/internal/services/frontdoor/parse/health_probe.go b/azurerm/internal/services/frontdoor/parse/health_probe.go index f924dffffd4b..1cc56b6865cb 100644 --- a/azurerm/internal/services/frontdoor/parse/health_probe.go +++ b/azurerm/internal/services/frontdoor/parse/health_probe.go @@ -32,10 +32,12 @@ func HealthProbeID(input string) (*HealthProbeId, error) { FrontDoorName: frontDoorId.Name, } - // TODO: handle this being case-insensitive // https://github.com/Azure/azure-sdk-for-go/issues/6762 - if probeId.Name, err = id.PopSegment("healthProbeSettings"); err != nil { - return nil, err + // note: the ordering is important since the defined case (we want to error with) is healthProbeSettings + if probeId.Name, err = id.PopSegment("HealthProbeSettings"); err != nil { + if probeId.Name, err = id.PopSegment("healthProbeSettings"); err != nil { + return nil, err + } } if err := id.ValidateNoEmptySegments(input); err != nil { diff --git a/azurerm/internal/services/frontdoor/parse/health_probe_test.go b/azurerm/internal/services/frontdoor/parse/health_probe_test.go index b5a764e7dccf..cf1d5bdc7524 100644 --- a/azurerm/internal/services/frontdoor/parse/health_probe_test.go +++ b/azurerm/internal/services/frontdoor/parse/health_probe_test.go @@ -1,5 +1,78 @@ package parse -import "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/resourceid" +import ( + "testing" + + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/resourceid" +) var _ resourceid.Formatter = HealthProbeId{} + +func TestHealthProbeIDFormatter(t *testing.T) { + subscriptionId := "12345678-1234-5678-1234-123456789012" + frontDoorId := NewFrontDoorID("group1", "frontdoor1") + actual := NewHealthProbeID(frontDoorId, "probe1").ID(subscriptionId) + expected := "/subscriptions/12345678-1234-5678-1234-123456789012/resourceGroups/group1/providers/Microsoft.Network/frontDoors/frontdoor1/healthProbeSettings/probe1" + if actual != expected { + t.Fatalf("Expected %q but got %q", expected, actual) + } +} + +func TestHealthProbeIDParser(t *testing.T) { + testData := []struct { + input string + expected *HealthProbeId + }{ + { + // lower case + input: "/subscriptions/12345678-1234-5678-1234-123456789012/resourceGroups/group1/providers/Microsoft.Network/frontdoors/frontDoor1/healthprobesettings/probe1", + expected: nil, + }, + { + // camel case + input: "/subscriptions/12345678-1234-5678-1234-123456789012/resourceGroups/group1/providers/Microsoft.Network/frontDoors/frontDoor1/healthProbeSettings/probe1", + expected: &HealthProbeId{ + ResourceGroup: "group1", + FrontDoorName: "frontDoor1", + Name: "probe1", + }, + }, + { + // title case + input: "/subscriptions/12345678-1234-5678-1234-123456789012/resourceGroups/group1/providers/Microsoft.Network/Frontdoors/frontDoor1/HealthProbeSettings/probe1", + expected: &HealthProbeId{ + ResourceGroup: "group1", + FrontDoorName: "frontDoor1", + Name: "probe1", + }, + }, + { + // pascal case + input: "/subscriptions/12345678-1234-5678-1234-123456789012/resourceGroups/group1/providers/Microsoft.Network/FrontDoors/frontDoor1/Healthprobesettings/probe1", + expected: nil, + }, + } + for _, test := range testData { + t.Logf("Testing %q..", test.input) + actual, err := HealthProbeID(test.input) + if err != nil && test.expected == nil { + continue + } else if err == nil && test.expected == nil { + t.Fatalf("Expected an error but didn't get one") + } else if err != nil && test.expected != nil { + t.Fatalf("Expected no error but got: %+v", err) + } + + if actual.ResourceGroup != test.expected.ResourceGroup { + t.Fatalf("Expected ResourceGroup to be %q but was %q", test.expected.ResourceGroup, actual.ResourceGroup) + } + + if actual.FrontDoorName != test.expected.FrontDoorName { + t.Fatalf("Expected FrontDoorName to be %q but was %q", test.expected.FrontDoorName, actual.FrontDoorName) + } + + if actual.Name != test.expected.Name { + t.Fatalf("Expected name to be %q but was %q", test.expected.Name, actual.Name) + } + } +} diff --git a/azurerm/internal/services/frontdoor/parse/load_balancing.go b/azurerm/internal/services/frontdoor/parse/load_balancing.go index 724c36f34a90..6e54be67e5ee 100644 --- a/azurerm/internal/services/frontdoor/parse/load_balancing.go +++ b/azurerm/internal/services/frontdoor/parse/load_balancing.go @@ -32,10 +32,12 @@ func LoadBalancingID(input string) (*LoadBalancingId, error) { FrontDoorName: frontDoorId.Name, } - // TODO: handle this being case-insensitive // https://github.com/Azure/azure-sdk-for-go/issues/6762 - if loadBalancingId.Name, err = id.PopSegment("loadBalancingSettings"); err != nil { - return nil, err + // note: the ordering is important since the defined case (we want to error with) is loadBalancingSettings + if loadBalancingId.Name, err = id.PopSegment("LoadBalancingSettings"); err != nil { + if loadBalancingId.Name, err = id.PopSegment("loadBalancingSettings"); err != nil { + return nil, err + } } if err := id.ValidateNoEmptySegments(input); err != nil { diff --git a/azurerm/internal/services/frontdoor/parse/load_balancing_test.go b/azurerm/internal/services/frontdoor/parse/load_balancing_test.go index 7f523828d24e..52e0191900f0 100644 --- a/azurerm/internal/services/frontdoor/parse/load_balancing_test.go +++ b/azurerm/internal/services/frontdoor/parse/load_balancing_test.go @@ -1,5 +1,78 @@ package parse -import "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/resourceid" +import ( + "testing" + + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/resourceid" +) var _ resourceid.Formatter = LoadBalancingId{} + +func TestLoadBalancingIDFormatter(t *testing.T) { + subscriptionId := "12345678-1234-5678-1234-123456789012" + frontDoorId := NewFrontDoorID("group1", "frontdoor1") + actual := NewLoadBalancingID(frontDoorId, "setting1").ID(subscriptionId) + expected := "/subscriptions/12345678-1234-5678-1234-123456789012/resourceGroups/group1/providers/Microsoft.Network/frontDoors/frontdoor1/loadBalancingSettings/setting1" + if actual != expected { + t.Fatalf("Expected %q but got %q", expected, actual) + } +} + +func TestLoadBalancingIDParser(t *testing.T) { + testData := []struct { + input string + expected *LoadBalancingId + }{ + { + // lower case + input: "/subscriptions/12345678-1234-5678-1234-123456789012/resourceGroups/group1/providers/Microsoft.Network/frontdoors/frontDoor1/loadbalancingsettings/setting1", + expected: nil, + }, + { + // camel case + input: "/subscriptions/12345678-1234-5678-1234-123456789012/resourceGroups/group1/providers/Microsoft.Network/frontDoors/frontDoor1/loadBalancingSettings/setting1", + expected: &LoadBalancingId{ + ResourceGroup: "group1", + FrontDoorName: "frontDoor1", + Name: "setting1", + }, + }, + { + // title case + input: "/subscriptions/12345678-1234-5678-1234-123456789012/resourceGroups/group1/providers/Microsoft.Network/Frontdoors/frontDoor1/LoadBalancingSettings/setting1", + expected: &LoadBalancingId{ + ResourceGroup: "group1", + FrontDoorName: "frontDoor1", + Name: "setting1", + }, + }, + { + // pascal case + input: "/subscriptions/12345678-1234-5678-1234-123456789012/resourceGroups/group1/providers/Microsoft.Network/FrontDoors/frontDoor1/Loadbalancingsettings/setting1", + expected: nil, + }, + } + for _, test := range testData { + t.Logf("Testing %q..", test.input) + actual, err := LoadBalancingID(test.input) + if err != nil && test.expected == nil { + continue + } else if err == nil && test.expected == nil { + t.Fatalf("Expected an error but didn't get one") + } else if err != nil && test.expected != nil { + t.Fatalf("Expected no error but got: %+v", err) + } + + if actual.ResourceGroup != test.expected.ResourceGroup { + t.Fatalf("Expected ResourceGroup to be %q but was %q", test.expected.ResourceGroup, actual.ResourceGroup) + } + + if actual.FrontDoorName != test.expected.FrontDoorName { + t.Fatalf("Expected FrontDoorName to be %q but was %q", test.expected.FrontDoorName, actual.FrontDoorName) + } + + if actual.Name != test.expected.Name { + t.Fatalf("Expected name to be %q but was %q", test.expected.Name, actual.Name) + } + } +} diff --git a/azurerm/internal/services/frontdoor/parse/routing_rule.go b/azurerm/internal/services/frontdoor/parse/routing_rule.go new file mode 100644 index 000000000000..688606a496e8 --- /dev/null +++ b/azurerm/internal/services/frontdoor/parse/routing_rule.go @@ -0,0 +1,48 @@ +package parse + +import "fmt" + +type RoutingRuleId struct { + ResourceGroup string + FrontDoorName string + Name string +} + +func NewRoutingRuleID(id FrontDoorId, name string) RoutingRuleId { + return RoutingRuleId{ + ResourceGroup: id.ResourceGroup, + FrontDoorName: id.Name, + Name: name, + } +} + +func (id RoutingRuleId) ID(subscriptionId string) string { + base := NewFrontDoorID(id.ResourceGroup, id.FrontDoorName).ID(subscriptionId) + return fmt.Sprintf("%s/routingRules/%s", base, id.Name) +} + +func RoutingRuleID(input string) (*RoutingRuleId, error) { + frontDoorId, id, err := parseFrontDoorChildResourceId(input) + if err != nil { + return nil, fmt.Errorf("parsing Routing Rule ID %q: %+v", input, err) + } + + poolId := RoutingRuleId{ + ResourceGroup: frontDoorId.ResourceGroup, + FrontDoorName: frontDoorId.Name, + } + + // API is broken - https://github.com/Azure/azure-sdk-for-go/issues/6762 + // note: the ordering is important since the defined case (we want to error with) is routingRules + if poolId.Name, err = id.PopSegment("RoutingRules"); err != nil { + if poolId.Name, err = id.PopSegment("routingRules"); err != nil { + return nil, err + } + } + + if err := id.ValidateNoEmptySegments(input); err != nil { + return nil, err + } + + return &poolId, nil +} diff --git a/azurerm/internal/services/frontdoor/parse/routing_rule_test.go b/azurerm/internal/services/frontdoor/parse/routing_rule_test.go new file mode 100644 index 000000000000..82ad41441aaa --- /dev/null +++ b/azurerm/internal/services/frontdoor/parse/routing_rule_test.go @@ -0,0 +1,78 @@ +package parse + +import ( + "testing" + + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/resourceid" +) + +var _ resourceid.Formatter = RoutingRuleId{} + +func TestRoutingRuleIDFormatter(t *testing.T) { + subscriptionId := "12345678-1234-5678-1234-123456789012" + frontDoorId := NewFrontDoorID("group1", "frontdoor1") + actual := NewRoutingRuleID(frontDoorId, "rule1").ID(subscriptionId) + expected := "/subscriptions/12345678-1234-5678-1234-123456789012/resourceGroups/group1/providers/Microsoft.Network/frontDoors/frontdoor1/routingRules/rule1" + if actual != expected { + t.Fatalf("Expected %q but got %q", expected, actual) + } +} + +func TestRoutingRuleIDParser(t *testing.T) { + testData := []struct { + input string + expected *RoutingRuleId + }{ + { + // lower case + input: "/subscriptions/12345678-1234-5678-1234-123456789012/resourceGroups/group1/providers/Microsoft.Network/frontdoors/frontDoor1/routingrules/rule1", + expected: nil, + }, + { + // camel case + input: "/subscriptions/12345678-1234-5678-1234-123456789012/resourceGroups/group1/providers/Microsoft.Network/frontDoors/frontDoor1/routingRules/rule1", + expected: &RoutingRuleId{ + ResourceGroup: "group1", + FrontDoorName: "frontDoor1", + Name: "rule1", + }, + }, + { + // title case + input: "/subscriptions/12345678-1234-5678-1234-123456789012/resourceGroups/group1/providers/Microsoft.Network/Frontdoors/frontDoor1/RoutingRules/rule1", + expected: &RoutingRuleId{ + ResourceGroup: "group1", + FrontDoorName: "frontDoor1", + Name: "rule1", + }, + }, + { + // pascal case + input: "/subscriptions/12345678-1234-5678-1234-123456789012/resourceGroups/group1/providers/Microsoft.Network/FrontDoors/frontDoor1/Routingrules/rule1", + expected: nil, + }, + } + for _, test := range testData { + t.Logf("Testing %q..", test.input) + actual, err := RoutingRuleID(test.input) + if err != nil && test.expected == nil { + continue + } else if err == nil && test.expected == nil { + t.Fatalf("Expected an error but didn't get one") + } else if err != nil && test.expected != nil { + t.Fatalf("Expected no error but got: %+v", err) + } + + if actual.ResourceGroup != test.expected.ResourceGroup { + t.Fatalf("Expected ResourceGroup to be %q but was %q", test.expected.ResourceGroup, actual.ResourceGroup) + } + + if actual.FrontDoorName != test.expected.FrontDoorName { + t.Fatalf("Expected FrontDoorName to be %q but was %q", test.expected.FrontDoorName, actual.FrontDoorName) + } + + if actual.Name != test.expected.Name { + t.Fatalf("Expected name to be %q but was %q", test.expected.Name, actual.Name) + } + } +} diff --git a/azurerm/internal/services/frontdoor/parse/web_application_firewall_policy_test.go b/azurerm/internal/services/frontdoor/parse/web_application_firewall_policy_test.go index c3eefcfac047..2eb245b6b565 100644 --- a/azurerm/internal/services/frontdoor/parse/web_application_firewall_policy_test.go +++ b/azurerm/internal/services/frontdoor/parse/web_application_firewall_policy_test.go @@ -1,5 +1,68 @@ package parse -import "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/resourceid" +import ( + "testing" + + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/resourceid" +) var _ resourceid.Formatter = WebApplicationFirewallPolicyId{} + +func TestWebApplicationFirewallPolicyIDFormatter(t *testing.T) { + subscriptionId := "12345678-1234-5678-1234-123456789012" + actual := NewWebApplicationFirewallPolicyID("group1", "policy1").ID(subscriptionId) + expected := "/subscriptions/12345678-1234-5678-1234-123456789012/resourceGroups/group1/providers/Microsoft.Network/frontDoorWebApplicationFirewallPolicies/policy1" + if actual != expected { + t.Fatalf("Expected %q but got %q", expected, actual) + } +} + +func TestWebApplicationFirewallPolicyIDParser(t *testing.T) { + testData := []struct { + input string + expected *WebApplicationFirewallPolicyId + }{ + { + // lower case + input: "/subscriptions/12345678-1234-5678-1234-123456789012/resourceGroups/group1/providers/Microsoft.Network/frontdoorwebapplicationfirewallpolicies/policy1", + expected: nil, + }, + { + // camel case + input: "/subscriptions/12345678-1234-5678-1234-123456789012/resourceGroups/group1/providers/Microsoft.Network/frontDoorWebApplicationFirewallPolicies/policy1", + expected: &WebApplicationFirewallPolicyId{ + ResourceGroup: "group1", + Name: "policy1", + }, + }, + { + // title case + input: "/subscriptions/12345678-1234-5678-1234-123456789012/resourceGroups/group1/providers/Microsoft.Network/FrontDoorWebApplicationFirewallPolicies/policy1", + expected: nil, + }, + { + // pascal case + input: "/subscriptions/12345678-1234-5678-1234-123456789012/resourceGroups/group1/providers/Microsoft.Network/Frontdoorwebapplicationfirewallpolicies/policy1", + expected: nil, + }, + } + for _, test := range testData { + t.Logf("Testing %q..", test.input) + actual, err := WebApplicationFirewallPolicyID(test.input) + if err != nil && test.expected == nil { + continue + } else if err == nil && test.expected == nil { + t.Fatalf("Expected an error but didn't get one") + } else if err != nil && test.expected != nil { + t.Fatalf("Expected no error but got: %+v", err) + } + + if actual.ResourceGroup != test.expected.ResourceGroup { + t.Fatalf("Expected ResourceGroup to be %q but was %q", test.expected.ResourceGroup, actual.ResourceGroup) + } + + if actual.Name != test.expected.Name { + t.Fatalf("Expected name to be %q but was %q", test.expected.Name, actual.Name) + } + } +} From 771075e4339245ad87607a75db3c550db2e54a40 Mon Sep 17 00:00:00 2001 From: tombuildsstuff Date: Mon, 17 Aug 2020 12:40:33 +0200 Subject: [PATCH 34/41] r/frontdoor_custom_https_configuration: validating the ID is the correct case at import time --- ...oor_custom_https_configuration_resource.go | 2 +- .../frontdoor/parse/frontend_endpoint.go | 25 ++++++++- .../frontdoor/parse/frontend_endpoint_test.go | 55 +++++++++++++++++++ 3 files changed, 78 insertions(+), 4 deletions(-) diff --git a/azurerm/internal/services/frontdoor/frontdoor_custom_https_configuration_resource.go b/azurerm/internal/services/frontdoor/frontdoor_custom_https_configuration_resource.go index e56caf3edcb2..4e2cdb8d6896 100644 --- a/azurerm/internal/services/frontdoor/frontdoor_custom_https_configuration_resource.go +++ b/azurerm/internal/services/frontdoor/frontdoor_custom_https_configuration_resource.go @@ -27,7 +27,7 @@ func resourceArmFrontDoorCustomHttpsConfiguration() *schema.Resource { Delete: resourceArmFrontDoorCustomHttpsConfigurationDelete, Importer: azSchema.ValidateResourceIDPriorToImport(func(id string) error { - _, err := parse.FrontendEndpointID(id) + _, err := parse.FrontendEndpointIDForImport(id) return err }), diff --git a/azurerm/internal/services/frontdoor/parse/frontend_endpoint.go b/azurerm/internal/services/frontdoor/parse/frontend_endpoint.go index 0c893fefaf38..74c04f61b9c1 100644 --- a/azurerm/internal/services/frontdoor/parse/frontend_endpoint.go +++ b/azurerm/internal/services/frontdoor/parse/frontend_endpoint.go @@ -22,6 +22,14 @@ func (id FrontendEndpointId) ID(subscriptionId string) string { } func FrontendEndpointID(input string) (*FrontendEndpointId, error) { + return parseFrontendEndpointID(input, false) +} + +func FrontendEndpointIDForImport(input string) (*FrontendEndpointId, error) { + return parseFrontendEndpointID(input, true) +} + +func parseFrontendEndpointID(input string, caseSensitive bool) (*FrontendEndpointId, error) { frontDoorId, id, err := parseFrontDoorChildResourceId(input) if err != nil { return nil, fmt.Errorf("parsing Frontend Endpoint ID %q: %+v", input, err) @@ -32,12 +40,23 @@ func FrontendEndpointID(input string) (*FrontendEndpointId, error) { FrontDoorName: frontDoorId.Name, } - // https://github.com/Azure/azure-sdk-for-go/issues/6762 - // note: the ordering is important since the defined case (we want to error with) is frontendEndpoints - if endpointId.Name, err = id.PopSegment("FrontendEndpoints"); err != nil { + // The Azure API (per the ARM Spec/chatting with the ARM Team) should be following Postel's Law; + // where ID's are insensitive for Requests but sensitive in responses - but it's not. + // + // For us this means ID's should be sensitive at import time - but we have to work around these + // API bugs for the moment. + if caseSensitive { if endpointId.Name, err = id.PopSegment("frontendEndpoints"); err != nil { return nil, err } + } else { + // https://github.com/Azure/azure-sdk-for-go/issues/6762 + // note: the ordering is important since the defined case (we want to error with) is frontendEndpoints + if endpointId.Name, err = id.PopSegment("FrontendEndpoints"); err != nil { + if endpointId.Name, err = id.PopSegment("frontendEndpoints"); err != nil { + return nil, err + } + } } if err := id.ValidateNoEmptySegments(input); err != nil { diff --git a/azurerm/internal/services/frontdoor/parse/frontend_endpoint_test.go b/azurerm/internal/services/frontdoor/parse/frontend_endpoint_test.go index d8f849d54a29..88f2a8fd0a00 100644 --- a/azurerm/internal/services/frontdoor/parse/frontend_endpoint_test.go +++ b/azurerm/internal/services/frontdoor/parse/frontend_endpoint_test.go @@ -76,3 +76,58 @@ func TestFrontendEndpointIDParser(t *testing.T) { } } } + +func TestFrontendEndpointIDForImportParser(t *testing.T) { + testData := []struct { + input string + expected *FrontendEndpointId + }{ + { + // lower case + input: "/subscriptions/12345678-1234-5678-1234-123456789012/resourceGroups/group1/providers/Microsoft.Network/frontdoors/frontDoor1/frontendendpoints/endpoint1", + expected: nil, + }, + { + // camel case + input: "/subscriptions/12345678-1234-5678-1234-123456789012/resourceGroups/group1/providers/Microsoft.Network/frontDoors/frontDoor1/frontendEndpoints/endpoint1", + expected: &FrontendEndpointId{ + ResourceGroup: "group1", + FrontDoorName: "frontDoor1", + Name: "endpoint1", + }, + }, + { + // title case + input: "/subscriptions/12345678-1234-5678-1234-123456789012/resourceGroups/group1/providers/Microsoft.Network/Frontdoors/frontDoor1/FrontendEndpoints/endpoint1", + expected: nil, + }, + { + // pascal case + input: "/subscriptions/12345678-1234-5678-1234-123456789012/resourceGroups/group1/providers/Microsoft.Network/FrontDoors/frontDoor1/Frontendendpoints/endpoint1", + expected: nil, + }, + } + for _, test := range testData { + t.Logf("Testing %q..", test.input) + actual, err := FrontendEndpointIDForImport(test.input) + if err != nil && test.expected == nil { + continue + } else if err == nil && test.expected == nil { + t.Fatalf("Expected an error but didn't get one") + } else if err != nil && test.expected != nil { + t.Fatalf("Expected no error but got: %+v", err) + } + + if actual.ResourceGroup != test.expected.ResourceGroup { + t.Fatalf("Expected ResourceGroup to be %q but was %q", test.expected.ResourceGroup, actual.ResourceGroup) + } + + if actual.FrontDoorName != test.expected.FrontDoorName { + t.Fatalf("Expected FrontDoorName to be %q but was %q", test.expected.FrontDoorName, actual.FrontDoorName) + } + + if actual.Name != test.expected.Name { + t.Fatalf("Expected name to be %q but was %q", test.expected.Name, actual.Name) + } + } +} From 17b425829f5f0ebd2930a8e68dd7af423ebdb5ec Mon Sep 17 00:00:00 2001 From: tombuildsstuff Date: Mon, 17 Aug 2020 12:43:42 +0200 Subject: [PATCH 35/41] r/frontdoor: ensuring the ID is consistent at import time --- .../services/frontdoor/frontdoor_resource.go | 2 +- .../services/frontdoor/parse/frontdoor.go | 21 ++++++++ .../frontdoor/parse/frontdoor_test.go | 50 +++++++++++++++++++ 3 files changed, 72 insertions(+), 1 deletion(-) diff --git a/azurerm/internal/services/frontdoor/frontdoor_resource.go b/azurerm/internal/services/frontdoor/frontdoor_resource.go index 36b81b081153..e3ceff3e27ab 100644 --- a/azurerm/internal/services/frontdoor/frontdoor_resource.go +++ b/azurerm/internal/services/frontdoor/frontdoor_resource.go @@ -32,7 +32,7 @@ func resourceArmFrontDoor() *schema.Resource { Delete: resourceArmFrontDoorDelete, Importer: azSchema.ValidateResourceIDPriorToImport(func(id string) error { - _, err := parse.FrontDoorID(id) + _, err := parse.FrontDoorIDForImport(id) return err }), diff --git a/azurerm/internal/services/frontdoor/parse/frontdoor.go b/azurerm/internal/services/frontdoor/parse/frontdoor.go index 93ecd692620a..185e21f9be38 100644 --- a/azurerm/internal/services/frontdoor/parse/frontdoor.go +++ b/azurerm/internal/services/frontdoor/parse/frontdoor.go @@ -32,6 +32,27 @@ func FrontDoorID(input string) (*FrontDoorId, error) { return frontDoorId, nil } +func FrontDoorIDForImport(input string) (*FrontDoorId, error) { + id, err := azure.ParseAzureResourceID(input) + if err != nil { + return nil, fmt.Errorf("[ERROR] Unable to parse FrontDoor ID %q: %+v", input, err) + } + + frontDoorId := FrontDoorId{ + ResourceGroup: id.ResourceGroup, + } + + if frontDoorId.Name, err = id.PopSegment("frontDoors"); err != nil { + return nil, err + } + + if err := id.ValidateNoEmptySegments(input); err != nil { + return nil, err + } + + return &frontDoorId, nil +} + func (id FrontDoorId) ID(subscriptionId string) string { return fmt.Sprintf("/subscriptions/%s/resourceGroups/%s/providers/Microsoft.Network/frontDoors/%s", subscriptionId, id.ResourceGroup, id.Name) } diff --git a/azurerm/internal/services/frontdoor/parse/frontdoor_test.go b/azurerm/internal/services/frontdoor/parse/frontdoor_test.go index a48f41aef592..e007e1179489 100644 --- a/azurerm/internal/services/frontdoor/parse/frontdoor_test.go +++ b/azurerm/internal/services/frontdoor/parse/frontdoor_test.go @@ -75,3 +75,53 @@ func TestFrontDoorIDParser(t *testing.T) { } } } + +func TestFrontDoorIDForImportParser(t *testing.T) { + testData := []struct { + input string + expected *FrontDoorId + }{ + { + // lower case + input: "/subscriptions/12345678-1234-5678-1234-123456789012/resourceGroups/group1/providers/Microsoft.Network/frontdoors/frontDoor1", + expected: nil, + }, + { + // camel case + input: "/subscriptions/12345678-1234-5678-1234-123456789012/resourceGroups/group1/providers/Microsoft.Network/frontDoors/frontDoor1", + expected: &FrontDoorId{ + ResourceGroup: "group1", + Name: "frontDoor1", + }, + }, + { + // title case + input: "/subscriptions/12345678-1234-5678-1234-123456789012/resourceGroups/group1/providers/Microsoft.Network/Frontdoors/frontDoor1", + expected: nil, + }, + { + // pascal case + input: "/subscriptions/12345678-1234-5678-1234-123456789012/resourceGroups/group1/providers/Microsoft.Network/FrontDoors/frontDoor1", + expected: nil, + }, + } + for _, test := range testData { + t.Logf("Testing %q..", test.input) + actual, err := FrontDoorIDForImport(test.input) + if err != nil && test.expected == nil { + continue + } else if err == nil && test.expected == nil { + t.Fatalf("Expected an error but didn't get one") + } else if err != nil && test.expected != nil { + t.Fatalf("Expected no error but got: %+v", err) + } + + if actual.ResourceGroup != test.expected.ResourceGroup { + t.Fatalf("Expected ResourceGroup to be %q but was %q", test.expected.ResourceGroup, actual.ResourceGroup) + } + + if actual.Name != test.expected.Name { + t.Fatalf("Expected name to be %q but was %q", test.expected.Name, actual.Name) + } + } +} From 308f1843be346d46ca96435dcae904e84b933a10 Mon Sep 17 00:00:00 2001 From: tombuildsstuff Date: Mon, 17 Aug 2020 13:00:40 +0200 Subject: [PATCH 36/41] typo --- azurerm/helpers/azure/resource_group.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/azurerm/helpers/azure/resource_group.go b/azurerm/helpers/azure/resource_group.go index 1d0feb59b670..5faa73643c8c 100644 --- a/azurerm/helpers/azure/resource_group.go +++ b/azurerm/helpers/azure/resource_group.go @@ -23,7 +23,7 @@ func SchemaResourceGroupNameDeprecated() *schema.Schema { Type: schema.TypeString, Optional: true, ValidateFunc: validateResourceGroupName, - Deprecated: "This field is no longer used and will be removed in the next major verrsion of the Azure Provider", + Deprecated: "This field is no longer used and will be removed in the next major version of the Azure Provider", } } From 33e3b80997e99b47a123a2e60a08c86a3921ec4d Mon Sep 17 00:00:00 2001 From: tombuildsstuff Date: Mon, 17 Aug 2020 14:30:35 +0200 Subject: [PATCH 37/41] r/frontdoor_https_configuration: ensuring the Frontend Endpoint ID is consistent --- ...oor_custom_https_configuration_resource.go | 7 +++--- .../validate/frontend_endpoint_id.go | 22 +++++++++++++++++++ .../services/frontdoor/validate/validate.go | 2 +- 3 files changed, 27 insertions(+), 4 deletions(-) create mode 100644 azurerm/internal/services/frontdoor/validate/frontend_endpoint_id.go diff --git a/azurerm/internal/services/frontdoor/frontdoor_custom_https_configuration_resource.go b/azurerm/internal/services/frontdoor/frontdoor_custom_https_configuration_resource.go index 4e2cdb8d6896..3c0f2eff8d49 100644 --- a/azurerm/internal/services/frontdoor/frontdoor_custom_https_configuration_resource.go +++ b/azurerm/internal/services/frontdoor/frontdoor_custom_https_configuration_resource.go @@ -43,7 +43,7 @@ func resourceArmFrontDoorCustomHttpsConfiguration() *schema.Resource { Type: schema.TypeString, Required: true, ForceNew: true, - ValidateFunc: azure.ValidateResourceID, + ValidateFunc: validate.FrontendEndpointID, }, "custom_https_provisioning_enabled": { @@ -66,7 +66,7 @@ func resourceArmFrontDoorCustomHttpsConfiguration() *schema.Resource { CustomizeDiff: func(d *schema.ResourceDiff, v interface{}) error { if v, ok := d.GetOk("frontend_endpoint_id"); ok && v.(string) != "" { - id, err := parse.FrontendEndpointID(v.(string)) + id, err := parse.FrontendEndpointIDForImport(v.(string)) if err != nil { return err } @@ -134,6 +134,7 @@ func resourceArmFrontDoorCustomHttpsConfigurationCreateUpdate(d *schema.Resource func resourceArmFrontDoorCustomHttpsConfigurationRead(d *schema.ResourceData, meta interface{}) error { client := meta.(*clients.Client).Frontdoor.FrontDoorsFrontendClient + subscriptionId := meta.(*clients.Client).Account.SubscriptionId ctx, cancel := timeouts.ForRead(meta.(*clients.Client).StopContext, d) defer cancel() @@ -153,7 +154,7 @@ func resourceArmFrontDoorCustomHttpsConfigurationRead(d *schema.ResourceData, me return fmt.Errorf("reading Front Door Endpoint %q (Resource Group %q): %+v", id.Name, id.ResourceGroup, err) } - d.Set("frontend_endpoint_id", resp.ID) + d.Set("frontend_endpoint_id", id.ID(subscriptionId)) flattenedHttpsConfig := flattenCustomHttpsConfiguration(resp.FrontendEndpointProperties) if err := d.Set("custom_https_configuration", flattenedHttpsConfig.CustomHTTPSConfiguration); err != nil { diff --git a/azurerm/internal/services/frontdoor/validate/frontend_endpoint_id.go b/azurerm/internal/services/frontdoor/validate/frontend_endpoint_id.go new file mode 100644 index 000000000000..819c8929877b --- /dev/null +++ b/azurerm/internal/services/frontdoor/validate/frontend_endpoint_id.go @@ -0,0 +1,22 @@ +package validate + +import ( + "fmt" + + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/services/frontdoor/parse" +) + +func FrontendEndpointID(i interface{}, k string) (warnings []string, errors []error) { + v, ok := i.(string) + if !ok { + errors = append(errors, fmt.Errorf("expected type of %q to be string", k)) + return + } + + if _, err := parse.FrontendEndpointIDForImport(v); err != nil { + errors = append(errors, fmt.Errorf("Can not parse %q as a resource id: %v", k, err)) + return + } + + return warnings, errors +} diff --git a/azurerm/internal/services/frontdoor/validate/validate.go b/azurerm/internal/services/frontdoor/validate/validate.go index 4a0b1e00c2ae..394f760401d6 100644 --- a/azurerm/internal/services/frontdoor/validate/validate.go +++ b/azurerm/internal/services/frontdoor/validate/validate.go @@ -93,7 +93,7 @@ func FrontdoorCustomHttpsSettings(d *schema.ResourceDiff) error { // Verify frontend endpoints custom https configuration is valid if defined if err := verifyCustomHttpsConfiguration(frontendEndpointCustomHttpsConfig, frontendId); err != nil { - return fmt.Errorf(`%+v`, err) + return err } } else if customHttpsEnabled { return fmt.Errorf(`"frontend_endpoint":%q "custom_https_configuration" is invalid because "custom_https_provisioning_enabled" is set to "true". please add a "custom_https_configuration" block to the configuration file`, frontendId) From 8762d5f15bdb9bb6d5b5a92bf1a42e9ac40fab7e Mon Sep 17 00:00:00 2001 From: tombuildsstuff Date: Mon, 17 Aug 2020 14:35:33 +0200 Subject: [PATCH 38/41] frontdoor: moving the customizeDiff out --- .../services/frontdoor/customizediff.go | 229 ++++++++++++++++++ ...oor_custom_https_configuration_resource.go | 15 +- .../services/frontdoor/frontdoor_resource.go | 8 +- .../services/frontdoor/validate/validate.go | 200 --------------- 4 files changed, 231 insertions(+), 221 deletions(-) create mode 100644 azurerm/internal/services/frontdoor/customizediff.go diff --git a/azurerm/internal/services/frontdoor/customizediff.go b/azurerm/internal/services/frontdoor/customizediff.go new file mode 100644 index 000000000000..a78181b6d8d2 --- /dev/null +++ b/azurerm/internal/services/frontdoor/customizediff.go @@ -0,0 +1,229 @@ +package frontdoor + +import ( + "fmt" + "strings" + + "github.com/Azure/azure-sdk-for-go/services/frontdoor/mgmt/2020-01-01/frontdoor" + "github.com/hashicorp/terraform-plugin-sdk/helper/schema" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/services/frontdoor/parse" +) + +func customizeHttpsConfigurationCustomizeDiff(d *schema.ResourceDiff, v interface{}) error { + if v, ok := d.GetOk("frontend_endpoint_id"); ok && v.(string) != "" { + id, err := parse.FrontendEndpointIDForImport(v.(string)) + if err != nil { + return err + } + + if err := customHttpsSettings(d); err != nil { + return fmt.Errorf("validating Front Door Custom Https Configuration for Endpoint %q (Front Door %q / Resource Group %q): %+v", id.Name, id.FrontDoorName, id.ResourceGroup, err) + } + } + + return nil +} + +func customHttpsSettings(d *schema.ResourceDiff) error { + frontendId := d.Get("frontend_endpoint_id").(string) + frontendEndpointCustomHttpsConfig := d.Get("custom_https_configuration").([]interface{}) + customHttpsEnabled := d.Get("custom_https_provisioning_enabled").(bool) + + if len(frontendEndpointCustomHttpsConfig) > 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`, frontendId) + } + + // Verify frontend endpoints custom https configuration is valid if defined + if err := verifyCustomHttpsConfiguration(frontendEndpointCustomHttpsConfig, frontendId); err != nil { + return err + } + } else if customHttpsEnabled { + return fmt.Errorf(`"frontend_endpoint":%q "custom_https_configuration" is invalid because "custom_https_provisioning_enabled" is set to "true". please add a "custom_https_configuration" block to the configuration file`, frontendId) + } + + return nil +} + +func verifyCustomHttpsConfiguration(frontendEndpointCustomHttpsConfig []interface{}, frontendId string) error { + if len(frontendEndpointCustomHttpsConfig) > 0 { + customHttpsConfiguration := frontendEndpointCustomHttpsConfig[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"`, frontendId) + } + } 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"`, frontendId) + } + } + + 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 +} + +func frontDoorCustomizeDiff(d *schema.ResourceDiff, v interface{}) error { + if err := frontDoorSettings(d); err != nil { + return fmt.Errorf("validating Front Door %q (Resource Group %q): %+v", d.Get("name").(string), d.Get("resource_group_name").(string), err) + } + + return nil +} + +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) + } + + 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 +} diff --git a/azurerm/internal/services/frontdoor/frontdoor_custom_https_configuration_resource.go b/azurerm/internal/services/frontdoor/frontdoor_custom_https_configuration_resource.go index 3c0f2eff8d49..7fbba48bf4c5 100644 --- a/azurerm/internal/services/frontdoor/frontdoor_custom_https_configuration_resource.go +++ b/azurerm/internal/services/frontdoor/frontdoor_custom_https_configuration_resource.go @@ -64,20 +64,7 @@ func resourceArmFrontDoorCustomHttpsConfiguration() *schema.Resource { "resource_group_name": azure.SchemaResourceGroupNameDeprecated(), }, - CustomizeDiff: func(d *schema.ResourceDiff, v interface{}) error { - if v, ok := d.GetOk("frontend_endpoint_id"); ok && v.(string) != "" { - id, err := parse.FrontendEndpointIDForImport(v.(string)) - if err != nil { - return err - } - - if err := validate.FrontdoorCustomHttpsSettings(d); err != nil { - return fmt.Errorf("validating Front Door Custom Https Configuration for Endpoint %q (Front Door %q / Resource Group %q): %+v", id.Name, id.FrontDoorName, id.ResourceGroup, err) - } - } - - return nil - }, + CustomizeDiff: customizeHttpsConfigurationCustomizeDiff, SchemaVersion: 1, StateUpgraders: []schema.StateUpgrader{ diff --git a/azurerm/internal/services/frontdoor/frontdoor_resource.go b/azurerm/internal/services/frontdoor/frontdoor_resource.go index e3ceff3e27ab..99cd3dd25e8d 100644 --- a/azurerm/internal/services/frontdoor/frontdoor_resource.go +++ b/azurerm/internal/services/frontdoor/frontdoor_resource.go @@ -472,13 +472,7 @@ func resourceArmFrontDoor() *schema.Resource { "tags": tags.Schema(), }, - CustomizeDiff: func(d *schema.ResourceDiff, v interface{}) error { - 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 - }, + CustomizeDiff: frontDoorCustomizeDiff, } } diff --git a/azurerm/internal/services/frontdoor/validate/validate.go b/azurerm/internal/services/frontdoor/validate/validate.go index 394f760401d6..4e0641441230 100644 --- a/azurerm/internal/services/frontdoor/validate/validate.go +++ b/azurerm/internal/services/frontdoor/validate/validate.go @@ -2,10 +2,7 @@ package validate import ( "fmt" - "strings" - "github.com/Azure/azure-sdk-for-go/services/frontdoor/mgmt/2020-01-01/frontdoor" - "github.com/hashicorp/terraform-plugin-sdk/helper/schema" "github.com/terraform-providers/terraform-provider-azurerm/azurerm/helpers/validate" ) @@ -24,200 +21,3 @@ func FrontdoorCustomBlockResponseBody(i interface{}, k string) (_ []string, erro return nil, nil } - -func FrontdoorSettings(d *schema.ResourceDiff) error { - // TODO: move this out of here - this package should only be taking parsed objects - 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) - } - - return nil -} - -func FrontdoorCustomHttpsSettings(d *schema.ResourceDiff) error { - frontendId := d.Get("frontend_endpoint_id").(string) - frontendEndpointCustomHttpsConfig := d.Get("custom_https_configuration").([]interface{}) - customHttpsEnabled := d.Get("custom_https_provisioning_enabled").(bool) - - if len(frontendEndpointCustomHttpsConfig) > 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`, frontendId) - } - - // Verify frontend endpoints custom https configuration is valid if defined - if err := verifyCustomHttpsConfiguration(frontendEndpointCustomHttpsConfig, frontendId); err != nil { - return err - } - } else if customHttpsEnabled { - return fmt.Errorf(`"frontend_endpoint":%q "custom_https_configuration" is invalid because "custom_https_provisioning_enabled" is set to "true". please add a "custom_https_configuration" block to the configuration file`, frontendId) - } - - 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(frontendEndpointCustomHttpsConfig []interface{}, frontendId string) error { - if len(frontendEndpointCustomHttpsConfig) > 0 { - customHttpsConfiguration := frontendEndpointCustomHttpsConfig[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"`, frontendId) - } - } 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"`, frontendId) - } - } - - 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 -} From 36c723832a97298546231145b520e1fe3f2afe7e Mon Sep 17 00:00:00 2001 From: tombuildsstuff Date: Mon, 17 Aug 2020 15:22:59 +0200 Subject: [PATCH 39/41] fixing the assertion --- ..._custom_https_configuration_resource_test.go | 17 ++++------------- 1 file changed, 4 insertions(+), 13 deletions(-) diff --git a/azurerm/internal/services/frontdoor/tests/frontdoor_custom_https_configuration_resource_test.go b/azurerm/internal/services/frontdoor/tests/frontdoor_custom_https_configuration_resource_test.go index e8dbd654d79e..d9f6a99ab324 100644 --- a/azurerm/internal/services/frontdoor/tests/frontdoor_custom_https_configuration_resource_test.go +++ b/azurerm/internal/services/frontdoor/tests/frontdoor_custom_https_configuration_resource_test.go @@ -6,9 +6,9 @@ import ( "github.com/hashicorp/terraform-plugin-sdk/helper/resource" "github.com/hashicorp/terraform-plugin-sdk/terraform" - "github.com/terraform-providers/terraform-provider-azurerm/azurerm/helpers/azure" "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/services/frontdoor/parse" "github.com/terraform-providers/terraform-provider-azurerm/azurerm/utils" ) @@ -49,24 +49,15 @@ func testCheckAzureRMFrontDoorCustomHttpsConfigurationExists(resourceName string } resourceGroup := rs.Primary.Attributes["resource_group_name"] - id, err := azure.ParseAzureResourceID(rs.Primary.Attributes["frontend_endpoint_id"]) + id, err := parse.FrontendEndpointID(rs.Primary.Attributes["frontend_endpoint_id"]) if err != nil { return fmt.Errorf("Bad: cannot parse frontend_endpoint_id for %q", resourceName) } - frontDoorName := id.Path["frontdoors"] - // Link to issue: https://github.com/Azure/azure-sdk-for-go/issues/6762 - if frontDoorName == "" { - frontDoorName = id.Path["Frontdoors"] - } - frontendEndpointName := id.Path["frontendendpoints"] - if frontendEndpointName == "" { - frontDoorName = id.Path["FrontendEndpoints"] - } - resp, err := client.Get(ctx, resourceGroup, frontDoorName, frontendEndpointName) + resp, err := client.Get(ctx, resourceGroup, id.FrontDoorName, id.Name) if err != nil { if utils.ResponseWasNotFound(resp.Response) { - return fmt.Errorf("Bad: Front Door (%q) Frontend Endpoint %q (Resource Group %q) does not exist", frontDoorName, frontendEndpointName, resourceGroup) + return fmt.Errorf("Bad: Frontend Endpoint %q (Front Door %q / Resource Group %q) does not exist", id.Name, id.FrontDoorName, resourceGroup) } return fmt.Errorf("Bad: Get on FrontDoorsFrontendClient: %+v", err) } From 2177727d639a697f87e147f810167b296f3bf098 Mon Sep 17 00:00:00 2001 From: tombuildsstuff Date: Tue, 18 Aug 2020 19:59:37 +0200 Subject: [PATCH 40/41] pr comments --- .../services/frontdoor/frontdoor_firewall_policy_resource.go | 2 -- azurerm/internal/services/frontdoor/parse/frontdoor.go | 4 ++-- azurerm/internal/services/frontdoor/validate/name_test.go | 2 +- 3 files changed, 3 insertions(+), 5 deletions(-) diff --git a/azurerm/internal/services/frontdoor/frontdoor_firewall_policy_resource.go b/azurerm/internal/services/frontdoor/frontdoor_firewall_policy_resource.go index c48856fb3607..a73b62294f6d 100644 --- a/azurerm/internal/services/frontdoor/frontdoor_firewall_policy_resource.go +++ b/azurerm/internal/services/frontdoor/frontdoor_firewall_policy_resource.go @@ -22,8 +22,6 @@ import ( "github.com/terraform-providers/terraform-provider-azurerm/azurerm/utils" ) -// TODO: a state migration to patch the ID's - func resourceArmFrontDoorFirewallPolicy() *schema.Resource { return &schema.Resource{ Create: resourceArmFrontDoorFirewallPolicyCreateUpdate, diff --git a/azurerm/internal/services/frontdoor/parse/frontdoor.go b/azurerm/internal/services/frontdoor/parse/frontdoor.go index 185e21f9be38..9172078ff58c 100644 --- a/azurerm/internal/services/frontdoor/parse/frontdoor.go +++ b/azurerm/internal/services/frontdoor/parse/frontdoor.go @@ -22,7 +22,7 @@ func NewFrontDoorID(resourceGroup, name string) FrontDoorId { func FrontDoorID(input string) (*FrontDoorId, error) { frontDoorId, id, err := parseFrontDoorChildResourceId(input) if err != nil { - return nil, fmt.Errorf("[ERROR] Unable to parse FrontDoor ID %q: %+v", input, err) + return nil, fmt.Errorf("parsing FrontDoor ID %q: %+v", input, err) } if err := id.ValidateNoEmptySegments(input); err != nil { @@ -35,7 +35,7 @@ func FrontDoorID(input string) (*FrontDoorId, error) { func FrontDoorIDForImport(input string) (*FrontDoorId, error) { id, err := azure.ParseAzureResourceID(input) if err != nil { - return nil, fmt.Errorf("[ERROR] Unable to parse FrontDoor ID %q: %+v", input, err) + return nil, fmt.Errorf("parsing FrontDoor ID %q: %+v", input, err) } frontDoorId := FrontDoorId{ diff --git a/azurerm/internal/services/frontdoor/validate/name_test.go b/azurerm/internal/services/frontdoor/validate/name_test.go index 3bc09001a655..481a747c86f6 100644 --- a/azurerm/internal/services/frontdoor/validate/name_test.go +++ b/azurerm/internal/services/frontdoor/validate/name_test.go @@ -16,7 +16,7 @@ func TestAccAzureRMFrontDoorFirewallPolicy_validateName(t *testing.T) { ExpectError: true, }, { - Name: "Starst with Numeric", + Name: "Starts with Numeric", Input: "1WellThisIsAllWrong", ExpectError: true, }, From 75223f44941fff60e958cf39807e35adade5e161 Mon Sep 17 00:00:00 2001 From: tombuildsstuff Date: Tue, 18 Aug 2020 20:02:12 +0200 Subject: [PATCH 41/41] linting --- .../custom_https_configuration_test.go | 10 ++++++---- .../frontdoor/migration/frontdoor_test.go | 10 ++++++---- .../web_application_firewall_policy_test.go | 10 ++++++---- .../frontdoor/parse/backend_pool_test.go | 10 ++++++---- .../frontdoor/parse/frontdoor_test.go | 20 +++++++++++-------- .../frontdoor/parse/frontend_endpoint_test.go | 20 +++++++++++-------- .../frontdoor/parse/health_probe_test.go | 10 ++++++---- .../frontdoor/parse/load_balancing_test.go | 10 ++++++---- .../frontdoor/parse/routing_rule_test.go | 10 ++++++---- .../web_application_firewall_policy_test.go | 10 ++++++---- 10 files changed, 72 insertions(+), 48 deletions(-) diff --git a/azurerm/internal/services/frontdoor/migration/custom_https_configuration_test.go b/azurerm/internal/services/frontdoor/migration/custom_https_configuration_test.go index 3869cd283e5f..f1c28a5dd596 100644 --- a/azurerm/internal/services/frontdoor/migration/custom_https_configuration_test.go +++ b/azurerm/internal/services/frontdoor/migration/custom_https_configuration_test.go @@ -46,10 +46,12 @@ func TestCustomHttpsConfigurationV0ToV1(t *testing.T) { result, err := CustomHttpsConfigurationV0ToV1(test.input, nil) if err != nil && test.expected == nil { continue - } else if err == nil && test.expected == nil { - t.Fatalf("Expected an error but didn't get one") - } else if err != nil && test.expected != nil { - t.Fatalf("Expected no error but got: %+v", err) + } else { + if err == nil && test.expected == nil { + t.Fatalf("Expected an error but didn't get one") + } else if err != nil && test.expected != nil { + t.Fatalf("Expected no error but got: %+v", err) + } } actualId := result["id"].(string) diff --git a/azurerm/internal/services/frontdoor/migration/frontdoor_test.go b/azurerm/internal/services/frontdoor/migration/frontdoor_test.go index 17a6242a0c16..de4bdd502206 100644 --- a/azurerm/internal/services/frontdoor/migration/frontdoor_test.go +++ b/azurerm/internal/services/frontdoor/migration/frontdoor_test.go @@ -53,10 +53,12 @@ func TestFrontDoorV1ToV2(t *testing.T) { result, err := FrontDoorV1ToV2(test.input, nil) if err != nil && test.expected == nil { continue - } else if err == nil && test.expected == nil { - t.Fatalf("Expected an error but didn't get one") - } else if err != nil && test.expected != nil { - t.Fatalf("Expected no error but got: %+v", err) + } else { + if err == nil && test.expected == nil { + t.Fatalf("Expected an error but didn't get one") + } else if err != nil && test.expected != nil { + t.Fatalf("Expected no error but got: %+v", err) + } } actualId := result["id"].(string) diff --git a/azurerm/internal/services/frontdoor/migration/web_application_firewall_policy_test.go b/azurerm/internal/services/frontdoor/migration/web_application_firewall_policy_test.go index a71fa7fd4853..b632e3a082f9 100644 --- a/azurerm/internal/services/frontdoor/migration/web_application_firewall_policy_test.go +++ b/azurerm/internal/services/frontdoor/migration/web_application_firewall_policy_test.go @@ -46,10 +46,12 @@ func TestWebApplicationFirewallPolicyV0ToV1(t *testing.T) { result, err := WebApplicationFirewallPolicyV0ToV1(test.input, nil) if err != nil && test.expected == nil { continue - } else if err == nil && test.expected == nil { - t.Fatalf("Expected an error but didn't get one") - } else if err != nil && test.expected != nil { - t.Fatalf("Expected no error but got: %+v", err) + } else { + if err == nil && test.expected == nil { + t.Fatalf("Expected an error but didn't get one") + } else if err != nil && test.expected != nil { + t.Fatalf("Expected no error but got: %+v", err) + } } actualId := result["id"].(string) diff --git a/azurerm/internal/services/frontdoor/parse/backend_pool_test.go b/azurerm/internal/services/frontdoor/parse/backend_pool_test.go index 6d7a28458cb9..6e4ee710d2d9 100644 --- a/azurerm/internal/services/frontdoor/parse/backend_pool_test.go +++ b/azurerm/internal/services/frontdoor/parse/backend_pool_test.go @@ -61,10 +61,12 @@ func TestBackendPoolIDParser(t *testing.T) { actual, err := BackendPoolID(test.input) if err != nil && test.expected == nil { continue - } else if err == nil && test.expected == nil { - t.Fatalf("Expected an error but didn't get one") - } else if err != nil && test.expected != nil { - t.Fatalf("Expected no error but got: %+v", err) + } else { + if err == nil && test.expected == nil { + t.Fatalf("Expected an error but didn't get one") + } else if err != nil && test.expected != nil { + t.Fatalf("Expected no error but got: %+v", err) + } } if actual.ResourceGroup != test.expected.ResourceGroup { diff --git a/azurerm/internal/services/frontdoor/parse/frontdoor_test.go b/azurerm/internal/services/frontdoor/parse/frontdoor_test.go index e007e1179489..3cc2cadcbb4e 100644 --- a/azurerm/internal/services/frontdoor/parse/frontdoor_test.go +++ b/azurerm/internal/services/frontdoor/parse/frontdoor_test.go @@ -60,10 +60,12 @@ func TestFrontDoorIDParser(t *testing.T) { actual, err := FrontDoorID(test.input) if err != nil && test.expected == nil { continue - } else if err == nil && test.expected == nil { - t.Fatalf("Expected an error but didn't get one") - } else if err != nil && test.expected != nil { - t.Fatalf("Expected no error but got: %+v", err) + } else { + if err == nil && test.expected == nil { + t.Fatalf("Expected an error but didn't get one") + } else if err != nil && test.expected != nil { + t.Fatalf("Expected no error but got: %+v", err) + } } if actual.ResourceGroup != test.expected.ResourceGroup { @@ -110,10 +112,12 @@ func TestFrontDoorIDForImportParser(t *testing.T) { actual, err := FrontDoorIDForImport(test.input) if err != nil && test.expected == nil { continue - } else if err == nil && test.expected == nil { - t.Fatalf("Expected an error but didn't get one") - } else if err != nil && test.expected != nil { - t.Fatalf("Expected no error but got: %+v", err) + } else { + if err == nil && test.expected == nil { + t.Fatalf("Expected an error but didn't get one") + } else if err != nil && test.expected != nil { + t.Fatalf("Expected no error but got: %+v", err) + } } if actual.ResourceGroup != test.expected.ResourceGroup { diff --git a/azurerm/internal/services/frontdoor/parse/frontend_endpoint_test.go b/azurerm/internal/services/frontdoor/parse/frontend_endpoint_test.go index 88f2a8fd0a00..ea51d53f3233 100644 --- a/azurerm/internal/services/frontdoor/parse/frontend_endpoint_test.go +++ b/azurerm/internal/services/frontdoor/parse/frontend_endpoint_test.go @@ -57,10 +57,12 @@ func TestFrontendEndpointIDParser(t *testing.T) { actual, err := FrontendEndpointID(test.input) if err != nil && test.expected == nil { continue - } else if err == nil && test.expected == nil { - t.Fatalf("Expected an error but didn't get one") - } else if err != nil && test.expected != nil { - t.Fatalf("Expected no error but got: %+v", err) + } else { + if err == nil && test.expected == nil { + t.Fatalf("Expected an error but didn't get one") + } else if err != nil && test.expected != nil { + t.Fatalf("Expected no error but got: %+v", err) + } } if actual.ResourceGroup != test.expected.ResourceGroup { @@ -112,10 +114,12 @@ func TestFrontendEndpointIDForImportParser(t *testing.T) { actual, err := FrontendEndpointIDForImport(test.input) if err != nil && test.expected == nil { continue - } else if err == nil && test.expected == nil { - t.Fatalf("Expected an error but didn't get one") - } else if err != nil && test.expected != nil { - t.Fatalf("Expected no error but got: %+v", err) + } else { + if err == nil && test.expected == nil { + t.Fatalf("Expected an error but didn't get one") + } else if err != nil && test.expected != nil { + t.Fatalf("Expected no error but got: %+v", err) + } } if actual.ResourceGroup != test.expected.ResourceGroup { diff --git a/azurerm/internal/services/frontdoor/parse/health_probe_test.go b/azurerm/internal/services/frontdoor/parse/health_probe_test.go index cf1d5bdc7524..52951a31165a 100644 --- a/azurerm/internal/services/frontdoor/parse/health_probe_test.go +++ b/azurerm/internal/services/frontdoor/parse/health_probe_test.go @@ -57,10 +57,12 @@ func TestHealthProbeIDParser(t *testing.T) { actual, err := HealthProbeID(test.input) if err != nil && test.expected == nil { continue - } else if err == nil && test.expected == nil { - t.Fatalf("Expected an error but didn't get one") - } else if err != nil && test.expected != nil { - t.Fatalf("Expected no error but got: %+v", err) + } else { + if err == nil && test.expected == nil { + t.Fatalf("Expected an error but didn't get one") + } else if err != nil && test.expected != nil { + t.Fatalf("Expected no error but got: %+v", err) + } } if actual.ResourceGroup != test.expected.ResourceGroup { diff --git a/azurerm/internal/services/frontdoor/parse/load_balancing_test.go b/azurerm/internal/services/frontdoor/parse/load_balancing_test.go index 52e0191900f0..375e5cc37c36 100644 --- a/azurerm/internal/services/frontdoor/parse/load_balancing_test.go +++ b/azurerm/internal/services/frontdoor/parse/load_balancing_test.go @@ -57,10 +57,12 @@ func TestLoadBalancingIDParser(t *testing.T) { actual, err := LoadBalancingID(test.input) if err != nil && test.expected == nil { continue - } else if err == nil && test.expected == nil { - t.Fatalf("Expected an error but didn't get one") - } else if err != nil && test.expected != nil { - t.Fatalf("Expected no error but got: %+v", err) + } else { + if err == nil && test.expected == nil { + t.Fatalf("Expected an error but didn't get one") + } else if err != nil && test.expected != nil { + t.Fatalf("Expected no error but got: %+v", err) + } } if actual.ResourceGroup != test.expected.ResourceGroup { diff --git a/azurerm/internal/services/frontdoor/parse/routing_rule_test.go b/azurerm/internal/services/frontdoor/parse/routing_rule_test.go index 82ad41441aaa..9a3e5abf95fd 100644 --- a/azurerm/internal/services/frontdoor/parse/routing_rule_test.go +++ b/azurerm/internal/services/frontdoor/parse/routing_rule_test.go @@ -57,10 +57,12 @@ func TestRoutingRuleIDParser(t *testing.T) { actual, err := RoutingRuleID(test.input) if err != nil && test.expected == nil { continue - } else if err == nil && test.expected == nil { - t.Fatalf("Expected an error but didn't get one") - } else if err != nil && test.expected != nil { - t.Fatalf("Expected no error but got: %+v", err) + } else { + if err == nil && test.expected == nil { + t.Fatalf("Expected an error but didn't get one") + } else if err != nil && test.expected != nil { + t.Fatalf("Expected no error but got: %+v", err) + } } if actual.ResourceGroup != test.expected.ResourceGroup { diff --git a/azurerm/internal/services/frontdoor/parse/web_application_firewall_policy_test.go b/azurerm/internal/services/frontdoor/parse/web_application_firewall_policy_test.go index 2eb245b6b565..ff7a93df1595 100644 --- a/azurerm/internal/services/frontdoor/parse/web_application_firewall_policy_test.go +++ b/azurerm/internal/services/frontdoor/parse/web_application_firewall_policy_test.go @@ -51,10 +51,12 @@ func TestWebApplicationFirewallPolicyIDParser(t *testing.T) { actual, err := WebApplicationFirewallPolicyID(test.input) if err != nil && test.expected == nil { continue - } else if err == nil && test.expected == nil { - t.Fatalf("Expected an error but didn't get one") - } else if err != nil && test.expected != nil { - t.Fatalf("Expected no error but got: %+v", err) + } else { + if err == nil && test.expected == nil { + t.Fatalf("Expected an error but didn't get one") + } else if err != nil && test.expected != nil { + t.Fatalf("Expected no error but got: %+v", err) + } } if actual.ResourceGroup != test.expected.ResourceGroup {