Compare commits
44 Commits
v24.0.0-be
...
v23.0.2
| Author | SHA1 | Date | |
|---|---|---|---|
| 569dd73db1 | |||
| f6643207a2 | |||
| f381e08425 | |||
| 18f20a5537 | |||
| d3a36fc38c | |||
| 59bb07f2e4 | |||
| 80f27987f4 | |||
| 6a8406e602 | |||
| c2c122fb65 | |||
| 40a48e4154 | |||
| a43c9f3440 | |||
| 114e17ac4b | |||
| e2c402118c | |||
| d07453890c | |||
| 288b6c79fe | |||
| fbab8cd2be | |||
| b898a46135 | |||
| 90a72a5894 | |||
| 4c63110a92 | |||
| b61b5a9878 | |||
| 84fe451ec7 | |||
| 71615c2df1 | |||
| a1acc9af91 | |||
| 95066ff3a2 | |||
| 0dbf70fad2 | |||
| e0b8e19687 | |||
| 98e874dac7 | |||
| 92164b0306 | |||
| 5af8077eeb | |||
| d352c504a8 | |||
| 28c74b759b | |||
| 57a502772b | |||
| 14ac8db968 | |||
| 1ab7665be8 | |||
| 1810e922ac | |||
| 5051d82a17 | |||
| 7f4e3ead75 | |||
| a5ee5b1dfc | |||
| 27b19a6acf | |||
| ab4ef4aed4 | |||
| 14aac2c232 | |||
| 0cd15abfde | |||
| 168f1b55e2 | |||
| 53ed25d9b6 |
71
.github/workflows/build.yml
vendored
71
.github/workflows/build.yml
vendored
@ -15,35 +15,14 @@ on:
|
||||
pull_request:
|
||||
|
||||
jobs:
|
||||
prepare:
|
||||
runs-on: ubuntu-20.04
|
||||
outputs:
|
||||
matrix: ${{ steps.platforms.outputs.matrix }}
|
||||
steps:
|
||||
-
|
||||
name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
-
|
||||
name: Create matrix
|
||||
id: platforms
|
||||
run: |
|
||||
echo "matrix=$(docker buildx bake cross --print | jq -cr '.target."cross".platforms')" >>${GITHUB_OUTPUT}
|
||||
-
|
||||
name: Show matrix
|
||||
run: |
|
||||
echo ${{ steps.platforms.outputs.matrix }}
|
||||
|
||||
build:
|
||||
runs-on: ubuntu-20.04
|
||||
needs:
|
||||
- prepare
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
target:
|
||||
- binary
|
||||
- dynbinary
|
||||
platform: ${{ fromJson(needs.prepare.outputs.matrix) }}
|
||||
- cross
|
||||
- dynbinary-cross
|
||||
use_glibc:
|
||||
- ""
|
||||
- glibc
|
||||
@ -57,22 +36,22 @@ jobs:
|
||||
name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v2
|
||||
-
|
||||
name: Build
|
||||
name: Run ${{ matrix.target }}
|
||||
uses: docker/bake-action@v2
|
||||
with:
|
||||
targets: ${{ matrix.target }}
|
||||
set: |
|
||||
*.platform=${{ matrix.platform }}
|
||||
env:
|
||||
USE_GLIBC: ${{ matrix.use_glibc }}
|
||||
-
|
||||
name: Create tarball
|
||||
name: Flatten artifacts
|
||||
working-directory: ./build
|
||||
run: |
|
||||
mkdir /tmp/out
|
||||
platform=${{ matrix.platform }}
|
||||
platformPair=${platform//\//-}
|
||||
tar -cvzf "/tmp/out/docker-${platformPair}.tar.gz" .
|
||||
for dir in */; do
|
||||
base=$(basename "$dir")
|
||||
echo "Creating ${base}.tar.gz ..."
|
||||
tar -cvzf "${base}.tar.gz" "$dir"
|
||||
rm -rf "$dir"
|
||||
done
|
||||
if [ -z "${{ matrix.use_glibc }}" ]; then
|
||||
echo "ARTIFACT_NAME=${{ matrix.target }}" >> $GITHUB_ENV
|
||||
else
|
||||
@ -83,35 +62,11 @@ jobs:
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: ${{ env.ARTIFACT_NAME }}
|
||||
path: /tmp/out/*
|
||||
path: ./build/*
|
||||
if-no-files-found: error
|
||||
|
||||
prepare-plugins:
|
||||
runs-on: ubuntu-20.04
|
||||
outputs:
|
||||
matrix: ${{ steps.platforms.outputs.matrix }}
|
||||
steps:
|
||||
-
|
||||
name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
-
|
||||
name: Create matrix
|
||||
id: platforms
|
||||
run: |
|
||||
echo "matrix=$(docker buildx bake plugins-cross --print | jq -cr '.target."plugins-cross".platforms')" >>${GITHUB_OUTPUT}
|
||||
-
|
||||
name: Show matrix
|
||||
run: |
|
||||
echo ${{ steps.platforms.outputs.matrix }}
|
||||
|
||||
plugins:
|
||||
runs-on: ubuntu-20.04
|
||||
needs:
|
||||
- prepare-plugins
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
platform: ${{ fromJson(needs.prepare-plugins.outputs.matrix) }}
|
||||
steps:
|
||||
-
|
||||
name: Checkout
|
||||
@ -120,9 +75,7 @@ jobs:
|
||||
name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v2
|
||||
-
|
||||
name: Build
|
||||
name: Build plugins
|
||||
uses: docker/bake-action@v2
|
||||
with:
|
||||
targets: plugins-cross
|
||||
set: |
|
||||
*.platform=${{ matrix.platform }}
|
||||
|
||||
4
.github/workflows/test.yml
vendored
4
.github/workflows/test.yml
vendored
@ -61,9 +61,9 @@ jobs:
|
||||
path: ${{ env.GOPATH }}/src/github.com/docker/cli
|
||||
-
|
||||
name: Set up Go
|
||||
uses: actions/setup-go@v4
|
||||
uses: actions/setup-go@v3
|
||||
with:
|
||||
go-version: 1.20.3
|
||||
go-version: 1.19.4
|
||||
-
|
||||
name: Test
|
||||
run: |
|
||||
|
||||
25
.github/workflows/validate.yml
vendored
25
.github/workflows/validate.yml
vendored
@ -29,33 +29,14 @@ jobs:
|
||||
-
|
||||
name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
fetch-depth: 0
|
||||
-
|
||||
name: Run
|
||||
uses: docker/bake-action@v2
|
||||
with:
|
||||
targets: ${{ matrix.target }}
|
||||
|
||||
# check that the generated Markdown and the checked-in files match
|
||||
validate-md:
|
||||
runs-on: ubuntu-20.04
|
||||
steps:
|
||||
-
|
||||
name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
-
|
||||
name: Generate
|
||||
shell: 'script --return --quiet --command "bash {0}"'
|
||||
run: |
|
||||
make -f docker.Makefile mddocs
|
||||
-
|
||||
name: Validate
|
||||
run: |
|
||||
if [[ $(git diff --stat) != '' ]]; then
|
||||
echo 'fail: generated files do not match checked-in files'
|
||||
git --no-pager diff
|
||||
exit 1
|
||||
fi
|
||||
|
||||
validate-make:
|
||||
runs-on: ubuntu-20.04
|
||||
strategy:
|
||||
@ -68,6 +49,8 @@ jobs:
|
||||
-
|
||||
name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
fetch-depth: 0
|
||||
-
|
||||
name: Run
|
||||
shell: 'script --return --quiet --command "bash {0}"'
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
# syntax=docker/dockerfile:1
|
||||
|
||||
ARG BASE_VARIANT=alpine
|
||||
ARG GO_VERSION=1.20.3
|
||||
ARG GO_VERSION=1.19.7
|
||||
ARG ALPINE_VERSION=3.16
|
||||
ARG XX_VERSION=1.1.1
|
||||
ARG GOVERSIONINFO_VERSION=v1.3.0
|
||||
@ -125,8 +125,8 @@ CMD ./scripts/test/e2e/entry
|
||||
FROM build-base-${BASE_VARIANT} AS dev
|
||||
COPY . .
|
||||
|
||||
FROM scratch AS plugins
|
||||
COPY --from=build-plugins /out .
|
||||
|
||||
FROM scratch AS binary
|
||||
COPY --from=build /out .
|
||||
|
||||
FROM scratch AS plugins
|
||||
COPY --from=build-plugins /out .
|
||||
|
||||
@ -49,9 +49,9 @@
|
||||
|
||||
people = [
|
||||
"bsousaa",
|
||||
"neersighted",
|
||||
"programmerq",
|
||||
"sam-thibault",
|
||||
"thajeztah",
|
||||
"vvoland"
|
||||
]
|
||||
|
||||
@ -103,11 +103,6 @@
|
||||
Email = "nicolas.deloof@gmail.com"
|
||||
GitHub = "ndeloof"
|
||||
|
||||
[people.neersighted]
|
||||
Name = "Bjorn Neergaard"
|
||||
Email = "bneergaard@mirantis.com"
|
||||
GitHub = "neersighted"
|
||||
|
||||
[people.programmerq]
|
||||
Name = "Jeff Anderson"
|
||||
Email = "jeff@docker.com"
|
||||
|
||||
@ -74,7 +74,7 @@ func TestValidateCandidate(t *testing.T) {
|
||||
{name: "experimental + allowing experimental", c: &fakeCandidate{path: goodPluginPath, exec: true, meta: metaExperimental}},
|
||||
} {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
p, err := newPlugin(tc.c, fakeroot.Commands())
|
||||
p, err := newPlugin(tc.c, fakeroot)
|
||||
if tc.err != "" {
|
||||
assert.ErrorContains(t, err, tc.err)
|
||||
} else if tc.invalid != "" {
|
||||
|
||||
@ -3,7 +3,6 @@ package manager
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"sync"
|
||||
|
||||
"github.com/docker/cli/cli/command"
|
||||
"github.com/spf13/cobra"
|
||||
@ -32,69 +31,64 @@ const (
|
||||
CommandAnnotationPluginInvalid = "com.docker.cli.plugin-invalid"
|
||||
)
|
||||
|
||||
var pluginCommandStubsOnce sync.Once
|
||||
|
||||
// AddPluginCommandStubs adds a stub cobra.Commands for each valid and invalid
|
||||
// plugin. The command stubs will have several annotations added, see
|
||||
// `CommandAnnotationPlugin*`.
|
||||
func AddPluginCommandStubs(dockerCli command.Cli, rootCmd *cobra.Command) (err error) {
|
||||
pluginCommandStubsOnce.Do(func() {
|
||||
var plugins []Plugin
|
||||
plugins, err = ListPlugins(dockerCli, rootCmd)
|
||||
if err != nil {
|
||||
return
|
||||
func AddPluginCommandStubs(dockerCli command.Cli, rootCmd *cobra.Command) error {
|
||||
plugins, err := ListPlugins(dockerCli, rootCmd)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for _, p := range plugins {
|
||||
p := p
|
||||
vendor := p.Vendor
|
||||
if vendor == "" {
|
||||
vendor = "unknown"
|
||||
}
|
||||
for _, p := range plugins {
|
||||
p := p
|
||||
vendor := p.Vendor
|
||||
if vendor == "" {
|
||||
vendor = "unknown"
|
||||
}
|
||||
annotations := map[string]string{
|
||||
CommandAnnotationPlugin: "true",
|
||||
CommandAnnotationPluginVendor: vendor,
|
||||
CommandAnnotationPluginVersion: p.Version,
|
||||
}
|
||||
if p.Err != nil {
|
||||
annotations[CommandAnnotationPluginInvalid] = p.Err.Error()
|
||||
}
|
||||
rootCmd.AddCommand(&cobra.Command{
|
||||
Use: p.Name,
|
||||
Short: p.ShortDescription,
|
||||
Run: func(_ *cobra.Command, _ []string) {},
|
||||
Annotations: annotations,
|
||||
DisableFlagParsing: true,
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
flags := rootCmd.PersistentFlags()
|
||||
flags.SetOutput(nil)
|
||||
perr := flags.Parse(args)
|
||||
if perr != nil {
|
||||
return err
|
||||
}
|
||||
if flags.Changed("help") {
|
||||
cmd.HelpFunc()(rootCmd, args)
|
||||
return nil
|
||||
}
|
||||
return fmt.Errorf("docker: '%s' is not a docker command.\nSee 'docker --help'", cmd.Name())
|
||||
},
|
||||
ValidArgsFunction: func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
|
||||
// Delegate completion to plugin
|
||||
cargs := []string{p.Path, cobra.ShellCompRequestCmd, p.Name}
|
||||
cargs = append(cargs, args...)
|
||||
cargs = append(cargs, toComplete)
|
||||
os.Args = cargs
|
||||
runCommand, runErr := PluginRunCommand(dockerCli, p.Name, cmd)
|
||||
if runErr != nil {
|
||||
return nil, cobra.ShellCompDirectiveError
|
||||
}
|
||||
runErr = runCommand.Run()
|
||||
if runErr == nil {
|
||||
os.Exit(0) // plugin already rendered complete data
|
||||
}
|
||||
annotations := map[string]string{
|
||||
CommandAnnotationPlugin: "true",
|
||||
CommandAnnotationPluginVendor: vendor,
|
||||
CommandAnnotationPluginVersion: p.Version,
|
||||
}
|
||||
if p.Err != nil {
|
||||
annotations[CommandAnnotationPluginInvalid] = p.Err.Error()
|
||||
}
|
||||
rootCmd.AddCommand(&cobra.Command{
|
||||
Use: p.Name,
|
||||
Short: p.ShortDescription,
|
||||
Run: func(_ *cobra.Command, _ []string) {},
|
||||
Annotations: annotations,
|
||||
DisableFlagParsing: true,
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
flags := rootCmd.PersistentFlags()
|
||||
flags.SetOutput(nil)
|
||||
err := flags.Parse(args)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if flags.Changed("help") {
|
||||
cmd.HelpFunc()(rootCmd, args)
|
||||
return nil
|
||||
}
|
||||
return fmt.Errorf("docker: '%s' is not a docker command.\nSee 'docker --help'", cmd.Name())
|
||||
},
|
||||
ValidArgsFunction: func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
|
||||
// Delegate completion to plugin
|
||||
cargs := []string{p.Path, cobra.ShellCompRequestCmd, p.Name}
|
||||
cargs = append(cargs, args...)
|
||||
cargs = append(cargs, toComplete)
|
||||
os.Args = cargs
|
||||
runCommand, err := PluginRunCommand(dockerCli, p.Name, cmd)
|
||||
if err != nil {
|
||||
return nil, cobra.ShellCompDirectiveError
|
||||
},
|
||||
})
|
||||
}
|
||||
})
|
||||
return err
|
||||
}
|
||||
err = runCommand.Run()
|
||||
if err == nil {
|
||||
os.Exit(0) // plugin already rendered complete data
|
||||
}
|
||||
return nil, cobra.ShellCompDirectiveError
|
||||
},
|
||||
})
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@ -1,18 +1,15 @@
|
||||
package manager
|
||||
|
||||
import (
|
||||
"context"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"sort"
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
"github.com/docker/cli/cli/command"
|
||||
"github.com/docker/cli/cli/config"
|
||||
"github.com/fvbommel/sortorder"
|
||||
"github.com/spf13/cobra"
|
||||
"golang.org/x/sync/errgroup"
|
||||
exec "golang.org/x/sys/execabs"
|
||||
)
|
||||
|
||||
@ -123,7 +120,7 @@ func GetPlugin(name string, dockerCli command.Cli, rootcmd *cobra.Command) (*Plu
|
||||
return nil, errPluginNotFound(name)
|
||||
}
|
||||
c := &candidate{paths[0]}
|
||||
p, err := newPlugin(c, rootcmd.Commands())
|
||||
p, err := newPlugin(c, rootcmd)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -149,32 +146,19 @@ func ListPlugins(dockerCli command.Cli, rootcmd *cobra.Command) ([]Plugin, error
|
||||
}
|
||||
|
||||
var plugins []Plugin
|
||||
var mu sync.Mutex
|
||||
eg, _ := errgroup.WithContext(context.TODO())
|
||||
cmds := rootcmd.Commands()
|
||||
for _, paths := range candidates {
|
||||
func(paths []string) {
|
||||
eg.Go(func() error {
|
||||
if len(paths) == 0 {
|
||||
return nil
|
||||
}
|
||||
c := &candidate{paths[0]}
|
||||
p, err := newPlugin(c, cmds)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if !IsNotFound(p.Err) {
|
||||
p.ShadowedPaths = paths[1:]
|
||||
mu.Lock()
|
||||
defer mu.Unlock()
|
||||
plugins = append(plugins, p)
|
||||
}
|
||||
return nil
|
||||
})
|
||||
}(paths)
|
||||
}
|
||||
if err := eg.Wait(); err != nil {
|
||||
return nil, err
|
||||
if len(paths) == 0 {
|
||||
continue
|
||||
}
|
||||
c := &candidate{paths[0]}
|
||||
p, err := newPlugin(c, rootcmd)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if !IsNotFound(p.Err) {
|
||||
p.ShadowedPaths = paths[1:]
|
||||
plugins = append(plugins, p)
|
||||
}
|
||||
}
|
||||
|
||||
sort.Slice(plugins, func(i, j int) bool {
|
||||
@ -215,7 +199,7 @@ func PluginRunCommand(dockerCli command.Cli, name string, rootcmd *cobra.Command
|
||||
}
|
||||
|
||||
c := &candidate{path: path}
|
||||
plugin, err := newPlugin(c, rootcmd.Commands())
|
||||
plugin, err := newPlugin(c, rootcmd)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@ -31,7 +31,7 @@ type Plugin struct {
|
||||
// is set, and is always a `pluginError`, but the `Plugin` is still
|
||||
// returned with no error. An error is only returned due to a
|
||||
// non-recoverable error.
|
||||
func newPlugin(c Candidate, cmds []*cobra.Command) (Plugin, error) {
|
||||
func newPlugin(c Candidate, rootcmd *cobra.Command) (Plugin, error) {
|
||||
path := c.Path()
|
||||
if path == "" {
|
||||
return Plugin{}, errors.New("plugin candidate path cannot be empty")
|
||||
@ -62,20 +62,22 @@ func newPlugin(c Candidate, cmds []*cobra.Command) (Plugin, error) {
|
||||
return p, nil
|
||||
}
|
||||
|
||||
for _, cmd := range cmds {
|
||||
// Ignore conflicts with commands which are
|
||||
// just plugin stubs (i.e. from a previous
|
||||
// call to AddPluginCommandStubs).
|
||||
if IsPluginCommand(cmd) {
|
||||
continue
|
||||
}
|
||||
if cmd.Name() == p.Name {
|
||||
p.Err = NewPluginError("plugin %q duplicates builtin command", p.Name)
|
||||
return p, nil
|
||||
}
|
||||
if cmd.HasAlias(p.Name) {
|
||||
p.Err = NewPluginError("plugin %q duplicates an alias of builtin command %q", p.Name, cmd.Name())
|
||||
return p, nil
|
||||
if rootcmd != nil {
|
||||
for _, cmd := range rootcmd.Commands() {
|
||||
// Ignore conflicts with commands which are
|
||||
// just plugin stubs (i.e. from a previous
|
||||
// call to AddPluginCommandStubs).
|
||||
if IsPluginCommand(cmd) {
|
||||
continue
|
||||
}
|
||||
if cmd.Name() == p.Name {
|
||||
p.Err = NewPluginError("plugin %q duplicates builtin command", p.Name)
|
||||
return p, nil
|
||||
}
|
||||
if cmd.HasAlias(p.Name) {
|
||||
p.Err = NewPluginError("plugin %q duplicates an alias of builtin command %q", p.Name, cmd.Name())
|
||||
return p, nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
14
cli/cobra.go
14
cli/cobra.go
@ -204,16 +204,6 @@ func DisableFlagsInUseLine(cmd *cobra.Command) {
|
||||
})
|
||||
}
|
||||
|
||||
// HasCompletionArg returns true if a cobra completion arg request is found.
|
||||
func HasCompletionArg(args []string) bool {
|
||||
for _, arg := range args {
|
||||
if arg == cobra.ShellCompRequestCmd || arg == cobra.ShellCompNoDescRequestCmd {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
var helpCommand = &cobra.Command{
|
||||
Use: "help [command]",
|
||||
Short: "Help about the command",
|
||||
@ -426,7 +416,7 @@ func invalidPluginReason(cmd *cobra.Command) string {
|
||||
return cmd.Annotations[pluginmanager.CommandAnnotationPluginInvalid]
|
||||
}
|
||||
|
||||
const usageTemplate = `Usage:
|
||||
var usageTemplate = `Usage:
|
||||
|
||||
{{- if not .HasSubCommands}} {{.UseLine}}{{end}}
|
||||
{{- if .HasSubCommands}} {{ .CommandPath}}{{- if .HasAvailableFlags}} [OPTIONS]{{end}} COMMAND{{end}}
|
||||
@ -525,5 +515,5 @@ Run '{{.CommandPath}} COMMAND --help' for more information on a command.
|
||||
{{- end}}
|
||||
`
|
||||
|
||||
const helpTemplate = `
|
||||
var helpTemplate = `
|
||||
{{if or .Runnable .HasSubCommands}}{{.UsageString}}{{end}}`
|
||||
|
||||
@ -14,21 +14,21 @@ type fakeClient struct {
|
||||
checkpointListFunc func(container string, options types.CheckpointListOptions) ([]types.Checkpoint, error)
|
||||
}
|
||||
|
||||
func (cli *fakeClient) CheckpointCreate(_ context.Context, container string, options types.CheckpointCreateOptions) error {
|
||||
func (cli *fakeClient) CheckpointCreate(ctx context.Context, container string, options types.CheckpointCreateOptions) error {
|
||||
if cli.checkpointCreateFunc != nil {
|
||||
return cli.checkpointCreateFunc(container, options)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (cli *fakeClient) CheckpointDelete(_ context.Context, container string, options types.CheckpointDeleteOptions) error {
|
||||
func (cli *fakeClient) CheckpointDelete(ctx context.Context, container string, options types.CheckpointDeleteOptions) error {
|
||||
if cli.checkpointDeleteFunc != nil {
|
||||
return cli.checkpointDeleteFunc(container, options)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (cli *fakeClient) CheckpointList(_ context.Context, container string, options types.CheckpointListOptions) ([]types.Checkpoint, error) {
|
||||
func (cli *fakeClient) CheckpointList(ctx context.Context, container string, options types.CheckpointListOptions) ([]types.Checkpoint, error) {
|
||||
if cli.checkpointListFunc != nil {
|
||||
return cli.checkpointListFunc(container, options)
|
||||
}
|
||||
|
||||
@ -48,7 +48,9 @@ type Streams interface {
|
||||
// Cli represents the docker command line client.
|
||||
type Cli interface {
|
||||
Client() client.APIClient
|
||||
Streams
|
||||
Out() *streams.Out
|
||||
Err() io.Writer
|
||||
In() *streams.In
|
||||
SetIn(in *streams.In)
|
||||
Apply(ops ...DockerCliOption) error
|
||||
ConfigFile() *configfile.ConfigFile
|
||||
@ -189,7 +191,7 @@ func (cli *DockerCli) ManifestStore() manifeststore.Store {
|
||||
// RegistryClient returns a client for communicating with a Docker distribution
|
||||
// registry
|
||||
func (cli *DockerCli) RegistryClient(allowInsecure bool) registryclient.RegistryClient {
|
||||
resolver := func(ctx context.Context, index *registry.IndexInfo) registry.AuthConfig {
|
||||
resolver := func(ctx context.Context, index *registry.IndexInfo) types.AuthConfig {
|
||||
return ResolveAuthConfig(ctx, cli, index)
|
||||
}
|
||||
return registryclient.NewRegistryClient(resolver, UserAgent(), allowInsecure)
|
||||
|
||||
@ -6,7 +6,7 @@ import (
|
||||
"github.com/docker/cli/cli/command"
|
||||
"github.com/docker/cli/cli/command/formatter"
|
||||
"github.com/docker/docker/api/types"
|
||||
"github.com/docker/docker/api/types/volume"
|
||||
"github.com/docker/docker/api/types/filters"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
@ -66,13 +66,13 @@ func ContainerNames(dockerCli command.Cli, all bool, filters ...func(types.Conta
|
||||
// VolumeNames offers completion for volumes
|
||||
func VolumeNames(dockerCli command.Cli) ValidArgsFn {
|
||||
return func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
|
||||
list, err := dockerCli.Client().VolumeList(cmd.Context(), volume.ListOptions{})
|
||||
list, err := dockerCli.Client().VolumeList(cmd.Context(), filters.Args{})
|
||||
if err != nil {
|
||||
return nil, cobra.ShellCompDirectiveError
|
||||
}
|
||||
var names []string
|
||||
for _, vol := range list.Volumes {
|
||||
names = append(names, vol.Name)
|
||||
for _, volume := range list.Volumes {
|
||||
names = append(names, volume.Name)
|
||||
}
|
||||
return names, cobra.ShellCompDirectiveNoFileComp
|
||||
}
|
||||
@ -94,6 +94,6 @@ func NetworkNames(dockerCli command.Cli) ValidArgsFn {
|
||||
}
|
||||
|
||||
// NoComplete is used for commands where there's no relevant completion
|
||||
func NoComplete(*cobra.Command, []string, string) ([]string, cobra.ShellCompDirective) {
|
||||
func NoComplete(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
|
||||
return nil, cobra.ShellCompDirectiveNoFileComp
|
||||
}
|
||||
|
||||
@ -10,34 +10,34 @@ import (
|
||||
|
||||
type fakeClient struct {
|
||||
client.Client
|
||||
configCreateFunc func(context.Context, swarm.ConfigSpec) (types.ConfigCreateResponse, error)
|
||||
configInspectFunc func(context.Context, string) (swarm.Config, []byte, error)
|
||||
configListFunc func(context.Context, types.ConfigListOptions) ([]swarm.Config, error)
|
||||
configCreateFunc func(swarm.ConfigSpec) (types.ConfigCreateResponse, error)
|
||||
configInspectFunc func(string) (swarm.Config, []byte, error)
|
||||
configListFunc func(types.ConfigListOptions) ([]swarm.Config, error)
|
||||
configRemoveFunc func(string) error
|
||||
}
|
||||
|
||||
func (c *fakeClient) ConfigCreate(ctx context.Context, spec swarm.ConfigSpec) (types.ConfigCreateResponse, error) {
|
||||
if c.configCreateFunc != nil {
|
||||
return c.configCreateFunc(ctx, spec)
|
||||
return c.configCreateFunc(spec)
|
||||
}
|
||||
return types.ConfigCreateResponse{}, nil
|
||||
}
|
||||
|
||||
func (c *fakeClient) ConfigInspectWithRaw(ctx context.Context, id string) (swarm.Config, []byte, error) {
|
||||
if c.configInspectFunc != nil {
|
||||
return c.configInspectFunc(ctx, id)
|
||||
return c.configInspectFunc(id)
|
||||
}
|
||||
return swarm.Config{}, nil, nil
|
||||
}
|
||||
|
||||
func (c *fakeClient) ConfigList(ctx context.Context, options types.ConfigListOptions) ([]swarm.Config, error) {
|
||||
if c.configListFunc != nil {
|
||||
return c.configListFunc(ctx, options)
|
||||
return c.configListFunc(options)
|
||||
}
|
||||
return []swarm.Config{}, nil
|
||||
}
|
||||
|
||||
func (c *fakeClient) ConfigRemove(_ context.Context, name string) error {
|
||||
func (c *fakeClient) ConfigRemove(ctx context.Context, name string) error {
|
||||
if c.configRemoveFunc != nil {
|
||||
return c.configRemoveFunc(name)
|
||||
}
|
||||
|
||||
@ -1,7 +1,6 @@
|
||||
package config
|
||||
|
||||
import (
|
||||
"context"
|
||||
"io"
|
||||
"os"
|
||||
"path/filepath"
|
||||
@ -23,7 +22,7 @@ const configDataFile = "config-create-with-name.golden"
|
||||
func TestConfigCreateErrors(t *testing.T) {
|
||||
testCases := []struct {
|
||||
args []string
|
||||
configCreateFunc func(context.Context, swarm.ConfigSpec) (types.ConfigCreateResponse, error)
|
||||
configCreateFunc func(swarm.ConfigSpec) (types.ConfigCreateResponse, error)
|
||||
expectedError string
|
||||
}{
|
||||
{
|
||||
@ -36,7 +35,7 @@ func TestConfigCreateErrors(t *testing.T) {
|
||||
},
|
||||
{
|
||||
args: []string{"name", filepath.Join("testdata", configDataFile)},
|
||||
configCreateFunc: func(_ context.Context, configSpec swarm.ConfigSpec) (types.ConfigCreateResponse, error) {
|
||||
configCreateFunc: func(configSpec swarm.ConfigSpec) (types.ConfigCreateResponse, error) {
|
||||
return types.ConfigCreateResponse{}, errors.Errorf("error creating config")
|
||||
},
|
||||
expectedError: "error creating config",
|
||||
@ -58,7 +57,7 @@ func TestConfigCreateWithName(t *testing.T) {
|
||||
name := "foo"
|
||||
var actual []byte
|
||||
cli := test.NewFakeCli(&fakeClient{
|
||||
configCreateFunc: func(_ context.Context, spec swarm.ConfigSpec) (types.ConfigCreateResponse, error) {
|
||||
configCreateFunc: func(spec swarm.ConfigSpec) (types.ConfigCreateResponse, error) {
|
||||
if spec.Name != name {
|
||||
return types.ConfigCreateResponse{}, errors.Errorf("expected name %q, got %q", name, spec.Name)
|
||||
}
|
||||
@ -97,7 +96,7 @@ func TestConfigCreateWithLabels(t *testing.T) {
|
||||
}
|
||||
|
||||
cli := test.NewFakeCli(&fakeClient{
|
||||
configCreateFunc: func(_ context.Context, spec swarm.ConfigSpec) (types.ConfigCreateResponse, error) {
|
||||
configCreateFunc: func(spec swarm.ConfigSpec) (types.ConfigCreateResponse, error) {
|
||||
if !reflect.DeepEqual(spec, expected) {
|
||||
return types.ConfigCreateResponse{}, errors.Errorf("expected %+v, got %+v", expected, spec)
|
||||
}
|
||||
@ -123,7 +122,7 @@ func TestConfigCreateWithTemplatingDriver(t *testing.T) {
|
||||
name := "foo"
|
||||
|
||||
cli := test.NewFakeCli(&fakeClient{
|
||||
configCreateFunc: func(_ context.Context, spec swarm.ConfigSpec) (types.ConfigCreateResponse, error) {
|
||||
configCreateFunc: func(spec swarm.ConfigSpec) (types.ConfigCreateResponse, error) {
|
||||
if spec.Name != name {
|
||||
return types.ConfigCreateResponse{}, errors.Errorf("expected name %q, got %q", name, spec.Name)
|
||||
}
|
||||
|
||||
@ -1,7 +1,6 @@
|
||||
package config
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"io"
|
||||
"testing"
|
||||
@ -19,7 +18,7 @@ func TestConfigInspectErrors(t *testing.T) {
|
||||
testCases := []struct {
|
||||
args []string
|
||||
flags map[string]string
|
||||
configInspectFunc func(_ context.Context, configID string) (swarm.Config, []byte, error)
|
||||
configInspectFunc func(configID string) (swarm.Config, []byte, error)
|
||||
expectedError string
|
||||
}{
|
||||
{
|
||||
@ -27,7 +26,7 @@ func TestConfigInspectErrors(t *testing.T) {
|
||||
},
|
||||
{
|
||||
args: []string{"foo"},
|
||||
configInspectFunc: func(_ context.Context, configID string) (swarm.Config, []byte, error) {
|
||||
configInspectFunc: func(configID string) (swarm.Config, []byte, error) {
|
||||
return swarm.Config{}, nil, errors.Errorf("error while inspecting the config")
|
||||
},
|
||||
expectedError: "error while inspecting the config",
|
||||
@ -41,7 +40,7 @@ func TestConfigInspectErrors(t *testing.T) {
|
||||
},
|
||||
{
|
||||
args: []string{"foo", "bar"},
|
||||
configInspectFunc: func(_ context.Context, configID string) (swarm.Config, []byte, error) {
|
||||
configInspectFunc: func(configID string) (swarm.Config, []byte, error) {
|
||||
if configID == "foo" {
|
||||
return *Config(ConfigName("foo")), nil, nil
|
||||
}
|
||||
@ -69,12 +68,12 @@ func TestConfigInspectWithoutFormat(t *testing.T) {
|
||||
testCases := []struct {
|
||||
name string
|
||||
args []string
|
||||
configInspectFunc func(_ context.Context, configID string) (swarm.Config, []byte, error)
|
||||
configInspectFunc func(configID string) (swarm.Config, []byte, error)
|
||||
}{
|
||||
{
|
||||
name: "single-config",
|
||||
args: []string{"foo"},
|
||||
configInspectFunc: func(_ context.Context, name string) (swarm.Config, []byte, error) {
|
||||
configInspectFunc: func(name string) (swarm.Config, []byte, error) {
|
||||
if name != "foo" {
|
||||
return swarm.Config{}, nil, errors.Errorf("Invalid name, expected %s, got %s", "foo", name)
|
||||
}
|
||||
@ -84,7 +83,7 @@ func TestConfigInspectWithoutFormat(t *testing.T) {
|
||||
{
|
||||
name: "multiple-configs-with-labels",
|
||||
args: []string{"foo", "bar"},
|
||||
configInspectFunc: func(_ context.Context, name string) (swarm.Config, []byte, error) {
|
||||
configInspectFunc: func(name string) (swarm.Config, []byte, error) {
|
||||
return *Config(ConfigID("ID-"+name), ConfigName(name), ConfigLabels(map[string]string{
|
||||
"label1": "label-foo",
|
||||
})), nil, nil
|
||||
@ -101,7 +100,7 @@ func TestConfigInspectWithoutFormat(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestConfigInspectWithFormat(t *testing.T) {
|
||||
configInspectFunc := func(_ context.Context, name string) (swarm.Config, []byte, error) {
|
||||
configInspectFunc := func(name string) (swarm.Config, []byte, error) {
|
||||
return *Config(ConfigName("foo"), ConfigLabels(map[string]string{
|
||||
"label1": "label-foo",
|
||||
})), nil, nil
|
||||
@ -110,7 +109,7 @@ func TestConfigInspectWithFormat(t *testing.T) {
|
||||
name string
|
||||
format string
|
||||
args []string
|
||||
configInspectFunc func(_ context.Context, name string) (swarm.Config, []byte, error)
|
||||
configInspectFunc func(name string) (swarm.Config, []byte, error)
|
||||
}{
|
||||
{
|
||||
name: "simple-template",
|
||||
@ -140,11 +139,11 @@ func TestConfigInspectWithFormat(t *testing.T) {
|
||||
func TestConfigInspectPretty(t *testing.T) {
|
||||
testCases := []struct {
|
||||
name string
|
||||
configInspectFunc func(context.Context, string) (swarm.Config, []byte, error)
|
||||
configInspectFunc func(string) (swarm.Config, []byte, error)
|
||||
}{
|
||||
{
|
||||
name: "simple",
|
||||
configInspectFunc: func(_ context.Context, id string) (swarm.Config, []byte, error) {
|
||||
configInspectFunc: func(id string) (swarm.Config, []byte, error) {
|
||||
return *Config(
|
||||
ConfigLabels(map[string]string{
|
||||
"lbl1": "value1",
|
||||
|
||||
@ -1,7 +1,6 @@
|
||||
package config
|
||||
|
||||
import (
|
||||
"context"
|
||||
"io"
|
||||
"testing"
|
||||
"time"
|
||||
@ -20,7 +19,7 @@ import (
|
||||
func TestConfigListErrors(t *testing.T) {
|
||||
testCases := []struct {
|
||||
args []string
|
||||
configListFunc func(context.Context, types.ConfigListOptions) ([]swarm.Config, error)
|
||||
configListFunc func(types.ConfigListOptions) ([]swarm.Config, error)
|
||||
expectedError string
|
||||
}{
|
||||
{
|
||||
@ -28,7 +27,7 @@ func TestConfigListErrors(t *testing.T) {
|
||||
expectedError: "accepts no argument",
|
||||
},
|
||||
{
|
||||
configListFunc: func(_ context.Context, options types.ConfigListOptions) ([]swarm.Config, error) {
|
||||
configListFunc: func(options types.ConfigListOptions) ([]swarm.Config, error) {
|
||||
return []swarm.Config{}, errors.Errorf("error listing configs")
|
||||
},
|
||||
expectedError: "error listing configs",
|
||||
@ -48,7 +47,7 @@ func TestConfigListErrors(t *testing.T) {
|
||||
|
||||
func TestConfigList(t *testing.T) {
|
||||
cli := test.NewFakeCli(&fakeClient{
|
||||
configListFunc: func(_ context.Context, options types.ConfigListOptions) ([]swarm.Config, error) {
|
||||
configListFunc: func(options types.ConfigListOptions) ([]swarm.Config, error) {
|
||||
return []swarm.Config{
|
||||
*Config(ConfigID("ID-1-foo"),
|
||||
ConfigName("1-foo"),
|
||||
@ -78,7 +77,7 @@ func TestConfigList(t *testing.T) {
|
||||
|
||||
func TestConfigListWithQuietOption(t *testing.T) {
|
||||
cli := test.NewFakeCli(&fakeClient{
|
||||
configListFunc: func(_ context.Context, options types.ConfigListOptions) ([]swarm.Config, error) {
|
||||
configListFunc: func(options types.ConfigListOptions) ([]swarm.Config, error) {
|
||||
return []swarm.Config{
|
||||
*Config(ConfigID("ID-foo"), ConfigName("foo")),
|
||||
*Config(ConfigID("ID-bar"), ConfigName("bar"), ConfigLabels(map[string]string{
|
||||
@ -95,7 +94,7 @@ func TestConfigListWithQuietOption(t *testing.T) {
|
||||
|
||||
func TestConfigListWithConfigFormat(t *testing.T) {
|
||||
cli := test.NewFakeCli(&fakeClient{
|
||||
configListFunc: func(_ context.Context, options types.ConfigListOptions) ([]swarm.Config, error) {
|
||||
configListFunc: func(options types.ConfigListOptions) ([]swarm.Config, error) {
|
||||
return []swarm.Config{
|
||||
*Config(ConfigID("ID-foo"), ConfigName("foo")),
|
||||
*Config(ConfigID("ID-bar"), ConfigName("bar"), ConfigLabels(map[string]string{
|
||||
@ -114,7 +113,7 @@ func TestConfigListWithConfigFormat(t *testing.T) {
|
||||
|
||||
func TestConfigListWithFormat(t *testing.T) {
|
||||
cli := test.NewFakeCli(&fakeClient{
|
||||
configListFunc: func(_ context.Context, options types.ConfigListOptions) ([]swarm.Config, error) {
|
||||
configListFunc: func(options types.ConfigListOptions) ([]swarm.Config, error) {
|
||||
return []swarm.Config{
|
||||
*Config(ConfigID("ID-foo"), ConfigName("foo")),
|
||||
*Config(ConfigID("ID-bar"), ConfigName("bar"), ConfigLabels(map[string]string{
|
||||
@ -131,7 +130,7 @@ func TestConfigListWithFormat(t *testing.T) {
|
||||
|
||||
func TestConfigListWithFilter(t *testing.T) {
|
||||
cli := test.NewFakeCli(&fakeClient{
|
||||
configListFunc: func(_ context.Context, options types.ConfigListOptions) ([]swarm.Config, error) {
|
||||
configListFunc: func(options types.ConfigListOptions) ([]swarm.Config, error) {
|
||||
assert.Check(t, is.Equal("foo", options.Filters.Get("name")[0]))
|
||||
assert.Check(t, is.Equal("lbl1=Label-bar", options.Filters.Get("label")[0]))
|
||||
return []swarm.Config{
|
||||
|
||||
@ -64,7 +64,7 @@ func (f *fakeClient) ContainerExecInspect(_ context.Context, execID string) (typ
|
||||
return types.ContainerExecInspect{}, nil
|
||||
}
|
||||
|
||||
func (f *fakeClient) ContainerExecStart(context.Context, string, types.ExecStartCheck) error {
|
||||
func (f *fakeClient) ContainerExecStart(ctx context.Context, execID string, config types.ExecStartCheck) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
@ -89,7 +89,7 @@ func (f *fakeClient) ContainerRemove(ctx context.Context, container string, opti
|
||||
return nil
|
||||
}
|
||||
|
||||
func (f *fakeClient) ImageCreate(_ context.Context, parentReference string, options types.ImageCreateOptions) (io.ReadCloser, error) {
|
||||
func (f *fakeClient) ImageCreate(ctx context.Context, parentReference string, options types.ImageCreateOptions) (io.ReadCloser, error) {
|
||||
if f.imageCreateFunc != nil {
|
||||
return f.imageCreateFunc(parentReference, options)
|
||||
}
|
||||
|
||||
@ -1,20 +1,15 @@
|
||||
package container
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"os/signal"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"sync/atomic"
|
||||
"time"
|
||||
|
||||
"github.com/docker/cli/cli"
|
||||
"github.com/docker/cli/cli/command"
|
||||
"github.com/docker/cli/cli/streams"
|
||||
"github.com/docker/docker/api/types"
|
||||
"github.com/docker/docker/pkg/archive"
|
||||
"github.com/docker/docker/pkg/system"
|
||||
@ -53,73 +48,26 @@ type cpConfig struct {
|
||||
// copying files to/from a container.
|
||||
type copyProgressPrinter struct {
|
||||
io.ReadCloser
|
||||
total *int64
|
||||
toContainer bool
|
||||
total *float64
|
||||
writer io.Writer
|
||||
}
|
||||
|
||||
const (
|
||||
copyToContainerHeader = "Copying to container - "
|
||||
copyFromContainerHeader = "Copying from container - "
|
||||
copyProgressUpdateThreshold = 75 * time.Millisecond
|
||||
)
|
||||
|
||||
func (pt *copyProgressPrinter) Read(p []byte) (int, error) {
|
||||
n, err := pt.ReadCloser.Read(p)
|
||||
atomic.AddInt64(pt.total, int64(n))
|
||||
return n, err
|
||||
}
|
||||
*pt.total += float64(n)
|
||||
|
||||
func copyProgress(ctx context.Context, dst io.Writer, header string, total *int64) (func(), <-chan struct{}) {
|
||||
done := make(chan struct{})
|
||||
if !streams.NewOut(dst).IsTerminal() {
|
||||
close(done)
|
||||
return func() {}, done
|
||||
}
|
||||
|
||||
fmt.Fprint(dst, aec.Save)
|
||||
fmt.Fprint(dst, "Preparing to copy...")
|
||||
|
||||
restore := func() {
|
||||
fmt.Fprint(dst, aec.Restore)
|
||||
fmt.Fprint(dst, aec.EraseLine(aec.EraseModes.All))
|
||||
}
|
||||
|
||||
go func() {
|
||||
defer close(done)
|
||||
fmt.Fprint(dst, aec.Hide)
|
||||
defer fmt.Fprint(dst, aec.Show)
|
||||
|
||||
fmt.Fprint(dst, aec.Restore)
|
||||
fmt.Fprint(dst, aec.EraseLine(aec.EraseModes.All))
|
||||
fmt.Fprint(dst, header)
|
||||
|
||||
var last int64
|
||||
fmt.Fprint(dst, progressHumanSize(last))
|
||||
|
||||
buf := bytes.NewBuffer(nil)
|
||||
ticker := time.NewTicker(copyProgressUpdateThreshold)
|
||||
for {
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
return
|
||||
case <-ticker.C:
|
||||
n := atomic.LoadInt64(total)
|
||||
if n == last {
|
||||
// Don't write to the terminal, if we don't need to.
|
||||
continue
|
||||
}
|
||||
|
||||
// Write to the buffer first to avoid flickering and context switching
|
||||
fmt.Fprint(buf, aec.Column(uint(len(header)+1)))
|
||||
fmt.Fprint(buf, aec.EraseLine(aec.EraseModes.Tail))
|
||||
fmt.Fprint(buf, progressHumanSize(n))
|
||||
|
||||
buf.WriteTo(dst)
|
||||
buf.Reset()
|
||||
last += n
|
||||
}
|
||||
if err == nil {
|
||||
fmt.Fprint(pt.writer, aec.Restore)
|
||||
fmt.Fprint(pt.writer, aec.EraseLine(aec.EraseModes.All))
|
||||
if pt.toContainer {
|
||||
fmt.Fprintln(pt.writer, "Copying to container - "+units.HumanSize(*pt.total))
|
||||
} else {
|
||||
fmt.Fprintln(pt.writer, "Copying from container - "+units.HumanSize(*pt.total))
|
||||
}
|
||||
}()
|
||||
return restore, done
|
||||
}
|
||||
|
||||
return n, err
|
||||
}
|
||||
|
||||
// NewCopyCommand creates a new `docker cp` command
|
||||
@ -165,10 +113,6 @@ func NewCopyCommand(dockerCli command.Cli) *cobra.Command {
|
||||
return cmd
|
||||
}
|
||||
|
||||
func progressHumanSize(n int64) string {
|
||||
return units.HumanSizeWithPrecision(float64(n), 3)
|
||||
}
|
||||
|
||||
func runCopy(dockerCli command.Cli, opts copyOptions) error {
|
||||
srcContainer, srcPath := splitCpArg(opts.source)
|
||||
destContainer, destPath := splitCpArg(opts.destination)
|
||||
@ -209,7 +153,7 @@ func resolveLocalPath(localPath string) (absPath string, err error) {
|
||||
if absPath, err = filepath.Abs(localPath); err != nil {
|
||||
return
|
||||
}
|
||||
return archive.PreserveTrailingDotOrSeparator(absPath, localPath), nil
|
||||
return archive.PreserveTrailingDotOrSeparator(absPath, localPath, filepath.Separator), nil
|
||||
}
|
||||
|
||||
func copyFromContainer(ctx context.Context, dockerCli command.Cli, copyConfig cpConfig) (err error) {
|
||||
@ -249,9 +193,6 @@ func copyFromContainer(ctx context.Context, dockerCli command.Cli, copyConfig cp
|
||||
|
||||
}
|
||||
|
||||
ctx, cancel := signal.NotifyContext(ctx, os.Interrupt)
|
||||
defer cancel()
|
||||
|
||||
content, stat, err := client.CopyFromContainer(ctx, copyConfig.container, srcPath)
|
||||
if err != nil {
|
||||
return err
|
||||
@ -270,11 +211,13 @@ func copyFromContainer(ctx context.Context, dockerCli command.Cli, copyConfig cp
|
||||
RebaseName: rebaseName,
|
||||
}
|
||||
|
||||
var copiedSize int64
|
||||
var copiedSize float64
|
||||
if !copyConfig.quiet {
|
||||
content = ©ProgressPrinter{
|
||||
ReadCloser: content,
|
||||
total: &copiedSize,
|
||||
ReadCloser: content,
|
||||
toContainer: false,
|
||||
writer: dockerCli.Err(),
|
||||
total: &copiedSize,
|
||||
}
|
||||
}
|
||||
|
||||
@ -288,12 +231,12 @@ func copyFromContainer(ctx context.Context, dockerCli command.Cli, copyConfig cp
|
||||
return archive.CopyTo(preArchive, srcInfo, dstPath)
|
||||
}
|
||||
|
||||
restore, done := copyProgress(ctx, dockerCli.Err(), copyFromContainerHeader, &copiedSize)
|
||||
fmt.Fprint(dockerCli.Err(), aec.Save)
|
||||
fmt.Fprintln(dockerCli.Err(), "Preparing to copy...")
|
||||
res := archive.CopyTo(preArchive, srcInfo, dstPath)
|
||||
cancel()
|
||||
<-done
|
||||
restore()
|
||||
fmt.Fprintln(dockerCli.Err(), "Successfully copied", progressHumanSize(copiedSize), "to", dstPath)
|
||||
fmt.Fprint(dockerCli.Err(), aec.Restore)
|
||||
fmt.Fprint(dockerCli.Err(), aec.EraseLine(aec.EraseModes.All))
|
||||
fmt.Fprintln(dockerCli.Err(), "Successfully copied", units.HumanSize(copiedSize), "to", dstPath)
|
||||
|
||||
return res
|
||||
}
|
||||
@ -350,7 +293,7 @@ func copyToContainer(ctx context.Context, dockerCli command.Cli, copyConfig cpCo
|
||||
var (
|
||||
content io.ReadCloser
|
||||
resolvedDstPath string
|
||||
copiedSize int64
|
||||
copiedSize float64
|
||||
)
|
||||
|
||||
if srcPath == "-" {
|
||||
@ -394,8 +337,10 @@ func copyToContainer(ctx context.Context, dockerCli command.Cli, copyConfig cpCo
|
||||
content = preparedArchive
|
||||
if !copyConfig.quiet {
|
||||
content = ©ProgressPrinter{
|
||||
ReadCloser: content,
|
||||
total: &copiedSize,
|
||||
ReadCloser: content,
|
||||
toContainer: true,
|
||||
writer: dockerCli.Err(),
|
||||
total: &copiedSize,
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -409,13 +354,12 @@ func copyToContainer(ctx context.Context, dockerCli command.Cli, copyConfig cpCo
|
||||
return client.CopyToContainer(ctx, copyConfig.container, resolvedDstPath, content, options)
|
||||
}
|
||||
|
||||
ctx, cancel := signal.NotifyContext(ctx, os.Interrupt)
|
||||
restore, done := copyProgress(ctx, dockerCli.Err(), copyToContainerHeader, &copiedSize)
|
||||
fmt.Fprint(dockerCli.Err(), aec.Save)
|
||||
fmt.Fprintln(dockerCli.Err(), "Preparing to copy...")
|
||||
res := client.CopyToContainer(ctx, copyConfig.container, resolvedDstPath, content, options)
|
||||
cancel()
|
||||
<-done
|
||||
restore()
|
||||
fmt.Fprintln(dockerCli.Err(), "Successfully copied", progressHumanSize(copiedSize), "to", copyConfig.container+":"+dstInfo.Path)
|
||||
fmt.Fprint(dockerCli.Err(), aec.Restore)
|
||||
fmt.Fprint(dockerCli.Err(), aec.EraseLine(aec.EraseModes.All))
|
||||
fmt.Fprintln(dockerCli.Err(), "Successfully copied", units.HumanSize(copiedSize), "to", copyConfig.container+":"+dstInfo.Path)
|
||||
|
||||
return res
|
||||
}
|
||||
|
||||
@ -12,7 +12,6 @@ import (
|
||||
"github.com/docker/cli/cli/command"
|
||||
"github.com/docker/cli/cli/command/completion"
|
||||
"github.com/docker/cli/cli/command/image"
|
||||
"github.com/docker/cli/cli/streams"
|
||||
"github.com/docker/cli/opts"
|
||||
"github.com/docker/distribution/reference"
|
||||
"github.com/docker/docker/api/types"
|
||||
@ -20,6 +19,7 @@ import (
|
||||
"github.com/docker/docker/api/types/versions"
|
||||
apiclient "github.com/docker/docker/client"
|
||||
"github.com/docker/docker/pkg/jsonmessage"
|
||||
"github.com/docker/docker/registry"
|
||||
specs "github.com/opencontainers/image-spec/specs-go/v1"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/spf13/cobra"
|
||||
@ -95,16 +95,16 @@ func runCreate(dockerCli command.Cli, flags *pflag.FlagSet, options *createOptio
|
||||
}
|
||||
}
|
||||
copts.env = *opts.NewListOptsRef(&newEnv, nil)
|
||||
containerCfg, err := parse(flags, copts, dockerCli.ServerInfo().OSType)
|
||||
containerConfig, err := parse(flags, copts, dockerCli.ServerInfo().OSType)
|
||||
if err != nil {
|
||||
reportError(dockerCli.Err(), "create", err.Error(), true)
|
||||
return cli.StatusError{StatusCode: 125}
|
||||
}
|
||||
if err = validateAPIVersion(containerCfg, dockerCli.Client().ClientVersion()); err != nil {
|
||||
if err = validateAPIVersion(containerConfig, dockerCli.Client().ClientVersion()); err != nil {
|
||||
reportError(dockerCli.Err(), "create", err.Error(), true)
|
||||
return cli.StatusError{StatusCode: 125}
|
||||
}
|
||||
response, err := createContainer(context.Background(), dockerCli, containerCfg, options)
|
||||
response, err := createContainer(context.Background(), dockerCli, containerConfig, options)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -112,27 +112,41 @@ func runCreate(dockerCli command.Cli, flags *pflag.FlagSet, options *createOptio
|
||||
return nil
|
||||
}
|
||||
|
||||
// FIXME(thaJeztah): this is the only code-path that uses APIClient.ImageCreate. Rewrite this to use the regular "pull" code (or vice-versa).
|
||||
func pullImage(ctx context.Context, dockerCli command.Cli, image string, opts *createOptions) error {
|
||||
encodedAuth, err := command.RetrieveAuthTokenFromImage(ctx, dockerCli, image)
|
||||
func pullImage(ctx context.Context, dockerCli command.Cli, image string, platform string, out io.Writer) error {
|
||||
ref, err := reference.ParseNormalizedNamed(image)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
responseBody, err := dockerCli.Client().ImageCreate(ctx, image, types.ImageCreateOptions{
|
||||
// Resolve the Repository name from fqn to RepositoryInfo
|
||||
repoInfo, err := registry.ParseRepositoryInfo(ref)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
authConfig := command.ResolveAuthConfig(ctx, dockerCli, repoInfo.Index)
|
||||
encodedAuth, err := command.EncodeAuthToBase64(authConfig)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
options := types.ImageCreateOptions{
|
||||
RegistryAuth: encodedAuth,
|
||||
Platform: opts.platform,
|
||||
})
|
||||
Platform: platform,
|
||||
}
|
||||
|
||||
responseBody, err := dockerCli.Client().ImageCreate(ctx, image, options)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer responseBody.Close()
|
||||
|
||||
out := dockerCli.Err()
|
||||
if opts.quiet {
|
||||
out = io.Discard
|
||||
}
|
||||
return jsonmessage.DisplayJSONMessagesToStream(responseBody, streams.NewOut(out), nil)
|
||||
return jsonmessage.DisplayJSONMessagesStream(
|
||||
responseBody,
|
||||
out,
|
||||
dockerCli.Out().FD(),
|
||||
dockerCli.Out().IsTerminal(),
|
||||
nil)
|
||||
}
|
||||
|
||||
type cidFile struct {
|
||||
@ -185,10 +199,10 @@ func newCIDFile(path string) (*cidFile, error) {
|
||||
}
|
||||
|
||||
//nolint:gocyclo
|
||||
func createContainer(ctx context.Context, dockerCli command.Cli, containerCfg *containerConfig, opts *createOptions) (*container.CreateResponse, error) {
|
||||
config := containerCfg.Config
|
||||
hostConfig := containerCfg.HostConfig
|
||||
networkingConfig := containerCfg.NetworkingConfig
|
||||
func createContainer(ctx context.Context, dockerCli command.Cli, containerConfig *containerConfig, opts *createOptions) (*container.CreateResponse, error) {
|
||||
config := containerConfig.Config
|
||||
hostConfig := containerConfig.HostConfig
|
||||
networkingConfig := containerConfig.NetworkingConfig
|
||||
|
||||
warnOnOomKillDisable(*hostConfig, dockerCli.Err())
|
||||
warnOnLocalhostDNS(*hostConfig, dockerCli.Err())
|
||||
@ -213,7 +227,7 @@ func createContainer(ctx context.Context, dockerCli command.Cli, containerCfg *c
|
||||
|
||||
if taggedRef, ok := namedRef.(reference.NamedTagged); ok && !opts.untrusted {
|
||||
var err error
|
||||
trustedRef, err = image.TrustedReference(ctx, dockerCli, taggedRef)
|
||||
trustedRef, err = image.TrustedReference(ctx, dockerCli, taggedRef, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -222,7 +236,11 @@ func createContainer(ctx context.Context, dockerCli command.Cli, containerCfg *c
|
||||
}
|
||||
|
||||
pullAndTagImage := func() error {
|
||||
if err := pullImage(ctx, dockerCli, config.Image, opts); err != nil {
|
||||
pullOut := dockerCli.Err()
|
||||
if opts.quiet {
|
||||
pullOut = io.Discard
|
||||
}
|
||||
if err := pullImage(ctx, dockerCli, config.Image, opts.platform, pullOut); err != nil {
|
||||
return err
|
||||
}
|
||||
if taggedRef, ok := namedRef.(reference.NamedTagged); ok && trustedRef != nil {
|
||||
@ -275,8 +293,8 @@ func createContainer(ctx context.Context, dockerCli command.Cli, containerCfg *c
|
||||
}
|
||||
}
|
||||
|
||||
for _, w := range response.Warnings {
|
||||
fmt.Fprintf(dockerCli.Err(), "WARNING: %s\n", w)
|
||||
for _, warning := range response.Warnings {
|
||||
fmt.Fprintf(dockerCli.Err(), "WARNING: %s\n", warning)
|
||||
}
|
||||
err = containerIDFile.Write(response.ID)
|
||||
return &response, err
|
||||
|
||||
@ -120,8 +120,6 @@ func runPs(dockerCli command.Cli, options *psOptions) error {
|
||||
if len(options.format) == 0 {
|
||||
// load custom psFormat from CLI config (if any)
|
||||
options.format = dockerCli.ConfigFile().PsFormat
|
||||
} else if options.quiet {
|
||||
_, _ = dockerCli.Err().Write([]byte("WARNING: Ignoring custom format, because both --format and --quiet are set.\n"))
|
||||
}
|
||||
|
||||
listOptions, err := buildContainerListOptions(options)
|
||||
|
||||
@ -309,22 +309,8 @@ func TestContainerListWithFormat(t *testing.T) {
|
||||
}, nil
|
||||
},
|
||||
})
|
||||
|
||||
t.Run("with format", func(t *testing.T) {
|
||||
cli.OutBuffer().Reset()
|
||||
cmd := newListCommand(cli)
|
||||
assert.Check(t, cmd.Flags().Set("format", "{{ .Names }} {{ .Image }} {{ .Labels }}"))
|
||||
assert.NilError(t, cmd.Execute())
|
||||
golden.Assert(t, cli.OutBuffer().String(), "container-list-with-format.golden")
|
||||
})
|
||||
|
||||
t.Run("with format and quiet", func(t *testing.T) {
|
||||
cli.OutBuffer().Reset()
|
||||
cmd := newListCommand(cli)
|
||||
assert.Check(t, cmd.Flags().Set("format", "{{ .Names }} {{ .Image }} {{ .Labels }}"))
|
||||
assert.Check(t, cmd.Flags().Set("quiet", "true"))
|
||||
assert.NilError(t, cmd.Execute())
|
||||
assert.Equal(t, cli.ErrBuffer().String(), "WARNING: Ignoring custom format, because both --format and --quiet are set.\n")
|
||||
golden.Assert(t, cli.OutBuffer().String(), "container-list-quiet.golden")
|
||||
})
|
||||
cmd := newListCommand(cli)
|
||||
cmd.Flags().Set("format", "{{ .Names }} {{ .Image }} {{ .Labels }}")
|
||||
assert.NilError(t, cmd.Execute())
|
||||
golden.Assert(t, cli.OutBuffer().String(), "container-list-with-format.golden")
|
||||
}
|
||||
|
||||
@ -49,11 +49,11 @@ func parseRun(args []string) (*container.Config, *container.HostConfig, *network
|
||||
return nil, nil, nil, err
|
||||
}
|
||||
// TODO: fix tests to accept ContainerConfig
|
||||
containerCfg, err := parse(flags, copts, runtime.GOOS)
|
||||
containerConfig, err := parse(flags, copts, runtime.GOOS)
|
||||
if err != nil {
|
||||
return nil, nil, nil, err
|
||||
}
|
||||
return containerCfg.Config, containerCfg.HostConfig, containerCfg.NetworkingConfig, err
|
||||
return containerConfig.Config, containerConfig.HostConfig, containerConfig.NetworkingConfig, err
|
||||
}
|
||||
|
||||
func setupRunFlags() (*pflag.FlagSet, *containerOptions) {
|
||||
|
||||
@ -75,6 +75,6 @@ func runPrune(dockerCli command.Cli, options pruneOptions) (spaceReclaimed uint6
|
||||
|
||||
// RunPrune calls the Container Prune API
|
||||
// This returns the amount of space reclaimed and a detailed output string
|
||||
func RunPrune(dockerCli command.Cli, _ bool, filter opts.FilterOpt) (uint64, string, error) {
|
||||
func RunPrune(dockerCli command.Cli, all bool, filter opts.FilterOpt) (uint64, string, error) {
|
||||
return runPrune(dockerCli, pruneOptions{force: true, filter: filter})
|
||||
}
|
||||
|
||||
@ -105,22 +105,22 @@ func runRun(dockerCli command.Cli, flags *pflag.FlagSet, ropts *runOptions, copt
|
||||
}
|
||||
}
|
||||
copts.env = *opts.NewListOptsRef(&newEnv, nil)
|
||||
containerCfg, err := parse(flags, copts, dockerCli.ServerInfo().OSType)
|
||||
containerConfig, err := parse(flags, copts, dockerCli.ServerInfo().OSType)
|
||||
// just in case the parse does not exit
|
||||
if err != nil {
|
||||
reportError(dockerCli.Err(), "run", err.Error(), true)
|
||||
return cli.StatusError{StatusCode: 125}
|
||||
}
|
||||
if err = validateAPIVersion(containerCfg, dockerCli.CurrentVersion()); err != nil {
|
||||
if err = validateAPIVersion(containerConfig, dockerCli.CurrentVersion()); err != nil {
|
||||
reportError(dockerCli.Err(), "run", err.Error(), true)
|
||||
return cli.StatusError{StatusCode: 125}
|
||||
}
|
||||
return runContainer(dockerCli, ropts, copts, containerCfg)
|
||||
return runContainer(dockerCli, ropts, copts, containerConfig)
|
||||
}
|
||||
|
||||
//nolint:gocyclo
|
||||
func runContainer(dockerCli command.Cli, opts *runOptions, copts *containerOptions, containerCfg *containerConfig) error {
|
||||
config := containerCfg.Config
|
||||
func runContainer(dockerCli command.Cli, opts *runOptions, copts *containerOptions, containerConfig *containerConfig) error {
|
||||
config := containerConfig.Config
|
||||
stdout, stderr := dockerCli.Out(), dockerCli.Err()
|
||||
client := dockerCli.Client()
|
||||
|
||||
@ -144,7 +144,7 @@ func runContainer(dockerCli command.Cli, opts *runOptions, copts *containerOptio
|
||||
ctx, cancelFun := context.WithCancel(context.Background())
|
||||
defer cancelFun()
|
||||
|
||||
createResponse, err := createContainer(ctx, dockerCli, containerCfg, &opts.createOptions)
|
||||
createResponse, err := createContainer(ctx, dockerCli, containerConfig, &opts.createOptions)
|
||||
if err != nil {
|
||||
reportError(stderr, "run", err.Error(), true)
|
||||
return runStartContainerErr(err)
|
||||
@ -173,11 +173,11 @@ func runContainer(dockerCli command.Cli, opts *runOptions, copts *containerOptio
|
||||
dockerCli.ConfigFile().DetachKeys = opts.detachKeys
|
||||
}
|
||||
|
||||
closeFn, err := attachContainer(ctx, dockerCli, &errCh, config, createResponse.ID)
|
||||
close, err := attachContainer(ctx, dockerCli, &errCh, config, createResponse.ID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer closeFn()
|
||||
defer close()
|
||||
}
|
||||
|
||||
statusChan := waitExitOrRemoved(ctx, dockerCli, createResponse.ID, copts.autoRemove)
|
||||
|
||||
@ -1,2 +0,0 @@
|
||||
container_id
|
||||
container_id
|
||||
@ -118,7 +118,10 @@ func createNewContext(o *CreateOptions, cli command.Cli, s store.Writer) error {
|
||||
if err := s.CreateOrUpdate(contextMetadata); err != nil {
|
||||
return err
|
||||
}
|
||||
return s.ResetTLSMaterial(o.Name, &contextTLSData)
|
||||
if err := s.ResetTLSMaterial(o.Name, &contextTLSData); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func checkContextNameForCreation(s store.Reader, name string) error {
|
||||
|
||||
@ -55,9 +55,6 @@ ports: {{- pad .Ports 1 0}}
|
||||
}
|
||||
return Format(format)
|
||||
default: // custom format
|
||||
if quiet {
|
||||
return DefaultQuietFormat
|
||||
}
|
||||
return Format(source)
|
||||
}
|
||||
}
|
||||
|
||||
@ -163,7 +163,7 @@ containerID2 ubuntu "" 24 hours ago foobar_bar
|
||||
},
|
||||
{
|
||||
Context{Format: NewContainerFormat("table {{.Image}}", true, false)},
|
||||
"containerID1\ncontainerID2\n",
|
||||
"IMAGE\nubuntu\nubuntu\n",
|
||||
},
|
||||
{
|
||||
Context{Format: NewContainerFormat("table", true, false)},
|
||||
|
||||
@ -84,3 +84,10 @@ func (c *clientContextContext) Error() string {
|
||||
// TODO(thaJeztah) add "--no-trunc" option to context ls and set default to 30 cols to match "docker service ps"
|
||||
return Ellipsis(c.c.Error, maxErrLength)
|
||||
}
|
||||
|
||||
// KubernetesEndpoint returns the kubernetes endpoint.
|
||||
//
|
||||
// Deprecated: support for kubernetes endpoints in contexts has been removed, and this formatting option will always be empty.
|
||||
func (c *clientContextContext) KubernetesEndpoint() string {
|
||||
return ""
|
||||
}
|
||||
|
||||
@ -19,7 +19,7 @@ const (
|
||||
JSONFormatKey = "json"
|
||||
|
||||
DefaultQuietFormat = "{{.ID}}"
|
||||
JSONFormat = "{{json .}}"
|
||||
jsonFormat = "{{json .}}"
|
||||
)
|
||||
|
||||
// Format is the format string rendered using the Context
|
||||
@ -62,7 +62,7 @@ func (c *Context) preFormat() {
|
||||
case c.Format.IsTable():
|
||||
c.finalFormat = c.finalFormat[len(TableFormatKey):]
|
||||
case c.Format.IsJSON():
|
||||
c.finalFormat = JSONFormat
|
||||
c.finalFormat = jsonFormat
|
||||
}
|
||||
|
||||
c.finalFormat = strings.Trim(c.finalFormat, " ")
|
||||
|
||||
@ -14,14 +14,14 @@ type fakeClient struct {
|
||||
serviceInspectFunc func(string) (swarm.Service, []byte, error)
|
||||
}
|
||||
|
||||
func (cli *fakeClient) NodeInspectWithRaw(_ context.Context, nodeID string) (swarm.Node, []byte, error) {
|
||||
func (cli *fakeClient) NodeInspectWithRaw(ctx context.Context, nodeID string) (swarm.Node, []byte, error) {
|
||||
if cli.nodeInspectFunc != nil {
|
||||
return cli.nodeInspectFunc(nodeID)
|
||||
}
|
||||
return swarm.Node{}, []byte{}, nil
|
||||
}
|
||||
|
||||
func (cli *fakeClient) ServiceInspectWithRaw(_ context.Context, serviceID string, _ types.ServiceInspectOptions) (swarm.Service, []byte, error) {
|
||||
func (cli *fakeClient) ServiceInspectWithRaw(ctx context.Context, serviceID string, options types.ServiceInspectOptions) (swarm.Service, []byte, error) {
|
||||
if cli.serviceInspectFunc != nil {
|
||||
return cli.serviceInspectFunc(serviceID)
|
||||
}
|
||||
|
||||
@ -22,7 +22,6 @@ import (
|
||||
"github.com/docker/docker/api"
|
||||
"github.com/docker/docker/api/types"
|
||||
"github.com/docker/docker/api/types/container"
|
||||
registrytypes "github.com/docker/docker/api/types/registry"
|
||||
"github.com/docker/docker/builder/remotecontext/urlutil"
|
||||
"github.com/docker/docker/pkg/archive"
|
||||
"github.com/docker/docker/pkg/idtools"
|
||||
@ -280,7 +279,7 @@ func runBuild(dockerCli command.Cli, options buildOptions) error {
|
||||
var resolvedTags []*resolvedTag
|
||||
if !options.untrusted {
|
||||
translator := func(ctx context.Context, ref reference.NamedTagged) (reference.Canonical, error) {
|
||||
return TrustedReference(ctx, dockerCli, ref)
|
||||
return TrustedReference(ctx, dockerCli, ref, nil)
|
||||
}
|
||||
// if there is a tar wrapper, the dockerfile needs to be replaced inside it
|
||||
if buildCtx != nil {
|
||||
@ -323,9 +322,9 @@ func runBuild(dockerCli command.Cli, options buildOptions) error {
|
||||
|
||||
configFile := dockerCli.ConfigFile()
|
||||
creds, _ := configFile.GetAllCredentials()
|
||||
authConfigs := make(map[string]registrytypes.AuthConfig, len(creds))
|
||||
authConfigs := make(map[string]types.AuthConfig, len(creds))
|
||||
for k, auth := range creds {
|
||||
authConfigs[k] = registrytypes.AuthConfig(auth)
|
||||
authConfigs[k] = types.AuthConfig(auth)
|
||||
}
|
||||
buildOptions := imageBuildOptions(dockerCli, options)
|
||||
buildOptions.Version = types.BuilderV1
|
||||
|
||||
@ -18,7 +18,7 @@ import (
|
||||
|
||||
const dockerfileContents = "FROM busybox"
|
||||
|
||||
func prepareEmpty(_ *testing.T) string {
|
||||
func prepareEmpty(t *testing.T) string {
|
||||
return ""
|
||||
}
|
||||
|
||||
|
||||
@ -87,7 +87,7 @@ func (cli *fakeClient) ImageLoad(_ context.Context, input io.Reader, quiet bool)
|
||||
return types.ImageLoadResponse{}, nil
|
||||
}
|
||||
|
||||
func (cli *fakeClient) ImageList(_ context.Context, options types.ImageListOptions) ([]types.ImageSummary, error) {
|
||||
func (cli *fakeClient) ImageList(ctx context.Context, options types.ImageListOptions) ([]types.ImageSummary, error) {
|
||||
if cli.imageListFunc != nil {
|
||||
return cli.imageListFunc(options)
|
||||
}
|
||||
|
||||
@ -69,7 +69,7 @@ func RunPull(cli command.Cli, opts PullOptions) error {
|
||||
}
|
||||
|
||||
ctx := context.Background()
|
||||
imgRefAndAuth, err := trust.GetImageReferencesAndAuth(ctx, AuthResolver(cli), distributionRef.String())
|
||||
imgRefAndAuth, err := trust.GetImageReferencesAndAuth(ctx, nil, AuthResolver(cli), distributionRef.String())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@ -11,7 +11,6 @@ import (
|
||||
"github.com/docker/cli/cli/streams"
|
||||
"github.com/docker/distribution/reference"
|
||||
"github.com/docker/docker/api/types"
|
||||
registrytypes "github.com/docker/docker/api/types/registry"
|
||||
"github.com/docker/docker/pkg/jsonmessage"
|
||||
"github.com/docker/docker/registry"
|
||||
"github.com/pkg/errors"
|
||||
@ -77,7 +76,7 @@ func RunPush(dockerCli command.Cli, opts pushOptions) error {
|
||||
|
||||
// Resolve the Auth config relevant for this server
|
||||
authConfig := command.ResolveAuthConfig(ctx, dockerCli, repoInfo.Index)
|
||||
encodedAuth, err := registrytypes.EncodeAuthConfig(authConfig)
|
||||
encodedAuth, err := command.EncodeAuthToBase64(authConfig)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@ -30,7 +30,7 @@ type target struct {
|
||||
}
|
||||
|
||||
// TrustedPush handles content trust pushing of an image
|
||||
func TrustedPush(ctx context.Context, cli command.Cli, repoInfo *registry.RepositoryInfo, ref reference.Named, authConfig registrytypes.AuthConfig, options types.ImagePushOptions) error {
|
||||
func TrustedPush(ctx context.Context, cli command.Cli, repoInfo *registry.RepositoryInfo, ref reference.Named, authConfig types.AuthConfig, options types.ImagePushOptions) error {
|
||||
responseBody, err := cli.Client().ImagePush(ctx, reference.FamiliarString(ref), options)
|
||||
if err != nil {
|
||||
return err
|
||||
@ -44,7 +44,7 @@ func TrustedPush(ctx context.Context, cli command.Cli, repoInfo *registry.Reposi
|
||||
// PushTrustedReference pushes a canonical reference to the trust server.
|
||||
//
|
||||
//nolint:gocyclo
|
||||
func PushTrustedReference(streams command.Streams, repoInfo *registry.RepositoryInfo, ref reference.Named, authConfig registrytypes.AuthConfig, in io.Reader) error {
|
||||
func PushTrustedReference(streams command.Streams, repoInfo *registry.RepositoryInfo, ref reference.Named, authConfig types.AuthConfig, in io.Reader) error {
|
||||
// If it is a trusted push we would like to find the target entry which match the
|
||||
// tag provided in the function and then do an AddTarget later.
|
||||
target := &client.Target{}
|
||||
@ -186,7 +186,7 @@ func trustedPull(ctx context.Context, cli command.Cli, imgRefAndAuth trust.Image
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
updatedImgRefAndAuth, err := trust.GetImageReferencesAndAuth(ctx, AuthResolver(cli), trustedRef.String())
|
||||
updatedImgRefAndAuth, err := trust.GetImageReferencesAndAuth(ctx, nil, AuthResolver(cli), trustedRef.String())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -262,17 +262,20 @@ func getTrustedPullTargets(cli command.Cli, imgRefAndAuth trust.ImageRefAndAuth)
|
||||
|
||||
// imagePullPrivileged pulls the image and displays it to the output
|
||||
func imagePullPrivileged(ctx context.Context, cli command.Cli, imgRefAndAuth trust.ImageRefAndAuth, opts PullOptions) error {
|
||||
encodedAuth, err := registrytypes.EncodeAuthConfig(*imgRefAndAuth.AuthConfig())
|
||||
ref := reference.FamiliarString(imgRefAndAuth.Reference())
|
||||
|
||||
encodedAuth, err := command.EncodeAuthToBase64(*imgRefAndAuth.AuthConfig())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
requestPrivilege := command.RegistryAuthenticationPrivilegedFunc(cli, imgRefAndAuth.RepoInfo().Index, "pull")
|
||||
responseBody, err := cli.Client().ImagePull(ctx, reference.FamiliarString(imgRefAndAuth.Reference()), types.ImagePullOptions{
|
||||
options := types.ImagePullOptions{
|
||||
RegistryAuth: encodedAuth,
|
||||
PrivilegeFunc: requestPrivilege,
|
||||
All: opts.all,
|
||||
Platform: opts.platform,
|
||||
})
|
||||
}
|
||||
responseBody, err := cli.Client().ImagePull(ctx, ref, options)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -286,8 +289,8 @@ func imagePullPrivileged(ctx context.Context, cli command.Cli, imgRefAndAuth tru
|
||||
}
|
||||
|
||||
// TrustedReference returns the canonical trusted reference for an image reference
|
||||
func TrustedReference(ctx context.Context, cli command.Cli, ref reference.NamedTagged) (reference.Canonical, error) {
|
||||
imgRefAndAuth, err := trust.GetImageReferencesAndAuth(ctx, AuthResolver(cli), ref.String())
|
||||
func TrustedReference(ctx context.Context, cli command.Cli, ref reference.NamedTagged, rs registry.Service) (reference.Canonical, error) {
|
||||
imgRefAndAuth, err := trust.GetImageReferencesAndAuth(ctx, rs, AuthResolver(cli), ref.String())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -337,8 +340,8 @@ func TagTrusted(ctx context.Context, cli command.Cli, trustedRef reference.Canon
|
||||
}
|
||||
|
||||
// AuthResolver returns an auth resolver function from a command.Cli
|
||||
func AuthResolver(cli command.Cli) func(ctx context.Context, index *registrytypes.IndexInfo) registrytypes.AuthConfig {
|
||||
return func(ctx context.Context, index *registrytypes.IndexInfo) registrytypes.AuthConfig {
|
||||
func AuthResolver(cli command.Cli) func(ctx context.Context, index *registrytypes.IndexInfo) types.AuthConfig {
|
||||
return func(ctx context.Context, index *registrytypes.IndexInfo) types.AuthConfig {
|
||||
return command.ResolveAuthConfig(ctx, cli, index)
|
||||
}
|
||||
}
|
||||
|
||||
@ -52,6 +52,6 @@ func (c *fakeClient) NetworkRemove(ctx context.Context, networkID string) error
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *fakeClient) NetworkInspectWithRaw(context.Context, string, types.NetworkInspectOptions) (types.NetworkResource, []byte, error) {
|
||||
func (c *fakeClient) NetworkInspectWithRaw(ctx context.Context, network string, options types.NetworkInspectOptions) (types.NetworkResource, []byte, error) {
|
||||
return types.NetworkResource{}, nil, nil
|
||||
}
|
||||
|
||||
@ -70,7 +70,7 @@ func runPrune(dockerCli command.Cli, options pruneOptions) (output string, err e
|
||||
|
||||
// RunPrune calls the Network Prune API
|
||||
// This returns the amount of space reclaimed and a detailed output string
|
||||
func RunPrune(dockerCli command.Cli, _ bool, filter opts.FilterOpt) (uint64, string, error) {
|
||||
func RunPrune(dockerCli command.Cli, all bool, filter opts.FilterOpt) (uint64, string, error) {
|
||||
output, err := runPrune(dockerCli, pruneOptions{force: true, filter: filter})
|
||||
return 0, output, err
|
||||
}
|
||||
|
||||
@ -20,49 +20,49 @@ type fakeClient struct {
|
||||
serviceInspectFunc func(ctx context.Context, serviceID string, opts types.ServiceInspectOptions) (swarm.Service, []byte, error)
|
||||
}
|
||||
|
||||
func (cli *fakeClient) NodeInspectWithRaw(context.Context, string) (swarm.Node, []byte, error) {
|
||||
func (cli *fakeClient) NodeInspectWithRaw(ctx context.Context, ref string) (swarm.Node, []byte, error) {
|
||||
if cli.nodeInspectFunc != nil {
|
||||
return cli.nodeInspectFunc()
|
||||
}
|
||||
return swarm.Node{}, []byte{}, nil
|
||||
}
|
||||
|
||||
func (cli *fakeClient) NodeList(context.Context, types.NodeListOptions) ([]swarm.Node, error) {
|
||||
func (cli *fakeClient) NodeList(ctx context.Context, options types.NodeListOptions) ([]swarm.Node, error) {
|
||||
if cli.nodeListFunc != nil {
|
||||
return cli.nodeListFunc()
|
||||
}
|
||||
return []swarm.Node{}, nil
|
||||
}
|
||||
|
||||
func (cli *fakeClient) NodeRemove(context.Context, string, types.NodeRemoveOptions) error {
|
||||
func (cli *fakeClient) NodeRemove(ctx context.Context, nodeID string, options types.NodeRemoveOptions) error {
|
||||
if cli.nodeRemoveFunc != nil {
|
||||
return cli.nodeRemoveFunc()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (cli *fakeClient) NodeUpdate(_ context.Context, nodeID string, version swarm.Version, node swarm.NodeSpec) error {
|
||||
func (cli *fakeClient) NodeUpdate(ctx context.Context, nodeID string, version swarm.Version, node swarm.NodeSpec) error {
|
||||
if cli.nodeUpdateFunc != nil {
|
||||
return cli.nodeUpdateFunc(nodeID, version, node)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (cli *fakeClient) Info(context.Context) (types.Info, error) {
|
||||
func (cli *fakeClient) Info(ctx context.Context) (types.Info, error) {
|
||||
if cli.infoFunc != nil {
|
||||
return cli.infoFunc()
|
||||
}
|
||||
return types.Info{}, nil
|
||||
}
|
||||
|
||||
func (cli *fakeClient) TaskInspectWithRaw(_ context.Context, taskID string) (swarm.Task, []byte, error) {
|
||||
func (cli *fakeClient) TaskInspectWithRaw(ctx context.Context, taskID string) (swarm.Task, []byte, error) {
|
||||
if cli.taskInspectFunc != nil {
|
||||
return cli.taskInspectFunc(taskID)
|
||||
}
|
||||
return swarm.Task{}, []byte{}, nil
|
||||
}
|
||||
|
||||
func (cli *fakeClient) TaskList(_ context.Context, options types.TaskListOptions) ([]swarm.Task, error) {
|
||||
func (cli *fakeClient) TaskList(ctx context.Context, options types.TaskListOptions) ([]swarm.Task, error) {
|
||||
if cli.taskListFunc != nil {
|
||||
return cli.taskListFunc(options)
|
||||
}
|
||||
|
||||
@ -20,42 +20,42 @@ type fakeClient struct {
|
||||
pluginInspectFunc func(name string) (*types.Plugin, []byte, error)
|
||||
}
|
||||
|
||||
func (c *fakeClient) PluginCreate(_ context.Context, createContext io.Reader, createOptions types.PluginCreateOptions) error {
|
||||
func (c *fakeClient) PluginCreate(ctx context.Context, createContext io.Reader, createOptions types.PluginCreateOptions) error {
|
||||
if c.pluginCreateFunc != nil {
|
||||
return c.pluginCreateFunc(createContext, createOptions)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *fakeClient) PluginEnable(_ context.Context, name string, enableOptions types.PluginEnableOptions) error {
|
||||
func (c *fakeClient) PluginEnable(ctx context.Context, name string, enableOptions types.PluginEnableOptions) error {
|
||||
if c.pluginEnableFunc != nil {
|
||||
return c.pluginEnableFunc(name, enableOptions)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *fakeClient) PluginDisable(_ context.Context, name string, disableOptions types.PluginDisableOptions) error {
|
||||
func (c *fakeClient) PluginDisable(context context.Context, name string, disableOptions types.PluginDisableOptions) error {
|
||||
if c.pluginDisableFunc != nil {
|
||||
return c.pluginDisableFunc(name, disableOptions)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *fakeClient) PluginRemove(_ context.Context, name string, removeOptions types.PluginRemoveOptions) error {
|
||||
func (c *fakeClient) PluginRemove(context context.Context, name string, removeOptions types.PluginRemoveOptions) error {
|
||||
if c.pluginRemoveFunc != nil {
|
||||
return c.pluginRemoveFunc(name, removeOptions)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *fakeClient) PluginInstall(_ context.Context, name string, installOptions types.PluginInstallOptions) (io.ReadCloser, error) {
|
||||
func (c *fakeClient) PluginInstall(context context.Context, name string, installOptions types.PluginInstallOptions) (io.ReadCloser, error) {
|
||||
if c.pluginInstallFunc != nil {
|
||||
return c.pluginInstallFunc(name, installOptions)
|
||||
}
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func (c *fakeClient) PluginList(_ context.Context, filter filters.Args) (types.PluginsListResponse, error) {
|
||||
func (c *fakeClient) PluginList(context context.Context, filter filters.Args) (types.PluginsListResponse, error) {
|
||||
if c.pluginListFunc != nil {
|
||||
return c.pluginListFunc(filter)
|
||||
}
|
||||
@ -63,7 +63,7 @@ func (c *fakeClient) PluginList(_ context.Context, filter filters.Args) (types.P
|
||||
return types.PluginsListResponse{}, nil
|
||||
}
|
||||
|
||||
func (c *fakeClient) PluginInspectWithRaw(_ context.Context, name string) (*types.Plugin, []byte, error) {
|
||||
func (c *fakeClient) PluginInspectWithRaw(ctx context.Context, name string) (*types.Plugin, []byte, error) {
|
||||
if c.pluginInspectFunc != nil {
|
||||
return c.pluginInspectFunc(name)
|
||||
}
|
||||
@ -71,6 +71,6 @@ func (c *fakeClient) PluginInspectWithRaw(_ context.Context, name string) (*type
|
||||
return nil, nil, nil
|
||||
}
|
||||
|
||||
func (c *fakeClient) Info(context.Context) (types.Info, error) {
|
||||
func (c *fakeClient) Info(ctx context.Context) (types.Info, error) {
|
||||
return types.Info{}, nil
|
||||
}
|
||||
|
||||
@ -10,7 +10,6 @@ import (
|
||||
"github.com/docker/cli/cli/command/image"
|
||||
"github.com/docker/distribution/reference"
|
||||
"github.com/docker/docker/api/types"
|
||||
registrytypes "github.com/docker/docker/api/types/registry"
|
||||
"github.com/docker/docker/pkg/jsonmessage"
|
||||
"github.com/docker/docker/registry"
|
||||
"github.com/pkg/errors"
|
||||
@ -55,6 +54,26 @@ func newInstallCommand(dockerCli command.Cli) *cobra.Command {
|
||||
return cmd
|
||||
}
|
||||
|
||||
type pluginRegistryService struct {
|
||||
registry.Service
|
||||
}
|
||||
|
||||
func (s pluginRegistryService) ResolveRepository(name reference.Named) (*registry.RepositoryInfo, error) {
|
||||
repoInfo, err := s.Service.ResolveRepository(name)
|
||||
if repoInfo != nil {
|
||||
repoInfo.Class = "plugin"
|
||||
}
|
||||
return repoInfo, err
|
||||
}
|
||||
|
||||
func newRegistryService() (registry.Service, error) {
|
||||
svc, err := registry.NewService(registry.ServiceOptions{})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return pluginRegistryService{Service: svc}, nil
|
||||
}
|
||||
|
||||
func buildPullConfig(ctx context.Context, dockerCli command.Cli, opts pluginOptions, cmdName string) (types.PluginInstallOptions, error) {
|
||||
// Names with both tag and digest will be treated by the daemon
|
||||
// as a pull by digest with a local name for the tag
|
||||
@ -79,7 +98,12 @@ func buildPullConfig(ctx context.Context, dockerCli command.Cli, opts pluginOpti
|
||||
return types.PluginInstallOptions{}, errors.Errorf("invalid name: %s", ref.String())
|
||||
}
|
||||
|
||||
trusted, err := image.TrustedReference(context.Background(), dockerCli, nt)
|
||||
ctx := context.Background()
|
||||
svc, err := newRegistryService()
|
||||
if err != nil {
|
||||
return types.PluginInstallOptions{}, err
|
||||
}
|
||||
trusted, err := image.TrustedReference(ctx, dockerCli, nt, svc)
|
||||
if err != nil {
|
||||
return types.PluginInstallOptions{}, err
|
||||
}
|
||||
@ -87,7 +111,8 @@ func buildPullConfig(ctx context.Context, dockerCli command.Cli, opts pluginOpti
|
||||
}
|
||||
|
||||
authConfig := command.ResolveAuthConfig(ctx, dockerCli, repoInfo.Index)
|
||||
encodedAuth, err := registrytypes.EncodeAuthConfig(authConfig)
|
||||
|
||||
encodedAuth, err := command.EncodeAuthToBase64(authConfig)
|
||||
if err != nil {
|
||||
return types.PluginInstallOptions{}, err
|
||||
}
|
||||
|
||||
@ -7,7 +7,6 @@ import (
|
||||
"github.com/docker/cli/cli/command"
|
||||
"github.com/docker/cli/cli/command/image"
|
||||
"github.com/docker/distribution/reference"
|
||||
registrytypes "github.com/docker/docker/api/types/registry"
|
||||
"github.com/docker/docker/pkg/jsonmessage"
|
||||
"github.com/docker/docker/registry"
|
||||
"github.com/pkg/errors"
|
||||
@ -56,7 +55,8 @@ func runPush(dockerCli command.Cli, opts pushOptions) error {
|
||||
return err
|
||||
}
|
||||
authConfig := command.ResolveAuthConfig(ctx, dockerCli, repoInfo.Index)
|
||||
encodedAuth, err := registrytypes.EncodeAuthConfig(authConfig)
|
||||
|
||||
encodedAuth, err := command.EncodeAuthToBase64(authConfig)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -68,6 +68,7 @@ func runPush(dockerCli command.Cli, opts pushOptions) error {
|
||||
defer responseBody.Close()
|
||||
|
||||
if !opts.untrusted {
|
||||
repoInfo.Class = "plugin"
|
||||
return image.PushTrustedReference(dockerCli, repoInfo, named, authConfig, responseBody)
|
||||
}
|
||||
|
||||
|
||||
@ -3,6 +3,8 @@ package command
|
||||
import (
|
||||
"bufio"
|
||||
"context"
|
||||
"encoding/base64"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
@ -19,11 +21,20 @@ import (
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
// EncodeAuthToBase64 serializes the auth configuration as JSON base64 payload.
|
||||
// ElectAuthServer returns the default registry to use.
|
||||
//
|
||||
// Deprecated: use [registrytypes.EncodeAuthConfig] instead.
|
||||
func EncodeAuthToBase64(authConfig registrytypes.AuthConfig) (string, error) {
|
||||
return registrytypes.EncodeAuthConfig(authConfig)
|
||||
// Deprecated: use [registry.IndexServer] instead.
|
||||
func ElectAuthServer(_ context.Context, _ Cli) string {
|
||||
return registry.IndexServer
|
||||
}
|
||||
|
||||
// EncodeAuthToBase64 serializes the auth configuration as JSON base64 payload
|
||||
func EncodeAuthToBase64(authConfig types.AuthConfig) (string, error) {
|
||||
buf, err := json.Marshal(authConfig)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return base64.URLEncoding.EncodeToString(buf), nil
|
||||
}
|
||||
|
||||
// RegistryAuthenticationPrivilegedFunc returns a RequestPrivilegeFunc from the specified registry index info
|
||||
@ -41,29 +52,26 @@ func RegistryAuthenticationPrivilegedFunc(cli Cli, index *registrytypes.IndexInf
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return registrytypes.EncodeAuthConfig(authConfig)
|
||||
return EncodeAuthToBase64(authConfig)
|
||||
}
|
||||
}
|
||||
|
||||
// ResolveAuthConfig returns auth-config for the given registry from the
|
||||
// credential-store. It returns an empty AuthConfig if no credentials were
|
||||
// found.
|
||||
//
|
||||
// It is similar to [registry.ResolveAuthConfig], but uses the credentials-
|
||||
// store, instead of looking up credentials from a map.
|
||||
func ResolveAuthConfig(_ context.Context, cli Cli, index *registrytypes.IndexInfo) registrytypes.AuthConfig {
|
||||
// ResolveAuthConfig is like registry.ResolveAuthConfig, but if using the
|
||||
// default index, it uses the default index name for the daemon's platform,
|
||||
// not the client's platform.
|
||||
func ResolveAuthConfig(_ context.Context, cli Cli, index *registrytypes.IndexInfo) types.AuthConfig {
|
||||
configKey := index.Name
|
||||
if index.Official {
|
||||
configKey = registry.IndexServer
|
||||
}
|
||||
|
||||
a, _ := cli.ConfigFile().GetAuthConfig(configKey)
|
||||
return registrytypes.AuthConfig(a)
|
||||
return types.AuthConfig(a)
|
||||
}
|
||||
|
||||
// GetDefaultAuthConfig gets the default auth config given a serverAddress
|
||||
// If credentials for given serverAddress exists in the credential store, the configuration will be populated with values in it
|
||||
func GetDefaultAuthConfig(cli Cli, checkCredStore bool, serverAddress string, isDefaultRegistry bool) (registrytypes.AuthConfig, error) {
|
||||
func GetDefaultAuthConfig(cli Cli, checkCredStore bool, serverAddress string, isDefaultRegistry bool) (types.AuthConfig, error) {
|
||||
if !isDefaultRegistry {
|
||||
serverAddress = registry.ConvertToHostname(serverAddress)
|
||||
}
|
||||
@ -72,27 +80,20 @@ func GetDefaultAuthConfig(cli Cli, checkCredStore bool, serverAddress string, is
|
||||
if checkCredStore {
|
||||
authconfig, err = cli.ConfigFile().GetAuthConfig(serverAddress)
|
||||
if err != nil {
|
||||
return registrytypes.AuthConfig{
|
||||
return types.AuthConfig{
|
||||
ServerAddress: serverAddress,
|
||||
}, err
|
||||
}
|
||||
}
|
||||
authconfig.ServerAddress = serverAddress
|
||||
authconfig.IdentityToken = ""
|
||||
res := registrytypes.AuthConfig(authconfig)
|
||||
res := types.AuthConfig(authconfig)
|
||||
return res, nil
|
||||
}
|
||||
|
||||
// ConfigureAuth handles prompting of user's username and password if needed
|
||||
func ConfigureAuth(cli Cli, flUser, flPassword string, authconfig *registrytypes.AuthConfig, isDefaultRegistry bool) error {
|
||||
// On Windows, force the use of the regular OS stdin stream.
|
||||
//
|
||||
// See:
|
||||
// - https://github.com/moby/moby/issues/14336
|
||||
// - https://github.com/moby/moby/issues/14210
|
||||
// - https://github.com/moby/moby/pull/17738
|
||||
//
|
||||
// TODO(thaJeztah): we need to confirm if this special handling is still needed, as we may not be doing this in other places.
|
||||
func ConfigureAuth(cli Cli, flUser, flPassword string, authconfig *types.AuthConfig, isDefaultRegistry bool) error {
|
||||
// On Windows, force the use of the regular OS stdin stream. Fixes #14336/#14210
|
||||
if runtime.GOOS == "windows" {
|
||||
cli.SetIn(streams.NewIn(os.Stdin))
|
||||
}
|
||||
@ -116,11 +117,8 @@ func ConfigureAuth(cli Cli, flUser, flPassword string, authconfig *registrytypes
|
||||
fmt.Fprintln(cli.Out(), "Login with your Docker ID to push and pull images from Docker Hub. If you don't have a Docker ID, head over to https://hub.docker.com to create one.")
|
||||
}
|
||||
promptWithDefault(cli.Out(), "Username", authconfig.Username)
|
||||
var err error
|
||||
flUser, err = readInput(cli.In())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
flUser = readInput(cli.In(), cli.Out())
|
||||
flUser = strings.TrimSpace(flUser)
|
||||
if flUser == "" {
|
||||
flUser = authconfig.Username
|
||||
}
|
||||
@ -134,15 +132,12 @@ func ConfigureAuth(cli Cli, flUser, flPassword string, authconfig *registrytypes
|
||||
return err
|
||||
}
|
||||
fmt.Fprintf(cli.Out(), "Password: ")
|
||||
_ = term.DisableEcho(cli.In().FD(), oldState)
|
||||
defer func() {
|
||||
_ = term.RestoreTerminal(cli.In().FD(), oldState)
|
||||
}()
|
||||
flPassword, err = readInput(cli.In())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
term.DisableEcho(cli.In().FD(), oldState)
|
||||
|
||||
flPassword = readInput(cli.In(), cli.Out())
|
||||
fmt.Fprint(cli.Out(), "\n")
|
||||
|
||||
term.RestoreTerminal(cli.In().FD(), oldState)
|
||||
if flPassword == "" {
|
||||
return errors.Errorf("Error: Password Required")
|
||||
}
|
||||
@ -154,15 +149,14 @@ func ConfigureAuth(cli Cli, flUser, flPassword string, authconfig *registrytypes
|
||||
return nil
|
||||
}
|
||||
|
||||
// readInput reads, and returns user input from in. It tries to return a
|
||||
// single line, not including the end-of-line bytes, and trims leading
|
||||
// and trailing whitespace.
|
||||
func readInput(in io.Reader) (string, error) {
|
||||
line, _, err := bufio.NewReader(in).ReadLine()
|
||||
func readInput(in io.Reader, out io.Writer) string {
|
||||
reader := bufio.NewReader(in)
|
||||
line, _, err := reader.ReadLine()
|
||||
if err != nil {
|
||||
return "", errors.Wrap(err, "error while reading input")
|
||||
fmt.Fprintln(out, err.Error())
|
||||
os.Exit(1)
|
||||
}
|
||||
return strings.TrimSpace(string(line)), nil
|
||||
return string(line)
|
||||
}
|
||||
|
||||
func promptWithDefault(out io.Writer, prompt string, configDefault string) {
|
||||
@ -173,19 +167,14 @@ func promptWithDefault(out io.Writer, prompt string, configDefault string) {
|
||||
}
|
||||
}
|
||||
|
||||
// RetrieveAuthTokenFromImage retrieves an encoded auth token given a complete
|
||||
// image. The auth configuration is serialized as a base64url encoded RFC4648,
|
||||
// section 5) JSON string for sending through the X-Registry-Auth header.
|
||||
//
|
||||
// For details on base64url encoding, see:
|
||||
// - RFC4648, section 5: https://tools.ietf.org/html/rfc4648#section-5
|
||||
// RetrieveAuthTokenFromImage retrieves an encoded auth token given a complete image
|
||||
func RetrieveAuthTokenFromImage(ctx context.Context, cli Cli, image string) (string, error) {
|
||||
// Retrieve encoded auth token from the image reference
|
||||
authConfig, err := resolveAuthConfigFromImage(ctx, cli, image)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
encodedAuth, err := registrytypes.EncodeAuthConfig(authConfig)
|
||||
encodedAuth, err := EncodeAuthToBase64(authConfig)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
@ -193,14 +182,14 @@ func RetrieveAuthTokenFromImage(ctx context.Context, cli Cli, image string) (str
|
||||
}
|
||||
|
||||
// resolveAuthConfigFromImage retrieves that AuthConfig using the image string
|
||||
func resolveAuthConfigFromImage(ctx context.Context, cli Cli, image string) (registrytypes.AuthConfig, error) {
|
||||
func resolveAuthConfigFromImage(ctx context.Context, cli Cli, image string) (types.AuthConfig, error) {
|
||||
registryRef, err := reference.ParseNormalizedNamed(image)
|
||||
if err != nil {
|
||||
return registrytypes.AuthConfig{}, err
|
||||
return types.AuthConfig{}, err
|
||||
}
|
||||
repoInfo, err := registry.ParseRepositoryInfo(registryRef)
|
||||
if err != nil {
|
||||
return registrytypes.AuthConfig{}, err
|
||||
return types.AuthConfig{}, err
|
||||
}
|
||||
return ResolveAuthConfig(ctx, cli, repoInfo.Index), nil
|
||||
}
|
||||
|
||||
@ -10,6 +10,7 @@ import (
|
||||
"github.com/docker/cli/cli/command"
|
||||
"github.com/docker/cli/cli/command/completion"
|
||||
configtypes "github.com/docker/cli/cli/config/types"
|
||||
"github.com/docker/docker/api/types"
|
||||
registrytypes "github.com/docker/docker/api/types/registry"
|
||||
"github.com/docker/docker/client"
|
||||
"github.com/docker/docker/errdefs"
|
||||
@ -163,7 +164,7 @@ func runLogin(dockerCli command.Cli, opts loginOptions) error { //nolint:gocyclo
|
||||
return nil
|
||||
}
|
||||
|
||||
func loginWithCredStoreCreds(ctx context.Context, dockerCli command.Cli, authConfig *registrytypes.AuthConfig) (registrytypes.AuthenticateOKBody, error) {
|
||||
func loginWithCredStoreCreds(ctx context.Context, dockerCli command.Cli, authConfig *types.AuthConfig) (registrytypes.AuthenticateOKBody, error) {
|
||||
fmt.Fprintf(dockerCli.Out(), "Authenticating with existing credentials...\n")
|
||||
cliClient := dockerCli.Client()
|
||||
response, err := cliClient.RegistryLogin(ctx, *authConfig)
|
||||
@ -177,7 +178,7 @@ func loginWithCredStoreCreds(ctx context.Context, dockerCli command.Cli, authCon
|
||||
return response, err
|
||||
}
|
||||
|
||||
func loginClientSide(ctx context.Context, auth registrytypes.AuthConfig) (registrytypes.AuthenticateOKBody, error) {
|
||||
func loginClientSide(ctx context.Context, auth types.AuthConfig) (registrytypes.AuthenticateOKBody, error) {
|
||||
svc, err := registry.NewService(registry.ServiceOptions{})
|
||||
if err != nil {
|
||||
return registrytypes.AuthenticateOKBody{}, err
|
||||
|
||||
@ -34,11 +34,11 @@ type fakeClient struct {
|
||||
client.Client
|
||||
}
|
||||
|
||||
func (c fakeClient) Info(context.Context) (types.Info, error) {
|
||||
func (c fakeClient) Info(ctx context.Context) (types.Info, error) {
|
||||
return types.Info{}, nil
|
||||
}
|
||||
|
||||
func (c fakeClient) RegistryLogin(_ context.Context, auth registrytypes.AuthConfig) (registrytypes.AuthenticateOKBody, error) {
|
||||
func (c fakeClient) RegistryLogin(ctx context.Context, auth types.AuthConfig) (registrytypes.AuthenticateOKBody, error) {
|
||||
if auth.Password == expiredPassword {
|
||||
return registrytypes.AuthenticateOKBody{}, fmt.Errorf("Invalid Username or Password")
|
||||
}
|
||||
@ -53,16 +53,16 @@ func (c fakeClient) RegistryLogin(_ context.Context, auth registrytypes.AuthConf
|
||||
|
||||
func TestLoginWithCredStoreCreds(t *testing.T) {
|
||||
testCases := []struct {
|
||||
inputAuthConfig registrytypes.AuthConfig
|
||||
inputAuthConfig types.AuthConfig
|
||||
expectedMsg string
|
||||
expectedErr string
|
||||
}{
|
||||
{
|
||||
inputAuthConfig: registrytypes.AuthConfig{},
|
||||
inputAuthConfig: types.AuthConfig{},
|
||||
expectedMsg: "Authenticating with existing credentials...\n",
|
||||
},
|
||||
{
|
||||
inputAuthConfig: registrytypes.AuthConfig{
|
||||
inputAuthConfig: types.AuthConfig{
|
||||
Username: userErr,
|
||||
},
|
||||
expectedMsg: "Authenticating with existing credentials...\n",
|
||||
|
||||
@ -8,7 +8,6 @@ import (
|
||||
"github.com/docker/cli/cli/command/formatter"
|
||||
"github.com/docker/cli/opts"
|
||||
"github.com/docker/docker/api/types"
|
||||
registrytypes "github.com/docker/docker/api/types/registry"
|
||||
"github.com/docker/docker/registry"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
@ -55,19 +54,25 @@ func runSearch(dockerCli command.Cli, options searchOptions) error {
|
||||
}
|
||||
|
||||
ctx := context.Background()
|
||||
|
||||
authConfig := command.ResolveAuthConfig(ctx, dockerCli, indexInfo)
|
||||
encodedAuth, err := registrytypes.EncodeAuthConfig(authConfig)
|
||||
requestPrivilege := command.RegistryAuthenticationPrivilegedFunc(dockerCli, indexInfo, "search")
|
||||
|
||||
encodedAuth, err := command.EncodeAuthToBase64(authConfig)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
requestPrivilege := command.RegistryAuthenticationPrivilegedFunc(dockerCli, indexInfo, "search")
|
||||
results, err := dockerCli.Client().ImageSearch(ctx, options.term, types.ImageSearchOptions{
|
||||
searchOptions := types.ImageSearchOptions{
|
||||
RegistryAuth: encodedAuth,
|
||||
PrivilegeFunc: requestPrivilege,
|
||||
Filters: options.filter.Value(),
|
||||
Limit: options.limit,
|
||||
})
|
||||
}
|
||||
|
||||
clnt := dockerCli.Client()
|
||||
|
||||
results, err := clnt.ImageSearch(ctx, options.term, searchOptions)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@ -10,7 +10,6 @@ import (
|
||||
configtypes "github.com/docker/cli/cli/config/types"
|
||||
"github.com/docker/cli/internal/test"
|
||||
"github.com/docker/docker/api/types"
|
||||
"github.com/docker/docker/api/types/registry"
|
||||
"github.com/docker/docker/client"
|
||||
"gotest.tools/v3/assert"
|
||||
is "gotest.tools/v3/assert/cmp"
|
||||
@ -21,7 +20,7 @@ type fakeClient struct {
|
||||
infoFunc func() (types.Info, error)
|
||||
}
|
||||
|
||||
var testAuthConfigs = []registry.AuthConfig{
|
||||
var testAuthConfigs = []types.AuthConfig{
|
||||
{
|
||||
ServerAddress: "https://index.docker.io/v1/",
|
||||
Username: "u0",
|
||||
@ -46,13 +45,13 @@ func TestGetDefaultAuthConfig(t *testing.T) {
|
||||
checkCredStore bool
|
||||
inputServerAddress string
|
||||
expectedErr string
|
||||
expectedAuthConfig registry.AuthConfig
|
||||
expectedAuthConfig types.AuthConfig
|
||||
}{
|
||||
{
|
||||
checkCredStore: false,
|
||||
inputServerAddress: "",
|
||||
expectedErr: "",
|
||||
expectedAuthConfig: registry.AuthConfig{
|
||||
expectedAuthConfig: types.AuthConfig{
|
||||
ServerAddress: "",
|
||||
Username: "",
|
||||
Password: "",
|
||||
@ -102,7 +101,7 @@ func TestGetDefaultAuthConfig_HelperError(t *testing.T) {
|
||||
cli.SetErr(errBuf)
|
||||
cli.ConfigFile().CredentialsStore = "fake-does-not-exist"
|
||||
serverAddress := "test-server-address"
|
||||
expectedAuthConfig := registry.AuthConfig{
|
||||
expectedAuthConfig := types.AuthConfig{
|
||||
ServerAddress: serverAddress,
|
||||
}
|
||||
authconfig, err := GetDefaultAuthConfig(cli, true, serverAddress, serverAddress == "https://index.docker.io/v1/")
|
||||
|
||||
@ -10,36 +10,36 @@ import (
|
||||
|
||||
type fakeClient struct {
|
||||
client.Client
|
||||
secretCreateFunc func(context.Context, swarm.SecretSpec) (types.SecretCreateResponse, error)
|
||||
secretInspectFunc func(context.Context, string) (swarm.Secret, []byte, error)
|
||||
secretListFunc func(context.Context, types.SecretListOptions) ([]swarm.Secret, error)
|
||||
secretRemoveFunc func(context.Context, string) error
|
||||
secretCreateFunc func(swarm.SecretSpec) (types.SecretCreateResponse, error)
|
||||
secretInspectFunc func(string) (swarm.Secret, []byte, error)
|
||||
secretListFunc func(types.SecretListOptions) ([]swarm.Secret, error)
|
||||
secretRemoveFunc func(string) error
|
||||
}
|
||||
|
||||
func (c *fakeClient) SecretCreate(ctx context.Context, spec swarm.SecretSpec) (types.SecretCreateResponse, error) {
|
||||
if c.secretCreateFunc != nil {
|
||||
return c.secretCreateFunc(ctx, spec)
|
||||
return c.secretCreateFunc(spec)
|
||||
}
|
||||
return types.SecretCreateResponse{}, nil
|
||||
}
|
||||
|
||||
func (c *fakeClient) SecretInspectWithRaw(ctx context.Context, id string) (swarm.Secret, []byte, error) {
|
||||
if c.secretInspectFunc != nil {
|
||||
return c.secretInspectFunc(ctx, id)
|
||||
return c.secretInspectFunc(id)
|
||||
}
|
||||
return swarm.Secret{}, nil, nil
|
||||
}
|
||||
|
||||
func (c *fakeClient) SecretList(ctx context.Context, options types.SecretListOptions) ([]swarm.Secret, error) {
|
||||
if c.secretListFunc != nil {
|
||||
return c.secretListFunc(ctx, options)
|
||||
return c.secretListFunc(options)
|
||||
}
|
||||
return []swarm.Secret{}, nil
|
||||
}
|
||||
|
||||
func (c *fakeClient) SecretRemove(ctx context.Context, name string) error {
|
||||
if c.secretRemoveFunc != nil {
|
||||
return c.secretRemoveFunc(ctx, name)
|
||||
return c.secretRemoveFunc(name)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@ -1,7 +1,6 @@
|
||||
package secret
|
||||
|
||||
import (
|
||||
"context"
|
||||
"io"
|
||||
"os"
|
||||
"path/filepath"
|
||||
@ -22,7 +21,7 @@ const secretDataFile = "secret-create-with-name.golden"
|
||||
func TestSecretCreateErrors(t *testing.T) {
|
||||
testCases := []struct {
|
||||
args []string
|
||||
secretCreateFunc func(context.Context, swarm.SecretSpec) (types.SecretCreateResponse, error)
|
||||
secretCreateFunc func(swarm.SecretSpec) (types.SecretCreateResponse, error)
|
||||
expectedError string
|
||||
}{
|
||||
{
|
||||
@ -35,7 +34,7 @@ func TestSecretCreateErrors(t *testing.T) {
|
||||
},
|
||||
{
|
||||
args: []string{"name", filepath.Join("testdata", secretDataFile)},
|
||||
secretCreateFunc: func(_ context.Context, secretSpec swarm.SecretSpec) (types.SecretCreateResponse, error) {
|
||||
secretCreateFunc: func(secretSpec swarm.SecretSpec) (types.SecretCreateResponse, error) {
|
||||
return types.SecretCreateResponse{}, errors.Errorf("error creating secret")
|
||||
},
|
||||
expectedError: "error creating secret",
|
||||
@ -67,7 +66,7 @@ func TestSecretCreateWithName(t *testing.T) {
|
||||
}
|
||||
|
||||
cli := test.NewFakeCli(&fakeClient{
|
||||
secretCreateFunc: func(_ context.Context, spec swarm.SecretSpec) (types.SecretCreateResponse, error) {
|
||||
secretCreateFunc: func(spec swarm.SecretSpec) (types.SecretCreateResponse, error) {
|
||||
if !reflect.DeepEqual(spec, expected) {
|
||||
return types.SecretCreateResponse{}, errors.Errorf("expected %+v, got %+v", expected, spec)
|
||||
}
|
||||
@ -90,7 +89,7 @@ func TestSecretCreateWithDriver(t *testing.T) {
|
||||
name := "foo"
|
||||
|
||||
cli := test.NewFakeCli(&fakeClient{
|
||||
secretCreateFunc: func(_ context.Context, spec swarm.SecretSpec) (types.SecretCreateResponse, error) {
|
||||
secretCreateFunc: func(spec swarm.SecretSpec) (types.SecretCreateResponse, error) {
|
||||
if spec.Name != name {
|
||||
return types.SecretCreateResponse{}, errors.Errorf("expected name %q, got %q", name, spec.Name)
|
||||
}
|
||||
@ -119,7 +118,7 @@ func TestSecretCreateWithTemplatingDriver(t *testing.T) {
|
||||
name := "foo"
|
||||
|
||||
cli := test.NewFakeCli(&fakeClient{
|
||||
secretCreateFunc: func(_ context.Context, spec swarm.SecretSpec) (types.SecretCreateResponse, error) {
|
||||
secretCreateFunc: func(spec swarm.SecretSpec) (types.SecretCreateResponse, error) {
|
||||
if spec.Name != name {
|
||||
return types.SecretCreateResponse{}, errors.Errorf("expected name %q, got %q", name, spec.Name)
|
||||
}
|
||||
@ -149,7 +148,7 @@ func TestSecretCreateWithLabels(t *testing.T) {
|
||||
name := "foo"
|
||||
|
||||
cli := test.NewFakeCli(&fakeClient{
|
||||
secretCreateFunc: func(_ context.Context, spec swarm.SecretSpec) (types.SecretCreateResponse, error) {
|
||||
secretCreateFunc: func(spec swarm.SecretSpec) (types.SecretCreateResponse, error) {
|
||||
if spec.Name != name {
|
||||
return types.SecretCreateResponse{}, errors.Errorf("expected name %q, got %q", name, spec.Name)
|
||||
}
|
||||
|
||||
@ -1,7 +1,6 @@
|
||||
package secret
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"io"
|
||||
"testing"
|
||||
@ -19,7 +18,7 @@ func TestSecretInspectErrors(t *testing.T) {
|
||||
testCases := []struct {
|
||||
args []string
|
||||
flags map[string]string
|
||||
secretInspectFunc func(ctx context.Context, secretID string) (swarm.Secret, []byte, error)
|
||||
secretInspectFunc func(secretID string) (swarm.Secret, []byte, error)
|
||||
expectedError string
|
||||
}{
|
||||
{
|
||||
@ -27,7 +26,7 @@ func TestSecretInspectErrors(t *testing.T) {
|
||||
},
|
||||
{
|
||||
args: []string{"foo"},
|
||||
secretInspectFunc: func(_ context.Context, secretID string) (swarm.Secret, []byte, error) {
|
||||
secretInspectFunc: func(secretID string) (swarm.Secret, []byte, error) {
|
||||
return swarm.Secret{}, nil, errors.Errorf("error while inspecting the secret")
|
||||
},
|
||||
expectedError: "error while inspecting the secret",
|
||||
@ -41,7 +40,7 @@ func TestSecretInspectErrors(t *testing.T) {
|
||||
},
|
||||
{
|
||||
args: []string{"foo", "bar"},
|
||||
secretInspectFunc: func(_ context.Context, secretID string) (swarm.Secret, []byte, error) {
|
||||
secretInspectFunc: func(secretID string) (swarm.Secret, []byte, error) {
|
||||
if secretID == "foo" {
|
||||
return *Secret(SecretName("foo")), nil, nil
|
||||
}
|
||||
@ -69,12 +68,12 @@ func TestSecretInspectWithoutFormat(t *testing.T) {
|
||||
testCases := []struct {
|
||||
name string
|
||||
args []string
|
||||
secretInspectFunc func(ctx context.Context, secretID string) (swarm.Secret, []byte, error)
|
||||
secretInspectFunc func(secretID string) (swarm.Secret, []byte, error)
|
||||
}{
|
||||
{
|
||||
name: "single-secret",
|
||||
args: []string{"foo"},
|
||||
secretInspectFunc: func(_ context.Context, name string) (swarm.Secret, []byte, error) {
|
||||
secretInspectFunc: func(name string) (swarm.Secret, []byte, error) {
|
||||
if name != "foo" {
|
||||
return swarm.Secret{}, nil, errors.Errorf("Invalid name, expected %s, got %s", "foo", name)
|
||||
}
|
||||
@ -84,7 +83,7 @@ func TestSecretInspectWithoutFormat(t *testing.T) {
|
||||
{
|
||||
name: "multiple-secrets-with-labels",
|
||||
args: []string{"foo", "bar"},
|
||||
secretInspectFunc: func(_ context.Context, name string) (swarm.Secret, []byte, error) {
|
||||
secretInspectFunc: func(name string) (swarm.Secret, []byte, error) {
|
||||
return *Secret(SecretID("ID-"+name), SecretName(name), SecretLabels(map[string]string{
|
||||
"label1": "label-foo",
|
||||
})), nil, nil
|
||||
@ -103,7 +102,7 @@ func TestSecretInspectWithoutFormat(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestSecretInspectWithFormat(t *testing.T) {
|
||||
secretInspectFunc := func(_ context.Context, name string) (swarm.Secret, []byte, error) {
|
||||
secretInspectFunc := func(name string) (swarm.Secret, []byte, error) {
|
||||
return *Secret(SecretName("foo"), SecretLabels(map[string]string{
|
||||
"label1": "label-foo",
|
||||
})), nil, nil
|
||||
@ -112,7 +111,7 @@ func TestSecretInspectWithFormat(t *testing.T) {
|
||||
name string
|
||||
format string
|
||||
args []string
|
||||
secretInspectFunc func(_ context.Context, name string) (swarm.Secret, []byte, error)
|
||||
secretInspectFunc func(name string) (swarm.Secret, []byte, error)
|
||||
}{
|
||||
{
|
||||
name: "simple-template",
|
||||
@ -142,11 +141,11 @@ func TestSecretInspectWithFormat(t *testing.T) {
|
||||
func TestSecretInspectPretty(t *testing.T) {
|
||||
testCases := []struct {
|
||||
name string
|
||||
secretInspectFunc func(context.Context, string) (swarm.Secret, []byte, error)
|
||||
secretInspectFunc func(string) (swarm.Secret, []byte, error)
|
||||
}{
|
||||
{
|
||||
name: "simple",
|
||||
secretInspectFunc: func(_ context.Context, id string) (swarm.Secret, []byte, error) {
|
||||
secretInspectFunc: func(id string) (swarm.Secret, []byte, error) {
|
||||
return *Secret(
|
||||
SecretLabels(map[string]string{
|
||||
"lbl1": "value1",
|
||||
|
||||
@ -1,7 +1,6 @@
|
||||
package secret
|
||||
|
||||
import (
|
||||
"context"
|
||||
"io"
|
||||
"testing"
|
||||
"time"
|
||||
@ -20,7 +19,7 @@ import (
|
||||
func TestSecretListErrors(t *testing.T) {
|
||||
testCases := []struct {
|
||||
args []string
|
||||
secretListFunc func(context.Context, types.SecretListOptions) ([]swarm.Secret, error)
|
||||
secretListFunc func(types.SecretListOptions) ([]swarm.Secret, error)
|
||||
expectedError string
|
||||
}{
|
||||
{
|
||||
@ -28,7 +27,7 @@ func TestSecretListErrors(t *testing.T) {
|
||||
expectedError: "accepts no argument",
|
||||
},
|
||||
{
|
||||
secretListFunc: func(_ context.Context, options types.SecretListOptions) ([]swarm.Secret, error) {
|
||||
secretListFunc: func(options types.SecretListOptions) ([]swarm.Secret, error) {
|
||||
return []swarm.Secret{}, errors.Errorf("error listing secrets")
|
||||
},
|
||||
expectedError: "error listing secrets",
|
||||
@ -48,7 +47,7 @@ func TestSecretListErrors(t *testing.T) {
|
||||
|
||||
func TestSecretList(t *testing.T) {
|
||||
cli := test.NewFakeCli(&fakeClient{
|
||||
secretListFunc: func(_ context.Context, options types.SecretListOptions) ([]swarm.Secret, error) {
|
||||
secretListFunc: func(options types.SecretListOptions) ([]swarm.Secret, error) {
|
||||
return []swarm.Secret{
|
||||
*Secret(SecretID("ID-1-foo"),
|
||||
SecretName("1-foo"),
|
||||
@ -80,7 +79,7 @@ func TestSecretList(t *testing.T) {
|
||||
|
||||
func TestSecretListWithQuietOption(t *testing.T) {
|
||||
cli := test.NewFakeCli(&fakeClient{
|
||||
secretListFunc: func(_ context.Context, options types.SecretListOptions) ([]swarm.Secret, error) {
|
||||
secretListFunc: func(options types.SecretListOptions) ([]swarm.Secret, error) {
|
||||
return []swarm.Secret{
|
||||
*Secret(SecretID("ID-foo"), SecretName("foo")),
|
||||
*Secret(SecretID("ID-bar"), SecretName("bar"), SecretLabels(map[string]string{
|
||||
@ -97,7 +96,7 @@ func TestSecretListWithQuietOption(t *testing.T) {
|
||||
|
||||
func TestSecretListWithConfigFormat(t *testing.T) {
|
||||
cli := test.NewFakeCli(&fakeClient{
|
||||
secretListFunc: func(_ context.Context, options types.SecretListOptions) ([]swarm.Secret, error) {
|
||||
secretListFunc: func(options types.SecretListOptions) ([]swarm.Secret, error) {
|
||||
return []swarm.Secret{
|
||||
*Secret(SecretID("ID-foo"), SecretName("foo")),
|
||||
*Secret(SecretID("ID-bar"), SecretName("bar"), SecretLabels(map[string]string{
|
||||
@ -116,7 +115,7 @@ func TestSecretListWithConfigFormat(t *testing.T) {
|
||||
|
||||
func TestSecretListWithFormat(t *testing.T) {
|
||||
cli := test.NewFakeCli(&fakeClient{
|
||||
secretListFunc: func(_ context.Context, options types.SecretListOptions) ([]swarm.Secret, error) {
|
||||
secretListFunc: func(options types.SecretListOptions) ([]swarm.Secret, error) {
|
||||
return []swarm.Secret{
|
||||
*Secret(SecretID("ID-foo"), SecretName("foo")),
|
||||
*Secret(SecretID("ID-bar"), SecretName("bar"), SecretLabels(map[string]string{
|
||||
@ -133,7 +132,7 @@ func TestSecretListWithFormat(t *testing.T) {
|
||||
|
||||
func TestSecretListWithFilter(t *testing.T) {
|
||||
cli := test.NewFakeCli(&fakeClient{
|
||||
secretListFunc: func(_ context.Context, options types.SecretListOptions) ([]swarm.Secret, error) {
|
||||
secretListFunc: func(options types.SecretListOptions) ([]swarm.Secret, error) {
|
||||
assert.Check(t, is.Equal("foo", options.Filters.Get("name")[0]), "foo")
|
||||
assert.Check(t, is.Equal("lbl1=Label-bar", options.Filters.Get("label")[0]))
|
||||
return []swarm.Secret{
|
||||
|
||||
@ -1,7 +1,6 @@
|
||||
package secret
|
||||
|
||||
import (
|
||||
"context"
|
||||
"io"
|
||||
"strings"
|
||||
"testing"
|
||||
@ -15,7 +14,7 @@ import (
|
||||
func TestSecretRemoveErrors(t *testing.T) {
|
||||
testCases := []struct {
|
||||
args []string
|
||||
secretRemoveFunc func(context.Context, string) error
|
||||
secretRemoveFunc func(string) error
|
||||
expectedError string
|
||||
}{
|
||||
{
|
||||
@ -24,7 +23,7 @@ func TestSecretRemoveErrors(t *testing.T) {
|
||||
},
|
||||
{
|
||||
args: []string{"foo"},
|
||||
secretRemoveFunc: func(_ context.Context, name string) error {
|
||||
secretRemoveFunc: func(name string) error {
|
||||
return errors.Errorf("error removing secret")
|
||||
},
|
||||
expectedError: "error removing secret",
|
||||
@ -46,7 +45,7 @@ func TestSecretRemoveWithName(t *testing.T) {
|
||||
names := []string{"foo", "bar"}
|
||||
var removedSecrets []string
|
||||
cli := test.NewFakeCli(&fakeClient{
|
||||
secretRemoveFunc: func(_ context.Context, name string) error {
|
||||
secretRemoveFunc: func(name string) error {
|
||||
removedSecrets = append(removedSecrets, name)
|
||||
return nil
|
||||
},
|
||||
@ -63,7 +62,7 @@ func TestSecretRemoveContinueAfterError(t *testing.T) {
|
||||
var removedSecrets []string
|
||||
|
||||
cli := test.NewFakeCli(&fakeClient{
|
||||
secretRemoveFunc: func(_ context.Context, name string) error {
|
||||
secretRemoveFunc: func(name string) error {
|
||||
removedSecrets = append(removedSecrets, name)
|
||||
if name == "foo" {
|
||||
return errors.Errorf("error removing secret: %s", name)
|
||||
|
||||
@ -414,7 +414,7 @@ type globalProgressUpdater struct {
|
||||
done bool
|
||||
}
|
||||
|
||||
func (u *globalProgressUpdater) update(_ swarm.Service, tasks []swarm.Task, activeNodes map[string]struct{}, rollback bool) (bool, error) {
|
||||
func (u *globalProgressUpdater) update(service swarm.Service, tasks []swarm.Task, activeNodes map[string]struct{}, rollback bool) (bool, error) {
|
||||
tasksByNode := u.tasksByNode(tasks)
|
||||
|
||||
// We don't have perfect knowledge of how many nodes meet the
|
||||
|
||||
@ -504,23 +504,23 @@ type secretAPIClientMock struct {
|
||||
listResult []swarm.Secret
|
||||
}
|
||||
|
||||
func (s secretAPIClientMock) SecretList(context.Context, types.SecretListOptions) ([]swarm.Secret, error) {
|
||||
func (s secretAPIClientMock) SecretList(ctx context.Context, options types.SecretListOptions) ([]swarm.Secret, error) {
|
||||
return s.listResult, nil
|
||||
}
|
||||
|
||||
func (s secretAPIClientMock) SecretCreate(context.Context, swarm.SecretSpec) (types.SecretCreateResponse, error) {
|
||||
func (s secretAPIClientMock) SecretCreate(ctx context.Context, secret swarm.SecretSpec) (types.SecretCreateResponse, error) {
|
||||
return types.SecretCreateResponse{}, nil
|
||||
}
|
||||
|
||||
func (s secretAPIClientMock) SecretRemove(context.Context, string) error {
|
||||
func (s secretAPIClientMock) SecretRemove(ctx context.Context, id string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s secretAPIClientMock) SecretInspectWithRaw(context.Context, string) (swarm.Secret, []byte, error) {
|
||||
func (s secretAPIClientMock) SecretInspectWithRaw(ctx context.Context, name string) (swarm.Secret, []byte, error) {
|
||||
return swarm.Secret{}, []byte{}, nil
|
||||
}
|
||||
|
||||
func (s secretAPIClientMock) SecretUpdate(context.Context, string, swarm.Version, swarm.SecretSpec) error {
|
||||
func (s secretAPIClientMock) SecretUpdate(ctx context.Context, id string, version swarm.Version, secret swarm.SecretSpec) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
|
||||
@ -43,7 +43,7 @@ type fakeClient struct {
|
||||
configRemoveFunc func(configID string) error
|
||||
}
|
||||
|
||||
func (cli *fakeClient) ServerVersion(context.Context) (types.Version, error) {
|
||||
func (cli *fakeClient) ServerVersion(ctx context.Context) (types.Version, error) {
|
||||
return types.Version{
|
||||
Version: "docker-dev",
|
||||
APIVersion: api.DefaultVersion,
|
||||
@ -54,7 +54,7 @@ func (cli *fakeClient) ClientVersion() string {
|
||||
return cli.version
|
||||
}
|
||||
|
||||
func (cli *fakeClient) ServiceList(_ context.Context, options types.ServiceListOptions) ([]swarm.Service, error) {
|
||||
func (cli *fakeClient) ServiceList(ctx context.Context, options types.ServiceListOptions) ([]swarm.Service, error) {
|
||||
if cli.serviceListFunc != nil {
|
||||
return cli.serviceListFunc(options)
|
||||
}
|
||||
@ -69,7 +69,7 @@ func (cli *fakeClient) ServiceList(_ context.Context, options types.ServiceListO
|
||||
return servicesList, nil
|
||||
}
|
||||
|
||||
func (cli *fakeClient) NetworkList(_ context.Context, options types.NetworkListOptions) ([]types.NetworkResource, error) {
|
||||
func (cli *fakeClient) NetworkList(ctx context.Context, options types.NetworkListOptions) ([]types.NetworkResource, error) {
|
||||
if cli.networkListFunc != nil {
|
||||
return cli.networkListFunc(options)
|
||||
}
|
||||
@ -84,7 +84,7 @@ func (cli *fakeClient) NetworkList(_ context.Context, options types.NetworkListO
|
||||
return networksList, nil
|
||||
}
|
||||
|
||||
func (cli *fakeClient) SecretList(_ context.Context, options types.SecretListOptions) ([]swarm.Secret, error) {
|
||||
func (cli *fakeClient) SecretList(ctx context.Context, options types.SecretListOptions) ([]swarm.Secret, error) {
|
||||
if cli.secretListFunc != nil {
|
||||
return cli.secretListFunc(options)
|
||||
}
|
||||
@ -99,7 +99,7 @@ func (cli *fakeClient) SecretList(_ context.Context, options types.SecretListOpt
|
||||
return secretsList, nil
|
||||
}
|
||||
|
||||
func (cli *fakeClient) ConfigList(_ context.Context, options types.ConfigListOptions) ([]swarm.Config, error) {
|
||||
func (cli *fakeClient) ConfigList(ctx context.Context, options types.ConfigListOptions) ([]swarm.Config, error) {
|
||||
if cli.configListFunc != nil {
|
||||
return cli.configListFunc(options)
|
||||
}
|
||||
@ -114,28 +114,28 @@ func (cli *fakeClient) ConfigList(_ context.Context, options types.ConfigListOpt
|
||||
return configsList, nil
|
||||
}
|
||||
|
||||
func (cli *fakeClient) TaskList(_ context.Context, options types.TaskListOptions) ([]swarm.Task, error) {
|
||||
func (cli *fakeClient) TaskList(ctx context.Context, options types.TaskListOptions) ([]swarm.Task, error) {
|
||||
if cli.taskListFunc != nil {
|
||||
return cli.taskListFunc(options)
|
||||
}
|
||||
return []swarm.Task{}, nil
|
||||
}
|
||||
|
||||
func (cli *fakeClient) NodeList(_ context.Context, options types.NodeListOptions) ([]swarm.Node, error) {
|
||||
func (cli *fakeClient) NodeList(ctx context.Context, options types.NodeListOptions) ([]swarm.Node, error) {
|
||||
if cli.nodeListFunc != nil {
|
||||
return cli.nodeListFunc(options)
|
||||
}
|
||||
return []swarm.Node{}, nil
|
||||
}
|
||||
|
||||
func (cli *fakeClient) NodeInspectWithRaw(_ context.Context, ref string) (swarm.Node, []byte, error) {
|
||||
func (cli *fakeClient) NodeInspectWithRaw(ctx context.Context, ref string) (swarm.Node, []byte, error) {
|
||||
if cli.nodeInspectWithRaw != nil {
|
||||
return cli.nodeInspectWithRaw(ref)
|
||||
}
|
||||
return swarm.Node{}, nil, nil
|
||||
}
|
||||
|
||||
func (cli *fakeClient) ServiceUpdate(_ context.Context, serviceID string, version swarm.Version, service swarm.ServiceSpec, options types.ServiceUpdateOptions) (types.ServiceUpdateResponse, error) {
|
||||
func (cli *fakeClient) ServiceUpdate(ctx context.Context, serviceID string, version swarm.Version, service swarm.ServiceSpec, options types.ServiceUpdateOptions) (types.ServiceUpdateResponse, error) {
|
||||
if cli.serviceUpdateFunc != nil {
|
||||
return cli.serviceUpdateFunc(serviceID, version, service, options)
|
||||
}
|
||||
@ -143,7 +143,7 @@ func (cli *fakeClient) ServiceUpdate(_ context.Context, serviceID string, versio
|
||||
return types.ServiceUpdateResponse{}, nil
|
||||
}
|
||||
|
||||
func (cli *fakeClient) ServiceRemove(_ context.Context, serviceID string) error {
|
||||
func (cli *fakeClient) ServiceRemove(ctx context.Context, serviceID string) error {
|
||||
if cli.serviceRemoveFunc != nil {
|
||||
return cli.serviceRemoveFunc(serviceID)
|
||||
}
|
||||
@ -152,7 +152,7 @@ func (cli *fakeClient) ServiceRemove(_ context.Context, serviceID string) error
|
||||
return nil
|
||||
}
|
||||
|
||||
func (cli *fakeClient) NetworkRemove(_ context.Context, networkID string) error {
|
||||
func (cli *fakeClient) NetworkRemove(ctx context.Context, networkID string) error {
|
||||
if cli.networkRemoveFunc != nil {
|
||||
return cli.networkRemoveFunc(networkID)
|
||||
}
|
||||
@ -161,7 +161,7 @@ func (cli *fakeClient) NetworkRemove(_ context.Context, networkID string) error
|
||||
return nil
|
||||
}
|
||||
|
||||
func (cli *fakeClient) SecretRemove(_ context.Context, secretID string) error {
|
||||
func (cli *fakeClient) SecretRemove(ctx context.Context, secretID string) error {
|
||||
if cli.secretRemoveFunc != nil {
|
||||
return cli.secretRemoveFunc(secretID)
|
||||
}
|
||||
@ -170,7 +170,7 @@ func (cli *fakeClient) SecretRemove(_ context.Context, secretID string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (cli *fakeClient) ConfigRemove(_ context.Context, configID string) error {
|
||||
func (cli *fakeClient) ConfigRemove(ctx context.Context, configID string) error {
|
||||
if cli.configRemoveFunc != nil {
|
||||
return cli.configRemoveFunc(configID)
|
||||
}
|
||||
@ -179,7 +179,7 @@ func (cli *fakeClient) ConfigRemove(_ context.Context, configID string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (cli *fakeClient) ServiceInspectWithRaw(_ context.Context, serviceID string, _ types.ServiceInspectOptions) (swarm.Service, []byte, error) {
|
||||
func (cli *fakeClient) ServiceInspectWithRaw(ctx context.Context, serviceID string, opts types.ServiceInspectOptions) (swarm.Service, []byte, error) {
|
||||
return swarm.Service{
|
||||
ID: serviceID,
|
||||
Spec: swarm.ServiceSpec{
|
||||
|
||||
@ -28,7 +28,7 @@ func newDeployCommand(dockerCli command.Cli) *cobra.Command {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return swarm.RunDeploy(dockerCli, opts, config)
|
||||
return RunDeploy(dockerCli, cmd.Flags(), config, opts)
|
||||
},
|
||||
ValidArgsFunction: func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
|
||||
return completeNames(dockerCli)(cmd, args, toComplete)
|
||||
@ -47,9 +47,7 @@ func newDeployCommand(dockerCli command.Cli) *cobra.Command {
|
||||
return cmd
|
||||
}
|
||||
|
||||
// RunDeploy performs a stack deploy against the specified swarm cluster.
|
||||
//
|
||||
// Deprecated: use [swarm.RunDeploy] instead.
|
||||
func RunDeploy(dockerCli command.Cli, _ *pflag.FlagSet, config *composetypes.Config, opts options.Deploy) error {
|
||||
// RunDeploy performs a stack deploy against the specified swarm cluster
|
||||
func RunDeploy(dockerCli command.Cli, flags *pflag.FlagSet, config *composetypes.Config, opts options.Deploy) error {
|
||||
return swarm.RunDeploy(dockerCli, opts, config)
|
||||
}
|
||||
|
||||
@ -23,7 +23,7 @@ func newListCommand(dockerCli command.Cli) *cobra.Command {
|
||||
Short: "List stacks",
|
||||
Args: cli.NoArgs,
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
return RunList(dockerCli, opts)
|
||||
return RunList(cmd, dockerCli, opts)
|
||||
},
|
||||
ValidArgsFunction: completion.NoComplete,
|
||||
}
|
||||
@ -34,24 +34,24 @@ func newListCommand(dockerCli command.Cli) *cobra.Command {
|
||||
}
|
||||
|
||||
// RunList performs a stack list against the specified swarm cluster
|
||||
func RunList(dockerCli command.Cli, opts options.List) error {
|
||||
func RunList(cmd *cobra.Command, dockerCli command.Cli, opts options.List) error {
|
||||
stacks := []*formatter.Stack{}
|
||||
ss, err := swarm.GetStacks(dockerCli)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
stacks := make([]*formatter.Stack, 0, len(ss))
|
||||
stacks = append(stacks, ss...)
|
||||
return format(dockerCli, opts, stacks)
|
||||
}
|
||||
|
||||
func format(dockerCli command.Cli, opts options.List, stacks []*formatter.Stack) error {
|
||||
fmt := formatter.Format(opts.Format)
|
||||
if fmt == "" || fmt == formatter.TableFormatKey {
|
||||
fmt = formatter.SwarmStackTableFormat
|
||||
format := formatter.Format(opts.Format)
|
||||
if format == "" || format == formatter.TableFormatKey {
|
||||
format = formatter.SwarmStackTableFormat
|
||||
}
|
||||
stackCtx := formatter.Context{
|
||||
Output: dockerCli.Out(),
|
||||
Format: fmt,
|
||||
Format: format,
|
||||
}
|
||||
sort.Slice(stacks, func(i, j int) bool {
|
||||
return sortorder.NaturalLess(stacks[i].Name, stacks[j].Name) ||
|
||||
|
||||
@ -23,7 +23,7 @@ func newPsCommand(dockerCli command.Cli) *cobra.Command {
|
||||
if err := validateStackName(opts.Namespace); err != nil {
|
||||
return err
|
||||
}
|
||||
return swarm.RunPS(dockerCli, opts)
|
||||
return RunPs(dockerCli, cmd.Flags(), opts)
|
||||
},
|
||||
ValidArgsFunction: func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
|
||||
return completeNames(dockerCli)(cmd, args, toComplete)
|
||||
@ -38,9 +38,7 @@ func newPsCommand(dockerCli command.Cli) *cobra.Command {
|
||||
return cmd
|
||||
}
|
||||
|
||||
// RunPs performs a stack ps against the specified swarm cluster.
|
||||
//
|
||||
// Deprecated: use [swarm.RunPS] instead.
|
||||
func RunPs(dockerCli command.Cli, _ *pflag.FlagSet, opts options.PS) error {
|
||||
// RunPs performs a stack ps against the specified swarm cluster
|
||||
func RunPs(dockerCli command.Cli, flags *pflag.FlagSet, opts options.PS) error {
|
||||
return swarm.RunPS(dockerCli, opts)
|
||||
}
|
||||
|
||||
@ -22,7 +22,7 @@ func newRemoveCommand(dockerCli command.Cli) *cobra.Command {
|
||||
if err := validateStackNames(opts.Namespaces); err != nil {
|
||||
return err
|
||||
}
|
||||
return swarm.RunRemove(dockerCli, opts)
|
||||
return RunRemove(dockerCli, cmd.Flags(), opts)
|
||||
},
|
||||
ValidArgsFunction: func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
|
||||
return completeNames(dockerCli)(cmd, args, toComplete)
|
||||
@ -31,9 +31,7 @@ func newRemoveCommand(dockerCli command.Cli) *cobra.Command {
|
||||
return cmd
|
||||
}
|
||||
|
||||
// RunRemove performs a stack remove against the specified swarm cluster.
|
||||
//
|
||||
// Deprecated: use [swarm.RunRemove] instead.
|
||||
func RunRemove(dockerCli command.Cli, _ *pflag.FlagSet, opts options.Remove) error {
|
||||
// RunRemove performs a stack remove against the specified swarm cluster
|
||||
func RunRemove(dockerCli command.Cli, flags *pflag.FlagSet, opts options.Remove) error {
|
||||
return swarm.RunRemove(dockerCli, opts)
|
||||
}
|
||||
|
||||
@ -30,7 +30,7 @@ func newServicesCommand(dockerCli command.Cli) *cobra.Command {
|
||||
if err := validateStackName(opts.Namespace); err != nil {
|
||||
return err
|
||||
}
|
||||
return RunServices(dockerCli, opts)
|
||||
return RunServices(dockerCli, cmd.Flags(), opts)
|
||||
},
|
||||
ValidArgsFunction: func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
|
||||
return completeNames(dockerCli)(cmd, args, toComplete)
|
||||
@ -44,18 +44,16 @@ func newServicesCommand(dockerCli command.Cli) *cobra.Command {
|
||||
}
|
||||
|
||||
// RunServices performs a stack services against the specified swarm cluster
|
||||
func RunServices(dockerCli command.Cli, opts options.Services) error {
|
||||
services, err := swarm.GetServices(dockerCli, opts)
|
||||
func RunServices(dockerCli command.Cli, flags *pflag.FlagSet, opts options.Services) error {
|
||||
services, err := GetServices(dockerCli, flags, opts)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return formatWrite(dockerCli, services, opts)
|
||||
}
|
||||
|
||||
// GetServices returns the services for the specified swarm cluster.
|
||||
//
|
||||
// Deprecated: use [swarm.GetServices] instead.
|
||||
func GetServices(dockerCli command.Cli, _ *pflag.FlagSet, opts options.Services) ([]swarmtypes.Service, error) {
|
||||
// GetServices returns the services for the specified swarm cluster
|
||||
func GetServices(dockerCli command.Cli, flags *pflag.FlagSet, opts options.Services) ([]swarmtypes.Service, error) {
|
||||
return swarm.GetServices(dockerCli, opts)
|
||||
}
|
||||
|
||||
|
||||
@ -43,7 +43,7 @@ type fakeClient struct {
|
||||
configRemoveFunc func(configID string) error
|
||||
}
|
||||
|
||||
func (cli *fakeClient) ServerVersion(context.Context) (types.Version, error) {
|
||||
func (cli *fakeClient) ServerVersion(ctx context.Context) (types.Version, error) {
|
||||
return types.Version{
|
||||
Version: "docker-dev",
|
||||
APIVersion: api.DefaultVersion,
|
||||
@ -54,7 +54,7 @@ func (cli *fakeClient) ClientVersion() string {
|
||||
return cli.version
|
||||
}
|
||||
|
||||
func (cli *fakeClient) ServiceList(_ context.Context, options types.ServiceListOptions) ([]swarm.Service, error) {
|
||||
func (cli *fakeClient) ServiceList(ctx context.Context, options types.ServiceListOptions) ([]swarm.Service, error) {
|
||||
if cli.serviceListFunc != nil {
|
||||
return cli.serviceListFunc(options)
|
||||
}
|
||||
@ -69,7 +69,7 @@ func (cli *fakeClient) ServiceList(_ context.Context, options types.ServiceListO
|
||||
return servicesList, nil
|
||||
}
|
||||
|
||||
func (cli *fakeClient) NetworkList(_ context.Context, options types.NetworkListOptions) ([]types.NetworkResource, error) {
|
||||
func (cli *fakeClient) NetworkList(ctx context.Context, options types.NetworkListOptions) ([]types.NetworkResource, error) {
|
||||
if cli.networkListFunc != nil {
|
||||
return cli.networkListFunc(options)
|
||||
}
|
||||
@ -84,7 +84,7 @@ func (cli *fakeClient) NetworkList(_ context.Context, options types.NetworkListO
|
||||
return networksList, nil
|
||||
}
|
||||
|
||||
func (cli *fakeClient) SecretList(_ context.Context, options types.SecretListOptions) ([]swarm.Secret, error) {
|
||||
func (cli *fakeClient) SecretList(ctx context.Context, options types.SecretListOptions) ([]swarm.Secret, error) {
|
||||
if cli.secretListFunc != nil {
|
||||
return cli.secretListFunc(options)
|
||||
}
|
||||
@ -99,7 +99,7 @@ func (cli *fakeClient) SecretList(_ context.Context, options types.SecretListOpt
|
||||
return secretsList, nil
|
||||
}
|
||||
|
||||
func (cli *fakeClient) ConfigList(_ context.Context, options types.ConfigListOptions) ([]swarm.Config, error) {
|
||||
func (cli *fakeClient) ConfigList(ctx context.Context, options types.ConfigListOptions) ([]swarm.Config, error) {
|
||||
if cli.configListFunc != nil {
|
||||
return cli.configListFunc(options)
|
||||
}
|
||||
@ -114,28 +114,28 @@ func (cli *fakeClient) ConfigList(_ context.Context, options types.ConfigListOpt
|
||||
return configsList, nil
|
||||
}
|
||||
|
||||
func (cli *fakeClient) TaskList(_ context.Context, options types.TaskListOptions) ([]swarm.Task, error) {
|
||||
func (cli *fakeClient) TaskList(ctx context.Context, options types.TaskListOptions) ([]swarm.Task, error) {
|
||||
if cli.taskListFunc != nil {
|
||||
return cli.taskListFunc(options)
|
||||
}
|
||||
return []swarm.Task{}, nil
|
||||
}
|
||||
|
||||
func (cli *fakeClient) NodeList(_ context.Context, options types.NodeListOptions) ([]swarm.Node, error) {
|
||||
func (cli *fakeClient) NodeList(ctx context.Context, options types.NodeListOptions) ([]swarm.Node, error) {
|
||||
if cli.nodeListFunc != nil {
|
||||
return cli.nodeListFunc(options)
|
||||
}
|
||||
return []swarm.Node{}, nil
|
||||
}
|
||||
|
||||
func (cli *fakeClient) NodeInspectWithRaw(_ context.Context, ref string) (swarm.Node, []byte, error) {
|
||||
func (cli *fakeClient) NodeInspectWithRaw(ctx context.Context, ref string) (swarm.Node, []byte, error) {
|
||||
if cli.nodeInspectWithRaw != nil {
|
||||
return cli.nodeInspectWithRaw(ref)
|
||||
}
|
||||
return swarm.Node{}, nil, nil
|
||||
}
|
||||
|
||||
func (cli *fakeClient) ServiceUpdate(_ context.Context, serviceID string, version swarm.Version, service swarm.ServiceSpec, options types.ServiceUpdateOptions) (types.ServiceUpdateResponse, error) {
|
||||
func (cli *fakeClient) ServiceUpdate(ctx context.Context, serviceID string, version swarm.Version, service swarm.ServiceSpec, options types.ServiceUpdateOptions) (types.ServiceUpdateResponse, error) {
|
||||
if cli.serviceUpdateFunc != nil {
|
||||
return cli.serviceUpdateFunc(serviceID, version, service, options)
|
||||
}
|
||||
@ -143,7 +143,7 @@ func (cli *fakeClient) ServiceUpdate(_ context.Context, serviceID string, versio
|
||||
return types.ServiceUpdateResponse{}, nil
|
||||
}
|
||||
|
||||
func (cli *fakeClient) ServiceRemove(_ context.Context, serviceID string) error {
|
||||
func (cli *fakeClient) ServiceRemove(ctx context.Context, serviceID string) error {
|
||||
if cli.serviceRemoveFunc != nil {
|
||||
return cli.serviceRemoveFunc(serviceID)
|
||||
}
|
||||
@ -152,7 +152,7 @@ func (cli *fakeClient) ServiceRemove(_ context.Context, serviceID string) error
|
||||
return nil
|
||||
}
|
||||
|
||||
func (cli *fakeClient) NetworkRemove(_ context.Context, networkID string) error {
|
||||
func (cli *fakeClient) NetworkRemove(ctx context.Context, networkID string) error {
|
||||
if cli.networkRemoveFunc != nil {
|
||||
return cli.networkRemoveFunc(networkID)
|
||||
}
|
||||
@ -161,7 +161,7 @@ func (cli *fakeClient) NetworkRemove(_ context.Context, networkID string) error
|
||||
return nil
|
||||
}
|
||||
|
||||
func (cli *fakeClient) SecretRemove(_ context.Context, secretID string) error {
|
||||
func (cli *fakeClient) SecretRemove(ctx context.Context, secretID string) error {
|
||||
if cli.secretRemoveFunc != nil {
|
||||
return cli.secretRemoveFunc(secretID)
|
||||
}
|
||||
@ -170,7 +170,7 @@ func (cli *fakeClient) SecretRemove(_ context.Context, secretID string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (cli *fakeClient) ConfigRemove(_ context.Context, configID string) error {
|
||||
func (cli *fakeClient) ConfigRemove(ctx context.Context, configID string) error {
|
||||
if cli.configRemoveFunc != nil {
|
||||
return cli.configRemoveFunc(configID)
|
||||
}
|
||||
|
||||
@ -1,32 +1,23 @@
|
||||
package command
|
||||
|
||||
import (
|
||||
"io"
|
||||
|
||||
"github.com/docker/cli/cli/streams"
|
||||
)
|
||||
|
||||
// InStream is an input stream used by the DockerCli to read user input
|
||||
//
|
||||
// Deprecated: Use [streams.In] instead.
|
||||
// Deprecated: Use github.com/docker/cli/cli/streams.In instead
|
||||
type InStream = streams.In
|
||||
|
||||
// OutStream is an output stream used by the DockerCli to write normal program
|
||||
// output.
|
||||
//
|
||||
// Deprecated: Use [streams.Out] instead.
|
||||
// Deprecated: Use github.com/docker/cli/cli/streams.Out instead
|
||||
type OutStream = streams.Out
|
||||
|
||||
// NewInStream returns a new [streams.In] from an [io.ReadCloser].
|
||||
//
|
||||
// Deprecated: Use [streams.NewIn] instead.
|
||||
func NewInStream(in io.ReadCloser) *streams.In {
|
||||
return streams.NewIn(in)
|
||||
}
|
||||
|
||||
// NewOutStream returns a new [streams.Out] from an [io.Writer].
|
||||
//
|
||||
// Deprecated: Use [streams.NewOut] instead.
|
||||
func NewOutStream(out io.Writer) *streams.Out {
|
||||
return streams.NewOut(out)
|
||||
}
|
||||
var (
|
||||
// NewInStream returns a new InStream object from a ReadCloser
|
||||
// Deprecated: Use github.com/docker/cli/cli/streams.NewIn instead
|
||||
NewInStream = streams.NewIn
|
||||
// NewOutStream returns a new OutStream object from a Writer
|
||||
// Deprecated: Use github.com/docker/cli/cli/streams.NewOut instead
|
||||
NewOutStream = streams.NewOut
|
||||
)
|
||||
|
||||
@ -21,63 +21,63 @@ type fakeClient struct {
|
||||
swarmUnlockFunc func(req swarm.UnlockRequest) error
|
||||
}
|
||||
|
||||
func (cli *fakeClient) Info(context.Context) (types.Info, error) {
|
||||
func (cli *fakeClient) Info(ctx context.Context) (types.Info, error) {
|
||||
if cli.infoFunc != nil {
|
||||
return cli.infoFunc()
|
||||
}
|
||||
return types.Info{}, nil
|
||||
}
|
||||
|
||||
func (cli *fakeClient) NodeInspectWithRaw(context.Context, string) (swarm.Node, []byte, error) {
|
||||
func (cli *fakeClient) NodeInspectWithRaw(ctx context.Context, ref string) (swarm.Node, []byte, error) {
|
||||
if cli.nodeInspectFunc != nil {
|
||||
return cli.nodeInspectFunc()
|
||||
}
|
||||
return swarm.Node{}, []byte{}, nil
|
||||
}
|
||||
|
||||
func (cli *fakeClient) SwarmInit(context.Context, swarm.InitRequest) (string, error) {
|
||||
func (cli *fakeClient) SwarmInit(ctx context.Context, req swarm.InitRequest) (string, error) {
|
||||
if cli.swarmInitFunc != nil {
|
||||
return cli.swarmInitFunc()
|
||||
}
|
||||
return "", nil
|
||||
}
|
||||
|
||||
func (cli *fakeClient) SwarmInspect(context.Context) (swarm.Swarm, error) {
|
||||
func (cli *fakeClient) SwarmInspect(ctx context.Context) (swarm.Swarm, error) {
|
||||
if cli.swarmInspectFunc != nil {
|
||||
return cli.swarmInspectFunc()
|
||||
}
|
||||
return swarm.Swarm{}, nil
|
||||
}
|
||||
|
||||
func (cli *fakeClient) SwarmGetUnlockKey(context.Context) (types.SwarmUnlockKeyResponse, error) {
|
||||
func (cli *fakeClient) SwarmGetUnlockKey(ctx context.Context) (types.SwarmUnlockKeyResponse, error) {
|
||||
if cli.swarmGetUnlockKeyFunc != nil {
|
||||
return cli.swarmGetUnlockKeyFunc()
|
||||
}
|
||||
return types.SwarmUnlockKeyResponse{}, nil
|
||||
}
|
||||
|
||||
func (cli *fakeClient) SwarmJoin(context.Context, swarm.JoinRequest) error {
|
||||
func (cli *fakeClient) SwarmJoin(ctx context.Context, req swarm.JoinRequest) error {
|
||||
if cli.swarmJoinFunc != nil {
|
||||
return cli.swarmJoinFunc()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (cli *fakeClient) SwarmLeave(context.Context, bool) error {
|
||||
func (cli *fakeClient) SwarmLeave(ctx context.Context, force bool) error {
|
||||
if cli.swarmLeaveFunc != nil {
|
||||
return cli.swarmLeaveFunc()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (cli *fakeClient) SwarmUpdate(_ context.Context, _ swarm.Version, swarm swarm.Spec, flags swarm.UpdateFlags) error {
|
||||
func (cli *fakeClient) SwarmUpdate(ctx context.Context, version swarm.Version, swarm swarm.Spec, flags swarm.UpdateFlags) error {
|
||||
if cli.swarmUpdateFunc != nil {
|
||||
return cli.swarmUpdateFunc(swarm, flags)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (cli *fakeClient) SwarmUnlock(_ context.Context, req swarm.UnlockRequest) error {
|
||||
func (cli *fakeClient) SwarmUnlock(ctx context.Context, req swarm.UnlockRequest) error {
|
||||
if cli.swarmUnlockFunc != nil {
|
||||
return cli.swarmUnlockFunc(req)
|
||||
}
|
||||
|
||||
@ -10,7 +10,7 @@ import (
|
||||
)
|
||||
|
||||
// Helper function to set static slices
|
||||
func getCIDR(_ net.IP, cidr *net.IPNet, _ error) net.IPNet {
|
||||
func getCIDR(ip net.IP, cidr *net.IPNet, err error) net.IPNet {
|
||||
return *cidr
|
||||
}
|
||||
|
||||
|
||||
@ -12,9 +12,7 @@ import (
|
||||
pluginmanager "github.com/docker/cli/cli-plugins/manager"
|
||||
"github.com/docker/cli/cli/command"
|
||||
"github.com/docker/cli/cli/command/completion"
|
||||
"github.com/docker/cli/cli/command/formatter"
|
||||
"github.com/docker/cli/cli/debug"
|
||||
flagsHelper "github.com/docker/cli/cli/flags"
|
||||
"github.com/docker/cli/templates"
|
||||
"github.com/docker/docker/api/types"
|
||||
"github.com/docker/docker/api/types/swarm"
|
||||
@ -28,8 +26,8 @@ type infoOptions struct {
|
||||
}
|
||||
|
||||
type clientInfo struct {
|
||||
Debug bool
|
||||
clientVersion
|
||||
Debug bool
|
||||
Context string
|
||||
Plugins []pluginmanager.Plugin
|
||||
Warnings []string
|
||||
}
|
||||
@ -46,13 +44,6 @@ type info struct {
|
||||
ClientErrors []string `json:",omitempty"`
|
||||
}
|
||||
|
||||
func (i *info) clientPlatform() string {
|
||||
if i.ClientInfo != nil && i.ClientInfo.Platform != nil {
|
||||
return i.ClientInfo.Platform.Name
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
// NewInfoCommand creates a new cobra.Command for `docker info`
|
||||
func NewInfoCommand(dockerCli command.Cli) *cobra.Command {
|
||||
var opts infoOptions
|
||||
@ -71,18 +62,18 @@ func NewInfoCommand(dockerCli command.Cli) *cobra.Command {
|
||||
ValidArgsFunction: completion.NoComplete,
|
||||
}
|
||||
|
||||
cmd.Flags().StringVarP(&opts.format, "format", "f", "", flagsHelper.InspectFormatHelp)
|
||||
flags := cmd.Flags()
|
||||
|
||||
flags.StringVarP(&opts.format, "format", "f", "", "Format the output using the given Go template")
|
||||
|
||||
return cmd
|
||||
}
|
||||
|
||||
func runInfo(cmd *cobra.Command, dockerCli command.Cli, opts *infoOptions) error {
|
||||
info := info{
|
||||
ClientInfo: &clientInfo{
|
||||
// Don't pass a dockerCLI to newClientVersion(), because we currently
|
||||
// don't include negotiated API version, and want to avoid making an
|
||||
// API connection when only printing the Client section.
|
||||
clientVersion: newClientVersion(dockerCli.CurrentContext(), nil),
|
||||
Debug: debug.IsEnabled(),
|
||||
Context: dockerCli.CurrentContext(),
|
||||
Debug: debug.IsEnabled(),
|
||||
},
|
||||
Info: &types.Info{},
|
||||
}
|
||||
@ -157,12 +148,7 @@ func needsServerInfo(template string, info info) bool {
|
||||
}
|
||||
|
||||
func prettyPrintInfo(dockerCli command.Cli, info info) error {
|
||||
// Only append the platform info if it's not empty, to prevent printing a trailing space.
|
||||
if p := info.clientPlatform(); p != "" {
|
||||
_, _ = fmt.Fprintln(dockerCli.Out(), "Client:", p)
|
||||
} else {
|
||||
_, _ = fmt.Fprintln(dockerCli.Out(), "Client:")
|
||||
}
|
||||
fmt.Fprintln(dockerCli.Out(), "Client:")
|
||||
if info.ClientInfo != nil {
|
||||
prettyPrintClientInfo(dockerCli, *info.ClientInfo)
|
||||
}
|
||||
@ -188,7 +174,6 @@ func prettyPrintInfo(dockerCli command.Cli, info info) error {
|
||||
}
|
||||
|
||||
func prettyPrintClientInfo(dockerCli command.Cli, info clientInfo) {
|
||||
fprintlnNonEmpty(dockerCli.Out(), " Version: ", info.Version)
|
||||
fmt.Fprintln(dockerCli.Out(), " Context: ", info.Context)
|
||||
fmt.Fprintln(dockerCli.Out(), " Debug Mode:", info.Debug)
|
||||
|
||||
@ -324,6 +309,7 @@ func prettyPrintServerInfo(dockerCli command.Cli, info types.Info) []error {
|
||||
if len(u) > 0 {
|
||||
fmt.Fprintln(dockerCli.Out(), " Username:", u)
|
||||
}
|
||||
fmt.Fprintln(dockerCli.Out(), " Registry:", info.IndexServerAddress)
|
||||
}
|
||||
|
||||
if len(info.Labels) > 0 {
|
||||
@ -521,10 +507,6 @@ func printServerWarningsLegacy(dockerCli command.Cli, info types.Info) {
|
||||
}
|
||||
|
||||
func formatInfo(dockerCli command.Cli, info info, format string) error {
|
||||
if format == formatter.JSONFormatKey {
|
||||
format = formatter.JSONFormat
|
||||
}
|
||||
|
||||
// Ensure slice/array fields render as `[]` not `null`
|
||||
if info.ClientInfo != nil && info.ClientInfo.Plugins == nil {
|
||||
info.ClientInfo.Plugins = make([]pluginmanager.Plugin, 0)
|
||||
|
||||
@ -278,12 +278,8 @@ func TestPrettyPrintInfo(t *testing.T) {
|
||||
dockerInfo: info{
|
||||
Info: &sampleInfoNoSwarm,
|
||||
ClientInfo: &clientInfo{
|
||||
clientVersion: clientVersion{
|
||||
Platform: &platformInfo{Name: "Docker Engine - Community"},
|
||||
Version: "24.0.0",
|
||||
Context: "default",
|
||||
},
|
||||
Debug: true,
|
||||
Context: "default",
|
||||
Debug: true,
|
||||
},
|
||||
},
|
||||
prettyGolden: "docker-info-no-swarm",
|
||||
@ -294,8 +290,8 @@ func TestPrettyPrintInfo(t *testing.T) {
|
||||
dockerInfo: info{
|
||||
Info: &sampleInfoNoSwarm,
|
||||
ClientInfo: &clientInfo{
|
||||
clientVersion: clientVersion{Context: "default"},
|
||||
Plugins: samplePluginsInfo,
|
||||
Context: "default",
|
||||
Plugins: samplePluginsInfo,
|
||||
},
|
||||
},
|
||||
prettyGolden: "docker-info-plugins",
|
||||
@ -306,7 +302,7 @@ func TestPrettyPrintInfo(t *testing.T) {
|
||||
doc: "info with nil labels",
|
||||
dockerInfo: info{
|
||||
Info: &sampleInfoLabelsNil,
|
||||
ClientInfo: &clientInfo{clientVersion: clientVersion{Context: "default"}},
|
||||
ClientInfo: &clientInfo{Context: "default"},
|
||||
},
|
||||
prettyGolden: "docker-info-with-labels-nil",
|
||||
},
|
||||
@ -314,7 +310,7 @@ func TestPrettyPrintInfo(t *testing.T) {
|
||||
doc: "info with empty labels",
|
||||
dockerInfo: info{
|
||||
Info: &sampleInfoLabelsEmpty,
|
||||
ClientInfo: &clientInfo{clientVersion: clientVersion{Context: "default"}},
|
||||
ClientInfo: &clientInfo{Context: "default"},
|
||||
},
|
||||
prettyGolden: "docker-info-with-labels-empty",
|
||||
},
|
||||
@ -323,8 +319,8 @@ func TestPrettyPrintInfo(t *testing.T) {
|
||||
dockerInfo: info{
|
||||
Info: &infoWithSwarm,
|
||||
ClientInfo: &clientInfo{
|
||||
clientVersion: clientVersion{Context: "default"},
|
||||
Debug: false,
|
||||
Context: "default",
|
||||
Debug: false,
|
||||
},
|
||||
},
|
||||
prettyGolden: "docker-info-with-swarm",
|
||||
@ -335,12 +331,8 @@ func TestPrettyPrintInfo(t *testing.T) {
|
||||
dockerInfo: info{
|
||||
Info: &infoWithWarningsLinux,
|
||||
ClientInfo: &clientInfo{
|
||||
clientVersion: clientVersion{
|
||||
Platform: &platformInfo{Name: "Docker Engine - Community"},
|
||||
Version: "24.0.0",
|
||||
Context: "default",
|
||||
},
|
||||
Debug: true,
|
||||
Context: "default",
|
||||
Debug: true,
|
||||
},
|
||||
},
|
||||
prettyGolden: "docker-info-no-swarm",
|
||||
@ -352,12 +344,8 @@ func TestPrettyPrintInfo(t *testing.T) {
|
||||
dockerInfo: info{
|
||||
Info: &sampleInfoDaemonWarnings,
|
||||
ClientInfo: &clientInfo{
|
||||
clientVersion: clientVersion{
|
||||
Platform: &platformInfo{Name: "Docker Engine - Community"},
|
||||
Version: "24.0.0",
|
||||
Context: "default",
|
||||
},
|
||||
Debug: true,
|
||||
Context: "default",
|
||||
Debug: true,
|
||||
},
|
||||
},
|
||||
prettyGolden: "docker-info-no-swarm",
|
||||
@ -388,7 +376,6 @@ func TestPrettyPrintInfo(t *testing.T) {
|
||||
expectedError: "errors pretty printing info",
|
||||
},
|
||||
} {
|
||||
tc := tc
|
||||
t.Run(tc.doc, func(t *testing.T) {
|
||||
cli := test.NewFakeCli(&fakeClient{})
|
||||
err := prettyPrintInfo(cli, tc.dockerInfo)
|
||||
@ -409,11 +396,6 @@ func TestPrettyPrintInfo(t *testing.T) {
|
||||
assert.NilError(t, formatInfo(cli, tc.dockerInfo, "{{json .}}"))
|
||||
golden.Assert(t, cli.OutBuffer().String(), tc.jsonGolden+".json.golden")
|
||||
assert.Check(t, is.Equal("", cli.ErrBuffer().String()))
|
||||
|
||||
cli = test.NewFakeCli(&fakeClient{})
|
||||
assert.NilError(t, formatInfo(cli, tc.dockerInfo, "json"))
|
||||
golden.Assert(t, cli.OutBuffer().String(), tc.jsonGolden+".json.golden")
|
||||
assert.Check(t, is.Equal("", cli.ErrBuffer().String()))
|
||||
}
|
||||
})
|
||||
}
|
||||
@ -442,7 +424,6 @@ func TestFormatInfo(t *testing.T) {
|
||||
expectedError: `template: :1:2: executing "" at <.badString>: can't evaluate field badString in type system.info`,
|
||||
},
|
||||
} {
|
||||
tc := tc
|
||||
t.Run(tc.doc, func(t *testing.T) {
|
||||
cli := test.NewFakeCli(&fakeClient{})
|
||||
info := info{
|
||||
|
||||
@ -1 +0,0 @@
|
||||
{"Client":{"Version":"18.99.5-ce","ApiVersion":"1.38","DefaultAPIVersion":"1.38","GitCommit":"deadbeef","GoVersion":"go1.10.2","Os":"linux","Arch":"amd64","BuildTime":"Wed May 30 22:21:05 2018","Context":"my-context"},"Server":{"Platform":{"Name":"Docker Enterprise Edition (EE) 2.0"},"Components":[{"Name":"Engine","Version":"17.06.2-ee-15","Details":{"ApiVersion":"1.30","Arch":"amd64","BuildTime":"Mon Jul 9 23:38:38 2018","Experimental":"false","GitCommit":"64ddfa6","GoVersion":"go1.8.7","MinAPIVersion":"1.12","Os":"linux"}},{"Name":"Universal Control Plane","Version":"17.06.2-ee-15","Details":{"ApiVersion":"1.30","Arch":"amd64","BuildTime":"Mon Jul 2 21:24:07 UTC 2018","GitCommit":"4513922","GoVersion":"go1.9.4","MinApiVersion":"1.20","Os":"linux","Version":"3.0.3-tp2"}},{"Name":"Kubernetes","Version":"1.8+","Details":{"buildDate":"2018-04-26T16:51:21Z","compiler":"gc","gitCommit":"8d637aedf46b9c21dde723e29c645b9f27106fa5","gitTreeState":"clean","gitVersion":"v1.8.11-docker-8d637ae","goVersion":"go1.8.3","major":"1","minor":"8+","platform":"linux/amd64"}},{"Name":"Calico","Version":"v3.0.8","Details":{"cni":"v2.0.6","kube-controllers":"v2.0.5","node":"v3.0.8"}}],"Version":"","ApiVersion":"","GitCommit":"","GoVersion":"","Os":"","Arch":""}}
|
||||
@ -41,6 +41,7 @@ Server:
|
||||
Goroutines: 135
|
||||
System Time: 2017-08-24T17:44:34.077811894Z
|
||||
EventsListeners: 0
|
||||
Registry: https://index.docker.io/v1/
|
||||
Labels:
|
||||
provider=digitalocean
|
||||
Experimental: false
|
||||
|
||||
@ -1 +1 @@
|
||||
{"ID":"EKHL:QDUU:QZ7U:MKGD:VDXK:S27Q:GIPU:24B7:R7VT:DGN6:QCSF:2UBX","Containers":0,"ContainersRunning":0,"ContainersPaused":0,"ContainersStopped":0,"Images":0,"Driver":"aufs","DriverStatus":[["Root Dir","/var/lib/docker/aufs"],["Backing Filesystem","extfs"],["Dirs","0"],["Dirperm1 Supported","true"]],"Plugins":{"Volume":["local"],"Network":["bridge","host","macvlan","null","overlay"],"Authorization":null,"Log":["awslogs","fluentd","gcplogs","gelf","journald","json-file","logentries","splunk","syslog"]},"MemoryLimit":true,"SwapLimit":true,"KernelMemory":true,"CpuCfsPeriod":true,"CpuCfsQuota":true,"CPUShares":true,"CPUSet":true,"PidsLimit":false,"IPv4Forwarding":true,"BridgeNfIptables":true,"BridgeNfIp6tables":true,"Debug":true,"NFd":33,"OomKillDisable":true,"NGoroutines":135,"SystemTime":"2017-08-24T17:44:34.077811894Z","LoggingDriver":"json-file","CgroupDriver":"cgroupfs","NEventsListener":0,"KernelVersion":"4.4.0-87-generic","OperatingSystem":"Ubuntu 16.04.3 LTS","OSVersion":"","OSType":"linux","Architecture":"x86_64","IndexServerAddress":"https://index.docker.io/v1/","RegistryConfig":{"AllowNondistributableArtifactsCIDRs":null,"AllowNondistributableArtifactsHostnames":null,"InsecureRegistryCIDRs":["127.0.0.0/8"],"IndexConfigs":{"docker.io":{"Name":"docker.io","Mirrors":null,"Secure":true,"Official":true}},"Mirrors":null},"NCPU":2,"MemTotal":2097356800,"GenericResources":null,"DockerRootDir":"/var/lib/docker","HttpProxy":"","HttpsProxy":"","NoProxy":"","Name":"system-sample","Labels":["provider=digitalocean"],"ExperimentalBuild":false,"ServerVersion":"17.06.1-ce","Runtimes":{"runc":{"path":"docker-runc"}},"DefaultRuntime":"runc","Swarm":{"NodeID":"","NodeAddr":"","LocalNodeState":"inactive","ControlAvailable":false,"Error":"","RemoteManagers":null},"LiveRestoreEnabled":false,"Isolation":"","InitBinary":"docker-init","ContainerdCommit":{"ID":"6e23458c129b551d5c9871e5174f6b1b7f6d1170","Expected":"6e23458c129b551d5c9871e5174f6b1b7f6d1170"},"RuncCommit":{"ID":"810190ceaa507aa2727d7ae6f4790c76ec150bd2","Expected":"810190ceaa507aa2727d7ae6f4790c76ec150bd2"},"InitCommit":{"ID":"949e6fa","Expected":"949e6fa"},"SecurityOptions":["name=apparmor","name=seccomp,profile=default"],"DefaultAddressPools":[{"Base":"10.123.0.0/16","Size":24}],"Warnings":["WARNING: No memory limit support","WARNING: No swap limit support","WARNING: No oom kill disable support","WARNING: No cpu cfs quota support","WARNING: No cpu cfs period support","WARNING: No cpu shares support","WARNING: No cpuset support","WARNING: IPv4 forwarding is disabled","WARNING: bridge-nf-call-iptables is disabled","WARNING: bridge-nf-call-ip6tables is disabled"],"ClientInfo":{"Debug":true,"Platform":{"Name":"Docker Engine - Community"},"Version":"24.0.0","Context":"default","Plugins":[],"Warnings":null}}
|
||||
{"ID":"EKHL:QDUU:QZ7U:MKGD:VDXK:S27Q:GIPU:24B7:R7VT:DGN6:QCSF:2UBX","Containers":0,"ContainersRunning":0,"ContainersPaused":0,"ContainersStopped":0,"Images":0,"Driver":"aufs","DriverStatus":[["Root Dir","/var/lib/docker/aufs"],["Backing Filesystem","extfs"],["Dirs","0"],["Dirperm1 Supported","true"]],"Plugins":{"Volume":["local"],"Network":["bridge","host","macvlan","null","overlay"],"Authorization":null,"Log":["awslogs","fluentd","gcplogs","gelf","journald","json-file","logentries","splunk","syslog"]},"MemoryLimit":true,"SwapLimit":true,"KernelMemory":true,"CpuCfsPeriod":true,"CpuCfsQuota":true,"CPUShares":true,"CPUSet":true,"PidsLimit":false,"IPv4Forwarding":true,"BridgeNfIptables":true,"BridgeNfIp6tables":true,"Debug":true,"NFd":33,"OomKillDisable":true,"NGoroutines":135,"SystemTime":"2017-08-24T17:44:34.077811894Z","LoggingDriver":"json-file","CgroupDriver":"cgroupfs","NEventsListener":0,"KernelVersion":"4.4.0-87-generic","OperatingSystem":"Ubuntu 16.04.3 LTS","OSVersion":"","OSType":"linux","Architecture":"x86_64","IndexServerAddress":"https://index.docker.io/v1/","RegistryConfig":{"AllowNondistributableArtifactsCIDRs":null,"AllowNondistributableArtifactsHostnames":null,"InsecureRegistryCIDRs":["127.0.0.0/8"],"IndexConfigs":{"docker.io":{"Name":"docker.io","Mirrors":null,"Secure":true,"Official":true}},"Mirrors":null},"NCPU":2,"MemTotal":2097356800,"GenericResources":null,"DockerRootDir":"/var/lib/docker","HttpProxy":"","HttpsProxy":"","NoProxy":"","Name":"system-sample","Labels":["provider=digitalocean"],"ExperimentalBuild":false,"ServerVersion":"17.06.1-ce","Runtimes":{"runc":{"path":"docker-runc"}},"DefaultRuntime":"runc","Swarm":{"NodeID":"","NodeAddr":"","LocalNodeState":"inactive","ControlAvailable":false,"Error":"","RemoteManagers":null},"LiveRestoreEnabled":false,"Isolation":"","InitBinary":"docker-init","ContainerdCommit":{"ID":"6e23458c129b551d5c9871e5174f6b1b7f6d1170","Expected":"6e23458c129b551d5c9871e5174f6b1b7f6d1170"},"RuncCommit":{"ID":"810190ceaa507aa2727d7ae6f4790c76ec150bd2","Expected":"810190ceaa507aa2727d7ae6f4790c76ec150bd2"},"InitCommit":{"ID":"949e6fa","Expected":"949e6fa"},"SecurityOptions":["name=apparmor","name=seccomp,profile=default"],"DefaultAddressPools":[{"Base":"10.123.0.0/16","Size":24}],"Warnings":["WARNING: No memory limit support","WARNING: No swap limit support","WARNING: No oom kill disable support","WARNING: No cpu cfs quota support","WARNING: No cpu cfs period support","WARNING: No cpu shares support","WARNING: No cpuset support","WARNING: IPv4 forwarding is disabled","WARNING: bridge-nf-call-iptables is disabled","WARNING: bridge-nf-call-ip6tables is disabled"],"ClientInfo":{"Debug":true,"Context":"default","Plugins":[],"Warnings":null}}
|
||||
|
||||
@ -1 +1 @@
|
||||
{"ID":"EKHL:QDUU:QZ7U:MKGD:VDXK:S27Q:GIPU:24B7:R7VT:DGN6:QCSF:2UBX","Containers":0,"ContainersRunning":0,"ContainersPaused":0,"ContainersStopped":0,"Images":0,"Driver":"aufs","DriverStatus":[["Root Dir","/var/lib/docker/aufs"],["Backing Filesystem","extfs"],["Dirs","0"],["Dirperm1 Supported","true"]],"Plugins":{"Volume":["local"],"Network":["bridge","host","macvlan","null","overlay"],"Authorization":null,"Log":["awslogs","fluentd","gcplogs","gelf","journald","json-file","logentries","splunk","syslog"]},"MemoryLimit":false,"SwapLimit":false,"CpuCfsPeriod":false,"CpuCfsQuota":false,"CPUShares":false,"CPUSet":false,"PidsLimit":false,"IPv4Forwarding":false,"BridgeNfIptables":false,"BridgeNfIp6tables":false,"Debug":true,"NFd":33,"OomKillDisable":false,"NGoroutines":135,"SystemTime":"2017-08-24T17:44:34.077811894Z","LoggingDriver":"json-file","CgroupDriver":"cgroupfs","NEventsListener":0,"KernelVersion":"4.4.0-87-generic","OperatingSystem":"Ubuntu 16.04.3 LTS","OSVersion":"","OSType":"linux","Architecture":"x86_64","IndexServerAddress":"https://index.docker.io/v1/","RegistryConfig":{"AllowNondistributableArtifactsCIDRs":null,"AllowNondistributableArtifactsHostnames":null,"InsecureRegistryCIDRs":["127.0.0.0/8"],"IndexConfigs":{"docker.io":{"Name":"docker.io","Mirrors":null,"Secure":true,"Official":true}},"Mirrors":null},"NCPU":2,"MemTotal":2097356800,"GenericResources":null,"DockerRootDir":"/var/lib/docker","HttpProxy":"","HttpsProxy":"","NoProxy":"","Name":"system-sample","Labels":["provider=digitalocean"],"ExperimentalBuild":false,"ServerVersion":"17.06.1-ce","Runtimes":{"runc":{"path":"docker-runc"}},"DefaultRuntime":"runc","Swarm":{"NodeID":"","NodeAddr":"","LocalNodeState":"inactive","ControlAvailable":false,"Error":"","RemoteManagers":null},"LiveRestoreEnabled":false,"Isolation":"","InitBinary":"docker-init","ContainerdCommit":{"ID":"6e23458c129b551d5c9871e5174f6b1b7f6d1170","Expected":"6e23458c129b551d5c9871e5174f6b1b7f6d1170"},"RuncCommit":{"ID":"810190ceaa507aa2727d7ae6f4790c76ec150bd2","Expected":"810190ceaa507aa2727d7ae6f4790c76ec150bd2"},"InitCommit":{"ID":"949e6fa","Expected":"949e6fa"},"SecurityOptions":["name=apparmor","name=seccomp,profile=default"],"DefaultAddressPools":[{"Base":"10.123.0.0/16","Size":24}],"Warnings":null,"ClientInfo":{"Debug":true,"Platform":{"Name":"Docker Engine - Community"},"Version":"24.0.0","Context":"default","Plugins":[],"Warnings":null}}
|
||||
{"ID":"EKHL:QDUU:QZ7U:MKGD:VDXK:S27Q:GIPU:24B7:R7VT:DGN6:QCSF:2UBX","Containers":0,"ContainersRunning":0,"ContainersPaused":0,"ContainersStopped":0,"Images":0,"Driver":"aufs","DriverStatus":[["Root Dir","/var/lib/docker/aufs"],["Backing Filesystem","extfs"],["Dirs","0"],["Dirperm1 Supported","true"]],"Plugins":{"Volume":["local"],"Network":["bridge","host","macvlan","null","overlay"],"Authorization":null,"Log":["awslogs","fluentd","gcplogs","gelf","journald","json-file","logentries","splunk","syslog"]},"MemoryLimit":false,"SwapLimit":false,"CpuCfsPeriod":false,"CpuCfsQuota":false,"CPUShares":false,"CPUSet":false,"PidsLimit":false,"IPv4Forwarding":false,"BridgeNfIptables":false,"BridgeNfIp6tables":false,"Debug":true,"NFd":33,"OomKillDisable":false,"NGoroutines":135,"SystemTime":"2017-08-24T17:44:34.077811894Z","LoggingDriver":"json-file","CgroupDriver":"cgroupfs","NEventsListener":0,"KernelVersion":"4.4.0-87-generic","OperatingSystem":"Ubuntu 16.04.3 LTS","OSVersion":"","OSType":"linux","Architecture":"x86_64","IndexServerAddress":"https://index.docker.io/v1/","RegistryConfig":{"AllowNondistributableArtifactsCIDRs":null,"AllowNondistributableArtifactsHostnames":null,"InsecureRegistryCIDRs":["127.0.0.0/8"],"IndexConfigs":{"docker.io":{"Name":"docker.io","Mirrors":null,"Secure":true,"Official":true}},"Mirrors":null},"NCPU":2,"MemTotal":2097356800,"GenericResources":null,"DockerRootDir":"/var/lib/docker","HttpProxy":"","HttpsProxy":"","NoProxy":"","Name":"system-sample","Labels":["provider=digitalocean"],"ExperimentalBuild":false,"ServerVersion":"17.06.1-ce","Runtimes":{"runc":{"path":"docker-runc"}},"DefaultRuntime":"runc","Swarm":{"NodeID":"","NodeAddr":"","LocalNodeState":"inactive","ControlAvailable":false,"Error":"","RemoteManagers":null},"LiveRestoreEnabled":false,"Isolation":"","InitBinary":"docker-init","ContainerdCommit":{"ID":"6e23458c129b551d5c9871e5174f6b1b7f6d1170","Expected":"6e23458c129b551d5c9871e5174f6b1b7f6d1170"},"RuncCommit":{"ID":"810190ceaa507aa2727d7ae6f4790c76ec150bd2","Expected":"810190ceaa507aa2727d7ae6f4790c76ec150bd2"},"InitCommit":{"ID":"949e6fa","Expected":"949e6fa"},"SecurityOptions":["name=apparmor","name=seccomp,profile=default"],"DefaultAddressPools":[{"Base":"10.123.0.0/16","Size":24}],"Warnings":null,"ClientInfo":{"Debug":true,"Context":"default","Plugins":[],"Warnings":null}}
|
||||
|
||||
@ -1,5 +1,4 @@
|
||||
Client: Docker Engine - Community
|
||||
Version: 24.0.0
|
||||
Client:
|
||||
Context: default
|
||||
Debug Mode: true
|
||||
|
||||
@ -46,6 +45,7 @@ Server:
|
||||
Goroutines: 135
|
||||
System Time: 2017-08-24T17:44:34.077811894Z
|
||||
EventsListeners: 0
|
||||
Registry: https://index.docker.io/v1/
|
||||
Labels:
|
||||
provider=digitalocean
|
||||
Experimental: false
|
||||
|
||||
@ -1 +1 @@
|
||||
{"ID":"EKHL:QDUU:QZ7U:MKGD:VDXK:S27Q:GIPU:24B7:R7VT:DGN6:QCSF:2UBX","Containers":0,"ContainersRunning":0,"ContainersPaused":0,"ContainersStopped":0,"Images":0,"Driver":"aufs","DriverStatus":[["Root Dir","/var/lib/docker/aufs"],["Backing Filesystem","extfs"],["Dirs","0"],["Dirperm1 Supported","true"]],"Plugins":{"Volume":["local"],"Network":["bridge","host","macvlan","null","overlay"],"Authorization":null,"Log":["awslogs","fluentd","gcplogs","gelf","journald","json-file","logentries","splunk","syslog"]},"MemoryLimit":true,"SwapLimit":true,"KernelMemory":true,"CpuCfsPeriod":true,"CpuCfsQuota":true,"CPUShares":true,"CPUSet":true,"PidsLimit":false,"IPv4Forwarding":true,"BridgeNfIptables":true,"BridgeNfIp6tables":true,"Debug":true,"NFd":33,"OomKillDisable":true,"NGoroutines":135,"SystemTime":"2017-08-24T17:44:34.077811894Z","LoggingDriver":"json-file","CgroupDriver":"cgroupfs","NEventsListener":0,"KernelVersion":"4.4.0-87-generic","OperatingSystem":"Ubuntu 16.04.3 LTS","OSVersion":"","OSType":"linux","Architecture":"x86_64","IndexServerAddress":"https://index.docker.io/v1/","RegistryConfig":{"AllowNondistributableArtifactsCIDRs":null,"AllowNondistributableArtifactsHostnames":null,"InsecureRegistryCIDRs":["127.0.0.0/8"],"IndexConfigs":{"docker.io":{"Name":"docker.io","Mirrors":null,"Secure":true,"Official":true}},"Mirrors":null},"NCPU":2,"MemTotal":2097356800,"GenericResources":null,"DockerRootDir":"/var/lib/docker","HttpProxy":"","HttpsProxy":"","NoProxy":"","Name":"system-sample","Labels":["provider=digitalocean"],"ExperimentalBuild":false,"ServerVersion":"17.06.1-ce","Runtimes":{"runc":{"path":"docker-runc"}},"DefaultRuntime":"runc","Swarm":{"NodeID":"","NodeAddr":"","LocalNodeState":"inactive","ControlAvailable":false,"Error":"","RemoteManagers":null},"LiveRestoreEnabled":false,"Isolation":"","InitBinary":"docker-init","ContainerdCommit":{"ID":"6e23458c129b551d5c9871e5174f6b1b7f6d1170","Expected":"6e23458c129b551d5c9871e5174f6b1b7f6d1170"},"RuncCommit":{"ID":"810190ceaa507aa2727d7ae6f4790c76ec150bd2","Expected":"810190ceaa507aa2727d7ae6f4790c76ec150bd2"},"InitCommit":{"ID":"949e6fa","Expected":"949e6fa"},"SecurityOptions":["name=apparmor","name=seccomp,profile=default"],"DefaultAddressPools":[{"Base":"10.123.0.0/16","Size":24}],"Warnings":null,"ClientInfo":{"Debug":true,"Platform":{"Name":"Docker Engine - Community"},"Version":"24.0.0","Context":"default","Plugins":[],"Warnings":null}}
|
||||
{"ID":"EKHL:QDUU:QZ7U:MKGD:VDXK:S27Q:GIPU:24B7:R7VT:DGN6:QCSF:2UBX","Containers":0,"ContainersRunning":0,"ContainersPaused":0,"ContainersStopped":0,"Images":0,"Driver":"aufs","DriverStatus":[["Root Dir","/var/lib/docker/aufs"],["Backing Filesystem","extfs"],["Dirs","0"],["Dirperm1 Supported","true"]],"Plugins":{"Volume":["local"],"Network":["bridge","host","macvlan","null","overlay"],"Authorization":null,"Log":["awslogs","fluentd","gcplogs","gelf","journald","json-file","logentries","splunk","syslog"]},"MemoryLimit":true,"SwapLimit":true,"KernelMemory":true,"CpuCfsPeriod":true,"CpuCfsQuota":true,"CPUShares":true,"CPUSet":true,"PidsLimit":false,"IPv4Forwarding":true,"BridgeNfIptables":true,"BridgeNfIp6tables":true,"Debug":true,"NFd":33,"OomKillDisable":true,"NGoroutines":135,"SystemTime":"2017-08-24T17:44:34.077811894Z","LoggingDriver":"json-file","CgroupDriver":"cgroupfs","NEventsListener":0,"KernelVersion":"4.4.0-87-generic","OperatingSystem":"Ubuntu 16.04.3 LTS","OSVersion":"","OSType":"linux","Architecture":"x86_64","IndexServerAddress":"https://index.docker.io/v1/","RegistryConfig":{"AllowNondistributableArtifactsCIDRs":null,"AllowNondistributableArtifactsHostnames":null,"InsecureRegistryCIDRs":["127.0.0.0/8"],"IndexConfigs":{"docker.io":{"Name":"docker.io","Mirrors":null,"Secure":true,"Official":true}},"Mirrors":null},"NCPU":2,"MemTotal":2097356800,"GenericResources":null,"DockerRootDir":"/var/lib/docker","HttpProxy":"","HttpsProxy":"","NoProxy":"","Name":"system-sample","Labels":["provider=digitalocean"],"ExperimentalBuild":false,"ServerVersion":"17.06.1-ce","Runtimes":{"runc":{"path":"docker-runc"}},"DefaultRuntime":"runc","Swarm":{"NodeID":"","NodeAddr":"","LocalNodeState":"inactive","ControlAvailable":false,"Error":"","RemoteManagers":null},"LiveRestoreEnabled":false,"Isolation":"","InitBinary":"docker-init","ContainerdCommit":{"ID":"6e23458c129b551d5c9871e5174f6b1b7f6d1170","Expected":"6e23458c129b551d5c9871e5174f6b1b7f6d1170"},"RuncCommit":{"ID":"810190ceaa507aa2727d7ae6f4790c76ec150bd2","Expected":"810190ceaa507aa2727d7ae6f4790c76ec150bd2"},"InitCommit":{"ID":"949e6fa","Expected":"949e6fa"},"SecurityOptions":["name=apparmor","name=seccomp,profile=default"],"DefaultAddressPools":[{"Base":"10.123.0.0/16","Size":24}],"Warnings":null,"ClientInfo":{"Debug":true,"Context":"default","Plugins":[],"Warnings":null}}
|
||||
|
||||
@ -51,6 +51,7 @@ Server:
|
||||
Goroutines: 135
|
||||
System Time: 2017-08-24T17:44:34.077811894Z
|
||||
EventsListeners: 0
|
||||
Registry: https://index.docker.io/v1/
|
||||
Labels:
|
||||
provider=digitalocean
|
||||
Experimental: false
|
||||
|
||||
@ -45,6 +45,7 @@ Server:
|
||||
Goroutines: 135
|
||||
System Time: 2017-08-24T17:44:34.077811894Z
|
||||
EventsListeners: 0
|
||||
Registry: https://index.docker.io/v1/
|
||||
Experimental: false
|
||||
Insecure Registries:
|
||||
127.0.0.0/8
|
||||
|
||||
@ -45,6 +45,7 @@ Server:
|
||||
Goroutines: 135
|
||||
System Time: 2017-08-24T17:44:34.077811894Z
|
||||
EventsListeners: 0
|
||||
Registry: https://index.docker.io/v1/
|
||||
Experimental: false
|
||||
Insecure Registries:
|
||||
127.0.0.0/8
|
||||
|
||||
@ -67,6 +67,7 @@ Server:
|
||||
Goroutines: 135
|
||||
System Time: 2017-08-24T17:44:34.077811894Z
|
||||
EventsListeners: 0
|
||||
Registry: https://index.docker.io/v1/
|
||||
Labels:
|
||||
provider=digitalocean
|
||||
Experimental: false
|
||||
|
||||
@ -11,9 +11,7 @@ import (
|
||||
"github.com/docker/cli/cli"
|
||||
"github.com/docker/cli/cli/command"
|
||||
"github.com/docker/cli/cli/command/completion"
|
||||
"github.com/docker/cli/cli/command/formatter"
|
||||
"github.com/docker/cli/cli/command/formatter/tabwriter"
|
||||
flagsHelper "github.com/docker/cli/cli/flags"
|
||||
"github.com/docker/cli/cli/version"
|
||||
"github.com/docker/cli/templates"
|
||||
"github.com/docker/docker/api/types"
|
||||
@ -22,8 +20,8 @@ import (
|
||||
"github.com/tonistiigi/go-rosetta"
|
||||
)
|
||||
|
||||
const defaultVersionTemplate = `{{with .Client -}}
|
||||
Client:{{if ne .Platform nil}}{{if ne .Platform.Name ""}} {{.Platform.Name}}{{end}}{{end}}
|
||||
var versionTemplate = `{{with .Client -}}
|
||||
Client:{{if ne .Platform.Name ""}} {{.Platform.Name}}{{end}}
|
||||
Version: {{.Version}}
|
||||
API version: {{.APIVersion}}{{if ne .APIVersion .DefaultAPIVersion}} (downgraded from {{.DefaultAPIVersion}}){{end}}
|
||||
Go version: {{.GoVersion}}
|
||||
@ -33,7 +31,7 @@ Client:{{if ne .Platform nil}}{{if ne .Platform.Name ""}} {{.Platform.Name}}{{en
|
||||
Context: {{.Context}}
|
||||
{{- end}}
|
||||
|
||||
{{- if ne .Server nil}}{{with .Server}}
|
||||
{{- if .ServerOK}}{{with .Server}}
|
||||
|
||||
Server:{{if ne .Platform.Name ""}} {{.Platform.Name}}{{end}}
|
||||
{{- range $component := .Components}}
|
||||
@ -66,45 +64,24 @@ type versionInfo struct {
|
||||
Server *types.Version
|
||||
}
|
||||
|
||||
type platformInfo struct {
|
||||
Name string `json:"Name,omitempty"`
|
||||
}
|
||||
|
||||
type clientVersion struct {
|
||||
Platform *platformInfo `json:"Platform,omitempty"`
|
||||
Version string `json:"Version,omitempty"`
|
||||
APIVersion string `json:"ApiVersion,omitempty"`
|
||||
DefaultAPIVersion string `json:"DefaultAPIVersion,omitempty"`
|
||||
GitCommit string `json:"GitCommit,omitempty"`
|
||||
GoVersion string `json:"GoVersion,omitempty"`
|
||||
Os string `json:"Os,omitempty"`
|
||||
Arch string `json:"Arch,omitempty"`
|
||||
BuildTime string `json:"BuildTime,omitempty"`
|
||||
Context string `json:"Context"`
|
||||
Platform struct{ Name string } `json:",omitempty"`
|
||||
|
||||
Version string
|
||||
APIVersion string `json:"ApiVersion"`
|
||||
DefaultAPIVersion string `json:"DefaultAPIVersion,omitempty"`
|
||||
GitCommit string
|
||||
GoVersion string
|
||||
Os string
|
||||
Arch string
|
||||
BuildTime string `json:",omitempty"`
|
||||
Context string
|
||||
}
|
||||
|
||||
// newClientVersion constructs a new clientVersion. If a dockerCLI is
|
||||
// passed as argument, additional information is included (API version),
|
||||
// which may invoke an API connection. Pass nil to omit the additional
|
||||
// information.
|
||||
func newClientVersion(contextName string, dockerCli command.Cli) clientVersion {
|
||||
v := clientVersion{
|
||||
Version: version.Version,
|
||||
GoVersion: runtime.Version(),
|
||||
GitCommit: version.GitCommit,
|
||||
BuildTime: reformatDate(version.BuildTime),
|
||||
Os: runtime.GOOS,
|
||||
Arch: arch(),
|
||||
Context: contextName,
|
||||
}
|
||||
if version.PlatformName != "" {
|
||||
v.Platform = &platformInfo{Name: version.PlatformName}
|
||||
}
|
||||
if dockerCli != nil {
|
||||
v.APIVersion = dockerCli.CurrentVersion()
|
||||
v.DefaultAPIVersion = dockerCli.DefaultVersion()
|
||||
}
|
||||
return v
|
||||
// ServerOK returns true when the client could connect to the docker server
|
||||
// and parse the information received. It returns false otherwise.
|
||||
func (v versionInfo) ServerOK() bool {
|
||||
return v.Server != nil
|
||||
}
|
||||
|
||||
// NewVersionCommand creates a new cobra.Command for `docker version`
|
||||
@ -124,7 +101,9 @@ func NewVersionCommand(dockerCli command.Cli) *cobra.Command {
|
||||
ValidArgsFunction: completion.NoComplete,
|
||||
}
|
||||
|
||||
cmd.Flags().StringVarP(&opts.format, "format", "f", "", flagsHelper.InspectFormatHelp)
|
||||
flags := cmd.Flags()
|
||||
flags.StringVarP(&opts.format, "format", "f", "", "Format the output using the given Go template")
|
||||
|
||||
return cmd
|
||||
}
|
||||
|
||||
@ -154,8 +133,20 @@ func runVersion(dockerCli command.Cli, opts *versionOptions) error {
|
||||
// TODO print error if kubernetes is used?
|
||||
|
||||
vd := versionInfo{
|
||||
Client: newClientVersion(dockerCli.CurrentContext(), dockerCli),
|
||||
Client: clientVersion{
|
||||
Platform: struct{ Name string }{version.PlatformName},
|
||||
Version: version.Version,
|
||||
APIVersion: dockerCli.CurrentVersion(),
|
||||
DefaultAPIVersion: dockerCli.DefaultVersion(),
|
||||
GoVersion: runtime.Version(),
|
||||
GitCommit: version.GitCommit,
|
||||
BuildTime: reformatDate(version.BuildTime),
|
||||
Os: runtime.GOOS,
|
||||
Arch: arch(),
|
||||
Context: dockerCli.CurrentContext(),
|
||||
},
|
||||
}
|
||||
|
||||
sv, err := dockerCli.Client().ServerVersion(context.Background())
|
||||
if err == nil {
|
||||
vd.Server = &sv
|
||||
@ -203,11 +194,8 @@ func prettyPrintVersion(dockerCli command.Cli, vd versionInfo, tmpl *template.Te
|
||||
}
|
||||
|
||||
func newVersionTemplate(templateFormat string) (*template.Template, error) {
|
||||
switch templateFormat {
|
||||
case "":
|
||||
templateFormat = defaultVersionTemplate
|
||||
case formatter.JSONFormatKey:
|
||||
templateFormat = formatter.JSONFormat
|
||||
if templateFormat == "" {
|
||||
templateFormat = versionTemplate
|
||||
}
|
||||
tmpl := templates.New("version").Funcs(template.FuncMap{"getDetailsOrder": getDetailsOrder})
|
||||
tmpl, err := tmpl.Parse(templateFormat)
|
||||
|
||||
@ -6,11 +6,12 @@ import (
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/docker/cli/internal/test"
|
||||
"github.com/docker/docker/api/types"
|
||||
"gotest.tools/v3/assert"
|
||||
is "gotest.tools/v3/assert/cmp"
|
||||
"gotest.tools/v3/golden"
|
||||
|
||||
"github.com/docker/cli/internal/test"
|
||||
"github.com/docker/docker/api/types"
|
||||
)
|
||||
|
||||
func TestVersionWithoutServer(t *testing.T) {
|
||||
@ -29,7 +30,7 @@ func TestVersionWithoutServer(t *testing.T) {
|
||||
assert.Assert(t, !strings.Contains(out, "Server:"), "actual: %s", out)
|
||||
}
|
||||
|
||||
func TestVersionFormat(t *testing.T) {
|
||||
func TestVersionAlign(t *testing.T) {
|
||||
vi := versionInfo{
|
||||
Client: clientVersion{
|
||||
Version: "18.99.5-ce",
|
||||
@ -103,28 +104,10 @@ func TestVersionFormat(t *testing.T) {
|
||||
},
|
||||
})
|
||||
|
||||
t.Run("default", func(t *testing.T) {
|
||||
cli := test.NewFakeCli(&fakeClient{})
|
||||
tmpl, err := newVersionTemplate("")
|
||||
assert.NilError(t, err)
|
||||
assert.NilError(t, prettyPrintVersion(cli, vi, tmpl))
|
||||
assert.Check(t, golden.String(cli.OutBuffer().String(), "docker-client-version.golden"))
|
||||
assert.Check(t, is.Equal("", cli.ErrBuffer().String()))
|
||||
})
|
||||
t.Run("json", func(t *testing.T) {
|
||||
cli := test.NewFakeCli(&fakeClient{})
|
||||
tmpl, err := newVersionTemplate("json")
|
||||
assert.NilError(t, err)
|
||||
assert.NilError(t, prettyPrintVersion(cli, vi, tmpl))
|
||||
assert.Check(t, golden.String(cli.OutBuffer().String(), "docker-client-version.json.golden"))
|
||||
assert.Check(t, is.Equal("", cli.ErrBuffer().String()))
|
||||
})
|
||||
t.Run("json template", func(t *testing.T) {
|
||||
cli := test.NewFakeCli(&fakeClient{})
|
||||
tmpl, err := newVersionTemplate("{{json .}}")
|
||||
assert.NilError(t, err)
|
||||
assert.NilError(t, prettyPrintVersion(cli, vi, tmpl))
|
||||
assert.Check(t, golden.String(cli.OutBuffer().String(), "docker-client-version.json.golden"))
|
||||
assert.Check(t, is.Equal("", cli.ErrBuffer().String()))
|
||||
})
|
||||
cli := test.NewFakeCli(&fakeClient{})
|
||||
tmpl, err := newVersionTemplate("")
|
||||
assert.NilError(t, err)
|
||||
assert.NilError(t, prettyPrintVersion(cli, vi, tmpl))
|
||||
assert.Check(t, golden.String(cli.OutBuffer().String(), "docker-client-version.golden"))
|
||||
assert.Check(t, is.Equal("", cli.ErrBuffer().String()))
|
||||
}
|
||||
|
||||
@ -14,14 +14,14 @@ type fakeClient struct {
|
||||
serviceInspectWithRaw func(ref string, options types.ServiceInspectOptions) (swarm.Service, []byte, error)
|
||||
}
|
||||
|
||||
func (cli *fakeClient) NodeInspectWithRaw(_ context.Context, ref string) (swarm.Node, []byte, error) {
|
||||
func (cli *fakeClient) NodeInspectWithRaw(ctx context.Context, ref string) (swarm.Node, []byte, error) {
|
||||
if cli.nodeInspectWithRaw != nil {
|
||||
return cli.nodeInspectWithRaw(ref)
|
||||
}
|
||||
return swarm.Node{}, nil, nil
|
||||
}
|
||||
|
||||
func (cli *fakeClient) ServiceInspectWithRaw(_ context.Context, ref string, options types.ServiceInspectOptions) (swarm.Service, []byte, error) {
|
||||
func (cli *fakeClient) ServiceInspectWithRaw(ctx context.Context, ref string, options types.ServiceInspectOptions) (swarm.Service, []byte, error) {
|
||||
if cli.serviceInspectWithRaw != nil {
|
||||
return cli.serviceInspectWithRaw(ref, options)
|
||||
}
|
||||
|
||||
@ -53,7 +53,7 @@ type trustKey struct {
|
||||
// This information is to be pretty printed or serialized into a machine-readable format.
|
||||
func lookupTrustInfo(cli command.Cli, remote string) ([]trustTagRow, []client.RoleWithSignatures, []data.Role, error) {
|
||||
ctx := context.Background()
|
||||
imgRefAndAuth, err := trust.GetImageReferencesAndAuth(ctx, image.AuthResolver(cli), remote)
|
||||
imgRefAndAuth, err := trust.GetImageReferencesAndAuth(ctx, nil, image.AuthResolver(cli), remote)
|
||||
if err != nil {
|
||||
return []trustTagRow{}, []client.RoleWithSignatures{}, []data.Role{}, err
|
||||
}
|
||||
|
||||
@ -27,15 +27,15 @@ type fakeClient struct {
|
||||
apiclient.Client
|
||||
}
|
||||
|
||||
func (c *fakeClient) Info(context.Context) (types.Info, error) {
|
||||
func (c *fakeClient) Info(ctx context.Context) (types.Info, error) {
|
||||
return types.Info{}, nil
|
||||
}
|
||||
|
||||
func (c *fakeClient) ImageInspectWithRaw(context.Context, string) (types.ImageInspect, []byte, error) {
|
||||
func (c *fakeClient) ImageInspectWithRaw(ctx context.Context, imageID string) (types.ImageInspect, []byte, error) {
|
||||
return types.ImageInspect{}, []byte{}, nil
|
||||
}
|
||||
|
||||
func (c *fakeClient) ImagePush(context.Context, string, types.ImagePushOptions) (io.ReadCloser, error) {
|
||||
func (c *fakeClient) ImagePush(ctx context.Context, image string, options types.ImagePushOptions) (io.ReadCloser, error) {
|
||||
return &utils.NoopCloser{Reader: bytes.NewBuffer([]byte{})}, nil
|
||||
}
|
||||
|
||||
|
||||
@ -36,7 +36,7 @@ func newRevokeCommand(dockerCli command.Cli) *cobra.Command {
|
||||
|
||||
func revokeTrust(cli command.Cli, remote string, options revokeOptions) error {
|
||||
ctx := context.Background()
|
||||
imgRefAndAuth, err := trust.GetImageReferencesAndAuth(ctx, image.AuthResolver(cli), remote)
|
||||
imgRefAndAuth, err := trust.GetImageReferencesAndAuth(ctx, nil, image.AuthResolver(cli), remote)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@ -13,7 +13,6 @@ import (
|
||||
"github.com/docker/cli/cli/command/image"
|
||||
"github.com/docker/cli/cli/trust"
|
||||
"github.com/docker/docker/api/types"
|
||||
registrytypes "github.com/docker/docker/api/types/registry"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/spf13/cobra"
|
||||
"github.com/theupdateframework/notary/client"
|
||||
@ -44,7 +43,7 @@ func newSignCommand(dockerCli command.Cli) *cobra.Command {
|
||||
func runSignImage(cli command.Cli, options signOptions) error {
|
||||
imageName := options.imageName
|
||||
ctx := context.Background()
|
||||
imgRefAndAuth, err := trust.GetImageReferencesAndAuth(ctx, image.AuthResolver(cli), imageName)
|
||||
imgRefAndAuth, err := trust.GetImageReferencesAndAuth(ctx, nil, image.AuthResolver(cli), imageName)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -94,7 +93,7 @@ func runSignImage(cli command.Cli, options signOptions) error {
|
||||
fmt.Fprintf(cli.Err(), "Signing and pushing trust data for local image %s, may overwrite remote trust data\n", imageName)
|
||||
|
||||
authConfig := command.ResolveAuthConfig(ctx, cli, imgRefAndAuth.RepoInfo().Index)
|
||||
encodedAuth, err := registrytypes.EncodeAuthConfig(authConfig)
|
||||
encodedAuth, err := command.EncodeAuthToBase64(authConfig)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@ -81,7 +81,7 @@ func addSigner(cli command.Cli, options signerAddOptions) error {
|
||||
|
||||
func addSignerToRepo(cli command.Cli, signerName string, repoName string, signerPubKeys []data.PublicKey) error {
|
||||
ctx := context.Background()
|
||||
imgRefAndAuth, err := trust.GetImageReferencesAndAuth(ctx, image.AuthResolver(cli), repoName)
|
||||
imgRefAndAuth, err := trust.GetImageReferencesAndAuth(ctx, nil, image.AuthResolver(cli), repoName)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@ -80,7 +80,7 @@ func isLastSignerForReleases(roleWithSig data.Role, allRoles []client.RoleWithSi
|
||||
// The signer not being removed doesn't necessarily raise an error e.g. user choosing "No" when prompted for confirmation.
|
||||
func removeSingleSigner(cli command.Cli, repoName, signerName string, forceYes bool) (bool, error) {
|
||||
ctx := context.Background()
|
||||
imgRefAndAuth, err := trust.GetImageReferencesAndAuth(ctx, image.AuthResolver(cli), repoName)
|
||||
imgRefAndAuth, err := trust.GetImageReferencesAndAuth(ctx, nil, image.AuthResolver(cli), repoName)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
@ -32,9 +32,9 @@ func (c *fakeClient) VolumeInspect(_ context.Context, volumeID string) (volume.V
|
||||
return volume.Volume{}, nil
|
||||
}
|
||||
|
||||
func (c *fakeClient) VolumeList(_ context.Context, options volume.ListOptions) (volume.ListResponse, error) {
|
||||
func (c *fakeClient) VolumeList(_ context.Context, filter filters.Args) (volume.ListResponse, error) {
|
||||
if c.volumeListFunc != nil {
|
||||
return c.volumeListFunc(options.Filters)
|
||||
return c.volumeListFunc(filter)
|
||||
}
|
||||
return volume.ListResponse{}, nil
|
||||
}
|
||||
|
||||
@ -50,7 +50,6 @@ func TestVolumeCreateErrors(t *testing.T) {
|
||||
cmd.Flags().Set(key, value)
|
||||
}
|
||||
cmd.SetOut(io.Discard)
|
||||
cmd.SetErr(io.Discard)
|
||||
assert.ErrorContains(t, cmd.Execute(), tc.expectedError)
|
||||
}
|
||||
}
|
||||
|
||||
@ -62,7 +62,6 @@ func TestVolumeInspectErrors(t *testing.T) {
|
||||
cmd.Flags().Set(key, value)
|
||||
}
|
||||
cmd.SetOut(io.Discard)
|
||||
cmd.SetErr(io.Discard)
|
||||
assert.ErrorContains(t, cmd.Execute(), tc.expectedError)
|
||||
}
|
||||
}
|
||||
|
||||
@ -10,7 +10,6 @@ import (
|
||||
"github.com/docker/cli/cli/command/formatter"
|
||||
flagsHelper "github.com/docker/cli/cli/flags"
|
||||
"github.com/docker/cli/opts"
|
||||
"github.com/docker/docker/api/types/volume"
|
||||
"github.com/fvbommel/sortorder"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
@ -53,7 +52,7 @@ func newListCommand(dockerCli command.Cli) *cobra.Command {
|
||||
|
||||
func runList(dockerCli command.Cli, options listOptions) error {
|
||||
client := dockerCli.Client()
|
||||
volumes, err := client.VolumeList(context.Background(), volume.ListOptions{Filters: options.filter.Value()})
|
||||
volumes, err := client.VolumeList(context.Background(), options.filter.Value())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -71,9 +70,9 @@ func runList(dockerCli command.Cli, options listOptions) error {
|
||||
|
||||
// trick for filtering in place
|
||||
n := 0
|
||||
for _, vol := range volumes.Volumes {
|
||||
if vol.ClusterVolume != nil {
|
||||
volumes.Volumes[n] = vol
|
||||
for _, volume := range volumes.Volumes {
|
||||
if volume.ClusterVolume != nil {
|
||||
volumes.Volumes[n] = volume
|
||||
n++
|
||||
}
|
||||
}
|
||||
|
||||
@ -43,7 +43,6 @@ func TestVolumeListErrors(t *testing.T) {
|
||||
cmd.Flags().Set(key, value)
|
||||
}
|
||||
cmd.SetOut(io.Discard)
|
||||
cmd.SetErr(io.Discard)
|
||||
assert.ErrorContains(t, cmd.Execute(), tc.expectedError)
|
||||
}
|
||||
}
|
||||
|
||||
@ -75,6 +75,6 @@ func runPrune(dockerCli command.Cli, options pruneOptions) (spaceReclaimed uint6
|
||||
|
||||
// RunPrune calls the Volume Prune API
|
||||
// This returns the amount of space reclaimed and a detailed output string
|
||||
func RunPrune(dockerCli command.Cli, _ bool, filter opts.FilterOpt) (uint64, string, error) {
|
||||
func RunPrune(dockerCli command.Cli, all bool, filter opts.FilterOpt) (uint64, string, error) {
|
||||
return runPrune(dockerCli, pruneOptions{force: true, filter: filter})
|
||||
}
|
||||
|
||||
@ -49,7 +49,6 @@ func TestVolumePruneErrors(t *testing.T) {
|
||||
cmd.Flags().Set(key, value)
|
||||
}
|
||||
cmd.SetOut(io.Discard)
|
||||
cmd.SetErr(io.Discard)
|
||||
assert.ErrorContains(t, cmd.Execute(), tc.expectedError)
|
||||
}
|
||||
}
|
||||
@ -110,7 +109,7 @@ func TestVolumePrunePromptNo(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func simplePruneFunc(filters.Args) (types.VolumesPruneReport, error) {
|
||||
func simplePruneFunc(args filters.Args) (types.VolumesPruneReport, error) {
|
||||
return types.VolumesPruneReport{
|
||||
VolumesDeleted: []string{
|
||||
"foo", "bar", "baz",
|
||||
|
||||
@ -33,7 +33,6 @@ func TestVolumeRemoveErrors(t *testing.T) {
|
||||
}))
|
||||
cmd.SetArgs(tc.args)
|
||||
cmd.SetOut(io.Discard)
|
||||
cmd.SetErr(io.Discard)
|
||||
assert.ErrorContains(t, cmd.Execute(), tc.expectedError)
|
||||
}
|
||||
}
|
||||
|
||||
@ -596,14 +596,14 @@ type fakeClient struct {
|
||||
configListFunc func(types.ConfigListOptions) ([]swarm.Config, error)
|
||||
}
|
||||
|
||||
func (c *fakeClient) SecretList(_ context.Context, options types.SecretListOptions) ([]swarm.Secret, error) {
|
||||
func (c *fakeClient) SecretList(ctx context.Context, options types.SecretListOptions) ([]swarm.Secret, error) {
|
||||
if c.secretListFunc != nil {
|
||||
return c.secretListFunc(options)
|
||||
}
|
||||
return []swarm.Secret{}, nil
|
||||
}
|
||||
|
||||
func (c *fakeClient) ConfigList(_ context.Context, options types.ConfigListOptions) ([]swarm.Config, error) {
|
||||
func (c *fakeClient) ConfigList(ctx context.Context, options types.ConfigListOptions) ([]swarm.Config, error) {
|
||||
if c.configListFunc != nil {
|
||||
return c.configListFunc(options)
|
||||
}
|
||||
|
||||
@ -17,7 +17,7 @@ const (
|
||||
|
||||
type portsFormatChecker struct{}
|
||||
|
||||
func (checker portsFormatChecker) IsFormat(_ interface{}) bool {
|
||||
func (checker portsFormatChecker) IsFormat(input interface{}) bool {
|
||||
// TODO: implement this
|
||||
return true
|
||||
}
|
||||
|
||||
@ -37,6 +37,7 @@ type ConfigFile struct {
|
||||
PruneFilters []string `json:"pruneFilters,omitempty"`
|
||||
Proxies map[string]ProxyConfig `json:"proxies,omitempty"`
|
||||
Experimental string `json:"experimental,omitempty"`
|
||||
StackOrchestrator string `json:"stackOrchestrator,omitempty"` // Deprecated: swarm is now the default orchestrator, and this option is ignored.
|
||||
CurrentContext string `json:"currentContext,omitempty"`
|
||||
CLIPluginsExtraDirs []string `json:"cliPluginsExtraDirs,omitempty"`
|
||||
Plugins map[string]map[string]string `json:"plugins,omitempty"`
|
||||
|
||||
@ -186,7 +186,7 @@ func (c *mockNativeStore) GetAll() (map[string]types.AuthConfig, error) {
|
||||
return c.authConfigs, nil
|
||||
}
|
||||
|
||||
func (c *mockNativeStore) Store(_ types.AuthConfig) error {
|
||||
func (c *mockNativeStore) Store(authConfig types.AuthConfig) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user