Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[New Resources:] azurerm_cdn_frontdoor_route, azurerm_cdn_frontdoor_custom_domain and azurerm_cdn_route_disable_link_to_default_domain #18231

Merged
merged 30 commits into from
Sep 29, 2022
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
4adc4fd
initial check-in
WodansSon Sep 2, 2022
7fa2ef1
still refactoring but should be functional
WodansSon Sep 3, 2022
4f07464
Doc updates
WodansSon Sep 3, 2022
2d53920
deprecate health_probes_enabled property
WodansSon Sep 6, 2022
091ec75
Update website/docs/r/cdn_frontdoor_custom_domain_secret_validator.ht…
WodansSon Sep 6, 2022
6fd2929
Update website/docs/r/cdn_frontdoor_custom_domain_txt_validator.html.…
WodansSon Sep 6, 2022
0102ca4
refactor CIDR validation into validation packages
WodansSon Sep 7, 2022
f532bfe
fix naked return lint error in cidr overlap func
WodansSon Sep 7, 2022
7861b5e
Update code comments to add context
WodansSon Sep 7, 2022
5a7b52d
Fix for 18249
WodansSon Sep 7, 2022
89341d6
Remove txt and secret validators
WodansSon Sep 9, 2022
afe979e
Remove validator ids, parse/validation packages
WodansSon Sep 9, 2022
ed5e6c9
Update rules doc for depends_on usage
WodansSon Sep 9, 2022
a841836
Doc updates
WodansSon Sep 10, 2022
15babb5
Update test cases
WodansSon Sep 10, 2022
26e05bf
Correct skip txt for origin test
WodansSon Sep 10, 2022
f5fef88
More test and doc updates
WodansSon Sep 10, 2022
44b5a74
Update test and docs to use new subnet field
WodansSon Sep 10, 2022
43abd6d
Fix for 18370
WodansSon Sep 13, 2022
68ffab3
Update docs per PR comment
WodansSon Sep 15, 2022
83a56f0
Incremental fixed per PR review
WodansSon Sep 20, 2022
7699d08
Initial additon of association and doc fix
WodansSon Sep 21, 2022
e8ae841
Custom domain assoc mostly working
WodansSon Sep 22, 2022
270310a
Additional progress...
WodansSon Sep 27, 2022
a8dd8b4
Fix lint errors
WodansSon Sep 27, 2022
5b221dc
Fix lint errors
WodansSon Sep 27, 2022
4da369c
Last of the PR comments addressed...
WodansSon Sep 27, 2022
0fad210
Fix for issue #18551
WodansSon Sep 28, 2022
70ada7a
Mostly working not done with the disable resource
WodansSon Sep 29, 2022
6774427
Done
WodansSon Sep 29, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
307 changes: 307 additions & 0 deletions internal/services/cdn/cdn_frontdoor_custom_domain_resource.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,307 @@
package cdn

import (
"fmt"
"time"

"github.com/Azure/azure-sdk-for-go/services/cdn/mgmt/2020-09-01/cdn"
track1 "github.com/Azure/azure-sdk-for-go/services/cdn/mgmt/2021-06-01/cdn"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why are we importing two versions of cdn here, can we not use one?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed.

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/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/tf/validation"
"github.com/hashicorp/terraform-provider-azurerm/internal/timeouts"
"github.com/hashicorp/terraform-provider-azurerm/utils"
)

