Adding server prune and undeploy prune #278
|
@ -2,15 +2,25 @@ package app
|
|||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"coopcloud.tech/abra/cli/internal"
|
||||
"coopcloud.tech/abra/pkg/autocomplete"
|
||||
"coopcloud.tech/abra/pkg/client"
|
||||
stack "coopcloud.tech/abra/pkg/upstream/stack"
|
||||
"github.com/docker/docker/api/types/filters"
|
||||
"github.com/sirupsen/logrus"
|
||||
"github.com/urfave/cli"
|
||||
)
|
||||
|
||||
var prune bool
|
||||
|
||||
var pruneFlag = &cli.BoolFlag{
|
||||
Name: "prune, p",
|
||||
Destination: &prune,
|
||||
Usage: "Prunes unused containers, networks, and dangling images for stack",
|
||||
codegod100 marked this conversation as resolved
|
||||
}
|
||||
|
||||
var appUndeployCommand = cli.Command{
|
||||
Name: "undeploy",
|
||||
Aliases: []string{"un"},
|
||||
|
@ -18,18 +28,18 @@ var appUndeployCommand = cli.Command{
|
|||
Flags: []cli.Flag{
|
||||
internal.DebugFlag,
|
||||
internal.NoInputFlag,
|
||||
pruneFlag,
|
||||
},
|
||||
Before: internal.SubCommandBefore,
|
||||
Usage: "Undeploy an app",
|
||||
Description: `
|
||||
This does not destroy any of the application data. However, you should remain
|
||||
vigilant, as your swarm installation will consider any previously attached
|
||||
volumes as eligiblef or pruning once undeployed.
|
||||
volumes as eligible for pruning once undeployed.
|
||||
`,
|
||||
Action: func(c *cli.Context) error {
|
||||
app := internal.ValidateApp(c)
|
||||
stackName := app.StackName()
|
||||
|
||||
cl, err := client.New(app.Server)
|
||||
if err != nil {
|
||||
logrus.Fatal(err)
|
||||
|
@ -57,5 +67,39 @@ volumes as eligiblef or pruning once undeployed.
|
|||
|
||||
return nil
|
||||
},
|
||||
After: func(c *cli.Context) error {
|
||||
codegod100 marked this conversation as resolved
Outdated
decentral1se
commented
Hmmm, I'm not sure we should be putting this in Hmmm, I'm not sure we should be putting this in `After` as it has some not obvious runtime behaviour (see https://pkg.go.dev/github.com/urfave/cli/v2#AfterFunc) and also the `--prune` is part of the normal functioning of the sub-command, not a thing to happen after execution? Perhaps abstracting to a function and calling from the main `Action`?
codegod100
commented
this part? this part? `it is run even if Action() panics`
The issue I was trying to tackle is that pruning while docker container is still running is kinda pointless. when we run `abra app undeploy` It takes clock time for the container to spin down. maybe we put an arbitrary wait in there? I hate doing that but not sure another way since we are done talking to docker by the time the actual spindown happens.
decentral1se
commented
Aha, I see. Could you just poll every second for the stack until it goes away? Then you can drop into the pruning logic after and still keep it all in the main Aha, I see. Could you just poll every second for the stack until it goes away? Then you can drop into the pruning logic after and still keep it all in the main `Action` code path.
|
||||
if !prune {
|
||||
return nil
|
||||
}
|
||||
app := internal.ValidateApp(c)
|
||||
stackName := app.StackName()
|
||||
cl, err := client.New(app.Server)
|
||||
if err != nil {
|
||||
logrus.Fatal(err)
|
||||
}
|
||||
ctx := context.Background()
|
||||
|
||||
pruneFilters := filters.NewArgs()
|
||||
codegod100 marked this conversation as resolved
Outdated
decentral1se
commented
Could this be tucked into
Could potentially learn from the new Could this be tucked into `app.Filters`? You might need to add a flag to specify the `*` logic? Would be then:
```
fs, err := app.Filters(false, false)
if err != nil {
logrus.Fatal(err)
}
```
Could potentially learn from the new `runtime` package options praxis 🤔 For another day...
codegod100
commented
I'm kinda confused what you mean here. What are those I'm kinda confused what you mean here. What are those `false,false` args being passed to `Filters()`?
decentral1se
commented
Yeh it's kinda a mess not of our making, i'll copy in the comments:
Yeh it's kinda a mess not of our making, i'll copy in the comments:
```
// Filters retrieves exact app filters for querying the container runtime. Due
// to upstream issues, filtering works different depending on what you're
// querying. So, for example, secrets don't work with regex! The caller needs
// to implement their own validation that the right secrets are matched. In
// order to handle these cases, we provide the `appendServiceNames` /
// `exactMatch` modifiers.
```
`Filters` goal was to hide away the weirdness. But I see now again that the function arguments are also confusing. Anyway, feel free to skip this for now and I can loop back after for a re-factor.
|
||||
stackSearch := fmt.Sprintf("%s*", stackName)
|
||||
pruneFilters.Add("label", stackSearch)
|
||||
cr, err := cl.ContainersPrune(ctx, pruneFilters)
|
||||
if err != nil {
|
||||
return err
|
||||
codegod100 marked this conversation as resolved
Outdated
decentral1se
commented
`logrus.Fatal(err)`
|
||||
}
|
||||
logrus.Infof("Containers deleted: %s; Space reclaimed: %v", cr.ContainersDeleted, cr.SpaceReclaimed)
|
||||
|
||||
nr, err := cl.NetworksPrune(ctx, pruneFilters)
|
||||
if err != nil {
|
||||
return err
|
||||
codegod100 marked this conversation as resolved
Outdated
decentral1se
commented
`logrus.Fatal(err)`
|
||||
}
|
||||
logrus.Infof("Networks deleted %s", nr.NetworksDeleted)
|
||||
|
||||
ir, err := cl.ImagesPrune(ctx, pruneFilters)
|
||||
if err != nil {
|
||||
return err
|
||||
codegod100 marked this conversation as resolved
Outdated
decentral1se
commented
`logrus.Fatal(err)`
|
||||
}
|
||||
logrus.Infof("Images deleted: %s; Space reclaimed: %v", ir.ImagesDeleted, ir.SpaceReclaimed)
|
||||
return nil
|
||||
},
|
||||
BashComplete: autocomplete.AppNameComplete,
|
||||
}
|
||||
|
|
|
@ -0,0 +1,85 @@
|
|||
package server
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"coopcloud.tech/abra/cli/internal"
|
||||
"coopcloud.tech/abra/pkg/client"
|
||||
"github.com/docker/docker/api/types/filters"
|
||||
"github.com/sirupsen/logrus"
|
||||
"github.com/urfave/cli"
|
||||
)
|
||||
|
||||
var allFilter bool
|
||||
|
||||
var allFilterFlag = &cli.BoolFlag{
|
||||
Name: "all, a",
|
||||
Usage: "Remove all unused images not just dangling ones",
|
||||
Destination: &allFilter,
|
||||
}
|
||||
|
||||
var volunesFilter bool
|
||||
|
||||
var volumesFilterFlag = &cli.BoolFlag{
|
||||
Name: "volumes, v",
|
||||
Usage: "Prune volumes",
|
||||
Destination: &volunesFilter,
|
||||
}
|
||||
|
||||
var serverPruneCommand = cli.Command{
|
||||
Name: "prune",
|
||||
Aliases: []string{"p"},
|
||||
Usage: "Prune a managed server; Runs a docker system prune",
|
||||
Description: `
|
||||
codegod100 marked this conversation as resolved
Outdated
decentral1se
commented
Could be a Could be a `"..."` oneliner after all?
|
||||
Prunes unused containers, networks, and dangling images
|
||||
`,
|
||||
ArgsUsage: "[<server>]",
|
||||
Flags: []cli.Flag{
|
||||
allFilterFlag,
|
||||
volumesFilterFlag,
|
||||
internal.DebugFlag,
|
||||
},
|
||||
Before: internal.SubCommandBefore,
|
||||
Action: func(c *cli.Context) error {
|
||||
// Leaving filters empty for now
|
||||
var args filters.Args
|
||||
serverName := internal.ValidateServer(c)
|
||||
|
||||
cl, err := client.New(serverName)
|
||||
if err != nil {
|
||||
return err
|
||||
codegod100 marked this conversation as resolved
decentral1se
commented
`logrus.Fatal(err)`
|
||||
}
|
||||
ctx := context.Background()
|
||||
cr, err := cl.ContainersPrune(ctx, args)
|
||||
if err != nil {
|
||||
return err
|
||||
codegod100 marked this conversation as resolved
decentral1se
commented
`logrus.Fatal(err)`
|
||||
}
|
||||
logrus.Infof("Containers deleted: %s; Space reclaimed: %v", cr.ContainersDeleted, cr.SpaceReclaimed)
|
||||
|
||||
nr, err := cl.NetworksPrune(ctx, args)
|
||||
if err != nil {
|
||||
return err
|
||||
codegod100 marked this conversation as resolved
decentral1se
commented
`logrus.Fatal(err)`
|
||||
}
|
||||
logrus.Infof("Networks deleted %s", nr.NetworksDeleted)
|
||||
|
||||
pruneFilters := filters.NewArgs()
|
||||
if allFilter {
|
||||
pruneFilters.Add("dangling", "false")
|
||||
}
|
||||
ir, err := cl.ImagesPrune(ctx, pruneFilters)
|
||||
if err != nil {
|
||||
return err
|
||||
codegod100 marked this conversation as resolved
decentral1se
commented
`logrus.Fatal(err)`
|
||||
}
|
||||
logrus.Infof("Images deleted: %s; Space reclaimed: %v", ir.ImagesDeleted, ir.SpaceReclaimed)
|
||||
|
||||
if volunesFilter {
|
||||
vr, err := cl.VolumesPrune(ctx, args)
|
||||
if err != nil {
|
||||
return err
|
||||
codegod100 marked this conversation as resolved
decentral1se
commented
`logrus.Fatal(err)`
|
||||
}
|
||||
logrus.Infof("Volumes deleted: %s; Space reclaimed: %v", vr.VolumesDeleted, vr.SpaceReclaimed)
|
||||
}
|
||||
|
||||
return nil
|
||||
},
|
||||
}
|
|
@ -22,5 +22,6 @@ recipes, see available flags on "abra server add" for more.
|
|||
serverAddCommand,
|
||||
serverListCommand,
|
||||
serverRemoveCommand,
|
||||
serverPruneCommand,
|
||||
},
|
||||
}
|
||||
|
|
stack
👉an app