Merge pull request #6232 from thaJeztah/bump_engine

vendor: moby/moby/api v1.52.0-alpha.1, moby/moby/client v0.1.0-alpha.0
This commit is contained in:
Sebastiaan van Stijn
2025-08-05 22:42:19 +02:00
committed by GitHub
85 changed files with 590 additions and 422 deletions
+2 -2
View File
@@ -239,7 +239,7 @@ func TestRunPullTermination(t *testing.T) {
return client.HijackedResponse{}, errors.New("shouldn't try to attach to a container")
},
imageCreateFunc: func(ctx context.Context, parentReference string, options image.CreateOptions) (io.ReadCloser, error) {
server, client := net.Pipe()
server, respReader := net.Pipe()
t.Cleanup(func() {
_ = server.Close()
})
@@ -269,7 +269,7 @@ func TestRunPullTermination(t *testing.T) {
}
}()
attachCh <- struct{}{}
return client, nil
return respReader, nil
},
Version: "1.30",
})
+6 -6
View File
@@ -4,8 +4,8 @@ import (
"context"
"io"
"github.com/moby/moby/api/types"
"github.com/moby/moby/api/types/filters"
"github.com/moby/moby/api/types/plugin"
"github.com/moby/moby/api/types/system"
"github.com/moby/moby/client"
)
@@ -17,8 +17,8 @@ type fakeClient struct {
pluginEnableFunc func(name string, options client.PluginEnableOptions) error
pluginRemoveFunc func(name string, options client.PluginRemoveOptions) error
pluginInstallFunc func(name string, options client.PluginInstallOptions) (io.ReadCloser, error)
pluginListFunc func(filter filters.Args) (types.PluginsListResponse, error)
pluginInspectFunc func(name string) (*types.Plugin, []byte, error)
pluginListFunc func(filter filters.Args) (plugin.ListResponse, error)
pluginInspectFunc func(name string) (*plugin.Plugin, []byte, error)
pluginUpgradeFunc func(name string, options client.PluginInstallOptions) (io.ReadCloser, error)
}
@@ -57,15 +57,15 @@ func (c *fakeClient) PluginInstall(_ context.Context, name string, installOption
return nil, nil
}
func (c *fakeClient) PluginList(_ context.Context, filter filters.Args) (types.PluginsListResponse, error) {
func (c *fakeClient) PluginList(_ context.Context, filter filters.Args) (plugin.ListResponse, error) {
if c.pluginListFunc != nil {
return c.pluginListFunc(filter)
}
return types.PluginsListResponse{}, nil
return plugin.ListResponse{}, nil
}
func (c *fakeClient) PluginInspectWithRaw(_ context.Context, name string) (*types.Plugin, []byte, error) {
func (c *fakeClient) PluginInspectWithRaw(_ context.Context, name string) (*plugin.Plugin, []byte, error) {
if c.pluginInspectFunc != nil {
return c.pluginInspectFunc(name)
}
+2 -2
View File
@@ -13,7 +13,7 @@ import (
"github.com/docker/cli/cli/command/completion"
"github.com/moby/go-archive"
"github.com/moby/go-archive/compression"
"github.com/moby/moby/api/types"
"github.com/moby/moby/api/types/plugin"
"github.com/moby/moby/client"
"github.com/pkg/errors"
"github.com/sirupsen/logrus"
@@ -34,7 +34,7 @@ func validateConfig(path string) error {
return err
}
m := types.PluginConfig{}
m := plugin.Config{}
err = json.NewDecoder(dt).Decode(&m)
_ = dt.Close()
+5 -5
View File
@@ -4,7 +4,7 @@ import (
"strings"
"github.com/docker/cli/cli/command/formatter"
"github.com/moby/moby/api/types"
"github.com/moby/moby/api/types/plugin"
)
const (
@@ -38,10 +38,10 @@ func NewFormat(source string, quiet bool) formatter.Format {
}
// FormatWrite writes the context
func FormatWrite(ctx formatter.Context, plugins []*types.Plugin) error {
func FormatWrite(ctx formatter.Context, plugins []*plugin.Plugin) error {
render := func(format func(subContext formatter.SubContext) error) error {
for _, plugin := range plugins {
pluginCtx := &pluginContext{trunc: ctx.Trunc, p: *plugin}
for _, p := range plugins {
pluginCtx := &pluginContext{trunc: ctx.Trunc, p: *p}
if err := format(pluginCtx); err != nil {
return err
}
@@ -62,7 +62,7 @@ func FormatWrite(ctx formatter.Context, plugins []*types.Plugin) error {
type pluginContext struct {
formatter.HeaderContext
trunc bool
p types.Plugin
p plugin.Plugin
}
func (c *pluginContext) MarshalJSON() ([]byte, error) {
+10 -10
View File
@@ -11,7 +11,7 @@ import (
"github.com/docker/cli/cli/command/formatter"
"github.com/docker/cli/internal/test"
"github.com/moby/moby/api/types"
"github.com/moby/moby/api/types/plugin"
"gotest.tools/v3/assert"
is "gotest.tools/v3/assert/cmp"
)
@@ -27,7 +27,7 @@ func TestPluginContext(t *testing.T) {
}{
{
pluginCtx: pluginContext{
p: types.Plugin{ID: pluginID},
p: plugin.Plugin{ID: pluginID},
trunc: false,
},
expValue: pluginID,
@@ -35,7 +35,7 @@ func TestPluginContext(t *testing.T) {
},
{
pluginCtx: pluginContext{
p: types.Plugin{ID: pluginID},
p: plugin.Plugin{ID: pluginID},
trunc: true,
},
expValue: formatter.TruncateID(pluginID),
@@ -43,14 +43,14 @@ func TestPluginContext(t *testing.T) {
},
{
pluginCtx: pluginContext{
p: types.Plugin{Name: "plugin_name"},
p: plugin.Plugin{Name: "plugin_name"},
},
expValue: "plugin_name",
call: pCtx.Name,
},
{
pluginCtx: pluginContext{
p: types.Plugin{Config: types.PluginConfig{Description: "plugin_description"}},
p: plugin.Plugin{Config: plugin.Config{Description: "plugin_description"}},
},
expValue: "plugin_description",
call: pCtx.Description,
@@ -146,9 +146,9 @@ foobar_bar
},
}
plugins := []*types.Plugin{
{ID: "pluginID1", Name: "foobar_baz", Config: types.PluginConfig{Description: "description 1"}, Enabled: true},
{ID: "pluginID2", Name: "foobar_bar", Config: types.PluginConfig{Description: "description 2"}, Enabled: false},
plugins := []*plugin.Plugin{
{ID: "pluginID1", Name: "foobar_baz", Config: plugin.Config{Description: "description 1"}, Enabled: true},
{ID: "pluginID2", Name: "foobar_bar", Config: plugin.Config{Description: "description 2"}, Enabled: false},
}
for _, tc := range tests {
@@ -167,7 +167,7 @@ foobar_bar
}
func TestPluginContextWriteJSON(t *testing.T) {
plugins := []*types.Plugin{
plugins := []*plugin.Plugin{
{ID: "pluginID1", Name: "foobar_baz"},
{ID: "pluginID2", Name: "foobar_bar"},
}
@@ -191,7 +191,7 @@ func TestPluginContextWriteJSON(t *testing.T) {
}
func TestPluginContextWriteJSONField(t *testing.T) {
plugins := []*types.Plugin{
plugins := []*plugin.Plugin{
{ID: "pluginID1", Name: "foobar_baz"},
{ID: "pluginID2", Name: "foobar_bar"},
}
+15 -15
View File
@@ -7,27 +7,27 @@ import (
"testing"
"github.com/docker/cli/internal/test"
"github.com/moby/moby/api/types"
"github.com/moby/moby/api/types/plugin"
"gotest.tools/v3/assert"
"gotest.tools/v3/golden"
)
var pluginFoo = &types.Plugin{
var pluginFoo = &plugin.Plugin{
ID: "id-foo",
Name: "name-foo",
Config: types.PluginConfig{
Config: plugin.Config{
Description: "plugin foo description",
DockerVersion: "17.12.1-ce",
Documentation: "plugin foo documentation",
Entrypoint: []string{"/foo"},
Interface: types.PluginConfigInterface{
Interface: plugin.Interface{
Socket: "plugin-foo.sock",
},
Linux: types.PluginConfigLinux{
Linux: plugin.LinuxConfig{
Capabilities: []string{"CAP_SYS_ADMIN"},
},
WorkDir: "workdir-foo",
Rootfs: &types.PluginConfigRootfs{
Rootfs: &plugin.RootFS{
DiffIds: []string{"sha256:deadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeef"},
Type: "layers",
},
@@ -40,7 +40,7 @@ func TestInspectErrors(t *testing.T) {
args []string
flags map[string]string
expectedError string
inspectFunc func(name string) (*types.Plugin, []byte, error)
inspectFunc func(name string) (*plugin.Plugin, []byte, error)
}{
{
description: "too few arguments",
@@ -51,7 +51,7 @@ func TestInspectErrors(t *testing.T) {
description: "error inspecting plugin",
args: []string{"foo"},
expectedError: "error inspecting plugin",
inspectFunc: func(name string) (*types.Plugin, []byte, error) {
inspectFunc: func(name string) (*plugin.Plugin, []byte, error) {
return nil, nil, errors.New("error inspecting plugin")
},
},
@@ -86,7 +86,7 @@ func TestInspect(t *testing.T) {
args []string
flags map[string]string
golden string
inspectFunc func(name string) (*types.Plugin, []byte, error)
inspectFunc func(name string) (*plugin.Plugin, []byte, error)
}{
{
description: "inspect single plugin with format",
@@ -95,8 +95,8 @@ func TestInspect(t *testing.T) {
"format": "{{ .Name }}",
},
golden: "plugin-inspect-single-with-format.golden",
inspectFunc: func(name string) (*types.Plugin, []byte, error) {
return &types.Plugin{
inspectFunc: func(name string) (*plugin.Plugin, []byte, error) {
return &plugin.Plugin{
ID: "id-foo",
Name: "name-foo",
}, []byte{}, nil
@@ -106,7 +106,7 @@ func TestInspect(t *testing.T) {
description: "inspect single plugin without format",
args: []string{"foo"},
golden: "plugin-inspect-single-without-format.golden",
inspectFunc: func(name string) (*types.Plugin, []byte, error) {
inspectFunc: func(name string) (*plugin.Plugin, []byte, error) {
return pluginFoo, nil, nil
},
},
@@ -117,15 +117,15 @@ func TestInspect(t *testing.T) {
"format": "{{ .Name }}",
},
golden: "plugin-inspect-multiple-with-format.golden",
inspectFunc: func(name string) (*types.Plugin, []byte, error) {
inspectFunc: func(name string) (*plugin.Plugin, []byte, error) {
switch name {
case "foo":
return &types.Plugin{
return &plugin.Plugin{
ID: "id-foo",
Name: "name-foo",
}, []byte{}, nil
case "bar":
return &types.Plugin{
return &plugin.Plugin{
ID: "id-bar",
Name: "name-bar",
}, []byte{}, nil
+3 -3
View File
@@ -12,7 +12,7 @@ import (
"github.com/docker/cli/internal/jsonstream"
"github.com/docker/cli/internal/prompt"
"github.com/docker/cli/internal/registry"
"github.com/moby/moby/api/types"
"github.com/moby/moby/api/types/plugin"
registrytypes "github.com/moby/moby/api/types/registry"
"github.com/moby/moby/client"
"github.com/pkg/errors"
@@ -136,8 +136,8 @@ func runInstall(ctx context.Context, dockerCLI command.Cli, opts pluginOptions)
return nil
}
func acceptPrivileges(dockerCLI command.Streams, name string) func(ctx context.Context, privileges types.PluginPrivileges) (bool, error) {
return func(ctx context.Context, privileges types.PluginPrivileges) (bool, error) {
func acceptPrivileges(dockerCLI command.Streams, name string) func(ctx context.Context, privileges plugin.Privileges) (bool, error) {
return func(ctx context.Context, privileges plugin.Privileges) (bool, error) {
_, _ = fmt.Fprintf(dockerCLI.Out(), "Plugin %q is requesting the following privileges:\n", name)
for _, privilege := range privileges {
_, _ = fmt.Fprintf(dockerCLI.Out(), " - %s: %v\n", privilege.Name, privilege.Value)
+14 -14
View File
@@ -6,8 +6,8 @@ import (
"testing"
"github.com/docker/cli/internal/test"
"github.com/moby/moby/api/types"
"github.com/moby/moby/api/types/filters"
"github.com/moby/moby/api/types/plugin"
"gotest.tools/v3/assert"
is "gotest.tools/v3/assert/cmp"
@@ -20,7 +20,7 @@ func TestListErrors(t *testing.T) {
args []string
flags map[string]string
expectedError string
listFunc func(filter filters.Args) (types.PluginsListResponse, error)
listFunc func(filter filters.Args) (plugin.ListResponse, error)
}{
{
description: "too many arguments",
@@ -31,8 +31,8 @@ func TestListErrors(t *testing.T) {
description: "error listing plugins",
args: []string{},
expectedError: "error listing plugins",
listFunc: func(filter filters.Args) (types.PluginsListResponse, error) {
return types.PluginsListResponse{}, errors.New("error listing plugins")
listFunc: func(filter filters.Args) (plugin.ListResponse, error) {
return plugin.ListResponse{}, errors.New("error listing plugins")
},
},
{
@@ -61,13 +61,13 @@ func TestListErrors(t *testing.T) {
}
func TestList(t *testing.T) {
singlePluginListFunc := func(_ filters.Args) (types.PluginsListResponse, error) {
return types.PluginsListResponse{
singlePluginListFunc := func(_ filters.Args) (plugin.ListResponse, error) {
return plugin.ListResponse{
{
ID: "id-foo",
Name: "name-foo",
Enabled: true,
Config: types.PluginConfig{
Config: plugin.Config{
Description: "desc-bar",
},
},
@@ -79,7 +79,7 @@ func TestList(t *testing.T) {
args []string
flags map[string]string
golden string
listFunc func(filter filters.Args) (types.PluginsListResponse, error)
listFunc func(filter filters.Args) (plugin.ListResponse, error)
}{
{
description: "list with no additional flags",
@@ -94,7 +94,7 @@ func TestList(t *testing.T) {
"filter": "foo=bar",
},
golden: "plugin-list-without-format.golden",
listFunc: func(filter filters.Args) (types.PluginsListResponse, error) {
listFunc: func(filter filters.Args) (plugin.ListResponse, error) {
assert.Check(t, is.Equal("bar", filter.Get("foo")[0]))
return singlePluginListFunc(filter)
},
@@ -116,13 +116,13 @@ func TestList(t *testing.T) {
"format": "{{ .ID }}",
},
golden: "plugin-list-with-no-trunc-option.golden",
listFunc: func(_ filters.Args) (types.PluginsListResponse, error) {
return types.PluginsListResponse{
listFunc: func(_ filters.Args) (plugin.ListResponse, error) {
return plugin.ListResponse{
{
ID: "xyg4z2hiSLO5yTnBJfg4OYia9gKA6Qjd",
Name: "name-foo",
Enabled: true,
Config: types.PluginConfig{
Config: plugin.Config{
Description: "desc-bar",
},
},
@@ -145,8 +145,8 @@ func TestList(t *testing.T) {
"format": "{{ .Name }}",
},
golden: "plugin-list-sort.golden",
listFunc: func(_ filters.Args) (types.PluginsListResponse, error) {
return types.PluginsListResponse{
listFunc: func(_ filters.Args) (plugin.ListResponse, error) {
return plugin.ListResponse{
{
ID: "id-1",
Name: "plugin-1-foo",
+3 -3
View File
@@ -7,7 +7,7 @@ import (
"testing"
"github.com/docker/cli/internal/test"
"github.com/moby/moby/api/types"
"github.com/moby/moby/api/types/plugin"
"github.com/moby/moby/client"
"gotest.tools/v3/golden"
)
@@ -20,8 +20,8 @@ func TestUpgradePromptTermination(t *testing.T) {
pluginUpgradeFunc: func(name string, options client.PluginInstallOptions) (io.ReadCloser, error) {
return nil, errors.New("should not be called")
},
pluginInspectFunc: func(name string) (*types.Plugin, []byte, error) {
return &types.Plugin{
pluginInspectFunc: func(name string) (*plugin.Plugin, []byte, error) {
return &plugin.Plugin{
ID: "5724e2c8652da337ab2eedd19fc6fc0ec908e4bd907c7421bf6a8dfc70c4c078",
Name: "foo/bar",
Enabled: false,
+9 -5
View File
@@ -12,7 +12,7 @@ import (
"path/filepath"
"testing"
"github.com/moby/moby/api/types"
"github.com/moby/moby/api/types/plugin"
"gotest.tools/v3/assert"
"gotest.tools/v3/fs"
"gotest.tools/v3/icmd"
@@ -26,13 +26,17 @@ var plugins embed.FS
func SetupPlugin(t *testing.T, ctx context.Context) *fs.Dir {
t.Helper()
p := &types.PluginConfig{
Linux: types.PluginConfigLinux{
p := &plugin.Config{
Linux: plugin.LinuxConfig{
Capabilities: []string{"CAP_SYS_ADMIN"},
},
Interface: types.PluginConfigInterface{
Interface: plugin.Interface{
Socket: "basic.sock",
Types: []types.PluginInterfaceType{{Capability: "docker.dummy/1.0"}},
Types: []plugin.CapabilityID{{
Capability: "dummy",
Prefix: "docker",
Version: "1.0",
}},
},
Entrypoint: []string{"/basic"},
}
+2 -8
View File
@@ -6,12 +6,6 @@ module github.com/docker/cli
go 1.23.0
replace (
// FIXME(thaJeztah): temporarily need to pin on commits, otherwise go modules won't resolve until these are tagged.
github.com/moby/moby/api => github.com/moby/moby/api v0.0.0-20250731152656-4faedf2bec36
github.com/moby/moby/client => github.com/moby/moby/client v0.0.0-20250731152656-4faedf2bec36
)
require (
dario.cat/mergo v1.0.1
github.com/containerd/errdefs v1.0.0
@@ -34,8 +28,8 @@ require (
github.com/google/uuid v1.6.0
github.com/mattn/go-runewidth v0.0.16
github.com/moby/go-archive v0.1.0
github.com/moby/moby/api v0.0.0
github.com/moby/moby/client v0.0.0
github.com/moby/moby/api v1.52.0-alpha.1
github.com/moby/moby/client v0.1.0-alpha.0
github.com/moby/patternmatcher v0.6.0
github.com/moby/swarmkit/v2 v2.0.0
github.com/moby/sys/atomicwriter v0.1.0
+6 -4
View File
@@ -170,10 +170,10 @@ github.com/moby/docker-image-spec v1.3.1 h1:jMKff3w6PgbfSa69GfNg+zN/XLhfXJGnEx3N
github.com/moby/docker-image-spec v1.3.1/go.mod h1:eKmb5VW8vQEh/BAr2yvVNvuiJuY6UIocYsFu/DxxRpo=
github.com/moby/go-archive v0.1.0 h1:Kk/5rdW/g+H8NHdJW2gsXyZ7UnzvJNOy6VKJqueWdcQ=
github.com/moby/go-archive v0.1.0/go.mod h1:G9B+YoujNohJmrIYFBpSd54GTUB4lt9S+xVQvsJyFuo=
github.com/moby/moby/api v0.0.0-20250731152656-4faedf2bec36 h1:2o6bmPZvLOYqE6mQGqnyt+556TMpa26ZtSxvgSpT+98=
github.com/moby/moby/api v0.0.0-20250731152656-4faedf2bec36/go.mod h1:GNQ0zU3WJGeJIcrLPE3xiQnsnLElvfqXQZZZiOqWuiE=
github.com/moby/moby/client v0.0.0-20250731152656-4faedf2bec36 h1:o32ntpp76dDd5Hf9+XL09+qs06120KvZl+Ogt+RkYG0=
github.com/moby/moby/client v0.0.0-20250731152656-4faedf2bec36/go.mod h1:+TFnycF6RuAUAq1tGTjZiSXuRcywpKUGo2dLkJ6tC48=
github.com/moby/moby/api v1.52.0-alpha.1 h1:fzxPD0h6l4LmvPd/rySW7T3G45G8eFTo9qEAEp5UZX0=
github.com/moby/moby/api v1.52.0-alpha.1/go.mod h1:MuA35dxT3DVZpImg0ORGCoZtT2dC1jgPjwH9/CQ/afQ=
github.com/moby/moby/client v0.1.0-alpha.0 h1:1Q393KgwO8L3SznKE+xGZJVDdApgcSM0vIhAEff+acc=
github.com/moby/moby/client v0.1.0-alpha.0/go.mod h1:pVMvmGeD4P9tbgBtEHZKW993Qkj4d1Nu6qhiW3GGJ6k=
github.com/moby/patternmatcher v0.6.0 h1:GmP9lR19aU5GqSSFko+5pRqHi+Ohk1O69aFiKkVGiPk=
github.com/moby/patternmatcher v0.6.0/go.mod h1:hDPoyOpDY7OrrMDLaYoY3hf52gNCR/YOUYxkhApJIxc=
github.com/moby/swarmkit/v2 v2.0.0 h1:jkWQKQaJ4ltA61/mC9UdPe1McLma55RUcacTO+pPweY=
@@ -416,5 +416,7 @@ gotest.tools/v3 v3.5.2 h1:7koQfIKdy+I8UTetycgUqXWSDwpgv193Ka+qRsmBY8Q=
gotest.tools/v3 v3.5.2/go.mod h1:LtdLGcnqToBH83WByAAi/wiwSFCArdFIUV/xxN4pcjA=
k8s.io/klog/v2 v2.90.1 h1:m4bYOKall2MmOiRaR1J+We67Do7vm9KiQVlT96lnHUw=
k8s.io/klog/v2 v2.90.1/go.mod h1:y1WjHnz7Dj687irZUWR/WLkLc5N1YHtjLdmgWjndZn0=
pgregory.net/rapid v1.2.0 h1:keKAYRcjm+e1F0oAuU5F5+YPAWcyxNNRK2wud503Gnk=
pgregory.net/rapid v1.2.0/go.mod h1:PY5XlDGj0+V1FCq0o192FdRhpKHGTRIWBgqjDBTrq04=
tags.cncf.io/container-device-interface v0.8.0 h1:8bCFo/g9WODjWx3m6EYl3GfUG31eKJbaggyBDxEldRc=
tags.cncf.io/container-device-interface v0.8.0/go.mod h1:Apb7N4VdILW0EVdEMRYXIDVRZfNJZ+kmEUss2kRRQ6Y=
+4 -4
View File
@@ -23,7 +23,7 @@ type Progress struct {
// Aux contains extra information not presented to the user, such as
// digests for push signing.
Aux interface{}
Aux any
LastUpdate bool
}
@@ -71,7 +71,7 @@ func Update(out Output, id, action string) {
// Updatef is a convenience function to write a printf-formatted progress update
// to the channel.
func Updatef(out Output, id, format string, a ...interface{}) {
func Updatef(out Output, id, format string, a ...any) {
Update(out, id, fmt.Sprintf(format, a...))
}
@@ -82,12 +82,12 @@ func Message(out Output, id, message string) {
// Messagef is a convenience function to write a printf-formatted progress
// message to the channel.
func Messagef(out Output, id, format string, a ...interface{}) {
func Messagef(out Output, id, format string, a ...any) {
Message(out, id, fmt.Sprintf(format, a...))
}
// Aux sends auxiliary information over a progress interface, which will not be
// formatted for the UI. This is used for things such as push signing.
func Aux(out Output, a interface{}) {
func Aux(out Output, a any) {
out.WriteProgress(Progress{Aux: a})
}
+28 -16
View File
@@ -14,16 +14,13 @@ import (
type StdType byte
const (
// Stdin represents standard input stream type.
Stdin StdType = iota
// Stdout represents standard output stream type.
Stdout
// Stderr represents standard error steam type.
Stderr
// Systemerr represents errors originating from the system that make it
// into the multiplexed stream.
Systemerr
Stdin StdType = 0 // Stdin represents standard input stream. It is present for completeness and should NOT be used. When reading the stream with [StdCopy] it is output on [Stdout].
Stdout StdType = 1 // Stdout represents standard output stream.
Stderr StdType = 2 // Stderr represents standard error steam.
Systemerr StdType = 3 // Systemerr represents errors originating from the system. When reading the stream with [StdCopy] it is returned as an error.
)
const (
stdWriterPrefixLen = 8
stdWriterFdIndex = 0
stdWriterSizeIndex = 4
@@ -31,7 +28,7 @@ const (
startingBufLen = 32*1024 + stdWriterPrefixLen + 1
)
var bufPool = &sync.Pool{New: func() interface{} { return bytes.NewBuffer(nil) }}
var bufPool = &sync.Pool{New: func() any { return bytes.NewBuffer(nil) }}
// stdWriter is wrapper of io.Writer with extra customized info.
type stdWriter struct {
@@ -75,9 +72,20 @@ func (w *stdWriter) Write(p []byte) (int, error) {
// stream "w".
//
// Writers created through NewStdWriter allow for multiple write streams
// (e.g. stdout ([Stdout]) and stderr ([Stderr]) to be multiplexed into a
// (e.g., stdout ([Stdout]) and stderr ([Stderr]) to be multiplexed into a
// single connection. "streamType" indicates the type of stream to encapsulate,
// and can be [Stdin], [Stdout], pr [Stderr].
// commonly, [Stdout] or [Stderr]. The [Systemerr] stream can be used to
// include server-side errors in the stream. Information on this stream
// is returned as an error by [StdCopy] and terminates processing the
// stream.
//
// The [Stdin] stream is present for completeness and should generally
// NOT be used. It is output on [Stdout] when reading the stream with
// [StdCopy].
//
// All streams must share the same underlying [io.Writer] to ensure proper
// multiplexing. Each call to NewStdWriter wraps that shared writer with
// a header indicating the target stream.
func NewStdWriter(w io.Writer, streamType StdType) io.Writer {
return &stdWriter{
Writer: w,
@@ -94,11 +102,15 @@ func NewStdWriter(w io.Writer, streamType StdType) io.Writer {
// [NewStdWriter].
//
// As it reads from "multiplexedSource", StdCopy writes [Stdout] messages
// to "destOut", and [Stderr] message to "destErr].
// to "destOut", and [Stderr] message to "destErr]. For backward-compatibility,
// [Stdin] messages are output to "destOut". The [Systemerr] stream provides
// errors produced by the daemon. It is returned as an error, and terminates
// processing the stream.
//
// StdCopy it reads until it hits [io.EOF] on "multiplexedSource", after
// which it returns a nil error. In other words: any error returned indicates
// a real underlying error.
// a real underlying error, which may be when an unknown [StdType] stream
// is received.
//
// The "written" return holds the total number of bytes written to "destOut"
// and "destErr" combined.
@@ -129,8 +141,8 @@ func StdCopy(destOut, destErr io.Writer, multiplexedSource io.Reader) (written i
}
}
stream := StdType(buf[stdWriterFdIndex])
// Check the first byte to know where to write
stream := StdType(buf[stdWriterFdIndex])
switch stream {
case Stdin:
fallthrough
@@ -146,7 +158,7 @@ func StdCopy(destOut, destErr io.Writer, multiplexedSource io.Reader) (written i
// to outstream if Systemerr is the stream
out = nil
default:
return 0, fmt.Errorf("unrecognized input header: %d", buf[stdWriterFdIndex])
return 0, fmt.Errorf("unrecognized stream: %d", stream)
}
// Retrieve the size of the frame
+8 -8
View File
@@ -42,7 +42,7 @@ func appendNewline(source []byte) []byte {
}
// FormatStatus formats the specified objects according to the specified format (and id).
func FormatStatus(id, format string, a ...interface{}) []byte {
func FormatStatus(id, format string, a ...any) []byte {
str := fmt.Sprintf(format, a...)
b, err := json.Marshal(&jsonMessage{ID: id, Status: str})
if err != nil {
@@ -63,12 +63,12 @@ func FormatError(err error) []byte {
return []byte(`{"error":"format error"}` + streamNewline)
}
func (sf *jsonProgressFormatter) formatStatus(id, format string, a ...interface{}) []byte {
func (sf *jsonProgressFormatter) formatStatus(id, format string, a ...any) []byte {
return FormatStatus(id, format, a...)
}
// formatProgress formats the progress information for a specified action.
func (sf *jsonProgressFormatter) formatProgress(id, action string, progress *jsonstream.Progress, aux interface{}) []byte {
func (sf *jsonProgressFormatter) formatProgress(id, action string, progress *jsonstream.Progress, aux any) []byte {
if progress == nil {
progress = &jsonstream.Progress{}
}
@@ -95,7 +95,7 @@ func (sf *jsonProgressFormatter) formatProgress(id, action string, progress *jso
type rawProgressFormatter struct{}
func (sf *rawProgressFormatter) formatStatus(id, format string, a ...interface{}) []byte {
func (sf *rawProgressFormatter) formatStatus(id, format string, a ...any) []byte {
return []byte(fmt.Sprintf(format, a...) + streamNewline)
}
@@ -155,7 +155,7 @@ func rawProgressString(p *jsonstream.Progress) string {
return pbBox + numbersBox + timeLeftBox
}
func (sf *rawProgressFormatter) formatProgress(id, action string, progress *jsonstream.Progress, aux interface{}) []byte {
func (sf *rawProgressFormatter) formatProgress(id, action string, progress *jsonstream.Progress, aux any) []byte {
if progress == nil {
progress = &jsonstream.Progress{}
}
@@ -180,8 +180,8 @@ func NewJSONProgressOutput(out io.Writer, newLines bool) progress.Output {
}
type formatProgress interface {
formatStatus(id, format string, a ...interface{}) []byte
formatProgress(id, action string, progress *jsonstream.Progress, aux interface{}) []byte
formatStatus(id, format string, a ...any) []byte
formatProgress(id, action string, progress *jsonstream.Progress, aux any) []byte
}
type progressOutput struct {
@@ -227,7 +227,7 @@ type AuxFormatter struct {
}
// Emit emits the given interface as an aux progress message
func (sf *AuxFormatter) Emit(id string, aux interface{}) error {
func (sf *AuxFormatter) Emit(id string, aux any) error {
auxJSONBytes, err := json.Marshal(aux)
if err != nil {
return err
@@ -1,9 +1,13 @@
package types
// Code generated by go-swagger; DO NOT EDIT.
package common
// This file was generated by the swagger tool.
// Editing this file might prove futile when you re-run the swagger generate command
// ErrorResponse Represents an error.
// Example: {"message":"Something went wrong."}
//
// swagger:model ErrorResponse
type ErrorResponse struct {
@@ -1,4 +1,4 @@
package types
package common
// Error returns the error message
func (e ErrorResponse) Error() string {
+3
View File
@@ -1,9 +1,12 @@
// Code generated by go-swagger; DO NOT EDIT.
package common
// This file was generated by the swagger tool.
// Editing this file might prove futile when you re-run the swagger generate command
// IDResponse Response to an API call that returns just an Id
//
// swagger:model IDResponse
type IDResponse struct {
+2
View File
@@ -1,3 +1,5 @@
// Code generated by go-swagger; DO NOT EDIT.
package container
// This file was generated by the swagger tool.
+6 -1
View File
@@ -1,3 +1,5 @@
// Code generated by go-swagger; DO NOT EDIT.
package container
// This file was generated by the swagger tool.
@@ -5,15 +7,18 @@ package container
// CreateResponse ContainerCreateResponse
//
// OK response to ContainerCreate operation
// # OK response to ContainerCreate operation
//
// swagger:model CreateResponse
type CreateResponse struct {
// The ID of the created container
// Example: ede54ee1afda366ab42f824e8a5ffd195155d853ceaec74a927f249ea270c743
// Required: true
ID string `json:"Id"`
// Warnings encountered when creating the container
// Example: []
// Required: true
Warnings []string `json:"Warnings"`
}
+2
View File
@@ -1,3 +1,5 @@
// Code generated by go-swagger; DO NOT EDIT.
package container
// This file was generated by the swagger tool.
+5
View File
@@ -1,9 +1,13 @@
// Code generated by go-swagger; DO NOT EDIT.
package container
// This file was generated by the swagger tool.
// Editing this file might prove futile when you re-run the swagger generate command
// Port An open port on a container
// Example: {"PrivatePort":8080,"PublicPort":80,"Type":"tcp"}
//
// swagger:model Port
type Port struct {
@@ -19,5 +23,6 @@ type Port struct {
// type
// Required: true
// Enum: ["tcp","udp","sctp"]
Type string `json:"Type"`
}
+5
View File
@@ -1,3 +1,5 @@
// Code generated by go-swagger; DO NOT EDIT.
package container
// This file was generated by the swagger tool.
@@ -6,13 +8,16 @@ package container
// TopResponse ContainerTopResponse
//
// Container "top" response.
//
// swagger:model TopResponse
type TopResponse struct {
// Each process running in the container, where each process
// is an array of values corresponding to the titles.
// Example: {"Processes":[["root","13642","882","0","17:03","pts/0","00:00:00","/bin/bash"],["root","13735","13642","0","17:06","pts/0","00:00:00","sleep 10"]]}
Processes [][]string `json:"Processes"`
// The ps column titles
// Example: {"Titles":["UID","PID","PPID","C","STIME","TTY","TIME","CMD"]}
Titles []string `json:"Titles"`
}
+4
View File
@@ -1,3 +1,5 @@
// Code generated by go-swagger; DO NOT EDIT.
package container
// This file was generated by the swagger tool.
@@ -6,9 +8,11 @@ package container
// UpdateResponse ContainerUpdateResponse
//
// Response for a successful container-update.
//
// swagger:model UpdateResponse
type UpdateResponse struct {
// Warnings encountered when updating the container.
// Example: ["Published ports are discarded when using host network mode"]
Warnings []string `json:"Warnings"`
}
+3
View File
@@ -1,9 +1,12 @@
// Code generated by go-swagger; DO NOT EDIT.
package container
// This file was generated by the swagger tool.
// Editing this file might prove futile when you re-run the swagger generate command
// WaitExitError container waiting error, if any
//
// swagger:model WaitExitError
type WaitExitError struct {
+4 -1
View File
@@ -1,3 +1,5 @@
// Code generated by go-swagger; DO NOT EDIT.
package container
// This file was generated by the swagger tool.
@@ -5,7 +7,8 @@ package container
// WaitResponse ContainerWaitResponse
//
// OK response to ContainerWait operation
// # OK response to ContainerWait operation
//
// swagger:model WaitResponse
type WaitResponse struct {
+3
View File
@@ -1,9 +1,12 @@
// Code generated by go-swagger; DO NOT EDIT.
package image
// This file was generated by the swagger tool.
// Editing this file might prove futile when you re-run the swagger generate command
// DeleteResponse delete response
//
// swagger:model DeleteResponse
type DeleteResponse struct {
+1
View File
@@ -7,6 +7,7 @@ package image
// ----------------------------------------------------------------------------
// HistoryResponseItem individual image layer information in response to ImageHistory operation
//
// swagger:model HistoryResponseItem
type HistoryResponseItem struct {
+5 -1
View File
@@ -1,3 +1,5 @@
// Code generated by go-swagger; DO NOT EDIT.
package network
// This file was generated by the swagger tool.
@@ -5,11 +7,13 @@ package network
// CreateResponse NetworkCreateResponse
//
// OK response to NetworkCreate operation
// # OK response to NetworkCreate operation
//
// swagger:model CreateResponse
type CreateResponse struct {
// The ID of the created network.
// Example: b5c4fc71e8022147cd25de22b22173de4e3b170134117172eb595cb91b4e7e5d
// Required: true
ID string `json:"Id"`
+1
View File
@@ -0,0 +1 @@
testdata/rapid/**
+55
View File
@@ -0,0 +1,55 @@
package plugin
import (
"bytes"
"encoding"
"fmt"
"strings"
)
type CapabilityID struct {
Capability string
Prefix string
Version string
}
var (
_ fmt.Stringer = CapabilityID{}
_ encoding.TextUnmarshaler = (*CapabilityID)(nil)
_ encoding.TextMarshaler = CapabilityID{}
)
// String implements [fmt.Stringer] for CapabilityID
func (t CapabilityID) String() string {
return fmt.Sprintf("%s.%s/%s", t.Prefix, t.Capability, t.Version)
}
// UnmarshalText implements [encoding.TextUnmarshaler] for CapabilityID
func (t *CapabilityID) UnmarshalText(p []byte) error {
fqcap, version, _ := bytes.Cut(p, []byte{'/'})
idx := bytes.LastIndexByte(fqcap, '.')
if idx < 0 {
t.Prefix = ""
t.Capability = string(fqcap)
} else {
t.Prefix = string(fqcap[:idx])
t.Capability = string(fqcap[idx+1:])
}
t.Version = string(version)
return nil
}
// MarshalText implements [encoding.TextMarshaler] for CapabilityID
func (t CapabilityID) MarshalText() ([]byte, error) {
// Assert that the value can be round-tripped successfully.
if strings.Contains(t.Capability, ".") {
return nil, fmt.Errorf("capability %q cannot contain a dot", t.Capability)
}
if strings.Contains(t.Prefix, "/") {
return nil, fmt.Errorf("prefix %q cannot contain a slash", t.Prefix)
}
if strings.Contains(t.Capability, "/") {
return nil, fmt.Errorf("capability %q cannot contain a slash", t.Capability)
}
return []byte(t.String()), nil
}
@@ -1,11 +1,14 @@
package types
// Code generated by go-swagger; DO NOT EDIT.
package plugin
// This file was generated by the swagger tool.
// Editing this file might prove futile when you re-run the swagger generate command
// PluginDevice plugin device
// swagger:model PluginDevice
type PluginDevice struct {
// Device device
//
// swagger:model Device
type Device struct {
// description
// Required: true
@@ -16,6 +19,7 @@ type PluginDevice struct {
Name string `json:"Name"`
// path
// Example: /dev/fuse
// Required: true
Path *string `json:"Path"`
@@ -1,11 +1,14 @@
package types
// Code generated by go-swagger; DO NOT EDIT.
package plugin
// This file was generated by the swagger tool.
// Editing this file might prove futile when you re-run the swagger generate command
// PluginEnv plugin env
// swagger:model PluginEnv
type PluginEnv struct {
// Env env
//
// swagger:model Env
type Env struct {
// description
// Required: true
@@ -1,25 +1,32 @@
package types
// Code generated by go-swagger; DO NOT EDIT.
package plugin
// This file was generated by the swagger tool.
// Editing this file might prove futile when you re-run the swagger generate command
// PluginMount plugin mount
// swagger:model PluginMount
type PluginMount struct {
// Mount mount
//
// swagger:model Mount
type Mount struct {
// description
// Example: This is a mount that's used by the plugin.
// Required: true
Description string `json:"Description"`
// destination
// Example: /mnt/state
// Required: true
Destination string `json:"Destination"`
// name
// Example: some-mount
// Required: true
Name string `json:"Name"`
// options
// Example: ["rbind","rw"]
// Required: true
Options []string `json:"Options"`
@@ -28,10 +35,12 @@ type PluginMount struct {
Settable []string `json:"Settable"`
// source
// Example: /var/lib/docker/plugins/
// Required: true
Source *string `json:"Source"`
// type
// Example: bind
// Required: true
Type string `json:"Type"`
}
@@ -1,110 +1,130 @@
package types
// Code generated by go-swagger; DO NOT EDIT.
package plugin
// This file was generated by the swagger tool.
// Editing this file might prove futile when you re-run the swagger generate command
// Plugin A plugin for the Engine API
//
// swagger:model Plugin
type Plugin struct {
// config
// Required: true
Config PluginConfig `json:"Config"`
Config Config `json:"Config"`
// True if the plugin is running. False if the plugin is not running, only installed.
// Example: true
// Required: true
Enabled bool `json:"Enabled"`
// Id
// Example: 5724e2c8652da337ab2eedd19fc6fc0ec908e4bd907c7421bf6a8dfc70c4c078
ID string `json:"Id,omitempty"`
// name
// Example: tiborvass/sample-volume-plugin
// Required: true
Name string `json:"Name"`
// plugin remote reference used to push/pull the plugin
// Example: localhost:5000/tiborvass/sample-volume-plugin:latest
PluginReference string `json:"PluginReference,omitempty"`
// settings
// Required: true
Settings PluginSettings `json:"Settings"`
Settings Settings `json:"Settings"`
}
// PluginConfig The config of a plugin.
// swagger:model PluginConfig
type PluginConfig struct {
// Config The config of a plugin.
//
// swagger:model Config
type Config struct {
// args
// Required: true
Args PluginConfigArgs `json:"Args"`
Args Args `json:"Args"`
// description
// Example: A sample volume plugin for Docker
// Required: true
Description string `json:"Description"`
// Docker Version used to create the plugin
// Example: 17.06.0-ce
DockerVersion string `json:"DockerVersion,omitempty"`
// documentation
// Example: https://docs.docker.com/engine/extend/plugins/
// Required: true
Documentation string `json:"Documentation"`
// entrypoint
// Example: ["/usr/bin/sample-volume-plugin","/data"]
// Required: true
Entrypoint []string `json:"Entrypoint"`
// env
// Example: [{"Description":"If set, prints debug messages","Name":"DEBUG","Settable":null,"Value":"0"}]
// Required: true
Env []PluginEnv `json:"Env"`
Env []Env `json:"Env"`
// interface
// Required: true
Interface PluginConfigInterface `json:"Interface"`
Interface Interface `json:"Interface"`
// ipc host
// Example: false
// Required: true
IpcHost bool `json:"IpcHost"`
// linux
// Required: true
Linux PluginConfigLinux `json:"Linux"`
Linux LinuxConfig `json:"Linux"`
// mounts
// Required: true
Mounts []PluginMount `json:"Mounts"`
Mounts []Mount `json:"Mounts"`
// network
// Required: true
Network PluginConfigNetwork `json:"Network"`
Network NetworkConfig `json:"Network"`
// pid host
// Example: false
// Required: true
PidHost bool `json:"PidHost"`
// propagated mount
// Example: /mnt/volumes
// Required: true
PropagatedMount string `json:"PropagatedMount"`
// user
User PluginConfigUser `json:"User,omitempty"`
User User `json:"User,omitempty"`
// work dir
// Example: /bin/
// Required: true
WorkDir string `json:"WorkDir"`
// rootfs
Rootfs *PluginConfigRootfs `json:"rootfs,omitempty"`
Rootfs *RootFS `json:"rootfs,omitempty"`
}
// PluginConfigArgs plugin config args
// swagger:model PluginConfigArgs
type PluginConfigArgs struct {
// Args args
//
// swagger:model Args
type Args struct {
// description
// Example: command line arguments
// Required: true
Description string `json:"Description"`
// name
// Example: args
// Required: true
Name string `json:"Name"`
@@ -117,73 +137,90 @@ type PluginConfigArgs struct {
Value []string `json:"Value"`
}
// PluginConfigInterface The interface between Docker and the plugin
// swagger:model PluginConfigInterface
type PluginConfigInterface struct {
// Interface The interface between Docker and the plugin
//
// swagger:model Interface
type Interface struct {
// Protocol to use for clients connecting to the plugin.
// Example: some.protocol/v1.0
// Enum: ["","moby.plugins.http/v1"]
ProtocolScheme string `json:"ProtocolScheme,omitempty"`
// socket
// Example: plugins.sock
// Required: true
Socket string `json:"Socket"`
// types
// Example: ["docker.volumedriver/1.0"]
// Required: true
Types []PluginInterfaceType `json:"Types"`
Types []CapabilityID `json:"Types"`
}
// PluginConfigLinux plugin config linux
// swagger:model PluginConfigLinux
type PluginConfigLinux struct {
// LinuxConfig linux config
//
// swagger:model LinuxConfig
type LinuxConfig struct {
// allow all devices
// Example: false
// Required: true
AllowAllDevices bool `json:"AllowAllDevices"`
// capabilities
// Example: ["CAP_SYS_ADMIN","CAP_SYSLOG"]
// Required: true
Capabilities []string `json:"Capabilities"`
// devices
// Required: true
Devices []PluginDevice `json:"Devices"`
Devices []Device `json:"Devices"`
}
// PluginConfigNetwork plugin config network
// swagger:model PluginConfigNetwork
type PluginConfigNetwork struct {
// NetworkConfig network config
//
// swagger:model NetworkConfig
type NetworkConfig struct {
// type
// Example: host
// Required: true
Type string `json:"Type"`
}
// PluginConfigRootfs plugin config rootfs
// swagger:model PluginConfigRootfs
type PluginConfigRootfs struct {
// RootFS root f s
//
// swagger:model RootFS
type RootFS struct {
// diff ids
// Example: ["sha256:675532206fbf3030b8458f88d6e26d4eb1577688a25efec97154c94e8b6b4887","sha256:e216a057b1cb1efc11f8a268f37ef62083e70b1b38323ba252e25ac88904a7e8"]
DiffIds []string `json:"diff_ids"`
// type
// Example: layers
Type string `json:"type,omitempty"`
}
// PluginConfigUser plugin config user
// swagger:model PluginConfigUser
type PluginConfigUser struct {
// User user
//
// swagger:model User
type User struct {
// g ID
// Example: 1000
GID uint32 `json:"GID,omitempty"`
// UID
// Example: 1000
UID uint32 `json:"UID,omitempty"`
}
// PluginSettings Settings that can be modified by users.
// swagger:model PluginSettings
type PluginSettings struct {
// Settings user-configurable settings for the plugin.
//
// swagger:model Settings
type Settings struct {
// args
// Required: true
@@ -191,13 +228,14 @@ type PluginSettings struct {
// devices
// Required: true
Devices []PluginDevice `json:"Devices"`
Devices []Device `json:"Devices"`
// env
// Example: ["DEBUG=0"]
// Required: true
Env []string `json:"Env"`
// mounts
// Required: true
Mounts []PluginMount `json:"Mounts"`
Mounts []Mount `json:"Mounts"`
}
+33
View File
@@ -0,0 +1,33 @@
package plugin
import (
"sort"
)
// ListResponse contains the response for the Engine API
type ListResponse []*Plugin
// Privilege describes a permission the user has to accept
// upon installing a plugin.
type Privilege struct {
Name string
Description string
Value []string
}
// Privileges is a list of Privilege
type Privileges []Privilege
func (s Privileges) Len() int {
return len(s)
}
func (s Privileges) Less(i, j int) bool {
return s[i].Name < s[j].Name
}
func (s Privileges) Swap(i, j int) {
sort.Strings(s[i].Value)
sort.Strings(s[j].Value)
s[i], s[j] = s[j], s[i]
}
-21
View File
@@ -1,21 +0,0 @@
package types
// This file was generated by the swagger tool.
// Editing this file might prove futile when you re-run the swagger generate command
// PluginInterfaceType plugin interface type
// swagger:model PluginInterfaceType
type PluginInterfaceType struct {
// capability
// Required: true
Capability string `json:"Capability"`
// prefix
// Required: true
Prefix string `json:"Prefix"`
// version
// Required: true
Version string `json:"Version"`
}
-71
View File
@@ -1,71 +0,0 @@
package types
import (
"encoding/json"
"fmt"
"sort"
)
// PluginsListResponse contains the response for the Engine API
type PluginsListResponse []*Plugin
// UnmarshalJSON implements json.Unmarshaler for PluginInterfaceType
func (t *PluginInterfaceType) UnmarshalJSON(p []byte) error {
versionIndex := len(p)
prefixIndex := 0
if len(p) < 2 || p[0] != '"' || p[len(p)-1] != '"' {
return fmt.Errorf("%q is not a plugin interface type", p)
}
p = p[1 : len(p)-1]
loop:
for i, b := range p {
switch b {
case '.':
prefixIndex = i
case '/':
versionIndex = i
break loop
}
}
t.Prefix = string(p[:prefixIndex])
t.Capability = string(p[prefixIndex+1 : versionIndex])
if versionIndex < len(p) {
t.Version = string(p[versionIndex+1:])
}
return nil
}
// MarshalJSON implements json.Marshaler for PluginInterfaceType
func (t *PluginInterfaceType) MarshalJSON() ([]byte, error) {
return json.Marshal(t.String())
}
// String implements fmt.Stringer for PluginInterfaceType
func (t PluginInterfaceType) String() string {
return fmt.Sprintf("%s.%s/%s", t.Prefix, t.Capability, t.Version)
}
// PluginPrivilege describes a permission the user has to accept
// upon installing a plugin.
type PluginPrivilege struct {
Name string
Description string
Value []string
}
// PluginPrivileges is a list of PluginPrivilege
type PluginPrivileges []PluginPrivilege
func (s PluginPrivileges) Len() int {
return len(s)
}
func (s PluginPrivileges) Less(i, j int) bool {
return s[i].Name < s[j].Name
}
func (s PluginPrivileges) Swap(i, j int) {
sort.Strings(s[i].Value)
sort.Strings(s[j].Value)
s[i], s[j] = s[j], s[i]
}
+4
View File
@@ -1,3 +1,5 @@
// Code generated by go-swagger; DO NOT EDIT.
package storage
// This file was generated by the swagger tool.
@@ -14,10 +16,12 @@ type DriverData struct {
// This information is driver-specific, and depends on the storage-driver
// in use, and should be used for informational purposes only.
//
// Example: {"MergedDir":"/var/lib/docker/overlay2/ef749362d13333e65fc95c572eb525abbe0052e16e086cb64bc3b98ae9aa6d74/merged","UpperDir":"/var/lib/docker/overlay2/ef749362d13333e65fc95c572eb525abbe0052e16e086cb64bc3b98ae9aa6d74/diff","WorkDir":"/var/lib/docker/overlay2/ef749362d13333e65fc95c572eb525abbe0052e16e086cb64bc3b98ae9aa6d74/work"}
// Required: true
Data map[string]string `json:"Data"`
// Name of the storage driver.
// Example: overlay2
// Required: true
Name string `json:"Name"`
}
+1 -1
View File
@@ -25,7 +25,7 @@ type SecretSpec struct {
// This field is only used to create the secret, and is not returned
// by other endpoints.
//
// [MaxSecretSize]: https://pkg.go.dev/github.com/moby/swarmkit/v2@v2.0.0-20250103191802-8c1959736554/api/validation#MaxSecretSize
// [MaxSecretSize]: https://pkg.go.dev/github.com/moby/swarmkit/v2@v2.0.0/api/validation#MaxSecretSize
Data []byte `json:",omitempty"`
// Driver is the name of the secrets driver used to fetch the secret's
@@ -1,3 +1,5 @@
// Code generated by go-swagger; DO NOT EDIT.
package swarm
// This file was generated by the swagger tool.
@@ -10,11 +12,13 @@ package swarm
type ServiceCreateResponse struct {
// The ID of the created service.
// Example: ak7w3gjqoa3kuz8xcpnyy0pvl
ID string `json:"ID,omitempty"`
// Optional warning message.
//
// FIXME(thaJeztah): this should have "omitempty" in the generated type.
//
// Example: ["unable to pin image doesnotexist:latest to digest: image library/doesnotexist:latest not found"]
Warnings []string `json:"Warnings"`
}
@@ -1,9 +1,13 @@
// Code generated by go-swagger; DO NOT EDIT.
package swarm
// This file was generated by the swagger tool.
// Editing this file might prove futile when you re-run the swagger generate command
// ServiceUpdateResponse service update response
// Example: {"Warnings":["unable to pin image doesnotexist:latest to digest: image library/doesnotexist:latest not found"]}
//
// swagger:model ServiceUpdateResponse
type ServiceUpdateResponse struct {
+2 -2
View File
@@ -9,8 +9,8 @@ type Runtime struct {
// Shimv2 runtime configuration. Mutually exclusive with the legacy config above.
Type string `json:"runtimeType,omitempty"`
Options map[string]interface{} `json:"options,omitempty"`
Type string `json:"runtimeType,omitempty"`
Options map[string]any `json:"options,omitempty"`
}
// RuntimeWithStatus extends [Runtime] to hold [RuntimeStatus].
+8 -1
View File
@@ -1,3 +1,5 @@
// Code generated by go-swagger; DO NOT EDIT.
package volume
// This file was generated by the swagger tool.
@@ -5,7 +7,8 @@ package volume
// CreateOptions VolumeConfig
//
// Volume configuration
// # Volume configuration
//
// swagger:model CreateOptions
type CreateOptions struct {
@@ -13,17 +16,21 @@ type CreateOptions struct {
ClusterVolumeSpec *ClusterVolumeSpec `json:"ClusterVolumeSpec,omitempty"`
// Name of the volume driver to use.
// Example: custom
Driver string `json:"Driver,omitempty"`
// A mapping of driver options and values. These options are
// passed directly to the driver and are driver specific.
//
// Example: {"device":"tmpfs","o":"size=100m,uid=1000","type":"tmpfs"}
DriverOpts map[string]string `json:"DriverOpts,omitempty"`
// User-defined key/value metadata.
// Example: {"com.example.some-label":"some-value","com.example.some-other-label":"some-other-value"}
Labels map[string]string `json:"Labels,omitempty"`
// The new volume's name. If not specified, Docker generates a name.
//
// Example: tardis
Name string `json:"Name,omitempty"`
}
+5 -1
View File
@@ -1,3 +1,5 @@
// Code generated by go-swagger; DO NOT EDIT.
package volume
// This file was generated by the swagger tool.
@@ -5,7 +7,8 @@ package volume
// ListResponse VolumeListResponse
//
// Volume list response
// # Volume list response
//
// swagger:model ListResponse
type ListResponse struct {
@@ -14,5 +17,6 @@ type ListResponse struct {
// Warnings that occurred when fetching the list of volumes.
//
// Example: []
Warnings []string `json:"Warnings"`
}
+12
View File
@@ -1,9 +1,12 @@
// Code generated by go-swagger; DO NOT EDIT.
package volume
// This file was generated by the swagger tool.
// Editing this file might prove futile when you re-run the swagger generate command
// Volume volume
//
// swagger:model Volume
type Volume struct {
@@ -11,33 +14,41 @@ type Volume struct {
ClusterVolume *ClusterVolume `json:"ClusterVolume,omitempty"`
// Date/Time the volume was created.
// Example: 2016-06-07T20:31:11.853781916Z
CreatedAt string `json:"CreatedAt,omitempty"`
// Name of the volume driver used by the volume.
// Example: custom
// Required: true
Driver string `json:"Driver"`
// User-defined key/value metadata.
// Example: {"com.example.some-label":"some-value","com.example.some-other-label":"some-other-value"}
// Required: true
Labels map[string]string `json:"Labels"`
// Mount path of the volume on the host.
// Example: /var/lib/docker/volumes/tardis
// Required: true
Mountpoint string `json:"Mountpoint"`
// Name of the volume.
// Example: tardis
// Required: true
Name string `json:"Name"`
// The driver specific options used when creating the volume.
//
// Example: {"device":"tmpfs","o":"size=100m,uid=1000","type":"tmpfs"}
// Required: true
Options map[string]string `json:"Options"`
// The level at which the volume exists. Either `global` for cluster-wide,
// or `local` for machine level.
//
// Example: local
// Required: true
// Enum: ["local","global"]
Scope string `json:"Scope"`
// Low-level details about the volume, provided by the volume driver.
@@ -47,6 +58,7 @@ type Volume struct {
// The `Status` field is optional, and is omitted if the volume driver
// does not support this feature.
//
// Example: {"hello":"world"}
Status map[string]interface{} `json:"Status,omitempty"`
// usage data
+2 -1
View File
@@ -5,7 +5,8 @@ import (
"net/url"
)
// BuildCancel requests the daemon to cancel the ongoing build request.
// BuildCancel requests the daemon to cancel the ongoing build request
// with the given id.
func (cli *Client) BuildCancel(ctx context.Context, id string) error {
query := url.Values{}
query.Set("id", id)
+4 -4
View File
@@ -3,15 +3,15 @@ package client
import (
"context"
"encoding/json"
"fmt"
"net/url"
"strconv"
"github.com/moby/moby/api/types/build"
"github.com/moby/moby/api/types/filters"
"github.com/pkg/errors"
)
// BuildCachePrune requests the daemon to delete unused cache data
// BuildCachePrune requests the daemon to delete unused cache data.
func (cli *Client) BuildCachePrune(ctx context.Context, opts build.CachePruneOptions) (*build.CachePruneReport, error) {
if err := cli.NewVersionError(ctx, "1.31", "build prune"); err != nil {
return nil, err
@@ -36,7 +36,7 @@ func (cli *Client) BuildCachePrune(ctx context.Context, opts build.CachePruneOpt
}
f, err := filters.ToJSON(opts.Filters)
if err != nil {
return nil, errors.Wrap(err, "prune could not marshal filters option")
return nil, fmt.Errorf("prune could not marshal filters option: %w", err)
}
query.Set("filters", f)
@@ -49,7 +49,7 @@ func (cli *Client) BuildCachePrune(ctx context.Context, opts build.CachePruneOpt
report := build.CachePruneReport{}
if err := json.NewDecoder(resp.Body).Decode(&report); err != nil {
return nil, errors.Wrap(err, "error retrieving disk usage")
return nil, fmt.Errorf("error retrieving disk usage: %w", err)
}
return &report, nil
+1 -1
View File
@@ -6,7 +6,7 @@ import (
"github.com/moby/moby/api/types/checkpoint"
)
// CheckpointCreate creates a checkpoint from the given container with the given name
// CheckpointCreate creates a checkpoint from the given container.
func (cli *Client) CheckpointCreate(ctx context.Context, containerID string, options checkpoint.CreateOptions) error {
containerID, err := trimID("container", containerID)
if err != nil {
+1 -1
View File
@@ -7,7 +7,7 @@ import (
"github.com/moby/moby/api/types/checkpoint"
)
// CheckpointDelete deletes the checkpoint with the given name from the given container
// CheckpointDelete deletes the checkpoint with the given name from the given container.
func (cli *Client) CheckpointDelete(ctx context.Context, containerID string, options checkpoint.DeleteOptions) error {
containerID, err := trimID("container", containerID)
if err != nil {
+1 -1
View File
@@ -8,7 +8,7 @@ import (
"github.com/moby/moby/api/types/checkpoint"
)
// CheckpointList returns the checkpoints of the given container in the docker host
// CheckpointList returns the checkpoints of the given container in the docker host.
func (cli *Client) CheckpointList(ctx context.Context, container string, options checkpoint.ListOptions) ([]checkpoint.Summary, error) {
var checkpoints []checkpoint.Summary
+3 -2
View File
@@ -44,6 +44,8 @@ package client
import (
"context"
"crypto/tls"
"errors"
"fmt"
"net"
"net/http"
"net/url"
@@ -56,7 +58,6 @@ import (
"github.com/docker/go-connections/sockets"
"github.com/moby/moby/api/types"
"github.com/moby/moby/api/types/versions"
"github.com/pkg/errors"
"go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp"
)
@@ -421,7 +422,7 @@ func (cli *Client) HTTPClient() *http.Client {
func ParseHostURL(host string) (*url.URL, error) {
proto, addr, ok := strings.Cut(host, "://")
if !ok || addr == "" {
return nil, errors.Errorf("unable to parse docker host `%s`", host)
return nil, fmt.Errorf("unable to parse docker host `%s`", host)
}
var basePath string
+3 -2
View File
@@ -13,6 +13,7 @@ import (
"github.com/moby/moby/api/types/filters"
"github.com/moby/moby/api/types/image"
"github.com/moby/moby/api/types/network"
"github.com/moby/moby/api/types/plugin"
"github.com/moby/moby/api/types/registry"
"github.com/moby/moby/api/types/swarm"
"github.com/moby/moby/api/types/system"
@@ -147,7 +148,7 @@ type NodeAPIClient interface {
// PluginAPIClient defines API client methods for the plugins
type PluginAPIClient interface {
PluginList(ctx context.Context, filter filters.Args) (types.PluginsListResponse, error)
PluginList(ctx context.Context, filter filters.Args) (plugin.ListResponse, error)
PluginRemove(ctx context.Context, name string, options PluginRemoveOptions) error
PluginEnable(ctx context.Context, name string, options PluginEnableOptions) error
PluginDisable(ctx context.Context, name string, options PluginDisableOptions) error
@@ -155,7 +156,7 @@ type PluginAPIClient interface {
PluginUpgrade(ctx context.Context, name string, options PluginInstallOptions) (io.ReadCloser, error)
PluginPush(ctx context.Context, name string, registryAuth string) (io.ReadCloser, error)
PluginSet(ctx context.Context, name string, args []string) error
PluginInspectWithRaw(ctx context.Context, name string) (*types.Plugin, []byte, error)
PluginInspectWithRaw(ctx context.Context, name string) (*plugin.Plugin, []byte, error)
PluginCreate(ctx context.Context, createContext io.Reader, options PluginCreateOptions) error
}
+20 -16
View File
@@ -9,29 +9,33 @@ import (
)
// ContainerAttach attaches a connection to a container in the server.
// It returns a types.HijackedConnection with the hijacked connection
// and the a reader to get output. It's up to the called to close
// the hijacked connection by calling types.HijackedResponse.Close.
// It returns a [HijackedResponse] with the hijacked connection
// and a reader to get output. It's up to the called to close
// the hijacked connection by calling [HijackedResponse.Close].
//
// The stream format on the response will be in one of two formats:
// The stream format on the response uses one of two formats:
//
// If the container is using a TTY, there is only a single stream (stdout), and
// data is copied directly from the container output stream, no extra
// multiplexing or headers.
// - If the container is using a TTY, there is only a single stream (stdout)
// and data is copied directly from the container output stream, no extra
// multiplexing or headers.
// - If the container is *not* using a TTY, streams for stdout and stderr are
// multiplexed.
//
// If the container is *not* using a TTY, streams for stdout and stderr are
// multiplexed.
// The format of the multiplexed stream is as follows:
// The format of the multiplexed stream is defined in the [stdcopy] package,
// and as follows:
//
// [8]byte{STREAM_TYPE, 0, 0, 0, SIZE1, SIZE2, SIZE3, SIZE4}[]byte{OUTPUT}
//
// STREAM_TYPE can be 1 for stdout and 2 for stderr
// STREAM_TYPE can be 1 for [Stdout] and 2 for [Stderr]. Refer to [stdcopy.StdType]
// for details. SIZE1, SIZE2, SIZE3, and SIZE4 are four bytes of uint32 encoded
// as big endian, this is the size of OUTPUT. You can use [stdcopy.StdCopy]
// to demultiplex this stream.
//
// SIZE1, SIZE2, SIZE3, and SIZE4 are four bytes of uint32 encoded as big endian.
// This is the size of OUTPUT.
//
// You can use github.com/moby/moby/api/stdcopy.StdCopy to demultiplex this
// stream.
// [stdcopy]: https://pkg.go.dev/github.com/moby/moby/api/pkg/stdcopy
// [stdcopy.StdCopy]: https://pkg.go.dev/github.com/moby/moby/api/pkg/stdcopy#StdCopy
// [stdcopy.StdType]: https://pkg.go.dev/github.com/moby/moby/api/pkg/stdcopy#StdType
// [Stdout]: https://pkg.go.dev/github.com/moby/moby/api/pkg/stdcopy#Stdout
// [Stderr]: https://pkg.go.dev/github.com/moby/moby/api/pkg/stdcopy#Stderr
func (cli *Client) ContainerAttach(ctx context.Context, containerID string, options container.AttachOptions) (HijackedResponse, error) {
containerID, err := trimID("container", containerID)
if err != nil {
+1 -1
View File
@@ -73,7 +73,7 @@ func (cli *Client) ContainerCreate(ctx context.Context, config *container.Config
hostConfig.CapDrop = normalizeCapabilities(hostConfig.CapDrop)
}
// Since API 1.44, the container-wide MacAddress is deprecated and will trigger a WARNING if it's specified.
// Since API 1.44, the container-wide MacAddress is deprecated and triggers a WARNING if it's specified.
if versions.GreaterThanOrEqualTo(cli.ClientVersion(), "1.44") {
config.MacAddress = "" //nolint:staticcheck // ignore SA1019: field is deprecated, but still used on API < v1.44.
}
+9 -8
View File
@@ -64,21 +64,22 @@ func (cli *Client) ContainerExecStart(ctx context.Context, execID string, config
// ContainerExecAttach attaches a connection to an exec process in the server.
//
// It returns a [types.HijackedResponse] with the hijacked connection
// and the a reader to get output. It's up to the called to close
// the hijacked connection by calling [types.HijackedResponse.Close].
// It returns a [HijackedResponse] with the hijacked connection
// and a reader to get output. It's up to the called to close
// the hijacked connection by calling [HijackedResponse.Close].
//
// The stream format on the response uses one of two formats:
//
// - If the container is using a TTY, there is only a single stream (stdout), and
// data is copied directly from the container output stream, no extra
// - If the container is using a TTY, there is only a single stream (stdout)
// and data is copied directly from the container output stream, no extra
// multiplexing or headers.
// - If the container is *not* using a TTY, streams for stdout and stderr are
// multiplexed.
//
// You can use [github.com/moby/moby/api/stdcopy.StdCopy] to demultiplex this
// stream. Refer to [Client.ContainerAttach] for details about the multiplexed
// stream.
// You can use [stdcopy.StdCopy] to demultiplex this stream. Refer to
// [Client.ContainerAttach] for details about the multiplexed stream.
//
// [stdcopy.StdCopy]: https://pkg.go.dev/github.com/moby/moby/api/pkg/stdcopy#StdCopy
func (cli *Client) ContainerExecAttach(ctx context.Context, execID string, config container.ExecAttachOptions) (HijackedResponse, error) {
if versions.LessThan(cli.ClientVersion(), "1.42") {
config.ConsoleSize = nil
+1 -1
View File
@@ -7,7 +7,7 @@ import (
)
// ContainerExport retrieves the raw contents of a container
// and returns them as an io.ReadCloser. It's up to the caller
// and returns them as an [io.ReadCloser]. It's up to the caller
// to close the stream.
func (cli *Client) ContainerExport(ctx context.Context, containerID string) (io.ReadCloser, error) {
containerID, err := trimID("container", containerID)
+21 -17
View File
@@ -2,37 +2,41 @@ package client
import (
"context"
"fmt"
"io"
"net/url"
"time"
"github.com/moby/moby/api/types/container"
timetypes "github.com/moby/moby/api/types/time"
"github.com/pkg/errors"
)
// ContainerLogs returns the logs generated by a container in an io.ReadCloser.
// ContainerLogs returns the logs generated by a container in an [io.ReadCloser].
// It's up to the caller to close the stream.
//
// The stream format on the response will be in one of two formats:
// The stream format on the response uses one of two formats:
//
// If the container is using a TTY, there is only a single stream (stdout), and
// data is copied directly from the container output stream, no extra
// multiplexing or headers.
// - If the container is using a TTY, there is only a single stream (stdout)
// and data is copied directly from the container output stream, no extra
// multiplexing or headers.
// - If the container is *not* using a TTY, streams for stdout and stderr are
// multiplexed.
//
// If the container is *not* using a TTY, streams for stdout and stderr are
// multiplexed.
// The format of the multiplexed stream is as follows:
// The format of the multiplexed stream is defined in the [stdcopy] package,
// and as follows:
//
// [8]byte{STREAM_TYPE, 0, 0, 0, SIZE1, SIZE2, SIZE3, SIZE4}[]byte{OUTPUT}
//
// STREAM_TYPE can be 1 for stdout and 2 for stderr
// STREAM_TYPE can be 1 for [Stdout] and 2 for [Stderr]. Refer to [stdcopy.StdType]
// for details. SIZE1, SIZE2, SIZE3, and SIZE4 are four bytes of uint32 encoded
// as big endian, this is the size of OUTPUT. You can use [stdcopy.StdCopy]
// to demultiplex this stream.
//
// SIZE1, SIZE2, SIZE3, and SIZE4 are four bytes of uint32 encoded as big endian.
// This is the size of OUTPUT.
//
// You can use github.com/moby/moby/api/stdcopy.StdCopy to demultiplex this
// stream.
// [stdcopy]: https://pkg.go.dev/github.com/moby/moby/api/pkg/stdcopy
// [stdcopy.StdCopy]: https://pkg.go.dev/github.com/moby/moby/api/pkg/stdcopy#StdCopy
// [stdcopy.StdType]: https://pkg.go.dev/github.com/moby/moby/api/pkg/stdcopy#StdType
// [Stdout]: https://pkg.go.dev/github.com/moby/moby/api/pkg/stdcopy#Stdout
// [Stderr]: https://pkg.go.dev/github.com/moby/moby/api/pkg/stdcopy#Stderr
func (cli *Client) ContainerLogs(ctx context.Context, containerID string, options container.LogsOptions) (io.ReadCloser, error) {
containerID, err := trimID("container", containerID)
if err != nil {
@@ -51,7 +55,7 @@ func (cli *Client) ContainerLogs(ctx context.Context, containerID string, option
if options.Since != "" {
ts, err := timetypes.GetTimestamp(options.Since, time.Now())
if err != nil {
return nil, errors.Wrap(err, `invalid value for "since"`)
return nil, fmt.Errorf(`invalid value for "since": %w`, err)
}
query.Set("since", ts)
}
@@ -59,7 +63,7 @@ func (cli *Client) ContainerLogs(ctx context.Context, containerID string, option
if options.Until != "" {
ts, err := timetypes.GetTimestamp(options.Until, time.Now())
if err != nil {
return nil, errors.Wrap(err, `invalid value for "until"`)
return nil, fmt.Errorf(`invalid value for "until": %w`, err)
}
query.Set("until", ts)
}
+1 -1
View File
@@ -8,7 +8,7 @@ import (
"github.com/moby/moby/api/types/container"
)
// ContainerResize changes the size of the tty for a container.
// ContainerResize changes the size of the pseudo-TTY for a container.
func (cli *Client) ContainerResize(ctx context.Context, containerID string, options container.ResizeOptions) error {
containerID, err := trimID("container", containerID)
if err != nil {
+1 -1
View File
@@ -9,7 +9,7 @@ import (
"github.com/moby/moby/api/types/versions"
)
// ContainerRestart stops and starts a container again.
// ContainerRestart stops, and starts a container again.
// It makes the daemon wait for the container to be up again for
// a specific amount of time, given the timeout.
func (cli *Client) ContainerRestart(ctx context.Context, containerID string, options container.StopOptions) error {
+2 -2
View File
@@ -6,7 +6,7 @@ import (
"net/url"
)
// StatsResponseReader wraps an io.ReadCloser to read (a stream of) stats
// StatsResponseReader wraps an [io.ReadCloser] to read (a stream of) stats
// for a container, as produced by the GET "/stats" endpoint.
//
// The OSType field is set to the server's platform to allow
@@ -19,7 +19,7 @@ type StatsResponseReader struct {
}
// ContainerStats returns near realtime stats for a given container.
// It's up to the caller to close the io.ReadCloser returned.
// It's up to the caller to close the [io.ReadCloser] returned.
func (cli *Client) ContainerStats(ctx context.Context, containerID string, stream bool) (StatsResponseReader, error) {
containerID, err := trimID("container", containerID)
if err != nil {
+1 -1
View File
@@ -2,7 +2,7 @@ package client
import "context"
// ContainerUnpause resumes the process execution within a container
// ContainerUnpause resumes the process execution within a container.
func (cli *Client) ContainerUnpause(ctx context.Context, containerID string) error {
containerID, err := trimID("container", containerID)
if err != nil {
+8 -6
View File
@@ -15,12 +15,13 @@ import (
const containerWaitErrorMsgLimit = 2 * 1024 /* Max: 2KiB */
// ContainerWait waits until the specified container is in a certain state
// indicated by the given condition, either "not-running" (default),
// "next-exit", or "removed".
// indicated by the given condition, either "not-running" ([container.WaitConditionNotRunning])
// (default), "next-exit" ([container.WaitConditionNextExit]), or "removed".
// ([container.WaitConditionRemoved]).
//
// If this client's API version is before 1.30, condition is ignored and
// ContainerWait will return immediately with the two channels, as the server
// will wait as if the condition were "not-running".
// If this client's API version is before 1.30, "condition" is ignored and
// ContainerWait returns immediately with the two channels, as the server
// waits as if the condition were "not-running".
//
// If this client's API version is at least 1.30, ContainerWait blocks until
// the request has been acknowledged by the server (with a response header),
@@ -28,7 +29,8 @@ const containerWaitErrorMsgLimit = 2 * 1024 /* Max: 2KiB */
// of the container or an error if there was a problem either beginning the
// wait request or in getting the response. This allows the caller to
// synchronize ContainerWait with other calls, such as specifying a
// "next-exit" condition before issuing a ContainerStart request.
// "next-exit" condition ([container.WaitConditionNextExit]) before
// issuing a [Client.ContainerStart] request.
func (cli *Client) ContainerWait(ctx context.Context, containerID string, condition container.WaitCondition) (<-chan container.WaitResponse, <-chan error) {
resultC := make(chan container.WaitResponse)
errC := make(chan error, 1)
+22 -17
View File
@@ -4,16 +4,16 @@ const (
// EnvOverrideHost is the name of the environment variable that can be used
// to override the default host to connect to (DefaultDockerHost).
//
// This env-var is read by FromEnv and WithHostFromEnv and when set to a
// This env-var is read by [FromEnv] and [WithHostFromEnv] and when set to a
// non-empty value, takes precedence over the default host (which is platform
// specific), or any host already set.
EnvOverrideHost = "DOCKER_HOST"
// EnvOverrideAPIVersion is the name of the environment variable that can
// be used to override the API version to use. Value should be
// be used to override the API version to use. Value must be
// formatted as MAJOR.MINOR, for example, "1.19".
//
// This env-var is read by FromEnv and WithVersionFromEnv and when set to a
// This env-var is read by [FromEnv] and [WithVersionFromEnv] and when set to a
// non-empty value, takes precedence over API version negotiation.
//
// This environment variable should be used for debugging purposes only, as
@@ -23,16 +23,15 @@ const (
// EnvOverrideCertPath is the name of the environment variable that can be
// used to specify the directory from which to load the TLS certificates
// (ca.pem, cert.pem, key.pem) from. These certificates are used to configure
// the Client for a TCP connection protected by TLS client authentication.
// the [Client] for a TCP connection protected by TLS client authentication.
//
// TLS certificate verification is enabled by default if the Client is configured
// to use a TLS connection. Refer to EnvTLSVerify below to learn how to
// to use a TLS connection. Refer to [EnvTLSVerify] below to learn how to
// disable verification for testing purposes.
//
// WARNING: Access to the remote API is equivalent to root access to the
// host where the daemon runs. Do not expose the API without protection,
// and only if needed. Make sure you are familiar with the "daemon attack
// surface" (https://docs.docker.com/go/attack-surface/).
// and only if needed. Make sure you are familiar with the ["daemon attack surface"].
//
// For local access to the API, it is recommended to connect with the daemon
// using the default local socket connection (on Linux), or the named pipe
@@ -43,11 +42,14 @@ const (
// configuration if the host is accessible using ssh.
//
// If you cannot use the alternatives above, and you must expose the API over
// a TCP connection, refer to https://docs.docker.com/engine/security/protect-access/
// a TCP connection. Refer to [Protect the Docker daemon socket]
// to learn how to configure the daemon and client to use a TCP connection
// with TLS client authentication. Make sure you know the differences between
// a regular TLS connection and a TLS connection protected by TLS client
// authentication, and verify that the API cannot be accessed by other clients.
//
// ["daemon attack surface"]: https://docs.docker.com/go/attack-surface/
// [Protect the Docker daemon socket]: https://docs.docker.com/engine/security/protect-access/
EnvOverrideCertPath = "DOCKER_CERT_PATH"
// EnvTLSVerify is the name of the environment variable that can be used to
@@ -59,26 +61,26 @@ const (
//
// WARNING: Access to the remote API is equivalent to root access to the
// host where the daemon runs. Do not expose the API without protection,
// and only if needed. Make sure you are familiar with the "daemon attack
// surface" (https://docs.docker.com/go/attack-surface/).
// and only if needed. Make sure you are familiar with the ["daemon attack surface"].
//
// Before setting up your client and daemon to use a TCP connection with TLS
// client authentication, consider using one of the alternatives mentioned
// in EnvOverrideCertPath above.
// in [EnvOverrideCertPath].
//
// Disabling TLS certificate verification (for testing purposes)
//
// TLS certificate verification is enabled by default if the Client is configured
// to use a TLS connection, and it is highly recommended to keep verification
// enabled to prevent machine-in-the-middle attacks. Refer to the documentation
// at https://docs.docker.com/engine/security/protect-access/ and pages linked
// from that page to learn how to configure the daemon and client to use a
// TCP connection with TLS client authentication enabled.
// enabled to prevent machine-in-the-middle attacks. Refer to [Protect the Docker daemon socket]
// in the documentation and pages linked from that page to learn how to
// configure the daemon and client to use a TCP connection with TLS client
// authentication enabled.
//
// Set the "DOCKER_TLS_VERIFY" environment to an empty string ("") to
// disable TLS certificate verification. Disabling verification is insecure,
// so should only be done for testing purposes. From the Go documentation
// (https://pkg.go.dev/crypto/tls#Config):
// so should only be done for testing purposes.
//
// From the[crypto/tls.Config] documentation:
//
// InsecureSkipVerify controls whether a client verifies the server's
// certificate chain and host name. If InsecureSkipVerify is true, crypto/tls
@@ -86,5 +88,8 @@ const (
// certificate. In this mode, TLS is susceptible to machine-in-the-middle
// attacks unless custom verification is used. This should be used only for
// testing or in combination with VerifyConnection or VerifyPeerCertificate.
//
// ["daemon attack surface"]: https://docs.docker.com/go/attack-surface/
// [Protect the Docker daemon socket]: https://docs.docker.com/engine/security/protect-access/
EnvTLSVerify = "DOCKER_TLS_VERIFY"
)
+5 -5
View File
@@ -10,7 +10,6 @@ import (
"time"
"github.com/moby/moby/api/types/versions"
"github.com/pkg/errors"
"go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp"
)
@@ -56,18 +55,18 @@ func setupHijackConn(dialer func(context.Context) (net.Conn, error), req *http.R
conn, err := dialer(ctx)
if err != nil {
return nil, "", errors.Wrap(err, "cannot connect to the Docker daemon. Is 'docker daemon' running on this host?")
return nil, "", fmt.Errorf("cannot connect to the Docker daemon. Is 'docker daemon' running on this host?: %w", err)
}
defer func() {
if retErr != nil {
conn.Close()
_ = conn.Close()
}
}()
// When we set up a TCP connection for hijack, there could be long periods
// of inactivity (a long running command with no output) that in certain
// network setups may cause ECONNTIMEOUT, leaving the client in an unknown
// state. Setting TCP KeepAlive on the socket connection will prohibit
// state. Setting TCP KeepAlive on the socket connection prohibits
// ECONNTIMEOUT unless the socket connection truly is broken
if tcpConn, ok := conn.(*net.TCPConn); ok {
_ = tcpConn.SetKeepAlive(true)
@@ -155,7 +154,8 @@ func (h *HijackedResponse) Close() {
}
// MediaType let client know if HijackedResponse hold a raw or multiplexed stream.
// returns false if HTTP Content-Type is not relevant, and container must be inspected
// returns false if HTTP Content-Type is not relevant, and the container must be
// inspected.
func (h *HijackedResponse) MediaType() (string, bool) {
if h.mediaType == "" {
return "", false
+1 -1
View File
@@ -16,7 +16,7 @@ import (
)
// ImageBuild sends a request to the daemon to build images.
// The Body in the response implements an io.ReadCloser and it's up to the caller to
// The Body in the response implements an [io.ReadCloser] and it's up to the caller to
// close it.
func (cli *Client) ImageBuild(ctx context.Context, buildContext io.Reader, options build.ImageBuildOptions) (build.ImageBuildResponse, error) {
query, err := cli.imageBuildOptionsToQuery(ctx, options)
+4 -3
View File
@@ -28,8 +28,9 @@ func ImageInspectWithRawResponse(raw *bytes.Buffer) ImageInspectOption {
// ImageInspectWithManifests sets manifests API option for the image inspect operation.
// This option is only available for API version 1.48 and up.
// With this option set, the image inspect operation response will have the
// [image.InspectResponse.Manifests] field populated if the server is multi-platform capable.
// With this option set, the image inspect operation response includes
// the [image.InspectResponse.Manifests] field if the server is multi-platform
// capable.
func ImageInspectWithManifests(manifests bool) ImageInspectOption {
return imageInspectOptionFunc(func(clientOpts *imageInspectOpts) error {
clientOpts.apiOptions.Manifests = manifests
@@ -39,7 +40,7 @@ func ImageInspectWithManifests(manifests bool) ImageInspectOption {
// ImageInspectWithPlatform sets platform API option for the image inspect operation.
// This option is only available for API version 1.49 and up.
// With this option set, the image inspect operation will return information for the
// With this option set, the image inspect operation returns information for the
// specified platform variant of the multi-platform image.
func ImageInspectWithPlatform(platform *ocispec.Platform) ImageInspectOption {
return imageInspectOptionFunc(func(clientOpts *imageInspectOpts) error {
+2 -2
View File
@@ -12,8 +12,8 @@ import (
// ImageList returns a list of images in the docker host.
//
// Experimental: Setting the [options.Manifest] will populate
// [image.Summary.Manifests] with information about image manifests.
// Experimental: Set the [image.ListOptions.Manifest] option
// to include [image.Summary.Manifests] with information about image manifests.
// This is experimental and might change in the future without any backward
// compatibility.
func (cli *Client) ImageList(ctx context.Context, options image.ListOptions) ([]image.Summary, error) {
+4 -4
View File
@@ -10,12 +10,12 @@ import (
)
// ImageLoad loads an image in the docker host from the client host.
// It's up to the caller to close the io.ReadCloser in the
// ImageLoadResponse returned by this function.
// It's up to the caller to close the [io.ReadCloser] in the
// [image.LoadResponse] returned by this function.
//
// Platform is an optional parameter that specifies the platform to load from
// the provided multi-platform image. This is only has effect if the input image
// is a multi-platform image.
// the provided multi-platform image. Passing a platform only has an effect
// if the input image is a multi-platform image.
func (cli *Client) ImageLoad(ctx context.Context, input io.Reader, loadOpts ...ImageLoadOption) (image.LoadResponse, error) {
var opts imageLoadOpts
for _, opt := range loadOpts {
+7 -5
View File
@@ -14,12 +14,14 @@ import (
// ImagePull requests the docker host to pull an image from a remote registry.
// It executes the privileged function if the operation is unauthorized
// and it tries one more time.
// It's up to the caller to handle the io.ReadCloser and close it properly.
//
// FIXME(vdemeester): there is currently used in a few way in docker/docker
// - if not in trusted content, ref is used to pass the whole reference, and tag is empty
// - if in trusted content, ref is used to pass the reference name, and tag for the digest
// It's up to the caller to handle the [io.ReadCloser] and close it.
func (cli *Client) ImagePull(ctx context.Context, refStr string, options image.PullOptions) (io.ReadCloser, error) {
// FIXME(vdemeester): there is currently used in a few way in docker/docker
// - if not in trusted content, ref is used to pass the whole reference, and tag is empty
// - if in trusted content, ref is used to pass the reference name, and tag for the digest
//
// ref; https://github.com/docker-archive-public/docker.engine-api/pull/162
ref, err := reference.ParseNormalizedNamed(refStr)
if err != nil {
return nil, err
+1 -1
View File
@@ -18,7 +18,7 @@ import (
// ImagePush requests the docker host to push an image to a remote registry.
// It executes the privileged function if the operation is unauthorized
// and it tries one more time.
// It's up to the caller to handle the io.ReadCloser and close it properly.
// It's up to the caller to handle the [io.ReadCloser] and close it.
func (cli *Client) ImagePush(ctx context.Context, image string, options image.PushOptions) (io.ReadCloser, error) {
ref, err := reference.ParseNormalizedNamed(image)
if err != nil {
+5 -3
View File
@@ -6,10 +6,12 @@ import (
"net/url"
)
// ImageSave retrieves one or more images from the docker host as an io.ReadCloser.
// ImageSave retrieves one or more images from the docker host as an
// [io.ReadCloser].
//
// Platforms is an optional parameter that specifies the platforms to save from the image.
// This is only has effect if the input image is a multi-platform image.
// Platforms is an optional parameter that specifies the platforms to save
// from the image. Passing a platform only has an effect if the input image
// is a multi-platform image.
func (cli *Client) ImageSave(ctx context.Context, imageIDs []string, saveOpts ...ImageSaveOption) (io.ReadCloser, error) {
var opts imageSaveOpts
for _, opt := range saveOpts {
+4 -3
View File
@@ -2,21 +2,22 @@ package client
import (
"context"
"errors"
"fmt"
"net/url"
"github.com/distribution/reference"
"github.com/pkg/errors"
)
// ImageTag tags an image in the docker host
func (cli *Client) ImageTag(ctx context.Context, source, target string) error {
if _, err := reference.ParseAnyReference(source); err != nil {
return errors.Wrapf(err, "Error parsing reference: %q is not a valid repository/tag", source)
return fmt.Errorf("error parsing reference: %q is not a valid repository/tag: %w", source, err)
}
ref, err := reference.ParseNormalizedNamed(target)
if err != nil {
return errors.Wrapf(err, "Error parsing reference: %q is not a valid repository/tag", target)
return fmt.Errorf("error parsing reference: %q is not a valid repository/tag: %w", target, err)
}
if _, isCanonical := ref.(reference.Canonical); isCanonical {
+6 -6
View File
@@ -2,6 +2,7 @@ package client
import (
"context"
"fmt"
"net"
"net/http"
"os"
@@ -11,7 +12,6 @@ import (
"github.com/docker/go-connections/sockets"
"github.com/docker/go-connections/tlsconfig"
"github.com/pkg/errors"
"go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp"
"go.opentelemetry.io/otel/trace"
)
@@ -55,7 +55,7 @@ func WithDialContext(dialContext func(ctx context.Context, network, addr string)
transport.DialContext = dialContext
return nil
}
return errors.Errorf("cannot apply dialer to transport: %T", c.client.Transport)
return fmt.Errorf("cannot apply dialer to transport: %T", c.client.Transport)
}
}
@@ -73,7 +73,7 @@ func WithHost(host string) Opt {
if transport, ok := c.client.Transport.(*http.Transport); ok {
return sockets.ConfigureTransport(transport, c.proto, c.addr)
}
return errors.Errorf("cannot apply host to transport: %T", c.client.Transport)
return fmt.Errorf("cannot apply host to transport: %T", c.client.Transport)
}
}
@@ -140,7 +140,7 @@ func WithTLSClientConfig(cacertPath, certPath, keyPath string) Opt {
return func(c *Client) error {
transport, ok := c.client.Transport.(*http.Transport)
if !ok {
return errors.Errorf("cannot apply tls config to transport: %T", c.client.Transport)
return fmt.Errorf("cannot apply tls config to transport: %T", c.client.Transport)
}
config, err := tlsconfig.Client(tlsconfig.Options{
CAFile: cacertPath,
@@ -149,7 +149,7 @@ func WithTLSClientConfig(cacertPath, certPath, keyPath string) Opt {
ExclusiveRootPools: true,
})
if err != nil {
return errors.Wrap(err, "failed to create tls config")
return fmt.Errorf("failed to create tls config: %w", err)
}
transport.TLSClientConfig = config
return nil
@@ -234,7 +234,7 @@ func WithAPIVersionNegotiation() Opt {
}
// WithTraceProvider sets the trace provider for the client.
// If this is not set then the global trace provider will be used.
// If this is not set then the global trace provider is used.
func WithTraceProvider(provider trace.TracerProvider) Opt {
return WithTraceOptions(otelhttp.WithTracerProvider(provider))
}
+3 -3
View File
@@ -6,11 +6,11 @@ import (
"encoding/json"
"io"
"github.com/moby/moby/api/types"
"github.com/moby/moby/api/types/plugin"
)
// PluginInspectWithRaw inspects an existing plugin
func (cli *Client) PluginInspectWithRaw(ctx context.Context, name string) (*types.Plugin, []byte, error) {
func (cli *Client) PluginInspectWithRaw(ctx context.Context, name string) (*plugin.Plugin, []byte, error) {
name, err := trimID("plugin", name)
if err != nil {
return nil, nil, err
@@ -25,7 +25,7 @@ func (cli *Client) PluginInspectWithRaw(ctx context.Context, name string) (*type
if err != nil {
return nil, nil, err
}
var p types.Plugin
var p plugin.Plugin
rdr := bytes.NewReader(body)
err = json.NewDecoder(rdr).Decode(&p)
return &p, body, err
+10 -9
View File
@@ -3,15 +3,16 @@ package client
import (
"context"
"encoding/json"
"errors"
"fmt"
"io"
"net/http"
"net/url"
cerrdefs "github.com/containerd/errdefs"
"github.com/distribution/reference"
"github.com/moby/moby/api/types"
"github.com/moby/moby/api/types/plugin"
"github.com/moby/moby/api/types/registry"
"github.com/pkg/errors"
)
// PluginInstallOptions holds parameters to install a plugin.
@@ -28,7 +29,7 @@ type PluginInstallOptions struct {
//
// For details, refer to [github.com/moby/moby/api/types/registry.RequestAuthConfig].
PrivilegeFunc func(context.Context) (string, error)
AcceptPermissionsFunc func(context.Context, types.PluginPrivileges) (bool, error)
AcceptPermissionsFunc func(context.Context, plugin.Privileges) (bool, error)
Args []string
}
@@ -36,7 +37,7 @@ type PluginInstallOptions struct {
func (cli *Client) PluginInstall(ctx context.Context, name string, options PluginInstallOptions) (_ io.ReadCloser, retErr error) {
query := url.Values{}
if _, err := reference.ParseNormalizedNamed(options.RemoteRef); err != nil {
return nil, errors.Wrap(err, "invalid remote reference")
return nil, fmt.Errorf("invalid remote reference: %w", err)
}
query.Set("remote", options.RemoteRef)
@@ -92,16 +93,16 @@ func (cli *Client) tryPluginPrivileges(ctx context.Context, query url.Values, re
})
}
func (cli *Client) tryPluginPull(ctx context.Context, query url.Values, privileges types.PluginPrivileges, registryAuth string) (*http.Response, error) {
func (cli *Client) tryPluginPull(ctx context.Context, query url.Values, privileges plugin.Privileges, registryAuth string) (*http.Response, error) {
return cli.post(ctx, "/plugins/pull", query, privileges, http.Header{
registry.AuthHeader: {registryAuth},
})
}
func (cli *Client) checkPluginPermissions(ctx context.Context, query url.Values, options PluginInstallOptions) (types.PluginPrivileges, error) {
func (cli *Client) checkPluginPermissions(ctx context.Context, query url.Values, options PluginInstallOptions) (plugin.Privileges, error) {
resp, err := cli.tryPluginPrivileges(ctx, query, options.RegistryAuth)
if cerrdefs.IsUnauthorized(err) && options.PrivilegeFunc != nil {
// todo: do inspect before to check existing name before checking privileges
// TODO: do inspect before to check existing name before checking privileges
newAuthHeader, privilegeErr := options.PrivilegeFunc(ctx)
if privilegeErr != nil {
ensureReaderClosed(resp)
@@ -115,7 +116,7 @@ func (cli *Client) checkPluginPermissions(ctx context.Context, query url.Values,
return nil, err
}
var privileges types.PluginPrivileges
var privileges plugin.Privileges
if err := json.NewDecoder(resp.Body).Decode(&privileges); err != nil {
ensureReaderClosed(resp)
return nil, err
@@ -128,7 +129,7 @@ func (cli *Client) checkPluginPermissions(ctx context.Context, query url.Values,
return nil, err
}
if !accept {
return nil, errors.Errorf("permission denied while installing plugin %s", options.RemoteRef)
return nil, errors.New("permission denied while installing plugin " + options.RemoteRef)
}
}
return privileges, nil
+3 -3
View File
@@ -5,14 +5,14 @@ import (
"encoding/json"
"net/url"
"github.com/moby/moby/api/types"
"github.com/moby/moby/api/types/filters"
"github.com/moby/moby/api/types/plugin"
"github.com/moby/moby/api/types/versions"
)
// PluginList returns the installed plugins
func (cli *Client) PluginList(ctx context.Context, filter filters.Args) (types.PluginsListResponse, error) {
var plugins types.PluginsListResponse
func (cli *Client) PluginList(ctx context.Context, filter filters.Args) (plugin.ListResponse, error) {
var plugins plugin.ListResponse
query := url.Values{}
if filter.Len() > 0 {
+4 -4
View File
@@ -2,14 +2,14 @@ package client
import (
"context"
"fmt"
"io"
"net/http"
"net/url"
"github.com/distribution/reference"
"github.com/moby/moby/api/types"
"github.com/moby/moby/api/types/plugin"
"github.com/moby/moby/api/types/registry"
"github.com/pkg/errors"
)
// PluginUpgrade upgrades a plugin
@@ -24,7 +24,7 @@ func (cli *Client) PluginUpgrade(ctx context.Context, name string, options Plugi
}
query := url.Values{}
if _, err := reference.ParseNormalizedNamed(options.RemoteRef); err != nil {
return nil, errors.Wrap(err, "invalid remote reference")
return nil, fmt.Errorf("invalid remote reference: %w", err)
}
query.Set("remote", options.RemoteRef)
@@ -40,7 +40,7 @@ func (cli *Client) PluginUpgrade(ctx context.Context, name string, options Plugi
return resp.Body, nil
}
func (cli *Client) tryPluginUpgrade(ctx context.Context, query url.Values, privileges types.PluginPrivileges, name, registryAuth string) (*http.Response, error) {
func (cli *Client) tryPluginUpgrade(ctx context.Context, query url.Values, privileges plugin.Privileges, name, registryAuth string) (*http.Response, error) {
return cli.post(ctx, "/plugins/"+name+"/upgrade", query, privileges, http.Header{
registry.AuthHeader: {registryAuth},
})
+13 -13
View File
@@ -4,6 +4,7 @@ import (
"bytes"
"context"
"encoding/json"
"errors"
"fmt"
"io"
"net"
@@ -13,8 +14,7 @@ import (
"reflect"
"strings"
"github.com/moby/moby/api/types"
"github.com/pkg/errors"
"github.com/moby/moby/api/types/common"
)
// head sends an http request to the docker API using the method HEAD.
@@ -144,7 +144,7 @@ func (cli *Client) doRequest(req *http.Request) (*http.Response, error) {
}
if cli.scheme == "https" && strings.Contains(err.Error(), "bad certificate") {
return nil, errConnectionFailed{errors.Wrap(err, "the server probably has client authentication (--tlsverify) enabled; check your TLS client certification settings")}
return nil, errConnectionFailed{fmt.Errorf("the server probably has client authentication (--tlsverify) enabled; check your TLS client certification settings: %w", err)}
}
// Don't decorate context sentinel errors; users may be comparing to
@@ -162,11 +162,11 @@ func (cli *Client) doRequest(req *http.Request) (*http.Response, error) {
// Unwrap the error to remove request errors ("Get "http://%2Fvar%2Frun%2Fdocker.sock/v1.51/version"),
// which are irrelevant if we weren't able to connect.
err = errors.Unwrap(err)
return nil, errConnectionFailed{errors.Wrapf(err, "failed to connect to the docker API at %v; check if the path is correct and if the daemon is running", cli.host)}
return nil, errConnectionFailed{fmt.Errorf("failed to connect to the docker API at %v; check if the path is correct and if the daemon is running: %w", cli.host, err)}
}
var dnsErr *net.DNSError
if errors.As(err, &dnsErr) {
return nil, errConnectionFailed{errors.Wrapf(dnsErr, "failed to connect to the docker API at %v", cli.host)}
return nil, errConnectionFailed{fmt.Errorf("failed to connect to the docker API at %v: %w", cli.host, dnsErr)}
}
var nErr net.Error
@@ -193,14 +193,14 @@ func (cli *Client) doRequest(req *http.Request) (*http.Response, error) {
if strings.Contains(err.Error(), `open //./pipe/docker_engine`) {
// Checks if client is running with elevated privileges
if f, elevatedErr := os.Open(`\\.\PHYSICALDRIVE0`); elevatedErr != nil {
err = errors.Wrap(err, "in the default daemon configuration on Windows, the docker client must be run with elevated privileges to connect")
err = fmt.Errorf("in the default daemon configuration on Windows, the docker client must be run with elevated privileges to connect: %w", err)
} else {
_ = f.Close()
err = errors.Wrap(err, "this error may indicate that the docker daemon is not running")
err = fmt.Errorf("this error may indicate that the docker daemon is not running: %w", err)
}
}
return nil, errConnectionFailed{errors.Wrap(err, "error during connect")}
return nil, errConnectionFailed{fmt.Errorf("error during connect: %w", err)}
}
func (cli *Client) checkResponseErr(serverResp *http.Response) (retErr error) {
@@ -250,20 +250,20 @@ func (cli *Client) checkResponseErr(serverResp *http.Response) (retErr error) {
var daemonErr error
if serverResp.Header.Get("Content-Type") == "application/json" {
var errorResponse types.ErrorResponse
var errorResponse common.ErrorResponse
if err := json.Unmarshal(body, &errorResponse); err != nil {
return errors.Wrap(err, "Error reading JSON")
return fmt.Errorf("error reading JSON: %w", err)
}
if errorResponse.Message == "" {
// Error-message is empty, which means that we successfully parsed the
// JSON-response (no error produced), but it didn't contain an error
// message. This could either be because the response was empty, or
// the response was valid JSON, but not with the expected schema
// ([types.ErrorResponse]).
// ([common.ErrorResponse]).
//
// We cannot use "strict" JSON handling (json.NewDecoder with DisallowUnknownFields)
// due to the API using an open schema (we must anticipate fields
// being added to [types.ErrorResponse] in the future, and not
// being added to [common.ErrorResponse] in the future, and not
// reject those responses.
//
// For these cases, we construct an error with the status-code
@@ -285,7 +285,7 @@ func (cli *Client) checkResponseErr(serverResp *http.Response) (retErr error) {
// situations where a proxy is involved, returning a HTML response.
daemonErr = errors.New(strings.TrimSpace(string(body)))
}
return errors.Wrap(daemonErr, "Error response from daemon")
return fmt.Errorf("Error response from daemon: %w", daemonErr)
}
func (cli *Client) addHeaders(req *http.Request, headers http.Header) *http.Request {
+3 -3
View File
@@ -3,6 +3,7 @@ package client
import (
"context"
"encoding/json"
"errors"
"fmt"
"net/http"
"strings"
@@ -12,7 +13,6 @@ import (
"github.com/moby/moby/api/types/swarm"
"github.com/moby/moby/api/types/versions"
"github.com/opencontainers/go-digest"
"github.com/pkg/errors"
)
// ServiceCreate creates a new service.
@@ -200,11 +200,11 @@ func validateAPIVersion(c swarm.ServiceSpec, apiVersion string) error {
for _, m := range c.TaskTemplate.ContainerSpec.Mounts {
if m.BindOptions != nil {
if m.BindOptions.NonRecursive && versions.LessThan(apiVersion, "1.40") {
return errors.Errorf("bind-recursive=disabled requires API v1.40 or later")
return errors.New("bind-recursive=disabled requires API v1.40 or later")
}
// ReadOnlyNonRecursive can be safely ignored when API < 1.44
if m.BindOptions.ReadOnlyForceRecursive && versions.LessThan(apiVersion, "1.44") {
return errors.Errorf("bind-recursive=readonly requires API v1.44 or later")
return errors.New("bind-recursive=readonly requires API v1.44 or later")
}
}
}
+3 -3
View File
@@ -2,16 +2,16 @@ package client
import (
"context"
"fmt"
"io"
"net/url"
"time"
"github.com/moby/moby/api/types/container"
timetypes "github.com/moby/moby/api/types/time"
"github.com/pkg/errors"
)
// ServiceLogs returns the logs generated by a service in an io.ReadCloser.
// ServiceLogs returns the logs generated by a service in an [io.ReadCloser].
// It's up to the caller to close the stream.
func (cli *Client) ServiceLogs(ctx context.Context, serviceID string, options container.LogsOptions) (io.ReadCloser, error) {
serviceID, err := trimID("service", serviceID)
@@ -31,7 +31,7 @@ func (cli *Client) ServiceLogs(ctx context.Context, serviceID string, options co
if options.Since != "" {
ts, err := timetypes.GetTimestamp(options.Since, time.Now())
if err != nil {
return nil, errors.Wrap(err, `invalid value for "since"`)
return nil, fmt.Errorf(`invalid value for "since": %w`, err)
}
query.Set("since", ts)
}
+4 -3
View File
@@ -11,9 +11,10 @@ import (
"github.com/moby/moby/api/types/versions"
)
// ServiceUpdate updates a Service. The version number is required to avoid conflicting writes.
// It should be the value as set *before* the update. You can find this value in the Meta field
// of swarm.Service, which can be found using ServiceInspectWithRaw.
// ServiceUpdate updates a Service. The version number is required to avoid
// conflicting writes. It must be the value as set *before* the update.
// You can find this value in the [swarm.Service.Meta] field, which can
// be found using [Client.ServiceInspectWithRaw].
func (cli *Client) ServiceUpdate(ctx context.Context, serviceID string, version swarm.Version, service swarm.ServiceSpec, options swarm.ServiceUpdateOptions) (swarm.ServiceUpdateResponse, error) {
serviceID, err := trimID("service", serviceID)
if err != nil {
+2 -2
View File
@@ -13,8 +13,8 @@ import (
)
// Events returns a stream of events in the daemon. It's up to the caller to close the stream
// by cancelling the context. Once the stream has been completely read an io.EOF error will
// be sent over the error channel. If an error is sent all processing will be stopped. It's up
// by cancelling the context. Once the stream has been completely read an [io.EOF] error is
// sent over the error channel. If an error is sent, all processing is stopped. It's up
// to the caller to reopen the stream in the event of an error by reinvoking this method.
func (cli *Client) Events(ctx context.Context, options events.ListOptions) (<-chan events.Message, <-chan error) {
messages := make(chan events.Message)
+1 -1
View File
@@ -10,7 +10,7 @@ import (
timetypes "github.com/moby/moby/api/types/time"
)
// TaskLogs returns the logs generated by a task in an io.ReadCloser.
// TaskLogs returns the logs generated by a task in an [io.ReadCloser].
// It's up to the caller to close the stream.
func (cli *Client) TaskLogs(ctx context.Context, taskID string, options container.LogsOptions) (io.ReadCloser, error) {
query := url.Values{}
+3 -4
View File
@@ -168,7 +168,7 @@ github.com/moby/docker-image-spec/specs-go/v1
github.com/moby/go-archive
github.com/moby/go-archive/compression
github.com/moby/go-archive/tarheader
# github.com/moby/moby/api v0.0.0 => github.com/moby/moby/api v0.0.0-20250731152656-4faedf2bec36
# github.com/moby/moby/api v1.52.0-alpha.1
## explicit; go 1.23.0
github.com/moby/moby/api/pkg/progress
github.com/moby/moby/api/pkg/stdcopy
@@ -186,6 +186,7 @@ github.com/moby/moby/api/types/image
github.com/moby/moby/api/types/jsonstream
github.com/moby/moby/api/types/mount
github.com/moby/moby/api/types/network
github.com/moby/moby/api/types/plugin
github.com/moby/moby/api/types/registry
github.com/moby/moby/api/types/storage
github.com/moby/moby/api/types/strslice
@@ -194,7 +195,7 @@ github.com/moby/moby/api/types/system
github.com/moby/moby/api/types/time
github.com/moby/moby/api/types/versions
github.com/moby/moby/api/types/volume
# github.com/moby/moby/client v0.0.0 => github.com/moby/moby/client v0.0.0-20250731152656-4faedf2bec36
# github.com/moby/moby/client v0.1.0-alpha.0
## explicit; go 1.23.0
github.com/moby/moby/client
github.com/moby/moby/client/pkg/jsonmessage
@@ -569,5 +570,3 @@ gotest.tools/v3/skip
# tags.cncf.io/container-device-interface v0.8.0
## explicit; go 1.20
tags.cncf.io/container-device-interface/pkg/parser
# github.com/moby/moby/api => github.com/moby/moby/api v0.0.0-20250731152656-4faedf2bec36
# github.com/moby/moby/client => github.com/moby/moby/client v0.0.0-20250731152656-4faedf2bec36