Fix CNAME updates to use content as target host

This commit is contained in:
beatz174-bit
2026-04-29 14:58:52 +10:00
parent ee7a24a0da
commit a64aa173ab
4 changed files with 84 additions and 6 deletions
+36 -2
View File
@@ -146,6 +146,7 @@ func (r *dnsRecordResource) Create(ctx context.Context, req resource.CreateReque
Group: stringFromOptional(plan.Group),
Host: stringFromOptional(plan.Host),
}
createReq = normalizeDNSRecordCreateRequestForType(createReq)
if !validateDNSRecordContentForType(createReq.RecordType, createReq.Content, dynamicIntent, &resp.Diagnostics) {
return
}
@@ -242,6 +243,7 @@ func (r *dnsRecordResource) Update(ctx context.Context, req resource.UpdateReque
Group: stringFromOptional(preferKnownString(plan.Group, state.Group)),
Host: stringFromOptional(preferKnownString(plan.Host, state.Host)),
}
updateReq = normalizeDNSRecordUpdateRequestForType(updateReq)
if !validateDNSRecordContentForType(updateReq.RecordType, updateReq.Content, dynamicIntent, &resp.Diagnostics) {
return
}
@@ -315,7 +317,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)
content := normalizeRecordContentForState(record.RecordType, record.Content, dynamicIntent, record.Host)
return dnsRecordResourceModel{
Hostname: mapString(record.Hostname),
RecordType: mapString(record.RecordType),
@@ -442,6 +444,35 @@ func stringPointer(value string) *string {
return &value
}
func normalizeDNSRecordCreateRequestForType(req dynuclient.CreateDNSRecordRequest) dynuclient.CreateDNSRecordRequest {
if strings.EqualFold(strings.TrimSpace(req.RecordType), "CNAME") {
if normalizedContent := normalizeOptionalContentString(req.Content); normalizedContent != nil {
req.Host = *normalizedContent
}
}
return req
}
func normalizeDNSRecordUpdateRequestForType(req dynuclient.UpdateDNSRecordRequest) dynuclient.UpdateDNSRecordRequest {
if strings.EqualFold(strings.TrimSpace(req.RecordType), "CNAME") {
if normalizedContent := normalizeOptionalContentString(req.Content); normalizedContent != nil {
req.Host = *normalizedContent
}
}
return req
}
func normalizeOptionalContentString(content *string) *string {
if content == nil {
return nil
}
trimmed := strings.TrimSpace(*content)
if trimmed == "" {
return nil
}
return &trimmed
}
func validateDNSRecordContentForType(recordType string, content *string, dynamicIntent bool, diagnostics *diag.Diagnostics) bool {
return validateDNSRecordContentForTypeWithKnowledge(recordType, content, true, dynamicIntent, diagnostics)
}
@@ -548,7 +579,7 @@ func inferDynamicIntentFromState(recordType types.String, content types.String,
return content.IsNull() || (content.IsUnknown())
}
func normalizeRecordContentForState(recordType string, content string, dynamicIntent bool) types.String {
func normalizeRecordContentForState(recordType string, content string, dynamicIntent bool, host string) types.String {
if dynamicIntent {
return types.StringNull()
}
@@ -569,6 +600,9 @@ func normalizeRecordContentForState(recordType string, content string, dynamicIn
return types.StringValue(addr.String())
}
case "CNAME":
if trimmedHost := strings.TrimSpace(host); trimmedHost != "" {
return types.StringValue(strings.TrimSuffix(trimmedHost, "."))
}
return types.StringValue(strings.TrimSuffix(trimmed, "."))
}
+19 -3
View File
@@ -146,17 +146,33 @@ 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("A", "(167.179.167.166)", true); !got.IsNull() {
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() {
t.Fatalf("expected dynamic content to remain null, got %q", got.ValueString())
}
}
func TestNormalizeDNSRecordUpdateRequestForType(t *testing.T) {
oldHost := "example.com"
newContent := "example.co"
req := normalizeDNSRecordUpdateRequestForType(dynuclient.UpdateDNSRecordRequest{
RecordType: "CNAME",
Content: &newContent,
Host: oldHost,
})
if req.Host != "example.co" {
t.Fatalf("expected CNAME host to be normalized from content, got %q", req.Host)
}
}
func TestInferDynamicIntentFromState(t *testing.T) {
tests := []struct {
name string