diff --git a/internal/services/dns/dns_zone_data_source.go b/internal/services/dns/dns_zone_data_source.go index df07f46d09a6..1e39342a3e87 100644 --- a/internal/services/dns/dns_zone_data_source.go +++ b/internal/services/dns/dns_zone_data_source.go @@ -8,118 +8,135 @@ import ( "fmt" "time" + "github.com/hashicorp/go-azure-helpers/lang/pointer" "github.com/hashicorp/go-azure-helpers/lang/response" "github.com/hashicorp/go-azure-helpers/resourcemanager/commonids" "github.com/hashicorp/go-azure-helpers/resourcemanager/commonschema" - "github.com/hashicorp/go-azure-helpers/resourcemanager/tags" "github.com/hashicorp/go-azure-sdk/resource-manager/dns/2018-05-01/zones" - "github.com/hashicorp/terraform-provider-azurerm/internal/clients" + "github.com/hashicorp/terraform-provider-azurerm/internal/sdk" "github.com/hashicorp/terraform-provider-azurerm/internal/tf/pluginsdk" - "github.com/hashicorp/terraform-provider-azurerm/internal/timeouts" ) -func dataSourceDnsZone() *pluginsdk.Resource { - return &pluginsdk.Resource{ - Read: dataSourceDnsZoneRead, +var _ sdk.DataSource = DnsZoneDataResource{} - Timeouts: &pluginsdk.ResourceTimeout{ - Read: pluginsdk.DefaultTimeout(5 * time.Minute), +type DnsZoneDataResource struct{} + +func (DnsZoneDataResource) ModelObject() interface{} { + return &DnsZoneDataResourceModel{} +} + +func (d DnsZoneDataResource) IDValidationFunc() pluginsdk.SchemaValidateFunc { + return zones.ValidateDnsZoneID +} + +func (DnsZoneDataResource) ResourceType() string { + return "azurerm_dns_zone" +} + +func (DnsZoneDataResource) Arguments() map[string]*pluginsdk.Schema { + return map[string]*pluginsdk.Schema{ + "name": { + Type: pluginsdk.TypeString, + Required: true, }, - Schema: map[string]*pluginsdk.Schema{ - "name": { - Type: pluginsdk.TypeString, - Required: true, - }, - - "resource_group_name": { - // TODO: we need a CommonSchema type for this which doesn't have ForceNew - Type: pluginsdk.TypeString, - Optional: true, - Computed: true, - }, - - "number_of_record_sets": { - Type: pluginsdk.TypeInt, - Computed: true, - }, - - "max_number_of_record_sets": { - Type: pluginsdk.TypeInt, - Computed: true, - }, - - "name_servers": { - Type: pluginsdk.TypeSet, - Computed: true, - Elem: &pluginsdk.Schema{Type: pluginsdk.TypeString}, - Set: pluginsdk.HashString, - }, - - "tags": commonschema.TagsDataSource(), + "resource_group_name": { + // TODO: we need a CommonSchema type for this which doesn't have ForceNew + Type: pluginsdk.TypeString, + Optional: true, + Computed: true, }, } } -func dataSourceDnsZoneRead(d *pluginsdk.ResourceData, meta interface{}) error { - client := meta.(*clients.Client).Dns.Zones - subscriptionId := meta.(*clients.Client).Account.SubscriptionId - ctx, cancel := timeouts.ForRead(meta.(*clients.Client).StopContext, d) - defer cancel() - - id := zones.NewDnsZoneID(subscriptionId, d.Get("resource_group_name").(string), d.Get("name").(string)) - var zone *zones.Zone - if id.ResourceGroupName != "" { - resp, err := client.Get(ctx, id) - if err != nil { - if response.WasNotFound(resp.HttpResponse) { - return fmt.Errorf("%s was not found", id) - } - return fmt.Errorf("retrieving %s: %+v", id, err) - } +func (DnsZoneDataResource) Attributes() map[string]*pluginsdk.Schema { + return map[string]*pluginsdk.Schema{ + "number_of_record_sets": { + Type: pluginsdk.TypeInt, + Computed: true, + }, - zone = resp.Model - } else { - result, resourceGroupName, err := findZone(ctx, client, id.SubscriptionId, id.DnsZoneName) - if err != nil { - return err - } + "max_number_of_record_sets": { + Type: pluginsdk.TypeInt, + Computed: true, + }, - if resourceGroupName == nil { - return fmt.Errorf("unable to locate the Resource Group for DNS Zone %q in Subscription %q", id.DnsZoneName, subscriptionId) - } + "name_servers": { + Type: pluginsdk.TypeSet, + Computed: true, + Elem: &pluginsdk.Schema{Type: pluginsdk.TypeString}, + Set: pluginsdk.HashString, + }, - zone = result - id.ResourceGroupName = *resourceGroupName + "tags": commonschema.TagsDataSource(), } +} - if zone == nil { - return fmt.Errorf("retrieving %s: `model` was nil", id) - } +type DnsZoneDataResourceModel struct { + Name string `tfschema:"name"` + ResourceGroupName string `tfschema:"resource_group_name"` + NumberOfRecordSets int64 `tfschema:"number_of_record_sets"` + MaxNumberOfRecordSets int64 `tfschema:"max_number_of_record_sets"` + NameServers []string `tfschema:"name_servers"` + Tags map[string]string `tfschema:"tags"` +} - d.SetId(id.ID()) +func (DnsZoneDataResource) Read() sdk.ResourceFunc { + return sdk.ResourceFunc{ + Timeout: 5 * time.Minute, + Func: func(ctx context.Context, metadata sdk.ResourceMetaData) error { + client := metadata.Client.Dns.Zones + subscriptionId := metadata.Client.Account.SubscriptionId - d.Set("name", id.DnsZoneName) - d.Set("resource_group_name", id.ResourceGroupName) + var state DnsZoneDataResourceModel + if err := metadata.Decode(&state); err != nil { + return fmt.Errorf("decoding: %+v", err) + } - if props := zone.Properties; props != nil { - d.Set("number_of_record_sets", props.NumberOfRecordSets) - d.Set("max_number_of_record_sets", props.MaxNumberOfRecordSets) + id := zones.NewDnsZoneID(subscriptionId, state.ResourceGroupName, state.Name) + var zone *zones.Zone + if id.ResourceGroupName != "" { + resp, err := client.Get(ctx, id) + if err != nil { + if response.WasNotFound(resp.HttpResponse) { + return fmt.Errorf("%s was not found", id) + } + return fmt.Errorf("retrieving %s: %+v", id, err) + } + + zone = resp.Model + } else { + result, resourceGroupName, err := findZone(ctx, client, id.SubscriptionId, id.DnsZoneName) + if err != nil { + return err + } + + if resourceGroupName == nil { + return fmt.Errorf("unable to locate the Resource Group for DNS Zone %q in Subscription %q", id.DnsZoneName, subscriptionId) + } + + zone = result + id.ResourceGroupName = pointer.From(resourceGroupName) + state.ResourceGroupName = pointer.From(resourceGroupName) + } - nameServers := make([]string, 0) - if ns := props.NameServers; ns != nil { - nameServers = *ns - } - if err := d.Set("name_servers", nameServers); err != nil { - return err - } - } + if zone == nil { + return fmt.Errorf("retrieving %s: `model` was nil", id) + } - if err := tags.FlattenAndSet(d, zone.Tags); err != nil { - return err - } + metadata.SetID(id) + + if props := zone.Properties; props != nil { + state.NumberOfRecordSets = pointer.From(props.NumberOfRecordSets) + state.MaxNumberOfRecordSets = pointer.From(props.MaxNumberOfRecordSets) + state.NameServers = pointer.From(props.NameServers) + } - return nil + state.Tags = pointer.From(zone.Tags) + + return metadata.Encode(&state) + }, + } } func findZone(ctx context.Context, client *zones.ZonesClient, subscriptionId, name string) (*zones.Zone, *string, error) { diff --git a/internal/services/dns/dns_zone_resource.go b/internal/services/dns/dns_zone_resource.go index e0a672a77e73..f85fd608c3e8 100644 --- a/internal/services/dns/dns_zone_resource.go +++ b/internal/services/dns/dns_zone_resource.go @@ -4,377 +4,364 @@ package dns import ( + "context" "fmt" "strings" "time" + "github.com/hashicorp/go-azure-helpers/lang/pointer" "github.com/hashicorp/go-azure-helpers/lang/response" "github.com/hashicorp/go-azure-helpers/resourcemanager/commonschema" "github.com/hashicorp/go-azure-helpers/resourcemanager/location" - "github.com/hashicorp/go-azure-helpers/resourcemanager/tags" "github.com/hashicorp/go-azure-sdk/resource-manager/dns/2018-05-01/recordsets" "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/sdk" "github.com/hashicorp/terraform-provider-azurerm/internal/services/dns/migration" "github.com/hashicorp/terraform-provider-azurerm/internal/services/dns/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 resourceDnsZone() *pluginsdk.Resource { - return &pluginsdk.Resource{ - Create: resourceDnsZoneCreateUpdate, - Read: resourceDnsZoneRead, - Update: resourceDnsZoneCreateUpdate, - Delete: resourceDnsZoneDelete, +var ( + _ sdk.Resource = DnsZoneResource{} + _ sdk.ResourceWithUpdate = DnsZoneResource{} + _ sdk.ResourceWithStateMigration = DnsZoneResource{} +) + +type DnsZoneResource struct{} + +func (DnsZoneResource) ModelObject() interface{} { + return &DnsZoneResourceModel{} +} + +func (DnsZoneResource) IDValidationFunc() pluginsdk.SchemaValidateFunc { + return zones.ValidateDnsZoneID +} + +func (DnsZoneResource) ResourceType() string { + return "azurerm_dns_zone" +} +func (r DnsZoneResource) StateUpgraders() sdk.StateUpgradeData { + return sdk.StateUpgradeData{ SchemaVersion: 2, - StateUpgraders: pluginsdk.StateUpgrades(map[int]pluginsdk.StateUpgrade{ + Upgraders: map[int]pluginsdk.StateUpgrade{ 0: migration.DnsZoneV0ToV1{}, 1: migration.DnsZoneV1ToV2{}, - }), + }, + } +} - 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), +func (DnsZoneResource) Arguments() map[string]*pluginsdk.Schema { + return map[string]*pluginsdk.Schema{ + "name": { + Type: pluginsdk.TypeString, + Required: true, + ForceNew: true, }, - Importer: pluginsdk.ImporterValidatingResourceId(func(id string) error { - _, err := zones.ParseDnsZoneID(id) - return err - }), - Schema: map[string]*pluginsdk.Schema{ - "name": { - Type: pluginsdk.TypeString, - Required: true, - ForceNew: true, - }, + "resource_group_name": commonschema.ResourceGroupName(), + + "soa_record": { + Type: pluginsdk.TypeList, + MaxItems: 1, + Optional: true, + Computed: true, + Elem: &pluginsdk.Resource{ + Schema: map[string]*pluginsdk.Schema{ + "email": { + Type: pluginsdk.TypeString, + Required: true, + ValidateFunc: validate.DnsZoneSOARecordEmail, + }, - "resource_group_name": commonschema.ResourceGroupName(), + "expire_time": { + Type: pluginsdk.TypeInt, + Optional: true, + Default: 2419200, + ValidateFunc: validation.IntAtLeast(0), + }, - "number_of_record_sets": { - Type: pluginsdk.TypeInt, - Computed: true, - }, + "minimum_ttl": { + Type: pluginsdk.TypeInt, + Optional: true, + Default: 300, + ValidateFunc: validation.IntAtLeast(0), + }, - "max_number_of_record_sets": { - Type: pluginsdk.TypeInt, - Computed: true, - }, + "refresh_time": { + Type: pluginsdk.TypeInt, + Optional: true, + Default: 3600, + ValidateFunc: validation.IntAtLeast(0), + }, - "name_servers": { - Type: pluginsdk.TypeSet, - Computed: true, - Elem: &pluginsdk.Schema{Type: pluginsdk.TypeString}, - Set: pluginsdk.HashString, - }, + "retry_time": { + Type: pluginsdk.TypeInt, + Optional: true, + Default: 300, + ValidateFunc: validation.IntAtLeast(0), + }, + + "serial_number": { + Type: pluginsdk.TypeInt, + Optional: true, + Default: 1, + ValidateFunc: validation.IntAtLeast(0), + }, + + "ttl": { + Type: pluginsdk.TypeInt, + Optional: true, + Default: 3600, + ValidateFunc: validation.IntBetween(0, 2147483647), + }, + + "tags": commonschema.Tags(), + + "fqdn": { + Type: pluginsdk.TypeString, + Computed: true, + }, - "soa_record": { - Type: pluginsdk.TypeList, - MaxItems: 1, - Optional: true, - Computed: true, - Elem: &pluginsdk.Resource{ - Schema: map[string]*pluginsdk.Schema{ - "email": { - Type: pluginsdk.TypeString, - Required: true, - ValidateFunc: validate.DnsZoneSOARecordEmail, - }, - - "expire_time": { - Type: pluginsdk.TypeInt, - Optional: true, - Default: 2419200, - ValidateFunc: validation.IntAtLeast(0), - }, - - "minimum_ttl": { - Type: pluginsdk.TypeInt, - Optional: true, - Default: 300, - ValidateFunc: validation.IntAtLeast(0), - }, - - "refresh_time": { - Type: pluginsdk.TypeInt, - Optional: true, - Default: 3600, - ValidateFunc: validation.IntAtLeast(0), - }, - - "retry_time": { - Type: pluginsdk.TypeInt, - Optional: true, - Default: 300, - ValidateFunc: validation.IntAtLeast(0), - }, - - "serial_number": { - Type: pluginsdk.TypeInt, - Optional: true, - Default: 1, - ValidateFunc: validation.IntAtLeast(0), - }, - - "ttl": { - Type: pluginsdk.TypeInt, - Optional: true, - Default: 3600, - ValidateFunc: validation.IntBetween(0, 2147483647), - }, - - "tags": commonschema.Tags(), - - "fqdn": { - Type: pluginsdk.TypeString, - Computed: true, - }, - - "host_name": { - Type: pluginsdk.TypeString, - Computed: true, // (@jackofallops) - This should not be set or updatable to meet API design, see https://learn.microsoft.com/en-us/azure/dns/dns-zones-records#soa-records - }, + "host_name": { + Type: pluginsdk.TypeString, + Computed: true, // (@jackofallops) - This should not be set or updatable to meet API design, see https://learn.microsoft.com/en-us/azure/dns/dns-zones-records#soa-records }, }, }, - - "tags": commonschema.Tags(), }, + + "tags": commonschema.Tags(), } } -func resourceDnsZoneCreateUpdate(d *pluginsdk.ResourceData, meta interface{}) error { - client := meta.(*clients.Client).Dns.Zones - recordSetsClient := meta.(*clients.Client).Dns.RecordSets - subscriptionId := meta.(*clients.Client).Account.SubscriptionId - ctx, cancel := timeouts.ForCreateUpdate(meta.(*clients.Client).StopContext, d) - defer cancel() - - id := zones.NewDnsZoneID(subscriptionId, d.Get("resource_group_name").(string), d.Get("name").(string)) - if d.IsNewResource() { - existing, err := client.Get(ctx, id) - if err != nil { - if !response.WasNotFound(existing.HttpResponse) { - return fmt.Errorf("checking for presence of existing %s: %+v", id, err) - } - } +func (DnsZoneResource) Attributes() map[string]*pluginsdk.Schema { + return map[string]*pluginsdk.Schema{ + "number_of_record_sets": { + Type: pluginsdk.TypeInt, + Computed: true, + }, - if !response.WasNotFound(existing.HttpResponse) { - return tf.ImportAsExistsError("azurerm_dns_zone", id.ID()) - } + "max_number_of_record_sets": { + Type: pluginsdk.TypeInt, + Computed: true, + }, + + "name_servers": { + Type: pluginsdk.TypeSet, + Computed: true, + Elem: &pluginsdk.Schema{Type: pluginsdk.TypeString}, + Set: pluginsdk.HashString, + }, } +} - t := d.Get("tags").(map[string]interface{}) +type DnsZoneResourceModel struct { + Name string `tfschema:"name"` + ResourceGroupName string `tfschema:"resource_group_name"` + NumberOfRecordSets int64 `tfschema:"number_of_record_sets"` + MaxNumberOfRecordSets int64 `tfschema:"max_number_of_record_sets"` + NameServers []string `tfschema:"name_servers"` + SoaRecord []DnsZoneSoaRecordResourceRecord `tfschema:"soa_record"` + Tags map[string]string `tfschema:"tags"` +} - parameters := zones.Zone{ - Location: location.Normalize("global"), - Tags: tags.Expand(t), - } +type DnsZoneSoaRecordResourceRecord struct { + Email string `tfschema:"email"` + ExpireTime int64 `tfschema:"expire_time"` + MinimumTtl int64 `tfschema:"minimum_ttl"` + RefreshTime int64 `tfschema:"refresh_time"` + RetryTime int64 `tfschema:"retry_time"` + SerialNumber int64 `tfschema:"serial_number"` + Ttl int64 `tfschema:"ttl"` + Fqdn string `tfschema:"fqdn"` + HostName string `tfschema:"host_name"` + Tags map[string]string `tfschema:"tags"` +} - if _, err := client.CreateOrUpdate(ctx, id, parameters, zones.DefaultCreateOrUpdateOperationOptions()); err != nil { - return fmt.Errorf("creating/updating %s: %+v", id, err) - } +func (r DnsZoneResource) Create() sdk.ResourceFunc { + return sdk.ResourceFunc{ + Timeout: 30 * time.Minute, + Func: func(ctx context.Context, metadata sdk.ResourceMetaData) error { + client := metadata.Client.Dns.Zones + recordSetsClient := metadata.Client.Dns.RecordSets + subscriptionId := metadata.Client.Account.SubscriptionId + + var model DnsZoneResourceModel + if err := metadata.Decode(&model); err != nil { + return fmt.Errorf("decoding: %+v", err) + } - if v, ok := d.GetOk("soa_record"); ok { - soaRecord := v.([]interface{})[0].(map[string]interface{}) + id := zones.NewDnsZoneID(subscriptionId, model.ResourceGroupName, model.Name) + if metadata.ResourceData.IsNewResource() { + existing, err := client.Get(ctx, id) + if err != nil { + if !response.WasNotFound(existing.HttpResponse) { + return fmt.Errorf("checking for presence of existing %s: %+v", id, err) + } + } - soaRecordID := recordsets.NewRecordTypeID(id.SubscriptionId, id.ResourceGroupName, id.DnsZoneName, recordsets.RecordTypeSOA, "@") - soaRecordResp, err := recordSetsClient.Get(ctx, soaRecordID) - if err != nil { - return fmt.Errorf("retrieving %s to update SOA: %+v", id, err) - } + if !response.WasNotFound(existing.HttpResponse) { + return metadata.ResourceRequiresImport(r.ResourceType(), id) + } + } - props := soaRecordResp.Model.Properties - if props == nil || props.SOARecord == nil { - return fmt.Errorf("could not read SOA properties for %s", id) - } + parameters := zones.Zone{ + Location: location.Normalize("global"), + Tags: pointer.To(model.Tags), + } - inputSOARecord := expandArmDNSZoneSOARecord(soaRecord) + if _, err := client.CreateOrUpdate(ctx, id, parameters, zones.DefaultCreateOrUpdateOperationOptions()); err != nil { + return fmt.Errorf("creating/updating %s: %+v", id, err) + } - inputSOARecord.Host = props.SOARecord.Host + if len(model.SoaRecord) == 1 { + soaRecordID := recordsets.NewRecordTypeID(id.SubscriptionId, id.ResourceGroupName, id.DnsZoneName, recordsets.RecordTypeSOA, "@") + soaRecordResp, err := recordSetsClient.Get(ctx, soaRecordID) + if err != nil { + return fmt.Errorf("retrieving %s to update SOA: %+v", id, err) + } - rsParameters := recordsets.RecordSet{ - Properties: &recordsets.RecordSetProperties{ - TTL: utils.Int64(int64(soaRecord["ttl"].(int))), - Metadata: tags.Expand(soaRecord["tags"].(map[string]interface{})), - SOARecord: inputSOARecord, - }, - } + props := soaRecordResp.Model.Properties + if props == nil || props.SOARecord == nil { + return fmt.Errorf("could not read SOA properties for %s", id) + } - if len(id.DnsZoneName+strings.TrimSuffix(*rsParameters.Properties.SOARecord.Email, ".")) > 253 { - return fmt.Errorf("`email` which is concatenated with DNS Zone `name` cannot exceed 253 characters excluding a trailing period") - } + inputSOARecord := expandDNSZoneSOARecord(model.SoaRecord[0]) - soaRecordId := recordsets.NewRecordTypeID(id.SubscriptionId, id.ResourceGroupName, id.DnsZoneName, recordsets.RecordTypeSOA, "@") - if _, err := recordSetsClient.CreateOrUpdate(ctx, soaRecordId, rsParameters, recordsets.DefaultCreateOrUpdateOperationOptions()); err != nil { - return fmt.Errorf("creating/updating %s: %+v", soaRecordId, err) - } - } + inputSOARecord.Host = props.SOARecord.Host - d.SetId(id.ID()) + rsParameters := recordsets.RecordSet{ + Properties: &recordsets.RecordSetProperties{ + TTL: pointer.To(model.SoaRecord[0].Ttl), + Metadata: pointer.To(model.SoaRecord[0].Tags), + SOARecord: inputSOARecord, + }, + } - return resourceDnsZoneRead(d, meta) -} + if len(id.DnsZoneName+strings.TrimSuffix(*rsParameters.Properties.SOARecord.Email, ".")) > 253 { + return fmt.Errorf("`email` which is concatenated with DNS Zone `name` cannot exceed 253 characters excluding a trailing period") + } -func resourceDnsZoneRead(d *pluginsdk.ResourceData, meta interface{}) error { - zonesClient := meta.(*clients.Client).Dns.Zones - recordSetsClient := meta.(*clients.Client).Dns.RecordSets - ctx, cancel := timeouts.ForRead(meta.(*clients.Client).StopContext, d) - defer cancel() + soaRecordId := recordsets.NewRecordTypeID(id.SubscriptionId, id.ResourceGroupName, id.DnsZoneName, recordsets.RecordTypeSOA, "@") + if _, err := recordSetsClient.CreateOrUpdate(ctx, soaRecordId, rsParameters, recordsets.DefaultCreateOrUpdateOperationOptions()); err != nil { + return fmt.Errorf("creating/updating %s: %+v", soaRecordId, err) + } + } - id, err := zones.ParseDnsZoneID(d.Id()) - if err != nil { - return err - } + metadata.SetID(id) - resp, err := zonesClient.Get(ctx, *id) - if err != nil { - if response.WasNotFound(resp.HttpResponse) { - d.SetId("") return nil - } - return fmt.Errorf("retrieving %s: %+v", *id, err) + }, } +} - soaRecord := recordsets.NewRecordTypeID(id.SubscriptionId, id.ResourceGroupName, id.DnsZoneName, recordsets.RecordTypeSOA, "@") - soaRecordResp, err := recordSetsClient.Get(ctx, soaRecord) - if err != nil { - return fmt.Errorf("retrieving %s: %+v", id, err) - } +func (DnsZoneResource) Read() sdk.ResourceFunc { + return sdk.ResourceFunc{ + Timeout: 5 * time.Minute, + Func: func(ctx context.Context, metadata sdk.ResourceMetaData) error { + zonesClient := metadata.Client.Dns.Zones + recordSetsClient := metadata.Client.Dns.RecordSets - if err := d.Set("soa_record", flattenArmDNSZoneSOARecord(soaRecordResp.Model)); err != nil { - return fmt.Errorf("setting `soa_record`: %+v", err) - } + state := DnsZoneResourceModel{} - d.Set("name", id.DnsZoneName) - d.Set("resource_group_name", id.ResourceGroupName) + id, err := zones.ParseDnsZoneID(metadata.ResourceData.Id()) + if err != nil { + return err + } - if model := resp.Model; model != nil { - if props := model.Properties; props != nil { - d.Set("number_of_record_sets", props.NumberOfRecordSets) - d.Set("max_number_of_record_sets", props.MaxNumberOfRecordSets) + resp, err := zonesClient.Get(ctx, *id) + if err != nil { + if response.WasNotFound(resp.HttpResponse) { + return metadata.MarkAsGone(id) + } + return fmt.Errorf("retrieving %s: %+v", *id, err) + } - nameServers := make([]string, 0) - if s := props.NameServers; s != nil { - nameServers = *s + soaRecord := recordsets.NewRecordTypeID(id.SubscriptionId, id.ResourceGroupName, id.DnsZoneName, recordsets.RecordTypeSOA, "@") + soaRecordResp, err := recordSetsClient.Get(ctx, soaRecord) + if err != nil { + return fmt.Errorf("retrieving %s: %+v", id, err) } - if err := d.Set("name_servers", nameServers); err != nil { - return err + + state.SoaRecord = flattenDNSZoneSOARecord(soaRecordResp.Model) + + state.Name = id.DnsZoneName + state.ResourceGroupName = id.ResourceGroupName + + if model := resp.Model; model != nil { + if props := model.Properties; props != nil { + state.NumberOfRecordSets = pointer.From(props.NumberOfRecordSets) + state.MaxNumberOfRecordSets = pointer.From(props.MaxNumberOfRecordSets) + state.NameServers = pointer.From(props.NameServers) + } + state.Tags = pointer.From(model.Tags) } - } - if err := tags.FlattenAndSet(d, model.Tags); err != nil { - return err - } + return metadata.Encode(&state) + }, } +} - return nil +func (r DnsZoneResource) Update() sdk.ResourceFunc { + return r.Create() } -func resourceDnsZoneDelete(d *pluginsdk.ResourceData, meta interface{}) error { - client := meta.(*clients.Client).Dns.Zones - ctx, cancel := timeouts.ForDelete(meta.(*clients.Client).StopContext, d) - defer cancel() +func (r DnsZoneResource) Delete() sdk.ResourceFunc { + return sdk.ResourceFunc{ + Timeout: 30 * time.Minute, + Func: func(ctx context.Context, metadata sdk.ResourceMetaData) error { + client := metadata.Client.Dns.Zones - id, err := zones.ParseDnsZoneID(d.Id()) - if err != nil { - return err - } + id, err := zones.ParseDnsZoneID(metadata.ResourceData.Id()) + if err != nil { + return err + } - if err := client.DeleteThenPoll(ctx, *id, zones.DefaultDeleteOperationOptions()); err != nil { - return fmt.Errorf("deleting %s: %+v", *id, err) - } + if err := client.DeleteThenPoll(ctx, *id, zones.DefaultDeleteOperationOptions()); err != nil { + return fmt.Errorf("deleting %s: %+v", *id, err) + } - return nil + return nil + }, + } } -func expandArmDNSZoneSOARecord(input map[string]interface{}) *recordsets.SoaRecord { +func expandDNSZoneSOARecord(input DnsZoneSoaRecordResourceRecord) *recordsets.SoaRecord { result := &recordsets.SoaRecord{ - Email: utils.String(input["email"].(string)), - ExpireTime: utils.Int64(int64(input["expire_time"].(int))), - MinimumTTL: utils.Int64(int64(input["minimum_ttl"].(int))), - RefreshTime: utils.Int64(int64(input["refresh_time"].(int))), - RetryTime: utils.Int64(int64(input["retry_time"].(int))), - SerialNumber: utils.Int64(int64(input["serial_number"].(int))), + Email: pointer.To(input.Email), + ExpireTime: pointer.To(input.ExpireTime), + MinimumTTL: pointer.To(input.MinimumTtl), + RefreshTime: pointer.To(input.RefreshTime), + RetryTime: pointer.To(input.RetryTime), + SerialNumber: pointer.To(input.SerialNumber), } return result } -func flattenArmDNSZoneSOARecord(input *recordsets.RecordSet) []interface{} { - output := make([]interface{}, 0) +func flattenDNSZoneSOARecord(input *recordsets.RecordSet) []DnsZoneSoaRecordResourceRecord { + output := make([]DnsZoneSoaRecordResourceRecord, 0) if input != nil { if props := input.Properties; props != nil { - ttl := 0 - if props.TTL != nil { - ttl = int(*props.TTL) - } - - metaData := make(map[string]interface{}) - if props.Metadata != nil { - metaData = tags.Flatten(props.Metadata) - } - - fqdn := "" - if props.Fqdn != nil { - fqdn = *props.Fqdn + result := DnsZoneSoaRecordResourceRecord{ + Ttl: pointer.From(props.TTL), + Tags: pointer.From(props.Metadata), + Fqdn: pointer.From(props.Fqdn), } - email := "" - hostName := "" - expireTime := 0 - minimumTTL := 0 - refreshTime := 0 - retryTime := 0 - serialNumber := 0 if record := props.SOARecord; record != nil { - if record.Email != nil { - email = *record.Email - } - - if record.Host != nil { - hostName = *record.Host - } - - if record.ExpireTime != nil { - expireTime = int(*record.ExpireTime) - } - - if record.MinimumTTL != nil { - minimumTTL = int(*record.MinimumTTL) - } - - if record.RefreshTime != nil { - refreshTime = int(*record.RefreshTime) - } - - if record.RetryTime != nil { - retryTime = int(*record.RetryTime) - } - - if record.SerialNumber != nil { - serialNumber = int(*record.SerialNumber) - } + result.Email = pointer.From(record.Email) + result.HostName = pointer.From(record.Host) + result.ExpireTime = pointer.From(record.ExpireTime) + result.MinimumTtl = pointer.From(record.MinimumTTL) + result.RefreshTime = pointer.From(record.RefreshTime) + result.RetryTime = pointer.From(record.RetryTime) + result.SerialNumber = pointer.From(record.SerialNumber) } - output = append(output, map[string]interface{}{ - "email": email, - "host_name": hostName, - "expire_time": expireTime, - "minimum_ttl": minimumTTL, - "refresh_time": refreshTime, - "retry_time": retryTime, - "serial_number": serialNumber, - "ttl": ttl, - "tags": metaData, - "fqdn": fqdn, - }) + output = append(output, result) } } diff --git a/internal/services/dns/registration.go b/internal/services/dns/registration.go index 6716712ba7f2..71ffffb1b2be 100644 --- a/internal/services/dns/registration.go +++ b/internal/services/dns/registration.go @@ -44,7 +44,6 @@ func (r Registration) SupportedDataSources() map[string]*pluginsdk.Resource { "azurerm_dns_soa_record": dataSourceDnsSoaRecord(), "azurerm_dns_srv_record": dataSourceDnsSrvRecord(), "azurerm_dns_txt_record": dataSourceDnsTxtRecord(), - "azurerm_dns_zone": dataSourceDnsZone(), } } @@ -60,16 +59,19 @@ func (r Registration) SupportedResources() map[string]*pluginsdk.Resource { "azurerm_dns_ptr_record": resourceDnsPtrRecord(), "azurerm_dns_srv_record": resourceDnsSrvRecord(), "azurerm_dns_txt_record": resourceDnsTxtRecord(), - "azurerm_dns_zone": resourceDnsZone(), } } // DataSources returns a list of Data Sources supported by this Service func (r Registration) DataSources() []sdk.DataSource { - return []sdk.DataSource{} + return []sdk.DataSource{ + DnsZoneDataResource{}, + } } // Resources returns a list of Resources supported by this Service func (r Registration) Resources() []sdk.Resource { - return []sdk.Resource{} + return []sdk.Resource{ + DnsZoneResource{}, + } }