Fresh dep ensure

This commit is contained in:
Mike Cronce
2018-11-26 13:23:56 -05:00
parent 93cb8a04d7
commit 407478ab9a
9016 changed files with 551394 additions and 279685 deletions

View File

@ -0,0 +1,74 @@
load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test")
go_library(
name = "go_default_library",
srcs = [
"config.go",
"defaults.go",
"registrations.go",
"scheme.go",
"validation.go",
],
importpath = "k8s.io/kubernetes/cmd/kubeadm/app/componentconfigs",
visibility = ["//visibility:public"],
deps = [
"//cmd/kubeadm/app/apis/kubeadm:go_default_library",
"//cmd/kubeadm/app/apis/kubeadm/v1beta1:go_default_library",
"//cmd/kubeadm/app/constants:go_default_library",
"//cmd/kubeadm/app/util:go_default_library",
"//pkg/kubelet/apis/config:go_default_library",
"//pkg/kubelet/apis/config/v1beta1:go_default_library",
"//pkg/kubelet/apis/config/validation:go_default_library",
"//pkg/proxy/apis/config:go_default_library",
"//pkg/proxy/apis/config/v1alpha1:go_default_library",
"//pkg/proxy/apis/config/validation:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/runtime:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/runtime/schema:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/runtime/serializer:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/util/runtime:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/util/validation/field:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/util/version:go_default_library",
"//staging/src/k8s.io/client-go/kubernetes:go_default_library",
"//staging/src/k8s.io/kube-proxy/config/v1alpha1:go_default_library",
"//staging/src/k8s.io/kubelet/config/v1beta1:go_default_library",
"//vendor/github.com/pkg/errors:go_default_library",
"//vendor/k8s.io/utils/pointer:go_default_library",
],
)
filegroup(
name = "package-srcs",
srcs = glob(["**"]),
tags = ["automanaged"],
visibility = ["//visibility:private"],
)
filegroup(
name = "all-srcs",
srcs = [":package-srcs"],
tags = ["automanaged"],
visibility = ["//visibility:public"],
)
go_test(
name = "go_default_test",
srcs = [
"config_test.go",
"validation_test.go",
],
embed = [":go_default_library"],
deps = [
"//cmd/kubeadm/app/apis/kubeadm:go_default_library",
"//cmd/kubeadm/app/constants:go_default_library",
"//cmd/kubeadm/app/util/apiclient:go_default_library",
"//pkg/kubelet/apis/config:go_default_library",
"//pkg/proxy/apis/config:go_default_library",
"//staging/src/k8s.io/api/core/v1:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/util/version:go_default_library",
"//staging/src/k8s.io/client-go/kubernetes:go_default_library",
"//staging/src/k8s.io/client-go/kubernetes/fake:go_default_library",
"//vendor/k8s.io/utils/pointer:go_default_library",
],
)

View File

