Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
77 changes: 69 additions & 8 deletions commands/rm.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,36 +2,53 @@ package commands

import (
"context"
"time"

"github.com/docker/buildx/store"
"github.com/docker/buildx/store/storeutil"
"github.com/docker/cli/cli"
"github.com/docker/cli/cli/command"
"github.com/moby/buildkit/util/appcontext"
"github.com/pkg/errors"
"github.com/spf13/cobra"
"golang.org/x/sync/errgroup"
)

type rmOptions struct {
builder string
keepState bool
keepDaemon bool
builder string
keepState 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 {
ctx := appcontext.Context()

if in.allInactive && !in.force && !command.PromptForConfirmation(dockerCli.In(), dockerCli.Out(), rmInactiveWarning) {
return nil
}

txn, release, err := storeutil.GetStore(dockerCli)
if err != nil {
return err
}
defer release()

if in.allInactive {
return rmAllInactive(ctx, txn, dockerCli, in)
}

if in.builder != "" {
ng, err := storeutil.GetNodeGroup(txn, dockerCli, in.builder)
if err != nil {
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 {
return err
}
Expand All @@ -43,7 +60,7 @@ func runRm(dockerCli command.Cli, in rmOptions) error {
return err
}
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 {
return err
}
Expand All @@ -63,6 +80,9 @@ func rmCmd(dockerCli command.Cli, rootOpts *rootOptions) *cobra.Command {
RunE: func(cmd *cobra.Command, args []string) error {
options.builder = rootOpts.builder
if len(args) > 0 {
if options.allInactive {
return errors.New("cannot specify builder name when --all-inactive is set")
}
options.builder = args[0]
}
return runRm(dockerCli, options)
Expand All @@ -72,11 +92,13 @@ func rmCmd(dockerCli command.Cli, rootOpts *rootOptions) *cobra.Command {
flags := cmd.Flags()
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.allInactive, "all-inactive", false, "Remove all inactive builders")
flags.BoolVarP(&options.force, "force", "f", false, "Do not prompt for confirmation")

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, "")
if err != nil {
return err
Expand All @@ -86,12 +108,12 @@ func rm(ctx context.Context, dockerCli command.Cli, ng *store.NodeGroup, keepSta
continue
}
// 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 {
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
}
if di.Err != nil {
Expand All @@ -100,3 +122,42 @@ func rm(ctx context.Context, dockerCli command.Cli, ng *store.NodeGroup, keepSta
}
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()
}
11 changes: 11 additions & 0 deletions commands/util.go
Original file line number Diff line number Diff line change
Expand Up @@ -389,6 +389,17 @@ type nginfo struct {
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) {
toBoot := make([]int, 0, len(ngi.drivers))
for i, d := range ngi.drivers {
Expand Down
25 changes: 22 additions & 3 deletions docs/reference/buildx_rm.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,9 @@ Remove a builder instance

| Name | Description |
| --- | --- |
| [`--all-inactive`](#all-inactive) | Remove all inactive builders |
| [`--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-state`](#keep-state) | Keep BuildKit state |

Expand All @@ -25,16 +27,33 @@ default builder.

## 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)

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.
Currently, only supported by the [`docker-container` driver](buildx_create.md#driver).
Do not prompt for confirmation before removing inactive builders.

```console
$ docker buildx rm --all-inactive --force
```

### <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.
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).