cli: add --all-inactive and --force flags for rm command

Signed-off-by: CrazyMax <crazy-max@users.noreply.github.com>
pull/885/head
CrazyMax 3 years ago
parent 33c121df01
commit 378f0b45c6
No known key found for this signature in database
GPG Key ID: 3248E46B6BB8C7F7

@ -2,36 +2,53 @@ package commands
import ( import (
"context" "context"
"time"
"github.com/docker/buildx/store" "github.com/docker/buildx/store"
"github.com/docker/buildx/store/storeutil" "github.com/docker/buildx/store/storeutil"
"github.com/docker/cli/cli" "github.com/docker/cli/cli"
"github.com/docker/cli/cli/command" "github.com/docker/cli/cli/command"
"github.com/moby/buildkit/util/appcontext" "github.com/moby/buildkit/util/appcontext"
"github.com/pkg/errors"
"github.com/spf13/cobra" "github.com/spf13/cobra"
"golang.org/x/sync/errgroup"
) )
type rmOptions struct { type rmOptions struct {
builder string builder string
keepState bool keepState bool
keepDaemon bool keepDaemon bool
allInactive bool
force bool
} }
const (
rmInactiveWarning = `WARNING! This will remove all builders that are not in running state. Are you sure you want to continue?`
)
func runRm(dockerCli command.Cli, in rmOptions) error { func runRm(dockerCli command.Cli, in rmOptions) error {
ctx := appcontext.Context() ctx := appcontext.Context()
if in.allInactive && !in.force && !command.PromptForConfirmation(dockerCli.In(), dockerCli.Out(), rmInactiveWarning) {
return nil
}
txn, release, err := storeutil.GetStore(dockerCli) txn, release, err := storeutil.GetStore(dockerCli)
if err != nil { if err != nil {
return err return err
} }
defer release() defer release()
if in.allInactive {
return rmAllInactive(ctx, txn, dockerCli, in)
}
if in.builder != "" { if in.builder != "" {
ng, err := storeutil.GetNodeGroup(txn, dockerCli, in.builder) ng, err := storeutil.GetNodeGroup(txn, dockerCli, in.builder)
if err != nil { if err != nil {
return err return err
} }
err1 := rm(ctx, dockerCli, ng, in.keepState, in.keepDaemon) err1 := rm(ctx, dockerCli, in, ng)
if err := txn.Remove(ng.Name); err != nil { if err := txn.Remove(ng.Name); err != nil {
return err return err
} }
@ -43,7 +60,7 @@ func runRm(dockerCli command.Cli, in rmOptions) error {
return err return err
} }
if ng != nil { if ng != nil {
err1 := rm(ctx, dockerCli, ng, in.keepState, in.keepDaemon) err1 := rm(ctx, dockerCli, in, ng)
if err := txn.Remove(ng.Name); err != nil { if err := txn.Remove(ng.Name); err != nil {
return err return err
} }
@ -63,6 +80,9 @@ func rmCmd(dockerCli command.Cli, rootOpts *rootOptions) *cobra.Command {
RunE: func(cmd *cobra.Command, args []string) error { RunE: func(cmd *cobra.Command, args []string) error {
options.builder = rootOpts.builder options.builder = rootOpts.builder
if len(args) > 0 { if len(args) > 0 {
if options.allInactive {
return errors.New("cannot specify builder name when --all-inactive is set")
}
options.builder = args[0] options.builder = args[0]
} }
return runRm(dockerCli, options) return runRm(dockerCli, options)
@ -72,11 +92,13 @@ func rmCmd(dockerCli command.Cli, rootOpts *rootOptions) *cobra.Command {
flags := cmd.Flags() flags := cmd.Flags()
flags.BoolVar(&options.keepState, "keep-state", false, "Keep BuildKit state") flags.BoolVar(&options.keepState, "keep-state", false, "Keep BuildKit state")
flags.BoolVar(&options.keepDaemon, "keep-daemon", false, "Keep the buildkitd daemon running") flags.BoolVar(&options.keepDaemon, "keep-daemon", false, "Keep the buildkitd daemon running")
flags.BoolVar(&options.allInactive, "all-inactive", false, "Remove all inactive builders")
flags.BoolVarP(&options.force, "force", "f", false, "Do not prompt for confirmation")
return cmd return cmd
} }
func rm(ctx context.Context, dockerCli command.Cli, ng *store.NodeGroup, keepState, keepDaemon bool) error { func rm(ctx context.Context, dockerCli command.Cli, in rmOptions, ng *store.NodeGroup) error {
dis, err := driversForNodeGroup(ctx, dockerCli, ng, "") dis, err := driversForNodeGroup(ctx, dockerCli, ng, "")
if err != nil { if err != nil {
return err return err
@ -86,12 +108,12 @@ func rm(ctx context.Context, dockerCli command.Cli, ng *store.NodeGroup, keepSta
continue continue
} }
// Do not stop the buildkitd daemon when --keep-daemon is provided // Do not stop the buildkitd daemon when --keep-daemon is provided
if !keepDaemon { if !in.keepDaemon {
if err := di.Driver.Stop(ctx, true); err != nil { if err := di.Driver.Stop(ctx, true); err != nil {
return err return err
} }
} }
if err := di.Driver.Rm(ctx, true, !keepState, !keepDaemon); err != nil { if err := di.Driver.Rm(ctx, true, !in.keepState, !in.keepDaemon); err != nil {
return err return err
} }
if di.Err != nil { if di.Err != nil {
@ -100,3 +122,42 @@ func rm(ctx context.Context, dockerCli command.Cli, ng *store.NodeGroup, keepSta
} }
return err return err
} }
func rmAllInactive(ctx context.Context, txn *store.Txn, dockerCli command.Cli, in rmOptions) error {
ctx, cancel := context.WithTimeout(ctx, 20*time.Second)
defer cancel()
ll, err := txn.List()
if err != nil {
return err
}
builders := make([]*nginfo, len(ll))
for i, ng := range ll {
builders[i] = &nginfo{ng: ng}
}
eg, _ := errgroup.WithContext(ctx)
for _, b := range builders {
func(b *nginfo) {
eg.Go(func() error {
if err := loadNodeGroupData(ctx, dockerCli, b); err != nil {
return errors.Wrapf(err, "cannot load %s", b.ng.Name)
}
if b.ng.Dynamic {
return nil
}
if b.inactive() {
rmerr := rm(ctx, dockerCli, in, b.ng)
if err := txn.Remove(b.ng.Name); err != nil {
return err
}
return rmerr
}
return nil
})
}(b)
}
return eg.Wait()
}

@ -389,6 +389,17 @@ type nginfo struct {
err error err error
} }
// inactive checks if all nodes are inactive for this builder
func (n *nginfo) inactive() bool {
for idx := range n.ng.Nodes {
d := n.drivers[idx]
if d.info != nil && d.info.Status == driver.Running {
return false
}
}
return true
}
func boot(ctx context.Context, ngi *nginfo) (bool, error) { func boot(ctx context.Context, ngi *nginfo) (bool, error) {
toBoot := make([]int, 0, len(ngi.drivers)) toBoot := make([]int, 0, len(ngi.drivers))
for i, d := range ngi.drivers { for i, d := range ngi.drivers {

@ -11,7 +11,9 @@ Remove a builder instance
| Name | Description | | Name | Description |
| --- | --- | | --- | --- |
| [`--all-inactive`](#all-inactive) | Remove all inactive builders |
| [`--builder string`](#builder) | Override the configured builder instance | | [`--builder string`](#builder) | Override the configured builder instance |
| [`-f`](#force), [`--force`](#force) | Do not prompt for confirmation |
| [`--keep-daemon`](#keep-daemon) | Keep the buildkitd daemon running | | [`--keep-daemon`](#keep-daemon) | Keep the buildkitd daemon running |
| [`--keep-state`](#keep-state) | Keep BuildKit state | | [`--keep-state`](#keep-state) | Keep BuildKit state |
@ -25,16 +27,33 @@ default builder.
## Examples ## Examples
### <a name="all-inactive"></a> Remove all inactive builders (--all-inactive)
Remove builders that are not in running state.
```console
$ docker buildx rm --all-inactive
WARNING! This will remove all builders that are not in running state. Are you sure you want to continue? [y/N] y
```
### <a name="builder"></a> Override the configured builder instance (--builder) ### <a name="builder"></a> Override the configured builder instance (--builder)
Same as [`buildx --builder`](buildx.md#builder). Same as [`buildx --builder`](buildx.md#builder).
### <a name="keep-state"></a> Keep BuildKit state (--keep-state) ### <a name="force"></a> Do not prompt for confirmation (--force)
Keep BuildKit state, so it can be reused by a new builder with the same name. Do not prompt for confirmation before removing inactive builders.
Currently, only supported by the [`docker-container` driver](buildx_create.md#driver).
```console
$ docker buildx rm --all-inactive --force
```
### <a name="keep-daemon"></a> Keep the buildkitd daemon running (--keep-daemon) ### <a name="keep-daemon"></a> Keep the buildkitd daemon running (--keep-daemon)
Keep the buildkitd daemon running after the buildx context is removed. This is useful when you manage buildkitd daemons and buildx contexts independently. Keep the buildkitd daemon running after the buildx context is removed. This is useful when you manage buildkitd daemons and buildx contexts independently.
Currently, only supported by the [`docker-container` and `kubernetes` drivers](buildx_create.md#driver). Currently, only supported by the [`docker-container` and `kubernetes` drivers](buildx_create.md#driver).
### <a name="keep-state"></a> Keep BuildKit state (--keep-state)
Keep BuildKit state, so it can be reused by a new builder with the same name.
Currently, only supported by the [`docker-container` driver](buildx_create.md#driver).

Loading…
Cancel
Save