func resourceCdnFrontDoorCustomDomain() *pluginsdk.Resource {
return &pluginsdk.Resource{
Create: resourceCdnFrontDoorCustomDomainCreate,
Read: resourceCdnFrontDoorCustomDomainRead,
Update: resourceCdnFrontDoorCustomDomainUpdate,
Delete: resourceCdnFrontDoorCustomDomainDelete,

Timeouts: &pluginsdk.ResourceTimeout{
// TODO: these timeouts need adjusting..?
// WS: No, these are correct as this is currently a manual step.
Create: pluginsdk.DefaultTimeout(12 * time.Hour),
Read: pluginsdk.DefaultTimeout(5 * time.Minute),
Update: pluginsdk.DefaultTimeout(24 * time.Hour),
Delete: pluginsdk.DefaultTimeout(12 * time.Hour),
},

Importer: pluginsdk.ImporterValidatingResourceId(func(id string) error {
_, err := parse.FrontdoorCustomDomainID(id)
return err
}),

Schema: map[string]*pluginsdk.Schema{
"name": {
Type: pluginsdk.TypeString,
Required: true,
ForceNew: true,
ValidateFunc: validate.FrontDoorCustomDomainName,
},

// NOTE: I need this fake field because I need the profile name during the create operation
"cdn_frontdoor_profile_id": {
Type: pluginsdk.TypeString,
Required: true,
ForceNew: true,
ValidateFunc: validate.FrontDoorProfileID,
},

"dns_zone_id": {
Type: pluginsdk.TypeString,
Optional: true,
ValidateFunc: dnsValidate.ValidateDnsZoneID,
},

"domain_validation_state": {
Type: pluginsdk.TypeString,
Computed: true,
},
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we don't expose the state fields since it's not something users are likely to be able to use here, what's the intention for this field?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This was a left over field from when I had the validators exposed, missed it when I removed them. Fixed.


"host_name": {
Type: pluginsdk.TypeString,
ForceNew: true,
Required: true,
},

"pre_validated_cdn_frontdoor_custom_domain_id": {
Type: pluginsdk.TypeString,
Optional: true,
ValidateFunc: validate.FrontDoorCustomDomainID,
},

"tls": {
Type: pluginsdk.TypeList,
Required: true,
MaxItems: 1,

Elem: &pluginsdk.Resource{
Schema: map[string]*pluginsdk.Schema{

"certificate_type": {
Type: pluginsdk.TypeString,
Optional: true,
Default: string(cdn.AfdCertificateTypeManagedCertificate),
ValidateFunc: validation.StringInSlice([]string{
string(cdn.AfdCertificateTypeCustomerCertificate),
string(cdn.AfdCertificateTypeManagedCertificate),
}, false),
},

"minimum_tls_version": {
Type: pluginsdk.TypeString,
Optional: true,
Default: string(cdn.AfdMinimumTLSVersionTLS12),
ValidateFunc: validation.StringInSlice([]string{
string(cdn.AfdMinimumTLSVersionTLS10),
string(cdn.AfdMinimumTLSVersionTLS12),
}, false),
},

"cdn_frontdoor_secret_id": {
Type: pluginsdk.TypeString,
Optional: true,
Computed: true,
ValidateFunc: validate.FrontDoorSecretID,
},
},
},
},

"expiration_date": {
Type: pluginsdk.TypeString,
Computed: true,
},

"validation_token": {
Type: pluginsdk.TypeString,
Computed: true,
},
},
}
}

func resourceCdnFrontDoorCustomDomainCreate(d *pluginsdk.ResourceData, meta interface{}) error {
client := meta.(*clients.Client).Cdn.FrontDoorCustomDomainsClient
ctx, cancel := timeouts.ForCreate(meta.(*clients.Client).StopContext, d)
defer cancel()

profileId, err := parse.FrontDoorProfileID(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))

if d.IsNewResource() {
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())
}
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is only a Create method so we can remove this since it'll always be true:

Suggested change
if d.IsNewResource() {
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())
}
}
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())
}

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed.


props := track1.AFDDomain{
AFDDomainProperties: &track1.AFDDomainProperties{
HostName: utils.String(d.Get("host_name").(string)),
AzureDNSZone: expandResourceReference(d.Get("dns_zone_id").(string)),
PreValidatedCustomDomainResourceID: expandResourceReference(d.Get("pre_validated_cdn_frontdoor_custom_domain_id").(string)),
TLSSettings: expandCdnFrontdoorCustomDomainHttpsParameters(d.Get("tls").([]interface{})),
},
}

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)
}

d.SetId(id.ID())
return resourceCdnFrontDoorCustomDomainRead(d, meta)
}

