cli: write Terraform migration output directly to constellation-id.json (#2107)

* backup `constellation-id.json` before upgrade

* remove superfluous `file.Handler` arguments

* merge `constellation-id.json` on upgrade

* fix typo
This commit is contained in:
Moritz Sanft 2023-07-18 09:33:42 +02:00 committed by GitHub
parent 5cbdb3a519
commit 5f71934f56
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 255 additions and 120 deletions

View File

@ -1,4 +1,5 @@
load("@io_bazel_rules_go//go:def.bzl", "go_library")
load("//bazel/go:go_test.bzl", "go_test")
go_library(
name = "clusterid",
@ -7,3 +8,10 @@ go_library(
visibility = ["//cli:__subpackages__"],
deps = ["//internal/cloud/cloudprovider"],
)
go_test(
name = "clusterid_test",
srcs = ["id_test.go"],
embed = [":clusterid"],
deps = ["@com_github_stretchr_testify//require"],
)

View File

@ -28,3 +28,38 @@ type File struct {
// It is only set if the cluster is created on Azure.
AttestationURL string `json:"attestationURL,omitempty"`
}
// Merge merges the other file into the current file and returns the result.
// If a field is set in both files, the value of the other file is used.
// This does in-place changes on the current file.
func (f *File) Merge(other File) *File {
if other.ClusterID != "" {
f.ClusterID = other.ClusterID
}
if other.OwnerID != "" {
f.OwnerID = other.OwnerID
}
if other.UID != "" {
f.UID = other.UID
}
if other.CloudProvider != cloudprovider.Unknown {
f.CloudProvider = other.CloudProvider
}
if other.IP != "" {
f.IP = other.IP
}
if other.InitSecret != nil {
f.InitSecret = other.InitSecret
}
if other.AttestationURL != "" {
f.AttestationURL = other.AttestationURL
}
return f
}

View File

@ -0,0 +1,63 @@
/*
Copyright (c) Edgeless Systems GmbH
SPDX-License-Identifier: AGPL-3.0-only
*/
package clusterid
import (
"testing"
"github.com/stretchr/testify/require"
)
func TestMerge(t *testing.T) {
testCases := map[string]struct {
current File
other File
want File
}{
"empty": {
current: File{},
other: File{},
want: File{},
},
"current empty": {
current: File{},
other: File{
ClusterID: "clusterID",
},
want: File{
ClusterID: "clusterID",
},
},
"other empty": {
current: File{
ClusterID: "clusterID",
},
other: File{},
want: File{
ClusterID: "clusterID",
},
},
"both set": {
current: File{
ClusterID: "clusterID",
},
other: File{
ClusterID: "otherClusterID",
},
want: File{
ClusterID: "otherClusterID",
},
},
}
for _, tc := range testCases {
require := require.New(t)
ret := tc.current.Merge(tc.other)
require.Equal(tc.want, *ret)
}
}

View File

@ -63,7 +63,7 @@ func runUpgradeApply(cmd *cobra.Command, _ []string) error {
defer log.Sync()
fileHandler := file.NewHandler(afero.NewOsFs())
upgrader, err := kubernetes.NewUpgrader(cmd.Context(), cmd.OutOrStdout(), log, kubernetes.UpgradeCmdKindApply)
upgrader, err := kubernetes.NewUpgrader(cmd.Context(), cmd.OutOrStdout(), fileHandler, log, kubernetes.UpgradeCmdKindApply)
if err != nil {
return err
}
@ -146,7 +146,7 @@ func (u *upgradeApplyCmd) upgradeApply(cmd *cobra.Command, fileHandler file.Hand
func (u *upgradeApplyCmd) migrateTerraform(cmd *cobra.Command, file file.Handler, fetcher imageFetcher, conf *config.Config, flags upgradeApplyFlags) error {
u.log.Debugf("Planning Terraform migrations")
if err := u.upgrader.CheckTerraformMigrations(file); err != nil {
if err := u.upgrader.CheckTerraformMigrations(); err != nil {
return fmt.Errorf("checking workspace: %w", err)
}
@ -168,10 +168,9 @@ func (u *upgradeApplyCmd) migrateTerraform(cmd *cobra.Command, file file.Handler
u.log.Debugf("Using Terraform variables:\n%v", vars)
opts := upgrade.TerraformUpgradeOptions{
LogLevel: flags.terraformLogLevel,
CSP: conf.GetProvider(),
Vars: vars,
OutputFile: constants.TerraformMigrationOutputFile,
LogLevel: flags.terraformLogLevel,
CSP: conf.GetProvider(),
Vars: vars,
}
// Check if there are any Terraform migrations to apply
@ -190,20 +189,20 @@ func (u *upgradeApplyCmd) migrateTerraform(cmd *cobra.Command, file file.Handler
}
if !ok {
cmd.Println("Aborting upgrade.")
if err := u.upgrader.CleanUpTerraformMigrations(file); err != nil {
if err := u.upgrader.CleanUpTerraformMigrations(); err != nil {
return fmt.Errorf("cleaning up workspace: %w", err)
}
return fmt.Errorf("aborted by user")
}
}
u.log.Debugf("Applying Terraform migrations")
err := u.upgrader.ApplyTerraformMigrations(cmd.Context(), file, opts)
err := u.upgrader.ApplyTerraformMigrations(cmd.Context(), opts)
if err != nil {
return fmt.Errorf("applying terraform migrations: %w", err)
}
cmd.Printf("Terraform migrations applied successfully and output written to: %s\n"+
"A backup of the pre-upgrade Terraform state has been written to: %s\n",
opts.OutputFile, filepath.Join(constants.UpgradeDir, constants.TerraformUpgradeBackupDir))
"A backup of the pre-upgrade state has been written to: %s\n",
constants.ClusterIDsFileName, filepath.Join(constants.UpgradeDir, constants.TerraformUpgradeBackupDir))
} else {
u.log.Debugf("No Terraform diff detected")
}
@ -442,9 +441,9 @@ type cloudUpgrader interface {
UpdateAttestationConfig(ctx context.Context, newConfig config.AttestationCfg) error
GetClusterAttestationConfig(ctx context.Context, variant variant.Variant) (config.AttestationCfg, *corev1.ConfigMap, error)
PlanTerraformMigrations(ctx context.Context, opts upgrade.TerraformUpgradeOptions) (bool, error)
ApplyTerraformMigrations(ctx context.Context, fileHandler file.Handler, opts upgrade.TerraformUpgradeOptions) error
CheckTerraformMigrations(fileHandler file.Handler) error
CleanUpTerraformMigrations(fileHandler file.Handler) error
ApplyTerraformMigrations(ctx context.Context, opts upgrade.TerraformUpgradeOptions) error
CheckTerraformMigrations() error
CleanUpTerraformMigrations() error
AddManualStateMigration(migration terraform.StateMigration)
}

View File

@ -181,11 +181,11 @@ func (u stubUpgrader) GetClusterAttestationConfig(_ context.Context, _ variant.V
return u.currentConfig, &corev1.ConfigMap{}, nil
}
func (u stubUpgrader) CheckTerraformMigrations(file.Handler) error {
func (u stubUpgrader) CheckTerraformMigrations() error {
return u.checkTerraformErr
}
func (u stubUpgrader) CleanUpTerraformMigrations(file.Handler) error {
func (u stubUpgrader) CleanUpTerraformMigrations() error {
return u.cleanTerraformErr
}
@ -193,7 +193,7 @@ func (u stubUpgrader) PlanTerraformMigrations(context.Context, upgrade.Terraform
return u.terraformDiff, u.planTerraformErr
}
func (u stubUpgrader) ApplyTerraformMigrations(context.Context, file.Handler, upgrade.TerraformUpgradeOptions) error {
func (u stubUpgrader) ApplyTerraformMigrations(context.Context, upgrade.TerraformUpgradeOptions) error {
return u.applyTerraformErr
}

View File

@ -68,7 +68,7 @@ func runUpgradeCheck(cmd *cobra.Command, _ []string) error {
if err != nil {
return err
}
checker, err := kubernetes.NewUpgrader(cmd.Context(), cmd.OutOrStdout(), log, kubernetes.UpgradeCmdKindCheck)
checker, err := kubernetes.NewUpgrader(cmd.Context(), cmd.OutOrStdout(), fileHandler, log, kubernetes.UpgradeCmdKindCheck)
if err != nil {
return err
}
@ -215,7 +215,7 @@ func (u *upgradeCheckCmd) upgradeCheck(cmd *cobra.Command, fileHandler file.Hand
u.checker.AddManualStateMigration(migration)
}
if err := u.checker.CheckTerraformMigrations(fileHandler); err != nil {
if err := u.checker.CheckTerraformMigrations(); err != nil {
return fmt.Errorf("checking workspace: %w", err)
}
@ -226,13 +226,12 @@ func (u *upgradeCheckCmd) upgradeCheck(cmd *cobra.Command, fileHandler file.Hand
u.log.Debugf("Using Terraform variables:\n%v", vars)
opts := upgrade.TerraformUpgradeOptions{
LogLevel: flags.terraformLogLevel,
CSP: conf.GetProvider(),
Vars: vars,
OutputFile: constants.TerraformMigrationOutputFile,
LogLevel: flags.terraformLogLevel,
CSP: conf.GetProvider(),
Vars: vars,
}
cmd.Println("The following Teraform migrations are available with this CLI:")
cmd.Println("The following Terraform migrations are available with this CLI:")
// Check if there are any Terraform migrations
hasDiff, err := u.checker.PlanTerraformMigrations(cmd.Context(), opts)
@ -240,7 +239,7 @@ func (u *upgradeCheckCmd) upgradeCheck(cmd *cobra.Command, fileHandler file.Hand
return fmt.Errorf("planning terraform migrations: %w", err)
}
defer func() {
if err := u.checker.CleanUpTerraformMigrations(fileHandler); err != nil {
if err := u.checker.CleanUpTerraformMigrations(); err != nil {
u.log.Debugf("Failed to clean up Terraform migrations: %v", err)
}
}()
@ -738,8 +737,8 @@ type upgradeChecker interface {
CurrentImage(ctx context.Context) (string, error)
CurrentKubernetesVersion(ctx context.Context) (string, error)
PlanTerraformMigrations(ctx context.Context, opts upgrade.TerraformUpgradeOptions) (bool, error)
CheckTerraformMigrations(fileHandler file.Handler) error
CleanUpTerraformMigrations(fileHandler file.Handler) error
CheckTerraformMigrations() error
CleanUpTerraformMigrations() error
AddManualStateMigration(migration terraform.StateMigration)
}

View File

@ -377,11 +377,11 @@ func (u stubUpgradeChecker) PlanTerraformMigrations(context.Context, upgrade.Ter
return u.tfDiff, u.err
}
func (u stubUpgradeChecker) CheckTerraformMigrations(file.Handler) error {
func (u stubUpgradeChecker) CheckTerraformMigrations() error {
return u.err
}
func (u stubUpgradeChecker) CleanUpTerraformMigrations(file.Handler) error {
func (u stubUpgradeChecker) CleanUpTerraformMigrations() error {
return u.err
}

View File

@ -97,7 +97,7 @@ type Upgrader struct {
}
// NewUpgrader returns a new Upgrader.
func NewUpgrader(ctx context.Context, outWriter io.Writer, log debugLog, upgradeCmdKind UpgradeCmdKind) (*Upgrader, error) {
func NewUpgrader(ctx context.Context, outWriter io.Writer, fileHandler file.Handler, log debugLog, upgradeCmdKind UpgradeCmdKind) (*Upgrader, error) {
upgradeID := "upgrade-" + time.Now().Format("20060102150405") + "-" + strings.Split(uuid.New().String(), "-")[0]
if upgradeCmdKind == UpgradeCmdKindCheck {
// When performing an upgrade check, the upgrade directory will only be used temporarily to store the
@ -143,7 +143,7 @@ func NewUpgrader(ctx context.Context, outWriter io.Writer, log debugLog, upgrade
}
u.tfClient = tfClient
tfUpgrader, err := upgrade.NewTerraformUpgrader(tfClient, outWriter)
tfUpgrader, err := upgrade.NewTerraformUpgrader(tfClient, outWriter, fileHandler)
if err != nil {
return nil, fmt.Errorf("setting up terraform upgrader: %w", err)
}
@ -160,14 +160,14 @@ func (u *Upgrader) AddManualStateMigration(migration terraform.StateMigration) {
// CheckTerraformMigrations checks whether Terraform migrations are possible in the current workspace.
// If the files that will be written during the upgrade already exist, it returns an error.
func (u *Upgrader) CheckTerraformMigrations(fileHandler file.Handler) error {
return u.tfUpgrader.CheckTerraformMigrations(fileHandler, u.upgradeID)
func (u *Upgrader) CheckTerraformMigrations() error {
return u.tfUpgrader.CheckTerraformMigrations(u.upgradeID)
}
// CleanUpTerraformMigrations cleans up the Terraform migration workspace, for example when an upgrade is
// aborted by the user.
func (u *Upgrader) CleanUpTerraformMigrations(fileHandler file.Handler) error {
return u.tfUpgrader.CleanUpTerraformMigrations(fileHandler, u.upgradeID)
func (u *Upgrader) CleanUpTerraformMigrations() error {
return u.tfUpgrader.CleanUpTerraformMigrations(u.upgradeID)
}
// PlanTerraformMigrations prepares the upgrade workspace and plans the Terraform migrations for the Constellation upgrade.
@ -181,8 +181,8 @@ func (u *Upgrader) PlanTerraformMigrations(ctx context.Context, opts upgrade.Ter
// If PlanTerraformMigrations has not been executed before, it will return an error.
// In case of a successful upgrade, the output will be written to the specified file and the old Terraform directory is replaced
// By the new one.
func (u *Upgrader) ApplyTerraformMigrations(ctx context.Context, fileHandler file.Handler, opts upgrade.TerraformUpgradeOptions) error {
return u.tfUpgrader.ApplyTerraformMigrations(ctx, fileHandler, opts, u.upgradeID)
func (u *Upgrader) ApplyTerraformMigrations(ctx context.Context, opts upgrade.TerraformUpgradeOptions) error {
return u.tfUpgrader.ApplyTerraformMigrations(ctx, opts, u.upgradeID)
}
// UpgradeHelmServices upgrade helm services.

View File

@ -23,11 +23,12 @@ import (
)
// NewTerraformUpgrader returns a new TerraformUpgrader.
func NewTerraformUpgrader(tfClient tfClient, outWriter io.Writer) (*TerraformUpgrader, error) {
func NewTerraformUpgrader(tfClient tfClient, outWriter io.Writer, fileHandler file.Handler) (*TerraformUpgrader, error) {
return &TerraformUpgrader{
tf: tfClient,
policyPatcher: cloudcmd.NewAzurePolicyPatcher(),
outWriter: outWriter,
fileHandler: fileHandler,
}, nil
}
@ -36,6 +37,7 @@ type TerraformUpgrader struct {
tf tfClient
policyPatcher policyPatcher
outWriter io.Writer
fileHandler file.Handler
}
// TerraformUpgradeOptions are the options used for the Terraform upgrade.
@ -46,21 +48,18 @@ type TerraformUpgradeOptions struct {
CSP cloudprovider.Provider
// Vars are the Terraform variables used for the upgrade.
Vars terraform.Variables
// OutputFile is the file to write the Terraform output to.
OutputFile string
}
// CheckTerraformMigrations checks whether Terraform migrations are possible in the current workspace.
// If the files that will be written during the upgrade already exist, it returns an error.
func (u *TerraformUpgrader) CheckTerraformMigrations(fileHandler file.Handler, upgradeID string) error {
func (u *TerraformUpgrader) CheckTerraformMigrations(upgradeID string) error {
var existingFiles []string
filesToCheck := []string{
constants.TerraformMigrationOutputFile,
filepath.Join(constants.UpgradeDir, upgradeID, constants.TerraformUpgradeBackupDir),
}
for _, f := range filesToCheck {
if err := checkFileExists(fileHandler, &existingFiles, f); err != nil {
if err := checkFileExists(u.fileHandler, &existingFiles, f); err != nil {
return fmt.Errorf("checking terraform migrations: %w", err)
}
}
@ -89,6 +88,7 @@ func checkFileExists(fileHandler file.Handler, existingFiles *[]string, filename
// If a diff exists, it's being written to the upgrader's output writer. It also returns
// a bool indicating whether a diff exists.
func (u *TerraformUpgrader) PlanTerraformMigrations(ctx context.Context, opts TerraformUpgradeOptions, upgradeID string) (bool, error) {
// Prepare the new Terraform workspace and backup the old one
err := u.tf.PrepareUpgradeWorkspace(
filepath.Join("terraform", strings.ToLower(opts.CSP.String())),
constants.TerraformWorkingDir,
@ -100,6 +100,14 @@ func (u *TerraformUpgrader) PlanTerraformMigrations(ctx context.Context, opts Te
return false, fmt.Errorf("preparing terraform workspace: %w", err)
}
// Backup the old constellation-id.json file
if err := u.fileHandler.CopyFile(
constants.ClusterIDsFileName,
filepath.Join(constants.UpgradeDir, upgradeID, constants.ClusterIDsFileName+".old"),
); err != nil {
return false, fmt.Errorf("backing up %s: %w", constants.ClusterIDsFileName, err)
}
hasDiff, err := u.tf.Plan(ctx, opts.LogLevel, constants.TerraformUpgradePlanFile)
if err != nil {
return false, fmt.Errorf("terraform plan: %w", err)
@ -116,13 +124,13 @@ func (u *TerraformUpgrader) PlanTerraformMigrations(ctx context.Context, opts Te
// CleanUpTerraformMigrations cleans up the Terraform migration workspace, for example when an upgrade is
// aborted by the user.
func (u *TerraformUpgrader) CleanUpTerraformMigrations(fileHandler file.Handler, upgradeID string) error {
func (u *TerraformUpgrader) CleanUpTerraformMigrations(upgradeID string) error {
cleanupFiles := []string{
filepath.Join(constants.UpgradeDir, upgradeID),
}
for _, f := range cleanupFiles {
if err := fileHandler.RemoveAll(f); err != nil {
if err := u.fileHandler.RemoveAll(f); err != nil {
return fmt.Errorf("cleaning up file %s: %w", f, err)
}
}
@ -134,7 +142,7 @@ func (u *TerraformUpgrader) CleanUpTerraformMigrations(fileHandler file.Handler,
// If PlanTerraformMigrations has not been executed before, it will return an error.
// In case of a successful upgrade, the output will be written to the specified file and the old Terraform directory is replaced
// By the new one.
func (u *TerraformUpgrader) ApplyTerraformMigrations(ctx context.Context, fileHandler file.Handler, opts TerraformUpgradeOptions, upgradeID string) error {
func (u *TerraformUpgrader) ApplyTerraformMigrations(ctx context.Context, opts TerraformUpgradeOptions, upgradeID string) error {
tfOutput, err := u.tf.CreateCluster(ctx, opts.LogLevel)
if err != nil {
return fmt.Errorf("terraform apply: %w", err)
@ -155,20 +163,34 @@ func (u *TerraformUpgrader) ApplyTerraformMigrations(ctx context.Context, fileHa
AttestationURL: tfOutput.AttestationURL,
}
if err := fileHandler.RemoveAll(constants.TerraformWorkingDir); err != nil {
if err := u.fileHandler.RemoveAll(constants.TerraformWorkingDir); err != nil {
return fmt.Errorf("removing old terraform directory: %w", err)
}
if err := fileHandler.CopyDir(filepath.Join(constants.UpgradeDir, upgradeID, constants.TerraformUpgradeWorkingDir), constants.TerraformWorkingDir); err != nil {
if err := u.fileHandler.CopyDir(filepath.Join(constants.UpgradeDir, upgradeID, constants.TerraformUpgradeWorkingDir), constants.TerraformWorkingDir); err != nil {
return fmt.Errorf("replacing old terraform directory with new one: %w", err)
}
if err := fileHandler.RemoveAll(filepath.Join(constants.UpgradeDir, upgradeID, constants.TerraformUpgradeWorkingDir)); err != nil {
if err := u.fileHandler.RemoveAll(filepath.Join(constants.UpgradeDir, upgradeID, constants.TerraformUpgradeWorkingDir)); err != nil {
return fmt.Errorf("removing terraform upgrade directory: %w", err)
}
if err := fileHandler.WriteJSON(opts.OutputFile, outputFileContents); err != nil {
return fmt.Errorf("writing terraform output to file: %w", err)
if err := u.mergeClusterIDFile(outputFileContents); err != nil {
return fmt.Errorf("merging migration output into %s: %w", constants.ClusterIDsFileName, err)
}
return nil
}
// mergeClusterIDFile merges the output of the migration into the constellation-id.json file.
func (u *TerraformUpgrader) mergeClusterIDFile(migrationOutput clusterid.File) error {
idFile := &clusterid.File{}
if err := u.fileHandler.ReadJSON(constants.ClusterIDsFileName, idFile); err != nil {
return fmt.Errorf("reading %s: %w", constants.ClusterIDsFileName, err)
}
if err := u.fileHandler.WriteJSON(constants.ClusterIDsFileName, idFile.Merge(migrationOutput), file.OptOverwrite); err != nil {
return fmt.Errorf("writing %s: %w", constants.ClusterIDsFileName, err)
}
return nil

View File

@ -23,8 +23,8 @@ import (
)
func TestCheckTerraformMigrations(t *testing.T) {
upgrader := func() *TerraformUpgrader {
u, err := NewTerraformUpgrader(&stubTerraformClient{}, bytes.NewBuffer(nil))
upgrader := func(fileHandler file.Handler) *TerraformUpgrader {
u, err := NewTerraformUpgrader(&stubTerraformClient{}, bytes.NewBuffer(nil), fileHandler)
require.NoError(t, err)
return u
@ -48,11 +48,6 @@ func TestCheckTerraformMigrations(t *testing.T) {
upgradeID: "1234",
workspace: workspace(nil),
},
"migration output file already exists": {
upgradeID: "1234",
workspace: workspace([]string{constants.TerraformMigrationOutputFile}),
wantErr: true,
},
"terraform backup dir already exists": {
upgradeID: "1234",
workspace: workspace([]string{filepath.Join(constants.UpgradeDir, "1234", constants.TerraformUpgradeBackupDir)}),
@ -62,8 +57,8 @@ func TestCheckTerraformMigrations(t *testing.T) {
for name, tc := range testCases {
t.Run(name, func(t *testing.T) {
u := upgrader()
err := u.CheckTerraformMigrations(tc.workspace, tc.upgradeID)
u := upgrader(tc.workspace)
err := u.CheckTerraformMigrations(tc.upgradeID)
if tc.wantErr {
require.Error(t, err)
return
@ -75,48 +70,74 @@ func TestCheckTerraformMigrations(t *testing.T) {
}
func TestPlanTerraformMigrations(t *testing.T) {
upgrader := func(tf tfClient) *TerraformUpgrader {
u, err := NewTerraformUpgrader(tf, bytes.NewBuffer(nil))
upgrader := func(tf tfClient, fileHandler file.Handler) *TerraformUpgrader {
u, err := NewTerraformUpgrader(tf, bytes.NewBuffer(nil), fileHandler)
require.NoError(t, err)
return u
}
workspace := func(existingFiles []string) file.Handler {
fs := afero.NewMemMapFs()
for _, f := range existingFiles {
require.NoError(t, afero.WriteFile(fs, f, []byte{}, 0o644))
}
return file.NewHandler(fs)
}
testCases := map[string]struct {
upgradeID string
tf tfClient
workspace file.Handler
want bool
wantErr bool
}{
"success no diff": {
upgradeID: "1234",
tf: &stubTerraformClient{},
workspace: workspace([]string{constants.ClusterIDsFileName}),
},
"success diff": {
upgradeID: "1234",
tf: &stubTerraformClient{
hasDiff: true,
},
want: true,
workspace: workspace([]string{constants.ClusterIDsFileName}),
want: true,
},
"prepare workspace error": {
upgradeID: "1234",
tf: &stubTerraformClient{
prepareWorkspaceErr: assert.AnError,
},
wantErr: true,
workspace: workspace([]string{constants.ClusterIDsFileName}),
wantErr: true,
},
"constellation-id.json does not exist": {
upgradeID: "1234",
tf: &stubTerraformClient{},
workspace: workspace(nil),
wantErr: true,
},
"constellation-id backup already exists": {
upgradeID: "1234",
tf: &stubTerraformClient{},
workspace: workspace([]string{filepath.Join(constants.UpgradeDir, "1234", constants.ClusterIDsFileName+".old")}),
wantErr: true,
},
"plan error": {
tf: &stubTerraformClient{
planErr: assert.AnError,
},
wantErr: true,
workspace: workspace([]string{constants.ClusterIDsFileName}),
wantErr: true,
},
"show plan error no diff": {
upgradeID: "1234",
tf: &stubTerraformClient{
showErr: assert.AnError,
},
workspace: workspace([]string{constants.ClusterIDsFileName}),
},
"show plan error diff": {
upgradeID: "1234",
@ -124,7 +145,8 @@ func TestPlanTerraformMigrations(t *testing.T) {
showErr: assert.AnError,
hasDiff: true,
},
wantErr: true,
workspace: workspace([]string{constants.ClusterIDsFileName}),
wantErr: true,
},
}
@ -132,7 +154,7 @@ func TestPlanTerraformMigrations(t *testing.T) {
t.Run(name, func(t *testing.T) {
require := require.New(t)
u := upgrader(tc.tf)
u := upgrader(tc.tf, tc.workspace)
opts := TerraformUpgradeOptions{
LogLevel: terraform.LogLevelDebug,
@ -152,8 +174,8 @@ func TestPlanTerraformMigrations(t *testing.T) {
}
func TestApplyTerraformMigrations(t *testing.T) {
upgrader := func(tf tfClient) *TerraformUpgrader {
u, err := NewTerraformUpgrader(tf, bytes.NewBuffer(nil))
upgrader := func(tf tfClient, fileHandler file.Handler) *TerraformUpgrader {
u, err := NewTerraformUpgrader(tf, bytes.NewBuffer(nil), fileHandler)
require.NoError(t, err)
return u
@ -161,6 +183,7 @@ func TestApplyTerraformMigrations(t *testing.T) {
fileHandler := func(upgradeID string, existingFiles ...string) file.Handler {
fh := file.NewHandler(afero.NewMemMapFs())
require.NoError(t,
fh.Write(
filepath.Join(constants.UpgradeDir, upgradeID, constants.TerraformUpgradeWorkingDir, "someFile"),
@ -173,54 +196,35 @@ func TestApplyTerraformMigrations(t *testing.T) {
}
testCases := map[string]struct {
upgradeID string
tf tfClient
policyPatcher stubPolicyPatcher
fs file.Handler
outputFileName string
wantErr bool
upgradeID string
tf tfClient
policyPatcher stubPolicyPatcher
fs file.Handler
skipIDFileCreation bool // if true, do not create the constellation-id.json file
wantErr bool
}{
"success": {
upgradeID: "1234",
tf: &stubTerraformClient{},
fs: fileHandler("1234"),
policyPatcher: stubPolicyPatcher{},
outputFileName: "test.json",
upgradeID: "1234",
tf: &stubTerraformClient{},
fs: fileHandler("1234"),
policyPatcher: stubPolicyPatcher{},
},
"create cluster error": {
upgradeID: "1234",
tf: &stubTerraformClient{
CreateClusterErr: assert.AnError,
},
fs: fileHandler("1234"),
policyPatcher: stubPolicyPatcher{},
outputFileName: "test.json",
wantErr: true,
fs: fileHandler("1234"),
policyPatcher: stubPolicyPatcher{},
wantErr: true,
},
"patch error": {
upgradeID: "1234",
tf: &stubTerraformClient{},
fs: fileHandler("1234"),
policyPatcher: stubPolicyPatcher{
patchErr: assert.AnError,
},
wantErr: true,
},
"empty file name": {
upgradeID: "1234",
tf: &stubTerraformClient{},
fs: fileHandler("1234"),
policyPatcher: stubPolicyPatcher{},
outputFileName: "",
wantErr: true,
},
"file already exists": {
upgradeID: "1234",
tf: &stubTerraformClient{},
fs: fileHandler("1234", "test.json"),
policyPatcher: stubPolicyPatcher{},
outputFileName: "test.json",
wantErr: true,
"constellation-id.json does not exist": {
upgradeID: "1234",
tf: &stubTerraformClient{},
fs: fileHandler("1234"),
policyPatcher: stubPolicyPatcher{},
skipIDFileCreation: true,
wantErr: true,
},
}
@ -228,16 +232,23 @@ func TestApplyTerraformMigrations(t *testing.T) {
t.Run(name, func(t *testing.T) {
require := require.New(t)
u := upgrader(tc.tf)
u := upgrader(tc.tf, tc.fs)
opts := TerraformUpgradeOptions{
LogLevel: terraform.LogLevelDebug,
CSP: cloudprovider.Unknown,
Vars: &terraform.QEMUVariables{},
OutputFile: tc.outputFileName,
if !tc.skipIDFileCreation {
require.NoError(
tc.fs.Write(
filepath.Join(constants.ClusterIDsFileName),
[]byte("{}"),
))
}
err := u.ApplyTerraformMigrations(context.Background(), tc.fs, opts, tc.upgradeID)
opts := TerraformUpgradeOptions{
LogLevel: terraform.LogLevelDebug,
CSP: cloudprovider.Unknown,
Vars: &terraform.QEMUVariables{},
}
err := u.ApplyTerraformMigrations(context.Background(), opts, tc.upgradeID)
if tc.wantErr {
require.Error(err)
} else {
@ -248,8 +259,8 @@ func TestApplyTerraformMigrations(t *testing.T) {
}
func TestCleanUpTerraformMigrations(t *testing.T) {
upgrader := func() *TerraformUpgrader {
u, err := NewTerraformUpgrader(&stubTerraformClient{}, bytes.NewBuffer(nil))
upgrader := func(fileHandler file.Handler) *TerraformUpgrader {
u, err := NewTerraformUpgrader(&stubTerraformClient{}, bytes.NewBuffer(nil), fileHandler)
require.NoError(t, err)
return u
@ -315,9 +326,9 @@ func TestCleanUpTerraformMigrations(t *testing.T) {
require := require.New(t)
workspace := workspace(tc.workspaceFiles)
u := upgrader()
u := upgrader(workspace)
err := u.CleanUpTerraformMigrations(workspace, tc.upgradeID)
err := u.CleanUpTerraformMigrations(tc.upgradeID)
if tc.wantErr {
require.Error(err)
return

View File

@ -156,8 +156,6 @@ const (
TerraformUpgradeWorkingDir = "terraform"
// TerraformUpgradeBackupDir is the directory name being used to backup the pre-upgrade state in an upgrade.
TerraformUpgradeBackupDir = "terraform-backup"
// TerraformMigrationOutputFile is the file name of the output file created by a successful Terraform migration.
TerraformMigrationOutputFile = "terraform-migration-output.json"
// UpgradeDir is the name of the directory being used for cluster upgrades.
UpgradeDir = "constellation-upgrade"