diff --git a/internal/services/dns/dns_ds_record_data_source.go b/internal/services/dns/dns_ds_record_data_source.go new file mode 100644 index 000000000000..403495417384 --- /dev/null +++ b/internal/services/dns/dns_ds_record_data_source.go @@ -0,0 +1,119 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +package dns + +import ( + "fmt" + "time" + + "github.com/hashicorp/go-azure-helpers/lang/response" + "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/2023-07-01-preview/recordsets" + "github.com/hashicorp/terraform-provider-azurerm/internal/clients" + "github.com/hashicorp/terraform-provider-azurerm/internal/tf/pluginsdk" + "github.com/hashicorp/terraform-provider-azurerm/internal/timeouts" +) + +func dataSourceDnsDSRecord() *pluginsdk.Resource { + return &pluginsdk.Resource{ + Read: dataSourceDnsDSRecordRead, + + Timeouts: &pluginsdk.ResourceTimeout{ + Read: pluginsdk.DefaultTimeout(5 * time.Minute), + }, + + Schema: map[string]*pluginsdk.Schema{ + "name": { + Type: pluginsdk.TypeString, + Required: true, + }, + + "resource_group_name": commonschema.ResourceGroupNameForDataSource(), + + "zone_name": { + Type: pluginsdk.TypeString, + Required: true, + }, + + "record": { + Type: pluginsdk.TypeSet, + Computed: true, + Elem: &pluginsdk.Resource{ + Schema: map[string]*pluginsdk.Schema{ + "algorithm": { + Type: pluginsdk.TypeInt, + Computed: true, + }, + + "key_tag": { + Type: pluginsdk.TypeInt, + Computed: true, + }, + + "digest_type": { + Type: pluginsdk.TypeInt, + Computed: true, + }, + + "digest_value": { + Type: pluginsdk.TypeString, + Computed: true, + }, + }, + }, + Set: resourceDnsDSRecordHash, + }, + + "ttl": { + Type: pluginsdk.TypeInt, + Computed: true, + }, + + "fqdn": { + Type: pluginsdk.TypeString, + Computed: true, + }, + + "tags": commonschema.TagsDataSource(), + }, + } +} + +func dataSourceDnsDSRecordRead(d *pluginsdk.ResourceData, meta interface{}) error { + recordSetsClient := meta.(*clients.Client).Dns.RecordSets + ctx, cancel := timeouts.ForRead(meta.(*clients.Client).StopContext, d) + defer cancel() + subscriptionId := meta.(*clients.Client).Account.SubscriptionId + + id := recordsets.NewRecordTypeID(subscriptionId, d.Get("resource_group_name").(string), d.Get("zone_name").(string), recordsets.RecordTypeDS, d.Get("name").(string)) + resp, err := recordSetsClient.Get(ctx, id) + if err != nil { + if response.WasNotFound(resp.HttpResponse) { + return fmt.Errorf("%s was not found", id) + } + return fmt.Errorf("reading %s: %+v", id, err) + } + + d.SetId(id.ID()) + + d.Set("name", id.RelativeRecordSetName) + d.Set("resource_group_name", id.ResourceGroupName) + d.Set("zone_name", id.DnsZoneName) + + if model := resp.Model; model != nil { + if props := model.Properties; props != nil { + d.Set("ttl", props.TTL) + d.Set("fqdn", props.Fqdn) + + if err := d.Set("record", flattenAzureRmDnsDSRecords(props.DSRecords)); err != nil { + return err + } + + return tags.FlattenAndSet(d, props.Metadata) + } + } + + return nil +} diff --git a/internal/services/dns/dns_ds_record_resource.go b/internal/services/dns/dns_ds_record_resource.go new file mode 100644 index 000000000000..52225ff9390d --- /dev/null +++ b/internal/services/dns/dns_ds_record_resource.go @@ -0,0 +1,328 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +package dns + +import ( + "bytes" + "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/commonschema" + "github.com/hashicorp/go-azure-helpers/resourcemanager/tags" + "github.com/hashicorp/go-azure-sdk/resource-manager/dns/2023-07-01-preview/recordsets" + "github.com/hashicorp/terraform-provider-azurerm/helpers/tf" + "github.com/hashicorp/terraform-provider-azurerm/internal/clients" + "github.com/hashicorp/terraform-provider-azurerm/internal/tf/pluginsdk" + "github.com/hashicorp/terraform-provider-azurerm/internal/timeouts" +) + +func resourceDnsDSRecord() *pluginsdk.Resource { + return &pluginsdk.Resource{ + Create: resourceDnsDSRecordCreate, + Read: resourceDnsDSRecordRead, + Update: resourceDnsDSRecordUpdate, + Delete: resourceDnsDSRecordDelete, + + 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 { + parsed, err := recordsets.ParseRecordTypeID(id) + if err != nil { + return err + } + if parsed.RecordType != recordsets.RecordTypeDS { + return fmt.Errorf("this resource only supports 'DS' records") + } + return nil + }), + + Schema: map[string]*pluginsdk.Schema{ + "name": { + Type: pluginsdk.TypeString, + Required: true, + ForceNew: true, + }, + + "resource_group_name": commonschema.ResourceGroupName(), + + "zone_name": { + Type: pluginsdk.TypeString, + Required: true, + ForceNew: true, + }, + + "record": { + Type: pluginsdk.TypeSet, + Required: true, + Elem: &pluginsdk.Resource{ + Schema: map[string]*pluginsdk.Schema{ + "algorithm": { + Type: pluginsdk.TypeInt, + Required: true, + }, + + "key_tag": { + Type: pluginsdk.TypeInt, + Required: true, + }, + + "digest_type": { + Type: pluginsdk.TypeInt, + Required: true, + }, + + "digest_value": { + Type: pluginsdk.TypeString, + Required: true, + }, + }, + }, + Set: resourceDnsDSRecordHash, + }, + + "ttl": { + Type: pluginsdk.TypeInt, + Required: true, + }, + + "fqdn": { + Type: pluginsdk.TypeString, + Computed: true, + }, + + "tags": commonschema.Tags(), + }, + } +} + +func resourceDnsDSRecordCreate(d *pluginsdk.ResourceData, meta interface{}) error { + client := meta.(*clients.Client).Dns.RecordSets + ctx, cancel := timeouts.ForCreate(meta.(*clients.Client).StopContext, d) + subscriptionId := meta.(*clients.Client).Account.SubscriptionId + defer cancel() + + name := d.Get("name").(string) + resGroup := d.Get("resource_group_name").(string) + zoneName := d.Get("zone_name").(string) + + id := recordsets.NewRecordTypeID(subscriptionId, resGroup, zoneName, recordsets.RecordTypeDS, name) + + 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) + } + } + + if !response.WasNotFound(existing.HttpResponse) { + return tf.ImportAsExistsError("azurerm_dns_ds_record", id.ID()) + } + + ttl := int64(d.Get("ttl").(int)) + t := d.Get("tags").(map[string]interface{}) + + parameters := recordsets.RecordSet{ + Name: &name, + Properties: &recordsets.RecordSetProperties{ + Metadata: tags.Expand(t), + TTL: pointer.To(ttl), + DSRecords: expandAzureRmDnsDSRecords(d), + }, + } + + if _, err := client.CreateOrUpdate(ctx, id, parameters, recordsets.DefaultCreateOrUpdateOperationOptions()); err != nil { + return fmt.Errorf("creating %s: %+v", id, err) + } + + d.SetId(id.ID()) + + return resourceDnsDSRecordRead(d, meta) +} + +func resourceDnsDSRecordRead(d *pluginsdk.ResourceData, meta interface{}) error { + client := meta.(*clients.Client).Dns.RecordSets + ctx, cancel := timeouts.ForRead(meta.(*clients.Client).StopContext, d) + defer cancel() + + id, err := recordsets.ParseRecordTypeID(d.Id()) + if err != nil { + return err + } + + resp, err := client.Get(ctx, *id) + if err != nil { + if response.WasNotFound(resp.HttpResponse) { + d.SetId("") + return nil + } + + return fmt.Errorf("retrieving %s: %+v", *id, err) + } + + d.Set("name", id.RelativeRecordSetName) + d.Set("resource_group_name", id.ResourceGroupName) + d.Set("zone_name", id.DnsZoneName) + + if model := resp.Model; model != nil { + if props := model.Properties; props != nil { + d.Set("ttl", props.TTL) + d.Set("fqdn", props.Fqdn) + + if err := d.Set("record", flattenAzureRmDnsDSRecords(props.DSRecords)); err != nil { + return err + } + if err := tags.FlattenAndSet(d, props.Metadata); err != nil { + return err + } + } + } + + return nil +} + +func resourceDnsDSRecordUpdate(d *pluginsdk.ResourceData, meta interface{}) error { + client := meta.(*clients.Client).Dns.RecordSets + ctx, cancel := timeouts.ForUpdate(meta.(*clients.Client).StopContext, d) + defer cancel() + + id, err := recordsets.ParseRecordTypeID(d.Id()) + if err != nil { + return err + } + + existing, err := client.Get(ctx, *id) + if err != nil { + return fmt.Errorf("retrieving %s: %+v", *id, err) + } + + if existing.Model == nil { + return fmt.Errorf("retrieving %s: `model` was nil", id) + } + + if existing.Model.Properties == nil { + return fmt.Errorf("retrieving %s: `properties` was nil", id) + } + + payload := *existing.Model + + if d.HasChange("record") { + payload.Properties.DSRecords = expandAzureRmDnsDSRecords(d) + } + + if d.HasChange("ttl") { + payload.Properties.TTL = pointer.To(int64(d.Get("ttl").(int))) + } + + if d.HasChange("tags") { + payload.Properties.Metadata = tags.Expand(d.Get("tags").(map[string]interface{})) + } + + if _, err := client.CreateOrUpdate(ctx, *id, payload, recordsets.DefaultCreateOrUpdateOperationOptions()); err != nil { + return fmt.Errorf("updating %s: %+v", id, err) + } + + d.SetId(id.ID()) + + return resourceDnsSrvRecordRead(d, meta) +} + +func resourceDnsDSRecordDelete(d *pluginsdk.ResourceData, meta interface{}) error { + client := meta.(*clients.Client).Dns.RecordSets + ctx, cancel := timeouts.ForDelete(meta.(*clients.Client).StopContext, d) + defer cancel() + + id, err := recordsets.ParseRecordTypeID(d.Id()) + if err != nil { + return err + } + + if _, err := client.Delete(ctx, *id, recordsets.DefaultDeleteOperationOptions()); err != nil { + return fmt.Errorf("deleting %s: %+v", *id, err) + } + + return nil +} + +func flattenAzureRmDnsDSRecords(records *[]recordsets.DsRecord) []map[string]interface{} { + results := make([]map[string]interface{}, 0) + + if records != nil { + for _, record := range *records { + algorithm := int64(0) + if record.Algorithm != nil { + algorithm = *record.Algorithm + } + + keyTag := int64(0) + if record.KeyTag != nil { + keyTag = *record.KeyTag + } + + digestType := int64(0) + digestValue := "" + if record.Digest != nil { + if record.Digest.AlgorithmType != nil { + digestType = *record.Digest.AlgorithmType + } + + if record.Digest.Value != nil { + digestValue = *record.Digest.Value + } + } + + results = append(results, map[string]interface{}{ + "algorithm": algorithm, + "key_tag": keyTag, + "digest_type": digestType, + "digest_value": digestValue, + }) + } + } + + return results +} + +func expandAzureRmDnsDSRecords(d *pluginsdk.ResourceData) *[]recordsets.DsRecord { + recordStrings := d.Get("record").(*pluginsdk.Set).List() + records := make([]recordsets.DsRecord, 0) + + for _, v := range recordStrings { + record := v.(map[string]interface{}) + algorithm := int64(record["algorithm"].(int)) + keyTag := int64(record["key_tag"].(int)) + digestType := int64(record["digest_type"].(int)) + digestValue := record["digest_value"].(string) + + records = append(records, recordsets.DsRecord{ + Algorithm: &algorithm, + KeyTag: &keyTag, + Digest: &recordsets.Digest{ + AlgorithmType: &digestType, + Value: &digestValue, + }, + }) + } + + return &records +} + +func resourceDnsDSRecordHash(v interface{}) int { + var buf bytes.Buffer + + if m, ok := v.(map[string]interface{}); ok { + buf.WriteString(fmt.Sprintf("%d-", m["algorithm"].(int))) + buf.WriteString(fmt.Sprintf("%d-", m["key_tag"].(int))) + buf.WriteString(fmt.Sprintf("%d-", m["digest_type"].(int))) + buf.WriteString(fmt.Sprintf("%s-", m["digest_value"].(string))) + } + + return pluginsdk.HashString(buf.String()) +} diff --git a/internal/services/dns/dns_ds_record_resource_test.go b/internal/services/dns/dns_ds_record_resource_test.go new file mode 100644 index 000000000000..2de00495bd08 --- /dev/null +++ b/internal/services/dns/dns_ds_record_resource_test.go @@ -0,0 +1,311 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +package dns_test + +import ( + "context" + "fmt" + "testing" + + "github.com/hashicorp/go-azure-sdk/resource-manager/dns/2023-07-01-preview/recordsets" + "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/tf/pluginsdk" + "github.com/hashicorp/terraform-provider-azurerm/utils" +) + +type DnsDSRecordResource struct{} + +func TestAccDnsDSRecord_basic(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_dns_ds_record", "test") + r := DnsDSRecordResource{} + + data.ResourceTest(t, r, []acceptance.TestStep{ + { + Config: r.basic(data), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + check.That(data.ResourceName).Key("fqdn").Exists(), + ), + }, + data.ImportStep(), + }) +} + +func TestAccDnsDSRecord_requiresImport(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_dns_ds_record", "test") + r := DnsDSRecordResource{} + + data.ResourceTest(t, r, []acceptance.TestStep{ + { + Config: r.basic(data), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + ), + }, + { + Config: r.requiresImport(data), + ExpectError: acceptance.RequiresImportError("azurerm_dns_ds_record"), + }, + }) +} + +func TestAccDnsDSRecord_updateRecords(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_dns_ds_record", "test") + r := DnsDSRecordResource{} + + data.ResourceTest(t, r, []acceptance.TestStep{ + { + Config: r.basic(data), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + check.That(data.ResourceName).Key("record.#").HasValue("2"), + ), + }, + { + Config: r.updateRecords(data), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + check.That(data.ResourceName).Key("record.#").HasValue("3"), + ), + }, + }) +} + +func TestAccDnsDSRecord_withTags(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_dns_ds_record", "test") + r := DnsDSRecordResource{} + + data.ResourceTest(t, r, []acceptance.TestStep{ + { + Config: r.withTags(data), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + check.That(data.ResourceName).Key("tags.%").HasValue("2"), + ), + }, + { + Config: r.withTagsUpdate(data), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + check.That(data.ResourceName).Key("tags.%").HasValue("1"), + ), + }, + data.ImportStep(), + }) +} + +func (DnsDSRecordResource) Exists(ctx context.Context, clients *clients.Client, state *pluginsdk.InstanceState) (*bool, error) { + id, err := recordsets.ParseRecordTypeID(state.ID) + if err != nil { + return nil, err + } + + resp, err := clients.Dns.RecordSets.Get(ctx, *id) + if err != nil { + return nil, fmt.Errorf("retrieving %s: %+v", *id, err) + } + + return utils.Bool(resp.Model != nil), nil +} + +func (DnsDSRecordResource) basic(data acceptance.TestData) string { + return fmt.Sprintf(` +provider "azurerm" { + features {} +} + +resource "azurerm_resource_group" "test" { + name = "acctestRG-%d" + location = "%s" +} + +resource "azurerm_dns_zone" "test" { + name = "acctestzone%d.com" + resource_group_name = azurerm_resource_group.test.name +} + +resource "azurerm_dns_ds_record" "test" { + name = "myarecord%d" + resource_group_name = azurerm_resource_group.test.name + zone_name = azurerm_dns_zone.test.name + ttl = 300 + + record { + algorithm = 13 + key_tag = 28237 + digest_type = 2 + digest_value = "40F628643831D5EAF7D005D3237DE32F3F37AE6025C7891D202B0BAFA9924778" + } + + record { + algorithm = 13 + key_tag = 46872 + digest_type = 2 + digest_value = "2C0BAC20EB5C8C315694CBEB62E56C71CDC0069D058A8B80992E6499D91DD247" + } +} +`, data.RandomInteger, data.Locations.Primary, data.RandomInteger, data.RandomInteger) +} + +func (r DnsDSRecordResource) requiresImport(data acceptance.TestData) string { + return fmt.Sprintf(` +%s + +resource "azurerm_dns_ds_record" "import" { + name = azurerm_dns_ds_record.test.name + resource_group_name = azurerm_dns_ds_record.test.resource_group_name + zone_name = azurerm_dns_ds_record.test.zone_name + ttl = 300 + + record { + algorithm = 13 + key_tag = 28237 + digest_type = 2 + digest_value = "40F628643831D5EAF7D005D3237DE32F3F37AE6025C7891D202B0BAFA9924778" + } + + record { + algorithm = 13 + key_tag = 46872 + digest_type = 2 + digest_value = "2C0BAC20EB5C8C315694CBEB62E56C71CDC0069D058A8B80992E6499D91DD247" + } +} +`, r.basic(data)) +} + +func (DnsDSRecordResource) updateRecords(data acceptance.TestData) string { + return fmt.Sprintf(` +provider "azurerm" { + features {} +} + +resource "azurerm_resource_group" "test" { + name = "acctestRG-%d" + location = "%s" +} + +resource "azurerm_dns_zone" "test" { + name = "acctestzone%d.com" + resource_group_name = azurerm_resource_group.test.name +} + +resource "azurerm_dns_ds_record" "test" { + name = "myarecord%d" + resource_group_name = azurerm_resource_group.test.name + zone_name = azurerm_dns_zone.test.name + ttl = 300 + + record { + algorithm = 13 + key_tag = 28237 + digest_type = 2 + digest_value = "40F628643831D5EAF7D005D3237DE32F3F37AE6025C7891D202B0BAFA9924778" + } + + record { + algorithm = 13 + key_tag = 46872 + digest_type = 2 + digest_value = "2C0BAC20EB5C8C315694CBEB62E56C71CDC0069D058A8B80992E6499D91DD247" + } + + record { + algorithm = 13 + key_tag = 20795 + digest_type = 2 + digest_value = "55E20DB8044B0C6190A925598F08F8146C9A0D4F668F8CA5A7276EB54064C5E3" + } +} +`, data.RandomInteger, data.Locations.Primary, data.RandomInteger, data.RandomInteger) +} + +func (DnsDSRecordResource) withTags(data acceptance.TestData) string { + return fmt.Sprintf(` +provider "azurerm" { + features {} +} + +resource "azurerm_resource_group" "test" { + name = "acctestRG-%d" + location = "%s" +} + +resource "azurerm_dns_zone" "test" { + name = "acctestzone%d.com" + resource_group_name = azurerm_resource_group.test.name +} + +resource "azurerm_dns_ds_record" "test" { + name = "myarecord%d" + resource_group_name = azurerm_resource_group.test.name + zone_name = azurerm_dns_zone.test.name + ttl = 300 + + record { + algorithm = 13 + key_tag = 28237 + digest_type = 2 + digest_value = "40F628643831D5EAF7D005D3237DE32F3F37AE6025C7891D202B0BAFA9924778" + } + + record { + algorithm = 13 + key_tag = 46872 + digest_type = 2 + digest_value = "2C0BAC20EB5C8C315694CBEB62E56C71CDC0069D058A8B80992E6499D91DD247" + } + + tags = { + environment = "Production" + cost_center = "MSFT" + } +} +`, data.RandomInteger, data.Locations.Primary, data.RandomInteger, data.RandomInteger) +} + +func (DnsDSRecordResource) withTagsUpdate(data acceptance.TestData) string { + return fmt.Sprintf(` +provider "azurerm" { + features {} +} + +resource "azurerm_resource_group" "test" { + name = "acctestRG-%d" + location = "%s" +} + +resource "azurerm_dns_zone" "test" { + name = "acctestzone%d.com" + resource_group_name = azurerm_resource_group.test.name +} + +resource "azurerm_dns_ds_record" "test" { + name = "myarecord%d" + resource_group_name = azurerm_resource_group.test.name + zone_name = azurerm_dns_zone.test.name + ttl = 300 + + record { + algorithm = 13 + key_tag = 28237 + digest_type = 2 + digest_value = "40F628643831D5EAF7D005D3237DE32F3F37AE6025C7891D202B0BAFA9924778" + } + + record { + algorithm = 13 + key_tag = 46872 + digest_type = 2 + digest_value = "2C0BAC20EB5C8C315694CBEB62E56C71CDC0069D058A8B80992E6499D91DD247" + } + + tags = { + environment = "staging" + } +} +`, data.RandomInteger, data.Locations.Primary, data.RandomInteger, data.RandomInteger) +} diff --git a/internal/services/dns/registration.go b/internal/services/dns/registration.go index 7b06cc559f27..22e989c81ae3 100644 --- a/internal/services/dns/registration.go +++ b/internal/services/dns/registration.go @@ -35,6 +35,7 @@ func (r Registration) SupportedDataSources() map[string]*pluginsdk.Resource { "azurerm_dns_aaaa_record": dataSourceDnsAAAARecord(), "azurerm_dns_caa_record": dataSourceDnsCaaRecord(), "azurerm_dns_cname_record": dataSourceDnsCNameRecord(), + "azurerm_dns_ds_record": dataSourceDnsDSRecord(), "azurerm_dns_mx_record": dataSourceDnsMxRecord(), "azurerm_dns_ns_record": dataSourceDnsNsRecord(), "azurerm_dns_ptr_record": dataSourceDnsPtrRecord(), @@ -52,6 +53,7 @@ func (r Registration) SupportedResources() map[string]*pluginsdk.Resource { "azurerm_dns_aaaa_record": resourceDnsAAAARecord(), "azurerm_dns_caa_record": resourceDnsCaaRecord(), "azurerm_dns_cname_record": resourceDnsCNameRecord(), + "azurerm_dns_ds_record": resourceDnsDSRecord(), "azurerm_dns_mx_record": resourceDnsMxRecord(), "azurerm_dns_ns_record": resourceDnsNsRecord(), "azurerm_dns_ptr_record": resourceDnsPtrRecord(), diff --git a/website/docs/r/dns_ds_record.html.markdown b/website/docs/r/dns_ds_record.html.markdown new file mode 100644 index 000000000000..5b72e225818d --- /dev/null +++ b/website/docs/r/dns_ds_record.html.markdown @@ -0,0 +1,101 @@ +--- +subcategory: "DNS" +layout: "azurerm" +page_title: "Azure Resource Manager: azurerm_dns_ds_record" +description: |- + Manages a DNS DS Record. +--- + +# azurerm_dns_ds_record + +Enables you to manage DNS DS Records within Azure DNS. + +~> **Note:** [The Azure DNS API has a throttle limit of 500 read (GET) operations per 5 minutes](https://docs.microsoft.com/azure/azure-resource-manager/management/request-limits-and-throttling#network-throttling) - whilst the default read timeouts will work for most cases - in larger configurations you may need to set a larger [read timeout](https://www.terraform.io/language/resources/syntax#operation-timeouts) then the default 5min. Although, we'd generally recommend that you split the resources out into smaller Terraform configurations to avoid the problem entirely. + +## Example Usage + +```hcl +resource "azurerm_resource_group" "example" { + name = "example-resources" + location = "West Europe" +} + +resource "azurerm_dns_zone" "example" { + name = "mydomain.com" + resource_group_name = azurerm_resource_group.example.name +} + +resource "azurerm_dns_ds_record" "example" { + name = "test" + zone_name = azurerm_dns_zone.example.name + resource_group_name = azurerm_resource_group.example.name + ttl = 300 + + record { + priority = 1 + weight = 5 + port = 8080 + target = "target1.contoso.com" + } + + tags = { + Environment = "Production" + } +} +``` + +## Argument Reference + +The following arguments are supported: + +- `name` - (Required) The name of the DNS DS Record. Changing this forces a new resource to be created. + +- `resource_group_name` - (Required) Specifies the resource group where the DNS Zone (parent resource) exists. Changing this forces a new resource to be created. + +- `zone_name` - (Required) Specifies the DNS Zone where the resource exists. Changing this forces a new resource to be created. + +- `ttl` - (Required) The Time To Live (TTL) of the DNS record in seconds. + +- `record` - (Required) A list of values that make up the DS record. Each `record` block supports fields documented below. + +- `tags` - (Optional) A mapping of tags to assign to the resource. + +--- + +The `record` block supports: + +- `algorithm` - (Required) Identifies the algorithm used to produce a legitimate signature. + +- `key_tag` - (Required) Contains the tag value of the DNSKEY Resource Record that validates this signature. + +- `digest_type` - (Required) Identifies the algorithm used to construct the digest. + +- `digest_value` - (Required) A cryptographic hash value of the referenced DNSKEY Record. + +## Attributes Reference + +In addition to the Arguments listed above - the following Attributes are exported: + +- `id` - The DNS DS Record ID. + +- `fqdn` - The FQDN of the DNS DS Record. + +## Timeouts + +The `timeouts` block allows you to specify [timeouts](https://www.terraform.io/language/resources/syntax#operation-timeouts) for certain actions: + +- `create` - (Defaults to 30 minutes) Used when creating the DNS DS Record. + +- `update` - (Defaults to 30 minutes) Used when updating the DNS DS Record. + +- `read` - (Defaults to 5 minutes) Used when retrieving the DNS DS Record. + +- `delete` - (Defaults to 30 minutes) Used when deleting the DNS DS Record. + +## Import + +DS records can be imported using the `resource id`, e.g. + +```shell +terraform import azurerm_dns_ds_record.example /subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/mygroup1/providers/Microsoft.Network/dnsZones/zone1/DS/myrecord1 +```