mirror of
https://github.com/edgelesssys/constellation.git
synced 2024-10-01 01:36:09 -04:00
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:
parent
5cbdb3a519
commit
5f71934f56
@ -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"],
|
||||
)
|
||||
|
@ -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
|
||||
}
|
||||
|
63
cli/internal/clusterid/id_test.go
Normal file
63
cli/internal/clusterid/id_test.go
Normal 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)
|
||||
}
|
||||
}
|
@ -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)
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
}
|
||||
|
||||
|
@ -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)
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
}
|
||||
|
||||
|
@ -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.
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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"
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user