Compare commits

...

33 Commits

Author SHA1 Message Date
363a3e75cd Merge pull request #229 from andrewhsu/static
[17.09] backport fix to get static builds going
2017-09-13 17:57:50 -07:00
22cec742b1 Fix fetching LVM2 sources
Version 2.02.173 has disappeared, let's revert back to latest stable
one.

https://github.com/moby/moby/issues/34843

Signed-off-by: Kir Kolyshkin <kolyshkin@gmail.com>
(cherry picked from commit a436d8a634392f9e82b6930a560d56900d887ce7)
Signed-off-by: Andrew Hsu <andrewhsu@docker.com>
2017-09-13 17:05:37 -07:00
17db25d098 Merge pull request #227 from andrewhsu/rc2
[17.09] bump version to 17.09.0-ce-rc2
2017-09-13 14:05:25 -07:00
3e2dc53d19 Merge pull request #228 from andrewhsu/cl
[17.09] update changelog for 17.09.0-ce-rc2
2017-09-13 14:05:05 -07:00
efac66c62b Merge pull request #221 from vieux/updatecli
[17.09] cli updated vendoring
2017-09-13 14:00:13 -07:00
9e5777a749 LCOW: Spot fix for multi-os image pulling
Signed-off-by: John Howard <jhoward@microsoft.com>
(cherry picked from commit b291f5a31728f7ff6386bb37f15e7c0885d3b2a7)
Signed-off-by: Andrew Hsu <andrewhsu@docker.com>
2017-09-13 12:38:48 -07:00
c6e21043d8 Use a local copy of ParseLogDetails
It's being removed from client/

Signed-off-by: Daniel Nephin <dnephin@docker.com>
(cherry picked from commit a747389bf4)
Signed-off-by: Victor Vieux <victorvieux@gmail.com>
2017-09-13 10:46:14 -07:00
7034626ac6 vndr github.com/docker/docker to 84144a8 to fix stuff
Signed-off-by: Andrew Hsu <andrewhsu@docker.com>
(cherry picked from commit 850b46e67c)
Signed-off-by: Victor Vieux <victorvieux@gmail.com>
2017-09-12 17:53:14 -07:00
1fa0e54ee7 remove unused vndr github.com/docker/libtrust
Signed-off-by: Andrew Hsu <andrewhsu@docker.com>
(cherry picked from commit 536da4a07a)
Signed-off-by: Victor Vieux <victorvieux@gmail.com>
2017-09-12 16:02:43 -07:00
5f31b291fb vndr golang.org/x/sys to 07c1829
To satisfy requirements of the vndr of docker/docker

Signed-off-by: Andrew Hsu <andrewhsu@docker.com>
(cherry picked from commit 50696bbf72)
Signed-off-by: Victor Vieux <victorvieux@gmail.com>
2017-09-12 16:02:36 -07:00
172695debf vndr docker/docker to ea220e7 to bring in fix for arm
Primarily to bring in fix for "Clear Architecture field in platform
constraint for arm architectures".

Signed-off-by: Andrew Hsu <andrewhsu@docker.com>
(cherry picked from commit ef027b6d72)
Signed-off-by: Victor Vieux <victorvieux@gmail.com>
2017-09-12 16:02:29 -07:00
49f307c88f Revert "Add skip for known failure"
This reverts commit b33e8d49d4.

Signed-off-by: Victor Vieux <victorvieux@gmail.com>
2017-09-12 15:52:22 -07:00
e6067b8038 Remove unused depdendencies from vendor
Signed-off-by: Daniel Nephin <dnephin@docker.com>
(cherry picked from commit 724f03bb23)
Signed-off-by: Victor Vieux <victorvieux@gmail.com>
2017-09-08 16:03:45 -07:00
49c9ca25c0 updated vendoring
Signed-off-by: Simon Ferquel <simon.ferquel@docker.com>
(cherry picked from commit a0113c3a44)
Signed-off-by: Victor Vieux <victorvieux@gmail.com>
2017-09-08 16:03:45 -07:00
21154792a5 Merge pull request #225 from seemethere/fix_metalinter_conversion_errors
[17.09] Fix metalinter conversion errors
2017-09-08 16:00:36 -07:00
be7f90619c Merge pull request #226 from seemethere/fix_test_run_environment
[17.09] Fix test run environment
2017-09-07 21:39:12 -07:00
4231d771bb update changelog for 17.09.0-ce-rc2
Signed-off-by: Andrew Hsu <andrewhsu@docker.com>
2017-09-07 13:34:31 -07:00
b4a675c535 bump version to 17.09.0-ce-rc2
Signed-off-by: Andrew Hsu <andrewhsu@docker.com>
2017-09-07 13:12:13 -07:00
dff328c8a6 Fix a bad assumption
If the empty variable happens to be sorted to the end of the list then TrimSpace()
would remove it. Instead only strip the single trailing newline.

Signed-off-by: Daniel Nephin <dnephin@docker.com>
(cherry picked from commit fff605c3b3557acf6bf793813d695fba59d7fa21)
Signed-off-by: Eli Uriegas <eli.uriegas@docker.com>
2017-09-07 11:40:46 -07:00
2b763fa480 overlay gd: fix build for 32-bit ARM
This commit reverts a hunk of commit 2f5f0af3f ("Add unconvert linter")
and adds a hint for unconvert linter to ignore excessive conversion as
it is required on 32-bit platforms (e.g. armhf).

The exact error on armhf is this:

	19:06:45 ---> Making bundle: dynbinary (in bundles/17.06.0-dev/dynbinary)
	19:06:48 Building: bundles/17.06.0-dev/dynbinary-daemon/dockerd-17.06.0-dev
	19:10:58 # github.com/docker/docker/daemon/graphdriver/overlay
	19:10:58 daemon/graphdriver/overlay/copy.go:161: cannot use stat.Atim.Sec (type int32) as type int64 in argument to time.Unix
	19:10:58 daemon/graphdriver/overlay/copy.go:161: cannot use stat.Atim.Nsec (type int32) as type int64 in argument to time.Unix
	19:10:58 daemon/graphdriver/overlay/copy.go:162: cannot use stat.Mtim.Sec (type int32) as type int64 in argument to time.Unix
	19:10:58 daemon/graphdriver/overlay/copy.go:162: cannot use stat.Mtim.Nsec (type int32) as type int64 in argument to time.Unix

Signed-off-by: Kir Kolyshkin <kolyshkin@gmail.com>
(cherry picked from commit 0120303d8ea4a1d9f8920ac4dba80521072e8536)
Signed-off-by: Eli Uriegas <eli.uriegas@docker.com>
2017-09-06 16:07:27 -07:00
8227e4e739 Fix 'make all' for other platforms
Since commit d7e2c4ce7 ("Use gometalinter for linting") command
"make all" fails on all the non-default platforms (i.e. ARMs, PPC, and
s390) in this way:

	# make all
	...
	Congratulations!  All commits are properly signed with the DCO!
	/go/src/github.com/docker/docker/hack/validate/gometalinter: line 6: gometalinter: command not found
	Makefile:105: recipe for target 'all' failed
	make: *** [all] Error 127

Make sure gometalinter is installed for those platforms

Signed-off-by: Kir Kolyshkin <kolyshkin@gmail.com>
(cherry picked from commit 0c0047e67f8ee73f73465ac60ccebbd16260ab46)
Signed-off-by: Eli Uriegas <eli.uriegas@docker.com>
2017-09-06 16:07:27 -07:00
a0a9bbd3f2 re-enable some conversion for darwin-amd64 platform
Signed-off-by: Simon Ferquel <simon.ferquel@docker.com>
(cherry picked from commit 7c9e64a2e1891bf1020d9312a18741c734fa1cd6)
Signed-off-by: Eli Uriegas <eli.uriegas@docker.com>
2017-09-06 16:06:15 -07:00
ae21824df8 Merge pull request #223 from seemethere/bump_17090rc1
[17.09] bump version to 17.09.0-ce-rc1
2017-09-06 15:22:01 -07:00
ec4c78a39b Merge pull request #214 from vieux/17.09-changelog
[17.09] add 17.09 changelog
2017-09-06 15:21:47 -07:00
aa56783035 Merge pull request #224 from seemethere/fix_integration_tests_1709
[17.09] Changes error check form NotNil to IsNil
2017-09-06 15:18:32 -07:00
b33e8d49d4 Add skip for known failure
Signed-off-by: Eli Uriegas <eli.uriegas@docker.com>
2017-09-06 13:41:55 -07:00
5d1587e61e Changes error check form NotNil to IsNil
rmi -f always returns a 0 exit code so these tests needed to be changed
accordingly.

Signed-off-by: Eli Uriegas <eli.uriegas@docker.com>
2017-09-06 11:30:29 -07:00
8574cd6b8a bump version to 17.09.0-ce-rc1
Signed-off-by: Eli Uriegas <eli.uriegas@docker.com>
2017-09-05 17:06:13 -07:00
54ddbdea25 Merge pull request #222 from vieux/fix_inspect
[17.09] Fix integration suite and propagate failures
2017-09-05 16:49:27 -07:00
efd69761fc Fix integration suite and propagate failures
Failures from the integration suite were not propagating to the outter shell
for some reason. Handle the failure with an if exit 1.

Signed-off-by: Daniel Nephin <dnephin@docker.com>
(cherry picked from commit 96707bc600747257e82917ca079fa5006d636b2c)
Signed-off-by: Victor Vieux <victorvieux@gmail.com>
2017-09-05 14:58:05 -07:00
c973c430a9 Merge pull request #220 from vieux/fix_nano_tests
[17.09] backport: force inspect test format
2017-09-05 14:43:58 -07:00
e3e65f6470 force inspect test format
Signed-off-by: Victor Vieux <victorvieux@gmail.com>
(cherry picked from commit 8e6567cb837e1c885de5146517557c7a5d8a5f17)
Signed-off-by: Victor Vieux <victorvieux@gmail.com>
2017-09-05 13:37:34 -07:00
f7ec4a69b3 add 17.09 changelog
Signed-off-by: Victor Vieux <victorvieux@gmail.com>
2017-09-01 10:32:17 -07:00
452 changed files with 58323 additions and 29425 deletions

View File

