mirror of
https://github.com/kubernetes-sigs/external-dns.git
synced 2025-08-05 17:16:59 +02:00
742 lines
22 KiB
Go
742 lines
22 KiB
Go
/*
|
|
Copyright 2017 The Kubernetes Authors.
|
|
|
|
Licensed under the Apache License, Version 2.0 (the "License");
|
|
you may not use this file except in compliance with the License.
|
|
You may obtain a copy of the License at
|
|
|
|
http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
Unless required by applicable law or agreed to in writing, software
|
|
distributed under the License is distributed on an "AS IS" BASIS,
|
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
See the License for the specific language governing permissions and
|
|
limitations under the License.
|
|
*/
|
|
|
|
package rfc2136
|
|
|
|
import (
|
|
"context"
|
|
"crypto/tls"
|
|
"fmt"
|
|
"os"
|
|
"regexp"
|
|
"sort"
|
|
"strings"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/miekg/dns"
|
|
log "github.com/sirupsen/logrus"
|
|
"github.com/stretchr/testify/assert"
|
|
|
|
"sigs.k8s.io/external-dns/endpoint"
|
|
"sigs.k8s.io/external-dns/plan"
|
|
"sigs.k8s.io/external-dns/provider"
|
|
)
|
|
|
|
type rfc2136Stub struct {
|
|
output []*dns.Envelope
|
|
updateMsgs []*dns.Msg
|
|
createMsgs []*dns.Msg
|
|
}
|
|
|
|
func newStub() *rfc2136Stub {
|
|
return &rfc2136Stub{
|
|
output: make([]*dns.Envelope, 0),
|
|
updateMsgs: make([]*dns.Msg, 0),
|
|
createMsgs: make([]*dns.Msg, 0),
|
|
}
|
|
}
|
|
|
|
func getSortedChanges(msgs []*dns.Msg) []string {
|
|
r := []string{}
|
|
for _, d := range msgs {
|
|
// only care about section after the ZONE SECTION: as the id: needs stripped out in order to sort and grantee the order when sorting
|
|
r = append(r, strings.Split(d.String(), "ZONE SECTION:")[1])
|
|
}
|
|
sort.Strings(r)
|
|
return r
|
|
}
|
|
|
|
func (r *rfc2136Stub) SendMessage(msg *dns.Msg) error {
|
|
zone := extractZoneFromMessage(msg.String())
|
|
// Make sure the zone starts with . to make sure HasSuffix does not match forbar.com for zone bar.com
|
|
if !strings.HasPrefix(zone, ".") {
|
|
zone = "." + zone
|
|
}
|
|
log.Infof("zone=%s", zone)
|
|
lines := extractUpdateSectionFromMessage(msg)
|
|
for _, line := range lines {
|
|
// break at first empty line
|
|
if len(strings.TrimSpace(line)) == 0 {
|
|
break
|
|
}
|
|
|
|
line = strings.Replace(line, "\t", " ", -1)
|
|
log.Info(line)
|
|
record := strings.Split(line, " ")[0]
|
|
if !strings.HasSuffix(record, zone) {
|
|
err := fmt.Errorf("Message contains updates outside of it's zone. zone=%v record=%v", zone, record)
|
|
log.Error(err)
|
|
return err
|
|
}
|
|
|
|
if strings.Contains(line, " NONE ") {
|
|
r.updateMsgs = append(r.updateMsgs, msg)
|
|
} else if strings.Contains(line, " IN ") {
|
|
r.createMsgs = append(r.createMsgs, msg)
|
|
}
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func (r *rfc2136Stub) setOutput(output []string) error {
|
|
r.output = make([]*dns.Envelope, len(output))
|
|
for i, e := range output {
|
|
rr, err := dns.NewRR(e)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
r.output[i] = &dns.Envelope{
|
|
RR: []dns.RR{rr},
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (r *rfc2136Stub) IncomeTransfer(m *dns.Msg, a string) (env chan *dns.Envelope, err error) {
|
|
outChan := make(chan *dns.Envelope)
|
|
go func() {
|
|
for _, e := range r.output {
|
|
outChan <- e
|
|
}
|
|
close(outChan)
|
|
}()
|
|
|
|
return outChan, nil
|
|
}
|
|
|
|
func createRfc2136StubProvider(stub *rfc2136Stub) (provider.Provider, error) {
|
|
tlsConfig := TLSConfig{
|
|
UseTLS: false,
|
|
SkipTLSVerify: false,
|
|
CAFilePath: "",
|
|
ClientCertFilePath: "",
|
|
ClientCertKeyFilePath: "",
|
|
}
|
|
return NewRfc2136Provider("", 0, nil, false, "key", "secret", "hmac-sha512", true, endpoint.DomainFilter{}, false, 300*time.Second, false, false, "", "", "", 50, tlsConfig, stub)
|
|
}
|
|
|
|
func createRfc2136TLSStubProvider(stub *rfc2136Stub, tlsConfig TLSConfig) (provider.Provider, error) {
|
|
return NewRfc2136Provider("rfc2136-host", 0, nil, false, "key", "secret", "hmac-sha512", true, endpoint.DomainFilter{}, false, 300*time.Second, false, false, "", "", "", 50, tlsConfig, stub)
|
|
}
|
|
|
|
func createRfc2136StubProviderWithZones(stub *rfc2136Stub) (provider.Provider, error) {
|
|
tlsConfig := TLSConfig{
|
|
UseTLS: false,
|
|
SkipTLSVerify: false,
|
|
CAFilePath: "",
|
|
ClientCertFilePath: "",
|
|
ClientCertKeyFilePath: "",
|
|
}
|
|
zones := []string{"foo.com", "foobar.com"}
|
|
return NewRfc2136Provider("", 0, zones, false, "key", "secret", "hmac-sha512", true, endpoint.DomainFilter{}, false, 300*time.Second, false, false, "", "", "", 50, tlsConfig, stub)
|
|
}
|
|
|
|
func createRfc2136StubProviderWithZonesFilters(stub *rfc2136Stub) (provider.Provider, error) {
|
|
tlsConfig := TLSConfig{
|
|
UseTLS: false,
|
|
SkipTLSVerify: false,
|
|
CAFilePath: "",
|
|
ClientCertFilePath: "",
|
|
ClientCertKeyFilePath: "",
|
|
}
|
|
zones := []string{"foo.com", "foobar.com"}
|
|
return NewRfc2136Provider("", 0, zones, false, "key", "secret", "hmac-sha512", true, endpoint.DomainFilter{Filters: zones}, false, 300*time.Second, false, false, "", "", "", 50, tlsConfig, stub)
|
|
}
|
|
|
|
func extractUpdateSectionFromMessage(msg fmt.Stringer) []string {
|
|
const searchPattern = "UPDATE SECTION:"
|
|
updateSectionOffset := strings.Index(msg.String(), searchPattern)
|
|
return strings.Split(strings.TrimSpace(msg.String()[updateSectionOffset+len(searchPattern):]), "\n")
|
|
}
|
|
|
|
func extractZoneFromMessage(msg string) string {
|
|
re := regexp.MustCompile(`ZONE SECTION:\n;(?P<ZONE>[\.,\-,\w,\d]+)\t`)
|
|
matches := re.FindStringSubmatch(msg)
|
|
return matches[re.SubexpIndex("ZONE")]
|
|
}
|
|
|
|
// TestRfc2136GetRecordsMultipleTargets simulates a single record with multiple targets.
|
|
func TestRfc2136GetRecordsMultipleTargets(t *testing.T) {
|
|
stub := newStub()
|
|
err := stub.setOutput([]string{
|
|
"foo.com 3600 IN A 1.1.1.1",
|
|
"foo.com 3600 IN A 2.2.2.2",
|
|
})
|
|
assert.NoError(t, err)
|
|
|
|
provider, err := createRfc2136StubProvider(stub)
|
|
assert.NoError(t, err)
|
|
|
|
recs, err := provider.Records(context.Background())
|
|
assert.NoError(t, err)
|
|
|
|
assert.Equal(t, 1, len(recs), "expected single record")
|
|
assert.Equal(t, recs[0].DNSName, "foo.com")
|
|
assert.Equal(t, 2, len(recs[0].Targets), "expected two targets")
|
|
assert.True(t, recs[0].Targets[0] == "1.1.1.1" || recs[0].Targets[1] == "1.1.1.1") // ignore order
|
|
assert.True(t, recs[0].Targets[0] == "2.2.2.2" || recs[0].Targets[1] == "2.2.2.2") // ignore order
|
|
assert.Equal(t, recs[0].RecordType, "A")
|
|
assert.Equal(t, recs[0].RecordTTL, endpoint.TTL(3600))
|
|
assert.Equal(t, 0, len(recs[0].Labels), "expected no labels")
|
|
assert.Equal(t, 0, len(recs[0].ProviderSpecific), "expected no provider specific config")
|
|
}
|
|
|
|
func TestRfc2136TLSConfig(t *testing.T) {
|
|
stub := newStub()
|
|
|
|
caFile, err := os.CreateTemp("", "rfc2136-test-XXXXXXXX.crt")
|
|
assert.NoError(t, err)
|
|
defer os.Remove(caFile.Name())
|
|
_, err = caFile.Write([]byte(
|
|
`-----BEGIN CERTIFICATE-----
|
|
MIH+MIGxAhR2n1aQk0ONrQ8QQfa6GCzFWLmTXTAFBgMrZXAwITELMAkGA1UEBhMC
|
|
REUxEjAQBgNVBAMMCWxvY2FsaG9zdDAgFw0yMzEwMjQwNzI5NDNaGA8yMTIzMDkz
|
|
MDA3Mjk0M1owITELMAkGA1UEBhMCREUxEjAQBgNVBAMMCWxvY2FsaG9zdDAqMAUG
|
|
AytlcAMhAA1FzGJXuQdOpKv02SEl7SIA8SP8RVRI0QTi1bUFiFBLMAUGAytlcANB
|
|
ADiCKRUGDMyafSSYhl0KXoiXrFOxvhrGM5l15L4q82JM5Qb8wv0gNrnbGTZlInuv
|
|
ouB5ZN+05DzKCQhBekMnygQ=
|
|
-----END CERTIFICATE-----
|
|
`))
|
|
|
|
tlsConfig := TLSConfig{
|
|
UseTLS: true,
|
|
SkipTLSVerify: false,
|
|
CAFilePath: caFile.Name(),
|
|
ClientCertFilePath: "",
|
|
ClientCertKeyFilePath: "",
|
|
}
|
|
|
|
provider, err := createRfc2136TLSStubProvider(stub, tlsConfig)
|
|
assert.NoError(t, err)
|
|
|
|
rawProvider := provider.(*rfc2136Provider)
|
|
|
|
client, err := makeClient(*rawProvider)
|
|
assert.NoError(t, err)
|
|
|
|
assert.Equal(t, "tcp-tls", client.Net)
|
|
assert.Equal(t, false, client.TLSConfig.InsecureSkipVerify)
|
|
assert.Equal(t, "rfc2136-host", client.TLSConfig.ServerName)
|
|
assert.Equal(t, uint16(tls.VersionTLS13), client.TLSConfig.MinVersion)
|
|
assert.Equal(t, []string{"dot"}, client.TLSConfig.NextProtos)
|
|
}
|
|
|
|
func TestRfc2136TLSConfigNoVerify(t *testing.T) {
|
|
stub := newStub()
|
|
|
|
caFile, err := os.CreateTemp("", "rfc2136-test-XXXXXXXX.crt")
|
|
assert.NoError(t, err)
|
|
defer os.Remove(caFile.Name())
|
|
_, err = caFile.Write([]byte(
|
|
`-----BEGIN CERTIFICATE-----
|
|
MIH+MIGxAhR2n1aQk0ONrQ8QQfa6GCzFWLmTXTAFBgMrZXAwITELMAkGA1UEBhMC
|
|
REUxEjAQBgNVBAMMCWxvY2FsaG9zdDAgFw0yMzEwMjQwNzI5NDNaGA8yMTIzMDkz
|
|
MDA3Mjk0M1owITELMAkGA1UEBhMCREUxEjAQBgNVBAMMCWxvY2FsaG9zdDAqMAUG
|
|
AytlcAMhAA1FzGJXuQdOpKv02SEl7SIA8SP8RVRI0QTi1bUFiFBLMAUGAytlcANB
|
|
ADiCKRUGDMyafSSYhl0KXoiXrFOxvhrGM5l15L4q82JM5Qb8wv0gNrnbGTZlInuv
|
|
ouB5ZN+05DzKCQhBekMnygQ=
|
|
-----END CERTIFICATE-----
|
|
`))
|
|
|
|
tlsConfig := TLSConfig{
|
|
UseTLS: true,
|
|
SkipTLSVerify: true,
|
|
CAFilePath: caFile.Name(),
|
|
ClientCertFilePath: "",
|
|
ClientCertKeyFilePath: "",
|
|
}
|
|
|
|
provider, err := createRfc2136TLSStubProvider(stub, tlsConfig)
|
|
assert.NoError(t, err)
|
|
|
|
rawProvider := provider.(*rfc2136Provider)
|
|
|
|
client, err := makeClient(*rawProvider)
|
|
assert.NoError(t, err)
|
|
|
|
assert.Equal(t, "tcp-tls", client.Net)
|
|
assert.Equal(t, true, client.TLSConfig.InsecureSkipVerify)
|
|
assert.Equal(t, "rfc2136-host", client.TLSConfig.ServerName)
|
|
assert.Equal(t, uint16(tls.VersionTLS13), client.TLSConfig.MinVersion)
|
|
assert.Equal(t, []string{"dot"}, client.TLSConfig.NextProtos)
|
|
}
|
|
|
|
func TestRfc2136TLSConfigClientAuth(t *testing.T) {
|
|
stub := newStub()
|
|
|
|
caFile, err := os.CreateTemp("", "rfc2136-test-XXXXXXXX.crt")
|
|
assert.NoError(t, err)
|
|
defer os.Remove(caFile.Name())
|
|
_, err = caFile.Write([]byte(
|
|
`-----BEGIN CERTIFICATE-----
|
|
MIH+MIGxAhR2n1aQk0ONrQ8QQfa6GCzFWLmTXTAFBgMrZXAwITELMAkGA1UEBhMC
|
|
REUxEjAQBgNVBAMMCWxvY2FsaG9zdDAgFw0yMzEwMjQwNzI5NDNaGA8yMTIzMDkz
|
|
MDA3Mjk0M1owITELMAkGA1UEBhMCREUxEjAQBgNVBAMMCWxvY2FsaG9zdDAqMAUG
|
|
AytlcAMhAA1FzGJXuQdOpKv02SEl7SIA8SP8RVRI0QTi1bUFiFBLMAUGAytlcANB
|
|
ADiCKRUGDMyafSSYhl0KXoiXrFOxvhrGM5l15L4q82JM5Qb8wv0gNrnbGTZlInuv
|
|
ouB5ZN+05DzKCQhBekMnygQ=
|
|
-----END CERTIFICATE-----
|
|
`))
|
|
|
|
certFile, err := os.CreateTemp("", "rfc2136-test-XXXXXXXX-client.crt")
|
|
assert.NoError(t, err)
|
|
defer os.Remove(certFile.Name())
|
|
_, err = certFile.Write([]byte(
|
|
`-----BEGIN CERTIFICATE-----
|
|
MIIBfDCCAQICFANNDjPVDMTPm63C0jZ9M3H5I7GJMAoGCCqGSM49BAMCMCExCzAJ
|
|
BgNVBAYTAkRFMRIwEAYDVQQDDAlsb2NhbGhvc3QwIBcNMjMxMDI0MDcyMTU1WhgP
|
|
MjEyMzA5MzAwNzIxNTVaMCExCzAJBgNVBAYTAkRFMRIwEAYDVQQDDAlsb2NhbGhv
|
|
c3QwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAAQj7rjkeUEvjBT++IBMnIWgmI9VIjFx
|
|
4VUGFmzPEawOckdnKW4fBdePiItsgePDVK4Oys5bzfSDhl6aAPCe16pwvljB7yIm
|
|
xLJ+ytWk7OV/s10cmlaczrEtNeUjV1X9MTMwCgYIKoZIzj0EAwIDaAAwZQIwcZl8
|
|
TrwwsyX3A0enXB1ih+nruF8Q9f9Rmm2pNcbEv24QIW/P2HGQm9qfx4lrYa7hAjEA
|
|
goRP/fRfTTTLwLg8UBpUAmALX8A8HBSBaUlTTQcaImbcwU4DRSbv5JEA8tM1mWrA
|
|
-----END CERTIFICATE-----
|
|
`))
|
|
|
|
keyFile, err := os.CreateTemp("", "rfc2136-test-XXXXXXXX-client.key")
|
|
assert.NoError(t, err)
|
|
defer os.Remove(keyFile.Name())
|
|
_, err = keyFile.Write([]byte(
|
|
`-----BEGIN PRIVATE KEY-----
|
|
MIG2AgEAMBAGByqGSM49AgEGBSuBBAAiBIGeMIGbAgEBBDD5B+aPE+TuHCvW1f7L
|
|
U8jEPVXHv1fvCR8uBSsf1qdPo929XGpt5y5QfIGdW3NUeHWhZANiAAQj7rjkeUEv
|
|
jBT++IBMnIWgmI9VIjFx4VUGFmzPEawOckdnKW4fBdePiItsgePDVK4Oys5bzfSD
|
|
hl6aAPCe16pwvljB7yImxLJ+ytWk7OV/s10cmlaczrEtNeUjV1X9MTM=
|
|
-----END PRIVATE KEY-----
|
|
`))
|
|
|
|
tlsConfig := TLSConfig{
|
|
UseTLS: true,
|
|
SkipTLSVerify: false,
|
|
CAFilePath: caFile.Name(),
|
|
ClientCertFilePath: certFile.Name(),
|
|
ClientCertKeyFilePath: keyFile.Name(),
|
|
}
|
|
|
|
provider, err := createRfc2136TLSStubProvider(stub, tlsConfig)
|
|
log.Infof("provider, err is: %s", err)
|
|
assert.NoError(t, err)
|
|
|
|
rawProvider := provider.(*rfc2136Provider)
|
|
|
|
client, err := makeClient(*rawProvider)
|
|
log.Infof("client, err is: %v", client)
|
|
log.Infof("client, err is: %s", err)
|
|
assert.NoError(t, err)
|
|
|
|
assert.Equal(t, "tcp-tls", client.Net)
|
|
assert.Equal(t, false, client.TLSConfig.InsecureSkipVerify)
|
|
assert.Equal(t, "rfc2136-host", client.TLSConfig.ServerName)
|
|
assert.Equal(t, uint16(tls.VersionTLS13), client.TLSConfig.MinVersion)
|
|
assert.Equal(t, []string{"dot"}, client.TLSConfig.NextProtos)
|
|
}
|
|
|
|
func TestRfc2136GetRecords(t *testing.T) {
|
|
stub := newStub()
|
|
err := stub.setOutput([]string{
|
|
"v4.barfoo.com 3600 TXT test1",
|
|
"v1.foo.com 3600 TXT test2",
|
|
"v2.bar.com 3600 A 8.8.8.8",
|
|
"v3.bar.com 3600 TXT bbbb",
|
|
"v2.foo.com 3600 CNAME cccc",
|
|
"v1.foobar.com 3600 TXT dddd",
|
|
})
|
|
assert.NoError(t, err)
|
|
|
|
provider, err := createRfc2136StubProvider(stub)
|
|
assert.NoError(t, err)
|
|
|
|
recs, err := provider.Records(context.Background())
|
|
assert.NoError(t, err)
|
|
|
|
assert.Equal(t, 6, len(recs))
|
|
assert.True(t, contains(recs, "v1.foo.com"))
|
|
assert.True(t, contains(recs, "v2.bar.com"))
|
|
assert.True(t, contains(recs, "v2.foo.com"))
|
|
}
|
|
|
|
// Make sure the test version of SendMessage raises an error
|
|
// if a zone update ever contains records outside of it's zone
|
|
// as the TestRfc2136ApplyChanges tests all assume this
|
|
func TestRfc2136SendMessage(t *testing.T) {
|
|
stub := newStub()
|
|
|
|
m := new(dns.Msg)
|
|
m.SetUpdate("foo.com.")
|
|
rr, err := dns.NewRR(fmt.Sprintf("%s %d %s %s", "v1.foo.com.", 0, "A", "1.2.3.4"))
|
|
m.Insert([]dns.RR{rr})
|
|
|
|
err = stub.SendMessage(m)
|
|
assert.NoError(t, err)
|
|
|
|
rr, err = dns.NewRR(fmt.Sprintf("%s %d %s %s", "v1.bar.com.", 0, "A", "1.2.3.4"))
|
|
m.Insert([]dns.RR{rr})
|
|
|
|
err = stub.SendMessage(m)
|
|
assert.Error(t, err)
|
|
|
|
m.SetUpdate(".")
|
|
err = stub.SendMessage(m)
|
|
assert.NoError(t, err)
|
|
}
|
|
|
|
// These tests are use the . root zone with no filters
|
|
func TestRfc2136ApplyChanges(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{"1.2.3.4"},
|
|
RecordTTL: endpoint.TTL(400),
|
|
},
|
|
{
|
|
DNSName: "v1.foobar.com",
|
|
RecordType: "TXT",
|
|
Targets: []string{"boom"},
|
|
},
|
|
{
|
|
DNSName: "ns.foobar.com",
|
|
RecordType: "NS",
|
|
Targets: []string{"boom"},
|
|
},
|
|
},
|
|
Delete: []*endpoint.Endpoint{
|
|
{
|
|
DNSName: "v2.foo.com",
|
|
RecordType: "A",
|
|
Targets: []string{"1.2.3.4"},
|
|
},
|
|
{
|
|
DNSName: "v2.foobar.com",
|
|
RecordType: "TXT",
|
|
Targets: []string{"boom2"},
|
|
},
|
|
},
|
|
}
|
|
|
|
err = provider.ApplyChanges(context.Background(), p)
|
|
assert.NoError(t, err)
|
|
|
|
assert.Equal(t, 3, len(stub.createMsgs))
|
|
assert.True(t, strings.Contains(stub.createMsgs[0].String(), "v1.foo.com"))
|
|
assert.True(t, strings.Contains(stub.createMsgs[0].String(), "1.2.3.4"))
|
|
|
|
assert.True(t, strings.Contains(stub.createMsgs[1].String(), "v1.foobar.com"))
|
|
assert.True(t, strings.Contains(stub.createMsgs[1].String(), "boom"))
|
|
|
|
assert.True(t, strings.Contains(stub.createMsgs[2].String(), "ns.foobar.com"))
|
|
assert.True(t, strings.Contains(stub.createMsgs[2].String(), "boom"))
|
|
|
|
assert.Equal(t, 2, len(stub.updateMsgs))
|
|
assert.True(t, strings.Contains(stub.updateMsgs[0].String(), "v2.foo.com"))
|
|
assert.True(t, strings.Contains(stub.updateMsgs[1].String(), "v2.foobar.com"))
|
|
}
|
|
|
|
// These tests all use the foo.com and foobar.com zones with no filters
|
|
// createMsgs and updateMsgs need sorted when are are used
|
|
func TestRfc2136ApplyChangesWithZones(t *testing.T) {
|
|
stub := newStub()
|
|
provider, err := createRfc2136StubProviderWithZones(stub)
|
|
assert.NoError(t, err)
|
|
|
|
p := &plan.Changes{
|
|
Create: []*endpoint.Endpoint{
|
|
{
|
|
DNSName: "v1.foo.com",
|
|
RecordType: "A",
|
|
Targets: []string{"1.2.3.4"},
|
|
RecordTTL: endpoint.TTL(400),
|
|
},
|
|
{
|
|
DNSName: "v1.foobar.com",
|
|
RecordType: "TXT",
|
|
Targets: []string{"boom"},
|
|
},
|
|
{
|
|
DNSName: "ns.foobar.com",
|
|
RecordType: "NS",
|
|
Targets: []string{"boom"},
|
|
},
|
|
},
|
|
Delete: []*endpoint.Endpoint{
|
|
{
|
|
DNSName: "v2.foo.com",
|
|
RecordType: "A",
|
|
Targets: []string{"1.2.3.4"},
|
|
},
|
|
{
|
|
DNSName: "v2.foobar.com",
|
|
RecordType: "TXT",
|
|
Targets: []string{"boom2"},
|
|
},
|
|
},
|
|
}
|
|
|
|
err = provider.ApplyChanges(context.Background(), p)
|
|
assert.NoError(t, err)
|
|
|
|
assert.Equal(t, 3, len(stub.createMsgs))
|
|
createMsgs := getSortedChanges(stub.createMsgs)
|
|
assert.Equal(t, 3, len(createMsgs))
|
|
|
|
assert.True(t, strings.Contains(createMsgs[0], "v1.foo.com"))
|
|
assert.True(t, strings.Contains(createMsgs[0], "1.2.3.4"))
|
|
|
|
assert.True(t, strings.Contains(createMsgs[1], "v1.foobar.com"))
|
|
assert.True(t, strings.Contains(createMsgs[1], "boom"))
|
|
|
|
assert.True(t, strings.Contains(createMsgs[2], "ns.foobar.com"))
|
|
assert.True(t, strings.Contains(createMsgs[2], "boom"))
|
|
|
|
assert.Equal(t, 2, len(stub.updateMsgs))
|
|
updateMsgs := getSortedChanges(stub.updateMsgs)
|
|
assert.Equal(t, 2, len(updateMsgs))
|
|
|
|
assert.True(t, strings.Contains(updateMsgs[0], "v2.foo.com"))
|
|
assert.True(t, strings.Contains(updateMsgs[1], "v2.foobar.com"))
|
|
}
|
|
|
|
// These tests use the foo.com and foobar.com zones and with filters set to both zones
|
|
// createMsgs and updateMsgs need sorted when are are used
|
|
func TestRfc2136ApplyChangesWithZonesFilters(t *testing.T) {
|
|
stub := newStub()
|
|
provider, err := createRfc2136StubProviderWithZonesFilters(stub)
|
|
assert.NoError(t, err)
|
|
|
|
p := &plan.Changes{
|
|
Create: []*endpoint.Endpoint{
|
|
{
|
|
DNSName: "v1.foo.com",
|
|
RecordType: "A",
|
|
Targets: []string{"1.2.3.4"},
|
|
RecordTTL: endpoint.TTL(400),
|
|
},
|
|
{
|
|
DNSName: "v1.foobar.com",
|
|
RecordType: "TXT",
|
|
Targets: []string{"boom"},
|
|
},
|
|
{
|
|
DNSName: "ns.foobar.com",
|
|
RecordType: "NS",
|
|
Targets: []string{"boom"},
|
|
},
|
|
{
|
|
DNSName: "filtered-out.foo.bar",
|
|
RecordType: "A",
|
|
Targets: []string{"1.2.3.4"},
|
|
RecordTTL: endpoint.TTL(400),
|
|
},
|
|
},
|
|
Delete: []*endpoint.Endpoint{
|
|
{
|
|
DNSName: "v2.foo.com",
|
|
RecordType: "A",
|
|
Targets: []string{"1.2.3.4"},
|
|
},
|
|
{
|
|
DNSName: "v2.foobar.com",
|
|
RecordType: "TXT",
|
|
Targets: []string{"boom2"},
|
|
},
|
|
},
|
|
}
|
|
|
|
err = provider.ApplyChanges(context.Background(), p)
|
|
assert.NoError(t, err)
|
|
|
|
assert.Equal(t, 3, len(stub.createMsgs))
|
|
createMsgs := getSortedChanges(stub.createMsgs)
|
|
assert.Equal(t, 3, len(createMsgs))
|
|
|
|
assert.True(t, strings.Contains(createMsgs[0], "v1.foo.com"))
|
|
assert.True(t, strings.Contains(createMsgs[0], "1.2.3.4"))
|
|
|
|
assert.True(t, strings.Contains(createMsgs[1], "v1.foobar.com"))
|
|
assert.True(t, strings.Contains(createMsgs[1], "boom"))
|
|
|
|
assert.True(t, strings.Contains(createMsgs[2], "ns.foobar.com"))
|
|
assert.True(t, strings.Contains(createMsgs[2], "boom"))
|
|
|
|
for _, s := range createMsgs {
|
|
assert.False(t, strings.Contains(s, "filtered-out.foo.bar"))
|
|
}
|
|
|
|
assert.Equal(t, 2, len(stub.updateMsgs))
|
|
updateMsgs := getSortedChanges(stub.updateMsgs)
|
|
assert.Equal(t, 2, len(updateMsgs))
|
|
|
|
assert.True(t, strings.Contains(updateMsgs[0], "v2.foo.com"))
|
|
assert.True(t, strings.Contains(updateMsgs[1], "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 := extractUpdateSectionFromMessage(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"))
|
|
}
|
|
|
|
func TestRfc2136ApplyChangesWithUpdate(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{"1.2.3.4"},
|
|
RecordTTL: endpoint.TTL(400),
|
|
},
|
|
{
|
|
DNSName: "v1.foobar.com",
|
|
RecordType: "TXT",
|
|
Targets: []string{"boom"},
|
|
},
|
|
},
|
|
}
|
|
|
|
err = provider.ApplyChanges(context.Background(), p)
|
|
assert.NoError(t, err)
|
|
|
|
p = &plan.Changes{
|
|
UpdateOld: []*endpoint.Endpoint{
|
|
{
|
|
DNSName: "v1.foo.com",
|
|
RecordType: "A",
|
|
Targets: []string{"1.2.3.4"},
|
|
RecordTTL: endpoint.TTL(400),
|
|
},
|
|
{
|
|
DNSName: "v1.foobar.com",
|
|
RecordType: "TXT",
|
|
Targets: []string{"boom"},
|
|
},
|
|
},
|
|
UpdateNew: []*endpoint.Endpoint{
|
|
{
|
|
DNSName: "v1.foo.com",
|
|
RecordType: "A",
|
|
Targets: []string{"1.2.3.5"},
|
|
RecordTTL: endpoint.TTL(400),
|
|
},
|
|
{
|
|
DNSName: "v1.foobar.com",
|
|
RecordType: "TXT",
|
|
Targets: []string{"kablui"},
|
|
},
|
|
},
|
|
}
|
|
|
|
err = provider.ApplyChanges(context.Background(), p)
|
|
assert.NoError(t, err)
|
|
|
|
assert.Equal(t, 4, len(stub.createMsgs))
|
|
assert.Equal(t, 2, len(stub.updateMsgs))
|
|
|
|
assert.True(t, strings.Contains(stub.createMsgs[0].String(), "v1.foo.com"))
|
|
assert.True(t, strings.Contains(stub.createMsgs[0].String(), "1.2.3.4"))
|
|
assert.True(t, strings.Contains(stub.createMsgs[2].String(), "v1.foo.com"))
|
|
assert.True(t, strings.Contains(stub.createMsgs[2].String(), "1.2.3.5"))
|
|
|
|
assert.True(t, strings.Contains(stub.updateMsgs[0].String(), "v1.foo.com"))
|
|
assert.True(t, strings.Contains(stub.updateMsgs[0].String(), "1.2.3.4"))
|
|
|
|
assert.True(t, strings.Contains(stub.createMsgs[1].String(), "v1.foobar.com"))
|
|
assert.True(t, strings.Contains(stub.createMsgs[1].String(), "boom"))
|
|
assert.True(t, strings.Contains(stub.createMsgs[3].String(), "v1.foobar.com"))
|
|
assert.True(t, strings.Contains(stub.createMsgs[3].String(), "kablui"))
|
|
|
|
assert.True(t, strings.Contains(stub.updateMsgs[1].String(), "v1.foobar.com"))
|
|
assert.True(t, strings.Contains(stub.updateMsgs[1].String(), "boom"))
|
|
}
|
|
|
|
func TestChunkBy(t *testing.T) {
|
|
var records []*endpoint.Endpoint
|
|
|
|
for i := 0; i < 10; i++ {
|
|
records = append(records, &endpoint.Endpoint{
|
|
DNSName: "v1.foo.com",
|
|
RecordType: "A",
|
|
Targets: []string{"1.1.2.2"},
|
|
RecordTTL: endpoint.TTL(400),
|
|
})
|
|
}
|
|
|
|
chunks := chunkBy(records, 2)
|
|
if len(chunks) != 5 {
|
|
t.Errorf("incorrect number of chunks returned")
|
|
}
|
|
}
|
|
|
|
func contains(arr []*endpoint.Endpoint, name string) bool {
|
|
for _, a := range arr {
|
|
if a.DNSName == name {
|
|
return true
|
|
}
|
|
}
|
|
return false
|
|
}
|