2023-02-24 05:36:41 -05:00
/ *
Copyright ( c ) Edgeless Systems GmbH
SPDX - License - Identifier : AGPL - 3.0 - only
* /
package cmd
import (
"errors"
"fmt"
"os"
"github.com/edgelesssys/constellation/v2/cli/internal/cloudcmd"
"github.com/edgelesssys/constellation/v2/internal/cloud/gcpshared"
"github.com/edgelesssys/constellation/v2/internal/constants"
"github.com/edgelesssys/constellation/v2/internal/file"
"github.com/spf13/afero"
"github.com/spf13/cobra"
2023-10-16 09:05:29 -04:00
"github.com/spf13/pflag"
2023-02-24 05:36:41 -05:00
)
2023-02-28 03:52:32 -05:00
// NewIAMDestroyCmd returns a new cobra.Command for the iam destroy subcommand.
func newIAMDestroyCmd ( ) * cobra . Command {
cmd := & cobra . Command {
Use : "destroy" ,
Short : "Destroy an IAM configuration and delete local Terraform files" ,
Long : "Destroy an IAM configuration and delete local Terraform files." ,
Args : cobra . ExactArgs ( 0 ) ,
RunE : runIAMDestroy ,
}
cmd . Flags ( ) . BoolP ( "yes" , "y" , false , "destroy the IAM configuration without asking for confirmation" )
return cmd
}
2023-10-16 09:05:29 -04:00
type iamDestroyFlags struct {
rootFlags
yes bool
}
func ( f * iamDestroyFlags ) parse ( flags * pflag . FlagSet ) error {
if err := f . rootFlags . parse ( flags ) ; err != nil {
return err
}
yes , err := flags . GetBool ( "yes" )
if err != nil {
return fmt . Errorf ( "getting 'yes' flag: %w" , err )
}
f . yes = yes
return nil
}
2023-03-20 06:03:36 -04:00
func runIAMDestroy ( cmd * cobra . Command , _ [ ] string ) error {
2023-02-24 05:36:41 -05:00
log , err := newCLILogger ( cmd )
if err != nil {
return fmt . Errorf ( "creating logger: %w" , err )
}
defer log . Sync ( )
spinner := newSpinner ( cmd . ErrOrStderr ( ) )
2023-08-04 07:53:51 -04:00
destroyer := cloudcmd . NewIAMDestroyer ( )
2023-02-24 05:36:41 -05:00
fsHandler := file . NewHandler ( afero . NewOsFs ( ) )
c := & destroyCmd { log : log }
2023-10-16 09:05:29 -04:00
if err := c . flags . parse ( cmd . Flags ( ) ) ; err != nil {
return err
}
2023-02-24 05:36:41 -05:00
return c . iamDestroy ( cmd , spinner , destroyer , fsHandler )
}
type destroyCmd struct {
2023-10-16 09:05:29 -04:00
log debugLog
flags iamDestroyFlags
2023-02-24 05:36:41 -05:00
}
func ( c * destroyCmd ) iamDestroy ( cmd * cobra . Command , spinner spinnerInterf , destroyer iamDestroyer , fsHandler file . Handler ) error {
// check if there is a possibility that the cluster is still running by looking out for specific files
2023-10-16 09:05:29 -04:00
c . log . Debugf ( "Checking if %q exists" , c . flags . pathPrefixer . PrefixPrintablePath ( constants . AdminConfFilename ) )
if _ , err := fsHandler . Stat ( constants . AdminConfFilename ) ; ! errors . Is ( err , os . ErrNotExist ) {
return fmt . Errorf ( "file %q still exists, please make sure to terminate your cluster before destroying your IAM configuration" , c . flags . pathPrefixer . PrefixPrintablePath ( constants . AdminConfFilename ) )
2023-02-24 05:36:41 -05:00
}
2023-10-16 09:05:29 -04:00
c . log . Debugf ( "Checking if %q exists" , c . flags . pathPrefixer . PrefixPrintablePath ( constants . StateFilename ) )
if _ , err := fsHandler . Stat ( constants . StateFilename ) ; ! errors . Is ( err , os . ErrNotExist ) {
return fmt . Errorf ( "file %q still exists, please make sure to terminate your cluster before destroying your IAM configuration" , c . flags . pathPrefixer . PrefixPrintablePath ( constants . StateFilename ) )
2023-02-24 05:36:41 -05:00
}
gcpFileExists := false
2023-10-16 09:05:29 -04:00
c . log . Debugf ( "Checking if %q exists" , c . flags . pathPrefixer . PrefixPrintablePath ( constants . GCPServiceAccountKeyFilename ) )
if _ , err := fsHandler . Stat ( constants . GCPServiceAccountKeyFilename ) ; err != nil {
2023-02-24 05:36:41 -05:00
if ! errors . Is ( err , os . ErrNotExist ) {
return err
}
} else {
2023-10-16 09:05:29 -04:00
c . log . Debugf ( "%q exists" , c . flags . pathPrefixer . PrefixPrintablePath ( constants . GCPServiceAccountKeyFilename ) )
2023-02-24 05:36:41 -05:00
gcpFileExists = true
}
2023-10-16 09:05:29 -04:00
if ! c . flags . yes {
2023-02-24 05:36:41 -05:00
// Confirmation
2023-04-19 02:30:11 -04:00
confirmString := "Do you really want to destroy your IAM configuration? Note that this will remove all resources in the resource group."
2023-02-24 05:36:41 -05:00
if gcpFileExists {
2023-10-16 09:05:29 -04:00
confirmString += fmt . Sprintf ( "\nThis will also delete %q" , c . flags . pathPrefixer . PrefixPrintablePath ( constants . GCPServiceAccountKeyFilename ) )
2023-02-24 05:36:41 -05:00
}
ok , err := askToConfirm ( cmd , confirmString )
if err != nil {
return err
}
if ! ok {
cmd . Println ( "The destruction of the IAM configuration was aborted" )
return nil
}
}
if gcpFileExists {
2023-10-16 09:05:29 -04:00
c . log . Debugf ( "Starting to delete %q" , c . flags . pathPrefixer . PrefixPrintablePath ( constants . GCPServiceAccountKeyFilename ) )
2023-08-08 09:42:06 -04:00
proceed , err := c . deleteGCPServiceAccountKeyFile ( cmd , destroyer , fsHandler )
2023-02-24 05:36:41 -05:00
if err != nil {
return err
}
if ! proceed {
cmd . Println ( "Destruction was aborted" )
return nil
}
}
c . log . Debugf ( "Starting to destroy IAM configuration" )
spinner . Start ( "Destroying IAM configuration" , false )
defer spinner . Stop ( )
2023-10-16 09:05:29 -04:00
if err := destroyer . DestroyIAMConfiguration ( cmd . Context ( ) , constants . TerraformIAMWorkingDir , c . flags . tfLogLevel ) ; err != nil {
2023-02-24 05:36:41 -05:00
return fmt . Errorf ( "destroying IAM configuration: %w" , err )
}
spinner . Stop ( ) // stop the spinner to print a new line
fmt . Println ( "Successfully destroyed IAM configuration" )
return nil
}
2023-08-08 09:42:06 -04:00
func ( c * destroyCmd ) deleteGCPServiceAccountKeyFile ( cmd * cobra . Command , destroyer iamDestroyer , fsHandler file . Handler ) ( bool , error ) {
2023-02-24 05:36:41 -05:00
var fileSaKey gcpshared . ServiceAccountKey
2023-10-16 09:05:29 -04:00
c . log . Debugf ( "Parsing %q" , c . flags . pathPrefixer . PrefixPrintablePath ( constants . GCPServiceAccountKeyFilename ) )
2023-08-08 09:42:06 -04:00
if err := fsHandler . ReadJSON ( constants . GCPServiceAccountKeyFilename , & fileSaKey ) ; err != nil {
2023-02-24 05:36:41 -05:00
return false , err
}
c . log . Debugf ( "Getting service account key from the tfstate" )
2023-08-04 07:53:51 -04:00
tfSaKey , err := destroyer . GetTfStateServiceAccountKey ( cmd . Context ( ) , constants . TerraformIAMWorkingDir )
2023-02-24 05:36:41 -05:00
if err != nil {
return false , err
}
c . log . Debugf ( "Checking if keys are the same" )
if tfSaKey != fileSaKey {
2023-10-16 09:05:29 -04:00
cmd . Printf (
"The key in %q don't match up with your Terraform state. %q will not be deleted.\n" ,
c . flags . pathPrefixer . PrefixPrintablePath ( constants . GCPServiceAccountKeyFilename ) ,
c . flags . pathPrefixer . PrefixPrintablePath ( constants . GCPServiceAccountKeyFilename ) ,
)
2023-02-24 05:36:41 -05:00
return true , nil
}
2023-08-08 09:42:06 -04:00
if err := fsHandler . Remove ( constants . GCPServiceAccountKeyFilename ) ; err != nil {
2023-02-24 05:36:41 -05:00
return false , err
}
2023-10-16 09:05:29 -04:00
c . log . Debugf ( "Successfully deleted %q" , c . flags . pathPrefixer . PrefixPrintablePath ( constants . GCPServiceAccountKeyFilename ) )
2023-02-24 05:36:41 -05:00
return true , nil
}