mirror of
https://github.com/kubernetes-sigs/external-dns.git
synced 2025-08-05 17:16:59 +02:00
Handle the migration to the new TXT format: create missing records
This commit is contained in:
parent
60809f4408
commit
50f196c0db
@ -167,6 +167,9 @@ func (c *Controller) RunOnce(ctx context.Context) error {
|
||||
deprecatedRegistryErrors.Inc()
|
||||
return err
|
||||
}
|
||||
|
||||
missingRecords := c.Registry.MissingRecords()
|
||||
|
||||
registryEndpointsTotal.Set(float64(len(records)))
|
||||
regARecords := filterARecords(records)
|
||||
registryARecords.Set(float64(len(regARecords)))
|
||||
@ -189,6 +192,7 @@ func (c *Controller) RunOnce(ctx context.Context) error {
|
||||
Policies: []plan.Policy{c.Policy},
|
||||
Current: records,
|
||||
Desired: endpoints,
|
||||
Missing: missingRecords,
|
||||
DomainFilter: endpoint.MatchAllDomainFilters{c.DomainFilter, c.Registry.GetDomainFilter()},
|
||||
PropertyComparator: c.Registry.PropertyValuesEqual,
|
||||
ManagedRecords: c.ManagedRecordTypes,
|
||||
|
@ -7,7 +7,8 @@ It contains record type it manages, e.g.:
|
||||
|
||||
Prefix and suffix are extended with %{record_type} template where the user can control how prefixed/suffixed records should look like.
|
||||
|
||||
In order to maintain compatibility, both records will be maintained for some time, in order to have downgrade possibility.
|
||||
In order to maintain compatibility, both records will be maintained for some time, in order to have downgrade possibility.
|
||||
The controller will try to create the "new format" TXT records if they are not present to ease the migration from the versions < 0.12.0.
|
||||
|
||||
Later on, the old format will be dropped and only the new format will be kept (<record_type>-<endpoint_name>).
|
||||
|
||||
|
2
main.go
2
main.go
@ -341,7 +341,7 @@ func main() {
|
||||
case "noop":
|
||||
r, err = registry.NewNoopRegistry(p)
|
||||
case "txt":
|
||||
r, err = registry.NewTXTRegistry(p, cfg.TXTPrefix, cfg.TXTSuffix, cfg.TXTOwnerID, cfg.TXTCacheInterval, cfg.TXTWildcardReplacement)
|
||||
r, err = registry.NewTXTRegistry(p, cfg.TXTPrefix, cfg.TXTSuffix, cfg.TXTOwnerID, cfg.TXTCacheInterval, cfg.TXTWildcardReplacement, cfg.ManagedDNSRecordTypes)
|
||||
case "aws-sd":
|
||||
r, err = registry.NewAWSSDRegistry(p.(*awssd.AWSSDProvider), cfg.TXTOwnerID)
|
||||
default:
|
||||
|
11
plan/plan.go
11
plan/plan.go
@ -37,6 +37,8 @@ type Plan struct {
|
||||
Current []*endpoint.Endpoint
|
||||
// List of desired records
|
||||
Desired []*endpoint.Endpoint
|
||||
// List of missing records to be created, use for the migrations (e.g. old-new TXT format)
|
||||
Missing []*endpoint.Endpoint
|
||||
// Policies under which the desired changes are calculated
|
||||
Policies []Policy
|
||||
// List of changes necessary to move towards desired state
|
||||
@ -170,6 +172,11 @@ func (p *Plan) Calculate() *Plan {
|
||||
changes = pol.Apply(changes)
|
||||
}
|
||||
|
||||
// Handle the migration of the TXT records created before the new format (introduced in v0.12.0)
|
||||
if len(p.Missing) > 0 {
|
||||
changes.Create = append(changes.Create, filterRecordsForPlan(p.Missing, p.DomainFilter, append(p.ManagedRecords, endpoint.RecordTypeTXT))...)
|
||||
}
|
||||
|
||||
plan := &Plan{
|
||||
Current: p.Current,
|
||||
Desired: p.Desired,
|
||||
@ -250,7 +257,7 @@ func filterRecordsForPlan(records []*endpoint.Endpoint, domainFilter endpoint.Do
|
||||
log.Debugf("ignoring record %s that does not match domain filter", record.DNSName)
|
||||
continue
|
||||
}
|
||||
if isManagedRecord(record.RecordType, managedRecords) {
|
||||
if IsManagedRecord(record.RecordType, managedRecords) {
|
||||
filtered = append(filtered, record)
|
||||
}
|
||||
}
|
||||
@ -293,7 +300,7 @@ func CompareBoolean(defaultValue bool, name, current, previous string) bool {
|
||||
return v1 == v2
|
||||
}
|
||||
|
||||
func isManagedRecord(record string, managedRecords []string) bool {
|
||||
func IsManagedRecord(record string, managedRecords []string) bool {
|
||||
for _, r := range managedRecords {
|
||||
if record == r {
|
||||
return true
|
||||
|
@ -48,6 +48,9 @@ type PlanTestSuite struct {
|
||||
domainFilterFiltered2 *endpoint.Endpoint
|
||||
domainFilterFiltered3 *endpoint.Endpoint
|
||||
domainFilterExcluded *endpoint.Endpoint
|
||||
domainFilterFilteredTXT1 *endpoint.Endpoint
|
||||
domainFilterFilteredTXT2 *endpoint.Endpoint
|
||||
domainFilterExcludedTXT *endpoint.Endpoint
|
||||
}
|
||||
|
||||
func (suite *PlanTestSuite) SetupTest() {
|
||||
@ -203,6 +206,21 @@ func (suite *PlanTestSuite) SetupTest() {
|
||||
Targets: endpoint.Targets{"1.1.1.1"},
|
||||
RecordType: "A",
|
||||
}
|
||||
suite.domainFilterFilteredTXT1 = &endpoint.Endpoint{
|
||||
DNSName: "a-foo.domain.tld",
|
||||
Targets: endpoint.Targets{"\"heritage=external-dns,external-dns/owner=owner\""},
|
||||
RecordType: "TXT",
|
||||
}
|
||||
suite.domainFilterFilteredTXT2 = &endpoint.Endpoint{
|
||||
DNSName: "cname-bar.domain.tld",
|
||||
Targets: endpoint.Targets{"\"heritage=external-dns,external-dns/owner=owner\""},
|
||||
RecordType: "TXT",
|
||||
}
|
||||
suite.domainFilterExcludedTXT = &endpoint.Endpoint{
|
||||
DNSName: "cname-bar.otherdomain.tld",
|
||||
Targets: endpoint.Targets{"\"heritage=external-dns,external-dns/owner=owner\""},
|
||||
RecordType: "TXT",
|
||||
}
|
||||
}
|
||||
|
||||
func (suite *PlanTestSuite) TestSyncFirstRound() {
|
||||
@ -667,6 +685,22 @@ func (suite *PlanTestSuite) TestDomainFiltersUpdate() {
|
||||
validateEntries(suite.T(), changes.Delete, expectedDelete)
|
||||
}
|
||||
|
||||
func (suite *PlanTestSuite) TestMissing() {
|
||||
|
||||
missing := []*endpoint.Endpoint{suite.domainFilterFilteredTXT1, suite.domainFilterFilteredTXT2, suite.domainFilterExcludedTXT}
|
||||
expectedCreate := []*endpoint.Endpoint{suite.domainFilterFilteredTXT1, suite.domainFilterFilteredTXT2}
|
||||
|
||||
p := &Plan{
|
||||
Policies: []Policy{&SyncPolicy{}},
|
||||
Missing: missing,
|
||||
DomainFilter: endpoint.NewDomainFilter([]string{"domain.tld"}),
|
||||
ManagedRecords: []string{endpoint.RecordTypeA, endpoint.RecordTypeCNAME},
|
||||
}
|
||||
|
||||
changes := p.Calculate().Changes
|
||||
validateEntries(suite.T(), changes.Create, expectedCreate)
|
||||
}
|
||||
|
||||
func TestPlan(t *testing.T) {
|
||||
suite.Run(t, new(PlanTestSuite))
|
||||
}
|
||||
|
@ -67,6 +67,11 @@ func (sdr *AWSSDRegistry) Records(ctx context.Context) ([]*endpoint.Endpoint, er
|
||||
return records, nil
|
||||
}
|
||||
|
||||
// MissingRecords returns nil because there is no missing records for AWSSD registry
|
||||
func (sdr *AWSSDRegistry) MissingRecords() []*endpoint.Endpoint {
|
||||
return nil
|
||||
}
|
||||
|
||||
// ApplyChanges filters out records not owned the External-DNS, additionally it adds the required label
|
||||
// inserted in the AWS SD instance as a CreateID field
|
||||
func (sdr *AWSSDRegistry) ApplyChanges(ctx context.Context, changes *plan.Changes) error {
|
||||
|
@ -45,6 +45,11 @@ func (im *NoopRegistry) Records(ctx context.Context) ([]*endpoint.Endpoint, erro
|
||||
return im.provider.Records(ctx)
|
||||
}
|
||||
|
||||
// MissingRecords returns nil because there is no missing records for Noop registry
|
||||
func (im *NoopRegistry) MissingRecords() []*endpoint.Endpoint {
|
||||
return nil
|
||||
}
|
||||
|
||||
// ApplyChanges propagates changes to the dns provider
|
||||
func (im *NoopRegistry) ApplyChanges(ctx context.Context, changes *plan.Changes) error {
|
||||
return im.provider.ApplyChanges(ctx, changes)
|
||||
|
@ -35,6 +35,7 @@ type Registry interface {
|
||||
PropertyValuesEqual(attribute string, previous string, current string) bool
|
||||
AdjustEndpoints(endpoints []*endpoint.Endpoint) []*endpoint.Endpoint
|
||||
GetDomainFilter() endpoint.DomainFilterInterface
|
||||
MissingRecords() []*endpoint.Endpoint
|
||||
}
|
||||
|
||||
//TODO(ideahitme): consider moving this to Plan
|
||||
|
@ -47,10 +47,15 @@ type TXTRegistry struct {
|
||||
// registry TXT records corresponding to wildcard records will be invalid (and rejected by most providers), due to
|
||||
// having a '*' appear (not as the first character) - see https://tools.ietf.org/html/rfc1034#section-4.3.3
|
||||
wildcardReplacement string
|
||||
|
||||
managedRecordTypes []string
|
||||
|
||||
// missingTXTRecords stores TXT records which are missing after the migration to the new format
|
||||
missingTXTRecords []*endpoint.Endpoint
|
||||
}
|
||||
|
||||
// NewTXTRegistry returns new TXTRegistry object
|
||||
func NewTXTRegistry(provider provider.Provider, txtPrefix, txtSuffix, ownerID string, cacheInterval time.Duration, txtWildcardReplacement string) (*TXTRegistry, error) {
|
||||
func NewTXTRegistry(provider provider.Provider, txtPrefix, txtSuffix, ownerID string, cacheInterval time.Duration, txtWildcardReplacement string, managedRecordTypes []string) (*TXTRegistry, error) {
|
||||
if ownerID == "" {
|
||||
return nil, errors.New("owner id cannot be empty")
|
||||
}
|
||||
@ -67,6 +72,7 @@ func NewTXTRegistry(provider provider.Provider, txtPrefix, txtSuffix, ownerID st
|
||||
mapper: mapper,
|
||||
cacheInterval: cacheInterval,
|
||||
wildcardReplacement: txtWildcardReplacement,
|
||||
managedRecordTypes: managedRecordTypes,
|
||||
}, nil
|
||||
}
|
||||
|
||||
@ -95,8 +101,10 @@ func (im *TXTRegistry) Records(ctx context.Context) ([]*endpoint.Endpoint, error
|
||||
}
|
||||
|
||||
endpoints := []*endpoint.Endpoint{}
|
||||
missingEndpoints := []*endpoint.Endpoint{}
|
||||
|
||||
labelMap := map[string]endpoint.Labels{}
|
||||
txtRecordsMap := map[string]struct{}{}
|
||||
|
||||
for _, record := range records {
|
||||
if record.RecordType != endpoint.RecordTypeTXT {
|
||||
@ -117,6 +125,7 @@ func (im *TXTRegistry) Records(ctx context.Context) ([]*endpoint.Endpoint, error
|
||||
}
|
||||
key := fmt.Sprintf("%s::%s", im.mapper.toEndpointName(record.DNSName), record.SetIdentifier)
|
||||
labelMap[key] = labels
|
||||
txtRecordsMap[record.DNSName] = struct{}{}
|
||||
}
|
||||
|
||||
for _, ep := range endpoints {
|
||||
@ -135,6 +144,26 @@ func (im *TXTRegistry) Records(ctx context.Context) ([]*endpoint.Endpoint, error
|
||||
ep.Labels[k] = v
|
||||
}
|
||||
}
|
||||
|
||||
// Handle the migration of TXT records created before the new format (introduced in v0.12.0).
|
||||
// The migration is done for the TXT records owned by this instance only.
|
||||
if len(txtRecordsMap) > 0 && ep.Labels[endpoint.OwnerLabelKey] == im.ownerID {
|
||||
if plan.IsManagedRecord(ep.RecordType, im.managedRecordTypes) {
|
||||
// Get desired TXT records and detect the missing ones
|
||||
desiredTXTs := im.generateTXTRecord(ep)
|
||||
missingDesiredTXTs := []*endpoint.Endpoint{}
|
||||
for _, desiredTXT := range desiredTXTs {
|
||||
if _, exists := txtRecordsMap[desiredTXT.DNSName]; !exists {
|
||||
missingDesiredTXTs = append(missingDesiredTXTs, desiredTXT)
|
||||
}
|
||||
}
|
||||
if len(desiredTXTs) > len(missingDesiredTXTs) {
|
||||
// Add missing TXT records only if those are managed (by externaldns) ones.
|
||||
// The unmanaged record has both of the desired TXT records missing.
|
||||
missingEndpoints = append(missingEndpoints, missingDesiredTXTs...)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Update the cache.
|
||||
@ -143,12 +172,25 @@ func (im *TXTRegistry) Records(ctx context.Context) ([]*endpoint.Endpoint, error
|
||||
im.recordsCacheRefreshTime = time.Now()
|
||||
}
|
||||
|
||||
im.missingTXTRecords = missingEndpoints
|
||||
|
||||
return endpoints, nil
|
||||
}
|
||||
|
||||
// MissingRecords returns the TXT record to be created.
|
||||
// The missing records are collected during the run of Records method.
|
||||
func (im *TXTRegistry) MissingRecords() []*endpoint.Endpoint {
|
||||
return im.missingTXTRecords
|
||||
}
|
||||
|
||||
// generateTXTRecord generates both "old" and "new" TXT records.
|
||||
// Once we decide to drop old format we need to drop toTXTName() and rename toNewTXTName
|
||||
func (im *TXTRegistry) generateTXTRecord(r *endpoint.Endpoint) []*endpoint.Endpoint {
|
||||
// Missing TXT records are added to the set of changes.
|
||||
// Obviously, we don't need any other TXT record for them.
|
||||
if r.RecordType == endpoint.RecordTypeTXT {
|
||||
return nil
|
||||
}
|
||||
// old TXT record format
|
||||
txt := endpoint.NewEndpoint(im.mapper.toTXTName(r.DNSName), endpoint.RecordTypeTXT, r.Labels.Serialize(true)).WithSetIdentifier(r.SetIdentifier)
|
||||
txt.ProviderSpecific = r.ProviderSpecific
|
||||
|
@ -41,24 +41,25 @@ func TestTXTRegistry(t *testing.T) {
|
||||
t.Run("TestNewTXTRegistry", testTXTRegistryNew)
|
||||
t.Run("TestRecords", testTXTRegistryRecords)
|
||||
t.Run("TestApplyChanges", testTXTRegistryApplyChanges)
|
||||
t.Run("TestMissingRecords", testTXTRegistryMissingRecords)
|
||||
}
|
||||
|
||||
func testTXTRegistryNew(t *testing.T) {
|
||||
p := inmemory.NewInMemoryProvider()
|
||||
_, err := NewTXTRegistry(p, "txt", "", "", time.Hour, "")
|
||||
_, err := NewTXTRegistry(p, "txt", "", "", time.Hour, "", []string{})
|
||||
require.Error(t, err)
|
||||
|
||||
_, err = NewTXTRegistry(p, "", "txt", "", time.Hour, "")
|
||||
_, err = NewTXTRegistry(p, "", "txt", "", time.Hour, "", []string{})
|
||||
require.Error(t, err)
|
||||
|
||||
r, err := NewTXTRegistry(p, "txt", "", "owner", time.Hour, "")
|
||||
r, err := NewTXTRegistry(p, "txt", "", "owner", time.Hour, "", []string{})
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, p, r.provider)
|
||||
|
||||
r, err = NewTXTRegistry(p, "", "txt", "owner", time.Hour, "")
|
||||
r, err = NewTXTRegistry(p, "", "txt", "owner", time.Hour, "", []string{})
|
||||
require.NoError(t, err)
|
||||
|
||||
_, err = NewTXTRegistry(p, "txt", "txt", "owner", time.Hour, "")
|
||||
_, err = NewTXTRegistry(p, "txt", "txt", "owner", time.Hour, "", []string{})
|
||||
require.Error(t, err)
|
||||
|
||||
_, ok := r.mapper.(affixNameMapper)
|
||||
@ -66,7 +67,7 @@ func testTXTRegistryNew(t *testing.T) {
|
||||
assert.Equal(t, "owner", r.ownerID)
|
||||
assert.Equal(t, p, r.provider)
|
||||
|
||||
r, err = NewTXTRegistry(p, "", "", "owner", time.Hour, "")
|
||||
r, err = NewTXTRegistry(p, "", "", "owner", time.Hour, "", []string{})
|
||||
require.NoError(t, err)
|
||||
|
||||
_, ok = r.mapper.(affixNameMapper)
|
||||
@ -182,13 +183,13 @@ func testTXTRegistryRecordsPrefixed(t *testing.T) {
|
||||
},
|
||||
}
|
||||
|
||||
r, _ := NewTXTRegistry(p, "txt.", "", "owner", time.Hour, "wc")
|
||||
r, _ := NewTXTRegistry(p, "txt.", "", "owner", time.Hour, "wc", []string{})
|
||||
records, _ := r.Records(ctx)
|
||||
|
||||
assert.True(t, testutils.SameEndpoints(records, expectedRecords))
|
||||
|
||||
// Ensure prefix is case-insensitive
|
||||
r, _ = NewTXTRegistry(p, "TxT.", "", "owner", time.Hour, "")
|
||||
r, _ = NewTXTRegistry(p, "TxT.", "", "owner", time.Hour, "", []string{})
|
||||
records, _ = r.Records(ctx)
|
||||
|
||||
assert.True(t, testutils.SameEndpointLabels(records, expectedRecords))
|
||||
@ -287,13 +288,13 @@ func testTXTRegistryRecordsSuffixed(t *testing.T) {
|
||||
},
|
||||
}
|
||||
|
||||
r, _ := NewTXTRegistry(p, "", "-txt", "owner", time.Hour, "")
|
||||
r, _ := NewTXTRegistry(p, "", "-txt", "owner", time.Hour, "", []string{})
|
||||
records, _ := r.Records(ctx)
|
||||
|
||||
assert.True(t, testutils.SameEndpoints(records, expectedRecords))
|
||||
|
||||
// Ensure prefix is case-insensitive
|
||||
r, _ = NewTXTRegistry(p, "", "-TxT", "owner", time.Hour, "")
|
||||
r, _ = NewTXTRegistry(p, "", "-TxT", "owner", time.Hour, "", []string{})
|
||||
records, _ = r.Records(ctx)
|
||||
|
||||
assert.True(t, testutils.SameEndpointLabels(records, expectedRecords))
|
||||
@ -368,7 +369,7 @@ func testTXTRegistryRecordsNoPrefix(t *testing.T) {
|
||||
},
|
||||
}
|
||||
|
||||
r, _ := NewTXTRegistry(p, "", "", "owner", time.Hour, "")
|
||||
r, _ := NewTXTRegistry(p, "", "", "owner", time.Hour, "", []string{})
|
||||
records, _ := r.Records(ctx)
|
||||
|
||||
assert.True(t, testutils.SameEndpoints(records, expectedRecords))
|
||||
@ -411,7 +412,7 @@ func testTXTRegistryApplyChangesWithPrefix(t *testing.T) {
|
||||
newEndpointWithOwner("txt.cname-multiple.test-zone.example.org", "\"heritage=external-dns,external-dns/owner=owner\"", endpoint.RecordTypeTXT, "").WithSetIdentifier("test-set-2"),
|
||||
},
|
||||
})
|
||||
r, _ := NewTXTRegistry(p, "txt.", "", "owner", time.Hour, "")
|
||||
r, _ := NewTXTRegistry(p, "txt.", "", "owner", time.Hour, "", []string{})
|
||||
|
||||
changes := &plan.Changes{
|
||||
Create: []*endpoint.Endpoint{
|
||||
@ -500,7 +501,7 @@ func testTXTRegistryApplyChangesWithTemplatedPrefix(t *testing.T) {
|
||||
p.ApplyChanges(ctx, &plan.Changes{
|
||||
Create: []*endpoint.Endpoint{},
|
||||
})
|
||||
r, _ := NewTXTRegistry(p, "prefix%{record_type}.", "", "owner", time.Hour, "")
|
||||
r, _ := NewTXTRegistry(p, "prefix%{record_type}.", "", "owner", time.Hour, "", []string{})
|
||||
changes := &plan.Changes{
|
||||
Create: []*endpoint.Endpoint{
|
||||
newEndpointWithOwnerResource("new-record-1.test-zone.example.org", "new-loadbalancer-1.lb.com", endpoint.RecordTypeCNAME, "", "ingress/default/my-ingress"),
|
||||
@ -543,7 +544,7 @@ func testTXTRegistryApplyChangesWithTemplatedSuffix(t *testing.T) {
|
||||
p.OnApplyChanges = func(ctx context.Context, got *plan.Changes) {
|
||||
assert.Equal(t, ctxEndpoints, ctx.Value(provider.RecordsContextKey))
|
||||
}
|
||||
r, _ := NewTXTRegistry(p, "", "-%{record_type}suffix", "owner", time.Hour, "")
|
||||
r, _ := NewTXTRegistry(p, "", "-%{record_type}suffix", "owner", time.Hour, "", []string{})
|
||||
changes := &plan.Changes{
|
||||
Create: []*endpoint.Endpoint{
|
||||
newEndpointWithOwnerResource("new-record-1.test-zone.example.org", "new-loadbalancer-1.lb.com", endpoint.RecordTypeCNAME, "", "ingress/default/my-ingress"),
|
||||
@ -608,7 +609,7 @@ func testTXTRegistryApplyChangesWithSuffix(t *testing.T) {
|
||||
newEndpointWithOwner("cname-multiple-txt.test-zone.example.org", "\"heritage=external-dns,external-dns/owner=owner\"", endpoint.RecordTypeTXT, "").WithSetIdentifier("test-set-2"),
|
||||
},
|
||||
})
|
||||
r, _ := NewTXTRegistry(p, "", "-txt", "owner", time.Hour, "wildcard")
|
||||
r, _ := NewTXTRegistry(p, "", "-txt", "owner", time.Hour, "wildcard", []string{})
|
||||
|
||||
changes := &plan.Changes{
|
||||
Create: []*endpoint.Endpoint{
|
||||
@ -712,7 +713,7 @@ func testTXTRegistryApplyChangesNoPrefix(t *testing.T) {
|
||||
newEndpointWithOwner("cname-foobar.test-zone.example.org", "\"heritage=external-dns,external-dns/owner=owner\"", endpoint.RecordTypeTXT, ""),
|
||||
},
|
||||
})
|
||||
r, _ := NewTXTRegistry(p, "", "", "owner", time.Hour, "")
|
||||
r, _ := NewTXTRegistry(p, "", "", "owner", time.Hour, "", []string{})
|
||||
|
||||
changes := &plan.Changes{
|
||||
Create: []*endpoint.Endpoint{
|
||||
@ -766,6 +767,208 @@ func testTXTRegistryApplyChangesNoPrefix(t *testing.T) {
|
||||
require.NoError(t, err)
|
||||
}
|
||||
|
||||
func testTXTRegistryMissingRecords(t *testing.T) {
|
||||
t.Run("No prefix", testTXTRegistryMissingRecordsNoPrefix)
|
||||
t.Run("With Prefix", testTXTRegistryMissingRecordsWithPrefix)
|
||||
}
|
||||
|
||||
func testTXTRegistryMissingRecordsNoPrefix(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
p := inmemory.NewInMemoryProvider()
|
||||
p.CreateZone(testZone)
|
||||
p.ApplyChanges(ctx, &plan.Changes{
|
||||
Create: []*endpoint.Endpoint{
|
||||
newEndpointWithOwner("oldformat.test-zone.example.org", "foo.loadbalancer.com", endpoint.RecordTypeCNAME, ""),
|
||||
newEndpointWithOwner("oldformat.test-zone.example.org", "\"heritage=external-dns,external-dns/owner=owner\"", endpoint.RecordTypeTXT, ""),
|
||||
newEndpointWithOwner("oldformat2.test-zone.example.org", "bar.loadbalancer.com", endpoint.RecordTypeA, ""),
|
||||
newEndpointWithOwner("oldformat2.test-zone.example.org", "\"heritage=external-dns,external-dns/owner=owner\"", endpoint.RecordTypeTXT, ""),
|
||||
newEndpointWithOwner("newformat.test-zone.example.org", "foobar.nameserver.com", endpoint.RecordTypeNS, ""),
|
||||
newEndpointWithOwner("ns-newformat.test-zone.example.org", "\"heritage=external-dns,external-dns/owner=owner\"", endpoint.RecordTypeTXT, ""),
|
||||
newEndpointWithOwner("newformat.test-zone.example.org", "\"heritage=external-dns,external-dns/owner=owner\"", endpoint.RecordTypeTXT, ""),
|
||||
newEndpointWithOwner("noheritage.test-zone.example.org", "random", endpoint.RecordTypeTXT, ""),
|
||||
newEndpointWithOwner("oldformat-otherowner.test-zone.example.org", "bar.loadbalancer.com", endpoint.RecordTypeA, ""),
|
||||
newEndpointWithOwner("oldformat-otherowner.test-zone.example.org", "\"heritage=external-dns,external-dns/owner=otherowner\"", endpoint.RecordTypeTXT, ""),
|
||||
endpoint.NewEndpoint("unmanaged1.test-zone.example.org", endpoint.RecordTypeA, "unmanaged1.loadbalancer.com"),
|
||||
endpoint.NewEndpoint("unmanaged2.test-zone.example.org", endpoint.RecordTypeCNAME, "unmanaged2.loadbalancer.com"),
|
||||
},
|
||||
})
|
||||
expectedRecords := []*endpoint.Endpoint{
|
||||
{
|
||||
DNSName: "oldformat.test-zone.example.org",
|
||||
Targets: endpoint.Targets{"foo.loadbalancer.com"},
|
||||
RecordType: endpoint.RecordTypeCNAME,
|
||||
Labels: map[string]string{
|
||||
// owner was added from the TXT record's target
|
||||
endpoint.OwnerLabelKey: "owner",
|
||||
},
|
||||
},
|
||||
{
|
||||
DNSName: "oldformat2.test-zone.example.org",
|
||||
Targets: endpoint.Targets{"bar.loadbalancer.com"},
|
||||
RecordType: endpoint.RecordTypeA,
|
||||
Labels: map[string]string{
|
||||
endpoint.OwnerLabelKey: "owner",
|
||||
},
|
||||
},
|
||||
{
|
||||
DNSName: "newformat.test-zone.example.org",
|
||||
Targets: endpoint.Targets{"foobar.nameserver.com"},
|
||||
RecordType: endpoint.RecordTypeNS,
|
||||
Labels: map[string]string{
|
||||
endpoint.OwnerLabelKey: "owner",
|
||||
},
|
||||
},
|
||||
// Only TXT records with the wrong heritage are returned by Records()
|
||||
{
|
||||
DNSName: "noheritage.test-zone.example.org",
|
||||
Targets: endpoint.Targets{"random"},
|
||||
RecordType: endpoint.RecordTypeTXT,
|
||||
Labels: map[string]string{
|
||||
// No owner because it's not external-dns heritage
|
||||
endpoint.OwnerLabelKey: "",
|
||||
},
|
||||
},
|
||||
{
|
||||
DNSName: "oldformat-otherowner.test-zone.example.org",
|
||||
Targets: endpoint.Targets{"bar.loadbalancer.com"},
|
||||
RecordType: endpoint.RecordTypeA,
|
||||
Labels: map[string]string{
|
||||
// Records() retrieves all the records of the zone, no matter the owner
|
||||
endpoint.OwnerLabelKey: "otherowner",
|
||||
},
|
||||
},
|
||||
{
|
||||
DNSName: "unmanaged1.test-zone.example.org",
|
||||
Targets: endpoint.Targets{"unmanaged1.loadbalancer.com"},
|
||||
RecordType: endpoint.RecordTypeA,
|
||||
},
|
||||
{
|
||||
DNSName: "unmanaged2.test-zone.example.org",
|
||||
Targets: endpoint.Targets{"unmanaged2.loadbalancer.com"},
|
||||
RecordType: endpoint.RecordTypeCNAME,
|
||||
},
|
||||
}
|
||||
|
||||
expectedMissingRecords := []*endpoint.Endpoint{
|
||||
{
|
||||
DNSName: "cname-oldformat.test-zone.example.org",
|
||||
// owner is taken from the source record (A, CNAME, etc.)
|
||||
Targets: endpoint.Targets{"\"heritage=external-dns,external-dns/owner=owner\""},
|
||||
RecordType: endpoint.RecordTypeTXT,
|
||||
},
|
||||
{
|
||||
DNSName: "a-oldformat2.test-zone.example.org",
|
||||
Targets: endpoint.Targets{"\"heritage=external-dns,external-dns/owner=owner\""},
|
||||
RecordType: endpoint.RecordTypeTXT,
|
||||
},
|
||||
}
|
||||
|
||||
r, _ := NewTXTRegistry(p, "", "", "owner", time.Hour, "wc", []string{endpoint.RecordTypeCNAME, endpoint.RecordTypeA, endpoint.RecordTypeNS})
|
||||
records, _ := r.Records(ctx)
|
||||
missingRecords := r.MissingRecords()
|
||||
|
||||
assert.True(t, testutils.SameEndpoints(records, expectedRecords))
|
||||
assert.True(t, testutils.SameEndpoints(missingRecords, expectedMissingRecords))
|
||||
}
|
||||
|
||||
func testTXTRegistryMissingRecordsWithPrefix(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
p := inmemory.NewInMemoryProvider()
|
||||
p.CreateZone(testZone)
|
||||
p.ApplyChanges(ctx, &plan.Changes{
|
||||
Create: []*endpoint.Endpoint{
|
||||
newEndpointWithOwner("oldformat.test-zone.example.org", "foo.loadbalancer.com", endpoint.RecordTypeCNAME, ""),
|
||||
newEndpointWithOwner("txt.oldformat.test-zone.example.org", "\"heritage=external-dns,external-dns/owner=owner\"", endpoint.RecordTypeTXT, ""),
|
||||
newEndpointWithOwner("oldformat2.test-zone.example.org", "bar.loadbalancer.com", endpoint.RecordTypeA, ""),
|
||||
newEndpointWithOwner("txt.oldformat2.test-zone.example.org", "\"heritage=external-dns,external-dns/owner=owner\"", endpoint.RecordTypeTXT, ""),
|
||||
newEndpointWithOwner("newformat.test-zone.example.org", "foobar.nameserver.com", endpoint.RecordTypeNS, ""),
|
||||
newEndpointWithOwner("txt.ns-newformat.test-zone.example.org", "\"heritage=external-dns,external-dns/owner=owner\"", endpoint.RecordTypeTXT, ""),
|
||||
newEndpointWithOwner("txt.newformat.test-zone.example.org", "\"heritage=external-dns,external-dns/owner=owner\"", endpoint.RecordTypeTXT, ""),
|
||||
newEndpointWithOwner("noheritage.test-zone.example.org", "random", endpoint.RecordTypeTXT, ""),
|
||||
newEndpointWithOwner("oldformat-otherowner.test-zone.example.org", "bar.loadbalancer.com", endpoint.RecordTypeA, ""),
|
||||
newEndpointWithOwner("txt.oldformat-otherowner.test-zone.example.org", "\"heritage=external-dns,external-dns/owner=otherowner\"", endpoint.RecordTypeTXT, ""),
|
||||
endpoint.NewEndpoint("unmanaged1.test-zone.example.org", endpoint.RecordTypeA, "unmanaged1.loadbalancer.com"),
|
||||
endpoint.NewEndpoint("unmanaged2.test-zone.example.org", endpoint.RecordTypeCNAME, "unmanaged2.loadbalancer.com"),
|
||||
},
|
||||
})
|
||||
expectedRecords := []*endpoint.Endpoint{
|
||||
{
|
||||
DNSName: "oldformat.test-zone.example.org",
|
||||
Targets: endpoint.Targets{"foo.loadbalancer.com"},
|
||||
RecordType: endpoint.RecordTypeCNAME,
|
||||
Labels: map[string]string{
|
||||
// owner was added from the TXT record's target
|
||||
endpoint.OwnerLabelKey: "owner",
|
||||
},
|
||||
},
|
||||
{
|
||||
DNSName: "oldformat2.test-zone.example.org",
|
||||
Targets: endpoint.Targets{"bar.loadbalancer.com"},
|
||||
RecordType: endpoint.RecordTypeA,
|
||||
Labels: map[string]string{
|
||||
endpoint.OwnerLabelKey: "owner",
|
||||
},
|
||||
},
|
||||
{
|
||||
DNSName: "newformat.test-zone.example.org",
|
||||
Targets: endpoint.Targets{"foobar.nameserver.com"},
|
||||
RecordType: endpoint.RecordTypeNS,
|
||||
Labels: map[string]string{
|
||||
endpoint.OwnerLabelKey: "owner",
|
||||
},
|
||||
},
|
||||
{
|
||||
DNSName: "noheritage.test-zone.example.org",
|
||||
Targets: endpoint.Targets{"random"},
|
||||
RecordType: endpoint.RecordTypeTXT,
|
||||
Labels: map[string]string{
|
||||
// No owner because it's not external-dns heritage
|
||||
endpoint.OwnerLabelKey: "",
|
||||
},
|
||||
},
|
||||
{
|
||||
DNSName: "oldformat-otherowner.test-zone.example.org",
|
||||
Targets: endpoint.Targets{"bar.loadbalancer.com"},
|
||||
RecordType: endpoint.RecordTypeA,
|
||||
Labels: map[string]string{
|
||||
// All the records of the zone are retrieved, no matter the owner
|
||||
endpoint.OwnerLabelKey: "otherowner",
|
||||
},
|
||||
},
|
||||
{
|
||||
DNSName: "unmanaged1.test-zone.example.org",
|
||||
Targets: endpoint.Targets{"unmanaged1.loadbalancer.com"},
|
||||
RecordType: endpoint.RecordTypeA,
|
||||
},
|
||||
{
|
||||
DNSName: "unmanaged2.test-zone.example.org",
|
||||
Targets: endpoint.Targets{"unmanaged2.loadbalancer.com"},
|
||||
RecordType: endpoint.RecordTypeCNAME,
|
||||
},
|
||||
}
|
||||
|
||||
expectedMissingRecords := []*endpoint.Endpoint{
|
||||
{
|
||||
DNSName: "txt.cname-oldformat.test-zone.example.org",
|
||||
// owner is taken from the source record (A, CNAME, etc.)
|
||||
Targets: endpoint.Targets{"\"heritage=external-dns,external-dns/owner=owner\""},
|
||||
RecordType: endpoint.RecordTypeTXT,
|
||||
},
|
||||
{
|
||||
DNSName: "txt.a-oldformat2.test-zone.example.org",
|
||||
Targets: endpoint.Targets{"\"heritage=external-dns,external-dns/owner=owner\""},
|
||||
RecordType: endpoint.RecordTypeTXT,
|
||||
},
|
||||
}
|
||||
|
||||
r, _ := NewTXTRegistry(p, "txt.", "", "owner", time.Hour, "wc", []string{endpoint.RecordTypeCNAME, endpoint.RecordTypeA, endpoint.RecordTypeNS})
|
||||
records, _ := r.Records(ctx)
|
||||
missingRecords := r.MissingRecords()
|
||||
|
||||
assert.True(t, testutils.SameEndpoints(records, expectedRecords))
|
||||
assert.True(t, testutils.SameEndpoints(missingRecords, expectedMissingRecords))
|
||||
}
|
||||
|
||||
func TestCacheMethods(t *testing.T) {
|
||||
cache := []*endpoint.Endpoint{
|
||||
newEndpointWithOwner("thing.com", "1.2.3.4", "A", "owner"),
|
||||
@ -877,7 +1080,7 @@ func TestNewTXTScheme(t *testing.T) {
|
||||
newEndpointWithOwner("cname-foobar.test-zone.example.org", "\"heritage=external-dns,external-dns/owner=owner\"", endpoint.RecordTypeTXT, ""),
|
||||
},
|
||||
})
|
||||
r, _ := NewTXTRegistry(p, "", "", "owner", time.Hour, "")
|
||||
r, _ := NewTXTRegistry(p, "", "", "owner", time.Hour, "", []string{})
|
||||
|
||||
changes := &plan.Changes{
|
||||
Create: []*endpoint.Endpoint{
|
||||
@ -938,18 +1141,18 @@ func TestGenerateTXT(t *testing.T) {
|
||||
DNSName: "foo.test-zone.example.org",
|
||||
Targets: endpoint.Targets{"\"heritage=external-dns,external-dns/owner=owner\""},
|
||||
RecordType: endpoint.RecordTypeTXT,
|
||||
Labels: map[string]string{},
|
||||
Labels: map[string]string{},
|
||||
},
|
||||
{
|
||||
DNSName: "cname-foo.test-zone.example.org",
|
||||
Targets: endpoint.Targets{"\"heritage=external-dns,external-dns/owner=owner\""},
|
||||
RecordType: endpoint.RecordTypeTXT,
|
||||
Labels: map[string]string{},
|
||||
Labels: map[string]string{},
|
||||
},
|
||||
}
|
||||
p := inmemory.NewInMemoryProvider()
|
||||
p.CreateZone(testZone)
|
||||
r, _ := NewTXTRegistry(p, "", "", "owner", time.Hour, "")
|
||||
r, _ := NewTXTRegistry(p, "", "", "owner", time.Hour, "", []string{})
|
||||
gotTXT := r.generateTXTRecord(record)
|
||||
assert.Equal(t, expectedTXT, gotTXT)
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user