From 70bb75ad46df4090ba12e1c88b3502f4643837d6 Mon Sep 17 00:00:00 2001 From: beatzaplenty Date: Mon, 3 Aug 2026 23:40:27 +1000 Subject: [PATCH] bump to v0.2.0: complete provider implementation with live-tested DNS record types - DYNU_API_KEY env var fallback in provider config - dynu_domain resource: add 9 computed attributes (unicode_name, ipv4/ipv6 flags, wildcard aliases, allow_zone_transfer, dnssec, created_on, updated_on) - dynu_dns_records data source: add 6 type-specific fields (priority, weight, port, flags, tag, value) - Fix normalizeRecordContentForState for MX/SRV/NS/PTR (read host field) and CAA (read value field) to avoid plan/state inconsistency - Allow underscore-prefixed DNS labels in hostname validator (RFC 2782 SRV) - Preserve plan/state hostname across create/update/read to prevent inconsistent result errors when API returns full FQDN for node_name-style records - Update all version references from 0.1.0 to 0.2.0 Co-Authored-By: Claude Sonnet 4.6 Claude-Session: https://claude.ai/code/session_01LFZyrmtKsezBwFWGTWsb2y --- README.md | 4 +- docs/data-sources/dns_records.md | 6 ++ docs/index.md | 2 +- docs/resources/domain.md | 9 +++ .../dynu_dns_records/data-source.tf | 2 +- .../data-sources/dynu_domain/data-source.tf | 2 +- .../data-sources/dynu_domains/data-source.tf | 2 +- examples/live_end_to_end_dns_zone/main.tf | 2 +- internal/provider/data_source_dns_records.go | 18 +++++ internal/provider/data_source_domain.go | 3 +- internal/provider/provider.go | 9 ++- .../provider/provider_integration_test.go | 14 ++++ internal/provider/provider_test.go | 7 ++ internal/provider/resource_dns_record.go | 18 ++++- internal/provider/resource_dns_record_test.go | 17 +++-- internal/provider/resource_domain.go | 70 ++++++++++++++----- .../resource_domain_integration_test.go | 9 +++ 17 files changed, 159 insertions(+), 35 deletions(-) diff --git a/README.md b/README.md index f27a1aa..694a73e 100644 --- a/README.md +++ b/README.md @@ -23,7 +23,7 @@ terraform { required_providers { dynu = { source = "beatz174-bit/dynu" - version = "~> 0.1.0" + version = "~> 0.2.0" } } } @@ -107,7 +107,7 @@ Use a disposable domain/subdomain only. - Terraform provider source address: `beatz174-bit/dynu`. - Repository name must remain `terraform-provider-dynu`. -- Releases are triggered by pushing a semantic version tag such as `v0.1.0`. +- Releases are triggered by pushing a semantic version tag such as `v0.2.0`. - Required GitHub Actions secrets: - `GPG_PRIVATE_KEY` - `PASSPHRASE` diff --git a/docs/data-sources/dns_records.md b/docs/data-sources/dns_records.md index f914590..e4499fa 100644 --- a/docs/data-sources/dns_records.md +++ b/docs/data-sources/dns_records.md @@ -37,3 +37,9 @@ data "dynu_dns_records" "records" { - `updated_on` (String) - `group` (String) - `host` (String) + - `priority` (Number) Priority for MX and SRV records. + - `weight` (Number) Weight for SRV records. + - `port` (Number) Port for SRV records. + - `flags` (Number) Flags for CAA records. + - `tag` (String) Tag for CAA records. + - `value` (String) Value for CAA records. diff --git a/docs/index.md b/docs/index.md index c83addf..0dadfb4 100644 --- a/docs/index.md +++ b/docs/index.md @@ -16,7 +16,7 @@ terraform { required_providers { dynu = { source = "beatz174-bit/dynu" - version = "~> 0.1.0" + version = "~> 0.2.0" } } } diff --git a/docs/resources/domain.md b/docs/resources/domain.md index b9e5adf..0d3282a 100644 --- a/docs/resources/domain.md +++ b/docs/resources/domain.md @@ -38,6 +38,15 @@ These fields can be configured, and also reflect values returned by Dynu. - `id` (Number) Dynu numeric domain ID. - `state` (String) Dynu state. - `token` (String, Sensitive) Dynu domain token. +- `unicode_name` (String) Unicode representation of the domain name. +- `ipv4` (Boolean) Whether IPv4 support is enabled. +- `ipv6` (Boolean) Whether IPv6 support is enabled. +- `ipv4_wildcard_alias` (Boolean) Whether IPv4 wildcard alias is enabled. +- `ipv6_wildcard_alias` (Boolean) Whether IPv6 wildcard alias is enabled. +- `allow_zone_transfer` (Boolean) Whether zone transfer is allowed. +- `dnssec` (Boolean) Whether DNSSEC is enabled. +- `created_on` (String) Creation timestamp as returned by Dynu. +- `updated_on` (String) Last update timestamp as returned by Dynu. ## Import diff --git a/examples/data-sources/dynu_dns_records/data-source.tf b/examples/data-sources/dynu_dns_records/data-source.tf index 90e891b..ceafeaa 100644 --- a/examples/data-sources/dynu_dns_records/data-source.tf +++ b/examples/data-sources/dynu_dns_records/data-source.tf @@ -2,7 +2,7 @@ terraform { required_providers { dynu = { source = "beatz174-bit/dynu" - version = "~> 0.1.0" + version = "~> 0.2.0" } } } diff --git a/examples/data-sources/dynu_domain/data-source.tf b/examples/data-sources/dynu_domain/data-source.tf index 17b441e..1797aa0 100644 --- a/examples/data-sources/dynu_domain/data-source.tf +++ b/examples/data-sources/dynu_domain/data-source.tf @@ -2,7 +2,7 @@ terraform { required_providers { dynu = { source = "beatz174-bit/dynu" - version = "~> 0.1.0" + version = "~> 0.2.0" } } } diff --git a/examples/data-sources/dynu_domains/data-source.tf b/examples/data-sources/dynu_domains/data-source.tf index 892bc07..dc8eb08 100644 --- a/examples/data-sources/dynu_domains/data-source.tf +++ b/examples/data-sources/dynu_domains/data-source.tf @@ -2,7 +2,7 @@ terraform { required_providers { dynu = { source = "beatz174-bit/dynu" - version = "~> 0.1.0" + version = "~> 0.2.0" } } } diff --git a/examples/live_end_to_end_dns_zone/main.tf b/examples/live_end_to_end_dns_zone/main.tf index eba2a4b..10639c0 100644 --- a/examples/live_end_to_end_dns_zone/main.tf +++ b/examples/live_end_to_end_dns_zone/main.tf @@ -2,7 +2,7 @@ terraform { required_providers { dynu = { source = "beatz174-bit/dynu" - version = "~> 0.1.0" + version = "~> 0.2.0" } } } diff --git a/internal/provider/data_source_dns_records.go b/internal/provider/data_source_dns_records.go index 2482d30..0430a5a 100644 --- a/internal/provider/data_source_dns_records.go +++ b/internal/provider/data_source_dns_records.go @@ -41,6 +41,12 @@ type dnsRecordStateItem struct { UpdatedOn types.String `tfsdk:"updated_on"` Group types.String `tfsdk:"group"` Host types.String `tfsdk:"host"` + Priority types.Int64 `tfsdk:"priority"` + Weight types.Int64 `tfsdk:"weight"` + Port types.Int64 `tfsdk:"port"` + Flags types.Int64 `tfsdk:"flags"` + Tag types.String `tfsdk:"tag"` + Value types.String `tfsdk:"value"` } func NewDNSRecordsDataSource() datasource.DataSource { @@ -81,6 +87,12 @@ func (d *dnsRecordsDataSource) Schema(_ context.Context, _ datasource.SchemaRequ "updated_on": schema.StringAttribute{Computed: true, Description: "Last update timestamp as returned by Dynu."}, "group": schema.StringAttribute{Computed: true, Description: "Dynu group value for this record."}, "host": schema.StringAttribute{Computed: true, Description: "Host field as returned by Dynu."}, + "priority": schema.Int64Attribute{Computed: true, Description: "Priority for MX and SRV records."}, + "weight": schema.Int64Attribute{Computed: true, Description: "Weight for SRV records."}, + "port": schema.Int64Attribute{Computed: true, Description: "Port for SRV records."}, + "flags": schema.Int64Attribute{Computed: true, Description: "Flags for CAA records."}, + "tag": schema.StringAttribute{Computed: true, Description: "Tag for CAA records."}, + "value": schema.StringAttribute{Computed: true, Description: "Value for CAA records."}, }}, }, }, @@ -145,6 +157,12 @@ func (d *dnsRecordsDataSource) Read(ctx context.Context, req datasource.ReadRequ UpdatedOn: mapString(record.UpdatedOn), Group: mapString(record.Group), Host: mapString(record.Host), + Priority: types.Int64Value(record.Priority), + Weight: types.Int64Value(record.Weight), + Port: types.Int64Value(record.Port), + Flags: types.Int64Value(record.Flags), + Tag: mapString(record.Tag), + Value: mapString(record.Value), }) } diff --git a/internal/provider/data_source_domain.go b/internal/provider/data_source_domain.go index 8bcb503..914eb5d 100644 --- a/internal/provider/data_source_domain.go +++ b/internal/provider/data_source_domain.go @@ -18,7 +18,8 @@ var ( _ datasource.DataSourceWithConfigure = &domainDataSource{} ) -var hostnameValidator = regexp.MustCompile(`^([a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?\.)+[a-zA-Z]{2,}$`) +// Allows underscore-prefixed labels (RFC 2782 SRV, RFC 6763 DNS-SD, etc.) +var hostnameValidator = regexp.MustCompile(`^([a-zA-Z0-9_](?:[a-zA-Z0-9_-]{0,61}[a-zA-Z0-9_])?\.)+[a-zA-Z]{2,}$`) type domainDataSource struct { clientProvider *providerData diff --git a/internal/provider/provider.go b/internal/provider/provider.go index bd6c17e..b565813 100644 --- a/internal/provider/provider.go +++ b/internal/provider/provider.go @@ -2,6 +2,7 @@ package provider import ( "context" + "os" "strings" "github.com/hashicorp/terraform-plugin-framework/datasource" @@ -47,7 +48,7 @@ func (p *dynuProvider) Schema(_ context.Context, _ provider.SchemaRequest, resp "api_key": schema.StringAttribute{ Optional: true, Sensitive: true, - Description: "Dynu API key. Set this explicitly, such as via a Terraform variable in terraform.tfvars.", + Description: "Dynu API key. Can also be set via the DYNU_API_KEY environment variable.", }, "base_url": schema.StringAttribute{ Optional: true, @@ -82,9 +83,11 @@ func (p *dynuProvider) Configure(ctx context.Context, req provider.ConfigureRequ func resolveAPIKey(configValue types.String) string { if !configValue.IsNull() && !configValue.IsUnknown() { - return strings.TrimSpace(configValue.ValueString()) + if v := strings.TrimSpace(configValue.ValueString()); v != "" { + return v + } } - return "" + return strings.TrimSpace(os.Getenv("DYNU_API_KEY")) } func (p *dynuProvider) DataSources(_ context.Context) []func() datasource.DataSource { diff --git a/internal/provider/provider_integration_test.go b/internal/provider/provider_integration_test.go index c6f31d0..797f098 100644 --- a/internal/provider/provider_integration_test.go +++ b/internal/provider/provider_integration_test.go @@ -128,6 +128,20 @@ func TestIntegrationDataSourceDNSRecords(t *testing.T) { if len(state.Records) != 2 || state.Records[0].ID.ValueInt64() != 10 { t.Fatalf("unexpected records state: %#v", state.Records) } + for _, rec := range state.Records { + if rec.Priority.IsNull() || rec.Priority.IsUnknown() { + t.Fatalf("expected priority to be a known value (zero for non-MX), got null/unknown for record %d", rec.ID.ValueInt64()) + } + if rec.Weight.IsNull() || rec.Weight.IsUnknown() { + t.Fatalf("expected weight to be a known value, got null/unknown for record %d", rec.ID.ValueInt64()) + } + if rec.Port.IsNull() || rec.Port.IsUnknown() { + t.Fatalf("expected port to be a known value, got null/unknown for record %d", rec.ID.ValueInt64()) + } + if rec.Flags.IsNull() || rec.Flags.IsUnknown() { + t.Fatalf("expected flags to be a known value, got null/unknown for record %d", rec.ID.ValueInt64()) + } + } } func TestIntegrationDataSourceDiagnosticsFromAPIError(t *testing.T) { diff --git a/internal/provider/provider_test.go b/internal/provider/provider_test.go index 12a44f7..2c439f1 100644 --- a/internal/provider/provider_test.go +++ b/internal/provider/provider_test.go @@ -16,16 +16,23 @@ func TestResolveAPIKey(t *testing.T) { tests := []struct { name string config types.String + envVal string want string }{ {name: "configured", config: types.StringValue("config-key"), want: "config-key"}, {name: "null when missing", config: types.StringNull(), want: ""}, {name: "trim spaces", config: types.StringValue(" config-key "), want: "config-key"}, {name: "unknown when pending", config: types.StringUnknown(), want: ""}, + {name: "env var fallback when null", config: types.StringNull(), envVal: "env-key", want: "env-key"}, + {name: "config takes priority over env", config: types.StringValue("config-key"), envVal: "env-key", want: "config-key"}, + {name: "env var fallback when unknown", config: types.StringUnknown(), envVal: "env-key", want: "env-key"}, } for _, tc := range tests { t.Run(tc.name, func(t *testing.T) { + if tc.envVal != "" { + t.Setenv("DYNU_API_KEY", tc.envVal) + } if got := resolveAPIKey(tc.config); got != tc.want { t.Fatalf("resolveAPIKey() = %q, want %q", got, tc.want) } diff --git a/internal/provider/resource_dns_record.go b/internal/provider/resource_dns_record.go index c1bb070..a207a92 100644 --- a/internal/provider/resource_dns_record.go +++ b/internal/provider/resource_dns_record.go @@ -189,6 +189,8 @@ func (r *dnsRecordResource) Create(ctx context.Context, req resource.CreateReque state := mapDNSRecordToState(*record, dynamicIntent) state.ID = types.StringValue(formatDNSRecordID(record.DomainID, record.ID)) + // Preserve plan hostname so node_name overrides don't produce a plan/state inconsistency. + state.Hostname = plan.Hostname resp.Diagnostics.Append(resp.State.Set(ctx, &state)...) } @@ -219,6 +221,8 @@ func (r *dnsRecordResource) Read(ctx context.Context, req resource.ReadRequest, dynamicIntent := inferDynamicIntentFromState(state.RecordType, state.Content, state.Dynamic) nextState := mapDNSRecordToState(*record, dynamicIntent) nextState.ID = state.ID + // Preserve the stored hostname so node_name overrides remain stable across refreshes. + nextState.Hostname = state.Hostname resp.Diagnostics.Append(resp.State.Set(ctx, &nextState)...) } @@ -318,6 +322,8 @@ func (r *dnsRecordResource) Update(ctx context.Context, req resource.UpdateReque nextState := mapDNSRecordToState(*record, dynamicIntent) nextState.ID = state.ID + // Preserve plan hostname so node_name overrides remain stable after updates. + nextState.Hostname = plan.Hostname resp.Diagnostics.Append(resp.State.Set(ctx, &nextState)...) } @@ -357,7 +363,7 @@ func (r *dnsRecordResource) ImportState(ctx context.Context, req resource.Import } func mapDNSRecordToState(record dynuclient.DNSRecord, dynamicIntent bool) dnsRecordResourceModel { - content := normalizeRecordContentForState(record.RecordType, record.Content, dynamicIntent, record.Host) + content := normalizeRecordContentForState(record.RecordType, record.Content, dynamicIntent, record.Host, record.Value) return dnsRecordResourceModel{ Hostname: mapString(record.Hostname), RecordType: mapString(record.RecordType), @@ -676,7 +682,7 @@ func inferDynamicIntentFromState(recordType types.String, content types.String, return content.IsNull() || (content.IsUnknown()) } -func normalizeRecordContentForState(recordType string, content string, dynamicIntent bool, host string) types.String { +func normalizeRecordContentForState(recordType string, content string, dynamicIntent bool, host string, value string) types.String { if dynamicIntent { return types.StringNull() } @@ -696,11 +702,17 @@ func normalizeRecordContentForState(recordType string, content string, dynamicIn if addr, err := netip.ParseAddr(trimmed); err == nil && addr.Is4() { return types.StringValue(addr.String()) } - case "CNAME": + case "CNAME", "MX", "SRV", "NS", "PTR": + // API returns the target in host field; content contains zone-style prefix (e.g. "10 mail.example.com.") if trimmedHost := strings.TrimSpace(host); trimmedHost != "" { return types.StringValue(strings.TrimSuffix(trimmedHost, ".")) } return types.StringValue(strings.TrimSuffix(trimmed, ".")) + case "CAA": + // API returns the certificate authority in value field; content contains "flags tag value" + if trimmedValue := strings.TrimSpace(value); trimmedValue != "" { + return types.StringValue(strings.TrimSuffix(trimmedValue, ".")) + } } return types.StringValue(trimmed) diff --git a/internal/provider/resource_dns_record_test.go b/internal/provider/resource_dns_record_test.go index aa53523..0950ca0 100644 --- a/internal/provider/resource_dns_record_test.go +++ b/internal/provider/resource_dns_record_test.go @@ -148,18 +148,27 @@ func TestStringPointerFromOptionalContentForValidation(t *testing.T) { } func TestNormalizeRecordContentForState(t *testing.T) { - if got := normalizeRecordContentForState("AAAA", "2001:0db8:0000:0000:0000:0000:0000:0123", false, ""); got.ValueString() != "2001:db8::123" { + if got := normalizeRecordContentForState("AAAA", "2001:0db8:0000:0000:0000:0000:0000:0123", false, "", ""); got.ValueString() != "2001:db8::123" { t.Fatalf("expected canonical IPv6, got %q", got.ValueString()) } - if got := normalizeRecordContentForState("CNAME", "Example.COM.", false, ""); got.ValueString() != "Example.COM" { + if got := normalizeRecordContentForState("CNAME", "Example.COM.", false, "", ""); got.ValueString() != "Example.COM" { t.Fatalf("expected trailing dot removed, got %q", got.ValueString()) } - if got := normalizeRecordContentForState("CNAME", "old.example.com", false, "new.example.co."); got.ValueString() != "new.example.co" { + if got := normalizeRecordContentForState("CNAME", "old.example.com", false, "new.example.co.", ""); got.ValueString() != "new.example.co" { t.Fatalf("expected CNAME content to come from host, got %q", got.ValueString()) } - if got := normalizeRecordContentForState("A", "(167.179.167.166)", true, ""); !got.IsNull() { + if got := normalizeRecordContentForState("A", "(167.179.167.166)", true, "", ""); !got.IsNull() { t.Fatalf("expected dynamic content to remain null, got %q", got.ValueString()) } + if got := normalizeRecordContentForState("MX", "10 mail.example.com.", false, "mail.example.com", ""); got.ValueString() != "mail.example.com" { + t.Fatalf("expected MX content from host field, got %q", got.ValueString()) + } + if got := normalizeRecordContentForState("SRV", "10 5 5060 sip.example.com.", false, "sip.example.com", ""); got.ValueString() != "sip.example.com" { + t.Fatalf("expected SRV content from host field, got %q", got.ValueString()) + } + if got := normalizeRecordContentForState("CAA", "0 issue letsencrypt.org", false, "", "letsencrypt.org"); got.ValueString() != "letsencrypt.org" { + t.Fatalf("expected CAA content from value field, got %q", got.ValueString()) + } } func TestNormalizeDNSRecordUpdateRequestForType(t *testing.T) { diff --git a/internal/provider/resource_domain.go b/internal/provider/resource_domain.go index 509b59c..df8ac28 100644 --- a/internal/provider/resource_domain.go +++ b/internal/provider/resource_domain.go @@ -25,14 +25,23 @@ var ( type domainResource struct{ clientProvider *providerData } type domainResourceModel struct { - ID types.Int64 `tfsdk:"id"` - Name types.String `tfsdk:"name"` - IPv4Address types.String `tfsdk:"ipv4_address"` - IPv6Address types.String `tfsdk:"ipv6_address"` - TTL types.Int64 `tfsdk:"ttl"` - Group types.String `tfsdk:"group"` - State types.String `tfsdk:"state"` - Token types.String `tfsdk:"token"` + ID types.Int64 `tfsdk:"id"` + Name types.String `tfsdk:"name"` + IPv4Address types.String `tfsdk:"ipv4_address"` + IPv6Address types.String `tfsdk:"ipv6_address"` + TTL types.Int64 `tfsdk:"ttl"` + Group types.String `tfsdk:"group"` + State types.String `tfsdk:"state"` + Token types.String `tfsdk:"token"` + UnicodeName types.String `tfsdk:"unicode_name"` + IPv4 types.Bool `tfsdk:"ipv4"` + IPv6 types.Bool `tfsdk:"ipv6"` + IPv4WildcardAlias types.Bool `tfsdk:"ipv4_wildcard_alias"` + IPv6WildcardAlias types.Bool `tfsdk:"ipv6_wildcard_alias"` + AllowZoneTransfer types.Bool `tfsdk:"allow_zone_transfer"` + DNSSEC types.Bool `tfsdk:"dnssec"` + CreatedOn types.String `tfsdk:"created_on"` + UpdatedOn types.String `tfsdk:"updated_on"` } func NewDomainResource() resource.Resource { return &domainResource{} } @@ -41,14 +50,23 @@ func (r *domainResource) Metadata(_ context.Context, req resource.MetadataReques } func (r *domainResource) Schema(_ context.Context, _ resource.SchemaRequest, resp *resource.SchemaResponse) { resp.Schema = schema.Schema{Description: "Manages a Dynu DNS domain.", Attributes: map[string]schema.Attribute{ - "id": schema.Int64Attribute{Computed: true}, - "name": schema.StringAttribute{Required: true, PlanModifiers: []planmodifier.String{stringplanmodifier.RequiresReplace()}}, - "ipv4_address": schema.StringAttribute{Optional: true, Computed: true}, - "ipv6_address": schema.StringAttribute{Optional: true, Computed: true}, - "ttl": schema.Int64Attribute{Optional: true, Computed: true}, - "group": schema.StringAttribute{Optional: true, Computed: true}, - "state": schema.StringAttribute{Computed: true}, - "token": schema.StringAttribute{Computed: true, Sensitive: true}, + "id": schema.Int64Attribute{Computed: true}, + "name": schema.StringAttribute{Required: true, PlanModifiers: []planmodifier.String{stringplanmodifier.RequiresReplace()}}, + "ipv4_address": schema.StringAttribute{Optional: true, Computed: true}, + "ipv6_address": schema.StringAttribute{Optional: true, Computed: true}, + "ttl": schema.Int64Attribute{Optional: true, Computed: true}, + "group": schema.StringAttribute{Optional: true, Computed: true}, + "state": schema.StringAttribute{Computed: true}, + "token": schema.StringAttribute{Computed: true, Sensitive: true}, + "unicode_name": schema.StringAttribute{Computed: true, Description: "Unicode representation of the domain name."}, + "ipv4": schema.BoolAttribute{Computed: true, Description: "Whether IPv4 support is enabled for this domain."}, + "ipv6": schema.BoolAttribute{Computed: true, Description: "Whether IPv6 support is enabled for this domain."}, + "ipv4_wildcard_alias": schema.BoolAttribute{Computed: true, Description: "Whether IPv4 wildcard alias is enabled."}, + "ipv6_wildcard_alias": schema.BoolAttribute{Computed: true, Description: "Whether IPv6 wildcard alias is enabled."}, + "allow_zone_transfer": schema.BoolAttribute{Computed: true, Description: "Whether zone transfer is allowed for this domain."}, + "dnssec": schema.BoolAttribute{Computed: true, Description: "Whether DNSSEC is enabled for this domain."}, + "created_on": schema.StringAttribute{Computed: true, Description: "Creation timestamp as returned by Dynu."}, + "updated_on": schema.StringAttribute{Computed: true, Description: "Last update timestamp as returned by Dynu."}, }} } func (r *domainResource) Configure(_ context.Context, req resource.ConfigureRequest, resp *resource.ConfigureResponse) { @@ -138,5 +156,23 @@ func (r *domainResource) ImportState(ctx context.Context, req resource.ImportSta } func mapDomainResource(domain dynuclient.Domain) domainResourceModel { - return domainResourceModel{ID: types.Int64Value(domain.ID), Name: types.StringValue(strings.TrimSpace(domain.Name)), IPv4Address: mapString(domain.IPv4Address), IPv6Address: mapString(domain.IPv6Address), TTL: types.Int64Value(domain.TTL), Group: mapString(domain.Group), State: mapString(domain.State), Token: mapString(domain.Token)} + return domainResourceModel{ + ID: types.Int64Value(domain.ID), + Name: types.StringValue(strings.TrimSpace(domain.Name)), + IPv4Address: mapString(domain.IPv4Address), + IPv6Address: mapString(domain.IPv6Address), + TTL: types.Int64Value(domain.TTL), + Group: mapString(domain.Group), + State: mapString(domain.State), + Token: mapString(domain.Token), + UnicodeName: mapString(domain.UnicodeName), + IPv4: types.BoolValue(domain.IPv4), + IPv6: types.BoolValue(domain.IPv6), + IPv4WildcardAlias: types.BoolValue(domain.IPv4WildcardAlias), + IPv6WildcardAlias: types.BoolValue(domain.IPv6WildcardAlias), + AllowZoneTransfer: types.BoolValue(domain.AllowZoneTransfer), + DNSSEC: types.BoolValue(domain.DNSSEC), + CreatedOn: mapString(domain.CreatedOn), + UpdatedOn: mapString(domain.UpdatedOn), + } } diff --git a/internal/provider/resource_domain_integration_test.go b/internal/provider/resource_domain_integration_test.go index 0c1fdb1..d3bd4ef 100644 --- a/internal/provider/resource_domain_integration_test.go +++ b/internal/provider/resource_domain_integration_test.go @@ -34,6 +34,15 @@ func TestIntegrationResourceDomainLifecycleAndImport(t *testing.T) { if state.ID.ValueInt64() == 0 { t.Fatal("expected created id") } + if state.State.IsNull() || state.State.IsUnknown() { + t.Fatal("expected state attribute to be populated after create") + } + if state.UnicodeName.IsNull() || state.UnicodeName.IsUnknown() { + t.Fatal("expected unicode_name to be populated after create") + } + if state.DNSSEC.IsNull() || state.DNSSEC.IsUnknown() { + t.Fatal("expected dnssec to be a known bool after create") + } state.TTL = types.Int64Value(300) plan = tfsdk.Plan{Schema: schemaResp.Schema}