diff --git a/federation/pkg/dnsprovider/dns.go b/federation/pkg/dnsprovider/dns.go new file mode 100644 index 00000000000..4e32850bf16 --- /dev/null +++ b/federation/pkg/dnsprovider/dns.go @@ -0,0 +1,61 @@ +/* +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 dnsprovider + +import "k8s.io/kubernetes/federation/pkg/dnsprovider/rrstype" + +// Interface is an abstract, pluggable interface for DNS providers. +type Interface interface { + // Zones returns the provider's Zones interface, or false if not supported. + Zones() (Zones, bool) +} + +type Zones interface { + // List returns the managed Zones, or an error if the list operation failed. + List() ([]Zone, error) +} + +type Zone interface { + // Name returns the name of the zone, e.g. "example.com" + Name() string + // ResourceRecordsets returns the provider's ResourceRecordSets interface, or false if not supported. + ResourceRecordSets() (ResourceRecordSets, bool) +} + +type ResourceRecordSets interface { + // List returns the ResourceRecordSets of the Zone, or an error if the list operation failed. + List() ([]ResourceRecordSet, error) + // Add adds and returns a ResourceRecordSet of the Zone, or an error if the add operation failed. + Add(ResourceRecordSet) (ResourceRecordSet, error) + // Remove removes a ResourceRecordSet from the Zone, or an error if the remove operation failed. + // The supplied ResourceRecordSet must match one of the existing zones (obtained via List()) exactly. + Remove(ResourceRecordSet) error + // New allocates a new ResourceRecordSet, which can then be passed to Add() or Remove() + // Arguments are as per the ResourceRecordSet interface below. + New(name string, rrdatas []string, ttl int64, rrstype rrstype.RrsType) ResourceRecordSet +} + +type ResourceRecordSet interface { + // Name returns the name of the ResourceRecordSet, e.g. "www.example.com". + Name() string + // Rrdatas returns the Resource Record Datas of the record set. + Rrdatas() []string + // Ttl returns the time-to-live of the record set, in seconds. + Ttl() int64 + // Type returns the type of the record set (A, CNAME, SRV, etc) + Type() rrstype.RrsType +} diff --git a/federation/pkg/dnsprovider/doc.go b/federation/pkg/dnsprovider/doc.go new file mode 100644 index 00000000000..9a3d7e0455c --- /dev/null +++ b/federation/pkg/dnsprovider/doc.go @@ -0,0 +1,21 @@ +/* +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. +*/ + +/* +dnsprovider supplies interfaces for dns service providers (e.g. Google Cloud DNS, AWS route53, etc). +Implementations exist in the providers sub-package +*/ +package dnsprovider diff --git a/federation/pkg/dnsprovider/plugins.go b/federation/pkg/dnsprovider/plugins.go new file mode 100644 index 00000000000..71dbf65268b --- /dev/null +++ b/federation/pkg/dnsprovider/plugins.go @@ -0,0 +1,98 @@ +/* +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 dnsprovider + +import ( + "fmt" + "io" + "os" + "sync" + + "github.com/golang/glog" +) + +// Factory is a function that returns a dnsprovider.Interface. +// The config parameter provides an io.Reader handler to the factory in +// order to load specific configurations. If no configuration is provided +// the parameter is nil. +type Factory func(config io.Reader) (Interface, error) + +// All registered dns providers. +var providersMutex sync.Mutex +var providers = make(map[string]Factory) + +// RegisterDnsProvider registers a dnsprovider.Factory by name. This +// is expected to happen during startup. +func RegisterDnsProvider(name string, cloud Factory) { + providersMutex.Lock() + defer providersMutex.Unlock() + if _, found := providers[name]; found { + glog.Fatalf("DNS provider %q was registered twice", name) + } + glog.V(1).Infof("Registered DNS provider %q", name) + providers[name] = cloud +} + +// GetDnsProvider creates an instance of the named DNS provider, or nil if +// the name is not known. The error return is only used if the named provider +// was known but failed to initialize. The config parameter specifies the +// io.Reader handler of the configuration file for the DNS provider, or nil +// for no configuation. +func GetDnsProvider(name string, config io.Reader) (Interface, error) { + providersMutex.Lock() + defer providersMutex.Unlock() + f, found := providers[name] + if !found { + return nil, nil + } + return f(config) +} + +// InitDnsProvider creates an instance of the named DNS provider. +func InitDnsProvider(name string, configFilePath string) (Interface, error) { + var dns Interface + var err error + + if name == "" { + glog.Info("No DNS provider specified.") + return nil, nil + } + + if configFilePath != "" { + var config *os.File + config, err = os.Open(configFilePath) + if err != nil { + return nil, fmt.Errorf("Couldn't open DNS provider configuration %s: %#v", configFilePath, err) + } + + defer config.Close() + dns, err = GetDnsProvider(name, config) + } else { + // Pass explicit nil so plugins can actually check for nil. See + // "Why is my nil error value not equal to nil?" in golang.org/doc/faq. + dns, err = GetDnsProvider(name, nil) + } + + if err != nil { + return nil, fmt.Errorf("could not init DNS provider %q: %v", name, err) + } + if dns == nil { + return nil, fmt.Errorf("unknown DNS provider %q", name) + } + + return dns, nil +} diff --git a/federation/pkg/dnsprovider/providers/google/clouddns/clouddns.go b/federation/pkg/dnsprovider/providers/google/clouddns/clouddns.go new file mode 100644 index 00000000000..1ad772de6e8 --- /dev/null +++ b/federation/pkg/dnsprovider/providers/google/clouddns/clouddns.go @@ -0,0 +1,101 @@ +/* +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. +*/ + +// clouddns is the implementation of pkg/dnsprovider interface for Google Cloud DNS +package clouddns + +import ( + "io" + + "github.com/golang/glog" + "golang.org/x/oauth2" + "golang.org/x/oauth2/google" + compute "google.golang.org/api/compute/v1" + dns "google.golang.org/api/dns/v1" + "google.golang.org/cloud/compute/metadata" + gcfg "gopkg.in/gcfg.v1" + + "k8s.io/kubernetes/federation/pkg/dnsprovider" + "k8s.io/kubernetes/federation/pkg/dnsprovider/providers/google/clouddns/internal" + "k8s.io/kubernetes/pkg/cloudprovider/providers/gce" +) + +const ( + ProviderName = "google-clouddns" +) + +func init() { + dnsprovider.RegisterDnsProvider(ProviderName, func(config io.Reader) (dnsprovider.Interface, error) { + return newCloudDns(config) + }) +} + +type Config struct { + Global struct { + TokenURL string `gcfg:"token-url"` + TokenBody string `gcfg:"token-body"` + ProjectID string `gcfg:"project-id"` + } +} + +// newCloudDns creates a new instance of a Google Cloud DNS Interface. +func newCloudDns(config io.Reader) (*Interface, error) { + projectID, _ := metadata.ProjectID() // On error we get an empty string, which is fine for now. + var tokenSource oauth2.TokenSource + // Possibly override defaults with config below + if config != nil { + var cfg Config + if err := gcfg.ReadInto(&cfg, config); err != nil { + glog.Errorf("Couldn't read config: %v", err) + return nil, err + } + glog.Infof("Using Google Cloud DNS provider config %+v", cfg) + if cfg.Global.ProjectID != "" { + projectID = cfg.Global.ProjectID + } + if cfg.Global.TokenURL != "" { + tokenSource = gce.NewAltTokenSource(cfg.Global.TokenURL, cfg.Global.TokenBody) + } + } + return CreateInterface(projectID, tokenSource) +} + +// CreateInterface creates a clouddns.Interface object using the specified parameters. +// If no tokenSource is specified, uses oauth2.DefaultTokenSource. +func CreateInterface(projectID string, tokenSource oauth2.TokenSource) (*Interface, error) { + if tokenSource == nil { + var err error + tokenSource, err = google.DefaultTokenSource( + oauth2.NoContext, + compute.CloudPlatformScope, + compute.ComputeScope) + glog.Infof("Using DefaultTokenSource %#v", tokenSource) + if err != nil { + return nil, err + } + } else { + glog.Infof("Using existing Token Source %#v", tokenSource) + } + + oauthClient := oauth2.NewClient(oauth2.NoContext, tokenSource) + + service, err := dns.New(oauthClient) + if err != nil { + glog.Errorf("Failed to get Cloud DNS client: %v", err) + } + glog.Infof("Successfully got DNS service: %v\n", service) + return newInterfaceWithStub(projectID, internal.NewService(service)), nil +} diff --git a/federation/pkg/dnsprovider/providers/google/clouddns/clouddns_test.go b/federation/pkg/dnsprovider/providers/google/clouddns/clouddns_test.go new file mode 100644 index 00000000000..7ab5b3b1202 --- /dev/null +++ b/federation/pkg/dnsprovider/providers/google/clouddns/clouddns_test.go @@ -0,0 +1,229 @@ +/* +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 clouddns + +import ( + "flag" + "fmt" + "os" + "testing" + + "k8s.io/kubernetes/federation/pkg/dnsprovider" + "k8s.io/kubernetes/federation/pkg/dnsprovider/providers/google/clouddns/internal/stubs" + "k8s.io/kubernetes/federation/pkg/dnsprovider/rrstype" +) + +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 newFakeInterface() // Use this to stub out the entire cloud service +} + +func newFakeInterface() (dnsprovider.Interface, error) { + service := stubs.NewService() + interface_ := newInterfaceWithStub("", service) + zones := service.ManagedZones_ + // Add a fake zone to test against. + zone := &stubs.ManagedZone{zones, "example.com", []stubs.ResourceRecordSet{}} + call := zones.Create(interface_.project(), zone) + _, err := call.Do() + if err != nil { + return nil, err + } + return interface_, nil +} + +var interface_ dnsprovider.Interface + +func TestMain(m *testing.M) { + flag.Parse() + var err error + interface_, err = newTestInterface() + if err != nil { + fmt.Printf("Error creating interface: %v", err) + os.Exit(1) + } + 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) + } +} diff --git a/federation/pkg/dnsprovider/providers/google/clouddns/interface.go b/federation/pkg/dnsprovider/providers/google/clouddns/interface.go new file mode 100644 index 00000000000..0dd5ab877e7 --- /dev/null +++ b/federation/pkg/dnsprovider/providers/google/clouddns/interface.go @@ -0,0 +1,43 @@ +/* +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 clouddns + +import ( + "k8s.io/kubernetes/federation/pkg/dnsprovider" + "k8s.io/kubernetes/federation/pkg/dnsprovider/providers/google/clouddns/internal/interfaces" +) + +var _ dnsprovider.Interface = Interface{} + +type Interface struct { + project_ string + service interfaces.Service +} + +// newInterfaceWithStub facilitates stubbing out the underlying Google Cloud DNS +// library for testing purposes. It returns an provider-independent interface. +func newInterfaceWithStub(project string, service interfaces.Service) *Interface { + return &Interface{project, service} +} + +func (i Interface) Zones() (zones dnsprovider.Zones, supported bool) { + return Zones{i.service.ManagedZones(), &i}, true +} + +func (i Interface) project() string { + return i.project_ +} diff --git a/federation/pkg/dnsprovider/providers/google/clouddns/internal/change.go b/federation/pkg/dnsprovider/providers/google/clouddns/internal/change.go new file mode 100644 index 00000000000..7b2a2edffaf --- /dev/null +++ b/federation/pkg/dnsprovider/providers/google/clouddns/internal/change.go @@ -0,0 +1,42 @@ +/* +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 internal + +import ( + dns "google.golang.org/api/dns/v1" + "k8s.io/kubernetes/federation/pkg/dnsprovider/providers/google/clouddns/internal/interfaces" +) + +var _ interfaces.Change = Change{} + +type Change struct{ impl *dns.Change } + +func (c Change) Additions() (rrsets []interfaces.ResourceRecordSet) { + rrsets = make([]interfaces.ResourceRecordSet, len(c.impl.Additions)) + for index, addition := range c.impl.Additions { + rrsets[index] = interfaces.ResourceRecordSet(&ResourceRecordSet{addition}) + } + return rrsets +} + +func (c Change) Deletions() (rrsets []interfaces.ResourceRecordSet) { + rrsets = make([]interfaces.ResourceRecordSet, len(c.impl.Deletions)) + for index, deletion := range c.impl.Deletions { + rrsets[index] = interfaces.ResourceRecordSet(&ResourceRecordSet{deletion}) + } + return rrsets +} diff --git a/federation/pkg/dnsprovider/providers/google/clouddns/internal/changes_create_call.go b/federation/pkg/dnsprovider/providers/google/clouddns/internal/changes_create_call.go new file mode 100644 index 00000000000..6877ebe14ff --- /dev/null +++ b/federation/pkg/dnsprovider/providers/google/clouddns/internal/changes_create_call.go @@ -0,0 +1,33 @@ +/* +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 internal + +import ( + dns "google.golang.org/api/dns/v1" + "google.golang.org/api/googleapi" + + "k8s.io/kubernetes/federation/pkg/dnsprovider/providers/google/clouddns/internal/interfaces" +) + +var _ interfaces.ChangesCreateCall = ChangesCreateCall{} + +type ChangesCreateCall struct{ impl *dns.ChangesCreateCall } + +func (c ChangesCreateCall) Do(opts ...googleapi.CallOption) (interfaces.Change, error) { + ch, err := c.impl.Do(opts...) + return &Change{ch}, err +} diff --git a/federation/pkg/dnsprovider/providers/google/clouddns/internal/changes_service.go b/federation/pkg/dnsprovider/providers/google/clouddns/internal/changes_service.go new file mode 100644 index 00000000000..3d8b7834912 --- /dev/null +++ b/federation/pkg/dnsprovider/providers/google/clouddns/internal/changes_service.go @@ -0,0 +1,42 @@ +/* +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 internal + +import ( + dns "google.golang.org/api/dns/v1" + "k8s.io/kubernetes/federation/pkg/dnsprovider/providers/google/clouddns/internal/interfaces" +) + +var _ interfaces.ChangesService = ChangesService{} + +type ChangesService struct{ impl *dns.ChangesService } + +func (c ChangesService) Create(project string, managedZone string, change interfaces.Change) interfaces.ChangesCreateCall { + return &ChangesCreateCall{c.impl.Create(project, managedZone, change.(*Change).impl)} +} + +func (c ChangesService) NewChange(additions, deletions []interfaces.ResourceRecordSet) interfaces.Change { + adds := make([]*dns.ResourceRecordSet, len(additions)) + deletes := make([]*dns.ResourceRecordSet, len(deletions)) + for i, a := range additions { + adds[i] = a.(*ResourceRecordSet).impl + } + for i, d := range deletions { + deletes[i] = d.(*ResourceRecordSet).impl + } + return &Change{&dns.Change{Additions: adds, Deletions: deletes}} +} diff --git a/federation/pkg/dnsprovider/providers/google/clouddns/internal/clouddns.go b/federation/pkg/dnsprovider/providers/google/clouddns/internal/clouddns.go new file mode 100644 index 00000000000..4a985bd5623 --- /dev/null +++ b/federation/pkg/dnsprovider/providers/google/clouddns/internal/clouddns.go @@ -0,0 +1,35 @@ +/* +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 internal + +// Implementation of internal/interfaces/* on top of Google Cloud DNS API. +// See https://godoc.org/google.golang.org/api/dns/v1 for details +// This facilitates stubbing out Google Cloud DNS for unit testing. +// Only the parts of the API that we use are included. +// Others can be added as needed. + +import dns "google.golang.org/api/dns/v1" + +type ( + Project struct{ impl *dns.Project } + + ProjectsGetCall struct{ impl *dns.ProjectsGetCall } + + ProjectsService struct{ impl *dns.ProjectsService } + + Quota struct{ impl *dns.Quota } +) diff --git a/federation/pkg/dnsprovider/providers/google/clouddns/internal/interfaces/interfaces.go b/federation/pkg/dnsprovider/providers/google/clouddns/internal/interfaces/interfaces.go new file mode 100644 index 00000000000..2e7aab9d150 --- /dev/null +++ b/federation/pkg/dnsprovider/providers/google/clouddns/internal/interfaces/interfaces.go @@ -0,0 +1,207 @@ +/* +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 interfaces + +import ( + "google.golang.org/api/googleapi" + "k8s.io/kubernetes/federation/pkg/dnsprovider/rrstype" +) + +// Interfaces to directly mirror the Google Cloud DNS API structures. +// See https://godoc.org/google.golang.org/api/dns/v1 for details +// This facilitates stubbing out Google Cloud DNS for unit testing. +// Only the parts of the API that we use are included. +// Others can be added as needed. + +type ( + Change interface { + Additions() []ResourceRecordSet + Deletions() []ResourceRecordSet + // Id() string // TODO: Add as needed + // Kind() string // TODO: Add as needed + // StartTime() string // TODO: Add as needed + // Status() string // TODO: Add as needed + } + + ChangesCreateCall interface { + // Context(ctx context.Context) *ChangesCreateCall // TODO: Add as needed + Do(opts ...googleapi.CallOption) (Change, error) + // Fields(s ...googleapi.Field) *ChangesCreateCall // TODO: Add as needed + } + + ChangesGetCall interface { + // Context(ctx context.Context) *ChangesGetCall // TODO: Add as needed + Do(opts ...googleapi.CallOption) (*Change, error) + // Fields(s ...googleapi.Field) *ChangesGetCall // TODO: Add as needed + // IfNoneMatch(entityTag string) *ChangesGetCall // TODO: Add as needed + } + + ChangesListCall interface { + // Context(ctx context.Context) *ChangesListCall // TODO: Add as needed + Do(opts ...googleapi.CallOption) (*ChangesListResponse, error) + // Fields(s ...googleapi.Field) *ChangesListCall // TODO: Add as needed + // IfNoneMatch(entityTag string) *ChangesListCall // TODO: Add as needed + // MaxResults(maxResults int64) *ChangesListCall // TODO: Add as needed + // PageToken(pageToken string) *ChangesListCall // TODO: Add as needed + // Pages(ctx context.Context, f func(*ChangesListResponse) error) error // TODO: Add as needed + // SortBy(sortBy string) *ChangesListCall // TODO: Add as needed + // SortOrder(sortOrder string) *ChangesListCall // TODO: Add as needed + } + + ChangesListResponse interface { + // Changes() []*Change // TODO: Add as needed + // Kind() string // TODO: Add as needed + // NextPageToken() string // TODO: Add as needed + // ServerResponse() googleapi.ServerResponse // TODO: Add as needed + // ForceSendFields() []string // TODO: Add as needed + } + + ChangesService interface { + // Create(project string, managedZone string, change *Change) *ChangesCreateCall // TODO: Add as needed + Create(project string, managedZone string, change Change) ChangesCreateCall + NewChange(additions, deletions []ResourceRecordSet) Change + + // Get(project string, managedZone string, changeId string) *ChangesGetCall // TODO: Add as needed + // List(project string, managedZone string) *ChangesListCall // TODO: Add as needed + } + + ManagedZone interface { + // CreationTime() string // TODO: Add as needed + // Description() string // TODO: Add as needed + DnsName() string + // Id() uint64 // TODO: Add as needed + // Kind() string // TODO: Add as needed + Name() string + // NameServerSet() string // TODO: Add as needed + // NameServers() []string // TODO: Add as needed + // ServerResponse() googleapi.ServerResponse // TODO: Add as needed + // ForceSendFields() []string // TODO: Add as needed + } + + ManagedZonesCreateCall interface { + // Context(ctx context.Context) *ManagedZonesCreateCall // TODO: Add as needed + Do(opts ...googleapi.CallOption) (ManagedZone, error) + // Fields(s ...googleapi.Field) *ManagedZonesCreateCall // TODO: Add as needed + } + + ManagedZonesDeleteCall interface { + // Context(ctx context.Context) *ManagedZonesDeleteCall // TODO: Add as needed + Do(opts ...googleapi.CallOption) error + // Fields(s ...googleapi.Field) *ManagedZonesDeleteCall // TODO: Add as needed + } + + ManagedZonesGetCall interface { + // Context(ctx context.Context) *ManagedZonesGetCall // TODO: Add as needed + Do(opts ...googleapi.CallOption) (ManagedZone, error) + // Fields(s ...googleapi.Field) *ManagedZonesGetCall // TODO: Add as needed + // IfNoneMatch(entityTag string) *ManagedZonesGetCall // TODO: Add as needed + } + + ManagedZonesListCall interface { + // Context(ctx context.Context) *ManagedZonesListCall // TODO: Add as needed + DnsName(dnsName string) ManagedZonesListCall + Do(opts ...googleapi.CallOption) (ManagedZonesListResponse, error) + // Fields(s ...googleapi.Field) *ManagedZonesListCall // TODO: Add as needed + // IfNoneMatch(entityTag string) *ManagedZonesListCall // TODO: Add as needed + // MaxResults(maxResults int64) *ManagedZonesListCall // TODO: Add as needed + // PageToken(pageToken string) *ManagedZonesListCall // TODO: Add as needed + // Pages(ctx context.Context, f func(*ManagedZonesListResponse) error) error // TODO: Add as needed + } + + ManagedZonesListResponse interface { + // Kind() string // TODO: Add as needed + // ManagedZones() []*ManagedZone // TODO: Add as needed + ManagedZones() []ManagedZone + // NextPageToken string // TODO: Add as needed + // ServerResponse() googleapi.ServerResponse // TODO: Add as needed + // ForceSendFields() []string // TODO: Add as needed + } + + ManagedZonesService interface { + // NewManagedZonesService(s *Service) *ManagedZonesService // TODO: Add to service if needed + Create(project string, managedzone ManagedZone) ManagedZonesCreateCall + Delete(project string, managedZone string) ManagedZonesDeleteCall + Get(project string, managedZone string) ManagedZonesGetCall + List(project string) ManagedZonesListCall + } + + Project interface { + // Id() string // TODO: Add as needed + // Kind() string // TODO: Add as needed + // Number() uint64 // TODO: Add as needed + // Quota() *Quota // TODO: Add as needed + // ServerResponse() googleapi.ServerResponse // TODO: Add as needed + // ForceSendFields() []string // TODO: Add as needed + } + + ProjectsGetCall interface { + // TODO: Add as needed + } + + ProjectsService interface { + // TODO: Add as needed + } + + Quota interface { + // TODO: Add as needed + } + + ResourceRecordSet interface { + // Kind() string // TODO: Add as needed + Name() string + Rrdatas() []string + Ttl() int64 + Type() string + // ForceSendFields []string // TODO: Add as needed + } + + ResourceRecordSetsListCall interface { + // Context(ctx context.Context) *ResourceRecordSetsListCall // TODO: Add as needed + // Do(opts ...googleapi.CallOption) (*ResourceRecordSetsListResponse, error) // TODO: Add as needed + Do(opts ...googleapi.CallOption) (ResourceRecordSetsListResponse, error) + // Fields(s ...googleapi.Field) *ResourceRecordSetsListCall // TODO: Add as needed + // IfNoneMatch(entityTag string) *ResourceRecordSetsListCall // TODO: Add as needed + // MaxResults(maxResults int64) *ResourceRecordSetsListCall // TODO: Add as needed + Name(name string) ResourceRecordSetsListCall + // PageToken(pageToken string) *ResourceRecordSetsListCall // TODO: Add as needed + Type(type_ string) ResourceRecordSetsListCall + } + + ResourceRecordSetsListResponse interface { + // Kind() string // TODO: Add as needed + // NextPageToken() string // TODO: Add as needed + Rrsets() []ResourceRecordSet + // ServerResponse() googleapi.ServerResponse // TODO: Add as needed + // ForceSendFields() []string // TODO: Add as needed + } + + ResourceRecordSetsService interface { + // NewResourceRecordSetsService(s *Service) *ResourceRecordSetsService // TODO: add to service as needed + List(project string, managedZone string) ResourceRecordSetsListCall + NewResourceRecordSet(name string, rrdatas []string, ttl int64, type_ rrstype.RrsType) ResourceRecordSet + } + + Service interface { + // BasePath() string // TODO: Add as needed + // UserAgent() string // TODO: Add as needed + Changes() ChangesService + ManagedZones() ManagedZonesService + Projects() ProjectsService + ResourceRecordSets() ResourceRecordSetsService + } + // New(client *http.Client) (*Service, error) // TODO: Add as needed +) diff --git a/federation/pkg/dnsprovider/providers/google/clouddns/internal/managed_zone.go b/federation/pkg/dnsprovider/providers/google/clouddns/internal/managed_zone.go new file mode 100644 index 00000000000..9336ea090eb --- /dev/null +++ b/federation/pkg/dnsprovider/providers/google/clouddns/internal/managed_zone.go @@ -0,0 +1,34 @@ +/* +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 internal + +import ( + dns "google.golang.org/api/dns/v1" + "k8s.io/kubernetes/federation/pkg/dnsprovider/providers/google/clouddns/internal/interfaces" +) + +var _ interfaces.ManagedZone = ManagedZone{} + +type ManagedZone struct{ impl *dns.ManagedZone } + +func (m ManagedZone) Name() string { + return m.impl.Name +} + +func (m ManagedZone) DnsName() string { + return m.impl.DnsName +} diff --git a/federation/pkg/dnsprovider/providers/google/clouddns/internal/managed_zone_create_call.go b/federation/pkg/dnsprovider/providers/google/clouddns/internal/managed_zone_create_call.go new file mode 100644 index 00000000000..dc7c09e05f5 --- /dev/null +++ b/federation/pkg/dnsprovider/providers/google/clouddns/internal/managed_zone_create_call.go @@ -0,0 +1,32 @@ +/* +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 internal + +import ( + dns "google.golang.org/api/dns/v1" + "google.golang.org/api/googleapi" + "k8s.io/kubernetes/federation/pkg/dnsprovider/providers/google/clouddns/internal/interfaces" +) + +var _ interfaces.ManagedZonesCreateCall = ManagedZonesCreateCall{} + +type ManagedZonesCreateCall struct{ impl *dns.ManagedZonesCreateCall } + +func (call ManagedZonesCreateCall) Do(opts ...googleapi.CallOption) (interfaces.ManagedZone, error) { + m, err := call.impl.Do(opts...) + return &ManagedZone{m}, err +} 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 new file mode 100644 index 00000000000..7bc398c166e --- /dev/null +++ b/federation/pkg/dnsprovider/providers/google/clouddns/internal/managed_zones_delete_call.go @@ -0,0 +1,31 @@ +/* +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 internal + +import ( + dns "google.golang.org/api/dns/v1" + "google.golang.org/api/googleapi" + "k8s.io/kubernetes/federation/pkg/dnsprovider/providers/google/clouddns/internal/interfaces" +) + +var _ interfaces.ManagedZonesDeleteCall = ManagedZonesDeleteCall{} + +type ManagedZonesDeleteCall struct{ impl *dns.ManagedZonesDeleteCall } + +func (call ManagedZonesDeleteCall) Do(opts ...googleapi.CallOption) error { + return call.Do(opts...) +} diff --git a/federation/pkg/dnsprovider/providers/google/clouddns/internal/managed_zones_get_call.go b/federation/pkg/dnsprovider/providers/google/clouddns/internal/managed_zones_get_call.go new file mode 100644 index 00000000000..ca1f5a412ea --- /dev/null +++ b/federation/pkg/dnsprovider/providers/google/clouddns/internal/managed_zones_get_call.go @@ -0,0 +1,32 @@ +/* +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 internal + +import ( + dns "google.golang.org/api/dns/v1" + "google.golang.org/api/googleapi" + "k8s.io/kubernetes/federation/pkg/dnsprovider/providers/google/clouddns/internal/interfaces" +) + +var _ interfaces.ManagedZonesGetCall = ManagedZonesGetCall{} + +type ManagedZonesGetCall struct{ impl *dns.ManagedZonesGetCall } + +func (call ManagedZonesGetCall) Do(opts ...googleapi.CallOption) (interfaces.ManagedZone, error) { + m, err := call.impl.Do(opts...) + return &ManagedZone{m}, err +} diff --git a/federation/pkg/dnsprovider/providers/google/clouddns/internal/managed_zones_list_call.go b/federation/pkg/dnsprovider/providers/google/clouddns/internal/managed_zones_list_call.go new file mode 100644 index 00000000000..6c0ec65ba27 --- /dev/null +++ b/federation/pkg/dnsprovider/providers/google/clouddns/internal/managed_zones_list_call.go @@ -0,0 +1,37 @@ +/* +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 internal + +import ( + dns "google.golang.org/api/dns/v1" + "google.golang.org/api/googleapi" + "k8s.io/kubernetes/federation/pkg/dnsprovider/providers/google/clouddns/internal/interfaces" +) + +var _ interfaces.ManagedZonesListCall = &ManagedZonesListCall{} + +type ManagedZonesListCall struct{ impl *dns.ManagedZonesListCall } + +func (call *ManagedZonesListCall) Do(opts ...googleapi.CallOption) (interfaces.ManagedZonesListResponse, error) { + response, err := call.impl.Do(opts...) + return &ManagedZonesListResponse{response}, err +} + +func (call *ManagedZonesListCall) DnsName(dnsName string) interfaces.ManagedZonesListCall { + call.impl.DnsName(dnsName) + return call +} diff --git a/federation/pkg/dnsprovider/providers/google/clouddns/internal/managed_zones_list_response.go b/federation/pkg/dnsprovider/providers/google/clouddns/internal/managed_zones_list_response.go new file mode 100644 index 00000000000..27b734d9059 --- /dev/null +++ b/federation/pkg/dnsprovider/providers/google/clouddns/internal/managed_zones_list_response.go @@ -0,0 +1,34 @@ +/* +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 internal + +import ( + dns "google.golang.org/api/dns/v1" + "k8s.io/kubernetes/federation/pkg/dnsprovider/providers/google/clouddns/internal/interfaces" +) + +var _ interfaces.ManagedZonesListResponse = &ManagedZonesListResponse{} + +type ManagedZonesListResponse struct{ impl *dns.ManagedZonesListResponse } + +func (response *ManagedZonesListResponse) ManagedZones() []interfaces.ManagedZone { + zones := make([]interfaces.ManagedZone, len(response.impl.ManagedZones)) + for i, z := range response.impl.ManagedZones { + zones[i] = &ManagedZone{z} + } + return zones +} 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 new file mode 100644 index 00000000000..91ea5cce008 --- /dev/null +++ b/federation/pkg/dnsprovider/providers/google/clouddns/internal/managed_zones_service.go @@ -0,0 +1,42 @@ +/* +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 internal + +import ( + dns "google.golang.org/api/dns/v1" + "k8s.io/kubernetes/federation/pkg/dnsprovider/providers/google/clouddns/internal/interfaces" +) + +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)} +} + +func (m *ManagedZonesService) Delete(project, managedZone string) interfaces.ManagedZonesDeleteCall { + return &ManagedZonesDeleteCall{m.impl.Delete(project, managedZone)} +} + +func (m *ManagedZonesService) Get(project, managedZone string) interfaces.ManagedZonesGetCall { + return &ManagedZonesGetCall{m.impl.Get(project, managedZone)} +} + +func (m *ManagedZonesService) List(project string) interfaces.ManagedZonesListCall { + return &ManagedZonesListCall{m.impl.List(project)} +} diff --git a/federation/pkg/dnsprovider/providers/google/clouddns/internal/rrset.go b/federation/pkg/dnsprovider/providers/google/clouddns/internal/rrset.go new file mode 100644 index 00000000000..5925cbe51e6 --- /dev/null +++ b/federation/pkg/dnsprovider/providers/google/clouddns/internal/rrset.go @@ -0,0 +1,31 @@ +/* +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 internal + +import ( + dns "google.golang.org/api/dns/v1" + "k8s.io/kubernetes/federation/pkg/dnsprovider/providers/google/clouddns/internal/interfaces" +) + +var _ interfaces.ResourceRecordSet = ResourceRecordSet{} + +type ResourceRecordSet struct{ impl *dns.ResourceRecordSet } + +func (r ResourceRecordSet) Name() string { return r.impl.Name } +func (r ResourceRecordSet) Rrdatas() []string { return r.impl.Rrdatas } +func (r ResourceRecordSet) Ttl() int64 { return r.impl.Ttl } +func (r ResourceRecordSet) Type() string { return r.impl.Type } diff --git a/federation/pkg/dnsprovider/providers/google/clouddns/internal/rrsets_list_call.go b/federation/pkg/dnsprovider/providers/google/clouddns/internal/rrsets_list_call.go new file mode 100644 index 00000000000..fc30be6d768 --- /dev/null +++ b/federation/pkg/dnsprovider/providers/google/clouddns/internal/rrsets_list_call.go @@ -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. +*/ + +package internal + +import ( + dns "google.golang.org/api/dns/v1" + "google.golang.org/api/googleapi" + "k8s.io/kubernetes/federation/pkg/dnsprovider/providers/google/clouddns/internal/interfaces" +) + +var _ interfaces.ResourceRecordSetsListCall = &ResourceRecordSetsListCall{} + +type ResourceRecordSetsListCall struct { + impl *dns.ResourceRecordSetsListCall +} + +func (call *ResourceRecordSetsListCall) Do(opts ...googleapi.CallOption) (interfaces.ResourceRecordSetsListResponse, error) { + response, err := call.impl.Do(opts...) + return &ResourceRecordSetsListResponse{response}, err +} + +func (call *ResourceRecordSetsListCall) Name(name string) interfaces.ResourceRecordSetsListCall { + call.impl.Name(name) + return call +} + +func (call *ResourceRecordSetsListCall) Type(type_ string) interfaces.ResourceRecordSetsListCall { + call.impl.Type(type_) + return call +} diff --git a/federation/pkg/dnsprovider/providers/google/clouddns/internal/rrsets_list_response.go b/federation/pkg/dnsprovider/providers/google/clouddns/internal/rrsets_list_response.go new file mode 100644 index 00000000000..af4aa87e252 --- /dev/null +++ b/federation/pkg/dnsprovider/providers/google/clouddns/internal/rrsets_list_response.go @@ -0,0 +1,37 @@ +/* +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 internal + +import ( + dns "google.golang.org/api/dns/v1" + "k8s.io/kubernetes/federation/pkg/dnsprovider/providers/google/clouddns/internal/interfaces" +) + +var _ interfaces.ResourceRecordSetsListResponse = &ResourceRecordSetsListResponse{} + +type ResourceRecordSetsListResponse struct { + impl *dns.ResourceRecordSetsListResponse +} + +func (response *ResourceRecordSetsListResponse) Rrsets() []interfaces.ResourceRecordSet { + rrsets := make([]interfaces.ResourceRecordSet, len(response.impl.Rrsets)) + for i, rrset := range response.impl.Rrsets { + rrsets[i] = &ResourceRecordSet{rrset} + } + return rrsets + +} diff --git a/federation/pkg/dnsprovider/providers/google/clouddns/internal/rrsets_service.go b/federation/pkg/dnsprovider/providers/google/clouddns/internal/rrsets_service.go new file mode 100644 index 00000000000..ba1832cd451 --- /dev/null +++ b/federation/pkg/dnsprovider/providers/google/clouddns/internal/rrsets_service.go @@ -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 internal + +import ( + dns "google.golang.org/api/dns/v1" + "k8s.io/kubernetes/federation/pkg/dnsprovider/providers/google/clouddns/internal/interfaces" + "k8s.io/kubernetes/federation/pkg/dnsprovider/rrstype" +) + +var _ interfaces.ResourceRecordSetsService = &ResourceRecordSetsService{} + +type ResourceRecordSetsService struct { + impl *dns.ResourceRecordSetsService +} + +func (service ResourceRecordSetsService) List(project string, managedZone string) interfaces.ResourceRecordSetsListCall { + return &ResourceRecordSetsListCall{service.impl.List(project, managedZone)} +} + +func (service ResourceRecordSetsService) NewResourceRecordSet(name string, rrdatas []string, ttl int64, type_ rrstype.RrsType) interfaces.ResourceRecordSet { + rrset := dns.ResourceRecordSet{Name: name, Rrdatas: rrdatas, Ttl: ttl, Type: string(type_)} + return &ResourceRecordSet{&rrset} +} diff --git a/federation/pkg/dnsprovider/providers/google/clouddns/internal/service.go b/federation/pkg/dnsprovider/providers/google/clouddns/internal/service.go new file mode 100644 index 00000000000..d3854fb6225 --- /dev/null +++ b/federation/pkg/dnsprovider/providers/google/clouddns/internal/service.go @@ -0,0 +1,48 @@ +/* +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 internal + +import ( + dns "google.golang.org/api/dns/v1" + "k8s.io/kubernetes/federation/pkg/dnsprovider/providers/google/clouddns/internal/interfaces" +) + +var _ interfaces.Service = &Service{} + +type Service struct { + impl *dns.Service +} + +func NewService(service *dns.Service) *Service { + return &Service{service} +} + +func (s *Service) Changes() interfaces.ChangesService { + return &ChangesService{s.impl.Changes} +} + +func (s *Service) ManagedZones() interfaces.ManagedZonesService { + return &ManagedZonesService{s.impl.ManagedZones} +} + +func (s *Service) Projects() interfaces.ProjectsService { + return &ProjectsService{s.impl.Projects} +} + +func (s *Service) ResourceRecordSets() interfaces.ResourceRecordSetsService { + return &ResourceRecordSetsService{s.impl.ResourceRecordSets} +} diff --git a/federation/pkg/dnsprovider/providers/google/clouddns/internal/stubs/change.go b/federation/pkg/dnsprovider/providers/google/clouddns/internal/stubs/change.go new file mode 100644 index 00000000000..2c103974974 --- /dev/null +++ b/federation/pkg/dnsprovider/providers/google/clouddns/internal/stubs/change.go @@ -0,0 +1,35 @@ +/* +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 stubs + +import "k8s.io/kubernetes/federation/pkg/dnsprovider/providers/google/clouddns/internal/interfaces" + +var _ interfaces.Change = &Change{} + +type Change struct { + Service *ChangesService + Additions_ []interfaces.ResourceRecordSet + Deletions_ []interfaces.ResourceRecordSet +} + +func (c *Change) Additions() (rrsets []interfaces.ResourceRecordSet) { + return c.Additions_ +} + +func (c *Change) Deletions() (rrsets []interfaces.ResourceRecordSet) { + return c.Deletions_ +} diff --git a/federation/pkg/dnsprovider/providers/google/clouddns/internal/stubs/changes_create_call.go b/federation/pkg/dnsprovider/providers/google/clouddns/internal/stubs/changes_create_call.go new file mode 100644 index 00000000000..6e81506cf39 --- /dev/null +++ b/federation/pkg/dnsprovider/providers/google/clouddns/internal/stubs/changes_create_call.go @@ -0,0 +1,68 @@ +/* +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 stubs + +import ( + "fmt" + + "google.golang.org/api/googleapi" + "k8s.io/kubernetes/federation/pkg/dnsprovider/providers/google/clouddns/internal/interfaces" +) + +var _ interfaces.ChangesCreateCall = ChangesCreateCall{} + +type ChangesCreateCall struct { + Service *ChangesService + Project string + Zone string + Change interfaces.Change + Error error // Use this to over-ride response if necessary +} + +func hashKey(set interfaces.ResourceRecordSet) string { + return fmt.Sprintf("%s-%d-%s", set.Name(), set.Ttl(), string(set.Type())) +} + +func (c ChangesCreateCall) Do(opts ...googleapi.CallOption) (interfaces.Change, error) { + if c.Error != nil { + return nil, c.Error + } + zone := (c.Service.Service.ManagedZones_.Impl[c.Project][c.Zone]).(*ManagedZone) + rrsets := map[string]int{} // Simple mechanism to detect dupes and missing rrsets before committing - stores index+1 + for i, set := range zone.Rrsets { + rrsets[hashKey(set)] = i + 1 + } + for _, add := range c.Change.Additions() { + if rrsets[hashKey(add)] > 0 { + return nil, fmt.Errorf("Attempt to insert duplicate rrset %v", add) + } + } + for _, del := range c.Change.Deletions() { + if !(rrsets[hashKey(del)] > 0) { + return nil, fmt.Errorf("Attempt to delete non-existent rrset %v", del) + } + } + for _, add := range c.Change.Additions() { + zone.Rrsets = append(zone.Rrsets, *(add.(*ResourceRecordSet))) + } + for _, del := range c.Change.Deletions() { + zone.Rrsets = append( + zone.Rrsets[:rrsets[hashKey(del)]-1], + zone.Rrsets[rrsets[hashKey(del)]:]...) + } + return c.Change, nil +} diff --git a/federation/pkg/dnsprovider/providers/google/clouddns/internal/stubs/changes_service.go b/federation/pkg/dnsprovider/providers/google/clouddns/internal/stubs/changes_service.go new file mode 100644 index 00000000000..1f764890722 --- /dev/null +++ b/federation/pkg/dnsprovider/providers/google/clouddns/internal/stubs/changes_service.go @@ -0,0 +1,33 @@ +/* +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 stubs + +import "k8s.io/kubernetes/federation/pkg/dnsprovider/providers/google/clouddns/internal/interfaces" + +var _ interfaces.ChangesService = &ChangesService{} + +type ChangesService struct { + Service *Service +} + +func (c *ChangesService) Create(project string, managedZone string, change interfaces.Change) interfaces.ChangesCreateCall { + return &ChangesCreateCall{c, project, managedZone, change, nil} +} + +func (c *ChangesService) NewChange(additions, deletions []interfaces.ResourceRecordSet) interfaces.Change { + return &Change{c, additions, deletions} +} diff --git a/federation/pkg/dnsprovider/providers/google/clouddns/internal/stubs/clouddns.go b/federation/pkg/dnsprovider/providers/google/clouddns/internal/stubs/clouddns.go new file mode 100644 index 00000000000..2d8a206dcac --- /dev/null +++ b/federation/pkg/dnsprovider/providers/google/clouddns/internal/stubs/clouddns.go @@ -0,0 +1,33 @@ +/* +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 stubs + +// Implementation of internal/interfaces/* on top of Google Cloud DNS API. +// See https://godoc.org/google.golang.org/api/dns/v1 for details +// This facilitates stubbing out Google Cloud DNS for unit testing. +// Only the parts of the API that we use are included. +// Others can be added as needed. + +import dns "google.golang.org/api/dns/v1" + +type ( + // TODO: We dont' need these yet, so they remain unimplemented. Add later as required. + Project struct{ impl *dns.Project } + ProjectsGetCall struct{ impl *dns.ProjectsGetCall } + ProjectsService struct{ impl *dns.ProjectsService } + Quota struct{ impl *dns.Quota } +) diff --git a/federation/pkg/dnsprovider/providers/google/clouddns/internal/stubs/managed_zone.go b/federation/pkg/dnsprovider/providers/google/clouddns/internal/stubs/managed_zone.go new file mode 100644 index 00000000000..4391efd31af --- /dev/null +++ b/federation/pkg/dnsprovider/providers/google/clouddns/internal/stubs/managed_zone.go @@ -0,0 +1,35 @@ +/* +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 stubs + +import "k8s.io/kubernetes/federation/pkg/dnsprovider/providers/google/clouddns/internal/interfaces" + +var _ interfaces.ManagedZone = ManagedZone{} + +type ManagedZone struct { + Service *ManagedZonesService + Name_ string + Rrsets []ResourceRecordSet +} + +func (m ManagedZone) Name() string { + return m.Name_ +} + +func (m ManagedZone) DnsName() string { + return m.Name_ // Don't bother storing a separate DNS name +} diff --git a/federation/pkg/dnsprovider/providers/google/clouddns/internal/stubs/managed_zone_create_call.go b/federation/pkg/dnsprovider/providers/google/clouddns/internal/stubs/managed_zone_create_call.go new file mode 100644 index 00000000000..fe4ef7cc882 --- /dev/null +++ b/federation/pkg/dnsprovider/providers/google/clouddns/internal/stubs/managed_zone_create_call.go @@ -0,0 +1,51 @@ +/* +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 stubs + +import ( + "fmt" + + "google.golang.org/api/googleapi" + "k8s.io/kubernetes/federation/pkg/dnsprovider/providers/google/clouddns/internal/interfaces" +) + +var _ interfaces.ManagedZonesCreateCall = ManagedZonesCreateCall{} + +type ManagedZonesCreateCall struct { + Error *error // Use to override response for testing + Service *ManagedZonesService + Project string + ManagedZone interfaces.ManagedZone +} + +func (call ManagedZonesCreateCall) Do(opts ...googleapi.CallOption) (interfaces.ManagedZone, error) { + if call.Error != nil { + return nil, *call.Error + } + if call.Service.Impl[call.Project][call.ManagedZone.DnsName()] != nil { + return nil, fmt.Errorf("Error - attempt to create duplicate zone %s in project %s.", + call.ManagedZone.DnsName(), call.Project) + } + if call.Service.Impl == nil { + call.Service.Impl = map[string]map[string]interfaces.ManagedZone{} + } + if call.Service.Impl[call.Project] == nil { + call.Service.Impl[call.Project] = map[string]interfaces.ManagedZone{} + } + call.Service.Impl[call.Project][call.ManagedZone.DnsName()] = call.ManagedZone + return call.ManagedZone, nil +} diff --git a/federation/pkg/dnsprovider/providers/google/clouddns/internal/stubs/managed_zones_delete_call.go b/federation/pkg/dnsprovider/providers/google/clouddns/internal/stubs/managed_zones_delete_call.go new file mode 100644 index 00000000000..e63fb74da26 --- /dev/null +++ b/federation/pkg/dnsprovider/providers/google/clouddns/internal/stubs/managed_zones_delete_call.go @@ -0,0 +1,52 @@ +/* +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 stubs + +import ( + "fmt" + + "google.golang.org/api/googleapi" + "k8s.io/kubernetes/federation/pkg/dnsprovider/providers/google/clouddns/internal/interfaces" +) + +var _ interfaces.ManagedZonesDeleteCall = ManagedZonesDeleteCall{} + +type ManagedZonesDeleteCall struct { + Service *ManagedZonesService + Project string + ZoneName string + Error *error // Use this to overide response for testing if required +} + +func (call ManagedZonesDeleteCall) Do(opts ...googleapi.CallOption) error { + if call.Error != nil { // Return the override value + return *call.Error + } else { // Just try to delete it from the in-memory array. + project, ok := call.Service.Impl[call.Project] + if ok { + zone, ok := project[call.ZoneName] + if ok { + delete(project, zone.Name()) + return nil + } else { + return fmt.Errorf("Failed to find zone %s in project %s to delete it", call.ZoneName, call.Project) + } + } else { + return fmt.Errorf("Failed to find project %s to delete zone %s from it", call.Project, call.ZoneName) + } + } +} diff --git a/federation/pkg/dnsprovider/providers/google/clouddns/internal/stubs/managed_zones_get_call.go b/federation/pkg/dnsprovider/providers/google/clouddns/internal/stubs/managed_zones_get_call.go new file mode 100644 index 00000000000..6fe75c04a83 --- /dev/null +++ b/federation/pkg/dnsprovider/providers/google/clouddns/internal/stubs/managed_zones_get_call.go @@ -0,0 +1,41 @@ +/* +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 stubs + +import ( + "google.golang.org/api/googleapi" + "k8s.io/kubernetes/federation/pkg/dnsprovider/providers/google/clouddns/internal/interfaces" +) + +var _ interfaces.ManagedZonesGetCall = ManagedZonesGetCall{} + +type ManagedZonesGetCall struct { + Service *ManagedZonesService + Project string + ZoneName string + Response interfaces.ManagedZone // Use this to overide response if required + Error *error // Use this to overide response if required + DnsName_ string +} + +func (call ManagedZonesGetCall) Do(opts ...googleapi.CallOption) (interfaces.ManagedZone, error) { + if call.Response != nil { + return call.Response, *call.Error + } else { + return call.Service.Impl[call.Project][call.ZoneName], nil + } +} diff --git a/federation/pkg/dnsprovider/providers/google/clouddns/internal/stubs/managed_zones_list_call.go b/federation/pkg/dnsprovider/providers/google/clouddns/internal/stubs/managed_zones_list_call.go new file mode 100644 index 00000000000..d57815c79cd --- /dev/null +++ b/federation/pkg/dnsprovider/providers/google/clouddns/internal/stubs/managed_zones_list_call.go @@ -0,0 +1,58 @@ +/* +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 stubs + +import ( + "fmt" + + "google.golang.org/api/googleapi" + "k8s.io/kubernetes/federation/pkg/dnsprovider/providers/google/clouddns/internal/interfaces" +) + +var _ interfaces.ManagedZonesListCall = &ManagedZonesListCall{} + +type ManagedZonesListCall struct { + Service *ManagedZonesService + Project string + Response *interfaces.ManagedZonesListResponse // Use this to overide response if required + Error *error // Use this to overide response if required + DnsName_ string +} + +func (call *ManagedZonesListCall) Do(opts ...googleapi.CallOption) (interfaces.ManagedZonesListResponse, error) { + if call.Response != nil { + return *call.Response, *call.Error + } else { + proj, projectFound := call.Service.Impl[call.Project] + if !projectFound { + return nil, fmt.Errorf("Project %s not found.", call.Project) + } + if call.DnsName_ != "" { + return &ManagedZonesListResponse{[]interfaces.ManagedZone{proj[call.DnsName_]}}, nil + } + list := []interfaces.ManagedZone{} + for _, zone := range proj { + list = append(list, zone) + } + return &ManagedZonesListResponse{list}, nil + } +} + +func (call *ManagedZonesListCall) DnsName(dnsName string) interfaces.ManagedZonesListCall { + call.DnsName_ = dnsName + return call +} diff --git a/federation/pkg/dnsprovider/providers/google/clouddns/internal/stubs/managed_zones_list_response.go b/federation/pkg/dnsprovider/providers/google/clouddns/internal/stubs/managed_zones_list_response.go new file mode 100644 index 00000000000..b949612f0c7 --- /dev/null +++ b/federation/pkg/dnsprovider/providers/google/clouddns/internal/stubs/managed_zones_list_response.go @@ -0,0 +1,27 @@ +/* +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 stubs + +import "k8s.io/kubernetes/federation/pkg/dnsprovider/providers/google/clouddns/internal/interfaces" + +var _ interfaces.ManagedZonesListResponse = &ManagedZonesListResponse{} + +type ManagedZonesListResponse struct{ ManagedZones_ []interfaces.ManagedZone } + +func (response *ManagedZonesListResponse) ManagedZones() []interfaces.ManagedZone { + return response.ManagedZones_ +} diff --git a/federation/pkg/dnsprovider/providers/google/clouddns/internal/stubs/managed_zones_service.go b/federation/pkg/dnsprovider/providers/google/clouddns/internal/stubs/managed_zones_service.go new file mode 100644 index 00000000000..85b0087ea6d --- /dev/null +++ b/federation/pkg/dnsprovider/providers/google/clouddns/internal/stubs/managed_zones_service.go @@ -0,0 +1,41 @@ +/* +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 stubs + +import "k8s.io/kubernetes/federation/pkg/dnsprovider/providers/google/clouddns/internal/interfaces" + +var _ interfaces.ManagedZonesService = &ManagedZonesService{} + +type ManagedZonesService struct { + Impl map[string]map[string]interfaces.ManagedZone +} + +func (m *ManagedZonesService) Create(project string, managedzone interfaces.ManagedZone) interfaces.ManagedZonesCreateCall { + return &ManagedZonesCreateCall{nil, m, project, managedzone.(*ManagedZone)} +} + +func (m *ManagedZonesService) Delete(project string, managedZone string) interfaces.ManagedZonesDeleteCall { + return &ManagedZonesDeleteCall{m, project, managedZone, nil} +} + +func (m *ManagedZonesService) Get(project string, managedZone string) interfaces.ManagedZonesGetCall { + return &ManagedZonesGetCall{m, project, managedZone, nil, nil, ""} +} + +func (m *ManagedZonesService) List(project string) interfaces.ManagedZonesListCall { + return &ManagedZonesListCall{m, project, nil, nil, ""} +} diff --git a/federation/pkg/dnsprovider/providers/google/clouddns/internal/stubs/rrset.go b/federation/pkg/dnsprovider/providers/google/clouddns/internal/stubs/rrset.go new file mode 100644 index 00000000000..bef4de8c920 --- /dev/null +++ b/federation/pkg/dnsprovider/providers/google/clouddns/internal/stubs/rrset.go @@ -0,0 +1,33 @@ +/* +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 stubs + +import "k8s.io/kubernetes/federation/pkg/dnsprovider/providers/google/clouddns/internal/interfaces" + +var _ interfaces.ResourceRecordSet = ResourceRecordSet{} + +type ResourceRecordSet struct { + Name_ string + Rrdatas_ []string + Ttl_ int64 + Type_ string +} + +func (r ResourceRecordSet) Name() string { return r.Name_ } +func (r ResourceRecordSet) Rrdatas() []string { return r.Rrdatas_ } +func (r ResourceRecordSet) Ttl() int64 { return r.Ttl_ } +func (r ResourceRecordSet) Type() string { return r.Type_ } diff --git a/federation/pkg/dnsprovider/providers/google/clouddns/internal/stubs/rrsets_list_call.go b/federation/pkg/dnsprovider/providers/google/clouddns/internal/stubs/rrsets_list_call.go new file mode 100644 index 00000000000..0bdbafcc54d --- /dev/null +++ b/federation/pkg/dnsprovider/providers/google/clouddns/internal/stubs/rrsets_list_call.go @@ -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 stubs + +import ( + "google.golang.org/api/googleapi" + "k8s.io/kubernetes/federation/pkg/dnsprovider/providers/google/clouddns/internal/interfaces" +) + +var _ interfaces.ResourceRecordSetsListCall = &ResourceRecordSetsListCall{} + +type ResourceRecordSetsListCall struct { + Response_ *ResourceRecordSetsListResponse + Err_ error + Name_ string + Type_ string +} + +func (call *ResourceRecordSetsListCall) Do(opts ...googleapi.CallOption) (interfaces.ResourceRecordSetsListResponse, error) { + return call.Response_, call.Err_ +} + +func (call *ResourceRecordSetsListCall) Name(name string) interfaces.ResourceRecordSetsListCall { + call.Name_ = name + return call +} + +func (call *ResourceRecordSetsListCall) Type(type_ string) interfaces.ResourceRecordSetsListCall { + call.Type_ = type_ + return call +} diff --git a/federation/pkg/dnsprovider/providers/google/clouddns/internal/stubs/rrsets_list_response.go b/federation/pkg/dnsprovider/providers/google/clouddns/internal/stubs/rrsets_list_response.go new file mode 100644 index 00000000000..0e0b20a7f78 --- /dev/null +++ b/federation/pkg/dnsprovider/providers/google/clouddns/internal/stubs/rrsets_list_response.go @@ -0,0 +1,29 @@ +/* +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 stubs + +import "k8s.io/kubernetes/federation/pkg/dnsprovider/providers/google/clouddns/internal/interfaces" + +var _ interfaces.ResourceRecordSetsListResponse = &ResourceRecordSetsListResponse{} + +type ResourceRecordSetsListResponse struct { + impl []interfaces.ResourceRecordSet +} + +func (response *ResourceRecordSetsListResponse) Rrsets() []interfaces.ResourceRecordSet { + return response.impl +} diff --git a/federation/pkg/dnsprovider/providers/google/clouddns/internal/stubs/rrsets_service.go b/federation/pkg/dnsprovider/providers/google/clouddns/internal/stubs/rrsets_service.go new file mode 100644 index 00000000000..753f31e42c3 --- /dev/null +++ b/federation/pkg/dnsprovider/providers/google/clouddns/internal/stubs/rrsets_service.go @@ -0,0 +1,58 @@ +/* +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 stubs + +import ( + "fmt" + + "k8s.io/kubernetes/federation/pkg/dnsprovider/providers/google/clouddns/internal/interfaces" + "k8s.io/kubernetes/federation/pkg/dnsprovider/rrstype" +) + +var _ interfaces.ResourceRecordSetsService = &ResourceRecordSetsService{} + +type ResourceRecordSetsService struct { + Service *Service + ListCall interfaces.ResourceRecordSetsListCall // Use to override response if reqired for testing +} + +func (s ResourceRecordSetsService) List(project string, managedZone string) interfaces.ResourceRecordSetsListCall { + if s.ListCall != nil { + return s.ListCall + } + p := s.Service.ManagedZones_.Impl[project] + if p == nil { + return &ResourceRecordSetsListCall{Err_: fmt.Errorf("Project not found: %s", project)} + } + z := s.Service.ManagedZones_.Impl[project][managedZone] + if z == nil { + return &ResourceRecordSetsListCall{ + Err_: fmt.Errorf("Zone %s not found in project %s", managedZone, project), + } + } + zone := s.Service.ManagedZones_.Impl[project][managedZone].(*ManagedZone) + response := &ResourceRecordSetsListResponse{} + for _, set := range zone.Rrsets { + response.impl = append(response.impl, set) + } + return &ResourceRecordSetsListCall{Response_: response} +} + +func (service ResourceRecordSetsService) NewResourceRecordSet(name string, rrdatas []string, ttl int64, type_ rrstype.RrsType) interfaces.ResourceRecordSet { + rrset := ResourceRecordSet{Name_: name, Rrdatas_: rrdatas, Ttl_: ttl, Type_: string(type_)} + return &rrset +} diff --git a/federation/pkg/dnsprovider/providers/google/clouddns/internal/stubs/service.go b/federation/pkg/dnsprovider/providers/google/clouddns/internal/stubs/service.go new file mode 100644 index 00000000000..ac7c48367a1 --- /dev/null +++ b/federation/pkg/dnsprovider/providers/google/clouddns/internal/stubs/service.go @@ -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 stubs + +import "k8s.io/kubernetes/federation/pkg/dnsprovider/providers/google/clouddns/internal/interfaces" + +var _ interfaces.Service = &Service{} + +type Service struct { + Changes_ *ChangesService + ManagedZones_ *ManagedZonesService + Projects_ *ProjectsService + Rrsets_ *ResourceRecordSetsService +} + +func NewService() *Service { + s := &Service{} + s.Changes_ = &ChangesService{s} + s.ManagedZones_ = &ManagedZonesService{} + s.Projects_ = &ProjectsService{} + s.Rrsets_ = &ResourceRecordSetsService{s, nil} + return s +} + +func (s *Service) Changes() interfaces.ChangesService { + return s.Changes_ +} + +func (s *Service) ManagedZones() interfaces.ManagedZonesService { + return s.ManagedZones_ +} + +func (s *Service) Projects() interfaces.ProjectsService { + return s.Projects_ +} + +func (s *Service) ResourceRecordSets() interfaces.ResourceRecordSetsService { + return s.Rrsets_ +} diff --git a/federation/pkg/dnsprovider/providers/google/clouddns/rrset.go b/federation/pkg/dnsprovider/providers/google/clouddns/rrset.go new file mode 100644 index 00000000000..40176b35706 --- /dev/null +++ b/federation/pkg/dnsprovider/providers/google/clouddns/rrset.go @@ -0,0 +1,43 @@ +/* +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 clouddns + +import ( + "k8s.io/kubernetes/federation/pkg/dnsprovider/providers/google/clouddns/internal/interfaces" + "k8s.io/kubernetes/federation/pkg/dnsprovider/rrstype" +) + +type ResourceRecordSet struct { + impl interfaces.ResourceRecordSet + rrsets *ResourceRecordSets +} + +func (rrset ResourceRecordSet) Name() string { + return rrset.impl.Name() +} + +func (rrset ResourceRecordSet) Rrdatas() []string { + return rrset.impl.Rrdatas() +} + +func (rrset ResourceRecordSet) Ttl() int64 { + return rrset.impl.Ttl() +} + +func (rrset ResourceRecordSet) Type() rrstype.RrsType { + return rrstype.RrsType(rrset.impl.Type()) +} diff --git a/federation/pkg/dnsprovider/providers/google/clouddns/rrsets.go b/federation/pkg/dnsprovider/providers/google/clouddns/rrsets.go new file mode 100644 index 00000000000..3a03820ef33 --- /dev/null +++ b/federation/pkg/dnsprovider/providers/google/clouddns/rrsets.go @@ -0,0 +1,80 @@ +/* +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 clouddns + +import ( + "fmt" + + "k8s.io/kubernetes/federation/pkg/dnsprovider" + "k8s.io/kubernetes/federation/pkg/dnsprovider/providers/google/clouddns/internal/interfaces" + "k8s.io/kubernetes/federation/pkg/dnsprovider/rrstype" +) + +type ResourceRecordSets struct { + zone *Zone + impl interfaces.ResourceRecordSetsService +} + +func (rrsets ResourceRecordSets) List() ([]dnsprovider.ResourceRecordSet, error) { + response, err := rrsets.impl.List(rrsets.project(), rrsets.zone.impl.Name()).Do() + if err != nil { + return nil, err + } + list := make([]dnsprovider.ResourceRecordSet, len(response.Rrsets())) + for i, rrset := range response.Rrsets() { + list[i] = &ResourceRecordSet{rrset, &rrsets} + } + return list, nil +} + +func (rrsets ResourceRecordSets) Add(rrset dnsprovider.ResourceRecordSet) (dnsprovider.ResourceRecordSet, error) { + service := rrsets.zone.zones.interface_.service.Changes() + additions := []interfaces.ResourceRecordSet{rrset.(*ResourceRecordSet).impl} + change := service.NewChange(additions, []interfaces.ResourceRecordSet{}) + newChange, err := service.Create(rrsets.project(), rrsets.zone.impl.Name(), change).Do() + if err != nil { + return nil, err + } + newAdditions := newChange.Additions() + if len(newAdditions) != len(additions) { + return nil, fmt.Errorf("Internal error when adding resource record set. Call succeeded but number of records returned is incorrect. Records sent=%d, records returned=%d, record set:%v", len(additions), len(newAdditions), rrset) + } + return ResourceRecordSet{newChange.Additions()[0], &rrsets}, nil +} + +func (rrsets ResourceRecordSets) Remove(rrset dnsprovider.ResourceRecordSet) error { + service := rrsets.zone.zones.interface_.service.Changes() + deletions := []interfaces.ResourceRecordSet{rrset.(ResourceRecordSet).impl} + change := service.NewChange([]interfaces.ResourceRecordSet{}, deletions) + newChange, err := service.Create(rrsets.project(), rrsets.zone.impl.Name(), change).Do() + if err != nil { + return err + } + newDeletions := newChange.Deletions() + if len(newDeletions) != len(deletions) { + return fmt.Errorf("Internal error when deleting resource record set. Call succeeded but number of records returned is incorrect. Records sent=%d, records returned=%d, record set:%v", len(deletions), len(newDeletions), rrset) + } + return nil +} + +func (rrsets ResourceRecordSets) New(name string, rrdatas []string, ttl int64, rrstype rrstype.RrsType) dnsprovider.ResourceRecordSet { + return &ResourceRecordSet{rrsets.impl.NewResourceRecordSet(name, rrdatas, ttl, rrstype), &rrsets} +} + +func (rrsets ResourceRecordSets) project() string { + return rrsets.zone.project() +} diff --git a/federation/pkg/dnsprovider/providers/google/clouddns/zone.go b/federation/pkg/dnsprovider/providers/google/clouddns/zone.go new file mode 100644 index 00000000000..824df344c36 --- /dev/null +++ b/federation/pkg/dnsprovider/providers/google/clouddns/zone.go @@ -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 clouddns + +import ( + "k8s.io/kubernetes/federation/pkg/dnsprovider" + "k8s.io/kubernetes/federation/pkg/dnsprovider/providers/google/clouddns/internal/interfaces" +) + +type Zone struct { + impl interfaces.ManagedZone + zones *Zones +} + +func (zone *Zone) Name() string { + return zone.impl.DnsName() +} + +func (zone *Zone) ResourceRecordSets() (dnsprovider.ResourceRecordSets, bool) { + return &ResourceRecordSets{zone, zone.zones.interface_.service.ResourceRecordSets()}, true +} + +func (zone Zone) project() string { + return zone.zones.project() +} diff --git a/federation/pkg/dnsprovider/providers/google/clouddns/zones.go b/federation/pkg/dnsprovider/providers/google/clouddns/zones.go new file mode 100644 index 00000000000..3a76f535d7d --- /dev/null +++ b/federation/pkg/dnsprovider/providers/google/clouddns/zones.go @@ -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. +*/ + +package clouddns + +import ( + "k8s.io/kubernetes/federation/pkg/dnsprovider" + "k8s.io/kubernetes/federation/pkg/dnsprovider/providers/google/clouddns/internal/interfaces" +) + +type Zones struct { + impl interfaces.ManagedZonesService + interface_ *Interface +} + +func (zones Zones) List() ([]dnsprovider.Zone, error) { + response, err := zones.impl.List(zones.project()).Do() + if err != nil { + return []dnsprovider.Zone{}, nil + } + managedZones := response.ManagedZones() + zoneList := make([]dnsprovider.Zone, len(managedZones)) + for i, zone := range managedZones { + zoneList[i] = &Zone{zone, &zones} + } + return zoneList, nil +} + +func (zones Zones) project() string { + return zones.interface_.project() +} diff --git a/federation/pkg/dnsprovider/rrstype/rrstype.go b/federation/pkg/dnsprovider/rrstype/rrstype.go new file mode 100644 index 00000000000..414c88f7f18 --- /dev/null +++ b/federation/pkg/dnsprovider/rrstype/rrstype.go @@ -0,0 +1,27 @@ +/* +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 rrstype + +type ( + RrsType string +) + +const ( + A = RrsType("A") + CNAME = RrsType("CNAME") + // TODO: Add other types as required +) diff --git a/pkg/cloudprovider/providers/gce/gce.go b/pkg/cloudprovider/providers/gce/gce.go index 20505d7098e..6e030345e67 100644 --- a/pkg/cloudprovider/providers/gce/gce.go +++ b/pkg/cloudprovider/providers/gce/gce.go @@ -28,6 +28,8 @@ import ( "strings" "time" + "gopkg.in/gcfg.v1" + "k8s.io/kubernetes/pkg/api" "k8s.io/kubernetes/pkg/api/service" "k8s.io/kubernetes/pkg/api/unversioned" @@ -47,7 +49,6 @@ import ( container "google.golang.org/api/container/v1" "google.golang.org/api/googleapi" "google.golang.org/cloud/compute/metadata" - "gopkg.in/gcfg.v1" ) const ( @@ -252,7 +253,7 @@ func newGCECloud(config io.Reader) (*GCECloud, error) { } } if cfg.Global.TokenURL != "" { - tokenSource = newAltTokenSource(cfg.Global.TokenURL, cfg.Global.TokenBody) + tokenSource = NewAltTokenSource(cfg.Global.TokenURL, cfg.Global.TokenBody) } nodeTags = cfg.Global.NodeTags if cfg.Global.Multizone { diff --git a/pkg/cloudprovider/providers/gce/token_source.go b/pkg/cloudprovider/providers/gce/token_source.go index 70f3c987dca..20028c02c6b 100644 --- a/pkg/cloudprovider/providers/gce/token_source.go +++ b/pkg/cloudprovider/providers/gce/token_source.go @@ -57,14 +57,14 @@ func init() { prometheus.MustRegister(getTokenFailCounter) } -type altTokenSource struct { +type AltTokenSource struct { oauthClient *http.Client tokenURL string tokenBody string throttle flowcontrol.RateLimiter } -func (a *altTokenSource) Token() (*oauth2.Token, error) { +func (a *AltTokenSource) Token() (*oauth2.Token, error) { a.throttle.Accept() getTokenCounter.Inc() t, err := a.token() @@ -74,7 +74,7 @@ func (a *altTokenSource) Token() (*oauth2.Token, error) { return t, err } -func (a *altTokenSource) token() (*oauth2.Token, error) { +func (a *AltTokenSource) token() (*oauth2.Token, error) { req, err := http.NewRequest("POST", a.tokenURL, strings.NewReader(a.tokenBody)) if err != nil { return nil, err @@ -100,9 +100,9 @@ func (a *altTokenSource) token() (*oauth2.Token, error) { }, nil } -func newAltTokenSource(tokenURL, tokenBody string) oauth2.TokenSource { +func NewAltTokenSource(tokenURL, tokenBody string) oauth2.TokenSource { client := oauth2.NewClient(oauth2.NoContext, google.ComputeTokenSource("")) - a := &altTokenSource{ + a := &AltTokenSource{ oauthClient: client, tokenURL: tokenURL, tokenBody: tokenBody,