package app import ( "context" "fmt" "os" "coopcloud.tech/abra/cli/internal" "coopcloud.tech/abra/pkg/autocomplete" "coopcloud.tech/abra/pkg/client" stack "coopcloud.tech/abra/pkg/upstream/stack" "github.com/AlecAivazis/survey/v2" "github.com/docker/docker/api/types" "github.com/docker/docker/api/types/filters" "github.com/sirupsen/logrus" "github.com/urfave/cli" ) // Volumes stores the variable from VolumesFlag var Volumes bool // VolumesFlag is used to specify if volumes should be deleted when deleting an app var VolumesFlag = &cli.BoolFlag{ Name: "volumes", Destination: &Volumes, } var appRemoveCommand = cli.Command{ Name: "remove", Aliases: []string{"rm"}, Usage: "Remove an already undeployed app", Flags: []cli.Flag{ VolumesFlag, internal.ForceFlag, internal.DebugFlag, internal.NoInputFlag, }, Before: internal.SubCommandBefore, Action: func(c *cli.Context) error { app := internal.ValidateApp(c) if !internal.Force { response := false prompt := &survey.Confirm{ Message: fmt.Sprintf("about to remove %s, are you sure?", app.Name), } if err := survey.AskOne(prompt, &response); err != nil { logrus.Fatal(err) } if !response { logrus.Fatal("aborting as requested") } } cl, err := client.New(app.Server) if err != nil { logrus.Fatal(err) } isDeployed, _, err := stack.IsDeployed(context.Background(), cl, app.StackName()) if err != nil { logrus.Fatal(err) } if isDeployed { logrus.Fatalf("%s is still deployed. Run \"abra app undeploy %s \" or pass --force", app.Name, app.Name) } fs := filters.NewArgs() fs.Add("name", app.StackName()) secretList, err := cl.SecretList(context.Background(), types.SecretListOptions{Filters: fs}) if err != nil { logrus.Fatal(err) } secrets := make(map[string]string) var secretNames []string for _, cont := range secretList { secrets[cont.Spec.Annotations.Name] = cont.ID // we have to map the names to ID's secretNames = append(secretNames, cont.Spec.Annotations.Name) } if len(secrets) > 0 { var secretNamesToRemove []string if !internal.Force { secretsPrompt := &survey.MultiSelect{ Message: "which secrets do you want to remove?", Help: "'x' indicates selected, enter / return to confirm, ctrl-c to exit, vim mode is enabled", VimMode: true, Options: secretNames, Default: secretNames, } if err := survey.AskOne(secretsPrompt, &secretNamesToRemove); err != nil { logrus.Fatal(err) } } for _, name := range secretNamesToRemove { err := cl.SecretRemove(context.Background(), secrets[name]) if err != nil { logrus.Fatal(err) } logrus.Info(fmt.Sprintf("secret: %s removed", name)) } } else { logrus.Info("no secrets to remove") } volumeListOKBody, err := cl.VolumeList(context.Background(), fs) volumeList := volumeListOKBody.Volumes if err != nil { logrus.Fatal(err) } var vols []string for _, vol := range volumeList { vols = append(vols, vol.Name) } if len(vols) > 0 { if Volumes { var removeVols []string if !internal.Force { volumesPrompt := &survey.MultiSelect{ Message: "which volumes do you want to remove?", Help: "'x' indicates selected, enter / return to confirm, ctrl-c to exit, vim mode is enabled", VimMode: true, Options: vols, Default: vols, } if err := survey.AskOne(volumesPrompt, &removeVols); err != nil { logrus.Fatal(err) } } for _, vol := range removeVols { err := cl.VolumeRemove(context.Background(), vol, internal.Force) // last argument is for force removing if err != nil { logrus.Fatal(err) } logrus.Info(fmt.Sprintf("volume %s removed", vol)) } } else { logrus.Info("no volumes were removed") } } else { if Volumes { logrus.Info("no volumes to remove") } } err = os.Remove(app.Path) if err != nil { logrus.Fatal(err) } logrus.Info(fmt.Sprintf("file: %s removed", app.Path)) return nil }, BashComplete: autocomplete.AppNameComplete, }