Fix bug dns record name inconsistent (#307)

* add fqdn to model, map fqdn in mapFields

* add testing

* update examples, generate docs, fix linting

* addressed comments in PR

* add comment to acc tests, explaining ignore

* update docs
This commit is contained in:
Diogo Ferrão 2024-03-25 11:45:29 +00:00 committed by GitHub
parent 7223a5244c
commit d6c677552f
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
9 changed files with 61 additions and 18 deletions

View file

@ -34,6 +34,7 @@ data "stackit_dns_record_set" "example" {
- `active` (Boolean) Specifies if the record set is active or not. - `active` (Boolean) Specifies if the record set is active or not.
- `comment` (String) Comment. - `comment` (String) Comment.
- `error` (String) Error shows error in case create/update/delete failed. - `error` (String) Error shows error in case create/update/delete failed.
- `fqdn` (String) Fully qualified domain name (FQDN) of the record set.
- `id` (String) Terraform's internal data source. ID. It is structured as "`project_id`,`zone_id`,`record_set_id`". - `id` (String) Terraform's internal data source. ID. It is structured as "`project_id`,`zone_id`,`record_set_id`".
- `name` (String) Name of the record which should be a valid domain according to rfc1035 Section 2.3.4. E.g. `example.com` - `name` (String) Name of the record which should be a valid domain according to rfc1035 Section 2.3.4. E.g. `example.com`
- `records` (List of String) Records. - `records` (List of String) Records.

View file

@ -16,7 +16,7 @@ DNS Record Set Resource schema.
resource "stackit_dns_record_set" "example" { resource "stackit_dns_record_set" "example" {
project_id = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" project_id = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
zone_id = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" zone_id = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
name = "example-record-set.www.example-zone.com" name = "example-record-set"
type = "A" type = "A"
comment = "Example comment" comment = "Example comment"
records = ["1.2.3.4"] records = ["1.2.3.4"]
@ -43,6 +43,7 @@ resource "stackit_dns_record_set" "example" {
### Read-Only ### Read-Only
- `error` (String) Error shows error in case create/update/delete failed. - `error` (String) Error shows error in case create/update/delete failed.
- `fqdn` (String) Fully qualified domain name (FQDN) of the record set.
- `id` (String) Terraform's internal resource ID. It is structured as "`project_id`,`zone_id`,`record_set_id`". - `id` (String) Terraform's internal resource ID. It is structured as "`project_id`,`zone_id`,`record_set_id`".
- `record_set_id` (String) The rr set id. - `record_set_id` (String) The rr set id.
- `state` (String) Record set state. - `state` (String) Record set state.

View file

@ -16,7 +16,7 @@ DNS Zone resource schema.
resource "stackit_dns_zone" "example" { resource "stackit_dns_zone" "example" {
project_id = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" project_id = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
name = "Example zone" name = "Example zone"
dns_name = "www.example-zone.com" dns_name = "example-zone.com"
contact_email = "aa@bb.ccc" contact_email = "aa@bb.ccc"
type = "primary" type = "primary"
acl = "192.168.0.0/24" acl = "192.168.0.0/24"

View file

@ -1,7 +1,7 @@
resource "stackit_dns_record_set" "example" { resource "stackit_dns_record_set" "example" {
project_id = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" project_id = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
zone_id = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" zone_id = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
name = "example-record-set.www.example-zone.com" name = "example-record-set"
type = "A" type = "A"
comment = "Example comment" comment = "Example comment"
records = ["1.2.3.4"] records = ["1.2.3.4"]

View file

@ -1,7 +1,7 @@
resource "stackit_dns_zone" "example" { resource "stackit_dns_zone" "example" {
project_id = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" project_id = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
name = "Example zone" name = "Example zone"
dns_name = "www.example-zone.com" dns_name = "example-zone.com"
contact_email = "aa@bb.ccc" contact_email = "aa@bb.ccc"
type = "primary" type = "primary"
acl = "192.168.0.0/24" acl = "192.168.0.0/24"

View file

@ -41,8 +41,8 @@ var zoneResource = map[string]string{
// Record set resource data // Record set resource data
var recordSetResource = map[string]string{ var recordSetResource = map[string]string{
"name": fmt.Sprintf("tf-acc-%s.%s.", acctest.RandStringFromCharSet(5, acctest.CharSetAlpha), zoneResource["dns_name"]), "name": fmt.Sprintf("tf-acc-%s", acctest.RandStringFromCharSet(5, acctest.CharSetAlpha)),
"name_min": fmt.Sprintf("tf-acc-%s.%s.", acctest.RandStringFromCharSet(5, acctest.CharSetAlpha), zoneResource["dns_name_min"]), "name_min": fmt.Sprintf("tf-acc-%s", acctest.RandStringFromCharSet(5, acctest.CharSetAlpha)),
"records": `"1.2.3.4"`, "records": `"1.2.3.4"`,
"records_updated": `"5.6.7.8", "9.10.11.12"`, "records_updated": `"5.6.7.8", "9.10.11.12"`,
"ttl": "3700", "ttl": "3700",
@ -153,6 +153,7 @@ func TestAccDnsResource(t *testing.T) {
), ),
resource.TestCheckResourceAttrSet("stackit_dns_record_set.record_set", "record_set_id"), resource.TestCheckResourceAttrSet("stackit_dns_record_set.record_set", "record_set_id"),
resource.TestCheckResourceAttr("stackit_dns_record_set.record_set", "name", recordSetResource["name"]), resource.TestCheckResourceAttr("stackit_dns_record_set.record_set", "name", recordSetResource["name"]),
resource.TestCheckResourceAttr("stackit_dns_record_set.record_set", "fqdn", recordSetResource["name"]+"."+zoneResource["dns_name"]+"."),
resource.TestCheckResourceAttr("stackit_dns_record_set.record_set", "records.#", "1"), resource.TestCheckResourceAttr("stackit_dns_record_set.record_set", "records.#", "1"),
resource.TestCheckResourceAttr("stackit_dns_record_set.record_set", "records.0", strings.ReplaceAll(recordSetResource["records"], "\"", "")), resource.TestCheckResourceAttr("stackit_dns_record_set.record_set", "records.0", strings.ReplaceAll(recordSetResource["records"], "\"", "")),
resource.TestCheckResourceAttr("stackit_dns_record_set.record_set", "type", recordSetResource["type"]), resource.TestCheckResourceAttr("stackit_dns_record_set.record_set", "type", recordSetResource["type"]),
@ -221,7 +222,8 @@ func TestAccDnsResource(t *testing.T) {
// Record set data // Record set data
resource.TestCheckResourceAttrSet("data.stackit_dns_record_set.record_set", "record_set_id"), resource.TestCheckResourceAttrSet("data.stackit_dns_record_set.record_set", "record_set_id"),
resource.TestCheckResourceAttr("data.stackit_dns_record_set.record_set", "name", recordSetResource["name"]), resource.TestCheckResourceAttr("data.stackit_dns_record_set.record_set", "name", recordSetResource["name"]+"."+zoneResource["dns_name"]+"."),
resource.TestCheckResourceAttr("data.stackit_dns_record_set.record_set", "fqdn", recordSetResource["name"]+"."+zoneResource["dns_name"]+"."),
resource.TestCheckResourceAttr("data.stackit_dns_record_set.record_set", "records.#", "1"), resource.TestCheckResourceAttr("data.stackit_dns_record_set.record_set", "records.#", "1"),
resource.TestCheckResourceAttr("data.stackit_dns_record_set.record_set", "type", recordSetResource["type"]), resource.TestCheckResourceAttr("data.stackit_dns_record_set.record_set", "type", recordSetResource["type"]),
resource.TestCheckResourceAttr("data.stackit_dns_record_set.record_set", "ttl", recordSetResource["ttl"]), resource.TestCheckResourceAttr("data.stackit_dns_record_set.record_set", "ttl", recordSetResource["ttl"]),
@ -267,6 +269,8 @@ func TestAccDnsResource(t *testing.T) {
}, },
ImportState: true, ImportState: true,
ImportStateVerify: true, ImportStateVerify: true,
// Will be different because of the name vs fqdn problem, but the value is already tested in the datasource acc test
ImportStateVerifyIgnore: []string{"name"},
}, },
// Update. The zone ttl should not be updated according to the DNS API. // Update. The zone ttl should not be updated according to the DNS API.
{ {
@ -306,6 +310,7 @@ func TestAccDnsResource(t *testing.T) {
), ),
resource.TestCheckResourceAttrSet("stackit_dns_record_set.record_set", "record_set_id"), resource.TestCheckResourceAttrSet("stackit_dns_record_set.record_set", "record_set_id"),
resource.TestCheckResourceAttr("stackit_dns_record_set.record_set", "name", recordSetResource["name"]), resource.TestCheckResourceAttr("stackit_dns_record_set.record_set", "name", recordSetResource["name"]),
resource.TestCheckResourceAttr("stackit_dns_record_set.record_set", "fqdn", recordSetResource["name"]+"."+zoneResource["dns_name"]+"."),
resource.TestCheckResourceAttr("stackit_dns_record_set.record_set", "records.#", "2"), resource.TestCheckResourceAttr("stackit_dns_record_set.record_set", "records.#", "2"),
resource.TestCheckResourceAttr("stackit_dns_record_set.record_set", "type", recordSetResource["type"]), resource.TestCheckResourceAttr("stackit_dns_record_set.record_set", "type", recordSetResource["type"]),
resource.TestCheckResourceAttr("stackit_dns_record_set.record_set", "ttl", recordSetResource["ttl"]), resource.TestCheckResourceAttr("stackit_dns_record_set.record_set", "ttl", recordSetResource["ttl"]),
@ -393,6 +398,7 @@ func TestAccDnsMinimalResource(t *testing.T) {
), ),
resource.TestCheckResourceAttrSet("stackit_dns_record_set.record_set_min", "record_set_id"), resource.TestCheckResourceAttrSet("stackit_dns_record_set.record_set_min", "record_set_id"),
resource.TestCheckResourceAttr("stackit_dns_record_set.record_set_min", "name", recordSetResource["name_min"]), resource.TestCheckResourceAttr("stackit_dns_record_set.record_set_min", "name", recordSetResource["name_min"]),
resource.TestCheckResourceAttr("stackit_dns_record_set.record_set_min", "fqdn", recordSetResource["name_min"]+"."+zoneResource["dns_name_min"]+"."),
resource.TestCheckResourceAttr("stackit_dns_record_set.record_set_min", "records.#", "1"), resource.TestCheckResourceAttr("stackit_dns_record_set.record_set_min", "records.#", "1"),
resource.TestCheckResourceAttr("stackit_dns_record_set.record_set_min", "records.0", strings.ReplaceAll(recordSetResource["records"], "\"", "")), resource.TestCheckResourceAttr("stackit_dns_record_set.record_set_min", "records.0", strings.ReplaceAll(recordSetResource["records"], "\"", "")),
resource.TestCheckResourceAttr("stackit_dns_record_set.record_set_min", "type", recordSetResource["type"]), resource.TestCheckResourceAttr("stackit_dns_record_set.record_set_min", "type", recordSetResource["type"]),
@ -458,7 +464,8 @@ func TestAccDnsMinimalResource(t *testing.T) {
// Record set data // Record set data
resource.TestCheckResourceAttrSet("data.stackit_dns_record_set.record_set_min", "record_set_id"), resource.TestCheckResourceAttrSet("data.stackit_dns_record_set.record_set_min", "record_set_id"),
resource.TestCheckResourceAttr("data.stackit_dns_record_set.record_set_min", "name", recordSetResource["name_min"]), resource.TestCheckResourceAttr("data.stackit_dns_record_set.record_set_min", "name", recordSetResource["name_min"]+"."+zoneResource["dns_name_min"]+"."),
resource.TestCheckResourceAttr("data.stackit_dns_record_set.record_set_min", "fqdn", recordSetResource["name_min"]+"."+zoneResource["dns_name_min"]+"."),
resource.TestCheckResourceAttr("data.stackit_dns_record_set.record_set_min", "records.#", "1"), resource.TestCheckResourceAttr("data.stackit_dns_record_set.record_set_min", "records.#", "1"),
resource.TestCheckResourceAttr("data.stackit_dns_record_set.record_set_min", "records.0", strings.ReplaceAll(recordSetResource["records"], "\"", "")), resource.TestCheckResourceAttr("data.stackit_dns_record_set.record_set_min", "records.0", strings.ReplaceAll(recordSetResource["records"], "\"", "")),
resource.TestCheckResourceAttr("data.stackit_dns_record_set.record_set_min", "type", recordSetResource["type"]), resource.TestCheckResourceAttr("data.stackit_dns_record_set.record_set_min", "type", recordSetResource["type"]),
@ -503,8 +510,9 @@ func TestAccDnsMinimalResource(t *testing.T) {
return fmt.Sprintf("%s,%s,%s", testutil.ProjectId, zoneId, recordSetId), nil return fmt.Sprintf("%s,%s,%s", testutil.ProjectId, zoneId, recordSetId), nil
}, },
ImportState: true, ImportState: true,
ImportStateVerify: true, ImportStateVerify: true,
ImportStateVerifyIgnore: []string{"name"},
}, },
// Deletion is done by the framework implicitly // Deletion is done by the framework implicitly
}, },

View file

@ -107,6 +107,10 @@ func (d *recordSetDataSource) Schema(_ context.Context, _ datasource.SchemaReque
Description: "Name of the record which should be a valid domain according to rfc1035 Section 2.3.4. E.g. `example.com`", Description: "Name of the record which should be a valid domain according to rfc1035 Section 2.3.4. E.g. `example.com`",
Computed: true, Computed: true,
}, },
"fqdn": schema.StringAttribute{
Description: "Fully qualified domain name (FQDN) of the record set.",
Computed: true,
},
"records": schema.ListAttribute{ "records": schema.ListAttribute{
Description: "Records.", Description: "Records.",
Computed: true, Computed: true,

View file

@ -46,6 +46,7 @@ type Model struct {
Type types.String `tfsdk:"type"` Type types.String `tfsdk:"type"`
Error types.String `tfsdk:"error"` Error types.String `tfsdk:"error"`
State types.String `tfsdk:"state"` State types.String `tfsdk:"state"`
FQDN types.String `tfsdk:"fqdn"`
} }
// NewRecordSetResource is a helper function to simplify the provider implementation. // NewRecordSetResource is a helper function to simplify the provider implementation.
@ -151,6 +152,10 @@ func (r *recordSetResource) Schema(_ context.Context, _ resource.SchemaRequest,
stringvalidator.LengthAtMost(63), stringvalidator.LengthAtMost(63),
}, },
}, },
"fqdn": schema.StringAttribute{
Description: "Fully qualified domain name (FQDN) of the record set.",
Computed: true,
},
"records": schema.ListAttribute{ "records": schema.ListAttribute{
Description: "Records.", Description: "Records.",
ElementType: types.StringType, ElementType: types.StringType,
@ -433,7 +438,10 @@ func mapFields(recordSetResp *dns.RecordSetResponse, model *Model) error {
model.Active = types.BoolPointerValue(recordSet.Active) model.Active = types.BoolPointerValue(recordSet.Active)
model.Comment = types.StringPointerValue(recordSet.Comment) model.Comment = types.StringPointerValue(recordSet.Comment)
model.Error = types.StringPointerValue(recordSet.Error) model.Error = types.StringPointerValue(recordSet.Error)
model.Name = types.StringPointerValue(recordSet.Name) if model.Name.IsNull() || model.Name.IsUnknown() {
model.Name = types.StringPointerValue(recordSet.Name)
}
model.FQDN = types.StringPointerValue(recordSet.Name)
model.State = types.StringPointerValue(recordSet.State) model.State = types.StringPointerValue(recordSet.State)
model.TTL = types.Int64PointerValue(recordSet.Ttl) model.TTL = types.Int64PointerValue(recordSet.Ttl)
model.Type = types.StringPointerValue(recordSet.Type) model.Type = types.StringPointerValue(recordSet.Type)

View file

@ -13,12 +13,17 @@ import (
func TestMapFields(t *testing.T) { func TestMapFields(t *testing.T) {
tests := []struct { tests := []struct {
description string description string
state Model
input *dns.RecordSetResponse input *dns.RecordSetResponse
expected Model expected Model
isValid bool isValid bool
}{ }{
{ {
"default_values", "default_values",
Model{
ProjectId: types.StringValue("pid"),
ZoneId: types.StringValue("zid"),
},
&dns.RecordSetResponse{ &dns.RecordSetResponse{
Rrset: &dns.RecordSet{ Rrset: &dns.RecordSet{
Id: utils.Ptr("rid"), Id: utils.Ptr("rid"),
@ -33,6 +38,7 @@ func TestMapFields(t *testing.T) {
Comment: types.StringNull(), Comment: types.StringNull(),
Error: types.StringNull(), Error: types.StringNull(),
Name: types.StringNull(), Name: types.StringNull(),
FQDN: types.StringNull(),
Records: types.ListNull(types.StringType), Records: types.ListNull(types.StringType),
State: types.StringNull(), State: types.StringNull(),
TTL: types.Int64Null(), TTL: types.Int64Null(),
@ -42,6 +48,10 @@ func TestMapFields(t *testing.T) {
}, },
{ {
"simple_values", "simple_values",
Model{
ProjectId: types.StringValue("pid"),
ZoneId: types.StringValue("zid"),
},
&dns.RecordSetResponse{ &dns.RecordSetResponse{
Rrset: &dns.RecordSet{ Rrset: &dns.RecordSet{
Id: utils.Ptr("rid"), Id: utils.Ptr("rid"),
@ -67,6 +77,7 @@ func TestMapFields(t *testing.T) {
Comment: types.StringValue("comment"), Comment: types.StringValue("comment"),
Error: types.StringValue("error"), Error: types.StringValue("error"),
Name: types.StringValue("name"), Name: types.StringValue("name"),
FQDN: types.StringValue("name"),
Records: types.ListValueMust(types.StringType, []attr.Value{ Records: types.ListValueMust(types.StringType, []attr.Value{
types.StringValue("record_1"), types.StringValue("record_1"),
types.StringValue("record_2"), types.StringValue("record_2"),
@ -79,6 +90,11 @@ func TestMapFields(t *testing.T) {
}, },
{ {
"null_fields_and_int_conversions", "null_fields_and_int_conversions",
Model{
ProjectId: types.StringValue("pid"),
ZoneId: types.StringValue("zid"),
Name: types.StringValue("other-name"),
},
&dns.RecordSetResponse{ &dns.RecordSetResponse{
Rrset: &dns.RecordSet{ Rrset: &dns.RecordSet{
Id: utils.Ptr("rid"), Id: utils.Ptr("rid"),
@ -100,7 +116,8 @@ func TestMapFields(t *testing.T) {
Active: types.BoolNull(), Active: types.BoolNull(),
Comment: types.StringNull(), Comment: types.StringNull(),
Error: types.StringNull(), Error: types.StringNull(),
Name: types.StringValue("name"), Name: types.StringValue("other-name"),
FQDN: types.StringValue("name"),
Records: types.ListNull(types.StringType), Records: types.ListNull(types.StringType),
State: types.StringValue("state"), State: types.StringValue("state"),
TTL: types.Int64Value(2123456789), TTL: types.Int64Value(2123456789),
@ -110,12 +127,20 @@ func TestMapFields(t *testing.T) {
}, },
{ {
"nil_response", "nil_response",
Model{
ProjectId: types.StringValue("pid"),
ZoneId: types.StringValue("zid"),
},
nil, nil,
Model{}, Model{},
false, false,
}, },
{ {
"no_resource_id", "no_resource_id",
Model{
ProjectId: types.StringValue("pid"),
ZoneId: types.StringValue("zid"),
},
&dns.RecordSetResponse{}, &dns.RecordSetResponse{},
Model{}, Model{},
false, false,
@ -123,11 +148,7 @@ func TestMapFields(t *testing.T) {
} }
for _, tt := range tests { for _, tt := range tests {
t.Run(tt.description, func(t *testing.T) { t.Run(tt.description, func(t *testing.T) {
state := &Model{ err := mapFields(tt.input, &tt.state)
ProjectId: tt.expected.ProjectId,
ZoneId: tt.expected.ZoneId,
}
err := mapFields(tt.input, state)
if !tt.isValid && err == nil { if !tt.isValid && err == nil {
t.Fatalf("Should have failed") t.Fatalf("Should have failed")
} }
@ -135,7 +156,7 @@ func TestMapFields(t *testing.T) {
t.Fatalf("Should not have failed: %v", err) t.Fatalf("Should not have failed: %v", err)
} }
if tt.isValid { if tt.isValid {
diff := cmp.Diff(state, &tt.expected) diff := cmp.Diff(tt.state, tt.expected)
if diff != "" { if diff != "" {
t.Fatalf("Data does not match: %s", diff) t.Fatalf("Data does not match: %s", diff)
} }