diff --git a/cli/internal/cmd/configgenerate.go b/cli/internal/cmd/configgenerate.go index eb5259912..5fe0f057b 100644 --- a/cli/internal/cmd/configgenerate.go +++ b/cli/internal/cmd/configgenerate.go @@ -133,7 +133,7 @@ func parseGenerateFlags(cmd *cobra.Command) (generateFlags, error) { if err != nil { return generateFlags{}, fmt.Errorf("parsing Kubernetes flag: %w", err) } - resolvedVersion, err := versions.NewValidK8sVersion(k8sVersion, true) // allow versions without specified patch + resolvedVersion, err := versions.NewValidK8sVersion(k8sVersion, true) if err != nil { return generateFlags{}, fmt.Errorf("resolving Kubernetes version from flag: %w", err) } diff --git a/cli/internal/cmd/upgradeapply.go b/cli/internal/cmd/upgradeapply.go index a2ba9da19..201e3bd7a 100644 --- a/cli/internal/cmd/upgradeapply.go +++ b/cli/internal/cmd/upgradeapply.go @@ -149,9 +149,7 @@ func (u *upgradeApplyCmd) upgradeApply(cmd *cobra.Command, upgradeDir string, fl } } } - if versions.IsPreviewK8sVersion(conf.KubernetesVersion) { - cmd.PrintErrf("Warning: Constellation with Kubernetes %q is still in preview. Use only for evaluation purposes.\n", conf.KubernetesVersion) - } + conf.KubernetesVersion, err = validK8sVersion(cmd, string(conf.KubernetesVersion), flags.yes) if err != nil { return err } @@ -307,6 +305,27 @@ func (u *upgradeApplyCmd) migrateTerraform(cmd *cobra.Command, conf *config.Conf return tfOutput, nil } +// validK8sVersion checks if the Kubernetes patch version is supported and asks for confirmation if not. +func validK8sVersion(cmd *cobra.Command, version string, yes bool) (validVersion versions.ValidK8sVersion, err error) { + validVersion, err = versions.NewValidK8sVersion(version, true) + if versions.IsPreviewK8sVersion(validVersion) { + cmd.PrintErrf("Warning: Constellation with Kubernetes %v is still in preview. Use only for evaluation purposes.\n", validVersion) + } + valid := err == nil + + if !valid && !yes { + confirmed, err := askToConfirm(cmd, fmt.Sprintf("WARNING: The Kubernetes patch version %s is not supported. If you continue, Kubernetes upgrades will be skipped. Do you want to continue anyway?", version)) + if err != nil { + return validVersion, fmt.Errorf("asking for confirmation: %w", err) + } + if !confirmed { + return validVersion, fmt.Errorf("aborted by user") + } + } + + return validVersion, nil +} + // confirmAndUpgradeAttestationConfig checks if the locally configured measurements are different from the cluster's measurements. // If so the function will ask the user to confirm (if --yes is not set) and upgrade the cluster's config. func (u *upgradeApplyCmd) confirmAndUpgradeAttestationConfig( diff --git a/cli/internal/cmd/upgradeapply_test.go b/cli/internal/cmd/upgradeapply_test.go index d6542f97b..8e4bcb434 100644 --- a/cli/internal/cmd/upgradeapply_test.go +++ b/cli/internal/cmd/upgradeapply_test.go @@ -115,8 +115,8 @@ func TestUpgradeApply(t *testing.T) { require.NoError(t, err) return semver.NewFromInt(v.Major(), v.Minor(), v.Patch()-1, "").String() }(), - wantErr: false, flags: upgradeApplyFlags{yes: true}, + wantErr: false, }, "outdated K8s version": { kubeUpgrader: &stubKubernetesUpgrader{ @@ -125,8 +125,8 @@ func TestUpgradeApply(t *testing.T) { helmUpgrader: stubApplier{}, terraformUpgrader: &stubTerraformUpgrader{}, customK8sVersion: "v1.20.0", - wantErr: true, flags: upgradeApplyFlags{yes: true}, + wantErr: true, }, } diff --git a/cli/internal/kubecmd/kubecmd.go b/cli/internal/kubecmd/kubecmd.go index 930e4b3b5..e069a5b93 100644 --- a/cli/internal/kubecmd/kubecmd.go +++ b/cli/internal/kubecmd/kubecmd.go @@ -124,7 +124,6 @@ func (k *KubeCmd) UpgradeNodeVersion(ctx context.Context, conf *config.Config, f nodeVersion.Spec.ImageReference = imageReference nodeVersion.Spec.ImageVersion = imageVersion.Version() - // TODO(elchead): why? // We have to allow users to specify outdated k8s patch versions. // Therefore, this code has to skip k8s updates if a user configures an outdated (i.e. invalid) k8s version. var components *corev1.ConfigMap diff --git a/e2e/internal/upgrade/upgrade_test.go b/e2e/internal/upgrade/upgrade_test.go index c33346bc5..b72d252f8 100644 --- a/e2e/internal/upgrade/upgrade_test.go +++ b/e2e/internal/upgrade/upgrade_test.go @@ -277,8 +277,7 @@ func writeUpgradeConfig(require *require.Assertions, image string, kubernetes st if kubernetes == "" { kubernetesVersion = defaultConfig.KubernetesVersion } else { - kubernetesVersion, err = versions.NewValidK8sVersion(kubernetes, true) - require.NoError(err) + kubernetesVersion = versions.ValidK8sVersion(kubernetes) // ignore validation because the config is only written to file } var microserviceVersion semver.Semver diff --git a/internal/versions/versions.go b/internal/versions/versions.go index ebba4546a..4cfd591dc 100644 --- a/internal/versions/versions.go +++ b/internal/versions/versions.go @@ -48,10 +48,11 @@ func SupportedValidK8sVersions() (res []ValidK8sVersion) { type ValidK8sVersion string // NewValidK8sVersion validates the given string and produces a new ValidK8sVersion object. +// It accepts a major minor version (e.g. 1.26) and transforms it into a supported patch version (e.g. 1.26.7). +// It also accepts a full version (e.g. 1.26.7) and validates it. // Returns an empty string if the given version is invalid. // strict controls whether the patch version is checked or not. -// If strict is false, the patch version is ignored and the returned -// TODO(elchead): only allow strict mode? +// If strict is false, the patch version is ignored and the returned. func NewValidK8sVersion(k8sVersion string, strict bool) (ValidK8sVersion, error) { prefixedVersion := compatibility.EnsurePrefixV(k8sVersion) parsedVersion, err := resolveK8sPatchVersion(prefixedVersion) @@ -86,7 +87,6 @@ func (v *ValidK8sVersion) UnmarshalYAML(unmarshal func(interface{}) error) error // resolveK8sPatchVersion takes the user input from --kubernetes and transforms a MAJOR.MINOR definition into a supported // MAJOR.MINOR.PATCH release. -// TODO(elchead): should we support this resolvement also for the config? func resolveK8sPatchVersion(k8sVersion string) (string, error) { if !semver.IsValid(k8sVersion) { return "", fmt.Errorf("kubernetes flag does not specify a valid semantic version: %s", k8sVersion)