Merge pull request #29229 from vieux/1.13.0-rc4-cherrypicks

1.13.0-rc4 cherry-picks: part1
This commit is contained in:
Victor Vieux 2016-12-14 17:18:17 -08:00 committed by GitHub
commit 1b521547f0
146 changed files with 1888 additions and 878 deletions

View File

@ -7,6 +7,22 @@ be found.
## 1.13.0 (2017-01-10)
**IMPORTANT**: In Docker 1.13, the managed plugin api changed, as compared to the experimental
version introduced in Docker 1.12. You must **uninstall** plugins which you installed with Docker 1.12
_before_ upgrading to Docker 1.13. You can uninstall plugins using the `docker plugin rm` command.
If you have already upgraded to Docker 1.13 without uninstalling
previously-installed plugins, you may see this message when the Docker daemon
starts:
Error starting daemon: json: cannot unmarshal string into Go value of type types.PluginEnv
To manually remove all plugins and resolve this problem, take the following steps:
1. Remove plugins.json from: `/var/lib/docker/plugins/`.
2. Restart Docker. Verify that the Docker daemon starts with no errors.
3. Reinstall your plugins.
### Builder
+ Add capability to specify images used as a cache source on build. These images do not need to have local parent chain and can be pulled from other registries [#26839](https://github.com/docker/docker/pull/26839)
+ (experimental) Add option to squash image layers to the FROM image after successful builds [#22641](https://github.com/docker/docker/pull/22641)
@ -185,7 +201,7 @@ be found.
### Volume
+ Add support for labels on volumes [#25628](https://github.com/docker/docker/pull/21567)
+ Add support for labels on volumes [#21270](https://github.com/docker/docker/pull/21270)
+ Add support for filtering volumes by label [#25628](https://github.com/docker/docker/pull/25628)
* Add a `--force` flag in `docker volume rm` to forcefully purge the data of the volume that has already been deleted [#23436](https://github.com/docker/docker/pull/23436)
* Enhance `docker volume inspect` to show all options used when creating the volume [#26671](https://github.com/docker/docker/pull/26671)
@ -207,6 +223,7 @@ be found.
- Deprecate `MAINTAINER` in Dockerfile [#25466](https://github.com/docker/docker/pull/25466)
- Deprecate `filter` param for endpoint `/images/json` [#27872](https://github.com/docker/docker/pull/27872)
- Deprecate setting duplicate engine labels [#24533](https://github.com/docker/docker/pull/24533)
- Deprecate "top-level" network information in `NetworkSettings` [#28437](https://github.com/docker/docker/pull/28437)
## 1.12.3 (2016-10-26)
@ -595,7 +612,7 @@ installing docker, please make sure to update them accordingly.
### DEPRECATION
* Environment variables `DOCKER_CONTENT_TRUST_OFFLINE_PASSPHRASE` and `DOCKER_CONTENT_TRUST_TAGGING_PASSPHRASE` have been renamed
* Environment variables `DOCKER_CONTENT_TRUST_OFFLINE_PASSPHRASE` and `DOCKER_CONTENT_TRUST_TAGGING_PASSPHRASE` have been renamed
to `DOCKER_CONTENT_TRUST_ROOT_PASSPHRASE` and `DOCKER_CONTENT_TRUST_REPOSITORY_PASSPHRASE` respectively [#22574](https://github.com/docker/docker/pull/22574)
* Remove deprecated `syslog-tag`, `gelf-tag`, `fluentd-tag` log option in favor of the more generic `tag` one [#22620](https://github.com/docker/docker/pull/22620)
* Remove deprecated feature of passing HostConfig at API container start [#22570](https://github.com/docker/docker/pull/22570)
@ -766,7 +783,7 @@ installing docker, please make sure to update them accordingly.
- Fix a panic that could occur when cleanup after a container started with invalid parameters ([#21716](https://github.com/docker/docker/pull/21716))
- Fix a race with event timers stopping early ([#21692](https://github.com/docker/docker/pull/21692))
- Fix race conditions in the layer store, potentially corrupting the map and crashing the process ([#21677](https://github.com/docker/docker/pull/21677))
- Un-deprecate auto-creation of host directories for mounts. This feature was marked deprecated in ([#21666](https://github.com/docker/docker/pull/21666))
- Un-deprecate auto-creation of host directories for mounts. This feature was marked deprecated in ([#21666](https://github.com/docker/docker/pull/21666))
Docker 1.9, but was decided to be too much of a backward-incompatible change, so it was decided to keep the feature.
+ It is now possible for containers to share the NET and IPC namespaces when `userns` is enabled ([#21383](https://github.com/docker/docker/pull/21383))
+ `docker inspect <image-id>` will now expose the rootfs layers ([#21370](https://github.com/docker/docker/pull/21370))

View File

@ -62,14 +62,17 @@
# >> cd C:\go\src\github.com\docker\docker
#
#
# 3. Build a docker image with the components required to build the docker binaries from source:
# 3. Build a docker image with the components required to build the docker binaries from source
# by running one of the following:
#
# >> docker build -t nativebuildimage -f Dockerfile.windows .
# >> docker build -t nativebuildimage -f Dockerfile.windows .
# >> docker build -t nativebuildimage -f Dockerfile.windows -m 2GB . (if using Hyper-V containers)
#
#
# 4. Build the docker executable binaries:
# 4. Build the docker executable binaries by running one of the following:
#
# >> docker run --name binaries nativebuildimage hack\make.ps1 -Binary
# >> docker run --name binaries -m 2GB nativebuildimage hack\make.ps1 -Binary (if using Hyper-V containers)
#
#
# 5. Copy the binaries out of the container, replacing HostPath with an appropriate destination
@ -96,10 +99,11 @@
# The validation tests can either run in a container, or directly on the host. To run in a
# container, ensure you have created the nativebuildimage above. Then run the following
# from an (elevated) Windows PowerShell prompt:
# container, ensure you have created the nativebuildimage above. Then run one of the
# following from an (elevated) Windows PowerShell prompt:
#
# >> docker run --rm nativebuildimage hack\make.ps1 -DCO -PkgImports -GoFormat
# >> docker run --rm -m 2GB nativebuildimage hack\make.ps1 -DCO -PkgImports -GoFormat (if using Hyper-V containers)
# To run the validation tests on the host, from the root of the repository, run the
# following from a Windows PowerShell prompt (elevation is not required): (Note Go
@ -110,20 +114,21 @@
# -----------------------------------------------------------------------------------------
# To run unit tests, ensure you have created the nativebuildimage above. Then run the
# following from an (elevated) Windows PowerShell prompt:
# To run unit tests, ensure you have created the nativebuildimage above. Then run one of
# the following from an (elevated) Windows PowerShell prompt:
#
# >> docker run --rm nativebuildimage hack\make.ps1 -TestUnit
# >> docker run --rm -m 2GB nativebuildimage hack\make.ps1 -TestUnit (if using Hyper-V containers)
# -----------------------------------------------------------------------------------------
# To run all tests and binary build, ensure you have created the nativebuildimage above. Then
# run the following from an (elevated) Windows PowerShell prompt:
# run one of the following from an (elevated) Windows PowerShell prompt:
#
# >> docker run nativebuildimage hack\make.ps1 -All
# >> docker run -m 2GB nativebuildimage hack\make.ps1 -All (if using Hyper-V containers)
# -----------------------------------------------------------------------------------------

View File

@ -84,14 +84,28 @@ func newImageBuildOptions(ctx context.Context, r *http.Request) (*types.ImageBui
options.Ulimits = buildUlimits
}
var buildArgs = map[string]string{}
var buildArgs = map[string]*string{}
buildArgsJSON := r.FormValue("buildargs")
// Note that there are two ways a --build-arg might appear in the
// json of the query param:
// "foo":"bar"
// and "foo":nil
// The first is the normal case, ie. --build-arg foo=bar
// or --build-arg foo
// where foo's value was picked up from an env var.
// The second ("foo":nil) is where they put --build-arg foo
// but "foo" isn't set as an env var. In that case we can't just drop
// the fact they mentioned it, we need to pass that along to the builder
// so that it can print a warning about "foo" being unused if there is
// no "ARG foo" in the Dockerfile.
if buildArgsJSON != "" {
if err := json.Unmarshal([]byte(buildArgsJSON), &buildArgs); err != nil {
return nil, err
}
options.BuildArgs = buildArgs
}
var labels = map[string]string{}
labelsJSON := r.FormValue("labels")
if labelsJSON != "" {

View File

@ -9,6 +9,7 @@ import (
"github.com/docker/docker/api/types"
"github.com/docker/docker/api/types/backend"
"github.com/docker/docker/api/types/container"
"github.com/docker/docker/api/types/filters"
"github.com/docker/docker/pkg/archive"
)
@ -64,7 +65,7 @@ type attachBackend interface {
// systemBackend includes functions to implement to provide system wide containers functionality
type systemBackend interface {
ContainersPrune(config *types.ContainersPruneConfig) (*types.ContainersPruneReport, error)
ContainersPrune(pruneFilters filters.Args) (*types.ContainersPruneReport, error)
}
// Backend is all the methods that need to be implemented to provide container specific functionality.

View File

@ -541,16 +541,12 @@ func (s *containerRouter) postContainersPrune(ctx context.Context, w http.Respon
return err
}
if err := httputils.CheckForJSON(r); err != nil {
pruneFilters, err := filters.FromParam(r.Form.Get("filters"))
if err != nil {
return err
}
var cfg types.ContainersPruneConfig
if err := json.NewDecoder(r.Body).Decode(&cfg); err != nil {
return err
}
pruneReport, err := s.backend.ContainersPrune(&cfg)
pruneReport, err := s.backend.ContainersPrune(pruneFilters)
if err != nil {
return err
}

View File

@ -92,11 +92,17 @@ func (s *containerRouter) postContainerExecStart(ctx context.Context, w http.Res
defer httputils.CloseStreams(inStream, outStream)
if _, ok := r.Header["Upgrade"]; ok {
fmt.Fprintf(outStream, "HTTP/1.1 101 UPGRADED\r\nContent-Type: application/vnd.docker.raw-stream\r\nConnection: Upgrade\r\nUpgrade: tcp\r\n\r\n")
fmt.Fprint(outStream, "HTTP/1.1 101 UPGRADED\r\nContent-Type: application/vnd.docker.raw-stream\r\nConnection: Upgrade\r\nUpgrade: tcp\r\n")
} else {
fmt.Fprintf(outStream, "HTTP/1.1 200 OK\r\nContent-Type: application/vnd.docker.raw-stream\r\n\r\n")
fmt.Fprint(outStream, "HTTP/1.1 200 OK\r\nContent-Type: application/vnd.docker.raw-stream\r\n")
}
// copy headers that were removed as part of hijack
if err := w.Header().WriteSubset(outStream, nil); err != nil {
return err
}
fmt.Fprint(outStream, "\r\n")
stdin = inStream
stdout = outStream
if !execStartCheck.Tty {

View File

@ -29,7 +29,7 @@ type imageBackend interface {
Images(imageFilters filters.Args, all bool, withExtraAttrs bool) ([]*types.ImageSummary, error)
LookupImage(name string) (*types.ImageInspect, error)
TagImage(imageName, repository, tag string) error
ImagesPrune(config *types.ImagesPruneConfig) (*types.ImagesPruneReport, error)
ImagesPrune(pruneFilters filters.Args) (*types.ImagesPruneReport, error)
}
type importExportBackend interface {

View File

@ -331,16 +331,12 @@ func (s *imageRouter) postImagesPrune(ctx context.Context, w http.ResponseWriter
return err
}
if err := httputils.CheckForJSON(r); err != nil {
pruneFilters, err := filters.FromParam(r.Form.Get("filters"))
if err != nil {
return err
}
var cfg types.ImagesPruneConfig
if err := json.NewDecoder(r.Body).Decode(&cfg); err != nil {
return err
}
pruneReport, err := s.backend.ImagesPrune(&cfg)
pruneReport, err := s.backend.ImagesPrune(pruneFilters)
if err != nil {
return err
}

View File

@ -2,6 +2,7 @@ package network
import (
"github.com/docker/docker/api/types"
"github.com/docker/docker/api/types/filters"
"github.com/docker/docker/api/types/network"
"github.com/docker/libnetwork"
)
@ -17,5 +18,5 @@ type Backend interface {
ConnectContainerToNetwork(containerName, networkName string, endpointConfig *network.EndpointSettings) error
DisconnectContainerFromNetwork(containerName string, networkName string, force bool) error
DeleteNetwork(name string) error
NetworksPrune(config *types.NetworksPruneConfig) (*types.NetworksPruneReport, error)
NetworksPrune(pruneFilters filters.Args) (*types.NetworksPruneReport, error)
}

View File

@ -300,16 +300,7 @@ func (n *networkRouter) postNetworksPrune(ctx context.Context, w http.ResponseWr
return err
}
if err := httputils.CheckForJSON(r); err != nil {
return err
}
var cfg types.NetworksPruneConfig
if err := json.NewDecoder(r.Body).Decode(&cfg); err != nil {
return err
}
pruneReport, err := n.backend.NetworksPrune(&cfg)
pruneReport, err := n.backend.NetworksPrune(filters.Args{})
if err != nil {
return err
}

View File

@ -16,7 +16,8 @@ type Backend interface {
Inspect(name string) (enginetypes.Plugin, error)
Remove(name string, config *enginetypes.PluginRmConfig) error
Set(name string, args []string) error
Pull(name string, metaHeaders http.Header, authConfig *enginetypes.AuthConfig) (enginetypes.PluginPrivileges, error)
Privileges(name string, metaHeaders http.Header, authConfig *enginetypes.AuthConfig) (enginetypes.PluginPrivileges, error)
Pull(name string, metaHeaders http.Header, authConfig *enginetypes.AuthConfig, privileges enginetypes.PluginPrivileges) error
Push(name string, metaHeaders http.Header, authConfig *enginetypes.AuthConfig) error
CreateFromContext(ctx context.Context, tarCtx io.Reader, options *enginetypes.PluginCreateOptions) error
}

View File

@ -25,7 +25,8 @@ func (r *pluginRouter) Routes() []router.Route {
func (r *pluginRouter) initRoutes() {
r.routes = []router.Route{
router.NewGetRoute("/plugins", r.listPlugins),
router.NewGetRoute("/plugins/{name:.*}", r.inspectPlugin),
router.NewGetRoute("/plugins/{name:.*}/json", r.inspectPlugin),
router.NewGetRoute("/plugins/privileges", r.getPrivileges),
router.NewDeleteRoute("/plugins/{name:.*}", r.removePlugin),
router.NewPostRoute("/plugins/{name:.*}/enable", r.enablePlugin), // PATCH?
router.NewPostRoute("/plugins/{name:.*}/disable", r.disablePlugin),

View File

@ -12,20 +12,17 @@ import (
"golang.org/x/net/context"
)
func (pr *pluginRouter) pullPlugin(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
if err := httputils.ParseForm(r); err != nil {
return err
}
func parseHeaders(headers http.Header) (map[string][]string, *types.AuthConfig) {
metaHeaders := map[string][]string{}
for k, v := range r.Header {
for k, v := range headers {
if strings.HasPrefix(k, "X-Meta-") {
metaHeaders[k] = v
}
}
// Get X-Registry-Auth
authEncoded := r.Header.Get("X-Registry-Auth")
authEncoded := headers.Get("X-Registry-Auth")
authConfig := &types.AuthConfig{}
if authEncoded != "" {
authJSON := base64.NewDecoder(base64.URLEncoding, strings.NewReader(authEncoded))
@ -34,13 +31,42 @@ func (pr *pluginRouter) pullPlugin(ctx context.Context, w http.ResponseWriter, r
}
}
privileges, err := pr.backend.Pull(r.FormValue("name"), metaHeaders, authConfig)
return metaHeaders, authConfig
}
func (pr *pluginRouter) getPrivileges(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
if err := httputils.ParseForm(r); err != nil {
return err
}
metaHeaders, authConfig := parseHeaders(r.Header)
privileges, err := pr.backend.Privileges(r.FormValue("name"), metaHeaders, authConfig)
if err != nil {
return err
}
return httputils.WriteJSON(w, http.StatusOK, privileges)
}
func (pr *pluginRouter) pullPlugin(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
if err := httputils.ParseForm(r); err != nil {
return err
}
var privileges types.PluginPrivileges
if err := json.NewDecoder(r.Body).Decode(&privileges); err != nil {
return err
}
metaHeaders, authConfig := parseHeaders(r.Header)
if err := pr.backend.Pull(r.FormValue("name"), metaHeaders, authConfig, privileges); err != nil {
return err
}
w.WriteHeader(http.StatusCreated)
return nil
}
func (pr *pluginRouter) createPlugin(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
if err := httputils.ParseForm(r); err != nil {
return err
@ -52,6 +78,7 @@ func (pr *pluginRouter) createPlugin(ctx context.Context, w http.ResponseWriter,
if err := pr.backend.CreateFromContext(ctx, r.Body, options); err != nil {
return err
}
//TODO: send progress bar
w.WriteHeader(http.StatusNoContent)
return nil
}
@ -92,22 +119,8 @@ func (pr *pluginRouter) pushPlugin(ctx context.Context, w http.ResponseWriter, r
return err
}
metaHeaders := map[string][]string{}
for k, v := range r.Header {
if strings.HasPrefix(k, "X-Meta-") {
metaHeaders[k] = v
}
}
metaHeaders, authConfig := parseHeaders(r.Header)
// Get X-Registry-Auth
authEncoded := r.Header.Get("X-Registry-Auth")
authConfig := &types.AuthConfig{}
if authEncoded != "" {
authJSON := base64.NewDecoder(base64.URLEncoding, strings.NewReader(authEncoded))
if err := json.NewDecoder(authJSON).Decode(authConfig); err != nil {
authConfig = &types.AuthConfig{}
}
}
return pr.backend.Push(vars["name"], metaHeaders, authConfig)
}

View File

@ -3,6 +3,7 @@ package volume
import (
// TODO return types need to be refactored into pkg
"github.com/docker/docker/api/types"
"github.com/docker/docker/api/types/filters"
)
// Backend is the methods that need to be implemented to provide
@ -12,5 +13,5 @@ type Backend interface {
VolumeInspect(name string) (*types.Volume, error)
VolumeCreate(name, driverName string, opts, labels map[string]string) (*types.Volume, error)
VolumeRm(name string, force bool) error
VolumesPrune(config *types.VolumesPruneConfig) (*types.VolumesPruneReport, error)
VolumesPrune(pruneFilters filters.Args) (*types.VolumesPruneReport, error)
}

View File

@ -5,7 +5,7 @@ import (
"net/http"
"github.com/docker/docker/api/server/httputils"
"github.com/docker/docker/api/types"
"github.com/docker/docker/api/types/filters"
volumetypes "github.com/docker/docker/api/types/volume"
"golang.org/x/net/context"
)
@ -72,16 +72,7 @@ func (v *volumeRouter) postVolumesPrune(ctx context.Context, w http.ResponseWrit
return err
}
if err := httputils.CheckForJSON(r); err != nil {
return err
}
var cfg types.VolumesPruneConfig
if err := json.NewDecoder(r.Body).Decode(&cfg); err != nil {
return err
}
pruneReport, err := v.backend.VolumesPrune(&cfg)
pruneReport, err := v.backend.VolumesPrune(filters.Args{})
if err != nil {
return err
}

View File

@ -97,37 +97,49 @@ info:
tags:
# Primary objects
- name: "Container"
x-displayName: "Containers"
description: |
Create and manage containers.
- name: "Image"
x-displayName: "Images"
- name: "Network"
x-displayName: "Networks"
description: |
Networks are user-defined networks that containers can be attached to. See the [networking documentation](https://docs.docker.com/engine/userguide/networking/) for more information.
- name: "Volume"
x-displayName: "Volumes"
description: |
Create and manage persistent storage that can be attached to containers.
- name: "Exec"
x-displayName: "Exec"
description: |
Run new commands inside running containers. See the [command-line reference](https://docs.docker.com/engine/reference/commandline/exec/) for more information.
To exec a command in a container, you first need to create an exec instance, then start it. These two API endpoints are wrapped up in a single command-line command, `docker exec`.
- name: "Secret"
x-displayName: "Secrets"
# Swarm things
- name: "Swarm"
x-displayName: "Swarm"
description: |
Engines can be clustered together in a swarm. See [the swarm mode documentation](https://docs.docker.com/engine/swarm/) for more information.
- name: "Node"
x-displayName: "Nodes"
description: |
Nodes are instances of the Engine participating in a swarm. Swarm mode must be enabled for these endpoints to work.
- name: "Service"
x-displayName: "Services"
description: |
Services are the definitions of tasks to run on a swarm. Swarm mode must be enabled for these endpoints to work.
- name: "Task"
x-displayName: "Tasks"
description: |
A task is a container running on a swarm. It is the atomic scheduling unit of swarm. Swarm mode must be enabled for these endpoints to work.
# System things
- name: "Plugin"
x-displayName: "Plugins"
- name: "System"
x-displayName: "System"
definitions:
Port:
@ -1382,6 +1394,7 @@ definitions:
- Workdir
- Network
- Linux
- PropagatedMount
- Mounts
- Env
- Args
@ -1446,6 +1459,9 @@ definitions:
type: "array"
items:
$ref: "#/definitions/PluginDevice"
PropagatedMount:
type: "string"
x-nullable: false
Mounts:
type: "array"
items:
@ -4186,11 +4202,17 @@ paths:
/containers/prune:
post:
summary: "Delete stopped containers"
consumes:
- "application/json"
produces:
- "application/json"
operationId: "ContainerPrune"
parameters:
- name: "filters"
in: "query"
description: |
Filters to process on the prune list, encoded as JSON (a `map[string][]string`).
Available filters:
type: "string"
responses:
200:
description: "No error"
@ -4442,6 +4464,10 @@ paths:
responses:
200:
description: "no error"
404:
description: "repository does not exist or no read access"
schema:
$ref: "#/definitions/ErrorResponse"
500:
description: "server error"
schema:
@ -4848,21 +4874,20 @@ paths:
/images/prune:
post:
summary: "Delete unused images"
consumes:
- "application/json"
produces:
- "application/json"
operationId: "ImagePrune"
parameters:
- name: "body"
in: "body"
schema:
type: "object"
properties:
DanglingOnly:
description: "Only delete unused *and* untagged images"
type: "boolean"
default: false
- name: "filters"
in: "query"
description: |
Filters to process on the prune list, encoded as JSON (a `map[string][]string`).
Available filters:
- `dangling=<boolean>` When set to `true` (or `1`), prune only
unused *and* untagged images. When set to `false`
(or `0`), all unused images are pruned.
type: "string"
responses:
200:
description: "No error"
@ -5944,11 +5969,17 @@ paths:
/volumes/prune:
post:
summary: "Delete unused volumes"
consumes:
- "application/json"
produces:
- "application/json"
operationId: "VolumePrune"
parameters:
- name: "filters"
in: "query"
description: |
Filters to process on the prune list, encoded as JSON (a `map[string][]string`).
Available filters:
type: "string"
responses:
200:
description: "No error"
@ -6118,6 +6149,10 @@ paths:
example:
Id: "22be93d5babb089c5aab8dbc369042fad48ff791584ca2da2100db837a1c7c30"
Warning: ""
403:
description: "operation not supported for pre-defined networks"
schema:
$ref: "#/definitions/ErrorResponse"
404:
description: "plugin not found"
schema:
@ -6286,6 +6321,14 @@ paths:
produces:
- "application/json"
operationId: "NetworkPrune"
parameters:
- name: "filters"
in: "query"
description: |
Filters to process on the prune list, encoded as JSON (a `map[string][]string`).
Available filters:
type: "string"
responses:
200:
description: "No error"
@ -6396,14 +6439,10 @@ paths:
$ref: "#/definitions/ErrorResponse"
tags: ["Plugin"]
/plugins/pull:
post:
summary: "Install a plugin"
operationId: "PluginPull"
description: |
Pulls and installs a plugin. After the plugin is installed, it can be enabled using the [`POST /plugins/{name}/enable` endpoint](#operation/PluginEnable).
produces:
- "application/json"
/plugins/privileges:
get:
summary: "Get plugin privileges"
operationId: "GetPluginPrivileges"
responses:
200:
description: "no error"
@ -6438,6 +6477,30 @@ paths:
description: "server error"
schema:
$ref: "#/definitions/ErrorResponse"
parameters:
- name: "name"
in: "query"
description: "The name of the plugin. The `:latest` tag is optional, and is the default if omitted."
required: true
type: "string"
tags:
- "Plugin"
/plugins/pull:
post:
summary: "Install a plugin"
operationId: "PluginPull"
description: |
Pulls and installs a plugin. After the plugin is installed, it can be enabled using the [`POST /plugins/{name}/enable` endpoint](#operation/PostPluginsEnable).
produces:
- "application/json"
responses:
204:
description: "no error"
500:
description: "server error"
schema:
$ref: "#/definitions/ErrorResponse"
parameters:
- name: "name"
in: "query"
@ -6451,8 +6514,37 @@ paths:
in: "header"
description: "A base64-encoded auth configuration to use when pulling a plugin from a registry. [See the authentication section for details.](#section/Authentication)"
type: "string"
- name: "body"
in: "body"
schema:
type: "array"
items:
description: "Describes a permission accepted by the user upon installing the plugin."
type: "object"
properties:
Name:
type: "string"
Description:
type: "string"
Value:
type: "array"
items:
type: "string"
example:
- Name: "network"
Description: ""
Value:
- "host"
- Name: "mount"
Description: ""
Value:
- "/data"
- Name: "device"
Description: ""
Value:
- "/dev/cpu_dma_latency"
tags: ["Plugin"]
/plugins/{name}:
/plugins/{name}/json:
get:
summary: "Inspect a plugin"
operationId: "PluginInspect"
@ -7058,6 +7150,10 @@ paths:
example:
ID: "ak7w3gjqoa3kuz8xcpnyy0pvl"
Warning: "unable to pin image doesnotexist:latest to digest: image library/doesnotexist:latest not found"
403:
description: "network is not eligible for services"
schema:
$ref: "#/definitions/ErrorResponse"
409:
description: "name conflicts with an existing service"
schema:

View File

@ -160,10 +160,13 @@ type ImageBuildOptions struct {
ShmSize int64
Dockerfile string
Ulimits []*units.Ulimit
BuildArgs map[string]string
AuthConfigs map[string]AuthConfig
Context io.Reader
Labels map[string]string
// See the parsing of buildArgs in api/server/router/build/build_routes.go
// for an explaination of why BuildArgs needs to use *string instead of
// just a string
BuildArgs map[string]*string
AuthConfigs map[string]AuthConfig
Context io.Reader
Labels map[string]string
// squash the resulting image's layers to the parent
// preserves the original image and creates a new one from the parent with all
// the changes applied to a single layer

View File

@ -71,6 +71,10 @@ type PluginConfig struct {
// Required: true
Network PluginConfigNetwork `json:"Network"`
// propagated mount
// Required: true
PropagatedMount string `json:"PropagatedMount"`
// user
User PluginConfigUser `json:"User,omitempty"`

View File

@ -19,3 +19,9 @@ type Annotations struct {
Name string `json:",omitempty"`
Labels map[string]string `json:",omitempty"`
}
// Driver represents a driver (network, logging).
type Driver struct {
Name string `json:",omitempty"`
Options map[string]string `json:",omitempty"`
}

View File

@ -109,9 +109,3 @@ type IPAMConfig struct {
Range string `json:",omitempty"`
Gateway string `json:",omitempty"`
}
// Driver represents a network driver.
type Driver struct {
Name string `json:",omitempty"`
Options map[string]string `json:",omitempty"`
}

View File

@ -509,27 +509,6 @@ type DiskUsage struct {
Volumes []*Volume
}
// ImagesPruneConfig contains the configuration for Engine API:
// POST "/images/prune"
type ImagesPruneConfig struct {
DanglingOnly bool
}
// ContainersPruneConfig contains the configuration for Engine API:
// POST "/images/prune"
type ContainersPruneConfig struct {
}
// VolumesPruneConfig contains the configuration for Engine API:
// POST "/images/prune"
type VolumesPruneConfig struct {
}
// NetworksPruneConfig contains the configuration for Engine API:
// POST "/networks/prune"
type NetworksPruneConfig struct {
}
// ContainersPruneReport contains the response for Engine API:
// POST "/containers/prune"
type ContainersPruneReport struct {

View File

@ -125,7 +125,7 @@ func NewBuilder(clientCtx context.Context, config *types.ImageBuildOptions, back
config = new(types.ImageBuildOptions)
}
if config.BuildArgs == nil {
config.BuildArgs = make(map[string]string)
config.BuildArgs = make(map[string]*string)
}
ctx, cancel := context.WithCancel(clientCtx)
b = &Builder{

View File

@ -384,8 +384,8 @@ func run(b *Builder, args []string, attributes map[string]bool, original string)
// the entire file (see 'leftoverArgs' processing in evaluator.go )
continue
}
if _, ok := configEnv[key]; !ok {
cmdBuildEnv = append(cmdBuildEnv, fmt.Sprintf("%s=%s", key, val))
if _, ok := configEnv[key]; !ok && val != nil {
cmdBuildEnv = append(cmdBuildEnv, fmt.Sprintf("%s=%s", key, *val))
}
}
@ -728,7 +728,7 @@ func arg(b *Builder, args []string, attributes map[string]bool, original string)
var (
name string
value string
newValue string
hasDefault bool
)
@ -745,7 +745,7 @@ func arg(b *Builder, args []string, attributes map[string]bool, original string)
}
name = parts[0]
value = parts[1]
newValue = parts[1]
hasDefault = true
} else {
name = arg
@ -756,9 +756,12 @@ func arg(b *Builder, args []string, attributes map[string]bool, original string)
// If there is a default value associated with this arg then add it to the
// b.buildArgs if one is not already passed to the builder. The args passed
// to builder override the default value of 'arg'.
if _, ok := b.options.BuildArgs[name]; !ok && hasDefault {
b.options.BuildArgs[name] = value
// to builder override the default value of 'arg'. Note that a 'nil' for
// a value means that the user specified "--build-arg FOO" and "FOO" wasn't
// defined as an env var - and in that case we DO want to use the default
// value specified in the ARG cmd.
if baValue, ok := b.options.BuildArgs[name]; (!ok || baValue == nil) && hasDefault {
b.options.BuildArgs[name] = &newValue
}
return b.commit("", b.runConfig.Cmd, fmt.Sprintf("ARG %s", arg))

View File

@ -460,7 +460,7 @@ func TestStopSignal(t *testing.T) {
}
func TestArg(t *testing.T) {
buildOptions := &types.ImageBuildOptions{BuildArgs: make(map[string]string)}
buildOptions := &types.ImageBuildOptions{BuildArgs: make(map[string]*string)}
b := &Builder{flags: &BFlags{}, runConfig: &container.Config{}, disableCommit: true, allowedBuildArgs: make(map[string]bool), options: buildOptions}
@ -488,7 +488,7 @@ func TestArg(t *testing.T) {
t.Fatalf("%s argument should be a build arg", argName)
}
if val != "bar" {
if *val != "bar" {
t.Fatalf("%s argument should have default value 'bar', got %s", argName, val)
}
}

View File

@ -158,7 +158,7 @@ func (b *Builder) dispatch(stepN int, stepTotal int, ast *parser.Node) error {
// the entire file (see 'leftoverArgs' processing in evaluator.go )
continue
}
envs = append(envs, fmt.Sprintf("%s=%s", key, val))
envs = append(envs, fmt.Sprintf("%s=%s", key, *val))
}
for ast.Next != nil {
ast = ast.Next

View File

@ -1,6 +1,8 @@
package checkpoint
import (
"fmt"
"golang.org/x/net/context"
"github.com/docker/docker/api/types"
@ -51,5 +53,6 @@ func runCreate(dockerCli *command.DockerCli, opts createOptions) error {
return err
}
fmt.Fprintf(dockerCli.Out(), "%s\n", opts.checkpoint)
return nil
}

View File

@ -10,6 +10,7 @@ import (
"runtime"
"github.com/docker/docker/api"
"github.com/docker/docker/api/types"
"github.com/docker/docker/api/types/versions"
cliflags "github.com/docker/docker/cli/flags"
"github.com/docker/docker/cliconfig"
@ -86,15 +87,55 @@ func (cli *DockerCli) ConfigFile() *configfile.ConfigFile {
return cli.configFile
}
// GetAllCredentials returns all of the credentials stored in all of the
// configured credential stores.
func (cli *DockerCli) GetAllCredentials() (map[string]types.AuthConfig, error) {
auths := make(map[string]types.AuthConfig)
for registry := range cli.configFile.CredentialHelpers {
helper := cli.CredentialsStore(registry)
newAuths, err := helper.GetAll()
if err != nil {
return nil, err
}
addAll(auths, newAuths)
}
defaultStore := cli.CredentialsStore("")
newAuths, err := defaultStore.GetAll()
if err != nil {
return nil, err
}
addAll(auths, newAuths)
return auths, nil
}
func addAll(to, from map[string]types.AuthConfig) {
for reg, ac := range from {
to[reg] = ac
}
}
// CredentialsStore returns a new credentials store based
// on the settings provided in the configuration file.
func (cli *DockerCli) CredentialsStore() credentials.Store {
if cli.configFile.CredentialsStore != "" {
return credentials.NewNativeStore(cli.configFile)
// on the settings provided in the configuration file. Empty string returns
// the default credential store.
func (cli *DockerCli) CredentialsStore(serverAddress string) credentials.Store {
if helper := getConfiguredCredentialStore(cli.configFile, serverAddress); helper != "" {
return credentials.NewNativeStore(cli.configFile, helper)
}
return credentials.NewFileStore(cli.configFile)
}
// getConfiguredCredentialStore returns the credential helper configured for the
// given registry, the default credsStore, or the empty string if neither are
// configured.
func getConfiguredCredentialStore(c *configfile.ConfigFile, serverAddress string) string {
if c.CredentialHelpers != nil && serverAddress != "" {
if helper, exists := c.CredentialHelpers[serverAddress]; exists {
return helper
}
}
return c.CredentialsStore
}
// Initialize the dockerCli runs initialization that must happen after command
// line flags are parsed.
func (cli *DockerCli) Initialize(opts *cliflags.ClientOptions) error {

View File

@ -5,7 +5,7 @@ import (
"golang.org/x/net/context"
"github.com/docker/docker/api/types"
"github.com/docker/docker/api/types/filters"
"github.com/docker/docker/cli"
"github.com/docker/docker/cli/command"
units "github.com/docker/go-units"
@ -52,7 +52,7 @@ func runPrune(dockerCli *command.DockerCli, opts pruneOptions) (spaceReclaimed u
return
}
report, err := dockerCli.Client().ContainersPrune(context.Background(), types.ContainersPruneConfig{})
report, err := dockerCli.Client().ContainersPrune(context.Background(), filters.Args{})
if err != nil {
return
}

View File

@ -67,7 +67,7 @@ func NewBuildCommand(dockerCli *command.DockerCli) *cobra.Command {
ulimits := make(map[string]*units.Ulimit)
options := buildOptions{
tags: opts.NewListOpts(validateTag),
buildArgs: opts.NewListOpts(runconfigopts.ValidateArg),
buildArgs: opts.NewListOpts(runconfigopts.ValidateEnv),
ulimits: runconfigopts.NewUlimitOpt(&ulimits),
labels: opts.NewListOpts(runconfigopts.ValidateEnv),
}
@ -107,7 +107,7 @@ func NewBuildCommand(dockerCli *command.DockerCli) *cobra.Command {
flags.StringSliceVar(&options.cacheFrom, "cache-from", []string{}, "Images to consider as cache sources")
flags.BoolVar(&options.compress, "compress", false, "Compress the build context using gzip")
flags.StringSliceVar(&options.securityOpt, "security-opt", []string{}, "Security options")
flags.StringVar(&options.networkMode, "network", "default", "Connect a container to a network")
flags.StringVar(&options.networkMode, "network", "default", "Set the networking mode for the RUN instructions during build")
command.AddTrustedFlags(flags, true)
@ -280,7 +280,7 @@ func runBuild(dockerCli *command.DockerCli, options buildOptions) error {
}
}
authConfig, _ := dockerCli.CredentialsStore().GetAll()
authConfigs, _ := dockerCli.GetAllCredentials()
buildOptions := types.ImageBuildOptions{
Memory: memory,
MemorySwap: memorySwap,
@ -300,8 +300,8 @@ func runBuild(dockerCli *command.DockerCli, options buildOptions) error {
Dockerfile: relDockerfile,
ShmSize: shmSize,
Ulimits: options.ulimits.GetList(),
BuildArgs: runconfigopts.ConvertKVStringsToMap(options.buildArgs.GetAll()),
AuthConfigs: authConfig,
BuildArgs: runconfigopts.ConvertKVStringsToMapWithNil(options.buildArgs.GetAll()),
AuthConfigs: authConfigs,
Labels: runconfigopts.ConvertKVStringsToMap(options.labels.GetAll()),
CacheFrom: options.cacheFrom,
SecurityOpt: options.securityOpt,

View File

@ -5,7 +5,7 @@ import (
"golang.org/x/net/context"
"github.com/docker/docker/api/types"
"github.com/docker/docker/api/types/filters"
"github.com/docker/docker/cli"
"github.com/docker/docker/cli/command"
units "github.com/docker/go-units"
@ -54,6 +54,9 @@ Are you sure you want to continue?`
)
func runPrune(dockerCli *command.DockerCli, opts pruneOptions) (spaceReclaimed uint64, output string, err error) {
pruneFilters := filters.NewArgs()
pruneFilters.Add("dangling", fmt.Sprintf("%v", !opts.all))
warning := danglingWarning
if opts.all {
warning = allImageWarning
@ -62,9 +65,7 @@ func runPrune(dockerCli *command.DockerCli, opts pruneOptions) (spaceReclaimed u
return
}
report, err := dockerCli.Client().ImagesPrune(context.Background(), types.ImagesPruneConfig{
DanglingOnly: !opts.all,
})
report, err := dockerCli.Client().ImagesPrune(context.Background(), pruneFilters)
if err != nil {
return
}

View File

@ -5,7 +5,7 @@ import (
"golang.org/x/net/context"
"github.com/docker/docker/api/types"
"github.com/docker/docker/api/types/filters"
"github.com/docker/docker/cli"
"github.com/docker/docker/cli/command"
"github.com/spf13/cobra"
@ -50,7 +50,7 @@ func runPrune(dockerCli *command.DockerCli, opts pruneOptions) (output string, e
return
}
report, err := dockerCli.Client().NetworksPrune(context.Background(), types.NetworksPruneConfig{})
report, err := dockerCli.Client().NetworksPrune(context.Background(), filters.Args{})
if err != nil {
return
}

View File

@ -67,7 +67,7 @@ func ResolveAuthConfig(ctx context.Context, cli *DockerCli, index *registrytypes
configKey = ElectAuthServer(ctx, cli)
}
a, _ := cli.CredentialsStore().Get(configKey)
a, _ := cli.CredentialsStore(configKey).Get(configKey)
return a
}
@ -82,7 +82,7 @@ func ConfigureAuth(cli *DockerCli, flUser, flPassword, serverAddress string, isD
serverAddress = registry.ConvertToHostname(serverAddress)
}
authconfig, err := cli.CredentialsStore().Get(serverAddress)
authconfig, err := cli.CredentialsStore(serverAddress).Get(serverAddress)
if err != nil {
return authconfig, err
}

View File

@ -74,7 +74,7 @@ func runLogin(dockerCli *command.DockerCli, opts loginOptions) error {
authConfig.Password = ""
authConfig.IdentityToken = response.IdentityToken
}
if err := dockerCli.CredentialsStore().Store(authConfig); err != nil {
if err := dockerCli.CredentialsStore(serverAddress).Store(authConfig); err != nil {
return fmt.Errorf("Error saving credentials: %v", err)
}

View File

@ -68,7 +68,7 @@ func runLogout(dockerCli *command.DockerCli, serverAddress string) error {
fmt.Fprintf(dockerCli.Out(), "Removing login credentials for %s\n", hostnameAddress)
for _, r := range regsToLogout {
if err := dockerCli.CredentialsStore().Erase(r); err != nil {
if err := dockerCli.CredentialsStore(r).Erase(r); err != nil {
fmt.Fprintf(dockerCli.Err(), "WARNING: could not erase credentials: %v\n", err)
}
}

View File

@ -1,6 +1,9 @@
package secret
import (
"fmt"
"strings"
"github.com/docker/docker/api/types"
"github.com/docker/docker/api/types/filters"
"github.com/docker/docker/api/types/swarm"
@ -8,10 +11,11 @@ import (
"golang.org/x/net/context"
)
func getSecretsByName(ctx context.Context, client client.APIClient, names []string) ([]swarm.Secret, error) {
func getSecretsByNameOrIDPrefixes(ctx context.Context, client client.APIClient, terms []string) ([]swarm.Secret, error) {
args := filters.NewArgs()
for _, n := range names {
for _, n := range terms {
args.Add("names", n)
args.Add("id", n)
}
return client.SecretList(ctx, types.SecretListOptions{
@ -19,29 +23,53 @@ func getSecretsByName(ctx context.Context, client client.APIClient, names []stri
})
}
func getCliRequestedSecretIDs(ctx context.Context, client client.APIClient, names []string) ([]string, error) {
ids := names
// attempt to lookup secret by name
secrets, err := getSecretsByName(ctx, client, ids)
func getCliRequestedSecretIDs(ctx context.Context, client client.APIClient, terms []string) ([]string, error) {
secrets, err := getSecretsByNameOrIDPrefixes(ctx, client, terms)
if err != nil {
return nil, err
}
lookup := make(map[string]struct{})
for _, id := range ids {
lookup[id] = struct{}{}
}
if len(secrets) > 0 {
ids = []string{}
for _, s := range secrets {
if _, ok := lookup[s.Spec.Annotations.Name]; ok {
ids = append(ids, s.ID)
found := make(map[string]struct{})
next:
for _, term := range terms {
// attempt to lookup secret by full ID
for _, s := range secrets {
if s.ID == term {
found[s.ID] = struct{}{}
continue next
}
}
// attempt to lookup secret by full name
for _, s := range secrets {
if s.Spec.Annotations.Name == term {
found[s.ID] = struct{}{}
continue next
}
}
// attempt to lookup secret by partial ID (prefix)
// return error if more than one matches found (ambiguous)
n := 0
for _, s := range secrets {
if strings.HasPrefix(s.ID, term) {
found[s.ID] = struct{}{}
n++
}
}
if n > 1 {
return nil, fmt.Errorf("secret %s is ambiguous (%d matches found)", term, n)
}
}
// We already collected all the IDs found.
// Now we will remove duplicates by converting the map to slice
ids := []string{}
for id := range found {
ids = append(ids, id)
}
return ids, nil
}
return ids, nil
return terms, nil
}

View File

@ -567,6 +567,14 @@ func convertService(
return swarm.ServiceSpec{}, err
}
var logDriver *swarm.Driver
if service.Logging != nil {
logDriver = &swarm.Driver{
Name: service.Logging.Driver,
Options: service.Logging.Options,
}
}
serviceSpec := swarm.ServiceSpec{
Annotations: swarm.Annotations{
Name: name,
@ -589,6 +597,7 @@ func convertService(
TTY: service.Tty,
OpenStdin: service.StdinOpen,
},
LogDriver: logDriver,
Resources: resources,
RestartPolicy: restartPolicy,
Placement: &swarm.Placement{

View File

@ -14,11 +14,12 @@ import (
"github.com/docker/docker/api/types/swarm"
"github.com/docker/docker/cli/command"
"github.com/docker/docker/cli/command/idresolver"
"github.com/docker/docker/pkg/stringid"
"github.com/docker/go-units"
)
const (
psTaskItemFmt = "%s\t%s\t%s\t%s\t%s %s ago\t%s\t%s\n"
psTaskItemFmt = "%s\t%s\t%s\t%s\t%s\t%s %s ago\t%s\t%s\n"
maxErrLength = 30
)
@ -67,7 +68,7 @@ func Print(dockerCli *command.DockerCli, ctx context.Context, tasks []swarm.Task
// Ignore flushing errors
defer writer.Flush()
fmt.Fprintln(writer, strings.Join([]string{"NAME", "IMAGE", "NODE", "DESIRED STATE", "CURRENT STATE", "ERROR", "PORTS"}, "\t"))
fmt.Fprintln(writer, strings.Join([]string{"ID", "NAME", "IMAGE", "NODE", "DESIRED STATE", "CURRENT STATE", "ERROR", "PORTS"}, "\t"))
if err := print(writer, ctx, tasks, resolver, noTrunc); err != nil {
return err
@ -90,25 +91,36 @@ func PrintQuiet(dockerCli *command.DockerCli, tasks []swarm.Task) error {
}
func print(out io.Writer, ctx context.Context, tasks []swarm.Task, resolver *idresolver.IDResolver, noTrunc bool) error {
prevService := ""
prevSlot := 0
prevName := ""
for _, task := range tasks {
name, err := resolver.Resolve(ctx, task, task.ID)
id := task.ID
if !noTrunc {
id = stringid.TruncateID(id)
}
serviceName, err := resolver.Resolve(ctx, swarm.Service{}, task.ServiceID)
if err != nil {
return err
}
nodeValue, err := resolver.Resolve(ctx, swarm.Node{}, task.NodeID)
if err != nil {
return err
}
name := ""
if task.Slot != 0 {
name = fmt.Sprintf("%v.%v", serviceName, task.Slot)
} else {
name = fmt.Sprintf("%v.%v", serviceName, task.NodeID)
}
// Indent the name if necessary
indentedName := name
// Since the new format of the task name is <ServiceName>.<Slot>.<taskID>, we should only compare
// <ServiceName> and <Slot> here.
if prevService == task.ServiceID && prevSlot == task.Slot {
if name == prevName {
indentedName = fmt.Sprintf(" \\_ %s", indentedName)
}
prevService = task.ServiceID
prevSlot = task.Slot
prevName = name
// Trim and quote the error message.
taskErr := task.Status.Err
@ -134,6 +146,7 @@ func print(out io.Writer, ctx context.Context, tasks []swarm.Task, resolver *idr
fmt.Fprintf(
out,
psTaskItemFmt,
id,
indentedName,
image,
nodeValue,

View File

@ -6,6 +6,7 @@ import (
"io/ioutil"
"os"
"path/filepath"
"runtime"
"strings"
)
@ -71,6 +72,11 @@ func PromptForConfirmation(ins *InStream, outs *OutStream, message string) bool
fmt.Fprintf(outs, message)
// On Windows, force the use of the regular OS stdin stream.
if runtime.GOOS == "windows" {
ins = NewInStream(os.Stdin)
}
answer := ""
n, _ := fmt.Fscan(ins, &answer)
if n != 1 || (answer != "y" && answer != "Y") {

View File

@ -5,7 +5,7 @@ import (
"golang.org/x/net/context"
"github.com/docker/docker/api/types"
"github.com/docker/docker/api/types/filters"
"github.com/docker/docker/cli"
"github.com/docker/docker/cli/command"
units "github.com/docker/go-units"
@ -52,7 +52,7 @@ func runPrune(dockerCli *command.DockerCli, opts pruneOptions) (spaceReclaimed u
return
}
report, err := dockerCli.Client().VolumesPrune(context.Background(), types.VolumesPruneConfig{})
report, err := dockerCli.Client().VolumesPrune(context.Background(), filters.Args{})
if err != nil {
return
}

View File

@ -86,7 +86,7 @@ func TestEmptyFile(t *testing.T) {
}
}
func TestEmptyJson(t *testing.T) {
func TestEmptyJSON(t *testing.T) {
tmpHome, err := ioutil.TempDir("", "config-test")
if err != nil {
t.Fatal(err)
@ -193,7 +193,7 @@ func TestOldValidAuth(t *testing.T) {
}
}
func TestOldJsonInvalid(t *testing.T) {
func TestOldJSONInvalid(t *testing.T) {
tmpHome, err := ioutil.TempDir("", "config-test")
if err != nil {
t.Fatal(err)
@ -219,7 +219,7 @@ func TestOldJsonInvalid(t *testing.T) {
}
}
func TestOldJson(t *testing.T) {
func TestOldJSON(t *testing.T) {
tmpHome, err := ioutil.TempDir("", "config-test")
if err != nil {
t.Fatal(err)
@ -265,7 +265,7 @@ func TestOldJson(t *testing.T) {
}
}
func TestNewJson(t *testing.T) {
func TestNewJSON(t *testing.T) {
tmpHome, err := ioutil.TempDir("", "config-test")
if err != nil {
t.Fatal(err)
@ -304,7 +304,7 @@ func TestNewJson(t *testing.T) {
}
}
func TestNewJsonNoEmail(t *testing.T) {
func TestNewJSONNoEmail(t *testing.T) {
tmpHome, err := ioutil.TempDir("", "config-test")
if err != nil {
t.Fatal(err)
@ -343,7 +343,7 @@ func TestNewJsonNoEmail(t *testing.T) {
}
}
func TestJsonWithPsFormat(t *testing.T) {
func TestJSONWithPsFormat(t *testing.T) {
tmpHome, err := ioutil.TempDir("", "config-test")
if err != nil {
t.Fatal(err)
@ -376,6 +376,78 @@ func TestJsonWithPsFormat(t *testing.T) {
}
}
func TestJSONWithCredentialStore(t *testing.T) {
tmpHome, err := ioutil.TempDir("", "config-test")
if err != nil {
t.Fatal(err)
}
defer os.RemoveAll(tmpHome)
fn := filepath.Join(tmpHome, ConfigFileName)
js := `{
"auths": { "https://index.docker.io/v1/": { "auth": "am9lam9lOmhlbGxv", "email": "user@example.com" } },
"credsStore": "crazy-secure-storage"
}`
if err := ioutil.WriteFile(fn, []byte(js), 0600); err != nil {
t.Fatal(err)
}
config, err := Load(tmpHome)
if err != nil {
t.Fatalf("Failed loading on empty json file: %q", err)
}
if config.CredentialsStore != "crazy-secure-storage" {
t.Fatalf("Unknown credential store: %s\n", config.CredentialsStore)
}
// Now save it and make sure it shows up in new form
configStr := saveConfigAndValidateNewFormat(t, config, tmpHome)
if !strings.Contains(configStr, `"credsStore":`) ||
!strings.Contains(configStr, "crazy-secure-storage") {
t.Fatalf("Should have save in new form: %s", configStr)
}
}
func TestJSONWithCredentialHelpers(t *testing.T) {
tmpHome, err := ioutil.TempDir("", "config-test")
if err != nil {
t.Fatal(err)
}
defer os.RemoveAll(tmpHome)
fn := filepath.Join(tmpHome, ConfigFileName)
js := `{
"auths": { "https://index.docker.io/v1/": { "auth": "am9lam9lOmhlbGxv", "email": "user@example.com" } },
"credHelpers": { "images.io": "images-io", "containers.com": "crazy-secure-storage" }
}`
if err := ioutil.WriteFile(fn, []byte(js), 0600); err != nil {
t.Fatal(err)
}
config, err := Load(tmpHome)
if err != nil {
t.Fatalf("Failed loading on empty json file: %q", err)
}
if config.CredentialHelpers == nil {
t.Fatal("config.CredentialHelpers was nil")
} else if config.CredentialHelpers["images.io"] != "images-io" ||
config.CredentialHelpers["containers.com"] != "crazy-secure-storage" {
t.Fatalf("Credential helpers not deserialized properly: %v\n", config.CredentialHelpers)
}
// Now save it and make sure it shows up in new form
configStr := saveConfigAndValidateNewFormat(t, config, tmpHome)
if !strings.Contains(configStr, `"credHelpers":`) ||
!strings.Contains(configStr, "images.io") ||
!strings.Contains(configStr, "images-io") ||
!strings.Contains(configStr, "containers.com") ||
!strings.Contains(configStr, "crazy-secure-storage") {
t.Fatalf("Should have save in new form: %s", configStr)
}
}
// Save it and make sure it shows up in new form
func saveConfigAndValidateNewFormat(t *testing.T, config *configfile.ConfigFile, homeFolder string) string {
if err := config.Save(); err != nil {
@ -420,7 +492,7 @@ func TestConfigFile(t *testing.T) {
}
}
func TestJsonReaderNoFile(t *testing.T) {
func TestJSONReaderNoFile(t *testing.T) {
js := ` { "auths": { "https://index.docker.io/v1/": { "auth": "am9lam9lOmhlbGxv", "email": "user@example.com" } } }`
config, err := LoadFromReader(strings.NewReader(js))
@ -435,7 +507,7 @@ func TestJsonReaderNoFile(t *testing.T) {
}
func TestOldJsonReaderNoFile(t *testing.T) {
func TestOldJSONReaderNoFile(t *testing.T) {
js := `{"https://index.docker.io/v1/":{"auth":"am9lam9lOmhlbGxv","email":"user@example.com"}}`
config, err := LegacyLoadFromReader(strings.NewReader(js))
@ -449,7 +521,7 @@ func TestOldJsonReaderNoFile(t *testing.T) {
}
}
func TestJsonWithPsFormatNoFile(t *testing.T) {
func TestJSONWithPsFormatNoFile(t *testing.T) {
js := `{
"auths": { "https://index.docker.io/v1/": { "auth": "am9lam9lOmhlbGxv", "email": "user@example.com" } },
"psFormat": "table {{.ID}}\\t{{.Label \"com.docker.label.cpu\"}}"
@ -465,7 +537,7 @@ func TestJsonWithPsFormatNoFile(t *testing.T) {
}
func TestJsonSaveWithNoFile(t *testing.T) {
func TestJSONSaveWithNoFile(t *testing.T) {
js := `{
"auths": { "https://index.docker.io/v1/": { "auth": "am9lam9lOmhlbGxv" } },
"psFormat": "table {{.ID}}\\t{{.Label \"com.docker.label.cpu\"}}"
@ -507,7 +579,7 @@ func TestJsonSaveWithNoFile(t *testing.T) {
}
}
func TestLegacyJsonSaveWithNoFile(t *testing.T) {
func TestLegacyJSONSaveWithNoFile(t *testing.T) {
js := `{"https://index.docker.io/v1/":{"auth":"am9lam9lOmhlbGxv","email":"user@example.com"}}`
config, err := LegacyLoadFromReader(strings.NewReader(js))

View File

@ -31,6 +31,7 @@ type ConfigFile struct {
StatsFormat string `json:"statsFormat,omitempty"`
DetachKeys string `json:"detachKeys,omitempty"`
CredentialsStore string `json:"credsStore,omitempty"`
CredentialHelpers map[string]string `json:"credHelpers,omitempty"`
Filename string `json:"-"` // Note: for internal use only
ServiceInspectFormat string `json:"serviceInspectFormat,omitempty"`
}
@ -96,7 +97,8 @@ func (configFile *ConfigFile) LoadFromReader(configData io.Reader) error {
// in this file or not.
func (configFile *ConfigFile) ContainsAuth() bool {
return configFile.CredentialsStore != "" ||
(configFile.AuthConfigs != nil && len(configFile.AuthConfigs) > 0)
len(configFile.CredentialHelpers) > 0 ||
len(configFile.AuthConfigs) > 0
}
// SaveToWriter encodes and writes out all the authorization information to

View File

@ -22,8 +22,8 @@ type nativeStore struct {
// NewNativeStore creates a new native store that
// uses a remote helper program to manage credentials.
func NewNativeStore(file *configfile.ConfigFile) Store {
name := remoteCredentialsPrefix + file.CredentialsStore
func NewNativeStore(file *configfile.ConfigFile, helperSuffix string) Store {
name := remoteCredentialsPrefix + helperSuffix
return &nativeStore{
programFunc: client.NewShellProgramFunc(name),
fileStore: NewFileStore(file),

View File

@ -78,10 +78,10 @@ func TestContainerStatPath(t *testing.T) {
t.Fatal(err)
}
if stat.Name != "name" {
t.Fatalf("expected container path stat name to be 'name', was '%s'", stat.Name)
t.Fatalf("expected container path stat name to be 'name', got '%s'", stat.Name)
}
if stat.Mode != 0700 {
t.Fatalf("expected container path stat mode to be 0700, was '%v'", stat.Mode)
t.Fatalf("expected container path stat mode to be 0700, got '%v'", stat.Mode)
}
}
@ -226,10 +226,10 @@ func TestCopyFromContainer(t *testing.T) {
t.Fatal(err)
}
if stat.Name != "name" {
t.Fatalf("expected container path stat name to be 'name', was '%s'", stat.Name)
t.Fatalf("expected container path stat name to be 'name', got '%s'", stat.Name)
}
if stat.Mode != 0700 {
t.Fatalf("expected container path stat mode to be 0700, was '%v'", stat.Mode)
t.Fatalf("expected container path stat mode to be 0700, got '%v'", stat.Mode)
}
content, err := ioutil.ReadAll(r)
if err != nil {

View File

@ -5,18 +5,24 @@ import (
"fmt"
"github.com/docker/docker/api/types"
"github.com/docker/docker/api/types/filters"
"golang.org/x/net/context"
)
// ContainersPrune requests the daemon to delete unused data
func (cli *Client) ContainersPrune(ctx context.Context, cfg types.ContainersPruneConfig) (types.ContainersPruneReport, error) {
func (cli *Client) ContainersPrune(ctx context.Context, pruneFilters filters.Args) (types.ContainersPruneReport, error) {
var report types.ContainersPruneReport
if err := cli.NewVersionError("1.25", "container prune"); err != nil {
return report, err
}
serverResp, err := cli.post(ctx, "/containers/prune", nil, cfg, nil)
query, err := getFiltersQuery(pruneFilters)
if err != nil {
return report, err
}
serverResp, err := cli.post(ctx, "/containers/prune", query, nil, nil)
if err != nil {
return report, err
}

View File

@ -27,6 +27,8 @@ func TestImageBuildError(t *testing.T) {
}
func TestImageBuild(t *testing.T) {
v1 := "value1"
v2 := "value2"
emptyRegistryConfig := "bnVsbA=="
buildCases := []struct {
buildOptions types.ImageBuildOptions
@ -105,13 +107,14 @@ func TestImageBuild(t *testing.T) {
},
{
buildOptions: types.ImageBuildOptions{
BuildArgs: map[string]string{
"ARG1": "value1",
"ARG2": "value2",
BuildArgs: map[string]*string{
"ARG1": &v1,
"ARG2": &v2,
"ARG3": nil,
},
},
expectedQueryParams: map[string]string{
"buildargs": `{"ARG1":"value1","ARG2":"value2"}`,
"buildargs": `{"ARG1":"value1","ARG2":"value2","ARG3":null}`,
"rm": "0",
},
expectedTags: []string{},

View File

@ -5,18 +5,24 @@ import (
"fmt"
"github.com/docker/docker/api/types"
"github.com/docker/docker/api/types/filters"
"golang.org/x/net/context"
)
// ImagesPrune requests the daemon to delete unused data
func (cli *Client) ImagesPrune(ctx context.Context, cfg types.ImagesPruneConfig) (types.ImagesPruneReport, error) {
func (cli *Client) ImagesPrune(ctx context.Context, pruneFilters filters.Args) (types.ImagesPruneReport, error) {
var report types.ImagesPruneReport
if err := cli.NewVersionError("1.25", "image prune"); err != nil {
return report, err
}
serverResp, err := cli.post(ctx, "/images/prune", nil, cfg, nil)
query, err := getFiltersQuery(pruneFilters)
if err != nil {
return report, err
}
serverResp, err := cli.post(ctx, "/images/prune", query, nil, nil)
if err != nil {
return report, err
}

View File

@ -81,12 +81,12 @@ func TestImageSearchWithPrivilegedFuncNoError(t *testing.T) {
}, nil
}
if auth != "IAmValid" {
return nil, fmt.Errorf("Invalid auth header : expected %s, got %s", "IAmValid", auth)
return nil, fmt.Errorf("Invalid auth header : expected 'IAmValid', got %s", auth)
}
query := req.URL.Query()
term := query.Get("term")
if term != "some-image" {
return nil, fmt.Errorf("tag not set in URL query properly. Expected '%s', got %s", "some-image", term)
return nil, fmt.Errorf("term not set in URL query properly. Expected 'some-image', got %s", term)
}
content, err := json.Marshal([]registry.SearchResult{
{
@ -113,7 +113,7 @@ func TestImageSearchWithPrivilegedFuncNoError(t *testing.T) {
t.Fatal(err)
}
if len(results) != 1 {
t.Fatalf("expected a result, got %v", results)
t.Fatalf("expected 1 result, got %v", results)
}
}
@ -133,7 +133,7 @@ func TestImageSearchWithoutErrors(t *testing.T) {
query := req.URL.Query()
term := query.Get("term")
if term != "some-image" {
return nil, fmt.Errorf("tag not set in URL query properly. Expected '%s', got %s", "some-image", term)
return nil, fmt.Errorf("term not set in URL query properly. Expected 'some-image', got %s", term)
}
filters := query.Get("filters")
if filters != expectedFilters {

View File

@ -64,7 +64,7 @@ type ContainerAPIClient interface {
ContainerWait(ctx context.Context, container string) (int64, error)
CopyFromContainer(ctx context.Context, container, srcPath string) (io.ReadCloser, types.ContainerPathStat, error)
CopyToContainer(ctx context.Context, container, path string, content io.Reader, options types.CopyToContainerOptions) error
ContainersPrune(ctx context.Context, cfg types.ContainersPruneConfig) (types.ContainersPruneReport, error)
ContainersPrune(ctx context.Context, pruneFilters filters.Args) (types.ContainersPruneReport, error)
}
// ImageAPIClient defines API client methods for the images
@ -82,7 +82,7 @@ type ImageAPIClient interface {
ImageSearch(ctx context.Context, term string, options types.ImageSearchOptions) ([]registry.SearchResult, error)
ImageSave(ctx context.Context, images []string) (io.ReadCloser, error)
ImageTag(ctx context.Context, image, ref string) error
ImagesPrune(ctx context.Context, cfg types.ImagesPruneConfig) (types.ImagesPruneReport, error)
ImagesPrune(ctx context.Context, pruneFilter filters.Args) (types.ImagesPruneReport, error)
}
// NetworkAPIClient defines API client methods for the networks
@ -94,7 +94,7 @@ type NetworkAPIClient interface {
NetworkInspectWithRaw(ctx context.Context, networkID string) (types.NetworkResource, []byte, error)
NetworkList(ctx context.Context, options types.NetworkListOptions) ([]types.NetworkResource, error)
NetworkRemove(ctx context.Context, networkID string) error
NetworksPrune(ctx context.Context, cfg types.NetworksPruneConfig) (types.NetworksPruneReport, error)
NetworksPrune(ctx context.Context, pruneFilter filters.Args) (types.NetworksPruneReport, error)
}
// NodeAPIClient defines API client methods for the nodes
@ -157,7 +157,7 @@ type VolumeAPIClient interface {
VolumeInspectWithRaw(ctx context.Context, volumeID string) (types.Volume, []byte, error)
VolumeList(ctx context.Context, filter filters.Args) (volumetypes.VolumesListOKBody, error)
VolumeRemove(ctx context.Context, volumeID string, force bool) error
VolumesPrune(ctx context.Context, cfg types.VolumesPruneConfig) (types.VolumesPruneReport, error)
VolumesPrune(ctx context.Context, pruneFilter filters.Args) (types.VolumesPruneReport, error)
}
// SecretAPIClient defines API client methods for secrets

View File

@ -5,14 +5,24 @@ import (
"fmt"
"github.com/docker/docker/api/types"
"github.com/docker/docker/api/types/filters"
"golang.org/x/net/context"
)
// NetworksPrune requests the daemon to delete unused networks
func (cli *Client) NetworksPrune(ctx context.Context, cfg types.NetworksPruneConfig) (types.NetworksPruneReport, error) {
func (cli *Client) NetworksPrune(ctx context.Context, pruneFilters filters.Args) (types.NetworksPruneReport, error) {
var report types.NetworksPruneReport
serverResp, err := cli.post(ctx, "/networks/prune", nil, cfg, nil)
if err := cli.NewVersionError("1.25", "network prune"); err != nil {
return report, err
}
query, err := getFiltersQuery(pruneFilters)
if err != nil {
return report, err
}
serverResp, err := cli.post(ctx, "/networks/prune", query, nil, nil)
if err != nil {
return report, err
}

View File

@ -12,7 +12,7 @@ import (
// PluginInspectWithRaw inspects an existing plugin
func (cli *Client) PluginInspectWithRaw(ctx context.Context, name string) (*types.Plugin, []byte, error) {
resp, err := cli.get(ctx, "/plugins/"+name, nil, nil)
resp, err := cli.get(ctx, "/plugins/"+name+"/json", nil, nil)
if err != nil {
if resp.statusCode == http.StatusNotFound {
return nil, nil, pluginNotFoundError{name}

View File

@ -14,27 +14,21 @@ func (cli *Client) PluginInstall(ctx context.Context, name string, options types
// FIXME(vdemeester) name is a ref, we might want to parse/validate it here.
query := url.Values{}
query.Set("name", name)
resp, err := cli.tryPluginPull(ctx, query, options.RegistryAuth)
resp, err := cli.tryPluginPrivileges(ctx, query, options.RegistryAuth)
if resp.statusCode == http.StatusUnauthorized && options.PrivilegeFunc != nil {
newAuthHeader, privilegeErr := options.PrivilegeFunc()
if privilegeErr != nil {
ensureReaderClosed(resp)
return privilegeErr
}
resp, err = cli.tryPluginPull(ctx, query, newAuthHeader)
options.RegistryAuth = newAuthHeader
resp, err = cli.tryPluginPrivileges(ctx, query, options.RegistryAuth)
}
if err != nil {
ensureReaderClosed(resp)
return err
}
defer func() {
if err != nil {
delResp, _ := cli.delete(ctx, "/plugins/"+name, nil, nil)
ensureReaderClosed(delResp)
}
}()
var privileges types.PluginPrivileges
if err := json.NewDecoder(resp.body).Decode(&privileges); err != nil {
ensureReaderClosed(resp)
@ -52,6 +46,18 @@ func (cli *Client) PluginInstall(ctx context.Context, name string, options types
}
}
_, err = cli.tryPluginPull(ctx, query, privileges, options.RegistryAuth)
if err != nil {
return err
}
defer func() {
if err != nil {
delResp, _ := cli.delete(ctx, "/plugins/"+name, nil, nil)
ensureReaderClosed(delResp)
}
}()
if len(options.Args) > 0 {
if err := cli.PluginSet(ctx, name, options.Args); err != nil {
return err
@ -65,7 +71,12 @@ func (cli *Client) PluginInstall(ctx context.Context, name string, options types
return cli.PluginEnable(ctx, name, types.PluginEnableOptions{Timeout: 0})
}
func (cli *Client) tryPluginPull(ctx context.Context, query url.Values, registryAuth string) (serverResponse, error) {
func (cli *Client) tryPluginPrivileges(ctx context.Context, query url.Values, registryAuth string) (serverResponse, error) {
headers := map[string][]string{"X-Registry-Auth": {registryAuth}}
return cli.post(ctx, "/plugins/pull", query, nil, headers)
return cli.get(ctx, "/plugins/privileges", query, headers)
}
func (cli *Client) tryPluginPull(ctx context.Context, query url.Values, privileges types.PluginPrivileges, registryAuth string) (serverResponse, error) {
headers := map[string][]string{"X-Registry-Auth": {registryAuth}}
return cli.post(ctx, "/plugins/pull", query, privileges, headers)
}

View File

@ -35,7 +35,7 @@ func TestPluginPush(t *testing.T) {
}
auth := req.Header.Get("X-Registry-Auth")
if auth != "authtoken" {
return nil, fmt.Errorf("Invalid auth header : expected %s, got %s", "authtoken", auth)
return nil, fmt.Errorf("Invalid auth header : expected 'authtoken', got %s", auth)
}
return &http.Response{
StatusCode: http.StatusOK,

View File

@ -1,6 +1,10 @@
package client
import "regexp"
import (
"github.com/docker/docker/api/types/filters"
"net/url"
"regexp"
)
var headerRegexp = regexp.MustCompile(`\ADocker/.+\s\((.+)\)\z`)
@ -13,3 +17,17 @@ func getDockerOS(serverHeader string) string {
}
return osType
}
// getFiltersQuery returns a url query with "filters" query term, based on the
// filters provided.
func getFiltersQuery(f filters.Args) (url.Values, error) {
query := url.Values{}
if f.Len() > 0 {
filterJSON, err := filters.ToParam(f)
if err != nil {
return query, err
}
query.Set("filters", filterJSON)
}
return query, nil
}

View File

@ -5,18 +5,24 @@ import (
"fmt"
"github.com/docker/docker/api/types"
"github.com/docker/docker/api/types/filters"
"golang.org/x/net/context"
)
// VolumesPrune requests the daemon to delete unused data
func (cli *Client) VolumesPrune(ctx context.Context, cfg types.VolumesPruneConfig) (types.VolumesPruneReport, error) {
func (cli *Client) VolumesPrune(ctx context.Context, pruneFilters filters.Args) (types.VolumesPruneReport, error) {
var report types.VolumesPruneReport
if err := cli.NewVersionError("1.25", "volume prune"); err != nil {
return report, err
}
serverResp, err := cli.post(ctx, "/volumes/prune", nil, cfg, nil)
query, err := getFiltersQuery(pruneFilters)
if err != nil {
return report, err
}
serverResp, err := cli.post(ctx, "/volumes/prune", query, nil, nil)
if err != nil {
return report, err
}

View File

@ -224,7 +224,8 @@ echo 'Optional Features:'
}
{
if is_set LEGACY_VSYSCALL_NATIVE; then
echo -n "- "; wrap_good "CONFIG_LEGACY_VSYSCALL_NATIVE" 'enabled'
echo -n "- "; wrap_bad "CONFIG_LEGACY_VSYSCALL_NATIVE" 'enabled'
echo " $(wrap_color '(dangerous, provides an ASLR-bypassing target with usable ROP gadgets.)' bold black)"
elif is_set LEGACY_VSYSCALL_EMULATE; then
echo -n "- "; wrap_good "CONFIG_LEGACY_VSYSCALL_EMULATE" 'enabled'
elif is_set LEGACY_VSYSCALL_NONE; then

View File

@ -23,6 +23,7 @@
# DOCKER_COMPLETION_SHOW_CONTAINER_IDS
# DOCKER_COMPLETION_SHOW_NETWORK_IDS
# DOCKER_COMPLETION_SHOW_NODE_IDS
# DOCKER_COMPLETION_SHOW_SECRET_IDS
# DOCKER_COMPLETION_SHOW_SERVICE_IDS
# "no" - Show names only (default)
# "yes" - Show names and ids
@ -311,6 +312,22 @@ __docker_complete_runtimes() {
COMPREPLY=( $(compgen -W "$(__docker_runtimes)" -- "$cur") )
}
# __docker_secrets returns a list of all secrets.
# By default, only names of secrets are returned.
# Set DOCKER_COMPLETION_SHOW_SECRET_IDS=yes to also complete IDs of secrets.
__docker_secrets() {
local fields='$2' # default: name only
[ "${DOCKER_COMPLETION_SHOW_SECRET_IDS}" = yes ] && fields='$1,$2' # ID and name
__docker_q secret ls | awk "NR>1 {print $fields}"
}
# __docker_complete_secrets applies completion of secrets based on the current value
# of `$cur`.
__docker_complete_secrets() {
COMPREPLY=( $(compgen -W "$(__docker_secrets)" -- "$cur") )
}
# __docker_stacks returns a list of all stacks.
__docker_stacks() {
__docker_q stack ls | awk 'NR>1 {print $1}'
@ -2276,7 +2293,7 @@ _docker_inspect() {
;;
--type)
if [ -z "$preselected_type" ] ; then
COMPREPLY=( $( compgen -W "container image network node service volume" -- "$cur" ) )
COMPREPLY=( $( compgen -W "container image network node plugin service volume" -- "$cur" ) )
return
fi
;;
@ -2298,6 +2315,7 @@ _docker_inspect() {
$(__docker_images)
$(__docker_networks)
$(__docker_nodes)
$(__docker_plugins_installed)
$(__docker_services)
$(__docker_volumes)
" -- "$cur" ) )
@ -2314,6 +2332,9 @@ _docker_inspect() {
node)
__docker_complete_nodes
;;
plugin)
__docker_complete_plugins_installed
;;
service)
__docker_complete_services
;;
@ -2425,7 +2446,7 @@ _docker_network_create() {
case "$cur" in
-*)
COMPREPLY=( $( compgen -W "--aux-address --driver -d --gateway --help --internal --ip-range --ipam-driver --ipam-opt --ipv6 --label --opt -o --subnet" -- "$cur" ) )
COMPREPLY=( $( compgen -W "--attachable --aux-address --driver -d --gateway --help --internal --ip-range --ipam-driver --ipam-opt --ipv6 --label --opt -o --subnet" -- "$cur" ) )
;;
esac
}
@ -2736,6 +2757,7 @@ _docker_service_update() {
--mode
--name
--port
--secret
"
case "$prev" in
@ -2755,6 +2777,10 @@ _docker_service_update() {
COMPREPLY=( $( compgen -W "global replicated" -- "$cur" ) )
return
;;
--secret)
__docker_complete_secrets
return
;;
--group)
COMPREPLY=( $(compgen -g -- "$cur") )
return
@ -2779,6 +2805,8 @@ _docker_service_update() {
--image
--port-add
--port-rm
--secret-add
--secret-rm
"
case "$prev" in
@ -2802,6 +2830,10 @@ _docker_service_update() {
__docker_complete_image_repos_and_tags
return
;;
--secret-add|--secret-rm)
__docker_complete_secrets
return
;;
esac
fi
@ -2846,9 +2878,17 @@ _docker_service_update() {
COMPREPLY=( $( compgen -W "$boolean_options $options_with_args" -- "$cur" ) )
;;
*)
local counter=$( __docker_pos_first_nonflag $( __docker_to_alternatives "$options_with_args" ) )
if [ "$subcommand" = "update" ] ; then
__docker_complete_services
if [ $cword -eq $counter ]; then
__docker_complete_services
fi
else
if [ $cword -eq $counter ]; then
__docker_complete_images
fi
fi
;;
esac
}
@ -3329,6 +3369,90 @@ _docker_save() {
_docker_image_save
}
_docker_secret() {
local subcommands="
create
inspect
ls
rm
"
local aliases="
list
remove
"
__docker_subcommands "$subcommands $aliases" && return
case "$cur" in
-*)
COMPREPLY=( $( compgen -W "--help" -- "$cur" ) )
;;
*)
COMPREPLY=( $( compgen -W "$subcommands" -- "$cur" ) )
;;
esac
}
_docker_secret_create() {
case "$prev" in
--label|-l)
return
;;
esac
case "$cur" in
-*)
COMPREPLY=( $( compgen -W "--help --label -l" -- "$cur" ) )
;;
esac
}
_docker_secret_inspect() {
case "$prev" in
--format|-f)
return
;;
esac
case "$cur" in
-*)
COMPREPLY=( $( compgen -W "--format -f --help" -- "$cur" ) )
;;
*)
__docker_complete_secrets
;;
esac
}
_docker_secret_list() {
_docker_secret_ls
}
_docker_secret_ls() {
case "$cur" in
-*)
COMPREPLY=( $( compgen -W "--help --quiet -q" -- "$cur" ) )
;;
esac
}
_docker_secret_remove() {
case "$cur" in
-*)
COMPREPLY=( $( compgen -W "--help" -- "$cur" ) )
;;
*)
__docker_complete_secrets
;;
esac
}
_docker_secret_rm() {
_docker_secret_remove
}
_docker_search() {
local key=$(__docker_map_key_of_current_option '--filter|-f')
case "$key" in
@ -3690,9 +3814,15 @@ _docker_top() {
}
_docker_version() {
case "$prev" in
--format|-f)
return
;;
esac
case "$cur" in
-*)
COMPREPLY=( $( compgen -W "--help" -- "$cur" ) )
COMPREPLY=( $( compgen -W "--format -f --help" -- "$cur" ) )
;;
esac
}
@ -3852,6 +3982,7 @@ _docker() {
run
save
search
secret
service
stack
start

View File

@ -348,14 +348,14 @@ __docker_complete_ps_filters() {
__docker_complete_containers_names && ret=0
;;
(network)
__docker_networks && ret=0
__docker_complete_networks && ret=0
;;
(status)
status_opts=('created' 'dead' 'exited' 'paused' 'restarting' 'running' 'removing')
_describe -t status-filter-opts "status filter options" status_opts && ret=0
;;
(volume)
__docker_volumes && ret=0
__docker_complete_volumes && ret=0
;;
*)
_message 'value' && ret=0
@ -453,7 +453,7 @@ __docker_complete_events_filter() {
__docker_complete_images && ret=0
;;
(network)
__docker_networks && ret=0
__docker_complete_networks && ret=0
;;
(type)
local -a type_opts
@ -461,7 +461,7 @@ __docker_complete_events_filter() {
_describe -t type-filter-opts "type filter options" type_opts && ret=0
;;
(volume)
__docker_volumes && ret=0
__docker_complete_volumes && ret=0
;;
*)
_message 'value' && ret=0
@ -1033,10 +1033,10 @@ __docker_network_complete_ls_filters() {
__docker_complete_info_plugins Network && ret=0
;;
(id)
__docker_networks_ids && ret=0
__docker_complete_networks_ids && ret=0
;;
(name)
__docker_networks_names && ret=0
__docker_complete_networks_names && ret=0
;;
(type)
type_opts=('builtin' 'custom')
@ -1082,6 +1082,7 @@ __docker_get_networks() {
for line in $lines; do
s="${line[${begin[NETWORK ID]},${end[NETWORK ID]}]%% ##}"
s="$s:${(l:7:: :::)${${line[${begin[DRIVER]},${end[DRIVER]}]}%% ##}}"
s="$s, ${${line[${begin[SCOPE]},${end[SCOPE]}]}%% ##}"
networks=($networks $s)
done
fi
@ -1091,6 +1092,7 @@ __docker_get_networks() {
for line in $lines; do
s="${line[${begin[NAME]},${end[NAME]}]%% ##}"
s="$s:${(l:7:: :::)${${line[${begin[DRIVER]},${end[DRIVER]}]}%% ##}}"
s="$s, ${${line[${begin[SCOPE]},${end[SCOPE]}]}%% ##}"
networks=($networks $s)
done
fi
@ -1099,17 +1101,17 @@ __docker_get_networks() {
return ret
}
__docker_networks() {
__docker_complete_networks() {
[[ $PREFIX = -* ]] && return 1
__docker_get_networks all "$@"
}
__docker_networks_ids() {
__docker_complete_networks_ids() {
[[ $PREFIX = -* ]] && return 1
__docker_get_networks ids "$@"
}
__docker_networks_names() {
__docker_complete_networks_names() {
[[ $PREFIX = -* ]] && return 1
__docker_get_networks names "$@"
}
@ -1144,7 +1146,7 @@ __docker_network_subcommand() {
"($help)--ip6=[Container IPv6 address]:IPv6: " \
"($help)*--link=[Add a link to another container]:link:->link" \
"($help)*--link-local-ip=[Add a link-local address for the container]:IPv4/IPv6: " \
"($help -)1:network:__docker_networks" \
"($help -)1:network:__docker_complete_networks" \
"($help -)2:containers:__docker_complete_containers" && ret=0
case $state in
@ -1160,6 +1162,7 @@ __docker_network_subcommand() {
(create)
_arguments $(__docker_arguments) -A '-*' \
$opts_help \
"($help)--attachable[Enable manual container attachment]" \
"($help)*--aux-address[Auxiliary IPv4 or IPv6 addresses used by network driver]:key=IP: " \
"($help -d --driver)"{-d=,--driver=}"[Driver to manage the Network]:driver:(null host bridge overlay)" \
"($help)*--gateway=[IPv4 or IPv6 Gateway for the master subnet]:IP: " \
@ -1176,14 +1179,14 @@ __docker_network_subcommand() {
(disconnect)
_arguments $(__docker_arguments) \
$opts_help \
"($help -)1:network:__docker_networks" \
"($help -)1:network:__docker_complete_networks" \
"($help -)2:containers:__docker_complete_containers" && ret=0
;;
(inspect)
_arguments $(__docker_arguments) \
$opts_help \
"($help -f --format)"{-f=,--format=}"[Format the output using the given go template]:template: " \
"($help -)*:network:__docker_networks" && ret=0
"($help -)*:network:__docker_complete_networks" && ret=0
;;
(ls)
_arguments $(__docker_arguments) \
@ -1206,7 +1209,7 @@ __docker_network_subcommand() {
(rm)
_arguments $(__docker_arguments) \
$opts_help \
"($help -)*:network:__docker_networks" && ret=0
"($help -)*:network:__docker_complete_networks" && ret=0
;;
(help)
_arguments $(__docker_arguments) ":subcommand:__docker_network_commands" && ret=0
@ -2167,7 +2170,7 @@ __docker_volume_complete_ls_filters() {
__docker_complete_info_plugins Volume && ret=0
;;
(name)
__docker_volumes && ret=0
__docker_complete_volumes && ret=0
;;
*)
_message 'value' && ret=0
@ -2181,7 +2184,7 @@ __docker_volume_complete_ls_filters() {
return ret
}
__docker_volumes() {
__docker_complete_volumes() {
[[ $PREFIX = -* ]] && return 1
integer ret=1
declare -a lines volumes
@ -2245,7 +2248,7 @@ __docker_volume_subcommand() {
_arguments $(__docker_arguments) \
$opts_help \
"($help -f --format)"{-f=,--format=}"[Format the output using the given go template]:template: " \
"($help -)1:volume:__docker_volumes" && ret=0
"($help -)1:volume:__docker_complete_volumes" && ret=0
;;
(ls)
_arguments $(__docker_arguments) \
@ -2268,7 +2271,7 @@ __docker_volume_subcommand() {
_arguments $(__docker_arguments) \
$opts_help \
"($help -f --force)"{-f,--force}"[Force the removal of one or more volumes]" \
"($help -):volume:__docker_volumes" && ret=0
"($help -):volume:__docker_complete_volumes" && ret=0
;;
(help)
_arguments $(__docker_arguments) ":subcommand:__docker_volume_commands" && ret=0
@ -2457,7 +2460,7 @@ __docker_subcommand() {
$opts_help \
"($help -f --format)"{-f=,--format=}"[Format the output using the given go template]:template: " \
"($help -s --size)"{-s,--size}"[Display total file sizes if the type is container]" \
"($help)--type=[Return JSON for specified type]:type:(image container)" \
"($help)--type=[Return JSON for specified type]:type:(container image network node plugin service volume)" \
"($help -)*: :->values" && ret=0
case $state in
@ -2466,8 +2469,24 @@ __docker_subcommand() {
__docker_complete_containers && ret=0
elif [[ ${words[(r)--type=image]} == --type=image ]]; then
__docker_complete_images && ret=0
elif [[ ${words[(r)--type=network]} == --type=network ]]; then
__docker_complete_networks && ret=0
elif [[ ${words[(r)--type=node]} == --type=node ]]; then
__docker_complete_nodes && ret=0
elif [[ ${words[(r)--type=plugin]} == --type=plugin ]]; then
__docker_complete_plugins && ret=0
elif [[ ${words[(r)--type=service]} == --type=service ]]; then
__docker_complete_services && ret=0
elif [[ ${words[(r)--type=volume]} == --type=volume ]]; then
__docker_complete_volumes && ret=0
else
__docker_complete_images && __docker_complete_containers && ret=0
__docker_complete_containers
__docker_complete_images
__docker_complete_networks
__docker_complete_nodes
__docker_complete_plugins
__docker_complete_services
__docker_complete_volumes && ret=0
fi
;;
esac

View File

@ -3,7 +3,8 @@
package daemon
import (
"github.com/Sirupsen/logrus"
"fmt"
aaprofile "github.com/docker/docker/profiles/apparmor"
"github.com/opencontainers/runc/libcontainer/apparmor"
)
@ -13,18 +14,23 @@ const (
defaultApparmorProfile = "docker-default"
)
func installDefaultAppArmorProfile() {
func ensureDefaultAppArmorProfile() error {
if apparmor.IsEnabled() {
if err := aaprofile.InstallDefault(defaultApparmorProfile); err != nil {
apparmorProfiles := []string{defaultApparmorProfile}
loaded, err := aaprofile.IsLoaded(defaultApparmorProfile)
if err != nil {
return fmt.Errorf("Could not check if %s AppArmor profile was loaded: %s", defaultApparmorProfile, err)
}
// Allow daemon to run if loading failed, but are active
// (possibly through another run, manually, or via system startup)
for _, policy := range apparmorProfiles {
if err := aaprofile.IsLoaded(policy); err != nil {
logrus.Errorf("AppArmor enabled on system but the %s profile could not be loaded.", policy)
}
}
// Nothing to do.
if loaded {
return nil
}
// Load the profile.
if err := aaprofile.InstallDefault(defaultApparmorProfile); err != nil {
return fmt.Errorf("AppArmor enabled on system but the %s profile could not be loaded.", defaultApparmorProfile)
}
}
return nil
}

View File

@ -2,5 +2,6 @@
package daemon
func installDefaultAppArmorProfile() {
func ensureDefaultAppArmorProfile() error {
return nil
}

View File

@ -566,7 +566,8 @@ func (c *containerConfig) networkCreateRequest(name string) (clustertypes.Networ
// ID: na.Network.ID,
Driver: na.Network.DriverState.Name,
IPAM: &network.IPAM{
Driver: na.Network.IPAM.Driver.Name,
Driver: na.Network.IPAM.Driver.Name,
Options: na.Network.IPAM.Driver.Options,
},
Options: na.Network.DriverState.Options,
Labels: na.Network.Spec.Annotations.Labels,

View File

@ -2,6 +2,7 @@ package daemon
import (
"fmt"
"os"
"path/filepath"
"time"
@ -101,7 +102,7 @@ func (daemon *Daemon) Register(c *container.Container) error {
return nil
}
func (daemon *Daemon) newContainer(name string, config *containertypes.Config, imgID image.ID, managed bool) (*container.Container, error) {
func (daemon *Daemon) newContainer(name string, config *containertypes.Config, hostConfig *containertypes.HostConfig, imgID image.ID, managed bool) (*container.Container, error) {
var (
id string
err error
@ -112,7 +113,16 @@ func (daemon *Daemon) newContainer(name string, config *containertypes.Config, i
return nil, err
}
daemon.generateHostname(id, config)
if hostConfig.NetworkMode.IsHost() {
if config.Hostname == "" {
config.Hostname, err = os.Hostname()
if err != nil {
return nil, err
}
}
} else {
daemon.generateHostname(id, config)
}
entrypoint, args := daemon.getEntrypointAndArgs(config.Entrypoint, config.Cmd)
base := daemon.newBaseContainer(id)

View File

@ -851,9 +851,11 @@ func (daemon *Daemon) initializeNetworking(container *container.Container) error
}
if container.HostConfig.NetworkMode.IsHost() {
container.Config.Hostname, err = os.Hostname()
if err != nil {
return err
if container.Config.Hostname == "" {
container.Config.Hostname, err = os.Hostname()
if err != nil {
return err
}
}
}

View File

@ -96,7 +96,7 @@ func (daemon *Daemon) create(params types.ContainerCreateConfig, managed bool) (
return nil, err
}
if container, err = daemon.newContainer(params.Name, params.Config, imgID, managed); err != nil {
if container, err = daemon.newContainer(params.Name, params.Config, params.HostConfig, imgID, managed); err != nil {
return nil, err
}
defer func() {

View File

@ -524,7 +524,10 @@ func NewDaemon(config *Config, registryService registry.Service, containerdRemot
logrus.Warnf("Failed to configure golang's threads limit: %v", err)
}
installDefaultAppArmorProfile()
if err := ensureDefaultAppArmorProfile(); err != nil {
logrus.Errorf(err.Error())
}
daemonRepo := filepath.Join(config.Root, "containers")
if err := idtools.MkdirAllAs(daemonRepo, 0700, rootUID, rootGID); err != nil && !os.IsExist(err) {
return nil, err

View File

@ -22,10 +22,10 @@ func lookupPlugin(name, home string, opts []string, pg plugingetter.PluginGetter
if err != nil {
return nil, fmt.Errorf("Error looking up graphdriver plugin %s: %v", name, err)
}
return newPluginDriver(name, home, opts, pl.Client())
return newPluginDriver(name, home, opts, pl)
}
func newPluginDriver(name, home string, opts []string, c pluginClient) (Driver, error) {
proxy := &graphDriverProxy{name, c}
func newPluginDriver(name, home string, opts []string, pl plugingetter.CompatPlugin) (Driver, error) {
proxy := &graphDriverProxy{name, pl.Client(), pl}
return proxy, proxy.Init(filepath.Join(home, name), opts)
}

View File

@ -6,11 +6,13 @@ import (
"io"
"github.com/docker/docker/pkg/archive"
"github.com/docker/docker/pkg/plugingetter"
)
type graphDriverProxy struct {
name string
client pluginClient
p plugingetter.CompatPlugin
}
type graphDriverRequest struct {
@ -35,6 +37,12 @@ type graphDriverInitRequest struct {
}
func (d *graphDriverProxy) Init(home string, opts []string) error {
if !d.p.IsV1() {
if cp, ok := d.p.(plugingetter.CountedPlugin); ok {
// always acquire here, it will be cleaned up on daemon shutdown
cp.Acquire()
}
}
args := &graphDriverInitRequest{
Home: home,
Opts: opts,
@ -167,6 +175,13 @@ func (d *graphDriverProxy) GetMetadata(id string) (map[string]string, error) {
}
func (d *graphDriverProxy) Cleanup() error {
if !d.p.IsV1() {
if cp, ok := d.p.(plugingetter.CountedPlugin); ok {
// always release
defer cp.Release()
}
}
args := &graphDriverRequest{}
var ret graphDriverResponse
if err := d.client.Call("GraphDriver.Cleanup", args, &ret); err != nil {

View File

@ -733,12 +733,27 @@ func (daemon *Daemon) createSpec(c *container.Container) (*specs.Spec, error) {
}
if apparmor.IsEnabled() {
appArmorProfile := "docker-default"
if len(c.AppArmorProfile) > 0 {
var appArmorProfile string
if c.AppArmorProfile != "" {
appArmorProfile = c.AppArmorProfile
} else if c.HostConfig.Privileged {
appArmorProfile = "unconfined"
} else {
appArmorProfile = "docker-default"
}
if appArmorProfile == "docker-default" {
// Unattended upgrades and other fun services can unload AppArmor
// profiles inadvertently. Since we cannot store our profile in
// /etc/apparmor.d, nor can we practically add other ways of
// telling the system to keep our profile loaded, in order to make
// sure that we keep the default profile enabled we dynamically
// reload it if necessary.
if err := ensureDefaultAppArmorProfile(); err != nil {
return nil, err
}
}
s.Process.ApparmorProfile = appArmorProfile
}
s.Process.SelinuxLabel = c.GetProcessLabel()

View File

@ -1,11 +1,13 @@
package daemon
import (
"fmt"
"regexp"
"github.com/Sirupsen/logrus"
"github.com/docker/distribution/digest"
"github.com/docker/docker/api/types"
"github.com/docker/docker/api/types/filters"
"github.com/docker/docker/image"
"github.com/docker/docker/layer"
"github.com/docker/docker/pkg/directory"
@ -16,7 +18,7 @@ import (
)
// ContainersPrune removes unused containers
func (daemon *Daemon) ContainersPrune(config *types.ContainersPruneConfig) (*types.ContainersPruneReport, error) {
func (daemon *Daemon) ContainersPrune(pruneFilters filters.Args) (*types.ContainersPruneReport, error) {
rep := &types.ContainersPruneReport{}
allContainers := daemon.List()
@ -40,7 +42,7 @@ func (daemon *Daemon) ContainersPrune(config *types.ContainersPruneConfig) (*typ
}
// VolumesPrune removes unused local volumes
func (daemon *Daemon) VolumesPrune(config *types.VolumesPruneConfig) (*types.VolumesPruneReport, error) {
func (daemon *Daemon) VolumesPrune(pruneFilters filters.Args) (*types.VolumesPruneReport, error) {
rep := &types.VolumesPruneReport{}
pruneVols := func(v volume.Volume) error {
@ -70,11 +72,20 @@ func (daemon *Daemon) VolumesPrune(config *types.VolumesPruneConfig) (*types.Vol
}
// ImagesPrune removes unused images
func (daemon *Daemon) ImagesPrune(config *types.ImagesPruneConfig) (*types.ImagesPruneReport, error) {
func (daemon *Daemon) ImagesPrune(pruneFilters filters.Args) (*types.ImagesPruneReport, error) {
rep := &types.ImagesPruneReport{}
danglingOnly := true
if pruneFilters.Include("dangling") {
if pruneFilters.ExactMatch("dangling", "false") || pruneFilters.ExactMatch("dangling", "0") {
danglingOnly = false
} else if !pruneFilters.ExactMatch("dangling", "true") && !pruneFilters.ExactMatch("dangling", "1") {
return nil, fmt.Errorf("Invalid filter 'dangling=%s'", pruneFilters.Get("dangling"))
}
}
var allImages map[image.ID]*image.Image
if config.DanglingOnly {
if danglingOnly {
allImages = daemon.imageStore.Heads()
} else {
allImages = daemon.imageStore.Map()
@ -106,7 +117,7 @@ func (daemon *Daemon) ImagesPrune(config *types.ImagesPruneConfig) (*types.Image
deletedImages := []types.ImageDelete{}
refs := daemon.referenceStore.References(dgst)
if len(refs) > 0 {
if config.DanglingOnly {
if danglingOnly {
// Not a dangling image
continue
}
@ -156,7 +167,7 @@ func (daemon *Daemon) ImagesPrune(config *types.ImagesPruneConfig) (*types.Image
}
// localNetworksPrune removes unused local networks
func (daemon *Daemon) localNetworksPrune(config *types.NetworksPruneConfig) (*types.NetworksPruneReport, error) {
func (daemon *Daemon) localNetworksPrune(pruneFilters filters.Args) (*types.NetworksPruneReport, error) {
rep := &types.NetworksPruneReport{}
var err error
// When the function returns true, the walk will stop.
@ -177,7 +188,7 @@ func (daemon *Daemon) localNetworksPrune(config *types.NetworksPruneConfig) (*ty
}
// clusterNetworksPrune removes unused cluster networks
func (daemon *Daemon) clusterNetworksPrune(config *types.NetworksPruneConfig) (*types.NetworksPruneReport, error) {
func (daemon *Daemon) clusterNetworksPrune(pruneFilters filters.Args) (*types.NetworksPruneReport, error) {
rep := &types.NetworksPruneReport{}
cluster := daemon.GetCluster()
networks, err := cluster.GetNetworks()
@ -207,15 +218,15 @@ func (daemon *Daemon) clusterNetworksPrune(config *types.NetworksPruneConfig) (*
}
// NetworksPrune removes unused networks
func (daemon *Daemon) NetworksPrune(config *types.NetworksPruneConfig) (*types.NetworksPruneReport, error) {
func (daemon *Daemon) NetworksPrune(pruneFilters filters.Args) (*types.NetworksPruneReport, error) {
rep := &types.NetworksPruneReport{}
clusterRep, err := daemon.clusterNetworksPrune(config)
clusterRep, err := daemon.clusterNetworksPrune(pruneFilters)
if err != nil {
logrus.Warnf("could not remove cluster networks: %v", err)
} else {
rep.NetworksDeleted = append(rep.NetworksDeleted, clusterRep.NetworksDeleted...)
}
localRep, err := daemon.localNetworksPrune(config)
localRep, err := daemon.localNetworksPrune(pruneFilters)
if err != nil {
logrus.Warnf("could not remove local networks: %v", err)
} else {

View File

@ -119,6 +119,9 @@ func (daemon *Daemon) containerStart(container *container.Container, checkpoint
container.SetExitCode(128)
}
container.ToDisk()
container.Reset(false)
daemon.Cleanup(container)
// if containers AutoRemove flag is set, remove it after clean up
if container.HostConfig.AutoRemove {
@ -187,8 +190,6 @@ func (daemon *Daemon) containerStart(container *container.Container, checkpoint
container.SetExitCode(127)
}
container.Reset(false)
return fmt.Errorf("%s", errDesc)
}

View File

@ -60,21 +60,25 @@ func shouldV2Fallback(err errcode.Error) bool {
return false
}
func translatePullError(err error, ref reference.Named) error {
// TranslatePullError is used to convert an error from a registry pull
// operation to an error representing the entire pull operation. Any error
// information which is not used by the returned error gets output to
// log at info level.
func TranslatePullError(err error, ref reference.Named) error {
switch v := err.(type) {
case errcode.Errors:
if len(v) != 0 {
for _, extra := range v[1:] {
logrus.Infof("Ignoring extra error returned from registry: %v", extra)
}
return translatePullError(v[0], ref)
return TranslatePullError(v[0], ref)
}
case errcode.Error:
var newErr error
switch v.Code {
case errcode.ErrorCodeDenied:
// ErrorCodeDenied is used when access to the repository was denied
newErr = errors.Errorf("repository %s not found: does not exist or no read access", ref.Name())
newErr = errors.Errorf("repository %s not found: does not exist or no pull access", ref.Name())
case v2.ErrorCodeManifestUnknown:
newErr = errors.Errorf("manifest for %s not found", ref.String())
case v2.ErrorCodeNameUnknown:
@ -85,7 +89,7 @@ func translatePullError(err error, ref reference.Named) error {
return newErr
}
case xfer.DoNotRetry:
return translatePullError(v.Err, ref)
return TranslatePullError(v.Err, ref)
}
return err

View File

@ -168,7 +168,7 @@ func Pull(ctx context.Context, ref reference.Named, imagePullConfig *ImagePullCo
continue
}
logrus.Errorf("Not continuing with pull after error: %v", err)
return translatePullError(err, ref)
return TranslatePullError(err, ref)
}
imagePullConfig.ImageEventLogger(ref.String(), repoInfo.Name(), "pull")
@ -179,7 +179,7 @@ func Pull(ctx context.Context, ref reference.Named, imagePullConfig *ImagePullCo
lastErr = fmt.Errorf("no endpoints found for %s", ref.String())
}
return translatePullError(lastErr, ref)
return TranslatePullError(lastErr, ref)
}
// writeStatus writes a status message to out. If layersDownloaded is true, the

View File

@ -355,8 +355,7 @@ func (p *v2Puller) pullV2Tag(ctx context.Context, ref reference.Named) (tagUpdat
}
if m, ok := manifest.(*schema2.DeserializedManifest); ok {
if m.Manifest.Config.MediaType == schema2.MediaTypePluginConfig ||
m.Manifest.Config.MediaType == "application/vnd.docker.plugin.image.v0+json" { //TODO: remove this v0 before 1.13 GA
if m.Manifest.Config.MediaType == schema2.MediaTypePluginConfig {
return false, errMediaTypePlugin
}
}

View File

@ -70,17 +70,22 @@ func NewV2Repository(ctx context.Context, repoInfo *registry.RepositoryInfo, end
passThruTokenHandler := &existingTokenHandler{token: authConfig.RegistryToken}
modifiers = append(modifiers, auth.NewAuthorizer(challengeManager, passThruTokenHandler))
} else {
scope := auth.RepositoryScope{
Repository: repoName,
Actions: actions,
}
// Keep image repositories blank for scope compatibility
if repoInfo.Class != "image" {
scope.Class = repoInfo.Class
}
creds := registry.NewStaticCredentialStore(authConfig)
tokenHandlerOptions := auth.TokenHandlerOptions{
Transport: authTransport,
Credentials: creds,
Scopes: []auth.Scope{
auth.RepositoryScope{
Repository: repoName,
Actions: actions,
},
},
ClientID: registry.AuthClientID,
Scopes: []auth.Scope{scope},
ClientID: registry.AuthClientID,
}
tokenHandler := auth.NewTokenHandlerWithOptions(tokenHandlerOptions)
basicHandler := auth.NewBasicHandler(creds)

View File

@ -19,7 +19,7 @@ redirect_from:
## 1. Brief introduction
- The daemon listens on `unix:///var/run/docker.sock` but you can
[Bind Docker to another host/port or a Unix socket](../commandline/dockerd.md#bind-docker-to-another-host-port-or-a-unix-socket).
[Bind Docker to another host/port or a Unix socket](../reference/commandline/dockerd.md#bind-docker-to-another-host-port-or-a-unix-socket).
- The API tends to be REST, but for some complex commands, like `attach`
or `pull`, the HTTP connection is hijacked to transport `STDOUT`,
`STDIN` and `STDERR`.
@ -1294,6 +1294,7 @@ a base64-encoded AuthConfig object.
**Status codes**:
- **200** no error
- **404** - repository does not exist or no read access
- **500** server error

View File

@ -19,7 +19,7 @@ redirect_from:
## 1. Brief introduction
- The daemon listens on `unix:///var/run/docker.sock` but you can
[Bind Docker to another host/port or a Unix socket](../commandline/dockerd.md#bind-docker-to-another-host-port-or-a-unix-socket).
[Bind Docker to another host/port or a Unix socket](../reference/commandline/dockerd.md#bind-docker-to-another-host-port-or-a-unix-socket).
- The API tends to be REST. However, for some complex commands, like `attach`
or `pull`, the HTTP connection is hijacked to transport `stdout`,
`stdin` and `stderr`.
@ -1340,6 +1340,7 @@ a base64-encoded AuthConfig object.
**Status codes**:
- **200** no error
- **404** - repository does not exist or no read access
- **500** server error

View File

@ -19,7 +19,7 @@ redirect_from:
## 1. Brief introduction
- The daemon listens on `unix:///var/run/docker.sock` but you can
[Bind Docker to another host/port or a Unix socket](../commandline/dockerd.md#bind-docker-to-another-host-port-or-a-unix-socket).
[Bind Docker to another host/port or a Unix socket](../reference/commandline/dockerd.md#bind-docker-to-another-host-port-or-a-unix-socket).
- The API tends to be REST. However, for some complex commands, like `attach`
or `pull`, the HTTP connection is hijacked to transport `stdout`,
`stdin` and `stderr`.
@ -1494,6 +1494,7 @@ a base64-encoded AuthConfig object.
**Status codes**:
- **200** no error
- **404** - repository does not exist or no read access
- **500** server error

View File

@ -19,7 +19,7 @@ redirect_from:
## 1. Brief introduction
- The daemon listens on `unix:///var/run/docker.sock` but you can
[Bind Docker to another host/port or a Unix socket](../commandline/dockerd.md#bind-docker-to-another-host-port-or-a-unix-socket).
[Bind Docker to another host/port or a Unix socket](../reference/commandline/dockerd.md#bind-docker-to-another-host-port-or-a-unix-socket).
- The API tends to be REST. However, for some complex commands, like `attach`
or `pull`, the HTTP connection is hijacked to transport `stdout`,
`stdin` and `stderr`.
@ -1587,6 +1587,7 @@ a base64-encoded AuthConfig object.
**Status codes**:
- **200** no error
- **404** - repository does not exist or no read access
- **500** server error

View File

@ -19,7 +19,7 @@ redirect_from:
## 1. Brief introduction
- The daemon listens on `unix:///var/run/docker.sock` but you can
[Bind Docker to another host/port or a Unix socket](../commandline/dockerd.md#bind-docker-to-another-host-port-or-a-unix-socket).
[Bind Docker to another host/port or a Unix socket](../reference/commandline/dockerd.md#bind-docker-to-another-host-port-or-a-unix-socket).
- The API tends to be REST. However, for some complex commands, like `attach`
or `pull`, the HTTP connection is hijacked to transport `stdout`,
`stdin` and `stderr`.
@ -1785,6 +1785,7 @@ a base64-encoded AuthConfig object.
**Status codes**:
- **200** no error
- **404** - repository does not exist or no read access
- **500** server error

View File

@ -19,7 +19,7 @@ redirect_from:
## 1. Brief introduction
- The daemon listens on `unix:///var/run/docker.sock` but you can
[Bind Docker to another host/port or a Unix socket](../commandline/dockerd.md#bind-docker-to-another-host-port-or-a-unix-socket).
[Bind Docker to another host/port or a Unix socket](../reference/commandline/dockerd.md#bind-docker-to-another-host-port-or-a-unix-socket).
- The API tends to be REST. However, for some complex commands, like `attach`
or `pull`, the HTTP connection is hijacked to transport `stdout`,
`stdin` and `stderr`.
@ -1821,6 +1821,7 @@ a base64-encoded AuthConfig object.
**Status codes**:
- **200** no error
- **404** - repository does not exist or no read access
- **500** server error

View File

@ -19,7 +19,7 @@ redirect_from:
## 1. Brief introduction
- The daemon listens on `unix:///var/run/docker.sock` but you can
[Bind Docker to another host/port or a Unix socket](../commandline/dockerd.md#bind-docker-to-another-host-port-or-a-unix-socket).
[Bind Docker to another host/port or a Unix socket](../reference/commandline/dockerd.md#bind-docker-to-another-host-port-or-a-unix-socket).
- The API tends to be REST. However, for some complex commands, like `attach`
or `pull`, the HTTP connection is hijacked to transport `stdout`,
`stdin` and `stderr`.
@ -1818,6 +1818,7 @@ a base64-encoded AuthConfig object.
**Status codes**:
- **200** no error
- **404** - repository does not exist or no read access
- **500** server error
@ -3319,6 +3320,7 @@ Content-Type: application/json
**Status codes**:
- **201** - no error
- **403** - operation not supported for pre-defined networks
- **404** - plugin not found
- **500** - server error
@ -4561,6 +4563,11 @@ image](#create-an-image) section for more details.
],
"User": "33"
},
"Networks": [
{
"Target": "overlay1"
}
],
"LogDriver": {
"Name": "json-file",
"Options": {
@ -4618,6 +4625,7 @@ image](#create-an-image) section for more details.
**Status codes**:
- **201** no error
- **403** - network is not eligible for services
- **406** node is not part of a swarm
- **409** name conflicts with an existing object
- **500** - server error

View File

@ -20,29 +20,49 @@ The following list of features are deprecated in Engine.
To learn more about Docker Engine's deprecation policy,
see [Feature Deprecation Policy](https://docs.docker.com/engine/#feature-deprecation-policy).
### Top-level network properties in NetworkSettings
**Deprecated In Release: v1.13.0**
**Target For Removal In Release: v1.16**
When inspecting a container, `NetworkSettings` contains top-level information
about the default ("bridge") network;
`EndpointID`, `Gateway`, `GlobalIPv6Address`, `GlobalIPv6PrefixLen`, `IPAddress`,
`IPPrefixLen`, `IPv6Gateway`, and `MacAddress`.
These properties are deprecated in favor of per-network properties in
`NetworkSettings.Networks`. These properties were already "deprecated" in
docker 1.9, but kept around for backward compatibility.
Refer to [#17538](https://github.com/docker/docker/pull/17538) for further
information.
## `filter` param for `/images/json` endpoint
**Deprecated In Release: [v1.13](https://github.com/docker/docker/releases/tag/v1.13.0)**
**Deprecated In Release: [v1.13.0](https://github.com/docker/docker/releases/tag/v1.13.0)**
**Target For Removal In Release: v1.16**
The `filter` param to filter the list of image by reference (name or name:tag) is now implemented as a regular filter, named `reference`.
### `repository:shortid` image references
**Deprecated In Release: [v1.13](https://github.com/docker/docker/releases/tag/v1.13.0)**
**Deprecated In Release: [v1.13.0](https://github.com/docker/docker/releases/tag/v1.13.0)**
**Target For Removal In Release: v1.16**
`repository:shortid` syntax for referencing images is very little used, collides with tag references can be confused with digest references.
### `docker daemon` subcommand
**Deprecated In Release: [v1.13](https://github.com/docker/docker/releases/tag/v1.13.0)**
**Deprecated In Release: [v1.13.0](https://github.com/docker/docker/releases/tag/v1.13.0)**
**Target For Removal In Release: v1.16**
The daemon is moved to a separate binary (`dockerd`), and should be used instead.
### Duplicate keys with conflicting values in engine labels
**Deprecated In Release: [v1.13](https://github.com/docker/docker/releases/tag/v1.13.0)**
**Deprecated In Release: [v1.13.0](https://github.com/docker/docker/releases/tag/v1.13.0)**
**Target For Removal In Release: v1.16**
@ -50,12 +70,12 @@ Duplicate keys with conflicting values have been deprecated. A warning is displa
in the output, and an error will be returned in the future.
### `MAINTAINER` in Dockerfile
**Deprecated In Release: v1.13.0**
**Deprecated In Release: [v1.13.0](https://github.com/docker/docker/releases/tag/v1.13.0)**
`MAINTAINER` was an early very limited form of `LABEL` which should be used instead.
### API calls without a version
**Deprecated In Release: [v1.13](https://github.com/docker/docker/releases/)**
**Deprecated In Release: [v1.13.0](https://github.com/docker/docker/releases/tag/v1.13.0)**
**Target For Removal In Release: v1.16**
@ -64,7 +84,7 @@ future Engine versions. Instead of just requesting, for example, the URL
`/containers/json`, you must now request `/v1.25/containers/json`.
### Backing filesystem without `d_type` support for overlay/overlay2
**Deprecated In Release: v1.13.0**
**Deprecated In Release: [v1.13.0](https://github.com/docker/docker/releases/tag/v1.13.0)**
**Target For Removal In Release: v1.16**
@ -75,12 +95,12 @@ if it is formatted with the `ftype=0` option.
Please also refer to [#27358](https://github.com/docker/docker/issues/27358) for
further information.
### Three argument form in `docker import`
### Three arguments form in `docker import`
**Deprecated In Release: [v0.6.7](https://github.com/docker/docker/releases/tag/v0.6.7)**
**Removed In Release: [v1.12.0](https://github.com/docker/docker/releases/tag/v1.12.0)**
The `docker import` command format 'file|URL|- [REPOSITORY [TAG]]' is deprecated since November 2013. It's no more supported.
The `docker import` command format `file|URL|- [REPOSITORY [TAG]]` is deprecated since November 2013. It's no more supported.
### `-h` shorthand for `--help`
@ -136,7 +156,7 @@ To make tagging consistent across the various `docker` commands, the `-f` flag o
Passing an `HostConfig` to `POST /containers/{name}/start` is deprecated in favor of
defining it at container creation (`POST /containers/create`).
### Docker ps 'before' and 'since' options
### `--before` and `--since` flags on `docker ps`
**Deprecated In Release: [v1.10.0](https://github.com/docker/docker/releases/tag/v1.10.0)**
@ -145,7 +165,7 @@ defining it at container creation (`POST /containers/create`).
The `docker ps --before` and `docker ps --since` options are deprecated.
Use `docker ps --filter=before=...` and `docker ps --filter=since=...` instead.
### Docker search 'automated' and 'stars' options
### `--automated` and `--stars` flags on `docker search`
**Deprecated in Release: [v1.12.0](https://github.com/docker/docker/releases/tag/v1.12.0)**
@ -234,7 +254,7 @@ The single-dash (`-help`) was removed, in favor of the double-dash `--help`
**Deprecated In Release: [v0.10.0](https://github.com/docker/docker/releases/tag/v0.10.0)**
**Removed In Release: [v1.13.0](https://github.com/docker/docker/releases/)**
**Removed In Release: [v1.13.0](https://github.com/docker/docker/releases/tag/v1.13.0)**
The flag `--run` of the docker commit (and its short version `-run`) were deprecated in favor
of the `--changes` flag that allows to pass `Dockerfile` commands.

View File

@ -14,7 +14,7 @@ keywords: "API, Usage, plugins, documentation, developer"
-->
# Plugin Config Version 0 of Plugin V2
# Plugin Config Version 1 of Plugin V2
This document outlines the format of the V0 plugin configuration. The plugin
config described herein was introduced in the Docker daemon in the [v1.12.0
@ -25,7 +25,7 @@ configs can be serialized to JSON format with the following media types:
Config Type | Media Type
------------- | -------------
config | "application/vnd.docker.plugin.v0+json"
config | "application/vnd.docker.plugin.v1+json"
## *Config* Field Descriptions
@ -111,6 +111,10 @@ Config provides the base accessible fields for working with V0 plugin format
options of the mount.
- **`propagatedMount`** *string*
path to be mounted as rshared, so that mounts under that path are visible to docker. This is useful for volume plugins.
- **`env`** *PluginEnv array*
env of the plugin, struct consisting of the following fields
@ -133,11 +137,11 @@ Config provides the base accessible fields for working with V0 plugin format
- **`name`** *string*
name of the env.
name of the args.
- **`description`** *string*
description of the env.
description of the args.
- **`value`** *string array*

View File

@ -22,6 +22,10 @@ beyond the lifetime of a single Engine host. See the
## Changelog
### 1.13.0
- If used as part of the v2 plugin architecture, mountpoints that are part of paths returned by plugin have to be mounted under the directory specified by PropagatedMount in the plugin configuration [#26398](https://github.com/docker/docker/pull/26398)
### 1.12.0
- Add `Status` field to `VolumeDriver.Get` response ([#21006](https://github.com/docker/docker/pull/21006#))

View File

@ -38,8 +38,7 @@ Options:
--label value Set metadata for an image (default [])
-m, --memory string Memory limit
--memory-swap string Swap limit equal to memory plus swap: '-1' to enable unlimited swap
--network string Set the networking mode for the run commands
during build.
--network string Set the networking mode for the RUN instructions during build
'bridge': use default Docker bridge
'none': no networking
'container:<name|id>': reuse another container's network stack
@ -54,7 +53,7 @@ Options:
The format is `<number><unit>`. `number` must be greater than `0`.
Unit is optional and can be `b` (bytes), `k` (kilobytes), `m` (megabytes),
or `g` (gigabytes). If you omit the unit, the system uses bytes.
--squash Squash newly built layers into a single new layer (**Experimental Only**)
--squash Squash newly built layers into a single new layer (**Experimental Only**)
-t, --tag value Name and optionally a tag in the 'name:tag' format (default [])
--ulimit value Ulimit options (default [])
```

View File

@ -40,7 +40,7 @@ NETWORK ID NAME DRIVER SCOPE
7fca4eb8c647 bridge bridge local
9f904ee27bf5 none null local
cf03ee007fb4 host host local
78b03ee04fc4 multi-host overlay local
78b03ee04fc4 multi-host overlay swarm
```
Use the `--no-trunc` option to display the full network id:

View File

@ -534,9 +534,11 @@ service's name and the node's ID where it sits.
```bash
$ docker service create --name hosttempl --hostname={% raw %}"{{.Node.ID}}-{{.Service.Name}}"{% endraw %} busybox top
va8ew30grofhjoychbr6iot8c
$ docker service ps va8ew30grofhjoychbr6iot8c
NAME IMAGE NODE DESIRED STATE CURRENT STATE ERROR PORTS
hosttempl.1.wo41w8hg8qan busybox:latest@sha256:29f5d56d12684887bdfa50dcd29fc31eea4aaf4ad3bec43daf19026a7ce69912 2e7a8a9c4da2 Running Running about a minute ago
ID NAME IMAGE NODE DESIRED STATE CURRENT STATE ERROR PORTS
wo41w8hg8qan hosttempl.1 busybox:latest@sha256:29f5d56d12684887bdfa50dcd29fc31eea4aaf4ad3bec43daf19026a7ce69912 2e7a8a9c4da2 Running Running about a minute ago
$ docker inspect --format={% raw %}"{{.Config.Hostname}}"{% endraw %} hosttempl.1.wo41w8hg8qanxwjwsg4kxpprj
x3ti0erg11rjpg64m75kej2mz-hosttempl
```

View File

@ -40,36 +40,57 @@ The following command shows all the tasks that are part of the `redis` service:
```bash
$ docker service ps redis
NAME IMAGE NODE DESIRED STATE CURRENT STATE
redis.1.0qihejybwf1x5vqi8lgzlgnpq redis:3.0.6 manager1 Running Running 8 seconds
redis.2.bk658fpbex0d57cqcwoe3jthu redis:3.0.6 worker2 Running Running 9 seconds
redis.3.5ls5s5fldaqg37s9pwayjecrf redis:3.0.6 worker1 Running Running 9 seconds
redis.4.8ryt076polmclyihzx67zsssj redis:3.0.6 worker1 Running Running 9 seconds
redis.5.1x0v8yomsncd6sbvfn0ph6ogc redis:3.0.6 manager1 Running Running 8 seconds
redis.6.71v7je3el7rrw0osfywzs0lko redis:3.0.6 worker2 Running Running 9 seconds
redis.7.4l3zm9b7tfr7cedaik8roxq6r redis:3.0.6 worker2 Running Running 9 seconds
redis.8.9tfpyixiy2i74ad9uqmzp1q6o redis:3.0.6 worker1 Running Running 9 seconds
redis.9.3w1wu13yuplna8ri3fx47iwad redis:3.0.6 manager1 Running Running 8 seconds
redis.10.8eaxrb2fqpbnv9x30vr06i6vt redis:3.0.6 manager1 Running Running 8 seconds
ID NAME IMAGE NODE DESIRED STATE CURRENT STATE ERROR PORTS
0qihejybwf1x redis.1 redis:3.0.5 manager1 Running Running 8 seconds
bk658fpbex0d redis.2 redis:3.0.5 worker2 Running Running 9 seconds
5ls5s5fldaqg redis.3 redis:3.0.5 worker1 Running Running 9 seconds
8ryt076polmc redis.4 redis:3.0.5 worker1 Running Running 9 seconds
1x0v8yomsncd redis.5 redis:3.0.5 manager1 Running Running 8 seconds
71v7je3el7rr redis.6 redis:3.0.5 worker2 Running Running 9 seconds
4l3zm9b7tfr7 redis.7 redis:3.0.5 worker2 Running Running 9 seconds
9tfpyixiy2i7 redis.8 redis:3.0.5 worker1 Running Running 9 seconds
3w1wu13yupln redis.9 redis:3.0.5 manager1 Running Running 8 seconds
8eaxrb2fqpbn redis.10 redis:3.0.5 manager1 Running Running 8 seconds
```
In addition to _running_ tasks, the output also shows the task history. For
example, after updating the service to use the `redis:3.0.6` image, the output
may look like this:
```bash
$ docker service ps redis
ID NAME IMAGE NODE DESIRED STATE CURRENT STATE ERROR PORTS
50qe8lfnxaxk redis.1 redis:3.0.6 manager1 Running Running 6 seconds ago
ky2re9oz86r9 \_ redis.1 redis:3.0.5 manager1 Shutdown Shutdown 8 seconds ago
3s46te2nzl4i redis.2 redis:3.0.6 worker2 Running Running less than a second ago
nvjljf7rmor4 \_ redis.2 redis:3.0.6 worker2 Shutdown Rejected 23 seconds ago "No such image: redis@sha256:6…"
vtiuz2fpc0yb \_ redis.2 redis:3.0.5 worker2 Shutdown Shutdown 1 second ago
jnarweeha8x4 redis.3 redis:3.0.6 worker1 Running Running 3 seconds ago
vs448yca2nz4 \_ redis.3 redis:3.0.5 worker1 Shutdown Shutdown 4 seconds ago
jf1i992619ir redis.4 redis:3.0.6 worker1 Running Running 10 seconds ago
blkttv7zs8ee \_ redis.4 redis:3.0.5 worker1 Shutdown Shutdown 11 seconds ago
```
The number of items in the task history is determined by the
`--task-history-limit` option that was set when initializing the swarm. You can
change the task history retention limit using the
[`docker swarm update`](swarm_update.md) command.
When deploying a service, docker resolves the digest for the service's
image, and pins the service to that digest. The digest is not shown by
default, but is printed if `--no-trunc` is used;
default, but is printed if `--no-trunc` is used. The `--no-trunc` option
also shows the non-truncated task ID, and error-messages, as can be seen below;
```bash
$ docker service ps --no-trunc redis
NAME IMAGE NODE DESIRED STATE CURRENT STATE
redis.1.0qihejybwf1x5vqi8lgzlgnpq redis:3.0.6@sha256:6a692a76c2081888b589e26e6ec835743119fe453d67ecf03df7de5b73d69842 manager1 Running Running 28 seconds
redis.2.bk658fpbex0d57cqcwoe3jthu redis:3.0.6@sha256:6a692a76c2081888b589e26e6ec835743119fe453d67ecf03df7de5b73d69842 worker2 Running Running 29 seconds
redis.3.5ls5s5fldaqg37s9pwayjecrf redis:3.0.6@sha256:6a692a76c2081888b589e26e6ec835743119fe453d67ecf03df7de5b73d69842 worker1 Running Running 29 seconds
redis.4.8ryt076polmclyihzx67zsssj redis:3.0.6@sha256:6a692a76c2081888b589e26e6ec835743119fe453d67ecf03df7de5b73d69842 worker1 Running Running 29 seconds
redis.5.1x0v8yomsncd6sbvfn0ph6ogc redis:3.0.6@sha256:6a692a76c2081888b589e26e6ec835743119fe453d67ecf03df7de5b73d69842 manager1 Running Running 28 seconds
redis.6.71v7je3el7rrw0osfywzs0lko redis:3.0.6@sha256:6a692a76c2081888b589e26e6ec835743119fe453d67ecf03df7de5b73d69842 worker2 Running Running 29 seconds
redis.7.4l3zm9b7tfr7cedaik8roxq6r redis:3.0.6@sha256:6a692a76c2081888b589e26e6ec835743119fe453d67ecf03df7de5b73d69842 worker2 Running Running 29 seconds
redis.8.9tfpyixiy2i74ad9uqmzp1q6o redis:3.0.6@sha256:6a692a76c2081888b589e26e6ec835743119fe453d67ecf03df7de5b73d69842 worker1 Running Running 29 seconds
redis.9.3w1wu13yuplna8ri3fx47iwad redis:3.0.6@sha256:6a692a76c2081888b589e26e6ec835743119fe453d67ecf03df7de5b73d69842 manager1 Running Running 28 seconds
redis.10.8eaxrb2fqpbnv9x30vr06i6vt redis:3.0.6@sha256:6a692a76c2081888b589e26e6ec835743119fe453d67ecf03df7de5b73d69842 manager1 Running Running 28 seconds
ID NAME IMAGE NODE DESIRED STATE CURRENT STATE ERROR PORTS
50qe8lfnxaxksi9w2a704wkp7 redis.1 redis:3.0.6@sha256:6a692a76c2081888b589e26e6ec835743119fe453d67ecf03df7de5b73d69842 manager1 Running Running 5 minutes ago
ky2re9oz86r9556i2szb8a8af \_ redis.1 redis:3.0.5@sha256:f8829e00d95672c48c60f468329d6693c4bdd28d1f057e755f8ba8b40008682e worker2 Shutdown Shutdown 5 minutes ago
bk658fpbex0d57cqcwoe3jthu redis.2 redis:3.0.6@sha256:6a692a76c2081888b589e26e6ec835743119fe453d67ecf03df7de5b73d69842 worker2 Running Running 5 seconds
nvjljf7rmor4htv7l8rwcx7i7 \_ redis.2 redis:3.0.6@sha256:6a692a76c2081888b589e26e6ec835743119fe453d67ecf03df7de5b73d69842 worker2 Shutdown Rejected 5 minutes ago "No such image: redis@sha256:6a692a76c2081888b589e26e6ec835743119fe453d67ecf03df7de5b73d69842"
```
## Filtering
@ -93,9 +114,10 @@ The `id` filter matches on all or a prefix of a task's ID.
```bash
$ docker service ps -f "id=8" redis
NAME IMAGE NODE DESIRED STATE CURRENT STATE
redis.4.8ryt076polmclyihzx67zsssj redis:3.0.6 worker1 Running Running 9 seconds
redis.10.8eaxrb2fqpbnv9x30vr06i6vt redis:3.0.6 manager1 Running Running 8 seconds
ID NAME IMAGE NODE DESIRED STATE CURRENT STATE ERROR PORTS
8ryt076polmc redis.4 redis:3.0.6 worker1 Running Running 9 seconds
8eaxrb2fqpbn redis.10 redis:3.0.6 manager1 Running Running 8 seconds
```
#### Name
@ -104,8 +126,8 @@ The `name` filter matches on task names.
```bash
$ docker service ps -f "name=redis.1" redis
NAME IMAGE NODE DESIRED STATE CURRENT STATE
redis.1.0qihejybwf1x5vqi8lgzlgnpq redis:3.0.6 manager1 Running Running 8 seconds
ID NAME IMAGE NODE DESIRED STATE CURRENT STATE ERROR PORTS
qihejybwf1x5 redis.1 redis:3.0.6 manager1 Running Running 8 seconds
```
@ -115,11 +137,11 @@ The `node` filter matches on a node name or a node ID.
```bash
$ docker service ps -f "node=manager1" redis
NAME IMAGE NODE DESIRED STATE CURRENT STATE
redis.1.0qihejybwf1x5vqi8lgzlgnpq redis:3.0.6 manager1 Running Running 8 seconds
redis.5.1x0v8yomsncd6sbvfn0ph6ogc redis:3.0.6 manager1 Running Running 8 seconds
redis.9.3w1wu13yuplna8ri3fx47iwad redis:3.0.6 manager1 Running Running 8 seconds
redis.10.8eaxrb2fqpbnv9x30vr06i6vt redis:3.0.6 manager1 Running Running 8 seconds
ID NAME IMAGE NODE DESIRED STATE CURRENT STATE ERROR PORTS
0qihejybwf1x redis.1 redis:3.0.6 manager1 Running Running 8 seconds
1x0v8yomsncd redis.5 redis:3.0.6 manager1 Running Running 8 seconds
3w1wu13yupln redis.9 redis:3.0.6 manager1 Running Running 8 seconds
8eaxrb2fqpbn redis.10 redis:3.0.6 manager1 Running Running 8 seconds
```

View File

@ -92,7 +92,6 @@ axqh55ipl40h vossibility_vossibility-collector replicated 1/1 icecrime/
## Related information
* [stack config](stack_config.md)
* [stack ls](stack_ls.md)
* [stack ps](stack_ps.md)
* [stack rm](stack_rm.md)

View File

@ -41,8 +41,7 @@ myapp 2
## Related information
* [stack config](stack_config.md)
* [stack deploy](stack_deploy.md)
* [stack rm](stack_rm.md)
* [stack ps](stack_ps.md)
* [stack rm](stack_rm.md)
* [stack services](stack_services.md)

View File

@ -45,8 +45,7 @@ The currently supported filters are:
## Related information
* [stack config](stack_config.md)
* [stack deploy](stack_deploy.md)
* [stack rm](stack_ls.md)
* [stack rm](stack_rm.md)
* [stack services](stack_services.md)
* [stack ls](stack_ls.md)

View File

@ -32,8 +32,7 @@ a manager node.
## Related information
* [stack config](stack_config.md)
* [stack deploy](stack_deploy.md)
* [stack services](stack_services.md)
* [stack ps](stack_ps.md)
* [stack ls](stack_ls.md)
* [stack ps](stack_ps.md)
* [stack services](stack_services.md)

View File

@ -64,8 +64,7 @@ The currently supported filters are:
## Related information
* [stack config](stack_config.md)
* [stack deploy](stack_deploy.md)
* [stack rm](stack_rm.md)
* [stack ps](stack_ps.md)
* [stack ls](stack_ls.md)
* [stack ps](stack_ps.md)
* [stack rm](stack_rm.md)

View File

@ -21,10 +21,10 @@ Usage: docker swarm join [OPTIONS] HOST:PORT
Join a swarm as a node and/or manager
Options:
--advertise-addr value Advertised address (format: <ip|interface>[:port])
--help Print usage
--listen-addr value Listen address (format: <ip|interface>[:port)
--token string Token for entry into the swarm
--advertise-addr string Advertised address (format: <ip|interface>[:port])
--help Print usage
--listen-addr node-addr Listen address (format: <ip|interface>[:port]) (default 0.0.0.0:2377)
--token string Token for entry into the swarm
```
Join a node to a swarm. The node joins as a manager node or worker node based upon the token you

View File

@ -24,10 +24,10 @@ Options:
--autolock Change manager autolocking setting (true|false)
--cert-expiry duration Validity period for node certificates (ns|us|ms|s|m|h) (default 2160h0m0s)
--dispatcher-heartbeat duration Dispatcher heartbeat period (ns|us|ms|s|m|h) (default 5s)
--external-ca value Specifications of one or more certificate signing endpoints
--external-ca external-ca Specifications of one or more certificate signing endpoints
--help Print usage
--max-snapshots int Number of additional Raft snapshots to retain
--snapshot-interval int Number of log entries between Raft snapshots
--max-snapshots uint Number of additional Raft snapshots to retain
--snapshot-interval uint Number of log entries between Raft snapshots (default 10000)
--task-history-limit int Task history retention limit (default 5)
```

View File

@ -63,15 +63,15 @@ Only the operator (the person executing `docker run`) can set the
following options.
- [Detached vs foreground](#detached-vs-foreground)
- [Detached (-d)](#detached-d)
- [Detached (-d)](#detached--d)
- [Foreground](#foreground)
- [Container identification](#container-identification)
- [Name (--name)](#name-name)
- [Name (--name)](#name---name)
- [PID equivalent](#pid-equivalent)
- [IPC settings (--ipc)](#ipc-settings-ipc)
- [IPC settings (--ipc)](#ipc-settings---ipc)
- [Network settings](#network-settings)
- [Restart policies (--restart)](#restart-policies-restart)
- [Clean up (--rm)](#clean-up-rm)
- [Restart policies (--restart)](#restart-policies---restart)
- [Clean up (--rm)](#clean-up---rm)
- [Runtime constraints on resources](#runtime-constraints-on-resources)
- [Runtime privilege and Linux capabilities](#runtime-privilege-and-linux-capabilities)

View File

@ -348,74 +348,6 @@ do_install() {
# Run setup for each distro accordingly
case "$lsb_dist" in
amzn)
(
set -x
$sh_c 'sleep 3; yum -y -q install docker'
)
echo_docker_as_nonroot
exit 0
;;
'opensuse project'|opensuse)
echo 'Going to perform the following operations:'
if [ "$repo" != 'main' ]; then
echo ' * add repository obs://Virtualization:containers'
fi
echo ' * install Docker'
$sh_c 'echo "Press CTRL-C to abort"; sleep 3'
if [ "$repo" != 'main' ]; then
# install experimental packages from OBS://Virtualization:containers
(
set -x
zypper -n ar -f obs://Virtualization:containers Virtualization:containers
rpm_import_repository_key 55A0B34D49501BB7CA474F5AA193FBB572174FC2
)
fi
(
set -x
zypper -n install docker
)
echo_docker_as_nonroot
exit 0
;;
'suse linux'|sle[sd])
echo 'Going to perform the following operations:'
if [ "$repo" != 'main' ]; then
echo ' * add repository obs://Virtualization:containers'
echo ' * install experimental Docker using packages NOT supported by SUSE'
else
echo ' * add the "Containers" module'
echo ' * install Docker using packages supported by SUSE'
fi
$sh_c 'echo "Press CTRL-C to abort"; sleep 3'
if [ "$repo" != 'main' ]; then
# install experimental packages from OBS://Virtualization:containers
echo >&2 'Warning: installing experimental packages from OBS, these packages are NOT supported by SUSE'
(
set -x
zypper -n ar -f obs://Virtualization:containers/SLE_12 Virtualization:containers
rpm_import_repository_key 55A0B34D49501BB7CA474F5AA193FBB572174FC2
)
else
# Add the containers module
# Note well-1: the SLE machine must already be registered against SUSE Customer Center
# Note well-2: the `-r ""` is required to workaround a known issue of SUSEConnect
(
set -x
SUSEConnect -p sle-module-containers/12/x86_64 -r ""
)
fi
(
set -x
zypper -n install docker
)
echo_docker_as_nonroot
exit 0
;;
ubuntu|debian|raspbian)
export DEBIAN_FRONTEND=noninteractive
@ -522,33 +454,6 @@ do_install() {
echo_docker_as_nonroot
exit 0
;;
gentoo)
if [ "$url" = "https://test.docker.com/" ]; then
# intentionally mixed spaces and tabs here -- tabs are stripped by "<<-'EOF'", spaces are kept in the output
cat >&2 <<-'EOF'
You appear to be trying to install the latest nightly build in Gentoo.'
The portage tree should contain the latest stable release of Docker, but'
if you want something more recent, you can always use the live ebuild'
provided in the "docker" overlay available via layman. For more'
instructions, please see the following URL:'
https://github.com/tianon/docker-overlay#using-this-overlay'
After adding the "docker" overlay, you should be able to:'
emerge -av =app-emulation/docker-9999'
EOF
exit 1
fi
(
set -x
$sh_c 'sleep 3; emerge app-emulation/docker'
)
exit 0
;;
esac
# intentionally mixed spaces and tabs here -- tabs are stripped by "<<-'EOF'", spaces are kept in the output

View File

@ -6,17 +6,17 @@
by hack\make.sh, but uses native Windows PowerShell semantics. It does
not support the full set of options provided by the Linux counterpart.
For example:
- You can't cross-build Linux docker binaries on Windows
- Hashes aren't generated on binaries
- 'Releasing' isn't supported.
- Integration tests. This is because they currently cannot run inside a container,
and require significant external setup.
It does however provided the minimum necessary to support parts of local Windows
and require significant external setup.
It does however provided the minimum necessary to support parts of local Windows
development and Windows to Windows CI.
Usage Examples (run from repo root):
Usage Examples (run from repo root):
"hack\make.ps1 -Binary" to build the binaries
"hack\make.ps1 -Client" to build just the client 64-bit binary
"hack\make.ps1 -TestUnit" to run unit tests
@ -176,6 +176,7 @@ Function Execute-Build($type, $additionalBuildTags, $directory) {
Pop-Location; $global:pushed=$False
}
# Validates the DCO marker is present on each commit
Function Validate-DCO($headCommit, $upstreamCommit) {
Write-Host "INFO: Validating Developer Certificate of Origin..."
@ -189,7 +190,11 @@ Function Validate-DCO($headCommit, $upstreamCommit) {
if ($LASTEXITCODE -ne 0) { Throw "Failed git diff --numstat" }
# Counts of adds and deletes after removing multiple white spaces. AWK anyone? :(
$adds=0; $dels=0; $($counts -replace '\s+', ' ') | %{ $a=$_.Split(" "); $adds+=[int]$a[0]; $dels+=[int]$a[1] }
$adds=0; $dels=0; $($counts -replace '\s+', ' ') | %{
$a=$_.Split(" ");
if ($a[0] -ne "-") { $adds+=[int]$a[0] }
if ($a[1] -ne "-") { $dels+=[int]$a[1] }
}
if (($adds -eq 0) -and ($dels -eq 0)) {
Write-Warning "DCO validation - nothing to validate!"
return
@ -199,7 +204,7 @@ Function Validate-DCO($headCommit, $upstreamCommit) {
if ($LASTEXITCODE -ne 0) { Throw "Failed git log --format" }
$commits = $($commits -split '\s+' -match '\S')
$badCommits=@()
$commits | %{
$commits | %{
# Skip commits with no content such as merge commits etc
if ($(git log -1 --format=format: --name-status $_).Length -gt 0) {
# Ignore exit code on next call - always process regardless
@ -230,7 +235,7 @@ Function Validate-PkgImports($headCommit, $upstreamCommit) {
# For the current changed file, get its list of dependencies, sorted and uniqued.
$imports = Invoke-Expression "go list -e -f `'{{ .Deps }}`' $file"
if ($LASTEXITCODE -ne 0) { Throw "Failed go list for dependencies on $file" }
$imports = $imports -Replace "\[" -Replace "\]", "" -Split(" ") | Sort-Object | Get-Unique
$imports = $imports -Replace "\[" -Replace "\]", "" -Split(" ") | Sort-Object | Get-Unique
# Filter out what we are looking for
$imports = $imports -NotMatch "^github.com/docker/docker/pkg/" `
-NotMatch "^github.com/docker/docker/vendor" `
@ -255,11 +260,11 @@ Function Validate-GoFormat($headCommit, $upstreamCommit) {
if ($(Get-Command gofmt -ErrorAction SilentlyContinue) -eq $nil) { Throw "gofmt does not appear to be installed" }
# Get a list of all go source-code files which have changed. Ignore exit code on next call - always process regardless
$files=@(); $files = Invoke-Expression "git diff $upstreamCommit...$headCommit --diff-filter=ACMR --name-only -- `'*.go`'"
$files=@(); $files = Invoke-Expression "git diff $upstreamCommit...$headCommit --diff-filter=ACMR --name-only -- `'*.go`'"
$files = $files | Select-String -NotMatch "^vendor/"
$badFiles=@(); $files | %{
# Deliberately ignore error on next line - treat as failed
$content=Invoke-Expression "git show $headCommit`:$_"
$content=Invoke-Expression "git show $headCommit`:$_"
# Next set of hoops are to ensure we have LF not CRLF semantics as otherwise gofmt on Windows will not succeed.
# Also note that gofmt on Windows does not appear to support stdin piping correctly. Hence go through a temporary file.
@ -327,7 +332,7 @@ Try {
# Get the version of docker (eg 1.14.0-dev)
$dockerVersion=Get-DockerVersion
# Give a warning if we are not running in a container and are building binaries or running unit tests.
# Give a warning if we are not running in a container and are building binaries or running unit tests.
# Not relevant for validation tests as these are fine to run outside of a container.
if ($Client -or $Daemon -or $TestUnit) { Check-InContainer }
@ -341,7 +346,7 @@ Try {
Catch [Exception] { Throw $_ }
}
# DCO, Package import and Go formatting tests.
# DCO, Package import and Go formatting tests.
if ($DCO -or $PkgImports -or $GoFormat) {
# We need the head and upstream commits for these
$headCommit=Get-HeadCommit
@ -394,6 +399,8 @@ Catch [Exception] {
Write-Host -ForegroundColor Red " \___ / (____ /__`|____/\___ `>____ `| "
Write-Host -ForegroundColor Red " \/ \/ \/ \/ "
Write-Host
Throw $_
}
Finally {
if ($global:pushed) { Pop-Location }

View File

@ -69,6 +69,7 @@ DEFAULT_BUNDLES=(
)
VERSION=$(< ./VERSION)
! BUILDTIME=$(date --rfc-3339 ns 2> /dev/null | sed -e 's/ /T/')
if command -v git &> /dev/null && [ -d .git ] && git rev-parse &> /dev/null; then
GITCOMMIT=$(git rev-parse --short HEAD)
if [ -n "$(git status --porcelain --untracked-files=no)" ]; then
@ -82,11 +83,6 @@ if command -v git &> /dev/null && [ -d .git ] && git rev-parse &> /dev/null; the
git status --porcelain --untracked-files=no
echo "#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"
fi
! BUILDTIME=$(date --rfc-3339 ns 2> /dev/null | sed -e 's/ /T/') &> /dev/null
if [ -z $BUILDTIME ]; then
# If using bash 3.1 which doesn't support --rfc-3389, eg Windows CI
BUILDTIME=$(date -u)
fi
elif [ "$DOCKER_GITCOMMIT" ]; then
GITCOMMIT="$DOCKER_GITCOMMIT"
else

View File

@ -88,6 +88,11 @@ func NewDaemon(c *check.C) *Daemon {
}
}
// RootDir returns the root directory of the daemon.
func (d *Daemon) RootDir() string {
return d.root
}
func (d *Daemon) getClientConfig() (*clientConfig, error) {
var (
transport *http.Transport

View File

@ -89,6 +89,16 @@ func (s *DockerSuite) TestExecAPIStart(c *check.C) {
startExec(c, id, http.StatusOK)
}
func (s *DockerSuite) TestExecAPIStartEnsureHeaders(c *check.C) {
testRequires(c, DaemonIsLinux)
dockerCmd(c, "run", "-d", "--name", "test", "busybox", "top")
id := createExec(c, "test")
resp, _, err := sockRequestRaw("POST", fmt.Sprintf("/exec/%s/start", id), strings.NewReader(`{"Detach": true}`), "application/json")
c.Assert(err, checker.IsNil)
c.Assert(resp.Header.Get("Server"), checker.Not(checker.Equals), "")
}
func (s *DockerSuite) TestExecAPIStartBackwardsCompatible(c *check.C) {
testRequires(c, DaemonIsLinux) // Windows only supports 1.25 or later
runSleepingContainer(c, "-d", "--name", "test")

Some files were not shown because too many files have changed in this diff Show More