diff --git a/docs/data-sources/recursive_cname_record_set.md b/docs/data-sources/recursive_cname_record_set.md new file mode 100644 index 00000000..f855aeae --- /dev/null +++ b/docs/data-sources/recursive_cname_record_set.md @@ -0,0 +1,36 @@ +--- +# generated by https://github.com/hashicorp/terraform-plugin-docs +page_title: "dns_recursive_cname_record_set Data Source - terraform-provider-dns" +subcategory: "" +description: |- + Use this data source to get DNS CNAME record set of the host. +--- + +# dns_recursive_cname_record_set (Data Source) + +Use this data source to get DNS CNAME record set of the host. + +## Example Usage + +```terraform +data "dns_recursive_cname_record_set" "hashicorp" { + host = "www.hashicorp.com" +} + +output "hashi_cnames" { + value = data.dns_recursive_cname_record_set.hashicorp.cnames +} +``` + + +## Schema + +### Required + +- `host` (String) Host to recursively look up. + +### Read-Only + +- `cnames` (List of String) Chained CNAME records associated with host. +- `id` (String) Always set to the host. +- `last_cname` (String) The final CNAME at end of the chain. diff --git a/examples/data-sources/dns_recursive_cname_record_set/data-source.tf b/examples/data-sources/dns_recursive_cname_record_set/data-source.tf new file mode 100644 index 00000000..c6e46bf2 --- /dev/null +++ b/examples/data-sources/dns_recursive_cname_record_set/data-source.tf @@ -0,0 +1,7 @@ +data "dns_recursive_cname_record_set" "hashicorp" { + host = "www.hashicorp.com" +} + +output "hashi_cnames" { + value = data.dns_recursive_cname_record_set.hashicorp.cnames +} diff --git a/internal/provider/data_dns_recursive_cname_record_set.go b/internal/provider/data_dns_recursive_cname_record_set.go new file mode 100644 index 00000000..68236d30 --- /dev/null +++ b/internal/provider/data_dns_recursive_cname_record_set.go @@ -0,0 +1,89 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +package provider + +import ( + "context" + "fmt" + "net" + "strings" + + "github.com/hashicorp/terraform-plugin-framework/datasource" + "github.com/hashicorp/terraform-plugin-framework/datasource/schema" + "github.com/hashicorp/terraform-plugin-framework/types" +) + +var ( + _ datasource.DataSource = (*dnsCNAMERecursiveRecordSetDataSource)(nil) +) + +func NewDnsCNAMERecursiveRecordSetDataSource() datasource.DataSource { + return &dnsCNAMERecursiveRecordSetDataSource{} +} + +type dnsCNAMERecursiveRecordSetDataSource struct{} + +func (d *dnsCNAMERecursiveRecordSetDataSource) Metadata(ctx context.Context, req datasource.MetadataRequest, resp *datasource.MetadataResponse) { + resp.TypeName = req.ProviderTypeName + "_recursive_cname_record_set" +} + +func (d *dnsCNAMERecursiveRecordSetDataSource) Schema(ctx context.Context, req datasource.SchemaRequest, resp *datasource.SchemaResponse) { + resp.Schema = schema.Schema{ + Description: "Use this data source to get DNS CNAME record set of the host.", + Attributes: map[string]schema.Attribute{ + "host": schema.StringAttribute{ + Required: true, + Description: "Host to recursively look up.", + }, + "cnames": schema.ListAttribute{ + ElementType: types.StringType, + Computed: true, + Description: "Chained CNAME records associated with host.", + }, + "last_cname": schema.StringAttribute{ + Computed: true, + Description: "The final CNAME at end of the chain.", + }, + "id": schema.StringAttribute{ + Computed: true, + Description: "Always set to the host.", + }, + }, + } +} + +func (d *dnsCNAMERecursiveRecordSetDataSource) Read(ctx context.Context, req datasource.ReadRequest, resp *datasource.ReadResponse) { + var config cnameRecursiveRecordSetConfig + + resp.Diagnostics.Append(req.Config.Get(ctx, &config)...) + if resp.Diagnostics.HasError() { + return + } + + cnames := []string{} + + host := config.Host.ValueString() + for cname, err := net.LookupCNAME(host); cname != host; cname, err = net.LookupCNAME(host) { + if err != nil { + resp.Diagnostics.AddError(fmt.Sprintf("error looking up CNAME records for %q: ", host), err.Error()) + return + } + cnames = append(cnames, strings.Clone(cname)) + host = cname + } + + config.CNAMES, _ = types.ListValueFrom(ctx, types.StringType, cnames) + if len(cnames) > 0 { + config.LastCNAME = types.StringValue(cnames[len(cnames)-1]) + } + config.ID = config.Host + resp.Diagnostics.Append(resp.State.Set(ctx, config)...) +} + +type cnameRecursiveRecordSetConfig struct { + ID types.String `tfsdk:"id"` + Host types.String `tfsdk:"host"` + CNAMES types.List `tfsdk:"cnames"` + LastCNAME types.String `tfsdk:"last_cname"` +} diff --git a/internal/provider/data_dns_recursive_cname_record_set_test.go b/internal/provider/data_dns_recursive_cname_record_set_test.go new file mode 100644 index 00000000..26dcf253 --- /dev/null +++ b/internal/provider/data_dns_recursive_cname_record_set_test.go @@ -0,0 +1,59 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +package provider + +import ( + "testing" + + "github.com/hashicorp/terraform-plugin-testing/helper/resource" +) + +func TestAccDataDnsRecursiveCnameRecordSet_Basic(t *testing.T) { + recordName := "data.dns_recursive_cname_record_set.test" + + resource.UnitTest(t, resource.TestCase{ + ProtoV5ProviderFactories: testProtoV5ProviderFactories, + Steps: []resource.TestStep{ + { + Config: ` +data "dns_recursive_cname_record_set" "test" { + host = "terraform-provider-dns-cname.hashicorptest.com" +} +`, + Check: resource.ComposeAggregateTestCheckFunc( + resource.TestCheckResourceAttr(recordName, "cnames.0", "example.com."), + resource.TestCheckNoResourceAttr(recordName, "cnames.1"), + resource.TestCheckResourceAttr(recordName, "last_cname", "example.com."), + resource.TestCheckResourceAttr(recordName, "host", "terraform-provider-dns-cname.hashicorptest.com"), + resource.TestCheckResourceAttr(recordName, "id", "terraform-provider-dns-cname.hashicorptest.com"), + ), + }, + }, + }) +} + +func TestAccDataDnsRecursiveCnameRecordSet_Complex(t *testing.T) { + recordName := "data.dns_recursive_cname_record_set.test" + + resource.UnitTest(t, resource.TestCase{ + ProtoV5ProviderFactories: testProtoV5ProviderFactories, + Steps: []resource.TestStep{ + { + Config: ` +data "dns_recursive_cname_record_set" "test" { + host = "test2.tony.docusign.dev" +} +`, + Check: resource.ComposeAggregateTestCheckFunc( + resource.TestCheckResourceAttr(recordName, "cnames.0", "stage.services.docusign.net."), + resource.TestCheckResourceAttr(recordName, "cnames.1", "stage.services.docusign.net.akadns.net."), + resource.TestCheckNoResourceAttr(recordName, "cnames.2"), + resource.TestCheckResourceAttr(recordName, "last_cname", "stage.services.docusign.net.akadns.net."), + resource.TestCheckResourceAttr(recordName, "host", "test2.tony.docusign.dev"), + resource.TestCheckResourceAttr(recordName, "id", "test2.tony.docusign.dev"), + ), + }, + }, + }) +} diff --git a/internal/provider/provider_framework.go b/internal/provider/provider_framework.go index ac814754..1b22ecac 100644 --- a/internal/provider/provider_framework.go +++ b/internal/provider/provider_framework.go @@ -347,6 +347,7 @@ func (p *dnsProvider) DataSources(ctx context.Context) []func() datasource.DataS NewDnsARecordSetDataSource, NewDnsAAAARecordSetDataSource, NewDnsCNAMERecordSetDataSource, + NewDnsCNAMERecursiveRecordSetDataSource, NewDnsMXRecordSetDataSource, NewDnsNSRecordSetDataSource, NewDnsPTRRecordSetDataSource,