From 46e2144823b60fb9144ad0c99956bd372518c88a Mon Sep 17 00:00:00 2001 From: Jeffrey Cline <20408400+WodansSon@users.noreply.github.com> Date: Fri, 30 Sep 2022 12:59:45 -0600 Subject: [PATCH 01/58] Initial check-in... --- .../cdn_frontdoor_custom_domain_resource.go | 411 ++++++++++++------ .../services/cdn/cdn_frontdoor_helpers.go | 23 +- .../cdn_frontdoor_custom_domain.html.markdown | 6 +- 3 files changed, 295 insertions(+), 145 deletions(-) diff --git a/internal/services/cdn/cdn_frontdoor_custom_domain_resource.go b/internal/services/cdn/cdn_frontdoor_custom_domain_resource.go index b03d1112f8da..0a50fb7b3570 100644 --- a/internal/services/cdn/cdn_frontdoor_custom_domain_resource.go +++ b/internal/services/cdn/cdn_frontdoor_custom_domain_resource.go @@ -9,6 +9,7 @@ import ( dnsValidate "github.com/hashicorp/go-azure-sdk/resource-manager/dns/2018-05-01/zones" "github.com/hashicorp/terraform-provider-azurerm/helpers/tf" "github.com/hashicorp/terraform-provider-azurerm/internal/clients" + "github.com/hashicorp/terraform-provider-azurerm/internal/features" "github.com/hashicorp/terraform-provider-azurerm/internal/locks" "github.com/hashicorp/terraform-provider-azurerm/internal/services/cdn/parse" "github.com/hashicorp/terraform-provider-azurerm/internal/services/cdn/validate" @@ -59,11 +60,36 @@ func resourceCdnFrontDoorCustomDomain() *pluginsdk.Resource { // this will also offload the task of maintaining the custom domain association // IDs in the route resource to the custom domains themselves... "associate_with_cdn_frontdoor_route_id": { - Type: pluginsdk.TypeString, - Optional: true, + Type: pluginsdk.TypeString, + Optional: true, + Computed: !features.FourPointOhBeta(), + Deprecated: "'associate_with_cdn_frontdoor_route_id' has been deprecated in favour of 'associate_with_cdn_frontdoor_route_ids' and will be removed in version 4.0 of the AzureRM provider", + ConflictsWith: func() []string { + if !features.FourPointOh() { + return []string{"associate_with_cdn_frontdoor_route_ids"} + } + return []string{} + }(), ValidateFunc: validate.FrontDoorRouteID, }, + "associate_with_cdn_frontdoor_route_ids": { + Type: pluginsdk.TypeList, + Optional: true, + Computed: !features.FourPointOhBeta(), + ConflictsWith: func() []string { + if !features.FourPointOh() { + return []string{"associate_with_cdn_frontdoor_route_id"} + } + return []string{} + }(), + + Elem: &pluginsdk.Schema{ + Type: pluginsdk.TypeString, + ValidateFunc: validate.FrontDoorRouteID, + }, + }, + "dns_zone_id": { Type: pluginsdk.TypeString, Optional: true, @@ -141,81 +167,105 @@ func resourceCdnFrontDoorCustomDomainCreate(d *pluginsdk.ResourceData, meta inte id := parse.NewFrontDoorCustomDomainID(profileId.SubscriptionId, profileId.ResourceGroup, profileId.ProfileName, d.Get("name").(string)) - if route := d.Get("associate_with_cdn_frontdoor_route_id").(string); route != "" { - routeId, err := parse.FrontDoorRouteID(route) - if err != nil { - return err + if !features.FourPointOhBeta() { + if route := d.Get("associate_with_cdn_frontdoor_route_id").(string); route != "" { + if err := validateCustomDomainRouteProfile(route, id); err != nil { + return err + } } - if id.ProfileName != routeId.ProfileName { - return fmt.Errorf("azurerm_cdn_frontdoor_custom_domain: the configuration is invalid, the Front Door Custom Domain(Name: %q, Profile: %q) and the Front Door Route(Name: %q, Profile: %q) must belong to the same Front Door Profile", id.CustomDomainName, id.ProfileName, routeId.RouteName, routeId.ProfileName) + + if routes := d.Get("associate_with_cdn_frontdoor_route_ids").([]interface{}); len(routes) > 0 { + for _, route := range routes { + if err := validateCustomDomainRouteProfile(route.(string), id); err != nil { + return err + } + } + } + + existing, err := client.Get(ctx, id.ResourceGroup, id.ProfileName, id.CustomDomainName) + if err != nil { + if !utils.ResponseWasNotFound(existing.Response) { + return fmt.Errorf("checking for existing %s: %+v", id, err) + } } - } - existing, err := client.Get(ctx, id.ResourceGroup, id.ProfileName, id.CustomDomainName) - if err != nil { if !utils.ResponseWasNotFound(existing.Response) { - return fmt.Errorf("checking for existing %s: %+v", id, err) + return tf.ImportAsExistsError("azurerm_cdn_frontdoor_custom_domain", id.ID()) } - } - if !utils.ResponseWasNotFound(existing.Response) { - return tf.ImportAsExistsError("azurerm_cdn_frontdoor_custom_domain", id.ID()) - } + // preValidatedDomain := d.Get("pre_validated_custom_domain_id").(string) + dnsZone := d.Get("dns_zone_id").(string) + tls := d.Get("tls").([]interface{}) - // preValidatedDomain := d.Get("pre_validated_custom_domain_id").(string) - dnsZone := d.Get("dns_zone_id").(string) - tls := d.Get("tls").([]interface{}) + props := cdn.AFDDomain{ + AFDDomainProperties: &cdn.AFDDomainProperties{ + HostName: utils.String(d.Get("host_name").(string)), + }, + } - props := cdn.AFDDomain{ - AFDDomainProperties: &cdn.AFDDomainProperties{ - HostName: utils.String(d.Get("host_name").(string)), - }, - } + if dnsZone != "" { + props.AFDDomainProperties.AzureDNSZone = expandResourceReference(dnsZone) + } - if dnsZone != "" { - props.AFDDomainProperties.AzureDNSZone = expandResourceReference(dnsZone) - } + tlsSettings, err := expandTlsParameters(tls, false) + if err != nil { + return err + } - tlsSettings, err := expandTlsParameters(tls, false) - if err != nil { - return err - } + props.AFDDomainProperties.TLSSettings = tlsSettings - props.AFDDomainProperties.TLSSettings = tlsSettings + future, err := client.Create(ctx, id.ResourceGroup, id.ProfileName, id.CustomDomainName, props) + if err != nil { + return fmt.Errorf("creating %s: %+v", id, err) + } - future, err := client.Create(ctx, id.ResourceGroup, id.ProfileName, id.CustomDomainName, props) - if err != nil { - return fmt.Errorf("creating %s: %+v", id, err) - } + if err = future.WaitForCompletionRef(ctx, client.Client); err != nil { + return fmt.Errorf("waiting for the creation of %s: %+v", id, err) + } - if err = future.WaitForCompletionRef(ctx, client.Client); err != nil { - return fmt.Errorf("waiting for the creation of %s: %+v", id, err) - } + d.SetId(id.ID()) - d.SetId(id.ID()) + // Associate the custom domain with the route, if that field was passed... + if !features.FourPointOhBeta() { + associateWithRoute := d.Get("associate_with_cdn_frontdoor_route_id").(string) + if associateWithRoute != "" { + // Associate the custom domain with theroute, if that field was passed... + routeId, err := parse.FrontDoorRouteID(associateWithRoute) + if err != nil { + return err + } - // Now that the Custom Domain has been created we need to associate the custom domain with the - // route, if that field was passed... - associateWithRoute := d.Get("associate_with_cdn_frontdoor_route_id").(string) - if associateWithRoute != "" { - // Lock the route for update... - routeId, err := parse.FrontDoorRouteID(associateWithRoute) - if err != nil { - return err - } + locks.ByName(routeId.RouteName, cdnFrontDoorRouteResourceName) + defer locks.UnlockByName(routeId.RouteName, cdnFrontDoorRouteResourceName) - locks.ByName(routeId.RouteName, cdnFrontDoorRouteResourceName) - defer locks.UnlockByName(routeId.RouteName, cdnFrontDoorRouteResourceName) + if err = addCustomDomainAssociationToRoute(d, meta, routeId, &id); err != nil { + return err + } + } - // add the association to the route... - writeFieldToState, err := addCustomDomainAssociationToRoute(d, meta, routeId, &id) - if err != nil { - return err + d.Set("associate_with_cdn_frontdoor_route_id", associateWithRoute) } + } - if writeFieldToState { - d.Set("associate_with_cdn_frontdoor_route_id", associateWithRoute) + associateWithRoutes := d.Get("associate_with_cdn_frontdoor_route_ids").([]interface{}) + if len(associateWithRoutes) > 0 { + for _, route := range associateWithRoutes { + // Lock the route for update... + routeId, err := parse.FrontDoorRouteID(route.(string)) + if err != nil { + return err + } + + locks.ByName(routeId.RouteName, cdnFrontDoorRouteResourceName) + defer locks.UnlockByName(routeId.RouteName, cdnFrontDoorRouteResourceName) + + // add the association to the route... + if err = addCustomDomainAssociationToRoute(d, meta, routeId, &id); err != nil { + return err + } } + + d.Set("associate_with_cdn_frontdoor_route_ids", associateWithRoutes) } return resourceCdnFrontDoorCustomDomainRead(d, meta) @@ -273,13 +323,19 @@ func resourceCdnFrontDoorCustomDomainUpdate(d *pluginsdk.ResourceData, meta inte return err } - if route := d.Get("associate_with_cdn_frontdoor_route_id").(string); route != "" { - routeId, err := parse.FrontDoorRouteID(route) - if err != nil { - return err + if !features.FourPointOhBeta() { + if route := d.Get("associate_with_cdn_frontdoor_route_id").(string); route != "" { + if err := validateCustomDomainRouteProfile(route, id); err != nil { + return err + } } - if id.ProfileName != routeId.ProfileName { - return fmt.Errorf("azurerm_cdn_frontdoor_custom_domain: the configuration is invalid, the Front Door Custom Domain(Name: %q, Profile: %q) and the Front Door Route(Name: %q, Profile: %q) must belong to the same Front Door Profile", id.CustomDomainName, id.ProfileName, routeId.RouteName, routeId.ProfileName) + } + + if routes := d.Get("associate_with_cdn_frontdoor_route_ids").([]interface{}); len(routes) > 0 { + for _, route := range routes { + if err := validateCustomDomainRouteProfile(route.(string), id); err != nil { + return err + } } } @@ -334,90 +390,175 @@ func resourceCdnFrontDoorCustomDomainUpdate(d *pluginsdk.ResourceData, meta inte // Now that the Custom Domain has been updated we need to ensure the referential integrity of the route resource // and associate/unassociate the custom domain with the route, if that field was defined/removed... - if d.HasChange("associate_with_cdn_frontdoor_route_id") { - var writeFieldToState bool + if !features.FourPointOhBeta() { + if d.HasChange("associate_with_cdn_frontdoor_route_id") { + old, new := d.GetChange("associate_with_cdn_frontdoor_route_id") + oldRouteValue := old.(string) + newRouteValue := new.(string) + + // If the old value was "" and the new value is something we are adding an association (lock only new value route) + // if the old value was something and it isn't the same as the new value we are associating the custom domain with a different route (lock both new and old routes) + // if the old value was something and the new value is "" we are removing the association with the route (lock only the old value route) + // the only other possibility here is that the old and new value are not empty and are the same value, which is a no op so do nothing... + + switch { + case (oldRouteValue == "" && newRouteValue != ""): + // Add + newRouteId, err := parse.FrontDoorRouteID(newRouteValue) + if err != nil { + return err + } + + // lock the route resource for update... + locks.ByName(newRouteId.RouteName, cdnFrontDoorRouteResourceName) + defer locks.UnlockByName(newRouteId.RouteName, cdnFrontDoorRouteResourceName) + + // add the association to the route... + err = addCustomDomainAssociationToRoute(d, meta, newRouteId, id) + if err != nil { + return err + } + + case (oldRouteValue != "" && newRouteValue == ""): + // Remove + oldRouteId, err := parse.FrontDoorRouteID(oldRouteValue) + if err != nil { + return err + } + + // lock the route resource for update... + locks.ByName(oldRouteId.RouteName, cdnFrontDoorRouteResourceName) + defer locks.UnlockByName(oldRouteId.RouteName, cdnFrontDoorRouteResourceName) + + // remove the association from the route.. + err = removeCustomDomainAssociationFromRoute(d, meta, oldRouteId, id) + if err != nil { + return err + } + + case (oldRouteValue != "" && newRouteValue != "" && !strings.EqualFold(oldRouteValue, newRouteValue)): + // Swap + oldRouteId, err := parse.FrontDoorRouteID(oldRouteValue) + if err != nil { + return err + } + + newRouteId, err := parse.FrontDoorRouteID(newRouteValue) + if err != nil { + return err + } + + // lock the route resources for update... + locks.ByName(oldRouteId.RouteName, cdnFrontDoorRouteResourceName) + defer locks.UnlockByName(oldRouteId.RouteName, cdnFrontDoorRouteResourceName) + + locks.ByName(newRouteId.RouteName, cdnFrontDoorRouteResourceName) + defer locks.UnlockByName(newRouteId.RouteName, cdnFrontDoorRouteResourceName) + + // remove the association from the old route.. + err = removeCustomDomainAssociationFromRoute(d, meta, oldRouteId, id) + if err != nil { + return err + } + + // add the association to the new route... + err = addCustomDomainAssociationToRoute(d, meta, newRouteId, id) + if err != nil { + return err + } + } + + d.Set("associate_with_cdn_frontdoor_route_id", newRouteValue) + } + } + + if d.HasChange("associate_with_cdn_frontdoor_route_ids") { + old, new := d.GetChange("associate_with_cdn_frontdoor_route_ids") + oldRouteValue := old.([]interface{}) + newRouteValue := new.([]interface{}) - old, new := d.GetChange("associate_with_cdn_frontdoor_route_id") - oldRouteValue := old.(string) - newRouteValue := new.(string) + // I need to figure out what work I need to do here because + // old and new are slices, so I need to figure out first + // what I am doing, there can be and add and a remove + // in the same Set... // If the old value was "" and the new value is something we are adding an association (lock only new value route) // if the old value was something and it isn't the same as the new value we are associating the custom domain with a different route (lock both new and old routes) // if the old value was something and the new value is "" we are removing the association with the route (lock only the old value route) // the only other possibility here is that the old and new value are not empty and are the same value, which is a no op so do nothing... - switch { - case (oldRouteValue == "" && newRouteValue != ""): - // Add - newRouteId, err := parse.FrontDoorRouteID(newRouteValue) - if err != nil { - return err - } - - // lock the route resource for update... - locks.ByName(newRouteId.RouteName, cdnFrontDoorRouteResourceName) - defer locks.UnlockByName(newRouteId.RouteName, cdnFrontDoorRouteResourceName) - - // add the association to the route... - writeFieldToState, err = addCustomDomainAssociationToRoute(d, meta, newRouteId, id) - if err != nil { - return err - } - - case (oldRouteValue != "" && newRouteValue == ""): - // Remove - oldRouteId, err := parse.FrontDoorRouteID(oldRouteValue) - if err != nil { - return err - } - - // lock the route resource for update... - locks.ByName(oldRouteId.RouteName, cdnFrontDoorRouteResourceName) - defer locks.UnlockByName(oldRouteId.RouteName, cdnFrontDoorRouteResourceName) - - // remove the association from the route.. - err = removeCustomDomainAssociationFromRoute(d, meta, oldRouteId, id) - if err != nil { - return err - } - - case (oldRouteValue != "" && newRouteValue != "" && !strings.EqualFold(oldRouteValue, newRouteValue)): - // Swap - oldRouteId, err := parse.FrontDoorRouteID(oldRouteValue) - if err != nil { - return err - } - - newRouteId, err := parse.FrontDoorRouteID(newRouteValue) - if err != nil { - return err - } - - // lock the route resources for update... - locks.ByName(oldRouteId.RouteName, cdnFrontDoorRouteResourceName) - defer locks.UnlockByName(oldRouteId.RouteName, cdnFrontDoorRouteResourceName) - - locks.ByName(newRouteId.RouteName, cdnFrontDoorRouteResourceName) - defer locks.UnlockByName(newRouteId.RouteName, cdnFrontDoorRouteResourceName) - - // remove the association from the old route.. - err = removeCustomDomainAssociationFromRoute(d, meta, oldRouteId, id) - if err != nil { - return err - } - - // add the association to the new route... - writeFieldToState, err = addCustomDomainAssociationToRoute(d, meta, newRouteId, id) - if err != nil { - return err + for _, route := range newRouteValue { + switch { + case (len(oldRouteValue) == 0 && len(newRouteValue) != 0): + // Add + newRouteId, err := parse.FrontDoorRouteID(route.(string)) + if err != nil { + return err + } + + // lock the route resource for update... + locks.ByName(newRouteId.RouteName, cdnFrontDoorRouteResourceName) + defer locks.UnlockByName(newRouteId.RouteName, cdnFrontDoorRouteResourceName) + + // add the association to the route... + err = addCustomDomainAssociationToRoute(d, meta, newRouteId, id) + if err != nil { + return err + } + + case (len(oldRouteValue) != 0 && len(newRouteValue) == 0): + // Remove + oldRouteId, err := parse.FrontDoorRouteID(oldRouteValue) + if err != nil { + return err + } + + // lock the route resource for update... + locks.ByName(oldRouteId.RouteName, cdnFrontDoorRouteResourceName) + defer locks.UnlockByName(oldRouteId.RouteName, cdnFrontDoorRouteResourceName) + + // remove the association from the route.. + err = removeCustomDomainAssociationFromRoute(d, meta, oldRouteId, id) + if err != nil { + return err + } + + case (oldRouteValue != "" && newRouteValue != "" && !strings.EqualFold(oldRouteValue, newRouteValue)): + // Swap + oldRouteId, err := parse.FrontDoorRouteID(oldRouteValue) + if err != nil { + return err + } + + newRouteId, err := parse.FrontDoorRouteID(newRouteValue) + if err != nil { + return err + } + + // lock the route resources for update... + locks.ByName(oldRouteId.RouteName, cdnFrontDoorRouteResourceName) + defer locks.UnlockByName(oldRouteId.RouteName, cdnFrontDoorRouteResourceName) + + locks.ByName(newRouteId.RouteName, cdnFrontDoorRouteResourceName) + defer locks.UnlockByName(newRouteId.RouteName, cdnFrontDoorRouteResourceName) + + // remove the association from the old route.. + err = removeCustomDomainAssociationFromRoute(d, meta, oldRouteId, id) + if err != nil { + return err + } + + // add the association to the new route... + err = addCustomDomainAssociationToRoute(d, meta, newRouteId, id) + if err != nil { + return err + } } } // Now that all of the routes have been processed and updated correctly // write the value to the state file if we need too... - if writeFieldToState { - d.Set("associate_with_cdn_frontdoor_route_id", newRouteValue) - } + d.Set("associate_with_cdn_frontdoor_route_id", newRouteValue) } return resourceCdnFrontDoorCustomDomainRead(d, meta) diff --git a/internal/services/cdn/cdn_frontdoor_helpers.go b/internal/services/cdn/cdn_frontdoor_helpers.go index 59d219f42802..3ada8f7411ac 100644 --- a/internal/services/cdn/cdn_frontdoor_helpers.go +++ b/internal/services/cdn/cdn_frontdoor_helpers.go @@ -267,13 +267,11 @@ func checkIfRouteExists(d *pluginsdk.ResourceData, meta interface{}, id *parse.F return customDomains, props, nil } -func addCustomDomainAssociationToRoute(d *pluginsdk.ResourceData, meta interface{}, routeId *parse.FrontDoorRouteId, customDomainID *parse.FrontDoorCustomDomainId) (bool, error) { - var associationFailed bool - +func addCustomDomainAssociationToRoute(d *pluginsdk.ResourceData, meta interface{}, routeId *parse.FrontDoorRouteId, customDomainID *parse.FrontDoorCustomDomainId) error { // Check to see if the route still exists or not... customDomains, props, err := checkIfRouteExists(d, meta, routeId, cdnFrontDoorCustomDomainResourceName) if err != nil { - return associationFailed, err + return err } // Check to make sure the custom domain is not already associated with the route @@ -285,11 +283,11 @@ func addCustomDomainAssociationToRoute(d *pluginsdk.ResourceData, meta interface customDomains = append(customDomains, customDomainID.ID()) err := updateRouteAssociations(d, meta, routeId, customDomains, props, customDomainID) if err != nil { - return associationFailed, err + return err } } - return !associationFailed, nil + return nil } func removeCustomDomainAssociationFromRoute(d *pluginsdk.ResourceData, meta interface{}, routeId *parse.FrontDoorRouteId, customDomainID *parse.FrontDoorCustomDomainId) error { @@ -412,3 +410,16 @@ func validateCustomDomanLinkToDefaultDomainState(resourceCustomDomains []interfa return nil } + +func validateCustomDomainRouteProfile(route string, customDomainID *parse.FrontDoorCustomDomainId) error { + routeId, err := parse.FrontDoorRouteID(route) + if err != nil { + return err + } + + if customDomainID.ProfileName != routeId.ProfileName { + return fmt.Errorf("azurerm_cdn_frontdoor_custom_domain: the configuration is invalid, the Front Door Custom Domain(Name: %q, Profile: %q) and the Front Door Route(Name: %q, Profile: %q) must belong to the same Front Door Profile", customDomainID.CustomDomainName, customDomainID.ProfileName, routeId.RouteName, routeId.ProfileName) + } + + return nil +} diff --git a/website/docs/r/cdn_frontdoor_custom_domain.html.markdown b/website/docs/r/cdn_frontdoor_custom_domain.html.markdown index f641340fff81..3661774fccae 100644 --- a/website/docs/r/cdn_frontdoor_custom_domain.html.markdown +++ b/website/docs/r/cdn_frontdoor_custom_domain.html.markdown @@ -36,7 +36,7 @@ resource "azurerm_cdn_frontdoor_custom_domain" "example" { dns_zone_id = azurerm_dns_zone.example.id host_name = "contoso.com" - associate_with_cdn_frontdoor_route_id = azurerm_cdn_frontdoor_route.example.id + associate_with_cdn_frontdoor_route_ids = [azurerm_cdn_frontdoor_route.example.id] tls { certificate_type = "ManagedCertificate" @@ -85,9 +85,7 @@ The following arguments are supported: * `host_name` - (Required) The host name of the domain. Changing this forces a new CDN FrontDoor Custom Domain to be created. -* `associate_with_cdn_frontdoor_route_id` (Optional) - The resource ID of the CDN FrontDoor Route this Custom Domain should be associated with. - -->**NOTE:** Once a CDN Front Door Custom Domain has been associated with a CDN Front Door Route changing this value will force a new CDN Front Door Custom Domain to be created. +* `associate_with_cdn_frontdoor_route_ids` (Optional) - One or more CDN FrontDoor Route resource IDs for which this Custom Domain should be associated with. * `dns_zone_id` - (Optional) The ID of the DNS Zone which should be used for this FrontDoor Custom Domain. From fcb98e0e84bfc7fc36378ca9e53cba14e99ed93d Mon Sep 17 00:00:00 2001 From: Jeffrey Cline <20408400+WodansSon@users.noreply.github.com> Date: Sat, 1 Oct 2022 03:39:25 -0600 Subject: [PATCH 02/58] Churn while I work out the logic... --- .../cdn_frontdoor_custom_domain_resource.go | 358 +++++++----------- .../services/cdn/cdn_frontdoor_helpers.go | 118 ++++-- 2 files changed, 226 insertions(+), 250 deletions(-) diff --git a/internal/services/cdn/cdn_frontdoor_custom_domain_resource.go b/internal/services/cdn/cdn_frontdoor_custom_domain_resource.go index 0a50fb7b3570..e483ec374d36 100644 --- a/internal/services/cdn/cdn_frontdoor_custom_domain_resource.go +++ b/internal/services/cdn/cdn_frontdoor_custom_domain_resource.go @@ -10,7 +10,6 @@ import ( "github.com/hashicorp/terraform-provider-azurerm/helpers/tf" "github.com/hashicorp/terraform-provider-azurerm/internal/clients" "github.com/hashicorp/terraform-provider-azurerm/internal/features" - "github.com/hashicorp/terraform-provider-azurerm/internal/locks" "github.com/hashicorp/terraform-provider-azurerm/internal/services/cdn/parse" "github.com/hashicorp/terraform-provider-azurerm/internal/services/cdn/validate" "github.com/hashicorp/terraform-provider-azurerm/internal/tf/pluginsdk" @@ -19,6 +18,11 @@ import ( "github.com/hashicorp/terraform-provider-azurerm/utils" ) +type RouteInfo struct { + CustomDomains []interface{} + Props *cdn.RouteProperties +} + func resourceCdnFrontDoorCustomDomain() *pluginsdk.Resource { return &pluginsdk.Resource{ Create: resourceCdnFrontDoorCustomDomainCreate, @@ -167,105 +171,80 @@ func resourceCdnFrontDoorCustomDomainCreate(d *pluginsdk.ResourceData, meta inte id := parse.NewFrontDoorCustomDomainID(profileId.SubscriptionId, profileId.ResourceGroup, profileId.ProfileName, d.Get("name").(string)) - if !features.FourPointOhBeta() { - if route := d.Get("associate_with_cdn_frontdoor_route_id").(string); route != "" { - if err := validateCustomDomainRouteProfile(route, id); err != nil { - return err - } - } - - if routes := d.Get("associate_with_cdn_frontdoor_route_ids").([]interface{}); len(routes) > 0 { - for _, route := range routes { - if err := validateCustomDomainRouteProfile(route.(string), id); err != nil { - return err - } - } - } - - existing, err := client.Get(ctx, id.ResourceGroup, id.ProfileName, id.CustomDomainName) - if err != nil { - if !utils.ResponseWasNotFound(existing.Response) { - return fmt.Errorf("checking for existing %s: %+v", id, err) - } - } - + existing, err := client.Get(ctx, id.ResourceGroup, id.ProfileName, id.CustomDomainName) + if err != nil { if !utils.ResponseWasNotFound(existing.Response) { - return tf.ImportAsExistsError("azurerm_cdn_frontdoor_custom_domain", id.ID()) + return fmt.Errorf("checking for existing %s: %+v", id, err) } + } - // preValidatedDomain := d.Get("pre_validated_custom_domain_id").(string) - dnsZone := d.Get("dns_zone_id").(string) - tls := d.Get("tls").([]interface{}) + if !utils.ResponseWasNotFound(existing.Response) { + return tf.ImportAsExistsError("azurerm_cdn_frontdoor_custom_domain", id.ID()) + } - props := cdn.AFDDomain{ - AFDDomainProperties: &cdn.AFDDomainProperties{ - HostName: utils.String(d.Get("host_name").(string)), - }, - } + // preValidatedDomain := d.Get("pre_validated_custom_domain_id").(string) + dnsZone := d.Get("dns_zone_id").(string) + tls := d.Get("tls").([]interface{}) - if dnsZone != "" { - props.AFDDomainProperties.AzureDNSZone = expandResourceReference(dnsZone) - } + props := cdn.AFDDomain{ + AFDDomainProperties: &cdn.AFDDomainProperties{ + HostName: utils.String(d.Get("host_name").(string)), + }, + } - tlsSettings, err := expandTlsParameters(tls, false) - if err != nil { - return err - } + if dnsZone != "" { + props.AFDDomainProperties.AzureDNSZone = expandResourceReference(dnsZone) + } - props.AFDDomainProperties.TLSSettings = tlsSettings + tlsSettings, err := expandTlsParameters(tls, false) + if err != nil { + return err + } - future, err := client.Create(ctx, id.ResourceGroup, id.ProfileName, id.CustomDomainName, props) - if err != nil { - return fmt.Errorf("creating %s: %+v", id, err) - } + props.AFDDomainProperties.TLSSettings = tlsSettings - if err = future.WaitForCompletionRef(ctx, client.Client); err != nil { - return fmt.Errorf("waiting for the creation of %s: %+v", id, err) - } + future, err := client.Create(ctx, id.ResourceGroup, id.ProfileName, id.CustomDomainName, props) + if err != nil { + return fmt.Errorf("creating %s: %+v", id, err) + } - d.SetId(id.ID()) + if err = future.WaitForCompletionRef(ctx, client.Client); err != nil { + return fmt.Errorf("waiting for the creation of %s: %+v", id, err) + } - // Associate the custom domain with the route, if that field was passed... - if !features.FourPointOhBeta() { - associateWithRoute := d.Get("associate_with_cdn_frontdoor_route_id").(string) - if associateWithRoute != "" { - // Associate the custom domain with theroute, if that field was passed... - routeId, err := parse.FrontDoorRouteID(associateWithRoute) - if err != nil { - return err - } + d.SetId(id.ID()) - locks.ByName(routeId.RouteName, cdnFrontDoorRouteResourceName) - defer locks.UnlockByName(routeId.RouteName, cdnFrontDoorRouteResourceName) + // Associate the custom domain with the route, if that field was passed... + if !features.FourPointOhBeta() { + if routes := []interface{}{d.Get("associate_with_cdn_frontdoor_route_id")}; len(routes) > 0 { + if err := validateCustomDomainRoutesProfile(routes, &id); err != nil { + return err + } - if err = addCustomDomainAssociationToRoute(d, meta, routeId, &id); err != nil { - return err - } + if err = addCustomDomainAssociationToRoutes(d, meta, routes, &id); err != nil { + return err } - d.Set("associate_with_cdn_frontdoor_route_id", associateWithRoute) + d.Set("associate_with_cdn_frontdoor_route_id", routes[0].(string)) + } else { + d.Set("associate_with_cdn_frontdoor_route_id", "") } } - associateWithRoutes := d.Get("associate_with_cdn_frontdoor_route_ids").([]interface{}) - if len(associateWithRoutes) > 0 { - for _, route := range associateWithRoutes { - // Lock the route for update... - routeId, err := parse.FrontDoorRouteID(route.(string)) - if err != nil { - return err - } + if routes := d.Get("associate_with_cdn_frontdoor_route_ids").([]interface{}); len(routes) > 0 { + if err := hasDuplicateRoute(routes); err != nil { + return err + } - locks.ByName(routeId.RouteName, cdnFrontDoorRouteResourceName) - defer locks.UnlockByName(routeId.RouteName, cdnFrontDoorRouteResourceName) + if err := validateCustomDomainRoutesProfile(routes, &id); err != nil { + return err + } - // add the association to the route... - if err = addCustomDomainAssociationToRoute(d, meta, routeId, &id); err != nil { - return err - } + if err = addCustomDomainAssociationToRoutes(d, meta, routes, &id); err != nil { + return err } - d.Set("associate_with_cdn_frontdoor_route_ids", associateWithRoutes) + d.Set("associate_with_cdn_frontdoor_route_ids", routes) } return resourceCdnFrontDoorCustomDomainRead(d, meta) @@ -276,7 +255,7 @@ func resourceCdnFrontDoorCustomDomainRead(d *pluginsdk.ResourceData, meta interf ctx, cancel := timeouts.ForRead(meta.(*clients.Client).StopContext, d) defer cancel() - id, err := parse.FrontdoorCustomDomainID(d.Id()) + id, err := customDomainIDWithErrorTxt(d.Id()) if err != nil { return err } @@ -323,19 +302,18 @@ func resourceCdnFrontDoorCustomDomainUpdate(d *pluginsdk.ResourceData, meta inte return err } + // validate the associations first... if !features.FourPointOhBeta() { - if route := d.Get("associate_with_cdn_frontdoor_route_id").(string); route != "" { - if err := validateCustomDomainRouteProfile(route, id); err != nil { + if routes := []interface{}{d.Get("associate_with_cdn_frontdoor_route_id")}; len(routes) > 0 { + if err := validateCustomDomainRoutesProfile(routes, id); err != nil { return err } } } if routes := d.Get("associate_with_cdn_frontdoor_route_ids").([]interface{}); len(routes) > 0 { - for _, route := range routes { - if err := validateCustomDomainRouteProfile(route.(string), id); err != nil { - return err - } + if err := validateCustomDomainRoutesProfile(routes, id); err != nil { + return fmt.Errorf("azurerm_cdn_frontdoor_custom_domain: the 'associate_with_cdn_frontdoor_route_ids' field is invalid: %+v", err) } } @@ -389,176 +367,117 @@ func resourceCdnFrontDoorCustomDomainUpdate(d *pluginsdk.ResourceData, meta inte } // Now that the Custom Domain has been updated we need to ensure the referential integrity of the route resource - // and associate/unassociate the custom domain with the route, if that field was defined/removed... + // and associate/unassociate the custom domain with the route(s), if that field was defined/removed... if !features.FourPointOhBeta() { if d.HasChange("associate_with_cdn_frontdoor_route_id") { old, new := d.GetChange("associate_with_cdn_frontdoor_route_id") oldRouteValue := old.(string) newRouteValue := new.(string) - // If the old value was "" and the new value is something we are adding an association (lock only new value route) - // if the old value was something and it isn't the same as the new value we are associating the custom domain with a different route (lock both new and old routes) - // if the old value was something and the new value is "" we are removing the association with the route (lock only the old value route) - // the only other possibility here is that the old and new value are not empty and are the same value, which is a no op so do nothing... - switch { case (oldRouteValue == "" && newRouteValue != ""): // Add - newRouteId, err := parse.FrontDoorRouteID(newRouteValue) - if err != nil { - return err - } + routes := []interface{}{oldRouteValue} - // lock the route resource for update... - locks.ByName(newRouteId.RouteName, cdnFrontDoorRouteResourceName) - defer locks.UnlockByName(newRouteId.RouteName, cdnFrontDoorRouteResourceName) - - // add the association to the route... - err = addCustomDomainAssociationToRoute(d, meta, newRouteId, id) - if err != nil { + // add the association to the new route... + if err := addCustomDomainAssociationToRoutes(d, meta, routes, id); err != nil { return err } case (oldRouteValue != "" && newRouteValue == ""): // Remove - oldRouteId, err := parse.FrontDoorRouteID(oldRouteValue) - if err != nil { - return err - } + routes := []interface{}{oldRouteValue} - // lock the route resource for update... - locks.ByName(oldRouteId.RouteName, cdnFrontDoorRouteResourceName) - defer locks.UnlockByName(oldRouteId.RouteName, cdnFrontDoorRouteResourceName) - - // remove the association from the route.. - err = removeCustomDomainAssociationFromRoute(d, meta, oldRouteId, id) - if err != nil { + // remove the association from the old route.. + if err := removeCustomDomainAssociationFromRoutes(d, meta, routes, id); err != nil { return err } + d.Set("associate_with_cdn_frontdoor_route_id", "") + case (oldRouteValue != "" && newRouteValue != "" && !strings.EqualFold(oldRouteValue, newRouteValue)): // Swap - oldRouteId, err := parse.FrontDoorRouteID(oldRouteValue) - if err != nil { - return err - } - - newRouteId, err := parse.FrontDoorRouteID(newRouteValue) - if err != nil { - return err - } - - // lock the route resources for update... - locks.ByName(oldRouteId.RouteName, cdnFrontDoorRouteResourceName) - defer locks.UnlockByName(oldRouteId.RouteName, cdnFrontDoorRouteResourceName) - - locks.ByName(newRouteId.RouteName, cdnFrontDoorRouteResourceName) - defer locks.UnlockByName(newRouteId.RouteName, cdnFrontDoorRouteResourceName) + routes := []interface{}{oldRouteValue} // remove the association from the old route.. - err = removeCustomDomainAssociationFromRoute(d, meta, oldRouteId, id) - if err != nil { + if err = removeCustomDomainAssociationFromRoutes(d, meta, routes, id); err != nil { return err } + d.Set("associate_with_cdn_frontdoor_route_id", "") + routes = []interface{}{newRouteValue} + // add the association to the new route... - err = addCustomDomainAssociationToRoute(d, meta, newRouteId, id) - if err != nil { + if err = addCustomDomainAssociationToRoutes(d, meta, routes, id); err != nil { return err } - } - d.Set("associate_with_cdn_frontdoor_route_id", newRouteValue) + d.Set("associate_with_cdn_frontdoor_route_id", newRouteValue) + } } } if d.HasChange("associate_with_cdn_frontdoor_route_ids") { old, new := d.GetChange("associate_with_cdn_frontdoor_route_ids") - oldRouteValue := old.([]interface{}) - newRouteValue := new.([]interface{}) - - // I need to figure out what work I need to do here because - // old and new are slices, so I need to figure out first - // what I am doing, there can be and add and a remove - // in the same Set... - - // If the old value was "" and the new value is something we are adding an association (lock only new value route) - // if the old value was something and it isn't the same as the new value we are associating the custom domain with a different route (lock both new and old routes) - // if the old value was something and the new value is "" we are removing the association with the route (lock only the old value route) - // the only other possibility here is that the old and new value are not empty and are the same value, which is a no op so do nothing... - - for _, route := range newRouteValue { - switch { - case (len(oldRouteValue) == 0 && len(newRouteValue) != 0): - // Add - newRouteId, err := parse.FrontDoorRouteID(route.(string)) - if err != nil { - return err - } - - // lock the route resource for update... - locks.ByName(newRouteId.RouteName, cdnFrontDoorRouteResourceName) - defer locks.UnlockByName(newRouteId.RouteName, cdnFrontDoorRouteResourceName) - - // add the association to the route... - err = addCustomDomainAssociationToRoute(d, meta, newRouteId, id) - if err != nil { - return err - } - - case (len(oldRouteValue) != 0 && len(newRouteValue) == 0): - // Remove - oldRouteId, err := parse.FrontDoorRouteID(oldRouteValue) - if err != nil { - return err - } - - // lock the route resource for update... - locks.ByName(oldRouteId.RouteName, cdnFrontDoorRouteResourceName) - defer locks.UnlockByName(oldRouteId.RouteName, cdnFrontDoorRouteResourceName) + oldRoutes := old.([]interface{}) + newRoutes := new.([]interface{}) - // remove the association from the route.. - err = removeCustomDomainAssociationFromRoute(d, meta, oldRouteId, id) - if err != nil { - return err - } + switch { + case (len(oldRoutes) == 0 && len(newRoutes) > 0): + // Add + err = addCustomDomainAssociationToRoutes(d, meta, newRoutes, id) + if err != nil { + return err + } + case (len(oldRoutes) > 0 && len(newRoutes) == 0): + // Remove the custom domain from all of the previously associated routes... + err = removeCustomDomainAssociationFromRoutes(d, meta, oldRoutes, id) + if err != nil { + return err + } - case (oldRouteValue != "" && newRouteValue != "" && !strings.EqualFold(oldRouteValue, newRouteValue)): - // Swap - oldRouteId, err := parse.FrontDoorRouteID(oldRouteValue) - if err != nil { - return err + d.Set("associate_with_cdn_frontdoor_route_ids", newRoutes) + + case (len(oldRoutes) > 0 && len(newRoutes) > 0): + // Remove(e.g. Swap): here I need to find out what was in the old list and is not in the new list, + // those are the routes I need to remove this custom domain from... + + // find the delta between the old and the new lists... + var removeDelta []interface{} + for _, nr := range newRoutes { + var found bool + var removeRoute interface{} + for _, or := range oldRoutes { + removeRoute = or + if strings.EqualFold(or.(string), nr.(string)) { + // they are in both lists so ignore it... + found = true + break + } } - newRouteId, err := parse.FrontDoorRouteID(newRouteValue) - if err != nil { - return err + // I did not find a route in the new list that is in the old route list so I need to disassociate that route with this custom domain... + if !found { + removeDelta = append(removeDelta, removeRoute) } + } - // lock the route resources for update... - locks.ByName(oldRouteId.RouteName, cdnFrontDoorRouteResourceName) - defer locks.UnlockByName(oldRouteId.RouteName, cdnFrontDoorRouteResourceName) - - locks.ByName(newRouteId.RouteName, cdnFrontDoorRouteResourceName) - defer locks.UnlockByName(newRouteId.RouteName, cdnFrontDoorRouteResourceName) - - // remove the association from the old route.. - err = removeCustomDomainAssociationFromRoute(d, meta, oldRouteId, id) + // delta now contains the list of all the routes that were not in our new list of routes that were in the old list of routes... + if len(removeDelta) > 0 { + err = removeCustomDomainAssociationFromRoutes(d, meta, removeDelta, id) if err != nil { return err } + } - // add the association to the new route... - err = addCustomDomainAssociationToRoute(d, meta, newRouteId, id) - if err != nil { - return err - } + // do not need to do the add delta as the addCustomDomainAssociationToRoutes figures that out for us automatically... + err = addCustomDomainAssociationToRoutes(d, meta, newRoutes, id) + if err != nil { + return err } } - // Now that all of the routes have been processed and updated correctly - // write the value to the state file if we need too... - d.Set("associate_with_cdn_frontdoor_route_id", newRouteValue) + d.Set("associate_with_cdn_frontdoor_route_ids", newRoutes) } return resourceCdnFrontDoorCustomDomainRead(d, meta) @@ -576,20 +495,21 @@ func resourceCdnFrontDoorCustomDomainDelete(d *pluginsdk.ResourceData, meta inte // NOTE: If the custom domain is still associated with a route you cannot delete it // you must first update the route to remove the association with the custom domain... - disassociateRoute := d.Get("associate_with_cdn_frontdoor_route_id").(string) - if disassociateRoute != "" { - routeId, err := parse.FrontDoorRouteID(disassociateRoute) - if err != nil { - return err - } + if !features.FourPointOhBeta() { + if route := []interface{}{d.Get("associate_with_cdn_frontdoor_route_id")}; len(route) > 0 { + routes := []interface{}{route} - // NOTE: cdnFrontDoorRouteResourceName is defined in the "cdn_frontdoor_route_unlink_default_domain_resource.go" file - locks.ByName(routeId.RouteName, cdnFrontDoorRouteResourceName) - defer locks.UnlockByName(routeId.RouteName, cdnFrontDoorRouteResourceName) + // remove the association from the old route.. + if err := removeCustomDomainAssociationFromRoutes(d, meta, routes, id); err != nil { + return err + } + } + } - // remove the association from the route.. - err = removeCustomDomainAssociationFromRoute(d, meta, routeId, id) - if err != nil { + routes := d.Get("associate_with_cdn_frontdoor_route_ids").([]interface{}) + if len(routes) > 0 { + // remove the association from the old route.. + if err := removeCustomDomainAssociationFromRoutes(d, meta, routes, id); err != nil { return err } } diff --git a/internal/services/cdn/cdn_frontdoor_helpers.go b/internal/services/cdn/cdn_frontdoor_helpers.go index 3ada8f7411ac..f4c830567ff3 100644 --- a/internal/services/cdn/cdn_frontdoor_helpers.go +++ b/internal/services/cdn/cdn_frontdoor_helpers.go @@ -7,6 +7,7 @@ import ( "github.com/Azure/azure-sdk-for-go/services/cdn/mgmt/2021-06-01/cdn" "github.com/Azure/azure-sdk-for-go/services/frontdoor/mgmt/2020-11-01/frontdoor" "github.com/hashicorp/terraform-provider-azurerm/internal/clients" + "github.com/hashicorp/terraform-provider-azurerm/internal/locks" "github.com/hashicorp/terraform-provider-azurerm/internal/services/cdn/azuresdkhacks" "github.com/hashicorp/terraform-provider-azurerm/internal/services/cdn/parse" "github.com/hashicorp/terraform-provider-azurerm/internal/tf/pluginsdk" @@ -267,49 +268,69 @@ func checkIfRouteExists(d *pluginsdk.ResourceData, meta interface{}, id *parse.F return customDomains, props, nil } -func addCustomDomainAssociationToRoute(d *pluginsdk.ResourceData, meta interface{}, routeId *parse.FrontDoorRouteId, customDomainID *parse.FrontDoorCustomDomainId) error { - // Check to see if the route still exists or not... - customDomains, props, err := checkIfRouteExists(d, meta, routeId, cdnFrontDoorCustomDomainResourceName) - if err != nil { - return err - } +func addCustomDomainAssociationToRoutes(d *pluginsdk.ResourceData, meta interface{}, route []interface{}, customDomainID *parse.FrontDoorCustomDomainId) error { + // NOTE: This is very inefficient because it will update the route multipule times to and multiple domains... fix this... + for _, v := range route { + route, err := routeIDWithErrorTxt(v.(string)) + if err != nil { + return err + } - // Check to make sure the custom domain is not already associated with the route - // if it is, then there is nothing for us to do... - isAssociated := sliceContainsString(customDomains, customDomainID.ID()) + // lock the route resource for update... + locks.ByName(route.RouteName, cdnFrontDoorRouteResourceName) + defer locks.UnlockByName(route.RouteName, cdnFrontDoorRouteResourceName) - // if it is not associated update the route to add the association... - if !isAssociated { - customDomains = append(customDomains, customDomainID.ID()) - err := updateRouteAssociations(d, meta, routeId, customDomains, props, customDomainID) + // Check to see if the route still exists or not... + // NOTE: the custom domains that are returned are the ones from the route GET call... + // NOTE: cdnFrontDoorRouteResourceName is defined in the "cdn_frontdoor_route_disable_link_to_default_domain_resource" file + customDomains, props, err := checkIfRouteExists(d, meta, route, cdnFrontDoorCustomDomainResourceName) if err != nil { return err } + + isAssociated := sliceContainsString(customDomains, customDomainID.ID()) + + // if it is not associated update the route to add the association... + if !isAssociated { + err := updateRouteAssociations(d, meta, route, customDomains, props, customDomainID) + if err != nil { + return err + } + } } return nil } -func removeCustomDomainAssociationFromRoute(d *pluginsdk.ResourceData, meta interface{}, routeId *parse.FrontDoorRouteId, customDomainID *parse.FrontDoorCustomDomainId) error { - // Check to see if the route still exists or not... - customDomains, props, err := checkIfRouteExists(d, meta, routeId, cdnFrontDoorCustomDomainResourceName) - if err != nil { - return err - } +func removeCustomDomainAssociationFromRoutes(d *pluginsdk.ResourceData, meta interface{}, route []interface{}, customDomainID *parse.FrontDoorCustomDomainId) error { + for _, v := range route { + route, err := routeIDWithErrorTxt(v.(string)) + if err != nil { + return err + } - // Check to make sure the custom domain is still associated with the route - isAssociated := sliceContainsString(customDomains, customDomainID.ID()) + // lock the route resource for update... + locks.ByName(route.RouteName, cdnFrontDoorRouteResourceName) + defer locks.UnlockByName(route.RouteName, cdnFrontDoorRouteResourceName) - if isAssociated { - // it is, now remove the association... - newDomains := sliceRemoveString(customDomains, customDomainID.ID()) - err := updateRouteAssociations(d, meta, routeId, newDomains, props, customDomainID) + // Check to see if the route still exists or not... + // NOTE: cdnFrontDoorRouteResourceName is defined in the "cdn_frontdoor_route_disable_link_to_default_domain_resource" file + customDomains, props, err := checkIfRouteExists(d, meta, route, cdnFrontDoorCustomDomainResourceName) if err != nil { return err } - // remove the field from state... - d.Set("associate_with_cdn_frontdoor_route_id", "") + // Check to make sure the custom domain is still associated with the route + isAssociated := sliceContainsString(customDomains, customDomainID.ID()) + + if isAssociated { + // it is, now removed the association... + newDomains := sliceRemoveString(customDomains, customDomainID.ID()) + err := updateRouteAssociations(d, meta, route, newDomains, props, customDomainID) + if err != nil { + return err + } + } } return nil @@ -411,14 +432,49 @@ func validateCustomDomanLinkToDefaultDomainState(resourceCustomDomains []interfa return nil } -func validateCustomDomainRouteProfile(route string, customDomainID *parse.FrontDoorCustomDomainId) error { +func validateCustomDomainRoutesProfile(routes []interface{}, customDomainID *parse.FrontDoorCustomDomainId) error { + for _, route := range routes { + routeId, err := routeIDWithErrorTxt(route.(string)) + if err != nil { + return err + } + + if customDomainID.ProfileName != routeId.ProfileName { + return fmt.Errorf("the Front Door Custom Domain(Name: %q, Profile: %q) and the Front Door Route(Name: %q, Profile: %q) must belong to the same Front Door Profile", customDomainID.CustomDomainName, customDomainID.ProfileName, routeId.RouteName, routeId.ProfileName) + } + } + + return nil +} + +func routeIDWithErrorTxt(route string) (*parse.FrontDoorRouteId, error) { routeId, err := parse.FrontDoorRouteID(route) if err != nil { - return err + return nil, fmt.Errorf("unable to parse CDN FrontDoor Route ID: %+v", err) } - if customDomainID.ProfileName != routeId.ProfileName { - return fmt.Errorf("azurerm_cdn_frontdoor_custom_domain: the configuration is invalid, the Front Door Custom Domain(Name: %q, Profile: %q) and the Front Door Route(Name: %q, Profile: %q) must belong to the same Front Door Profile", customDomainID.CustomDomainName, customDomainID.ProfileName, routeId.RouteName, routeId.ProfileName) + return routeId, nil +} + +func customDomainIDWithErrorTxt(route string) (*parse.FrontDoorCustomDomainId, error) { + customDomainId, err := parse.FrontDoorCustomDomainID(route) + if err != nil { + return nil, fmt.Errorf("unable to parse CDN FrontDoor Custom Domain ID: %+v", err) + } + + return customDomainId, nil +} + +// checks to make sure the list of routes and the custom domain belong to the same profile +func hasDuplicateRoute(route []interface{}) error { + k := make(map[string]bool) + + for _, v := range route { + if _, d := k[strings.ToLower(v.(string))]; !d { + k[strings.ToLower(v.(string))] = true + } else { + return fmt.Errorf("duplicate CDN FrontDoor Route, please remove the CDN FrontDoor Route(ID: %q) from your configuration file", v.(string)) + } } return nil From bfb62350afd8710ae3795b61d36cde8be5dae37b Mon Sep 17 00:00:00 2001 From: Jeffrey Cline <20408400+WodansSon@users.noreply.github.com> Date: Mon, 3 Oct 2022 00:03:27 -0600 Subject: [PATCH 03/58] So close... --- .../cdn_frontdoor_custom_domain_resource.go | 229 ++++++++---------- .../services/cdn/cdn_frontdoor_helpers.go | 160 +++++++----- 2 files changed, 207 insertions(+), 182 deletions(-) diff --git a/internal/services/cdn/cdn_frontdoor_custom_domain_resource.go b/internal/services/cdn/cdn_frontdoor_custom_domain_resource.go index e483ec374d36..e067c046ca36 100644 --- a/internal/services/cdn/cdn_frontdoor_custom_domain_resource.go +++ b/internal/services/cdn/cdn_frontdoor_custom_domain_resource.go @@ -18,11 +18,6 @@ import ( "github.com/hashicorp/terraform-provider-azurerm/utils" ) -type RouteInfo struct { - CustomDomains []interface{} - Props *cdn.RouteProperties -} - func resourceCdnFrontDoorCustomDomain() *pluginsdk.Resource { return &pluginsdk.Resource{ Create: resourceCdnFrontDoorCustomDomainCreate, @@ -69,7 +64,7 @@ func resourceCdnFrontDoorCustomDomain() *pluginsdk.Resource { Computed: !features.FourPointOhBeta(), Deprecated: "'associate_with_cdn_frontdoor_route_id' has been deprecated in favour of 'associate_with_cdn_frontdoor_route_ids' and will be removed in version 4.0 of the AzureRM provider", ConflictsWith: func() []string { - if !features.FourPointOh() { + if !features.FourPointOhBeta() { return []string{"associate_with_cdn_frontdoor_route_ids"} } return []string{} @@ -82,7 +77,7 @@ func resourceCdnFrontDoorCustomDomain() *pluginsdk.Resource { Optional: true, Computed: !features.FourPointOhBeta(), ConflictsWith: func() []string { - if !features.FourPointOh() { + if !features.FourPointOhBeta() { return []string{"associate_with_cdn_frontdoor_route_id"} } return []string{} @@ -182,7 +177,23 @@ func resourceCdnFrontDoorCustomDomainCreate(d *pluginsdk.ResourceData, meta inte return tf.ImportAsExistsError("azurerm_cdn_frontdoor_custom_domain", id.ID()) } - // preValidatedDomain := d.Get("pre_validated_custom_domain_id").(string) + // do the validation first on the deprecated field... + if !features.FourPointOhBeta() { + if route := d.Get("associate_with_cdn_frontdoor_route_id").(string); route != "" { + routes := []interface{}{route} + if err := validateCustomDomainRoutesProfileAndEndpoints(routes, &id); err != nil { + return err + } + } + } + + // do the validation on the 4.0 field... + if routes := d.Get("associate_with_cdn_frontdoor_route_ids").([]interface{}); len(routes) != 0 { + if err := validateCustomDomainRoutesProfileAndEndpoints(routes, &id); err != nil { + return err + } + } + dnsZone := d.Get("dns_zone_id").(string) tls := d.Get("tls").([]interface{}) @@ -216,35 +227,25 @@ func resourceCdnFrontDoorCustomDomainCreate(d *pluginsdk.ResourceData, meta inte // Associate the custom domain with the route, if that field was passed... if !features.FourPointOhBeta() { - if routes := []interface{}{d.Get("associate_with_cdn_frontdoor_route_id")}; len(routes) > 0 { - if err := validateCustomDomainRoutesProfile(routes, &id); err != nil { - return err - } + if route := d.Get("associate_with_cdn_frontdoor_route_id").(string); route != "" { + routes := []interface{}{route} if err = addCustomDomainAssociationToRoutes(d, meta, routes, &id); err != nil { return err + } else { + d.Set("associate_with_cdn_frontdoor_route_id", route) } - - d.Set("associate_with_cdn_frontdoor_route_id", routes[0].(string)) - } else { - d.Set("associate_with_cdn_frontdoor_route_id", "") } } - if routes := d.Get("associate_with_cdn_frontdoor_route_ids").([]interface{}); len(routes) > 0 { - if err := hasDuplicateRoute(routes); err != nil { - return err - } - - if err := validateCustomDomainRoutesProfile(routes, &id); err != nil { - return err - } - + // NOTE: To associate a custom domain with more than one route, you must also make sure that all of the routes point to the same endpoint + // NOTE: I also now have to wait until all of the front door custom domains are created befor I move on here? + if routes := d.Get("associate_with_cdn_frontdoor_route_ids").([]interface{}); len(routes) != 0 { if err = addCustomDomainAssociationToRoutes(d, meta, routes, &id); err != nil { return err + } else { + d.Set("associate_with_cdn_frontdoor_route_ids", routes) } - - d.Set("associate_with_cdn_frontdoor_route_ids", routes) } return resourceCdnFrontDoorCustomDomainRead(d, meta) @@ -289,6 +290,16 @@ func resourceCdnFrontDoorCustomDomainRead(d *pluginsdk.ResourceData, meta interf } } + if !features.FourPointOhBeta() { + if route := d.Get("associate_with_cdn_frontdoor_route_id").(string); route == "" { + d.Set("associate_with_cdn_frontdoor_route_id", "") + } + } + + if routes := d.Get("associate_with_cdn_frontdoor_route_ids").([]interface{}); len(routes) == 0 { + d.Set("associate_with_cdn_frontdoor_route_ids", []interface{}{}) + } + return nil } @@ -302,17 +313,19 @@ func resourceCdnFrontDoorCustomDomainUpdate(d *pluginsdk.ResourceData, meta inte return err } - // validate the associations first... + // validate the associations first for common errors... if !features.FourPointOhBeta() { - if routes := []interface{}{d.Get("associate_with_cdn_frontdoor_route_id")}; len(routes) > 0 { - if err := validateCustomDomainRoutesProfile(routes, id); err != nil { - return err + if route := d.Get("associate_with_cdn_frontdoor_route_id").(string); route != "" { + routes := []interface{}{route} + + if err := validateCustomDomainRoutesProfileAndEndpoints(routes, id); err != nil { + return fmt.Errorf("azurerm_cdn_frontdoor_custom_domain: the 'associate_with_cdn_frontdoor_route_id' field is invalid: %+v", err) } } } - if routes := d.Get("associate_with_cdn_frontdoor_route_ids").([]interface{}); len(routes) > 0 { - if err := validateCustomDomainRoutesProfile(routes, id); err != nil { + if routes := d.Get("associate_with_cdn_frontdoor_route_ids").([]interface{}); len(routes) != 0 { + if err := validateCustomDomainRoutesProfileAndEndpoints(routes, id); err != nil { return fmt.Errorf("azurerm_cdn_frontdoor_custom_domain: the 'associate_with_cdn_frontdoor_route_ids' field is invalid: %+v", err) } } @@ -368,116 +381,90 @@ func resourceCdnFrontDoorCustomDomainUpdate(d *pluginsdk.ResourceData, meta inte // Now that the Custom Domain has been updated we need to ensure the referential integrity of the route resource // and associate/unassociate the custom domain with the route(s), if that field was defined/removed... + if !features.FourPointOhBeta() { - if d.HasChange("associate_with_cdn_frontdoor_route_id") { - old, new := d.GetChange("associate_with_cdn_frontdoor_route_id") - oldRouteValue := old.(string) - newRouteValue := new.(string) + if route := d.Get("associate_with_cdn_frontdoor_route_id").(string); route != "" { + if d.HasChange("associate_with_cdn_frontdoor_route_id") { + old, new := d.GetChange("associate_with_cdn_frontdoor_route_id") + oldRoute := []interface{}{old.(string)} + newRoute := []interface{}{new.(string)} + + switch { + case (len(oldRoute) == 0 && len(newRoute) != 0): + // Add + if err := addCustomDomainAssociationToRoutes(d, meta, newRoute, id); err != nil { + return err + } - switch { - case (oldRouteValue == "" && newRouteValue != ""): - // Add - routes := []interface{}{oldRouteValue} + d.Set("associate_with_cdn_frontdoor_route_id", new.(string)) - // add the association to the new route... - if err := addCustomDomainAssociationToRoutes(d, meta, routes, id); err != nil { - return err - } + case (len(oldRoute) != 0 && len(newRoute) == 0): + // Remove + if err := removeCustomDomainAssociationFromRoutes(d, meta, newRoute, id); err != nil { + return err + } - case (oldRouteValue != "" && newRouteValue == ""): - // Remove - routes := []interface{}{oldRouteValue} + d.Set("associate_with_cdn_frontdoor_route_id", "") - // remove the association from the old route.. - if err := removeCustomDomainAssociationFromRoutes(d, meta, routes, id); err != nil { - return err - } + case (len(oldRoute) != 0 && len(newRoute) != 0 && !strings.EqualFold(old.(string), new.(string))): + // Swap + if err = removeCustomDomainAssociationFromRoutes(d, meta, oldRoute, id); err != nil { + return err + } - d.Set("associate_with_cdn_frontdoor_route_id", "") + d.Set("associate_with_cdn_frontdoor_route_id", "") - case (oldRouteValue != "" && newRouteValue != "" && !strings.EqualFold(oldRouteValue, newRouteValue)): - // Swap - routes := []interface{}{oldRouteValue} + // add the association to the new route... + if err = addCustomDomainAssociationToRoutes(d, meta, newRoute, id); err != nil { + return err + } - // remove the association from the old route.. - if err = removeCustomDomainAssociationFromRoutes(d, meta, routes, id); err != nil { - return err + d.Set("associate_with_cdn_frontdoor_route_id", new.(string)) } + } + } + } - d.Set("associate_with_cdn_frontdoor_route_id", "") - routes = []interface{}{newRouteValue} + if d.HasChange("associate_with_cdn_frontdoor_route_ids") { + if routes := d.Get("associate_with_cdn_frontdoor_route_ids").([]interface{}); len(routes) != 0 { + old, new := d.GetChange("associate_with_cdn_frontdoor_route_ids") + oldRoutes := old.([]interface{}) + newRoutes := new.([]interface{}) - // add the association to the new route... - if err = addCustomDomainAssociationToRoutes(d, meta, routes, id); err != nil { + switch { + case (len(oldRoutes) == 0 && len(newRoutes) != 0): + // Add + if err = addCustomDomainAssociationToRoutes(d, meta, newRoutes, id); err != nil { return err } - d.Set("associate_with_cdn_frontdoor_route_id", newRouteValue) - } - } - } + d.Set("associate_with_cdn_frontdoor_route_ids", newRoutes) - if d.HasChange("associate_with_cdn_frontdoor_route_ids") { - old, new := d.GetChange("associate_with_cdn_frontdoor_route_ids") - oldRoutes := old.([]interface{}) - newRoutes := new.([]interface{}) - - switch { - case (len(oldRoutes) == 0 && len(newRoutes) > 0): - // Add - err = addCustomDomainAssociationToRoutes(d, meta, newRoutes, id) - if err != nil { - return err - } - case (len(oldRoutes) > 0 && len(newRoutes) == 0): - // Remove the custom domain from all of the previously associated routes... - err = removeCustomDomainAssociationFromRoutes(d, meta, oldRoutes, id) - if err != nil { - return err - } + case (len(oldRoutes) != 0 && len(newRoutes) == 0): + // Remove + if err = removeCustomDomainAssociationFromRoutes(d, meta, oldRoutes, id); err != nil { + return err + } + + d.Set("associate_with_cdn_frontdoor_route_ids", []interface{}{}) - d.Set("associate_with_cdn_frontdoor_route_ids", newRoutes) - - case (len(oldRoutes) > 0 && len(newRoutes) > 0): - // Remove(e.g. Swap): here I need to find out what was in the old list and is not in the new list, - // those are the routes I need to remove this custom domain from... - - // find the delta between the old and the new lists... - var removeDelta []interface{} - for _, nr := range newRoutes { - var found bool - var removeRoute interface{} - for _, or := range oldRoutes { - removeRoute = or - if strings.EqualFold(or.(string), nr.(string)) { - // they are in both lists so ignore it... - found = true - break + case (len(oldRoutes) != 0 && len(newRoutes) != 0): + // Swap + if removeRoutes, sharedRoutes := getRemoveRoutesDelta(oldRoutes, newRoutes); len(removeRoutes) != 0 { + if err = removeCustomDomainAssociationFromRoutes(d, meta, removeRoutes, id); err != nil { + return err } - } - // I did not find a route in the new list that is in the old route list so I need to disassociate that route with this custom domain... - if !found { - removeDelta = append(removeDelta, removeRoute) + d.Set("associate_with_cdn_frontdoor_route_ids", sharedRoutes) } - } - // delta now contains the list of all the routes that were not in our new list of routes that were in the old list of routes... - if len(removeDelta) > 0 { - err = removeCustomDomainAssociationFromRoutes(d, meta, removeDelta, id) - if err != nil { + if err = addCustomDomainAssociationToRoutes(d, meta, newRoutes, id); err != nil { return err } - } - // do not need to do the add delta as the addCustomDomainAssociationToRoutes figures that out for us automatically... - err = addCustomDomainAssociationToRoutes(d, meta, newRoutes, id) - if err != nil { - return err + d.Set("associate_with_cdn_frontdoor_route_ids", newRoutes) } } - - d.Set("associate_with_cdn_frontdoor_route_ids", newRoutes) } return resourceCdnFrontDoorCustomDomainRead(d, meta) @@ -496,9 +483,8 @@ func resourceCdnFrontDoorCustomDomainDelete(d *pluginsdk.ResourceData, meta inte // NOTE: If the custom domain is still associated with a route you cannot delete it // you must first update the route to remove the association with the custom domain... if !features.FourPointOhBeta() { - if route := []interface{}{d.Get("associate_with_cdn_frontdoor_route_id")}; len(route) > 0 { + if route := d.Get("associate_with_cdn_frontdoor_route_id").(string); route != "" { routes := []interface{}{route} - // remove the association from the old route.. if err := removeCustomDomainAssociationFromRoutes(d, meta, routes, id); err != nil { return err @@ -506,8 +492,7 @@ func resourceCdnFrontDoorCustomDomainDelete(d *pluginsdk.ResourceData, meta inte } } - routes := d.Get("associate_with_cdn_frontdoor_route_ids").([]interface{}) - if len(routes) > 0 { + if routes := d.Get("associate_with_cdn_frontdoor_route_ids").([]interface{}); len(routes) != 0 { // remove the association from the old route.. if err := removeCustomDomainAssociationFromRoutes(d, meta, routes, id); err != nil { return err diff --git a/internal/services/cdn/cdn_frontdoor_helpers.go b/internal/services/cdn/cdn_frontdoor_helpers.go index f4c830567ff3..a2495c1f72cf 100644 --- a/internal/services/cdn/cdn_frontdoor_helpers.go +++ b/internal/services/cdn/cdn_frontdoor_helpers.go @@ -247,7 +247,7 @@ func sliceRemoveString(input []interface{}, value string) []interface{} { return out } -func checkIfRouteExists(d *pluginsdk.ResourceData, meta interface{}, id *parse.FrontDoorRouteId, resourceName string) ([]interface{}, *cdn.RouteProperties, error) { +func getRouteProperties(d *pluginsdk.ResourceData, meta interface{}, id *parse.FrontDoorRouteId, resourceName string) ([]interface{}, *cdn.RouteProperties, error) { client := meta.(*clients.Client).Cdn.FrontDoorRoutesClient ctx, routeCancel := timeouts.ForUpdate(meta.(*clients.Client).StopContext, d) defer routeCancel() @@ -269,33 +269,29 @@ func checkIfRouteExists(d *pluginsdk.ResourceData, meta interface{}, id *parse.F } func addCustomDomainAssociationToRoutes(d *pluginsdk.ResourceData, meta interface{}, route []interface{}, customDomainID *parse.FrontDoorCustomDomainId) error { - // NOTE: This is very inefficient because it will update the route multipule times to and multiple domains... fix this... for _, v := range route { - route, err := routeIDWithErrorTxt(v.(string)) - if err != nil { - return err - } - - // lock the route resource for update... - locks.ByName(route.RouteName, cdnFrontDoorRouteResourceName) - defer locks.UnlockByName(route.RouteName, cdnFrontDoorRouteResourceName) - - // Check to see if the route still exists or not... - // NOTE: the custom domains that are returned are the ones from the route GET call... - // NOTE: cdnFrontDoorRouteResourceName is defined in the "cdn_frontdoor_route_disable_link_to_default_domain_resource" file - customDomains, props, err := checkIfRouteExists(d, meta, route, cdnFrontDoorCustomDomainResourceName) - if err != nil { + if route, err := routeIDWithErrorTxt(v.(string)); err != nil { return err - } - - isAssociated := sliceContainsString(customDomains, customDomainID.ID()) + } else { + // lock the route resource for update... + locks.ByName(route.RouteName, cdnFrontDoorRouteResourceName) + defer locks.UnlockByName(route.RouteName, cdnFrontDoorRouteResourceName) - // if it is not associated update the route to add the association... - if !isAssociated { - err := updateRouteAssociations(d, meta, route, customDomains, props, customDomainID) + // Check to see if the route still exists or not... + customDomains, props, err := getRouteProperties(d, meta, route, cdnFrontDoorCustomDomainResourceName) if err != nil { return err } + + isAssociated := sliceContainsString(customDomains, customDomainID.ID()) + + // if it is not associated update the route to add the association... + if !isAssociated { + err := updateRouteAssociations(d, meta, route, customDomains, props, customDomainID) + if err != nil { + return err + } + } } } @@ -304,32 +300,30 @@ func addCustomDomainAssociationToRoutes(d *pluginsdk.ResourceData, meta interfac func removeCustomDomainAssociationFromRoutes(d *pluginsdk.ResourceData, meta interface{}, route []interface{}, customDomainID *parse.FrontDoorCustomDomainId) error { for _, v := range route { - route, err := routeIDWithErrorTxt(v.(string)) - if err != nil { - return err - } - - // lock the route resource for update... - locks.ByName(route.RouteName, cdnFrontDoorRouteResourceName) - defer locks.UnlockByName(route.RouteName, cdnFrontDoorRouteResourceName) - - // Check to see if the route still exists or not... - // NOTE: cdnFrontDoorRouteResourceName is defined in the "cdn_frontdoor_route_disable_link_to_default_domain_resource" file - customDomains, props, err := checkIfRouteExists(d, meta, route, cdnFrontDoorCustomDomainResourceName) - if err != nil { + if route, err := routeIDWithErrorTxt(v.(string)); err != nil { return err - } - - // Check to make sure the custom domain is still associated with the route - isAssociated := sliceContainsString(customDomains, customDomainID.ID()) + } else { + // lock the route resource for update... + locks.ByName(route.RouteName, cdnFrontDoorRouteResourceName) + defer locks.UnlockByName(route.RouteName, cdnFrontDoorRouteResourceName) - if isAssociated { - // it is, now removed the association... - newDomains := sliceRemoveString(customDomains, customDomainID.ID()) - err := updateRouteAssociations(d, meta, route, newDomains, props, customDomainID) + // Check to see if the route still exists or not... + // NOTE: cdnFrontDoorRouteResourceName is defined in the "cdn_frontdoor_route_disable_link_to_default_domain_resource" file + customDomains, props, err := getRouteProperties(d, meta, route, cdnFrontDoorCustomDomainResourceName) if err != nil { return err } + + // Check to make sure the custom domain is still associated with the route + isAssociated := sliceContainsString(customDomains, customDomainID.ID()) + + if isAssociated { + // it is, now removed the association... + newDomains := sliceRemoveString(customDomains, customDomainID.ID()) + if err := updateRouteAssociations(d, meta, route, newDomains, props, customDomainID); err != nil { + return err + } + } } } @@ -389,7 +383,7 @@ func validateCustomDomanLinkToDefaultDomainState(resourceCustomDomains []interfa } if len(wrongProfile) > 0 { - return fmt.Errorf("the following CDN Front Door Custom Domain(s) do not belong to the expected CDN Front Door Profile(Name: %q). Please remove the following CDN Front Door Custom Domain(s) from your CDN Route Disable Link To Default Domain configuration: %s", routeProfile, strings.Join(wrongProfile, ", ")) + return fmt.Errorf("the following CDN FrontDoor Custom Domain(s) do not belong to the expected CDN FrontDoor Profile(Name: %q). Please remove the following CDN FrontDoor Custom Domain(s) from your CDN Route Disable Link To Default Domain configuration: %s", routeProfile, strings.Join(wrongProfile, ", ")) } // Make sure the resource is referencing all of the custom domains that are associated with the route... @@ -408,7 +402,7 @@ func validateCustomDomanLinkToDefaultDomainState(resourceCustomDomains []interfa } if len(missingDomains) > 0 { - return fmt.Errorf("does not contain all of the CDN Front Door Custom Domains that are associated with the CDN Front Door Route(Name: %q). Please add the following CDN Front Door Custom Domain(s) to your CDN Route Disable Link To Default Domain configuration: %s", routeName, strings.Join(missingDomains, ", ")) + return fmt.Errorf("does not contain all of the CDN FrontDoor Custom Domains that are associated with the CDN FrontDoor Route(Name: %q). Please add the following CDN FrontDoor Custom Domain(s) to your CDN Route Disable Link To Default Domain configuration: %s", routeName, strings.Join(missingDomains, ", ")) } // Make sure all of the custom domains that are referenced by the resource are actually associated with the route... @@ -426,56 +420,102 @@ func validateCustomDomanLinkToDefaultDomainState(resourceCustomDomains []interfa } if len(notAssociated) > 0 { - return fmt.Errorf("contains CDN Front Door Custom Domains that are not associated with the CDN Front Door Route(Name: %q). Please remove the following CDN Front Door Custom Domain(s) from your CDN Route Disable Link To Default Domain configuration: %s", routeName, strings.Join(notAssociated, ", ")) + return fmt.Errorf("contains CDN FrontDoor Custom Domains that are not associated with the CDN FrontDoor Route(Name: %q). Please remove the following CDN FrontDoor Custom Domain(s) from your CDN Route Disable Link To Default Domain configuration: %s", routeName, strings.Join(notAssociated, ", ")) } return nil } -func validateCustomDomainRoutesProfile(routes []interface{}, customDomainID *parse.FrontDoorCustomDomainId) error { - for _, route := range routes { - routeId, err := routeIDWithErrorTxt(route.(string)) - if err != nil { +// Validates that the CDN FrontDoor Custom Domain can be associated with the CDN FrontDoor Route or not +func validateCustomDomainRoutesProfileAndEndpoints(routes []interface{}, customDomainID *parse.FrontDoorCustomDomainId) error { + if len(routes) > 1 { + // check for duplicates... + if err := hasDuplicateRoute(routes); err != nil { return err } + } - if customDomainID.ProfileName != routeId.ProfileName { - return fmt.Errorf("the Front Door Custom Domain(Name: %q, Profile: %q) and the Front Door Route(Name: %q, Profile: %q) must belong to the same Front Door Profile", customDomainID.CustomDomainName, customDomainID.ProfileName, routeId.RouteName, routeId.ProfileName) + for i, route := range routes { + var routeId *parse.FrontDoorRouteId + + // validate route and custom domain profiles match... + if v, err := routeIDWithErrorTxt(route.(string)); err != nil { + return err + } else { + routeId = v + if customDomainID.ProfileName != routeId.ProfileName { + return fmt.Errorf("the CDN FrontDoor Custom Domain(Name: %q, Profile: %q) and the CDN FrontDoor Route(Name: %q, Profile: %q) must belong to the same CDN FrontDoor Profile", customDomainID.CustomDomainName, customDomainID.ProfileName, routeId.RouteName, routeId.ProfileName) + } + } + + // validate all routes are using the same endpoint... + for t, nextRoute := range routes { + if i == t { + continue + } + + if nextRouteId, err := routeIDWithErrorTxt(nextRoute.(string)); err != nil { + return err + } else { + if routeId.AfdEndpointName != nextRouteId.AfdEndpointName { + return fmt.Errorf("the CDN FrontDoor Route(Name: %q) and CDN FrontDoor Route(Name: %q) do not reference the same CDN FrontDoor Endpoint(Name: %q), all CDN FrontDoor Routes must reference the same CDN FrontDoor Endpoint %q to associate this CDN FrontDoor Custom Domain with more than one CDN FrontDoor Route", routeId.RouteName, nextRouteId.RouteName, routeId.AfdEndpointName, routeId.RouteName) + } + } } } return nil } +// Returns a verbose CDN FrontDoor Route parse error message func routeIDWithErrorTxt(route string) (*parse.FrontDoorRouteId, error) { routeId, err := parse.FrontDoorRouteID(route) if err != nil { - return nil, fmt.Errorf("unable to parse CDN FrontDoor Route ID: %+v", err) + return nil, fmt.Errorf("unable to parse CDN FrontDoor Route ID %q [validateCustomDomainRoutesProfileAndEndpoints:first loop]: %+v", route, err) } return routeId, nil } -func customDomainIDWithErrorTxt(route string) (*parse.FrontDoorCustomDomainId, error) { - customDomainId, err := parse.FrontDoorCustomDomainID(route) +// Returns a verbose CDN FrontDoor Custom Domain parse error message +func customDomainIDWithErrorTxt(customDomain string) (*parse.FrontDoorCustomDomainId, error) { + customDomainId, err := parse.FrontDoorCustomDomainID(customDomain) if err != nil { - return nil, fmt.Errorf("unable to parse CDN FrontDoor Custom Domain ID: %+v", err) + return nil, fmt.Errorf("unable to parse CDN FrontDoor Custom Domain ID %q: %+v", customDomain, err) } return customDomainId, nil } -// checks to make sure the list of routes and the custom domain belong to the same profile -func hasDuplicateRoute(route []interface{}) error { +// Checks to make sure the list of CDN FrontDoor Routes does not contain duplicate entries +func hasDuplicateRoute(routes []interface{}) error { k := make(map[string]bool) - for _, v := range route { + for _, v := range routes { if _, d := k[strings.ToLower(v.(string))]; !d { k[strings.ToLower(v.(string))] = true } else { - return fmt.Errorf("duplicate CDN FrontDoor Route, please remove the CDN FrontDoor Route(ID: %q) from your configuration file", v.(string)) + return fmt.Errorf("duplicate CDN FrontDoor Route detected, please remove all duplivate entries for the CDN FrontDoor Route(ID: %q) from your 'azurerm_cdn_frontdoor_custom_domain' configuration block", v.(string)) } } return nil } + +// Determines what CDN FrontDoor Routes need to be removed/disassociated from this CDN FrontDoor Custom Domain +func getRemoveRoutesDelta(oldRoutes []interface{}, newRoutes []interface{}) ([]interface{}, []interface{}) { + remove := make([]interface{}, 0) + shared := make([]interface{}, 0) + + // just find what old routes are not in the new route list... + for _, oldRoute := range oldRoutes { + if !sliceContainsString(newRoutes, oldRoute.(string)) { + remove = append(remove, oldRoute.(string)) + } else { + shared = append(shared, oldRoute.(string)) + } + + } + + return remove, shared +} From d17d5ccdd67a8b653a0ea1ccef1bbe92dc2f0834 Mon Sep 17 00:00:00 2001 From: Jeffrey Cline <20408400+WodansSon@users.noreply.github.com> Date: Mon, 3 Oct 2022 00:47:44 -0600 Subject: [PATCH 04/58] Fix lint error... --- internal/services/cdn/cdn_frontdoor_helpers.go | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/internal/services/cdn/cdn_frontdoor_helpers.go b/internal/services/cdn/cdn_frontdoor_helpers.go index a2495c1f72cf..14fa5262d8b3 100644 --- a/internal/services/cdn/cdn_frontdoor_helpers.go +++ b/internal/services/cdn/cdn_frontdoor_helpers.go @@ -287,8 +287,7 @@ func addCustomDomainAssociationToRoutes(d *pluginsdk.ResourceData, meta interfac // if it is not associated update the route to add the association... if !isAssociated { - err := updateRouteAssociations(d, meta, route, customDomains, props, customDomainID) - if err != nil { + if err := updateRouteAssociations(d, meta, route, customDomains, props, customDomainID); err != nil { return err } } @@ -456,7 +455,7 @@ func validateCustomDomainRoutesProfileAndEndpoints(routes []interface{}, customD if nextRouteId, err := routeIDWithErrorTxt(nextRoute.(string)); err != nil { return err - } else { + } else if err == nil { if routeId.AfdEndpointName != nextRouteId.AfdEndpointName { return fmt.Errorf("the CDN FrontDoor Route(Name: %q) and CDN FrontDoor Route(Name: %q) do not reference the same CDN FrontDoor Endpoint(Name: %q), all CDN FrontDoor Routes must reference the same CDN FrontDoor Endpoint %q to associate this CDN FrontDoor Custom Domain with more than one CDN FrontDoor Route", routeId.RouteName, nextRouteId.RouteName, routeId.AfdEndpointName, routeId.RouteName) } From f8d3b0d488395bd38a5b5b28fa81686594c7b990 Mon Sep 17 00:00:00 2001 From: Jeffrey Cline <20408400+WodansSon@users.noreply.github.com> Date: Wed, 5 Oct 2022 02:03:31 -0600 Subject: [PATCH 05/58] Fix case sensitivity and move toward association --- .../cdn_frontdoor_custom_domain_resource.go | 332 ++++++++---------- .../cdn/cdn_frontdoor_endpoint_resource.go | 8 +- .../services/cdn/cdn_frontdoor_helpers.go | 255 +++++++++----- .../cdn_frontdoor_origin_group_resource.go | 8 +- .../cdn/cdn_frontdoor_origin_resource.go | 22 +- .../cdn/cdn_frontdoor_profile_resource.go | 6 +- ...disable_link_to_default_domain_resource.go | 6 +- .../cdn/cdn_frontdoor_route_resource.go | 99 ++++-- .../cdn/cdn_frontdoor_rule_resource.go | 8 +- .../cdn/cdn_frontdoor_rule_set_resource.go | 6 +- .../cdn/cdn_frontdoor_secret_resource.go | 6 +- .../cdn_frontdoor_security_policy_resource.go | 6 +- 12 files changed, 424 insertions(+), 338 deletions(-) diff --git a/internal/services/cdn/cdn_frontdoor_custom_domain_resource.go b/internal/services/cdn/cdn_frontdoor_custom_domain_resource.go index e067c046ca36..cbcf035609f6 100644 --- a/internal/services/cdn/cdn_frontdoor_custom_domain_resource.go +++ b/internal/services/cdn/cdn_frontdoor_custom_domain_resource.go @@ -2,12 +2,10 @@ package cdn import ( "fmt" - "strings" "time" "github.com/Azure/azure-sdk-for-go/services/cdn/mgmt/2021-06-01/cdn" dnsValidate "github.com/hashicorp/go-azure-sdk/resource-manager/dns/2018-05-01/zones" - "github.com/hashicorp/terraform-provider-azurerm/helpers/tf" "github.com/hashicorp/terraform-provider-azurerm/internal/clients" "github.com/hashicorp/terraform-provider-azurerm/internal/features" "github.com/hashicorp/terraform-provider-azurerm/internal/services/cdn/parse" @@ -19,7 +17,7 @@ import ( ) func resourceCdnFrontDoorCustomDomain() *pluginsdk.Resource { - return &pluginsdk.Resource{ + resource := &pluginsdk.Resource{ Create: resourceCdnFrontDoorCustomDomainCreate, Read: resourceCdnFrontDoorCustomDomainRead, Update: resourceCdnFrontDoorCustomDomainUpdate, @@ -55,27 +53,13 @@ func resourceCdnFrontDoorCustomDomain() *pluginsdk.Resource { ValidateFunc: validate.FrontDoorProfileID, }, - // NOTE: I need the reference to ensure the correct destroy order - // this will also offload the task of maintaining the custom domain association - // IDs in the route resource to the custom domains themselves... - "associate_with_cdn_frontdoor_route_id": { - Type: pluginsdk.TypeString, - Optional: true, - Computed: !features.FourPointOhBeta(), - Deprecated: "'associate_with_cdn_frontdoor_route_id' has been deprecated in favour of 'associate_with_cdn_frontdoor_route_ids' and will be removed in version 4.0 of the AzureRM provider", - ConflictsWith: func() []string { - if !features.FourPointOhBeta() { - return []string{"associate_with_cdn_frontdoor_route_ids"} - } - return []string{} - }(), - ValidateFunc: validate.FrontDoorRouteID, - }, - - "associate_with_cdn_frontdoor_route_ids": { + // NOTE: Was afraid of this "Error: Cycle: azurerm_cdn_frontdoor_custom_domain.wodan, azurerm_cdn_frontdoor_route.wodan" + // have to create a 'azurerm_cdn_frontdoor_custom_domain_routes_association' resource to manage the associations between + // the routes and the custom domains for delete/destroy operation... + "cdn_frontdoor_route_ids": { Type: pluginsdk.TypeList, Optional: true, - Computed: !features.FourPointOhBeta(), + ConflictsWith: func() []string { if !features.FourPointOhBeta() { return []string{"associate_with_cdn_frontdoor_route_id"} @@ -152,6 +136,23 @@ func resourceCdnFrontDoorCustomDomain() *pluginsdk.Resource { }, }, } + + if !features.FourPointOhBeta() { + resource.Schema["associate_with_cdn_frontdoor_route_id"] = &pluginsdk.Schema{ + Type: pluginsdk.TypeString, + Optional: true, + Deprecated: "'associate_with_cdn_frontdoor_route_id' is no longer used and and will be removed in version 4.0 of the AzureRM provider. Please use the 'cdn_frontdoor_custom_domains_ids' field in the 'cdn_frontdoor_route' resource to control the CDN FrontDoor Custom Domain association(s) with the CDN FrontDoor Route", + ConflictsWith: func() []string { + if !features.FourPointOhBeta() { + return []string{"cdn_frontdoor_route_ids"} + } + return []string{} + }(), + ValidateFunc: validate.FrontDoorRouteID, + } + } + + return resource } func resourceCdnFrontDoorCustomDomainCreate(d *pluginsdk.ResourceData, meta interface{}) error { @@ -159,37 +160,17 @@ func resourceCdnFrontDoorCustomDomainCreate(d *pluginsdk.ResourceData, meta inte ctx, cancel := timeouts.ForCreate(meta.(*clients.Client).StopContext, d) defer cancel() - profileId, err := parse.FrontDoorProfileID(d.Get("cdn_frontdoor_profile_id").(string)) + profileId, err := parse.FrontDoorProfileIDInsensitively(d.Get("cdn_frontdoor_profile_id").(string)) if err != nil { return err } id := parse.NewFrontDoorCustomDomainID(profileId.SubscriptionId, profileId.ResourceGroup, profileId.ProfileName, d.Get("name").(string)) - existing, err := client.Get(ctx, id.ResourceGroup, id.ProfileName, id.CustomDomainName) - if err != nil { - if !utils.ResponseWasNotFound(existing.Response) { - return fmt.Errorf("checking for existing %s: %+v", id, err) - } - } - - if !utils.ResponseWasNotFound(existing.Response) { - return tf.ImportAsExistsError("azurerm_cdn_frontdoor_custom_domain", id.ID()) - } - - // do the validation first on the deprecated field... - if !features.FourPointOhBeta() { - if route := d.Get("associate_with_cdn_frontdoor_route_id").(string); route != "" { - routes := []interface{}{route} - if err := validateCustomDomainRoutesProfileAndEndpoints(routes, &id); err != nil { - return err - } - } - } - - // do the validation on the 4.0 field... - if routes := d.Get("associate_with_cdn_frontdoor_route_ids").([]interface{}); len(routes) != 0 { - if err := validateCustomDomainRoutesProfileAndEndpoints(routes, &id); err != nil { + // validate the routes... + routes := d.Get("cdn_frontdoor_route_ids").([]interface{}) + if len(routes) != 0 { + if err := validateCustomDomainRoutes(routes, &id); err != nil { return err } } @@ -224,29 +205,30 @@ func resourceCdnFrontDoorCustomDomainCreate(d *pluginsdk.ResourceData, meta inte } d.SetId(id.ID()) + d.Set("cdn_frontdoor_route_ids", routes) // Associate the custom domain with the route, if that field was passed... - if !features.FourPointOhBeta() { - if route := d.Get("associate_with_cdn_frontdoor_route_id").(string); route != "" { - routes := []interface{}{route} - - if err = addCustomDomainAssociationToRoutes(d, meta, routes, &id); err != nil { - return err - } else { - d.Set("associate_with_cdn_frontdoor_route_id", route) - } - } - } - - // NOTE: To associate a custom domain with more than one route, you must also make sure that all of the routes point to the same endpoint - // NOTE: I also now have to wait until all of the front door custom domains are created befor I move on here? - if routes := d.Get("associate_with_cdn_frontdoor_route_ids").([]interface{}); len(routes) != 0 { - if err = addCustomDomainAssociationToRoutes(d, meta, routes, &id); err != nil { - return err - } else { - d.Set("associate_with_cdn_frontdoor_route_ids", routes) - } - } + // if !features.FourPointOhBeta() { + // if route := d.Get("associate_with_cdn_frontdoor_route_id").(string); route != "" { + // routes := []interface{}{route} + + // if err = addCustomDomainAssociationToRoutes(d, meta, routes, &id); err != nil { + // return err + // } else { + // d.Set("associate_with_cdn_frontdoor_route_id", route) + // } + // } + // } + + // // NOTE: To associate a custom domain with more than one route, you must also make sure that all of the routes point to the same endpoint + // // NOTE: I also now have to wait until all of the front door custom domains are created befor I move on here? + // if routes := d.Get("associate_with_cdn_frontdoor_route_ids").([]interface{}); len(routes) != 0 { + // if err = addCustomDomainAssociationToRoutes(d, meta, routes, &id); err != nil { + // return err + // } else { + // d.Set("associate_with_cdn_frontdoor_route_ids", routes) + // } + // } return resourceCdnFrontDoorCustomDomainRead(d, meta) } @@ -290,15 +272,7 @@ func resourceCdnFrontDoorCustomDomainRead(d *pluginsdk.ResourceData, meta interf } } - if !features.FourPointOhBeta() { - if route := d.Get("associate_with_cdn_frontdoor_route_id").(string); route == "" { - d.Set("associate_with_cdn_frontdoor_route_id", "") - } - } - - if routes := d.Get("associate_with_cdn_frontdoor_route_ids").([]interface{}); len(routes) == 0 { - d.Set("associate_with_cdn_frontdoor_route_ids", []interface{}{}) - } + d.Set("cdn_frontdoor_route_ids", d.Get("cdn_frontdoor_route_ids").([]interface{})) return nil } @@ -313,21 +287,17 @@ func resourceCdnFrontDoorCustomDomainUpdate(d *pluginsdk.ResourceData, meta inte return err } - // validate the associations first for common errors... - if !features.FourPointOhBeta() { - if route := d.Get("associate_with_cdn_frontdoor_route_id").(string); route != "" { - routes := []interface{}{route} + // validate the routes... + if d.HasChange("cdn_frontdoor_route_ids") { + routes := d.Get("cdn_frontdoor_route_ids").([]interface{}) - if err := validateCustomDomainRoutesProfileAndEndpoints(routes, id); err != nil { - return fmt.Errorf("azurerm_cdn_frontdoor_custom_domain: the 'associate_with_cdn_frontdoor_route_id' field is invalid: %+v", err) + if len(routes) != 0 { + if err := validateCustomDomainRoutes(routes, id); err != nil { + return fmt.Errorf("azurerm_cdn_frontdoor_custom_domain: the 'cdn_frontdoor_route_ids' field is invalid: %+v", err) } } - } - if routes := d.Get("associate_with_cdn_frontdoor_route_ids").([]interface{}); len(routes) != 0 { - if err := validateCustomDomainRoutesProfileAndEndpoints(routes, id); err != nil { - return fmt.Errorf("azurerm_cdn_frontdoor_custom_domain: the 'associate_with_cdn_frontdoor_route_ids' field is invalid: %+v", err) - } + d.Set("cdn_frontdoor_route_ids", routes) } props := cdn.AFDDomainUpdateParameters{ @@ -382,90 +352,90 @@ func resourceCdnFrontDoorCustomDomainUpdate(d *pluginsdk.ResourceData, meta inte // Now that the Custom Domain has been updated we need to ensure the referential integrity of the route resource // and associate/unassociate the custom domain with the route(s), if that field was defined/removed... - if !features.FourPointOhBeta() { - if route := d.Get("associate_with_cdn_frontdoor_route_id").(string); route != "" { - if d.HasChange("associate_with_cdn_frontdoor_route_id") { - old, new := d.GetChange("associate_with_cdn_frontdoor_route_id") - oldRoute := []interface{}{old.(string)} - newRoute := []interface{}{new.(string)} - - switch { - case (len(oldRoute) == 0 && len(newRoute) != 0): - // Add - if err := addCustomDomainAssociationToRoutes(d, meta, newRoute, id); err != nil { - return err - } - - d.Set("associate_with_cdn_frontdoor_route_id", new.(string)) - - case (len(oldRoute) != 0 && len(newRoute) == 0): - // Remove - if err := removeCustomDomainAssociationFromRoutes(d, meta, newRoute, id); err != nil { - return err - } - - d.Set("associate_with_cdn_frontdoor_route_id", "") - - case (len(oldRoute) != 0 && len(newRoute) != 0 && !strings.EqualFold(old.(string), new.(string))): - // Swap - if err = removeCustomDomainAssociationFromRoutes(d, meta, oldRoute, id); err != nil { - return err - } - - d.Set("associate_with_cdn_frontdoor_route_id", "") - - // add the association to the new route... - if err = addCustomDomainAssociationToRoutes(d, meta, newRoute, id); err != nil { - return err - } - - d.Set("associate_with_cdn_frontdoor_route_id", new.(string)) - } - } - } - } - - if d.HasChange("associate_with_cdn_frontdoor_route_ids") { - if routes := d.Get("associate_with_cdn_frontdoor_route_ids").([]interface{}); len(routes) != 0 { - old, new := d.GetChange("associate_with_cdn_frontdoor_route_ids") - oldRoutes := old.([]interface{}) - newRoutes := new.([]interface{}) - - switch { - case (len(oldRoutes) == 0 && len(newRoutes) != 0): - // Add - if err = addCustomDomainAssociationToRoutes(d, meta, newRoutes, id); err != nil { - return err - } - - d.Set("associate_with_cdn_frontdoor_route_ids", newRoutes) - - case (len(oldRoutes) != 0 && len(newRoutes) == 0): - // Remove - if err = removeCustomDomainAssociationFromRoutes(d, meta, oldRoutes, id); err != nil { - return err - } - - d.Set("associate_with_cdn_frontdoor_route_ids", []interface{}{}) - - case (len(oldRoutes) != 0 && len(newRoutes) != 0): - // Swap - if removeRoutes, sharedRoutes := getRemoveRoutesDelta(oldRoutes, newRoutes); len(removeRoutes) != 0 { - if err = removeCustomDomainAssociationFromRoutes(d, meta, removeRoutes, id); err != nil { - return err - } - - d.Set("associate_with_cdn_frontdoor_route_ids", sharedRoutes) - } - - if err = addCustomDomainAssociationToRoutes(d, meta, newRoutes, id); err != nil { - return err - } - - d.Set("associate_with_cdn_frontdoor_route_ids", newRoutes) - } - } - } + // if !features.FourPointOhBeta() { + // if route := d.Get("associate_with_cdn_frontdoor_route_id").(string); route != "" { + // if d.HasChange("associate_with_cdn_frontdoor_route_id") { + // old, new := d.GetChange("associate_with_cdn_frontdoor_route_id") + // oldRoute := []interface{}{old.(string)} + // newRoute := []interface{}{new.(string)} + + // switch { + // case (len(oldRoute) == 0 && len(newRoute) != 0): + // // Add + // if err := addCustomDomainAssociationToRoutes(d, meta, newRoute, id); err != nil { + // return err + // } + + // d.Set("associate_with_cdn_frontdoor_route_id", new.(string)) + + // case (len(oldRoute) != 0 && len(newRoute) == 0): + // // Remove + // if err := removeCustomDomainAssociationFromRoutes(d, meta, newRoute, id); err != nil { + // return err + // } + + // d.Set("associate_with_cdn_frontdoor_route_id", "") + + // case (len(oldRoute) != 0 && len(newRoute) != 0 && !strings.EqualFold(old.(string), new.(string))): + // // Swap + // if err = removeCustomDomainAssociationFromRoutes(d, meta, oldRoute, id); err != nil { + // return err + // } + + // d.Set("associate_with_cdn_frontdoor_route_id", "") + + // // add the association to the new route... + // if err = addCustomDomainAssociationToRoutes(d, meta, newRoute, id); err != nil { + // return err + // } + + // d.Set("associate_with_cdn_frontdoor_route_id", new.(string)) + // } + // } + // } + // } + + // if d.HasChange("cdn_frontdoor_route_ids") { + // if routes := d.Get("cdn_frontdoor_route_ids").([]interface{}); len(routes) != 0 { + // old, new := d.GetChange("associate_with_cdn_frontdoor_route_ids") + // oldRoutes := old.([]interface{}) + // newRoutes := new.([]interface{}) + + // switch { + // case (len(oldRoutes) == 0 && len(newRoutes) != 0): + // // Add + // if err = addCustomDomainAssociationToRoutes(d, meta, newRoutes, id); err != nil { + // return err + // } + + // d.Set("associate_with_cdn_frontdoor_route_ids", newRoutes) + + // case (len(oldRoutes) != 0 && len(newRoutes) == 0): + // // Remove + // if err = removeCustomDomainAssociationFromRoutes(d, meta, oldRoutes, id); err != nil { + // return err + // } + + // d.Set("associate_with_cdn_frontdoor_route_ids", []interface{}{}) + + // case (len(oldRoutes) != 0 && len(newRoutes) != 0): + // // Swap + // if removeRoutes, sharedRoutes := getRemoveRoutesDelta(oldRoutes, newRoutes); len(removeRoutes) != 0 { + // if err = removeCustomDomainAssociationFromRoutes(d, meta, removeRoutes, id); err != nil { + // return err + // } + + // d.Set("associate_with_cdn_frontdoor_route_ids", sharedRoutes) + // } + + // if err = addCustomDomainAssociationToRoutes(d, meta, newRoutes, id); err != nil { + // return err + // } + + // d.Set("associate_with_cdn_frontdoor_route_ids", newRoutes) + // } + // } + // } return resourceCdnFrontDoorCustomDomainRead(d, meta) } @@ -475,24 +445,14 @@ func resourceCdnFrontDoorCustomDomainDelete(d *pluginsdk.ResourceData, meta inte ctx, cancel := timeouts.ForDelete(meta.(*clients.Client).StopContext, d) defer cancel() - id, err := parse.FrontDoorCustomDomainID(d.Id()) + id, err := parse.FrontDoorCustomDomainIDInsensitively(d.Id()) if err != nil { return err } - // NOTE: If the custom domain is still associated with a route you cannot delete it - // you must first update the route to remove the association with the custom domain... - if !features.FourPointOhBeta() { - if route := d.Get("associate_with_cdn_frontdoor_route_id").(string); route != "" { - routes := []interface{}{route} - // remove the association from the old route.. - if err := removeCustomDomainAssociationFromRoutes(d, meta, routes, id); err != nil { - return err - } - } - } - - if routes := d.Get("associate_with_cdn_frontdoor_route_ids").([]interface{}); len(routes) != 0 { + // NOTE: If the custom domain is still associated with a route you cannot delete the custom domain + // without the service throwing an error. You must first update the route to remove the association... + if routes := d.Get("cdn_frontdoor_route_ids").([]interface{}); len(routes) != 0 { // remove the association from the old route.. if err := removeCustomDomainAssociationFromRoutes(d, meta, routes, id); err != nil { return err diff --git a/internal/services/cdn/cdn_frontdoor_endpoint_resource.go b/internal/services/cdn/cdn_frontdoor_endpoint_resource.go index f05993cd1114..edb5cf5e035f 100644 --- a/internal/services/cdn/cdn_frontdoor_endpoint_resource.go +++ b/internal/services/cdn/cdn_frontdoor_endpoint_resource.go @@ -72,7 +72,7 @@ func resourceCdnFrontDoorEndpointCreate(d *pluginsdk.ResourceData, meta interfac ctx, cancel := timeouts.ForCreate(meta.(*clients.Client).StopContext, d) defer cancel() - profileId, err := parse.FrontDoorProfileID(d.Get("cdn_frontdoor_profile_id").(string)) + profileId, err := parse.FrontDoorProfileIDInsensitively(d.Get("cdn_frontdoor_profile_id").(string)) if err != nil { return err } @@ -117,7 +117,7 @@ func resourceCdnFrontDoorEndpointRead(d *pluginsdk.ResourceData, meta interface{ ctx, cancel := timeouts.ForRead(meta.(*clients.Client).StopContext, d) defer cancel() - id, err := parse.FrontDoorEndpointID(d.Id()) + id, err := parse.FrontDoorEndpointIDInsensitively(d.Id()) if err != nil { return err } @@ -147,7 +147,7 @@ func resourceCdnFrontDoorEndpointUpdate(d *pluginsdk.ResourceData, meta interfac ctx, cancel := timeouts.ForUpdate(meta.(*clients.Client).StopContext, d) defer cancel() - id, err := parse.FrontDoorEndpointID(d.Id()) + id, err := parse.FrontDoorEndpointIDInsensitively(d.Id()) if err != nil { return err } @@ -180,7 +180,7 @@ func resourceCdnFrontDoorEndpointDelete(d *pluginsdk.ResourceData, meta interfac ctx, cancel := timeouts.ForDelete(meta.(*clients.Client).StopContext, d) defer cancel() - id, err := parse.FrontDoorEndpointID(d.Id()) + id, err := parse.FrontDoorEndpointIDInsensitively(d.Id()) if err != nil { return err } diff --git a/internal/services/cdn/cdn_frontdoor_helpers.go b/internal/services/cdn/cdn_frontdoor_helpers.go index 14fa5262d8b3..34b64af1d146 100644 --- a/internal/services/cdn/cdn_frontdoor_helpers.go +++ b/internal/services/cdn/cdn_frontdoor_helpers.go @@ -7,6 +7,7 @@ import ( "github.com/Azure/azure-sdk-for-go/services/cdn/mgmt/2021-06-01/cdn" "github.com/Azure/azure-sdk-for-go/services/frontdoor/mgmt/2020-11-01/frontdoor" "github.com/hashicorp/terraform-provider-azurerm/internal/clients" + "github.com/hashicorp/terraform-provider-azurerm/internal/features" "github.com/hashicorp/terraform-provider-azurerm/internal/locks" "github.com/hashicorp/terraform-provider-azurerm/internal/services/cdn/azuresdkhacks" "github.com/hashicorp/terraform-provider-azurerm/internal/services/cdn/parse" @@ -31,22 +32,21 @@ func expandEnabledBoolToRouteHttpsRedirect(isEnabled bool) cdn.HTTPSRedirect { return cdn.HTTPSRedirectDisabled } -// TODO: May not need these anymore... remove if the association resource tests work... -// func expandEnabledBoolToLinkToDefaultDomain(isEnabled bool) cdn.LinkToDefaultDomain { -// if isEnabled { -// return cdn.LinkToDefaultDomainEnabled -// } +func expandEnabledBoolToLinkToDefaultDomain(isEnabled bool) cdn.LinkToDefaultDomain { + if isEnabled { + return cdn.LinkToDefaultDomainEnabled + } -// return cdn.LinkToDefaultDomainDisabled -// } + return cdn.LinkToDefaultDomainDisabled +} -// func flattenLinkToDefaultDomainToBool(linkToDefaultDomain cdn.LinkToDefaultDomain) bool { -// if len(linkToDefaultDomain) == 0 { -// return false -// } +func flattenLinkToDefaultDomainToBool(linkToDefaultDomain cdn.LinkToDefaultDomain) bool { + if len(linkToDefaultDomain) == 0 { + return false + } -// return linkToDefaultDomain == cdn.LinkToDefaultDomainEnabled -// } + return linkToDefaultDomain == cdn.LinkToDefaultDomainEnabled +} func expandResourceReference(input string) *cdn.ResourceReference { if len(input) == 0 { @@ -268,45 +268,45 @@ func getRouteProperties(d *pluginsdk.ResourceData, meta interface{}, id *parse.F return customDomains, props, nil } -func addCustomDomainAssociationToRoutes(d *pluginsdk.ResourceData, meta interface{}, route []interface{}, customDomainID *parse.FrontDoorCustomDomainId) error { - for _, v := range route { - if route, err := routeIDWithErrorTxt(v.(string)); err != nil { - return err - } else { - // lock the route resource for update... - locks.ByName(route.RouteName, cdnFrontDoorRouteResourceName) - defer locks.UnlockByName(route.RouteName, cdnFrontDoorRouteResourceName) - - // Check to see if the route still exists or not... - customDomains, props, err := getRouteProperties(d, meta, route, cdnFrontDoorCustomDomainResourceName) - if err != nil { - return err - } - - isAssociated := sliceContainsString(customDomains, customDomainID.ID()) - - // if it is not associated update the route to add the association... - if !isAssociated { - if err := updateRouteAssociations(d, meta, route, customDomains, props, customDomainID); err != nil { - return err - } - } - } - } +// func addCustomDomainAssociationToRoutes(d *pluginsdk.ResourceData, meta interface{}, route []interface{}, customDomainID *parse.FrontDoorCustomDomainId) error { +// for _, v := range route { +// if route, err := routeIDWithErrorTxt(v.(string)); err != nil { +// return err +// } else if err == nil { +// // lock the route resource for update... +// locks.ByName(route.RouteName, cdnFrontDoorRouteResourceName) +// defer locks.UnlockByName(route.RouteName, cdnFrontDoorRouteResourceName) + +// // Check to see if the route still exists or not... +// customDomains, props, err := getRouteProperties(d, meta, route, cdnFrontDoorCustomDomainResourceName) +// if err != nil { +// return err +// } + +// isAssociated := sliceContainsString(customDomains, customDomainID.ID()) + +// // if it is not associated update the route to add the association... +// if !isAssociated { +// if err := updateRouteAssociations(d, meta, route, customDomains, props, customDomainID); err != nil { +// return err +// } +// } +// } +// } - return nil -} +// return nil +// } -func removeCustomDomainAssociationFromRoutes(d *pluginsdk.ResourceData, meta interface{}, route []interface{}, customDomainID *parse.FrontDoorCustomDomainId) error { - for _, v := range route { +func removeCustomDomainAssociationFromRoutes(d *pluginsdk.ResourceData, meta interface{}, routes []interface{}, customDomainID *parse.FrontDoorCustomDomainId) error { + for _, v := range routes { if route, err := routeIDWithErrorTxt(v.(string)); err != nil { return err - } else { + } else if err == nil { // lock the route resource for update... locks.ByName(route.RouteName, cdnFrontDoorRouteResourceName) defer locks.UnlockByName(route.RouteName, cdnFrontDoorRouteResourceName) - // Check to see if the route still exists or not... + // Check to see if the route still exists and grab its properties... // NOTE: cdnFrontDoorRouteResourceName is defined in the "cdn_frontdoor_route_disable_link_to_default_domain_resource" file customDomains, props, err := getRouteProperties(d, meta, route, cdnFrontDoorCustomDomainResourceName) if err != nil { @@ -367,71 +367,134 @@ func updateRouteAssociations(d *pluginsdk.ResourceData, meta interface{}, routeI } func validateCustomDomanLinkToDefaultDomainState(resourceCustomDomains []interface{}, routeCustomDomains []interface{}, routeName string, routeProfile string) error { - // Make all of the custom domains belong to the same profile as the route... - wrongProfile := make([]string, 0) + if !features.FourPointOhBeta() { + // Make all of the custom domains belong to the same profile as the route... + wrongProfile := make([]string, 0) - for _, v := range resourceCustomDomains { - customDomain, err := parse.FrontDoorCustomDomainIDInsensitively(v.(string)) - if err != nil { - return err + for _, v := range resourceCustomDomains { + customDomain, err := parse.FrontDoorCustomDomainIDInsensitively(v.(string)) + if err != nil { + return err + } + + if customDomain.ProfileName != routeProfile { + wrongProfile = append(wrongProfile, fmt.Sprintf("%q", customDomain.ID())) + } } - if customDomain.ProfileName != routeProfile { - wrongProfile = append(wrongProfile, fmt.Sprintf("%q", customDomain.ID())) + if len(wrongProfile) > 0 { + return fmt.Errorf("the following CDN FrontDoor Custom Domain(s) do not belong to the expected CDN FrontDoor Profile(Name: %q). Please remove the following CDN FrontDoor Custom Domain(s) from your CDN Route Disable Link To Default Domain configuration: %s", routeProfile, strings.Join(wrongProfile, ", ")) } - } - if len(wrongProfile) > 0 { - return fmt.Errorf("the following CDN FrontDoor Custom Domain(s) do not belong to the expected CDN FrontDoor Profile(Name: %q). Please remove the following CDN FrontDoor Custom Domain(s) from your CDN Route Disable Link To Default Domain configuration: %s", routeProfile, strings.Join(wrongProfile, ", ")) - } + // Make sure the resource is referencing all of the custom domains that are associated with the route... + missingDomains := make([]string, 0) - // Make sure the resource is referencing all of the custom domains that are associated with the route... - missingDomains := make([]string, 0) + for _, v := range routeCustomDomains { + // If this was updated by the portal, it lowercases to resource ID... + customDomain, err := parse.FrontDoorCustomDomainIDInsensitively(v.(string)) + if err != nil { + return fmt.Errorf("unable to parse %q: %+v", v.(string), err) + } - for _, v := range routeCustomDomains { - // If this was updated by the portal, it lowercases to resource ID... - customDomain, err := parse.FrontDoorCustomDomainIDInsensitively(v.(string)) - if err != nil { - return fmt.Errorf("unable to parse %q: %+v", v.(string), err) + if !sliceContainsString(resourceCustomDomains, customDomain.ID()) { + missingDomains = append(missingDomains, fmt.Sprintf("%q", customDomain.ID())) + } } - if !sliceContainsString(resourceCustomDomains, customDomain.ID()) { - missingDomains = append(missingDomains, fmt.Sprintf("%q", customDomain.ID())) + if len(missingDomains) > 0 { + return fmt.Errorf("does not contain all of the CDN FrontDoor Custom Domains that are associated with the CDN FrontDoor Route(Name: %q). Please add the following CDN FrontDoor Custom Domain(s) to your CDN Route Disable Link To Default Domain configuration: %s", routeName, strings.Join(missingDomains, ", ")) } - } - if len(missingDomains) > 0 { - return fmt.Errorf("does not contain all of the CDN FrontDoor Custom Domains that are associated with the CDN FrontDoor Route(Name: %q). Please add the following CDN FrontDoor Custom Domain(s) to your CDN Route Disable Link To Default Domain configuration: %s", routeName, strings.Join(missingDomains, ", ")) + // Make sure all of the custom domains that are referenced by the resource are actually associated with the route... + notAssociated := make([]string, 0) + + for _, v := range resourceCustomDomains { + customDomain, err := parse.FrontDoorCustomDomainIDInsensitively(v.(string)) + if err != nil { + return fmt.Errorf("unable to parse %q: %+v", v.(string), err) + } + + if !sliceContainsString(routeCustomDomains, customDomain.ID()) { + notAssociated = append(notAssociated, fmt.Sprintf("%q", customDomain.ID())) + } + } + + if len(notAssociated) > 0 { + return fmt.Errorf("contains CDN FrontDoor Custom Domains that are not associated with the CDN FrontDoor Route(Name: %q). Please remove the following CDN FrontDoor Custom Domain(s) from your CDN Route Disable Link To Default Domain configuration: %s", routeName, strings.Join(notAssociated, ", ")) + } } - // Make sure all of the custom domains that are referenced by the resource are actually associated with the route... - notAssociated := make([]string, 0) + return nil +} + +func validateRoutesCustomDomanProfile(customDomains []interface{}, routeName string, routeProfile string) error { + // Make all of the custom domains belong to the same profile as the route... + wrongProfile := make([]string, 0) - for _, v := range resourceCustomDomains { + for _, v := range customDomains { customDomain, err := parse.FrontDoorCustomDomainIDInsensitively(v.(string)) if err != nil { - return fmt.Errorf("unable to parse %q: %+v", v.(string), err) + return err } - if !sliceContainsString(routeCustomDomains, customDomain.ID()) { - notAssociated = append(notAssociated, fmt.Sprintf("%q", customDomain.ID())) + if customDomain.ProfileName != routeProfile { + wrongProfile = append(wrongProfile, fmt.Sprintf("%q", customDomain.ID())) } } - if len(notAssociated) > 0 { - return fmt.Errorf("contains CDN FrontDoor Custom Domains that are not associated with the CDN FrontDoor Route(Name: %q). Please remove the following CDN FrontDoor Custom Domain(s) from your CDN Route Disable Link To Default Domain configuration: %s", routeName, strings.Join(notAssociated, ", ")) + if len(wrongProfile) > 0 { + return fmt.Errorf("the following CDN FrontDoor Custom Domain(s) do not belong to the expected CDN FrontDoor Profile(Name: %q). Please remove the following CDN FrontDoor Custom Domain(s) from your CDN FrontDoor Route configuration block: %s", routeProfile, strings.Join(wrongProfile, ", ")) } + // Make sure the resource is referencing all of the custom domains that are associated with the route... + // missingDomains := make([]string, 0) + + // for _, v := range routeCustomDomains { + // // If this was updated by the portal, it lowercases to resource ID... + // customDomain, err := parse.FrontDoorCustomDomainIDInsensitively(v.(string)) + // if err != nil { + // return fmt.Errorf("unable to parse %q: %+v", v.(string), err) + // } + + // if !sliceContainsString(resourceCustomDomains, customDomain.ID()) { + // missingDomains = append(missingDomains, fmt.Sprintf("%q", customDomain.ID())) + // } + // } + + // if len(missingDomains) > 0 { + // return fmt.Errorf("does not contain all of the CDN FrontDoor Custom Domains that are associated with the CDN FrontDoor Route(Name: %q). Please add the following CDN FrontDoor Custom Domain(s) to your CDN Route Disable Link To Default Domain configuration: %s", routeName, strings.Join(missingDomains, ", ")) + // } + + // // Make sure all of the custom domains that are referenced by the resource are actually associated with the route... + // notAssociated := make([]string, 0) + + // for _, v := range resourceCustomDomains { + // customDomain, err := parse.FrontDoorCustomDomainIDInsensitively(v.(string)) + // if err != nil { + // return fmt.Errorf("unable to parse %q: %+v", v.(string), err) + // } + + // if !sliceContainsString(routeCustomDomains, customDomain.ID()) { + // notAssociated = append(notAssociated, fmt.Sprintf("%q", customDomain.ID())) + // } + // } + + // if len(notAssociated) > 0 { + // return fmt.Errorf("contains CDN FrontDoor Custom Domains that are not associated with the CDN FrontDoor Route(Name: %q). Please remove the following CDN FrontDoor Custom Domain(s) from your CDN Route Disable Link To Default Domain configuration: %s", routeName, strings.Join(notAssociated, ", ")) + // } + return nil } // Validates that the CDN FrontDoor Custom Domain can be associated with the CDN FrontDoor Route or not -func validateCustomDomainRoutesProfileAndEndpoints(routes []interface{}, customDomainID *parse.FrontDoorCustomDomainId) error { - if len(routes) > 1 { - // check for duplicates... - if err := hasDuplicateRoute(routes); err != nil { - return err - } +func validateCustomDomainRoutes(routes []interface{}, customDomainID *parse.FrontDoorCustomDomainId) error { + if len(routes) == 0 { + return nil + } + + // check for duplicates... + if err := sliceHasDuplicates(routes, "CDN FrontDoor Route"); err != nil { + return err } for i, route := range routes { @@ -455,12 +518,11 @@ func validateCustomDomainRoutesProfileAndEndpoints(routes []interface{}, customD if nextRouteId, err := routeIDWithErrorTxt(nextRoute.(string)); err != nil { return err - } else if err == nil { - if routeId.AfdEndpointName != nextRouteId.AfdEndpointName { - return fmt.Errorf("the CDN FrontDoor Route(Name: %q) and CDN FrontDoor Route(Name: %q) do not reference the same CDN FrontDoor Endpoint(Name: %q), all CDN FrontDoor Routes must reference the same CDN FrontDoor Endpoint %q to associate this CDN FrontDoor Custom Domain with more than one CDN FrontDoor Route", routeId.RouteName, nextRouteId.RouteName, routeId.AfdEndpointName, routeId.RouteName) - } + } else if err == nil && routeId.AfdEndpointName != nextRouteId.AfdEndpointName { + return fmt.Errorf("the CDN FrontDoor Route(Name: %q) and CDN FrontDoor Route(Name: %q) do not reference the same CDN FrontDoor Endpoint(Name: %q), all CDN FrontDoor Routes must reference the same CDN FrontDoor Endpoint %q to associate this CDN FrontDoor Custom Domain with more than one CDN FrontDoor Route", routeId.RouteName, nextRouteId.RouteName, routeId.AfdEndpointName, routeId.RouteName) } } + } return nil @@ -468,9 +530,9 @@ func validateCustomDomainRoutesProfileAndEndpoints(routes []interface{}, customD // Returns a verbose CDN FrontDoor Route parse error message func routeIDWithErrorTxt(route string) (*parse.FrontDoorRouteId, error) { - routeId, err := parse.FrontDoorRouteID(route) + routeId, err := parse.FrontDoorRouteIDInsensitively(route) if err != nil { - return nil, fmt.Errorf("unable to parse CDN FrontDoor Route ID %q [validateCustomDomainRoutesProfileAndEndpoints:first loop]: %+v", route, err) + return nil, fmt.Errorf("unable to parse CDN FrontDoor Route ID %q: %+v", route, err) } return routeId, nil @@ -478,23 +540,22 @@ func routeIDWithErrorTxt(route string) (*parse.FrontDoorRouteId, error) { // Returns a verbose CDN FrontDoor Custom Domain parse error message func customDomainIDWithErrorTxt(customDomain string) (*parse.FrontDoorCustomDomainId, error) { - customDomainId, err := parse.FrontDoorCustomDomainID(customDomain) - if err != nil { - return nil, fmt.Errorf("unable to parse CDN FrontDoor Custom Domain ID %q: %+v", customDomain, err) + if customDomainId, err := parse.FrontDoorCustomDomainIDInsensitively(customDomain); err != nil { + return nil, fmt.Errorf("unable to parse CDN FrontDoor Custom Domain(ID: %q): %+v", customDomain, err) + } else { + return customDomainId, nil } - - return customDomainId, nil } -// Checks to make sure the list of CDN FrontDoor Routes does not contain duplicate entries -func hasDuplicateRoute(routes []interface{}) error { +// Checks to make sure the list of CDN FrontDoor Custom Domains does not contain duplicate entries +func sliceHasDuplicates(input []interface{}, resouceTxt string) error { k := make(map[string]bool) - for _, v := range routes { + for _, v := range input { if _, d := k[strings.ToLower(v.(string))]; !d { k[strings.ToLower(v.(string))] = true } else { - return fmt.Errorf("duplicate CDN FrontDoor Route detected, please remove all duplivate entries for the CDN FrontDoor Route(ID: %q) from your 'azurerm_cdn_frontdoor_custom_domain' configuration block", v.(string)) + return fmt.Errorf("duplicate %[1]s detected, please remove all duplicate entries for the %[1]s(ID: %q) from your configuration block", resouceTxt, v.(string)) } } diff --git a/internal/services/cdn/cdn_frontdoor_origin_group_resource.go b/internal/services/cdn/cdn_frontdoor_origin_group_resource.go index 92156cee3c9f..31c98a774415 100644 --- a/internal/services/cdn/cdn_frontdoor_origin_group_resource.go +++ b/internal/services/cdn/cdn_frontdoor_origin_group_resource.go @@ -144,7 +144,7 @@ func resourceCdnFrontDoorOriginGroupCreate(d *pluginsdk.ResourceData, meta inter ctx, cancel := timeouts.ForCreate(meta.(*clients.Client).StopContext, d) defer cancel() - profileId, err := parse.FrontDoorProfileID(d.Get("cdn_frontdoor_profile_id").(string)) + profileId, err := parse.FrontDoorProfileIDInsensitively(d.Get("cdn_frontdoor_profile_id").(string)) if err != nil { return err } @@ -188,7 +188,7 @@ func resourceCdnFrontDoorOriginGroupRead(d *pluginsdk.ResourceData, meta interfa ctx, cancel := timeouts.ForRead(meta.(*clients.Client).StopContext, d) defer cancel() - id, err := parse.FrontDoorOriginGroupID(d.Id()) + id, err := parse.FrontDoorOriginGroupIDInsensitively(d.Id()) if err != nil { return err } @@ -226,7 +226,7 @@ func resourceCdnFrontDoorOriginGroupUpdate(d *pluginsdk.ResourceData, meta inter ctx, cancel := timeouts.ForUpdate(meta.(*clients.Client).StopContext, d) defer cancel() - id, err := parse.FrontDoorOriginGroupID(d.Id()) + id, err := parse.FrontDoorOriginGroupIDInsensitively(d.Id()) if err != nil { return err } @@ -270,7 +270,7 @@ func resourceCdnFrontDoorOriginGroupDelete(d *pluginsdk.ResourceData, meta inter ctx, cancel := timeouts.ForDelete(meta.(*clients.Client).StopContext, d) defer cancel() - id, err := parse.FrontDoorOriginGroupID(d.Id()) + id, err := parse.FrontDoorOriginGroupIDInsensitively(d.Id()) if err != nil { return err } diff --git a/internal/services/cdn/cdn_frontdoor_origin_resource.go b/internal/services/cdn/cdn_frontdoor_origin_resource.go index 5dca884460f3..5a4f22c479d5 100644 --- a/internal/services/cdn/cdn_frontdoor_origin_resource.go +++ b/internal/services/cdn/cdn_frontdoor_origin_resource.go @@ -179,7 +179,7 @@ func resourceCdnFrontDoorOriginCreate(d *pluginsdk.ResourceData, meta interface{ ctx, cancel := timeouts.ForCreate(meta.(*clients.Client).StopContext, d) defer cancel() - originGroupId, err := parse.FrontDoorOriginGroupID(d.Get("cdn_frontdoor_origin_group_id").(string)) + originGroupId, err := parse.FrontDoorOriginGroupIDInsensitively(d.Get("cdn_frontdoor_origin_group_id").(string)) if err != nil { return err } @@ -265,7 +265,7 @@ func resourceCdnFrontDoorOriginRead(d *pluginsdk.ResourceData, meta interface{}) ctx, cancel := timeouts.ForRead(meta.(*clients.Client).StopContext, d) defer cancel() - id, err := parse.FrontDoorOriginID(d.Id()) + id, err := parse.FrontDoorOriginIDInsensitively(d.Id()) if err != nil { return err } @@ -309,7 +309,7 @@ func resourceCdnFrontDoorOriginUpdate(d *pluginsdk.ResourceData, meta interface{ ctx, cancel := timeouts.ForUpdate(meta.(*clients.Client).StopContext, d) defer cancel() - id, err := parse.FrontDoorOriginID(d.Id()) + id, err := parse.FrontDoorOriginIDInsensitively(d.Id()) if err != nil { return err } @@ -319,26 +319,33 @@ func resourceCdnFrontDoorOriginUpdate(d *pluginsdk.ResourceData, meta interface{ if d.HasChange("certificate_name_check_enabled") { params.EnforceCertificateNameCheck = utils.Bool(d.Get("certificate_name_check_enabled").(bool)) } + if !features.FourPointOhBeta() { if d.HasChange("health_probes_enabled") { params.EnabledState = expandEnabledBool(d.Get("health_probes_enabled").(bool)) } } + if d.HasChange("enabled") { params.EnabledState = expandEnabledBool(d.Get("enabled").(bool)) } + if d.HasChange("host_name") { params.HostName = utils.String(d.Get("host_name").(string)) } + if d.HasChange("http_port") { params.HTTPPort = utils.Int32(int32(d.Get("http_port").(int))) } + if d.HasChange("https_port") { params.HTTPSPort = utils.Int32(int32(d.Get("https_port").(int))) } + if d.HasChange("origin_host_header") { params.OriginHostHeader = utils.String(d.Get("origin_host_header").(string)) } + if d.HasChange("private_link") { // I need to get the profile SKU so I know if it is valid or not to define a private link as // private links are only allowed in the premium sku... @@ -351,9 +358,11 @@ func resourceCdnFrontDoorOriginUpdate(d *pluginsdk.ResourceData, meta interface{ return fmt.Errorf("retrieving parent %s: %+v", profileId, err) } + if profile.Sku == nil { return fmt.Errorf("retrieving parent %s: 'sku' was nil", profileId) } + skuName := profile.Sku.Name enableCertNameCheck := d.Get("certificate_name_check_enabled").(bool) @@ -361,11 +370,14 @@ func resourceCdnFrontDoorOriginUpdate(d *pluginsdk.ResourceData, meta interface{ if err != nil { return err } + params.SharedPrivateLinkResource = privateLinkSettings } + if d.HasChange("priority") { params.Priority = utils.Int32(int32(d.Get("priority").(int))) } + if d.HasChange("weight") { params.Weight = utils.Int32(int32(d.Get("weight").(int))) } @@ -373,10 +385,12 @@ func resourceCdnFrontDoorOriginUpdate(d *pluginsdk.ResourceData, meta interface{ payload := cdn.AFDOriginUpdateParameters{ AFDOriginUpdatePropertiesParameters: ¶ms, } + future, err := client.Update(ctx, id.ResourceGroup, id.ProfileName, id.OriginGroupName, id.OriginName, payload) if err != nil { return fmt.Errorf("updating %s: %+v", *id, err) } + if err = future.WaitForCompletionRef(ctx, client.Client); err != nil { return fmt.Errorf("waiting for the update of %s: %+v", *id, err) } @@ -389,7 +403,7 @@ func resourceCdnFrontDoorOriginDelete(d *pluginsdk.ResourceData, meta interface{ ctx, cancel := timeouts.ForDelete(meta.(*clients.Client).StopContext, d) defer cancel() - id, err := parse.FrontDoorOriginID(d.Id()) + id, err := parse.FrontDoorOriginIDInsensitively(d.Id()) if err != nil { return err } diff --git a/internal/services/cdn/cdn_frontdoor_profile_resource.go b/internal/services/cdn/cdn_frontdoor_profile_resource.go index e25538804408..611bfcacee17 100644 --- a/internal/services/cdn/cdn_frontdoor_profile_resource.go +++ b/internal/services/cdn/cdn_frontdoor_profile_resource.go @@ -122,7 +122,7 @@ func resourceCdnFrontDoorProfileRead(d *pluginsdk.ResourceData, meta interface{} ctx, cancel := timeouts.ForRead(meta.(*clients.Client).StopContext, d) defer cancel() - id, err := parse.FrontDoorProfileID(d.Id()) + id, err := parse.FrontDoorProfileIDInsensitively(d.Id()) if err != nil { return err } @@ -161,7 +161,7 @@ func resourceCdnFrontDoorProfileUpdate(d *pluginsdk.ResourceData, meta interface ctx, cancel := timeouts.ForUpdate(meta.(*clients.Client).StopContext, d) defer cancel() - id, err := parse.FrontDoorProfileID(d.Id()) + id, err := parse.FrontDoorProfileIDInsensitively(d.Id()) if err != nil { return err } @@ -187,7 +187,7 @@ func resourceCdnFrontDoorProfileDelete(d *pluginsdk.ResourceData, meta interface ctx, cancel := timeouts.ForDelete(meta.(*clients.Client).StopContext, d) defer cancel() - id, err := parse.FrontDoorProfileID(d.Id()) + id, err := parse.FrontDoorProfileIDInsensitively(d.Id()) if err != nil { return err } diff --git a/internal/services/cdn/cdn_frontdoor_route_disable_link_to_default_domain_resource.go b/internal/services/cdn/cdn_frontdoor_route_disable_link_to_default_domain_resource.go index 64126a986a7b..751b918adb03 100644 --- a/internal/services/cdn/cdn_frontdoor_route_disable_link_to_default_domain_resource.go +++ b/internal/services/cdn/cdn_frontdoor_route_disable_link_to_default_domain_resource.go @@ -46,12 +46,14 @@ func resourceCdnFrontDoorRouteDisableLinkToDefaultDomain() *pluginsdk.Resource { Type: pluginsdk.TypeString, Required: true, ForceNew: true, + Deprecated: "the 'cdn_frontdoor_route_disable_link_to_default_domain' resource has been deprecated and will be removed from the 4.0 AzureRM provider. Please use the 'link_to_default_domain' field in the 'cdn_frontdoor_route' resource to control this value", ValidateFunc: validate.FrontDoorRouteID, }, "cdn_frontdoor_custom_domain_ids": { - Type: pluginsdk.TypeList, - Required: true, + Type: pluginsdk.TypeList, + Required: true, + Deprecated: "the 'cdn_frontdoor_route_disable_link_to_default_domain' resource has been deprecated and will be removed from the 4.0 AzureRM provider. Please use the 'link_to_default_domain' field in the 'cdn_frontdoor_route' resource to control this value", Elem: &pluginsdk.Schema{ Type: pluginsdk.TypeString, diff --git a/internal/services/cdn/cdn_frontdoor_route_resource.go b/internal/services/cdn/cdn_frontdoor_route_resource.go index 30a157814087..48698c25f8c3 100644 --- a/internal/services/cdn/cdn_frontdoor_route_resource.go +++ b/internal/services/cdn/cdn_frontdoor_route_resource.go @@ -7,7 +7,6 @@ import ( "github.com/Azure/azure-sdk-for-go/services/cdn/mgmt/2021-06-01/cdn" "github.com/hashicorp/terraform-provider-azurerm/helpers/tf" "github.com/hashicorp/terraform-provider-azurerm/internal/clients" - "github.com/hashicorp/terraform-provider-azurerm/internal/locks" "github.com/hashicorp/terraform-provider-azurerm/internal/services/cdn/azuresdkhacks" "github.com/hashicorp/terraform-provider-azurerm/internal/services/cdn/parse" "github.com/hashicorp/terraform-provider-azurerm/internal/services/cdn/validate" @@ -69,6 +68,22 @@ func resourceCdnFrontDoorRoute() *pluginsdk.Resource { }, }, + "cdn_frontdoor_custom_domain_ids": { + Type: pluginsdk.TypeList, + Optional: true, + + Elem: &pluginsdk.Schema{ + Type: pluginsdk.TypeString, + ValidateFunc: validate.FrontDoorCustomDomainID, + }, + }, + + "link_to_default_domain": { + Type: pluginsdk.TypeBool, + Optional: true, + Default: true, + }, + // NOTE: Per the service team this cannot just be omitted it must explicitly be set to nil to disable caching "cache": { Type: pluginsdk.TypeList, @@ -187,7 +202,7 @@ func resourceCdnFrontDoorRouteCreate(d *pluginsdk.ResourceData, meta interface{} ctx, cancel := timeouts.ForCreate(meta.(*clients.Client).StopContext, d) defer cancel() - endpointId, err := parse.FrontDoorEndpointID(d.Get("cdn_frontdoor_endpoint_id").(string)) + endpointId, err := parse.FrontDoorEndpointIDInsensitively(d.Get("cdn_frontdoor_endpoint_id").(string)) if err != nil { return err } @@ -207,6 +222,8 @@ func resourceCdnFrontDoorRouteCreate(d *pluginsdk.ResourceData, meta interface{} protocolsRaw := d.Get("supported_protocols").(*pluginsdk.Set).List() httpsRedirect := d.Get("https_redirect_enabled").(bool) + linkToDefaultDomain := d.Get("link_to_default_domain").(bool) + customDomains := d.Get("cdn_frontdoor_custom_domain_ids").([]interface{}) if httpsRedirect { // NOTE: If HTTPS Redirect is enabled the Supported Protocols must support both HTTP and HTTPS @@ -218,16 +235,28 @@ func resourceCdnFrontDoorRouteCreate(d *pluginsdk.ResourceData, meta interface{} } } + if !linkToDefaultDomain && len(customDomains) == 0 { + return fmt.Errorf("it is invalid to disable the 'LinkToDefaultDomain' for the CDN Front Door Route(Name: %s) since the route does not have any CDN Front Door Custom Domains associated with it", id.RouteName) + } + + if len(customDomains) != 0 { + if err := sliceHasDuplicates(customDomains, "CDN FrontDoor Custom Domain"); err != nil { + return err + } + + if err := validateRoutesCustomDomanProfile(customDomains, id.RouteName, id.ProfileName); err != nil { + return err + } + } + props := cdn.Route{ RouteProperties: &cdn.RouteProperties{ - CacheConfiguration: expandCdnFrontdoorRouteCacheConfiguration(d.Get("cache").([]interface{})), - EnabledState: expandEnabledBool(d.Get("enabled").(bool)), - ForwardingProtocol: cdn.ForwardingProtocol(d.Get("forwarding_protocol").(string)), - HTTPSRedirect: expandEnabledBoolToRouteHttpsRedirect(httpsRedirect), - // NOTE: Hack due to the API's design, must create the route with the link to default - // domain as true else you will receive an error from the service this value is now - // controlled by the cdn_frontdoor_route_unlink_default_domain resource... :/ - LinkToDefaultDomain: cdn.LinkToDefaultDomainEnabled, + CustomDomains: expandCdnFrontdoorRouteActivatedResourceArray(customDomains), + CacheConfiguration: expandCdnFrontdoorRouteCacheConfiguration(d.Get("cache").([]interface{})), + EnabledState: expandEnabledBool(d.Get("enabled").(bool)), + ForwardingProtocol: cdn.ForwardingProtocol(d.Get("forwarding_protocol").(string)), + HTTPSRedirect: expandEnabledBoolToRouteHttpsRedirect(httpsRedirect), + LinkToDefaultDomain: expandEnabledBoolToLinkToDefaultDomain(linkToDefaultDomain), OriginGroup: expandResourceReference(d.Get("cdn_frontdoor_origin_group_id").(string)), PatternsToMatch: utils.ExpandStringSlice(d.Get("patterns_to_match").([]interface{})), RuleSets: expandCdnFrontdoorRouteResourceReferenceArray(d.Get("cdn_frontdoor_rule_set_ids").([]interface{})), @@ -264,7 +293,7 @@ func resourceCdnFrontDoorRouteRead(d *pluginsdk.ResourceData, meta interface{}) ctx, cancel := timeouts.ForRead(meta.(*clients.Client).StopContext, d) defer cancel() - id, err := parse.FrontDoorRouteID(d.Id()) + id, err := parse.FrontDoorRouteIDInsensitively(d.Id()) if err != nil { return err } @@ -289,11 +318,13 @@ func resourceCdnFrontDoorRouteRead(d *pluginsdk.ResourceData, meta interface{}) d.Set("cdn_frontdoor_endpoint_id", parse.NewFrontDoorEndpointID(id.SubscriptionId, id.ResourceGroup, id.ProfileName, id.AfdEndpointName).ID()) if props := resp.RouteProperties; props != nil { + d.Set("cdn_frontdoor_custom_domain_ids", flattenCdnFrontdoorRouteActivatedResourceArray(props.CustomDomains)) d.Set("enabled", flattenEnabledBool(props.EnabledState)) d.Set("forwarding_protocol", props.ForwardingProtocol) d.Set("https_redirect_enabled", flattenHttpsRedirectToBool(props.HTTPSRedirect)) d.Set("cdn_frontdoor_origin_path", props.OriginPath) d.Set("patterns_to_match", props.PatternsToMatch) + d.Set("link_to_default_domain", flattenLinkToDefaultDomainToBool(props.LinkToDefaultDomain)) if err := d.Set("cache", flattenCdnFrontdoorRouteCacheConfiguration(props.CacheConfiguration)); err != nil { return fmt.Errorf("setting `cache`: %+v", err) @@ -321,17 +352,11 @@ func resourceCdnFrontDoorRouteUpdate(d *pluginsdk.ResourceData, meta interface{} ctx, cancel := timeouts.ForUpdate(meta.(*clients.Client).StopContext, d) defer cancel() - id, err := parse.FrontDoorRouteID(d.Id()) + id, err := parse.FrontDoorRouteIDInsensitively(d.Id()) if err != nil { return err } - // NOTE: I now need to lock this resource when updating because the - // cdn_frontdoor_route_unlink_default_domain resources may also be - // trying to update it as well... - locks.ByName(id.RouteName, cdnFrontDoorRouteResourceName) - defer locks.UnlockByName(id.RouteName, cdnFrontDoorRouteResourceName) - existing, err := client.Get(ctx, id.ResourceGroup, id.ProfileName, id.AfdEndpointName, id.RouteName) if err != nil { return fmt.Errorf("retrieving existing %s: %+v", *id, err) @@ -343,6 +368,8 @@ func resourceCdnFrontDoorRouteUpdate(d *pluginsdk.ResourceData, meta interface{} var checkProtocols bool httpsRedirect := d.Get("https_redirect_enabled").(bool) protocolsRaw := d.Get("supported_protocols").(*pluginsdk.Set).List() + customDomains := d.Get("cdn_frontdoor_custom_domain_ids").([]interface{}) + linkToDefaultDomain := d.Get("link_to_default_domain").(bool) props := azuresdkhacks.RouteUpdatePropertiesParameters{ CustomDomains: existing.RouteProperties.CustomDomains, @@ -365,6 +392,14 @@ func resourceCdnFrontDoorRouteUpdate(d *pluginsdk.ResourceData, meta interface{} props.HTTPSRedirect = expandEnabledBoolToRouteHttpsRedirect(httpsRedirect) } + if d.HasChange("link_to_default_domain") { + props.LinkToDefaultDomain = expandEnabledBoolToLinkToDefaultDomain(d.Get("link_to_default_domain").(bool)) + } + + if d.HasChange("cdn_frontdoor_custom_domain_ids") { + props.CustomDomains = expandCdnFrontdoorRouteActivatedResourceArray(customDomains) + } + if d.HasChange("cdn_frontdoor_origin_group_id") { props.OriginGroup = expandResourceReference(d.Get("cdn_frontdoor_origin_group_id").(string)) } @@ -400,6 +435,20 @@ func resourceCdnFrontDoorRouteUpdate(d *pluginsdk.ResourceData, meta interface{} } } + if !linkToDefaultDomain && len(customDomains) == 0 { + return fmt.Errorf("it is invalid to disable the 'LinkToDefaultDomain' for the CDN Front Door Route(Name: %s) since the route does not have any CDN Front Door Custom Domains associated with it", id.RouteName) + } + + if len(customDomains) != 0 { + if err := sliceHasDuplicates(customDomains, "CDN FrontDoor Custom Domain"); err != nil { + return err + } + + if err := validateRoutesCustomDomanProfile(customDomains, id.RouteName, id.ProfileName); err != nil { + return err + } + } + future, err := workaroundsClient.Update(ctx, id.ResourceGroup, id.ProfileName, id.AfdEndpointName, id.RouteName, updatePrarams) if err != nil { return fmt.Errorf("updating %s: %+v", *id, err) @@ -422,16 +471,11 @@ func resourceCdnFrontDoorRouteDelete(d *pluginsdk.ResourceData, meta interface{} ctx, cancel := timeouts.ForDelete(meta.(*clients.Client).StopContext, d) defer cancel() - id, err := parse.FrontDoorRouteID(d.Id()) + id, err := parse.FrontDoorRouteIDInsensitively(d.Id()) if err != nil { return err } - // I now need to lock this resource when updating because the association resources may also be trying - // to update it as well... - locks.ByName(id.RouteName, cdnFrontDoorRouteResourceName) - defer locks.UnlockByName(id.RouteName, cdnFrontDoorRouteResourceName) - future, err := client.Delete(ctx, id.ResourceGroup, id.ProfileName, id.AfdEndpointName, id.RouteName) if err != nil { return fmt.Errorf("deleting %s: %+v", *id, err) @@ -525,7 +569,12 @@ func flattenCdnFrontdoorRouteActivatedResourceArray(inputs *[]cdn.ActivatedResou } for _, customDomain := range *inputs { - results = append(results, *customDomain.ID) + // Normalize these values in the configuration file + // we know they are valid because they were set on the + // resource... if these are modified in the portal the + // will all be lowercased... + id, _ := parse.FrontDoorCustomDomainIDInsensitively(*customDomain.ID) + results = append(results, id.ID()) } return results diff --git a/internal/services/cdn/cdn_frontdoor_rule_resource.go b/internal/services/cdn/cdn_frontdoor_rule_resource.go index 5705b2c0a6e5..9b46af45d868 100644 --- a/internal/services/cdn/cdn_frontdoor_rule_resource.go +++ b/internal/services/cdn/cdn_frontdoor_rule_resource.go @@ -618,7 +618,7 @@ func resourceCdnFrontDoorRuleCreate(d *pluginsdk.ResourceData, meta interface{}) ctx, cancel := timeouts.ForCreate(meta.(*clients.Client).StopContext, d) defer cancel() - ruleSetId, err := parse.FrontDoorRuleSetID(d.Get("cdn_frontdoor_rule_set_id").(string)) + ruleSetId, err := parse.FrontDoorRuleSetIDInsensitively(d.Get("cdn_frontdoor_rule_set_id").(string)) if err != nil { return err } @@ -678,7 +678,7 @@ func resourceCdnFrontDoorRuleRead(d *pluginsdk.ResourceData, meta interface{}) e ctx, cancel := timeouts.ForRead(meta.(*clients.Client).StopContext, d) defer cancel() - id, err := parse.FrontDoorRuleID(d.Id()) + id, err := parse.FrontDoorRuleIDInsensitively(d.Id()) if err != nil { return err } @@ -726,7 +726,7 @@ func resourceCdnFrontDoorRuleUpdate(d *pluginsdk.ResourceData, meta interface{}) ctx, cancel := timeouts.ForUpdate(meta.(*clients.Client).StopContext, d) defer cancel() - id, err := parse.FrontDoorRuleID(d.Id()) + id, err := parse.FrontDoorRuleIDInsensitively(d.Id()) if err != nil { return err } @@ -783,7 +783,7 @@ func resourceCdnFrontDoorRuleDelete(d *pluginsdk.ResourceData, meta interface{}) ctx, cancel := timeouts.ForDelete(meta.(*clients.Client).StopContext, d) defer cancel() - id, err := parse.FrontDoorRuleID(d.Id()) + id, err := parse.FrontDoorRuleIDInsensitively(d.Id()) if err != nil { return err } diff --git a/internal/services/cdn/cdn_frontdoor_rule_set_resource.go b/internal/services/cdn/cdn_frontdoor_rule_set_resource.go index bbf6c411456b..b3bbbd3a3656 100644 --- a/internal/services/cdn/cdn_frontdoor_rule_set_resource.go +++ b/internal/services/cdn/cdn_frontdoor_rule_set_resource.go @@ -54,7 +54,7 @@ func resourceCdnFrontDoorRuleSetCreate(d *pluginsdk.ResourceData, meta interface ctx, cancel := timeouts.ForCreate(meta.(*clients.Client).StopContext, d) defer cancel() - profileId, err := parse.FrontDoorProfileID(d.Get("cdn_frontdoor_profile_id").(string)) + profileId, err := parse.FrontDoorProfileIDInsensitively(d.Get("cdn_frontdoor_profile_id").(string)) if err != nil { return err } @@ -86,7 +86,7 @@ func resourceCdnFrontDoorRuleSetRead(d *pluginsdk.ResourceData, meta interface{} ctx, cancel := timeouts.ForRead(meta.(*clients.Client).StopContext, d) defer cancel() - id, err := parse.FrontDoorRuleSetID(d.Id()) + id, err := parse.FrontDoorRuleSetIDInsensitively(d.Id()) if err != nil { return err } @@ -111,7 +111,7 @@ func resourceCdnFrontDoorRuleSetDelete(d *pluginsdk.ResourceData, meta interface ctx, cancel := timeouts.ForDelete(meta.(*clients.Client).StopContext, d) defer cancel() - id, err := parse.FrontDoorRuleSetID(d.Id()) + id, err := parse.FrontDoorRuleSetIDInsensitively(d.Id()) if err != nil { return err } diff --git a/internal/services/cdn/cdn_frontdoor_secret_resource.go b/internal/services/cdn/cdn_frontdoor_secret_resource.go index 7c70e32ac9fe..6dcd864d658d 100644 --- a/internal/services/cdn/cdn_frontdoor_secret_resource.go +++ b/internal/services/cdn/cdn_frontdoor_secret_resource.go @@ -98,7 +98,7 @@ func resourceCdnFrontDoorSecretCreate(d *pluginsdk.ResourceData, meta interface{ ctx, cancel := timeouts.ForCreate(meta.(*clients.Client).StopContext, d) defer cancel() - profileId, err := parse.FrontDoorProfileID(d.Get("cdn_frontdoor_profile_id").(string)) + profileId, err := parse.FrontDoorProfileIDInsensitively(d.Get("cdn_frontdoor_profile_id").(string)) if err != nil { return err } @@ -145,7 +145,7 @@ func resourceCdnFrontDoorSecretRead(d *pluginsdk.ResourceData, meta interface{}) ctx, cancel := timeouts.ForRead(meta.(*clients.Client).StopContext, d) defer cancel() - id, err := parse.FrontDoorSecretID(d.Id()) + id, err := parse.FrontDoorSecretIDInsensitively(d.Id()) if err != nil { return err } @@ -183,7 +183,7 @@ func resourceCdnFrontDoorSecretDelete(d *pluginsdk.ResourceData, meta interface{ ctx, cancel := timeouts.ForDelete(meta.(*clients.Client).StopContext, d) defer cancel() - id, err := parse.FrontDoorSecretID(d.Id()) + id, err := parse.FrontDoorSecretIDInsensitively(d.Id()) if err != nil { return err } diff --git a/internal/services/cdn/cdn_frontdoor_security_policy_resource.go b/internal/services/cdn/cdn_frontdoor_security_policy_resource.go index 1ce5351706ec..c997edf33904 100644 --- a/internal/services/cdn/cdn_frontdoor_security_policy_resource.go +++ b/internal/services/cdn/cdn_frontdoor_security_policy_resource.go @@ -140,7 +140,7 @@ func resourceCdnFrontdoorSecurityPolicyCreate(d *pluginsdk.ResourceData, meta in defer cancel() // NOTE: The profile id is used to retrieve properties from the related profile that must match in this security policy - profileId, err := parse.FrontDoorProfileID(d.Get("cdn_frontdoor_profile_id").(string)) + profileId, err := parse.FrontDoorProfileIDInsensitively(d.Get("cdn_frontdoor_profile_id").(string)) if err != nil { return err } @@ -200,7 +200,7 @@ func resourceCdnFrontdoorSecurityPolicyRead(d *pluginsdk.ResourceData, meta inte ctx, cancel := timeouts.ForRead(meta.(*clients.Client).StopContext, d) defer cancel() - id, err := parse.FrontDoorSecurityPolicyID(d.Id()) + id, err := parse.FrontDoorSecurityPolicyIDInsensitively(d.Id()) if err != nil { return err } @@ -263,7 +263,7 @@ func resourceCdnFrontdoorSecurityPolicyDelete(d *pluginsdk.ResourceData, meta in ctx, cancel := timeouts.ForDelete(meta.(*clients.Client).StopContext, d) defer cancel() - id, err := parse.FrontDoorSecurityPolicyID(d.Id()) + id, err := parse.FrontDoorSecurityPolicyIDInsensitively(d.Id()) if err != nil { return err } From 6ad1250c370d2d3513e422afa26f79ea2976d58c Mon Sep 17 00:00:00 2001 From: Jeffrey Cline <20408400+WodansSon@users.noreply.github.com> Date: Thu, 6 Oct 2022 01:02:25 -0600 Subject: [PATCH 06/58] Almost there... total redesign... --- ...door_custom_domain_association_resource.go | 217 +++++++++++++ .../cdn_frontdoor_custom_domain_resource.go | 179 +---------- .../services/cdn/cdn_frontdoor_helpers.go | 209 ++++++------ ...disable_link_to_default_domain_resource.go | 3 - .../cdn/cdn_frontdoor_route_resource.go | 73 ++++- .../front_door_custom_domain_association.go | 149 +++++++++ ...ont_door_custom_domain_association_test.go | 299 ++++++++++++++++++ internal/services/cdn/registration.go | 1 + internal/services/cdn/resourceids.go | 1 + ...front_door_custom_domain_association_id.go | 23 ++ ..._door_custom_domain_association_id_test.go | 100 ++++++ 11 files changed, 944 insertions(+), 310 deletions(-) create mode 100644 internal/services/cdn/cdn_frontdoor_custom_domain_association_resource.go create mode 100644 internal/services/cdn/parse/front_door_custom_domain_association.go create mode 100644 internal/services/cdn/parse/front_door_custom_domain_association_test.go create mode 100644 internal/services/cdn/validate/front_door_custom_domain_association_id.go create mode 100644 internal/services/cdn/validate/front_door_custom_domain_association_id_test.go diff --git a/internal/services/cdn/cdn_frontdoor_custom_domain_association_resource.go b/internal/services/cdn/cdn_frontdoor_custom_domain_association_resource.go new file mode 100644 index 000000000000..c35ea2809a07 --- /dev/null +++ b/internal/services/cdn/cdn_frontdoor_custom_domain_association_resource.go @@ -0,0 +1,217 @@ +package cdn + +import ( + "fmt" + "log" + "time" + + "github.com/hashicorp/go-uuid" + "github.com/hashicorp/terraform-provider-azurerm/internal/services/cdn/parse" + "github.com/hashicorp/terraform-provider-azurerm/internal/services/cdn/validate" + "github.com/hashicorp/terraform-provider-azurerm/internal/tf/pluginsdk" +) + +var cdnFrontDoorCustomDomainResourceName = "azurerm_cdn_frontdoor_custom_domain" +var cdnFrontDoorRouteResourceName = "azurerm_cdn_frontdoor_route" +var notAssociatedErr = "the CDN FrontDoor Route(Name: %q) is currently not associated with the CDN FrontDoor Custom Domain(Name: %q). Please remove the CDN FrontDoor Route from your 'cdn_frontdoor_custom_domain_association' configuration block" + +func resourceCdnFrontDoorCustomDomainAssociation() *pluginsdk.Resource { + return &pluginsdk.Resource{ + Create: resourceCdnFrontDoorCustomDomainAssociationCreate, + Read: resourceCdnFrontDoorCustomDomainAssociationRead, + Update: resourceCdnFrontDoorCustomDomainAssociationUpdate, + Delete: resourceCdnFrontDoorCustomDomainAssociationDelete, + + Timeouts: &pluginsdk.ResourceTimeout{ + Create: pluginsdk.DefaultTimeout(30 * time.Minute), + Read: pluginsdk.DefaultTimeout(5 * time.Minute), + Update: pluginsdk.DefaultTimeout(30 * time.Minute), + Delete: pluginsdk.DefaultTimeout(30 * time.Minute), + }, + + Importer: pluginsdk.ImporterValidatingResourceId(func(id string) error { + if _, err := parse.FrontDoorRouteDisableLinkToDefaultDomainID(id); err != nil { + return err + } + return nil + }), + + Schema: map[string]*pluginsdk.Schema{ + "cdn_frontdoor_custom_domain_id": { + Type: pluginsdk.TypeString, + Required: true, + ForceNew: true, + ValidateFunc: validate.FrontDoorCustomDomainID, + }, + + "cdn_frontdoor_route_ids": { + Type: pluginsdk.TypeList, + Required: true, + + Elem: &pluginsdk.Schema{ + Type: pluginsdk.TypeString, + ValidateFunc: validate.FrontDoorRouteID, + }, + }, + }, + } +} + +func resourceCdnFrontDoorCustomDomainAssociationCreate(d *pluginsdk.ResourceData, meta interface{}) error { + log.Printf("[INFO] preparing arguments for CDN FrontDoor Custom Domain Association") + customDomain := d.Get("cdn_frontdoor_custom_domain_id").(string) + configRouteIds := d.Get("cdn_frontdoor_route_ids").([]interface{}) + + customDomainId, err := parse.FrontDoorCustomDomainIDInsensitively(customDomain) + if err != nil { + return err + } + + // create the resource id + uuid, err := uuid.GenerateUUID() + if err != nil { + return fmt.Errorf("generating UUID: %+v", err) + } + id := parse.NewFrontDoorCustomDomainAssociationID(customDomainId.SubscriptionId, customDomainId.ResourceGroup, customDomainId.ProfileName, customDomainId.CustomDomainName, uuid) + + routeIds, normalizedRoutes, err := normalizeRouteIds(configRouteIds) + if err != nil { + return err + } + + for _, routeId := range *routeIds { + // Make sure the route exists and get the routes custom domain association list... + routeAssociations, _, err := getRouteProperties(d, meta, &routeId, "cdn_frontdoor_custom_domain_association") + if err != nil { + return err + } + + // Make sure the custom domain is in the routes association list + if len(routeAssociations) == 0 || !sliceContainsString(routeAssociations, customDomainId.ID()) { + return fmt.Errorf(notAssociatedErr, routeId.RouteName, customDomainId.CustomDomainName) + } + } + + // validate the routes... + if len(*routeIds) != 0 { + if err := validateCustomDomainRoutes(routeIds, customDomainId); err != nil { + return err + } + } + + d.SetId(id.ID()) + d.Set("cdn_frontdoor_custom_domain_id", customDomainId.ID()) + d.Set("cdn_frontdoor_route_ids", normalizedRoutes) + + return resourceCdnFrontDoorCustomDomainAssociationRead(d, meta) +} + +func resourceCdnFrontDoorCustomDomainAssociationRead(d *pluginsdk.ResourceData, meta interface{}) error { + + customDomain := d.Get("cdn_frontdoor_custom_domain_id").(string) + configRouteIds := d.Get("cdn_frontdoor_route_ids").([]interface{}) + + customDomainId, err := parse.FrontDoorCustomDomainIDInsensitively(customDomain) + if err != nil { + return err + } + + routeIds, normalizedRoutes, err := normalizeRouteIds(configRouteIds) + if err != nil { + return err + } + + for _, route := range *routeIds { + // Make sure the route exists and get the routes custom domain association list... + routeAssociations, _, err := getRouteProperties(d, meta, &route, "cdn_frontdoor_custom_domain_association") + if err != nil { + return err + } + + // Make sure the custom domain is in the routes association list + if len(routeAssociations) == 0 || !sliceContainsString(routeAssociations, customDomainId.ID()) { + return fmt.Errorf(notAssociatedErr, route.RouteName, customDomainId.CustomDomainName) + } + } + + // validate the routes... + if len(*routeIds) != 0 { + if err := validateCustomDomainRoutes(routeIds, customDomainId); err != nil { + return err + } + } + + d.Set("cdn_frontdoor_custom_domain_id", customDomainId.ID()) + d.Set("cdn_frontdoor_route_ids", normalizedRoutes) + + return nil +} + +func resourceCdnFrontDoorCustomDomainAssociationUpdate(d *pluginsdk.ResourceData, meta interface{}) error { + customDomain := d.Get("cdn_frontdoor_custom_domain_id").(string) + + customDomainId, err := parse.FrontDoorCustomDomainIDInsensitively(customDomain) + if err != nil { + return err + } + + if d.HasChange("cdn_frontdoor_route_ids") { + old, new := d.GetChange("cdn_frontdoor_route_ids") + oldRoutes := old.([]interface{}) + newRoutes := new.([]interface{}) + + oldRouteIds, _, err := normalizeRouteIds(oldRoutes) + if err != nil { + return err + } + + newRouteIds, newNormalizedRoutes, err := normalizeRouteIds(newRoutes) + if err != nil { + return err + } + + // validate the new routes... + if len(*newRouteIds) != 0 { + if err := validateCustomDomainRoutes(newRouteIds, customDomainId); err != nil { + return err + } + } + + // now get the delta between the old and the new list, if any custom domains were removed from + // the list we need to remove the custom domain association from those routes... + if delta, _ := routeDelta(oldRouteIds, newRouteIds); len(*delta) != 0 { + if err = removeCustomDomainAssociationFromRoutes(d, meta, delta, customDomainId); err != nil { + return err + } + + d.Set("cdn_frontdoor_route_ids", newNormalizedRoutes) + } + } + + return nil +} + +func resourceCdnFrontDoorCustomDomainAssociationDelete(d *pluginsdk.ResourceData, meta interface{}) error { + customDomain := d.Get("cdn_frontdoor_custom_domain_id").(string) + configRouteIds := d.Get("cdn_frontdoor_route_ids").([]interface{}) + + customDomainId, err := parse.FrontDoorCustomDomainIDInsensitively(customDomain) + if err != nil { + return err + } + + routeIds, _, err := normalizeRouteIds(configRouteIds) + if err != nil { + return err + } + + if len(*routeIds) != 0 { + if err := removeCustomDomainAssociationFromRoutes(d, meta, routeIds, customDomainId); err != nil { + return err + } + } + + d.SetId("") + + return nil +} diff --git a/internal/services/cdn/cdn_frontdoor_custom_domain_resource.go b/internal/services/cdn/cdn_frontdoor_custom_domain_resource.go index cbcf035609f6..4103fb791155 100644 --- a/internal/services/cdn/cdn_frontdoor_custom_domain_resource.go +++ b/internal/services/cdn/cdn_frontdoor_custom_domain_resource.go @@ -53,26 +53,6 @@ func resourceCdnFrontDoorCustomDomain() *pluginsdk.Resource { ValidateFunc: validate.FrontDoorProfileID, }, - // NOTE: Was afraid of this "Error: Cycle: azurerm_cdn_frontdoor_custom_domain.wodan, azurerm_cdn_frontdoor_route.wodan" - // have to create a 'azurerm_cdn_frontdoor_custom_domain_routes_association' resource to manage the associations between - // the routes and the custom domains for delete/destroy operation... - "cdn_frontdoor_route_ids": { - Type: pluginsdk.TypeList, - Optional: true, - - ConflictsWith: func() []string { - if !features.FourPointOhBeta() { - return []string{"associate_with_cdn_frontdoor_route_id"} - } - return []string{} - }(), - - Elem: &pluginsdk.Schema{ - Type: pluginsdk.TypeString, - ValidateFunc: validate.FrontDoorRouteID, - }, - }, - "dns_zone_id": { Type: pluginsdk.TypeString, Optional: true, @@ -139,15 +119,9 @@ func resourceCdnFrontDoorCustomDomain() *pluginsdk.Resource { if !features.FourPointOhBeta() { resource.Schema["associate_with_cdn_frontdoor_route_id"] = &pluginsdk.Schema{ - Type: pluginsdk.TypeString, - Optional: true, - Deprecated: "'associate_with_cdn_frontdoor_route_id' is no longer used and and will be removed in version 4.0 of the AzureRM provider. Please use the 'cdn_frontdoor_custom_domains_ids' field in the 'cdn_frontdoor_route' resource to control the CDN FrontDoor Custom Domain association(s) with the CDN FrontDoor Route", - ConflictsWith: func() []string { - if !features.FourPointOhBeta() { - return []string{"cdn_frontdoor_route_ids"} - } - return []string{} - }(), + Type: pluginsdk.TypeString, + Optional: true, + Deprecated: "'associate_with_cdn_frontdoor_route_id' is no longer used and and will be removed in version 4.0 of the AzureRM provider. Please use the 'cdn_frontdoor_custom_domains_ids' field in the 'cdn_frontdoor_route' resource to control the CDN FrontDoor Custom Domain association(s) with the CDN FrontDoor Route", ValidateFunc: validate.FrontDoorRouteID, } } @@ -167,14 +141,6 @@ func resourceCdnFrontDoorCustomDomainCreate(d *pluginsdk.ResourceData, meta inte id := parse.NewFrontDoorCustomDomainID(profileId.SubscriptionId, profileId.ResourceGroup, profileId.ProfileName, d.Get("name").(string)) - // validate the routes... - routes := d.Get("cdn_frontdoor_route_ids").([]interface{}) - if len(routes) != 0 { - if err := validateCustomDomainRoutes(routes, &id); err != nil { - return err - } - } - dnsZone := d.Get("dns_zone_id").(string) tls := d.Get("tls").([]interface{}) @@ -205,30 +171,6 @@ func resourceCdnFrontDoorCustomDomainCreate(d *pluginsdk.ResourceData, meta inte } d.SetId(id.ID()) - d.Set("cdn_frontdoor_route_ids", routes) - - // Associate the custom domain with the route, if that field was passed... - // if !features.FourPointOhBeta() { - // if route := d.Get("associate_with_cdn_frontdoor_route_id").(string); route != "" { - // routes := []interface{}{route} - - // if err = addCustomDomainAssociationToRoutes(d, meta, routes, &id); err != nil { - // return err - // } else { - // d.Set("associate_with_cdn_frontdoor_route_id", route) - // } - // } - // } - - // // NOTE: To associate a custom domain with more than one route, you must also make sure that all of the routes point to the same endpoint - // // NOTE: I also now have to wait until all of the front door custom domains are created befor I move on here? - // if routes := d.Get("associate_with_cdn_frontdoor_route_ids").([]interface{}); len(routes) != 0 { - // if err = addCustomDomainAssociationToRoutes(d, meta, routes, &id); err != nil { - // return err - // } else { - // d.Set("associate_with_cdn_frontdoor_route_ids", routes) - // } - // } return resourceCdnFrontDoorCustomDomainRead(d, meta) } @@ -238,7 +180,7 @@ func resourceCdnFrontDoorCustomDomainRead(d *pluginsdk.ResourceData, meta interf ctx, cancel := timeouts.ForRead(meta.(*clients.Client).StopContext, d) defer cancel() - id, err := customDomainIDWithErrorTxt(d.Id()) + id, err := friendlyCustomDomainID(d.Id()) if err != nil { return err } @@ -249,6 +191,7 @@ func resourceCdnFrontDoorCustomDomainRead(d *pluginsdk.ResourceData, meta interf d.SetId("") return nil } + return fmt.Errorf("retrieving %s: %+v", id, err) } @@ -272,8 +215,6 @@ func resourceCdnFrontDoorCustomDomainRead(d *pluginsdk.ResourceData, meta interf } } - d.Set("cdn_frontdoor_route_ids", d.Get("cdn_frontdoor_route_ids").([]interface{})) - return nil } @@ -287,19 +228,6 @@ func resourceCdnFrontDoorCustomDomainUpdate(d *pluginsdk.ResourceData, meta inte return err } - // validate the routes... - if d.HasChange("cdn_frontdoor_route_ids") { - routes := d.Get("cdn_frontdoor_route_ids").([]interface{}) - - if len(routes) != 0 { - if err := validateCustomDomainRoutes(routes, id); err != nil { - return fmt.Errorf("azurerm_cdn_frontdoor_custom_domain: the 'cdn_frontdoor_route_ids' field is invalid: %+v", err) - } - } - - d.Set("cdn_frontdoor_route_ids", routes) - } - props := cdn.AFDDomainUpdateParameters{ AFDDomainUpdatePropertiesParameters: &cdn.AFDDomainUpdatePropertiesParameters{}, } @@ -349,94 +277,6 @@ func resourceCdnFrontDoorCustomDomainUpdate(d *pluginsdk.ResourceData, meta inte return fmt.Errorf("waiting for the update of %s: %+v", *id, err) } - // Now that the Custom Domain has been updated we need to ensure the referential integrity of the route resource - // and associate/unassociate the custom domain with the route(s), if that field was defined/removed... - - // if !features.FourPointOhBeta() { - // if route := d.Get("associate_with_cdn_frontdoor_route_id").(string); route != "" { - // if d.HasChange("associate_with_cdn_frontdoor_route_id") { - // old, new := d.GetChange("associate_with_cdn_frontdoor_route_id") - // oldRoute := []interface{}{old.(string)} - // newRoute := []interface{}{new.(string)} - - // switch { - // case (len(oldRoute) == 0 && len(newRoute) != 0): - // // Add - // if err := addCustomDomainAssociationToRoutes(d, meta, newRoute, id); err != nil { - // return err - // } - - // d.Set("associate_with_cdn_frontdoor_route_id", new.(string)) - - // case (len(oldRoute) != 0 && len(newRoute) == 0): - // // Remove - // if err := removeCustomDomainAssociationFromRoutes(d, meta, newRoute, id); err != nil { - // return err - // } - - // d.Set("associate_with_cdn_frontdoor_route_id", "") - - // case (len(oldRoute) != 0 && len(newRoute) != 0 && !strings.EqualFold(old.(string), new.(string))): - // // Swap - // if err = removeCustomDomainAssociationFromRoutes(d, meta, oldRoute, id); err != nil { - // return err - // } - - // d.Set("associate_with_cdn_frontdoor_route_id", "") - - // // add the association to the new route... - // if err = addCustomDomainAssociationToRoutes(d, meta, newRoute, id); err != nil { - // return err - // } - - // d.Set("associate_with_cdn_frontdoor_route_id", new.(string)) - // } - // } - // } - // } - - // if d.HasChange("cdn_frontdoor_route_ids") { - // if routes := d.Get("cdn_frontdoor_route_ids").([]interface{}); len(routes) != 0 { - // old, new := d.GetChange("associate_with_cdn_frontdoor_route_ids") - // oldRoutes := old.([]interface{}) - // newRoutes := new.([]interface{}) - - // switch { - // case (len(oldRoutes) == 0 && len(newRoutes) != 0): - // // Add - // if err = addCustomDomainAssociationToRoutes(d, meta, newRoutes, id); err != nil { - // return err - // } - - // d.Set("associate_with_cdn_frontdoor_route_ids", newRoutes) - - // case (len(oldRoutes) != 0 && len(newRoutes) == 0): - // // Remove - // if err = removeCustomDomainAssociationFromRoutes(d, meta, oldRoutes, id); err != nil { - // return err - // } - - // d.Set("associate_with_cdn_frontdoor_route_ids", []interface{}{}) - - // case (len(oldRoutes) != 0 && len(newRoutes) != 0): - // // Swap - // if removeRoutes, sharedRoutes := getRemoveRoutesDelta(oldRoutes, newRoutes); len(removeRoutes) != 0 { - // if err = removeCustomDomainAssociationFromRoutes(d, meta, removeRoutes, id); err != nil { - // return err - // } - - // d.Set("associate_with_cdn_frontdoor_route_ids", sharedRoutes) - // } - - // if err = addCustomDomainAssociationToRoutes(d, meta, newRoutes, id); err != nil { - // return err - // } - - // d.Set("associate_with_cdn_frontdoor_route_ids", newRoutes) - // } - // } - // } - return resourceCdnFrontDoorCustomDomainRead(d, meta) } @@ -450,15 +290,6 @@ func resourceCdnFrontDoorCustomDomainDelete(d *pluginsdk.ResourceData, meta inte return err } - // NOTE: If the custom domain is still associated with a route you cannot delete the custom domain - // without the service throwing an error. You must first update the route to remove the association... - if routes := d.Get("cdn_frontdoor_route_ids").([]interface{}); len(routes) != 0 { - // remove the association from the old route.. - if err := removeCustomDomainAssociationFromRoutes(d, meta, routes, id); err != nil { - return err - } - } - // delete the custom domain... future, err := client.Delete(ctx, id.ResourceGroup, id.ProfileName, id.CustomDomainName) if err != nil { diff --git a/internal/services/cdn/cdn_frontdoor_helpers.go b/internal/services/cdn/cdn_frontdoor_helpers.go index 34b64af1d146..e85073b8e55e 100644 --- a/internal/services/cdn/cdn_frontdoor_helpers.go +++ b/internal/services/cdn/cdn_frontdoor_helpers.go @@ -229,6 +229,18 @@ func sliceContainsString(input []interface{}, value string) bool { return false } +// determines if the slice contains the value case-insensitively +func routeSliceContains(input *[]parse.FrontDoorRouteId, value string) bool { + for _, key := range *input { + v := key.ID() + if strings.EqualFold(v, value) { + return true + } + } + + return false +} + // returns the slice with the value removed case-insensitively func sliceRemoveString(input []interface{}, value string) []interface{} { out := make([]interface{}, 0) @@ -268,58 +280,24 @@ func getRouteProperties(d *pluginsdk.ResourceData, meta interface{}, id *parse.F return customDomains, props, nil } -// func addCustomDomainAssociationToRoutes(d *pluginsdk.ResourceData, meta interface{}, route []interface{}, customDomainID *parse.FrontDoorCustomDomainId) error { -// for _, v := range route { -// if route, err := routeIDWithErrorTxt(v.(string)); err != nil { -// return err -// } else if err == nil { -// // lock the route resource for update... -// locks.ByName(route.RouteName, cdnFrontDoorRouteResourceName) -// defer locks.UnlockByName(route.RouteName, cdnFrontDoorRouteResourceName) - -// // Check to see if the route still exists or not... -// customDomains, props, err := getRouteProperties(d, meta, route, cdnFrontDoorCustomDomainResourceName) -// if err != nil { -// return err -// } - -// isAssociated := sliceContainsString(customDomains, customDomainID.ID()) - -// // if it is not associated update the route to add the association... -// if !isAssociated { -// if err := updateRouteAssociations(d, meta, route, customDomains, props, customDomainID); err != nil { -// return err -// } -// } -// } -// } - -// return nil -// } - -func removeCustomDomainAssociationFromRoutes(d *pluginsdk.ResourceData, meta interface{}, routes []interface{}, customDomainID *parse.FrontDoorCustomDomainId) error { - for _, v := range routes { - if route, err := routeIDWithErrorTxt(v.(string)); err != nil { - return err - } else if err == nil { - // lock the route resource for update... - locks.ByName(route.RouteName, cdnFrontDoorRouteResourceName) - defer locks.UnlockByName(route.RouteName, cdnFrontDoorRouteResourceName) - - // Check to see if the route still exists and grab its properties... - // NOTE: cdnFrontDoorRouteResourceName is defined in the "cdn_frontdoor_route_disable_link_to_default_domain_resource" file - customDomains, props, err := getRouteProperties(d, meta, route, cdnFrontDoorCustomDomainResourceName) - if err != nil { - return err - } - +func removeCustomDomainAssociationFromRoutes(d *pluginsdk.ResourceData, meta interface{}, routes *[]parse.FrontDoorRouteId, customDomainID *parse.FrontDoorCustomDomainId) error { + for _, route := range *routes { + // lock the route resource for update... + locks.ByName(route.RouteName, cdnFrontDoorRouteResourceName) + defer locks.UnlockByName(route.RouteName, cdnFrontDoorRouteResourceName) + + // Check to see if the route still exists and grab its properties... + // NOTE: cdnFrontDoorRouteResourceName is defined in the "cdn_frontdoor_route_disable_link_to_default_domain_resource" file + // ignore the error because that could just mean that the route has already been deleted... + customDomains, props, err := getRouteProperties(d, meta, &route, cdnFrontDoorCustomDomainResourceName) + if err == nil { // Check to make sure the custom domain is still associated with the route isAssociated := sliceContainsString(customDomains, customDomainID.ID()) if isAssociated { // it is, now removed the association... newDomains := sliceRemoveString(customDomains, customDomainID.ID()) - if err := updateRouteAssociations(d, meta, route, newDomains, props, customDomainID); err != nil { + if err := updateRouteAssociations(d, meta, &route, newDomains, props, customDomainID); err != nil { return err } } @@ -359,6 +337,7 @@ func updateRouteAssociations(d *pluginsdk.ResourceData, meta interface{}, routeI if err != nil { return fmt.Errorf("%s: updating the association with %s: %+v", *customDomainID, *routeId, err) } + if err = future.WaitForCompletionRef(ctx, client.Client); err != nil { return fmt.Errorf("%s: waiting to update the association with %s: %+v", *customDomainID, *routeId, err) } @@ -446,100 +425,43 @@ func validateRoutesCustomDomanProfile(customDomains []interface{}, routeName str return fmt.Errorf("the following CDN FrontDoor Custom Domain(s) do not belong to the expected CDN FrontDoor Profile(Name: %q). Please remove the following CDN FrontDoor Custom Domain(s) from your CDN FrontDoor Route configuration block: %s", routeProfile, strings.Join(wrongProfile, ", ")) } - // Make sure the resource is referencing all of the custom domains that are associated with the route... - // missingDomains := make([]string, 0) - - // for _, v := range routeCustomDomains { - // // If this was updated by the portal, it lowercases to resource ID... - // customDomain, err := parse.FrontDoorCustomDomainIDInsensitively(v.(string)) - // if err != nil { - // return fmt.Errorf("unable to parse %q: %+v", v.(string), err) - // } - - // if !sliceContainsString(resourceCustomDomains, customDomain.ID()) { - // missingDomains = append(missingDomains, fmt.Sprintf("%q", customDomain.ID())) - // } - // } - - // if len(missingDomains) > 0 { - // return fmt.Errorf("does not contain all of the CDN FrontDoor Custom Domains that are associated with the CDN FrontDoor Route(Name: %q). Please add the following CDN FrontDoor Custom Domain(s) to your CDN Route Disable Link To Default Domain configuration: %s", routeName, strings.Join(missingDomains, ", ")) - // } - - // // Make sure all of the custom domains that are referenced by the resource are actually associated with the route... - // notAssociated := make([]string, 0) - - // for _, v := range resourceCustomDomains { - // customDomain, err := parse.FrontDoorCustomDomainIDInsensitively(v.(string)) - // if err != nil { - // return fmt.Errorf("unable to parse %q: %+v", v.(string), err) - // } - - // if !sliceContainsString(routeCustomDomains, customDomain.ID()) { - // notAssociated = append(notAssociated, fmt.Sprintf("%q", customDomain.ID())) - // } - // } - - // if len(notAssociated) > 0 { - // return fmt.Errorf("contains CDN FrontDoor Custom Domains that are not associated with the CDN FrontDoor Route(Name: %q). Please remove the following CDN FrontDoor Custom Domain(s) from your CDN Route Disable Link To Default Domain configuration: %s", routeName, strings.Join(notAssociated, ", ")) - // } - return nil } // Validates that the CDN FrontDoor Custom Domain can be associated with the CDN FrontDoor Route or not -func validateCustomDomainRoutes(routes []interface{}, customDomainID *parse.FrontDoorCustomDomainId) error { - if len(routes) == 0 { +func validateCustomDomainRoutes(routes *[]parse.FrontDoorRouteId, customDomainID *parse.FrontDoorCustomDomainId) error { + if len(*routes) == 0 { return nil } // check for duplicates... - if err := sliceHasDuplicates(routes, "CDN FrontDoor Route"); err != nil { + if err := routeSliceHasDuplicates(routes, "CDN FrontDoor Route"); err != nil { return err } - for i, route := range routes { - var routeId *parse.FrontDoorRouteId - + for i, route := range *routes { // validate route and custom domain profiles match... - if v, err := routeIDWithErrorTxt(route.(string)); err != nil { - return err - } else { - routeId = v - if customDomainID.ProfileName != routeId.ProfileName { - return fmt.Errorf("the CDN FrontDoor Custom Domain(Name: %q, Profile: %q) and the CDN FrontDoor Route(Name: %q, Profile: %q) must belong to the same CDN FrontDoor Profile", customDomainID.CustomDomainName, customDomainID.ProfileName, routeId.RouteName, routeId.ProfileName) - } + if customDomainID.ProfileName != route.ProfileName { + return fmt.Errorf("the CDN FrontDoor Custom Domain(Name: %q, Profile: %q) and the CDN FrontDoor Route(Name: %q, Profile: %q) must belong to the same CDN FrontDoor Profile", customDomainID.CustomDomainName, customDomainID.ProfileName, route.RouteName, route.ProfileName) } // validate all routes are using the same endpoint... - for t, nextRoute := range routes { + for t, nextRoute := range *routes { if i == t { continue } - if nextRouteId, err := routeIDWithErrorTxt(nextRoute.(string)); err != nil { - return err - } else if err == nil && routeId.AfdEndpointName != nextRouteId.AfdEndpointName { - return fmt.Errorf("the CDN FrontDoor Route(Name: %q) and CDN FrontDoor Route(Name: %q) do not reference the same CDN FrontDoor Endpoint(Name: %q), all CDN FrontDoor Routes must reference the same CDN FrontDoor Endpoint %q to associate this CDN FrontDoor Custom Domain with more than one CDN FrontDoor Route", routeId.RouteName, nextRouteId.RouteName, routeId.AfdEndpointName, routeId.RouteName) + if route.AfdEndpointName != nextRoute.AfdEndpointName { + return fmt.Errorf("the CDN FrontDoor Route(Name: %q) and CDN FrontDoor Route(Name: %q) do not reference the same CDN FrontDoor Endpoint(Name: %q), all CDN FrontDoor Routes must reference the same CDN FrontDoor Endpoint %q to associate this CDN FrontDoor Custom Domain with more than one CDN FrontDoor Route", route.RouteName, nextRoute.RouteName, route.AfdEndpointName, route.AfdEndpointName) } } - } return nil } -// Returns a verbose CDN FrontDoor Route parse error message -func routeIDWithErrorTxt(route string) (*parse.FrontDoorRouteId, error) { - routeId, err := parse.FrontDoorRouteIDInsensitively(route) - if err != nil { - return nil, fmt.Errorf("unable to parse CDN FrontDoor Route ID %q: %+v", route, err) - } - - return routeId, nil -} - // Returns a verbose CDN FrontDoor Custom Domain parse error message -func customDomainIDWithErrorTxt(customDomain string) (*parse.FrontDoorCustomDomainId, error) { +func friendlyCustomDomainID(customDomain string) (*parse.FrontDoorCustomDomainId, error) { if customDomainId, err := parse.FrontDoorCustomDomainIDInsensitively(customDomain); err != nil { return nil, fmt.Errorf("unable to parse CDN FrontDoor Custom Domain(ID: %q): %+v", customDomain, err) } else { @@ -562,20 +484,65 @@ func sliceHasDuplicates(input []interface{}, resouceTxt string) error { return nil } +func routeSliceHasDuplicates(input *[]parse.FrontDoorRouteId, resourceName string) error { + k := make(map[string]bool) + + for _, route := range *input { + if _, d := k[strings.ToLower(route.ID())]; !d { + k[strings.ToLower(route.ID())] = true + } else { + return fmt.Errorf("duplicate %[1]s detected, please remove all duplicate entries for the %[1]s(ID: %q) from your configuration block", resourceName, route.ID()) + } + } + + return nil +} + // Determines what CDN FrontDoor Routes need to be removed/disassociated from this CDN FrontDoor Custom Domain -func getRemoveRoutesDelta(oldRoutes []interface{}, newRoutes []interface{}) ([]interface{}, []interface{}) { - remove := make([]interface{}, 0) - shared := make([]interface{}, 0) +func routeDelta(oldRoutes *[]parse.FrontDoorRouteId, newRoutes *[]parse.FrontDoorRouteId) (*[]parse.FrontDoorRouteId, *[]parse.FrontDoorRouteId) { + remove := make([]parse.FrontDoorRouteId, 0) + shared := make([]parse.FrontDoorRouteId, 0) // just find what old routes are not in the new route list... - for _, oldRoute := range oldRoutes { - if !sliceContainsString(newRoutes, oldRoute.(string)) { - remove = append(remove, oldRoute.(string)) + for _, oldRoute := range *oldRoutes { + if !routeSliceContains(newRoutes, oldRoute.ID()) { + remove = append(remove, oldRoute) } else { - shared = append(shared, oldRoute.(string)) + shared = append(shared, oldRoute) + } + } + + return &remove, &shared +} + +func normalizeRuleSetIds(input []interface{}) ([]interface{}, error) { + out := make([]interface{}, 0) + + for _, ruleSet := range input { + id, err := parse.FrontDoorRuleSetIDInsensitively(ruleSet.(string)) + if err != nil { + return nil, err + } + + out = append(out, id.ID()) + } + + return out, nil +} + +func normalizeRouteIds(input []interface{}) (*[]parse.FrontDoorRouteId, []interface{}, error) { + out := make([]parse.FrontDoorRouteId, 0) + config := make([]interface{}, 0) + + for _, route := range input { + id, err := parse.FrontDoorRouteIDInsensitively(route.(string)) + if err != nil { + return nil, nil, err } + out = append(out, *id) + config = append(config, id.ID()) } - return remove, shared + return &out, config, nil } diff --git a/internal/services/cdn/cdn_frontdoor_route_disable_link_to_default_domain_resource.go b/internal/services/cdn/cdn_frontdoor_route_disable_link_to_default_domain_resource.go index 751b918adb03..f0ac4cf66dbc 100644 --- a/internal/services/cdn/cdn_frontdoor_route_disable_link_to_default_domain_resource.go +++ b/internal/services/cdn/cdn_frontdoor_route_disable_link_to_default_domain_resource.go @@ -17,9 +17,6 @@ import ( "github.com/hashicorp/terraform-provider-azurerm/utils" ) -var cdnFrontDoorCustomDomainResourceName = "azurerm_cdn_frontdoor_custom_domain" -var cdnFrontDoorRouteResourceName = "azurerm_cdn_frontdoor_route" - func resourceCdnFrontDoorRouteDisableLinkToDefaultDomain() *pluginsdk.Resource { return &pluginsdk.Resource{ Create: resourceCdnFrontDoorRouteDisableLinkToDefaultDomainCreate, diff --git a/internal/services/cdn/cdn_frontdoor_route_resource.go b/internal/services/cdn/cdn_frontdoor_route_resource.go index 48698c25f8c3..2e1edd1e1d1a 100644 --- a/internal/services/cdn/cdn_frontdoor_route_resource.go +++ b/internal/services/cdn/cdn_frontdoor_route_resource.go @@ -220,10 +220,27 @@ func resourceCdnFrontDoorRouteCreate(d *pluginsdk.ResourceData, meta interface{} return tf.ImportAsExistsError("azurerm_cdn_frontdoor_route", id.ID()) } + var customDomains []interface{} + var originIds []interface{} + var originGroupId *cdn.ResourceReference + var ruleSetIds *[]cdn.ResourceReference + protocolsRaw := d.Get("supported_protocols").(*pluginsdk.Set).List() + orginGroupIdRaw := d.Get("cdn_frontdoor_origin_group_id").(string) + ruleSetIdsRaw := d.Get("cdn_frontdoor_rule_set_ids").([]interface{}) httpsRedirect := d.Get("https_redirect_enabled").(bool) linkToDefaultDomain := d.Get("link_to_default_domain").(bool) - customDomains := d.Get("cdn_frontdoor_custom_domain_ids").([]interface{}) + rawOriginIds := d.Get("cdn_frontdoor_origin_ids").([]interface{}) + rawCustomDomains := d.Get("cdn_frontdoor_custom_domain_ids").([]interface{}) + + for _, customDomain := range rawCustomDomains { + id, err := parse.FrontDoorCustomDomainIDInsensitively(customDomain.(string)) + if err != nil { + return err + } + + customDomains = append(customDomains, id.ID()) + } if httpsRedirect { // NOTE: If HTTPS Redirect is enabled the Supported Protocols must support both HTTP and HTTPS @@ -249,6 +266,22 @@ func resourceCdnFrontDoorRouteCreate(d *pluginsdk.ResourceData, meta interface{} } } + if orginGroupIdRaw != "" { + id, err := parse.FrontDoorOriginGroupIDInsensitively(orginGroupIdRaw) + if err != nil { + return err + } + + originGroupId = expandResourceReference(id.ID()) + } + + tmp, err := normalizeRuleSetIds(ruleSetIdsRaw) + if err != nil { + return err + } + + ruleSetIds = expandCdnFrontdoorRouteResourceReferenceArray(tmp) + props := cdn.Route{ RouteProperties: &cdn.RouteProperties{ CustomDomains: expandCdnFrontdoorRouteActivatedResourceArray(customDomains), @@ -257,9 +290,9 @@ func resourceCdnFrontDoorRouteCreate(d *pluginsdk.ResourceData, meta interface{} ForwardingProtocol: cdn.ForwardingProtocol(d.Get("forwarding_protocol").(string)), HTTPSRedirect: expandEnabledBoolToRouteHttpsRedirect(httpsRedirect), LinkToDefaultDomain: expandEnabledBoolToLinkToDefaultDomain(linkToDefaultDomain), - OriginGroup: expandResourceReference(d.Get("cdn_frontdoor_origin_group_id").(string)), + OriginGroup: originGroupId, PatternsToMatch: utils.ExpandStringSlice(d.Get("patterns_to_match").([]interface{})), - RuleSets: expandCdnFrontdoorRouteResourceReferenceArray(d.Get("cdn_frontdoor_rule_set_ids").([]interface{})), + RuleSets: ruleSetIds, SupportedProtocols: expandCdnFrontdoorRouteEndpointProtocolsArray(protocolsRaw), }, } @@ -281,8 +314,17 @@ func resourceCdnFrontDoorRouteCreate(d *pluginsdk.ResourceData, meta interface{} // NOTE: These are not sent to the API, they are only here so Terraform // can provision/destroy the resources in the correct order. - if originIds := d.Get("cdn_frontdoor_origin_ids").([]interface{}); len(originIds) > 0 { - d.Set("cdn_frontdoor_origin_ids", utils.ExpandStringSlice(originIds)) + for _, originId := range rawOriginIds { + id, err := parse.FrontDoorOriginIDInsensitively(originId.(string)) + if err != nil { + return err + } + + originIds = append(originIds, id.ID()) + } + + if len(originIds) != 0 { + d.Set("cdn_frontdoor_origin_ids", originIds) } return resourceCdnFrontDoorRouteRead(d, meta) @@ -352,6 +394,7 @@ func resourceCdnFrontDoorRouteUpdate(d *pluginsdk.ResourceData, meta interface{} ctx, cancel := timeouts.ForUpdate(meta.(*clients.Client).StopContext, d) defer cancel() + // TODO: Fix Casing on update id, err := parse.FrontDoorRouteIDInsensitively(d.Id()) if err != nil { return err @@ -366,15 +409,23 @@ func resourceCdnFrontDoorRouteUpdate(d *pluginsdk.ResourceData, meta interface{} } var checkProtocols bool + var customDomains []interface{} httpsRedirect := d.Get("https_redirect_enabled").(bool) protocolsRaw := d.Get("supported_protocols").(*pluginsdk.Set).List() - customDomains := d.Get("cdn_frontdoor_custom_domain_ids").([]interface{}) linkToDefaultDomain := d.Get("link_to_default_domain").(bool) + rawCustomDomains := d.Get("cdn_frontdoor_custom_domain_ids").([]interface{}) - props := azuresdkhacks.RouteUpdatePropertiesParameters{ - CustomDomains: existing.RouteProperties.CustomDomains, + for _, customDomain := range rawCustomDomains { + id, err := parse.FrontDoorCustomDomainIDInsensitively(customDomain.(string)) + if err != nil { + return err + } + + customDomains = append(customDomains, id.ID()) } + props := azuresdkhacks.RouteUpdatePropertiesParameters{} + if d.HasChange("cache") { props.CacheConfiguration = expandCdnFrontdoorRouteCacheConfiguration(d.Get("cache").([]interface{})) } @@ -569,10 +620,8 @@ func flattenCdnFrontdoorRouteActivatedResourceArray(inputs *[]cdn.ActivatedResou } for _, customDomain := range *inputs { - // Normalize these values in the configuration file - // we know they are valid because they were set on the - // resource... if these are modified in the portal the - // will all be lowercased... + // Normalize these values in the configuration file we know they are valid because they were set on the + // resource... if these are modified in the portal the will all be lowercased... id, _ := parse.FrontDoorCustomDomainIDInsensitively(*customDomain.ID) results = append(results, id.ID()) } diff --git a/internal/services/cdn/parse/front_door_custom_domain_association.go b/internal/services/cdn/parse/front_door_custom_domain_association.go new file mode 100644 index 000000000000..da5bd67781b4 --- /dev/null +++ b/internal/services/cdn/parse/front_door_custom_domain_association.go @@ -0,0 +1,149 @@ +package parse + +// NOTE: this file is generated via 'go:generate' - manual changes will be overwritten + +import ( + "fmt" + "strings" + + "github.com/hashicorp/go-azure-helpers/resourcemanager/resourceids" +) + +type FrontDoorCustomDomainAssociationId struct { + SubscriptionId string + ResourceGroup string + ProfileName string + CustomDomainName string + AssociationName string +} + +func NewFrontDoorCustomDomainAssociationID(subscriptionId, resourceGroup, profileName, customDomainName, associationName string) FrontDoorCustomDomainAssociationId { + return FrontDoorCustomDomainAssociationId{ + SubscriptionId: subscriptionId, + ResourceGroup: resourceGroup, + ProfileName: profileName, + CustomDomainName: customDomainName, + AssociationName: associationName, + } +} + +func (id FrontDoorCustomDomainAssociationId) String() string { + segments := []string{ + fmt.Sprintf("Association Name %q", id.AssociationName), + fmt.Sprintf("Custom Domain Name %q", id.CustomDomainName), + fmt.Sprintf("Profile Name %q", id.ProfileName), + fmt.Sprintf("Resource Group %q", id.ResourceGroup), + } + segmentsStr := strings.Join(segments, " / ") + return fmt.Sprintf("%s: (%s)", "Front Door Custom Domain Association", segmentsStr) +} + +func (id FrontDoorCustomDomainAssociationId) ID() string { + fmtString := "/subscriptions/%s/resourceGroups/%s/providers/Microsoft.Cdn/profiles/%s/customDomains/%s/associations/%s" + return fmt.Sprintf(fmtString, id.SubscriptionId, id.ResourceGroup, id.ProfileName, id.CustomDomainName, id.AssociationName) +} + +// FrontDoorCustomDomainAssociationID parses a FrontDoorCustomDomainAssociation ID into an FrontDoorCustomDomainAssociationId struct +func FrontDoorCustomDomainAssociationID(input string) (*FrontDoorCustomDomainAssociationId, error) { + id, err := resourceids.ParseAzureResourceID(input) + if err != nil { + return nil, err + } + + resourceId := FrontDoorCustomDomainAssociationId{ + SubscriptionId: id.SubscriptionID, + ResourceGroup: id.ResourceGroup, + } + + if resourceId.SubscriptionId == "" { + return nil, fmt.Errorf("ID was missing the 'subscriptions' element") + } + + if resourceId.ResourceGroup == "" { + return nil, fmt.Errorf("ID was missing the 'resourceGroups' element") + } + + if resourceId.ProfileName, err = id.PopSegment("profiles"); err != nil { + return nil, err + } + if resourceId.CustomDomainName, err = id.PopSegment("customDomains"); err != nil { + return nil, err + } + if resourceId.AssociationName, err = id.PopSegment("associations"); err != nil { + return nil, err + } + + if err := id.ValidateNoEmptySegments(input); err != nil { + return nil, err + } + + return &resourceId, nil +} + +// FrontDoorCustomDomainAssociationIDInsensitively parses an FrontDoorCustomDomainAssociation ID into an FrontDoorCustomDomainAssociationId struct, insensitively +// This should only be used to parse an ID for rewriting, the FrontDoorCustomDomainAssociationID +// method should be used instead for validation etc. +// +// Whilst this may seem strange, this enables Terraform have consistent casing +// which works around issues in Core, whilst handling broken API responses. +func FrontDoorCustomDomainAssociationIDInsensitively(input string) (*FrontDoorCustomDomainAssociationId, error) { + id, err := resourceids.ParseAzureResourceID(input) + if err != nil { + return nil, err + } + + resourceId := FrontDoorCustomDomainAssociationId{ + SubscriptionId: id.SubscriptionID, + ResourceGroup: id.ResourceGroup, + } + + if resourceId.SubscriptionId == "" { + return nil, fmt.Errorf("ID was missing the 'subscriptions' element") + } + + if resourceId.ResourceGroup == "" { + return nil, fmt.Errorf("ID was missing the 'resourceGroups' element") + } + + // find the correct casing for the 'profiles' segment + profilesKey := "profiles" + for key := range id.Path { + if strings.EqualFold(key, profilesKey) { + profilesKey = key + break + } + } + if resourceId.ProfileName, err = id.PopSegment(profilesKey); err != nil { + return nil, err + } + + // find the correct casing for the 'customDomains' segment + customDomainsKey := "customDomains" + for key := range id.Path { + if strings.EqualFold(key, customDomainsKey) { + customDomainsKey = key + break + } + } + if resourceId.CustomDomainName, err = id.PopSegment(customDomainsKey); err != nil { + return nil, err + } + + // find the correct casing for the 'associations' segment + associationsKey := "associations" + for key := range id.Path { + if strings.EqualFold(key, associationsKey) { + associationsKey = key + break + } + } + if resourceId.AssociationName, err = id.PopSegment(associationsKey); err != nil { + return nil, err + } + + if err := id.ValidateNoEmptySegments(input); err != nil { + return nil, err + } + + return &resourceId, nil +} diff --git a/internal/services/cdn/parse/front_door_custom_domain_association_test.go b/internal/services/cdn/parse/front_door_custom_domain_association_test.go new file mode 100644 index 000000000000..ed219b17d537 --- /dev/null +++ b/internal/services/cdn/parse/front_door_custom_domain_association_test.go @@ -0,0 +1,299 @@ +package parse + +// NOTE: this file is generated via 'go:generate' - manual changes will be overwritten + +import ( + "testing" + + "github.com/hashicorp/go-azure-helpers/resourcemanager/resourceids" +) + +var _ resourceids.Id = FrontDoorCustomDomainAssociationId{} + +func TestFrontDoorCustomDomainAssociationIDFormatter(t *testing.T) { + actual := NewFrontDoorCustomDomainAssociationID("12345678-1234-9876-4563-123456789012", "resGroup1", "profile1", "customDomain1", "assoc1").ID() + expected := "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Cdn/profiles/profile1/customDomains/customDomain1/associations/assoc1" + if actual != expected { + t.Fatalf("Expected %q but got %q", expected, actual) + } +} + +func TestFrontDoorCustomDomainAssociationID(t *testing.T) { + testData := []struct { + Input string + Error bool + Expected *FrontDoorCustomDomainAssociationId + }{ + + { + // empty + Input: "", + Error: true, + }, + + { + // missing SubscriptionId + Input: "/", + Error: true, + }, + + { + // missing value for SubscriptionId + Input: "/subscriptions/", + Error: true, + }, + + { + // missing ResourceGroup + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/", + Error: true, + }, + + { + // missing value for ResourceGroup + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/", + Error: true, + }, + + { + // missing ProfileName + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Cdn/", + Error: true, + }, + + { + // missing value for ProfileName + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Cdn/profiles/", + Error: true, + }, + + { + // missing CustomDomainName + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Cdn/profiles/profile1/", + Error: true, + }, + + { + // missing value for CustomDomainName + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Cdn/profiles/profile1/customDomains/", + Error: true, + }, + + { + // missing AssociationName + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Cdn/profiles/profile1/customDomains/customDomain1/", + Error: true, + }, + + { + // missing value for AssociationName + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Cdn/profiles/profile1/customDomains/customDomain1/associations/", + Error: true, + }, + + { + // valid + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Cdn/profiles/profile1/customDomains/customDomain1/associations/assoc1", + Expected: &FrontDoorCustomDomainAssociationId{ + SubscriptionId: "12345678-1234-9876-4563-123456789012", + ResourceGroup: "resGroup1", + ProfileName: "profile1", + CustomDomainName: "customDomain1", + AssociationName: "assoc1", + }, + }, + + { + // upper-cased + Input: "/SUBSCRIPTIONS/12345678-1234-9876-4563-123456789012/RESOURCEGROUPS/RESGROUP1/PROVIDERS/MICROSOFT.CDN/PROFILES/PROFILE1/CUSTOMDOMAINS/CUSTOMDOMAIN1/ASSOCIATIONS/ASSOC1", + Error: true, + }, + } + + for _, v := range testData { + t.Logf("[DEBUG] Testing %q", v.Input) + + actual, err := FrontDoorCustomDomainAssociationID(v.Input) + if err != nil { + if v.Error { + continue + } + + t.Fatalf("Expect a value but got an error: %s", err) + } + if v.Error { + t.Fatal("Expect an error but didn't get one") + } + + if actual.SubscriptionId != v.Expected.SubscriptionId { + t.Fatalf("Expected %q but got %q for SubscriptionId", v.Expected.SubscriptionId, actual.SubscriptionId) + } + if actual.ResourceGroup != v.Expected.ResourceGroup { + t.Fatalf("Expected %q but got %q for ResourceGroup", v.Expected.ResourceGroup, actual.ResourceGroup) + } + if actual.ProfileName != v.Expected.ProfileName { + t.Fatalf("Expected %q but got %q for ProfileName", v.Expected.ProfileName, actual.ProfileName) + } + if actual.CustomDomainName != v.Expected.CustomDomainName { + t.Fatalf("Expected %q but got %q for CustomDomainName", v.Expected.CustomDomainName, actual.CustomDomainName) + } + if actual.AssociationName != v.Expected.AssociationName { + t.Fatalf("Expected %q but got %q for AssociationName", v.Expected.AssociationName, actual.AssociationName) + } + } +} + +func TestFrontDoorCustomDomainAssociationIDInsensitively(t *testing.T) { + testData := []struct { + Input string + Error bool + Expected *FrontDoorCustomDomainAssociationId + }{ + + { + // empty + Input: "", + Error: true, + }, + + { + // missing SubscriptionId + Input: "/", + Error: true, + }, + + { + // missing value for SubscriptionId + Input: "/subscriptions/", + Error: true, + }, + + { + // missing ResourceGroup + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/", + Error: true, + }, + + { + // missing value for ResourceGroup + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/", + Error: true, + }, + + { + // missing ProfileName + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Cdn/", + Error: true, + }, + + { + // missing value for ProfileName + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Cdn/profiles/", + Error: true, + }, + + { + // missing CustomDomainName + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Cdn/profiles/profile1/", + Error: true, + }, + + { + // missing value for CustomDomainName + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Cdn/profiles/profile1/customDomains/", + Error: true, + }, + + { + // missing AssociationName + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Cdn/profiles/profile1/customDomains/customDomain1/", + Error: true, + }, + + { + // missing value for AssociationName + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Cdn/profiles/profile1/customDomains/customDomain1/associations/", + Error: true, + }, + + { + // valid + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Cdn/profiles/profile1/customDomains/customDomain1/associations/assoc1", + Expected: &FrontDoorCustomDomainAssociationId{ + SubscriptionId: "12345678-1234-9876-4563-123456789012", + ResourceGroup: "resGroup1", + ProfileName: "profile1", + CustomDomainName: "customDomain1", + AssociationName: "assoc1", + }, + }, + + { + // lower-cased segment names + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Cdn/profiles/profile1/customdomains/customDomain1/associations/assoc1", + Expected: &FrontDoorCustomDomainAssociationId{ + SubscriptionId: "12345678-1234-9876-4563-123456789012", + ResourceGroup: "resGroup1", + ProfileName: "profile1", + CustomDomainName: "customDomain1", + AssociationName: "assoc1", + }, + }, + + { + // upper-cased segment names + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Cdn/PROFILES/profile1/CUSTOMDOMAINS/customDomain1/ASSOCIATIONS/assoc1", + Expected: &FrontDoorCustomDomainAssociationId{ + SubscriptionId: "12345678-1234-9876-4563-123456789012", + ResourceGroup: "resGroup1", + ProfileName: "profile1", + CustomDomainName: "customDomain1", + AssociationName: "assoc1", + }, + }, + + { + // mixed-cased segment names + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Cdn/PrOfIlEs/profile1/CuStOmDoMaInS/customDomain1/AsSoCiAtIoNs/assoc1", + Expected: &FrontDoorCustomDomainAssociationId{ + SubscriptionId: "12345678-1234-9876-4563-123456789012", + ResourceGroup: "resGroup1", + ProfileName: "profile1", + CustomDomainName: "customDomain1", + AssociationName: "assoc1", + }, + }, + } + + for _, v := range testData { + t.Logf("[DEBUG] Testing %q", v.Input) + + actual, err := FrontDoorCustomDomainAssociationIDInsensitively(v.Input) + if err != nil { + if v.Error { + continue + } + + t.Fatalf("Expect a value but got an error: %s", err) + } + if v.Error { + t.Fatal("Expect an error but didn't get one") + } + + if actual.SubscriptionId != v.Expected.SubscriptionId { + t.Fatalf("Expected %q but got %q for SubscriptionId", v.Expected.SubscriptionId, actual.SubscriptionId) + } + if actual.ResourceGroup != v.Expected.ResourceGroup { + t.Fatalf("Expected %q but got %q for ResourceGroup", v.Expected.ResourceGroup, actual.ResourceGroup) + } + if actual.ProfileName != v.Expected.ProfileName { + t.Fatalf("Expected %q but got %q for ProfileName", v.Expected.ProfileName, actual.ProfileName) + } + if actual.CustomDomainName != v.Expected.CustomDomainName { + t.Fatalf("Expected %q but got %q for CustomDomainName", v.Expected.CustomDomainName, actual.CustomDomainName) + } + if actual.AssociationName != v.Expected.AssociationName { + t.Fatalf("Expected %q but got %q for AssociationName", v.Expected.AssociationName, actual.AssociationName) + } + } +} diff --git a/internal/services/cdn/registration.go b/internal/services/cdn/registration.go index bfe488f71675..2a27a4340e4e 100644 --- a/internal/services/cdn/registration.go +++ b/internal/services/cdn/registration.go @@ -49,6 +49,7 @@ func (r Registration) SupportedResources() map[string]*pluginsdk.Resource { // FrontDoor "azurerm_cdn_frontdoor_custom_domain": resourceCdnFrontDoorCustomDomain(), + "azurerm_cdn_frontdoor_custom_domain_association": resourceCdnFrontDoorCustomDomainAssociation(), "azurerm_cdn_frontdoor_endpoint": resourceCdnFrontDoorEndpoint(), "azurerm_cdn_frontdoor_firewall_policy": resourceCdnFrontDoorFirewallPolicy(), "azurerm_cdn_frontdoor_origin": resourceCdnFrontDoorOrigin(), diff --git a/internal/services/cdn/resourceids.go b/internal/services/cdn/resourceids.go index bc0f9bfa68f6..0a5e225d8ee3 100644 --- a/internal/services/cdn/resourceids.go +++ b/internal/services/cdn/resourceids.go @@ -20,3 +20,4 @@ package cdn // CDN FrontDoor "Associations" //go:generate go run ../../tools/generator-resource-id/main.go -path=./ -name=FrontDoorRouteDisableLinkToDefaultDomain -id=/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Cdn/profiles/profile1/afdEndpoints/endpoint1/routes/route1/disableLinkToDefaultDomain/disableLinkToDefaultDomain1 -rewrite=true +//go:generate go run ../../tools/generator-resource-id/main.go -path=./ -name=FrontDoorCustomDomainAssociation -id=/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Cdn/profiles/profile1/customDomains/customDomain1/associations/assoc1 -rewrite=true diff --git a/internal/services/cdn/validate/front_door_custom_domain_association_id.go b/internal/services/cdn/validate/front_door_custom_domain_association_id.go new file mode 100644 index 000000000000..ef4591830316 --- /dev/null +++ b/internal/services/cdn/validate/front_door_custom_domain_association_id.go @@ -0,0 +1,23 @@ +package validate + +// NOTE: this file is generated via 'go:generate' - manual changes will be overwritten + +import ( + "fmt" + + "github.com/hashicorp/terraform-provider-azurerm/internal/services/cdn/parse" +) + +func FrontDoorCustomDomainAssociationID(input interface{}, key string) (warnings []string, errors []error) { + v, ok := input.(string) + if !ok { + errors = append(errors, fmt.Errorf("expected %q to be a string", key)) + return + } + + if _, err := parse.FrontDoorCustomDomainAssociationID(v); err != nil { + errors = append(errors, err) + } + + return +} diff --git a/internal/services/cdn/validate/front_door_custom_domain_association_id_test.go b/internal/services/cdn/validate/front_door_custom_domain_association_id_test.go new file mode 100644 index 000000000000..b33af51047bf --- /dev/null +++ b/internal/services/cdn/validate/front_door_custom_domain_association_id_test.go @@ -0,0 +1,100 @@ +package validate + +// NOTE: this file is generated via 'go:generate' - manual changes will be overwritten + +import "testing" + +func TestFrontDoorCustomDomainAssociationID(t *testing.T) { + cases := []struct { + Input string + Valid bool + }{ + + { + // empty + Input: "", + Valid: false, + }, + + { + // missing SubscriptionId + Input: "/", + Valid: false, + }, + + { + // missing value for SubscriptionId + Input: "/subscriptions/", + Valid: false, + }, + + { + // missing ResourceGroup + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/", + Valid: false, + }, + + { + // missing value for ResourceGroup + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/", + Valid: false, + }, + + { + // missing ProfileName + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Cdn/", + Valid: false, + }, + + { + // missing value for ProfileName + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Cdn/profiles/", + Valid: false, + }, + + { + // missing CustomDomainName + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Cdn/profiles/profile1/", + Valid: false, + }, + + { + // missing value for CustomDomainName + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Cdn/profiles/profile1/customDomains/", + Valid: false, + }, + + { + // missing AssociationName + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Cdn/profiles/profile1/customDomains/customDomain1/", + Valid: false, + }, + + { + // missing value for AssociationName + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Cdn/profiles/profile1/customDomains/customDomain1/associations/", + Valid: false, + }, + + { + // valid + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Cdn/profiles/profile1/customDomains/customDomain1/associations/assoc1", + Valid: true, + }, + + { + // upper-cased + Input: "/SUBSCRIPTIONS/12345678-1234-9876-4563-123456789012/RESOURCEGROUPS/RESGROUP1/PROVIDERS/MICROSOFT.CDN/PROFILES/PROFILE1/CUSTOMDOMAINS/CUSTOMDOMAIN1/ASSOCIATIONS/ASSOC1", + Valid: false, + }, + } + for _, tc := range cases { + t.Logf("[DEBUG] Testing Value %s", tc.Input) + _, errors := FrontDoorCustomDomainAssociationID(tc.Input, "test") + valid := len(errors) == 0 + + if tc.Valid != valid { + t.Fatalf("Expected %t but got %t", tc.Valid, valid) + } + } +} From 3736a07302e4c6420816a74211ee27984c9308b0 Mon Sep 17 00:00:00 2001 From: Jeffrey Cline <20408400+WodansSon@users.noreply.github.com> Date: Thu, 6 Oct 2022 18:33:36 -0600 Subject: [PATCH 07/58] Done... now write test cases... --- .../frontdoor-cmk-byoc-custom-domain/main.tf | 58 +++++++++---------- .../main.tf | 22 ++++--- .../cdn_frontdoor_custom_domain_resource.go | 2 +- .../services/cdn/cdn_frontdoor_helpers.go | 22 +++---- ...disable_link_to_default_domain_resource.go | 6 +- .../cdn/cdn_frontdoor_route_resource.go | 23 +++++--- .../cdn/cdn_frontdoor_rule_resource.go | 6 +- .../cdn_frontdoor_custom_domain.html.markdown | 4 -- ...or_custom_domain_association.html.markdown | 57 ++++++++++++++++++ .../docs/r/cdn_frontdoor_route.html.markdown | 24 +++++--- ...sable_link_to_default_domain.html.markdown | 16 ++--- 11 files changed, 157 insertions(+), 83 deletions(-) create mode 100644 website/docs/r/cdn_frontdoor_custom_domain_association.html.markdown diff --git a/examples/cdn/frontdoor/frontdoor-cmk-byoc-custom-domain/main.tf b/examples/cdn/frontdoor/frontdoor-cmk-byoc-custom-domain/main.tf index 75e6cb3bbf9c..96263508047a 100644 --- a/examples/cdn/frontdoor/frontdoor-cmk-byoc-custom-domain/main.tf +++ b/examples/cdn/frontdoor/frontdoor-cmk-byoc-custom-domain/main.tf @@ -288,14 +288,36 @@ resource "azurerm_cdn_frontdoor_security_policy" "example" { } } +resource "azurerm_cdn_frontdoor_route" "example" { + name = "${var.prefix}-route" + cdn_frontdoor_endpoint_id = azurerm_cdn_frontdoor_endpoint.example.id + cdn_frontdoor_origin_group_id = azurerm_cdn_frontdoor_origin_group.example.id + cdn_frontdoor_origin_ids = [azurerm_cdn_frontdoor_origin.example.id] + enabled = true + + https_redirect_enabled = true + forwarding_protocol = "HttpsOnly" + patterns_to_match = ["/*"] + supported_protocols = ["Http", "Https"] + cdn_frontdoor_rule_set_ids = [azurerm_cdn_frontdoor_rule_set.example.id] + + cdn_frontdoor_custom_domain_ids = [azurerm_cdn_frontdoor_custom_domain.contoso.id] + link_to_default_domain = false + + cache { + compression_enabled = true + content_types_to_compress = ["text/html", "text/javascript", "text/xml"] + query_strings = ["account", "settings", "foo", "bar"] + query_string_caching_behavior = "IgnoreSpecifiedQueryStrings" + } +} + resource "azurerm_cdn_frontdoor_custom_domain" "contoso" { name = "${var.prefix}-custom-domain" cdn_frontdoor_profile_id = azurerm_cdn_frontdoor_profile.example.id dns_zone_id = azurerm_dns_zone.example.id host_name = join(".", ["contoso", azurerm_dns_zone.example.name]) - associate_with_cdn_frontdoor_route_id = azurerm_cdn_frontdoor_route.example.id - tls { certificate_type = "CustomerCertificate" minimum_tls_version = "TLS12" @@ -303,6 +325,11 @@ resource "azurerm_cdn_frontdoor_custom_domain" "contoso" { } } +resource "azurerm_cdn_frontdoor_custom_domain_association" "contoso" { + cdn_frontdoor_custom_domain_id = azurerm_cdn_frontdoor_custom_domain.contoso.id + cdn_frontdoor_route_ids = [azurerm_cdn_frontdoor_route.example.id] +} + resource "azurerm_dns_txt_record" "contoso" { name = join(".", ["_dnsauth", "contoso"]) zone_name = azurerm_dns_zone.example.name @@ -314,33 +341,6 @@ resource "azurerm_dns_txt_record" "contoso" { } } -resource "azurerm_cdn_frontdoor_route" "example" { - name = "${var.prefix}-route" - cdn_frontdoor_endpoint_id = azurerm_cdn_frontdoor_endpoint.example.id - cdn_frontdoor_origin_group_id = azurerm_cdn_frontdoor_origin_group.example.id - cdn_frontdoor_origin_ids = [azurerm_cdn_frontdoor_origin.example.id] - enabled = true - - https_redirect_enabled = true - forwarding_protocol = "HttpsOnly" - - patterns_to_match = ["/*"] - supported_protocols = ["Http", "Https"] - cdn_frontdoor_rule_set_ids = [azurerm_cdn_frontdoor_rule_set.example.id] - - cache { - compression_enabled = true - content_types_to_compress = ["text/html", "text/javascript", "text/xml"] - query_strings = ["account", "settings", "foo", "bar"] - query_string_caching_behavior = "IgnoreSpecifiedQueryStrings" - } -} - -resource "azurerm_cdn_frontdoor_route_disable_link_to_default_domain" "example" { - cdn_frontdoor_route_id = azurerm_cdn_frontdoor_route.example.id - cdn_frontdoor_custom_domain_ids = [azurerm_cdn_frontdoor_custom_domain.contoso.id] -} - resource "azurerm_dns_cname_record" "contoso" { depends_on = [azurerm_cdn_frontdoor_route.example, azurerm_cdn_frontdoor_security_policy.example] diff --git a/examples/cdn/frontdoor/frontdoor-managed-ssl-certificate-with-multiple-custom-domains/main.tf b/examples/cdn/frontdoor/frontdoor-managed-ssl-certificate-with-multiple-custom-domains/main.tf index 409bb781850d..2f4142ebe9b1 100644 --- a/examples/cdn/frontdoor/frontdoor-managed-ssl-certificate-with-multiple-custom-domains/main.tf +++ b/examples/cdn/frontdoor/frontdoor-managed-ssl-certificate-with-multiple-custom-domains/main.tf @@ -223,6 +223,9 @@ resource "azurerm_cdn_frontdoor_route" "example" { supported_protocols = ["Http", "Https"] cdn_frontdoor_rule_set_ids = [azurerm_cdn_frontdoor_rule_set.example.id] + cdn_frontdoor_custom_domain_ids = [azurerm_cdn_frontdoor_custom_domain.contoso.id, azurerm_cdn_frontdoor_custom_domain.fabrikam.id] + link_to_default_domain = false + cache { compression_enabled = true content_types_to_compress = ["text/html", "text/javascript", "text/xml"] @@ -231,19 +234,12 @@ resource "azurerm_cdn_frontdoor_route" "example" { } } -resource "azurerm_cdn_frontdoor_route_disable_link_to_default_domain" "example" { - cdn_frontdoor_route_id = azurerm_cdn_frontdoor_route.example.id - cdn_frontdoor_custom_domain_ids = [azurerm_cdn_frontdoor_custom_domain.contoso.id, azurerm_cdn_frontdoor_custom_domain.fabrikam.id] -} - resource "azurerm_cdn_frontdoor_custom_domain" "contoso" { name = "${var.prefix}-contoso-custom-domain" cdn_frontdoor_profile_id = azurerm_cdn_frontdoor_profile.example.id dns_zone_id = azurerm_dns_zone.example.id host_name = join(".", ["contoso", azurerm_dns_zone.example.name]) - associate_with_cdn_frontdoor_route_id = azurerm_cdn_frontdoor_route.example.id - tls { certificate_type = "ManagedCertificate" minimum_tls_version = "TLS12" @@ -256,14 +252,22 @@ resource "azurerm_cdn_frontdoor_custom_domain" "fabrikam" { dns_zone_id = azurerm_dns_zone.example.id host_name = join(".", ["fabrikam", azurerm_dns_zone.example.name]) - associate_with_cdn_frontdoor_route_id = azurerm_cdn_frontdoor_route.example.id - tls { certificate_type = "ManagedCertificate" minimum_tls_version = "TLS12" } } +resource "azurerm_cdn_frontdoor_custom_domain_association" "contoso" { + cdn_frontdoor_custom_domain_id = azurerm_cdn_frontdoor_custom_domain.contoso.id + cdn_frontdoor_route_ids = [azurerm_cdn_frontdoor_route.example.id] +} + +resource "azurerm_cdn_frontdoor_custom_domain_association" "fabrikam" { + cdn_frontdoor_custom_domain_id = azurerm_cdn_frontdoor_custom_domain.fabrikam.id + cdn_frontdoor_route_ids = [azurerm_cdn_frontdoor_route.example.id] +} + resource "azurerm_dns_txt_record" "contoso" { name = join(".", ["_dnsauth", "contoso"]) zone_name = azurerm_dns_zone.example.name diff --git a/internal/services/cdn/cdn_frontdoor_custom_domain_resource.go b/internal/services/cdn/cdn_frontdoor_custom_domain_resource.go index 4103fb791155..0e0dbb778dad 100644 --- a/internal/services/cdn/cdn_frontdoor_custom_domain_resource.go +++ b/internal/services/cdn/cdn_frontdoor_custom_domain_resource.go @@ -24,7 +24,7 @@ func resourceCdnFrontDoorCustomDomain() *pluginsdk.Resource { Delete: resourceCdnFrontDoorCustomDomainDelete, Timeouts: &pluginsdk.ResourceTimeout{ - // NOTE: These timeouts are extreamly long due to the manual + // NOTE: These timeouts are extremely long due to the manual // step of approving the private link if defined. Create: pluginsdk.DefaultTimeout(12 * time.Hour), Read: pluginsdk.DefaultTimeout(5 * time.Minute), diff --git a/internal/services/cdn/cdn_frontdoor_helpers.go b/internal/services/cdn/cdn_frontdoor_helpers.go index e85073b8e55e..9c22c837dc09 100644 --- a/internal/services/cdn/cdn_frontdoor_helpers.go +++ b/internal/services/cdn/cdn_frontdoor_helpers.go @@ -329,11 +329,11 @@ func updateRouteAssociations(d *pluginsdk.ResourceData, meta interface{}, routeI updateProps.LinkToDefaultDomain = cdn.LinkToDefaultDomainEnabled } - updatePrarams := azuresdkhacks.RouteUpdateParameters{ + updateParams := azuresdkhacks.RouteUpdateParameters{ RouteUpdatePropertiesParameters: &updateProps, } - future, err := workaroundsClient.Update(ctx, routeId.ResourceGroup, routeId.ProfileName, routeId.AfdEndpointName, routeId.RouteName, updatePrarams) + future, err := workaroundsClient.Update(ctx, routeId.ResourceGroup, routeId.ProfileName, routeId.AfdEndpointName, routeId.RouteName, updateParams) if err != nil { return fmt.Errorf("%s: updating the association with %s: %+v", *customDomainID, *routeId, err) } @@ -345,7 +345,8 @@ func updateRouteAssociations(d *pluginsdk.ResourceData, meta interface{}, routeI return nil } -func validateCustomDomanLinkToDefaultDomainState(resourceCustomDomains []interface{}, routeCustomDomains []interface{}, routeName string, routeProfile string) error { +func validateCustomDomainLinkToDefaultDomainState(resourceCustomDomains []interface{}, routeCustomDomains []interface{}, routeName string, routeProfile string) error { + // NOTE: Only used in the deprecated custom domain link to default domain resource if !features.FourPointOhBeta() { // Make all of the custom domains belong to the same profile as the route... wrongProfile := make([]string, 0) @@ -406,7 +407,7 @@ func validateCustomDomanLinkToDefaultDomainState(resourceCustomDomains []interfa return nil } -func validateRoutesCustomDomanProfile(customDomains []interface{}, routeName string, routeProfile string) error { +func validateRoutesCustomDomainProfile(customDomains []interface{}, routeName string, routeProfile string) error { // Make all of the custom domains belong to the same profile as the route... wrongProfile := make([]string, 0) @@ -428,7 +429,7 @@ func validateRoutesCustomDomanProfile(customDomains []interface{}, routeName str return nil } -// Validates that the CDN FrontDoor Custom Domain can be associated with the CDN FrontDoor Route or not +// Validates that the CDN FrontDoor Custom Domain can be associated with the CDN FrontDoor Route func validateCustomDomainRoutes(routes *[]parse.FrontDoorRouteId, customDomainID *parse.FrontDoorCustomDomainId) error { if len(*routes) == 0 { return nil @@ -440,19 +441,20 @@ func validateCustomDomainRoutes(routes *[]parse.FrontDoorRouteId, customDomainID } for i, route := range *routes { - // validate route and custom domain profiles match... + // the route and custom domain profiles must match... if customDomainID.ProfileName != route.ProfileName { return fmt.Errorf("the CDN FrontDoor Custom Domain(Name: %q, Profile: %q) and the CDN FrontDoor Route(Name: %q, Profile: %q) must belong to the same CDN FrontDoor Profile", customDomainID.CustomDomainName, customDomainID.ProfileName, route.RouteName, route.ProfileName) } - // validate all routes are using the same endpoint... + // validate all routes are using the same endpoint because a custom domain can not + // be associated with routes that target two different endpoints... for t, nextRoute := range *routes { if i == t { continue } if route.AfdEndpointName != nextRoute.AfdEndpointName { - return fmt.Errorf("the CDN FrontDoor Route(Name: %q) and CDN FrontDoor Route(Name: %q) do not reference the same CDN FrontDoor Endpoint(Name: %q), all CDN FrontDoor Routes must reference the same CDN FrontDoor Endpoint %q to associate this CDN FrontDoor Custom Domain with more than one CDN FrontDoor Route", route.RouteName, nextRoute.RouteName, route.AfdEndpointName, route.AfdEndpointName) + return fmt.Errorf("the CDN FrontDoor Route(Name: %q) and CDN FrontDoor Route(Name: %q) do not reference the same CDN FrontDoor Endpoint(Name: %q). All CDN FrontDoor Routes must reference the same CDN FrontDoor Endpoint %q to associate the CDN FrontDoor Custom Domain(Name: %q) with more than one CDN FrontDoor Route", route.RouteName, nextRoute.RouteName, route.AfdEndpointName, route.AfdEndpointName, customDomainID.CustomDomainName) } } } @@ -470,14 +472,14 @@ func friendlyCustomDomainID(customDomain string) (*parse.FrontDoorCustomDomainId } // Checks to make sure the list of CDN FrontDoor Custom Domains does not contain duplicate entries -func sliceHasDuplicates(input []interface{}, resouceTxt string) error { +func sliceHasDuplicates(input []interface{}, resourceTxt string) error { k := make(map[string]bool) for _, v := range input { if _, d := k[strings.ToLower(v.(string))]; !d { k[strings.ToLower(v.(string))] = true } else { - return fmt.Errorf("duplicate %[1]s detected, please remove all duplicate entries for the %[1]s(ID: %q) from your configuration block", resouceTxt, v.(string)) + return fmt.Errorf("duplicate %[1]s detected, please remove all duplicate entries for the %[1]s(ID: %q) from your configuration block", resourceTxt, v.(string)) } } diff --git a/internal/services/cdn/cdn_frontdoor_route_disable_link_to_default_domain_resource.go b/internal/services/cdn/cdn_frontdoor_route_disable_link_to_default_domain_resource.go index f0ac4cf66dbc..a0bee0bb8d4b 100644 --- a/internal/services/cdn/cdn_frontdoor_route_disable_link_to_default_domain_resource.go +++ b/internal/services/cdn/cdn_frontdoor_route_disable_link_to_default_domain_resource.go @@ -120,7 +120,7 @@ func resourceCdnFrontDoorRouteDisableLinkToDefaultDomainCreate(d *pluginsdk.Reso } // validate the custom domains... - if err := validateCustomDomanLinkToDefaultDomainState(resourceCustomDomains, routeCustomDomains, routeId.RouteName, routeId.ProfileName); err != nil { + if err := validateCustomDomainLinkToDefaultDomainState(resourceCustomDomains, routeCustomDomains, routeId.RouteName, routeId.ProfileName); err != nil { return err } @@ -204,7 +204,7 @@ func resourceCdnFrontDoorRouteDisableLinkToDefaultDomainRead(d *pluginsdk.Resour } // validate the custom domains... - if err := validateCustomDomanLinkToDefaultDomainState(resourceCustomDomains, routeCustomDomains, routeId.RouteName, routeId.ProfileName); err != nil { + if err := validateCustomDomainLinkToDefaultDomainState(resourceCustomDomains, routeCustomDomains, routeId.RouteName, routeId.ProfileName); err != nil { return err } @@ -245,7 +245,7 @@ func resourceCdnFrontDoorRouteDisableLinkToDefaultDomainUpdate(d *pluginsdk.Reso routeCustomDomains := flattenCdnFrontdoorRouteActivatedResourceArray(props.CustomDomains) // validate the custom domains... - if err := validateCustomDomanLinkToDefaultDomainState(resourceCustomDomains, routeCustomDomains, routeId.RouteName, routeId.ProfileName); err != nil { + if err := validateCustomDomainLinkToDefaultDomainState(resourceCustomDomains, routeCustomDomains, routeId.RouteName, routeId.ProfileName); err != nil { return err } diff --git a/internal/services/cdn/cdn_frontdoor_route_resource.go b/internal/services/cdn/cdn_frontdoor_route_resource.go index 2e1edd1e1d1a..c14be5dbedfe 100644 --- a/internal/services/cdn/cdn_frontdoor_route_resource.go +++ b/internal/services/cdn/cdn_frontdoor_route_resource.go @@ -226,7 +226,7 @@ func resourceCdnFrontDoorRouteCreate(d *pluginsdk.ResourceData, meta interface{} var ruleSetIds *[]cdn.ResourceReference protocolsRaw := d.Get("supported_protocols").(*pluginsdk.Set).List() - orginGroupIdRaw := d.Get("cdn_frontdoor_origin_group_id").(string) + originGroupIdRaw := d.Get("cdn_frontdoor_origin_group_id").(string) ruleSetIdsRaw := d.Get("cdn_frontdoor_rule_set_ids").([]interface{}) httpsRedirect := d.Get("https_redirect_enabled").(bool) linkToDefaultDomain := d.Get("link_to_default_domain").(bool) @@ -261,13 +261,13 @@ func resourceCdnFrontDoorRouteCreate(d *pluginsdk.ResourceData, meta interface{} return err } - if err := validateRoutesCustomDomanProfile(customDomains, id.RouteName, id.ProfileName); err != nil { + if err := validateRoutesCustomDomainProfile(customDomains, id.RouteName, id.ProfileName); err != nil { return err } } - if orginGroupIdRaw != "" { - id, err := parse.FrontDoorOriginGroupIDInsensitively(orginGroupIdRaw) + if originGroupIdRaw != "" { + id, err := parse.FrontDoorOriginGroupIDInsensitively(originGroupIdRaw) if err != nil { return err } @@ -424,7 +424,12 @@ func resourceCdnFrontDoorRouteUpdate(d *pluginsdk.ResourceData, meta interface{} customDomains = append(customDomains, id.ID()) } - props := azuresdkhacks.RouteUpdatePropertiesParameters{} + // NOTE: You need to always pass these two on update else you will + // disable your cache and disassociate your custom domains... + props := azuresdkhacks.RouteUpdatePropertiesParameters{ + CustomDomains: existing.RouteProperties.CustomDomains, + CacheConfiguration: existing.RouteProperties.CacheConfiguration, + } if d.HasChange("cache") { props.CacheConfiguration = expandCdnFrontdoorRouteCacheConfiguration(d.Get("cache").([]interface{})) @@ -495,7 +500,7 @@ func resourceCdnFrontDoorRouteUpdate(d *pluginsdk.ResourceData, meta interface{} return err } - if err := validateRoutesCustomDomanProfile(customDomains, id.RouteName, id.ProfileName); err != nil { + if err := validateRoutesCustomDomainProfile(customDomains, id.RouteName, id.ProfileName); err != nil { return err } } @@ -668,9 +673,9 @@ func flattenCdnFrontdoorRouteCacheConfiguration(input *cdn.AfdRouteCacheConfigur queryParameters = flattenCsvToStringSlice(input.QueryParameters) } - cachingBehaviour := "" + cachingBehavior := "" if input.QueryStringCachingBehavior != "" { - cachingBehaviour = string(input.QueryStringCachingBehavior) + cachingBehavior = string(input.QueryStringCachingBehavior) } compressionEnabled := false @@ -686,7 +691,7 @@ func flattenCdnFrontdoorRouteCacheConfiguration(input *cdn.AfdRouteCacheConfigur map[string]interface{}{ "compression_enabled": compressionEnabled, "content_types_to_compress": contentTypesToCompress, - "query_string_caching_behavior": cachingBehaviour, + "query_string_caching_behavior": cachingBehavior, "query_strings": queryParameters, }, } diff --git a/internal/services/cdn/cdn_frontdoor_rule_resource.go b/internal/services/cdn/cdn_frontdoor_rule_resource.go index 9b46af45d868..46fdfabab7bd 100644 --- a/internal/services/cdn/cdn_frontdoor_rule_resource.go +++ b/internal/services/cdn/cdn_frontdoor_rule_resource.go @@ -273,7 +273,7 @@ func resourceCdnFrontDoorRule() *pluginsdk.Resource { }, false), }, - // NOTE: CSV implemented as a list, code alread written for the expaned and flatten to CSV + // NOTE: CSV implemented as a list, code already written for the expanded and flatten to CSV // not valid when IncludeAll or ExcludeAll behavior is defined "query_string_parameters": { Type: pluginsdk.TypeList, @@ -845,7 +845,7 @@ func expandFrontdoorDeliveryRuleActions(input []interface{}) ([]cdn.BasicDeliver } if len(results) > 5 { - return nil, fmt.Errorf("the 'actions' match block may only contain upto 5 match actions, got %d", len(results)) + return nil, fmt.Errorf("the 'actions' match block may only contain up to 5 match actions, got %d", len(results)) } if err := validate.CdnFrontDoorActionsBlock(results); err != nil { @@ -903,7 +903,7 @@ func expandFrontdoorDeliveryRuleConditions(input []interface{}) ([]cdn.BasicDeli } if len(results) > 10 { - return nil, fmt.Errorf("the 'conditions' match block may only contain upto 10 match conditions, got %d", len(results)) + return nil, fmt.Errorf("the 'conditions' match block may only contain up to 10 match conditions, got %d", len(results)) } return results, nil diff --git a/website/docs/r/cdn_frontdoor_custom_domain.html.markdown b/website/docs/r/cdn_frontdoor_custom_domain.html.markdown index 4c67950bd29d..67b35d860140 100644 --- a/website/docs/r/cdn_frontdoor_custom_domain.html.markdown +++ b/website/docs/r/cdn_frontdoor_custom_domain.html.markdown @@ -36,8 +36,6 @@ resource "azurerm_cdn_frontdoor_custom_domain" "example" { dns_zone_id = azurerm_dns_zone.example.id host_name = "contoso.com" - associate_with_cdn_frontdoor_route_ids = [azurerm_cdn_frontdoor_route.example.id] - tls { certificate_type = "ManagedCertificate" minimum_tls_version = "TLS12" @@ -85,8 +83,6 @@ The following arguments are supported: * `host_name` - (Required) The host name of the domain. Changing this forces a new CDN FrontDoor Custom Domain to be created. -* `associate_with_cdn_frontdoor_route_ids` (Optional) - One or more CDN FrontDoor Route resource IDs for which this Custom Domain should be associated with. - * `dns_zone_id` - (Optional) The ID of the DNS Zone which should be used for this FrontDoor Custom Domain. **RECOMMENDATION:** If your CDN FrontDoor deployment contains multiple CDN FrontDoor Route resources it is advised that you should daisy chain a `depends_on` meta-argument to each of the CDN FrontDoor Route resources to avoid the various service code race conditions that arise while moving CDN FrontDoor Custom Domains across multiple CDN FrontDoor Routes. Please see the `Daisy Chain Depends_On Example` below for more details. +-> **RECOMMENDATION:** If your CDN FrontDoor deployment contains multiple CDN FrontDoor Route resources it is advised that you should daisy chain a `depends_on` meta-argument to each of the CDN FrontDoor Route resources to avoid the various service code race conditions that arise while moving CDN FrontDoor Custom Domains across multiple CDN FrontDoor Routes. Keep in mind that the `depends_on` daisy chain will not guard against all potential race conditions depending on how you moving your CDN FrontDoor Custom Domains across your CDN FrontDoor Route resources, but it will alleviate a vast majority of the issues that may occur. Please see the `Daisy Chain Depends_On Example` below for more details. ## Example Usage @@ -118,17 +118,34 @@ resource "azurerm_cdn_frontdoor_custom_domain_association" "fabrikam" { ```hcl resource "azurerm_cdn_frontdoor_route" "first" { - ... + name = "example-route-one" + cdn_frontdoor_endpoint_id = azurerm_cdn_frontdoor_endpoint.example.id + cdn_frontdoor_origin_group_id = azurerm_cdn_frontdoor_origin_group.example.id + cdn_frontdoor_origin_ids = [azurerm_cdn_frontdoor_origin.example.id] + cdn_frontdoor_rule_set_ids = [azurerm_cdn_frontdoor_rule_set.example.id] + enabled = true } resource "azurerm_cdn_frontdoor_route" "second" { depends_on = [azurerm_cdn_frontdoor_route.first] - ... + + name = "example-route-two" + cdn_frontdoor_endpoint_id = azurerm_cdn_frontdoor_endpoint.example.id + cdn_frontdoor_origin_group_id = azurerm_cdn_frontdoor_origin_group.example.id + cdn_frontdoor_origin_ids = [azurerm_cdn_frontdoor_origin.example.id] + cdn_frontdoor_rule_set_ids = [azurerm_cdn_frontdoor_rule_set.example.id] + enabled = true } resource "azurerm_cdn_frontdoor_route" "third" { depends_on = [azurerm_cdn_frontdoor_route.first, azurerm_cdn_frontdoor_route.second] - ... + + name = "example-route-three" + cdn_frontdoor_endpoint_id = azurerm_cdn_frontdoor_endpoint.example.id + cdn_frontdoor_origin_group_id = azurerm_cdn_frontdoor_origin_group.example.id + cdn_frontdoor_origin_ids = [azurerm_cdn_frontdoor_origin.example.id] + cdn_frontdoor_rule_set_ids = [azurerm_cdn_frontdoor_rule_set.example.id] + enabled = true } ``` From 61137016c1b6a6c7f0cb086ef4c9bf2cfae211b5 Mon Sep 17 00:00:00 2001 From: Jeffrey Cline <20408400+WodansSon@users.noreply.github.com> Date: Fri, 7 Oct 2022 20:36:56 -0600 Subject: [PATCH 14/58] terrafmt --- .../cdn_frontdoor_custom_domain_association_resource_test.go | 4 ++-- .../services/cdn/cdn_frontdoor_custom_domain_resource_test.go | 1 + 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/internal/services/cdn/cdn_frontdoor_custom_domain_association_resource_test.go b/internal/services/cdn/cdn_frontdoor_custom_domain_association_resource_test.go index 0a3605827fee..8cddc564da4c 100644 --- a/internal/services/cdn/cdn_frontdoor_custom_domain_association_resource_test.go +++ b/internal/services/cdn/cdn_frontdoor_custom_domain_association_resource_test.go @@ -107,7 +107,7 @@ func (r CdnFrontDoorCustomDomainAssociationResource) Exists(ctx context.Context, } func (r CdnFrontDoorCustomDomainAssociationResource) preCheck(t *testing.T) { - // NOTE: To test custom domain you need to have an actual real hosted domain, + // NOTE: To test custom domain association you need to have an actual real hosted domain, // for manual testing I have purchased my own domain to verify functionality. if v := os.Getenv("ARM_TEST_CDN_FRONT_DOOR_CUSTOM_DOMAIN_HOST"); v == "" { t.Skipf("skipping tests `ARM_TEST_CDN_FRONT_DOOR_CUSTOM_DOMAIN_HOST` not defined, live web hosting is required for DNS naming server redirect.") @@ -172,7 +172,7 @@ resource "azurerm_cdn_frontdoor_custom_domain_association" "test" { func (r CdnFrontDoorCustomDomainAssociationResource) template(data acceptance.TestData) string { return fmt.Sprintf(` - provider "azurerm" { +provider "azurerm" { features {} } diff --git a/internal/services/cdn/cdn_frontdoor_custom_domain_resource_test.go b/internal/services/cdn/cdn_frontdoor_custom_domain_resource_test.go index 908e780d0770..7b33078a2963 100644 --- a/internal/services/cdn/cdn_frontdoor_custom_domain_resource_test.go +++ b/internal/services/cdn/cdn_frontdoor_custom_domain_resource_test.go @@ -102,6 +102,7 @@ func (r CdnFrontDoorCustomDomainResource) Exists(ctx context.Context, clients *c } return nil, fmt.Errorf("retrieving %s: %+v", id, err) } + return utils.Bool(true), nil } From f57c8a4f1d075563a93b54f1a8be9fd3bf1b42b1 Mon Sep 17 00:00:00 2001 From: Jeffrey Cline <20408400+WodansSon@users.noreply.github.com> Date: Sun, 9 Oct 2022 01:47:28 -0600 Subject: [PATCH 15/58] Fix up some loose ends and test cases --- ...door_custom_domain_association_resource.go | 212 +++++++----------- ...custom_domain_association_resource_test.go | 178 +++++++-------- .../cdn_frontdoor_custom_domain_resource.go | 12 + ...n_frontdoor_custom_domain_resource_test.go | 46 +--- .../cdn_frontdoor_firewall_policy_resource.go | 17 +- ...le_link_to_default_domain_resource_test.go | 36 +-- .../cdn/cdn_frontdoor_route_resource.go | 10 +- .../front_door_custom_domain_association.go | 40 +--- ...ont_door_custom_domain_association_test.go | 99 +++----- internal/services/cdn/resourceids.go | 2 +- ..._door_custom_domain_association_id_test.go | 20 +- 11 files changed, 264 insertions(+), 408 deletions(-) diff --git a/internal/services/cdn/cdn_frontdoor_custom_domain_association_resource.go b/internal/services/cdn/cdn_frontdoor_custom_domain_association_resource.go index baee82f676ae..a8ca2fbaf73c 100644 --- a/internal/services/cdn/cdn_frontdoor_custom_domain_association_resource.go +++ b/internal/services/cdn/cdn_frontdoor_custom_domain_association_resource.go @@ -5,7 +5,6 @@ import ( "log" "time" - "github.com/hashicorp/go-uuid" "github.com/hashicorp/terraform-provider-azurerm/internal/services/cdn/parse" "github.com/hashicorp/terraform-provider-azurerm/internal/services/cdn/validate" "github.com/hashicorp/terraform-provider-azurerm/internal/tf/pluginsdk" @@ -30,7 +29,7 @@ func resourceCdnFrontDoorCustomDomainAssociation() *pluginsdk.Resource { }, Importer: pluginsdk.ImporterValidatingResourceId(func(id string) error { - if _, err := parse.FrontDoorRouteDisableLinkToDefaultDomainID(id); err != nil { + if _, err := parse.FrontDoorCustomDomainAssociationID(id); err != nil { return err } return nil @@ -58,177 +57,136 @@ func resourceCdnFrontDoorCustomDomainAssociation() *pluginsdk.Resource { } func resourceCdnFrontDoorCustomDomainAssociationCreate(d *pluginsdk.ResourceData, meta interface{}) error { - log.Printf("[INFO] preparing arguments for CDN FrontDoor Custom Domain Association") - customDomain := d.Get("cdn_frontdoor_custom_domain_id").(string) - configRouteIds := d.Get("cdn_frontdoor_route_ids").([]interface{}) + log.Printf("[INFO] preparing arguments for CDN FrontDoor Route <-> CDN FrontDoor Custom Domain Association creation") - customDomainId, err := parse.FrontDoorCustomDomainIDInsensitively(customDomain) - if err != nil { + if customDomain, err := expandCustomDomain(d.Get("cdn_frontdoor_custom_domain_id").(string)); err != nil { return err - } + } else if customDomain != nil { + id := parse.NewFrontDoorCustomDomainAssociationID(customDomain.SubscriptionId, customDomain.ResourceGroup, customDomain.ProfileName, customDomain.CustomDomainName) - // create the resource id - uuid, err := uuid.GenerateUUID() - if err != nil { - return fmt.Errorf("generating UUID: %+v", err) - } - id := parse.NewFrontDoorCustomDomainAssociationID(customDomainId.SubscriptionId, customDomainId.ResourceGroup, customDomainId.ProfileName, customDomainId.CustomDomainName, uuid) + // TODO: Get import error to work + // if !utils.ResponseWasNotFound(existing.Response) { + // return tf.ImportAsExistsError("azurerm_cdn_frontdoor_custom_domain_association", id.ID()) + // } - routeIds, normalizedRoutes, err := normalizeRouteIds(configRouteIds) - if err != nil { - return err + d.SetId(id.ID()) } - for _, routeId := range *routeIds { - // Make sure the route exists and get the routes custom domain association list... - routeAssociations, _, err := getRouteProperties(d, meta, &routeId, "cdn_frontdoor_custom_domain_association") - if err != nil { - return err - } + return resourceCdnFrontDoorCustomDomainAssociationRead(d, meta) +} - // Make sure the custom domain is in the routes association list - if len(routeAssociations) == 0 || !sliceContainsString(routeAssociations, customDomainId.ID()) { - return fmt.Errorf(notAssociatedErr, routeId.RouteName, customDomainId.CustomDomainName) - } +func resourceCdnFrontDoorCustomDomainAssociationRead(d *pluginsdk.ResourceData, meta interface{}) error { + if customDomain, err := expandCustomDomain(d.Get("cdn_frontdoor_custom_domain_id").(string)); err != nil { + return err + } else if customDomain != nil { + d.Set("cdn_frontdoor_custom_domain_id", customDomain.ID()) + d.Set("cdn_frontdoor_route_ids", d.Get("cdn_frontdoor_route_ids").([]interface{})) } - // validate the routes... - if len(*routeIds) != 0 { - if err := validateCustomDomainRoutes(routeIds, customDomainId); err != nil { + return nil +} + +func resourceCdnFrontDoorCustomDomainAssociationUpdate(d *pluginsdk.ResourceData, meta interface{}) error { + if customDomain, err := expandCustomDomain(d.Get("cdn_frontdoor_custom_domain_id").(string)); err != nil { + return err + } else if customDomain != nil { + _, err := expandRouteIds(d, meta, customDomain) + if err != nil { return err } } - d.SetId(id.ID()) - d.Set("cdn_frontdoor_custom_domain_id", customDomainId.ID()) - d.Set("cdn_frontdoor_route_ids", normalizedRoutes) - return resourceCdnFrontDoorCustomDomainAssociationRead(d, meta) } -func resourceCdnFrontDoorCustomDomainAssociationRead(d *pluginsdk.ResourceData, meta interface{}) error { - customDomain := d.Get("cdn_frontdoor_custom_domain_id").(string) - configRouteIds := d.Get("cdn_frontdoor_route_ids").([]interface{}) +func resourceCdnFrontDoorCustomDomainAssociationDelete(d *pluginsdk.ResourceData, meta interface{}) error { + // since you are deleting the resource you cannot grab the value from the config + // because it will be empty, you have to get it from the states old value... + oldCustomDomain, _ := d.GetChange("cdn_frontdoor_custom_domain_id") + customDomain, _ := expandCustomDomain(oldCustomDomain.(string)) - customDomainId, err := parse.FrontDoorCustomDomainIDInsensitively(customDomain) - if err != nil { - return err - } + old, _ := d.GetChange("cdn_frontdoor_route_ids") + oldRoutes := old.([]interface{}) - routeIds, normalizedRoutes, err := normalizeRouteIds(configRouteIds) + routes, _, err := normalizeRouteIds(oldRoutes) if err != nil { return err } - // Only do the validation if you are not deleting the resource... - if d.HasChange("cdn_frontdoor_route_ids") { - if _, newRoute := d.GetChange("cdn_frontdoor_route_ids"); len(newRoute.([]interface{})) != 0 { - for _, route := range *routeIds { - // Make sure the route exists and get the routes custom domain association list... - routeAssociations, _, err := getRouteProperties(d, meta, &route, "cdn_frontdoor_custom_domain_association") - if err != nil { - return err - } - - // Make sure the custom domain is in the routes association list - if len(routeAssociations) == 0 || !sliceContainsString(routeAssociations, customDomainId.ID()) { - return fmt.Errorf(notAssociatedErr, route.RouteName, customDomainId.CustomDomainName) - } - } - - // validate the routes... - if len(*routeIds) != 0 { - if err := validateCustomDomainRoutes(routeIds, customDomainId); err != nil { - return err - } - } + if len(*routes) != 0 { + if err := removeCustomDomainAssociationFromRoutes(d, meta, routes, customDomain); err != nil { + return err } } - d.Set("cdn_frontdoor_custom_domain_id", customDomainId.ID()) - d.Set("cdn_frontdoor_route_ids", normalizedRoutes) + d.SetId("") return nil } -func resourceCdnFrontDoorCustomDomainAssociationUpdate(d *pluginsdk.ResourceData, meta interface{}) error { - customDomain := d.Get("cdn_frontdoor_custom_domain_id").(string) +func expandCustomDomain(input string) (*parse.FrontDoorCustomDomainId, error) { + if len(input) == 0 || input == "" { + return nil, nil + } - customDomainId, err := parse.FrontDoorCustomDomainIDInsensitively(customDomain) + customDomain, err := parse.FrontDoorCustomDomainIDInsensitively(input) if err != nil { - return err + return nil, err } - if d.HasChange("cdn_frontdoor_route_ids") { - old, new := d.GetChange("cdn_frontdoor_route_ids") - oldRoutes := old.([]interface{}) - newRoutes := new.([]interface{}) - - oldRouteIds, _, err := normalizeRouteIds(oldRoutes) - if err != nil { - return err - } - - newRouteIds, newNormalizedRoutes, err := normalizeRouteIds(newRoutes) - if err != nil { - return err - } + return customDomain, nil +} - // validate the new routes... - if len(*newRouteIds) != 0 { - for _, newRoute := range *newRouteIds { - // Make sure the route exists and get the routes custom domain association list... - routeAssociations, _, err := getRouteProperties(d, meta, &newRoute, "cdn_frontdoor_custom_domain_association") - if err != nil { - return err - } - - // Make sure the custom domain is in the routes association list - if len(routeAssociations) == 0 || !sliceContainsString(routeAssociations, customDomainId.ID()) { - return fmt.Errorf(notAssociatedErr, newRoute.RouteName, customDomainId.CustomDomainName) - } - } +func expandRouteIds(d *pluginsdk.ResourceData, meta interface{}, customDomain *parse.FrontDoorCustomDomainId) ([]interface{}, error) { + out := make([]interface{}, 0) - if err := validateCustomDomainRoutes(newRouteIds, customDomainId); err != nil { - return err - } - } + old, new := d.GetChange("cdn_frontdoor_route_ids") + oldRoutes := old.([]interface{}) + newRoutes := new.([]interface{}) - // now get the delta between the old and the new list, if any custom domains were removed from - // the list we need to remove the custom domain association from those routes... - if delta, _ := routeDelta(oldRouteIds, newRouteIds); len(*delta) != 0 { - if err = removeCustomDomainAssociationFromRoutes(d, meta, delta, customDomainId); err != nil { - return err - } - - d.Set("cdn_frontdoor_route_ids", newNormalizedRoutes) - } + if len(newRoutes) == 0 || newRoutes == nil || customDomain == nil { + return out, nil } - return nil -} - -func resourceCdnFrontDoorCustomDomainAssociationDelete(d *pluginsdk.ResourceData, meta interface{}) error { - customDomain := d.Get("cdn_frontdoor_custom_domain_id").(string) - configRouteIds := d.Get("cdn_frontdoor_route_ids").([]interface{}) - - customDomainId, err := parse.FrontDoorCustomDomainIDInsensitively(customDomain) + oldRouteIds, _, err := normalizeRouteIds(oldRoutes) if err != nil { - return err + return nil, err } - routeIds, _, err := normalizeRouteIds(configRouteIds) + newRouteIds, out, err := normalizeRouteIds(newRoutes) if err != nil { - return err + return nil, err } - if len(*routeIds) != 0 { - if err := removeCustomDomainAssociationFromRoutes(d, meta, routeIds, customDomainId); err != nil { - return err + // validate the new routes... + if len(*newRouteIds) != 0 { + for _, newRoute := range *newRouteIds { + // Make sure the route exists and get the routes custom domain association list... + routeAssociations, _, err := getRouteProperties(d, meta, &newRoute, "cdn_frontdoor_custom_domain_association") + if err != nil { + return nil, err + } + + // Make sure the custom domain is in the routes association list + if len(routeAssociations) == 0 || !sliceContainsString(routeAssociations, customDomain.ID()) { + return nil, fmt.Errorf(notAssociatedErr, newRoute.RouteName, customDomain.CustomDomainName) + } + } + + if err := validateCustomDomainRoutes(newRouteIds, customDomain); err != nil { + return nil, err } } - d.SetId("") + if len(oldRoutes) != 0 { + // now get the delta between the old and the new list, if any custom domains were removed from + // the list we need to remove the custom domain association from those routes... + if delta, _ := routeDelta(oldRouteIds, newRouteIds); len(*delta) != 0 { + if err = removeCustomDomainAssociationFromRoutes(d, meta, delta, customDomain); err != nil { + return nil, err + } + } + } - return nil + return out, nil } diff --git a/internal/services/cdn/cdn_frontdoor_custom_domain_association_resource_test.go b/internal/services/cdn/cdn_frontdoor_custom_domain_association_resource_test.go index 8cddc564da4c..cd2ef1ffd54a 100644 --- a/internal/services/cdn/cdn_frontdoor_custom_domain_association_resource_test.go +++ b/internal/services/cdn/cdn_frontdoor_custom_domain_association_resource_test.go @@ -3,7 +3,6 @@ package cdn_test import ( "context" "fmt" - "os" "testing" "github.com/hashicorp/terraform-provider-azurerm/internal/acceptance" @@ -17,10 +16,11 @@ import ( type CdnFrontDoorCustomDomainAssociationResource struct { } +// NOTE: There isn't a complete test case because the basic and the +// update together equals what the complete test case would be... func TestAccCdnFrontDoorCustomDomainAssociation_basic(t *testing.T) { data := acceptance.BuildTestData(t, "azurerm_cdn_frontdoor_custom_domain_association", "test") r := CdnFrontDoorCustomDomainAssociationResource{} - r.preCheck(t) data.ResourceTest(t, r, []acceptance.TestStep{ { @@ -29,14 +29,27 @@ func TestAccCdnFrontDoorCustomDomainAssociation_basic(t *testing.T) { check.That(data.ResourceName).ExistsInAzure(r), ), }, - data.ImportStep(), }) } -func TestAccCdnFrontDoorCustomDomainAssociation_requiresImport(t *testing.T) { +// TODO: Implement the requires import functionality +// func TestAccCdnFrontDoorCustomDomainAssociation_requiresImport(t *testing.T) { +// data := acceptance.BuildTestData(t, "azurerm_cdn_frontdoor_custom_domain_association", "test") +// r := CdnFrontDoorCustomDomainAssociationResource{} +// data.ResourceTest(t, r, []acceptance.TestStep{ +// { +// Config: r.basic(data), +// Check: acceptance.ComposeTestCheckFunc( +// check.That(data.ResourceName).ExistsInAzure(r), +// ), +// }, +// data.RequiresImportErrorStep(r.requiresImport), +// }) +// } + +func TestAccCdnFrontDoorCustomDomainAssociation_destroyAssociation(t *testing.T) { data := acceptance.BuildTestData(t, "azurerm_cdn_frontdoor_custom_domain_association", "test") r := CdnFrontDoorCustomDomainAssociationResource{} - r.preCheck(t) data.ResourceTest(t, r, []acceptance.TestStep{ { @@ -45,46 +58,30 @@ func TestAccCdnFrontDoorCustomDomainAssociation_requiresImport(t *testing.T) { check.That(data.ResourceName).ExistsInAzure(r), ), }, - data.RequiresImportErrorStep(r.requiresImport), + { + Config: r.destroy(data), + Check: acceptance.ComposeTestCheckFunc(), + ExpectNonEmptyPlan: true, //since deleting this resource actually removes the linked custom domain from the route resource(s) + }, }) } -func TestAccCdnFrontDoorCustomDomainAssociation_update(t *testing.T) { +func TestAccCdnFrontDoorCustomDomainAssociation_DestroyAssociations(t *testing.T) { data := acceptance.BuildTestData(t, "azurerm_cdn_frontdoor_custom_domain_association", "test") r := CdnFrontDoorCustomDomainAssociationResource{} - r.preCheck(t) data.ResourceTest(t, r, []acceptance.TestStep{ - { - Config: r.complete(data), - Check: acceptance.ComposeTestCheckFunc( - check.That(data.ResourceName).ExistsInAzure(r), - ), - }, - data.ImportStep(), { Config: r.update(data), Check: acceptance.ComposeTestCheckFunc( check.That(data.ResourceName).ExistsInAzure(r), ), }, - data.ImportStep(), - }) -} - -func TestAccCdnFrontDoorCustomDomainAssociation_complete(t *testing.T) { - data := acceptance.BuildTestData(t, "azurerm_cdn_frontdoor_custom_domain_association", "test") - r := CdnFrontDoorCustomDomainAssociationResource{} - r.preCheck(t) - - data.ResourceTest(t, r, []acceptance.TestStep{ { - Config: r.complete(data), - Check: acceptance.ComposeTestCheckFunc( - check.That(data.ResourceName).ExistsInAzure(r), - ), + Config: r.destroy(data), + Check: acceptance.ComposeTestCheckFunc(), + ExpectNonEmptyPlan: true, //since deleting this resource actually removes the linked custom domain from the route resource(s) }, - data.ImportStep(), }) } @@ -95,7 +92,7 @@ func (r CdnFrontDoorCustomDomainAssociationResource) Exists(ctx context.Context, } client := clients.Cdn.FrontDoorCustomDomainsClient - resp, err := client.Get(ctx, id.ResourceGroup, id.ProfileName, id.CustomDomainName) + resp, err := client.Get(ctx, id.ResourceGroup, id.ProfileName, id.AssociationName) if err != nil { if utils.ResponseWasNotFound(resp.Response) { return utils.Bool(false), nil @@ -106,68 +103,70 @@ func (r CdnFrontDoorCustomDomainAssociationResource) Exists(ctx context.Context, return utils.Bool(true), nil } -func (r CdnFrontDoorCustomDomainAssociationResource) preCheck(t *testing.T) { - // NOTE: To test custom domain association you need to have an actual real hosted domain, - // for manual testing I have purchased my own domain to verify functionality. - if v := os.Getenv("ARM_TEST_CDN_FRONT_DOOR_CUSTOM_DOMAIN_HOST"); v == "" { - t.Skipf("skipping tests `ARM_TEST_CDN_FRONT_DOOR_CUSTOM_DOMAIN_HOST` not defined, live web hosting is required for DNS naming server redirect.") - } -} - func (r CdnFrontDoorCustomDomainAssociationResource) basic(data acceptance.TestData) string { template := r.template(data) return fmt.Sprintf(` %s resource "azurerm_cdn_frontdoor_custom_domain_association" "test" { - cdn_frontdoor_custom_domain_id = azurerm_cdn_frontdoor_custom_domain.test.id - cdn_frontdoor_route_ids = [azurerm_cdn_frontdoor_route.test.id] + cdn_frontdoor_custom_domain_id = azurerm_cdn_frontdoor_custom_domain.contoso.id + cdn_frontdoor_route_ids = [azurerm_cdn_frontdoor_route.contoso.id] } `, template) } -func (r CdnFrontDoorCustomDomainAssociationResource) requiresImport(data acceptance.TestData) string { - config := r.basic(data) - return fmt.Sprintf(` -%s +// func (r CdnFrontDoorCustomDomainAssociationResource) requiresImport(data acceptance.TestData) string { +// config := r.basic(data) +// return fmt.Sprintf(` +// %s -resource "azurerm_cdn_frontdoor_custom_domain_association" "import" { - cdn_frontdoor_custom_domain_id = azurerm_cdn_frontdoor_custom_domain.test.id - cdn_frontdoor_route_ids = [azurerm_cdn_frontdoor_route.test.id] -} -`, config) -} +// resource "azurerm_cdn_frontdoor_custom_domain_association" "import" { +// cdn_frontdoor_custom_domain_id = azurerm_cdn_frontdoor_custom_domain_association.test.cdn_frontdoor_custom_domain_id +// cdn_frontdoor_route_ids = azurerm_cdn_frontdoor_custom_domain_association.test.cdn_frontdoor_route_ids +// } +// `, config) +// } func (r CdnFrontDoorCustomDomainAssociationResource) update(data acceptance.TestData) string { template := r.template(data) return fmt.Sprintf(` %s +resource "azurerm_cdn_frontdoor_route" "fabrikam" { + name = "acctest-fabrikam-%[2]d" + cdn_frontdoor_endpoint_id = azurerm_cdn_frontdoor_endpoint.test.id + cdn_frontdoor_origin_group_id = azurerm_cdn_frontdoor_origin_group.test.id + cdn_frontdoor_origin_ids = [azurerm_cdn_frontdoor_origin.test.id] + enabled = true + + https_redirect_enabled = true + forwarding_protocol = "HttpsOnly" + patterns_to_match = ["/sub-%[3]s"] + supported_protocols = ["Http", "Https"] + + cdn_frontdoor_custom_domain_ids = [azurerm_cdn_frontdoor_custom_domain.contoso.id] + link_to_default_domain = true + + cache { + compression_enabled = true + content_types_to_compress = ["text/html", "text/javascript", "text/xml"] + query_strings = ["account", "settings", "foo", "bar"] + query_string_caching_behavior = "IgnoreSpecifiedQueryStrings" + } +} + resource "azurerm_cdn_frontdoor_custom_domain_association" "test" { - cdn_frontdoor_custom_domain_id = azurerm_cdn_frontdoor_custom_domain.test.id - cdn_frontdoor_route_ids = [azurerm_cdn_frontdoor_route.test.id, azurerm_cdn_frontdoor_route.two.id] + cdn_frontdoor_custom_domain_id = azurerm_cdn_frontdoor_custom_domain.contoso.id + cdn_frontdoor_route_ids = [azurerm_cdn_frontdoor_route.contoso.id, azurerm_cdn_frontdoor_route.fabrikam.id] } -`, template) +`, template, data.RandomInteger, data.RandomStringOfLength(10)) } -func (r CdnFrontDoorCustomDomainAssociationResource) complete(data acceptance.TestData) string { +func (r CdnFrontDoorCustomDomainAssociationResource) destroy(data acceptance.TestData) string { template := r.template(data) return fmt.Sprintf(` %s - -resource "azurerm_cdn_frontdoor_custom_domain_association" "test" { - name = "acctestcustomdomain-%d" - cdn_frontdoor_profile_id = azurerm_cdn_frontdoor_profile.test.id - - dns_zone_id = azurerm_dns_zone.test.id - host_name = join(".", ["%s", azurerm_dns_zone.test.name]) - - tls { - certificate_type = "ManagedCertificate" - minimum_tls_version = "TLS10" - } -} -`, template, data.RandomInteger, data.RandomStringOfLength(8)) +`, template) } func (r CdnFrontDoorCustomDomainAssociationResource) template(data acceptance.TestData) string { @@ -182,18 +181,18 @@ resource "azurerm_resource_group" "test" { } resource "azurerm_dns_zone" "test" { - name = "acctestzone%[1]d.com" + name = "acctest-dns-zone.com" resource_group_name = azurerm_resource_group.test.name } resource "azurerm_cdn_frontdoor_profile" "test" { - name = "acctestcdnfdprofile-%[1]d" + name = "acctest-profile-%[1]d" resource_group_name = azurerm_resource_group.test.name sku_name = "Standard_AzureFrontDoor" } resource "azurerm_cdn_frontdoor_origin_group" "test" { - name = "acctest-origin-%[1]d" + name = "acctest-origin-group-%[1]d" cdn_frontdoor_profile_id = azurerm_cdn_frontdoor_profile.test.id session_affinity_enabled = true @@ -230,8 +229,8 @@ resource "azurerm_cdn_frontdoor_endpoint" "test" { enabled = true } -resource "azurerm_cdn_frontdoor_route" "test" { - name = "acctest1-route-%[1]d" +resource "azurerm_cdn_frontdoor_route" "contoso" { + name = "acctest-contoso-%[1]d" cdn_frontdoor_endpoint_id = azurerm_cdn_frontdoor_endpoint.test.id cdn_frontdoor_origin_group_id = azurerm_cdn_frontdoor_origin_group.test.id cdn_frontdoor_origin_ids = [azurerm_cdn_frontdoor_origin.test.id] @@ -242,7 +241,7 @@ resource "azurerm_cdn_frontdoor_route" "test" { patterns_to_match = ["/%[3]s"] supported_protocols = ["Http", "Https"] - cdn_frontdoor_custom_domain_ids = [azurerm_cdn_frontdoor_custom_domain.test.id] + cdn_frontdoor_custom_domain_ids = [azurerm_cdn_frontdoor_custom_domain.contoso.id] link_to_default_domain = false cache { @@ -253,31 +252,8 @@ resource "azurerm_cdn_frontdoor_route" "test" { } } -resource "azurerm_cdn_frontdoor_route" "two" { - name = "acctest2-route-%[1]d" - cdn_frontdoor_endpoint_id = azurerm_cdn_frontdoor_endpoint.test.id - cdn_frontdoor_origin_group_id = azurerm_cdn_frontdoor_origin_group.test.id - cdn_frontdoor_origin_ids = [azurerm_cdn_frontdoor_origin.test.id] - enabled = true - - https_redirect_enabled = true - forwarding_protocol = "HttpsOnly" - patterns_to_match = ["/sub-%[3]s"] - supported_protocols = ["Http", "Https"] - - cdn_frontdoor_custom_domain_ids = [azurerm_cdn_frontdoor_custom_domain.test.id] - link_to_default_domain = true - - cache { - compression_enabled = true - content_types_to_compress = ["text/html", "text/javascript", "text/xml"] - query_strings = ["account", "settings", "foo", "bar"] - query_string_caching_behavior = "IgnoreSpecifiedQueryStrings" - } -} - -resource "azurerm_cdn_frontdoor_custom_domain" "test" { - name = "acctest-custom-domain-%[1]d" +resource "azurerm_cdn_frontdoor_custom_domain" "contoso" { + name = "acctest-contoso-%[1]d" cdn_frontdoor_profile_id = azurerm_cdn_frontdoor_profile.test.id dns_zone_id = azurerm_dns_zone.test.id host_name = join(".", ["%[3]s", azurerm_dns_zone.test.name]) @@ -287,5 +263,5 @@ resource "azurerm_cdn_frontdoor_custom_domain" "test" { minimum_tls_version = "TLS12" } } -`, data.RandomInteger, data.Locations.Primary, data.RandomStringOfLength(9)) +`, data.RandomInteger, data.Locations.Primary, data.RandomStringOfLength(10)) } diff --git a/internal/services/cdn/cdn_frontdoor_custom_domain_resource.go b/internal/services/cdn/cdn_frontdoor_custom_domain_resource.go index 913e1d7bfab2..a17db2d36095 100644 --- a/internal/services/cdn/cdn_frontdoor_custom_domain_resource.go +++ b/internal/services/cdn/cdn_frontdoor_custom_domain_resource.go @@ -6,6 +6,7 @@ import ( "github.com/Azure/azure-sdk-for-go/services/cdn/mgmt/2021-06-01/cdn" dnsValidate "github.com/hashicorp/go-azure-sdk/resource-manager/dns/2018-05-01/zones" + "github.com/hashicorp/terraform-provider-azurerm/helpers/tf" "github.com/hashicorp/terraform-provider-azurerm/internal/clients" "github.com/hashicorp/terraform-provider-azurerm/internal/features" "github.com/hashicorp/terraform-provider-azurerm/internal/services/cdn/parse" @@ -141,6 +142,17 @@ func resourceCdnFrontDoorCustomDomainCreate(d *pluginsdk.ResourceData, meta inte id := parse.NewFrontDoorCustomDomainID(profileId.SubscriptionId, profileId.ResourceGroup, profileId.ProfileName, d.Get("name").(string)) + existing, err := client.Get(ctx, id.ResourceGroup, id.ProfileName, id.CustomDomainName) + if err != nil { + if !utils.ResponseWasNotFound(existing.Response) { + return fmt.Errorf("checking for existing %s: %+v", id, err) + } + } + + if !utils.ResponseWasNotFound(existing.Response) { + return tf.ImportAsExistsError("azurerm_cdn_frontdoor_custom_domain", id.ID()) + } + dnsZone := d.Get("dns_zone_id").(string) tls := d.Get("tls").([]interface{}) diff --git a/internal/services/cdn/cdn_frontdoor_custom_domain_resource_test.go b/internal/services/cdn/cdn_frontdoor_custom_domain_resource_test.go index 7b33078a2963..656c95691239 100644 --- a/internal/services/cdn/cdn_frontdoor_custom_domain_resource_test.go +++ b/internal/services/cdn/cdn_frontdoor_custom_domain_resource_test.go @@ -3,7 +3,6 @@ package cdn_test import ( "context" "fmt" - "os" "testing" "github.com/hashicorp/terraform-provider-azurerm/internal/acceptance" @@ -20,7 +19,6 @@ type CdnFrontDoorCustomDomainResource struct { func TestAccCdnFrontDoorCustomDomain_basic(t *testing.T) { data := acceptance.BuildTestData(t, "azurerm_cdn_frontdoor_custom_domain", "test") r := CdnFrontDoorCustomDomainResource{} - r.preCheck(t) data.ResourceTest(t, r, []acceptance.TestStep{ { @@ -36,7 +34,6 @@ func TestAccCdnFrontDoorCustomDomain_basic(t *testing.T) { func TestAccCdnFrontDoorCustomDomain_requiresImport(t *testing.T) { data := acceptance.BuildTestData(t, "azurerm_cdn_frontdoor_custom_domain", "test") r := CdnFrontDoorCustomDomainResource{} - r.preCheck(t) data.ResourceTest(t, r, []acceptance.TestStep{ { @@ -52,7 +49,6 @@ func TestAccCdnFrontDoorCustomDomain_requiresImport(t *testing.T) { func TestAccCdnFrontDoorCustomDomain_update(t *testing.T) { data := acceptance.BuildTestData(t, "azurerm_cdn_frontdoor_custom_domain", "test") r := CdnFrontDoorCustomDomainResource{} - r.preCheck(t) data.ResourceTest(t, r, []acceptance.TestStep{ { @@ -75,7 +71,6 @@ func TestAccCdnFrontDoorCustomDomain_update(t *testing.T) { func TestAccCdnFrontDoorCustomDomain_complete(t *testing.T) { data := acceptance.BuildTestData(t, "azurerm_cdn_frontdoor_custom_domain", "test") r := CdnFrontDoorCustomDomainResource{} - r.preCheck(t) data.ResourceTest(t, r, []acceptance.TestStep{ { @@ -106,21 +101,9 @@ func (r CdnFrontDoorCustomDomainResource) Exists(ctx context.Context, clients *c return utils.Bool(true), nil } -func (r CdnFrontDoorCustomDomainResource) preCheck(t *testing.T) { - // NOTE: To test custom domain you need to have an actual real hosted domain, - // for manual testing I have purchased my own domain to verify functionality. - if v := os.Getenv("ARM_TEST_CDN_FRONT_DOOR_CUSTOM_DOMAIN_HOST"); v == "" { - t.Skipf("skipping tests `ARM_TEST_CDN_FRONT_DOOR_CUSTOM_DOMAIN_HOST` not defined, live web hosting is required for DNS naming server redirect.") - } -} - func (r CdnFrontDoorCustomDomainResource) basic(data acceptance.TestData) string { template := r.template(data) return fmt.Sprintf(` -provider "azurerm" { - features {} -} - %s resource "azurerm_cdn_frontdoor_custom_domain" "test" { @@ -159,27 +142,17 @@ resource "azurerm_cdn_frontdoor_custom_domain" "import" { func (r CdnFrontDoorCustomDomainResource) update(data acceptance.TestData) string { template := r.template(data) return fmt.Sprintf(` -provider "azurerm" { - features {} -} - %s -resource "azurerm_dns_zone" "update" { - name = "acctestzonealt%[2]d.com" - resource_group_name = azurerm_resource_group.test.name -} - resource "azurerm_cdn_frontdoor_custom_domain" "test" { name = "acctestcustomdomain-%[2]d" cdn_frontdoor_profile_id = azurerm_cdn_frontdoor_profile.test.id - - dns_zone_id = azurerm_dns_zone.update.id - host_name = join(".", ["%s", azurerm_dns_zone.test.name]) + dns_zone_id = azurerm_dns_zone.test.id + host_name = join(".", ["sub-%[3]s", azurerm_dns_zone.test.name]) tls { certificate_type = "ManagedCertificate" - minimum_tls_version = "TLS12" + minimum_tls_version = "TLS10" } } `, template, data.RandomInteger, data.RandomStringOfLength(8)) @@ -188,18 +161,13 @@ resource "azurerm_cdn_frontdoor_custom_domain" "test" { func (r CdnFrontDoorCustomDomainResource) complete(data acceptance.TestData) string { template := r.template(data) return fmt.Sprintf(` -provider "azurerm" { - features {} -} - %s resource "azurerm_cdn_frontdoor_custom_domain" "test" { name = "acctestcustomdomain-%d" cdn_frontdoor_profile_id = azurerm_cdn_frontdoor_profile.test.id - - dns_zone_id = azurerm_dns_zone.test.id - host_name = join(".", ["%s", azurerm_dns_zone.test.name]) + dns_zone_id = azurerm_dns_zone.test.id + host_name = join(".", ["%s", azurerm_dns_zone.test.name]) tls { certificate_type = "ManagedCertificate" @@ -216,6 +184,10 @@ resource "azurerm_cdn_frontdoor_custom_domain" "test" { func (r CdnFrontDoorCustomDomainResource) template(data acceptance.TestData) string { return fmt.Sprintf(` +provider "azurerm" { + features {} +} + resource "azurerm_resource_group" "test" { name = "acctestRG-cdn-afdx-%[1]d" location = "%[2]s" diff --git a/internal/services/cdn/cdn_frontdoor_firewall_policy_resource.go b/internal/services/cdn/cdn_frontdoor_firewall_policy_resource.go index 74110540e72b..0003a04e2e3d 100644 --- a/internal/services/cdn/cdn_frontdoor_firewall_policy_resource.go +++ b/internal/services/cdn/cdn_frontdoor_firewall_policy_resource.go @@ -448,22 +448,19 @@ func resourceCdnFrontDoorFirewallPolicyCreate(d *pluginsdk.ResourceData, meta in name := d.Get("name").(string) resourceGroup := d.Get("resource_group_name").(string) - log.Printf("[INFO] preparing args for Cdn Frontdoor %q Firewall Policy(Resource Group: %q)", name, resourceGroup) id := parse.NewFrontDoorFirewallPolicyID(subscriptionId, resourceGroup, name) - if d.IsNewResource() { - existing, err := client.Get(ctx, id.ResourceGroup, id.FrontDoorWebApplicationFirewallPolicyName) - if err != nil { - if !utils.ResponseWasNotFound(existing.Response) { - return fmt.Errorf("checking for existing %s: %+v", id, err) - } - } - + existing, err := client.Get(ctx, id.ResourceGroup, id.FrontDoorWebApplicationFirewallPolicyName) + if err != nil { if !utils.ResponseWasNotFound(existing.Response) { - return tf.ImportAsExistsError("azurerm_cdn_frontdoor_firewall_policy", id.ID()) + return fmt.Errorf("checking for existing %s: %+v", id, err) } } + if !utils.ResponseWasNotFound(existing.Response) { + return tf.ImportAsExistsError("azurerm_cdn_frontdoor_firewall_policy", id.ID()) + } + enabled := frontdoor.PolicyEnabledStateDisabled if d.Get("enabled").(bool) { diff --git a/internal/services/cdn/cdn_frontdoor_route_disable_link_to_default_domain_resource_test.go b/internal/services/cdn/cdn_frontdoor_route_disable_link_to_default_domain_resource_test.go index 7f526254cfeb..d4a6428236c4 100644 --- a/internal/services/cdn/cdn_frontdoor_route_disable_link_to_default_domain_resource_test.go +++ b/internal/services/cdn/cdn_frontdoor_route_disable_link_to_default_domain_resource_test.go @@ -8,6 +8,7 @@ import ( "github.com/hashicorp/terraform-provider-azurerm/internal/acceptance" "github.com/hashicorp/terraform-provider-azurerm/internal/acceptance/check" "github.com/hashicorp/terraform-provider-azurerm/internal/clients" + "github.com/hashicorp/terraform-provider-azurerm/internal/features" "github.com/hashicorp/terraform-provider-azurerm/internal/services/cdn/parse" "github.com/hashicorp/terraform-provider-azurerm/internal/tf/pluginsdk" "github.com/hashicorp/terraform-provider-azurerm/utils" @@ -16,16 +17,21 @@ import ( type CdnFrontDoorRouteDisableLinkToDefaultDomainResource struct{} func TestAccCdnFrontDoorRouteDisableLinkToDefaultDomain_basic(t *testing.T) { - data := acceptance.BuildTestData(t, "azurerm_cdn_frontdoor_route_disable_link_to_default_domain", "test") - r := CdnFrontDoorRouteDisableLinkToDefaultDomainResource{} - data.ResourceTest(t, r, []acceptance.TestStep{ - { - Config: r.basic(data), - Check: acceptance.ComposeTestCheckFunc( - check.That(data.ResourceName).ExistsInAzure(r), - ), - }, - }) + if !features.FourPointOhBeta() { + t.Skip("test case is no longer valid since the 'cdn_frontdoor_route_ids' and 'link_to_default_domain' fields have been moved back to the 'cdn_frontdoor_route' resource, remove this test case from the AzureRM provider v4.0") + data := acceptance.BuildTestData(t, "azurerm_cdn_frontdoor_route_disable_link_to_default_domain", "test") + r := CdnFrontDoorRouteDisableLinkToDefaultDomainResource{} + data.ResourceTest(t, r, []acceptance.TestStep{ + { + Config: r.basic(data), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + ), + }, + }) + } else { + t.Skip("the 'azurerm_cdn_frontdoor_route_disable_link_to_default_domain' resource is no longer supported in the AzureRM provider v4.0, please remove this test case") + } } func (r CdnFrontDoorRouteDisableLinkToDefaultDomainResource) Exists(ctx context.Context, clients *clients.Client, state *pluginsdk.InstanceState) (*bool, error) { @@ -49,10 +55,6 @@ func (r CdnFrontDoorRouteDisableLinkToDefaultDomainResource) Exists(ctx context. func (r CdnFrontDoorRouteDisableLinkToDefaultDomainResource) basic(data acceptance.TestData) string { template := r.template(data) return fmt.Sprintf(` -provider "azurerm" { - features {} -} - %s resource "azurerm_cdn_frontdoor_route_disable_link_to_default_domain" "test" { @@ -78,7 +80,11 @@ resource "azurerm_cdn_frontdoor_custom_domain" "test" { func (r CdnFrontDoorRouteDisableLinkToDefaultDomainResource) template(data acceptance.TestData) string { return fmt.Sprintf(` -resource "azurerm_resource_group" "test" { +provider "azurerm" { + features {} +} + + resource "azurerm_resource_group" "test" { name = "acctestRG-cdn-afdx-%[1]d" location = "%[2]s" } diff --git a/internal/services/cdn/cdn_frontdoor_route_resource.go b/internal/services/cdn/cdn_frontdoor_route_resource.go index 8fd6b9fad4a1..35deb4634689 100644 --- a/internal/services/cdn/cdn_frontdoor_route_resource.go +++ b/internal/services/cdn/cdn_frontdoor_route_resource.go @@ -399,6 +399,11 @@ func resourceCdnFrontDoorRouteUpdate(d *pluginsdk.ResourceData, meta interface{} return fmt.Errorf("retrieving existing %s: 'properties' was nil", *id) } + // we need to lock the route for update because the custom domain + // association may also be trying to update the route as well... + locks.ByName(id.RouteName, cdnFrontDoorRouteResourceName) + defer locks.UnlockByName(id.RouteName, cdnFrontDoorRouteResourceName) + httpsRedirect := d.Get("https_redirect_enabled").(bool) protocolsRaw := d.Get("supported_protocols").(*pluginsdk.Set).List() customDomainsRaw := d.Get("cdn_frontdoor_custom_domain_ids").([]interface{}) @@ -497,11 +502,6 @@ func resourceCdnFrontDoorRouteUpdate(d *pluginsdk.ResourceData, meta interface{} RouteUpdatePropertiesParameters: &updateProps, } - // we need to lock the route for update because the custom domain - // association may also be trying to update the route as well... - locks.ByName(id.RouteName, cdnFrontDoorRouteResourceName) - defer locks.UnlockByName(id.RouteName, cdnFrontDoorRouteResourceName) - future, err := workaroundsClient.Update(ctx, id.ResourceGroup, id.ProfileName, id.AfdEndpointName, id.RouteName, updateParams) if err != nil { return fmt.Errorf("updating %s: %+v", *id, err) diff --git a/internal/services/cdn/parse/front_door_custom_domain_association.go b/internal/services/cdn/parse/front_door_custom_domain_association.go index da5bd67781b4..75db26ccb310 100644 --- a/internal/services/cdn/parse/front_door_custom_domain_association.go +++ b/internal/services/cdn/parse/front_door_custom_domain_association.go @@ -10,27 +10,24 @@ import ( ) type FrontDoorCustomDomainAssociationId struct { - SubscriptionId string - ResourceGroup string - ProfileName string - CustomDomainName string - AssociationName string + SubscriptionId string + ResourceGroup string + ProfileName string + AssociationName string } -func NewFrontDoorCustomDomainAssociationID(subscriptionId, resourceGroup, profileName, customDomainName, associationName string) FrontDoorCustomDomainAssociationId { +func NewFrontDoorCustomDomainAssociationID(subscriptionId, resourceGroup, profileName, associationName string) FrontDoorCustomDomainAssociationId { return FrontDoorCustomDomainAssociationId{ - SubscriptionId: subscriptionId, - ResourceGroup: resourceGroup, - ProfileName: profileName, - CustomDomainName: customDomainName, - AssociationName: associationName, + SubscriptionId: subscriptionId, + ResourceGroup: resourceGroup, + ProfileName: profileName, + AssociationName: associationName, } } func (id FrontDoorCustomDomainAssociationId) String() string { segments := []string{ fmt.Sprintf("Association Name %q", id.AssociationName), - fmt.Sprintf("Custom Domain Name %q", id.CustomDomainName), fmt.Sprintf("Profile Name %q", id.ProfileName), fmt.Sprintf("Resource Group %q", id.ResourceGroup), } @@ -39,8 +36,8 @@ func (id FrontDoorCustomDomainAssociationId) String() string { } func (id FrontDoorCustomDomainAssociationId) ID() string { - fmtString := "/subscriptions/%s/resourceGroups/%s/providers/Microsoft.Cdn/profiles/%s/customDomains/%s/associations/%s" - return fmt.Sprintf(fmtString, id.SubscriptionId, id.ResourceGroup, id.ProfileName, id.CustomDomainName, id.AssociationName) + fmtString := "/subscriptions/%s/resourceGroups/%s/providers/Microsoft.Cdn/profiles/%s/associations/%s" + return fmt.Sprintf(fmtString, id.SubscriptionId, id.ResourceGroup, id.ProfileName, id.AssociationName) } // FrontDoorCustomDomainAssociationID parses a FrontDoorCustomDomainAssociation ID into an FrontDoorCustomDomainAssociationId struct @@ -66,9 +63,6 @@ func FrontDoorCustomDomainAssociationID(input string) (*FrontDoorCustomDomainAss if resourceId.ProfileName, err = id.PopSegment("profiles"); err != nil { return nil, err } - if resourceId.CustomDomainName, err = id.PopSegment("customDomains"); err != nil { - return nil, err - } if resourceId.AssociationName, err = id.PopSegment("associations"); err != nil { return nil, err } @@ -117,18 +111,6 @@ func FrontDoorCustomDomainAssociationIDInsensitively(input string) (*FrontDoorCu return nil, err } - // find the correct casing for the 'customDomains' segment - customDomainsKey := "customDomains" - for key := range id.Path { - if strings.EqualFold(key, customDomainsKey) { - customDomainsKey = key - break - } - } - if resourceId.CustomDomainName, err = id.PopSegment(customDomainsKey); err != nil { - return nil, err - } - // find the correct casing for the 'associations' segment associationsKey := "associations" for key := range id.Path { diff --git a/internal/services/cdn/parse/front_door_custom_domain_association_test.go b/internal/services/cdn/parse/front_door_custom_domain_association_test.go index ed219b17d537..0fa943871459 100644 --- a/internal/services/cdn/parse/front_door_custom_domain_association_test.go +++ b/internal/services/cdn/parse/front_door_custom_domain_association_test.go @@ -11,8 +11,8 @@ import ( var _ resourceids.Id = FrontDoorCustomDomainAssociationId{} func TestFrontDoorCustomDomainAssociationIDFormatter(t *testing.T) { - actual := NewFrontDoorCustomDomainAssociationID("12345678-1234-9876-4563-123456789012", "resGroup1", "profile1", "customDomain1", "assoc1").ID() - expected := "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Cdn/profiles/profile1/customDomains/customDomain1/associations/assoc1" + actual := NewFrontDoorCustomDomainAssociationID("12345678-1234-9876-4563-123456789012", "resGroup1", "profile1", "assoc1").ID() + expected := "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Cdn/profiles/profile1/associations/assoc1" if actual != expected { t.Fatalf("Expected %q but got %q", expected, actual) } @@ -67,45 +67,32 @@ func TestFrontDoorCustomDomainAssociationID(t *testing.T) { Error: true, }, - { - // missing CustomDomainName - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Cdn/profiles/profile1/", - Error: true, - }, - - { - // missing value for CustomDomainName - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Cdn/profiles/profile1/customDomains/", - Error: true, - }, - { // missing AssociationName - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Cdn/profiles/profile1/customDomains/customDomain1/", + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Cdn/profiles/profile1/", Error: true, }, { // missing value for AssociationName - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Cdn/profiles/profile1/customDomains/customDomain1/associations/", + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Cdn/profiles/profile1/associations/", Error: true, }, { // valid - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Cdn/profiles/profile1/customDomains/customDomain1/associations/assoc1", + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Cdn/profiles/profile1/associations/assoc1", Expected: &FrontDoorCustomDomainAssociationId{ - SubscriptionId: "12345678-1234-9876-4563-123456789012", - ResourceGroup: "resGroup1", - ProfileName: "profile1", - CustomDomainName: "customDomain1", - AssociationName: "assoc1", + SubscriptionId: "12345678-1234-9876-4563-123456789012", + ResourceGroup: "resGroup1", + ProfileName: "profile1", + AssociationName: "assoc1", }, }, { // upper-cased - Input: "/SUBSCRIPTIONS/12345678-1234-9876-4563-123456789012/RESOURCEGROUPS/RESGROUP1/PROVIDERS/MICROSOFT.CDN/PROFILES/PROFILE1/CUSTOMDOMAINS/CUSTOMDOMAIN1/ASSOCIATIONS/ASSOC1", + Input: "/SUBSCRIPTIONS/12345678-1234-9876-4563-123456789012/RESOURCEGROUPS/RESGROUP1/PROVIDERS/MICROSOFT.CDN/PROFILES/PROFILE1/ASSOCIATIONS/ASSOC1", Error: true, }, } @@ -134,9 +121,6 @@ func TestFrontDoorCustomDomainAssociationID(t *testing.T) { if actual.ProfileName != v.Expected.ProfileName { t.Fatalf("Expected %q but got %q for ProfileName", v.Expected.ProfileName, actual.ProfileName) } - if actual.CustomDomainName != v.Expected.CustomDomainName { - t.Fatalf("Expected %q but got %q for CustomDomainName", v.Expected.CustomDomainName, actual.CustomDomainName) - } if actual.AssociationName != v.Expected.AssociationName { t.Fatalf("Expected %q but got %q for AssociationName", v.Expected.AssociationName, actual.AssociationName) } @@ -192,75 +176,59 @@ func TestFrontDoorCustomDomainAssociationIDInsensitively(t *testing.T) { Error: true, }, - { - // missing CustomDomainName - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Cdn/profiles/profile1/", - Error: true, - }, - - { - // missing value for CustomDomainName - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Cdn/profiles/profile1/customDomains/", - Error: true, - }, - { // missing AssociationName - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Cdn/profiles/profile1/customDomains/customDomain1/", + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Cdn/profiles/profile1/", Error: true, }, { // missing value for AssociationName - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Cdn/profiles/profile1/customDomains/customDomain1/associations/", + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Cdn/profiles/profile1/associations/", Error: true, }, { // valid - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Cdn/profiles/profile1/customDomains/customDomain1/associations/assoc1", + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Cdn/profiles/profile1/associations/assoc1", Expected: &FrontDoorCustomDomainAssociationId{ - SubscriptionId: "12345678-1234-9876-4563-123456789012", - ResourceGroup: "resGroup1", - ProfileName: "profile1", - CustomDomainName: "customDomain1", - AssociationName: "assoc1", + SubscriptionId: "12345678-1234-9876-4563-123456789012", + ResourceGroup: "resGroup1", + ProfileName: "profile1", + AssociationName: "assoc1", }, }, { // lower-cased segment names - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Cdn/profiles/profile1/customdomains/customDomain1/associations/assoc1", + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Cdn/profiles/profile1/associations/assoc1", Expected: &FrontDoorCustomDomainAssociationId{ - SubscriptionId: "12345678-1234-9876-4563-123456789012", - ResourceGroup: "resGroup1", - ProfileName: "profile1", - CustomDomainName: "customDomain1", - AssociationName: "assoc1", + SubscriptionId: "12345678-1234-9876-4563-123456789012", + ResourceGroup: "resGroup1", + ProfileName: "profile1", + AssociationName: "assoc1", }, }, { // upper-cased segment names - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Cdn/PROFILES/profile1/CUSTOMDOMAINS/customDomain1/ASSOCIATIONS/assoc1", + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Cdn/PROFILES/profile1/ASSOCIATIONS/assoc1", Expected: &FrontDoorCustomDomainAssociationId{ - SubscriptionId: "12345678-1234-9876-4563-123456789012", - ResourceGroup: "resGroup1", - ProfileName: "profile1", - CustomDomainName: "customDomain1", - AssociationName: "assoc1", + SubscriptionId: "12345678-1234-9876-4563-123456789012", + ResourceGroup: "resGroup1", + ProfileName: "profile1", + AssociationName: "assoc1", }, }, { // mixed-cased segment names - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Cdn/PrOfIlEs/profile1/CuStOmDoMaInS/customDomain1/AsSoCiAtIoNs/assoc1", + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Cdn/PrOfIlEs/profile1/AsSoCiAtIoNs/assoc1", Expected: &FrontDoorCustomDomainAssociationId{ - SubscriptionId: "12345678-1234-9876-4563-123456789012", - ResourceGroup: "resGroup1", - ProfileName: "profile1", - CustomDomainName: "customDomain1", - AssociationName: "assoc1", + SubscriptionId: "12345678-1234-9876-4563-123456789012", + ResourceGroup: "resGroup1", + ProfileName: "profile1", + AssociationName: "assoc1", }, }, } @@ -289,9 +257,6 @@ func TestFrontDoorCustomDomainAssociationIDInsensitively(t *testing.T) { if actual.ProfileName != v.Expected.ProfileName { t.Fatalf("Expected %q but got %q for ProfileName", v.Expected.ProfileName, actual.ProfileName) } - if actual.CustomDomainName != v.Expected.CustomDomainName { - t.Fatalf("Expected %q but got %q for CustomDomainName", v.Expected.CustomDomainName, actual.CustomDomainName) - } if actual.AssociationName != v.Expected.AssociationName { t.Fatalf("Expected %q but got %q for AssociationName", v.Expected.AssociationName, actual.AssociationName) } diff --git a/internal/services/cdn/resourceids.go b/internal/services/cdn/resourceids.go index 0a5e225d8ee3..fc8f3e439ac0 100644 --- a/internal/services/cdn/resourceids.go +++ b/internal/services/cdn/resourceids.go @@ -20,4 +20,4 @@ package cdn // CDN FrontDoor "Associations" //go:generate go run ../../tools/generator-resource-id/main.go -path=./ -name=FrontDoorRouteDisableLinkToDefaultDomain -id=/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Cdn/profiles/profile1/afdEndpoints/endpoint1/routes/route1/disableLinkToDefaultDomain/disableLinkToDefaultDomain1 -rewrite=true -//go:generate go run ../../tools/generator-resource-id/main.go -path=./ -name=FrontDoorCustomDomainAssociation -id=/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Cdn/profiles/profile1/customDomains/customDomain1/associations/assoc1 -rewrite=true +//go:generate go run ../../tools/generator-resource-id/main.go -path=./ -name=FrontDoorCustomDomainAssociation -id=/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Cdn/profiles/profile1/associations/assoc1 -rewrite=true diff --git a/internal/services/cdn/validate/front_door_custom_domain_association_id_test.go b/internal/services/cdn/validate/front_door_custom_domain_association_id_test.go index b33af51047bf..09a90130ad7d 100644 --- a/internal/services/cdn/validate/front_door_custom_domain_association_id_test.go +++ b/internal/services/cdn/validate/front_door_custom_domain_association_id_test.go @@ -52,39 +52,27 @@ func TestFrontDoorCustomDomainAssociationID(t *testing.T) { Valid: false, }, - { - // missing CustomDomainName - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Cdn/profiles/profile1/", - Valid: false, - }, - - { - // missing value for CustomDomainName - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Cdn/profiles/profile1/customDomains/", - Valid: false, - }, - { // missing AssociationName - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Cdn/profiles/profile1/customDomains/customDomain1/", + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Cdn/profiles/profile1/", Valid: false, }, { // missing value for AssociationName - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Cdn/profiles/profile1/customDomains/customDomain1/associations/", + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Cdn/profiles/profile1/associations/", Valid: false, }, { // valid - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Cdn/profiles/profile1/customDomains/customDomain1/associations/assoc1", + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Cdn/profiles/profile1/associations/assoc1", Valid: true, }, { // upper-cased - Input: "/SUBSCRIPTIONS/12345678-1234-9876-4563-123456789012/RESOURCEGROUPS/RESGROUP1/PROVIDERS/MICROSOFT.CDN/PROFILES/PROFILE1/CUSTOMDOMAINS/CUSTOMDOMAIN1/ASSOCIATIONS/ASSOC1", + Input: "/SUBSCRIPTIONS/12345678-1234-9876-4563-123456789012/RESOURCEGROUPS/RESGROUP1/PROVIDERS/MICROSOFT.CDN/PROFILES/PROFILE1/ASSOCIATIONS/ASSOC1", Valid: false, }, } From e2bc53ce08b2b9bfca2c899758d1e06ee1749e1e Mon Sep 17 00:00:00 2001 From: Jeffrey Cline <20408400+WodansSon@users.noreply.github.com> Date: Sun, 9 Oct 2022 01:58:28 -0600 Subject: [PATCH 16/58] Fix comment spacing --- .../cdn_frontdoor_custom_domain_association_resource_test.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/internal/services/cdn/cdn_frontdoor_custom_domain_association_resource_test.go b/internal/services/cdn/cdn_frontdoor_custom_domain_association_resource_test.go index cd2ef1ffd54a..2b2b59290e23 100644 --- a/internal/services/cdn/cdn_frontdoor_custom_domain_association_resource_test.go +++ b/internal/services/cdn/cdn_frontdoor_custom_domain_association_resource_test.go @@ -61,7 +61,7 @@ func TestAccCdnFrontDoorCustomDomainAssociation_destroyAssociation(t *testing.T) { Config: r.destroy(data), Check: acceptance.ComposeTestCheckFunc(), - ExpectNonEmptyPlan: true, //since deleting this resource actually removes the linked custom domain from the route resource(s) + ExpectNonEmptyPlan: true, // since deleting this resource actually removes the linked custom domain from the route resource(s) }, }) } @@ -80,7 +80,7 @@ func TestAccCdnFrontDoorCustomDomainAssociation_DestroyAssociations(t *testing.T { Config: r.destroy(data), Check: acceptance.ComposeTestCheckFunc(), - ExpectNonEmptyPlan: true, //since deleting this resource actually removes the linked custom domain from the route resource(s) + ExpectNonEmptyPlan: true, // since deleting this resource actually removes the linked custom domain from the route resource(s) }, }) } From a64c10738fe568089b81e47110124663b903a913 Mon Sep 17 00:00:00 2001 From: Jeffrey Cline <20408400+WodansSon@users.noreply.github.com> Date: Sun, 9 Oct 2022 02:11:54 -0600 Subject: [PATCH 17/58] Terrafmt test --- ...ntdoor_route_disable_link_to_default_domain_resource_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/services/cdn/cdn_frontdoor_route_disable_link_to_default_domain_resource_test.go b/internal/services/cdn/cdn_frontdoor_route_disable_link_to_default_domain_resource_test.go index d4a6428236c4..f5dc7b6910e0 100644 --- a/internal/services/cdn/cdn_frontdoor_route_disable_link_to_default_domain_resource_test.go +++ b/internal/services/cdn/cdn_frontdoor_route_disable_link_to_default_domain_resource_test.go @@ -84,7 +84,7 @@ provider "azurerm" { features {} } - resource "azurerm_resource_group" "test" { +resource "azurerm_resource_group" "test" { name = "acctestRG-cdn-afdx-%[1]d" location = "%[2]s" } From e46d4c71381284109e8ad0249dd69f52c920bd59 Mon Sep 17 00:00:00 2001 From: Jeffrey Cline <20408400+WodansSon@users.noreply.github.com> Date: Sun, 9 Oct 2022 20:49:20 -0600 Subject: [PATCH 18/58] Remove import check for association --- ...rontdoor_custom_domain_association_resource.go | 5 ----- ...oor_custom_domain_association_resource_test.go | 15 --------------- 2 files changed, 20 deletions(-) diff --git a/internal/services/cdn/cdn_frontdoor_custom_domain_association_resource.go b/internal/services/cdn/cdn_frontdoor_custom_domain_association_resource.go index a8ca2fbaf73c..0347b635bdc9 100644 --- a/internal/services/cdn/cdn_frontdoor_custom_domain_association_resource.go +++ b/internal/services/cdn/cdn_frontdoor_custom_domain_association_resource.go @@ -64,11 +64,6 @@ func resourceCdnFrontDoorCustomDomainAssociationCreate(d *pluginsdk.ResourceData } else if customDomain != nil { id := parse.NewFrontDoorCustomDomainAssociationID(customDomain.SubscriptionId, customDomain.ResourceGroup, customDomain.ProfileName, customDomain.CustomDomainName) - // TODO: Get import error to work - // if !utils.ResponseWasNotFound(existing.Response) { - // return tf.ImportAsExistsError("azurerm_cdn_frontdoor_custom_domain_association", id.ID()) - // } - d.SetId(id.ID()) } diff --git a/internal/services/cdn/cdn_frontdoor_custom_domain_association_resource_test.go b/internal/services/cdn/cdn_frontdoor_custom_domain_association_resource_test.go index 2b2b59290e23..ace0eaf0c7d2 100644 --- a/internal/services/cdn/cdn_frontdoor_custom_domain_association_resource_test.go +++ b/internal/services/cdn/cdn_frontdoor_custom_domain_association_resource_test.go @@ -32,21 +32,6 @@ func TestAccCdnFrontDoorCustomDomainAssociation_basic(t *testing.T) { }) } -// TODO: Implement the requires import functionality -// func TestAccCdnFrontDoorCustomDomainAssociation_requiresImport(t *testing.T) { -// data := acceptance.BuildTestData(t, "azurerm_cdn_frontdoor_custom_domain_association", "test") -// r := CdnFrontDoorCustomDomainAssociationResource{} -// data.ResourceTest(t, r, []acceptance.TestStep{ -// { -// Config: r.basic(data), -// Check: acceptance.ComposeTestCheckFunc( -// check.That(data.ResourceName).ExistsInAzure(r), -// ), -// }, -// data.RequiresImportErrorStep(r.requiresImport), -// }) -// } - func TestAccCdnFrontDoorCustomDomainAssociation_destroyAssociation(t *testing.T) { data := acceptance.BuildTestData(t, "azurerm_cdn_frontdoor_custom_domain_association", "test") r := CdnFrontDoorCustomDomainAssociationResource{} From bed92ba6c07acffcc44a08e49839b4b6305c8608 Mon Sep 17 00:00:00 2001 From: Jeffrey Cline <20408400+WodansSon@users.noreply.github.com> Date: Mon, 10 Oct 2022 14:43:08 -0600 Subject: [PATCH 19/58] last minute changes --- ...ntdoor_custom_domain_association_import.go | 31 ++++ ...door_custom_domain_association_resource.go | 132 ++++++++++-------- ...custom_domain_association_resource_test.go | 24 +--- .../services/cdn/cdn_frontdoor_helpers.go | 26 ++-- ...le_link_to_default_domain_resource_test.go | 51 ++++--- .../cdn/cdn_frontdoor_route_resource.go | 4 +- ...or_custom_domain_association.html.markdown | 4 +- 7 files changed, 159 insertions(+), 113 deletions(-) create mode 100644 internal/services/cdn/cdn_frontdoor_custom_domain_association_import.go diff --git a/internal/services/cdn/cdn_frontdoor_custom_domain_association_import.go b/internal/services/cdn/cdn_frontdoor_custom_domain_association_import.go new file mode 100644 index 000000000000..c8fe52b1e729 --- /dev/null +++ b/internal/services/cdn/cdn_frontdoor_custom_domain_association_import.go @@ -0,0 +1,31 @@ +package cdn + +import ( + "context" + "fmt" + + "github.com/hashicorp/terraform-provider-azurerm/internal/clients" + "github.com/hashicorp/terraform-provider-azurerm/internal/services/cdn/parse" + "github.com/hashicorp/terraform-provider-azurerm/internal/tf/pluginsdk" +) + +func importCdnFrontDoorCustomDomainAssociation() pluginsdk.ImporterFunc { + return func(ctx context.Context, d *pluginsdk.ResourceData, meta interface{}) (data []*pluginsdk.ResourceData, err error) { + id, err := parse.FrontDoorCustomDomainAssociationIDInsensitively(d.Id()) + if err != nil { + return []*pluginsdk.ResourceData{}, err + } + + client := meta.(*clients.Client).Cdn.FrontDoorCustomDomainsClient + resp, err := client.Get(ctx, id.ResourceGroup, id.ProfileName, id.AssociationName) + if err != nil { + return []*pluginsdk.ResourceData{}, fmt.Errorf("retrieving %s: %+v", id, err) + } + + if resp.AFDDomainProperties == nil { + return []*pluginsdk.ResourceData{}, fmt.Errorf("retrieving %s: `AFDDomainProperties` was nil", id) + } + + return []*pluginsdk.ResourceData{d}, nil + } +} diff --git a/internal/services/cdn/cdn_frontdoor_custom_domain_association_resource.go b/internal/services/cdn/cdn_frontdoor_custom_domain_association_resource.go index 0347b635bdc9..d4ac578e1975 100644 --- a/internal/services/cdn/cdn_frontdoor_custom_domain_association_resource.go +++ b/internal/services/cdn/cdn_frontdoor_custom_domain_association_resource.go @@ -5,14 +5,16 @@ import ( "log" "time" + "github.com/hashicorp/terraform-provider-azurerm/internal/clients" "github.com/hashicorp/terraform-provider-azurerm/internal/services/cdn/parse" "github.com/hashicorp/terraform-provider-azurerm/internal/services/cdn/validate" "github.com/hashicorp/terraform-provider-azurerm/internal/tf/pluginsdk" + "github.com/hashicorp/terraform-provider-azurerm/internal/timeouts" + "github.com/hashicorp/terraform-provider-azurerm/utils" ) var cdnFrontDoorCustomDomainResourceName = "azurerm_cdn_frontdoor_custom_domain" var cdnFrontDoorRouteResourceName = "azurerm_cdn_frontdoor_route" -var notAssociatedErr = "the CDN FrontDoor Route(Name: %q) is currently not associated with the CDN FrontDoor Custom Domain(Name: %q). Please remove the CDN FrontDoor Route from your 'cdn_frontdoor_custom_domain_association' configuration block" func resourceCdnFrontDoorCustomDomainAssociation() *pluginsdk.Resource { return &pluginsdk.Resource{ @@ -28,12 +30,10 @@ func resourceCdnFrontDoorCustomDomainAssociation() *pluginsdk.Resource { Delete: pluginsdk.DefaultTimeout(30 * time.Minute), }, - Importer: pluginsdk.ImporterValidatingResourceId(func(id string) error { - if _, err := parse.FrontDoorCustomDomainAssociationID(id); err != nil { - return err - } - return nil - }), + Importer: pluginsdk.ImporterValidatingResourceIdThen(func(id string) error { + _, err := parse.FrontDoorCustomDomainAssociationID(id) + return err + }, importCdnFrontDoorCustomDomainAssociation()), Schema: map[string]*pluginsdk.Schema{ "cdn_frontdoor_custom_domain_id": { @@ -59,36 +59,57 @@ func resourceCdnFrontDoorCustomDomainAssociation() *pluginsdk.Resource { func resourceCdnFrontDoorCustomDomainAssociationCreate(d *pluginsdk.ResourceData, meta interface{}) error { log.Printf("[INFO] preparing arguments for CDN FrontDoor Route <-> CDN FrontDoor Custom Domain Association creation") - if customDomain, err := expandCustomDomain(d.Get("cdn_frontdoor_custom_domain_id").(string)); err != nil { + cdId, err := customDomainNullable(d.Get("cdn_frontdoor_custom_domain_id").(string)) + if err != nil { return err - } else if customDomain != nil { - id := parse.NewFrontDoorCustomDomainAssociationID(customDomain.SubscriptionId, customDomain.ResourceGroup, customDomain.ProfileName, customDomain.CustomDomainName) - - d.SetId(id.ID()) } + id := parse.NewFrontDoorCustomDomainAssociationID(cdId.SubscriptionId, cdId.ResourceGroup, cdId.ProfileName, cdId.CustomDomainName) + + d.SetId(id.ID()) + return resourceCdnFrontDoorCustomDomainAssociationRead(d, meta) } func resourceCdnFrontDoorCustomDomainAssociationRead(d *pluginsdk.ResourceData, meta interface{}) error { - if customDomain, err := expandCustomDomain(d.Get("cdn_frontdoor_custom_domain_id").(string)); err != nil { + client := meta.(*clients.Client).Cdn.FrontDoorCustomDomainsClient + ctx, cancel := timeouts.ForCreate(meta.(*clients.Client).StopContext, d) + defer cancel() + + id, err := customDomainNullable(d.Get("cdn_frontdoor_custom_domain_id").(string)) + if err != nil { return err - } else if customDomain != nil { - d.Set("cdn_frontdoor_custom_domain_id", customDomain.ID()) - d.Set("cdn_frontdoor_route_ids", d.Get("cdn_frontdoor_route_ids").([]interface{})) } - return nil -} + // id will be nill if you are deleting the resource + if id != nil { + existing, err := client.Get(ctx, id.ResourceGroup, id.ProfileName, id.CustomDomainName) + if err != nil { + if utils.ResponseWasNotFound(existing.Response) { + d.SetId("") + return fmt.Errorf("CDN FrontDoor Custom Domain(Resource Group: %q Name: %q) was not found", id.ResourceGroup, id.CustomDomainName) + } -func resourceCdnFrontDoorCustomDomainAssociationUpdate(d *pluginsdk.ResourceData, meta interface{}) error { - if customDomain, err := expandCustomDomain(d.Get("cdn_frontdoor_custom_domain_id").(string)); err != nil { - return err - } else if customDomain != nil { - _, err := expandRouteIds(d, meta, customDomain) + return fmt.Errorf("checking for existing %s: %+v", id, err) + } + + // make sure the routes exist and are valid for this custom domain... + routes, err := flattenRoutes(d, meta, id) if err != nil { return err } + + d.Set("cdn_frontdoor_custom_domain_id", id.ID()) + d.Set("cdn_frontdoor_route_ids", routes) + } + + return nil +} + +func resourceCdnFrontDoorCustomDomainAssociationUpdate(d *pluginsdk.ResourceData, meta interface{}) error { + // if this value has not changed there is nothing to do so just return + if !d.HasChange("cdn_frontdoor_route_ids") { + return nil } return resourceCdnFrontDoorCustomDomainAssociationRead(d, meta) @@ -97,19 +118,19 @@ func resourceCdnFrontDoorCustomDomainAssociationUpdate(d *pluginsdk.ResourceData func resourceCdnFrontDoorCustomDomainAssociationDelete(d *pluginsdk.ResourceData, meta interface{}) error { // since you are deleting the resource you cannot grab the value from the config // because it will be empty, you have to get it from the states old value... - oldCustomDomain, _ := d.GetChange("cdn_frontdoor_custom_domain_id") - customDomain, _ := expandCustomDomain(oldCustomDomain.(string)) + oCdId, _ := d.GetChange("cdn_frontdoor_custom_domain_id") + id, _ := customDomainNullable(oCdId.(string)) - old, _ := d.GetChange("cdn_frontdoor_route_ids") - oldRoutes := old.([]interface{}) + oRids, _ := d.GetChange("cdn_frontdoor_route_ids") + oR := oRids.([]interface{}) - routes, _, err := normalizeRouteIds(oldRoutes) + v, _, err := routesInsensitively(oR) if err != nil { return err } - if len(*routes) != 0 { - if err := removeCustomDomainAssociationFromRoutes(d, meta, routes, customDomain); err != nil { + if len(*v) != 0 { + if err := removeCustomDomainAssociationFromRoutes(d, meta, v, id); err != nil { return err } } @@ -119,69 +140,68 @@ func resourceCdnFrontDoorCustomDomainAssociationDelete(d *pluginsdk.ResourceData return nil } -func expandCustomDomain(input string) (*parse.FrontDoorCustomDomainId, error) { +func customDomainNullable(input string) (*parse.FrontDoorCustomDomainId, error) { if len(input) == 0 || input == "" { return nil, nil } - customDomain, err := parse.FrontDoorCustomDomainIDInsensitively(input) + v, err := parse.FrontDoorCustomDomainIDInsensitively(input) if err != nil { return nil, err } - return customDomain, nil + return v, nil } -func expandRouteIds(d *pluginsdk.ResourceData, meta interface{}, customDomain *parse.FrontDoorCustomDomainId) ([]interface{}, error) { +func flattenRoutes(d *pluginsdk.ResourceData, meta interface{}, id *parse.FrontDoorCustomDomainId) ([]interface{}, error) { out := make([]interface{}, 0) + o, n := d.GetChange("cdn_frontdoor_route_ids") + oRoutes := o.([]interface{}) + nRoutes := n.([]interface{}) - old, new := d.GetChange("cdn_frontdoor_route_ids") - oldRoutes := old.([]interface{}) - newRoutes := new.([]interface{}) - - if len(newRoutes) == 0 || newRoutes == nil || customDomain == nil { + if len(nRoutes) == 0 || nRoutes == nil || id == nil { return out, nil } - oldRouteIds, _, err := normalizeRouteIds(oldRoutes) + oIds, _, err := routesInsensitively(oRoutes) if err != nil { - return nil, err + return out, err } - newRouteIds, out, err := normalizeRouteIds(newRoutes) + nIds, result, err := routesInsensitively(nRoutes) if err != nil { - return nil, err + return out, err } // validate the new routes... - if len(*newRouteIds) != 0 { - for _, newRoute := range *newRouteIds { + if len(*nIds) != 0 { + for _, v := range *nIds { // Make sure the route exists and get the routes custom domain association list... - routeAssociations, _, err := getRouteProperties(d, meta, &newRoute, "cdn_frontdoor_custom_domain_association") + associations, _, err := getRouteProperties(d, meta, &v, "cdn_frontdoor_custom_domain_association") if err != nil { - return nil, err + return out, err } // Make sure the custom domain is in the routes association list - if len(routeAssociations) == 0 || !sliceContainsString(routeAssociations, customDomain.ID()) { - return nil, fmt.Errorf(notAssociatedErr, newRoute.RouteName, customDomain.CustomDomainName) + if len(associations) == 0 || !sliceContainsString(associations, id.ID()) { + return out, fmt.Errorf("the CDN FrontDoor Route(Name: %q) is currently not associated with the CDN FrontDoor Custom Domain(Name: %q). Please remove the CDN FrontDoor Route from your 'cdn_frontdoor_custom_domain_association' configuration block", v.RouteName, id.CustomDomainName) } } - if err := validateCustomDomainRoutes(newRouteIds, customDomain); err != nil { - return nil, err + if err := validateCustomDomainRoutes(nIds, id); err != nil { + return out, err } } - if len(oldRoutes) != 0 { + if len(oRoutes) != 0 { // now get the delta between the old and the new list, if any custom domains were removed from // the list we need to remove the custom domain association from those routes... - if delta, _ := routeDelta(oldRouteIds, newRouteIds); len(*delta) != 0 { - if err = removeCustomDomainAssociationFromRoutes(d, meta, delta, customDomain); err != nil { - return nil, err + if delta, _ := routeDelta(oIds, nIds); len(*delta) != 0 { + if err = removeCustomDomainAssociationFromRoutes(d, meta, delta, id); err != nil { + return out, err } } } - return out, nil + return result, nil } diff --git a/internal/services/cdn/cdn_frontdoor_custom_domain_association_resource_test.go b/internal/services/cdn/cdn_frontdoor_custom_domain_association_resource_test.go index ace0eaf0c7d2..510527eeaa57 100644 --- a/internal/services/cdn/cdn_frontdoor_custom_domain_association_resource_test.go +++ b/internal/services/cdn/cdn_frontdoor_custom_domain_association_resource_test.go @@ -32,7 +32,9 @@ func TestAccCdnFrontDoorCustomDomainAssociation_basic(t *testing.T) { }) } -func TestAccCdnFrontDoorCustomDomainAssociation_destroyAssociation(t *testing.T) { +// NOTE: the 'requiresImport' test is not possible on this resource + +func TestAccCdnFrontDoorCustomDomainAssociation_removeAssociation(t *testing.T) { data := acceptance.BuildTestData(t, "azurerm_cdn_frontdoor_custom_domain_association", "test") r := CdnFrontDoorCustomDomainAssociationResource{} @@ -44,14 +46,14 @@ func TestAccCdnFrontDoorCustomDomainAssociation_destroyAssociation(t *testing.T) ), }, { - Config: r.destroy(data), + Config: r.remove(data), Check: acceptance.ComposeTestCheckFunc(), ExpectNonEmptyPlan: true, // since deleting this resource actually removes the linked custom domain from the route resource(s) }, }) } -func TestAccCdnFrontDoorCustomDomainAssociation_DestroyAssociations(t *testing.T) { +func TestAccCdnFrontDoorCustomDomainAssociation_removeAssociations(t *testing.T) { data := acceptance.BuildTestData(t, "azurerm_cdn_frontdoor_custom_domain_association", "test") r := CdnFrontDoorCustomDomainAssociationResource{} @@ -63,7 +65,7 @@ func TestAccCdnFrontDoorCustomDomainAssociation_DestroyAssociations(t *testing.T ), }, { - Config: r.destroy(data), + Config: r.remove(data), Check: acceptance.ComposeTestCheckFunc(), ExpectNonEmptyPlan: true, // since deleting this resource actually removes the linked custom domain from the route resource(s) }, @@ -100,18 +102,6 @@ resource "azurerm_cdn_frontdoor_custom_domain_association" "test" { `, template) } -// func (r CdnFrontDoorCustomDomainAssociationResource) requiresImport(data acceptance.TestData) string { -// config := r.basic(data) -// return fmt.Sprintf(` -// %s - -// resource "azurerm_cdn_frontdoor_custom_domain_association" "import" { -// cdn_frontdoor_custom_domain_id = azurerm_cdn_frontdoor_custom_domain_association.test.cdn_frontdoor_custom_domain_id -// cdn_frontdoor_route_ids = azurerm_cdn_frontdoor_custom_domain_association.test.cdn_frontdoor_route_ids -// } -// `, config) -// } - func (r CdnFrontDoorCustomDomainAssociationResource) update(data acceptance.TestData) string { template := r.template(data) return fmt.Sprintf(` @@ -147,7 +137,7 @@ resource "azurerm_cdn_frontdoor_custom_domain_association" "test" { `, template, data.RandomInteger, data.RandomStringOfLength(10)) } -func (r CdnFrontDoorCustomDomainAssociationResource) destroy(data acceptance.TestData) string { +func (r CdnFrontDoorCustomDomainAssociationResource) remove(data acceptance.TestData) string { template := r.template(data) return fmt.Sprintf(` %s diff --git a/internal/services/cdn/cdn_frontdoor_helpers.go b/internal/services/cdn/cdn_frontdoor_helpers.go index 62bf9718730c..8098339305dc 100644 --- a/internal/services/cdn/cdn_frontdoor_helpers.go +++ b/internal/services/cdn/cdn_frontdoor_helpers.go @@ -486,17 +486,17 @@ func validateRoutesCustomDomainProfile(customDomains []interface{}, routeName st } // Validates that the CDN FrontDoor Custom Domain can be associated with the CDN FrontDoor Route -func validateCustomDomainRoutes(routes *[]parse.FrontDoorRouteId, customDomainID *parse.FrontDoorCustomDomainId) error { - if len(*routes) == 0 || routes == nil { +func validateCustomDomainRoutes(input *[]parse.FrontDoorRouteId, customDomainID *parse.FrontDoorCustomDomainId) error { + if len(*input) == 0 || input == nil { return nil } // check for duplicates... - if err := routeSliceHasDuplicates(routes, "CDN FrontDoor Route"); err != nil { + if err := routeSliceHasDuplicates(input, "CDN FrontDoor Route"); err != nil { return err } - for i, route := range *routes { + for i, route := range *input { // the route and custom domain profiles must match... if customDomainID.ProfileName != route.ProfileName { return fmt.Errorf("the CDN FrontDoor Custom Domain(Name: %q, Profile: %q) and the CDN FrontDoor Route(Name: %q, Profile: %q) must belong to the same CDN FrontDoor Profile", customDomainID.CustomDomainName, customDomainID.ProfileName, route.RouteName, route.ProfileName) @@ -504,13 +504,13 @@ func validateCustomDomainRoutes(routes *[]parse.FrontDoorRouteId, customDomainID // validate all routes are using the same endpoint because a custom domain can not // be associated with routes that target two different endpoints... - for t, nextRoute := range *routes { + for t, v := range *input { if i == t { continue } - if route.AfdEndpointName != nextRoute.AfdEndpointName { - return fmt.Errorf("the CDN FrontDoor Route(Name: %q) and CDN FrontDoor Route(Name: %q) do not reference the same CDN FrontDoor Endpoint(Name: %q). All CDN FrontDoor Routes must reference the same CDN FrontDoor Endpoint %q to associate the CDN FrontDoor Custom Domain(Name: %q) with more than one CDN FrontDoor Route", route.RouteName, nextRoute.RouteName, route.AfdEndpointName, route.AfdEndpointName, customDomainID.CustomDomainName) + if route.AfdEndpointName != v.AfdEndpointName { + return fmt.Errorf("the CDN FrontDoor Route(Name: %q) and CDN FrontDoor Route(Name: %q) do not reference the same CDN FrontDoor Endpoint(Name: %q). All CDN FrontDoor Routes must reference the same CDN FrontDoor Endpoint %q to associate the CDN FrontDoor Custom Domain(Name: %q) with more than one CDN FrontDoor Route", route.RouteName, v.RouteName, route.AfdEndpointName, route.AfdEndpointName, customDomainID.CustomDomainName) } } } @@ -608,15 +608,15 @@ func normalizeRuleSetIds(input []interface{}) ([]interface{}, error) { return out, nil } -func normalizeRouteIds(input []interface{}) (*[]parse.FrontDoorRouteId, []interface{}, error) { +func routesInsensitively(input []interface{}) (*[]parse.FrontDoorRouteId, []interface{}, error) { out := make([]parse.FrontDoorRouteId, 0) config := make([]interface{}, 0) if len(input) == 0 || input == nil { return &out, config, nil } - for _, route := range input { - id, err := parse.FrontDoorRouteIDInsensitively(route.(string)) + for _, v := range input { + id, err := parse.FrontDoorRouteIDInsensitively(v.(string)) if err != nil { return nil, nil, err } @@ -628,14 +628,14 @@ func normalizeRouteIds(input []interface{}) (*[]parse.FrontDoorRouteId, []interf return &out, config, nil } -func normalizeCustomDomainIds(input []interface{}) ([]interface{}, error) { +func customDomainsInsensitively(input []interface{}) ([]interface{}, error) { out := make([]interface{}, 0) if len(input) == 0 || input == nil { return out, nil } - for _, customDomain := range input { - id, err := parse.FrontDoorCustomDomainIDInsensitively(customDomain.(string)) + for _, v := range input { + id, err := parse.FrontDoorCustomDomainIDInsensitively(v.(string)) if err != nil { return nil, err } diff --git a/internal/services/cdn/cdn_frontdoor_route_disable_link_to_default_domain_resource_test.go b/internal/services/cdn/cdn_frontdoor_route_disable_link_to_default_domain_resource_test.go index f5dc7b6910e0..51adac3787ed 100644 --- a/internal/services/cdn/cdn_frontdoor_route_disable_link_to_default_domain_resource_test.go +++ b/internal/services/cdn/cdn_frontdoor_route_disable_link_to_default_domain_resource_test.go @@ -18,7 +18,6 @@ type CdnFrontDoorRouteDisableLinkToDefaultDomainResource struct{} func TestAccCdnFrontDoorRouteDisableLinkToDefaultDomain_basic(t *testing.T) { if !features.FourPointOhBeta() { - t.Skip("test case is no longer valid since the 'cdn_frontdoor_route_ids' and 'link_to_default_domain' fields have been moved back to the 'cdn_frontdoor_route' resource, remove this test case from the AzureRM provider v4.0") data := acceptance.BuildTestData(t, "azurerm_cdn_frontdoor_route_disable_link_to_default_domain", "test") r := CdnFrontDoorRouteDisableLinkToDefaultDomainResource{} data.ResourceTest(t, r, []acceptance.TestStep{ @@ -27,6 +26,7 @@ func TestAccCdnFrontDoorRouteDisableLinkToDefaultDomain_basic(t *testing.T) { Check: acceptance.ComposeTestCheckFunc( check.That(data.ResourceName).ExistsInAzure(r), ), + ExpectNonEmptyPlan: true, // since this resource actually modifies the routes 'linked to default domain' field }, }) } else { @@ -61,21 +61,7 @@ resource "azurerm_cdn_frontdoor_route_disable_link_to_default_domain" "test" { cdn_frontdoor_route_id = azurerm_cdn_frontdoor_route.test.id cdn_frontdoor_custom_domain_ids = [azurerm_cdn_frontdoor_custom_domain.test.id] } - -resource "azurerm_cdn_frontdoor_custom_domain" "test" { - name = "acctestcustomdomain-%d" - cdn_frontdoor_profile_id = azurerm_cdn_frontdoor_profile.test.id - dns_zone_id = azurerm_dns_zone.test.id - host_name = join(".", ["%s", azurerm_dns_zone.test.name]) - - associate_with_cdn_frontdoor_route_id = azurerm_cdn_frontdoor_route.test.id - - tls { - certificate_type = "ManagedCertificate" - minimum_tls_version = "TLS12" - } -} -`, template, data.RandomInteger, data.RandomStringOfLength(8)) +`, template) } func (r CdnFrontDoorRouteDisableLinkToDefaultDomainResource) template(data acceptance.TestData) string { @@ -90,18 +76,18 @@ resource "azurerm_resource_group" "test" { } resource "azurerm_dns_zone" "test" { - name = "acctestzone%[1]d.com" + name = "acctest-dns-zone%[1]d.com" resource_group_name = azurerm_resource_group.test.name } resource "azurerm_cdn_frontdoor_profile" "test" { - name = "acctestcdnfdprofile-%[1]d" + name = "acctest-profile-%[1]d" resource_group_name = azurerm_resource_group.test.name sku_name = "Standard_AzureFrontDoor" } resource "azurerm_cdn_frontdoor_origin_group" "test" { - name = "accTestOriginGroup-%[1]d" + name = "accTest-origin-group-%[1]d" cdn_frontdoor_profile_id = azurerm_cdn_frontdoor_profile.test.id load_balancing { @@ -112,7 +98,7 @@ resource "azurerm_cdn_frontdoor_origin_group" "test" { } resource "azurerm_cdn_frontdoor_origin" "test" { - name = "accTestOrigin-%[1]d" + name = "acctest-origin-%[1]d" cdn_frontdoor_origin_group_id = azurerm_cdn_frontdoor_origin_group.test.id enabled = true @@ -126,17 +112,36 @@ resource "azurerm_cdn_frontdoor_origin" "test" { } resource "azurerm_cdn_frontdoor_endpoint" "test" { - name = "accTestEndpoint-%[1]d" + name = "acctest-endpoint-%[1]d" cdn_frontdoor_profile_id = azurerm_cdn_frontdoor_profile.test.id } resource "azurerm_cdn_frontdoor_route" "test" { - name = "accTestRoute-%[1]d" + name = "acctest-route-%[1]d" cdn_frontdoor_endpoint_id = azurerm_cdn_frontdoor_endpoint.test.id cdn_frontdoor_origin_group_id = azurerm_cdn_frontdoor_origin_group.test.id cdn_frontdoor_origin_ids = [azurerm_cdn_frontdoor_origin.test.id] patterns_to_match = ["/*"] supported_protocols = ["Http", "Https"] + + cdn_frontdoor_custom_domain_ids = [azurerm_cdn_frontdoor_custom_domain.test.id] +} + +resource "azurerm_cdn_frontdoor_custom_domain" "test" { + name = "acctest-custom-domain-%[1]d" + cdn_frontdoor_profile_id = azurerm_cdn_frontdoor_profile.test.id + dns_zone_id = azurerm_dns_zone.test.id + host_name = join(".", ["%[3]s", azurerm_dns_zone.test.name]) + + tls { + certificate_type = "ManagedCertificate" + minimum_tls_version = "TLS10" + } +} + +resource "azurerm_cdn_frontdoor_custom_domain_association" "test" { + cdn_frontdoor_custom_domain_id = azurerm_cdn_frontdoor_custom_domain.test.id + cdn_frontdoor_route_ids = [azurerm_cdn_frontdoor_route.test.id] } -`, data.RandomInteger, data.Locations.Primary) +`, data.RandomInteger, data.Locations.Primary, data.RandomStringOfLength(8)) } diff --git a/internal/services/cdn/cdn_frontdoor_route_resource.go b/internal/services/cdn/cdn_frontdoor_route_resource.go index 35deb4634689..d06fabee33b4 100644 --- a/internal/services/cdn/cdn_frontdoor_route_resource.go +++ b/internal/services/cdn/cdn_frontdoor_route_resource.go @@ -242,7 +242,7 @@ func resourceCdnFrontDoorRouteCreate(d *pluginsdk.ResourceData, meta interface{} } } - normalizedCustomDomains, err := normalizeCustomDomainIds(customDomainsRaw) + normalizedCustomDomains, err := customDomainsInsensitively(customDomainsRaw) if err != nil { return err } @@ -425,7 +425,7 @@ func resourceCdnFrontDoorRouteUpdate(d *pluginsdk.ResourceData, meta interface{} return err } - normalizedCustomDomains, err := normalizeCustomDomainIds(customDomainsRaw) + normalizedCustomDomains, err := customDomainsInsensitively(customDomainsRaw) if err != nil { return err } diff --git a/website/docs/r/cdn_frontdoor_custom_domain_association.html.markdown b/website/docs/r/cdn_frontdoor_custom_domain_association.html.markdown index c1dd5c7bf602..028a115b990c 100644 --- a/website/docs/r/cdn_frontdoor_custom_domain_association.html.markdown +++ b/website/docs/r/cdn_frontdoor_custom_domain_association.html.markdown @@ -8,7 +8,7 @@ description: |- # azurerm_cdn_frontdoor_custom_domain_association -Manages the single apply/single destroy incompatibility between the CDN FrontDoor API and the Terraform dependency graph. You should use this association resource to avoid receiving the `This resource is still associated with a route. Please delete the association with the route first before deleting this resource` error. +Manages the single destroy incompatibility between the CDN FrontDoor API and the Terraform dependency graph generation. You should use this association resource to avoid receiving the `This resource is still associated with a route. Please delete the association with the route first before deleting this resource` error when issuing the Terraform `destroy` command. ## Example Usage @@ -53,5 +53,5 @@ The `timeouts` block allows you to specify [timeouts](https://www.terraform.io/d Frontdoor Routes can be imported using the `resource id`, e.g. ```shell -terraform import azurerm_cdn_frontdoor_custom_domain_association.example /subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/resourceGroup1/providers/Microsoft.Cdn/profiles/profile1/customDomains/domain1/associations/assoc1 +terraform import azurerm_cdn_frontdoor_custom_domain_association.example /subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/resourceGroup1/providers/Microsoft.Cdn/profiles/profile1/associations/assoc1 ``` From 9042993f52f703729141f43b0df082ebb9cbe9e0 Mon Sep 17 00:00:00 2001 From: Jeffrey Cline <20408400+WodansSon@users.noreply.github.com> Date: Tue, 11 Oct 2022 04:17:05 -0600 Subject: [PATCH 20/58] Remove associate_with_cdn_frontdoor_route_id --- ...cdn_frontdoor_custom_domain_association_resource.go | 2 +- .../cdn/cdn_frontdoor_custom_domain_resource.go | 10 ---------- website/docs/r/cdn_frontdoor_route.html.markdown | 2 -- 3 files changed, 1 insertion(+), 13 deletions(-) diff --git a/internal/services/cdn/cdn_frontdoor_custom_domain_association_resource.go b/internal/services/cdn/cdn_frontdoor_custom_domain_association_resource.go index d4ac578e1975..cfef8a2db989 100644 --- a/internal/services/cdn/cdn_frontdoor_custom_domain_association_resource.go +++ b/internal/services/cdn/cdn_frontdoor_custom_domain_association_resource.go @@ -81,7 +81,7 @@ func resourceCdnFrontDoorCustomDomainAssociationRead(d *pluginsdk.ResourceData, return err } - // id will be nill if you are deleting the resource + // id will be nil if you are deleting the resource if id != nil { existing, err := client.Get(ctx, id.ResourceGroup, id.ProfileName, id.CustomDomainName) if err != nil { diff --git a/internal/services/cdn/cdn_frontdoor_custom_domain_resource.go b/internal/services/cdn/cdn_frontdoor_custom_domain_resource.go index a17db2d36095..431d0ec976b0 100644 --- a/internal/services/cdn/cdn_frontdoor_custom_domain_resource.go +++ b/internal/services/cdn/cdn_frontdoor_custom_domain_resource.go @@ -8,7 +8,6 @@ import ( dnsValidate "github.com/hashicorp/go-azure-sdk/resource-manager/dns/2018-05-01/zones" "github.com/hashicorp/terraform-provider-azurerm/helpers/tf" "github.com/hashicorp/terraform-provider-azurerm/internal/clients" - "github.com/hashicorp/terraform-provider-azurerm/internal/features" "github.com/hashicorp/terraform-provider-azurerm/internal/services/cdn/parse" "github.com/hashicorp/terraform-provider-azurerm/internal/services/cdn/validate" "github.com/hashicorp/terraform-provider-azurerm/internal/tf/pluginsdk" @@ -118,15 +117,6 @@ func resourceCdnFrontDoorCustomDomain() *pluginsdk.Resource { }, } - if !features.FourPointOhBeta() { - resource.Schema["associate_with_cdn_frontdoor_route_id"] = &pluginsdk.Schema{ - Type: pluginsdk.TypeString, - Optional: true, - Deprecated: "'associate_with_cdn_frontdoor_route_id' is no longer used and and will be removed in version 4.0 of the AzureRM provider. Please use the 'cdn_frontdoor_custom_domains_ids' field in the 'cdn_frontdoor_route' resource to control the CDN FrontDoor Custom Domain association(s) with the CDN FrontDoor Route", - ValidateFunc: validate.FrontDoorRouteID, - } - } - return resource } diff --git a/website/docs/r/cdn_frontdoor_route.html.markdown b/website/docs/r/cdn_frontdoor_route.html.markdown index 4081abefabab..05e79061986b 100644 --- a/website/docs/r/cdn_frontdoor_route.html.markdown +++ b/website/docs/r/cdn_frontdoor_route.html.markdown @@ -10,8 +10,6 @@ description: |- Manages a CDN FrontDoor Route. --> **RECOMMENDATION:** If your CDN FrontDoor deployment contains multiple CDN FrontDoor Route resources it is advised that you should daisy chain a `depends_on` meta-argument to each of the CDN FrontDoor Route resources to avoid the various service code race conditions that arise while moving CDN FrontDoor Custom Domains across multiple CDN FrontDoor Routes. Keep in mind that the `depends_on` daisy chain will not guard against all potential race conditions depending on how you moving your CDN FrontDoor Custom Domains across your CDN FrontDoor Route resources, but it will alleviate a vast majority of the issues that may occur. Please see the `Daisy Chain Depends_On Example` below for more details. - ## Example Usage ```hcl From c3341da4c1ec3308d2cfd476907641f6e1fe849c Mon Sep 17 00:00:00 2001 From: Jeffrey Cline <20408400+WodansSon@users.noreply.github.com> Date: Tue, 11 Oct 2022 14:31:40 -0600 Subject: [PATCH 21/58] remove validation from read func --- ...door_custom_domain_association_resource.go | 102 +++++++++++------- .../docs/r/cdn_frontdoor_route.html.markdown | 36 ------- 2 files changed, 66 insertions(+), 72 deletions(-) diff --git a/internal/services/cdn/cdn_frontdoor_custom_domain_association_resource.go b/internal/services/cdn/cdn_frontdoor_custom_domain_association_resource.go index cfef8a2db989..f55098001607 100644 --- a/internal/services/cdn/cdn_frontdoor_custom_domain_association_resource.go +++ b/internal/services/cdn/cdn_frontdoor_custom_domain_association_resource.go @@ -57,16 +57,37 @@ func resourceCdnFrontDoorCustomDomainAssociation() *pluginsdk.Resource { } func resourceCdnFrontDoorCustomDomainAssociationCreate(d *pluginsdk.ResourceData, meta interface{}) error { + client := meta.(*clients.Client).Cdn.FrontDoorCustomDomainsClient + ctx, cancel := timeouts.ForCreate(meta.(*clients.Client).StopContext, d) + defer cancel() + log.Printf("[INFO] preparing arguments for CDN FrontDoor Route <-> CDN FrontDoor Custom Domain Association creation") - cdId, err := customDomainNullable(d.Get("cdn_frontdoor_custom_domain_id").(string)) + cdId, err := parse.FrontDoorCustomDomainIDInsensitively(d.Get("cdn_frontdoor_custom_domain_id").(string)) if err != nil { return err } id := parse.NewFrontDoorCustomDomainAssociationID(cdId.SubscriptionId, cdId.ResourceGroup, cdId.ProfileName, cdId.CustomDomainName) + existing, err := client.Get(ctx, cdId.ResourceGroup, cdId.ProfileName, cdId.CustomDomainName) + if err != nil { + if utils.ResponseWasNotFound(existing.Response) { + return fmt.Errorf("creating %s: %s was not found", id, cdId) + } + + return fmt.Errorf("creating %s: %+v", id, err) + } + + // make sure the routes exist and are valid for this custom domain... + routes, err := flattenRoutes(d, meta, cdId) + if err != nil { + return fmt.Errorf("creating %s: %+v", id, err) + } + d.SetId(id.ID()) + d.Set("cdn_frontdoor_custom_domain_id", cdId.ID()) + d.Set("cdn_frontdoor_route_ids", routes) return resourceCdnFrontDoorCustomDomainAssociationRead(d, meta) } @@ -76,42 +97,55 @@ func resourceCdnFrontDoorCustomDomainAssociationRead(d *pluginsdk.ResourceData, ctx, cancel := timeouts.ForCreate(meta.(*clients.Client).StopContext, d) defer cancel() - id, err := customDomainNullable(d.Get("cdn_frontdoor_custom_domain_id").(string)) + id, err := parse.FrontDoorCustomDomainAssociationID(d.Id()) if err != nil { return err } - // id will be nil if you are deleting the resource - if id != nil { - existing, err := client.Get(ctx, id.ResourceGroup, id.ProfileName, id.CustomDomainName) + resp, err := client.Get(ctx, id.ResourceGroup, id.ProfileName, id.AssociationName) + if err != nil { + if utils.ResponseWasNotFound(resp.Response) { + d.SetId("") + return nil + } + + return fmt.Errorf("retrieving %s: %+v", *id, err) + } + + return nil +} + +func resourceCdnFrontDoorCustomDomainAssociationUpdate(d *pluginsdk.ResourceData, meta interface{}) error { + client := meta.(*clients.Client).Cdn.FrontDoorCustomDomainsClient + ctx, cancel := timeouts.ForCreate(meta.(*clients.Client).StopContext, d) + defer cancel() + + if d.HasChange("cdn_frontdoor_route_ids") { + cdId, err := parse.FrontDoorCustomDomainIDInsensitively(d.Get("cdn_frontdoor_custom_domain_id").(string)) + if err != nil { + return err + } + + id := parse.NewFrontDoorCustomDomainAssociationID(cdId.SubscriptionId, cdId.ResourceGroup, cdId.ProfileName, cdId.CustomDomainName) + + existing, err := client.Get(ctx, cdId.ResourceGroup, cdId.ProfileName, cdId.CustomDomainName) if err != nil { if utils.ResponseWasNotFound(existing.Response) { - d.SetId("") - return fmt.Errorf("CDN FrontDoor Custom Domain(Resource Group: %q Name: %q) was not found", id.ResourceGroup, id.CustomDomainName) + return fmt.Errorf("updating %s: %s was not found", id, cdId) } - return fmt.Errorf("checking for existing %s: %+v", id, err) + return fmt.Errorf("updating %s: %+v", id, err) } // make sure the routes exist and are valid for this custom domain... - routes, err := flattenRoutes(d, meta, id) + routes, err := flattenRoutes(d, meta, cdId) if err != nil { - return err + return fmt.Errorf("updating %s: %+v", id, err) } - d.Set("cdn_frontdoor_custom_domain_id", id.ID()) d.Set("cdn_frontdoor_route_ids", routes) } - return nil -} - -func resourceCdnFrontDoorCustomDomainAssociationUpdate(d *pluginsdk.ResourceData, meta interface{}) error { - // if this value has not changed there is nothing to do so just return - if !d.HasChange("cdn_frontdoor_route_ids") { - return nil - } - return resourceCdnFrontDoorCustomDomainAssociationRead(d, meta) } @@ -119,7 +153,16 @@ func resourceCdnFrontDoorCustomDomainAssociationDelete(d *pluginsdk.ResourceData // since you are deleting the resource you cannot grab the value from the config // because it will be empty, you have to get it from the states old value... oCdId, _ := d.GetChange("cdn_frontdoor_custom_domain_id") - id, _ := customDomainNullable(oCdId.(string)) + + cdId, err := parse.FrontDoorCustomDomainIDInsensitively(oCdId.(string)) + if err != nil { + return err + } + + id, err := parse.FrontDoorCustomDomainAssociationID(d.Id()) + if err != nil { + return err + } oRids, _ := d.GetChange("cdn_frontdoor_route_ids") oR := oRids.([]interface{}) @@ -130,8 +173,8 @@ func resourceCdnFrontDoorCustomDomainAssociationDelete(d *pluginsdk.ResourceData } if len(*v) != 0 { - if err := removeCustomDomainAssociationFromRoutes(d, meta, v, id); err != nil { - return err + if err := removeCustomDomainAssociationFromRoutes(d, meta, v, cdId); err != nil { + return fmt.Errorf("deleting %s: %+v", id, err) } } @@ -140,19 +183,6 @@ func resourceCdnFrontDoorCustomDomainAssociationDelete(d *pluginsdk.ResourceData return nil } -func customDomainNullable(input string) (*parse.FrontDoorCustomDomainId, error) { - if len(input) == 0 || input == "" { - return nil, nil - } - - v, err := parse.FrontDoorCustomDomainIDInsensitively(input) - if err != nil { - return nil, err - } - - return v, nil -} - func flattenRoutes(d *pluginsdk.ResourceData, meta interface{}, id *parse.FrontDoorCustomDomainId) ([]interface{}, error) { out := make([]interface{}, 0) o, n := d.GetChange("cdn_frontdoor_route_ids") diff --git a/website/docs/r/cdn_frontdoor_route.html.markdown b/website/docs/r/cdn_frontdoor_route.html.markdown index 05e79061986b..f9d37c9d4d67 100644 --- a/website/docs/r/cdn_frontdoor_route.html.markdown +++ b/website/docs/r/cdn_frontdoor_route.html.markdown @@ -111,42 +111,6 @@ resource "azurerm_cdn_frontdoor_custom_domain_association" "fabrikam" { cdn_frontdoor_route_ids = [azurerm_cdn_frontdoor_route.example.id] } ``` - -## Daisy Chain Depends_On Example - -```hcl -resource "azurerm_cdn_frontdoor_route" "first" { - name = "example-route-one" - cdn_frontdoor_endpoint_id = azurerm_cdn_frontdoor_endpoint.example.id - cdn_frontdoor_origin_group_id = azurerm_cdn_frontdoor_origin_group.example.id - cdn_frontdoor_origin_ids = [azurerm_cdn_frontdoor_origin.example.id] - cdn_frontdoor_rule_set_ids = [azurerm_cdn_frontdoor_rule_set.example.id] - enabled = true -} - -resource "azurerm_cdn_frontdoor_route" "second" { - depends_on = [azurerm_cdn_frontdoor_route.first] - - name = "example-route-two" - cdn_frontdoor_endpoint_id = azurerm_cdn_frontdoor_endpoint.example.id - cdn_frontdoor_origin_group_id = azurerm_cdn_frontdoor_origin_group.example.id - cdn_frontdoor_origin_ids = [azurerm_cdn_frontdoor_origin.example.id] - cdn_frontdoor_rule_set_ids = [azurerm_cdn_frontdoor_rule_set.example.id] - enabled = true -} - -resource "azurerm_cdn_frontdoor_route" "third" { - depends_on = [azurerm_cdn_frontdoor_route.first, azurerm_cdn_frontdoor_route.second] - - name = "example-route-three" - cdn_frontdoor_endpoint_id = azurerm_cdn_frontdoor_endpoint.example.id - cdn_frontdoor_origin_group_id = azurerm_cdn_frontdoor_origin_group.example.id - cdn_frontdoor_origin_ids = [azurerm_cdn_frontdoor_origin.example.id] - cdn_frontdoor_rule_set_ids = [azurerm_cdn_frontdoor_rule_set.example.id] - enabled = true -} -``` - ## Arguments Reference The following arguments are supported: From e128c68021849651286978a146b13757000fe791 Mon Sep 17 00:00:00 2001 From: Jeffrey Cline <20408400+WodansSon@users.noreply.github.com> Date: Tue, 11 Oct 2022 22:43:41 -0600 Subject: [PATCH 22/58] refactor disable link resource --- ...disable_link_to_default_domain_resource.go | 232 ++++++++++-------- 1 file changed, 132 insertions(+), 100 deletions(-) diff --git a/internal/services/cdn/cdn_frontdoor_route_disable_link_to_default_domain_resource.go b/internal/services/cdn/cdn_frontdoor_route_disable_link_to_default_domain_resource.go index 147a82ff78e9..641d086ee0bb 100644 --- a/internal/services/cdn/cdn_frontdoor_route_disable_link_to_default_domain_resource.go +++ b/internal/services/cdn/cdn_frontdoor_route_disable_link_to_default_domain_resource.go @@ -71,9 +71,9 @@ func resourceCdnFrontDoorRouteDisableLinkToDefaultDomainCreate(d *pluginsdk.Reso customDomains := d.Get("cdn_frontdoor_custom_domain_ids").([]interface{}) - routeId, err := parse.FrontDoorRouteID(d.Get("cdn_frontdoor_route_id").(string)) + routeId, err := parse.FrontDoorRouteIDInsensitively(d.Get("cdn_frontdoor_route_id").(string)) if err != nil { - return err + return fmt.Errorf("creating Front Door Route Disable Link To Default Domain: %+v", err) } // create the resource id @@ -81,34 +81,34 @@ func resourceCdnFrontDoorRouteDisableLinkToDefaultDomainCreate(d *pluginsdk.Reso if err != nil { return fmt.Errorf("generating UUID: %+v", err) } + id := parse.NewFrontDoorRouteDisableLinkToDefaultDomainID(routeId.SubscriptionId, routeId.ResourceGroup, routeId.ProfileName, routeId.AfdEndpointName, routeId.RouteName, uuid) - // Lock the resources to make sure this will be an atomic operation - // as this is a one to many association potentially(e.g. route -> custom domain(s))... locks.ByName(routeId.RouteName, cdnFrontDoorRouteResourceName) defer locks.UnlockByName(routeId.RouteName, cdnFrontDoorRouteResourceName) - // Lock all of the custom domains associated with this unlink default domain resource - // prolly overkill but we don't want the custom domains moving while we are doing this - // operation as well... for _, v := range customDomains { - customDomainId, err := parse.FrontDoorCustomDomainID(v.(string)) + customDomainId, err := parse.FrontDoorCustomDomainIDInsensitively(v.(string)) if err != nil { - return err + return fmt.Errorf("creating %s: %+v", id, err) } locks.ByName(customDomainId.CustomDomainName, cdnFrontDoorCustomDomainResourceName) defer locks.UnlockByName(customDomainId.CustomDomainName, cdnFrontDoorCustomDomainResourceName) } - routeResp, err := routeClient.Get(routeCtx, routeId.ResourceGroup, routeId.ProfileName, routeId.AfdEndpointName, routeId.RouteName) + existing, err := routeClient.Get(routeCtx, routeId.ResourceGroup, routeId.ProfileName, routeId.AfdEndpointName, routeId.RouteName) if err != nil { + if utils.ResponseWasNotFound(existing.Response) { + return fmt.Errorf("creating %s: %s was not found", id, routeId) + } + return fmt.Errorf("retrieving existing %s: %+v", *routeId, err) } - props := routeResp.RouteProperties + props := existing.RouteProperties if props == nil { - return fmt.Errorf("%s properties are 'nil': %+v", *routeId, err) + return fmt.Errorf("creating %s: %s properties are 'nil': %+v", id, *routeId, err) } resourceCustomDomains := d.Get("cdn_frontdoor_custom_domain_ids").([]interface{}) @@ -116,12 +116,12 @@ func resourceCdnFrontDoorRouteDisableLinkToDefaultDomainCreate(d *pluginsdk.Reso // make sure its valid to disable the LinkToDefaultDomain on this route... if len(routeCustomDomains) == 0 { - return fmt.Errorf("it is invalid to disable the 'LinkToDefaultDomain' for the CDN Front Door Route(Name: %s) since the route does not have any CDN Front Door Custom Domains associated with it", routeId.RouteName) + return fmt.Errorf("creating %s: it is invalid to disable the 'LinkToDefaultDomain' for the CDN Front Door Route(Name: %s) since the route does not have any CDN Front Door Custom Domains associated with it", id, routeId.RouteName) } // validate the custom domains... if err := validateCustomDomainLinkToDefaultDomainState(resourceCustomDomains, routeCustomDomains, routeId.RouteName, routeId.ProfileName); err != nil { - return err + return fmt.Errorf("creating %s: %+v", id, err) } // If it is already disabled do not update the route... @@ -152,6 +152,8 @@ func resourceCdnFrontDoorRouteDisableLinkToDefaultDomainCreate(d *pluginsdk.Reso } d.SetId(id.ID()) + d.Set("cdn_frontdoor_route_id", routeId.ID()) + d.Set("cdn_frontdoor_custom_domain_ids", customDomains) return resourceCdnFrontDoorRouteDisableLinkToDefaultDomainRead(d, meta) } @@ -162,143 +164,173 @@ func resourceCdnFrontDoorRouteDisableLinkToDefaultDomainRead(d *pluginsdk.Resour defer routeCancel() customDomainClient := meta.(*clients.Client).Cdn.FrontDoorCustomDomainsClient - customDomainCtx, customDomaincancel := timeouts.ForCreate(meta.(*clients.Client).StopContext, d) - defer customDomaincancel() + customDomainCtx, customDomainCancel := timeouts.ForCreate(meta.(*clients.Client).StopContext, d) + defer customDomainCancel() + + id, err := parse.FrontDoorRouteDisableLinkToDefaultDomainID(d.Id()) + if err != nil { + return err + } routeId, err := parse.FrontDoorRouteID(d.Get("cdn_frontdoor_route_id").(string)) if err != nil { - return fmt.Errorf("unable to parse CDN Front Door Route ID: %+v", err) + return fmt.Errorf("front door route disable link to default domain: %+v", err) } // Make sure the route still exist... - routeResp, err := routeClient.Get(routeCtx, routeId.ResourceGroup, routeId.ProfileName, routeId.AfdEndpointName, routeId.RouteName) + existing, err := routeClient.Get(routeCtx, routeId.ResourceGroup, routeId.ProfileName, routeId.AfdEndpointName, routeId.RouteName) if err != nil { + if utils.ResponseWasNotFound(existing.Response) { + return fmt.Errorf("creating %s: %s was not found", id, routeId) + } + return fmt.Errorf("retrieving existing %s: %+v", *routeId, err) } - props := routeResp.RouteProperties - if props == nil { - return fmt.Errorf("%s properties are 'nil': %+v", *routeId, err) + customDomains := d.Get("cdn_frontdoor_custom_domain_ids").([]interface{}) + for _, v := range customDomains { + cdId, err := parse.FrontDoorCustomDomainIDInsensitively(v.(string)) + if err != nil { + return fmt.Errorf("%s: unable to parse CDN Front Door Custom Domain ID: %+v", id, err) + } + + _, err = customDomainClient.Get(customDomainCtx, cdId.ResourceGroup, cdId.ProfileName, cdId.CustomDomainName) + if err != nil { + return fmt.Errorf("retrieving existing %s: %+v", cdId, err) + } } - // Make sure all of the custom domains still exist... - routeCustomDomains := flattenCustomDomainActivatedResourceArray(props.CustomDomains) - resourceCustomDomains := d.Get("cdn_frontdoor_custom_domain_ids").([]interface{}) - for _, v := range resourceCustomDomains { - customDomainId, err := parse.FrontDoorCustomDomainID(v.(string)) + return nil +} + +func resourceCdnFrontDoorRouteDisableLinkToDefaultDomainUpdate(d *pluginsdk.ResourceData, meta interface{}) error { + routeClient := meta.(*clients.Client).Cdn.FrontDoorRoutesClient + workaroundsClient := azuresdkhacks.NewCdnFrontDoorRoutesWorkaroundClient(routeClient) + routeCtx, routeCancel := timeouts.ForCreate(meta.(*clients.Client).StopContext, d) + defer routeCancel() + + if d.HasChange("cdn_frontdoor_custom_domain_ids") { + customDomains := d.Get("cdn_frontdoor_custom_domain_ids").([]interface{}) + + routeId, err := parse.FrontDoorRouteIDInsensitively(d.Get("cdn_frontdoor_route_id").(string)) if err != nil { - return fmt.Errorf("unable to parse CDN Front Door Custom Domain ID: %+v", err) + return fmt.Errorf("updating Front Door Route Disable Link To Default Domain: %+v", err) } - _, err = customDomainClient.Get(customDomainCtx, customDomainId.ResourceGroup, customDomainId.ProfileName, customDomainId.CustomDomainName) + id, err := parse.FrontDoorRouteDisableLinkToDefaultDomainID(d.Id()) if err != nil { - return fmt.Errorf("retrieving existing %s: %+v", customDomainId, err) + return err } - } - // Only do the validation if you are not deleting the resource... - if d.HasChange("cdn_frontdoor_route_id") { - if _, newRoute := d.GetChange("cdn_frontdoor_route_id"); newRoute != "" { - if len(routeCustomDomains) == 0 { - return fmt.Errorf("there are currently no CDN Front Door Custom Domains associated with the CDN Front Door Route(Name: %q). Please remove the resource from your configuration file", routeId.RouteName) - } + locks.ByName(routeId.RouteName, cdnFrontDoorRouteResourceName) + defer locks.UnlockByName(routeId.RouteName, cdnFrontDoorRouteResourceName) - // validate the custom domains... - if err := validateCustomDomainLinkToDefaultDomainState(resourceCustomDomains, routeCustomDomains, routeId.RouteName, routeId.ProfileName); err != nil { - return err + for _, v := range customDomains { + customDomainId, err := parse.FrontDoorCustomDomainIDInsensitively(v.(string)) + if err != nil { + return fmt.Errorf("updating %s: %+v", id, err) } - // In case someone updates this value in portal... - if props.LinkToDefaultDomain != cdn.LinkToDefaultDomainDisabled { - return fmt.Errorf("the 'LinkToDefaultDomain' field has been 'enabled' on the CDN Front Door Route(Name: %q). Please revert this value to 'disabled' before proceeding", routeId.RouteName) + locks.ByName(customDomainId.CustomDomainName, cdnFrontDoorCustomDomainResourceName) + defer locks.UnlockByName(customDomainId.CustomDomainName, cdnFrontDoorCustomDomainResourceName) + } + + existing, err := routeClient.Get(routeCtx, routeId.ResourceGroup, routeId.ProfileName, routeId.AfdEndpointName, routeId.RouteName) + if err != nil { + if utils.ResponseWasNotFound(existing.Response) { + d.SetId("") + return nil } + + return fmt.Errorf("%s: retrieving existing %s: %+v", *id, *routeId, err) } - } - d.Set("cdn_frontdoor_route_id", routeId.ID()) - d.Set("cdn_frontdoor_custom_domain_ids", resourceCustomDomains) + props := existing.RouteProperties + if props == nil { + return fmt.Errorf("updating %s: %s properties are 'nil': %+v", id, *routeId, err) + } - return nil -} + resourceCustomDomains := d.Get("cdn_frontdoor_custom_domain_ids").([]interface{}) + routeCustomDomains := flattenCustomDomainActivatedResourceArray(props.CustomDomains) -func resourceCdnFrontDoorRouteDisableLinkToDefaultDomainUpdate(d *pluginsdk.ResourceData, meta interface{}) error { - routeClient := meta.(*clients.Client).Cdn.FrontDoorRoutesClient - routeCtx, routeCancel := timeouts.ForRead(meta.(*clients.Client).StopContext, d) - defer routeCancel() + // make sure its valid to disable the LinkToDefaultDomain on this route... + if len(routeCustomDomains) == 0 { + return fmt.Errorf("updating %s: it is invalid to disable the 'LinkToDefaultDomain' for the CDN Front Door Route(Name: %s) since the route does not have any CDN Front Door Custom Domains associated with it", id, routeId.RouteName) + } - routeId, err := parse.FrontDoorRouteID(d.Get("cdn_frontdoor_route_id").(string)) - if err != nil { - return fmt.Errorf("unable to parse CDN Front Door Route ID: %+v", err) - } + // validate the custom domains... + if err := validateCustomDomainLinkToDefaultDomainState(resourceCustomDomains, routeCustomDomains, routeId.RouteName, routeId.ProfileName); err != nil { + return fmt.Errorf("updating %s: %+v", id, err) + } - routeResp, err := routeClient.Get(routeCtx, routeId.ResourceGroup, routeId.ProfileName, routeId.AfdEndpointName, routeId.RouteName) - if err != nil { - return fmt.Errorf("retrieving existing %s: %+v", *routeId, err) - } + // If it is already disabled do not update the route... + if props.LinkToDefaultDomain != cdn.LinkToDefaultDomainDisabled { + updateProps := azuresdkhacks.RouteUpdatePropertiesParameters{ + CustomDomains: expandCustomDomainActivatedResourceArray(customDomains), + } - props := routeResp.RouteProperties - if props == nil { - return fmt.Errorf("%s properties are 'nil': %+v", *routeId, err) - } + // Since this unlink default domain resource always set the value to false + updateProps.LinkToDefaultDomain = cdn.LinkToDefaultDomainDisabled - resourceCustomDomains := d.Get("cdn_frontdoor_custom_domain_ids").([]interface{}) - routeCustomDomains := flattenCustomDomainActivatedResourceArray(props.CustomDomains) + // NOTE: You must pull the Cache Configuration from the existing route else you will get a diff, because a nil value means disabled + if props.CacheConfiguration != nil { + updateProps.CacheConfiguration = props.CacheConfiguration + } - // validate the custom domains... - if err := validateCustomDomainLinkToDefaultDomainState(resourceCustomDomains, routeCustomDomains, routeId.RouteName, routeId.ProfileName); err != nil { - return err - } + updatePrarams := azuresdkhacks.RouteUpdateParameters{ + RouteUpdatePropertiesParameters: &updateProps, + } - d.Set("cdn_frontdoor_custom_domain_ids", resourceCustomDomains) + future, err := workaroundsClient.Update(routeCtx, routeId.ResourceGroup, routeId.ProfileName, routeId.AfdEndpointName, routeId.RouteName, updatePrarams) + if err != nil { + return fmt.Errorf("updating %s: %+v", id, err) + } + if err = future.WaitForCompletionRef(routeCtx, routeClient.Client); err != nil { + return fmt.Errorf("waiting for the update of %s: %+v", id, err) + } + } - return nil + d.Set("cdn_frontdoor_route_id", routeId.ID()) + d.Set("cdn_frontdoor_custom_domain_ids", customDomains) + } + + return resourceCdnFrontDoorRouteDisableLinkToDefaultDomainRead(d, meta) } func resourceCdnFrontDoorRouteDisableLinkToDefaultDomainDelete(d *pluginsdk.ResourceData, meta interface{}) error { - routeClient := meta.(*clients.Client).Cdn.FrontDoorRoutesClient - workaroundsClient := azuresdkhacks.NewCdnFrontDoorRoutesWorkaroundClient(routeClient) - routeCtx, routeCancel := timeouts.ForDelete(meta.(*clients.Client).StopContext, d) - defer routeCancel() + client := meta.(*clients.Client).Cdn.FrontDoorRoutesClient + workaroundsClient := azuresdkhacks.NewCdnFrontDoorRoutesWorkaroundClient(client) + ctx, cancel := timeouts.ForDelete(meta.(*clients.Client).StopContext, d) + defer cancel() id, err := parse.FrontDoorRouteDisableLinkToDefaultDomainID(d.Id()) if err != nil { return err } - currentRoute := d.Get("cdn_frontdoor_route_id").(string) + oldRoute, _ := d.GetChange("cdn_frontdoor_route_id") - // If this delete was due to a change you need to revert - // the old route not the new route... - if d.HasChange("cdn_frontdoor_route_id") { - if oldRoute, _ := d.GetChange("cdn_frontdoor_route_id"); oldRoute.(string) != "" { - currentRoute = oldRoute.(string) - } - } - - routeId, err := parse.FrontDoorRouteID(currentRoute) + route, err := parse.FrontDoorRouteIDInsensitively(oldRoute.(string)) if err != nil { return err } - locks.ByName(routeId.RouteName, cdnFrontDoorRouteResourceName) - defer locks.UnlockByName(routeId.RouteName, cdnFrontDoorRouteResourceName) + locks.ByName(route.RouteName, cdnFrontDoorRouteResourceName) + defer locks.UnlockByName(route.RouteName, cdnFrontDoorRouteResourceName) - routeResp, err := routeClient.Get(routeCtx, routeId.ResourceGroup, routeId.ProfileName, routeId.AfdEndpointName, routeId.RouteName) + resp, err := client.Get(ctx, route.ResourceGroup, route.ProfileName, route.AfdEndpointName, route.RouteName) if err != nil { - // No Op: Since the route and the custom domain resources will be deleted before this resource - // in the destroy scenario a 404 can be ignored as it means that it was already destroyed - // so you do not need to set the "link to default domain" value on the route anymore... - if utils.ResponseWasNotFound(routeResp.Response) { + if utils.ResponseWasNotFound(resp.Response) { d.SetId("") return nil } - return fmt.Errorf("retrieving existing %s: %+v", *routeId, err) + return fmt.Errorf("retrieving existing %s: %+v", *route, err) } - props := routeResp.RouteProperties + props := resp.RouteProperties if props == nil { - return fmt.Errorf("%s properties are 'nil': %+v", *routeId, err) + return fmt.Errorf("deleting %s: %s properties are 'nil': %+v", *id, *route, err) } updateProps := azuresdkhacks.RouteUpdatePropertiesParameters{ @@ -311,10 +343,10 @@ func resourceCdnFrontDoorRouteDisableLinkToDefaultDomainDelete(d *pluginsdk.Reso updateProps.CacheConfiguration = props.CacheConfiguration } - // NOTE: Only update LinkToDefaultDomain to enabled if there are not any custom domains associated with the route - routeCustomDomains := flattenCustomDomainActivatedResourceArray(props.CustomDomains) + customDomains := flattenCustomDomainActivatedResourceArray(props.CustomDomains) - if len(routeCustomDomains) == 0 { + // NOTE: Only update LinkToDefaultDomain to enabled if there are not any custom domains associated with the route + if len(customDomains) == 0 { // only update the route if it is currently in the disabled state... if updateProps.LinkToDefaultDomain == cdn.LinkToDefaultDomainDisabled { updateProps.LinkToDefaultDomain = cdn.LinkToDefaultDomainEnabled @@ -323,11 +355,11 @@ func resourceCdnFrontDoorRouteDisableLinkToDefaultDomainDelete(d *pluginsdk.Reso RouteUpdatePropertiesParameters: &updateProps, } - future, err := workaroundsClient.Update(routeCtx, routeId.ResourceGroup, routeId.ProfileName, routeId.AfdEndpointName, routeId.RouteName, updatePrarams) + future, err := workaroundsClient.Update(ctx, route.ResourceGroup, route.ProfileName, route.AfdEndpointName, route.RouteName, updatePrarams) if err != nil { return fmt.Errorf("deleting %s: %+v", *id, err) } - if err = future.WaitForCompletionRef(routeCtx, routeClient.Client); err != nil { + if err = future.WaitForCompletionRef(ctx, client.Client); err != nil { return fmt.Errorf("waiting for the deletion of %s: %+v", *id, err) } } From 2dc38334b513759e3e5ec602ed30ce9b24c77fa8 Mon Sep 17 00:00:00 2001 From: Jeffrey Cline <20408400+WodansSon@users.noreply.github.com> Date: Tue, 11 Oct 2022 23:37:30 -0600 Subject: [PATCH 23/58] Update nil error message --- ...ontdoor_route_disable_link_to_default_domain_resource.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/internal/services/cdn/cdn_frontdoor_route_disable_link_to_default_domain_resource.go b/internal/services/cdn/cdn_frontdoor_route_disable_link_to_default_domain_resource.go index 641d086ee0bb..8e79f16e8b9f 100644 --- a/internal/services/cdn/cdn_frontdoor_route_disable_link_to_default_domain_resource.go +++ b/internal/services/cdn/cdn_frontdoor_route_disable_link_to_default_domain_resource.go @@ -108,7 +108,7 @@ func resourceCdnFrontDoorRouteDisableLinkToDefaultDomainCreate(d *pluginsdk.Reso props := existing.RouteProperties if props == nil { - return fmt.Errorf("creating %s: %s properties are 'nil': %+v", id, *routeId, err) + return fmt.Errorf("creating %s: %s properties are 'nil'", id, *routeId) } resourceCustomDomains := d.Get("cdn_frontdoor_custom_domain_ids").([]interface{}) @@ -247,7 +247,7 @@ func resourceCdnFrontDoorRouteDisableLinkToDefaultDomainUpdate(d *pluginsdk.Reso props := existing.RouteProperties if props == nil { - return fmt.Errorf("updating %s: %s properties are 'nil': %+v", id, *routeId, err) + return fmt.Errorf("updating %s: %s properties are 'nil'", id, *routeId) } resourceCustomDomains := d.Get("cdn_frontdoor_custom_domain_ids").([]interface{}) @@ -330,7 +330,7 @@ func resourceCdnFrontDoorRouteDisableLinkToDefaultDomainDelete(d *pluginsdk.Reso props := resp.RouteProperties if props == nil { - return fmt.Errorf("deleting %s: %s properties are 'nil': %+v", *id, *route, err) + return fmt.Errorf("deleting %s: %s properties are 'nil'", *id, *route) } updateProps := azuresdkhacks.RouteUpdatePropertiesParameters{ From 87ef090de1047819d727155e9de0a9b066e50b4f Mon Sep 17 00:00:00 2001 From: Jeffrey Cline <20408400+WodansSon@users.noreply.github.com> Date: Tue, 11 Oct 2022 23:40:31 -0600 Subject: [PATCH 24/58] fix typo in var name --- ..._route_disable_link_to_default_domain_resource.go | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/internal/services/cdn/cdn_frontdoor_route_disable_link_to_default_domain_resource.go b/internal/services/cdn/cdn_frontdoor_route_disable_link_to_default_domain_resource.go index 8e79f16e8b9f..b667a8ad8f4d 100644 --- a/internal/services/cdn/cdn_frontdoor_route_disable_link_to_default_domain_resource.go +++ b/internal/services/cdn/cdn_frontdoor_route_disable_link_to_default_domain_resource.go @@ -138,11 +138,11 @@ func resourceCdnFrontDoorRouteDisableLinkToDefaultDomainCreate(d *pluginsdk.Reso updateProps.CacheConfiguration = props.CacheConfiguration } - updatePrarams := azuresdkhacks.RouteUpdateParameters{ + updateParams := azuresdkhacks.RouteUpdateParameters{ RouteUpdatePropertiesParameters: &updateProps, } - future, err := workaroundsClient.Update(routeCtx, routeId.ResourceGroup, routeId.ProfileName, routeId.AfdEndpointName, routeId.RouteName, updatePrarams) + future, err := workaroundsClient.Update(routeCtx, routeId.ResourceGroup, routeId.ProfileName, routeId.AfdEndpointName, routeId.RouteName, updateParams) if err != nil { return fmt.Errorf("creating %s: %+v", id, err) } @@ -277,11 +277,11 @@ func resourceCdnFrontDoorRouteDisableLinkToDefaultDomainUpdate(d *pluginsdk.Reso updateProps.CacheConfiguration = props.CacheConfiguration } - updatePrarams := azuresdkhacks.RouteUpdateParameters{ + updateParams := azuresdkhacks.RouteUpdateParameters{ RouteUpdatePropertiesParameters: &updateProps, } - future, err := workaroundsClient.Update(routeCtx, routeId.ResourceGroup, routeId.ProfileName, routeId.AfdEndpointName, routeId.RouteName, updatePrarams) + future, err := workaroundsClient.Update(routeCtx, routeId.ResourceGroup, routeId.ProfileName, routeId.AfdEndpointName, routeId.RouteName, updateParams) if err != nil { return fmt.Errorf("updating %s: %+v", id, err) } @@ -351,11 +351,11 @@ func resourceCdnFrontDoorRouteDisableLinkToDefaultDomainDelete(d *pluginsdk.Reso if updateProps.LinkToDefaultDomain == cdn.LinkToDefaultDomainDisabled { updateProps.LinkToDefaultDomain = cdn.LinkToDefaultDomainEnabled - updatePrarams := azuresdkhacks.RouteUpdateParameters{ + updateParams := azuresdkhacks.RouteUpdateParameters{ RouteUpdatePropertiesParameters: &updateProps, } - future, err := workaroundsClient.Update(ctx, route.ResourceGroup, route.ProfileName, route.AfdEndpointName, route.RouteName, updatePrarams) + future, err := workaroundsClient.Update(ctx, route.ResourceGroup, route.ProfileName, route.AfdEndpointName, route.RouteName, updateParams) if err != nil { return fmt.Errorf("deleting %s: %+v", *id, err) } From fd01df88f5c82ff35d24b00c5156b2fc0d27bf31 Mon Sep 17 00:00:00 2001 From: Wodans Son <20408400+WodansSon@users.noreply.github.com> Date: Wed, 12 Oct 2022 17:49:11 -0600 Subject: [PATCH 25/58] Update website/docs/r/cdn_frontdoor_route_disable_link_to_default_domain.html.markdown Co-authored-by: Tom Harvey --- ...frontdoor_route_disable_link_to_default_domain.html.markdown | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/website/docs/r/cdn_frontdoor_route_disable_link_to_default_domain.html.markdown b/website/docs/r/cdn_frontdoor_route_disable_link_to_default_domain.html.markdown index 4637a2a2f634..6cee69148193 100644 --- a/website/docs/r/cdn_frontdoor_route_disable_link_to_default_domain.html.markdown +++ b/website/docs/r/cdn_frontdoor_route_disable_link_to_default_domain.html.markdown @@ -10,7 +10,7 @@ description: |- Manages the Link To Default Domain property of a CDN FrontDoor Route. -!>**IMPORTANT:** This resource has been deprecated and should not be used. The `azurerm_cdn_frontdoor_route_disable_link_to_default_domain` resource will be removed from the 4.0 AzureRM provider. Please use the `link_to_default_domain` field in the `azurerm_cdn_frontdoor_route` resource to control this value. +!>**IMPORTANT:** This resource has been deprecated and should not be used for new deployments. The `azurerm_cdn_frontdoor_route_disable_link_to_default_domain` resource will be removed from the 4.0 AzureRM provider. Please use the `link_to_default_domain` field in the `azurerm_cdn_frontdoor_route` resource to control this value. ## Example Usage From 367c149c781ec11ad759f660df85edfd16e5c772 Mon Sep 17 00:00:00 2001 From: Wodans Son <20408400+WodansSon@users.noreply.github.com> Date: Wed, 12 Oct 2022 17:49:26 -0600 Subject: [PATCH 26/58] Update website/docs/r/cdn_frontdoor_route.html.markdown Co-authored-by: Tom Harvey --- website/docs/r/cdn_frontdoor_route.html.markdown | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/website/docs/r/cdn_frontdoor_route.html.markdown b/website/docs/r/cdn_frontdoor_route.html.markdown index f9d37c9d4d67..6f12bfeeb86d 100644 --- a/website/docs/r/cdn_frontdoor_route.html.markdown +++ b/website/docs/r/cdn_frontdoor_route.html.markdown @@ -135,7 +135,7 @@ The following arguments are supported: ~> **NOTE:** To to disable caching, do not provide the `cache` block in the configuration file. -* `cdn_frontdoor_custom_domain_ids` - (Optional) The resource IDs of the CDN FrontDoor Custom Domains which are associated with this CDN FrontDoor Route. +* `cdn_frontdoor_custom_domain_ids` - (Optional) The IDs of the CDN FrontDoor Custom Domains which are associated with this CDN FrontDoor Route. * `cdn_frontdoor_origin_path` - (Optional) A directory path on the origin that Frontdoor can use to retrieve content from (e.g. `contoso.cloudapp.net/originpath`). From df9d44242c4e434f316c828305e118c421ebbd32 Mon Sep 17 00:00:00 2001 From: Wodans Son <20408400+WodansSon@users.noreply.github.com> Date: Wed, 12 Oct 2022 17:50:30 -0600 Subject: [PATCH 27/58] Update website/docs/r/cdn_frontdoor_custom_domain_association.html.markdown Co-authored-by: Tom Harvey --- .../r/cdn_frontdoor_custom_domain_association.html.markdown | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/website/docs/r/cdn_frontdoor_custom_domain_association.html.markdown b/website/docs/r/cdn_frontdoor_custom_domain_association.html.markdown index 028a115b990c..3a9e78ad0643 100644 --- a/website/docs/r/cdn_frontdoor_custom_domain_association.html.markdown +++ b/website/docs/r/cdn_frontdoor_custom_domain_association.html.markdown @@ -27,7 +27,7 @@ The following arguments are supported: -> **NOTE:** When the resource is destroyed it will remove the CDN FrontDoor Custom Domain association with the CDN FrontDoor Route resource(s) referenced in the resources `cdn_frontdoor_route_ids` field. -* `cdn_frontdoor_route_ids` - (Required) One or more resource IDs of the CDN FrontDoor Route to which the CDN FrontDoor Custom Domain is associated with. +* `cdn_frontdoor_route_ids` - (Required) One or more IDs of the CDN FrontDoor Route to which the CDN FrontDoor Custom Domain is associated with. -> **NOTE:** This should include all of the CDN FrontDoor Route resources that the CDN FrontDoor Custom Domain is associated with. If the list of CDN FrontDoor Routes is not complete you will receive the service side error mentioned above when you attempt to `destroy`/`delete` your CDN FrontDoor Custom Domain. From 84a11f9025aab09d95e565817515973be0fa202a Mon Sep 17 00:00:00 2001 From: Wodans Son <20408400+WodansSon@users.noreply.github.com> Date: Wed, 12 Oct 2022 17:51:15 -0600 Subject: [PATCH 28/58] Update website/docs/r/cdn_frontdoor_custom_domain_association.html.markdown Co-authored-by: Tom Harvey --- .../docs/r/cdn_frontdoor_custom_domain_association.html.markdown | 1 - 1 file changed, 1 deletion(-) diff --git a/website/docs/r/cdn_frontdoor_custom_domain_association.html.markdown b/website/docs/r/cdn_frontdoor_custom_domain_association.html.markdown index 3a9e78ad0643..679abb89b411 100644 --- a/website/docs/r/cdn_frontdoor_custom_domain_association.html.markdown +++ b/website/docs/r/cdn_frontdoor_custom_domain_association.html.markdown @@ -25,7 +25,6 @@ The following arguments are supported: * `cdn_frontdoor_custom_domain_id` - (Required) The resource ID of the CDN FrontDoor Custom Domain that should be managed by the association resource. Changing this forces a new association resource to be created. --> **NOTE:** When the resource is destroyed it will remove the CDN FrontDoor Custom Domain association with the CDN FrontDoor Route resource(s) referenced in the resources `cdn_frontdoor_route_ids` field. * `cdn_frontdoor_route_ids` - (Required) One or more IDs of the CDN FrontDoor Route to which the CDN FrontDoor Custom Domain is associated with. From ab0845e2aca061b19f1714ab7d6f46e56efb25d9 Mon Sep 17 00:00:00 2001 From: Wodans Son <20408400+WodansSon@users.noreply.github.com> Date: Wed, 12 Oct 2022 19:47:41 -0600 Subject: [PATCH 29/58] Update internal/services/cdn/cdn_frontdoor_custom_domain_association_resource.go Co-authored-by: Tom Harvey --- .../cdn/cdn_frontdoor_custom_domain_association_resource.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/services/cdn/cdn_frontdoor_custom_domain_association_resource.go b/internal/services/cdn/cdn_frontdoor_custom_domain_association_resource.go index f55098001607..120d8445a632 100644 --- a/internal/services/cdn/cdn_frontdoor_custom_domain_association_resource.go +++ b/internal/services/cdn/cdn_frontdoor_custom_domain_association_resource.go @@ -121,7 +121,7 @@ func resourceCdnFrontDoorCustomDomainAssociationUpdate(d *pluginsdk.ResourceData defer cancel() if d.HasChange("cdn_frontdoor_route_ids") { - cdId, err := parse.FrontDoorCustomDomainIDInsensitively(d.Get("cdn_frontdoor_custom_domain_id").(string)) + cdId, err := parse.FrontDoorCustomDomainID(d.Get("cdn_frontdoor_custom_domain_id").(string)) if err != nil { return err } From a0d78816f8c03d0cdbe55296aeeff7cbb39def63 Mon Sep 17 00:00:00 2001 From: Wodans Son <20408400+WodansSon@users.noreply.github.com> Date: Wed, 12 Oct 2022 19:48:11 -0600 Subject: [PATCH 30/58] Update internal/services/cdn/cdn_frontdoor_custom_domain_association_resource.go Co-authored-by: Tom Harvey --- .../cdn/cdn_frontdoor_custom_domain_association_resource.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/services/cdn/cdn_frontdoor_custom_domain_association_resource.go b/internal/services/cdn/cdn_frontdoor_custom_domain_association_resource.go index 120d8445a632..90b171b52229 100644 --- a/internal/services/cdn/cdn_frontdoor_custom_domain_association_resource.go +++ b/internal/services/cdn/cdn_frontdoor_custom_domain_association_resource.go @@ -154,7 +154,7 @@ func resourceCdnFrontDoorCustomDomainAssociationDelete(d *pluginsdk.ResourceData // because it will be empty, you have to get it from the states old value... oCdId, _ := d.GetChange("cdn_frontdoor_custom_domain_id") - cdId, err := parse.FrontDoorCustomDomainIDInsensitively(oCdId.(string)) + cdId, err := parse.FrontDoorCustomDomainID(oCdId.(string)) if err != nil { return err } From 88e1d0be46150c2234811b71efbe83764223c8c2 Mon Sep 17 00:00:00 2001 From: Wodans Son <20408400+WodansSon@users.noreply.github.com> Date: Wed, 12 Oct 2022 19:55:21 -0600 Subject: [PATCH 31/58] Update internal/services/cdn/cdn_frontdoor_custom_domain_resource.go Co-authored-by: Tom Harvey --- internal/services/cdn/cdn_frontdoor_custom_domain_resource.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/services/cdn/cdn_frontdoor_custom_domain_resource.go b/internal/services/cdn/cdn_frontdoor_custom_domain_resource.go index 431d0ec976b0..33f3738ed28f 100644 --- a/internal/services/cdn/cdn_frontdoor_custom_domain_resource.go +++ b/internal/services/cdn/cdn_frontdoor_custom_domain_resource.go @@ -125,7 +125,7 @@ func resourceCdnFrontDoorCustomDomainCreate(d *pluginsdk.ResourceData, meta inte ctx, cancel := timeouts.ForCreate(meta.(*clients.Client).StopContext, d) defer cancel() - profileId, err := parse.FrontDoorProfileIDInsensitively(d.Get("cdn_frontdoor_profile_id").(string)) + profileId, err := parse.FrontDoorProfileID(d.Get("cdn_frontdoor_profile_id").(string)) if err != nil { return err } From 2d8a224a4dc2dbfc26e5f56a4631d477652f569e Mon Sep 17 00:00:00 2001 From: Wodans Son <20408400+WodansSon@users.noreply.github.com> Date: Wed, 12 Oct 2022 20:12:07 -0600 Subject: [PATCH 32/58] Update internal/services/cdn/cdn_frontdoor_custom_domain_resource.go Co-authored-by: Tom Harvey --- internal/services/cdn/cdn_frontdoor_custom_domain_resource.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/services/cdn/cdn_frontdoor_custom_domain_resource.go b/internal/services/cdn/cdn_frontdoor_custom_domain_resource.go index 33f3738ed28f..6d7f6f65badf 100644 --- a/internal/services/cdn/cdn_frontdoor_custom_domain_resource.go +++ b/internal/services/cdn/cdn_frontdoor_custom_domain_resource.go @@ -225,7 +225,7 @@ func resourceCdnFrontDoorCustomDomainUpdate(d *pluginsdk.ResourceData, meta inte ctx, cancel := timeouts.ForUpdate(meta.(*clients.Client).StopContext, d) defer cancel() - id, err := parse.FrontDoorCustomDomainIDInsensitively(d.Id()) + id, err := parse.FrontDoorCustomDomainID(d.Id()) if err != nil { return err } From b9c12456b823292c68d1b6ed84049f28ba098da6 Mon Sep 17 00:00:00 2001 From: Wodans Son <20408400+WodansSon@users.noreply.github.com> Date: Wed, 12 Oct 2022 20:12:45 -0600 Subject: [PATCH 33/58] Update internal/services/cdn/cdn_frontdoor_custom_domain_resource.go Co-authored-by: Tom Harvey --- internal/services/cdn/cdn_frontdoor_custom_domain_resource.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/services/cdn/cdn_frontdoor_custom_domain_resource.go b/internal/services/cdn/cdn_frontdoor_custom_domain_resource.go index 6d7f6f65badf..33c157ea590f 100644 --- a/internal/services/cdn/cdn_frontdoor_custom_domain_resource.go +++ b/internal/services/cdn/cdn_frontdoor_custom_domain_resource.go @@ -253,7 +253,7 @@ func resourceCdnFrontDoorCustomDomainUpdate(d *pluginsdk.ResourceData, meta inte // NOTE: Secret always needs to be passed if it is defined else you will // receive a 500 Internal Server Error if secretRaw != "" { - secret, err := parse.FrontDoorSecretIDInsensitively(secretRaw) + secret, err := parse.FrontDoorSecretID(secretRaw) if err != nil { return err } From d0a0cfe069416fbc2a042975e48fdea7df31b311 Mon Sep 17 00:00:00 2001 From: Wodans Son <20408400+WodansSon@users.noreply.github.com> Date: Wed, 12 Oct 2022 20:16:23 -0600 Subject: [PATCH 34/58] Update internal/services/cdn/cdn_frontdoor_custom_domain_resource.go Co-authored-by: Tom Harvey --- internal/services/cdn/cdn_frontdoor_custom_domain_resource.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/services/cdn/cdn_frontdoor_custom_domain_resource.go b/internal/services/cdn/cdn_frontdoor_custom_domain_resource.go index 33c157ea590f..ebf40ec9b8bb 100644 --- a/internal/services/cdn/cdn_frontdoor_custom_domain_resource.go +++ b/internal/services/cdn/cdn_frontdoor_custom_domain_resource.go @@ -291,7 +291,7 @@ func resourceCdnFrontDoorCustomDomainDelete(d *pluginsdk.ResourceData, meta inte ctx, cancel := timeouts.ForDelete(meta.(*clients.Client).StopContext, d) defer cancel() - id, err := parse.FrontDoorCustomDomainIDInsensitively(d.Id()) + id, err := parse.FrontDoorCustomDomainID(d.Id()) if err != nil { return err } From b48f8f625b62dcd952dd7503145e4d2573fdc984 Mon Sep 17 00:00:00 2001 From: Wodans Son <20408400+WodansSon@users.noreply.github.com> Date: Wed, 12 Oct 2022 20:16:47 -0600 Subject: [PATCH 35/58] Update internal/services/cdn/cdn_frontdoor_custom_domain_resource.go Co-authored-by: Tom Harvey --- internal/services/cdn/cdn_frontdoor_custom_domain_resource.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/services/cdn/cdn_frontdoor_custom_domain_resource.go b/internal/services/cdn/cdn_frontdoor_custom_domain_resource.go index ebf40ec9b8bb..13514d650d39 100644 --- a/internal/services/cdn/cdn_frontdoor_custom_domain_resource.go +++ b/internal/services/cdn/cdn_frontdoor_custom_domain_resource.go @@ -332,7 +332,7 @@ func expandTlsParameters(input []interface{}, isPreValidatedDomain bool) (*cdn.A } if secretRaw != "" { - secret, err := parse.FrontDoorSecretIDInsensitively(secretRaw) + secret, err := parse.FrontDoorSecretID(secretRaw) if err != nil { return nil, err } From ec1f6aa2a23cdc8a6c87a96d4e4561b1f5970b7a Mon Sep 17 00:00:00 2001 From: Wodans Son <20408400+WodansSon@users.noreply.github.com> Date: Wed, 12 Oct 2022 20:30:17 -0600 Subject: [PATCH 36/58] Update internal/services/cdn/cdn_frontdoor_endpoint_resource.go Co-authored-by: Tom Harvey --- internal/services/cdn/cdn_frontdoor_endpoint_resource.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/services/cdn/cdn_frontdoor_endpoint_resource.go b/internal/services/cdn/cdn_frontdoor_endpoint_resource.go index 616339fca929..51438d82cd3c 100644 --- a/internal/services/cdn/cdn_frontdoor_endpoint_resource.go +++ b/internal/services/cdn/cdn_frontdoor_endpoint_resource.go @@ -73,7 +73,7 @@ func resourceCdnFrontDoorEndpointCreate(d *pluginsdk.ResourceData, meta interfac defer cancel() profileRaw := d.Get("cdn_frontdoor_profile_id").(string) - profileId, err := parse.FrontDoorProfileIDInsensitively(profileRaw) + profileId, err := parse.FrontDoorProfileID(profileRaw) if err != nil { return err } From 1665107a9a39e5101fa95d38fba0ce7f45f029c0 Mon Sep 17 00:00:00 2001 From: Wodans Son <20408400+WodansSon@users.noreply.github.com> Date: Wed, 12 Oct 2022 20:30:53 -0600 Subject: [PATCH 37/58] Update internal/services/cdn/cdn_frontdoor_endpoint_resource.go Co-authored-by: Tom Harvey --- internal/services/cdn/cdn_frontdoor_endpoint_resource.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/services/cdn/cdn_frontdoor_endpoint_resource.go b/internal/services/cdn/cdn_frontdoor_endpoint_resource.go index 51438d82cd3c..c06f9ff66d7c 100644 --- a/internal/services/cdn/cdn_frontdoor_endpoint_resource.go +++ b/internal/services/cdn/cdn_frontdoor_endpoint_resource.go @@ -118,7 +118,7 @@ func resourceCdnFrontDoorEndpointRead(d *pluginsdk.ResourceData, meta interface{ ctx, cancel := timeouts.ForRead(meta.(*clients.Client).StopContext, d) defer cancel() - id, err := parse.FrontDoorEndpointIDInsensitively(d.Id()) + id, err := parse.FrontDoorEndpointID(d.Id()) if err != nil { return err } From d387a0efef39bc03e7d2dfdbfe657e6f12b74ba6 Mon Sep 17 00:00:00 2001 From: Wodans Son <20408400+WodansSon@users.noreply.github.com> Date: Wed, 12 Oct 2022 20:31:14 -0600 Subject: [PATCH 38/58] Update internal/services/cdn/cdn_frontdoor_endpoint_resource.go Co-authored-by: Tom Harvey --- internal/services/cdn/cdn_frontdoor_endpoint_resource.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/services/cdn/cdn_frontdoor_endpoint_resource.go b/internal/services/cdn/cdn_frontdoor_endpoint_resource.go index c06f9ff66d7c..855fae1f8745 100644 --- a/internal/services/cdn/cdn_frontdoor_endpoint_resource.go +++ b/internal/services/cdn/cdn_frontdoor_endpoint_resource.go @@ -148,7 +148,7 @@ func resourceCdnFrontDoorEndpointUpdate(d *pluginsdk.ResourceData, meta interfac ctx, cancel := timeouts.ForUpdate(meta.(*clients.Client).StopContext, d) defer cancel() - id, err := parse.FrontDoorEndpointIDInsensitively(d.Id()) + id, err := parse.FrontDoorEndpointID(d.Id()) if err != nil { return err } From f789e0375dc4b3dec57d9615d91158d5647dafb2 Mon Sep 17 00:00:00 2001 From: Wodans Son <20408400+WodansSon@users.noreply.github.com> Date: Wed, 12 Oct 2022 20:31:34 -0600 Subject: [PATCH 39/58] Update internal/services/cdn/cdn_frontdoor_endpoint_resource.go Co-authored-by: Tom Harvey --- internal/services/cdn/cdn_frontdoor_endpoint_resource.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/services/cdn/cdn_frontdoor_endpoint_resource.go b/internal/services/cdn/cdn_frontdoor_endpoint_resource.go index 855fae1f8745..52bea3317a6c 100644 --- a/internal/services/cdn/cdn_frontdoor_endpoint_resource.go +++ b/internal/services/cdn/cdn_frontdoor_endpoint_resource.go @@ -181,7 +181,7 @@ func resourceCdnFrontDoorEndpointDelete(d *pluginsdk.ResourceData, meta interfac ctx, cancel := timeouts.ForDelete(meta.(*clients.Client).StopContext, d) defer cancel() - id, err := parse.FrontDoorEndpointIDInsensitively(d.Id()) + id, err := parse.FrontDoorEndpointID(d.Id()) if err != nil { return err } From dcae3cf51996ac1273656c4073147907a4eaad78 Mon Sep 17 00:00:00 2001 From: Wodans Son <20408400+WodansSon@users.noreply.github.com> Date: Wed, 12 Oct 2022 20:32:11 -0600 Subject: [PATCH 40/58] Update internal/services/cdn/cdn_frontdoor_firewall_policy_resource.go Co-authored-by: Tom Harvey --- internal/services/cdn/cdn_frontdoor_firewall_policy_resource.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/services/cdn/cdn_frontdoor_firewall_policy_resource.go b/internal/services/cdn/cdn_frontdoor_firewall_policy_resource.go index 0003a04e2e3d..35bd8a29e3a0 100644 --- a/internal/services/cdn/cdn_frontdoor_firewall_policy_resource.go +++ b/internal/services/cdn/cdn_frontdoor_firewall_policy_resource.go @@ -530,7 +530,7 @@ func resourceCdnFrontDoorFirewallPolicyUpdate(d *pluginsdk.ResourceData, meta in ctx, cancel := timeouts.ForUpdate(meta.(*clients.Client).StopContext, d) defer cancel() - id, err := parse.FrontDoorFirewallPolicyIDInsensitively(d.Id()) + id, err := parse.FrontDoorFirewallPolicyID(d.Id()) if err != nil { return err } From 0ac6010328c32c42b5d986adb54e4acd7c6beff4 Mon Sep 17 00:00:00 2001 From: Wodans Son <20408400+WodansSon@users.noreply.github.com> Date: Wed, 12 Oct 2022 20:32:40 -0600 Subject: [PATCH 41/58] Update internal/services/cdn/cdn_frontdoor_firewall_policy_resource.go Co-authored-by: Tom Harvey --- internal/services/cdn/cdn_frontdoor_firewall_policy_resource.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/services/cdn/cdn_frontdoor_firewall_policy_resource.go b/internal/services/cdn/cdn_frontdoor_firewall_policy_resource.go index 35bd8a29e3a0..65d0400c519d 100644 --- a/internal/services/cdn/cdn_frontdoor_firewall_policy_resource.go +++ b/internal/services/cdn/cdn_frontdoor_firewall_policy_resource.go @@ -609,7 +609,7 @@ func resourceCdnFrontDoorFirewallPolicyRead(d *pluginsdk.ResourceData, meta inte ctx, cancel := timeouts.ForRead(meta.(*clients.Client).StopContext, d) defer cancel() - id, err := parse.FrontDoorFirewallPolicyIDInsensitively(d.Id()) + id, err := parse.FrontDoorFirewallPolicyID(d.Id()) if err != nil { return err } From 8a0779a9a090fe42c3b27c920cba0e370ee4bf5a Mon Sep 17 00:00:00 2001 From: Wodans Son <20408400+WodansSon@users.noreply.github.com> Date: Wed, 12 Oct 2022 20:37:15 -0600 Subject: [PATCH 42/58] Update internal/services/cdn/cdn_frontdoor_helpers.go Co-authored-by: Tom Harvey --- internal/services/cdn/cdn_frontdoor_helpers.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/services/cdn/cdn_frontdoor_helpers.go b/internal/services/cdn/cdn_frontdoor_helpers.go index 8098339305dc..b467f83ad735 100644 --- a/internal/services/cdn/cdn_frontdoor_helpers.go +++ b/internal/services/cdn/cdn_frontdoor_helpers.go @@ -105,7 +105,7 @@ func flattenFrontDoorTags(tagMap map[string]*string) *map[string]string { func flattenTransformSlice(input *[]frontdoor.TransformType) []interface{} { result := make([]interface{}, 0) - if len(*input) == 0 || input == nil { + if input == nil || len(*input) == 0 { return result } From acb73d08d98191a12349e6086c64029279f799f8 Mon Sep 17 00:00:00 2001 From: Wodans Son <20408400+WodansSon@users.noreply.github.com> Date: Wed, 12 Oct 2022 20:37:52 -0600 Subject: [PATCH 43/58] Update internal/services/cdn/cdn_frontdoor_helpers.go Co-authored-by: Tom Harvey --- internal/services/cdn/cdn_frontdoor_helpers.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/services/cdn/cdn_frontdoor_helpers.go b/internal/services/cdn/cdn_frontdoor_helpers.go index b467f83ad735..491bfd38f96e 100644 --- a/internal/services/cdn/cdn_frontdoor_helpers.go +++ b/internal/services/cdn/cdn_frontdoor_helpers.go @@ -219,7 +219,7 @@ func expandCustomDomainActivatedResourceArray(input []interface{}) *[]cdn.Activa // Normalize these values, if these are imported from portal the will all be lowercased... for _, customDomain := range input { - if id, err := parse.FrontDoorCustomDomainIDInsensitively(customDomain.(string)); err == nil { + if id, err := parse.FrontDoorCustomDomainID(customDomain.(string)); err == nil { results = append(results, cdn.ActivatedResourceReference{ ID: utils.String(id.ID()), }) From 7b8b1bfe8274119b03e55ce6c8bc1ca81dd50ce8 Mon Sep 17 00:00:00 2001 From: Wodans Son <20408400+WodansSon@users.noreply.github.com> Date: Wed, 12 Oct 2022 20:40:12 -0600 Subject: [PATCH 44/58] Update internal/services/cdn/cdn_frontdoor_helpers.go Co-authored-by: Tom Harvey --- internal/services/cdn/cdn_frontdoor_helpers.go | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/internal/services/cdn/cdn_frontdoor_helpers.go b/internal/services/cdn/cdn_frontdoor_helpers.go index 491bfd38f96e..d6d8251b5888 100644 --- a/internal/services/cdn/cdn_frontdoor_helpers.go +++ b/internal/services/cdn/cdn_frontdoor_helpers.go @@ -254,7 +254,13 @@ func flattenCustomDomainActivatedResourceArray(input *[]cdn.ActivatedResourceRef // Normalize these values in the configuration file we know they are valid because they were set on the // resource... if these are modified in the portal the will all be lowercased... for _, customDomain := range *input { - id, _ := parse.FrontDoorCustomDomainIDInsensitively(*customDomain.ID) + if customDomain.ID == nil { + continue + } + id, err := parse.FrontDoorCustomDomainIDInsensitively(*customDomain.ID) + if err != nil { + // we should raise this + } results = append(results, id.ID()) } From 04caf16781cf17ed39b3996fb0845d6b124bf643 Mon Sep 17 00:00:00 2001 From: Wodans Son <20408400+WodansSon@users.noreply.github.com> Date: Wed, 12 Oct 2022 20:41:35 -0600 Subject: [PATCH 45/58] Update internal/services/cdn/cdn_frontdoor_helpers.go Co-authored-by: Tom Harvey --- internal/services/cdn/cdn_frontdoor_helpers.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/services/cdn/cdn_frontdoor_helpers.go b/internal/services/cdn/cdn_frontdoor_helpers.go index d6d8251b5888..480a2577d238 100644 --- a/internal/services/cdn/cdn_frontdoor_helpers.go +++ b/internal/services/cdn/cdn_frontdoor_helpers.go @@ -412,7 +412,7 @@ func validateCustomDomainLinkToDefaultDomainState(resourceCustomDomains []interf wrongProfile := make([]string, 0) for _, v := range resourceCustomDomains { - customDomain, err := parse.FrontDoorCustomDomainIDInsensitively(v.(string)) + customDomain, err := parse.FrontDoorCustomDomainID(v.(string)) if err != nil { return err } From 954f74cc041ee2fae2f3fde4b047ae5ec1e32db6 Mon Sep 17 00:00:00 2001 From: Wodans Son <20408400+WodansSon@users.noreply.github.com> Date: Wed, 12 Oct 2022 20:42:12 -0600 Subject: [PATCH 46/58] Update internal/services/cdn/cdn_frontdoor_helpers.go Co-authored-by: Tom Harvey --- internal/services/cdn/cdn_frontdoor_helpers.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/services/cdn/cdn_frontdoor_helpers.go b/internal/services/cdn/cdn_frontdoor_helpers.go index 480a2577d238..a33be3f52eee 100644 --- a/internal/services/cdn/cdn_frontdoor_helpers.go +++ b/internal/services/cdn/cdn_frontdoor_helpers.go @@ -449,7 +449,7 @@ func validateCustomDomainLinkToDefaultDomainState(resourceCustomDomains []interf notAssociated := make([]string, 0) for _, v := range resourceCustomDomains { - customDomain, err := parse.FrontDoorCustomDomainIDInsensitively(v.(string)) + customDomain, err := parse.FrontDoorCustomDomainID(v.(string)) if err != nil { return fmt.Errorf("unable to parse %q: %+v", v.(string), err) } From 89cdf25ab5e5618ccfb8a5163e0a7e1dbf75bc14 Mon Sep 17 00:00:00 2001 From: Wodans Son <20408400+WodansSon@users.noreply.github.com> Date: Wed, 12 Oct 2022 20:44:13 -0600 Subject: [PATCH 47/58] Update internal/services/cdn/cdn_frontdoor_helpers.go Co-authored-by: Tom Harvey --- internal/services/cdn/cdn_frontdoor_helpers.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/services/cdn/cdn_frontdoor_helpers.go b/internal/services/cdn/cdn_frontdoor_helpers.go index a33be3f52eee..8001c4ecfe70 100644 --- a/internal/services/cdn/cdn_frontdoor_helpers.go +++ b/internal/services/cdn/cdn_frontdoor_helpers.go @@ -473,7 +473,7 @@ func validateRoutesCustomDomainProfile(customDomains []interface{}, routeName st if len(customDomains) != 0 { // Verify all of the custom domains belong to the same profile as the route... for _, v := range customDomains { - customDomain, err := parse.FrontDoorCustomDomainIDInsensitively(v.(string)) + customDomain, err := parse.FrontDoorCustomDomainID(v.(string)) if err != nil { return err } From 6f0bad3b4ed580fac2eca33828aebd27a6af571d Mon Sep 17 00:00:00 2001 From: Wodans Son <20408400+WodansSon@users.noreply.github.com> Date: Wed, 12 Oct 2022 21:21:03 -0600 Subject: [PATCH 48/58] Update internal/services/cdn/cdn_frontdoor_helpers.go Co-authored-by: Tom Harvey --- internal/services/cdn/cdn_frontdoor_helpers.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/services/cdn/cdn_frontdoor_helpers.go b/internal/services/cdn/cdn_frontdoor_helpers.go index 8001c4ecfe70..a66bf712daf3 100644 --- a/internal/services/cdn/cdn_frontdoor_helpers.go +++ b/internal/services/cdn/cdn_frontdoor_helpers.go @@ -493,7 +493,7 @@ func validateRoutesCustomDomainProfile(customDomains []interface{}, routeName st // Validates that the CDN FrontDoor Custom Domain can be associated with the CDN FrontDoor Route func validateCustomDomainRoutes(input *[]parse.FrontDoorRouteId, customDomainID *parse.FrontDoorCustomDomainId) error { - if len(*input) == 0 || input == nil { + if input == nil || len(*input) == 0 { return nil } From 3f87506b974bae1954d5a12435c7e9470754d82a Mon Sep 17 00:00:00 2001 From: Wodans Son <20408400+WodansSon@users.noreply.github.com> Date: Wed, 12 Oct 2022 21:22:05 -0600 Subject: [PATCH 49/58] Update internal/services/cdn/cdn_frontdoor_origin_group_resource.go Co-authored-by: Tom Harvey --- internal/services/cdn/cdn_frontdoor_origin_group_resource.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/services/cdn/cdn_frontdoor_origin_group_resource.go b/internal/services/cdn/cdn_frontdoor_origin_group_resource.go index 84021075cc63..09ffa78204cb 100644 --- a/internal/services/cdn/cdn_frontdoor_origin_group_resource.go +++ b/internal/services/cdn/cdn_frontdoor_origin_group_resource.go @@ -188,7 +188,7 @@ func resourceCdnFrontDoorOriginGroupRead(d *pluginsdk.ResourceData, meta interfa ctx, cancel := timeouts.ForRead(meta.(*clients.Client).StopContext, d) defer cancel() - id, err := parse.FrontDoorOriginGroupIDInsensitively(d.Id()) + id, err := parse.FrontDoorOriginGroupID(d.Id()) if err != nil { return err } From bf212b3b894bd0351356df7e11b0f182b10843cb Mon Sep 17 00:00:00 2001 From: Wodans Son <20408400+WodansSon@users.noreply.github.com> Date: Wed, 12 Oct 2022 21:22:32 -0600 Subject: [PATCH 50/58] Update internal/services/cdn/cdn_frontdoor_origin_group_resource.go Co-authored-by: Tom Harvey --- internal/services/cdn/cdn_frontdoor_origin_group_resource.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/services/cdn/cdn_frontdoor_origin_group_resource.go b/internal/services/cdn/cdn_frontdoor_origin_group_resource.go index 09ffa78204cb..3bc336e22229 100644 --- a/internal/services/cdn/cdn_frontdoor_origin_group_resource.go +++ b/internal/services/cdn/cdn_frontdoor_origin_group_resource.go @@ -226,7 +226,7 @@ func resourceCdnFrontDoorOriginGroupUpdate(d *pluginsdk.ResourceData, meta inter ctx, cancel := timeouts.ForUpdate(meta.(*clients.Client).StopContext, d) defer cancel() - id, err := parse.FrontDoorOriginGroupIDInsensitively(d.Id()) + id, err := parse.FrontDoorOriginGroupID(d.Id()) if err != nil { return err } From 7c26b1c0a9dd7a9c5bd5a11c3a5ebd75f5e04d64 Mon Sep 17 00:00:00 2001 From: Wodans Son <20408400+WodansSon@users.noreply.github.com> Date: Wed, 12 Oct 2022 21:23:11 -0600 Subject: [PATCH 51/58] Update internal/services/cdn/cdn_frontdoor_origin_group_resource.go Co-authored-by: Tom Harvey --- internal/services/cdn/cdn_frontdoor_origin_group_resource.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/services/cdn/cdn_frontdoor_origin_group_resource.go b/internal/services/cdn/cdn_frontdoor_origin_group_resource.go index 3bc336e22229..04717711f1d7 100644 --- a/internal/services/cdn/cdn_frontdoor_origin_group_resource.go +++ b/internal/services/cdn/cdn_frontdoor_origin_group_resource.go @@ -270,7 +270,7 @@ func resourceCdnFrontDoorOriginGroupDelete(d *pluginsdk.ResourceData, meta inter ctx, cancel := timeouts.ForDelete(meta.(*clients.Client).StopContext, d) defer cancel() - id, err := parse.FrontDoorOriginGroupIDInsensitively(d.Id()) + id, err := parse.FrontDoorOriginGroupID(d.Id()) if err != nil { return err } From c213b052ae0609bfd59d75eab07159306982a9e8 Mon Sep 17 00:00:00 2001 From: Wodans Son <20408400+WodansSon@users.noreply.github.com> Date: Wed, 12 Oct 2022 21:25:51 -0600 Subject: [PATCH 52/58] Update website/docs/r/cdn_frontdoor_custom_domain_association.html.markdown Co-authored-by: Tom Harvey --- .../cdn_frontdoor_custom_domain_association.html.markdown | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/website/docs/r/cdn_frontdoor_custom_domain_association.html.markdown b/website/docs/r/cdn_frontdoor_custom_domain_association.html.markdown index 679abb89b411..d7db3ddfb779 100644 --- a/website/docs/r/cdn_frontdoor_custom_domain_association.html.markdown +++ b/website/docs/r/cdn_frontdoor_custom_domain_association.html.markdown @@ -3,12 +3,12 @@ subcategory: "CDN" layout: "azurerm" page_title: "Azure Resource Manager: azurerm_cdn_frontdoor_custom_domain_association" description: |- - Manages the single apply/single destroy incompatibility between the CDN FrontDoor API and the Terraform dependency graph. ---- + Manages the association between a CDN FrontDoor Custom Domain and one or more CDN FrontDoor Routes. + --- -# azurerm_cdn_frontdoor_custom_domain_association + # azurerm_cdn_frontdoor_custom_domain_association -Manages the single destroy incompatibility between the CDN FrontDoor API and the Terraform dependency graph generation. You should use this association resource to avoid receiving the `This resource is still associated with a route. Please delete the association with the route first before deleting this resource` error when issuing the Terraform `destroy` command. +Manages the association between a CDN FrontDoor Custom Domain and one or more CDN FrontDoor Routes. ## Example Usage From e18037e675063910b523e562fd719f5cfced03e6 Mon Sep 17 00:00:00 2001 From: Jeffrey Cline <20408400+WodansSon@users.noreply.github.com> Date: Wed, 12 Oct 2022 21:36:45 -0600 Subject: [PATCH 53/58] remove all Insensitively from resource --- ...frontdoor_custom_domain_association_import.go | 2 +- ...ontdoor_custom_domain_association_resource.go | 5 +++-- ...dn_frontdoor_firewall_policy_resource_test.go | 2 +- internal/services/cdn/cdn_frontdoor_helpers.go | 12 ++++++------ .../cdn/cdn_frontdoor_origin_group_resource.go | 2 +- .../cdn/cdn_frontdoor_origin_resource.go | 8 ++++---- .../cdn/cdn_frontdoor_profile_resource.go | 6 +++--- ...te_disable_link_to_default_domain_resource.go | 12 ++++++------ .../services/cdn/cdn_frontdoor_route_resource.go | 16 ++++++++-------- .../services/cdn/cdn_frontdoor_rule_resource.go | 8 ++++---- .../cdn/cdn_frontdoor_rule_set_resource.go | 6 +++--- .../cdn/cdn_frontdoor_secret_resource.go | 6 +++--- .../cdn_frontdoor_security_policy_resource.go | 6 +++--- 13 files changed, 46 insertions(+), 45 deletions(-) diff --git a/internal/services/cdn/cdn_frontdoor_custom_domain_association_import.go b/internal/services/cdn/cdn_frontdoor_custom_domain_association_import.go index c8fe52b1e729..70f51b6dda4c 100644 --- a/internal/services/cdn/cdn_frontdoor_custom_domain_association_import.go +++ b/internal/services/cdn/cdn_frontdoor_custom_domain_association_import.go @@ -11,7 +11,7 @@ import ( func importCdnFrontDoorCustomDomainAssociation() pluginsdk.ImporterFunc { return func(ctx context.Context, d *pluginsdk.ResourceData, meta interface{}) (data []*pluginsdk.ResourceData, err error) { - id, err := parse.FrontDoorCustomDomainAssociationIDInsensitively(d.Id()) + id, err := parse.FrontDoorCustomDomainAssociationID(d.Id()) if err != nil { return []*pluginsdk.ResourceData{}, err } diff --git a/internal/services/cdn/cdn_frontdoor_custom_domain_association_resource.go b/internal/services/cdn/cdn_frontdoor_custom_domain_association_resource.go index 90b171b52229..7c4251217fad 100644 --- a/internal/services/cdn/cdn_frontdoor_custom_domain_association_resource.go +++ b/internal/services/cdn/cdn_frontdoor_custom_domain_association_resource.go @@ -5,6 +5,7 @@ import ( "log" "time" + "github.com/hashicorp/terraform-provider-azurerm/helpers/tf" "github.com/hashicorp/terraform-provider-azurerm/internal/clients" "github.com/hashicorp/terraform-provider-azurerm/internal/services/cdn/parse" "github.com/hashicorp/terraform-provider-azurerm/internal/services/cdn/validate" @@ -63,7 +64,7 @@ func resourceCdnFrontDoorCustomDomainAssociationCreate(d *pluginsdk.ResourceData log.Printf("[INFO] preparing arguments for CDN FrontDoor Route <-> CDN FrontDoor Custom Domain Association creation") - cdId, err := parse.FrontDoorCustomDomainIDInsensitively(d.Get("cdn_frontdoor_custom_domain_id").(string)) + cdId, err := parse.FrontDoorCustomDomainID(d.Get("cdn_frontdoor_custom_domain_id").(string)) if err != nil { return err } @@ -214,7 +215,7 @@ func flattenRoutes(d *pluginsdk.ResourceData, meta interface{}, id *parse.FrontD // Make sure the custom domain is in the routes association list if len(associations) == 0 || !sliceContainsString(associations, id.ID()) { - return out, fmt.Errorf("the CDN FrontDoor Route(Name: %q) is currently not associated with the CDN FrontDoor Custom Domain(Name: %q). Please remove the CDN FrontDoor Route from your 'cdn_frontdoor_custom_domain_association' configuration block", v.RouteName, id.CustomDomainName) + return out, tf.ImportAsExistsError("cdn_frontdoor_custom_domain_association", id.ID()) } } diff --git a/internal/services/cdn/cdn_frontdoor_firewall_policy_resource_test.go b/internal/services/cdn/cdn_frontdoor_firewall_policy_resource_test.go index 662635fcc8e7..177bc8a6775d 100644 --- a/internal/services/cdn/cdn_frontdoor_firewall_policy_resource_test.go +++ b/internal/services/cdn/cdn_frontdoor_firewall_policy_resource_test.go @@ -85,7 +85,7 @@ func TestAccCdnFrontDoorFirewallPolicy_complete(t *testing.T) { } func (CdnFrontDoorFirewallPolicyResource) Exists(ctx context.Context, clients *clients.Client, state *pluginsdk.InstanceState) (*bool, error) { - id, err := parse.FrontDoorFirewallPolicyIDInsensitively(state.ID) + id, err := parse.FrontDoorFirewallPolicyID(state.ID) if err != nil { return nil, err } diff --git a/internal/services/cdn/cdn_frontdoor_helpers.go b/internal/services/cdn/cdn_frontdoor_helpers.go index a66bf712daf3..71bda02c7fdc 100644 --- a/internal/services/cdn/cdn_frontdoor_helpers.go +++ b/internal/services/cdn/cdn_frontdoor_helpers.go @@ -257,7 +257,7 @@ func flattenCustomDomainActivatedResourceArray(input *[]cdn.ActivatedResourceRef if customDomain.ID == nil { continue } - id, err := parse.FrontDoorCustomDomainIDInsensitively(*customDomain.ID) + id, err := parse.FrontDoorCustomDomainID(*customDomain.ID) if err != nil { // we should raise this } @@ -431,7 +431,7 @@ func validateCustomDomainLinkToDefaultDomainState(resourceCustomDomains []interf for _, v := range routeCustomDomains { // If this was updated by the portal, it lowercases to resource ID... - customDomain, err := parse.FrontDoorCustomDomainIDInsensitively(v.(string)) + customDomain, err := parse.FrontDoorCustomDomainID(v.(string)) if err != nil { return fmt.Errorf("unable to parse %q: %+v", v.(string), err) } @@ -527,7 +527,7 @@ func validateCustomDomainRoutes(input *[]parse.FrontDoorRouteId, customDomainID // Returns a verbose CDN FrontDoor Custom Domain parse error message func friendlyCustomDomainID(customDomain string) (*parse.FrontDoorCustomDomainId, error) { if customDomain != "" { - if customDomainId, err := parse.FrontDoorCustomDomainIDInsensitively(customDomain); err != nil { + if customDomainId, err := parse.FrontDoorCustomDomainID(customDomain); err != nil { return nil, fmt.Errorf("unable to parse CDN FrontDoor Custom Domain(ID: %q): %+v", customDomain, err) } else { return customDomainId, nil @@ -603,7 +603,7 @@ func normalizeRuleSetIds(input []interface{}) ([]interface{}, error) { } for _, ruleSet := range input { - id, err := parse.FrontDoorRuleSetIDInsensitively(ruleSet.(string)) + id, err := parse.FrontDoorRuleSetID(ruleSet.(string)) if err != nil { return nil, err } @@ -622,7 +622,7 @@ func routesInsensitively(input []interface{}) (*[]parse.FrontDoorRouteId, []inte } for _, v := range input { - id, err := parse.FrontDoorRouteIDInsensitively(v.(string)) + id, err := parse.FrontDoorRouteID(v.(string)) if err != nil { return nil, nil, err } @@ -641,7 +641,7 @@ func customDomainsInsensitively(input []interface{}) ([]interface{}, error) { } for _, v := range input { - id, err := parse.FrontDoorCustomDomainIDInsensitively(v.(string)) + id, err := parse.FrontDoorCustomDomainID(v.(string)) if err != nil { return nil, err } diff --git a/internal/services/cdn/cdn_frontdoor_origin_group_resource.go b/internal/services/cdn/cdn_frontdoor_origin_group_resource.go index 04717711f1d7..188a0565ac2c 100644 --- a/internal/services/cdn/cdn_frontdoor_origin_group_resource.go +++ b/internal/services/cdn/cdn_frontdoor_origin_group_resource.go @@ -144,7 +144,7 @@ func resourceCdnFrontDoorOriginGroupCreate(d *pluginsdk.ResourceData, meta inter ctx, cancel := timeouts.ForCreate(meta.(*clients.Client).StopContext, d) defer cancel() - profile, err := parse.FrontDoorProfileIDInsensitively(d.Get("cdn_frontdoor_profile_id").(string)) + profile, err := parse.FrontDoorProfileID(d.Get("cdn_frontdoor_profile_id").(string)) if err != nil { return err } diff --git a/internal/services/cdn/cdn_frontdoor_origin_resource.go b/internal/services/cdn/cdn_frontdoor_origin_resource.go index 6845abcc16b5..82fa2aa84e63 100644 --- a/internal/services/cdn/cdn_frontdoor_origin_resource.go +++ b/internal/services/cdn/cdn_frontdoor_origin_resource.go @@ -180,7 +180,7 @@ func resourceCdnFrontDoorOriginCreate(d *pluginsdk.ResourceData, meta interface{ defer cancel() originGroupRaw := d.Get("cdn_frontdoor_origin_group_id").(string) - originGroup, err := parse.FrontDoorOriginGroupIDInsensitively(originGroupRaw) + originGroup, err := parse.FrontDoorOriginGroupID(originGroupRaw) if err != nil { return err } @@ -267,7 +267,7 @@ func resourceCdnFrontDoorOriginRead(d *pluginsdk.ResourceData, meta interface{}) ctx, cancel := timeouts.ForRead(meta.(*clients.Client).StopContext, d) defer cancel() - id, err := parse.FrontDoorOriginIDInsensitively(d.Id()) + id, err := parse.FrontDoorOriginID(d.Id()) if err != nil { return err } @@ -311,7 +311,7 @@ func resourceCdnFrontDoorOriginUpdate(d *pluginsdk.ResourceData, meta interface{ ctx, cancel := timeouts.ForUpdate(meta.(*clients.Client).StopContext, d) defer cancel() - id, err := parse.FrontDoorOriginIDInsensitively(d.Id()) + id, err := parse.FrontDoorOriginID(d.Id()) if err != nil { return err } @@ -405,7 +405,7 @@ func resourceCdnFrontDoorOriginDelete(d *pluginsdk.ResourceData, meta interface{ ctx, cancel := timeouts.ForDelete(meta.(*clients.Client).StopContext, d) defer cancel() - id, err := parse.FrontDoorOriginIDInsensitively(d.Id()) + id, err := parse.FrontDoorOriginID(d.Id()) if err != nil { return err } diff --git a/internal/services/cdn/cdn_frontdoor_profile_resource.go b/internal/services/cdn/cdn_frontdoor_profile_resource.go index 611bfcacee17..e25538804408 100644 --- a/internal/services/cdn/cdn_frontdoor_profile_resource.go +++ b/internal/services/cdn/cdn_frontdoor_profile_resource.go @@ -122,7 +122,7 @@ func resourceCdnFrontDoorProfileRead(d *pluginsdk.ResourceData, meta interface{} ctx, cancel := timeouts.ForRead(meta.(*clients.Client).StopContext, d) defer cancel() - id, err := parse.FrontDoorProfileIDInsensitively(d.Id()) + id, err := parse.FrontDoorProfileID(d.Id()) if err != nil { return err } @@ -161,7 +161,7 @@ func resourceCdnFrontDoorProfileUpdate(d *pluginsdk.ResourceData, meta interface ctx, cancel := timeouts.ForUpdate(meta.(*clients.Client).StopContext, d) defer cancel() - id, err := parse.FrontDoorProfileIDInsensitively(d.Id()) + id, err := parse.FrontDoorProfileID(d.Id()) if err != nil { return err } @@ -187,7 +187,7 @@ func resourceCdnFrontDoorProfileDelete(d *pluginsdk.ResourceData, meta interface ctx, cancel := timeouts.ForDelete(meta.(*clients.Client).StopContext, d) defer cancel() - id, err := parse.FrontDoorProfileIDInsensitively(d.Id()) + id, err := parse.FrontDoorProfileID(d.Id()) if err != nil { return err } diff --git a/internal/services/cdn/cdn_frontdoor_route_disable_link_to_default_domain_resource.go b/internal/services/cdn/cdn_frontdoor_route_disable_link_to_default_domain_resource.go index b667a8ad8f4d..7833fd50d9f0 100644 --- a/internal/services/cdn/cdn_frontdoor_route_disable_link_to_default_domain_resource.go +++ b/internal/services/cdn/cdn_frontdoor_route_disable_link_to_default_domain_resource.go @@ -71,7 +71,7 @@ func resourceCdnFrontDoorRouteDisableLinkToDefaultDomainCreate(d *pluginsdk.Reso customDomains := d.Get("cdn_frontdoor_custom_domain_ids").([]interface{}) - routeId, err := parse.FrontDoorRouteIDInsensitively(d.Get("cdn_frontdoor_route_id").(string)) + routeId, err := parse.FrontDoorRouteID(d.Get("cdn_frontdoor_route_id").(string)) if err != nil { return fmt.Errorf("creating Front Door Route Disable Link To Default Domain: %+v", err) } @@ -88,7 +88,7 @@ func resourceCdnFrontDoorRouteDisableLinkToDefaultDomainCreate(d *pluginsdk.Reso defer locks.UnlockByName(routeId.RouteName, cdnFrontDoorRouteResourceName) for _, v := range customDomains { - customDomainId, err := parse.FrontDoorCustomDomainIDInsensitively(v.(string)) + customDomainId, err := parse.FrontDoorCustomDomainID(v.(string)) if err != nil { return fmt.Errorf("creating %s: %+v", id, err) } @@ -189,7 +189,7 @@ func resourceCdnFrontDoorRouteDisableLinkToDefaultDomainRead(d *pluginsdk.Resour customDomains := d.Get("cdn_frontdoor_custom_domain_ids").([]interface{}) for _, v := range customDomains { - cdId, err := parse.FrontDoorCustomDomainIDInsensitively(v.(string)) + cdId, err := parse.FrontDoorCustomDomainID(v.(string)) if err != nil { return fmt.Errorf("%s: unable to parse CDN Front Door Custom Domain ID: %+v", id, err) } @@ -212,7 +212,7 @@ func resourceCdnFrontDoorRouteDisableLinkToDefaultDomainUpdate(d *pluginsdk.Reso if d.HasChange("cdn_frontdoor_custom_domain_ids") { customDomains := d.Get("cdn_frontdoor_custom_domain_ids").([]interface{}) - routeId, err := parse.FrontDoorRouteIDInsensitively(d.Get("cdn_frontdoor_route_id").(string)) + routeId, err := parse.FrontDoorRouteID(d.Get("cdn_frontdoor_route_id").(string)) if err != nil { return fmt.Errorf("updating Front Door Route Disable Link To Default Domain: %+v", err) } @@ -226,7 +226,7 @@ func resourceCdnFrontDoorRouteDisableLinkToDefaultDomainUpdate(d *pluginsdk.Reso defer locks.UnlockByName(routeId.RouteName, cdnFrontDoorRouteResourceName) for _, v := range customDomains { - customDomainId, err := parse.FrontDoorCustomDomainIDInsensitively(v.(string)) + customDomainId, err := parse.FrontDoorCustomDomainID(v.(string)) if err != nil { return fmt.Errorf("updating %s: %+v", id, err) } @@ -310,7 +310,7 @@ func resourceCdnFrontDoorRouteDisableLinkToDefaultDomainDelete(d *pluginsdk.Reso oldRoute, _ := d.GetChange("cdn_frontdoor_route_id") - route, err := parse.FrontDoorRouteIDInsensitively(oldRoute.(string)) + route, err := parse.FrontDoorRouteID(oldRoute.(string)) if err != nil { return err } diff --git a/internal/services/cdn/cdn_frontdoor_route_resource.go b/internal/services/cdn/cdn_frontdoor_route_resource.go index d06fabee33b4..ffa46d20cb92 100644 --- a/internal/services/cdn/cdn_frontdoor_route_resource.go +++ b/internal/services/cdn/cdn_frontdoor_route_resource.go @@ -204,7 +204,7 @@ func resourceCdnFrontDoorRouteCreate(d *pluginsdk.ResourceData, meta interface{} defer cancel() endpointRaw := d.Get("cdn_frontdoor_endpoint_id").(string) - endpoint, err := parse.FrontDoorEndpointIDInsensitively(endpointRaw) + endpoint, err := parse.FrontDoorEndpointID(endpointRaw) if err != nil { return err } @@ -260,7 +260,7 @@ func resourceCdnFrontDoorRouteCreate(d *pluginsdk.ResourceData, meta interface{} } if originGroupRaw != "" { - id, err := parse.FrontDoorOriginGroupIDInsensitively(originGroupRaw) + id, err := parse.FrontDoorOriginGroupID(originGroupRaw) if err != nil { return err } @@ -306,7 +306,7 @@ func resourceCdnFrontDoorRouteCreate(d *pluginsdk.ResourceData, meta interface{} // NOTE: These are not sent to the API, they are only here so Terraform // can provision/destroy the resources in the correct order. for _, origin := range originsRaw { - id, err := parse.FrontDoorOriginIDInsensitively(origin.(string)) + id, err := parse.FrontDoorOriginID(origin.(string)) if err != nil { return err } @@ -326,7 +326,7 @@ func resourceCdnFrontDoorRouteRead(d *pluginsdk.ResourceData, meta interface{}) ctx, cancel := timeouts.ForRead(meta.(*clients.Client).StopContext, d) defer cancel() - id, err := parse.FrontDoorRouteIDInsensitively(d.Id()) + id, err := parse.FrontDoorRouteID(d.Id()) if err != nil { return err } @@ -385,7 +385,7 @@ func resourceCdnFrontDoorRouteUpdate(d *pluginsdk.ResourceData, meta interface{} ctx, cancel := timeouts.ForUpdate(meta.(*clients.Client).StopContext, d) defer cancel() - id, err := parse.FrontDoorRouteIDInsensitively(d.Id()) + id, err := parse.FrontDoorRouteID(d.Id()) if err != nil { return err } @@ -420,7 +420,7 @@ func resourceCdnFrontDoorRouteUpdate(d *pluginsdk.ResourceData, meta interface{} } } - originGroup, err := parse.FrontDoorOriginGroupIDInsensitively(originGroupRaw) + originGroup, err := parse.FrontDoorOriginGroupID(originGroupRaw) if err != nil { return err } @@ -525,7 +525,7 @@ func resourceCdnFrontDoorRouteDelete(d *pluginsdk.ResourceData, meta interface{} ctx, cancel := timeouts.ForDelete(meta.(*clients.Client).StopContext, d) defer cancel() - id, err := parse.FrontDoorRouteIDInsensitively(d.Id()) + id, err := parse.FrontDoorRouteID(d.Id()) if err != nil { return err } @@ -608,7 +608,7 @@ func flattenRuleSetResourceArray(input *[]cdn.ResourceReference) []interface{} { // Normalize these values in the configuration file we know they are valid because they were set on the // resource... if these are modified in the portal the will all be lowercased... for _, ruleSet := range *input { - id, _ := parse.FrontDoorRuleSetIDInsensitively(*ruleSet.ID) + id, _ := parse.FrontDoorRuleSetID(*ruleSet.ID) results = append(results, id.ID()) } diff --git a/internal/services/cdn/cdn_frontdoor_rule_resource.go b/internal/services/cdn/cdn_frontdoor_rule_resource.go index 72de5809d20f..fb8bb18c40f2 100644 --- a/internal/services/cdn/cdn_frontdoor_rule_resource.go +++ b/internal/services/cdn/cdn_frontdoor_rule_resource.go @@ -618,7 +618,7 @@ func resourceCdnFrontDoorRuleCreate(d *pluginsdk.ResourceData, meta interface{}) ctx, cancel := timeouts.ForCreate(meta.(*clients.Client).StopContext, d) defer cancel() - ruleSet, err := parse.FrontDoorRuleSetIDInsensitively(d.Get("cdn_frontdoor_rule_set_id").(string)) + ruleSet, err := parse.FrontDoorRuleSetID(d.Get("cdn_frontdoor_rule_set_id").(string)) if err != nil { return err } @@ -678,7 +678,7 @@ func resourceCdnFrontDoorRuleRead(d *pluginsdk.ResourceData, meta interface{}) e ctx, cancel := timeouts.ForRead(meta.(*clients.Client).StopContext, d) defer cancel() - id, err := parse.FrontDoorRuleIDInsensitively(d.Id()) + id, err := parse.FrontDoorRuleID(d.Id()) if err != nil { return err } @@ -726,7 +726,7 @@ func resourceCdnFrontDoorRuleUpdate(d *pluginsdk.ResourceData, meta interface{}) ctx, cancel := timeouts.ForUpdate(meta.(*clients.Client).StopContext, d) defer cancel() - id, err := parse.FrontDoorRuleIDInsensitively(d.Id()) + id, err := parse.FrontDoorRuleID(d.Id()) if err != nil { return err } @@ -783,7 +783,7 @@ func resourceCdnFrontDoorRuleDelete(d *pluginsdk.ResourceData, meta interface{}) ctx, cancel := timeouts.ForDelete(meta.(*clients.Client).StopContext, d) defer cancel() - id, err := parse.FrontDoorRuleIDInsensitively(d.Id()) + id, err := parse.FrontDoorRuleID(d.Id()) if err != nil { return err } diff --git a/internal/services/cdn/cdn_frontdoor_rule_set_resource.go b/internal/services/cdn/cdn_frontdoor_rule_set_resource.go index ce330e57db82..40c07d5f0d02 100644 --- a/internal/services/cdn/cdn_frontdoor_rule_set_resource.go +++ b/internal/services/cdn/cdn_frontdoor_rule_set_resource.go @@ -54,7 +54,7 @@ func resourceCdnFrontDoorRuleSetCreate(d *pluginsdk.ResourceData, meta interface ctx, cancel := timeouts.ForCreate(meta.(*clients.Client).StopContext, d) defer cancel() - profile, err := parse.FrontDoorProfileIDInsensitively(d.Get("cdn_frontdoor_profile_id").(string)) + profile, err := parse.FrontDoorProfileID(d.Get("cdn_frontdoor_profile_id").(string)) if err != nil { return err } @@ -86,7 +86,7 @@ func resourceCdnFrontDoorRuleSetRead(d *pluginsdk.ResourceData, meta interface{} ctx, cancel := timeouts.ForRead(meta.(*clients.Client).StopContext, d) defer cancel() - id, err := parse.FrontDoorRuleSetIDInsensitively(d.Id()) + id, err := parse.FrontDoorRuleSetID(d.Id()) if err != nil { return err } @@ -111,7 +111,7 @@ func resourceCdnFrontDoorRuleSetDelete(d *pluginsdk.ResourceData, meta interface ctx, cancel := timeouts.ForDelete(meta.(*clients.Client).StopContext, d) defer cancel() - id, err := parse.FrontDoorRuleSetIDInsensitively(d.Id()) + id, err := parse.FrontDoorRuleSetID(d.Id()) if err != nil { return err } diff --git a/internal/services/cdn/cdn_frontdoor_secret_resource.go b/internal/services/cdn/cdn_frontdoor_secret_resource.go index 5c2080f4afe7..0397dddf0415 100644 --- a/internal/services/cdn/cdn_frontdoor_secret_resource.go +++ b/internal/services/cdn/cdn_frontdoor_secret_resource.go @@ -98,7 +98,7 @@ func resourceCdnFrontDoorSecretCreate(d *pluginsdk.ResourceData, meta interface{ ctx, cancel := timeouts.ForCreate(meta.(*clients.Client).StopContext, d) defer cancel() - profile, err := parse.FrontDoorProfileIDInsensitively(d.Get("cdn_frontdoor_profile_id").(string)) + profile, err := parse.FrontDoorProfileID(d.Get("cdn_frontdoor_profile_id").(string)) if err != nil { return err } @@ -145,7 +145,7 @@ func resourceCdnFrontDoorSecretRead(d *pluginsdk.ResourceData, meta interface{}) ctx, cancel := timeouts.ForRead(meta.(*clients.Client).StopContext, d) defer cancel() - id, err := parse.FrontDoorSecretIDInsensitively(d.Id()) + id, err := parse.FrontDoorSecretID(d.Id()) if err != nil { return err } @@ -183,7 +183,7 @@ func resourceCdnFrontDoorSecretDelete(d *pluginsdk.ResourceData, meta interface{ ctx, cancel := timeouts.ForDelete(meta.(*clients.Client).StopContext, d) defer cancel() - id, err := parse.FrontDoorSecretIDInsensitively(d.Id()) + id, err := parse.FrontDoorSecretID(d.Id()) if err != nil { return err } diff --git a/internal/services/cdn/cdn_frontdoor_security_policy_resource.go b/internal/services/cdn/cdn_frontdoor_security_policy_resource.go index 5e295af99b11..ee8bb671f710 100644 --- a/internal/services/cdn/cdn_frontdoor_security_policy_resource.go +++ b/internal/services/cdn/cdn_frontdoor_security_policy_resource.go @@ -140,7 +140,7 @@ func resourceCdnFrontdoorSecurityPolicyCreate(d *pluginsdk.ResourceData, meta in defer cancel() // NOTE: The profile id is used to retrieve properties from the related profile that must match in this security policy - profile, err := parse.FrontDoorProfileIDInsensitively(d.Get("cdn_frontdoor_profile_id").(string)) + profile, err := parse.FrontDoorProfileID(d.Get("cdn_frontdoor_profile_id").(string)) if err != nil { return err } @@ -200,7 +200,7 @@ func resourceCdnFrontdoorSecurityPolicyRead(d *pluginsdk.ResourceData, meta inte ctx, cancel := timeouts.ForRead(meta.(*clients.Client).StopContext, d) defer cancel() - id, err := parse.FrontDoorSecurityPolicyIDInsensitively(d.Id()) + id, err := parse.FrontDoorSecurityPolicyID(d.Id()) if err != nil { return err } @@ -263,7 +263,7 @@ func resourceCdnFrontdoorSecurityPolicyDelete(d *pluginsdk.ResourceData, meta in ctx, cancel := timeouts.ForDelete(meta.(*clients.Client).StopContext, d) defer cancel() - id, err := parse.FrontDoorSecurityPolicyIDInsensitively(d.Id()) + id, err := parse.FrontDoorSecurityPolicyID(d.Id()) if err != nil { return err } From dc4495390308124dabd4ca9780c9452d690117a1 Mon Sep 17 00:00:00 2001 From: Wodans Son <20408400+WodansSon@users.noreply.github.com> Date: Wed, 12 Oct 2022 22:46:10 -0600 Subject: [PATCH 54/58] Update website/docs/r/cdn_frontdoor_custom_domain_association.html.markdown Co-authored-by: Tom Harvey --- .../r/cdn_frontdoor_custom_domain_association.html.markdown | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/website/docs/r/cdn_frontdoor_custom_domain_association.html.markdown b/website/docs/r/cdn_frontdoor_custom_domain_association.html.markdown index d7db3ddfb779..d3a1924adc8b 100644 --- a/website/docs/r/cdn_frontdoor_custom_domain_association.html.markdown +++ b/website/docs/r/cdn_frontdoor_custom_domain_association.html.markdown @@ -23,7 +23,7 @@ resource "azurerm_cdn_frontdoor_custom_domain_association" "example" { The following arguments are supported: -* `cdn_frontdoor_custom_domain_id` - (Required) The resource ID of the CDN FrontDoor Custom Domain that should be managed by the association resource. Changing this forces a new association resource to be created. +* `cdn_frontdoor_custom_domain_id` - (Required) The ID of the CDN FrontDoor Custom Domain that should be managed by the association resource. Changing this forces a new association resource to be created. * `cdn_frontdoor_route_ids` - (Required) One or more IDs of the CDN FrontDoor Route to which the CDN FrontDoor Custom Domain is associated with. From 1a281aad7efd62b3e28a017d8e8af5dd8a4d55f3 Mon Sep 17 00:00:00 2001 From: Jeffrey Cline <20408400+WodansSon@users.noreply.github.com> Date: Wed, 12 Oct 2022 23:31:50 -0600 Subject: [PATCH 55/58] Address PR comments --- ...door_custom_domain_association_resource.go | 15 +- .../services/cdn/cdn_frontdoor_helpers.go | 48 ++--- ...disable_link_to_default_domain_resource.go | 17 +- .../cdn/cdn_frontdoor_route_resource.go | 39 ++-- .../front_door_custom_domain_association.go | 56 ------ ...ont_door_custom_domain_association_test.go | 136 -------------- ...or_route_disable_link_to_default_domain.go | 80 -------- ...ute_disable_link_to_default_domain_test.go | 174 ------------------ internal/services/cdn/resourceids.go | 4 +- ...or_custom_domain_association.html.markdown | 3 +- 10 files changed, 70 insertions(+), 502 deletions(-) diff --git a/internal/services/cdn/cdn_frontdoor_custom_domain_association_resource.go b/internal/services/cdn/cdn_frontdoor_custom_domain_association_resource.go index 7c4251217fad..0541f326c61c 100644 --- a/internal/services/cdn/cdn_frontdoor_custom_domain_association_resource.go +++ b/internal/services/cdn/cdn_frontdoor_custom_domain_association_resource.go @@ -5,7 +5,6 @@ import ( "log" "time" - "github.com/hashicorp/terraform-provider-azurerm/helpers/tf" "github.com/hashicorp/terraform-provider-azurerm/internal/clients" "github.com/hashicorp/terraform-provider-azurerm/internal/services/cdn/parse" "github.com/hashicorp/terraform-provider-azurerm/internal/services/cdn/validate" @@ -81,7 +80,7 @@ func resourceCdnFrontDoorCustomDomainAssociationCreate(d *pluginsdk.ResourceData } // make sure the routes exist and are valid for this custom domain... - routes, err := flattenRoutes(d, meta, cdId) + routes, err := validateRoutes(d, meta, cdId) if err != nil { return fmt.Errorf("creating %s: %+v", id, err) } @@ -139,7 +138,7 @@ func resourceCdnFrontDoorCustomDomainAssociationUpdate(d *pluginsdk.ResourceData } // make sure the routes exist and are valid for this custom domain... - routes, err := flattenRoutes(d, meta, cdId) + routes, err := validateRoutes(d, meta, cdId) if err != nil { return fmt.Errorf("updating %s: %+v", id, err) } @@ -168,7 +167,7 @@ func resourceCdnFrontDoorCustomDomainAssociationDelete(d *pluginsdk.ResourceData oRids, _ := d.GetChange("cdn_frontdoor_route_ids") oR := oRids.([]interface{}) - v, _, err := routesInsensitively(oR) + v, _, err := expandRoutes(oR) if err != nil { return err } @@ -184,7 +183,7 @@ func resourceCdnFrontDoorCustomDomainAssociationDelete(d *pluginsdk.ResourceData return nil } -func flattenRoutes(d *pluginsdk.ResourceData, meta interface{}, id *parse.FrontDoorCustomDomainId) ([]interface{}, error) { +func validateRoutes(d *pluginsdk.ResourceData, meta interface{}, id *parse.FrontDoorCustomDomainId) ([]interface{}, error) { out := make([]interface{}, 0) o, n := d.GetChange("cdn_frontdoor_route_ids") oRoutes := o.([]interface{}) @@ -194,12 +193,12 @@ func flattenRoutes(d *pluginsdk.ResourceData, meta interface{}, id *parse.FrontD return out, nil } - oIds, _, err := routesInsensitively(oRoutes) + oIds, _, err := expandRoutes(oRoutes) if err != nil { return out, err } - nIds, result, err := routesInsensitively(nRoutes) + nIds, result, err := expandRoutes(nRoutes) if err != nil { return out, err } @@ -215,7 +214,7 @@ func flattenRoutes(d *pluginsdk.ResourceData, meta interface{}, id *parse.FrontD // Make sure the custom domain is in the routes association list if len(associations) == 0 || !sliceContainsString(associations, id.ID()) { - return out, tf.ImportAsExistsError("cdn_frontdoor_custom_domain_association", id.ID()) + return out, fmt.Errorf("the CDN FrontDoor Route(Name: %q) is currently not associated with the CDN FrontDoor Custom Domain(Name: %q). Please remove the CDN FrontDoor Route from your 'cdn_frontdoor_custom_domain_association' configuration block", v.RouteName, id.CustomDomainName) } } diff --git a/internal/services/cdn/cdn_frontdoor_helpers.go b/internal/services/cdn/cdn_frontdoor_helpers.go index 71bda02c7fdc..c713c2d7c13a 100644 --- a/internal/services/cdn/cdn_frontdoor_helpers.go +++ b/internal/services/cdn/cdn_frontdoor_helpers.go @@ -16,36 +16,36 @@ import ( "github.com/hashicorp/terraform-provider-azurerm/utils" ) -func expandEnabledBool(isEnabled bool) cdn.EnabledState { - if isEnabled { +func expandEnabledBool(input bool) cdn.EnabledState { + if input { return cdn.EnabledStateEnabled } return cdn.EnabledStateDisabled } -func expandEnabledBoolToRouteHttpsRedirect(isEnabled bool) cdn.HTTPSRedirect { - if isEnabled { +func expandEnabledBoolToRouteHttpsRedirect(input bool) cdn.HTTPSRedirect { + if input { return cdn.HTTPSRedirectEnabled } return cdn.HTTPSRedirectDisabled } -func expandEnabledBoolToLinkToDefaultDomain(isEnabled bool) cdn.LinkToDefaultDomain { - if isEnabled { +func expandEnabledBoolToLinkToDefaultDomain(input bool) cdn.LinkToDefaultDomain { + if input { return cdn.LinkToDefaultDomainEnabled } return cdn.LinkToDefaultDomainDisabled } -func flattenLinkToDefaultDomainToBool(linkToDefaultDomain cdn.LinkToDefaultDomain) bool { - if len(linkToDefaultDomain) == 0 { +func flattenLinkToDefaultDomainToBool(input cdn.LinkToDefaultDomain) bool { + if len(input) == 0 { return false } - return linkToDefaultDomain == cdn.LinkToDefaultDomainEnabled + return input == cdn.LinkToDefaultDomainEnabled } func expandResourceReference(input string) *cdn.ResourceReference { @@ -120,7 +120,7 @@ func flattenTransformSlice(input *[]frontdoor.TransformType) []interface{} { func flattenFrontendEndpointLinkSlice(input *[]frontdoor.FrontendEndpointLink) []interface{} { result := make([]interface{}, 0) - if len(*input) == 0 || input == nil { + if input == nil || len(*input) == 0 { return result } @@ -213,11 +213,10 @@ func expandCustomDomainActivatedResourceArray(input []interface{}) *[]cdn.Activa // NOTE: I have confirmed with the service team that this is required to be an explicit "nil" value, an empty // list will not work. I had to modify the SDK to allow for nil which in the API means disassociate the custom domains. - if len(input) == 0 || input == nil { + if len(input) == 0 { return nil } - // Normalize these values, if these are imported from portal the will all be lowercased... for _, customDomain := range input { if id, err := parse.FrontDoorCustomDomainID(customDomain.(string)); err == nil { results = append(results, cdn.ActivatedResourceReference{ @@ -232,7 +231,7 @@ func expandCustomDomainActivatedResourceArray(input []interface{}) *[]cdn.Activa // Takes a CSV formatted string and transforms it into a Slice of strings. func flattenCsvToStringSlice(input *string) []interface{} { results := make([]interface{}, 0) - if len(*input) == 0 || input == nil { + if input == nil || len(*input) == 0 { return results } @@ -245,10 +244,10 @@ func flattenCsvToStringSlice(input *string) []interface{} { return results } -func flattenCustomDomainActivatedResourceArray(input *[]cdn.ActivatedResourceReference) []interface{} { +func flattenCustomDomainActivatedResourceArray(input *[]cdn.ActivatedResourceReference) ([]interface{}, error) { results := make([]interface{}, 0) - if len(*input) == 0 || input == nil { - return results + if input == nil || len(*input) == 0 { + return results, nil } // Normalize these values in the configuration file we know they are valid because they were set on the @@ -257,14 +256,14 @@ func flattenCustomDomainActivatedResourceArray(input *[]cdn.ActivatedResourceRef if customDomain.ID == nil { continue } - id, err := parse.FrontDoorCustomDomainID(*customDomain.ID) + id, err := parse.FrontDoorCustomDomainIDInsensitively(*customDomain.ID) if err != nil { - // we should raise this + return nil, err } results = append(results, id.ID()) } - return results + return results, nil } // determines if the slice contains the value case-insensitively @@ -333,7 +332,10 @@ func getRouteProperties(d *pluginsdk.ResourceData, meta interface{}, id *parse.F return nil, nil, fmt.Errorf("%s: %s properties are 'nil': %+v", resourceName, *id, err) } - customDomains := flattenCustomDomainActivatedResourceArray(props.CustomDomains) + customDomains, err := flattenCustomDomainActivatedResourceArray(props.CustomDomains) + if err != nil { + return nil, nil, err + } return customDomains, props, nil } @@ -596,7 +598,7 @@ func routeDelta(oldRoutes *[]parse.FrontDoorRouteId, newRoutes *[]parse.FrontDoo return &remove, &shared } -func normalizeRuleSetIds(input []interface{}) ([]interface{}, error) { +func expandRuleSetIds(input []interface{}) ([]interface{}, error) { out := make([]interface{}, 0) if len(input) == 0 || input == nil { return out, nil @@ -614,7 +616,7 @@ func normalizeRuleSetIds(input []interface{}) ([]interface{}, error) { return out, nil } -func routesInsensitively(input []interface{}) (*[]parse.FrontDoorRouteId, []interface{}, error) { +func expandRoutes(input []interface{}) (*[]parse.FrontDoorRouteId, []interface{}, error) { out := make([]parse.FrontDoorRouteId, 0) config := make([]interface{}, 0) if len(input) == 0 || input == nil { @@ -634,7 +636,7 @@ func routesInsensitively(input []interface{}) (*[]parse.FrontDoorRouteId, []inte return &out, config, nil } -func customDomainsInsensitively(input []interface{}) ([]interface{}, error) { +func expandCustomDomains(input []interface{}) ([]interface{}, error) { out := make([]interface{}, 0) if len(input) == 0 || input == nil { return out, nil diff --git a/internal/services/cdn/cdn_frontdoor_route_disable_link_to_default_domain_resource.go b/internal/services/cdn/cdn_frontdoor_route_disable_link_to_default_domain_resource.go index 7833fd50d9f0..ea8f101cf869 100644 --- a/internal/services/cdn/cdn_frontdoor_route_disable_link_to_default_domain_resource.go +++ b/internal/services/cdn/cdn_frontdoor_route_disable_link_to_default_domain_resource.go @@ -112,7 +112,10 @@ func resourceCdnFrontDoorRouteDisableLinkToDefaultDomainCreate(d *pluginsdk.Reso } resourceCustomDomains := d.Get("cdn_frontdoor_custom_domain_ids").([]interface{}) - routeCustomDomains := flattenCustomDomainActivatedResourceArray(props.CustomDomains) + routeCustomDomains, err := flattenCustomDomainActivatedResourceArray(props.CustomDomains) + if err != nil { + return err + } // make sure its valid to disable the LinkToDefaultDomain on this route... if len(routeCustomDomains) == 0 { @@ -164,7 +167,7 @@ func resourceCdnFrontDoorRouteDisableLinkToDefaultDomainRead(d *pluginsdk.Resour defer routeCancel() customDomainClient := meta.(*clients.Client).Cdn.FrontDoorCustomDomainsClient - customDomainCtx, customDomainCancel := timeouts.ForCreate(meta.(*clients.Client).StopContext, d) + customDomainCtx, customDomainCancel := timeouts.ForRead(meta.(*clients.Client).StopContext, d) defer customDomainCancel() id, err := parse.FrontDoorRouteDisableLinkToDefaultDomainID(d.Id()) @@ -251,7 +254,10 @@ func resourceCdnFrontDoorRouteDisableLinkToDefaultDomainUpdate(d *pluginsdk.Reso } resourceCustomDomains := d.Get("cdn_frontdoor_custom_domain_ids").([]interface{}) - routeCustomDomains := flattenCustomDomainActivatedResourceArray(props.CustomDomains) + routeCustomDomains, err := flattenCustomDomainActivatedResourceArray(props.CustomDomains) + if err != nil { + return err + } // make sure its valid to disable the LinkToDefaultDomain on this route... if len(routeCustomDomains) == 0 { @@ -343,7 +349,10 @@ func resourceCdnFrontDoorRouteDisableLinkToDefaultDomainDelete(d *pluginsdk.Reso updateProps.CacheConfiguration = props.CacheConfiguration } - customDomains := flattenCustomDomainActivatedResourceArray(props.CustomDomains) + customDomains, err := flattenCustomDomainActivatedResourceArray(props.CustomDomains) + if err != nil { + return err + } // NOTE: Only update LinkToDefaultDomain to enabled if there are not any custom domains associated with the route if len(customDomains) == 0 { diff --git a/internal/services/cdn/cdn_frontdoor_route_resource.go b/internal/services/cdn/cdn_frontdoor_route_resource.go index ffa46d20cb92..5f9fc941cb95 100644 --- a/internal/services/cdn/cdn_frontdoor_route_resource.go +++ b/internal/services/cdn/cdn_frontdoor_route_resource.go @@ -70,7 +70,7 @@ func resourceCdnFrontDoorRoute() *pluginsdk.Resource { }, "cdn_frontdoor_custom_domain_ids": { - Type: pluginsdk.TypeList, + Type: pluginsdk.TypeSet, Optional: true, Elem: &pluginsdk.Schema{ @@ -173,7 +173,7 @@ func resourceCdnFrontDoorRoute() *pluginsdk.Resource { }, "cdn_frontdoor_rule_set_ids": { - Type: pluginsdk.TypeList, + Type: pluginsdk.TypeSet, Optional: true, Elem: &pluginsdk.Schema{ @@ -227,9 +227,9 @@ func resourceCdnFrontDoorRouteCreate(d *pluginsdk.ResourceData, meta interface{} protocolsRaw := d.Get("supported_protocols").(*pluginsdk.Set).List() originGroupRaw := d.Get("cdn_frontdoor_origin_group_id").(string) - ruleSetIdsRaw := d.Get("cdn_frontdoor_rule_set_ids").([]interface{}) + ruleSetIdsRaw := d.Get("cdn_frontdoor_rule_set_ids").(*pluginsdk.Set).List() originsRaw := d.Get("cdn_frontdoor_origin_ids").([]interface{}) - customDomainsRaw := d.Get("cdn_frontdoor_custom_domain_ids").([]interface{}) + customDomainsRaw := d.Get("cdn_frontdoor_custom_domain_ids").(*pluginsdk.Set).List() httpsRedirect := d.Get("https_redirect_enabled").(bool) linkToDefaultDomain := d.Get("link_to_default_domain").(bool) @@ -242,7 +242,7 @@ func resourceCdnFrontDoorRouteCreate(d *pluginsdk.ResourceData, meta interface{} } } - normalizedCustomDomains, err := customDomainsInsensitively(customDomainsRaw) + normalizedCustomDomains, err := expandCustomDomains(customDomainsRaw) if err != nil { return err } @@ -268,7 +268,7 @@ func resourceCdnFrontDoorRouteCreate(d *pluginsdk.ResourceData, meta interface{} originGroup = expandResourceReference(id.ID()) } - normalizedRuleSets, err := normalizeRuleSetIds(ruleSetIdsRaw) + normalizedRuleSets, err := expandRuleSetIds(ruleSetIdsRaw) if err != nil { return err } @@ -351,7 +351,12 @@ func resourceCdnFrontDoorRouteRead(d *pluginsdk.ResourceData, meta interface{}) d.Set("cdn_frontdoor_endpoint_id", parse.NewFrontDoorEndpointID(id.SubscriptionId, id.ResourceGroup, id.ProfileName, id.AfdEndpointName).ID()) if props := resp.RouteProperties; props != nil { - d.Set("cdn_frontdoor_custom_domain_ids", flattenCustomDomainActivatedResourceArray(props.CustomDomains)) + customDomains, err := flattenCustomDomainActivatedResourceArray(props.CustomDomains) + if err != nil { + return err + } + + d.Set("cdn_frontdoor_custom_domain_ids", customDomains) d.Set("enabled", flattenEnabledBool(props.EnabledState)) d.Set("forwarding_protocol", props.ForwardingProtocol) d.Set("https_redirect_enabled", flattenHttpsRedirectToBool(props.HTTPSRedirect)) @@ -406,9 +411,9 @@ func resourceCdnFrontDoorRouteUpdate(d *pluginsdk.ResourceData, meta interface{} httpsRedirect := d.Get("https_redirect_enabled").(bool) protocolsRaw := d.Get("supported_protocols").(*pluginsdk.Set).List() - customDomainsRaw := d.Get("cdn_frontdoor_custom_domain_ids").([]interface{}) + customDomainsRaw := d.Get("cdn_frontdoor_custom_domain_ids").(*pluginsdk.Set).List() originGroupRaw := d.Get("cdn_frontdoor_origin_group_id").(string) - ruleSetIdsRaw := d.Get("cdn_frontdoor_rule_set_ids").([]interface{}) + ruleSetIdsRaw := d.Get("cdn_frontdoor_rule_set_ids").(*pluginsdk.Set).List() linkToDefaultDomain := d.Get("link_to_default_domain").(bool) // NOTE: If HTTPS Redirect is enabled the Supported Protocols must support both HTTP and HTTPS @@ -425,19 +430,19 @@ func resourceCdnFrontDoorRouteUpdate(d *pluginsdk.ResourceData, meta interface{} return err } - normalizedCustomDomains, err := customDomainsInsensitively(customDomainsRaw) + customDomains, err := expandCustomDomains(customDomainsRaw) if err != nil { return err } - if !linkToDefaultDomain && len(normalizedCustomDomains) == 0 { + if !linkToDefaultDomain && len(customDomains) == 0 { return fmt.Errorf("it is invalid to disable the 'LinkToDefaultDomain' for the CDN Front Door Route(Name: %s) since the route does not have any CDN Front Door Custom Domains associated with it", id.RouteName) - } else if len(normalizedCustomDomains) != 0 { - if err := sliceHasDuplicates(normalizedCustomDomains, "CDN FrontDoor Custom Domain"); err != nil { + } else if len(customDomains) != 0 { + if err := sliceHasDuplicates(customDomains, "CDN FrontDoor Custom Domain"); err != nil { return err } - if err := validateRoutesCustomDomainProfile(normalizedCustomDomains, id.RouteName, id.ProfileName); err != nil { + if err := validateRoutesCustomDomainProfile(customDomains, id.RouteName, id.ProfileName); err != nil { return err } } @@ -470,7 +475,7 @@ func resourceCdnFrontDoorRouteUpdate(d *pluginsdk.ResourceData, meta interface{} } if d.HasChange("cdn_frontdoor_custom_domain_ids") { - updateProps.CustomDomains = expandCustomDomainActivatedResourceArray(normalizedCustomDomains) + updateProps.CustomDomains = expandCustomDomainActivatedResourceArray(customDomains) } if d.HasChange("cdn_frontdoor_origin_group_id") { @@ -486,12 +491,12 @@ func resourceCdnFrontDoorRouteUpdate(d *pluginsdk.ResourceData, meta interface{} } if d.HasChange("cdn_frontdoor_rule_set_ids") { - normalizedRuleSets, err := normalizeRuleSetIds(ruleSetIdsRaw) + ruleSets, err := expandRuleSetIds(ruleSetIdsRaw) if err != nil { return err } - updateProps.RuleSets = expandRuleSetReferenceArray(normalizedRuleSets) + updateProps.RuleSets = expandRuleSetReferenceArray(ruleSets) } if d.HasChange("supported_protocols") { diff --git a/internal/services/cdn/parse/front_door_custom_domain_association.go b/internal/services/cdn/parse/front_door_custom_domain_association.go index 75db26ccb310..4a7c2db6a1d6 100644 --- a/internal/services/cdn/parse/front_door_custom_domain_association.go +++ b/internal/services/cdn/parse/front_door_custom_domain_association.go @@ -73,59 +73,3 @@ func FrontDoorCustomDomainAssociationID(input string) (*FrontDoorCustomDomainAss return &resourceId, nil } - -// FrontDoorCustomDomainAssociationIDInsensitively parses an FrontDoorCustomDomainAssociation ID into an FrontDoorCustomDomainAssociationId struct, insensitively -// This should only be used to parse an ID for rewriting, the FrontDoorCustomDomainAssociationID -// method should be used instead for validation etc. -// -// Whilst this may seem strange, this enables Terraform have consistent casing -// which works around issues in Core, whilst handling broken API responses. -func FrontDoorCustomDomainAssociationIDInsensitively(input string) (*FrontDoorCustomDomainAssociationId, error) { - id, err := resourceids.ParseAzureResourceID(input) - if err != nil { - return nil, err - } - - resourceId := FrontDoorCustomDomainAssociationId{ - SubscriptionId: id.SubscriptionID, - ResourceGroup: id.ResourceGroup, - } - - if resourceId.SubscriptionId == "" { - return nil, fmt.Errorf("ID was missing the 'subscriptions' element") - } - - if resourceId.ResourceGroup == "" { - return nil, fmt.Errorf("ID was missing the 'resourceGroups' element") - } - - // find the correct casing for the 'profiles' segment - profilesKey := "profiles" - for key := range id.Path { - if strings.EqualFold(key, profilesKey) { - profilesKey = key - break - } - } - if resourceId.ProfileName, err = id.PopSegment(profilesKey); err != nil { - return nil, err - } - - // find the correct casing for the 'associations' segment - associationsKey := "associations" - for key := range id.Path { - if strings.EqualFold(key, associationsKey) { - associationsKey = key - break - } - } - if resourceId.AssociationName, err = id.PopSegment(associationsKey); err != nil { - return nil, err - } - - if err := id.ValidateNoEmptySegments(input); err != nil { - return nil, err - } - - return &resourceId, nil -} diff --git a/internal/services/cdn/parse/front_door_custom_domain_association_test.go b/internal/services/cdn/parse/front_door_custom_domain_association_test.go index 0fa943871459..23bd0cc1ff5d 100644 --- a/internal/services/cdn/parse/front_door_custom_domain_association_test.go +++ b/internal/services/cdn/parse/front_door_custom_domain_association_test.go @@ -126,139 +126,3 @@ func TestFrontDoorCustomDomainAssociationID(t *testing.T) { } } } - -func TestFrontDoorCustomDomainAssociationIDInsensitively(t *testing.T) { - testData := []struct { - Input string - Error bool - Expected *FrontDoorCustomDomainAssociationId - }{ - - { - // empty - Input: "", - Error: true, - }, - - { - // missing SubscriptionId - Input: "/", - Error: true, - }, - - { - // missing value for SubscriptionId - Input: "/subscriptions/", - Error: true, - }, - - { - // missing ResourceGroup - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/", - Error: true, - }, - - { - // missing value for ResourceGroup - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/", - Error: true, - }, - - { - // missing ProfileName - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Cdn/", - Error: true, - }, - - { - // missing value for ProfileName - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Cdn/profiles/", - Error: true, - }, - - { - // missing AssociationName - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Cdn/profiles/profile1/", - Error: true, - }, - - { - // missing value for AssociationName - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Cdn/profiles/profile1/associations/", - Error: true, - }, - - { - // valid - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Cdn/profiles/profile1/associations/assoc1", - Expected: &FrontDoorCustomDomainAssociationId{ - SubscriptionId: "12345678-1234-9876-4563-123456789012", - ResourceGroup: "resGroup1", - ProfileName: "profile1", - AssociationName: "assoc1", - }, - }, - - { - // lower-cased segment names - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Cdn/profiles/profile1/associations/assoc1", - Expected: &FrontDoorCustomDomainAssociationId{ - SubscriptionId: "12345678-1234-9876-4563-123456789012", - ResourceGroup: "resGroup1", - ProfileName: "profile1", - AssociationName: "assoc1", - }, - }, - - { - // upper-cased segment names - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Cdn/PROFILES/profile1/ASSOCIATIONS/assoc1", - Expected: &FrontDoorCustomDomainAssociationId{ - SubscriptionId: "12345678-1234-9876-4563-123456789012", - ResourceGroup: "resGroup1", - ProfileName: "profile1", - AssociationName: "assoc1", - }, - }, - - { - // mixed-cased segment names - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Cdn/PrOfIlEs/profile1/AsSoCiAtIoNs/assoc1", - Expected: &FrontDoorCustomDomainAssociationId{ - SubscriptionId: "12345678-1234-9876-4563-123456789012", - ResourceGroup: "resGroup1", - ProfileName: "profile1", - AssociationName: "assoc1", - }, - }, - } - - for _, v := range testData { - t.Logf("[DEBUG] Testing %q", v.Input) - - actual, err := FrontDoorCustomDomainAssociationIDInsensitively(v.Input) - if err != nil { - if v.Error { - continue - } - - t.Fatalf("Expect a value but got an error: %s", err) - } - if v.Error { - t.Fatal("Expect an error but didn't get one") - } - - if actual.SubscriptionId != v.Expected.SubscriptionId { - t.Fatalf("Expected %q but got %q for SubscriptionId", v.Expected.SubscriptionId, actual.SubscriptionId) - } - if actual.ResourceGroup != v.Expected.ResourceGroup { - t.Fatalf("Expected %q but got %q for ResourceGroup", v.Expected.ResourceGroup, actual.ResourceGroup) - } - if actual.ProfileName != v.Expected.ProfileName { - t.Fatalf("Expected %q but got %q for ProfileName", v.Expected.ProfileName, actual.ProfileName) - } - if actual.AssociationName != v.Expected.AssociationName { - t.Fatalf("Expected %q but got %q for AssociationName", v.Expected.AssociationName, actual.AssociationName) - } - } -} diff --git a/internal/services/cdn/parse/front_door_route_disable_link_to_default_domain.go b/internal/services/cdn/parse/front_door_route_disable_link_to_default_domain.go index 7d7f2d051381..f40ea47a5add 100644 --- a/internal/services/cdn/parse/front_door_route_disable_link_to_default_domain.go +++ b/internal/services/cdn/parse/front_door_route_disable_link_to_default_domain.go @@ -85,83 +85,3 @@ func FrontDoorRouteDisableLinkToDefaultDomainID(input string) (*FrontDoorRouteDi return &resourceId, nil } - -// FrontDoorRouteDisableLinkToDefaultDomainIDInsensitively parses an FrontDoorRouteDisableLinkToDefaultDomain ID into an FrontDoorRouteDisableLinkToDefaultDomainId struct, insensitively -// This should only be used to parse an ID for rewriting, the FrontDoorRouteDisableLinkToDefaultDomainID -// method should be used instead for validation etc. -// -// Whilst this may seem strange, this enables Terraform have consistent casing -// which works around issues in Core, whilst handling broken API responses. -func FrontDoorRouteDisableLinkToDefaultDomainIDInsensitively(input string) (*FrontDoorRouteDisableLinkToDefaultDomainId, error) { - id, err := resourceids.ParseAzureResourceID(input) - if err != nil { - return nil, err - } - - resourceId := FrontDoorRouteDisableLinkToDefaultDomainId{ - SubscriptionId: id.SubscriptionID, - ResourceGroup: id.ResourceGroup, - } - - if resourceId.SubscriptionId == "" { - return nil, fmt.Errorf("ID was missing the 'subscriptions' element") - } - - if resourceId.ResourceGroup == "" { - return nil, fmt.Errorf("ID was missing the 'resourceGroups' element") - } - - // find the correct casing for the 'profiles' segment - profilesKey := "profiles" - for key := range id.Path { - if strings.EqualFold(key, profilesKey) { - profilesKey = key - break - } - } - if resourceId.ProfileName, err = id.PopSegment(profilesKey); err != nil { - return nil, err - } - - // find the correct casing for the 'afdEndpoints' segment - afdEndpointsKey := "afdEndpoints" - for key := range id.Path { - if strings.EqualFold(key, afdEndpointsKey) { - afdEndpointsKey = key - break - } - } - if resourceId.AfdEndpointName, err = id.PopSegment(afdEndpointsKey); err != nil { - return nil, err - } - - // find the correct casing for the 'routes' segment - routesKey := "routes" - for key := range id.Path { - if strings.EqualFold(key, routesKey) { - routesKey = key - break - } - } - if resourceId.RouteName, err = id.PopSegment(routesKey); err != nil { - return nil, err - } - - // find the correct casing for the 'disableLinkToDefaultDomain' segment - disableLinkToDefaultDomainKey := "disableLinkToDefaultDomain" - for key := range id.Path { - if strings.EqualFold(key, disableLinkToDefaultDomainKey) { - disableLinkToDefaultDomainKey = key - break - } - } - if resourceId.DisableLinkToDefaultDomainName, err = id.PopSegment(disableLinkToDefaultDomainKey); err != nil { - return nil, err - } - - if err := id.ValidateNoEmptySegments(input); err != nil { - return nil, err - } - - return &resourceId, nil -} diff --git a/internal/services/cdn/parse/front_door_route_disable_link_to_default_domain_test.go b/internal/services/cdn/parse/front_door_route_disable_link_to_default_domain_test.go index 8319d7a5e9a5..6efe97eb10e6 100644 --- a/internal/services/cdn/parse/front_door_route_disable_link_to_default_domain_test.go +++ b/internal/services/cdn/parse/front_door_route_disable_link_to_default_domain_test.go @@ -158,177 +158,3 @@ func TestFrontDoorRouteDisableLinkToDefaultDomainID(t *testing.T) { } } } - -func TestFrontDoorRouteDisableLinkToDefaultDomainIDInsensitively(t *testing.T) { - testData := []struct { - Input string - Error bool - Expected *FrontDoorRouteDisableLinkToDefaultDomainId - }{ - - { - // empty - Input: "", - Error: true, - }, - - { - // missing SubscriptionId - Input: "/", - Error: true, - }, - - { - // missing value for SubscriptionId - Input: "/subscriptions/", - Error: true, - }, - - { - // missing ResourceGroup - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/", - Error: true, - }, - - { - // missing value for ResourceGroup - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/", - Error: true, - }, - - { - // missing ProfileName - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Cdn/", - Error: true, - }, - - { - // missing value for ProfileName - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Cdn/profiles/", - Error: true, - }, - - { - // missing AfdEndpointName - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Cdn/profiles/profile1/", - Error: true, - }, - - { - // missing value for AfdEndpointName - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Cdn/profiles/profile1/afdEndpoints/", - Error: true, - }, - - { - // missing RouteName - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Cdn/profiles/profile1/afdEndpoints/endpoint1/", - Error: true, - }, - - { - // missing value for RouteName - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Cdn/profiles/profile1/afdEndpoints/endpoint1/routes/", - Error: true, - }, - - { - // missing DisableLinkToDefaultDomainName - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Cdn/profiles/profile1/afdEndpoints/endpoint1/routes/route1/", - Error: true, - }, - - { - // missing value for DisableLinkToDefaultDomainName - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Cdn/profiles/profile1/afdEndpoints/endpoint1/routes/route1/disableLinkToDefaultDomain/", - Error: true, - }, - - { - // valid - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Cdn/profiles/profile1/afdEndpoints/endpoint1/routes/route1/disableLinkToDefaultDomain/disableLinkToDefaultDomain1", - Expected: &FrontDoorRouteDisableLinkToDefaultDomainId{ - SubscriptionId: "12345678-1234-9876-4563-123456789012", - ResourceGroup: "resGroup1", - ProfileName: "profile1", - AfdEndpointName: "endpoint1", - RouteName: "route1", - DisableLinkToDefaultDomainName: "disableLinkToDefaultDomain1", - }, - }, - - { - // lower-cased segment names - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Cdn/profiles/profile1/afdendpoints/endpoint1/routes/route1/disablelinktodefaultdomain/disableLinkToDefaultDomain1", - Expected: &FrontDoorRouteDisableLinkToDefaultDomainId{ - SubscriptionId: "12345678-1234-9876-4563-123456789012", - ResourceGroup: "resGroup1", - ProfileName: "profile1", - AfdEndpointName: "endpoint1", - RouteName: "route1", - DisableLinkToDefaultDomainName: "disableLinkToDefaultDomain1", - }, - }, - - { - // upper-cased segment names - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Cdn/PROFILES/profile1/AFDENDPOINTS/endpoint1/ROUTES/route1/DISABLELINKTODEFAULTDOMAIN/disableLinkToDefaultDomain1", - Expected: &FrontDoorRouteDisableLinkToDefaultDomainId{ - SubscriptionId: "12345678-1234-9876-4563-123456789012", - ResourceGroup: "resGroup1", - ProfileName: "profile1", - AfdEndpointName: "endpoint1", - RouteName: "route1", - DisableLinkToDefaultDomainName: "disableLinkToDefaultDomain1", - }, - }, - - { - // mixed-cased segment names - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Cdn/PrOfIlEs/profile1/AfDeNdPoInTs/endpoint1/RoUtEs/route1/DiSaBlElInKtOdEfAuLtDoMaIn/disableLinkToDefaultDomain1", - Expected: &FrontDoorRouteDisableLinkToDefaultDomainId{ - SubscriptionId: "12345678-1234-9876-4563-123456789012", - ResourceGroup: "resGroup1", - ProfileName: "profile1", - AfdEndpointName: "endpoint1", - RouteName: "route1", - DisableLinkToDefaultDomainName: "disableLinkToDefaultDomain1", - }, - }, - } - - for _, v := range testData { - t.Logf("[DEBUG] Testing %q", v.Input) - - actual, err := FrontDoorRouteDisableLinkToDefaultDomainIDInsensitively(v.Input) - if err != nil { - if v.Error { - continue - } - - t.Fatalf("Expect a value but got an error: %s", err) - } - if v.Error { - t.Fatal("Expect an error but didn't get one") - } - - if actual.SubscriptionId != v.Expected.SubscriptionId { - t.Fatalf("Expected %q but got %q for SubscriptionId", v.Expected.SubscriptionId, actual.SubscriptionId) - } - if actual.ResourceGroup != v.Expected.ResourceGroup { - t.Fatalf("Expected %q but got %q for ResourceGroup", v.Expected.ResourceGroup, actual.ResourceGroup) - } - if actual.ProfileName != v.Expected.ProfileName { - t.Fatalf("Expected %q but got %q for ProfileName", v.Expected.ProfileName, actual.ProfileName) - } - if actual.AfdEndpointName != v.Expected.AfdEndpointName { - t.Fatalf("Expected %q but got %q for AfdEndpointName", v.Expected.AfdEndpointName, actual.AfdEndpointName) - } - if actual.RouteName != v.Expected.RouteName { - t.Fatalf("Expected %q but got %q for RouteName", v.Expected.RouteName, actual.RouteName) - } - if actual.DisableLinkToDefaultDomainName != v.Expected.DisableLinkToDefaultDomainName { - t.Fatalf("Expected %q but got %q for DisableLinkToDefaultDomainName", v.Expected.DisableLinkToDefaultDomainName, actual.DisableLinkToDefaultDomainName) - } - } -} diff --git a/internal/services/cdn/resourceids.go b/internal/services/cdn/resourceids.go index fc8f3e439ac0..6dc16a0dfab6 100644 --- a/internal/services/cdn/resourceids.go +++ b/internal/services/cdn/resourceids.go @@ -19,5 +19,5 @@ package cdn //go:generate go run ../../tools/generator-resource-id/main.go -path=./ -name=FrontDoorSecurityPolicy -id=/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Cdn/profiles/profile1/securityPolicies/securityPolicy1 -rewrite=true // CDN FrontDoor "Associations" -//go:generate go run ../../tools/generator-resource-id/main.go -path=./ -name=FrontDoorRouteDisableLinkToDefaultDomain -id=/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Cdn/profiles/profile1/afdEndpoints/endpoint1/routes/route1/disableLinkToDefaultDomain/disableLinkToDefaultDomain1 -rewrite=true -//go:generate go run ../../tools/generator-resource-id/main.go -path=./ -name=FrontDoorCustomDomainAssociation -id=/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Cdn/profiles/profile1/associations/assoc1 -rewrite=true +//go:generate go run ../../tools/generator-resource-id/main.go -path=./ -name=FrontDoorRouteDisableLinkToDefaultDomain -id=/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Cdn/profiles/profile1/afdEndpoints/endpoint1/routes/route1/disableLinkToDefaultDomain/disableLinkToDefaultDomain1 +//go:generate go run ../../tools/generator-resource-id/main.go -path=./ -name=FrontDoorCustomDomainAssociation -id=/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Cdn/profiles/profile1/associations/assoc1 diff --git a/website/docs/r/cdn_frontdoor_custom_domain_association.html.markdown b/website/docs/r/cdn_frontdoor_custom_domain_association.html.markdown index d7db3ddfb779..414bb94aa5ba 100644 --- a/website/docs/r/cdn_frontdoor_custom_domain_association.html.markdown +++ b/website/docs/r/cdn_frontdoor_custom_domain_association.html.markdown @@ -25,10 +25,9 @@ The following arguments are supported: * `cdn_frontdoor_custom_domain_id` - (Required) The resource ID of the CDN FrontDoor Custom Domain that should be managed by the association resource. Changing this forces a new association resource to be created. - * `cdn_frontdoor_route_ids` - (Required) One or more IDs of the CDN FrontDoor Route to which the CDN FrontDoor Custom Domain is associated with. --> **NOTE:** This should include all of the CDN FrontDoor Route resources that the CDN FrontDoor Custom Domain is associated with. If the list of CDN FrontDoor Routes is not complete you will receive the service side error mentioned above when you attempt to `destroy`/`delete` your CDN FrontDoor Custom Domain. +-> **NOTE:** This should include all of the CDN FrontDoor Route resources that the CDN FrontDoor Custom Domain is associated with. If the list of CDN FrontDoor Routes is not complete you will receive the service side error `This resource is still associated with a route. Please delete the association with the route first before deleting this resource` when you attempt to `destroy`/`delete` your CDN FrontDoor Custom Domain. ## Attributes Reference From ba549435f2ccd249809a8bf42b113bb7c480c418 Mon Sep 17 00:00:00 2001 From: Jeffrey Cline <20408400+WodansSon@users.noreply.github.com> Date: Thu, 13 Oct 2022 00:01:53 -0600 Subject: [PATCH 56/58] Fix frontmatter issue with doc --- .../r/cdn_frontdoor_custom_domain_association.html.markdown | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/website/docs/r/cdn_frontdoor_custom_domain_association.html.markdown b/website/docs/r/cdn_frontdoor_custom_domain_association.html.markdown index 6eb56d044719..a6a304712752 100644 --- a/website/docs/r/cdn_frontdoor_custom_domain_association.html.markdown +++ b/website/docs/r/cdn_frontdoor_custom_domain_association.html.markdown @@ -4,7 +4,7 @@ layout: "azurerm" page_title: "Azure Resource Manager: azurerm_cdn_frontdoor_custom_domain_association" description: |- Manages the association between a CDN FrontDoor Custom Domain and one or more CDN FrontDoor Routes. - --- +--- # azurerm_cdn_frontdoor_custom_domain_association From fa1939f99d2acd863c0b943e147c911aabea2cb2 Mon Sep 17 00:00:00 2001 From: Jeffrey Cline <20408400+WodansSon@users.noreply.github.com> Date: Thu, 13 Oct 2022 00:16:07 -0600 Subject: [PATCH 57/58] Remove extra space from H1 --- .../r/cdn_frontdoor_custom_domain_association.html.markdown | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/website/docs/r/cdn_frontdoor_custom_domain_association.html.markdown b/website/docs/r/cdn_frontdoor_custom_domain_association.html.markdown index a6a304712752..04a279d264c4 100644 --- a/website/docs/r/cdn_frontdoor_custom_domain_association.html.markdown +++ b/website/docs/r/cdn_frontdoor_custom_domain_association.html.markdown @@ -6,7 +6,7 @@ description: |- Manages the association between a CDN FrontDoor Custom Domain and one or more CDN FrontDoor Routes. --- - # azurerm_cdn_frontdoor_custom_domain_association +# azurerm_cdn_frontdoor_custom_domain_association Manages the association between a CDN FrontDoor Custom Domain and one or more CDN FrontDoor Routes. From 0572a381b0482ee62d93f722085dd7d7dd47d30a Mon Sep 17 00:00:00 2001 From: Jeffrey Cline <20408400+WodansSon@users.noreply.github.com> Date: Thu, 13 Oct 2022 17:50:43 -0600 Subject: [PATCH 58/58] remove friendly parse function --- .../cdn/cdn_frontdoor_custom_domain_resource.go | 2 +- internal/services/cdn/cdn_frontdoor_helpers.go | 13 ------------- 2 files changed, 1 insertion(+), 14 deletions(-) diff --git a/internal/services/cdn/cdn_frontdoor_custom_domain_resource.go b/internal/services/cdn/cdn_frontdoor_custom_domain_resource.go index 13514d650d39..2a3dbd8b74ec 100644 --- a/internal/services/cdn/cdn_frontdoor_custom_domain_resource.go +++ b/internal/services/cdn/cdn_frontdoor_custom_domain_resource.go @@ -182,7 +182,7 @@ func resourceCdnFrontDoorCustomDomainRead(d *pluginsdk.ResourceData, meta interf ctx, cancel := timeouts.ForRead(meta.(*clients.Client).StopContext, d) defer cancel() - id, err := friendlyCustomDomainID(d.Id()) + id, err := parse.FrontDoorCustomDomainID(d.Id()) if err != nil { return err } diff --git a/internal/services/cdn/cdn_frontdoor_helpers.go b/internal/services/cdn/cdn_frontdoor_helpers.go index c713c2d7c13a..fcf96dd3fd35 100644 --- a/internal/services/cdn/cdn_frontdoor_helpers.go +++ b/internal/services/cdn/cdn_frontdoor_helpers.go @@ -526,19 +526,6 @@ func validateCustomDomainRoutes(input *[]parse.FrontDoorRouteId, customDomainID return nil } -// Returns a verbose CDN FrontDoor Custom Domain parse error message -func friendlyCustomDomainID(customDomain string) (*parse.FrontDoorCustomDomainId, error) { - if customDomain != "" { - if customDomainId, err := parse.FrontDoorCustomDomainID(customDomain); err != nil { - return nil, fmt.Errorf("unable to parse CDN FrontDoor Custom Domain(ID: %q): %+v", customDomain, err) - } else { - return customDomainId, nil - } - } - - return nil, fmt.Errorf("unable to parse CDN FrontDoor Custom Domain: no value was passed") -} - // Checks to make sure the list of CDN FrontDoor Custom Domains does not contain duplicate entries func sliceHasDuplicates(input []interface{}, resourceTxt string) error { k := make(map[string]bool)