From 5ff994f17b9910d3d67dc5a4c5c1431b004be238 Mon Sep 17 00:00:00 2001 From: fabriziopandini Date: Wed, 23 Aug 2017 09:55:47 +0200 Subject: [PATCH] Move package `app/cmd/features` to `app/features` + bazel files --- cmd/kubeadm/app/BUILD | 1 + cmd/kubeadm/app/apis/kubeadm/validation/BUILD | 2 +- .../app/apis/kubeadm/validation/validation.go | 2 +- cmd/kubeadm/app/cmd/BUILD | 3 +- cmd/kubeadm/app/cmd/phases/BUILD | 1 + cmd/kubeadm/app/{cmd => }/features/BUILD | 8 ++ .../app/{cmd => }/features/features.go | 50 ++++++++ cmd/kubeadm/app/features/features_test.go | 119 ++++++++++++++++++ cmd/kubeadm/app/phases/selfhosting/BUILD | 2 +- .../app/phases/selfhosting/selfhosting.go | 2 +- 10 files changed, 184 insertions(+), 6 deletions(-) rename cmd/kubeadm/app/{cmd => }/features/BUILD (71%) rename cmd/kubeadm/app/{cmd => }/features/features.go (59%) create mode 100644 cmd/kubeadm/app/features/features_test.go diff --git a/cmd/kubeadm/app/BUILD b/cmd/kubeadm/app/BUILD index a54eeb757d3..83e384e8fcd 100644 --- a/cmd/kubeadm/app/BUILD +++ b/cmd/kubeadm/app/BUILD @@ -31,6 +31,7 @@ filegroup( "//cmd/kubeadm/app/cmd:all-srcs", "//cmd/kubeadm/app/constants:all-srcs", "//cmd/kubeadm/app/discovery:all-srcs", + "//cmd/kubeadm/app/features:all-srcs", "//cmd/kubeadm/app/images:all-srcs", "//cmd/kubeadm/app/node:all-srcs", "//cmd/kubeadm/app/phases/addons/dns:all-srcs", diff --git a/cmd/kubeadm/app/apis/kubeadm/validation/BUILD b/cmd/kubeadm/app/apis/kubeadm/validation/BUILD index 5e5dbb15225..09eed2d163d 100644 --- a/cmd/kubeadm/app/apis/kubeadm/validation/BUILD +++ b/cmd/kubeadm/app/apis/kubeadm/validation/BUILD @@ -22,8 +22,8 @@ go_library( srcs = ["validation.go"], 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/features:go_default_library", "//cmd/kubeadm/app/util: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 b91c0849fe5..4459af6db3a 100644 --- a/cmd/kubeadm/app/apis/kubeadm/validation/validation.go +++ b/cmd/kubeadm/app/apis/kubeadm/validation/validation.go @@ -29,8 +29,8 @@ 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" + "k8s.io/kubernetes/cmd/kubeadm/app/features" kubeadmutil "k8s.io/kubernetes/cmd/kubeadm/app/util" tokenutil "k8s.io/kubernetes/cmd/kubeadm/app/util/token" apivalidation "k8s.io/kubernetes/pkg/api/validation" diff --git a/cmd/kubeadm/app/cmd/BUILD b/cmd/kubeadm/app/cmd/BUILD index 4544a53cdbe..ae031e54646 100644 --- a/cmd/kubeadm/app/cmd/BUILD +++ b/cmd/kubeadm/app/cmd/BUILD @@ -22,10 +22,10 @@ go_library( "//cmd/kubeadm/app/apis/kubeadm:go_default_library", "//cmd/kubeadm/app/apis/kubeadm/v1alpha1:go_default_library", "//cmd/kubeadm/app/apis/kubeadm/validation:go_default_library", - "//cmd/kubeadm/app/cmd/features:go_default_library", "//cmd/kubeadm/app/cmd/phases:go_default_library", "//cmd/kubeadm/app/constants:go_default_library", "//cmd/kubeadm/app/discovery:go_default_library", + "//cmd/kubeadm/app/features:go_default_library", "//cmd/kubeadm/app/phases/addons/dns:go_default_library", "//cmd/kubeadm/app/phases/addons/proxy:go_default_library", "//cmd/kubeadm/app/phases/apiconfig:go_default_library", @@ -94,7 +94,6 @@ 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/phases/BUILD b/cmd/kubeadm/app/cmd/phases/BUILD index 787750a0322..683b2ef5ed2 100644 --- a/cmd/kubeadm/app/cmd/phases/BUILD +++ b/cmd/kubeadm/app/cmd/phases/BUILD @@ -26,6 +26,7 @@ go_library( "//cmd/kubeadm/app/apis/kubeadm/v1alpha1:go_default_library", "//cmd/kubeadm/app/apis/kubeadm/validation:go_default_library", "//cmd/kubeadm/app/constants:go_default_library", + "//cmd/kubeadm/app/features:go_default_library", "//cmd/kubeadm/app/phases/bootstraptoken/clusterinfo:go_default_library", "//cmd/kubeadm/app/phases/bootstraptoken/node:go_default_library", "//cmd/kubeadm/app/phases/certs:go_default_library", diff --git a/cmd/kubeadm/app/cmd/features/BUILD b/cmd/kubeadm/app/features/BUILD similarity index 71% rename from cmd/kubeadm/app/cmd/features/BUILD rename to cmd/kubeadm/app/features/BUILD index 2341efdef2d..1dcb8630446 100644 --- a/cmd/kubeadm/app/cmd/features/BUILD +++ b/cmd/kubeadm/app/features/BUILD @@ -3,6 +3,7 @@ package(default_visibility = ["//visibility:public"]) load( "@io_bazel_rules_go//go:def.bzl", "go_library", + "go_test", ) go_library( @@ -23,3 +24,10 @@ filegroup( srcs = [":package-srcs"], tags = ["automanaged"], ) + +go_test( + name = "go_default_test", + srcs = ["features_test.go"], + library = ":go_default_library", + deps = ["//vendor/k8s.io/apiserver/pkg/util/feature:go_default_library"], +) diff --git a/cmd/kubeadm/app/cmd/features/features.go b/cmd/kubeadm/app/features/features.go similarity index 59% rename from cmd/kubeadm/app/cmd/features/features.go rename to cmd/kubeadm/app/features/features.go index 62fa02574c6..767d2128230 100644 --- a/cmd/kubeadm/app/cmd/features/features.go +++ b/cmd/kubeadm/app/features/features.go @@ -17,6 +17,11 @@ limitations under the License. package features import ( + "fmt" + "sort" + "strconv" + "strings" + utilfeature "k8s.io/apiserver/pkg/util/feature" ) @@ -61,3 +66,48 @@ var InitFeatureGates = FeatureList{ SelfHosting: {Default: false, PreRelease: utilfeature.Beta}, StoreCertsInSecrets: {Default: false, PreRelease: utilfeature.Alpha}, } + +// KnownFeatures returns a slice of strings describing the FeatureList features. +func KnownFeatures(f *FeatureList) []string { + var known []string + for k, v := range *f { + pre := "" + if v.PreRelease != utilfeature.GA { + pre = fmt.Sprintf("%s - ", v.PreRelease) + } + known = append(known, fmt.Sprintf("%s=true|false (%sdefault=%t)", k, pre, v.Default)) + } + sort.Strings(known) + return known +} + +// NewFeatureGate parse a string of the form "key1=value1,key2=value2,..." into a +// map[string]bool of known keys or returns an error. +func NewFeatureGate(f *FeatureList, value string) (map[string]bool, error) { + featureGate := map[string]bool{} + for _, s := range strings.Split(value, ",") { + if len(s) == 0 { + continue + } + + arr := strings.SplitN(s, "=", 2) + if len(arr) != 2 { + return nil, fmt.Errorf("missing bool value for feature-gate key:%s", s) + } + + k := strings.TrimSpace(arr[0]) + v := strings.TrimSpace(arr[1]) + + if !Supports(*f, k) { + return nil, fmt.Errorf("unrecognized feature-gate key: %s", k) + } + + boolValue, err := strconv.ParseBool(v) + if err != nil { + return nil, fmt.Errorf("invalid value %v for feature-gate key: %s, use true|false instead", v, k) + } + featureGate[k] = boolValue + } + + return featureGate, nil +} diff --git a/cmd/kubeadm/app/features/features_test.go b/cmd/kubeadm/app/features/features_test.go new file mode 100644 index 00000000000..486f10f84fc --- /dev/null +++ b/cmd/kubeadm/app/features/features_test.go @@ -0,0 +1,119 @@ +/* +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 ( + "reflect" + "testing" + + utilfeature "k8s.io/apiserver/pkg/util/feature" +) + +func TestKnownFeatures(t *testing.T) { + var someFeatures = FeatureList{ + "feature2": {Default: true, PreRelease: utilfeature.Alpha}, + "feature1": {Default: false, PreRelease: utilfeature.Beta}, + "feature3": {Default: false, PreRelease: utilfeature.GA}, + } + + r := KnownFeatures(&someFeatures) + + if len(r) != 3 { + t.Errorf("KnownFeatures returned %d values, expected 3", len(r)) + } + + // check the first value is feature1 (the list should be sorted); prerelease and default should be present + f1 := "feature1=true|false (BETA - default=false)" + if r[0] != f1 { + t.Errorf("KnownFeatures returned %s values, expected %s", r[0], f1) + } + // check the second value is feature2; prerelease and default should be present + f2 := "feature2=true|false (ALPHA - default=true)" + if r[1] != f2 { + t.Errorf("KnownFeatures returned %s values, expected %s", r[1], f2) + } + // check the second value is feature3; prerelease should not shown fo GA features; default should be present + f3 := "feature3=true|false (default=false)" + if r[2] != f3 { + t.Errorf("KnownFeatures returned %s values, expected %s", r[2], f3) + } +} + +func TestNewFeatureGate(t *testing.T) { + var someFeatures = FeatureList{ + "feature1": {Default: false, PreRelease: utilfeature.Beta}, + "feature2": {Default: true, PreRelease: utilfeature.Alpha}, + } + + var tests = []struct { + value string + expectedError bool + expectedFeaturesGate map[string]bool + }{ + { //invalid value (missing =) + value: "invalidValue", + expectedError: true, + }, + { //invalid value (missing =) + value: "feature1=true,invalidValue", + expectedError: true, + }, + { //invalid value (not a boolean) + value: "feature1=notABoolean", + expectedError: true, + }, + { //invalid value (not a boolean) + value: "feature1=true,feature2=notABoolean", + expectedError: true, + }, + { //unrecognized feature-gate key + value: "unknownFeature=false", + expectedError: true, + }, + { //unrecognized feature-gate key + value: "feature1=true,unknownFeature=false", + expectedError: true, + }, + { //one feature + value: "feature1=true", + expectedError: false, + expectedFeaturesGate: map[string]bool{"feature1": true}, + }, + { //two features + value: "feature1=true,feature2=false", + expectedError: false, + expectedFeaturesGate: map[string]bool{"feature1": true, "feature2": false}, + }, + } + + for _, test := range tests { + + r, err := NewFeatureGate(&someFeatures, test.value) + + if !test.expectedError && err != nil { + t.Errorf("NewFeatureGate failed when not expected: %v", err) + continue + } else if test.expectedError && err == nil { + t.Error("NewFeatureGate didn't failed when expected") + continue + } + + if !reflect.DeepEqual(r, test.expectedFeaturesGate) { + t.Errorf("NewFeatureGate returned a unexpected value") + } + } +} diff --git a/cmd/kubeadm/app/phases/selfhosting/BUILD b/cmd/kubeadm/app/phases/selfhosting/BUILD index ae5a836f769..0860458c1af 100644 --- a/cmd/kubeadm/app/phases/selfhosting/BUILD +++ b/cmd/kubeadm/app/phases/selfhosting/BUILD @@ -30,8 +30,8 @@ go_library( ], 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/features:go_default_library", "//cmd/kubeadm/app/util:go_default_library", "//cmd/kubeadm/app/util/apiclient:go_default_library", "//pkg/api:go_default_library", diff --git a/cmd/kubeadm/app/phases/selfhosting/selfhosting.go b/cmd/kubeadm/app/phases/selfhosting/selfhosting.go index 0929aab5d99..8fea9e9a035 100644 --- a/cmd/kubeadm/app/phases/selfhosting/selfhosting.go +++ b/cmd/kubeadm/app/phases/selfhosting/selfhosting.go @@ -28,8 +28,8 @@ import ( kuberuntime "k8s.io/apimachinery/pkg/runtime" clientset "k8s.io/client-go/kubernetes" kubeadmapi "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm" - "k8s.io/kubernetes/cmd/kubeadm/app/cmd/features" kubeadmconstants "k8s.io/kubernetes/cmd/kubeadm/app/constants" + "k8s.io/kubernetes/cmd/kubeadm/app/features" "k8s.io/kubernetes/cmd/kubeadm/app/util/apiclient" "k8s.io/kubernetes/pkg/api" )