1
0
mirror of https://github.com/docker/cli.git synced 2026-01-06 05:41:44 +03:00

vendor: github.com/moby/moby/api, github.com/moby/moby/client master

full diffs:

- https://github.com/moby/moby/compare/api/v1.52.0-beta.1...e98849831fc4e35bdc09ed31b85f91caa87a0103
- https://github.com/moby/moby/compare/client/v0.1.0-beta.0...e98849831fc4e35bdc09ed31b85f91caa87a0103

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
This commit is contained in:
Sebastiaan van Stijn
2025-09-19 16:30:55 +02:00
parent e241f53ebc
commit c5cbb3e648
59 changed files with 292 additions and 464 deletions

View File

@@ -15,8 +15,8 @@ import (
type fakeClient struct {
client.Client
inspectFunc func(string) (container.InspectResponse, error)
execInspectFunc func(execID string) (container.ExecInspect, error)
execCreateFunc func(containerID string, options container.ExecOptions) (container.ExecCreateResponse, error)
execInspectFunc func(execID string) (client.ExecInspect, error)
execCreateFunc func(containerID string, options client.ExecCreateOptions) (container.ExecCreateResponse, error)
createContainerFunc func(config *container.Config,
hostConfig *container.HostConfig,
networkingConfig *network.NetworkingConfig,
@@ -59,21 +59,21 @@ func (f *fakeClient) ContainerInspect(_ context.Context, containerID string) (co
return container.InspectResponse{}, nil
}
func (f *fakeClient) ContainerExecCreate(_ context.Context, containerID string, config container.ExecOptions) (container.ExecCreateResponse, error) {
func (f *fakeClient) ContainerExecCreate(_ context.Context, containerID string, config client.ExecCreateOptions) (container.ExecCreateResponse, error) {
if f.execCreateFunc != nil {
return f.execCreateFunc(containerID, config)
}
return container.ExecCreateResponse{}, nil
}
func (f *fakeClient) ContainerExecInspect(_ context.Context, execID string) (container.ExecInspect, error) {
func (f *fakeClient) ContainerExecInspect(_ context.Context, execID string) (client.ExecInspect, error) {
if f.execInspectFunc != nil {
return f.execInspectFunc(execID)
}
return container.ExecInspect{}, nil
return client.ExecInspect{}, nil
}
func (*fakeClient) ContainerExecStart(context.Context, string, container.ExecStartOptions) error {
func (*fakeClient) ContainerExecStart(context.Context, string, client.ExecStartOptions) error {
return nil
}

View File

@@ -75,7 +75,7 @@ func runCommit(ctx context.Context, dockerCli command.Cli, options *commitOption
Comment: options.comment,
Author: options.author,
Changes: options.changes.GetSlice(),
Pause: !options.noPause,
NoPause: options.noPause,
})
if err != nil {
return err

View File

@@ -23,7 +23,7 @@ func TestRunCommit(t *testing.T) {
assert.Check(t, is.Equal(options.Author, "Author Name <author@name.com>"))
assert.Check(t, is.DeepEqual(options.Changes, []string{"EXPOSE 80"}))
assert.Check(t, is.Equal(options.Comment, "commit message"))
assert.Check(t, is.Equal(options.Pause, false))
assert.Check(t, is.Equal(options.NoPause, true))
assert.Check(t, is.Equal(ctr, "container-id"))
return container.CommitResponse{ID: "image-id"}, nil

View File

@@ -119,7 +119,7 @@ func RunExec(ctx context.Context, dockerCLI command.Cli, containerIDorName strin
}
if options.Detach {
return apiClient.ContainerExecStart(ctx, execID, container.ExecStartOptions{
return apiClient.ContainerExecStart(ctx, execID, client.ExecStartOptions{
Detach: options.Detach,
Tty: execOptions.Tty,
ConsoleSize: execOptions.ConsoleSize,
@@ -128,14 +128,14 @@ func RunExec(ctx context.Context, dockerCLI command.Cli, containerIDorName strin
return interactiveExec(ctx, dockerCLI, execOptions, execID)
}
func fillConsoleSize(execOptions *container.ExecOptions, dockerCli command.Cli) {
func fillConsoleSize(execOptions *client.ExecCreateOptions, dockerCli command.Cli) {
if execOptions.Tty {
height, width := dockerCli.Out().GetTtySize()
execOptions.ConsoleSize = &[2]uint{height, width}
}
}
func interactiveExec(ctx context.Context, dockerCli command.Cli, execOptions *container.ExecOptions, execID string) error {
func interactiveExec(ctx context.Context, dockerCli command.Cli, execOptions *client.ExecCreateOptions, execID string) error {
// Interactive exec requested.
var (
out, stderr io.Writer
@@ -158,7 +158,7 @@ func interactiveExec(ctx context.Context, dockerCli command.Cli, execOptions *co
fillConsoleSize(execOptions, dockerCli)
apiClient := dockerCli.Client()
resp, err := apiClient.ContainerExecAttach(ctx, execID, container.ExecAttachOptions{
resp, err := apiClient.ContainerExecAttach(ctx, execID, client.ExecAttachOptions{
Tty: execOptions.Tty,
ConsoleSize: execOptions.ConsoleSize,
})
@@ -218,8 +218,8 @@ func getExecExitStatus(ctx context.Context, apiClient client.ContainerAPIClient,
// parseExec parses the specified args for the specified command and generates
// an ExecConfig from it.
func parseExec(execOpts ExecOptions, configFile *configfile.ConfigFile) (*container.ExecOptions, error) {
execOptions := &container.ExecOptions{
func parseExec(execOpts ExecOptions, configFile *configfile.ConfigFile) (*client.ExecCreateOptions, error) {
execOptions := &client.ExecCreateOptions{
User: execOpts.User,
Privileged: execOpts.Privileged,
Tty: execOpts.TTY,

View File

@@ -13,6 +13,7 @@ import (
"github.com/docker/cli/internal/test"
"github.com/docker/cli/opts"
"github.com/moby/moby/api/types/container"
"github.com/moby/moby/client"
"gotest.tools/v3/assert"
is "gotest.tools/v3/assert/cmp"
"gotest.tools/v3/fs"
@@ -38,10 +39,10 @@ TWO=2
testcases := []struct {
options ExecOptions
configFile configfile.ConfigFile
expected container.ExecOptions
expected client.ExecCreateOptions
}{
{
expected: container.ExecOptions{
expected: client.ExecCreateOptions{
Cmd: []string{"command"},
AttachStdout: true,
AttachStderr: true,
@@ -49,7 +50,7 @@ TWO=2
options: withDefaultOpts(ExecOptions{}),
},
{
expected: container.ExecOptions{
expected: client.ExecCreateOptions{
Cmd: []string{"command1", "command2"},
AttachStdout: true,
AttachStderr: true,
@@ -64,7 +65,7 @@ TWO=2
TTY: true,
User: "uid",
}),
expected: container.ExecOptions{
expected: client.ExecCreateOptions{
User: "uid",
AttachStdin: true,
AttachStdout: true,
@@ -75,7 +76,7 @@ TWO=2
},
{
options: withDefaultOpts(ExecOptions{Detach: true}),
expected: container.ExecOptions{
expected: client.ExecCreateOptions{
Cmd: []string{"command"},
},
},
@@ -85,7 +86,7 @@ TWO=2
Interactive: true,
Detach: true,
}),
expected: container.ExecOptions{
expected: client.ExecCreateOptions{
Tty: true,
Cmd: []string{"command"},
},
@@ -93,7 +94,7 @@ TWO=2
{
options: withDefaultOpts(ExecOptions{Detach: true}),
configFile: configfile.ConfigFile{DetachKeys: "de"},
expected: container.ExecOptions{
expected: client.ExecCreateOptions{
Cmd: []string{"command"},
DetachKeys: "de",
},
@@ -104,13 +105,13 @@ TWO=2
DetachKeys: "ab",
}),
configFile: configfile.ConfigFile{DetachKeys: "de"},
expected: container.ExecOptions{
expected: client.ExecCreateOptions{
Cmd: []string{"command"},
DetachKeys: "ab",
},
},
{
expected: container.ExecOptions{
expected: client.ExecCreateOptions{
Cmd: []string{"command"},
AttachStdout: true,
AttachStderr: true,
@@ -123,7 +124,7 @@ TWO=2
}(),
},
{
expected: container.ExecOptions{
expected: client.ExecCreateOptions{
Cmd: []string{"command"},
AttachStdout: true,
AttachStderr: true,
@@ -206,7 +207,7 @@ func TestRunExec(t *testing.T) {
}
}
func execCreateWithID(_ string, _ container.ExecOptions) (container.ExecCreateResponse, error) {
func execCreateWithID(_ string, _ client.ExecCreateOptions) (container.ExecCreateResponse, error) {
return container.ExecCreateResponse{ID: "execid"}, nil
}
@@ -235,9 +236,9 @@ func TestGetExecExitStatus(t *testing.T) {
for _, testcase := range testcases {
apiClient := &fakeClient{
execInspectFunc: func(id string) (container.ExecInspect, error) {
execInspectFunc: func(id string) (client.ExecInspect, error) {
assert.Check(t, is.Equal(execID, id))
return container.ExecInspect{ExitCode: testcase.exitCode}, testcase.inspectError
return client.ExecInspect{ExitCode: testcase.exitCode}, testcase.inspectError
},
}
err := getExecExitStatus(context.Background(), apiClient, execID)

View File

@@ -28,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 v1.52.0-beta.1
github.com/moby/moby/client v0.1.0-beta.0
github.com/moby/moby/api v1.52.0-beta.1.0.20250923190348-e98849831fc4 // master
github.com/moby/moby/client v0.1.0-beta.0.0.20250923190348-e98849831fc4 // master
github.com/moby/patternmatcher v0.6.0
github.com/moby/swarmkit/v2 v2.0.0
github.com/moby/sys/atomicwriter v0.1.0

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 v1.52.0-beta.1 h1:r5U4U72E7xSHh4zX72ndY1mA/FOGiAPiGiz2a8rBW+w=
github.com/moby/moby/api v1.52.0-beta.1/go.mod h1:8sBV0soUREiudtow4vqJGOxa4GyHI5vLQmvgKdHq5Ok=
github.com/moby/moby/client v0.1.0-beta.0 h1:eXzrwi0YkzLvezOBKHafvAWNmH1B9HFh4n13yb2QgFE=
github.com/moby/moby/client v0.1.0-beta.0/go.mod h1:irAv8jRi4yKKBeND96Y+3AM9ers+KaJYk9Vmcm7loxs=
github.com/moby/moby/api v1.52.0-beta.1.0.20250923190348-e98849831fc4 h1:nwVKjkAlQJp32lsr/TZ4dGUIkj+Ga6ftle+IVov9HYs=
github.com/moby/moby/api v1.52.0-beta.1.0.20250923190348-e98849831fc4/go.mod h1:8sBV0soUREiudtow4vqJGOxa4GyHI5vLQmvgKdHq5Ok=
github.com/moby/moby/client v0.1.0-beta.0.0.20250923190348-e98849831fc4 h1:fk0TcJJf4rrgD3I35xxPkb9R4S+KCToMNomydm/n2Pg=
github.com/moby/moby/client v0.1.0-beta.0.0.20250923190348-e98849831fc4/go.mod h1:o5CkJu0RlmnLWRZRaEd7fL6wo0Ggr8Hw/UvgqdIUBuI=
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=

View File

@@ -8,56 +8,6 @@ import "github.com/moby/moby/api/types/common"
// TODO(thaJeztah): make this a distinct type.
type ExecCreateResponse = common.IDResponse
// ExecOptions is a small subset of the Config struct that holds the configuration
// for the exec feature of docker.
type ExecOptions struct {
User string // User that will run the command
Privileged bool // Is the container in privileged mode
Tty bool // Attach standard streams to a tty.
ConsoleSize *[2]uint `json:",omitempty"` // Initial console size [height, width]
AttachStdin bool // Attach the standard input, makes possible user interaction
AttachStderr bool // Attach the standard error
AttachStdout bool // Attach the standard output
DetachKeys string // Escape keys for detach
Env []string // Environment variables
WorkingDir string // Working directory
Cmd []string // Execution commands and args
// Deprecated: the Detach field is not used, and will be removed in a future release.
Detach bool
}
// ExecStartOptions is a temp struct used by execStart
// Config fields is part of ExecConfig in runconfig package
type ExecStartOptions struct {
// ExecStart will first check if it's detached
Detach bool
// Check if there's a tty
Tty bool
// Terminal size [height, width], unused if Tty == false
ConsoleSize *[2]uint `json:",omitempty"`
}
// ExecAttachOptions is a temp struct used by execAttach.
//
// TODO(thaJeztah): make this a separate type; ContainerExecAttach does not use the Detach option, and cannot run detached.
type ExecAttachOptions = ExecStartOptions
// ExecInspect holds information returned by exec inspect.
//
// It is used by the client to unmarshal a [ExecInspectResponse],
// but currently only provides a subset of the information included
// in that type.
//
// TODO(thaJeztah): merge [ExecInspect] and [ExecInspectResponse],
type ExecInspect struct {
ExecID string `json:"ID"`
ContainerID string `json:"ContainerID"`
Running bool `json:"Running"`
ExitCode int `json:"ExitCode"`
Pid int `json:"Pid"`
}
// ExecInspectResponse is the API response for the "GET /exec/{id}/json"
// endpoint and holds information about and exec.
type ExecInspectResponse struct {

View File

@@ -0,0 +1,17 @@
package container
// ExecCreateRequest is a small subset of the Config struct that holds the configuration
// for the exec feature of docker.
type ExecCreateRequest struct {
User string // User that will run the command
Privileged bool // Is the container in privileged mode
Tty bool // Attach standard streams to a tty.
ConsoleSize *[2]uint `json:",omitempty"` // Initial console size [height, width]
AttachStdin bool // Attach the standard input, makes possible user interaction
AttachStderr bool // Attach the standard error
AttachStdout bool // Attach the standard output
DetachKeys string // Escape keys for detach
Env []string // Environment variables
WorkingDir string // Working directory
Cmd []string // Execution commands and args
}

View File

@@ -0,0 +1,12 @@
package container
// ExecStartRequest is a temp struct used by execStart
// Config fields is part of ExecConfig in runconfig package
type ExecStartRequest struct {
// ExecStart will first check if it's detached
Detach bool
// Check if there's a tty
Tty bool
// Terminal size [height, width], unused if Tty == false
ConsoleSize *[2]uint `json:",omitempty"`
}

View File

@@ -390,9 +390,6 @@ type Resources struct {
DeviceCgroupRules []string // List of rule to be added to the device cgroup
DeviceRequests []DeviceRequest // List of device requests for device drivers
// KernelMemory specifies the kernel memory limit (in bytes) for the container.
// Deprecated: kernel 5.4 deprecated kmem.limit_in_bytes.
KernelMemory int64 `json:",omitempty"`
KernelMemoryTCP int64 `json:",omitempty"` // Hard limit for kernel TCP buffer memory (in bytes)
MemoryReservation int64 // Memory soft limit (in bytes)
MemorySwap int64 // Total memory usage (memory + swap); set `-1` to enable unlimited swap

View File

@@ -6,75 +6,10 @@ import (
// NetworkSettings exposes the network settings in the api
type NetworkSettings struct {
NetworkSettingsBase
DefaultNetworkSettings
Networks map[string]*network.EndpointSettings
}
// NetworkSettingsBase holds networking state for a container when inspecting it.
//
// Deprecated: Most fields in NetworkSettingsBase are deprecated. Fields which aren't deprecated will move to
// NetworkSettings in v29.0, and this struct will be removed.
type NetworkSettingsBase struct {
Bridge string // Deprecated: This field is only set when the daemon is started with the --bridge flag specified.
SandboxID string // SandboxID uniquely represents a container's network stack
SandboxKey string // SandboxKey identifies the sandbox
Ports PortMap // Ports is a collection of PortBinding indexed by Port
// HairpinMode specifies if hairpin NAT should be enabled on the virtual interface
//
// Deprecated: This field is never set and will be removed in a future release.
HairpinMode bool
// LinkLocalIPv6Address is an IPv6 unicast address using the link-local prefix
//
// Deprecated: This field is never set and will be removed in a future release.
LinkLocalIPv6Address string
// LinkLocalIPv6PrefixLen is the prefix length of an IPv6 unicast address
//
// Deprecated: This field is never set and will be removed in a future release.
LinkLocalIPv6PrefixLen int
SecondaryIPAddresses []network.Address // Deprecated: This field is never set and will be removed in a future release.
SecondaryIPv6Addresses []network.Address // Deprecated: This field is never set and will be removed in a future release.
}
// DefaultNetworkSettings holds the networking state for the default bridge, if the container is connected to that
// network.
//
// Deprecated: this struct is deprecated since Docker v1.11 and will be removed in v29. You should look for the default
// network in NetworkSettings.Networks instead.
type DefaultNetworkSettings struct {
// EndpointID uniquely represents a service endpoint in a Sandbox
//
// Deprecated: This field will be removed in v29. You should look for the default network in NetworkSettings.Networks instead.
EndpointID string
// Gateway holds the gateway address for the network
//
// Deprecated: This field will be removed in v29. You should look for the default network in NetworkSettings.Networks instead.
Gateway string
// GlobalIPv6Address holds network's global IPv6 address
//
// Deprecated: This field will be removed in v29. You should look for the default network in NetworkSettings.Networks instead.
GlobalIPv6Address string
// GlobalIPv6PrefixLen represents mask length of network's global IPv6 address
//
// Deprecated: This field will be removed in v29. You should look for the default network in NetworkSettings.Networks instead.
GlobalIPv6PrefixLen int
// IPAddress holds the IPv4 address for the network
//
// Deprecated: This field will be removed in v29. You should look for the default network in NetworkSettings.Networks instead.
IPAddress string
// IPPrefixLen represents mask length of network's IPv4 address
//
// Deprecated: This field will be removed in v29. You should look for the default network in NetworkSettings.Networks instead.
IPPrefixLen int
// IPv6Gateway holds gateway address specific for IPv6
//
// Deprecated: This field will be removed in v29. You should look for the default network in NetworkSettings.Networks instead.
IPv6Gateway string
// MacAddress holds the MAC address for the network
//
// Deprecated: This field will be removed in v29. You should look for the default network in NetworkSettings.Networks instead.
MacAddress string
Networks map[string]*network.EndpointSettings
}
// NetworkSettingsSummary provides a summary of container's networks

View File

@@ -110,15 +110,6 @@ type Actor struct {
// Message represents the information an event contains
type Message struct {
// Deprecated: use Action instead.
// Information from JSONMessage.
// With data only in container events.
Status string `json:"status,omitempty"`
// Deprecated: use Actor.ID instead.
ID string `json:"id,omitempty"`
// Deprecated: use Actor.Attributes["image"] instead.
From string `json:"from,omitempty"`
Type Type
Action Action
Actor Actor

View File

@@ -20,4 +20,8 @@ type Inspect struct {
// swarm scope networks, and omitted for local scope networks.
//
Services map[string]ServiceInfo `json:"Services,omitempty"`
// provides runtime information about the network such as the number of allocated IPs.
//
Status *Status `json:"Status,omitempty"`
}

View File

@@ -22,6 +22,8 @@ type IPAMConfig struct {
AuxAddress map[string]string `json:"AuxiliaryAddresses,omitempty"`
}
type SubnetStatuses = map[netip.Prefix]SubnetStatus
type ipFamily string
const (

View File

@@ -0,0 +1,16 @@
// Code generated by go-swagger; DO NOT EDIT.
package network
// This file was generated by the swagger tool.
// Editing this file might prove futile when you re-run the swagger generate command
// IPAMStatus IPAM status
//
// swagger:model IPAMStatus
type IPAMStatus struct {
// subnets
// Example: {"172.16.0.0/16":{"DynamicIPsAvailable":65533,"IPsInUse":3},"2001:db8:abcd:0012::0/96":{"DynamicIPsAvailable":4294967291,"IPsInUse":5}}
Subnets SubnetStatuses `json:"Subnets,omitempty"`
}

View File

@@ -28,16 +28,6 @@ type CreateRequest struct {
ConfigFrom *ConfigReference // ConfigFrom specifies the source which will provide the configuration for this network. The specified network must be a config-only network; see [CreateOptions.ConfigOnly].
Options map[string]string // Options specifies the network-specific options to use for when creating the network.
Labels map[string]string // Labels holds metadata specific to the network being created.
// Deprecated: CheckDuplicate is deprecated since API v1.44, but it defaults to true when sent by the client
// package to older daemons.
CheckDuplicate *bool `json:",omitempty"`
}
// Address represents an IP address
type Address struct {
Addr string
PrefixLen int
}
// ServiceInfo represents service parameters with the list of service's tasks

View File

@@ -0,0 +1,15 @@
// Code generated by go-swagger; DO NOT EDIT.
package network
// This file was generated by the swagger tool.
// Editing this file might prove futile when you re-run the swagger generate command
// Status provides runtime information about the network such as the number of allocated IPs.
//
// swagger:model Status
type Status struct {
// IPAM
IPAM IPAMStatus `json:"IPAM"`
}

View File

@@ -0,0 +1,20 @@
// Code generated by go-swagger; DO NOT EDIT.
package network
// This file was generated by the swagger tool.
// Editing this file might prove futile when you re-run the swagger generate command
// SubnetStatus subnet status
//
// swagger:model SubnetStatus
type SubnetStatus struct {
// Number of IP addresses in the subnet that are in use or reserved and are therefore unavailable for allocation, saturating at 2<sup>64</sup> - 1.
//
IPsInUse uint64 `json:"IPsInUse"`
// Number of IP addresses within the network's IPRange for the subnet that are available for allocation, saturating at 2<sup>64</sup> - 1.
//
DynamicIPsAvailable uint64 `json:"DynamicIPsAvailable"`
}

View File

@@ -21,7 +21,6 @@ type Info struct {
Plugins PluginsInfo
MemoryLimit bool
SwapLimit bool
KernelMemory bool `json:",omitempty"` // Deprecated: kernel 5.4 deprecated kmem.limit_in_bytes
KernelMemoryTCP bool `json:",omitempty"` // KernelMemoryTCP is not supported on cgroups v2.
CPUCfsPeriod bool `json:"CpuCfsPeriod"`
CPUCfsQuota bool `json:"CpuCfsQuota"`

View File

@@ -23,10 +23,6 @@ type BuildCachePruneOptions struct {
// BuildCachePrune requests the daemon to delete unused cache data.
func (cli *Client) BuildCachePrune(ctx context.Context, opts BuildCachePruneOptions) (*build.CachePruneReport, error) {
if err := cli.NewVersionError(ctx, "1.31", "build prune"); err != nil {
return nil, err
}
query := url.Values{}
if opts.All {
query.Set("all", "1")

View File

@@ -275,7 +275,7 @@ func (cli *Client) checkVersion(ctx context.Context) error {
if err != nil {
return err
}
cli.negotiateAPIVersionPing(ping)
cli.negotiateAPIVersionPing(ping.APIVersion)
}
return nil
}
@@ -324,7 +324,7 @@ func (cli *Client) NegotiateAPIVersion(ctx context.Context) {
// FIXME(thaJeztah): Ping returns an error when failing to connect to the API; we should not swallow the error here, and instead returning it.
return
}
cli.negotiateAPIVersionPing(ping)
cli.negotiateAPIVersionPing(ping.APIVersion)
}
}
@@ -347,16 +347,18 @@ func (cli *Client) NegotiateAPIVersionPing(pingResponse types.Ping) {
cli.negotiateLock.Lock()
defer cli.negotiateLock.Unlock()
cli.negotiateAPIVersionPing(pingResponse)
cli.negotiateAPIVersionPing(pingResponse.APIVersion)
}
}
// negotiateAPIVersionPing queries the API and updates the version to match the
// API version from the ping response.
func (cli *Client) negotiateAPIVersionPing(pingResponse types.Ping) {
func (cli *Client) negotiateAPIVersionPing(pingVersion string) {
pingVersion = strings.TrimPrefix(pingVersion, "v")
// default to the latest version before versioning headers existed
if pingResponse.APIVersion == "" {
pingResponse.APIVersion = fallbackAPIVersion
if pingVersion == "" {
pingVersion = fallbackAPIVersion
}
// if the client is not initialized with a version, start with the latest supported version
@@ -365,8 +367,8 @@ func (cli *Client) negotiateAPIVersionPing(pingResponse types.Ping) {
}
// if server version is lower than the client version, downgrade
if versions.LessThan(pingResponse.APIVersion, cli.version) {
cli.version = pingResponse.APIVersion
if versions.LessThan(pingVersion, cli.version) {
cli.version = pingVersion
}
// Store the results, so that automatic API version negotiation (if enabled)
@@ -381,12 +383,6 @@ func (cli *Client) DaemonHost() string {
return cli.host
}
// HTTPClient returns a copy of the HTTP client bound to the server
func (cli *Client) HTTPClient() *http.Client {
c := *cli.client
return &c
}
// ParseHostURL parses a url string, validates the string is a host url, and
// returns the parsed URL
func ParseHostURL(host string) (*url.URL, error) {

View File

@@ -4,7 +4,6 @@ import (
"context"
"io"
"net"
"net/http"
"github.com/moby/moby/api/types"
"github.com/moby/moby/api/types/build"
@@ -38,7 +37,6 @@ type stableAPIClient interface {
VolumeAPIClient
ClientVersion() string
DaemonHost() string
HTTPClient() *http.Client
ServerVersion(ctx context.Context) (types.Version, error)
NegotiateAPIVersion(ctx context.Context)
NegotiateAPIVersionPing(types.Ping)
@@ -69,11 +67,7 @@ type ContainerAPIClient interface {
ContainerCommit(ctx context.Context, container string, options ContainerCommitOptions) (container.CommitResponse, error)
ContainerCreate(ctx context.Context, config *container.Config, hostConfig *container.HostConfig, networkingConfig *network.NetworkingConfig, platform *ocispec.Platform, containerName string) (container.CreateResponse, error)
ContainerDiff(ctx context.Context, container string) ([]container.FilesystemChange, error)
ContainerExecAttach(ctx context.Context, execID string, options container.ExecAttachOptions) (HijackedResponse, error)
ContainerExecCreate(ctx context.Context, container string, options container.ExecOptions) (container.ExecCreateResponse, error)
ContainerExecInspect(ctx context.Context, execID string) (container.ExecInspect, error)
ContainerExecResize(ctx context.Context, execID string, options ContainerResizeOptions) error
ContainerExecStart(ctx context.Context, execID string, options container.ExecStartOptions) error
ExecAPIClient
ContainerExport(ctx context.Context, container string) (io.ReadCloser, error)
ContainerInspect(ctx context.Context, container string) (container.InspectResponse, error)
ContainerInspectWithRaw(ctx context.Context, container string, getSize bool) (container.InspectResponse, []byte, error)
@@ -99,6 +93,14 @@ type ContainerAPIClient interface {
ContainersPrune(ctx context.Context, pruneFilters filters.Args) (container.PruneReport, error)
}
type ExecAPIClient interface {
ContainerExecCreate(ctx context.Context, container string, options ExecCreateOptions) (container.ExecCreateResponse, error)
ContainerExecStart(ctx context.Context, execID string, options ExecStartOptions) error
ContainerExecAttach(ctx context.Context, execID string, options ExecAttachOptions) (HijackedResponse, error)
ContainerExecInspect(ctx context.Context, execID string) (ExecInspect, error)
ContainerExecResize(ctx context.Context, execID string, options ContainerResizeOptions) error
}
// DistributionAPIClient defines API client methods for the registry
type DistributionAPIClient interface {
DistributionInspect(ctx context.Context, image, encodedRegistryAuth string) (registry.DistributionInspect, error)

View File

@@ -9,16 +9,13 @@ import (
// ConfigCreate creates a new config.
func (cli *Client) ConfigCreate(ctx context.Context, config swarm.ConfigSpec) (swarm.ConfigCreateResponse, error) {
var response swarm.ConfigCreateResponse
if err := cli.NewVersionError(ctx, "1.30", "config create"); err != nil {
return response, err
}
resp, err := cli.post(ctx, "/configs/create", nil, config, nil)
defer ensureReaderClosed(resp)
if err != nil {
return response, err
return swarm.ConfigCreateResponse{}, err
}
var response swarm.ConfigCreateResponse
err = json.NewDecoder(resp.Body).Decode(&response)
return response, err
}

View File

@@ -15,9 +15,6 @@ func (cli *Client) ConfigInspectWithRaw(ctx context.Context, id string) (swarm.C
if err != nil {
return swarm.Config{}, nil, err
}
if err := cli.NewVersionError(ctx, "1.30", "config inspect"); err != nil {
return swarm.Config{}, nil, err
}
resp, err := cli.get(ctx, "/configs/"+id, nil, nil)
defer ensureReaderClosed(resp)
if err != nil {

View File

@@ -11,9 +11,6 @@ import (
// ConfigList returns the list of configs.
func (cli *Client) ConfigList(ctx context.Context, options ConfigListOptions) ([]swarm.Config, error) {
if err := cli.NewVersionError(ctx, "1.30", "config list"); err != nil {
return nil, err
}
query := url.Values{}
if options.Filters.Len() > 0 {

View File

@@ -8,9 +8,6 @@ func (cli *Client) ConfigRemove(ctx context.Context, id string) error {
if err != nil {
return err
}
if err := cli.NewVersionError(ctx, "1.30", "config remove"); err != nil {
return err
}
resp, err := cli.delete(ctx, "/configs/"+id, nil, nil)
defer ensureReaderClosed(resp)
return err

View File

@@ -13,9 +13,6 @@ func (cli *Client) ConfigUpdate(ctx context.Context, id string, version swarm.Ve
if err != nil {
return err
}
if err := cli.NewVersionError(ctx, "1.30", "config update"); err != nil {
return err
}
query := url.Values{}
query.Set("version", version.String())
resp, err := cli.post(ctx, "/configs/"+id+"/update", query, config, nil)

View File

@@ -16,7 +16,7 @@ type ContainerCommitOptions struct {
Comment string
Author string
Changes []string
Pause bool
NoPause bool // NoPause disables pausing the container during commit.
Config *container.Config
}
@@ -54,7 +54,7 @@ func (cli *Client) ContainerCommit(ctx context.Context, containerID string, opti
for _, change := range options.Changes {
query.Add("changes", change)
}
if !options.Pause {
if options.NoPause {
query.Set("pause", "0")
}

View File

@@ -9,6 +9,7 @@ import (
"sort"
"strings"
cerrdefs "github.com/containerd/errdefs"
"github.com/moby/moby/api/types/container"
"github.com/moby/moby/api/types/network"
"github.com/moby/moby/api/types/versions"
@@ -18,6 +19,10 @@ import (
// ContainerCreate creates a new container based on the given configuration.
// It can be associated with a name, but it's not mandatory.
func (cli *Client) ContainerCreate(ctx context.Context, config *container.Config, hostConfig *container.HostConfig, networkingConfig *network.NetworkingConfig, platform *ocispec.Platform, containerName string) (container.CreateResponse, error) {
if config == nil {
return container.CreateResponse{}, cerrdefs.ErrInvalidArgument.WithMessage("config is nil")
}
var response container.CreateResponse
// Make sure we negotiated (if the client is configured to do so),
@@ -29,13 +34,13 @@ func (cli *Client) ContainerCreate(ctx context.Context, config *container.Config
return response, err
}
if err := cli.NewVersionError(ctx, "1.25", "stop timeout"); config != nil && config.StopTimeout != nil && err != nil {
if err := cli.NewVersionError(ctx, "1.25", "stop timeout"); config.StopTimeout != nil && err != nil {
return response, err
}
if err := cli.NewVersionError(ctx, "1.41", "specify container image platform"); platform != nil && err != nil {
return response, err
}
if err := cli.NewVersionError(ctx, "1.44", "specify health-check start interval"); config != nil && config.Healthcheck != nil && config.Healthcheck.StartInterval != 0 && err != nil {
if err := cli.NewVersionError(ctx, "1.44", "specify health-check start interval"); config.Healthcheck != nil && config.Healthcheck.StartInterval != 0 && err != nil {
return response, err
}
if err := cli.NewVersionError(ctx, "1.44", "specify mac-address per network"); hasEndpointSpecificMacAddress(networkingConfig) && err != nil {
@@ -47,10 +52,6 @@ func (cli *Client) ContainerCreate(ctx context.Context, config *container.Config
// When using API 1.24 and under, the client is responsible for removing the container
hostConfig.AutoRemove = false
}
if versions.GreaterThanOrEqualTo(cli.ClientVersion(), "1.42") || versions.LessThan(cli.ClientVersion(), "1.40") {
// KernelMemory was added in API 1.40, and deprecated in API 1.42
hostConfig.KernelMemory = 0
}
if platform != nil && platform.OS == "linux" && versions.LessThan(cli.ClientVersion(), "1.42") {
// When using API under 1.42, the Linux daemon doesn't respect the ConsoleSize
hostConfig.ConsoleSize = [2]uint{0, 0}

View File

@@ -9,8 +9,24 @@ import (
"github.com/moby/moby/api/types/versions"
)
// ExecCreateOptions is a small subset of the Config struct that holds the configuration
// for the exec feature of docker.
type ExecCreateOptions struct {
User string // User that will run the command
Privileged bool // Is the container in privileged mode
Tty bool // Attach standard streams to a tty.
ConsoleSize *[2]uint `json:",omitempty"` // Initial console size [height, width]
AttachStdin bool // Attach the standard input, makes possible user interaction
AttachStderr bool // Attach the standard error
AttachStdout bool // Attach the standard output
DetachKeys string // Escape keys for detach
Env []string // Environment variables
WorkingDir string // Working directory
Cmd []string // Execution commands and args
}
// ContainerExecCreate creates a new exec configuration to run an exec process.
func (cli *Client) ContainerExecCreate(ctx context.Context, containerID string, options container.ExecOptions) (container.ExecCreateResponse, error) {
func (cli *Client) ContainerExecCreate(ctx context.Context, containerID string, options ExecCreateOptions) (container.ExecCreateResponse, error) {
containerID, err := trimID("container", containerID)
if err != nil {
return container.ExecCreateResponse{}, err
@@ -32,7 +48,21 @@ func (cli *Client) ContainerExecCreate(ctx context.Context, containerID string,
options.ConsoleSize = nil
}
resp, err := cli.post(ctx, "/containers/"+containerID+"/exec", nil, options, nil)
req := container.ExecCreateRequest{
User: options.User,
Privileged: options.Privileged,
Tty: options.Tty,
ConsoleSize: options.ConsoleSize,
AttachStdin: options.AttachStdin,
AttachStderr: options.AttachStderr,
AttachStdout: options.AttachStdout,
DetachKeys: options.DetachKeys,
Env: options.Env,
WorkingDir: options.WorkingDir,
Cmd: options.Cmd,
}
resp, err := cli.post(ctx, "/containers/"+containerID+"/exec", nil, req, nil)
defer ensureReaderClosed(resp)
if err != nil {
return container.ExecCreateResponse{}, err
@@ -43,8 +73,19 @@ func (cli *Client) ContainerExecCreate(ctx context.Context, containerID string,
return response, err
}
// ExecStartOptions is a temp struct used by execStart
// Config fields is part of ExecConfig in runconfig package
type ExecStartOptions struct {
// ExecStart will first check if it's detached
Detach bool
// Check if there's a tty
Tty bool
// Terminal size [height, width], unused if Tty == false
ConsoleSize *[2]uint `json:",omitempty"`
}
// ContainerExecStart starts an exec process already created in the docker host.
func (cli *Client) ContainerExecStart(ctx context.Context, execID string, config container.ExecStartOptions) error {
func (cli *Client) ContainerExecStart(ctx context.Context, execID string, config ExecStartOptions) error {
// Make sure we negotiated (if the client is configured to do so),
// as code below contains API-version specific handling of options.
//
@@ -57,11 +98,22 @@ func (cli *Client) ContainerExecStart(ctx context.Context, execID string, config
if versions.LessThan(cli.ClientVersion(), "1.42") {
config.ConsoleSize = nil
}
resp, err := cli.post(ctx, "/exec/"+execID+"/start", nil, config, nil)
req := container.ExecStartRequest{
Detach: config.Detach,
Tty: config.Tty,
ConsoleSize: config.ConsoleSize,
}
resp, err := cli.post(ctx, "/exec/"+execID+"/start", nil, req, nil)
defer ensureReaderClosed(resp)
return err
}
// ExecAttachOptions is a temp struct used by execAttach.
//
// TODO(thaJeztah): make this a separate type; ContainerExecAttach does not use the Detach option, and cannot run detached.
type ExecAttachOptions = ExecStartOptions
// ContainerExecAttach attaches a connection to an exec process in the server.
//
// It returns a [HijackedResponse] with the hijacked connection
@@ -80,24 +132,57 @@ func (cli *Client) ContainerExecStart(ctx context.Context, execID string, config
// [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) {
func (cli *Client) ContainerExecAttach(ctx context.Context, execID string, config ExecAttachOptions) (HijackedResponse, error) {
if versions.LessThan(cli.ClientVersion(), "1.42") {
config.ConsoleSize = nil
}
return cli.postHijacked(ctx, "/exec/"+execID+"/start", nil, config, http.Header{
req := container.ExecStartRequest{
Detach: config.Detach,
Tty: config.Tty,
ConsoleSize: config.ConsoleSize,
}
return cli.postHijacked(ctx, "/exec/"+execID+"/start", nil, req, http.Header{
"Content-Type": {"application/json"},
})
}
// ExecInspect holds information returned by exec inspect.
//
// It provides a subset of the information included in [container.ExecInspectResponse].
//
// TODO(thaJeztah): include all fields of [container.ExecInspectResponse] ?
type ExecInspect struct {
ExecID string `json:"ID"`
ContainerID string `json:"ContainerID"`
Running bool `json:"Running"`
ExitCode int `json:"ExitCode"`
Pid int `json:"Pid"`
}
// ContainerExecInspect returns information about a specific exec process on the docker host.
func (cli *Client) ContainerExecInspect(ctx context.Context, execID string) (container.ExecInspect, error) {
func (cli *Client) ContainerExecInspect(ctx context.Context, execID string) (ExecInspect, error) {
resp, err := cli.get(ctx, "/exec/"+execID+"/json", nil, nil)
defer ensureReaderClosed(resp)
if err != nil {
return container.ExecInspect{}, err
return ExecInspect{}, err
}
var response container.ExecInspect
var response container.ExecInspectResponse
err = json.NewDecoder(resp.Body).Decode(&response)
return response, err
if err != nil {
return ExecInspect{}, err
}
var ec int
if response.ExitCode != nil {
ec = *response.ExitCode
}
return ExecInspect{
ExecID: response.ID,
ContainerID: response.ContainerID,
Running: response.Running,
ExitCode: ec,
Pid: response.Pid,
}, nil
}

View File

@@ -8,7 +8,6 @@ import (
"github.com/moby/moby/api/types/container"
"github.com/moby/moby/api/types/filters"
"github.com/moby/moby/api/types/versions"
)
// ContainerListOptions holds parameters to list containers with.
@@ -47,27 +46,10 @@ func (cli *Client) ContainerList(ctx context.Context, options ContainerListOptio
}
if options.Filters.Len() > 0 {
// Make sure we negotiated (if the client is configured to do so),
// as code below contains API-version specific handling of options.
//
// Normally, version-negotiation (if enabled) would not happen until
// the API request is made.
if err := cli.checkVersion(ctx); err != nil {
return nil, err
}
filterJSON, err := filters.ToJSON(options.Filters)
if err != nil {
return nil, err
}
if cli.version != "" && versions.LessThan(cli.version, "1.22") {
legacyFormat, err := encodeLegacyFilters(filterJSON)
if err != nil {
return nil, err
}
filterJSON = legacyFormat
}
query.Set("filters", filterJSON)
}

View File

@@ -11,10 +11,6 @@ import (
// ContainersPrune requests the daemon to delete unused data
func (cli *Client) ContainersPrune(ctx context.Context, pruneFilters filters.Args) (container.PruneReport, error) {
if err := cli.NewVersionError(ctx, "1.25", "container prune"); err != nil {
return container.PruneReport{}, err
}
query, err := getFiltersQuery(pruneFilters)
if err != nil {
return container.PruneReport{}, err

View File

@@ -15,10 +15,6 @@ func (cli *Client) DistributionInspect(ctx context.Context, imageRef, encodedReg
return registry.DistributionInspect{}, objectNotFoundError{object: "distribution", id: imageRef}
}
if err := cli.NewVersionError(ctx, "1.30", "distribution inspect"); err != nil {
return registry.DistributionInspect{}, err
}
var headers http.Header
if encodedRegistryAuth != "" {
headers = http.Header{

View File

@@ -38,8 +38,7 @@ func (cli *Client) ImageBuild(ctx context.Context, buildContext io.Reader, optio
}
return ImageBuildResponse{
Body: resp.Body,
OSType: resp.Header.Get("Ostype"),
Body: resp.Body,
}, nil
}

View File

@@ -72,6 +72,5 @@ type ImageBuildOutput struct {
// returned by a server after building
// an image.
type ImageBuildResponse struct {
Body io.ReadCloser
OSType string
Body io.ReadCloser
}

View File

@@ -48,20 +48,12 @@ func ImageInspectWithPlatform(platform *ocispec.Platform) ImageInspectOption {
})
}
// ImageInspectWithAPIOpts sets the API options for the image inspect operation.
func ImageInspectWithAPIOpts(opts ImageInspectOptions) ImageInspectOption {
return imageInspectOptionFunc(func(clientOpts *imageInspectOpts) error {
clientOpts.apiOptions = opts
return nil
})
}
type imageInspectOpts struct {
raw *bytes.Buffer
apiOptions ImageInspectOptions
apiOptions imageInspectOptions
}
type ImageInspectOptions struct {
type imageInspectOptions struct {
// Manifests returns the image manifests.
Manifests bool

View File

@@ -30,26 +30,11 @@ func (cli *Client) ImageList(ctx context.Context, options ImageListOptions) ([]i
query := url.Values{}
optionFilters := options.Filters
referenceFilters := optionFilters.Get("reference")
if versions.LessThan(cli.version, "1.25") && len(referenceFilters) > 0 {
query.Set("filter", referenceFilters[0])
for _, filterValue := range referenceFilters {
optionFilters.Del("reference", filterValue)
}
}
if optionFilters.Len() > 0 {
filterJSON, err := filters.ToJSON(optionFilters)
if options.Filters.Len() > 0 {
filterJSON, err := filters.ToJSON(options.Filters)
if err != nil {
return images, err
}
if cli.version != "" && versions.LessThan(cli.version, "1.22") {
legacyFormat, err := encodeLegacyFilters(filterJSON)
if err != nil {
return nil, err
}
filterJSON = legacyFormat
}
query.Set("filters", filterJSON)
}
if options.All {

View File

@@ -14,11 +14,6 @@ type ImageListOptions struct {
// SharedSize indicates whether the shared size of images should be computed.
SharedSize bool
// ContainerCount indicates whether container count should be computed.
//
// Deprecated: This field has been unused and is no longer required and will be removed in a future version.
ContainerCount bool
// Manifests indicates whether the image manifests should be returned.
Manifests bool
}

View File

@@ -11,10 +11,6 @@ import (
// ImagesPrune requests the daemon to delete unused data
func (cli *Client) ImagesPrune(ctx context.Context, pruneFilters filters.Args) (image.PruneReport, error) {
if err := cli.NewVersionError(ctx, "1.25", "image prune"); err != nil {
return image.PruneReport{}, err
}
query, err := getFiltersQuery(pruneFilters)
if err != nil {
return image.PruneReport{}, err

View File

@@ -34,12 +34,29 @@ func (cli *Client) NetworkCreate(ctx context.Context, name string, options Netwo
Options: options.Options,
Labels: options.Labels,
}
var req any
if versions.LessThan(cli.version, "1.44") {
enabled := true
networkCreateRequest.CheckDuplicate = &enabled //nolint:staticcheck // ignore SA1019: CheckDuplicate is deprecated since API v1.44.
// CheckDuplicate is removed in API v1.44, and no longer used by
// daemons supporting that API version (v25.0.0-beta.1 and up)
// regardless of the API version used, but it must be set to true
// when sent to older daemons.
//
// TODO(thaJeztah) remove this once daemon versions v24.0 and lower are no
// longer expected to be used (when Mirantis Container Runtime v23
// is EOL); https://github.com/moby/moby/blob/v2.0.0-beta.0/project/BRANCHES-AND-TAGS.md
req = struct {
network.CreateRequest
CheckDuplicate bool
}{
CreateRequest: networkCreateRequest,
CheckDuplicate: true,
}
} else {
req = networkCreateRequest
}
resp, err := cli.post(ctx, "/networks/create", nil, networkCreateRequest, nil)
resp, err := cli.post(ctx, "/networks/create", nil, req, nil)
defer ensureReaderClosed(resp)
if err != nil {
return network.CreateResponse{}, err

View File

@@ -7,7 +7,6 @@ import (
"github.com/moby/moby/api/types/filters"
"github.com/moby/moby/api/types/network"
"github.com/moby/moby/api/types/versions"
)
// NetworkList returns the list of networks configured in the docker host.
@@ -18,14 +17,6 @@ func (cli *Client) NetworkList(ctx context.Context, options NetworkListOptions)
if err != nil {
return nil, err
}
if cli.version != "" && versions.LessThan(cli.version, "1.22") {
legacyFormat, err := encodeLegacyFilters(filterJSON)
if err != nil {
return nil, err
}
filterJSON = legacyFormat
}
query.Set("filters", filterJSON)
}
var networkResources []network.Summary

View File

@@ -11,10 +11,6 @@ import (
// NetworksPrune requests the daemon to delete unused networks
func (cli *Client) NetworksPrune(ctx context.Context, pruneFilters filters.Args) (network.PruneReport, error) {
if err := cli.NewVersionError(ctx, "1.25", "network prune"); err != nil {
return network.PruneReport{}, err
}
query, err := getFiltersQuery(pruneFilters)
if err != nil {
return network.PruneReport{}, err

View File

@@ -7,7 +7,6 @@ import (
"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
@@ -20,13 +19,6 @@ func (cli *Client) PluginList(ctx context.Context, filter filters.Args) (plugin.
if err != nil {
return plugins, err
}
if cli.version != "" && versions.LessThan(cli.version, "1.22") {
legacyFormat, err := encodeLegacyFilters(filterJSON)
if err != nil {
return plugins, err
}
filterJSON = legacyFormat
}
query.Set("filters", filterJSON)
}
resp, err := cli.get(ctx, "/plugins", query, nil)

View File

@@ -19,9 +19,6 @@ func (cli *Client) PluginUpgrade(ctx context.Context, name string, options Plugi
return nil, err
}
if err := cli.NewVersionError(ctx, "1.26", "plugin upgrade"); err != nil {
return nil, err
}
query := url.Values{}
if _, err := reference.ParseNormalizedNamed(options.RemoteRef); err != nil {
return nil, fmt.Errorf("invalid remote reference: %w", err)

View File

@@ -9,9 +9,6 @@ import (
// SecretCreate creates a new secret.
func (cli *Client) SecretCreate(ctx context.Context, secret swarm.SecretSpec) (swarm.SecretCreateResponse, error) {
if err := cli.NewVersionError(ctx, "1.25", "secret create"); err != nil {
return swarm.SecretCreateResponse{}, err
}
resp, err := cli.post(ctx, "/secrets/create", nil, secret, nil)
defer ensureReaderClosed(resp)
if err != nil {

View File

@@ -15,9 +15,6 @@ func (cli *Client) SecretInspectWithRaw(ctx context.Context, id string) (swarm.S
if err != nil {
return swarm.Secret{}, nil, err
}
if err := cli.NewVersionError(ctx, "1.25", "secret inspect"); err != nil {
return swarm.Secret{}, nil, err
}
resp, err := cli.get(ctx, "/secrets/"+id, nil, nil)
defer ensureReaderClosed(resp)
if err != nil {

View File

@@ -11,9 +11,6 @@ import (
// SecretList returns the list of secrets.
func (cli *Client) SecretList(ctx context.Context, options SecretListOptions) ([]swarm.Secret, error) {
if err := cli.NewVersionError(ctx, "1.25", "secret list"); err != nil {
return nil, err
}
query := url.Values{}
if options.Filters.Len() > 0 {

View File

@@ -8,9 +8,6 @@ func (cli *Client) SecretRemove(ctx context.Context, id string) error {
if err != nil {
return err
}
if err := cli.NewVersionError(ctx, "1.25", "secret remove"); err != nil {
return err
}
resp, err := cli.delete(ctx, "/secrets/"+id, nil, nil)
defer ensureReaderClosed(resp)
return err

View File

@@ -13,9 +13,6 @@ func (cli *Client) SecretUpdate(ctx context.Context, id string, version swarm.Ve
if err != nil {
return err
}
if err := cli.NewVersionError(ctx, "1.25", "secret update"); err != nil {
return err
}
query := url.Values{}
query.Set("version", version.String())
resp, err := cli.post(ctx, "/secrets/"+id+"/update", query, secret, nil)

View File

@@ -33,14 +33,9 @@ func (cli *Client) ServiceCreate(ctx context.Context, service swarm.ServiceSpec,
service.TaskTemplate.ContainerSpec = &swarm.ContainerSpec{}
}
if err := validateServiceSpec(service); err != nil {
if err := validateServiceSpec(service, cli.version); err != nil {
return response, err
}
if versions.LessThan(cli.version, "1.30") {
if err := validateAPIVersion(service, cli.version); err != nil {
return response, err
}
}
// ensure that the image is tagged
var resolveWarning string
@@ -62,12 +57,6 @@ func (cli *Client) ServiceCreate(ctx context.Context, service swarm.ServiceSpec,
}
headers := http.Header{}
if versions.LessThan(cli.version, "1.30") {
// the custom "version" header was used by engine API before 20.10
// (API 1.30) to switch between client- and server-side lookup of
// image digests.
headers["version"] = []string{cli.version}
}
if options.EncodedRegistryAuth != "" {
headers[registry.AuthHeader] = []string{options.EncodedRegistryAuth}
}
@@ -183,7 +172,7 @@ func digestWarning(image string) string {
return fmt.Sprintf("image %s could not be accessed on a registry to record\nits digest. Each node will access %s independently,\npossibly leading to different nodes running different\nversions of the image.\n", image, image)
}
func validateServiceSpec(s swarm.ServiceSpec) error {
func validateServiceSpec(s swarm.ServiceSpec, apiVersion string) error {
if s.TaskTemplate.ContainerSpec != nil && s.TaskTemplate.PluginSpec != nil {
return errors.New("must not specify both a container spec and a plugin spec in the task template")
}
@@ -193,18 +182,16 @@ func validateServiceSpec(s swarm.ServiceSpec) error {
if s.TaskTemplate.ContainerSpec != nil && (s.TaskTemplate.Runtime != "" && s.TaskTemplate.Runtime != swarm.RuntimeContainer) {
return errors.New("mismatched runtime with container spec")
}
return nil
}
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.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.New("bind-recursive=readonly requires API v1.44 or later")
if s.TaskTemplate.ContainerSpec != nil && apiVersion != "" && versions.LessThan(apiVersion, "1.44") {
for _, m := range s.TaskTemplate.ContainerSpec.Mounts {
if m.BindOptions != nil {
if m.BindOptions.NonRecursive && versions.LessThan(apiVersion, "1.40") {
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.New("bind-recursive=readonly requires API v1.44 or later")
}
}
}
}

View File

@@ -8,7 +8,6 @@ import (
"github.com/moby/moby/api/types/registry"
"github.com/moby/moby/api/types/swarm"
"github.com/moby/moby/api/types/versions"
)
// ServiceUpdate updates a Service. The version number is required to avoid
@@ -29,6 +28,9 @@ func (cli *Client) ServiceUpdate(ctx context.Context, serviceID string, version
if err := cli.checkVersion(ctx); err != nil {
return swarm.ServiceUpdateResponse{}, err
}
if err := validateServiceSpec(service, cli.version); err != nil {
return swarm.ServiceUpdateResponse{}, err
}
query := url.Values{}
if options.RegistryAuthFrom != "" {
@@ -41,10 +43,6 @@ func (cli *Client) ServiceUpdate(ctx context.Context, serviceID string, version
query.Set("version", version.String())
if err := validateServiceSpec(service); err != nil {
return swarm.ServiceUpdateResponse{}, err
}
// ensure that the image is tagged
var resolveWarning string
switch {
@@ -65,12 +63,6 @@ func (cli *Client) ServiceUpdate(ctx context.Context, serviceID string, version
}
headers := http.Header{}
if versions.LessThan(cli.version, "1.30") {
// the custom "version" header was used by engine API before 20.10
// (API 1.30) to switch between client- and server-side lookup of
// image digests.
headers["version"] = []string{cli.version}
}
if options.EncodedRegistryAuth != "" {
headers.Set(registry.AuthHeader, options.EncodedRegistryAuth)
}

View File

@@ -8,7 +8,6 @@ import (
"github.com/moby/moby/api/types/events"
"github.com/moby/moby/api/types/filters"
"github.com/moby/moby/api/types/versions"
"github.com/moby/moby/client/internal/timestamp"
)
@@ -31,17 +30,7 @@ func (cli *Client) Events(ctx context.Context, options EventsListOptions) (<-cha
go func() {
defer close(errs)
// Make sure we negotiated (if the client is configured to do so),
// as code below contains API-version specific handling of options.
//
// Normally, version-negotiation (if enabled) would not happen until
// the API request is made.
if err := cli.checkVersion(ctx); err != nil {
close(started)
errs <- err
return
}
query, err := buildEventsQueryParams(cli.version, options)
query, err := buildEventsQueryParams(options)
if err != nil {
close(started)
errs <- err
@@ -85,7 +74,7 @@ func (cli *Client) Events(ctx context.Context, options EventsListOptions) (<-cha
return messages, errs
}
func buildEventsQueryParams(cliVersion string, options EventsListOptions) (url.Values, error) {
func buildEventsQueryParams(options EventsListOptions) (url.Values, error) {
query := url.Values{}
ref := time.Now()
@@ -110,13 +99,6 @@ func buildEventsQueryParams(cliVersion string, options EventsListOptions) (url.V
if err != nil {
return nil, err
}
if cliVersion != "" && versions.LessThan(cliVersion, "1.22") {
legacyFormat, err := encodeLegacyFilters(filterJSON)
if err != nil {
return nil, err
}
filterJSON = legacyFormat
}
query.Set("filters", filterJSON)
}

View File

@@ -81,41 +81,3 @@ func encodePlatform(platform *ocispec.Platform) (string, error) {
}
return string(p), nil
}
// encodeLegacyFilters encodes Args in the legacy format as used in API v1.21 and older.
// where values are a list of strings, instead of a set.
//
// Don't use in any new code; use [filters.ToJSON]] instead.
func encodeLegacyFilters(currentFormat string) (string, error) {
// The Args.fields field is not exported, but used to marshal JSON,
// so we'll marshal to the new format, then unmarshal to get the
// fields, and marshal again.
//
// This is far from optimal, but this code is only used for deprecated
// API versions, so should not be hit commonly.
var argsFields map[string]map[string]bool
err := json.Unmarshal([]byte(currentFormat), &argsFields)
if err != nil {
return "", err
}
buf, err := json.Marshal(convertArgsToSlice(argsFields))
if err != nil {
return "", err
}
return string(buf), nil
}
func convertArgsToSlice(f map[string]map[string]bool) map[string][]string {
m := map[string][]string{}
for k, v := range f {
values := []string{}
for kk := range v {
if v[kk] {
values = append(values, kk)
}
}
m[k] = values
}
return m
}

View File

@@ -6,7 +6,6 @@ import (
"net/url"
"github.com/moby/moby/api/types/filters"
"github.com/moby/moby/api/types/versions"
"github.com/moby/moby/api/types/volume"
)
@@ -19,13 +18,6 @@ func (cli *Client) VolumeList(ctx context.Context, options VolumeListOptions) (v
if err != nil {
return volume.ListResponse{}, err
}
if cli.version != "" && versions.LessThan(cli.version, "1.22") {
legacyFormat, err := encodeLegacyFilters(filterJSON)
if err != nil {
return volume.ListResponse{}, err
}
filterJSON = legacyFormat
}
query.Set("filters", filterJSON)
}
resp, err := cli.get(ctx, "/volumes", query, nil)

View File

@@ -11,10 +11,6 @@ import (
// VolumesPrune requests the daemon to delete unused data
func (cli *Client) VolumesPrune(ctx context.Context, pruneFilters filters.Args) (volume.PruneReport, error) {
if err := cli.NewVersionError(ctx, "1.25", "volume prune"); err != nil {
return volume.PruneReport{}, err
}
query, err := getFiltersQuery(pruneFilters)
if err != nil {
return volume.PruneReport{}, err

View File

@@ -3,8 +3,6 @@ package client
import (
"context"
"net/url"
"github.com/moby/moby/api/types/versions"
)
// VolumeRemove removes a volume from the docker host.
@@ -16,17 +14,7 @@ func (cli *Client) VolumeRemove(ctx context.Context, volumeID string, force bool
query := url.Values{}
if force {
// Make sure we negotiated (if the client is configured to do so),
// as code below contains API-version specific handling of options.
//
// Normally, version-negotiation (if enabled) would not happen until
// the API request is made.
if err := cli.checkVersion(ctx); err != nil {
return err
}
if versions.GreaterThanOrEqualTo(cli.version, "1.25") {
query.Set("force", "1")
}
query.Set("force", "1")
}
resp, err := cli.delete(ctx, "/volumes/"+volumeID, query, nil)
defer ensureReaderClosed(resp)

View File

@@ -15,9 +15,6 @@ func (cli *Client) VolumeUpdate(ctx context.Context, volumeID string, version sw
if err != nil {
return err
}
if err := cli.NewVersionError(ctx, "1.42", "volume update"); err != nil {
return err
}
query := url.Values{}
query.Set("version", version.String())

4
vendor/modules.txt vendored
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 v1.52.0-beta.1
# github.com/moby/moby/api v1.52.0-beta.1.0.20250923190348-e98849831fc4
## explicit; go 1.23.0
github.com/moby/moby/api/pkg/authconfig
github.com/moby/moby/api/pkg/progress
@@ -194,7 +194,7 @@ github.com/moby/moby/api/types/swarm
github.com/moby/moby/api/types/system
github.com/moby/moby/api/types/versions
github.com/moby/moby/api/types/volume
# github.com/moby/moby/client v0.1.0-beta.0
# github.com/moby/moby/client v0.1.0-beta.0.0.20250923190348-e98849831fc4
## explicit; go 1.23.0
github.com/moby/moby/client
github.com/moby/moby/client/internal/timestamp