cli: perform upgrades in-place in Terraform workspace (#2317)

* perform upgrades in-place in terraform workspace

Signed-off-by: Moritz Sanft <58110325+msanft@users.noreply.github.com>

* update buildfiles

Signed-off-by: Moritz Sanft <58110325+msanft@users.noreply.github.com>

* add iam upgrade apply test

Signed-off-by: Moritz Sanft <58110325+msanft@users.noreply.github.com>

* update buildfiles

Signed-off-by: Moritz Sanft <58110325+msanft@users.noreply.github.com>

* fix linter

Signed-off-by: Moritz Sanft <58110325+msanft@users.noreply.github.com>

* make config fetcher stubbable

Signed-off-by: Moritz Sanft <58110325+msanft@users.noreply.github.com>

* change workspace restoring behaviour

Signed-off-by: Moritz Sanft <58110325+msanft@users.noreply.github.com>

* allow overwriting existing Terraform files

Signed-off-by: Moritz Sanft <58110325+msanft@users.noreply.github.com>

* allow overwrites of TF variables

Signed-off-by: Moritz Sanft <58110325+msanft@users.noreply.github.com>

* fix iam upgrade apply

Signed-off-by: Moritz Sanft <58110325+msanft@users.noreply.github.com>

* fix embed directive

Signed-off-by: Moritz Sanft <58110325+msanft@users.noreply.github.com>

* make loader test less brittle

Signed-off-by: Moritz Sanft <58110325+msanft@users.noreply.github.com>

* pass upgrade ID to user

Signed-off-by: Moritz Sanft <58110325+msanft@users.noreply.github.com>

* naming nit

Signed-off-by: Moritz Sanft <58110325+msanft@users.noreply.github.com>

* use upgradeDir

Signed-off-by: Moritz Sanft <58110325+msanft@users.noreply.github.com>

* tidy

Signed-off-by: Moritz Sanft <58110325+msanft@users.noreply.github.com>

---------

Signed-off-by: Moritz Sanft <58110325+msanft@users.noreply.github.com>
This commit is contained in:
Moritz Sanft 2023-09-14 11:51:20 +02:00 committed by GitHub
parent 9c54ff06e0
commit 95cf4bdf21
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
19 changed files with 410 additions and 286 deletions

View file

@ -20,6 +20,8 @@ import (
"github.com/stretchr/testify/require"
)
var oldFileContent = []byte("1234")
func TestPrepareWorkspace(t *testing.T) {
testCases := map[string]struct {
pathBase string
@ -109,20 +111,20 @@ func TestPrepareWorkspace(t *testing.T) {
err := prepareWorkspace(path, file, testWorkspace)
require.NoError(err)
checkFiles(t, file, func(err error) { assert.NoError(err) }, testWorkspace, tc.fileList)
checkFiles(t, file, func(err error) { assert.NoError(err) }, nil, testWorkspace, tc.fileList)
if tc.testAlreadyUnpacked {
// Let's try the same again and check if we don't get a "file already exists" error.
require.NoError(file.Remove(filepath.Join(testWorkspace, "variables.tf")))
err := prepareWorkspace(path, file, testWorkspace)
assert.NoError(err)
checkFiles(t, file, func(err error) { assert.NoError(err) }, testWorkspace, tc.fileList)
checkFiles(t, file, func(err error) { assert.NoError(err) }, nil, testWorkspace, tc.fileList)
}
err = cleanUpWorkspace(file, testWorkspace)
require.NoError(err)
checkFiles(t, file, func(err error) { assert.ErrorIs(err, fs.ErrNotExist) }, testWorkspace, tc.fileList)
checkFiles(t, file, func(err error) { assert.ErrorIs(err, fs.ErrNotExist) }, nil, testWorkspace, tc.fileList)
})
}
}
@ -131,49 +133,56 @@ func TestPrepareUpgradeWorkspace(t *testing.T) {
testCases := map[string]struct {
pathBase string
provider cloudprovider.Provider
oldWorkingDir string
newWorkingDir string
workingDir string
backupDir string
oldWorkspaceFiles []string
newWorkspaceFiles []string
workspaceFiles []string
expectedFiles []string
expectedBackupFiles []string
testAlreadyUnpacked bool
wantErr bool
}{
"works": {
pathBase: "terraform",
provider: cloudprovider.AWS,
oldWorkingDir: "old",
newWorkingDir: "new",
backupDir: "backup",
oldWorkspaceFiles: []string{"terraform.tfstate"},
pathBase: "terraform",
provider: cloudprovider.AWS,
workingDir: "working",
backupDir: "backup",
workspaceFiles: []string{"main.tf", "variables.tf", "outputs.tf"},
expectedFiles: []string{
"main.tf",
"variables.tf",
"outputs.tf",
"modules",
"terraform.tfstate",
},
expectedBackupFiles: []string{
"main.tf",
"variables.tf",
"outputs.tf",
},
},
"state file does not exist": {
pathBase: "terraform",
provider: cloudprovider.AWS,
oldWorkingDir: "old",
newWorkingDir: "new",
backupDir: "backup",
oldWorkspaceFiles: []string{},
expectedFiles: []string{},
wantErr: true,
pathBase: "terraform",
provider: cloudprovider.AWS,
workingDir: "working",
backupDir: "backup",
workspaceFiles: []string{},
expectedFiles: []string{},
wantErr: true,
},
"terraform files already exist in new dir": {
pathBase: "terraform",
provider: cloudprovider.AWS,
oldWorkingDir: "old",
newWorkingDir: "new",
backupDir: "backup",
oldWorkspaceFiles: []string{"terraform.tfstate"},
newWorkspaceFiles: []string{"main.tf"},
wantErr: true,
"terraform file already exists in working dir (overwrite)": {
pathBase: "terraform",
provider: cloudprovider.AWS,
workingDir: "working",
backupDir: "backup",
workspaceFiles: []string{"main.tf", "variables.tf", "outputs.tf"},
expectedFiles: []string{
"main.tf",
"variables.tf",
"outputs.tf",
},
expectedBackupFiles: []string{
"main.tf",
"variables.tf",
"outputs.tf",
},
},
}
@ -186,31 +195,44 @@ func TestPrepareUpgradeWorkspace(t *testing.T) {
path := path.Join(tc.pathBase, strings.ToLower(tc.provider.String()))
createFiles(t, file, tc.oldWorkspaceFiles, tc.oldWorkingDir)
createFiles(t, file, tc.newWorkspaceFiles, tc.newWorkingDir)
createFiles(t, file, tc.workspaceFiles, tc.workingDir)
err := prepareUpgradeWorkspace(path, file, tc.oldWorkingDir, tc.newWorkingDir, tc.backupDir)
err := prepareUpgradeWorkspace(path, file, tc.workingDir, tc.backupDir)
if tc.wantErr {
require.Error(err)
} else {
require.NoError(err)
checkFiles(
t, file,
func(err error) { assert.NoError(err) },
func(content []byte) { assert.NotEqual(oldFileContent, content) },
tc.workingDir, tc.expectedFiles,
)
checkFiles(
t, file,
func(err error) { assert.NoError(err) },
func(content []byte) { assert.Equal(oldFileContent, content) },
tc.backupDir, tc.expectedBackupFiles,
)
}
checkFiles(t, file, func(err error) { assert.NoError(err) }, tc.newWorkingDir, tc.expectedFiles)
checkFiles(t, file, func(err error) { assert.NoError(err) },
tc.backupDir,
tc.oldWorkspaceFiles,
)
})
}
}
func checkFiles(t *testing.T, fileHandler file.Handler, assertion func(error), dir string, files []string) {
func checkFiles(t *testing.T, fileHandler file.Handler, assertion func(error), contentExpection func(content []byte), dir string, files []string) {
t.Helper()
for _, f := range files {
path := filepath.Join(dir, f)
_, err := fileHandler.Stat(path)
assertion(err)
if err == nil {
content, err := fileHandler.Read(path)
assertion(err)
if contentExpection != nil {
contentExpection(content)
}
}
}
}
@ -220,7 +242,7 @@ func createFiles(t *testing.T, fileHandler file.Handler, fileList []string, targ
for _, f := range fileList {
path := filepath.Join(targetDir, f)
err := fileHandler.Write(path, []byte("1234"), file.OptOverwrite, file.OptMkdirAll)
err := fileHandler.Write(path, oldFileContent, file.OptOverwrite, file.OptMkdirAll)
require.NoError(err)
}
}