package app import ( "context" "errors" "os" "strings" "coopcloud.tech/abra/cli/internal" "coopcloud.tech/abra/client" "coopcloud.tech/abra/config" "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/v2" ) // 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", Value: false, Destination: &Volumes, } var Force bool var ForceFlag = &cli.BoolFlag{ Name: "force", Value: false, Destination: &Force, } var appRemoveCommand = &cli.Command{ Name: "remove", Aliases: []string{"rm", "delete"}, Flags: []cli.Flag{ VolumesFlag, ForceFlag, }, Action: func(c *cli.Context) error { // Check if app name was provided by user AppName := c.Args().First() if AppName == "" { internal.ShowSubcommandHelpAndError(c, errors.New("No app name provided!")) } // Make sure that the user really wants to delete the app if !Force { response := false prompt := &survey.Confirm{ Message: "About to delete " + AppName + ", are you sure?", } survey.AskOne(prompt, &response) if response == false { return errors.New("User aborted app removal") } } // Get app list AppFiles, err := config.LoadAppFiles("") if err != nil { return err } AppPath := AppFiles[AppName].Path host := AppFiles[AppName].Server // Initialize docker client ctx := context.Background() cl, err := client.NewClientWithContext(host) if err != nil { return err } // Remove the file err = os.Remove(AppPath) if err != nil { return err } else { logrus.Info("File :" + AppPath + " removed.") } // Check if the app has secrets fs := filters.NewArgs() fs.Add("name", AppName) SecretList, err := cl.SecretList(ctx, types.SecretListOptions{Filters: fs}) if err != nil { return err } Secrets := make(map[string]string) 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) } SecretNamesToRemove := []string{} // Ask if the user really wants to remove the apps if Force { SecretNamesToRemove = SecretNames } else { SecretsPrompt := &survey.MultiSelect{ Message: "Which secrets do you want to remove?", Options: SecretNames, Default: SecretNames, } survey.AskOne(SecretsPrompt, &SecretNamesToRemove) } // Actually remove the secrets for _, name := range SecretNamesToRemove { // DEBUG: SecretIDsToRemove = append(SecretIDsToRemove, Secrets[name]) err := cl.SecretRemove(ctx, Secrets[name]) if err != nil { return err } else { logrus.Info("Secret: " + name + " removed") } } // Get volumes associated with the app VolumeListOKBody, err := cl.VolumeList(ctx, fs) VolumeList := VolumeListOKBody.Volumes if err != nil { return err } Vols := []string{} for _, vol := range VolumeList { Vols = append(Vols, vol.Name) } // Remove the volumes if desired if Volumes == true { RemoveVols := []string{} // If there's no --force, ask if the user wants to remove if Force { RemoveVols = Vols } else { VolumesPrompt := &survey.MultiSelect{ Message: "Which volumes do you want to remove?", Options: Vols, Default: Vols, } survey.AskOne(VolumesPrompt, &RemoveVols) } // Remove the volumes for _, vol := range RemoveVols { err := cl.VolumeRemove(ctx, vol, Force) // false is for force removing if err != nil { return err } else { logrus.Info("Volume " + vol + " removed") } } } else { logrus.Info("No volumes were removed. Volumes left: " + strings.Join(Vols, ", ")) } return nil }, }