Update go dependencies (#2234)
This commit is contained in:
parent
6e099c5f57
commit
93c72ef646
1236 changed files with 37226 additions and 49844 deletions
193
vendor/k8s.io/kubernetes/pkg/master/BUILD
generated
vendored
Normal file
193
vendor/k8s.io/kubernetes/pkg/master/BUILD
generated
vendored
Normal file
|
|
@ -0,0 +1,193 @@
|
|||
package(default_visibility = ["//visibility:public"])
|
||||
|
||||
load(
|
||||
"@io_bazel_rules_go//go:def.bzl",
|
||||
"go_library",
|
||||
"go_test",
|
||||
)
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = [
|
||||
"client_ca_hook.go",
|
||||
"controller.go",
|
||||
"doc.go",
|
||||
"import_known_versions.go",
|
||||
"master.go",
|
||||
"services.go",
|
||||
],
|
||||
importpath = "k8s.io/kubernetes/pkg/master",
|
||||
deps = [
|
||||
"//pkg/api/legacyscheme:go_default_library",
|
||||
"//pkg/apis/admission/install:go_default_library",
|
||||
"//pkg/apis/admissionregistration/install:go_default_library",
|
||||
"//pkg/apis/apps/install:go_default_library",
|
||||
"//pkg/apis/authentication/install:go_default_library",
|
||||
"//pkg/apis/authorization/install:go_default_library",
|
||||
"//pkg/apis/autoscaling/install:go_default_library",
|
||||
"//pkg/apis/batch/install:go_default_library",
|
||||
"//pkg/apis/certificates/install:go_default_library",
|
||||
"//pkg/apis/componentconfig/install:go_default_library",
|
||||
"//pkg/apis/core:go_default_library",
|
||||
"//pkg/apis/core/install:go_default_library",
|
||||
"//pkg/apis/events/install:go_default_library",
|
||||
"//pkg/apis/extensions/install:go_default_library",
|
||||
"//pkg/apis/imagepolicy/install:go_default_library",
|
||||
"//pkg/apis/networking/install:go_default_library",
|
||||
"//pkg/apis/policy/install:go_default_library",
|
||||
"//pkg/apis/rbac/install:go_default_library",
|
||||
"//pkg/apis/scheduling/install:go_default_library",
|
||||
"//pkg/apis/settings/install:go_default_library",
|
||||
"//pkg/apis/storage/install:go_default_library",
|
||||
"//pkg/client/clientset_generated/internalclientset/typed/core/internalversion:go_default_library",
|
||||
"//pkg/kubeapiserver/options:go_default_library",
|
||||
"//pkg/kubelet/client:go_default_library",
|
||||
"//pkg/master/reconcilers:go_default_library",
|
||||
"//pkg/master/tunneler:go_default_library",
|
||||
"//pkg/registry/admissionregistration/rest:go_default_library",
|
||||
"//pkg/registry/apps/rest:go_default_library",
|
||||
"//pkg/registry/authentication/rest:go_default_library",
|
||||
"//pkg/registry/authorization/rest:go_default_library",
|
||||
"//pkg/registry/autoscaling/rest:go_default_library",
|
||||
"//pkg/registry/batch/rest:go_default_library",
|
||||
"//pkg/registry/certificates/rest:go_default_library",
|
||||
"//pkg/registry/core/endpoint:go_default_library",
|
||||
"//pkg/registry/core/endpoint/storage:go_default_library",
|
||||
"//pkg/registry/core/rangeallocation:go_default_library",
|
||||
"//pkg/registry/core/rest:go_default_library",
|
||||
"//pkg/registry/core/service/ipallocator:go_default_library",
|
||||
"//pkg/registry/core/service/ipallocator/controller:go_default_library",
|
||||
"//pkg/registry/core/service/portallocator/controller:go_default_library",
|
||||
"//pkg/registry/events/rest:go_default_library",
|
||||
"//pkg/registry/extensions/rest:go_default_library",
|
||||
"//pkg/registry/networking/rest:go_default_library",
|
||||
"//pkg/registry/policy/rest:go_default_library",
|
||||
"//pkg/registry/rbac/rest:go_default_library",
|
||||
"//pkg/registry/scheduling/rest:go_default_library",
|
||||
"//pkg/registry/settings/rest:go_default_library",
|
||||
"//pkg/registry/storage/rest:go_default_library",
|
||||
"//pkg/routes:go_default_library",
|
||||
"//pkg/util/async:go_default_library",
|
||||
"//pkg/util/node:go_default_library",
|
||||
"//vendor/github.com/golang/glog:go_default_library",
|
||||
"//vendor/github.com/prometheus/client_golang/prometheus:go_default_library",
|
||||
"//vendor/k8s.io/api/admissionregistration/v1beta1:go_default_library",
|
||||
"//vendor/k8s.io/api/apps/v1:go_default_library",
|
||||
"//vendor/k8s.io/api/apps/v1beta1:go_default_library",
|
||||
"//vendor/k8s.io/api/apps/v1beta2:go_default_library",
|
||||
"//vendor/k8s.io/api/authentication/v1:go_default_library",
|
||||
"//vendor/k8s.io/api/authentication/v1beta1:go_default_library",
|
||||
"//vendor/k8s.io/api/authorization/v1:go_default_library",
|
||||
"//vendor/k8s.io/api/authorization/v1beta1:go_default_library",
|
||||
"//vendor/k8s.io/api/autoscaling/v1:go_default_library",
|
||||
"//vendor/k8s.io/api/autoscaling/v2beta1:go_default_library",
|
||||
"//vendor/k8s.io/api/batch/v1:go_default_library",
|
||||
"//vendor/k8s.io/api/batch/v1beta1:go_default_library",
|
||||
"//vendor/k8s.io/api/certificates/v1beta1:go_default_library",
|
||||
"//vendor/k8s.io/api/core/v1:go_default_library",
|
||||
"//vendor/k8s.io/api/events/v1beta1:go_default_library",
|
||||
"//vendor/k8s.io/api/extensions/v1beta1:go_default_library",
|
||||
"//vendor/k8s.io/api/networking/v1:go_default_library",
|
||||
"//vendor/k8s.io/api/policy/v1beta1:go_default_library",
|
||||
"//vendor/k8s.io/api/rbac/v1:go_default_library",
|
||||
"//vendor/k8s.io/api/rbac/v1beta1:go_default_library",
|
||||
"//vendor/k8s.io/api/storage/v1:go_default_library",
|
||||
"//vendor/k8s.io/api/storage/v1beta1:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/api/errors:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/util/intstr:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/util/net:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/util/runtime:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/util/wait:go_default_library",
|
||||
"//vendor/k8s.io/apiserver/pkg/endpoints/discovery:go_default_library",
|
||||
"//vendor/k8s.io/apiserver/pkg/registry/generic:go_default_library",
|
||||
"//vendor/k8s.io/apiserver/pkg/server:go_default_library",
|
||||
"//vendor/k8s.io/apiserver/pkg/server/healthz:go_default_library",
|
||||
"//vendor/k8s.io/apiserver/pkg/server/storage:go_default_library",
|
||||
"//vendor/k8s.io/apiserver/pkg/storage/storagebackend/factory:go_default_library",
|
||||
"//vendor/k8s.io/client-go/informers:go_default_library",
|
||||
"//vendor/k8s.io/client-go/kubernetes/typed/core/v1:go_default_library",
|
||||
],
|
||||
)
|
||||
|
||||
go_test(
|
||||
name = "go_default_test",
|
||||
srcs = [
|
||||
"client_ca_hook_test.go",
|
||||
"controller_test.go",
|
||||
"import_known_versions_test.go",
|
||||
"master_openapi_test.go",
|
||||
"master_test.go",
|
||||
],
|
||||
embed = [":go_default_library"],
|
||||
importpath = "k8s.io/kubernetes/pkg/master",
|
||||
race = "off",
|
||||
deps = [
|
||||
"//pkg/api/legacyscheme:go_default_library",
|
||||
"//pkg/api/testapi:go_default_library",
|
||||
"//pkg/apis/apps:go_default_library",
|
||||
"//pkg/apis/autoscaling:go_default_library",
|
||||
"//pkg/apis/batch:go_default_library",
|
||||
"//pkg/apis/certificates:go_default_library",
|
||||
"//pkg/apis/core:go_default_library",
|
||||
"//pkg/apis/extensions:go_default_library",
|
||||
"//pkg/apis/rbac:go_default_library",
|
||||
"//pkg/client/clientset_generated/internalclientset/fake:go_default_library",
|
||||
"//pkg/generated/openapi:go_default_library",
|
||||
"//pkg/kubelet/client:go_default_library",
|
||||
"//pkg/master/reconcilers:go_default_library",
|
||||
"//pkg/registry/certificates/rest:go_default_library",
|
||||
"//pkg/registry/core/rest:go_default_library",
|
||||
"//pkg/registry/registrytest:go_default_library",
|
||||
"//pkg/version:go_default_library",
|
||||
"//vendor/github.com/go-openapi/loads:go_default_library",
|
||||
"//vendor/github.com/go-openapi/spec:go_default_library",
|
||||
"//vendor/github.com/go-openapi/strfmt:go_default_library",
|
||||
"//vendor/github.com/go-openapi/validate:go_default_library",
|
||||
"//vendor/github.com/stretchr/testify/assert:go_default_library",
|
||||
"//vendor/k8s.io/api/apps/v1beta1:go_default_library",
|
||||
"//vendor/k8s.io/api/autoscaling/v1:go_default_library",
|
||||
"//vendor/k8s.io/api/batch/v1:go_default_library",
|
||||
"//vendor/k8s.io/api/batch/v1beta1:go_default_library",
|
||||
"//vendor/k8s.io/api/certificates/v1beta1:go_default_library",
|
||||
"//vendor/k8s.io/api/core/v1:go_default_library",
|
||||
"//vendor/k8s.io/api/extensions/v1beta1:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/runtime:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/runtime/schema:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/util/diff:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/util/intstr:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/util/net:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/util/sets:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/version:go_default_library",
|
||||
"//vendor/k8s.io/apiserver/pkg/endpoints/request:go_default_library",
|
||||
"//vendor/k8s.io/apiserver/pkg/server:go_default_library",
|
||||
"//vendor/k8s.io/apiserver/pkg/server/options:go_default_library",
|
||||
"//vendor/k8s.io/apiserver/pkg/server/storage:go_default_library",
|
||||
"//vendor/k8s.io/apiserver/pkg/storage/etcd/testing:go_default_library",
|
||||
"//vendor/k8s.io/client-go/informers:go_default_library",
|
||||
"//vendor/k8s.io/client-go/kubernetes:go_default_library",
|
||||
"//vendor/k8s.io/client-go/kubernetes/fake:go_default_library",
|
||||
"//vendor/k8s.io/client-go/rest:go_default_library",
|
||||
"//vendor/k8s.io/client-go/testing:go_default_library",
|
||||
],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "package-srcs",
|
||||
srcs = glob(["**"]),
|
||||
tags = ["automanaged"],
|
||||
visibility = ["//visibility:private"],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "all-srcs",
|
||||
srcs = [
|
||||
":package-srcs",
|
||||
"//pkg/master/controller/crdregistration:all-srcs",
|
||||
"//pkg/master/ports:all-srcs",
|
||||
"//pkg/master/reconcilers:all-srcs",
|
||||
"//pkg/master/tunneler:all-srcs",
|
||||
],
|
||||
tags = ["automanaged"],
|
||||
)
|
||||
41
vendor/k8s.io/kubernetes/pkg/master/OWNERS
generated
vendored
Normal file
41
vendor/k8s.io/kubernetes/pkg/master/OWNERS
generated
vendored
Normal file
|
|
@ -0,0 +1,41 @@
|
|||
approvers:
|
||||
- deads2k
|
||||
- derekwaynecarr
|
||||
- lavalamp
|
||||
- mikedanese
|
||||
- nikhiljindal
|
||||
- sttts
|
||||
- wojtek-t
|
||||
reviewers:
|
||||
- thockin
|
||||
- lavalamp
|
||||
- smarterclayton
|
||||
- wojtek-t
|
||||
- deads2k
|
||||
- yujuhong
|
||||
- derekwaynecarr
|
||||
- caesarxuchao
|
||||
- mikedanese
|
||||
- liggitt
|
||||
- nikhiljindal
|
||||
- gmarek
|
||||
- erictune
|
||||
- davidopp
|
||||
- pmorie
|
||||
- sttts
|
||||
- dchen1107
|
||||
- saad-ali
|
||||
- luxas
|
||||
- janetkuo
|
||||
- justinsb
|
||||
- roberthbailey
|
||||
- ncdc
|
||||
- tallclair
|
||||
- mwielgus
|
||||
- timothysc
|
||||
- soltysh
|
||||
- piosz
|
||||
- madhusudancs
|
||||
- hongchaodeng
|
||||
- jszczepkowski
|
||||
- enj
|
||||
143
vendor/k8s.io/kubernetes/pkg/master/client_ca_hook.go
generated
vendored
Normal file
143
vendor/k8s.io/kubernetes/pkg/master/client_ca_hook.go
generated
vendored
Normal file
|
|
@ -0,0 +1,143 @@
|
|||
/*
|
||||
Copyright 2017 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 master
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
apierrors "k8s.io/apimachinery/pkg/api/errors"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
utilruntime "k8s.io/apimachinery/pkg/util/runtime"
|
||||
"k8s.io/apimachinery/pkg/util/wait"
|
||||
genericapiserver "k8s.io/apiserver/pkg/server"
|
||||
api "k8s.io/kubernetes/pkg/apis/core"
|
||||
coreclient "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset/typed/core/internalversion"
|
||||
)
|
||||
|
||||
type ClientCARegistrationHook struct {
|
||||
ClientCA []byte
|
||||
|
||||
RequestHeaderUsernameHeaders []string
|
||||
RequestHeaderGroupHeaders []string
|
||||
RequestHeaderExtraHeaderPrefixes []string
|
||||
RequestHeaderCA []byte
|
||||
RequestHeaderAllowedNames []string
|
||||
}
|
||||
|
||||
func (h ClientCARegistrationHook) PostStartHook(hookContext genericapiserver.PostStartHookContext) error {
|
||||
// no work to do
|
||||
if len(h.ClientCA) == 0 && len(h.RequestHeaderCA) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
// initializing CAs is important so that aggregated API servers can come up with "normal" config.
|
||||
// We've seen lagging etcd before, so we want to retry this a few times before we decide to crashloop
|
||||
// the API server on it.
|
||||
err := wait.Poll(1*time.Second, 30*time.Second, func() (done bool, err error) {
|
||||
// retry building the config since sometimes the server can be in an inbetween state which caused
|
||||
// some kind of auto detection failure as I recall from other post start hooks.
|
||||
// TODO see if this is still true and fix the RBAC one too if it isn't.
|
||||
client, err := coreclient.NewForConfig(hookContext.LoopbackClientConfig)
|
||||
if err != nil {
|
||||
utilruntime.HandleError(err)
|
||||
return false, nil
|
||||
}
|
||||
|
||||
return h.tryToWriteClientCAs(client)
|
||||
})
|
||||
|
||||
// if we're never able to make it through initialization, kill the API server
|
||||
if err != nil {
|
||||
return fmt.Errorf("unable to initialize client CA configmap: %v", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
|
||||
}
|
||||
|
||||
// tryToWriteClientCAs is here for unit testing with a fake client. This is a wait.ConditionFunc so the bool
|
||||
// indicates if the condition was met. True when its finished, false when it should retry.
|
||||
func (h ClientCARegistrationHook) tryToWriteClientCAs(client coreclient.CoreInterface) (bool, error) {
|
||||
if _, err := client.Namespaces().Create(&api.Namespace{ObjectMeta: metav1.ObjectMeta{Name: metav1.NamespaceSystem}}); err != nil && !apierrors.IsAlreadyExists(err) {
|
||||
utilruntime.HandleError(err)
|
||||
return false, nil
|
||||
}
|
||||
|
||||
data := map[string]string{}
|
||||
if len(h.ClientCA) > 0 {
|
||||
data["client-ca-file"] = string(h.ClientCA)
|
||||
}
|
||||
|
||||
if len(h.RequestHeaderCA) > 0 {
|
||||
var err error
|
||||
|
||||
// encoding errors aren't going to get better, so just fail on them.
|
||||
data["requestheader-username-headers"], err = jsonSerializeStringSlice(h.RequestHeaderUsernameHeaders)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
data["requestheader-group-headers"], err = jsonSerializeStringSlice(h.RequestHeaderGroupHeaders)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
data["requestheader-extra-headers-prefix"], err = jsonSerializeStringSlice(h.RequestHeaderExtraHeaderPrefixes)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
data["requestheader-client-ca-file"] = string(h.RequestHeaderCA)
|
||||
data["requestheader-allowed-names"], err = jsonSerializeStringSlice(h.RequestHeaderAllowedNames)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
}
|
||||
|
||||
// write errors may work next time if we retry, so queue for retry
|
||||
if err := writeConfigMap(client, "extension-apiserver-authentication", data); err != nil {
|
||||
utilruntime.HandleError(err)
|
||||
return false, nil
|
||||
}
|
||||
|
||||
return true, nil
|
||||
}
|
||||
|
||||
func jsonSerializeStringSlice(in []string) (string, error) {
|
||||
out, err := json.Marshal(in)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return string(out), err
|
||||
}
|
||||
|
||||
func writeConfigMap(client coreclient.ConfigMapsGetter, name string, data map[string]string) error {
|
||||
existing, err := client.ConfigMaps(metav1.NamespaceSystem).Get(name, metav1.GetOptions{})
|
||||
if apierrors.IsNotFound(err) {
|
||||
_, err := client.ConfigMaps(metav1.NamespaceSystem).Create(&api.ConfigMap{
|
||||
ObjectMeta: metav1.ObjectMeta{Namespace: metav1.NamespaceSystem, Name: name},
|
||||
Data: data,
|
||||
})
|
||||
return err
|
||||
}
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
existing.Data = data
|
||||
_, err = client.ConfigMaps(metav1.NamespaceSystem).Update(existing)
|
||||
return err
|
||||
}
|
||||
223
vendor/k8s.io/kubernetes/pkg/master/client_ca_hook_test.go
generated
vendored
Normal file
223
vendor/k8s.io/kubernetes/pkg/master/client_ca_hook_test.go
generated
vendored
Normal file
|
|
@ -0,0 +1,223 @@
|
|||
/*
|
||||
Copyright 2017 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 master
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/util/diff"
|
||||
clienttesting "k8s.io/client-go/testing"
|
||||
api "k8s.io/kubernetes/pkg/apis/core"
|
||||
"k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset/fake"
|
||||
)
|
||||
|
||||
func TestWriteClientCAs(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
hook ClientCARegistrationHook
|
||||
preexistingObjs []runtime.Object
|
||||
expectedConfigMaps map[string]*api.ConfigMap
|
||||
expectUpdate bool
|
||||
}{
|
||||
{
|
||||
name: "basic",
|
||||
hook: ClientCARegistrationHook{
|
||||
ClientCA: []byte("foo"),
|
||||
RequestHeaderUsernameHeaders: []string{"alfa", "bravo", "charlie"},
|
||||
RequestHeaderGroupHeaders: []string{"delta"},
|
||||
RequestHeaderExtraHeaderPrefixes: []string{"echo", "foxtrot"},
|
||||
RequestHeaderCA: []byte("bar"),
|
||||
RequestHeaderAllowedNames: []string{"first", "second"},
|
||||
},
|
||||
expectedConfigMaps: map[string]*api.ConfigMap{
|
||||
"extension-apiserver-authentication": {
|
||||
ObjectMeta: metav1.ObjectMeta{Namespace: metav1.NamespaceSystem, Name: "extension-apiserver-authentication"},
|
||||
Data: map[string]string{
|
||||
"client-ca-file": "foo",
|
||||
"requestheader-username-headers": `["alfa","bravo","charlie"]`,
|
||||
"requestheader-group-headers": `["delta"]`,
|
||||
"requestheader-extra-headers-prefix": `["echo","foxtrot"]`,
|
||||
"requestheader-client-ca-file": "bar",
|
||||
"requestheader-allowed-names": `["first","second"]`,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "skip extension-apiserver-authentication",
|
||||
hook: ClientCARegistrationHook{
|
||||
RequestHeaderCA: []byte("bar"),
|
||||
RequestHeaderAllowedNames: []string{"first", "second"},
|
||||
},
|
||||
expectedConfigMaps: map[string]*api.ConfigMap{
|
||||
"extension-apiserver-authentication": {
|
||||
ObjectMeta: metav1.ObjectMeta{Namespace: metav1.NamespaceSystem, Name: "extension-apiserver-authentication"},
|
||||
Data: map[string]string{
|
||||
"requestheader-username-headers": `null`,
|
||||
"requestheader-group-headers": `null`,
|
||||
"requestheader-extra-headers-prefix": `null`,
|
||||
"requestheader-client-ca-file": "bar",
|
||||
"requestheader-allowed-names": `["first","second"]`,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "skip extension-apiserver-authentication",
|
||||
hook: ClientCARegistrationHook{
|
||||
ClientCA: []byte("foo"),
|
||||
},
|
||||
expectedConfigMaps: map[string]*api.ConfigMap{
|
||||
"extension-apiserver-authentication": {
|
||||
ObjectMeta: metav1.ObjectMeta{Namespace: metav1.NamespaceSystem, Name: "extension-apiserver-authentication"},
|
||||
Data: map[string]string{
|
||||
"client-ca-file": "foo",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "empty allowed names",
|
||||
hook: ClientCARegistrationHook{
|
||||
RequestHeaderCA: []byte("bar"),
|
||||
},
|
||||
expectedConfigMaps: map[string]*api.ConfigMap{
|
||||
"extension-apiserver-authentication": {
|
||||
ObjectMeta: metav1.ObjectMeta{Namespace: metav1.NamespaceSystem, Name: "extension-apiserver-authentication"},
|
||||
Data: map[string]string{
|
||||
"requestheader-username-headers": `null`,
|
||||
"requestheader-group-headers": `null`,
|
||||
"requestheader-extra-headers-prefix": `null`,
|
||||
"requestheader-client-ca-file": "bar",
|
||||
"requestheader-allowed-names": `null`,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "overwrite extension-apiserver-authentication",
|
||||
hook: ClientCARegistrationHook{
|
||||
ClientCA: []byte("foo"),
|
||||
},
|
||||
preexistingObjs: []runtime.Object{
|
||||
&api.ConfigMap{
|
||||
ObjectMeta: metav1.ObjectMeta{Namespace: metav1.NamespaceSystem, Name: "extension-apiserver-authentication"},
|
||||
Data: map[string]string{
|
||||
"client-ca-file": "other",
|
||||
},
|
||||
},
|
||||
},
|
||||
expectedConfigMaps: map[string]*api.ConfigMap{
|
||||
"extension-apiserver-authentication": {
|
||||
ObjectMeta: metav1.ObjectMeta{Namespace: metav1.NamespaceSystem, Name: "extension-apiserver-authentication"},
|
||||
Data: map[string]string{
|
||||
"client-ca-file": "foo",
|
||||
},
|
||||
},
|
||||
},
|
||||
expectUpdate: true,
|
||||
},
|
||||
{
|
||||
name: "overwrite extension-apiserver-authentication requestheader",
|
||||
hook: ClientCARegistrationHook{
|
||||
RequestHeaderUsernameHeaders: []string{},
|
||||
RequestHeaderGroupHeaders: []string{},
|
||||
RequestHeaderExtraHeaderPrefixes: []string{},
|
||||
RequestHeaderCA: []byte("bar"),
|
||||
RequestHeaderAllowedNames: []string{},
|
||||
},
|
||||
preexistingObjs: []runtime.Object{
|
||||
&api.ConfigMap{
|
||||
ObjectMeta: metav1.ObjectMeta{Namespace: metav1.NamespaceSystem, Name: "extension-apiserver-authentication"},
|
||||
Data: map[string]string{
|
||||
"requestheader-username-headers": `null`,
|
||||
"requestheader-group-headers": `null`,
|
||||
"requestheader-extra-headers-prefix": `null`,
|
||||
"requestheader-client-ca-file": "something",
|
||||
"requestheader-allowed-names": `null`,
|
||||
},
|
||||
},
|
||||
},
|
||||
expectedConfigMaps: map[string]*api.ConfigMap{
|
||||
"extension-apiserver-authentication": {
|
||||
ObjectMeta: metav1.ObjectMeta{Namespace: metav1.NamespaceSystem, Name: "extension-apiserver-authentication"},
|
||||
Data: map[string]string{
|
||||
"requestheader-username-headers": `[]`,
|
||||
"requestheader-group-headers": `[]`,
|
||||
"requestheader-extra-headers-prefix": `[]`,
|
||||
"requestheader-client-ca-file": "bar",
|
||||
"requestheader-allowed-names": `[]`,
|
||||
},
|
||||
},
|
||||
},
|
||||
expectUpdate: true,
|
||||
},
|
||||
{
|
||||
name: "namespace exists",
|
||||
hook: ClientCARegistrationHook{
|
||||
ClientCA: []byte("foo"),
|
||||
},
|
||||
preexistingObjs: []runtime.Object{
|
||||
&api.Namespace{ObjectMeta: metav1.ObjectMeta{Name: metav1.NamespaceSystem}},
|
||||
},
|
||||
expectedConfigMaps: map[string]*api.ConfigMap{
|
||||
"extension-apiserver-authentication": {
|
||||
ObjectMeta: metav1.ObjectMeta{Namespace: metav1.NamespaceSystem, Name: "extension-apiserver-authentication"},
|
||||
Data: map[string]string{
|
||||
"client-ca-file": "foo",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
client := fake.NewSimpleClientset(test.preexistingObjs...)
|
||||
test.hook.tryToWriteClientCAs(client.Core())
|
||||
|
||||
actualConfigMaps, updated := getFinalConfiMaps(client)
|
||||
if !reflect.DeepEqual(test.expectedConfigMaps, actualConfigMaps) {
|
||||
t.Errorf("%s: %v", test.name, diff.ObjectReflectDiff(test.expectedConfigMaps, actualConfigMaps))
|
||||
continue
|
||||
}
|
||||
if test.expectUpdate != updated {
|
||||
t.Errorf("%s: expected %v, got %v", test.name, test.expectUpdate, updated)
|
||||
continue
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func getFinalConfiMaps(client *fake.Clientset) (map[string]*api.ConfigMap, bool) {
|
||||
ret := map[string]*api.ConfigMap{}
|
||||
updated := false
|
||||
|
||||
for _, action := range client.Actions() {
|
||||
if action.Matches("create", "configmaps") {
|
||||
obj := action.(clienttesting.CreateAction).GetObject().(*api.ConfigMap)
|
||||
ret[obj.Name] = obj
|
||||
}
|
||||
if action.Matches("update", "configmaps") {
|
||||
updated = true
|
||||
obj := action.(clienttesting.UpdateAction).GetObject().(*api.ConfigMap)
|
||||
ret[obj.Name] = obj
|
||||
}
|
||||
}
|
||||
return ret, updated
|
||||
}
|
||||
289
vendor/k8s.io/kubernetes/pkg/master/controller.go
generated
vendored
Normal file
289
vendor/k8s.io/kubernetes/pkg/master/controller.go
generated
vendored
Normal file
|
|
@ -0,0 +1,289 @@
|
|||
/*
|
||||
Copyright 2014 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 master
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net"
|
||||
"time"
|
||||
|
||||
"github.com/golang/glog"
|
||||
"k8s.io/apimachinery/pkg/api/errors"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/util/intstr"
|
||||
utilnet "k8s.io/apimachinery/pkg/util/net"
|
||||
"k8s.io/apimachinery/pkg/util/runtime"
|
||||
"k8s.io/apimachinery/pkg/util/wait"
|
||||
genericapiserver "k8s.io/apiserver/pkg/server"
|
||||
api "k8s.io/kubernetes/pkg/apis/core"
|
||||
coreclient "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset/typed/core/internalversion"
|
||||
"k8s.io/kubernetes/pkg/master/reconcilers"
|
||||
"k8s.io/kubernetes/pkg/registry/core/rangeallocation"
|
||||
corerest "k8s.io/kubernetes/pkg/registry/core/rest"
|
||||
servicecontroller "k8s.io/kubernetes/pkg/registry/core/service/ipallocator/controller"
|
||||
portallocatorcontroller "k8s.io/kubernetes/pkg/registry/core/service/portallocator/controller"
|
||||
"k8s.io/kubernetes/pkg/util/async"
|
||||
)
|
||||
|
||||
const kubernetesServiceName = "kubernetes"
|
||||
|
||||
// Controller is the controller manager for the core bootstrap Kubernetes
|
||||
// controller loops, which manage creating the "kubernetes" service, the
|
||||
// "default", "kube-system" and "kube-public" namespaces, and provide the IP
|
||||
// repair check on service IPs
|
||||
type Controller struct {
|
||||
ServiceClient coreclient.ServicesGetter
|
||||
NamespaceClient coreclient.NamespacesGetter
|
||||
EventClient coreclient.EventsGetter
|
||||
|
||||
ServiceClusterIPRegistry rangeallocation.RangeRegistry
|
||||
ServiceClusterIPInterval time.Duration
|
||||
ServiceClusterIPRange net.IPNet
|
||||
|
||||
ServiceNodePortRegistry rangeallocation.RangeRegistry
|
||||
ServiceNodePortInterval time.Duration
|
||||
ServiceNodePortRange utilnet.PortRange
|
||||
|
||||
EndpointReconciler reconcilers.EndpointReconciler
|
||||
EndpointInterval time.Duration
|
||||
|
||||
SystemNamespaces []string
|
||||
SystemNamespacesInterval time.Duration
|
||||
|
||||
PublicIP net.IP
|
||||
|
||||
// ServiceIP indicates where the kubernetes service will live. It may not be nil.
|
||||
ServiceIP net.IP
|
||||
ServicePort int
|
||||
ExtraServicePorts []api.ServicePort
|
||||
ExtraEndpointPorts []api.EndpointPort
|
||||
PublicServicePort int
|
||||
KubernetesServiceNodePort int
|
||||
|
||||
runner *async.Runner
|
||||
}
|
||||
|
||||
// NewBootstrapController returns a controller for watching the core capabilities of the master
|
||||
func (c *completedConfig) NewBootstrapController(legacyRESTStorage corerest.LegacyRESTStorage, serviceClient coreclient.ServicesGetter, nsClient coreclient.NamespacesGetter, eventClient coreclient.EventsGetter) *Controller {
|
||||
return &Controller{
|
||||
ServiceClient: serviceClient,
|
||||
NamespaceClient: nsClient,
|
||||
EventClient: eventClient,
|
||||
|
||||
EndpointReconciler: c.ExtraConfig.EndpointReconcilerConfig.Reconciler,
|
||||
EndpointInterval: c.ExtraConfig.EndpointReconcilerConfig.Interval,
|
||||
|
||||
SystemNamespaces: []string{metav1.NamespaceSystem, metav1.NamespacePublic},
|
||||
SystemNamespacesInterval: 1 * time.Minute,
|
||||
|
||||
ServiceClusterIPRegistry: legacyRESTStorage.ServiceClusterIPAllocator,
|
||||
ServiceClusterIPRange: c.ExtraConfig.ServiceIPRange,
|
||||
ServiceClusterIPInterval: 3 * time.Minute,
|
||||
|
||||
ServiceNodePortRegistry: legacyRESTStorage.ServiceNodePortAllocator,
|
||||
ServiceNodePortRange: c.ExtraConfig.ServiceNodePortRange,
|
||||
ServiceNodePortInterval: 3 * time.Minute,
|
||||
|
||||
PublicIP: c.GenericConfig.PublicAddress,
|
||||
|
||||
ServiceIP: c.ExtraConfig.APIServerServiceIP,
|
||||
ServicePort: c.ExtraConfig.APIServerServicePort,
|
||||
ExtraServicePorts: c.ExtraConfig.ExtraServicePorts,
|
||||
ExtraEndpointPorts: c.ExtraConfig.ExtraEndpointPorts,
|
||||
PublicServicePort: c.GenericConfig.ReadWritePort,
|
||||
KubernetesServiceNodePort: c.ExtraConfig.KubernetesServiceNodePort,
|
||||
}
|
||||
}
|
||||
|
||||
func (c *Controller) PostStartHook(hookContext genericapiserver.PostStartHookContext) error {
|
||||
c.Start()
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *Controller) PreShutdownHook() error {
|
||||
c.Stop()
|
||||
return nil
|
||||
}
|
||||
|
||||
// Start begins the core controller loops that must exist for bootstrapping
|
||||
// a cluster.
|
||||
func (c *Controller) Start() {
|
||||
if c.runner != nil {
|
||||
return
|
||||
}
|
||||
|
||||
repairClusterIPs := servicecontroller.NewRepair(c.ServiceClusterIPInterval, c.ServiceClient, c.EventClient, &c.ServiceClusterIPRange, c.ServiceClusterIPRegistry)
|
||||
repairNodePorts := portallocatorcontroller.NewRepair(c.ServiceNodePortInterval, c.ServiceClient, c.EventClient, c.ServiceNodePortRange, c.ServiceNodePortRegistry)
|
||||
|
||||
// run all of the controllers once prior to returning from Start.
|
||||
if err := repairClusterIPs.RunOnce(); err != nil {
|
||||
// If we fail to repair cluster IPs apiserver is useless. We should restart and retry.
|
||||
glog.Fatalf("Unable to perform initial IP allocation check: %v", err)
|
||||
}
|
||||
if err := repairNodePorts.RunOnce(); err != nil {
|
||||
// If we fail to repair node ports apiserver is useless. We should restart and retry.
|
||||
glog.Fatalf("Unable to perform initial service nodePort check: %v", err)
|
||||
}
|
||||
// Service definition is reconciled during first run to correct port and type per expectations.
|
||||
if err := c.UpdateKubernetesService(true); err != nil {
|
||||
glog.Errorf("Unable to perform initial Kubernetes service initialization: %v", err)
|
||||
}
|
||||
|
||||
c.runner = async.NewRunner(c.RunKubernetesNamespaces, c.RunKubernetesService, repairClusterIPs.RunUntil, repairNodePorts.RunUntil)
|
||||
c.runner.Start()
|
||||
}
|
||||
|
||||
func (c *Controller) Stop() {
|
||||
if c.runner != nil {
|
||||
c.runner.Stop()
|
||||
}
|
||||
endpointPorts := createEndpointPortSpec(c.PublicServicePort, "https", c.ExtraEndpointPorts)
|
||||
c.EndpointReconciler.StopReconciling("kubernetes", c.PublicIP, endpointPorts)
|
||||
}
|
||||
|
||||
// RunKubernetesNamespaces periodically makes sure that all internal namespaces exist
|
||||
func (c *Controller) RunKubernetesNamespaces(ch chan struct{}) {
|
||||
wait.Until(func() {
|
||||
// Loop the system namespace list, and create them if they do not exist
|
||||
for _, ns := range c.SystemNamespaces {
|
||||
if err := c.CreateNamespaceIfNeeded(ns); err != nil {
|
||||
runtime.HandleError(fmt.Errorf("unable to create required kubernetes system namespace %s: %v", ns, err))
|
||||
}
|
||||
}
|
||||
}, c.SystemNamespacesInterval, ch)
|
||||
}
|
||||
|
||||
// RunKubernetesService periodically updates the kubernetes service
|
||||
func (c *Controller) RunKubernetesService(ch chan struct{}) {
|
||||
wait.Until(func() {
|
||||
// Service definition is not reconciled after first
|
||||
// run, ports and type will be corrected only during
|
||||
// start.
|
||||
if err := c.UpdateKubernetesService(false); err != nil {
|
||||
runtime.HandleError(fmt.Errorf("unable to sync kubernetes service: %v", err))
|
||||
}
|
||||
}, c.EndpointInterval, ch)
|
||||
}
|
||||
|
||||
// UpdateKubernetesService attempts to update the default Kube service.
|
||||
func (c *Controller) UpdateKubernetesService(reconcile bool) error {
|
||||
// Update service & endpoint records.
|
||||
// TODO: when it becomes possible to change this stuff,
|
||||
// stop polling and start watching.
|
||||
// TODO: add endpoints of all replicas, not just the elected master.
|
||||
if err := c.CreateNamespaceIfNeeded(metav1.NamespaceDefault); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
servicePorts, serviceType := createPortAndServiceSpec(c.ServicePort, c.PublicServicePort, c.KubernetesServiceNodePort, "https", c.ExtraServicePorts)
|
||||
if err := c.CreateOrUpdateMasterServiceIfNeeded(kubernetesServiceName, c.ServiceIP, servicePorts, serviceType, reconcile); err != nil {
|
||||
return err
|
||||
}
|
||||
endpointPorts := createEndpointPortSpec(c.PublicServicePort, "https", c.ExtraEndpointPorts)
|
||||
if err := c.EndpointReconciler.ReconcileEndpoints(kubernetesServiceName, c.PublicIP, endpointPorts, reconcile); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// CreateNamespaceIfNeeded will create a namespace if it doesn't already exist
|
||||
func (c *Controller) CreateNamespaceIfNeeded(ns string) error {
|
||||
if _, err := c.NamespaceClient.Namespaces().Get(ns, metav1.GetOptions{}); err == nil {
|
||||
// the namespace already exists
|
||||
return nil
|
||||
}
|
||||
newNs := &api.Namespace{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: ns,
|
||||
Namespace: "",
|
||||
},
|
||||
}
|
||||
_, err := c.NamespaceClient.Namespaces().Create(newNs)
|
||||
if err != nil && errors.IsAlreadyExists(err) {
|
||||
err = nil
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
// createPortAndServiceSpec creates an array of service ports.
|
||||
// If the NodePort value is 0, just the servicePort is used, otherwise, a node port is exposed.
|
||||
func createPortAndServiceSpec(servicePort int, targetServicePort int, nodePort int, servicePortName string, extraServicePorts []api.ServicePort) ([]api.ServicePort, api.ServiceType) {
|
||||
//Use the Cluster IP type for the service port if NodePort isn't provided.
|
||||
//Otherwise, we will be binding the master service to a NodePort.
|
||||
servicePorts := []api.ServicePort{{Protocol: api.ProtocolTCP,
|
||||
Port: int32(servicePort),
|
||||
Name: servicePortName,
|
||||
TargetPort: intstr.FromInt(targetServicePort)}}
|
||||
serviceType := api.ServiceTypeClusterIP
|
||||
if nodePort > 0 {
|
||||
servicePorts[0].NodePort = int32(nodePort)
|
||||
serviceType = api.ServiceTypeNodePort
|
||||
}
|
||||
if extraServicePorts != nil {
|
||||
servicePorts = append(servicePorts, extraServicePorts...)
|
||||
}
|
||||
return servicePorts, serviceType
|
||||
}
|
||||
|
||||
// createEndpointPortSpec creates an array of endpoint ports
|
||||
func createEndpointPortSpec(endpointPort int, endpointPortName string, extraEndpointPorts []api.EndpointPort) []api.EndpointPort {
|
||||
endpointPorts := []api.EndpointPort{{Protocol: api.ProtocolTCP,
|
||||
Port: int32(endpointPort),
|
||||
Name: endpointPortName,
|
||||
}}
|
||||
if extraEndpointPorts != nil {
|
||||
endpointPorts = append(endpointPorts, extraEndpointPorts...)
|
||||
}
|
||||
return endpointPorts
|
||||
}
|
||||
|
||||
// CreateMasterServiceIfNeeded will create the specified service if it
|
||||
// doesn't already exist.
|
||||
func (c *Controller) CreateOrUpdateMasterServiceIfNeeded(serviceName string, serviceIP net.IP, servicePorts []api.ServicePort, serviceType api.ServiceType, reconcile bool) error {
|
||||
if s, err := c.ServiceClient.Services(metav1.NamespaceDefault).Get(serviceName, metav1.GetOptions{}); err == nil {
|
||||
// The service already exists.
|
||||
if reconcile {
|
||||
if svc, updated := reconcilers.GetMasterServiceUpdateIfNeeded(s, servicePorts, serviceType); updated {
|
||||
glog.Warningf("Resetting master service %q to %#v", serviceName, svc)
|
||||
_, err := c.ServiceClient.Services(metav1.NamespaceDefault).Update(svc)
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
svc := &api.Service{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: serviceName,
|
||||
Namespace: metav1.NamespaceDefault,
|
||||
Labels: map[string]string{"provider": "kubernetes", "component": "apiserver"},
|
||||
},
|
||||
Spec: api.ServiceSpec{
|
||||
Ports: servicePorts,
|
||||
// maintained by this code, not by the pod selector
|
||||
Selector: nil,
|
||||
ClusterIP: serviceIP.String(),
|
||||
SessionAffinity: api.ServiceAffinityClientIP,
|
||||
Type: serviceType,
|
||||
},
|
||||
}
|
||||
|
||||
_, err := c.ServiceClient.Services(metav1.NamespaceDefault).Create(svc)
|
||||
if errors.IsAlreadyExists(err) {
|
||||
return c.CreateOrUpdateMasterServiceIfNeeded(serviceName, serviceIP, servicePorts, serviceType, reconcile)
|
||||
}
|
||||
return err
|
||||
}
|
||||
948
vendor/k8s.io/kubernetes/pkg/master/controller_test.go
generated
vendored
Normal file
948
vendor/k8s.io/kubernetes/pkg/master/controller_test.go
generated
vendored
Normal file
|
|
@ -0,0 +1,948 @@
|
|||
/*
|
||||
Copyright 2014 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 master
|
||||
|
||||
import (
|
||||
"net"
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/util/intstr"
|
||||
core "k8s.io/client-go/testing"
|
||||
api "k8s.io/kubernetes/pkg/apis/core"
|
||||
"k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset/fake"
|
||||
"k8s.io/kubernetes/pkg/master/reconcilers"
|
||||
)
|
||||
|
||||
func TestReconcileEndpoints(t *testing.T) {
|
||||
ns := metav1.NamespaceDefault
|
||||
om := func(name string) metav1.ObjectMeta {
|
||||
return metav1.ObjectMeta{Namespace: ns, Name: name}
|
||||
}
|
||||
reconcile_tests := []struct {
|
||||
testName string
|
||||
serviceName string
|
||||
ip string
|
||||
endpointPorts []api.EndpointPort
|
||||
additionalMasters int
|
||||
endpoints *api.EndpointsList
|
||||
expectUpdate *api.Endpoints // nil means none expected
|
||||
expectCreate *api.Endpoints // nil means none expected
|
||||
}{
|
||||
{
|
||||
testName: "no existing endpoints",
|
||||
serviceName: "foo",
|
||||
ip: "1.2.3.4",
|
||||
endpointPorts: []api.EndpointPort{{Name: "foo", Port: 8080, Protocol: "TCP"}},
|
||||
endpoints: nil,
|
||||
expectCreate: &api.Endpoints{
|
||||
ObjectMeta: om("foo"),
|
||||
Subsets: []api.EndpointSubset{{
|
||||
Addresses: []api.EndpointAddress{{IP: "1.2.3.4"}},
|
||||
Ports: []api.EndpointPort{{Name: "foo", Port: 8080, Protocol: "TCP"}},
|
||||
}},
|
||||
},
|
||||
},
|
||||
{
|
||||
testName: "existing endpoints satisfy",
|
||||
serviceName: "foo",
|
||||
ip: "1.2.3.4",
|
||||
endpointPorts: []api.EndpointPort{{Name: "foo", Port: 8080, Protocol: "TCP"}},
|
||||
endpoints: &api.EndpointsList{
|
||||
Items: []api.Endpoints{{
|
||||
ObjectMeta: om("foo"),
|
||||
Subsets: []api.EndpointSubset{{
|
||||
Addresses: []api.EndpointAddress{{IP: "1.2.3.4"}},
|
||||
Ports: []api.EndpointPort{{Name: "foo", Port: 8080, Protocol: "TCP"}},
|
||||
}},
|
||||
}},
|
||||
},
|
||||
},
|
||||
{
|
||||
testName: "existing endpoints satisfy but too many",
|
||||
serviceName: "foo",
|
||||
ip: "1.2.3.4",
|
||||
endpointPorts: []api.EndpointPort{{Name: "foo", Port: 8080, Protocol: "TCP"}},
|
||||
endpoints: &api.EndpointsList{
|
||||
Items: []api.Endpoints{{
|
||||
ObjectMeta: om("foo"),
|
||||
Subsets: []api.EndpointSubset{{
|
||||
Addresses: []api.EndpointAddress{{IP: "1.2.3.4"}, {IP: "4.3.2.1"}},
|
||||
Ports: []api.EndpointPort{{Name: "foo", Port: 8080, Protocol: "TCP"}},
|
||||
}},
|
||||
}},
|
||||
},
|
||||
expectUpdate: &api.Endpoints{
|
||||
ObjectMeta: om("foo"),
|
||||
Subsets: []api.EndpointSubset{{
|
||||
Addresses: []api.EndpointAddress{{IP: "1.2.3.4"}},
|
||||
Ports: []api.EndpointPort{{Name: "foo", Port: 8080, Protocol: "TCP"}},
|
||||
}},
|
||||
},
|
||||
},
|
||||
{
|
||||
testName: "existing endpoints satisfy but too many + extra masters",
|
||||
serviceName: "foo",
|
||||
ip: "1.2.3.4",
|
||||
endpointPorts: []api.EndpointPort{{Name: "foo", Port: 8080, Protocol: "TCP"}},
|
||||
additionalMasters: 3,
|
||||
endpoints: &api.EndpointsList{
|
||||
Items: []api.Endpoints{{
|
||||
ObjectMeta: om("foo"),
|
||||
Subsets: []api.EndpointSubset{{
|
||||
Addresses: []api.EndpointAddress{
|
||||
{IP: "1.2.3.4"},
|
||||
{IP: "4.3.2.1"},
|
||||
{IP: "4.3.2.2"},
|
||||
{IP: "4.3.2.3"},
|
||||
{IP: "4.3.2.4"},
|
||||
},
|
||||
Ports: []api.EndpointPort{{Name: "foo", Port: 8080, Protocol: "TCP"}},
|
||||
}},
|
||||
}},
|
||||
},
|
||||
expectUpdate: &api.Endpoints{
|
||||
ObjectMeta: om("foo"),
|
||||
Subsets: []api.EndpointSubset{{
|
||||
Addresses: []api.EndpointAddress{
|
||||
{IP: "1.2.3.4"},
|
||||
{IP: "4.3.2.2"},
|
||||
{IP: "4.3.2.3"},
|
||||
{IP: "4.3.2.4"},
|
||||
},
|
||||
Ports: []api.EndpointPort{{Name: "foo", Port: 8080, Protocol: "TCP"}},
|
||||
}},
|
||||
},
|
||||
},
|
||||
{
|
||||
testName: "existing endpoints satisfy but too many + extra masters + delete first",
|
||||
serviceName: "foo",
|
||||
ip: "4.3.2.4",
|
||||
endpointPorts: []api.EndpointPort{{Name: "foo", Port: 8080, Protocol: "TCP"}},
|
||||
additionalMasters: 3,
|
||||
endpoints: &api.EndpointsList{
|
||||
Items: []api.Endpoints{{
|
||||
ObjectMeta: om("foo"),
|
||||
Subsets: []api.EndpointSubset{{
|
||||
Addresses: []api.EndpointAddress{
|
||||
{IP: "1.2.3.4"},
|
||||
{IP: "4.3.2.1"},
|
||||
{IP: "4.3.2.2"},
|
||||
{IP: "4.3.2.3"},
|
||||
{IP: "4.3.2.4"},
|
||||
},
|
||||
Ports: []api.EndpointPort{{Name: "foo", Port: 8080, Protocol: "TCP"}},
|
||||
}},
|
||||
}},
|
||||
},
|
||||
expectUpdate: &api.Endpoints{
|
||||
ObjectMeta: om("foo"),
|
||||
Subsets: []api.EndpointSubset{{
|
||||
Addresses: []api.EndpointAddress{
|
||||
{IP: "4.3.2.1"},
|
||||
{IP: "4.3.2.2"},
|
||||
{IP: "4.3.2.3"},
|
||||
{IP: "4.3.2.4"},
|
||||
},
|
||||
Ports: []api.EndpointPort{{Name: "foo", Port: 8080, Protocol: "TCP"}},
|
||||
}},
|
||||
},
|
||||
},
|
||||
{
|
||||
testName: "existing endpoints satisfy and endpoint addresses length less than master count",
|
||||
serviceName: "foo",
|
||||
ip: "4.3.2.2",
|
||||
endpointPorts: []api.EndpointPort{{Name: "foo", Port: 8080, Protocol: "TCP"}},
|
||||
additionalMasters: 3,
|
||||
endpoints: &api.EndpointsList{
|
||||
Items: []api.Endpoints{{
|
||||
ObjectMeta: om("foo"),
|
||||
Subsets: []api.EndpointSubset{{
|
||||
Addresses: []api.EndpointAddress{
|
||||
{IP: "4.3.2.1"},
|
||||
{IP: "4.3.2.2"},
|
||||
},
|
||||
Ports: []api.EndpointPort{{Name: "foo", Port: 8080, Protocol: "TCP"}},
|
||||
}},
|
||||
}},
|
||||
},
|
||||
expectUpdate: nil,
|
||||
},
|
||||
{
|
||||
testName: "existing endpoints current IP missing and address length less than master count",
|
||||
serviceName: "foo",
|
||||
ip: "4.3.2.2",
|
||||
endpointPorts: []api.EndpointPort{{Name: "foo", Port: 8080, Protocol: "TCP"}},
|
||||
additionalMasters: 3,
|
||||
endpoints: &api.EndpointsList{
|
||||
Items: []api.Endpoints{{
|
||||
ObjectMeta: om("foo"),
|
||||
Subsets: []api.EndpointSubset{{
|
||||
Addresses: []api.EndpointAddress{
|
||||
{IP: "4.3.2.1"},
|
||||
},
|
||||
Ports: []api.EndpointPort{{Name: "foo", Port: 8080, Protocol: "TCP"}},
|
||||
}},
|
||||
}},
|
||||
},
|
||||
expectUpdate: &api.Endpoints{
|
||||
ObjectMeta: om("foo"),
|
||||
Subsets: []api.EndpointSubset{{
|
||||
Addresses: []api.EndpointAddress{
|
||||
{IP: "4.3.2.1"},
|
||||
{IP: "4.3.2.2"},
|
||||
},
|
||||
Ports: []api.EndpointPort{{Name: "foo", Port: 8080, Protocol: "TCP"}},
|
||||
}},
|
||||
},
|
||||
},
|
||||
{
|
||||
testName: "existing endpoints wrong name",
|
||||
serviceName: "foo",
|
||||
ip: "1.2.3.4",
|
||||
endpointPorts: []api.EndpointPort{{Name: "foo", Port: 8080, Protocol: "TCP"}},
|
||||
endpoints: &api.EndpointsList{
|
||||
Items: []api.Endpoints{{
|
||||
ObjectMeta: om("bar"),
|
||||
Subsets: []api.EndpointSubset{{
|
||||
Addresses: []api.EndpointAddress{{IP: "1.2.3.4"}},
|
||||
Ports: []api.EndpointPort{{Name: "foo", Port: 8080, Protocol: "TCP"}},
|
||||
}},
|
||||
}},
|
||||
},
|
||||
expectCreate: &api.Endpoints{
|
||||
ObjectMeta: om("foo"),
|
||||
Subsets: []api.EndpointSubset{{
|
||||
Addresses: []api.EndpointAddress{{IP: "1.2.3.4"}},
|
||||
Ports: []api.EndpointPort{{Name: "foo", Port: 8080, Protocol: "TCP"}},
|
||||
}},
|
||||
},
|
||||
},
|
||||
{
|
||||
testName: "existing endpoints wrong IP",
|
||||
serviceName: "foo",
|
||||
ip: "1.2.3.4",
|
||||
endpointPorts: []api.EndpointPort{{Name: "foo", Port: 8080, Protocol: "TCP"}},
|
||||
endpoints: &api.EndpointsList{
|
||||
Items: []api.Endpoints{{
|
||||
ObjectMeta: om("foo"),
|
||||
Subsets: []api.EndpointSubset{{
|
||||
Addresses: []api.EndpointAddress{{IP: "4.3.2.1"}},
|
||||
Ports: []api.EndpointPort{{Name: "foo", Port: 8080, Protocol: "TCP"}},
|
||||
}},
|
||||
}},
|
||||
},
|
||||
expectUpdate: &api.Endpoints{
|
||||
ObjectMeta: om("foo"),
|
||||
Subsets: []api.EndpointSubset{{
|
||||
Addresses: []api.EndpointAddress{{IP: "1.2.3.4"}},
|
||||
Ports: []api.EndpointPort{{Name: "foo", Port: 8080, Protocol: "TCP"}},
|
||||
}},
|
||||
},
|
||||
},
|
||||
{
|
||||
testName: "existing endpoints wrong port",
|
||||
serviceName: "foo",
|
||||
ip: "1.2.3.4",
|
||||
endpointPorts: []api.EndpointPort{{Name: "foo", Port: 8080, Protocol: "TCP"}},
|
||||
endpoints: &api.EndpointsList{
|
||||
Items: []api.Endpoints{{
|
||||
ObjectMeta: om("foo"),
|
||||
Subsets: []api.EndpointSubset{{
|
||||
Addresses: []api.EndpointAddress{{IP: "1.2.3.4"}},
|
||||
Ports: []api.EndpointPort{{Name: "foo", Port: 9090, Protocol: "TCP"}},
|
||||
}},
|
||||
}},
|
||||
},
|
||||
expectUpdate: &api.Endpoints{
|
||||
ObjectMeta: om("foo"),
|
||||
Subsets: []api.EndpointSubset{{
|
||||
Addresses: []api.EndpointAddress{{IP: "1.2.3.4"}},
|
||||
Ports: []api.EndpointPort{{Name: "foo", Port: 8080, Protocol: "TCP"}},
|
||||
}},
|
||||
},
|
||||
},
|
||||
{
|
||||
testName: "existing endpoints wrong protocol",
|
||||
serviceName: "foo",
|
||||
ip: "1.2.3.4",
|
||||
endpointPorts: []api.EndpointPort{{Name: "foo", Port: 8080, Protocol: "TCP"}},
|
||||
endpoints: &api.EndpointsList{
|
||||
Items: []api.Endpoints{{
|
||||
ObjectMeta: om("foo"),
|
||||
Subsets: []api.EndpointSubset{{
|
||||
Addresses: []api.EndpointAddress{{IP: "1.2.3.4"}},
|
||||
Ports: []api.EndpointPort{{Name: "foo", Port: 8080, Protocol: "UDP"}},
|
||||
}},
|
||||
}},
|
||||
},
|
||||
expectUpdate: &api.Endpoints{
|
||||
ObjectMeta: om("foo"),
|
||||
Subsets: []api.EndpointSubset{{
|
||||
Addresses: []api.EndpointAddress{{IP: "1.2.3.4"}},
|
||||
Ports: []api.EndpointPort{{Name: "foo", Port: 8080, Protocol: "TCP"}},
|
||||
}},
|
||||
},
|
||||
},
|
||||
{
|
||||
testName: "existing endpoints wrong port name",
|
||||
serviceName: "foo",
|
||||
ip: "1.2.3.4",
|
||||
endpointPorts: []api.EndpointPort{{Name: "baz", Port: 8080, Protocol: "TCP"}},
|
||||
endpoints: &api.EndpointsList{
|
||||
Items: []api.Endpoints{{
|
||||
ObjectMeta: om("foo"),
|
||||
Subsets: []api.EndpointSubset{{
|
||||
Addresses: []api.EndpointAddress{{IP: "1.2.3.4"}},
|
||||
Ports: []api.EndpointPort{{Name: "foo", Port: 8080, Protocol: "TCP"}},
|
||||
}},
|
||||
}},
|
||||
},
|
||||
expectUpdate: &api.Endpoints{
|
||||
ObjectMeta: om("foo"),
|
||||
Subsets: []api.EndpointSubset{{
|
||||
Addresses: []api.EndpointAddress{{IP: "1.2.3.4"}},
|
||||
Ports: []api.EndpointPort{{Name: "baz", Port: 8080, Protocol: "TCP"}},
|
||||
}},
|
||||
},
|
||||
},
|
||||
{
|
||||
testName: "existing endpoints extra service ports satisfy",
|
||||
serviceName: "foo",
|
||||
ip: "1.2.3.4",
|
||||
endpointPorts: []api.EndpointPort{
|
||||
{Name: "foo", Port: 8080, Protocol: "TCP"},
|
||||
{Name: "bar", Port: 1000, Protocol: "TCP"},
|
||||
{Name: "baz", Port: 1010, Protocol: "TCP"},
|
||||
},
|
||||
endpoints: &api.EndpointsList{
|
||||
Items: []api.Endpoints{{
|
||||
ObjectMeta: om("foo"),
|
||||
Subsets: []api.EndpointSubset{{
|
||||
Addresses: []api.EndpointAddress{{IP: "1.2.3.4"}},
|
||||
Ports: []api.EndpointPort{
|
||||
{Name: "foo", Port: 8080, Protocol: "TCP"},
|
||||
{Name: "bar", Port: 1000, Protocol: "TCP"},
|
||||
{Name: "baz", Port: 1010, Protocol: "TCP"},
|
||||
},
|
||||
}},
|
||||
}},
|
||||
},
|
||||
},
|
||||
{
|
||||
testName: "existing endpoints extra service ports missing port",
|
||||
serviceName: "foo",
|
||||
ip: "1.2.3.4",
|
||||
endpointPorts: []api.EndpointPort{
|
||||
{Name: "foo", Port: 8080, Protocol: "TCP"},
|
||||
{Name: "bar", Port: 1000, Protocol: "TCP"},
|
||||
},
|
||||
endpoints: &api.EndpointsList{
|
||||
Items: []api.Endpoints{{
|
||||
ObjectMeta: om("foo"),
|
||||
Subsets: []api.EndpointSubset{{
|
||||
Addresses: []api.EndpointAddress{{IP: "1.2.3.4"}},
|
||||
Ports: []api.EndpointPort{{Name: "foo", Port: 8080, Protocol: "TCP"}},
|
||||
}},
|
||||
}},
|
||||
},
|
||||
expectUpdate: &api.Endpoints{
|
||||
ObjectMeta: om("foo"),
|
||||
Subsets: []api.EndpointSubset{{
|
||||
Addresses: []api.EndpointAddress{{IP: "1.2.3.4"}},
|
||||
Ports: []api.EndpointPort{
|
||||
{Name: "foo", Port: 8080, Protocol: "TCP"},
|
||||
{Name: "bar", Port: 1000, Protocol: "TCP"},
|
||||
},
|
||||
}},
|
||||
},
|
||||
},
|
||||
}
|
||||
for _, test := range reconcile_tests {
|
||||
fakeClient := fake.NewSimpleClientset()
|
||||
if test.endpoints != nil {
|
||||
fakeClient = fake.NewSimpleClientset(test.endpoints)
|
||||
}
|
||||
reconciler := reconcilers.NewMasterCountEndpointReconciler(test.additionalMasters+1, fakeClient.Core())
|
||||
err := reconciler.ReconcileEndpoints(test.serviceName, net.ParseIP(test.ip), test.endpointPorts, true)
|
||||
if err != nil {
|
||||
t.Errorf("case %q: unexpected error: %v", test.testName, err)
|
||||
}
|
||||
|
||||
updates := []core.UpdateAction{}
|
||||
for _, action := range fakeClient.Actions() {
|
||||
if action.GetVerb() != "update" {
|
||||
continue
|
||||
}
|
||||
updates = append(updates, action.(core.UpdateAction))
|
||||
}
|
||||
if test.expectUpdate != nil {
|
||||
if len(updates) != 1 {
|
||||
t.Errorf("case %q: unexpected updates: %v", test.testName, updates)
|
||||
} else if e, a := test.expectUpdate, updates[0].GetObject(); !reflect.DeepEqual(e, a) {
|
||||
t.Errorf("case %q: expected update:\n%#v\ngot:\n%#v\n", test.testName, e, a)
|
||||
}
|
||||
}
|
||||
if test.expectUpdate == nil && len(updates) > 0 {
|
||||
t.Errorf("case %q: no update expected, yet saw: %v", test.testName, updates)
|
||||
}
|
||||
|
||||
creates := []core.CreateAction{}
|
||||
for _, action := range fakeClient.Actions() {
|
||||
if action.GetVerb() != "create" {
|
||||
continue
|
||||
}
|
||||
creates = append(creates, action.(core.CreateAction))
|
||||
}
|
||||
if test.expectCreate != nil {
|
||||
if len(creates) != 1 {
|
||||
t.Errorf("case %q: unexpected creates: %v", test.testName, creates)
|
||||
} else if e, a := test.expectCreate, creates[0].GetObject(); !reflect.DeepEqual(e, a) {
|
||||
t.Errorf("case %q: expected create:\n%#v\ngot:\n%#v\n", test.testName, e, a)
|
||||
}
|
||||
}
|
||||
if test.expectCreate == nil && len(creates) > 0 {
|
||||
t.Errorf("case %q: no create expected, yet saw: %v", test.testName, creates)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
non_reconcile_tests := []struct {
|
||||
testName string
|
||||
serviceName string
|
||||
ip string
|
||||
endpointPorts []api.EndpointPort
|
||||
additionalMasters int
|
||||
endpoints *api.EndpointsList
|
||||
expectUpdate *api.Endpoints // nil means none expected
|
||||
expectCreate *api.Endpoints // nil means none expected
|
||||
}{
|
||||
{
|
||||
testName: "existing endpoints extra service ports missing port no update",
|
||||
serviceName: "foo",
|
||||
ip: "1.2.3.4",
|
||||
endpointPorts: []api.EndpointPort{
|
||||
{Name: "foo", Port: 8080, Protocol: "TCP"},
|
||||
{Name: "bar", Port: 1000, Protocol: "TCP"},
|
||||
},
|
||||
endpoints: &api.EndpointsList{
|
||||
Items: []api.Endpoints{{
|
||||
ObjectMeta: om("foo"),
|
||||
Subsets: []api.EndpointSubset{{
|
||||
Addresses: []api.EndpointAddress{{IP: "1.2.3.4"}},
|
||||
Ports: []api.EndpointPort{{Name: "foo", Port: 8080, Protocol: "TCP"}},
|
||||
}},
|
||||
}},
|
||||
},
|
||||
expectUpdate: nil,
|
||||
},
|
||||
{
|
||||
testName: "existing endpoints extra service ports, wrong ports, wrong IP",
|
||||
serviceName: "foo",
|
||||
ip: "1.2.3.4",
|
||||
endpointPorts: []api.EndpointPort{
|
||||
{Name: "foo", Port: 8080, Protocol: "TCP"},
|
||||
{Name: "bar", Port: 1000, Protocol: "TCP"},
|
||||
},
|
||||
endpoints: &api.EndpointsList{
|
||||
Items: []api.Endpoints{{
|
||||
ObjectMeta: om("foo"),
|
||||
Subsets: []api.EndpointSubset{{
|
||||
Addresses: []api.EndpointAddress{{IP: "4.3.2.1"}},
|
||||
Ports: []api.EndpointPort{{Name: "foo", Port: 8080, Protocol: "TCP"}},
|
||||
}},
|
||||
}},
|
||||
},
|
||||
expectUpdate: &api.Endpoints{
|
||||
ObjectMeta: om("foo"),
|
||||
Subsets: []api.EndpointSubset{{
|
||||
Addresses: []api.EndpointAddress{{IP: "1.2.3.4"}},
|
||||
Ports: []api.EndpointPort{{Name: "foo", Port: 8080, Protocol: "TCP"}},
|
||||
}},
|
||||
},
|
||||
},
|
||||
{
|
||||
testName: "no existing endpoints",
|
||||
serviceName: "foo",
|
||||
ip: "1.2.3.4",
|
||||
endpointPorts: []api.EndpointPort{{Name: "foo", Port: 8080, Protocol: "TCP"}},
|
||||
endpoints: nil,
|
||||
expectCreate: &api.Endpoints{
|
||||
ObjectMeta: om("foo"),
|
||||
Subsets: []api.EndpointSubset{{
|
||||
Addresses: []api.EndpointAddress{{IP: "1.2.3.4"}},
|
||||
Ports: []api.EndpointPort{{Name: "foo", Port: 8080, Protocol: "TCP"}},
|
||||
}},
|
||||
},
|
||||
},
|
||||
}
|
||||
for _, test := range non_reconcile_tests {
|
||||
fakeClient := fake.NewSimpleClientset()
|
||||
if test.endpoints != nil {
|
||||
fakeClient = fake.NewSimpleClientset(test.endpoints)
|
||||
}
|
||||
reconciler := reconcilers.NewMasterCountEndpointReconciler(test.additionalMasters+1, fakeClient.Core())
|
||||
err := reconciler.ReconcileEndpoints(test.serviceName, net.ParseIP(test.ip), test.endpointPorts, false)
|
||||
if err != nil {
|
||||
t.Errorf("case %q: unexpected error: %v", test.testName, err)
|
||||
}
|
||||
|
||||
updates := []core.UpdateAction{}
|
||||
for _, action := range fakeClient.Actions() {
|
||||
if action.GetVerb() != "update" {
|
||||
continue
|
||||
}
|
||||
updates = append(updates, action.(core.UpdateAction))
|
||||
}
|
||||
if test.expectUpdate != nil {
|
||||
if len(updates) != 1 {
|
||||
t.Errorf("case %q: unexpected updates: %v", test.testName, updates)
|
||||
} else if e, a := test.expectUpdate, updates[0].GetObject(); !reflect.DeepEqual(e, a) {
|
||||
t.Errorf("case %q: expected update:\n%#v\ngot:\n%#v\n", test.testName, e, a)
|
||||
}
|
||||
}
|
||||
if test.expectUpdate == nil && len(updates) > 0 {
|
||||
t.Errorf("case %q: no update expected, yet saw: %v", test.testName, updates)
|
||||
}
|
||||
|
||||
creates := []core.CreateAction{}
|
||||
for _, action := range fakeClient.Actions() {
|
||||
if action.GetVerb() != "create" {
|
||||
continue
|
||||
}
|
||||
creates = append(creates, action.(core.CreateAction))
|
||||
}
|
||||
if test.expectCreate != nil {
|
||||
if len(creates) != 1 {
|
||||
t.Errorf("case %q: unexpected creates: %v", test.testName, creates)
|
||||
} else if e, a := test.expectCreate, creates[0].GetObject(); !reflect.DeepEqual(e, a) {
|
||||
t.Errorf("case %q: expected create:\n%#v\ngot:\n%#v\n", test.testName, e, a)
|
||||
}
|
||||
}
|
||||
if test.expectCreate == nil && len(creates) > 0 {
|
||||
t.Errorf("case %q: no create expected, yet saw: %v", test.testName, creates)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func TestCreateOrUpdateMasterService(t *testing.T) {
|
||||
ns := metav1.NamespaceDefault
|
||||
om := func(name string) metav1.ObjectMeta {
|
||||
return metav1.ObjectMeta{Namespace: ns, Name: name}
|
||||
}
|
||||
|
||||
create_tests := []struct {
|
||||
testName string
|
||||
serviceName string
|
||||
servicePorts []api.ServicePort
|
||||
serviceType api.ServiceType
|
||||
expectCreate *api.Service // nil means none expected
|
||||
}{
|
||||
{
|
||||
testName: "service does not exist",
|
||||
serviceName: "foo",
|
||||
servicePorts: []api.ServicePort{
|
||||
{Name: "foo", Port: 8080, Protocol: "TCP", TargetPort: intstr.FromInt(8080)},
|
||||
},
|
||||
serviceType: api.ServiceTypeClusterIP,
|
||||
expectCreate: &api.Service{
|
||||
ObjectMeta: om("foo"),
|
||||
Spec: api.ServiceSpec{
|
||||
Ports: []api.ServicePort{
|
||||
{Name: "foo", Port: 8080, Protocol: "TCP", TargetPort: intstr.FromInt(8080)},
|
||||
},
|
||||
Selector: nil,
|
||||
ClusterIP: "1.2.3.4",
|
||||
SessionAffinity: api.ServiceAffinityClientIP,
|
||||
Type: api.ServiceTypeClusterIP,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
for _, test := range create_tests {
|
||||
master := Controller{}
|
||||
fakeClient := fake.NewSimpleClientset()
|
||||
master.ServiceClient = fakeClient.Core()
|
||||
master.CreateOrUpdateMasterServiceIfNeeded(test.serviceName, net.ParseIP("1.2.3.4"), test.servicePorts, test.serviceType, false)
|
||||
creates := []core.CreateAction{}
|
||||
for _, action := range fakeClient.Actions() {
|
||||
if action.GetVerb() == "create" {
|
||||
creates = append(creates, action.(core.CreateAction))
|
||||
}
|
||||
}
|
||||
if test.expectCreate != nil {
|
||||
if len(creates) != 1 {
|
||||
t.Errorf("case %q: unexpected creations: %v", test.testName, creates)
|
||||
} else {
|
||||
obj := creates[0].GetObject()
|
||||
if e, a := test.expectCreate.Spec, obj.(*api.Service).Spec; !reflect.DeepEqual(e, a) {
|
||||
t.Errorf("case %q: expected create:\n%#v\ngot:\n%#v\n", test.testName, e, a)
|
||||
}
|
||||
}
|
||||
}
|
||||
if test.expectCreate == nil && len(creates) > 1 {
|
||||
t.Errorf("case %q: no create expected, yet saw: %v", test.testName, creates)
|
||||
}
|
||||
}
|
||||
|
||||
reconcile_tests := []struct {
|
||||
testName string
|
||||
serviceName string
|
||||
servicePorts []api.ServicePort
|
||||
serviceType api.ServiceType
|
||||
service *api.Service
|
||||
expectUpdate *api.Service // nil means none expected
|
||||
}{
|
||||
{
|
||||
testName: "service definition wrong port",
|
||||
serviceName: "foo",
|
||||
servicePorts: []api.ServicePort{
|
||||
{Name: "foo", Port: 8080, Protocol: "TCP", TargetPort: intstr.FromInt(8080)},
|
||||
},
|
||||
serviceType: api.ServiceTypeClusterIP,
|
||||
service: &api.Service{
|
||||
ObjectMeta: om("foo"),
|
||||
Spec: api.ServiceSpec{
|
||||
Ports: []api.ServicePort{
|
||||
{Name: "foo", Port: 8000, Protocol: "TCP", TargetPort: intstr.FromInt(8080)},
|
||||
},
|
||||
Selector: nil,
|
||||
ClusterIP: "1.2.3.4",
|
||||
SessionAffinity: api.ServiceAffinityClientIP,
|
||||
Type: api.ServiceTypeClusterIP,
|
||||
},
|
||||
},
|
||||
expectUpdate: &api.Service{
|
||||
ObjectMeta: om("foo"),
|
||||
Spec: api.ServiceSpec{
|
||||
Ports: []api.ServicePort{
|
||||
{Name: "foo", Port: 8080, Protocol: "TCP", TargetPort: intstr.FromInt(8080)},
|
||||
},
|
||||
Selector: nil,
|
||||
ClusterIP: "1.2.3.4",
|
||||
SessionAffinity: api.ServiceAffinityClientIP,
|
||||
Type: api.ServiceTypeClusterIP,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
testName: "service definition missing port",
|
||||
serviceName: "foo",
|
||||
servicePorts: []api.ServicePort{
|
||||
{Name: "foo", Port: 8080, Protocol: "TCP", TargetPort: intstr.FromInt(8080)},
|
||||
{Name: "baz", Port: 1000, Protocol: "TCP", TargetPort: intstr.FromInt(1000)},
|
||||
},
|
||||
serviceType: api.ServiceTypeClusterIP,
|
||||
service: &api.Service{
|
||||
ObjectMeta: om("foo"),
|
||||
Spec: api.ServiceSpec{
|
||||
Ports: []api.ServicePort{
|
||||
{Name: "foo", Port: 8080, Protocol: "TCP", TargetPort: intstr.FromInt(8080)},
|
||||
},
|
||||
Selector: nil,
|
||||
ClusterIP: "1.2.3.4",
|
||||
SessionAffinity: api.ServiceAffinityClientIP,
|
||||
Type: api.ServiceTypeClusterIP,
|
||||
},
|
||||
},
|
||||
expectUpdate: &api.Service{
|
||||
ObjectMeta: om("foo"),
|
||||
Spec: api.ServiceSpec{
|
||||
Ports: []api.ServicePort{
|
||||
{Name: "foo", Port: 8080, Protocol: "TCP", TargetPort: intstr.FromInt(8080)},
|
||||
{Name: "baz", Port: 1000, Protocol: "TCP", TargetPort: intstr.FromInt(1000)},
|
||||
},
|
||||
Selector: nil,
|
||||
ClusterIP: "1.2.3.4",
|
||||
SessionAffinity: api.ServiceAffinityClientIP,
|
||||
Type: api.ServiceTypeClusterIP,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
testName: "service definition incorrect port",
|
||||
serviceName: "foo",
|
||||
servicePorts: []api.ServicePort{
|
||||
{Name: "foo", Port: 8080, Protocol: "TCP", TargetPort: intstr.FromInt(8080)},
|
||||
},
|
||||
serviceType: api.ServiceTypeClusterIP,
|
||||
service: &api.Service{
|
||||
ObjectMeta: om("foo"),
|
||||
Spec: api.ServiceSpec{
|
||||
Ports: []api.ServicePort{
|
||||
{Name: "bar", Port: 1000, Protocol: "UDP", TargetPort: intstr.FromInt(1000)},
|
||||
},
|
||||
Selector: nil,
|
||||
ClusterIP: "1.2.3.4",
|
||||
SessionAffinity: api.ServiceAffinityClientIP,
|
||||
Type: api.ServiceTypeClusterIP,
|
||||
},
|
||||
},
|
||||
expectUpdate: &api.Service{
|
||||
ObjectMeta: om("foo"),
|
||||
Spec: api.ServiceSpec{
|
||||
Ports: []api.ServicePort{
|
||||
{Name: "foo", Port: 8080, Protocol: "TCP", TargetPort: intstr.FromInt(8080)},
|
||||
},
|
||||
Selector: nil,
|
||||
ClusterIP: "1.2.3.4",
|
||||
SessionAffinity: api.ServiceAffinityClientIP,
|
||||
Type: api.ServiceTypeClusterIP,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
testName: "service definition incorrect port name",
|
||||
serviceName: "foo",
|
||||
servicePorts: []api.ServicePort{
|
||||
{Name: "foo", Port: 8080, Protocol: "TCP", TargetPort: intstr.FromInt(8080)},
|
||||
},
|
||||
serviceType: api.ServiceTypeClusterIP,
|
||||
service: &api.Service{
|
||||
ObjectMeta: om("foo"),
|
||||
Spec: api.ServiceSpec{
|
||||
Ports: []api.ServicePort{
|
||||
{Name: "foo", Port: 1000, Protocol: "UDP", TargetPort: intstr.FromInt(1000)},
|
||||
},
|
||||
Selector: nil,
|
||||
ClusterIP: "1.2.3.4",
|
||||
SessionAffinity: api.ServiceAffinityClientIP,
|
||||
Type: api.ServiceTypeClusterIP,
|
||||
},
|
||||
},
|
||||
expectUpdate: &api.Service{
|
||||
ObjectMeta: om("foo"),
|
||||
Spec: api.ServiceSpec{
|
||||
Ports: []api.ServicePort{
|
||||
{Name: "foo", Port: 8080, Protocol: "TCP", TargetPort: intstr.FromInt(8080)},
|
||||
},
|
||||
Selector: nil,
|
||||
ClusterIP: "1.2.3.4",
|
||||
SessionAffinity: api.ServiceAffinityClientIP,
|
||||
Type: api.ServiceTypeClusterIP,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
testName: "service definition incorrect target port",
|
||||
serviceName: "foo",
|
||||
servicePorts: []api.ServicePort{
|
||||
{Name: "foo", Port: 8080, Protocol: "TCP", TargetPort: intstr.FromInt(8080)},
|
||||
},
|
||||
serviceType: api.ServiceTypeClusterIP,
|
||||
service: &api.Service{
|
||||
ObjectMeta: om("foo"),
|
||||
Spec: api.ServiceSpec{
|
||||
Ports: []api.ServicePort{
|
||||
{Name: "foo", Port: 8080, Protocol: "TCP", TargetPort: intstr.FromInt(1000)},
|
||||
},
|
||||
Selector: nil,
|
||||
ClusterIP: "1.2.3.4",
|
||||
SessionAffinity: api.ServiceAffinityClientIP,
|
||||
Type: api.ServiceTypeClusterIP,
|
||||
},
|
||||
},
|
||||
expectUpdate: &api.Service{
|
||||
ObjectMeta: om("foo"),
|
||||
Spec: api.ServiceSpec{
|
||||
Ports: []api.ServicePort{
|
||||
{Name: "foo", Port: 8080, Protocol: "TCP", TargetPort: intstr.FromInt(8080)},
|
||||
},
|
||||
Selector: nil,
|
||||
ClusterIP: "1.2.3.4",
|
||||
SessionAffinity: api.ServiceAffinityClientIP,
|
||||
Type: api.ServiceTypeClusterIP,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
testName: "service definition incorrect protocol",
|
||||
serviceName: "foo",
|
||||
servicePorts: []api.ServicePort{
|
||||
{Name: "foo", Port: 8080, Protocol: "TCP", TargetPort: intstr.FromInt(8080)},
|
||||
},
|
||||
serviceType: api.ServiceTypeClusterIP,
|
||||
service: &api.Service{
|
||||
ObjectMeta: om("foo"),
|
||||
Spec: api.ServiceSpec{
|
||||
Ports: []api.ServicePort{
|
||||
{Name: "foo", Port: 8080, Protocol: "UDP", TargetPort: intstr.FromInt(8080)},
|
||||
},
|
||||
Selector: nil,
|
||||
ClusterIP: "1.2.3.4",
|
||||
SessionAffinity: api.ServiceAffinityClientIP,
|
||||
Type: api.ServiceTypeClusterIP,
|
||||
},
|
||||
},
|
||||
expectUpdate: &api.Service{
|
||||
ObjectMeta: om("foo"),
|
||||
Spec: api.ServiceSpec{
|
||||
Ports: []api.ServicePort{
|
||||
{Name: "foo", Port: 8080, Protocol: "TCP", TargetPort: intstr.FromInt(8080)},
|
||||
},
|
||||
Selector: nil,
|
||||
ClusterIP: "1.2.3.4",
|
||||
SessionAffinity: api.ServiceAffinityClientIP,
|
||||
Type: api.ServiceTypeClusterIP,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
testName: "service definition has incorrect type",
|
||||
serviceName: "foo",
|
||||
servicePorts: []api.ServicePort{
|
||||
{Name: "foo", Port: 8080, Protocol: "TCP", TargetPort: intstr.FromInt(8080)},
|
||||
},
|
||||
serviceType: api.ServiceTypeClusterIP,
|
||||
service: &api.Service{
|
||||
ObjectMeta: om("foo"),
|
||||
Spec: api.ServiceSpec{
|
||||
Ports: []api.ServicePort{
|
||||
{Name: "foo", Port: 8080, Protocol: "TCP", TargetPort: intstr.FromInt(8080)},
|
||||
},
|
||||
Selector: nil,
|
||||
ClusterIP: "1.2.3.4",
|
||||
SessionAffinity: api.ServiceAffinityClientIP,
|
||||
Type: api.ServiceTypeNodePort,
|
||||
},
|
||||
},
|
||||
expectUpdate: &api.Service{
|
||||
ObjectMeta: om("foo"),
|
||||
Spec: api.ServiceSpec{
|
||||
Ports: []api.ServicePort{
|
||||
{Name: "foo", Port: 8080, Protocol: "TCP", TargetPort: intstr.FromInt(8080)},
|
||||
},
|
||||
Selector: nil,
|
||||
ClusterIP: "1.2.3.4",
|
||||
SessionAffinity: api.ServiceAffinityClientIP,
|
||||
Type: api.ServiceTypeClusterIP,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
testName: "service definition satisfies",
|
||||
serviceName: "foo",
|
||||
servicePorts: []api.ServicePort{
|
||||
{Name: "foo", Port: 8080, Protocol: "TCP", TargetPort: intstr.FromInt(8080)},
|
||||
},
|
||||
serviceType: api.ServiceTypeClusterIP,
|
||||
service: &api.Service{
|
||||
ObjectMeta: om("foo"),
|
||||
Spec: api.ServiceSpec{
|
||||
Ports: []api.ServicePort{
|
||||
{Name: "foo", Port: 8080, Protocol: "TCP", TargetPort: intstr.FromInt(8080)},
|
||||
},
|
||||
Selector: nil,
|
||||
ClusterIP: "1.2.3.4",
|
||||
SessionAffinity: api.ServiceAffinityClientIP,
|
||||
Type: api.ServiceTypeClusterIP,
|
||||
},
|
||||
},
|
||||
expectUpdate: nil,
|
||||
},
|
||||
}
|
||||
for _, test := range reconcile_tests {
|
||||
master := Controller{}
|
||||
fakeClient := fake.NewSimpleClientset(test.service)
|
||||
master.ServiceClient = fakeClient.Core()
|
||||
err := master.CreateOrUpdateMasterServiceIfNeeded(test.serviceName, net.ParseIP("1.2.3.4"), test.servicePorts, test.serviceType, true)
|
||||
if err != nil {
|
||||
t.Errorf("case %q: unexpected error: %v", test.testName, err)
|
||||
}
|
||||
updates := []core.UpdateAction{}
|
||||
for _, action := range fakeClient.Actions() {
|
||||
if action.GetVerb() == "update" {
|
||||
updates = append(updates, action.(core.UpdateAction))
|
||||
}
|
||||
}
|
||||
if test.expectUpdate != nil {
|
||||
if len(updates) != 1 {
|
||||
t.Errorf("case %q: unexpected updates: %v", test.testName, updates)
|
||||
} else {
|
||||
obj := updates[0].GetObject()
|
||||
if e, a := test.expectUpdate.Spec, obj.(*api.Service).Spec; !reflect.DeepEqual(e, a) {
|
||||
t.Errorf("case %q: expected update:\n%#v\ngot:\n%#v\n", test.testName, e, a)
|
||||
}
|
||||
}
|
||||
}
|
||||
if test.expectUpdate == nil && len(updates) > 0 {
|
||||
t.Errorf("case %q: no update expected, yet saw: %v", test.testName, updates)
|
||||
}
|
||||
}
|
||||
|
||||
non_reconcile_tests := []struct {
|
||||
testName string
|
||||
serviceName string
|
||||
servicePorts []api.ServicePort
|
||||
serviceType api.ServiceType
|
||||
service *api.Service
|
||||
expectUpdate *api.Service // nil means none expected
|
||||
}{
|
||||
{
|
||||
testName: "service definition wrong port, no expected update",
|
||||
serviceName: "foo",
|
||||
servicePorts: []api.ServicePort{
|
||||
{Name: "foo", Port: 8080, Protocol: "TCP", TargetPort: intstr.FromInt(8080)},
|
||||
},
|
||||
serviceType: api.ServiceTypeClusterIP,
|
||||
service: &api.Service{
|
||||
ObjectMeta: om("foo"),
|
||||
Spec: api.ServiceSpec{
|
||||
Ports: []api.ServicePort{
|
||||
{Name: "foo", Port: 1000, Protocol: "TCP", TargetPort: intstr.FromInt(1000)},
|
||||
},
|
||||
Selector: nil,
|
||||
ClusterIP: "1.2.3.4",
|
||||
SessionAffinity: api.ServiceAffinityClientIP,
|
||||
Type: api.ServiceTypeClusterIP,
|
||||
},
|
||||
},
|
||||
expectUpdate: nil,
|
||||
},
|
||||
}
|
||||
for _, test := range non_reconcile_tests {
|
||||
master := Controller{}
|
||||
fakeClient := fake.NewSimpleClientset(test.service)
|
||||
master.ServiceClient = fakeClient.Core()
|
||||
err := master.CreateOrUpdateMasterServiceIfNeeded(test.serviceName, net.ParseIP("1.2.3.4"), test.servicePorts, test.serviceType, false)
|
||||
if err != nil {
|
||||
t.Errorf("case %q: unexpected error: %v", test.testName, err)
|
||||
}
|
||||
updates := []core.UpdateAction{}
|
||||
for _, action := range fakeClient.Actions() {
|
||||
if action.GetVerb() == "update" {
|
||||
updates = append(updates, action.(core.UpdateAction))
|
||||
}
|
||||
}
|
||||
if test.expectUpdate != nil {
|
||||
if len(updates) != 1 {
|
||||
t.Errorf("case %q: unexpected updates: %v", test.testName, updates)
|
||||
} else {
|
||||
obj := updates[0].GetObject()
|
||||
if e, a := test.expectUpdate.Spec, obj.(*api.Service).Spec; !reflect.DeepEqual(e, a) {
|
||||
t.Errorf("case %q: expected update:\n%#v\ngot:\n%#v\n", test.testName, e, a)
|
||||
}
|
||||
}
|
||||
}
|
||||
if test.expectUpdate == nil && len(updates) > 0 {
|
||||
t.Errorf("case %q: no update expected, yet saw: %v", test.testName, updates)
|
||||
}
|
||||
}
|
||||
}
|
||||
19
vendor/k8s.io/kubernetes/pkg/master/doc.go
generated
vendored
Normal file
19
vendor/k8s.io/kubernetes/pkg/master/doc.go
generated
vendored
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
/*
|
||||
Copyright 2014 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 master contains code for setting up and running a Kubernetes
|
||||
// cluster master.
|
||||
package master // import "k8s.io/kubernetes/pkg/master"
|
||||
50
vendor/k8s.io/kubernetes/pkg/master/import_known_versions.go
generated
vendored
Normal file
50
vendor/k8s.io/kubernetes/pkg/master/import_known_versions.go
generated
vendored
Normal file
|
|
@ -0,0 +1,50 @@
|
|||
/*
|
||||
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 master
|
||||
|
||||
// These imports are the API groups the API server will support.
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"k8s.io/kubernetes/pkg/api/legacyscheme"
|
||||
|
||||
_ "k8s.io/kubernetes/pkg/apis/admission/install"
|
||||
_ "k8s.io/kubernetes/pkg/apis/admissionregistration/install"
|
||||
_ "k8s.io/kubernetes/pkg/apis/apps/install"
|
||||
_ "k8s.io/kubernetes/pkg/apis/authentication/install"
|
||||
_ "k8s.io/kubernetes/pkg/apis/authorization/install"
|
||||
_ "k8s.io/kubernetes/pkg/apis/autoscaling/install"
|
||||
_ "k8s.io/kubernetes/pkg/apis/batch/install"
|
||||
_ "k8s.io/kubernetes/pkg/apis/certificates/install"
|
||||
_ "k8s.io/kubernetes/pkg/apis/componentconfig/install"
|
||||
_ "k8s.io/kubernetes/pkg/apis/core/install"
|
||||
_ "k8s.io/kubernetes/pkg/apis/events/install"
|
||||
_ "k8s.io/kubernetes/pkg/apis/extensions/install"
|
||||
_ "k8s.io/kubernetes/pkg/apis/imagepolicy/install"
|
||||
_ "k8s.io/kubernetes/pkg/apis/networking/install"
|
||||
_ "k8s.io/kubernetes/pkg/apis/policy/install"
|
||||
_ "k8s.io/kubernetes/pkg/apis/rbac/install"
|
||||
_ "k8s.io/kubernetes/pkg/apis/scheduling/install"
|
||||
_ "k8s.io/kubernetes/pkg/apis/settings/install"
|
||||
_ "k8s.io/kubernetes/pkg/apis/storage/install"
|
||||
)
|
||||
|
||||
func init() {
|
||||
if missingVersions := legacyscheme.Registry.ValidateEnvRequestedVersions(); len(missingVersions) != 0 {
|
||||
panic(fmt.Sprintf("KUBE_API_VERSIONS contains versions that are not installed: %q.", missingVersions))
|
||||
}
|
||||
}
|
||||
187
vendor/k8s.io/kubernetes/pkg/master/import_known_versions_test.go
generated
vendored
Normal file
187
vendor/k8s.io/kubernetes/pkg/master/import_known_versions_test.go
generated
vendored
Normal file
|
|
@ -0,0 +1,187 @@
|
|||
/*
|
||||
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 master
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"reflect"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"k8s.io/api/core/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
"k8s.io/apimachinery/pkg/util/intstr"
|
||||
"k8s.io/apimachinery/pkg/util/sets"
|
||||
"k8s.io/kubernetes/pkg/api/legacyscheme"
|
||||
)
|
||||
|
||||
func TestGroupVersions(t *testing.T) {
|
||||
// legacyUnsuffixedGroups contains the groups released prior to deciding that kubernetes API groups should be dns-suffixed
|
||||
// new groups should be suffixed with ".k8s.io" (https://github.com/kubernetes/kubernetes/pull/31887#issuecomment-244462396)
|
||||
legacyUnsuffixedGroups := sets.NewString(
|
||||
"",
|
||||
"apps",
|
||||
"autoscaling",
|
||||
"batch",
|
||||
"componentconfig",
|
||||
"extensions",
|
||||
"policy",
|
||||
)
|
||||
|
||||
// No new groups should be added to the legacyUnsuffixedGroups exclusion list
|
||||
if len(legacyUnsuffixedGroups) != 7 {
|
||||
t.Errorf("No additional unnamespaced groups should be created")
|
||||
}
|
||||
|
||||
for _, gv := range legacyscheme.Registry.RegisteredGroupVersions() {
|
||||
if !strings.HasSuffix(gv.Group, ".k8s.io") && !legacyUnsuffixedGroups.Has(gv.Group) {
|
||||
t.Errorf("Group %s does not have the standard kubernetes API group suffix of .k8s.io", gv.Group)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestTypeTags(t *testing.T) {
|
||||
for gvk, knownType := range legacyscheme.Scheme.AllKnownTypes() {
|
||||
if gvk.Version == runtime.APIVersionInternal {
|
||||
ensureNoTags(t, gvk, knownType, nil)
|
||||
} else {
|
||||
ensureTags(t, gvk, knownType, nil)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// These types are registered in external versions, and therefore include json tags,
|
||||
// but are also registered in internal versions (or referenced from internal types),
|
||||
// so we explicitly allow tags for them
|
||||
var typesAllowedTags = map[reflect.Type]bool{
|
||||
reflect.TypeOf(intstr.IntOrString{}): true,
|
||||
reflect.TypeOf(metav1.Time{}): true,
|
||||
reflect.TypeOf(metav1.MicroTime{}): true,
|
||||
reflect.TypeOf(metav1.Duration{}): true,
|
||||
reflect.TypeOf(metav1.TypeMeta{}): true,
|
||||
reflect.TypeOf(metav1.ListMeta{}): true,
|
||||
reflect.TypeOf(metav1.ObjectMeta{}): true,
|
||||
reflect.TypeOf(metav1.OwnerReference{}): true,
|
||||
reflect.TypeOf(metav1.LabelSelector{}): true,
|
||||
reflect.TypeOf(metav1.GetOptions{}): true,
|
||||
reflect.TypeOf(metav1.ExportOptions{}): true,
|
||||
reflect.TypeOf(metav1.ListOptions{}): true,
|
||||
reflect.TypeOf(metav1.DeleteOptions{}): true,
|
||||
reflect.TypeOf(metav1.GroupVersionKind{}): true,
|
||||
reflect.TypeOf(metav1.GroupVersionResource{}): true,
|
||||
reflect.TypeOf(metav1.Status{}): true,
|
||||
}
|
||||
|
||||
func ensureNoTags(t *testing.T, gvk schema.GroupVersionKind, tp reflect.Type, parents []reflect.Type) {
|
||||
if _, ok := typesAllowedTags[tp]; ok {
|
||||
return
|
||||
}
|
||||
|
||||
parents = append(parents, tp)
|
||||
|
||||
switch tp.Kind() {
|
||||
case reflect.Map, reflect.Slice, reflect.Ptr:
|
||||
ensureNoTags(t, gvk, tp.Elem(), parents)
|
||||
|
||||
case reflect.String, reflect.Bool, reflect.Float32, reflect.Int32, reflect.Int64, reflect.Uint8, reflect.Uintptr, reflect.Uint32, reflect.Uint64, reflect.Interface:
|
||||
// no-op
|
||||
|
||||
case reflect.Struct:
|
||||
for i := 0; i < tp.NumField(); i++ {
|
||||
f := tp.Field(i)
|
||||
if f.PkgPath != "" {
|
||||
continue // Ignore unexported fields
|
||||
}
|
||||
jsonTag := f.Tag.Get("json")
|
||||
protoTag := f.Tag.Get("protobuf")
|
||||
if len(jsonTag) > 0 || len(protoTag) > 0 {
|
||||
t.Errorf("Internal types should not have json or protobuf tags. %#v has tag on field %v: %v", gvk, f.Name, f.Tag)
|
||||
for i, tp := range parents {
|
||||
t.Logf("%s%v:", strings.Repeat(" ", i), tp)
|
||||
}
|
||||
}
|
||||
|
||||
ensureNoTags(t, gvk, f.Type, parents)
|
||||
}
|
||||
|
||||
default:
|
||||
t.Errorf("Unexpected type %v in %#v", tp.Kind(), gvk)
|
||||
for i, tp := range parents {
|
||||
t.Logf("%s%v:", strings.Repeat(" ", i), tp)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var (
|
||||
marshalerType = reflect.TypeOf((*json.Marshaler)(nil)).Elem()
|
||||
unmarshalerType = reflect.TypeOf((*json.Unmarshaler)(nil)).Elem()
|
||||
)
|
||||
|
||||
// These fields are limited exceptions to the standard JSON naming structure.
|
||||
// Additions should only be made if a non-standard field name was released and cannot be changed for compatibility reasons.
|
||||
var allowedNonstandardJSONNames = map[reflect.Type]string{
|
||||
reflect.TypeOf(v1.DaemonEndpoint{}): "Port",
|
||||
}
|
||||
|
||||
func ensureTags(t *testing.T, gvk schema.GroupVersionKind, tp reflect.Type, parents []reflect.Type) {
|
||||
// This type handles its own encoding/decoding and doesn't need json tags
|
||||
if tp.Implements(marshalerType) && (tp.Implements(unmarshalerType) || reflect.PtrTo(tp).Implements(unmarshalerType)) {
|
||||
return
|
||||
}
|
||||
|
||||
parents = append(parents, tp)
|
||||
|
||||
switch tp.Kind() {
|
||||
case reflect.Map, reflect.Slice, reflect.Ptr:
|
||||
ensureTags(t, gvk, tp.Elem(), parents)
|
||||
|
||||
case reflect.String, reflect.Bool, reflect.Float32, reflect.Int, reflect.Int32, reflect.Int64, reflect.Uint8, reflect.Uintptr, reflect.Uint32, reflect.Uint64, reflect.Interface:
|
||||
// no-op
|
||||
|
||||
case reflect.Struct:
|
||||
for i := 0; i < tp.NumField(); i++ {
|
||||
f := tp.Field(i)
|
||||
jsonTag := f.Tag.Get("json")
|
||||
if len(jsonTag) == 0 {
|
||||
t.Errorf("External types should have json tags. %#v tags on field %v are: %s", gvk, f.Name, f.Tag)
|
||||
for i, tp := range parents {
|
||||
t.Logf("%s%v", strings.Repeat(" ", i), tp)
|
||||
}
|
||||
}
|
||||
|
||||
jsonTagName := strings.Split(jsonTag, ",")[0]
|
||||
if len(jsonTagName) > 0 && (jsonTagName[0] < 'a' || jsonTagName[0] > 'z') && jsonTagName != "-" && allowedNonstandardJSONNames[tp] != jsonTagName {
|
||||
t.Errorf("External types should have json names starting with lowercase letter. %#v has json tag on field %v with name %s", gvk, f.Name, jsonTagName)
|
||||
t.Log(tp)
|
||||
t.Log(allowedNonstandardJSONNames[tp])
|
||||
for i, tp := range parents {
|
||||
t.Logf("%s%v", strings.Repeat(" ", i), tp)
|
||||
}
|
||||
}
|
||||
|
||||
ensureTags(t, gvk, f.Type, parents)
|
||||
}
|
||||
|
||||
default:
|
||||
t.Errorf("Unexpected type %v in %#v", tp.Kind(), gvk)
|
||||
for i, tp := range parents {
|
||||
t.Logf("%s%v:", strings.Repeat(" ", i), tp)
|
||||
}
|
||||
}
|
||||
}
|
||||
501
vendor/k8s.io/kubernetes/pkg/master/master.go
generated
vendored
Normal file
501
vendor/k8s.io/kubernetes/pkg/master/master.go
generated
vendored
Normal file
|
|
@ -0,0 +1,501 @@
|
|||
/*
|
||||
Copyright 2014 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 master
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net"
|
||||
"net/http"
|
||||
"reflect"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
admissionregistrationv1beta1 "k8s.io/api/admissionregistration/v1beta1"
|
||||
appsv1 "k8s.io/api/apps/v1"
|
||||
appsv1beta1 "k8s.io/api/apps/v1beta1"
|
||||
appsv1beta2 "k8s.io/api/apps/v1beta2"
|
||||
authenticationv1 "k8s.io/api/authentication/v1"
|
||||
authenticationv1beta1 "k8s.io/api/authentication/v1beta1"
|
||||
authorizationapiv1 "k8s.io/api/authorization/v1"
|
||||
authorizationapiv1beta1 "k8s.io/api/authorization/v1beta1"
|
||||
autoscalingapiv1 "k8s.io/api/autoscaling/v1"
|
||||
autoscalingapiv2beta1 "k8s.io/api/autoscaling/v2beta1"
|
||||
batchapiv1 "k8s.io/api/batch/v1"
|
||||
batchapiv1beta1 "k8s.io/api/batch/v1beta1"
|
||||
certificatesapiv1beta1 "k8s.io/api/certificates/v1beta1"
|
||||
apiv1 "k8s.io/api/core/v1"
|
||||
eventsv1beta1 "k8s.io/api/events/v1beta1"
|
||||
extensionsapiv1beta1 "k8s.io/api/extensions/v1beta1"
|
||||
networkingapiv1 "k8s.io/api/networking/v1"
|
||||
policyapiv1beta1 "k8s.io/api/policy/v1beta1"
|
||||
rbacv1 "k8s.io/api/rbac/v1"
|
||||
rbacv1beta1 "k8s.io/api/rbac/v1beta1"
|
||||
storageapiv1 "k8s.io/api/storage/v1"
|
||||
storageapiv1beta1 "k8s.io/api/storage/v1beta1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
utilnet "k8s.io/apimachinery/pkg/util/net"
|
||||
"k8s.io/apiserver/pkg/endpoints/discovery"
|
||||
"k8s.io/apiserver/pkg/registry/generic"
|
||||
genericapiserver "k8s.io/apiserver/pkg/server"
|
||||
"k8s.io/apiserver/pkg/server/healthz"
|
||||
serverstorage "k8s.io/apiserver/pkg/server/storage"
|
||||
storagefactory "k8s.io/apiserver/pkg/storage/storagebackend/factory"
|
||||
"k8s.io/client-go/informers"
|
||||
corev1client "k8s.io/client-go/kubernetes/typed/core/v1"
|
||||
api "k8s.io/kubernetes/pkg/apis/core"
|
||||
coreclient "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset/typed/core/internalversion"
|
||||
kubeoptions "k8s.io/kubernetes/pkg/kubeapiserver/options"
|
||||
kubeletclient "k8s.io/kubernetes/pkg/kubelet/client"
|
||||
"k8s.io/kubernetes/pkg/master/reconcilers"
|
||||
"k8s.io/kubernetes/pkg/master/tunneler"
|
||||
"k8s.io/kubernetes/pkg/registry/core/endpoint"
|
||||
endpointsstorage "k8s.io/kubernetes/pkg/registry/core/endpoint/storage"
|
||||
"k8s.io/kubernetes/pkg/routes"
|
||||
nodeutil "k8s.io/kubernetes/pkg/util/node"
|
||||
|
||||
"github.com/golang/glog"
|
||||
"github.com/prometheus/client_golang/prometheus"
|
||||
|
||||
// RESTStorage installers
|
||||
admissionregistrationrest "k8s.io/kubernetes/pkg/registry/admissionregistration/rest"
|
||||
appsrest "k8s.io/kubernetes/pkg/registry/apps/rest"
|
||||
authenticationrest "k8s.io/kubernetes/pkg/registry/authentication/rest"
|
||||
authorizationrest "k8s.io/kubernetes/pkg/registry/authorization/rest"
|
||||
autoscalingrest "k8s.io/kubernetes/pkg/registry/autoscaling/rest"
|
||||
batchrest "k8s.io/kubernetes/pkg/registry/batch/rest"
|
||||
certificatesrest "k8s.io/kubernetes/pkg/registry/certificates/rest"
|
||||
corerest "k8s.io/kubernetes/pkg/registry/core/rest"
|
||||
eventsrest "k8s.io/kubernetes/pkg/registry/events/rest"
|
||||
extensionsrest "k8s.io/kubernetes/pkg/registry/extensions/rest"
|
||||
networkingrest "k8s.io/kubernetes/pkg/registry/networking/rest"
|
||||
policyrest "k8s.io/kubernetes/pkg/registry/policy/rest"
|
||||
rbacrest "k8s.io/kubernetes/pkg/registry/rbac/rest"
|
||||
schedulingrest "k8s.io/kubernetes/pkg/registry/scheduling/rest"
|
||||
settingsrest "k8s.io/kubernetes/pkg/registry/settings/rest"
|
||||
storagerest "k8s.io/kubernetes/pkg/registry/storage/rest"
|
||||
)
|
||||
|
||||
const (
|
||||
// DefaultEndpointReconcilerInterval is the default amount of time for how often the endpoints for
|
||||
// the kubernetes Service are reconciled.
|
||||
DefaultEndpointReconcilerInterval = 10 * time.Second
|
||||
// DefaultEndpointReconcilerTTL is the default TTL timeout for the storage layer
|
||||
DefaultEndpointReconcilerTTL = 15 * time.Second
|
||||
)
|
||||
|
||||
type ExtraConfig struct {
|
||||
ClientCARegistrationHook ClientCARegistrationHook
|
||||
|
||||
APIResourceConfigSource serverstorage.APIResourceConfigSource
|
||||
StorageFactory serverstorage.StorageFactory
|
||||
EnableCoreControllers bool
|
||||
EndpointReconcilerConfig EndpointReconcilerConfig
|
||||
EventTTL time.Duration
|
||||
KubeletClientConfig kubeletclient.KubeletClientConfig
|
||||
|
||||
// Used to start and monitor tunneling
|
||||
Tunneler tunneler.Tunneler
|
||||
EnableUISupport bool
|
||||
EnableLogsSupport bool
|
||||
ProxyTransport http.RoundTripper
|
||||
|
||||
// Values to build the IP addresses used by discovery
|
||||
// The range of IPs to be assigned to services with type=ClusterIP or greater
|
||||
ServiceIPRange net.IPNet
|
||||
// The IP address for the GenericAPIServer service (must be inside ServiceIPRange)
|
||||
APIServerServiceIP net.IP
|
||||
// Port for the apiserver service.
|
||||
APIServerServicePort int
|
||||
|
||||
// TODO, we can probably group service related items into a substruct to make it easier to configure
|
||||
// the API server items and `Extra*` fields likely fit nicely together.
|
||||
|
||||
// The range of ports to be assigned to services with type=NodePort or greater
|
||||
ServiceNodePortRange utilnet.PortRange
|
||||
// Additional ports to be exposed on the GenericAPIServer service
|
||||
// extraServicePorts is injectable in the event that more ports
|
||||
// (other than the default 443/tcp) are exposed on the GenericAPIServer
|
||||
// and those ports need to be load balanced by the GenericAPIServer
|
||||
// service because this pkg is linked by out-of-tree projects
|
||||
// like openshift which want to use the GenericAPIServer but also do
|
||||
// more stuff.
|
||||
ExtraServicePorts []api.ServicePort
|
||||
// Additional ports to be exposed on the GenericAPIServer endpoints
|
||||
// Port names should align with ports defined in ExtraServicePorts
|
||||
ExtraEndpointPorts []api.EndpointPort
|
||||
// If non-zero, the "kubernetes" services uses this port as NodePort.
|
||||
KubernetesServiceNodePort int
|
||||
|
||||
// Number of masters running; all masters must be started with the
|
||||
// same value for this field. (Numbers > 1 currently untested.)
|
||||
MasterCount int
|
||||
|
||||
// MasterEndpointReconcileTTL sets the time to live in seconds of an
|
||||
// endpoint record recorded by each master. The endpoints are checked at an
|
||||
// interval that is 2/3 of this value and this value defaults to 15s if
|
||||
// unset. In very large clusters, this value may be increased to reduce the
|
||||
// possibility that the master endpoint record expires (due to other load
|
||||
// on the etcd server) and causes masters to drop in and out of the
|
||||
// kubernetes service record. It is not recommended to set this value below
|
||||
// 15s.
|
||||
MasterEndpointReconcileTTL time.Duration
|
||||
|
||||
// Selects which reconciler to use
|
||||
EndpointReconcilerType reconcilers.Type
|
||||
}
|
||||
|
||||
type Config struct {
|
||||
GenericConfig *genericapiserver.Config
|
||||
ExtraConfig ExtraConfig
|
||||
}
|
||||
|
||||
type completedConfig struct {
|
||||
GenericConfig genericapiserver.CompletedConfig
|
||||
ExtraConfig *ExtraConfig
|
||||
}
|
||||
|
||||
type CompletedConfig struct {
|
||||
// Embed a private pointer that cannot be instantiated outside of this package.
|
||||
*completedConfig
|
||||
}
|
||||
|
||||
// EndpointReconcilerConfig holds the endpoint reconciler and endpoint reconciliation interval to be
|
||||
// used by the master.
|
||||
type EndpointReconcilerConfig struct {
|
||||
Reconciler reconcilers.EndpointReconciler
|
||||
Interval time.Duration
|
||||
}
|
||||
|
||||
// Master contains state for a Kubernetes cluster master/api server.
|
||||
type Master struct {
|
||||
GenericAPIServer *genericapiserver.GenericAPIServer
|
||||
|
||||
ClientCARegistrationHook ClientCARegistrationHook
|
||||
}
|
||||
|
||||
func (c *Config) createMasterCountReconciler() reconcilers.EndpointReconciler {
|
||||
endpointClient := coreclient.NewForConfigOrDie(c.GenericConfig.LoopbackClientConfig)
|
||||
return reconcilers.NewMasterCountEndpointReconciler(c.ExtraConfig.MasterCount, endpointClient)
|
||||
}
|
||||
|
||||
func (c *Config) createNoneReconciler() reconcilers.EndpointReconciler {
|
||||
return reconcilers.NewNoneEndpointReconciler()
|
||||
}
|
||||
|
||||
func (c *Config) createLeaseReconciler() reconcilers.EndpointReconciler {
|
||||
ttl := c.ExtraConfig.MasterEndpointReconcileTTL
|
||||
config, err := c.ExtraConfig.StorageFactory.NewConfig(api.Resource("apiServerIPInfo"))
|
||||
if err != nil {
|
||||
glog.Fatalf("Error determining service IP ranges: %v", err)
|
||||
}
|
||||
leaseStorage, _, err := storagefactory.Create(*config)
|
||||
if err != nil {
|
||||
glog.Fatalf("Error creating storage factory: %v", err)
|
||||
}
|
||||
endpointConfig, err := c.ExtraConfig.StorageFactory.NewConfig(api.Resource("endpoints"))
|
||||
if err != nil {
|
||||
glog.Fatalf("Error getting storage config: %v", err)
|
||||
}
|
||||
endpointsStorage := endpointsstorage.NewREST(generic.RESTOptions{
|
||||
StorageConfig: endpointConfig,
|
||||
Decorator: generic.UndecoratedStorage,
|
||||
DeleteCollectionWorkers: 0,
|
||||
ResourcePrefix: c.ExtraConfig.StorageFactory.ResourcePrefix(api.Resource("endpoints")),
|
||||
})
|
||||
endpointRegistry := endpoint.NewRegistry(endpointsStorage)
|
||||
masterLeases := reconcilers.NewLeases(leaseStorage, "/masterleases/", ttl)
|
||||
return reconcilers.NewLeaseEndpointReconciler(endpointRegistry, masterLeases)
|
||||
}
|
||||
|
||||
func (c *Config) createEndpointReconciler() reconcilers.EndpointReconciler {
|
||||
glog.Infof("Using reconciler: %v", c.ExtraConfig.EndpointReconcilerType)
|
||||
switch c.ExtraConfig.EndpointReconcilerType {
|
||||
// there are numerous test dependencies that depend on a default controller
|
||||
case "", reconcilers.MasterCountReconcilerType:
|
||||
return c.createMasterCountReconciler()
|
||||
case reconcilers.LeaseEndpointReconcilerType:
|
||||
return c.createLeaseReconciler()
|
||||
case reconcilers.NoneEndpointReconcilerType:
|
||||
return c.createNoneReconciler()
|
||||
default:
|
||||
glog.Fatalf("Reconciler not implemented: %v", c.ExtraConfig.EndpointReconcilerType)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Complete fills in any fields not set that are required to have valid data. It's mutating the receiver.
|
||||
func (cfg *Config) Complete(informers informers.SharedInformerFactory) CompletedConfig {
|
||||
c := completedConfig{
|
||||
cfg.GenericConfig.Complete(informers),
|
||||
&cfg.ExtraConfig,
|
||||
}
|
||||
|
||||
serviceIPRange, apiServerServiceIP, err := DefaultServiceIPRange(c.ExtraConfig.ServiceIPRange)
|
||||
if err != nil {
|
||||
glog.Fatalf("Error determining service IP ranges: %v", err)
|
||||
}
|
||||
if c.ExtraConfig.ServiceIPRange.IP == nil {
|
||||
c.ExtraConfig.ServiceIPRange = serviceIPRange
|
||||
}
|
||||
if c.ExtraConfig.APIServerServiceIP == nil {
|
||||
c.ExtraConfig.APIServerServiceIP = apiServerServiceIP
|
||||
}
|
||||
|
||||
discoveryAddresses := discovery.DefaultAddresses{DefaultAddress: c.GenericConfig.ExternalAddress}
|
||||
discoveryAddresses.CIDRRules = append(discoveryAddresses.CIDRRules,
|
||||
discovery.CIDRRule{IPRange: c.ExtraConfig.ServiceIPRange, Address: net.JoinHostPort(c.ExtraConfig.APIServerServiceIP.String(), strconv.Itoa(c.ExtraConfig.APIServerServicePort))})
|
||||
c.GenericConfig.DiscoveryAddresses = discoveryAddresses
|
||||
|
||||
if c.ExtraConfig.ServiceNodePortRange.Size == 0 {
|
||||
// TODO: Currently no way to specify an empty range (do we need to allow this?)
|
||||
// We should probably allow this for clouds that don't require NodePort to do load-balancing (GCE)
|
||||
// but then that breaks the strict nestedness of ServiceType.
|
||||
// Review post-v1
|
||||
c.ExtraConfig.ServiceNodePortRange = kubeoptions.DefaultServiceNodePortRange
|
||||
glog.Infof("Node port range unspecified. Defaulting to %v.", c.ExtraConfig.ServiceNodePortRange)
|
||||
}
|
||||
|
||||
// enable swagger UI only if general UI support is on
|
||||
c.GenericConfig.EnableSwaggerUI = c.GenericConfig.EnableSwaggerUI && c.ExtraConfig.EnableUISupport
|
||||
|
||||
if c.ExtraConfig.EndpointReconcilerConfig.Interval == 0 {
|
||||
c.ExtraConfig.EndpointReconcilerConfig.Interval = DefaultEndpointReconcilerInterval
|
||||
}
|
||||
|
||||
if c.ExtraConfig.MasterEndpointReconcileTTL == 0 {
|
||||
c.ExtraConfig.MasterEndpointReconcileTTL = DefaultEndpointReconcilerTTL
|
||||
}
|
||||
|
||||
if c.ExtraConfig.EndpointReconcilerConfig.Reconciler == nil {
|
||||
c.ExtraConfig.EndpointReconcilerConfig.Reconciler = cfg.createEndpointReconciler()
|
||||
}
|
||||
|
||||
// this has always been hardcoded true in the past
|
||||
c.GenericConfig.EnableMetrics = true
|
||||
|
||||
return CompletedConfig{&c}
|
||||
}
|
||||
|
||||
// New returns a new instance of Master from the given config.
|
||||
// Certain config fields will be set to a default value if unset.
|
||||
// Certain config fields must be specified, including:
|
||||
// KubeletClientConfig
|
||||
func (c completedConfig) New(delegationTarget genericapiserver.DelegationTarget) (*Master, error) {
|
||||
if reflect.DeepEqual(c.ExtraConfig.KubeletClientConfig, kubeletclient.KubeletClientConfig{}) {
|
||||
return nil, fmt.Errorf("Master.New() called with empty config.KubeletClientConfig")
|
||||
}
|
||||
|
||||
s, err := c.GenericConfig.New("kube-apiserver", delegationTarget)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if c.ExtraConfig.EnableUISupport {
|
||||
routes.UIRedirect{}.Install(s.Handler.NonGoRestfulMux)
|
||||
}
|
||||
if c.ExtraConfig.EnableLogsSupport {
|
||||
routes.Logs{}.Install(s.Handler.GoRestfulContainer)
|
||||
}
|
||||
|
||||
m := &Master{
|
||||
GenericAPIServer: s,
|
||||
}
|
||||
|
||||
// install legacy rest storage
|
||||
if c.ExtraConfig.APIResourceConfigSource.AnyResourcesForVersionEnabled(apiv1.SchemeGroupVersion) {
|
||||
legacyRESTStorageProvider := corerest.LegacyRESTStorageProvider{
|
||||
StorageFactory: c.ExtraConfig.StorageFactory,
|
||||
ProxyTransport: c.ExtraConfig.ProxyTransport,
|
||||
KubeletClientConfig: c.ExtraConfig.KubeletClientConfig,
|
||||
EventTTL: c.ExtraConfig.EventTTL,
|
||||
ServiceIPRange: c.ExtraConfig.ServiceIPRange,
|
||||
ServiceNodePortRange: c.ExtraConfig.ServiceNodePortRange,
|
||||
LoopbackClientConfig: c.GenericConfig.LoopbackClientConfig,
|
||||
}
|
||||
m.InstallLegacyAPI(&c, c.GenericConfig.RESTOptionsGetter, legacyRESTStorageProvider)
|
||||
}
|
||||
|
||||
// The order here is preserved in discovery.
|
||||
// If resources with identical names exist in more than one of these groups (e.g. "deployments.apps"" and "deployments.extensions"),
|
||||
// the order of this list determines which group an unqualified resource name (e.g. "deployments") should prefer.
|
||||
// This priority order is used for local discovery, but it ends up aggregated in `k8s.io/kubernetes/cmd/kube-apiserver/app/aggregator.go
|
||||
// with specific priorities.
|
||||
// TODO: describe the priority all the way down in the RESTStorageProviders and plumb it back through the various discovery
|
||||
// handlers that we have.
|
||||
restStorageProviders := []RESTStorageProvider{
|
||||
authenticationrest.RESTStorageProvider{Authenticator: c.GenericConfig.Authenticator},
|
||||
authorizationrest.RESTStorageProvider{Authorizer: c.GenericConfig.Authorizer, RuleResolver: c.GenericConfig.RuleResolver},
|
||||
autoscalingrest.RESTStorageProvider{},
|
||||
batchrest.RESTStorageProvider{},
|
||||
certificatesrest.RESTStorageProvider{},
|
||||
extensionsrest.RESTStorageProvider{},
|
||||
networkingrest.RESTStorageProvider{},
|
||||
policyrest.RESTStorageProvider{},
|
||||
rbacrest.RESTStorageProvider{Authorizer: c.GenericConfig.Authorizer},
|
||||
schedulingrest.RESTStorageProvider{},
|
||||
settingsrest.RESTStorageProvider{},
|
||||
storagerest.RESTStorageProvider{},
|
||||
// keep apps after extensions so legacy clients resolve the extensions versions of shared resource names.
|
||||
// See https://github.com/kubernetes/kubernetes/issues/42392
|
||||
appsrest.RESTStorageProvider{},
|
||||
admissionregistrationrest.RESTStorageProvider{},
|
||||
eventsrest.RESTStorageProvider{TTL: c.ExtraConfig.EventTTL},
|
||||
}
|
||||
m.InstallAPIs(c.ExtraConfig.APIResourceConfigSource, c.GenericConfig.RESTOptionsGetter, restStorageProviders...)
|
||||
|
||||
if c.ExtraConfig.Tunneler != nil {
|
||||
m.installTunneler(c.ExtraConfig.Tunneler, corev1client.NewForConfigOrDie(c.GenericConfig.LoopbackClientConfig).Nodes())
|
||||
}
|
||||
|
||||
m.GenericAPIServer.AddPostStartHookOrDie("ca-registration", c.ExtraConfig.ClientCARegistrationHook.PostStartHook)
|
||||
|
||||
return m, nil
|
||||
}
|
||||
|
||||
func (m *Master) InstallLegacyAPI(c *completedConfig, restOptionsGetter generic.RESTOptionsGetter, legacyRESTStorageProvider corerest.LegacyRESTStorageProvider) {
|
||||
legacyRESTStorage, apiGroupInfo, err := legacyRESTStorageProvider.NewLegacyRESTStorage(restOptionsGetter)
|
||||
if err != nil {
|
||||
glog.Fatalf("Error building core storage: %v", err)
|
||||
}
|
||||
|
||||
if c.ExtraConfig.EnableCoreControllers {
|
||||
controllerName := "bootstrap-controller"
|
||||
coreClient := coreclient.NewForConfigOrDie(c.GenericConfig.LoopbackClientConfig)
|
||||
bootstrapController := c.NewBootstrapController(legacyRESTStorage, coreClient, coreClient, coreClient)
|
||||
m.GenericAPIServer.AddPostStartHookOrDie(controllerName, bootstrapController.PostStartHook)
|
||||
m.GenericAPIServer.AddPreShutdownHookOrDie(controllerName, bootstrapController.PreShutdownHook)
|
||||
}
|
||||
|
||||
if err := m.GenericAPIServer.InstallLegacyAPIGroup(genericapiserver.DefaultLegacyAPIPrefix, &apiGroupInfo); err != nil {
|
||||
glog.Fatalf("Error in registering group versions: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func (m *Master) installTunneler(nodeTunneler tunneler.Tunneler, nodeClient corev1client.NodeInterface) {
|
||||
nodeTunneler.Run(nodeAddressProvider{nodeClient}.externalAddresses)
|
||||
m.GenericAPIServer.AddHealthzChecks(healthz.NamedCheck("SSH Tunnel Check", tunneler.TunnelSyncHealthChecker(nodeTunneler)))
|
||||
prometheus.NewGaugeFunc(prometheus.GaugeOpts{
|
||||
Name: "apiserver_proxy_tunnel_sync_latency_secs",
|
||||
Help: "The time since the last successful synchronization of the SSH tunnels for proxy requests.",
|
||||
}, func() float64 { return float64(nodeTunneler.SecondsSinceSync()) })
|
||||
}
|
||||
|
||||
// RESTStorageProvider is a factory type for REST storage.
|
||||
type RESTStorageProvider interface {
|
||||
GroupName() string
|
||||
NewRESTStorage(apiResourceConfigSource serverstorage.APIResourceConfigSource, restOptionsGetter generic.RESTOptionsGetter) (genericapiserver.APIGroupInfo, bool)
|
||||
}
|
||||
|
||||
// InstallAPIs will install the APIs for the restStorageProviders if they are enabled.
|
||||
func (m *Master) InstallAPIs(apiResourceConfigSource serverstorage.APIResourceConfigSource, restOptionsGetter generic.RESTOptionsGetter, restStorageProviders ...RESTStorageProvider) {
|
||||
apiGroupsInfo := []genericapiserver.APIGroupInfo{}
|
||||
|
||||
for _, restStorageBuilder := range restStorageProviders {
|
||||
groupName := restStorageBuilder.GroupName()
|
||||
if !apiResourceConfigSource.AnyResourcesForGroupEnabled(groupName) {
|
||||
glog.V(1).Infof("Skipping disabled API group %q.", groupName)
|
||||
continue
|
||||
}
|
||||
apiGroupInfo, enabled := restStorageBuilder.NewRESTStorage(apiResourceConfigSource, restOptionsGetter)
|
||||
if !enabled {
|
||||
glog.Warningf("Problem initializing API group %q, skipping.", groupName)
|
||||
continue
|
||||
}
|
||||
glog.V(1).Infof("Enabling API group %q.", groupName)
|
||||
|
||||
if postHookProvider, ok := restStorageBuilder.(genericapiserver.PostStartHookProvider); ok {
|
||||
name, hook, err := postHookProvider.PostStartHook()
|
||||
if err != nil {
|
||||
glog.Fatalf("Error building PostStartHook: %v", err)
|
||||
}
|
||||
m.GenericAPIServer.AddPostStartHookOrDie(name, hook)
|
||||
}
|
||||
|
||||
apiGroupsInfo = append(apiGroupsInfo, apiGroupInfo)
|
||||
}
|
||||
|
||||
for i := range apiGroupsInfo {
|
||||
if err := m.GenericAPIServer.InstallAPIGroup(&apiGroupsInfo[i]); err != nil {
|
||||
glog.Fatalf("Error in registering group versions: %v", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
type nodeAddressProvider struct {
|
||||
nodeClient corev1client.NodeInterface
|
||||
}
|
||||
|
||||
func (n nodeAddressProvider) externalAddresses() ([]string, error) {
|
||||
preferredAddressTypes := []apiv1.NodeAddressType{
|
||||
apiv1.NodeExternalIP,
|
||||
}
|
||||
nodes, err := n.nodeClient.List(metav1.ListOptions{})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
addrs := []string{}
|
||||
for ix := range nodes.Items {
|
||||
node := &nodes.Items[ix]
|
||||
addr, err := nodeutil.GetPreferredNodeAddress(node, preferredAddressTypes)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
addrs = append(addrs, addr)
|
||||
}
|
||||
return addrs, nil
|
||||
}
|
||||
|
||||
func DefaultAPIResourceConfigSource() *serverstorage.ResourceConfig {
|
||||
ret := serverstorage.NewResourceConfig()
|
||||
// NOTE: GroupVersions listed here will be enabled by default. Don't put alpha versions in the list.
|
||||
ret.EnableVersions(
|
||||
apiv1.SchemeGroupVersion,
|
||||
extensionsapiv1beta1.SchemeGroupVersion,
|
||||
batchapiv1.SchemeGroupVersion,
|
||||
batchapiv1beta1.SchemeGroupVersion,
|
||||
authenticationv1.SchemeGroupVersion,
|
||||
authenticationv1beta1.SchemeGroupVersion,
|
||||
autoscalingapiv1.SchemeGroupVersion,
|
||||
autoscalingapiv2beta1.SchemeGroupVersion,
|
||||
appsv1beta1.SchemeGroupVersion,
|
||||
appsv1beta2.SchemeGroupVersion,
|
||||
appsv1.SchemeGroupVersion,
|
||||
policyapiv1beta1.SchemeGroupVersion,
|
||||
rbacv1.SchemeGroupVersion,
|
||||
rbacv1beta1.SchemeGroupVersion,
|
||||
storageapiv1.SchemeGroupVersion,
|
||||
storageapiv1beta1.SchemeGroupVersion,
|
||||
certificatesapiv1beta1.SchemeGroupVersion,
|
||||
authorizationapiv1.SchemeGroupVersion,
|
||||
authorizationapiv1beta1.SchemeGroupVersion,
|
||||
networkingapiv1.SchemeGroupVersion,
|
||||
eventsv1beta1.SchemeGroupVersion,
|
||||
admissionregistrationv1beta1.SchemeGroupVersion,
|
||||
)
|
||||
|
||||
// all extensions resources except these are disabled by default
|
||||
ret.EnableResources(
|
||||
extensionsapiv1beta1.SchemeGroupVersion.WithResource("daemonsets"),
|
||||
extensionsapiv1beta1.SchemeGroupVersion.WithResource("deployments"),
|
||||
extensionsapiv1beta1.SchemeGroupVersion.WithResource("ingresses"),
|
||||
extensionsapiv1beta1.SchemeGroupVersion.WithResource("networkpolicies"),
|
||||
extensionsapiv1beta1.SchemeGroupVersion.WithResource("replicasets"),
|
||||
extensionsapiv1beta1.SchemeGroupVersion.WithResource("podsecuritypolicies"),
|
||||
)
|
||||
|
||||
return ret
|
||||
}
|
||||
97
vendor/k8s.io/kubernetes/pkg/master/master_openapi_test.go
generated
vendored
Normal file
97
vendor/k8s.io/kubernetes/pkg/master/master_openapi_test.go
generated
vendored
Normal file
|
|
@ -0,0 +1,97 @@
|
|||
// +build !race
|
||||
|
||||
/*
|
||||
Copyright 2014 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 master
|
||||
|
||||
// This test file is separated from master_test.go so we would be able to disable
|
||||
// race check for it. TestValidOpenAPISpec will became extremely slow if -race
|
||||
// flag exists, and will cause the tests to timeout.
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"testing"
|
||||
|
||||
apirequest "k8s.io/apiserver/pkg/endpoints/request"
|
||||
genericapiserver "k8s.io/apiserver/pkg/server"
|
||||
"k8s.io/kubernetes/pkg/api/legacyscheme"
|
||||
openapigen "k8s.io/kubernetes/pkg/generated/openapi"
|
||||
|
||||
"github.com/go-openapi/loads"
|
||||
"github.com/go-openapi/spec"
|
||||
"github.com/go-openapi/strfmt"
|
||||
"github.com/go-openapi/validate"
|
||||
)
|
||||
|
||||
// TestValidOpenAPISpec verifies that the open api is added
|
||||
// at the proper endpoint and the spec is valid.
|
||||
func TestValidOpenAPISpec(t *testing.T) {
|
||||
etcdserver, config, sharedInformers, assert := setUp(t)
|
||||
defer etcdserver.Terminate(t)
|
||||
|
||||
config.GenericConfig.EnableIndex = true
|
||||
config.GenericConfig.OpenAPIConfig = genericapiserver.DefaultOpenAPIConfig(openapigen.GetOpenAPIDefinitions, legacyscheme.Scheme)
|
||||
config.GenericConfig.OpenAPIConfig.Info = &spec.Info{
|
||||
InfoProps: spec.InfoProps{
|
||||
Title: "Kubernetes",
|
||||
Version: "unversioned",
|
||||
},
|
||||
}
|
||||
config.GenericConfig.SwaggerConfig = genericapiserver.DefaultSwaggerConfig()
|
||||
|
||||
master, err := config.Complete(sharedInformers).New(genericapiserver.EmptyDelegate)
|
||||
if err != nil {
|
||||
t.Fatalf("Error in bringing up the master: %v", err)
|
||||
}
|
||||
|
||||
// make sure swagger.json is not registered before calling PrepareRun.
|
||||
server := httptest.NewServer(apirequest.WithRequestContext(master.GenericAPIServer.Handler.Director, master.GenericAPIServer.RequestContextMapper()))
|
||||
defer server.Close()
|
||||
resp, err := http.Get(server.URL + "/swagger.json")
|
||||
if !assert.NoError(err) {
|
||||
t.Errorf("unexpected error: %v", err)
|
||||
}
|
||||
assert.Equal(http.StatusNotFound, resp.StatusCode)
|
||||
|
||||
master.GenericAPIServer.PrepareRun()
|
||||
|
||||
resp, err = http.Get(server.URL + "/swagger.json")
|
||||
if !assert.NoError(err) {
|
||||
t.Errorf("unexpected error: %v", err)
|
||||
}
|
||||
assert.Equal(http.StatusOK, resp.StatusCode)
|
||||
|
||||
// as json schema
|
||||
var sch spec.Schema
|
||||
if assert.NoError(decodeResponse(resp, &sch)) {
|
||||
validator := validate.NewSchemaValidator(spec.MustLoadSwagger20Schema(), nil, "", strfmt.Default)
|
||||
res := validator.Validate(&sch)
|
||||
assert.NoError(res.AsError())
|
||||
}
|
||||
|
||||
// Validate OpenApi spec
|
||||
doc, err := loads.Spec(server.URL + "/swagger.json")
|
||||
if assert.NoError(err) {
|
||||
validator := validate.NewSpecValidator(doc.Schema(), strfmt.Default)
|
||||
res, warns := validator.Validate(doc)
|
||||
assert.NoError(res.AsError())
|
||||
if !warns.IsValid() {
|
||||
t.Logf("Open API spec on root has some warnings : %v", warns)
|
||||
}
|
||||
}
|
||||
}
|
||||
385
vendor/k8s.io/kubernetes/pkg/master/master_test.go
generated
vendored
Normal file
385
vendor/k8s.io/kubernetes/pkg/master/master_test.go
generated
vendored
Normal file
|
|
@ -0,0 +1,385 @@
|
|||
/*
|
||||
Copyright 2014 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 master
|
||||
|
||||
import (
|
||||
"crypto/tls"
|
||||
"encoding/json"
|
||||
"io/ioutil"
|
||||
"net"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"reflect"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
appsapiv1beta1 "k8s.io/api/apps/v1beta1"
|
||||
autoscalingapiv1 "k8s.io/api/autoscaling/v1"
|
||||
batchapiv1 "k8s.io/api/batch/v1"
|
||||
batchapiv1beta1 "k8s.io/api/batch/v1beta1"
|
||||
certificatesapiv1beta1 "k8s.io/api/certificates/v1beta1"
|
||||
apiv1 "k8s.io/api/core/v1"
|
||||
extensionsapiv1beta1 "k8s.io/api/extensions/v1beta1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
utilnet "k8s.io/apimachinery/pkg/util/net"
|
||||
"k8s.io/apimachinery/pkg/util/sets"
|
||||
"k8s.io/apimachinery/pkg/version"
|
||||
genericapirequest "k8s.io/apiserver/pkg/endpoints/request"
|
||||
genericapiserver "k8s.io/apiserver/pkg/server"
|
||||
"k8s.io/apiserver/pkg/server/options"
|
||||
serverstorage "k8s.io/apiserver/pkg/server/storage"
|
||||
etcdtesting "k8s.io/apiserver/pkg/storage/etcd/testing"
|
||||
"k8s.io/client-go/informers"
|
||||
"k8s.io/client-go/kubernetes"
|
||||
"k8s.io/client-go/kubernetes/fake"
|
||||
restclient "k8s.io/client-go/rest"
|
||||
"k8s.io/kubernetes/pkg/api/legacyscheme"
|
||||
"k8s.io/kubernetes/pkg/api/testapi"
|
||||
"k8s.io/kubernetes/pkg/apis/apps"
|
||||
"k8s.io/kubernetes/pkg/apis/autoscaling"
|
||||
"k8s.io/kubernetes/pkg/apis/batch"
|
||||
"k8s.io/kubernetes/pkg/apis/certificates"
|
||||
api "k8s.io/kubernetes/pkg/apis/core"
|
||||
"k8s.io/kubernetes/pkg/apis/extensions"
|
||||
"k8s.io/kubernetes/pkg/apis/rbac"
|
||||
kubeletclient "k8s.io/kubernetes/pkg/kubelet/client"
|
||||
"k8s.io/kubernetes/pkg/master/reconcilers"
|
||||
certificatesrest "k8s.io/kubernetes/pkg/registry/certificates/rest"
|
||||
corerest "k8s.io/kubernetes/pkg/registry/core/rest"
|
||||
"k8s.io/kubernetes/pkg/registry/registrytest"
|
||||
kubeversion "k8s.io/kubernetes/pkg/version"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
// setUp is a convience function for setting up for (most) tests.
|
||||
func setUp(t *testing.T) (*etcdtesting.EtcdTestServer, Config, informers.SharedInformerFactory, *assert.Assertions) {
|
||||
server, storageConfig := etcdtesting.NewUnsecuredEtcd3TestClientServer(t)
|
||||
|
||||
config := &Config{
|
||||
GenericConfig: genericapiserver.NewConfig(legacyscheme.Codecs),
|
||||
ExtraConfig: ExtraConfig{
|
||||
APIResourceConfigSource: DefaultAPIResourceConfigSource(),
|
||||
APIServerServicePort: 443,
|
||||
MasterCount: 1,
|
||||
EndpointReconcilerType: reconcilers.MasterCountReconcilerType,
|
||||
},
|
||||
}
|
||||
|
||||
resourceEncoding := serverstorage.NewDefaultResourceEncodingConfig(legacyscheme.Registry)
|
||||
resourceEncoding.SetVersionEncoding(api.GroupName, legacyscheme.Registry.GroupOrDie(api.GroupName).GroupVersion, schema.GroupVersion{Group: api.GroupName, Version: runtime.APIVersionInternal})
|
||||
resourceEncoding.SetVersionEncoding(autoscaling.GroupName, *testapi.Autoscaling.GroupVersion(), schema.GroupVersion{Group: autoscaling.GroupName, Version: runtime.APIVersionInternal})
|
||||
resourceEncoding.SetVersionEncoding(batch.GroupName, *testapi.Batch.GroupVersion(), schema.GroupVersion{Group: batch.GroupName, Version: runtime.APIVersionInternal})
|
||||
// FIXME (soltysh): this GroupVersionResource override should be configurable
|
||||
resourceEncoding.SetResourceEncoding(schema.GroupResource{Group: "batch", Resource: "cronjobs"}, schema.GroupVersion{Group: batch.GroupName, Version: "v1beta1"}, schema.GroupVersion{Group: batch.GroupName, Version: runtime.APIVersionInternal})
|
||||
resourceEncoding.SetVersionEncoding(apps.GroupName, *testapi.Apps.GroupVersion(), schema.GroupVersion{Group: apps.GroupName, Version: runtime.APIVersionInternal})
|
||||
resourceEncoding.SetVersionEncoding(extensions.GroupName, *testapi.Extensions.GroupVersion(), schema.GroupVersion{Group: extensions.GroupName, Version: runtime.APIVersionInternal})
|
||||
resourceEncoding.SetVersionEncoding(rbac.GroupName, *testapi.Rbac.GroupVersion(), schema.GroupVersion{Group: rbac.GroupName, Version: runtime.APIVersionInternal})
|
||||
resourceEncoding.SetVersionEncoding(certificates.GroupName, *testapi.Certificates.GroupVersion(), schema.GroupVersion{Group: certificates.GroupName, Version: runtime.APIVersionInternal})
|
||||
storageFactory := serverstorage.NewDefaultStorageFactory(*storageConfig, testapi.StorageMediaType(), legacyscheme.Codecs, resourceEncoding, DefaultAPIResourceConfigSource(), nil)
|
||||
|
||||
err := options.NewEtcdOptions(storageConfig).ApplyWithStorageFactoryTo(storageFactory, config.GenericConfig)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
kubeVersion := kubeversion.Get()
|
||||
config.GenericConfig.Version = &kubeVersion
|
||||
config.ExtraConfig.StorageFactory = storageFactory
|
||||
config.GenericConfig.LoopbackClientConfig = &restclient.Config{APIPath: "/api", ContentConfig: restclient.ContentConfig{NegotiatedSerializer: legacyscheme.Codecs}}
|
||||
config.GenericConfig.PublicAddress = net.ParseIP("192.168.10.4")
|
||||
config.GenericConfig.LegacyAPIGroupPrefixes = sets.NewString("/api")
|
||||
config.GenericConfig.RequestContextMapper = genericapirequest.NewRequestContextMapper()
|
||||
config.GenericConfig.LoopbackClientConfig = &restclient.Config{APIPath: "/api", ContentConfig: restclient.ContentConfig{NegotiatedSerializer: legacyscheme.Codecs}}
|
||||
config.GenericConfig.EnableMetrics = true
|
||||
config.ExtraConfig.EnableCoreControllers = false
|
||||
config.ExtraConfig.KubeletClientConfig = kubeletclient.KubeletClientConfig{Port: 10250}
|
||||
config.ExtraConfig.ProxyTransport = utilnet.SetTransportDefaults(&http.Transport{
|
||||
Dial: func(network, addr string) (net.Conn, error) { return nil, nil },
|
||||
TLSClientConfig: &tls.Config{},
|
||||
})
|
||||
|
||||
clientset, err := kubernetes.NewForConfig(config.GenericConfig.LoopbackClientConfig)
|
||||
if err != nil {
|
||||
t.Fatalf("unable to create client set due to %v", err)
|
||||
}
|
||||
sharedInformers := informers.NewSharedInformerFactory(clientset, config.GenericConfig.LoopbackClientConfig.Timeout)
|
||||
|
||||
return server, *config, sharedInformers, assert.New(t)
|
||||
}
|
||||
|
||||
// TestLegacyRestStorageStrategies ensures that all Storage objects which are using the generic registry Store have
|
||||
// their various strategies properly wired up. This surfaced as a bug where strategies defined Export functions, but
|
||||
// they were never used outside of unit tests because the export strategies were not assigned inside the Store.
|
||||
func TestLegacyRestStorageStrategies(t *testing.T) {
|
||||
_, etcdserver, masterCfg, _ := newMaster(t)
|
||||
defer etcdserver.Terminate(t)
|
||||
|
||||
storageProvider := corerest.LegacyRESTStorageProvider{
|
||||
StorageFactory: masterCfg.ExtraConfig.StorageFactory,
|
||||
ProxyTransport: masterCfg.ExtraConfig.ProxyTransport,
|
||||
KubeletClientConfig: masterCfg.ExtraConfig.KubeletClientConfig,
|
||||
EventTTL: masterCfg.ExtraConfig.EventTTL,
|
||||
ServiceIPRange: masterCfg.ExtraConfig.ServiceIPRange,
|
||||
ServiceNodePortRange: masterCfg.ExtraConfig.ServiceNodePortRange,
|
||||
LoopbackClientConfig: masterCfg.GenericConfig.LoopbackClientConfig,
|
||||
}
|
||||
|
||||
_, apiGroupInfo, err := storageProvider.NewLegacyRESTStorage(masterCfg.GenericConfig.RESTOptionsGetter)
|
||||
if err != nil {
|
||||
t.Errorf("failed to create legacy REST storage: %v", err)
|
||||
}
|
||||
|
||||
// Any new stores with export logic will need to be added here:
|
||||
exceptions := registrytest.StrategyExceptions{
|
||||
// Only these stores should have an export strategy defined:
|
||||
HasExportStrategy: []string{
|
||||
"secrets",
|
||||
"limitRanges",
|
||||
"nodes",
|
||||
"podTemplates",
|
||||
},
|
||||
}
|
||||
|
||||
strategyErrors := registrytest.ValidateStorageStrategies(apiGroupInfo.VersionedResourcesStorageMap["v1"], exceptions)
|
||||
for _, err := range strategyErrors {
|
||||
t.Error(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestCertificatesRestStorageStrategies(t *testing.T) {
|
||||
_, etcdserver, masterCfg, _ := newMaster(t)
|
||||
defer etcdserver.Terminate(t)
|
||||
|
||||
certStorageProvider := certificatesrest.RESTStorageProvider{}
|
||||
apiGroupInfo, _ := certStorageProvider.NewRESTStorage(masterCfg.ExtraConfig.APIResourceConfigSource, masterCfg.GenericConfig.RESTOptionsGetter)
|
||||
|
||||
exceptions := registrytest.StrategyExceptions{
|
||||
HasExportStrategy: []string{
|
||||
"certificatesigningrequests",
|
||||
},
|
||||
}
|
||||
|
||||
strategyErrors := registrytest.ValidateStorageStrategies(
|
||||
apiGroupInfo.VersionedResourcesStorageMap[certificatesapiv1beta1.SchemeGroupVersion.Version], exceptions)
|
||||
for _, err := range strategyErrors {
|
||||
t.Error(err)
|
||||
}
|
||||
}
|
||||
|
||||
func newMaster(t *testing.T) (*Master, *etcdtesting.EtcdTestServer, Config, *assert.Assertions) {
|
||||
etcdserver, config, sharedInformers, assert := setUp(t)
|
||||
|
||||
master, err := config.Complete(sharedInformers).New(genericapiserver.EmptyDelegate)
|
||||
if err != nil {
|
||||
t.Fatalf("Error in bringing up the master: %v", err)
|
||||
}
|
||||
|
||||
return master, etcdserver, config, assert
|
||||
}
|
||||
|
||||
// limitedAPIResourceConfigSource only enables the core group, the extensions group, the batch group, and the autoscaling group.
|
||||
func limitedAPIResourceConfigSource() *serverstorage.ResourceConfig {
|
||||
ret := serverstorage.NewResourceConfig()
|
||||
ret.EnableVersions(
|
||||
apiv1.SchemeGroupVersion,
|
||||
extensionsapiv1beta1.SchemeGroupVersion,
|
||||
batchapiv1.SchemeGroupVersion,
|
||||
batchapiv1beta1.SchemeGroupVersion,
|
||||
appsapiv1beta1.SchemeGroupVersion,
|
||||
autoscalingapiv1.SchemeGroupVersion,
|
||||
)
|
||||
return ret
|
||||
}
|
||||
|
||||
// newLimitedMaster only enables the core group, the extensions group, the batch group, and the autoscaling group.
|
||||
func newLimitedMaster(t *testing.T) (*Master, *etcdtesting.EtcdTestServer, Config, *assert.Assertions) {
|
||||
etcdserver, config, sharedInformers, assert := setUp(t)
|
||||
config.ExtraConfig.APIResourceConfigSource = limitedAPIResourceConfigSource()
|
||||
master, err := config.Complete(sharedInformers).New(genericapiserver.EmptyDelegate)
|
||||
if err != nil {
|
||||
t.Fatalf("Error in bringing up the master: %v", err)
|
||||
}
|
||||
|
||||
return master, etcdserver, config, assert
|
||||
}
|
||||
|
||||
// TestVersion tests /version
|
||||
func TestVersion(t *testing.T) {
|
||||
s, etcdserver, _, _ := newMaster(t)
|
||||
defer etcdserver.Terminate(t)
|
||||
|
||||
req, _ := http.NewRequest("GET", "/version", nil)
|
||||
resp := httptest.NewRecorder()
|
||||
s.GenericAPIServer.Handler.ServeHTTP(resp, req)
|
||||
if resp.Code != 200 {
|
||||
t.Fatalf("expected http 200, got: %d", resp.Code)
|
||||
}
|
||||
|
||||
var info version.Info
|
||||
err := json.NewDecoder(resp.Body).Decode(&info)
|
||||
if err != nil {
|
||||
t.Errorf("unexpected error: %v", err)
|
||||
}
|
||||
|
||||
if !reflect.DeepEqual(kubeversion.Get(), info) {
|
||||
t.Errorf("Expected %#v, Got %#v", kubeversion.Get(), info)
|
||||
}
|
||||
}
|
||||
|
||||
type fakeEndpointReconciler struct{}
|
||||
|
||||
func (*fakeEndpointReconciler) ReconcileEndpoints(serviceName string, ip net.IP, endpointPorts []api.EndpointPort, reconcilePorts bool) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func makeNodeList(nodes []string, nodeResources apiv1.NodeResources) *apiv1.NodeList {
|
||||
list := apiv1.NodeList{
|
||||
Items: make([]apiv1.Node, len(nodes)),
|
||||
}
|
||||
for i := range nodes {
|
||||
list.Items[i].Name = nodes[i]
|
||||
list.Items[i].Status.Capacity = nodeResources.Capacity
|
||||
}
|
||||
return &list
|
||||
}
|
||||
|
||||
// TestGetNodeAddresses verifies that proper results are returned
|
||||
// when requesting node addresses.
|
||||
func TestGetNodeAddresses(t *testing.T) {
|
||||
assert := assert.New(t)
|
||||
|
||||
fakeNodeClient := fake.NewSimpleClientset(makeNodeList([]string{"node1", "node2"}, apiv1.NodeResources{})).Core().Nodes()
|
||||
addressProvider := nodeAddressProvider{fakeNodeClient}
|
||||
|
||||
// Fail case (no addresses associated with nodes)
|
||||
nodes, _ := fakeNodeClient.List(metav1.ListOptions{})
|
||||
addrs, err := addressProvider.externalAddresses()
|
||||
|
||||
assert.Error(err, "addresses should have caused an error as there are no addresses.")
|
||||
assert.Equal([]string(nil), addrs)
|
||||
|
||||
// Pass case with External type IP
|
||||
nodes, _ = fakeNodeClient.List(metav1.ListOptions{})
|
||||
for index := range nodes.Items {
|
||||
nodes.Items[index].Status.Addresses = []apiv1.NodeAddress{{Type: apiv1.NodeExternalIP, Address: "127.0.0.1"}}
|
||||
fakeNodeClient.Update(&nodes.Items[index])
|
||||
}
|
||||
addrs, err = addressProvider.externalAddresses()
|
||||
assert.NoError(err, "addresses should not have returned an error.")
|
||||
assert.Equal([]string{"127.0.0.1", "127.0.0.1"}, addrs)
|
||||
}
|
||||
|
||||
func decodeResponse(resp *http.Response, obj interface{}) error {
|
||||
defer resp.Body.Close()
|
||||
|
||||
data, err := ioutil.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err := json.Unmarshal(data, obj); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Because we need to be backwards compatible with release 1.1, at endpoints
|
||||
// that exist in release 1.1, the responses should have empty APIVersion.
|
||||
func TestAPIVersionOfDiscoveryEndpoints(t *testing.T) {
|
||||
master, etcdserver, _, assert := newMaster(t)
|
||||
defer etcdserver.Terminate(t)
|
||||
|
||||
server := httptest.NewServer(genericapirequest.WithRequestContext(master.GenericAPIServer.Handler.GoRestfulContainer.ServeMux, master.GenericAPIServer.RequestContextMapper()))
|
||||
|
||||
// /api exists in release-1.1
|
||||
resp, err := http.Get(server.URL + "/api")
|
||||
if err != nil {
|
||||
t.Errorf("unexpected error: %v", err)
|
||||
}
|
||||
apiVersions := metav1.APIVersions{}
|
||||
assert.NoError(decodeResponse(resp, &apiVersions))
|
||||
assert.Equal(apiVersions.APIVersion, "")
|
||||
|
||||
// /api/v1 exists in release-1.1
|
||||
resp, err = http.Get(server.URL + "/api/v1")
|
||||
if err != nil {
|
||||
t.Errorf("unexpected error: %v", err)
|
||||
}
|
||||
resourceList := metav1.APIResourceList{}
|
||||
assert.NoError(decodeResponse(resp, &resourceList))
|
||||
assert.Equal(resourceList.APIVersion, "")
|
||||
|
||||
// /apis exists in release-1.1
|
||||
resp, err = http.Get(server.URL + "/apis")
|
||||
if err != nil {
|
||||
t.Errorf("unexpected error: %v", err)
|
||||
}
|
||||
groupList := metav1.APIGroupList{}
|
||||
assert.NoError(decodeResponse(resp, &groupList))
|
||||
assert.Equal(groupList.APIVersion, "")
|
||||
|
||||
// /apis/extensions exists in release-1.1
|
||||
resp, err = http.Get(server.URL + "/apis/extensions")
|
||||
if err != nil {
|
||||
t.Errorf("unexpected error: %v", err)
|
||||
}
|
||||
group := metav1.APIGroup{}
|
||||
assert.NoError(decodeResponse(resp, &group))
|
||||
assert.Equal(group.APIVersion, "")
|
||||
|
||||
// /apis/extensions/v1beta1 exists in release-1.1
|
||||
resp, err = http.Get(server.URL + "/apis/extensions/v1beta1")
|
||||
if err != nil {
|
||||
t.Errorf("unexpected error: %v", err)
|
||||
}
|
||||
resourceList = metav1.APIResourceList{}
|
||||
assert.NoError(decodeResponse(resp, &resourceList))
|
||||
assert.Equal(resourceList.APIVersion, "")
|
||||
|
||||
// /apis/autoscaling doesn't exist in release-1.1, so the APIVersion field
|
||||
// should be non-empty in the results returned by the server.
|
||||
resp, err = http.Get(server.URL + "/apis/autoscaling")
|
||||
if err != nil {
|
||||
t.Errorf("unexpected error: %v", err)
|
||||
}
|
||||
group = metav1.APIGroup{}
|
||||
assert.NoError(decodeResponse(resp, &group))
|
||||
assert.Equal(group.APIVersion, "v1")
|
||||
|
||||
// apis/autoscaling/v1 doesn't exist in release-1.1, so the APIVersion field
|
||||
// should be non-empty in the results returned by the server.
|
||||
|
||||
resp, err = http.Get(server.URL + "/apis/autoscaling/v1")
|
||||
if err != nil {
|
||||
t.Errorf("unexpected error: %v", err)
|
||||
}
|
||||
resourceList = metav1.APIResourceList{}
|
||||
assert.NoError(decodeResponse(resp, &resourceList))
|
||||
assert.Equal(resourceList.APIVersion, "v1")
|
||||
|
||||
}
|
||||
|
||||
func TestNoAlphaVersionsEnabledByDefault(t *testing.T) {
|
||||
config := DefaultAPIResourceConfigSource()
|
||||
for gv, gvConfig := range config.GroupVersionResourceConfigs {
|
||||
if gvConfig.Enable && strings.Contains(gv.Version, "alpha") {
|
||||
t.Errorf("Alpha API version %s enabled by default", gv.String())
|
||||
}
|
||||
}
|
||||
}
|
||||
28
vendor/k8s.io/kubernetes/pkg/master/ports/BUILD
generated
vendored
Normal file
28
vendor/k8s.io/kubernetes/pkg/master/ports/BUILD
generated
vendored
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
package(default_visibility = ["//visibility:public"])
|
||||
|
||||
load(
|
||||
"@io_bazel_rules_go//go:def.bzl",
|
||||
"go_library",
|
||||
)
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = [
|
||||
"doc.go",
|
||||
"ports.go",
|
||||
],
|
||||
importpath = "k8s.io/kubernetes/pkg/master/ports",
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "package-srcs",
|
||||
srcs = glob(["**"]),
|
||||
tags = ["automanaged"],
|
||||
visibility = ["//visibility:private"],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "all-srcs",
|
||||
srcs = [":package-srcs"],
|
||||
tags = ["automanaged"],
|
||||
)
|
||||
19
vendor/k8s.io/kubernetes/pkg/master/ports/doc.go
generated
vendored
Normal file
19
vendor/k8s.io/kubernetes/pkg/master/ports/doc.go
generated
vendored
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
/*
|
||||
Copyright 2014 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 ports defines ports used by various pieces of the kubernetes
|
||||
// infrastructure.
|
||||
package ports // import "k8s.io/kubernetes/pkg/master/ports"
|
||||
44
vendor/k8s.io/kubernetes/pkg/master/ports/ports.go
generated
vendored
Normal file
44
vendor/k8s.io/kubernetes/pkg/master/ports/ports.go
generated
vendored
Normal file
|
|
@ -0,0 +1,44 @@
|
|||
/*
|
||||
Copyright 2014 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 ports
|
||||
|
||||
const (
|
||||
// ProxyStatusPort is the default port for the proxy metrics server.
|
||||
// May be overridden by a flag at startup.
|
||||
ProxyStatusPort = 10249
|
||||
// KubeletPort is the default port for the kubelet server on each host machine.
|
||||
// May be overridden by a flag at startup.
|
||||
KubeletPort = 10250
|
||||
// SchedulerPort is the default port for the scheduler status server.
|
||||
// May be overridden by a flag at startup.
|
||||
SchedulerPort = 10251
|
||||
// ControllerManagerPort is the default port for the controller manager status server.
|
||||
// May be overridden by a flag at startup.
|
||||
ControllerManagerPort = 10252
|
||||
// CloudControllerManagerPort is the default port for the cloud controller manager server.
|
||||
// This value may be overriden by a flag at startup.
|
||||
CloudControllerManagerPort = 10253
|
||||
// KubeletReadOnlyPort exposes basic read-only services from the kubelet.
|
||||
// May be overridden by a flag at startup.
|
||||
// This is necessary for heapster to collect monitoring stats from the kubelet
|
||||
// until heapster can transition to using the SSL endpoint.
|
||||
// TODO(roberthbailey): Remove this once we have a better solution for heapster.
|
||||
KubeletReadOnlyPort = 10255
|
||||
// ProxyHealthzPort is the default port for the proxy healthz server.
|
||||
// May be overridden by a flag at startup.
|
||||
ProxyHealthzPort = 10256
|
||||
)
|
||||
54
vendor/k8s.io/kubernetes/pkg/master/services.go
generated
vendored
Normal file
54
vendor/k8s.io/kubernetes/pkg/master/services.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 master
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net"
|
||||
|
||||
"github.com/golang/glog"
|
||||
|
||||
"k8s.io/kubernetes/pkg/registry/core/service/ipallocator"
|
||||
)
|
||||
|
||||
// DefaultServiceIPRange takes a the serviceIPRange flag and returns the defaulted service ip range (if needed),
|
||||
// api server service IP, and an error
|
||||
// TODO move this out of the genericapiserver package
|
||||
func DefaultServiceIPRange(passedServiceClusterIPRange net.IPNet) (net.IPNet, net.IP, error) {
|
||||
serviceClusterIPRange := passedServiceClusterIPRange
|
||||
if passedServiceClusterIPRange.IP == nil {
|
||||
defaultNet := "10.0.0.0/24"
|
||||
glog.Infof("Network range for service cluster IPs is unspecified. Defaulting to %v.", defaultNet)
|
||||
_, defaultServiceClusterIPRange, err := net.ParseCIDR(defaultNet)
|
||||
if err != nil {
|
||||
return net.IPNet{}, net.IP{}, err
|
||||
}
|
||||
serviceClusterIPRange = *defaultServiceClusterIPRange
|
||||
}
|
||||
if size := ipallocator.RangeSize(&serviceClusterIPRange); size < 8 {
|
||||
return net.IPNet{}, net.IP{}, fmt.Errorf("The service cluster IP range must be at least %d IP addresses", 8)
|
||||
}
|
||||
|
||||
// Select the first valid IP from ServiceClusterIPRange to use as the GenericAPIServer service IP.
|
||||
apiServerServiceIP, err := ipallocator.GetIndexedIP(&serviceClusterIPRange, 1)
|
||||
if err != nil {
|
||||
return net.IPNet{}, net.IP{}, err
|
||||
}
|
||||
glog.V(4).Infof("Setting service IP to %q (read-write).", apiServerServiceIP)
|
||||
|
||||
return serviceClusterIPRange, apiServerServiceIP, nil
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue