Add --exclude-record-types flag

This commit is contained in:
John Gardiner Myers 2023-06-28 20:02:54 -07:00
parent fa332e9ed3
commit 94713c20c6
9 changed files with 97 additions and 56 deletions

View File

@ -181,8 +181,10 @@ type Controller struct {
nextRunAt time.Time nextRunAt time.Time
// The nextRunAtMux is for atomic updating of nextRunAt // The nextRunAtMux is for atomic updating of nextRunAt
nextRunAtMux sync.Mutex nextRunAtMux sync.Mutex
// DNS record types that will be considered for management // MangedRecordTypes are DNS record types that will be considered for management.
ManagedRecordTypes []string ManagedRecordTypes []string
// ExcludeRecordTypes are DNS record types that will be excluded from management.
ExcludeRecordTypes []string
// MinEventSyncInterval is used as window for batching events // MinEventSyncInterval is used as window for batching events
MinEventSyncInterval time.Duration MinEventSyncInterval time.Duration
} }
@ -227,6 +229,7 @@ func (c *Controller) RunOnce(ctx context.Context) error {
Desired: endpoints, Desired: endpoints,
DomainFilter: endpoint.MatchAllDomainFilters{&c.DomainFilter, &registryFilter}, DomainFilter: endpoint.MatchAllDomainFilters{&c.DomainFilter, &registryFilter},
ManagedRecords: c.ManagedRecordTypes, ManagedRecords: c.ManagedRecordTypes,
ExcludeRecords: c.ExcludeRecordTypes,
OwnerID: c.Registry.OwnerID(), OwnerID: c.Registry.OwnerID(),
} }

View File

@ -416,11 +416,11 @@ func main() {
if cfg.AWSDynamoDBRegion != "" { if cfg.AWSDynamoDBRegion != "" {
config = config.WithRegion(cfg.AWSDynamoDBRegion) config = config.WithRegion(cfg.AWSDynamoDBRegion)
} }
r, err = registry.NewDynamoDBRegistry(p, cfg.TXTOwnerID, dynamodb.New(awsSession, config), cfg.AWSDynamoDBTable, cfg.TXTPrefix, cfg.TXTSuffix, cfg.TXTWildcardReplacement, cfg.ManagedDNSRecordTypes, []byte(cfg.TXTEncryptAESKey), cfg.TXTCacheInterval) r, err = registry.NewDynamoDBRegistry(p, cfg.TXTOwnerID, dynamodb.New(awsSession, config), cfg.AWSDynamoDBTable, cfg.TXTPrefix, cfg.TXTSuffix, cfg.TXTWildcardReplacement, cfg.ManagedDNSRecordTypes, cfg.ExcludeDNSRecordTypes, []byte(cfg.TXTEncryptAESKey), cfg.TXTCacheInterval)
case "noop": case "noop":
r, err = registry.NewNoopRegistry(p) r, err = registry.NewNoopRegistry(p)
case "txt": case "txt":
r, err = registry.NewTXTRegistry(p, cfg.TXTPrefix, cfg.TXTSuffix, cfg.TXTOwnerID, cfg.TXTCacheInterval, cfg.TXTWildcardReplacement, cfg.ManagedDNSRecordTypes, cfg.TXTEncryptEnabled, []byte(cfg.TXTEncryptAESKey)) r, err = registry.NewTXTRegistry(p, cfg.TXTPrefix, cfg.TXTSuffix, cfg.TXTOwnerID, cfg.TXTCacheInterval, cfg.TXTWildcardReplacement, cfg.ManagedDNSRecordTypes, cfg.ExcludeDNSRecordTypes, cfg.TXTEncryptEnabled, []byte(cfg.TXTEncryptAESKey))
case "aws-sd": case "aws-sd":
r, err = registry.NewAWSSDRegistry(p.(*awssd.AWSSDProvider), cfg.TXTOwnerID) r, err = registry.NewAWSSDRegistry(p.(*awssd.AWSSDProvider), cfg.TXTOwnerID)
default: default:
@ -443,6 +443,7 @@ func main() {
Interval: cfg.Interval, Interval: cfg.Interval,
DomainFilter: domainFilter, DomainFilter: domainFilter,
ManagedRecordTypes: cfg.ManagedDNSRecordTypes, ManagedRecordTypes: cfg.ManagedDNSRecordTypes,
ExcludeRecordTypes: cfg.ExcludeDNSRecordTypes,
MinEventSyncInterval: cfg.MinEventSyncInterval, MinEventSyncInterval: cfg.MinEventSyncInterval,
} }

View File

