Archived
bump to v0.2.0: complete provider implementation with live-tested DNS record types
ci / test (push) Failing after 5m55s
ci / test (push) Failing after 5m55s
- 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 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LFZyrmtKsezBwFWGTWsb2y
This commit is contained in:
1 parent
12b8f2460d
commit
70bb75ad46
17 files changed
+159
-35
No files matched your search
@@ -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)
|
||||
|
||||
Reference in new issue
Block a user