Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add HA feature gate and minVersion validation #54539

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
add HA gate and minVersion validation
  • Loading branch information
jamiehannaford committed Oct 26, 2017
commit 0ff425db4fa9f7d0f7d4aab17e79f6c24e2c4b38
4 changes: 4 additions & 0 deletions cmd/kubeadm/app/cmd/init.go
Original file line number Diff line number Diff line change
Expand Up @@ -231,6 +231,10 @@ func NewInit(cfgPath string, cfg *kubeadmapi.MasterConfiguration, skipPreFlight,
return nil, err
}

if err := features.ValidateVersion(features.InitFeatureGates, cfg.FeatureGates, cfg.KubernetesVersion); err != nil {
return nil, err
}

fmt.Printf("[init] Using Kubernetes version: %s\n", cfg.KubernetesVersion)
fmt.Printf("[init] Using Authorization modes: %v\n", cfg.AuthorizationModes)

Expand Down
5 changes: 4 additions & 1 deletion cmd/kubeadm/app/features/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,10 @@ go_library(
name = "go_default_library",
srcs = ["features.go"],
importpath = "k8s.io/kubernetes/cmd/kubeadm/app/features",
deps = ["//vendor/k8s.io/apiserver/pkg/util/feature:go_default_library"],
deps = [
"//pkg/util/version:go_default_library",
"//vendor/k8s.io/apiserver/pkg/util/feature:go_default_library",
],
)

filegroup(
Expand Down
54 changes: 44 additions & 10 deletions cmd/kubeadm/app/features/features.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,21 +23,61 @@ import (
"strings"

utilfeature "k8s.io/apiserver/pkg/util/feature"
"k8s.io/kubernetes/pkg/util/version"
)

const (
// HighAvailability is alpha in v1.9
HighAvailability = "HighAvailability"

// SelfHosting is beta in v1.8
SelfHosting utilfeature.Feature = "SelfHosting"
SelfHosting = "SelfHosting"

// StoreCertsInSecrets is alpha in v1.8
StoreCertsInSecrets utilfeature.Feature = "StoreCertsInSecrets"
StoreCertsInSecrets = "StoreCertsInSecrets"
)

var v190 = version.MustParseSemantic("v1.9.0")
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

sigh that should probably be v1.9.0-alpha.1 😄

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@luxas Yep, I'll update this in a follow-up PR

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

cool, thanks!


// InitFeatureGates are the default feature gates for the init command
var InitFeatureGates = FeatureList{
SelfHosting: {FeatureSpec: utilfeature.FeatureSpec{Default: false, PreRelease: utilfeature.Beta}},
StoreCertsInSecrets: {FeatureSpec: utilfeature.FeatureSpec{Default: false, PreRelease: utilfeature.Alpha}},
HighAvailability: {FeatureSpec: utilfeature.FeatureSpec{Default: false, PreRelease: utilfeature.Alpha}, MinimumVersion: v190},
}

// Feature represents a feature being gated
type Feature struct {
utilfeature.FeatureSpec
MinimumVersion *version.Version
}

// FeatureList represents a list of feature gates
type FeatureList map[utilfeature.Feature]utilfeature.FeatureSpec
type FeatureList map[string]Feature

// ValidateVersion ensures that a feature gate list is compatible with the chosen kubernetes version
func ValidateVersion(allFeatures FeatureList, requestedFeatures map[string]bool, requestedVersion string) error {
if requestedVersion == "" {
return nil
}
parsedExpVersion, err := version.ParseSemantic(requestedVersion)
if err != nil {
return fmt.Errorf("Error parsing version %s: %v", requestedVersion, err)
}
for k := range requestedFeatures {
if minVersion := allFeatures[k].MinimumVersion; minVersion != nil {
if !parsedExpVersion.AtLeast(minVersion) {
return fmt.Errorf(
"the requested kubernetes version (%s) is incompatible with the %s feature gate, which needs %s as a minimum",
requestedVersion, k, minVersion)
}
}
}
return nil
}

// Enabled indicates whether a feature name has been enabled
func Enabled(featureList map[string]bool, featureName utilfeature.Feature) bool {
func Enabled(featureList map[string]bool, featureName string) bool {
return featureList[string(featureName)]
}

Expand All @@ -61,12 +101,6 @@ func Keys(featureList FeatureList) []string {
return list
}

// InitFeatureGates are the default feature gates for the init command
var InitFeatureGates = FeatureList{
SelfHosting: {Default: false, PreRelease: utilfeature.Alpha},
StoreCertsInSecrets: {Default: false, PreRelease: utilfeature.Alpha},
}

// KnownFeatures returns a slice of strings describing the FeatureList features.
func KnownFeatures(f *FeatureList) []string {
var known []string
Expand Down
49 changes: 44 additions & 5 deletions cmd/kubeadm/app/features/features_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,9 @@ import (

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},
"feature2": {FeatureSpec: utilfeature.FeatureSpec{Default: true, PreRelease: utilfeature.Alpha}},
"feature1": {FeatureSpec: utilfeature.FeatureSpec{Default: false, PreRelease: utilfeature.Beta}},
"feature3": {FeatureSpec: utilfeature.FeatureSpec{Default: false, PreRelease: utilfeature.GA}},
}

r := KnownFeatures(&someFeatures)
Expand Down Expand Up @@ -55,8 +55,8 @@ func TestKnownFeatures(t *testing.T) {

func TestNewFeatureGate(t *testing.T) {
var someFeatures = FeatureList{
"feature1": {Default: false, PreRelease: utilfeature.Beta},
"feature2": {Default: true, PreRelease: utilfeature.Alpha},
"feature1": {FeatureSpec: utilfeature.FeatureSpec{Default: false, PreRelease: utilfeature.Beta}},
"feature2": {FeatureSpec: utilfeature.FeatureSpec{Default: true, PreRelease: utilfeature.Alpha}},
}

var tests = []struct {
Expand Down Expand Up @@ -117,3 +117,42 @@ func TestNewFeatureGate(t *testing.T) {
}
}
}

func TestValidateVersion(t *testing.T) {
var someFeatures = FeatureList{
"feature1": {FeatureSpec: utilfeature.FeatureSpec{Default: false, PreRelease: utilfeature.Beta}},
"feature2": {FeatureSpec: utilfeature.FeatureSpec{Default: true, PreRelease: utilfeature.Alpha}, MinimumVersion: v190},
}

var tests = []struct {
requestedVersion string
requestedFeatures map[string]bool
expectedError bool
}{
{ //no min version
requestedFeatures: map[string]bool{"feature1": true},
expectedError: false,
},
{ //min version but correct value given
requestedFeatures: map[string]bool{"feature2": true},
requestedVersion: "v1.9.0",
expectedError: false,
},
{ //min version and incorrect value given
requestedFeatures: map[string]bool{"feature2": true},
requestedVersion: "v1.8.2",
expectedError: true,
},
}

for _, test := range tests {
err := ValidateVersion(someFeatures, test.requestedFeatures, test.requestedVersion)
if !test.expectedError && err != nil {
t.Errorf("ValidateVersion failed when not expected: %v", err)
continue
} else if test.expectedError && err == nil {
t.Error("ValidateVersion didn't failed when expected")
continue
}
}
}