From 6ee08c60f83113b8f62ca7ea17fc5701588a8e16 Mon Sep 17 00:00:00 2001 From: Adrian Stobbe Date: Mon, 28 Aug 2023 11:05:59 +0200 Subject: [PATCH] upgrade allows outdated patch version --- cli/internal/cmd/init.go | 5 +++++ cli/internal/cmd/init_test.go | 19 +++++++++++++--- cli/internal/cmd/upgradeapply_test.go | 31 ++++++++++++++++++++++++++- internal/versions/versions.go | 21 +++--------------- 4 files changed, 54 insertions(+), 22 deletions(-) diff --git a/cli/internal/cmd/init.go b/cli/internal/cmd/init.go index c3f90b678..93cdbc352 100644 --- a/cli/internal/cmd/init.go +++ b/cli/internal/cmd/init.go @@ -152,6 +152,11 @@ func (i *initCmd) initialize( if err != nil { return err } + conf.KubernetesVersion, err = versions.NewValidK8sVersion(string(conf.KubernetesVersion), true) + // cfg validation does not check k8s patch version since upgrade may accept an outdated patch version. + if err != nil { + return err + } if !flags.force { if err := validateCLIandConstellationVersionAreEqual(constants.BinaryVersion(), conf.Image, conf.MicroserviceVersion); err != nil { return err diff --git a/cli/internal/cmd/init_test.go b/cli/internal/cmd/init_test.go index 81351e19a..0992bf446 100644 --- a/cli/internal/cmd/init_test.go +++ b/cli/internal/cmd/init_test.go @@ -38,6 +38,7 @@ import ( "github.com/edgelesssys/constellation/v2/internal/kms/uri" "github.com/edgelesssys/constellation/v2/internal/license" "github.com/edgelesssys/constellation/v2/internal/logger" + "github.com/edgelesssys/constellation/v2/internal/semver" "github.com/edgelesssys/constellation/v2/internal/versions" "github.com/spf13/afero" "github.com/stretchr/testify/assert" @@ -73,7 +74,6 @@ func TestInitialize(t *testing.T) { ClusterId: []byte("clusterID"), } serviceAccPath := "/test/service-account.json" - someErr := errors.New("failed") testCases := map[string]struct { provider cloudprovider.Provider @@ -105,7 +105,7 @@ func TestInitialize(t *testing.T) { "non retriable error": { provider: cloudprovider.QEMU, idFile: &clusterid.File{IP: "192.0.2.1"}, - initServerAPI: &stubInitServer{initErr: &nonRetriableError{someErr}}, + initServerAPI: &stubInitServer{initErr: &nonRetriableError{assert.AnError}}, retriable: false, masterSecretShouldExist: true, wantErr: true, @@ -125,7 +125,7 @@ func TestInitialize(t *testing.T) { "init call fails": { provider: cloudprovider.GCP, idFile: &clusterid.File{IP: "192.0.2.1"}, - initServerAPI: &stubInitServer{initErr: someErr}, + initServerAPI: &stubInitServer{initErr: assert.AnError}, retriable: true, wantErr: true, }, @@ -141,6 +141,19 @@ func TestInitialize(t *testing.T) { c.KubernetesVersion = res }, }, + "outdated k8s patch version doesn't work": { + provider: cloudprovider.Azure, + idFile: &clusterid.File{IP: "192.0.2.1"}, + initServerAPI: &stubInitServer{res: &initproto.InitResponse{Kind: &initproto.InitResponse_InitSuccess{InitSuccess: testInitResp}}}, + configMutator: func(c *config.Config) { + v, err := semver.New(versions.SupportedK8sVersions()[0]) + require.NoError(t, err) + outdatedPatchVer := semver.NewFromInt(v.Major(), v.Minor(), v.Patch()-1, "").String() + c.KubernetesVersion = versions.ValidK8sVersion(outdatedPatchVer) + }, + wantErr: true, + retriable: true, // doesn't need to show retriable error message + }, } for name, tc := range testCases { diff --git a/cli/internal/cmd/upgradeapply_test.go b/cli/internal/cmd/upgradeapply_test.go index 6b2e68629..d6542f97b 100644 --- a/cli/internal/cmd/upgradeapply_test.go +++ b/cli/internal/cmd/upgradeapply_test.go @@ -22,6 +22,8 @@ import ( "github.com/edgelesssys/constellation/v2/internal/file" "github.com/edgelesssys/constellation/v2/internal/kms/uri" "github.com/edgelesssys/constellation/v2/internal/logger" + "github.com/edgelesssys/constellation/v2/internal/semver" + "github.com/edgelesssys/constellation/v2/internal/versions" "github.com/spf13/afero" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" @@ -34,6 +36,7 @@ func TestUpgradeApply(t *testing.T) { kubeUpgrader *stubKubernetesUpgrader terraformUpgrader *stubTerraformUpgrader wantErr bool + customK8sVersion string flags upgradeApplyFlags stdin string }{ @@ -101,6 +104,30 @@ func TestUpgradeApply(t *testing.T) { wantErr: true, flags: upgradeApplyFlags{yes: true}, }, + "outdated K8s patch version": { + kubeUpgrader: &stubKubernetesUpgrader{ + currentConfig: config.DefaultForAzureSEVSNP(), + }, + helmUpgrader: stubApplier{}, + terraformUpgrader: &stubTerraformUpgrader{}, + customK8sVersion: func() string { + v, err := semver.New(versions.SupportedK8sVersions()[0]) + require.NoError(t, err) + return semver.NewFromInt(v.Major(), v.Minor(), v.Patch()-1, "").String() + }(), + wantErr: false, + flags: upgradeApplyFlags{yes: true}, + }, + "outdated K8s version": { + kubeUpgrader: &stubKubernetesUpgrader{ + currentConfig: config.DefaultForAzureSEVSNP(), + }, + helmUpgrader: stubApplier{}, + terraformUpgrader: &stubTerraformUpgrader{}, + customK8sVersion: "v1.20.0", + wantErr: true, + flags: upgradeApplyFlags{yes: true}, + }, } for name, tc := range testCases { @@ -113,7 +140,9 @@ func TestUpgradeApply(t *testing.T) { handler := file.NewHandler(afero.NewMemMapFs()) cfg := defaultConfigWithExpectedMeasurements(t, config.Default(), cloudprovider.Azure) - + if tc.customK8sVersion != "" { + cfg.KubernetesVersion = versions.ValidK8sVersion(tc.customK8sVersion) + } require.NoError(handler.WriteYAML(constants.ConfigFilename, cfg)) require.NoError(handler.WriteJSON(constants.ClusterIDsFilename, clusterid.File{MeasurementSalt: []byte("measurementSalt")})) require.NoError(handler.WriteJSON(constants.MasterSecretFilename, uri.MasterSecret{})) diff --git a/internal/versions/versions.go b/internal/versions/versions.go index bbce5194d..ebba4546a 100644 --- a/internal/versions/versions.go +++ b/internal/versions/versions.go @@ -51,7 +51,6 @@ type ValidK8sVersion string // 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 -// ValidK8sVersion is a supported patch version for the given major.minor version. // TODO(elchead): only allow strict mode? func NewValidK8sVersion(k8sVersion string, strict bool) (ValidK8sVersion, error) { prefixedVersion := compatibility.EnsurePrefixV(k8sVersion) @@ -59,7 +58,6 @@ func NewValidK8sVersion(k8sVersion string, strict bool) (ValidK8sVersion, error) if err != nil { return "", fmt.Errorf("resolving kubernetes patch version from flag: %w", err) } - fmt.Println(parsedVersion) var supported bool if strict { supported = isSupportedK8sVersionStrict(parsedVersion) @@ -69,10 +67,6 @@ func NewValidK8sVersion(k8sVersion string, strict bool) (ValidK8sVersion, error) if !supported { return "", fmt.Errorf("invalid Kubernetes version: %s; supported versions are %v", parsedVersion, SupportedK8sVersions()) } - if !strict { - parsedVersion, _ = supportedVersionForMajorMinor(parsedVersion) - } - return ValidK8sVersion(parsedVersion), nil } @@ -82,9 +76,9 @@ func (v *ValidK8sVersion) UnmarshalYAML(unmarshal func(interface{}) error) error if err := unmarshal(&version); err != nil { return err } - valid, err := NewValidK8sVersion(version, true) + valid, err := NewValidK8sVersion(version, false) // allow any patch version to not force K8s patch upgrades if err != nil { - return fmt.Errorf("unsupported Kubernetes version, supported versions are %s", strings.Join(SupportedK8sVersions(), ", ")) + return fmt.Errorf("unsupported Kubernetes version %s, supported versions are %s", version, strings.Join(SupportedK8sVersions(), ", ")) } *v = valid return nil @@ -97,6 +91,7 @@ func resolveK8sPatchVersion(k8sVersion string) (string, error) { if !semver.IsValid(k8sVersion) { return "", fmt.Errorf("kubernetes flag does not specify a valid semantic version: %s", k8sVersion) } + fmt.Println("COMPARE", semver.MajorMinor(k8sVersion), k8sVersion) if semver.MajorMinor(k8sVersion) != k8sVersion { // patch version is specified @@ -165,16 +160,6 @@ func IsPreviewK8sVersion(_ ValidK8sVersion) bool { return false } -func supportedVersionForMajorMinor(majorMinor string) (string, bool) { - majorMinor = semver.MajorMinor(majorMinor) - for _, valid := range SupportedK8sVersions() { - if semver.MajorMinor(valid) == majorMinor { - return valid, true - } - } - return "", false -} - const ( // // Constellation images.