From e6a98688d0a3a186a611152c3d36024350a3ae3c Mon Sep 17 00:00:00 2001 From: Jamie Hannaford Date: Fri, 14 Jul 2017 16:24:08 +0200 Subject: [PATCH] Add --feature-gate flags to kubeadm --- cmd/kubeadm/app/apis/kubeadm/fuzzer/fuzzer.go | 1 + cmd/kubeadm/app/apis/kubeadm/types.go | 3 + .../app/apis/kubeadm/v1alpha1/types.go | 3 + .../kubeadm/v1alpha1/zz_generated.deepcopy.go | 7 +++ cmd/kubeadm/app/apis/kubeadm/validation/BUILD | 1 + .../app/apis/kubeadm/validation/validation.go | 17 ++++++ .../kubeadm/validation/validation_test.go | 24 ++++++++ .../app/apis/kubeadm/zz_generated.deepcopy.go | 7 +++ cmd/kubeadm/app/cmd/BUILD | 1 + cmd/kubeadm/app/cmd/features/BUILD | 28 +++++++++ cmd/kubeadm/app/cmd/features/features.go | 58 +++++++++++++++++++ 11 files changed, 150 insertions(+) create mode 100644 cmd/kubeadm/app/cmd/features/BUILD create mode 100644 cmd/kubeadm/app/cmd/features/features.go diff --git a/cmd/kubeadm/app/apis/kubeadm/fuzzer/fuzzer.go b/cmd/kubeadm/app/apis/kubeadm/fuzzer/fuzzer.go index c1293057a3f..5dedda4e4b5 100644 --- a/cmd/kubeadm/app/apis/kubeadm/fuzzer/fuzzer.go +++ b/cmd/kubeadm/app/apis/kubeadm/fuzzer/fuzzer.go @@ -41,6 +41,7 @@ func Funcs(codecs runtimeserializer.CodecFactory) []interface{} { obj.Etcd.DataDir = "foo" obj.ImageRepository = "foo" obj.UnifiedControlPlaneImage = "foo" + obj.FeatureFlags = map[string]bool{} }, func(obj *kubeadm.NodeConfiguration, c fuzz.Continue) { c.FuzzNoCustom(obj) diff --git a/cmd/kubeadm/app/apis/kubeadm/types.go b/cmd/kubeadm/app/apis/kubeadm/types.go index e8d6cf4460c..8968ff77742 100644 --- a/cmd/kubeadm/app/apis/kubeadm/types.go +++ b/cmd/kubeadm/app/apis/kubeadm/types.go @@ -56,6 +56,9 @@ type MasterConfiguration struct { ImageRepository string // UnifiedControlPlaneImage specifies if a specific container image should be used for all control plane components UnifiedControlPlaneImage string + + // FeatureFlags enabled by the user + FeatureFlags map[string]bool } type API struct { diff --git a/cmd/kubeadm/app/apis/kubeadm/v1alpha1/types.go b/cmd/kubeadm/app/apis/kubeadm/v1alpha1/types.go index 51a6e195228..ca2b698f152 100644 --- a/cmd/kubeadm/app/apis/kubeadm/v1alpha1/types.go +++ b/cmd/kubeadm/app/apis/kubeadm/v1alpha1/types.go @@ -56,6 +56,9 @@ type MasterConfiguration struct { ImageRepository string `json:"imageRepository"` // UnifiedControlPlaneImage specifies if a specific container image should be used for all control plane components UnifiedControlPlaneImage string `json:"unifiedControlPlaneImage"` + + // FeatureFlags enabled by the user + FeatureFlags map[string]bool `json:"featureFlags"` } type API struct { diff --git a/cmd/kubeadm/app/apis/kubeadm/v1alpha1/zz_generated.deepcopy.go b/cmd/kubeadm/app/apis/kubeadm/v1alpha1/zz_generated.deepcopy.go index 64666a265a8..bc7fc95a988 100644 --- a/cmd/kubeadm/app/apis/kubeadm/v1alpha1/zz_generated.deepcopy.go +++ b/cmd/kubeadm/app/apis/kubeadm/v1alpha1/zz_generated.deepcopy.go @@ -138,6 +138,13 @@ func (in *MasterConfiguration) DeepCopyInto(out *MasterConfiguration) { *out = make([]string, len(*in)) copy(*out, *in) } + if in.FeatureFlags != nil { + in, out := &in.FeatureFlags, &out.FeatureFlags + *out = make(map[string]bool, len(*in)) + for key, val := range *in { + (*out)[key] = val + } + } return } diff --git a/cmd/kubeadm/app/apis/kubeadm/validation/BUILD b/cmd/kubeadm/app/apis/kubeadm/validation/BUILD index 797d7a7daed..f9b9adf17bb 100644 --- a/cmd/kubeadm/app/apis/kubeadm/validation/BUILD +++ b/cmd/kubeadm/app/apis/kubeadm/validation/BUILD @@ -26,6 +26,7 @@ go_library( tags = ["automanaged"], deps = [ "//cmd/kubeadm/app/apis/kubeadm:go_default_library", + "//cmd/kubeadm/app/cmd/features:go_default_library", "//cmd/kubeadm/app/constants:go_default_library", "//cmd/kubeadm/app/util/token:go_default_library", "//pkg/api/validation:go_default_library", diff --git a/cmd/kubeadm/app/apis/kubeadm/validation/validation.go b/cmd/kubeadm/app/apis/kubeadm/validation/validation.go index 88def18d610..3c19c02d3ec 100644 --- a/cmd/kubeadm/app/apis/kubeadm/validation/validation.go +++ b/cmd/kubeadm/app/apis/kubeadm/validation/validation.go @@ -29,6 +29,7 @@ import ( "k8s.io/apimachinery/pkg/util/validation" "k8s.io/apimachinery/pkg/util/validation/field" "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm" + "k8s.io/kubernetes/cmd/kubeadm/app/cmd/features" "k8s.io/kubernetes/cmd/kubeadm/app/constants" tokenutil "k8s.io/kubernetes/cmd/kubeadm/app/util/token" apivalidation "k8s.io/kubernetes/pkg/api/validation" @@ -66,6 +67,7 @@ func ValidateMasterConfiguration(c *kubeadm.MasterConfiguration) field.ErrorList allErrs = append(allErrs, ValidateAbsolutePath(c.CertificatesDir, field.NewPath("certificates-dir"))...) allErrs = append(allErrs, ValidateNodeName(c.NodeName, field.NewPath("node-name"))...) allErrs = append(allErrs, ValidateToken(c.Token, field.NewPath("token"))...) + allErrs = append(allErrs, ValidateFeatureFlags(c.FeatureFlags, field.NewPath("feature-flags"))...) return allErrs } @@ -281,3 +283,18 @@ func ValidateMixedArguments(flag *pflag.FlagSet) error { } return nil } + +func ValidateFeatureFlags(featureFlags map[string]bool, fldPath *field.Path) field.ErrorList { + allErrs := field.ErrorList{} + validFeatures := features.Keys(features.InitFeatureGates) + + // check valid feature names are provided + for k := range featureFlags { + if !features.Supports(features.InitFeatureGates, k) { + allErrs = append(allErrs, field.Invalid(fldPath, featureFlags, + fmt.Sprintf("%s is not a valid feature name. Valid features are: %s", k, validFeatures))) + } + } + + return allErrs +} diff --git a/cmd/kubeadm/app/apis/kubeadm/validation/validation_test.go b/cmd/kubeadm/app/apis/kubeadm/validation/validation_test.go index 1d62d53c102..fb55372eece 100644 --- a/cmd/kubeadm/app/apis/kubeadm/validation/validation_test.go +++ b/cmd/kubeadm/app/apis/kubeadm/validation/validation_test.go @@ -323,3 +323,27 @@ func TestValidateMixedArguments(t *testing.T) { } } } + +func TestValidateFeatureFlags(t *testing.T) { + type featureFlag map[string]bool + var tests = []struct { + featureFlags featureFlag + expected bool + }{ + {featureFlag{"SelfHosting": true}, true}, + {featureFlag{"SelfHosting": false}, true}, + {featureFlag{"StoreCertsInSecrets": true}, true}, + {featureFlag{"StoreCertsInSecrets": false}, true}, + {featureFlag{"Foo": true}, false}, + } + for _, rt := range tests { + actual := ValidateFeatureFlags(rt.featureFlags, nil) + if (len(actual) == 0) != rt.expected { + t.Errorf( + "failed featureFlags:\n\texpected: %t\n\t actual: %t", + rt.expected, + (len(actual) == 0), + ) + } + } +} diff --git a/cmd/kubeadm/app/apis/kubeadm/zz_generated.deepcopy.go b/cmd/kubeadm/app/apis/kubeadm/zz_generated.deepcopy.go index 68eef052fd3..e45e142a641 100644 --- a/cmd/kubeadm/app/apis/kubeadm/zz_generated.deepcopy.go +++ b/cmd/kubeadm/app/apis/kubeadm/zz_generated.deepcopy.go @@ -144,6 +144,13 @@ func (in *MasterConfiguration) DeepCopyInto(out *MasterConfiguration) { *out = make([]string, len(*in)) copy(*out, *in) } + if in.FeatureFlags != nil { + in, out := &in.FeatureFlags, &out.FeatureFlags + *out = make(map[string]bool, len(*in)) + for key, val := range *in { + (*out)[key] = val + } + } return } diff --git a/cmd/kubeadm/app/cmd/BUILD b/cmd/kubeadm/app/cmd/BUILD index 09dd40f3ef5..57d18294b2c 100644 --- a/cmd/kubeadm/app/cmd/BUILD +++ b/cmd/kubeadm/app/cmd/BUILD @@ -87,6 +87,7 @@ filegroup( name = "all-srcs", srcs = [ ":package-srcs", + "//cmd/kubeadm/app/cmd/features:all-srcs", "//cmd/kubeadm/app/cmd/phases:all-srcs", ], tags = ["automanaged"], diff --git a/cmd/kubeadm/app/cmd/features/BUILD b/cmd/kubeadm/app/cmd/features/BUILD new file mode 100644 index 00000000000..c5b61b4cbaf --- /dev/null +++ b/cmd/kubeadm/app/cmd/features/BUILD @@ -0,0 +1,28 @@ +package(default_visibility = ["//visibility:public"]) + +licenses(["notice"]) + +load( + "@io_bazel_rules_go//go:def.bzl", + "go_library", +) + +go_library( + name = "go_default_library", + srcs = ["features.go"], + tags = ["automanaged"], + deps = ["//vendor/k8s.io/apiserver/pkg/util/feature:go_default_library"], +) + +filegroup( + name = "package-srcs", + srcs = glob(["**"]), + tags = ["automanaged"], + visibility = ["//visibility:private"], +) + +filegroup( + name = "all-srcs", + srcs = [":package-srcs"], + tags = ["automanaged"], +) diff --git a/cmd/kubeadm/app/cmd/features/features.go b/cmd/kubeadm/app/cmd/features/features.go new file mode 100644 index 00000000000..ad2a584b4b8 --- /dev/null +++ b/cmd/kubeadm/app/cmd/features/features.go @@ -0,0 +1,58 @@ +/* +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 features + +import ( + utilfeature "k8s.io/apiserver/pkg/util/feature" +) + +const ( + // SelfHosting is beta in v1.8 + SelfHosting utilfeature.Feature = "SelfHosting" + + // StoreCertsInSecrets is alpha in v1.8 + StoreCertsInSecrets utilfeature.Feature = "StoreCertsInSecrets" +) + +// FeatureList represents a list of feature gates +type FeatureList map[utilfeature.Feature]utilfeature.FeatureSpec + +// Supports indicates whether a feature name is supported on the given +// feature set +func Supports(featureList FeatureList, featureName string) bool { + for k := range featureList { + if featureName == string(k) { + return true + } + } + return false +} + +// Keys returns a slice of feature names for a given feature set +func Keys(featureList FeatureList) []string { + var list []string + for k := range featureList { + list = append(list, string(k)) + } + return list +} + +// InitFeatureGates are the default feature gates for the init command +var InitFeatureGates = FeatureList{ + SelfHosting: {Default: false, PreRelease: utilfeature.Beta}, + StoreCertsInSecrets: {Default: false, PreRelease: utilfeature.Alpha}, +}