Adding server prune and undeploy prune #278
@ -2,15 +2,70 @@ package app
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"time"
|
||||||
|
|
||||||
"coopcloud.tech/abra/cli/internal"
|
"coopcloud.tech/abra/cli/internal"
|
||||||
"coopcloud.tech/abra/pkg/autocomplete"
|
"coopcloud.tech/abra/pkg/autocomplete"
|
||||||
"coopcloud.tech/abra/pkg/client"
|
"coopcloud.tech/abra/pkg/client"
|
||||||
stack "coopcloud.tech/abra/pkg/upstream/stack"
|
stack "coopcloud.tech/abra/pkg/upstream/stack"
|
||||||
|
"github.com/docker/docker/api/types/filters"
|
||||||
"github.com/sirupsen/logrus"
|
"github.com/sirupsen/logrus"
|
||||||
"github.com/urfave/cli"
|
"github.com/urfave/cli"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var prune bool
|
||||||
|
|
||||||
|
var pruneFlag = &cli.BoolFlag{
|
||||||
|
Name: "prune, p",
|
||||||
|
Destination: &prune,
|
||||||
codegod100 marked this conversation as resolved
|
|||||||
|
Usage: "Prunes unused containers, networks, and dangling images for an app",
|
||||||
|
}
|
||||||
|
|
||||||
|
func cleanup(c *cli.Context) error {
|
||||||
|
for {
|
||||||
|
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()
|
||||||
|
stackSearch := fmt.Sprintf("%s*", stackName)
|
||||||
|
pruneFilters.Add("label", stackSearch)
|
||||||
|
cr, err := cl.ContainersPrune(ctx, pruneFilters)
|
||||||
|
if err != nil {
|
||||||
|
logrus.Errorf(err.Error())
|
||||||
|
time.Sleep(time.Second)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
logrus.Infof("Containers deleted: %s; Space reclaimed: %v", cr.ContainersDeleted, cr.SpaceReclaimed)
|
||||||
|
|
||||||
|
nr, err := cl.NetworksPrune(ctx, pruneFilters)
|
||||||
|
if err != nil {
|
||||||
|
logrus.Errorf(err.Error())
|
||||||
|
time.Sleep(time.Second)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
logrus.Infof("Networks deleted %s", nr.NetworksDeleted)
|
||||||
|
|
||||||
|
ir, err := cl.ImagesPrune(ctx, pruneFilters)
|
||||||
|
if err != nil {
|
||||||
|
logrus.Errorf(err.Error())
|
||||||
|
time.Sleep(time.Second)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
logrus.Infof("Images deleted: %s; Space reclaimed: %v", ir.ImagesDeleted, ir.SpaceReclaimed)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
var appUndeployCommand = cli.Command{
|
var appUndeployCommand = cli.Command{
|
||||||
Name: "undeploy",
|
Name: "undeploy",
|
||||||
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.
|
|||||||
Aliases: []string{"un"},
|
Aliases: []string{"un"},
|
||||||
@ -18,6 +73,7 @@ var appUndeployCommand = cli.Command{
|
|||||||
Flags: []cli.Flag{
|
Flags: []cli.Flag{
|
||||||
internal.DebugFlag,
|
internal.DebugFlag,
|
||||||
internal.NoInputFlag,
|
internal.NoInputFlag,
|
||||||
|
pruneFlag,
|
||||||
},
|
},
|
||||||
Before: internal.SubCommandBefore,
|
Before: internal.SubCommandBefore,
|
||||||
Usage: "Undeploy an app",
|
Usage: "Undeploy an app",
|
||||||
@ -29,7 +85,6 @@ volumes as eligiblef or pruning once undeployed.
|
|||||||
Action: func(c *cli.Context) error {
|
Action: func(c *cli.Context) error {
|
||||||
app := internal.ValidateApp(c)
|
app := internal.ValidateApp(c)
|
||||||
stackName := app.StackName()
|
stackName := app.StackName()
|
||||||
codegod100 marked this conversation as resolved
Outdated
decentral1se
commented
`logrus.Fatal(err)`
|
|||||||
|
|
||||||
cl, err := client.New(app.Server)
|
cl, err := client.New(app.Server)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logrus.Fatal(err)
|
logrus.Fatal(err)
|
||||||
@ -54,7 +109,7 @@ volumes as eligiblef or pruning once undeployed.
|
|||||||
if err := stack.RunRemove(context.Background(), cl, rmOpts); err != nil {
|
if err := stack.RunRemove(context.Background(), cl, rmOpts); err != nil {
|
||||||
logrus.Fatal(err)
|
logrus.Fatal(err)
|
||||||
}
|
}
|
||||||
|
cleanup(c)
|
||||||
return nil
|
return nil
|
||||||
},
|
},
|
||||||
BashComplete: autocomplete.AppNameComplete,
|
BashComplete: autocomplete.AppNameComplete,
|
||||||
|
83
cli/server/prune.go
Normal file
@ -0,0 +1,83 @@
|
|||||||
|
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: "Prunes unused containers, networks, and dangling images",
|
||||||
codegod100 marked this conversation as resolved
Outdated
decentral1se
commented
Could be a Could be a `"..."` oneliner after all?
|
|||||||
|
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 {
|
||||||
|
logrus.Fatal(err)
|
||||||
|
}
|
||||||
|
ctx := context.Background()
|
||||||
codegod100 marked this conversation as resolved
decentral1se
commented
`logrus.Fatal(err)`
|
|||||||
|
cr, err := cl.ContainersPrune(ctx, args)
|
||||||
|
if err != nil {
|
||||||
|
logrus.Fatal(err)
|
||||||
|
}
|
||||||
|
logrus.Infof("Containers deleted: %s; Space reclaimed: %v", cr.ContainersDeleted, cr.SpaceReclaimed)
|
||||||
codegod100 marked this conversation as resolved
decentral1se
commented
`logrus.Fatal(err)`
|
|||||||
|
|
||||||
|
nr, err := cl.NetworksPrune(ctx, args)
|
||||||
|
if err != nil {
|
||||||
|
logrus.Fatal(err)
|
||||||
|
}
|
||||||
|
logrus.Infof("Networks deleted %s", nr.NetworksDeleted)
|
||||||
codegod100 marked this conversation as resolved
decentral1se
commented
`logrus.Fatal(err)`
|
|||||||
|
|
||||||
|
pruneFilters := filters.NewArgs()
|
||||||
|
if allFilter {
|
||||||
|
pruneFilters.Add("dangling", "false")
|
||||||
|
}
|
||||||
|
ir, err := cl.ImagesPrune(ctx, pruneFilters)
|
||||||
|
if err != nil {
|
||||||
|
logrus.Fatal(err)
|
||||||
|
}
|
||||||
|
logrus.Infof("Images deleted: %s; Space reclaimed: %v", ir.ImagesDeleted, ir.SpaceReclaimed)
|
||||||
codegod100 marked this conversation as resolved
decentral1se
commented
`logrus.Fatal(err)`
|
|||||||
|
|
||||||
|
if volunesFilter {
|
||||||
|
vr, err := cl.VolumesPrune(ctx, args)
|
||||||
|
if err != nil {
|
||||||
|
logrus.Fatal(err)
|
||||||
|
}
|
||||||
|
logrus.Infof("Volumes deleted: %s; Space reclaimed: %v", vr.VolumesDeleted, vr.SpaceReclaimed)
|
||||||
codegod100 marked this conversation as resolved
decentral1se
commented
`logrus.Fatal(err)`
|
|||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
},
|
||||||
|
}
|
@ -22,5 +22,6 @@ recipes, see available flags on "abra server add" for more.
|
|||||||
serverAddCommand,
|
serverAddCommand,
|
||||||
serverListCommand,
|
serverListCommand,
|
||||||
serverRemoveCommand,
|
serverRemoveCommand,
|
||||||
|
serverPruneCommand,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
stack
👉an app