@ -0,0 +1,82 @@
/*
Copyright 2018 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 componentconfigs
import (
"github.com/pkg/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/util/version"
clientset "k8s.io/client-go/kubernetes"
kubeadmconstants "k8s.io/kubernetes/cmd/kubeadm/app/constants"
kubeletconfig "k8s.io/kubernetes/pkg/kubelet/apis/config"
kubeproxyconfig "k8s.io/kubernetes/pkg/proxy/apis/config"
)
// GetFromKubeletConfigMap returns the pointer to the ComponentConfig API object read from the kubelet-config-version
// ConfigMap map stored in the cluster
func GetFromKubeletConfigMap(client clientset.Interface, version *version.Version) (runtime.Object, error) {
// Read the ConfigMap from the cluster based on what version the kubelet is
configMapName := kubeadmconstants.GetKubeletConfigMapName(version)
kubeletCfg, err := client.CoreV1().ConfigMaps(metav1.NamespaceSystem).Get(configMapName, metav1.GetOptions{})
if err != nil {
return nil, err
}
kubeletConfigData, ok := kubeletCfg.Data[kubeadmconstants.KubeletBaseConfigurationConfigMapKey]
if !ok {
return nil, errors.Errorf("unexpected error when reading %s ConfigMap: %s key value pair missing",
configMapName, kubeadmconstants.KubeletBaseConfigurationConfigMapKey)
}
// Decodes the kubeletConfigData into the internal component config
obj := &kubeletconfig.KubeletConfiguration{}
err = unmarshalObject(obj, []byte(kubeletConfigData))
if err != nil {
return nil, err
}
return obj, nil
}
// GetFromKubeProxyConfigMap returns the pointer to the ComponentConfig API object read from the kube-proxy
// ConfigMap map stored in the cluster
func GetFromKubeProxyConfigMap(client clientset.Interface, version *version.Version) (runtime.Object, error) {
// Read the ConfigMap from the cluster
kubeproxyCfg, err := client.CoreV1().ConfigMaps(metav1.NamespaceSystem).Get(kubeadmconstants.KubeProxyConfigMap, metav1.GetOptions{})
if err != nil {
return nil, err
}
kubeproxyConfigData, ok := kubeproxyCfg.Data[kubeadmconstants.KubeProxyConfigMapKey]
if !ok {
return nil, errors.Errorf("unexpected error when reading %s ConfigMap: %s key value pair missing",
kubeadmconstants.KubeProxyConfigMap, kubeadmconstants.KubeProxyConfigMapKey)
}
// Decodes the Config map dat into the internal component config
obj := &kubeproxyconfig.KubeProxyConfiguration{}
err = unmarshalObject(obj, []byte(kubeproxyConfigData))
if err != nil {
return nil, err
}
return obj, nil
}

View File

@ -0,0 +1,146 @@
/*
Copyright 2018 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 componentconfigs
import (
"testing"
"k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/util/version"
clientset "k8s.io/client-go/kubernetes"
clientsetfake "k8s.io/client-go/kubernetes/fake"
kubeadmconstants "k8s.io/kubernetes/cmd/kubeadm/app/constants"
"k8s.io/kubernetes/cmd/kubeadm/app/util/apiclient"
)
var cfgFiles = map[string][]byte{
"Kube-proxy_componentconfig": []byte(`
apiVersion: kubeproxy.config.k8s.io/v1alpha1
kind: KubeProxyConfiguration
`),
"Kubelet_componentconfig": []byte(`
apiVersion: kubelet.config.k8s.io/v1beta1
kind: KubeletConfiguration
`),
}
func TestGetFromConfigMap(t *testing.T) {
k8sVersion := version.MustParseGeneric("v1.12.0")
var tests = []struct {
name string
component RegistrationKind
configMap *fakeConfigMap
expectedError bool
}{
{
name: "valid kube-proxy",
component: KubeProxyConfigurationKind,
configMap: &fakeConfigMap{
name: kubeadmconstants.KubeProxyConfigMap,
data: map[string]string{
kubeadmconstants.KubeProxyConfigMapKey: string(cfgFiles["Kube-proxy_componentconfig"]),
},
},
},
{
name: "invalid kube-proxy - missing ConfigMap",
component: KubeProxyConfigurationKind,
configMap: nil,
expectedError: true,
},
{
name: "invalid kube-proxy - missing key",
component: KubeProxyConfigurationKind,
configMap: &fakeConfigMap{
name: kubeadmconstants.KubeProxyConfigMap,
data: map[string]string{},
},
expectedError: true,
},
{
name: "valid kubelet",
component: KubeletConfigurationKind,
configMap: &fakeConfigMap{
name: kubeadmconstants.GetKubeletConfigMapName(k8sVersion),
data: map[string]string{
kubeadmconstants.KubeletBaseConfigurationConfigMapKey: string(cfgFiles["Kubelet_componentconfig"]),
},
},
},
{
name: "invalid kubelet - missing ConfigMap",
component: KubeletConfigurationKind,
configMap: nil,
expectedError: true,
},
{
name: "invalid kubelet - missing key",
component: KubeletConfigurationKind,
configMap: &fakeConfigMap{
name: kubeadmconstants.GetKubeletConfigMapName(k8sVersion),
data: map[string]string{},
},
expectedError: true,
},
}
for _, rt := range tests {
t.Run(rt.name, func(t2 *testing.T) {
client := clientsetfake.NewSimpleClientset()
if rt.configMap != nil {
err := rt.configMap.create(client)
if err != nil {
t.Errorf("unexpected create ConfigMap %s", rt.configMap.name)
return
}
}
registration := Known[rt.component]
obj, err := registration.GetFromConfigMap(client, k8sVersion)
if rt.expectedError != (err != nil) {
t.Errorf("unexpected return err from GetFromConfigMap: %v", err)
return
}
if rt.expectedError {
return
}
if obj == nil {
t.Error("unexpected nil return value")
}
})
}
}
type fakeConfigMap struct {
name string
data map[string]string
}
func (c *fakeConfigMap) create(client clientset.Interface) error {
return apiclient.CreateOrUpdateConfigMap(client, &v1.ConfigMap{
ObjectMeta: metav1.ObjectMeta{
Name: c.name,
Namespace: metav1.NamespaceSystem,
},
Data: c.data,
})
}

View File

@ -0,0 +1,120 @@
/*
Copyright 2018 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 componentconfigs
import (
kubeproxyconfigv1alpha1 "k8s.io/kube-proxy/config/v1alpha1"
kubeletconfigv1beta1 "k8s.io/kubelet/config/v1beta1"
kubeadmapi "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm"
kubeadmapiv1beta1 "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm/v1beta1"
"k8s.io/kubernetes/cmd/kubeadm/app/constants"
kubeletconfig "k8s.io/kubernetes/pkg/kubelet/apis/config"
kubeproxyconfig "k8s.io/kubernetes/pkg/proxy/apis/config"
utilpointer "k8s.io/utils/pointer"
)
const (
// KubeproxyKubeConfigFileName defines the file name for the kube-proxy's kubeconfig file
KubeproxyKubeConfigFileName = "/var/lib/kube-proxy/kubeconfig.conf"
)
// DefaultKubeProxyConfiguration assigns default values for the kube-proxy ComponentConfig
func DefaultKubeProxyConfiguration(internalcfg *kubeadmapi.ClusterConfiguration) {
externalproxycfg := &kubeproxyconfigv1alpha1.KubeProxyConfiguration{}
// Do a roundtrip to the external version for defaulting
if internalcfg.ComponentConfigs.KubeProxy != nil {
Scheme.Convert(internalcfg.ComponentConfigs.KubeProxy, externalproxycfg, nil)
}
if externalproxycfg.ClusterCIDR == "" && internalcfg.Networking.PodSubnet != "" {
externalproxycfg.ClusterCIDR = internalcfg.Networking.PodSubnet
}
if externalproxycfg.ClientConnection.Kubeconfig == "" {
externalproxycfg.ClientConnection.Kubeconfig = KubeproxyKubeConfigFileName
}
// Run the rest of the kube-proxy defaulting code
Scheme.Default(externalproxycfg)
if internalcfg.ComponentConfigs.KubeProxy == nil {
internalcfg.ComponentConfigs.KubeProxy = &kubeproxyconfig.KubeProxyConfiguration{}
}
// TODO: Figure out how to handle errors in defaulting code
// Go back to the internal version
Scheme.Convert(externalproxycfg, internalcfg.ComponentConfigs.KubeProxy, nil)
}
// DefaultKubeletConfiguration assigns default values for the kubelet ComponentConfig
func DefaultKubeletConfiguration(internalcfg *kubeadmapi.ClusterConfiguration) {
externalkubeletcfg := &kubeletconfigv1beta1.KubeletConfiguration{}
// Do a roundtrip to the external version for defaulting
if internalcfg.ComponentConfigs.Kubelet != nil {
Scheme.Convert(internalcfg.ComponentConfigs.Kubelet, externalkubeletcfg, nil)
}
if externalkubeletcfg.StaticPodPath == "" {
externalkubeletcfg.StaticPodPath = kubeadmapiv1beta1.DefaultManifestsDir
}
if externalkubeletcfg.ClusterDNS == nil {
dnsIP, err := constants.GetDNSIP(internalcfg.Networking.ServiceSubnet)
if err != nil {
externalkubeletcfg.ClusterDNS = []string{kubeadmapiv1beta1.DefaultClusterDNSIP}
} else {
externalkubeletcfg.ClusterDNS = []string{dnsIP.String()}
}
}
if externalkubeletcfg.ClusterDomain == "" {
externalkubeletcfg.ClusterDomain = internalcfg.Networking.DNSDomain
}
// Enforce security-related kubelet options
// Require all clients to the kubelet API to have client certs signed by the cluster CA
externalkubeletcfg.Authentication.X509.ClientCAFile = kubeadmapiv1beta1.DefaultCACertPath
externalkubeletcfg.Authentication.Anonymous.Enabled = utilpointer.BoolPtr(false)
// On every client request to the kubelet API, execute a webhook (SubjectAccessReview request) to the API server
// and ask it whether the client is authorized to access the kubelet API
externalkubeletcfg.Authorization.Mode = kubeletconfigv1beta1.KubeletAuthorizationModeWebhook
// Let clients using other authentication methods like ServiceAccount tokens also access the kubelet API
externalkubeletcfg.Authentication.Webhook.Enabled = utilpointer.BoolPtr(true)
// Disable the readonly port of the kubelet, in order to not expose unnecessary information
externalkubeletcfg.ReadOnlyPort = 0
// Enables client certificate rotation for the kubelet
externalkubeletcfg.RotateCertificates = true
// Serve a /healthz webserver on localhost:10248 that kubeadm can talk to
externalkubeletcfg.HealthzBindAddress = "127.0.0.1"
externalkubeletcfg.HealthzPort = utilpointer.Int32Ptr(constants.KubeletHealthzPort)
Scheme.Default(externalkubeletcfg)
if internalcfg.ComponentConfigs.Kubelet == nil {
internalcfg.ComponentConfigs.Kubelet = &kubeletconfig.KubeletConfiguration{}
}
// TODO: Figure out how to handle errors in defaulting code
// Go back to the internal version
Scheme.Convert(externalkubeletcfg, internalcfg.ComponentConfigs.Kubelet, nil)
}

View File

@ -0,0 +1,165 @@
/*
Copyright 2018 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 componentconfigs
import (
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/apimachinery/pkg/util/validation/field"
"k8s.io/apimachinery/pkg/util/version"
clientset "k8s.io/client-go/kubernetes"
kubeproxyconfigv1alpha1 "k8s.io/kube-proxy/config/v1alpha1"
kubeletconfigv1beta1 "k8s.io/kubelet/config/v1beta1"
kubeadmapi "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm"
kubeadmutil "k8s.io/kubernetes/cmd/kubeadm/app/util"
kubeletconfig "k8s.io/kubernetes/pkg/kubelet/apis/config"
kubeletconfigv1beta1scheme "k8s.io/kubernetes/pkg/kubelet/apis/config/v1beta1"
kubeproxyconfig "k8s.io/kubernetes/pkg/proxy/apis/config"
kubeproxyconfigv1alpha1scheme "k8s.io/kubernetes/pkg/proxy/apis/config/v1alpha1"
)
// AddToSchemeFunc is a function that adds known types and API GroupVersions to a scheme
type AddToSchemeFunc func(*runtime.Scheme) error
// Registration is an object for registering a Kubernetes ComponentConfig type to be recognized and handled by kubeadm
type Registration struct {
// MarshalGroupVersion is the preferred external API version to use when marshalling the ComponentConfig
MarshalGroupVersion schema.GroupVersion
// AddToSchemeFuncs are a set of functions that register APIs to the scheme
AddToSchemeFuncs []AddToSchemeFunc
// DefaulterFunc is a function that based on the internal kubeadm configuration defaults the ComponentConfig struct
DefaulterFunc func(*kubeadmapi.ClusterConfiguration)
// ValidateFunc is a function that should validate the ComponentConfig type embedded in the internal kubeadm config struct
ValidateFunc func(*kubeadmapi.ClusterConfiguration, *field.Path) field.ErrorList
// EmptyValue holds a pointer to an empty struct of the internal ComponentConfig type
EmptyValue runtime.Object
// GetFromInternalConfig returns the pointer to the ComponentConfig API object from the internal kubeadm config struct
GetFromInternalConfig func(*kubeadmapi.ClusterConfiguration) (runtime.Object, bool)
// SetToInternalConfig sets the pointer to a ComponentConfig API object embedded in the internal kubeadm config struct
SetToInternalConfig func(runtime.Object, *kubeadmapi.ClusterConfiguration) bool
// GetFromConfigMap returns the pointer to the ComponentConfig API object read from the config map stored in the cluster
GetFromConfigMap func(clientset.Interface, *version.Version) (runtime.Object, error)
}
// Marshal marshals obj to bytes for the current Registration
func (r Registration) Marshal(obj runtime.Object) ([]byte, error) {
return kubeadmutil.MarshalToYamlForCodecs(obj, r.MarshalGroupVersion, Codecs)
}
// Unmarshal unmarshals the bytes to a runtime.Object using the Codecs registered in this Scheme
func (r Registration) Unmarshal(fileContent []byte) (runtime.Object, error) {
// Do a deepcopy of the empty value so we don't mutate it, which could lead to strange errors
obj := r.EmptyValue.DeepCopyObject()
// Decode the file content into obj which is a pointer to an empty struct of the internal ComponentConfig
if err := unmarshalObject(obj, fileContent); err != nil {
return nil, err
}
return obj, nil
}
func unmarshalObject(obj runtime.Object, fileContent []byte) error {
// Decode the file content using the componentconfig Codecs that knows about all APIs
if err := runtime.DecodeInto(Codecs.UniversalDecoder(), fileContent, obj); err != nil {
return err
}
return nil
}
const (
// KubeletConfigurationKind is the kind for the kubelet ComponentConfig
KubeletConfigurationKind RegistrationKind = "KubeletConfiguration"
// KubeProxyConfigurationKind is the kind for the kubelet ComponentConfig
KubeProxyConfigurationKind RegistrationKind = "KubeProxyConfiguration"
)
// RegistrationKind is a string type to ensure not any string can be a key in the Registrations map
type RegistrationKind string
// Registrations holds a set of ComponentConfig Registration objects, where the map key is the kind
type Registrations map[RegistrationKind]Registration
// Known contains the known ComponentConfig registrations to kubeadm
var Known Registrations = map[RegistrationKind]Registration{
KubeProxyConfigurationKind: {
// TODO: When a beta version of the kube-proxy ComponentConfig API is available, start using it
MarshalGroupVersion: kubeproxyconfigv1alpha1.SchemeGroupVersion,
// AddToSchemeFuncs must use v1alpha1scheme defined in k8s.io/kubernetes, because the schema defined in k8s.io/kube-proxy doesn't have defaulting functions
AddToSchemeFuncs: []AddToSchemeFunc{kubeproxyconfig.AddToScheme, kubeproxyconfigv1alpha1scheme.AddToScheme},
DefaulterFunc: DefaultKubeProxyConfiguration,
ValidateFunc: ValidateKubeProxyConfiguration,
EmptyValue: &kubeproxyconfig.KubeProxyConfiguration{},
GetFromInternalConfig: func(cfg *kubeadmapi.ClusterConfiguration) (runtime.Object, bool) {
return cfg.ComponentConfigs.KubeProxy, cfg.ComponentConfigs.KubeProxy != nil
},
SetToInternalConfig: func(obj runtime.Object, cfg *kubeadmapi.ClusterConfiguration) bool {
kubeproxyConfig, ok := obj.(*kubeproxyconfig.KubeProxyConfiguration)
if ok {
cfg.ComponentConfigs.KubeProxy = kubeproxyConfig
}
return ok
},
GetFromConfigMap: GetFromKubeProxyConfigMap,
},
KubeletConfigurationKind: {
MarshalGroupVersion: kubeletconfigv1beta1.SchemeGroupVersion,
// PAddToSchemeFuncs must use v1alpha1scheme defined in k8s.io/kubernetes, because the schema defined in k8s.io/kubelet doesn't have defaulting functions
AddToSchemeFuncs: []AddToSchemeFunc{kubeletconfig.AddToScheme, kubeletconfigv1beta1scheme.AddToScheme},
DefaulterFunc: DefaultKubeletConfiguration,
ValidateFunc: ValidateKubeletConfiguration,
EmptyValue: &kubeletconfig.KubeletConfiguration{},
GetFromInternalConfig: func(cfg *kubeadmapi.ClusterConfiguration) (runtime.Object, bool) {
return cfg.ComponentConfigs.Kubelet, cfg.ComponentConfigs.Kubelet != nil
},
SetToInternalConfig: func(obj runtime.Object, cfg *kubeadmapi.ClusterConfiguration) bool {
kubeletConfig, ok := obj.(*kubeletconfig.KubeletConfiguration)
if ok {
cfg.ComponentConfigs.Kubelet = kubeletConfig
}
return ok
},
GetFromConfigMap: GetFromKubeletConfigMap,
},
}
// AddToScheme adds all the known ComponentConfig API types referenced in the Registrations object to the scheme
func (rs *Registrations) AddToScheme(scheme *runtime.Scheme) error {
for _, registration := range *rs {
for _, addToSchemeFunc := range registration.AddToSchemeFuncs {
if err := addToSchemeFunc(scheme); err != nil {
return err
}
}
}
return nil
}
// Default applies to the ComponentConfig defaults to the internal kubeadm API type
func (rs *Registrations) Default(internalcfg *kubeadmapi.ClusterConfiguration) {
for _, registration := range *rs {
registration.DefaulterFunc(internalcfg)
}
}
// Validate validates the ComponentConfig parts of the internal kubeadm API type
func (rs *Registrations) Validate(internalcfg *kubeadmapi.ClusterConfiguration) field.ErrorList {
allErrs := field.ErrorList{}
for kind, registration := range *rs {
allErrs = append(allErrs, registration.ValidateFunc(internalcfg, field.NewPath(string(kind)))...)
}
return allErrs
}

View File

@ -0,0 +1,41 @@
/*
Copyright 2018 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 componentconfigs
import (
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/apimachinery/pkg/runtime/serializer"
utilruntime "k8s.io/apimachinery/pkg/util/runtime"
)
// Scheme is the runtime.Scheme to which all supported kubeadm ComponentConfig API types are registered.
var Scheme = runtime.NewScheme()
// Codecs provides access to encoding and decoding for the scheme.
var Codecs = serializer.NewCodecFactory(Scheme)
func init() {
metav1.AddToGroupVersion(Scheme, schema.GroupVersion{Version: "v1"})
AddToScheme(Scheme)
}
// AddToScheme builds the kubeadm ComponentConfig scheme using all known ComponentConfig versions.
func AddToScheme(scheme *runtime.Scheme) {
utilruntime.Must(Known.AddToScheme(scheme))
}

View File

@ -0,0 +1,46 @@
/*
Copyright 2018 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 componentconfigs
import (
"k8s.io/apimachinery/pkg/util/validation/field"
kubeadmapi "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm"
kubeletvalidation "k8s.io/kubernetes/pkg/kubelet/apis/config/validation"
proxyvalidation "k8s.io/kubernetes/pkg/proxy/apis/config/validation"
)
// ValidateKubeProxyConfiguration validates proxy configuration and collects all encountered errors
func ValidateKubeProxyConfiguration(internalcfg *kubeadmapi.ClusterConfiguration, _ *field.Path) field.ErrorList {
allErrs := field.ErrorList{}
if internalcfg.ComponentConfigs.KubeProxy == nil {
return allErrs
}
return proxyvalidation.Validate(internalcfg.ComponentConfigs.KubeProxy)
}
// ValidateKubeletConfiguration validates kubelet configuration and collects all encountered errors
func ValidateKubeletConfiguration(internalcfg *kubeadmapi.ClusterConfiguration, fldPath *field.Path) field.ErrorList {
allErrs := field.ErrorList{}
if internalcfg.ComponentConfigs.Kubelet == nil {
return allErrs
}
if err := kubeletvalidation.ValidateKubeletConfiguration(internalcfg.ComponentConfigs.Kubelet); err != nil {
allErrs = append(allErrs, field.Invalid(fldPath, "", err.Error()))
}
return allErrs
}

View File

@ -0,0 +1,353 @@
/*
Copyright 2018 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 componentconfigs
import (
"strings"
"testing"
"time"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm"
kubeadmconstants "k8s.io/kubernetes/cmd/kubeadm/app/constants"
kubeletconfig "k8s.io/kubernetes/pkg/kubelet/apis/config"
kubeproxyconfig "k8s.io/kubernetes/pkg/proxy/apis/config"
utilpointer "k8s.io/utils/pointer"
)
func TestValidateKubeProxyConfiguration(t *testing.T) {
var tests = []struct {
clusterConfig *kubeadm.ClusterConfiguration
msg string
expectErr bool
}{
{
clusterConfig: &kubeadm.ClusterConfiguration{
ComponentConfigs: kubeadm.ComponentConfigs{
KubeProxy: &kubeproxyconfig.KubeProxyConfiguration{
BindAddress: "192.168.59.103",
HealthzBindAddress: "0.0.0.0:10256",
MetricsBindAddress: "127.0.0.1:10249",
ClusterCIDR: "192.168.59.0/24",
UDPIdleTimeout: metav1.Duration{Duration: 1 * time.Second},
ConfigSyncPeriod: metav1.Duration{Duration: 1 * time.Second},
IPTables: kubeproxyconfig.KubeProxyIPTablesConfiguration{
MasqueradeAll: true,
SyncPeriod: metav1.Duration{Duration: 5 * time.Second},
MinSyncPeriod: metav1.Duration{Duration: 2 * time.Second},
},
IPVS: kubeproxyconfig.KubeProxyIPVSConfiguration{
SyncPeriod: metav1.Duration{Duration: 10 * time.Second},
MinSyncPeriod: metav1.Duration{Duration: 5 * time.Second},
},
Conntrack: kubeproxyconfig.KubeProxyConntrackConfiguration{
Max: utilpointer.Int32Ptr(2),
MaxPerCore: utilpointer.Int32Ptr(1),
Min: utilpointer.Int32Ptr(1),
TCPEstablishedTimeout: &metav1.Duration{Duration: 5 * time.Second},
TCPCloseWaitTimeout: &metav1.Duration{Duration: 5 * time.Second},
},
},
},
},
expectErr: false,
},
{
clusterConfig: &kubeadm.ClusterConfiguration{
ComponentConfigs: kubeadm.ComponentConfigs{
KubeProxy: &kubeproxyconfig.KubeProxyConfiguration{
// only BindAddress is invalid
BindAddress: "10.10.12.11:2000",
HealthzBindAddress: "0.0.0.0:10256",
MetricsBindAddress: "127.0.0.1:10249",
ClusterCIDR: "192.168.59.0/24",
UDPIdleTimeout: metav1.Duration{Duration: 1 * time.Second},
ConfigSyncPeriod: metav1.Duration{Duration: 1 * time.Second},
IPTables: kubeproxyconfig.KubeProxyIPTablesConfiguration{
MasqueradeAll: true,
SyncPeriod: metav1.Duration{Duration: 5 * time.Second},
MinSyncPeriod: metav1.Duration{Duration: 2 * time.Second},
},
IPVS: kubeproxyconfig.KubeProxyIPVSConfiguration{
SyncPeriod: metav1.Duration{Duration: 10 * time.Second},
MinSyncPeriod: metav1.Duration{Duration: 5 * time.Second},
},
Conntrack: kubeproxyconfig.KubeProxyConntrackConfiguration{
Max: utilpointer.Int32Ptr(2),
MaxPerCore: utilpointer.Int32Ptr(1),
Min: utilpointer.Int32Ptr(1),
TCPEstablishedTimeout: &metav1.Duration{Duration: 5 * time.Second},
TCPCloseWaitTimeout: &metav1.Duration{Duration: 5 * time.Second},
},
},
},
},
msg: "not a valid textual representation of an IP address",
expectErr: true,
},
{
clusterConfig: &kubeadm.ClusterConfiguration{
ComponentConfigs: kubeadm.ComponentConfigs{
KubeProxy: &kubeproxyconfig.KubeProxyConfiguration{
BindAddress: "10.10.12.11",
// only HealthzBindAddress is invalid
HealthzBindAddress: "0.0.0.0",
MetricsBindAddress: "127.0.0.1:10249",
ClusterCIDR: "192.168.59.0/24",
UDPIdleTimeout: metav1.Duration{Duration: 1 * time.Second},
ConfigSyncPeriod: metav1.Duration{Duration: 1 * time.Second},
IPTables: kubeproxyconfig.KubeProxyIPTablesConfiguration{
MasqueradeAll: true,
SyncPeriod: metav1.Duration{Duration: 5 * time.Second},
MinSyncPeriod: metav1.Duration{Duration: 2 * time.Second},
},
IPVS: kubeproxyconfig.KubeProxyIPVSConfiguration{
SyncPeriod: metav1.Duration{Duration: 10 * time.Second},
MinSyncPeriod: metav1.Duration{Duration: 5 * time.Second},
},
Conntrack: kubeproxyconfig.KubeProxyConntrackConfiguration{
Max: utilpointer.Int32Ptr(2),
MaxPerCore: utilpointer.Int32Ptr(1),
Min: utilpointer.Int32Ptr(1),
TCPEstablishedTimeout: &metav1.Duration{Duration: 5 * time.Second},
TCPCloseWaitTimeout: &metav1.Duration{Duration: 5 * time.Second},
},
},
},
},
msg: "must be IP:port",
expectErr: true,
},
{
clusterConfig: &kubeadm.ClusterConfiguration{
ComponentConfigs: kubeadm.ComponentConfigs{
KubeProxy: &kubeproxyconfig.KubeProxyConfiguration{
BindAddress: "10.10.12.11",
HealthzBindAddress: "0.0.0.0:12345",
// only MetricsBindAddress is invalid
MetricsBindAddress: "127.0.0.1",
ClusterCIDR: "192.168.59.0/24",
UDPIdleTimeout: metav1.Duration{Duration: 1 * time.Second},
ConfigSyncPeriod: metav1.Duration{Duration: 1 * time.Second},
IPTables: kubeproxyconfig.KubeProxyIPTablesConfiguration{
MasqueradeAll: true,
SyncPeriod: metav1.Duration{Duration: 5 * time.Second},
MinSyncPeriod: metav1.Duration{Duration: 2 * time.Second},
},
IPVS: kubeproxyconfig.KubeProxyIPVSConfiguration{
SyncPeriod: metav1.Duration{Duration: 10 * time.Second},
MinSyncPeriod: metav1.Duration{Duration: 5 * time.Second},
},
Conntrack: kubeproxyconfig.KubeProxyConntrackConfiguration{
Max: utilpointer.Int32Ptr(2),
MaxPerCore: utilpointer.Int32Ptr(1),
Min: utilpointer.Int32Ptr(1),
TCPEstablishedTimeout: &metav1.Duration{Duration: 5 * time.Second},
TCPCloseWaitTimeout: &metav1.Duration{Duration: 5 * time.Second},
},
},
},
},
msg: "must be IP:port",
expectErr: true,
},
{
clusterConfig: &kubeadm.ClusterConfiguration{
ComponentConfigs: kubeadm.ComponentConfigs{
KubeProxy: &kubeproxyconfig.KubeProxyConfiguration{
BindAddress: "10.10.12.11",
HealthzBindAddress: "0.0.0.0:12345",
MetricsBindAddress: "127.0.0.1:10249",
// only ClusterCIDR is invalid
ClusterCIDR: "192.168.59.0",
UDPIdleTimeout: metav1.Duration{Duration: 1 * time.Second},
ConfigSyncPeriod: metav1.Duration{Duration: 1 * time.Second},
IPTables: kubeproxyconfig.KubeProxyIPTablesConfiguration{
MasqueradeAll: true,
SyncPeriod: metav1.Duration{Duration: 5 * time.Second},
MinSyncPeriod: metav1.Duration{Duration: 2 * time.Second},
},
IPVS: kubeproxyconfig.KubeProxyIPVSConfiguration{
SyncPeriod: metav1.Duration{Duration: 10 * time.Second},
MinSyncPeriod: metav1.Duration{Duration: 5 * time.Second},
},
Conntrack: kubeproxyconfig.KubeProxyConntrackConfiguration{
Max: utilpointer.Int32Ptr(2),
MaxPerCore: utilpointer.Int32Ptr(1),
Min: utilpointer.Int32Ptr(1),
TCPEstablishedTimeout: &metav1.Duration{Duration: 5 * time.Second},
TCPCloseWaitTimeout: &metav1.Duration{Duration: 5 * time.Second},
},
},
},
},
msg: "must be a valid CIDR block (e.g. 10.100.0.0/16)",
expectErr: true,
},
{
clusterConfig: &kubeadm.ClusterConfiguration{
ComponentConfigs: kubeadm.ComponentConfigs{
KubeProxy: &kubeproxyconfig.KubeProxyConfiguration{
BindAddress: "10.10.12.11",
HealthzBindAddress: "0.0.0.0:12345",
MetricsBindAddress: "127.0.0.1:10249",
ClusterCIDR: "192.168.59.0/24",
// only UDPIdleTimeout is invalid
UDPIdleTimeout: metav1.Duration{Duration: -1 * time.Second},
ConfigSyncPeriod: metav1.Duration{Duration: 1 * time.Second},
IPTables: kubeproxyconfig.KubeProxyIPTablesConfiguration{
MasqueradeAll: true,
SyncPeriod: metav1.Duration{Duration: 5 * time.Second},
MinSyncPeriod: metav1.Duration{Duration: 2 * time.Second},
},
IPVS: kubeproxyconfig.KubeProxyIPVSConfiguration{
SyncPeriod: metav1.Duration{Duration: 10 * time.Second},
MinSyncPeriod: metav1.Duration{Duration: 5 * time.Second},
},
Conntrack: kubeproxyconfig.KubeProxyConntrackConfiguration{
Max: utilpointer.Int32Ptr(2),
MaxPerCore: utilpointer.Int32Ptr(1),
Min: utilpointer.Int32Ptr(1),
TCPEstablishedTimeout: &metav1.Duration{Duration: 5 * time.Second},
TCPCloseWaitTimeout: &metav1.Duration{Duration: 5 * time.Second},
},
},
},
},
msg: "must be greater than 0",
expectErr: true,
},
{
clusterConfig: &kubeadm.ClusterConfiguration{
ComponentConfigs: kubeadm.ComponentConfigs{
KubeProxy: &kubeproxyconfig.KubeProxyConfiguration{
BindAddress: "10.10.12.11",
HealthzBindAddress: "0.0.0.0:12345",
MetricsBindAddress: "127.0.0.1:10249",
ClusterCIDR: "192.168.59.0/24",
UDPIdleTimeout: metav1.Duration{Duration: 1 * time.Second},
// only ConfigSyncPeriod is invalid
ConfigSyncPeriod: metav1.Duration{Duration: -1 * time.Second},
IPTables: kubeproxyconfig.KubeProxyIPTablesConfiguration{
MasqueradeAll: true,
SyncPeriod: metav1.Duration{Duration: 5 * time.Second},
MinSyncPeriod: metav1.Duration{Duration: 2 * time.Second},
},
IPVS: kubeproxyconfig.KubeProxyIPVSConfiguration{
SyncPeriod: metav1.Duration{Duration: 10 * time.Second},
MinSyncPeriod: metav1.Duration{Duration: 5 * time.Second},
},
Conntrack: kubeproxyconfig.KubeProxyConntrackConfiguration{
Max: utilpointer.Int32Ptr(2),
MaxPerCore: utilpointer.Int32Ptr(1),
Min: utilpointer.Int32Ptr(1),
TCPEstablishedTimeout: &metav1.Duration{Duration: 5 * time.Second},
TCPCloseWaitTimeout: &metav1.Duration{Duration: 5 * time.Second},
},
},
},
},
msg: "must be greater than 0",
expectErr: true,
},
}
for i, rt := range tests {
err := ValidateKubeProxyConfiguration(rt.clusterConfig, nil).ToAggregate()
if (err != nil) != rt.expectErr {
t.Errorf("%d failed ValidateKubeProxyConfiguration: expected error %t, got error %t", i, rt.expectErr, err != nil)
}
if err != nil && !strings.Contains(err.Error(), rt.msg) {
t.Errorf("%d failed ValidateKubeProxyConfiguration: unexpected error: %v, expected: %s", i, err, rt.msg)
}
}
}
func TestValidateKubeletConfiguration(t *testing.T) {
var tests = []struct {
clusterConfig *kubeadm.ClusterConfiguration
expectErr bool
}{
{
clusterConfig: &kubeadm.ClusterConfiguration{
ComponentConfigs: kubeadm.ComponentConfigs{
Kubelet: &kubeletconfig.KubeletConfiguration{
CgroupsPerQOS: true,
EnforceNodeAllocatable: []string{"pods", "system-reserved", "kube-reserved"},
SystemCgroups: "",
CgroupRoot: "",
EventBurst: 10,
EventRecordQPS: 5,
HealthzPort: kubeadmconstants.KubeletHealthzPort,
ImageGCHighThresholdPercent: 85,
ImageGCLowThresholdPercent: 80,
IPTablesDropBit: 15,
IPTablesMasqueradeBit: 14,
KubeAPIBurst: 10,
KubeAPIQPS: 5,
MaxOpenFiles: 1000000,
MaxPods: 110,
OOMScoreAdj: -999,
PodsPerCore: 100,
Port: 65535,
ReadOnlyPort: 0,
RegistryBurst: 10,
RegistryPullQPS: 5,
HairpinMode: "promiscuous-bridge",
NodeLeaseDurationSeconds: 40,
},
},
},
expectErr: false,
},
{
clusterConfig: &kubeadm.ClusterConfiguration{
ComponentConfigs: kubeadm.ComponentConfigs{
Kubelet: &kubeletconfig.KubeletConfiguration{
CgroupsPerQOS: false,
EnforceNodeAllocatable: []string{"pods", "system-reserved", "kube-reserved", "illegal-key"},
SystemCgroups: "/",
CgroupRoot: "",
EventBurst: -10,
EventRecordQPS: -10,
HealthzPort: -10,
ImageGCHighThresholdPercent: 101,
ImageGCLowThresholdPercent: 101,
IPTablesDropBit: -10,
IPTablesMasqueradeBit: -10,
KubeAPIBurst: -10,
KubeAPIQPS: -10,
MaxOpenFiles: -10,
MaxPods: -10,
OOMScoreAdj: -1001,
PodsPerCore: -10,
Port: 0,
ReadOnlyPort: -10,
RegistryBurst: -10,
RegistryPullQPS: -10,
},
},
},
expectErr: true,
},
}
for i, rt := range tests {
err := ValidateKubeletConfiguration(rt.clusterConfig, nil).ToAggregate()
if (err != nil) != rt.expectErr {
t.Errorf("%d failed ValidateKubeletConfiguration: expected error %t, got error %t", i, rt.expectErr, err != nil)
}
}
}