Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 22 additions & 0 deletions internal/provider/helper.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,3 +38,25 @@ func parseArrayFromEnv(env string) []string {
}
return parts
}

func adjustCNAMETarget(zones []*hcloud.Zone, dnsName string, target string) (string, error) {
zone, err := findZoneByHostname(zones, dnsName)
if err != nil {
return "", err
}

var adjustedTarget string
zoneSuffix := fmt.Sprintf(".%s", zone.Name)
absoluteZoneSuffix := fmt.Sprintf(".%s.", zone.Name)
switch {
case strings.HasSuffix(target, zoneSuffix):
adjustedTarget = strings.TrimSuffix(target, zoneSuffix)
case strings.HasSuffix(target, absoluteZoneSuffix):
adjustedTarget = strings.TrimSuffix(target, absoluteZoneSuffix)
default:
// ensure CNAME targets in different zones end in a dot
adjustedTarget = strings.TrimSuffix(target, ".") + "."
}

return adjustedTarget, nil
}
57 changes: 57 additions & 0 deletions internal/provider/helper_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
"testing"

"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"

"github.com/hetznercloud/hcloud-go/v2/hcloud"
)
Expand Down Expand Up @@ -177,3 +178,59 @@ func TestParseArrayFromEnv(t *testing.T) {
})
}
}

func TestAdjustCNAMETarget(t *testing.T) {
tests := []struct {
name string
zones []*hcloud.Zone
dnsName string
target string
rrsetValue string
expectedError error
}{
{
name: "same zone target",
zones: []*hcloud.Zone{
{Name: "example.de"},
},
dnsName: "foo.example.de",
target: "bar.example.de",
rrsetValue: "bar",
},
{
name: "same zone absolute target",
zones: []*hcloud.Zone{
{Name: "example.de"},
},
dnsName: "foo.example.de",
target: "bar.example.de.",
rrsetValue: "bar",
},
{
name: "different zone target",
zones: []*hcloud.Zone{
{Name: "example.de"},
},
dnsName: "foo.example.de",
target: "foo.example.com.",
rrsetValue: "foo.example.com.",
},
{
name: "unknown zone",
zones: []*hcloud.Zone{
{Name: "example.de"},
},
dnsName: "foo.example.com",
target: "foo.example.com.",
expectedError: fmt.Errorf("could not find zone with hostname: %s", "foo.example.com"),
},
}

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
target, err := adjustCNAMETarget(tt.zones, tt.dnsName, tt.target)
require.Equal(t, tt.expectedError, err)
require.Equal(t, tt.rrsetValue, target)
})
}
}
14 changes: 14 additions & 0 deletions internal/provider/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,13 @@ func (p *Provider) applyCreateChanges(

var records []hcloud.ZoneRRSetRecord
for _, target := range ep.Targets {
if ep.RecordType == "CNAME" {
target, err = adjustCNAMETarget(zones, ep.DNSName, target)
if err != nil {
return err
}
}

records = append(records, hcloud.ZoneRRSetRecord{Value: target})
}

Expand Down Expand Up @@ -279,6 +286,13 @@ func (p *Provider) applyUpdateChanges(

records := make([]hcloud.ZoneRRSetRecord, 0, len(endpointsNew[i].Targets))
for _, target := range endpointsNew[i].Targets {
if endpointsNew[i].RecordType == "CNAME" {
target, err = adjustCNAMETarget(zones, endpointsNew[i].DNSName, target)
if err != nil {
return err
}
}

records = append(records, hcloud.ZoneRRSetRecord{Value: target})
}

Expand Down
50 changes: 45 additions & 5 deletions internal/provider/provider_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -253,6 +253,46 @@ func TestApplyCreateChanges(t *testing.T) {
return mocks
},
},
{
name: "create a single cname rrset",
zoneNameFn: func(id string) string { return fmt.Sprintf("example-%s.com", id) },
inputEndpointsFn: func(zoneName string) []*endpoint.Endpoint {
return []*endpoint.Endpoint{
{
DNSName: fmt.Sprintf("%s.%s", "test", zoneName),
RecordType: "CNAME",
Targets: []string{"foo.mydomain.com"},
},
}
},
mocksFn: func(zoneName string, inputEndpoints []*endpoint.Endpoint) []mockutil.Request {
mocks := make([]mockutil.Request, 0, len(inputEndpoints))
for _, ep := range inputEndpoints {
mocks = append(mocks, mockutil.Request{
Method: "POST",
Path: fmt.Sprintf("/zones/%s/rrsets/%s/%s/actions/add_records", zoneName, "test", ep.RecordType),
Status: 200,
Want: func(t *testing.T, r *http.Request) {
request := schema.ZoneRRSetAddRecordsRequest{}
require.NoError(t, json.NewDecoder(r.Body).Decode(&request))
assert.Equal(
t,
schema.ZoneRRSetAddRecordsRequest{
Records: []schema.ZoneRRSetRecord{
{Value: "foo.mydomain.com."},
},
},
request,
)
},
JSON: schema.ActionGetResponse{
Action: schema.Action{ID: 1, Command: "add_rrset_records", Status: "success"},
},
})
}
return mocks
},
},
}

for _, tt := range tests {
Expand Down Expand Up @@ -448,17 +488,17 @@ func TestApplyUpdateChanges(t *testing.T) {
return []*endpoint.Endpoint{
{
DNSName: fmt.Sprintf("%s.%s", "test", zoneName),
RecordType: "A",
Targets: []string{"127.0.0.1"},
RecordType: "CNAME",
Targets: []string{"foo.mydomain.com"},
},
}
},
newEndpointsFn: func(zoneName string) []*endpoint.Endpoint {
return []*endpoint.Endpoint{
{
DNSName: fmt.Sprintf("%s.%s", "test", zoneName),
RecordType: "A",
Targets: []string{"192.168.0.1"},
RecordType: "CNAME",
Targets: []string{"bar.mydomain.com"},
},
}
},
Expand All @@ -475,7 +515,7 @@ func TestApplyUpdateChanges(t *testing.T) {
assert.Equal(
t,
schema.ZoneRRSetSetRecordsRequest{
Records: []schema.ZoneRRSetRecord{{Value: "192.168.0.1"}},
Records: []schema.ZoneRRSetRecord{{Value: "bar.mydomain.com."}},
},
request,
)
Expand Down