mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-08-01 07:47:56 +00:00
AWS Route53 dnsprovider
This commit is contained in:
parent
9dc06e85fb
commit
7c14d767c5
@ -0,0 +1,39 @@
|
|||||||
|
/*
|
||||||
|
Copyright 2016 The Kubernetes Authors All rights reserved.
|
||||||
|
|
||||||
|
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 route53
|
||||||
|
|
||||||
|
import (
|
||||||
|
"k8s.io/kubernetes/federation/pkg/dnsprovider"
|
||||||
|
"k8s.io/kubernetes/federation/pkg/dnsprovider/providers/aws/route53/testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Compile time check for interface adeherence
|
||||||
|
var _ dnsprovider.Interface = Interface{}
|
||||||
|
|
||||||
|
type Interface struct {
|
||||||
|
service testing.Route53API
|
||||||
|
}
|
||||||
|
|
||||||
|
// newInterfaceWithStub facilitates stubbing out the underlying AWS Route53
|
||||||
|
// library for testing purposes. It returns an provider-independent interface.
|
||||||
|
func newInterfaceWithStub(service testing.Route53API) *Interface {
|
||||||
|
return &Interface{service}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (i Interface) Zones() (zones dnsprovider.Zones, supported bool) {
|
||||||
|
return Zones{&i}, true
|
||||||
|
}
|
44
federation/pkg/dnsprovider/providers/aws/route53/route53.go
Normal file
44
federation/pkg/dnsprovider/providers/aws/route53/route53.go
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
/*
|
||||||
|
Copyright 2016 The Kubernetes Authors All rights reserved.
|
||||||
|
|
||||||
|
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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
// route53 is the implementation of pkg/dnsprovider interface for AWS Route53
|
||||||
|
package route53
|
||||||
|
|
||||||
|
import (
|
||||||
|
"io"
|
||||||
|
|
||||||
|
"k8s.io/kubernetes/federation/pkg/dnsprovider"
|
||||||
|
|
||||||
|
"github.com/aws/aws-sdk-go/aws/session"
|
||||||
|
"github.com/aws/aws-sdk-go/service/route53"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
ProviderName = "aws-route53"
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
dnsprovider.RegisterDnsProvider(ProviderName, func(config io.Reader) (dnsprovider.Interface, error) {
|
||||||
|
return newRoute53(config)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// newRoute53 creates a new instance of an AWS Route53 DNS Interface.
|
||||||
|
func newRoute53(config io.Reader) (*Interface, error) {
|
||||||
|
// Connect to AWS Route53 - TODO: Do more sophisticated auth
|
||||||
|
svc := route53.New(session.New())
|
||||||
|
return newInterfaceWithStub(svc), nil
|
||||||
|
}
|
236
federation/pkg/dnsprovider/providers/aws/route53/route53_test.go
Normal file
236
federation/pkg/dnsprovider/providers/aws/route53/route53_test.go
Normal file
@ -0,0 +1,236 @@
|
|||||||
|
/*
|
||||||
|
Copyright 2016 The Kubernetes Authors All rights reserved.
|
||||||
|
|
||||||
|
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 route53
|
||||||
|
|
||||||
|
import (
|
||||||
|
"flag"
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"k8s.io/kubernetes/federation/pkg/dnsprovider"
|
||||||
|
route53testing "k8s.io/kubernetes/federation/pkg/dnsprovider/providers/aws/route53/testing"
|
||||||
|
"k8s.io/kubernetes/federation/pkg/dnsprovider/rrstype"
|
||||||
|
|
||||||
|
"github.com/aws/aws-sdk-go/aws"
|
||||||
|
"github.com/aws/aws-sdk-go/service/route53"
|
||||||
|
)
|
||||||
|
|
||||||
|
func newTestInterface() (dnsprovider.Interface, error) {
|
||||||
|
// Use this to test the real cloud service.
|
||||||
|
// i, err := dnsprovider.GetDnsProvider(ProviderName, strings.NewReader("\n[global]\nproject-id = federation0-cluster00"))
|
||||||
|
return newFakeInterface() // Use this to stub out the entire cloud service
|
||||||
|
}
|
||||||
|
|
||||||
|
func newFakeInterface() (dnsprovider.Interface, error) {
|
||||||
|
var service route53testing.Route53API
|
||||||
|
service = route53testing.NewRoute53APIStub()
|
||||||
|
iface := newInterfaceWithStub(service)
|
||||||
|
// Add a fake zone to test against.
|
||||||
|
params := &route53.CreateHostedZoneInput{
|
||||||
|
CallerReference: aws.String("Nonce"), // Required
|
||||||
|
Name: aws.String("example.com"), // Required
|
||||||
|
}
|
||||||
|
_, err := iface.service.CreateHostedZone(params)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return iface, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
var interface_ dnsprovider.Interface
|
||||||
|
|
||||||
|
func TestMain(m *testing.M) {
|
||||||
|
fmt.Printf("Parsing flags.\n")
|
||||||
|
flag.Parse()
|
||||||
|
var err error
|
||||||
|
fmt.Printf("Getting new test interface.\n")
|
||||||
|
interface_, err = newTestInterface()
|
||||||
|
if err != nil {
|
||||||
|
fmt.Printf("Error creating interface: %v", err)
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
fmt.Printf("Running tests...\n")
|
||||||
|
os.Exit(m.Run())
|
||||||
|
}
|
||||||
|
|
||||||
|
// firstZone returns the first zone for the configured dns provider account/project,
|
||||||
|
// or fails if it can't be found
|
||||||
|
func firstZone(t *testing.T) dnsprovider.Zone {
|
||||||
|
t.Logf("Getting zones")
|
||||||
|
z, supported := interface_.Zones()
|
||||||
|
if supported {
|
||||||
|
t.Logf("Got zones %v\n", z)
|
||||||
|
} else {
|
||||||
|
t.Fatalf("Zones interface not supported by interface %v", interface_)
|
||||||
|
}
|
||||||
|
zones, err := z.List()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Failed to list zones: %v", err)
|
||||||
|
} else {
|
||||||
|
t.Logf("Got zone list: %v\n", zones)
|
||||||
|
}
|
||||||
|
if len(zones) < 1 {
|
||||||
|
t.Fatalf("Zone listing returned %d, expected >= %d", len(zones), 1)
|
||||||
|
} else {
|
||||||
|
t.Logf("Got at least 1 zone in list:%v\n", zones[0])
|
||||||
|
}
|
||||||
|
return zones[0]
|
||||||
|
}
|
||||||
|
|
||||||
|
/* rrs returns the ResourceRecordSets interface for a given zone */
|
||||||
|
func rrs(t *testing.T, zone dnsprovider.Zone) (r dnsprovider.ResourceRecordSets) {
|
||||||
|
rrsets, supported := zone.ResourceRecordSets()
|
||||||
|
if !supported {
|
||||||
|
t.Fatalf("ResourceRecordSets interface not supported by zone %v", zone)
|
||||||
|
return r
|
||||||
|
}
|
||||||
|
return rrsets
|
||||||
|
}
|
||||||
|
|
||||||
|
func listRrsOrFail(t *testing.T, rrsets dnsprovider.ResourceRecordSets) []dnsprovider.ResourceRecordSet {
|
||||||
|
rrset, err := rrsets.List()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Failed to list recordsets: %v", err)
|
||||||
|
} else {
|
||||||
|
if len(rrset) < 0 {
|
||||||
|
t.Fatalf("Record set length=%d, expected >=0", len(rrset))
|
||||||
|
} else {
|
||||||
|
t.Logf("Got %d recordsets: %v", len(rrset), rrset)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return rrset
|
||||||
|
}
|
||||||
|
|
||||||
|
func getExampleRrs(zone dnsprovider.Zone) dnsprovider.ResourceRecordSet {
|
||||||
|
rrsets, _ := zone.ResourceRecordSets()
|
||||||
|
return rrsets.New("www11."+zone.Name(), []string{"10.10.10.10", "169.20.20.20"}, 180, rrstype.A)
|
||||||
|
}
|
||||||
|
|
||||||
|
func getInvalidRrs(zone dnsprovider.Zone) dnsprovider.ResourceRecordSet {
|
||||||
|
rrsets, _ := zone.ResourceRecordSets()
|
||||||
|
return rrsets.New("www12."+zone.Name(), []string{"rubbish", "rubbish"}, 180, rrstype.A)
|
||||||
|
}
|
||||||
|
|
||||||
|
func addRrsetOrFail(t *testing.T, rrsets dnsprovider.ResourceRecordSets, rrset dnsprovider.ResourceRecordSet) dnsprovider.ResourceRecordSet {
|
||||||
|
result, err := rrsets.Add(rrset)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Failed to add recordsets: %v", err)
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
/* TestResourceRecordSetsList verifies that listing of zones succeeds */
|
||||||
|
func TestZonesList(t *testing.T) {
|
||||||
|
firstZone(t)
|
||||||
|
}
|
||||||
|
|
||||||
|
/* TestResourceRecordSetsList verifies that listing of RRS's succeeds */
|
||||||
|
func TestResourceRecordSetsList(t *testing.T) {
|
||||||
|
listRrsOrFail(t, rrs(t, firstZone(t)))
|
||||||
|
}
|
||||||
|
|
||||||
|
/* TestResourceRecordSetsAddSuccess verifies that addition of a valid RRS succeeds */
|
||||||
|
func TestResourceRecordSetsAddSuccess(t *testing.T) {
|
||||||
|
zone := firstZone(t)
|
||||||
|
sets := rrs(t, zone)
|
||||||
|
set := addRrsetOrFail(t, sets, getExampleRrs(zone))
|
||||||
|
defer sets.Remove(set)
|
||||||
|
t.Logf("Successfully added resource record set: %v", set)
|
||||||
|
}
|
||||||
|
|
||||||
|
/* TestResourceRecordSetsAdditionVisible verifies that added RRS is visible after addition */
|
||||||
|
func TestResourceRecordSetsAdditionVisible(t *testing.T) {
|
||||||
|
zone := firstZone(t)
|
||||||
|
sets := rrs(t, zone)
|
||||||
|
rrset := getExampleRrs(zone)
|
||||||
|
set := addRrsetOrFail(t, sets, rrset)
|
||||||
|
defer sets.Remove(set)
|
||||||
|
t.Logf("Successfully added resource record set: %v", set)
|
||||||
|
found := false
|
||||||
|
for _, record := range listRrsOrFail(t, sets) {
|
||||||
|
if record.Name() == rrset.Name() {
|
||||||
|
found = true
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if !found {
|
||||||
|
t.Errorf("Failed to find added resource record set %s", rrset.Name())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* TestResourceRecordSetsAddDuplicateFail verifies that addition of a duplicate RRS fails */
|
||||||
|
func TestResourceRecordSetsAddDuplicateFail(t *testing.T) {
|
||||||
|
zone := firstZone(t)
|
||||||
|
sets := rrs(t, zone)
|
||||||
|
rrset := getExampleRrs(zone)
|
||||||
|
set := addRrsetOrFail(t, sets, rrset)
|
||||||
|
defer sets.Remove(set)
|
||||||
|
t.Logf("Successfully added resource record set: %v", set)
|
||||||
|
// Try to add it again, and verify that the call fails.
|
||||||
|
rrs, err := sets.Add(rrset)
|
||||||
|
if err == nil {
|
||||||
|
defer sets.Remove(rrs)
|
||||||
|
t.Errorf("Should have failed to add duplicate resource record %v, but succeeded instead.", set)
|
||||||
|
} else {
|
||||||
|
t.Logf("Correctly failed to add duplicate resource record %v: %v", set, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* TestResourceRecordSetsRemove verifies that the removal of an existing RRS succeeds */
|
||||||
|
func TestResourceRecordSetsRemove(t *testing.T) {
|
||||||
|
zone := firstZone(t)
|
||||||
|
sets := rrs(t, zone)
|
||||||
|
rrset := getExampleRrs(zone)
|
||||||
|
set := addRrsetOrFail(t, sets, rrset)
|
||||||
|
err := sets.Remove(set)
|
||||||
|
if err != nil {
|
||||||
|
// Try again to clean up.
|
||||||
|
defer sets.Remove(rrset)
|
||||||
|
t.Errorf("Failed to remove resource record set %v after adding", rrset)
|
||||||
|
} else {
|
||||||
|
t.Logf("Successfully removed resource set %v after adding", set)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* TestResourceRecordSetsRemoveGone verifies that a removed RRS no longer exists */
|
||||||
|
func TestResourceRecordSetsRemoveGone(t *testing.T) {
|
||||||
|
zone := firstZone(t)
|
||||||
|
sets := rrs(t, zone)
|
||||||
|
rrset := getExampleRrs(zone)
|
||||||
|
set := addRrsetOrFail(t, sets, rrset)
|
||||||
|
err := sets.Remove(set)
|
||||||
|
if err != nil {
|
||||||
|
// Try again to clean up.
|
||||||
|
defer sets.Remove(rrset)
|
||||||
|
t.Errorf("Failed to remove resource record set %v after adding", rrset)
|
||||||
|
} else {
|
||||||
|
t.Logf("Successfully removed resource set %v after adding", set)
|
||||||
|
}
|
||||||
|
// Check that it's gone
|
||||||
|
list := listRrsOrFail(t, sets)
|
||||||
|
found := false
|
||||||
|
for _, set := range list {
|
||||||
|
if set.Name() == rrset.Name() {
|
||||||
|
found = true
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if found {
|
||||||
|
t.Errorf("Deleted resource record set %v is still present", rrset)
|
||||||
|
}
|
||||||
|
}
|
53
federation/pkg/dnsprovider/providers/aws/route53/rrset.go
Normal file
53
federation/pkg/dnsprovider/providers/aws/route53/rrset.go
Normal file
@ -0,0 +1,53 @@
|
|||||||
|
/*
|
||||||
|
Copyright 2016 The Kubernetes Authors All rights reserved.
|
||||||
|
|
||||||
|
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 route53
|
||||||
|
|
||||||
|
import (
|
||||||
|
"k8s.io/kubernetes/federation/pkg/dnsprovider"
|
||||||
|
"k8s.io/kubernetes/federation/pkg/dnsprovider/rrstype"
|
||||||
|
|
||||||
|
"github.com/aws/aws-sdk-go/service/route53"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Compile time check for interface adeherence
|
||||||
|
var _ dnsprovider.ResourceRecordSet = ResourceRecordSet{}
|
||||||
|
|
||||||
|
type ResourceRecordSet struct {
|
||||||
|
impl *route53.ResourceRecordSet
|
||||||
|
rrsets *ResourceRecordSets
|
||||||
|
}
|
||||||
|
|
||||||
|
func (rrset ResourceRecordSet) Name() string {
|
||||||
|
return *rrset.impl.Name
|
||||||
|
}
|
||||||
|
|
||||||
|
func (rrset ResourceRecordSet) Rrdatas() []string {
|
||||||
|
// Sigh - need to unpack the strings out of the route53 ResourceRecords
|
||||||
|
result := make([]string, len(rrset.impl.ResourceRecords))
|
||||||
|
for i, record := range rrset.impl.ResourceRecords {
|
||||||
|
result[i] = *record.Value
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
func (rrset ResourceRecordSet) Ttl() int64 {
|
||||||
|
return *rrset.impl.TTL
|
||||||
|
}
|
||||||
|
|
||||||
|
func (rrset ResourceRecordSet) Type() rrstype.RrsType {
|
||||||
|
return rrstype.RrsType(*rrset.impl.Type)
|
||||||
|
}
|
135
federation/pkg/dnsprovider/providers/aws/route53/rrsets.go
Normal file
135
federation/pkg/dnsprovider/providers/aws/route53/rrsets.go
Normal file
@ -0,0 +1,135 @@
|
|||||||
|
/*
|
||||||
|
Copyright 2016 The Kubernetes Authors All rights reserved.
|
||||||
|
|
||||||
|
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 route53
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/aws/aws-sdk-go/aws"
|
||||||
|
"github.com/aws/aws-sdk-go/service/route53"
|
||||||
|
"k8s.io/kubernetes/federation/pkg/dnsprovider"
|
||||||
|
"k8s.io/kubernetes/federation/pkg/dnsprovider/rrstype"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Compile time check for interface adeherence
|
||||||
|
var _ dnsprovider.ResourceRecordSets = ResourceRecordSets{}
|
||||||
|
|
||||||
|
type ResourceRecordSets struct {
|
||||||
|
zone *Zone
|
||||||
|
}
|
||||||
|
|
||||||
|
func (rrsets ResourceRecordSets) List() ([]dnsprovider.ResourceRecordSet, error) {
|
||||||
|
input := route53.ListResourceRecordSetsInput{
|
||||||
|
HostedZoneId: rrsets.zone.impl.Id,
|
||||||
|
}
|
||||||
|
response, err := rrsets.zone.zones.interface_.service.ListResourceRecordSets(&input)
|
||||||
|
// TODO: Handle truncated responses
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
list := make([]dnsprovider.ResourceRecordSet, len(response.ResourceRecordSets))
|
||||||
|
for i, rrset := range response.ResourceRecordSets {
|
||||||
|
list[i] = &ResourceRecordSet{rrset, &rrsets}
|
||||||
|
}
|
||||||
|
return list, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (rrsets ResourceRecordSets) Add(rrset dnsprovider.ResourceRecordSet) (dnsprovider.ResourceRecordSet, error) {
|
||||||
|
service := rrsets.zone.zones.interface_.service
|
||||||
|
input := getChangeResourceRecordSetsInput("CREATE", rrset.Name(), string(rrset.Type()), *rrset.(ResourceRecordSet).rrsets.zone.impl.Id, rrset.Rrdatas(), rrset.Ttl())
|
||||||
|
_, err := service.ChangeResourceRecordSets(input)
|
||||||
|
if err != nil {
|
||||||
|
// Cast err to awserr.Error to get the Code and
|
||||||
|
// Message from an error.
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return ResourceRecordSet{input.ChangeBatch.Changes[0].ResourceRecordSet, &rrsets}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (rrsets ResourceRecordSets) Remove(rrset dnsprovider.ResourceRecordSet) error {
|
||||||
|
input := getChangeResourceRecordSetsInput("DELETE", rrset.Name(), string(rrset.Type()), *rrset.(ResourceRecordSet).rrsets.zone.impl.Id, rrset.Rrdatas(), rrset.Ttl())
|
||||||
|
_, err := rrsets.zone.zones.interface_.service.ChangeResourceRecordSets(input)
|
||||||
|
if err != nil {
|
||||||
|
// Cast err to awserr.Error to get the Code and
|
||||||
|
// Message from an error.
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func getChangeResourceRecordSetsInput(action, name, type_, hostedZoneId string, rrdatas []string, ttl int64) *route53.ChangeResourceRecordSetsInput {
|
||||||
|
input := &route53.ChangeResourceRecordSetsInput{
|
||||||
|
ChangeBatch: &route53.ChangeBatch{ // Required
|
||||||
|
Changes: []*route53.Change{ // Required
|
||||||
|
{ // Required
|
||||||
|
Action: aws.String(action), // Required
|
||||||
|
ResourceRecordSet: &route53.ResourceRecordSet{ // Required
|
||||||
|
Name: aws.String(name), // Required
|
||||||
|
Type: aws.String(type_), // Required
|
||||||
|
/*
|
||||||
|
AliasTarget: &route53.AliasTarget{
|
||||||
|
DNSName: aws.String("DNSName"), // Required
|
||||||
|
EvaluateTargetHealth: aws.Bool(true), // Required
|
||||||
|
HostedZoneId: aws.String("ResourceId"), // Required
|
||||||
|
},
|
||||||
|
Failover: aws.String("ResourceRecordSetFailover"),
|
||||||
|
GeoLocation: &route53.GeoLocation{
|
||||||
|
ContinentCode: aws.String("GeoLocationContinentCode"),
|
||||||
|
CountryCode: aws.String("GeoLocationCountryCode"),
|
||||||
|
SubdivisionCode: aws.String("GeoLocationSubdivisionCode"),
|
||||||
|
},
|
||||||
|
HealthCheckId: aws.String("HealthCheckId"),
|
||||||
|
Region: aws.String("ResourceRecordSetRegion"),
|
||||||
|
*/
|
||||||
|
ResourceRecords: []*route53.ResourceRecord{
|
||||||
|
{ // Required
|
||||||
|
Value: aws.String(rrdatas[0]), // Required
|
||||||
|
},
|
||||||
|
// More values...
|
||||||
|
},
|
||||||
|
/*
|
||||||
|
SetIdentifier: aws.String("ResourceRecordSetIdentifier"),
|
||||||
|
|
||||||
|
*/
|
||||||
|
TTL: aws.Int64(ttl),
|
||||||
|
/*
|
||||||
|
TrafficPolicyInstanceId: aws.String("TrafficPolicyInstanceId"),
|
||||||
|
Weight: aws.Int64(1),
|
||||||
|
*/
|
||||||
|
},
|
||||||
|
},
|
||||||
|
// More values...
|
||||||
|
},
|
||||||
|
},
|
||||||
|
HostedZoneId: aws.String(hostedZoneId), // Required
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (rrsets ResourceRecordSets) New(name string, rrdatas []string, ttl int64, rrstype rrstype.RrsType) dnsprovider.ResourceRecordSet {
|
||||||
|
rrstypeStr := string(rrstype)
|
||||||
|
return ResourceRecordSet{
|
||||||
|
&route53.ResourceRecordSet{
|
||||||
|
Name: &name,
|
||||||
|
Type: &rrstypeStr,
|
||||||
|
TTL: &ttl,
|
||||||
|
ResourceRecords: []*route53.ResourceRecord{
|
||||||
|
{
|
||||||
|
Value: &rrdatas[0],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}, // TODO: Add remaining rrdatas
|
||||||
|
&rrsets,
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,112 @@
|
|||||||
|
/*
|
||||||
|
Copyright 2016 The Kubernetes Authors All rights reserved.
|
||||||
|
|
||||||
|
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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* internal implements a stub for the AWS Route53 API, used primarily for unit testing purposes */
|
||||||
|
package testing
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/aws/aws-sdk-go/service/route53"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Compile time check for interface conformance
|
||||||
|
var _ Route53API = &Route53APIStub{}
|
||||||
|
|
||||||
|
/* Route53API is the subset of the AWS Route53 API that we actually use. Add methods as required. Signatures must match exactly. */
|
||||||
|
type Route53API interface {
|
||||||
|
ListResourceRecordSets(*route53.ListResourceRecordSetsInput) (*route53.ListResourceRecordSetsOutput, error)
|
||||||
|
ChangeResourceRecordSets(*route53.ChangeResourceRecordSetsInput) (*route53.ChangeResourceRecordSetsOutput, error)
|
||||||
|
ListHostedZones(*route53.ListHostedZonesInput) (*route53.ListHostedZonesOutput, error)
|
||||||
|
CreateHostedZone(*route53.CreateHostedZoneInput) (*route53.CreateHostedZoneOutput, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Route53APIStub is a minimal implementation of Route53API, used primarily for unit testing.
|
||||||
|
// See http://http://docs.aws.amazon.com/sdk-for-go/api/service/route53.html for descriptions
|
||||||
|
// of all of it's methods.
|
||||||
|
type Route53APIStub struct {
|
||||||
|
zones map[string]*route53.HostedZone
|
||||||
|
recordSets map[string]map[string][]*route53.ResourceRecordSet
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewRoute53APIStub returns an initlialized Route53APIStub
|
||||||
|
func NewRoute53APIStub() *Route53APIStub {
|
||||||
|
return &Route53APIStub{
|
||||||
|
zones: make(map[string]*route53.HostedZone),
|
||||||
|
recordSets: make(map[string]map[string][]*route53.ResourceRecordSet),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *Route53APIStub) ListResourceRecordSets(input *route53.ListResourceRecordSetsInput) (*route53.ListResourceRecordSetsOutput, error) {
|
||||||
|
output := route53.ListResourceRecordSetsOutput{} // TODO: Support optional input args.
|
||||||
|
if len(r.recordSets) <= 0 {
|
||||||
|
output.ResourceRecordSets = []*route53.ResourceRecordSet{}
|
||||||
|
} else if _, ok := r.recordSets[*input.HostedZoneId]; !ok {
|
||||||
|
output.ResourceRecordSets = []*route53.ResourceRecordSet{}
|
||||||
|
} else {
|
||||||
|
for _, rrsets := range r.recordSets[*input.HostedZoneId] {
|
||||||
|
for _, rrset := range rrsets {
|
||||||
|
output.ResourceRecordSets = append(output.ResourceRecordSets, rrset)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return &output, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *Route53APIStub) ChangeResourceRecordSets(input *route53.ChangeResourceRecordSetsInput) (*route53.ChangeResourceRecordSetsOutput, error) {
|
||||||
|
output := &route53.ChangeResourceRecordSetsOutput{}
|
||||||
|
recordSets, ok := r.recordSets[*input.HostedZoneId]
|
||||||
|
if !ok {
|
||||||
|
recordSets = make(map[string][]*route53.ResourceRecordSet)
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, change := range input.ChangeBatch.Changes {
|
||||||
|
switch *change.Action {
|
||||||
|
case route53.ChangeActionCreate:
|
||||||
|
if _, found := recordSets[*change.ResourceRecordSet.Name]; found {
|
||||||
|
return nil, fmt.Errorf("Attempt to create duplicate rrset %s", change.ResourceRecordSet.Name) // TODO: Return AWS errors with codes etc
|
||||||
|
}
|
||||||
|
recordSets[*change.ResourceRecordSet.Name] = append(recordSets[*change.ResourceRecordSet.Name], change.ResourceRecordSet)
|
||||||
|
case route53.ChangeActionDelete:
|
||||||
|
if _, found := recordSets[*change.ResourceRecordSet.Name]; !found {
|
||||||
|
return nil, fmt.Errorf("Attempt to delete non-existant rrset %s", change.ResourceRecordSet.Name) // TODO: Check other fields too
|
||||||
|
}
|
||||||
|
delete(recordSets, *change.ResourceRecordSet.Name)
|
||||||
|
case route53.ChangeActionUpsert:
|
||||||
|
// TODO - not used yet
|
||||||
|
}
|
||||||
|
}
|
||||||
|
r.recordSets[*input.HostedZoneId] = recordSets
|
||||||
|
return output, nil // TODO: We should ideally return status etc, but we dont' use that yet.
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *Route53APIStub) ListHostedZones(*route53.ListHostedZonesInput) (*route53.ListHostedZonesOutput, error) {
|
||||||
|
output := &route53.ListHostedZonesOutput{}
|
||||||
|
for _, zone := range r.zones {
|
||||||
|
output.HostedZones = append(output.HostedZones, zone)
|
||||||
|
}
|
||||||
|
return output, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *Route53APIStub) CreateHostedZone(input *route53.CreateHostedZoneInput) (*route53.CreateHostedZoneOutput, error) {
|
||||||
|
if _, ok := r.zones[*input.Name]; ok {
|
||||||
|
return nil, fmt.Errorf("Error creating hosted DNS zone: %s already exists", input.Name)
|
||||||
|
}
|
||||||
|
r.zones[*input.Name] = &route53.HostedZone{
|
||||||
|
Id: input.Name,
|
||||||
|
Name: input.Name,
|
||||||
|
}
|
||||||
|
return &route53.CreateHostedZoneOutput{HostedZone: r.zones[*input.Name]}, nil
|
||||||
|
}
|
38
federation/pkg/dnsprovider/providers/aws/route53/zone.go
Normal file
38
federation/pkg/dnsprovider/providers/aws/route53/zone.go
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
/*
|
||||||
|
Copyright 2016 The Kubernetes Authors All rights reserved.
|
||||||
|
|
||||||
|
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 route53
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/aws/aws-sdk-go/service/route53"
|
||||||
|
"k8s.io/kubernetes/federation/pkg/dnsprovider"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Compile time check for interface adeherence
|
||||||
|
var _ dnsprovider.Zone = &Zone{}
|
||||||
|
|
||||||
|
type Zone struct {
|
||||||
|
impl *route53.HostedZone
|
||||||
|
zones *Zones
|
||||||
|
}
|
||||||
|
|
||||||
|
func (zone *Zone) Name() string {
|
||||||
|
return *zone.impl.Name
|
||||||
|
}
|
||||||
|
|
||||||
|
func (zone *Zone) ResourceRecordSets() (dnsprovider.ResourceRecordSets, bool) {
|
||||||
|
return &ResourceRecordSets{zone}, true
|
||||||
|
}
|
45
federation/pkg/dnsprovider/providers/aws/route53/zones.go
Normal file
45
federation/pkg/dnsprovider/providers/aws/route53/zones.go
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
/*
|
||||||
|
Copyright 2016 The Kubernetes Authors All rights reserved.
|
||||||
|
|
||||||
|
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 route53
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/aws/aws-sdk-go/service/route53"
|
||||||
|
"k8s.io/kubernetes/federation/pkg/dnsprovider"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Compile time check for interface adeherence
|
||||||
|
var _ dnsprovider.Zones = Zones{}
|
||||||
|
|
||||||
|
type Zones struct {
|
||||||
|
interface_ *Interface
|
||||||
|
}
|
||||||
|
|
||||||
|
func (zones Zones) List() ([]dnsprovider.Zone, error) {
|
||||||
|
input := route53.ListHostedZonesInput{}
|
||||||
|
response, err := zones.interface_.service.ListHostedZones(&input)
|
||||||
|
if err != nil {
|
||||||
|
return []dnsprovider.Zone{}, err
|
||||||
|
}
|
||||||
|
hostedZones := response.HostedZones
|
||||||
|
// TODO: Handle result truncation
|
||||||
|
// https://docs.aws.amazon.com/sdk-for-go/api/service/route53/Route53.html#ListHostedZones-instance_method
|
||||||
|
zoneList := make([]dnsprovider.Zone, len(hostedZones))
|
||||||
|
for i, zone := range hostedZones {
|
||||||
|
zoneList[i] = &Zone{zone, &zones}
|
||||||
|
}
|
||||||
|
return zoneList, nil
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user