From e5082d6b9233ed89a4cfb6463febfee64a9572d8 Mon Sep 17 00:00:00 2001 From: beatz174-bit Date: Wed, 29 Apr 2026 09:36:38 +1000 Subject: [PATCH] Preserve legacy dynamic intent during DNS record read --- internal/provider/resource_dns_record.go | 18 +++++-- internal/provider/resource_dns_record_test.go | 47 +++++++++++++++++++ 2 files changed, 61 insertions(+), 4 deletions(-) diff --git a/internal/provider/resource_dns_record.go b/internal/provider/resource_dns_record.go index 972b75f..beb0583 100644 --- a/internal/provider/resource_dns_record.go +++ b/internal/provider/resource_dns_record.go @@ -190,10 +190,7 @@ func (r *dnsRecordResource) Read(ctx context.Context, req resource.ReadRequest, return } - dynamicIntent := false - if !state.Dynamic.IsNull() && !state.Dynamic.IsUnknown() { - dynamicIntent = state.Dynamic.ValueBool() - } + dynamicIntent := inferDynamicIntentFromState(state.RecordType, state.Content, state.Dynamic) nextState := mapDNSRecordToState(*record, dynamicIntent) nextState.ID = state.ID resp.Diagnostics.Append(resp.State.Set(ctx, &nextState)...) @@ -485,6 +482,19 @@ func resolveDynamicIntent(recordType string, content types.String, dynamic types return true, true } +func inferDynamicIntentFromState(recordType types.String, content types.String, dynamic types.Bool) bool { + if !dynamic.IsNull() && !dynamic.IsUnknown() { + return dynamic.ValueBool() + } + + normalizedType := strings.ToUpper(strings.TrimSpace(recordType.ValueString())) + if normalizedType != "A" && normalizedType != "AAAA" { + return false + } + + return content.IsNull() || (content.IsUnknown()) +} + func normalizeRecordContentForState(recordType string, content string, dynamicIntent bool) types.String { if dynamicIntent { return types.StringNull() diff --git a/internal/provider/resource_dns_record_test.go b/internal/provider/resource_dns_record_test.go index 3b9221d..040fda0 100644 --- a/internal/provider/resource_dns_record_test.go +++ b/internal/provider/resource_dns_record_test.go @@ -90,3 +90,50 @@ func TestNormalizeRecordContentForState(t *testing.T) { t.Fatalf("expected dynamic content to remain null, got %q", got.ValueString()) } } + +func TestInferDynamicIntentFromState(t *testing.T) { + tests := []struct { + name string + recordType types.String + content types.String + dynamic types.Bool + want bool + }{ + { + name: "explicit dynamic false wins", + recordType: types.StringValue("A"), + content: types.StringNull(), + dynamic: types.BoolValue(false), + want: false, + }, + { + name: "legacy A null content treated dynamic", + recordType: types.StringValue("A"), + content: types.StringNull(), + dynamic: types.BoolNull(), + want: true, + }, + { + name: "legacy AAAA unknown content treated dynamic", + recordType: types.StringValue("AAAA"), + content: types.StringUnknown(), + dynamic: types.BoolNull(), + want: true, + }, + { + name: "legacy non-A not dynamic", + recordType: types.StringValue("TXT"), + content: types.StringNull(), + dynamic: types.BoolNull(), + want: false, + }, + } + + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + if got := inferDynamicIntentFromState(tc.recordType, tc.content, tc.dynamic); got != tc.want { + t.Fatalf("inferDynamicIntentFromState()=%v, want %v", got, tc.want) + } + }) + } +}