diff --git a/cli/internal/cmd/create.go b/cli/internal/cmd/create.go index 4912bba82..93e46ff5f 100644 --- a/cli/internal/cmd/create.go +++ b/cli/internal/cmd/create.go @@ -12,6 +12,7 @@ import ( "io/fs" "github.com/edgelesssys/constellation/v2/cli/internal/cloudcmd" + "github.com/edgelesssys/constellation/v2/cli/internal/terraform" "github.com/edgelesssys/constellation/v2/internal/cloud/cloudprovider" "github.com/edgelesssys/constellation/v2/internal/config" "github.com/edgelesssys/constellation/v2/internal/constants" @@ -126,7 +127,7 @@ func create(cmd *cobra.Command, creator cloudCreator, fileHandler file.Handler, idFile, err := creator.Create(cmd.Context(), provider, conf, flags.name, instanceType, flags.controllerCount, flags.workerCount) spinner.Stop() if err != nil { - return err + return translateCreateErrors(cmd, err) } if err := fileHandler.WriteJSON(constants.ClusterIDsFileName, idFile, file.OptNone); err != nil { @@ -209,6 +210,27 @@ func checkDirClean(fileHandler file.Handler) error { return nil } +func translateCreateErrors(cmd *cobra.Command, err error) error { + switch { + case errors.Is(err, terraform.ErrTerraformWorkspaceDifferentFiles): + cmd.PrintErrln("\nYour current working directory contains an existing Terraform workspace which does not match the expected state.") + cmd.PrintErrln("This can be due to a mix up between providers, versions or an otherwise corrupted workspace.") + cmd.PrintErrln("Before creating a new cluster, try \"constellation terminate\".") + cmd.PrintErrf("If this does not work, either move or delete the directory %q.\n", constants.TerraformWorkingDir) + cmd.PrintErrln("Please only delete the directory if you made sure that all created cloud resources have been terminated.") + return err + case errors.Is(err, terraform.ErrTerraformWorkspaceExistsWithDifferentVariables): + cmd.PrintErrln("\nYour current working directory contains an existing Terraform workspace which was initiated with different input variables.") + cmd.PrintErrln("This can be the case if you have tried to create a cluster before with different options which did not complete, or the workspace is corrupted.") + cmd.PrintErrln("Before creating a new cluster, try \"constellation terminate\".") + cmd.PrintErrf("If this does not work, either move or delete the directory %q.\n", constants.TerraformWorkingDir) + cmd.PrintErrln("Please only delete the directory if you made sure that all created cloud resources have been terminated.") + return err + default: + return err + } +} + func must(err error) { if err != nil { panic(err) diff --git a/cli/internal/terraform/loader.go b/cli/internal/terraform/loader.go index 1fd86e080..b40aac690 100644 --- a/cli/internal/terraform/loader.go +++ b/cli/internal/terraform/loader.go @@ -10,7 +10,6 @@ import ( "bytes" "embed" "errors" - "fmt" "io/fs" "path" "path/filepath" @@ -21,6 +20,9 @@ import ( "github.com/spf13/afero" ) +// ErrTerraformWorkspaceDifferentFiles is returned when a re-used existing Terraform workspace has different files than the ones to be extracted (e.g. due to a version mix-up or incomplete writes). +var ErrTerraformWorkspaceDifferentFiles = errors.New("creating cluster: trying to overwrite an existing Terraform file with a different version") + //go:embed terraform/* //go:embed terraform/*/.terraform.lock.hcl var terraformFS embed.FS @@ -53,7 +55,7 @@ func prepareWorkspace(fileHandler file.Handler, provider cloudprovider.Provider, } if !bytes.Equal(content, existingFileContent) { - return fmt.Errorf("trying to overwrite existing Terraform file with different version") + return ErrTerraformWorkspaceDifferentFiles } return nil } else if err != nil { diff --git a/cli/internal/terraform/terraform.go b/cli/internal/terraform/terraform.go index 2fe70678f..055a7def7 100644 --- a/cli/internal/terraform/terraform.go +++ b/cli/internal/terraform/terraform.go @@ -29,6 +29,9 @@ const ( terraformVarsFile = "terraform.tfvars" ) +// ErrTerraformWorkspaceExistsWithDifferentVariables is returned when existing Terraform files differ from the version the CLI wants to extract. +var ErrTerraformWorkspaceExistsWithDifferentVariables = errors.New("creating cluster: a Terraform workspace already exists with different variables") + // Client manages interaction with Terraform. type Client struct { tf tfInterface @@ -162,7 +165,7 @@ func (c *Client) writeVars(vars Variables) error { return err } if vars.String() != string(varsContent) { - return errors.New("creating cluster: workspace already exists with different variables") + return ErrTerraformWorkspaceExistsWithDifferentVariables } } else if err != nil { return err