mirror of
https://github.com/edgelesssys/constellation.git
synced 2025-02-14 14:01:57 -05:00
![Moritz Sanft](/assets/img/avatar_default.png)
* [wip] use state file in CLI Signed-off-by: Moritz Sanft <58110325+msanft@users.noreply.github.com> tidy Signed-off-by: Moritz Sanft <58110325+msanft@users.noreply.github.com> * use state file in CLI Signed-off-by: Moritz Sanft <58110325+msanft@users.noreply.github.com> take clusterConfig from IDFile for compat Signed-off-by: Moritz Sanft <58110325+msanft@users.noreply.github.com> various fixes Signed-off-by: Moritz Sanft <58110325+msanft@users.noreply.github.com> wip Signed-off-by: Moritz Sanft <58110325+msanft@users.noreply.github.com> * add GCP-specific values in Helm loader test Signed-off-by: Moritz Sanft <58110325+msanft@users.noreply.github.com> * remove unnecessary pointer Signed-off-by: Moritz Sanft <58110325+msanft@users.noreply.github.com> * write ClusterValues in one step Signed-off-by: Moritz Sanft <58110325+msanft@users.noreply.github.com> * move stub to test file Signed-off-by: Moritz Sanft <58110325+msanft@users.noreply.github.com> * remove mention of id-file Signed-off-by: Moritz Sanft <58110325+msanft@users.noreply.github.com> * move output to `migrateTerraform` Signed-off-by: Moritz Sanft <58110325+msanft@users.noreply.github.com> * unconditional assignments converting from idFile Signed-off-by: Moritz Sanft <58110325+msanft@users.noreply.github.com> * move require block in go modules file Signed-off-by: Moritz Sanft <58110325+msanft@users.noreply.github.com> * fall back to id file on upgrade Signed-off-by: Moritz Sanft <58110325+msanft@users.noreply.github.com> * tidy Signed-off-by: Moritz Sanft <58110325+msanft@users.noreply.github.com> * fix linter check Signed-off-by: Moritz Sanft <58110325+msanft@users.noreply.github.com> * add notice to remove Terraform state check on manual migration Signed-off-by: Moritz Sanft <58110325+msanft@users.noreply.github.com> * add `name` field Signed-off-by: Moritz Sanft <58110325+msanft@users.noreply.github.com> fix name tests Signed-off-by: Moritz Sanft <58110325+msanft@users.noreply.github.com> * return early if no Terraform diff Signed-off-by: Moritz Sanft <58110325+msanft@users.noreply.github.com> * tidy Signed-off-by: Moritz Sanft <58110325+msanft@users.noreply.github.com> * return infrastructure state even if no diff exists Signed-off-by: Moritz Sanft <58110325+msanft@users.noreply.github.com> * add TODO to remove comment Signed-off-by: Moritz Sanft <58110325+msanft@users.noreply.github.com> * use state-file in miniconstellation Signed-off-by: Moritz Sanft <58110325+msanft@users.noreply.github.com> * cli: remove id-file (#2402) * remove id-file from `constellation create` Signed-off-by: Moritz Sanft <58110325+msanft@users.noreply.github.com> * add file renaming to handler * rename id-file after upgrade * use idFile on `constellation init` Signed-off-by: Moritz Sanft <58110325+msanft@users.noreply.github.com> * remove id-file from `constellation verify` Signed-off-by: Moritz Sanft <58110325+msanft@users.noreply.github.com> * linter fixes Signed-off-by: Moritz Sanft <58110325+msanft@users.noreply.github.com> * remove id-file from `constellation mini` * remove id-file from `constellation recover` * linter fixes * remove id-file from `constellation terminate` * fix initSecret type * fix recover argument precedence * fix terminate test * generate * add TODO to remove id-file removal * Update cli/internal/cmd/init.go Co-authored-by: Adrian Stobbe <stobbe.adrian@gmail.com> * fix verify arg parse logic Signed-off-by: Moritz Sanft <58110325+msanft@users.noreply.github.com> * add version test Signed-off-by: Moritz Sanft <58110325+msanft@users.noreply.github.com> * remove id-file from docs * add file not found log * use state-file in miniconstellation Signed-off-by: Moritz Sanft <58110325+msanft@users.noreply.github.com> * remove id-file from `constellation iam destroy` Signed-off-by: Moritz Sanft <58110325+msanft@users.noreply.github.com> * remove id-file from `cdbg deploy` Signed-off-by: Moritz Sanft <58110325+msanft@users.noreply.github.com> --------- Signed-off-by: Moritz Sanft <58110325+msanft@users.noreply.github.com> Co-authored-by: Adrian Stobbe <stobbe.adrian@gmail.com> * use state-file in CI Signed-off-by: Moritz Sanft <58110325+msanft@users.noreply.github.com> * update orchestration docs --------- Signed-off-by: Moritz Sanft <58110325+msanft@users.noreply.github.com> Co-authored-by: Adrian Stobbe <stobbe.adrian@gmail.com>
193 lines
6.4 KiB
Go
193 lines
6.4 KiB
Go
/*
|
|
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/cli/internal/cmd/pathprefix"
|
|
"github.com/edgelesssys/constellation/v2/cli/internal/terraform"
|
|
"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"
|
|
)
|
|
|
|
// 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
|
|
}
|
|
|
|
func runIAMDestroy(cmd *cobra.Command, _ []string) error {
|
|
log, err := newCLILogger(cmd)
|
|
if err != nil {
|
|
return fmt.Errorf("creating logger: %w", err)
|
|
}
|
|
defer log.Sync()
|
|
spinner := newSpinner(cmd.ErrOrStderr())
|
|
destroyer := cloudcmd.NewIAMDestroyer()
|
|
fsHandler := file.NewHandler(afero.NewOsFs())
|
|
|
|
c := &destroyCmd{log: log}
|
|
|
|
return c.iamDestroy(cmd, spinner, destroyer, fsHandler)
|
|
}
|
|
|
|
type destroyCmd struct {
|
|
log debugLog
|
|
pf pathprefix.PathPrefixer
|
|
}
|
|
|
|
func (c *destroyCmd) iamDestroy(cmd *cobra.Command, spinner spinnerInterf, destroyer iamDestroyer, fsHandler file.Handler) error {
|
|
flags, err := c.parseDestroyFlags(cmd)
|
|
if err != nil {
|
|
return fmt.Errorf("parsing flags: %w", err)
|
|
}
|
|
|
|
// check if there is a possibility that the cluster is still running by looking out for specific files
|
|
c.log.Debugf("Checking if %q exists", c.pf.PrefixPrintablePath(constants.AdminConfFilename))
|
|
_, err = fsHandler.Stat(constants.AdminConfFilename)
|
|
if !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.pf.PrefixPrintablePath(constants.AdminConfFilename))
|
|
}
|
|
c.log.Debugf("Checking if %q exists", c.pf.PrefixPrintablePath(constants.StateFilename))
|
|
_, err = fsHandler.Stat(constants.StateFilename)
|
|
if !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.pf.PrefixPrintablePath(constants.StateFilename))
|
|
}
|
|
|
|
gcpFileExists := false
|
|
|
|
c.log.Debugf("Checking if %q exists", c.pf.PrefixPrintablePath(constants.GCPServiceAccountKeyFilename))
|
|
_, err = fsHandler.Stat(constants.GCPServiceAccountKeyFilename)
|
|
if err != nil {
|
|
if !errors.Is(err, os.ErrNotExist) {
|
|
return err
|
|
}
|
|
} else {
|
|
c.log.Debugf("%q exists", c.pf.PrefixPrintablePath(constants.GCPServiceAccountKeyFilename))
|
|
gcpFileExists = true
|
|
}
|
|
|
|
if !flags.yes {
|
|
// Confirmation
|
|
confirmString := "Do you really want to destroy your IAM configuration? Note that this will remove all resources in the resource group."
|
|
if gcpFileExists {
|
|
confirmString += fmt.Sprintf("\nThis will also delete %q", c.pf.PrefixPrintablePath(constants.GCPServiceAccountKeyFilename))
|
|
}
|
|
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 {
|
|
c.log.Debugf("Starting to delete %q", c.pf.PrefixPrintablePath(constants.GCPServiceAccountKeyFilename))
|
|
proceed, err := c.deleteGCPServiceAccountKeyFile(cmd, destroyer, fsHandler)
|
|
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()
|
|
if err := destroyer.DestroyIAMConfiguration(cmd.Context(), constants.TerraformIAMWorkingDir, flags.tfLogLevel); err != nil {
|
|
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
|
|
}
|
|
|
|
func (c *destroyCmd) deleteGCPServiceAccountKeyFile(cmd *cobra.Command, destroyer iamDestroyer, fsHandler file.Handler) (bool, error) {
|
|
var fileSaKey gcpshared.ServiceAccountKey
|
|
|
|
c.log.Debugf("Parsing %q", c.pf.PrefixPrintablePath(constants.GCPServiceAccountKeyFilename))
|
|
if err := fsHandler.ReadJSON(constants.GCPServiceAccountKeyFilename, &fileSaKey); err != nil {
|
|
return false, err
|
|
}
|
|
|
|
c.log.Debugf("Getting service account key from the tfstate")
|
|
tfSaKey, err := destroyer.GetTfStateServiceAccountKey(cmd.Context(), constants.TerraformIAMWorkingDir)
|
|
if err != nil {
|
|
return false, err
|
|
}
|
|
|
|
c.log.Debugf("Checking if keys are the same")
|
|
if tfSaKey != fileSaKey {
|
|
cmd.Printf("The key in %q don't match up with your Terraform state. %q will not be deleted.\n", c.pf.PrefixPrintablePath(constants.GCPServiceAccountKeyFilename), c.pf.PrefixPrintablePath(constants.GCPServiceAccountKeyFilename))
|
|
return true, nil
|
|
}
|
|
|
|
if err := fsHandler.Remove(constants.GCPServiceAccountKeyFilename); err != nil {
|
|
return false, err
|
|
}
|
|
|
|
c.log.Debugf("Successfully deleted %q", c.pf.PrefixPrintablePath(constants.GCPServiceAccountKeyFilename))
|
|
return true, nil
|
|
}
|
|
|
|
type destroyFlags struct {
|
|
yes bool
|
|
tfLogLevel terraform.LogLevel
|
|
}
|
|
|
|
// parseDestroyFlags parses the flags of the create command.
|
|
func (c *destroyCmd) parseDestroyFlags(cmd *cobra.Command) (destroyFlags, error) {
|
|
yes, err := cmd.Flags().GetBool("yes")
|
|
if err != nil {
|
|
return destroyFlags{}, fmt.Errorf("parsing yes bool: %w", err)
|
|
}
|
|
c.log.Debugf("Yes flag is %t", yes)
|
|
|
|
workDir, err := cmd.Flags().GetString("workspace")
|
|
if err != nil {
|
|
return destroyFlags{}, fmt.Errorf("parsing workspace string: %w", err)
|
|
}
|
|
c.log.Debugf("Workspace set to %q", workDir)
|
|
c.pf = pathprefix.New(workDir)
|
|
|
|
logLevelString, err := cmd.Flags().GetString("tf-log")
|
|
if err != nil {
|
|
return destroyFlags{}, fmt.Errorf("parsing tf-log string: %w", err)
|
|
}
|
|
logLevel, err := terraform.ParseLogLevel(logLevelString)
|
|
if err != nil {
|
|
return destroyFlags{}, fmt.Errorf("parsing Terraform log level %s: %w", logLevelString, err)
|
|
}
|
|
c.log.Debugf("Terraform logs will be written into %s at level %s", c.pf.PrefixPrintablePath(constants.TerraformWorkingDir), logLevel.String())
|
|
|
|
return destroyFlags{
|
|
tfLogLevel: logLevel,
|
|
yes: yes,
|
|
}, nil
|
|
}
|