From e4b034b17e14b2cd3be7f15fea630450f3450087 Mon Sep 17 00:00:00 2001 From: Manfred Touron Date: Thu, 14 Feb 2019 12:19:23 +0100 Subject: [PATCH] feat: add hypervisor prune command --- go.mod | 1 + hypervisor/cmd_hypervisor.go | 6 ++- hypervisor/cmd_hypervisor_prune.go | 87 ++++++++++++++++++++++++++++++ hypervisor/cmd_hypervisor_run.go | 3 ++ 4 files changed, 95 insertions(+), 2 deletions(-) create mode 100644 hypervisor/cmd_hypervisor_prune.go diff --git a/go.mod b/go.mod index bba0ea1df..dd1c840c6 100644 --- a/go.mod +++ b/go.mod @@ -35,6 +35,7 @@ require ( go.uber.org/zap v1.9.1 golang.org/x/crypto v0.0.0-20190103213133-ff983b9c42bc // indirect golang.org/x/net v0.0.0-20190110044637-be1c187aa6c6 + golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4 golang.org/x/time v0.0.0-20181108054448-85acf8d2951c // indirect google.golang.org/appengine v1.2.0 // indirect google.golang.org/genproto v0.0.0-20190108161440-ae2f86662275 diff --git a/hypervisor/cmd_hypervisor.go b/hypervisor/cmd_hypervisor.go index ed48bfc9c..6b6b7da53 100644 --- a/hypervisor/cmd_hypervisor.go +++ b/hypervisor/cmd_hypervisor.go @@ -21,8 +21,9 @@ func (opts Options) String() string { func Commands() cli.Commands { return cli.Commands{ - "hypervisor": &hypervisorCommand{}, - "hypervisor run": &runCommand{}, + "hypervisor": &hypervisorCommand{}, + "hypervisor run": &runCommand{}, + "hypervisor prune": &pruneCommand{}, } } @@ -39,5 +40,6 @@ func (cmd *hypervisorCommand) CobraCommand(commands cli.Commands) *cobra.Command Use: "hypervisor", } command.AddCommand(commands["hypervisor run"].CobraCommand(commands)) + command.AddCommand(commands["hypervisor prune"].CobraCommand(commands)) return command } diff --git a/hypervisor/cmd_hypervisor_prune.go b/hypervisor/cmd_hypervisor_prune.go new file mode 100644 index 000000000..2cda80755 --- /dev/null +++ b/hypervisor/cmd_hypervisor_prune.go @@ -0,0 +1,87 @@ +package hypervisor + +import ( + "context" + "fmt" + "log" + "time" + + "github.com/docker/docker/api/types" + "github.com/docker/docker/api/types/filters" + "github.com/docker/docker/client" + "github.com/pkg/errors" + "github.com/spf13/cobra" + "github.com/spf13/pflag" + "github.com/spf13/viper" + "go.uber.org/zap" + "golang.org/x/sync/errgroup" + + "pathwar.pw/pkg/cli" +) + +type pruneOptions struct { + // timeout + // driver=docker +} + +type pruneCommand struct{ opts pruneOptions } + +func (cmd *pruneCommand) CobraCommand(commands cli.Commands) *cobra.Command { + cc := &cobra.Command{ + Use: "prune", + RunE: func(_ *cobra.Command, args []string) error { + opts := cmd.opts + return runPrune(opts) + }, + } + cmd.ParseFlags(cc.Flags()) + return cc +} +func (cmd *pruneCommand) LoadDefaultOptions() error { return viper.Unmarshal(&cmd.opts) } +func (cmd *pruneCommand) ParseFlags(flags *pflag.FlagSet) { + if err := viper.BindPFlags(flags); err != nil { + zap.L().Warn("failed to bind viper flags", zap.Error(err)) + } +} + +func runPrune(opts pruneOptions) error { + ctx := context.Background() + cli, err := client.NewClientWithOpts(client.FromEnv) + if err != nil { + return errors.Wrap(err, "failed to create docker client") + } + + filters := filters.NewArgs() + filters.Add("label", fmt.Sprintf("%s", createdByPathwarLabel)) + + // list containers + containers, err := cli.ContainerList(ctx, types.ContainerListOptions{ + Filters: filters, + }) + if err != nil { + return err + } + log.Printf("%d container(s) stopped", len(containers)) + + // stop containers + var g errgroup.Group + var timeout = 5 * time.Second + for _, container := range containers { + g.Go(func() error { + return cli.ContainerStop(ctx, container.ID, &timeout) + }) + } + if err := g.Wait(); err != nil { + log.Printf("some container failed to stop: %v", err) + } + + // prune containers + report, err := cli.ContainersPrune(ctx, filters) + if err != nil { + return err + } + if len(report.ContainersDeleted) > 0 { + log.Printf("%d container(s) pruned", len(report.ContainersDeleted)) + } + return err +} diff --git a/hypervisor/cmd_hypervisor_run.go b/hypervisor/cmd_hypervisor_run.go index c68ef3d0a..18df2327a 100644 --- a/hypervisor/cmd_hypervisor_run.go +++ b/hypervisor/cmd_hypervisor_run.go @@ -29,6 +29,8 @@ type runOptions struct { // driver=docker } +const createdByPathwarLabel = "created-by-pathwar-hypervisor" + type runCommand struct{ opts runOptions } func (cmd *runCommand) CobraCommand(commands cli.Commands) *cobra.Command { @@ -83,6 +85,7 @@ func runRun(opts runOptions) error { // Hostname: "" Entrypoint: strslice.StrSlice{"/pathwar"}, Cmd: append(imageInspect.Config.Entrypoint, imageInspect.Config.Cmd...), + Labels: map[string]string{createdByPathwarLabel: "true"}, } hostConfig := &container.HostConfig{ // Binds: /etc/timezone