Add glide.yaml and vendor deps
This commit is contained in:
parent
db918f12ad
commit
5b3d5e81bd
18880 changed files with 5166045 additions and 1 deletions
33
vendor/k8s.io/kubernetes/federation/pkg/dnsprovider/BUILD
generated
vendored
Normal file
33
vendor/k8s.io/kubernetes/federation/pkg/dnsprovider/BUILD
generated
vendored
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
package(default_visibility = ["//visibility:public"])
|
||||
|
||||
licenses(["notice"])
|
||||
|
||||
load(
|
||||
"@io_bazel_rules_go//go:def.bzl",
|
||||
"go_binary",
|
||||
"go_library",
|
||||
"go_test",
|
||||
"cgo_library",
|
||||
)
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = [
|
||||
"dns.go",
|
||||
"doc.go",
|
||||
"plugins.go",
|
||||
],
|
||||
tags = ["automanaged"],
|
||||
deps = [
|
||||
"//federation/pkg/dnsprovider/rrstype:go_default_library",
|
||||
"//vendor:github.com/golang/glog",
|
||||
],
|
||||
)
|
||||
|
||||
go_test(
|
||||
name = "go_default_test",
|
||||
srcs = ["dns_test.go"],
|
||||
library = "go_default_library",
|
||||
tags = ["automanaged"],
|
||||
deps = ["//federation/pkg/dnsprovider/rrstype:go_default_library"],
|
||||
)
|
||||
98
vendor/k8s.io/kubernetes/federation/pkg/dnsprovider/dns.go
generated
vendored
Normal file
98
vendor/k8s.io/kubernetes/federation/pkg/dnsprovider/dns.go
generated
vendored
Normal file
|
|
@ -0,0 +1,98 @@
|
|||
/*
|
||||
Copyright 2016 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package dnsprovider
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
|
||||
"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)
|
||||
// Add creates and returns a new managed zone, or an error if the operation failed
|
||||
Add(Zone) (Zone, error)
|
||||
// Remove deletes a managed zone, or returns an error if the operation failed.
|
||||
Remove(Zone) error
|
||||
// New allocates a new Zone, which can then be passed to Add()
|
||||
// Arguments are as per the Zone interface below.
|
||||
New(name string) (Zone, error)
|
||||
}
|
||||
|
||||
type Zone interface {
|
||||
// Name returns the name of the zone, e.g. "example.com"
|
||||
Name() string
|
||||
// ID returns the unique provider identifier for the zone
|
||||
ID() 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)
|
||||
// New allocates a new ResourceRecordSet, which can then be passed to ResourceRecordChangeset Add() or Remove()
|
||||
// Arguments are as per the ResourceRecordSet interface below.
|
||||
New(name string, rrdatas []string, ttl int64, rrstype rrstype.RrsType) ResourceRecordSet
|
||||
// StartChangeset begins a new batch operation of changes against the Zone
|
||||
StartChangeset() ResourceRecordChangeset
|
||||
}
|
||||
|
||||
// ResourceRecordChangeset accumulates a set of changes, that can then be applied with Apply
|
||||
type ResourceRecordChangeset interface {
|
||||
// Add adds the creation of a ResourceRecordSet in the Zone to the changeset
|
||||
Add(ResourceRecordSet) ResourceRecordChangeset
|
||||
// Remove adds the removal of a ResourceRecordSet in the Zone to the changeset
|
||||
// The supplied ResourceRecordSet must match one of the existing recordsets (obtained via List()) exactly.
|
||||
Remove(ResourceRecordSet) ResourceRecordChangeset
|
||||
// Apply applies the accumulated operations to the Zone.
|
||||
Apply() error
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
/* ResourceRecordSetsEquivalent compares two ResourceRecordSets for semantic equivalence.
|
||||
Go's equality operator doesn't work the way we want it to in this case,
|
||||
hence the need for this function.
|
||||
More specifically (from the Go spec):
|
||||
"Two struct values are equal if their corresponding non-blank fields are equal."
|
||||
In our case, there may be some private internal member variables that may not be not equal,
|
||||
but we want the two structs to be considered equivalent anyway, if the fields exposed
|
||||
via their interfaces are equal.
|
||||
*/
|
||||
func ResourceRecordSetsEquivalent(r1, r2 ResourceRecordSet) bool {
|
||||
if r1.Name() == r2.Name() && reflect.DeepEqual(r1.Rrdatas(), r2.Rrdatas()) && r1.Ttl() == r2.Ttl() && r1.Type() == r2.Type() {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
96
vendor/k8s.io/kubernetes/federation/pkg/dnsprovider/dns_test.go
generated
vendored
Normal file
96
vendor/k8s.io/kubernetes/federation/pkg/dnsprovider/dns_test.go
generated
vendored
Normal file
|
|
@ -0,0 +1,96 @@
|
|||
/*
|
||||
Copyright 2016 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package dnsprovider
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"k8s.io/kubernetes/federation/pkg/dnsprovider/rrstype"
|
||||
)
|
||||
|
||||
// Compile time interface check
|
||||
var _ ResourceRecordSet = record{}
|
||||
|
||||
type record struct {
|
||||
name string
|
||||
rrdatas []string
|
||||
ttl int64
|
||||
type_ string
|
||||
}
|
||||
|
||||
func (r record) Name() string {
|
||||
return r.name
|
||||
}
|
||||
|
||||
func (r record) Ttl() int64 {
|
||||
return r.ttl
|
||||
}
|
||||
|
||||
func (r record) Rrdatas() []string {
|
||||
return r.rrdatas
|
||||
}
|
||||
|
||||
func (r record) Type() rrstype.RrsType {
|
||||
return rrstype.RrsType(r.type_)
|
||||
}
|
||||
|
||||
const testDNSZone string = "foo.com"
|
||||
|
||||
var testData = []struct {
|
||||
inputs [2]record
|
||||
expectedOutput bool
|
||||
}{
|
||||
{
|
||||
[2]record{
|
||||
{"foo", []string{"1.2.3.4", "5,6,7,8"}, 180, "A"}, // Identical
|
||||
{"foo", []string{"1.2.3.4", "5,6,7,8"}, 180, "A"}}, true,
|
||||
},
|
||||
{
|
||||
[2]record{
|
||||
{"foo", []string{"1.2.3.4", "5,6,7,8"}, 180, "A"}, // Identical except Name
|
||||
{"bar", []string{"1.2.3.4", "5,6,7,8"}, 180, "A"}}, false,
|
||||
},
|
||||
{
|
||||
[2]record{
|
||||
{"foo", []string{"1.2.3.4", "5,6,7,8"}, 180, "A"}, // Identical except Rrdata
|
||||
{"foo", []string{"1.2.3.4", "5,6,7,9"}, 180, "A"}}, false,
|
||||
},
|
||||
{
|
||||
[2]record{
|
||||
{"foo", []string{"1.2.3.4", "5,6,7,8"}, 180, "A"}, // Identical except Rrdata ordering reversed
|
||||
{"foo", []string{"5,6,7,8", "1.2.3.4"}, 180, "A"}}, false,
|
||||
},
|
||||
{
|
||||
[2]record{
|
||||
{"foo", []string{"1.2.3.4", "5,6,7,8"}, 180, "A"}, // Identical except TTL
|
||||
{"foo", []string{"1.2.3.4", "5,6,7,8"}, 150, "A"}}, false,
|
||||
},
|
||||
{
|
||||
[2]record{
|
||||
{"foo", []string{"1.2.3.4", "5,6,7,8"}, 180, "A"}, // Identical except Type
|
||||
{"foo", []string{"1.2.3.4", "5,6,7,8"}, 180, "CNAME"}}, false,
|
||||
},
|
||||
}
|
||||
|
||||
func TestEquivalent(t *testing.T) {
|
||||
for _, test := range testData {
|
||||
output := ResourceRecordSetsEquivalent(test.inputs[0], test.inputs[1])
|
||||
if output != test.expectedOutput {
|
||||
t.Errorf("Expected equivalence comparison of %q and %q to yield %v, but it vielded %v", test.inputs[0], test.inputs[1], test.expectedOutput, output)
|
||||
}
|
||||
}
|
||||
}
|
||||
21
vendor/k8s.io/kubernetes/federation/pkg/dnsprovider/doc.go
generated
vendored
Normal file
21
vendor/k8s.io/kubernetes/federation/pkg/dnsprovider/doc.go
generated
vendored
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
/*
|
||||
Copyright 2016 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
/*
|
||||
dnsprovider supplies interfaces for dns service providers (e.g. Google Cloud DNS, AWS route53, etc).
|
||||
Implementations exist in the providers sub-package
|
||||
*/
|
||||
package dnsprovider // import "k8s.io/kubernetes/federation/pkg/dnsprovider"
|
||||
109
vendor/k8s.io/kubernetes/federation/pkg/dnsprovider/plugins.go
generated
vendored
Normal file
109
vendor/k8s.io/kubernetes/federation/pkg/dnsprovider/plugins.go
generated
vendored
Normal file
|
|
@ -0,0 +1,109 @@
|
|||
/*
|
||||
Copyright 2016 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package 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)
|
||||
}
|
||||
|
||||
// Returns a list of registered dns providers.
|
||||
func RegisteredDnsProviders() []string {
|
||||
registeredProviders := make([]string, len(providers))
|
||||
i := 0
|
||||
for provider := range providers {
|
||||
registeredProviders[i] = provider
|
||||
i = i + 1
|
||||
}
|
||||
return registeredProviders
|
||||
}
|
||||
|
||||
// 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
|
||||
}
|
||||
49
vendor/k8s.io/kubernetes/federation/pkg/dnsprovider/providers/aws/route53/BUILD
generated
vendored
Normal file
49
vendor/k8s.io/kubernetes/federation/pkg/dnsprovider/providers/aws/route53/BUILD
generated
vendored
Normal file
|
|
@ -0,0 +1,49 @@
|
|||
package(default_visibility = ["//visibility:public"])
|
||||
|
||||
licenses(["notice"])
|
||||
|
||||
load(
|
||||
"@io_bazel_rules_go//go:def.bzl",
|
||||
"go_binary",
|
||||
"go_library",
|
||||
"go_test",
|
||||
"cgo_library",
|
||||
)
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = [
|
||||
"interface.go",
|
||||
"route53.go",
|
||||
"rrchangeset.go",
|
||||
"rrset.go",
|
||||
"rrsets.go",
|
||||
"zone.go",
|
||||
"zones.go",
|
||||
],
|
||||
tags = ["automanaged"],
|
||||
deps = [
|
||||
"//federation/pkg/dnsprovider:go_default_library",
|
||||
"//federation/pkg/dnsprovider/providers/aws/route53/stubs:go_default_library",
|
||||
"//federation/pkg/dnsprovider/rrstype:go_default_library",
|
||||
"//pkg/util/uuid:go_default_library",
|
||||
"//vendor:github.com/aws/aws-sdk-go/aws",
|
||||
"//vendor:github.com/aws/aws-sdk-go/aws/session",
|
||||
"//vendor:github.com/aws/aws-sdk-go/service/route53",
|
||||
],
|
||||
)
|
||||
|
||||
go_test(
|
||||
name = "go_default_test",
|
||||
srcs = ["route53_test.go"],
|
||||
library = "go_default_library",
|
||||
tags = ["automanaged"],
|
||||
deps = [
|
||||
"//federation/pkg/dnsprovider:go_default_library",
|
||||
"//federation/pkg/dnsprovider/providers/aws/route53/stubs:go_default_library",
|
||||
"//federation/pkg/dnsprovider/rrstype:go_default_library",
|
||||
"//federation/pkg/dnsprovider/tests:go_default_library",
|
||||
"//vendor:github.com/aws/aws-sdk-go/aws",
|
||||
"//vendor:github.com/aws/aws-sdk-go/service/route53",
|
||||
],
|
||||
)
|
||||
39
vendor/k8s.io/kubernetes/federation/pkg/dnsprovider/providers/aws/route53/interface.go
generated
vendored
Normal file
39
vendor/k8s.io/kubernetes/federation/pkg/dnsprovider/providers/aws/route53/interface.go
generated
vendored
Normal file
|
|
@ -0,0 +1,39 @@
|
|||
/*
|
||||
Copyright 2016 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package route53
|
||||
|
||||
import (
|
||||
"k8s.io/kubernetes/federation/pkg/dnsprovider"
|
||||
"k8s.io/kubernetes/federation/pkg/dnsprovider/providers/aws/route53/stubs"
|
||||
)
|
||||
|
||||
// Compile time check for interface adeherence
|
||||
var _ dnsprovider.Interface = Interface{}
|
||||
|
||||
type Interface struct {
|
||||
service stubs.Route53API
|
||||
}
|
||||
|
||||
// newInterfaceWithStub facilitates stubbing out the underlying AWS Route53
|
||||
// library for testing purposes. It returns an provider-independent interface.
|
||||
func newInterfaceWithStub(service stubs.Route53API) *Interface {
|
||||
return &Interface{service}
|
||||
}
|
||||
|
||||
func (i Interface) Zones() (zones dnsprovider.Zones, supported bool) {
|
||||
return Zones{&i}, true
|
||||
}
|
||||
44
vendor/k8s.io/kubernetes/federation/pkg/dnsprovider/providers/aws/route53/route53.go
generated
vendored
Normal file
44
vendor/k8s.io/kubernetes/federation/pkg/dnsprovider/providers/aws/route53/route53.go
generated
vendored
Normal file
|
|
@ -0,0 +1,44 @@
|
|||
/*
|
||||
Copyright 2016 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
// route53 is the implementation of pkg/dnsprovider interface for AWS Route53
|
||||
package route53
|
||||
|
||||
import (
|
||||
"io"
|
||||
|
||||
"k8s.io/kubernetes/federation/pkg/dnsprovider"
|
||||
|
||||
"github.com/aws/aws-sdk-go/aws/session"
|
||||
"github.com/aws/aws-sdk-go/service/route53"
|
||||
)
|
||||
|
||||
const (
|
||||
ProviderName = "aws-route53"
|
||||
)
|
||||
|
||||
func init() {
|
||||
dnsprovider.RegisterDnsProvider(ProviderName, func(config io.Reader) (dnsprovider.Interface, error) {
|
||||
return newRoute53(config)
|
||||
})
|
||||
}
|
||||
|
||||
// newRoute53 creates a new instance of an AWS Route53 DNS Interface.
|
||||
func newRoute53(config io.Reader) (*Interface, error) {
|
||||
// Connect to AWS Route53 - TODO: Do more sophisticated auth
|
||||
svc := route53.New(session.New())
|
||||
return newInterfaceWithStub(svc), nil
|
||||
}
|
||||
295
vendor/k8s.io/kubernetes/federation/pkg/dnsprovider/providers/aws/route53/route53_test.go
generated
vendored
Normal file
295
vendor/k8s.io/kubernetes/federation/pkg/dnsprovider/providers/aws/route53/route53_test.go
generated
vendored
Normal file
|
|
@ -0,0 +1,295 @@
|
|||
/*
|
||||
Copyright 2016 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package route53
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"fmt"
|
||||
"os"
|
||||
"testing"
|
||||
|
||||
"k8s.io/kubernetes/federation/pkg/dnsprovider"
|
||||
route53testing "k8s.io/kubernetes/federation/pkg/dnsprovider/providers/aws/route53/stubs"
|
||||
"k8s.io/kubernetes/federation/pkg/dnsprovider/rrstype"
|
||||
|
||||
"github.com/aws/aws-sdk-go/aws"
|
||||
"github.com/aws/aws-sdk-go/service/route53"
|
||||
"k8s.io/kubernetes/federation/pkg/dnsprovider/tests"
|
||||
)
|
||||
|
||||
func newTestInterface() (dnsprovider.Interface, error) {
|
||||
// Use this to test the real cloud service.
|
||||
// return dnsprovider.GetDnsProvider(ProviderName, strings.NewReader("\n[global]\nproject-id = federation0-cluster00"))
|
||||
return newFakeInterface() // Use this to stub out the entire cloud service
|
||||
}
|
||||
|
||||
func newFakeInterface() (dnsprovider.Interface, error) {
|
||||
var service route53testing.Route53API
|
||||
service = route53testing.NewRoute53APIStub()
|
||||
iface := newInterfaceWithStub(service)
|
||||
// Add a fake zone to test against.
|
||||
params := &route53.CreateHostedZoneInput{
|
||||
CallerReference: aws.String("Nonce"), // Required
|
||||
Name: aws.String("example.com"), // Required
|
||||
}
|
||||
_, err := iface.service.CreateHostedZone(params)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return iface, nil
|
||||
}
|
||||
|
||||
var interface_ dnsprovider.Interface
|
||||
|
||||
func TestMain(m *testing.M) {
|
||||
fmt.Printf("Parsing flags.\n")
|
||||
flag.Parse()
|
||||
var err error
|
||||
fmt.Printf("Getting new test interface.\n")
|
||||
interface_, err = newTestInterface()
|
||||
if err != nil {
|
||||
fmt.Printf("Error creating interface: %v", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
fmt.Printf("Running tests...\n")
|
||||
os.Exit(m.Run())
|
||||
}
|
||||
|
||||
// zones returns the zones interface for the configured dns provider account/project,
|
||||
// or fails if it can't be found
|
||||
func zones(t *testing.T) dnsprovider.Zones {
|
||||
zonesInterface, supported := interface_.Zones()
|
||||
if !supported {
|
||||
t.Fatalf("Zones interface not supported by interface %v", interface_)
|
||||
} else {
|
||||
t.Logf("Got zones %v\n", zonesInterface)
|
||||
}
|
||||
return zonesInterface
|
||||
}
|
||||
|
||||
// firstZone returns the first zone for the configured dns provider account/project,
|
||||
// or fails if it can't be found
|
||||
func firstZone(t *testing.T) dnsprovider.Zone {
|
||||
t.Logf("Getting zones")
|
||||
z := zones(t)
|
||||
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) {
|
||||
err := rrsets.StartChangeset().Add(rrset).Apply()
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to add recordsets: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
/* TestZonesList verifies that listing of zones succeeds */
|
||||
func TestZonesList(t *testing.T) {
|
||||
firstZone(t)
|
||||
}
|
||||
|
||||
/* TestZonesID verifies that the id of the zone is returned with the prefix removed */
|
||||
func TestZonesID(t *testing.T) {
|
||||
zone := firstZone(t)
|
||||
|
||||
// Check /hostedzone/ prefix is removed
|
||||
zoneID := zone.ID()
|
||||
if zoneID != zone.Name() {
|
||||
t.Fatalf("Unexpected zone id: %q", zoneID)
|
||||
}
|
||||
}
|
||||
|
||||
/* TestZoneAddSuccess verifies that addition of a valid managed DNS zone succeeds */
|
||||
func TestZoneAddSuccess(t *testing.T) {
|
||||
testZoneName := "ubernetes.testing"
|
||||
z := zones(t)
|
||||
input, err := z.New(testZoneName)
|
||||
if err != nil {
|
||||
t.Errorf("Failed to allocate new zone object %s: %v", testZoneName, err)
|
||||
}
|
||||
zone, err := z.Add(input)
|
||||
if err != nil {
|
||||
t.Errorf("Failed to create new managed DNS zone %s: %v", testZoneName, err)
|
||||
}
|
||||
defer func(zone dnsprovider.Zone) {
|
||||
if zone != nil {
|
||||
if err := z.Remove(zone); err != nil {
|
||||
t.Errorf("Failed to delete zone %v: %v", zone, err)
|
||||
}
|
||||
}
|
||||
}(zone)
|
||||
t.Logf("Successfully added managed DNS zone: %v", zone)
|
||||
}
|
||||
|
||||
/* TestResourceRecordSetsList verifies that listing of RRS's succeeds */
|
||||
func TestResourceRecordSetsList(t *testing.T) {
|
||||
listRrsOrFail(t, rrs(t, firstZone(t)))
|
||||
}
|
||||
|
||||
/* TestResourceRecordSetsAddSuccess verifies that addition of a valid RRS succeeds */
|
||||
func TestResourceRecordSetsAddSuccess(t *testing.T) {
|
||||
zone := firstZone(t)
|
||||
sets := rrs(t, zone)
|
||||
set := getExampleRrs(zone)
|
||||
addRrsetOrFail(t, sets, set)
|
||||
defer sets.StartChangeset().Remove(set).Apply()
|
||||
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)
|
||||
addRrsetOrFail(t, sets, rrset)
|
||||
defer sets.StartChangeset().Remove(rrset).Apply()
|
||||
t.Logf("Successfully added resource record set: %v", rrset)
|
||||
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)
|
||||
addRrsetOrFail(t, sets, rrset)
|
||||
defer sets.StartChangeset().Remove(rrset).Apply()
|
||||
t.Logf("Successfully added resource record set: %v", rrset)
|
||||
// Try to add it again, and verify that the call fails.
|
||||
err := sets.StartChangeset().Add(rrset).Apply()
|
||||
if err == nil {
|
||||
defer sets.StartChangeset().Remove(rrset).Apply()
|
||||
t.Errorf("Should have failed to add duplicate resource record %v, but succeeded instead.", rrset)
|
||||
} else {
|
||||
t.Logf("Correctly failed to add duplicate resource record %v: %v", rrset, 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)
|
||||
addRrsetOrFail(t, sets, rrset)
|
||||
err := sets.StartChangeset().Remove(rrset).Apply()
|
||||
if err != nil {
|
||||
// Try again to clean up.
|
||||
defer sets.StartChangeset().Remove(rrset).Apply()
|
||||
t.Errorf("Failed to remove resource record set %v after adding", rrset)
|
||||
} else {
|
||||
t.Logf("Successfully removed resource set %v after adding", rrset)
|
||||
}
|
||||
}
|
||||
|
||||
/* TestResourceRecordSetsRemoveGone verifies that a removed RRS no longer exists */
|
||||
func TestResourceRecordSetsRemoveGone(t *testing.T) {
|
||||
zone := firstZone(t)
|
||||
sets := rrs(t, zone)
|
||||
rrset := getExampleRrs(zone)
|
||||
addRrsetOrFail(t, sets, rrset)
|
||||
err := sets.StartChangeset().Remove(rrset).Apply()
|
||||
if err != nil {
|
||||
// Try again to clean up.
|
||||
defer sets.StartChangeset().Remove(rrset).Apply()
|
||||
t.Errorf("Failed to remove resource record set %v after adding", rrset)
|
||||
} else {
|
||||
t.Logf("Successfully removed resource set %v after adding", rrset)
|
||||
}
|
||||
// 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)
|
||||
}
|
||||
}
|
||||
|
||||
/* TestResourceRecordSetsReplace verifies that replacing an RRS works */
|
||||
func TestResourceRecordSetsReplace(t *testing.T) {
|
||||
zone := firstZone(t)
|
||||
tests.CommonTestResourceRecordSetsReplace(t, zone)
|
||||
}
|
||||
|
||||
/* TestResourceRecordSetsReplaceAll verifies that we can remove an RRS and create one with a different name*/
|
||||
func TestResourceRecordSetsReplaceAll(t *testing.T) {
|
||||
zone := firstZone(t)
|
||||
tests.CommonTestResourceRecordSetsReplaceAll(t, zone)
|
||||
}
|
||||
|
||||
/* TestResourceRecordSetsHonorsType verifies that we can add records of the same name but different types */
|
||||
func TestResourceRecordSetsDifferentTypes(t *testing.T) {
|
||||
zone := firstZone(t)
|
||||
tests.CommonTestResourceRecordSetsDifferentTypes(t, zone)
|
||||
}
|
||||
101
vendor/k8s.io/kubernetes/federation/pkg/dnsprovider/providers/aws/route53/rrchangeset.go
generated
vendored
Normal file
101
vendor/k8s.io/kubernetes/federation/pkg/dnsprovider/providers/aws/route53/rrchangeset.go
generated
vendored
Normal file
|
|
@ -0,0 +1,101 @@
|
|||
/*
|
||||
Copyright 2016 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package route53
|
||||
|
||||
import (
|
||||
"github.com/aws/aws-sdk-go/aws"
|
||||
"github.com/aws/aws-sdk-go/service/route53"
|
||||
"k8s.io/kubernetes/federation/pkg/dnsprovider"
|
||||
)
|
||||
|
||||
// Compile time check for interface adherence
|
||||
var _ dnsprovider.ResourceRecordChangeset = &ResourceRecordChangeset{}
|
||||
|
||||
type ResourceRecordChangeset struct {
|
||||
zone *Zone
|
||||
rrsets *ResourceRecordSets
|
||||
|
||||
additions []dnsprovider.ResourceRecordSet
|
||||
removals []dnsprovider.ResourceRecordSet
|
||||
}
|
||||
|
||||
func (c *ResourceRecordChangeset) Add(rrset dnsprovider.ResourceRecordSet) dnsprovider.ResourceRecordChangeset {
|
||||
c.additions = append(c.additions, rrset)
|
||||
return c
|
||||
}
|
||||
|
||||
func (c *ResourceRecordChangeset) Remove(rrset dnsprovider.ResourceRecordSet) dnsprovider.ResourceRecordChangeset {
|
||||
c.removals = append(c.removals, rrset)
|
||||
return c
|
||||
}
|
||||
|
||||
// buildChange converts a dnsprovider.ResourceRecordSet to a route53.Change request
|
||||
func buildChange(action string, rrs dnsprovider.ResourceRecordSet) *route53.Change {
|
||||
change := &route53.Change{
|
||||
Action: aws.String(action),
|
||||
ResourceRecordSet: &route53.ResourceRecordSet{
|
||||
Name: aws.String(rrs.Name()),
|
||||
Type: aws.String(string(rrs.Type())),
|
||||
TTL: aws.Int64(rrs.Ttl()),
|
||||
},
|
||||
}
|
||||
|
||||
for _, rrdata := range rrs.Rrdatas() {
|
||||
rr := &route53.ResourceRecord{
|
||||
Value: aws.String(rrdata),
|
||||
}
|
||||
change.ResourceRecordSet.ResourceRecords = append(change.ResourceRecordSet.ResourceRecords, rr)
|
||||
}
|
||||
return change
|
||||
}
|
||||
|
||||
func (c *ResourceRecordChangeset) Apply() error {
|
||||
hostedZoneID := c.zone.impl.Id
|
||||
|
||||
var changes []*route53.Change
|
||||
|
||||
for _, removal := range c.removals {
|
||||
change := buildChange(route53.ChangeActionDelete, removal)
|
||||
changes = append(changes, change)
|
||||
}
|
||||
|
||||
for _, addition := range c.additions {
|
||||
change := buildChange(route53.ChangeActionCreate, addition)
|
||||
changes = append(changes, change)
|
||||
}
|
||||
|
||||
if len(changes) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
service := c.zone.zones.interface_.service
|
||||
|
||||
request := &route53.ChangeResourceRecordSetsInput{
|
||||
ChangeBatch: &route53.ChangeBatch{
|
||||
Changes: changes,
|
||||
},
|
||||
HostedZoneId: hostedZoneID,
|
||||
}
|
||||
|
||||
_, err := service.ChangeResourceRecordSets(request)
|
||||
if err != nil {
|
||||
// Cast err to awserr.Error to get the Code and
|
||||
// Message from an error.
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
53
vendor/k8s.io/kubernetes/federation/pkg/dnsprovider/providers/aws/route53/rrset.go
generated
vendored
Normal file
53
vendor/k8s.io/kubernetes/federation/pkg/dnsprovider/providers/aws/route53/rrset.go
generated
vendored
Normal file
|
|
@ -0,0 +1,53 @@
|
|||
/*
|
||||
Copyright 2016 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package route53
|
||||
|
||||
import (
|
||||
"k8s.io/kubernetes/federation/pkg/dnsprovider"
|
||||
"k8s.io/kubernetes/federation/pkg/dnsprovider/rrstype"
|
||||
|
||||
"github.com/aws/aws-sdk-go/service/route53"
|
||||
)
|
||||
|
||||
// Compile time check for interface adherence
|
||||
var _ dnsprovider.ResourceRecordSet = ResourceRecordSet{}
|
||||
|
||||
type ResourceRecordSet struct {
|
||||
impl *route53.ResourceRecordSet
|
||||
rrsets *ResourceRecordSets
|
||||
}
|
||||
|
||||
func (rrset ResourceRecordSet) Name() string {
|
||||
return *rrset.impl.Name
|
||||
}
|
||||
|
||||
func (rrset ResourceRecordSet) Rrdatas() []string {
|
||||
// Sigh - need to unpack the strings out of the route53 ResourceRecords
|
||||
result := make([]string, len(rrset.impl.ResourceRecords))
|
||||
for i, record := range rrset.impl.ResourceRecords {
|
||||
result[i] = *record.Value
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
func (rrset ResourceRecordSet) Ttl() int64 {
|
||||
return *rrset.impl.TTL
|
||||
}
|
||||
|
||||
func (rrset ResourceRecordSet) Type() rrstype.RrsType {
|
||||
return rrstype.RrsType(*rrset.impl.Type)
|
||||
}
|
||||
75
vendor/k8s.io/kubernetes/federation/pkg/dnsprovider/providers/aws/route53/rrsets.go
generated
vendored
Normal file
75
vendor/k8s.io/kubernetes/federation/pkg/dnsprovider/providers/aws/route53/rrsets.go
generated
vendored
Normal file
|
|
@ -0,0 +1,75 @@
|
|||
/*
|
||||
Copyright 2016 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package route53
|
||||
|
||||
import (
|
||||
"github.com/aws/aws-sdk-go/aws"
|
||||
"github.com/aws/aws-sdk-go/service/route53"
|
||||
"k8s.io/kubernetes/federation/pkg/dnsprovider"
|
||||
"k8s.io/kubernetes/federation/pkg/dnsprovider/rrstype"
|
||||
)
|
||||
|
||||
// Compile time check for interface adherence
|
||||
var _ dnsprovider.ResourceRecordSets = ResourceRecordSets{}
|
||||
|
||||
type ResourceRecordSets struct {
|
||||
zone *Zone
|
||||
}
|
||||
|
||||
func (rrsets ResourceRecordSets) List() ([]dnsprovider.ResourceRecordSet, error) {
|
||||
input := route53.ListResourceRecordSetsInput{
|
||||
HostedZoneId: rrsets.zone.impl.Id,
|
||||
}
|
||||
|
||||
var list []dnsprovider.ResourceRecordSet
|
||||
err := rrsets.zone.zones.interface_.service.ListResourceRecordSetsPages(&input, func(page *route53.ListResourceRecordSetsOutput, lastPage bool) bool {
|
||||
for _, rrset := range page.ResourceRecordSets {
|
||||
list = append(list, &ResourceRecordSet{rrset, &rrsets})
|
||||
}
|
||||
return true
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return list, nil
|
||||
}
|
||||
|
||||
func (r ResourceRecordSets) StartChangeset() dnsprovider.ResourceRecordChangeset {
|
||||
return &ResourceRecordChangeset{
|
||||
zone: r.zone,
|
||||
rrsets: &r,
|
||||
}
|
||||
}
|
||||
|
||||
func (r ResourceRecordSets) New(name string, rrdatas []string, ttl int64, rrstype rrstype.RrsType) dnsprovider.ResourceRecordSet {
|
||||
rrstypeStr := string(rrstype)
|
||||
rrs := &route53.ResourceRecordSet{
|
||||
Name: &name,
|
||||
Type: &rrstypeStr,
|
||||
TTL: &ttl,
|
||||
}
|
||||
for _, rrdata := range rrdatas {
|
||||
rrs.ResourceRecords = append(rrs.ResourceRecords, &route53.ResourceRecord{
|
||||
Value: aws.String(rrdata),
|
||||
})
|
||||
}
|
||||
|
||||
return ResourceRecordSet{
|
||||
rrs,
|
||||
&r,
|
||||
}
|
||||
}
|
||||
21
vendor/k8s.io/kubernetes/federation/pkg/dnsprovider/providers/aws/route53/stubs/BUILD
generated
vendored
Normal file
21
vendor/k8s.io/kubernetes/federation/pkg/dnsprovider/providers/aws/route53/stubs/BUILD
generated
vendored
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
package(default_visibility = ["//visibility:public"])
|
||||
|
||||
licenses(["notice"])
|
||||
|
||||
load(
|
||||
"@io_bazel_rules_go//go:def.bzl",
|
||||
"go_binary",
|
||||
"go_library",
|
||||
"go_test",
|
||||
"cgo_library",
|
||||
)
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = ["route53api.go"],
|
||||
tags = ["automanaged"],
|
||||
deps = [
|
||||
"//vendor:github.com/aws/aws-sdk-go/aws",
|
||||
"//vendor:github.com/aws/aws-sdk-go/service/route53",
|
||||
],
|
||||
)
|
||||
133
vendor/k8s.io/kubernetes/federation/pkg/dnsprovider/providers/aws/route53/stubs/route53api.go
generated
vendored
Normal file
133
vendor/k8s.io/kubernetes/federation/pkg/dnsprovider/providers/aws/route53/stubs/route53api.go
generated
vendored
Normal file
|
|
@ -0,0 +1,133 @@
|
|||
/*
|
||||
Copyright 2016 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
/* internal implements a stub for the AWS Route53 API, used primarily for unit testing purposes */
|
||||
package stubs
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/aws/aws-sdk-go/aws"
|
||||
"github.com/aws/aws-sdk-go/service/route53"
|
||||
)
|
||||
|
||||
// Compile time check for interface conformance
|
||||
var _ Route53API = &Route53APIStub{}
|
||||
|
||||
/* Route53API is the subset of the AWS Route53 API that we actually use. Add methods as required. Signatures must match exactly. */
|
||||
type Route53API interface {
|
||||
ListResourceRecordSetsPages(input *route53.ListResourceRecordSetsInput, fn func(p *route53.ListResourceRecordSetsOutput, lastPage bool) (shouldContinue bool)) error
|
||||
ChangeResourceRecordSets(*route53.ChangeResourceRecordSetsInput) (*route53.ChangeResourceRecordSetsOutput, error)
|
||||
ListHostedZonesPages(input *route53.ListHostedZonesInput, fn func(p *route53.ListHostedZonesOutput, lastPage bool) (shouldContinue bool)) error
|
||||
CreateHostedZone(*route53.CreateHostedZoneInput) (*route53.CreateHostedZoneOutput, error)
|
||||
DeleteHostedZone(*route53.DeleteHostedZoneInput) (*route53.DeleteHostedZoneOutput, error)
|
||||
}
|
||||
|
||||
// Route53APIStub is a minimal implementation of Route53API, used primarily for unit testing.
|
||||
// See http://http://docs.aws.amazon.com/sdk-for-go/api/service/route53.html for descriptions
|
||||
// of all of its methods.
|
||||
type Route53APIStub struct {
|
||||
zones map[string]*route53.HostedZone
|
||||
recordSets map[string]map[string][]*route53.ResourceRecordSet
|
||||
}
|
||||
|
||||
// NewRoute53APIStub returns an initlialized Route53APIStub
|
||||
func NewRoute53APIStub() *Route53APIStub {
|
||||
return &Route53APIStub{
|
||||
zones: make(map[string]*route53.HostedZone),
|
||||
recordSets: make(map[string]map[string][]*route53.ResourceRecordSet),
|
||||
}
|
||||
}
|
||||
|
||||
func (r *Route53APIStub) ListResourceRecordSetsPages(input *route53.ListResourceRecordSetsInput, fn func(p *route53.ListResourceRecordSetsOutput, lastPage bool) (shouldContinue bool)) error {
|
||||
output := route53.ListResourceRecordSetsOutput{} // TODO: Support optional input args.
|
||||
if len(r.recordSets) <= 0 {
|
||||
output.ResourceRecordSets = []*route53.ResourceRecordSet{}
|
||||
} else if _, ok := r.recordSets[*input.HostedZoneId]; !ok {
|
||||
output.ResourceRecordSets = []*route53.ResourceRecordSet{}
|
||||
} else {
|
||||
for _, rrsets := range r.recordSets[*input.HostedZoneId] {
|
||||
for _, rrset := range rrsets {
|
||||
output.ResourceRecordSets = append(output.ResourceRecordSets, rrset)
|
||||
}
|
||||
}
|
||||
}
|
||||
lastPage := true
|
||||
fn(&output, lastPage)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *Route53APIStub) ChangeResourceRecordSets(input *route53.ChangeResourceRecordSetsInput) (*route53.ChangeResourceRecordSetsOutput, error) {
|
||||
output := &route53.ChangeResourceRecordSetsOutput{}
|
||||
recordSets, ok := r.recordSets[*input.HostedZoneId]
|
||||
if !ok {
|
||||
recordSets = make(map[string][]*route53.ResourceRecordSet)
|
||||
}
|
||||
|
||||
for _, change := range input.ChangeBatch.Changes {
|
||||
key := *change.ResourceRecordSet.Name + "::" + *change.ResourceRecordSet.Type
|
||||
switch *change.Action {
|
||||
case route53.ChangeActionCreate:
|
||||
if _, found := recordSets[key]; found {
|
||||
return nil, fmt.Errorf("Attempt to create duplicate rrset %s", key) // TODO: Return AWS errors with codes etc
|
||||
}
|
||||
recordSets[key] = append(recordSets[key], change.ResourceRecordSet)
|
||||
case route53.ChangeActionDelete:
|
||||
if _, found := recordSets[key]; !found {
|
||||
return nil, fmt.Errorf("Attempt to delete non-existent rrset %s", key) // TODO: Check other fields too
|
||||
}
|
||||
delete(recordSets, key)
|
||||
case route53.ChangeActionUpsert:
|
||||
// TODO - not used yet
|
||||
}
|
||||
}
|
||||
r.recordSets[*input.HostedZoneId] = recordSets
|
||||
return output, nil // TODO: We should ideally return status etc, but we don't' use that yet.
|
||||
}
|
||||
|
||||
func (r *Route53APIStub) ListHostedZonesPages(input *route53.ListHostedZonesInput, fn func(p *route53.ListHostedZonesOutput, lastPage bool) (shouldContinue bool)) error {
|
||||
output := &route53.ListHostedZonesOutput{}
|
||||
for _, zone := range r.zones {
|
||||
output.HostedZones = append(output.HostedZones, zone)
|
||||
}
|
||||
lastPage := true
|
||||
fn(output, lastPage)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *Route53APIStub) CreateHostedZone(input *route53.CreateHostedZoneInput) (*route53.CreateHostedZoneOutput, error) {
|
||||
name := aws.StringValue(input.Name)
|
||||
id := "/hostedzone/" + name
|
||||
if _, ok := r.zones[id]; ok {
|
||||
return nil, fmt.Errorf("Error creating hosted DNS zone: %s already exists", id)
|
||||
}
|
||||
r.zones[id] = &route53.HostedZone{
|
||||
Id: aws.String(id),
|
||||
Name: aws.String(name),
|
||||
}
|
||||
return &route53.CreateHostedZoneOutput{HostedZone: r.zones[id]}, nil
|
||||
}
|
||||
|
||||
func (r *Route53APIStub) DeleteHostedZone(input *route53.DeleteHostedZoneInput) (*route53.DeleteHostedZoneOutput, error) {
|
||||
if _, ok := r.zones[*input.Id]; !ok {
|
||||
return nil, fmt.Errorf("Error deleting hosted DNS zone: %s does not exist", *input.Id)
|
||||
}
|
||||
if len(r.recordSets[*input.Id]) > 0 {
|
||||
return nil, fmt.Errorf("Error deleting hosted DNS zone: %s has resource records", *input.Id)
|
||||
}
|
||||
delete(r.zones, *input.Id)
|
||||
return &route53.DeleteHostedZoneOutput{}, nil
|
||||
}
|
||||
47
vendor/k8s.io/kubernetes/federation/pkg/dnsprovider/providers/aws/route53/zone.go
generated
vendored
Normal file
47
vendor/k8s.io/kubernetes/federation/pkg/dnsprovider/providers/aws/route53/zone.go
generated
vendored
Normal file
|
|
@ -0,0 +1,47 @@
|
|||
/*
|
||||
Copyright 2016 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package route53
|
||||
|
||||
import (
|
||||
"strings"
|
||||
|
||||
"github.com/aws/aws-sdk-go/aws"
|
||||
"github.com/aws/aws-sdk-go/service/route53"
|
||||
"k8s.io/kubernetes/federation/pkg/dnsprovider"
|
||||
)
|
||||
|
||||
// Compile time check for interface adeherence
|
||||
var _ dnsprovider.Zone = &Zone{}
|
||||
|
||||
type Zone struct {
|
||||
impl *route53.HostedZone
|
||||
zones *Zones
|
||||
}
|
||||
|
||||
func (zone *Zone) Name() string {
|
||||
return aws.StringValue(zone.impl.Name)
|
||||
}
|
||||
|
||||
func (zone *Zone) ID() string {
|
||||
id := aws.StringValue(zone.impl.Id)
|
||||
id = strings.TrimPrefix(id, "/hostedzone/")
|
||||
return id
|
||||
}
|
||||
|
||||
func (zone *Zone) ResourceRecordSets() (dnsprovider.ResourceRecordSets, bool) {
|
||||
return &ResourceRecordSets{zone}, true
|
||||
}
|
||||
73
vendor/k8s.io/kubernetes/federation/pkg/dnsprovider/providers/aws/route53/zones.go
generated
vendored
Normal file
73
vendor/k8s.io/kubernetes/federation/pkg/dnsprovider/providers/aws/route53/zones.go
generated
vendored
Normal file
|
|
@ -0,0 +1,73 @@
|
|||
/*
|
||||
Copyright 2016 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package route53
|
||||
|
||||
import (
|
||||
"github.com/aws/aws-sdk-go/service/route53"
|
||||
|
||||
"k8s.io/kubernetes/federation/pkg/dnsprovider"
|
||||
"k8s.io/kubernetes/pkg/util/uuid"
|
||||
)
|
||||
|
||||
// Compile time check for interface adeherence
|
||||
var _ dnsprovider.Zones = Zones{}
|
||||
|
||||
type Zones struct {
|
||||
interface_ *Interface
|
||||
}
|
||||
|
||||
func (zones Zones) List() ([]dnsprovider.Zone, error) {
|
||||
var zoneList []dnsprovider.Zone
|
||||
|
||||
input := route53.ListHostedZonesInput{}
|
||||
err := zones.interface_.service.ListHostedZonesPages(&input, func(page *route53.ListHostedZonesOutput, lastPage bool) bool {
|
||||
for _, zone := range page.HostedZones {
|
||||
zoneList = append(zoneList, &Zone{zone, &zones})
|
||||
}
|
||||
return true
|
||||
})
|
||||
if err != nil {
|
||||
return []dnsprovider.Zone{}, err
|
||||
}
|
||||
return zoneList, nil
|
||||
}
|
||||
|
||||
func (zones Zones) Add(zone dnsprovider.Zone) (dnsprovider.Zone, error) {
|
||||
dnsName := zone.Name()
|
||||
callerReference := string(uuid.NewUUID())
|
||||
input := route53.CreateHostedZoneInput{Name: &dnsName, CallerReference: &callerReference}
|
||||
output, err := zones.interface_.service.CreateHostedZone(&input)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &Zone{output.HostedZone, &zones}, nil
|
||||
}
|
||||
|
||||
func (zones Zones) Remove(zone dnsprovider.Zone) error {
|
||||
zoneId := zone.(*Zone).impl.Id
|
||||
input := route53.DeleteHostedZoneInput{Id: zoneId}
|
||||
_, err := zones.interface_.service.DeleteHostedZone(&input)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
func (zones Zones) New(name string) (dnsprovider.Zone, error) {
|
||||
id := string(uuid.NewUUID())
|
||||
managedZone := route53.HostedZone{Id: &id, Name: &name}
|
||||
return &Zone{&managedZone, &zones}, nil
|
||||
}
|
||||
52
vendor/k8s.io/kubernetes/federation/pkg/dnsprovider/providers/google/clouddns/BUILD
generated
vendored
Normal file
52
vendor/k8s.io/kubernetes/federation/pkg/dnsprovider/providers/google/clouddns/BUILD
generated
vendored
Normal file
|
|
@ -0,0 +1,52 @@
|
|||
package(default_visibility = ["//visibility:public"])
|
||||
|
||||
licenses(["notice"])
|
||||
|
||||
load(
|
||||
"@io_bazel_rules_go//go:def.bzl",
|
||||
"go_binary",
|
||||
"go_library",
|
||||
"go_test",
|
||||
"cgo_library",
|
||||
)
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = [
|
||||
"clouddns.go",
|
||||
"interface.go",
|
||||
"rrchangeset.go",
|
||||
"rrset.go",
|
||||
"rrsets.go",
|
||||
"zone.go",
|
||||
"zones.go",
|
||||
],
|
||||
tags = ["automanaged"],
|
||||
deps = [
|
||||
"//federation/pkg/dnsprovider:go_default_library",
|
||||
"//federation/pkg/dnsprovider/providers/google/clouddns/internal:go_default_library",
|
||||
"//federation/pkg/dnsprovider/providers/google/clouddns/internal/interfaces:go_default_library",
|
||||
"//federation/pkg/dnsprovider/providers/google/clouddns/internal/stubs:go_default_library",
|
||||
"//federation/pkg/dnsprovider/rrstype:go_default_library",
|
||||
"//pkg/cloudprovider/providers/gce:go_default_library",
|
||||
"//vendor:cloud.google.com/go/compute/metadata",
|
||||
"//vendor:github.com/golang/glog",
|
||||
"//vendor:golang.org/x/oauth2",
|
||||
"//vendor:golang.org/x/oauth2/google",
|
||||
"//vendor:google.golang.org/api/compute/v1",
|
||||
"//vendor:google.golang.org/api/dns/v1",
|
||||
"//vendor:gopkg.in/gcfg.v1",
|
||||
],
|
||||
)
|
||||
|
||||
go_test(
|
||||
name = "go_default_test",
|
||||
srcs = ["clouddns_test.go"],
|
||||
library = "go_default_library",
|
||||
tags = ["automanaged"],
|
||||
deps = [
|
||||
"//federation/pkg/dnsprovider:go_default_library",
|
||||
"//federation/pkg/dnsprovider/rrstype:go_default_library",
|
||||
"//federation/pkg/dnsprovider/tests:go_default_library",
|
||||
],
|
||||
)
|
||||
116
vendor/k8s.io/kubernetes/federation/pkg/dnsprovider/providers/google/clouddns/clouddns.go
generated
vendored
Normal file
116
vendor/k8s.io/kubernetes/federation/pkg/dnsprovider/providers/google/clouddns/clouddns.go
generated
vendored
Normal file
|
|
@ -0,0 +1,116 @@
|
|||
/*
|
||||
Copyright 2016 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
// clouddns is the implementation of pkg/dnsprovider interface for Google Cloud DNS
|
||||
package clouddns
|
||||
|
||||
import (
|
||||
"io"
|
||||
|
||||
"cloud.google.com/go/compute/metadata"
|
||||
"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"
|
||||
gcfg "gopkg.in/gcfg.v1"
|
||||
|
||||
"k8s.io/kubernetes/federation/pkg/dnsprovider"
|
||||
"k8s.io/kubernetes/federation/pkg/dnsprovider/providers/google/clouddns/internal"
|
||||
"k8s.io/kubernetes/federation/pkg/dnsprovider/providers/google/clouddns/internal/stubs"
|
||||
"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
|
||||
}
|
||||
|
||||
// NewFakeInterface returns a fake clouddns interface, useful for unit testing purposes.
|
||||
func NewFakeInterface() (dnsprovider.Interface, error) {
|
||||
service := stubs.NewService()
|
||||
interface_ := newInterfaceWithStub("", service)
|
||||
zones := service.ManagedZones_
|
||||
// Add a fake zone to test against.
|
||||
zone := &stubs.ManagedZone{Service: zones, Name_: "example.com", Rrsets: []stubs.ResourceRecordSet{}, Id_: 1}
|
||||
call := zones.Create(interface_.project(), zone)
|
||||
if _, err := call.Do(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return interface_, nil
|
||||
}
|
||||
273
vendor/k8s.io/kubernetes/federation/pkg/dnsprovider/providers/google/clouddns/clouddns_test.go
generated
vendored
Normal file
273
vendor/k8s.io/kubernetes/federation/pkg/dnsprovider/providers/google/clouddns/clouddns_test.go
generated
vendored
Normal file
|
|
@ -0,0 +1,273 @@
|
|||
/*
|
||||
Copyright 2016 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package clouddns
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"fmt"
|
||||
"os"
|
||||
"testing"
|
||||
|
||||
"k8s.io/kubernetes/federation/pkg/dnsprovider"
|
||||
"k8s.io/kubernetes/federation/pkg/dnsprovider/rrstype"
|
||||
"k8s.io/kubernetes/federation/pkg/dnsprovider/tests"
|
||||
)
|
||||
|
||||
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.
|
||||
// return dnsprovider.GetDnsProvider(ProviderName, strings.NewReader("\n[global]\nproject-id = federation0-cluster00"))
|
||||
return NewFakeInterface() // Use this to stub out the entire cloud service
|
||||
}
|
||||
|
||||
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())
|
||||
}
|
||||
|
||||
// zones returns the zones interface for the configured dns provider account/project,
|
||||
// or fails if it can't be found
|
||||
func zones(t *testing.T) dnsprovider.Zones {
|
||||
zonesInterface, supported := interface_.Zones()
|
||||
if !supported {
|
||||
t.Fatalf("Zones interface not supported by interface %v", interface_)
|
||||
} else {
|
||||
t.Logf("Got zones %v\n", zonesInterface)
|
||||
}
|
||||
return zonesInterface
|
||||
}
|
||||
|
||||
// firstZone returns the first zone for the configured dns provider account/project,
|
||||
// or fails if it can't be found
|
||||
func firstZone(t *testing.T) dnsprovider.Zone {
|
||||
t.Logf("Getting zones")
|
||||
zones, err := zones(t).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) {
|
||||
err := rrsets.StartChangeset().Add(rrset).Apply()
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to add recordsets: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
/* TestZonesList verifies that listing of zones succeeds */
|
||||
func TestZonesList(t *testing.T) {
|
||||
firstZone(t)
|
||||
}
|
||||
|
||||
/* TestZonesID verifies that the id of the zone is returned with the prefix removed */
|
||||
func TestZonesID(t *testing.T) {
|
||||
zone := firstZone(t)
|
||||
|
||||
zoneID := zone.ID()
|
||||
if zoneID != "1" {
|
||||
t.Fatalf("Unexpected zone id: %q", zoneID)
|
||||
}
|
||||
}
|
||||
|
||||
/* TestZoneAddSuccess verifies that addition of a valid managed DNS zone succeeds */
|
||||
func TestZoneAddSuccess(t *testing.T) {
|
||||
testZoneName := "ubernetesv2.test."
|
||||
t.Logf("Getting zones")
|
||||
z := zones(t)
|
||||
t.Logf("Got zones, making new Zone")
|
||||
input, err := z.New(testZoneName)
|
||||
if err != nil {
|
||||
t.Errorf("Failed to allocate new zone object %s: %v", testZoneName, err)
|
||||
}
|
||||
zone, err := z.Add(input)
|
||||
if err != nil {
|
||||
t.Errorf("Failed to create new managed DNS zone %s: %v", testZoneName, err)
|
||||
}
|
||||
defer func(zone dnsprovider.Zone) {
|
||||
if zone != nil {
|
||||
if err := z.Remove(zone); err != nil {
|
||||
t.Errorf("Failed to delete zone %v: %v", zone, err)
|
||||
}
|
||||
}
|
||||
}(zone)
|
||||
t.Logf("Successfully added managed DNS zone: %v", zone)
|
||||
}
|
||||
|
||||
/* TestResourceRecordSetsList verifies that listing of RRS's succeeds */
|
||||
func TestResourceRecordSetsList(t *testing.T) {
|
||||
listRrsOrFail(t, rrs(t, firstZone(t)))
|
||||
}
|
||||
|
||||
/* TestResourceRecordSetsAddSuccess verifies that addition of a valid RRS succeeds */
|
||||
func TestResourceRecordSetsAddSuccess(t *testing.T) {
|
||||
zone := firstZone(t)
|
||||
sets := rrs(t, zone)
|
||||
set := getExampleRrs(zone)
|
||||
addRrsetOrFail(t, sets, set)
|
||||
defer sets.StartChangeset().Remove(set).Apply()
|
||||
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)
|
||||
addRrsetOrFail(t, sets, rrset)
|
||||
defer sets.StartChangeset().Remove(rrset).Apply()
|
||||
t.Logf("Successfully added resource record set: %v", rrset)
|
||||
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)
|
||||
addRrsetOrFail(t, sets, rrset)
|
||||
defer sets.StartChangeset().Remove(rrset).Apply()
|
||||
t.Logf("Successfully added resource record set: %v", rrset)
|
||||
// Try to add it again, and verify that the call fails.
|
||||
err := sets.StartChangeset().Add(rrset).Apply()
|
||||
if err == nil {
|
||||
defer sets.StartChangeset().Remove(rrset).Apply()
|
||||
t.Errorf("Should have failed to add duplicate resource record %v, but succeeded instead.", rrset)
|
||||
} else {
|
||||
t.Logf("Correctly failed to add duplicate resource record %v: %v", rrset, 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)
|
||||
addRrsetOrFail(t, sets, rrset)
|
||||
err := sets.StartChangeset().Remove(rrset).Apply()
|
||||
if err != nil {
|
||||
// Try again to clean up.
|
||||
defer sets.StartChangeset().Remove(rrset).Apply()
|
||||
t.Errorf("Failed to remove resource record set %v after adding: %v", rrset, err)
|
||||
} else {
|
||||
t.Logf("Successfully removed resource set %v after adding", rrset)
|
||||
}
|
||||
}
|
||||
|
||||
/* TestResourceRecordSetsRemoveGone verifies that a removed RRS no longer exists */
|
||||
func TestResourceRecordSetsRemoveGone(t *testing.T) {
|
||||
zone := firstZone(t)
|
||||
sets := rrs(t, zone)
|
||||
rrset := getExampleRrs(zone)
|
||||
addRrsetOrFail(t, sets, rrset)
|
||||
err := sets.StartChangeset().Remove(rrset).Apply()
|
||||
if err != nil {
|
||||
// Try again to clean up.
|
||||
defer sets.StartChangeset().Remove(rrset).Apply()
|
||||
t.Errorf("Failed to remove resource record set %v after adding: %v", rrset, err)
|
||||
} else {
|
||||
t.Logf("Successfully removed resource set %v after adding", rrset)
|
||||
}
|
||||
// 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)
|
||||
}
|
||||
}
|
||||
|
||||
/* TestResourceRecordSetsReplace verifies that replacing an RRS works */
|
||||
func TestResourceRecordSetsReplace(t *testing.T) {
|
||||
zone := firstZone(t)
|
||||
tests.CommonTestResourceRecordSetsReplace(t, zone)
|
||||
}
|
||||
|
||||
/* TestResourceRecordSetsReplaceAll verifies that we can remove an RRS and create one with a different name*/
|
||||
func TestResourceRecordSetsReplaceAll(t *testing.T) {
|
||||
zone := firstZone(t)
|
||||
tests.CommonTestResourceRecordSetsReplaceAll(t, zone)
|
||||
}
|
||||
|
||||
/* TestResourceRecordSetsHonorsType verifies that we can add records of the same name but different types */
|
||||
func TestResourceRecordSetsDifferentTypes(t *testing.T) {
|
||||
zone := firstZone(t)
|
||||
tests.CommonTestResourceRecordSetsDifferentTypes(t, zone)
|
||||
}
|
||||
43
vendor/k8s.io/kubernetes/federation/pkg/dnsprovider/providers/google/clouddns/interface.go
generated
vendored
Normal file
43
vendor/k8s.io/kubernetes/federation/pkg/dnsprovider/providers/google/clouddns/interface.go
generated
vendored
Normal file
|
|
@ -0,0 +1,43 @@
|
|||
/*
|
||||
Copyright 2016 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package 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_
|
||||
}
|
||||
41
vendor/k8s.io/kubernetes/federation/pkg/dnsprovider/providers/google/clouddns/internal/BUILD
generated
vendored
Normal file
41
vendor/k8s.io/kubernetes/federation/pkg/dnsprovider/providers/google/clouddns/internal/BUILD
generated
vendored
Normal file
|
|
@ -0,0 +1,41 @@
|
|||
package(default_visibility = ["//visibility:public"])
|
||||
|
||||
licenses(["notice"])
|
||||
|
||||
load(
|
||||
"@io_bazel_rules_go//go:def.bzl",
|
||||
"go_binary",
|
||||
"go_library",
|
||||
"go_test",
|
||||
"cgo_library",
|
||||
)
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = [
|
||||
"change.go",
|
||||
"changes_create_call.go",
|
||||
"changes_service.go",
|
||||
"clouddns.go",
|
||||
"managed_zone.go",
|
||||
"managed_zone_create_call.go",
|
||||
"managed_zones_delete_call.go",
|
||||
"managed_zones_get_call.go",
|
||||
"managed_zones_list_call.go",
|
||||
"managed_zones_list_response.go",
|
||||
"managed_zones_service.go",
|
||||
"rrset.go",
|
||||
"rrsets_list_call.go",
|
||||
"rrsets_list_response.go",
|
||||
"rrsets_service.go",
|
||||
"service.go",
|
||||
],
|
||||
tags = ["automanaged"],
|
||||
deps = [
|
||||
"//federation/pkg/dnsprovider/providers/google/clouddns/internal/interfaces:go_default_library",
|
||||
"//federation/pkg/dnsprovider/rrstype:go_default_library",
|
||||
"//pkg/util/uuid:go_default_library",
|
||||
"//vendor:google.golang.org/api/dns/v1",
|
||||
"//vendor:google.golang.org/api/googleapi",
|
||||
],
|
||||
)
|
||||
43
vendor/k8s.io/kubernetes/federation/pkg/dnsprovider/providers/google/clouddns/internal/change.go
generated
vendored
Normal file
43
vendor/k8s.io/kubernetes/federation/pkg/dnsprovider/providers/google/clouddns/internal/change.go
generated
vendored
Normal file
|
|
@ -0,0 +1,43 @@
|
|||
/*
|
||||
Copyright 2016 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package internal
|
||||
|
||||
import (
|
||||
dns "google.golang.org/api/dns/v1"
|
||||
"k8s.io/kubernetes/federation/pkg/dnsprovider/providers/google/clouddns/internal/interfaces"
|
||||
)
|
||||
|
||||
// Compile time check for interface adeherence
|
||||
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
|
||||
}
|
||||
34
vendor/k8s.io/kubernetes/federation/pkg/dnsprovider/providers/google/clouddns/internal/changes_create_call.go
generated
vendored
Normal file
34
vendor/k8s.io/kubernetes/federation/pkg/dnsprovider/providers/google/clouddns/internal/changes_create_call.go
generated
vendored
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
/*
|
||||
Copyright 2016 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package 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"
|
||||
)
|
||||
|
||||
// Compile time check for interface adeherence
|
||||
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
|
||||
}
|
||||
43
vendor/k8s.io/kubernetes/federation/pkg/dnsprovider/providers/google/clouddns/internal/changes_service.go
generated
vendored
Normal file
43
vendor/k8s.io/kubernetes/federation/pkg/dnsprovider/providers/google/clouddns/internal/changes_service.go
generated
vendored
Normal file
|
|
@ -0,0 +1,43 @@
|
|||
/*
|
||||
Copyright 2016 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package internal
|
||||
|
||||
import (
|
||||
dns "google.golang.org/api/dns/v1"
|
||||
"k8s.io/kubernetes/federation/pkg/dnsprovider/providers/google/clouddns/internal/interfaces"
|
||||
)
|
||||
|
||||
// Compile time check for interface adeherence
|
||||
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}}
|
||||
}
|
||||
35
vendor/k8s.io/kubernetes/federation/pkg/dnsprovider/providers/google/clouddns/internal/clouddns.go
generated
vendored
Normal file
35
vendor/k8s.io/kubernetes/federation/pkg/dnsprovider/providers/google/clouddns/internal/clouddns.go
generated
vendored
Normal file
|
|
@ -0,0 +1,35 @@
|
|||
/*
|
||||
Copyright 2016 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package 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 }
|
||||
)
|
||||
21
vendor/k8s.io/kubernetes/federation/pkg/dnsprovider/providers/google/clouddns/internal/interfaces/BUILD
generated
vendored
Normal file
21
vendor/k8s.io/kubernetes/federation/pkg/dnsprovider/providers/google/clouddns/internal/interfaces/BUILD
generated
vendored
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
package(default_visibility = ["//visibility:public"])
|
||||
|
||||
licenses(["notice"])
|
||||
|
||||
load(
|
||||
"@io_bazel_rules_go//go:def.bzl",
|
||||
"go_binary",
|
||||
"go_library",
|
||||
"go_test",
|
||||
"cgo_library",
|
||||
)
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = ["interfaces.go"],
|
||||
tags = ["automanaged"],
|
||||
deps = [
|
||||
"//federation/pkg/dnsprovider/rrstype:go_default_library",
|
||||
"//vendor:google.golang.org/api/googleapi",
|
||||
],
|
||||
)
|
||||
208
vendor/k8s.io/kubernetes/federation/pkg/dnsprovider/providers/google/clouddns/internal/interfaces/interfaces.go
generated
vendored
Normal file
208
vendor/k8s.io/kubernetes/federation/pkg/dnsprovider/providers/google/clouddns/internal/interfaces/interfaces.go
generated
vendored
Normal file
|
|
@ -0,0 +1,208 @@
|
|||
/*
|
||||
Copyright 2016 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package 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
|
||||
// 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
|
||||
NewManagedZone(dnsName string) ManagedZone
|
||||
}
|
||||
|
||||
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
|
||||
)
|
||||
39
vendor/k8s.io/kubernetes/federation/pkg/dnsprovider/providers/google/clouddns/internal/managed_zone.go
generated
vendored
Normal file
39
vendor/k8s.io/kubernetes/federation/pkg/dnsprovider/providers/google/clouddns/internal/managed_zone.go
generated
vendored
Normal file
|
|
@ -0,0 +1,39 @@
|
|||
/*
|
||||
Copyright 2016 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package internal
|
||||
|
||||
import (
|
||||
dns "google.golang.org/api/dns/v1"
|
||||
"k8s.io/kubernetes/federation/pkg/dnsprovider/providers/google/clouddns/internal/interfaces"
|
||||
)
|
||||
|
||||
// Compile time check for interface adeherence
|
||||
var _ interfaces.ManagedZone = ManagedZone{}
|
||||
|
||||
type ManagedZone struct{ impl *dns.ManagedZone }
|
||||
|
||||
func (m ManagedZone) Name() string {
|
||||
return m.impl.Name
|
||||
}
|
||||
|
||||
func (m ManagedZone) Id() uint64 {
|
||||
return m.impl.Id
|
||||
}
|
||||
|
||||
func (m ManagedZone) DnsName() string {
|
||||
return m.impl.DnsName
|
||||
}
|
||||
33
vendor/k8s.io/kubernetes/federation/pkg/dnsprovider/providers/google/clouddns/internal/managed_zone_create_call.go
generated
vendored
Normal file
33
vendor/k8s.io/kubernetes/federation/pkg/dnsprovider/providers/google/clouddns/internal/managed_zone_create_call.go
generated
vendored
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
/*
|
||||
Copyright 2016 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package 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"
|
||||
)
|
||||
|
||||
// Compile time check for interface adeherence
|
||||
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
|
||||
}
|
||||
32
vendor/k8s.io/kubernetes/federation/pkg/dnsprovider/providers/google/clouddns/internal/managed_zones_delete_call.go
generated
vendored
Normal file
32
vendor/k8s.io/kubernetes/federation/pkg/dnsprovider/providers/google/clouddns/internal/managed_zones_delete_call.go
generated
vendored
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
/*
|
||||
Copyright 2016 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package 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"
|
||||
)
|
||||
|
||||
// Compile time check for interface adeherence
|
||||
var _ interfaces.ManagedZonesDeleteCall = ManagedZonesDeleteCall{}
|
||||
|
||||
type ManagedZonesDeleteCall struct{ impl *dns.ManagedZonesDeleteCall }
|
||||
|
||||
func (call ManagedZonesDeleteCall) Do(opts ...googleapi.CallOption) error {
|
||||
return call.impl.Do(opts...)
|
||||
}
|
||||
33
vendor/k8s.io/kubernetes/federation/pkg/dnsprovider/providers/google/clouddns/internal/managed_zones_get_call.go
generated
vendored
Normal file
33
vendor/k8s.io/kubernetes/federation/pkg/dnsprovider/providers/google/clouddns/internal/managed_zones_get_call.go
generated
vendored
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
/*
|
||||
Copyright 2016 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package 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"
|
||||
)
|
||||
|
||||
// Compile time check for interface adeherence
|
||||
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
|
||||
}
|
||||
38
vendor/k8s.io/kubernetes/federation/pkg/dnsprovider/providers/google/clouddns/internal/managed_zones_list_call.go
generated
vendored
Normal file
38
vendor/k8s.io/kubernetes/federation/pkg/dnsprovider/providers/google/clouddns/internal/managed_zones_list_call.go
generated
vendored
Normal file
|
|
@ -0,0 +1,38 @@
|
|||
/*
|
||||
Copyright 2016 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package 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"
|
||||
)
|
||||
|
||||
// Compile time check for interface adeherence
|
||||
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
|
||||
}
|
||||
35
vendor/k8s.io/kubernetes/federation/pkg/dnsprovider/providers/google/clouddns/internal/managed_zones_list_response.go
generated
vendored
Normal file
35
vendor/k8s.io/kubernetes/federation/pkg/dnsprovider/providers/google/clouddns/internal/managed_zones_list_response.go
generated
vendored
Normal file
|
|
@ -0,0 +1,35 @@
|
|||
/*
|
||||
Copyright 2016 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package internal
|
||||
|
||||
import (
|
||||
dns "google.golang.org/api/dns/v1"
|
||||
"k8s.io/kubernetes/federation/pkg/dnsprovider/providers/google/clouddns/internal/interfaces"
|
||||
)
|
||||
|
||||
// Compile time check for interface adeherence
|
||||
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
|
||||
}
|
||||
51
vendor/k8s.io/kubernetes/federation/pkg/dnsprovider/providers/google/clouddns/internal/managed_zones_service.go
generated
vendored
Normal file
51
vendor/k8s.io/kubernetes/federation/pkg/dnsprovider/providers/google/clouddns/internal/managed_zones_service.go
generated
vendored
Normal file
|
|
@ -0,0 +1,51 @@
|
|||
/*
|
||||
Copyright 2016 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package internal
|
||||
|
||||
import (
|
||||
"strings"
|
||||
|
||||
dns "google.golang.org/api/dns/v1"
|
||||
"k8s.io/kubernetes/federation/pkg/dnsprovider/providers/google/clouddns/internal/interfaces"
|
||||
"k8s.io/kubernetes/pkg/util/uuid"
|
||||
)
|
||||
|
||||
// Compile time check for interface adeherence
|
||||
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)}
|
||||
}
|
||||
|
||||
func (m *ManagedZonesService) NewManagedZone(dnsName string) interfaces.ManagedZone {
|
||||
name := "x" + strings.Replace(string(uuid.NewUUID()), "-", "", -1)[0:30] // Unique name, strip out the "-" chars to shorten it, start with a lower case alpha, and truncate to Cloud DNS 32 character limit
|
||||
return &ManagedZone{impl: &dns.ManagedZone{Name: name, Description: "Kubernetes Federated Service", DnsName: dnsName}}
|
||||
}
|
||||
32
vendor/k8s.io/kubernetes/federation/pkg/dnsprovider/providers/google/clouddns/internal/rrset.go
generated
vendored
Normal file
32
vendor/k8s.io/kubernetes/federation/pkg/dnsprovider/providers/google/clouddns/internal/rrset.go
generated
vendored
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
/*
|
||||
Copyright 2016 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package internal
|
||||
|
||||
import (
|
||||
dns "google.golang.org/api/dns/v1"
|
||||
"k8s.io/kubernetes/federation/pkg/dnsprovider/providers/google/clouddns/internal/interfaces"
|
||||
)
|
||||
|
||||
// Compile time check for interface adeherence
|
||||
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 }
|
||||
45
vendor/k8s.io/kubernetes/federation/pkg/dnsprovider/providers/google/clouddns/internal/rrsets_list_call.go
generated
vendored
Normal file
45
vendor/k8s.io/kubernetes/federation/pkg/dnsprovider/providers/google/clouddns/internal/rrsets_list_call.go
generated
vendored
Normal file
|
|
@ -0,0 +1,45 @@
|
|||
/*
|
||||
Copyright 2016 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package 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"
|
||||
)
|
||||
|
||||
// Compile time check for interface adeherence
|
||||
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
|
||||
}
|
||||
38
vendor/k8s.io/kubernetes/federation/pkg/dnsprovider/providers/google/clouddns/internal/rrsets_list_response.go
generated
vendored
Normal file
38
vendor/k8s.io/kubernetes/federation/pkg/dnsprovider/providers/google/clouddns/internal/rrsets_list_response.go
generated
vendored
Normal file
|
|
@ -0,0 +1,38 @@
|
|||
/*
|
||||
Copyright 2016 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package internal
|
||||
|
||||
import (
|
||||
dns "google.golang.org/api/dns/v1"
|
||||
"k8s.io/kubernetes/federation/pkg/dnsprovider/providers/google/clouddns/internal/interfaces"
|
||||
)
|
||||
|
||||
// Compile time check for interface adeherence
|
||||
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
|
||||
|
||||
}
|
||||
39
vendor/k8s.io/kubernetes/federation/pkg/dnsprovider/providers/google/clouddns/internal/rrsets_service.go
generated
vendored
Normal file
39
vendor/k8s.io/kubernetes/federation/pkg/dnsprovider/providers/google/clouddns/internal/rrsets_service.go
generated
vendored
Normal file
|
|
@ -0,0 +1,39 @@
|
|||
/*
|
||||
Copyright 2016 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package 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"
|
||||
)
|
||||
|
||||
// Compile time check for interface adeherence
|
||||
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}
|
||||
}
|
||||
49
vendor/k8s.io/kubernetes/federation/pkg/dnsprovider/providers/google/clouddns/internal/service.go
generated
vendored
Normal file
49
vendor/k8s.io/kubernetes/federation/pkg/dnsprovider/providers/google/clouddns/internal/service.go
generated
vendored
Normal file
|
|
@ -0,0 +1,49 @@
|
|||
/*
|
||||
Copyright 2016 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package internal
|
||||
|
||||
import (
|
||||
dns "google.golang.org/api/dns/v1"
|
||||
"k8s.io/kubernetes/federation/pkg/dnsprovider/providers/google/clouddns/internal/interfaces"
|
||||
)
|
||||
|
||||
// Compile time check for interface adeherence
|
||||
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}
|
||||
}
|
||||
40
vendor/k8s.io/kubernetes/federation/pkg/dnsprovider/providers/google/clouddns/internal/stubs/BUILD
generated
vendored
Normal file
40
vendor/k8s.io/kubernetes/federation/pkg/dnsprovider/providers/google/clouddns/internal/stubs/BUILD
generated
vendored
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
package(default_visibility = ["//visibility:public"])
|
||||
|
||||
licenses(["notice"])
|
||||
|
||||
load(
|
||||
"@io_bazel_rules_go//go:def.bzl",
|
||||
"go_binary",
|
||||
"go_library",
|
||||
"go_test",
|
||||
"cgo_library",
|
||||
)
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = [
|
||||
"change.go",
|
||||
"changes_create_call.go",
|
||||
"changes_service.go",
|
||||
"clouddns.go",
|
||||
"managed_zone.go",
|
||||
"managed_zone_create_call.go",
|
||||
"managed_zones_delete_call.go",
|
||||
"managed_zones_get_call.go",
|
||||
"managed_zones_list_call.go",
|
||||
"managed_zones_list_response.go",
|
||||
"managed_zones_service.go",
|
||||
"rrset.go",
|
||||
"rrsets_list_call.go",
|
||||
"rrsets_list_response.go",
|
||||
"rrsets_service.go",
|
||||
"service.go",
|
||||
],
|
||||
tags = ["automanaged"],
|
||||
deps = [
|
||||
"//federation/pkg/dnsprovider/providers/google/clouddns/internal/interfaces:go_default_library",
|
||||
"//federation/pkg/dnsprovider/rrstype:go_default_library",
|
||||
"//vendor:google.golang.org/api/dns/v1",
|
||||
"//vendor:google.golang.org/api/googleapi",
|
||||
],
|
||||
)
|
||||
36
vendor/k8s.io/kubernetes/federation/pkg/dnsprovider/providers/google/clouddns/internal/stubs/change.go
generated
vendored
Normal file
36
vendor/k8s.io/kubernetes/federation/pkg/dnsprovider/providers/google/clouddns/internal/stubs/change.go
generated
vendored
Normal file
|
|
@ -0,0 +1,36 @@
|
|||
/*
|
||||
Copyright 2016 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package stubs
|
||||
|
||||
import "k8s.io/kubernetes/federation/pkg/dnsprovider/providers/google/clouddns/internal/interfaces"
|
||||
|
||||
// Compile time check for interface adeherence
|
||||
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_
|
||||
}
|
||||
67
vendor/k8s.io/kubernetes/federation/pkg/dnsprovider/providers/google/clouddns/internal/stubs/changes_create_call.go
generated
vendored
Normal file
67
vendor/k8s.io/kubernetes/federation/pkg/dnsprovider/providers/google/clouddns/internal/stubs/changes_create_call.go
generated
vendored
Normal file
|
|
@ -0,0 +1,67 @@
|
|||
/*
|
||||
Copyright 2016 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package stubs
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"google.golang.org/api/googleapi"
|
||||
"k8s.io/kubernetes/federation/pkg/dnsprovider/providers/google/clouddns/internal/interfaces"
|
||||
)
|
||||
|
||||
// Compile time check for interface adeherence
|
||||
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]ResourceRecordSet{} // compute the new state
|
||||
for _, set := range zone.Rrsets {
|
||||
rrsets[hashKey(set)] = set
|
||||
}
|
||||
for _, del := range c.Change.Deletions() {
|
||||
if _, found := rrsets[hashKey(del)]; !found {
|
||||
return nil, fmt.Errorf("Attempt to delete non-existent rrset %v", del)
|
||||
}
|
||||
delete(rrsets, hashKey(del))
|
||||
}
|
||||
for _, add := range c.Change.Additions() {
|
||||
if _, found := rrsets[hashKey(add)]; found {
|
||||
return nil, fmt.Errorf("Attempt to insert duplicate rrset %v", add)
|
||||
}
|
||||
rrsets[hashKey(add)] = add.(ResourceRecordSet)
|
||||
}
|
||||
zone.Rrsets = []ResourceRecordSet{}
|
||||
for _, rrset := range rrsets {
|
||||
zone.Rrsets = append(zone.Rrsets, rrset)
|
||||
}
|
||||
return c.Change, nil
|
||||
}
|
||||
34
vendor/k8s.io/kubernetes/federation/pkg/dnsprovider/providers/google/clouddns/internal/stubs/changes_service.go
generated
vendored
Normal file
34
vendor/k8s.io/kubernetes/federation/pkg/dnsprovider/providers/google/clouddns/internal/stubs/changes_service.go
generated
vendored
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
/*
|
||||
Copyright 2016 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package stubs
|
||||
|
||||
import "k8s.io/kubernetes/federation/pkg/dnsprovider/providers/google/clouddns/internal/interfaces"
|
||||
|
||||
// Compile time check for interface adeherence
|
||||
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}
|
||||
}
|
||||
33
vendor/k8s.io/kubernetes/federation/pkg/dnsprovider/providers/google/clouddns/internal/stubs/clouddns.go
generated
vendored
Normal file
33
vendor/k8s.io/kubernetes/federation/pkg/dnsprovider/providers/google/clouddns/internal/stubs/clouddns.go
generated
vendored
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
/*
|
||||
Copyright 2016 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package 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 don't 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 }
|
||||
)
|
||||
41
vendor/k8s.io/kubernetes/federation/pkg/dnsprovider/providers/google/clouddns/internal/stubs/managed_zone.go
generated
vendored
Normal file
41
vendor/k8s.io/kubernetes/federation/pkg/dnsprovider/providers/google/clouddns/internal/stubs/managed_zone.go
generated
vendored
Normal file
|
|
@ -0,0 +1,41 @@
|
|||
/*
|
||||
Copyright 2016 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package stubs
|
||||
|
||||
import "k8s.io/kubernetes/federation/pkg/dnsprovider/providers/google/clouddns/internal/interfaces"
|
||||
|
||||
// Compile time check for interface adeherence
|
||||
var _ interfaces.ManagedZone = ManagedZone{}
|
||||
|
||||
type ManagedZone struct {
|
||||
Service *ManagedZonesService
|
||||
Name_ string
|
||||
Id_ uint64
|
||||
Rrsets []ResourceRecordSet
|
||||
}
|
||||
|
||||
func (m ManagedZone) Name() string {
|
||||
return m.Name_
|
||||
}
|
||||
|
||||
func (m ManagedZone) Id() uint64 {
|
||||
return m.Id_
|
||||
}
|
||||
|
||||
func (m ManagedZone) DnsName() string {
|
||||
return m.Name_ // Don't bother storing a separate DNS name
|
||||
}
|
||||
52
vendor/k8s.io/kubernetes/federation/pkg/dnsprovider/providers/google/clouddns/internal/stubs/managed_zone_create_call.go
generated
vendored
Normal file
52
vendor/k8s.io/kubernetes/federation/pkg/dnsprovider/providers/google/clouddns/internal/stubs/managed_zone_create_call.go
generated
vendored
Normal file
|
|
@ -0,0 +1,52 @@
|
|||
/*
|
||||
Copyright 2016 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package stubs
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"google.golang.org/api/googleapi"
|
||||
"k8s.io/kubernetes/federation/pkg/dnsprovider/providers/google/clouddns/internal/interfaces"
|
||||
)
|
||||
|
||||
// Compile time check for interface adeherence
|
||||
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
|
||||
}
|
||||
53
vendor/k8s.io/kubernetes/federation/pkg/dnsprovider/providers/google/clouddns/internal/stubs/managed_zones_delete_call.go
generated
vendored
Normal file
53
vendor/k8s.io/kubernetes/federation/pkg/dnsprovider/providers/google/clouddns/internal/stubs/managed_zones_delete_call.go
generated
vendored
Normal file
|
|
@ -0,0 +1,53 @@
|
|||
/*
|
||||
Copyright 2016 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package stubs
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"google.golang.org/api/googleapi"
|
||||
"k8s.io/kubernetes/federation/pkg/dnsprovider/providers/google/clouddns/internal/interfaces"
|
||||
)
|
||||
|
||||
// Compile time check for interface adeherence
|
||||
var _ interfaces.ManagedZonesDeleteCall = ManagedZonesDeleteCall{}
|
||||
|
||||
type ManagedZonesDeleteCall struct {
|
||||
Service *ManagedZonesService
|
||||
Project string
|
||||
ZoneName string
|
||||
Error *error // Use this to override 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)
|
||||
}
|
||||
}
|
||||
}
|
||||
42
vendor/k8s.io/kubernetes/federation/pkg/dnsprovider/providers/google/clouddns/internal/stubs/managed_zones_get_call.go
generated
vendored
Normal file
42
vendor/k8s.io/kubernetes/federation/pkg/dnsprovider/providers/google/clouddns/internal/stubs/managed_zones_get_call.go
generated
vendored
Normal file
|
|
@ -0,0 +1,42 @@
|
|||
/*
|
||||
Copyright 2016 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package stubs
|
||||
|
||||
import (
|
||||
"google.golang.org/api/googleapi"
|
||||
"k8s.io/kubernetes/federation/pkg/dnsprovider/providers/google/clouddns/internal/interfaces"
|
||||
)
|
||||
|
||||
// Compile time check for interface adeherence
|
||||
var _ interfaces.ManagedZonesGetCall = ManagedZonesGetCall{}
|
||||
|
||||
type ManagedZonesGetCall struct {
|
||||
Service *ManagedZonesService
|
||||
Project string
|
||||
ZoneName string
|
||||
Response interfaces.ManagedZone // Use this to override response if required
|
||||
Error *error // Use this to override 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
|
||||
}
|
||||
}
|
||||
59
vendor/k8s.io/kubernetes/federation/pkg/dnsprovider/providers/google/clouddns/internal/stubs/managed_zones_list_call.go
generated
vendored
Normal file
59
vendor/k8s.io/kubernetes/federation/pkg/dnsprovider/providers/google/clouddns/internal/stubs/managed_zones_list_call.go
generated
vendored
Normal file
|
|
@ -0,0 +1,59 @@
|
|||
/*
|
||||
Copyright 2016 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package stubs
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"google.golang.org/api/googleapi"
|
||||
"k8s.io/kubernetes/federation/pkg/dnsprovider/providers/google/clouddns/internal/interfaces"
|
||||
)
|
||||
|
||||
// Compile time check for interface adeherence
|
||||
var _ interfaces.ManagedZonesListCall = &ManagedZonesListCall{}
|
||||
|
||||
type ManagedZonesListCall struct {
|
||||
Service *ManagedZonesService
|
||||
Project string
|
||||
Response *interfaces.ManagedZonesListResponse // Use this to override response if required
|
||||
Error *error // Use this to override 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
|
||||
}
|
||||
28
vendor/k8s.io/kubernetes/federation/pkg/dnsprovider/providers/google/clouddns/internal/stubs/managed_zones_list_response.go
generated
vendored
Normal file
28
vendor/k8s.io/kubernetes/federation/pkg/dnsprovider/providers/google/clouddns/internal/stubs/managed_zones_list_response.go
generated
vendored
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
/*
|
||||
Copyright 2016 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package stubs
|
||||
|
||||
import "k8s.io/kubernetes/federation/pkg/dnsprovider/providers/google/clouddns/internal/interfaces"
|
||||
|
||||
// Compile time check for interface adeherence
|
||||
var _ interfaces.ManagedZonesListResponse = &ManagedZonesListResponse{}
|
||||
|
||||
type ManagedZonesListResponse struct{ ManagedZones_ []interfaces.ManagedZone }
|
||||
|
||||
func (response *ManagedZonesListResponse) ManagedZones() []interfaces.ManagedZone {
|
||||
return response.ManagedZones_
|
||||
}
|
||||
46
vendor/k8s.io/kubernetes/federation/pkg/dnsprovider/providers/google/clouddns/internal/stubs/managed_zones_service.go
generated
vendored
Normal file
46
vendor/k8s.io/kubernetes/federation/pkg/dnsprovider/providers/google/clouddns/internal/stubs/managed_zones_service.go
generated
vendored
Normal file
|
|
@ -0,0 +1,46 @@
|
|||
/*
|
||||
Copyright 2016 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package stubs
|
||||
|
||||
import "k8s.io/kubernetes/federation/pkg/dnsprovider/providers/google/clouddns/internal/interfaces"
|
||||
|
||||
// Compile time check for interface adeherence
|
||||
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, ""}
|
||||
}
|
||||
|
||||
func (m *ManagedZonesService) NewManagedZone(dnsName string) interfaces.ManagedZone {
|
||||
return &ManagedZone{Service: m, Name_: dnsName}
|
||||
}
|
||||
34
vendor/k8s.io/kubernetes/federation/pkg/dnsprovider/providers/google/clouddns/internal/stubs/rrset.go
generated
vendored
Normal file
34
vendor/k8s.io/kubernetes/federation/pkg/dnsprovider/providers/google/clouddns/internal/stubs/rrset.go
generated
vendored
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
/*
|
||||
Copyright 2016 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package stubs
|
||||
|
||||
import "k8s.io/kubernetes/federation/pkg/dnsprovider/providers/google/clouddns/internal/interfaces"
|
||||
|
||||
// Compile time check for interface adeherence
|
||||
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_ }
|
||||
46
vendor/k8s.io/kubernetes/federation/pkg/dnsprovider/providers/google/clouddns/internal/stubs/rrsets_list_call.go
generated
vendored
Normal file
46
vendor/k8s.io/kubernetes/federation/pkg/dnsprovider/providers/google/clouddns/internal/stubs/rrsets_list_call.go
generated
vendored
Normal file
|
|
@ -0,0 +1,46 @@
|
|||
/*
|
||||
Copyright 2016 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package stubs
|
||||
|
||||
import (
|
||||
"google.golang.org/api/googleapi"
|
||||
"k8s.io/kubernetes/federation/pkg/dnsprovider/providers/google/clouddns/internal/interfaces"
|
||||
)
|
||||
|
||||
// Compile time check for interface adeherence
|
||||
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
|
||||
}
|
||||
30
vendor/k8s.io/kubernetes/federation/pkg/dnsprovider/providers/google/clouddns/internal/stubs/rrsets_list_response.go
generated
vendored
Normal file
30
vendor/k8s.io/kubernetes/federation/pkg/dnsprovider/providers/google/clouddns/internal/stubs/rrsets_list_response.go
generated
vendored
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
/*
|
||||
Copyright 2016 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package stubs
|
||||
|
||||
import "k8s.io/kubernetes/federation/pkg/dnsprovider/providers/google/clouddns/internal/interfaces"
|
||||
|
||||
// Compile time check for interface adeherence
|
||||
var _ interfaces.ResourceRecordSetsListResponse = &ResourceRecordSetsListResponse{}
|
||||
|
||||
type ResourceRecordSetsListResponse struct {
|
||||
impl []interfaces.ResourceRecordSet
|
||||
}
|
||||
|
||||
func (response *ResourceRecordSetsListResponse) Rrsets() []interfaces.ResourceRecordSet {
|
||||
return response.impl
|
||||
}
|
||||
59
vendor/k8s.io/kubernetes/federation/pkg/dnsprovider/providers/google/clouddns/internal/stubs/rrsets_service.go
generated
vendored
Normal file
59
vendor/k8s.io/kubernetes/federation/pkg/dnsprovider/providers/google/clouddns/internal/stubs/rrsets_service.go
generated
vendored
Normal file
|
|
@ -0,0 +1,59 @@
|
|||
/*
|
||||
Copyright 2016 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package stubs
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"k8s.io/kubernetes/federation/pkg/dnsprovider/providers/google/clouddns/internal/interfaces"
|
||||
"k8s.io/kubernetes/federation/pkg/dnsprovider/rrstype"
|
||||
)
|
||||
|
||||
// Compile time check for interface adeherence
|
||||
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
|
||||
}
|
||||
54
vendor/k8s.io/kubernetes/federation/pkg/dnsprovider/providers/google/clouddns/internal/stubs/service.go
generated
vendored
Normal file
54
vendor/k8s.io/kubernetes/federation/pkg/dnsprovider/providers/google/clouddns/internal/stubs/service.go
generated
vendored
Normal file
|
|
@ -0,0 +1,54 @@
|
|||
/*
|
||||
Copyright 2016 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package stubs
|
||||
|
||||
import "k8s.io/kubernetes/federation/pkg/dnsprovider/providers/google/clouddns/internal/interfaces"
|
||||
|
||||
// Compile time check for interface adeherence
|
||||
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_
|
||||
}
|
||||
74
vendor/k8s.io/kubernetes/federation/pkg/dnsprovider/providers/google/clouddns/rrchangeset.go
generated
vendored
Normal file
74
vendor/k8s.io/kubernetes/federation/pkg/dnsprovider/providers/google/clouddns/rrchangeset.go
generated
vendored
Normal file
|
|
@ -0,0 +1,74 @@
|
|||
/*
|
||||
Copyright 2016 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package clouddns
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"k8s.io/kubernetes/federation/pkg/dnsprovider"
|
||||
"k8s.io/kubernetes/federation/pkg/dnsprovider/providers/google/clouddns/internal/interfaces"
|
||||
)
|
||||
|
||||
// Compile time check for interface adherence
|
||||
var _ dnsprovider.ResourceRecordChangeset = &ResourceRecordChangeset{}
|
||||
|
||||
type ResourceRecordChangeset struct {
|
||||
rrsets *ResourceRecordSets
|
||||
|
||||
additions []dnsprovider.ResourceRecordSet
|
||||
removals []dnsprovider.ResourceRecordSet
|
||||
}
|
||||
|
||||
func (c *ResourceRecordChangeset) Add(rrset dnsprovider.ResourceRecordSet) dnsprovider.ResourceRecordChangeset {
|
||||
c.additions = append(c.additions, rrset)
|
||||
return c
|
||||
}
|
||||
|
||||
func (c *ResourceRecordChangeset) Remove(rrset dnsprovider.ResourceRecordSet) dnsprovider.ResourceRecordChangeset {
|
||||
c.removals = append(c.removals, rrset)
|
||||
return c
|
||||
}
|
||||
|
||||
func (c *ResourceRecordChangeset) Apply() error {
|
||||
rrsets := c.rrsets
|
||||
|
||||
service := rrsets.zone.zones.interface_.service.Changes()
|
||||
var additions []interfaces.ResourceRecordSet
|
||||
for _, r := range c.additions {
|
||||
additions = append(additions, r.(ResourceRecordSet).impl)
|
||||
}
|
||||
var deletions []interfaces.ResourceRecordSet
|
||||
for _, r := range c.removals {
|
||||
deletions = append(deletions, r.(ResourceRecordSet).impl)
|
||||
}
|
||||
|
||||
change := service.NewChange(additions, deletions)
|
||||
newChange, err := service.Create(rrsets.project(), rrsets.zone.impl.Name(), change).Do()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
newAdditions := newChange.Additions()
|
||||
if len(newAdditions) != len(additions) {
|
||||
return fmt.Errorf("Internal error when adding resource record set. Call succeeded but number of records returned is incorrect. Records sent=%d, records returned=%d, additions:%v", len(additions), len(newAdditions), c.additions)
|
||||
}
|
||||
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, deletions:%v", len(deletions), len(newDeletions), c.removals)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
53
vendor/k8s.io/kubernetes/federation/pkg/dnsprovider/providers/google/clouddns/rrset.go
generated
vendored
Normal file
53
vendor/k8s.io/kubernetes/federation/pkg/dnsprovider/providers/google/clouddns/rrset.go
generated
vendored
Normal file
|
|
@ -0,0 +1,53 @@
|
|||
/*
|
||||
Copyright 2016 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package 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"
|
||||
)
|
||||
|
||||
// Compile time check for interface adeherence
|
||||
var _ dnsprovider.ResourceRecordSet = ResourceRecordSet{}
|
||||
|
||||
type ResourceRecordSet struct {
|
||||
impl interfaces.ResourceRecordSet
|
||||
rrsets *ResourceRecordSets
|
||||
}
|
||||
|
||||
func (rrset ResourceRecordSet) String() string {
|
||||
return fmt.Sprintf("<(clouddns) %q type=%s rrdatas=%q ttl=%v>", rrset.Name(), rrset.Type(), rrset.Rrdatas(), rrset.Ttl())
|
||||
}
|
||||
|
||||
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())
|
||||
}
|
||||
57
vendor/k8s.io/kubernetes/federation/pkg/dnsprovider/providers/google/clouddns/rrsets.go
generated
vendored
Normal file
57
vendor/k8s.io/kubernetes/federation/pkg/dnsprovider/providers/google/clouddns/rrsets.go
generated
vendored
Normal file
|
|
@ -0,0 +1,57 @@
|
|||
/*
|
||||
Copyright 2016 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package clouddns
|
||||
|
||||
import (
|
||||
"k8s.io/kubernetes/federation/pkg/dnsprovider"
|
||||
"k8s.io/kubernetes/federation/pkg/dnsprovider/providers/google/clouddns/internal/interfaces"
|
||||
"k8s.io/kubernetes/federation/pkg/dnsprovider/rrstype"
|
||||
)
|
||||
|
||||
// Compile time check for interface adherence
|
||||
var _ dnsprovider.ResourceRecordSets = ResourceRecordSets{}
|
||||
|
||||
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 (r ResourceRecordSets) StartChangeset() dnsprovider.ResourceRecordChangeset {
|
||||
return &ResourceRecordChangeset{
|
||||
rrsets: &r,
|
||||
}
|
||||
}
|
||||
|
||||
func (r ResourceRecordSets) New(name string, rrdatas []string, ttl int64, rrstype rrstype.RrsType) dnsprovider.ResourceRecordSet {
|
||||
return ResourceRecordSet{r.impl.NewResourceRecordSet(name, rrdatas, ttl, rrstype), &r}
|
||||
}
|
||||
|
||||
func (rrsets ResourceRecordSets) project() string {
|
||||
return rrsets.zone.project()
|
||||
}
|
||||
48
vendor/k8s.io/kubernetes/federation/pkg/dnsprovider/providers/google/clouddns/zone.go
generated
vendored
Normal file
48
vendor/k8s.io/kubernetes/federation/pkg/dnsprovider/providers/google/clouddns/zone.go
generated
vendored
Normal file
|
|
@ -0,0 +1,48 @@
|
|||
/*
|
||||
Copyright 2016 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package clouddns
|
||||
|
||||
import (
|
||||
"strconv"
|
||||
|
||||
"k8s.io/kubernetes/federation/pkg/dnsprovider"
|
||||
"k8s.io/kubernetes/federation/pkg/dnsprovider/providers/google/clouddns/internal/interfaces"
|
||||
)
|
||||
|
||||
// Compile time check for interface adeherence
|
||||
var _ dnsprovider.Zone = &Zone{}
|
||||
|
||||
type Zone struct {
|
||||
impl interfaces.ManagedZone
|
||||
zones *Zones
|
||||
}
|
||||
|
||||
func (zone *Zone) Name() string {
|
||||
return zone.impl.DnsName()
|
||||
}
|
||||
|
||||
func (zone *Zone) ID() string {
|
||||
return strconv.FormatUint(zone.impl.Id(), 10)
|
||||
}
|
||||
|
||||
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()
|
||||
}
|
||||
68
vendor/k8s.io/kubernetes/federation/pkg/dnsprovider/providers/google/clouddns/zones.go
generated
vendored
Normal file
68
vendor/k8s.io/kubernetes/federation/pkg/dnsprovider/providers/google/clouddns/zones.go
generated
vendored
Normal file
|
|
@ -0,0 +1,68 @@
|
|||
/*
|
||||
Copyright 2016 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package clouddns
|
||||
|
||||
import (
|
||||
"k8s.io/kubernetes/federation/pkg/dnsprovider"
|
||||
"k8s.io/kubernetes/federation/pkg/dnsprovider/providers/google/clouddns/internal/interfaces"
|
||||
)
|
||||
|
||||
// Compile time check for interface adeherence
|
||||
var _ dnsprovider.Zones = Zones{}
|
||||
|
||||
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 nil, err
|
||||
}
|
||||
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) Add(zone dnsprovider.Zone) (dnsprovider.Zone, error) {
|
||||
managedZone := zones.impl.NewManagedZone(zone.Name())
|
||||
response, err := zones.impl.Create(zones.project(), managedZone).Do()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &Zone{response, &zones}, nil
|
||||
}
|
||||
|
||||
func (zones Zones) Remove(zone dnsprovider.Zone) error {
|
||||
if err := zones.impl.Delete(zones.project(), zone.(*Zone).impl.Name()).Do(); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (zones Zones) New(name string) (dnsprovider.Zone, error) {
|
||||
managedZone := zones.impl.NewManagedZone(name)
|
||||
return &Zone{managedZone, &zones}, nil
|
||||
}
|
||||
|
||||
func (zones Zones) project() string {
|
||||
return zones.interface_.project()
|
||||
}
|
||||
17
vendor/k8s.io/kubernetes/federation/pkg/dnsprovider/rrstype/BUILD
generated
vendored
Normal file
17
vendor/k8s.io/kubernetes/federation/pkg/dnsprovider/rrstype/BUILD
generated
vendored
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
package(default_visibility = ["//visibility:public"])
|
||||
|
||||
licenses(["notice"])
|
||||
|
||||
load(
|
||||
"@io_bazel_rules_go//go:def.bzl",
|
||||
"go_binary",
|
||||
"go_library",
|
||||
"go_test",
|
||||
"cgo_library",
|
||||
)
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = ["rrstype.go"],
|
||||
tags = ["automanaged"],
|
||||
)
|
||||
28
vendor/k8s.io/kubernetes/federation/pkg/dnsprovider/rrstype/rrstype.go
generated
vendored
Normal file
28
vendor/k8s.io/kubernetes/federation/pkg/dnsprovider/rrstype/rrstype.go
generated
vendored
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
/*
|
||||
Copyright 2016 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package rrstype
|
||||
|
||||
type (
|
||||
RrsType string
|
||||
)
|
||||
|
||||
const (
|
||||
A = RrsType("A")
|
||||
AAAA = RrsType("AAAA")
|
||||
CNAME = RrsType("CNAME")
|
||||
// TODO: Add other types as required
|
||||
)
|
||||
21
vendor/k8s.io/kubernetes/federation/pkg/dnsprovider/tests/BUILD
generated
vendored
Normal file
21
vendor/k8s.io/kubernetes/federation/pkg/dnsprovider/tests/BUILD
generated
vendored
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
package(default_visibility = ["//visibility:public"])
|
||||
|
||||
licenses(["notice"])
|
||||
|
||||
load(
|
||||
"@io_bazel_rules_go//go:def.bzl",
|
||||
"go_binary",
|
||||
"go_library",
|
||||
"go_test",
|
||||
"cgo_library",
|
||||
)
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = ["commontests.go"],
|
||||
tags = ["automanaged"],
|
||||
deps = [
|
||||
"//federation/pkg/dnsprovider:go_default_library",
|
||||
"//federation/pkg/dnsprovider/rrstype:go_default_library",
|
||||
],
|
||||
)
|
||||
184
vendor/k8s.io/kubernetes/federation/pkg/dnsprovider/tests/commontests.go
generated
vendored
Normal file
184
vendor/k8s.io/kubernetes/federation/pkg/dnsprovider/tests/commontests.go
generated
vendored
Normal file
|
|
@ -0,0 +1,184 @@
|
|||
/*
|
||||
Copyright 2016 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package tests
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
"k8s.io/kubernetes/federation/pkg/dnsprovider"
|
||||
"k8s.io/kubernetes/federation/pkg/dnsprovider/rrstype"
|
||||
)
|
||||
|
||||
/* CommonTestResourceRecordSetsReplace verifies that replacing an RRS works */
|
||||
func CommonTestResourceRecordSetsReplace(t *testing.T, zone dnsprovider.Zone) {
|
||||
rrsets, _ := zone.ResourceRecordSets()
|
||||
|
||||
sets := rrs(t, zone)
|
||||
rrset := rrsets.New("alpha.test.com", []string{"8.8.4.4"}, 40, rrstype.A)
|
||||
addRrsetOrFail(t, sets, rrset)
|
||||
defer sets.StartChangeset().Remove(rrset).Apply()
|
||||
t.Logf("Successfully added resource record set: %v", rrset)
|
||||
|
||||
// Replace the record (change ttl and rrdatas)
|
||||
newRrset := rrsets.New("alpha.test.com", []string{"8.8.8.8"}, 80, rrstype.A)
|
||||
err := sets.StartChangeset().Add(newRrset).Remove(rrset).Apply()
|
||||
if err != nil {
|
||||
t.Errorf("Failed to replace resource record set %v -> %v: %v", rrset, newRrset, err)
|
||||
} else {
|
||||
t.Logf("Correctly replaced resource record %v -> %v", rrset, newRrset)
|
||||
}
|
||||
defer sets.StartChangeset().Remove(newRrset).Apply()
|
||||
|
||||
// Check that the record was updated
|
||||
assertHasRecord(t, sets, newRrset)
|
||||
}
|
||||
|
||||
/* CommonTestResourceRecordSetsReplaceAll verifies that we can remove an RRS and create one with a different name*/
|
||||
func CommonTestResourceRecordSetsReplaceAll(t *testing.T, zone dnsprovider.Zone) {
|
||||
rrsets, _ := zone.ResourceRecordSets()
|
||||
|
||||
sets := rrs(t, zone)
|
||||
rrset := rrsets.New("alpha.test.com", []string{"8.8.4.4"}, 40, rrstype.A)
|
||||
addRrsetOrFail(t, sets, rrset)
|
||||
defer sets.StartChangeset().Remove(rrset).Apply()
|
||||
t.Logf("Successfully added resource record set: %v", rrset)
|
||||
|
||||
newRrset := rrsets.New("beta.test.com", []string{"8.8.8.8"}, 80, rrstype.A)
|
||||
|
||||
// Try to add it again, and verify that the call fails.
|
||||
err := sets.StartChangeset().Add(newRrset).Remove(rrset).Apply()
|
||||
if err != nil {
|
||||
t.Errorf("Failed to replace resource record set %v -> %v: %v", rrset, newRrset, err)
|
||||
} else {
|
||||
defer sets.StartChangeset().Remove(newRrset).Apply()
|
||||
t.Logf("Correctly replaced resource record %v -> %v", rrset, newRrset)
|
||||
}
|
||||
|
||||
// Check that it was updated
|
||||
assertHasRecord(t, sets, newRrset)
|
||||
assertNotHasRecord(t, sets, rrset.Name(), rrset.Type())
|
||||
}
|
||||
|
||||
/* CommonTestResourceRecordSetsHonorsType verifies that we can add records of the same name but different types */
|
||||
func CommonTestResourceRecordSetsDifferentTypes(t *testing.T, zone dnsprovider.Zone) {
|
||||
rrsets, _ := zone.ResourceRecordSets()
|
||||
|
||||
sets := rrs(t, zone)
|
||||
rrset := rrsets.New("alpha.test.com", []string{"8.8.4.4"}, 40, rrstype.A)
|
||||
addRrsetOrFail(t, sets, rrset)
|
||||
defer sets.StartChangeset().Remove(rrset).Apply()
|
||||
t.Logf("Successfully added resource record set: %v", rrset)
|
||||
|
||||
aaaaRrset := rrsets.New("alpha.test.com", []string{"2001:4860:4860::8888"}, 80, rrstype.AAAA)
|
||||
|
||||
// Add the resource with the same name but different type
|
||||
err := sets.StartChangeset().Add(aaaaRrset).Apply()
|
||||
if err != nil {
|
||||
t.Errorf("Failed to add resource record set %v: %v", aaaaRrset, err)
|
||||
}
|
||||
defer sets.StartChangeset().Remove(aaaaRrset).Apply()
|
||||
|
||||
// Check that both records exist
|
||||
assertHasRecord(t, sets, aaaaRrset)
|
||||
assertHasRecord(t, sets, rrset)
|
||||
}
|
||||
|
||||
/* 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
|
||||
}
|
||||
|
||||
// assertHasRecord tests that rrsets has a record equivalent to rrset
|
||||
func assertHasRecord(t *testing.T, rrsets dnsprovider.ResourceRecordSets, rrset dnsprovider.ResourceRecordSet) {
|
||||
var found dnsprovider.ResourceRecordSet
|
||||
for _, r := range listRrsOrFail(t, rrsets) {
|
||||
if r.Name() != rrset.Name() || r.Type() != rrset.Type() {
|
||||
continue
|
||||
}
|
||||
|
||||
if found != nil {
|
||||
t.Errorf("found duplicate resource record set: %q and %q", r, found)
|
||||
}
|
||||
found = r
|
||||
}
|
||||
if found == nil {
|
||||
t.Errorf("resource record set %v not found", rrset)
|
||||
} else {
|
||||
assertEquivalent(t, found, rrset)
|
||||
}
|
||||
}
|
||||
|
||||
// assertNotHasRecord tests that rrsets does not have a record matching name and type
|
||||
func assertNotHasRecord(t *testing.T, rrsets dnsprovider.ResourceRecordSets, name string, rrstype rrstype.RrsType) {
|
||||
var found dnsprovider.ResourceRecordSet
|
||||
for _, r := range listRrsOrFail(t, rrsets) {
|
||||
if r.Name() != name || r.Type() != rrstype {
|
||||
continue
|
||||
}
|
||||
|
||||
if found != nil {
|
||||
t.Errorf("found duplicate resource record set: %q and %q", r, found)
|
||||
}
|
||||
found = r
|
||||
}
|
||||
if found != nil {
|
||||
t.Errorf("resource record set found unexpectedly: %v", found)
|
||||
}
|
||||
}
|
||||
|
||||
// assertEquivalent tests that l is equal to r, for the methods in ResourceRecordSet
|
||||
func assertEquivalent(t *testing.T, l, r dnsprovider.ResourceRecordSet) {
|
||||
if l.Name() != r.Name() {
|
||||
t.Errorf("resource record sets not equal %v vs %v", l, r)
|
||||
}
|
||||
if l.Type() != r.Type() {
|
||||
t.Errorf("resource record sets not equal %v vs %v", l, r)
|
||||
}
|
||||
if l.Ttl() != r.Ttl() {
|
||||
t.Errorf("resource record sets not equal %v vs %v", l, r)
|
||||
}
|
||||
if !reflect.DeepEqual(l.Rrdatas(), r.Rrdatas()) {
|
||||
t.Errorf("resource record sets not equal %v vs %v", l, r)
|
||||
}
|
||||
}
|
||||
|
||||
func addRrsetOrFail(t *testing.T, rrsets dnsprovider.ResourceRecordSets, rrset dnsprovider.ResourceRecordSet) {
|
||||
err := rrsets.StartChangeset().Add(rrset).Apply()
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to add recordsets: %v", err)
|
||||
}
|
||||
}
|
||||
17
vendor/k8s.io/kubernetes/federation/pkg/federation-controller/BUILD
generated
vendored
Normal file
17
vendor/k8s.io/kubernetes/federation/pkg/federation-controller/BUILD
generated
vendored
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
package(default_visibility = ["//visibility:public"])
|
||||
|
||||
licenses(["notice"])
|
||||
|
||||
load(
|
||||
"@io_bazel_rules_go//go:def.bzl",
|
||||
"go_binary",
|
||||
"go_library",
|
||||
"go_test",
|
||||
"cgo_library",
|
||||
)
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = ["doc.go"],
|
||||
tags = ["automanaged"],
|
||||
)
|
||||
4
vendor/k8s.io/kubernetes/federation/pkg/federation-controller/OWNERS
generated
vendored
Normal file
4
vendor/k8s.io/kubernetes/federation/pkg/federation-controller/OWNERS
generated
vendored
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
assignees:
|
||||
- quinton-hoole
|
||||
- nikhiljindal
|
||||
- madhusudancs
|
||||
60
vendor/k8s.io/kubernetes/federation/pkg/federation-controller/cluster/BUILD
generated
vendored
Normal file
60
vendor/k8s.io/kubernetes/federation/pkg/federation-controller/cluster/BUILD
generated
vendored
Normal file
|
|
@ -0,0 +1,60 @@
|
|||
package(default_visibility = ["//visibility:public"])
|
||||
|
||||
licenses(["notice"])
|
||||
|
||||
load(
|
||||
"@io_bazel_rules_go//go:def.bzl",
|
||||
"go_binary",
|
||||
"go_library",
|
||||
"go_test",
|
||||
"cgo_library",
|
||||
)
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = [
|
||||
"cluster_client.go",
|
||||
"clustercontroller.go",
|
||||
"doc.go",
|
||||
],
|
||||
tags = ["automanaged"],
|
||||
deps = [
|
||||
"//federation/apis/federation/v1beta1:go_default_library",
|
||||
"//federation/client/cache:go_default_library",
|
||||
"//federation/client/clientset_generated/federation_release_1_5:go_default_library",
|
||||
"//federation/pkg/federation-controller/util:go_default_library",
|
||||
"//pkg/api:go_default_library",
|
||||
"//pkg/api/v1:go_default_library",
|
||||
"//pkg/apis/meta/v1:go_default_library",
|
||||
"//pkg/client/cache:go_default_library",
|
||||
"//pkg/client/clientset_generated/internalclientset:go_default_library",
|
||||
"//pkg/client/restclient:go_default_library",
|
||||
"//pkg/client/typed/discovery:go_default_library",
|
||||
"//pkg/controller:go_default_library",
|
||||
"//pkg/runtime:go_default_library",
|
||||
"//pkg/util/runtime:go_default_library",
|
||||
"//pkg/util/sets:go_default_library",
|
||||
"//pkg/util/wait:go_default_library",
|
||||
"//pkg/watch:go_default_library",
|
||||
"//vendor:github.com/golang/glog",
|
||||
],
|
||||
)
|
||||
|
||||
go_test(
|
||||
name = "go_default_test",
|
||||
srcs = ["clustercontroller_test.go"],
|
||||
library = "go_default_library",
|
||||
tags = ["automanaged"],
|
||||
deps = [
|
||||
"//federation/apis/federation/v1beta1:go_default_library",
|
||||
"//federation/client/clientset_generated/federation_release_1_5:go_default_library",
|
||||
"//federation/pkg/federation-controller/util:go_default_library",
|
||||
"//pkg/api/testapi:go_default_library",
|
||||
"//pkg/api/v1:go_default_library",
|
||||
"//pkg/apis/meta/v1:go_default_library",
|
||||
"//pkg/client/restclient:go_default_library",
|
||||
"//pkg/client/unversioned/clientcmd:go_default_library",
|
||||
"//pkg/client/unversioned/clientcmd/api:go_default_library",
|
||||
"//pkg/util/uuid:go_default_library",
|
||||
],
|
||||
)
|
||||
169
vendor/k8s.io/kubernetes/federation/pkg/federation-controller/cluster/cluster_client.go
generated
vendored
Normal file
169
vendor/k8s.io/kubernetes/federation/pkg/federation-controller/cluster/cluster_client.go
generated
vendored
Normal file
|
|
@ -0,0 +1,169 @@
|
|||
/*
|
||||
Copyright 2016 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package cluster
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/golang/glog"
|
||||
federation_v1beta1 "k8s.io/kubernetes/federation/apis/federation/v1beta1"
|
||||
"k8s.io/kubernetes/federation/pkg/federation-controller/util"
|
||||
"k8s.io/kubernetes/pkg/api"
|
||||
"k8s.io/kubernetes/pkg/api/v1"
|
||||
metav1 "k8s.io/kubernetes/pkg/apis/meta/v1"
|
||||
clientset "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset"
|
||||
"k8s.io/kubernetes/pkg/client/restclient"
|
||||
"k8s.io/kubernetes/pkg/client/typed/discovery"
|
||||
"k8s.io/kubernetes/pkg/util/sets"
|
||||
)
|
||||
|
||||
const (
|
||||
UserAgentName = "Cluster-Controller"
|
||||
KubeAPIQPS = 20.0
|
||||
KubeAPIBurst = 30
|
||||
KubeconfigSecretDataKey = "kubeconfig"
|
||||
)
|
||||
|
||||
type ClusterClient struct {
|
||||
discoveryClient *discovery.DiscoveryClient
|
||||
kubeClient *clientset.Clientset
|
||||
}
|
||||
|
||||
func NewClusterClientSet(c *federation_v1beta1.Cluster) (*ClusterClient, error) {
|
||||
clusterConfig, err := util.BuildClusterConfig(c)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var clusterClientSet = ClusterClient{}
|
||||
if clusterConfig != nil {
|
||||
clusterClientSet.discoveryClient = discovery.NewDiscoveryClientForConfigOrDie((restclient.AddUserAgent(clusterConfig, UserAgentName)))
|
||||
if clusterClientSet.discoveryClient == nil {
|
||||
return nil, nil
|
||||
}
|
||||
clusterClientSet.kubeClient = clientset.NewForConfigOrDie((restclient.AddUserAgent(clusterConfig, UserAgentName)))
|
||||
if clusterClientSet.kubeClient == nil {
|
||||
return nil, nil
|
||||
}
|
||||
}
|
||||
return &clusterClientSet, nil
|
||||
}
|
||||
|
||||
// GetClusterHealthStatus gets the kubernetes cluster health status by requesting "/healthz"
|
||||
func (self *ClusterClient) GetClusterHealthStatus() *federation_v1beta1.ClusterStatus {
|
||||
clusterStatus := federation_v1beta1.ClusterStatus{}
|
||||
currentTime := metav1.Now()
|
||||
newClusterReadyCondition := federation_v1beta1.ClusterCondition{
|
||||
Type: federation_v1beta1.ClusterReady,
|
||||
Status: v1.ConditionTrue,
|
||||
Reason: "ClusterReady",
|
||||
Message: "/healthz responded with ok",
|
||||
LastProbeTime: currentTime,
|
||||
LastTransitionTime: currentTime,
|
||||
}
|
||||
newClusterNotReadyCondition := federation_v1beta1.ClusterCondition{
|
||||
Type: federation_v1beta1.ClusterReady,
|
||||
Status: v1.ConditionFalse,
|
||||
Reason: "ClusterNotReady",
|
||||
Message: "/healthz responded without ok",
|
||||
LastProbeTime: currentTime,
|
||||
LastTransitionTime: currentTime,
|
||||
}
|
||||
newNodeOfflineCondition := federation_v1beta1.ClusterCondition{
|
||||
Type: federation_v1beta1.ClusterOffline,
|
||||
Status: v1.ConditionTrue,
|
||||
Reason: "ClusterNotReachable",
|
||||
Message: "cluster is not reachable",
|
||||
LastProbeTime: currentTime,
|
||||
LastTransitionTime: currentTime,
|
||||
}
|
||||
newNodeNotOfflineCondition := federation_v1beta1.ClusterCondition{
|
||||
Type: federation_v1beta1.ClusterOffline,
|
||||
Status: v1.ConditionFalse,
|
||||
Reason: "ClusterReachable",
|
||||
Message: "cluster is reachable",
|
||||
LastProbeTime: currentTime,
|
||||
LastTransitionTime: currentTime,
|
||||
}
|
||||
body, err := self.discoveryClient.RESTClient().Get().AbsPath("/healthz").Do().Raw()
|
||||
if err != nil {
|
||||
clusterStatus.Conditions = append(clusterStatus.Conditions, newNodeOfflineCondition)
|
||||
} else {
|
||||
if !strings.EqualFold(string(body), "ok") {
|
||||
clusterStatus.Conditions = append(clusterStatus.Conditions, newClusterNotReadyCondition, newNodeNotOfflineCondition)
|
||||
} else {
|
||||
clusterStatus.Conditions = append(clusterStatus.Conditions, newClusterReadyCondition)
|
||||
}
|
||||
}
|
||||
return &clusterStatus
|
||||
}
|
||||
|
||||
// GetClusterZones gets the kubernetes cluster zones and region by inspecting labels on nodes in the cluster.
|
||||
func (self *ClusterClient) GetClusterZones() (zones []string, region string, err error) {
|
||||
return getZoneNames(self.kubeClient)
|
||||
}
|
||||
|
||||
// Find the name of the zone in which a Node is running
|
||||
func getZoneNameForNode(node api.Node) (string, error) {
|
||||
for key, value := range node.Labels {
|
||||
if key == metav1.LabelZoneFailureDomain {
|
||||
return value, nil
|
||||
}
|
||||
}
|
||||
return "", fmt.Errorf("Zone name for node %s not found. No label with key %s",
|
||||
node.Name, metav1.LabelZoneFailureDomain)
|
||||
}
|
||||
|
||||
// Find the name of the region in which a Node is running
|
||||
func getRegionNameForNode(node api.Node) (string, error) {
|
||||
for key, value := range node.Labels {
|
||||
if key == metav1.LabelZoneRegion {
|
||||
return value, nil
|
||||
}
|
||||
}
|
||||
return "", fmt.Errorf("Region name for node %s not found. No label with key %s",
|
||||
node.Name, metav1.LabelZoneRegion)
|
||||
}
|
||||
|
||||
// Find the names of all zones and the region in which we have nodes in this cluster.
|
||||
func getZoneNames(client *clientset.Clientset) (zones []string, region string, err error) {
|
||||
zoneNames := sets.NewString()
|
||||
nodes, err := client.Core().Nodes().List(api.ListOptions{})
|
||||
if err != nil {
|
||||
glog.Errorf("Failed to list nodes while getting zone names: %v", err)
|
||||
return nil, "", err
|
||||
}
|
||||
for i, node := range nodes.Items {
|
||||
// TODO: quinton-hoole make this more efficient.
|
||||
// For non-multi-zone clusters the zone will
|
||||
// be identical for all nodes, so we only need to look at one node
|
||||
// For multi-zone clusters we know at build time
|
||||
// which zones are included. Rather get this info from there, because it's cheaper.
|
||||
zoneName, err := getZoneNameForNode(node)
|
||||
if err != nil {
|
||||
return nil, "", err
|
||||
}
|
||||
zoneNames.Insert(zoneName)
|
||||
if i == 0 {
|
||||
region, err = getRegionNameForNode(node)
|
||||
if err != nil {
|
||||
return nil, "", err
|
||||
}
|
||||
}
|
||||
}
|
||||
return zoneNames.List(), region, nil
|
||||
}
|
||||
209
vendor/k8s.io/kubernetes/federation/pkg/federation-controller/cluster/clustercontroller.go
generated
vendored
Normal file
209
vendor/k8s.io/kubernetes/federation/pkg/federation-controller/cluster/clustercontroller.go
generated
vendored
Normal file
|
|
@ -0,0 +1,209 @@
|
|||
/*
|
||||
Copyright 2016 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package cluster
|
||||
|
||||
import (
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/golang/glog"
|
||||
federationv1beta1 "k8s.io/kubernetes/federation/apis/federation/v1beta1"
|
||||
clustercache "k8s.io/kubernetes/federation/client/cache"
|
||||
federationclientset "k8s.io/kubernetes/federation/client/clientset_generated/federation_release_1_5"
|
||||
"k8s.io/kubernetes/pkg/api/v1"
|
||||
"k8s.io/kubernetes/pkg/client/cache"
|
||||
"k8s.io/kubernetes/pkg/controller"
|
||||
"k8s.io/kubernetes/pkg/runtime"
|
||||
utilruntime "k8s.io/kubernetes/pkg/util/runtime"
|
||||
"k8s.io/kubernetes/pkg/util/sets"
|
||||
"k8s.io/kubernetes/pkg/util/wait"
|
||||
"k8s.io/kubernetes/pkg/watch"
|
||||
)
|
||||
|
||||
type ClusterController struct {
|
||||
knownClusterSet sets.String
|
||||
|
||||
// federationClient used to operate cluster
|
||||
federationClient federationclientset.Interface
|
||||
|
||||
// clusterMonitorPeriod is the period for updating status of cluster
|
||||
clusterMonitorPeriod time.Duration
|
||||
// clusterClusterStatusMap is a mapping of clusterName and cluster status of last sampling
|
||||
clusterClusterStatusMap map[string]federationv1beta1.ClusterStatus
|
||||
|
||||
// clusterKubeClientMap is a mapping of clusterName and restclient
|
||||
clusterKubeClientMap map[string]ClusterClient
|
||||
|
||||
// cluster framework and store
|
||||
clusterController *cache.Controller
|
||||
clusterStore clustercache.StoreToClusterLister
|
||||
}
|
||||
|
||||
// NewclusterController returns a new cluster controller
|
||||
func NewclusterController(federationClient federationclientset.Interface, clusterMonitorPeriod time.Duration) *ClusterController {
|
||||
cc := &ClusterController{
|
||||
knownClusterSet: make(sets.String),
|
||||
federationClient: federationClient,
|
||||
clusterMonitorPeriod: clusterMonitorPeriod,
|
||||
clusterClusterStatusMap: make(map[string]federationv1beta1.ClusterStatus),
|
||||
clusterKubeClientMap: make(map[string]ClusterClient),
|
||||
}
|
||||
cc.clusterStore.Store, cc.clusterController = cache.NewInformer(
|
||||
&cache.ListWatch{
|
||||
ListFunc: func(options v1.ListOptions) (runtime.Object, error) {
|
||||
return cc.federationClient.Federation().Clusters().List(options)
|
||||
},
|
||||
WatchFunc: func(options v1.ListOptions) (watch.Interface, error) {
|
||||
return cc.federationClient.Federation().Clusters().Watch(options)
|
||||
},
|
||||
},
|
||||
&federationv1beta1.Cluster{},
|
||||
controller.NoResyncPeriodFunc(),
|
||||
cache.ResourceEventHandlerFuncs{
|
||||
DeleteFunc: cc.delFromClusterSet,
|
||||
AddFunc: cc.addToClusterSet,
|
||||
},
|
||||
)
|
||||
return cc
|
||||
}
|
||||
|
||||
// delFromClusterSet delete a cluster from clusterSet and
|
||||
// delete the corresponding restclient from the map clusterKubeClientMap
|
||||
func (cc *ClusterController) delFromClusterSet(obj interface{}) {
|
||||
cluster := obj.(*federationv1beta1.Cluster)
|
||||
cc.knownClusterSet.Delete(cluster.Name)
|
||||
delete(cc.clusterKubeClientMap, cluster.Name)
|
||||
}
|
||||
|
||||
// addToClusterSet insert the new cluster to clusterSet and create a corresponding
|
||||
// restclient to map clusterKubeClientMap
|
||||
func (cc *ClusterController) addToClusterSet(obj interface{}) {
|
||||
cluster := obj.(*federationv1beta1.Cluster)
|
||||
cc.knownClusterSet.Insert(cluster.Name)
|
||||
// create the restclient of cluster
|
||||
restClient, err := NewClusterClientSet(cluster)
|
||||
if err != nil || restClient == nil {
|
||||
glog.Errorf("Failed to create corresponding restclient of kubernetes cluster: %v", err)
|
||||
return
|
||||
}
|
||||
cc.clusterKubeClientMap[cluster.Name] = *restClient
|
||||
}
|
||||
|
||||
// Run begins watching and syncing.
|
||||
func (cc *ClusterController) Run() {
|
||||
defer utilruntime.HandleCrash()
|
||||
go cc.clusterController.Run(wait.NeverStop)
|
||||
// monitor cluster status periodically, in phase 1 we just get the health state from "/healthz"
|
||||
go wait.Until(func() {
|
||||
if err := cc.UpdateClusterStatus(); err != nil {
|
||||
glog.Errorf("Error monitoring cluster status: %v", err)
|
||||
}
|
||||
}, cc.clusterMonitorPeriod, wait.NeverStop)
|
||||
}
|
||||
|
||||
func (cc *ClusterController) GetClusterStatus(cluster *federationv1beta1.Cluster) (*federationv1beta1.ClusterStatus, error) {
|
||||
// just get the status of cluster, by requesting the restapi "/healthz"
|
||||
clusterClient, found := cc.clusterKubeClientMap[cluster.Name]
|
||||
if !found {
|
||||
glog.Infof("It's a new cluster, a cluster client will be created")
|
||||
client, err := NewClusterClientSet(cluster)
|
||||
if err != nil || client == nil {
|
||||
glog.Errorf("Failed to create cluster client, err: %v", err)
|
||||
return nil, err
|
||||
}
|
||||
clusterClient = *client
|
||||
cc.clusterKubeClientMap[cluster.Name] = clusterClient
|
||||
}
|
||||
clusterStatus := clusterClient.GetClusterHealthStatus()
|
||||
return clusterStatus, nil
|
||||
}
|
||||
|
||||
// UpdateClusterStatus checks cluster status and get the metrics from cluster's restapi
|
||||
func (cc *ClusterController) UpdateClusterStatus() error {
|
||||
clusters, err := cc.federationClient.Federation().Clusters().List(v1.ListOptions{})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for _, cluster := range clusters.Items {
|
||||
if !cc.knownClusterSet.Has(cluster.Name) {
|
||||
glog.V(1).Infof("ClusterController observed a new cluster: %#v", cluster)
|
||||
cc.knownClusterSet.Insert(cluster.Name)
|
||||
}
|
||||
}
|
||||
|
||||
// If there's a difference between lengths of known clusters and observed clusters
|
||||
if len(cc.knownClusterSet) != len(clusters.Items) {
|
||||
observedSet := make(sets.String)
|
||||
for _, cluster := range clusters.Items {
|
||||
observedSet.Insert(cluster.Name)
|
||||
}
|
||||
deleted := cc.knownClusterSet.Difference(observedSet)
|
||||
for clusterName := range deleted {
|
||||
glog.V(1).Infof("ClusterController observed a Cluster deletion: %v", clusterName)
|
||||
cc.knownClusterSet.Delete(clusterName)
|
||||
}
|
||||
}
|
||||
for _, cluster := range clusters.Items {
|
||||
clusterStatusNew, err := cc.GetClusterStatus(&cluster)
|
||||
if err != nil {
|
||||
glog.Infof("Failed to Get the status of cluster: %v", cluster.Name)
|
||||
continue
|
||||
}
|
||||
clusterStatusOld, found := cc.clusterClusterStatusMap[cluster.Name]
|
||||
if !found {
|
||||
glog.Infof("There is no status stored for cluster: %v before", cluster.Name)
|
||||
|
||||
} else {
|
||||
hasTransition := false
|
||||
for i := 0; i < len(clusterStatusNew.Conditions); i++ {
|
||||
if !(strings.EqualFold(string(clusterStatusNew.Conditions[i].Type), string(clusterStatusOld.Conditions[i].Type)) &&
|
||||
strings.EqualFold(string(clusterStatusNew.Conditions[i].Status), string(clusterStatusOld.Conditions[i].Status))) {
|
||||
hasTransition = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if !hasTransition {
|
||||
for j := 0; j < len(clusterStatusNew.Conditions); j++ {
|
||||
clusterStatusNew.Conditions[j].LastTransitionTime = clusterStatusOld.Conditions[j].LastTransitionTime
|
||||
}
|
||||
}
|
||||
}
|
||||
clusterClient, found := cc.clusterKubeClientMap[cluster.Name]
|
||||
if !found {
|
||||
glog.Warningf("Failed to client for cluster %s", cluster.Name)
|
||||
continue
|
||||
}
|
||||
|
||||
zones, region, err := clusterClient.GetClusterZones()
|
||||
if err != nil {
|
||||
glog.Warningf("Failed to get zones and region for cluster %s: %v", cluster.Name, err)
|
||||
// Don't return err here, as we want the rest of the status update to proceed.
|
||||
} else {
|
||||
clusterStatusNew.Zones = zones
|
||||
clusterStatusNew.Region = region
|
||||
}
|
||||
cc.clusterClusterStatusMap[cluster.Name] = *clusterStatusNew
|
||||
cluster.Status = *clusterStatusNew
|
||||
cluster, err := cc.federationClient.Federation().Clusters().UpdateStatus(&cluster)
|
||||
if err != nil {
|
||||
glog.Warningf("Failed to update the status of cluster: %v ,error is : %v", cluster.Name, err)
|
||||
// Don't return err here, as we want to continue processing remaining clusters.
|
||||
continue
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
151
vendor/k8s.io/kubernetes/federation/pkg/federation-controller/cluster/clustercontroller_test.go
generated
vendored
Normal file
151
vendor/k8s.io/kubernetes/federation/pkg/federation-controller/cluster/clustercontroller_test.go
generated
vendored
Normal file
|
|
@ -0,0 +1,151 @@
|
|||
/*
|
||||
Copyright 2016 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package cluster
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"testing"
|
||||
|
||||
federationv1beta1 "k8s.io/kubernetes/federation/apis/federation/v1beta1"
|
||||
federationclientset "k8s.io/kubernetes/federation/client/clientset_generated/federation_release_1_5"
|
||||
controllerutil "k8s.io/kubernetes/federation/pkg/federation-controller/util"
|
||||
"k8s.io/kubernetes/pkg/api/testapi"
|
||||
"k8s.io/kubernetes/pkg/api/v1"
|
||||
metav1 "k8s.io/kubernetes/pkg/apis/meta/v1"
|
||||
"k8s.io/kubernetes/pkg/client/restclient"
|
||||
"k8s.io/kubernetes/pkg/client/unversioned/clientcmd"
|
||||
clientcmdapi "k8s.io/kubernetes/pkg/client/unversioned/clientcmd/api"
|
||||
"k8s.io/kubernetes/pkg/util/uuid"
|
||||
)
|
||||
|
||||
func newCluster(clusterName string, serverUrl string) *federationv1beta1.Cluster {
|
||||
cluster := federationv1beta1.Cluster{
|
||||
TypeMeta: metav1.TypeMeta{APIVersion: testapi.Federation.GroupVersion().String()},
|
||||
ObjectMeta: v1.ObjectMeta{
|
||||
UID: uuid.NewUUID(),
|
||||
Name: clusterName,
|
||||
},
|
||||
Spec: federationv1beta1.ClusterSpec{
|
||||
ServerAddressByClientCIDRs: []federationv1beta1.ServerAddressByClientCIDR{
|
||||
{
|
||||
ClientCIDR: "0.0.0.0/0",
|
||||
ServerAddress: serverUrl,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
return &cluster
|
||||
}
|
||||
|
||||
func newClusterList(cluster *federationv1beta1.Cluster) *federationv1beta1.ClusterList {
|
||||
clusterList := federationv1beta1.ClusterList{
|
||||
TypeMeta: metav1.TypeMeta{APIVersion: testapi.Federation.GroupVersion().String()},
|
||||
ListMeta: metav1.ListMeta{
|
||||
SelfLink: "foobar",
|
||||
},
|
||||
Items: []federationv1beta1.Cluster{},
|
||||
}
|
||||
clusterList.Items = append(clusterList.Items, *cluster)
|
||||
return &clusterList
|
||||
}
|
||||
|
||||
// init a fake http handler, simulate a federation apiserver, response the "DELETE" "PUT" "GET" "UPDATE"
|
||||
// when "canBeGotten" is false, means that user can not get the cluster cluster from apiserver
|
||||
func createHttptestFakeHandlerForFederation(clusterList *federationv1beta1.ClusterList, canBeGotten bool) *http.HandlerFunc {
|
||||
fakeHandler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
clusterListString, _ := json.Marshal(*clusterList)
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
switch r.Method {
|
||||
case "PUT":
|
||||
fmt.Fprintln(w, string(clusterListString))
|
||||
case "GET":
|
||||
if canBeGotten {
|
||||
fmt.Fprintln(w, string(clusterListString))
|
||||
} else {
|
||||
fmt.Fprintln(w, "")
|
||||
}
|
||||
default:
|
||||
fmt.Fprintln(w, "")
|
||||
}
|
||||
})
|
||||
return &fakeHandler
|
||||
}
|
||||
|
||||
// init a fake http handler, simulate a cluster apiserver, response the "/healthz"
|
||||
// when "canBeGotten" is false, means that user can not get response from apiserver
|
||||
func createHttptestFakeHandlerForCluster(canBeGotten bool) *http.HandlerFunc {
|
||||
fakeHandler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
switch r.Method {
|
||||
case "GET":
|
||||
if canBeGotten {
|
||||
fmt.Fprintln(w, "ok")
|
||||
} else {
|
||||
w.WriteHeader(http.StatusNotFound)
|
||||
}
|
||||
default:
|
||||
fmt.Fprintln(w, "")
|
||||
}
|
||||
})
|
||||
return &fakeHandler
|
||||
}
|
||||
|
||||
func TestUpdateClusterStatusOK(t *testing.T) {
|
||||
clusterName := "foobarCluster"
|
||||
// create dummy httpserver
|
||||
testClusterServer := httptest.NewServer(createHttptestFakeHandlerForCluster(true))
|
||||
defer testClusterServer.Close()
|
||||
federationCluster := newCluster(clusterName, testClusterServer.URL)
|
||||
federationClusterList := newClusterList(federationCluster)
|
||||
|
||||
testFederationServer := httptest.NewServer(createHttptestFakeHandlerForFederation(federationClusterList, true))
|
||||
defer testFederationServer.Close()
|
||||
|
||||
restClientCfg, err := clientcmd.BuildConfigFromFlags(testFederationServer.URL, "")
|
||||
if err != nil {
|
||||
t.Errorf("Failed to build client config")
|
||||
}
|
||||
federationClientSet := federationclientset.NewForConfigOrDie(restclient.AddUserAgent(restClientCfg, "cluster-controller"))
|
||||
|
||||
// Override KubeconfigGetterForCluster to avoid having to setup service accounts and mount files with secret tokens.
|
||||
originalGetter := controllerutil.KubeconfigGetterForCluster
|
||||
controllerutil.KubeconfigGetterForCluster = func(c *federationv1beta1.Cluster) clientcmd.KubeconfigGetter {
|
||||
return func() (*clientcmdapi.Config, error) {
|
||||
return &clientcmdapi.Config{}, nil
|
||||
}
|
||||
}
|
||||
|
||||
manager := NewclusterController(federationClientSet, 5)
|
||||
err = manager.UpdateClusterStatus()
|
||||
if err != nil {
|
||||
t.Errorf("Failed to Update Cluster Status: %v", err)
|
||||
}
|
||||
clusterStatus, found := manager.clusterClusterStatusMap[clusterName]
|
||||
if !found {
|
||||
t.Errorf("Failed to Update Cluster Status")
|
||||
} else {
|
||||
if (clusterStatus.Conditions[1].Status != v1.ConditionFalse) || (clusterStatus.Conditions[1].Type != federationv1beta1.ClusterOffline) {
|
||||
t.Errorf("Failed to Update Cluster Status")
|
||||
}
|
||||
}
|
||||
|
||||
// Reset KubeconfigGetterForCluster
|
||||
controllerutil.KubeconfigGetterForCluster = originalGetter
|
||||
}
|
||||
18
vendor/k8s.io/kubernetes/federation/pkg/federation-controller/cluster/doc.go
generated
vendored
Normal file
18
vendor/k8s.io/kubernetes/federation/pkg/federation-controller/cluster/doc.go
generated
vendored
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
/*
|
||||
Copyright 2016 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
// Package cluster contains code for syncing cluster
|
||||
package cluster // import "k8s.io/kubernetes/federation/pkg/federation-controller/cluster"
|
||||
54
vendor/k8s.io/kubernetes/federation/pkg/federation-controller/configmap/BUILD
generated
vendored
Normal file
54
vendor/k8s.io/kubernetes/federation/pkg/federation-controller/configmap/BUILD
generated
vendored
Normal file
|
|
@ -0,0 +1,54 @@
|
|||
package(default_visibility = ["//visibility:public"])
|
||||
|
||||
licenses(["notice"])
|
||||
|
||||
load(
|
||||
"@io_bazel_rules_go//go:def.bzl",
|
||||
"go_binary",
|
||||
"go_library",
|
||||
"go_test",
|
||||
"cgo_library",
|
||||
)
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = ["configmap_controller.go"],
|
||||
tags = ["automanaged"],
|
||||
deps = [
|
||||
"//federation/apis/federation/v1beta1:go_default_library",
|
||||
"//federation/client/clientset_generated/federation_release_1_5:go_default_library",
|
||||
"//federation/pkg/federation-controller/util:go_default_library",
|
||||
"//federation/pkg/federation-controller/util/eventsink:go_default_library",
|
||||
"//pkg/api:go_default_library",
|
||||
"//pkg/api/v1:go_default_library",
|
||||
"//pkg/client/cache:go_default_library",
|
||||
"//pkg/client/clientset_generated/release_1_5:go_default_library",
|
||||
"//pkg/client/record:go_default_library",
|
||||
"//pkg/controller:go_default_library",
|
||||
"//pkg/runtime:go_default_library",
|
||||
"//pkg/types:go_default_library",
|
||||
"//pkg/util/flowcontrol:go_default_library",
|
||||
"//pkg/watch:go_default_library",
|
||||
"//vendor:github.com/golang/glog",
|
||||
],
|
||||
)
|
||||
|
||||
go_test(
|
||||
name = "go_default_test",
|
||||
srcs = ["configmap_controller_test.go"],
|
||||
library = "go_default_library",
|
||||
tags = ["automanaged"],
|
||||
deps = [
|
||||
"//federation/apis/federation/v1beta1:go_default_library",
|
||||
"//federation/client/clientset_generated/federation_release_1_5/fake:go_default_library",
|
||||
"//federation/pkg/federation-controller/util:go_default_library",
|
||||
"//federation/pkg/federation-controller/util/test:go_default_library",
|
||||
"//pkg/api/v1:go_default_library",
|
||||
"//pkg/client/clientset_generated/release_1_5:go_default_library",
|
||||
"//pkg/client/clientset_generated/release_1_5/fake:go_default_library",
|
||||
"//pkg/runtime:go_default_library",
|
||||
"//pkg/types:go_default_library",
|
||||
"//pkg/util/wait:go_default_library",
|
||||
"//vendor:github.com/stretchr/testify/assert",
|
||||
],
|
||||
)
|
||||
315
vendor/k8s.io/kubernetes/federation/pkg/federation-controller/configmap/configmap_controller.go
generated
vendored
Normal file
315
vendor/k8s.io/kubernetes/federation/pkg/federation-controller/configmap/configmap_controller.go
generated
vendored
Normal file
|
|
@ -0,0 +1,315 @@
|
|||
/*
|
||||
Copyright 2016 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package configmap
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
federationapi "k8s.io/kubernetes/federation/apis/federation/v1beta1"
|
||||
federationclientset "k8s.io/kubernetes/federation/client/clientset_generated/federation_release_1_5"
|
||||
"k8s.io/kubernetes/federation/pkg/federation-controller/util"
|
||||
"k8s.io/kubernetes/federation/pkg/federation-controller/util/eventsink"
|
||||
"k8s.io/kubernetes/pkg/api"
|
||||
apiv1 "k8s.io/kubernetes/pkg/api/v1"
|
||||
"k8s.io/kubernetes/pkg/client/cache"
|
||||
kubeclientset "k8s.io/kubernetes/pkg/client/clientset_generated/release_1_5"
|
||||
"k8s.io/kubernetes/pkg/client/record"
|
||||
"k8s.io/kubernetes/pkg/controller"
|
||||
pkgruntime "k8s.io/kubernetes/pkg/runtime"
|
||||
"k8s.io/kubernetes/pkg/types"
|
||||
"k8s.io/kubernetes/pkg/util/flowcontrol"
|
||||
"k8s.io/kubernetes/pkg/watch"
|
||||
|
||||
"github.com/golang/glog"
|
||||
)
|
||||
|
||||
const (
|
||||
allClustersKey = "ALL_CLUSTERS"
|
||||
)
|
||||
|
||||
type ConfigMapController struct {
|
||||
// For triggering single configmap reconciliation. This is used when there is an
|
||||
// add/update/delete operation on a configmap in either federated API server or
|
||||
// in some member of the federation.
|
||||
configmapDeliverer *util.DelayingDeliverer
|
||||
|
||||
// For triggering all configmaps reconciliation. This is used when
|
||||
// a new cluster becomes available.
|
||||
clusterDeliverer *util.DelayingDeliverer
|
||||
|
||||
// Contains configmaps present in members of federation.
|
||||
configmapFederatedInformer util.FederatedInformer
|
||||
// For updating members of federation.
|
||||
federatedUpdater util.FederatedUpdater
|
||||
// Definitions of configmaps that should be federated.
|
||||
configmapInformerStore cache.Store
|
||||
// Informer controller for configmaps that should be federated.
|
||||
configmapInformerController cache.ControllerInterface
|
||||
|
||||
// Client to federated api server.
|
||||
federatedApiClient federationclientset.Interface
|
||||
|
||||
// Backoff manager for configmaps
|
||||
configmapBackoff *flowcontrol.Backoff
|
||||
|
||||
// For events
|
||||
eventRecorder record.EventRecorder
|
||||
|
||||
configmapReviewDelay time.Duration
|
||||
clusterAvailableDelay time.Duration
|
||||
smallDelay time.Duration
|
||||
updateTimeout time.Duration
|
||||
}
|
||||
|
||||
// NewConfigMapController returns a new configmap controller
|
||||
func NewConfigMapController(client federationclientset.Interface) *ConfigMapController {
|
||||
broadcaster := record.NewBroadcaster()
|
||||
broadcaster.StartRecordingToSink(eventsink.NewFederatedEventSink(client))
|
||||
recorder := broadcaster.NewRecorder(apiv1.EventSource{Component: "federated-configmaps-controller"})
|
||||
|
||||
configmapcontroller := &ConfigMapController{
|
||||
federatedApiClient: client,
|
||||
configmapReviewDelay: time.Second * 10,
|
||||
clusterAvailableDelay: time.Second * 20,
|
||||
smallDelay: time.Second * 3,
|
||||
updateTimeout: time.Second * 30,
|
||||
configmapBackoff: flowcontrol.NewBackOff(5*time.Second, time.Minute),
|
||||
eventRecorder: recorder,
|
||||
}
|
||||
|
||||
// Build delivereres for triggering reconciliations.
|
||||
configmapcontroller.configmapDeliverer = util.NewDelayingDeliverer()
|
||||
configmapcontroller.clusterDeliverer = util.NewDelayingDeliverer()
|
||||
|
||||
// Start informer on federated API servers on configmaps that should be federated.
|
||||
configmapcontroller.configmapInformerStore, configmapcontroller.configmapInformerController = cache.NewInformer(
|
||||
&cache.ListWatch{
|
||||
ListFunc: func(options apiv1.ListOptions) (pkgruntime.Object, error) {
|
||||
return client.Core().ConfigMaps(apiv1.NamespaceAll).List(options)
|
||||
},
|
||||
WatchFunc: func(options apiv1.ListOptions) (watch.Interface, error) {
|
||||
return client.Core().ConfigMaps(apiv1.NamespaceAll).Watch(options)
|
||||
},
|
||||
},
|
||||
&apiv1.ConfigMap{},
|
||||
controller.NoResyncPeriodFunc(),
|
||||
util.NewTriggerOnAllChanges(func(obj pkgruntime.Object) { configmapcontroller.deliverConfigMapObj(obj, 0, false) }))
|
||||
|
||||
// Federated informer on configmaps in members of federation.
|
||||
configmapcontroller.configmapFederatedInformer = util.NewFederatedInformer(
|
||||
client,
|
||||
func(cluster *federationapi.Cluster, targetClient kubeclientset.Interface) (cache.Store, cache.ControllerInterface) {
|
||||
return cache.NewInformer(
|
||||
&cache.ListWatch{
|
||||
ListFunc: func(options apiv1.ListOptions) (pkgruntime.Object, error) {
|
||||
return targetClient.Core().ConfigMaps(apiv1.NamespaceAll).List(options)
|
||||
},
|
||||
WatchFunc: func(options apiv1.ListOptions) (watch.Interface, error) {
|
||||
return targetClient.Core().ConfigMaps(apiv1.NamespaceAll).Watch(options)
|
||||
},
|
||||
},
|
||||
&apiv1.ConfigMap{},
|
||||
controller.NoResyncPeriodFunc(),
|
||||
// Trigger reconciliation whenever something in federated cluster is changed. In most cases it
|
||||
// would be just confirmation that some configmap opration succeeded.
|
||||
util.NewTriggerOnAllChanges(
|
||||
func(obj pkgruntime.Object) {
|
||||
configmapcontroller.deliverConfigMapObj(obj, configmapcontroller.configmapReviewDelay, false)
|
||||
},
|
||||
))
|
||||
},
|
||||
|
||||
&util.ClusterLifecycleHandlerFuncs{
|
||||
ClusterAvailable: func(cluster *federationapi.Cluster) {
|
||||
// When new cluster becomes available process all the configmaps again.
|
||||
configmapcontroller.clusterDeliverer.DeliverAt(allClustersKey, nil, time.Now().Add(configmapcontroller.clusterAvailableDelay))
|
||||
},
|
||||
},
|
||||
)
|
||||
|
||||
// Federated updater along with Create/Update/Delete operations.
|
||||
configmapcontroller.federatedUpdater = util.NewFederatedUpdater(configmapcontroller.configmapFederatedInformer,
|
||||
func(client kubeclientset.Interface, obj pkgruntime.Object) error {
|
||||
configmap := obj.(*apiv1.ConfigMap)
|
||||
_, err := client.Core().ConfigMaps(configmap.Namespace).Create(configmap)
|
||||
return err
|
||||
},
|
||||
func(client kubeclientset.Interface, obj pkgruntime.Object) error {
|
||||
configmap := obj.(*apiv1.ConfigMap)
|
||||
_, err := client.Core().ConfigMaps(configmap.Namespace).Update(configmap)
|
||||
return err
|
||||
},
|
||||
func(client kubeclientset.Interface, obj pkgruntime.Object) error {
|
||||
configmap := obj.(*apiv1.ConfigMap)
|
||||
err := client.Core().ConfigMaps(configmap.Namespace).Delete(configmap.Name, &apiv1.DeleteOptions{})
|
||||
return err
|
||||
})
|
||||
return configmapcontroller
|
||||
}
|
||||
|
||||
func (configmapcontroller *ConfigMapController) Run(stopChan <-chan struct{}) {
|
||||
go configmapcontroller.configmapInformerController.Run(stopChan)
|
||||
configmapcontroller.configmapFederatedInformer.Start()
|
||||
go func() {
|
||||
<-stopChan
|
||||
configmapcontroller.configmapFederatedInformer.Stop()
|
||||
}()
|
||||
configmapcontroller.configmapDeliverer.StartWithHandler(func(item *util.DelayingDelivererItem) {
|
||||
configmap := item.Value.(*types.NamespacedName)
|
||||
configmapcontroller.reconcileConfigMap(*configmap)
|
||||
})
|
||||
configmapcontroller.clusterDeliverer.StartWithHandler(func(_ *util.DelayingDelivererItem) {
|
||||
configmapcontroller.reconcileConfigMapsOnClusterChange()
|
||||
})
|
||||
util.StartBackoffGC(configmapcontroller.configmapBackoff, stopChan)
|
||||
}
|
||||
|
||||
func (configmapcontroller *ConfigMapController) deliverConfigMapObj(obj interface{}, delay time.Duration, failed bool) {
|
||||
configmap := obj.(*apiv1.ConfigMap)
|
||||
configmapcontroller.deliverConfigMap(types.NamespacedName{Namespace: configmap.Namespace, Name: configmap.Name}, delay, failed)
|
||||
}
|
||||
|
||||
// Adds backoff to delay if this delivery is related to some failure. Resets backoff if there was no failure.
|
||||
func (configmapcontroller *ConfigMapController) deliverConfigMap(configmap types.NamespacedName, delay time.Duration, failed bool) {
|
||||
key := configmap.String()
|
||||
if failed {
|
||||
configmapcontroller.configmapBackoff.Next(key, time.Now())
|
||||
delay = delay + configmapcontroller.configmapBackoff.Get(key)
|
||||
} else {
|
||||
configmapcontroller.configmapBackoff.Reset(key)
|
||||
}
|
||||
configmapcontroller.configmapDeliverer.DeliverAfter(key, &configmap, delay)
|
||||
}
|
||||
|
||||
// Check whether all data stores are in sync. False is returned if any of the informer/stores is not yet
|
||||
// synced with the corresponding api server.
|
||||
func (configmapcontroller *ConfigMapController) isSynced() bool {
|
||||
if !configmapcontroller.configmapFederatedInformer.ClustersSynced() {
|
||||
glog.V(2).Infof("Cluster list not synced")
|
||||
return false
|
||||
}
|
||||
clusters, err := configmapcontroller.configmapFederatedInformer.GetReadyClusters()
|
||||
if err != nil {
|
||||
glog.Errorf("Failed to get ready clusters: %v", err)
|
||||
return false
|
||||
}
|
||||
if !configmapcontroller.configmapFederatedInformer.GetTargetStore().ClustersSynced(clusters) {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// The function triggers reconciliation of all federated configmaps.
|
||||
func (configmapcontroller *ConfigMapController) reconcileConfigMapsOnClusterChange() {
|
||||
if !configmapcontroller.isSynced() {
|
||||
glog.V(4).Infof("Configmap controller not synced")
|
||||
configmapcontroller.clusterDeliverer.DeliverAt(allClustersKey, nil, time.Now().Add(configmapcontroller.clusterAvailableDelay))
|
||||
}
|
||||
for _, obj := range configmapcontroller.configmapInformerStore.List() {
|
||||
configmap := obj.(*apiv1.ConfigMap)
|
||||
configmapcontroller.deliverConfigMap(types.NamespacedName{Namespace: configmap.Namespace, Name: configmap.Name},
|
||||
configmapcontroller.smallDelay, false)
|
||||
}
|
||||
}
|
||||
|
||||
func (configmapcontroller *ConfigMapController) reconcileConfigMap(configmap types.NamespacedName) {
|
||||
|
||||
if !configmapcontroller.isSynced() {
|
||||
glog.V(4).Infof("Configmap controller not synced")
|
||||
configmapcontroller.deliverConfigMap(configmap, configmapcontroller.clusterAvailableDelay, false)
|
||||
return
|
||||
}
|
||||
|
||||
key := configmap.String()
|
||||
baseConfigMapObj, exist, err := configmapcontroller.configmapInformerStore.GetByKey(key)
|
||||
if err != nil {
|
||||
glog.Errorf("Failed to query main configmap store for %v: %v", key, err)
|
||||
configmapcontroller.deliverConfigMap(configmap, 0, true)
|
||||
return
|
||||
}
|
||||
|
||||
if !exist {
|
||||
// Not federated configmap, ignoring.
|
||||
glog.V(8).Infof("Skipping not federated config map: %s", key)
|
||||
return
|
||||
}
|
||||
baseConfigMap := baseConfigMapObj.(*apiv1.ConfigMap)
|
||||
|
||||
clusters, err := configmapcontroller.configmapFederatedInformer.GetReadyClusters()
|
||||
if err != nil {
|
||||
glog.Errorf("Failed to get cluster list: %v, retrying shortly", err)
|
||||
configmapcontroller.deliverConfigMap(configmap, configmapcontroller.clusterAvailableDelay, false)
|
||||
return
|
||||
}
|
||||
|
||||
operations := make([]util.FederatedOperation, 0)
|
||||
for _, cluster := range clusters {
|
||||
clusterConfigMapObj, found, err := configmapcontroller.configmapFederatedInformer.GetTargetStore().GetByKey(cluster.Name, key)
|
||||
if err != nil {
|
||||
glog.Errorf("Failed to get %s from %s: %v, retrying shortly", key, cluster.Name, err)
|
||||
configmapcontroller.deliverConfigMap(configmap, 0, true)
|
||||
return
|
||||
}
|
||||
|
||||
// Do not modify data.
|
||||
desiredConfigMap := &apiv1.ConfigMap{
|
||||
ObjectMeta: util.DeepCopyRelevantObjectMeta(baseConfigMap.ObjectMeta),
|
||||
Data: baseConfigMap.Data,
|
||||
}
|
||||
|
||||
if !found {
|
||||
configmapcontroller.eventRecorder.Eventf(baseConfigMap, api.EventTypeNormal, "CreateInCluster",
|
||||
"Creating configmap in cluster %s", cluster.Name)
|
||||
|
||||
operations = append(operations, util.FederatedOperation{
|
||||
Type: util.OperationTypeAdd,
|
||||
Obj: desiredConfigMap,
|
||||
ClusterName: cluster.Name,
|
||||
})
|
||||
} else {
|
||||
clusterConfigMap := clusterConfigMapObj.(*apiv1.ConfigMap)
|
||||
|
||||
// Update existing configmap, if needed.
|
||||
if !util.ConfigMapEquivalent(desiredConfigMap, clusterConfigMap) {
|
||||
configmapcontroller.eventRecorder.Eventf(baseConfigMap, api.EventTypeNormal, "UpdateInCluster",
|
||||
"Updating configmap in cluster %s", cluster.Name)
|
||||
operations = append(operations, util.FederatedOperation{
|
||||
Type: util.OperationTypeUpdate,
|
||||
Obj: desiredConfigMap,
|
||||
ClusterName: cluster.Name,
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if len(operations) == 0 {
|
||||
// Everything is in order
|
||||
glog.V(8).Infof("No operations needed for %s", key)
|
||||
return
|
||||
}
|
||||
err = configmapcontroller.federatedUpdater.UpdateWithOnError(operations, configmapcontroller.updateTimeout,
|
||||
func(op util.FederatedOperation, operror error) {
|
||||
configmapcontroller.eventRecorder.Eventf(baseConfigMap, api.EventTypeNormal, "UpdateInClusterFailed",
|
||||
"ConfigMap update in cluster %s failed: %v", op.ClusterName, operror)
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
glog.Errorf("Failed to execute updates for %s: %v, retrying shortly", key, err)
|
||||
configmapcontroller.deliverConfigMap(configmap, 0, true)
|
||||
return
|
||||
}
|
||||
}
|
||||
142
vendor/k8s.io/kubernetes/federation/pkg/federation-controller/configmap/configmap_controller_test.go
generated
vendored
Normal file
142
vendor/k8s.io/kubernetes/federation/pkg/federation-controller/configmap/configmap_controller_test.go
generated
vendored
Normal file
|
|
@ -0,0 +1,142 @@
|
|||
/*
|
||||
Copyright 2016 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package configmap
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
federationapi "k8s.io/kubernetes/federation/apis/federation/v1beta1"
|
||||
fakefedclientset "k8s.io/kubernetes/federation/client/clientset_generated/federation_release_1_5/fake"
|
||||
"k8s.io/kubernetes/federation/pkg/federation-controller/util"
|
||||
. "k8s.io/kubernetes/federation/pkg/federation-controller/util/test"
|
||||
apiv1 "k8s.io/kubernetes/pkg/api/v1"
|
||||
kubeclientset "k8s.io/kubernetes/pkg/client/clientset_generated/release_1_5"
|
||||
fakekubeclientset "k8s.io/kubernetes/pkg/client/clientset_generated/release_1_5/fake"
|
||||
"k8s.io/kubernetes/pkg/runtime"
|
||||
"k8s.io/kubernetes/pkg/types"
|
||||
"k8s.io/kubernetes/pkg/util/wait"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestConfigMapController(t *testing.T) {
|
||||
cluster1 := NewCluster("cluster1", apiv1.ConditionTrue)
|
||||
cluster2 := NewCluster("cluster2", apiv1.ConditionTrue)
|
||||
|
||||
fakeClient := &fakefedclientset.Clientset{}
|
||||
RegisterFakeList("clusters", &fakeClient.Fake, &federationapi.ClusterList{Items: []federationapi.Cluster{*cluster1}})
|
||||
RegisterFakeList("configmaps", &fakeClient.Fake, &apiv1.ConfigMapList{Items: []apiv1.ConfigMap{}})
|
||||
configmapWatch := RegisterFakeWatch("configmaps", &fakeClient.Fake)
|
||||
clusterWatch := RegisterFakeWatch("clusters", &fakeClient.Fake)
|
||||
|
||||
cluster1Client := &fakekubeclientset.Clientset{}
|
||||
cluster1Watch := RegisterFakeWatch("configmaps", &cluster1Client.Fake)
|
||||
RegisterFakeList("configmaps", &cluster1Client.Fake, &apiv1.ConfigMapList{Items: []apiv1.ConfigMap{}})
|
||||
cluster1CreateChan := RegisterFakeCopyOnCreate("configmaps", &cluster1Client.Fake, cluster1Watch)
|
||||
cluster1UpdateChan := RegisterFakeCopyOnUpdate("configmaps", &cluster1Client.Fake, cluster1Watch)
|
||||
|
||||
cluster2Client := &fakekubeclientset.Clientset{}
|
||||
cluster2Watch := RegisterFakeWatch("configmaps", &cluster2Client.Fake)
|
||||
RegisterFakeList("configmaps", &cluster2Client.Fake, &apiv1.ConfigMapList{Items: []apiv1.ConfigMap{}})
|
||||
cluster2CreateChan := RegisterFakeCopyOnCreate("configmaps", &cluster2Client.Fake, cluster2Watch)
|
||||
|
||||
configmapController := NewConfigMapController(fakeClient)
|
||||
informer := ToFederatedInformerForTestOnly(configmapController.configmapFederatedInformer)
|
||||
informer.SetClientFactory(func(cluster *federationapi.Cluster) (kubeclientset.Interface, error) {
|
||||
switch cluster.Name {
|
||||
case cluster1.Name:
|
||||
return cluster1Client, nil
|
||||
case cluster2.Name:
|
||||
return cluster2Client, nil
|
||||
default:
|
||||
return nil, fmt.Errorf("Unknown cluster")
|
||||
}
|
||||
})
|
||||
|
||||
configmapController.clusterAvailableDelay = time.Second
|
||||
configmapController.configmapReviewDelay = 50 * time.Millisecond
|
||||
configmapController.smallDelay = 20 * time.Millisecond
|
||||
configmapController.updateTimeout = 5 * time.Second
|
||||
|
||||
stop := make(chan struct{})
|
||||
configmapController.Run(stop)
|
||||
|
||||
configmap1 := &apiv1.ConfigMap{
|
||||
ObjectMeta: apiv1.ObjectMeta{
|
||||
Name: "test-configmap",
|
||||
Namespace: "ns",
|
||||
SelfLink: "/api/v1/namespaces/ns/configmaps/test-configmap",
|
||||
},
|
||||
Data: map[string]string{
|
||||
"A": "ala ma kota",
|
||||
"B": "quick brown fox",
|
||||
},
|
||||
}
|
||||
|
||||
// Test add federated configmap.
|
||||
configmapWatch.Add(configmap1)
|
||||
createdConfigMap := GetConfigMapFromChan(cluster1CreateChan)
|
||||
assert.NotNil(t, createdConfigMap)
|
||||
assert.Equal(t, configmap1.Namespace, createdConfigMap.Namespace)
|
||||
assert.Equal(t, configmap1.Name, createdConfigMap.Name)
|
||||
assert.True(t, util.ConfigMapEquivalent(configmap1, createdConfigMap))
|
||||
|
||||
// Wait for the configmap to appear in the informer store
|
||||
err := WaitForStoreUpdate(
|
||||
configmapController.configmapFederatedInformer.GetTargetStore(),
|
||||
cluster1.Name, types.NamespacedName{Namespace: configmap1.Namespace, Name: configmap1.Name}.String(), wait.ForeverTestTimeout)
|
||||
assert.Nil(t, err, "configmap should have appeared in the informer store")
|
||||
|
||||
// Test update federated configmap.
|
||||
configmap1.Annotations = map[string]string{
|
||||
"A": "B",
|
||||
}
|
||||
configmapWatch.Modify(configmap1)
|
||||
updatedConfigMap := GetConfigMapFromChan(cluster1UpdateChan)
|
||||
assert.NotNil(t, updatedConfigMap)
|
||||
assert.Equal(t, configmap1.Name, updatedConfigMap.Name)
|
||||
assert.Equal(t, configmap1.Namespace, updatedConfigMap.Namespace)
|
||||
assert.True(t, util.ConfigMapEquivalent(configmap1, updatedConfigMap))
|
||||
|
||||
// Test update federated configmap.
|
||||
configmap1.Data = map[string]string{
|
||||
"config": "myconfigurationfile",
|
||||
}
|
||||
configmapWatch.Modify(configmap1)
|
||||
updatedConfigMap2 := GetConfigMapFromChan(cluster1UpdateChan)
|
||||
assert.NotNil(t, updatedConfigMap)
|
||||
assert.Equal(t, configmap1.Name, updatedConfigMap.Name)
|
||||
assert.Equal(t, configmap1.Namespace, updatedConfigMap.Namespace)
|
||||
assert.True(t, util.ConfigMapEquivalent(configmap1, updatedConfigMap2))
|
||||
|
||||
// Test add cluster
|
||||
clusterWatch.Add(cluster2)
|
||||
createdConfigMap2 := GetConfigMapFromChan(cluster2CreateChan)
|
||||
assert.NotNil(t, createdConfigMap2)
|
||||
assert.Equal(t, configmap1.Name, createdConfigMap2.Name)
|
||||
assert.Equal(t, configmap1.Namespace, createdConfigMap2.Namespace)
|
||||
assert.True(t, util.ConfigMapEquivalent(configmap1, createdConfigMap2))
|
||||
|
||||
close(stop)
|
||||
}
|
||||
|
||||
func GetConfigMapFromChan(c chan runtime.Object) *apiv1.ConfigMap {
|
||||
configmap := GetObjectFromChan(c).(*apiv1.ConfigMap)
|
||||
return configmap
|
||||
}
|
||||
60
vendor/k8s.io/kubernetes/federation/pkg/federation-controller/daemonset/BUILD
generated
vendored
Normal file
60
vendor/k8s.io/kubernetes/federation/pkg/federation-controller/daemonset/BUILD
generated
vendored
Normal file
|
|
@ -0,0 +1,60 @@
|
|||
package(default_visibility = ["//visibility:public"])
|
||||
|
||||
licenses(["notice"])
|
||||
|
||||
load(
|
||||
"@io_bazel_rules_go//go:def.bzl",
|
||||
"go_binary",
|
||||
"go_library",
|
||||
"go_test",
|
||||
"cgo_library",
|
||||
)
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = ["daemonset_controller.go"],
|
||||
tags = ["automanaged"],
|
||||
deps = [
|
||||
"//federation/apis/federation/v1beta1:go_default_library",
|
||||
"//federation/client/clientset_generated/federation_release_1_5:go_default_library",
|
||||
"//federation/pkg/federation-controller/util:go_default_library",
|
||||
"//federation/pkg/federation-controller/util/deletionhelper:go_default_library",
|
||||
"//federation/pkg/federation-controller/util/eventsink:go_default_library",
|
||||
"//pkg/api:go_default_library",
|
||||
"//pkg/api/errors:go_default_library",
|
||||
"//pkg/api/v1:go_default_library",
|
||||
"//pkg/apis/extensions/v1beta1:go_default_library",
|
||||
"//pkg/client/cache:go_default_library",
|
||||
"//pkg/client/clientset_generated/release_1_5:go_default_library",
|
||||
"//pkg/client/record:go_default_library",
|
||||
"//pkg/controller:go_default_library",
|
||||
"//pkg/conversion:go_default_library",
|
||||
"//pkg/runtime:go_default_library",
|
||||
"//pkg/types:go_default_library",
|
||||
"//pkg/util/flowcontrol:go_default_library",
|
||||
"//pkg/watch:go_default_library",
|
||||
"//vendor:github.com/golang/glog",
|
||||
],
|
||||
)
|
||||
|
||||
go_test(
|
||||
name = "go_default_test",
|
||||
srcs = ["daemonset_controller_test.go"],
|
||||
library = "go_default_library",
|
||||
tags = ["automanaged"],
|
||||
deps = [
|
||||
"//federation/apis/federation/v1beta1:go_default_library",
|
||||
"//federation/client/clientset_generated/federation_release_1_5/fake:go_default_library",
|
||||
"//federation/pkg/federation-controller/util:go_default_library",
|
||||
"//federation/pkg/federation-controller/util/deletionhelper:go_default_library",
|
||||
"//federation/pkg/federation-controller/util/test:go_default_library",
|
||||
"//pkg/api/v1:go_default_library",
|
||||
"//pkg/apis/extensions/v1beta1:go_default_library",
|
||||
"//pkg/apis/meta/v1:go_default_library",
|
||||
"//pkg/client/clientset_generated/release_1_5:go_default_library",
|
||||
"//pkg/client/clientset_generated/release_1_5/fake:go_default_library",
|
||||
"//pkg/runtime:go_default_library",
|
||||
"//pkg/util/wait:go_default_library",
|
||||
"//vendor:github.com/stretchr/testify/assert",
|
||||
],
|
||||
)
|
||||
472
vendor/k8s.io/kubernetes/federation/pkg/federation-controller/daemonset/daemonset_controller.go
generated
vendored
Normal file
472
vendor/k8s.io/kubernetes/federation/pkg/federation-controller/daemonset/daemonset_controller.go
generated
vendored
Normal file
|
|
@ -0,0 +1,472 @@
|
|||
/*
|
||||
Copyright 2016 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package daemonset
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
"time"
|
||||
|
||||
federationapi "k8s.io/kubernetes/federation/apis/federation/v1beta1"
|
||||
federationclientset "k8s.io/kubernetes/federation/client/clientset_generated/federation_release_1_5"
|
||||
"k8s.io/kubernetes/federation/pkg/federation-controller/util"
|
||||
"k8s.io/kubernetes/federation/pkg/federation-controller/util/deletionhelper"
|
||||
"k8s.io/kubernetes/federation/pkg/federation-controller/util/eventsink"
|
||||
"k8s.io/kubernetes/pkg/api"
|
||||
"k8s.io/kubernetes/pkg/api/errors"
|
||||
apiv1 "k8s.io/kubernetes/pkg/api/v1"
|
||||
extensionsv1 "k8s.io/kubernetes/pkg/apis/extensions/v1beta1"
|
||||
"k8s.io/kubernetes/pkg/client/cache"
|
||||
kubeclientset "k8s.io/kubernetes/pkg/client/clientset_generated/release_1_5"
|
||||
"k8s.io/kubernetes/pkg/client/record"
|
||||
"k8s.io/kubernetes/pkg/controller"
|
||||
"k8s.io/kubernetes/pkg/conversion"
|
||||
pkgruntime "k8s.io/kubernetes/pkg/runtime"
|
||||
"k8s.io/kubernetes/pkg/types"
|
||||
"k8s.io/kubernetes/pkg/util/flowcontrol"
|
||||
"k8s.io/kubernetes/pkg/watch"
|
||||
|
||||
"github.com/golang/glog"
|
||||
)
|
||||
|
||||
const (
|
||||
allClustersKey = "ALL_CLUSTERS"
|
||||
)
|
||||
|
||||
type DaemonSetController struct {
|
||||
// For triggering single daemonset reconciliation. This is used when there is an
|
||||
// add/update/delete operation on a daemonset in either federated API server or
|
||||
// in some member of the federation.
|
||||
daemonsetDeliverer *util.DelayingDeliverer
|
||||
|
||||
// For triggering all daemonsets reconciliation. This is used when
|
||||
// a new cluster becomes available.
|
||||
clusterDeliverer *util.DelayingDeliverer
|
||||
|
||||
// Contains daemonsets present in members of federation.
|
||||
daemonsetFederatedInformer util.FederatedInformer
|
||||
// For updating members of federation.
|
||||
federatedUpdater util.FederatedUpdater
|
||||
// Definitions of daemonsets that should be federated.
|
||||
daemonsetInformerStore cache.Store
|
||||
// Informer controller for daemonsets that should be federated.
|
||||
daemonsetInformerController cache.ControllerInterface
|
||||
|
||||
// Client to federated api server.
|
||||
federatedApiClient federationclientset.Interface
|
||||
|
||||
// Backoff manager for daemonsets
|
||||
daemonsetBackoff *flowcontrol.Backoff
|
||||
|
||||
// For events
|
||||
eventRecorder record.EventRecorder
|
||||
|
||||
deletionHelper *deletionhelper.DeletionHelper
|
||||
|
||||
daemonsetReviewDelay time.Duration
|
||||
clusterAvailableDelay time.Duration
|
||||
smallDelay time.Duration
|
||||
updateTimeout time.Duration
|
||||
}
|
||||
|
||||
// NewDaemonSetController returns a new daemonset controller
|
||||
func NewDaemonSetController(client federationclientset.Interface) *DaemonSetController {
|
||||
broadcaster := record.NewBroadcaster()
|
||||
broadcaster.StartRecordingToSink(eventsink.NewFederatedEventSink(client))
|
||||
recorder := broadcaster.NewRecorder(apiv1.EventSource{Component: "federated-daemonset-controller"})
|
||||
|
||||
daemonsetcontroller := &DaemonSetController{
|
||||
federatedApiClient: client,
|
||||
daemonsetReviewDelay: time.Second * 10,
|
||||
clusterAvailableDelay: time.Second * 20,
|
||||
smallDelay: time.Second * 3,
|
||||
updateTimeout: time.Second * 30,
|
||||
daemonsetBackoff: flowcontrol.NewBackOff(5*time.Second, time.Minute),
|
||||
eventRecorder: recorder,
|
||||
}
|
||||
|
||||
// Build deliverers for triggering reconciliations.
|
||||
daemonsetcontroller.daemonsetDeliverer = util.NewDelayingDeliverer()
|
||||
daemonsetcontroller.clusterDeliverer = util.NewDelayingDeliverer()
|
||||
|
||||
// Start informer in federated API servers on daemonsets that should be federated.
|
||||
daemonsetcontroller.daemonsetInformerStore, daemonsetcontroller.daemonsetInformerController = cache.NewInformer(
|
||||
&cache.ListWatch{
|
||||
ListFunc: func(options apiv1.ListOptions) (pkgruntime.Object, error) {
|
||||
return client.Extensions().DaemonSets(apiv1.NamespaceAll).List(options)
|
||||
},
|
||||
WatchFunc: func(options apiv1.ListOptions) (watch.Interface, error) {
|
||||
return client.Extensions().DaemonSets(apiv1.NamespaceAll).Watch(options)
|
||||
},
|
||||
},
|
||||
&extensionsv1.DaemonSet{},
|
||||
controller.NoResyncPeriodFunc(),
|
||||
util.NewTriggerOnAllChanges(func(obj pkgruntime.Object) { daemonsetcontroller.deliverDaemonSetObj(obj, 0, false) }))
|
||||
|
||||
// Federated informer on daemonsets in members of federation.
|
||||
daemonsetcontroller.daemonsetFederatedInformer = util.NewFederatedInformer(
|
||||
client,
|
||||
func(cluster *federationapi.Cluster, targetClient kubeclientset.Interface) (cache.Store, cache.ControllerInterface) {
|
||||
return cache.NewInformer(
|
||||
&cache.ListWatch{
|
||||
ListFunc: func(options apiv1.ListOptions) (pkgruntime.Object, error) {
|
||||
return targetClient.Extensions().DaemonSets(apiv1.NamespaceAll).List(options)
|
||||
},
|
||||
WatchFunc: func(options apiv1.ListOptions) (watch.Interface, error) {
|
||||
return targetClient.Extensions().DaemonSets(apiv1.NamespaceAll).Watch(options)
|
||||
},
|
||||
},
|
||||
&extensionsv1.DaemonSet{},
|
||||
controller.NoResyncPeriodFunc(),
|
||||
// Trigger reconciliation whenever something in federated cluster is changed. In most cases it
|
||||
// would be just confirmation that some daemonset opration succeeded.
|
||||
util.NewTriggerOnAllChanges(
|
||||
func(obj pkgruntime.Object) {
|
||||
daemonsetcontroller.deliverDaemonSetObj(obj, daemonsetcontroller.daemonsetReviewDelay, false)
|
||||
},
|
||||
))
|
||||
},
|
||||
|
||||
&util.ClusterLifecycleHandlerFuncs{
|
||||
ClusterAvailable: func(cluster *federationapi.Cluster) {
|
||||
// When new cluster becomes available process all the daemonsets again.
|
||||
daemonsetcontroller.clusterDeliverer.DeliverAt(allClustersKey, nil, time.Now().Add(daemonsetcontroller.clusterAvailableDelay))
|
||||
},
|
||||
},
|
||||
)
|
||||
|
||||
// Federated updater along with Create/Update/Delete operations.
|
||||
daemonsetcontroller.federatedUpdater = util.NewFederatedUpdater(daemonsetcontroller.daemonsetFederatedInformer,
|
||||
func(client kubeclientset.Interface, obj pkgruntime.Object) error {
|
||||
daemonset := obj.(*extensionsv1.DaemonSet)
|
||||
glog.V(4).Infof("Attempting to create daemonset: %s/%s", daemonset.Namespace, daemonset.Name)
|
||||
_, err := client.Extensions().DaemonSets(daemonset.Namespace).Create(daemonset)
|
||||
if err != nil {
|
||||
glog.Errorf("Error creating daemonset %s/%s/: %v", daemonset.Namespace, daemonset.Name, err)
|
||||
} else {
|
||||
glog.V(4).Infof("Successfully created deamonset %s/%s", daemonset.Namespace, daemonset.Name)
|
||||
}
|
||||
return err
|
||||
},
|
||||
func(client kubeclientset.Interface, obj pkgruntime.Object) error {
|
||||
daemonset := obj.(*extensionsv1.DaemonSet)
|
||||
glog.V(4).Infof("Attempting to update daemonset: %s/%s", daemonset.Namespace, daemonset.Name)
|
||||
_, err := client.Extensions().DaemonSets(daemonset.Namespace).Update(daemonset)
|
||||
if err != nil {
|
||||
glog.Errorf("Error updating daemonset %s/%s/: %v", daemonset.Namespace, daemonset.Name, err)
|
||||
} else {
|
||||
glog.V(4).Infof("Successfully updating deamonset %s/%s", daemonset.Namespace, daemonset.Name)
|
||||
}
|
||||
return err
|
||||
},
|
||||
func(client kubeclientset.Interface, obj pkgruntime.Object) error {
|
||||
daemonset := obj.(*extensionsv1.DaemonSet)
|
||||
glog.V(4).Infof("Attempting to delete daemonset: %s/%s", daemonset.Namespace, daemonset.Name)
|
||||
err := client.Extensions().DaemonSets(daemonset.Namespace).Delete(daemonset.Name, &apiv1.DeleteOptions{})
|
||||
if err != nil {
|
||||
glog.Errorf("Error deleting daemonset %s/%s/: %v", daemonset.Namespace, daemonset.Name, err)
|
||||
} else {
|
||||
glog.V(4).Infof("Successfully deleting deamonset %s/%s", daemonset.Namespace, daemonset.Name)
|
||||
}
|
||||
return err
|
||||
})
|
||||
|
||||
daemonsetcontroller.deletionHelper = deletionhelper.NewDeletionHelper(
|
||||
daemonsetcontroller.hasFinalizerFunc,
|
||||
daemonsetcontroller.removeFinalizerFunc,
|
||||
daemonsetcontroller.addFinalizerFunc,
|
||||
// objNameFunc
|
||||
func(obj pkgruntime.Object) string {
|
||||
daemonset := obj.(*extensionsv1.DaemonSet)
|
||||
return daemonset.Name
|
||||
},
|
||||
daemonsetcontroller.updateTimeout,
|
||||
daemonsetcontroller.eventRecorder,
|
||||
daemonsetcontroller.daemonsetFederatedInformer,
|
||||
daemonsetcontroller.federatedUpdater,
|
||||
)
|
||||
|
||||
return daemonsetcontroller
|
||||
}
|
||||
|
||||
// Returns true if the given object has the given finalizer in its ObjectMeta.
|
||||
func (daemonsetcontroller *DaemonSetController) hasFinalizerFunc(obj pkgruntime.Object, finalizer string) bool {
|
||||
daemonset := obj.(*extensionsv1.DaemonSet)
|
||||
for i := range daemonset.ObjectMeta.Finalizers {
|
||||
if string(daemonset.ObjectMeta.Finalizers[i]) == finalizer {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// Removes the finalizer from the given objects ObjectMeta.
|
||||
// Assumes that the given object is a daemonset.
|
||||
func (daemonsetcontroller *DaemonSetController) removeFinalizerFunc(obj pkgruntime.Object, finalizer string) (pkgruntime.Object, error) {
|
||||
daemonset := obj.(*extensionsv1.DaemonSet)
|
||||
newFinalizers := []string{}
|
||||
hasFinalizer := false
|
||||
for i := range daemonset.ObjectMeta.Finalizers {
|
||||
if string(daemonset.ObjectMeta.Finalizers[i]) != finalizer {
|
||||
newFinalizers = append(newFinalizers, daemonset.ObjectMeta.Finalizers[i])
|
||||
} else {
|
||||
hasFinalizer = true
|
||||
}
|
||||
}
|
||||
if !hasFinalizer {
|
||||
// Nothing to do.
|
||||
return obj, nil
|
||||
}
|
||||
daemonset.ObjectMeta.Finalizers = newFinalizers
|
||||
daemonset, err := daemonsetcontroller.federatedApiClient.Extensions().DaemonSets(daemonset.Namespace).Update(daemonset)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to remove finalizer %s from daemonset %s: %v", finalizer, daemonset.Name, err)
|
||||
}
|
||||
return daemonset, nil
|
||||
}
|
||||
|
||||
// Adds the given finalizer to the given objects ObjectMeta.
|
||||
// Assumes that the given object is a daemonset.
|
||||
func (daemonsetcontroller *DaemonSetController) addFinalizerFunc(obj pkgruntime.Object, finalizer string) (pkgruntime.Object, error) {
|
||||
daemonset := obj.(*extensionsv1.DaemonSet)
|
||||
daemonset.ObjectMeta.Finalizers = append(daemonset.ObjectMeta.Finalizers, finalizer)
|
||||
daemonset, err := daemonsetcontroller.federatedApiClient.Extensions().DaemonSets(daemonset.Namespace).Update(daemonset)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to add finalizer %s to daemonset %s: %v", finalizer, daemonset.Name, err)
|
||||
}
|
||||
return daemonset, nil
|
||||
}
|
||||
|
||||
func (daemonsetcontroller *DaemonSetController) Run(stopChan <-chan struct{}) {
|
||||
glog.V(1).Infof("Starting daemonset controllr")
|
||||
go daemonsetcontroller.daemonsetInformerController.Run(stopChan)
|
||||
|
||||
glog.V(1).Infof("Starting daemonset federated informer")
|
||||
daemonsetcontroller.daemonsetFederatedInformer.Start()
|
||||
go func() {
|
||||
<-stopChan
|
||||
daemonsetcontroller.daemonsetFederatedInformer.Stop()
|
||||
}()
|
||||
glog.V(1).Infof("Starting daemonset deliverers")
|
||||
daemonsetcontroller.daemonsetDeliverer.StartWithHandler(func(item *util.DelayingDelivererItem) {
|
||||
daemonset := item.Value.(*types.NamespacedName)
|
||||
glog.V(4).Infof("Trigerring reconciliation of daemonset %s", daemonset.String())
|
||||
daemonsetcontroller.reconcileDaemonSet(daemonset.Namespace, daemonset.Name)
|
||||
})
|
||||
daemonsetcontroller.clusterDeliverer.StartWithHandler(func(_ *util.DelayingDelivererItem) {
|
||||
glog.V(4).Infof("Triggering reconciliation of all daemonsets")
|
||||
daemonsetcontroller.reconcileDaemonSetsOnClusterChange()
|
||||
})
|
||||
util.StartBackoffGC(daemonsetcontroller.daemonsetBackoff, stopChan)
|
||||
}
|
||||
|
||||
func getDaemonSetKey(namespace, name string) string {
|
||||
return types.NamespacedName{
|
||||
Namespace: namespace,
|
||||
Name: name,
|
||||
}.String()
|
||||
}
|
||||
|
||||
func (daemonsetcontroller *DaemonSetController) deliverDaemonSetObj(obj interface{}, delay time.Duration, failed bool) {
|
||||
daemonset := obj.(*extensionsv1.DaemonSet)
|
||||
daemonsetcontroller.deliverDaemonSet(daemonset.Namespace, daemonset.Name, delay, failed)
|
||||
}
|
||||
|
||||
// Adds backoff to delay if this delivery is related to some failure. Resets backoff if there was no failure.
|
||||
func (daemonsetcontroller *DaemonSetController) deliverDaemonSet(namespace string, name string, delay time.Duration, failed bool) {
|
||||
key := getDaemonSetKey(namespace, name)
|
||||
if failed {
|
||||
daemonsetcontroller.daemonsetBackoff.Next(key, time.Now())
|
||||
delay = delay + daemonsetcontroller.daemonsetBackoff.Get(key)
|
||||
} else {
|
||||
daemonsetcontroller.daemonsetBackoff.Reset(key)
|
||||
}
|
||||
daemonsetcontroller.daemonsetDeliverer.DeliverAfter(key,
|
||||
&types.NamespacedName{Namespace: namespace, Name: name}, delay)
|
||||
}
|
||||
|
||||
// Check whether all data stores are in sync. False is returned if any of the informer/stores is not yet
|
||||
// synced with the corresponding api server.
|
||||
func (daemonsetcontroller *DaemonSetController) isSynced() bool {
|
||||
if !daemonsetcontroller.daemonsetFederatedInformer.ClustersSynced() {
|
||||
glog.V(2).Infof("Cluster list not synced")
|
||||
return false
|
||||
}
|
||||
clusters, err := daemonsetcontroller.daemonsetFederatedInformer.GetReadyClusters()
|
||||
if err != nil {
|
||||
glog.Errorf("Failed to get ready clusters: %v", err)
|
||||
return false
|
||||
}
|
||||
if !daemonsetcontroller.daemonsetFederatedInformer.GetTargetStore().ClustersSynced(clusters) {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// The function triggers reconciliation of all federated daemonsets.
|
||||
func (daemonsetcontroller *DaemonSetController) reconcileDaemonSetsOnClusterChange() {
|
||||
if !daemonsetcontroller.isSynced() {
|
||||
daemonsetcontroller.clusterDeliverer.DeliverAt(allClustersKey, nil, time.Now().Add(daemonsetcontroller.clusterAvailableDelay))
|
||||
}
|
||||
for _, obj := range daemonsetcontroller.daemonsetInformerStore.List() {
|
||||
daemonset := obj.(*extensionsv1.DaemonSet)
|
||||
daemonsetcontroller.deliverDaemonSet(daemonset.Namespace, daemonset.Name, daemonsetcontroller.smallDelay, false)
|
||||
}
|
||||
}
|
||||
|
||||
func (daemonsetcontroller *DaemonSetController) reconcileDaemonSet(namespace string, daemonsetName string) {
|
||||
glog.V(4).Infof("Reconciling daemonset %s/%s", namespace, daemonsetName)
|
||||
|
||||
if !daemonsetcontroller.isSynced() {
|
||||
glog.V(4).Infof("Daemonset controller is not synced")
|
||||
daemonsetcontroller.deliverDaemonSet(namespace, daemonsetName, daemonsetcontroller.clusterAvailableDelay, false)
|
||||
return
|
||||
}
|
||||
|
||||
key := getDaemonSetKey(namespace, daemonsetName)
|
||||
baseDaemonSetObjFromStore, exist, err := daemonsetcontroller.daemonsetInformerStore.GetByKey(key)
|
||||
if err != nil {
|
||||
glog.Errorf("Failed to query main daemonset store for %v: %v", key, err)
|
||||
daemonsetcontroller.deliverDaemonSet(namespace, daemonsetName, 0, true)
|
||||
return
|
||||
}
|
||||
|
||||
if !exist {
|
||||
glog.V(4).Infof("Skipping daemonset %s/%s - not federated", namespace, daemonsetName)
|
||||
// Not federated daemonset, ignoring.
|
||||
return
|
||||
}
|
||||
baseDaemonSetObj, err := conversion.NewCloner().DeepCopy(baseDaemonSetObjFromStore)
|
||||
baseDaemonSet, ok := baseDaemonSetObj.(*extensionsv1.DaemonSet)
|
||||
if err != nil || !ok {
|
||||
glog.Errorf("Error in retrieving obj %s from store: %v, %v", daemonsetName, ok, err)
|
||||
daemonsetcontroller.deliverDaemonSet(namespace, daemonsetName, 0, true)
|
||||
return
|
||||
}
|
||||
if baseDaemonSet.DeletionTimestamp != nil {
|
||||
if err := daemonsetcontroller.delete(baseDaemonSet); err != nil {
|
||||
glog.Errorf("Failed to delete %s: %v", daemonsetName, err)
|
||||
daemonsetcontroller.eventRecorder.Eventf(baseDaemonSet, api.EventTypeNormal, "DeleteFailed",
|
||||
"DaemonSet delete failed: %v", err)
|
||||
daemonsetcontroller.deliverDaemonSet(namespace, daemonsetName, 0, true)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
glog.V(3).Infof("Ensuring delete object from underlying clusters finalizer for daemonset: %s",
|
||||
baseDaemonSet.Name)
|
||||
// Add the required finalizers before creating a daemonset in underlying clusters.
|
||||
updatedDaemonSetObj, err := daemonsetcontroller.deletionHelper.EnsureFinalizers(baseDaemonSet)
|
||||
if err != nil {
|
||||
glog.Errorf("Failed to ensure delete object from underlying clusters finalizer in daemonset %s: %v",
|
||||
baseDaemonSet.Name, err)
|
||||
daemonsetcontroller.deliverDaemonSet(namespace, daemonsetName, 0, false)
|
||||
return
|
||||
}
|
||||
baseDaemonSet = updatedDaemonSetObj.(*extensionsv1.DaemonSet)
|
||||
|
||||
glog.V(3).Infof("Syncing daemonset %s in underlying clusters", baseDaemonSet.Name)
|
||||
|
||||
clusters, err := daemonsetcontroller.daemonsetFederatedInformer.GetReadyClusters()
|
||||
if err != nil {
|
||||
glog.Errorf("Failed to get cluster list: %v", err)
|
||||
daemonsetcontroller.deliverDaemonSet(namespace, daemonsetName, daemonsetcontroller.clusterAvailableDelay, false)
|
||||
return
|
||||
}
|
||||
|
||||
operations := make([]util.FederatedOperation, 0)
|
||||
for _, cluster := range clusters {
|
||||
clusterDaemonSetObj, found, err := daemonsetcontroller.daemonsetFederatedInformer.GetTargetStore().GetByKey(cluster.Name, key)
|
||||
if err != nil {
|
||||
glog.Errorf("Failed to get %s from %s: %v", key, cluster.Name, err)
|
||||
daemonsetcontroller.deliverDaemonSet(namespace, daemonsetName, 0, true)
|
||||
return
|
||||
}
|
||||
|
||||
// Do not modify. Otherwise make a deep copy.
|
||||
desiredDaemonSet := &extensionsv1.DaemonSet{
|
||||
ObjectMeta: util.DeepCopyRelevantObjectMeta(baseDaemonSet.ObjectMeta),
|
||||
Spec: util.DeepCopyApiTypeOrPanic(baseDaemonSet.Spec).(extensionsv1.DaemonSetSpec),
|
||||
}
|
||||
|
||||
if !found {
|
||||
glog.V(4).Infof("Creating daemonset %s/%s in cluster %s", namespace, daemonsetName, cluster.Name)
|
||||
|
||||
daemonsetcontroller.eventRecorder.Eventf(baseDaemonSet, api.EventTypeNormal, "CreateInCluster",
|
||||
"Creating daemonset in cluster %s", cluster.Name)
|
||||
|
||||
operations = append(operations, util.FederatedOperation{
|
||||
Type: util.OperationTypeAdd,
|
||||
Obj: desiredDaemonSet,
|
||||
ClusterName: cluster.Name,
|
||||
})
|
||||
} else {
|
||||
clusterDaemonSet := clusterDaemonSetObj.(*extensionsv1.DaemonSet)
|
||||
|
||||
// Update existing daemonset, if needed.
|
||||
if !util.ObjectMetaEquivalent(desiredDaemonSet.ObjectMeta, clusterDaemonSet.ObjectMeta) ||
|
||||
!reflect.DeepEqual(desiredDaemonSet.Spec, clusterDaemonSet.Spec) {
|
||||
|
||||
glog.V(4).Infof("Upadting daemonset %s/%s in cluster %s", namespace, daemonsetName, cluster.Name)
|
||||
daemonsetcontroller.eventRecorder.Eventf(baseDaemonSet, api.EventTypeNormal, "UpdateInCluster",
|
||||
"Updating daemonset in cluster %s", cluster.Name)
|
||||
operations = append(operations, util.FederatedOperation{
|
||||
Type: util.OperationTypeUpdate,
|
||||
Obj: desiredDaemonSet,
|
||||
ClusterName: cluster.Name,
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if len(operations) == 0 {
|
||||
glog.V(4).Infof("No operation needed for %s/%s", namespace, daemonsetName)
|
||||
// Everything is in order
|
||||
return
|
||||
}
|
||||
err = daemonsetcontroller.federatedUpdater.UpdateWithOnError(operations, daemonsetcontroller.updateTimeout,
|
||||
func(op util.FederatedOperation, operror error) {
|
||||
daemonsetcontroller.eventRecorder.Eventf(baseDaemonSet, api.EventTypeNormal, "UpdateInClusterFailed",
|
||||
"DaemonSet update in cluster %s failed: %v", op.ClusterName, operror)
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
glog.Errorf("Failed to execute updates for %s: %v, retrying shortly", key, err)
|
||||
daemonsetcontroller.deliverDaemonSet(namespace, daemonsetName, 0, true)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// delete deletes the given daemonset or returns error if the deletion was not complete.
|
||||
func (daemonsetcontroller *DaemonSetController) delete(daemonset *extensionsv1.DaemonSet) error {
|
||||
glog.V(3).Infof("Handling deletion of daemonset: %v", *daemonset)
|
||||
_, err := daemonsetcontroller.deletionHelper.HandleObjectInUnderlyingClusters(daemonset)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = daemonsetcontroller.federatedApiClient.Extensions().DaemonSets(daemonset.Namespace).Delete(daemonset.Name, nil)
|
||||
if err != nil {
|
||||
// Its all good if the error is not found error. That means it is deleted already and we do not have to do anything.
|
||||
// This is expected when we are processing an update as a result of daemonset finalizer deletion.
|
||||
// The process that deleted the last finalizer is also going to delete the daemonset and we do not have to do anything.
|
||||
if !errors.IsNotFound(err) {
|
||||
return fmt.Errorf("failed to delete daemonset: %v", err)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
158
vendor/k8s.io/kubernetes/federation/pkg/federation-controller/daemonset/daemonset_controller_test.go
generated
vendored
Normal file
158
vendor/k8s.io/kubernetes/federation/pkg/federation-controller/daemonset/daemonset_controller_test.go
generated
vendored
Normal file
|
|
@ -0,0 +1,158 @@
|
|||
/*
|
||||
Copyright 2016 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package daemonset
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
federationapi "k8s.io/kubernetes/federation/apis/federation/v1beta1"
|
||||
fakefedclientset "k8s.io/kubernetes/federation/client/clientset_generated/federation_release_1_5/fake"
|
||||
"k8s.io/kubernetes/federation/pkg/federation-controller/util"
|
||||
"k8s.io/kubernetes/federation/pkg/federation-controller/util/deletionhelper"
|
||||
. "k8s.io/kubernetes/federation/pkg/federation-controller/util/test"
|
||||
apiv1 "k8s.io/kubernetes/pkg/api/v1"
|
||||
extensionsv1 "k8s.io/kubernetes/pkg/apis/extensions/v1beta1"
|
||||
metav1 "k8s.io/kubernetes/pkg/apis/meta/v1"
|
||||
kubeclientset "k8s.io/kubernetes/pkg/client/clientset_generated/release_1_5"
|
||||
fakekubeclientset "k8s.io/kubernetes/pkg/client/clientset_generated/release_1_5/fake"
|
||||
"k8s.io/kubernetes/pkg/runtime"
|
||||
"k8s.io/kubernetes/pkg/util/wait"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestDaemonSetController(t *testing.T) {
|
||||
cluster1 := NewCluster("cluster1", apiv1.ConditionTrue)
|
||||
cluster2 := NewCluster("cluster2", apiv1.ConditionTrue)
|
||||
|
||||
fakeClient := &fakefedclientset.Clientset{}
|
||||
RegisterFakeList("clusters", &fakeClient.Fake, &federationapi.ClusterList{Items: []federationapi.Cluster{*cluster1}})
|
||||
RegisterFakeList("daemonsets", &fakeClient.Fake, &extensionsv1.DaemonSetList{Items: []extensionsv1.DaemonSet{}})
|
||||
daemonsetWatch := RegisterFakeWatch("daemonsets", &fakeClient.Fake)
|
||||
daemonsetUpdateChan := RegisterFakeCopyOnUpdate("daemonsets", &fakeClient.Fake, daemonsetWatch)
|
||||
clusterWatch := RegisterFakeWatch("clusters", &fakeClient.Fake)
|
||||
|
||||
cluster1Client := &fakekubeclientset.Clientset{}
|
||||
cluster1Watch := RegisterFakeWatch("daemonsets", &cluster1Client.Fake)
|
||||
RegisterFakeList("daemonsets", &cluster1Client.Fake, &extensionsv1.DaemonSetList{Items: []extensionsv1.DaemonSet{}})
|
||||
cluster1CreateChan := RegisterFakeCopyOnCreate("daemonsets", &cluster1Client.Fake, cluster1Watch)
|
||||
cluster1UpdateChan := RegisterFakeCopyOnUpdate("daemonsets", &cluster1Client.Fake, cluster1Watch)
|
||||
|
||||
cluster2Client := &fakekubeclientset.Clientset{}
|
||||
cluster2Watch := RegisterFakeWatch("daemonsets", &cluster2Client.Fake)
|
||||
RegisterFakeList("daemonsets", &cluster2Client.Fake, &extensionsv1.DaemonSetList{Items: []extensionsv1.DaemonSet{}})
|
||||
cluster2CreateChan := RegisterFakeCopyOnCreate("daemonsets", &cluster2Client.Fake, cluster2Watch)
|
||||
|
||||
daemonsetController := NewDaemonSetController(fakeClient)
|
||||
informer := ToFederatedInformerForTestOnly(daemonsetController.daemonsetFederatedInformer)
|
||||
informer.SetClientFactory(func(cluster *federationapi.Cluster) (kubeclientset.Interface, error) {
|
||||
switch cluster.Name {
|
||||
case cluster1.Name:
|
||||
return cluster1Client, nil
|
||||
case cluster2.Name:
|
||||
return cluster2Client, nil
|
||||
default:
|
||||
return nil, fmt.Errorf("Unknown cluster")
|
||||
}
|
||||
})
|
||||
|
||||
daemonsetController.clusterAvailableDelay = time.Second
|
||||
daemonsetController.daemonsetReviewDelay = 50 * time.Millisecond
|
||||
daemonsetController.smallDelay = 20 * time.Millisecond
|
||||
daemonsetController.updateTimeout = 5 * time.Second
|
||||
|
||||
stop := make(chan struct{})
|
||||
daemonsetController.Run(stop)
|
||||
|
||||
daemonset1 := extensionsv1.DaemonSet{
|
||||
ObjectMeta: apiv1.ObjectMeta{
|
||||
Name: "test-daemonset",
|
||||
Namespace: "ns",
|
||||
SelfLink: "/api/v1/namespaces/ns/daemonsets/test-daemonset",
|
||||
},
|
||||
Spec: extensionsv1.DaemonSetSpec{
|
||||
Selector: &metav1.LabelSelector{
|
||||
MatchLabels: make(map[string]string),
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
// Test add federated daemonset.
|
||||
daemonsetWatch.Add(&daemonset1)
|
||||
|
||||
// There should be 2 updates to add both the finalizers.
|
||||
updatedDaemonSet := GetDaemonSetFromChan(daemonsetUpdateChan)
|
||||
assert.True(t, daemonsetController.hasFinalizerFunc(updatedDaemonSet, deletionhelper.FinalizerDeleteFromUnderlyingClusters))
|
||||
updatedDaemonSet = GetDaemonSetFromChan(daemonsetUpdateChan)
|
||||
assert.True(t, daemonsetController.hasFinalizerFunc(updatedDaemonSet, apiv1.FinalizerOrphan))
|
||||
daemonset1 = *updatedDaemonSet
|
||||
|
||||
createdDaemonSet := GetDaemonSetFromChan(cluster1CreateChan)
|
||||
assert.NotNil(t, createdDaemonSet)
|
||||
assert.Equal(t, daemonset1.Namespace, createdDaemonSet.Namespace)
|
||||
assert.Equal(t, daemonset1.Name, createdDaemonSet.Name)
|
||||
assert.True(t, daemonsetsEqual(daemonset1, *createdDaemonSet),
|
||||
fmt.Sprintf("expected: %v, actual: %v", daemonset1, *createdDaemonSet))
|
||||
|
||||
// Wait for the daemonset to appear in the informer store
|
||||
err := WaitForStoreUpdate(
|
||||
daemonsetController.daemonsetFederatedInformer.GetTargetStore(),
|
||||
cluster1.Name, getDaemonSetKey(daemonset1.Namespace, daemonset1.Name), wait.ForeverTestTimeout)
|
||||
assert.Nil(t, err, "daemonset should have appeared in the informer store")
|
||||
|
||||
// TODO: Re-enable this when we have fixed these flaky tests: https://github.com/kubernetes/kubernetes/issues/36540.
|
||||
// Test update federated daemonset.
|
||||
daemonset1.Annotations = map[string]string{
|
||||
"A": "B",
|
||||
}
|
||||
daemonsetWatch.Modify(&daemonset1)
|
||||
updatedDaemonSet = GetDaemonSetFromChan(cluster1UpdateChan)
|
||||
assert.NotNil(t, updatedDaemonSet)
|
||||
assert.Equal(t, daemonset1.Name, updatedDaemonSet.Name)
|
||||
assert.Equal(t, daemonset1.Namespace, updatedDaemonSet.Namespace)
|
||||
assert.True(t, daemonsetsEqual(daemonset1, *updatedDaemonSet),
|
||||
fmt.Sprintf("expected: %v, actual: %v", daemonset1, *updatedDaemonSet))
|
||||
|
||||
// Test update federated daemonset.
|
||||
daemonset1.Spec.Template.Name = "TEST"
|
||||
daemonsetWatch.Modify(&daemonset1)
|
||||
err = CheckObjectFromChan(cluster1UpdateChan, MetaAndSpecCheckingFunction(&daemonset1))
|
||||
assert.NoError(t, err)
|
||||
|
||||
// Test add cluster
|
||||
clusterWatch.Add(cluster2)
|
||||
createdDaemonSet2 := GetDaemonSetFromChan(cluster2CreateChan)
|
||||
assert.NotNil(t, createdDaemonSet2)
|
||||
assert.Equal(t, daemonset1.Name, createdDaemonSet2.Name)
|
||||
assert.Equal(t, daemonset1.Namespace, createdDaemonSet2.Namespace)
|
||||
assert.True(t, daemonsetsEqual(daemonset1, *createdDaemonSet2),
|
||||
fmt.Sprintf("expected: %v, actual: %v", daemonset1, *createdDaemonSet2))
|
||||
|
||||
close(stop)
|
||||
}
|
||||
|
||||
func daemonsetsEqual(a, b extensionsv1.DaemonSet) bool {
|
||||
return util.ObjectMetaEquivalent(a.ObjectMeta, b.ObjectMeta) && reflect.DeepEqual(a.Spec, b.Spec)
|
||||
}
|
||||
|
||||
func GetDaemonSetFromChan(c chan runtime.Object) *extensionsv1.DaemonSet {
|
||||
daemonset := GetObjectFromChan(c).(*extensionsv1.DaemonSet)
|
||||
return daemonset
|
||||
}
|
||||
63
vendor/k8s.io/kubernetes/federation/pkg/federation-controller/deployment/BUILD
generated
vendored
Normal file
63
vendor/k8s.io/kubernetes/federation/pkg/federation-controller/deployment/BUILD
generated
vendored
Normal file
|
|
@ -0,0 +1,63 @@
|
|||
package(default_visibility = ["//visibility:public"])
|
||||
|
||||
licenses(["notice"])
|
||||
|
||||
load(
|
||||
"@io_bazel_rules_go//go:def.bzl",
|
||||
"go_binary",
|
||||
"go_library",
|
||||
"go_test",
|
||||
"cgo_library",
|
||||
)
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = ["deploymentcontroller.go"],
|
||||
tags = ["automanaged"],
|
||||
deps = [
|
||||
"//federation/apis/federation:go_default_library",
|
||||
"//federation/apis/federation/v1beta1:go_default_library",
|
||||
"//federation/client/clientset_generated/federation_release_1_5:go_default_library",
|
||||
"//federation/pkg/federation-controller/util:go_default_library",
|
||||
"//federation/pkg/federation-controller/util/deletionhelper:go_default_library",
|
||||
"//federation/pkg/federation-controller/util/eventsink:go_default_library",
|
||||
"//federation/pkg/federation-controller/util/planner:go_default_library",
|
||||
"//federation/pkg/federation-controller/util/podanalyzer:go_default_library",
|
||||
"//pkg/api:go_default_library",
|
||||
"//pkg/api/errors:go_default_library",
|
||||
"//pkg/api/v1:go_default_library",
|
||||
"//pkg/apis/extensions/v1beta1:go_default_library",
|
||||
"//pkg/client/cache:go_default_library",
|
||||
"//pkg/client/clientset_generated/release_1_5:go_default_library",
|
||||
"//pkg/client/record:go_default_library",
|
||||
"//pkg/controller:go_default_library",
|
||||
"//pkg/conversion:go_default_library",
|
||||
"//pkg/runtime:go_default_library",
|
||||
"//pkg/util/flowcontrol:go_default_library",
|
||||
"//pkg/util/wait:go_default_library",
|
||||
"//pkg/util/workqueue:go_default_library",
|
||||
"//pkg/watch:go_default_library",
|
||||
"//vendor:github.com/golang/glog",
|
||||
],
|
||||
)
|
||||
|
||||
go_test(
|
||||
name = "go_default_test",
|
||||
srcs = ["deploymentcontroller_test.go"],
|
||||
library = "go_default_library",
|
||||
tags = ["automanaged"],
|
||||
deps = [
|
||||
"//federation/apis/federation/v1beta1:go_default_library",
|
||||
"//federation/client/clientset_generated/federation_release_1_5/fake:go_default_library",
|
||||
"//federation/pkg/federation-controller/util/test:go_default_library",
|
||||
"//pkg/api/meta:go_default_library",
|
||||
"//pkg/api/v1:go_default_library",
|
||||
"//pkg/apis/extensions/v1beta1:go_default_library",
|
||||
"//pkg/client/clientset_generated/release_1_5:go_default_library",
|
||||
"//pkg/client/clientset_generated/release_1_5/fake:go_default_library",
|
||||
"//pkg/runtime:go_default_library",
|
||||
"//pkg/types:go_default_library",
|
||||
"//pkg/util/wait:go_default_library",
|
||||
"//vendor:github.com/stretchr/testify/assert",
|
||||
],
|
||||
)
|
||||
651
vendor/k8s.io/kubernetes/federation/pkg/federation-controller/deployment/deploymentcontroller.go
generated
vendored
Normal file
651
vendor/k8s.io/kubernetes/federation/pkg/federation-controller/deployment/deploymentcontroller.go
generated
vendored
Normal file
File diff suppressed because it is too large
Load diff
186
vendor/k8s.io/kubernetes/federation/pkg/federation-controller/deployment/deploymentcontroller_test.go
generated
vendored
Normal file
186
vendor/k8s.io/kubernetes/federation/pkg/federation-controller/deployment/deploymentcontroller_test.go
generated
vendored
Normal file
|
|
@ -0,0 +1,186 @@
|
|||
/*
|
||||
Copyright 2016 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package deployment
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"fmt"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
fedv1 "k8s.io/kubernetes/federation/apis/federation/v1beta1"
|
||||
fakefedclientset "k8s.io/kubernetes/federation/client/clientset_generated/federation_release_1_5/fake"
|
||||
. "k8s.io/kubernetes/federation/pkg/federation-controller/util/test"
|
||||
"k8s.io/kubernetes/pkg/api/meta"
|
||||
apiv1 "k8s.io/kubernetes/pkg/api/v1"
|
||||
extensionsv1 "k8s.io/kubernetes/pkg/apis/extensions/v1beta1"
|
||||
kubeclientset "k8s.io/kubernetes/pkg/client/clientset_generated/release_1_5"
|
||||
fakekubeclientset "k8s.io/kubernetes/pkg/client/clientset_generated/release_1_5/fake"
|
||||
"k8s.io/kubernetes/pkg/runtime"
|
||||
"k8s.io/kubernetes/pkg/types"
|
||||
"k8s.io/kubernetes/pkg/util/wait"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestParseFederationDeploymentPreference(t *testing.T) {
|
||||
successPrefs := []string{
|
||||
`{"rebalance": true,
|
||||
"clusters": {
|
||||
"k8s-1": {"minReplicas": 10, "maxReplicas": 20, "weight": 2},
|
||||
"*": {"weight": 1}
|
||||
}}`,
|
||||
}
|
||||
failedPrefes := []string{
|
||||
`{`, // bad json
|
||||
}
|
||||
|
||||
rs := newDeploymentWithReplicas("d-1", 100)
|
||||
accessor, _ := meta.Accessor(rs)
|
||||
anno := accessor.GetAnnotations()
|
||||
if anno == nil {
|
||||
anno = make(map[string]string)
|
||||
accessor.SetAnnotations(anno)
|
||||
}
|
||||
for _, prefString := range successPrefs {
|
||||
anno[FedDeploymentPreferencesAnnotation] = prefString
|
||||
pref, err := parseFederationDeploymentPreference(rs)
|
||||
assert.NotNil(t, pref)
|
||||
assert.Nil(t, err)
|
||||
}
|
||||
for _, prefString := range failedPrefes {
|
||||
anno[FedDeploymentPreferencesAnnotation] = prefString
|
||||
pref, err := parseFederationDeploymentPreference(rs)
|
||||
assert.Nil(t, pref)
|
||||
assert.NotNil(t, err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestDeploymentController(t *testing.T) {
|
||||
flag.Set("logtostderr", "true")
|
||||
flag.Set("v", "5")
|
||||
flag.Parse()
|
||||
|
||||
deploymentReviewDelay = 500 * time.Millisecond
|
||||
clusterAvailableDelay = 100 * time.Millisecond
|
||||
clusterUnavailableDelay = 100 * time.Millisecond
|
||||
allDeploymentReviewDelay = 500 * time.Millisecond
|
||||
|
||||
cluster1 := NewCluster("cluster1", apiv1.ConditionTrue)
|
||||
cluster2 := NewCluster("cluster2", apiv1.ConditionTrue)
|
||||
|
||||
fakeClient := &fakefedclientset.Clientset{}
|
||||
RegisterFakeList("clusters", &fakeClient.Fake, &fedv1.ClusterList{Items: []fedv1.Cluster{*cluster1}})
|
||||
deploymentsWatch := RegisterFakeWatch("deployments", &fakeClient.Fake)
|
||||
clusterWatch := RegisterFakeWatch("clusters", &fakeClient.Fake)
|
||||
|
||||
cluster1Client := &fakekubeclientset.Clientset{}
|
||||
cluster1Watch := RegisterFakeWatch("deployments", &cluster1Client.Fake)
|
||||
_ = RegisterFakeWatch("pods", &cluster1Client.Fake)
|
||||
RegisterFakeList("deployments", &cluster1Client.Fake, &extensionsv1.DeploymentList{Items: []extensionsv1.Deployment{}})
|
||||
cluster1CreateChan := RegisterFakeCopyOnCreate("deployments", &cluster1Client.Fake, cluster1Watch)
|
||||
cluster1UpdateChan := RegisterFakeCopyOnUpdate("deployments", &cluster1Client.Fake, cluster1Watch)
|
||||
|
||||
cluster2Client := &fakekubeclientset.Clientset{}
|
||||
cluster2Watch := RegisterFakeWatch("deployments", &cluster2Client.Fake)
|
||||
_ = RegisterFakeWatch("pods", &cluster2Client.Fake)
|
||||
RegisterFakeList("deployments", &cluster2Client.Fake, &extensionsv1.DeploymentList{Items: []extensionsv1.Deployment{}})
|
||||
cluster2CreateChan := RegisterFakeCopyOnCreate("deployments", &cluster2Client.Fake, cluster2Watch)
|
||||
|
||||
deploymentController := NewDeploymentController(fakeClient)
|
||||
clientFactory := func(cluster *fedv1.Cluster) (kubeclientset.Interface, error) {
|
||||
switch cluster.Name {
|
||||
case cluster1.Name:
|
||||
return cluster1Client, nil
|
||||
case cluster2.Name:
|
||||
return cluster2Client, nil
|
||||
default:
|
||||
return nil, fmt.Errorf("Unknown cluster")
|
||||
}
|
||||
}
|
||||
ToFederatedInformerForTestOnly(deploymentController.fedDeploymentInformer).SetClientFactory(clientFactory)
|
||||
ToFederatedInformerForTestOnly(deploymentController.fedPodInformer).SetClientFactory(clientFactory)
|
||||
|
||||
stop := make(chan struct{})
|
||||
go deploymentController.Run(5, stop)
|
||||
|
||||
// Create deployment. Expect to see it in cluster1.
|
||||
dep1 := newDeploymentWithReplicas("depA", 6)
|
||||
deploymentsWatch.Add(dep1)
|
||||
checkDeployment := func(base *extensionsv1.Deployment, replicas int32) CheckingFunction {
|
||||
return func(obj runtime.Object) error {
|
||||
if obj == nil {
|
||||
return fmt.Errorf("Observed object is nil")
|
||||
}
|
||||
d := obj.(*extensionsv1.Deployment)
|
||||
if err := CompareObjectMeta(base.ObjectMeta, d.ObjectMeta); err != nil {
|
||||
return err
|
||||
}
|
||||
if replicas != *d.Spec.Replicas {
|
||||
return fmt.Errorf("Replica count is different expected:%d observed:%d", replicas, *d.Spec.Replicas)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
}
|
||||
assert.NoError(t, CheckObjectFromChan(cluster1CreateChan, checkDeployment(dep1, *dep1.Spec.Replicas)))
|
||||
err := WaitForStoreUpdate(
|
||||
deploymentController.fedDeploymentInformer.GetTargetStore(),
|
||||
cluster1.Name, types.NamespacedName{Namespace: dep1.Namespace, Name: dep1.Name}.String(), wait.ForeverTestTimeout)
|
||||
assert.Nil(t, err, "deployment should have appeared in the informer store")
|
||||
|
||||
// Increase replica count. Expect to see the update in cluster1.
|
||||
newRep := int32(8)
|
||||
dep1.Spec.Replicas = &newRep
|
||||
deploymentsWatch.Modify(dep1)
|
||||
assert.NoError(t, CheckObjectFromChan(cluster1UpdateChan, checkDeployment(dep1, *dep1.Spec.Replicas)))
|
||||
|
||||
// Add new cluster. Although rebalance = false, no pods have been created yet so it should
|
||||
// rebalance anyway.
|
||||
clusterWatch.Add(cluster2)
|
||||
assert.NoError(t, CheckObjectFromChan(cluster1UpdateChan, checkDeployment(dep1, *dep1.Spec.Replicas/2)))
|
||||
assert.NoError(t, CheckObjectFromChan(cluster2CreateChan, checkDeployment(dep1, *dep1.Spec.Replicas/2)))
|
||||
|
||||
// Add new deployment with non-default replica placement preferences.
|
||||
dep2 := newDeploymentWithReplicas("deployment2", 9)
|
||||
dep2.Annotations = make(map[string]string)
|
||||
dep2.Annotations[FedDeploymentPreferencesAnnotation] = `{"rebalance": true,
|
||||
"clusters": {
|
||||
"cluster1": {"weight": 2},
|
||||
"cluster2": {"weight": 1}
|
||||
}}`
|
||||
deploymentsWatch.Add(dep2)
|
||||
assert.NoError(t, CheckObjectFromChan(cluster1CreateChan, checkDeployment(dep2, 6)))
|
||||
assert.NoError(t, CheckObjectFromChan(cluster2CreateChan, checkDeployment(dep2, 3)))
|
||||
}
|
||||
|
||||
func GetDeploymentFromChan(c chan runtime.Object) *extensionsv1.Deployment {
|
||||
secret := GetObjectFromChan(c).(*extensionsv1.Deployment)
|
||||
return secret
|
||||
}
|
||||
|
||||
func newDeploymentWithReplicas(name string, replicas int32) *extensionsv1.Deployment {
|
||||
return &extensionsv1.Deployment{
|
||||
ObjectMeta: apiv1.ObjectMeta{
|
||||
Name: name,
|
||||
Namespace: apiv1.NamespaceDefault,
|
||||
SelfLink: "/api/v1/namespaces/default/deployments/name",
|
||||
},
|
||||
Spec: extensionsv1.DeploymentSpec{
|
||||
Replicas: &replicas,
|
||||
},
|
||||
}
|
||||
}
|
||||
19
vendor/k8s.io/kubernetes/federation/pkg/federation-controller/doc.go
generated
vendored
Normal file
19
vendor/k8s.io/kubernetes/federation/pkg/federation-controller/doc.go
generated
vendored
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
/*
|
||||
Copyright 2015 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
// Package federation_controller contains code for controllers (like the cluster
|
||||
// controller).
|
||||
package federation_controller // import "k8s.io/kubernetes/federation/pkg/federation-controller"
|
||||
62
vendor/k8s.io/kubernetes/federation/pkg/federation-controller/ingress/BUILD
generated
vendored
Normal file
62
vendor/k8s.io/kubernetes/federation/pkg/federation-controller/ingress/BUILD
generated
vendored
Normal file
|
|
@ -0,0 +1,62 @@
|
|||
package(default_visibility = ["//visibility:public"])
|
||||
|
||||
licenses(["notice"])
|
||||
|
||||
load(
|
||||
"@io_bazel_rules_go//go:def.bzl",
|
||||
"go_binary",
|
||||
"go_library",
|
||||
"go_test",
|
||||
"cgo_library",
|
||||
)
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = ["ingress_controller.go"],
|
||||
tags = ["automanaged"],
|
||||
deps = [
|
||||
"//federation/apis/federation/v1beta1:go_default_library",
|
||||
"//federation/client/clientset_generated/federation_release_1_5:go_default_library",
|
||||
"//federation/pkg/federation-controller/util:go_default_library",
|
||||
"//federation/pkg/federation-controller/util/deletionhelper:go_default_library",
|
||||
"//federation/pkg/federation-controller/util/eventsink:go_default_library",
|
||||
"//pkg/api:go_default_library",
|
||||
"//pkg/api/errors:go_default_library",
|
||||
"//pkg/api/v1:go_default_library",
|
||||
"//pkg/apis/extensions/v1beta1:go_default_library",
|
||||
"//pkg/client/cache:go_default_library",
|
||||
"//pkg/client/clientset_generated/release_1_5:go_default_library",
|
||||
"//pkg/client/record:go_default_library",
|
||||
"//pkg/controller:go_default_library",
|
||||
"//pkg/conversion:go_default_library",
|
||||
"//pkg/runtime:go_default_library",
|
||||
"//pkg/types:go_default_library",
|
||||
"//pkg/util/flowcontrol:go_default_library",
|
||||
"//pkg/watch:go_default_library",
|
||||
"//vendor:github.com/golang/glog",
|
||||
],
|
||||
)
|
||||
|
||||
go_test(
|
||||
name = "go_default_test",
|
||||
srcs = ["ingress_controller_test.go"],
|
||||
library = "go_default_library",
|
||||
tags = ["automanaged"],
|
||||
deps = [
|
||||
"//federation/apis/federation/v1beta1:go_default_library",
|
||||
"//federation/client/clientset_generated/federation_release_1_5/fake:go_default_library",
|
||||
"//federation/pkg/federation-controller/util:go_default_library",
|
||||
"//federation/pkg/federation-controller/util/deletionhelper:go_default_library",
|
||||
"//federation/pkg/federation-controller/util/test:go_default_library",
|
||||
"//pkg/api/errors:go_default_library",
|
||||
"//pkg/api/v1:go_default_library",
|
||||
"//pkg/apis/extensions/v1beta1:go_default_library",
|
||||
"//pkg/client/cache:go_default_library",
|
||||
"//pkg/client/clientset_generated/release_1_5:go_default_library",
|
||||
"//pkg/client/clientset_generated/release_1_5/fake:go_default_library",
|
||||
"//pkg/runtime:go_default_library",
|
||||
"//pkg/types:go_default_library",
|
||||
"//pkg/util/wait:go_default_library",
|
||||
"//vendor:github.com/stretchr/testify/assert",
|
||||
],
|
||||
)
|
||||
918
vendor/k8s.io/kubernetes/federation/pkg/federation-controller/ingress/ingress_controller.go
generated
vendored
Normal file
918
vendor/k8s.io/kubernetes/federation/pkg/federation-controller/ingress/ingress_controller.go
generated
vendored
Normal file
File diff suppressed because it is too large
Load diff
294
vendor/k8s.io/kubernetes/federation/pkg/federation-controller/ingress/ingress_controller_test.go
generated
vendored
Normal file
294
vendor/k8s.io/kubernetes/federation/pkg/federation-controller/ingress/ingress_controller_test.go
generated
vendored
Normal file
|
|
@ -0,0 +1,294 @@
|
|||
/*
|
||||
Copyright 2016 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package ingress
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
federationapi "k8s.io/kubernetes/federation/apis/federation/v1beta1"
|
||||
fakefedclientset "k8s.io/kubernetes/federation/client/clientset_generated/federation_release_1_5/fake"
|
||||
"k8s.io/kubernetes/federation/pkg/federation-controller/util"
|
||||
"k8s.io/kubernetes/federation/pkg/federation-controller/util/deletionhelper"
|
||||
. "k8s.io/kubernetes/federation/pkg/federation-controller/util/test"
|
||||
"k8s.io/kubernetes/pkg/api/errors"
|
||||
apiv1 "k8s.io/kubernetes/pkg/api/v1"
|
||||
extensionsv1beta1 "k8s.io/kubernetes/pkg/apis/extensions/v1beta1"
|
||||
"k8s.io/kubernetes/pkg/client/cache"
|
||||
kubeclientset "k8s.io/kubernetes/pkg/client/clientset_generated/release_1_5"
|
||||
fakekubeclientset "k8s.io/kubernetes/pkg/client/clientset_generated/release_1_5/fake"
|
||||
"k8s.io/kubernetes/pkg/runtime"
|
||||
"k8s.io/kubernetes/pkg/types"
|
||||
"k8s.io/kubernetes/pkg/util/wait"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestIngressController(t *testing.T) {
|
||||
fakeClusterList := federationapi.ClusterList{Items: []federationapi.Cluster{}}
|
||||
fakeConfigMapList1 := apiv1.ConfigMapList{Items: []apiv1.ConfigMap{}}
|
||||
fakeConfigMapList2 := apiv1.ConfigMapList{Items: []apiv1.ConfigMap{}}
|
||||
cluster1 := NewCluster("cluster1", apiv1.ConditionTrue)
|
||||
cluster2 := NewCluster("cluster2", apiv1.ConditionTrue)
|
||||
cfg1 := NewConfigMap("foo")
|
||||
cfg2 := NewConfigMap("bar") // Different UID from cfg1, so that we can check that they get reconciled.
|
||||
|
||||
t.Log("Creating fake infrastructure")
|
||||
fedClient := &fakefedclientset.Clientset{}
|
||||
RegisterFakeList("clusters", &fedClient.Fake, &fakeClusterList)
|
||||
RegisterFakeList("ingresses", &fedClient.Fake, &extensionsv1beta1.IngressList{Items: []extensionsv1beta1.Ingress{}})
|
||||
fedIngressWatch := RegisterFakeWatch("ingresses", &fedClient.Fake)
|
||||
clusterWatch := RegisterFakeWatch("clusters", &fedClient.Fake)
|
||||
fedClusterUpdateChan := RegisterFakeCopyOnUpdate("clusters", &fedClient.Fake, clusterWatch)
|
||||
//fedIngressUpdateChan := RegisterFakeCopyOnUpdate("ingresses", &fedClient.Fake, fedIngressWatch)
|
||||
|
||||
cluster1Client := &fakekubeclientset.Clientset{}
|
||||
RegisterFakeList("ingresses", &cluster1Client.Fake, &extensionsv1beta1.IngressList{Items: []extensionsv1beta1.Ingress{}})
|
||||
RegisterFakeList("configmaps", &cluster1Client.Fake, &fakeConfigMapList1)
|
||||
cluster1IngressWatch := RegisterFakeWatch("ingresses", &cluster1Client.Fake)
|
||||
cluster1ConfigMapWatch := RegisterFakeWatch("configmaps", &cluster1Client.Fake)
|
||||
cluster1IngressCreateChan := RegisterFakeCopyOnCreate("ingresses", &cluster1Client.Fake, cluster1IngressWatch)
|
||||
// cluster1IngressUpdateChan := RegisterFakeCopyOnUpdate("ingresses", &cluster1Client.Fake, cluster1IngressWatch)
|
||||
|
||||
cluster2Client := &fakekubeclientset.Clientset{}
|
||||
RegisterFakeList("ingresses", &cluster2Client.Fake, &extensionsv1beta1.IngressList{Items: []extensionsv1beta1.Ingress{}})
|
||||
RegisterFakeList("configmaps", &cluster2Client.Fake, &fakeConfigMapList2)
|
||||
cluster2IngressWatch := RegisterFakeWatch("ingresses", &cluster2Client.Fake)
|
||||
cluster2ConfigMapWatch := RegisterFakeWatch("configmaps", &cluster2Client.Fake)
|
||||
cluster2IngressCreateChan := RegisterFakeCopyOnCreate("ingresses", &cluster2Client.Fake, cluster2IngressWatch)
|
||||
cluster2ConfigMapUpdateChan := RegisterFakeCopyOnUpdate("configmaps", &cluster2Client.Fake, cluster2ConfigMapWatch)
|
||||
|
||||
clientFactoryFunc := func(cluster *federationapi.Cluster) (kubeclientset.Interface, error) {
|
||||
switch cluster.Name {
|
||||
case cluster1.Name:
|
||||
return cluster1Client, nil
|
||||
case cluster2.Name:
|
||||
return cluster2Client, nil
|
||||
default:
|
||||
return nil, fmt.Errorf("Unknown cluster")
|
||||
}
|
||||
}
|
||||
ingressController := NewIngressController(fedClient)
|
||||
ingressInformer := ToFederatedInformerForTestOnly(ingressController.ingressFederatedInformer)
|
||||
ingressInformer.SetClientFactory(clientFactoryFunc)
|
||||
configMapInformer := ToFederatedInformerForTestOnly(ingressController.configMapFederatedInformer)
|
||||
configMapInformer.SetClientFactory(clientFactoryFunc)
|
||||
ingressController.clusterAvailableDelay = time.Second
|
||||
ingressController.ingressReviewDelay = 10 * time.Millisecond
|
||||
ingressController.configMapReviewDelay = 10 * time.Millisecond
|
||||
ingressController.smallDelay = 20 * time.Millisecond
|
||||
ingressController.updateTimeout = 5 * time.Second
|
||||
|
||||
stop := make(chan struct{})
|
||||
t.Log("Running Ingress Controller")
|
||||
ingressController.Run(stop)
|
||||
|
||||
// TODO: Here we are creating the ingress with first cluster annotation.
|
||||
// Add another test without that annotation when
|
||||
// https://github.com/kubernetes/kubernetes/issues/36540 is fixed.
|
||||
ing1 := extensionsv1beta1.Ingress{
|
||||
ObjectMeta: apiv1.ObjectMeta{
|
||||
Name: "test-ingress",
|
||||
Namespace: "mynamespace",
|
||||
SelfLink: "/api/v1/namespaces/mynamespace/ingress/test-ingress",
|
||||
Annotations: map[string]string{
|
||||
firstClusterAnnotation: cluster1.Name,
|
||||
},
|
||||
},
|
||||
Status: extensionsv1beta1.IngressStatus{
|
||||
LoadBalancer: apiv1.LoadBalancerStatus{
|
||||
Ingress: make([]apiv1.LoadBalancerIngress, 0, 0),
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
t.Log("Adding cluster 1")
|
||||
clusterWatch.Add(cluster1)
|
||||
|
||||
t.Log("Adding Ingress UID ConfigMap to cluster 1")
|
||||
cluster1ConfigMapWatch.Add(cfg1)
|
||||
|
||||
t.Log("Checking that UID annotation on Cluster 1 annotation was correctly updated")
|
||||
cluster := GetClusterFromChan(fedClusterUpdateChan)
|
||||
assert.NotNil(t, cluster)
|
||||
assert.Equal(t, cluster.ObjectMeta.Annotations[uidAnnotationKey], cfg1.Data[uidKey])
|
||||
|
||||
// Test add federated ingress.
|
||||
t.Log("Adding Federated Ingress")
|
||||
fedIngressWatch.Add(&ing1)
|
||||
/*
|
||||
// TODO: Re-enable this when we have fixed these flaky tests: https://github.com/kubernetes/kubernetes/issues/36540.
|
||||
t.Logf("Checking that approproate finalizers are added")
|
||||
// There should be 2 updates to add both the finalizers.
|
||||
updatedIngress := GetIngressFromChan(t, fedIngressUpdateChan)
|
||||
assert.True(t, ingressController.hasFinalizerFunc(updatedIngress, deletionhelper.FinalizerDeleteFromUnderlyingClusters))
|
||||
updatedIngress = GetIngressFromChan(t, fedIngressUpdateChan)
|
||||
assert.True(t, ingressController.hasFinalizerFunc(updatedIngress, apiv1.FinalizerOrphan), fmt.Sprintf("ingress does not have the orphan finalizer: %v", updatedIngress))
|
||||
ing1 = *updatedIngress
|
||||
*/
|
||||
t.Log("Checking that Ingress was correctly created in cluster 1")
|
||||
createdIngress := GetIngressFromChan(t, cluster1IngressCreateChan)
|
||||
assert.NotNil(t, createdIngress)
|
||||
assert.True(t, reflect.DeepEqual(ing1.Spec, createdIngress.Spec), "Spec of created ingress is not equal")
|
||||
assert.True(t, util.ObjectMetaEquivalent(ing1.ObjectMeta, createdIngress.ObjectMeta), "Metadata of created object is not equivalent")
|
||||
// Wait for finalizers to appear in federation store.
|
||||
// assert.NoError(t, WaitForFinalizersInFederationStore(ingressController, ingressController.ingressInformerStore,
|
||||
// types.NamespacedName{Namespace: ing1.Namespace, Name: ing1.Name}.String()), "finalizers not found in federated ingress")
|
||||
// Wait for the cluster ingress to appear in cluster store.
|
||||
assert.NoError(t, WaitForIngressInClusterStore(ingressController.ingressFederatedInformer.GetTargetStore(), cluster1.Name,
|
||||
types.NamespacedName{Namespace: createdIngress.Namespace, Name: createdIngress.Name}.String()),
|
||||
"Created ingress not found in underlying cluster store")
|
||||
|
||||
/*
|
||||
// TODO: Re-enable this when we have fixed these flaky tests: https://github.com/kubernetes/kubernetes/issues/36540.
|
||||
// Test that IP address gets transferred from cluster ingress to federated ingress.
|
||||
t.Log("Checking that IP address gets transferred from cluster ingress to federated ingress")
|
||||
createdIngress.Status.LoadBalancer.Ingress = append(createdIngress.Status.LoadBalancer.Ingress, apiv1.LoadBalancerIngress{IP: "1.2.3.4"})
|
||||
cluster1IngressWatch.Modify(createdIngress)
|
||||
// Wait for store to see the updated cluster ingress.
|
||||
assert.NoError(t, WaitForStatusUpdate(t, ingressController.ingressFederatedInformer.GetTargetStore(),
|
||||
cluster1.Name, types.NamespacedName{Namespace: createdIngress.Namespace, Name: createdIngress.Name}.String(),
|
||||
createdIngress.Status.LoadBalancer, 4*wait.ForeverTestTimeout))
|
||||
updatedIngress = GetIngressFromChan(t, fedIngressUpdateChan)
|
||||
assert.NotNil(t, updatedIngress, "Cluster's ingress load balancer status was not correctly transferred to the federated ingress")
|
||||
if updatedIngress != nil {
|
||||
assert.True(t, reflect.DeepEqual(createdIngress.Status.LoadBalancer.Ingress, updatedIngress.Status.LoadBalancer.Ingress), fmt.Sprintf("Ingress IP was not transferred from cluster ingress to federated ingress. %v is not equal to %v", createdIngress.Status.LoadBalancer.Ingress, updatedIngress.Status.LoadBalancer.Ingress))
|
||||
t.Logf("expected: %v, actual: %v", createdIngress, updatedIngress)
|
||||
}
|
||||
|
||||
// Test update federated ingress.
|
||||
if updatedIngress.ObjectMeta.Annotations == nil {
|
||||
updatedIngress.ObjectMeta.Annotations = make(map[string]string)
|
||||
}
|
||||
updatedIngress.ObjectMeta.Annotations["A"] = "B"
|
||||
t.Log("Modifying Federated Ingress")
|
||||
fedIngressWatch.Modify(updatedIngress)
|
||||
t.Log("Checking that Ingress was correctly updated in cluster 1")
|
||||
updatedIngress2 := GetIngressFromChan(t, cluster1IngressUpdateChan)
|
||||
assert.NotNil(t, updatedIngress2)
|
||||
assert.True(t, reflect.DeepEqual(updatedIngress2.Spec, updatedIngress.Spec), "Spec of updated ingress is not equal")
|
||||
assert.Equal(t, updatedIngress2.ObjectMeta.Annotations["A"], updatedIngress.ObjectMeta.Annotations["A"], "Updated annotation not transferred from federated to cluster ingress.")
|
||||
*/
|
||||
// Test add cluster
|
||||
t.Log("Adding a second cluster")
|
||||
ing1.Annotations[staticIPNameKeyWritable] = "foo" // Make sure that the base object has a static IP name first.
|
||||
fedIngressWatch.Modify(&ing1)
|
||||
clusterWatch.Add(cluster2)
|
||||
// First check that the original values are not equal - see above comment
|
||||
assert.NotEqual(t, cfg1.Data[uidKey], cfg2.Data[uidKey], fmt.Sprintf("ConfigMap in cluster 2 must initially not equal that in cluster 1 for this test - please fix test"))
|
||||
cluster2ConfigMapWatch.Add(cfg2)
|
||||
t.Log("Checking that the ingress got created in cluster 2")
|
||||
createdIngress2 := GetIngressFromChan(t, cluster2IngressCreateChan)
|
||||
assert.NotNil(t, createdIngress2)
|
||||
assert.True(t, reflect.DeepEqual(ing1.Spec, createdIngress2.Spec), "Spec of created ingress is not equal")
|
||||
assert.True(t, util.ObjectMetaEquivalent(ing1.ObjectMeta, createdIngress2.ObjectMeta), "Metadata of created object is not equivalent")
|
||||
|
||||
t.Log("Checking that the configmap in cluster 2 got updated.")
|
||||
updatedConfigMap2 := GetConfigMapFromChan(cluster2ConfigMapUpdateChan)
|
||||
assert.NotNil(t, updatedConfigMap2, fmt.Sprintf("ConfigMap in cluster 2 was not updated (or more likely the test is broken and the API type written is wrong)"))
|
||||
if updatedConfigMap2 != nil {
|
||||
assert.Equal(t, cfg1.Data[uidKey], updatedConfigMap2.Data[uidKey],
|
||||
fmt.Sprintf("UID's in configmaps in cluster's 1 and 2 are not equal (%q != %q)", cfg1.Data["uid"], updatedConfigMap2.Data["uid"]))
|
||||
}
|
||||
|
||||
close(stop)
|
||||
}
|
||||
|
||||
func GetIngressFromChan(t *testing.T, c chan runtime.Object) *extensionsv1beta1.Ingress {
|
||||
obj := GetObjectFromChan(c)
|
||||
ingress, ok := obj.(*extensionsv1beta1.Ingress)
|
||||
if !ok {
|
||||
t.Logf("Object on channel was not of type *extensionsv1beta1.Ingress: %v", obj)
|
||||
}
|
||||
return ingress
|
||||
}
|
||||
|
||||
func GetConfigMapFromChan(c chan runtime.Object) *apiv1.ConfigMap {
|
||||
configMap, _ := GetObjectFromChan(c).(*apiv1.ConfigMap)
|
||||
return configMap
|
||||
}
|
||||
|
||||
func GetClusterFromChan(c chan runtime.Object) *federationapi.Cluster {
|
||||
cluster, _ := GetObjectFromChan(c).(*federationapi.Cluster)
|
||||
return cluster
|
||||
}
|
||||
|
||||
func NewConfigMap(uid string) *apiv1.ConfigMap {
|
||||
return &apiv1.ConfigMap{
|
||||
ObjectMeta: apiv1.ObjectMeta{
|
||||
Name: uidConfigMapName,
|
||||
Namespace: uidConfigMapNamespace,
|
||||
SelfLink: "/api/v1/namespaces/" + uidConfigMapNamespace + "/configmap/" + uidConfigMapName,
|
||||
// TODO: Remove: Annotations: map[string]string{},
|
||||
},
|
||||
Data: map[string]string{
|
||||
uidKey: uid,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// Wait for finalizers to appear in federation store.
|
||||
func WaitForFinalizersInFederationStore(ingressController *IngressController, store cache.Store, key string) error {
|
||||
retryInterval := 100 * time.Millisecond
|
||||
timeout := wait.ForeverTestTimeout
|
||||
err := wait.PollImmediate(retryInterval, timeout, func() (bool, error) {
|
||||
obj, found, err := store.GetByKey(key)
|
||||
if !found || err != nil {
|
||||
return false, err
|
||||
}
|
||||
ingress := obj.(*extensionsv1beta1.Ingress)
|
||||
if ingressController.hasFinalizerFunc(ingress, apiv1.FinalizerOrphan) &&
|
||||
ingressController.hasFinalizerFunc(ingress, deletionhelper.FinalizerDeleteFromUnderlyingClusters) {
|
||||
return true, nil
|
||||
}
|
||||
return false, nil
|
||||
})
|
||||
return err
|
||||
}
|
||||
|
||||
// Wait for the cluster ingress to appear in cluster store.
|
||||
func WaitForIngressInClusterStore(store util.FederatedReadOnlyStore, clusterName, key string) error {
|
||||
retryInterval := 100 * time.Millisecond
|
||||
timeout := wait.ForeverTestTimeout
|
||||
err := wait.PollImmediate(retryInterval, timeout, func() (bool, error) {
|
||||
_, found, err := store.GetByKey(clusterName, key)
|
||||
if found && err == nil {
|
||||
return true, nil
|
||||
}
|
||||
if errors.IsNotFound(err) {
|
||||
return false, nil
|
||||
}
|
||||
return false, err
|
||||
})
|
||||
return err
|
||||
}
|
||||
|
||||
// Wait for ingress status to be updated to match the desiredStatus.
|
||||
func WaitForStatusUpdate(t *testing.T, store util.FederatedReadOnlyStore, clusterName, key string, desiredStatus apiv1.LoadBalancerStatus, timeout time.Duration) error {
|
||||
retryInterval := 100 * time.Millisecond
|
||||
err := wait.PollImmediate(retryInterval, timeout, func() (bool, error) {
|
||||
obj, found, err := store.GetByKey(clusterName, key)
|
||||
if !found || err != nil {
|
||||
return false, err
|
||||
}
|
||||
ingress := obj.(*extensionsv1beta1.Ingress)
|
||||
return reflect.DeepEqual(ingress.Status.LoadBalancer, desiredStatus), nil
|
||||
})
|
||||
return err
|
||||
}
|
||||
59
vendor/k8s.io/kubernetes/federation/pkg/federation-controller/namespace/BUILD
generated
vendored
Normal file
59
vendor/k8s.io/kubernetes/federation/pkg/federation-controller/namespace/BUILD
generated
vendored
Normal file
|
|
@ -0,0 +1,59 @@
|
|||
package(default_visibility = ["//visibility:public"])
|
||||
|
||||
licenses(["notice"])
|
||||
|
||||
load(
|
||||
"@io_bazel_rules_go//go:def.bzl",
|
||||
"go_binary",
|
||||
"go_library",
|
||||
"go_test",
|
||||
"cgo_library",
|
||||
)
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = ["namespace_controller.go"],
|
||||
tags = ["automanaged"],
|
||||
deps = [
|
||||
"//federation/apis/federation/v1beta1:go_default_library",
|
||||
"//federation/client/clientset_generated/federation_release_1_5:go_default_library",
|
||||
"//federation/pkg/federation-controller/util:go_default_library",
|
||||
"//federation/pkg/federation-controller/util/deletionhelper:go_default_library",
|
||||
"//federation/pkg/federation-controller/util/eventsink:go_default_library",
|
||||
"//pkg/api:go_default_library",
|
||||
"//pkg/api/errors:go_default_library",
|
||||
"//pkg/api/v1:go_default_library",
|
||||
"//pkg/client/cache:go_default_library",
|
||||
"//pkg/client/clientset_generated/release_1_5:go_default_library",
|
||||
"//pkg/client/record:go_default_library",
|
||||
"//pkg/controller:go_default_library",
|
||||
"//pkg/conversion:go_default_library",
|
||||
"//pkg/runtime:go_default_library",
|
||||
"//pkg/util/flowcontrol:go_default_library",
|
||||
"//pkg/watch:go_default_library",
|
||||
"//vendor:github.com/golang/glog",
|
||||
],
|
||||
)
|
||||
|
||||
go_test(
|
||||
name = "go_default_test",
|
||||
srcs = ["namespace_controller_test.go"],
|
||||
library = "go_default_library",
|
||||
tags = ["automanaged"],
|
||||
deps = [
|
||||
"//federation/apis/federation/v1beta1:go_default_library",
|
||||
"//federation/client/clientset_generated/federation_release_1_5/fake:go_default_library",
|
||||
"//federation/pkg/federation-controller/util:go_default_library",
|
||||
"//federation/pkg/federation-controller/util/deletionhelper:go_default_library",
|
||||
"//federation/pkg/federation-controller/util/test:go_default_library",
|
||||
"//pkg/api/v1:go_default_library",
|
||||
"//pkg/apis/extensions/v1beta1:go_default_library",
|
||||
"//pkg/apis/meta/v1:go_default_library",
|
||||
"//pkg/client/clientset_generated/release_1_5:go_default_library",
|
||||
"//pkg/client/clientset_generated/release_1_5/fake:go_default_library",
|
||||
"//pkg/client/testing/core:go_default_library",
|
||||
"//pkg/runtime:go_default_library",
|
||||
"//pkg/util/wait:go_default_library",
|
||||
"//vendor:github.com/stretchr/testify/assert",
|
||||
],
|
||||
)
|
||||
529
vendor/k8s.io/kubernetes/federation/pkg/federation-controller/namespace/namespace_controller.go
generated
vendored
Normal file
529
vendor/k8s.io/kubernetes/federation/pkg/federation-controller/namespace/namespace_controller.go
generated
vendored
Normal file
File diff suppressed because it is too large
Load diff
206
vendor/k8s.io/kubernetes/federation/pkg/federation-controller/namespace/namespace_controller_test.go
generated
vendored
Normal file
206
vendor/k8s.io/kubernetes/federation/pkg/federation-controller/namespace/namespace_controller_test.go
generated
vendored
Normal file
|
|
@ -0,0 +1,206 @@
|
|||
/*
|
||||
Copyright 2016 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package namespace
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
federationapi "k8s.io/kubernetes/federation/apis/federation/v1beta1"
|
||||
fakefedclientset "k8s.io/kubernetes/federation/client/clientset_generated/federation_release_1_5/fake"
|
||||
"k8s.io/kubernetes/federation/pkg/federation-controller/util"
|
||||
"k8s.io/kubernetes/federation/pkg/federation-controller/util/deletionhelper"
|
||||
. "k8s.io/kubernetes/federation/pkg/federation-controller/util/test"
|
||||
apiv1 "k8s.io/kubernetes/pkg/api/v1"
|
||||
extensionsv1 "k8s.io/kubernetes/pkg/apis/extensions/v1beta1"
|
||||
metav1 "k8s.io/kubernetes/pkg/apis/meta/v1"
|
||||
kubeclientset "k8s.io/kubernetes/pkg/client/clientset_generated/release_1_5"
|
||||
fakekubeclientset "k8s.io/kubernetes/pkg/client/clientset_generated/release_1_5/fake"
|
||||
"k8s.io/kubernetes/pkg/client/testing/core"
|
||||
"k8s.io/kubernetes/pkg/runtime"
|
||||
"k8s.io/kubernetes/pkg/util/wait"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestNamespaceController(t *testing.T) {
|
||||
cluster1 := NewCluster("cluster1", apiv1.ConditionTrue)
|
||||
cluster2 := NewCluster("cluster2", apiv1.ConditionTrue)
|
||||
ns1 := apiv1.Namespace{
|
||||
ObjectMeta: apiv1.ObjectMeta{
|
||||
Name: "test-namespace",
|
||||
SelfLink: "/api/v1/namespaces/test-namespace",
|
||||
},
|
||||
Spec: apiv1.NamespaceSpec{
|
||||
Finalizers: []apiv1.FinalizerName{apiv1.FinalizerKubernetes},
|
||||
},
|
||||
}
|
||||
|
||||
fakeClient := &fakefedclientset.Clientset{}
|
||||
RegisterFakeList("clusters", &fakeClient.Fake, &federationapi.ClusterList{Items: []federationapi.Cluster{*cluster1}})
|
||||
RegisterFakeList("namespaces", &fakeClient.Fake, &apiv1.NamespaceList{Items: []apiv1.Namespace{}})
|
||||
namespaceWatch := RegisterFakeWatch("namespaces", &fakeClient.Fake)
|
||||
namespaceCreateChan := RegisterFakeCopyOnCreate("namespaces", &fakeClient.Fake, namespaceWatch)
|
||||
clusterWatch := RegisterFakeWatch("clusters", &fakeClient.Fake)
|
||||
|
||||
cluster1Client := &fakekubeclientset.Clientset{}
|
||||
cluster1Watch := RegisterFakeWatch("namespaces", &cluster1Client.Fake)
|
||||
RegisterFakeList("namespaces", &cluster1Client.Fake, &apiv1.NamespaceList{Items: []apiv1.Namespace{}})
|
||||
cluster1CreateChan := RegisterFakeCopyOnCreate("namespaces", &cluster1Client.Fake, cluster1Watch)
|
||||
// cluster1UpdateChan := RegisterFakeCopyOnUpdate("namespaces", &cluster1Client.Fake, cluster1Watch)
|
||||
|
||||
cluster2Client := &fakekubeclientset.Clientset{}
|
||||
cluster2Watch := RegisterFakeWatch("namespaces", &cluster2Client.Fake)
|
||||
RegisterFakeList("namespaces", &cluster2Client.Fake, &apiv1.NamespaceList{Items: []apiv1.Namespace{}})
|
||||
cluster2CreateChan := RegisterFakeCopyOnCreate("namespaces", &cluster2Client.Fake, cluster2Watch)
|
||||
|
||||
RegisterFakeList("replicasets", &fakeClient.Fake, &extensionsv1.ReplicaSetList{Items: []extensionsv1.ReplicaSet{
|
||||
{
|
||||
ObjectMeta: apiv1.ObjectMeta{
|
||||
Name: "test-rs",
|
||||
Namespace: ns1.Namespace,
|
||||
}}}})
|
||||
RegisterFakeList("secrets", &fakeClient.Fake, &apiv1.SecretList{Items: []apiv1.Secret{
|
||||
{
|
||||
ObjectMeta: apiv1.ObjectMeta{
|
||||
Name: "test-secret",
|
||||
Namespace: ns1.Namespace,
|
||||
}}}})
|
||||
RegisterFakeList("services", &fakeClient.Fake, &apiv1.ServiceList{Items: []apiv1.Service{
|
||||
{
|
||||
ObjectMeta: apiv1.ObjectMeta{
|
||||
Name: "test-service",
|
||||
Namespace: ns1.Namespace,
|
||||
}}}})
|
||||
nsDeleteChan := RegisterDelete(&fakeClient.Fake, "namespaces")
|
||||
rsDeleteChan := RegisterDeleteCollection(&fakeClient.Fake, "replicasets")
|
||||
serviceDeleteChan := RegisterDeleteCollection(&fakeClient.Fake, "services")
|
||||
secretDeleteChan := RegisterDeleteCollection(&fakeClient.Fake, "secrets")
|
||||
|
||||
namespaceController := NewNamespaceController(fakeClient)
|
||||
informerClientFactory := func(cluster *federationapi.Cluster) (kubeclientset.Interface, error) {
|
||||
switch cluster.Name {
|
||||
case cluster1.Name:
|
||||
return cluster1Client, nil
|
||||
case cluster2.Name:
|
||||
return cluster2Client, nil
|
||||
default:
|
||||
return nil, fmt.Errorf("Unknown cluster")
|
||||
}
|
||||
}
|
||||
setClientFactory(namespaceController.namespaceFederatedInformer, informerClientFactory)
|
||||
namespaceController.clusterAvailableDelay = time.Second
|
||||
namespaceController.namespaceReviewDelay = 50 * time.Millisecond
|
||||
namespaceController.smallDelay = 20 * time.Millisecond
|
||||
namespaceController.updateTimeout = 5 * time.Second
|
||||
|
||||
stop := make(chan struct{})
|
||||
namespaceController.Run(stop)
|
||||
|
||||
// Test add federated namespace.
|
||||
namespaceWatch.Add(&ns1)
|
||||
// Verify that the DeleteFromUnderlyingClusters finalizer is added to the namespace.
|
||||
// Note: finalize invokes the create action in Fake client.
|
||||
// TODO: Seems like a bug. Should invoke update. Fix it.
|
||||
updatedNamespace := GetNamespaceFromChan(namespaceCreateChan)
|
||||
assert.True(t, namespaceController.hasFinalizerFunc(updatedNamespace, deletionhelper.FinalizerDeleteFromUnderlyingClusters))
|
||||
ns1 = *updatedNamespace
|
||||
|
||||
// Verify that the namespace is created in underlying cluster1.
|
||||
createdNamespace := GetNamespaceFromChan(cluster1CreateChan)
|
||||
assert.NotNil(t, createdNamespace)
|
||||
assert.Equal(t, ns1.Name, createdNamespace.Name)
|
||||
|
||||
// Wait for the namespace to appear in the informer store
|
||||
err := WaitForStoreUpdate(
|
||||
namespaceController.namespaceFederatedInformer.GetTargetStore(),
|
||||
cluster1.Name, ns1.Name, wait.ForeverTestTimeout)
|
||||
assert.Nil(t, err, "namespace should have appeared in the informer store")
|
||||
|
||||
/*
|
||||
// TODO: Uncomment this once we have figured out why this is flaky.
|
||||
// Test update federated namespace.
|
||||
ns1.Annotations = map[string]string{
|
||||
"A": "B",
|
||||
}
|
||||
namespaceWatch.Modify(&ns1)
|
||||
updatedNamespace = GetNamespaceFromChan(cluster1UpdateChan)
|
||||
assert.NotNil(t, updatedNamespace)
|
||||
assert.Equal(t, ns1.Name, updatedNamespace.Name)
|
||||
// assert.Contains(t, updatedNamespace.Annotations, "A")
|
||||
*/
|
||||
|
||||
// Test add cluster
|
||||
clusterWatch.Add(cluster2)
|
||||
createdNamespace2 := GetNamespaceFromChan(cluster2CreateChan)
|
||||
assert.NotNil(t, createdNamespace2)
|
||||
assert.Equal(t, ns1.Name, createdNamespace2.Name)
|
||||
// assert.Contains(t, createdNamespace2.Annotations, "A")
|
||||
|
||||
// Delete the namespace with orphan finalizer (let namespaces
|
||||
// in underlying clusters be as is).
|
||||
// TODO: Add a test without orphan finalizer.
|
||||
ns1.ObjectMeta.Finalizers = append(ns1.ObjectMeta.Finalizers, apiv1.FinalizerOrphan)
|
||||
ns1.DeletionTimestamp = &metav1.Time{Time: time.Now()}
|
||||
namespaceWatch.Modify(&ns1)
|
||||
assert.Equal(t, ns1.Name, GetStringFromChan(nsDeleteChan))
|
||||
assert.Equal(t, "all", GetStringFromChan(rsDeleteChan))
|
||||
assert.Equal(t, "all", GetStringFromChan(serviceDeleteChan))
|
||||
assert.Equal(t, "all", GetStringFromChan(secretDeleteChan))
|
||||
|
||||
close(stop)
|
||||
}
|
||||
|
||||
func setClientFactory(informer util.FederatedInformer, informerClientFactory func(*federationapi.Cluster) (kubeclientset.Interface, error)) {
|
||||
testInformer := ToFederatedInformerForTestOnly(informer)
|
||||
testInformer.SetClientFactory(informerClientFactory)
|
||||
}
|
||||
|
||||
func RegisterDeleteCollection(client *core.Fake, resource string) chan string {
|
||||
deleteChan := make(chan string, 100)
|
||||
client.AddReactor("delete-collection", resource, func(action core.Action) (bool, runtime.Object, error) {
|
||||
deleteChan <- "all"
|
||||
return true, nil, nil
|
||||
})
|
||||
return deleteChan
|
||||
}
|
||||
|
||||
func RegisterDelete(client *core.Fake, resource string) chan string {
|
||||
deleteChan := make(chan string, 100)
|
||||
client.AddReactor("delete", resource, func(action core.Action) (bool, runtime.Object, error) {
|
||||
deleteAction := action.(core.DeleteAction)
|
||||
deleteChan <- deleteAction.GetName()
|
||||
return true, nil, nil
|
||||
})
|
||||
return deleteChan
|
||||
}
|
||||
|
||||
func GetStringFromChan(c chan string) string {
|
||||
select {
|
||||
case str := <-c:
|
||||
return str
|
||||
case <-time.After(5 * time.Second):
|
||||
return "timedout"
|
||||
}
|
||||
}
|
||||
|
||||
func GetNamespaceFromChan(c chan runtime.Object) *apiv1.Namespace {
|
||||
namespace := GetObjectFromChan(c).(*apiv1.Namespace)
|
||||
return namespace
|
||||
|
||||
}
|
||||
62
vendor/k8s.io/kubernetes/federation/pkg/federation-controller/replicaset/BUILD
generated
vendored
Normal file
62
vendor/k8s.io/kubernetes/federation/pkg/federation-controller/replicaset/BUILD
generated
vendored
Normal file
|
|
@ -0,0 +1,62 @@
|
|||
package(default_visibility = ["//visibility:public"])
|
||||
|
||||
licenses(["notice"])
|
||||
|
||||
load(
|
||||
"@io_bazel_rules_go//go:def.bzl",
|
||||
"go_binary",
|
||||
"go_library",
|
||||
"go_test",
|
||||
"cgo_library",
|
||||
)
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = ["replicasetcontroller.go"],
|
||||
tags = ["automanaged"],
|
||||
deps = [
|
||||
"//federation/apis/federation:go_default_library",
|
||||
"//federation/apis/federation/v1beta1:go_default_library",
|
||||
"//federation/client/clientset_generated/federation_release_1_5:go_default_library",
|
||||
"//federation/pkg/federation-controller/util:go_default_library",
|
||||
"//federation/pkg/federation-controller/util/deletionhelper:go_default_library",
|
||||
"//federation/pkg/federation-controller/util/eventsink:go_default_library",
|
||||
"//federation/pkg/federation-controller/util/planner:go_default_library",
|
||||
"//federation/pkg/federation-controller/util/podanalyzer:go_default_library",
|
||||
"//pkg/api:go_default_library",
|
||||
"//pkg/api/errors:go_default_library",
|
||||
"//pkg/api/v1:go_default_library",
|
||||
"//pkg/apis/extensions/v1beta1:go_default_library",
|
||||
"//pkg/client/cache:go_default_library",
|
||||
"//pkg/client/clientset_generated/release_1_5:go_default_library",
|
||||
"//pkg/client/record:go_default_library",
|
||||
"//pkg/controller:go_default_library",
|
||||
"//pkg/conversion:go_default_library",
|
||||
"//pkg/runtime:go_default_library",
|
||||
"//pkg/util/flowcontrol:go_default_library",
|
||||
"//pkg/util/wait:go_default_library",
|
||||
"//pkg/util/workqueue:go_default_library",
|
||||
"//pkg/watch:go_default_library",
|
||||
"//vendor:github.com/golang/glog",
|
||||
],
|
||||
)
|
||||
|
||||
go_test(
|
||||
name = "go_default_test",
|
||||
srcs = ["replicasetcontroller_test.go"],
|
||||
library = "go_default_library",
|
||||
tags = ["automanaged"],
|
||||
deps = [
|
||||
"//federation/apis/federation/v1beta1:go_default_library",
|
||||
"//federation/client/clientset_generated/federation_release_1_5/fake:go_default_library",
|
||||
"//federation/pkg/federation-controller/util/test:go_default_library",
|
||||
"//pkg/api/meta:go_default_library",
|
||||
"//pkg/api/v1:go_default_library",
|
||||
"//pkg/apis/extensions/v1beta1:go_default_library",
|
||||
"//pkg/client/clientset_generated/release_1_5:go_default_library",
|
||||
"//pkg/client/clientset_generated/release_1_5/fake:go_default_library",
|
||||
"//pkg/client/testing/core:go_default_library",
|
||||
"//pkg/watch:go_default_library",
|
||||
"//vendor:github.com/stretchr/testify/assert",
|
||||
],
|
||||
)
|
||||
652
vendor/k8s.io/kubernetes/federation/pkg/federation-controller/replicaset/replicasetcontroller.go
generated
vendored
Normal file
652
vendor/k8s.io/kubernetes/federation/pkg/federation-controller/replicaset/replicasetcontroller.go
generated
vendored
Normal file
File diff suppressed because it is too large
Load diff
193
vendor/k8s.io/kubernetes/federation/pkg/federation-controller/replicaset/replicasetcontroller_test.go
generated
vendored
Normal file
193
vendor/k8s.io/kubernetes/federation/pkg/federation-controller/replicaset/replicasetcontroller_test.go
generated
vendored
Normal file
|
|
@ -0,0 +1,193 @@
|
|||
/*
|
||||
Copyright 2016 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package replicaset
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"fmt"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
fedv1 "k8s.io/kubernetes/federation/apis/federation/v1beta1"
|
||||
fedclientfake "k8s.io/kubernetes/federation/client/clientset_generated/federation_release_1_5/fake"
|
||||
"k8s.io/kubernetes/federation/pkg/federation-controller/util/test"
|
||||
"k8s.io/kubernetes/pkg/api/meta"
|
||||
apiv1 "k8s.io/kubernetes/pkg/api/v1"
|
||||
extensionsv1 "k8s.io/kubernetes/pkg/apis/extensions/v1beta1"
|
||||
kubeclientset "k8s.io/kubernetes/pkg/client/clientset_generated/release_1_5"
|
||||
kubeclientfake "k8s.io/kubernetes/pkg/client/clientset_generated/release_1_5/fake"
|
||||
"k8s.io/kubernetes/pkg/client/testing/core"
|
||||
"k8s.io/kubernetes/pkg/watch"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestParseFederationReplicaSetReference(t *testing.T) {
|
||||
successPrefs := []string{
|
||||
`{"rebalance": true,
|
||||
"clusters": {
|
||||
"k8s-1": {"minReplicas": 10, "maxReplicas": 20, "weight": 2},
|
||||
"*": {"weight": 1}
|
||||
}}`,
|
||||
}
|
||||
failedPrefes := []string{
|
||||
`{`, // bad json
|
||||
}
|
||||
|
||||
rs := newReplicaSetWithReplicas("rs-1", 100)
|
||||
accessor, _ := meta.Accessor(rs)
|
||||
anno := accessor.GetAnnotations()
|
||||
if anno == nil {
|
||||
anno = make(map[string]string)
|
||||
accessor.SetAnnotations(anno)
|
||||
}
|
||||
for _, prefString := range successPrefs {
|
||||
anno[FedReplicaSetPreferencesAnnotation] = prefString
|
||||
pref, err := parseFederationReplicaSetReference(rs)
|
||||
assert.NotNil(t, pref)
|
||||
assert.Nil(t, err)
|
||||
}
|
||||
for _, prefString := range failedPrefes {
|
||||
anno[FedReplicaSetPreferencesAnnotation] = prefString
|
||||
pref, err := parseFederationReplicaSetReference(rs)
|
||||
assert.Nil(t, pref)
|
||||
assert.NotNil(t, err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestReplicaSetController(t *testing.T) {
|
||||
flag.Set("logtostderr", "true")
|
||||
flag.Set("v", "5")
|
||||
flag.Parse()
|
||||
|
||||
replicaSetReviewDelay = 10 * time.Millisecond
|
||||
clusterAvailableDelay = 20 * time.Millisecond
|
||||
clusterUnavailableDelay = 60 * time.Millisecond
|
||||
allReplicaSetReviewDelay = 120 * time.Millisecond
|
||||
|
||||
fedclientset := fedclientfake.NewSimpleClientset()
|
||||
fedrswatch := watch.NewFake()
|
||||
fedclientset.PrependWatchReactor("replicasets", core.DefaultWatchReactor(fedrswatch, nil))
|
||||
|
||||
fedclientset.Federation().Clusters().Create(testutil.NewCluster("k8s-1", apiv1.ConditionTrue))
|
||||
fedclientset.Federation().Clusters().Create(testutil.NewCluster("k8s-2", apiv1.ConditionTrue))
|
||||
|
||||
kube1clientset := kubeclientfake.NewSimpleClientset()
|
||||
kube1rswatch := watch.NewFake()
|
||||
kube1clientset.PrependWatchReactor("replicasets", core.DefaultWatchReactor(kube1rswatch, nil))
|
||||
kube1Podwatch := watch.NewFake()
|
||||
kube1clientset.PrependWatchReactor("pods", core.DefaultWatchReactor(kube1Podwatch, nil))
|
||||
kube2clientset := kubeclientfake.NewSimpleClientset()
|
||||
kube2rswatch := watch.NewFake()
|
||||
kube2clientset.PrependWatchReactor("replicasets", core.DefaultWatchReactor(kube2rswatch, nil))
|
||||
kube2Podwatch := watch.NewFake()
|
||||
kube2clientset.PrependWatchReactor("pods", core.DefaultWatchReactor(kube2Podwatch, nil))
|
||||
|
||||
fedInformerClientFactory := func(cluster *fedv1.Cluster) (kubeclientset.Interface, error) {
|
||||
switch cluster.Name {
|
||||
case "k8s-1":
|
||||
return kube1clientset, nil
|
||||
case "k8s-2":
|
||||
return kube2clientset, nil
|
||||
default:
|
||||
return nil, fmt.Errorf("Unknown cluster: %v", cluster.Name)
|
||||
}
|
||||
}
|
||||
replicaSetController := NewReplicaSetController(fedclientset)
|
||||
rsFedinformer := testutil.ToFederatedInformerForTestOnly(replicaSetController.fedReplicaSetInformer)
|
||||
rsFedinformer.SetClientFactory(fedInformerClientFactory)
|
||||
podFedinformer := testutil.ToFederatedInformerForTestOnly(replicaSetController.fedPodInformer)
|
||||
podFedinformer.SetClientFactory(fedInformerClientFactory)
|
||||
|
||||
stopChan := make(chan struct{})
|
||||
defer close(stopChan)
|
||||
go replicaSetController.Run(1, stopChan)
|
||||
|
||||
rs := newReplicaSetWithReplicas("rs", 9)
|
||||
rs, _ = fedclientset.Extensions().ReplicaSets(apiv1.NamespaceDefault).Create(rs)
|
||||
fedrswatch.Add(rs)
|
||||
time.Sleep(1 * time.Second)
|
||||
|
||||
rs1, _ := kube1clientset.Extensions().ReplicaSets(apiv1.NamespaceDefault).Get(rs.Name)
|
||||
kube1rswatch.Add(rs1)
|
||||
rs1.Status.Replicas = *rs1.Spec.Replicas
|
||||
rs1.Status.FullyLabeledReplicas = *rs1.Spec.Replicas
|
||||
rs1.Status.ReadyReplicas = *rs1.Spec.Replicas
|
||||
rs1.Status.AvailableReplicas = *rs1.Spec.Replicas
|
||||
rs1, _ = kube1clientset.Extensions().ReplicaSets(apiv1.NamespaceDefault).UpdateStatus(rs1)
|
||||
kube1rswatch.Modify(rs1)
|
||||
|
||||
rs2, _ := kube2clientset.Extensions().ReplicaSets(apiv1.NamespaceDefault).Get(rs.Name)
|
||||
kube2rswatch.Add(rs2)
|
||||
rs2.Status.Replicas = *rs2.Spec.Replicas
|
||||
rs2.Status.FullyLabeledReplicas = *rs2.Spec.Replicas
|
||||
rs2.Status.ReadyReplicas = *rs2.Spec.Replicas
|
||||
rs2.Status.AvailableReplicas = *rs2.Spec.Replicas
|
||||
rs2, _ = kube2clientset.Extensions().ReplicaSets(apiv1.NamespaceDefault).UpdateStatus(rs2)
|
||||
kube2rswatch.Modify(rs2)
|
||||
|
||||
time.Sleep(1 * time.Second)
|
||||
rs, _ = fedclientset.Extensions().ReplicaSets(apiv1.NamespaceDefault).Get(rs.Name)
|
||||
assert.Equal(t, *rs.Spec.Replicas, *rs1.Spec.Replicas+*rs2.Spec.Replicas)
|
||||
assert.Equal(t, rs.Status.Replicas, rs1.Status.Replicas+rs2.Status.Replicas)
|
||||
assert.Equal(t, rs.Status.FullyLabeledReplicas, rs1.Status.FullyLabeledReplicas+rs2.Status.FullyLabeledReplicas)
|
||||
assert.Equal(t, rs.Status.ReadyReplicas, rs1.Status.ReadyReplicas+rs2.Status.ReadyReplicas)
|
||||
assert.Equal(t, rs.Status.AvailableReplicas, rs1.Status.AvailableReplicas+rs2.Status.AvailableReplicas)
|
||||
|
||||
var replicas int32 = 20
|
||||
rs.Spec.Replicas = &replicas
|
||||
rs, _ = fedclientset.Extensions().ReplicaSets(apiv1.NamespaceDefault).Update(rs)
|
||||
fedrswatch.Modify(rs)
|
||||
time.Sleep(1 * time.Second)
|
||||
|
||||
rs1, _ = kube1clientset.Extensions().ReplicaSets(apiv1.NamespaceDefault).Get(rs.Name)
|
||||
rs1.Status.Replicas = *rs1.Spec.Replicas
|
||||
rs1.Status.FullyLabeledReplicas = *rs1.Spec.Replicas
|
||||
rs1.Status.ReadyReplicas = *rs1.Spec.Replicas
|
||||
rs1.Status.AvailableReplicas = *rs1.Spec.Replicas
|
||||
rs1, _ = kube1clientset.Extensions().ReplicaSets(apiv1.NamespaceDefault).UpdateStatus(rs1)
|
||||
kube1rswatch.Modify(rs1)
|
||||
|
||||
rs2, _ = kube2clientset.Extensions().ReplicaSets(apiv1.NamespaceDefault).Get(rs.Name)
|
||||
rs2.Status.Replicas = *rs2.Spec.Replicas
|
||||
rs2.Status.FullyLabeledReplicas = *rs2.Spec.Replicas
|
||||
rs2.Status.ReadyReplicas = *rs2.Spec.Replicas
|
||||
rs2.Status.AvailableReplicas = *rs2.Spec.Replicas
|
||||
rs2, _ = kube2clientset.Extensions().ReplicaSets(apiv1.NamespaceDefault).UpdateStatus(rs2)
|
||||
kube2rswatch.Modify(rs2)
|
||||
|
||||
time.Sleep(1 * time.Second)
|
||||
rs, _ = fedclientset.Extensions().ReplicaSets(apiv1.NamespaceDefault).Get(rs.Name)
|
||||
assert.Equal(t, *rs.Spec.Replicas, *rs1.Spec.Replicas+*rs2.Spec.Replicas)
|
||||
assert.Equal(t, rs.Status.Replicas, rs1.Status.Replicas+rs2.Status.Replicas)
|
||||
assert.Equal(t, rs.Status.FullyLabeledReplicas, rs1.Status.FullyLabeledReplicas+rs2.Status.FullyLabeledReplicas)
|
||||
assert.Equal(t, rs.Status.ReadyReplicas, rs1.Status.ReadyReplicas+rs2.Status.ReadyReplicas)
|
||||
assert.Equal(t, rs.Status.AvailableReplicas, rs1.Status.AvailableReplicas+rs2.Status.AvailableReplicas)
|
||||
}
|
||||
|
||||
func newReplicaSetWithReplicas(name string, replicas int32) *extensionsv1.ReplicaSet {
|
||||
return &extensionsv1.ReplicaSet{
|
||||
ObjectMeta: apiv1.ObjectMeta{
|
||||
Name: name,
|
||||
Namespace: apiv1.NamespaceDefault,
|
||||
SelfLink: "/api/v1/namespaces/default/replicasets/name",
|
||||
},
|
||||
Spec: extensionsv1.ReplicaSetSpec{
|
||||
Replicas: &replicas,
|
||||
},
|
||||
}
|
||||
}
|
||||
58
vendor/k8s.io/kubernetes/federation/pkg/federation-controller/secret/BUILD
generated
vendored
Normal file
58
vendor/k8s.io/kubernetes/federation/pkg/federation-controller/secret/BUILD
generated
vendored
Normal file
|
|
@ -0,0 +1,58 @@
|
|||
package(default_visibility = ["//visibility:public"])
|
||||
|
||||
licenses(["notice"])
|
||||
|
||||
load(
|
||||
"@io_bazel_rules_go//go:def.bzl",
|
||||
"go_binary",
|
||||
"go_library",
|
||||
"go_test",
|
||||
"cgo_library",
|
||||
)
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = ["secret_controller.go"],
|
||||
tags = ["automanaged"],
|
||||
deps = [
|
||||
"//federation/apis/federation/v1beta1:go_default_library",
|
||||
"//federation/client/clientset_generated/federation_release_1_5:go_default_library",
|
||||
"//federation/pkg/federation-controller/util:go_default_library",
|
||||
"//federation/pkg/federation-controller/util/deletionhelper:go_default_library",
|
||||
"//federation/pkg/federation-controller/util/eventsink:go_default_library",
|
||||
"//pkg/api:go_default_library",
|
||||
"//pkg/api/errors:go_default_library",
|
||||
"//pkg/api/v1:go_default_library",
|
||||
"//pkg/client/cache:go_default_library",
|
||||
"//pkg/client/clientset_generated/release_1_5:go_default_library",
|
||||
"//pkg/client/record:go_default_library",
|
||||
"//pkg/controller:go_default_library",
|
||||
"//pkg/conversion:go_default_library",
|
||||
"//pkg/runtime:go_default_library",
|
||||
"//pkg/types:go_default_library",
|
||||
"//pkg/util/flowcontrol:go_default_library",
|
||||
"//pkg/watch:go_default_library",
|
||||
"//vendor:github.com/golang/glog",
|
||||
],
|
||||
)
|
||||
|
||||
go_test(
|
||||
name = "go_default_test",
|
||||
srcs = ["secret_controller_test.go"],
|
||||
library = "go_default_library",
|
||||
tags = ["automanaged"],
|
||||
deps = [
|
||||
"//federation/apis/federation/v1beta1:go_default_library",
|
||||
"//federation/client/clientset_generated/federation_release_1_5/fake:go_default_library",
|
||||
"//federation/pkg/federation-controller/util:go_default_library",
|
||||
"//federation/pkg/federation-controller/util/deletionhelper:go_default_library",
|
||||
"//federation/pkg/federation-controller/util/test:go_default_library",
|
||||
"//pkg/api/v1:go_default_library",
|
||||
"//pkg/client/clientset_generated/release_1_5:go_default_library",
|
||||
"//pkg/client/clientset_generated/release_1_5/fake:go_default_library",
|
||||
"//pkg/runtime:go_default_library",
|
||||
"//pkg/types:go_default_library",
|
||||
"//pkg/util/wait:go_default_library",
|
||||
"//vendor:github.com/stretchr/testify/assert",
|
||||
],
|
||||
)
|
||||
436
vendor/k8s.io/kubernetes/federation/pkg/federation-controller/secret/secret_controller.go
generated
vendored
Normal file
436
vendor/k8s.io/kubernetes/federation/pkg/federation-controller/secret/secret_controller.go
generated
vendored
Normal file
|
|
@ -0,0 +1,436 @@
|
|||
/*
|
||||
Copyright 2016 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package secret
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
federationapi "k8s.io/kubernetes/federation/apis/federation/v1beta1"
|
||||
federationclientset "k8s.io/kubernetes/federation/client/clientset_generated/federation_release_1_5"
|
||||
"k8s.io/kubernetes/federation/pkg/federation-controller/util"
|
||||
"k8s.io/kubernetes/federation/pkg/federation-controller/util/deletionhelper"
|
||||
"k8s.io/kubernetes/federation/pkg/federation-controller/util/eventsink"
|
||||
"k8s.io/kubernetes/pkg/api"
|
||||
"k8s.io/kubernetes/pkg/api/errors"
|
||||
apiv1 "k8s.io/kubernetes/pkg/api/v1"
|
||||
"k8s.io/kubernetes/pkg/client/cache"
|
||||
kubeclientset "k8s.io/kubernetes/pkg/client/clientset_generated/release_1_5"
|
||||
"k8s.io/kubernetes/pkg/client/record"
|
||||
"k8s.io/kubernetes/pkg/controller"
|
||||
"k8s.io/kubernetes/pkg/conversion"
|
||||
pkgruntime "k8s.io/kubernetes/pkg/runtime"
|
||||
"k8s.io/kubernetes/pkg/types"
|
||||
"k8s.io/kubernetes/pkg/util/flowcontrol"
|
||||
"k8s.io/kubernetes/pkg/watch"
|
||||
|
||||
"github.com/golang/glog"
|
||||
)
|
||||
|
||||
const (
|
||||
allClustersKey = "ALL_CLUSTERS"
|
||||
)
|
||||
|
||||
type SecretController struct {
|
||||
// For triggering single secret reconciliation. This is used when there is an
|
||||
// add/update/delete operation on a secret in either federated API server or
|
||||
// in some member of the federation.
|
||||
secretDeliverer *util.DelayingDeliverer
|
||||
|
||||
// For triggering all secrets reconciliation. This is used when
|
||||
// a new cluster becomes available.
|
||||
clusterDeliverer *util.DelayingDeliverer
|
||||
|
||||
// Contains secrets present in members of federation.
|
||||
secretFederatedInformer util.FederatedInformer
|
||||
// For updating members of federation.
|
||||
federatedUpdater util.FederatedUpdater
|
||||
// Definitions of secrets that should be federated.
|
||||
secretInformerStore cache.Store
|
||||
// Informer controller for secrets that should be federated.
|
||||
secretInformerController cache.ControllerInterface
|
||||
|
||||
// Client to federated api server.
|
||||
federatedApiClient federationclientset.Interface
|
||||
|
||||
// Backoff manager for secrets
|
||||
secretBackoff *flowcontrol.Backoff
|
||||
|
||||
// For events
|
||||
eventRecorder record.EventRecorder
|
||||
|
||||
deletionHelper *deletionhelper.DeletionHelper
|
||||
|
||||
secretReviewDelay time.Duration
|
||||
clusterAvailableDelay time.Duration
|
||||
smallDelay time.Duration
|
||||
updateTimeout time.Duration
|
||||
}
|
||||
|
||||
// NewSecretController returns a new secret controller
|
||||
func NewSecretController(client federationclientset.Interface) *SecretController {
|
||||
broadcaster := record.NewBroadcaster()
|
||||
broadcaster.StartRecordingToSink(eventsink.NewFederatedEventSink(client))
|
||||
recorder := broadcaster.NewRecorder(apiv1.EventSource{Component: "federated-secrets-controller"})
|
||||
|
||||
secretcontroller := &SecretController{
|
||||
federatedApiClient: client,
|
||||
secretReviewDelay: time.Second * 10,
|
||||
clusterAvailableDelay: time.Second * 20,
|
||||
smallDelay: time.Second * 3,
|
||||
updateTimeout: time.Second * 30,
|
||||
secretBackoff: flowcontrol.NewBackOff(5*time.Second, time.Minute),
|
||||
eventRecorder: recorder,
|
||||
}
|
||||
|
||||
// Build delivereres for triggering reconciliations.
|
||||
secretcontroller.secretDeliverer = util.NewDelayingDeliverer()
|
||||
secretcontroller.clusterDeliverer = util.NewDelayingDeliverer()
|
||||
|
||||
// Start informer in federated API servers on secrets that should be federated.
|
||||
secretcontroller.secretInformerStore, secretcontroller.secretInformerController = cache.NewInformer(
|
||||
&cache.ListWatch{
|
||||
ListFunc: func(options apiv1.ListOptions) (pkgruntime.Object, error) {
|
||||
return client.Core().Secrets(apiv1.NamespaceAll).List(options)
|
||||
},
|
||||
WatchFunc: func(options apiv1.ListOptions) (watch.Interface, error) {
|
||||
return client.Core().Secrets(apiv1.NamespaceAll).Watch(options)
|
||||
},
|
||||
},
|
||||
&apiv1.Secret{},
|
||||
controller.NoResyncPeriodFunc(),
|
||||
util.NewTriggerOnAllChanges(func(obj pkgruntime.Object) { secretcontroller.deliverSecretObj(obj, 0, false) }))
|
||||
|
||||
// Federated informer on secrets in members of federation.
|
||||
secretcontroller.secretFederatedInformer = util.NewFederatedInformer(
|
||||
client,
|
||||
func(cluster *federationapi.Cluster, targetClient kubeclientset.Interface) (cache.Store, cache.ControllerInterface) {
|
||||
return cache.NewInformer(
|
||||
&cache.ListWatch{
|
||||
ListFunc: func(options apiv1.ListOptions) (pkgruntime.Object, error) {
|
||||
return targetClient.Core().Secrets(apiv1.NamespaceAll).List(options)
|
||||
},
|
||||
WatchFunc: func(options apiv1.ListOptions) (watch.Interface, error) {
|
||||
return targetClient.Core().Secrets(apiv1.NamespaceAll).Watch(options)
|
||||
},
|
||||
},
|
||||
&apiv1.Secret{},
|
||||
controller.NoResyncPeriodFunc(),
|
||||
// Trigger reconciliation whenever something in federated cluster is changed. In most cases it
|
||||
// would be just confirmation that some secret opration succeeded.
|
||||
util.NewTriggerOnAllChanges(
|
||||
func(obj pkgruntime.Object) {
|
||||
secretcontroller.deliverSecretObj(obj, secretcontroller.secretReviewDelay, false)
|
||||
},
|
||||
))
|
||||
},
|
||||
|
||||
&util.ClusterLifecycleHandlerFuncs{
|
||||
ClusterAvailable: func(cluster *federationapi.Cluster) {
|
||||
// When new cluster becomes available process all the secrets again.
|
||||
secretcontroller.clusterDeliverer.DeliverAt(allClustersKey, nil, time.Now().Add(secretcontroller.clusterAvailableDelay))
|
||||
},
|
||||
},
|
||||
)
|
||||
|
||||
// Federated updeater along with Create/Update/Delete operations.
|
||||
secretcontroller.federatedUpdater = util.NewFederatedUpdater(secretcontroller.secretFederatedInformer,
|
||||
func(client kubeclientset.Interface, obj pkgruntime.Object) error {
|
||||
secret := obj.(*apiv1.Secret)
|
||||
_, err := client.Core().Secrets(secret.Namespace).Create(secret)
|
||||
return err
|
||||
},
|
||||
func(client kubeclientset.Interface, obj pkgruntime.Object) error {
|
||||
secret := obj.(*apiv1.Secret)
|
||||
_, err := client.Core().Secrets(secret.Namespace).Update(secret)
|
||||
return err
|
||||
},
|
||||
func(client kubeclientset.Interface, obj pkgruntime.Object) error {
|
||||
secret := obj.(*apiv1.Secret)
|
||||
err := client.Core().Secrets(secret.Namespace).Delete(secret.Name, &apiv1.DeleteOptions{})
|
||||
return err
|
||||
})
|
||||
|
||||
secretcontroller.deletionHelper = deletionhelper.NewDeletionHelper(
|
||||
secretcontroller.hasFinalizerFunc,
|
||||
secretcontroller.removeFinalizerFunc,
|
||||
secretcontroller.addFinalizerFunc,
|
||||
// objNameFunc
|
||||
func(obj pkgruntime.Object) string {
|
||||
secret := obj.(*apiv1.Secret)
|
||||
return secret.Name
|
||||
},
|
||||
secretcontroller.updateTimeout,
|
||||
secretcontroller.eventRecorder,
|
||||
secretcontroller.secretFederatedInformer,
|
||||
secretcontroller.federatedUpdater,
|
||||
)
|
||||
|
||||
return secretcontroller
|
||||
}
|
||||
|
||||
// Returns true if the given object has the given finalizer in its ObjectMeta.
|
||||
func (secretcontroller *SecretController) hasFinalizerFunc(obj pkgruntime.Object, finalizer string) bool {
|
||||
secret := obj.(*apiv1.Secret)
|
||||
for i := range secret.ObjectMeta.Finalizers {
|
||||
if string(secret.ObjectMeta.Finalizers[i]) == finalizer {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// Removes the finalizer from the given objects ObjectMeta.
|
||||
// Assumes that the given object is a secret.
|
||||
func (secretcontroller *SecretController) removeFinalizerFunc(obj pkgruntime.Object, finalizer string) (pkgruntime.Object, error) {
|
||||
secret := obj.(*apiv1.Secret)
|
||||
newFinalizers := []string{}
|
||||
hasFinalizer := false
|
||||
for i := range secret.ObjectMeta.Finalizers {
|
||||
if string(secret.ObjectMeta.Finalizers[i]) != finalizer {
|
||||
newFinalizers = append(newFinalizers, secret.ObjectMeta.Finalizers[i])
|
||||
} else {
|
||||
hasFinalizer = true
|
||||
}
|
||||
}
|
||||
if !hasFinalizer {
|
||||
// Nothing to do.
|
||||
return obj, nil
|
||||
}
|
||||
secret.ObjectMeta.Finalizers = newFinalizers
|
||||
secret, err := secretcontroller.federatedApiClient.Core().Secrets(secret.Namespace).Update(secret)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to remove finalizer %s from secret %s: %v", finalizer, secret.Name, err)
|
||||
}
|
||||
return secret, nil
|
||||
}
|
||||
|
||||
// Adds the given finalizer to the given objects ObjectMeta.
|
||||
// Assumes that the given object is a secret.
|
||||
func (secretcontroller *SecretController) addFinalizerFunc(obj pkgruntime.Object, finalizer string) (pkgruntime.Object, error) {
|
||||
secret := obj.(*apiv1.Secret)
|
||||
secret.ObjectMeta.Finalizers = append(secret.ObjectMeta.Finalizers, finalizer)
|
||||
secret, err := secretcontroller.federatedApiClient.Core().Secrets(secret.Namespace).Update(secret)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to add finalizer %s to secret %s: %v", finalizer, secret.Name, err)
|
||||
}
|
||||
return secret, nil
|
||||
}
|
||||
|
||||
func (secretcontroller *SecretController) Run(stopChan <-chan struct{}) {
|
||||
go secretcontroller.secretInformerController.Run(stopChan)
|
||||
secretcontroller.secretFederatedInformer.Start()
|
||||
go func() {
|
||||
<-stopChan
|
||||
secretcontroller.secretFederatedInformer.Stop()
|
||||
}()
|
||||
secretcontroller.secretDeliverer.StartWithHandler(func(item *util.DelayingDelivererItem) {
|
||||
secret := item.Value.(*types.NamespacedName)
|
||||
secretcontroller.reconcileSecret(*secret)
|
||||
})
|
||||
secretcontroller.clusterDeliverer.StartWithHandler(func(_ *util.DelayingDelivererItem) {
|
||||
secretcontroller.reconcileSecretsOnClusterChange()
|
||||
})
|
||||
util.StartBackoffGC(secretcontroller.secretBackoff, stopChan)
|
||||
}
|
||||
|
||||
func (secretcontroller *SecretController) deliverSecretObj(obj interface{}, delay time.Duration, failed bool) {
|
||||
secret := obj.(*apiv1.Secret)
|
||||
secretcontroller.deliverSecret(types.NamespacedName{Namespace: secret.Namespace, Name: secret.Name}, delay, failed)
|
||||
}
|
||||
|
||||
// Adds backoff to delay if this delivery is related to some failure. Resets backoff if there was no failure.
|
||||
func (secretcontroller *SecretController) deliverSecret(secret types.NamespacedName, delay time.Duration, failed bool) {
|
||||
key := secret.String()
|
||||
if failed {
|
||||
secretcontroller.secretBackoff.Next(key, time.Now())
|
||||
delay = delay + secretcontroller.secretBackoff.Get(key)
|
||||
} else {
|
||||
secretcontroller.secretBackoff.Reset(key)
|
||||
}
|
||||
secretcontroller.secretDeliverer.DeliverAfter(key, &secret, delay)
|
||||
}
|
||||
|
||||
// Check whether all data stores are in sync. False is returned if any of the informer/stores is not yet
|
||||
// synced with the corresponding api server.
|
||||
func (secretcontroller *SecretController) isSynced() bool {
|
||||
if !secretcontroller.secretFederatedInformer.ClustersSynced() {
|
||||
glog.V(2).Infof("Cluster list not synced")
|
||||
return false
|
||||
}
|
||||
clusters, err := secretcontroller.secretFederatedInformer.GetReadyClusters()
|
||||
if err != nil {
|
||||
glog.Errorf("Failed to get ready clusters: %v", err)
|
||||
return false
|
||||
}
|
||||
if !secretcontroller.secretFederatedInformer.GetTargetStore().ClustersSynced(clusters) {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// The function triggers reconciliation of all federated secrets.
|
||||
func (secretcontroller *SecretController) reconcileSecretsOnClusterChange() {
|
||||
if !secretcontroller.isSynced() {
|
||||
secretcontroller.clusterDeliverer.DeliverAt(allClustersKey, nil, time.Now().Add(secretcontroller.clusterAvailableDelay))
|
||||
}
|
||||
for _, obj := range secretcontroller.secretInformerStore.List() {
|
||||
secret := obj.(*apiv1.Secret)
|
||||
secretcontroller.deliverSecret(types.NamespacedName{Namespace: secret.Namespace, Name: secret.Name}, secretcontroller.smallDelay, false)
|
||||
}
|
||||
}
|
||||
|
||||
func (secretcontroller *SecretController) reconcileSecret(secret types.NamespacedName) {
|
||||
if !secretcontroller.isSynced() {
|
||||
secretcontroller.deliverSecret(secret, secretcontroller.clusterAvailableDelay, false)
|
||||
return
|
||||
}
|
||||
|
||||
key := secret.String()
|
||||
baseSecretObjFromStore, exist, err := secretcontroller.secretInformerStore.GetByKey(key)
|
||||
if err != nil {
|
||||
glog.Errorf("Failed to query main secret store for %v: %v", key, err)
|
||||
secretcontroller.deliverSecret(secret, 0, true)
|
||||
return
|
||||
}
|
||||
|
||||
if !exist {
|
||||
// Not federated secret, ignoring.
|
||||
return
|
||||
}
|
||||
|
||||
// Create a copy before modifying the obj to prevent race condition with
|
||||
// other readers of obj from store.
|
||||
baseSecretObj, err := conversion.NewCloner().DeepCopy(baseSecretObjFromStore)
|
||||
baseSecret, ok := baseSecretObj.(*apiv1.Secret)
|
||||
if err != nil || !ok {
|
||||
glog.Errorf("Error in retrieving obj from store: %v, %v", ok, err)
|
||||
secretcontroller.deliverSecret(secret, 0, true)
|
||||
return
|
||||
}
|
||||
if baseSecret.DeletionTimestamp != nil {
|
||||
if err := secretcontroller.delete(baseSecret); err != nil {
|
||||
glog.Errorf("Failed to delete %s: %v", secret, err)
|
||||
secretcontroller.eventRecorder.Eventf(baseSecret, api.EventTypeNormal, "DeleteFailed",
|
||||
"Secret delete failed: %v", err)
|
||||
secretcontroller.deliverSecret(secret, 0, true)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
glog.V(3).Infof("Ensuring delete object from underlying clusters finalizer for secret: %s",
|
||||
baseSecret.Name)
|
||||
// Add the required finalizers before creating a secret in underlying clusters.
|
||||
updatedSecretObj, err := secretcontroller.deletionHelper.EnsureFinalizers(baseSecret)
|
||||
if err != nil {
|
||||
glog.Errorf("Failed to ensure delete object from underlying clusters finalizer in secret %s: %v",
|
||||
baseSecret.Name, err)
|
||||
secretcontroller.deliverSecret(secret, 0, false)
|
||||
return
|
||||
}
|
||||
baseSecret = updatedSecretObj.(*apiv1.Secret)
|
||||
|
||||
glog.V(3).Infof("Syncing secret %s in underlying clusters", baseSecret.Name)
|
||||
|
||||
clusters, err := secretcontroller.secretFederatedInformer.GetReadyClusters()
|
||||
if err != nil {
|
||||
glog.Errorf("Failed to get cluster list: %v", err)
|
||||
secretcontroller.deliverSecret(secret, secretcontroller.clusterAvailableDelay, false)
|
||||
return
|
||||
}
|
||||
|
||||
operations := make([]util.FederatedOperation, 0)
|
||||
for _, cluster := range clusters {
|
||||
clusterSecretObj, found, err := secretcontroller.secretFederatedInformer.GetTargetStore().GetByKey(cluster.Name, key)
|
||||
if err != nil {
|
||||
glog.Errorf("Failed to get %s from %s: %v", key, cluster.Name, err)
|
||||
secretcontroller.deliverSecret(secret, 0, true)
|
||||
return
|
||||
}
|
||||
|
||||
// The data should not be modified.
|
||||
desiredSecret := &apiv1.Secret{
|
||||
ObjectMeta: util.DeepCopyRelevantObjectMeta(baseSecret.ObjectMeta),
|
||||
Data: baseSecret.Data,
|
||||
Type: baseSecret.Type,
|
||||
}
|
||||
|
||||
if !found {
|
||||
secretcontroller.eventRecorder.Eventf(baseSecret, api.EventTypeNormal, "CreateInCluster",
|
||||
"Creating secret in cluster %s", cluster.Name)
|
||||
|
||||
operations = append(operations, util.FederatedOperation{
|
||||
Type: util.OperationTypeAdd,
|
||||
Obj: desiredSecret,
|
||||
ClusterName: cluster.Name,
|
||||
})
|
||||
} else {
|
||||
clusterSecret := clusterSecretObj.(*apiv1.Secret)
|
||||
|
||||
// Update existing secret, if needed.
|
||||
if !util.SecretEquivalent(*desiredSecret, *clusterSecret) {
|
||||
|
||||
secretcontroller.eventRecorder.Eventf(baseSecret, api.EventTypeNormal, "UpdateInCluster",
|
||||
"Updating secret in cluster %s", cluster.Name)
|
||||
operations = append(operations, util.FederatedOperation{
|
||||
Type: util.OperationTypeUpdate,
|
||||
Obj: desiredSecret,
|
||||
ClusterName: cluster.Name,
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if len(operations) == 0 {
|
||||
// Everything is in order
|
||||
return
|
||||
}
|
||||
err = secretcontroller.federatedUpdater.UpdateWithOnError(operations, secretcontroller.updateTimeout,
|
||||
func(op util.FederatedOperation, operror error) {
|
||||
secretcontroller.eventRecorder.Eventf(baseSecret, api.EventTypeNormal, "UpdateInClusterFailed",
|
||||
"Secret update in cluster %s failed: %v", op.ClusterName, operror)
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
glog.Errorf("Failed to execute updates for %s: %v", key, err)
|
||||
secretcontroller.deliverSecret(secret, 0, true)
|
||||
return
|
||||
}
|
||||
|
||||
// Evertyhing is in order but lets be double sure
|
||||
secretcontroller.deliverSecret(secret, secretcontroller.secretReviewDelay, false)
|
||||
}
|
||||
|
||||
// delete deletes the given secret or returns error if the deletion was not complete.
|
||||
func (secretcontroller *SecretController) delete(secret *apiv1.Secret) error {
|
||||
glog.V(3).Infof("Handling deletion of secret: %v", *secret)
|
||||
_, err := secretcontroller.deletionHelper.HandleObjectInUnderlyingClusters(secret)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = secretcontroller.federatedApiClient.Core().Secrets(secret.Namespace).Delete(secret.Name, nil)
|
||||
if err != nil {
|
||||
// Its all good if the error is not found error. That means it is deleted already and we do not have to do anything.
|
||||
// This is expected when we are processing an update as a result of secret finalizer deletion.
|
||||
// The process that deleted the last finalizer is also going to delete the secret and we do not have to do anything.
|
||||
if !errors.IsNotFound(err) {
|
||||
return fmt.Errorf("failed to delete secret: %v", err)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
196
vendor/k8s.io/kubernetes/federation/pkg/federation-controller/secret/secret_controller_test.go
generated
vendored
Normal file
196
vendor/k8s.io/kubernetes/federation/pkg/federation-controller/secret/secret_controller_test.go
generated
vendored
Normal file
|
|
@ -0,0 +1,196 @@
|
|||
/*
|
||||
Copyright 2016 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package secret
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
federationapi "k8s.io/kubernetes/federation/apis/federation/v1beta1"
|
||||
fakefedclientset "k8s.io/kubernetes/federation/client/clientset_generated/federation_release_1_5/fake"
|
||||
"k8s.io/kubernetes/federation/pkg/federation-controller/util"
|
||||
"k8s.io/kubernetes/federation/pkg/federation-controller/util/deletionhelper"
|
||||
. "k8s.io/kubernetes/federation/pkg/federation-controller/util/test"
|
||||
apiv1 "k8s.io/kubernetes/pkg/api/v1"
|
||||
kubeclientset "k8s.io/kubernetes/pkg/client/clientset_generated/release_1_5"
|
||||
fakekubeclientset "k8s.io/kubernetes/pkg/client/clientset_generated/release_1_5/fake"
|
||||
"k8s.io/kubernetes/pkg/runtime"
|
||||
"k8s.io/kubernetes/pkg/types"
|
||||
"k8s.io/kubernetes/pkg/util/wait"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestSecretController(t *testing.T) {
|
||||
cluster1 := NewCluster("cluster1", apiv1.ConditionTrue)
|
||||
cluster2 := NewCluster("cluster2", apiv1.ConditionTrue)
|
||||
|
||||
fakeClient := &fakefedclientset.Clientset{}
|
||||
RegisterFakeList("clusters", &fakeClient.Fake, &federationapi.ClusterList{Items: []federationapi.Cluster{*cluster1}})
|
||||
RegisterFakeList("secrets", &fakeClient.Fake, &apiv1.SecretList{Items: []apiv1.Secret{}})
|
||||
secretWatch := RegisterFakeWatch("secrets", &fakeClient.Fake)
|
||||
secretUpdateChan := RegisterFakeCopyOnUpdate("secrets", &fakeClient.Fake, secretWatch)
|
||||
clusterWatch := RegisterFakeWatch("clusters", &fakeClient.Fake)
|
||||
|
||||
cluster1Client := &fakekubeclientset.Clientset{}
|
||||
cluster1Watch := RegisterFakeWatch("secrets", &cluster1Client.Fake)
|
||||
RegisterFakeList("secrets", &cluster1Client.Fake, &apiv1.SecretList{Items: []apiv1.Secret{}})
|
||||
cluster1CreateChan := RegisterFakeCopyOnCreate("secrets", &cluster1Client.Fake, cluster1Watch)
|
||||
// cluster1UpdateChan := RegisterFakeCopyOnUpdate("secrets", &cluster1Client.Fake, cluster1Watch)
|
||||
|
||||
cluster2Client := &fakekubeclientset.Clientset{}
|
||||
cluster2Watch := RegisterFakeWatch("secrets", &cluster2Client.Fake)
|
||||
RegisterFakeList("secrets", &cluster2Client.Fake, &apiv1.SecretList{Items: []apiv1.Secret{}})
|
||||
cluster2CreateChan := RegisterFakeCopyOnCreate("secrets", &cluster2Client.Fake, cluster2Watch)
|
||||
|
||||
secretController := NewSecretController(fakeClient)
|
||||
informerClientFactory := func(cluster *federationapi.Cluster) (kubeclientset.Interface, error) {
|
||||
switch cluster.Name {
|
||||
case cluster1.Name:
|
||||
return cluster1Client, nil
|
||||
case cluster2.Name:
|
||||
return cluster2Client, nil
|
||||
default:
|
||||
return nil, fmt.Errorf("Unknown cluster")
|
||||
}
|
||||
}
|
||||
setClientFactory(secretController.secretFederatedInformer, informerClientFactory)
|
||||
|
||||
secretController.clusterAvailableDelay = time.Second
|
||||
secretController.secretReviewDelay = 50 * time.Millisecond
|
||||
secretController.smallDelay = 20 * time.Millisecond
|
||||
secretController.updateTimeout = 5 * time.Second
|
||||
|
||||
stop := make(chan struct{})
|
||||
secretController.Run(stop)
|
||||
|
||||
secret1 := apiv1.Secret{
|
||||
ObjectMeta: apiv1.ObjectMeta{
|
||||
Name: "test-secret",
|
||||
Namespace: "ns",
|
||||
SelfLink: "/api/v1/namespaces/ns/secrets/test-secret",
|
||||
},
|
||||
Data: map[string][]byte{
|
||||
"A": []byte("ala ma kota"),
|
||||
"B": []byte("quick brown fox"),
|
||||
},
|
||||
Type: apiv1.SecretTypeOpaque,
|
||||
}
|
||||
|
||||
// Test add federated secret.
|
||||
secretWatch.Add(&secret1)
|
||||
// There should be 2 updates to add both the finalizers.
|
||||
updatedSecret := GetSecretFromChan(secretUpdateChan)
|
||||
assert.True(t, secretController.hasFinalizerFunc(updatedSecret, deletionhelper.FinalizerDeleteFromUnderlyingClusters))
|
||||
updatedSecret = GetSecretFromChan(secretUpdateChan)
|
||||
assert.True(t, secretController.hasFinalizerFunc(updatedSecret, apiv1.FinalizerOrphan))
|
||||
secret1 = *updatedSecret
|
||||
|
||||
// Verify that the secret is created in underlying cluster1.
|
||||
createdSecret := GetSecretFromChan(cluster1CreateChan)
|
||||
assert.NotNil(t, createdSecret)
|
||||
assert.Equal(t, secret1.Namespace, createdSecret.Namespace)
|
||||
assert.Equal(t, secret1.Name, createdSecret.Name)
|
||||
assert.True(t, secretsEqual(secret1, *createdSecret),
|
||||
fmt.Sprintf("expected: %v, actual: %v", secret1, *createdSecret))
|
||||
|
||||
// Wait for the secret to appear in the informer store
|
||||
err := WaitForStoreUpdate(
|
||||
secretController.secretFederatedInformer.GetTargetStore(),
|
||||
cluster1.Name, types.NamespacedName{Namespace: secret1.Namespace, Name: secret1.Name}.String(), wait.ForeverTestTimeout)
|
||||
assert.Nil(t, err, "secret should have appeared in the informer store")
|
||||
|
||||
/*
|
||||
// TODO: Uncomment this once we have figured out why this is flaky.
|
||||
// Test update federated secret.
|
||||
secret1.Annotations = map[string]string{
|
||||
"A": "B",
|
||||
}
|
||||
secretWatch.Modify(&secret1)
|
||||
updatedSecret = GetSecretFromChan(cluster1UpdateChan)
|
||||
assert.NotNil(t, updatedSecret)
|
||||
assert.Equal(t, secret1.Name, updatedSecret.Name)
|
||||
assert.Equal(t, secret1.Namespace, updatedSecret.Namespace)
|
||||
assert.True(t, secretsEqual(secret1, *updatedSecret),
|
||||
fmt.Sprintf("expected: %v, actual: %v", secret1, *updatedSecret))
|
||||
// Wait for the secret to be updated in the informer store.
|
||||
err = WaitForSecretStoreUpdate(
|
||||
secretController.secretFederatedInformer.GetTargetStore(),
|
||||
cluster1.Name, types.NamespacedName{Namespace: secret1.Namespace, Name: secret1.Name}.String(),
|
||||
updatedSecret, wait.ForeverTestTimeout)
|
||||
assert.Nil(t, err, "secret should have been updated in the informer store")
|
||||
|
||||
// Test update federated secret.
|
||||
secret1.Data = map[string][]byte{
|
||||
"config": []byte("myconfigurationfile"),
|
||||
}
|
||||
secretWatch.Modify(&secret1)
|
||||
updatedSecret2 := GetSecretFromChan(cluster1UpdateChan)
|
||||
assert.NotNil(t, updatedSecret2)
|
||||
assert.Equal(t, secret1.Name, updatedSecret2.Name)
|
||||
assert.Equal(t, secret1.Namespace, updatedSecret.Namespace)
|
||||
assert.True(t, secretsEqual(secret1, *updatedSecret2),
|
||||
fmt.Sprintf("expected: %v, actual: %v", secret1, *updatedSecret2))
|
||||
*/
|
||||
|
||||
// Test add cluster
|
||||
clusterWatch.Add(cluster2)
|
||||
createdSecret2 := GetSecretFromChan(cluster2CreateChan)
|
||||
assert.NotNil(t, createdSecret2)
|
||||
assert.Equal(t, secret1.Name, createdSecret2.Name)
|
||||
assert.Equal(t, secret1.Namespace, createdSecret2.Namespace)
|
||||
assert.True(t, secretsEqual(secret1, *createdSecret2),
|
||||
fmt.Sprintf("expected: %v, actual: %v", secret1, *createdSecret2))
|
||||
|
||||
close(stop)
|
||||
}
|
||||
|
||||
func setClientFactory(informer util.FederatedInformer, informerClientFactory func(*federationapi.Cluster) (kubeclientset.Interface, error)) {
|
||||
testInformer := ToFederatedInformerForTestOnly(informer)
|
||||
testInformer.SetClientFactory(informerClientFactory)
|
||||
}
|
||||
|
||||
func secretsEqual(a, b apiv1.Secret) bool {
|
||||
// Clear the SelfLink and ObjectMeta.Finalizers since they will be different
|
||||
// in resoure in federation control plane and resource in underlying cluster.
|
||||
a.SelfLink = ""
|
||||
b.SelfLink = ""
|
||||
a.ObjectMeta.Finalizers = []string{}
|
||||
b.ObjectMeta.Finalizers = []string{}
|
||||
return reflect.DeepEqual(a, b)
|
||||
}
|
||||
|
||||
func GetSecretFromChan(c chan runtime.Object) *apiv1.Secret {
|
||||
secret := GetObjectFromChan(c).(*apiv1.Secret)
|
||||
return secret
|
||||
}
|
||||
|
||||
// Wait till the store is updated with latest secret.
|
||||
func WaitForSecretStoreUpdate(store util.FederatedReadOnlyStore, clusterName, key string, desiredSecret *apiv1.Secret, timeout time.Duration) error {
|
||||
retryInterval := 100 * time.Millisecond
|
||||
err := wait.PollImmediate(retryInterval, timeout, func() (bool, error) {
|
||||
obj, found, err := store.GetByKey(clusterName, key)
|
||||
if !found || err != nil {
|
||||
return false, err
|
||||
}
|
||||
equal := secretsEqual(*obj.(*apiv1.Secret), *desiredSecret)
|
||||
return equal, err
|
||||
})
|
||||
return err
|
||||
}
|
||||
65
vendor/k8s.io/kubernetes/federation/pkg/federation-controller/service/BUILD
generated
vendored
Normal file
65
vendor/k8s.io/kubernetes/federation/pkg/federation-controller/service/BUILD
generated
vendored
Normal file
|
|
@ -0,0 +1,65 @@
|
|||
package(default_visibility = ["//visibility:public"])
|
||||
|
||||
licenses(["notice"])
|
||||
|
||||
load(
|
||||
"@io_bazel_rules_go//go:def.bzl",
|
||||
"go_binary",
|
||||
"go_library",
|
||||
"go_test",
|
||||
"cgo_library",
|
||||
)
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = [
|
||||
"cluster_helper.go",
|
||||
"dns.go",
|
||||
"doc.go",
|
||||
"endpoint_helper.go",
|
||||
"service_helper.go",
|
||||
"servicecontroller.go",
|
||||
],
|
||||
tags = ["automanaged"],
|
||||
deps = [
|
||||
"//federation/apis/federation/v1beta1:go_default_library",
|
||||
"//federation/client/cache:go_default_library",
|
||||
"//federation/client/clientset_generated/federation_release_1_5:go_default_library",
|
||||
"//federation/pkg/dnsprovider:go_default_library",
|
||||
"//federation/pkg/dnsprovider/rrstype:go_default_library",
|
||||
"//federation/pkg/federation-controller/util:go_default_library",
|
||||
"//pkg/api/errors:go_default_library",
|
||||
"//pkg/api/v1:go_default_library",
|
||||
"//pkg/client/cache:go_default_library",
|
||||
"//pkg/client/clientset_generated/release_1_5:go_default_library",
|
||||
"//pkg/client/record:go_default_library",
|
||||
"//pkg/client/restclient:go_default_library",
|
||||
"//pkg/controller:go_default_library",
|
||||
"//pkg/conversion:go_default_library",
|
||||
"//pkg/runtime:go_default_library",
|
||||
"//pkg/util/runtime:go_default_library",
|
||||
"//pkg/util/sets:go_default_library",
|
||||
"//pkg/util/wait:go_default_library",
|
||||
"//pkg/util/workqueue:go_default_library",
|
||||
"//pkg/watch:go_default_library",
|
||||
"//vendor:github.com/golang/glog",
|
||||
],
|
||||
)
|
||||
|
||||
go_test(
|
||||
name = "go_default_test",
|
||||
srcs = [
|
||||
"dns_test.go",
|
||||
"endpoint_helper_test.go",
|
||||
"service_helper_test.go",
|
||||
"servicecontroller_test.go",
|
||||
],
|
||||
library = "go_default_library",
|
||||
tags = ["automanaged"],
|
||||
deps = [
|
||||
"//federation/apis/federation/v1beta1:go_default_library",
|
||||
"//federation/pkg/dnsprovider/providers/google/clouddns:go_default_library",
|
||||
"//pkg/api/v1:go_default_library",
|
||||
"//pkg/util/sets:go_default_library",
|
||||
],
|
||||
)
|
||||
205
vendor/k8s.io/kubernetes/federation/pkg/federation-controller/service/cluster_helper.go
generated
vendored
Normal file
205
vendor/k8s.io/kubernetes/federation/pkg/federation-controller/service/cluster_helper.go
generated
vendored
Normal file
|
|
@ -0,0 +1,205 @@
|
|||
/*
|
||||
Copyright 2016 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package service
|
||||
|
||||
import (
|
||||
"sync"
|
||||
|
||||
v1beta1 "k8s.io/kubernetes/federation/apis/federation/v1beta1"
|
||||
v1 "k8s.io/kubernetes/pkg/api/v1"
|
||||
cache "k8s.io/kubernetes/pkg/client/cache"
|
||||
kubeclientset "k8s.io/kubernetes/pkg/client/clientset_generated/release_1_5"
|
||||
"k8s.io/kubernetes/pkg/client/restclient"
|
||||
pkgruntime "k8s.io/kubernetes/pkg/runtime"
|
||||
"k8s.io/kubernetes/pkg/util/wait"
|
||||
"k8s.io/kubernetes/pkg/util/workqueue"
|
||||
"k8s.io/kubernetes/pkg/watch"
|
||||
|
||||
"reflect"
|
||||
|
||||
"github.com/golang/glog"
|
||||
"k8s.io/kubernetes/federation/pkg/federation-controller/util"
|
||||
)
|
||||
|
||||
type clusterCache struct {
|
||||
clientset *kubeclientset.Clientset
|
||||
cluster *v1beta1.Cluster
|
||||
// A store of services, populated by the serviceController
|
||||
serviceStore cache.StoreToServiceLister
|
||||
// Watches changes to all services
|
||||
serviceController *cache.Controller
|
||||
// A store of endpoint, populated by the serviceController
|
||||
endpointStore cache.StoreToEndpointsLister
|
||||
// Watches changes to all endpoints
|
||||
endpointController *cache.Controller
|
||||
// services that need to be synced
|
||||
serviceQueue *workqueue.Type
|
||||
// endpoints that need to be synced
|
||||
endpointQueue *workqueue.Type
|
||||
}
|
||||
|
||||
type clusterClientCache struct {
|
||||
rwlock sync.Mutex // protects serviceMap
|
||||
clientMap map[string]*clusterCache
|
||||
}
|
||||
|
||||
func (cc *clusterClientCache) startClusterLW(cluster *v1beta1.Cluster, clusterName string) {
|
||||
cachedClusterClient, ok := cc.clientMap[clusterName]
|
||||
// only create when no existing cachedClusterClient
|
||||
if ok {
|
||||
if !reflect.DeepEqual(cachedClusterClient.cluster.Spec, cluster.Spec) {
|
||||
//rebuild clientset when cluster spec is changed
|
||||
clientset, err := newClusterClientset(cluster)
|
||||
if err != nil || clientset == nil {
|
||||
glog.Errorf("Failed to create corresponding restclient of kubernetes cluster: %v", err)
|
||||
}
|
||||
glog.V(4).Infof("Cluster spec changed, rebuild clientset for cluster %s", clusterName)
|
||||
cachedClusterClient.clientset = clientset
|
||||
go cachedClusterClient.serviceController.Run(wait.NeverStop)
|
||||
go cachedClusterClient.endpointController.Run(wait.NeverStop)
|
||||
glog.V(2).Infof("Start watching services and endpoints on cluster %s", clusterName)
|
||||
} else {
|
||||
// do nothing when there is no spec change
|
||||
glog.V(4).Infof("Keep clientset for cluster %s", clusterName)
|
||||
return
|
||||
}
|
||||
} else {
|
||||
glog.V(4).Infof("No client cache for cluster %s, building new", clusterName)
|
||||
clientset, err := newClusterClientset(cluster)
|
||||
if err != nil || clientset == nil {
|
||||
glog.Errorf("Failed to create corresponding restclient of kubernetes cluster: %v", err)
|
||||
}
|
||||
cachedClusterClient = &clusterCache{
|
||||
cluster: cluster,
|
||||
clientset: clientset,
|
||||
serviceQueue: workqueue.New(),
|
||||
endpointQueue: workqueue.New(),
|
||||
}
|
||||
cachedClusterClient.endpointStore.Store, cachedClusterClient.endpointController = cache.NewInformer(
|
||||
&cache.ListWatch{
|
||||
ListFunc: func(options v1.ListOptions) (pkgruntime.Object, error) {
|
||||
return clientset.Core().Endpoints(v1.NamespaceAll).List(options)
|
||||
},
|
||||
WatchFunc: func(options v1.ListOptions) (watch.Interface, error) {
|
||||
return clientset.Core().Endpoints(v1.NamespaceAll).Watch(options)
|
||||
},
|
||||
},
|
||||
&v1.Endpoints{},
|
||||
serviceSyncPeriod,
|
||||
cache.ResourceEventHandlerFuncs{
|
||||
AddFunc: func(obj interface{}) {
|
||||
cc.enqueueEndpoint(obj, clusterName)
|
||||
},
|
||||
UpdateFunc: func(old, cur interface{}) {
|
||||
cc.enqueueEndpoint(cur, clusterName)
|
||||
},
|
||||
DeleteFunc: func(obj interface{}) {
|
||||
cc.enqueueEndpoint(obj, clusterName)
|
||||
},
|
||||
},
|
||||
)
|
||||
|
||||
cachedClusterClient.serviceStore.Indexer, cachedClusterClient.serviceController = cache.NewIndexerInformer(
|
||||
&cache.ListWatch{
|
||||
ListFunc: func(options v1.ListOptions) (pkgruntime.Object, error) {
|
||||
return clientset.Core().Services(v1.NamespaceAll).List(options)
|
||||
},
|
||||
WatchFunc: func(options v1.ListOptions) (watch.Interface, error) {
|
||||
return clientset.Core().Services(v1.NamespaceAll).Watch(options)
|
||||
},
|
||||
},
|
||||
&v1.Service{},
|
||||
serviceSyncPeriod,
|
||||
cache.ResourceEventHandlerFuncs{
|
||||
AddFunc: func(obj interface{}) {
|
||||
cc.enqueueService(obj, clusterName)
|
||||
},
|
||||
UpdateFunc: func(old, cur interface{}) {
|
||||
oldService, ok := old.(*v1.Service)
|
||||
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
curService, ok := cur.(*v1.Service)
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
if !reflect.DeepEqual(oldService.Status.LoadBalancer, curService.Status.LoadBalancer) {
|
||||
cc.enqueueService(cur, clusterName)
|
||||
}
|
||||
},
|
||||
DeleteFunc: func(obj interface{}) {
|
||||
service, _ := obj.(*v1.Service)
|
||||
cc.enqueueService(obj, clusterName)
|
||||
glog.V(2).Infof("Service %s/%s deletion found and enque to service store %s", service.Namespace, service.Name, clusterName)
|
||||
},
|
||||
},
|
||||
cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc},
|
||||
)
|
||||
cc.clientMap[clusterName] = cachedClusterClient
|
||||
go cachedClusterClient.serviceController.Run(wait.NeverStop)
|
||||
go cachedClusterClient.endpointController.Run(wait.NeverStop)
|
||||
glog.V(2).Infof("Start watching services and endpoints on cluster %s", clusterName)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//TODO: copied from cluster controller, to make this as common function in pass 2
|
||||
// delFromClusterSet delete a cluster from clusterSet and
|
||||
// delete the corresponding restclient from the map clusterKubeClientMap
|
||||
func (cc *clusterClientCache) delFromClusterSet(obj interface{}) {
|
||||
cluster, ok := obj.(*v1beta1.Cluster)
|
||||
cc.rwlock.Lock()
|
||||
defer cc.rwlock.Unlock()
|
||||
if ok {
|
||||
delete(cc.clientMap, cluster.Name)
|
||||
} else {
|
||||
tombstone, ok := obj.(cache.DeletedFinalStateUnknown)
|
||||
if !ok {
|
||||
glog.Infof("Object contained wasn't a cluster or a deleted key: %+v", obj)
|
||||
return
|
||||
}
|
||||
glog.Infof("Found tombstone for %v", obj)
|
||||
delete(cc.clientMap, tombstone.Key)
|
||||
}
|
||||
}
|
||||
|
||||
// addToClusterSet inserts the new cluster to clusterSet and creates a corresponding
|
||||
// restclient to map clusterKubeClientMap
|
||||
func (cc *clusterClientCache) addToClientMap(obj interface{}) {
|
||||
cc.rwlock.Lock()
|
||||
defer cc.rwlock.Unlock()
|
||||
cluster, ok := obj.(*v1beta1.Cluster)
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
pred := getClusterConditionPredicate()
|
||||
// check status
|
||||
// skip if not ready
|
||||
if pred(*cluster) {
|
||||
cc.startClusterLW(cluster, cluster.Name)
|
||||
}
|
||||
}
|
||||
|
||||
func newClusterClientset(c *v1beta1.Cluster) (*kubeclientset.Clientset, error) {
|
||||
clusterConfig, err := util.BuildClusterConfig(c)
|
||||
if clusterConfig != nil {
|
||||
clientset := kubeclientset.NewForConfigOrDie(restclient.AddUserAgent(clusterConfig, UserAgentName))
|
||||
return clientset, nil
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
366
vendor/k8s.io/kubernetes/federation/pkg/federation-controller/service/dns.go
generated
vendored
Normal file
366
vendor/k8s.io/kubernetes/federation/pkg/federation-controller/service/dns.go
generated
vendored
Normal file
|
|
@ -0,0 +1,366 @@
|
|||
/*
|
||||
Copyright 2016 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package service
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net"
|
||||
|
||||
"github.com/golang/glog"
|
||||
|
||||
"strings"
|
||||
|
||||
"k8s.io/kubernetes/federation/pkg/dnsprovider"
|
||||
"k8s.io/kubernetes/federation/pkg/dnsprovider/rrstype"
|
||||
)
|
||||
|
||||
const (
|
||||
// minDnsTtl is the minimum safe DNS TTL value to use (in seconds). We use this as the TTL for all DNS records.
|
||||
minDnsTtl = 180
|
||||
)
|
||||
|
||||
// getHealthyEndpoints returns the hostnames and/or IP addresses of healthy endpoints for the service, at a zone, region and global level (or an error)
|
||||
func (s *ServiceController) getHealthyEndpoints(clusterName string, cachedService *cachedService) (zoneEndpoints, regionEndpoints, globalEndpoints []string, err error) {
|
||||
var (
|
||||
zoneNames []string
|
||||
regionName string
|
||||
)
|
||||
if zoneNames, regionName, err = s.getClusterZoneNames(clusterName); err != nil {
|
||||
return nil, nil, nil, err
|
||||
}
|
||||
for lbClusterName, lbStatus := range cachedService.serviceStatusMap {
|
||||
lbZoneNames, lbRegionName, err := s.getClusterZoneNames(lbClusterName)
|
||||
if err != nil {
|
||||
return nil, nil, nil, err
|
||||
}
|
||||
for _, ingress := range lbStatus.Ingress {
|
||||
readyEndpoints, ok := cachedService.endpointMap[lbClusterName]
|
||||
if !ok || readyEndpoints == 0 {
|
||||
continue
|
||||
}
|
||||
var address string
|
||||
// We should get either an IP address or a hostname - use whichever one we get
|
||||
if ingress.IP != "" {
|
||||
address = ingress.IP
|
||||
} else if ingress.Hostname != "" {
|
||||
address = ingress.Hostname
|
||||
}
|
||||
if len(address) <= 0 {
|
||||
return nil, nil, nil, fmt.Errorf("Service %s/%s in cluster %s has neither LoadBalancerStatus.ingress.ip nor LoadBalancerStatus.ingress.hostname. Cannot use it as endpoint for federated service.",
|
||||
cachedService.lastState.Name, cachedService.lastState.Namespace, clusterName)
|
||||
}
|
||||
for _, lbZoneName := range lbZoneNames {
|
||||
for _, zoneName := range zoneNames {
|
||||
if lbZoneName == zoneName {
|
||||
zoneEndpoints = append(zoneEndpoints, address)
|
||||
}
|
||||
}
|
||||
}
|
||||
if lbRegionName == regionName {
|
||||
regionEndpoints = append(regionEndpoints, address)
|
||||
}
|
||||
globalEndpoints = append(globalEndpoints, address)
|
||||
}
|
||||
}
|
||||
return zoneEndpoints, regionEndpoints, globalEndpoints, nil
|
||||
}
|
||||
|
||||
// getClusterZoneNames returns the name of the zones (and the region) where the specified cluster exists (e.g. zones "us-east1-c" on GCE, or "us-east-1b" on AWS)
|
||||
func (s *ServiceController) getClusterZoneNames(clusterName string) (zones []string, region string, err error) {
|
||||
client, ok := s.clusterCache.clientMap[clusterName]
|
||||
if !ok {
|
||||
return nil, "", fmt.Errorf("Cluster cache does not contain entry for cluster %s", clusterName)
|
||||
}
|
||||
if client.cluster == nil {
|
||||
return nil, "", fmt.Errorf("Cluster cache entry for cluster %s is nil", clusterName)
|
||||
}
|
||||
return client.cluster.Status.Zones, client.cluster.Status.Region, nil
|
||||
}
|
||||
|
||||
// getServiceDnsSuffix returns the DNS suffix to use when creating federated-service DNS records
|
||||
func (s *ServiceController) getServiceDnsSuffix() (string, error) {
|
||||
return s.serviceDnsSuffix, nil
|
||||
}
|
||||
|
||||
// getDnsZones returns the DNS zones matching dnsZoneName and dnsZoneID (if specified)
|
||||
func getDnsZones(dnsZoneName string, dnsZoneID string, dnsZonesInterface dnsprovider.Zones) ([]dnsprovider.Zone, error) {
|
||||
// TODO: We need query-by-name and query-by-id functions
|
||||
dnsZones, err := dnsZonesInterface.List()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var matches []dnsprovider.Zone
|
||||
findName := strings.TrimSuffix(dnsZoneName, ".")
|
||||
for _, dnsZone := range dnsZones {
|
||||
if dnsZoneID != "" {
|
||||
if dnsZoneID != dnsZone.ID() {
|
||||
continue
|
||||
}
|
||||
}
|
||||
if findName != "" {
|
||||
if strings.TrimSuffix(dnsZone.Name(), ".") != findName {
|
||||
continue
|
||||
}
|
||||
}
|
||||
matches = append(matches, dnsZone)
|
||||
}
|
||||
|
||||
return matches, nil
|
||||
}
|
||||
|
||||
// getDnsZone returns the DNS zone, as identified by dnsZoneName and dnsZoneID
|
||||
// This is similar to getDnsZones, but returns an error if there are zero or multiple matching zones.
|
||||
func getDnsZone(dnsZoneName string, dnsZoneID string, dnsZonesInterface dnsprovider.Zones) (dnsprovider.Zone, error) {
|
||||
dnsZones, err := getDnsZones(dnsZoneName, dnsZoneID, dnsZonesInterface)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if len(dnsZones) == 1 {
|
||||
return dnsZones[0], nil
|
||||
}
|
||||
|
||||
name := dnsZoneName
|
||||
if dnsZoneID != "" {
|
||||
name += "/" + dnsZoneID
|
||||
}
|
||||
|
||||
if len(dnsZones) == 0 {
|
||||
return nil, fmt.Errorf("DNS zone %s not found.", name)
|
||||
} else {
|
||||
return nil, fmt.Errorf("DNS zone %s is ambiguous (please specify zoneID).", name)
|
||||
}
|
||||
}
|
||||
|
||||
/* getRrset is a hack around the fact that dnsprovider.ResourceRecordSets interface does not yet include a Get() method, only a List() method. TODO: Fix that.
|
||||
Note that if the named resource record set does not exist, but no error occurred, the returned set, and error, are both nil
|
||||
*/
|
||||
func getRrset(dnsName string, rrsetsInterface dnsprovider.ResourceRecordSets) (dnsprovider.ResourceRecordSet, error) {
|
||||
var returnVal dnsprovider.ResourceRecordSet
|
||||
rrsets, err := rrsetsInterface.List()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for _, rrset := range rrsets {
|
||||
if rrset.Name() == dnsName {
|
||||
returnVal = rrset
|
||||
break
|
||||
}
|
||||
}
|
||||
return returnVal, nil
|
||||
}
|
||||
|
||||
/* getResolvedEndpoints performs DNS resolution on the provided slice of endpoints (which might be DNS names or IPv4 addresses)
|
||||
and returns a list of IPv4 addresses. If any of the endpoints are neither valid IPv4 addresses nor resolvable DNS names,
|
||||
non-nil error is also returned (possibly along with a partially complete list of resolved endpoints.
|
||||
*/
|
||||
func getResolvedEndpoints(endpoints []string) ([]string, error) {
|
||||
resolvedEndpoints := make([]string, 0, len(endpoints))
|
||||
for _, endpoint := range endpoints {
|
||||
if net.ParseIP(endpoint) == nil {
|
||||
// It's not a valid IP address, so assume it's a DNS name, and try to resolve it,
|
||||
// replacing its DNS name with its IP addresses in expandedEndpoints
|
||||
ipAddrs, err := net.LookupHost(endpoint)
|
||||
if err != nil {
|
||||
return resolvedEndpoints, err
|
||||
}
|
||||
resolvedEndpoints = append(resolvedEndpoints, ipAddrs...)
|
||||
|
||||
} else {
|
||||
resolvedEndpoints = append(resolvedEndpoints, endpoint)
|
||||
}
|
||||
}
|
||||
return resolvedEndpoints, nil
|
||||
}
|
||||
|
||||
/* ensureDnsRrsets ensures (idempotently, and with minimum mutations) that all of the DNS resource record sets for dnsName are consistent with endpoints.
|
||||
if endpoints is nil or empty, a CNAME record to uplevelCname is ensured.
|
||||
*/
|
||||
func (s *ServiceController) ensureDnsRrsets(dnsZone dnsprovider.Zone, dnsName string, endpoints []string, uplevelCname string) error {
|
||||
rrsets, supported := dnsZone.ResourceRecordSets()
|
||||
if !supported {
|
||||
return fmt.Errorf("Failed to ensure DNS records for %s. DNS provider does not support the ResourceRecordSets interface.", dnsName)
|
||||
}
|
||||
rrset, err := getRrset(dnsName, rrsets) // TODO: rrsets.Get(dnsName)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if rrset == nil {
|
||||
glog.V(4).Infof("No recordsets found for DNS name %q. Need to add either A records (if we have healthy endpoints), or a CNAME record to %q", dnsName, uplevelCname)
|
||||
if len(endpoints) < 1 {
|
||||
glog.V(4).Infof("There are no healthy endpoint addresses at level %q, so CNAME to %q, if provided", dnsName, uplevelCname)
|
||||
if uplevelCname != "" {
|
||||
glog.V(4).Infof("Creating CNAME to %q for %q", uplevelCname, dnsName)
|
||||
newRrset := rrsets.New(dnsName, []string{uplevelCname}, minDnsTtl, rrstype.CNAME)
|
||||
glog.V(4).Infof("Adding recordset %v", newRrset)
|
||||
err = rrsets.StartChangeset().Add(newRrset).Apply()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
glog.V(4).Infof("Successfully created CNAME to %q for %q", uplevelCname, dnsName)
|
||||
} else {
|
||||
glog.V(4).Infof("We want no record for %q, and we have no record, so we're all good.", dnsName)
|
||||
}
|
||||
} else {
|
||||
// We have valid endpoint addresses, so just add them as A records.
|
||||
// But first resolve DNS names, as some cloud providers (like AWS) expose
|
||||
// load balancers behind DNS names, not IP addresses.
|
||||
glog.V(4).Infof("We have valid endpoint addresses %v at level %q, so add them as A records, after resolving DNS names", endpoints, dnsName)
|
||||
resolvedEndpoints, err := getResolvedEndpoints(endpoints)
|
||||
if err != nil {
|
||||
return err // TODO: We could potentially add the ones we did get back, even if some of them failed to resolve.
|
||||
}
|
||||
newRrset := rrsets.New(dnsName, resolvedEndpoints, minDnsTtl, rrstype.A)
|
||||
glog.V(4).Infof("Adding recordset %v", newRrset)
|
||||
err = rrsets.StartChangeset().Add(newRrset).Apply()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
glog.V(4).Infof("Successfully added recordset %v", newRrset)
|
||||
}
|
||||
} else {
|
||||
// the rrset already exists, so make it right.
|
||||
glog.V(4).Infof("Recordset %v already exists. Ensuring that it is correct.", rrset)
|
||||
if len(endpoints) < 1 {
|
||||
// Need an appropriate CNAME record. Check that we have it.
|
||||
newRrset := rrsets.New(dnsName, []string{uplevelCname}, minDnsTtl, rrstype.CNAME)
|
||||
glog.V(4).Infof("No healthy endpoints for %s. Have recordset %v. Need recordset %v", dnsName, rrset, newRrset)
|
||||
if dnsprovider.ResourceRecordSetsEquivalent(rrset, newRrset) {
|
||||
// The existing rrset is equivalent to the required one - our work is done here
|
||||
glog.V(4).Infof("Existing recordset %v is equivalent to needed recordset %v, our work is done here.", rrset, newRrset)
|
||||
return nil
|
||||
} else {
|
||||
// Need to replace the existing one with a better one (or just remove it if we have no healthy endpoints).
|
||||
glog.V(4).Infof("Existing recordset %v not equivalent to needed recordset %v removing existing and adding needed.", rrset, newRrset)
|
||||
changeSet := rrsets.StartChangeset()
|
||||
changeSet.Remove(rrset)
|
||||
if uplevelCname != "" {
|
||||
changeSet.Add(newRrset)
|
||||
if err := changeSet.Apply(); err != nil {
|
||||
return err
|
||||
}
|
||||
glog.V(4).Infof("Successfully replaced needed recordset %v -> %v", rrset, newRrset)
|
||||
} else {
|
||||
if err := changeSet.Apply(); err != nil {
|
||||
return err
|
||||
}
|
||||
glog.V(4).Infof("Successfully removed existing recordset %v", rrset)
|
||||
glog.V(4).Infof("Uplevel CNAME is empty string. Not adding recordset %v", newRrset)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// We have an rrset in DNS, possibly with some missing addresses and some unwanted addresses.
|
||||
// And we have healthy endpoints. Just replace what's there with the healthy endpoints, if it's not already correct.
|
||||
glog.V(4).Infof("%s: Healthy endpoints %v exist. Recordset %v exists. Reconciling.", dnsName, endpoints, rrset)
|
||||
resolvedEndpoints, err := getResolvedEndpoints(endpoints)
|
||||
if err != nil { // Some invalid addresses or otherwise unresolvable DNS names.
|
||||
return err // TODO: We could potentially add the ones we did get back, even if some of them failed to resolve.
|
||||
}
|
||||
newRrset := rrsets.New(dnsName, resolvedEndpoints, minDnsTtl, rrstype.A)
|
||||
glog.V(4).Infof("Have recordset %v. Need recordset %v", rrset, newRrset)
|
||||
if dnsprovider.ResourceRecordSetsEquivalent(rrset, newRrset) {
|
||||
glog.V(4).Infof("Existing recordset %v is equivalent to needed recordset %v, our work is done here.", rrset, newRrset)
|
||||
// TODO: We could be more thorough about checking for equivalence to avoid unnecessary updates, but in the
|
||||
// worst case we'll just replace what's there with an equivalent, if not exactly identical record set.
|
||||
return nil
|
||||
} else {
|
||||
// Need to replace the existing one with a better one
|
||||
glog.V(4).Infof("Existing recordset %v is not equivalent to needed recordset %v, removing existing and adding needed.", rrset, newRrset)
|
||||
if err = rrsets.StartChangeset().Remove(rrset).Add(newRrset).Apply(); err != nil {
|
||||
return err
|
||||
}
|
||||
glog.V(4).Infof("Successfully replaced recordset %v -> %v", rrset, newRrset)
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
/* ensureDnsRecords ensures (idempotently, and with minimum mutations) that all of the DNS records for a service in a given cluster are correct,
|
||||
given the current state of that service in that cluster. This should be called every time the state of a service might have changed
|
||||
(either w.r.t. it's loadbalancer address, or if the number of healthy backend endpoints for that service transitioned from zero to non-zero
|
||||
(or vice verse). Only shards of the service which have both a loadbalancer ingress IP address or hostname AND at least one healthy backend endpoint
|
||||
are included in DNS records for that service (at all of zone, region and global levels). All other addresses are removed. Also, if no shards exist
|
||||
in the zone or region of the cluster, a CNAME reference to the next higher level is ensured to exist. */
|
||||
func (s *ServiceController) ensureDnsRecords(clusterName string, cachedService *cachedService) error {
|
||||
// Quinton: Pseudocode....
|
||||
// See https://github.com/kubernetes/kubernetes/pull/25107#issuecomment-218026648
|
||||
// For each service we need the following DNS names:
|
||||
// mysvc.myns.myfed.svc.z1.r1.mydomain.com (for zone z1 in region r1)
|
||||
// - an A record to IP address of specific shard in that zone (if that shard exists and has healthy endpoints)
|
||||
// - OR a CNAME record to the next level up, i.e. mysvc.myns.myfed.svc.r1.mydomain.com (if a healthy shard does not exist in zone z1)
|
||||
// mysvc.myns.myfed.svc.r1.federation
|
||||
// - a set of A records to IP addresses of all healthy shards in region r1, if one or more of these exist
|
||||
// - OR a CNAME record to the next level up, i.e. mysvc.myns.myfed.svc.mydomain.com (if no healthy shards exist in region r1)
|
||||
// mysvc.myns.myfed.svc.federation
|
||||
// - a set of A records to IP addresses of all healthy shards in all regions, if one or more of these exist.
|
||||
// - no record (NXRECORD response) if no healthy shards exist in any regions)
|
||||
//
|
||||
// For each cached service, cachedService.lastState tracks the current known state of the service, while cachedService.appliedState contains
|
||||
// the state of the service when we last successfully sync'd it's DNS records.
|
||||
// So this time around we only need to patch that (add new records, remove deleted records, and update changed records.
|
||||
//
|
||||
if s == nil {
|
||||
return fmt.Errorf("nil ServiceController passed to ServiceController.ensureDnsRecords(clusterName: %s, cachedService: %v)", clusterName, cachedService)
|
||||
}
|
||||
if s.dns == nil {
|
||||
return nil
|
||||
}
|
||||
if cachedService == nil {
|
||||
return fmt.Errorf("nil cachedService passed to ServiceController.ensureDnsRecords(clusterName: %s, cachedService: %v)", clusterName, cachedService)
|
||||
}
|
||||
serviceName := cachedService.lastState.Name
|
||||
namespaceName := cachedService.lastState.Namespace
|
||||
zoneNames, regionName, err := s.getClusterZoneNames(clusterName)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if zoneNames == nil {
|
||||
return fmt.Errorf("failed to get cluster zone names")
|
||||
}
|
||||
serviceDnsSuffix, err := s.getServiceDnsSuffix()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
zoneEndpoints, regionEndpoints, globalEndpoints, err := s.getHealthyEndpoints(clusterName, cachedService)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
commonPrefix := serviceName + "." + namespaceName + "." + s.federationName + ".svc"
|
||||
// dnsNames is the path up the DNS search tree, starting at the leaf
|
||||
dnsNames := []string{
|
||||
commonPrefix + "." + zoneNames[0] + "." + regionName + "." + serviceDnsSuffix, // zone level - TODO might need other zone names for multi-zone clusters
|
||||
commonPrefix + "." + regionName + "." + serviceDnsSuffix, // region level, one up from zone level
|
||||
commonPrefix + "." + serviceDnsSuffix, // global level, one up from region level
|
||||
"", // nowhere to go up from global level
|
||||
}
|
||||
|
||||
endpoints := [][]string{zoneEndpoints, regionEndpoints, globalEndpoints}
|
||||
|
||||
dnsZone, err := getDnsZone(s.zoneName, s.zoneID, s.dnsZones)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for i, endpoint := range endpoints {
|
||||
if err = s.ensureDnsRrsets(dnsZone, dnsNames[i], endpoint, dnsNames[i+1]); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
171
vendor/k8s.io/kubernetes/federation/pkg/federation-controller/service/dns_test.go
generated
vendored
Normal file
171
vendor/k8s.io/kubernetes/federation/pkg/federation-controller/service/dns_test.go
generated
vendored
Normal file
|
|
@ -0,0 +1,171 @@
|
|||
/*
|
||||
Copyright 2016 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package service
|
||||
|
||||
import (
|
||||
"sync"
|
||||
"testing"
|
||||
|
||||
"fmt"
|
||||
"reflect"
|
||||
"sort"
|
||||
|
||||
"k8s.io/kubernetes/federation/apis/federation/v1beta1"
|
||||
"k8s.io/kubernetes/federation/pkg/dnsprovider/providers/google/clouddns" // Only for unit testing purposes.
|
||||
"k8s.io/kubernetes/pkg/api/v1"
|
||||
"k8s.io/kubernetes/pkg/util/sets"
|
||||
)
|
||||
|
||||
func TestServiceController_ensureDnsRecords(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
service v1.Service
|
||||
expected []string
|
||||
serviceStatus v1.LoadBalancerStatus
|
||||
}{
|
||||
{
|
||||
name: "withip",
|
||||
service: v1.Service{
|
||||
ObjectMeta: v1.ObjectMeta{
|
||||
Name: "servicename",
|
||||
Namespace: "servicenamespace",
|
||||
},
|
||||
},
|
||||
serviceStatus: buildServiceStatus([][]string{{"198.51.100.1", ""}}),
|
||||
expected: []string{
|
||||
"example.com:servicename.servicenamespace.myfederation.svc.federation.example.com:A:180:[198.51.100.1]",
|
||||
"example.com:servicename.servicenamespace.myfederation.svc.fooregion.federation.example.com:A:180:[198.51.100.1]",
|
||||
"example.com:servicename.servicenamespace.myfederation.svc.foozone.fooregion.federation.example.com:A:180:[198.51.100.1]",
|
||||
},
|
||||
},
|
||||
/*
|
||||
TODO: getResolvedEndpoints preforms DNS lookup.
|
||||
Mock and maybe look at error handling when some endpoints resolve, but also caching?
|
||||
{
|
||||
name: "withname",
|
||||
service: v1.Service{
|
||||
ObjectMeta: v1.ObjectMeta{
|
||||
Name: "servicename",
|
||||
Namespace: "servicenamespace",
|
||||
},
|
||||
},
|
||||
serviceStatus: buildServiceStatus([][]string{{"", "randomstring.amazonelb.example.com"}}),
|
||||
expected: []string{
|
||||
"example.com:servicename.servicenamespace.myfederation.svc.federation.example.com:A:180:[198.51.100.1]",
|
||||
"example.com:servicename.servicenamespace.myfederation.svc.fooregion.federation.example.com:A:180:[198.51.100.1]",
|
||||
"example.com:servicename.servicenamespace.myfederation.svc.foozone.fooregion.federation.example.com:A:180:[198.51.100.1]",
|
||||
},
|
||||
},
|
||||
*/
|
||||
{
|
||||
name: "noendpoints",
|
||||
service: v1.Service{
|
||||
ObjectMeta: v1.ObjectMeta{
|
||||
Name: "servicename",
|
||||
Namespace: "servicenamespace",
|
||||
},
|
||||
},
|
||||
expected: []string{
|
||||
"example.com:servicename.servicenamespace.myfederation.svc.fooregion.federation.example.com:CNAME:180:[servicename.servicenamespace.myfederation.svc.federation.example.com]",
|
||||
"example.com:servicename.servicenamespace.myfederation.svc.foozone.fooregion.federation.example.com:CNAME:180:[servicename.servicenamespace.myfederation.svc.fooregion.federation.example.com]",
|
||||
},
|
||||
},
|
||||
}
|
||||
for _, test := range tests {
|
||||
fakedns, _ := clouddns.NewFakeInterface()
|
||||
fakednsZones, ok := fakedns.Zones()
|
||||
if !ok {
|
||||
t.Error("Unable to fetch zones")
|
||||
}
|
||||
serviceController := ServiceController{
|
||||
dns: fakedns,
|
||||
dnsZones: fakednsZones,
|
||||
serviceDnsSuffix: "federation.example.com",
|
||||
zoneName: "example.com",
|
||||
federationName: "myfederation",
|
||||
serviceCache: &serviceCache{fedServiceMap: make(map[string]*cachedService)},
|
||||
clusterCache: &clusterClientCache{
|
||||
rwlock: sync.Mutex{},
|
||||
clientMap: make(map[string]*clusterCache),
|
||||
},
|
||||
knownClusterSet: make(sets.String),
|
||||
}
|
||||
|
||||
clusterName := "testcluster"
|
||||
|
||||
serviceController.clusterCache.clientMap[clusterName] = &clusterCache{
|
||||
cluster: &v1beta1.Cluster{
|
||||
Status: v1beta1.ClusterStatus{
|
||||
Zones: []string{"foozone"},
|
||||
Region: "fooregion",
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
cachedService := &cachedService{
|
||||
lastState: &test.service,
|
||||
endpointMap: make(map[string]int),
|
||||
serviceStatusMap: make(map[string]v1.LoadBalancerStatus),
|
||||
}
|
||||
cachedService.endpointMap[clusterName] = 1
|
||||
if !reflect.DeepEqual(&test.serviceStatus, &v1.LoadBalancerStatus{}) {
|
||||
cachedService.serviceStatusMap[clusterName] = test.serviceStatus
|
||||
}
|
||||
|
||||
err := serviceController.ensureDnsRecords(clusterName, cachedService)
|
||||
if err != nil {
|
||||
t.Errorf("Test failed for %s, unexpected error %v", test.name, err)
|
||||
}
|
||||
|
||||
zones, err := fakednsZones.List()
|
||||
if err != nil {
|
||||
t.Errorf("error querying zones: %v", err)
|
||||
}
|
||||
|
||||
// Dump every record to a testable-by-string-comparison form
|
||||
var records []string
|
||||
for _, z := range zones {
|
||||
zoneName := z.Name()
|
||||
|
||||
rrs, ok := z.ResourceRecordSets()
|
||||
if !ok {
|
||||
t.Errorf("cannot get rrs for zone %q", zoneName)
|
||||
}
|
||||
|
||||
rrList, err := rrs.List()
|
||||
if err != nil {
|
||||
t.Errorf("error querying rr for zone %q: %v", zoneName, err)
|
||||
}
|
||||
for _, rr := range rrList {
|
||||
rrdatas := rr.Rrdatas()
|
||||
|
||||
// Put in consistent (testable-by-string-comparison) order
|
||||
sort.Strings(rrdatas)
|
||||
records = append(records, fmt.Sprintf("%s:%s:%s:%d:%s", zoneName, rr.Name(), rr.Type(), rr.Ttl(), rrdatas))
|
||||
}
|
||||
}
|
||||
|
||||
// Ignore order of records
|
||||
sort.Strings(records)
|
||||
sort.Strings(test.expected)
|
||||
|
||||
if !reflect.DeepEqual(records, test.expected) {
|
||||
t.Errorf("Test %q failed. Actual=%v, Expected=%v", test.name, records, test.expected)
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
19
vendor/k8s.io/kubernetes/federation/pkg/federation-controller/service/doc.go
generated
vendored
Normal file
19
vendor/k8s.io/kubernetes/federation/pkg/federation-controller/service/doc.go
generated
vendored
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
/*
|
||||
Copyright 2016 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
// Package service contains code for syncing Kubernetes services,
|
||||
// and cloud DNS servers with the federated service registry.
|
||||
package service // import "k8s.io/kubernetes/federation/pkg/federation-controller/service"
|
||||
206
vendor/k8s.io/kubernetes/federation/pkg/federation-controller/service/endpoint_helper.go
generated
vendored
Normal file
206
vendor/k8s.io/kubernetes/federation/pkg/federation-controller/service/endpoint_helper.go
generated
vendored
Normal file
|
|
@ -0,0 +1,206 @@
|
|||
/*
|
||||
Copyright 2016 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package service
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
fedclientset "k8s.io/kubernetes/federation/client/clientset_generated/federation_release_1_5"
|
||||
v1 "k8s.io/kubernetes/pkg/api/v1"
|
||||
cache "k8s.io/kubernetes/pkg/client/cache"
|
||||
"k8s.io/kubernetes/pkg/controller"
|
||||
|
||||
"github.com/golang/glog"
|
||||
)
|
||||
|
||||
// worker runs a worker thread that just dequeues items, processes them, and marks them done.
|
||||
// It enforces that the syncHandler is never invoked concurrently with the same key.
|
||||
func (sc *ServiceController) clusterEndpointWorker() {
|
||||
// process all pending events in endpointWorkerDoneChan
|
||||
ForLoop:
|
||||
for {
|
||||
select {
|
||||
case clusterName := <-sc.endpointWorkerDoneChan:
|
||||
sc.endpointWorkerMap[clusterName] = false
|
||||
default:
|
||||
// non-blocking, comes here if all existing events are processed
|
||||
break ForLoop
|
||||
}
|
||||
}
|
||||
|
||||
for clusterName, cache := range sc.clusterCache.clientMap {
|
||||
workerExist, found := sc.endpointWorkerMap[clusterName]
|
||||
if found && workerExist {
|
||||
continue
|
||||
}
|
||||
|
||||
// create a worker only if the previous worker has finished and gone out of scope
|
||||
go func(cache *clusterCache, clusterName string) {
|
||||
fedClient := sc.federationClient
|
||||
for {
|
||||
func() {
|
||||
key, quit := cache.endpointQueue.Get()
|
||||
// update endpoint cache
|
||||
if quit {
|
||||
// send signal that current worker has finished tasks and is going out of scope
|
||||
sc.endpointWorkerDoneChan <- clusterName
|
||||
return
|
||||
}
|
||||
defer cache.endpointQueue.Done(key)
|
||||
err := sc.clusterCache.syncEndpoint(key.(string), clusterName, cache, sc.serviceCache, fedClient, sc)
|
||||
if err != nil {
|
||||
glog.V(2).Infof("Failed to sync endpoint: %+v", err)
|
||||
}
|
||||
}()
|
||||
}
|
||||
}(cache, clusterName)
|
||||
sc.endpointWorkerMap[clusterName] = true
|
||||
}
|
||||
}
|
||||
|
||||
// Whenever there is change on endpoint, the federation service should be updated
|
||||
// key is the namespaced name of endpoint
|
||||
func (cc *clusterClientCache) syncEndpoint(key, clusterName string, clusterCache *clusterCache, serviceCache *serviceCache, fedClient fedclientset.Interface, serviceController *ServiceController) error {
|
||||
cachedService, ok := serviceCache.get(key)
|
||||
if !ok {
|
||||
// here we filtered all non-federation services
|
||||
return nil
|
||||
}
|
||||
endpointInterface, exists, err := clusterCache.endpointStore.GetByKey(key)
|
||||
if err != nil {
|
||||
glog.Errorf("Did not successfully get %v from store: %v, will retry later", key, err)
|
||||
clusterCache.endpointQueue.Add(key)
|
||||
return err
|
||||
}
|
||||
if exists {
|
||||
endpoint, ok := endpointInterface.(*v1.Endpoints)
|
||||
if ok {
|
||||
glog.V(4).Infof("Found endpoint for federation service %s/%s from cluster %s", endpoint.Namespace, endpoint.Name, clusterName)
|
||||
err = cc.processEndpointUpdate(cachedService, endpoint, clusterName, serviceController)
|
||||
} else {
|
||||
_, ok := endpointInterface.(cache.DeletedFinalStateUnknown)
|
||||
if !ok {
|
||||
return fmt.Errorf("Object contained wasn't a service or a deleted key: %+v", endpointInterface)
|
||||
}
|
||||
glog.Infof("Found tombstone for %v", key)
|
||||
err = cc.processEndpointDeletion(cachedService, clusterName, serviceController)
|
||||
}
|
||||
} else {
|
||||
// service absence in store means watcher caught the deletion, ensure LB info is cleaned
|
||||
glog.Infof("Can not get endpoint %v for cluster %s from endpointStore", key, clusterName)
|
||||
err = cc.processEndpointDeletion(cachedService, clusterName, serviceController)
|
||||
}
|
||||
if err != nil {
|
||||
glog.Errorf("Failed to sync service: %+v, put back to service queue", err)
|
||||
clusterCache.endpointQueue.Add(key)
|
||||
}
|
||||
cachedService.resetDNSUpdateDelay()
|
||||
return nil
|
||||
}
|
||||
|
||||
func (cc *clusterClientCache) processEndpointDeletion(cachedService *cachedService, clusterName string, serviceController *ServiceController) error {
|
||||
glog.V(4).Infof("Processing endpoint deletion for %s/%s, cluster %s", cachedService.lastState.Namespace, cachedService.lastState.Name, clusterName)
|
||||
var err error
|
||||
cachedService.rwlock.Lock()
|
||||
defer cachedService.rwlock.Unlock()
|
||||
_, ok := cachedService.endpointMap[clusterName]
|
||||
// TODO remove ok checking? if service controller is restarted, then endpointMap for the cluster does not exist
|
||||
// need to query dns info from dnsprovider and make sure of if deletion is needed
|
||||
if ok {
|
||||
// endpoints lost, clean dns record
|
||||
glog.V(4).Infof("Cached endpoint was found for %s/%s, cluster %s, removing", cachedService.lastState.Namespace, cachedService.lastState.Name, clusterName)
|
||||
delete(cachedService.endpointMap, clusterName)
|
||||
for i := 0; i < clientRetryCount; i++ {
|
||||
err := serviceController.ensureDnsRecords(clusterName, cachedService)
|
||||
if err == nil {
|
||||
return nil
|
||||
}
|
||||
glog.V(4).Infof("Error ensuring DNS Records: %v", err)
|
||||
time.Sleep(cachedService.nextDNSUpdateDelay())
|
||||
}
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
// Update dns info when endpoint update event received
|
||||
// We do not care about the endpoint info, what we need to make sure here is len(endpoints.subsets)>0
|
||||
func (cc *clusterClientCache) processEndpointUpdate(cachedService *cachedService, endpoint *v1.Endpoints, clusterName string, serviceController *ServiceController) error {
|
||||
glog.V(4).Infof("Processing endpoint update for %s/%s, cluster %s", endpoint.Namespace, endpoint.Name, clusterName)
|
||||
var err error
|
||||
cachedService.rwlock.Lock()
|
||||
var reachable bool
|
||||
defer cachedService.rwlock.Unlock()
|
||||
_, ok := cachedService.endpointMap[clusterName]
|
||||
if !ok {
|
||||
for _, subset := range endpoint.Subsets {
|
||||
if len(subset.Addresses) > 0 {
|
||||
reachable = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if reachable {
|
||||
// first time get endpoints, update dns record
|
||||
glog.V(4).Infof("Reachable endpoint was found for %s/%s, cluster %s, building endpointMap", endpoint.Namespace, endpoint.Name, clusterName)
|
||||
cachedService.endpointMap[clusterName] = 1
|
||||
for i := 0; i < clientRetryCount; i++ {
|
||||
err := serviceController.ensureDnsRecords(clusterName, cachedService)
|
||||
if err == nil {
|
||||
return nil
|
||||
}
|
||||
glog.V(4).Infof("Error ensuring DNS Records: %v", err)
|
||||
time.Sleep(cachedService.nextDNSUpdateDelay())
|
||||
}
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
for _, subset := range endpoint.Subsets {
|
||||
if len(subset.Addresses) > 0 {
|
||||
reachable = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if !reachable {
|
||||
// first time get endpoints, update dns record
|
||||
glog.V(4).Infof("Reachable endpoint was lost for %s/%s, cluster %s, deleting endpointMap", endpoint.Namespace, endpoint.Name, clusterName)
|
||||
delete(cachedService.endpointMap, clusterName)
|
||||
for i := 0; i < clientRetryCount; i++ {
|
||||
err := serviceController.ensureDnsRecords(clusterName, cachedService)
|
||||
if err == nil {
|
||||
return nil
|
||||
}
|
||||
glog.V(4).Infof("Error ensuring DNS Records: %v", err)
|
||||
time.Sleep(cachedService.nextDNSUpdateDelay())
|
||||
}
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// obj could be an *api.Endpoints, or a DeletionFinalStateUnknown marker item.
|
||||
func (cc *clusterClientCache) enqueueEndpoint(obj interface{}, clusterName string) {
|
||||
key, err := controller.KeyFunc(obj)
|
||||
if err != nil {
|
||||
glog.Errorf("Couldn't get key for object %+v: %v", obj, err)
|
||||
return
|
||||
}
|
||||
_, ok := cc.clientMap[clusterName]
|
||||
if ok {
|
||||
cc.clientMap[clusterName].endpointQueue.Add(key)
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue