mirror of
https://github.com/docker/cli.git
synced 2026-08-24 10:05:37 -05:00
Compare commits
97
Commits
v28.0.0-rc.1
...
v28.0.0
@@ -19,11 +19,14 @@ Provide the following information:
|
||||
|
||||
**- How to verify it**
|
||||
|
||||
**- Description for the changelog**
|
||||
**- Human readable description for the release notes**
|
||||
<!--
|
||||
Write a short (one line) summary that describes the changes in this
|
||||
pull request for inclusion in the changelog.
|
||||
It must be placed inside the below triple backticks section:
|
||||
It must be placed inside the below triple backticks section.
|
||||
|
||||
NOTE: Only fill this section if changes introduced in this PR are user-facing.
|
||||
The PR must have a relevant impact/ label.
|
||||
-->
|
||||
```markdown changelog
|
||||
|
||||
|
||||
@@ -16,6 +16,7 @@ on:
|
||||
jobs:
|
||||
check-area-label:
|
||||
runs-on: ubuntu-20.04
|
||||
timeout-minutes: 120 # guardrails timeout for the whole job
|
||||
steps:
|
||||
- name: Missing `area/` label
|
||||
if: contains(join(github.event.pull_request.labels.*.name, ','), 'impact/') && !contains(join(github.event.pull_request.labels.*.name, ','), 'area/')
|
||||
@@ -26,9 +27,10 @@ jobs:
|
||||
run: exit 0
|
||||
|
||||
check-changelog:
|
||||
if: contains(join(github.event.pull_request.labels.*.name, ','), 'impact/')
|
||||
runs-on: ubuntu-20.04
|
||||
timeout-minutes: 120 # guardrails timeout for the whole job
|
||||
env:
|
||||
HAS_IMPACT_LABEL: ${{ contains(join(github.event.pull_request.labels.*.name, ','), 'impact/') }}
|
||||
PR_BODY: |
|
||||
${{ github.event.pull_request.body }}
|
||||
steps:
|
||||
@@ -40,15 +42,23 @@ jobs:
|
||||
# Strip empty lines
|
||||
desc=$(echo "$block" | awk NF)
|
||||
|
||||
if [ -z "$desc" ]; then
|
||||
echo "::error::Changelog section is empty. Provide a description for the changelog."
|
||||
exit 1
|
||||
fi
|
||||
if [ "$HAS_IMPACT_LABEL" = "true" ]; then
|
||||
if [ -z "$desc" ]; then
|
||||
echo "::error::Changelog section is empty. Please provide a description for the changelog."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
len=$(echo -n "$desc" | wc -c)
|
||||
if [[ $len -le 6 ]]; then
|
||||
echo "::error::Description looks too short: $desc"
|
||||
exit 1
|
||||
len=$(echo -n "$desc" | wc -c)
|
||||
if [[ $len -le 6 ]]; then
|
||||
echo "::error::Description looks too short: $desc"
|
||||
exit 1
|
||||
fi
|
||||
else
|
||||
if [ -n "$desc" ]; then
|
||||
echo "::error::PR has a changelog description, but no changelog label"
|
||||
echo "::error::Please add the relevant 'impact/' label to the PR or remove the changelog description"
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
|
||||
echo "This PR will be included in the release notes with the following note:"
|
||||
@@ -56,6 +66,7 @@ jobs:
|
||||
|
||||
check-pr-branch:
|
||||
runs-on: ubuntu-20.04
|
||||
timeout-minutes: 120 # guardrails timeout for the whole job
|
||||
env:
|
||||
PR_TITLE: ${{ github.event.pull_request.title }}
|
||||
steps:
|
||||
|
||||
+29
-13
@@ -15,9 +15,8 @@ linters:
|
||||
- gosimple
|
||||
- govet
|
||||
- ineffassign
|
||||
- lll
|
||||
- misspell # Detects commonly misspelled English words in comments.
|
||||
- nakedret
|
||||
- nakedret # Detects uses of naked returns.
|
||||
- nilerr # Detects code that returns nil even if it checks that the error is not nil.
|
||||
- nolintlint # Detects ill-formed or insufficient nolint directives.
|
||||
- perfsprint # Detects fmt.Sprintf uses that can be replaced with a faster alternative.
|
||||
@@ -27,7 +26,6 @@ linters:
|
||||
- revive # Metalinter; drop-in replacement for golint.
|
||||
- staticcheck
|
||||
- stylecheck # Replacement for golint
|
||||
- tenv # Detects using os.Setenv instead of t.Setenv.
|
||||
- thelper # Detects test helpers without t.Helper().
|
||||
- tparallel # Detects inappropriate usage of t.Parallel().
|
||||
- typecheck
|
||||
@@ -35,6 +33,7 @@ linters:
|
||||
- unparam
|
||||
- unused
|
||||
- usestdlibvars
|
||||
- usetesting # Reports uses of functions with replacement inside the testing package.
|
||||
- wastedassign
|
||||
|
||||
disable:
|
||||
@@ -43,6 +42,8 @@ linters:
|
||||
run:
|
||||
# prevent golangci-lint from deducting the go version to lint for through go.mod,
|
||||
# which causes it to fallback to go1.17 semantics.
|
||||
#
|
||||
# TODO(thaJeztah): update "usetesting" settings to enable go1.24 features once our minimum version is go1.24
|
||||
go: "1.23.6"
|
||||
timeout: 5m
|
||||
|
||||
@@ -81,15 +82,12 @@ linters-settings:
|
||||
lll:
|
||||
line-length: 200
|
||||
nakedret:
|
||||
command: nakedret
|
||||
pattern: ^(?P<path>.*?\\.go):(?P<line>\\d+)\\s*(?P<message>.*)$
|
||||
# Disallow naked returns if func has more lines of code than this setting.
|
||||
# Default: 30
|
||||
max-func-lines: 0
|
||||
|
||||
revive:
|
||||
rules:
|
||||
# https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#import-shadowing
|
||||
- name: import-shadowing
|
||||
severity: warning
|
||||
disabled: false
|
||||
# https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#empty-block
|
||||
- name: empty-block
|
||||
severity: warning
|
||||
@@ -98,11 +96,32 @@ linters-settings:
|
||||
- name: empty-lines
|
||||
severity: warning
|
||||
disabled: false
|
||||
# https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#import-shadowing
|
||||
- name: import-shadowing
|
||||
severity: warning
|
||||
disabled: false
|
||||
# https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#line-length-limit
|
||||
- name: line-length-limit
|
||||
severity: warning
|
||||
disabled: false
|
||||
arguments: [200]
|
||||
# https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#unused-receiver
|
||||
- name: unused-receiver
|
||||
severity: warning
|
||||
disabled: false
|
||||
# https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#use-any
|
||||
- name: use-any
|
||||
severity: warning
|
||||
disabled: false
|
||||
|
||||
usetesting:
|
||||
# FIXME(thaJeztah): Disable `os.Chdir()` detections; should be automatically disabled on Go < 1.24; see https://github.com/docker/cli/pull/5835#issuecomment-2665302478
|
||||
os-chdir: false
|
||||
# FIXME(thaJeztah): Disable `context.Background()` detections; should be automatically disabled on Go < 1.24; see https://github.com/docker/cli/pull/5835#issuecomment-2665302478
|
||||
context-background: false
|
||||
# FIXME(thaJeztah): Disable `context.TODO()` detections; should be automatically disabled on Go < 1.24; see https://github.com/docker/cli/pull/5835#issuecomment-2665302478
|
||||
context-todo: false
|
||||
|
||||
issues:
|
||||
# The default exclusion rules are a bit too permissive, so copying the relevant ones below
|
||||
exclude-use-default: false
|
||||
@@ -161,10 +180,7 @@ issues:
|
||||
- text: "package-comments: should have a package comment"
|
||||
linters:
|
||||
- revive
|
||||
# FIXME temporarily suppress these (see https://github.com/gotestyourself/gotest.tools/issues/272)
|
||||
- text: "SA1019: (assert|cmp|is)\\.ErrorType is deprecated"
|
||||
linters:
|
||||
- staticcheck
|
||||
|
||||
# Exclude some linters from running on tests files.
|
||||
- path: _test\.go
|
||||
linters:
|
||||
|
||||
+6
-2
@@ -7,8 +7,12 @@ ARG BASE_DEBIAN_DISTRO=bookworm
|
||||
ARG GO_VERSION=1.23.6
|
||||
ARG XX_VERSION=1.6.1
|
||||
ARG GOVERSIONINFO_VERSION=v1.4.1
|
||||
ARG GOTESTSUM_VERSION=v1.10.0
|
||||
ARG BUILDX_VERSION=0.20.0
|
||||
ARG GOTESTSUM_VERSION=v1.12.0
|
||||
|
||||
# BUILDX_VERSION sets the version of buildx to use for the e2e tests.
|
||||
# It must be a tag in the docker.io/docker/buildx-bin image repository
|
||||
# on Docker Hub.
|
||||
ARG BUILDX_VERSION=0.20.1
|
||||
ARG COMPOSE_VERSION=v2.32.4
|
||||
|
||||
FROM --platform=$BUILDPLATFORM tonistiigi/xx:${XX_VERSION} AS xx
|
||||
|
||||
@@ -32,7 +32,7 @@ const (
|
||||
// errPluginNotFound is the error returned when a plugin could not be found.
|
||||
type errPluginNotFound string
|
||||
|
||||
func (e errPluginNotFound) NotFound() {}
|
||||
func (errPluginNotFound) NotFound() {}
|
||||
|
||||
func (e errPluginNotFound) Error() string {
|
||||
return "Error: No such CLI plugin: " + string(e)
|
||||
|
||||
+4
-2
@@ -337,8 +337,10 @@ func operationSubCommands(cmd *cobra.Command) []*cobra.Command {
|
||||
return cmds
|
||||
}
|
||||
|
||||
const defaultTermWidth = 80
|
||||
|
||||
func wrappedFlagUsages(cmd *cobra.Command) string {
|
||||
width := 80
|
||||
width := defaultTermWidth
|
||||
if ws, err := term.GetWinsize(0); err == nil {
|
||||
width = int(ws.Width)
|
||||
}
|
||||
@@ -518,4 +520,4 @@ Run '{{.CommandPath}} COMMAND --help' for more information on a command.
|
||||
`
|
||||
|
||||
const helpTemplate = `
|
||||
{{if or .Runnable .HasSubCommands}}{{.UsageString}}{{end}}`
|
||||
{{- if or .Runnable .HasSubCommands}}{{.UsageString}}{{end}}`
|
||||
|
||||
+2
-2
@@ -97,7 +97,7 @@ type DockerCli struct {
|
||||
}
|
||||
|
||||
// DefaultVersion returns api.defaultVersion.
|
||||
func (cli *DockerCli) DefaultVersion() string {
|
||||
func (*DockerCli) DefaultVersion() string {
|
||||
return api.DefaultVersion
|
||||
}
|
||||
|
||||
@@ -231,7 +231,7 @@ func (cli *DockerCli) HooksEnabled() bool {
|
||||
}
|
||||
|
||||
// ManifestStore returns a store for local manifests
|
||||
func (cli *DockerCli) ManifestStore() manifeststore.Store {
|
||||
func (*DockerCli) ManifestStore() manifeststore.Store {
|
||||
// TODO: support override default location from config file
|
||||
return manifeststore.NewStore(filepath.Join(config.Dir(), "manifests"))
|
||||
}
|
||||
|
||||
@@ -177,7 +177,10 @@ func withCustomHeadersFromEnv() client.Opt {
|
||||
csvReader := csv.NewReader(strings.NewReader(value))
|
||||
fields, err := csvReader.Read()
|
||||
if err != nil {
|
||||
return errdefs.InvalidParameter(errors.Errorf("failed to parse custom headers from %s environment variable: value must be formatted as comma-separated key=value pairs", envOverrideHTTPHeaders))
|
||||
return errdefs.InvalidParameter(errors.Errorf(
|
||||
"failed to parse custom headers from %s environment variable: value must be formatted as comma-separated key=value pairs",
|
||||
envOverrideHTTPHeaders,
|
||||
))
|
||||
}
|
||||
if len(fields) == 0 {
|
||||
return nil
|
||||
@@ -191,7 +194,10 @@ func withCustomHeadersFromEnv() client.Opt {
|
||||
k = strings.TrimSpace(k)
|
||||
|
||||
if k == "" {
|
||||
return errdefs.InvalidParameter(errors.Errorf(`failed to set custom headers from %s environment variable: value contains a key=value pair with an empty key: '%s'`, envOverrideHTTPHeaders, kv))
|
||||
return errdefs.InvalidParameter(errors.Errorf(
|
||||
`failed to set custom headers from %s environment variable: value contains a key=value pair with an empty key: '%s'`,
|
||||
envOverrideHTTPHeaders, kv,
|
||||
))
|
||||
}
|
||||
|
||||
// We don't currently allow empty key=value pairs, and produce an error.
|
||||
@@ -199,7 +205,10 @@ func withCustomHeadersFromEnv() client.Opt {
|
||||
// from an environment variable with the same name). In the meantime,
|
||||
// produce an error to prevent users from depending on this.
|
||||
if !hasValue {
|
||||
return errdefs.InvalidParameter(errors.Errorf(`failed to set custom headers from %s environment variable: missing "=" in key=value pair: '%s'`, envOverrideHTTPHeaders, kv))
|
||||
return errdefs.InvalidParameter(errors.Errorf(
|
||||
`failed to set custom headers from %s environment variable: missing "=" in key=value pair: '%s'`,
|
||||
envOverrideHTTPHeaders, kv,
|
||||
))
|
||||
}
|
||||
|
||||
env[http.CanonicalHeaderKey(k)] = v
|
||||
|
||||
@@ -27,8 +27,11 @@ type APIClientProvider interface {
|
||||
}
|
||||
|
||||
// ImageNames offers completion for images present within the local store
|
||||
func ImageNames(dockerCLI APIClientProvider) ValidArgsFn {
|
||||
func ImageNames(dockerCLI APIClientProvider, limit int) ValidArgsFn {
|
||||
return func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
|
||||
if limit > 0 && len(args) >= limit {
|
||||
return nil, cobra.ShellCompDirectiveNoFileComp
|
||||
}
|
||||
list, err := dockerCLI.Client().ImageList(cmd.Context(), image.ListOptions{})
|
||||
if err != nil {
|
||||
return nil, cobra.ShellCompDirectiveError
|
||||
|
||||
@@ -234,7 +234,7 @@ func TestCompleteImageNames(t *testing.T) {
|
||||
}
|
||||
return tc.images, nil
|
||||
},
|
||||
}})
|
||||
}}, -1)
|
||||
|
||||
volumes, directives := comp(&cobra.Command{}, nil, "")
|
||||
assert.Check(t, is.Equal(directives&tc.expDirective, tc.expDirective))
|
||||
|
||||
@@ -18,7 +18,7 @@ type fakeClient struct {
|
||||
client.Client
|
||||
inspectFunc func(string) (container.InspectResponse, error)
|
||||
execInspectFunc func(execID string) (container.ExecInspect, error)
|
||||
execCreateFunc func(containerID string, options container.ExecOptions) (types.IDResponse, error)
|
||||
execCreateFunc func(containerID string, options container.ExecOptions) (container.ExecCreateResponse, error)
|
||||
createContainerFunc func(config *container.Config,
|
||||
hostConfig *container.HostConfig,
|
||||
networkingConfig *network.NetworkingConfig,
|
||||
@@ -42,7 +42,7 @@ type fakeClient struct {
|
||||
containerAttachFunc func(ctx context.Context, containerID string, options container.AttachOptions) (types.HijackedResponse, error)
|
||||
containerDiffFunc func(ctx context.Context, containerID string) ([]container.FilesystemChange, error)
|
||||
containerRenameFunc func(ctx context.Context, oldName, newName string) error
|
||||
containerCommitFunc func(ctx context.Context, container string, options container.CommitOptions) (types.IDResponse, error)
|
||||
containerCommitFunc func(ctx context.Context, container string, options container.CommitOptions) (container.CommitResponse, error)
|
||||
containerPauseFunc func(ctx context.Context, container string) error
|
||||
Version string
|
||||
}
|
||||
@@ -61,11 +61,11 @@ func (f *fakeClient) ContainerInspect(_ context.Context, containerID string) (co
|
||||
return container.InspectResponse{}, nil
|
||||
}
|
||||
|
||||
func (f *fakeClient) ContainerExecCreate(_ context.Context, containerID string, config container.ExecOptions) (types.IDResponse, error) {
|
||||
func (f *fakeClient) ContainerExecCreate(_ context.Context, containerID string, config container.ExecOptions) (container.ExecCreateResponse, error) {
|
||||
if f.execCreateFunc != nil {
|
||||
return f.execCreateFunc(containerID, config)
|
||||
}
|
||||
return types.IDResponse{}, nil
|
||||
return container.ExecCreateResponse{}, nil
|
||||
}
|
||||
|
||||
func (f *fakeClient) ContainerExecInspect(_ context.Context, execID string) (container.ExecInspect, error) {
|
||||
@@ -75,7 +75,7 @@ func (f *fakeClient) ContainerExecInspect(_ context.Context, execID string) (con
|
||||
return container.ExecInspect{}, nil
|
||||
}
|
||||
|
||||
func (f *fakeClient) ContainerExecStart(context.Context, string, container.ExecStartOptions) error {
|
||||
func (*fakeClient) ContainerExecStart(context.Context, string, container.ExecStartOptions) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -218,11 +218,11 @@ func (f *fakeClient) ContainerRename(ctx context.Context, oldName, newName strin
|
||||
return nil
|
||||
}
|
||||
|
||||
func (f *fakeClient) ContainerCommit(ctx context.Context, containerID string, options container.CommitOptions) (types.IDResponse, error) {
|
||||
func (f *fakeClient) ContainerCommit(ctx context.Context, containerID string, options container.CommitOptions) (container.CommitResponse, error) {
|
||||
if f.containerCommitFunc != nil {
|
||||
return f.containerCommitFunc(ctx, containerID, options)
|
||||
}
|
||||
return types.IDResponse{}, nil
|
||||
return container.CommitResponse{}, nil
|
||||
}
|
||||
|
||||
func (f *fakeClient) ContainerPause(ctx context.Context, containerID string) error {
|
||||
|
||||
@@ -7,7 +7,6 @@ import (
|
||||
"testing"
|
||||
|
||||
"github.com/docker/cli/internal/test"
|
||||
"github.com/docker/docker/api/types"
|
||||
"github.com/docker/docker/api/types/container"
|
||||
"gotest.tools/v3/assert"
|
||||
is "gotest.tools/v3/assert/cmp"
|
||||
@@ -17,16 +16,16 @@ func TestRunCommit(t *testing.T) {
|
||||
cli := test.NewFakeCli(&fakeClient{
|
||||
containerCommitFunc: func(
|
||||
ctx context.Context,
|
||||
container string,
|
||||
ctr string,
|
||||
options container.CommitOptions,
|
||||
) (types.IDResponse, error) {
|
||||
) (container.CommitResponse, error) {
|
||||
assert.Check(t, is.Equal(options.Author, "Author Name <author@name.com>"))
|
||||
assert.Check(t, is.DeepEqual(options.Changes, []string{"EXPOSE 80"}))
|
||||
assert.Check(t, is.Equal(options.Comment, "commit message"))
|
||||
assert.Check(t, is.Equal(options.Pause, false))
|
||||
assert.Check(t, is.Equal(container, "container-id"))
|
||||
assert.Check(t, is.Equal(ctr, "container-id"))
|
||||
|
||||
return types.IDResponse{ID: "image-id"}, nil
|
||||
return container.CommitResponse{ID: "image-id"}, nil
|
||||
},
|
||||
})
|
||||
|
||||
@@ -54,10 +53,10 @@ func TestRunCommitClientError(t *testing.T) {
|
||||
cli := test.NewFakeCli(&fakeClient{
|
||||
containerCommitFunc: func(
|
||||
ctx context.Context,
|
||||
container string,
|
||||
ctr string,
|
||||
options container.CommitOptions,
|
||||
) (types.IDResponse, error) {
|
||||
return types.IDResponse{}, clientError
|
||||
) (container.CommitResponse, error) {
|
||||
return container.CommitResponse{}, clientError
|
||||
},
|
||||
})
|
||||
|
||||
|
||||
@@ -201,9 +201,10 @@ func runCopy(ctx context.Context, dockerCli command.Cli, opts copyOptions) error
|
||||
}
|
||||
}
|
||||
|
||||
func resolveLocalPath(localPath string) (absPath string, err error) {
|
||||
if absPath, err = filepath.Abs(localPath); err != nil {
|
||||
return
|
||||
func resolveLocalPath(localPath string) (absPath string, _ error) {
|
||||
absPath, err := filepath.Abs(localPath)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return archive.PreserveTrailingDotOrSeparator(absPath, localPath), nil
|
||||
}
|
||||
|
||||
@@ -60,7 +60,7 @@ func NewCreateCommand(dockerCli command.Cli) *cobra.Command {
|
||||
Annotations: map[string]string{
|
||||
"aliases": "docker container create, docker create",
|
||||
},
|
||||
ValidArgsFunction: completion.ImageNames(dockerCli),
|
||||
ValidArgsFunction: completion.ImageNames(dockerCli, -1),
|
||||
}
|
||||
|
||||
flags := cmd.Flags()
|
||||
|
||||
@@ -380,5 +380,5 @@ func TestCreateContainerWithProxyConfig(t *testing.T) {
|
||||
|
||||
type fakeNotFound struct{}
|
||||
|
||||
func (f fakeNotFound) NotFound() {}
|
||||
func (f fakeNotFound) Error() string { return "error fake not found" }
|
||||
func (fakeNotFound) NotFound() {}
|
||||
func (fakeNotFound) Error() string { return "error fake not found" }
|
||||
|
||||
@@ -11,7 +11,6 @@ import (
|
||||
"github.com/docker/cli/cli/config/configfile"
|
||||
"github.com/docker/cli/internal/test"
|
||||
"github.com/docker/cli/opts"
|
||||
"github.com/docker/docker/api/types"
|
||||
"github.com/docker/docker/api/types/container"
|
||||
"gotest.tools/v3/assert"
|
||||
is "gotest.tools/v3/assert/cmp"
|
||||
@@ -208,8 +207,8 @@ func TestRunExec(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func execCreateWithID(_ string, _ container.ExecOptions) (types.IDResponse, error) {
|
||||
return types.IDResponse{ID: "execid"}, nil
|
||||
func execCreateWithID(_ string, _ container.ExecOptions) (container.ExecCreateResponse, error) {
|
||||
return container.ExecCreateResponse{ID: "execid"}, nil
|
||||
}
|
||||
|
||||
func TestGetExecExitStatus(t *testing.T) {
|
||||
|
||||
@@ -22,6 +22,8 @@ const (
|
||||
winMemUseHeader = "PRIV WORKING SET" // Used only on Windows
|
||||
memUseHeader = "MEM USAGE / LIMIT" // Used only on Linux
|
||||
pidsHeader = "PIDS" // Used only on Linux
|
||||
|
||||
noValue = "--"
|
||||
)
|
||||
|
||||
// StatsEntry represents the statistics data collected from a container
|
||||
@@ -169,7 +171,7 @@ func (c *statsContext) Name() string {
|
||||
if len(c.s.Name) > 1 {
|
||||
return c.s.Name[1:]
|
||||
}
|
||||
return "--"
|
||||
return noValue
|
||||
}
|
||||
|
||||
func (c *statsContext) ID() string {
|
||||
@@ -181,7 +183,7 @@ func (c *statsContext) ID() string {
|
||||
|
||||
func (c *statsContext) CPUPerc() string {
|
||||
if c.s.IsInvalid {
|
||||
return "--"
|
||||
return noValue
|
||||
}
|
||||
return formatPercentage(c.s.CPUPercentage)
|
||||
}
|
||||
@@ -198,28 +200,28 @@ func (c *statsContext) MemUsage() string {
|
||||
|
||||
func (c *statsContext) MemPerc() string {
|
||||
if c.s.IsInvalid || c.os == winOSType {
|
||||
return "--"
|
||||
return noValue
|
||||
}
|
||||
return formatPercentage(c.s.MemoryPercentage)
|
||||
}
|
||||
|
||||
func (c *statsContext) NetIO() string {
|
||||
if c.s.IsInvalid {
|
||||
return "--"
|
||||
return noValue
|
||||
}
|
||||
return units.HumanSizeWithPrecision(c.s.NetworkRx, 3) + " / " + units.HumanSizeWithPrecision(c.s.NetworkTx, 3)
|
||||
}
|
||||
|
||||
func (c *statsContext) BlockIO() string {
|
||||
if c.s.IsInvalid {
|
||||
return "--"
|
||||
return noValue
|
||||
}
|
||||
return units.HumanSizeWithPrecision(c.s.BlockRead, 3) + " / " + units.HumanSizeWithPrecision(c.s.BlockWrite, 3)
|
||||
}
|
||||
|
||||
func (c *statsContext) PIDs() string {
|
||||
if c.s.IsInvalid || c.os == winOSType {
|
||||
return "--"
|
||||
return noValue
|
||||
}
|
||||
return strconv.FormatUint(c.s.PidsCurrent, 10)
|
||||
}
|
||||
|
||||
@@ -1016,12 +1016,8 @@ func TestParseLabelfileVariables(t *testing.T) {
|
||||
|
||||
func TestParseEntryPoint(t *testing.T) {
|
||||
config, _, _, err := parseRun([]string{"--entrypoint=anything", "cmd", "img"})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if len(config.Entrypoint) != 1 && config.Entrypoint[0] != "anything" {
|
||||
t.Fatalf("Expected entrypoint 'anything', got %v", config.Entrypoint)
|
||||
}
|
||||
assert.NilError(t, err)
|
||||
assert.Check(t, is.DeepEqual([]string(config.Entrypoint), []string{"anything"}))
|
||||
}
|
||||
|
||||
func TestValidateDevice(t *testing.T) {
|
||||
|
||||
@@ -43,7 +43,7 @@ func NewRunCommand(dockerCli command.Cli) *cobra.Command {
|
||||
}
|
||||
return runRun(cmd.Context(), dockerCli, cmd.Flags(), &options, copts)
|
||||
},
|
||||
ValidArgsFunction: completion.ImageNames(dockerCli),
|
||||
ValidArgsFunction: completion.ImageNames(dockerCli, 1),
|
||||
Annotations: map[string]string{
|
||||
"category-top": "1",
|
||||
"aliases": "docker container run, docker run",
|
||||
|
||||
@@ -331,7 +331,12 @@ size: 0B
|
||||
},
|
||||
// Special headers for customized table format
|
||||
{
|
||||
context: Context{Format: NewContainerFormat(`table {{truncate .ID 5}}\t{{json .Image}} {{.RunningFor}}/{{title .Status}}/{{pad .Ports 2 2}}.{{upper .Names}} {{lower .Status}}`, false, true)},
|
||||
context: Context{
|
||||
Format: NewContainerFormat(
|
||||
`table {{truncate .ID 5}}\t{{json .Image}} {{.RunningFor}}/{{title .Status}}/{{pad .Ports 2 2}}.{{upper .Names}} {{lower .Status}}`,
|
||||
false, true,
|
||||
),
|
||||
},
|
||||
expected: string(golden.Get(t, "container-context-write-special-headers.golden")),
|
||||
},
|
||||
{
|
||||
@@ -525,7 +530,6 @@ type ports struct {
|
||||
expected string
|
||||
}
|
||||
|
||||
//nolint:lll
|
||||
func TestDisplayablePorts(t *testing.T) {
|
||||
cases := []ports{
|
||||
{
|
||||
@@ -828,7 +832,7 @@ func TestDisplayablePorts(t *testing.T) {
|
||||
Type: "sctp",
|
||||
},
|
||||
},
|
||||
expected: "80/tcp, 80/udp, 1024/tcp, 1024/udp, 12345/sctp, 1.1.1.1:1024->80/tcp, 1.1.1.1:1024->80/udp, 2.1.1.1:1024->80/tcp, 2.1.1.1:1024->80/udp, 1.1.1.1:80->1024/tcp, 1.1.1.1:80->1024/udp, 2.1.1.1:80->1024/tcp, 2.1.1.1:80->1024/udp",
|
||||
expected: "80/tcp, 80/udp, 1024/tcp, 1024/udp, 12345/sctp, 1.1.1.1:1024->80/tcp, 1.1.1.1:1024->80/udp, 2.1.1.1:1024->80/tcp, 2.1.1.1:1024->80/udp, 1.1.1.1:80->1024/tcp, 1.1.1.1:80->1024/udp, 2.1.1.1:80->1024/tcp, 2.1.1.1:80->1024/udp", //nolint:revive // ignore line-length-limit (revive)
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
@@ -32,7 +32,7 @@ type SubContext interface {
|
||||
type SubHeaderContext map[string]string
|
||||
|
||||
// Label returns the header label for the specified string
|
||||
func (c SubHeaderContext) Label(name string) string {
|
||||
func (SubHeaderContext) Label(name string) string {
|
||||
n := strings.Split(name, ".")
|
||||
r := strings.NewReplacer("-", " ", "_", " ")
|
||||
h := r.Replace(n[len(n)-1])
|
||||
|
||||
@@ -270,7 +270,7 @@ func (c *diskUsageImagesContext) MarshalJSON() ([]byte, error) {
|
||||
return MarshalJSON(c)
|
||||
}
|
||||
|
||||
func (c *diskUsageImagesContext) Type() string {
|
||||
func (*diskUsageImagesContext) Type() string {
|
||||
return "Images"
|
||||
}
|
||||
|
||||
@@ -321,7 +321,7 @@ func (c *diskUsageContainersContext) MarshalJSON() ([]byte, error) {
|
||||
return MarshalJSON(c)
|
||||
}
|
||||
|
||||
func (c *diskUsageContainersContext) Type() string {
|
||||
func (*diskUsageContainersContext) Type() string {
|
||||
return "Containers"
|
||||
}
|
||||
|
||||
@@ -329,7 +329,7 @@ func (c *diskUsageContainersContext) TotalCount() string {
|
||||
return strconv.Itoa(len(c.containers))
|
||||
}
|
||||
|
||||
func (c *diskUsageContainersContext) isActive(ctr container.Summary) bool {
|
||||
func (*diskUsageContainersContext) isActive(ctr container.Summary) bool {
|
||||
return strings.Contains(ctr.State, "running") ||
|
||||
strings.Contains(ctr.State, "paused") ||
|
||||
strings.Contains(ctr.State, "restarting")
|
||||
@@ -382,7 +382,7 @@ func (c *diskUsageVolumesContext) MarshalJSON() ([]byte, error) {
|
||||
return MarshalJSON(c)
|
||||
}
|
||||
|
||||
func (c *diskUsageVolumesContext) Type() string {
|
||||
func (*diskUsageVolumesContext) Type() string {
|
||||
return "Local Volumes"
|
||||
}
|
||||
|
||||
@@ -443,7 +443,7 @@ func (c *diskUsageBuilderContext) MarshalJSON() ([]byte, error) {
|
||||
return MarshalJSON(c)
|
||||
}
|
||||
|
||||
func (c *diskUsageBuilderContext) Type() string {
|
||||
func (*diskUsageBuilderContext) Type() string {
|
||||
return "Build Cache"
|
||||
}
|
||||
|
||||
|
||||
@@ -28,7 +28,7 @@ type fakeSubContext struct {
|
||||
Name string
|
||||
}
|
||||
|
||||
func (f fakeSubContext) FullHeader() any {
|
||||
func (fakeSubContext) FullHeader() any {
|
||||
return map[string]string{"Name": "NAME"}
|
||||
}
|
||||
|
||||
|
||||
@@ -10,29 +10,29 @@ import (
|
||||
|
||||
type dummy struct{}
|
||||
|
||||
func (d *dummy) Func1() string {
|
||||
func (*dummy) Func1() string {
|
||||
return "Func1"
|
||||
}
|
||||
|
||||
func (d *dummy) func2() string { //nolint:unused
|
||||
func (*dummy) func2() string { //nolint:unused
|
||||
return "func2(should not be marshalled)"
|
||||
}
|
||||
|
||||
func (d *dummy) Func3() (string, int) {
|
||||
func (*dummy) Func3() (string, int) {
|
||||
return "Func3(should not be marshalled)", -42
|
||||
}
|
||||
|
||||
func (d *dummy) Func4() int {
|
||||
func (*dummy) Func4() int {
|
||||
return 4
|
||||
}
|
||||
|
||||
type dummyType string
|
||||
|
||||
func (d *dummy) Func5() dummyType {
|
||||
return dummyType("Func5")
|
||||
func (*dummy) Func5() dummyType {
|
||||
return "Func5"
|
||||
}
|
||||
|
||||
func (d *dummy) FullHeader() string {
|
||||
func (*dummy) FullHeader() string {
|
||||
return "FullHeader(should not be marshalled)"
|
||||
}
|
||||
|
||||
|
||||
@@ -16,17 +16,17 @@ import (
|
||||
type fakeClient struct {
|
||||
client.Client
|
||||
imageTagFunc func(string, string) error
|
||||
imageSaveFunc func(images []string, options image.SaveOptions) (io.ReadCloser, error)
|
||||
imageSaveFunc func(images []string, options ...client.ImageSaveOption) (io.ReadCloser, error)
|
||||
imageRemoveFunc func(image string, options image.RemoveOptions) ([]image.DeleteResponse, error)
|
||||
imagePushFunc func(ref string, options image.PushOptions) (io.ReadCloser, error)
|
||||
infoFunc func() (system.Info, error)
|
||||
imagePullFunc func(ref string, options image.PullOptions) (io.ReadCloser, error)
|
||||
imagesPruneFunc func(pruneFilter filters.Args) (image.PruneReport, error)
|
||||
imageLoadFunc func(input io.Reader, options image.LoadOptions) (image.LoadResponse, error)
|
||||
imageLoadFunc func(input io.Reader, options ...client.ImageLoadOption) (image.LoadResponse, error)
|
||||
imageListFunc func(options image.ListOptions) ([]image.Summary, error)
|
||||
imageInspectFunc func(img string) (image.InspectResponse, error)
|
||||
imageImportFunc func(source image.ImportSource, ref string, options image.ImportOptions) (io.ReadCloser, error)
|
||||
imageHistoryFunc func(img string, options image.HistoryOptions) ([]image.HistoryResponseItem, error)
|
||||
imageHistoryFunc func(img string, options ...client.ImageHistoryOption) ([]image.HistoryResponseItem, error)
|
||||
imageBuildFunc func(context.Context, io.Reader, types.ImageBuildOptions) (types.ImageBuildResponse, error)
|
||||
}
|
||||
|
||||
@@ -37,9 +37,9 @@ func (cli *fakeClient) ImageTag(_ context.Context, img, ref string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (cli *fakeClient) ImageSave(_ context.Context, images []string, options image.SaveOptions) (io.ReadCloser, error) {
|
||||
func (cli *fakeClient) ImageSave(_ context.Context, images []string, options ...client.ImageSaveOption) (io.ReadCloser, error) {
|
||||
if cli.imageSaveFunc != nil {
|
||||
return cli.imageSaveFunc(images, options)
|
||||
return cli.imageSaveFunc(images, options...)
|
||||
}
|
||||
return io.NopCloser(strings.NewReader("")), nil
|
||||
}
|
||||
@@ -81,9 +81,9 @@ func (cli *fakeClient) ImagesPrune(_ context.Context, pruneFilter filters.Args)
|
||||
return image.PruneReport{}, nil
|
||||
}
|
||||
|
||||
func (cli *fakeClient) ImageLoad(_ context.Context, input io.Reader, options image.LoadOptions) (image.LoadResponse, error) {
|
||||
func (cli *fakeClient) ImageLoad(_ context.Context, input io.Reader, options ...client.ImageLoadOption) (image.LoadResponse, error) {
|
||||
if cli.imageLoadFunc != nil {
|
||||
return cli.imageLoadFunc(input, options)
|
||||
return cli.imageLoadFunc(input, options...)
|
||||
}
|
||||
return image.LoadResponse{}, nil
|
||||
}
|
||||
@@ -111,9 +111,9 @@ func (cli *fakeClient) ImageImport(_ context.Context, source image.ImportSource,
|
||||
return io.NopCloser(strings.NewReader("")), nil
|
||||
}
|
||||
|
||||
func (cli *fakeClient) ImageHistory(_ context.Context, img string, options image.HistoryOptions) ([]image.HistoryResponseItem, error) {
|
||||
func (cli *fakeClient) ImageHistory(_ context.Context, img string, options ...client.ImageHistoryOption) ([]image.HistoryResponseItem, error) {
|
||||
if cli.imageHistoryFunc != nil {
|
||||
return cli.imageHistoryFunc(img, options)
|
||||
return cli.imageHistoryFunc(img, options...)
|
||||
}
|
||||
return []image.HistoryResponseItem{{ID: img, Created: time.Now().Unix()}}, nil
|
||||
}
|
||||
|
||||
@@ -107,8 +107,8 @@ func TestHistoryContext_CreatedSince(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestHistoryContext_CreatedBy(t *testing.T) {
|
||||
withTabs := `/bin/sh -c apt-key adv --keyserver hkp://pgp.mit.edu:80 --recv-keys 573BFD6B3D8FBC641079A6ABABF5BD827BD9BF62 && echo "deb http://nginx.org/packages/mainline/debian/ jessie nginx" >> /etc/apt/sources.list && apt-get update && apt-get install --no-install-recommends --no-install-suggests -y ca-certificates nginx=${NGINX_VERSION} nginx-module-xslt nginx-module-geoip nginx-module-image-filter nginx-module-perl nginx-module-njs gettext-base && rm -rf /var/lib/apt/lists/*` //nolint:lll
|
||||
expected := `/bin/sh -c apt-key adv --keyserver hkp://pgp.mit.edu:80 --recv-keys 573BFD6B3D8FBC641079A6ABABF5BD827BD9BF62 && echo "deb http://nginx.org/packages/mainline/debian/ jessie nginx" >> /etc/apt/sources.list && apt-get update && apt-get install --no-install-recommends --no-install-suggests -y ca-certificates nginx=${NGINX_VERSION} nginx-module-xslt nginx-module-geoip nginx-module-image-filter nginx-module-perl nginx-module-njs gettext-base && rm -rf /var/lib/apt/lists/*` //nolint:lll
|
||||
const withTabs = `/bin/sh -c apt-key adv --keyserver hkp://pgp.mit.edu:80 --recv-keys 573BFD6B3D8FBC641079A6ABABF5BD827BD9BF62 && echo "deb http://nginx.org/packages/mainline/debian/ jessie nginx" >> /etc/apt/sources.list && apt-get update && apt-get install --no-install-recommends --no-install-suggests -y ca-certificates nginx=${NGINX_VERSION} nginx-module-xslt nginx-module-geoip nginx-module-image-filter nginx-module-perl nginx-module-njs gettext-base && rm -rf /var/lib/apt/lists/*` //nolint:revive // ignore line-length-limit
|
||||
const expected = `/bin/sh -c apt-key adv --keyserver hkp://pgp.mit.edu:80 --recv-keys 573BFD6B3D8FBC641079A6ABABF5BD827BD9BF62 && echo "deb http://nginx.org/packages/mainline/debian/ jessie nginx" >> /etc/apt/sources.list && apt-get update && apt-get install --no-install-recommends --no-install-suggests -y ca-certificates nginx=${NGINX_VERSION} nginx-module-xslt nginx-module-geoip nginx-module-image-filter nginx-module-perl nginx-module-njs gettext-base && rm -rf /var/lib/apt/lists/*` //nolint:revive // ignore line-length-limit
|
||||
|
||||
var ctx historyContext
|
||||
cases := []historyCase{
|
||||
@@ -138,8 +138,8 @@ func TestHistoryContext_CreatedBy(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestHistoryContext_Size(t *testing.T) {
|
||||
size := int64(182964289)
|
||||
expected := "183MB"
|
||||
const size = int64(182964289)
|
||||
const expected = "183MB"
|
||||
|
||||
var ctx historyContext
|
||||
cases := []historyCase{
|
||||
@@ -170,7 +170,7 @@ func TestHistoryContext_Size(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestHistoryContext_Comment(t *testing.T) {
|
||||
comment := "Some comment"
|
||||
const comment = "Some comment"
|
||||
|
||||
var ctx historyContext
|
||||
cases := []historyCase{
|
||||
|
||||
@@ -9,7 +9,7 @@ import (
|
||||
"github.com/docker/cli/cli/command/completion"
|
||||
"github.com/docker/cli/cli/command/formatter"
|
||||
flagsHelper "github.com/docker/cli/cli/flags"
|
||||
"github.com/docker/docker/api/types/image"
|
||||
"github.com/docker/docker/client"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
@@ -36,7 +36,7 @@ func NewHistoryCommand(dockerCli command.Cli) *cobra.Command {
|
||||
opts.image = args[0]
|
||||
return runHistory(cmd.Context(), dockerCli, opts)
|
||||
},
|
||||
ValidArgsFunction: completion.ImageNames(dockerCli),
|
||||
ValidArgsFunction: completion.ImageNames(dockerCli, 1),
|
||||
Annotations: map[string]string{
|
||||
"aliases": "docker image history, docker history",
|
||||
},
|
||||
@@ -56,16 +56,16 @@ func NewHistoryCommand(dockerCli command.Cli) *cobra.Command {
|
||||
}
|
||||
|
||||
func runHistory(ctx context.Context, dockerCli command.Cli, opts historyOptions) error {
|
||||
var options image.HistoryOptions
|
||||
var options []client.ImageHistoryOption
|
||||
if opts.platform != "" {
|
||||
p, err := platforms.Parse(opts.platform)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "invalid platform")
|
||||
}
|
||||
options.Platform = &p
|
||||
options = append(options, client.ImageHistoryWithPlatform(p))
|
||||
}
|
||||
|
||||
history, err := dockerCli.Client().ImageHistory(ctx, opts.image, options)
|
||||
history, err := dockerCli.Client().ImageHistory(ctx, opts.image, options...)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -9,9 +9,8 @@ import (
|
||||
|
||||
"github.com/docker/cli/internal/test"
|
||||
"github.com/docker/docker/api/types/image"
|
||||
ocispec "github.com/opencontainers/image-spec/specs-go/v1"
|
||||
"github.com/docker/docker/client"
|
||||
"gotest.tools/v3/assert"
|
||||
is "gotest.tools/v3/assert/cmp"
|
||||
"gotest.tools/v3/golden"
|
||||
)
|
||||
|
||||
@@ -20,7 +19,7 @@ func TestNewHistoryCommandErrors(t *testing.T) {
|
||||
name string
|
||||
args []string
|
||||
expectedError string
|
||||
imageHistoryFunc func(img string, options image.HistoryOptions) ([]image.HistoryResponseItem, error)
|
||||
imageHistoryFunc func(img string, options ...client.ImageHistoryOption) ([]image.HistoryResponseItem, error)
|
||||
}{
|
||||
{
|
||||
name: "wrong-args",
|
||||
@@ -31,7 +30,7 @@ func TestNewHistoryCommandErrors(t *testing.T) {
|
||||
name: "client-error",
|
||||
args: []string{"image:tag"},
|
||||
expectedError: "something went wrong",
|
||||
imageHistoryFunc: func(img string, options image.HistoryOptions) ([]image.HistoryResponseItem, error) {
|
||||
imageHistoryFunc: func(string, ...client.ImageHistoryOption) ([]image.HistoryResponseItem, error) {
|
||||
return []image.HistoryResponseItem{{}}, errors.New("something went wrong")
|
||||
},
|
||||
},
|
||||
@@ -56,12 +55,12 @@ func TestNewHistoryCommandSuccess(t *testing.T) {
|
||||
testCases := []struct {
|
||||
name string
|
||||
args []string
|
||||
imageHistoryFunc func(img string, options image.HistoryOptions) ([]image.HistoryResponseItem, error)
|
||||
imageHistoryFunc func(img string, options ...client.ImageHistoryOption) ([]image.HistoryResponseItem, error)
|
||||
}{
|
||||
{
|
||||
name: "simple",
|
||||
args: []string{"image:tag"},
|
||||
imageHistoryFunc: func(img string, options image.HistoryOptions) ([]image.HistoryResponseItem, error) {
|
||||
imageHistoryFunc: func(string, ...client.ImageHistoryOption) ([]image.HistoryResponseItem, error) {
|
||||
return []image.HistoryResponseItem{{
|
||||
ID: "1234567890123456789",
|
||||
Created: time.Now().Unix(),
|
||||
@@ -76,7 +75,7 @@ func TestNewHistoryCommandSuccess(t *testing.T) {
|
||||
{
|
||||
name: "non-human",
|
||||
args: []string{"--human=false", "image:tag"},
|
||||
imageHistoryFunc: func(img string, options image.HistoryOptions) ([]image.HistoryResponseItem, error) {
|
||||
imageHistoryFunc: func(string, ...client.ImageHistoryOption) ([]image.HistoryResponseItem, error) {
|
||||
return []image.HistoryResponseItem{{
|
||||
ID: "abcdef",
|
||||
Created: time.Date(2017, 1, 1, 12, 0, 3, 0, time.UTC).Unix(),
|
||||
@@ -88,7 +87,7 @@ func TestNewHistoryCommandSuccess(t *testing.T) {
|
||||
{
|
||||
name: "quiet-no-trunc",
|
||||
args: []string{"--quiet", "--no-trunc", "image:tag"},
|
||||
imageHistoryFunc: func(img string, options image.HistoryOptions) ([]image.HistoryResponseItem, error) {
|
||||
imageHistoryFunc: func(string, ...client.ImageHistoryOption) ([]image.HistoryResponseItem, error) {
|
||||
return []image.HistoryResponseItem{{
|
||||
ID: "1234567890123456789",
|
||||
Created: time.Now().Unix(),
|
||||
@@ -98,8 +97,10 @@ func TestNewHistoryCommandSuccess(t *testing.T) {
|
||||
{
|
||||
name: "platform",
|
||||
args: []string{"--platform", "linux/amd64", "image:tag"},
|
||||
imageHistoryFunc: func(img string, options image.HistoryOptions) ([]image.HistoryResponseItem, error) {
|
||||
assert.Check(t, is.DeepEqual(ocispec.Platform{OS: "linux", Architecture: "amd64"}, *options.Platform))
|
||||
imageHistoryFunc: func(img string, options ...client.ImageHistoryOption) ([]image.HistoryResponseItem, error) {
|
||||
// FIXME(thaJeztah): need to find appropriate way to test the result of "ImageHistoryWithPlatform" being applied
|
||||
assert.Check(t, len(options) > 0) // can be 1 or two depending on whether a terminal is attached :/
|
||||
// assert.Check(t, is.Contains(options, client.ImageHistoryWithPlatform(ocispec.Platform{OS: "linux", Architecture: "amd64"})))
|
||||
return []image.HistoryResponseItem{{
|
||||
ID: "1234567890123456789",
|
||||
Created: time.Now().Unix(),
|
||||
|
||||
@@ -34,7 +34,7 @@ func newInspectCommand(dockerCli command.Cli) *cobra.Command {
|
||||
opts.refs = args
|
||||
return runInspect(cmd.Context(), dockerCli, opts)
|
||||
},
|
||||
ValidArgsFunction: completion.ImageNames(dockerCli),
|
||||
ValidArgsFunction: completion.ImageNames(dockerCli, -1),
|
||||
}
|
||||
|
||||
flags := cmd.Flags()
|
||||
|
||||
@@ -9,7 +9,7 @@ import (
|
||||
"github.com/docker/cli/cli/command"
|
||||
"github.com/docker/cli/cli/command/completion"
|
||||
"github.com/docker/cli/cli/internal/jsonstream"
|
||||
"github.com/docker/docker/api/types/image"
|
||||
"github.com/docker/docker/client"
|
||||
"github.com/moby/sys/sequential"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/spf13/cobra"
|
||||
@@ -68,9 +68,9 @@ func runLoad(ctx context.Context, dockerCli command.Cli, opts loadOptions) error
|
||||
return errors.Errorf("requested load from stdin, but stdin is empty")
|
||||
}
|
||||
|
||||
var options image.LoadOptions
|
||||
var options []client.ImageLoadOption
|
||||
if opts.quiet || !dockerCli.Out().IsTerminal() {
|
||||
options.Quiet = true
|
||||
options = append(options, client.ImageLoadWithQuiet(true))
|
||||
}
|
||||
|
||||
if opts.platform != "" {
|
||||
@@ -79,10 +79,10 @@ func runLoad(ctx context.Context, dockerCli command.Cli, opts loadOptions) error
|
||||
return errors.Wrap(err, "invalid platform")
|
||||
}
|
||||
// TODO(thaJeztah): change flag-type to support multiple platforms.
|
||||
options.Platforms = append(options.Platforms, p)
|
||||
options = append(options, client.ImageLoadWithPlatforms(p))
|
||||
}
|
||||
|
||||
response, err := dockerCli.Client().ImageLoad(ctx, input, options)
|
||||
response, err := dockerCli.Client().ImageLoad(ctx, input, options...)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -9,9 +9,8 @@ import (
|
||||
|
||||
"github.com/docker/cli/internal/test"
|
||||
"github.com/docker/docker/api/types/image"
|
||||
ocispec "github.com/opencontainers/image-spec/specs-go/v1"
|
||||
"github.com/docker/docker/client"
|
||||
"gotest.tools/v3/assert"
|
||||
is "gotest.tools/v3/assert/cmp"
|
||||
"gotest.tools/v3/golden"
|
||||
)
|
||||
|
||||
@@ -21,7 +20,7 @@ func TestNewLoadCommandErrors(t *testing.T) {
|
||||
args []string
|
||||
isTerminalIn bool
|
||||
expectedError string
|
||||
imageLoadFunc func(input io.Reader, options image.LoadOptions) (image.LoadResponse, error)
|
||||
imageLoadFunc func(input io.Reader, options ...client.ImageLoadOption) (image.LoadResponse, error)
|
||||
}{
|
||||
{
|
||||
name: "wrong-args",
|
||||
@@ -38,7 +37,7 @@ func TestNewLoadCommandErrors(t *testing.T) {
|
||||
name: "pull-error",
|
||||
args: []string{},
|
||||
expectedError: "something went wrong",
|
||||
imageLoadFunc: func(input io.Reader, options image.LoadOptions) (image.LoadResponse, error) {
|
||||
imageLoadFunc: func(io.Reader, ...client.ImageLoadOption) (image.LoadResponse, error) {
|
||||
return image.LoadResponse{}, errors.New("something went wrong")
|
||||
},
|
||||
},
|
||||
@@ -46,7 +45,7 @@ func TestNewLoadCommandErrors(t *testing.T) {
|
||||
name: "invalid platform",
|
||||
args: []string{"--platform", "<invalid>"},
|
||||
expectedError: `invalid platform`,
|
||||
imageLoadFunc: func(input io.Reader, options image.LoadOptions) (image.LoadResponse, error) {
|
||||
imageLoadFunc: func(io.Reader, ...client.ImageLoadOption) (image.LoadResponse, error) {
|
||||
return image.LoadResponse{}, nil
|
||||
},
|
||||
},
|
||||
@@ -78,22 +77,21 @@ func TestNewLoadCommandSuccess(t *testing.T) {
|
||||
testCases := []struct {
|
||||
name string
|
||||
args []string
|
||||
imageLoadFunc func(input io.Reader, options image.LoadOptions) (image.LoadResponse, error)
|
||||
imageLoadFunc func(input io.Reader, options ...client.ImageLoadOption) (image.LoadResponse, error)
|
||||
}{
|
||||
{
|
||||
name: "simple",
|
||||
args: []string{},
|
||||
imageLoadFunc: func(input io.Reader, options image.LoadOptions) (image.LoadResponse, error) {
|
||||
imageLoadFunc: func(io.Reader, ...client.ImageLoadOption) (image.LoadResponse, error) {
|
||||
return image.LoadResponse{Body: io.NopCloser(strings.NewReader("Success"))}, nil
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "json",
|
||||
args: []string{},
|
||||
imageLoadFunc: func(input io.Reader, options image.LoadOptions) (image.LoadResponse, error) {
|
||||
json := "{\"ID\": \"1\"}"
|
||||
imageLoadFunc: func(io.Reader, ...client.ImageLoadOption) (image.LoadResponse, error) {
|
||||
return image.LoadResponse{
|
||||
Body: io.NopCloser(strings.NewReader(json)),
|
||||
Body: io.NopCloser(strings.NewReader(`{"ID": "1"}`)),
|
||||
JSON: true,
|
||||
}, nil
|
||||
},
|
||||
@@ -101,15 +99,17 @@ func TestNewLoadCommandSuccess(t *testing.T) {
|
||||
{
|
||||
name: "input-file",
|
||||
args: []string{"--input", "testdata/load-command-success.input.txt"},
|
||||
imageLoadFunc: func(input io.Reader, options image.LoadOptions) (image.LoadResponse, error) {
|
||||
imageLoadFunc: func(input io.Reader, options ...client.ImageLoadOption) (image.LoadResponse, error) {
|
||||
return image.LoadResponse{Body: io.NopCloser(strings.NewReader("Success"))}, nil
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "with platform",
|
||||
args: []string{"--platform", "linux/amd64"},
|
||||
imageLoadFunc: func(input io.Reader, options image.LoadOptions) (image.LoadResponse, error) {
|
||||
assert.Check(t, is.DeepEqual([]ocispec.Platform{{OS: "linux", Architecture: "amd64"}}, options.Platforms))
|
||||
imageLoadFunc: func(input io.Reader, options ...client.ImageLoadOption) (image.LoadResponse, error) {
|
||||
// FIXME(thaJeztah): need to find appropriate way to test the result of "ImageHistoryWithPlatform" being applied
|
||||
assert.Check(t, len(options) > 0) // can be 1 or two depending on whether a terminal is attached :/
|
||||
// assert.Check(t, is.Contains(options, client.ImageHistoryWithPlatform(ocispec.Platform{OS: "linux", Architecture: "amd64"})))
|
||||
return image.LoadResponse{Body: io.NopCloser(strings.NewReader("Success"))}, nil
|
||||
},
|
||||
},
|
||||
|
||||
@@ -51,7 +51,7 @@ func NewPushCommand(dockerCli command.Cli) *cobra.Command {
|
||||
"category-top": "6",
|
||||
"aliases": "docker image push, docker push",
|
||||
},
|
||||
ValidArgsFunction: completion.ImageNames(dockerCli),
|
||||
ValidArgsFunction: completion.ImageNames(dockerCli, 1),
|
||||
}
|
||||
|
||||
flags := cmd.Flags()
|
||||
|
||||
@@ -29,7 +29,7 @@ func NewRemoveCommand(dockerCli command.Cli) *cobra.Command {
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
return runRemove(cmd.Context(), dockerCli, opts, args)
|
||||
},
|
||||
ValidArgsFunction: completion.ImageNames(dockerCli),
|
||||
ValidArgsFunction: completion.ImageNames(dockerCli, -1),
|
||||
Annotations: map[string]string{
|
||||
"aliases": "docker image rm, docker image remove, docker rmi",
|
||||
},
|
||||
|
||||
@@ -21,7 +21,7 @@ func (n notFound) Error() string {
|
||||
return "Error: No such image: " + n.imageID
|
||||
}
|
||||
|
||||
func (n notFound) NotFound() {}
|
||||
func (notFound) NotFound() {}
|
||||
|
||||
func TestNewRemoveCommandAlias(t *testing.T) {
|
||||
cmd := newRemoveCommand(test.NewFakeCli(&fakeClient{}))
|
||||
|
||||
@@ -8,7 +8,7 @@ import (
|
||||
"github.com/docker/cli/cli"
|
||||
"github.com/docker/cli/cli/command"
|
||||
"github.com/docker/cli/cli/command/completion"
|
||||
"github.com/docker/docker/api/types/image"
|
||||
"github.com/docker/docker/client"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
@@ -34,7 +34,7 @@ func NewSaveCommand(dockerCli command.Cli) *cobra.Command {
|
||||
Annotations: map[string]string{
|
||||
"aliases": "docker image save, docker save",
|
||||
},
|
||||
ValidArgsFunction: completion.ImageNames(dockerCli),
|
||||
ValidArgsFunction: completion.ImageNames(dockerCli, -1),
|
||||
}
|
||||
|
||||
flags := cmd.Flags()
|
||||
@@ -57,17 +57,17 @@ func RunSave(ctx context.Context, dockerCli command.Cli, opts saveOptions) error
|
||||
return errors.Wrap(err, "failed to save image")
|
||||
}
|
||||
|
||||
var options image.SaveOptions
|
||||
var options []client.ImageSaveOption
|
||||
if opts.platform != "" {
|
||||
p, err := platforms.Parse(opts.platform)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "invalid platform")
|
||||
}
|
||||
// TODO(thaJeztah): change flag-type to support multiple platforms.
|
||||
options.Platforms = append(options.Platforms, p)
|
||||
options = append(options, client.ImageSaveWithPlatforms(p))
|
||||
}
|
||||
|
||||
responseBody, err := dockerCli.Client().ImageSave(ctx, opts.images, options)
|
||||
responseBody, err := dockerCli.Client().ImageSave(ctx, opts.images, options...)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -8,8 +8,7 @@ import (
|
||||
"testing"
|
||||
|
||||
"github.com/docker/cli/internal/test"
|
||||
"github.com/docker/docker/api/types/image"
|
||||
ocispec "github.com/opencontainers/image-spec/specs-go/v1"
|
||||
"github.com/docker/docker/client"
|
||||
"gotest.tools/v3/assert"
|
||||
is "gotest.tools/v3/assert/cmp"
|
||||
)
|
||||
@@ -20,7 +19,7 @@ func TestNewSaveCommandErrors(t *testing.T) {
|
||||
args []string
|
||||
isTerminal bool
|
||||
expectedError string
|
||||
imageSaveFunc func(images []string, options image.SaveOptions) (io.ReadCloser, error)
|
||||
imageSaveFunc func(images []string, options ...client.ImageSaveOption) (io.ReadCloser, error)
|
||||
}{
|
||||
{
|
||||
name: "wrong args",
|
||||
@@ -38,7 +37,7 @@ func TestNewSaveCommandErrors(t *testing.T) {
|
||||
args: []string{"arg1"},
|
||||
isTerminal: false,
|
||||
expectedError: "error saving image",
|
||||
imageSaveFunc: func(images []string, options image.SaveOptions) (io.ReadCloser, error) {
|
||||
imageSaveFunc: func([]string, ...client.ImageSaveOption) (io.ReadCloser, error) {
|
||||
return io.NopCloser(strings.NewReader("")), errors.New("error saving image")
|
||||
},
|
||||
},
|
||||
@@ -75,13 +74,13 @@ func TestNewSaveCommandSuccess(t *testing.T) {
|
||||
testCases := []struct {
|
||||
args []string
|
||||
isTerminal bool
|
||||
imageSaveFunc func(images []string, options image.SaveOptions) (io.ReadCloser, error)
|
||||
imageSaveFunc func(images []string, options ...client.ImageSaveOption) (io.ReadCloser, error)
|
||||
deferredFunc func()
|
||||
}{
|
||||
{
|
||||
args: []string{"-o", "save_tmp_file", "arg1"},
|
||||
isTerminal: true,
|
||||
imageSaveFunc: func(images []string, _ image.SaveOptions) (io.ReadCloser, error) {
|
||||
imageSaveFunc: func(images []string, _ ...client.ImageSaveOption) (io.ReadCloser, error) {
|
||||
assert.Assert(t, is.Len(images, 1))
|
||||
assert.Check(t, is.Equal("arg1", images[0]))
|
||||
return io.NopCloser(strings.NewReader("")), nil
|
||||
@@ -93,7 +92,7 @@ func TestNewSaveCommandSuccess(t *testing.T) {
|
||||
{
|
||||
args: []string{"arg1", "arg2"},
|
||||
isTerminal: false,
|
||||
imageSaveFunc: func(images []string, _ image.SaveOptions) (io.ReadCloser, error) {
|
||||
imageSaveFunc: func(images []string, _ ...client.ImageSaveOption) (io.ReadCloser, error) {
|
||||
assert.Assert(t, is.Len(images, 2))
|
||||
assert.Check(t, is.Equal("arg1", images[0]))
|
||||
assert.Check(t, is.Equal("arg2", images[1]))
|
||||
@@ -103,10 +102,12 @@ func TestNewSaveCommandSuccess(t *testing.T) {
|
||||
{
|
||||
args: []string{"--platform", "linux/amd64", "arg1"},
|
||||
isTerminal: false,
|
||||
imageSaveFunc: func(images []string, options image.SaveOptions) (io.ReadCloser, error) {
|
||||
imageSaveFunc: func(images []string, options ...client.ImageSaveOption) (io.ReadCloser, error) {
|
||||
assert.Assert(t, is.Len(images, 1))
|
||||
assert.Check(t, is.Equal("arg1", images[0]))
|
||||
assert.Check(t, is.DeepEqual([]ocispec.Platform{{OS: "linux", Architecture: "amd64"}}, options.Platforms))
|
||||
// FIXME(thaJeztah): need to find appropriate way to test the result of "ImageHistoryWithPlatform" being applied
|
||||
assert.Check(t, len(options) > 0) // can be 1 or two depending on whether a terminal is attached :/
|
||||
// assert.Check(t, is.Contains(options, client.ImageHistoryWithPlatform(ocispec.Platform{OS: "linux", Architecture: "amd64"})))
|
||||
return io.NopCloser(strings.NewReader("")), nil
|
||||
},
|
||||
},
|
||||
|
||||
@@ -30,7 +30,7 @@ func NewTagCommand(dockerCli command.Cli) *cobra.Command {
|
||||
Annotations: map[string]string{
|
||||
"aliases": "docker image tag, docker tag",
|
||||
},
|
||||
ValidArgsFunction: completion.ImageNames(dockerCli),
|
||||
ValidArgsFunction: completion.ImageNames(dockerCli, 2),
|
||||
}
|
||||
|
||||
flags := cmd.Flags()
|
||||
|
||||
@@ -281,7 +281,8 @@ func (ctx *nodeInspectContext) ResourceNanoCPUs() int {
|
||||
if ctx.Node.Description.Resources.NanoCPUs == 0 {
|
||||
return int(0)
|
||||
}
|
||||
return int(ctx.Node.Description.Resources.NanoCPUs) / 1e9
|
||||
const nano = 1e9
|
||||
return int(ctx.Node.Description.Resources.NanoCPUs) / nano
|
||||
}
|
||||
|
||||
func (ctx *nodeInspectContext) ResourceMemory() string {
|
||||
|
||||
@@ -73,11 +73,11 @@ func (c *fakeClient) PluginInspectWithRaw(_ context.Context, name string) (*type
|
||||
return nil, nil, nil
|
||||
}
|
||||
|
||||
func (c *fakeClient) Info(context.Context) (system.Info, error) {
|
||||
func (*fakeClient) Info(context.Context) (system.Info, error) {
|
||||
return system.Info{}, nil
|
||||
}
|
||||
|
||||
func (c *fakeClient) PluginUpgrade(ctx context.Context, name string, options types.PluginInstallOptions) (io.ReadCloser, error) {
|
||||
func (c *fakeClient) PluginUpgrade(_ context.Context, name string, options types.PluginInstallOptions) (io.ReadCloser, error) {
|
||||
if c.pluginUpgradeFunc != nil {
|
||||
return c.pluginUpgradeFunc(name, options)
|
||||
}
|
||||
|
||||
@@ -33,11 +33,11 @@ type fakeClient struct {
|
||||
client.Client
|
||||
}
|
||||
|
||||
func (c *fakeClient) Info(context.Context) (system.Info, error) {
|
||||
func (*fakeClient) Info(context.Context) (system.Info, error) {
|
||||
return system.Info{}, nil
|
||||
}
|
||||
|
||||
func (c *fakeClient) RegistryLogin(_ context.Context, auth registrytypes.AuthConfig) (registrytypes.AuthenticateOKBody, error) {
|
||||
func (*fakeClient) RegistryLogin(_ context.Context, auth registrytypes.AuthConfig) (registrytypes.AuthenticateOKBody, error) {
|
||||
if auth.Password == expiredPassword {
|
||||
return registrytypes.AuthenticateOKBody{}, errors.New("Invalid Username or Password")
|
||||
}
|
||||
|
||||
@@ -21,19 +21,19 @@ func (f fakeConfigAPIClientList) ConfigList(ctx context.Context, opts types.Conf
|
||||
return f(ctx, opts)
|
||||
}
|
||||
|
||||
func (f fakeConfigAPIClientList) ConfigCreate(_ context.Context, _ swarm.ConfigSpec) (types.ConfigCreateResponse, error) {
|
||||
func (fakeConfigAPIClientList) ConfigCreate(_ context.Context, _ swarm.ConfigSpec) (types.ConfigCreateResponse, error) {
|
||||
return types.ConfigCreateResponse{}, nil
|
||||
}
|
||||
|
||||
func (f fakeConfigAPIClientList) ConfigRemove(_ context.Context, _ string) error {
|
||||
func (fakeConfigAPIClientList) ConfigRemove(_ context.Context, _ string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (f fakeConfigAPIClientList) ConfigInspectWithRaw(_ context.Context, _ string) (swarm.Config, []byte, error) {
|
||||
func (fakeConfigAPIClientList) ConfigInspectWithRaw(_ context.Context, _ string) (swarm.Config, []byte, error) {
|
||||
return swarm.Config{}, nil, nil
|
||||
}
|
||||
|
||||
func (f fakeConfigAPIClientList) ConfigUpdate(_ context.Context, _ string, _ swarm.Version, _ swarm.ConfigSpec) error {
|
||||
func (fakeConfigAPIClientList) ConfigUpdate(_ context.Context, _ string, _ swarm.Version, _ swarm.ConfigSpec) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
|
||||
@@ -503,7 +503,8 @@ func (ctx *serviceInspectContext) ResourceReservationNanoCPUs() float64 {
|
||||
if ctx.Service.Spec.TaskTemplate.Resources.Reservations.NanoCPUs == 0 {
|
||||
return float64(0)
|
||||
}
|
||||
return float64(ctx.Service.Spec.TaskTemplate.Resources.Reservations.NanoCPUs) / 1e9
|
||||
const nano = 1e9
|
||||
return float64(ctx.Service.Spec.TaskTemplate.Resources.Reservations.NanoCPUs) / nano
|
||||
}
|
||||
|
||||
func (ctx *serviceInspectContext) ResourceReservationMemory() string {
|
||||
@@ -521,7 +522,8 @@ func (ctx *serviceInspectContext) HasResourceLimits() bool {
|
||||
}
|
||||
|
||||
func (ctx *serviceInspectContext) ResourceLimitsNanoCPUs() float64 {
|
||||
return float64(ctx.Service.Spec.TaskTemplate.Resources.Limits.NanoCPUs) / 1e9
|
||||
const nano = 1e9
|
||||
return float64(ctx.Service.Spec.TaskTemplate.Resources.Limits.NanoCPUs) / nano
|
||||
}
|
||||
|
||||
func (ctx *serviceInspectContext) ResourceLimitMemory() string {
|
||||
|
||||
@@ -43,7 +43,9 @@ func ParseGenericResources(value []string) ([]swarm.GenericResource, error) {
|
||||
swarmResources := genericResourcesFromGRPC(resources)
|
||||
for _, res := range swarmResources {
|
||||
if res.NamedResourceSpec != nil {
|
||||
return nil, fmt.Errorf("invalid generic-resource request `%s=%s`, Named Generic Resources is not supported for service create or update", res.NamedResourceSpec.Kind, res.NamedResourceSpec.Value)
|
||||
return nil, fmt.Errorf("invalid generic-resource request `%s=%s`, Named Generic Resources is not supported for service create or update",
|
||||
res.NamedResourceSpec.Kind, res.NamedResourceSpec.Value,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -265,7 +265,7 @@ func (lw *logWriter) Write(buf []byte) (int, error) {
|
||||
// and then create a context from the details
|
||||
// this removes the context-specific details from the details map, so we
|
||||
// can more easily print the details later
|
||||
logCtx, err := lw.parseContext(details)
|
||||
logCtx, err := parseContext(details)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
@@ -317,7 +317,7 @@ func (lw *logWriter) Write(buf []byte) (int, error) {
|
||||
}
|
||||
|
||||
// parseContext returns a log context and REMOVES the context from the details map
|
||||
func (lw *logWriter) parseContext(details map[string]string) (logContext, error) {
|
||||
func parseContext(details map[string]string) (logContext, error) {
|
||||
nodeID, ok := details["com.docker.swarm.node.id"]
|
||||
if !ok {
|
||||
return logContext{}, errors.Errorf("missing node id in details: %v", details)
|
||||
|
||||
@@ -42,7 +42,7 @@ func (i *Uint64Opt) Set(s string) error {
|
||||
}
|
||||
|
||||
// Type returns the type of this option, which will be displayed in `--help` output
|
||||
func (i *Uint64Opt) Type() string {
|
||||
func (*Uint64Opt) Type() string {
|
||||
return "uint"
|
||||
}
|
||||
|
||||
@@ -67,7 +67,7 @@ func (f *floatValue) Set(s string) error {
|
||||
return err
|
||||
}
|
||||
|
||||
func (f *floatValue) Type() string {
|
||||
func (*floatValue) Type() string {
|
||||
return "float"
|
||||
}
|
||||
|
||||
@@ -114,7 +114,7 @@ func (o *placementPrefOpts) Set(value string) error {
|
||||
}
|
||||
|
||||
// Type returns a string name for this Option type
|
||||
func (o *placementPrefOpts) Type() string {
|
||||
func (*placementPrefOpts) Type() string {
|
||||
return "pref"
|
||||
}
|
||||
|
||||
@@ -132,7 +132,7 @@ func (s *ShlexOpt) Set(value string) error {
|
||||
}
|
||||
|
||||
// Type returns the type of the value
|
||||
func (s *ShlexOpt) Type() string {
|
||||
func (*ShlexOpt) Type() string {
|
||||
return "command"
|
||||
}
|
||||
|
||||
@@ -363,7 +363,7 @@ func (c *credentialSpecOpt) Set(value string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *credentialSpecOpt) Type() string {
|
||||
func (*credentialSpecOpt) Type() string {
|
||||
return "credential-spec"
|
||||
}
|
||||
|
||||
|
||||
@@ -273,8 +273,9 @@ func truncError(errMsg string) string {
|
||||
|
||||
// Limit the length to 75 characters, so that even on narrow terminals
|
||||
// this will not overflow to the next line.
|
||||
if len(errMsg) > 75 {
|
||||
errMsg = errMsg[:74] + "…"
|
||||
const maxWidth = 75
|
||||
if len(errMsg) > maxWidth {
|
||||
errMsg = errMsg[:maxWidth-1] + "…"
|
||||
}
|
||||
return errMsg
|
||||
}
|
||||
@@ -349,7 +350,7 @@ func (u *replicatedProgressUpdater) update(service swarm.Service, tasks []swarm.
|
||||
return running == replicas, nil
|
||||
}
|
||||
|
||||
func (u *replicatedProgressUpdater) tasksBySlot(tasks []swarm.Task, activeNodes map[string]struct{}) map[int]swarm.Task {
|
||||
func (*replicatedProgressUpdater) tasksBySlot(tasks []swarm.Task, activeNodes map[string]struct{}) map[int]swarm.Task {
|
||||
// If there are multiple tasks with the same slot number, favor the one
|
||||
// with the *lowest* desired state. This can happen in restart
|
||||
// scenarios.
|
||||
@@ -470,7 +471,7 @@ func (u *globalProgressUpdater) update(_ swarm.Service, tasks []swarm.Task, acti
|
||||
return running == nodeCount, nil
|
||||
}
|
||||
|
||||
func (u *globalProgressUpdater) tasksByNode(tasks []swarm.Task) map[string]swarm.Task {
|
||||
func (*globalProgressUpdater) tasksByNode(tasks []swarm.Task) map[string]swarm.Task {
|
||||
// If there are multiple tasks with the same node ID, favor the one
|
||||
// with the *lowest* desired state. This can happen in restart
|
||||
// scenarios.
|
||||
|
||||
@@ -508,19 +508,19 @@ func (s secretAPIClientMock) SecretList(context.Context, types.SecretListOptions
|
||||
return s.listResult, nil
|
||||
}
|
||||
|
||||
func (s secretAPIClientMock) SecretCreate(context.Context, swarm.SecretSpec) (types.SecretCreateResponse, error) {
|
||||
func (secretAPIClientMock) SecretCreate(context.Context, swarm.SecretSpec) (types.SecretCreateResponse, error) {
|
||||
return types.SecretCreateResponse{}, nil
|
||||
}
|
||||
|
||||
func (s secretAPIClientMock) SecretRemove(context.Context, string) error {
|
||||
func (secretAPIClientMock) SecretRemove(context.Context, string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s secretAPIClientMock) SecretInspectWithRaw(context.Context, string) (swarm.Secret, []byte, error) {
|
||||
func (secretAPIClientMock) SecretInspectWithRaw(context.Context, string) (swarm.Secret, []byte, error) {
|
||||
return swarm.Secret{}, []byte{}, nil
|
||||
}
|
||||
|
||||
func (s secretAPIClientMock) SecretUpdate(context.Context, string, swarm.Version, swarm.SecretSpec) error {
|
||||
func (secretAPIClientMock) SecretUpdate(context.Context, string, swarm.Version, swarm.SecretSpec) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
|
||||
@@ -44,7 +44,7 @@ type fakeClient struct {
|
||||
configRemoveFunc func(configID string) error
|
||||
}
|
||||
|
||||
func (cli *fakeClient) ServerVersion(context.Context) (types.Version, error) {
|
||||
func (*fakeClient) ServerVersion(context.Context) (types.Version, error) {
|
||||
return types.Version{
|
||||
Version: "docker-dev",
|
||||
APIVersion: api.DefaultVersion,
|
||||
@@ -180,7 +180,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 (*fakeClient) ServiceInspectWithRaw(_ context.Context, serviceID string, _ types.ServiceInspectOptions) (swarm.Service, []byte, error) {
|
||||
return swarm.Service{
|
||||
ID: serviceID,
|
||||
Spec: swarm.ServiceSpec{
|
||||
|
||||
@@ -44,7 +44,7 @@ type fakeClient struct {
|
||||
configRemoveFunc func(configID string) error
|
||||
}
|
||||
|
||||
func (cli *fakeClient) ServerVersion(context.Context) (types.Version, error) {
|
||||
func (*fakeClient) ServerVersion(context.Context) (types.Version, error) {
|
||||
return types.Version{
|
||||
Version: "docker-dev",
|
||||
APIVersion: api.DefaultVersion,
|
||||
|
||||
@@ -14,7 +14,7 @@ type notFound struct {
|
||||
error
|
||||
}
|
||||
|
||||
func (n notFound) NotFound() {}
|
||||
func (notFound) NotFound() {}
|
||||
|
||||
func TestValidateExternalNetworks(t *testing.T) {
|
||||
testcases := []struct {
|
||||
|
||||
@@ -57,7 +57,7 @@ func newInitCommand(dockerCli command.Cli) *cobra.Command {
|
||||
flags.BoolVar(&opts.forceNewCluster, "force-new-cluster", false, "Force create a new cluster from current state")
|
||||
flags.BoolVar(&opts.autolock, flagAutolock, false, "Enable manager autolocking (requiring an unlock key to start a stopped manager)")
|
||||
flags.StringVar(&opts.availability, flagAvailability, "active", `Availability of the node ("active", "pause", "drain")`)
|
||||
flags.Var(newIPNetSliceValue([]net.IPNet{}, &opts.defaultAddrPools), flagDefaultAddrPool, "default address pool in CIDR format")
|
||||
flags.IPNetSliceVar(&opts.defaultAddrPools, flagDefaultAddrPool, []net.IPNet{}, "default address pool in CIDR format")
|
||||
flags.SetAnnotation(flagDefaultAddrPool, "version", []string{"1.39"})
|
||||
flags.Uint32Var(&opts.DefaultAddrPoolMaskLength, flagDefaultAddrPoolMaskLength, 24, "default address pool subnet mask length")
|
||||
flags.SetAnnotation(flagDefaultAddrPoolMaskLength, "version", []string{"1.39"})
|
||||
|
||||
@@ -1,92 +0,0 @@
|
||||
package swarm
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/csv"
|
||||
"fmt"
|
||||
"io"
|
||||
"net"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// -- ipNetSlice Value
|
||||
type ipNetSliceValue struct {
|
||||
value *[]net.IPNet
|
||||
changed bool
|
||||
}
|
||||
|
||||
func newIPNetSliceValue(val []net.IPNet, p *[]net.IPNet) *ipNetSliceValue {
|
||||
ipnsv := new(ipNetSliceValue)
|
||||
ipnsv.value = p
|
||||
*ipnsv.value = val
|
||||
return ipnsv
|
||||
}
|
||||
|
||||
// Set converts, and assigns, the comma-separated IPNet argument string representation as the []net.IPNet value of this flag.
|
||||
// If Set is called on a flag that already has a []net.IPNet assigned, the newly converted values will be appended.
|
||||
func (s *ipNetSliceValue) Set(val string) error {
|
||||
// remove all quote characters
|
||||
rmQuote := strings.NewReplacer(`"`, "", `'`, "", "`", "")
|
||||
|
||||
// read flag arguments with CSV parser
|
||||
ipNetStrSlice, err := readAsCSV(rmQuote.Replace(val))
|
||||
if err != nil && err != io.EOF {
|
||||
return err
|
||||
}
|
||||
|
||||
// parse ip values into slice
|
||||
out := make([]net.IPNet, 0, len(ipNetStrSlice))
|
||||
for _, ipNetStr := range ipNetStrSlice {
|
||||
_, n, err := net.ParseCIDR(strings.TrimSpace(ipNetStr))
|
||||
if err != nil {
|
||||
return fmt.Errorf("invalid string being converted to CIDR: %s", ipNetStr)
|
||||
}
|
||||
out = append(out, *n)
|
||||
}
|
||||
|
||||
if !s.changed {
|
||||
*s.value = out
|
||||
} else {
|
||||
*s.value = append(*s.value, out...)
|
||||
}
|
||||
|
||||
s.changed = true
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Type returns a string that uniquely represents this flag's type.
|
||||
func (s *ipNetSliceValue) Type() string {
|
||||
return "ipNetSlice"
|
||||
}
|
||||
|
||||
// String defines a "native" format for this net.IPNet slice flag value.
|
||||
func (s *ipNetSliceValue) String() string {
|
||||
ipNetStrSlice := make([]string, len(*s.value))
|
||||
for i, n := range *s.value {
|
||||
ipNetStrSlice[i] = n.String()
|
||||
}
|
||||
|
||||
out, _ := writeAsCSV(ipNetStrSlice)
|
||||
return "[" + out + "]"
|
||||
}
|
||||
|
||||
func readAsCSV(val string) ([]string, error) {
|
||||
if val == "" {
|
||||
return []string{}, nil
|
||||
}
|
||||
stringReader := strings.NewReader(val)
|
||||
csvReader := csv.NewReader(stringReader)
|
||||
return csvReader.Read()
|
||||
}
|
||||
|
||||
func writeAsCSV(vals []string) (string, error) {
|
||||
b := &bytes.Buffer{}
|
||||
w := csv.NewWriter(b)
|
||||
err := w.Write(vals)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
w.Flush()
|
||||
return strings.TrimSuffix(b.String(), "\n"), nil
|
||||
}
|
||||
@@ -1,148 +0,0 @@
|
||||
package swarm
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/spf13/pflag"
|
||||
)
|
||||
|
||||
// Helper function to set static slices
|
||||
func getCIDR(_ net.IP, cidr *net.IPNet, _ error) net.IPNet {
|
||||
return *cidr
|
||||
}
|
||||
|
||||
func equalCIDR(c1 net.IPNet, c2 net.IPNet) bool {
|
||||
return c1.String() == c2.String()
|
||||
}
|
||||
|
||||
func setUpIPNetFlagSet(ipsp *[]net.IPNet) *pflag.FlagSet {
|
||||
f := pflag.NewFlagSet("test", pflag.ContinueOnError)
|
||||
f.Var(newIPNetSliceValue([]net.IPNet{}, ipsp), "cidrs", "Command separated list!")
|
||||
return f
|
||||
}
|
||||
|
||||
func TestIPNets(t *testing.T) {
|
||||
var ips []net.IPNet
|
||||
f := setUpIPNetFlagSet(&ips)
|
||||
|
||||
vals := []string{"192.168.1.1/24", "10.0.0.1/16", "fd00:0:0:0:0:0:0:2/64"}
|
||||
arg := "--cidrs=" + strings.Join(vals, ",")
|
||||
err := f.Parse([]string{arg})
|
||||
if err != nil {
|
||||
t.Fatal("expected no error; got", err)
|
||||
}
|
||||
for i, v := range ips {
|
||||
if _, cidr, _ := net.ParseCIDR(vals[i]); cidr == nil {
|
||||
t.Fatalf("invalid string being converted to CIDR: %s", vals[i])
|
||||
} else if !equalCIDR(*cidr, v) {
|
||||
t.Fatalf("expected ips[%d] to be %s but got: %s from GetIPSlice", i, vals[i], v)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestIPNetCalledTwice(t *testing.T) {
|
||||
var cidrs []net.IPNet
|
||||
f := setUpIPNetFlagSet(&cidrs)
|
||||
|
||||
in := []string{"192.168.1.2/16,fd00::/64", "10.0.0.1/24"}
|
||||
|
||||
expected := []net.IPNet{
|
||||
getCIDR(net.ParseCIDR("192.168.1.2/16")),
|
||||
getCIDR(net.ParseCIDR("fd00::/64")),
|
||||
getCIDR(net.ParseCIDR("10.0.0.1/24")),
|
||||
}
|
||||
argfmt := "--cidrs=%s"
|
||||
arg1 := fmt.Sprintf(argfmt, in[0])
|
||||
arg2 := fmt.Sprintf(argfmt, in[1])
|
||||
err := f.Parse([]string{arg1, arg2})
|
||||
if err != nil {
|
||||
t.Fatal("expected no error; got", err)
|
||||
}
|
||||
for i, v := range cidrs {
|
||||
if !equalCIDR(expected[i], v) {
|
||||
t.Fatalf("expected cidrs[%d] to be %s but got: %s", i, expected[i], v)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestIPNetBadQuoting(t *testing.T) {
|
||||
tests := []struct {
|
||||
Want []net.IPNet
|
||||
FlagArg []string
|
||||
}{
|
||||
{
|
||||
Want: []net.IPNet{
|
||||
getCIDR(net.ParseCIDR("a4ab:61d:f03e:5d7d:fad7:d4c2:a1a5:568/128")),
|
||||
getCIDR(net.ParseCIDR("203.107.49.208/32")),
|
||||
getCIDR(net.ParseCIDR("14.57.204.90/32")),
|
||||
},
|
||||
FlagArg: []string{
|
||||
"a4ab:61d:f03e:5d7d:fad7:d4c2:a1a5:568/128",
|
||||
"203.107.49.208/32",
|
||||
"14.57.204.90/32",
|
||||
},
|
||||
},
|
||||
{
|
||||
Want: []net.IPNet{
|
||||
getCIDR(net.ParseCIDR("204.228.73.195/32")),
|
||||
getCIDR(net.ParseCIDR("86.141.15.94/32")),
|
||||
},
|
||||
FlagArg: []string{
|
||||
"204.228.73.195/32",
|
||||
"86.141.15.94/32",
|
||||
},
|
||||
},
|
||||
{
|
||||
Want: []net.IPNet{
|
||||
getCIDR(net.ParseCIDR("c70c:db36:3001:890f:c6ea:3f9b:7a39:cc3f/128")),
|
||||
getCIDR(net.ParseCIDR("4d17:1d6e:e699:bd7a:88c5:5e7e:ac6a:4472/128")),
|
||||
},
|
||||
FlagArg: []string{
|
||||
"c70c:db36:3001:890f:c6ea:3f9b:7a39:cc3f/128",
|
||||
"4d17:1d6e:e699:bd7a:88c5:5e7e:ac6a:4472/128",
|
||||
},
|
||||
},
|
||||
{
|
||||
Want: []net.IPNet{
|
||||
getCIDR(net.ParseCIDR("5170:f971:cfac:7be3:512a:af37:952c:bc33/128")),
|
||||
getCIDR(net.ParseCIDR("93.21.145.140/32")),
|
||||
getCIDR(net.ParseCIDR("2cac:61d3:c5ff:6caf:73e0:1b1a:c336:c1ca/128")),
|
||||
},
|
||||
FlagArg: []string{
|
||||
" 5170:f971:cfac:7be3:512a:af37:952c:bc33/128 , 93.21.145.140/32 ",
|
||||
"2cac:61d3:c5ff:6caf:73e0:1b1a:c336:c1ca/128",
|
||||
},
|
||||
},
|
||||
{
|
||||
Want: []net.IPNet{
|
||||
getCIDR(net.ParseCIDR("2e5e:66b2:6441:848:5b74:76ea:574c:3a7b/128")),
|
||||
getCIDR(net.ParseCIDR("2e5e:66b2:6441:848:5b74:76ea:574c:3a7b/128")),
|
||||
getCIDR(net.ParseCIDR("2e5e:66b2:6441:848:5b74:76ea:574c:3a7b/128")),
|
||||
getCIDR(net.ParseCIDR("2e5e:66b2:6441:848:5b74:76ea:574c:3a7b/128")),
|
||||
},
|
||||
FlagArg: []string{
|
||||
`"2e5e:66b2:6441:848:5b74:76ea:574c:3a7b/128, 2e5e:66b2:6441:848:5b74:76ea:574c:3a7b/128,2e5e:66b2:6441:848:5b74:76ea:574c:3a7b/128 "`,
|
||||
" 2e5e:66b2:6441:848:5b74:76ea:574c:3a7b/128",
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for i, test := range tests {
|
||||
var cidrs []net.IPNet
|
||||
f := setUpIPNetFlagSet(&cidrs)
|
||||
|
||||
if err := f.Parse([]string{"--cidrs=" + strings.Join(test.FlagArg, ",")}); err != nil {
|
||||
t.Fatalf("flag parsing failed with error: %s\nparsing:\t%#v\nwant:\t\t%s",
|
||||
err, test.FlagArg, test.Want[i])
|
||||
}
|
||||
|
||||
for j, b := range cidrs {
|
||||
if !equalCIDR(b, test.Want[j]) {
|
||||
t.Fatalf("bad value parsed for test %d on net.IP %d:\nwant:\t%s\ngot:\t%s", i, j, test.Want[j], b)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -68,7 +68,7 @@ func (a *NodeAddrOption) Set(value string) error {
|
||||
}
|
||||
|
||||
// Type returns the type of this flag
|
||||
func (a *NodeAddrOption) Type() string {
|
||||
func (*NodeAddrOption) Type() string {
|
||||
return "node-addr"
|
||||
}
|
||||
|
||||
@@ -104,7 +104,7 @@ func (m *ExternalCAOption) Set(value string) error {
|
||||
}
|
||||
|
||||
// Type returns the type of this option.
|
||||
func (m *ExternalCAOption) Type() string {
|
||||
func (*ExternalCAOption) Type() string {
|
||||
return "external-ca"
|
||||
}
|
||||
|
||||
@@ -129,7 +129,7 @@ type PEMFile struct {
|
||||
}
|
||||
|
||||
// Type returns the type of this option.
|
||||
func (p *PEMFile) Type() string {
|
||||
func (*PEMFile) Type() string {
|
||||
return "pem-file"
|
||||
}
|
||||
|
||||
|
||||
@@ -110,7 +110,7 @@ type nopCloseReader struct {
|
||||
halfReadWriteCloser
|
||||
}
|
||||
|
||||
func (x *nopCloseReader) CloseRead() error {
|
||||
func (*nopCloseReader) CloseRead() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
|
||||
@@ -54,11 +54,11 @@ func (cli *DockerCli) Resource() *resource.Resource {
|
||||
return cli.res.Get()
|
||||
}
|
||||
|
||||
func (cli *DockerCli) TracerProvider() trace.TracerProvider {
|
||||
func (*DockerCli) TracerProvider() trace.TracerProvider {
|
||||
return otel.GetTracerProvider()
|
||||
}
|
||||
|
||||
func (cli *DockerCli) MeterProvider() metric.MeterProvider {
|
||||
func (*DockerCli) MeterProvider() metric.MeterProvider {
|
||||
return otel.GetMeterProvider()
|
||||
}
|
||||
|
||||
|
||||
@@ -28,15 +28,15 @@ type fakeClient struct {
|
||||
client.Client
|
||||
}
|
||||
|
||||
func (c *fakeClient) Info(context.Context) (system.Info, error) {
|
||||
func (*fakeClient) Info(context.Context) (system.Info, error) {
|
||||
return system.Info{}, nil
|
||||
}
|
||||
|
||||
func (c *fakeClient) ImageInspect(context.Context, string, ...client.ImageInspectOption) (image.InspectResponse, error) {
|
||||
func (*fakeClient) ImageInspect(context.Context, string, ...client.ImageInspectOption) (image.InspectResponse, error) {
|
||||
return image.InspectResponse{}, nil
|
||||
}
|
||||
|
||||
func (c *fakeClient) ImagePush(context.Context, string, image.PushOptions) (io.ReadCloser, error) {
|
||||
func (*fakeClient) ImagePush(context.Context, string, image.PushOptions) (io.ReadCloser, error) {
|
||||
return &utils.NoopCloser{Reader: bytes.NewBuffer([]byte{})}, nil
|
||||
}
|
||||
|
||||
|
||||
@@ -68,19 +68,19 @@ func TestTrustSignerAddErrors(t *testing.T) {
|
||||
func TestSignerAddCommandNoTargetsKey(t *testing.T) {
|
||||
config.SetDir(t.TempDir())
|
||||
|
||||
tmpfile, err := os.CreateTemp("", "pemfile")
|
||||
tmpDir := t.TempDir()
|
||||
tmpFile, err := os.CreateTemp(tmpDir, "pemfile")
|
||||
assert.NilError(t, err)
|
||||
tmpfile.Close()
|
||||
defer os.Remove(tmpfile.Name())
|
||||
assert.Check(t, tmpFile.Close())
|
||||
|
||||
cli := test.NewFakeCli(&fakeClient{})
|
||||
cli.SetNotaryClient(notaryfake.GetEmptyTargetsNotaryRepository)
|
||||
cmd := newSignerAddCommand(cli)
|
||||
cmd.SetArgs([]string{"--key", tmpfile.Name(), "alice", "alpine", "linuxkit/alpine"})
|
||||
cmd.SetArgs([]string{"--key", tmpFile.Name(), "alice", "alpine", "linuxkit/alpine"})
|
||||
|
||||
cmd.SetOut(io.Discard)
|
||||
cmd.SetErr(io.Discard)
|
||||
assert.Error(t, cmd.Execute(), fmt.Sprintf("could not parse public key from file: %s: no valid public key found", tmpfile.Name()))
|
||||
assert.Error(t, cmd.Execute(), fmt.Sprintf("could not parse public key from file: %s: no valid public key found", tmpFile.Name()))
|
||||
}
|
||||
|
||||
func TestSignerAddCommandBadKeyPath(t *testing.T) {
|
||||
@@ -130,10 +130,10 @@ func TestIngestPublicKeys(t *testing.T) {
|
||||
}
|
||||
assert.Error(t, err, expectedError)
|
||||
// Call with real file path
|
||||
tmpfile, err := os.CreateTemp("", "pemfile")
|
||||
tmpDir := t.TempDir()
|
||||
tmpFile, err := os.CreateTemp(tmpDir, "pemfile")
|
||||
assert.NilError(t, err)
|
||||
tmpfile.Close()
|
||||
defer os.Remove(tmpfile.Name())
|
||||
_, err = ingestPublicKeys([]string{tmpfile.Name()})
|
||||
assert.Error(t, err, fmt.Sprintf("could not parse public key from file: %s: no valid public key found", tmpfile.Name()))
|
||||
assert.Check(t, tmpFile.Close())
|
||||
_, err = ingestPublicKeys([]string{tmpFile.Name()})
|
||||
assert.Error(t, err, fmt.Sprintf("could not parse public key from file: %s: no valid public key found", tmpFile.Name()))
|
||||
}
|
||||
|
||||
@@ -40,6 +40,9 @@ func handleVolumeToMount(
|
||||
) (mount.Mount, error) {
|
||||
result := createMountFromVolume(volume)
|
||||
|
||||
if volume.Image != nil {
|
||||
return mount.Mount{}, errors.New("images options are incompatible with type volume")
|
||||
}
|
||||
if volume.Tmpfs != nil {
|
||||
return mount.Mount{}, errors.New("tmpfs options are incompatible with type volume")
|
||||
}
|
||||
@@ -64,6 +67,7 @@ func handleVolumeToMount(
|
||||
|
||||
if volume.Volume != nil {
|
||||
result.VolumeOptions.NoCopy = volume.Volume.NoCopy
|
||||
result.VolumeOptions.Subpath = volume.Volume.Subpath
|
||||
}
|
||||
|
||||
if stackVolume.Name != "" {
|
||||
@@ -86,6 +90,32 @@ func handleVolumeToMount(
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func handleImageToMount(volume composetypes.ServiceVolumeConfig) (mount.Mount, error) {
|
||||
result := createMountFromVolume(volume)
|
||||
|
||||
if volume.Source == "" {
|
||||
return mount.Mount{}, errors.New("invalid image source, source cannot be empty")
|
||||
}
|
||||
if volume.Volume != nil {
|
||||
return mount.Mount{}, errors.New("volume options are incompatible with type image")
|
||||
}
|
||||
if volume.Bind != nil {
|
||||
return mount.Mount{}, errors.New("bind options are incompatible with type image")
|
||||
}
|
||||
if volume.Tmpfs != nil {
|
||||
return mount.Mount{}, errors.New("tmpfs options are incompatible with type image")
|
||||
}
|
||||
if volume.Cluster != nil {
|
||||
return mount.Mount{}, errors.New("cluster options are incompatible with type image")
|
||||
}
|
||||
if volume.Image != nil {
|
||||
result.ImageOptions = &mount.ImageOptions{
|
||||
Subpath: volume.Image.Subpath,
|
||||
}
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func handleBindToMount(volume composetypes.ServiceVolumeConfig) (mount.Mount, error) {
|
||||
result := createMountFromVolume(volume)
|
||||
|
||||
@@ -95,6 +125,9 @@ func handleBindToMount(volume composetypes.ServiceVolumeConfig) (mount.Mount, er
|
||||
if volume.Volume != nil {
|
||||
return mount.Mount{}, errors.New("volume options are incompatible with type bind")
|
||||
}
|
||||
if volume.Image != nil {
|
||||
return mount.Mount{}, errors.New("image options are incompatible with type bind")
|
||||
}
|
||||
if volume.Tmpfs != nil {
|
||||
return mount.Mount{}, errors.New("tmpfs options are incompatible with type bind")
|
||||
}
|
||||
@@ -121,6 +154,9 @@ func handleTmpfsToMount(volume composetypes.ServiceVolumeConfig) (mount.Mount, e
|
||||
if volume.Volume != nil {
|
||||
return mount.Mount{}, errors.New("volume options are incompatible with type tmpfs")
|
||||
}
|
||||
if volume.Image != nil {
|
||||
return mount.Mount{}, errors.New("image options are incompatible with type tmpfs")
|
||||
}
|
||||
if volume.Cluster != nil {
|
||||
return mount.Mount{}, errors.New("cluster options are incompatible with type tmpfs")
|
||||
}
|
||||
@@ -141,6 +177,9 @@ func handleNpipeToMount(volume composetypes.ServiceVolumeConfig) (mount.Mount, e
|
||||
if volume.Volume != nil {
|
||||
return mount.Mount{}, errors.New("volume options are incompatible with type npipe")
|
||||
}
|
||||
if volume.Image != nil {
|
||||
return mount.Mount{}, errors.New("image options are incompatible with type npipe")
|
||||
}
|
||||
if volume.Tmpfs != nil {
|
||||
return mount.Mount{}, errors.New("tmpfs options are incompatible with type npipe")
|
||||
}
|
||||
@@ -203,6 +242,8 @@ func convertVolumeToMount(
|
||||
switch volume.Type {
|
||||
case "volume", "":
|
||||
return handleVolumeToMount(volume, stackVolumes, namespace)
|
||||
case "image":
|
||||
return handleImageToMount(volume)
|
||||
case "bind":
|
||||
return handleBindToMount(volume)
|
||||
case "tmpfs":
|
||||
|
||||
@@ -269,7 +269,7 @@ type ForbiddenPropertiesError struct {
|
||||
Properties map[string]string
|
||||
}
|
||||
|
||||
func (e *ForbiddenPropertiesError) Error() string {
|
||||
func (*ForbiddenPropertiesError) Error() string {
|
||||
return "Configuration contains forbidden properties"
|
||||
}
|
||||
|
||||
|
||||
@@ -971,7 +971,7 @@ func uint32Ptr(value uint32) *uint32 {
|
||||
}
|
||||
|
||||
func TestFullExample(t *testing.T) {
|
||||
skip.If(t, runtime.GOOS == "windows", "FIXME: TestFullExample substitutes platform-specific HOME-directories and requires platform-specific golden files; see https://github.com/docker/cli/pull/4610")
|
||||
skip.If(t, runtime.GOOS == "windows", "FIXME: substitutes platform-specific HOME-dirs and requires platform-specific golden files; see https://github.com/docker/cli/pull/4610")
|
||||
|
||||
data, err := os.ReadFile("full-example.yml")
|
||||
assert.NilError(t, err)
|
||||
|
||||
@@ -22,7 +22,7 @@ const (
|
||||
|
||||
type portsFormatChecker struct{}
|
||||
|
||||
func (checker portsFormatChecker) IsFormat(input any) bool {
|
||||
func (portsFormatChecker) IsFormat(input any) bool {
|
||||
var portSpec string
|
||||
|
||||
switch p := input.(type) {
|
||||
@@ -38,7 +38,7 @@ func (checker portsFormatChecker) IsFormat(input any) bool {
|
||||
|
||||
type durationFormatChecker struct{}
|
||||
|
||||
func (checker durationFormatChecker) IsFormat(input any) bool {
|
||||
func (durationFormatChecker) IsFormat(input any) bool {
|
||||
value, ok := input.(string)
|
||||
if !ok {
|
||||
return false
|
||||
|
||||
@@ -398,6 +398,7 @@ type ServiceVolumeConfig struct {
|
||||
Consistency string `yaml:",omitempty" json:"consistency,omitempty"`
|
||||
Bind *ServiceVolumeBind `yaml:",omitempty" json:"bind,omitempty"`
|
||||
Volume *ServiceVolumeVolume `yaml:",omitempty" json:"volume,omitempty"`
|
||||
Image *ServiceVolumeImage `yaml:",omitempty" json:"image,omitempty"`
|
||||
Tmpfs *ServiceVolumeTmpfs `yaml:",omitempty" json:"tmpfs,omitempty"`
|
||||
Cluster *ServiceVolumeCluster `yaml:",omitempty" json:"cluster,omitempty"`
|
||||
}
|
||||
@@ -409,7 +410,13 @@ type ServiceVolumeBind struct {
|
||||
|
||||
// ServiceVolumeVolume are options for a service volume of type volume
|
||||
type ServiceVolumeVolume struct {
|
||||
NoCopy bool `mapstructure:"nocopy" yaml:"nocopy,omitempty" json:"nocopy,omitempty"`
|
||||
NoCopy bool `mapstructure:"nocopy" yaml:"nocopy,omitempty" json:"nocopy,omitempty"`
|
||||
Subpath string `mapstructure:"subpath" yaml:"subpath,omitempty" json:"subpath,omitempty"`
|
||||
}
|
||||
|
||||
// ServiceVolumeImage are options for a service volume of type image
|
||||
type ServiceVolumeImage struct {
|
||||
Subpath string `mapstructure:"subpath" yaml:"subpath,omitempty" json:"subpath,omitempty"`
|
||||
}
|
||||
|
||||
// ServiceVolumeTmpfs are options for a service volume of type tmpfs
|
||||
|
||||
@@ -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 (*mockNativeStore) Store(_ types.AuthConfig) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
|
||||
@@ -26,7 +26,7 @@ func (f *fakeStore) GetAuthConfigs() map[string]types.AuthConfig {
|
||||
return f.configs
|
||||
}
|
||||
|
||||
func (f *fakeStore) GetFilename() string {
|
||||
func (*fakeStore) GetFilename() string {
|
||||
return "no-config.json"
|
||||
}
|
||||
|
||||
|
||||
@@ -33,18 +33,28 @@ import (
|
||||
)
|
||||
|
||||
// New returns net.Conn
|
||||
func New(_ context.Context, cmd string, args ...string) (net.Conn, error) {
|
||||
var (
|
||||
c commandConn
|
||||
err error
|
||||
)
|
||||
c.cmd = exec.Command(cmd, args...)
|
||||
func New(ctx context.Context, cmd string, args ...string) (net.Conn, error) {
|
||||
// Don't kill the ssh process if the context is cancelled. Killing the
|
||||
// ssh process causes an error when go's http.Client tries to reuse the
|
||||
// net.Conn (commandConn).
|
||||
//
|
||||
// Not passing down the Context might seem counter-intuitive, but in this
|
||||
// case, the lifetime of the process should be managed by the http.Client,
|
||||
// not the caller's Context.
|
||||
//
|
||||
// Further details;;
|
||||
//
|
||||
// - https://github.com/docker/cli/pull/3900
|
||||
// - https://github.com/docker/compose/issues/9448#issuecomment-1264263721
|
||||
ctx = context.WithoutCancel(ctx)
|
||||
c := commandConn{cmd: exec.CommandContext(ctx, cmd, args...)}
|
||||
// we assume that args never contains sensitive information
|
||||
logrus.Debugf("commandconn: starting %s with %v", cmd, args)
|
||||
c.cmd.Env = os.Environ()
|
||||
c.cmd.SysProcAttr = &syscall.SysProcAttr{}
|
||||
setPdeathsig(c.cmd)
|
||||
createSession(c.cmd)
|
||||
var err error
|
||||
c.stdin, err = c.cmd.StdinPipe()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -243,17 +253,17 @@ func (c *commandConn) RemoteAddr() net.Addr {
|
||||
return c.remoteAddr
|
||||
}
|
||||
|
||||
func (c *commandConn) SetDeadline(t time.Time) error {
|
||||
func (*commandConn) SetDeadline(t time.Time) error {
|
||||
logrus.Debugf("unimplemented call: SetDeadline(%v)", t)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *commandConn) SetReadDeadline(t time.Time) error {
|
||||
func (*commandConn) SetReadDeadline(t time.Time) error {
|
||||
logrus.Debugf("unimplemented call: SetReadDeadline(%v)", t)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *commandConn) SetWriteDeadline(t time.Time) error {
|
||||
func (*commandConn) SetWriteDeadline(t time.Time) error {
|
||||
logrus.Debugf("unimplemented call: SetWriteDeadline(%v)", t)
|
||||
return nil
|
||||
}
|
||||
|
||||
+2
-2
@@ -10,14 +10,14 @@ import (
|
||||
// Enable sets the DEBUG env var to true
|
||||
// and makes the logger to log at debug level.
|
||||
func Enable() {
|
||||
os.Setenv("DEBUG", "1")
|
||||
_ = os.Setenv("DEBUG", "1")
|
||||
logrus.SetLevel(logrus.DebugLevel)
|
||||
}
|
||||
|
||||
// Disable sets the DEBUG env var to false
|
||||
// and makes the logger to log at info level.
|
||||
func Disable() {
|
||||
os.Setenv("DEBUG", "")
|
||||
_ = os.Setenv("DEBUG", "")
|
||||
logrus.SetLevel(logrus.InfoLevel)
|
||||
}
|
||||
|
||||
|
||||
@@ -9,9 +9,9 @@ import (
|
||||
|
||||
func TestEnable(t *testing.T) {
|
||||
defer func() {
|
||||
os.Setenv("DEBUG", "")
|
||||
logrus.SetLevel(logrus.InfoLevel)
|
||||
}()
|
||||
t.Setenv("DEBUG", "")
|
||||
Enable()
|
||||
if os.Getenv("DEBUG") != "1" {
|
||||
t.Fatalf("expected DEBUG=1, got %s\n", os.Getenv("DEBUG"))
|
||||
@@ -22,6 +22,7 @@ func TestEnable(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestDisable(t *testing.T) {
|
||||
t.Setenv("DEBUG", "1")
|
||||
Disable()
|
||||
if os.Getenv("DEBUG") != "" {
|
||||
t.Fatalf("expected DEBUG=\"\", got %s\n", os.Getenv("DEBUG"))
|
||||
@@ -32,6 +33,7 @@ func TestDisable(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestEnabled(t *testing.T) {
|
||||
t.Setenv("DEBUG", "")
|
||||
Enable()
|
||||
if !IsEnabled() {
|
||||
t.Fatal("expected debug enabled, got false")
|
||||
|
||||
@@ -224,7 +224,7 @@ func postForm(ctx context.Context, reqURL string, data io.Reader) (*http.Respons
|
||||
return http.DefaultClient.Do(req)
|
||||
}
|
||||
|
||||
func (a API) GetAutoPAT(ctx context.Context, audience string, res TokenResponse) (string, error) {
|
||||
func (API) GetAutoPAT(ctx context.Context, audience string, res TokenResponse) (string, error) {
|
||||
patURL := audience + "/v2/access-tokens/desktop-generate"
|
||||
req, err := http.NewRequestWithContext(ctx, http.MethodPost, patURL, nil)
|
||||
if err != nil {
|
||||
|
||||
@@ -56,15 +56,19 @@ type Source struct {
|
||||
}
|
||||
|
||||
// GetClaims returns claims from an access token without verification.
|
||||
func GetClaims(accessToken string) (claims Claims, err error) {
|
||||
func GetClaims(accessToken string) (Claims, error) {
|
||||
token, err := parseSigned(accessToken)
|
||||
if err != nil {
|
||||
return
|
||||
return Claims{}, err
|
||||
}
|
||||
|
||||
var claims Claims
|
||||
err = token.UnsafeClaimsWithoutVerification(&claims)
|
||||
if err != nil {
|
||||
return Claims{}, err
|
||||
}
|
||||
|
||||
return
|
||||
return claims, nil
|
||||
}
|
||||
|
||||
// allowedSignatureAlgorithms is a list of allowed signature algorithms for JWTs.
|
||||
|
||||
@@ -14,7 +14,7 @@ import (
|
||||
)
|
||||
|
||||
const (
|
||||
//nolint:lll
|
||||
//nolint:revive // ignore line-length-limit
|
||||
validToken = "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6InhYa3BCdDNyV3MyRy11YjlscEpncSJ9.eyJodHRwczovL2h1Yi5kb2NrZXIuY29tIjp7ImVtYWlsIjoiYm9ya0Bkb2NrZXIuY29tIiwic2Vzc2lvbl9pZCI6ImEtc2Vzc2lvbi1pZCIsInNvdXJjZSI6InNhbWxwIiwidXNlcm5hbWUiOiJib3JrISIsInV1aWQiOiIwMTIzLTQ1Njc4OSJ9LCJpc3MiOiJodHRwczovL2xvZ2luLmRvY2tlci5jb20vIiwic3ViIjoic2FtbHB8c2FtbHAtZG9ja2VyfGJvcmtAZG9ja2VyLmNvbSIsImF1ZCI6WyJodHRwczovL2F1ZGllbmNlLmNvbSJdLCJpYXQiOjE3MTk1MDI5MzksImV4cCI6MTcxOTUwNjUzOSwic2NvcGUiOiJvcGVuaWQgb2ZmbGluZV9hY2Nlc3MifQ.VUSp-9_SOvMPWJPRrSh7p4kSPoye4DA3kyd2I0TW0QtxYSRq7xCzNj0NC_ywlPlKBFBeXKm4mh93d1vBSh79I9Heq5tj0Fr4KH77U5xJRMEpjHqoT5jxMEU1hYXX92xctnagBMXxDvzUfu3Yf0tvYSA0RRoGbGTHfdYYRwOrGbwQ75Qg1dyIxUkwsG053eYX2XkmLGxymEMgIq_gWksgAamOc40_0OCdGr-MmDeD2HyGUa309aGltzQUw7Z0zG1AKSXy3WwfMHdWNFioTAvQphwEyY3US8ybSJi78upSFTjwUcryMeHUwQ3uV9PxwPMyPoYxo1izVB-OUJxM8RqEbg"
|
||||
)
|
||||
|
||||
@@ -346,7 +346,7 @@ type fakeStore struct {
|
||||
configs map[string]types.AuthConfig
|
||||
}
|
||||
|
||||
func (f *fakeStore) Save() error {
|
||||
func (*fakeStore) Save() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -354,7 +354,7 @@ func (f *fakeStore) GetAuthConfigs() map[string]types.AuthConfig {
|
||||
return f.configs
|
||||
}
|
||||
|
||||
func (f *fakeStore) GetFilename() string {
|
||||
func (*fakeStore) GetFilename() string {
|
||||
return "/tmp/docker-fakestore"
|
||||
}
|
||||
|
||||
|
||||
@@ -44,7 +44,7 @@ func (s *fsStore) Get(listRef reference.Reference, manifest reference.Reference)
|
||||
return s.getFromFilename(manifest, filename)
|
||||
}
|
||||
|
||||
func (s *fsStore) getFromFilename(ref reference.Reference, filename string) (types.ImageManifest, error) {
|
||||
func (*fsStore) getFromFilename(ref reference.Reference, filename string) (types.ImageManifest, error) {
|
||||
bytes, err := os.ReadFile(filename)
|
||||
switch {
|
||||
case os.IsNotExist(err):
|
||||
@@ -165,7 +165,7 @@ func (n *notFoundError) Error() string {
|
||||
}
|
||||
|
||||
// NotFound interface
|
||||
func (n *notFoundError) NotFound() {}
|
||||
func (*notFoundError) NotFound() {}
|
||||
|
||||
// IsNotFound returns true if the error is a not found error
|
||||
func IsNotFound(err error) bool {
|
||||
|
||||
@@ -123,6 +123,6 @@ func (th *existingTokenHandler) AuthorizeRequest(req *http.Request, _ map[string
|
||||
return nil
|
||||
}
|
||||
|
||||
func (th *existingTokenHandler) Scheme() string {
|
||||
func (*existingTokenHandler) Scheme() string {
|
||||
return "bearer"
|
||||
}
|
||||
|
||||
@@ -304,4 +304,4 @@ func (n *notFoundError) Error() string {
|
||||
}
|
||||
|
||||
// NotFound satisfies interface github.com/docker/docker/errdefs.ErrNotFound
|
||||
func (n *notFoundError) NotFound() {}
|
||||
func (notFoundError) NotFound() {}
|
||||
|
||||
+1
-1
@@ -89,7 +89,7 @@ func (scs simpleCredentialStore) RefreshToken(*url.URL, string) string {
|
||||
return scs.auth.IdentityToken
|
||||
}
|
||||
|
||||
func (scs simpleCredentialStore) SetRefreshToken(*url.URL, string, string) {}
|
||||
func (simpleCredentialStore) SetRefreshToken(*url.URL, string, string) {}
|
||||
|
||||
// GetNotaryRepository returns a NotaryRepository which stores all the
|
||||
// information needed to operate on a notary repository.
|
||||
|
||||
@@ -127,7 +127,7 @@ type fakeClient struct {
|
||||
client.Client
|
||||
}
|
||||
|
||||
func (c *fakeClient) Ping(_ context.Context) (types.Ping, error) {
|
||||
func (*fakeClient) Ping(context.Context) (types.Ping, error) {
|
||||
return types.Ping{OSType: "linux"}, nil
|
||||
}
|
||||
|
||||
|
||||
@@ -32,7 +32,7 @@ type errCtxSignalTerminated struct {
|
||||
signal os.Signal
|
||||
}
|
||||
|
||||
func (e errCtxSignalTerminated) Error() string {
|
||||
func (errCtxSignalTerminated) Error() string {
|
||||
return ""
|
||||
}
|
||||
|
||||
|
||||
@@ -3,7 +3,10 @@
|
||||
ARG GO_VERSION=1.23.6
|
||||
ARG ALPINE_VERSION=3.21
|
||||
|
||||
ARG BUILDX_VERSION=0.17.1
|
||||
# BUILDX_VERSION sets the version of buildx to install in the dev container.
|
||||
# It must be a valid tag in the docker.io/docker/buildx-bin image repository
|
||||
# on Docker Hub.
|
||||
ARG BUILDX_VERSION=0.20.1
|
||||
FROM docker/buildx-bin:${BUILDX_VERSION} AS buildx
|
||||
|
||||
FROM golang:${GO_VERSION}-alpine${ALPINE_VERSION} AS golang
|
||||
@@ -11,7 +14,7 @@ ENV GOTOOLCHAIN=local
|
||||
ENV CGO_ENABLED=0
|
||||
|
||||
FROM golang AS gofumpt
|
||||
ARG GOFUMPT_VERSION=v0.6.0
|
||||
ARG GOFUMPT_VERSION=v0.7.0
|
||||
RUN --mount=type=cache,target=/root/.cache/go-build \
|
||||
--mount=type=cache,target=/go/pkg/mod \
|
||||
--mount=type=tmpfs,target=/go/src/ \
|
||||
@@ -19,14 +22,14 @@ RUN --mount=type=cache,target=/root/.cache/go-build \
|
||||
&& gofumpt --version
|
||||
|
||||
FROM golang AS gotestsum
|
||||
ARG GOTESTSUM_VERSION=v1.10.0
|
||||
ARG GOTESTSUM_VERSION=v1.12.0
|
||||
RUN --mount=type=cache,target=/root/.cache/go-build \
|
||||
--mount=type=cache,target=/go/pkg/mod \
|
||||
--mount=type=tmpfs,target=/go/src/ \
|
||||
GO111MODULE=on go install gotest.tools/gotestsum@${GOTESTSUM_VERSION}
|
||||
|
||||
FROM golang AS goversioninfo
|
||||
ARG GOVERSIONINFO_VERSION=v1.3.0
|
||||
ARG GOVERSIONINFO_VERSION=v1.4.1
|
||||
RUN --mount=type=cache,target=/root/.cache/go-build \
|
||||
--mount=type=cache,target=/go/pkg/mod \
|
||||
--mount=type=tmpfs,target=/go/src/ \
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
ARG GO_VERSION=1.23.6
|
||||
ARG ALPINE_VERSION=3.21
|
||||
ARG GOLANGCI_LINT_VERSION=v1.62.2
|
||||
ARG GOLANGCI_LINT_VERSION=v1.64.5
|
||||
|
||||
FROM golangci/golangci-lint:${GOLANGCI_LINT_VERSION}-alpine AS golangci-lint
|
||||
|
||||
|
||||
@@ -5,23 +5,23 @@ Initialize a swarm
|
||||
|
||||
### Options
|
||||
|
||||
| Name | Type | Default | Description |
|
||||
|:--------------------------------------------|:--------------|:---------------|:-----------------------------------------------------------------------------------------------------------------------------|
|
||||
| [`--advertise-addr`](#advertise-addr) | `string` | | Advertised address (format: `<ip\|interface>[:port]`) |
|
||||
| [`--autolock`](#autolock) | `bool` | | Enable manager autolocking (requiring an unlock key to start a stopped manager) |
|
||||
| [`--availability`](#availability) | `string` | `active` | Availability of the node (`active`, `pause`, `drain`) |
|
||||
| `--cert-expiry` | `duration` | `2160h0m0s` | Validity period for node certificates (ns\|us\|ms\|s\|m\|h) |
|
||||
| [`--data-path-addr`](#data-path-addr) | `string` | | Address or interface to use for data path traffic (format: `<ip\|interface>`) |
|
||||
| [`--data-path-port`](#data-path-port) | `uint32` | `0` | Port number to use for data path traffic (1024 - 49151). If no value is set or is set to 0, the default port (4789) is used. |
|
||||
| [`--default-addr-pool`](#default-addr-pool) | `ipNetSlice` | | default address pool in CIDR format |
|
||||
| `--default-addr-pool-mask-length` | `uint32` | `24` | default address pool subnet mask length |
|
||||
| `--dispatcher-heartbeat` | `duration` | `5s` | Dispatcher heartbeat period (ns\|us\|ms\|s\|m\|h) |
|
||||
| [`--external-ca`](#external-ca) | `external-ca` | | Specifications of one or more certificate signing endpoints |
|
||||
| [`--force-new-cluster`](#force-new-cluster) | `bool` | | Force create a new cluster from current state |
|
||||
| [`--listen-addr`](#listen-addr) | `node-addr` | `0.0.0.0:2377` | Listen address (format: `<ip\|interface>[:port]`) |
|
||||
| [`--max-snapshots`](#max-snapshots) | `uint64` | `0` | Number of additional Raft snapshots to retain |
|
||||
| [`--snapshot-interval`](#snapshot-interval) | `uint64` | `10000` | Number of log entries between Raft snapshots |
|
||||
| `--task-history-limit` | `int64` | `5` | Task history retention limit |
|
||||
| Name | Type | Default | Description |
|
||||
|:--------------------------------------------------|:--------------|:---------------|:-----------------------------------------------------------------------------------------------------------------------------|
|
||||
| [`--advertise-addr`](#advertise-addr) | `string` | | Advertised address (format: `<ip\|interface>[:port]`) |
|
||||
| [`--autolock`](#autolock) | `bool` | | Enable manager autolocking (requiring an unlock key to start a stopped manager) |
|
||||
| [`--availability`](#availability) | `string` | `active` | Availability of the node (`active`, `pause`, `drain`) |
|
||||
| `--cert-expiry` | `duration` | `2160h0m0s` | Validity period for node certificates (ns\|us\|ms\|s\|m\|h) |
|
||||
| [`--data-path-addr`](#data-path-addr) | `string` | | Address or interface to use for data path traffic (format: `<ip\|interface>`) |
|
||||
| [`--data-path-port`](#data-path-port) | `uint32` | `0` | Port number to use for data path traffic (1024 - 49151). If no value is set or is set to 0, the default port (4789) is used. |
|
||||
| [`--default-addr-pool`](#default-addr-pool) | `ipNetSlice` | | default address pool in CIDR format |
|
||||
| `--default-addr-pool-mask-length` | `uint32` | `24` | default address pool subnet mask length |
|
||||
| [`--dispatcher-heartbeat`](#dispatcher-heartbeat) | `duration` | `5s` | Dispatcher heartbeat period (ns\|us\|ms\|s\|m\|h) |
|
||||
| [`--external-ca`](#external-ca) | `external-ca` | | Specifications of one or more certificate signing endpoints |
|
||||
| [`--force-new-cluster`](#force-new-cluster) | `bool` | | Force create a new cluster from current state |
|
||||
| [`--listen-addr`](#listen-addr) | `node-addr` | `0.0.0.0:2377` | Listen address (format: `<ip\|interface>[:port]`) |
|
||||
| [`--max-snapshots`](#max-snapshots) | `uint64` | `0` | Number of additional Raft snapshots to retain |
|
||||
| [`--snapshot-interval`](#snapshot-interval) | `uint64` | `10000` | Number of log entries between Raft snapshots |
|
||||
| `--task-history-limit` | `int64` | `5` | Task history retention limit |
|
||||
|
||||
|
||||
<!---MARKER_GEN_END-->
|
||||
@@ -64,7 +64,7 @@ You can disable autolock by running `docker swarm update --autolock=false`.
|
||||
After disabling it, the encryption key is no longer required to start the
|
||||
manager, and it will start up on its own without user intervention.
|
||||
|
||||
### <a name=""></a> Configure node healthcheck frequency (--dispatcher-heartbeat)
|
||||
### <a name="dispatcher-heartbeat"></a> Configure node healthcheck frequency (--dispatcher-heartbeat)
|
||||
|
||||
The `--dispatcher-heartbeat` flag sets the frequency at which nodes are told to
|
||||
report their health.
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
|
||||
Usage: docker helloworld goodbye
|
||||
|
||||
Say Goodbye instead of Hello
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
|
||||
Usage: docker helloworld [OPTIONS] COMMAND
|
||||
|
||||
A basic Hello World plugin for tests
|
||||
|
||||
-1
@@ -1,4 +1,3 @@
|
||||
|
||||
Usage: docker stack deploy [OPTIONS] STACK
|
||||
|
||||
Deploy a new stack or update an existing stack
|
||||
|
||||
@@ -208,6 +208,6 @@ func EnableContentTrust(c *FakeCli) {
|
||||
}
|
||||
|
||||
// BuildKitEnabled on the fake cli
|
||||
func (c *FakeCli) BuildKitEnabled() (bool, error) {
|
||||
func (*FakeCli) BuildKitEnabled() (bool, error) {
|
||||
return true, nil
|
||||
}
|
||||
|
||||
@@ -22,127 +22,127 @@ type OfflineNotaryRepository struct{}
|
||||
|
||||
// Initialize creates a new repository by using rootKey as the root Key for the
|
||||
// TUF repository.
|
||||
func (o OfflineNotaryRepository) Initialize([]string, ...data.RoleName) error {
|
||||
func (OfflineNotaryRepository) Initialize([]string, ...data.RoleName) error {
|
||||
return storage.ErrOffline{}
|
||||
}
|
||||
|
||||
// InitializeWithCertificate initializes the repository with root keys and their corresponding certificates
|
||||
func (o OfflineNotaryRepository) InitializeWithCertificate([]string, []data.PublicKey, ...data.RoleName) error {
|
||||
func (OfflineNotaryRepository) InitializeWithCertificate([]string, []data.PublicKey, ...data.RoleName) error {
|
||||
return storage.ErrOffline{}
|
||||
}
|
||||
|
||||
// Publish pushes the local changes in signed material to the remote notary-server
|
||||
// Conceptually it performs an operation similar to a `git rebase`
|
||||
func (o OfflineNotaryRepository) Publish() error {
|
||||
func (OfflineNotaryRepository) Publish() error {
|
||||
return storage.ErrOffline{}
|
||||
}
|
||||
|
||||
// AddTarget creates new changelist entries to add a target to the given roles
|
||||
// in the repository when the changelist gets applied at publish time.
|
||||
func (o OfflineNotaryRepository) AddTarget(*client.Target, ...data.RoleName) error {
|
||||
func (OfflineNotaryRepository) AddTarget(*client.Target, ...data.RoleName) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// RemoveTarget creates new changelist entries to remove a target from the given
|
||||
// roles in the repository when the changelist gets applied at publish time.
|
||||
func (o OfflineNotaryRepository) RemoveTarget(string, ...data.RoleName) error {
|
||||
func (OfflineNotaryRepository) RemoveTarget(string, ...data.RoleName) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// ListTargets lists all targets for the current repository. The list of
|
||||
// roles should be passed in order from highest to lowest priority.
|
||||
func (o OfflineNotaryRepository) ListTargets(...data.RoleName) ([]*client.TargetWithRole, error) {
|
||||
func (OfflineNotaryRepository) ListTargets(...data.RoleName) ([]*client.TargetWithRole, error) {
|
||||
return nil, storage.ErrOffline{}
|
||||
}
|
||||
|
||||
// GetTargetByName returns a target by the given name.
|
||||
func (o OfflineNotaryRepository) GetTargetByName(string, ...data.RoleName) (*client.TargetWithRole, error) {
|
||||
func (OfflineNotaryRepository) GetTargetByName(string, ...data.RoleName) (*client.TargetWithRole, error) {
|
||||
return nil, storage.ErrOffline{}
|
||||
}
|
||||
|
||||
// GetAllTargetMetadataByName searches the entire delegation role tree to find the specified target by name for all
|
||||
// roles, and returns a list of TargetSignedStructs for each time it finds the specified target.
|
||||
func (o OfflineNotaryRepository) GetAllTargetMetadataByName(string) ([]client.TargetSignedStruct, error) {
|
||||
func (OfflineNotaryRepository) GetAllTargetMetadataByName(string) ([]client.TargetSignedStruct, error) {
|
||||
return nil, storage.ErrOffline{}
|
||||
}
|
||||
|
||||
// GetChangelist returns the list of the repository's unpublished changes
|
||||
func (o OfflineNotaryRepository) GetChangelist() (changelist.Changelist, error) {
|
||||
func (OfflineNotaryRepository) GetChangelist() (changelist.Changelist, error) {
|
||||
return changelist.NewMemChangelist(), nil
|
||||
}
|
||||
|
||||
// ListRoles returns a list of RoleWithSignatures objects for this repo
|
||||
func (o OfflineNotaryRepository) ListRoles() ([]client.RoleWithSignatures, error) {
|
||||
func (OfflineNotaryRepository) ListRoles() ([]client.RoleWithSignatures, error) {
|
||||
return nil, storage.ErrOffline{}
|
||||
}
|
||||
|
||||
// GetDelegationRoles returns the keys and roles of the repository's delegations
|
||||
func (o OfflineNotaryRepository) GetDelegationRoles() ([]data.Role, error) {
|
||||
func (OfflineNotaryRepository) GetDelegationRoles() ([]data.Role, error) {
|
||||
return nil, storage.ErrOffline{}
|
||||
}
|
||||
|
||||
// AddDelegation creates changelist entries to add provided delegation public keys and paths.
|
||||
func (o OfflineNotaryRepository) AddDelegation(data.RoleName, []data.PublicKey, []string) error {
|
||||
func (OfflineNotaryRepository) AddDelegation(data.RoleName, []data.PublicKey, []string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// AddDelegationRoleAndKeys creates a changelist entry to add provided delegation public keys.
|
||||
func (o OfflineNotaryRepository) AddDelegationRoleAndKeys(data.RoleName, []data.PublicKey) error {
|
||||
func (OfflineNotaryRepository) AddDelegationRoleAndKeys(data.RoleName, []data.PublicKey) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// AddDelegationPaths creates a changelist entry to add provided paths to an existing delegation.
|
||||
func (o OfflineNotaryRepository) AddDelegationPaths(data.RoleName, []string) error {
|
||||
func (OfflineNotaryRepository) AddDelegationPaths(data.RoleName, []string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// RemoveDelegationKeysAndPaths creates changelist entries to remove provided delegation key IDs and paths.
|
||||
func (o OfflineNotaryRepository) RemoveDelegationKeysAndPaths(data.RoleName, []string, []string) error {
|
||||
func (OfflineNotaryRepository) RemoveDelegationKeysAndPaths(data.RoleName, []string, []string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// RemoveDelegationRole creates a changelist to remove all paths and keys from a role, and delete the role in its entirety.
|
||||
func (o OfflineNotaryRepository) RemoveDelegationRole(data.RoleName) error {
|
||||
func (OfflineNotaryRepository) RemoveDelegationRole(data.RoleName) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// RemoveDelegationPaths creates a changelist entry to remove provided paths from an existing delegation.
|
||||
func (o OfflineNotaryRepository) RemoveDelegationPaths(data.RoleName, []string) error {
|
||||
func (OfflineNotaryRepository) RemoveDelegationPaths(data.RoleName, []string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// RemoveDelegationKeys creates a changelist entry to remove provided keys from an existing delegation.
|
||||
func (o OfflineNotaryRepository) RemoveDelegationKeys(data.RoleName, []string) error {
|
||||
func (OfflineNotaryRepository) RemoveDelegationKeys(data.RoleName, []string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// ClearDelegationPaths creates a changelist entry to remove all paths from an existing delegation.
|
||||
func (o OfflineNotaryRepository) ClearDelegationPaths(data.RoleName) error {
|
||||
func (OfflineNotaryRepository) ClearDelegationPaths(data.RoleName) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Witness creates change objects to witness (i.e. re-sign) the given
|
||||
// roles on the next publish. One change is created per role
|
||||
func (o OfflineNotaryRepository) Witness(...data.RoleName) ([]data.RoleName, error) {
|
||||
func (OfflineNotaryRepository) Witness(...data.RoleName) ([]data.RoleName, error) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// RotateKey rotates a private key and returns the public component from the remote server
|
||||
func (o OfflineNotaryRepository) RotateKey(data.RoleName, bool, []string) error {
|
||||
func (OfflineNotaryRepository) RotateKey(data.RoleName, bool, []string) error {
|
||||
return storage.ErrOffline{}
|
||||
}
|
||||
|
||||
// GetCryptoService is the getter for the repository's CryptoService
|
||||
func (o OfflineNotaryRepository) GetCryptoService() signed.CryptoService {
|
||||
func (OfflineNotaryRepository) GetCryptoService() signed.CryptoService {
|
||||
return nil
|
||||
}
|
||||
|
||||
// SetLegacyVersions allows the number of legacy versions of the root
|
||||
// to be inspected for old signing keys to be configured.
|
||||
func (o OfflineNotaryRepository) SetLegacyVersions(int) {}
|
||||
func (OfflineNotaryRepository) SetLegacyVersions(int) {}
|
||||
|
||||
// GetGUN is a getter for the GUN object from a Repository
|
||||
func (o OfflineNotaryRepository) GetGUN() data.GUN {
|
||||
func (OfflineNotaryRepository) GetGUN() data.GUN {
|
||||
return data.GUN("gun")
|
||||
}
|
||||
|
||||
@@ -160,50 +160,50 @@ type UninitializedNotaryRepository struct {
|
||||
|
||||
// Initialize creates a new repository by using rootKey as the root Key for the
|
||||
// TUF repository.
|
||||
func (u UninitializedNotaryRepository) Initialize([]string, ...data.RoleName) error {
|
||||
func (UninitializedNotaryRepository) Initialize([]string, ...data.RoleName) error {
|
||||
return client.ErrRepositoryNotExist{}
|
||||
}
|
||||
|
||||
// InitializeWithCertificate initializes the repository with root keys and their corresponding certificates
|
||||
func (u UninitializedNotaryRepository) InitializeWithCertificate([]string, []data.PublicKey, ...data.RoleName) error {
|
||||
func (UninitializedNotaryRepository) InitializeWithCertificate([]string, []data.PublicKey, ...data.RoleName) error {
|
||||
return client.ErrRepositoryNotExist{}
|
||||
}
|
||||
|
||||
// Publish pushes the local changes in signed material to the remote notary-server
|
||||
// Conceptually it performs an operation similar to a `git rebase`
|
||||
func (u UninitializedNotaryRepository) Publish() error {
|
||||
func (UninitializedNotaryRepository) Publish() error {
|
||||
return client.ErrRepositoryNotExist{}
|
||||
}
|
||||
|
||||
// ListTargets lists all targets for the current repository. The list of
|
||||
// roles should be passed in order from highest to lowest priority.
|
||||
func (u UninitializedNotaryRepository) ListTargets(...data.RoleName) ([]*client.TargetWithRole, error) {
|
||||
func (UninitializedNotaryRepository) ListTargets(...data.RoleName) ([]*client.TargetWithRole, error) {
|
||||
return nil, client.ErrRepositoryNotExist{}
|
||||
}
|
||||
|
||||
// GetTargetByName returns a target by the given name.
|
||||
func (u UninitializedNotaryRepository) GetTargetByName(string, ...data.RoleName) (*client.TargetWithRole, error) {
|
||||
func (UninitializedNotaryRepository) GetTargetByName(string, ...data.RoleName) (*client.TargetWithRole, error) {
|
||||
return nil, client.ErrRepositoryNotExist{}
|
||||
}
|
||||
|
||||
// GetAllTargetMetadataByName searches the entire delegation role tree to find the specified target by name for all
|
||||
// roles, and returns a list of TargetSignedStructs for each time it finds the specified target.
|
||||
func (u UninitializedNotaryRepository) GetAllTargetMetadataByName(string) ([]client.TargetSignedStruct, error) {
|
||||
func (UninitializedNotaryRepository) GetAllTargetMetadataByName(string) ([]client.TargetSignedStruct, error) {
|
||||
return nil, client.ErrRepositoryNotExist{}
|
||||
}
|
||||
|
||||
// ListRoles returns a list of RoleWithSignatures objects for this repo
|
||||
func (u UninitializedNotaryRepository) ListRoles() ([]client.RoleWithSignatures, error) {
|
||||
func (UninitializedNotaryRepository) ListRoles() ([]client.RoleWithSignatures, error) {
|
||||
return nil, client.ErrRepositoryNotExist{}
|
||||
}
|
||||
|
||||
// GetDelegationRoles returns the keys and roles of the repository's delegations
|
||||
func (u UninitializedNotaryRepository) GetDelegationRoles() ([]data.Role, error) {
|
||||
func (UninitializedNotaryRepository) GetDelegationRoles() ([]data.Role, error) {
|
||||
return nil, client.ErrRepositoryNotExist{}
|
||||
}
|
||||
|
||||
// RotateKey rotates a private key and returns the public component from the remote server
|
||||
func (u UninitializedNotaryRepository) RotateKey(data.RoleName, bool, []string) error {
|
||||
func (UninitializedNotaryRepository) RotateKey(data.RoleName, bool, []string) error {
|
||||
return client.ErrRepositoryNotExist{}
|
||||
}
|
||||
|
||||
@@ -220,40 +220,40 @@ type EmptyTargetsNotaryRepository struct {
|
||||
|
||||
// Initialize creates a new repository by using rootKey as the root Key for the
|
||||
// TUF repository.
|
||||
func (e EmptyTargetsNotaryRepository) Initialize([]string, ...data.RoleName) error {
|
||||
func (EmptyTargetsNotaryRepository) Initialize([]string, ...data.RoleName) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// InitializeWithCertificate initializes the repository with root keys and their corresponding certificates
|
||||
func (e EmptyTargetsNotaryRepository) InitializeWithCertificate([]string, []data.PublicKey, ...data.RoleName) error {
|
||||
func (EmptyTargetsNotaryRepository) InitializeWithCertificate([]string, []data.PublicKey, ...data.RoleName) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Publish pushes the local changes in signed material to the remote notary-server
|
||||
// Conceptually it performs an operation similar to a `git rebase`
|
||||
func (e EmptyTargetsNotaryRepository) Publish() error {
|
||||
func (EmptyTargetsNotaryRepository) Publish() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// ListTargets lists all targets for the current repository. The list of
|
||||
// roles should be passed in order from highest to lowest priority.
|
||||
func (e EmptyTargetsNotaryRepository) ListTargets(...data.RoleName) ([]*client.TargetWithRole, error) {
|
||||
func (EmptyTargetsNotaryRepository) ListTargets(...data.RoleName) ([]*client.TargetWithRole, error) {
|
||||
return []*client.TargetWithRole{}, nil
|
||||
}
|
||||
|
||||
// GetTargetByName returns a target by the given name.
|
||||
func (e EmptyTargetsNotaryRepository) GetTargetByName(name string, _ ...data.RoleName) (*client.TargetWithRole, error) {
|
||||
func (EmptyTargetsNotaryRepository) GetTargetByName(name string, _ ...data.RoleName) (*client.TargetWithRole, error) {
|
||||
return nil, client.ErrNoSuchTarget(name)
|
||||
}
|
||||
|
||||
// GetAllTargetMetadataByName searches the entire delegation role tree to find the specified target by name for all
|
||||
// roles, and returns a list of TargetSignedStructs for each time it finds the specified target.
|
||||
func (e EmptyTargetsNotaryRepository) GetAllTargetMetadataByName(name string) ([]client.TargetSignedStruct, error) {
|
||||
func (EmptyTargetsNotaryRepository) GetAllTargetMetadataByName(name string) ([]client.TargetSignedStruct, error) {
|
||||
return nil, client.ErrNoSuchTarget(name)
|
||||
}
|
||||
|
||||
// ListRoles returns a list of RoleWithSignatures objects for this repo
|
||||
func (e EmptyTargetsNotaryRepository) ListRoles() ([]client.RoleWithSignatures, error) {
|
||||
func (EmptyTargetsNotaryRepository) ListRoles() ([]client.RoleWithSignatures, error) {
|
||||
rootRole := data.Role{
|
||||
RootRole: data.RootRole{
|
||||
KeyIDs: []string{"rootID"},
|
||||
@@ -276,12 +276,12 @@ func (e EmptyTargetsNotaryRepository) ListRoles() ([]client.RoleWithSignatures,
|
||||
}
|
||||
|
||||
// GetDelegationRoles returns the keys and roles of the repository's delegations
|
||||
func (e EmptyTargetsNotaryRepository) GetDelegationRoles() ([]data.Role, error) {
|
||||
func (EmptyTargetsNotaryRepository) GetDelegationRoles() ([]data.Role, error) {
|
||||
return []data.Role{}, nil
|
||||
}
|
||||
|
||||
// RotateKey rotates a private key and returns the public component from the remote server
|
||||
func (e EmptyTargetsNotaryRepository) RotateKey(data.RoleName, bool, []string) error {
|
||||
func (EmptyTargetsNotaryRepository) RotateKey(data.RoleName, bool, []string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -390,7 +390,7 @@ var loadedTargets = []client.TargetSignedStruct{
|
||||
}
|
||||
|
||||
// ListRoles returns a list of RoleWithSignatures objects for this repo
|
||||
func (l LoadedNotaryRepository) ListRoles() ([]client.RoleWithSignatures, error) {
|
||||
func (LoadedNotaryRepository) ListRoles() ([]client.RoleWithSignatures, error) {
|
||||
rootRole := data.Role{
|
||||
RootRole: data.RootRole{
|
||||
KeyIDs: []string{"rootID"},
|
||||
@@ -444,7 +444,7 @@ func (l LoadedNotaryRepository) ListRoles() ([]client.RoleWithSignatures, error)
|
||||
|
||||
// ListTargets lists all targets for the current repository. The list of
|
||||
// roles should be passed in order from highest to lowest priority.
|
||||
func (l LoadedNotaryRepository) ListTargets(roles ...data.RoleName) ([]*client.TargetWithRole, error) {
|
||||
func (LoadedNotaryRepository) ListTargets(roles ...data.RoleName) ([]*client.TargetWithRole, error) {
|
||||
filteredTargets := []*client.TargetWithRole{}
|
||||
for _, tgt := range loadedTargets {
|
||||
if len(roles) == 0 || (len(roles) > 0 && roles[0] == tgt.Role.Name) {
|
||||
@@ -455,7 +455,7 @@ func (l LoadedNotaryRepository) ListTargets(roles ...data.RoleName) ([]*client.T
|
||||
}
|
||||
|
||||
// GetTargetByName returns a target by the given name.
|
||||
func (l LoadedNotaryRepository) GetTargetByName(name string, roles ...data.RoleName) (*client.TargetWithRole, error) {
|
||||
func (LoadedNotaryRepository) GetTargetByName(name string, roles ...data.RoleName) (*client.TargetWithRole, error) {
|
||||
for _, tgt := range loadedTargets {
|
||||
if name == tgt.Target.Name {
|
||||
if len(roles) == 0 || (len(roles) > 0 && roles[0] == tgt.Role.Name) {
|
||||
@@ -468,7 +468,7 @@ func (l LoadedNotaryRepository) GetTargetByName(name string, roles ...data.RoleN
|
||||
|
||||
// GetAllTargetMetadataByName searches the entire delegation role tree to find the specified target by name for all
|
||||
// roles, and returns a list of TargetSignedStructs for each time it finds the specified target.
|
||||
func (l LoadedNotaryRepository) GetAllTargetMetadataByName(name string) ([]client.TargetSignedStruct, error) {
|
||||
func (LoadedNotaryRepository) GetAllTargetMetadataByName(name string) ([]client.TargetSignedStruct, error) {
|
||||
if name == "" {
|
||||
return loadedTargets, nil
|
||||
}
|
||||
@@ -485,12 +485,12 @@ func (l LoadedNotaryRepository) GetAllTargetMetadataByName(name string) ([]clien
|
||||
}
|
||||
|
||||
// GetGUN is a getter for the GUN object from a Repository
|
||||
func (l LoadedNotaryRepository) GetGUN() data.GUN {
|
||||
return data.GUN("signed-repo")
|
||||
func (LoadedNotaryRepository) GetGUN() data.GUN {
|
||||
return "signed-repo"
|
||||
}
|
||||
|
||||
// GetDelegationRoles returns the keys and roles of the repository's delegations
|
||||
func (l LoadedNotaryRepository) GetDelegationRoles() ([]data.Role, error) {
|
||||
func (LoadedNotaryRepository) GetDelegationRoles() ([]data.Role, error) {
|
||||
return loadedDelegationRoles, nil
|
||||
}
|
||||
|
||||
@@ -518,7 +518,7 @@ type LoadedWithNoSignersNotaryRepository struct {
|
||||
|
||||
// ListTargets lists all targets for the current repository. The list of
|
||||
// roles should be passed in order from highest to lowest priority.
|
||||
func (l LoadedWithNoSignersNotaryRepository) ListTargets(roles ...data.RoleName) ([]*client.TargetWithRole, error) {
|
||||
func (LoadedWithNoSignersNotaryRepository) ListTargets(roles ...data.RoleName) ([]*client.TargetWithRole, error) {
|
||||
filteredTargets := []*client.TargetWithRole{}
|
||||
for _, tgt := range loadedTargets {
|
||||
if len(roles) == 0 || (len(roles) > 0 && roles[0] == tgt.Role.Name) {
|
||||
@@ -529,7 +529,7 @@ func (l LoadedWithNoSignersNotaryRepository) ListTargets(roles ...data.RoleName)
|
||||
}
|
||||
|
||||
// GetTargetByName returns a target by the given name.
|
||||
func (l LoadedWithNoSignersNotaryRepository) GetTargetByName(name string, _ ...data.RoleName) (*client.TargetWithRole, error) {
|
||||
func (LoadedWithNoSignersNotaryRepository) GetTargetByName(name string, _ ...data.RoleName) (*client.TargetWithRole, error) {
|
||||
if name == "" || name == loadedGreenTarget.Name {
|
||||
return &client.TargetWithRole{Target: loadedGreenTarget, Role: data.CanonicalTargetsRole}, nil
|
||||
}
|
||||
@@ -538,7 +538,7 @@ func (l LoadedWithNoSignersNotaryRepository) GetTargetByName(name string, _ ...d
|
||||
|
||||
// GetAllTargetMetadataByName searches the entire delegation role tree to find the specified target by name for all
|
||||
// roles, and returns a list of TargetSignedStructs for each time it finds the specified target.
|
||||
func (l LoadedWithNoSignersNotaryRepository) GetAllTargetMetadataByName(name string) ([]client.TargetSignedStruct, error) {
|
||||
func (LoadedWithNoSignersNotaryRepository) GetAllTargetMetadataByName(name string) ([]client.TargetSignedStruct, error) {
|
||||
if name == "" || name == loadedGreenTarget.Name {
|
||||
return []client.TargetSignedStruct{{Target: loadedGreenTarget, Role: loadedTargetsRole}}, nil
|
||||
}
|
||||
@@ -546,6 +546,6 @@ func (l LoadedWithNoSignersNotaryRepository) GetAllTargetMetadataByName(name str
|
||||
}
|
||||
|
||||
// GetDelegationRoles returns the keys and roles of the repository's delegations
|
||||
func (l LoadedWithNoSignersNotaryRepository) GetDelegationRoles() ([]data.Role, error) {
|
||||
func (LoadedWithNoSignersNotaryRepository) GetDelegationRoles() ([]data.Role, error) {
|
||||
return []data.Role{}, nil
|
||||
}
|
||||
|
||||
@@ -24,10 +24,10 @@ func (a noColor) With(_ ...aec.ANSI) aec.ANSI {
|
||||
return a
|
||||
}
|
||||
|
||||
func (a noColor) Apply(s string) string {
|
||||
func (noColor) Apply(s string) string {
|
||||
return s
|
||||
}
|
||||
|
||||
func (a noColor) String() string {
|
||||
func (noColor) String() string {
|
||||
return ""
|
||||
}
|
||||
|
||||
+1
-1
@@ -80,7 +80,7 @@ func (o *ConfigOpt) Set(value string) error {
|
||||
}
|
||||
|
||||
// Type returns the type of this option
|
||||
func (o *ConfigOpt) Type() string {
|
||||
func (*ConfigOpt) Type() string {
|
||||
return "config"
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -46,7 +46,7 @@ func (d *DurationOpt) Set(s string) error {
|
||||
}
|
||||
|
||||
// Type returns the type of this option, which will be displayed in `--help` output
|
||||
func (d *DurationOpt) Type() string {
|
||||
func (*DurationOpt) Type() string {
|
||||
return "duration"
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -92,7 +92,7 @@ func (o *GpuOpts) Set(value string) error {
|
||||
}
|
||||
|
||||
// Type returns the type of this option
|
||||
func (o *GpuOpts) Type() string {
|
||||
func (*GpuOpts) Type() string {
|
||||
return "gpu-request"
|
||||
}
|
||||
|
||||
|
||||
+13
-1
@@ -43,6 +43,13 @@ func (m *MountOpt) Set(value string) error {
|
||||
return mount.VolumeOptions
|
||||
}
|
||||
|
||||
imageOptions := func() *mounttypes.ImageOptions {
|
||||
if mount.ImageOptions == nil {
|
||||
mount.ImageOptions = new(mounttypes.ImageOptions)
|
||||
}
|
||||
return mount.ImageOptions
|
||||
}
|
||||
|
||||
bindOptions := func() *mounttypes.BindOptions {
|
||||
if mount.BindOptions == nil {
|
||||
mount.BindOptions = new(mounttypes.BindOptions)
|
||||
@@ -147,6 +154,8 @@ func (m *MountOpt) Set(value string) error {
|
||||
volumeOptions().DriverConfig.Options = make(map[string]string)
|
||||
}
|
||||
setValueOnMap(volumeOptions().DriverConfig.Options, val)
|
||||
case "image-subpath":
|
||||
imageOptions().Subpath = val
|
||||
case "tmpfs-size":
|
||||
sizeBytes, err := units.RAMInBytes(val)
|
||||
if err != nil {
|
||||
@@ -175,6 +184,9 @@ func (m *MountOpt) Set(value string) error {
|
||||
if mount.VolumeOptions != nil && mount.Type != mounttypes.TypeVolume {
|
||||
return fmt.Errorf("cannot mix 'volume-*' options with mount type '%s'", mount.Type)
|
||||
}
|
||||
if mount.ImageOptions != nil && mount.Type != mounttypes.TypeImage {
|
||||
return fmt.Errorf("cannot mix 'image-*' options with mount type '%s'", mount.Type)
|
||||
}
|
||||
if mount.BindOptions != nil && mount.Type != mounttypes.TypeBind {
|
||||
return fmt.Errorf("cannot mix 'bind-*' options with mount type '%s'", mount.Type)
|
||||
}
|
||||
@@ -203,7 +215,7 @@ func (m *MountOpt) Set(value string) error {
|
||||
}
|
||||
|
||||
// Type returns the type of this option
|
||||
func (m *MountOpt) Type() string {
|
||||
func (*MountOpt) Type() string {
|
||||
return "mount"
|
||||
}
|
||||
|
||||
|
||||
@@ -188,6 +188,27 @@ func TestMountOptTypeConflict(t *testing.T) {
|
||||
assert.ErrorContains(t, m.Set("type=volume,target=/foo,source=/foo,bind-propagation=rprivate"), "cannot mix")
|
||||
}
|
||||
|
||||
func TestMountOptSetImageNoError(t *testing.T) {
|
||||
for _, testcase := range []string{
|
||||
"type=image,source=foo,target=/target,image-subpath=/bar",
|
||||
} {
|
||||
var mount MountOpt
|
||||
|
||||
assert.NilError(t, mount.Set(testcase))
|
||||
|
||||
mounts := mount.Value()
|
||||
assert.Assert(t, is.Len(mounts, 1))
|
||||
assert.Check(t, is.DeepEqual(mounttypes.Mount{
|
||||
Type: mounttypes.TypeImage,
|
||||
Source: "foo",
|
||||
Target: "/target",
|
||||
ImageOptions: &mounttypes.ImageOptions{
|
||||
Subpath: "/bar",
|
||||
},
|
||||
}, mounts[0]))
|
||||
}
|
||||
}
|
||||
|
||||
func TestMountOptSetTmpfsNoError(t *testing.T) {
|
||||
for _, testcase := range []string{
|
||||
// tests several aliases that should have same result.
|
||||
|
||||
+2
-2
@@ -106,7 +106,7 @@ func (n *NetworkOpt) Set(value string) error { //nolint:gocyclo
|
||||
}
|
||||
|
||||
// Type returns the type of this option
|
||||
func (n *NetworkOpt) Type() string {
|
||||
func (*NetworkOpt) Type() string {
|
||||
return "network"
|
||||
}
|
||||
|
||||
@@ -116,7 +116,7 @@ func (n *NetworkOpt) Value() []NetworkAttachmentOpts {
|
||||
}
|
||||
|
||||
// String returns the network opts as a string
|
||||
func (n *NetworkOpt) String() string {
|
||||
func (*NetworkOpt) String() string {
|
||||
return ""
|
||||
}
|
||||
|
||||
|
||||
+6
-6
@@ -110,7 +110,7 @@ func (opts *ListOpts) Len() int {
|
||||
}
|
||||
|
||||
// Type returns a string name for this Option type
|
||||
func (opts *ListOpts) Type() string {
|
||||
func (*ListOpts) Type() string {
|
||||
return "list"
|
||||
}
|
||||
|
||||
@@ -180,7 +180,7 @@ func (opts *MapOpts) String() string {
|
||||
}
|
||||
|
||||
// Type returns a string name for this Option type
|
||||
func (opts *MapOpts) Type() string {
|
||||
func (*MapOpts) Type() string {
|
||||
return "map"
|
||||
}
|
||||
|
||||
@@ -358,7 +358,7 @@ func (o *FilterOpt) Set(value string) error {
|
||||
}
|
||||
|
||||
// Type returns the option type
|
||||
func (o *FilterOpt) Type() string {
|
||||
func (*FilterOpt) Type() string {
|
||||
return "filter"
|
||||
}
|
||||
|
||||
@@ -386,7 +386,7 @@ func (c *NanoCPUs) Set(value string) error {
|
||||
}
|
||||
|
||||
// Type returns the type
|
||||
func (c *NanoCPUs) Type() string {
|
||||
func (*NanoCPUs) Type() string {
|
||||
return "decimal"
|
||||
}
|
||||
|
||||
@@ -463,7 +463,7 @@ func (m *MemBytes) Set(value string) error {
|
||||
}
|
||||
|
||||
// Type returns the type
|
||||
func (m *MemBytes) Type() string {
|
||||
func (*MemBytes) Type() string {
|
||||
return "bytes"
|
||||
}
|
||||
|
||||
@@ -498,7 +498,7 @@ func (m *MemSwapBytes) Set(value string) error {
|
||||
}
|
||||
|
||||
// Type returns the type
|
||||
func (m *MemSwapBytes) Type() string {
|
||||
func (*MemSwapBytes) Type() string {
|
||||
return "bytes"
|
||||
}
|
||||
|
||||
|
||||
+5
-2
@@ -190,7 +190,6 @@ func TestListOptsWithValidator(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
//nolint:lll
|
||||
func TestValidateDNSSearch(t *testing.T) {
|
||||
valid := []string{
|
||||
`.`,
|
||||
@@ -232,7 +231,11 @@ func TestValidateDNSSearch(t *testing.T) {
|
||||
`foo.bar-.baz`,
|
||||
`foo.-bar`,
|
||||
`foo.-bar.baz`,
|
||||
`foo.bar.baz.this.should.fail.on.long.name.because.it.is.longer.thanisshouldbethis.should.fail.on.long.name.because.it.is.longer.thanisshouldbethis.should.fail.on.long.name.because.it.is.longer.thanisshouldbethis.should.fail.on.long.name.because.it.is.longer.thanisshouldbe`,
|
||||
`foo.bar.baz.` +
|
||||
`this.should.fail.on.long.name.because.it.is.longer.thanisshouldbe` +
|
||||
`this.should.fail.on.long.name.because.it.is.longer.thanisshouldbe` +
|
||||
`this.should.fail.on.long.name.because.it.is.longer.thanisshouldbe` +
|
||||
`this.should.fail.on.long.name.because.it.is.longer.thanisshouldbe`,
|
||||
}
|
||||
|
||||
for _, domain := range valid {
|
||||
|
||||
+1
-1
@@ -121,7 +121,7 @@ func (p *PortOpt) Set(value string) error {
|
||||
}
|
||||
|
||||
// Type returns the type of this option
|
||||
func (p *PortOpt) Type() string {
|
||||
func (*PortOpt) Type() string {
|
||||
return "port"
|
||||
}
|
||||
|
||||
|
||||
@@ -13,7 +13,7 @@ func (s *QuotedString) Set(val string) error {
|
||||
}
|
||||
|
||||
// Type returns the type of the value
|
||||
func (s *QuotedString) Type() string {
|
||||
func (*QuotedString) Type() string {
|
||||
return "string"
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -79,7 +79,7 @@ func (o *SecretOpt) Set(value string) error {
|
||||
}
|
||||
|
||||
// Type returns the type of this option
|
||||
func (o *SecretOpt) Type() string {
|
||||
func (*SecretOpt) Type() string {
|
||||
return "secret"
|
||||
}
|
||||
|
||||
|
||||
@@ -100,6 +100,6 @@ func (opt *ThrottledeviceOpt) GetList() []*blkiodev.ThrottleDevice {
|
||||
}
|
||||
|
||||
// Type returns the option type
|
||||
func (opt *ThrottledeviceOpt) Type() string {
|
||||
func (*ThrottledeviceOpt) Type() string {
|
||||
return "list"
|
||||
}
|
||||
|
||||
+1
-1
@@ -58,6 +58,6 @@ func (o *UlimitOpt) GetList() []*container.Ulimit {
|
||||
}
|
||||
|
||||
// Type returns the option type
|
||||
func (o *UlimitOpt) Type() string {
|
||||
func (*UlimitOpt) Type() string {
|
||||
return "ulimit"
|
||||
}
|
||||
|
||||
@@ -79,6 +79,6 @@ func (opt *WeightdeviceOpt) GetList() []*blkiodev.WeightDevice {
|
||||
}
|
||||
|
||||
// Type returns the option type
|
||||
func (opt *WeightdeviceOpt) Type() string {
|
||||
func (*WeightdeviceOpt) Type() string {
|
||||
return "list"
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user