func resourceCdnFrontDoorCustomDomainRead(d *pluginsdk.ResourceData, meta interface{}) error {
client := meta.(*clients.Client).Cdn.FrontDoorCustomDomainsClient
ctx, cancel := timeouts.ForRead(meta.(*clients.Client).StopContext, d)
defer cancel()

id, err := parse.FrontdoorCustomDomainID(d.Id())
if err != nil {
return err
}

resp, err := client.Get(ctx, id.ResourceGroup, id.ProfileName, id.CustomDomainName)
if err != nil {
if utils.ResponseWasNotFound(resp.Response) {
d.SetId("")
return nil
}
return fmt.Errorf("retrieving %s: %+v", id, err)
}

d.Set("name", id.CustomDomainName)
d.Set("cdn_frontdoor_profile_id", parse.NewFrontDoorProfileID(id.SubscriptionId, id.ResourceGroup, id.ProfileName).ID())

if props := resp.AFDDomainProperties; props != nil {
d.Set("domain_validation_state", props.DomainValidationState)
d.Set("host_name", props.HostName)

if err := d.Set("dns_zone_id", flattenResourceReference(props.AzureDNSZone)); err != nil {
return fmt.Errorf("setting `dns_zone_id`: %+v", err)
}

if err := d.Set("pre_validated_cdn_frontdoor_custom_domain_id", flattenResourceReference(props.PreValidatedCustomDomainResourceID)); err != nil {
return fmt.Errorf("setting `pre_validated_cdn_frontdoor_custom_domain_id`: %+v", err)
}

if err := d.Set("tls", flattenCustomDomainAFDDomainHttpsParameters(props.TLSSettings)); err != nil {
return fmt.Errorf("setting `tls`: %+v", err)
}

if validationProps := props.ValidationProperties; validationProps != nil {
d.Set("expiration_date", validationProps.ExpirationDate)
d.Set("validation_token", validationProps.ValidationToken)
}
}

return nil
}

func resourceCdnFrontDoorCustomDomainUpdate(d *pluginsdk.ResourceData, meta interface{}) error {
client := meta.(*clients.Client).Cdn.FrontDoorCustomDomainsClient
ctx, cancel := timeouts.ForUpdate(meta.(*clients.Client).StopContext, d)
defer cancel()

id, err := parse.FrontdoorCustomDomainID(d.Id())
if err != nil {
return err
}

props := track1.AFDDomainUpdateParameters{
AFDDomainUpdatePropertiesParameters: &track1.AFDDomainUpdatePropertiesParameters{
AzureDNSZone: expandResourceReference(d.Get("dns_zone_id").(string)),
PreValidatedCustomDomainResourceID: expandResourceReference(d.Get("pre_validated_cdn_frontdoor_custom_domain_id").(string)),
TLSSettings: expandCdnFrontdoorCustomDomainHttpsParameters(d.Get("tls").([]interface{})),
},
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

since there's 3 of these and this is a separate update method, can we conditionally set these (using if d.HasChange("dns_zone_id") { .. } etc

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed.


future, err := client.Update(ctx, id.ResourceGroup, id.ProfileName, id.CustomDomainName, props)
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)
}

return resourceCdnFrontDoorCustomDomainRead(d, meta)
}

func resourceCdnFrontDoorCustomDomainDelete(d *pluginsdk.ResourceData, meta interface{}) error {
client := meta.(*clients.Client).Cdn.FrontDoorCustomDomainsClient
ctx, cancel := timeouts.ForDelete(meta.(*clients.Client).StopContext, d)
defer cancel()

id, err := parse.FrontdoorCustomDomainID(d.Id())
if err != nil {
return err
}

future, err := client.Delete(ctx, id.ResourceGroup, id.ProfileName, id.CustomDomainName)
if err != nil {
return fmt.Errorf("deleting %s: %+v", *id, err)
}

if err = future.WaitForCompletionRef(ctx, client.Client); err != nil {
return fmt.Errorf("waiting for the deletion of %s: %+v", *id, err)
}

return nil
}

func expandCdnFrontdoorCustomDomainHttpsParameters(input []interface{}) *track1.AFDDomainHTTPSParameters {
if len(input) == 0 || input[0] == nil {
// TODO: why is this returning nil and not an empty object?
// WS: Because with the Frontdoor service, they do not treat an empty object like an empty object
// if it is not nil they assume it is fully defined and then end up throwing errors when they attempt
// to get a value from one of the fields.
return nil
}

v := input[0].(map[string]interface{})

return &track1.AFDDomainHTTPSParameters{
CertificateType: track1.AfdCertificateType(v["certificate_type"].(string)),
MinimumTLSVersion: track1.AfdMinimumTLSVersion(v["minimum_tls_version"].(string)),
Secret: expandResourceReference(v["cdn_frontdoor_secret_id"].(string)),
}
}

func flattenCustomDomainAFDDomainHttpsParameters(input *track1.AFDDomainHTTPSParameters) []interface{} {
if input == nil {
return []interface{}{}
}

return []interface{}{
map[string]interface{}{
"cdn_frontdoor_secret_id": flattenResourceReference(input.Secret),
"certificate_type": string(input.CertificateType),
"minimum_tls_version": string(input.MinimumTLSVersion),
},
}
}
Loading