@ -6,3 +6,48 @@ https://docs.docker.com/engine/deprecated/ where target removal dates can also
be found.
## 17.09.0-ce (2017-09-DD)
### Builder
+ Add `--chown` flag to `ADD/COPY` commands in Dockerfile [moby/moby#34263](https://github.com/moby/moby/pull/34263)
* Fix cloning unneeded files while building from git repositories [moby/moby#33704](https://github.com/moby/moby/pull/33704)
### Client
* Allow extension fields in the v3.4 version of the compose format [docker/cli#452](https://github.com/docker/cli/pull/452)
* Make compose file allow to specify names for non-external volume [docker/cli#306](https://github.com/docker/cli/pull/306)
* Support `--compose-file -` as stdin [docker/cli#347](https://github.com/docker/cli/pull/347)
* Support `start_period` for healthcheck in Docker Compose [docker/cli#475](https://github.com/docker/cli/pull/475)
+ Add support for `stop-signal` in docker stack commands [docker/cli#388](https://github.com/docker/cli/pull/388)
+ Add support for update order in compose deployments [docker/cli#360](https://github.com/docker/cli/pull/360)
+ Add ulimits to unsupported compose fields [docker/cli#482](https://github.com/docker/cli/pull/482)
+ Add `--format` to `docker-search` [docker/cli#440](https://github.com/docker/cli/pull/440)
* Show images digests when `{{.Digest}}` is in format [docker/cli#439](https://github.com/docker/cli/pull/439)
* Print timestamp when `--human=true` [docker/cli#438](https://github.com/docker/cli/pull/438)
### Networking
+ Add the control plane MTU option in the daemon config [moby/moby#34103](https://github.com/moby/moby/pull/34103)
+ Add service virtual IP to sandbox's loopback address [docker/libnetwork#1877](https://github.com/docker/libnetwork/pull/1877)
### Runtime
* Graphdriver: promote overlay2 over aufs [moby/moby#34430](https://github.com/moby/moby/pull/34430)
* LCOW: Additional flags for VHD boot [moby/moby#34451](https://github.com/moby/moby/pull/34451)
* LCOW: Don't block export [moby/moby#34448](https://github.com/moby/moby/pull/34448)
* LCOW: Dynamic sandbox management [moby/moby#34170](https://github.com/moby/moby/pull/34170)
* LCOW: Force Hyper-V Isolation [moby/moby#34468](https://github.com/moby/moby/pull/34468)
* LCOW: Move toolsScratchPath to /tmp [moby/moby#34396](https://github.com/moby/moby/pull/34396)
* LCOW: Remove hard-coding [moby/moby#34398](https://github.com/moby/moby/pull/34398)
* LCOW: WORKDIR correct handling [moby/moby#34405](https://github.com/moby/moby/pull/34405)
* Windows: named pipe mounts [moby/moby#33852](https://github.com/moby/moby/pull/33852)
### Swarm Mode
* Include whether the managers in the swarm are autolocked as part of `docker info` [docker/cli#471](https://github.com/docker/cli/pull/471)
+ Add 'docker service rollback' subcommand [docker/cli#205](https://github.com/docker/cli/pull/205)
### Packaging
+ Build scripts for ppc64el on Ubuntu [docker/docker-ce-packaging#43](https://github.com/docker/docker-ce-packaging/pull/43)

View File

@ -1 +1 @@
17.09.0-dev
17.09.0-ce-rc2

View File

@ -1 +1 @@
17.08.0-dev
17.09.0-ce-rc2

View File

@ -4,13 +4,13 @@ import (
"io"
"net/http/httputil"
"github.com/Sirupsen/logrus"
"github.com/docker/cli/cli"
"github.com/docker/cli/cli/command"
"github.com/docker/docker/api/types"
"github.com/docker/docker/client"
"github.com/docker/docker/pkg/signal"
"github.com/pkg/errors"
"github.com/sirupsen/logrus"
"github.com/spf13/cobra"
"golang.org/x/net/context"
)

View File

@ -4,7 +4,6 @@ import (
"fmt"
"io"
"github.com/Sirupsen/logrus"
"github.com/docker/cli/cli"
"github.com/docker/cli/cli/command"
"github.com/docker/cli/cli/config/configfile"
@ -13,6 +12,7 @@ import (
apiclient "github.com/docker/docker/client"
"github.com/docker/docker/pkg/promise"
"github.com/pkg/errors"
"github.com/sirupsen/logrus"
"github.com/spf13/cobra"
"golang.org/x/net/context"
)

View File

@ -6,12 +6,12 @@ import (
"runtime"
"sync"
"github.com/Sirupsen/logrus"
"github.com/docker/cli/cli/command"
"github.com/docker/docker/api/types"
"github.com/docker/docker/pkg/ioutils"
"github.com/docker/docker/pkg/stdcopy"
"github.com/docker/docker/pkg/term"
"github.com/sirupsen/logrus"
"golang.org/x/net/context"
)

View File

@ -11,7 +11,6 @@ import (
"strings"
"time"
"github.com/Sirupsen/logrus"
"github.com/docker/cli/cli/compose/loader"
"github.com/docker/cli/opts"
"github.com/docker/docker/api/types/container"
@ -20,6 +19,7 @@ import (
"github.com/docker/docker/pkg/signal"
"github.com/docker/go-connections/nat"
"github.com/pkg/errors"
"github.com/sirupsen/logrus"
"github.com/spf13/pflag"
)

View File

@ -10,7 +10,6 @@ import (
"strings"
"syscall"
"github.com/Sirupsen/logrus"
"github.com/docker/cli/cli"
"github.com/docker/cli/cli/command"
"github.com/docker/cli/opts"
@ -20,6 +19,7 @@ import (
"github.com/docker/docker/pkg/signal"
"github.com/docker/docker/pkg/term"
"github.com/pkg/errors"
"github.com/sirupsen/logrus"
"github.com/spf13/cobra"
"github.com/spf13/pflag"
"golang.org/x/net/context"

View File

@ -7,11 +7,11 @@ import (
"sync"
"time"
"github.com/Sirupsen/logrus"
"github.com/docker/cli/cli/command/formatter"
"github.com/docker/docker/api/types"
"github.com/docker/docker/client"
"github.com/pkg/errors"
"github.com/sirupsen/logrus"
"golang.org/x/net/context"
)

View File

@ -7,11 +7,11 @@ import (
"runtime"
"time"
"github.com/Sirupsen/logrus"
"github.com/docker/cli/cli/command"
"github.com/docker/docker/api/types"
"github.com/docker/docker/client"
"github.com/docker/docker/pkg/signal"
"github.com/sirupsen/logrus"
"golang.org/x/net/context"
)

View File

@ -3,13 +3,13 @@ package container
import (
"strconv"
"github.com/Sirupsen/logrus"
"github.com/docker/cli/cli/command"
"github.com/docker/docker/api/types"
"github.com/docker/docker/api/types/container"
"github.com/docker/docker/api/types/events"
"github.com/docker/docker/api/types/filters"
"github.com/docker/docker/api/types/versions"
"github.com/sirupsen/logrus"
"golang.org/x/net/context"
)

View File

@ -3,8 +3,8 @@ package command
import (
"sync"
"github.com/Sirupsen/logrus"
eventtypes "github.com/docker/docker/api/types/events"
"github.com/sirupsen/logrus"
)
// EventHandler is abstract interface for user to customize

View File

@ -504,7 +504,10 @@ func (c *serviceContext) Replicas() string {
}
func (c *serviceContext) Image() string {
image := c.service.Spec.TaskTemplate.ContainerSpec.Image
var image string
if c.service.Spec.TaskTemplate.ContainerSpec != nil {
image = c.service.Spec.TaskTemplate.ContainerSpec.Image
}
if ref, err := reference.ParseNormalizedNamed(image); err == nil {
// update image string for display, (strips any digest)
if nt, ok := ref.(reference.NamedTagged); ok {

View File

@ -12,7 +12,6 @@ import (
"regexp"
"runtime"
"github.com/Sirupsen/logrus"
"github.com/docker/cli/cli"
"github.com/docker/cli/cli/command"
"github.com/docker/cli/cli/command/image/build"
@ -28,6 +27,7 @@ import (
"github.com/docker/docker/pkg/urlutil"
units "github.com/docker/go-units"
"github.com/pkg/errors"
"github.com/sirupsen/logrus"
"github.com/spf13/cobra"
"golang.org/x/net/context"
)

View File

@ -17,9 +17,9 @@ import (
"github.com/docker/cli/cli/command/image/build"
cliconfig "github.com/docker/cli/cli/config"
"github.com/docker/docker/api/types/versions"
"github.com/docker/docker/client/session"
"github.com/docker/docker/client/session/filesync"
"github.com/docker/docker/pkg/progress"
"github.com/moby/buildkit/session"
"github.com/moby/buildkit/session/filesync"
"github.com/pkg/errors"
"golang.org/x/time/rate"
)

View File

@ -8,7 +8,6 @@ import (
"path"
"sort"
"github.com/Sirupsen/logrus"
"github.com/docker/cli/cli/command"
"github.com/docker/cli/cli/trust"
"github.com/docker/distribution/reference"
@ -19,6 +18,7 @@ import (
"github.com/docker/notary/tuf/data"
"github.com/opencontainers/go-digest"
"github.com/pkg/errors"
"github.com/sirupsen/logrus"
"golang.org/x/net/context"
)

View File

@ -7,10 +7,10 @@ import (
"strings"
"text/template"
"github.com/Sirupsen/logrus"
"github.com/docker/cli/cli"
"github.com/docker/cli/templates"
"github.com/pkg/errors"
"github.com/sirupsen/logrus"
)
// Inspector defines an interface to implement to process elements

View File

@ -4,8 +4,8 @@ import (
"io"
"os"
"github.com/Sirupsen/logrus"
"github.com/docker/docker/pkg/term"
"github.com/sirupsen/logrus"
)
// OutStream is an output stream used by the DockerCli to write normal program

View File

@ -7,13 +7,13 @@ import (
"os"
"path/filepath"
"github.com/Sirupsen/logrus"
"github.com/docker/cli/cli"
"github.com/docker/cli/cli/command"
"github.com/docker/distribution/reference"
"github.com/docker/docker/api/types"
"github.com/docker/docker/pkg/archive"
"github.com/pkg/errors"
"github.com/sirupsen/logrus"
"github.com/spf13/cobra"
"golang.org/x/net/context"
)

View File

@ -41,7 +41,7 @@ func formatServiceInspect(t *testing.T, format formatter.Format, now time.Time)
Labels: map[string]string{"com.label": "foo"},
},
TaskTemplate: swarm.TaskSpec{
ContainerSpec: swarm.ContainerSpec{
ContainerSpec: &swarm.ContainerSpec{
Image: "foo/bar@sha256:this_is_a_test",
},
Networks: []swarm.NetworkAttachmentConfig{

View File

@ -13,6 +13,7 @@ import (
"github.com/docker/cli/cli"
"github.com/docker/cli/cli/command"
"github.com/docker/cli/cli/command/idresolver"
"github.com/docker/cli/service/logs"
"github.com/docker/docker/api/types"
"github.com/docker/docker/api/types/swarm"
"github.com/docker/docker/client"
@ -257,7 +258,7 @@ func (lw *logWriter) Write(buf []byte) (int, error) {
return 0, errors.Errorf("invalid context in log message: %v", string(buf))
}
// parse the details out
details, err := client.ParseLogDetails(string(parts[detailsIndex]))
details, err := logs.ParseLogDetails(string(parts[detailsIndex]))
if err != nil {
return 0, err
}

View File

@ -592,7 +592,7 @@ func (options *serviceOptions) ToService(ctx context.Context, apiClient client.N
Labels: opts.ConvertKVStringsToMap(options.labels.GetAll()),
},
TaskTemplate: swarm.TaskSpec{
ContainerSpec: swarm.ContainerSpec{
ContainerSpec: &swarm.ContainerSpec{
Image: options.image,
Args: options.args,
Command: options.entrypoint.Value(),

View File

@ -3,7 +3,6 @@ package service
import (
"encoding/hex"
"github.com/Sirupsen/logrus"
"github.com/docker/cli/cli/command"
"github.com/docker/cli/cli/trust"
"github.com/docker/distribution/reference"
@ -12,6 +11,7 @@ import (
"github.com/docker/notary/tuf/data"
"github.com/opencontainers/go-digest"
"github.com/pkg/errors"
"github.com/sirupsen/logrus"
"golang.org/x/net/context"
)

View File

@ -270,7 +270,7 @@ func updateService(ctx context.Context, apiClient client.NetworkAPIClient, flags
}
}
cspec := &spec.TaskTemplate.ContainerSpec
cspec := spec.TaskTemplate.ContainerSpec
task := &spec.TaskTemplate
taskResources := func() *swarm.ResourceRequirements {

View File

@ -19,8 +19,12 @@ func TestUpdateServiceArgs(t *testing.T) {
flags := newUpdateCommand(nil).Flags()
flags.Set("args", "the \"new args\"")
spec := &swarm.ServiceSpec{}
cspec := &spec.TaskTemplate.ContainerSpec
spec := &swarm.ServiceSpec{
TaskTemplate: swarm.TaskSpec{
ContainerSpec: &swarm.ContainerSpec{},
},
}
cspec := spec.TaskTemplate.ContainerSpec
cspec.Args = []string{"old", "args"}
updateService(nil, nil, flags, spec)
@ -452,8 +456,12 @@ func TestUpdateSecretUpdateInPlace(t *testing.T) {
}
func TestUpdateReadOnly(t *testing.T) {
spec := &swarm.ServiceSpec{}
cspec := &spec.TaskTemplate.ContainerSpec
spec := &swarm.ServiceSpec{
TaskTemplate: swarm.TaskSpec{
ContainerSpec: &swarm.ContainerSpec{},
},
}
cspec := spec.TaskTemplate.ContainerSpec
// Update with --read-only=true, changed to true
flags := newUpdateCommand(nil).Flags()
@ -474,8 +482,12 @@ func TestUpdateReadOnly(t *testing.T) {
}
func TestUpdateStopSignal(t *testing.T) {
spec := &swarm.ServiceSpec{}
cspec := &spec.TaskTemplate.ContainerSpec
spec := &swarm.ServiceSpec{
TaskTemplate: swarm.TaskSpec{
ContainerSpec: &swarm.ContainerSpec{},
},
}
cspec := spec.TaskTemplate.ContainerSpec
// Update with --stop-signal=SIGUSR1
flags := newUpdateCommand(nil).Flags()

View File

@ -64,7 +64,7 @@ func deployBundle(ctx context.Context, dockerCli command.Cli, opts deployOptions
Labels: convert.AddStackLabel(namespace, service.Labels),
},
TaskTemplate: swarm.TaskSpec{
ContainerSpec: swarm.ContainerSpec{
ContainerSpec: &swarm.ContainerSpec{
Image: service.Image,
Command: service.Command,
Args: service.Args,

View File

@ -45,7 +45,7 @@ func TestServiceUpdateResolveImageChanged(t *testing.T) {
Labels: map[string]string{"com.docker.stack.image": "foobar:1.2.3"},
},
TaskTemplate: swarm.TaskSpec{
ContainerSpec: swarm.ContainerSpec{
ContainerSpec: &swarm.ContainerSpec{
Image: "foobar:1.2.3@sha256:deadbeef",
},
},
@ -86,7 +86,7 @@ func TestServiceUpdateResolveImageChanged(t *testing.T) {
spec := map[string]swarm.ServiceSpec{
"myservice": {
TaskTemplate: swarm.TaskSpec{
ContainerSpec: swarm.ContainerSpec{
ContainerSpec: &swarm.ContainerSpec{
Image: testcase.image,
},
},

View File

@ -128,7 +128,7 @@ func Service(
Labels: AddStackLabel(namespace, service.Deploy.Labels),
},
TaskTemplate: swarm.TaskSpec{
ContainerSpec: swarm.ContainerSpec{
ContainerSpec: &swarm.ContainerSpec{
Image: service.Image,
Command: service.Entrypoint,
Args: service.Command,

View File

@ -8,7 +8,6 @@ import (
"sort"
"strings"
"github.com/Sirupsen/logrus"
"github.com/docker/cli/cli/compose/interpolation"
"github.com/docker/cli/cli/compose/schema"
"github.com/docker/cli/cli/compose/template"
@ -19,6 +18,7 @@ import (
shellwords "github.com/mattn/go-shellwords"
"github.com/mitchellh/mapstructure"
"github.com/pkg/errors"
"github.com/sirupsen/logrus"
yaml "gopkg.in/yaml.v2"
)

View File

@ -3,7 +3,7 @@ package debug
import (
"os"
"github.com/Sirupsen/logrus"
"github.com/sirupsen/logrus"
)
// Enable sets the DEBUG env var to true

View File

@ -4,7 +4,7 @@ import (
"os"
"testing"
"github.com/Sirupsen/logrus"
"github.com/sirupsen/logrus"
)
func TestEnable(t *testing.T) {

View File

@ -5,10 +5,10 @@ import (
"os"
"path/filepath"
"github.com/Sirupsen/logrus"
cliconfig "github.com/docker/cli/cli/config"
"github.com/docker/cli/opts"
"github.com/docker/go-connections/tlsconfig"
"github.com/sirupsen/logrus"
"github.com/spf13/pflag"
)

View File

@ -10,7 +10,6 @@ import (
"path/filepath"
"time"
"github.com/Sirupsen/logrus"
"github.com/docker/cli/cli/command"
cliconfig "github.com/docker/cli/cli/config"
"github.com/docker/distribution/registry/client/auth"
@ -29,6 +28,7 @@ import (
"github.com/docker/notary/tuf/data"
"github.com/docker/notary/tuf/signed"
"github.com/pkg/errors"
"github.com/sirupsen/logrus"
)
var (

View File

@ -6,7 +6,6 @@ import (
"os"
"strings"
"github.com/Sirupsen/logrus"
"github.com/docker/cli/cli"
"github.com/docker/cli/cli/command"
"github.com/docker/cli/cli/command/commands"
@ -16,6 +15,7 @@ import (
"github.com/docker/docker/api/types/versions"
"github.com/docker/docker/client"
"github.com/docker/docker/pkg/term"
"github.com/sirupsen/logrus"
"github.com/spf13/cobra"
"github.com/spf13/pflag"
)

View File

@ -5,9 +5,9 @@ import (
"os"
"testing"
"github.com/Sirupsen/logrus"
"github.com/docker/cli/cli/command"
"github.com/docker/cli/cli/debug"
"github.com/sirupsen/logrus"
"github.com/stretchr/testify/assert"
)

View File

@ -56,7 +56,7 @@ func ReplicatedService(replicas uint64) func(*swarm.Service) {
// ServiceImage sets the service's image
func ServiceImage(image string) func(*swarm.Service) {
return func(service *swarm.Service) {
service.Spec.TaskTemplate = swarm.TaskSpec{ContainerSpec: swarm.ContainerSpec{Image: image}}
service.Spec.TaskTemplate = swarm.TaskSpec{ContainerSpec: &swarm.ContainerSpec{Image: image}}
}
}

View File

@ -140,7 +140,7 @@ func WithTaskSpec(specBuilders ...func(*swarm.TaskSpec)) func(*swarm.Task) {
// Any number of taskSpec function builder can be pass to augment it.
func TaskSpec(specBuilders ...func(*swarm.TaskSpec)) *swarm.TaskSpec {
taskSpec := &swarm.TaskSpec{
ContainerSpec: swarm.ContainerSpec{
ContainerSpec: &swarm.ContainerSpec{
Image: "myimage:mytag",
},
}

View File

@ -1,9 +1,6 @@
package client
// parse_logs.go contains utility helpers for getting information out of docker
// log lines. really, it only contains ParseDetails right now. maybe in the
// future there will be some desire to parse log messages back into a struct?
// that would go here if we did
/*Package logs contains tools for parsing docker log lines.
*/
package logs
import (
"net/url"
@ -12,12 +9,13 @@ import (
"github.com/pkg/errors"
)
// ParseLogDetails takes a details string of key value pairs in the form
// ParseLogDetails parses a string of key value pairs in the form
// "k=v,l=w", where the keys and values are url query escaped, and each pair
// is separated by a comma, returns a map. returns an error if the details
// string is not in a valid format
// the exact form of details encoding is implemented in
// api/server/httputils/write_log_stream.go
// is separated by a comma. Returns a map of the key value pairs on success,
// and an error if the details string is not in a valid format.
//
// The details string encoding is implemented in
// github.com/moby/moby/api/server/httputils/write_log_stream.go
func ParseLogDetails(details string) (map[string]string, error) {
pairs := strings.Split(details, ",")
detailsMap := make(map[string]string, len(pairs))

View File

@ -0,0 +1,33 @@
package logs
import (
"testing"
"github.com/pkg/errors"
"github.com/stretchr/testify/assert"
)
func TestParseLogDetails(t *testing.T) {
testCases := []struct {
line string
expected map[string]string
err error
}{
{"key=value", map[string]string{"key": "value"}, nil},
{"key1=value1,key2=value2", map[string]string{"key1": "value1", "key2": "value2"}, nil},
{"key+with+spaces=value%3Dequals,asdf%2C=", map[string]string{"key with spaces": "value=equals", "asdf,": ""}, nil},
{"key=,=nothing", map[string]string{"key": "", "": "nothing"}, nil},
{"=", map[string]string{"": ""}, nil},
{"errors", nil, errors.New("invalid details format")},
}
for _, testcase := range testCases {
t.Run(testcase.line, func(t *testing.T) {
actual, err := ParseLogDetails(testcase.line)
if testcase.err != nil {
assert.EqualError(t, err, testcase.err.Error())
return
}
assert.Equal(t, testcase.expected, actual)
})
}
}

View File

@ -1,56 +1,56 @@
github.com/Azure/go-ansiterm 388960b655244e76e24c75f48631564eaefade62
github.com/Microsoft/go-winio v0.4.2
github.com/Nvveen/Gotty a8b993ba6abdb0e0c12b0125c603323a71c7790c https://github.com/ijc25/Gotty
github.com/Sirupsen/logrus v0.11.0
github.com/agl/ed25519 d2b94fd789ea21d12fac1a4443dd3a3f79cda72c
github.com/Azure/go-ansiterm 19f72df4d05d31cbe1c56bfc8045c96babff6c7e
github.com/coreos/etcd 824277cb3a577a0e8c829ca9ec557b973fe06d20
github.com/cpuguy83/go-md2man a65d4d2de4d5f7c74868dfa9b202a3c8be315aaa
github.com/davecgh/go-spew 346938d642f2ec3594ed81d874461961cd0faa76
github.com/docker/distribution b38e5838b7b2f2ad48e06ec4b500011976080621
github.com/docker/docker d58ffa0364c04d03a8f25704d7f0489ee6cd9634
github.com/docker/distribution edc3ab29cdff8694dd6feb85cfeb4b5f1b38ed9c
github.com/docker/docker 84144a8c66c1bb2af8fa997288f51ef2719971b4
github.com/docker/docker-credential-helpers v0.5.1
# the docker/go package contains a customized version of canonical/json
# and is used by Notary. The package is periodically rebased on current Go versions.
github.com/docker/go d30aec9fd63c35133f8f79c3412ad91a3b08be06
github.com/docker/go-connections 3ede32e2033de7505e6500d6c868c2b9ed9f169d
github.com/docker/go-events 18b43f1bc85d9cdd42c05a6cd2d444c7a200a894
github.com/docker/go-events 9461782956ad83b30282bf90e31fa6a70c255ba9
github.com/docker/go-units 9e638d38cf6977a37a8ea0078f3ee75a7cdb2dd1
github.com/docker/libtrust 9cbd2a1374f46905c68a4eb3694a130610adc62a
github.com/docker/notary v0.4.2
github.com/docker/swarmkit 79381d0840be27f8b3f5c667b348a4467d866eeb
github.com/docker/notary v0.4.2-sirupsen https://github.com/simonferquel/notary.git
github.com/docker/swarmkit 0554c9bc9a485025e89b8e5c2c1f0d75961906a2
github.com/flynn-archive/go-shlex 3f9db97f856818214da2e1057f8ad84803971cff
github.com/gogo/protobuf 7efa791bd276fd4db00867cbd982b552627c24cb
github.com/gogo/protobuf v0.4
github.com/golang/protobuf 7a211bcf3bce0e3f1d74f9894916e6f116ae83b4
github.com/gotestyourself/gotestyourself v1.0.0
github.com/gorilla/context v1.1
github.com/gorilla/mux v1.1
github.com/gotestyourself/gotestyourself v1.0.0
github.com/inconshreveable/mousetrap 76626ae9c91c4f2a10f34cad8ce83ea42c93bb75
github.com/mattn/go-shellwords v1.0.3
github.com/Microsoft/go-winio v0.4.4
github.com/miekg/pkcs11 df8ae6ca730422dba20c768ff38ef7d79077a59f
github.com/mitchellh/mapstructure f3009df150dadf309fdee4a54ed65c124afad715
github.com/opencontainers/go-digest a6d0ee40d4207ea02364bd3b9e8e77b9159ba1eb
github.com/opencontainers/image-spec f03dbe35d449c54915d235f1a3cf8f585a24babe
github.com/opencontainers/runc 9c2d8d184e5da67c95d601382adf14862e4f2228 https://github.com/docker/runc.git
github.com/moby/buildkit da2b9dc7dab99e824b2b1067ad7d0523e32dd2d9 https://github.com/dmcgowan/buildkit.git
github.com/Nvveen/Gotty a8b993ba6abdb0e0c12b0125c603323a71c7790c https://github.com/ijc25/Gotty
github.com/opencontainers/go-digest 21dfd564fd89c944783d00d069f33e3e7123c448
github.com/opencontainers/image-spec v1.0.0
github.com/opencontainers/runc d40db12e72a40109dfcf28539f5ee0930d2f0277
github.com/pkg/errors 839d9e913e063e28dfd0e6c7b7512793e0a48be9
github.com/pmezard/go-difflib v1.0.0
github.com/russross/blackfriday 1d6b8e9301e720b08a8938b8c25c018285885438
github.com/shurcooL/sanitized_anchor_name 10ef21a441db47d8b13ebcc5fd2310f636973c77
github.com/sirupsen/logrus v1.0.1
github.com/spf13/cobra v1.5.1 https://github.com/dnephin/cobra.git
github.com/spf13/pflag 9ff6c6923cfffbcd502984b8e0c80539a94968b7
github.com/stevvooe/continuity cd7a8e21e2b6f84799f5dd4b65faf49c8d3ee02d
github.com/stretchr/testify 4d4bfba8f1d1027c4fdbe371823030df51419987
github.com/tonistiigi/fsutil 0ac4c11b053b9c5c7c47558f81f96c7100ce50fb
github.com/xeipuuv/gojsonpointer e0fe6f68307607d540ed8eac07a342c33fa1b54a
github.com/xeipuuv/gojsonreference e02fc20de94c78484cd5ffb007f8af96be030a45
github.com/xeipuuv/gojsonschema 93e72a773fade158921402d6a24c819b48aba29d
golang.org/x/crypto 3fbbcd23f1cb824e69491a5930cfeff09b12f4d2
golang.org/x/net 7dcfb8076726a3fdd9353b6b8a1f1b6be6811bd6
golang.org/x/sys 8f0908ab3b2457e2e15403d3697c9ef5cb4b57a9
golang.org/x/sync 450f422ab23cf9881c94e2db30cac0eb1b7cf80c
golang.org/x/sys 07c182904dbd53199946ba614a412c61d3c548f5
golang.org/x/text f72d8390a633d5dfb0cc84043294db9f6c935756
golang.org/x/time a4bde12657593d5e90d0533a3e4fd95e635124cb
google.golang.org/genproto d80a6e20e776b0b17a324d0ba1ab50a39c8e8944
google.golang.org/grpc v1.3.0
gopkg.in/yaml.v2 4c78c975fe7c825c6d1466c42be594d1d6f3aba6
github.com/tonistiigi/fsutil 0ac4c11b053b9c5c7c47558f81f96c7100ce50fb
github.com/stevvooe/continuity cd7a8e21e2b6f84799f5dd4b65faf49c8d3ee02d
golang.org/x/sync de49d9dcd27d4f764488181bea099dfe6179bcf0
vbom.ml/util 928aaa586d7718c70f4090ddf83f2b34c16fdc8d

View File

@ -7,3 +7,6 @@ For example the parser might receive "ESC, [, A" as a stream of three characters
The parser (parser.go) is a partial implementation of this state machine (http://vt100.net/emu/vt500_parser.png). There are also two event handler implementations, one for tests (test_event_handler.go) to validate that the expected events are being produced and called, the other is a Windows implementation (winterm/win_event_handler.go).
See parser_test.go for examples exercising the state machine and generating appropriate function calls.
-----
This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/). For more information see the [Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/) or contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with any additional questions or comments.

View File

@ -5,7 +5,7 @@ import (
"io/ioutil"
"os"
"github.com/Sirupsen/logrus"
"github.com/sirupsen/logrus"
)
var logger *logrus.Logger

View File

@ -9,7 +9,7 @@ import (
"strconv"
"github.com/Azure/go-ansiterm"
"github.com/Sirupsen/logrus"
"github.com/sirupsen/logrus"
)
var logger *logrus.Logger

View File

@ -23,6 +23,13 @@ type atomicBool int32
func (b *atomicBool) isSet() bool { return atomic.LoadInt32((*int32)(b)) != 0 }
func (b *atomicBool) setFalse() { atomic.StoreInt32((*int32)(b), 0) }
func (b *atomicBool) setTrue() { atomic.StoreInt32((*int32)(b), 1) }
func (b *atomicBool) swap(new bool) bool {
var newInt int32
if new {
newInt = 1
}
return atomic.SwapInt32((*int32)(b), newInt) == 1
}
const (
cFILE_SKIP_COMPLETION_PORT_ON_SUCCESS = 1
@ -71,7 +78,7 @@ func initIo() {
type win32File struct {
handle syscall.Handle
wg sync.WaitGroup
closing bool
closing atomicBool
readDeadline deadlineHandler
writeDeadline deadlineHandler
}
@ -107,9 +114,9 @@ func MakeOpenFile(h syscall.Handle) (io.ReadWriteCloser, error) {
// closeHandle closes the resources associated with a Win32 handle
func (f *win32File) closeHandle() {
if !f.closing {
// Atomically set that we are closing, releasing the resources only once.
if !f.closing.swap(true) {
// cancel all IO and wait for it to complete
f.closing = true
cancelIoEx(f.handle, nil)
f.wg.Wait()
// at this point, no new IO can start
@ -127,10 +134,10 @@ func (f *win32File) Close() error {
// prepareIo prepares for a new IO operation.
// The caller must call f.wg.Done() when the IO is finished, prior to Close() returning.
func (f *win32File) prepareIo() (*ioOperation, error) {
f.wg.Add(1)
if f.closing {
if f.closing.isSet() {
return nil, ErrFileClosed
}
f.wg.Add(1)
c := &ioOperation{}
c.ch = make(chan ioResult)
return c, nil
@ -159,7 +166,7 @@ func (f *win32File) asyncIo(c *ioOperation, d *deadlineHandler, bytes uint32, er
return int(bytes), err
}
if f.closing {
if f.closing.isSet() {
cancelIoEx(f.handle, &c.o)
}
@ -175,7 +182,7 @@ func (f *win32File) asyncIo(c *ioOperation, d *deadlineHandler, bytes uint32, er
case r = <-c.ch:
err = r.err
if err == syscall.ERROR_OPERATION_ABORTED {
if f.closing {
if f.closing.isSet() {
err = ErrFileClosed
}
}

View File

@ -1,41 +0,0 @@
package logrus
import (
"encoding/json"
"fmt"
)
type JSONFormatter struct {
// TimestampFormat sets the format used for marshaling timestamps.
TimestampFormat string
}
func (f *JSONFormatter) Format(entry *Entry) ([]byte, error) {
data := make(Fields, len(entry.Data)+3)
for k, v := range entry.Data {
switch v := v.(type) {
case error:
// Otherwise errors are ignored by `encoding/json`
// https://github.com/Sirupsen/logrus/issues/137
data[k] = v.Error()
default:
data[k] = v
}
}
prefixFieldClashes(data)
timestampFormat := f.TimestampFormat
if timestampFormat == "" {
timestampFormat = DefaultTimestampFormat
}
data["time"] = entry.Time.Format(timestampFormat)
data["msg"] = entry.Message
data["level"] = entry.Level.String()
serialized, err := json.Marshal(data)
if err != nil {
return nil, fmt.Errorf("Failed to marshal fields to JSON, %v", err)
}
return append(serialized, '\n'), nil
}

View File

@ -1,15 +0,0 @@
// +build solaris,!appengine
package logrus
import (
"os"
"golang.org/x/sys/unix"
)
// IsTerminal returns true if the given file descriptor is a terminal.
func IsTerminal() bool {
_, err := unix.IoctlGetTermios(int(os.Stdout.Fd()), unix.TCGETA)
return err == nil
}

View File

@ -1,27 +0,0 @@
// Based on ssh/terminal:
// Copyright 2011 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build windows,!appengine
package logrus
import (
"syscall"
"unsafe"
)
var kernel32 = syscall.NewLazyDLL("kernel32.dll")
var (
procGetConsoleMode = kernel32.NewProc("GetConsoleMode")
)
// IsTerminal returns true if stderr's file descriptor is a terminal.
func IsTerminal() bool {
fd := syscall.Stderr
var st uint32
r, _, e := syscall.Syscall(procGetConsoleMode.Addr(), 2, uintptr(fd), uintptr(unsafe.Pointer(&st)), 0)
return r != 0 && e == 0
}

View File

@ -76,8 +76,7 @@ may be the better choice.
For those who have previously deployed their own registry based on the Registry
1.0 implementation and wish to deploy a Registry 2.0 while retaining images,
data migration is required. A tool to assist with migration efforts has been
created. For more information see [docker/migrator]
(https://github.com/docker/migrator).
created. For more information see [docker/migrator](https://github.com/docker/migrator).
## Contribute

View File

@ -152,7 +152,7 @@ type BlobProvider interface {
// BlobServer can serve blobs via http.
type BlobServer interface {
// ServeBlob attempts to serve the blob, identifed by dgst, via http. The
// ServeBlob attempts to serve the blob, identified by dgst, via http. The
// service may decide to redirect the client elsewhere or serve the data
// directly.
//

View File

@ -64,7 +64,7 @@
// Note that this only affects the new context, the previous context, with the
// version field, can be used independently. Put another way, the new logger,
// added to the request context, is unique to that context and can have
// request scoped varaibles.
// request scoped variables.
//
// HTTP Requests
//

View File

@ -8,9 +8,9 @@ import (
"sync"
"time"
log "github.com/Sirupsen/logrus"
"github.com/docker/distribution/uuid"
"github.com/gorilla/mux"
log "github.com/sirupsen/logrus"
)
// Common errors used with this package.

View File

@ -3,7 +3,7 @@ package context
import (
"fmt"
"github.com/Sirupsen/logrus"
"github.com/sirupsen/logrus"
"runtime"
)

View File

@ -77,7 +77,7 @@ func (err ErrManifestUnknownRevision) Error() string {
type ErrManifestUnverified struct{}
func (ErrManifestUnverified) Error() string {
return fmt.Sprintf("unverified manifest")
return "unverified manifest"
}
// ErrManifestVerification provides a type to collect errors encountered

View File

@ -15,7 +15,7 @@
// tag := /[\w][\w.-]{0,127}/
//
// digest := digest-algorithm ":" digest-hex
// digest-algorithm := digest-algorithm-component [ digest-algorithm-separator digest-algorithm-component ]
// digest-algorithm := digest-algorithm-component [ digest-algorithm-separator digest-algorithm-component ]*
// digest-algorithm-separator := /[+.-_]/
// digest-algorithm-component := /[A-Za-z][A-Za-z0-9]*/
// digest-hex := /[0-9a-fA-F]{32,}/ ; At least 128 bit digest value

View File

@ -1,10 +1,9 @@
package v2
import (
"net"
"fmt"
"net/http"
"net/url"
"strconv"
"strings"
"github.com/docker/distribution/reference"
@ -48,66 +47,42 @@ func NewURLBuilderFromString(root string, relative bool) (*URLBuilder, error) {
// NewURLBuilderFromRequest uses information from an *http.Request to
// construct the root url.
func NewURLBuilderFromRequest(r *http.Request, relative bool) *URLBuilder {
var scheme string
forwardedProto := r.Header.Get("X-Forwarded-Proto")
// TODO: log the error
forwardedHeader, _, _ := parseForwardedHeader(r.Header.Get("Forwarded"))
switch {
case len(forwardedProto) > 0:
scheme = forwardedProto
case len(forwardedHeader["proto"]) > 0:
scheme = forwardedHeader["proto"]
case r.TLS != nil:
scheme = "https"
case len(r.URL.Scheme) > 0:
scheme = r.URL.Scheme
default:
var (
scheme = "http"
host = r.Host
)
if r.TLS != nil {
scheme = "https"
} else if len(r.URL.Scheme) > 0 {
scheme = r.URL.Scheme
}
host := r.Host
if forwardedHost := r.Header.Get("X-Forwarded-Host"); len(forwardedHost) > 0 {
// According to the Apache mod_proxy docs, X-Forwarded-Host can be a
// comma-separated list of hosts, to which each proxy appends the
// requested host. We want to grab the first from this comma-separated
// list.
hosts := strings.SplitN(forwardedHost, ",", 2)
host = strings.TrimSpace(hosts[0])
} else if addr, exists := forwardedHeader["for"]; exists {
host = addr
} else if h, exists := forwardedHeader["host"]; exists {
host = h
}
portLessHost, port := host, ""
if !isIPv6Address(portLessHost) {
// with go 1.6, this would treat the last part of IPv6 address as a port
portLessHost, port, _ = net.SplitHostPort(host)
}
if forwardedPort := r.Header.Get("X-Forwarded-Port"); len(port) == 0 && len(forwardedPort) > 0 {
ports := strings.SplitN(forwardedPort, ",", 2)
forwardedPort = strings.TrimSpace(ports[0])
if _, err := strconv.ParseInt(forwardedPort, 10, 32); err == nil {
port = forwardedPort
// Handle fowarded headers
// Prefer "Forwarded" header as defined by rfc7239 if given
// see https://tools.ietf.org/html/rfc7239
if forwarded := r.Header.Get("Forwarded"); len(forwarded) > 0 {
forwardedHeader, _, err := parseForwardedHeader(forwarded)
if err == nil {
if fproto := forwardedHeader["proto"]; len(fproto) > 0 {
scheme = fproto
}
if fhost := forwardedHeader["host"]; len(fhost) > 0 {
host = fhost
}
}
}
if len(portLessHost) > 0 {
host = portLessHost
}
if len(port) > 0 {
// remove enclosing brackets of ipv6 address otherwise they will be duplicated
if len(host) > 1 && host[0] == '[' && host[len(host)-1] == ']' {
host = host[1 : len(host)-1]
} else {
if forwardedProto := r.Header.Get("X-Forwarded-Proto"); len(forwardedProto) > 0 {
scheme = forwardedProto
}
if forwardedHost := r.Header.Get("X-Forwarded-Host"); len(forwardedHost) > 0 {
// According to the Apache mod_proxy docs, X-Forwarded-Host can be a
// comma-separated list of hosts, to which each proxy appends the
// requested host. We want to grab the first from this comma-separated
// list.
hosts := strings.SplitN(forwardedHost, ",", 2)
host = strings.TrimSpace(hosts[0])
}
// JoinHostPort properly encloses ipv6 addresses in square brackets
host = net.JoinHostPort(host, port)
} else if isIPv6Address(host) && host[0] != '[' {
// ipv6 needs to be enclosed in square brackets in urls
host = "[" + host + "]"
}
basePath := routeDescriptorsMap[RouteNameBase].Path
@ -175,6 +150,8 @@ func (ub *URLBuilder) BuildManifestURL(ref reference.Named) (string, error) {
tagOrDigest = v.Tag()
case reference.Digested:
tagOrDigest = v.Digest().String()
default:
return "", fmt.Errorf("reference must have a tag or digest")
}
manifestURL, err := route.URL("name", ref.Name(), "reference", tagOrDigest)
@ -287,28 +264,3 @@ func appendValues(u string, values ...url.Values) string {
return appendValuesURL(up, values...).String()
}
// isIPv6Address returns true if given string is a valid IPv6 address. No port is allowed. The address may be
// enclosed in square brackets.
func isIPv6Address(host string) bool {
if len(host) > 1 && host[0] == '[' && host[len(host)-1] == ']' {
host = host[1 : len(host)-1]
}
// The IPv6 scoped addressing zone identifier starts after the last percent sign.
if i := strings.LastIndexByte(host, '%'); i > 0 {
host = host[:i]
}
ip := net.ParseIP(host)
if ip == nil {
return false
}
if ip.To16() == nil {
return false
}
if ip.To4() == nil {
return true
}
// dot can be present in ipv4-mapped address, it needs to come after a colon though
i := strings.IndexAny(host, ":.")
return i >= 0 && host[i] == ':'
}

View File

@ -10,10 +10,10 @@ import (
"sync"
"time"
"github.com/Sirupsen/logrus"
"github.com/docker/distribution/registry/client"
"github.com/docker/distribution/registry/client/auth/challenge"
"github.com/docker/distribution/registry/client/transport"
"github.com/sirupsen/logrus"
)
var (

View File

@ -1,19 +1,21 @@
github.com/Azure/azure-sdk-for-go c6f0533defaaaa26ea4dff3c9774e36033088112
github.com/Sirupsen/logrus d26492970760ca5d33129d2d799e34be5c4782eb
github.com/Azure/azure-sdk-for-go 088007b3b08cc02b27f2eadfdcd870958460ce7e
github.com/Azure/go-autorest ec5f4903f77ed9927ac95b19ab8e44ada64c1356
github.com/sirupsen/logrus 3d4380f53a34dcdc95f0c1db702615992b38d9a4
github.com/aws/aws-sdk-go c6fc52983ea2375810aa38ddb5370e9cdf611716
github.com/bshuster-repo/logrus-logstash-hook 5f729f2fb50a301153cae84ff5c58981d51c095a
github.com/bshuster-repo/logrus-logstash-hook d2c0ecc1836d91814e15e23bb5dc309c3ef51f4a
github.com/bugsnag/bugsnag-go b1d153021fcd90ca3f080db36bec96dc690fb274
github.com/bugsnag/osext 0dd3f918b21bec95ace9dc86c7e70266cfc5c702
github.com/bugsnag/panicwrap e2c28503fcd0675329da73bf48b33404db873782
github.com/denverdino/aliyungo afedced274aa9a7fcdd47ac97018f0f8db4e5de2
github.com/dgrijalva/jwt-go a601269ab70c205d26370c16f7c81e9017c14e04
github.com/docker/goamz f0a21f5b2e12f83a505ecf79b633bb2035cf6f85
github.com/docker/libtrust fa567046d9b14f6aa788882a950d69651d230b21
github.com/garyburd/redigo 535138d7bcd717d6531c701ef5933d98b1866257
github.com/go-ini/ini 2ba15ac2dc9cdf88c110ec2dc0ced7fa45f5678c
github.com/golang/protobuf/proto 8d92cf5fc15a4382f8964b08e1f42a75c0591aa3
github.com/golang/protobuf 8d92cf5fc15a4382f8964b08e1f42a75c0591aa3
github.com/gorilla/context 14f550f51af52180c2eefed15e5fd18d63c0a64a
github.com/gorilla/handlers 60c7bfde3e33c201519a200a4507a158cc03a17b
github.com/gorilla/mux e444e69cbd2e2e3e0749a2f3c717cec491552bbf
github.com/gorilla/mux 599cba5e7b6137d46ddf58fb1765f5d928e69604
github.com/inconshreveable/mousetrap 76626ae9c91c4f2a10f34cad8ce83ea42c93bb75
github.com/jmespath/go-jmespath bd40a432e4c76585ef6b72d3fd96fb9b6dc7b68d
github.com/miekg/dns 271c58e0c14f552178ea321a545ff9af38930f39
@ -21,15 +23,15 @@ github.com/mitchellh/mapstructure 482a9fd5fa83e8c4e7817413b80f3eb8feec03ef
github.com/ncw/swift b964f2ca856aac39885e258ad25aec08d5f64ee6
github.com/spf13/cobra 312092086bed4968099259622145a0c9ae280064
github.com/spf13/pflag 5644820622454e71517561946e3d94b9f9db6842
github.com/stevvooe/resumable 51ad44105773cafcbe91927f70ac68e1bf78f8b4
github.com/xenolf/lego/acme a9d8cec0e6563575e5868a005359ac97911b5985
github.com/stevvooe/resumable 2aaf90b2ceea5072cb503ef2a620b08ff3119870
github.com/xenolf/lego a9d8cec0e6563575e5868a005359ac97911b5985
github.com/yvasiyarov/go-metrics 57bccd1ccd43f94bb17fdd8bf3007059b802f85e
github.com/yvasiyarov/gorelic a9bba5b9ab508a086f9a12b8c51fab68478e2128
github.com/yvasiyarov/newrelic_platform_go b21fdbd4370f3717f3bbd2bf41c223bc273068e6
golang.org/x/crypto c10c31b5e94b6f7a0283272dc2bb27163dcea24b
golang.org/x/net 4876518f9e71663000c348837735820161a42df7
golang.org/x/oauth2 045497edb6234273d67dbc25da3f2ddbc4c4cacf
golang.org/x/time/rate a4bde12657593d5e90d0533a3e4fd95e635124cb
golang.org/x/time a4bde12657593d5e90d0533a3e4fd95e635124cb
google.golang.org/api 9bf6e6e569ff057f75d9604a46c52928f17d2b54
google.golang.org/appengine 12d5545dc1cfa6047a286d5e853841b6471f4c19
google.golang.org/cloud 975617b05ea8a58727e6c1a06b6161ff4185a9f2

View File

@ -51,7 +51,7 @@ Moby is NOT recommended for:
- Application developers looking for an easy way to run their applications in containers. We recommend Docker CE instead.
- Enterprise IT and development teams looking for a ready-to-use, commercially supported container platform. We recommend Docker EE instead.
- Anyone curious about containers and looking for an easy way to learn. We recommend the docker.com website instead.
- Anyone curious about containers and looking for an easy way to learn. We recommend the [docker.com](https://www.docker.com/) website instead.
# Transitioning to Moby

View File

@ -1,65 +1,11 @@
package api
import (
"encoding/json"
"encoding/pem"
"fmt"
"os"
"path/filepath"
"github.com/docker/docker/pkg/ioutils"
"github.com/docker/docker/pkg/system"
"github.com/docker/libtrust"
)
// Common constants for daemon and client.
const (
// DefaultVersion of Current REST API
DefaultVersion string = "1.31"
DefaultVersion string = "1.32"
// NoBaseImageSpecifier is the symbol used by the FROM
// command to specify that no base image is to be used.
NoBaseImageSpecifier string = "scratch"
)
// LoadOrCreateTrustKey attempts to load the libtrust key at the given path,
// otherwise generates a new one
func LoadOrCreateTrustKey(trustKeyPath string) (libtrust.PrivateKey, error) {
err := system.MkdirAll(filepath.Dir(trustKeyPath), 0700, "")
if err != nil {
return nil, err
}
trustKey, err := libtrust.LoadKeyFile(trustKeyPath)
if err == libtrust.ErrKeyFileDoesNotExist {
trustKey, err = libtrust.GenerateECP256PrivateKey()
if err != nil {
return nil, fmt.Errorf("Error generating key: %s", err)
}
encodedKey, err := serializePrivateKey(trustKey, filepath.Ext(trustKeyPath))
if err != nil {
return nil, fmt.Errorf("Error serializing key: %s", err)
}
if err := ioutils.AtomicWriteFile(trustKeyPath, encodedKey, os.FileMode(0600)); err != nil {
return nil, fmt.Errorf("Error saving key file: %s", err)
}
} else if err != nil {
return nil, fmt.Errorf("Error loading key file %s: %s", trustKeyPath, err)
}
return trustKey, nil
}
func serializePrivateKey(key libtrust.PrivateKey, ext string) (encoded []byte, err error) {
if ext == ".json" || ext == ".jwk" {
encoded, err = json.Marshal(key)
if err != nil {
return nil, fmt.Errorf("unable to encode private key JWK: %s", err)
}
} else {
pemBlock, err := key.PEMBlock()
if err != nil {
return nil, fmt.Errorf("unable to encode private key PEM: %s", err)
}
encoded = pem.EncodeToMemory(pemBlock)
}
return
}

View File

@ -1,9 +0,0 @@
package api
import "regexp"
// RestrictedNameChars collects the characters allowed to represent a name, normally used to validate container and volume names.
const RestrictedNameChars = `[a-zA-Z0-9][a-zA-Z0-9_.-]`
// RestrictedNamePattern is a regular expression to validate names against the collection of restricted characters.
var RestrictedNamePattern = regexp.MustCompile(`^` + RestrictedNameChars + `+$`)

View File

@ -181,7 +181,7 @@ type ImageBuildOptions struct {
SessionID string
// TODO @jhowardmsft LCOW Support: This will require extending to include
// `Platform string`, but is ommited for now as it's hard-coded temporarily
// `Platform string`, but is omitted for now as it's hard-coded temporarily
// to avoid API changes.
}

View File

@ -23,41 +23,46 @@ func (i Isolation) IsDefault() bool {
// IpcMode represents the container ipc stack.
type IpcMode string
// IsPrivate indicates whether the container uses its private ipc stack.
// IsPrivate indicates whether the container uses its own private ipc namespace which can not be shared.
func (n IpcMode) IsPrivate() bool {
return !(n.IsHost() || n.IsContainer())
return n == "private"
}
// IsHost indicates whether the container uses the host's ipc stack.
// IsHost indicates whether the container shares the host's ipc namespace.
func (n IpcMode) IsHost() bool {
return n == "host"
}
// IsContainer indicates whether the container uses a container's ipc stack.
// IsShareable indicates whether the container's ipc namespace can be shared with another container.
func (n IpcMode) IsShareable() bool {
return n == "shareable"
}
// IsContainer indicates whether the container uses another container's ipc namespace.
func (n IpcMode) IsContainer() bool {
parts := strings.SplitN(string(n), ":", 2)
return len(parts) > 1 && parts[0] == "container"
}
// Valid indicates whether the ipc stack is valid.
// IsNone indicates whether container IpcMode is set to "none".
func (n IpcMode) IsNone() bool {
return n == "none"
}
// IsEmpty indicates whether container IpcMode is empty
func (n IpcMode) IsEmpty() bool {
return n == ""
}
// Valid indicates whether the ipc mode is valid.
func (n IpcMode) Valid() bool {
parts := strings.Split(string(n), ":")
switch mode := parts[0]; mode {
case "", "host":
case "container":
if len(parts) != 2 || parts[1] == "" {
return false
}
default:
return false
}
return true
return n.IsEmpty() || n.IsNone() || n.IsPrivate() || n.IsHost() || n.IsShareable() || n.IsContainer()
}
// Container returns the name of the container ipc stack is going to be used.
func (n IpcMode) Container() string {
parts := strings.SplitN(string(n), ":", 2)
if len(parts) > 1 {
if len(parts) > 1 && parts[0] == "container" {
return parts[1]
}
return ""

View File

@ -19,6 +19,8 @@ const (
NodeEventType = "node"
// SecretEventType is the event type that secrets generate
SecretEventType = "secret"
// ConfigEventType is the event type that configs generate
ConfigEventType = "config"
)
// Actor describes something that generates events,

View File

@ -1,38 +1,45 @@
// Package filters provides helper function to parse and handle command line
// filter, used for example in docker ps or docker images commands.
/*Package filters provides tools for encoding a mapping of keys to a set of
multiple values.
*/
package filters
import (
"encoding/json"
"errors"
"fmt"
"regexp"
"strings"
"github.com/docker/docker/api/types/versions"
)
// Args stores filter arguments as map key:{map key: bool}.
// It contains an aggregation of the map of arguments (which are in the form
// of -f 'key=value') based on the key, and stores values for the same key
// in a map with string keys and boolean values.
// e.g given -f 'label=label1=1' -f 'label=label2=2' -f 'image.name=ubuntu'
// the args will be {"image.name":{"ubuntu":true},"label":{"label1=1":true,"label2=2":true}}
// Args stores a mapping of keys to a set of multiple values.
type Args struct {
fields map[string]map[string]bool
}
// NewArgs initializes a new Args struct.
func NewArgs() Args {
return Args{fields: map[string]map[string]bool{}}
// KeyValuePair are used to initialize a new Args
type KeyValuePair struct {
Key string
Value string
}
// ParseFlag parses the argument to the filter flag. Like
// Arg creates a new KeyValuePair for initializing Args
func Arg(key, value string) KeyValuePair {
return KeyValuePair{Key: key, Value: value}
}
// NewArgs returns a new Args populated with the initial args
func NewArgs(initialArgs ...KeyValuePair) Args {
args := Args{fields: map[string]map[string]bool{}}
for _, arg := range initialArgs {
args.Add(arg.Key, arg.Value)
}
return args
}
// ParseFlag parses a key=value string and adds it to an Args.
//
// `docker ps -f 'created=today' -f 'image.name=ubuntu*'`
//
// If prev map is provided, then it is appended to, and returned. By default a new
// map is created.
// Deprecated: Use Args.Add()
func ParseFlag(arg string, prev Args) (Args, error) {
filters := prev
if len(arg) == 0 {
@ -53,74 +60,95 @@ func ParseFlag(arg string, prev Args) (Args, error) {
return filters, nil
}
// ErrBadFormat is an error returned in case of bad format for a filter.
// ErrBadFormat is an error returned when a filter is not in the form key=value
//
// Deprecated: this error will be removed in a future version
var ErrBadFormat = errors.New("bad format of filter (expected name=value)")
// ToParam packs the Args into a string for easy transport from client to server.
// ToParam encodes the Args as args JSON encoded string
//
// Deprecated: use ToJSON
func ToParam(a Args) (string, error) {
// this way we don't URL encode {}, just empty space
return ToJSON(a)
}
// MarshalJSON returns a JSON byte representation of the Args
func (args Args) MarshalJSON() ([]byte, error) {
if len(args.fields) == 0 {
return []byte{}, nil
}
return json.Marshal(args.fields)
}
// ToJSON returns the Args as a JSON encoded string
func ToJSON(a Args) (string, error) {
if a.Len() == 0 {
return "", nil
}
buf, err := json.Marshal(a.fields)
if err != nil {
return "", err
}
return string(buf), nil
buf, err := json.Marshal(a)
return string(buf), err
}
// ToParamWithVersion packs the Args into a string for easy transport from client to server.
// The generated string will depend on the specified version (corresponding to the API version).
// ToParamWithVersion encodes Args as a JSON string. If version is less than 1.22
// then the encoded format will use an older legacy format where the values are a
// list of strings, instead of a set.
//
// Deprecated: Use ToJSON
func ToParamWithVersion(version string, a Args) (string, error) {
// this way we don't URL encode {}, just empty space
if a.Len() == 0 {
return "", nil
}
// for daemons older than v1.10, filter must be of the form map[string][]string
var buf []byte
var err error
if version != "" && versions.LessThan(version, "1.22") {
buf, err = json.Marshal(convertArgsToSlice(a.fields))
} else {
buf, err = json.Marshal(a.fields)
buf, err := json.Marshal(convertArgsToSlice(a.fields))
return string(buf), err
}
if err != nil {
return "", err
}
return string(buf), nil
return ToJSON(a)
}
// FromParam unpacks the filter Args.
// FromParam decodes a JSON encoded string into Args
//
// Deprecated: use FromJSON
func FromParam(p string) (Args, error) {
if len(p) == 0 {
return NewArgs(), nil
}
r := strings.NewReader(p)
d := json.NewDecoder(r)
m := map[string]map[string]bool{}
if err := d.Decode(&m); err != nil {
r.Seek(0, 0)
// Allow parsing old arguments in slice format.
// Because other libraries might be sending them in this format.
deprecated := map[string][]string{}
if deprecatedErr := d.Decode(&deprecated); deprecatedErr == nil {
m = deprecatedArgs(deprecated)
} else {
return NewArgs(), err
}
}
return Args{m}, nil
return FromJSON(p)
}
// Get returns the list of values associates with a field.
// It returns a slice of strings to keep backwards compatibility with old code.
func (filters Args) Get(field string) []string {
values := filters.fields[field]
// FromJSON decodes a JSON encoded string into Args
func FromJSON(p string) (Args, error) {
args := NewArgs()
if p == "" {
return args, nil
}
raw := []byte(p)
err := json.Unmarshal(raw, &args)
if err == nil {
return args, nil
}
// Fallback to parsing arguments in the legacy slice format
deprecated := map[string][]string{}
if legacyErr := json.Unmarshal(raw, &deprecated); legacyErr != nil {
return args, err
}
args.fields = deprecatedArgs(deprecated)
return args, nil
}
// UnmarshalJSON populates the Args from JSON encode bytes
func (args Args) UnmarshalJSON(raw []byte) error {
if len(raw) == 0 {
return nil
}
return json.Unmarshal(raw, &args.fields)
}
// Get returns the list of values associated with the key
func (args Args) Get(key string) []string {
values := args.fields[key]
if values == nil {
return make([]string, 0)
}
@ -131,37 +159,34 @@ func (filters Args) Get(field string) []string {
return slice
}
// Add adds a new value to a filter field.
func (filters Args) Add(name, value string) {
if _, ok := filters.fields[name]; ok {
filters.fields[name][value] = true
// Add a new value to the set of values
func (args Args) Add(key, value string) {
if _, ok := args.fields[key]; ok {
args.fields[key][value] = true
} else {
filters.fields[name] = map[string]bool{value: true}
args.fields[key] = map[string]bool{value: true}
}
}
// Del removes a value from a filter field.
func (filters Args) Del(name, value string) {
if _, ok := filters.fields[name]; ok {
delete(filters.fields[name], value)
if len(filters.fields[name]) == 0 {
delete(filters.fields, name)
// Del removes a value from the set
func (args Args) Del(key, value string) {
if _, ok := args.fields[key]; ok {
delete(args.fields[key], value)
if len(args.fields[key]) == 0 {
delete(args.fields, key)
}
}
}
// Len returns the number of fields in the arguments.
func (filters Args) Len() int {
return len(filters.fields)
// Len returns the number of keys in the mapping
func (args Args) Len() int {
return len(args.fields)
}
// MatchKVList returns true if the values for the specified field matches the ones
// from the sources.
// e.g. given Args are {'label': {'label1=1','label2=1'}, 'image.name', {'ubuntu'}},
// field is 'label' and sources are {'label1': '1', 'label2': '2'}
// it returns true.
func (filters Args) MatchKVList(field string, sources map[string]string) bool {
fieldValues := filters.fields[field]
// MatchKVList returns true if all the pairs in sources exist as key=value
// pairs in the mapping at key, or if there are no values at key.
func (args Args) MatchKVList(key string, sources map[string]string) bool {
fieldValues := args.fields[key]
//do not filter if there is no filter set or cannot determine filter
if len(fieldValues) == 0 {
@ -172,8 +197,8 @@ func (filters Args) MatchKVList(field string, sources map[string]string) bool {
return false
}
for name2match := range fieldValues {
testKV := strings.SplitN(name2match, "=", 2)
for value := range fieldValues {
testKV := strings.SplitN(value, "=", 2)
v, ok := sources[testKV[0]]
if !ok {
@ -187,16 +212,13 @@ func (filters Args) MatchKVList(field string, sources map[string]string) bool {
return true
}
// Match returns true if the values for the specified field matches the source string
// e.g. given Args are {'label': {'label1=1','label2=1'}, 'image.name', {'ubuntu'}},
// field is 'image.name' and source is 'ubuntu'
// it returns true.
func (filters Args) Match(field, source string) bool {
if filters.ExactMatch(field, source) {
// Match returns true if any of the values at key match the source string
func (args Args) Match(field, source string) bool {
if args.ExactMatch(field, source) {
return true
}
fieldValues := filters.fields[field]
fieldValues := args.fields[field]
for name2match := range fieldValues {
match, err := regexp.MatchString(name2match, source)
if err != nil {
@ -209,9 +231,9 @@ func (filters Args) Match(field, source string) bool {
return false
}
// ExactMatch returns true if the source matches exactly one of the filters.
func (filters Args) ExactMatch(field, source string) bool {
fieldValues, ok := filters.fields[field]
// ExactMatch returns true if the source matches exactly one of the values.
func (args Args) ExactMatch(key, source string) bool {
fieldValues, ok := args.fields[key]
//do not filter if there is no filter set or cannot determine filter
if !ok || len(fieldValues) == 0 {
return true
@ -221,14 +243,15 @@ func (filters Args) ExactMatch(field, source string) bool {
return fieldValues[source]
}
// UniqueExactMatch returns true if there is only one filter and the source matches exactly this one.
func (filters Args) UniqueExactMatch(field, source string) bool {
fieldValues := filters.fields[field]
// UniqueExactMatch returns true if there is only one value and the source
// matches exactly the value.
func (args Args) UniqueExactMatch(key, source string) bool {
fieldValues := args.fields[key]
//do not filter if there is no filter set or cannot determine filter
if len(fieldValues) == 0 {
return true
}
if len(filters.fields[field]) != 1 {
if len(args.fields[key]) != 1 {
return false
}
@ -236,14 +259,14 @@ func (filters Args) UniqueExactMatch(field, source string) bool {
return fieldValues[source]
}
// FuzzyMatch returns true if the source matches exactly one of the filters,
// or the source has one of the filters as a prefix.
func (filters Args) FuzzyMatch(field, source string) bool {
if filters.ExactMatch(field, source) {
// FuzzyMatch returns true if the source matches exactly one value, or the
// source has one of the values as a prefix.
func (args Args) FuzzyMatch(key, source string) bool {
if args.ExactMatch(key, source) {
return true
}
fieldValues := filters.fields[field]
fieldValues := args.fields[key]
for prefix := range fieldValues {
if strings.HasPrefix(source, prefix) {
return true
@ -252,30 +275,47 @@ func (filters Args) FuzzyMatch(field, source string) bool {
return false
}
// Include returns true if the name of the field to filter is in the filters.
func (filters Args) Include(field string) bool {
_, ok := filters.fields[field]
// Include returns true if the key exists in the mapping
//
// Deprecated: use Contains
func (args Args) Include(field string) bool {
_, ok := args.fields[field]
return ok
}
// Validate ensures that all the fields in the filter are valid.
// It returns an error as soon as it finds an invalid field.
func (filters Args) Validate(accepted map[string]bool) error {
for name := range filters.fields {
// Contains returns true if the key exists in the mapping
func (args Args) Contains(field string) bool {
_, ok := args.fields[field]
return ok
}
type invalidFilter string
func (e invalidFilter) Error() string {
return "Invalid filter '" + string(e) + "'"
}
func (invalidFilter) InvalidParameter() {}
// Validate compared the set of accepted keys against the keys in the mapping.
// An error is returned if any mapping keys are not in the accepted set.
func (args Args) Validate(accepted map[string]bool) error {
for name := range args.fields {
if !accepted[name] {
return fmt.Errorf("Invalid filter '%s'", name)
return invalidFilter(name)
}
}
return nil
}
// WalkValues iterates over the list of filtered values for a field.
// It stops the iteration if it finds an error and it returns that error.
func (filters Args) WalkValues(field string, op func(value string) error) error {
if _, ok := filters.fields[field]; !ok {
// WalkValues iterates over the list of values for a key in the mapping and calls
// op() for each value. If op returns an error the iteration stops and the
// error is returned.
func (args Args) WalkValues(field string, op func(value string) error) error {
if _, ok := args.fields[field]; !ok {
return nil
}
for v := range filters.fields[field] {
for v := range args.fields[field] {
if err := op(v); err != nil {
return err
}

View File

@ -15,6 +15,8 @@ const (
TypeVolume Type = "volume"
// TypeTmpfs is the type for mounting tmpfs
TypeTmpfs Type = "tmpfs"
// TypeNamedPipe is the type for mounting Windows named pipes
TypeNamedPipe Type = "npipe"
)
// Mount represents a mount (volume).
@ -65,7 +67,7 @@ var Propagations = []Propagation{
type Consistency string
const (
// ConsistencyFull guarantees bind-mount-like consistency
// ConsistencyFull guarantees bind mount-like consistency
ConsistencyFull Consistency = "consistent"
// ConsistencyCached mounts can cache read data and FS structure
ConsistencyCached Consistency = "cached"

View File

@ -11,7 +11,7 @@ type Plugin struct {
// Required: true
Config PluginConfig `json:"Config"`
// True when the plugin is running. False when the plugin is not running, only installed.
// True if the plugin is running. False if the plugin is not running, only installed.
// Required: true
Enabled bool `json:"Enabled"`

View File

@ -9,14 +9,6 @@ import (
// PluginsListResponse contains the response for the Engine API
type PluginsListResponse []*Plugin
const (
authzDriver = "AuthzDriver"
graphDriver = "GraphDriver"
ipamDriver = "IpamDriver"
networkDriver = "NetworkDriver"
volumeDriver = "VolumeDriver"
)
// UnmarshalJSON implements json.Unmarshaler for PluginInterfaceType
func (t *PluginInterfaceType) UnmarshalJSON(p []byte) error {
versionIndex := len(p)

View File

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

View File

@ -0,0 +1,3 @@
//go:generate protoc -I . --gogofast_out=import_path=github.com/docker/docker/api/types/swarm/runtime:. plugin.proto
package runtime

View File

@ -0,0 +1,712 @@
// Code generated by protoc-gen-gogo.
// source: plugin.proto
// DO NOT EDIT!
/*
Package runtime is a generated protocol buffer package.
It is generated from these files:
plugin.proto
It has these top-level messages:
PluginSpec
PluginPrivilege
*/
package runtime
import proto "github.com/gogo/protobuf/proto"
import fmt "fmt"
import math "math"
import io "io"
// Reference imports to suppress errors if they are not otherwise used.
var _ = proto.Marshal
var _ = fmt.Errorf
var _ = math.Inf
// This is a compile-time assertion to ensure that this generated file
// is compatible with the proto package it is being compiled against.
// A compilation error at this line likely means your copy of the
// proto package needs to be updated.
const _ = proto.GoGoProtoPackageIsVersion2 // please upgrade the proto package
// PluginSpec defines the base payload which clients can specify for creating
// a service with the plugin runtime.
type PluginSpec struct {
Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"`
Remote string `protobuf:"bytes,2,opt,name=remote,proto3" json:"remote,omitempty"`
Privileges []*PluginPrivilege `protobuf:"bytes,3,rep,name=privileges" json:"privileges,omitempty"`
Disabled bool `protobuf:"varint,4,opt,name=disabled,proto3" json:"disabled,omitempty"`
}
func (m *PluginSpec) Reset() { *m = PluginSpec{} }
func (m *PluginSpec) String() string { return proto.CompactTextString(m) }
func (*PluginSpec) ProtoMessage() {}
func (*PluginSpec) Descriptor() ([]byte, []int) { return fileDescriptorPlugin, []int{0} }
func (m *PluginSpec) GetName() string {
if m != nil {
return m.Name
}
return ""
}
func (m *PluginSpec) GetRemote() string {
if m != nil {
return m.Remote
}
return ""
}
func (m *PluginSpec) GetPrivileges() []*PluginPrivilege {
if m != nil {
return m.Privileges
}
return nil
}
func (m *PluginSpec) GetDisabled() bool {
if m != nil {
return m.Disabled
}
return false
}
// PluginPrivilege describes a permission the user has to accept
// upon installing a plugin.
type PluginPrivilege struct {
Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"`
Description string `protobuf:"bytes,2,opt,name=description,proto3" json:"description,omitempty"`
Value []string `protobuf:"bytes,3,rep,name=value" json:"value,omitempty"`
}
func (m *PluginPrivilege) Reset() { *m = PluginPrivilege{} }
func (m *PluginPrivilege) String() string { return proto.CompactTextString(m) }
func (*PluginPrivilege) ProtoMessage() {}
func (*PluginPrivilege) Descriptor() ([]byte, []int) { return fileDescriptorPlugin, []int{1} }
func (m *PluginPrivilege) GetName() string {
if m != nil {
return m.Name
}
return ""
}
func (m *PluginPrivilege) GetDescription() string {
if m != nil {
return m.Description
}
return ""
}
func (m *PluginPrivilege) GetValue() []string {
if m != nil {
return m.Value
}
return nil
}
func init() {
proto.RegisterType((*PluginSpec)(nil), "PluginSpec")
proto.RegisterType((*PluginPrivilege)(nil), "PluginPrivilege")
}
func (m *PluginSpec) Marshal() (dAtA []byte, err error) {
size := m.Size()
dAtA = make([]byte, size)
n, err := m.MarshalTo(dAtA)
if err != nil {
return nil, err
}
return dAtA[:n], nil
}
func (m *PluginSpec) MarshalTo(dAtA []byte) (int, error) {
var i int
_ = i
var l int
_ = l
if len(m.Name) > 0 {
dAtA[i] = 0xa
i++
i = encodeVarintPlugin(dAtA, i, uint64(len(m.Name)))
i += copy(dAtA[i:], m.Name)
}
if len(m.Remote) > 0 {
dAtA[i] = 0x12
i++
i = encodeVarintPlugin(dAtA, i, uint64(len(m.Remote)))
i += copy(dAtA[i:], m.Remote)
}
if len(m.Privileges) > 0 {
for _, msg := range m.Privileges {
dAtA[i] = 0x1a
i++
i = encodeVarintPlugin(dAtA, i, uint64(msg.Size()))
n, err := msg.MarshalTo(dAtA[i:])
if err != nil {
return 0, err
}
i += n
}
}
if m.Disabled {
dAtA[i] = 0x20
i++
if m.Disabled {
dAtA[i] = 1
} else {
dAtA[i] = 0
}
i++
}
return i, nil
}
func (m *PluginPrivilege) Marshal() (dAtA []byte, err error) {
size := m.Size()
dAtA = make([]byte, size)
n, err := m.MarshalTo(dAtA)
if err != nil {
return nil, err
}
return dAtA[:n], nil
}
func (m *PluginPrivilege) MarshalTo(dAtA []byte) (int, error) {
var i int
_ = i
var l int
_ = l
if len(m.Name) > 0 {
dAtA[i] = 0xa
i++
i = encodeVarintPlugin(dAtA, i, uint64(len(m.Name)))
i += copy(dAtA[i:], m.Name)
}
if len(m.Description) > 0 {
dAtA[i] = 0x12
i++
i = encodeVarintPlugin(dAtA, i, uint64(len(m.Description)))
i += copy(dAtA[i:], m.Description)
}
if len(m.Value) > 0 {
for _, s := range m.Value {
dAtA[i] = 0x1a
i++
l = len(s)
for l >= 1<<7 {
dAtA[i] = uint8(uint64(l)&0x7f | 0x80)
l >>= 7
i++
}
dAtA[i] = uint8(l)
i++
i += copy(dAtA[i:], s)
}
}
return i, nil
}
func encodeFixed64Plugin(dAtA []byte, offset int, v uint64) int {
dAtA[offset] = uint8(v)
dAtA[offset+1] = uint8(v >> 8)
dAtA[offset+2] = uint8(v >> 16)
dAtA[offset+3] = uint8(v >> 24)
dAtA[offset+4] = uint8(v >> 32)
dAtA[offset+5] = uint8(v >> 40)
dAtA[offset+6] = uint8(v >> 48)
dAtA[offset+7] = uint8(v >> 56)
return offset + 8
}
func encodeFixed32Plugin(dAtA []byte, offset int, v uint32) int {
dAtA[offset] = uint8(v)
dAtA[offset+1] = uint8(v >> 8)
dAtA[offset+2] = uint8(v >> 16)
dAtA[offset+3] = uint8(v >> 24)
return offset + 4
}
func encodeVarintPlugin(dAtA []byte, offset int, v uint64) int {
for v >= 1<<7 {
dAtA[offset] = uint8(v&0x7f | 0x80)
v >>= 7
offset++
}
dAtA[offset] = uint8(v)
return offset + 1
}
func (m *PluginSpec) Size() (n int) {
var l int
_ = l
l = len(m.Name)
if l > 0 {
n += 1 + l + sovPlugin(uint64(l))
}
l = len(m.Remote)
if l > 0 {
n += 1 + l + sovPlugin(uint64(l))
}
if len(m.Privileges) > 0 {
for _, e := range m.Privileges {
l = e.Size()
n += 1 + l + sovPlugin(uint64(l))
}
}
if m.Disabled {
n += 2
}
return n
}
func (m *PluginPrivilege) Size() (n int) {
var l int
_ = l
l = len(m.Name)
if l > 0 {
n += 1 + l + sovPlugin(uint64(l))
}
l = len(m.Description)
if l > 0 {
n += 1 + l + sovPlugin(uint64(l))
}
if len(m.Value) > 0 {
for _, s := range m.Value {
l = len(s)
n += 1 + l + sovPlugin(uint64(l))
}
}
return n
}
func sovPlugin(x uint64) (n int) {
for {
n++
x >>= 7
if x == 0 {
break
}
}
return n
}
func sozPlugin(x uint64) (n int) {
return sovPlugin(uint64((x << 1) ^ uint64((int64(x) >> 63))))
}
func (m *PluginSpec) Unmarshal(dAtA []byte) error {
l := len(dAtA)
iNdEx := 0
for iNdEx < l {
preIndex := iNdEx
var wire uint64
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowPlugin
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
wire |= (uint64(b) & 0x7F) << shift
if b < 0x80 {
break
}
}
fieldNum := int32(wire >> 3)
wireType := int(wire & 0x7)
if wireType == 4 {
return fmt.Errorf("proto: PluginSpec: wiretype end group for non-group")
}
if fieldNum <= 0 {
return fmt.Errorf("proto: PluginSpec: illegal tag %d (wire type %d)", fieldNum, wire)
}
switch fieldNum {
case 1:
if wireType != 2 {
return fmt.Errorf("proto: wrong wireType = %d for field Name", wireType)
}
var stringLen uint64
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowPlugin
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
stringLen |= (uint64(b) & 0x7F) << shift
if b < 0x80 {
break
}
}
intStringLen := int(stringLen)
if intStringLen < 0 {
return ErrInvalidLengthPlugin
}
postIndex := iNdEx + intStringLen
if postIndex > l {
return io.ErrUnexpectedEOF
}
m.Name = string(dAtA[iNdEx:postIndex])
iNdEx = postIndex
case 2:
if wireType != 2 {
return fmt.Errorf("proto: wrong wireType = %d for field Remote", wireType)
}
var stringLen uint64
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowPlugin
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
stringLen |= (uint64(b) & 0x7F) << shift
if b < 0x80 {
break
}
}
intStringLen := int(stringLen)
if intStringLen < 0 {
return ErrInvalidLengthPlugin
}
postIndex := iNdEx + intStringLen
if postIndex > l {
return io.ErrUnexpectedEOF
}
m.Remote = string(dAtA[iNdEx:postIndex])
iNdEx = postIndex
case 3:
if wireType != 2 {
return fmt.Errorf("proto: wrong wireType = %d for field Privileges", wireType)
}
var msglen int
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowPlugin
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
msglen |= (int(b) & 0x7F) << shift
if b < 0x80 {
break
}
}
if msglen < 0 {
return ErrInvalidLengthPlugin
}
postIndex := iNdEx + msglen
if postIndex > l {
return io.ErrUnexpectedEOF
}
m.Privileges = append(m.Privileges, &PluginPrivilege{})
if err := m.Privileges[len(m.Privileges)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil {
return err
}
iNdEx = postIndex
case 4:
if wireType != 0 {
return fmt.Errorf("proto: wrong wireType = %d for field Disabled", wireType)
}
var v int
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowPlugin
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
v |= (int(b) & 0x7F) << shift
if b < 0x80 {
break
}
}
m.Disabled = bool(v != 0)
default:
iNdEx = preIndex
skippy, err := skipPlugin(dAtA[iNdEx:])
if err != nil {
return err
}
if skippy < 0 {
return ErrInvalidLengthPlugin
}
if (iNdEx + skippy) > l {
return io.ErrUnexpectedEOF
}
iNdEx += skippy
}
}
if iNdEx > l {
return io.ErrUnexpectedEOF
}
return nil
}
func (m *PluginPrivilege) Unmarshal(dAtA []byte) error {
l := len(dAtA)
iNdEx := 0
for iNdEx < l {
preIndex := iNdEx
var wire uint64
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowPlugin
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
wire |= (uint64(b) & 0x7F) << shift
if b < 0x80 {
break
}
}
fieldNum := int32(wire >> 3)
wireType := int(wire & 0x7)
if wireType == 4 {
return fmt.Errorf("proto: PluginPrivilege: wiretype end group for non-group")
}
if fieldNum <= 0 {
return fmt.Errorf("proto: PluginPrivilege: illegal tag %d (wire type %d)", fieldNum, wire)
}
switch fieldNum {
case 1:
if wireType != 2 {
return fmt.Errorf("proto: wrong wireType = %d for field Name", wireType)
}
var stringLen uint64
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowPlugin
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
stringLen |= (uint64(b) & 0x7F) << shift
if b < 0x80 {
break
}
}
intStringLen := int(stringLen)
if intStringLen < 0 {
return ErrInvalidLengthPlugin
}
postIndex := iNdEx + intStringLen
if postIndex > l {
return io.ErrUnexpectedEOF
}
m.Name = string(dAtA[iNdEx:postIndex])
iNdEx = postIndex
case 2:
if wireType != 2 {
return fmt.Errorf("proto: wrong wireType = %d for field Description", wireType)
}
var stringLen uint64
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowPlugin
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
stringLen |= (uint64(b) & 0x7F) << shift
if b < 0x80 {
break
}
}
intStringLen := int(stringLen)
if intStringLen < 0 {
return ErrInvalidLengthPlugin
}
postIndex := iNdEx + intStringLen
if postIndex > l {
return io.ErrUnexpectedEOF
}
m.Description = string(dAtA[iNdEx:postIndex])
iNdEx = postIndex
case 3:
if wireType != 2 {
return fmt.Errorf("proto: wrong wireType = %d for field Value", wireType)
}
var stringLen uint64
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowPlugin
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
stringLen |= (uint64(b) & 0x7F) << shift
if b < 0x80 {
break
}
}
intStringLen := int(stringLen)
if intStringLen < 0 {
return ErrInvalidLengthPlugin
}
postIndex := iNdEx + intStringLen
if postIndex > l {
return io.ErrUnexpectedEOF
}
m.Value = append(m.Value, string(dAtA[iNdEx:postIndex]))
iNdEx = postIndex
default:
iNdEx = preIndex
skippy, err := skipPlugin(dAtA[iNdEx:])
if err != nil {
return err
}
if skippy < 0 {
return ErrInvalidLengthPlugin
}
if (iNdEx + skippy) > l {
return io.ErrUnexpectedEOF
}
iNdEx += skippy
}
}
if iNdEx > l {
return io.ErrUnexpectedEOF
}
return nil
}
func skipPlugin(dAtA []byte) (n int, err error) {
l := len(dAtA)
iNdEx := 0
for iNdEx < l {
var wire uint64
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return 0, ErrIntOverflowPlugin
}
if iNdEx >= l {
return 0, io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
wire |= (uint64(b) & 0x7F) << shift
if b < 0x80 {
break
}
}
wireType := int(wire & 0x7)
switch wireType {
case 0:
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return 0, ErrIntOverflowPlugin
}
if iNdEx >= l {
return 0, io.ErrUnexpectedEOF
}
iNdEx++
if dAtA[iNdEx-1] < 0x80 {
break
}
}
return iNdEx, nil
case 1:
iNdEx += 8
return iNdEx, nil
case 2:
var length int
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return 0, ErrIntOverflowPlugin
}
if iNdEx >= l {
return 0, io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
length |= (int(b) & 0x7F) << shift
if b < 0x80 {
break
}
}
iNdEx += length
if length < 0 {
return 0, ErrInvalidLengthPlugin
}
return iNdEx, nil
case 3:
for {
var innerWire uint64
var start int = iNdEx
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return 0, ErrIntOverflowPlugin
}
if iNdEx >= l {
return 0, io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
innerWire |= (uint64(b) & 0x7F) << shift
if b < 0x80 {
break
}
}
innerWireType := int(innerWire & 0x7)
if innerWireType == 4 {
break
}
next, err := skipPlugin(dAtA[start:])
if err != nil {
return 0, err
}
iNdEx = start + next
}
return iNdEx, nil
case 4:
return iNdEx, nil
case 5:
iNdEx += 4
return iNdEx, nil
default:
return 0, fmt.Errorf("proto: illegal wireType %d", wireType)
}
}
panic("unreachable")
}
var (
ErrInvalidLengthPlugin = fmt.Errorf("proto: negative length found during unmarshaling")
ErrIntOverflowPlugin = fmt.Errorf("proto: integer overflow")
)
func init() { proto.RegisterFile("plugin.proto", fileDescriptorPlugin) }
var fileDescriptorPlugin = []byte{
// 196 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x09, 0x6e, 0x88, 0x02, 0xff, 0xe2, 0xe2, 0x29, 0xc8, 0x29, 0x4d,
0xcf, 0xcc, 0xd3, 0x2b, 0x28, 0xca, 0x2f, 0xc9, 0x57, 0x6a, 0x63, 0xe4, 0xe2, 0x0a, 0x00, 0x0b,
0x04, 0x17, 0xa4, 0x26, 0x0b, 0x09, 0x71, 0xb1, 0xe4, 0x25, 0xe6, 0xa6, 0x4a, 0x30, 0x2a, 0x30,
0x6a, 0x70, 0x06, 0x81, 0xd9, 0x42, 0x62, 0x5c, 0x6c, 0x45, 0xa9, 0xb9, 0xf9, 0x25, 0xa9, 0x12,
0x4c, 0x60, 0x51, 0x28, 0x4f, 0xc8, 0x80, 0x8b, 0xab, 0xa0, 0x28, 0xb3, 0x2c, 0x33, 0x27, 0x35,
0x3d, 0xb5, 0x58, 0x82, 0x59, 0x81, 0x59, 0x83, 0xdb, 0x48, 0x40, 0x0f, 0x62, 0x58, 0x00, 0x4c,
0x22, 0x08, 0x49, 0x8d, 0x90, 0x14, 0x17, 0x47, 0x4a, 0x66, 0x71, 0x62, 0x52, 0x4e, 0x6a, 0x8a,
0x04, 0x8b, 0x02, 0xa3, 0x06, 0x47, 0x10, 0x9c, 0xaf, 0x14, 0xcb, 0xc5, 0x8f, 0xa6, 0x15, 0xab,
0x63, 0x14, 0xb8, 0xb8, 0x53, 0x52, 0x8b, 0x93, 0x8b, 0x32, 0x0b, 0x4a, 0x32, 0xf3, 0xf3, 0xa0,
0x2e, 0x42, 0x16, 0x12, 0x12, 0xe1, 0x62, 0x2d, 0x4b, 0xcc, 0x29, 0x4d, 0x05, 0xbb, 0x88, 0x33,
0x08, 0xc2, 0x71, 0xe2, 0x39, 0xf1, 0x48, 0x8e, 0xf1, 0xc2, 0x23, 0x39, 0xc6, 0x07, 0x8f, 0xe4,
0x18, 0x93, 0xd8, 0xc0, 0x9e, 0x37, 0x06, 0x04, 0x00, 0x00, 0xff, 0xff, 0xb8, 0x84, 0xad, 0x79,
0x0c, 0x01, 0x00, 0x00,
}

View File

@ -0,0 +1,18 @@
syntax = "proto3";
// PluginSpec defines the base payload which clients can specify for creating
// a service with the plugin runtime.
message PluginSpec {
string name = 1;
string remote = 2;
repeated PluginPrivilege privileges = 3;
bool disabled = 4;
}
// PluginPrivilege describes a permission the user has to accept
// upon installing a plugin.
message PluginPrivilege {
string name = 1;
string description = 2;
repeated string value = 3;
}

View File

@ -12,7 +12,8 @@ type Secret struct {
// SecretSpec represents a secret specification from a secret in swarm
type SecretSpec struct {
Annotations
Data []byte `json:",omitempty"`
Data []byte `json:",omitempty"`
Driver *Driver `json:",omitempty"` // name of the secrets driver used to fetch the secret's value from an external secret store
}
// SecretReferenceFileTarget is a file target in a secret reference

View File

@ -1,6 +1,10 @@
package swarm
import "time"
import (
"time"
"github.com/docker/docker/api/types/swarm/runtime"
)
// TaskState represents the state of a task.
type TaskState string
@ -47,11 +51,16 @@ type Task struct {
Status TaskStatus `json:",omitempty"`
DesiredState TaskState `json:",omitempty"`
NetworksAttachments []NetworkAttachment `json:",omitempty"`
GenericResources []GenericResource `json:",omitempty"`
}
// TaskSpec represents the spec of a task.
type TaskSpec struct {
ContainerSpec ContainerSpec `json:",omitempty"`
// ContainerSpec and PluginSpec are mutually exclusive.
// PluginSpec will only be used when the `Runtime` field is set to `plugin`
ContainerSpec *ContainerSpec `json:",omitempty"`
PluginSpec *runtime.PluginSpec `json:",omitempty"`
Resources *ResourceRequirements `json:",omitempty"`
RestartPolicy *RestartPolicy `json:",omitempty"`
Placement *Placement `json:",omitempty"`
@ -71,8 +80,34 @@ type TaskSpec struct {
// Resources represents resources (CPU/Memory).
type Resources struct {
NanoCPUs int64 `json:",omitempty"`
MemoryBytes int64 `json:",omitempty"`
NanoCPUs int64 `json:",omitempty"`
MemoryBytes int64 `json:",omitempty"`
GenericResources []GenericResource `json:",omitempty"`
}
// GenericResource represents a "user defined" resource which can
// be either an integer (e.g: SSD=3) or a string (e.g: SSD=sda1)
type GenericResource struct {
NamedResourceSpec *NamedGenericResource `json:",omitempty"`
DiscreteResourceSpec *DiscreteGenericResource `json:",omitempty"`
}
// NamedGenericResource represents a "user defined" resource which is defined
// as a string.
// "Kind" is used to describe the Kind of a resource (e.g: "GPU", "FPGA", "SSD", ...)
// Value is used to identify the resource (GPU="UUID-1", FPGA="/dev/sdb5", ...)
type NamedGenericResource struct {
Kind string `json:",omitempty"`
Value string `json:",omitempty"`
}
// DiscreteGenericResource represents a "user defined" resource which is defined
// as an integer
// "Kind" is used to describe the Kind of a resource (e.g: "GPU", "FPGA", "SSD", ...)
// Value is used to count the resource (SSD=5, HDD=3, ...)
type DiscreteGenericResource struct {
Kind string `json:",omitempty"`
Value int64 `json:",omitempty"`
}
// ResourceRequirements represents resources requirements.

View File

@ -168,6 +168,7 @@ type Info struct {
RegistryConfig *registry.ServiceConfig
NCPU int
MemTotal int64
GenericResources []swarm.GenericResource
DockerRootDir string
HTTPProxy string `json:"HttpProxy"`
HTTPSProxy string `json:"HttpsProxy"`

View File

@ -7,7 +7,7 @@ package types
// swagger:model Volume
type Volume struct {
// Time volume was created.
// Date/Time the volume was created.
CreatedAt string `json:"CreatedAt,omitempty"`
// Name of the volume driver used by the volume.
@ -47,15 +47,23 @@ type Volume struct {
UsageData *VolumeUsageData `json:"UsageData,omitempty"`
}
// VolumeUsageData volume usage data
// VolumeUsageData Usage details about the volume. This information is used by the
// `GET /system/df` endpoint, and omitted in other endpoints.
//
// swagger:model VolumeUsageData
type VolumeUsageData struct {
// The number of containers referencing this volume.
// The number of containers referencing this volume. This field
// is set to `-1` if the reference-count is not available.
//
// Required: true
RefCount int64 `json:"RefCount"`
// The disk space used by the volume (local driver only)
// Amount of disk space used by the volume (in bytes). This information
// is only available for volumes created with the `"local"` volume
// driver. For volumes created with other volume drivers, this field
// is set to `-1` ("not available")
//
// Required: true
Size int64 `json:"Size"`
}

View File

@ -1,7 +1,6 @@
package git
import (
"fmt"
"io/ioutil"
"net/http"
"net/url"
@ -98,22 +97,46 @@ func getRefAndSubdir(fragment string) (ref string, subdir string) {
func fetchArgs(remoteURL string, ref string) []string {
args := []string{"fetch", "--recurse-submodules=yes"}
shallow := true
if urlutil.IsURL(remoteURL) {
res, err := http.Head(fmt.Sprintf("%s/info/refs?service=git-upload-pack", remoteURL))
if err != nil || res.Header.Get("Content-Type") != "application/x-git-upload-pack-advertisement" {
shallow = false
}
}
if shallow {
if supportsShallowClone(remoteURL) {
args = append(args, "--depth", "1")
}
return append(args, "origin", ref)
}
// Check if a given git URL supports a shallow git clone,
// i.e. it is a non-HTTP server or a smart HTTP server.
func supportsShallowClone(remoteURL string) bool {
if urlutil.IsURL(remoteURL) {
// Check if the HTTP server is smart
// Smart servers must correctly respond to a query for the git-upload-pack service
serviceURL := remoteURL + "/info/refs?service=git-upload-pack"
// Try a HEAD request and fallback to a Get request on error
res, err := http.Head(serviceURL)
if err != nil || res.StatusCode != http.StatusOK {
res, err = http.Get(serviceURL)
if err == nil {
res.Body.Close()
}
if err != nil || res.StatusCode != http.StatusOK {
// request failed
return false
}
}
if res.Header.Get("Content-Type") != "application/x-git-upload-pack-advertisement" {
// Fallback, not a smart server
return false
}
return true
}
// Non-HTTP protocols always support shallow clones
return true
}
func checkoutGit(root, ref, subdir string) (string, error) {
// Try checking out by ref name first. This will work on branches and sets
// .git/HEAD to the current branch name

View File

@ -1,10 +1,6 @@
/*
Package client is a Go client for the Docker Engine API.
The "docker" command uses this package to communicate with the daemon. It can also
be used by your own Go applications to do anything the command-line interface does
- running containers, pulling images, managing swarms, etc.
For more information about the Engine API, see the documentation:
https://docs.docker.com/engine/reference/api/
@ -51,6 +47,7 @@ import (
"net/http"
"net/url"
"os"
"path"
"path/filepath"
"strings"
@ -159,18 +156,18 @@ func NewEnvClient() (*Client, error) {
// highly recommended that you set a version or your client may break if the
// server is upgraded.
func NewClient(host string, version string, client *http.Client, httpHeaders map[string]string) (*Client, error) {
proto, addr, basePath, err := ParseHost(host)
hostURL, err := ParseHostURL(host)
if err != nil {
return nil, err
}
if client != nil {
if _, ok := client.Transport.(*http.Transport); !ok {
if _, ok := client.Transport.(http.RoundTripper); !ok {
return nil, fmt.Errorf("unable to verify TLS configuration, invalid transport %v", client.Transport)
}
} else {
transport := new(http.Transport)
sockets.ConfigureTransport(transport, proto, addr)
sockets.ConfigureTransport(transport, hostURL.Scheme, hostURL.Host)
client = &http.Client{
Transport: transport,
CheckRedirect: CheckRedirect,
@ -188,28 +185,24 @@ func NewClient(host string, version string, client *http.Client, httpHeaders map
scheme = "https"
}
// TODO: store URL instead of proto/addr/basePath
return &Client{
scheme: scheme,
host: host,
proto: proto,
addr: addr,
basePath: basePath,
proto: hostURL.Scheme,
addr: hostURL.Host,
basePath: hostURL.Path,
client: client,
version: version,
customHTTPHeaders: httpHeaders,
}, nil
}
// Close ensures that transport.Client is closed
// especially needed while using NewClient with *http.Client = nil
// for example
// client.NewClient("unix:///var/run/docker.sock", nil, "v1.18", map[string]string{"User-Agent": "engine-api-cli-1.0"})
// Close the transport used by the client
func (cli *Client) Close() error {
if t, ok := cli.client.Transport.(*http.Transport); ok {
t.CloseIdleConnections()
}
return nil
}
@ -219,37 +212,27 @@ func (cli *Client) getAPIPath(p string, query url.Values) string {
var apiPath string
if cli.version != "" {
v := strings.TrimPrefix(cli.version, "v")
apiPath = cli.basePath + "/v" + v + p
apiPath = path.Join(cli.basePath, "/v"+v, p)
} else {
apiPath = cli.basePath + p
apiPath = path.Join(cli.basePath, p)
}
u := &url.URL{
Path: apiPath,
}
if len(query) > 0 {
u.RawQuery = query.Encode()
}
return u.String()
return (&url.URL{Path: apiPath, RawQuery: query.Encode()}).String()
}
// ClientVersion returns the version string associated with this
// instance of the Client. Note that this value can be changed
// via the DOCKER_API_VERSION env var.
// This operation doesn't acquire a mutex.
// ClientVersion returns the API version used by this client.
func (cli *Client) ClientVersion() string {
return cli.version
}
// NegotiateAPIVersion updates the version string associated with this
// instance of the Client to match the latest version the server supports
// NegotiateAPIVersion queries the API and updates the version to match the
// API version. Any errors are silently ignored.
func (cli *Client) NegotiateAPIVersion(ctx context.Context) {
ping, _ := cli.Ping(ctx)
cli.NegotiateAPIVersionPing(ping)
}
// NegotiateAPIVersionPing updates the version string associated with this
// instance of the Client to match the latest version the server supports
// NegotiateAPIVersionPing updates the client version to match the Ping.APIVersion
// if the ping version is less than the default version.
func (cli *Client) NegotiateAPIVersionPing(p types.Ping) {
if cli.manualOverride {
return
@ -271,17 +254,28 @@ func (cli *Client) NegotiateAPIVersionPing(p types.Ping) {
}
}
// DaemonHost returns the host associated with this instance of the Client.
// This operation doesn't acquire a mutex.
// DaemonHost returns the host address used by the client
func (cli *Client) DaemonHost() string {
return cli.host
}
// ParseHost verifies that the given host strings is valid.
// ParseHost parses a url string, validates the strings is a host url, and returns
// the parsed host as: protocol, address, and base path
// Deprecated: use ParseHostURL
func ParseHost(host string) (string, string, string, error) {
hostURL, err := ParseHostURL(host)
if err != nil {
return "", "", "", err
}
return hostURL.Scheme, hostURL.Host, hostURL.Path, nil
}
// ParseHostURL parses a url string, validates the string is a host url, and
// returns the parsed URL
func ParseHostURL(host string) (*url.URL, error) {
protoAddrParts := strings.SplitN(host, "://", 2)
if len(protoAddrParts) == 1 {
return "", "", "", fmt.Errorf("unable to parse docker host `%s`", host)
return nil, fmt.Errorf("unable to parse docker host `%s`", host)
}
var basePath string
@ -289,16 +283,19 @@ func ParseHost(host string) (string, string, string, error) {
if proto == "tcp" {
parsed, err := url.Parse("tcp://" + addr)
if err != nil {
return "", "", "", err
return nil, err
}
addr = parsed.Host
basePath = parsed.Path
}
return proto, addr, basePath, nil
return &url.URL{
Scheme: proto,
Host: addr,
Path: basePath,
}, nil
}
// CustomHTTPHeaders returns the custom http headers associated with this
// instance of the Client. This operation doesn't acquire a mutex.
// CustomHTTPHeaders returns the custom http headers stored by the client.
func (cli *Client) CustomHTTPHeaders() map[string]string {
m := make(map[string]string)
for k, v := range cli.customHTTPHeaders {
@ -307,8 +304,7 @@ func (cli *Client) CustomHTTPHeaders() map[string]string {
return m
}
// SetCustomHTTPHeaders updates the custom http headers associated with this
// instance of the Client. This operation doesn't acquire a mutex.
// SetCustomHTTPHeaders that will be set on every HTTP request made by the client.
func (cli *Client) SetCustomHTTPHeaders(headers map[string]string) {
cli.customHTTPHeaders = headers
}

View File

@ -36,8 +36,8 @@ type notFound interface {
NotFound() bool // Is the error a NotFound error
}
// IsErrNotFound returns true if the error is caused with an
// object (image, container, network, volume, …) is not found in the docker host.
// IsErrNotFound returns true if the error is a NotFound error, which is returned
// by the API when some object is not found.
func IsErrNotFound(err error) bool {
te, ok := err.(notFound)
return ok && te.NotFound()
@ -60,6 +60,8 @@ func (e imageNotFoundError) Error() string {
// IsErrImageNotFound returns true if the error is caused
// when an image is not found in the docker host.
//
// Deprecated: Use IsErrNotFound
func IsErrImageNotFound(err error) bool {
return IsErrNotFound(err)
}
@ -81,6 +83,8 @@ func (e containerNotFoundError) Error() string {
// IsErrContainerNotFound returns true if the error is caused
// when a container is not found in the docker host.
//
// Deprecated: Use IsErrNotFound
func IsErrContainerNotFound(err error) bool {
return IsErrNotFound(err)
}
@ -102,6 +106,8 @@ func (e networkNotFoundError) Error() string {
// IsErrNetworkNotFound returns true if the error is caused
// when a network is not found in the docker host.
//
// Deprecated: Use IsErrNotFound
func IsErrNetworkNotFound(err error) bool {
return IsErrNotFound(err)
}
@ -123,6 +129,8 @@ func (e volumeNotFoundError) Error() string {
// IsErrVolumeNotFound returns true if the error is caused
// when a volume is not found in the docker host.
//
// Deprecated: Use IsErrNotFound
func IsErrVolumeNotFound(err error) bool {
return IsErrNotFound(err)
}
@ -161,6 +169,8 @@ func (e nodeNotFoundError) NotFound() bool {
// IsErrNodeNotFound returns true if the error is caused
// when a node is not found.
//
// Deprecated: Use IsErrNotFound
func IsErrNodeNotFound(err error) bool {
_, ok := err.(nodeNotFoundError)
return ok
@ -183,6 +193,8 @@ func (e serviceNotFoundError) NotFound() bool {
// IsErrServiceNotFound returns true if the error is caused
// when a service is not found.
//
// Deprecated: Use IsErrNotFound
func IsErrServiceNotFound(err error) bool {
_, ok := err.(serviceNotFoundError)
return ok
@ -205,6 +217,8 @@ func (e taskNotFoundError) NotFound() bool {
// IsErrTaskNotFound returns true if the error is caused
// when a task is not found.
//
// Deprecated: Use IsErrNotFound
func IsErrTaskNotFound(err error) bool {
_, ok := err.(taskNotFoundError)
return ok
@ -228,7 +242,7 @@ func IsErrPluginPermissionDenied(err error) bool {
// NewVersionError returns an error if the APIVersion required
// if less than the current supported version
func (cli *Client) NewVersionError(APIrequired, feature string) error {
if versions.LessThan(cli.version, APIrequired) {
if cli.version != "" && versions.LessThan(cli.version, APIrequired) {
return fmt.Errorf("%q requires API version %s, but the Docker daemon API version is %s", feature, APIrequired, cli.version)
}
return nil
@ -251,6 +265,8 @@ func (e secretNotFoundError) NotFound() bool {
// IsErrSecretNotFound returns true if the error is caused
// when a secret is not found.
//
// Deprecated: Use IsErrNotFound
func IsErrSecretNotFound(err error) bool {
_, ok := err.(secretNotFoundError)
return ok
@ -273,6 +289,8 @@ func (e configNotFoundError) NotFound() bool {
// IsErrConfigNotFound returns true if the error is caused
// when a config is not found.
//
// Deprecated: Use IsErrNotFound
func IsErrConfigNotFound(err error) bool {
_, ok := err.(configNotFoundError)
return ok
@ -295,6 +313,8 @@ func (e pluginNotFoundError) Error() string {
// IsErrPluginNotFound returns true if the error is caused
// when a plugin is not found in the docker host.
//
// Deprecated: Use IsErrNotFound
func IsErrPluginNotFound(err error) bool {
return IsErrNotFound(err)
}

View File

@ -12,7 +12,6 @@ import (
"time"
"github.com/docker/docker/api/types"
"github.com/docker/docker/pkg/tlsconfig"
"github.com/docker/go-connections/sockets"
"github.com/pkg/errors"
"golang.org/x/net/context"
@ -115,7 +114,7 @@ func tlsDialWithDialer(dialer *net.Dialer, network, addr string, config *tls.Con
// from the hostname we're connecting to.
if config.ServerName == "" {
// Make a copy to avoid polluting argument or default.
config = tlsconfig.Clone(config)
config = tlsConfigClone(config)
config.ServerName = hostname
}
@ -177,12 +176,14 @@ func (cli *Client) setupHijackConn(req *http.Request, proto string) (net.Conn, e
// Server hijacks the connection, error 'connection closed' expected
resp, err := clientconn.Do(req)
if err != nil {
return nil, err
}
if resp.StatusCode != http.StatusSwitchingProtocols {
resp.Body.Close()
return nil, fmt.Errorf("unable to upgrade to %s, received %d", proto, resp.StatusCode)
if err != httputil.ErrPersistEOF {
if err != nil {
return nil, err
}
if resp.StatusCode != http.StatusSwitchingProtocols {
resp.Body.Close()
return nil, fmt.Errorf("unable to upgrade to %s, received %d", proto, resp.StatusCode)
}
}
c, br := clientconn.Hijack()

View File

@ -2,6 +2,7 @@ package client
import (
"encoding/json"
"net/http"
"net/url"
"github.com/docker/docker/api/types"
@ -21,6 +22,9 @@ func (cli *Client) ImageRemove(ctx context.Context, imageID string, options type
resp, err := cli.delete(ctx, "/images/"+imageID, query, nil)
if err != nil {
if resp.statusCode == http.StatusNotFound {
return nil, imageNotFoundError{imageID}
}
return nil, err
}

View File

@ -1,6 +1,8 @@
package client
import (
"path"
"github.com/docker/docker/api/types"
"golang.org/x/net/context"
)
@ -8,7 +10,7 @@ import (
// Ping pings the server and returns the value of the "Docker-Experimental", "OS-Type" & "API-Version" headers
func (cli *Client) Ping(ctx context.Context) (types.Ping, error) {
var ping types.Ping
req, err := cli.buildRequest("GET", cli.basePath+"/_ping", nil, nil)
req, err := cli.buildRequest("GET", path.Join(cli.basePath, "/_ping"), nil, nil)
if err != nil {
return ping, err
}

View File

@ -3,12 +3,13 @@ package client
import (
"encoding/json"
"fmt"
"strings"
"github.com/docker/distribution/reference"
"github.com/docker/docker/api/types"
registrytypes "github.com/docker/docker/api/types/registry"
"github.com/docker/docker/api/types/swarm"
"github.com/opencontainers/go-digest"
digest "github.com/opencontainers/go-digest"
"github.com/pkg/errors"
"golang.org/x/net/context"
)
@ -24,24 +25,51 @@ func (cli *Client) ServiceCreate(ctx context.Context, service swarm.ServiceSpec,
headers["X-Registry-Auth"] = []string{options.EncodedRegistryAuth}
}
// ensure that the image is tagged
if taggedImg := imageWithTagString(service.TaskTemplate.ContainerSpec.Image); taggedImg != "" {
service.TaskTemplate.ContainerSpec.Image = taggedImg
// Make sure containerSpec is not nil when no runtime is set or the runtime is set to container
if service.TaskTemplate.ContainerSpec == nil && (service.TaskTemplate.Runtime == "" || service.TaskTemplate.Runtime == swarm.RuntimeContainer) {
service.TaskTemplate.ContainerSpec = &swarm.ContainerSpec{}
}
// Contact the registry to retrieve digest and platform information
if options.QueryRegistry {
distributionInspect, err := cli.DistributionInspect(ctx, service.TaskTemplate.ContainerSpec.Image, options.EncodedRegistryAuth)
distErr = err
if err == nil {
// now pin by digest if the image doesn't already contain a digest
if img := imageWithDigestString(service.TaskTemplate.ContainerSpec.Image, distributionInspect.Descriptor.Digest); img != "" {
if err := validateServiceSpec(service); err != nil {
return types.ServiceCreateResponse{}, err
}
// ensure that the image is tagged
var imgPlatforms []swarm.Platform
if service.TaskTemplate.ContainerSpec != nil {
if taggedImg := imageWithTagString(service.TaskTemplate.ContainerSpec.Image); taggedImg != "" {
service.TaskTemplate.ContainerSpec.Image = taggedImg
}
if options.QueryRegistry {
var img string
img, imgPlatforms, distErr = imageDigestAndPlatforms(ctx, cli, service.TaskTemplate.ContainerSpec.Image, options.EncodedRegistryAuth)
if img != "" {
service.TaskTemplate.ContainerSpec.Image = img
}
// add platforms that are compatible with the service
service.TaskTemplate.Placement = setServicePlatforms(service.TaskTemplate.Placement, distributionInspect)
}
}
// ensure that the image is tagged
if service.TaskTemplate.PluginSpec != nil {
if taggedImg := imageWithTagString(service.TaskTemplate.PluginSpec.Remote); taggedImg != "" {
service.TaskTemplate.PluginSpec.Remote = taggedImg
}
if options.QueryRegistry {
var img string
img, imgPlatforms, distErr = imageDigestAndPlatforms(ctx, cli, service.TaskTemplate.PluginSpec.Remote, options.EncodedRegistryAuth)
if img != "" {
service.TaskTemplate.PluginSpec.Remote = img
}
}
}
if service.TaskTemplate.Placement == nil && len(imgPlatforms) > 0 {
service.TaskTemplate.Placement = &swarm.Placement{}
}
if len(imgPlatforms) > 0 {
service.TaskTemplate.Placement.Platforms = imgPlatforms
}
var response types.ServiceCreateResponse
resp, err := cli.post(ctx, "/services/create", nil, service, headers)
if err != nil {
@ -58,6 +86,37 @@ func (cli *Client) ServiceCreate(ctx context.Context, service swarm.ServiceSpec,
return response, err
}
func imageDigestAndPlatforms(ctx context.Context, cli DistributionAPIClient, image, encodedAuth string) (string, []swarm.Platform, error) {
distributionInspect, err := cli.DistributionInspect(ctx, image, encodedAuth)
var platforms []swarm.Platform
if err != nil {
return "", nil, err
}
imageWithDigest := imageWithDigestString(image, distributionInspect.Descriptor.Digest)
if len(distributionInspect.Platforms) > 0 {
platforms = make([]swarm.Platform, 0, len(distributionInspect.Platforms))
for _, p := range distributionInspect.Platforms {
// clear architecture field for arm. This is a temporary patch to address
// https://github.com/docker/swarmkit/issues/2294. The issue is that while
// image manifests report "arm" as the architecture, the node reports
// something like "armv7l" (includes the variant), which causes arm images
// to stop working with swarm mode. This patch removes the architecture
// constraint for arm images to ensure tasks get scheduled.
arch := p.Architecture
if strings.ToLower(arch) == "arm" {
arch = ""
}
platforms = append(platforms, swarm.Platform{
Architecture: arch,
OS: p.OS,
})
}
}
return imageWithDigest, platforms, err
}
// imageWithDigestString takes an image string and a digest, and updates
// the image string if it didn't originally contain a digest. It returns
// an empty string if there are no updates.
@ -86,27 +145,22 @@ func imageWithTagString(image string) string {
return ""
}
// setServicePlatforms sets Platforms in swarm.Placement to list all
// compatible platforms for the service, as found in distributionInspect
// and returns a pointer to the new or updated swarm.Placement struct.
func setServicePlatforms(placement *swarm.Placement, distributionInspect registrytypes.DistributionInspect) *swarm.Placement {
if placement == nil {
placement = &swarm.Placement{}
}
// reset any existing listed platforms
placement.Platforms = []swarm.Platform{}
for _, p := range distributionInspect.Platforms {
placement.Platforms = append(placement.Platforms, swarm.Platform{
Architecture: p.Architecture,
OS: p.OS,
})
}
return placement
}
// digestWarning constructs a formatted warning string using the
// image name that could not be pinned by digest. The formatting
// is hardcoded, but could me made smarter in the future
func digestWarning(image string) string {
return fmt.Sprintf("image %s could not be accessed on a registry to record\nits digest. Each node will access %s independently,\npossibly leading to different nodes running different\nversions of the image.\n", image, image)
}
func validateServiceSpec(s swarm.ServiceSpec) error {
if s.TaskTemplate.ContainerSpec != nil && s.TaskTemplate.PluginSpec != nil {
return errors.New("must not specify both a container spec and a plugin spec in the task template")
}
if s.TaskTemplate.PluginSpec != nil && s.TaskTemplate.Runtime != swarm.RuntimePlugin {
return errors.New("mismatched runtime with plugin spec")
}
if s.TaskTemplate.ContainerSpec != nil && (s.TaskTemplate.Runtime != "" && s.TaskTemplate.Runtime != swarm.RuntimeContainer) {
return errors.New("mismatched runtime with container spec")
}
return nil
}

View File

@ -35,26 +35,46 @@ func (cli *Client) ServiceUpdate(ctx context.Context, serviceID string, version
query.Set("version", strconv.FormatUint(version.Index, 10))
// ensure that the image is tagged
if taggedImg := imageWithTagString(service.TaskTemplate.ContainerSpec.Image); taggedImg != "" {
service.TaskTemplate.ContainerSpec.Image = taggedImg
if err := validateServiceSpec(service); err != nil {
return types.ServiceUpdateResponse{}, err
}
// Contact the registry to retrieve digest and platform information
// This happens only when the image has changed
if options.QueryRegistry {
distributionInspect, err := cli.DistributionInspect(ctx, service.TaskTemplate.ContainerSpec.Image, options.EncodedRegistryAuth)
distErr = err
if err == nil {
// now pin by digest if the image doesn't already contain a digest
if img := imageWithDigestString(service.TaskTemplate.ContainerSpec.Image, distributionInspect.Descriptor.Digest); img != "" {
var imgPlatforms []swarm.Platform
// ensure that the image is tagged
if service.TaskTemplate.ContainerSpec != nil {
if taggedImg := imageWithTagString(service.TaskTemplate.ContainerSpec.Image); taggedImg != "" {
service.TaskTemplate.ContainerSpec.Image = taggedImg
}
if options.QueryRegistry {
var img string
img, imgPlatforms, distErr = imageDigestAndPlatforms(ctx, cli, service.TaskTemplate.ContainerSpec.Image, options.EncodedRegistryAuth)
if img != "" {
service.TaskTemplate.ContainerSpec.Image = img
}
// add platforms that are compatible with the service
service.TaskTemplate.Placement = setServicePlatforms(service.TaskTemplate.Placement, distributionInspect)
}
}
// ensure that the image is tagged
if service.TaskTemplate.PluginSpec != nil {
if taggedImg := imageWithTagString(service.TaskTemplate.PluginSpec.Remote); taggedImg != "" {
service.TaskTemplate.PluginSpec.Remote = taggedImg
}
if options.QueryRegistry {
var img string
img, imgPlatforms, distErr = imageDigestAndPlatforms(ctx, cli, service.TaskTemplate.PluginSpec.Remote, options.EncodedRegistryAuth)
if img != "" {
service.TaskTemplate.PluginSpec.Remote = img
}
}
}
if service.TaskTemplate.Placement == nil && len(imgPlatforms) > 0 {
service.TaskTemplate.Placement = &swarm.Placement{}
}
if len(imgPlatforms) > 0 {
service.TaskTemplate.Placement.Platforms = imgPlatforms
}
var response types.ServiceUpdateResponse
resp, err := cli.post(ctx, "/services/"+serviceID+"/update", query, service, headers)
if err != nil {

View File

@ -0,0 +1,11 @@
// +build go1.8
package client
import "crypto/tls"
// tlsConfigClone returns a clone of tls.Config. This function is provided for
// compatibility for go1.7 that doesn't include this method in stdlib.
func tlsConfigClone(c *tls.Config) *tls.Config {
return c.Clone()
}

View File

@ -1,12 +1,12 @@
// +build go1.7,!go1.8
package tlsconfig
package client
import "crypto/tls"
// Clone returns a clone of tls.Config. This function is provided for
// tlsConfigClone returns a clone of tls.Config. This function is provided for
// compatibility for go1.7 that doesn't include this method in stdlib.
func Clone(c *tls.Config) *tls.Config {
func tlsConfigClone(c *tls.Config) *tls.Config {
return &tls.Config{
Rand: c.Rand,
Time: c.Time,

View File

@ -5,14 +5,6 @@ import (
"net/http"
)
// transportFunc allows us to inject a mock transport for testing. We define it
// here so we can detect the tlsconfig and return nil for only this type.
type transportFunc func(*http.Request) (*http.Response, error)
func (tf transportFunc) RoundTrip(req *http.Request) (*http.Response, error) {
return tf(req)
}
// resolveTLSConfig attempts to resolve the TLS configuration from the
// RoundTripper.
func resolveTLSConfig(transport http.RoundTripper) *tls.Config {

View File

@ -5,6 +5,7 @@ import (
"encoding/json"
"io/ioutil"
"net/http"
"path"
"github.com/docker/docker/api/types"
"golang.org/x/net/context"
@ -18,8 +19,15 @@ func (cli *Client) VolumeInspect(ctx context.Context, volumeID string) (types.Vo
// VolumeInspectWithRaw returns the information about a specific volume in the docker host and its raw representation
func (cli *Client) VolumeInspectWithRaw(ctx context.Context, volumeID string) (types.Volume, []byte, error) {
// The empty ID needs to be handled here because with an empty ID the
// request url will not contain a trailing / which calls the volume list API
// instead of volume inspect
if volumeID == "" {
return types.Volume{}, nil, volumeNotFoundError{volumeID}
}
var volume types.Volume
resp, err := cli.get(ctx, "/volumes/"+volumeID, nil, nil)
resp, err := cli.get(ctx, path.Join("/volumes", volumeID), nil, nil)
if err != nil {
if resp.statusCode == http.StatusNotFound {
return volume, nil, volumeNotFoundError{volumeID}

View File

@ -18,14 +18,6 @@ Generates AUTHORS; a file with all the names and corresponding emails of
individual contributors. AUTHORS can be found in the home directory of
this repository.
## Install (install.sh)
Executable install script for installing Docker. If updates to this are
desired, please use hack/release.sh during a normal release. The following
one-liner may be used for script hotfixes:
- `aws s3 cp --acl public-read hack/install.sh s3://get.docker.com/index`
## Make
There are two make files, each with different extensions. Neither are supposed
@ -45,14 +37,14 @@ More information is found within `make.ps1` by the author, @jhowardmsft
- Referenced via `make test` when running tests on a local machine,
or directly referenced when running tests inside a Docker development container.
- When running on a local machine, `make test` to run all tests found in
`test`, `test-unit`, `test-integration-cli`, and `test-docker-py` on
`test`, `test-unit`, `test-integration`, and `test-docker-py` on
your local machine. The default timeout is set in `make.sh` to 60 minutes
(`${TIMEOUT:=60m}`), since it currently takes up to an hour to run
all of the tests.
- When running inside a Docker development container, `hack/make.sh` does
not have a single target that runs all the tests. You need to provide a
single command line with multiple targets that performs the same thing.
An example referenced from [Run targets inside a development container](https://docs.docker.com/opensource/project/test-and-docs/#run-targets-inside-a-development-container): `root@5f8630b873fe:/go/src/github.com/moby/moby# hack/make.sh dynbinary binary cross test-unit test-integration-cli test-docker-py`
An example referenced from [Run targets inside a development container](https://docs.docker.com/opensource/project/test-and-docs/#run-targets-inside-a-development-container): `root@5f8630b873fe:/go/src/github.com/moby/moby# hack/make.sh dynbinary binary cross test-unit test-integration test-docker-py`
- For more information related to testing outside the scope of this README,
refer to
[Run tests and test documentation](https://docs.docker.com/opensource/project/test-and-docs/)

View File

@ -1,46 +0,0 @@
package opts
import (
"fmt"
"os"
"runtime"
"strings"
)
// ValidateEnv validates an environment variable and returns it.
// If no value is specified, it returns the current value using os.Getenv.
//
// As on ParseEnvFile and related to #16585, environment variable names
// are not validate what so ever, it's up to application inside docker
// to validate them or not.
//
// The only validation here is to check if name is empty, per #25099
func ValidateEnv(val string) (string, error) {
arr := strings.Split(val, "=")
if arr[0] == "" {
return "", fmt.Errorf("invalid environment variable: %s", val)
}
if len(arr) > 1 {
return val, nil
}
if !doesEnvExist(val) {
return val, nil
}
return fmt.Sprintf("%s=%s", val, os.Getenv(val)), nil
}
func doesEnvExist(name string) bool {
for _, entry := range os.Environ() {
parts := strings.SplitN(entry, "=", 2)
if runtime.GOOS == "windows" {
// Environment variable are case-insensitive on Windows. PaTh, path and PATH are equivalent.
if strings.EqualFold(parts[0], name) {
return true
}
}
if parts[0] == name {
return true
}
}
return false
}

View File

@ -1,165 +0,0 @@
package opts
import (
"fmt"
"net"
"net/url"
"strconv"
"strings"
)
var (
// DefaultHTTPPort Default HTTP Port used if only the protocol is provided to -H flag e.g. dockerd -H tcp://
// These are the IANA registered port numbers for use with Docker
// see http://www.iana.org/assignments/service-names-port-numbers/service-names-port-numbers.xhtml?search=docker
DefaultHTTPPort = 2375 // Default HTTP Port
// DefaultTLSHTTPPort Default HTTP Port used when TLS enabled
DefaultTLSHTTPPort = 2376 // Default TLS encrypted HTTP Port
// DefaultUnixSocket Path for the unix socket.
// Docker daemon by default always listens on the default unix socket
DefaultUnixSocket = "/var/run/docker.sock"
// DefaultTCPHost constant defines the default host string used by docker on Windows
DefaultTCPHost = fmt.Sprintf("tcp://%s:%d", DefaultHTTPHost, DefaultHTTPPort)
// DefaultTLSHost constant defines the default host string used by docker for TLS sockets
DefaultTLSHost = fmt.Sprintf("tcp://%s:%d", DefaultHTTPHost, DefaultTLSHTTPPort)
// DefaultNamedPipe defines the default named pipe used by docker on Windows
DefaultNamedPipe = `//./pipe/docker_engine`
)
// ValidateHost validates that the specified string is a valid host and returns it.
func ValidateHost(val string) (string, error) {
host := strings.TrimSpace(val)
// The empty string means default and is not handled by parseDockerDaemonHost
if host != "" {
_, err := parseDockerDaemonHost(host)
if err != nil {
return val, err
}
}
// Note: unlike most flag validators, we don't return the mutated value here
// we need to know what the user entered later (using ParseHost) to adjust for TLS
return val, nil
}
// ParseHost and set defaults for a Daemon host string
func ParseHost(defaultToTLS bool, val string) (string, error) {
host := strings.TrimSpace(val)
if host == "" {
if defaultToTLS {
host = DefaultTLSHost
} else {
host = DefaultHost
}
} else {
var err error
host, err = parseDockerDaemonHost(host)
if err != nil {
return val, err
}
}
return host, nil
}
// parseDockerDaemonHost parses the specified address and returns an address that will be used as the host.
// Depending of the address specified, this may return one of the global Default* strings defined in hosts.go.
func parseDockerDaemonHost(addr string) (string, error) {
addrParts := strings.SplitN(addr, "://", 2)
if len(addrParts) == 1 && addrParts[0] != "" {
addrParts = []string{"tcp", addrParts[0]}
}
switch addrParts[0] {
case "tcp":
return ParseTCPAddr(addrParts[1], DefaultTCPHost)
case "unix":
return parseSimpleProtoAddr("unix", addrParts[1], DefaultUnixSocket)
case "npipe":
return parseSimpleProtoAddr("npipe", addrParts[1], DefaultNamedPipe)
case "fd":
return addr, nil
default:
return "", fmt.Errorf("Invalid bind address format: %s", addr)
}
}
// parseSimpleProtoAddr parses and validates that the specified address is a valid
// socket address for simple protocols like unix and npipe. It returns a formatted
// socket address, either using the address parsed from addr, or the contents of
// defaultAddr if addr is a blank string.
func parseSimpleProtoAddr(proto, addr, defaultAddr string) (string, error) {
addr = strings.TrimPrefix(addr, proto+"://")
if strings.Contains(addr, "://") {
return "", fmt.Errorf("Invalid proto, expected %s: %s", proto, addr)
}
if addr == "" {
addr = defaultAddr
}
return fmt.Sprintf("%s://%s", proto, addr), nil
}
// ParseTCPAddr parses and validates that the specified address is a valid TCP
// address. It returns a formatted TCP address, either using the address parsed
// from tryAddr, or the contents of defaultAddr if tryAddr is a blank string.
// tryAddr is expected to have already been Trim()'d
// defaultAddr must be in the full `tcp://host:port` form
func ParseTCPAddr(tryAddr string, defaultAddr string) (string, error) {
if tryAddr == "" || tryAddr == "tcp://" {
return defaultAddr, nil
}
addr := strings.TrimPrefix(tryAddr, "tcp://")
if strings.Contains(addr, "://") || addr == "" {
return "", fmt.Errorf("Invalid proto, expected tcp: %s", tryAddr)
}
defaultAddr = strings.TrimPrefix(defaultAddr, "tcp://")
defaultHost, defaultPort, err := net.SplitHostPort(defaultAddr)
if err != nil {
return "", err
}
// url.Parse fails for trailing colon on IPv6 brackets on Go 1.5, but
// not 1.4. See https://github.com/golang/go/issues/12200 and
// https://github.com/golang/go/issues/6530.
if strings.HasSuffix(addr, "]:") {
addr += defaultPort
}
u, err := url.Parse("tcp://" + addr)
if err != nil {
return "", err
}
host, port, err := net.SplitHostPort(u.Host)
if err != nil {
// try port addition once
host, port, err = net.SplitHostPort(net.JoinHostPort(u.Host, defaultPort))
}
if err != nil {
return "", fmt.Errorf("Invalid bind address format: %s", tryAddr)
}
if host == "" {
host = defaultHost
}
if port == "" {
port = defaultPort
}
p, err := strconv.Atoi(port)
if err != nil && p == 0 {
return "", fmt.Errorf("Invalid bind address format: %s", tryAddr)
}
return fmt.Sprintf("tcp://%s%s", net.JoinHostPort(host, port), u.Path), nil
}
// ValidateExtraHost validates that the specified string is a valid extrahost and returns it.
// ExtraHost is in the form of name:ip where the ip has to be a valid ip (IPv4 or IPv6).
func ValidateExtraHost(val string) (string, error) {
// allow for IPv6 addresses in extra hosts by only splitting on first ":"
arr := strings.SplitN(val, ":", 2)
if len(arr) != 2 || len(arr[0]) == 0 {
return "", fmt.Errorf("bad format for add-host: %q", val)
}
if _, err := ValidateIPAddress(arr[1]); err != nil {
return "", fmt.Errorf("invalid IP address in add-host: %q", arr[1])
}
return val, nil
}

View File

@ -1,8 +0,0 @@
// +build !windows
package opts
import "fmt"
// DefaultHost constant defines the default host string used by docker on other hosts than Windows
var DefaultHost = fmt.Sprintf("unix://%s", DefaultUnixSocket)

View File

@ -1,6 +0,0 @@
// +build windows
package opts
// DefaultHost constant defines the default host string used by docker on Windows
var DefaultHost = "npipe://" + DefaultNamedPipe

View File

@ -1,47 +0,0 @@
package opts
import (
"fmt"
"net"
)
// IPOpt holds an IP. It is used to store values from CLI flags.
type IPOpt struct {
*net.IP
}
// NewIPOpt creates a new IPOpt from a reference net.IP and a
// string representation of an IP. If the string is not a valid
// IP it will fallback to the specified reference.
func NewIPOpt(ref *net.IP, defaultVal string) *IPOpt {
o := &IPOpt{
IP: ref,
}
o.Set(defaultVal)
return o
}
// Set sets an IPv4 or IPv6 address from a given string. If the given
// string is not parsable as an IP address it returns an error.
func (o *IPOpt) Set(val string) error {
ip := net.ParseIP(val)
if ip == nil {
return fmt.Errorf("%s is not an ip address", val)
}
*o.IP = ip
return nil
}
// String returns the IP address stored in the IPOpt. If stored IP is a
// nil pointer, it returns an empty string.
func (o *IPOpt) String() string {
if *o.IP == nil {
return ""
}
return o.IP.String()
}
// Type returns the type of the option
func (o *IPOpt) Type() string {
return "ip"
}

View File

@ -1,327 +0,0 @@
package opts
import (
"fmt"
"net"
"path"
"regexp"
"strings"
units "github.com/docker/go-units"
)
var (
alphaRegexp = regexp.MustCompile(`[a-zA-Z]`)
domainRegexp = regexp.MustCompile(`^(:?(:?[a-zA-Z0-9]|(:?[a-zA-Z0-9][a-zA-Z0-9\-]*[a-zA-Z0-9]))(:?\.(:?[a-zA-Z0-9]|(:?[a-zA-Z0-9][a-zA-Z0-9\-]*[a-zA-Z0-9])))*)\.?\s*$`)
)
// ListOpts holds a list of values and a validation function.
type ListOpts struct {
values *[]string
validator ValidatorFctType
}
// NewListOpts creates a new ListOpts with the specified validator.
func NewListOpts(validator ValidatorFctType) ListOpts {
var values []string
return *NewListOptsRef(&values, validator)
}
// NewListOptsRef creates a new ListOpts with the specified values and validator.
func NewListOptsRef(values *[]string, validator ValidatorFctType) *ListOpts {
return &ListOpts{
values: values,
validator: validator,
}
}
func (opts *ListOpts) String() string {
if len(*opts.values) == 0 {
return ""
}
return fmt.Sprintf("%v", *opts.values)
}
// Set validates if needed the input value and adds it to the
// internal slice.
func (opts *ListOpts) Set(value string) error {
if opts.validator != nil {
v, err := opts.validator(value)
if err != nil {
return err
}
value = v
}
(*opts.values) = append((*opts.values), value)
return nil
}
// Delete removes the specified element from the slice.
func (opts *ListOpts) Delete(key string) {
for i, k := range *opts.values {
if k == key {
(*opts.values) = append((*opts.values)[:i], (*opts.values)[i+1:]...)
return
}
}
}
// GetMap returns the content of values in a map in order to avoid
// duplicates.
func (opts *ListOpts) GetMap() map[string]struct{} {
ret := make(map[string]struct{})
for _, k := range *opts.values {
ret[k] = struct{}{}
}
return ret
}
// GetAll returns the values of slice.
func (opts *ListOpts) GetAll() []string {
return (*opts.values)
}
// GetAllOrEmpty returns the values of the slice
// or an empty slice when there are no values.
func (opts *ListOpts) GetAllOrEmpty() []string {
v := *opts.values
if v == nil {
return make([]string, 0)
}
return v
}
// Get checks the existence of the specified key.
func (opts *ListOpts) Get(key string) bool {
for _, k := range *opts.values {
if k == key {
return true
}
}
return false
}
// Len returns the amount of element in the slice.
func (opts *ListOpts) Len() int {
return len((*opts.values))
}
// Type returns a string name for this Option type
func (opts *ListOpts) Type() string {
return "list"
}
// WithValidator returns the ListOpts with validator set.
func (opts *ListOpts) WithValidator(validator ValidatorFctType) *ListOpts {
opts.validator = validator
return opts
}
// NamedOption is an interface that list and map options
// with names implement.
type NamedOption interface {
Name() string
}
// NamedListOpts is a ListOpts with a configuration name.
// This struct is useful to keep reference to the assigned
// field name in the internal configuration struct.
type NamedListOpts struct {
name string
ListOpts
}
var _ NamedOption = &NamedListOpts{}
// NewNamedListOptsRef creates a reference to a new NamedListOpts struct.
func NewNamedListOptsRef(name string, values *[]string, validator ValidatorFctType) *NamedListOpts {
return &NamedListOpts{
name: name,
ListOpts: *NewListOptsRef(values, validator),
}
}
// Name returns the name of the NamedListOpts in the configuration.
func (o *NamedListOpts) Name() string {
return o.name
}
// MapOpts holds a map of values and a validation function.
type MapOpts struct {
values map[string]string
validator ValidatorFctType
}
// Set validates if needed the input value and add it to the
// internal map, by splitting on '='.
func (opts *MapOpts) Set(value string) error {
if opts.validator != nil {
v, err := opts.validator(value)
if err != nil {
return err
}
value = v
}
vals := strings.SplitN(value, "=", 2)
if len(vals) == 1 {
(opts.values)[vals[0]] = ""
} else {
(opts.values)[vals[0]] = vals[1]
}
return nil
}
// GetAll returns the values of MapOpts as a map.
func (opts *MapOpts) GetAll() map[string]string {
return opts.values
}
func (opts *MapOpts) String() string {
return fmt.Sprintf("%v", map[string]string((opts.values)))
}
// Type returns a string name for this Option type
func (opts *MapOpts) Type() string {
return "map"
}
// NewMapOpts creates a new MapOpts with the specified map of values and a validator.
func NewMapOpts(values map[string]string, validator ValidatorFctType) *MapOpts {
if values == nil {
values = make(map[string]string)
}
return &MapOpts{
values: values,
validator: validator,
}
}
// NamedMapOpts is a MapOpts struct with a configuration name.
// This struct is useful to keep reference to the assigned
// field name in the internal configuration struct.
type NamedMapOpts struct {
name string
MapOpts
}
var _ NamedOption = &NamedMapOpts{}
// NewNamedMapOpts creates a reference to a new NamedMapOpts struct.
func NewNamedMapOpts(name string, values map[string]string, validator ValidatorFctType) *NamedMapOpts {
return &NamedMapOpts{
name: name,
MapOpts: *NewMapOpts(values, validator),
}
}
// Name returns the name of the NamedMapOpts in the configuration.
func (o *NamedMapOpts) Name() string {
return o.name
}
// ValidatorFctType defines a validator function that returns a validated string and/or an error.
type ValidatorFctType func(val string) (string, error)
// ValidatorFctListType defines a validator function that returns a validated list of string and/or an error
type ValidatorFctListType func(val string) ([]string, error)
// ValidateIPAddress validates an Ip address.
func ValidateIPAddress(val string) (string, error) {
var ip = net.ParseIP(strings.TrimSpace(val))
if ip != nil {
return ip.String(), nil
}
return "", fmt.Errorf("%s is not an ip address", val)
}
// ValidateDNSSearch validates domain for resolvconf search configuration.
// A zero length domain is represented by a dot (.).
func ValidateDNSSearch(val string) (string, error) {
if val = strings.Trim(val, " "); val == "." {
return val, nil
}
return validateDomain(val)
}
func validateDomain(val string) (string, error) {
if alphaRegexp.FindString(val) == "" {
return "", fmt.Errorf("%s is not a valid domain", val)
}
ns := domainRegexp.FindSubmatch([]byte(val))
if len(ns) > 0 && len(ns[1]) < 255 {
return string(ns[1]), nil
}
return "", fmt.Errorf("%s is not a valid domain", val)
}
// ValidateLabel validates that the specified string is a valid label, and returns it.
// Labels are in the form on key=value.
func ValidateLabel(val string) (string, error) {
if strings.Count(val, "=") < 1 {
return "", fmt.Errorf("bad attribute format: %s", val)
}
return val, nil
}
// ParseLink parses and validates the specified string as a link format (name:alias)
func ParseLink(val string) (string, string, error) {
if val == "" {
return "", "", fmt.Errorf("empty string specified for links")
}
arr := strings.Split(val, ":")
if len(arr) > 2 {
return "", "", fmt.Errorf("bad format for links: %s", val)
}
if len(arr) == 1 {
return val, val, nil
}
// This is kept because we can actually get a HostConfig with links
// from an already created container and the format is not `foo:bar`
// but `/foo:/c1/bar`
if strings.HasPrefix(arr[0], "/") {
_, alias := path.Split(arr[1])
return arr[0][1:], alias, nil
}
return arr[0], arr[1], nil
}
// MemBytes is a type for human readable memory bytes (like 128M, 2g, etc)
type MemBytes int64
// String returns the string format of the human readable memory bytes
func (m *MemBytes) String() string {
// NOTE: In spf13/pflag/flag.go, "0" is considered as "zero value" while "0 B" is not.
// We return "0" in case value is 0 here so that the default value is hidden.
// (Sometimes "default 0 B" is actually misleading)
if m.Value() != 0 {
return units.BytesSize(float64(m.Value()))
}
return "0"
}
// Set sets the value of the MemBytes by passing a string
func (m *MemBytes) Set(value string) error {
val, err := units.RAMInBytes(value)
*m = MemBytes(val)
return err
}
// Type returns the type
func (m *MemBytes) Type() string {
return "bytes"
}
// Value returns the value in int64
func (m *MemBytes) Value() int64 {
return int64(*m)
}
// UnmarshalJSON is the customized unmarshaler for MemBytes
func (m *MemBytes) UnmarshalJSON(s []byte) error {
if len(s) <= 2 || s[0] != '"' || s[len(s)-1] != '"' {
return fmt.Errorf("invalid size: %q", s)
}
val, err := units.RAMInBytes(string(s[1 : len(s)-1]))
*m = MemBytes(val)
return err
}

View File

@ -1,6 +0,0 @@
// +build !windows
package opts
// DefaultHTTPHost Default HTTP Host used if only port is provided to -H flag e.g. dockerd -H tcp://:8080
const DefaultHTTPHost = "localhost"

View File

@ -1,56 +0,0 @@
package opts
// TODO Windows. Identify bug in GOLang 1.5.1+ and/or Windows Server 2016 TP5.
// @jhowardmsft, @swernli.
//
// On Windows, this mitigates a problem with the default options of running
// a docker client against a local docker daemon on TP5.
//
// What was found that if the default host is "localhost", even if the client
// (and daemon as this is local) is not physically on a network, and the DNS
// cache is flushed (ipconfig /flushdns), then the client will pause for
// exactly one second when connecting to the daemon for calls. For example
// using docker run windowsservercore cmd, the CLI will send a create followed
// by an attach. You see the delay between the attach finishing and the attach
// being seen by the daemon.
//
// Here's some daemon debug logs with additional debug spew put in. The
// AfterWriteJSON log is the very last thing the daemon does as part of the
// create call. The POST /attach is the second CLI call. Notice the second
// time gap.
//
// time="2015-11-06T13:38:37.259627400-08:00" level=debug msg="After createRootfs"
// time="2015-11-06T13:38:37.263626300-08:00" level=debug msg="After setHostConfig"
// time="2015-11-06T13:38:37.267631200-08:00" level=debug msg="before createContainerPl...."
// time="2015-11-06T13:38:37.271629500-08:00" level=debug msg=ToDiskLocking....
// time="2015-11-06T13:38:37.275643200-08:00" level=debug msg="loggin event...."
// time="2015-11-06T13:38:37.277627600-08:00" level=debug msg="logged event...."
// time="2015-11-06T13:38:37.279631800-08:00" level=debug msg="In defer func"
// time="2015-11-06T13:38:37.282628100-08:00" level=debug msg="After daemon.create"
// time="2015-11-06T13:38:37.286651700-08:00" level=debug msg="return 2"
// time="2015-11-06T13:38:37.289629500-08:00" level=debug msg="Returned from daemon.ContainerCreate"
// time="2015-11-06T13:38:37.311629100-08:00" level=debug msg="After WriteJSON"
// ... 1 second gap here....
// time="2015-11-06T13:38:38.317866200-08:00" level=debug msg="Calling POST /v1.22/containers/984758282b842f779e805664b2c95d563adc9a979c8a3973e68c807843ee4757/attach"
// time="2015-11-06T13:38:38.326882500-08:00" level=info msg="POST /v1.22/containers/984758282b842f779e805664b2c95d563adc9a979c8a3973e68c807843ee4757/attach?stderr=1&stdin=1&stdout=1&stream=1"
//
// We suspect this is either a bug introduced in GOLang 1.5.1, or that a change
// in GOLang 1.5.1 (from 1.4.3) is exposing a bug in Windows. In theory,
// the Windows networking stack is supposed to resolve "localhost" internally,
// without hitting DNS, or even reading the hosts file (which is why localhost
// is commented out in the hosts file on Windows).
//
// We have validated that working around this using the actual IPv4 localhost
// address does not cause the delay.
//
// This does not occur with the docker client built with 1.4.3 on the same
// Windows build, regardless of whether the daemon is built using 1.5.1
// or 1.4.3. It does not occur on Linux. We also verified we see the same thing
// on a cross-compiled Windows binary (from Linux).
//
// Final note: This is a mitigation, not a 'real' fix. It is still susceptible
// to the delay if a user were to do 'docker run -H=tcp://localhost:2375...'
// explicitly.
// DefaultHTTPHost Default HTTP Host used if only port is provided to -H flag e.g. dockerd -H tcp://:8080
const DefaultHTTPHost = "127.0.0.1"

View File

@ -1,37 +0,0 @@
package opts
// QuotedString is a string that may have extra quotes around the value. The
// quotes are stripped from the value.
type QuotedString struct {
value *string
}
// Set sets a new value
func (s *QuotedString) Set(val string) error {
*s.value = trimQuotes(val)
return nil
}
// Type returns the type of the value
func (s *QuotedString) Type() string {
return "string"
}
func (s *QuotedString) String() string {
return string(*s.value)
}
func trimQuotes(value string) string {
lastIndex := len(value) - 1
for _, char := range []byte{'\'', '"'} {
if value[0] == char && value[lastIndex] == char {
return value[1:lastIndex]
}
}
return value
}
// NewQuotedString returns a new quoted string option
func NewQuotedString(value *string) *QuotedString {
return &QuotedString{value: value}
}

View File

@ -1,79 +0,0 @@
package opts
import (
"fmt"
"strings"
"github.com/docker/docker/api/types"
)
// RuntimeOpt defines a map of Runtimes
type RuntimeOpt struct {
name string
stockRuntimeName string
values *map[string]types.Runtime
}
// NewNamedRuntimeOpt creates a new RuntimeOpt
func NewNamedRuntimeOpt(name string, ref *map[string]types.Runtime, stockRuntime string) *RuntimeOpt {
if ref == nil {
ref = &map[string]types.Runtime{}
}
return &RuntimeOpt{name: name, values: ref, stockRuntimeName: stockRuntime}
}
// Name returns the name of the NamedListOpts in the configuration.
func (o *RuntimeOpt) Name() string {
return o.name
}
// Set validates and updates the list of Runtimes
func (o *RuntimeOpt) Set(val string) error {
parts := strings.SplitN(val, "=", 2)
if len(parts) != 2 {
return fmt.Errorf("invalid runtime argument: %s", val)
}
parts[0] = strings.TrimSpace(parts[0])
parts[1] = strings.TrimSpace(parts[1])
if parts[0] == "" || parts[1] == "" {
return fmt.Errorf("invalid runtime argument: %s", val)
}
parts[0] = strings.ToLower(parts[0])
if parts[0] == o.stockRuntimeName {
return fmt.Errorf("runtime name '%s' is reserved", o.stockRuntimeName)
}
if _, ok := (*o.values)[parts[0]]; ok {
return fmt.Errorf("runtime '%s' was already defined", parts[0])
}
(*o.values)[parts[0]] = types.Runtime{Path: parts[1]}
return nil
}
// String returns Runtime values as a string.
func (o *RuntimeOpt) String() string {
var out []string
for k := range *o.values {
out = append(out, k)
}
return fmt.Sprintf("%v", out)
}
// GetMap returns a map of Runtimes (name: path)
func (o *RuntimeOpt) GetMap() map[string]types.Runtime {
if o.values != nil {
return *o.values
}
return map[string]types.Runtime{}
}
// Type returns the type of the option
func (o *RuntimeOpt) Type() string {
return "runtime"
}

View File

@ -1,81 +0,0 @@
package opts
import (
"fmt"
"github.com/docker/go-units"
)
// UlimitOpt defines a map of Ulimits
type UlimitOpt struct {
values *map[string]*units.Ulimit
}
// NewUlimitOpt creates a new UlimitOpt
func NewUlimitOpt(ref *map[string]*units.Ulimit) *UlimitOpt {
if ref == nil {
ref = &map[string]*units.Ulimit{}
}
return &UlimitOpt{ref}
}
// Set validates a Ulimit and sets its name as a key in UlimitOpt
func (o *UlimitOpt) Set(val string) error {
l, err := units.ParseUlimit(val)
if err != nil {
return err
}
(*o.values)[l.Name] = l
return nil
}
// String returns Ulimit values as a string.
func (o *UlimitOpt) String() string {
var out []string
for _, v := range *o.values {
out = append(out, v.String())
}
return fmt.Sprintf("%v", out)
}
// GetList returns a slice of pointers to Ulimits.
func (o *UlimitOpt) GetList() []*units.Ulimit {
var ulimits []*units.Ulimit
for _, v := range *o.values {
ulimits = append(ulimits, v)
}
return ulimits
}
// Type returns the option type
func (o *UlimitOpt) Type() string {
return "ulimit"
}
// NamedUlimitOpt defines a named map of Ulimits
type NamedUlimitOpt struct {
name string
UlimitOpt
}
var _ NamedOption = &NamedUlimitOpt{}
// NewNamedUlimitOpt creates a new NamedUlimitOpt
func NewNamedUlimitOpt(name string, ref *map[string]*units.Ulimit) *NamedUlimitOpt {
if ref == nil {
ref = &map[string]*units.Ulimit{}
}
return &NamedUlimitOpt{
name: name,
UlimitOpt: *NewUlimitOpt(ref),
}
}
// Name returns the option name
func (o *NamedUlimitOpt) Name() string {
return o.name
}

View File

@ -16,13 +16,13 @@ import (
"strings"
"syscall"
"github.com/Sirupsen/logrus"
"github.com/docker/docker/pkg/fileutils"
"github.com/docker/docker/pkg/idtools"
"github.com/docker/docker/pkg/ioutils"
"github.com/docker/docker/pkg/pools"
"github.com/docker/docker/pkg/promise"
"github.com/docker/docker/pkg/system"
"github.com/sirupsen/logrus"
)
type (
@ -93,6 +93,16 @@ const (
OverlayWhiteoutFormat
)
const (
modeISDIR = 040000 // Directory
modeISFIFO = 010000 // FIFO
modeISREG = 0100000 // Regular file
modeISLNK = 0120000 // Symbolic link
modeISBLK = 060000 // Block special file
modeISCHR = 020000 // Character special file
modeISSOCK = 0140000 // Socket
)
// IsArchivePath checks if the (possibly compressed) file at the given path
// starts with a tar file header.
func IsArchivePath(path string) bool {
@ -305,12 +315,14 @@ func (compression *Compression) Extension() string {
// FileInfoHeader creates a populated Header from fi.
// Compared to archive pkg this function fills in more information.
// Also, regardless of Go version, this function fills file type bits (e.g. hdr.Mode |= modeISDIR),
// which have been deleted since Go 1.9 archive/tar.
func FileInfoHeader(name string, fi os.FileInfo, link string) (*tar.Header, error) {
hdr, err := tar.FileInfoHeader(fi, link)
if err != nil {
return nil, err
}
hdr.Mode = int64(chmodTarEntry(os.FileMode(hdr.Mode)))
hdr.Mode = fillGo18FileTypeBits(int64(chmodTarEntry(os.FileMode(hdr.Mode))), fi)
name, err = canonicalTarName(name, fi.IsDir())
if err != nil {
return nil, fmt.Errorf("tar: cannot canonicalize path: %v", err)
@ -322,6 +334,31 @@ func FileInfoHeader(name string, fi os.FileInfo, link string) (*tar.Header, erro
return hdr, nil
}
// fillGo18FileTypeBits fills type bits which have been removed on Go 1.9 archive/tar
// https://github.com/golang/go/commit/66b5a2f
func fillGo18FileTypeBits(mode int64, fi os.FileInfo) int64 {
fm := fi.Mode()
switch {
case fm.IsRegular():
mode |= modeISREG
case fi.IsDir():
mode |= modeISDIR
case fm&os.ModeSymlink != 0:
mode |= modeISLNK
case fm&os.ModeDevice != 0:
if fm&os.ModeCharDevice != 0 {
mode |= modeISCHR
} else {
mode |= modeISBLK
}
case fm&os.ModeNamedPipe != 0:
mode |= modeISFIFO
case fm&os.ModeSocket != 0:
mode |= modeISSOCK
}
return mode
}
// ReadSecurityXattrToTarHeader reads security.capability xattr from filesystem
// to a tar header
func ReadSecurityXattrToTarHeader(path string, hdr *tar.Header) error {
@ -345,6 +382,7 @@ type tarAppender struct {
// for hardlink mapping
SeenFiles map[uint64]string
IDMappings *idtools.IDMappings
ChownOpts *idtools.IDPair
// For packing and unpacking whiteout files in the
// non standard format. The whiteout files defined
@ -353,12 +391,13 @@ type tarAppender struct {
WhiteoutConverter tarWhiteoutConverter
}
func newTarAppender(idMapping *idtools.IDMappings, writer io.Writer) *tarAppender {
func newTarAppender(idMapping *idtools.IDMappings, writer io.Writer, chownOpts *idtools.IDPair) *tarAppender {
return &tarAppender{
SeenFiles: make(map[uint64]string),
TarWriter: tar.NewWriter(writer),
Buffer: pools.BufioWriter32KPool.Get(nil),
IDMappings: idMapping,
ChownOpts: chownOpts,
}
}
@ -433,6 +472,12 @@ func (ta *tarAppender) addTarFile(path, name string) error {
}
}
// explicitly override with ChownOpts
if ta.ChownOpts != nil {
hdr.Uid = ta.ChownOpts.UID
hdr.Gid = ta.ChownOpts.GID
}
if ta.WhiteoutConverter != nil {
wo, err := ta.WhiteoutConverter.ConvertWrite(hdr, path, fi)
if err != nil {
@ -558,7 +603,7 @@ func createTarFile(path, extractDir string, hdr *tar.Header, reader io.Reader, L
return nil
default:
return fmt.Errorf("Unhandled tar header type %d\n", hdr.Typeflag)
return fmt.Errorf("unhandled tar header type %d", hdr.Typeflag)
}
// Lchown is not supported on Windows.
@ -655,6 +700,7 @@ func TarWithOptions(srcPath string, options *TarOptions) (io.ReadCloser, error)
ta := newTarAppender(
idtools.NewIDMappingsFromMaps(options.UIDMaps, options.GIDMaps),
compressWriter,
options.ChownOpts,
)
ta.WhiteoutConverter = getWhiteoutConverter(options.WhiteoutFormat)

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