diff --git a/cli/internal/cloudcmd/rollback.go b/cli/internal/cloudcmd/rollback.go index 42e30071c..5c2a41d78 100644 --- a/cli/internal/cloudcmd/rollback.go +++ b/cli/internal/cloudcmd/rollback.go @@ -13,11 +13,12 @@ import ( "io" "github.com/edgelesssys/constellation/v2/cli/internal/terraform" + "github.com/edgelesssys/constellation/v2/internal/constants" ) // rollbacker does a rollback. type rollbacker interface { - rollback(ctx context.Context, logLevel terraform.LogLevel) error + rollback(ctx context.Context, w io.Writer, logLevel terraform.LogLevel) error } // rollbackOnError calls rollback on the rollbacker if the handed error is not nil, @@ -28,7 +29,7 @@ func rollbackOnError(w io.Writer, onErr *error, roll rollbacker, logLevel terraf } fmt.Fprintf(w, "An error occurred: %s\n", *onErr) fmt.Fprintln(w, "Attempting to roll back.") - if err := roll.rollback(context.Background(), logLevel); err != nil { + if err := roll.rollback(context.Background(), w, logLevel); err != nil { *onErr = errors.Join(*onErr, fmt.Errorf("on rollback: %w", err)) // TODO(katexochen): print the error, or return it? return } @@ -39,8 +40,10 @@ type rollbackerTerraform struct { client tfCommonClient } -func (r *rollbackerTerraform) rollback(ctx context.Context, logLevel terraform.LogLevel) error { +func (r *rollbackerTerraform) rollback(ctx context.Context, w io.Writer, logLevel terraform.LogLevel) error { if err := r.client.Destroy(ctx, logLevel); err != nil { + fmt.Fprintf(w, "Could not destroy the resources. Please delete the %q directory manually if no resources were created\n", + constants.TerraformWorkingDir) return err } return r.client.CleanUpWorkspace() @@ -52,11 +55,13 @@ type rollbackerQEMU struct { createdWorkspace bool } -func (r *rollbackerQEMU) rollback(ctx context.Context, logLevel terraform.LogLevel) (retErr error) { +func (r *rollbackerQEMU) rollback(ctx context.Context, w io.Writer, logLevel terraform.LogLevel) (retErr error) { if r.createdWorkspace { retErr = r.client.Destroy(ctx, logLevel) } if retErr := errors.Join(retErr, r.libvirt.Stop(ctx)); retErr != nil { + fmt.Fprintf(w, "Could not destroy the resources. Please delete the %q directory manually if no resources were created\n", + constants.TerraformWorkingDir) return retErr } return r.client.CleanUpWorkspace() diff --git a/cli/internal/cloudcmd/rollback_test.go b/cli/internal/cloudcmd/rollback_test.go index 07895a1fc..fa64331bc 100644 --- a/cli/internal/cloudcmd/rollback_test.go +++ b/cli/internal/cloudcmd/rollback_test.go @@ -7,6 +7,7 @@ SPDX-License-Identifier: AGPL-3.0-only package cloudcmd import ( + "bytes" "context" "errors" "testing" @@ -19,19 +20,20 @@ func TestRollbackTerraform(t *testing.T) { someErr := errors.New("failed") testCases := map[string]struct { - tfClient *stubTerraformClient - wantErr bool + tfClient *stubTerraformClient + wantCleanupErr bool + wantDestroyErr bool }{ "success": { tfClient: &stubTerraformClient{}, }, "destroy cluster error": { - tfClient: &stubTerraformClient{destroyErr: someErr}, - wantErr: true, + tfClient: &stubTerraformClient{destroyErr: someErr}, + wantDestroyErr: true, }, "clean up workspace error": { - tfClient: &stubTerraformClient{cleanUpWorkspaceErr: someErr}, - wantErr: true, + tfClient: &stubTerraformClient{cleanUpWorkspaceErr: someErr}, + wantCleanupErr: true, }, } @@ -43,14 +45,20 @@ func TestRollbackTerraform(t *testing.T) { client: tc.tfClient, } - err := rollbacker.rollback(context.Background(), terraform.LogLevelNone) - if tc.wantErr { + destroyClusterErrOutput := &bytes.Buffer{} + err := rollbacker.rollback(context.Background(), destroyClusterErrOutput, terraform.LogLevelNone) + if tc.wantCleanupErr { assert.Error(err) if tc.tfClient.cleanUpWorkspaceErr == nil { assert.False(tc.tfClient.cleanUpWorkspaceCalled) } return } + if tc.wantDestroyErr { + assert.Error(err) + assert.Equal("Could not destroy the resources. Please delete the \"constellation-terraform\" directory manually if no resources were created\n", destroyClusterErrOutput.String()) + return + } assert.NoError(err) assert.True(tc.tfClient.destroyCalled) assert.True(tc.tfClient.cleanUpWorkspaceCalled) @@ -65,6 +73,7 @@ func TestRollbackQEMU(t *testing.T) { libvirt *stubLibvirtRunner tfClient *stubTerraformClient createdWorkspace bool + wantDestroyErr bool wantErr bool }{ "success": { @@ -78,9 +87,9 @@ func TestRollbackQEMU(t *testing.T) { wantErr: true, }, "destroy cluster error": { - libvirt: &stubLibvirtRunner{stopErr: someErr}, - tfClient: &stubTerraformClient{destroyErr: someErr}, - wantErr: true, + libvirt: &stubLibvirtRunner{stopErr: someErr}, + tfClient: &stubTerraformClient{destroyErr: someErr}, + wantDestroyErr: true, }, "clean up workspace error": { libvirt: &stubLibvirtRunner{}, @@ -99,7 +108,9 @@ func TestRollbackQEMU(t *testing.T) { createdWorkspace: tc.createdWorkspace, } - err := rollbacker.rollback(context.Background(), terraform.LogLevelNone) + destroyClusterErrOutput := &bytes.Buffer{} + + err := rollbacker.rollback(context.Background(), destroyClusterErrOutput, terraform.LogLevelNone) if tc.wantErr { assert.Error(err) if tc.tfClient.cleanUpWorkspaceErr == nil { @@ -107,6 +118,11 @@ func TestRollbackQEMU(t *testing.T) { } return } + if tc.wantDestroyErr { + assert.Error(err) + assert.Equal("Could not destroy the resources. Please delete the \"constellation-terraform\" directory manually if no resources were created\n", destroyClusterErrOutput.String()) + return + } assert.NoError(err) assert.True(tc.libvirt.stopCalled) if tc.createdWorkspace {