From 7d0e5ab8ec20520fe1823b737a5b4735151e9bee Mon Sep 17 00:00:00 2001 From: Marvin Beckers Date: Mon, 7 Feb 2022 12:03:55 +0100 Subject: [PATCH] Use semver constraints on Kubernetes version for upper and lower bounds (#1808) * Use semver constraints on Kubernetes version for upper and lower bounds Signed-off-by: Marvin Beckers * Fix linting issues Signed-off-by: Marvin Beckers * Improve constraint usage and correctly append errors Signed-off-by: Marvin Beckers * Use mustParseConstraint Signed-off-by: Marvin Beckers * Fix test case Signed-off-by: Marvin Beckers * Appease linter Signed-off-by: Marvin Beckers --- pkg/apis/kubeone/validation/validation.go | 37 +++++++++++++++++-- .../kubeone/validation/validation_test.go | 14 +++++++ 2 files changed, 48 insertions(+), 3 deletions(-) diff --git a/pkg/apis/kubeone/validation/validation.go b/pkg/apis/kubeone/validation/validation.go index 52ed015b3..1e3b50d80 100644 --- a/pkg/apis/kubeone/validation/validation.go +++ b/pkg/apis/kubeone/validation/validation.go @@ -30,6 +30,18 @@ import ( "k8s.io/apimachinery/pkg/util/validation/field" ) +const ( + // lowerVersionConstraint defines a semver constraint that validates Kubernetes versions against a lower bound + lowerVersionConstraint = ">= 1.19" + // upperVersionConstraint defines a semver constraint that validates Kubernetes versions against an upper bound + upperVersionConstraint = "<= 1.23" +) + +var ( + lowerConstraint = mustParseConstraint(lowerVersionConstraint) + upperConstraint = mustParseConstraint(upperVersionConstraint) +) + // ValidateKubeOneCluster validates the KubeOneCluster object func ValidateKubeOneCluster(c kubeone.KubeOneCluster) field.ErrorList { allErrs := field.ErrorList{} @@ -183,13 +195,23 @@ func ValidateVersionConfig(version kubeone.VersionConfig, fldPath *field.Path) f allErrs = append(allErrs, field.Invalid(fldPath.Child("kubernetes"), version, ".versions.kubernetes is not a semver string")) return allErrs } - if v.Major() != 1 || v.Minor() < 19 { - allErrs = append(allErrs, field.Invalid(fldPath.Child("kubernetes"), version, "kubernetes versions lower than 1.19 are not supported. You need to use an older KubeOne version to upgrade your cluster to v1.19. Please refer to the Compatibility section of docs for more details.")) - } + if strings.HasPrefix(version.Kubernetes, "v") { allErrs = append(allErrs, field.Invalid(fldPath.Child("kubernetes"), version, ".versions.kubernetes can't start with a leading 'v'")) } + if valid, errs := lowerConstraint.Validate(v); !valid { + for _, err := range errs { + allErrs = append(allErrs, field.Invalid(fldPath.Child("kubernetes"), version, fmt.Sprintf("kubernetes version does not satisfy version constraint '%s': %s. You need to use an older KubeOne version to upgrade your cluster to a supported version. Please refer to the Compatibility section of docs for more details.", lowerVersionConstraint, err.Error()))) + } + } + + if valid, errs := upperConstraint.Validate(v); !valid { + for _, err := range errs { + allErrs = append(allErrs, field.Invalid(fldPath.Child("kubernetes"), version, fmt.Sprintf("kubernetes version does not satisfy version constraint '%s': %s. This version is not yet supported. Please refer to the Compatibility section of docs for more details.", upperVersionConstraint, err.Error()))) + } + } + return allErrs } @@ -516,3 +538,12 @@ func ValidateAssetConfiguration(a *kubeone.AssetConfiguration, fldPath *field.Pa return allErrs } + +func mustParseConstraint(constraint string) *semver.Constraints { + result, err := semver.NewConstraint(constraint) + if err != nil { + panic(err) + } + + return result +} diff --git a/pkg/apis/kubeone/validation/validation_test.go b/pkg/apis/kubeone/validation/validation_test.go index 2cf8af29d..ddd183df0 100644 --- a/pkg/apis/kubeone/validation/validation_test.go +++ b/pkg/apis/kubeone/validation/validation_test.go @@ -629,6 +629,13 @@ func TestValidateVersionConfig(t *testing.T) { versionConfig kubeone.VersionConfig expectedError bool }{ + { + name: "valid version config (1.23.1)", + versionConfig: kubeoneapi.VersionConfig{ + Kubernetes: "1.23.1", + }, + expectedError: false, + }, { name: "valid version config (1.22.1)", versionConfig: kubeone.VersionConfig{ @@ -678,6 +685,13 @@ func TestValidateVersionConfig(t *testing.T) { }, expectedError: false, }, + { + name: "not supported kubernetes version (1.24.0)", + versionConfig: kubeoneapi.VersionConfig{ + Kubernetes: "1.24.0", + }, + expectedError: true, + }, { name: "not supported kubernetes version (1.18.19)", versionConfig: kubeone.VersionConfig{