vendor: github.com/docker/docker f1dd6bf84e28930e1ccd903361f9284fb22d3b8a

full diff: 7c69b6dc08...f1dd6bf84e

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
This commit is contained in:
Sebastiaan van Stijn 2022-05-13 14:44:41 +02:00
parent ec37bfb245
commit 9bf28fc003
No known key found for this signature in database
GPG Key ID: 76698F39D527CE8C
20 changed files with 894 additions and 22 deletions

View File

@ -76,7 +76,7 @@ require (
)
replace (
github.com/docker/docker => github.com/docker/docker v20.10.3-0.20220512073244-7c69b6dc08c7+incompatible // master (v22.06-dev)
github.com/docker/docker => github.com/docker/docker v20.10.3-0.20220513094153-f1dd6bf84e28+incompatible // master (v22.06-dev)
github.com/gogo/googleapis => github.com/gogo/googleapis v1.3.2
// Resolve dependency hell with github.com/cloudflare/cfssl (transitive via

View File

@ -105,8 +105,8 @@ github.com/denisenkom/go-mssqldb v0.0.0-20191128021309-1d7a30a10f73/go.mod h1:xb
github.com/docker/distribution v2.7.1+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w=
github.com/docker/distribution v2.8.1+incompatible h1:Q50tZOPR6T/hjNsyc9g8/syEs6bk8XXApsHjKukMl68=
github.com/docker/distribution v2.8.1+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w=
github.com/docker/docker v20.10.3-0.20220512073244-7c69b6dc08c7+incompatible h1:QNoUa4JDYdN4PQOdB89GO9urFixZfrKTH2qcxCthbYk=
github.com/docker/docker v20.10.3-0.20220512073244-7c69b6dc08c7+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
github.com/docker/docker v20.10.3-0.20220513094153-f1dd6bf84e28+incompatible h1:N6klPo5I0m29g5jQgwNNmdL8KTyHXOYdtB0lep7H5Y0=
github.com/docker/docker v20.10.3-0.20220513094153-f1dd6bf84e28+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
github.com/docker/docker-credential-helpers v0.6.4 h1:axCks+yV+2MR3/kZhAmy07yC56WZ2Pwu/fKWtKuZB0o=
github.com/docker/docker-credential-helpers v0.6.4/go.mod h1:ofX3UI0Gz1TteYBjtgs07O36Pyasyp66D2uKT7H8W1c=
github.com/docker/go v1.5.1-1.0.20160303222718-d30aec9fd63c h1:lzqkGL9b3znc+ZUgi7FlLnqjQhcXxkNM/quxIjBVMD0=

View File

@ -1996,6 +1996,8 @@ definitions:
x-nullable: false
enum: ["local", "global"]
example: "local"
ClusterVolume:
$ref: "#/definitions/ClusterVolume"
Options:
type: "object"
description: |
@ -2069,6 +2071,8 @@ definitions:
example:
com.example.some-label: "some-value"
com.example.some-other-label: "some-other-value"
ClusterVolumeSpec:
$ref: "#/definitions/ClusterVolumeSpec"
VolumeListResponse:
type: "object"
@ -5740,6 +5744,242 @@ definitions:
items:
$ref: "#/definitions/OCIPlatform"
ClusterVolume:
type: "object"
description: |
Options and information specific to, and only present on, Swarm CSI
cluster volumes.
properties:
ID:
type: "string"
description: |
The Swarm ID of this volume. Because cluster volumes are Swarm
objects, they have an ID, unlike non-cluster volumes. This ID can
be used to refer to the Volume instead of the name.
Version:
$ref: "#/definitions/ObjectVersion"
CreatedAt:
type: "string"
format: "dateTime"
UpdatedAt:
type: "string"
format: "dateTime"
Spec:
$ref: "#/definitions/ClusterVolumeSpec"
Info:
type: "object"
description: |
Information about the global status of the volume.
properties:
CapacityBytes:
type: "integer"
format: "int64"
description: |
The capacity of the volume in bytes. A value of 0 indicates that
the capacity is unknown.
VolumeContext:
type: "object"
description: |
A map of strings to strings returned from the storage plugin when
the volume is created.
additionalProperties:
type: "string"
VolumeID:
type: "string"
description: |
The ID of the volume as returned by the CSI storage plugin. This
is distinct from the volume's ID as provided by Docker. This ID
is never used by the user when communicating with Docker to refer
to this volume. If the ID is blank, then the Volume has not been
successfully created in the plugin yet.
AccessibleTopology:
type: "array"
description: |
The topology this volume is actually accessible from.
items:
$ref: "#/definitions/Topology"
PublishStatus:
type: "array"
description: |
The status of the volume as it pertains to its publishing and use on
specific nodes
items:
type: "object"
properties:
NodeID:
type: "string"
description: |
The ID of the Swarm node the volume is published on.
State:
type: "string"
description: |
The published state of the volume.
* `pending-publish` The volume should be published to this node, but the call to the controller plugin to do so has not yet been successfully completed.
* `published` The volume is published successfully to the node.
* `pending-node-unpublish` The volume should be unpublished from the node, and the manager is awaiting confirmation from the worker that it has done so.
* `pending-controller-unpublish` The volume is successfully unpublished from the node, but has not yet been successfully unpublished on the controller.
enum:
- "pending-publish"
- "published"
- "pending-node-unpublish"
- "pending-controller-unpublish"
PublishContext:
type: "object"
description: |
A map of strings to strings returned by the CSI controller
plugin when a volume is published.
additionalProperties:
type: "string"
ClusterVolumeSpec:
type: "object"
description: |
Cluster-specific options used to create the volume.
properties:
Group:
type: "string"
description: |
Group defines the volume group of this volume. Volumes belonging to
the same group can be referred to by group name when creating
Services. Referring to a volume by group instructs Swarm to treat
volumes in that group interchangeably for the purpose of scheduling.
Volumes with an empty string for a group technically all belong to
the same, emptystring group.
AccessMode:
type: "object"
description: |
Defines how the volume is used by tasks.
properties:
Scope:
type: "string"
description: |
The set of nodes this volume can be used on at one time.
- `single` The volume may only be scheduled to one node at a time.
- `multi` the volume may be scheduled to any supported number of nodes at a time.
default: "single"
enum: ["single", "multi"]
x-nullable: false
Sharing:
type: "string"
description: |
The number and way that different tasks can use this volume
at one time.
- `none` The volume may only be used by one task at a time.
- `readonly` The volume may be used by any number of tasks, but they all must mount the volume as readonly
- `onewriter` The volume may be used by any number of tasks, but only one may mount it as read/write.
- `all` The volume may have any number of readers and writers.
default: "none"
enum: ["none", "readonly", "onewriter", "all"]
x-nullable: false
MountVolume:
type: "object"
description: |
Options for using this volume as a Mount-type volume.
Either MountVolume or BlockVolume, but not both, must be
present.
properties:
FsType:
type: "string"
description: |
Specifies the filesystem type for the mount volume.
Optional.
MountFlags:
type: "array"
description: |
Flags to pass when mounting the volume. Optional.
items:
type: "string"
BlockVolume:
type: "object"
description: |
Options for using this volume as a Block-type volume.
Intentionally empty.
Secrets:
type: "array"
description: |
Swarm Secrets that are passed to the CSI storage plugin when
operating on this volume.
items:
type: "object"
description: |
One cluster volume secret entry. Defines a key-value pair that
is passed to the plugin.
properties:
Key:
type: "string"
description: |
Key is the name of the key of the key-value pair passed to
the plugin.
Secret:
type: "string"
description: |
Secret is the swarm Secret object from which to read data.
This can be a Secret name or ID. The Secret data is
retrieved by swarm and used as the value of the key-value
pair passed to the plugin.
AccessibilityRequirements:
type: "object"
description: |
Requirements for the accessible topology of the volume. These
fields are optional. For an in-depth description of what these
fields mean, see the CSI specification.
properties:
Requisite:
type: "array"
description: |
A list of required topologies, at least one of which the
volume must be accessible from.
items:
$ref: "#/definitions/Topology"
Preferred:
type: "array"
description: |
A list of topologies that the volume should attempt to be
provisioned in.
items:
$ref: "#/definitions/Topology"
CapacityRange:
type: "object"
description: |
The desired capacity that the volume should be created with. If
empty, the plugin will decide the capacity.
properties:
RequiredBytes:
type: "integer"
format: "int64"
description: |
The volume must be at least this big. The value of 0
indicates an unspecified minimum
LimitBytes:
type: "integer"
format: "int64"
description: |
The volume must not be bigger than this. The value of 0
indicates an unspecified maximum.
Availability:
type: "string"
description: |
The availability of the volume for use in tasks.
- `active` The volume is fully available for scheduling on the cluster
- `pause` No new workloads should use the volume, but existing workloads are not stopped.
- `drain` All workloads using this volume should be stopped and rescheduled, and no new ones should be started.
default: "active"
x-nullable: false
enum:
- "active"
- "pause"
- "drain"
Topology:
description: |
A map of topological domains to topological segments. For in depth
details, see documentation for the Topology object in the CSI
specification.
type: "object"
additionalProperties:
type: "string"
paths:
/containers/json:
get:
@ -6478,6 +6718,9 @@ paths:
Note: This endpoint works only for containers with the `json-file` or
`journald` logging driver.
produces:
- "application/vnd.docker.raw-stream"
- "application/vnd.docker.multiplexed-stream"
operationId: "ContainerLogs"
responses:
200:
@ -7189,7 +7432,8 @@ paths:
### Stream format
When the TTY setting is disabled in [`POST /containers/create`](#operation/ContainerCreate),
the stream over the hijacked connected is multiplexed to separate out
the HTTP Content-Type header is set to application/vnd.docker.multiplexed-stream
and the stream over the hijacked connected is multiplexed to separate out
`stdout` and `stderr`. The stream consists of a series of frames, each
containing a header and a payload.
@ -7233,6 +7477,7 @@ paths:
operationId: "ContainerAttach"
produces:
- "application/vnd.docker.raw-stream"
- "application/vnd.docker.multiplexed-stream"
responses:
101:
description: "no error, hints proxy about hijacking"
@ -9015,6 +9260,7 @@ paths:
- "application/json"
produces:
- "application/vnd.docker.raw-stream"
- "application/vnd.docker.multiplexed-stream"
responses:
200:
description: "No error"
@ -9241,6 +9487,64 @@ paths:
type: "string"
tags: ["Volume"]
put:
summary: |
"Update a volume. Valid only for Swarm cluster volumes"
operationId: "VolumeUpdate"
consumes: ["application/json"]
produces: ["application/json"]
responses:
200:
description: "no error"
400:
description: "bad parameter"
schema:
$ref: "#/definitions/ErrorResponse"
404:
description: "no such volume"
schema:
$ref: "#/definitions/ErrorResponse"
500:
description: "server error"
schema:
$ref: "#/definitions/ErrorResponse"
503:
description: "node is not part of a swarm"
schema:
$ref: "#/definitions/ErrorResponse"
parameters:
- name: "name"
in: "path"
description: "The name or ID of the volume"
type: "string"
required: true
- name: "body"
in: "body"
schema:
# though the schema for is an object that contains only a
# ClusterVolumeSpec, wrapping the ClusterVolumeSpec in this object
# means that if, later on, we support things like changing the
# labels, we can do so without duplicating that information to the
# ClusterVolumeSpec.
type: "object"
description: "Volume configuration"
properties:
Spec:
$ref: "#/definitions/ClusterVolumeSpec"
description: |
The spec of the volume to update. Currently, only Availability may
change. All other fields must remain unchanged.
- name: "version"
in: "query"
description: |
The version number of the volume being updated. This is required to
avoid conflicting writes. Found in the volume's `ClusterVolume`
field.
type: "integer"
format: "int64"
required: true
tags: ["Volume"]
delete:
summary: "Remove a volume"
description: "Instruct the driver to remove the volume."
@ -9272,6 +9576,7 @@ paths:
type: "boolean"
default: false
tags: ["Volume"]
/volumes/prune:
post:
summary: "Delete unused volumes"
@ -10913,6 +11218,9 @@ paths:
**Note**: This endpoint works only for services with the `local`,
`json-file` or `journald` logging drivers.
produces:
- "application/vnd.docker.raw-stream"
- "application/vnd.docker.multiplexed-stream"
operationId: "ServiceLogs"
responses:
200:
@ -11168,6 +11476,9 @@ paths:
**Note**: This endpoint works only for services with the `local`,
`json-file` or `journald` logging drivers.
operationId: "TaskLogs"
produces:
- "application/vnd.docker.raw-stream"
- "application/vnd.docker.multiplexed-stream"
responses:
200:
description: "logs returned as a stream in response body"

View File

@ -112,8 +112,14 @@ type NetworkListOptions struct {
Filters filters.Args
}
// NewHijackedResponse intializes a HijackedResponse type
func NewHijackedResponse(conn net.Conn, mediaType string) HijackedResponse {
return HijackedResponse{Conn: conn, Reader: bufio.NewReader(conn), mediaType: mediaType}
}
// HijackedResponse holds connection information for a hijacked request.
type HijackedResponse struct {
mediaType string
Conn net.Conn
Reader *bufio.Reader
}
@ -123,6 +129,15 @@ func (h *HijackedResponse) Close() {
h.Conn.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
func (h *HijackedResponse) MediaType() (string, bool) {
if h.mediaType == "" {
return "", false
}
return h.mediaType, true
}
// CloseWriter is an interface that implements structs
// that close input streams to prevent from writing.
type CloseWriter interface {

View File

@ -17,6 +17,8 @@ const (
TypeTmpfs Type = "tmpfs"
// TypeNamedPipe is the type for mounting Windows named pipes
TypeNamedPipe Type = "npipe"
// TypeCluster is the type for Swarm Cluster Volumes.
TypeCluster = "csi"
)
// Mount represents a mount (volume).
@ -33,6 +35,7 @@ type Mount struct {
BindOptions *BindOptions `json:",omitempty"`
VolumeOptions *VolumeOptions `json:",omitempty"`
TmpfsOptions *TmpfsOptions `json:",omitempty"`
ClusterOptions *ClusterOptions `json:",omitempty"`
}
// Propagation represents the propagation of a mount.
@ -129,3 +132,8 @@ type TmpfsOptions struct {
// Some of these may be straightforward to add, but others, such as
// uid/gid have implications in a clustered system.
}
// ClusterOptions specifies options for a Cluster volume.
type ClusterOptions struct {
// intentionally empty
}

View File

@ -53,6 +53,7 @@ type NodeDescription struct {
Resources Resources `json:",omitempty"`
Engine EngineDescription `json:",omitempty"`
TLSInfo TLSInfo `json:",omitempty"`
CSIInfo []NodeCSIInfo `json:",omitempty"`
}
// Platform represents the platform (Arch/OS).
@ -68,6 +69,21 @@ type EngineDescription struct {
Plugins []PluginDescription `json:",omitempty"`
}
// NodeCSIInfo represents information about a CSI plugin available on the node
type NodeCSIInfo struct {
// PluginName is the name of the CSI plugin.
PluginName string `json:",omitempty"`
// NodeID is the ID of the node as reported by the CSI plugin. This is
// different from the swarm node ID.
NodeID string `json:",omitempty"`
// MaxVolumesPerNode is the maximum number of volumes that may be published
// to this node
MaxVolumesPerNode int64 `json:",omitempty"`
// AccessibleTopology indicates the location of this node in the CSI
// plugin's topology
AccessibleTopology *Topology `json:",omitempty"`
}
// PluginDescription represents the description of an engine plugin.
type PluginDescription struct {
Type string `json:",omitempty"`
@ -113,3 +129,11 @@ const (
// NodeStateDisconnected DISCONNECTED
NodeStateDisconnected NodeState = "disconnected"
)
// Topology defines the CSI topology of this node. This type is a duplicate of
// github.com/docker/docker/api/types.Topology. Because the type definition
// is so simple and to avoid complicated structure or circular imports, we just
// duplicate it here. See that type for full documentation
type Topology struct {
Segments map[string]string `json:",omitempty"`
}

View File

@ -62,6 +62,11 @@ type Task struct {
// used to determine which Tasks belong to which run of the job. This field
// is absent if the Service mode is Replicated or Global.
JobIteration *Version `json:",omitempty"`
// Volumes is the list of VolumeAttachments for this task. It specifies
// which particular volumes are to be used by this particular task, and
// fulfilling what mounts in the spec.
Volumes []VolumeAttachment
}
// TaskSpec represents the spec of a task.
@ -204,3 +209,17 @@ type ContainerStatus struct {
type PortStatus struct {
Ports []PortConfig `json:",omitempty"`
}
// VolumeAttachment contains the associating a Volume to a Task.
type VolumeAttachment struct {
// ID is the Swarmkit ID of the Volume. This is not the CSI VolumeId.
ID string `json:",omitempty"`
// Source, together with Target, indicates the Mount, as specified in the
// ContainerSpec, that this volume fulfills.
Source string `json:",omitempty"`
// Target, together with Source, indicates the Mount, as specified
// in the ContainerSpec, that this volume fulfills.
Target string `json:",omitempty"`
}

View File

@ -18,6 +18,14 @@ import (
"github.com/docker/go-connections/nat"
)
const (
// MediaTypeRawStream is vendor specific MIME-Type set for raw TTY streams
MediaTypeRawStream = "application/vnd.docker.raw-stream"
// MediaTypeMultiplexedStream is vendor specific MIME-Type set for stdin/stdout/stderr multiplexed streams
MediaTypeMultiplexedStream = "application/vnd.docker.multiplexed-stream"
)
// RootFS returns Image's RootFS description including the layer IDs.
type RootFS struct {
Type string `json:",omitempty"`

View File

@ -0,0 +1,420 @@
package volume
import (
"github.com/docker/docker/api/types/swarm"
)
// ClusterVolume contains options and information specific to, and only present
// on, Swarm CSI cluster volumes.
type ClusterVolume struct {
// ID is the Swarm ID of the volume. Because cluster volumes are Swarm
// objects, they have an ID, unlike non-cluster volumes, which only have a
// Name. This ID can be used to refer to the cluster volume.
ID string
// Meta is the swarm metadata about this volume.
swarm.Meta
// Spec is the cluster-specific options from which this volume is derived.
Spec ClusterVolumeSpec
// PublishStatus contains the status of the volume as it pertains to its
// publishing on Nodes.
PublishStatus []*PublishStatus `json:",omitempty"`
// Info is information about the global status of the volume.
Info *Info `json:",omitempty"`
}
// ClusterVolumeSpec contains the spec used to create this volume.
type ClusterVolumeSpec struct {
// Group defines the volume group of this volume. Volumes belonging to the
// same group can be referred to by group name when creating Services.
// Referring to a volume by group instructs swarm to treat volumes in that
// group interchangeably for the purpose of scheduling. Volumes with an
// empty string for a group technically all belong to the same, emptystring
// group.
Group string `json:",omitempty"`
// AccessMode defines how the volume is used by tasks.
AccessMode *AccessMode `json:",omitempty"`
// AccessibilityRequirements specifies where in the cluster a volume must
// be accessible from.
//
// This field must be empty if the plugin does not support
// VOLUME_ACCESSIBILITY_CONSTRAINTS capabilities. If it is present but the
// plugin does not support it, volume will not be created.
//
// If AccessibilityRequirements is empty, but the plugin does support
// VOLUME_ACCESSIBILITY_CONSTRAINTS, then Swarmkit will assume the entire
// cluster is a valid target for the volume.
AccessibilityRequirements *TopologyRequirement `json:",omitempty"`
// CapacityRange defines the desired capacity that the volume should be
// created with. If nil, the plugin will decide the capacity.
CapacityRange *CapacityRange `json:",omitempty"`
// Secrets defines Swarm Secrets that are passed to the CSI storage plugin
// when operating on this volume.
Secrets []Secret `json:",omitempty"`
// Availability is the Volume's desired availability. Analogous to Node
// Availability, this allows the user to take volumes offline in order to
// update or delete them.
Availability Availability `json:",omitempty"`
}
// Availability specifies the availability of the volume.
type Availability string
const (
// AvailabilityActive indicates that the volume is active and fully
// schedulable on the cluster.
AvailabilityActive Availability = "active"
// AvailabilityPause indicates that no new workloads should use the
// volume, but existing workloads can continue to use it.
AvailabilityPause Availability = "pause"
// AvailabilityDrain indicates that all workloads using this volume
// should be rescheduled, and the volume unpublished from all nodes.
AvailabilityDrain Availability = "drain"
)
// AccessMode defines the access mode of a volume.
type AccessMode struct {
// Scope defines the set of nodes this volume can be used on at one time.
Scope Scope `json:",omitempty"`
// Sharing defines the number and way that different tasks can use this
// volume at one time.
Sharing SharingMode `json:",omitempty"`
// MountVolume defines options for using this volume as a Mount-type
// volume.
//
// Either BlockVolume or MountVolume, but not both, must be present.
MountVolume *TypeMount `json:",omitempty"`
// BlockVolume defines options for using this volume as a Block-type
// volume.
//
// Either BlockVolume or MountVolume, but not both, must be present.
BlockVolume *TypeBlock `json:",omitempty"`
}
// Scope defines the Scope of a CSI Volume. This is how many nodes a
// Volume can be accessed simultaneously on.
type Scope string
const (
// ScopeSingleNode indicates the volume can be used on one node at a
// time.
ScopeSingleNode Scope = "single"
// ScopeMultiNode indicates the volume can be used on many nodes at
// the same time.
ScopeMultiNode Scope = "multi"
)
// SharingMode defines the Sharing of a CSI Volume. This is how Tasks using a
// Volume at the same time can use it.
type SharingMode string
const (
// SharingNone indicates that only one Task may use the Volume at a
// time.
SharingNone SharingMode = "none"
// SharingReadOnly indicates that the Volume may be shared by any
// number of Tasks, but they must be read-only.
SharingReadOnly SharingMode = "readonly"
// SharingOneWriter indicates that the Volume may be shared by any
// number of Tasks, but all after the first must be read-only.
SharingOneWriter SharingMode = "onewriter"
// SharingAll means that the Volume may be shared by any number of
// Tasks, as readers or writers.
SharingAll SharingMode = "all"
)
// TypeBlock defines options for using a volume as a block-type volume.
//
// Intentionally empty.
type TypeBlock struct{}
// TypeMount contains options for using a volume as a Mount-type
// volume.
type TypeMount struct {
// FsType specifies the filesystem type for the mount volume. Optional.
FsType string `json:",omitempty"`
// MountFlags defines flags to pass when mounting the volume. Optional.
MountFlags []string `json:",omitempty"`
}
// TopologyRequirement expresses the user's requirements for a volume's
// accessible topology.
type TopologyRequirement struct {
// Requisite specifies a list of Topologies, at least one of which the
// volume must be accessible from.
//
// Taken verbatim from the CSI Spec:
//
// Specifies the list of topologies the provisioned volume MUST be
// accessible from.
// This field is OPTIONAL. If TopologyRequirement is specified either
// requisite or preferred or both MUST be specified.
//
// If requisite is specified, the provisioned volume MUST be
// accessible from at least one of the requisite topologies.
//
// Given
// x = number of topologies provisioned volume is accessible from
// n = number of requisite topologies
// The CO MUST ensure n >= 1. The SP MUST ensure x >= 1
// If x==n, then the SP MUST make the provisioned volume available to
// all topologies from the list of requisite topologies. If it is
// unable to do so, the SP MUST fail the CreateVolume call.
// For example, if a volume should be accessible from a single zone,
// and requisite =
// {"region": "R1", "zone": "Z2"}
// then the provisioned volume MUST be accessible from the "region"
// "R1" and the "zone" "Z2".
// Similarly, if a volume should be accessible from two zones, and
// requisite =
// {"region": "R1", "zone": "Z2"},
// {"region": "R1", "zone": "Z3"}
// then the provisioned volume MUST be accessible from the "region"
// "R1" and both "zone" "Z2" and "zone" "Z3".
//
// If x<n, then the SP SHALL choose x unique topologies from the list
// of requisite topologies. If it is unable to do so, the SP MUST fail
// the CreateVolume call.
// For example, if a volume should be accessible from a single zone,
// and requisite =
// {"region": "R1", "zone": "Z2"},
// {"region": "R1", "zone": "Z3"}
// then the SP may choose to make the provisioned volume available in
// either the "zone" "Z2" or the "zone" "Z3" in the "region" "R1".
// Similarly, if a volume should be accessible from two zones, and
// requisite =
// {"region": "R1", "zone": "Z2"},
// {"region": "R1", "zone": "Z3"},
// {"region": "R1", "zone": "Z4"}
// then the provisioned volume MUST be accessible from any combination
// of two unique topologies: e.g. "R1/Z2" and "R1/Z3", or "R1/Z2" and
// "R1/Z4", or "R1/Z3" and "R1/Z4".
//
// If x>n, then the SP MUST make the provisioned volume available from
// all topologies from the list of requisite topologies and MAY choose
// the remaining x-n unique topologies from the list of all possible
// topologies. If it is unable to do so, the SP MUST fail the
// CreateVolume call.
// For example, if a volume should be accessible from two zones, and
// requisite =
// {"region": "R1", "zone": "Z2"}
// then the provisioned volume MUST be accessible from the "region"
// "R1" and the "zone" "Z2" and the SP may select the second zone
// independently, e.g. "R1/Z4".
Requisite []Topology `json:",omitempty"`
// Preferred is a list of Topologies that the volume should attempt to be
// provisioned in.
//
// Taken from the CSI spec:
//
// Specifies the list of topologies the CO would prefer the volume to
// be provisioned in.
//
// This field is OPTIONAL. If TopologyRequirement is specified either
// requisite or preferred or both MUST be specified.
//
// An SP MUST attempt to make the provisioned volume available using
// the preferred topologies in order from first to last.
//
// If requisite is specified, all topologies in preferred list MUST
// also be present in the list of requisite topologies.
//
// If the SP is unable to to make the provisioned volume available
// from any of the preferred topologies, the SP MAY choose a topology
// from the list of requisite topologies.
// If the list of requisite topologies is not specified, then the SP
// MAY choose from the list of all possible topologies.
// If the list of requisite topologies is specified and the SP is
// unable to to make the provisioned volume available from any of the
// requisite topologies it MUST fail the CreateVolume call.
//
// Example 1:
// Given a volume should be accessible from a single zone, and
// requisite =
// {"region": "R1", "zone": "Z2"},
// {"region": "R1", "zone": "Z3"}
// preferred =
// {"region": "R1", "zone": "Z3"}
// then the the SP SHOULD first attempt to make the provisioned volume
// available from "zone" "Z3" in the "region" "R1" and fall back to
// "zone" "Z2" in the "region" "R1" if that is not possible.
//
// Example 2:
// Given a volume should be accessible from a single zone, and
// requisite =
// {"region": "R1", "zone": "Z2"},
// {"region": "R1", "zone": "Z3"},
// {"region": "R1", "zone": "Z4"},
// {"region": "R1", "zone": "Z5"}
// preferred =
// {"region": "R1", "zone": "Z4"},
// {"region": "R1", "zone": "Z2"}
// then the the SP SHOULD first attempt to make the provisioned volume
// accessible from "zone" "Z4" in the "region" "R1" and fall back to
// "zone" "Z2" in the "region" "R1" if that is not possible. If that
// is not possible, the SP may choose between either the "zone"
// "Z3" or "Z5" in the "region" "R1".
//
// Example 3:
// Given a volume should be accessible from TWO zones (because an
// opaque parameter in CreateVolumeRequest, for example, specifies
// the volume is accessible from two zones, aka synchronously
// replicated), and
// requisite =
// {"region": "R1", "zone": "Z2"},
// {"region": "R1", "zone": "Z3"},
// {"region": "R1", "zone": "Z4"},
// {"region": "R1", "zone": "Z5"}
// preferred =
// {"region": "R1", "zone": "Z5"},
// {"region": "R1", "zone": "Z3"}
// then the the SP SHOULD first attempt to make the provisioned volume
// accessible from the combination of the two "zones" "Z5" and "Z3" in
// the "region" "R1". If that's not possible, it should fall back to
// a combination of "Z5" and other possibilities from the list of
// requisite. If that's not possible, it should fall back to a
// combination of "Z3" and other possibilities from the list of
// requisite. If that's not possible, it should fall back to a
// combination of other possibilities from the list of requisite.
Preferred []Topology `json:",omitempty"`
}
// Topology is a map of topological domains to topological segments.
//
// This description is taken verbatim from the CSI Spec:
//
// A topological domain is a sub-division of a cluster, like "region",
// "zone", "rack", etc.
// A topological segment is a specific instance of a topological domain,
// like "zone3", "rack3", etc.
// For example {"com.company/zone": "Z1", "com.company/rack": "R3"}
// Valid keys have two segments: an OPTIONAL prefix and name, separated
// by a slash (/), for example: "com.company.example/zone".
// The key name segment is REQUIRED. The prefix is OPTIONAL.
// The key name MUST be 63 characters or less, begin and end with an
// alphanumeric character ([a-z0-9A-Z]), and contain only dashes (-),
// underscores (_), dots (.), or alphanumerics in between, for example
// "zone".
// The key prefix MUST be 63 characters or less, begin and end with a
// lower-case alphanumeric character ([a-z0-9]), contain only
// dashes (-), dots (.), or lower-case alphanumerics in between, and
// follow domain name notation format
// (https://tools.ietf.org/html/rfc1035#section-2.3.1).
// The key prefix SHOULD include the plugin's host company name and/or
// the plugin name, to minimize the possibility of collisions with keys
// from other plugins.
// If a key prefix is specified, it MUST be identical across all
// topology keys returned by the SP (across all RPCs).
// Keys MUST be case-insensitive. Meaning the keys "Zone" and "zone"
// MUST not both exist.
// Each value (topological segment) MUST contain 1 or more strings.
// Each string MUST be 63 characters or less and begin and end with an
// alphanumeric character with '-', '_', '.', or alphanumerics in
// between.
type Topology struct {
Segments map[string]string `json:",omitempty"`
}
// CapacityRange describes the minimum and maximum capacity a volume should be
// created with
type CapacityRange struct {
// RequiredBytes specifies that a volume must be at least this big. The
// value of 0 indicates an unspecified minimum.
RequiredBytes int64
// LimitBytes specifies that a volume must not be bigger than this. The
// value of 0 indicates an unspecified maximum
LimitBytes int64
}
// Secret represents a Swarm Secret value that must be passed to the CSI
// storage plugin when operating on this Volume. It represents one key-value
// pair of possibly many.
type Secret struct {
// Key is the name of the key of the key-value pair passed to the plugin.
Key string
// Secret is the swarm Secret object from which to read data. This can be a
// Secret name or ID. The Secret data is retrieved by Swarm and used as the
// value of the key-value pair passed to the plugin.
Secret string
}
// PublishState represents the state of a Volume as it pertains to its
// use on a particular Node.
type PublishState string
const (
// StatePending indicates that the volume should be published on
// this node, but the call to ControllerPublishVolume has not been
// successfully completed yet and the result recorded by swarmkit.
StatePending PublishState = "pending-publish"
// StatePublished means the volume is published successfully to the node.
StatePublished PublishState = "published"
// StatePendingNodeUnpublish indicates that the Volume should be
// unpublished on the Node, and we're waiting for confirmation that it has
// done so. After the Node has confirmed that the Volume has been
// unpublished, the state will move to StatePendingUnpublish.
StatePendingNodeUnpublish PublishState = "pending-node-unpublish"
// StatePendingUnpublish means the volume is still published to the node
// by the controller, awaiting the operation to unpublish it.
StatePendingUnpublish PublishState = "pending-controller-unpublish"
)
// PublishStatus represents the status of the volume as published to an
// individual node
type PublishStatus struct {
// NodeID is the ID of the swarm node this Volume is published to.
NodeID string `json:",omitempty"`
// State is the publish state of the volume.
State PublishState `json:",omitempty"`
// PublishContext is the PublishContext returned by the CSI plugin when
// a volume is published.
PublishContext map[string]string `json:",omitempty"`
}
// Info contains information about the Volume as a whole as provided by
// the CSI storage plugin.
type Info struct {
// CapacityBytes is the capacity of the volume in bytes. A value of 0
// indicates that the capacity is unknown.
CapacityBytes int64 `json:",omitempty"`
// VolumeContext is the context originating from the CSI storage plugin
// when the Volume is created.
VolumeContext map[string]string `json:",omitempty"`
// VolumeID is the ID of the Volume as seen by the CSI storage plugin. This
// is distinct from the Volume's Swarm ID, which is the ID used by all of
// the Docker Engine to refer to the Volume. If this field is blank, then
// the Volume has not been successfully created yet.
VolumeID string `json:",omitempty"`
// AccessibleTopolgoy is the topology this volume is actually accessible
// from.
AccessibleTopology []Topology `json:",omitempty"`
}

View File

@ -9,6 +9,9 @@ package volume
// swagger:model CreateOptions
type CreateOptions struct {
// cluster volume spec
ClusterVolumeSpec *ClusterVolumeSpec `json:"ClusterVolumeSpec,omitempty"`
// Name of the volume driver to use.
Driver string `json:"Driver,omitempty"`

View File

@ -0,0 +1,8 @@
package volume // import "github.com/docker/docker/api/types/volume"
import "github.com/docker/docker/api/types/filters"
// ListOptions holds parameters to list volumes.
type ListOptions struct {
Filters filters.Args
}

View File

@ -7,6 +7,9 @@ package volume
// swagger:model Volume
type Volume struct {
// cluster volume
ClusterVolume *ClusterVolume `json:"ClusterVolume,omitempty"`
// Date/Time the volume was created.
CreatedAt string `json:"CreatedAt,omitempty"`

View File

@ -0,0 +1,7 @@
package volume // import "github.com/docker/docker/api/types/volume"
// UpdateOptions is configuration to update a Volume with.
type UpdateOptions struct {
// Spec is the ClusterVolumeSpec to update the volume to.
Spec *ClusterVolumeSpec `json:"Spec,omitempty"`
}

View File

@ -52,6 +52,8 @@ func (cli *Client) ContainerAttach(ctx context.Context, container string, option
query.Set("logs", "1")
}
headers := map[string][]string{"Content-Type": {"text/plain"}}
headers := map[string][]string{
"Content-Type": {"text/plain"},
}
return cli.postHijacked(ctx, "/containers/"+container+"/attach", query, nil, headers)
}

View File

@ -36,7 +36,9 @@ func (cli *Client) ContainerExecStart(ctx context.Context, execID string, config
// and the a reader to get output. It's up to the called to close
// the hijacked connection by calling types.HijackedResponse.Close.
func (cli *Client) ContainerExecAttach(ctx context.Context, execID string, config types.ExecStartCheck) (types.HijackedResponse, error) {
headers := map[string][]string{"Content-Type": {"application/json"}}
headers := map[string][]string{
"Content-Type": {"application/json"},
}
return cli.postHijacked(ctx, "/exec/"+execID+"/start", nil, config, headers)
}

View File

@ -12,6 +12,7 @@ import (
"time"
"github.com/docker/docker/api/types"
"github.com/docker/docker/api/types/versions"
"github.com/docker/go-connections/sockets"
"github.com/pkg/errors"
)
@ -30,12 +31,12 @@ func (cli *Client) postHijacked(ctx context.Context, path string, query url.Valu
}
req = cli.addHeaders(req, headers)
conn, err := cli.setupHijackConn(ctx, req, "tcp")
conn, mediaType, err := cli.setupHijackConn(ctx, req, "tcp")
if err != nil {
return types.HijackedResponse{}, err
}
return types.HijackedResponse{Conn: conn, Reader: bufio.NewReader(conn)}, err
return types.NewHijackedResponse(conn, mediaType), err
}
// DialHijack returns a hijacked connection with negotiated protocol proto.
@ -46,7 +47,8 @@ func (cli *Client) DialHijack(ctx context.Context, url, proto string, meta map[s
}
req = cli.addHeaders(req, meta)
return cli.setupHijackConn(ctx, req, proto)
conn, _, err := cli.setupHijackConn(ctx, req, proto)
return conn, err
}
// fallbackDial is used when WithDialer() was not called.
@ -61,7 +63,7 @@ func fallbackDial(proto, addr string, tlsConfig *tls.Config) (net.Conn, error) {
return net.Dial(proto, addr)
}
func (cli *Client) setupHijackConn(ctx context.Context, req *http.Request, proto string) (net.Conn, error) {
func (cli *Client) setupHijackConn(ctx context.Context, req *http.Request, proto string) (net.Conn, string, error) {
req.Host = cli.addr
req.Header.Set("Connection", "Upgrade")
req.Header.Set("Upgrade", proto)
@ -69,7 +71,7 @@ func (cli *Client) setupHijackConn(ctx context.Context, req *http.Request, proto
dialer := cli.Dialer()
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, "", errors.Wrap(err, "cannot connect to the Docker daemon. Is 'docker daemon' running on this host?")
}
// When we set up a TCP connection for hijack, there could be long periods
@ -91,18 +93,18 @@ func (cli *Client) setupHijackConn(ctx context.Context, req *http.Request, proto
//nolint:staticcheck // ignore SA1019 for connecting to old (pre go1.8) daemons
if err != httputil.ErrPersistEOF {
if err != nil {
return nil, err
return nil, "", err
}
if resp.StatusCode != http.StatusSwitchingProtocols {
resp.Body.Close()
return nil, fmt.Errorf("unable to upgrade to %s, received %d", proto, resp.StatusCode)
return nil, "", fmt.Errorf("unable to upgrade to %s, received %d", proto, resp.StatusCode)
}
}
c, br := clientconn.Hijack()
if br.Buffered() > 0 {
// If there is buffered content, wrap the connection. We return an
// object that implements CloseWrite iff the underlying connection
// object that implements CloseWrite if the underlying connection
// implements it.
if _, ok := c.(types.CloseWriter); ok {
c = &hijackedConnCloseWriter{&hijackedConn{c, br}}
@ -113,7 +115,13 @@ func (cli *Client) setupHijackConn(ctx context.Context, req *http.Request, proto
br.Reset(nil)
}
return c, nil
var mediaType string
if versions.GreaterThanOrEqualTo(cli.ClientVersion(), "1.42") {
// Prior to 1.42, Content-Type is always set to raw-stream and not relevant
mediaType = resp.Header.Get("Content-Type")
}
return c, mediaType, nil
}
// hijackedConn wraps a net.Conn and is returned by setupHijackConn in the case

View File

@ -179,6 +179,7 @@ type VolumeAPIClient interface {
VolumeList(ctx context.Context, filter filters.Args) (volume.ListResponse, error)
VolumeRemove(ctx context.Context, volumeID string, force bool) error
VolumesPrune(ctx context.Context, pruneFilter filters.Args) (types.VolumesPruneReport, error)
VolumeUpdate(ctx context.Context, volumeID string, version swarm.Version, options volume.UpdateOptions) error
}
// SecretAPIClient defines API client methods for secrets

View File

@ -49,6 +49,14 @@ func (cli *Client) postRaw(ctx context.Context, path string, query url.Values, b
return cli.sendRequest(ctx, http.MethodPost, path, query, body, headers)
}
func (cli *Client) put(ctx context.Context, path string, query url.Values, obj interface{}, headers map[string][]string) (serverResponse, error) {
body, headers, err := encodeBody(obj, headers)
if err != nil {
return serverResponse{}, err
}
return cli.sendRequest(ctx, http.MethodPut, path, query, body, headers)
}
// putRaw sends an http request to the docker API using the method PUT.
func (cli *Client) putRaw(ctx context.Context, path string, query url.Values, body io.Reader, headers map[string][]string) (serverResponse, error) {
return cli.sendRequest(ctx, http.MethodPut, path, query, body, headers)

View File

@ -0,0 +1,25 @@
package client // import "github.com/docker/docker/client"
import (
"context"
"net/url"
"strconv"
"github.com/docker/docker/api/types/swarm"
"github.com/docker/docker/api/types/volume"
)
// VolumeUpdate updates a volume. This only works for Cluster Volumes, and
// only some fields can be updated.
func (cli *Client) VolumeUpdate(ctx context.Context, volumeID string, version swarm.Version, options volume.UpdateOptions) error {
if err := cli.NewVersionError("1.42", "volume update"); err != nil {
return err
}
query := url.Values{}
query.Set("version", strconv.FormatUint(version.Index, 10))
resp, err := cli.put(ctx, "/volumes/"+volumeID, query, options, nil)
ensureReaderClosed(resp)
return err
}

4
vendor/modules.txt vendored
View File

@ -39,7 +39,7 @@ github.com/docker/distribution/registry/client/transport
github.com/docker/distribution/registry/storage/cache
github.com/docker/distribution/registry/storage/cache/memory
github.com/docker/distribution/uuid
# github.com/docker/docker v20.10.14+incompatible => github.com/docker/docker v20.10.3-0.20220512073244-7c69b6dc08c7+incompatible
# github.com/docker/docker v20.10.14+incompatible => github.com/docker/docker v20.10.3-0.20220513094153-f1dd6bf84e28+incompatible
## explicit
github.com/docker/docker/api
github.com/docker/docker/api/types
@ -390,6 +390,6 @@ gotest.tools/v3/internal/format
gotest.tools/v3/internal/source
gotest.tools/v3/poll
gotest.tools/v3/skip
# github.com/docker/docker => github.com/docker/docker v20.10.3-0.20220512073244-7c69b6dc08c7+incompatible
# github.com/docker/docker => github.com/docker/docker v20.10.3-0.20220513094153-f1dd6bf84e28+incompatible
# github.com/gogo/googleapis => github.com/gogo/googleapis v1.3.2
# github.com/google/certificate-transparency-go => github.com/google/certificate-transparency-go v1.0.20