diff --git a/go.mod b/go.mod index 4f6b2ff..4fb6c8f 100644 --- a/go.mod +++ b/go.mod @@ -25,7 +25,7 @@ require ( github.com/spf13/pflag v1.0.10 github.com/stackitcloud/stackit-sdk-go/core v0.26.0 github.com/stackitcloud/stackit-sdk-go/services/authorization v0.15.2 - github.com/stackitcloud/stackit-sdk-go/services/dns v0.20.2 + github.com/stackitcloud/stackit-sdk-go/services/dns v0.21.0 github.com/stackitcloud/stackit-sdk-go/services/iaas v1.12.0 github.com/stackitcloud/stackit-sdk-go/services/loadbalancer v1.13.0 github.com/stackitcloud/stackit-sdk-go/services/resourcemanager v0.23.0 diff --git a/go.sum b/go.sum index 3afd58d..ba91a60 100644 --- a/go.sum +++ b/go.sum @@ -469,8 +469,8 @@ github.com/stackitcloud/stackit-sdk-go/core v0.26.0 h1:jQEb9gkehfp6VCP6TcYk7BI10 github.com/stackitcloud/stackit-sdk-go/core v0.26.0/go.mod h1:WU1hhxnjXw2EV7CYa1nlEvNpMiRY6CvmIOaHuL3pOaA= github.com/stackitcloud/stackit-sdk-go/services/authorization v0.15.2 h1:b7WJ/vwxlVmNNX91kI3obqGcuoPAyaCbDL5aCMQ/sNg= github.com/stackitcloud/stackit-sdk-go/services/authorization v0.15.2/go.mod h1:T/JF25XGJ3GqER/1L2N//DgY8x5tY7gA3N+/0nvmOWY= -github.com/stackitcloud/stackit-sdk-go/services/dns v0.20.2 h1:nMJRg1dKioOlMwXJnZZgIRwfTWYCksVA9GyfAVmib1g= -github.com/stackitcloud/stackit-sdk-go/services/dns v0.20.2/go.mod h1:FiYSv3D9rzgEVzi8Mpq5oYZBosrasa5uUYqVdEIbM1U= +github.com/stackitcloud/stackit-sdk-go/services/dns v0.21.0 h1:ZVkptfVCAqpaPWkE+WIopM9XdzqgbVcwmX5L1jZqqx8= +github.com/stackitcloud/stackit-sdk-go/services/dns v0.21.0/go.mod h1:FiYSv3D9rzgEVzi8Mpq5oYZBosrasa5uUYqVdEIbM1U= github.com/stackitcloud/stackit-sdk-go/services/iaas v1.12.0 h1:H4V3H8qSKOaOalIrf4nAPDHhXnHYGs6SDGuK8Zj41Zo= github.com/stackitcloud/stackit-sdk-go/services/iaas v1.12.0/go.mod h1:Ts06id0KejUlQWbpR+/rm+tKng6QkTuFV1VQTPJ4dA4= github.com/stackitcloud/stackit-sdk-go/services/loadbalancer v1.13.0 h1:UuLNwFHjJCpL11y4F7B9oBKtZkxpu01VkNPILNkpex4= diff --git a/pkg/stackit/client/dns.go b/pkg/stackit/client/dns.go index 5c0af9c..e28689d 100644 --- a/pkg/stackit/client/dns.go +++ b/pkg/stackit/client/dns.go @@ -71,7 +71,12 @@ func (c *dnsClient) ListZones(ctx context.Context) ([]DNSZone, error) { func (c *dnsClient) CreateOrUpdateRecordSet(ctx context.Context, zoneID, name, recordType string, wantedRecords []string, ttl int64, ) error { - recordSet, err := c.findRecordSet(ctx, zoneID, name, recordType) + recordSetType, err := dns.NewRecordSetTypeFromValue(recordType) + if err != nil || recordSetType == nil { + return fmt.Errorf("invalid DNS record type %q: %w", recordType, err) + } + + recordSet, err := c.findRecordSet(ctx, zoneID, name, recordSetType) if err != nil { return fmt.Errorf("failed to find record set: %w", err) } @@ -88,11 +93,16 @@ func (c *dnsClient) CreateOrUpdateRecordSet(ctx context.Context, return err } + payloadType, err := dns.NewCreateRecordSetPayloadTypeFromValue(recordType) + if err != nil || payloadType == nil { + return fmt.Errorf("invalid DNS record type %q for create payload: %w", recordType, err) + } + if recordSet == nil { _, err := c.api.CreateRecordSet(ctx, c.projectID, zoneID).CreateRecordSetPayload(dns.CreateRecordSetPayload{ Name: name, Records: wantedRecordsPayload, - Type: recordType, + Type: *payloadType, Ttl: new(cacheTTL), }).Execute() if err != nil { @@ -119,7 +129,12 @@ func (c *dnsClient) CreateOrUpdateRecordSet(ctx context.Context, } func (c *dnsClient) DeleteRecordSet(ctx context.Context, zoneID, name, recordType string) error { - recordSet, err := c.findRecordSet(ctx, zoneID, name, recordType) + recordSetType, err := dns.NewRecordSetTypeFromValue(recordType) + if err != nil || recordSetType == nil { + return fmt.Errorf("invalid DNS record type %q: %w", recordType, err) + } + + recordSet, err := c.findRecordSet(ctx, zoneID, name, recordSetType) if err != nil { return fmt.Errorf("failed to find record set: %w", err) } @@ -134,7 +149,7 @@ func (c *dnsClient) DeleteRecordSet(ctx context.Context, zoneID, name, recordTyp return nil } -func (c *dnsClient) findRecordSet(ctx context.Context, zoneID, name, recordType string) (*dns.RecordSet, error) { +func (c *dnsClient) findRecordSet(ctx context.Context, zoneID, name string, recordType *dns.RecordSetType) (*dns.RecordSet, error) { resp, err := c.api.ListRecordSets(ctx, c.projectID, zoneID).Execute() if err != nil { return nil, err @@ -148,7 +163,7 @@ func (c *dnsClient) findRecordSet(ctx context.Context, zoneID, name, recordType if strings.TrimSuffix(recordSet.GetName(), ".") != name { continue } - if recordSet.GetType() != recordType { + if recordType == nil || recordSet.GetType() != *recordType { continue } return &recordSet, nil diff --git a/pkg/stackit/client/dns_test.go b/pkg/stackit/client/dns_test.go index 6c65571..f8db7fa 100644 --- a/pkg/stackit/client/dns_test.go +++ b/pkg/stackit/client/dns_test.go @@ -52,46 +52,52 @@ var _ = Describe("DNSClient", func() { }) Describe("CreateOrUpdate Record", func() { - BeforeEach(func() { - mockAPI.EXPECT().ListRecordSets(ctx, client.projectID, "zone1").Return(dns.ApiListRecordSetsRequest{ApiService: mockAPI}) - mockAPI.EXPECT().ListRecordSetsExecute(gomock.Any()).Return(&dns.ListRecordSetsResponse{ - RrSets: []dns.RecordSet{ - { - Name: "test.example.com.", - Active: new(true), - Type: "A", - Records: []dns.Record{{Content: "1.1.1.1"}}, - Id: "some-uuid", - Ttl: 300, - }, - { - Name: "test.example.com.", - Active: new(false), - Type: "A", - Records: []dns.Record{{Content: "4.4.4.4"}}, - Id: "some-uuid2", - Ttl: 300, + Context("with a supported record type", func() { + BeforeEach(func() { + mockAPI.EXPECT().ListRecordSets(ctx, client.projectID, "zone1").Return(dns.ApiListRecordSetsRequest{ApiService: mockAPI}) + mockAPI.EXPECT().ListRecordSetsExecute(gomock.Any()).Return(&dns.ListRecordSetsResponse{ + RrSets: []dns.RecordSet{ + { + Name: "test.example.com.", + Active: new(true), + Type: dns.RECORDSETTYPE_A, + Records: []dns.Record{{Content: "1.1.1.1"}}, + Id: "some-uuid", + Ttl: 300, + }, + { + Name: "test.example.com.", + Active: new(false), + Type: dns.RECORDSETTYPE_A, + Records: []dns.Record{{Content: "4.4.4.4"}}, + Id: "some-uuid2", + Ttl: 300, + }, }, - }, - }, nil) - }) + }, nil) + }) - It("should create a new record set if it does not exist", func() { - mockAPI.EXPECT().CreateRecordSet(ctx, client.projectID, "zone1").Return(dns.ApiCreateRecordSetRequest{ApiService: mockAPI}) - mockAPI.EXPECT().CreateRecordSetExecute(gomock.Any()).Return(nil, nil) + It("should create a new record set if it does not exist", func() { + mockAPI.EXPECT().CreateRecordSet(ctx, client.projectID, "zone1").Return(dns.ApiCreateRecordSetRequest{ApiService: mockAPI}) + mockAPI.EXPECT().CreateRecordSetExecute(gomock.Any()).Return(nil, nil) - Expect(client.CreateOrUpdateRecordSet(ctx, "zone1", "new.example.com.", "A", []string{"1.1.1.1"}, 300)).To(Succeed()) - }) + Expect(client.CreateOrUpdateRecordSet(ctx, "zone1", "new.example.com.", string(dns.RECORDSETTYPE_A), []string{"1.1.1.1"}, 300)).To(Succeed()) + }) - It("should update the existing record set if it exists and records are different", func() { - mockAPI.EXPECT().PartialUpdateRecordSet(ctx, client.projectID, "zone1", "some-uuid").Return(dns.ApiPartialUpdateRecordSetRequest{ApiService: mockAPI}) - mockAPI.EXPECT().PartialUpdateRecordSetExecute(gomock.Any()).Return(nil, nil) + It("should update the existing record set if it exists and records are different", func() { + mockAPI.EXPECT().PartialUpdateRecordSet(ctx, client.projectID, "zone1", "some-uuid").Return(dns.ApiPartialUpdateRecordSetRequest{ApiService: mockAPI}) + mockAPI.EXPECT().PartialUpdateRecordSetExecute(gomock.Any()).Return(nil, nil) - Expect(client.CreateOrUpdateRecordSet(ctx, "zone1", "test.example.com.", "A", []string{"4.4.4.4"}, 300)).To(Succeed()) + Expect(client.CreateOrUpdateRecordSet(ctx, "zone1", "test.example.com.", string(dns.RECORDSETTYPE_A), []string{"4.4.4.4"}, 300)).To(Succeed()) + }) + + It("should do nothing if the existing record set has the same records and TTL", func() { + Expect(client.CreateOrUpdateRecordSet(ctx, "zone1", "test.example.com.", string(dns.RECORDSETTYPE_A), []string{"1.1.1.1"}, 300)).To(Succeed()) + }) }) - It("should do nothing if the existing record set has the same records and TTL", func() { - Expect(client.CreateOrUpdateRecordSet(ctx, "zone1", "test.example.com.", "A", []string{"1.1.1.1"}, 300)).To(Succeed()) + It("should reject unsupported record types before calling the API", func() { + Expect(client.CreateOrUpdateRecordSet(ctx, "zone1", "test.example.com.", "UNSUPPORTED", []string{"1.1.1.1"}, 300)).To(MatchError(ContainSubstring("invalid DNS record type \"UNSUPPORTED\""))) }) }) @@ -102,28 +108,28 @@ var _ = Describe("DNSClient", func() { RrSets: []dns.RecordSet{{ Name: "test.example.com.", Active: new(true), - Type: "A", + Type: dns.RECORDSETTYPE_A, Id: "some-uuid", }}, }, nil) }) It("should do nothing if the record set does not exist", func() { - Expect(client.DeleteRecordSet(ctx, "zone1", "nonexistent.example.com.", "A")).To(Succeed()) + Expect(client.DeleteRecordSet(ctx, "zone1", "nonexistent.example.com.", string(dns.RECORDSETTYPE_A))).To(Succeed()) }) It("should delete the record set if it exists", func() { mockAPI.EXPECT().DeleteRecordSet(ctx, client.projectID, "zone1", "some-uuid").Return(dns.ApiDeleteRecordSetRequest{ApiService: mockAPI}) mockAPI.EXPECT().DeleteRecordSetExecute(gomock.Any()).Return(nil, nil) - Expect(client.DeleteRecordSet(ctx, "zone1", "test.example.com.", "A")).To(Succeed()) + Expect(client.DeleteRecordSet(ctx, "zone1", "test.example.com.", string(dns.RECORDSETTYPE_A))).To(Succeed()) }) It("should delete the record even if a non-FQDN is specified", func() { mockAPI.EXPECT().DeleteRecordSet(ctx, client.projectID, "zone1", "some-uuid").Return(dns.ApiDeleteRecordSetRequest{ApiService: mockAPI}) mockAPI.EXPECT().DeleteRecordSetExecute(gomock.Any()).Return(nil, nil) - Expect(client.DeleteRecordSet(ctx, "zone1", "test.example.com", "A")).To(Succeed()) + Expect(client.DeleteRecordSet(ctx, "zone1", "test.example.com", string(dns.RECORDSETTYPE_A))).To(Succeed()) }) }) @@ -133,28 +139,28 @@ var _ = Describe("DNSClient", func() { { Name: "active.example.com.", Active: new(true), - Type: "A", + Type: dns.RECORDSETTYPE_A, Records: []dns.Record{{Content: "1.1.1.1"}}, Id: "active-a-uuid", }, { Name: "active2.example.com.", Active: new(true), - Type: "A", + Type: dns.RECORDSETTYPE_A, Records: []dns.Record{{Content: "1.1.1.1"}}, Id: "active2-a-uuid", }, { Name: "active.example.com.", Active: new(true), - Type: "TXT", + Type: dns.RECORDSETTYPE_TXT, Records: []dns.Record{{Content: "hello-world"}}, Id: "active-txt-uuid", }, { Name: "inactive.example.com.", Active: new(false), - Type: "A", + Type: dns.RECORDSETTYPE_A, Records: []dns.Record{{Content: "2.2.2.2"}}, Id: "inactive-a-uuid", }, @@ -169,21 +175,21 @@ var _ = Describe("DNSClient", func() { }) It("should return the correct A recordSet", func() { - recordSet, err := client.findRecordSet(ctx, "zone1", "active.example.com.", "A") + recordSet, err := client.findRecordSet(ctx, "zone1", "active.example.com.", dns.RECORDSETTYPE_A.Ptr()) Expect(err).ToNot(HaveOccurred()) Expect(recordSet).ToNot(BeNil()) Expect(recordSet.GetId()).To(Equal("active-a-uuid")) }) It("should return the correct TXT recordSet", func() { - recordSet, err := client.findRecordSet(ctx, "zone1", "active.example.com.", "TXT") + recordSet, err := client.findRecordSet(ctx, "zone1", "active.example.com.", dns.RECORDSETTYPE_TXT.Ptr()) Expect(err).ToNot(HaveOccurred()) Expect(recordSet).ToNot(BeNil()) Expect(recordSet.GetId()).To(Equal("active-txt-uuid")) }) It("should return nil if nothing matches", func() { - recordSet, err := client.findRecordSet(ctx, "zone1", "non-existant.example.com.", "A") + recordSet, err := client.findRecordSet(ctx, "zone1", "non-existant.example.com.", dns.RECORDSETTYPE_A.Ptr()) Expect(err).ToNot(HaveOccurred()) Expect(recordSet).To(BeNil()) })