Merge pull request #5791 from thaJeztah/multi_errors
cli/command: use errors.Join instead of our own implementation
This commit is contained in:
commit
7c3fa8172b
@ -2,12 +2,11 @@ package config
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"strings"
|
|
||||||
|
|
||||||
"github.com/docker/cli/cli"
|
"github.com/docker/cli/cli"
|
||||||
"github.com/docker/cli/cli/command"
|
"github.com/docker/cli/cli/command"
|
||||||
"github.com/pkg/errors"
|
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -35,23 +34,17 @@ func newConfigRemoveCommand(dockerCli command.Cli) *cobra.Command {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// RunConfigRemove removes the given Swarm configs.
|
// RunConfigRemove removes the given Swarm configs.
|
||||||
func RunConfigRemove(ctx context.Context, dockerCli command.Cli, opts RemoveOptions) error {
|
func RunConfigRemove(ctx context.Context, dockerCLI command.Cli, opts RemoveOptions) error {
|
||||||
client := dockerCli.Client()
|
apiClient := dockerCLI.Client()
|
||||||
|
|
||||||
var errs []string
|
|
||||||
|
|
||||||
|
var errs []error
|
||||||
for _, name := range opts.Names {
|
for _, name := range opts.Names {
|
||||||
if err := client.ConfigRemove(ctx, name); err != nil {
|
if err := apiClient.ConfigRemove(ctx, name); err != nil {
|
||||||
errs = append(errs, err.Error())
|
errs = append(errs, err)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
_, _ = fmt.Fprintln(dockerCLI.Out(), name)
|
||||||
fmt.Fprintln(dockerCli.Out(), name)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(errs) > 0 {
|
return errors.Join(errs...)
|
||||||
return errors.Errorf("%s", strings.Join(errs, "\n"))
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
@ -2,13 +2,12 @@ package container
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"strings"
|
|
||||||
|
|
||||||
"github.com/docker/cli/cli"
|
"github.com/docker/cli/cli"
|
||||||
"github.com/docker/cli/cli/command"
|
"github.com/docker/cli/cli/command"
|
||||||
"github.com/docker/cli/cli/command/completion"
|
"github.com/docker/cli/cli/command/completion"
|
||||||
"github.com/pkg/errors"
|
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -44,20 +43,19 @@ func NewKillCommand(dockerCli command.Cli) *cobra.Command {
|
|||||||
return cmd
|
return cmd
|
||||||
}
|
}
|
||||||
|
|
||||||
func runKill(ctx context.Context, dockerCli command.Cli, opts *killOptions) error {
|
func runKill(ctx context.Context, dockerCLI command.Cli, opts *killOptions) error {
|
||||||
var errs []string
|
apiClient := dockerCLI.Client()
|
||||||
errChan := parallelOperation(ctx, opts.containers, func(ctx context.Context, container string) error {
|
errChan := parallelOperation(ctx, opts.containers, func(ctx context.Context, container string) error {
|
||||||
return dockerCli.Client().ContainerKill(ctx, container, opts.signal)
|
return apiClient.ContainerKill(ctx, container, opts.signal)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
var errs []error
|
||||||
for _, name := range opts.containers {
|
for _, name := range opts.containers {
|
||||||
if err := <-errChan; err != nil {
|
if err := <-errChan; err != nil {
|
||||||
errs = append(errs, err.Error())
|
errs = append(errs, err)
|
||||||
} else {
|
continue
|
||||||
_, _ = fmt.Fprintln(dockerCli.Out(), name)
|
|
||||||
}
|
}
|
||||||
|
_, _ = fmt.Fprintln(dockerCLI.Out(), name)
|
||||||
}
|
}
|
||||||
if len(errs) > 0 {
|
return errors.Join(errs...)
|
||||||
return errors.New(strings.Join(errs, "\n"))
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
@ -2,14 +2,13 @@ package container
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"strings"
|
|
||||||
|
|
||||||
"github.com/docker/cli/cli"
|
"github.com/docker/cli/cli"
|
||||||
"github.com/docker/cli/cli/command"
|
"github.com/docker/cli/cli/command"
|
||||||
"github.com/docker/cli/cli/command/completion"
|
"github.com/docker/cli/cli/command/completion"
|
||||||
"github.com/docker/docker/api/types/container"
|
"github.com/docker/docker/api/types/container"
|
||||||
"github.com/pkg/errors"
|
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -38,18 +37,17 @@ func NewPauseCommand(dockerCli command.Cli) *cobra.Command {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func runPause(ctx context.Context, dockerCli command.Cli, opts *pauseOptions) error {
|
func runPause(ctx context.Context, dockerCLI command.Cli, opts *pauseOptions) error {
|
||||||
var errs []string
|
apiClient := dockerCLI.Client()
|
||||||
errChan := parallelOperation(ctx, opts.containers, dockerCli.Client().ContainerPause)
|
errChan := parallelOperation(ctx, opts.containers, apiClient.ContainerPause)
|
||||||
|
|
||||||
|
var errs []error
|
||||||
for _, ctr := range opts.containers {
|
for _, ctr := range opts.containers {
|
||||||
if err := <-errChan; err != nil {
|
if err := <-errChan; err != nil {
|
||||||
errs = append(errs, err.Error())
|
errs = append(errs, err)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
_, _ = fmt.Fprintln(dockerCli.Out(), ctr)
|
_, _ = fmt.Fprintln(dockerCLI.Out(), ctr)
|
||||||
}
|
}
|
||||||
if len(errs) > 0 {
|
return errors.Join(errs...)
|
||||||
return errors.New(strings.Join(errs, "\n"))
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
@ -2,14 +2,13 @@ package container
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"strings"
|
|
||||||
|
|
||||||
"github.com/docker/cli/cli"
|
"github.com/docker/cli/cli"
|
||||||
"github.com/docker/cli/cli/command"
|
"github.com/docker/cli/cli/command"
|
||||||
"github.com/docker/cli/cli/command/completion"
|
"github.com/docker/cli/cli/command/completion"
|
||||||
"github.com/docker/docker/api/types/container"
|
"github.com/docker/docker/api/types/container"
|
||||||
"github.com/pkg/errors"
|
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -56,27 +55,25 @@ func NewRestartCommand(dockerCli command.Cli) *cobra.Command {
|
|||||||
return cmd
|
return cmd
|
||||||
}
|
}
|
||||||
|
|
||||||
func runRestart(ctx context.Context, dockerCli command.Cli, opts *restartOptions) error {
|
func runRestart(ctx context.Context, dockerCLI command.Cli, opts *restartOptions) error {
|
||||||
var errs []string
|
|
||||||
var timeout *int
|
var timeout *int
|
||||||
if opts.timeoutChanged {
|
if opts.timeoutChanged {
|
||||||
timeout = &opts.timeout
|
timeout = &opts.timeout
|
||||||
}
|
}
|
||||||
|
|
||||||
|
apiClient := dockerCLI.Client()
|
||||||
|
var errs []error
|
||||||
// TODO(thaJeztah): consider using parallelOperation for restart, similar to "stop" and "remove"
|
// TODO(thaJeztah): consider using parallelOperation for restart, similar to "stop" and "remove"
|
||||||
for _, name := range opts.containers {
|
for _, name := range opts.containers {
|
||||||
err := dockerCli.Client().ContainerRestart(ctx, name, container.StopOptions{
|
err := apiClient.ContainerRestart(ctx, name, container.StopOptions{
|
||||||
Signal: opts.signal,
|
Signal: opts.signal,
|
||||||
Timeout: timeout,
|
Timeout: timeout,
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
errs = append(errs, err.Error())
|
errs = append(errs, err)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
_, _ = fmt.Fprintln(dockerCli.Out(), name)
|
_, _ = fmt.Fprintln(dockerCLI.Out(), name)
|
||||||
}
|
}
|
||||||
if len(errs) > 0 {
|
return errors.Join(errs...)
|
||||||
return errors.New(strings.Join(errs, "\n"))
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
@ -2,6 +2,7 @@ package container
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
@ -10,7 +11,6 @@ import (
|
|||||||
"github.com/docker/cli/cli/command/completion"
|
"github.com/docker/cli/cli/command/completion"
|
||||||
"github.com/docker/docker/api/types/container"
|
"github.com/docker/docker/api/types/container"
|
||||||
"github.com/docker/docker/errdefs"
|
"github.com/docker/docker/errdefs"
|
||||||
"github.com/pkg/errors"
|
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -50,33 +50,31 @@ func NewRmCommand(dockerCli command.Cli) *cobra.Command {
|
|||||||
return cmd
|
return cmd
|
||||||
}
|
}
|
||||||
|
|
||||||
func runRm(ctx context.Context, dockerCli command.Cli, opts *rmOptions) error {
|
func runRm(ctx context.Context, dockerCLI command.Cli, opts *rmOptions) error {
|
||||||
var errs []string
|
apiClient := dockerCLI.Client()
|
||||||
errChan := parallelOperation(ctx, opts.containers, func(ctx context.Context, ctrID string) error {
|
errChan := parallelOperation(ctx, opts.containers, func(ctx context.Context, ctrID string) error {
|
||||||
ctrID = strings.Trim(ctrID, "/")
|
ctrID = strings.Trim(ctrID, "/")
|
||||||
if ctrID == "" {
|
if ctrID == "" {
|
||||||
return errors.New("Container name cannot be empty")
|
return errors.New("container name cannot be empty")
|
||||||
}
|
}
|
||||||
return dockerCli.Client().ContainerRemove(ctx, ctrID, container.RemoveOptions{
|
return apiClient.ContainerRemove(ctx, ctrID, container.RemoveOptions{
|
||||||
RemoveVolumes: opts.rmVolumes,
|
RemoveVolumes: opts.rmVolumes,
|
||||||
RemoveLinks: opts.rmLink,
|
RemoveLinks: opts.rmLink,
|
||||||
Force: opts.force,
|
Force: opts.force,
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
var errs []error
|
||||||
for _, name := range opts.containers {
|
for _, name := range opts.containers {
|
||||||
if err := <-errChan; err != nil {
|
if err := <-errChan; err != nil {
|
||||||
if opts.force && errdefs.IsNotFound(err) {
|
if opts.force && errdefs.IsNotFound(err) {
|
||||||
fmt.Fprintln(dockerCli.Err(), err)
|
_, _ = fmt.Fprintln(dockerCLI.Err(), err)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
errs = append(errs, err.Error())
|
errs = append(errs, err)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
fmt.Fprintln(dockerCli.Out(), name)
|
_, _ = fmt.Fprintln(dockerCLI.Out(), name)
|
||||||
}
|
}
|
||||||
if len(errs) > 0 {
|
return errors.Join(errs...)
|
||||||
return errors.New(strings.Join(errs, "\n"))
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
@ -3,6 +3,7 @@ package container
|
|||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"context"
|
"context"
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"strings"
|
"strings"
|
||||||
@ -17,7 +18,6 @@ import (
|
|||||||
"github.com/docker/docker/api/types/container"
|
"github.com/docker/docker/api/types/container"
|
||||||
"github.com/docker/docker/api/types/events"
|
"github.com/docker/docker/api/types/events"
|
||||||
"github.com/docker/docker/api/types/filters"
|
"github.com/docker/docker/api/types/filters"
|
||||||
"github.com/pkg/errors"
|
|
||||||
"github.com/sirupsen/logrus"
|
"github.com/sirupsen/logrus"
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
)
|
)
|
||||||
@ -238,16 +238,16 @@ func RunStats(ctx context.Context, dockerCLI command.Cli, options *StatsOptions)
|
|||||||
// make sure each container get at least one valid stat data
|
// make sure each container get at least one valid stat data
|
||||||
waitFirst.Wait()
|
waitFirst.Wait()
|
||||||
|
|
||||||
var errs []string
|
var errs []error
|
||||||
cStats.mu.RLock()
|
cStats.mu.RLock()
|
||||||
for _, c := range cStats.cs {
|
for _, c := range cStats.cs {
|
||||||
if err := c.GetError(); err != nil {
|
if err := c.GetError(); err != nil {
|
||||||
errs = append(errs, err.Error())
|
errs = append(errs, err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
cStats.mu.RUnlock()
|
cStats.mu.RUnlock()
|
||||||
if len(errs) > 0 {
|
if err := errors.Join(errs...); err != nil {
|
||||||
return errors.New(strings.Join(errs, "\n"))
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2,14 +2,13 @@ package container
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"strings"
|
|
||||||
|
|
||||||
"github.com/docker/cli/cli"
|
"github.com/docker/cli/cli"
|
||||||
"github.com/docker/cli/cli/command"
|
"github.com/docker/cli/cli/command"
|
||||||
"github.com/docker/cli/cli/command/completion"
|
"github.com/docker/cli/cli/command/completion"
|
||||||
"github.com/docker/docker/api/types/container"
|
"github.com/docker/docker/api/types/container"
|
||||||
"github.com/pkg/errors"
|
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -56,28 +55,26 @@ func NewStopCommand(dockerCli command.Cli) *cobra.Command {
|
|||||||
return cmd
|
return cmd
|
||||||
}
|
}
|
||||||
|
|
||||||
func runStop(ctx context.Context, dockerCli command.Cli, opts *stopOptions) error {
|
func runStop(ctx context.Context, dockerCLI command.Cli, opts *stopOptions) error {
|
||||||
var timeout *int
|
var timeout *int
|
||||||
if opts.timeoutChanged {
|
if opts.timeoutChanged {
|
||||||
timeout = &opts.timeout
|
timeout = &opts.timeout
|
||||||
}
|
}
|
||||||
|
|
||||||
|
apiClient := dockerCLI.Client()
|
||||||
errChan := parallelOperation(ctx, opts.containers, func(ctx context.Context, id string) error {
|
errChan := parallelOperation(ctx, opts.containers, func(ctx context.Context, id string) error {
|
||||||
return dockerCli.Client().ContainerStop(ctx, id, container.StopOptions{
|
return apiClient.ContainerStop(ctx, id, container.StopOptions{
|
||||||
Signal: opts.signal,
|
Signal: opts.signal,
|
||||||
Timeout: timeout,
|
Timeout: timeout,
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
var errs []string
|
var errs []error
|
||||||
for _, ctr := range opts.containers {
|
for _, ctr := range opts.containers {
|
||||||
if err := <-errChan; err != nil {
|
if err := <-errChan; err != nil {
|
||||||
errs = append(errs, err.Error())
|
errs = append(errs, err)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
_, _ = fmt.Fprintln(dockerCli.Out(), ctr)
|
_, _ = fmt.Fprintln(dockerCLI.Out(), ctr)
|
||||||
}
|
}
|
||||||
if len(errs) > 0 {
|
return errors.Join(errs...)
|
||||||
return errors.New(strings.Join(errs, "\n"))
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
@ -2,14 +2,13 @@ package container
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"strings"
|
|
||||||
|
|
||||||
"github.com/docker/cli/cli"
|
"github.com/docker/cli/cli"
|
||||||
"github.com/docker/cli/cli/command"
|
"github.com/docker/cli/cli/command"
|
||||||
"github.com/docker/cli/cli/command/completion"
|
"github.com/docker/cli/cli/command/completion"
|
||||||
"github.com/docker/docker/api/types/container"
|
"github.com/docker/docker/api/types/container"
|
||||||
"github.com/pkg/errors"
|
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -39,18 +38,16 @@ func NewUnpauseCommand(dockerCli command.Cli) *cobra.Command {
|
|||||||
return cmd
|
return cmd
|
||||||
}
|
}
|
||||||
|
|
||||||
func runUnpause(ctx context.Context, dockerCli command.Cli, opts *unpauseOptions) error {
|
func runUnpause(ctx context.Context, dockerCLI command.Cli, opts *unpauseOptions) error {
|
||||||
var errs []string
|
apiClient := dockerCLI.Client()
|
||||||
errChan := parallelOperation(ctx, opts.containers, dockerCli.Client().ContainerUnpause)
|
errChan := parallelOperation(ctx, opts.containers, apiClient.ContainerUnpause)
|
||||||
|
var errs []error
|
||||||
for _, ctr := range opts.containers {
|
for _, ctr := range opts.containers {
|
||||||
if err := <-errChan; err != nil {
|
if err := <-errChan; err != nil {
|
||||||
errs = append(errs, err.Error())
|
errs = append(errs, err)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
_, _ = fmt.Fprintln(dockerCli.Out(), ctr)
|
_, _ = fmt.Fprintln(dockerCLI.Out(), ctr)
|
||||||
}
|
}
|
||||||
if len(errs) > 0 {
|
return errors.Join(errs...)
|
||||||
return errors.New(strings.Join(errs, "\n"))
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
@ -2,13 +2,12 @@ package container
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"strings"
|
|
||||||
|
|
||||||
"github.com/docker/cli/cli"
|
"github.com/docker/cli/cli"
|
||||||
"github.com/docker/cli/cli/command"
|
"github.com/docker/cli/cli/command"
|
||||||
"github.com/docker/cli/cli/command/completion"
|
"github.com/docker/cli/cli/command/completion"
|
||||||
"github.com/pkg/errors"
|
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -37,20 +36,19 @@ func NewWaitCommand(dockerCli command.Cli) *cobra.Command {
|
|||||||
return cmd
|
return cmd
|
||||||
}
|
}
|
||||||
|
|
||||||
func runWait(ctx context.Context, dockerCli command.Cli, opts *waitOptions) error {
|
func runWait(ctx context.Context, dockerCLI command.Cli, opts *waitOptions) error {
|
||||||
var errs []string
|
apiClient := dockerCLI.Client()
|
||||||
|
|
||||||
|
var errs []error
|
||||||
for _, ctr := range opts.containers {
|
for _, ctr := range opts.containers {
|
||||||
resultC, errC := dockerCli.Client().ContainerWait(ctx, ctr, "")
|
resultC, errC := apiClient.ContainerWait(ctx, ctr, "")
|
||||||
|
|
||||||
select {
|
select {
|
||||||
case result := <-resultC:
|
case result := <-resultC:
|
||||||
_, _ = fmt.Fprintf(dockerCli.Out(), "%d\n", result.StatusCode)
|
_, _ = fmt.Fprintf(dockerCLI.Out(), "%d\n", result.StatusCode)
|
||||||
case err := <-errC:
|
case err := <-errC:
|
||||||
errs = append(errs, err.Error())
|
errs = append(errs, err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if len(errs) > 0 {
|
return errors.Join(errs...)
|
||||||
return errors.New(strings.Join(errs, "\n"))
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
@ -1,14 +1,14 @@
|
|||||||
package context
|
package context
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
|
||||||
|
|
||||||
"github.com/docker/cli/cli/context"
|
"github.com/docker/cli/cli/context"
|
||||||
"github.com/docker/cli/cli/context/docker"
|
"github.com/docker/cli/cli/context/docker"
|
||||||
"github.com/docker/cli/cli/context/store"
|
"github.com/docker/cli/cli/context/store"
|
||||||
"github.com/docker/docker/client"
|
"github.com/docker/docker/client"
|
||||||
"github.com/pkg/errors"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@ -68,20 +68,17 @@ func parseBool(config map[string]string, name string) (bool, error) {
|
|||||||
return false, nil
|
return false, nil
|
||||||
}
|
}
|
||||||
res, err := strconv.ParseBool(strVal)
|
res, err := strconv.ParseBool(strVal)
|
||||||
return res, errors.Wrap(err, name)
|
return res, fmt.Errorf("name: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
func validateConfig(config map[string]string, allowedKeys map[string]struct{}) error {
|
func validateConfig(config map[string]string, allowedKeys map[string]struct{}) error {
|
||||||
var errs []string
|
var errs []error
|
||||||
for k := range config {
|
for k := range config {
|
||||||
if _, ok := allowedKeys[k]; !ok {
|
if _, ok := allowedKeys[k]; !ok {
|
||||||
errs = append(errs, "unrecognized config key: "+k)
|
errs = append(errs, errors.New("unrecognized config key: "+k))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if len(errs) == 0 {
|
return errors.Join(errs...)
|
||||||
return nil
|
|
||||||
}
|
|
||||||
return errors.New(strings.Join(errs, "\n"))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func getDockerEndpoint(contextStore store.Reader, config map[string]string) (docker.Endpoint, error) {
|
func getDockerEndpoint(contextStore store.Reader, config map[string]string) (docker.Endpoint, error) {
|
||||||
@ -96,7 +93,7 @@ func getDockerEndpoint(contextStore store.Reader, config map[string]string) (doc
|
|||||||
if ep, ok := metadata.Endpoints[docker.DockerEndpoint].(docker.EndpointMeta); ok {
|
if ep, ok := metadata.Endpoints[docker.DockerEndpoint].(docker.EndpointMeta); ok {
|
||||||
return docker.Endpoint{EndpointMeta: ep}, nil
|
return docker.Endpoint{EndpointMeta: ep}, nil
|
||||||
}
|
}
|
||||||
return docker.Endpoint{}, errors.Errorf("unable to get endpoint from context %q", contextName)
|
return docker.Endpoint{}, fmt.Errorf("unable to get endpoint from context %q", contextName)
|
||||||
}
|
}
|
||||||
tlsData, err := context.TLSDataFromFiles(config[keyCA], config[keyCert], config[keyKey])
|
tlsData, err := context.TLSDataFromFiles(config[keyCA], config[keyCert], config[keyKey])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -116,10 +113,11 @@ func getDockerEndpoint(contextStore store.Reader, config map[string]string) (doc
|
|||||||
// try to resolve a docker client, validating the configuration
|
// try to resolve a docker client, validating the configuration
|
||||||
opts, err := ep.ClientOpts()
|
opts, err := ep.ClientOpts()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return docker.Endpoint{}, errors.Wrap(err, "invalid docker endpoint options")
|
return docker.Endpoint{}, fmt.Errorf("invalid docker endpoint options: %w", err)
|
||||||
}
|
}
|
||||||
|
// FIXME(thaJeztah): this creates a new client (but discards it) only to validate the options; are the validation steps above not enough?
|
||||||
if _, err := client.NewClientWithOpts(opts...); err != nil {
|
if _, err := client.NewClientWithOpts(opts...); err != nil {
|
||||||
return docker.Endpoint{}, errors.Wrap(err, "unable to apply docker endpoint options")
|
return docker.Endpoint{}, fmt.Errorf("unable to apply docker endpoint options: %w", err)
|
||||||
}
|
}
|
||||||
return ep, nil
|
return ep, nil
|
||||||
}
|
}
|
||||||
|
@ -1,14 +1,13 @@
|
|||||||
package context
|
package context
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
"strings"
|
|
||||||
|
|
||||||
"github.com/docker/cli/cli"
|
"github.com/docker/cli/cli"
|
||||||
"github.com/docker/cli/cli/command"
|
"github.com/docker/cli/cli/command"
|
||||||
"github.com/docker/docker/errdefs"
|
"github.com/docker/docker/errdefs"
|
||||||
"github.com/pkg/errors"
|
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -33,28 +32,25 @@ func newRemoveCommand(dockerCli command.Cli) *cobra.Command {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// RunRemove removes one or more contexts
|
// RunRemove removes one or more contexts
|
||||||
func RunRemove(dockerCli command.Cli, opts RemoveOptions, names []string) error {
|
func RunRemove(dockerCLI command.Cli, opts RemoveOptions, names []string) error {
|
||||||
var errs []string
|
var errs []error
|
||||||
currentCtx := dockerCli.CurrentContext()
|
currentCtx := dockerCLI.CurrentContext()
|
||||||
for _, name := range names {
|
for _, name := range names {
|
||||||
if name == "default" {
|
if name == "default" {
|
||||||
errs = append(errs, `default: context "default" cannot be removed`)
|
errs = append(errs, errors.New(`context "default" cannot be removed`))
|
||||||
} else if err := doRemove(dockerCli, name, name == currentCtx, opts.Force); err != nil {
|
} else if err := doRemove(dockerCLI, name, name == currentCtx, opts.Force); err != nil {
|
||||||
errs = append(errs, err.Error())
|
errs = append(errs, err)
|
||||||
} else {
|
} else {
|
||||||
fmt.Fprintln(dockerCli.Out(), name)
|
_, _ = fmt.Fprintln(dockerCLI.Out(), name)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if len(errs) > 0 {
|
return errors.Join(errs...)
|
||||||
return errors.New(strings.Join(errs, "\n"))
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func doRemove(dockerCli command.Cli, name string, isCurrent, force bool) error {
|
func doRemove(dockerCli command.Cli, name string, isCurrent, force bool) error {
|
||||||
if isCurrent {
|
if isCurrent {
|
||||||
if !force {
|
if !force {
|
||||||
return errors.Errorf("context %q is in use, set -f flag to force remove", name)
|
return fmt.Errorf("context %q is in use, set -f flag to force remove", name)
|
||||||
}
|
}
|
||||||
// fallback to DOCKER_HOST
|
// fallback to DOCKER_HOST
|
||||||
cfg := dockerCli.ConfigFile()
|
cfg := dockerCli.ConfigFile()
|
||||||
@ -65,6 +61,7 @@ func doRemove(dockerCli command.Cli, name string, isCurrent, force bool) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if !force {
|
if !force {
|
||||||
|
// TODO(thaJeztah): instead of checking before removing, can we make ContextStore().Remove() return a proper errdef and ignore "not found" errors?
|
||||||
if err := checkContextExists(dockerCli, name); err != nil {
|
if err := checkContextExists(dockerCli, name); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -77,7 +74,7 @@ func checkContextExists(dockerCli command.Cli, name string) error {
|
|||||||
contextDir := dockerCli.ContextStore().GetStorageInfo(name).MetadataPath
|
contextDir := dockerCli.ContextStore().GetStorageInfo(name).MetadataPath
|
||||||
_, err := os.Stat(contextDir)
|
_, err := os.Stat(contextDir)
|
||||||
if os.IsNotExist(err) {
|
if os.IsNotExist(err) {
|
||||||
return errdefs.NotFound(errors.Errorf("context %q does not exist", name))
|
return errdefs.NotFound(fmt.Errorf("context %q does not exist", name))
|
||||||
}
|
}
|
||||||
// Ignore other errors; if relevant, they will produce an error when
|
// Ignore other errors; if relevant, they will produce an error when
|
||||||
// performing the actual delete.
|
// performing the actual delete.
|
||||||
|
@ -60,5 +60,5 @@ func TestRemoveDefault(t *testing.T) {
|
|||||||
createTestContext(t, cli, "other", nil)
|
createTestContext(t, cli, "other", nil)
|
||||||
cli.SetCurrentContext("current")
|
cli.SetCurrentContext("current")
|
||||||
err := RunRemove(cli, RemoveOptions{}, []string{"default"})
|
err := RunRemove(cli, RemoveOptions{}, []string{"default"})
|
||||||
assert.ErrorContains(t, err, `default: context "default" cannot be removed`)
|
assert.ErrorContains(t, err, `context "default" cannot be removed`)
|
||||||
}
|
}
|
||||||
|
@ -2,15 +2,14 @@ package image
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"strings"
|
|
||||||
|
|
||||||
"github.com/docker/cli/cli"
|
"github.com/docker/cli/cli"
|
||||||
"github.com/docker/cli/cli/command"
|
"github.com/docker/cli/cli/command"
|
||||||
"github.com/docker/cli/cli/command/completion"
|
"github.com/docker/cli/cli/command/completion"
|
||||||
"github.com/docker/docker/api/types/image"
|
"github.com/docker/docker/api/types/image"
|
||||||
"github.com/docker/docker/errdefs"
|
"github.com/docker/docker/errdefs"
|
||||||
"github.com/pkg/errors"
|
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -59,15 +58,16 @@ func runRemove(ctx context.Context, dockerCLI command.Cli, opts removeOptions, i
|
|||||||
PruneChildren: !opts.noPrune,
|
PruneChildren: !opts.noPrune,
|
||||||
}
|
}
|
||||||
|
|
||||||
var errs []string
|
// TODO(thaJeztah): this logic can likely be simplified: do we want to print "not found" errors at all when using "force"?
|
||||||
fatalErr := false
|
fatalErr := false
|
||||||
|
var errs []error
|
||||||
for _, img := range images {
|
for _, img := range images {
|
||||||
dels, err := apiClient.ImageRemove(ctx, img, options)
|
dels, err := apiClient.ImageRemove(ctx, img, options)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if !errdefs.IsNotFound(err) {
|
if !errdefs.IsNotFound(err) {
|
||||||
fatalErr = true
|
fatalErr = true
|
||||||
}
|
}
|
||||||
errs = append(errs, err.Error())
|
errs = append(errs, err)
|
||||||
} else {
|
} else {
|
||||||
for _, del := range dels {
|
for _, del := range dels {
|
||||||
if del.Deleted != "" {
|
if del.Deleted != "" {
|
||||||
@ -79,12 +79,11 @@ func runRemove(ctx context.Context, dockerCLI command.Cli, opts removeOptions, i
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(errs) > 0 {
|
if err := errors.Join(errs...); err != nil {
|
||||||
msg := strings.Join(errs, "\n")
|
|
||||||
if !opts.force || fatalErr {
|
if !opts.force || fatalErr {
|
||||||
return errors.New(msg)
|
return err
|
||||||
}
|
}
|
||||||
_, _ = fmt.Fprintln(dockerCLI.Err(), msg)
|
_, _ = fmt.Fprintln(dockerCLI.Err(), err)
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -6,13 +6,13 @@ package inspect
|
|||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"strings"
|
|
||||||
"text/template"
|
"text/template"
|
||||||
|
|
||||||
"github.com/docker/cli/cli"
|
"github.com/docker/cli/cli"
|
||||||
"github.com/docker/cli/templates"
|
"github.com/docker/cli/templates"
|
||||||
"github.com/pkg/errors"
|
|
||||||
"github.com/sirupsen/logrus"
|
"github.com/sirupsen/logrus"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -53,7 +53,7 @@ func NewTemplateInspectorFromString(out io.Writer, tmplStr string) (Inspector, e
|
|||||||
|
|
||||||
tmpl, err := templates.Parse(tmplStr)
|
tmpl, err := templates.Parse(tmplStr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, errors.Errorf("template parsing error: %s", err)
|
return nil, fmt.Errorf("template parsing error: %w", err)
|
||||||
}
|
}
|
||||||
return NewTemplateInspector(out, tmpl), nil
|
return NewTemplateInspector(out, tmpl), nil
|
||||||
}
|
}
|
||||||
@ -70,16 +70,16 @@ func Inspect(out io.Writer, references []string, tmplStr string, getRef GetRefFu
|
|||||||
return cli.StatusError{StatusCode: 64, Status: err.Error()}
|
return cli.StatusError{StatusCode: 64, Status: err.Error()}
|
||||||
}
|
}
|
||||||
|
|
||||||
var inspectErrs []string
|
var errs []error
|
||||||
for _, ref := range references {
|
for _, ref := range references {
|
||||||
element, raw, err := getRef(ref)
|
element, raw, err := getRef(ref)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
inspectErrs = append(inspectErrs, err.Error())
|
errs = append(errs, err)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := inspector.Inspect(element, raw); err != nil {
|
if err := inspector.Inspect(element, raw); err != nil {
|
||||||
inspectErrs = append(inspectErrs, err.Error())
|
errs = append(errs, err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -87,10 +87,10 @@ func Inspect(out io.Writer, references []string, tmplStr string, getRef GetRefFu
|
|||||||
logrus.Error(err)
|
logrus.Error(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(inspectErrs) != 0 {
|
if err := errors.Join(errs...); err != nil {
|
||||||
return cli.StatusError{
|
return cli.StatusError{
|
||||||
StatusCode: 1,
|
StatusCode: 1,
|
||||||
Status: strings.Join(inspectErrs, "\n"),
|
Status: err.Error(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
@ -103,7 +103,7 @@ func (i *TemplateInspector) Inspect(typedElement any, rawElement []byte) error {
|
|||||||
buffer := new(bytes.Buffer)
|
buffer := new(bytes.Buffer)
|
||||||
if err := i.tmpl.Execute(buffer, typedElement); err != nil {
|
if err := i.tmpl.Execute(buffer, typedElement); err != nil {
|
||||||
if rawElement == nil {
|
if rawElement == nil {
|
||||||
return errors.Errorf("template parsing error: %v", err)
|
return fmt.Errorf("template parsing error: %w", err)
|
||||||
}
|
}
|
||||||
return i.tryRawInspectFallback(rawElement)
|
return i.tryRawInspectFallback(rawElement)
|
||||||
}
|
}
|
||||||
@ -121,13 +121,13 @@ func (i *TemplateInspector) tryRawInspectFallback(rawElement []byte) error {
|
|||||||
dec := json.NewDecoder(rdr)
|
dec := json.NewDecoder(rdr)
|
||||||
dec.UseNumber()
|
dec.UseNumber()
|
||||||
|
|
||||||
if rawErr := dec.Decode(&raw); rawErr != nil {
|
if err := dec.Decode(&raw); err != nil {
|
||||||
return errors.Errorf("unable to read inspect data: %v", rawErr)
|
return fmt.Errorf("unable to read inspect data: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
tmplMissingKey := i.tmpl.Option("missingkey=error")
|
tmplMissingKey := i.tmpl.Option("missingkey=error")
|
||||||
if rawErr := tmplMissingKey.Execute(buffer, raw); rawErr != nil {
|
if err := tmplMissingKey.Execute(buffer, raw); err != nil {
|
||||||
return errors.Errorf("template parsing error: %v", rawErr)
|
return fmt.Errorf("template parsing error: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
i.buffer.Write(buffer.Bytes())
|
i.buffer.Write(buffer.Bytes())
|
||||||
|
@ -2,47 +2,47 @@ package manifest
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"strings"
|
"errors"
|
||||||
|
|
||||||
"github.com/docker/cli/cli"
|
"github.com/docker/cli/cli"
|
||||||
"github.com/docker/cli/cli/command"
|
"github.com/docker/cli/cli/command"
|
||||||
"github.com/pkg/errors"
|
manifeststore "github.com/docker/cli/cli/manifest/store"
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
)
|
)
|
||||||
|
|
||||||
func newRmManifestListCommand(dockerCli command.Cli) *cobra.Command {
|
func newRmManifestListCommand(dockerCLI command.Cli) *cobra.Command {
|
||||||
cmd := &cobra.Command{
|
cmd := &cobra.Command{
|
||||||
Use: "rm MANIFEST_LIST [MANIFEST_LIST...]",
|
Use: "rm MANIFEST_LIST [MANIFEST_LIST...]",
|
||||||
Short: "Delete one or more manifest lists from local storage",
|
Short: "Delete one or more manifest lists from local storage",
|
||||||
Args: cli.RequiresMinArgs(1),
|
Args: cli.RequiresMinArgs(1),
|
||||||
RunE: func(cmd *cobra.Command, args []string) error {
|
RunE: func(cmd *cobra.Command, args []string) error {
|
||||||
return runRm(cmd.Context(), dockerCli, args)
|
return runRemove(cmd.Context(), dockerCLI.ManifestStore(), args)
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
return cmd
|
return cmd
|
||||||
}
|
}
|
||||||
|
|
||||||
func runRm(_ context.Context, dockerCli command.Cli, targets []string) error {
|
func runRemove(ctx context.Context, store manifeststore.Store, targets []string) error {
|
||||||
var errs []string
|
var errs []error
|
||||||
for _, target := range targets {
|
for _, target := range targets {
|
||||||
targetRef, refErr := normalizeReference(target)
|
if ctx.Err() != nil {
|
||||||
if refErr != nil {
|
return ctx.Err()
|
||||||
errs = append(errs, refErr.Error())
|
}
|
||||||
|
targetRef, err := normalizeReference(target)
|
||||||
|
if err != nil {
|
||||||
|
errs = append(errs, err)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
_, searchErr := dockerCli.ManifestStore().GetList(targetRef)
|
_, err = store.GetList(targetRef)
|
||||||
if searchErr != nil {
|
if err != nil {
|
||||||
errs = append(errs, searchErr.Error())
|
errs = append(errs, err)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
rmErr := dockerCli.ManifestStore().Remove(targetRef)
|
err = store.Remove(targetRef)
|
||||||
if rmErr != nil {
|
if err != nil {
|
||||||
errs = append(errs, rmErr.Error())
|
errs = append(errs, err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if len(errs) > 0 {
|
return errors.Join(errs...)
|
||||||
return errors.New(strings.Join(errs, "\n"))
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
@ -2,13 +2,12 @@ package node
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"strings"
|
|
||||||
|
|
||||||
"github.com/docker/cli/cli"
|
"github.com/docker/cli/cli"
|
||||||
"github.com/docker/cli/cli/command"
|
"github.com/docker/cli/cli/command"
|
||||||
"github.com/docker/docker/api/types"
|
"github.com/docker/docker/api/types"
|
||||||
"github.com/pkg/errors"
|
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -36,20 +35,13 @@ func newRemoveCommand(dockerCli command.Cli) *cobra.Command {
|
|||||||
func runRemove(ctx context.Context, dockerCLI command.Cli, nodeIDs []string, opts removeOptions) error {
|
func runRemove(ctx context.Context, dockerCLI command.Cli, nodeIDs []string, opts removeOptions) error {
|
||||||
apiClient := dockerCLI.Client()
|
apiClient := dockerCLI.Client()
|
||||||
|
|
||||||
var errs []string
|
var errs []error
|
||||||
|
|
||||||
for _, id := range nodeIDs {
|
for _, id := range nodeIDs {
|
||||||
err := apiClient.NodeRemove(ctx, id, types.NodeRemoveOptions{Force: opts.force})
|
if err := apiClient.NodeRemove(ctx, id, types.NodeRemoveOptions{Force: opts.force}); err != nil {
|
||||||
if err != nil {
|
errs = append(errs, err)
|
||||||
errs = append(errs, err.Error())
|
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
_, _ = fmt.Fprintln(dockerCLI.Out(), id)
|
_, _ = fmt.Fprintln(dockerCLI.Out(), id)
|
||||||
}
|
}
|
||||||
|
return errors.Join(errs...)
|
||||||
if len(errs) > 0 {
|
|
||||||
return errors.Errorf("%s", strings.Join(errs, "\n"))
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
@ -2,12 +2,11 @@ package secret
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"strings"
|
|
||||||
|
|
||||||
"github.com/docker/cli/cli"
|
"github.com/docker/cli/cli"
|
||||||
"github.com/docker/cli/cli/command"
|
"github.com/docker/cli/cli/command"
|
||||||
"github.com/pkg/errors"
|
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -15,7 +14,7 @@ type removeOptions struct {
|
|||||||
names []string
|
names []string
|
||||||
}
|
}
|
||||||
|
|
||||||
func newSecretRemoveCommand(dockerCli command.Cli) *cobra.Command {
|
func newSecretRemoveCommand(dockerCLI command.Cli) *cobra.Command {
|
||||||
return &cobra.Command{
|
return &cobra.Command{
|
||||||
Use: "rm SECRET [SECRET...]",
|
Use: "rm SECRET [SECRET...]",
|
||||||
Aliases: []string{"remove"},
|
Aliases: []string{"remove"},
|
||||||
@ -25,31 +24,24 @@ func newSecretRemoveCommand(dockerCli command.Cli) *cobra.Command {
|
|||||||
opts := removeOptions{
|
opts := removeOptions{
|
||||||
names: args,
|
names: args,
|
||||||
}
|
}
|
||||||
return runSecretRemove(cmd.Context(), dockerCli, opts)
|
return runRemove(cmd.Context(), dockerCLI, opts)
|
||||||
},
|
},
|
||||||
ValidArgsFunction: func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
|
ValidArgsFunction: func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
|
||||||
return completeNames(dockerCli)(cmd, args, toComplete)
|
return completeNames(dockerCLI)(cmd, args, toComplete)
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func runSecretRemove(ctx context.Context, dockerCli command.Cli, opts removeOptions) error {
|
func runRemove(ctx context.Context, dockerCLI command.Cli, opts removeOptions) error {
|
||||||
client := dockerCli.Client()
|
apiClient := dockerCLI.Client()
|
||||||
|
|
||||||
var errs []string
|
|
||||||
|
|
||||||
|
var errs []error
|
||||||
for _, name := range opts.names {
|
for _, name := range opts.names {
|
||||||
if err := client.SecretRemove(ctx, name); err != nil {
|
if err := apiClient.SecretRemove(ctx, name); err != nil {
|
||||||
errs = append(errs, err.Error())
|
errs = append(errs, err)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
_, _ = fmt.Fprintln(dockerCLI.Out(), name)
|
||||||
fmt.Fprintln(dockerCli.Out(), name)
|
|
||||||
}
|
}
|
||||||
|
return errors.Join(errs...)
|
||||||
if len(errs) > 0 {
|
|
||||||
return errors.Errorf("%s", strings.Join(errs, "\n"))
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
@ -2,12 +2,11 @@ package service
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"strings"
|
|
||||||
|
|
||||||
"github.com/docker/cli/cli"
|
"github.com/docker/cli/cli"
|
||||||
"github.com/docker/cli/cli/command"
|
"github.com/docker/cli/cli/command"
|
||||||
"github.com/pkg/errors"
|
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -32,17 +31,13 @@ func newRemoveCommand(dockerCli command.Cli) *cobra.Command {
|
|||||||
func runRemove(ctx context.Context, dockerCLI command.Cli, serviceIDs []string) error {
|
func runRemove(ctx context.Context, dockerCLI command.Cli, serviceIDs []string) error {
|
||||||
apiClient := dockerCLI.Client()
|
apiClient := dockerCLI.Client()
|
||||||
|
|
||||||
var errs []string
|
var errs []error
|
||||||
for _, id := range serviceIDs {
|
for _, id := range serviceIDs {
|
||||||
err := apiClient.ServiceRemove(ctx, id)
|
if err := apiClient.ServiceRemove(ctx, id); err != nil {
|
||||||
if err != nil {
|
errs = append(errs, err)
|
||||||
errs = append(errs, err.Error())
|
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
_, _ = fmt.Fprintln(dockerCLI.Out(), id)
|
_, _ = fmt.Fprintln(dockerCLI.Out(), id)
|
||||||
}
|
}
|
||||||
if len(errs) > 0 {
|
return errors.Join(errs...)
|
||||||
return errors.New(strings.Join(errs, "\n"))
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
@ -42,12 +42,9 @@ func runRollback(ctx context.Context, dockerCLI command.Cli, options *serviceOpt
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
spec := &service.Spec
|
response, err := apiClient.ServiceUpdate(ctx, service.ID, service.Version, service.Spec, types.ServiceUpdateOptions{
|
||||||
updateOpts := types.ServiceUpdateOptions{
|
Rollback: "previous", // TODO(thaJeztah): this should have a const defined
|
||||||
Rollback: "previous",
|
})
|
||||||
}
|
|
||||||
|
|
||||||
response, err := apiClient.ServiceUpdate(ctx, service.ID, service.Version, *spec, updateOpts)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -2,6 +2,7 @@ package service
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
@ -10,7 +11,7 @@ import (
|
|||||||
"github.com/docker/cli/cli/command"
|
"github.com/docker/cli/cli/command"
|
||||||
"github.com/docker/docker/api/types"
|
"github.com/docker/docker/api/types"
|
||||||
"github.com/docker/docker/api/types/versions"
|
"github.com/docker/docker/api/types/versions"
|
||||||
"github.com/pkg/errors"
|
"github.com/docker/docker/client"
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -44,8 +45,8 @@ func scaleArgs(cmd *cobra.Command, args []string) error {
|
|||||||
}
|
}
|
||||||
for _, arg := range args {
|
for _, arg := range args {
|
||||||
if k, v, ok := strings.Cut(arg, "="); !ok || k == "" || v == "" {
|
if k, v, ok := strings.Cut(arg, "="); !ok || k == "" || v == "" {
|
||||||
return errors.Errorf(
|
return fmt.Errorf(
|
||||||
"Invalid scale specifier '%s'.\nSee '%s --help'.\n\nUsage: %s\n\n%s",
|
"invalid scale specifier '%s'.\nSee '%s --help'.\n\nUsage: %s\n\n%s",
|
||||||
arg,
|
arg,
|
||||||
cmd.CommandPath(),
|
cmd.CommandPath(),
|
||||||
cmd.UseLine(),
|
cmd.UseLine(),
|
||||||
@ -56,49 +57,48 @@ func scaleArgs(cmd *cobra.Command, args []string) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func runScale(ctx context.Context, dockerCli command.Cli, options *scaleOptions, args []string) error {
|
func runScale(ctx context.Context, dockerCLI command.Cli, options *scaleOptions, args []string) error {
|
||||||
var errs []string
|
apiClient := dockerCLI.Client()
|
||||||
var serviceIDs []string
|
var (
|
||||||
|
errs []error
|
||||||
|
serviceIDs = make([]string, 0, len(args))
|
||||||
|
)
|
||||||
for _, arg := range args {
|
for _, arg := range args {
|
||||||
serviceID, scaleStr, _ := strings.Cut(arg, "=")
|
serviceID, scaleStr, _ := strings.Cut(arg, "=")
|
||||||
|
|
||||||
// validate input arg scale number
|
// validate input arg scale number
|
||||||
scale, err := strconv.ParseUint(scaleStr, 10, 64)
|
scale, err := strconv.ParseUint(scaleStr, 10, 64)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
errs = append(errs, fmt.Sprintf("%s: invalid replicas value %s: %v", serviceID, scaleStr, err))
|
errs = append(errs, fmt.Errorf("%s: invalid replicas value %s: %v", serviceID, scaleStr, err))
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := runServiceScale(ctx, dockerCli, serviceID, scale); err != nil {
|
warnings, err := runServiceScale(ctx, apiClient, serviceID, scale)
|
||||||
errs = append(errs, fmt.Sprintf("%s: %v", serviceID, err))
|
if err != nil {
|
||||||
} else {
|
errs = append(errs, fmt.Errorf("%s: %v", serviceID, err))
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
for _, warning := range warnings {
|
||||||
|
_, _ = fmt.Fprintln(dockerCLI.Err(), warning)
|
||||||
|
}
|
||||||
|
_, _ = fmt.Fprintf(dockerCLI.Out(), "%s scaled to %d\n", serviceID, scale)
|
||||||
serviceIDs = append(serviceIDs, serviceID)
|
serviceIDs = append(serviceIDs, serviceID)
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if len(serviceIDs) > 0 {
|
if len(serviceIDs) > 0 && !options.detach && versions.GreaterThanOrEqualTo(dockerCLI.Client().ClientVersion(), "1.29") {
|
||||||
if !options.detach && versions.GreaterThanOrEqualTo(dockerCli.Client().ClientVersion(), "1.29") {
|
|
||||||
for _, serviceID := range serviceIDs {
|
for _, serviceID := range serviceIDs {
|
||||||
if err := WaitOnService(ctx, dockerCli, serviceID, false); err != nil {
|
if err := WaitOnService(ctx, dockerCLI, serviceID, false); err != nil {
|
||||||
errs = append(errs, fmt.Sprintf("%s: %v", serviceID, err))
|
errs = append(errs, fmt.Errorf("%s: %v", serviceID, err))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
return errors.Join(errs...)
|
||||||
|
|
||||||
if len(errs) == 0 {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
return errors.New(strings.Join(errs, "\n"))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func runServiceScale(ctx context.Context, dockerCli command.Cli, serviceID string, scale uint64) error {
|
func runServiceScale(ctx context.Context, apiClient client.ServiceAPIClient, serviceID string, scale uint64) (warnings []string, _ error) {
|
||||||
client := dockerCli.Client()
|
service, _, err := apiClient.ServiceInspectWithRaw(ctx, serviceID, types.ServiceInspectOptions{})
|
||||||
|
|
||||||
service, _, err := client.ServiceInspectWithRaw(ctx, serviceID, types.ServiceInspectOptions{})
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
serviceMode := &service.Spec.Mode
|
serviceMode := &service.Spec.Mode
|
||||||
@ -108,18 +108,12 @@ func runServiceScale(ctx context.Context, dockerCli command.Cli, serviceID strin
|
|||||||
case serviceMode.ReplicatedJob != nil:
|
case serviceMode.ReplicatedJob != nil:
|
||||||
serviceMode.ReplicatedJob.TotalCompletions = &scale
|
serviceMode.ReplicatedJob.TotalCompletions = &scale
|
||||||
default:
|
default:
|
||||||
return errors.Errorf("scale can only be used with replicated or replicated-job mode")
|
return nil, errors.New("scale can only be used with replicated or replicated-job mode")
|
||||||
}
|
}
|
||||||
|
|
||||||
response, err := client.ServiceUpdate(ctx, service.ID, service.Version, service.Spec, types.ServiceUpdateOptions{})
|
response, err := apiClient.ServiceUpdate(ctx, service.ID, service.Version, service.Spec, types.ServiceUpdateOptions{})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
return response.Warnings, nil
|
||||||
for _, warning := range response.Warnings {
|
|
||||||
_, _ = fmt.Fprintln(dockerCli.Err(), warning)
|
|
||||||
}
|
|
||||||
|
|
||||||
_, _ = fmt.Fprintf(dockerCli.Out(), "%s scaled to %d\n", serviceID, scale)
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
@ -161,7 +161,7 @@ func TestRemoveContinueAfterError(t *testing.T) {
|
|||||||
cmd.SetErr(io.Discard)
|
cmd.SetErr(io.Discard)
|
||||||
cmd.SetArgs([]string{"foo", "bar"})
|
cmd.SetArgs([]string{"foo", "bar"})
|
||||||
|
|
||||||
assert.Error(t, cmd.Execute(), "Failed to remove some resources from stack: foo")
|
assert.Error(t, cmd.Execute(), "failed to remove some resources from stack: foo")
|
||||||
assert.Check(t, is.DeepEqual(allServiceIDs, removedServices))
|
assert.Check(t, is.DeepEqual(allServiceIDs, removedServices))
|
||||||
assert.Check(t, is.DeepEqual(allNetworkIDs, cli.removedNetworks))
|
assert.Check(t, is.DeepEqual(allNetworkIDs, cli.removedNetworks))
|
||||||
assert.Check(t, is.DeepEqual(allSecretIDs, cli.removedSecrets))
|
assert.Check(t, is.DeepEqual(allSecretIDs, cli.removedSecrets))
|
||||||
|
@ -2,9 +2,9 @@ package swarm
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"sort"
|
"sort"
|
||||||
"strings"
|
|
||||||
|
|
||||||
"github.com/docker/cli/cli/command"
|
"github.com/docker/cli/cli/command"
|
||||||
"github.com/docker/cli/cli/command/stack/options"
|
"github.com/docker/cli/cli/command/stack/options"
|
||||||
@ -12,14 +12,13 @@ import (
|
|||||||
"github.com/docker/docker/api/types/swarm"
|
"github.com/docker/docker/api/types/swarm"
|
||||||
"github.com/docker/docker/api/types/versions"
|
"github.com/docker/docker/api/types/versions"
|
||||||
"github.com/docker/docker/client"
|
"github.com/docker/docker/client"
|
||||||
"github.com/pkg/errors"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// RunRemove is the swarm implementation of docker stack remove
|
// RunRemove is the swarm implementation of docker stack remove
|
||||||
func RunRemove(ctx context.Context, dockerCli command.Cli, opts options.Remove) error {
|
func RunRemove(ctx context.Context, dockerCli command.Cli, opts options.Remove) error {
|
||||||
apiClient := dockerCli.Client()
|
apiClient := dockerCli.Client()
|
||||||
|
|
||||||
var errs []string
|
var errs []error
|
||||||
for _, namespace := range opts.Namespaces {
|
for _, namespace := range opts.Namespaces {
|
||||||
services, err := getStackServices(ctx, apiClient, namespace)
|
services, err := getStackServices(ctx, apiClient, namespace)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -52,28 +51,25 @@ func RunRemove(ctx context.Context, dockerCli command.Cli, opts options.Remove)
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO(thaJeztah): change this "hasError" boolean to return a (multi-)error for each of these functions instead.
|
||||||
hasError := removeServices(ctx, dockerCli, services)
|
hasError := removeServices(ctx, dockerCli, services)
|
||||||
hasError = removeSecrets(ctx, dockerCli, secrets) || hasError
|
hasError = removeSecrets(ctx, dockerCli, secrets) || hasError
|
||||||
hasError = removeConfigs(ctx, dockerCli, configs) || hasError
|
hasError = removeConfigs(ctx, dockerCli, configs) || hasError
|
||||||
hasError = removeNetworks(ctx, dockerCli, networks) || hasError
|
hasError = removeNetworks(ctx, dockerCli, networks) || hasError
|
||||||
|
|
||||||
if hasError {
|
if hasError {
|
||||||
errs = append(errs, "Failed to remove some resources from stack: "+namespace)
|
errs = append(errs, errors.New("failed to remove some resources from stack: "+namespace))
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
if !opts.Detach {
|
if !opts.Detach {
|
||||||
err = waitOnTasks(ctx, apiClient, namespace)
|
err = waitOnTasks(ctx, apiClient, namespace)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
errs = append(errs, fmt.Sprintf("Failed to wait on tasks of stack: %s: %s", namespace, err))
|
errs = append(errs, fmt.Errorf("failed to wait on tasks of stack: %s: %w", namespace, err))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return errors.Join(errs...)
|
||||||
if len(errs) > 0 {
|
|
||||||
return errors.New(strings.Join(errs, "\n"))
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func sortServiceByName(services []swarm.Service) func(i, j int) bool {
|
func sortServiceByName(services []swarm.Service) func(i, j int) bool {
|
||||||
|
@ -2,13 +2,12 @@ package volume
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"strings"
|
|
||||||
|
|
||||||
"github.com/docker/cli/cli"
|
"github.com/docker/cli/cli"
|
||||||
"github.com/docker/cli/cli/command"
|
"github.com/docker/cli/cli/command"
|
||||||
"github.com/docker/cli/cli/command/completion"
|
"github.com/docker/cli/cli/command/completion"
|
||||||
"github.com/pkg/errors"
|
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -43,18 +42,13 @@ func newRemoveCommand(dockerCli command.Cli) *cobra.Command {
|
|||||||
func runRemove(ctx context.Context, dockerCLI command.Cli, opts *removeOptions) error {
|
func runRemove(ctx context.Context, dockerCLI command.Cli, opts *removeOptions) error {
|
||||||
apiClient := dockerCLI.Client()
|
apiClient := dockerCLI.Client()
|
||||||
|
|
||||||
var errs []string
|
var errs []error
|
||||||
|
|
||||||
for _, name := range opts.volumes {
|
for _, name := range opts.volumes {
|
||||||
if err := apiClient.VolumeRemove(ctx, name, opts.force); err != nil {
|
if err := apiClient.VolumeRemove(ctx, name, opts.force); err != nil {
|
||||||
errs = append(errs, err.Error())
|
errs = append(errs, err)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
_, _ = fmt.Fprintln(dockerCLI.Out(), name)
|
_, _ = fmt.Fprintln(dockerCLI.Out(), name)
|
||||||
}
|
}
|
||||||
|
return errors.Join(errs...)
|
||||||
if len(errs) > 0 {
|
|
||||||
return errors.Errorf("%s", strings.Join(errs, "\n"))
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user