Archived
Handle unknown dns_record content during config validation
This commit is contained in:
@@ -110,12 +110,12 @@ func (r *dnsRecordResource) ValidateConfig(ctx context.Context, req resource.Val
|
||||
if skip {
|
||||
return
|
||||
}
|
||||
content := stringPointerFromOptionalContent(config.Content)
|
||||
content, contentKnown := stringPointerFromOptionalContentForValidation(config.Content)
|
||||
dynamicIntent, ok := resolveDynamicIntent(recordType, config.Content, config.Dynamic, &resp.Diagnostics)
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
validateDNSRecordContentForType(recordType, content, dynamicIntent, &resp.Diagnostics)
|
||||
validateDNSRecordContentForTypeWithKnowledge(recordType, content, contentKnown, dynamicIntent, &resp.Diagnostics)
|
||||
}
|
||||
|
||||
func (r *dnsRecordResource) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) {
|
||||
@@ -393,11 +393,22 @@ func stringPointerFromOptionalContent(value types.String) *string {
|
||||
return &trimmed
|
||||
}
|
||||
|
||||
func stringPointerFromOptionalContentForValidation(value types.String) (*string, bool) {
|
||||
if value.IsUnknown() {
|
||||
return nil, false
|
||||
}
|
||||
return stringPointerFromOptionalContent(value), true
|
||||
}
|
||||
|
||||
func stringPointer(value string) *string {
|
||||
return &value
|
||||
}
|
||||
|
||||
func validateDNSRecordContentForType(recordType string, content *string, dynamicIntent bool, diagnostics *diag.Diagnostics) bool {
|
||||
return validateDNSRecordContentForTypeWithKnowledge(recordType, content, true, dynamicIntent, diagnostics)
|
||||
}
|
||||
|
||||
func validateDNSRecordContentForTypeWithKnowledge(recordType string, content *string, contentKnown bool, dynamicIntent bool, diagnostics *diag.Diagnostics) bool {
|
||||
normalizedType := strings.ToUpper(strings.TrimSpace(recordType))
|
||||
trimmedContent := ""
|
||||
if content != nil {
|
||||
@@ -440,6 +451,10 @@ func validateDNSRecordContentForType(recordType string, content *string, dynamic
|
||||
return false
|
||||
}
|
||||
|
||||
if !contentKnown {
|
||||
return true
|
||||
}
|
||||
|
||||
if trimmedContent == "" {
|
||||
diagnostics.AddError(
|
||||
"Missing required content for DNS record type",
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package provider
|
||||
|
||||
import (
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/hashicorp/terraform-plugin-framework/diag"
|
||||
@@ -79,6 +80,59 @@ func TestResolveDynamicIntent(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestValidateDNSRecordContentForTypeWithKnowledge(t *testing.T) {
|
||||
nonEmpty := "example.com"
|
||||
blank := ""
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
recordType string
|
||||
content *string
|
||||
contentKnown bool
|
||||
dynamic bool
|
||||
wantValid bool
|
||||
wantMessage string
|
||||
}{
|
||||
{name: "CNAME unknown content is allowed during validate", recordType: "CNAME", content: nil, contentKnown: false, wantValid: true},
|
||||
{name: "CNAME null content errors", recordType: "CNAME", content: nil, contentKnown: true, wantValid: false, wantMessage: "Missing required content"},
|
||||
{name: "CNAME empty content errors", recordType: "CNAME", content: &blank, contentKnown: true, wantValid: false, wantMessage: "Missing required content"},
|
||||
{name: "CNAME known content passes", recordType: "CNAME", content: &nonEmpty, contentKnown: true, wantValid: true},
|
||||
{name: "CNAME dynamic true errors", recordType: "CNAME", content: nil, contentKnown: false, dynamic: true, wantValid: false, wantMessage: "Dynamic mode is only supported"},
|
||||
{name: "A dynamic omitted content passes", recordType: "A", content: nil, contentKnown: true, dynamic: true, wantValid: true},
|
||||
{name: "AAAA dynamic omitted content passes", recordType: "AAAA", content: nil, contentKnown: true, dynamic: true, wantValid: true},
|
||||
}
|
||||
|
||||
for _, tc := range tests {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
diags := diag.Diagnostics{}
|
||||
got := validateDNSRecordContentForTypeWithKnowledge(tc.recordType, tc.content, tc.contentKnown, tc.dynamic, &diags)
|
||||
if got != tc.wantValid {
|
||||
t.Fatalf("validateDNSRecordContentForTypeWithKnowledge()=%v, want %v", got, tc.wantValid)
|
||||
}
|
||||
if tc.wantValid && diags.HasError() {
|
||||
t.Fatalf("expected no diagnostics, got %#v", diags)
|
||||
}
|
||||
if !tc.wantValid {
|
||||
if !diags.HasError() {
|
||||
t.Fatal("expected diagnostics but got none")
|
||||
}
|
||||
if tc.wantMessage != "" && diags[0].Summary() != "" && !strings.Contains(diags[0].Summary(), tc.wantMessage) {
|
||||
t.Fatalf("expected first diagnostic summary to contain %q, got %q", tc.wantMessage, diags[0].Summary())
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestStringPointerFromOptionalContentForValidation(t *testing.T) {
|
||||
if content, known := stringPointerFromOptionalContentForValidation(types.StringUnknown()); known || content != nil {
|
||||
t.Fatalf("expected unknown content to be unknown with nil pointer, got known=%v content=%v", known, content)
|
||||
}
|
||||
if content, known := stringPointerFromOptionalContentForValidation(types.StringNull()); !known || content != nil {
|
||||
t.Fatalf("expected null content to be known with nil pointer, got known=%v content=%v", known, content)
|
||||
}
|
||||
}
|
||||
|
||||
func TestNormalizeRecordContentForState(t *testing.T) {
|
||||
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())
|
||||
|
||||
Reference in New Issue
Block a user