Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Google Cloud DNS dnsprovider - replacement for #25389 #26020

Merged
2 commits merged into from May 28, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
4 changes: 4 additions & 0 deletions Godeps/Godeps.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

35 changes: 35 additions & 0 deletions Godeps/LICENSES

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

61 changes: 61 additions & 0 deletions federation/pkg/dnsprovider/dns.go
Original file line number Diff line number Diff line change
@@ -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
}
21 changes: 21 additions & 0 deletions federation/pkg/dnsprovider/doc.go
Original file line number Diff line number Diff line change
@@ -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
98 changes: 98 additions & 0 deletions federation/pkg/dnsprovider/plugins.go
Original file line number Diff line number Diff line change
@@ -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
}
101 changes: 101 additions & 0 deletions federation/pkg/dnsprovider/providers/google/clouddns/clouddns.go
Original file line number Diff line number Diff line change
@@ -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
}