Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add option to define minimum TTL for rfc2136 provider #1412

Merged
Merged
Show file tree
Hide file tree
Changes from 3 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
2 changes: 1 addition & 1 deletion main.go
Original file line number Diff line number Diff line change
Expand Up @@ -240,7 +240,7 @@ func main() {
p, err = provider.NewOCIProvider(*config, domainFilter, zoneIDFilter, cfg.DryRun)
}
case "rfc2136":
p, err = provider.NewRfc2136Provider(cfg.RFC2136Host, cfg.RFC2136Port, cfg.RFC2136Zone, cfg.RFC2136Insecure, cfg.RFC2136TSIGKeyName, cfg.RFC2136TSIGSecret, cfg.RFC2136TSIGSecretAlg, cfg.RFC2136TAXFR, domainFilter, cfg.DryRun, nil)
njuettner marked this conversation as resolved.
Show resolved Hide resolved
p, err = provider.NewRfc2136Provider(cfg.RFC2136Host, cfg.RFC2136Port, cfg.RFC2136Zone, cfg.RFC2136Insecure, cfg.RFC2136TSIGKeyName, cfg.RFC2136TSIGSecret, cfg.RFC2136TSIGSecretAlg, cfg.RFC2136TAXFR, domainFilter, cfg.DryRun, cfg.RFC2136MinTTLSeconds, nil)
case "ns1":
p, err = provider.NewNS1Provider(
provider.NS1Config{
Expand Down
3 changes: 3 additions & 0 deletions pkg/apis/externaldns/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,7 @@ type Config struct {
RFC2136TSIGSecret string `secure:"yes"`
RFC2136TSIGSecretAlg string
RFC2136TAXFR bool
RFC2136MinTTLSeconds int64
NS1Endpoint string
NS1IgnoreSSL bool
TransIPAccountName string
Expand Down Expand Up @@ -223,6 +224,7 @@ var defaultConfig = &Config{
RFC2136TSIGSecret: "",
RFC2136TSIGSecretAlg: "",
RFC2136TAXFR: true,
RFC2136MinTTLSeconds: 0,
NS1Endpoint: "",
NS1IgnoreSSL: false,
TransIPAccountName: "",
Expand Down Expand Up @@ -366,6 +368,7 @@ func (cfg *Config) ParseFlags(args []string) error {
app.Flag("rfc2136-tsig-secret", "When using the RFC2136 provider, specify the TSIG (base64) value to attached to DNS messages (required when --rfc2136-insecure=false)").Default(defaultConfig.RFC2136TSIGSecret).StringVar(&cfg.RFC2136TSIGSecret)
app.Flag("rfc2136-tsig-secret-alg", "When using the RFC2136 provider, specify the TSIG (base64) value to attached to DNS messages (required when --rfc2136-insecure=false)").Default(defaultConfig.RFC2136TSIGSecretAlg).StringVar(&cfg.RFC2136TSIGSecretAlg)
app.Flag("rfc2136-tsig-axfr", "When using the RFC2136 provider, specify the TSIG (base64) value to attached to DNS messages (required when --rfc2136-insecure=false)").BoolVar(&cfg.RFC2136TAXFR)
app.Flag("rfc2136-min-ttl", "When using the RFC2136 provider, specify minimal TTL (in seconds) for records. This value will be used if the provided TTL for a service/ingress is lower than this").Default(strconv.FormatInt(defaultConfig.RFC2136MinTTLSeconds, 10)).Int64Var(&cfg.RFC2136MinTTLSeconds)
njuettner marked this conversation as resolved.
Show resolved Hide resolved

// Flags related to TransIP provider
app.Flag("transip-account", "When using the TransIP provider, specify the account name (required when --provider=transip)").Default(defaultConfig.TransIPAccountName).StringVar(&cfg.TransIPAccountName)
Expand Down
6 changes: 6 additions & 0 deletions pkg/apis/externaldns/validation/validation.go
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,12 @@ func ValidateConfig(cfg *externaldns.Config) error {
}
}

if cfg.Provider == "rfc2136" {
if cfg.RFC2136MinTTLSeconds < 0 {
return errors.New("TTL specified for rfc2136 is negative")
}
}

if cfg.IgnoreHostnameAnnotation && cfg.FQDNTemplate == "" {
return errors.New("FQDN Template must be set if ignoring annotations")
}
Expand Down
26 changes: 26 additions & 0 deletions pkg/apis/externaldns/validation/validation_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -124,3 +124,29 @@ func TestValidateBadIgnoreHostnameAnnotationsConfig(t *testing.T) {

assert.Error(t, ValidateConfig(cfg))
}

func TestValidateBadRfc2136Config(t *testing.T) {
cfg := externaldns.NewConfig()

cfg.LogFormat = "json"
cfg.Sources = []string{"test-source"}
cfg.Provider = "rfc2136"
cfg.RFC2136MinTTLSeconds = -1

err := ValidateConfig(cfg)

assert.NotNil(t, err)
}

func TestValidateGoodRfc2136Config(t *testing.T) {
cfg := externaldns.NewConfig()

cfg.LogFormat = "json"
cfg.Sources = []string{"test-source"}
cfg.Provider = "rfc2136"
cfg.RFC2136MinTTLSeconds = 3600

err := ValidateConfig(cfg)

assert.Nil(t, err)
}
24 changes: 16 additions & 8 deletions provider/rfc2136.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ type rfc2136Provider struct {
tsigSecretAlg string
insecure bool
axfr bool
minTTLSeconds int64

// only consider hosted zones managing domains ending in this suffix
domainFilter DomainFilter
Expand All @@ -64,19 +65,20 @@ type rfc2136Actions interface {
}

// NewRfc2136Provider is a factory function for OpenStack rfc2136 providers
func NewRfc2136Provider(host string, port int, zoneName string, insecure bool, keyName string, secret string, secretAlg string, axfr bool, domainFilter DomainFilter, dryRun bool, actions rfc2136Actions) (Provider, error) {
func NewRfc2136Provider(host string, port int, zoneName string, insecure bool, keyName string, secret string, secretAlg string, axfr bool, domainFilter DomainFilter, dryRun bool, minTTLSeconds int64, actions rfc2136Actions) (Provider, error) {
secretAlgChecked, ok := tsigAlgs[secretAlg]
if !ok && !insecure {
return nil, errors.Errorf("%s is not supported TSIG algorithm", secretAlg)
}

r := &rfc2136Provider{
nameserver: net.JoinHostPort(host, strconv.Itoa(port)),
zoneName: dns.Fqdn(zoneName),
insecure: insecure,
domainFilter: domainFilter,
dryRun: dryRun,
axfr: axfr,
nameserver: net.JoinHostPort(host, strconv.Itoa(port)),
zoneName: dns.Fqdn(zoneName),
insecure: insecure,
domainFilter: domainFilter,
dryRun: dryRun,
axfr: axfr,
minTTLSeconds: minTTLSeconds,
}
if actions != nil {
r.actions = actions
Expand Down Expand Up @@ -253,8 +255,14 @@ func (r rfc2136Provider) UpdateRecord(m *dns.Msg, ep *endpoint.Endpoint) error {

func (r rfc2136Provider) AddRecord(m *dns.Msg, ep *endpoint.Endpoint) error {
log.Debugf("AddRecord.ep=%s", ep)

var ttl = r.minTTLSeconds
if ep.RecordTTL.IsConfigured() && int64(ep.RecordTTL) > ttl {
ttl = int64(ep.RecordTTL)
}

for _, target := range ep.Targets {
newRR := fmt.Sprintf("%s %d %s %s", ep.DNSName, ep.RecordTTL, ep.RecordType, target)
newRR := fmt.Sprintf("%s %d %s %s", ep.DNSName, ttl, ep.RecordType, target)
log.Infof("Adding RR: %s", newRR)

rr, err := dns.NewRR(newRR)
Expand Down
65 changes: 56 additions & 9 deletions provider/rfc2136_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ package provider

import (
"context"
"fmt"
"strings"
"testing"

Expand All @@ -44,14 +45,8 @@ func newStub() *rfc2136Stub {
}

func (r *rfc2136Stub) SendMessage(msg *dns.Msg) error {
const searchPattern = "AUTHORITY SECTION:"

data := msg.String()
log.Info(data)

authoritySectionOffset := strings.Index(data, searchPattern)
lines := strings.Split(strings.TrimSpace(data[authoritySectionOffset+len(searchPattern):]), "\n")

log.Info(msg.String())
lines := extractAuthoritySectionFromMessage(msg)
for _, line := range lines {
// break at first empty line
if len(strings.TrimSpace(line)) == 0 {
Expand Down Expand Up @@ -98,7 +93,13 @@ func (r *rfc2136Stub) IncomeTransfer(m *dns.Msg, a string) (env chan *dns.Envelo
}

func createRfc2136StubProvider(stub *rfc2136Stub) (Provider, error) {
return NewRfc2136Provider("", 0, "", false, "key", "secret", "hmac-sha512", true, DomainFilter{}, false, stub)
return NewRfc2136Provider("", 0, "", false, "key", "secret", "hmac-sha512", true, DomainFilter{}, false, 300, stub)
}

func extractAuthoritySectionFromMessage(msg fmt.Stringer) []string {
const searchPattern = "AUTHORITY SECTION:"
authoritySectionOffset := strings.Index(msg.String(), searchPattern)
return strings.Split(strings.TrimSpace(msg.String()[authoritySectionOffset+len(searchPattern):]), "\n")
}

// TestRfc2136GetRecordsMultipleTargets simulates a single record with multiple targets.
Expand Down Expand Up @@ -162,6 +163,7 @@ func TestRfc2136ApplyChanges(t *testing.T) {
DNSName: "v1.foo.com",
RecordType: "A",
Targets: []string{"1.2.3.4"},
RecordTTL: endpoint.TTL(400),
},
{
DNSName: "v1.foobar.com",
Expand Down Expand Up @@ -198,3 +200,48 @@ func TestRfc2136ApplyChanges(t *testing.T) {
assert.True(t, strings.Contains(stub.updateMsgs[1].String(), "v2.foobar.com"))

}

func TestRfc2136ApplyChangesWithDifferentTTLs(t *testing.T) {
stub := newStub()

provider, err := createRfc2136StubProvider(stub)
assert.NoError(t, err)

p := &plan.Changes{
Create: []*endpoint.Endpoint{
{
DNSName: "v1.foo.com",
RecordType: "A",
Targets: []string{"2.1.1.1"},
RecordTTL: endpoint.TTL(400),
},
{
DNSName: "v2.foo.com",
RecordType: "A",
Targets: []string{"3.2.2.2"},
RecordTTL: endpoint.TTL(200),
},
{
DNSName: "v3.foo.com",
RecordType: "A",
Targets: []string{"4.3.3.3"},
},
},
}

err = provider.ApplyChanges(context.Background(), p)
assert.NoError(t, err)

createRecords := extractAuthoritySectionFromMessage(stub.createMsgs[0])
assert.Equal(t, 3, len(createRecords))
assert.True(t, strings.Contains(createRecords[0], "v1.foo.com"))
assert.True(t, strings.Contains(createRecords[0], "2.1.1.1"))
assert.True(t, strings.Contains(createRecords[0], "400"))
assert.True(t, strings.Contains(createRecords[1], "v2.foo.com"))
assert.True(t, strings.Contains(createRecords[1], "3.2.2.2"))
assert.True(t, strings.Contains(createRecords[1], "300"))
assert.True(t, strings.Contains(createRecords[2], "v3.foo.com"))
assert.True(t, strings.Contains(createRecords[2], "4.3.3.3"))
assert.True(t, strings.Contains(createRecords[2], "300"))

}