mirror of
https://github.com/edgelesssys/constellation.git
synced 2025-05-02 06:16:08 -04:00
cli: common backend for init
and upgrade apply
commands (#2449)
* Use common 'apply' backend for init and upgrades * Move unit tests to new apply backend * Only perform Terraform migrations if state exists in cwd (#2457) * Rework skipPhases logic --------- Signed-off-by: Daniel Weiße <dw@edgeless.systems> Co-authored-by: Moritz Sanft <58110325+msanft@users.noreply.github.com>
This commit is contained in:
parent
15d249092c
commit
671cf36f0a
15 changed files with 1399 additions and 1018 deletions
|
@ -41,8 +41,9 @@ func TestUpgradeApply(t *testing.T) {
|
|||
InitSecret: []byte{0x42},
|
||||
}).
|
||||
SetClusterValues(state.ClusterValues{MeasurementSalt: []byte{0x41}})
|
||||
fsWithStateFile := func() file.Handler {
|
||||
fsWithStateFileAndTfState := func() file.Handler {
|
||||
fh := file.NewHandler(afero.NewMemMapFs())
|
||||
require.NoError(t, fh.MkdirAll(constants.TerraformWorkingDir))
|
||||
require.NoError(t, fh.WriteYAML(constants.StateFilename, defaultState))
|
||||
return fh
|
||||
}
|
||||
|
@ -55,15 +56,15 @@ func TestUpgradeApply(t *testing.T) {
|
|||
terraformUpgrader clusterUpgrader
|
||||
wantErr bool
|
||||
customK8sVersion string
|
||||
flags upgradeApplyFlags
|
||||
flags applyFlags
|
||||
stdin string
|
||||
}{
|
||||
"success": {
|
||||
kubeUpgrader: &stubKubernetesUpgrader{currentConfig: config.DefaultForAzureSEVSNP()},
|
||||
helmUpgrader: stubApplier{},
|
||||
terraformUpgrader: &stubTerraformUpgrader{},
|
||||
flags: upgradeApplyFlags{yes: true},
|
||||
fh: fsWithStateFile,
|
||||
flags: applyFlags{yes: true},
|
||||
fh: fsWithStateFileAndTfState,
|
||||
fhAssertions: func(require *require.Assertions, assert *assert.Assertions, fh file.Handler) {
|
||||
gotState, err := state.ReadFromFile(fh, constants.StateFilename)
|
||||
require.NoError(err)
|
||||
|
@ -71,11 +72,11 @@ func TestUpgradeApply(t *testing.T) {
|
|||
assert.Equal(defaultState, gotState)
|
||||
},
|
||||
},
|
||||
"state file does not exist": {
|
||||
"id file and state file do not exist": {
|
||||
kubeUpgrader: &stubKubernetesUpgrader{currentConfig: config.DefaultForAzureSEVSNP()},
|
||||
helmUpgrader: stubApplier{},
|
||||
terraformUpgrader: &stubTerraformUpgrader{},
|
||||
flags: upgradeApplyFlags{yes: true},
|
||||
flags: applyFlags{yes: true},
|
||||
fh: func() file.Handler {
|
||||
return file.NewHandler(afero.NewMemMapFs())
|
||||
},
|
||||
|
@ -89,8 +90,8 @@ func TestUpgradeApply(t *testing.T) {
|
|||
helmUpgrader: stubApplier{},
|
||||
terraformUpgrader: &stubTerraformUpgrader{},
|
||||
wantErr: true,
|
||||
flags: upgradeApplyFlags{yes: true},
|
||||
fh: fsWithStateFile,
|
||||
flags: applyFlags{yes: true},
|
||||
fh: fsWithStateFileAndTfState,
|
||||
},
|
||||
"nodeVersion in progress error": {
|
||||
kubeUpgrader: &stubKubernetesUpgrader{
|
||||
|
@ -99,8 +100,8 @@ func TestUpgradeApply(t *testing.T) {
|
|||
},
|
||||
helmUpgrader: stubApplier{},
|
||||
terraformUpgrader: &stubTerraformUpgrader{},
|
||||
flags: upgradeApplyFlags{yes: true},
|
||||
fh: fsWithStateFile,
|
||||
flags: applyFlags{yes: true},
|
||||
fh: fsWithStateFileAndTfState,
|
||||
},
|
||||
"helm other error": {
|
||||
kubeUpgrader: &stubKubernetesUpgrader{
|
||||
|
@ -109,8 +110,8 @@ func TestUpgradeApply(t *testing.T) {
|
|||
helmUpgrader: stubApplier{err: assert.AnError},
|
||||
terraformUpgrader: &stubTerraformUpgrader{},
|
||||
wantErr: true,
|
||||
flags: upgradeApplyFlags{yes: true},
|
||||
fh: fsWithStateFile,
|
||||
flags: applyFlags{yes: true},
|
||||
fh: fsWithStateFileAndTfState,
|
||||
},
|
||||
"abort": {
|
||||
kubeUpgrader: &stubKubernetesUpgrader{
|
||||
|
@ -120,7 +121,7 @@ func TestUpgradeApply(t *testing.T) {
|
|||
terraformUpgrader: &stubTerraformUpgrader{terraformDiff: true},
|
||||
wantErr: true,
|
||||
stdin: "no\n",
|
||||
fh: fsWithStateFile,
|
||||
fh: fsWithStateFileAndTfState,
|
||||
},
|
||||
"abort, restore terraform err": {
|
||||
kubeUpgrader: &stubKubernetesUpgrader{
|
||||
|
@ -130,7 +131,7 @@ func TestUpgradeApply(t *testing.T) {
|
|||
terraformUpgrader: &stubTerraformUpgrader{terraformDiff: true, rollbackWorkspaceErr: assert.AnError},
|
||||
wantErr: true,
|
||||
stdin: "no\n",
|
||||
fh: fsWithStateFile,
|
||||
fh: fsWithStateFileAndTfState,
|
||||
},
|
||||
"plan terraform error": {
|
||||
kubeUpgrader: &stubKubernetesUpgrader{
|
||||
|
@ -139,8 +140,8 @@ func TestUpgradeApply(t *testing.T) {
|
|||
helmUpgrader: stubApplier{},
|
||||
terraformUpgrader: &stubTerraformUpgrader{planTerraformErr: assert.AnError},
|
||||
wantErr: true,
|
||||
flags: upgradeApplyFlags{yes: true},
|
||||
fh: fsWithStateFile,
|
||||
flags: applyFlags{yes: true},
|
||||
fh: fsWithStateFileAndTfState,
|
||||
},
|
||||
"apply terraform error": {
|
||||
kubeUpgrader: &stubKubernetesUpgrader{
|
||||
|
@ -152,8 +153,8 @@ func TestUpgradeApply(t *testing.T) {
|
|||
terraformDiff: true,
|
||||
},
|
||||
wantErr: true,
|
||||
flags: upgradeApplyFlags{yes: true},
|
||||
fh: fsWithStateFile,
|
||||
flags: applyFlags{yes: true},
|
||||
fh: fsWithStateFileAndTfState,
|
||||
},
|
||||
"outdated K8s patch version": {
|
||||
kubeUpgrader: &stubKubernetesUpgrader{
|
||||
|
@ -166,8 +167,8 @@ func TestUpgradeApply(t *testing.T) {
|
|||
require.NoError(t, err)
|
||||
return semver.NewFromInt(v.Major(), v.Minor(), v.Patch()-1, "").String()
|
||||
}(),
|
||||
flags: upgradeApplyFlags{yes: true},
|
||||
fh: fsWithStateFile,
|
||||
flags: applyFlags{yes: true},
|
||||
fh: fsWithStateFileAndTfState,
|
||||
},
|
||||
"outdated K8s version": {
|
||||
kubeUpgrader: &stubKubernetesUpgrader{
|
||||
|
@ -176,9 +177,9 @@ func TestUpgradeApply(t *testing.T) {
|
|||
helmUpgrader: stubApplier{},
|
||||
terraformUpgrader: &stubTerraformUpgrader{},
|
||||
customK8sVersion: "v1.20.0",
|
||||
flags: upgradeApplyFlags{yes: true},
|
||||
flags: applyFlags{yes: true},
|
||||
wantErr: true,
|
||||
fh: fsWithStateFile,
|
||||
fh: fsWithStateFileAndTfState,
|
||||
},
|
||||
"skip all upgrade phases": {
|
||||
kubeUpgrader: &stubKubernetesUpgrader{
|
||||
|
@ -186,11 +187,14 @@ func TestUpgradeApply(t *testing.T) {
|
|||
},
|
||||
helmUpgrader: &mockApplier{}, // mocks ensure that no methods are called
|
||||
terraformUpgrader: &mockTerraformUpgrader{},
|
||||
flags: upgradeApplyFlags{
|
||||
skipPhases: []skipPhase{skipInfrastructurePhase, skipHelmPhase, skipK8sPhase, skipImagePhase},
|
||||
yes: true,
|
||||
flags: applyFlags{
|
||||
skipPhases: skipPhases{
|
||||
skipInfrastructurePhase: struct{}{}, skipHelmPhase: struct{}{},
|
||||
skipK8sPhase: struct{}{}, skipImagePhase: struct{}{},
|
||||
},
|
||||
yes: true,
|
||||
},
|
||||
fh: fsWithStateFile,
|
||||
fh: fsWithStateFileAndTfState,
|
||||
},
|
||||
"skip all phases except node upgrade": {
|
||||
kubeUpgrader: &stubKubernetesUpgrader{
|
||||
|
@ -198,11 +202,37 @@ func TestUpgradeApply(t *testing.T) {
|
|||
},
|
||||
helmUpgrader: &mockApplier{}, // mocks ensure that no methods are called
|
||||
terraformUpgrader: &mockTerraformUpgrader{},
|
||||
flags: upgradeApplyFlags{
|
||||
skipPhases: []skipPhase{skipInfrastructurePhase, skipHelmPhase, skipK8sPhase},
|
||||
yes: true,
|
||||
flags: applyFlags{
|
||||
skipPhases: skipPhases{
|
||||
skipInfrastructurePhase: struct{}{}, skipHelmPhase: struct{}{},
|
||||
skipK8sPhase: struct{}{},
|
||||
},
|
||||
yes: true,
|
||||
},
|
||||
fh: fsWithStateFile,
|
||||
fh: fsWithStateFileAndTfState,
|
||||
},
|
||||
"no tf state, skip infrastructure upgrade": {
|
||||
kubeUpgrader: &stubKubernetesUpgrader{
|
||||
currentConfig: config.DefaultForAzureSEVSNP(),
|
||||
},
|
||||
helmUpgrader: &stubApplier{},
|
||||
terraformUpgrader: &mockTerraformUpgrader{},
|
||||
flags: applyFlags{
|
||||
yes: true,
|
||||
},
|
||||
fh: func() file.Handler {
|
||||
fh := file.NewHandler(afero.NewMemMapFs())
|
||||
require.NoError(t, fh.WriteYAML(constants.StateFilename, defaultState))
|
||||
return fh
|
||||
},
|
||||
},
|
||||
"attempt to change attestation variant": {
|
||||
kubeUpgrader: &stubKubernetesUpgrader{currentConfig: &config.AzureTrustedLaunch{}},
|
||||
helmUpgrader: stubApplier{},
|
||||
terraformUpgrader: &stubTerraformUpgrader{},
|
||||
flags: applyFlags{yes: true},
|
||||
fh: fsWithStateFileAndTfState,
|
||||
wantErr: true,
|
||||
},
|
||||
}
|
||||
|
||||
|
@ -218,20 +248,26 @@ func TestUpgradeApply(t *testing.T) {
|
|||
cfg.KubernetesVersion = versions.ValidK8sVersion(tc.customK8sVersion)
|
||||
}
|
||||
fh := tc.fh()
|
||||
require.NoError(fh.Write(constants.AdminConfFilename, []byte{}))
|
||||
require.NoError(fh.WriteYAML(constants.ConfigFilename, cfg))
|
||||
require.NoError(fh.WriteJSON(constants.MasterSecretFilename, uri.MasterSecret{}))
|
||||
|
||||
upgrader := upgradeApplyCmd{
|
||||
kubeUpgrader: tc.kubeUpgrader,
|
||||
helmApplier: tc.helmUpgrader,
|
||||
upgrader := &applyCmd{
|
||||
fileHandler: fh,
|
||||
flags: tc.flags,
|
||||
log: logger.NewTest(t),
|
||||
spinner: &nopSpinner{},
|
||||
merger: &stubMerger{},
|
||||
quotaChecker: &stubLicenseClient{},
|
||||
newHelmClient: func(string, debugLog) (helmApplier, error) {
|
||||
return tc.helmUpgrader, nil
|
||||
},
|
||||
newKubeUpgrader: func(_ io.Writer, _ string, _ debugLog) (kubernetesUpgrader, error) {
|
||||
return tc.kubeUpgrader, nil
|
||||
},
|
||||
clusterUpgrader: tc.terraformUpgrader,
|
||||
log: logger.NewTest(t),
|
||||
configFetcher: stubAttestationFetcher{},
|
||||
flags: tc.flags,
|
||||
fileHandler: fh,
|
||||
}
|
||||
|
||||
err := upgrader.upgradeApply(cmd, "test")
|
||||
err := upgrader.apply(cmd, stubAttestationFetcher{}, "test")
|
||||
if tc.wantErr {
|
||||
assert.Error(err)
|
||||
return
|
||||
|
@ -255,27 +291,37 @@ func TestUpgradeApplyFlagsForSkipPhases(t *testing.T) {
|
|||
cmd.Flags().Bool("force", true, "")
|
||||
cmd.Flags().String("tf-log", "NONE", "")
|
||||
cmd.Flags().Bool("debug", false, "")
|
||||
cmd.Flags().Bool("merge-kubeconfig", false, "")
|
||||
|
||||
require.NoError(cmd.Flags().Set("skip-phases", "infrastructure,helm,k8s,image"))
|
||||
wantPhases := skipPhases{}
|
||||
wantPhases.add(skipInfrastructurePhase, skipHelmPhase, skipK8sPhase, skipImagePhase)
|
||||
|
||||
var flags upgradeApplyFlags
|
||||
var flags applyFlags
|
||||
err := flags.parse(cmd.Flags())
|
||||
require.NoError(err)
|
||||
assert.ElementsMatch(t, []skipPhase{skipInfrastructurePhase, skipHelmPhase, skipK8sPhase, skipImagePhase}, flags.skipPhases)
|
||||
assert.Equal(t, wantPhases, flags.skipPhases)
|
||||
}
|
||||
|
||||
type stubKubernetesUpgrader struct {
|
||||
nodeVersionErr error
|
||||
currentConfig config.AttestationCfg
|
||||
calledNodeUpgrade bool
|
||||
nodeVersionErr error
|
||||
currentConfig config.AttestationCfg
|
||||
getClusterAttestationConfigErr error
|
||||
calledNodeUpgrade bool
|
||||
backupCRDsErr error
|
||||
backupCRDsCalled bool
|
||||
backupCRsErr error
|
||||
backupCRsCalled bool
|
||||
}
|
||||
|
||||
func (u *stubKubernetesUpgrader) BackupCRDs(_ context.Context, _ string) ([]apiextensionsv1.CustomResourceDefinition, error) {
|
||||
return []apiextensionsv1.CustomResourceDefinition{}, nil
|
||||
u.backupCRDsCalled = true
|
||||
return []apiextensionsv1.CustomResourceDefinition{}, u.backupCRDsErr
|
||||
}
|
||||
|
||||
func (u *stubKubernetesUpgrader) BackupCRs(_ context.Context, _ []apiextensionsv1.CustomResourceDefinition, _ string) error {
|
||||
return nil
|
||||
u.backupCRsCalled = true
|
||||
return u.backupCRsErr
|
||||
}
|
||||
|
||||
func (u *stubKubernetesUpgrader) UpgradeNodeVersion(_ context.Context, _ *config.Config, _, _, _ bool) error {
|
||||
|
@ -288,7 +334,7 @@ func (u *stubKubernetesUpgrader) ApplyJoinConfig(_ context.Context, _ config.Att
|
|||
}
|
||||
|
||||
func (u *stubKubernetesUpgrader) GetClusterAttestationConfig(_ context.Context, _ variant.Variant) (config.AttestationCfg, error) {
|
||||
return u.currentConfig, nil
|
||||
return u.currentConfig, u.getClusterAttestationConfigErr
|
||||
}
|
||||
|
||||
func (u *stubKubernetesUpgrader) ExtendClusterConfigCertSANs(_ context.Context, _ []string) error {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue