From e93527144e714f667d206913c2d5cf94db0bcd81 Mon Sep 17 00:00:00 2001 From: Nils Hanke Date: Mon, 14 Nov 2022 19:15:10 +0100 Subject: [PATCH] Terraform: Try to use existing files on partially unpacked workspace --- cli/internal/terraform/loader.go | 21 ++++++++++++++++++++- cli/internal/terraform/loader_test.go | 24 +++++++++++++++++++++--- 2 files changed, 41 insertions(+), 4 deletions(-) diff --git a/cli/internal/terraform/loader.go b/cli/internal/terraform/loader.go index cb18ad098..1fd86e080 100644 --- a/cli/internal/terraform/loader.go +++ b/cli/internal/terraform/loader.go @@ -7,8 +7,10 @@ SPDX-License-Identifier: AGPL-3.0-only package terraform import ( + "bytes" "embed" "errors" + "fmt" "io/fs" "path" "path/filepath" @@ -41,7 +43,24 @@ func prepareWorkspace(fileHandler file.Handler, provider cloudprovider.Provider, return err } fileName := strings.Replace(filepath.Join(workingDir, path), rootDir+"/", "", 1) - return fileHandler.Write(fileName, content, file.OptMkdirAll) + if err := fileHandler.Write(fileName, content, file.OptMkdirAll); errors.Is(err, afero.ErrFileExists) { + // If a file already exists, check if it is identical. If yes, continue and don't write anything to disk. + // If no, don't overwrite it and instead throw an error. The affected file could be from a different version, + // provider, corrupted or manually modified in general. + existingFileContent, err := fileHandler.Read(fileName) + if err != nil { + return err + } + + if !bytes.Equal(content, existingFileContent) { + return fmt.Errorf("trying to overwrite existing Terraform file with different version") + } + return nil + } else if err != nil { + return err + } + + return nil }) } diff --git a/cli/internal/terraform/loader_test.go b/cli/internal/terraform/loader_test.go index 03b96f47f..0be642a1f 100644 --- a/cli/internal/terraform/loader_test.go +++ b/cli/internal/terraform/loader_test.go @@ -21,8 +21,9 @@ import ( func TestLoader(t *testing.T) { testCases := map[string]struct { - provider cloudprovider.Provider - fileList []string + provider cloudprovider.Provider + fileList []string + testAlreadyUnpacked bool }{ "aws": { provider: cloudprovider.AWS, @@ -51,6 +52,16 @@ func TestLoader(t *testing.T) { "modules", }, }, + "continue on (partially) unpacked": { + provider: cloudprovider.AWS, + fileList: []string{ + "main.tf", + "variables.tf", + "outputs.tf", + "modules", + }, + testAlreadyUnpacked: true, + }, } for name, tc := range testCases { @@ -62,9 +73,16 @@ func TestLoader(t *testing.T) { err := prepareWorkspace(file, tc.provider, constants.TerraformWorkingDir) require.NoError(err) - checkFiles(t, file, func(err error) { assert.NoError(err) }, 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(constants.TerraformWorkingDir, "variables.tf"))) + err := prepareWorkspace(file, tc.provider, constants.TerraformWorkingDir) + assert.NoError(err) + checkFiles(t, file, func(err error) { assert.NoError(err) }, tc.fileList) + } + err = cleanUpWorkspace(file, constants.TerraformWorkingDir) require.NoError(err)