feat: initial commit for abra app volume ls/rm #51

Merged
roxxers merged 2 commits from knoflook/abra:secret-create into main 2021-08-18 18:29:14 +00:00
3 changed files with 165 additions and 0 deletions

View File

@ -29,5 +29,6 @@ scaling apps up and spinning them down.
appRunCommand,
appRollbackCommand,
appSecretCommand,
appVolumeCommand,
},
}

113
cli/app/volume.go Normal file
View File

@ -0,0 +1,113 @@
package app
import (
"context"
"errors"
abraFormatter "coopcloud.tech/abra/cli/formatter"
"coopcloud.tech/abra/cli/internal"
"coopcloud.tech/abra/client"
"coopcloud.tech/abra/config"
"github.com/AlecAivazis/survey/v2"
"github.com/sirupsen/logrus"
"github.com/urfave/cli/v2"
)
func getAppsHost(appName string) string {
appFiles, err := config.LoadAppFiles("")
if err != nil {
logrus.Fatal(err)
}
var host string
if app, ok := appFiles[appName]; ok {
host = app.Server
roxxers marked this conversation as resolved Outdated

Style: Errors should not start with capital. https://staticcheck.io/docs/checks#ST1005

Style: Errors should not start with capital. https://staticcheck.io/docs/checks#ST1005

I am also unsure of using this error vs just printing the help page without the error. Since not giving the first arg seems to do so without error for other commands. This is more a thing for future clean up tbf and me rambling.

I am also unsure of using this error vs just printing the help page without the error. Since not giving the first arg seems to do so without error for other commands. This is more a thing for future clean up tbf and me rambling.
} else {
logrus.Fatalf(`app "%s" does not exist`, appName)
}
return host
}
knoflook marked this conversation as resolved Outdated

As discussed with my panic hour, this just isn't checking if the app itself exists leading to a weird error that is very confusing. Like "Context '' does not exist."

var host string
if app, ok := appFiles[appName]; ok {
	host = app.Server
}
if host == "" {
	logrus.Fatalf(`app "%s" does not exist`, appName)
}

Just tested this and it works great with this addition.

As discussed with my panic hour, this just isn't checking if the app itself exists leading to a weird error that is very confusing. Like "Context '' does not exist." ```go var host string if app, ok := appFiles[appName]; ok { host = app.Server } if host == "" { logrus.Fatalf(`app "%s" does not exist`, appName) } ``` Just tested this and it works great with this addition.

Just realised this should be simplified to

var host string
if app, ok := appFiles[appName]; ok {
	host = app.Server
} else {
	logrus.Fatalf(`app "%s" does not exist`, appName)
}
Just realised this should be simplified to ```go var host string if app, ok := appFiles[appName]; ok { host = app.Server } else { logrus.Fatalf(`app "%s" does not exist`, appName) } ```
var appVolumeListCommand = &cli.Command{
Name: "list",
Usage: "list volumes associated with an app",
Aliases: []string{"ls"},
Action: func(c *cli.Context) error {
appName := c.Args().First()
if appName == "" {
internal.ShowSubcommandHelpAndError(c, errors.New("no app name provided!"))
}
host := getAppsHost(appName)
ctx := context.Background()
volumeList, err := client.GetVolumes(ctx, host, appName)
if err != nil {
logrus.Fatal(err)
knoflook marked this conversation as resolved Outdated

Minimal: We use table creation in the formatter for the abra/cli package

Minimal: We use table creation in the formatter for the abra/cli package
}
table := abraFormatter.CreateTable([]string{"DRIVER", "VOLUME NAME"})
var volTable [][]string
for _, volume := range volumeList {
volRow := []string{
volume.Driver,
volume.Name,
}
volTable = append(volTable, volRow)
}
table.AppendBulk(volTable)
table.Render()
return nil
},
}
var appVolumeRemoveCommand = &cli.Command{
Name: "remove",
Usage: "remove volume(s) associated with an app",
Aliases: []string{"rm", "delete"},
Flags: []cli.Flag{
internal.ForceFlag,
},
Action: func(c *cli.Context) error {
knoflook marked this conversation as resolved Outdated

Same issue as before. Since you are doing this twice you could refactor some of the calls here into their own functions so both commands can use them?

Same issue as before. Since you are doing this twice you could refactor some of the calls here into their own functions so both commands can use them?
appName := c.Args().First()
if appName == "" {
internal.ShowSubcommandHelpAndError(c, errors.New("no app name provided!"))
}
host := getAppsHost(appName)
ctx := context.Background()
volumeList, err := client.GetVolumes(ctx, host, appName)
if err != nil {
logrus.Fatal(err)
}
volumeNames := client.GetVolumeNames(volumeList)
var volumesToRemove []string
if !internal.Force {
volumesPrompt := &survey.MultiSelect{
Message: "Which volumes do you want to remove?",
Options: volumeNames,
Default: volumeNames,
}
if err := survey.AskOne(volumesPrompt, &volumesToRemove); err != nil {
roxxers marked this conversation as resolved Outdated

This is great!!

This is great!!
logrus.Fatal(err)
}
} else {
volumesToRemove = volumeNames
}
err = client.RemoveVolumes(ctx, host, volumesToRemove, internal.Force)
if err != nil {
logrus.Fatal(err)
}
logrus.Info("Volumes removed successfully.")
return nil
},
}
var appVolumeCommand = &cli.Command{
Name: "volume",
Usage: "List or remove volumes associated with app",
ArgsUsage: "<command>",
Subcommands: []*cli.Command{
appVolumeListCommand,
appVolumeRemoveCommand,
},
}

51
client/volumes.go Normal file
View File

@ -0,0 +1,51 @@
package client
import (
"context"
"github.com/docker/docker/api/types"
"github.com/docker/docker/api/types/filters"
"github.com/sirupsen/logrus"
)
func GetVolumes(ctx context.Context, server string, appName string) ([]*types.Volume, error) {
cl, err := NewClientWithContext(server)
if err != nil {
return nil, err
}
fs := filters.NewArgs()
fs.Add("name", appName)
volumeListOKBody, err := cl.VolumeList(ctx, fs)
volumeList := volumeListOKBody.Volumes
if err != nil {
logrus.Fatal(err)
}
return volumeList, nil
}
func GetVolumeNames(volumes []*types.Volume) []string {
var volumeNames []string
for _, vol := range volumes {
volumeNames = append(volumeNames, vol.Name)
}
return volumeNames
}
func RemoveVolumes(ctx context.Context, server string, volumeNames []string, force bool) error {
cl, err := NewClientWithContext(server)
if err != nil {
return err
}
for _, volName := range volumeNames {
err := cl.VolumeRemove(ctx, volName, force)
if err != nil {
return err
}
}
return nil
}