mirror of
https://github.com/kubernetes-sigs/external-dns.git
synced 2025-08-06 17:46:57 +02:00
support multiple hosted zones and automatic lookup (#152)
* feat(aws): support multiple hosted zones and automatic lookup * chore: run gofmt with the simplified command * fix(aws): add missing method from google provider * fix: remove superflous parameter from google provider * feat: make domain configurable via flag * fix(aws): remove unused constant * fix(aws): don't log actions that were filtered out * feat(aws): detect best possible zone to put dns entries in * fix(aws): log error instead of failing if a change batch fails * chore: update changelog with support for multiple zones
This commit is contained in:
parent
d7513580f7
commit
03d76204f9
@ -1,5 +1,6 @@
|
|||||||
Features:
|
Features:
|
||||||
|
|
||||||
|
- Route 53: Support creation of records in multiple hosted zones.
|
||||||
- Route 53: Support creation of ALIAS records when endpoint target is a ELB/ALB.
|
- Route 53: Support creation of ALIAS records when endpoint target is a ELB/ALB.
|
||||||
- Ownership via TXT records
|
- Ownership via TXT records
|
||||||
1. Create TXT records to mark the records managed by External DNS
|
1. Create TXT records to mark the records managed by External DNS
|
||||||
|
2
main.go
2
main.go
@ -96,7 +96,7 @@ func main() {
|
|||||||
case "google":
|
case "google":
|
||||||
p, err = provider.NewGoogleProvider(cfg.GoogleProject, cfg.DryRun)
|
p, err = provider.NewGoogleProvider(cfg.GoogleProject, cfg.DryRun)
|
||||||
case "aws":
|
case "aws":
|
||||||
p, err = provider.NewAWSProvider(cfg.DryRun)
|
p, err = provider.NewAWSProvider(cfg.Domain, cfg.DryRun)
|
||||||
default:
|
default:
|
||||||
log.Fatalf("unknown dns provider: %s", cfg.Provider)
|
log.Fatalf("unknown dns provider: %s", cfg.Provider)
|
||||||
}
|
}
|
||||||
|
@ -35,6 +35,7 @@ type Config struct {
|
|||||||
KubeConfig string
|
KubeConfig string
|
||||||
Namespace string
|
Namespace string
|
||||||
Zone string
|
Zone string
|
||||||
|
Domain string
|
||||||
Sources []string
|
Sources []string
|
||||||
Provider string
|
Provider string
|
||||||
GoogleProject string
|
GoogleProject string
|
||||||
@ -64,6 +65,7 @@ func (cfg *Config) ParseFlags(args []string) error {
|
|||||||
flags.StringVar(&cfg.KubeConfig, "kubeconfig", "", "path to a local kubeconfig file")
|
flags.StringVar(&cfg.KubeConfig, "kubeconfig", "", "path to a local kubeconfig file")
|
||||||
flags.StringVar(&cfg.Namespace, "namespace", v1.NamespaceAll, "the namespace to look for endpoints; all namespaces by default")
|
flags.StringVar(&cfg.Namespace, "namespace", v1.NamespaceAll, "the namespace to look for endpoints; all namespaces by default")
|
||||||
flags.StringVar(&cfg.Zone, "zone", "", "the ID of the hosted zone to target")
|
flags.StringVar(&cfg.Zone, "zone", "", "the ID of the hosted zone to target")
|
||||||
|
flags.StringVar(&cfg.Domain, "domain", "example.org.", "the name of the top-level domain to manage")
|
||||||
flags.StringArrayVar(&cfg.Sources, "source", nil, "the sources to gather endpoints: [service, ingress], e.g. --source service --source ingress")
|
flags.StringArrayVar(&cfg.Sources, "source", nil, "the sources to gather endpoints: [service, ingress], e.g. --source service --source ingress")
|
||||||
flags.StringVar(&cfg.Provider, "provider", "", "the DNS provider to materialize the records in: <aws|google>")
|
flags.StringVar(&cfg.Provider, "provider", "", "the DNS provider to materialize the records in: <aws|google>")
|
||||||
flags.StringVar(&cfg.GoogleProject, "google-project", "", "gcloud project to target")
|
flags.StringVar(&cfg.GoogleProject, "google-project", "", "gcloud project to target")
|
||||||
|
@ -37,6 +37,7 @@ func TestParseFlags(t *testing.T) {
|
|||||||
KubeConfig: "",
|
KubeConfig: "",
|
||||||
Namespace: "",
|
Namespace: "",
|
||||||
Zone: "",
|
Zone: "",
|
||||||
|
Domain: "example.org.",
|
||||||
Sources: nil,
|
Sources: nil,
|
||||||
Provider: "",
|
Provider: "",
|
||||||
GoogleProject: "",
|
GoogleProject: "",
|
||||||
@ -62,6 +63,7 @@ func TestParseFlags(t *testing.T) {
|
|||||||
KubeConfig: "",
|
KubeConfig: "",
|
||||||
Namespace: "",
|
Namespace: "",
|
||||||
Zone: "",
|
Zone: "",
|
||||||
|
Domain: "example.org.",
|
||||||
Sources: nil,
|
Sources: nil,
|
||||||
Provider: "",
|
Provider: "",
|
||||||
GoogleProject: "",
|
GoogleProject: "",
|
||||||
@ -87,6 +89,7 @@ func TestParseFlags(t *testing.T) {
|
|||||||
KubeConfig: "myhome",
|
KubeConfig: "myhome",
|
||||||
Namespace: "",
|
Namespace: "",
|
||||||
Zone: "",
|
Zone: "",
|
||||||
|
Domain: "example.org.",
|
||||||
Sources: nil,
|
Sources: nil,
|
||||||
Provider: "",
|
Provider: "",
|
||||||
GoogleProject: "",
|
GoogleProject: "",
|
||||||
@ -117,6 +120,7 @@ func TestParseFlags(t *testing.T) {
|
|||||||
KubeConfig: "",
|
KubeConfig: "",
|
||||||
Namespace: "",
|
Namespace: "",
|
||||||
Zone: "",
|
Zone: "",
|
||||||
|
Domain: "example.org.",
|
||||||
Sources: nil,
|
Sources: nil,
|
||||||
Provider: "",
|
Provider: "",
|
||||||
GoogleProject: "",
|
GoogleProject: "",
|
||||||
@ -141,6 +145,7 @@ func TestParseFlags(t *testing.T) {
|
|||||||
"--kubeconfig", "/some/path",
|
"--kubeconfig", "/some/path",
|
||||||
"--namespace", "namespace",
|
"--namespace", "namespace",
|
||||||
"--zone", "zone",
|
"--zone", "zone",
|
||||||
|
"--domain", "kubernetes.io.",
|
||||||
"--source", "source",
|
"--source", "source",
|
||||||
"--provider", "provider",
|
"--provider", "provider",
|
||||||
"--google-project", "project",
|
"--google-project", "project",
|
||||||
@ -160,6 +165,7 @@ func TestParseFlags(t *testing.T) {
|
|||||||
KubeConfig: "/some/path",
|
KubeConfig: "/some/path",
|
||||||
Namespace: "namespace",
|
Namespace: "namespace",
|
||||||
Zone: "zone",
|
Zone: "zone",
|
||||||
|
Domain: "kubernetes.io.",
|
||||||
Sources: []string{"source"},
|
Sources: []string{"source"},
|
||||||
Provider: "provider",
|
Provider: "provider",
|
||||||
GoogleProject: "project",
|
GoogleProject: "project",
|
||||||
|
159
provider/aws.go
159
provider/aws.go
@ -17,6 +17,7 @@ limitations under the License.
|
|||||||
package provider
|
package provider
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"net"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
log "github.com/Sirupsen/logrus"
|
log "github.com/Sirupsen/logrus"
|
||||||
@ -30,7 +31,6 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
hostedZonePrefix = "/hostedzone/"
|
|
||||||
elbHostnameSuffix = ".elb.amazonaws.com"
|
elbHostnameSuffix = ".elb.amazonaws.com"
|
||||||
evaluateTargetHealth = true
|
evaluateTargetHealth = true
|
||||||
recordTTL = 300
|
recordTTL = 300
|
||||||
@ -62,16 +62,19 @@ type Route53API interface {
|
|||||||
ListResourceRecordSetsPages(input *route53.ListResourceRecordSetsInput, fn func(resp *route53.ListResourceRecordSetsOutput, lastPage bool) (shouldContinue bool)) error
|
ListResourceRecordSetsPages(input *route53.ListResourceRecordSetsInput, fn func(resp *route53.ListResourceRecordSetsOutput, lastPage bool) (shouldContinue bool)) error
|
||||||
ChangeResourceRecordSets(*route53.ChangeResourceRecordSetsInput) (*route53.ChangeResourceRecordSetsOutput, error)
|
ChangeResourceRecordSets(*route53.ChangeResourceRecordSetsInput) (*route53.ChangeResourceRecordSetsOutput, error)
|
||||||
CreateHostedZone(*route53.CreateHostedZoneInput) (*route53.CreateHostedZoneOutput, error)
|
CreateHostedZone(*route53.CreateHostedZoneInput) (*route53.CreateHostedZoneOutput, error)
|
||||||
|
ListHostedZonesPages(input *route53.ListHostedZonesInput, fn func(resp *route53.ListHostedZonesOutput, lastPage bool) (shouldContinue bool)) error
|
||||||
}
|
}
|
||||||
|
|
||||||
// AWSProvider is an implementation of Provider for AWS Route53.
|
// AWSProvider is an implementation of Provider for AWS Route53.
|
||||||
type AWSProvider struct {
|
type AWSProvider struct {
|
||||||
Client Route53API
|
Client Route53API
|
||||||
DryRun bool
|
DryRun bool
|
||||||
|
// only consider hosted zones managing domains ending in this suffix
|
||||||
|
Domain string
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewAWSProvider initializes a new AWS Route53 based Provider.
|
// NewAWSProvider initializes a new AWS Route53 based Provider.
|
||||||
func NewAWSProvider(dryRun bool) (Provider, error) {
|
func NewAWSProvider(domain string, dryRun bool) (Provider, error) {
|
||||||
config := aws.NewConfig()
|
config := aws.NewConfig()
|
||||||
|
|
||||||
session, err := session.NewSessionWithOptions(session.Options{
|
session, err := session.NewSessionWithOptions(session.Options{
|
||||||
@ -84,15 +87,41 @@ func NewAWSProvider(dryRun bool) (Provider, error) {
|
|||||||
|
|
||||||
provider := &AWSProvider{
|
provider := &AWSProvider{
|
||||||
Client: route53.New(session),
|
Client: route53.New(session),
|
||||||
|
Domain: domain,
|
||||||
DryRun: dryRun,
|
DryRun: dryRun,
|
||||||
}
|
}
|
||||||
|
|
||||||
return provider, nil
|
return provider, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Zones returns the list of hosted zones.
|
||||||
|
func (p *AWSProvider) Zones() (map[string]*route53.HostedZone, error) {
|
||||||
|
zones := make(map[string]*route53.HostedZone)
|
||||||
|
|
||||||
|
f := func(resp *route53.ListHostedZonesOutput, lastPage bool) (shouldContinue bool) {
|
||||||
|
for _, zone := range resp.HostedZones {
|
||||||
|
if strings.HasSuffix(aws.StringValue(zone.Name), p.Domain) {
|
||||||
|
zones[aws.StringValue(zone.Id)] = zone
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
err := p.Client.ListHostedZonesPages(&route53.ListHostedZonesInput{}, f)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return zones, nil
|
||||||
|
}
|
||||||
|
|
||||||
// Records returns the list of records in a given hosted zone.
|
// Records returns the list of records in a given hosted zone.
|
||||||
func (p *AWSProvider) Records(zone string) ([]*endpoint.Endpoint, error) {
|
func (p *AWSProvider) Records(_ string) (endpoints []*endpoint.Endpoint, _ error) {
|
||||||
endpoints := []*endpoint.Endpoint{}
|
zones, err := p.Zones()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
f := func(resp *route53.ListResourceRecordSetsOutput, lastPage bool) (shouldContinue bool) {
|
f := func(resp *route53.ListResourceRecordSetsOutput, lastPage bool) (shouldContinue bool) {
|
||||||
for _, r := range resp.ResourceRecordSets {
|
for _, r := range resp.ResourceRecordSets {
|
||||||
@ -117,72 +146,108 @@ func (p *AWSProvider) Records(zone string) ([]*endpoint.Endpoint, error) {
|
|||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
params := &route53.ListResourceRecordSetsInput{
|
for _, z := range zones {
|
||||||
HostedZoneId: aws.String(expandedHostedZoneID(zone)),
|
params := &route53.ListResourceRecordSetsInput{
|
||||||
}
|
HostedZoneId: z.Id,
|
||||||
|
}
|
||||||
|
|
||||||
if err := p.Client.ListResourceRecordSetsPages(params, f); err != nil {
|
if err := p.Client.ListResourceRecordSetsPages(params, f); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return endpoints, nil
|
return endpoints, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// CreateRecords creates a given set of DNS records in the given hosted zone.
|
// CreateRecords creates a given set of DNS records in the given hosted zone.
|
||||||
func (p *AWSProvider) CreateRecords(zone string, endpoints []*endpoint.Endpoint) error {
|
func (p *AWSProvider) CreateRecords(endpoints []*endpoint.Endpoint) error {
|
||||||
return p.submitChanges(zone, newChanges(route53.ChangeActionCreate, endpoints))
|
return p.submitChanges(newChanges(route53.ChangeActionCreate, endpoints))
|
||||||
}
|
}
|
||||||
|
|
||||||
// UpdateRecords updates a given set of old records to a new set of records in a given hosted zone.
|
// UpdateRecords updates a given set of old records to a new set of records in a given hosted zone.
|
||||||
func (p *AWSProvider) UpdateRecords(zone string, endpoints, _ []*endpoint.Endpoint) error {
|
func (p *AWSProvider) UpdateRecords(endpoints, _ []*endpoint.Endpoint) error {
|
||||||
return p.submitChanges(zone, newChanges(route53.ChangeActionUpsert, endpoints))
|
return p.submitChanges(newChanges(route53.ChangeActionUpsert, endpoints))
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeleteRecords deletes a given set of DNS records in a given zone.
|
// DeleteRecords deletes a given set of DNS records in a given zone.
|
||||||
func (p *AWSProvider) DeleteRecords(zone string, endpoints []*endpoint.Endpoint) error {
|
func (p *AWSProvider) DeleteRecords(endpoints []*endpoint.Endpoint) error {
|
||||||
return p.submitChanges(zone, newChanges(route53.ChangeActionDelete, endpoints))
|
return p.submitChanges(newChanges(route53.ChangeActionDelete, endpoints))
|
||||||
}
|
}
|
||||||
|
|
||||||
// ApplyChanges applies a given set of changes in a given zone.
|
// ApplyChanges applies a given set of changes in a given zone.
|
||||||
func (p *AWSProvider) ApplyChanges(zone string, changes *plan.Changes) error {
|
func (p *AWSProvider) ApplyChanges(_ string, changes *plan.Changes) error {
|
||||||
combinedChanges := make([]*route53.Change, 0, len(changes.Create)+len(changes.UpdateNew)+len(changes.Delete))
|
combinedChanges := make([]*route53.Change, 0, len(changes.Create)+len(changes.UpdateNew)+len(changes.Delete))
|
||||||
|
|
||||||
combinedChanges = append(combinedChanges, newChanges(route53.ChangeActionCreate, changes.Create)...)
|
combinedChanges = append(combinedChanges, newChanges(route53.ChangeActionCreate, changes.Create)...)
|
||||||
combinedChanges = append(combinedChanges, newChanges(route53.ChangeActionUpsert, changes.UpdateNew)...)
|
combinedChanges = append(combinedChanges, newChanges(route53.ChangeActionUpsert, changes.UpdateNew)...)
|
||||||
combinedChanges = append(combinedChanges, newChanges(route53.ChangeActionDelete, changes.Delete)...)
|
combinedChanges = append(combinedChanges, newChanges(route53.ChangeActionDelete, changes.Delete)...)
|
||||||
|
|
||||||
return p.submitChanges(zone, combinedChanges)
|
return p.submitChanges(combinedChanges)
|
||||||
}
|
}
|
||||||
|
|
||||||
// submitChanges takes a zone and a collection of Changes and sends them as a single transaction.
|
// submitChanges takes a zone and a collection of Changes and sends them as a single transaction.
|
||||||
func (p *AWSProvider) submitChanges(zone string, changes []*route53.Change) error {
|
func (p *AWSProvider) submitChanges(changes []*route53.Change) error {
|
||||||
// return early if there is nothing to change
|
// return early if there is nothing to change
|
||||||
if len(changes) == 0 {
|
if len(changes) == 0 {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
if p.DryRun {
|
zones, err := p.Zones()
|
||||||
for _, change := range changes {
|
if err != nil {
|
||||||
log.Infof("Changing records: %s %s", aws.StringValue(change.Action), change.String())
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
params := &route53.ChangeResourceRecordSetsInput{
|
|
||||||
HostedZoneId: aws.String(expandedHostedZoneID(zone)),
|
|
||||||
ChangeBatch: &route53.ChangeBatch{
|
|
||||||
Changes: changes,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
if _, err := p.Client.ChangeResourceRecordSets(params); err != nil {
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// separate into per-zone change sets to be passed to the API.
|
||||||
|
changesByZone := changesByZone(zones, changes)
|
||||||
|
|
||||||
|
for z, cs := range changesByZone {
|
||||||
|
if p.DryRun {
|
||||||
|
for _, c := range cs {
|
||||||
|
log.Infof("Changing records: %s %s", aws.StringValue(c.Action), c.String())
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
params := &route53.ChangeResourceRecordSetsInput{
|
||||||
|
HostedZoneId: aws.String(z),
|
||||||
|
ChangeBatch: &route53.ChangeBatch{
|
||||||
|
Changes: cs,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
if _, err := p.Client.ChangeResourceRecordSets(params); err != nil {
|
||||||
|
log.Error(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// changesByZone separates a multi-zone change into a single change per zone.
|
||||||
|
func changesByZone(zones map[string]*route53.HostedZone, changeSet []*route53.Change) map[string][]*route53.Change {
|
||||||
|
changes := make(map[string][]*route53.Change)
|
||||||
|
|
||||||
|
for _, z := range zones {
|
||||||
|
changes[aws.StringValue(z.Id)] = []*route53.Change{}
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, c := range changeSet {
|
||||||
|
hostname := ensureTrailingDot(aws.StringValue(c.ResourceRecordSet.Name))
|
||||||
|
|
||||||
|
if zone := suitableZone(hostname, zones); zone != nil {
|
||||||
|
changes[aws.StringValue(zone.Id)] = append(changes[aws.StringValue(zone.Id)], c)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// separating a change could lead to empty sub changes, remove them here.
|
||||||
|
for zone, change := range changes {
|
||||||
|
if len(change) == 0 {
|
||||||
|
delete(changes, zone)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return changes
|
||||||
|
}
|
||||||
|
|
||||||
// newChanges returns a collection of Changes based on the given records and action.
|
// newChanges returns a collection of Changes based on the given records and action.
|
||||||
func newChanges(action string, endpoints []*endpoint.Endpoint) []*route53.Change {
|
func newChanges(action string, endpoints []*endpoint.Endpoint) []*route53.Change {
|
||||||
changes := make([]*route53.Change, 0, len(endpoints))
|
changes := make([]*route53.Change, 0, len(endpoints))
|
||||||
@ -225,6 +290,22 @@ func newChange(action string, endpoint *endpoint.Endpoint) *route53.Change {
|
|||||||
return change
|
return change
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// suitableZone returns the most suitable zone for a given hostname and a set of zones.
|
||||||
|
func suitableZone(hostname string, zones map[string]*route53.HostedZone) *route53.HostedZone {
|
||||||
|
var zone *route53.HostedZone
|
||||||
|
|
||||||
|
for _, z := range zones {
|
||||||
|
if strings.HasSuffix(hostname, aws.StringValue(z.Name)) {
|
||||||
|
if zone == nil || len(aws.StringValue(z.Name)) > len(aws.StringValue(zone.Name)) {
|
||||||
|
zone = z
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return zone
|
||||||
|
}
|
||||||
|
|
||||||
|
// isAWSLoadBalancer determines if a given hostname belongs to an AWS load balancer.
|
||||||
func isAWSLoadBalancer(ep *endpoint.Endpoint) bool {
|
func isAWSLoadBalancer(ep *endpoint.Endpoint) bool {
|
||||||
if ep.RecordType == "" {
|
if ep.RecordType == "" {
|
||||||
return canonicalHostedZone(ep.Target) != ""
|
return canonicalHostedZone(ep.Target) != ""
|
||||||
@ -233,6 +314,7 @@ func isAWSLoadBalancer(ep *endpoint.Endpoint) bool {
|
|||||||
return ep.RecordType == "ALIAS"
|
return ep.RecordType == "ALIAS"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// canonicalHostedZone returns the matching canonical zone for a given hostname.
|
||||||
func canonicalHostedZone(hostname string) string {
|
func canonicalHostedZone(hostname string) string {
|
||||||
for suffix, zone := range canonicalHostedZones {
|
for suffix, zone := range canonicalHostedZones {
|
||||||
if strings.HasSuffix(hostname, suffix) {
|
if strings.HasSuffix(hostname, suffix) {
|
||||||
@ -243,6 +325,11 @@ func canonicalHostedZone(hostname string) string {
|
|||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
|
||||||
func expandedHostedZoneID(zone string) string {
|
// ensureTrailingDot ensures that the hostname receives a trailing dot if it hasn't already.
|
||||||
return hostedZonePrefix + strings.TrimPrefix(zone, hostedZonePrefix)
|
func ensureTrailingDot(hostname string) string {
|
||||||
|
if net.ParseIP(hostname) != nil {
|
||||||
|
return hostname
|
||||||
|
}
|
||||||
|
|
||||||
|
return strings.TrimSuffix(hostname, ".") + "."
|
||||||
}
|
}
|
||||||
|
@ -20,7 +20,6 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"net"
|
"net"
|
||||||
"reflect"
|
"reflect"
|
||||||
"strings"
|
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/aws/aws-sdk-go/aws"
|
"github.com/aws/aws-sdk-go/aws"
|
||||||
@ -32,11 +31,6 @@ import (
|
|||||||
"github.com/kubernetes-incubator/external-dns/plan"
|
"github.com/kubernetes-incubator/external-dns/plan"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
|
||||||
// ID of the hosted zone where the tests are running.
|
|
||||||
testZone = "ext-dns-test.teapot.zalan.do."
|
|
||||||
)
|
|
||||||
|
|
||||||
// Compile time check for interface conformance
|
// Compile time check for interface conformance
|
||||||
var _ Route53API = &Route53APIStub{}
|
var _ Route53API = &Route53APIStub{}
|
||||||
|
|
||||||
@ -126,6 +120,16 @@ func (r *Route53APIStub) ChangeResourceRecordSets(input *route53.ChangeResourceR
|
|||||||
return output, nil // TODO: We should ideally return status etc, but we don't' use that yet.
|
return output, nil // TODO: We should ideally return status etc, but we don't' use that yet.
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (r *Route53APIStub) ListHostedZonesPages(input *route53.ListHostedZonesInput, fn func(p *route53.ListHostedZonesOutput, lastPage bool) (shouldContinue bool)) error {
|
||||||
|
output := &route53.ListHostedZonesOutput{}
|
||||||
|
for _, zone := range r.zones {
|
||||||
|
output.HostedZones = append(output.HostedZones, zone)
|
||||||
|
}
|
||||||
|
lastPage := true
|
||||||
|
fn(output, lastPage)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func (r *Route53APIStub) CreateHostedZone(input *route53.CreateHostedZoneInput) (*route53.CreateHostedZoneOutput, error) {
|
func (r *Route53APIStub) CreateHostedZone(input *route53.CreateHostedZoneInput) (*route53.CreateHostedZoneOutput, error) {
|
||||||
name := aws.StringValue(input.Name)
|
name := aws.StringValue(input.Name)
|
||||||
id := "/hostedzone/" + name
|
id := "/hostedzone/" + name
|
||||||
@ -139,84 +143,124 @@ func (r *Route53APIStub) CreateHostedZone(input *route53.CreateHostedZoneInput)
|
|||||||
return &route53.CreateHostedZoneOutput{HostedZone: r.zones[id]}, nil
|
return &route53.CreateHostedZoneOutput{HostedZone: r.zones[id]}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestAWSRecords(t *testing.T) {
|
func TestAWSZones(t *testing.T) {
|
||||||
provider := newAWSProvider(t, false, []*endpoint.Endpoint{
|
provider := newAWSProvider(t, "ext-dns-test-2.teapot.zalan.do.", false, []*endpoint.Endpoint{})
|
||||||
endpoint.NewEndpoint("list-test.ext-dns-test.teapot.zalan.do", "8.8.8.8", "A"),
|
|
||||||
endpoint.NewEndpoint("list-test-alias.ext-dns-test.teapot.zalan.do", "foo.eu-central-1.elb.amazonaws.com", "ALIAS"),
|
|
||||||
})
|
|
||||||
|
|
||||||
records, err := provider.Records(testZone)
|
zones, err := provider.Zones()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
validateAWSZones(t, zones, map[string]*route53.HostedZone{
|
||||||
|
"/hostedzone/zone-1.ext-dns-test-2.teapot.zalan.do.": {
|
||||||
|
Id: aws.String("/hostedzone/zone-1.ext-dns-test-2.teapot.zalan.do."),
|
||||||
|
Name: aws.String("zone-1.ext-dns-test-2.teapot.zalan.do."),
|
||||||
|
},
|
||||||
|
"/hostedzone/zone-2.ext-dns-test-2.teapot.zalan.do.": {
|
||||||
|
Id: aws.String("/hostedzone/zone-2.ext-dns-test-2.teapot.zalan.do."),
|
||||||
|
Name: aws.String("zone-2.ext-dns-test-2.teapot.zalan.do."),
|
||||||
|
},
|
||||||
|
"/hostedzone/zone-3.ext-dns-test-2.teapot.zalan.do.": {
|
||||||
|
Id: aws.String("/hostedzone/zone-3.ext-dns-test-2.teapot.zalan.do."),
|
||||||
|
Name: aws.String("zone-3.ext-dns-test-2.teapot.zalan.do."),
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestAWSRecords(t *testing.T) {
|
||||||
|
provider := newAWSProvider(t, "ext-dns-test-2.teapot.zalan.do.", false, []*endpoint.Endpoint{
|
||||||
|
endpoint.NewEndpoint("list-test.zone-1.ext-dns-test-2.teapot.zalan.do", "1.2.3.4", "A"),
|
||||||
|
endpoint.NewEndpoint("list-test.zone-2.ext-dns-test-2.teapot.zalan.do", "8.8.8.8", "A"),
|
||||||
|
endpoint.NewEndpoint("list-test-alias.zone-1.ext-dns-test-2.teapot.zalan.do", "foo.eu-central-1.elb.amazonaws.com", "ALIAS"),
|
||||||
|
})
|
||||||
|
|
||||||
|
records, err := provider.Records("_")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
validateEndpoints(t, records, []*endpoint.Endpoint{
|
validateEndpoints(t, records, []*endpoint.Endpoint{
|
||||||
endpoint.NewEndpoint("list-test.ext-dns-test.teapot.zalan.do", "8.8.8.8", "A"),
|
endpoint.NewEndpoint("list-test.zone-1.ext-dns-test-2.teapot.zalan.do", "1.2.3.4", "A"),
|
||||||
endpoint.NewEndpoint("list-test-alias.ext-dns-test.teapot.zalan.do", "foo.eu-central-1.elb.amazonaws.com", "ALIAS"),
|
endpoint.NewEndpoint("list-test.zone-2.ext-dns-test-2.teapot.zalan.do", "8.8.8.8", "A"),
|
||||||
|
endpoint.NewEndpoint("list-test-alias.zone-1.ext-dns-test-2.teapot.zalan.do", "foo.eu-central-1.elb.amazonaws.com", "ALIAS"),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestAWSCreateRecords(t *testing.T) {
|
func TestAWSCreateRecords(t *testing.T) {
|
||||||
provider := newAWSProvider(t, false, []*endpoint.Endpoint{})
|
provider := newAWSProvider(t, "ext-dns-test-2.teapot.zalan.do.", false, []*endpoint.Endpoint{})
|
||||||
|
|
||||||
records := []*endpoint.Endpoint{
|
records := []*endpoint.Endpoint{
|
||||||
endpoint.NewEndpoint("create-test.ext-dns-test.teapot.zalan.do", "8.8.8.8", ""),
|
endpoint.NewEndpoint("create-test.zone-1.ext-dns-test-2.teapot.zalan.do", "1.2.3.4", ""),
|
||||||
|
endpoint.NewEndpoint("create-test.zone-2.ext-dns-test-2.teapot.zalan.do", "8.8.8.8", ""),
|
||||||
|
endpoint.NewEndpoint("create-test-cname.zone-1.ext-dns-test-2.teapot.zalan.do", "foo.elb.amazonaws.com", ""),
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := provider.CreateRecords(testZone, records); err != nil {
|
if err := provider.CreateRecords(records); err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
records, err := provider.Records(testZone)
|
records, err := provider.Records("_")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
validateEndpoints(t, records, []*endpoint.Endpoint{
|
validateEndpoints(t, records, []*endpoint.Endpoint{
|
||||||
endpoint.NewEndpoint("create-test.ext-dns-test.teapot.zalan.do", "8.8.8.8", "A"),
|
endpoint.NewEndpoint("create-test.zone-1.ext-dns-test-2.teapot.zalan.do", "1.2.3.4", "A"),
|
||||||
|
endpoint.NewEndpoint("create-test.zone-2.ext-dns-test-2.teapot.zalan.do", "8.8.8.8", "A"),
|
||||||
|
endpoint.NewEndpoint("create-test-cname.zone-1.ext-dns-test-2.teapot.zalan.do", "foo.elb.amazonaws.com", "CNAME"),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestAWSUpdateRecords(t *testing.T) {
|
func TestAWSUpdateRecords(t *testing.T) {
|
||||||
provider := newAWSProvider(t, false, []*endpoint.Endpoint{
|
provider := newAWSProvider(t, "ext-dns-test-2.teapot.zalan.do.", false, []*endpoint.Endpoint{
|
||||||
endpoint.NewEndpoint("update-test.ext-dns-test.teapot.zalan.do", "8.8.8.8", "A"),
|
endpoint.NewEndpoint("update-test.zone-1.ext-dns-test-2.teapot.zalan.do", "8.8.8.8", "A"),
|
||||||
|
endpoint.NewEndpoint("update-test.zone-2.ext-dns-test-2.teapot.zalan.do", "8.8.4.4", "A"),
|
||||||
|
endpoint.NewEndpoint("update-test-cname.zone-1.ext-dns-test-2.teapot.zalan.do", "foo.elb.amazonaws.com", "CNAME"),
|
||||||
})
|
})
|
||||||
|
|
||||||
currentRecords := []*endpoint.Endpoint{
|
currentRecords := []*endpoint.Endpoint{
|
||||||
endpoint.NewEndpoint("update-test.ext-dns-test.teapot.zalan.do", "8.8.8.8", "A"),
|
endpoint.NewEndpoint("update-test.zone-1.ext-dns-test-2.teapot.zalan.do", "8.8.8.8", "A"),
|
||||||
|
endpoint.NewEndpoint("update-test.zone-2.ext-dns-test-2.teapot.zalan.do", "8.8.4.4", "A"),
|
||||||
|
endpoint.NewEndpoint("update-test-cname.zone-1.ext-dns-test-2.teapot.zalan.do", "foo.elb.amazonaws.com", "CNAME"),
|
||||||
}
|
}
|
||||||
updatedRecords := []*endpoint.Endpoint{
|
updatedRecords := []*endpoint.Endpoint{
|
||||||
endpoint.NewEndpoint("update-test.ext-dns-test.teapot.zalan.do", "1.2.3.4", "A"),
|
endpoint.NewEndpoint("update-test.zone-1.ext-dns-test-2.teapot.zalan.do", "1.2.3.4", "A"),
|
||||||
|
endpoint.NewEndpoint("update-test.zone-2.ext-dns-test-2.teapot.zalan.do", "4.3.2.1", "A"),
|
||||||
|
endpoint.NewEndpoint("update-test-cname.zone-1.ext-dns-test-2.teapot.zalan.do", "bar.elb.amazonaws.com", "CNAME"),
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := provider.UpdateRecords(testZone, updatedRecords, currentRecords); err != nil {
|
if err := provider.UpdateRecords(updatedRecords, currentRecords); err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
records, err := provider.Records(testZone)
|
records, err := provider.Records("_")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
validateEndpoints(t, records, []*endpoint.Endpoint{
|
validateEndpoints(t, records, []*endpoint.Endpoint{
|
||||||
endpoint.NewEndpoint("update-test.ext-dns-test.teapot.zalan.do", "1.2.3.4", "A"),
|
endpoint.NewEndpoint("update-test.zone-1.ext-dns-test-2.teapot.zalan.do", "1.2.3.4", "A"),
|
||||||
|
endpoint.NewEndpoint("update-test.zone-2.ext-dns-test-2.teapot.zalan.do", "4.3.2.1", "A"),
|
||||||
|
endpoint.NewEndpoint("update-test-cname.zone-1.ext-dns-test-2.teapot.zalan.do", "bar.elb.amazonaws.com", "CNAME"),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestAWSDeleteRecords(t *testing.T) {
|
func TestAWSDeleteRecords(t *testing.T) {
|
||||||
originalEndpoints := []*endpoint.Endpoint{
|
originalEndpoints := []*endpoint.Endpoint{
|
||||||
endpoint.NewEndpoint("delete-test.ext-dns-test.teapot.zalan.do", "8.8.8.8", "A"),
|
endpoint.NewEndpoint("delete-test.zone-1.ext-dns-test-2.teapot.zalan.do", "1.2.3.4", "A"),
|
||||||
endpoint.NewEndpoint("delete-test-cname.ext-dns-test.teapot.zalan.do", "foo.example.org", "CNAME"),
|
endpoint.NewEndpoint("delete-test.zone-2.ext-dns-test-2.teapot.zalan.do", "8.8.8.8", "A"),
|
||||||
endpoint.NewEndpoint("delete-test-cname.ext-dns-test.teapot.zalan.do", "foo.eu-central-1.elb.amazonaws.com", "ALIAS"),
|
endpoint.NewEndpoint("delete-test-cname.zone-1.ext-dns-test-2.teapot.zalan.do", "baz.elb.amazonaws.com", "CNAME"),
|
||||||
endpoint.NewEndpoint("delete-test-cname-alias.ext-dns-test.teapot.zalan.do", "foo.eu-central-1.elb.amazonaws.com", "CNAME"),
|
endpoint.NewEndpoint("delete-test-cname.zone-1.ext-dns-test-2.teapot.zalan.do", "foo.eu-central-1.elb.amazonaws.com", "ALIAS"),
|
||||||
|
endpoint.NewEndpoint("delete-test-cname-alias.zone-1.ext-dns-test-2.teapot.zalan.do", "foo.eu-central-1.elb.amazonaws.com", "CNAME"),
|
||||||
}
|
}
|
||||||
|
|
||||||
provider := newAWSProvider(t, false, originalEndpoints)
|
provider := newAWSProvider(t, "ext-dns-test-2.teapot.zalan.do.", false, originalEndpoints)
|
||||||
|
|
||||||
if err := provider.DeleteRecords(testZone, originalEndpoints); err != nil {
|
if err := provider.DeleteRecords(originalEndpoints); err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
records, err := provider.Records(testZone)
|
records, err := provider.Records("_")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
@ -225,24 +269,42 @@ func TestAWSDeleteRecords(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestAWSApplyChanges(t *testing.T) {
|
func TestAWSApplyChanges(t *testing.T) {
|
||||||
provider := newAWSProvider(t, false, []*endpoint.Endpoint{
|
provider := newAWSProvider(t, "ext-dns-test-2.teapot.zalan.do.", false, []*endpoint.Endpoint{
|
||||||
endpoint.NewEndpoint("update-test.ext-dns-test.teapot.zalan.do", "8.8.8.8", "A"),
|
endpoint.NewEndpoint("update-test.zone-1.ext-dns-test-2.teapot.zalan.do", "8.8.8.8", "A"),
|
||||||
endpoint.NewEndpoint("delete-test.ext-dns-test.teapot.zalan.do", "8.8.8.8", "A"),
|
endpoint.NewEndpoint("delete-test.zone-1.ext-dns-test-2.teapot.zalan.do", "8.8.8.8", "A"),
|
||||||
|
endpoint.NewEndpoint("update-test.zone-2.ext-dns-test-2.teapot.zalan.do", "8.8.4.4", "A"),
|
||||||
|
endpoint.NewEndpoint("delete-test.zone-2.ext-dns-test-2.teapot.zalan.do", "8.8.4.4", "A"),
|
||||||
|
endpoint.NewEndpoint("update-test-cname.zone-1.ext-dns-test-2.teapot.zalan.do", "bar.elb.amazonaws.com", "CNAME"),
|
||||||
|
endpoint.NewEndpoint("delete-test-cname.zone-1.ext-dns-test-2.teapot.zalan.do", "qux.elb.amazonaws.com", "CNAME"),
|
||||||
|
endpoint.NewEndpoint("update-test-cname-alias.zone-1.ext-dns-test-2.teapot.zalan.do", "bar.elb.amazonaws.com", "ALIAS"),
|
||||||
|
endpoint.NewEndpoint("delete-test-cname-alias.zone-1.ext-dns-test-2.teapot.zalan.do", "qux.elb.amazonaws.com", "ALIAS"),
|
||||||
})
|
})
|
||||||
|
|
||||||
createRecords := []*endpoint.Endpoint{
|
createRecords := []*endpoint.Endpoint{
|
||||||
endpoint.NewEndpoint("create-test.ext-dns-test.teapot.zalan.do", "8.8.8.8", ""),
|
endpoint.NewEndpoint("create-test.zone-1.ext-dns-test-2.teapot.zalan.do", "8.8.8.8", ""),
|
||||||
|
endpoint.NewEndpoint("create-test.zone-2.ext-dns-test-2.teapot.zalan.do", "8.8.4.4", ""),
|
||||||
|
endpoint.NewEndpoint("create-test-cname.zone-1.ext-dns-test-2.teapot.zalan.do", "foo.elb.amazonaws.com", ""),
|
||||||
|
endpoint.NewEndpoint("create-test-cname-alias.zone-1.ext-dns-test-2.teapot.zalan.do", "foo.elb.amazonaws.com", "ALIAS"),
|
||||||
}
|
}
|
||||||
|
|
||||||
currentRecords := []*endpoint.Endpoint{
|
currentRecords := []*endpoint.Endpoint{
|
||||||
endpoint.NewEndpoint("update-test.ext-dns-test.teapot.zalan.do", "8.8.8.8", ""),
|
endpoint.NewEndpoint("update-test.zone-1.ext-dns-test-2.teapot.zalan.do", "8.8.8.8", ""),
|
||||||
|
endpoint.NewEndpoint("update-test.zone-2.ext-dns-test-2.teapot.zalan.do", "8.8.4.4", ""),
|
||||||
|
endpoint.NewEndpoint("update-test-cname.zone-1.ext-dns-test-2.teapot.zalan.do", "bar.elb.amazonaws.com", ""),
|
||||||
|
endpoint.NewEndpoint("update-test-cname-alias.zone-1.ext-dns-test-2.teapot.zalan.do", "bar.elb.amazonaws.com", "ALIAS"),
|
||||||
}
|
}
|
||||||
updatedRecords := []*endpoint.Endpoint{
|
updatedRecords := []*endpoint.Endpoint{
|
||||||
endpoint.NewEndpoint("update-test.ext-dns-test.teapot.zalan.do", "1.2.3.4", ""),
|
endpoint.NewEndpoint("update-test.zone-1.ext-dns-test-2.teapot.zalan.do", "1.2.3.4", ""),
|
||||||
|
endpoint.NewEndpoint("update-test.zone-2.ext-dns-test-2.teapot.zalan.do", "4.3.2.1", ""),
|
||||||
|
endpoint.NewEndpoint("update-test-cname.zone-1.ext-dns-test-2.teapot.zalan.do", "baz.elb.amazonaws.com", ""),
|
||||||
|
endpoint.NewEndpoint("update-test-cname-alias.zone-1.ext-dns-test-2.teapot.zalan.do", "baz.elb.amazonaws.com", "ALIAS"),
|
||||||
}
|
}
|
||||||
|
|
||||||
deleteRecords := []*endpoint.Endpoint{
|
deleteRecords := []*endpoint.Endpoint{
|
||||||
endpoint.NewEndpoint("delete-test.ext-dns-test.teapot.zalan.do", "8.8.8.8", ""),
|
endpoint.NewEndpoint("delete-test.zone-1.ext-dns-test-2.teapot.zalan.do", "8.8.8.8", ""),
|
||||||
|
endpoint.NewEndpoint("delete-test.zone-2.ext-dns-test-2.teapot.zalan.do", "8.8.4.4", ""),
|
||||||
|
endpoint.NewEndpoint("delete-test-cname.zone-1.ext-dns-test-2.teapot.zalan.do", "qux.elb.amazonaws.com", ""),
|
||||||
|
endpoint.NewEndpoint("delete-test-cname-alias.zone-1.ext-dns-test-2.teapot.zalan.do", "qux.elb.amazonaws.com", "ALIAS"),
|
||||||
}
|
}
|
||||||
|
|
||||||
changes := &plan.Changes{
|
changes := &plan.Changes{
|
||||||
@ -252,89 +314,80 @@ func TestAWSApplyChanges(t *testing.T) {
|
|||||||
Delete: deleteRecords,
|
Delete: deleteRecords,
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := provider.ApplyChanges(testZone, changes); err != nil {
|
if err := provider.ApplyChanges("_", changes); err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
records, err := provider.Records(testZone)
|
records, err := provider.Records("_")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
validateEndpoints(t, records, []*endpoint.Endpoint{
|
validateEndpoints(t, records, []*endpoint.Endpoint{
|
||||||
endpoint.NewEndpoint("create-test.ext-dns-test.teapot.zalan.do", "8.8.8.8", "A"),
|
endpoint.NewEndpoint("create-test.zone-1.ext-dns-test-2.teapot.zalan.do", "8.8.8.8", "A"),
|
||||||
endpoint.NewEndpoint("update-test.ext-dns-test.teapot.zalan.do", "1.2.3.4", "A"),
|
endpoint.NewEndpoint("update-test.zone-1.ext-dns-test-2.teapot.zalan.do", "1.2.3.4", "A"),
|
||||||
|
endpoint.NewEndpoint("create-test.zone-2.ext-dns-test-2.teapot.zalan.do", "8.8.4.4", "A"),
|
||||||
|
endpoint.NewEndpoint("update-test.zone-2.ext-dns-test-2.teapot.zalan.do", "4.3.2.1", "A"),
|
||||||
|
endpoint.NewEndpoint("create-test-cname.zone-1.ext-dns-test-2.teapot.zalan.do", "foo.elb.amazonaws.com", "CNAME"),
|
||||||
|
endpoint.NewEndpoint("update-test-cname.zone-1.ext-dns-test-2.teapot.zalan.do", "baz.elb.amazonaws.com", "CNAME"),
|
||||||
|
endpoint.NewEndpoint("create-test-cname-alias.zone-1.ext-dns-test-2.teapot.zalan.do", "foo.elb.amazonaws.com", "ALIAS"),
|
||||||
|
endpoint.NewEndpoint("update-test-cname-alias.zone-1.ext-dns-test-2.teapot.zalan.do", "baz.elb.amazonaws.com", "ALIAS"),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestAWSApplyNoChanges(t *testing.T) {
|
func TestAWSApplyChangesDryRun(t *testing.T) {
|
||||||
provider := newAWSProvider(t, false, []*endpoint.Endpoint{})
|
originalEndpoints := []*endpoint.Endpoint{
|
||||||
|
endpoint.NewEndpoint("update-test.zone-1.ext-dns-test-2.teapot.zalan.do", "8.8.8.8", "A"),
|
||||||
if err := provider.ApplyChanges(testZone, &plan.Changes{}); err != nil {
|
endpoint.NewEndpoint("delete-test.zone-1.ext-dns-test-2.teapot.zalan.do", "8.8.8.8", "A"),
|
||||||
t.Error(err)
|
endpoint.NewEndpoint("update-test.zone-2.ext-dns-test-2.teapot.zalan.do", "8.8.4.4", "A"),
|
||||||
}
|
endpoint.NewEndpoint("delete-test.zone-2.ext-dns-test-2.teapot.zalan.do", "8.8.4.4", "A"),
|
||||||
}
|
endpoint.NewEndpoint("update-test-cname.zone-1.ext-dns-test-2.teapot.zalan.do", "bar.elb.amazonaws.com", "CNAME"),
|
||||||
|
endpoint.NewEndpoint("delete-test-cname.zone-1.ext-dns-test-2.teapot.zalan.do", "qux.elb.amazonaws.com", "CNAME"),
|
||||||
func TestAWSCreateRecordsDryRun(t *testing.T) {
|
endpoint.NewEndpoint("update-test-cname-alias.zone-1.ext-dns-test-2.teapot.zalan.do", "bar.elb.amazonaws.com", "ALIAS"),
|
||||||
provider := newAWSProvider(t, true, []*endpoint.Endpoint{})
|
endpoint.NewEndpoint("delete-test-cname-alias.zone-1.ext-dns-test-2.teapot.zalan.do", "qux.elb.amazonaws.com", "ALIAS"),
|
||||||
|
|
||||||
records := []*endpoint.Endpoint{
|
|
||||||
endpoint.NewEndpoint("create-test.ext-dns-test.teapot.zalan.do", "8.8.8.8", ""),
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := provider.CreateRecords(testZone, records); err != nil {
|
provider := newAWSProvider(t, "ext-dns-test-2.teapot.zalan.do.", true, originalEndpoints)
|
||||||
t.Fatal(err)
|
|
||||||
|
createRecords := []*endpoint.Endpoint{
|
||||||
|
endpoint.NewEndpoint("create-test.zone-1.ext-dns-test-2.teapot.zalan.do", "8.8.8.8", ""),
|
||||||
|
endpoint.NewEndpoint("create-test.zone-2.ext-dns-test-2.teapot.zalan.do", "8.8.4.4", ""),
|
||||||
|
endpoint.NewEndpoint("create-test-cname.zone-1.ext-dns-test-2.teapot.zalan.do", "foo.elb.amazonaws.com", ""),
|
||||||
|
endpoint.NewEndpoint("create-test-cname-alias.zone-1.ext-dns-test-2.teapot.zalan.do", "foo.elb.amazonaws.com", "ALIAS"),
|
||||||
}
|
}
|
||||||
|
|
||||||
records, err := provider.Records(testZone)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
validateEndpoints(t, records, []*endpoint.Endpoint{})
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestAWSUpdateRecordsDryRun(t *testing.T) {
|
|
||||||
provider := newAWSProvider(t, true, []*endpoint.Endpoint{
|
|
||||||
endpoint.NewEndpoint("update-test.ext-dns-test.teapot.zalan.do", "8.8.8.8", "A"),
|
|
||||||
})
|
|
||||||
|
|
||||||
currentRecords := []*endpoint.Endpoint{
|
currentRecords := []*endpoint.Endpoint{
|
||||||
endpoint.NewEndpoint("update-test.ext-dns-test.teapot.zalan.do", "8.8.8.8", ""),
|
endpoint.NewEndpoint("update-test.zone-1.ext-dns-test-2.teapot.zalan.do", "8.8.8.8", ""),
|
||||||
|
endpoint.NewEndpoint("update-test.zone-2.ext-dns-test-2.teapot.zalan.do", "8.8.4.4", ""),
|
||||||
|
endpoint.NewEndpoint("update-test-cname.zone-1.ext-dns-test-2.teapot.zalan.do", "bar.elb.amazonaws.com", ""),
|
||||||
|
endpoint.NewEndpoint("update-test-cname-alias.zone-1.ext-dns-test-2.teapot.zalan.do", "bar.elb.amazonaws.com", "ALIAS"),
|
||||||
}
|
}
|
||||||
updatedRecords := []*endpoint.Endpoint{
|
updatedRecords := []*endpoint.Endpoint{
|
||||||
endpoint.NewEndpoint("update-test.ext-dns-test.teapot.zalan.do", "1.2.3.4", ""),
|
endpoint.NewEndpoint("update-test.zone-1.ext-dns-test-2.teapot.zalan.do", "1.2.3.4", ""),
|
||||||
|
endpoint.NewEndpoint("update-test.zone-2.ext-dns-test-2.teapot.zalan.do", "4.3.2.1", ""),
|
||||||
|
endpoint.NewEndpoint("update-test-cname.zone-1.ext-dns-test-2.teapot.zalan.do", "baz.elb.amazonaws.com", ""),
|
||||||
|
endpoint.NewEndpoint("update-test-cname-alias.zone-1.ext-dns-test-2.teapot.zalan.do", "baz.elb.amazonaws.com", "ALIAS"),
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := provider.UpdateRecords(testZone, updatedRecords, currentRecords); err != nil {
|
deleteRecords := []*endpoint.Endpoint{
|
||||||
|
endpoint.NewEndpoint("delete-test.zone-1.ext-dns-test-2.teapot.zalan.do", "8.8.8.8", ""),
|
||||||
|
endpoint.NewEndpoint("delete-test.zone-2.ext-dns-test-2.teapot.zalan.do", "8.8.4.4", ""),
|
||||||
|
endpoint.NewEndpoint("delete-test-cname.zone-1.ext-dns-test-2.teapot.zalan.do", "qux.elb.amazonaws.com", ""),
|
||||||
|
endpoint.NewEndpoint("delete-test-cname-alias.zone-1.ext-dns-test-2.teapot.zalan.do", "qux.elb.amazonaws.com", "ALIAS"),
|
||||||
|
}
|
||||||
|
|
||||||
|
changes := &plan.Changes{
|
||||||
|
Create: createRecords,
|
||||||
|
UpdateNew: updatedRecords,
|
||||||
|
UpdateOld: currentRecords,
|
||||||
|
Delete: deleteRecords,
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := provider.ApplyChanges("_", changes); err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
records, err := provider.Records(testZone)
|
records, err := provider.Records("_")
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
validateEndpoints(t, records, []*endpoint.Endpoint{
|
|
||||||
endpoint.NewEndpoint("update-test.ext-dns-test.teapot.zalan.do", "8.8.8.8", "A"),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestAWSDeleteRecordsDryRun(t *testing.T) {
|
|
||||||
originalEndpoints := []*endpoint.Endpoint{
|
|
||||||
endpoint.NewEndpoint("delete-test.ext-dns-test.teapot.zalan.do", "8.8.8.8", "A"),
|
|
||||||
endpoint.NewEndpoint("delete-test-cname.ext-dns-test.teapot.zalan.do", "foo.example.org", "CNAME"),
|
|
||||||
endpoint.NewEndpoint("delete-test-cname.ext-dns-test.teapot.zalan.do", "foo.eu-central-1.elb.amazonaws.com", "ALIAS"),
|
|
||||||
endpoint.NewEndpoint("delete-test-cname-alias.ext-dns-test.teapot.zalan.do", "foo.eu-central-1.elb.amazonaws.com", "CNAME"),
|
|
||||||
}
|
|
||||||
|
|
||||||
provider := newAWSProvider(t, true, originalEndpoints)
|
|
||||||
|
|
||||||
if err := provider.DeleteRecords(testZone, originalEndpoints); err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
records, err := provider.Records(testZone)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
@ -342,176 +395,148 @@ func TestAWSDeleteRecordsDryRun(t *testing.T) {
|
|||||||
validateEndpoints(t, records, originalEndpoints)
|
validateEndpoints(t, records, originalEndpoints)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestAWSApplyChangesDryRun(t *testing.T) {
|
func TestAWSChangesByZones(t *testing.T) {
|
||||||
provider := newAWSProvider(t, true, []*endpoint.Endpoint{
|
changes := []*route53.Change{
|
||||||
endpoint.NewEndpoint("update-test.ext-dns-test.teapot.zalan.do", "8.8.8.8", "A"),
|
{
|
||||||
endpoint.NewEndpoint("delete-test.ext-dns-test.teapot.zalan.do", "8.8.8.8", "A"),
|
Action: aws.String(route53.ChangeActionCreate),
|
||||||
|
ResourceRecordSet: &route53.ResourceRecordSet{
|
||||||
|
Name: aws.String("qux.foo.example.org"), TTL: aws.Int64(1),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Action: aws.String(route53.ChangeActionCreate),
|
||||||
|
ResourceRecordSet: &route53.ResourceRecordSet{
|
||||||
|
Name: aws.String("qux.bar.example.org"), TTL: aws.Int64(2),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Action: aws.String(route53.ChangeActionDelete),
|
||||||
|
ResourceRecordSet: &route53.ResourceRecordSet{
|
||||||
|
Name: aws.String("wambo.foo.example.org"), TTL: aws.Int64(10),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Action: aws.String(route53.ChangeActionDelete),
|
||||||
|
ResourceRecordSet: &route53.ResourceRecordSet{
|
||||||
|
Name: aws.String("wambo.bar.example.org"), TTL: aws.Int64(20),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
zones := map[string]*route53.HostedZone{
|
||||||
|
"foo-example-org": {
|
||||||
|
Id: aws.String("foo-example-org"),
|
||||||
|
Name: aws.String("foo.example.org."),
|
||||||
|
},
|
||||||
|
"bar-example-org": {
|
||||||
|
Id: aws.String("bar-example-org"),
|
||||||
|
Name: aws.String("bar.example.org."),
|
||||||
|
},
|
||||||
|
"baz-example-org": {
|
||||||
|
Id: aws.String("baz-example-org"),
|
||||||
|
Name: aws.String("baz.example.org."),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
changesByZone := changesByZone(zones, changes)
|
||||||
|
|
||||||
|
if len(changesByZone) != 2 {
|
||||||
|
t.Fatalf("expected %d change(s), got %d", 2, len(changesByZone))
|
||||||
|
}
|
||||||
|
|
||||||
|
validateAWSChangeRecords(t, changesByZone["foo-example-org"], []*route53.Change{
|
||||||
|
{
|
||||||
|
Action: aws.String(route53.ChangeActionCreate),
|
||||||
|
ResourceRecordSet: &route53.ResourceRecordSet{
|
||||||
|
Name: aws.String("qux.foo.example.org"), TTL: aws.Int64(1),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Action: aws.String(route53.ChangeActionDelete),
|
||||||
|
ResourceRecordSet: &route53.ResourceRecordSet{
|
||||||
|
Name: aws.String("wambo.foo.example.org"), TTL: aws.Int64(10),
|
||||||
|
},
|
||||||
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
createRecords := []*endpoint.Endpoint{
|
validateAWSChangeRecords(t, changesByZone["bar-example-org"], []*route53.Change{
|
||||||
endpoint.NewEndpoint("create-test.ext-dns-test.teapot.zalan.do", "8.8.8.8", ""),
|
{
|
||||||
}
|
Action: aws.String(route53.ChangeActionCreate),
|
||||||
|
ResourceRecordSet: &route53.ResourceRecordSet{
|
||||||
currentRecords := []*endpoint.Endpoint{
|
Name: aws.String("qux.bar.example.org"), TTL: aws.Int64(2),
|
||||||
endpoint.NewEndpoint("update-test.ext-dns-test.teapot.zalan.do", "8.8.8.8", ""),
|
},
|
||||||
}
|
},
|
||||||
updatedRecords := []*endpoint.Endpoint{
|
{
|
||||||
endpoint.NewEndpoint("update-test.ext-dns-test.teapot.zalan.do", "1.2.3.4", ""),
|
Action: aws.String(route53.ChangeActionDelete),
|
||||||
}
|
ResourceRecordSet: &route53.ResourceRecordSet{
|
||||||
|
Name: aws.String("wambo.bar.example.org"), TTL: aws.Int64(20),
|
||||||
deleteRecords := []*endpoint.Endpoint{
|
},
|
||||||
endpoint.NewEndpoint("delete-test.ext-dns-test.teapot.zalan.do", "8.8.8.8", ""),
|
},
|
||||||
}
|
|
||||||
|
|
||||||
changes := &plan.Changes{
|
|
||||||
Create: createRecords,
|
|
||||||
UpdateNew: updatedRecords,
|
|
||||||
UpdateOld: currentRecords,
|
|
||||||
Delete: deleteRecords,
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := provider.ApplyChanges(testZone, changes); err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
records, err := provider.Records(testZone)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
validateEndpoints(t, records, []*endpoint.Endpoint{
|
|
||||||
endpoint.NewEndpoint("update-test.ext-dns-test.teapot.zalan.do", "8.8.8.8", "A"),
|
|
||||||
endpoint.NewEndpoint("delete-test.ext-dns-test.teapot.zalan.do", "8.8.8.8", "A"),
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestAWSCreateRecordsCNAME(t *testing.T) {
|
func validateEndpoints(t *testing.T, endpoints []*endpoint.Endpoint, expected []*endpoint.Endpoint) {
|
||||||
provider := newAWSProvider(t, false, []*endpoint.Endpoint{})
|
if !testutils.SameEndpoints(endpoints, expected) {
|
||||||
|
t.Errorf("expected and actual endpoints don't match")
|
||||||
records := []*endpoint.Endpoint{
|
|
||||||
endpoint.NewEndpoint("create-test.ext-dns-test.teapot.zalan.do", "foo.example.org", ""),
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := provider.CreateRecords(testZone, records); err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
records, err := provider.Records(testZone)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
validateEndpoints(t, records, []*endpoint.Endpoint{
|
|
||||||
endpoint.NewEndpoint("create-test.ext-dns-test.teapot.zalan.do", "foo.example.org", "CNAME"),
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestAWSUpdateRecordsCNAME(t *testing.T) {
|
func validateAWSZones(t *testing.T, zones map[string]*route53.HostedZone, expected map[string]*route53.HostedZone) {
|
||||||
provider := newAWSProvider(t, false, []*endpoint.Endpoint{
|
if len(zones) != len(expected) {
|
||||||
endpoint.NewEndpoint("update-test.ext-dns-test.teapot.zalan.do", "foo.example.org", "CNAME"),
|
t.Fatalf("expected %d zone(s), got %d", len(expected), len(zones))
|
||||||
})
|
|
||||||
|
|
||||||
currentRecords := []*endpoint.Endpoint{
|
|
||||||
endpoint.NewEndpoint("update-test.ext-dns-test.teapot.zalan.do", "foo.example.org", ""),
|
|
||||||
}
|
|
||||||
updatedRecords := []*endpoint.Endpoint{
|
|
||||||
endpoint.NewEndpoint("update-test.ext-dns-test.teapot.zalan.do", "bar.example.org", ""),
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := provider.UpdateRecords(testZone, updatedRecords, currentRecords); err != nil {
|
for i, zone := range zones {
|
||||||
t.Fatal(err)
|
validateAWSZone(t, zone, expected[i])
|
||||||
}
|
}
|
||||||
|
|
||||||
records, err := provider.Records(testZone)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
validateEndpoints(t, records, []*endpoint.Endpoint{
|
|
||||||
endpoint.NewEndpoint("update-test.ext-dns-test.teapot.zalan.do", "bar.example.org", "CNAME"),
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestAWSDeleteRecordsCNAME(t *testing.T) {
|
func validateAWSZone(t *testing.T, zone *route53.HostedZone, expected *route53.HostedZone) {
|
||||||
provider := newAWSProvider(t, false, []*endpoint.Endpoint{
|
if aws.StringValue(zone.Id) != aws.StringValue(expected.Id) {
|
||||||
endpoint.NewEndpoint("delete-test.ext-dns-test.teapot.zalan.do", "baz.example.org", "CNAME"),
|
t.Errorf("expected %s, got %s", aws.StringValue(expected.Id), aws.StringValue(zone.Id))
|
||||||
})
|
|
||||||
|
|
||||||
currentRecords := []*endpoint.Endpoint{
|
|
||||||
endpoint.NewEndpoint("delete-test.ext-dns-test.teapot.zalan.do", "baz.example.org", ""),
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := provider.DeleteRecords(testZone, currentRecords); err != nil {
|
if aws.StringValue(zone.Name) != aws.StringValue(expected.Name) {
|
||||||
t.Fatal(err)
|
t.Errorf("expected %s, got %s", aws.StringValue(expected.Name), aws.StringValue(zone.Name))
|
||||||
}
|
}
|
||||||
|
|
||||||
records, err := provider.Records(testZone)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
validateEndpoints(t, records, []*endpoint.Endpoint{})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestAWSApplyChangesCNAME(t *testing.T) {
|
func validateAWSChangeRecords(t *testing.T, records []*route53.Change, expected []*route53.Change) {
|
||||||
provider := newAWSProvider(t, false, []*endpoint.Endpoint{
|
if len(records) != len(expected) {
|
||||||
endpoint.NewEndpoint("update-test.ext-dns-test.teapot.zalan.do", "foo.example.org", "CNAME"),
|
t.Fatalf("expected %d change(s), got %d", len(expected), len(records))
|
||||||
endpoint.NewEndpoint("delete-test.ext-dns-test.teapot.zalan.do", "qux.example.org", "CNAME"),
|
|
||||||
})
|
|
||||||
|
|
||||||
createRecords := []*endpoint.Endpoint{
|
|
||||||
endpoint.NewEndpoint("create-test.ext-dns-test.teapot.zalan.do", "foo.example.org", ""),
|
|
||||||
}
|
}
|
||||||
|
|
||||||
currentRecords := []*endpoint.Endpoint{
|
for i := range records {
|
||||||
endpoint.NewEndpoint("update-test.ext-dns-test.teapot.zalan.do", "bar.example.org", ""),
|
validateAWSChangeRecord(t, records[i], expected[i])
|
||||||
}
|
}
|
||||||
updatedRecords := []*endpoint.Endpoint{
|
}
|
||||||
endpoint.NewEndpoint("update-test.ext-dns-test.teapot.zalan.do", "baz.example.org", ""),
|
|
||||||
|
func validateAWSChangeRecord(t *testing.T, record *route53.Change, expected *route53.Change) {
|
||||||
|
if aws.StringValue(record.Action) != aws.StringValue(expected.Action) {
|
||||||
|
t.Errorf("expected %s, got %s", aws.StringValue(expected.Action), aws.StringValue(record.Action))
|
||||||
}
|
}
|
||||||
|
|
||||||
deleteRecords := []*endpoint.Endpoint{
|
if aws.StringValue(record.ResourceRecordSet.Name) != aws.StringValue(expected.ResourceRecordSet.Name) {
|
||||||
endpoint.NewEndpoint("delete-test.ext-dns-test.teapot.zalan.do", "qux.example.org", ""),
|
t.Errorf("expected %s, got %s", aws.StringValue(expected.ResourceRecordSet.Name), aws.StringValue(record.ResourceRecordSet.Name))
|
||||||
}
|
}
|
||||||
|
|
||||||
changes := &plan.Changes{
|
|
||||||
Create: createRecords,
|
|
||||||
UpdateNew: updatedRecords,
|
|
||||||
UpdateOld: currentRecords,
|
|
||||||
Delete: deleteRecords,
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := provider.ApplyChanges(testZone, changes); err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
records, err := provider.Records(testZone)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
validateEndpoints(t, records, []*endpoint.Endpoint{
|
|
||||||
endpoint.NewEndpoint("create-test.ext-dns-test.teapot.zalan.do", "foo.example.org", "CNAME"),
|
|
||||||
endpoint.NewEndpoint("update-test.ext-dns-test.teapot.zalan.do", "baz.example.org", "CNAME"),
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestAWSCreateRecordsWithCNAME(t *testing.T) {
|
func TestAWSCreateRecordsWithCNAME(t *testing.T) {
|
||||||
provider := newAWSProvider(t, false, []*endpoint.Endpoint{})
|
provider := newAWSProvider(t, "ext-dns-test-2.teapot.zalan.do.", false, []*endpoint.Endpoint{})
|
||||||
|
|
||||||
records := []*endpoint.Endpoint{
|
records := []*endpoint.Endpoint{
|
||||||
{DNSName: "create-test.ext-dns-test.teapot.zalan.do", Target: "foo.example.org"},
|
{DNSName: "create-test.zone-1.ext-dns-test-2.teapot.zalan.do", Target: "foo.example.org"},
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := provider.CreateRecords(testZone, records); err != nil {
|
if err := provider.CreateRecords(records); err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
recordSets := listRecords(t, provider.Client)
|
recordSets := listAWSRecords(t, provider.Client, "/hostedzone/zone-1.ext-dns-test-2.teapot.zalan.do.")
|
||||||
|
|
||||||
validateRecords(t, recordSets, []*route53.ResourceRecordSet{
|
validateRecords(t, recordSets, []*route53.ResourceRecordSet{
|
||||||
{
|
{
|
||||||
Name: aws.String("create-test.ext-dns-test.teapot.zalan.do."),
|
Name: aws.String("create-test.zone-1.ext-dns-test-2.teapot.zalan.do."),
|
||||||
Type: aws.String("CNAME"),
|
Type: aws.String("CNAME"),
|
||||||
TTL: aws.Int64(300),
|
TTL: aws.Int64(300),
|
||||||
ResourceRecords: []*route53.ResourceRecord{
|
ResourceRecords: []*route53.ResourceRecord{
|
||||||
@ -524,17 +549,17 @@ func TestAWSCreateRecordsWithCNAME(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestAWSCreateRecordsWithALIAS(t *testing.T) {
|
func TestAWSCreateRecordsWithALIAS(t *testing.T) {
|
||||||
provider := newAWSProvider(t, false, []*endpoint.Endpoint{})
|
provider := newAWSProvider(t, "ext-dns-test-2.teapot.zalan.do.", false, []*endpoint.Endpoint{})
|
||||||
|
|
||||||
records := []*endpoint.Endpoint{
|
records := []*endpoint.Endpoint{
|
||||||
{DNSName: "create-test.ext-dns-test.teapot.zalan.do", Target: "foo.eu-central-1.elb.amazonaws.com"},
|
{DNSName: "create-test.zone-1.ext-dns-test-2.teapot.zalan.do", Target: "foo.eu-central-1.elb.amazonaws.com"},
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := provider.CreateRecords(testZone, records); err != nil {
|
if err := provider.CreateRecords(records); err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
recordSets := listRecords(t, provider.Client)
|
recordSets := listAWSRecords(t, provider.Client, "/hostedzone/zone-1.ext-dns-test-2.teapot.zalan.do.")
|
||||||
|
|
||||||
validateRecords(t, recordSets, []*route53.ResourceRecordSet{
|
validateRecords(t, recordSets, []*route53.ResourceRecordSet{
|
||||||
{
|
{
|
||||||
@ -543,7 +568,7 @@ func TestAWSCreateRecordsWithALIAS(t *testing.T) {
|
|||||||
EvaluateTargetHealth: aws.Bool(true),
|
EvaluateTargetHealth: aws.Bool(true),
|
||||||
HostedZoneId: aws.String("Z215JYRZR1TBD5"),
|
HostedZoneId: aws.String("Z215JYRZR1TBD5"),
|
||||||
},
|
},
|
||||||
Name: aws.String("create-test.ext-dns-test.teapot.zalan.do."),
|
Name: aws.String("create-test.zone-1.ext-dns-test-2.teapot.zalan.do."),
|
||||||
Type: aws.String("A"),
|
Type: aws.String("A"),
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
@ -604,72 +629,69 @@ func TestAWSCanonicalHostedZone(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestAWSSanitizeZone(t *testing.T) {
|
func TestAWSSuitableZone(t *testing.T) {
|
||||||
provider := newAWSProvider(t, false, []*endpoint.Endpoint{
|
zones := map[string]*route53.HostedZone{
|
||||||
endpoint.NewEndpoint("list-test.ext-dns-test.teapot.zalan.do", "8.8.8.8", "A"),
|
"example-org": {Id: aws.String("example-org"), Name: aws.String("example.org.")},
|
||||||
})
|
"bar-example-org": {Id: aws.String("bar-example-org"), Name: aws.String("bar.example.org.")},
|
||||||
|
|
||||||
records, err := provider.Records(testZone)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
validateEndpoints(t, records, []*endpoint.Endpoint{
|
for _, tc := range []struct {
|
||||||
endpoint.NewEndpoint("list-test.ext-dns-test.teapot.zalan.do", "8.8.8.8", "A"),
|
hostname string
|
||||||
})
|
expected *route53.HostedZone
|
||||||
|
}{
|
||||||
|
{"foo.bar.example.org.", zones["bar-example-org"]},
|
||||||
|
{"foo.example.org.", zones["example-org"]},
|
||||||
|
{"foo.kubernetes.io.", nil},
|
||||||
|
} {
|
||||||
|
suitableZone := suitableZone(tc.hostname, zones)
|
||||||
|
|
||||||
records, err = provider.Records("/hostedzone/" + testZone)
|
if suitableZone != tc.expected {
|
||||||
if err != nil {
|
t.Errorf("expected %s, got %s", tc.expected, suitableZone)
|
||||||
t.Fatal(err)
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
validateEndpoints(t, records, []*endpoint.Endpoint{
|
|
||||||
endpoint.NewEndpoint("list-test.ext-dns-test.teapot.zalan.do", "8.8.8.8", "A"),
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func newAWSProvider(t *testing.T, dryRun bool, records []*endpoint.Endpoint) *AWSProvider {
|
func createAWSZone(t *testing.T, provider *AWSProvider, zone *route53.HostedZone) {
|
||||||
client := NewRoute53APIStub()
|
params := &route53.CreateHostedZoneInput{
|
||||||
|
|
||||||
if _, err := client.CreateHostedZone(&route53.CreateHostedZoneInput{
|
|
||||||
CallerReference: aws.String("external-dns.alpha.kubernetes.io/test-zone"),
|
CallerReference: aws.String("external-dns.alpha.kubernetes.io/test-zone"),
|
||||||
Name: aws.String("ext-dns-test.teapot.zalan.do."),
|
Name: zone.Name,
|
||||||
}); err != nil {
|
}
|
||||||
|
|
||||||
|
if _, err := provider.Client.CreateHostedZone(params); err != nil {
|
||||||
if err, ok := err.(awserr.Error); !ok || err.Code() != route53.ErrCodeHostedZoneAlreadyExists {
|
if err, ok := err.(awserr.Error); !ok || err.Code() != route53.ErrCodeHostedZoneAlreadyExists {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
provider := &AWSProvider{
|
|
||||||
Client: client,
|
|
||||||
DryRun: false,
|
|
||||||
}
|
|
||||||
|
|
||||||
setupRecords(t, provider, records)
|
|
||||||
|
|
||||||
provider.DryRun = dryRun
|
|
||||||
|
|
||||||
return provider
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func setupRecords(t *testing.T, provider *AWSProvider, endpoints []*endpoint.Endpoint) {
|
func setupAWSRecords(t *testing.T, provider *AWSProvider, endpoints []*endpoint.Endpoint) {
|
||||||
clearRecords(t, provider)
|
clearAWSRecords(t, provider, "/hostedzone/zone-1.ext-dns-test-2.teapot.zalan.do.")
|
||||||
|
clearAWSRecords(t, provider, "/hostedzone/zone-2.ext-dns-test-2.teapot.zalan.do.")
|
||||||
|
clearAWSRecords(t, provider, "/hostedzone/zone-3.ext-dns-test-2.teapot.zalan.do.")
|
||||||
|
|
||||||
if err := provider.CreateRecords(testZone, endpoints); err != nil {
|
records, err := provider.Records("_")
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
records, err := provider.Records(testZone)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
validateEndpoints(t, records, []*endpoint.Endpoint{})
|
||||||
|
|
||||||
|
if err = provider.CreateRecords(endpoints); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
records, err = provider.Records("_")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
validateEndpoints(t, records, endpoints)
|
validateEndpoints(t, records, endpoints)
|
||||||
}
|
}
|
||||||
|
|
||||||
func listRecords(t *testing.T, client Route53API) []*route53.ResourceRecordSet {
|
func listAWSRecords(t *testing.T, client Route53API, zone string) []*route53.ResourceRecordSet {
|
||||||
recordSets := []*route53.ResourceRecordSet{}
|
recordSets := []*route53.ResourceRecordSet{}
|
||||||
if err := client.ListResourceRecordSetsPages(&route53.ListResourceRecordSetsInput{
|
if err := client.ListResourceRecordSetsPages(&route53.ListResourceRecordSetsInput{
|
||||||
HostedZoneId: aws.String(expandedHostedZoneID(testZone)),
|
HostedZoneId: aws.String(zone),
|
||||||
}, func(resp *route53.ListResourceRecordSetsOutput, _ bool) bool {
|
}, func(resp *route53.ListResourceRecordSetsOutput, _ bool) bool {
|
||||||
for _, recordSet := range resp.ResourceRecordSets {
|
for _, recordSet := range resp.ResourceRecordSets {
|
||||||
switch aws.StringValue(recordSet.Type) {
|
switch aws.StringValue(recordSet.Type) {
|
||||||
@ -684,8 +706,8 @@ func listRecords(t *testing.T, client Route53API) []*route53.ResourceRecordSet {
|
|||||||
return recordSets
|
return recordSets
|
||||||
}
|
}
|
||||||
|
|
||||||
func clearRecords(t *testing.T, provider *AWSProvider) {
|
func clearAWSRecords(t *testing.T, provider *AWSProvider, zone string) {
|
||||||
recordSets := listRecords(t, provider.Client)
|
recordSets := listAWSRecords(t, provider.Client, zone)
|
||||||
|
|
||||||
changes := make([]*route53.Change, 0, len(recordSets))
|
changes := make([]*route53.Change, 0, len(recordSets))
|
||||||
for _, recordSet := range recordSets {
|
for _, recordSet := range recordSets {
|
||||||
@ -697,7 +719,7 @@ func clearRecords(t *testing.T, provider *AWSProvider) {
|
|||||||
|
|
||||||
if len(changes) != 0 {
|
if len(changes) != 0 {
|
||||||
if _, err := provider.Client.ChangeResourceRecordSets(&route53.ChangeResourceRecordSetsInput{
|
if _, err := provider.Client.ChangeResourceRecordSets(&route53.ChangeResourceRecordSetsInput{
|
||||||
HostedZoneId: aws.String(testZone),
|
HostedZoneId: aws.String(zone),
|
||||||
ChangeBatch: &route53.ChangeBatch{
|
ChangeBatch: &route53.ChangeBatch{
|
||||||
Changes: changes,
|
Changes: changes,
|
||||||
},
|
},
|
||||||
@ -705,24 +727,42 @@ func clearRecords(t *testing.T, provider *AWSProvider) {
|
|||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
records, err := provider.Records(testZone)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
validateEndpoints(t, records, []*endpoint.Endpoint{})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func validateEndpoints(t *testing.T, endpoints []*endpoint.Endpoint, expected []*endpoint.Endpoint) {
|
func newAWSProvider(t *testing.T, domain string, dryRun bool, records []*endpoint.Endpoint) *AWSProvider {
|
||||||
if !testutils.SameEndpoints(endpoints, expected) {
|
client := NewRoute53APIStub()
|
||||||
t.Errorf("expected %v, got %v", expected, endpoints)
|
|
||||||
|
provider := &AWSProvider{
|
||||||
|
Client: client,
|
||||||
|
Domain: domain,
|
||||||
|
DryRun: false,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
createAWSZone(t, provider, &route53.HostedZone{
|
||||||
|
Id: aws.String("/hostedzone/zone-1.ext-dns-test-2.teapot.zalan.do."),
|
||||||
|
Name: aws.String("zone-1.ext-dns-test-2.teapot.zalan.do."),
|
||||||
|
})
|
||||||
|
|
||||||
|
createAWSZone(t, provider, &route53.HostedZone{
|
||||||
|
Id: aws.String("/hostedzone/zone-2.ext-dns-test-2.teapot.zalan.do."),
|
||||||
|
Name: aws.String("zone-2.ext-dns-test-2.teapot.zalan.do."),
|
||||||
|
})
|
||||||
|
|
||||||
|
createAWSZone(t, provider, &route53.HostedZone{
|
||||||
|
Id: aws.String("/hostedzone/zone-3.ext-dns-test-2.teapot.zalan.do."),
|
||||||
|
Name: aws.String("zone-3.ext-dns-test-2.teapot.zalan.do."),
|
||||||
|
})
|
||||||
|
|
||||||
|
setupAWSRecords(t, provider, records)
|
||||||
|
|
||||||
|
provider.DryRun = dryRun
|
||||||
|
|
||||||
|
return provider
|
||||||
}
|
}
|
||||||
|
|
||||||
func validateRecords(t *testing.T, records []*route53.ResourceRecordSet, expected []*route53.ResourceRecordSet) {
|
func validateRecords(t *testing.T, records []*route53.ResourceRecordSet, expected []*route53.ResourceRecordSet) {
|
||||||
if len(records) != len(expected) {
|
if len(records) != len(expected) {
|
||||||
t.Errorf("expected %d records, got %d", len(records), len(expected))
|
t.Errorf("expected %d records, got %d", len(expected), len(records))
|
||||||
}
|
}
|
||||||
|
|
||||||
for i := range records {
|
for i := range records {
|
||||||
@ -731,7 +771,3 @@ func validateRecords(t *testing.T, records []*route53.ResourceRecordSet, expecte
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func ensureTrailingDot(hostname string) string {
|
|
||||||
return strings.TrimSuffix(hostname, ".") + "."
|
|
||||||
}
|
|
||||||
|
@ -35,8 +35,8 @@ func suitableType(ep *endpoint.Endpoint) string {
|
|||||||
if ep.RecordType != "" {
|
if ep.RecordType != "" {
|
||||||
return ep.RecordType
|
return ep.RecordType
|
||||||
}
|
}
|
||||||
if net.ParseIP(ep.Target) == nil {
|
if net.ParseIP(ep.Target) != nil {
|
||||||
return "CNAME"
|
return "A"
|
||||||
}
|
}
|
||||||
return "A"
|
return "CNAME"
|
||||||
}
|
}
|
||||||
|
45
provider/provider_test.go
Normal file
45
provider/provider_test.go
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
/*
|
||||||
|
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 provider
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/kubernetes-incubator/external-dns/endpoint"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestSuitableType(t *testing.T) {
|
||||||
|
for _, tc := range []struct {
|
||||||
|
target, recordType, expected string
|
||||||
|
}{
|
||||||
|
{"8.8.8.8", "", "A"},
|
||||||
|
{"foo.example.org", "", "CNAME"},
|
||||||
|
{"foo.example.org", "ALIAS", "ALIAS"},
|
||||||
|
{"bar.eu-central-1.elb.amazonaws.com", "CNAME", "CNAME"},
|
||||||
|
} {
|
||||||
|
ep := &endpoint.Endpoint{
|
||||||
|
Target: tc.target,
|
||||||
|
RecordType: tc.recordType,
|
||||||
|
}
|
||||||
|
|
||||||
|
recordType := suitableType(ep)
|
||||||
|
|
||||||
|
if recordType != tc.expected {
|
||||||
|
t.Errorf("expected %s, got %s", tc.expected, recordType)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user