@ -194,6 +194,7 @@ type Config struct {
TransIPPrivateKeyFile string TransIPPrivateKeyFile string
DigitalOceanAPIPageSize int DigitalOceanAPIPageSize int
ManagedDNSRecordTypes []string ManagedDNSRecordTypes []string
ExcludeDNSRecordTypes []string
GoDaddyAPIKey string `secure:"yes"` GoDaddyAPIKey string `secure:"yes"`
GoDaddySecretKey string `secure:"yes"` GoDaddySecretKey string `secure:"yes"`
GoDaddyTTL int64 GoDaddyTTL int64
@ -342,6 +343,7 @@ var defaultConfig = &Config{
TransIPPrivateKeyFile: "", TransIPPrivateKeyFile: "",
DigitalOceanAPIPageSize: 50, DigitalOceanAPIPageSize: 50,
ManagedDNSRecordTypes: []string{endpoint.RecordTypeA, endpoint.RecordTypeAAAA, endpoint.RecordTypeCNAME}, ManagedDNSRecordTypes: []string{endpoint.RecordTypeA, endpoint.RecordTypeAAAA, endpoint.RecordTypeCNAME},
ExcludeDNSRecordTypes: []string{},
GoDaddyAPIKey: "", GoDaddyAPIKey: "",
GoDaddySecretKey: "", GoDaddySecretKey: "",
GoDaddyTTL: 600, GoDaddyTTL: 600,
@ -437,7 +439,8 @@ func (cfg *Config) ParseFlags(args []string) error {
app.Flag("crd-source-apiversion", "API version of the CRD for crd source, e.g. `externaldns.k8s.io/v1alpha1`, valid only when using crd source").Default(defaultConfig.CRDSourceAPIVersion).StringVar(&cfg.CRDSourceAPIVersion) app.Flag("crd-source-apiversion", "API version of the CRD for crd source, e.g. `externaldns.k8s.io/v1alpha1`, valid only when using crd source").Default(defaultConfig.CRDSourceAPIVersion).StringVar(&cfg.CRDSourceAPIVersion)
app.Flag("crd-source-kind", "Kind of the CRD for the crd source in API group and version specified by crd-source-apiversion").Default(defaultConfig.CRDSourceKind).StringVar(&cfg.CRDSourceKind) app.Flag("crd-source-kind", "Kind of the CRD for the crd source in API group and version specified by crd-source-apiversion").Default(defaultConfig.CRDSourceKind).StringVar(&cfg.CRDSourceKind)
app.Flag("service-type-filter", "The service types to take care about (default: all, expected: ClusterIP, NodePort, LoadBalancer or ExternalName)").StringsVar(&cfg.ServiceTypeFilter) app.Flag("service-type-filter", "The service types to take care about (default: all, expected: ClusterIP, NodePort, LoadBalancer or ExternalName)").StringsVar(&cfg.ServiceTypeFilter)
app.Flag("managed-record-types", "Record types to manage; specify multiple times to include many; (default: A, AAAA, CNAME) (supported records: CNAME, A, AAAA, NS").Default("A", "AAAA", "CNAME").StringsVar(&cfg.ManagedDNSRecordTypes) app.Flag("managed-record-types", "Record types to manage; specify multiple times to include many; (default: A, AAAA, CNAME) (supported records: A, AAAA, CNAME, NS, SRV, TXT)").Default("A", "AAAA", "CNAME").StringsVar(&cfg.ManagedDNSRecordTypes)
app.Flag("exclude-record-types", "Record types to exclude from management; specify multiple times to exclude many; (optional)").Default().StringsVar(&cfg.ExcludeDNSRecordTypes)
app.Flag("default-targets", "Set globally default host/IP that will apply as a target instead of source addresses. Specify multiple times for multiple targets (optional)").StringsVar(&cfg.DefaultTargets) app.Flag("default-targets", "Set globally default host/IP that will apply as a target instead of source addresses. Specify multiple times for multiple targets (optional)").StringsVar(&cfg.DefaultTargets)
app.Flag("target-net-filter", "Limit possible targets by a net filter; specify multiple times for multiple possible nets (optional)").StringsVar(&cfg.TargetNetFilter) app.Flag("target-net-filter", "Limit possible targets by a net filter; specify multiple times for multiple possible nets (optional)").StringsVar(&cfg.TargetNetFilter)
app.Flag("exclude-target-net", "Exclude target nets (optional)").StringsVar(&cfg.ExcludeTargetNets) app.Flag("exclude-target-net", "Exclude target nets (optional)").StringsVar(&cfg.ExcludeTargetNets)

View File

@ -44,8 +44,10 @@ type Plan struct {
Changes *Changes Changes *Changes
// DomainFilter matches DNS names // DomainFilter matches DNS names
DomainFilter endpoint.MatchAllDomainFilters DomainFilter endpoint.MatchAllDomainFilters
// DNS record types that will be considered for management // ManagedRecords are DNS record types that will be considered for management.
ManagedRecords []string ManagedRecords []string
// ExcludeRecords are DNS record types that will be excluded from management.
ExcludeRecords []string
// OwnerID of records to manage // OwnerID of records to manage
OwnerID string OwnerID string
} }
@ -170,10 +172,10 @@ func (p *Plan) Calculate() *Plan {
p.DomainFilter = endpoint.MatchAllDomainFilters(nil) p.DomainFilter = endpoint.MatchAllDomainFilters(nil)
} }
for _, current := range filterRecordsForPlan(p.Current, p.DomainFilter, p.ManagedRecords) { for _, current := range filterRecordsForPlan(p.Current, p.DomainFilter, p.ManagedRecords, p.ExcludeRecords) {
t.addCurrent(current) t.addCurrent(current)
} }
for _, desired := range filterRecordsForPlan(p.Desired, p.DomainFilter, p.ManagedRecords) { for _, desired := range filterRecordsForPlan(p.Desired, p.DomainFilter, p.ManagedRecords, p.ExcludeRecords) {
t.addCandidate(desired) t.addCandidate(desired)
} }
@ -313,7 +315,7 @@ func (p *Plan) shouldUpdateProviderSpecific(desired, current *endpoint.Endpoint)
// Per RFC 1034, CNAME records conflict with all other records - it is the // Per RFC 1034, CNAME records conflict with all other records - it is the
// only record with this property. The behavior of the planner may need to be // only record with this property. The behavior of the planner may need to be
// made more sophisticated to codify this. // made more sophisticated to codify this.
func filterRecordsForPlan(records []*endpoint.Endpoint, domainFilter endpoint.MatchAllDomainFilters, managedRecords []string) []*endpoint.Endpoint { func filterRecordsForPlan(records []*endpoint.Endpoint, domainFilter endpoint.MatchAllDomainFilters, managedRecords, excludeRecords []string) []*endpoint.Endpoint {
filtered := []*endpoint.Endpoint{} filtered := []*endpoint.Endpoint{}
for _, record := range records { for _, record := range records {
@ -322,7 +324,7 @@ func filterRecordsForPlan(records []*endpoint.Endpoint, domainFilter endpoint.Ma
log.Debugf("ignoring record %s that does not match domain filter", record.DNSName) log.Debugf("ignoring record %s that does not match domain filter", record.DNSName)
continue continue
} }
if IsManagedRecord(record.RecordType, managedRecords) { if IsManagedRecord(record.RecordType, managedRecords, excludeRecords) {
filtered = append(filtered, record) filtered = append(filtered, record)
} }
} }
@ -365,7 +367,12 @@ func CompareBoolean(defaultValue bool, name, current, previous string) bool {
return v1 == v2 return v1 == v2
} }
func IsManagedRecord(record string, managedRecords []string) bool { func IsManagedRecord(record string, managedRecords, excludeRecords []string) bool {
for _, r := range excludeRecords {
if record == r {
return false
}
}
for _, r := range managedRecords { for _, r := range managedRecords {
if record == r { if record == r {
return true return true

View File

@ -681,6 +681,29 @@ func (suite *PlanTestSuite) TestIgnoreTXT() {
validateEntries(suite.T(), changes.Delete, expectedDelete) validateEntries(suite.T(), changes.Delete, expectedDelete)
} }
func (suite *PlanTestSuite) TestExcludeTXT() {
current := []*endpoint.Endpoint{suite.fooV2TXT}
desired := []*endpoint.Endpoint{suite.fooV2Cname}
expectedCreate := []*endpoint.Endpoint{suite.fooV2Cname}
expectedUpdateOld := []*endpoint.Endpoint{}
expectedUpdateNew := []*endpoint.Endpoint{}
expectedDelete := []*endpoint.Endpoint{}
p := &Plan{
Policies: []Policy{&SyncPolicy{}},
Current: current,
Desired: desired,
ManagedRecords: []string{endpoint.RecordTypeA, endpoint.RecordTypeCNAME, endpoint.RecordTypeTXT},
ExcludeRecords: []string{endpoint.RecordTypeTXT},
}
changes := p.Calculate().Changes
validateEntries(suite.T(), changes.Create, expectedCreate)
validateEntries(suite.T(), changes.UpdateNew, expectedUpdateNew)
validateEntries(suite.T(), changes.UpdateOld, expectedUpdateOld)
validateEntries(suite.T(), changes.Delete, expectedDelete)
}
func (suite *PlanTestSuite) TestIgnoreTargetCase() { func (suite *PlanTestSuite) TestIgnoreTargetCase() {
current := []*endpoint.Endpoint{suite.fooV2Cname} current := []*endpoint.Endpoint{suite.fooV2Cname}
desired := []*endpoint.Endpoint{suite.fooV2CnameUppercase} desired := []*endpoint.Endpoint{suite.fooV2CnameUppercase}

View File

@ -53,6 +53,7 @@ type DynamoDBRegistry struct {
mapper nameMapper mapper nameMapper
wildcardReplacement string wildcardReplacement string
managedRecordTypes []string managedRecordTypes []string
excludeRecordTypes []string
txtEncryptAESKey []byte txtEncryptAESKey []byte
// cache the dynamodb records owned by us. // cache the dynamodb records owned by us.
@ -68,7 +69,7 @@ type DynamoDBRegistry struct {
const dynamodbAttributeMigrate = "dynamodb/needs-migration" const dynamodbAttributeMigrate = "dynamodb/needs-migration"
// NewDynamoDBRegistry returns a new DynamoDBRegistry object. // NewDynamoDBRegistry returns a new DynamoDBRegistry object.
func NewDynamoDBRegistry(provider provider.Provider, ownerID string, dynamodbAPI DynamoDBAPI, table string, txtPrefix, txtSuffix, txtWildcardReplacement string, managedRecordTypes []string, txtEncryptAESKey []byte, cacheInterval time.Duration) (*DynamoDBRegistry, error) { func NewDynamoDBRegistry(provider provider.Provider, ownerID string, dynamodbAPI DynamoDBAPI, table string, txtPrefix, txtSuffix, txtWildcardReplacement string, managedRecordTypes, excludeRecordTypes []string, txtEncryptAESKey []byte, cacheInterval time.Duration) (*DynamoDBRegistry, error) {
if ownerID == "" { if ownerID == "" {
return nil, errors.New("owner id cannot be empty") return nil, errors.New("owner id cannot be empty")
} }
@ -95,6 +96,7 @@ func NewDynamoDBRegistry(provider provider.Provider, ownerID string, dynamodbAPI
mapper: mapper, mapper: mapper,
wildcardReplacement: txtWildcardReplacement, wildcardReplacement: txtWildcardReplacement,
managedRecordTypes: managedRecordTypes, managedRecordTypes: managedRecordTypes,
excludeRecordTypes: excludeRecordTypes,
txtEncryptAESKey: txtEncryptAESKey, txtEncryptAESKey: txtEncryptAESKey,
cacheInterval: cacheInterval, cacheInterval: cacheInterval,
}, nil }, nil
@ -194,7 +196,7 @@ func (im *DynamoDBRegistry) Records(ctx context.Context) ([]*endpoint.Endpoint,
} }
// Remove any unused TXT ownership records owned by us // Remove any unused TXT ownership records owned by us
if len(txtRecordsMap) > 0 && !plan.IsManagedRecord(endpoint.RecordTypeTXT, im.managedRecordTypes) { if len(txtRecordsMap) > 0 && !plan.IsManagedRecord(endpoint.RecordTypeTXT, im.managedRecordTypes, im.excludeRecordTypes) {
log.Infof("Old TXT ownership records will not be deleted because \"TXT\" is not in the set of managed record types.") log.Infof("Old TXT ownership records will not be deleted because \"TXT\" is not in the set of managed record types.")
} }
for _, record := range txtRecordsMap { for _, record := range txtRecordsMap {

View File

@ -38,31 +38,31 @@ import (
func TestDynamoDBRegistryNew(t *testing.T) { func TestDynamoDBRegistryNew(t *testing.T) {
api, p := newDynamoDBAPIStub(t, nil) api, p := newDynamoDBAPIStub(t, nil)
_, err := NewDynamoDBRegistry(p, "test-owner", api, "test-table", "", "", "", []string{}, []byte(""), time.Hour) _, err := NewDynamoDBRegistry(p, "test-owner", api, "test-table", "", "", "", []string{}, []string{}, []byte(""), time.Hour)
require.NoError(t, err) require.NoError(t, err)
_, err = NewDynamoDBRegistry(p, "test-owner", api, "test-table", "testPrefix", "", "", []string{}, []byte(""), time.Hour) _, err = NewDynamoDBRegistry(p, "test-owner", api, "test-table", "testPrefix", "", "", []string{}, []string{}, []byte(""), time.Hour)
require.NoError(t, err) require.NoError(t, err)
_, err = NewDynamoDBRegistry(p, "test-owner", api, "test-table", "", "testSuffix", "", []string{}, []byte(""), time.Hour) _, err = NewDynamoDBRegistry(p, "test-owner", api, "test-table", "", "testSuffix", "", []string{}, []string{}, []byte(""), time.Hour)
require.NoError(t, err) require.NoError(t, err)
_, err = NewDynamoDBRegistry(p, "test-owner", api, "test-table", "", "", "testWildcard", []string{}, []byte(""), time.Hour) _, err = NewDynamoDBRegistry(p, "test-owner", api, "test-table", "", "", "testWildcard", []string{}, []string{}, []byte(""), time.Hour)
require.NoError(t, err) require.NoError(t, err)
_, err = NewDynamoDBRegistry(p, "test-owner", api, "test-table", "", "", "testWildcard", []string{}, []byte(";k&l)nUC/33:{?d{3)54+,AD?]SX%yh^"), time.Hour) _, err = NewDynamoDBRegistry(p, "test-owner", api, "test-table", "", "", "testWildcard", []string{}, []string{}, []byte(";k&l)nUC/33:{?d{3)54+,AD?]SX%yh^"), time.Hour)
require.NoError(t, err) require.NoError(t, err)
_, err = NewDynamoDBRegistry(p, "", api, "test-table", "", "", "", []string{}, []byte(""), time.Hour) _, err = NewDynamoDBRegistry(p, "", api, "test-table", "", "", "", []string{}, []string{}, []byte(""), time.Hour)
require.EqualError(t, err, "owner id cannot be empty") require.EqualError(t, err, "owner id cannot be empty")
_, err = NewDynamoDBRegistry(p, "test-owner", api, "", "", "", "", []string{}, []byte(""), time.Hour) _, err = NewDynamoDBRegistry(p, "test-owner", api, "", "", "", "", []string{}, []string{}, []byte(""), time.Hour)
require.EqualError(t, err, "table cannot be empty") require.EqualError(t, err, "table cannot be empty")
_, err = NewDynamoDBRegistry(p, "test-owner", api, "test-table", "", "", "", []string{}, []byte(";k&l)nUC/33:{?d{3)54+,AD?]SX%yh^x"), time.Hour) _, err = NewDynamoDBRegistry(p, "test-owner", api, "test-table", "", "", "", []string{}, []string{}, []byte(";k&l)nUC/33:{?d{3)54+,AD?]SX%yh^x"), time.Hour)
require.EqualError(t, err, "the AES Encryption key must have a length of 32 bytes") require.EqualError(t, err, "the AES Encryption key must have a length of 32 bytes")
_, err = NewDynamoDBRegistry(p, "test-owner", api, "test-table", "testPrefix", "testSuffix", "", []string{}, []byte(""), time.Hour) _, err = NewDynamoDBRegistry(p, "test-owner", api, "test-table", "testPrefix", "testSuffix", "", []string{}, []string{}, []byte(""), time.Hour)
require.EqualError(t, err, "txt-prefix and txt-suffix are mutually exclusive") require.EqualError(t, err, "txt-prefix and txt-suffix are mutually exclusive")
} }
@ -112,7 +112,7 @@ func TestDynamoDBRegistryRecordsBadTable(t *testing.T) {
api, p := newDynamoDBAPIStub(t, nil) api, p := newDynamoDBAPIStub(t, nil)
tc.setup(&api.tableDescription) tc.setup(&api.tableDescription)
r, _ := NewDynamoDBRegistry(p, "test-owner", api, "test-table", "", "", "", []string{}, nil, time.Hour) r, _ := NewDynamoDBRegistry(p, "test-owner", api, "test-table", "", "", "", []string{}, []string{}, nil, time.Hour)
_, err := r.Records(context.Background()) _, err := r.Records(context.Background())
assert.EqualError(t, err, tc.expected) assert.EqualError(t, err, tc.expected)
@ -198,7 +198,7 @@ func TestDynamoDBRegistryRecords(t *testing.T) {
}, },
} }
r, _ := NewDynamoDBRegistry(p, "test-owner", api, "test-table", "txt.", "", "", []string{}, nil, time.Hour) r, _ := NewDynamoDBRegistry(p, "test-owner", api, "test-table", "txt.", "", "", []string{}, []string{}, nil, time.Hour)
_ = p.(*wrappedProvider).Provider.ApplyChanges(context.Background(), &plan.Changes{ _ = p.(*wrappedProvider).Provider.ApplyChanges(context.Background(), &plan.Changes{
Create: []*endpoint.Endpoint{ Create: []*endpoint.Endpoint{
endpoint.NewEndpoint("migrate.test-zone.example.org", endpoint.RecordTypeA, "3.3.3.3").WithSetIdentifier("set-3"), endpoint.NewEndpoint("migrate.test-zone.example.org", endpoint.RecordTypeA, "3.3.3.3").WithSetIdentifier("set-3"),
@ -920,7 +920,7 @@ func TestDynamoDBRegistryApplyChanges(t *testing.T) {
ctx := context.Background() ctx := context.Background()
r, _ := NewDynamoDBRegistry(p, "test-owner", api, "test-table", "txt.", "", "", []string{}, nil, time.Hour) r, _ := NewDynamoDBRegistry(p, "test-owner", api, "test-table", "txt.", "", "", []string{}, []string{}, nil, time.Hour)
_, err := r.Records(ctx) _, err := r.Records(ctx)
require.Nil(t, err) require.Nil(t, err)

View File

@ -51,6 +51,7 @@ type TXTRegistry struct {
wildcardReplacement string wildcardReplacement string
managedRecordTypes []string managedRecordTypes []string
excludeRecordTypes []string
// encrypt text records // encrypt text records
txtEncryptEnabled bool txtEncryptEnabled bool
@ -58,7 +59,7 @@ type TXTRegistry struct {
} }
// NewTXTRegistry returns new TXTRegistry object // NewTXTRegistry returns new TXTRegistry object
func NewTXTRegistry(provider provider.Provider, txtPrefix, txtSuffix, ownerID string, cacheInterval time.Duration, txtWildcardReplacement string, managedRecordTypes []string, txtEncryptEnabled bool, txtEncryptAESKey []byte) (*TXTRegistry, error) { func NewTXTRegistry(provider provider.Provider, txtPrefix, txtSuffix, ownerID string, cacheInterval time.Duration, txtWildcardReplacement string, managedRecordTypes, excludeRecordTypes []string, txtEncryptEnabled bool, txtEncryptAESKey []byte) (*TXTRegistry, error) {
if ownerID == "" { if ownerID == "" {
return nil, errors.New("owner id cannot be empty") return nil, errors.New("owner id cannot be empty")
} }
@ -84,6 +85,7 @@ func NewTXTRegistry(provider provider.Provider, txtPrefix, txtSuffix, ownerID st
cacheInterval: cacheInterval, cacheInterval: cacheInterval,
wildcardReplacement: txtWildcardReplacement, wildcardReplacement: txtWildcardReplacement,
managedRecordTypes: managedRecordTypes, managedRecordTypes: managedRecordTypes,
excludeRecordTypes: excludeRecordTypes,
txtEncryptEnabled: txtEncryptEnabled, txtEncryptEnabled: txtEncryptEnabled,
txtEncryptAESKey: txtEncryptAESKey, txtEncryptAESKey: txtEncryptAESKey,
}, nil }, nil
@ -181,7 +183,7 @@ func (im *TXTRegistry) Records(ctx context.Context) ([]*endpoint.Endpoint, error
// Handle the migration of TXT records created before the new format (introduced in v0.12.0). // 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. // The migration is done for the TXT records owned by this instance only.
if len(txtRecordsMap) > 0 && ep.Labels[endpoint.OwnerLabelKey] == im.ownerID { if len(txtRecordsMap) > 0 && ep.Labels[endpoint.OwnerLabelKey] == im.ownerID {
if plan.IsManagedRecord(ep.RecordType, im.managedRecordTypes) { if plan.IsManagedRecord(ep.RecordType, im.managedRecordTypes, im.excludeRecordTypes) {
// Get desired TXT records and detect the missing ones // Get desired TXT records and detect the missing ones
desiredTXTs := im.generateTXTRecord(ep) desiredTXTs := im.generateTXTRecord(ep)
for _, desiredTXT := range desiredTXTs { for _, desiredTXT := range desiredTXTs {

View File

@ -46,20 +46,20 @@ func TestTXTRegistry(t *testing.T) {
func testTXTRegistryNew(t *testing.T) { func testTXTRegistryNew(t *testing.T) {
p := inmemory.NewInMemoryProvider() p := inmemory.NewInMemoryProvider()
_, err := NewTXTRegistry(p, "txt", "", "", time.Hour, "", []string{}, false, nil) _, err := NewTXTRegistry(p, "txt", "", "", time.Hour, "", []string{}, []string{}, false, nil)
require.Error(t, err) require.Error(t, err)
_, err = NewTXTRegistry(p, "", "txt", "", time.Hour, "", []string{}, false, nil) _, err = NewTXTRegistry(p, "", "txt", "", time.Hour, "", []string{}, []string{}, false, nil)
require.Error(t, err) require.Error(t, err)
r, err := NewTXTRegistry(p, "txt", "", "owner", time.Hour, "", []string{}, false, nil) r, err := NewTXTRegistry(p, "txt", "", "owner", time.Hour, "", []string{}, []string{}, false, nil)
require.NoError(t, err) require.NoError(t, err)
assert.Equal(t, p, r.provider) assert.Equal(t, p, r.provider)
r, err = NewTXTRegistry(p, "", "txt", "owner", time.Hour, "", []string{}, false, nil) r, err = NewTXTRegistry(p, "", "txt", "owner", time.Hour, "", []string{}, []string{}, false, nil)
require.NoError(t, err) require.NoError(t, err)
_, err = NewTXTRegistry(p, "txt", "txt", "owner", time.Hour, "", []string{}, false, nil) _, err = NewTXTRegistry(p, "txt", "txt", "owner", time.Hour, "", []string{}, []string{}, false, nil)
require.Error(t, err) require.Error(t, err)
_, ok := r.mapper.(affixNameMapper) _, ok := r.mapper.(affixNameMapper)
@ -68,16 +68,16 @@ func testTXTRegistryNew(t *testing.T) {
assert.Equal(t, p, r.provider) assert.Equal(t, p, r.provider)
aesKey := []byte(";k&l)nUC/33:{?d{3)54+,AD?]SX%yh^") aesKey := []byte(";k&l)nUC/33:{?d{3)54+,AD?]SX%yh^")
_, err = NewTXTRegistry(p, "", "", "owner", time.Hour, "", []string{}, false, nil) _, err = NewTXTRegistry(p, "", "", "owner", time.Hour, "", []string{}, []string{}, false, nil)
require.NoError(t, err) require.NoError(t, err)
_, err = NewTXTRegistry(p, "", "", "owner", time.Hour, "", []string{}, false, aesKey) _, err = NewTXTRegistry(p, "", "", "owner", time.Hour, "", []string{}, []string{}, false, aesKey)
require.NoError(t, err) require.NoError(t, err)
_, err = NewTXTRegistry(p, "", "", "owner", time.Hour, "", []string{}, true, nil) _, err = NewTXTRegistry(p, "", "", "owner", time.Hour, "", []string{}, []string{}, true, nil)
require.Error(t, err) require.Error(t, err)
r, err = NewTXTRegistry(p, "", "", "owner", time.Hour, "", []string{}, true, aesKey) r, err = NewTXTRegistry(p, "", "", "owner", time.Hour, "", []string{}, []string{}, true, aesKey)
require.NoError(t, err) require.NoError(t, err)
_, ok = r.mapper.(affixNameMapper) _, ok = r.mapper.(affixNameMapper)
@ -215,13 +215,13 @@ func testTXTRegistryRecordsPrefixed(t *testing.T) {
}, },
} }
r, _ := NewTXTRegistry(p, "txt.", "", "owner", time.Hour, "wc", []string{}, false, nil) r, _ := NewTXTRegistry(p, "txt.", "", "owner", time.Hour, "wc", []string{}, []string{}, false, nil)
records, _ := r.Records(ctx) records, _ := r.Records(ctx)
assert.True(t, testutils.SameEndpoints(records, expectedRecords)) assert.True(t, testutils.SameEndpoints(records, expectedRecords))
// Ensure prefix is case-insensitive // Ensure prefix is case-insensitive
r, _ = NewTXTRegistry(p, "TxT.", "", "owner", time.Hour, "wc", []string{}, false, nil) r, _ = NewTXTRegistry(p, "TxT.", "", "owner", time.Hour, "wc", []string{}, []string{}, false, nil)
records, _ = r.Records(ctx) records, _ = r.Records(ctx)
assert.True(t, testutils.SameEndpoints(records, expectedRecords)) assert.True(t, testutils.SameEndpoints(records, expectedRecords))
@ -340,13 +340,13 @@ func testTXTRegistryRecordsSuffixed(t *testing.T) {
}, },
} }
r, _ := NewTXTRegistry(p, "", "-txt", "owner", time.Hour, "", []string{}, false, nil) r, _ := NewTXTRegistry(p, "", "-txt", "owner", time.Hour, "", []string{}, []string{}, false, nil)
records, _ := r.Records(ctx) records, _ := r.Records(ctx)
assert.True(t, testutils.SameEndpoints(records, expectedRecords)) assert.True(t, testutils.SameEndpoints(records, expectedRecords))
// Ensure prefix is case-insensitive // Ensure prefix is case-insensitive
r, _ = NewTXTRegistry(p, "", "-TxT", "owner", time.Hour, "", []string{}, false, nil) r, _ = NewTXTRegistry(p, "", "-TxT", "owner", time.Hour, "", []string{}, []string{}, false, nil)
records, _ = r.Records(ctx) records, _ = r.Records(ctx)
assert.True(t, testutils.SameEndpointLabels(records, expectedRecords)) assert.True(t, testutils.SameEndpointLabels(records, expectedRecords))
@ -441,7 +441,7 @@ func testTXTRegistryRecordsNoPrefix(t *testing.T) {
}, },
} }
r, _ := NewTXTRegistry(p, "", "", "owner", time.Hour, "", []string{}, false, nil) r, _ := NewTXTRegistry(p, "", "", "owner", time.Hour, "", []string{}, []string{}, false, nil)
records, _ := r.Records(ctx) records, _ := r.Records(ctx)
assert.True(t, testutils.SameEndpoints(records, expectedRecords)) assert.True(t, testutils.SameEndpoints(records, expectedRecords))
@ -468,12 +468,12 @@ func testTXTRegistryRecordsPrefixedTemplated(t *testing.T) {
}, },
} }
r, _ := NewTXTRegistry(p, "txt-%{record_type}.", "", "owner", time.Hour, "wc", []string{}, false, nil) r, _ := NewTXTRegistry(p, "txt-%{record_type}.", "", "owner", time.Hour, "wc", []string{}, []string{}, false, nil)
records, _ := r.Records(ctx) records, _ := r.Records(ctx)
assert.True(t, testutils.SameEndpoints(records, expectedRecords)) assert.True(t, testutils.SameEndpoints(records, expectedRecords))
r, _ = NewTXTRegistry(p, "TxT-%{record_type}.", "", "owner", time.Hour, "wc", []string{}, false, nil) r, _ = NewTXTRegistry(p, "TxT-%{record_type}.", "", "owner", time.Hour, "wc", []string{}, []string{}, false, nil)
records, _ = r.Records(ctx) records, _ = r.Records(ctx)
assert.True(t, testutils.SameEndpoints(records, expectedRecords)) assert.True(t, testutils.SameEndpoints(records, expectedRecords))
@ -500,12 +500,12 @@ func testTXTRegistryRecordsSuffixedTemplated(t *testing.T) {
}, },
} }
r, _ := NewTXTRegistry(p, "", "txt%{record_type}", "owner", time.Hour, "wc", []string{}, false, nil) r, _ := NewTXTRegistry(p, "", "txt%{record_type}", "owner", time.Hour, "wc", []string{}, []string{}, false, nil)
records, _ := r.Records(ctx) records, _ := r.Records(ctx)
assert.True(t, testutils.SameEndpoints(records, expectedRecords)) assert.True(t, testutils.SameEndpoints(records, expectedRecords))
r, _ = NewTXTRegistry(p, "", "TxT%{record_type}", "owner", time.Hour, "wc", []string{}, false, nil) r, _ = NewTXTRegistry(p, "", "TxT%{record_type}", "owner", time.Hour, "wc", []string{}, []string{}, false, nil)
records, _ = r.Records(ctx) records, _ = r.Records(ctx)
assert.True(t, testutils.SameEndpoints(records, expectedRecords)) assert.True(t, testutils.SameEndpoints(records, expectedRecords))
@ -548,7 +548,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"), 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, "", []string{}, false, nil) r, _ := NewTXTRegistry(p, "txt.", "", "owner", time.Hour, "", []string{}, []string{}, false, nil)
changes := &plan.Changes{ changes := &plan.Changes{
Create: []*endpoint.Endpoint{ Create: []*endpoint.Endpoint{
@ -637,7 +637,7 @@ func testTXTRegistryApplyChangesWithTemplatedPrefix(t *testing.T) {
p.ApplyChanges(ctx, &plan.Changes{ p.ApplyChanges(ctx, &plan.Changes{
Create: []*endpoint.Endpoint{}, Create: []*endpoint.Endpoint{},
}) })
r, _ := NewTXTRegistry(p, "prefix%{record_type}.", "", "owner", time.Hour, "", []string{}, false, nil) r, _ := NewTXTRegistry(p, "prefix%{record_type}.", "", "owner", time.Hour, "", []string{}, []string{}, false, nil)
changes := &plan.Changes{ changes := &plan.Changes{
Create: []*endpoint.Endpoint{ Create: []*endpoint.Endpoint{
newEndpointWithOwnerResource("new-record-1.test-zone.example.org", "new-loadbalancer-1.lb.com", endpoint.RecordTypeCNAME, "", "ingress/default/my-ingress"), newEndpointWithOwnerResource("new-record-1.test-zone.example.org", "new-loadbalancer-1.lb.com", endpoint.RecordTypeCNAME, "", "ingress/default/my-ingress"),
@ -680,7 +680,7 @@ func testTXTRegistryApplyChangesWithTemplatedSuffix(t *testing.T) {
p.OnApplyChanges = func(ctx context.Context, got *plan.Changes) { p.OnApplyChanges = func(ctx context.Context, got *plan.Changes) {
assert.Equal(t, ctxEndpoints, ctx.Value(provider.RecordsContextKey)) assert.Equal(t, ctxEndpoints, ctx.Value(provider.RecordsContextKey))
} }
r, _ := NewTXTRegistry(p, "", "-%{record_type}suffix", "owner", time.Hour, "", []string{}, false, nil) r, _ := NewTXTRegistry(p, "", "-%{record_type}suffix", "owner", time.Hour, "", []string{}, []string{}, false, nil)
changes := &plan.Changes{ changes := &plan.Changes{
Create: []*endpoint.Endpoint{ Create: []*endpoint.Endpoint{
newEndpointWithOwnerResource("new-record-1.test-zone.example.org", "new-loadbalancer-1.lb.com", endpoint.RecordTypeCNAME, "", "ingress/default/my-ingress"), newEndpointWithOwnerResource("new-record-1.test-zone.example.org", "new-loadbalancer-1.lb.com", endpoint.RecordTypeCNAME, "", "ingress/default/my-ingress"),
@ -745,7 +745,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"), 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", []string{}, false, nil) r, _ := NewTXTRegistry(p, "", "-txt", "owner", time.Hour, "wildcard", []string{}, []string{}, false, nil)
changes := &plan.Changes{ changes := &plan.Changes{
Create: []*endpoint.Endpoint{ Create: []*endpoint.Endpoint{
@ -849,7 +849,7 @@ func testTXTRegistryApplyChangesNoPrefix(t *testing.T) {
newEndpointWithOwner("cname-foobar.test-zone.example.org", "\"heritage=external-dns,external-dns/owner=owner\"", endpoint.RecordTypeTXT, ""), newEndpointWithOwner("cname-foobar.test-zone.example.org", "\"heritage=external-dns,external-dns/owner=owner\"", endpoint.RecordTypeTXT, ""),
}, },
}) })
r, _ := NewTXTRegistry(p, "", "", "owner", time.Hour, "", []string{}, false, nil) r, _ := NewTXTRegistry(p, "", "", "owner", time.Hour, "", []string{}, []string{}, false, nil)
changes := &plan.Changes{ changes := &plan.Changes{
Create: []*endpoint.Endpoint{ Create: []*endpoint.Endpoint{
@ -1007,7 +1007,7 @@ func testTXTRegistryMissingRecordsNoPrefix(t *testing.T) {
}, },
} }
r, _ := NewTXTRegistry(p, "", "", "owner", time.Hour, "wc", []string{endpoint.RecordTypeCNAME, endpoint.RecordTypeA, endpoint.RecordTypeNS}, false, nil) r, _ := NewTXTRegistry(p, "", "", "owner", time.Hour, "wc", []string{endpoint.RecordTypeCNAME, endpoint.RecordTypeA, endpoint.RecordTypeNS}, []string{}, false, nil)
records, _ := r.Records(ctx) records, _ := r.Records(ctx)
assert.True(t, testutils.SameEndpoints(records, expectedRecords)) assert.True(t, testutils.SameEndpoints(records, expectedRecords))
@ -1101,7 +1101,7 @@ func testTXTRegistryMissingRecordsWithPrefix(t *testing.T) {
}, },
} }
r, _ := NewTXTRegistry(p, "txt.", "", "owner", time.Hour, "wc", []string{endpoint.RecordTypeCNAME, endpoint.RecordTypeA, endpoint.RecordTypeNS}, false, nil) r, _ := NewTXTRegistry(p, "txt.", "", "owner", time.Hour, "wc", []string{endpoint.RecordTypeCNAME, endpoint.RecordTypeA, endpoint.RecordTypeNS}, []string{}, false, nil)
records, _ := r.Records(ctx) records, _ := r.Records(ctx)
assert.True(t, testutils.SameEndpoints(records, expectedRecords)) assert.True(t, testutils.SameEndpoints(records, expectedRecords))
@ -1389,7 +1389,7 @@ func TestNewTXTScheme(t *testing.T) {
newEndpointWithOwner("cname-foobar.test-zone.example.org", "\"heritage=external-dns,external-dns/owner=owner\"", endpoint.RecordTypeTXT, ""), newEndpointWithOwner("cname-foobar.test-zone.example.org", "\"heritage=external-dns,external-dns/owner=owner\"", endpoint.RecordTypeTXT, ""),
}, },
}) })
r, _ := NewTXTRegistry(p, "", "", "owner", time.Hour, "", []string{}, false, nil) r, _ := NewTXTRegistry(p, "", "", "owner", time.Hour, "", []string{}, []string{}, false, nil)
changes := &plan.Changes{ changes := &plan.Changes{
Create: []*endpoint.Endpoint{ Create: []*endpoint.Endpoint{
@ -1465,7 +1465,7 @@ func TestGenerateTXT(t *testing.T) {
} }
p := inmemory.NewInMemoryProvider() p := inmemory.NewInMemoryProvider()
p.CreateZone(testZone) p.CreateZone(testZone)
r, _ := NewTXTRegistry(p, "", "", "owner", time.Hour, "", []string{}, false, nil) r, _ := NewTXTRegistry(p, "", "", "owner", time.Hour, "", []string{}, []string{}, false, nil)
gotTXT := r.generateTXTRecord(record) gotTXT := r.generateTXTRecord(record)
assert.Equal(t, expectedTXT, gotTXT) assert.Equal(t, expectedTXT, gotTXT)
} }
@ -1484,7 +1484,7 @@ func TestGenerateTXTForAAAA(t *testing.T) {
} }
p := inmemory.NewInMemoryProvider() p := inmemory.NewInMemoryProvider()
p.CreateZone(testZone) p.CreateZone(testZone)
r, _ := NewTXTRegistry(p, "", "", "owner", time.Hour, "", []string{}, false, nil) r, _ := NewTXTRegistry(p, "", "", "owner", time.Hour, "", []string{}, []string{}, false, nil)
gotTXT := r.generateTXTRecord(record) gotTXT := r.generateTXTRecord(record)
assert.Equal(t, expectedTXT, gotTXT) assert.Equal(t, expectedTXT, gotTXT)
} }
@ -1501,7 +1501,7 @@ func TestFailGenerateTXT(t *testing.T) {
expectedTXT := []*endpoint.Endpoint{} expectedTXT := []*endpoint.Endpoint{}
p := inmemory.NewInMemoryProvider() p := inmemory.NewInMemoryProvider()
p.CreateZone(testZone) p.CreateZone(testZone)
r, _ := NewTXTRegistry(p, "", "", "owner", time.Hour, "", []string{}, false, nil) r, _ := NewTXTRegistry(p, "", "", "owner", time.Hour, "", []string{}, []string{}, false, nil)
gotTXT := r.generateTXTRecord(cnameRecord) gotTXT := r.generateTXTRecord(cnameRecord)
assert.Equal(t, expectedTXT, gotTXT) assert.Equal(t, expectedTXT, gotTXT)
} }
@ -1524,7 +1524,7 @@ func TestMultiClusterDifferentRecordTypeOwnership(t *testing.T) {
}, },
}) })
r, _ := NewTXTRegistry(p, "_owner.", "", "bar", time.Hour, "", []string{}, false, nil) r, _ := NewTXTRegistry(p, "_owner.", "", "bar", time.Hour, "", []string{}, []string{}, false, nil)
records, _ := r.Records(ctx) records, _ := r.Records(ctx)
// new cluster has same ingress host as other cluster and uses CNAME ingress address // new cluster has same ingress host as other cluster and uses CNAME ingress address