diff --git a/federation/pkg/dnsprovider/dns.go b/federation/pkg/dnsprovider/dns.go index 787367599a8..f100133081a 100644 --- a/federation/pkg/dnsprovider/dns.go +++ b/federation/pkg/dnsprovider/dns.go @@ -29,6 +29,8 @@ type Zones interface { List() ([]Zone, error) // Add creates and returns a new managed zone, or an error if the operation failed Add(Zone) (Zone, error) + // Remove deletes a managed zone, or returns an error if the operation failed. + Remove(Zone) error // New allocates a new Zone, which can then be passed to Add() // Arguments are as per the Zone interface below. New(name string) (Zone, error) diff --git a/federation/pkg/dnsprovider/providers/aws/route53/route53_test.go b/federation/pkg/dnsprovider/providers/aws/route53/route53_test.go index 0fc61d1caff..180d7cc45b2 100644 --- a/federation/pkg/dnsprovider/providers/aws/route53/route53_test.go +++ b/federation/pkg/dnsprovider/providers/aws/route53/route53_test.go @@ -32,7 +32,7 @@ import ( 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 dnsprovider.GetDnsProvider(ProviderName, strings.NewReader("\n[global]\nproject-id = federation0-cluster00")) return newFakeInterface() // Use this to stub out the entire cloud service } @@ -68,16 +68,23 @@ func TestMain(m *testing.M) { os.Exit(m.Run()) } +// zones returns the zones interface for the configured dns provider account/project, +// or fails if it can't be found +func zones(t *testing.T) dnsprovider.Zones { + zonesInterface, supported := interface_.Zones() + if !supported { + t.Fatalf("Zones interface not supported by interface %v", interface_) + } else { + t.Logf("Got zones %v\n", zonesInterface) + } + return zonesInterface +} + // 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_) - } + z := zones(t) zones, err := z.List() if err != nil { t.Fatalf("Failed to list zones: %v", err) @@ -139,6 +146,28 @@ func TestZonesList(t *testing.T) { firstZone(t) } +/* TestZoneAddSuccess verifies that addition of a valid managed DNS zone succeeds */ +func TestZoneAddSuccess(t *testing.T) { + testZoneName := "ubernetes.testing" + z := zones(t) + input, err := z.New(testZoneName) + if err != nil { + t.Errorf("Failed to allocate new zone object %s: %v", testZoneName, err) + } + zone, err := z.Add(input) + if err != nil { + t.Errorf("Failed to create new managed DNS zone %s: %v", testZoneName, err) + } + defer func(zone dnsprovider.Zone) { + if zone != nil { + if err := z.Remove(zone); err != nil { + t.Errorf("Failed to delete zone %v: %v", zone, err) + } + } + }(zone) + t.Logf("Successfully added managed DNS zone: %v", zone) +} + /* TestResourceRecordSetsList verifies that listing of RRS's succeeds */ func TestResourceRecordSetsList(t *testing.T) { listRrsOrFail(t, rrs(t, firstZone(t))) diff --git a/federation/pkg/dnsprovider/providers/aws/route53/stubs/route53api.go b/federation/pkg/dnsprovider/providers/aws/route53/stubs/route53api.go index 879c72b014a..0869b3de233 100644 --- a/federation/pkg/dnsprovider/providers/aws/route53/stubs/route53api.go +++ b/federation/pkg/dnsprovider/providers/aws/route53/stubs/route53api.go @@ -31,6 +31,7 @@ type Route53API interface { ChangeResourceRecordSets(*route53.ChangeResourceRecordSetsInput) (*route53.ChangeResourceRecordSetsOutput, error) ListHostedZones(*route53.ListHostedZonesInput) (*route53.ListHostedZonesOutput, error) CreateHostedZone(*route53.CreateHostedZoneInput) (*route53.CreateHostedZoneOutput, error) + DeleteHostedZone(*route53.DeleteHostedZoneInput) (*route53.DeleteHostedZoneOutput, error) } // Route53APIStub is a minimal implementation of Route53API, used primarily for unit testing. @@ -110,3 +111,14 @@ func (r *Route53APIStub) CreateHostedZone(input *route53.CreateHostedZoneInput) } return &route53.CreateHostedZoneOutput{HostedZone: r.zones[*input.Name]}, nil } + +func (r *Route53APIStub) DeleteHostedZone(input *route53.DeleteHostedZoneInput) (*route53.DeleteHostedZoneOutput, error) { + if _, ok := r.zones[*input.Id]; !ok { + return nil, fmt.Errorf("Error deleting hosted DNS zone: %s does not exist", *input.Id) + } + if len(r.recordSets[*input.Id]) > 0 { + return nil, fmt.Errorf("Error deleting hosted DNS zone: %s has resource records", *input.Id) + } + delete(r.zones, *input.Id) + return &route53.DeleteHostedZoneOutput{}, nil +} diff --git a/federation/pkg/dnsprovider/providers/aws/route53/zones.go b/federation/pkg/dnsprovider/providers/aws/route53/zones.go index e836e5406ef..3b40bc1408c 100644 --- a/federation/pkg/dnsprovider/providers/aws/route53/zones.go +++ b/federation/pkg/dnsprovider/providers/aws/route53/zones.go @@ -48,7 +48,8 @@ func (zones Zones) List() ([]dnsprovider.Zone, error) { func (zones Zones) Add(zone dnsprovider.Zone) (dnsprovider.Zone, error) { dnsName := zone.Name() - input := route53.CreateHostedZoneInput{Name: &dnsName} + callerReference := string(util.NewUUID()) + input := route53.CreateHostedZoneInput{Name: &dnsName, CallerReference: &callerReference} output, err := zones.interface_.service.CreateHostedZone(&input) if err != nil { return nil, err @@ -56,6 +57,15 @@ func (zones Zones) Add(zone dnsprovider.Zone) (dnsprovider.Zone, error) { return &Zone{output.HostedZone, &zones}, nil } +func (zones Zones) Remove(zone dnsprovider.Zone) error { + zoneId := zone.(*Zone).impl.Id + input := route53.DeleteHostedZoneInput{Id: zoneId} + _, err := zones.interface_.service.DeleteHostedZone(&input) + if err != nil { + return err + } + return nil +} func (zones Zones) New(name string) (dnsprovider.Zone, error) { id := string(util.NewUUID()) managedZone := route53.HostedZone{Id: &id, Name: &name} diff --git a/federation/pkg/dnsprovider/providers/google/clouddns/clouddns_test.go b/federation/pkg/dnsprovider/providers/google/clouddns/clouddns_test.go index bf41d792049..9d0b06e5fbd 100644 --- a/federation/pkg/dnsprovider/providers/google/clouddns/clouddns_test.go +++ b/federation/pkg/dnsprovider/providers/google/clouddns/clouddns_test.go @@ -29,7 +29,7 @@ import ( func newTestInterface() (dnsprovider.Interface, error) { // Use this to test the real cloud service - insert appropriate project-id. Default token source will be used. See // https://github.com/golang/oauth2/blob/master/google/default.go for details. - // i, err := dnsprovider.GetDnsProvider(ProviderName, strings.NewReader("\n[global]\nproject-id = federation0-cluster00")) + // return dnsprovider.GetDnsProvider(ProviderName, strings.NewReader("\n[global]\nproject-id = federation0-cluster00")) return NewFakeInterface() // Use this to stub out the entire cloud service } @@ -46,17 +46,23 @@ func TestMain(m *testing.M) { os.Exit(m.Run()) } +// zones returns the zones interface for the configured dns provider account/project, +// or fails if it can't be found +func zones(t *testing.T) dnsprovider.Zones { + zonesInterface, supported := interface_.Zones() + if !supported { + t.Fatalf("Zones interface not supported by interface %v", interface_) + } else { + t.Logf("Got zones %v\n", zonesInterface) + } + return zonesInterface +} + // 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() + zones, err := zones(t).List() if err != nil { t.Fatalf("Failed to list zones: %v", err) } else { @@ -117,6 +123,30 @@ func TestZonesList(t *testing.T) { firstZone(t) } +/* TestZoneAddSuccess verifies that addition of a valid managed DNS zone succeeds */ +func TestZoneAddSuccess(t *testing.T) { + testZoneName := "ubernetesv2.test." + t.Logf("Getting zones") + z := zones(t) + t.Logf("Got zones, making new Zone") + input, err := z.New(testZoneName) + if err != nil { + t.Errorf("Failed to allocate new zone object %s: %v", testZoneName, err) + } + zone, err := z.Add(input) + if err != nil { + t.Errorf("Failed to create new managed DNS zone %s: %v", testZoneName, err) + } + defer func(zone dnsprovider.Zone) { + if zone != nil { + if err := z.Remove(zone); err != nil { + t.Errorf("Failed to delete zone %v: %v", zone, err) + } + } + }(zone) + t.Logf("Successfully added managed DNS zone: %v", zone) +} + /* TestResourceRecordSetsList verifies that listing of RRS's succeeds */ func TestResourceRecordSetsList(t *testing.T) { listRrsOrFail(t, rrs(t, firstZone(t))) diff --git a/federation/pkg/dnsprovider/providers/google/clouddns/internal/managed_zones_delete_call.go b/federation/pkg/dnsprovider/providers/google/clouddns/internal/managed_zones_delete_call.go index 6fe25343ab7..157ade04356 100644 --- a/federation/pkg/dnsprovider/providers/google/clouddns/internal/managed_zones_delete_call.go +++ b/federation/pkg/dnsprovider/providers/google/clouddns/internal/managed_zones_delete_call.go @@ -28,5 +28,5 @@ var _ interfaces.ManagedZonesDeleteCall = ManagedZonesDeleteCall{} type ManagedZonesDeleteCall struct{ impl *dns.ManagedZonesDeleteCall } func (call ManagedZonesDeleteCall) Do(opts ...googleapi.CallOption) error { - return call.Do(opts...) + return call.impl.Do(opts...) } diff --git a/federation/pkg/dnsprovider/providers/google/clouddns/internal/managed_zones_service.go b/federation/pkg/dnsprovider/providers/google/clouddns/internal/managed_zones_service.go index 62d2587df90..9862078618f 100644 --- a/federation/pkg/dnsprovider/providers/google/clouddns/internal/managed_zones_service.go +++ b/federation/pkg/dnsprovider/providers/google/clouddns/internal/managed_zones_service.go @@ -17,6 +17,8 @@ limitations under the License. package internal import ( + "strings" + dns "google.golang.org/api/dns/v1" "k8s.io/kubernetes/federation/pkg/dnsprovider/providers/google/clouddns/internal/interfaces" "k8s.io/kubernetes/pkg/util" @@ -28,7 +30,7 @@ var _ interfaces.ManagedZonesService = &ManagedZonesService{} type ManagedZonesService struct{ impl *dns.ManagedZonesService } func (m *ManagedZonesService) Create(project string, managedzone interfaces.ManagedZone) interfaces.ManagedZonesCreateCall { - return &ManagedZonesCreateCall{m.impl.Create(project, managedzone.(ManagedZone).impl)} + return &ManagedZonesCreateCall{m.impl.Create(project, managedzone.(*ManagedZone).impl)} } func (m *ManagedZonesService) Delete(project, managedZone string) interfaces.ManagedZonesDeleteCall { @@ -44,5 +46,6 @@ func (m *ManagedZonesService) List(project string) interfaces.ManagedZonesListCa } func (m *ManagedZonesService) NewManagedZone(dnsName string) interfaces.ManagedZone { - return &ManagedZone{impl: &dns.ManagedZone{Name: string(util.NewUUID()), DnsName: dnsName}} + name := "x" + strings.Replace(string(util.NewUUID()), "-", "", -1)[0:30] // Unique name, strip out the "-" chars to shorten it, start with a lower case alpha, and truncate to Cloud DNS 32 character limit + return &ManagedZone{impl: &dns.ManagedZone{Name: name, Description: "Kubernetes Federated Service", DnsName: dnsName}} } diff --git a/federation/pkg/dnsprovider/providers/google/clouddns/zones.go b/federation/pkg/dnsprovider/providers/google/clouddns/zones.go index 2cd7f21fe45..4018037daa0 100644 --- a/federation/pkg/dnsprovider/providers/google/clouddns/zones.go +++ b/federation/pkg/dnsprovider/providers/google/clouddns/zones.go @@ -51,6 +51,13 @@ func (zones Zones) Add(zone dnsprovider.Zone) (dnsprovider.Zone, error) { return &Zone{response, &zones}, nil } +func (zones Zones) Remove(zone dnsprovider.Zone) error { + if err := zones.impl.Delete(zones.project(), zone.(*Zone).impl.Name()).Do(); err != nil { + return err + } + return nil +} + func (zones Zones) New(name string) (dnsprovider.Zone, error) { managedZone := zones.impl.NewManagedZone(name) return &Zone{managedZone, &zones}, nil