From 8adcc1277ac77be8e1351b4c031f30d8f894423c Mon Sep 17 00:00:00 2001 From: Daniel Nephin Date: Fri, 23 Jun 2017 00:52:34 -0400 Subject: [PATCH 01/47] Add a warning when make is run outside of a container. The warning can be disabled by setting the environment variable Signed-off-by: Daniel Nephin Upstream-commit: 12a7387c8e6394e16dd9449500a0532f465184c0 Component: cli --- components/cli/Makefile | 2 ++ components/cli/docker.Makefile | 22 ++++++++++--------- components/cli/scripts/warn-outside-container | 18 +++++++++++++++ 3 files changed, 32 insertions(+), 10 deletions(-) create mode 100755 components/cli/scripts/warn-outside-container diff --git a/components/cli/Makefile b/components/cli/Makefile index 771f496abe..81b0041b84 100644 --- a/components/cli/Makefile +++ b/components/cli/Makefile @@ -4,6 +4,8 @@ all: binary +_:=$(shell ./scripts/warn-outside-container $(MAKECMDGOALS)) + .PHONY: clean clean: ## remove build artifacts rm -rf ./build/* cli/winresources/rsrc_* ./man/man[1-9] docs/yaml/gen diff --git a/components/cli/docker.Makefile b/components/cli/docker.Makefile index 9b958397a1..4aaee5489a 100644 --- a/components/cli/docker.Makefile +++ b/components/cli/docker.Makefile @@ -10,7 +10,7 @@ CROSS_IMAGE_NAME = docker-cli-cross VALIDATE_IMAGE_NAME = docker-cli-shell-validate MOUNTS = -v "$(CURDIR)":/go/src/github.com/docker/cli VERSION = $(shell cat VERSION) -ENVVARS = -e VERSION=$(VERSION) -e GITCOMMIT +ENVVARS = -e VERSION=$(VERSION) -e GITCOMMIT -e DISABLE_WARN_OUTSIDE_CONTAINER=1 # build docker image (dockerfiles/Dockerfile.build) .PHONY: build_docker_image @@ -39,12 +39,12 @@ build: binary # clean build artifacts using a container .PHONY: clean clean: build_docker_image - docker run --rm $(MOUNTS) $(DEV_DOCKER_IMAGE_NAME) make clean + docker run --rm $(ENVVARS) $(MOUNTS) $(DEV_DOCKER_IMAGE_NAME) make clean # run go test .PHONY: test test: build_docker_image - docker run --rm $(MOUNTS) $(DEV_DOCKER_IMAGE_NAME) make test + docker run --rm $(ENVVARS) $(MOUNTS) $(DEV_DOCKER_IMAGE_NAME) make test # build the CLI for multiple architectures using a container .PHONY: cross @@ -53,24 +53,26 @@ cross: build_cross_image .PHONY: watch watch: build_docker_image - docker run --rm $(MOUNTS) $(DEV_DOCKER_IMAGE_NAME) make watch + docker run --rm $(ENVVARS) $(MOUNTS) $(DEV_DOCKER_IMAGE_NAME) make watch # start container in interactive mode for in-container development .PHONY: dev dev: build_docker_image - docker run -ti $(MOUNTS) -v /var/run/docker.sock:/var/run/docker.sock $(DEV_DOCKER_IMAGE_NAME) ash + docker run -ti $(ENVVARS) $(MOUNTS) \ + -v /var/run/docker.sock:/var/run/docker.sock \ + $(DEV_DOCKER_IMAGE_NAME) ash shell: dev # run linters in a container .PHONY: lint lint: build_linter_image - docker run -ti $(MOUNTS) $(LINTER_IMAGE_NAME) + docker run -ti $(ENVVARS) $(MOUNTS) $(LINTER_IMAGE_NAME) # download dependencies (vendor/) listed in vendor.conf, using a container .PHONY: vendor vendor: build_docker_image vendor.conf - docker run -ti --rm $(MOUNTS) $(DEV_DOCKER_IMAGE_NAME) make vendor + docker run -ti --rm $(ENVVARS) $(MOUNTS) $(DEV_DOCKER_IMAGE_NAME) make vendor dynbinary: build_cross_image docker run -ti --rm $(ENVVARS) $(MOUNTS) $(CROSS_IMAGE_NAME) make dynbinary @@ -78,13 +80,13 @@ dynbinary: build_cross_image ## generate man pages from go source and markdown .PHONY: manpages manpages: build_docker_image - docker run -ti --rm $(MOUNTS) $(DEV_DOCKER_IMAGE_NAME) make manpages + docker run -ti --rm $(ENVVARS) $(MOUNTS) $(DEV_DOCKER_IMAGE_NAME) make manpages ## Generate documentation YAML files consumed by docs repo .PHONY: yamldocs yamldocs: build_docker_image - docker run -ti --rm $(MOUNTS) $(DEV_DOCKER_IMAGE_NAME) make yamldocs + docker run -ti --rm $(ENVVARS) $(MOUNTS) $(DEV_DOCKER_IMAGE_NAME) make yamldocs .PHONY: shellcheck shellcheck: build_shell_validate_image - docker run -ti --rm $(MOUNTS) $(VALIDATE_IMAGE_NAME) make shellcheck + docker run -ti --rm $(ENVVARS) $(MOUNTS) $(VALIDATE_IMAGE_NAME) make shellcheck diff --git a/components/cli/scripts/warn-outside-container b/components/cli/scripts/warn-outside-container new file mode 100755 index 0000000000..cb11b8fa8d --- /dev/null +++ b/components/cli/scripts/warn-outside-container @@ -0,0 +1,18 @@ +#!/usr/bin/env bash +set -eu + +target="${1:-}" + +if [[ -z "${DISABLE_WARN_OUTSIDE_CONTAINER:-}" ]]; then + ( + echo + echo + echo "WARNING: you are not in a container." + echo "Use \"make -f docker.Makefile $target\" or set" + echo "DISABLE_WARN_OUTSIDE_CONTAINER=1 to disable this warning." + echo + echo "Press Ctrl+C now to abort." + echo + ) >&2 + sleep 10 +fi From 814542744c0dfb9dd7e7e57d7ba7504a0d0f9818 Mon Sep 17 00:00:00 2001 From: Sebastiaan van Stijn Date: Wed, 26 Jul 2017 15:33:57 +0200 Subject: [PATCH 02/47] Preserve resolved image-digest if QueryRegistry == false When re-deploying a stack without re-resolving the image digest, the service's ContainerSpec was updated with the image-reference as specified in the stack/compose file. As a result, the image-digest that was resolved in a previous deploy was overwritten, causing the service to be re-deployed. This patch preserves the previously resolve image-digest by copying it from the current service spec. A unit test is also added to verify that the image information in the service spec is not updated if QueryRegistry is disabled. Signed-off-by: Sebastiaan van Stijn Upstream-commit: d0bea64185218807ac007f14d903f2d2409da756 Component: cli --- .../cli/cli/command/stack/client_test.go | 19 ++++- .../cli/command/stack/deploy_composefile.go | 11 ++- .../cli/cli/command/stack/deploy_test.go | 79 +++++++++++++++++++ 3 files changed, 103 insertions(+), 6 deletions(-) diff --git a/components/cli/cli/command/stack/client_test.go b/components/cli/cli/command/stack/client_test.go index d1d85193e7..bcb92db6c9 100644 --- a/components/cli/cli/command/stack/client_test.go +++ b/components/cli/cli/command/stack/client_test.go @@ -34,10 +34,13 @@ type fakeClient struct { nodeListFunc func(options types.NodeListOptions) ([]swarm.Node, error) taskListFunc func(options types.TaskListOptions) ([]swarm.Task, error) nodeInspectWithRaw func(ref string) (swarm.Node, []byte, error) - serviceRemoveFunc func(serviceID string) error - networkRemoveFunc func(networkID string) error - secretRemoveFunc func(secretID string) error - configRemoveFunc func(configID string) error + + serviceUpdateFunc func(serviceID string, version swarm.Version, service swarm.ServiceSpec, options types.ServiceUpdateOptions) (types.ServiceUpdateResponse, error) + + serviceRemoveFunc func(serviceID string) error + networkRemoveFunc func(networkID string) error + secretRemoveFunc func(secretID string) error + configRemoveFunc func(configID string) error } func (cli *fakeClient) ServerVersion(ctx context.Context) (types.Version, error) { @@ -132,6 +135,14 @@ func (cli *fakeClient) NodeInspectWithRaw(ctx context.Context, ref string) (swar return swarm.Node{}, nil, nil } +func (cli *fakeClient) ServiceUpdate(ctx context.Context, serviceID string, version swarm.Version, service swarm.ServiceSpec, options types.ServiceUpdateOptions) (types.ServiceUpdateResponse, error) { + if cli.serviceUpdateFunc != nil { + return cli.serviceUpdateFunc(serviceID, version, service, options) + } + + return types.ServiceUpdateResponse{}, nil +} + func (cli *fakeClient) ServiceRemove(ctx context.Context, serviceID string) error { if cli.serviceRemoveFunc != nil { return cli.serviceRemoveFunc(serviceID) diff --git a/components/cli/cli/command/stack/deploy_composefile.go b/components/cli/cli/command/stack/deploy_composefile.go index 1f50ae1a1d..16d583ed99 100644 --- a/components/cli/cli/command/stack/deploy_composefile.go +++ b/components/cli/cli/command/stack/deploy_composefile.go @@ -318,10 +318,17 @@ func deployServices( updateOpts := types.ServiceUpdateOptions{EncodedRegistryAuth: encodedAuth} - if resolveImage == resolveImageAlways || (resolveImage == resolveImageChanged && image != service.Spec.Labels[convert.LabelImage]) { + switch { + case resolveImage == resolveImageAlways || (resolveImage == resolveImageChanged && image != service.Spec.Labels[convert.LabelImage]): + // image should be updated by the server using QueryRegistry updateOpts.QueryRegistry = true + case image == service.Spec.Labels[convert.LabelImage]: + // image has not changed; update the serviceSpec with the + // existing information that was set by QueryRegistry on the + // previous deploy. Otherwise this will trigger an incorrect + // service update. + serviceSpec.TaskTemplate.ContainerSpec.Image = service.Spec.TaskTemplate.ContainerSpec.Image } - response, err := apiClient.ServiceUpdate( ctx, service.ID, diff --git a/components/cli/cli/command/stack/deploy_test.go b/components/cli/cli/command/stack/deploy_test.go index c04f86c251..f91a825f9b 100644 --- a/components/cli/cli/command/stack/deploy_test.go +++ b/components/cli/cli/command/stack/deploy_test.go @@ -5,6 +5,8 @@ import ( "github.com/docker/cli/cli/compose/convert" "github.com/docker/cli/cli/internal/test" + "github.com/docker/docker/api/types" + "github.com/docker/docker/api/types/swarm" "github.com/stretchr/testify/assert" "golang.org/x/net/context" ) @@ -22,3 +24,80 @@ func TestPruneServices(t *testing.T) { pruneServices(ctx, dockerCli, namespace, services) assert.Equal(t, buildObjectIDs([]string{objectName("foo", "remove")}), client.removedServices) } + +// TestServiceUpdateResolveImageChanged tests that the service's +// image digest is preserved if the image did not change in the compose file +func TestServiceUpdateResolveImageChanged(t *testing.T) { + namespace := convert.NewNamespace("mystack") + + var ( + receivedOptions types.ServiceUpdateOptions + receivedService swarm.ServiceSpec + ) + + client := test.NewFakeCli(&fakeClient{ + serviceListFunc: func(options types.ServiceListOptions) ([]swarm.Service, error) { + return []swarm.Service{ + { + Spec: swarm.ServiceSpec{ + Annotations: swarm.Annotations{ + Name: namespace.Name() + "_myservice", + Labels: map[string]string{"com.docker.stack.image": "foobar:1.2.3"}, + }, + TaskTemplate: swarm.TaskSpec{ + ContainerSpec: swarm.ContainerSpec{ + Image: "foobar:1.2.3@sha256:deadbeef", + }, + }, + }, + }, + }, nil + }, + serviceUpdateFunc: func(serviceID string, version swarm.Version, service swarm.ServiceSpec, options types.ServiceUpdateOptions) (types.ServiceUpdateResponse, error) { + receivedOptions = options + receivedService = service + return types.ServiceUpdateResponse{}, nil + }, + }) + + var testcases = []struct { + image string + expectedQueryRegistry bool + expectedImage string + }{ + // Image not changed + { + image: "foobar:1.2.3", + expectedQueryRegistry: false, + expectedImage: "foobar:1.2.3@sha256:deadbeef", + }, + // Image changed + { + image: "foobar:1.2.4", + expectedQueryRegistry: true, + expectedImage: "foobar:1.2.4", + }, + } + + ctx := context.Background() + + for _, testcase := range testcases { + t.Logf("Testing image %q", testcase.image) + spec := map[string]swarm.ServiceSpec{ + "myservice": { + TaskTemplate: swarm.TaskSpec{ + ContainerSpec: swarm.ContainerSpec{ + Image: testcase.image, + }, + }, + }, + } + err := deployServices(ctx, client, spec, namespace, false, resolveImageChanged) + assert.NoError(t, err) + assert.Equal(t, testcase.expectedQueryRegistry, receivedOptions.QueryRegistry) + assert.Equal(t, testcase.expectedImage, receivedService.TaskTemplate.ContainerSpec.Image) + + receivedService = swarm.ServiceSpec{} + receivedOptions = types.ServiceUpdateOptions{} + } +} From 2d71d40a39c58271e2cd4f6abb497938be940f85 Mon Sep 17 00:00:00 2001 From: Kir Kolyshkin Date: Thu, 20 Jul 2017 14:42:51 -0700 Subject: [PATCH 03/47] Introduce/document new IPC modes This builds (and depends) on https://github.com/moby/moby/pull/34087 Version 2: - remove --ipc argument validation (it is now done by daemon) - add/document 'none' value - docs/reference/run.md: add a table with better modes description - dockerd(8) typesetting fixes Version 3: - remove ipc mode tests from cli/command/container/opts_test.go Signed-off-by: Kir Kolyshkin Upstream-commit: 9285db67525c4dce4308903dcf80627f693388dc Component: cli --- components/cli/cli/command/container/opts.go | 9 ++------ .../cli/cli/command/container/opts_test.go | 15 ++----------- components/cli/contrib/completion/bash/docker | 2 +- components/cli/docs/reference/run.md | 21 ++++++++++++++----- components/cli/man/dockerd.8.md | 5 +++++ 5 files changed, 26 insertions(+), 26 deletions(-) diff --git a/components/cli/cli/command/container/opts.go b/components/cli/cli/command/container/opts.go index cf1f931b29..f80474d3fe 100644 --- a/components/cli/cli/command/container/opts.go +++ b/components/cli/cli/command/container/opts.go @@ -274,7 +274,7 @@ func addFlags(flags *pflag.FlagSet) *containerOptions { // Low-level execution (cgroups, namespaces, ...) flags.StringVar(&copts.cgroupParent, "cgroup-parent", "", "Optional parent cgroup for the container") - flags.StringVar(&copts.ipcMode, "ipc", "", "IPC namespace to use") + flags.StringVar(&copts.ipcMode, "ipc", "", "IPC mode to use") flags.StringVar(&copts.isolation, "isolation", "", "Container isolation technology") flags.StringVar(&copts.pidMode, "pid", "", "PID namespace to use") flags.Var(&copts.shmSize, "shm-size", "Size of /dev/shm") @@ -421,11 +421,6 @@ func parse(flags *pflag.FlagSet, copts *containerOptions) (*containerConfig, err return nil, err } - ipcMode := container.IpcMode(copts.ipcMode) - if !ipcMode.Valid() { - return nil, errors.Errorf("--ipc: invalid IPC mode") - } - pidMode := container.PidMode(copts.pidMode) if !pidMode.Valid() { return nil, errors.Errorf("--pid: invalid PID mode") @@ -584,7 +579,7 @@ func parse(flags *pflag.FlagSet, copts *containerOptions) (*containerConfig, err ExtraHosts: copts.extraHosts.GetAll(), VolumesFrom: copts.volumesFrom.GetAll(), NetworkMode: container.NetworkMode(copts.netMode), - IpcMode: ipcMode, + IpcMode: container.IpcMode(copts.ipcMode), PidMode: pidMode, UTSMode: utsMode, UsernsMode: usernsMode, diff --git a/components/cli/cli/command/container/opts_test.go b/components/cli/cli/command/container/opts_test.go index 25e5b04fc8..6443ed3310 100644 --- a/components/cli/cli/command/container/opts_test.go +++ b/components/cli/cli/command/container/opts_test.go @@ -366,23 +366,12 @@ func TestParseDevice(t *testing.T) { } func TestParseModes(t *testing.T) { - // ipc ko - _, _, _, err := parseRun([]string{"--ipc=container:", "img", "cmd"}) - testutil.ErrorContains(t, err, "--ipc: invalid IPC mode") - - // ipc ok - _, hostconfig, _, err := parseRun([]string{"--ipc=host", "img", "cmd"}) - require.NoError(t, err) - if !hostconfig.IpcMode.Valid() { - t.Fatalf("Expected a valid IpcMode, got %v", hostconfig.IpcMode) - } - // pid ko - _, _, _, err = parseRun([]string{"--pid=container:", "img", "cmd"}) + _, _, _, err := parseRun([]string{"--pid=container:", "img", "cmd"}) testutil.ErrorContains(t, err, "--pid: invalid PID mode") // pid ok - _, hostconfig, _, err = parseRun([]string{"--pid=host", "img", "cmd"}) + _, hostconfig, _, err := parseRun([]string{"--pid=host", "img", "cmd"}) require.NoError(t, err) if !hostconfig.PidMode.Valid() { t.Fatalf("Expected a valid PidMode, got %v", hostconfig.PidMode) diff --git a/components/cli/contrib/completion/bash/docker b/components/cli/contrib/completion/bash/docker index 280bca1069..55613d70a5 100644 --- a/components/cli/contrib/completion/bash/docker +++ b/components/cli/contrib/completion/bash/docker @@ -1862,7 +1862,7 @@ _docker_container_run_and_create() { __docker_complete_containers_running ;; *) - COMPREPLY=( $( compgen -W 'host container:' -- "$cur" ) ) + COMPREPLY=( $( compgen -W 'none host private shareable container:' -- "$cur" ) ) # shellcheck disable=SC2128 if [ "$COMPREPLY" = "container:" ]; then __docker_nospace diff --git a/components/cli/docs/reference/run.md b/components/cli/docs/reference/run.md index 4a1a4c1cb9..22d3b249d3 100644 --- a/components/cli/docs/reference/run.md +++ b/components/cli/docs/reference/run.md @@ -265,11 +265,21 @@ more advanced use case would be changing the host's hostname from a container. ## IPC settings (--ipc) - --ipc="" : Set the IPC mode for the container, - 'container:': reuses another container's IPC namespace - 'host': use the host's IPC namespace inside the container + --ipc="MODE" : Set the IPC mode for the container -By default, all containers have the IPC namespace enabled. +The following values are accepted: + +| Value | Description | +|:---------------------------|:----------------------------------------------------------------------------------| +| "" | Use daemon's default. | +| "none" | Own private IPC namespace, with /dev/shm not mounted. | +| "private" | Own private IPC namespace. | +| "shareable" | Own private IPC namespace, with a possibility to share it with other containers. | +| "container:<_name-or-ID_>" | Join another ("shareable") container's IPC namespace. | +| "host" | Use the host system's IPC namespace. | + +If not specified, daemon default is used, which can either be `"private"` +or `"shareable"`, depending on the daemon version and configration. IPC (POSIX/SysV IPC) namespace provides separation of named shared memory segments, semaphores and message queues. @@ -280,7 +290,8 @@ memory is commonly used by databases and custom-built (typically C/OpenMPI, C++/using boost libraries) high performance applications for scientific computing and financial services industries. If these types of applications are broken into multiple containers, you might need to share the IPC mechanisms -of the containers. +of the containers, using `"shareable"` mode for the main (i.e. "donor") +container, and `"container:"` for other containers. ## Network settings diff --git a/components/cli/man/dockerd.8.md b/components/cli/man/dockerd.8.md index 8a7619ca2c..733cc20f88 100644 --- a/components/cli/man/dockerd.8.md +++ b/components/cli/man/dockerd.8.md @@ -23,6 +23,7 @@ dockerd - Enable daemon mode [**--default-gateway**[=*DEFAULT-GATEWAY*]] [**--default-gateway-v6**[=*DEFAULT-GATEWAY-V6*]] [**--default-runtime**[=*runc*]] +[**--default-ipc-mode**=*MODE*] [**--default-shm-size**[=*64MiB*]] [**--default-ulimit**[=*[]*]] [**--disable-legacy-registry**] @@ -185,6 +186,10 @@ $ sudo dockerd --add-runtime runc=runc --add-runtime custom=/usr/local/bin/my-ru **--default-runtime**="runc" Set default runtime if there're more than one specified by `--add-runtime`. +**--default-ipc-mode**="**private**|**shareable**" + Set the default IPC mode for newly created containers. The argument + can either be **private** or **shareable**. + **--default-shm-size**=*64MiB* Set the daemon-wide default shm size for containers. Default is `64MiB`. From 148a5718295145e1c7b2f01b9660ebbaa4575604 Mon Sep 17 00:00:00 2001 From: Daniel Nephin Date: Wed, 9 Aug 2017 10:50:32 -0400 Subject: [PATCH 04/47] Add network and target to build in v3.4 Signed-off-by: Daniel Nephin Upstream-commit: eef256943bf04540370a273d0ef39a91919ef89d Component: cli --- components/cli/cli/compose/schema/bindata.go | 2 +- .../cli/cli/compose/schema/data/config_schema_v3.4.json | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/components/cli/cli/compose/schema/bindata.go b/components/cli/cli/compose/schema/bindata.go index 4f34a8b6e9..cfd6a91c66 100644 --- a/components/cli/cli/compose/schema/bindata.go +++ b/components/cli/cli/compose/schema/bindata.go @@ -152,7 +152,7 @@ func dataConfig_schema_v33Json() (*asset, error) { return a, nil } -var _dataConfig_schema_v34Json = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xec\x5b\x4f\x73\xe3\x28\x16\xbf\xfb\x53\xa8\x98\xb9\x8d\x93\x4c\xd5\x76\x6d\xd5\xf6\x6d\x8f\x7b\xda\x3d\x6f\xca\xa3\xc2\xe8\xd9\x66\x82\x80\x06\xe4\xc4\xdd\x95\xef\xbe\xa5\xbf\x06\x09\x04\xb6\x95\x4e\x7a\xa7\x4f\x89\xa5\xdf\x03\xde\xff\xf7\x00\x7d\x5b\x65\x19\xfa\x55\x93\x03\x94\x18\x7d\xce\xd0\xc1\x18\xf9\xf9\xe1\xe1\x4f\x2d\xf8\x5d\xfb\xf4\x5e\xa8\xfd\x43\xa1\xf0\xce\xdc\xfd\xfe\xe9\xa1\x7d\xf6\x0b\x5a\xd7\x74\xb4\xa8\x49\x88\xe0\x3b\xba\xcf\xdb\x37\xf9\xf1\x6f\xf7\x9f\xee\x6b\xf2\x16\x62\x4e\x12\x6a\x90\xd8\xfe\x09\xc4\xb4\xcf\x14\x7c\xa9\xa8\x82\x9a\xf8\x11\x1d\x41\x69\x2a\x38\xda\xac\x57\xf5\x3b\xa9\x84\x04\x65\x28\x68\xf4\x39\xab\x17\x97\x65\x03\xa4\x7f\x60\x0d\xab\x8d\xa2\x7c\x8f\x9a\xc7\xaf\xcd\x08\x59\x86\x34\xa8\x23\x25\xd6\x08\xc3\x52\x7f\x79\x38\x8f\xff\x30\xc0\xd6\xe3\x51\xad\xc5\x36\xcf\x25\x36\x06\x14\xff\xcf\x74\x6d\xcd\xeb\x3f\x1e\xf1\xdd\xd7\x7f\xde\xfd\xf7\xf7\xbb\x7f\xdc\xe7\x77\x9b\xdf\x7e\x75\x5e\xd7\xf2\x55\xb0\x6b\xa7\x2f\x60\x47\x39\x35\x54\xf0\x61\x7e\x34\x20\x5f\xbb\xff\x5e\x87\x89\x71\x51\x34\x60\xcc\x9c\xb9\x77\x98\x69\x70\x79\xe6\x60\x9e\x85\x7a\x8a\xf1\x3c\xc0\xde\x89\xe7\x6e\x7e\x0f\xcf\x2e\x3b\x47\xc1\xaa\x32\xaa\xc1\x1e\xf5\x4e\xcc\xb4\xd3\x2f\xa3\x3f\x0d\x44\x81\x89\x9b\x6c\x8b\x7a\x37\x8b\xad\xa7\x5f\x86\xe1\x36\x6a\xc4\x18\xee\x51\xef\xc4\x70\x3b\xfd\x6d\x0c\xaf\x7a\xa6\x67\xb1\x2d\xc2\x9a\xbb\x59\xa0\x13\xcf\x7c\xa2\xf2\xc5\x93\xb0\xac\x06\x61\x05\xa4\x54\x80\x64\xe2\x54\x3f\x0b\xc8\xa3\x05\x94\xc0\x0d\x1a\x44\x90\x65\x68\x5b\x51\x56\x8c\x25\x2a\x38\xfc\xbb\x1e\xe2\xd1\x7a\x98\x65\xdf\xc6\xa1\xdb\x1a\xa7\x79\xef\xfc\x0a\x2b\x7c\x78\x1f\xe0\x65\x78\x4f\x04\x37\xf0\x62\x1a\xa6\xe6\xa7\x6e\x45\x20\xc8\x13\xa8\x1d\x65\x90\x4a\x81\x55\x6b\xc5\x01\x91\x31\xaa\x4d\x2e\x54\x5e\x50\x62\xbc\xf4\x0c\x6f\x81\xdd\x34\x02\xc1\xe4\x00\xf9\x4e\x89\x32\x3a\xca\x2e\x6f\x39\xd1\xe8\x75\x34\xce\x64\xe0\xb8\x69\x0f\xa4\xd6\xaf\xcd\xca\x33\x20\x22\x58\xe6\xb8\x28\x1c\x91\x62\xa5\xf0\x09\xad\x33\x44\x0d\x94\xda\x2f\xed\x0c\x55\x9c\x7e\xa9\xe0\x5f\x1d\xc4\xa8\x0a\xc6\xe3\x16\x4a\xc8\xe5\x07\xde\x2b\x51\xc9\x5c\x62\x55\xdb\xfa\xbc\x25\x20\x22\xca\x12\xf3\xa5\x1c\xe0\x12\x3e\x12\x24\x3f\x09\xb3\x99\xed\x55\xdd\x1c\xf6\xab\x61\x36\x67\x59\x01\x6e\xe2\xfc\x4c\x5d\x3a\xee\xd4\x71\xb7\xae\xa3\xa2\xa8\x14\x49\xf5\xd2\x7a\x4e\xac\xf6\x90\x1a\x07\xb2\x0c\x55\xb4\x48\x07\xef\x2f\x01\x97\xa2\x70\xd7\xcd\xab\x72\x0b\x6a\xe2\x92\xae\x67\x4d\x7f\x6f\x56\xbe\x37\x23\xed\x1b\x4c\x39\xa8\x9c\xe3\x32\x26\x2b\x44\x14\x14\xc0\x0d\xc5\x2c\xd7\x12\x88\x03\xef\x35\x35\xa3\x19\x94\x14\x35\x91\x82\x3d\xd5\x46\x9d\xbc\xc8\x33\x17\xf6\xc2\x0a\x90\xc0\x0b\x9d\xb7\x3d\x40\x6a\x80\x73\x06\x18\x1a\x82\x45\xc3\x44\xc1\xe7\x02\x77\x3b\x4c\x1d\xba\xeb\xb5\xa1\x11\x61\xae\x01\x2b\x72\xb8\x92\x5e\x94\x98\xf2\x14\xa5\x02\x37\xea\x24\x05\x6d\xc3\xd8\x87\x8b\x4f\xc0\x8f\xf9\x60\x37\x17\x8b\x01\xf8\x91\x2a\xc1\xcb\x3e\x48\xa7\x25\x50\x8b\xfe\x45\x0a\x0d\xb7\x07\xc7\x8e\xe2\xb1\x67\x7c\x3d\xf8\xf4\xc6\x95\x1e\xda\x09\x55\xe2\x7a\xb1\xfd\xdc\xb6\x0f\x3b\x53\x4d\x2d\xcf\x16\xa0\xcd\x43\x5d\xf8\x62\x96\x33\xca\x9f\x96\x37\x71\x78\x31\x0a\xe7\x07\xa1\xcd\x35\x35\x0a\x3a\x00\x66\xe6\x40\x0e\x40\x9e\x66\xc8\x6d\x94\x43\x2d\xb4\x49\x31\x72\x5a\xe2\x7d\x1c\x24\x49\x0c\x72\x75\x2d\x86\x16\x15\xbe\x35\xac\xd8\xef\x6b\x68\xc8\xe2\x26\xb5\x7d\xf7\x3a\x56\x15\x17\x8a\x1e\x41\xa5\x96\xb8\x42\x9e\x5b\x92\xf1\xcb\x94\x6c\x1e\xed\xcf\x1c\xe8\x1f\xf7\x6d\x7b\x36\xe3\x55\xcd\x7f\x8c\xa1\xcd\x34\x65\x4e\x93\xe6\xf8\xc9\x88\xc3\xb4\x3a\xd7\xd1\x4a\x89\x49\x5d\xce\x2a\xd0\x01\xbd\x9e\xa1\xdd\x86\x47\x3e\xc9\xf9\x67\xec\x04\x3c\x49\xac\xa1\x48\x7d\x71\x22\xcc\xae\xea\xb0\x92\x54\x17\x6d\xb1\x23\xdc\x84\x96\x97\xba\xcc\xf3\x72\xe3\x26\xd6\xe0\x30\xa3\x58\x43\xdc\xd9\x83\x82\x74\x46\xa3\xf2\xf8\x29\xd1\x26\x7c\xb4\x7f\x9f\xa5\x0d\x90\x06\xc7\x4c\x6f\xdd\x22\x43\xd9\x25\x2a\x63\xde\x85\x6c\xe2\x45\xeb\x5b\x76\x96\xd2\x2d\xbc\xdd\x58\xd1\x44\x08\xdb\xc1\xa4\x50\xe6\xbb\xf4\x42\xe7\x38\x75\x4e\xf8\xed\xe4\xd3\xf6\x68\xac\xee\x24\xa2\xb7\xe9\xa9\x66\xa2\x94\x07\xed\xe9\xa8\x28\x37\xb0\xaf\x5b\x19\x7f\x12\xa8\xb6\x8c\xea\x03\x14\x97\xd0\x28\x61\x04\x11\x2c\xcd\x31\xbc\x1b\x34\xe9\xce\x30\xd3\x5f\x5d\x55\x9b\x49\x45\x8f\x94\xc1\x7e\xc4\xf1\x56\x08\x06\x98\x3b\x89\x42\x01\x2e\x72\xc1\xd9\x29\x01\xa9\x0d\x56\xd1\x5d\x09\x0d\xa4\x52\xd4\x9c\x72\x21\xcd\xe2\x55\xa1\x3e\x94\xb9\xa6\x5f\xc1\xf5\xbd\xb3\xd5\x77\x03\x6d\x46\x0b\x1a\x6d\x71\x67\x3f\xb7\x22\xfe\x32\x5b\x11\xfa\xa4\x89\xb9\xae\xb6\xd6\xa6\xa0\x3c\x17\x12\x78\xd4\x37\xb4\x11\x32\xdf\x2b\x4c\x20\x97\xa0\xa8\xf0\x8a\xc2\x09\xb0\x45\xa5\x70\x3d\xff\x74\x18\x4d\xf7\x1c\xfb\xe3\x8e\x05\x35\xa5\xdc\x5d\xb9\x09\x60\x4c\xdc\xd9\x2b\x46\x4b\x1a\x76\x1a\x8f\xd5\x26\xd4\x6b\x6d\xad\xe6\x2f\xd1\x66\xca\xb3\xa4\x90\x3d\xd3\x21\xcc\x37\x08\x09\x9d\xc1\x01\xab\x0b\x52\x47\xe3\x98\xbb\x40\x7e\xf2\xf5\x0d\xde\x75\x39\x87\xd5\xcd\x78\xeb\x6e\x21\x1b\x2f\xfe\xa2\xd2\x6b\xbc\x8c\x4d\xb0\xfa\xf1\x3b\x55\xa5\xa3\x4d\x5c\x83\xe1\x7a\xae\x01\x19\xa0\xd3\x53\xd7\xec\x87\x88\xd0\x8e\x8e\x1a\xb8\x47\x37\x09\x71\xbc\x9b\x29\x31\x76\xbe\x75\xd4\x4f\xae\x08\x2c\x1a\x22\xb8\xa6\xda\x00\x27\xfe\xfd\x55\x2f\xd1\x96\x4e\x0e\x2f\xa6\x42\x99\xef\xbb\xd2\xba\xae\x06\x85\xf7\x6d\xbc\x4d\x6e\x74\xd2\x7d\xb5\x3b\x90\xff\x2e\xac\x70\x41\x84\x0c\xa8\x26\x9d\x8d\x4b\xd3\xec\x68\xeb\x62\xa6\x0e\x0d\x85\x8c\x67\xa1\x9e\xea\x84\x54\x50\x7f\xe4\x58\x8d\x48\x2e\x38\xd2\x1f\xed\xf5\xf5\x03\xf8\xce\xaa\x6d\x68\xf4\x6c\x7f\xfe\xdc\xbc\x03\x05\xcf\xb4\xa9\xc6\xdb\xd1\xb9\x84\x2f\xd1\xd6\x99\x41\x1d\xe3\xf9\x5e\x81\x51\x74\x74\x94\xd0\x17\x4d\x76\x6e\x07\xfd\x31\x37\xdc\x0d\x2d\x41\x54\xfe\x30\xb4\xb2\x0d\xa7\x23\x42\xd6\x99\x7f\x44\xa9\x16\x72\xac\xd3\x47\xeb\x00\xa9\xed\xcb\xa3\x8a\x4b\x49\x58\xc0\x8b\xe6\x68\x23\x29\xbb\x29\x90\x8c\x12\xac\x63\x15\xc4\x0d\xbb\xc0\x95\x2c\xb0\x81\xbc\xbb\x36\x72\x49\xcd\x36\x53\xac\x49\xac\x30\x63\xc0\xa8\x2e\x53\x8a\x1f\x54\x00\xc3\xde\xe8\x1f\xad\x7b\x1b\xf2\x1d\xa6\xac\x52\x90\x63\x12\x0c\xd3\x23\x8a\x52\x70\x6a\x84\x37\x9c\xa4\x4d\x59\xe2\x97\xbc\x9f\xb6\x81\x44\xbc\xab\x21\x12\xaa\xf0\x17\x3f\xeb\xda\x2e\xaa\xd2\x53\x7e\xa0\xa6\x71\xbe\xdb\x51\xa5\x4d\xdb\xa5\x0a\xd9\xfd\x72\xc3\xec\x6b\xb0\xf3\x4f\xdd\x2c\xb6\xac\xae\xad\x13\x2e\x2b\xe1\x67\xcc\xe1\xdc\x10\x04\xac\xb3\x9f\x71\x22\x31\x05\xba\x0e\x71\xc3\x5e\x7e\x94\x3e\x9a\x4c\xba\xad\x88\x5c\x0a\x46\xdb\x8a\x63\x09\x0e\x89\xe0\xad\x90\x53\x8c\xef\x46\x6b\xaf\x4d\xaf\xee\x97\x4a\x69\xa2\x81\xa1\x21\x78\xa6\xbc\x10\xcf\x17\x4c\xb8\x9c\x29\x49\x86\x09\x8c\x02\xf1\xad\x82\xd6\x46\x61\xca\xcd\xc5\x47\x57\x63\xb1\x48\x05\x3b\x50\xc0\xa7\x86\x9e\xcd\xb7\x10\x59\xb8\x8d\x88\xf1\x16\xe7\xb0\x43\x68\x59\xd7\xd2\xef\xb0\x83\x78\xab\xf2\x6f\x28\xc6\x06\x2f\x8e\x24\xed\x01\x17\x2d\xc3\x42\x89\x9a\xc8\x2a\x7a\x0c\x56\x42\x29\xe6\xaf\x7c\xdc\x70\xe9\x39\xc6\x62\x0f\x5b\xa0\x28\x49\x3a\x37\xed\x50\xb9\x90\xcb\x6f\xdc\xc4\xcf\x46\x37\xf1\xb0\x4d\x25\x2e\x97\x8a\x21\xc9\x27\xc9\xc8\x5b\x15\x65\x1f\x20\x3a\x54\x5b\x1e\xe8\xcb\x3f\x76\x74\x70\x6f\x69\x34\x97\x40\x02\x5a\x7d\x1c\x5a\x9e\xf5\x20\xab\x4d\xb2\x8a\x83\x37\x30\x96\x5b\x7f\xd3\x7d\x8d\x77\x5b\x7d\x6d\x1a\x36\x06\x93\x43\x52\x47\x77\x61\x19\x7f\x43\x1c\x9a\xec\x3b\x78\xc3\x50\x87\x5a\x20\x0a\xa5\x5c\x89\xf9\xff\x88\x54\x3f\xba\x5d\x7f\x3f\x1b\xec\xbe\xcd\x88\x7e\x23\xd0\xa0\xae\xce\xf5\x09\x57\x3c\x3f\x80\xce\xde\x59\x15\x93\x44\xe7\x55\x45\x87\xfa\xa9\x8a\x37\xf5\x0a\xf7\xf4\xcd\x52\xc9\x74\x33\x6e\x4e\x92\x97\x7e\x55\xb1\x71\x97\x31\x86\x79\xbe\x64\x74\x6b\x9f\xb9\xb3\xf9\x1e\x12\xd8\xfc\x1d\x4d\xda\x09\x71\x9e\xf3\x05\xe3\xfe\xfd\x6f\x33\x15\xde\xdc\x55\xbe\x37\x2a\x8d\x16\xb8\xf7\xe0\xd7\xe9\xa8\x79\xee\xa5\x3b\xfd\x58\x2b\xec\xff\x3d\xfd\xe4\xd3\xad\x9a\x4f\x7e\x9a\x6c\x16\x7f\x73\x4f\xba\xda\xcf\xae\x36\x8e\x7c\x46\x90\xf6\x62\xac\x95\x68\x37\xf6\x7e\x42\xf0\x26\xbf\xef\x83\xae\xf1\x39\x5b\xff\x61\x55\xe0\xe8\x7f\x65\xff\x6d\x3e\x82\x5b\xbd\xae\xfe\x17\x00\x00\xff\xff\xf8\x93\x01\x77\x6e\x3c\x00\x00") +var _dataConfig_schema_v34Json = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xec\x5b\xcd\x72\xdb\x38\x12\xbe\xeb\x29\x58\x4c\x6e\x91\xed\x54\x6d\x6a\xab\x36\xb7\x3d\xee\x69\xe7\x3c\x2e\x85\x05\x81\x2d\x09\x31\x08\x20\x0d\x50\xb6\x92\xf2\xbb\x4f\xf1\x57\xfc\x01\x01\x50\xa2\x63\x67\x26\x27\x5b\xe4\xd7\x00\xba\x1b\xf8\xba\x1b\x00\x7f\xac\xa2\x28\x7e\xaf\xe9\x01\x32\x12\x7f\x8e\xe2\x83\x31\xea\xf3\xdd\xdd\x57\x2d\xc5\x4d\xf5\xf4\x56\xe2\xfe\x2e\x45\xb2\x33\x37\x1f\x3f\xdd\x55\xcf\xde\xc5\xeb\x42\x8e\xa5\x85\x08\x95\x62\xc7\xf6\x49\xf5\x26\x39\xfe\xeb\xf6\xd3\x6d\x21\x5e\x41\xcc\x49\x41\x01\x92\xdb\xaf\x40\x4d\xf5\x0c\xe1\x5b\xce\x10\x0a\xe1\xfb\xf8\x08\xa8\x99\x14\xf1\x66\xbd\x2a\xde\x29\x94\x0a\xd0\x30\xd0\xf1\xe7\xa8\x18\x5c\x14\xb5\x90\xe6\x41\xa7\x59\x6d\x90\x89\x7d\x5c\x3e\x7e\x2e\x5b\x88\xa2\x58\x03\x1e\x19\xed\xb4\xd0\x0e\xf5\xdd\xdd\xb9\xfd\xbb\x16\xb6\x1e\xb6\xda\x19\x6c\xf9\x5c\x11\x63\x00\xc5\x1f\xe3\xb1\x95\xaf\xbf\xdc\x93\x9b\xef\xff\xbd\xf9\xf3\xe3\xcd\x7f\x6e\x93\x9b\xcd\x87\xf7\xbd\xd7\x85\x7d\x11\x76\x55\xf7\x29\xec\x98\x60\x86\x49\xd1\xf6\x1f\xb7\xc8\xe7\xfa\xbf\xe7\xb6\x63\x92\xa6\x25\x98\xf0\x5e\xdf\x3b\xc2\x35\xf4\x75\x16\x60\x1e\x25\x3e\xf8\x74\x6e\x61\xaf\xa4\x73\xdd\xbf\x45\xe7\xbe\x3a\x47\xc9\xf3\xcc\xeb\xc1\x06\xf5\x4a\xca\x54\xdd\x2f\xe3\x3f\x0d\x14\xc1\xf8\xa7\x6c\x85\x7a\xb5\x19\x5b\x74\xbf\x8c\xc2\x15\x6b\xf8\x14\x6e\x50\xaf\xa4\x70\xd5\xfd\x75\x0a\xaf\x1a\xa5\x9d\xd8\x0a\xd1\xe9\xbb\x1c\x60\x8f\xcf\x6c\xa6\xb2\xf1\xc9\xb4\xad\x5a\x63\x4d\x58\x29\x05\xc5\xe5\xa9\x78\x36\x61\x8f\x0a\x90\x81\x30\x71\x6b\x82\x28\x8a\xb7\x39\xe3\xe9\xd0\xa2\x52\xc0\xff\x8b\x26\xee\x3b\x0f\xa3\xe8\xc7\x90\xba\x3b\xed\x94\xef\x7b\xbf\xa6\x1d\xde\xbe\x9f\xd0\xa5\x7d\x4f\xa5\x30\xf0\x64\x4a\xa5\xdc\x5d\x57\x26\x90\xf4\x01\x70\xc7\x38\x84\x4a\x10\xac\x66\xf1\x84\xc9\x38\xd3\x26\x91\x98\xa4\x8c\x1a\xab\x3c\x27\x5b\xe0\x57\xb5\x40\x09\x3d\x40\xb2\x43\x99\x79\x5b\xd9\x25\x95\x26\xda\xda\x50\xc3\xce\x81\x9a\x1b\x82\x7b\xb0\x5b\x76\x00\x1e\x49\xfb\xd7\x4d\x2b\xda\xf9\xb5\x59\x59\x1a\x8c\x29\x51\x09\x49\xd3\xde\x38\x08\x22\x39\xc5\xeb\x28\x66\x06\x32\x6d\x57\x28\x8a\x73\xc1\xbe\xe5\xf0\xbf\x1a\x62\x30\x87\x61\xbb\x29\x4a\xb5\x7c\xc3\x7b\x94\xb9\x4a\x14\xc1\x62\x21\xb9\x8d\x1d\x53\x99\x65\x44\x2c\xb5\xba\xe6\xe8\x11\x60\xf9\x11\x87\x47\xdd\x25\x5b\xf7\xd1\x7d\xd5\xf6\xd6\x1b\xd6\x84\x36\x7e\x7d\xc6\x7c\xe1\x67\x0c\x3f\x67\x14\x94\x2b\x73\xa4\xa1\x14\xe0\x5e\x0a\x56\x7c\xce\xd2\x70\xf0\x7e\x0e\x38\x93\x69\x7f\xdc\x22\xcf\xb6\x80\xa3\x25\xd9\x5f\x59\xe3\xdf\x9b\x95\xed\xcd\xc0\xfb\x86\x30\x01\x98\x08\x92\xf9\x6c\x15\x53\x84\x14\x84\x61\x84\x27\x5a\x01\xed\xc1\x1b\x4f\x39\x3c\x13\x07\x51\x72\x8c\xb0\x67\xda\xe0\xc9\x4d\x4a\xcf\xdd\x81\xa5\xa0\x40\xa4\x3a\xa9\x0a\x8c\xf9\xec\x19\xa7\xd0\x56\x1b\x8b\xd2\x44\x2a\x5c\x51\xa1\x6a\xa6\x88\x0b\xc5\xd8\xe2\x81\x60\xa2\x81\x20\x3d\x5c\x28\x2f\x33\xc2\x44\x88\x53\x41\x18\x3c\x29\xc9\x2a\x1a\x7b\x73\xfc\x04\xe2\x98\xb4\xf3\x66\xb6\x19\x40\x1c\x19\x4a\x91\x35\x24\x1d\x16\x9d\x3b\xf2\x4f\x4a\x6a\xb8\x9e\x1c\x6b\x89\xfb\x46\xf1\x75\xbb\xa6\x37\x7d\xeb\xc5\x3b\x89\x19\x29\x06\xdb\xf4\xdd\x5d\xc3\xbd\xae\xc6\x33\xaf\x6b\xc0\xae\x0e\x45\x56\x4d\x78\xc2\x99\x78\x58\x7e\x8a\xc3\x93\x41\x92\x1c\xa4\x36\x97\x24\x40\xf1\x01\x08\x37\x07\x7a\x00\xfa\xe0\x10\xef\xa2\x7a\xd2\x52\x9b\x90\x49\xce\x32\xb2\xf7\x83\x14\xf5\x41\x2e\x4e\xf4\xe2\x45\x8d\xdf\x69\x56\xee\xf7\x05\x74\x6a\xc6\x8d\x0a\x87\xfa\xb5\x2f\xe5\x4e\x91\x1d\x01\x43\xb3\x48\xa9\xce\xf5\xce\xf0\x65\x48\x34\xf7\x16\x7f\x3d\xe8\x97\xdb\xaa\xf6\x73\xac\xaa\xf2\x3f\xce\xe3\xcd\x38\x64\x8e\x83\xe6\xf0\xc9\x40\xc3\xb0\x3c\xb7\xe7\x95\x8c\xd0\x22\x9d\x45\xd0\x13\x7e\x3d\x43\xeb\x7c\x3d\x19\xc5\xfc\x33\x76\x04\x1e\x05\xd6\x29\xa6\xbe\xa8\x8c\x98\x5f\xbe\x05\xb9\xce\x5b\xbf\x7b\xb4\x99\x1a\x5e\xe8\x30\xcf\xc3\xf5\x4f\xb1\x12\x47\x38\x23\x1a\xfc\x8b\xdd\x59\x8f\xb5\xad\x31\x75\xfc\x14\x38\x27\x6c\xb2\xff\x76\xca\x4e\x88\x4e\xb6\x19\x5e\xba\x79\x9a\xea\xa6\xa8\x9c\x5b\x07\xb2\xf1\x27\xad\x2f\x59\x59\xaa\x7e\xe2\xdd\xe7\x8a\x92\x21\xba\x0b\x4c\x49\x34\x3f\xa5\x16\x3a\xf3\xd4\x39\xe0\x57\x9d\x8f\xcb\xa3\xa1\xbb\x83\x84\x5e\xa6\xa6\x72\xb0\x94\x05\x6d\xa9\xa8\x98\x30\xb0\x2f\x4a\x19\x7b\x10\xc8\xb7\x9c\xe9\x03\xa4\x73\x64\x50\x1a\x49\x25\x0f\x5b\x18\xd6\xdd\x9f\xf0\xc5\xe0\xa8\xaf\x2e\xca\xcd\x14\xb2\x23\xe3\xb0\x1f\x68\xbc\x95\x92\x03\x11\xbd\x40\x81\x40\xd2\x44\x0a\x7e\x0a\x40\x6a\x43\xd0\xbb\x2b\xa1\x81\xe6\xc8\xcc\x29\x91\xca\x2c\x9e\x15\xea\x43\x96\x68\xf6\x1d\xfa\x6b\xef\x3c\xeb\xeb\x86\x36\x83\x01\x0d\xf6\xcf\xa3\xdf\x5b\x11\xff\x98\xad\x08\x7d\xd2\xd4\x5c\x96\x5b\x6b\x93\x32\x91\x48\x05\xc2\xbb\x36\xb4\x91\x2a\xd9\x23\xa1\x90\x28\x40\x26\xad\xa6\xe8\x11\x6c\x9a\x23\x29\xfa\x1f\x37\xa3\xd9\x5e\x10\x3b\xef\x74\xa0\x26\x53\xbb\x0b\x37\x01\x8c\xf1\x2f\xf6\x9c\xb3\x8c\x4d\x2f\x1a\xcb\xac\x0d\xc8\xd7\xaa\x5c\xcd\x9e\xa2\x39\xd2\xb3\x20\xca\x76\x54\x08\xee\x02\x21\xa0\x32\x38\x10\x9c\x11\x3a\xca\x85\xb9\x9b\x88\x4f\xb6\xba\xc1\x3a\xae\xde\x49\x78\xd9\xde\xba\x1e\xc8\xc6\x8a\x9f\x95\x7a\x0d\x87\xb1\x99\xcc\x7e\xec\x8b\x2a\xd7\xde\x22\xae\xc4\x08\xed\x2a\x40\x5a\xe8\xf8\x48\x37\xfa\x25\x18\xba\xe7\xa3\x12\x6e\xf1\x4d\x00\x8f\xd7\x3d\x05\x72\xe7\x4b\xb3\x7e\x70\x46\xd0\x91\xa1\x52\x68\xa6\x0d\x08\x6a\xdf\x5f\xb5\x0a\x6d\xd9\xe8\xf0\x62\x6c\x14\x77\xdd\x15\x56\x75\x95\x28\xb2\xaf\xf8\x36\xb8\xd0\x09\x5f\xab\xf5\x69\xff\x4f\x51\x45\x48\x2a\xd5\x84\x6b\xc2\xd5\x98\x1b\x66\x07\x5b\x17\x8e\x3c\x74\x8a\x32\x1e\x25\x3e\x14\x01\x29\x65\x76\xe6\x58\x0d\x44\x66\xdc\x17\x18\xec\xf5\x35\x0d\xd8\x0e\xc2\xbb\x50\xef\xc5\x01\xf7\xa1\x7c\x0d\x9a\x3c\x30\x67\x9a\x6c\x07\xe7\x12\xb6\x40\x5b\x44\x06\x3c\xfa\xe3\x3d\x82\x41\x36\x38\x4a\x68\x92\xa6\x6e\x6c\x07\xfd\x36\x37\xdc\x0d\xcb\x40\xe6\xce\x23\xe1\xf6\xa2\x4f\x65\xc0\xf3\x85\x02\x8f\x53\x3b\xc8\xa1\x4f\xef\x3b\x07\x48\x55\x5d\xee\x75\x5c\x48\xc0\x02\x91\x96\x47\x1b\x41\xd1\x0d\x41\x71\x46\x89\xf6\x65\x10\x57\xec\x02\xe7\x2a\x25\x06\x92\xfa\x4e\xca\x9c\x9c\xcd\x91\xac\x29\x82\x84\x73\xe0\x4c\x67\x21\xc9\x4f\x9c\x02\x27\x56\xf6\xf7\xe6\xbd\xa5\xf8\x8e\x30\x9e\x23\x24\x84\x4e\xd2\xf4\x40\x22\x93\x82\x19\x69\xa5\x93\xb0\x2e\x33\xf2\x94\x34\xdd\x96\x10\xcf\xea\x2a\x85\x24\xa6\xf6\xe4\x67\x5d\xcc\x8b\x3c\xb3\xa4\x1f\x71\x59\x38\xdf\xec\x18\x6a\x53\x55\xa9\x52\xd5\xbf\xfa\x34\xfb\x3c\x59\xf9\x87\x6e\x16\x77\x66\x5d\x95\x27\xcc\x4b\xe1\x1d\xd3\xe1\x5c\x10\x4c\xcc\xce\xa6\xc7\x91\xc5\x10\x74\x41\x71\xed\x5e\xbe\x57\xde\x1b\x4c\xea\xad\x88\x44\x49\xce\xaa\x8c\x63\x09\x0d\xa9\x14\x95\x91\x43\x26\xdf\x95\xb3\xbd\x98\x7a\x45\xbd\x94\x29\xe3\x25\x86\x52\xe0\x91\x89\x54\x3e\xce\xe8\x70\xb9\xa9\xa4\x38\xa1\x30\x20\xe2\x6b\x0d\xad\x0d\x12\x26\xcc\xec\xa3\xab\xa1\x59\x14\xc2\x0e\x10\xc4\x78\xa2\x47\xee\x12\x22\x9a\x2e\x23\x7c\xba\xf9\x35\xac\x11\x5a\x15\xb9\xf4\x2b\xec\x20\x5e\xeb\xfc\x2b\x92\xb1\x76\x15\x7b\x82\x76\x8b\xf3\xa6\x61\x53\x81\x9a\xaa\xdc\x7b\x0c\x96\x41\x26\xdd\x57\x3e\xae\xb8\x51\xed\x53\xb1\x81\x2d\x90\x94\x04\x9d\x9b\xd6\xa8\x44\xaa\xe5\x37\x6e\xfc\x67\xa3\x1b\x3f\x6d\x33\x45\xb2\xa5\x38\x24\xf8\x24\x39\xb6\x66\x45\xd1\x1b\x60\x87\x7c\x2b\xc2\xee\x48\xbe\x31\x76\xe8\xdf\xd2\x28\x2f\x81\x4c\x78\xf5\xbe\x2d\x79\xd6\xad\xad\x36\xc1\x2e\x9e\xbc\x81\xb1\xdc\xf8\xcb\xea\x6b\xb8\xdb\x6a\x2b\xd3\x88\x31\x84\x1e\x82\x2a\xba\x99\x69\xfc\x15\x3c\x34\xda\x77\xb0\xd2\x50\x8d\x5a\x80\x85\x42\xae\xc4\xfc\x3d\x98\xea\x57\x9f\xd7\x3f\x6f\x0e\xd6\x1f\x7e\x78\x3f\x40\x28\x51\x17\xc7\xfa\x80\x2b\x9e\x6f\xc0\x67\xaf\xec\x8a\x51\xa0\xb3\xba\xa2\x46\xfd\x76\xc5\x8b\xae\x8a\xfe\xe9\x5b\xc7\x25\xe3\xcd\x38\x97\x25\x83\xaf\x08\xd5\x12\x9b\xfe\x30\x86\x30\xcb\x67\x92\xfd\xdc\xc7\x75\x36\xdf\x40\x26\x36\x7f\x07\x9d\xd6\x46\x74\x6b\xbe\x20\xef\xdf\x7e\x70\x64\x78\xae\xab\x7c\x2f\x94\x1a\x2d\x70\xef\xc1\xee\xd3\x41\xf1\xdc\x58\x77\xfc\x25\xd8\xf4\xfa\x6f\xe4\x47\xdf\x85\x15\x7a\x8a\xd3\x68\xb3\xf8\x47\xff\xa4\xab\xfa\xa6\x6b\xd3\xb3\xcf\x00\x52\x5d\x8c\xed\x04\xda\x4d\x77\x3f\x61\xf2\x26\xbf\xed\x6b\xb1\xe1\x39\x5b\xf3\xd5\xd6\xc4\xd1\xff\xaa\xfb\xb7\xfc\xc2\x6e\xf5\xbc\xfa\x2b\x00\x00\xff\xff\x54\x48\x04\xd1\xcb\x3c\x00\x00") func dataConfig_schema_v34JsonBytes() ([]byte, error) { return bindataRead( diff --git a/components/cli/cli/compose/schema/data/config_schema_v3.4.json b/components/cli/cli/compose/schema/data/config_schema_v3.4.json index ce9512076b..7edf9d6a55 100644 --- a/components/cli/cli/compose/schema/data/config_schema_v3.4.json +++ b/components/cli/cli/compose/schema/data/config_schema_v3.4.json @@ -84,7 +84,9 @@ "dockerfile": {"type": "string"}, "args": {"$ref": "#/definitions/list_or_dict"}, "labels": {"$ref": "#/definitions/list_or_dict"}, - "cache_from": {"$ref": "#/definitions/list_of_strings"} + "cache_from": {"$ref": "#/definitions/list_of_strings"}, + "network": {"type": "string"}, + "target": {"type": "string"} }, "additionalProperties": false } From e3f190dc00fd990862bee2325b57f8c8dad191e7 Mon Sep 17 00:00:00 2001 From: Daniel Nephin Date: Tue, 15 Aug 2017 13:17:20 -0400 Subject: [PATCH 05/47] Ignore codecov upload failures in CI. Signed-off-by: Daniel Nephin Upstream-commit: 6a7dc459dd9f86910c2a0d65db1c421123337be0 Component: cli --- components/cli/circle.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/components/cli/circle.yml b/components/cli/circle.yml index 2a9c196750..ecf597fa36 100644 --- a/components/cli/circle.yml +++ b/components/cli/circle.yml @@ -71,7 +71,8 @@ jobs: test-$CIRCLE_BUILD_NUM:/go/src/github.com/docker/cli/coverage.txt \ coverage.txt apk add -U bash curl - curl -s https://codecov.io/bash | bash + curl -s https://codecov.io/bash | bash || \ + echo 'Codecov failed to upload' validate: working_directory: /work From 750260f43f87b6375c48911245acf05bd1ec8383 Mon Sep 17 00:00:00 2001 From: Daniel Nephin Date: Tue, 15 Aug 2017 13:17:20 -0400 Subject: [PATCH 06/47] Ignore codecov upload failures in CI. Signed-off-by: Daniel Nephin Upstream-commit: 4e09dba0689136798103908737fa6c39b433021f Component: cli --- components/cli/circle.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/components/cli/circle.yml b/components/cli/circle.yml index 2a9c196750..ecf597fa36 100644 --- a/components/cli/circle.yml +++ b/components/cli/circle.yml @@ -71,7 +71,8 @@ jobs: test-$CIRCLE_BUILD_NUM:/go/src/github.com/docker/cli/coverage.txt \ coverage.txt apk add -U bash curl - curl -s https://codecov.io/bash | bash + curl -s https://codecov.io/bash | bash || \ + echo 'Codecov failed to upload' validate: working_directory: /work From b4e14f104b06de57d6dad112bc5b5b6fdc569510 Mon Sep 17 00:00:00 2001 From: Daniel Nephin Date: Tue, 15 Aug 2017 14:32:44 -0400 Subject: [PATCH 07/47] Set DISABLE_WARN_OUTSIDE_CONTAINER in the Dockerfile so that we don't spend 10s sleeping in CI also add time to validate check Signed-off-by: Daniel Nephin Upstream-commit: 058733969c4216b9be8338a4a57e90d080751520 Component: cli --- components/cli/Makefile | 7 +++++++ components/cli/circle.yml | 4 ++-- components/cli/docker.Makefile | 2 +- components/cli/dockerfiles/Dockerfile.cross | 1 + components/cli/dockerfiles/Dockerfile.dev | 3 ++- components/cli/dockerfiles/Dockerfile.lint | 1 + components/cli/dockerfiles/Dockerfile.shellcheck | 12 ++++++------ 7 files changed, 20 insertions(+), 10 deletions(-) diff --git a/components/cli/Makefile b/components/cli/Makefile index 81b0041b84..ccf36b4665 100644 --- a/components/cli/Makefile +++ b/components/cli/Makefile @@ -65,3 +65,10 @@ cli/compose/schema/bindata.go: cli/compose/schema/data/*.json compose-jsonschema: cli/compose/schema/bindata.go scripts/validate/check-git-diff cli/compose/schema/bindata.go + +.PHONY: ci-validate +ci-validate: + time make -B vendor + time make -B compose-jsonschema + time make manpages + time make yamldocs diff --git a/components/cli/circle.yml b/components/cli/circle.yml index ecf597fa36..53fcac7389 100644 --- a/components/cli/circle.yml +++ b/components/cli/circle.yml @@ -90,7 +90,7 @@ jobs: rm -f .dockerignore # include .git docker build -f $dockerfile --tag cli-builder-with-git:$CIRCLE_BUILD_NUM . docker run --rm cli-builder-with-git:$CIRCLE_BUILD_NUM \ - make -B vendor compose-jsonschema manpages yamldocs + make ci-validate shellcheck: working_directory: /work docker: [{image: 'docker:17.06-git'}] @@ -104,7 +104,7 @@ jobs: echo "COPY . ." >> $dockerfile docker build -f $dockerfile --tag cli-validator:$CIRCLE_BUILD_NUM . docker run --rm cli-validator:$CIRCLE_BUILD_NUM \ - make -B shellcheck + make shellcheck workflows: version: 2 ci: diff --git a/components/cli/docker.Makefile b/components/cli/docker.Makefile index 4aaee5489a..b7a34da314 100644 --- a/components/cli/docker.Makefile +++ b/components/cli/docker.Makefile @@ -10,7 +10,7 @@ CROSS_IMAGE_NAME = docker-cli-cross VALIDATE_IMAGE_NAME = docker-cli-shell-validate MOUNTS = -v "$(CURDIR)":/go/src/github.com/docker/cli VERSION = $(shell cat VERSION) -ENVVARS = -e VERSION=$(VERSION) -e GITCOMMIT -e DISABLE_WARN_OUTSIDE_CONTAINER=1 +ENVVARS = -e VERSION=$(VERSION) -e GITCOMMIT # build docker image (dockerfiles/Dockerfile.build) .PHONY: build_docker_image diff --git a/components/cli/dockerfiles/Dockerfile.cross b/components/cli/dockerfiles/Dockerfile.cross index 60487dca90..d4b900cab1 100644 --- a/components/cli/dockerfiles/Dockerfile.cross +++ b/components/cli/dockerfiles/Dockerfile.cross @@ -1,2 +1,3 @@ FROM dockercore/golang-cross@sha256:d24e7affa3a85d460d2303c2549f03fc866f2b97d771ccf07b0e6e2b411dd207 +ENV DISABLE_WARN_OUTSIDE_CONTAINER=1 WORKDIR /go/src/github.com/docker/cli diff --git a/components/cli/dockerfiles/Dockerfile.dev b/components/cli/dockerfiles/Dockerfile.dev index 5b9d35f516..dc67eeb07f 100644 --- a/components/cli/dockerfiles/Dockerfile.dev +++ b/components/cli/dockerfiles/Dockerfile.dev @@ -25,6 +25,7 @@ RUN go get -d github.com/dnephin/filewatcher && \ rm -rf /go/src/* /go/pkg/* /go/bin/* ENV CGO_ENABLED=0 \ - PATH=$PATH:/go/src/github.com/docker/cli/build + PATH=$PATH:/go/src/github.com/docker/cli/build \ + DISABLE_WARN_OUTSIDE_CONTAINER=1 WORKDIR /go/src/github.com/docker/cli CMD sh diff --git a/components/cli/dockerfiles/Dockerfile.lint b/components/cli/dockerfiles/Dockerfile.lint index c981efbadc..4b3cccf085 100644 --- a/components/cli/dockerfiles/Dockerfile.lint +++ b/components/cli/dockerfiles/Dockerfile.lint @@ -12,5 +12,6 @@ RUN go get -d github.com/alecthomas/gometalinter && \ WORKDIR /go/src/github.com/docker/cli ENV CGO_ENABLED=0 +ENV DISABLE_WARN_OUTSIDE_CONTAINER=1 ENTRYPOINT ["/usr/local/bin/gometalinter"] CMD ["--config=gometalinter.json", "./..."] diff --git a/components/cli/dockerfiles/Dockerfile.shellcheck b/components/cli/dockerfiles/Dockerfile.shellcheck index 12f665f7a7..43112b314d 100644 --- a/components/cli/dockerfiles/Dockerfile.shellcheck +++ b/components/cli/dockerfiles/Dockerfile.shellcheck @@ -1,9 +1,9 @@ -FROM debian:stretch-slim +FROM debian:stretch-slim -RUN apt-get update && \ - apt-get -y install make shellcheck && \ - apt-get clean +RUN apt-get update && \ + apt-get -y install make shellcheck && \ + apt-get clean WORKDIR /go/src/github.com/docker/cli - -CMD bash +ENV DISABLE_WARN_OUTSIDE_CONTAINER=1 +CMD bash From 53ea16fce88fdf979784d60b0a59e40e1f4cd324 Mon Sep 17 00:00:00 2001 From: Daniel Nephin Date: Mon, 14 Aug 2017 14:28:08 -0400 Subject: [PATCH 08/47] Add gotestyourself dependency. Signed-off-by: Daniel Nephin Upstream-commit: 85f7ed8cfabbc2e737b7176346e65d8d5f02fa0c Component: cli --- components/cli/vendor.conf | 1 + .../gotestyourself/gotestyourself/LICENSE | 202 +++++++++++++ .../gotestyourself/gotestyourself/README.md | 32 ++ .../gotestyourself/golden/golden.go | 71 +++++ .../gotestyourself/icmd/command.go | 277 ++++++++++++++++++ .../gotestyourself/icmd/exitcode.go | 32 ++ 6 files changed, 615 insertions(+) create mode 100644 components/cli/vendor/github.com/gotestyourself/gotestyourself/LICENSE create mode 100644 components/cli/vendor/github.com/gotestyourself/gotestyourself/README.md create mode 100644 components/cli/vendor/github.com/gotestyourself/gotestyourself/golden/golden.go create mode 100644 components/cli/vendor/github.com/gotestyourself/gotestyourself/icmd/command.go create mode 100644 components/cli/vendor/github.com/gotestyourself/gotestyourself/icmd/exitcode.go diff --git a/components/cli/vendor.conf b/components/cli/vendor.conf index 1e9e72ff43..d27abce96a 100755 --- a/components/cli/vendor.conf +++ b/components/cli/vendor.conf @@ -22,6 +22,7 @@ github.com/docker/swarmkit 79381d0840be27f8b3f5c667b348a4467d866eeb github.com/flynn-archive/go-shlex 3f9db97f856818214da2e1057f8ad84803971cff github.com/gogo/protobuf 7efa791bd276fd4db00867cbd982b552627c24cb 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/inconshreveable/mousetrap 76626ae9c91c4f2a10f34cad8ce83ea42c93bb75 diff --git a/components/cli/vendor/github.com/gotestyourself/gotestyourself/LICENSE b/components/cli/vendor/github.com/gotestyourself/gotestyourself/LICENSE new file mode 100644 index 0000000000..d645695673 --- /dev/null +++ b/components/cli/vendor/github.com/gotestyourself/gotestyourself/LICENSE @@ -0,0 +1,202 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/components/cli/vendor/github.com/gotestyourself/gotestyourself/README.md b/components/cli/vendor/github.com/gotestyourself/gotestyourself/README.md new file mode 100644 index 0000000000..2648074900 --- /dev/null +++ b/components/cli/vendor/github.com/gotestyourself/gotestyourself/README.md @@ -0,0 +1,32 @@ +# Go Test Yourself + +A collection of packages compatible with `go test` to support common testing +patterns. + +[![GoDoc](https://godoc.org/github.com/gotestyourself/gotestyourself?status.svg)](https://godoc.org/github.com/gotestyourself/gotestyourself) +[![CircleCI](https://circleci.com/gh/gotestyourself/gotestyourself/tree/master.svg?style=shield)](https://circleci.com/gh/gotestyourself/gotestyourself/tree/master) +[![Go Reportcard](https://goreportcard.com/badge/github.com/gotestyourself/gotestyourself)](https://goreportcard.com/report/github.com/gotestyourself/gotestyourself) + + +## Packages + +* [fs](http://godoc.org/github.com/gotestyourself/gotestyourself/fs) - + create test files and directories +* [golden](http://godoc.org/github.com/gotestyourself/gotestyourself/golden) - + compare large multi-line strings +* [testsum](http://godoc.org/github.com/gotestyourself/gotestyourself/testsum) - + a program to summarize `go test` output and test failures +* [icmd](http://godoc.org/github.com/gotestyourself/gotestyourself/icmd) - + execute binaries and test the output +* [skip](http://godoc.org/github.com/gotestyourself/gotestyourself/skip) - + skip tests based on conditions + + +## Related + +* [testify/assert](https://godoc.org/github.com/stretchr/testify/assert) and + [testify/require](https://godoc.org/github.com/stretchr/testify/require) - + assertion libraries with common assertions +* [golang/mock](https://github.com/golang/mock) - generate mocks for interfaces +* [testify/suite](https://godoc.org/github.com/stretchr/testify/suite) - + group test into suites to share common setup/teardown logic diff --git a/components/cli/vendor/github.com/gotestyourself/gotestyourself/golden/golden.go b/components/cli/vendor/github.com/gotestyourself/gotestyourself/golden/golden.go new file mode 100644 index 0000000000..230ff685cd --- /dev/null +++ b/components/cli/vendor/github.com/gotestyourself/gotestyourself/golden/golden.go @@ -0,0 +1,71 @@ +/*Package golden provides tools for comparing large mutli-line strings. + +Golden files are files in the ./testdata/ subdirectory of the package under test. +*/ +package golden + +import ( + "flag" + "fmt" + "io/ioutil" + "path/filepath" + + "github.com/pmezard/go-difflib/difflib" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +var flagUpdate = flag.Bool("test.update-golden", false, "update golden file") + +// Get returns the golden file content +func Get(t require.TestingT, filename string) []byte { + expected, err := ioutil.ReadFile(Path(filename)) + require.NoError(t, err) + return expected +} + +// Path returns the full path to a golden file +func Path(filename string) string { + return filepath.Join("testdata", filename) +} + +func update(t require.TestingT, filename string, actual []byte) { + if *flagUpdate { + err := ioutil.WriteFile(Path(filename), actual, 0644) + require.NoError(t, err) + } +} + +// Assert compares the actual content to the expected content in the golden file. +// If `--update-golden` is set then the actual content is written to the golden +// file. +// Returns whether the assertion was successful (true) or not (false) +func Assert(t require.TestingT, actual string, filename string, msgAndArgs ...interface{}) bool { + expected := Get(t, filename) + update(t, filename, []byte(actual)) + + if assert.ObjectsAreEqual(expected, []byte(actual)) { + return true + } + + diff, err := difflib.GetUnifiedDiffString(difflib.UnifiedDiff{ + A: difflib.SplitLines(string(expected)), + B: difflib.SplitLines(actual), + FromFile: "Expected", + ToFile: "Actual", + Context: 3, + }) + require.NoError(t, err, msgAndArgs...) + return assert.Fail(t, fmt.Sprintf("Not Equal: \n%s", diff), msgAndArgs...) +} + +// AssertBytes compares the actual result to the expected result in the golden +// file. If `--update-golden` is set then the actual content is written to the +// golden file. +// Returns whether the assertion was successful (true) or not (false) +// nolint: lll +func AssertBytes(t require.TestingT, actual []byte, filename string, msgAndArgs ...interface{}) bool { + expected := Get(t, filename) + update(t, filename, actual) + return assert.Equal(t, expected, actual, msgAndArgs...) +} diff --git a/components/cli/vendor/github.com/gotestyourself/gotestyourself/icmd/command.go b/components/cli/vendor/github.com/gotestyourself/gotestyourself/icmd/command.go new file mode 100644 index 0000000000..2470fdc662 --- /dev/null +++ b/components/cli/vendor/github.com/gotestyourself/gotestyourself/icmd/command.go @@ -0,0 +1,277 @@ +/*Package icmd executes binaries and provides convenient assertions for testing the results. + */ +package icmd + +import ( + "bytes" + "fmt" + "io" + "os/exec" + "path/filepath" + "runtime" + "strings" + "sync" + "time" +) + +type testingT interface { + Fatalf(string, ...interface{}) +} + +const ( + // None is a token to inform Result.Assert that the output should be empty + None string = "" +) + +type lockedBuffer struct { + m sync.RWMutex + buf bytes.Buffer +} + +func (buf *lockedBuffer) Write(b []byte) (int, error) { + buf.m.Lock() + defer buf.m.Unlock() + return buf.buf.Write(b) +} + +func (buf *lockedBuffer) String() string { + buf.m.RLock() + defer buf.m.RUnlock() + return buf.buf.String() +} + +// Result stores the result of running a command +type Result struct { + Cmd *exec.Cmd + ExitCode int + Error error + // Timeout is true if the command was killed because it ran for too long + Timeout bool + outBuffer *lockedBuffer + errBuffer *lockedBuffer +} + +// Assert compares the Result against the Expected struct, and fails the test if +// any of the expectations are not met. +func (r *Result) Assert(t testingT, exp Expected) *Result { + err := r.Compare(exp) + if err == nil { + return r + } + _, file, line, ok := runtime.Caller(1) + if ok { + t.Fatalf("at %s:%d - %s\n", filepath.Base(file), line, err.Error()) + } else { + t.Fatalf("(no file/line info) - %s", err.Error()) + } + return nil +} + +// Compare returns a formatted error with the command, stdout, stderr, exit +// code, and any failed expectations +// nolint: gocyclo +func (r *Result) Compare(exp Expected) error { + errors := []string{} + add := func(format string, args ...interface{}) { + errors = append(errors, fmt.Sprintf(format, args...)) + } + + if exp.ExitCode != r.ExitCode { + add("ExitCode was %d expected %d", r.ExitCode, exp.ExitCode) + } + if exp.Timeout != r.Timeout { + if exp.Timeout { + add("Expected command to timeout") + } else { + add("Expected command to finish, but it hit the timeout") + } + } + if !matchOutput(exp.Out, r.Stdout()) { + add("Expected stdout to contain %q", exp.Out) + } + if !matchOutput(exp.Err, r.Stderr()) { + add("Expected stderr to contain %q", exp.Err) + } + switch { + // If a non-zero exit code is expected there is going to be an error. + // Don't require an error message as well as an exit code because the + // error message is going to be "exit status which is not useful + case exp.Error == "" && exp.ExitCode != 0: + case exp.Error == "" && r.Error != nil: + add("Expected no error") + case exp.Error != "" && r.Error == nil: + add("Expected error to contain %q, but there was no error", exp.Error) + case exp.Error != "" && !strings.Contains(r.Error.Error(), exp.Error): + add("Expected error to contain %q", exp.Error) + } + + if len(errors) == 0 { + return nil + } + return fmt.Errorf("%s\nFailures:\n%s", r, strings.Join(errors, "\n")) +} + +func matchOutput(expected string, actual string) bool { + switch expected { + case None: + return actual == "" + default: + return strings.Contains(actual, expected) + } +} + +func (r *Result) String() string { + var timeout string + if r.Timeout { + timeout = " (timeout)" + } + + return fmt.Sprintf(` +Command: %s +ExitCode: %d%s +Error: %v +Stdout: %v +Stderr: %v +`, + strings.Join(r.Cmd.Args, " "), + r.ExitCode, + timeout, + r.Error, + r.Stdout(), + r.Stderr()) +} + +// Expected is the expected output from a Command. This struct is compared to a +// Result struct by Result.Assert(). +type Expected struct { + ExitCode int + Timeout bool + Error string + Out string + Err string +} + +// Success is the default expected result. A Success result is one with a 0 +// ExitCode. +var Success = Expected{} + +// Stdout returns the stdout of the process as a string +func (r *Result) Stdout() string { + return r.outBuffer.String() +} + +// Stderr returns the stderr of the process as a string +func (r *Result) Stderr() string { + return r.errBuffer.String() +} + +// Combined returns the stdout and stderr combined into a single string +func (r *Result) Combined() string { + return r.outBuffer.String() + r.errBuffer.String() +} + +// SetExitError sets Error and ExitCode based on Error +func (r *Result) SetExitError(err error) { + if err == nil { + return + } + r.Error = err + r.ExitCode = processExitCode(err) +} + +// Cmd contains the arguments and options for a process to run as part of a test +// suite. +type Cmd struct { + Command []string + Timeout time.Duration + Stdin io.Reader + Stdout io.Writer + Dir string + Env []string +} + +// Command create a simple Cmd with the specified command and arguments +func Command(command string, args ...string) Cmd { + return Cmd{Command: append([]string{command}, args...)} +} + +// RunCmd runs a command and returns a Result +func RunCmd(cmd Cmd, cmdOperators ...func(*Cmd)) *Result { + for _, op := range cmdOperators { + op(&cmd) + } + result := StartCmd(cmd) + if result.Error != nil { + return result + } + return WaitOnCmd(cmd.Timeout, result) +} + +// RunCommand parses a command line and runs it, returning a result +func RunCommand(command string, args ...string) *Result { + return RunCmd(Command(command, args...)) +} + +// StartCmd starts a command, but doesn't wait for it to finish +func StartCmd(cmd Cmd) *Result { + result := buildCmd(cmd) + if result.Error != nil { + return result + } + result.SetExitError(result.Cmd.Start()) + return result +} + +func buildCmd(cmd Cmd) *Result { + var execCmd *exec.Cmd + switch len(cmd.Command) { + case 1: + execCmd = exec.Command(cmd.Command[0]) + default: + execCmd = exec.Command(cmd.Command[0], cmd.Command[1:]...) + } + outBuffer := new(lockedBuffer) + errBuffer := new(lockedBuffer) + + execCmd.Stdin = cmd.Stdin + execCmd.Dir = cmd.Dir + execCmd.Env = cmd.Env + if cmd.Stdout != nil { + execCmd.Stdout = io.MultiWriter(outBuffer, cmd.Stdout) + } else { + execCmd.Stdout = outBuffer + } + execCmd.Stderr = errBuffer + return &Result{ + Cmd: execCmd, + outBuffer: outBuffer, + errBuffer: errBuffer, + } +} + +// WaitOnCmd waits for a command to complete. If timeout is non-nil then +// only wait until the timeout. +func WaitOnCmd(timeout time.Duration, result *Result) *Result { + if timeout == time.Duration(0) { + result.SetExitError(result.Cmd.Wait()) + return result + } + + done := make(chan error, 1) + // Wait for command to exit in a goroutine + go func() { + done <- result.Cmd.Wait() + }() + + select { + case <-time.After(timeout): + killErr := result.Cmd.Process.Kill() + if killErr != nil { + fmt.Printf("failed to kill (pid=%d): %v\n", result.Cmd.Process.Pid, killErr) + } + result.Timeout = true + case err := <-done: + result.SetExitError(err) + } + return result +} diff --git a/components/cli/vendor/github.com/gotestyourself/gotestyourself/icmd/exitcode.go b/components/cli/vendor/github.com/gotestyourself/gotestyourself/icmd/exitcode.go new file mode 100644 index 0000000000..32272b4bbb --- /dev/null +++ b/components/cli/vendor/github.com/gotestyourself/gotestyourself/icmd/exitcode.go @@ -0,0 +1,32 @@ +package icmd + +import ( + "os/exec" + "syscall" + + "github.com/pkg/errors" +) + +// GetExitCode returns the ExitStatus of a process from the error returned by +// exec.Run(). If the exit status could not be parsed an error is returned. +func GetExitCode(err error) (int, error) { + if exiterr, ok := err.(*exec.ExitError); ok { + if procExit, ok := exiterr.Sys().(syscall.WaitStatus); ok { + return procExit.ExitStatus(), nil + } + } + return 0, errors.Wrap(err, "failed to get exit code") +} + +func processExitCode(err error) (exitCode int) { + if err == nil { + return 0 + } + exitCode, exiterr := GetExitCode(err) + if exiterr != nil { + // TODO: Fix this so we check the error's text. + // we've failed to retrieve exit code, so we set it to 127 + return 127 + } + return exitCode +} From 581aa22bc8fa704c4079607a2aa5aeb08703499a Mon Sep 17 00:00:00 2001 From: Daniel Nephin Date: Mon, 14 Aug 2017 15:47:06 -0400 Subject: [PATCH 09/47] Add scripts for setting up e2e test environment. Signed-off-by: Daniel Nephin Upstream-commit: 26418a12fb80375ec10d8d7564d857560eb33994 Component: cli --- components/cli/Makefile | 8 +- components/cli/docker.Makefile | 10 ++- .../cli/dockerfiles/Dockerfile.test-e2e-env | 15 ++++ components/cli/e2e/compose-env.yaml | 10 +++ components/cli/scripts/test/e2e/load-alpine | 8 ++ components/cli/scripts/test/e2e/run | 85 +++++++++++++++++++ .../cli/scripts/test/e2e/wait-on-daemon | 9 ++ components/cli/scripts/test/e2e/wrapper | 33 +++++++ components/cli/scripts/test/watch | 2 +- 9 files changed, 172 insertions(+), 8 deletions(-) create mode 100644 components/cli/dockerfiles/Dockerfile.test-e2e-env create mode 100644 components/cli/e2e/compose-env.yaml create mode 100755 components/cli/scripts/test/e2e/load-alpine create mode 100755 components/cli/scripts/test/e2e/run create mode 100755 components/cli/scripts/test/e2e/wait-on-daemon create mode 100755 components/cli/scripts/test/e2e/wrapper diff --git a/components/cli/Makefile b/components/cli/Makefile index ccf36b4665..17ba8e5b2d 100644 --- a/components/cli/Makefile +++ b/components/cli/Makefile @@ -10,13 +10,13 @@ _:=$(shell ./scripts/warn-outside-container $(MAKECMDGOALS)) clean: ## remove build artifacts rm -rf ./build/* cli/winresources/rsrc_* ./man/man[1-9] docs/yaml/gen -.PHONY: test -test: ## run go test - ./scripts/test/unit $(shell go list ./... | grep -v '/vendor/') +.PHONY: test-unit +test-unit: ## run unit test + ./scripts/test/unit $(shell go list ./... | grep -vE '/vendor/|/e2e/') .PHONY: test-coverage test-coverage: ## run test coverage - ./scripts/test/unit-with-coverage $(shell go list ./... | grep -v '/vendor/') + ./scripts/test/unit-with-coverage $(shell go list ./... | grep -vE '/vendor/|/e2e/') .PHONY: lint lint: ## run all the lint tools diff --git a/components/cli/docker.Makefile b/components/cli/docker.Makefile index b7a34da314..2054c89209 100644 --- a/components/cli/docker.Makefile +++ b/components/cli/docker.Makefile @@ -42,9 +42,9 @@ clean: build_docker_image docker run --rm $(ENVVARS) $(MOUNTS) $(DEV_DOCKER_IMAGE_NAME) make clean # run go test -.PHONY: test -test: build_docker_image - docker run --rm $(ENVVARS) $(MOUNTS) $(DEV_DOCKER_IMAGE_NAME) make test +.PHONY: test-unit +test-unit: build_docker_image + docker run --rm $(ENVVARS) $(MOUNTS) $(DEV_DOCKER_IMAGE_NAME) make test-unit # build the CLI for multiple architectures using a container .PHONY: cross @@ -90,3 +90,7 @@ yamldocs: build_docker_image .PHONY: shellcheck shellcheck: build_shell_validate_image docker run -ti --rm $(ENVVARS) $(MOUNTS) $(VALIDATE_IMAGE_NAME) make shellcheck + +.PHONY: test-e2e: +test-e2e: binary + ./scripts/test/e2e/wrapper diff --git a/components/cli/dockerfiles/Dockerfile.test-e2e-env b/components/cli/dockerfiles/Dockerfile.test-e2e-env new file mode 100644 index 0000000000..c16b914bdb --- /dev/null +++ b/components/cli/dockerfiles/Dockerfile.test-e2e-env @@ -0,0 +1,15 @@ +FROM docker/compose:1.15.0 + +RUN apk add -U bash curl + +RUN curl -Ls https://download.docker.com/linux/static/edge/x86_64/docker-17.06.0-ce.tgz | \ + tar -xz docker/docker && \ + mv docker/docker /usr/local/bin/ && \ + rmdir docker +ENV DISABLE_WARN_OUTSIDE_CONTAINER=1 +WORKDIR /work +COPY scripts/test/e2e scripts/test/e2e +COPY e2e/compose-env.yaml e2e/compose-env.yaml + +ENTRYPOINT ["bash", "/work/scripts/test/e2e/run"] +CMD [] diff --git a/components/cli/e2e/compose-env.yaml b/components/cli/e2e/compose-env.yaml new file mode 100644 index 0000000000..f16a23c608 --- /dev/null +++ b/components/cli/e2e/compose-env.yaml @@ -0,0 +1,10 @@ +version: '3.3' + +services: + registry: + image: 'registry:2' + + engine: + image: 'docker:${TEST_ENGINE_VERSION:-edge-dind}' + privileged: true + command: ['--insecure-registry=registry:5000'] diff --git a/components/cli/scripts/test/e2e/load-alpine b/components/cli/scripts/test/e2e/load-alpine new file mode 100755 index 0000000000..5b75f0989c --- /dev/null +++ b/components/cli/scripts/test/e2e/load-alpine @@ -0,0 +1,8 @@ +#!/usr/bin/env bash +set -eu -o pipefail + +src=alpine:3.6 +dest=registry:5000/alpine:3.6 +docker pull $src +docker tag $src $dest +docker push $dest diff --git a/components/cli/scripts/test/e2e/run b/components/cli/scripts/test/e2e/run new file mode 100755 index 0000000000..936b5898fd --- /dev/null +++ b/components/cli/scripts/test/e2e/run @@ -0,0 +1,85 @@ +#!/usr/bin/env bash +# Run integration tests against the latest docker-ce dind +set -eu -o pipefail + +function container_ip { + local cid=$1 + local network=$2 + docker inspect \ + -f "{{.NetworkSettings.Networks.${network}.IPAddress}}" "$cid" +} + +function setup { + local project=$1 + COMPOSE_PROJECT_NAME=$1 COMPOSE_FILE=$2 docker-compose up -d >&2 + + local network="${project}_default" + # TODO: only run if inside a container + docker network connect "$network" "$(hostname)" + + engine_ip="$(container_ip "${project}_engine_1" "$network")" + engine_host="tcp://$engine_ip:2375" + ( + export DOCKER_HOST="$engine_host" + timeout -t 200 ./scripts/test/e2e/wait-on-daemon + ./scripts/test/e2e/load-alpine + is_swarm_enabled || docker swarm init + ) >&2 + echo "$engine_host" +} + +function is_swarm_enabled { + docker info 2> /dev/null | grep -q 'Swarm: active' +} + +function cleanup { + COMPOSE_PROJECT_NAME=$1 COMPOSE_FILE=$2 docker-compose down >&2 +} + +function runtests { + local engine_host=$1 + + env -i \ + TEST_DOCKER_HOST="$engine_host" \ + GOPATH="$GOPATH" \ + PATH="$PWD/build/" \ + "$(which go)" test -v ./e2e/... +} + +export unique_id="${E2E_UNIQUE_ID:-cliendtoendsuite}" +compose_env_file=./e2e/compose-env.yaml + +cmd=${1-} + +case "$cmd" in + setup) + setup "$unique_id" "$compose_env_file" + exit + ;; + cleanup) + cleanup "$unique_id" "$compose_env_file" + exit + ;; + test) + engine_host=${2-} + if [[ -z "${engine_host}" ]]; then + echo "missing parameter docker engine host" + echo "Usage: $0 test ENGINE_HOST" + exit 3 + fi + runtests "$engine_host" + ;; + run|"") + engine_host="$(setup "$unique_id" "$compose_env_file")" + testexit=0 + runtests "$engine_host" || testexit=$? + cleanup "$unique_id" "$compose_env_file" + exit $testexit + ;; + *) + echo "Unknown command: $cmd" + echo "Usage: " + echo " $0 [setup | cleanup | test | run] [engine_host]" + exit 1 + ;; +esac diff --git a/components/cli/scripts/test/e2e/wait-on-daemon b/components/cli/scripts/test/e2e/wait-on-daemon new file mode 100755 index 0000000000..d1dd5c39f2 --- /dev/null +++ b/components/cli/scripts/test/e2e/wait-on-daemon @@ -0,0 +1,9 @@ +#!/usr/bin/env bash +set -eu -o pipefail + +echo "Waiting for docker daemon to become available at $DOCKER_HOST" +while ! docker version > /dev/null; do + sleep 0.3 +done + +docker version diff --git a/components/cli/scripts/test/e2e/wrapper b/components/cli/scripts/test/e2e/wrapper new file mode 100755 index 0000000000..a3a4f00b67 --- /dev/null +++ b/components/cli/scripts/test/e2e/wrapper @@ -0,0 +1,33 @@ +#!/usr/bin/env bash +# Setup, run and teardown e2e test suite in containers. +set -eu -o pipefail + +unique_id="${E2E_UNIQUE_ID:-cliendtoendsuite}" +e2e_env_image=docker-cli-e2e-env:$unique_id +dev_image=docker-cli-dev:$unique_id + +function run_in_env { + local cmd=$1 + docker run -i --rm \ + -v /var/run/docker.sock:/var/run/docker.sock \ + -e E2E_UNIQUE_ID \ + "$e2e_env_image" "$cmd" +} + +docker build \ + -t "$e2e_env_image" \ + -f dockerfiles/Dockerfile.test-e2e-env . + +docker build \ + -t "$dev_image" \ + -f dockerfiles/Dockerfile.dev . + +engine_host=$(run_in_env setup) +testexit=0 +docker run -i --rm \ + -v "$PWD:/go/src/github.com/docker/cli" \ + --network "${unique_id}_default" \ + "$dev_image" \ + ./scripts/test/e2e/run test "$engine_host" || testexit="$?" +run_in_env cleanup +exit "$testexit" diff --git a/components/cli/scripts/test/watch b/components/cli/scripts/test/watch index 6c9745aead..264eb7c249 100755 --- a/components/cli/scripts/test/watch +++ b/components/cli/scripts/test/watch @@ -1,3 +1,3 @@ #!/bin/sh # shellcheck disable=SC2016 -exec filewatcher -L 6 -x build -x script go test -timeout 10s -v './${dir}' +exec filewatcher -L 6 -x build -x script go test -timeout 30s -v './${dir}' From 66fb82e7e840214ffbf225acc02b31fb4753614c Mon Sep 17 00:00:00 2001 From: Daniel Nephin Date: Mon, 14 Aug 2017 14:24:11 -0400 Subject: [PATCH 10/47] Add first e2e test Signed-off-by: Daniel Nephin Upstream-commit: b5cb5ee4462cd485348aeb9b2f74ecfd35eb2951 Component: cli --- components/cli/cli/command/stack/remove.go | 8 ++ components/cli/e2e/stack/main_test.go | 26 ++++++ components/cli/e2e/stack/remove_test.go | 89 +++++++++++++++++++ .../cli/e2e/stack/testdata/full-stack.yml | 9 ++ .../testdata/stack-remove-success.golden | 3 + 5 files changed, 135 insertions(+) create mode 100644 components/cli/e2e/stack/main_test.go create mode 100644 components/cli/e2e/stack/remove_test.go create mode 100644 components/cli/e2e/stack/testdata/full-stack.yml create mode 100644 components/cli/e2e/stack/testdata/stack-remove-success.golden diff --git a/components/cli/cli/command/stack/remove.go b/components/cli/cli/command/stack/remove.go index d95171aabf..157f71ea12 100644 --- a/components/cli/cli/command/stack/remove.go +++ b/components/cli/cli/command/stack/remove.go @@ -2,6 +2,7 @@ package stack import ( "fmt" + "sort" "strings" "github.com/docker/cli/cli" @@ -88,12 +89,19 @@ func runRemove(dockerCli command.Cli, opts removeOptions) error { return nil } +func sortServiceByName(services []swarm.Service) func(i, j int) bool { + return func(i, j int) bool { + return services[i].Spec.Name < services[j].Spec.Name + } +} + func removeServices( ctx context.Context, dockerCli command.Cli, services []swarm.Service, ) bool { var hasError bool + sort.Slice(services, sortServiceByName(services)) for _, service := range services { fmt.Fprintf(dockerCli.Err(), "Removing service %s\n", service.Spec.Name) if err := dockerCli.Client().ServiceRemove(ctx, service.ID); err != nil { diff --git a/components/cli/e2e/stack/main_test.go b/components/cli/e2e/stack/main_test.go new file mode 100644 index 0000000000..74081f457b --- /dev/null +++ b/components/cli/e2e/stack/main_test.go @@ -0,0 +1,26 @@ +package stack + +import ( + "fmt" + "os" + "testing" + + "github.com/pkg/errors" +) + +func TestMain(m *testing.M) { + if err := setupTestEnv(); err != nil { + fmt.Println(err.Error()) + os.Exit(3) + } + os.Exit(m.Run()) +} + +// TODO: move to shared internal package +func setupTestEnv() error { + dockerHost := os.Getenv("TEST_DOCKER_HOST") + if dockerHost == "" { + return errors.New("$TEST_DOCKER_HOST must be set") + } + return os.Setenv("DOCKER_HOST", dockerHost) +} diff --git a/components/cli/e2e/stack/remove_test.go b/components/cli/e2e/stack/remove_test.go new file mode 100644 index 0000000000..77d95c793d --- /dev/null +++ b/components/cli/e2e/stack/remove_test.go @@ -0,0 +1,89 @@ +package stack + +import ( + "fmt" + "strings" + "testing" + "time" + + shlex "github.com/flynn-archive/go-shlex" + "github.com/gotestyourself/gotestyourself/golden" + "github.com/gotestyourself/gotestyourself/icmd" + "github.com/stretchr/testify/require" +) + +func TestRemove(t *testing.T) { + stackname := "test-stack-remove" + deployFullStack(t, stackname) + defer cleanupFullStack(t, stackname) + + result := icmd.RunCmd(shell(t, "docker stack rm %s", stackname)) + + result.Assert(t, icmd.Expected{Out: icmd.None}) + golden.Assert(t, result.Stderr(), "stack-remove-success.golden") +} + +func deployFullStack(t *testing.T, stackname string) { + // TODO: this stack should have full options not minimal options + result := icmd.RunCmd(shell(t, + "docker stack deploy --compose-file=./testdata/full-stack.yml %s", stackname)) + result.Assert(t, icmd.Success) + + waitOn(t, taskCount(stackname, 2), 0) +} + +func cleanupFullStack(t *testing.T, stackname string) { + result := icmd.RunCmd(shell(t, "docker stack rm %s", stackname)) + result.Assert(t, icmd.Success) + waitOn(t, taskCount(stackname, 0), 0) +} + +func taskCount(stackname string, expected int) func() (bool, error) { + return func() (bool, error) { + result := icmd.RunCommand( + "docker", "stack", "ps", "-f=desired-state=running", stackname) + count := lines(result.Stdout()) - 1 + return count == expected, nil + } +} + +func lines(out string) int { + return len(strings.Split(strings.TrimSpace(out), "\n")) +} + +// TODO: move to gotestyourself +func shell(t *testing.T, format string, args ...interface{}) icmd.Cmd { + cmd, err := shlex.Split(fmt.Sprintf(format, args...)) + require.NoError(t, err) + return icmd.Cmd{Command: cmd} +} + +// TODO: move to gotestyourself +func waitOn(t *testing.T, check func() (bool, error), timeout time.Duration) { + if timeout == time.Duration(0) { + timeout = defaultTimeout() + } + + after := time.After(timeout) + for { + select { + case <-after: + // TODO: include check function name in error message + t.Fatalf("timeout hit after %s", timeout) + default: + // TODO: maybe return a failure message as well? + done, err := check() + if done { + return + } + if err != nil { + t.Fatal(err.Error()) + } + } + } +} + +func defaultTimeout() time.Duration { + // TODO: support override from environment variable + return 10 * time.Second +} diff --git a/components/cli/e2e/stack/testdata/full-stack.yml b/components/cli/e2e/stack/testdata/full-stack.yml new file mode 100644 index 0000000000..8c4d06f854 --- /dev/null +++ b/components/cli/e2e/stack/testdata/full-stack.yml @@ -0,0 +1,9 @@ +version: '3.3' + +services: + one: + image: registry:5000/alpine:3.6 + command: top + two: + image: registry:5000/alpine:3.6 + command: top diff --git a/components/cli/e2e/stack/testdata/stack-remove-success.golden b/components/cli/e2e/stack/testdata/stack-remove-success.golden new file mode 100644 index 0000000000..f41a891702 --- /dev/null +++ b/components/cli/e2e/stack/testdata/stack-remove-success.golden @@ -0,0 +1,3 @@ +Removing service test-stack-remove_one +Removing service test-stack-remove_two +Removing network test-stack-remove_default From 847cb8e0df74c1a00185bf4acd8478e1585780d3 Mon Sep 17 00:00:00 2001 From: Daniel Nephin Date: Tue, 15 Aug 2017 16:59:43 -0400 Subject: [PATCH 11/47] Add a Jenkinsfile Signed-off-by: Daniel Nephin Upstream-commit: 63d76065bb34cdf39804ee185be49b77667ba490 Component: cli --- components/cli/Jenkinsfile | 12 ++++++++++++ components/cli/docker.Makefile | 10 +++++----- components/cli/dockerfiles/Dockerfile.test-e2e-env | 6 ++++-- components/cli/e2e/compose-env.yaml | 2 +- 4 files changed, 22 insertions(+), 8 deletions(-) create mode 100644 components/cli/Jenkinsfile diff --git a/components/cli/Jenkinsfile b/components/cli/Jenkinsfile new file mode 100644 index 0000000000..c5fd505597 --- /dev/null +++ b/components/cli/Jenkinsfile @@ -0,0 +1,12 @@ +wrappedNode(label: 'linux && x86_64', cleanWorkspace: true) { + timeout(time: 60, unit: 'MINUTES') { + stage "Git Checkout" + checkout scm + + stage "Run end-to-end test suite" + sh "docker version" + sh "E2E_UNIQUE_ID=clie2e${BUILD_NUMBER} \ + IMAGE_TAG=clie2e${BUILD_NUMBER} \ + make -f docker.Makefile test-e2e" + } +} diff --git a/components/cli/docker.Makefile b/components/cli/docker.Makefile index 2054c89209..097ad49399 100644 --- a/components/cli/docker.Makefile +++ b/components/cli/docker.Makefile @@ -4,10 +4,10 @@ # Makefile for developing using Docker # -DEV_DOCKER_IMAGE_NAME = docker-cli-dev -LINTER_IMAGE_NAME = docker-cli-lint -CROSS_IMAGE_NAME = docker-cli-cross -VALIDATE_IMAGE_NAME = docker-cli-shell-validate +DEV_DOCKER_IMAGE_NAME = docker-cli-dev$(IMAGE_TAG) +LINTER_IMAGE_NAME = docker-cli-lint$(IMAGE_TAG) +CROSS_IMAGE_NAME = docker-cli-cross$(IMAGE_TAG) +VALIDATE_IMAGE_NAME = docker-cli-shell-validate$(IMAGE_TAG) MOUNTS = -v "$(CURDIR)":/go/src/github.com/docker/cli VERSION = $(shell cat VERSION) ENVVARS = -e VERSION=$(VERSION) -e GITCOMMIT @@ -91,6 +91,6 @@ yamldocs: build_docker_image shellcheck: build_shell_validate_image docker run -ti --rm $(ENVVARS) $(MOUNTS) $(VALIDATE_IMAGE_NAME) make shellcheck -.PHONY: test-e2e: +.PHONY: test-e2e test-e2e: binary ./scripts/test/e2e/wrapper diff --git a/components/cli/dockerfiles/Dockerfile.test-e2e-env b/components/cli/dockerfiles/Dockerfile.test-e2e-env index c16b914bdb..3c672f4e8c 100644 --- a/components/cli/dockerfiles/Dockerfile.test-e2e-env +++ b/components/cli/dockerfiles/Dockerfile.test-e2e-env @@ -2,7 +2,10 @@ FROM docker/compose:1.15.0 RUN apk add -U bash curl -RUN curl -Ls https://download.docker.com/linux/static/edge/x86_64/docker-17.06.0-ce.tgz | \ +ARG DOCKER_CHANNEL=edge +ARG DOCKER_VERSION=17.06.0-ce +RUN export URL=https://download.docker.com/linux/static; \ + curl -Ls $URL/$DOCKER_CHANNEL/x86_64/docker-$DOCKER_VERSION.tgz | \ tar -xz docker/docker && \ mv docker/docker /usr/local/bin/ && \ rmdir docker @@ -12,4 +15,3 @@ COPY scripts/test/e2e scripts/test/e2e COPY e2e/compose-env.yaml e2e/compose-env.yaml ENTRYPOINT ["bash", "/work/scripts/test/e2e/run"] -CMD [] diff --git a/components/cli/e2e/compose-env.yaml b/components/cli/e2e/compose-env.yaml index f16a23c608..afc95e3af0 100644 --- a/components/cli/e2e/compose-env.yaml +++ b/components/cli/e2e/compose-env.yaml @@ -1,4 +1,4 @@ -version: '3.3' +version: '2.1' services: registry: From 457a3de5d940a00e420b13147370ad577e3e0c19 Mon Sep 17 00:00:00 2001 From: Christophe Vidal Date: Wed, 16 Aug 2017 09:05:44 +0700 Subject: [PATCH 12/47] Updated & reformulated kinds of mounts section Signed-off-by: Christophe Vidal Upstream-commit: 9c4b9c6f63b2096352d52291f259d9c37dd5f455 Component: cli --- .../cli/docs/reference/commandline/service_create.md | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/components/cli/docs/reference/commandline/service_create.md b/components/cli/docs/reference/commandline/service_create.md index 184e9f952a..458575c87b 100644 --- a/components/cli/docs/reference/commandline/service_create.md +++ b/components/cli/docs/reference/commandline/service_create.md @@ -243,14 +243,12 @@ $ docker service create \ For more information about labels, refer to [apply custom metadata](https://docs.docker.com/engine/userguide/labels-custom-metadata/). -### Add bind-mounts or volumes +### Add bind-mounts, volumes or memory filesystems -Docker supports two different kinds of mounts, which allow containers to read to -or write from files or directories on other containers or the host operating -system. These types are _data volumes_ (often referred to simply as volumes) and -_bind-mounts_. - -Additionally, Docker supports `tmpfs` mounts. +Docker supports three different kinds of mounts, which allow containers to read +from or write to files or directories, either on the host operating system, or +on memory filesystems. These types are _data volumes_ (often referred to simply +as volumes), _bind-mounts_, and _tmpfs_. A **bind-mount** makes a file or directory on the host available to the container it is mounted within. A bind-mount may be either read-only or From 3b7026d84cd152aec97f75bb381ed303356fc75b Mon Sep 17 00:00:00 2001 From: Daniel Nephin Date: Mon, 14 Aug 2017 14:28:08 -0400 Subject: [PATCH 13/47] Add gotestyourself dependency. Signed-off-by: Daniel Nephin Upstream-commit: 882992c6fc801bba517c9e3197477a1e990e2e07 Component: cli --- components/cli/vendor.conf | 1 + .../docker/pkg/testutil/golden/golden.go | 28 --- .../docker/pkg/testutil/tempfile/tempfile.go | 56 ----- .../gotestyourself/gotestyourself/LICENSE | 202 ++++++++++++++++++ .../gotestyourself/gotestyourself/README.md | 32 +++ .../gotestyourself/gotestyourself/fs/file.go | 81 +++++++ .../gotestyourself/gotestyourself/fs/ops.go | 94 ++++++++ .../gotestyourself/golden/golden.go | 71 ++++++ .../gotestyourself/skip/skip.go | 133 ++++++++++++ 9 files changed, 614 insertions(+), 84 deletions(-) delete mode 100644 components/cli/vendor/github.com/docker/docker/pkg/testutil/golden/golden.go delete mode 100644 components/cli/vendor/github.com/docker/docker/pkg/testutil/tempfile/tempfile.go create mode 100644 components/cli/vendor/github.com/gotestyourself/gotestyourself/LICENSE create mode 100644 components/cli/vendor/github.com/gotestyourself/gotestyourself/README.md create mode 100644 components/cli/vendor/github.com/gotestyourself/gotestyourself/fs/file.go create mode 100644 components/cli/vendor/github.com/gotestyourself/gotestyourself/fs/ops.go create mode 100644 components/cli/vendor/github.com/gotestyourself/gotestyourself/golden/golden.go create mode 100644 components/cli/vendor/github.com/gotestyourself/gotestyourself/skip/skip.go diff --git a/components/cli/vendor.conf b/components/cli/vendor.conf index 1e9e72ff43..d27abce96a 100755 --- a/components/cli/vendor.conf +++ b/components/cli/vendor.conf @@ -22,6 +22,7 @@ github.com/docker/swarmkit 79381d0840be27f8b3f5c667b348a4467d866eeb github.com/flynn-archive/go-shlex 3f9db97f856818214da2e1057f8ad84803971cff github.com/gogo/protobuf 7efa791bd276fd4db00867cbd982b552627c24cb 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/inconshreveable/mousetrap 76626ae9c91c4f2a10f34cad8ce83ea42c93bb75 diff --git a/components/cli/vendor/github.com/docker/docker/pkg/testutil/golden/golden.go b/components/cli/vendor/github.com/docker/docker/pkg/testutil/golden/golden.go deleted file mode 100644 index 8f725da7bf..0000000000 --- a/components/cli/vendor/github.com/docker/docker/pkg/testutil/golden/golden.go +++ /dev/null @@ -1,28 +0,0 @@ -// Package golden provides function and helpers to use golden file for -// testing purpose. -package golden - -import ( - "flag" - "io/ioutil" - "path/filepath" - "testing" -) - -var update = flag.Bool("test.update", false, "update golden file") - -// Get returns the golden file content. If the `test.update` is specified, it updates the -// file with the current output and returns it. -func Get(t *testing.T, actual []byte, filename string) []byte { - golden := filepath.Join("testdata", filename) - if *update { - if err := ioutil.WriteFile(golden, actual, 0644); err != nil { - t.Fatal(err) - } - } - expected, err := ioutil.ReadFile(golden) - if err != nil { - t.Fatal(err) - } - return expected -} diff --git a/components/cli/vendor/github.com/docker/docker/pkg/testutil/tempfile/tempfile.go b/components/cli/vendor/github.com/docker/docker/pkg/testutil/tempfile/tempfile.go deleted file mode 100644 index 01474babff..0000000000 --- a/components/cli/vendor/github.com/docker/docker/pkg/testutil/tempfile/tempfile.go +++ /dev/null @@ -1,56 +0,0 @@ -package tempfile - -import ( - "io/ioutil" - "os" - - "github.com/stretchr/testify/require" -) - -// TempFile is a temporary file that can be used with unit tests. TempFile -// reduces the boilerplate setup required in each test case by handling -// setup errors. -type TempFile struct { - File *os.File -} - -// NewTempFile returns a new temp file with contents -func NewTempFile(t require.TestingT, prefix string, content string) *TempFile { - file, err := ioutil.TempFile("", prefix+"-") - require.NoError(t, err) - - _, err = file.Write([]byte(content)) - require.NoError(t, err) - file.Close() - return &TempFile{File: file} -} - -// Name returns the filename -func (f *TempFile) Name() string { - return f.File.Name() -} - -// Remove removes the file -func (f *TempFile) Remove() { - os.Remove(f.Name()) -} - -// TempDir is a temporary directory that can be used with unit tests. TempDir -// reduces the boilerplate setup required in each test case by handling -// setup errors. -type TempDir struct { - Path string -} - -// NewTempDir returns a new temp file with contents -func NewTempDir(t require.TestingT, prefix string) *TempDir { - path, err := ioutil.TempDir("", prefix+"-") - require.NoError(t, err) - - return &TempDir{Path: path} -} - -// Remove removes the file -func (f *TempDir) Remove() { - os.Remove(f.Path) -} diff --git a/components/cli/vendor/github.com/gotestyourself/gotestyourself/LICENSE b/components/cli/vendor/github.com/gotestyourself/gotestyourself/LICENSE new file mode 100644 index 0000000000..d645695673 --- /dev/null +++ b/components/cli/vendor/github.com/gotestyourself/gotestyourself/LICENSE @@ -0,0 +1,202 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/components/cli/vendor/github.com/gotestyourself/gotestyourself/README.md b/components/cli/vendor/github.com/gotestyourself/gotestyourself/README.md new file mode 100644 index 0000000000..2648074900 --- /dev/null +++ b/components/cli/vendor/github.com/gotestyourself/gotestyourself/README.md @@ -0,0 +1,32 @@ +# Go Test Yourself + +A collection of packages compatible with `go test` to support common testing +patterns. + +[![GoDoc](https://godoc.org/github.com/gotestyourself/gotestyourself?status.svg)](https://godoc.org/github.com/gotestyourself/gotestyourself) +[![CircleCI](https://circleci.com/gh/gotestyourself/gotestyourself/tree/master.svg?style=shield)](https://circleci.com/gh/gotestyourself/gotestyourself/tree/master) +[![Go Reportcard](https://goreportcard.com/badge/github.com/gotestyourself/gotestyourself)](https://goreportcard.com/report/github.com/gotestyourself/gotestyourself) + + +## Packages + +* [fs](http://godoc.org/github.com/gotestyourself/gotestyourself/fs) - + create test files and directories +* [golden](http://godoc.org/github.com/gotestyourself/gotestyourself/golden) - + compare large multi-line strings +* [testsum](http://godoc.org/github.com/gotestyourself/gotestyourself/testsum) - + a program to summarize `go test` output and test failures +* [icmd](http://godoc.org/github.com/gotestyourself/gotestyourself/icmd) - + execute binaries and test the output +* [skip](http://godoc.org/github.com/gotestyourself/gotestyourself/skip) - + skip tests based on conditions + + +## Related + +* [testify/assert](https://godoc.org/github.com/stretchr/testify/assert) and + [testify/require](https://godoc.org/github.com/stretchr/testify/require) - + assertion libraries with common assertions +* [golang/mock](https://github.com/golang/mock) - generate mocks for interfaces +* [testify/suite](https://godoc.org/github.com/stretchr/testify/suite) - + group test into suites to share common setup/teardown logic diff --git a/components/cli/vendor/github.com/gotestyourself/gotestyourself/fs/file.go b/components/cli/vendor/github.com/gotestyourself/gotestyourself/fs/file.go new file mode 100644 index 0000000000..dcda10a02a --- /dev/null +++ b/components/cli/vendor/github.com/gotestyourself/gotestyourself/fs/file.go @@ -0,0 +1,81 @@ +/*Package fs provides tools for creating and working with temporary files and +directories. +*/ +package fs + +import ( + "io/ioutil" + "os" + "path/filepath" + + "github.com/stretchr/testify/require" +) + +// Path objects return their filesystem path. Both File and Dir implement Path. +type Path interface { + Path() string +} + +// File is a temporary file on the filesystem +type File struct { + path string +} + +// NewFile creates a new file in a temporary directory using prefix as part of +// the filename. The PathOps are applied to the before returning the File. +func NewFile(t require.TestingT, prefix string, ops ...PathOp) *File { + tempfile, err := ioutil.TempFile("", prefix+"-") + require.NoError(t, err) + file := &File{path: tempfile.Name()} + require.NoError(t, tempfile.Close()) + + for _, op := range ops { + require.NoError(t, op(file)) + } + return file +} + +// Path returns the full path to the file +func (f *File) Path() string { + return f.path +} + +// Remove the file +func (f *File) Remove() { + // nolint: errcheck + os.Remove(f.path) +} + +// Dir is a temporary directory +type Dir struct { + path string +} + +// NewDir returns a new temporary directory using prefix as part of the directory +// name. The PathOps are applied before returning the Dir. +func NewDir(t require.TestingT, prefix string, ops ...PathOp) *Dir { + path, err := ioutil.TempDir("", prefix+"-") + require.NoError(t, err) + dir := &Dir{path: path} + + for _, op := range ops { + require.NoError(t, op(dir)) + } + return dir +} + +// Path returns the full path to the directory +func (d *Dir) Path() string { + return d.path +} + +// Remove the directory +func (d *Dir) Remove() { + // nolint: errcheck + os.RemoveAll(d.path) +} + +// Join returns a new path with this directory as the base of the path +func (d *Dir) Join(parts ...string) string { + return filepath.Join(append([]string{d.Path()}, parts...)...) +} diff --git a/components/cli/vendor/github.com/gotestyourself/gotestyourself/fs/ops.go b/components/cli/vendor/github.com/gotestyourself/gotestyourself/fs/ops.go new file mode 100644 index 0000000000..4fbc40f422 --- /dev/null +++ b/components/cli/vendor/github.com/gotestyourself/gotestyourself/fs/ops.go @@ -0,0 +1,94 @@ +package fs + +import ( + "io/ioutil" + "os" + "path/filepath" +) + +// PathOp is a function which accepts a Path to perform some operation +type PathOp func(path Path) error + +// WithContent writes content to a file at Path +func WithContent(content string) PathOp { + return func(path Path) error { + return ioutil.WriteFile(path.Path(), []byte(content), 0644) + } +} + +// WithBytes write bytes to a file at Path +func WithBytes(raw []byte) PathOp { + return func(path Path) error { + return ioutil.WriteFile(path.Path(), raw, 0644) + } +} + +// AsUser changes ownership of the file system object at Path +func AsUser(uid, gid int) PathOp { + return func(path Path) error { + return os.Chown(path.Path(), uid, gid) + } +} + +// WithFile creates a file in the directory at path with content +func WithFile(filename, content string) PathOp { + return func(path Path) error { + return createFile(path.Path(), filename, content) + } +} + +func createFile(dir, filename, content string) error { + fullpath := filepath.Join(dir, filepath.FromSlash(filename)) + return ioutil.WriteFile(fullpath, []byte(content), 0644) +} + +// WithFiles creates all the files in the directory at path with their content +func WithFiles(files map[string]string) PathOp { + return func(path Path) error { + for filename, content := range files { + if err := createFile(path.Path(), filename, content); err != nil { + return err + } + } + return nil + } +} + +// FromDir copies the directory tree from the source path into the new Dir +func FromDir(source string) PathOp { + return func(path Path) error { + return copyDirectory(source, path.Path()) + } +} + +func copyDirectory(source, dest string) error { + entries, err := ioutil.ReadDir(source) + if err != nil { + return err + } + for _, entry := range entries { + sourcePath := filepath.Join(source, entry.Name()) + destPath := filepath.Join(dest, entry.Name()) + if entry.IsDir() { + if err := os.Mkdir(destPath, 0755); err != nil { + return err + } + if err := copyDirectory(sourcePath, destPath); err != nil { + return err + } + continue + } + if err := copyFile(sourcePath, destPath); err != nil { + return err + } + } + return nil +} + +func copyFile(source, dest string) error { + content, err := ioutil.ReadFile(source) + if err != nil { + return err + } + return ioutil.WriteFile(dest, content, 0644) +} diff --git a/components/cli/vendor/github.com/gotestyourself/gotestyourself/golden/golden.go b/components/cli/vendor/github.com/gotestyourself/gotestyourself/golden/golden.go new file mode 100644 index 0000000000..230ff685cd --- /dev/null +++ b/components/cli/vendor/github.com/gotestyourself/gotestyourself/golden/golden.go @@ -0,0 +1,71 @@ +/*Package golden provides tools for comparing large mutli-line strings. + +Golden files are files in the ./testdata/ subdirectory of the package under test. +*/ +package golden + +import ( + "flag" + "fmt" + "io/ioutil" + "path/filepath" + + "github.com/pmezard/go-difflib/difflib" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +var flagUpdate = flag.Bool("test.update-golden", false, "update golden file") + +// Get returns the golden file content +func Get(t require.TestingT, filename string) []byte { + expected, err := ioutil.ReadFile(Path(filename)) + require.NoError(t, err) + return expected +} + +// Path returns the full path to a golden file +func Path(filename string) string { + return filepath.Join("testdata", filename) +} + +func update(t require.TestingT, filename string, actual []byte) { + if *flagUpdate { + err := ioutil.WriteFile(Path(filename), actual, 0644) + require.NoError(t, err) + } +} + +// Assert compares the actual content to the expected content in the golden file. +// If `--update-golden` is set then the actual content is written to the golden +// file. +// Returns whether the assertion was successful (true) or not (false) +func Assert(t require.TestingT, actual string, filename string, msgAndArgs ...interface{}) bool { + expected := Get(t, filename) + update(t, filename, []byte(actual)) + + if assert.ObjectsAreEqual(expected, []byte(actual)) { + return true + } + + diff, err := difflib.GetUnifiedDiffString(difflib.UnifiedDiff{ + A: difflib.SplitLines(string(expected)), + B: difflib.SplitLines(actual), + FromFile: "Expected", + ToFile: "Actual", + Context: 3, + }) + require.NoError(t, err, msgAndArgs...) + return assert.Fail(t, fmt.Sprintf("Not Equal: \n%s", diff), msgAndArgs...) +} + +// AssertBytes compares the actual result to the expected result in the golden +// file. If `--update-golden` is set then the actual content is written to the +// golden file. +// Returns whether the assertion was successful (true) or not (false) +// nolint: lll +func AssertBytes(t require.TestingT, actual []byte, filename string, msgAndArgs ...interface{}) bool { + expected := Get(t, filename) + update(t, filename, actual) + return assert.Equal(t, expected, actual, msgAndArgs...) +} diff --git a/components/cli/vendor/github.com/gotestyourself/gotestyourself/skip/skip.go b/components/cli/vendor/github.com/gotestyourself/gotestyourself/skip/skip.go new file mode 100644 index 0000000000..d92110b0ef --- /dev/null +++ b/components/cli/vendor/github.com/gotestyourself/gotestyourself/skip/skip.go @@ -0,0 +1,133 @@ +/*Package skip provides functions for skipping based on a condition. + */ +package skip + +import ( + "bytes" + "fmt" + "go/ast" + "go/format" + "go/parser" + "go/token" + "io/ioutil" + "path" + "reflect" + "runtime" + "strings" + + "github.com/pkg/errors" +) + +type skipT interface { + Skip(args ...interface{}) + Log(args ...interface{}) +} + +// If skips the test if the check function returns true. The skip message will +// contain the name of the check function. Extra message text can be passed as a +// format string with args +func If(t skipT, check func() bool, msgAndArgs ...interface{}) { + if check() { + t.Skip(formatWithCustomMessage( + getFunctionName(check), + formatMessage(msgAndArgs...))) + } +} + +func getFunctionName(function func() bool) string { + funcPath := runtime.FuncForPC(reflect.ValueOf(function).Pointer()).Name() + return strings.SplitN(path.Base(funcPath), ".", 2)[1] +} + +// IfCondition skips the test if the condition is true. The skip message will +// contain the source of the expression passed as the condition. Extra message +// text can be passed as a format string with args. +func IfCondition(t skipT, condition bool, msgAndArgs ...interface{}) { + if !condition { + return + } + source, err := getConditionSource() + if err != nil { + t.Log(err.Error()) + t.Skip(formatMessage(msgAndArgs...)) + } + t.Skip(formatWithCustomMessage(source, formatMessage(msgAndArgs...))) +} + +func getConditionSource() (string, error) { + const callstackIndex = 3 + lines, err := getSourceLine(callstackIndex) + if err != nil { + return "", err + } + + for i := range lines { + source := strings.Join(lines[len(lines)-i-1:], "\n") + node, err := parser.ParseExpr(source) + if err == nil { + return getConditionArgFromAST(node) + } + } + return "", errors.Wrapf(err, "failed to parse source") +} + +// maxContextLines is the maximum number of lines to scan for a complete +// skip.If() statement +const maxContextLines = 10 + +// getSourceLines returns the source line which called skip.If() along with a +// few preceding lines. To properly parse the AST a complete statement is +// required, and that statement may be split across multiple lines, so include +// up to maxContextLines. +func getSourceLine(stackIndex int) ([]string, error) { + _, filename, line, ok := runtime.Caller(stackIndex) + if !ok { + return nil, errors.New("failed to get caller info") + } + + raw, err := ioutil.ReadFile(filename) + if err != nil { + return nil, errors.Wrapf(err, "failed to read source file: %s", filename) + } + + lines := strings.Split(string(raw), "\n") + if len(lines) < line { + return nil, errors.Errorf("file %s does not have line %d", filename, line) + } + firstLine := line - maxContextLines + if firstLine < 0 { + firstLine = 0 + } + return lines[firstLine:line], nil +} + +func getConditionArgFromAST(node ast.Expr) (string, error) { + switch expr := node.(type) { + case *ast.CallExpr: + buf := new(bytes.Buffer) + err := format.Node(buf, token.NewFileSet(), expr.Args[1]) + return buf.String(), err + } + return "", errors.New("unexpected ast") +} + +func formatMessage(msgAndArgs ...interface{}) string { + switch len(msgAndArgs) { + case 0: + return "" + case 1: + return msgAndArgs[0].(string) + default: + return fmt.Sprintf(msgAndArgs[0].(string), msgAndArgs[1:]...) + } +} + +func formatWithCustomMessage(source, custom string) string { + switch { + case custom == "": + return source + case source == "": + return custom + } + return fmt.Sprintf("%s: %s", source, custom) +} From 5a6dec9ec18ec9ea9bf44131063f4bd357b96e92 Mon Sep 17 00:00:00 2001 From: Daniel Nephin Date: Wed, 16 Aug 2017 11:54:23 -0400 Subject: [PATCH 14/47] Update config and checkpoint commands to use gotestyourself/golden Signed-off-by: Daniel Nephin Upstream-commit: f9007ad7db50db4a2d2e3267efd3ec5d8adba3d3 Component: cli --- .../cli/cli/command/checkpoint/list_test.go | 16 +++---- .../cli/cli/command/checkpoint/remove_test.go | 9 ++-- .../cli/cli/command/config/create_test.go | 5 +- .../cli/cli/command/config/inspect_test.go | 48 +++++++------------ components/cli/cli/command/config/ls_test.go | 22 +++------ .../cli/cli/command/config/remove_test.go | 18 +++---- .../config-inspect-pretty.simple.golden | 10 ++-- ...format.multiple-configs-with-labels.golden | 4 +- ...nspect-without-format.single-config.golden | 6 +-- .../config-list-with-config-format.golden | 2 +- .../testdata/config-list-with-format.golden | 2 +- 11 files changed, 54 insertions(+), 88 deletions(-) diff --git a/components/cli/cli/command/checkpoint/list_test.go b/components/cli/cli/command/checkpoint/list_test.go index 1c13f27755..26dd963a8c 100644 --- a/components/cli/cli/command/checkpoint/list_test.go +++ b/components/cli/cli/command/checkpoint/list_test.go @@ -1,14 +1,13 @@ package checkpoint import ( - "bytes" "io/ioutil" "testing" "github.com/docker/cli/cli/internal/test" "github.com/docker/docker/api/types" "github.com/docker/docker/pkg/testutil" - "github.com/docker/docker/pkg/testutil/golden" + "github.com/gotestyourself/gotestyourself/golden" "github.com/pkg/errors" "github.com/stretchr/testify/assert" ) @@ -37,9 +36,9 @@ func TestCheckpointListErrors(t *testing.T) { } for _, tc := range testCases { - cli := test.NewFakeCliWithOutput(&fakeClient{ + cli := test.NewFakeCli(&fakeClient{ checkpointListFunc: tc.checkpointListFunc, - }, &bytes.Buffer{}) + }) cmd := newListCommand(cli) cmd.SetArgs(tc.args) cmd.SetOutput(ioutil.Discard) @@ -49,8 +48,7 @@ func TestCheckpointListErrors(t *testing.T) { func TestCheckpointListWithOptions(t *testing.T) { var containerID, checkpointDir string - buf := new(bytes.Buffer) - cli := test.NewFakeCliWithOutput(&fakeClient{ + cli := test.NewFakeCli(&fakeClient{ checkpointListFunc: func(container string, options types.CheckpointListOptions) ([]types.Checkpoint, error) { containerID = container checkpointDir = options.CheckpointDir @@ -58,14 +56,12 @@ func TestCheckpointListWithOptions(t *testing.T) { {Name: "checkpoint-foo"}, }, nil }, - }, buf) + }) cmd := newListCommand(cli) cmd.SetArgs([]string{"container-foo"}) cmd.Flags().Set("checkpoint-dir", "/dir/foo") assert.NoError(t, cmd.Execute()) assert.Equal(t, "container-foo", containerID) assert.Equal(t, "/dir/foo", checkpointDir) - actual := buf.String() - expected := golden.Get(t, []byte(actual), "checkpoint-list-with-options.golden") - testutil.EqualNormalizedString(t, testutil.RemoveSpace, actual, string(expected)) + golden.Assert(t, cli.OutBuffer().String(), "checkpoint-list-with-options.golden") } diff --git a/components/cli/cli/command/checkpoint/remove_test.go b/components/cli/cli/command/checkpoint/remove_test.go index 3d85d16cda..976aa07892 100644 --- a/components/cli/cli/command/checkpoint/remove_test.go +++ b/components/cli/cli/command/checkpoint/remove_test.go @@ -1,7 +1,6 @@ package checkpoint import ( - "bytes" "io/ioutil" "testing" @@ -36,9 +35,9 @@ func TestCheckpointRemoveErrors(t *testing.T) { } for _, tc := range testCases { - cli := test.NewFakeCliWithOutput(&fakeClient{ + cli := test.NewFakeCli(&fakeClient{ checkpointDeleteFunc: tc.checkpointDeleteFunc, - }, &bytes.Buffer{}) + }) cmd := newRemoveCommand(cli) cmd.SetArgs(tc.args) cmd.SetOutput(ioutil.Discard) @@ -48,14 +47,14 @@ func TestCheckpointRemoveErrors(t *testing.T) { func TestCheckpointRemoveWithOptions(t *testing.T) { var containerID, checkpointID, checkpointDir string - cli := test.NewFakeCliWithOutput(&fakeClient{ + cli := test.NewFakeCli(&fakeClient{ checkpointDeleteFunc: func(container string, options types.CheckpointDeleteOptions) error { containerID = container checkpointID = options.CheckpointID checkpointDir = options.CheckpointDir return nil }, - }, &bytes.Buffer{}) + }) cmd := newRemoveCommand(cli) cmd.SetArgs([]string{"container-foo", "checkpoint-bar"}) cmd.Flags().Set("checkpoint-dir", "/dir/foo") diff --git a/components/cli/cli/command/config/create_test.go b/components/cli/cli/command/config/create_test.go index f2338d0038..7a6b2f54d3 100644 --- a/components/cli/cli/command/config/create_test.go +++ b/components/cli/cli/command/config/create_test.go @@ -11,7 +11,7 @@ import ( "github.com/docker/docker/api/types" "github.com/docker/docker/api/types/swarm" "github.com/docker/docker/pkg/testutil" - "github.com/docker/docker/pkg/testutil/golden" + "github.com/gotestyourself/gotestyourself/golden" "github.com/pkg/errors" "github.com/stretchr/testify/assert" ) @@ -71,8 +71,7 @@ func TestConfigCreateWithName(t *testing.T) { cmd := newConfigCreateCommand(cli) cmd.SetArgs([]string{name, filepath.Join("testdata", configDataFile)}) assert.NoError(t, cmd.Execute()) - expected := golden.Get(t, actual, configDataFile) - assert.Equal(t, string(expected), string(actual)) + golden.Assert(t, string(actual), configDataFile) assert.Equal(t, "ID-"+name, strings.TrimSpace(cli.OutBuffer().String())) } diff --git a/components/cli/cli/command/config/inspect_test.go b/components/cli/cli/command/config/inspect_test.go index e1af0b6b09..0431ffd652 100644 --- a/components/cli/cli/command/config/inspect_test.go +++ b/components/cli/cli/command/config/inspect_test.go @@ -1,7 +1,6 @@ package config import ( - "bytes" "fmt" "io/ioutil" "testing" @@ -13,7 +12,7 @@ import ( // Import builders to get the builder function as package function . "github.com/docker/cli/cli/internal/test/builders" "github.com/docker/docker/pkg/testutil" - "github.com/docker/docker/pkg/testutil/golden" + "github.com/gotestyourself/gotestyourself/golden" "github.com/stretchr/testify/assert" ) @@ -53,11 +52,10 @@ func TestConfigInspectErrors(t *testing.T) { }, } for _, tc := range testCases { - buf := new(bytes.Buffer) cmd := newConfigInspectCommand( - test.NewFakeCliWithOutput(&fakeClient{ + test.NewFakeCli(&fakeClient{ configInspectFunc: tc.configInspectFunc, - }, buf), + }), ) cmd.SetArgs(tc.args) for key, value := range tc.flags { @@ -95,17 +93,11 @@ func TestConfigInspectWithoutFormat(t *testing.T) { }, } for _, tc := range testCases { - buf := new(bytes.Buffer) - cmd := newConfigInspectCommand( - test.NewFakeCliWithOutput(&fakeClient{ - configInspectFunc: tc.configInspectFunc, - }, buf), - ) + cli := test.NewFakeCli(&fakeClient{configInspectFunc: tc.configInspectFunc}) + cmd := newConfigInspectCommand(cli) cmd.SetArgs(tc.args) assert.NoError(t, cmd.Execute()) - actual := buf.String() - expected := golden.Get(t, []byte(actual), fmt.Sprintf("config-inspect-without-format.%s.golden", tc.name)) - testutil.EqualNormalizedString(t, testutil.RemoveSpace, actual, string(expected)) + golden.Assert(t, cli.OutBuffer().String(), fmt.Sprintf("config-inspect-without-format.%s.golden", tc.name)) } } @@ -135,18 +127,14 @@ func TestConfigInspectWithFormat(t *testing.T) { }, } for _, tc := range testCases { - buf := new(bytes.Buffer) - cmd := newConfigInspectCommand( - test.NewFakeCliWithOutput(&fakeClient{ - configInspectFunc: tc.configInspectFunc, - }, buf), - ) + cli := test.NewFakeCli(&fakeClient{ + configInspectFunc: tc.configInspectFunc, + }) + cmd := newConfigInspectCommand(cli) cmd.SetArgs(tc.args) cmd.Flags().Set("format", tc.format) assert.NoError(t, cmd.Execute()) - actual := buf.String() - expected := golden.Get(t, []byte(actual), fmt.Sprintf("config-inspect-with-format.%s.golden", tc.name)) - testutil.EqualNormalizedString(t, testutil.RemoveSpace, actual, string(expected)) + golden.Assert(t, cli.OutBuffer().String(), fmt.Sprintf("config-inspect-with-format.%s.golden", tc.name)) } } @@ -172,16 +160,14 @@ func TestConfigInspectPretty(t *testing.T) { }, } for _, tc := range testCases { - buf := new(bytes.Buffer) - cmd := newConfigInspectCommand( - test.NewFakeCliWithOutput(&fakeClient{ - configInspectFunc: tc.configInspectFunc, - }, buf)) + cli := test.NewFakeCli(&fakeClient{ + configInspectFunc: tc.configInspectFunc, + }) + cmd := newConfigInspectCommand(cli) + cmd.SetArgs([]string{"configID"}) cmd.Flags().Set("pretty", "true") assert.NoError(t, cmd.Execute()) - actual := buf.String() - expected := golden.Get(t, []byte(actual), fmt.Sprintf("config-inspect-pretty.%s.golden", tc.name)) - testutil.EqualNormalizedString(t, testutil.RemoveSpace, actual, string(expected)) + golden.Assert(t, cli.OutBuffer().String(), fmt.Sprintf("config-inspect-pretty.%s.golden", tc.name)) } } diff --git a/components/cli/cli/command/config/ls_test.go b/components/cli/cli/command/config/ls_test.go index c8393caca5..f58e815a5b 100644 --- a/components/cli/cli/command/config/ls_test.go +++ b/components/cli/cli/command/config/ls_test.go @@ -13,7 +13,7 @@ import ( // Import builders to get the builder function as package function . "github.com/docker/cli/cli/internal/test/builders" "github.com/docker/docker/pkg/testutil" - "github.com/docker/docker/pkg/testutil/golden" + "github.com/gotestyourself/gotestyourself/golden" "github.com/stretchr/testify/assert" ) @@ -68,9 +68,7 @@ func TestConfigList(t *testing.T) { cmd := newConfigListCommand(cli) cmd.SetOutput(cli.OutBuffer()) assert.NoError(t, cmd.Execute()) - actual := cli.OutBuffer().String() - expected := golden.Get(t, []byte(actual), "config-list.golden") - testutil.EqualNormalizedString(t, testutil.RemoveSpace, actual, string(expected)) + golden.Assert(t, cli.OutBuffer().String(), "config-list.golden") } func TestConfigListWithQuietOption(t *testing.T) { @@ -87,9 +85,7 @@ func TestConfigListWithQuietOption(t *testing.T) { cmd := newConfigListCommand(cli) cmd.Flags().Set("quiet", "true") assert.NoError(t, cmd.Execute()) - actual := cli.OutBuffer().String() - expected := golden.Get(t, []byte(actual), "config-list-with-quiet-option.golden") - testutil.EqualNormalizedString(t, testutil.RemoveSpace, actual, string(expected)) + golden.Assert(t, cli.OutBuffer().String(), "config-list-with-quiet-option.golden") } func TestConfigListWithConfigFormat(t *testing.T) { @@ -108,9 +104,7 @@ func TestConfigListWithConfigFormat(t *testing.T) { }) cmd := newConfigListCommand(cli) assert.NoError(t, cmd.Execute()) - actual := cli.OutBuffer().String() - expected := golden.Get(t, []byte(actual), "config-list-with-config-format.golden") - testutil.EqualNormalizedString(t, testutil.RemoveSpace, actual, string(expected)) + golden.Assert(t, cli.OutBuffer().String(), "config-list-with-config-format.golden") } func TestConfigListWithFormat(t *testing.T) { @@ -127,9 +121,7 @@ func TestConfigListWithFormat(t *testing.T) { cmd := newConfigListCommand(cli) cmd.Flags().Set("format", "{{ .Name }} {{ .Labels }}") assert.NoError(t, cmd.Execute()) - actual := cli.OutBuffer().String() - expected := golden.Get(t, []byte(actual), "config-list-with-format.golden") - testutil.EqualNormalizedString(t, testutil.RemoveSpace, actual, string(expected)) + golden.Assert(t, cli.OutBuffer().String(), "config-list-with-format.golden") } func TestConfigListWithFilter(t *testing.T) { @@ -157,7 +149,5 @@ func TestConfigListWithFilter(t *testing.T) { cmd.Flags().Set("filter", "name=foo") cmd.Flags().Set("filter", "label=lbl1=Label-bar") assert.NoError(t, cmd.Execute()) - actual := cli.OutBuffer().String() - expected := golden.Get(t, []byte(actual), "config-list-with-filter.golden") - testutil.EqualNormalizedString(t, testutil.RemoveSpace, actual, string(expected)) + golden.Assert(t, cli.OutBuffer().String(), "config-list-with-filter.golden") } diff --git a/components/cli/cli/command/config/remove_test.go b/components/cli/cli/command/config/remove_test.go index 2b2b28ae11..28cc41f670 100644 --- a/components/cli/cli/command/config/remove_test.go +++ b/components/cli/cli/command/config/remove_test.go @@ -1,7 +1,6 @@ package config import ( - "bytes" "io/ioutil" "strings" "testing" @@ -31,11 +30,10 @@ func TestConfigRemoveErrors(t *testing.T) { }, } for _, tc := range testCases { - buf := new(bytes.Buffer) cmd := newConfigRemoveCommand( - test.NewFakeCliWithOutput(&fakeClient{ + test.NewFakeCli(&fakeClient{ configRemoveFunc: tc.configRemoveFunc, - }, buf), + }), ) cmd.SetArgs(tc.args) cmd.SetOutput(ioutil.Discard) @@ -45,27 +43,25 @@ func TestConfigRemoveErrors(t *testing.T) { func TestConfigRemoveWithName(t *testing.T) { names := []string{"foo", "bar"} - buf := new(bytes.Buffer) var removedConfigs []string - cli := test.NewFakeCliWithOutput(&fakeClient{ + cli := test.NewFakeCli(&fakeClient{ configRemoveFunc: func(name string) error { removedConfigs = append(removedConfigs, name) return nil }, - }, buf) + }) cmd := newConfigRemoveCommand(cli) cmd.SetArgs(names) assert.NoError(t, cmd.Execute()) - assert.Equal(t, names, strings.Split(strings.TrimSpace(buf.String()), "\n")) + assert.Equal(t, names, strings.Split(strings.TrimSpace(cli.OutBuffer().String()), "\n")) assert.Equal(t, names, removedConfigs) } func TestConfigRemoveContinueAfterError(t *testing.T) { names := []string{"foo", "bar"} - buf := new(bytes.Buffer) var removedConfigs []string - cli := test.NewFakeCliWithOutput(&fakeClient{ + cli := test.NewFakeCli(&fakeClient{ configRemoveFunc: func(name string) error { removedConfigs = append(removedConfigs, name) if name == "foo" { @@ -73,7 +69,7 @@ func TestConfigRemoveContinueAfterError(t *testing.T) { } return nil }, - }, buf) + }) cmd := newConfigRemoveCommand(cli) cmd.SetArgs(names) diff --git a/components/cli/cli/command/config/testdata/config-inspect-pretty.simple.golden b/components/cli/cli/command/config/testdata/config-inspect-pretty.simple.golden index d5eefec543..60b5c7fa4a 100644 --- a/components/cli/cli/command/config/testdata/config-inspect-pretty.simple.golden +++ b/components/cli/cli/command/config/testdata/config-inspect-pretty.simple.golden @@ -1,8 +1,8 @@ -ID: configID -Name: configName +ID: configID +Name: configName Labels: - - lbl1=value1 -Created at: 0001-01-01 00:00:00+0000 utc -Updated at: 0001-01-01 00:00:00+0000 utc + - lbl1=value1 +Created at: 0001-01-01 00:00:00 +0000 utc +Updated at: 0001-01-01 00:00:00 +0000 utc Data: payload here diff --git a/components/cli/cli/command/config/testdata/config-inspect-without-format.multiple-configs-with-labels.golden b/components/cli/cli/command/config/testdata/config-inspect-without-format.multiple-configs-with-labels.golden index 6887c185f1..b01a400c57 100644 --- a/components/cli/cli/command/config/testdata/config-inspect-without-format.multiple-configs-with-labels.golden +++ b/components/cli/cli/command/config/testdata/config-inspect-without-format.multiple-configs-with-labels.golden @@ -1,7 +1,7 @@ [ { "ID": "ID-foo", - "Version": {}, + "Version": {}, "CreatedAt": "0001-01-01T00:00:00Z", "UpdatedAt": "0001-01-01T00:00:00Z", "Spec": { @@ -13,7 +13,7 @@ }, { "ID": "ID-bar", - "Version": {}, + "Version": {}, "CreatedAt": "0001-01-01T00:00:00Z", "UpdatedAt": "0001-01-01T00:00:00Z", "Spec": { diff --git a/components/cli/cli/command/config/testdata/config-inspect-without-format.single-config.golden b/components/cli/cli/command/config/testdata/config-inspect-without-format.single-config.golden index ea42ec6f4f..c4f41c1067 100644 --- a/components/cli/cli/command/config/testdata/config-inspect-without-format.single-config.golden +++ b/components/cli/cli/command/config/testdata/config-inspect-without-format.single-config.golden @@ -1,9 +1,9 @@ [ { "ID": "ID-foo", - "Version": {}, - "CreatedAt": "0001-01-01T00:00:00Z", - "UpdatedAt": "0001-01-01T00:00:00Z", + "Version": {}, + "CreatedAt": "0001-01-01T00:00:00Z", + "UpdatedAt": "0001-01-01T00:00:00Z", "Spec": { "Name": "foo", "Labels": null diff --git a/components/cli/cli/command/config/testdata/config-list-with-config-format.golden b/components/cli/cli/command/config/testdata/config-list-with-config-format.golden index 9a47538804..11c39229b8 100644 --- a/components/cli/cli/command/config/testdata/config-list-with-config-format.golden +++ b/components/cli/cli/command/config/testdata/config-list-with-config-format.golden @@ -1,2 +1,2 @@ -foo +foo bar label=label-bar diff --git a/components/cli/cli/command/config/testdata/config-list-with-format.golden b/components/cli/cli/command/config/testdata/config-list-with-format.golden index 9a47538804..11c39229b8 100644 --- a/components/cli/cli/command/config/testdata/config-list-with-format.golden +++ b/components/cli/cli/command/config/testdata/config-list-with-format.golden @@ -1,2 +1,2 @@ -foo +foo bar label=label-bar From c06d7f05e3153231be64b2ddf101dd11640be6d4 Mon Sep 17 00:00:00 2001 From: Daniel Nephin Date: Wed, 16 Aug 2017 12:19:53 -0400 Subject: [PATCH 15/47] Update image command tests to use the new golden Signed-off-by: Daniel Nephin Upstream-commit: 75f7bfedf8b856b55748b0dfe6e0f630092ca0b1 Component: cli --- components/cli/cli/command/image/build_test.go | 2 +- .../cli/cli/command/image/history_test.go | 9 +++------ .../cli/cli/command/image/import_test.go | 7 ++----- .../cli/cli/command/image/inspect_test.go | 14 +++++--------- components/cli/cli/command/image/list_test.go | 10 +++------- components/cli/cli/command/image/load_test.go | 11 ++++------- components/cli/cli/command/image/prune_test.go | 18 ++++++------------ components/cli/cli/command/image/pull_test.go | 6 ++---- .../cli/cli/command/image/remove_test.go | 12 +++++------- components/cli/cli/command/image/save_test.go | 5 ++--- 10 files changed, 33 insertions(+), 61 deletions(-) diff --git a/components/cli/cli/command/image/build_test.go b/components/cli/cli/command/image/build_test.go index c874e90965..3664b91b7c 100644 --- a/components/cli/cli/command/image/build_test.go +++ b/components/cli/cli/command/image/build_test.go @@ -73,7 +73,7 @@ func TestRunBuildDockerfileFromStdinWithCompress(t *testing.T) { // starting with `github.com/` are special-cased, and the build command attempts // to clone the remote repo. func TestRunBuildFromGitHubSpecialCase(t *testing.T) { - cmd := NewBuildCommand(&command.DockerCli{}) + cmd := NewBuildCommand(test.NewFakeCli(nil)) cmd.SetArgs([]string{"github.com/docker/no-such-repository"}) cmd.SetOutput(ioutil.Discard) err := cmd.Execute() diff --git a/components/cli/cli/command/image/history_test.go b/components/cli/cli/command/image/history_test.go index 59c79f573e..7053735aa3 100644 --- a/components/cli/cli/command/image/history_test.go +++ b/components/cli/cli/command/image/history_test.go @@ -3,14 +3,13 @@ package image import ( "fmt" "io/ioutil" - "regexp" "testing" "time" "github.com/docker/cli/cli/internal/test" "github.com/docker/docker/api/types/image" "github.com/docker/docker/pkg/testutil" - "github.com/docker/docker/pkg/testutil/golden" + "github.com/gotestyourself/gotestyourself/golden" "github.com/pkg/errors" "github.com/stretchr/testify/assert" ) @@ -96,11 +95,9 @@ func TestNewHistoryCommandSuccess(t *testing.T) { assert.NoError(t, err) actual := cli.OutBuffer().String() if tc.outputRegex == "" { - expected := string(golden.Get(t, []byte(actual), fmt.Sprintf("history-command-success.%s.golden", tc.name))[:]) - testutil.EqualNormalizedString(t, testutil.RemoveSpace, actual, expected) + golden.Assert(t, actual, fmt.Sprintf("history-command-success.%s.golden", tc.name)) } else { - match, _ := regexp.MatchString(tc.outputRegex, actual) - assert.True(t, match) + assert.Regexp(t, tc.outputRegex, actual) } } } diff --git a/components/cli/cli/command/image/import_test.go b/components/cli/cli/command/image/import_test.go index 6fda4d6cf1..87cc89693c 100644 --- a/components/cli/cli/command/image/import_test.go +++ b/components/cli/cli/command/image/import_test.go @@ -1,7 +1,6 @@ package image import ( - "bytes" "io" "io/ioutil" "strings" @@ -36,8 +35,7 @@ func TestNewImportCommandErrors(t *testing.T) { }, } for _, tc := range testCases { - buf := new(bytes.Buffer) - cmd := NewImportCommand(test.NewFakeCliWithOutput(&fakeClient{imageImportFunc: tc.imageImportFunc}, buf)) + cmd := NewImportCommand(test.NewFakeCli(&fakeClient{imageImportFunc: tc.imageImportFunc})) cmd.SetOutput(ioutil.Discard) cmd.SetArgs(tc.args) testutil.ErrorContains(t, cmd.Execute(), tc.expectedError) @@ -91,8 +89,7 @@ func TestNewImportCommandSuccess(t *testing.T) { }, } for _, tc := range testCases { - buf := new(bytes.Buffer) - cmd := NewImportCommand(test.NewFakeCliWithOutput(&fakeClient{imageImportFunc: tc.imageImportFunc}, buf)) + cmd := NewImportCommand(test.NewFakeCli(&fakeClient{imageImportFunc: tc.imageImportFunc})) cmd.SetOutput(ioutil.Discard) cmd.SetArgs(tc.args) assert.NoError(t, cmd.Execute()) diff --git a/components/cli/cli/command/image/inspect_test.go b/components/cli/cli/command/image/inspect_test.go index acf80f3782..0bcb65836c 100644 --- a/components/cli/cli/command/image/inspect_test.go +++ b/components/cli/cli/command/image/inspect_test.go @@ -1,7 +1,6 @@ package image import ( - "bytes" "fmt" "io/ioutil" "testing" @@ -9,7 +8,7 @@ import ( "github.com/docker/cli/cli/internal/test" "github.com/docker/docker/api/types" "github.com/docker/docker/pkg/testutil" - "github.com/docker/docker/pkg/testutil/golden" + "github.com/gotestyourself/gotestyourself/golden" "github.com/stretchr/testify/assert" ) @@ -26,8 +25,7 @@ func TestNewInspectCommandErrors(t *testing.T) { }, } for _, tc := range testCases { - buf := new(bytes.Buffer) - cmd := newInspectCommand(test.NewFakeCliWithOutput(&fakeClient{}, buf)) + cmd := newInspectCommand(test.NewFakeCli(&fakeClient{})) cmd.SetOutput(ioutil.Discard) cmd.SetArgs(tc.args) testutil.ErrorContains(t, cmd.Execute(), tc.expectedError) @@ -78,15 +76,13 @@ func TestNewInspectCommandSuccess(t *testing.T) { } for _, tc := range testCases { imageInspectInvocationCount = 0 - buf := new(bytes.Buffer) - cmd := newInspectCommand(test.NewFakeCliWithOutput(&fakeClient{imageInspectFunc: tc.imageInspectFunc}, buf)) + cli := test.NewFakeCli(&fakeClient{imageInspectFunc: tc.imageInspectFunc}) + cmd := newInspectCommand(cli) cmd.SetOutput(ioutil.Discard) cmd.SetArgs(tc.args) err := cmd.Execute() assert.NoError(t, err) - actual := buf.String() - expected := string(golden.Get(t, []byte(actual), fmt.Sprintf("inspect-command-success.%s.golden", tc.name))[:]) - testutil.EqualNormalizedString(t, testutil.RemoveSpace, actual, expected) + golden.Assert(t, cli.OutBuffer().String(), fmt.Sprintf("inspect-command-success.%s.golden", tc.name)) assert.Equal(t, imageInspectInvocationCount, tc.imageCount) } } diff --git a/components/cli/cli/command/image/list_test.go b/components/cli/cli/command/image/list_test.go index 5ae1e47e8d..58b7a71bdb 100644 --- a/components/cli/cli/command/image/list_test.go +++ b/components/cli/cli/command/image/list_test.go @@ -1,7 +1,6 @@ package image import ( - "bytes" "fmt" "io/ioutil" "testing" @@ -10,7 +9,7 @@ import ( "github.com/docker/cli/cli/internal/test" "github.com/docker/docker/api/types" "github.com/docker/docker/pkg/testutil" - "github.com/docker/docker/pkg/testutil/golden" + "github.com/gotestyourself/gotestyourself/golden" "github.com/pkg/errors" "github.com/stretchr/testify/assert" ) @@ -80,17 +79,14 @@ func TestNewImagesCommandSuccess(t *testing.T) { }, } for _, tc := range testCases { - buf := new(bytes.Buffer) - cli := test.NewFakeCliWithOutput(&fakeClient{imageListFunc: tc.imageListFunc}, buf) + cli := test.NewFakeCli(&fakeClient{imageListFunc: tc.imageListFunc}) cli.SetConfigFile(&configfile.ConfigFile{ImagesFormat: tc.imageFormat}) cmd := NewImagesCommand(cli) cmd.SetOutput(ioutil.Discard) cmd.SetArgs(tc.args) err := cmd.Execute() assert.NoError(t, err) - actual := buf.String() - expected := string(golden.Get(t, []byte(actual), fmt.Sprintf("list-command-success.%s.golden", tc.name))[:]) - testutil.EqualNormalizedString(t, testutil.RemoveSpace, actual, expected) + golden.Assert(t, cli.OutBuffer().String(), fmt.Sprintf("list-command-success.%s.golden", tc.name)) } } diff --git a/components/cli/cli/command/image/load_test.go b/components/cli/cli/command/image/load_test.go index 519604d096..bebe40cb07 100644 --- a/components/cli/cli/command/image/load_test.go +++ b/components/cli/cli/command/image/load_test.go @@ -1,7 +1,6 @@ package image import ( - "bytes" "fmt" "io" "io/ioutil" @@ -11,7 +10,7 @@ import ( "github.com/docker/cli/cli/internal/test" "github.com/docker/docker/api/types" "github.com/docker/docker/pkg/testutil" - "github.com/docker/docker/pkg/testutil/golden" + "github.com/gotestyourself/gotestyourself/golden" "github.com/pkg/errors" "github.com/stretchr/testify/assert" ) @@ -92,14 +91,12 @@ func TestNewLoadCommandSuccess(t *testing.T) { }, } for _, tc := range testCases { - buf := new(bytes.Buffer) - cmd := NewLoadCommand(test.NewFakeCliWithOutput(&fakeClient{imageLoadFunc: tc.imageLoadFunc}, buf)) + cli := test.NewFakeCli(&fakeClient{imageLoadFunc: tc.imageLoadFunc}) + cmd := NewLoadCommand(cli) cmd.SetOutput(ioutil.Discard) cmd.SetArgs(tc.args) err := cmd.Execute() assert.NoError(t, err) - actual := buf.String() - expected := string(golden.Get(t, []byte(actual), fmt.Sprintf("load-command-success.%s.golden", tc.name))[:]) - testutil.EqualNormalizedString(t, testutil.RemoveSpace, actual, expected) + golden.Assert(t, cli.OutBuffer().String(), fmt.Sprintf("load-command-success.%s.golden", tc.name)) } } diff --git a/components/cli/cli/command/image/prune_test.go b/components/cli/cli/command/image/prune_test.go index 7f320c7a94..b52601608f 100644 --- a/components/cli/cli/command/image/prune_test.go +++ b/components/cli/cli/command/image/prune_test.go @@ -1,7 +1,6 @@ package image import ( - "bytes" "fmt" "io/ioutil" "testing" @@ -10,7 +9,7 @@ import ( "github.com/docker/docker/api/types" "github.com/docker/docker/api/types/filters" "github.com/docker/docker/pkg/testutil" - "github.com/docker/docker/pkg/testutil/golden" + "github.com/gotestyourself/gotestyourself/golden" "github.com/pkg/errors" "github.com/stretchr/testify/assert" ) @@ -37,10 +36,9 @@ func TestNewPruneCommandErrors(t *testing.T) { }, } for _, tc := range testCases { - buf := new(bytes.Buffer) - cmd := NewPruneCommand(test.NewFakeCliWithOutput(&fakeClient{ + cmd := NewPruneCommand(test.NewFakeCli(&fakeClient{ imagesPruneFunc: tc.imagesPruneFunc, - }, buf)) + })) cmd.SetOutput(ioutil.Discard) cmd.SetArgs(tc.args) testutil.ErrorContains(t, cmd.Execute(), tc.expectedError) @@ -85,16 +83,12 @@ func TestNewPruneCommandSuccess(t *testing.T) { }, } for _, tc := range testCases { - buf := new(bytes.Buffer) - cmd := NewPruneCommand(test.NewFakeCliWithOutput(&fakeClient{ - imagesPruneFunc: tc.imagesPruneFunc, - }, buf)) + cli := test.NewFakeCli(&fakeClient{imagesPruneFunc: tc.imagesPruneFunc}) + cmd := NewPruneCommand(cli) cmd.SetOutput(ioutil.Discard) cmd.SetArgs(tc.args) err := cmd.Execute() assert.NoError(t, err) - actual := buf.String() - expected := string(golden.Get(t, []byte(actual), fmt.Sprintf("prune-command-success.%s.golden", tc.name))[:]) - testutil.EqualNormalizedString(t, testutil.RemoveSpace, actual, expected) + golden.Assert(t, cli.OutBuffer().String(), fmt.Sprintf("prune-command-success.%s.golden", tc.name)) } } diff --git a/components/cli/cli/command/image/pull_test.go b/components/cli/cli/command/image/pull_test.go index 71d258323a..7b24cdbb08 100644 --- a/components/cli/cli/command/image/pull_test.go +++ b/components/cli/cli/command/image/pull_test.go @@ -7,7 +7,7 @@ import ( "github.com/docker/cli/cli/internal/test" "github.com/docker/docker/pkg/testutil" - "github.com/docker/docker/pkg/testutil/golden" + "github.com/gotestyourself/gotestyourself/golden" "github.com/stretchr/testify/assert" ) @@ -68,8 +68,6 @@ func TestNewPullCommandSuccess(t *testing.T) { cmd.SetArgs(tc.args) err := cmd.Execute() assert.NoError(t, err) - actual := cli.OutBuffer().String() - expected := string(golden.Get(t, []byte(actual), fmt.Sprintf("pull-command-success.%s.golden", tc.name))[:]) - testutil.EqualNormalizedString(t, testutil.RemoveSpace, actual, expected) + golden.Assert(t, cli.OutBuffer().String(), fmt.Sprintf("pull-command-success.%s.golden", tc.name)) } } diff --git a/components/cli/cli/command/image/remove_test.go b/components/cli/cli/command/image/remove_test.go index f88bc88520..a813f8f107 100644 --- a/components/cli/cli/command/image/remove_test.go +++ b/components/cli/cli/command/image/remove_test.go @@ -8,7 +8,7 @@ import ( "github.com/docker/cli/cli/internal/test" "github.com/docker/docker/api/types" "github.com/docker/docker/pkg/testutil" - "github.com/docker/docker/pkg/testutil/golden" + "github.com/gotestyourself/gotestyourself/golden" "github.com/pkg/errors" "github.com/stretchr/testify/assert" ) @@ -96,16 +96,14 @@ func TestNewRemoveCommandSuccess(t *testing.T) { }, } for _, tc := range testCases { - fakeCli := test.NewFakeCli(&fakeClient{imageRemoveFunc: tc.imageRemoveFunc}) - cmd := NewRemoveCommand(fakeCli) + cli := test.NewFakeCli(&fakeClient{imageRemoveFunc: tc.imageRemoveFunc}) + cmd := NewRemoveCommand(cli) cmd.SetOutput(ioutil.Discard) cmd.SetArgs(tc.args) assert.NoError(t, cmd.Execute()) if tc.expectedErrMsg != "" { - assert.Equal(t, tc.expectedErrMsg, fakeCli.ErrBuffer().String()) + assert.Equal(t, tc.expectedErrMsg, cli.ErrBuffer().String()) } - actual := fakeCli.OutBuffer().String() - expected := string(golden.Get(t, []byte(actual), fmt.Sprintf("remove-command-success.%s.golden", tc.name))[:]) - testutil.EqualNormalizedString(t, testutil.RemoveSpace, actual, expected) + golden.Assert(t, cli.OutBuffer().String(), fmt.Sprintf("remove-command-success.%s.golden", tc.name)) } } diff --git a/components/cli/cli/command/image/save_test.go b/components/cli/cli/command/image/save_test.go index 84dee142d8..424c2c9a42 100644 --- a/components/cli/cli/command/image/save_test.go +++ b/components/cli/cli/command/image/save_test.go @@ -1,7 +1,6 @@ package image import ( - "bytes" "io" "io/ioutil" "os" @@ -90,11 +89,11 @@ func TestNewSaveCommandSuccess(t *testing.T) { }, } for _, tc := range testCases { - cmd := NewSaveCommand(test.NewFakeCliWithOutput(&fakeClient{ + cmd := NewSaveCommand(test.NewFakeCli(&fakeClient{ imageSaveFunc: func(images []string) (io.ReadCloser, error) { return ioutil.NopCloser(strings.NewReader("")), nil }, - }, new(bytes.Buffer))) + })) cmd.SetOutput(ioutil.Discard) cmd.SetArgs(tc.args) assert.NoError(t, cmd.Execute()) From 79c79c9b8ff854a507a492974fce3bbf5eb07f27 Mon Sep 17 00:00:00 2001 From: Daniel Nephin Date: Wed, 16 Aug 2017 12:42:19 -0400 Subject: [PATCH 16/47] Update node command tests to the new golden Also remove some superfluous tests that are now covered by a strict golden.Assert Signed-off-by: Daniel Nephin Upstream-commit: 0e2bf7420aba3ad77397f0c7f1c3f78bbd2021ae Component: cli --- .../cli/cli/command/node/inspect_test.go | 21 +++--- components/cli/cli/command/node/list_test.go | 71 +++++-------------- .../cli/cli/command/node/promote_test.go | 16 ++--- components/cli/cli/command/node/ps_test.go | 38 +++++----- .../cli/cli/command/node/remove_test.go | 9 +-- .../node-inspect-pretty.manager-leader.golden | 15 ++-- .../node-inspect-pretty.manager.golden | 15 ++-- .../node-inspect-pretty.simple.golden | 17 +++-- .../testdata/node-list-format-flag.golden | 2 + .../node-list-format-from-config.golden | 3 + .../node/testdata/node-list-sort.golden | 7 +- .../node/testdata/node-ps.simple.golden | 4 +- .../node/testdata/node-ps.with-errors.golden | 8 +-- 13 files changed, 86 insertions(+), 140 deletions(-) create mode 100644 components/cli/cli/command/node/testdata/node-list-format-flag.golden create mode 100644 components/cli/cli/command/node/testdata/node-list-format-from-config.golden diff --git a/components/cli/cli/command/node/inspect_test.go b/components/cli/cli/command/node/inspect_test.go index ca88371f8a..b841b0639d 100644 --- a/components/cli/cli/command/node/inspect_test.go +++ b/components/cli/cli/command/node/inspect_test.go @@ -1,7 +1,6 @@ package node import ( - "bytes" "fmt" "io/ioutil" "testing" @@ -13,7 +12,7 @@ import ( // Import builders to get the builder function as package function . "github.com/docker/cli/cli/internal/test/builders" "github.com/docker/docker/pkg/testutil" - "github.com/docker/docker/pkg/testutil/golden" + "github.com/gotestyourself/gotestyourself/golden" "github.com/stretchr/testify/assert" ) @@ -67,12 +66,11 @@ func TestNodeInspectErrors(t *testing.T) { }, } for _, tc := range testCases { - buf := new(bytes.Buffer) cmd := newInspectCommand( - test.NewFakeCliWithOutput(&fakeClient{ + test.NewFakeCli(&fakeClient{ nodeInspectFunc: tc.nodeInspectFunc, infoFunc: tc.infoFunc, - }, buf)) + })) cmd.SetArgs(tc.args) for key, value := range tc.flags { cmd.Flags().Set(key, value) @@ -109,16 +107,13 @@ func TestNodeInspectPretty(t *testing.T) { }, } for _, tc := range testCases { - buf := new(bytes.Buffer) - cmd := newInspectCommand( - test.NewFakeCliWithOutput(&fakeClient{ - nodeInspectFunc: tc.nodeInspectFunc, - }, buf)) + cli := test.NewFakeCli(&fakeClient{ + nodeInspectFunc: tc.nodeInspectFunc, + }) + cmd := newInspectCommand(cli) cmd.SetArgs([]string{"nodeID"}) cmd.Flags().Set("pretty", "true") assert.NoError(t, cmd.Execute()) - actual := buf.String() - expected := golden.Get(t, []byte(actual), fmt.Sprintf("node-inspect-pretty.%s.golden", tc.name)) - testutil.EqualNormalizedString(t, testutil.RemoveSpace, actual, string(expected)) + golden.Assert(t, cli.OutBuffer().String(), fmt.Sprintf("node-inspect-pretty.%s.golden", tc.name)) } } diff --git a/components/cli/cli/command/node/list_test.go b/components/cli/cli/command/node/list_test.go index f579ebc88a..fee29e284b 100644 --- a/components/cli/cli/command/node/list_test.go +++ b/components/cli/cli/command/node/list_test.go @@ -1,7 +1,6 @@ package node import ( - "bytes" "io/ioutil" "testing" @@ -9,8 +8,7 @@ import ( "github.com/docker/cli/cli/internal/test" "github.com/docker/docker/api/types" "github.com/docker/docker/api/types/swarm" - "github.com/docker/docker/pkg/testutil" - "github.com/docker/docker/pkg/testutil/golden" + "github.com/gotestyourself/gotestyourself/golden" "github.com/pkg/errors" // Import builders to get the builder function as package function . "github.com/docker/cli/cli/internal/test/builders" @@ -58,9 +56,9 @@ func TestNodeList(t *testing.T) { cli := test.NewFakeCli(&fakeClient{ nodeListFunc: func() ([]swarm.Node, error) { return []swarm.Node{ - *Node(NodeID("nodeID1"), Hostname("nodeHostname1"), Manager(Leader())), - *Node(NodeID("nodeID2"), Hostname("nodeHostname2"), Manager()), - *Node(NodeID("nodeID3"), Hostname("nodeHostname3")), + *Node(NodeID("nodeID1"), Hostname("node-2-foo"), Manager(Leader())), + *Node(NodeID("nodeID2"), Hostname("node-10-foo"), Manager()), + *Node(NodeID("nodeID3"), Hostname("node-1-foo")), }, nil }, infoFunc: func() (types.Info, error) { @@ -74,39 +72,25 @@ func TestNodeList(t *testing.T) { cmd := newListCommand(cli) assert.NoError(t, cmd.Execute()) - out := cli.OutBuffer().String() - assert.Contains(t, out, `nodeID1 * nodeHostname1 Ready Active Leader`) - assert.Contains(t, out, `nodeID2 nodeHostname2 Ready Active Reachable`) - assert.Contains(t, out, `nodeID3 nodeHostname3 Ready Active`) + golden.Assert(t, cli.OutBuffer().String(), "node-list-sort.golden") } func TestNodeListQuietShouldOnlyPrintIDs(t *testing.T) { - buf := new(bytes.Buffer) - cli := test.NewFakeCliWithOutput(&fakeClient{ + cli := test.NewFakeCli(&fakeClient{ nodeListFunc: func() ([]swarm.Node, error) { return []swarm.Node{ - *Node(), + *Node(NodeID("nodeID1")), }, nil }, - }, buf) + }) cmd := newListCommand(cli) cmd.Flags().Set("quiet", "true") assert.NoError(t, cmd.Execute()) - assert.Contains(t, buf.String(), "nodeID") + assert.Equal(t, cli.OutBuffer().String(), "nodeID1\n") } -// Test case for #24090 -func TestNodeListContainsHostname(t *testing.T) { - buf := new(bytes.Buffer) - cli := test.NewFakeCliWithOutput(&fakeClient{}, buf) - cmd := newListCommand(cli) - assert.NoError(t, cmd.Execute()) - assert.Contains(t, buf.String(), "HOSTNAME") -} - -func TestNodeListDefaultFormat(t *testing.T) { - buf := new(bytes.Buffer) - cli := test.NewFakeCliWithOutput(&fakeClient{ +func TestNodeListDefaultFormatFromConfig(t *testing.T) { + cli := test.NewFakeCli(&fakeClient{ nodeListFunc: func() ([]swarm.Node, error) { return []swarm.Node{ *Node(NodeID("nodeID1"), Hostname("nodeHostname1"), Manager(Leader())), @@ -121,20 +105,17 @@ func TestNodeListDefaultFormat(t *testing.T) { }, }, nil }, - }, buf) + }) cli.SetConfigFile(&configfile.ConfigFile{ NodesFormat: "{{.ID}}: {{.Hostname}} {{.Status}}/{{.ManagerStatus}}", }) cmd := newListCommand(cli) assert.NoError(t, cmd.Execute()) - assert.Contains(t, buf.String(), `nodeID1: nodeHostname1 Ready/Leader`) - assert.Contains(t, buf.String(), `nodeID2: nodeHostname2 Ready/Reachable`) - assert.Contains(t, buf.String(), `nodeID3: nodeHostname3 Ready`) + golden.Assert(t, cli.OutBuffer().String(), "node-list-format-from-config.golden") } func TestNodeListFormat(t *testing.T) { - buf := new(bytes.Buffer) - cli := test.NewFakeCliWithOutput(&fakeClient{ + cli := test.NewFakeCli(&fakeClient{ nodeListFunc: func() ([]swarm.Node, error) { return []swarm.Node{ *Node(NodeID("nodeID1"), Hostname("nodeHostname1"), Manager(Leader())), @@ -148,32 +129,12 @@ func TestNodeListFormat(t *testing.T) { }, }, nil }, - }, buf) + }) cli.SetConfigFile(&configfile.ConfigFile{ NodesFormat: "{{.ID}}: {{.Hostname}} {{.Status}}/{{.ManagerStatus}}", }) cmd := newListCommand(cli) cmd.Flags().Set("format", "{{.Hostname}}: {{.ManagerStatus}}") assert.NoError(t, cmd.Execute()) - assert.Contains(t, buf.String(), `nodeHostname1: Leader`) - assert.Contains(t, buf.String(), `nodeHostname2: Reachable`) -} - -func TestNodeListOrder(t *testing.T) { - cli := test.NewFakeCli(&fakeClient{ - nodeListFunc: func() ([]swarm.Node, error) { - return []swarm.Node{ - *Node(Hostname("node-2-foo"), Manager(Leader())), - *Node(Hostname("node-10-foo"), Manager()), - *Node(Hostname("node-1-foo")), - }, nil - - }, - }) - cmd := newListCommand(cli) - cmd.Flags().Set("format", "{{.Hostname}}: {{.ManagerStatus}}") - assert.NoError(t, cmd.Execute()) - actual := cli.OutBuffer().String() - expected := golden.Get(t, []byte(actual), "node-list-sort.golden") - testutil.EqualNormalizedString(t, testutil.RemoveSpace, actual, string(expected)) + golden.Assert(t, cli.OutBuffer().String(), "node-list-format-flag.golden") } diff --git a/components/cli/cli/command/node/promote_test.go b/components/cli/cli/command/node/promote_test.go index 95e067eb15..2399b2ee8c 100644 --- a/components/cli/cli/command/node/promote_test.go +++ b/components/cli/cli/command/node/promote_test.go @@ -1,7 +1,6 @@ package node import ( - "bytes" "io/ioutil" "testing" @@ -40,12 +39,11 @@ func TestNodePromoteErrors(t *testing.T) { }, } for _, tc := range testCases { - buf := new(bytes.Buffer) cmd := newPromoteCommand( - test.NewFakeCliWithOutput(&fakeClient{ + test.NewFakeCli(&fakeClient{ nodeInspectFunc: tc.nodeInspectFunc, nodeUpdateFunc: tc.nodeUpdateFunc, - }, buf)) + })) cmd.SetArgs(tc.args) cmd.SetOutput(ioutil.Discard) testutil.ErrorContains(t, cmd.Execute(), tc.expectedError) @@ -53,9 +51,8 @@ func TestNodePromoteErrors(t *testing.T) { } func TestNodePromoteNoChange(t *testing.T) { - buf := new(bytes.Buffer) cmd := newPromoteCommand( - test.NewFakeCliWithOutput(&fakeClient{ + test.NewFakeCli(&fakeClient{ nodeInspectFunc: func() (swarm.Node, []byte, error) { return *Node(Manager()), []byte{}, nil }, @@ -65,15 +62,14 @@ func TestNodePromoteNoChange(t *testing.T) { } return nil }, - }, buf)) + })) cmd.SetArgs([]string{"nodeID"}) assert.NoError(t, cmd.Execute()) } func TestNodePromoteMultipleNode(t *testing.T) { - buf := new(bytes.Buffer) cmd := newPromoteCommand( - test.NewFakeCliWithOutput(&fakeClient{ + test.NewFakeCli(&fakeClient{ nodeInspectFunc: func() (swarm.Node, []byte, error) { return *Node(), []byte{}, nil }, @@ -83,7 +79,7 @@ func TestNodePromoteMultipleNode(t *testing.T) { } return nil }, - }, buf)) + })) cmd.SetArgs([]string{"nodeID1", "nodeID2"}) assert.NoError(t, cmd.Execute()) } diff --git a/components/cli/cli/command/node/ps_test.go b/components/cli/cli/command/node/ps_test.go index d3ef6f30a2..8733e5e0f4 100644 --- a/components/cli/cli/command/node/ps_test.go +++ b/components/cli/cli/command/node/ps_test.go @@ -1,7 +1,6 @@ package node import ( - "bytes" "fmt" "io/ioutil" "testing" @@ -13,8 +12,7 @@ import ( "github.com/pkg/errors" // Import builders to get the builder function as package function . "github.com/docker/cli/cli/internal/test/builders" - "github.com/docker/docker/pkg/testutil" - "github.com/docker/docker/pkg/testutil/golden" + "github.com/gotestyourself/gotestyourself/golden" "github.com/stretchr/testify/assert" ) @@ -50,14 +48,13 @@ func TestNodePsErrors(t *testing.T) { }, } for _, tc := range testCases { - buf := new(bytes.Buffer) - cmd := newPsCommand( - test.NewFakeCliWithOutput(&fakeClient{ - infoFunc: tc.infoFunc, - nodeInspectFunc: tc.nodeInspectFunc, - taskInspectFunc: tc.taskInspectFunc, - taskListFunc: tc.taskListFunc, - }, buf)) + cli := test.NewFakeCli(&fakeClient{ + infoFunc: tc.infoFunc, + nodeInspectFunc: tc.nodeInspectFunc, + taskInspectFunc: tc.taskInspectFunc, + taskListFunc: tc.taskListFunc, + }) + cmd := newPsCommand(cli) cmd.SetArgs(tc.args) for key, value := range tc.flags { cmd.Flags().Set(key, value) @@ -114,21 +111,18 @@ func TestNodePs(t *testing.T) { }, } for _, tc := range testCases { - buf := new(bytes.Buffer) - cmd := newPsCommand( - test.NewFakeCliWithOutput(&fakeClient{ - infoFunc: tc.infoFunc, - nodeInspectFunc: tc.nodeInspectFunc, - taskInspectFunc: tc.taskInspectFunc, - taskListFunc: tc.taskListFunc, - }, buf)) + cli := test.NewFakeCli(&fakeClient{ + infoFunc: tc.infoFunc, + nodeInspectFunc: tc.nodeInspectFunc, + taskInspectFunc: tc.taskInspectFunc, + taskListFunc: tc.taskListFunc, + }) + cmd := newPsCommand(cli) cmd.SetArgs(tc.args) for key, value := range tc.flags { cmd.Flags().Set(key, value) } assert.NoError(t, cmd.Execute()) - actual := buf.String() - expected := golden.Get(t, []byte(actual), fmt.Sprintf("node-ps.%s.golden", tc.name)) - testutil.EqualNormalizedString(t, testutil.RemoveSpace, actual, string(expected)) + golden.Assert(t, cli.OutBuffer().String(), fmt.Sprintf("node-ps.%s.golden", tc.name)) } } diff --git a/components/cli/cli/command/node/remove_test.go b/components/cli/cli/command/node/remove_test.go index 81daa2f025..e0f3f238e6 100644 --- a/components/cli/cli/command/node/remove_test.go +++ b/components/cli/cli/command/node/remove_test.go @@ -1,7 +1,6 @@ package node import ( - "bytes" "io/ioutil" "testing" @@ -29,11 +28,10 @@ func TestNodeRemoveErrors(t *testing.T) { }, } for _, tc := range testCases { - buf := new(bytes.Buffer) cmd := newRemoveCommand( - test.NewFakeCliWithOutput(&fakeClient{ + test.NewFakeCli(&fakeClient{ nodeRemoveFunc: tc.nodeRemoveFunc, - }, buf)) + })) cmd.SetArgs(tc.args) cmd.SetOutput(ioutil.Discard) testutil.ErrorContains(t, cmd.Execute(), tc.expectedError) @@ -41,8 +39,7 @@ func TestNodeRemoveErrors(t *testing.T) { } func TestNodeRemoveMultiple(t *testing.T) { - buf := new(bytes.Buffer) - cmd := newRemoveCommand(test.NewFakeCliWithOutput(&fakeClient{}, buf)) + cmd := newRemoveCommand(test.NewFakeCli(&fakeClient{})) cmd.SetArgs([]string{"nodeID1", "nodeID2"}) assert.NoError(t, cmd.Execute()) } diff --git a/components/cli/cli/command/node/testdata/node-inspect-pretty.manager-leader.golden b/components/cli/cli/command/node/testdata/node-inspect-pretty.manager-leader.golden index 461fc46ea2..5cd95c5b91 100644 --- a/components/cli/cli/command/node/testdata/node-inspect-pretty.manager-leader.golden +++ b/components/cli/cli/command/node/testdata/node-inspect-pretty.manager-leader.golden @@ -1,10 +1,10 @@ ID: nodeID Name: defaultNodeName -Hostname: defaultNodeHostname -Joined at: 2009-11-10 23:00:00 +0000 utc +Hostname: defaultNodeHostname +Joined at: 2009-11-10 23:00:00 +0000 utc Status: State: Ready - Availability: Active + Availability: Active Address: 127.0.0.1 Manager Status: Address: 127.0.0.1 @@ -15,11 +15,10 @@ Platform: Architecture: x86_64 Resources: CPUs: 0 - Memory: 20 MiB + Memory: 20MiB Plugins: - Network: bridge, overlay - Volume: local + Network: bridge, overlay + Volume: local Engine Version: 1.13.0 Engine Labels: - - engine = label - + - engine=label diff --git a/components/cli/cli/command/node/testdata/node-inspect-pretty.manager.golden b/components/cli/cli/command/node/testdata/node-inspect-pretty.manager.golden index 2c660188d5..a63718293c 100644 --- a/components/cli/cli/command/node/testdata/node-inspect-pretty.manager.golden +++ b/components/cli/cli/command/node/testdata/node-inspect-pretty.manager.golden @@ -1,10 +1,10 @@ ID: nodeID Name: defaultNodeName -Hostname: defaultNodeHostname -Joined at: 2009-11-10 23:00:00 +0000 utc +Hostname: defaultNodeHostname +Joined at: 2009-11-10 23:00:00 +0000 utc Status: State: Ready - Availability: Active + Availability: Active Address: 127.0.0.1 Manager Status: Address: 127.0.0.1 @@ -15,11 +15,10 @@ Platform: Architecture: x86_64 Resources: CPUs: 0 - Memory: 20 MiB + Memory: 20MiB Plugins: - Network: bridge, overlay - Volume: local + Network: bridge, overlay + Volume: local Engine Version: 1.13.0 Engine Labels: - - engine = label - + - engine=label diff --git a/components/cli/cli/command/node/testdata/node-inspect-pretty.simple.golden b/components/cli/cli/command/node/testdata/node-inspect-pretty.simple.golden index e63bc12596..8aaf90899e 100644 --- a/components/cli/cli/command/node/testdata/node-inspect-pretty.simple.golden +++ b/components/cli/cli/command/node/testdata/node-inspect-pretty.simple.golden @@ -1,23 +1,22 @@ ID: nodeID Name: defaultNodeName Labels: - - lbl1 = value1 -Hostname: defaultNodeHostname -Joined at: 2009-11-10 23:00:00 +0000 utc + - lbl1=value1 +Hostname: defaultNodeHostname +Joined at: 2009-11-10 23:00:00 +0000 utc Status: State: Ready - Availability: Active + Availability: Active Address: 127.0.0.1 Platform: Operating System: linux Architecture: x86_64 Resources: CPUs: 0 - Memory: 20 MiB + Memory: 20MiB Plugins: - Network: bridge, overlay - Volume: local + Network: bridge, overlay + Volume: local Engine Version: 1.13.0 Engine Labels: - - engine = label - + - engine=label diff --git a/components/cli/cli/command/node/testdata/node-list-format-flag.golden b/components/cli/cli/command/node/testdata/node-list-format-flag.golden new file mode 100644 index 0000000000..c898df13e6 --- /dev/null +++ b/components/cli/cli/command/node/testdata/node-list-format-flag.golden @@ -0,0 +1,2 @@ +nodeHostname1: Leader +nodeHostname2: Reachable diff --git a/components/cli/cli/command/node/testdata/node-list-format-from-config.golden b/components/cli/cli/command/node/testdata/node-list-format-from-config.golden new file mode 100644 index 0000000000..91beb4a29b --- /dev/null +++ b/components/cli/cli/command/node/testdata/node-list-format-from-config.golden @@ -0,0 +1,3 @@ +nodeID1: nodeHostname1 Ready/Leader +nodeID2: nodeHostname2 Ready/Reachable +nodeID3: nodeHostname3 Ready/ diff --git a/components/cli/cli/command/node/testdata/node-list-sort.golden b/components/cli/cli/command/node/testdata/node-list-sort.golden index e2f2811994..ad8c34a813 100644 --- a/components/cli/cli/command/node/testdata/node-list-sort.golden +++ b/components/cli/cli/command/node/testdata/node-list-sort.golden @@ -1,3 +1,4 @@ -node-1-foo: -node-2-foo: Leader -node-10-foo: Reachable +ID HOSTNAME STATUS AVAILABILITY MANAGER STATUS +nodeID3 node-1-foo Ready Active +nodeID1 * node-2-foo Ready Active Leader +nodeID2 node-10-foo Ready Active Reachable diff --git a/components/cli/cli/command/node/testdata/node-ps.simple.golden b/components/cli/cli/command/node/testdata/node-ps.simple.golden index f9555d8792..b1818b96b4 100644 --- a/components/cli/cli/command/node/testdata/node-ps.simple.golden +++ b/components/cli/cli/command/node/testdata/node-ps.simple.golden @@ -1,2 +1,2 @@ -ID NAME IMAGE NODE DESIRED STATE CURRENT STATE ERROR PORTS -taskID rl02d5gwz6chzu7il5fhtb8be.1 myimage:mytag defaultNodeName Ready Ready 2 hours ago *:80->80/tcp +ID NAME IMAGE NODE DESIRED STATE CURRENT STATE ERROR PORTS +taskID rl02d5gwz6chzu7il5fhtb8be.1 myimage:mytag defaultNodeName Ready Ready 2 hours ago *:80->80/tcp diff --git a/components/cli/cli/command/node/testdata/node-ps.with-errors.golden b/components/cli/cli/command/node/testdata/node-ps.with-errors.golden index 273b30fa11..99e34931a6 100644 --- a/components/cli/cli/command/node/testdata/node-ps.with-errors.golden +++ b/components/cli/cli/command/node/testdata/node-ps.with-errors.golden @@ -1,4 +1,4 @@ -ID NAME IMAGE NODE DESIRED STATE CURRENT STATE ERROR PORTS -taskID1 failure.1 myimage:mytag defaultNodeName Ready Ready 2 hours ago "a task error" -taskID2 \_ failure.1 myimage:mytag defaultNodeName Ready Ready 3 hours ago "a task error" -taskID3 \_ failure.1 myimage:mytag defaultNodeName Ready Ready 4 hours ago "a task error" +ID NAME IMAGE NODE DESIRED STATE CURRENT STATE ERROR PORTS +taskID1 failure.1 myimage:mytag defaultNodeName Ready Ready 2 hours ago "a task error" +taskID2 \_ failure.1 myimage:mytag defaultNodeName Ready Ready 3 hours ago "a task error" +taskID3 \_ failure.1 myimage:mytag defaultNodeName Ready Ready 4 hours ago "a task error" From 2c6a1a2476862d814e1e4b30765ad13aef0d0fcd Mon Sep 17 00:00:00 2001 From: Daniel Nephin Date: Wed, 16 Aug 2017 12:53:41 -0400 Subject: [PATCH 17/47] Update service and secret command tests to new golden Signed-off-by: Daniel Nephin Upstream-commit: 4c62d7288f50bad15674431944cd1b6a5bc3fb8c Component: cli --- .../cli/cli/command/secret/create_test.go | 20 +++----- .../cli/cli/command/secret/inspect_test.go | 49 +++++++----------- components/cli/cli/command/secret/ls_test.go | 51 +++++++------------ .../cli/cli/command/secret/remove_test.go | 18 +++---- .../secret-inspect-pretty.simple.golden | 10 ++-- ...format.multiple-secrets-with-labels.golden | 4 +- ...nspect-without-format.single-secret.golden | 6 +-- .../secret-list-with-config-format.golden | 2 +- .../testdata/secret-list-with-format.golden | 2 +- .../cli/cli/command/service/list_test.go | 10 ++-- components/cli/cli/command/service/ps_test.go | 5 +- 11 files changed, 67 insertions(+), 110 deletions(-) diff --git a/components/cli/cli/command/secret/create_test.go b/components/cli/cli/command/secret/create_test.go index 592ede0fe5..0887601ab6 100644 --- a/components/cli/cli/command/secret/create_test.go +++ b/components/cli/cli/command/secret/create_test.go @@ -1,7 +1,6 @@ package secret import ( - "bytes" "io/ioutil" "path/filepath" "reflect" @@ -12,7 +11,7 @@ import ( "github.com/docker/docker/api/types" "github.com/docker/docker/api/types/swarm" "github.com/docker/docker/pkg/testutil" - "github.com/docker/docker/pkg/testutil/golden" + "github.com/gotestyourself/gotestyourself/golden" "github.com/pkg/errors" "github.com/stretchr/testify/assert" ) @@ -54,9 +53,8 @@ func TestSecretCreateErrors(t *testing.T) { func TestSecretCreateWithName(t *testing.T) { name := "foo" - buf := new(bytes.Buffer) var actual []byte - cli := test.NewFakeCliWithOutput(&fakeClient{ + cli := test.NewFakeCli(&fakeClient{ secretCreateFunc: func(spec swarm.SecretSpec) (types.SecretCreateResponse, error) { if spec.Name != name { return types.SecretCreateResponse{}, errors.Errorf("expected name %q, got %q", name, spec.Name) @@ -68,14 +66,13 @@ func TestSecretCreateWithName(t *testing.T) { ID: "ID-" + spec.Name, }, nil }, - }, buf) + }) cmd := newSecretCreateCommand(cli) cmd.SetArgs([]string{name, filepath.Join("testdata", secretDataFile)}) assert.NoError(t, cmd.Execute()) - expected := golden.Get(t, actual, secretDataFile) - assert.Equal(t, expected, actual) - assert.Equal(t, "ID-"+name, strings.TrimSpace(buf.String())) + golden.Assert(t, string(actual), secretDataFile) + assert.Equal(t, "ID-"+name, strings.TrimSpace(cli.OutBuffer().String())) } func TestSecretCreateWithLabels(t *testing.T) { @@ -85,8 +82,7 @@ func TestSecretCreateWithLabels(t *testing.T) { } name := "foo" - buf := new(bytes.Buffer) - cli := test.NewFakeCliWithOutput(&fakeClient{ + cli := test.NewFakeCli(&fakeClient{ secretCreateFunc: func(spec swarm.SecretSpec) (types.SecretCreateResponse, error) { if spec.Name != name { return types.SecretCreateResponse{}, errors.Errorf("expected name %q, got %q", name, spec.Name) @@ -100,12 +96,12 @@ func TestSecretCreateWithLabels(t *testing.T) { ID: "ID-" + spec.Name, }, nil }, - }, buf) + }) cmd := newSecretCreateCommand(cli) cmd.SetArgs([]string{name, filepath.Join("testdata", secretDataFile)}) cmd.Flags().Set("label", "lbl1=Label-foo") cmd.Flags().Set("label", "lbl2=Label-bar") assert.NoError(t, cmd.Execute()) - assert.Equal(t, "ID-"+name, strings.TrimSpace(buf.String())) + assert.Equal(t, "ID-"+name, strings.TrimSpace(cli.OutBuffer().String())) } diff --git a/components/cli/cli/command/secret/inspect_test.go b/components/cli/cli/command/secret/inspect_test.go index 093624ddfe..eef789d80b 100644 --- a/components/cli/cli/command/secret/inspect_test.go +++ b/components/cli/cli/command/secret/inspect_test.go @@ -1,7 +1,6 @@ package secret import ( - "bytes" "fmt" "io/ioutil" "testing" @@ -13,7 +12,7 @@ import ( // Import builders to get the builder function as package function . "github.com/docker/cli/cli/internal/test/builders" "github.com/docker/docker/pkg/testutil" - "github.com/docker/docker/pkg/testutil/golden" + "github.com/gotestyourself/gotestyourself/golden" "github.com/stretchr/testify/assert" ) @@ -53,11 +52,10 @@ func TestSecretInspectErrors(t *testing.T) { }, } for _, tc := range testCases { - buf := new(bytes.Buffer) cmd := newSecretInspectCommand( - test.NewFakeCliWithOutput(&fakeClient{ + test.NewFakeCli(&fakeClient{ secretInspectFunc: tc.secretInspectFunc, - }, buf), + }), ) cmd.SetArgs(tc.args) for key, value := range tc.flags { @@ -95,17 +93,13 @@ func TestSecretInspectWithoutFormat(t *testing.T) { }, } for _, tc := range testCases { - buf := new(bytes.Buffer) - cmd := newSecretInspectCommand( - test.NewFakeCliWithOutput(&fakeClient{ - secretInspectFunc: tc.secretInspectFunc, - }, buf), - ) + cli := test.NewFakeCli(&fakeClient{ + secretInspectFunc: tc.secretInspectFunc, + }) + cmd := newSecretInspectCommand(cli) cmd.SetArgs(tc.args) assert.NoError(t, cmd.Execute()) - actual := buf.String() - expected := golden.Get(t, []byte(actual), fmt.Sprintf("secret-inspect-without-format.%s.golden", tc.name)) - testutil.EqualNormalizedString(t, testutil.RemoveSpace, actual, string(expected)) + golden.Assert(t, cli.OutBuffer().String(), fmt.Sprintf("secret-inspect-without-format.%s.golden", tc.name)) } } @@ -135,18 +129,14 @@ func TestSecretInspectWithFormat(t *testing.T) { }, } for _, tc := range testCases { - buf := new(bytes.Buffer) - cmd := newSecretInspectCommand( - test.NewFakeCliWithOutput(&fakeClient{ - secretInspectFunc: tc.secretInspectFunc, - }, buf), - ) + cli := test.NewFakeCli(&fakeClient{ + secretInspectFunc: tc.secretInspectFunc, + }) + cmd := newSecretInspectCommand(cli) cmd.SetArgs(tc.args) cmd.Flags().Set("format", tc.format) assert.NoError(t, cmd.Execute()) - actual := buf.String() - expected := golden.Get(t, []byte(actual), fmt.Sprintf("secret-inspect-with-format.%s.golden", tc.name)) - testutil.EqualNormalizedString(t, testutil.RemoveSpace, actual, string(expected)) + golden.Assert(t, cli.OutBuffer().String(), fmt.Sprintf("secret-inspect-with-format.%s.golden", tc.name)) } } @@ -171,16 +161,13 @@ func TestSecretInspectPretty(t *testing.T) { }, } for _, tc := range testCases { - buf := new(bytes.Buffer) - cmd := newSecretInspectCommand( - test.NewFakeCliWithOutput(&fakeClient{ - secretInspectFunc: tc.secretInspectFunc, - }, buf)) + cli := test.NewFakeCli(&fakeClient{ + secretInspectFunc: tc.secretInspectFunc, + }) + cmd := newSecretInspectCommand(cli) cmd.SetArgs([]string{"secretID"}) cmd.Flags().Set("pretty", "true") assert.NoError(t, cmd.Execute()) - actual := buf.String() - expected := golden.Get(t, []byte(actual), fmt.Sprintf("secret-inspect-pretty.%s.golden", tc.name)) - testutil.EqualNormalizedString(t, testutil.RemoveSpace, actual, string(expected)) + golden.Assert(t, cli.OutBuffer().String(), fmt.Sprintf("secret-inspect-pretty.%s.golden", tc.name)) } } diff --git a/components/cli/cli/command/secret/ls_test.go b/components/cli/cli/command/secret/ls_test.go index fb033efea6..cced136106 100644 --- a/components/cli/cli/command/secret/ls_test.go +++ b/components/cli/cli/command/secret/ls_test.go @@ -14,7 +14,7 @@ import ( // Import builders to get the builder function as package function . "github.com/docker/cli/cli/internal/test/builders" "github.com/docker/docker/pkg/testutil" - "github.com/docker/docker/pkg/testutil/golden" + "github.com/gotestyourself/gotestyourself/golden" "github.com/stretchr/testify/assert" ) @@ -36,11 +36,10 @@ func TestSecretListErrors(t *testing.T) { }, } for _, tc := range testCases { - buf := new(bytes.Buffer) cmd := newSecretListCommand( - test.NewFakeCliWithOutput(&fakeClient{ + test.NewFakeCli(&fakeClient{ secretListFunc: tc.secretListFunc, - }, buf), + }), ) cmd.SetArgs(tc.args) cmd.SetOutput(ioutil.Discard) @@ -50,7 +49,7 @@ func TestSecretListErrors(t *testing.T) { func TestSecretList(t *testing.T) { buf := new(bytes.Buffer) - cli := test.NewFakeCliWithOutput(&fakeClient{ + cli := test.NewFakeCli(&fakeClient{ secretListFunc: func(options types.SecretListOptions) ([]swarm.Secret, error) { return []swarm.Secret{ *Secret(SecretID("ID-foo"), @@ -67,18 +66,15 @@ func TestSecretList(t *testing.T) { ), }, nil }, - }, buf) + }) cmd := newSecretListCommand(cli) cmd.SetOutput(buf) assert.NoError(t, cmd.Execute()) - actual := buf.String() - expected := golden.Get(t, []byte(actual), "secret-list.golden") - testutil.EqualNormalizedString(t, testutil.RemoveSpace, actual, string(expected)) + golden.Assert(t, cli.OutBuffer().String(), "secret-list.golden") } func TestSecretListWithQuietOption(t *testing.T) { - buf := new(bytes.Buffer) - cli := test.NewFakeCliWithOutput(&fakeClient{ + cli := test.NewFakeCli(&fakeClient{ secretListFunc: func(options types.SecretListOptions) ([]swarm.Secret, error) { return []swarm.Secret{ *Secret(SecretID("ID-foo"), SecretName("foo")), @@ -87,18 +83,15 @@ func TestSecretListWithQuietOption(t *testing.T) { })), }, nil }, - }, buf) + }) cmd := newSecretListCommand(cli) cmd.Flags().Set("quiet", "true") assert.NoError(t, cmd.Execute()) - actual := buf.String() - expected := golden.Get(t, []byte(actual), "secret-list-with-quiet-option.golden") - testutil.EqualNormalizedString(t, testutil.RemoveSpace, actual, string(expected)) + golden.Assert(t, cli.OutBuffer().String(), "secret-list-with-quiet-option.golden") } func TestSecretListWithConfigFormat(t *testing.T) { - buf := new(bytes.Buffer) - cli := test.NewFakeCliWithOutput(&fakeClient{ + cli := test.NewFakeCli(&fakeClient{ secretListFunc: func(options types.SecretListOptions) ([]swarm.Secret, error) { return []swarm.Secret{ *Secret(SecretID("ID-foo"), SecretName("foo")), @@ -107,20 +100,17 @@ func TestSecretListWithConfigFormat(t *testing.T) { })), }, nil }, - }, buf) + }) cli.SetConfigFile(&configfile.ConfigFile{ SecretFormat: "{{ .Name }} {{ .Labels }}", }) cmd := newSecretListCommand(cli) assert.NoError(t, cmd.Execute()) - actual := buf.String() - expected := golden.Get(t, []byte(actual), "secret-list-with-config-format.golden") - testutil.EqualNormalizedString(t, testutil.RemoveSpace, actual, string(expected)) + golden.Assert(t, cli.OutBuffer().String(), "secret-list-with-config-format.golden") } func TestSecretListWithFormat(t *testing.T) { - buf := new(bytes.Buffer) - cli := test.NewFakeCliWithOutput(&fakeClient{ + cli := test.NewFakeCli(&fakeClient{ secretListFunc: func(options types.SecretListOptions) ([]swarm.Secret, error) { return []swarm.Secret{ *Secret(SecretID("ID-foo"), SecretName("foo")), @@ -129,18 +119,15 @@ func TestSecretListWithFormat(t *testing.T) { })), }, nil }, - }, buf) + }) cmd := newSecretListCommand(cli) cmd.Flags().Set("format", "{{ .Name }} {{ .Labels }}") assert.NoError(t, cmd.Execute()) - actual := buf.String() - expected := golden.Get(t, []byte(actual), "secret-list-with-format.golden") - testutil.EqualNormalizedString(t, testutil.RemoveSpace, actual, string(expected)) + golden.Assert(t, cli.OutBuffer().String(), "secret-list-with-format.golden") } func TestSecretListWithFilter(t *testing.T) { - buf := new(bytes.Buffer) - cli := test.NewFakeCliWithOutput(&fakeClient{ + cli := test.NewFakeCli(&fakeClient{ secretListFunc: func(options types.SecretListOptions) ([]swarm.Secret, error) { assert.Equal(t, "foo", options.Filters.Get("name")[0], "foo") assert.Equal(t, "lbl1=Label-bar", options.Filters.Get("label")[0]) @@ -159,12 +146,10 @@ func TestSecretListWithFilter(t *testing.T) { ), }, nil }, - }, buf) + }) cmd := newSecretListCommand(cli) cmd.Flags().Set("filter", "name=foo") cmd.Flags().Set("filter", "label=lbl1=Label-bar") assert.NoError(t, cmd.Execute()) - actual := buf.String() - expected := golden.Get(t, []byte(actual), "secret-list-with-filter.golden") - testutil.EqualNormalizedString(t, testutil.RemoveSpace, actual, string(expected)) + golden.Assert(t, cli.OutBuffer().String(), "secret-list-with-filter.golden") } diff --git a/components/cli/cli/command/secret/remove_test.go b/components/cli/cli/command/secret/remove_test.go index ad479c0a80..f3e427f7d7 100644 --- a/components/cli/cli/command/secret/remove_test.go +++ b/components/cli/cli/command/secret/remove_test.go @@ -1,7 +1,6 @@ package secret import ( - "bytes" "io/ioutil" "strings" "testing" @@ -31,11 +30,10 @@ func TestSecretRemoveErrors(t *testing.T) { }, } for _, tc := range testCases { - buf := new(bytes.Buffer) cmd := newSecretRemoveCommand( - test.NewFakeCliWithOutput(&fakeClient{ + test.NewFakeCli(&fakeClient{ secretRemoveFunc: tc.secretRemoveFunc, - }, buf), + }), ) cmd.SetArgs(tc.args) cmd.SetOutput(ioutil.Discard) @@ -45,27 +43,25 @@ func TestSecretRemoveErrors(t *testing.T) { func TestSecretRemoveWithName(t *testing.T) { names := []string{"foo", "bar"} - buf := new(bytes.Buffer) var removedSecrets []string - cli := test.NewFakeCliWithOutput(&fakeClient{ + cli := test.NewFakeCli(&fakeClient{ secretRemoveFunc: func(name string) error { removedSecrets = append(removedSecrets, name) return nil }, - }, buf) + }) cmd := newSecretRemoveCommand(cli) cmd.SetArgs(names) assert.NoError(t, cmd.Execute()) - assert.Equal(t, names, strings.Split(strings.TrimSpace(buf.String()), "\n")) + assert.Equal(t, names, strings.Split(strings.TrimSpace(cli.OutBuffer().String()), "\n")) assert.Equal(t, names, removedSecrets) } func TestSecretRemoveContinueAfterError(t *testing.T) { names := []string{"foo", "bar"} - buf := new(bytes.Buffer) var removedSecrets []string - cli := test.NewFakeCliWithOutput(&fakeClient{ + cli := test.NewFakeCli(&fakeClient{ secretRemoveFunc: func(name string) error { removedSecrets = append(removedSecrets, name) if name == "foo" { @@ -73,7 +69,7 @@ func TestSecretRemoveContinueAfterError(t *testing.T) { } return nil }, - }, buf) + }) cmd := newSecretRemoveCommand(cli) cmd.SetOutput(ioutil.Discard) diff --git a/components/cli/cli/command/secret/testdata/secret-inspect-pretty.simple.golden b/components/cli/cli/command/secret/testdata/secret-inspect-pretty.simple.golden index cc14091e8b..4e2df1fb4c 100644 --- a/components/cli/cli/command/secret/testdata/secret-inspect-pretty.simple.golden +++ b/components/cli/cli/command/secret/testdata/secret-inspect-pretty.simple.golden @@ -1,6 +1,6 @@ -ID: secretID -Name: secretName +ID: secretID +Name: secretName Labels: - - lbl1=value1 -Created at: 0001-01-01 00:00:00+0000 utc -Updated at: 0001-01-01 00:00:00+0000 utc + - lbl1=value1 +Created at: 0001-01-01 00:00:00 +0000 utc +Updated at: 0001-01-01 00:00:00 +0000 utc diff --git a/components/cli/cli/command/secret/testdata/secret-inspect-without-format.multiple-secrets-with-labels.golden b/components/cli/cli/command/secret/testdata/secret-inspect-without-format.multiple-secrets-with-labels.golden index 6887c185f1..b01a400c57 100644 --- a/components/cli/cli/command/secret/testdata/secret-inspect-without-format.multiple-secrets-with-labels.golden +++ b/components/cli/cli/command/secret/testdata/secret-inspect-without-format.multiple-secrets-with-labels.golden @@ -1,7 +1,7 @@ [ { "ID": "ID-foo", - "Version": {}, + "Version": {}, "CreatedAt": "0001-01-01T00:00:00Z", "UpdatedAt": "0001-01-01T00:00:00Z", "Spec": { @@ -13,7 +13,7 @@ }, { "ID": "ID-bar", - "Version": {}, + "Version": {}, "CreatedAt": "0001-01-01T00:00:00Z", "UpdatedAt": "0001-01-01T00:00:00Z", "Spec": { diff --git a/components/cli/cli/command/secret/testdata/secret-inspect-without-format.single-secret.golden b/components/cli/cli/command/secret/testdata/secret-inspect-without-format.single-secret.golden index ea42ec6f4f..c4f41c1067 100644 --- a/components/cli/cli/command/secret/testdata/secret-inspect-without-format.single-secret.golden +++ b/components/cli/cli/command/secret/testdata/secret-inspect-without-format.single-secret.golden @@ -1,9 +1,9 @@ [ { "ID": "ID-foo", - "Version": {}, - "CreatedAt": "0001-01-01T00:00:00Z", - "UpdatedAt": "0001-01-01T00:00:00Z", + "Version": {}, + "CreatedAt": "0001-01-01T00:00:00Z", + "UpdatedAt": "0001-01-01T00:00:00Z", "Spec": { "Name": "foo", "Labels": null diff --git a/components/cli/cli/command/secret/testdata/secret-list-with-config-format.golden b/components/cli/cli/command/secret/testdata/secret-list-with-config-format.golden index 9a47538804..11c39229b8 100644 --- a/components/cli/cli/command/secret/testdata/secret-list-with-config-format.golden +++ b/components/cli/cli/command/secret/testdata/secret-list-with-config-format.golden @@ -1,2 +1,2 @@ -foo +foo bar label=label-bar diff --git a/components/cli/cli/command/secret/testdata/secret-list-with-format.golden b/components/cli/cli/command/secret/testdata/secret-list-with-format.golden index 9a47538804..11c39229b8 100644 --- a/components/cli/cli/command/secret/testdata/secret-list-with-format.golden +++ b/components/cli/cli/command/secret/testdata/secret-list-with-format.golden @@ -1,2 +1,2 @@ -foo +foo bar label=label-bar diff --git a/components/cli/cli/command/service/list_test.go b/components/cli/cli/command/service/list_test.go index 85ccd1fb79..297f5f9b17 100644 --- a/components/cli/cli/command/service/list_test.go +++ b/components/cli/cli/command/service/list_test.go @@ -3,14 +3,12 @@ package service import ( "testing" - "golang.org/x/net/context" - "github.com/docker/cli/cli/internal/test" "github.com/docker/docker/api/types" "github.com/docker/docker/api/types/swarm" - "github.com/docker/docker/pkg/testutil" - "github.com/docker/docker/pkg/testutil/golden" + "github.com/gotestyourself/gotestyourself/golden" "github.com/stretchr/testify/assert" + "golang.org/x/net/context" ) func TestServiceListOrder(t *testing.T) { @@ -26,7 +24,5 @@ func TestServiceListOrder(t *testing.T) { cmd := newListCommand(cli) cmd.Flags().Set("format", "{{.Name}}") assert.NoError(t, cmd.Execute()) - actual := cli.OutBuffer().String() - expected := golden.Get(t, []byte(actual), "service-list-sort.golden") - testutil.EqualNormalizedString(t, testutil.RemoveSpace, actual, string(expected)) + golden.Assert(t, cli.OutBuffer().String(), "service-list-sort.golden") } diff --git a/components/cli/cli/command/service/ps_test.go b/components/cli/cli/command/service/ps_test.go index dac79ab50a..083c58f91f 100644 --- a/components/cli/cli/command/service/ps_test.go +++ b/components/cli/cli/command/service/ps_test.go @@ -3,8 +3,6 @@ package service import ( "testing" - "bytes" - "github.com/docker/cli/cli/internal/test" "github.com/docker/cli/opts" "github.com/docker/docker/api/types" @@ -82,8 +80,7 @@ func TestRunPSWarnsOnNotFound(t *testing.T) { }, } - out := new(bytes.Buffer) - cli := test.NewFakeCliWithOutput(client, out) + cli := test.NewFakeCli(client) options := psOptions{ services: []string{"foo", "bar"}, filter: opts.NewFilterOpt(), From 38bd6cfe47380bbda6f246307625bede99a6d4a3 Mon Sep 17 00:00:00 2001 From: Daniel Nephin Date: Wed, 16 Aug 2017 13:04:44 -0400 Subject: [PATCH 18/47] Update stack and task command tests to new golden Signed-off-by: Daniel Nephin Upstream-commit: 1dd742eac872801b88de803cfa1083be40124f1a Component: cli --- components/cli/cli/command/stack/list_test.go | 33 +++++------- components/cli/cli/command/stack/ps_test.go | 26 +++------- .../cli/cli/command/stack/services_test.go | 18 ++----- .../testdata/stack-list-sort-natural.golden | 8 +-- .../testdata/stack-ps-without-format.golden | 4 +- components/cli/cli/command/task/print_test.go | 50 ++++++------------- .../task-print-with-indentation.golden | 6 +-- 7 files changed, 48 insertions(+), 97 deletions(-) diff --git a/components/cli/cli/command/stack/list_test.go b/components/cli/cli/command/stack/list_test.go index 48b141653f..0ae5bc78ce 100644 --- a/components/cli/cli/command/stack/list_test.go +++ b/components/cli/cli/command/stack/list_test.go @@ -1,7 +1,6 @@ package stack import ( - "bytes" "io/ioutil" "testing" @@ -11,7 +10,7 @@ import ( "github.com/docker/docker/api/types" "github.com/docker/docker/api/types/swarm" "github.com/docker/docker/pkg/testutil" - "github.com/docker/docker/pkg/testutil/golden" + "github.com/gotestyourself/gotestyourself/golden" "github.com/pkg/errors" "github.com/stretchr/testify/assert" ) @@ -61,8 +60,7 @@ func TestListErrors(t *testing.T) { } func TestListWithFormat(t *testing.T) { - buf := new(bytes.Buffer) - cmd := newListCommand(test.NewFakeCliWithOutput(&fakeClient{ + cli := test.NewFakeCli(&fakeClient{ serviceListFunc: func(options types.ServiceListOptions) ([]swarm.Service, error) { return []swarm.Service{ *Service( @@ -71,17 +69,15 @@ func TestListWithFormat(t *testing.T) { }), )}, nil }, - }, buf)) + }) + cmd := newListCommand(cli) cmd.Flags().Set("format", "{{ .Name }}") assert.NoError(t, cmd.Execute()) - actual := buf.String() - expected := golden.Get(t, []byte(actual), "stack-list-with-format.golden") - testutil.EqualNormalizedString(t, testutil.RemoveSpace, actual, string(expected)) + golden.Assert(t, cli.OutBuffer().String(), "stack-list-with-format.golden") } func TestListWithoutFormat(t *testing.T) { - buf := new(bytes.Buffer) - cmd := newListCommand(test.NewFakeCliWithOutput(&fakeClient{ + cli := test.NewFakeCli(&fakeClient{ serviceListFunc: func(options types.ServiceListOptions) ([]swarm.Service, error) { return []swarm.Service{ *Service( @@ -90,11 +86,10 @@ func TestListWithoutFormat(t *testing.T) { }), )}, nil }, - }, buf)) + }) + cmd := newListCommand(cli) assert.NoError(t, cmd.Execute()) - actual := buf.String() - expected := golden.Get(t, []byte(actual), "stack-list-without-format.golden") - testutil.EqualNormalizedString(t, testutil.RemoveSpace, actual, string(expected)) + golden.Assert(t, cli.OutBuffer().String(), "stack-list-without-format.golden") } func TestListOrder(t *testing.T) { @@ -140,15 +135,13 @@ func TestListOrder(t *testing.T) { } for _, uc := range usecases { - buf := new(bytes.Buffer) - cmd := newListCommand(test.NewFakeCliWithOutput(&fakeClient{ + cli := test.NewFakeCli(&fakeClient{ serviceListFunc: func(options types.ServiceListOptions) ([]swarm.Service, error) { return uc.swarmServices, nil }, - }, buf)) + }) + cmd := newListCommand(cli) assert.NoError(t, cmd.Execute()) - actual := buf.String() - expected := golden.Get(t, []byte(actual), uc.golden) - testutil.EqualNormalizedString(t, testutil.RemoveSpace, actual, string(expected)) + golden.Assert(t, cli.OutBuffer().String(), uc.golden) } } diff --git a/components/cli/cli/command/stack/ps_test.go b/components/cli/cli/command/stack/ps_test.go index 5387dd0347..249e1b656a 100644 --- a/components/cli/cli/command/stack/ps_test.go +++ b/components/cli/cli/command/stack/ps_test.go @@ -12,7 +12,7 @@ import ( "github.com/docker/docker/api/types" "github.com/docker/docker/api/types/swarm" "github.com/docker/docker/pkg/testutil" - "github.com/docker/docker/pkg/testutil/golden" + "github.com/gotestyourself/gotestyourself/golden" "github.com/pkg/errors" "github.com/stretchr/testify/assert" ) @@ -75,9 +75,7 @@ func TestStackPsWithQuietOption(t *testing.T) { cmd.SetArgs([]string{"foo"}) cmd.Flags().Set("quiet", "true") assert.NoError(t, cmd.Execute()) - actual := cli.OutBuffer().String() - expected := golden.Get(t, []byte(actual), "stack-ps-with-quiet-option.golden") - testutil.EqualNormalizedString(t, testutil.RemoveSpace, actual, string(expected)) + golden.Assert(t, cli.OutBuffer().String(), "stack-ps-with-quiet-option.golden") } @@ -92,9 +90,7 @@ func TestStackPsWithNoTruncOption(t *testing.T) { cmd.Flags().Set("no-trunc", "true") cmd.Flags().Set("format", "{{ .ID }}") assert.NoError(t, cmd.Execute()) - actual := cli.OutBuffer().String() - expected := golden.Get(t, []byte(actual), "stack-ps-with-no-trunc-option.golden") - testutil.EqualNormalizedString(t, testutil.RemoveSpace, actual, string(expected)) + golden.Assert(t, cli.OutBuffer().String(), "stack-ps-with-no-trunc-option.golden") } func TestStackPsWithNoResolveOption(t *testing.T) { @@ -113,9 +109,7 @@ func TestStackPsWithNoResolveOption(t *testing.T) { cmd.Flags().Set("no-resolve", "true") cmd.Flags().Set("format", "{{ .Node }}") assert.NoError(t, cmd.Execute()) - actual := cli.OutBuffer().String() - expected := golden.Get(t, []byte(actual), "stack-ps-with-no-resolve-option.golden") - testutil.EqualNormalizedString(t, testutil.RemoveSpace, actual, string(expected)) + golden.Assert(t, cli.OutBuffer().String(), "stack-ps-with-no-resolve-option.golden") } func TestStackPsWithFormat(t *testing.T) { @@ -128,9 +122,7 @@ func TestStackPsWithFormat(t *testing.T) { cmd.SetArgs([]string{"foo"}) cmd.Flags().Set("format", "{{ .Name }}") assert.NoError(t, cmd.Execute()) - actual := cli.OutBuffer().String() - expected := golden.Get(t, []byte(actual), "stack-ps-with-format.golden") - testutil.EqualNormalizedString(t, testutil.RemoveSpace, actual, string(expected)) + golden.Assert(t, cli.OutBuffer().String(), "stack-ps-with-format.golden") } func TestStackPsWithConfigFormat(t *testing.T) { @@ -145,9 +137,7 @@ func TestStackPsWithConfigFormat(t *testing.T) { cmd := newPsCommand(cli) cmd.SetArgs([]string{"foo"}) assert.NoError(t, cmd.Execute()) - actual := cli.OutBuffer().String() - expected := golden.Get(t, []byte(actual), "stack-ps-with-config-format.golden") - testutil.EqualNormalizedString(t, testutil.RemoveSpace, actual, string(expected)) + golden.Assert(t, cli.OutBuffer().String(), "stack-ps-with-config-format.golden") } func TestStackPsWithoutFormat(t *testing.T) { @@ -169,7 +159,5 @@ func TestStackPsWithoutFormat(t *testing.T) { cmd := newPsCommand(cli) cmd.SetArgs([]string{"foo"}) assert.NoError(t, cmd.Execute()) - actual := cli.OutBuffer().String() - expected := golden.Get(t, []byte(actual), "stack-ps-without-format.golden") - testutil.EqualNormalizedString(t, testutil.RemoveSpace, actual, string(expected)) + golden.Assert(t, cli.OutBuffer().String(), "stack-ps-without-format.golden") } diff --git a/components/cli/cli/command/stack/services_test.go b/components/cli/cli/command/stack/services_test.go index 822660fbc2..fcc82ec885 100644 --- a/components/cli/cli/command/stack/services_test.go +++ b/components/cli/cli/command/stack/services_test.go @@ -11,7 +11,7 @@ import ( "github.com/docker/docker/api/types" "github.com/docker/docker/api/types/swarm" "github.com/docker/docker/pkg/testutil" - "github.com/docker/docker/pkg/testutil/golden" + "github.com/gotestyourself/gotestyourself/golden" "github.com/pkg/errors" "github.com/stretchr/testify/assert" ) @@ -103,9 +103,7 @@ func TestStackServicesWithQuietOption(t *testing.T) { cmd.Flags().Set("quiet", "true") cmd.SetArgs([]string{"foo"}) assert.NoError(t, cmd.Execute()) - actual := cli.OutBuffer().String() - expected := golden.Get(t, []byte(actual), "stack-services-with-quiet-option.golden") - testutil.EqualNormalizedString(t, testutil.RemoveSpace, actual, string(expected)) + golden.Assert(t, cli.OutBuffer().String(), "stack-services-with-quiet-option.golden") } func TestStackServicesWithFormat(t *testing.T) { @@ -120,9 +118,7 @@ func TestStackServicesWithFormat(t *testing.T) { cmd.SetArgs([]string{"foo"}) cmd.Flags().Set("format", "{{ .Name }}") assert.NoError(t, cmd.Execute()) - actual := cli.OutBuffer().String() - expected := golden.Get(t, []byte(actual), "stack-services-with-format.golden") - testutil.EqualNormalizedString(t, testutil.RemoveSpace, actual, string(expected)) + golden.Assert(t, cli.OutBuffer().String(), "stack-services-with-format.golden") } func TestStackServicesWithConfigFormat(t *testing.T) { @@ -139,9 +135,7 @@ func TestStackServicesWithConfigFormat(t *testing.T) { cmd := newServicesCommand(cli) cmd.SetArgs([]string{"foo"}) assert.NoError(t, cmd.Execute()) - actual := cli.OutBuffer().String() - expected := golden.Get(t, []byte(actual), "stack-services-with-config-format.golden") - testutil.EqualNormalizedString(t, testutil.RemoveSpace, actual, string(expected)) + golden.Assert(t, cli.OutBuffer().String(), "stack-services-with-config-format.golden") } func TestStackServicesWithoutFormat(t *testing.T) { @@ -164,7 +158,5 @@ func TestStackServicesWithoutFormat(t *testing.T) { cmd := newServicesCommand(cli) cmd.SetArgs([]string{"foo"}) assert.NoError(t, cmd.Execute()) - actual := cli.OutBuffer().String() - expected := golden.Get(t, []byte(actual), "stack-services-without-format.golden") - testutil.EqualNormalizedString(t, testutil.RemoveSpace, actual, string(expected)) + golden.Assert(t, cli.OutBuffer().String(), "stack-services-without-format.golden") } diff --git a/components/cli/cli/command/stack/testdata/stack-list-sort-natural.golden b/components/cli/cli/command/stack/testdata/stack-list-sort-natural.golden index 09507fbf40..71eb63fd3b 100644 --- a/components/cli/cli/command/stack/testdata/stack-list-sort-natural.golden +++ b/components/cli/cli/command/stack/testdata/stack-list-sort-natural.golden @@ -1,4 +1,4 @@ -NAME SERVICES -service-name-1-foo 1 -service-name-2-foo 1 -service-name-10-foo 1 +NAME SERVICES +service-name-1-foo 1 +service-name-2-foo 1 +service-name-10-foo 1 diff --git a/components/cli/cli/command/stack/testdata/stack-ps-without-format.golden b/components/cli/cli/command/stack/testdata/stack-ps-without-format.golden index 9ca75f5890..ceb4f8411c 100644 --- a/components/cli/cli/command/stack/testdata/stack-ps-without-format.golden +++ b/components/cli/cli/command/stack/testdata/stack-ps-without-format.golden @@ -1,2 +1,2 @@ -ID NAME IMAGE NODE DESIRED STATE CURRENT STATE ERROR PORTS -id-foo service-id-foo.1 myimage:mytag node-name-bar Ready Failed 2 hours ago +ID NAME IMAGE NODE DESIRED STATE CURRENT STATE ERROR PORTS +id-foo service-id-foo.1 myimage:mytag node-name-bar Ready Failed 2 hours ago diff --git a/components/cli/cli/command/task/print_test.go b/components/cli/cli/command/task/print_test.go index 174ad72cd7..19e02c6d18 100644 --- a/components/cli/cli/command/task/print_test.go +++ b/components/cli/cli/command/task/print_test.go @@ -1,7 +1,6 @@ package task import ( - "bytes" "testing" "time" @@ -13,8 +12,7 @@ import ( . "github.com/docker/cli/cli/internal/test/builders" "github.com/docker/docker/api/types" "github.com/docker/docker/api/types/swarm" - "github.com/docker/docker/pkg/testutil" - "github.com/docker/docker/pkg/testutil/golden" + "github.com/gotestyourself/gotestyourself/golden" "github.com/stretchr/testify/assert" ) @@ -22,75 +20,60 @@ func TestTaskPrintWithQuietOption(t *testing.T) { quiet := true trunc := false noResolve := true - buf := new(bytes.Buffer) apiClient := &fakeClient{} - cli := test.NewFakeCliWithOutput(apiClient, buf) - tasks := []swarm.Task{ - *Task(TaskID("id-foo")), - } + cli := test.NewFakeCli(apiClient) + tasks := []swarm.Task{*Task(TaskID("id-foo"))} err := Print(context.Background(), cli, tasks, idresolver.New(apiClient, noResolve), trunc, quiet, formatter.TableFormatKey) assert.NoError(t, err) - actual := buf.String() - expected := golden.Get(t, []byte(actual), "task-print-with-quiet-option.golden") - testutil.EqualNormalizedString(t, testutil.RemoveSpace, actual, string(expected)) + golden.Assert(t, cli.OutBuffer().String(), "task-print-with-quiet-option.golden") } func TestTaskPrintWithNoTruncOption(t *testing.T) { quiet := false trunc := false noResolve := true - buf := new(bytes.Buffer) apiClient := &fakeClient{} - cli := test.NewFakeCliWithOutput(apiClient, buf) + cli := test.NewFakeCli(apiClient) tasks := []swarm.Task{ *Task(TaskID("id-foo-yov6omdek8fg3k5stosyp2m50")), } err := Print(context.Background(), cli, tasks, idresolver.New(apiClient, noResolve), trunc, quiet, "{{ .ID }}") assert.NoError(t, err) - actual := buf.String() - expected := golden.Get(t, []byte(actual), "task-print-with-no-trunc-option.golden") - testutil.EqualNormalizedString(t, testutil.RemoveSpace, actual, string(expected)) + golden.Assert(t, cli.OutBuffer().String(), "task-print-with-no-trunc-option.golden") } func TestTaskPrintWithGlobalService(t *testing.T) { quiet := false trunc := false noResolve := true - buf := new(bytes.Buffer) apiClient := &fakeClient{} - cli := test.NewFakeCliWithOutput(apiClient, buf) + cli := test.NewFakeCli(apiClient) tasks := []swarm.Task{ *Task(TaskServiceID("service-id-foo"), TaskNodeID("node-id-bar"), TaskSlot(0)), } err := Print(context.Background(), cli, tasks, idresolver.New(apiClient, noResolve), trunc, quiet, "{{ .Name }}") assert.NoError(t, err) - actual := buf.String() - expected := golden.Get(t, []byte(actual), "task-print-with-global-service.golden") - testutil.EqualNormalizedString(t, testutil.RemoveSpace, actual, string(expected)) + golden.Assert(t, cli.OutBuffer().String(), "task-print-with-global-service.golden") } func TestTaskPrintWithReplicatedService(t *testing.T) { quiet := false trunc := false noResolve := true - buf := new(bytes.Buffer) apiClient := &fakeClient{} - cli := test.NewFakeCliWithOutput(apiClient, buf) + cli := test.NewFakeCli(apiClient) tasks := []swarm.Task{ *Task(TaskServiceID("service-id-foo"), TaskSlot(1)), } err := Print(context.Background(), cli, tasks, idresolver.New(apiClient, noResolve), trunc, quiet, "{{ .Name }}") assert.NoError(t, err) - actual := buf.String() - expected := golden.Get(t, []byte(actual), "task-print-with-replicated-service.golden") - testutil.EqualNormalizedString(t, testutil.RemoveSpace, actual, string(expected)) + golden.Assert(t, cli.OutBuffer().String(), "task-print-with-replicated-service.golden") } func TestTaskPrintWithIndentation(t *testing.T) { quiet := false trunc := false noResolve := false - buf := new(bytes.Buffer) apiClient := &fakeClient{ serviceInspectWithRaw: func(ref string, options types.ServiceInspectOptions) (swarm.Service, []byte, error) { return *Service(ServiceName("service-name-foo")), nil, nil @@ -99,7 +82,7 @@ func TestTaskPrintWithIndentation(t *testing.T) { return *Node(NodeName("node-name-bar")), nil, nil }, } - cli := test.NewFakeCliWithOutput(apiClient, buf) + cli := test.NewFakeCli(apiClient) tasks := []swarm.Task{ *Task( TaskID("id-foo"), @@ -120,16 +103,13 @@ func TestTaskPrintWithIndentation(t *testing.T) { } err := Print(context.Background(), cli, tasks, idresolver.New(apiClient, noResolve), trunc, quiet, formatter.TableFormatKey) assert.NoError(t, err) - actual := buf.String() - expected := golden.Get(t, []byte(actual), "task-print-with-indentation.golden") - testutil.EqualNormalizedString(t, testutil.RemoveSpace, actual, string(expected)) + golden.Assert(t, cli.OutBuffer().String(), "task-print-with-indentation.golden") } func TestTaskPrintWithResolution(t *testing.T) { quiet := false trunc := false noResolve := false - buf := new(bytes.Buffer) apiClient := &fakeClient{ serviceInspectWithRaw: func(ref string, options types.ServiceInspectOptions) (swarm.Service, []byte, error) { return *Service(ServiceName("service-name-foo")), nil, nil @@ -138,13 +118,11 @@ func TestTaskPrintWithResolution(t *testing.T) { return *Node(NodeName("node-name-bar")), nil, nil }, } - cli := test.NewFakeCliWithOutput(apiClient, buf) + cli := test.NewFakeCli(apiClient) tasks := []swarm.Task{ *Task(TaskServiceID("service-id-foo"), TaskSlot(1)), } err := Print(context.Background(), cli, tasks, idresolver.New(apiClient, noResolve), trunc, quiet, "{{ .Name }} {{ .Node }}") assert.NoError(t, err) - actual := buf.String() - expected := golden.Get(t, []byte(actual), "task-print-with-resolution.golden") - testutil.EqualNormalizedString(t, testutil.RemoveSpace, actual, string(expected)) + golden.Assert(t, cli.OutBuffer().String(), "task-print-with-resolution.golden") } diff --git a/components/cli/cli/command/task/testdata/task-print-with-indentation.golden b/components/cli/cli/command/task/testdata/task-print-with-indentation.golden index 932126ad94..8fa174a442 100644 --- a/components/cli/cli/command/task/testdata/task-print-with-indentation.golden +++ b/components/cli/cli/command/task/testdata/task-print-with-indentation.golden @@ -1,3 +1,3 @@ -ID NAME IMAGE NODE DESIRED STATE CURRENT STATE ERROR PORTS -id-foo service-name-foo.1 myimage:mytag node-name-bar Ready Failed 2 hours ago -id-bar \_ service-name-foo.1 myimage:mytag node-name-bar Ready Failed 2 hours ago +ID NAME IMAGE NODE DESIRED STATE CURRENT STATE ERROR PORTS +id-foo service-name-foo.1 myimage:mytag node-name-bar Ready Failed 2 hours ago +id-bar \_ service-name-foo.1 myimage:mytag node-name-bar Ready Failed 2 hours ago From a5b8c46809e6f8b71fff27dddbcd5a9bdcf8f262 Mon Sep 17 00:00:00 2001 From: Daniel Nephin Date: Wed, 16 Aug 2017 13:48:31 -0400 Subject: [PATCH 19/47] Update swarm command tests to use the new golden Signed-off-by: Daniel Nephin Upstream-commit: 3d68aa84167411c53a04df53130c533791ce55a5 Component: cli --- components/cli/cli/command/swarm/init_test.go | 28 ++++++--------- components/cli/cli/command/swarm/join_test.go | 17 ++++----- .../cli/cli/command/swarm/join_token_test.go | 35 ++++++++----------- .../testdata/jointoken-manager-rotate.golden | 1 + .../swarm/testdata/jointoken-manager.golden | 1 + .../swarm/testdata/jointoken-worker.golden | 1 + .../cli/cli/command/swarm/unlock_key_test.go | 6 ++-- .../cli/cli/command/swarm/update_test.go | 6 ++-- 8 files changed, 40 insertions(+), 55 deletions(-) diff --git a/components/cli/cli/command/swarm/init_test.go b/components/cli/cli/command/swarm/init_test.go index f6969d1b0e..5991c3dd54 100644 --- a/components/cli/cli/command/swarm/init_test.go +++ b/components/cli/cli/command/swarm/init_test.go @@ -1,7 +1,6 @@ package swarm import ( - "bytes" "fmt" "io/ioutil" "testing" @@ -9,8 +8,7 @@ import ( "github.com/docker/cli/cli/internal/test" "github.com/docker/docker/api/types" "github.com/docker/docker/api/types/swarm" - "github.com/docker/docker/pkg/testutil" - "github.com/docker/docker/pkg/testutil/golden" + "github.com/gotestyourself/gotestyourself/golden" "github.com/pkg/errors" "github.com/stretchr/testify/assert" ) @@ -65,14 +63,13 @@ func TestSwarmInitErrorOnAPIFailure(t *testing.T) { }, } for _, tc := range testCases { - buf := new(bytes.Buffer) cmd := newInitCommand( - test.NewFakeCliWithOutput(&fakeClient{ + test.NewFakeCli(&fakeClient{ swarmInitFunc: tc.swarmInitFunc, swarmInspectFunc: tc.swarmInspectFunc, swarmGetUnlockKeyFunc: tc.swarmGetUnlockKeyFunc, nodeInspectFunc: tc.nodeInspectFunc, - }, buf)) + })) for key, value := range tc.flags { cmd.Flags().Set(key, value) } @@ -112,20 +109,17 @@ func TestSwarmInit(t *testing.T) { }, } for _, tc := range testCases { - buf := new(bytes.Buffer) - cmd := newInitCommand( - test.NewFakeCliWithOutput(&fakeClient{ - swarmInitFunc: tc.swarmInitFunc, - swarmInspectFunc: tc.swarmInspectFunc, - swarmGetUnlockKeyFunc: tc.swarmGetUnlockKeyFunc, - nodeInspectFunc: tc.nodeInspectFunc, - }, buf)) + cli := test.NewFakeCli(&fakeClient{ + swarmInitFunc: tc.swarmInitFunc, + swarmInspectFunc: tc.swarmInspectFunc, + swarmGetUnlockKeyFunc: tc.swarmGetUnlockKeyFunc, + nodeInspectFunc: tc.nodeInspectFunc, + }) + cmd := newInitCommand(cli) for key, value := range tc.flags { cmd.Flags().Set(key, value) } assert.NoError(t, cmd.Execute()) - actual := buf.String() - expected := golden.Get(t, []byte(actual), fmt.Sprintf("init-%s.golden", tc.name)) - testutil.EqualNormalizedString(t, testutil.RemoveSpace, actual, string(expected)) + golden.Assert(t, cli.OutBuffer().String(), fmt.Sprintf("init-%s.golden", tc.name)) } } diff --git a/components/cli/cli/command/swarm/join_test.go b/components/cli/cli/command/swarm/join_test.go index 331f2c1753..d9f5215b7b 100644 --- a/components/cli/cli/command/swarm/join_test.go +++ b/components/cli/cli/command/swarm/join_test.go @@ -1,7 +1,6 @@ package swarm import ( - "bytes" "io/ioutil" "strings" "testing" @@ -49,12 +48,11 @@ func TestSwarmJoinErrors(t *testing.T) { }, } for _, tc := range testCases { - buf := new(bytes.Buffer) cmd := newJoinCommand( - test.NewFakeCliWithOutput(&fakeClient{ + test.NewFakeCli(&fakeClient{ swarmJoinFunc: tc.swarmJoinFunc, infoFunc: tc.infoFunc, - }, buf)) + })) cmd.SetArgs(tc.args) cmd.SetOutput(ioutil.Discard) testutil.ErrorContains(t, cmd.Execute(), tc.expectedError) @@ -91,13 +89,12 @@ func TestSwarmJoin(t *testing.T) { }, } for _, tc := range testCases { - buf := new(bytes.Buffer) - cmd := newJoinCommand( - test.NewFakeCliWithOutput(&fakeClient{ - infoFunc: tc.infoFunc, - }, buf)) + cli := test.NewFakeCli(&fakeClient{ + infoFunc: tc.infoFunc, + }) + cmd := newJoinCommand(cli) cmd.SetArgs([]string{"remote"}) assert.NoError(t, cmd.Execute()) - assert.Equal(t, strings.TrimSpace(buf.String()), tc.expected) + assert.Equal(t, strings.TrimSpace(cli.OutBuffer().String()), tc.expected) } } diff --git a/components/cli/cli/command/swarm/join_token_test.go b/components/cli/cli/command/swarm/join_token_test.go index f8619a4bd6..da1b795321 100644 --- a/components/cli/cli/command/swarm/join_token_test.go +++ b/components/cli/cli/command/swarm/join_token_test.go @@ -1,7 +1,6 @@ package swarm import ( - "bytes" "fmt" "io/ioutil" "testing" @@ -13,7 +12,7 @@ import ( // Import builders to get the builder function as package function . "github.com/docker/cli/cli/internal/test/builders" "github.com/docker/docker/pkg/testutil" - "github.com/docker/docker/pkg/testutil/golden" + "github.com/gotestyourself/gotestyourself/golden" "github.com/stretchr/testify/assert" ) @@ -90,14 +89,13 @@ func TestSwarmJoinTokenErrors(t *testing.T) { }, } for _, tc := range testCases { - buf := new(bytes.Buffer) - cmd := newJoinTokenCommand( - test.NewFakeCliWithOutput(&fakeClient{ - swarmInspectFunc: tc.swarmInspectFunc, - swarmUpdateFunc: tc.swarmUpdateFunc, - infoFunc: tc.infoFunc, - nodeInspectFunc: tc.nodeInspectFunc, - }, buf)) + cli := test.NewFakeCli(&fakeClient{ + swarmInspectFunc: tc.swarmInspectFunc, + swarmUpdateFunc: tc.swarmUpdateFunc, + infoFunc: tc.infoFunc, + nodeInspectFunc: tc.nodeInspectFunc, + }) + cmd := newJoinTokenCommand(cli) cmd.SetArgs(tc.args) for key, value := range tc.flags { cmd.Flags().Set(key, value) @@ -198,20 +196,17 @@ func TestSwarmJoinToken(t *testing.T) { }, } for _, tc := range testCases { - buf := new(bytes.Buffer) - cmd := newJoinTokenCommand( - test.NewFakeCliWithOutput(&fakeClient{ - swarmInspectFunc: tc.swarmInspectFunc, - infoFunc: tc.infoFunc, - nodeInspectFunc: tc.nodeInspectFunc, - }, buf)) + cli := test.NewFakeCli(&fakeClient{ + swarmInspectFunc: tc.swarmInspectFunc, + infoFunc: tc.infoFunc, + nodeInspectFunc: tc.nodeInspectFunc, + }) + cmd := newJoinTokenCommand(cli) cmd.SetArgs(tc.args) for key, value := range tc.flags { cmd.Flags().Set(key, value) } assert.NoError(t, cmd.Execute()) - actual := buf.String() - expected := golden.Get(t, []byte(actual), fmt.Sprintf("jointoken-%s.golden", tc.name)) - testutil.EqualNormalizedString(t, testutil.RemoveSpace, actual, string(expected)) + golden.Assert(t, cli.OutBuffer().String(), fmt.Sprintf("jointoken-%s.golden", tc.name)) } } diff --git a/components/cli/cli/command/swarm/testdata/jointoken-manager-rotate.golden b/components/cli/cli/command/swarm/testdata/jointoken-manager-rotate.golden index b4d0a48f66..4a978e7624 100644 --- a/components/cli/cli/command/swarm/testdata/jointoken-manager-rotate.golden +++ b/components/cli/cli/command/swarm/testdata/jointoken-manager-rotate.golden @@ -3,3 +3,4 @@ Successfully rotated manager join token. To add a manager to this swarm, run the following command: docker swarm join --token manager-join-token 127.0.0.1 + diff --git a/components/cli/cli/command/swarm/testdata/jointoken-manager.golden b/components/cli/cli/command/swarm/testdata/jointoken-manager.golden index 522b2968fe..7bcb73373c 100644 --- a/components/cli/cli/command/swarm/testdata/jointoken-manager.golden +++ b/components/cli/cli/command/swarm/testdata/jointoken-manager.golden @@ -1,3 +1,4 @@ To add a manager to this swarm, run the following command: docker swarm join --token manager-join-token 127.0.0.1 + diff --git a/components/cli/cli/command/swarm/testdata/jointoken-worker.golden b/components/cli/cli/command/swarm/testdata/jointoken-worker.golden index 899df703fd..e6c3ab9af8 100644 --- a/components/cli/cli/command/swarm/testdata/jointoken-worker.golden +++ b/components/cli/cli/command/swarm/testdata/jointoken-worker.golden @@ -1,3 +1,4 @@ To add a worker to this swarm, run the following command: docker swarm join --token worker-join-token 127.0.0.1 + diff --git a/components/cli/cli/command/swarm/unlock_key_test.go b/components/cli/cli/command/swarm/unlock_key_test.go index bb3935ceda..0dc9fb5f08 100644 --- a/components/cli/cli/command/swarm/unlock_key_test.go +++ b/components/cli/cli/command/swarm/unlock_key_test.go @@ -12,7 +12,7 @@ import ( // Import builders to get the builder function as package function . "github.com/docker/cli/cli/internal/test/builders" "github.com/docker/docker/pkg/testutil" - "github.com/docker/docker/pkg/testutil/golden" + "github.com/gotestyourself/gotestyourself/golden" "github.com/stretchr/testify/assert" ) @@ -167,8 +167,6 @@ func TestSwarmUnlockKey(t *testing.T) { cmd.Flags().Set(key, value) } assert.NoError(t, cmd.Execute()) - actual := cli.OutBuffer().String() - expected := golden.Get(t, []byte(actual), fmt.Sprintf("unlockkeys-%s.golden", tc.name)) - testutil.EqualNormalizedString(t, testutil.RemoveSpace, actual, string(expected)) + golden.Assert(t, cli.OutBuffer().String(), fmt.Sprintf("unlockkeys-%s.golden", tc.name)) } } diff --git a/components/cli/cli/command/swarm/update_test.go b/components/cli/cli/command/swarm/update_test.go index b3cb02f25f..3c928a2e0d 100644 --- a/components/cli/cli/command/swarm/update_test.go +++ b/components/cli/cli/command/swarm/update_test.go @@ -13,7 +13,7 @@ import ( // Import builders to get the builder function as package function . "github.com/docker/cli/cli/internal/test/builders" "github.com/docker/docker/pkg/testutil" - "github.com/docker/docker/pkg/testutil/golden" + "github.com/gotestyourself/gotestyourself/golden" "github.com/stretchr/testify/assert" ) @@ -174,8 +174,6 @@ func TestSwarmUpdate(t *testing.T) { } cmd.SetOutput(cli.OutBuffer()) assert.NoError(t, cmd.Execute()) - actual := cli.OutBuffer().String() - expected := golden.Get(t, []byte(actual), fmt.Sprintf("update-%s.golden", tc.name)) - testutil.EqualNormalizedString(t, testutil.RemoveSpace, actual, string(expected)) + golden.Assert(t, cli.OutBuffer().String(), fmt.Sprintf("update-%s.golden", tc.name)) } } From 34fe016d0d6a884620adecc7dd6f14098d198d3a Mon Sep 17 00:00:00 2001 From: Daniel Nephin Date: Wed, 16 Aug 2017 13:50:28 -0400 Subject: [PATCH 20/47] Update volume command tests to use the new golden Signed-off-by: Daniel Nephin Upstream-commit: 505a0fe45f92633825f4b57609b7cc11ee67b92b Component: cli --- .../cli/cli/command/volume/create_test.go | 15 +++-- .../cli/cli/command/volume/inspect_test.go | 36 ++++------- .../cli/cli/command/volume/list_test.go | 35 ++++------- .../cli/cli/command/volume/prune_test.go | 63 +++++++------------ .../cli/cli/command/volume/remove_test.go | 9 +-- components/cli/cli/internal/test/cli.go | 8 --- 6 files changed, 59 insertions(+), 107 deletions(-) diff --git a/components/cli/cli/command/volume/create_test.go b/components/cli/cli/command/volume/create_test.go index e458a26c46..cf84195f45 100644 --- a/components/cli/cli/command/volume/create_test.go +++ b/components/cli/cli/command/volume/create_test.go @@ -1,7 +1,6 @@ package volume import ( - "bytes" "io/ioutil" "reflect" "strings" @@ -57,8 +56,7 @@ func TestVolumeCreateErrors(t *testing.T) { func TestVolumeCreateWithName(t *testing.T) { name := "foo" - buf := new(bytes.Buffer) - cli := test.NewFakeCliWithOutput(&fakeClient{ + cli := test.NewFakeCli(&fakeClient{ volumeCreateFunc: func(body volumetypes.VolumesCreateBody) (types.Volume, error) { if body.Name != name { return types.Volume{}, errors.Errorf("expected name %q, got %q", name, body.Name) @@ -67,7 +65,9 @@ func TestVolumeCreateWithName(t *testing.T) { Name: body.Name, }, nil }, - }, buf) + }) + + buf := cli.OutBuffer() // Test by flags cmd := newCreateCommand(cli) @@ -95,8 +95,7 @@ func TestVolumeCreateWithFlags(t *testing.T) { } name := "banana" - buf := new(bytes.Buffer) - cli := test.NewFakeCliWithOutput(&fakeClient{ + cli := test.NewFakeCli(&fakeClient{ volumeCreateFunc: func(body volumetypes.VolumesCreateBody) (types.Volume, error) { if body.Name != "" { return types.Volume{}, errors.Errorf("expected empty name, got %q", body.Name) @@ -114,7 +113,7 @@ func TestVolumeCreateWithFlags(t *testing.T) { Name: name, }, nil }, - }, buf) + }) cmd := newCreateCommand(cli) cmd.Flags().Set("driver", "foo") @@ -123,5 +122,5 @@ func TestVolumeCreateWithFlags(t *testing.T) { cmd.Flags().Set("label", "lbl1=v1") cmd.Flags().Set("label", "lbl2=v2") assert.NoError(t, cmd.Execute()) - assert.Equal(t, name, strings.TrimSpace(buf.String())) + assert.Equal(t, name, strings.TrimSpace(cli.OutBuffer().String())) } diff --git a/components/cli/cli/command/volume/inspect_test.go b/components/cli/cli/command/volume/inspect_test.go index 8f452d7dee..fccccf4442 100644 --- a/components/cli/cli/command/volume/inspect_test.go +++ b/components/cli/cli/command/volume/inspect_test.go @@ -1,7 +1,6 @@ package volume import ( - "bytes" "fmt" "io/ioutil" "testing" @@ -12,7 +11,7 @@ import ( // Import builders to get the builder function as package function . "github.com/docker/cli/cli/internal/test/builders" "github.com/docker/docker/pkg/testutil" - "github.com/docker/docker/pkg/testutil/golden" + "github.com/gotestyourself/gotestyourself/golden" "github.com/stretchr/testify/assert" ) @@ -54,11 +53,10 @@ func TestVolumeInspectErrors(t *testing.T) { }, } for _, tc := range testCases { - buf := new(bytes.Buffer) cmd := newInspectCommand( - test.NewFakeCliWithOutput(&fakeClient{ + test.NewFakeCli(&fakeClient{ volumeInspectFunc: tc.volumeInspectFunc, - }, buf), + }), ) cmd.SetArgs(tc.args) for key, value := range tc.flags { @@ -96,17 +94,13 @@ func TestVolumeInspectWithoutFormat(t *testing.T) { }, } for _, tc := range testCases { - buf := new(bytes.Buffer) - cmd := newInspectCommand( - test.NewFakeCliWithOutput(&fakeClient{ - volumeInspectFunc: tc.volumeInspectFunc, - }, buf), - ) + cli := test.NewFakeCli(&fakeClient{ + volumeInspectFunc: tc.volumeInspectFunc, + }) + cmd := newInspectCommand(cli) cmd.SetArgs(tc.args) assert.NoError(t, cmd.Execute()) - actual := buf.String() - expected := golden.Get(t, []byte(actual), fmt.Sprintf("volume-inspect-without-format.%s.golden", tc.name)) - testutil.EqualNormalizedString(t, testutil.RemoveSpace, actual, string(expected)) + golden.Assert(t, cli.OutBuffer().String(), fmt.Sprintf("volume-inspect-without-format.%s.golden", tc.name)) } } @@ -136,17 +130,13 @@ func TestVolumeInspectWithFormat(t *testing.T) { }, } for _, tc := range testCases { - buf := new(bytes.Buffer) - cmd := newInspectCommand( - test.NewFakeCliWithOutput(&fakeClient{ - volumeInspectFunc: tc.volumeInspectFunc, - }, buf), - ) + cli := test.NewFakeCli(&fakeClient{ + volumeInspectFunc: tc.volumeInspectFunc, + }) + cmd := newInspectCommand(cli) cmd.SetArgs(tc.args) cmd.Flags().Set("format", tc.format) assert.NoError(t, cmd.Execute()) - actual := buf.String() - expected := golden.Get(t, []byte(actual), fmt.Sprintf("volume-inspect-with-format.%s.golden", tc.name)) - testutil.EqualNormalizedString(t, testutil.RemoveSpace, actual, string(expected)) + golden.Assert(t, cli.OutBuffer().String(), fmt.Sprintf("volume-inspect-with-format.%s.golden", tc.name)) } } diff --git a/components/cli/cli/command/volume/list_test.go b/components/cli/cli/command/volume/list_test.go index 92cd62b597..0eab71dc45 100644 --- a/components/cli/cli/command/volume/list_test.go +++ b/components/cli/cli/command/volume/list_test.go @@ -1,7 +1,6 @@ package volume import ( - "bytes" "io/ioutil" "testing" @@ -14,7 +13,7 @@ import ( // Import builders to get the builder function as package function . "github.com/docker/cli/cli/internal/test/builders" "github.com/docker/docker/pkg/testutil" - "github.com/docker/docker/pkg/testutil/golden" + "github.com/gotestyourself/gotestyourself/golden" "github.com/stretchr/testify/assert" ) @@ -37,11 +36,10 @@ func TestVolumeListErrors(t *testing.T) { }, } for _, tc := range testCases { - buf := new(bytes.Buffer) cmd := newListCommand( - test.NewFakeCliWithOutput(&fakeClient{ + test.NewFakeCli(&fakeClient{ volumeListFunc: tc.volumeListFunc, - }, buf), + }), ) cmd.SetArgs(tc.args) for key, value := range tc.flags { @@ -53,8 +51,7 @@ func TestVolumeListErrors(t *testing.T) { } func TestVolumeListWithoutFormat(t *testing.T) { - buf := new(bytes.Buffer) - cli := test.NewFakeCliWithOutput(&fakeClient{ + cli := test.NewFakeCli(&fakeClient{ volumeListFunc: func(filter filters.Args) (volumetypes.VolumesListOKBody, error) { return volumetypes.VolumesListOKBody{ Volumes: []*types.Volume{ @@ -66,17 +63,14 @@ func TestVolumeListWithoutFormat(t *testing.T) { }, }, nil }, - }, buf) + }) cmd := newListCommand(cli) assert.NoError(t, cmd.Execute()) - actual := buf.String() - expected := golden.Get(t, []byte(actual), "volume-list-without-format.golden") - testutil.EqualNormalizedString(t, testutil.RemoveSpace, actual, string(expected)) + golden.Assert(t, cli.OutBuffer().String(), "volume-list-without-format.golden") } func TestVolumeListWithConfigFormat(t *testing.T) { - buf := new(bytes.Buffer) - cli := test.NewFakeCliWithOutput(&fakeClient{ + cli := test.NewFakeCli(&fakeClient{ volumeListFunc: func(filter filters.Args) (volumetypes.VolumesListOKBody, error) { return volumetypes.VolumesListOKBody{ Volumes: []*types.Volume{ @@ -88,20 +82,17 @@ func TestVolumeListWithConfigFormat(t *testing.T) { }, }, nil }, - }, buf) + }) cli.SetConfigFile(&configfile.ConfigFile{ VolumesFormat: "{{ .Name }} {{ .Driver }} {{ .Labels }}", }) cmd := newListCommand(cli) assert.NoError(t, cmd.Execute()) - actual := buf.String() - expected := golden.Get(t, []byte(actual), "volume-list-with-config-format.golden") - testutil.EqualNormalizedString(t, testutil.RemoveSpace, actual, string(expected)) + golden.Assert(t, cli.OutBuffer().String(), "volume-list-with-config-format.golden") } func TestVolumeListWithFormat(t *testing.T) { - buf := new(bytes.Buffer) - cli := test.NewFakeCliWithOutput(&fakeClient{ + cli := test.NewFakeCli(&fakeClient{ volumeListFunc: func(filter filters.Args) (volumetypes.VolumesListOKBody, error) { return volumetypes.VolumesListOKBody{ Volumes: []*types.Volume{ @@ -113,11 +104,9 @@ func TestVolumeListWithFormat(t *testing.T) { }, }, nil }, - }, buf) + }) cmd := newListCommand(cli) cmd.Flags().Set("format", "{{ .Name }} {{ .Driver }} {{ .Labels }}") assert.NoError(t, cmd.Execute()) - actual := buf.String() - expected := golden.Get(t, []byte(actual), "volume-list-with-format.golden") - testutil.EqualNormalizedString(t, testutil.RemoveSpace, actual, string(expected)) + golden.Assert(t, cli.OutBuffer().String(), "volume-list-with-format.golden") } diff --git a/components/cli/cli/command/volume/prune_test.go b/components/cli/cli/command/volume/prune_test.go index cf26d283f4..ccb5b15e39 100644 --- a/components/cli/cli/command/volume/prune_test.go +++ b/components/cli/cli/command/volume/prune_test.go @@ -1,7 +1,6 @@ package volume import ( - "bytes" "fmt" "io/ioutil" "runtime" @@ -13,7 +12,8 @@ import ( "github.com/docker/docker/api/types" "github.com/docker/docker/api/types/filters" "github.com/docker/docker/pkg/testutil" - "github.com/docker/docker/pkg/testutil/golden" + "github.com/gotestyourself/gotestyourself/golden" + "github.com/gotestyourself/gotestyourself/skip" "github.com/pkg/errors" "github.com/stretchr/testify/assert" ) @@ -41,9 +41,9 @@ func TestVolumePruneErrors(t *testing.T) { } for _, tc := range testCases { cmd := NewPruneCommand( - test.NewFakeCliWithOutput(&fakeClient{ + test.NewFakeCli(&fakeClient{ volumePruneFunc: tc.volumePruneFunc, - }, ioutil.Discard), + }), ) cmd.SetArgs(tc.args) for key, value := range tc.flags { @@ -68,60 +68,45 @@ func TestVolumePruneForce(t *testing.T) { }, } for _, tc := range testCases { - buf := new(bytes.Buffer) - cmd := NewPruneCommand( - test.NewFakeCliWithOutput(&fakeClient{ - volumePruneFunc: tc.volumePruneFunc, - }, buf), - ) + cli := test.NewFakeCli(&fakeClient{ + volumePruneFunc: tc.volumePruneFunc, + }) + cmd := NewPruneCommand(cli) cmd.Flags().Set("force", "true") assert.NoError(t, cmd.Execute()) - actual := buf.String() - expected := golden.Get(t, []byte(actual), fmt.Sprintf("volume-prune.%s.golden", tc.name)) - testutil.EqualNormalizedString(t, testutil.RemoveSpace, actual, string(expected)) + golden.Assert(t, cli.OutBuffer().String(), fmt.Sprintf("volume-prune.%s.golden", tc.name)) } } + func TestVolumePrunePromptYes(t *testing.T) { - if runtime.GOOS == "windows" { - // FIXME(vdemeester) make it work.. - t.Skip("skipping this test on Windows") - } + // FIXME(vdemeester) make it work.. + skip.IfCondition(t, runtime.GOOS == "windows", "TODO: fix test on windows") + for _, input := range []string{"y", "Y"} { - buf := new(bytes.Buffer) - cli := test.NewFakeCliWithOutput(&fakeClient{ + cli := test.NewFakeCli(&fakeClient{ volumePruneFunc: simplePruneFunc, - }, buf) + }) cli.SetIn(command.NewInStream(ioutil.NopCloser(strings.NewReader(input)))) - cmd := NewPruneCommand( - cli, - ) + cmd := NewPruneCommand(cli) assert.NoError(t, cmd.Execute()) - actual := buf.String() - expected := golden.Get(t, []byte(actual), "volume-prune-yes.golden") - testutil.EqualNormalizedString(t, testutil.RemoveSpace, actual, string(expected)) + golden.Assert(t, cli.OutBuffer().String(), "volume-prune-yes.golden") } } func TestVolumePrunePromptNo(t *testing.T) { - if runtime.GOOS == "windows" { - // FIXME(vdemeester) make it work.. - t.Skip("skipping this test on Windows") - } + // FIXME(vdemeester) make it work.. + skip.IfCondition(t, runtime.GOOS == "windows", "TODO: fix test on windows") + for _, input := range []string{"n", "N", "no", "anything", "really"} { - buf := new(bytes.Buffer) - cli := test.NewFakeCliWithOutput(&fakeClient{ + cli := test.NewFakeCli(&fakeClient{ volumePruneFunc: simplePruneFunc, - }, buf) + }) cli.SetIn(command.NewInStream(ioutil.NopCloser(strings.NewReader(input)))) - cmd := NewPruneCommand( - cli, - ) + cmd := NewPruneCommand(cli) assert.NoError(t, cmd.Execute()) - actual := buf.String() - expected := golden.Get(t, []byte(actual), "volume-prune-no.golden") - testutil.EqualNormalizedString(t, testutil.RemoveSpace, actual, string(expected)) + golden.Assert(t, cli.OutBuffer().String(), "volume-prune-no.golden") } } diff --git a/components/cli/cli/command/volume/remove_test.go b/components/cli/cli/command/volume/remove_test.go index 3d01905681..c10b18cc47 100644 --- a/components/cli/cli/command/volume/remove_test.go +++ b/components/cli/cli/command/volume/remove_test.go @@ -1,7 +1,6 @@ package volume import ( - "bytes" "io/ioutil" "testing" @@ -29,11 +28,10 @@ func TestVolumeRemoveErrors(t *testing.T) { }, } for _, tc := range testCases { - buf := new(bytes.Buffer) cmd := newRemoveCommand( - test.NewFakeCliWithOutput(&fakeClient{ + test.NewFakeCli(&fakeClient{ volumeRemoveFunc: tc.volumeRemoveFunc, - }, buf)) + })) cmd.SetArgs(tc.args) cmd.SetOutput(ioutil.Discard) testutil.ErrorContains(t, cmd.Execute(), tc.expectedError) @@ -41,8 +39,7 @@ func TestVolumeRemoveErrors(t *testing.T) { } func TestNodeRemoveMultiple(t *testing.T) { - buf := new(bytes.Buffer) - cmd := newRemoveCommand(test.NewFakeCliWithOutput(&fakeClient{}, buf)) + cmd := newRemoveCommand(test.NewFakeCli(&fakeClient{})) cmd.SetArgs([]string{"volume1", "volume2"}) assert.NoError(t, cmd.Execute()) } diff --git a/components/cli/cli/internal/test/cli.go b/components/cli/cli/internal/test/cli.go index 54b3bc83b1..0b3ee28978 100644 --- a/components/cli/cli/internal/test/cli.go +++ b/components/cli/cli/internal/test/cli.go @@ -23,14 +23,6 @@ type FakeCli struct { server command.ServerInfo } -// NewFakeCliWithOutput returns a Cli backed by the fakeCli -// Deprecated: Use NewFakeCli -func NewFakeCliWithOutput(client client.APIClient, out io.Writer) *FakeCli { - cli := NewFakeCli(client) - cli.out = command.NewOutStream(out) - return cli -} - // NewFakeCli returns a fake for the command.Cli interface func NewFakeCli(client client.APIClient) *FakeCli { outBuffer := new(bytes.Buffer) From 55bd0229fa77ebac8964e643fe26471dce232ed5 Mon Sep 17 00:00:00 2001 From: Daniel Nephin Date: Wed, 16 Aug 2017 14:07:49 -0400 Subject: [PATCH 21/47] Replace pkg/testutil/tempfile with gotestyourself/fs Signed-off-by: Daniel Nephin Upstream-commit: 15837afa777c61dbdcbea4c9e32251b43f647a72 Component: cli --- .../cli/cli/command/stack/deploy_composefile_test.go | 8 ++++---- components/cli/cli/compose/convert/compose_test.go | 10 +++++----- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/components/cli/cli/command/stack/deploy_composefile_test.go b/components/cli/cli/command/stack/deploy_composefile_test.go index 5d59ff7028..8d09ab056c 100644 --- a/components/cli/cli/command/stack/deploy_composefile_test.go +++ b/components/cli/cli/command/stack/deploy_composefile_test.go @@ -8,7 +8,7 @@ import ( "github.com/docker/cli/cli/internal/test/network" "github.com/docker/docker/api/types" "github.com/docker/docker/pkg/testutil" - "github.com/docker/docker/pkg/testutil/tempfile" + "github.com/gotestyourself/gotestyourself/fs" "github.com/pkg/errors" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" @@ -22,12 +22,12 @@ services: foo: image: alpine:3.5 ` - file := tempfile.NewTempFile(t, "test-get-config-details", content) + file := fs.NewFile(t, "test-get-config-details", fs.WithContent(content)) defer file.Remove() - details, err := getConfigDetails(file.Name()) + details, err := getConfigDetails(file.Path()) require.NoError(t, err) - assert.Equal(t, filepath.Dir(file.Name()), details.WorkingDir) + assert.Equal(t, filepath.Dir(file.Path()), details.WorkingDir) assert.Len(t, details.ConfigFiles, 1) assert.Len(t, details.Environment, len(os.Environ())) } diff --git a/components/cli/cli/compose/convert/compose_test.go b/components/cli/cli/compose/convert/compose_test.go index 57849dd9bc..bde0942069 100644 --- a/components/cli/cli/compose/convert/compose_test.go +++ b/components/cli/cli/compose/convert/compose_test.go @@ -6,7 +6,7 @@ import ( composetypes "github.com/docker/cli/cli/compose/types" "github.com/docker/docker/api/types" "github.com/docker/docker/api/types/network" - "github.com/docker/docker/pkg/testutil/tempfile" + "github.com/gotestyourself/gotestyourself/fs" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) @@ -107,12 +107,12 @@ func TestSecrets(t *testing.T) { namespace := Namespace{name: "foo"} secretText := "this is the first secret" - secretFile := tempfile.NewTempFile(t, "convert-secrets", secretText) + secretFile := fs.NewFile(t, "convert-secrets", fs.WithContent(secretText)) defer secretFile.Remove() source := map[string]composetypes.SecretConfig{ "one": { - File: secretFile.Name(), + File: secretFile.Path(), Labels: map[string]string{"monster": "mash"}, }, "ext": { @@ -138,12 +138,12 @@ func TestConfigs(t *testing.T) { namespace := Namespace{name: "foo"} configText := "this is the first config" - configFile := tempfile.NewTempFile(t, "convert-configs", configText) + configFile := fs.NewFile(t, "convert-configs", fs.WithContent(configText)) defer configFile.Remove() source := map[string]composetypes.ConfigObjConfig{ "one": { - File: configFile.Name(), + File: configFile.Path(), Labels: map[string]string{"monster": "mash"}, }, "ext": { From cded911aad2ad38c10756a467eead2e899d163df Mon Sep 17 00:00:00 2001 From: Jimmy Leger Date: Thu, 20 Jul 2017 10:32:51 +0200 Subject: [PATCH 22/47] Add 'docker service rollback' subcommand Signed-off-by: Jimmy Leger Implement runRollback to not use runUpdate Signed-off-by: Jimmy Leger Add version tag and add flag quiet to suppress progress output Signed-off-by: Jimmy Leger Removed flags from warnDetachDefault Signed-off-by: Jimmy Leger Used command.Cli interface Signed-off-by: Jimmy Leger Add detach flag on rollback command Signed-off-by: Jimmy Leger Create a fakeClient for service commands Signed-off-by: Jimmy Leger Added unit test for rollback command Signed-off-by: Jimmy Leger Used command.Cli interface instead of *command.DockerCli in service commands Signed-off-by: Jimmy Leger Revert "Removed flags from warnDetachDefault" This reverts commit 3e4f601c8a82cc2599a755dc693409bbc47917fc. Signed-off-by: Jimmy Leger Fixed test.NewFakeCli instanciation Signed-off-by: Jimmy Leger Removed unused receiver Signed-off-by: Jimmy Leger Replaced cli by dockerCli Signed-off-by: Jimmy Leger Revert "Removed unused receiver" This reverts commit 604ef7c13df3d019949ca81d992db501114dafce. Signed-off-by: Jimmy Leger Fixed last typo Signed-off-by: Jimmy Leger Upstream-commit: 11d471d6601617d0507e27dfa228563b7b9e0654 Component: cli --- .../cli/cli/command/service/client_test.go | 33 +++++- components/cli/cli/command/service/cmd.go | 1 + components/cli/cli/command/service/create.go | 4 +- components/cli/cli/command/service/helpers.go | 2 +- components/cli/cli/command/service/inspect.go | 4 +- components/cli/cli/command/service/remove.go | 4 +- .../cli/cli/command/service/rollback.go | 65 +++++++++++ .../cli/cli/command/service/rollback_test.go | 104 ++++++++++++++++++ components/cli/cli/command/service/scale.go | 6 +- components/cli/cli/command/service/update.go | 4 +- .../reference/commandline/service_create.md | 5 +- .../reference/commandline/service_inspect.md | 5 +- .../reference/commandline/service_logs.md | 5 +- .../docs/reference/commandline/service_ls.md | 5 +- .../docs/reference/commandline/service_ps.md | 1 + .../docs/reference/commandline/service_rm.md | 3 +- .../reference/commandline/service_rollback.md | 94 ++++++++++++++++ .../reference/commandline/service_scale.md | 1 + .../reference/commandline/service_update.md | 7 +- 19 files changed, 323 insertions(+), 30 deletions(-) create mode 100644 components/cli/cli/command/service/rollback.go create mode 100644 components/cli/cli/command/service/rollback_test.go create mode 100644 components/cli/docs/reference/commandline/service_rollback.md diff --git a/components/cli/cli/command/service/client_test.go b/components/cli/cli/command/service/client_test.go index b4f8905159..a886ff6a6d 100644 --- a/components/cli/cli/command/service/client_test.go +++ b/components/cli/cli/command/service/client_test.go @@ -5,17 +5,18 @@ import ( "github.com/docker/docker/api/types/swarm" "github.com/docker/docker/client" "golang.org/x/net/context" + // Import builders to get the builder function as package function + . "github.com/docker/cli/cli/internal/test/builders" ) type fakeClient struct { client.Client - serviceListFunc func(context.Context, types.ServiceListOptions) ([]swarm.Service, error) + serviceInspectWithRawFunc func(ctx context.Context, serviceID string, options types.ServiceInspectOptions) (swarm.Service, []byte, error) + serviceUpdateFunc func(ctx context.Context, serviceID string, version swarm.Version, service swarm.ServiceSpec, options types.ServiceUpdateOptions) (types.ServiceUpdateResponse, error) + serviceListFunc func(context.Context, types.ServiceListOptions) ([]swarm.Service, error) } -func (f *fakeClient) ServiceList(ctx context.Context, options types.ServiceListOptions) ([]swarm.Service, error) { - if f.serviceListFunc != nil { - return f.serviceListFunc(ctx, options) - } +func (f *fakeClient) NodeList(ctx context.Context, options types.NodeListOptions) ([]swarm.Node, error) { return nil, nil } @@ -23,10 +24,30 @@ func (f *fakeClient) TaskList(ctx context.Context, options types.TaskListOptions return nil, nil } -func (f *fakeClient) NodeList(ctx context.Context, options types.NodeListOptions) ([]swarm.Node, error) { +func (f *fakeClient) ServiceInspectWithRaw(ctx context.Context, serviceID string, options types.ServiceInspectOptions) (swarm.Service, []byte, error) { + if f.serviceInspectWithRawFunc != nil { + return f.serviceInspectWithRawFunc(ctx, serviceID, options) + } + + return *Service(ServiceID(serviceID)), []byte{}, nil +} + +func (f *fakeClient) ServiceList(ctx context.Context, options types.ServiceListOptions) ([]swarm.Service, error) { + if f.serviceListFunc != nil { + return f.serviceListFunc(ctx, options) + } + return nil, nil } +func (f *fakeClient) ServiceUpdate(ctx context.Context, serviceID string, version swarm.Version, service swarm.ServiceSpec, options types.ServiceUpdateOptions) (types.ServiceUpdateResponse, error) { + if f.serviceUpdateFunc != nil { + return f.serviceUpdateFunc(ctx, serviceID, version, service, options) + } + + return types.ServiceUpdateResponse{}, nil +} + func newService(id string, name string) swarm.Service { return swarm.Service{ ID: id, diff --git a/components/cli/cli/command/service/cmd.go b/components/cli/cli/command/service/cmd.go index 94e3a97d4e..107abf32d0 100644 --- a/components/cli/cli/command/service/cmd.go +++ b/components/cli/cli/command/service/cmd.go @@ -26,6 +26,7 @@ func NewServiceCommand(dockerCli *command.DockerCli) *cobra.Command { newScaleCommand(dockerCli), newUpdateCommand(dockerCli), newLogsCommand(dockerCli), + newRollbackCommand(dockerCli), ) return cmd } diff --git a/components/cli/cli/command/service/create.go b/components/cli/cli/command/service/create.go index e4b42a45ce..ecf7a37e28 100644 --- a/components/cli/cli/command/service/create.go +++ b/components/cli/cli/command/service/create.go @@ -12,7 +12,7 @@ import ( "golang.org/x/net/context" ) -func newCreateCommand(dockerCli *command.DockerCli) *cobra.Command { +func newCreateCommand(dockerCli command.Cli) *cobra.Command { opts := newServiceOptions() cmd := &cobra.Command{ @@ -62,7 +62,7 @@ func newCreateCommand(dockerCli *command.DockerCli) *cobra.Command { return cmd } -func runCreate(dockerCli *command.DockerCli, flags *pflag.FlagSet, opts *serviceOptions) error { +func runCreate(dockerCli command.Cli, flags *pflag.FlagSet, opts *serviceOptions) error { apiClient := dockerCli.Client() createOpts := types.ServiceCreateOptions{} diff --git a/components/cli/cli/command/service/helpers.go b/components/cli/cli/command/service/helpers.go index 8fb82c7cca..de6878c17b 100644 --- a/components/cli/cli/command/service/helpers.go +++ b/components/cli/cli/command/service/helpers.go @@ -15,7 +15,7 @@ import ( // waitOnService waits for the service to converge. It outputs a progress bar, // if appropriate based on the CLI flags. -func waitOnService(ctx context.Context, dockerCli *command.DockerCli, serviceID string, quiet bool) error { +func waitOnService(ctx context.Context, dockerCli command.Cli, serviceID string, quiet bool) error { errChan := make(chan error, 1) pipeReader, pipeWriter := io.Pipe() diff --git a/components/cli/cli/command/service/inspect.go b/components/cli/cli/command/service/inspect.go index ea0009d3a5..dbe8ac8ddc 100644 --- a/components/cli/cli/command/service/inspect.go +++ b/components/cli/cli/command/service/inspect.go @@ -20,7 +20,7 @@ type inspectOptions struct { pretty bool } -func newInspectCommand(dockerCli *command.DockerCli) *cobra.Command { +func newInspectCommand(dockerCli command.Cli) *cobra.Command { var opts inspectOptions cmd := &cobra.Command{ @@ -43,7 +43,7 @@ func newInspectCommand(dockerCli *command.DockerCli) *cobra.Command { return cmd } -func runInspect(dockerCli *command.DockerCli, opts inspectOptions) error { +func runInspect(dockerCli command.Cli, opts inspectOptions) error { client := dockerCli.Client() ctx := context.Background() diff --git a/components/cli/cli/command/service/remove.go b/components/cli/cli/command/service/remove.go index bc6a202f64..38833b2e7e 100644 --- a/components/cli/cli/command/service/remove.go +++ b/components/cli/cli/command/service/remove.go @@ -11,7 +11,7 @@ import ( "golang.org/x/net/context" ) -func newRemoveCommand(dockerCli *command.DockerCli) *cobra.Command { +func newRemoveCommand(dockerCli command.Cli) *cobra.Command { cmd := &cobra.Command{ Use: "rm SERVICE [SERVICE...]", @@ -27,7 +27,7 @@ func newRemoveCommand(dockerCli *command.DockerCli) *cobra.Command { return cmd } -func runRemove(dockerCli *command.DockerCli, sids []string) error { +func runRemove(dockerCli command.Cli, sids []string) error { client := dockerCli.Client() ctx := context.Background() diff --git a/components/cli/cli/command/service/rollback.go b/components/cli/cli/command/service/rollback.go new file mode 100644 index 0000000000..5cef656255 --- /dev/null +++ b/components/cli/cli/command/service/rollback.go @@ -0,0 +1,65 @@ +package service + +import ( + "context" + "fmt" + + "github.com/docker/cli/cli" + "github.com/docker/cli/cli/command" + "github.com/docker/docker/api/types" + "github.com/spf13/cobra" + "github.com/spf13/pflag" +) + +func newRollbackCommand(dockerCli command.Cli) *cobra.Command { + options := newServiceOptions() + + cmd := &cobra.Command{ + Use: "rollback [OPTIONS] SERVICE", + Short: "Revert changes to a service's configuration", + Args: cli.ExactArgs(1), + RunE: func(cmd *cobra.Command, args []string) error { + return runRollback(dockerCli, cmd.Flags(), options, args[0]) + }, + Tags: map[string]string{"version": "1.31"}, + } + + flags := cmd.Flags() + flags.BoolVarP(&options.quiet, flagQuiet, "q", false, "Suppress progress output") + addDetachFlag(flags, &options.detach) + + return cmd +} + +func runRollback(dockerCli command.Cli, flags *pflag.FlagSet, options *serviceOptions, serviceID string) error { + apiClient := dockerCli.Client() + ctx := context.Background() + + service, _, err := apiClient.ServiceInspectWithRaw(ctx, serviceID, types.ServiceInspectOptions{}) + if err != nil { + return err + } + + spec := &service.Spec + updateOpts := types.ServiceUpdateOptions{ + Rollback: "previous", + } + + response, err := apiClient.ServiceUpdate(ctx, service.ID, service.Version, *spec, updateOpts) + if err != nil { + return err + } + + for _, warning := range response.Warnings { + fmt.Fprintln(dockerCli.Err(), warning) + } + + fmt.Fprintf(dockerCli.Out(), "%s\n", serviceID) + + if options.detach { + warnDetachDefault(dockerCli.Err(), apiClient.ClientVersion(), flags, "rolled back") + return nil + } + + return waitOnService(ctx, dockerCli, serviceID, options.quiet) +} diff --git a/components/cli/cli/command/service/rollback_test.go b/components/cli/cli/command/service/rollback_test.go new file mode 100644 index 0000000000..48be5076d7 --- /dev/null +++ b/components/cli/cli/command/service/rollback_test.go @@ -0,0 +1,104 @@ +package service + +import ( + "fmt" + "io/ioutil" + "strings" + "testing" + + "github.com/docker/cli/cli/internal/test" + "github.com/docker/docker/api/types" + "github.com/docker/docker/api/types/swarm" + "github.com/docker/docker/pkg/testutil" + "github.com/stretchr/testify/assert" + "golang.org/x/net/context" +) + +func TestRollback(t *testing.T) { + testCases := []struct { + name string + args []string + serviceUpdateFunc func(ctx context.Context, serviceID string, version swarm.Version, service swarm.ServiceSpec, options types.ServiceUpdateOptions) (types.ServiceUpdateResponse, error) + expectedDockerCliErr string + }{ + { + name: "rollback-service", + args: []string{"service-id"}, + }, + { + name: "rollback-service-with-warnings", + args: []string{"service-id"}, + serviceUpdateFunc: func(ctx context.Context, serviceID string, version swarm.Version, service swarm.ServiceSpec, options types.ServiceUpdateOptions) (types.ServiceUpdateResponse, error) { + response := types.ServiceUpdateResponse{} + + response.Warnings = []string{ + "- warning 1", + "- warning 2", + } + + return response, nil + }, + expectedDockerCliErr: "- warning 1\n- warning 2", + }, + } + + for _, tc := range testCases { + cli := test.NewFakeCli(&fakeClient{ + serviceUpdateFunc: tc.serviceUpdateFunc, + }) + cmd := newRollbackCommand(cli) + cmd.SetArgs(tc.args) + cmd.Flags().Set("quiet", "true") + cmd.SetOutput(ioutil.Discard) + assert.NoError(t, cmd.Execute()) + assert.Equal(t, strings.TrimSpace(cli.ErrBuffer().String()), tc.expectedDockerCliErr) + } +} + +func TestRollbackWithErrors(t *testing.T) { + testCases := []struct { + name string + args []string + serviceInspectWithRawFunc func(ctx context.Context, serviceID string, options types.ServiceInspectOptions) (swarm.Service, []byte, error) + serviceUpdateFunc func(ctx context.Context, serviceID string, version swarm.Version, service swarm.ServiceSpec, options types.ServiceUpdateOptions) (types.ServiceUpdateResponse, error) + expectedError string + }{ + { + name: "not-enough-args", + expectedError: "requires exactly 1 argument", + }, + { + name: "too-many-args", + args: []string{"service-id-1", "service-id-2"}, + expectedError: "requires exactly 1 argument", + }, + { + name: "service-does-not-exists", + args: []string{"service-id"}, + serviceInspectWithRawFunc: func(ctx context.Context, serviceID string, options types.ServiceInspectOptions) (swarm.Service, []byte, error) { + return swarm.Service{}, []byte{}, fmt.Errorf("no such services: %s", serviceID) + }, + expectedError: "no such services: service-id", + }, + { + name: "service-update-failed", + args: []string{"service-id"}, + serviceUpdateFunc: func(ctx context.Context, serviceID string, version swarm.Version, service swarm.ServiceSpec, options types.ServiceUpdateOptions) (types.ServiceUpdateResponse, error) { + return types.ServiceUpdateResponse{}, fmt.Errorf("no such services: %s", serviceID) + }, + expectedError: "no such services: service-id", + }, + } + + for _, tc := range testCases { + cmd := newRollbackCommand( + test.NewFakeCli(&fakeClient{ + serviceInspectWithRawFunc: tc.serviceInspectWithRawFunc, + serviceUpdateFunc: tc.serviceUpdateFunc, + })) + cmd.SetArgs(tc.args) + cmd.Flags().Set("quiet", "true") + cmd.SetOutput(ioutil.Discard) + testutil.ErrorContains(t, cmd.Execute(), tc.expectedError) + } +} diff --git a/components/cli/cli/command/service/scale.go b/components/cli/cli/command/service/scale.go index f58786156a..4910d4fa50 100644 --- a/components/cli/cli/command/service/scale.go +++ b/components/cli/cli/command/service/scale.go @@ -19,7 +19,7 @@ type scaleOptions struct { detach bool } -func newScaleCommand(dockerCli *command.DockerCli) *cobra.Command { +func newScaleCommand(dockerCli command.Cli) *cobra.Command { options := &scaleOptions{} cmd := &cobra.Command{ @@ -54,7 +54,7 @@ func scaleArgs(cmd *cobra.Command, args []string) error { return nil } -func runScale(dockerCli *command.DockerCli, flags *pflag.FlagSet, options *scaleOptions, args []string) error { +func runScale(dockerCli command.Cli, flags *pflag.FlagSet, options *scaleOptions, args []string) error { var errs []string var serviceIDs []string ctx := context.Background() @@ -96,7 +96,7 @@ func runScale(dockerCli *command.DockerCli, flags *pflag.FlagSet, options *scale return errors.Errorf(strings.Join(errs, "\n")) } -func runServiceScale(ctx context.Context, dockerCli *command.DockerCli, serviceID string, scale uint64) error { +func runServiceScale(ctx context.Context, dockerCli command.Cli, serviceID string, scale uint64) error { client := dockerCli.Client() service, _, err := client.ServiceInspectWithRaw(ctx, serviceID, types.ServiceInspectOptions{}) diff --git a/components/cli/cli/command/service/update.go b/components/cli/cli/command/service/update.go index dba05a1b1e..90057adedf 100644 --- a/components/cli/cli/command/service/update.go +++ b/components/cli/cli/command/service/update.go @@ -22,7 +22,7 @@ import ( "golang.org/x/net/context" ) -func newUpdateCommand(dockerCli *command.DockerCli) *cobra.Command { +func newUpdateCommand(dockerCli command.Cli) *cobra.Command { options := newServiceOptions() cmd := &cobra.Command{ @@ -103,7 +103,7 @@ func newListOptsVar() *opts.ListOpts { } // nolint: gocyclo -func runUpdate(dockerCli *command.DockerCli, flags *pflag.FlagSet, options *serviceOptions, serviceID string) error { +func runUpdate(dockerCli command.Cli, flags *pflag.FlagSet, options *serviceOptions, serviceID string) error { apiClient := dockerCli.Client() ctx := context.Background() diff --git a/components/cli/docs/reference/commandline/service_create.md b/components/cli/docs/reference/commandline/service_create.md index 184e9f952a..c376fc02d9 100644 --- a/components/cli/docs/reference/commandline/service_create.md +++ b/components/cli/docs/reference/commandline/service_create.md @@ -877,9 +877,10 @@ x3ti0erg11rjpg64m75kej2mz-hosttempl * [service inspect](service_inspect.md) * [service logs](service_logs.md) * [service ls](service_ls.md) -* [service rm](service_rm.md) -* [service scale](service_scale.md) * [service ps](service_ps.md) +* [service rm](service_rm.md) +* [service rollback](service_rollback.md) +* [service scale](service_scale.md) * [service update](service_update.md) diff --git a/components/cli/docs/reference/commandline/service_inspect.md b/components/cli/docs/reference/commandline/service_inspect.md index af09b52be2..cbc954a5ae 100644 --- a/components/cli/docs/reference/commandline/service_inspect.md +++ b/components/cli/docs/reference/commandline/service_inspect.md @@ -164,7 +164,8 @@ $ docker service inspect --format='{{.Spec.Mode.Replicated.Replicas}}' redis * [service create](service_create.md) * [service logs](service_logs.md) * [service ls](service_ls.md) -* [service rm](service_rm.md) -* [service scale](service_scale.md) * [service ps](service_ps.md) +* [service rm](service_rm.md) +* [service rollback](service_rollback.md) +* [service scale](service_scale.md) * [service update](service_update.md) diff --git a/components/cli/docs/reference/commandline/service_logs.md b/components/cli/docs/reference/commandline/service_logs.md index cf12169bcf..4f8f35a62d 100644 --- a/components/cli/docs/reference/commandline/service_logs.md +++ b/components/cli/docs/reference/commandline/service_logs.md @@ -79,7 +79,8 @@ fraction of a second no more than nine digits long. You can combine the * [service create](service_create.md) * [service inspect](service_inspect.md) * [service ls](service_ls.md) -* [service rm](service_rm.md) -* [service scale](service_scale.md) * [service ps](service_ps.md) +* [service rm](service_rm.md) +* [service rollback](service_rollback.md) +* [service scale](service_scale.md) * [service update](service_update.md) diff --git a/components/cli/docs/reference/commandline/service_ls.md b/components/cli/docs/reference/commandline/service_ls.md index 1625dd254d..4ee551be3c 100644 --- a/components/cli/docs/reference/commandline/service_ls.md +++ b/components/cli/docs/reference/commandline/service_ls.md @@ -158,7 +158,8 @@ fm6uf97exkul: global 5/5 * [service create](service_create.md) * [service inspect](service_inspect.md) * [service logs](service_logs.md) -* [service rm](service_rm.md) -* [service scale](service_scale.md) * [service ps](service_ps.md) +* [service rm](service_rm.md) +* [service rollback](service_rollback.md) +* [service scale](service_scale.md) * [service update](service_update.md) diff --git a/components/cli/docs/reference/commandline/service_ps.md b/components/cli/docs/reference/commandline/service_ps.md index 51e3a28afe..88a963ae68 100644 --- a/components/cli/docs/reference/commandline/service_ps.md +++ b/components/cli/docs/reference/commandline/service_ps.md @@ -190,5 +190,6 @@ top.3: busybox * [service logs](service_logs.md) * [service ls](service_ls.md) * [service rm](service_rm.md) +* [service rollback](service_rollback.md) * [service scale](service_scale.md) * [service update](service_update.md) diff --git a/components/cli/docs/reference/commandline/service_rm.md b/components/cli/docs/reference/commandline/service_rm.md index 742fc38c80..1e3ada3d7d 100644 --- a/components/cli/docs/reference/commandline/service_rm.md +++ b/components/cli/docs/reference/commandline/service_rm.md @@ -55,6 +55,7 @@ ID NAME MODE REPLICAS IMAGE * [service inspect](service_inspect.md) * [service logs](service_logs.md) * [service ls](service_ls.md) -* [service scale](service_scale.md) * [service ps](service_ps.md) +* [service rollback](service_rollback.md) +* [service scale](service_scale.md) * [service update](service_update.md) diff --git a/components/cli/docs/reference/commandline/service_rollback.md b/components/cli/docs/reference/commandline/service_rollback.md new file mode 100644 index 0000000000..94ac2607e3 --- /dev/null +++ b/components/cli/docs/reference/commandline/service_rollback.md @@ -0,0 +1,94 @@ +--- +title: "service rollback" +description: "The service rollback command description and usage" +keywords: "service, rollback" +--- + + + +# service rollback + +```markdown +Usage: docker service rollback SERVICE + +Revert changes to a service's configuration + +Options: + -d, --detach Exit immediately instead of waiting for the service to converge (default true) + --help Print usage + -q, --quiet Suppress progress output +``` + +## Description + +Roll back a specified service to its previous version from the swarm. This command must be run +targeting a manager node. + +## Examples + +### Roll back to the previous version of a service + +Use the `docker service rollback` command to roll back to the previous version +of a service. After executing this command, the service is reverted to the +configuration that was in place before the most recent `docker service update` +command. + +The following example creates a service with a single replica, updates the +service to use three replicas, and then rolls back the service to the +previous version, having one replica. + +Create a service with a single replica: + +```bash +$ docker service create --name my-service -p 8080:80 nginx:alpine +``` + +Confirm that the service is running with a single replica: + +```bash +$ docker service ls + +ID NAME MODE REPLICAS IMAGE PORTS +xbw728mf6q0d my-service replicated 1/1 nginx:alpine *:8080->80/tcp +``` + +Update the service to use three replicas: + +```bash +$ docker service update --replicas=3 my-service + +$ docker service ls + +ID NAME MODE REPLICAS IMAGE PORTS +xbw728mf6q0d my-service replicated 3/3 nginx:alpine *:8080->80/tcp +``` + +Now roll back the service to its previous version, and confirm it is +running a single replica again: + +```bash +$ docker service rollback my-service + +$ docker service ls + +ID NAME MODE REPLICAS IMAGE PORTS +xbw728mf6q0d my-service replicated 1/1 nginx:alpine *:8080->80/tcp +``` + +## Related commands + +* [service create](service_create.md) +* [service inspect](service_inspect.md) +* [service logs](service_logs.md) +* [service ls](service_ls.md) +* [service ps](service_ps.md) +* [service rm](service_rm.md) +* [service scale](service_scale.md) +* [service update](service_update.md) diff --git a/components/cli/docs/reference/commandline/service_scale.md b/components/cli/docs/reference/commandline/service_scale.md index d16c850480..17a06a3ba3 100644 --- a/components/cli/docs/reference/commandline/service_scale.md +++ b/components/cli/docs/reference/commandline/service_scale.md @@ -101,5 +101,6 @@ ID NAME MODE REPLICAS IMAGE * [service logs](service_logs.md) * [service ls](service_ls.md) * [service rm](service_rm.md) +* [service rollback](service_rollback.md) * [service ps](service_ps.md) * [service update](service_update.md) diff --git a/components/cli/docs/reference/commandline/service_update.md b/components/cli/docs/reference/commandline/service_update.md index 32cc8abed2..ffadb54955 100644 --- a/components/cli/docs/reference/commandline/service_update.md +++ b/components/cli/docs/reference/commandline/service_update.md @@ -174,9 +174,9 @@ $ docker service update --mount-rm /somewhere myservice myservice ``` -### Rolling back to the previous version of a service +### Roll back to the previous version of a service -Use the `--rollback` option to roll back to the previous version of the service. +Use the `--rollback` option to roll back to the previous version of the service. This will revert the service to the configuration that was in place before the most recent `docker service update` command. @@ -193,7 +193,7 @@ ID NAME MODE REPLICAS IMAGE 80bvrzp6vxf3 web replicated 0/5 nginx:alpine ``` -Roll back the `web` service... +Roll back the `web` service... ```bash $ docker service update --rollback web @@ -266,4 +266,5 @@ See [`service create`](./service_create.md#templating) for the reference. * [service ls](service_ls.md) * [service ps](service_ps.md) * [service rm](service_rm.md) +* [service rollback](service_rollback.md) * [service scale](service_scale.md) From 0d15a1c160757bc0c0d0ee7d5b54cb992095dc13 Mon Sep 17 00:00:00 2001 From: Sebastiaan van Stijn Date: Wed, 16 Aug 2017 14:16:30 +0200 Subject: [PATCH 23/47] Fix "liquid" warning on logging plugins page Noticed this warning in the documentation CI: Liquid Warning: Liquid syntax error (line 210): Expected end_of_string but found id in "{{ log stream }}" in engine/extend/plugins_logging.md Signed-off-by: Sebastiaan van Stijn Upstream-commit: d30987f85f866849f31d61810b73aafc324cc237 Component: cli --- components/cli/docs/extend/plugins_logging.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/cli/docs/extend/plugins_logging.md b/components/cli/docs/extend/plugins_logging.md index 43203d3c58..c8df2045b9 100644 --- a/components/cli/docs/extend/plugins_logging.md +++ b/components/cli/docs/extend/plugins_logging.md @@ -213,7 +213,7 @@ to determine what set of logs to read. **Response**: ``` -{{ log stream }} +{% raw %}{{ log stream }}{% endraw %} ``` The response should be the encoded log message using the same format as the From 7048b7f05688dd40ce1f1ccc7f5f194c13f93444 Mon Sep 17 00:00:00 2001 From: Sebastiaan van Stijn Date: Wed, 16 Aug 2017 17:53:57 +0200 Subject: [PATCH 24/47] Fix typo and minor Markdown edits Signed-off-by: Sebastiaan van Stijn Upstream-commit: 9544b70cb304b5219c444eb29e86750805f751dd Component: cli --- components/cli/docs/reference/commandline/build.md | 2 +- components/cli/docs/reference/commandline/run.md | 7 +++++-- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/components/cli/docs/reference/commandline/build.md b/components/cli/docs/reference/commandline/build.md index 1e535edd2b..5f6623756d 100644 --- a/components/cli/docs/reference/commandline/build.md +++ b/components/cli/docs/reference/commandline/build.md @@ -78,7 +78,7 @@ When the `URL` parameter points to the location of a Git repository, the repository acts as the build context. The system recursively fetches the repository and its submodules. The commit history is not preserved. A repository is first pulled into a temporary directory on your local host. After -the that succeeds, the directory is sent to the Docker daemon as the context. +that succeeds, the directory is sent to the Docker daemon as the context. Local copy gives you the ability to access private repositories using local user credentials, VPN's, and so forth. diff --git a/components/cli/docs/reference/commandline/run.md b/components/cli/docs/reference/commandline/run.md index 985707a31a..77bac7d2ae 100644 --- a/components/cli/docs/reference/commandline/run.md +++ b/components/cli/docs/reference/commandline/run.md @@ -753,8 +753,9 @@ is set on the cgroup and applications in a container can query it at `/sys/fs/cg On Windows, this will affect containers differently depending on what type of isolation is used. - With `process` isolation, Windows will report the full memory of the host system, not the limit to applications running inside the container + ```powershell - docker run -it -m 2GB --isolation=process microsoft/nanoserver powershell Get-ComputerInfo *memory* + PS C:\> docker run -it -m 2GB --isolation=process microsoft/nanoserver powershell Get-ComputerInfo *memory* CsTotalPhysicalMemory : 17064509440 CsPhyicallyInstalledMemory : 16777216 @@ -765,9 +766,11 @@ On Windows, this will affect containers differently depending on what type of is OsInUseVirtualMemory : 1957488 OsMaxProcessMemorySize : 137438953344 ``` + - With `hyperv` isolation, Windows will create a utility VM that is big enough to hold the memory limit, plus the minimal OS needed to host the container. That size is reported as "Total Physical Memory." + ```powershell - docker run -it -m 2GB --isolation=hyperv microsoft/nanoserver powershell Get-ComputerInfo *memory* + PS C:\> docker run -it -m 2GB --isolation=hyperv microsoft/nanoserver powershell Get-ComputerInfo *memory* CsTotalPhysicalMemory : 2683355136 CsPhyicallyInstalledMemory : From 6092fc343f0fdef70e42abcf103b1b602a329a84 Mon Sep 17 00:00:00 2001 From: Joffrey F Date: Thu, 17 Aug 2017 15:41:21 -0700 Subject: [PATCH 25/47] Update schemas to prevent invalid properties in deploy.resources Signed-off-by: Joffrey F Upstream-commit: 166707390802ec0b3591f9f9b5aea03941559b59 Component: cli --- components/cli/cli/compose/loader/loader_test.go | 15 +++++++++++++++ components/cli/cli/compose/schema/bindata.go | 10 +++++----- .../compose/schema/data/config_schema_v3.0.json | 3 ++- .../compose/schema/data/config_schema_v3.1.json | 3 ++- .../compose/schema/data/config_schema_v3.2.json | 3 ++- .../compose/schema/data/config_schema_v3.3.json | 3 ++- .../compose/schema/data/config_schema_v3.4.json | 3 ++- 7 files changed, 30 insertions(+), 10 deletions(-) diff --git a/components/cli/cli/compose/loader/loader_test.go b/components/cli/cli/compose/loader/loader_test.go index 4ffc333f31..295e91e1e7 100644 --- a/components/cli/cli/compose/loader/loader_test.go +++ b/components/cli/cli/compose/loader/loader_test.go @@ -584,6 +584,21 @@ services: assert.Contains(t, forbidden, "extends") } +func TestInvalidResource(t *testing.T) { + _, err := loadYAML(` + version: "3" + services: + foo: + image: busybox + deploy: + resources: + impossible: + x: 1 +`) + assert.Error(t, err) + assert.Contains(t, err.Error(), "Additional property impossible is not allowed") +} + func TestInvalidExternalAndDriverCombination(t *testing.T) { _, err := loadYAML(` version: "3" diff --git a/components/cli/cli/compose/schema/bindata.go b/components/cli/cli/compose/schema/bindata.go index cfd6a91c66..7518735138 100644 --- a/components/cli/cli/compose/schema/bindata.go +++ b/components/cli/cli/compose/schema/bindata.go @@ -72,7 +72,7 @@ func (fi bindataFileInfo) Sys() interface{} { return nil } -var _dataConfig_schema_v30Json = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xec\x5a\x4b\x8f\xdb\x38\x12\xbe\xfb\x57\x08\x4a\x6e\x71\x77\x07\xd8\x60\x81\xcd\x6d\x8f\x7b\xda\x39\x4f\x43\x11\x68\xa9\x6c\x33\x4d\x91\x4c\x91\x72\xda\x09\xfc\xdf\x07\xd4\xcb\x14\x4d\x8a\xb2\xad\x3c\x30\x98\x53\xb7\xc5\xaa\x62\xbd\xf8\x55\xb1\xa4\xef\xab\x24\x49\xdf\xaa\x62\x0f\x15\x49\x3f\x26\xe9\x5e\x6b\xf9\xf1\xe9\xe9\xb3\x12\xfc\xa1\x7d\xfa\x28\x70\xf7\x54\x22\xd9\xea\x87\xf7\x1f\x9e\xda\x67\x6f\xd2\xb5\xe1\xa3\xa5\x61\x29\x04\xdf\xd2\x5d\xde\xae\xe4\x87\x7f\x3d\xbe\x7f\x34\xec\x2d\x89\x3e\x4a\x30\x44\x62\xf3\x19\x0a\xdd\x3e\x43\xf8\x52\x53\x04\xc3\xfc\x9c\x1e\x00\x15\x15\x3c\xcd\xd6\x2b\xb3\x26\x51\x48\x40\x4d\x41\xa5\x1f\x13\xa3\x5c\x92\x0c\x24\xfd\x03\x4b\xac\xd2\x48\xf9\x2e\x6d\x1e\x9f\x1a\x09\x49\x92\x2a\xc0\x03\x2d\x2c\x09\x83\xaa\x6f\x9e\xce\xf2\x9f\x06\xb2\xb5\x2b\xd5\x52\xb6\x79\x2e\x89\xd6\x80\xfc\x8f\x4b\xdd\x9a\xe5\x4f\xcf\xe4\xe1\xdb\x7f\x1f\xfe\x7c\xff\xf0\x9f\xc7\xfc\x21\x7b\xf7\x76\xb4\x6c\xfc\x8b\xb0\x6d\xb7\x2f\x61\x4b\x39\xd5\x54\xf0\x61\xff\x74\xa0\x3c\x75\xff\x9d\x86\x8d\x49\x59\x36\xc4\x84\x8d\xf6\xde\x12\xa6\x60\x6c\x33\x07\xfd\x55\xe0\x4b\xcc\xe6\x81\xec\x17\xd9\xdc\xed\xef\xb1\x79\x6c\xce\x41\xb0\xba\x8a\x46\xb0\xa7\xfa\x45\xc6\xb4\xdb\xdf\x17\xbf\x55\x6f\xf4\x24\x6d\x4b\x61\xed\xdd\x28\x38\xca\x76\x9f\xab\x7c\xd9\x16\xf6\xd5\xe0\xac\x80\x97\x4a\x90\x4c\x1c\xcd\xb3\x80\x3f\x5a\x82\x0a\xb8\x4e\x07\x17\x24\x49\xba\xa9\x29\x2b\x5d\x8f\x0a\x0e\xff\x37\x22\x9e\xad\x87\x49\xf2\xdd\x3d\xd8\x96\x9c\x66\x7d\xf4\x2b\x1c\xf0\x61\x3d\x60\xcb\xb0\x5e\x08\xae\xe1\x55\x37\x46\x4d\x6f\xdd\xba\x40\x14\x2f\x80\x5b\xca\x60\x2e\x07\xc1\x9d\x9a\x70\x19\xa3\x4a\xe7\x02\xf3\x92\x16\x3a\x3d\x39\xec\x17\xf2\xe2\xf9\x34\xb0\x5a\xbf\xb2\x95\x47\x60\x5a\x10\x99\x93\xb2\x1c\xd9\x41\x10\xc9\x31\x5d\x27\x29\xd5\x50\x29\xbf\x89\x49\x5a\x73\xfa\xa5\x86\xff\x75\x24\x1a\x6b\x70\xe5\x96\x28\xe4\xf2\x82\x77\x28\x6a\x99\x4b\x82\x26\xc1\xa6\xdd\x9f\x16\xa2\xaa\x08\x5f\x2a\xeb\xae\xb1\x63\x86\xe7\x05\xd7\x84\x72\xc0\x9c\x93\x2a\x96\x48\xe6\xd4\x01\x2f\x55\xde\xd6\xbf\xc9\x34\xda\xe6\x2d\xbf\x72\x04\x0c\xc5\x70\xd1\x78\x94\x7c\x2a\xb1\x5b\x31\x26\xb5\x8d\x6e\xa9\xc3\x98\x2b\x20\x58\xec\x6f\xe4\x17\x15\xa1\x7c\x8e\xef\x80\x6b\x3c\x4a\x41\xdb\x7c\xf9\xed\x12\x01\xf8\x21\x1f\xb0\xe4\x6a\x37\x00\x3f\x50\x14\xbc\xea\x4f\xc3\x1c\x80\x19\x40\xde\xf0\xbf\x4a\xa1\xc0\x75\x8c\x63\xa0\xbd\x34\x98\x3a\xf2\x49\xcf\xf1\xdc\x1b\xbe\x4e\x52\x5e\x57\x1b\x40\xd3\xd2\x8d\x28\xb7\x02\x2b\x62\x94\xed\xf7\xb6\x96\x47\x9e\xf6\x64\x9e\xed\x40\xdb\x06\x53\xd6\x09\xcb\x19\xe5\x2f\xcb\xa7\x38\xbc\x6a\x24\xf9\x5e\x28\x3d\x1f\xc3\x2d\xf6\x3d\x10\xa6\xf7\xc5\x1e\x8a\x97\x09\x76\x9b\x6a\xc4\x2d\x94\x9e\x93\xe4\xb4\x22\xbb\x38\x91\x2c\x62\x24\x8c\x6c\x80\xdd\x64\xe7\xa2\xce\xb7\xc4\x8a\xdd\xce\x90\x86\x32\xee\xa2\x73\xe9\x96\x63\x35\xbf\x44\x7a\x00\x9c\x5b\xc0\x85\x3c\x37\x5c\xee\x62\xbc\x01\x49\xe2\xdd\xe7\x88\xf4\xd3\x63\xdb\x7c\x4e\x9c\xaa\xe6\x3f\xc6\xd2\xcc\x6d\x17\x12\xa7\xee\xfb\x9e\x38\x16\xce\x6b\x28\x46\x51\xa9\x48\x61\xfa\x06\x04\x15\x88\xeb\x99\xb4\x6b\xf6\xf3\x4a\x94\xa1\x04\xbd\x20\x76\x7d\x13\x44\xea\xab\x0b\x61\x72\x53\xff\x38\x2b\x74\xd1\x0b\x44\xc4\x9a\x90\x7a\x73\xd5\x3c\xab\x1b\x4f\xb1\x86\x8e\x30\x4a\x14\xc4\x0f\x7b\xd0\x91\x23\x69\x54\x1e\x3e\xcc\xcc\x09\x1f\xef\xbf\x27\x79\x03\xac\x41\x99\xf3\x7b\xe4\x88\xa8\xb3\x2a\xcd\x71\xf3\x29\x92\x45\x4e\xdb\x0f\x6e\xe1\x25\x2d\xc3\x58\xd1\x20\x84\x7d\xc0\xa4\x40\x7d\x71\xba\x7e\x4e\xb9\x6f\xb7\xbe\xbb\xda\x4b\xa4\x07\xca\x60\x07\xe3\x5b\xcb\x46\x08\x06\x84\x8f\xa0\x07\x81\x94\xb9\xe0\xec\x38\x83\x52\x69\x82\xd1\x0b\x85\x82\xa2\x46\xaa\x8f\xb9\x90\x7a\xf1\x3e\x43\xed\xab\x5c\xd1\x6f\x30\x8e\xe6\x19\xef\x3b\x41\xd9\x88\xe7\xa8\x0a\x7d\x5b\xbd\x56\xba\xa4\x3c\x17\x12\x78\xd4\x3b\x4a\x0b\x99\xef\x90\x14\x90\x4b\x40\x2a\x4a\x9f\x81\x6b\x3b\xd6\x65\x8d\xc4\xec\x7f\x29\x46\xd1\x1d\x27\x2c\xe6\x68\x5d\xc9\xed\x8d\x17\x0b\xad\xe3\xe1\xae\x19\xad\x68\xf8\x1c\x78\x00\x76\x46\x0d\x68\xf1\xdf\x0f\xfb\x13\x90\x7f\xd6\x94\x72\x0d\x3b\x40\x1f\x52\x4e\x74\x1d\xd3\x4d\xc7\x8c\x6e\x63\x4f\x70\x1c\xd0\x09\x3d\x1a\x06\x25\xb6\xda\xcf\xe0\xeb\x45\xbc\x7a\x8d\x86\xbf\x8d\xbc\x75\xa7\x48\xe6\xa5\xbf\x0a\xce\x5d\x35\xb2\x20\xa2\x9e\xbc\x88\x5a\xab\x68\x63\xd8\xd0\x70\x35\xd5\xd4\x0c\xa4\xd6\x14\x73\x51\xbc\x30\x8d\x92\x39\x04\x25\xf5\x6b\xbb\x72\x2c\xbb\x62\x8e\xec\xdc\x59\x7a\x01\xbe\x89\xa2\x4d\x1a\x9d\xc0\x4e\x4f\x37\x3b\xa2\xe0\xe4\x91\x2a\xb2\x71\x66\x6e\xbe\xc3\x6d\xb2\x11\x0f\x71\x8c\x41\xd0\x48\x9d\xb8\x74\x68\x3b\xc2\x13\x50\xbf\xe7\xe0\x40\xd3\x0a\x44\xed\xaf\x59\x2b\x3b\xbf\x3b\xa6\xd4\x9a\xcc\x46\x82\x6a\x51\xba\x31\x7d\x1e\x82\xda\xf7\x17\xd1\xc0\xcd\x39\x24\x08\x92\xd1\x82\xa8\x18\x10\xdd\x71\x41\xad\x65\x49\x34\xe4\xed\x8b\xaa\xab\xa0\x7f\x02\xf3\x25\x41\xc2\x18\x30\xaa\xaa\x39\x18\x9a\x96\xc0\xc8\xf1\xa6\xf2\xd9\xb0\x6f\x09\x65\x35\x42\x4e\x0a\xdd\xbd\x0b\x8b\xe4\x5c\x5a\x09\x4e\xb5\xf0\x22\xc4\xbc\x2d\x2b\xf2\x9a\xf7\xdb\x36\x24\xde\x03\x13\x6c\xeb\xe6\xde\x2d\xad\x4c\x50\xa2\xc6\xe2\xc2\xd9\x37\x87\xe8\x5c\xeb\x03\x19\xd3\xef\x78\x61\x3a\x82\x32\x48\x32\x5c\xfd\xa3\xfc\xd1\xd2\xd2\xf5\x99\xb9\x14\x8c\x16\xc7\xa5\x2c\x2c\x04\x6f\x9d\x3c\x27\x21\xee\xcc\x40\x93\x0e\xa6\x15\xaa\xa4\x8e\x1e\xd6\x86\xe1\x2b\xe5\xa5\xf8\x7a\xc5\x86\xcb\xa5\x92\x64\xa4\x00\x07\xef\xee\x75\xb4\xd2\x48\x28\xd7\x57\x97\xf3\x7b\xcd\xba\xa3\x9a\x0f\xf9\x19\x41\xfd\x81\x2e\xfe\x26\x35\x80\xf4\x85\xac\xa3\xf3\xa0\x0a\x2a\x81\xde\x04\x5c\xe0\xcd\x77\xcc\xc4\x9e\x6c\x81\xaa\x36\x6b\x80\xd8\x51\x99\xfb\xe2\xe2\xb7\x8d\xf8\x90\x30\x8b\x03\x12\x95\xa4\x5a\xea\x74\xcc\x1e\xa9\xa6\xde\x1a\x9c\x4c\x8f\x22\x92\xf0\x38\x22\xa6\x75\x5c\xf7\x8e\x42\xd5\x1b\x0e\x93\x1d\x95\xe5\x4f\xdf\x7b\xde\xf9\xd7\x94\x53\xf8\x52\x72\x1f\xe8\xf5\x6f\x43\x02\x51\x7d\x1e\x7a\xe6\xf5\xe0\xab\x6c\x76\x88\x83\xaf\x22\x96\xd3\xbf\x69\xdf\xdd\x11\x81\xaf\xcf\xbf\xb2\x13\xbc\x03\x5c\xba\x4f\x3c\x22\xd8\xd2\x51\xfd\x03\x2d\x7f\x93\x44\xfc\x79\xf9\xe5\x4c\xb3\xac\x3c\xbb\xbc\x68\x4e\xa5\xc4\xec\x31\x7e\xc7\x91\x8d\xd5\x70\xc9\x3c\x5f\xda\x8d\x61\x79\x6a\x7a\xd1\x93\x04\xc6\xba\xce\xa6\x9d\x13\xa7\x2d\x5f\x30\xc3\x1f\xdf\x4d\x14\x9f\xa9\xd7\x6d\x3f\x08\xb5\x17\x98\x0c\xf9\x63\xea\x74\xac\xbd\x77\x2f\x3f\x17\x0b\x80\x9a\xc5\x7f\xf1\xf1\x98\xb1\x93\x1f\x2f\x06\x21\xdf\xc7\xd3\xbd\xf6\xc3\xaf\x6c\xe4\x1f\x87\xa4\x7d\x79\x6d\x41\x4a\x66\x37\xf1\xa1\x30\x7a\x3f\x29\x73\x67\x8b\xfd\xa7\x5d\x99\x1f\xae\x56\xf6\xdf\xe6\x33\xbc\xd5\x69\xf5\x57\x00\x00\x00\xff\xff\x78\x30\xec\x51\x0e\x2b\x00\x00") +var _dataConfig_schema_v30Json = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xec\x5a\x4b\x8f\xdb\x38\x12\xbe\xfb\x57\x08\x4a\x6e\x71\x77\x07\xd8\x60\x81\xcd\x6d\x8f\x7b\xda\x39\x4f\x43\x11\x68\xa9\x6c\x33\x4d\x91\x4c\x91\x72\xda\x09\xfc\xdf\x07\xd4\xcb\x14\x4d\x8a\xb2\xad\x3c\x30\x98\x53\xb7\xc5\xaa\x62\xbd\xf8\x55\xb1\xa4\xef\xab\x24\x49\xdf\xaa\x62\x0f\x15\x49\x3f\x26\xe9\x5e\x6b\xf9\xf1\xe9\xe9\xb3\x12\xfc\xa1\x7d\xfa\x28\x70\xf7\x54\x22\xd9\xea\x87\xf7\x1f\x9e\xda\x67\x6f\xd2\xb5\xe1\xa3\xa5\x61\x29\x04\xdf\xd2\x5d\xde\xae\xe4\x87\x7f\x3d\xbe\x7f\x34\xec\x2d\x89\x3e\x4a\x30\x44\x62\xf3\x19\x0a\xdd\x3e\x43\xf8\x52\x53\x04\xc3\xfc\x9c\x1e\x00\x15\x15\x3c\xcd\xd6\x2b\xb3\x26\x51\x48\x40\x4d\x41\xa5\x1f\x13\xa3\x5c\x92\x0c\x24\xfd\x03\x4b\xac\xd2\x48\xf9\x2e\x6d\x1e\x9f\x1a\x09\x49\x92\x2a\xc0\x03\x2d\x2c\x09\x83\xaa\x6f\x9e\xce\xf2\x9f\x06\xb2\xb5\x2b\xd5\x52\xb6\x79\x2e\x89\xd6\x80\xfc\x8f\x4b\xdd\x9a\xe5\x4f\xcf\xe4\xe1\xdb\x7f\x1f\xfe\x7c\xff\xf0\x9f\xc7\xfc\x21\x7b\xf7\x76\xb4\x6c\xfc\x8b\xb0\x6d\xb7\x2f\x61\x4b\x39\xd5\x54\xf0\x61\xff\x74\xa0\x3c\x75\xff\x9d\x86\x8d\x49\x59\x36\xc4\x84\x8d\xf6\xde\x12\xa6\x60\x6c\x33\x07\xfd\x55\xe0\x4b\xcc\xe6\x81\xec\x17\xd9\xdc\xed\xef\xb1\x79\x6c\xce\x41\xb0\xba\x8a\x46\xb0\xa7\xfa\x45\xc6\xb4\xdb\xdf\x17\xbf\x55\x6f\xf4\x24\x6d\x4b\x61\xed\xdd\x28\x38\xca\x76\x9f\xab\x7c\xd9\x16\xf6\xd5\xe0\xac\x80\x97\x4a\x90\x4c\x1c\xcd\xb3\x80\x3f\x5a\x82\x0a\xb8\x4e\x07\x17\x24\x49\xba\xa9\x29\x2b\x5d\x8f\x0a\x0e\xff\x37\x22\x9e\xad\x87\x49\xf2\xdd\x3d\xd8\x96\x9c\x66\x7d\xf4\x2b\x1c\xf0\x61\x3d\x60\xcb\xb0\x5e\x08\xae\xe1\x55\x37\x46\x4d\x6f\xdd\xba\x40\x14\x2f\x80\x5b\xca\x60\x2e\x07\xc1\x9d\x9a\x70\x19\xa3\x4a\xe7\x02\xf3\x92\x16\x3a\x3d\x39\xec\x17\xf2\xe2\xf9\x34\xb0\x5a\xbf\xb2\x95\x47\x60\x5a\x10\x99\x93\xb2\x1c\xd9\x41\x10\xc9\x31\x5d\x27\x29\xd5\x50\x29\xbf\x89\x49\x5a\x73\xfa\xa5\x86\xff\x75\x24\x1a\x6b\x70\xe5\x96\x28\xe4\xf2\x82\x77\x28\x6a\x99\x4b\x82\x26\xc1\xa6\xdd\x9f\x16\xa2\xaa\x08\x5f\x2a\xeb\xae\xb1\x63\x86\xe7\x05\xd7\x84\x72\xc0\x9c\x93\x2a\x96\x48\xe6\xd4\x01\x2f\x55\xde\xd6\xbf\xc9\x34\xda\xe6\x2d\xbf\x72\x04\x0c\xc5\x70\xd1\x78\x94\x7c\x2a\xb1\x5b\x31\x26\xb5\x8d\x6e\xa9\xc3\x98\x2b\x20\x58\xec\x6f\xe4\x17\x15\xa1\x7c\x8e\xef\x80\x6b\x3c\x4a\x41\xdb\x7c\xf9\xed\x12\x01\xf8\x21\x1f\xb0\xe4\x6a\x37\x00\x3f\x50\x14\xbc\xea\x4f\xc3\x1c\x80\x19\x40\xde\xf0\xbf\x4a\xa1\xc0\x75\x8c\x63\xa0\xbd\x34\x98\x3a\xf2\x49\xcf\xf1\xdc\x1b\xbe\x4e\x52\x5e\x57\x1b\x40\xd3\xd2\x8d\x28\xb7\x02\x2b\x62\x94\xed\xf7\xb6\x96\x47\x9e\xf6\x64\x9e\xed\x40\xdb\x06\x53\xd6\x09\xcb\x19\xe5\x2f\xcb\xa7\x38\xbc\x6a\x24\xf9\x5e\x28\x3d\x1f\xc3\x2d\xf6\x3d\x10\xa6\xf7\xc5\x1e\x8a\x97\x09\x76\x9b\x6a\xc4\x2d\x94\x9e\x93\xe4\xb4\x22\xbb\x38\x91\x2c\x62\x24\x8c\x6c\x80\xdd\x64\xe7\xa2\xce\xb7\xc4\x8a\xdd\xce\x90\x86\x32\xee\xa2\x73\xe9\x96\x63\x35\xbf\x44\x7a\x00\x9c\x5b\xc0\x85\x3c\x37\x5c\xee\x62\xbc\x01\x49\xe2\xdd\xe7\x88\xf4\xd3\x63\xdb\x7c\x4e\x9c\xaa\xe6\x3f\xc6\xd2\xcc\x6d\x17\x12\xa7\xee\xfb\x9e\x38\x16\xce\x6b\x28\x46\x51\xa9\x48\x61\xfa\x06\x04\x15\x88\xeb\x99\xb4\x6b\xf6\xf3\x4a\x94\xa1\x04\xbd\x20\x76\x7d\x13\x44\xea\xab\x0b\x61\x72\x53\xff\x38\x2b\x74\xd1\x0b\x44\xc4\x9a\x90\x7a\x73\xd5\x3c\xab\x1b\x4f\xb1\x86\x8e\x30\x4a\x14\xc4\x0f\x7b\xd0\x91\x23\x69\x54\x1e\x3e\xcc\xcc\x09\x1f\xef\xbf\x27\x79\x03\xac\x41\x99\xf3\x7b\xe4\x88\xa8\xb3\x2a\xcd\x71\xf3\x29\x92\x45\x4e\xdb\x0f\x6e\xe1\x25\x2d\xc3\x58\xd1\x20\x84\x7d\xc0\xa4\x40\x7d\x71\xba\x7e\x4e\xb9\x6f\xb7\xbe\xbb\xda\x4b\xa4\x07\xca\x60\x07\xe3\x5b\xcb\x46\x08\x06\x84\x8f\xa0\x07\x81\x94\xb9\xe0\xec\x38\x83\x52\x69\x82\xd1\x0b\x85\x82\xa2\x46\xaa\x8f\xb9\x90\x7a\xf1\x3e\x43\xed\xab\x5c\xd1\x6f\x30\x8e\xe6\x19\xef\x3b\x41\xd9\x88\xe7\xa8\x0a\x7d\x5b\xbd\x56\xba\xa4\x3c\x17\x12\x78\xd4\x3b\x4a\x0b\x99\xef\x90\x14\x90\x4b\x40\x2a\x4a\x9f\x81\x6b\x3b\xd6\x65\x8d\xc4\xec\x7f\x29\x46\xd1\x1d\x27\x2c\xe6\x68\x5d\xc9\xed\x8d\x17\x0b\xad\xe3\xe1\xae\x19\xad\x68\xf8\x1c\x78\x00\x76\x46\x0d\x68\xf1\xdf\x0f\xfb\x13\x90\x7f\xd6\x94\x72\x0d\x3b\x40\x1f\x52\x4e\x74\x1d\xd3\x4d\xc7\x8c\x6e\x63\x4f\x70\x1c\xd0\x09\x3d\x1a\x06\x25\xb6\xda\xcf\xe0\xeb\x45\xbc\x7a\x8d\x86\xbf\x8d\xbc\x75\xa7\x48\xe6\xa5\xbf\x0a\xce\x5d\x35\xb2\x20\xa2\x9e\xbc\x88\x5a\xab\x68\x63\xd8\xd0\x70\x35\xd5\xd4\x0c\xa4\xd6\x14\x73\x51\xbc\x30\x8d\x92\x39\x04\x25\xf5\x6b\xbb\x72\x2c\xbb\x62\x8e\xec\xdc\x59\x7a\x01\xbe\x89\xa2\x4d\x1a\x9d\xc0\x4e\x4f\x37\x3b\xa2\xe0\xe4\x91\x2a\xb2\x71\x66\x6e\xbe\xc3\x6d\xb2\x11\x0f\x71\x8c\x41\xd0\x48\x9d\xb8\x74\x68\x3b\xc2\x13\x50\xbf\xe7\xe0\x40\xd3\x0a\x44\xed\xaf\x59\x2b\x3b\xbf\x3b\xa6\xd4\x9a\xcc\x46\x82\x6a\x51\xba\x31\x7d\x1e\x82\xda\xf7\x17\xd1\xc0\xcd\x39\x24\x08\x92\xd1\x82\xa8\x18\x10\xdd\x71\x41\xad\x65\x49\x34\xe4\xed\x8b\xaa\xab\xa0\x7f\x02\xf3\x25\x41\xc2\x18\x30\xaa\xaa\x39\x18\x9a\x96\xc0\xc8\xf1\xa6\xf2\xd9\xb0\x6f\x09\x65\x35\x42\x4e\x0a\xdd\xbd\x0b\x8b\xe4\x5c\x5a\x09\x4e\xb5\xf0\x22\xc4\xbc\x2d\x2b\xf2\x9a\xf7\xdb\x36\x24\xde\x03\x13\x6c\xeb\xe6\xde\x2d\xad\x4c\x50\xa2\xc6\xe2\xc2\xd9\x37\x87\xe8\x5c\xeb\x03\x19\xd3\xef\x78\x61\x3a\x82\x32\x48\x32\x5c\xfd\xa3\xfc\x8b\x7a\xc1\x34\xa4\xb9\x14\x8c\x16\xc7\xa5\x5c\x51\x08\xde\xea\x31\x27\x73\xee\x4c\x55\x93\x37\xa6\x67\xaa\xa4\x8e\x9e\xea\x86\xe1\x2b\xe5\xa5\xf8\x7a\xc5\x86\xcb\x79\x5b\x32\x52\x80\x03\x8c\xf7\x3a\x5a\x69\x24\x94\xeb\xab\xeb\xfe\xbd\x66\xdd\x51\xf6\x87\x44\x8e\x94\x87\x81\x2e\xfe\xca\x35\x50\x12\x0a\x59\x47\x07\x47\x15\x54\x02\xbd\x09\xb8\xc0\x2b\xf2\x98\x89\x3d\xd9\x02\xe5\x6f\xd6\xa4\xb1\xa3\x32\x17\xcb\xc5\xaf\x25\xf1\x69\x62\x16\x6f\x8a\xa9\x24\xd5\x52\xa7\x63\xf6\xec\x35\xf5\x16\xeb\x64\x7a\x66\x91\x84\xe7\x16\x31\xad\xe3\xba\x77\x14\xaa\xde\x70\x98\x6c\xbd\x2c\x7f\xfa\x5e\x08\xcf\xbf\xcf\x9c\xc2\xb7\x97\xfb\x40\xaf\x7f\x6d\x12\x88\xea\xf3\xd0\x5c\xaf\x07\x5f\x65\xb3\x43\x1c\x7c\x67\xb1\x9c\xfe\x4d\x9f\xef\xce\x12\x7c\x17\x82\x2b\x5b\xc6\x3b\xc0\xa5\xfb\x16\x24\x82\x2d\x1d\xd5\x3f\xd0\xf2\x37\x49\xc4\x9f\x97\x5f\xce\xd8\xcb\xca\xb3\xcb\x1b\xe9\x54\x4a\xcc\x9e\xf7\x77\x1c\xd9\x58\x0d\x97\xcc\xf3\x49\xde\x18\x96\xa7\xc6\x1c\x3d\x49\x60\xfe\xeb\x6c\xda\x39\x71\xda\xf2\x05\x33\xfc\xf1\xdd\x44\xf1\x99\x7a\x2f\xf7\x83\x50\x7b\x81\x11\x92\x3f\xa6\x4e\xc7\xda\x7b\xf7\xf2\xbb\xb2\x00\xa8\x59\xfc\x17\x5f\x99\x19\x3b\xf9\xf1\x62\x62\xf2\x7d\x3c\x06\x6c\xbf\x10\xcb\x46\xfe\x71\x48\xda\xb7\xdc\x16\xa4\x64\x76\x13\x1f\x0a\xa3\xf7\xdb\x33\x77\x08\xd9\x7f\x03\x96\xf9\xe1\x6a\x65\xff\x6d\xbe\xd7\x5b\x9d\x56\x7f\x05\x00\x00\xff\xff\xef\x66\x29\x26\x37\x2b\x00\x00") func dataConfig_schema_v30JsonBytes() ([]byte, error) { return bindataRead( @@ -92,7 +92,7 @@ func dataConfig_schema_v30Json() (*asset, error) { return a, nil } -var _dataConfig_schema_v31Json = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xec\x1a\xcb\x8e\xdb\x36\xf0\xee\xaf\x10\x94\xdc\xe2\xdd\x4d\xd1\xa0\x40\x73\xeb\xb1\xa7\xf6\xdc\x85\x23\xd0\xd2\x58\x66\x96\x22\x19\x92\x72\xd6\x09\xfc\xef\x05\xf5\x32\x45\x91\x22\x6d\x2b\xd9\x45\xd1\xd3\xae\xc5\x99\xe1\xbc\x67\x38\xe4\xf7\x55\x92\xa4\x6f\x65\xbe\x87\x0a\xa5\x1f\x93\x74\xaf\x14\xff\xf8\xf0\xf0\x59\x32\x7a\xd7\x7e\xbd\x67\xa2\x7c\x28\x04\xda\xa9\xbb\xf7\x1f\x1e\xda\x6f\x6f\xd2\xb5\xc6\xc3\x85\x46\xc9\x19\xdd\xe1\x32\x6b\x57\xb2\xc3\xaf\xf7\xbf\xdc\x6b\xf4\x16\x44\x1d\x39\x68\x20\xb6\xfd\x0c\xb9\x6a\xbf\x09\xf8\x52\x63\x01\x1a\xf9\x31\x3d\x80\x90\x98\xd1\x74\xb3\x5e\xe9\x35\x2e\x18\x07\xa1\x30\xc8\xf4\x63\xa2\x99\x4b\x92\x01\xa4\xff\x60\x90\x95\x4a\x60\x5a\xa6\xcd\xe7\x53\x43\x21\x49\x52\x09\xe2\x80\x73\x83\xc2\xc0\xea\x9b\x87\x33\xfd\x87\x01\x6c\x6d\x53\x35\x98\x6d\xbe\x73\xa4\x14\x08\xfa\xf7\x94\xb7\x66\xf9\xd3\x23\xba\xfb\xf6\xc7\xdd\x3f\xef\xef\x7e\xbf\xcf\xee\x36\xef\xde\x8e\x96\xb5\x7e\x05\xec\xda\xed\x0b\xd8\x61\x8a\x15\x66\x74\xd8\x3f\x1d\x20\x4f\xdd\x7f\xa7\x61\x63\x54\x14\x0d\x30\x22\xa3\xbd\x77\x88\x48\x18\xcb\x4c\x41\x7d\x65\xe2\x29\x24\xf3\x00\xf6\x42\x32\x77\xfb\x3b\x64\x1e\x8b\x73\x60\xa4\xae\x82\x16\xec\xa1\x5e\x48\x98\x76\xfb\x65\xec\x27\x21\x17\xa0\xc2\x2e\xdb\x42\xbd\x98\xc7\xea\xed\x6f\x13\x78\xd5\x0b\x3d\x0b\xdb\x42\x18\x7b\x37\x0c\x8e\xc2\xdb\xa5\x2a\x57\x78\xf9\x75\x35\x28\xcb\xa3\xa5\x02\x38\x61\x47\xfd\xcd\xa3\x8f\x16\xa0\x02\xaa\xd2\x41\x05\x49\x92\x6e\x6b\x4c\x0a\x5b\xa3\x8c\xc2\x5f\x9a\xc4\xa3\xf1\x31\x49\xbe\xdb\x99\xcc\xa0\xd3\xac\x8f\x7e\xf9\x0d\x3e\xac\x7b\x64\x19\xd6\x73\x46\x15\x3c\xab\x46\xa8\xf9\xad\x5b\x15\xb0\xfc\x09\xc4\x0e\x13\x88\xc5\x40\xa2\x94\x33\x2a\x23\x58\xaa\x8c\x89\xac\xc0\xb9\x4a\x4f\x16\xfa\x84\x5e\xd8\x9f\x06\x54\xe3\xd7\x66\xe5\x20\x98\xe6\x88\x67\xa8\x28\x46\x72\x20\x21\xd0\x31\x5d\x27\x29\x56\x50\x49\xb7\x88\x49\x5a\x53\xfc\xa5\x86\x3f\x3b\x10\x25\x6a\xb0\xe9\x16\x82\xf1\xe5\x09\x97\x82\xd5\x3c\xe3\x48\x68\x07\x9b\x57\x7f\x9a\xb3\xaa\x42\x74\x29\xaf\xbb\x44\x8e\x08\xcd\x33\xaa\x10\xa6\x20\x32\x8a\xaa\x90\x23\xe9\xa8\x03\x5a\xc8\xac\x2d\xf8\xb3\x6e\xb4\xcb\x5a\x7c\x69\x11\x18\xaa\xff\xa2\xf6\x28\xe8\x9c\x63\xb7\x64\xb4\x6b\x6b\xde\x52\x0b\x31\x93\x80\x44\xbe\xbf\x12\x9f\x55\x08\xd3\x18\xdd\x01\x55\xe2\xc8\x19\x6e\xfd\xe5\xd5\x39\x02\xd0\x43\x36\xe4\x92\x8b\xd5\x00\xf4\x80\x05\xa3\x55\x1f\x0d\x31\x09\x66\x48\xf2\x1a\xff\x99\x33\x09\xb6\x62\x2c\x01\xcd\xa5\x41\xd4\x91\x4e\x7a\x8c\xc7\x5e\xf0\x75\x92\xd2\xba\xda\x82\xd0\x3d\xec\x08\x72\xc7\x44\x85\x34\xb3\xfd\xde\xc6\xf2\x48\xd3\x0e\xcf\x33\x15\x68\xca\xa0\xcb\x3a\x22\x19\xc1\xf4\x69\x79\x17\x87\x67\x25\x50\xb6\x67\x52\xc5\xe7\x70\x03\x7d\x0f\x88\xa8\x7d\xbe\x87\xfc\x69\x06\xdd\x84\x1a\x61\x33\xa9\x62\x9c\x1c\x57\xa8\x0c\x03\xf1\x3c\x04\x42\xd0\x16\xc8\x55\x72\x2e\xaa\x7c\x83\x2c\x2b\x4b\x0d\xea\xf3\xb8\x49\xe7\xd2\x2d\x87\x6a\x7e\x21\xf0\x01\x44\x6c\x01\x67\xfc\xdc\x70\xd9\x8b\xe1\x06\x24\x09\x77\x9f\x23\xd0\x4f\xf7\x6d\xf3\x39\x13\x55\xcd\x7f\x84\xa4\x1b\xbb\x5d\x48\xac\xba\xef\xfa\x62\x49\x18\xd7\x50\x8c\xac\x52\xa1\x5c\xf7\x0d\x02\xa4\xc7\xae\x67\xd0\xee\x74\x93\x55\xac\xf0\x39\xe8\x04\xd8\xd6\x8d\x37\x53\x5f\x5c\x08\x93\xab\xfa\xc7\x28\xd3\x05\x0f\x10\x01\x69\x7c\xec\xc5\xb2\x79\x66\x37\xec\x62\x0d\x1c\x22\x18\x49\x08\x07\xbb\x57\x91\x23\x6a\x98\x1f\x3e\x44\xfa\x84\x0b\xf7\xb7\x59\x5c\x0f\xaa\x97\x66\x7c\x8f\x1c\x20\x75\x66\xa5\x09\x37\x17\x23\x9b\x40\xb4\xfd\xe0\x16\x9e\xe3\xc2\x9f\x2b\x9a\x0c\x61\x06\x18\x67\x42\x4d\xa2\xeb\xe7\x94\xfb\x76\xeb\x9b\xab\x3d\x17\xf8\x80\x09\x94\x30\x3e\xb5\x6c\x19\x23\x80\xe8\x28\xf5\x08\x40\x45\xc6\x28\x39\x46\x40\x4a\x85\x44\xf0\x40\x21\x21\xaf\x05\x56\xc7\x8c\x71\xb5\x78\x9f\x21\xf7\x55\x26\xf1\x37\x18\x5b\xf3\x9c\xef\x3b\x42\x1b\x8b\x21\x6b\x42\x72\xa5\x41\x7d\x29\x29\x1c\xc6\x8e\x44\x18\x4c\x54\xe1\x14\x95\x4a\x56\x8b\x3c\xf6\x80\xad\xf7\x44\xa2\x84\xd8\x23\xbc\x76\xb7\x71\xd8\xcc\x03\x97\x97\x00\x4f\x0a\x5d\x67\xc2\x50\x55\xb6\x7f\x9b\x79\xe5\xe4\x0c\x7d\x79\x94\xb9\xba\xae\x5b\x93\xaa\xc0\x34\x63\x1c\x68\x30\x36\xa4\x62\x3c\x2b\x05\xca\x21\xe3\x20\x30\x73\xaa\x62\x6d\x46\x7a\x51\x0b\xa4\xf7\x9f\x92\x91\xb8\xa4\x88\x84\xc2\x4c\x55\x7c\x77\xe5\xb1\x52\xa9\x70\xb0\xd7\x04\x57\xd8\x1f\x34\x0e\xaf\x8d\xe8\x00\xda\xea\xef\x2e\xfa\x33\x05\xff\xcc\x29\xa6\x0a\x4a\xed\x26\x53\xa7\x9a\xe9\x39\xe7\x5b\xce\x88\x5e\x73\x8f\xc4\xd8\xa0\x33\x7c\x24\x6d\x60\xee\x94\x1b\xc1\xd5\x89\x3a\xf9\x1a\xdd\x75\x34\xf4\xd6\x1d\x23\x1b\x27\xfc\x45\xc5\xdc\x66\x63\xe3\xad\xa7\xee\xa0\xaa\x65\xf0\x58\xd0\xc0\x50\x39\xd7\xd2\x0e\xa0\xc6\xd0\x7e\xd1\x6a\xa1\xdb\x64\x1d\x04\x05\x76\x73\xbb\xb2\x24\xbb\x60\xec\x6e\x9d\x58\x7b\x02\xae\x79\xb2\x09\x1a\x9c\xbf\xcf\xcf\xb6\x3b\x20\xef\xdc\x19\x4b\xb4\xb5\x26\xae\xae\xe0\xd6\xde\x28\x0e\xe1\x1c\x23\x40\x09\x6c\xd9\xa5\x4f\xd4\x66\x3e\x01\xf9\x3a\xc7\x46\x0a\x57\xc0\x6a\x77\xc1\x5b\x99\xfe\xdd\x21\xa5\xc6\x5c\x3e\x60\x54\x03\xd2\xb6\xe9\xe3\x60\xd4\xbe\xbb\x0c\x1a\x2e\x26\x48\x04\x70\x82\x73\x24\x43\x89\xe8\x86\xf1\x44\xcd\x0b\xa4\x20\x6b\xef\x65\x2f\x4a\xfd\x33\x39\x9f\x23\x81\x08\x01\x82\x65\x15\x93\x43\xd3\x02\x08\x3a\x5e\x55\x3e\x1b\xf4\x1d\xc2\xa4\x16\x90\xa1\x5c\x75\x57\xbf\x01\x9f\x4b\x2b\x46\xb1\x62\xce\x0c\x11\xb7\x65\x85\x9e\xb3\x7e\xdb\x06\x24\xd4\xd9\x8c\x9b\xfa\xd8\xc9\x82\xe1\x09\x6d\xe3\x77\x59\x75\x9e\x31\xd1\xb9\xd6\x7b\x3c\xa6\xdf\x71\x22\xba\x00\xa9\x33\xc9\x30\xf8\x09\xe2\x07\x4b\x4b\x77\xca\xc8\x38\x23\x38\x3f\x2e\x25\x61\xce\x68\xab\xe4\x18\x87\xb8\xd1\x03\xb5\x3b\xe8\x56\xa8\xe2\x2a\x18\xac\x0d\xc2\x57\x4c\x0b\xf6\xf5\x82\x0d\x97\x73\x25\x4e\x50\x0e\x56\xbe\xbb\x55\xd1\x52\x09\x84\xa9\xba\xb8\x9c\xdf\x2a\xd6\x0d\xd5\x7c\xf0\xcf\x40\xd6\x1f\xe0\xc2\xf7\xe8\x9e\x4c\x9f\xf3\x3a\x38\x0d\xac\xa0\x62\xc2\xe9\x80\x0b\x3c\xf4\x08\x89\xd8\x83\x2d\x50\xd5\xa2\xc6\xc7\x1d\x54\xc6\xf8\xf2\xa7\x8d\xf0\x88\x78\x13\x4e\x48\x98\xa3\x6a\xa9\xe8\x88\x1e\xa8\xa7\xce\x1a\x9c\xcc\xcf\x2d\x12\xff\xec\x22\xc4\x75\x98\xf7\x0e\x42\xd6\x5b\xea\x19\x21\x4c\x4f\x19\xae\x5b\xfe\xf8\x63\xca\xc9\x7f\x28\xb9\x2d\xe9\xf5\x77\x61\x1e\xab\x3e\x0e\x3d\xf3\x7a\xd0\xd5\x26\xda\xc4\xde\x8b\xa8\xe5\xf8\x6f\xda\x77\x7b\x44\xe0\xea\xf3\x2f\xec\x04\x6f\x48\x2e\xdd\x8b\xa6\x40\x6e\xe9\xa0\xfe\x4f\x2d\xff\x11\x47\xfc\x79\xfe\xd5\x3d\x20\x0b\xbe\xdc\x6a\xa0\xae\x2e\xce\x11\xcf\x95\x5e\x81\xcd\x5e\xda\x14\xe3\xc1\xa2\x61\x92\xe9\x99\x7f\x4e\x93\xd1\xf7\x69\x1d\xc6\x66\xcc\x86\x0d\xe6\x78\xe3\x3b\xae\x90\x73\x83\xa4\x1e\xc4\x73\xbf\x62\x6d\xda\x29\x71\x5e\xf2\x05\x93\xcd\xfd\xbb\x99\x3e\x60\xee\xde\xfb\x07\x15\xd0\x05\x86\x74\x6e\x9b\x5a\x87\x87\x5e\xbb\xd3\x77\x9b\x9e\xf8\x37\xf0\x27\xaf\x38\xb5\x9c\xf4\x38\x99\x49\x7d\x1f\x0f\x5a\xdb\x17\x98\x9b\x91\x7e\x2c\x90\xf6\x15\x89\x91\xdd\x37\xe6\x79\xca\x67\x46\xe7\xdb\x4e\x7b\xcc\xdb\xbf\xb1\xf4\xdc\x6a\xac\xcc\xbf\xcd\x7b\xd8\xd5\x69\xf5\x6f\x00\x00\x00\xff\xff\xfc\xf3\x11\x6a\x88\x2f\x00\x00") +var _dataConfig_schema_v31Json = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xec\x1a\xcb\x8e\xdb\x36\xf0\xee\xaf\x10\x94\xdc\xe2\xdd\x4d\xd1\xa0\x40\x73\xeb\xb1\xa7\xf6\xdc\x85\x23\xd0\xd2\x58\x66\x96\x22\x19\x92\x72\xd6\x09\xfc\xef\x05\xf5\x32\x45\x91\x22\x6d\x2b\xd9\x45\xd1\xd3\xae\xc5\x99\xe1\xbc\x67\x38\xe4\xf7\x55\x92\xa4\x6f\x65\xbe\x87\x0a\xa5\x1f\x93\x74\xaf\x14\xff\xf8\xf0\xf0\x59\x32\x7a\xd7\x7e\xbd\x67\xa2\x7c\x28\x04\xda\xa9\xbb\xf7\x1f\x1e\xda\x6f\x6f\xd2\xb5\xc6\xc3\x85\x46\xc9\x19\xdd\xe1\x32\x6b\x57\xb2\xc3\xaf\xf7\xbf\xdc\x6b\xf4\x16\x44\x1d\x39\x68\x20\xb6\xfd\x0c\xb9\x6a\xbf\x09\xf8\x52\x63\x01\x1a\xf9\x31\x3d\x80\x90\x98\xd1\x74\xb3\x5e\xe9\x35\x2e\x18\x07\xa1\x30\xc8\xf4\x63\xa2\x99\x4b\x92\x01\xa4\xff\x60\x90\x95\x4a\x60\x5a\xa6\xcd\xe7\x53\x43\x21\x49\x52\x09\xe2\x80\x73\x83\xc2\xc0\xea\x9b\x87\x33\xfd\x87\x01\x6c\x6d\x53\x35\x98\x6d\xbe\x73\xa4\x14\x08\xfa\xf7\x94\xb7\x66\xf9\xd3\x23\xba\xfb\xf6\xc7\xdd\x3f\xef\xef\x7e\xbf\xcf\xee\x36\xef\xde\x8e\x96\xb5\x7e\x05\xec\xda\xed\x0b\xd8\x61\x8a\x15\x66\x74\xd8\x3f\x1d\x20\x4f\xdd\x7f\xa7\x61\x63\x54\x14\x0d\x30\x22\xa3\xbd\x77\x88\x48\x18\xcb\x4c\x41\x7d\x65\xe2\x29\x24\xf3\x00\xf6\x42\x32\x77\xfb\x3b\x64\x1e\x8b\x73\x60\xa4\xae\x82\x16\xec\xa1\x5e\x48\x98\x76\xfb\x65\xec\x27\x21\x17\xa0\xc2\x2e\xdb\x42\xbd\x98\xc7\xea\xed\x6f\x13\x78\xd5\x0b\x3d\x0b\xdb\x42\x18\x7b\x37\x0c\x8e\xc2\xdb\xa5\x2a\x57\x78\xf9\x75\x35\x28\xcb\xa3\xa5\x02\x38\x61\x47\xfd\xcd\xa3\x8f\x16\xa0\x02\xaa\xd2\x41\x05\x49\x92\x6e\x6b\x4c\x0a\x5b\xa3\x8c\xc2\x5f\x9a\xc4\xa3\xf1\x31\x49\xbe\xdb\x99\xcc\xa0\xd3\xac\x8f\x7e\xf9\x0d\x3e\xac\x7b\x64\x19\xd6\x73\x46\x15\x3c\xab\x46\xa8\xf9\xad\x5b\x15\xb0\xfc\x09\xc4\x0e\x13\x88\xc5\x40\xa2\x94\x33\x2a\x23\x58\xaa\x8c\x89\xac\xc0\xb9\x4a\x4f\x16\xfa\x84\x5e\xd8\x9f\x06\x54\xe3\xd7\x66\xe5\x20\x98\xe6\x88\x67\xa8\x28\x46\x72\x20\x21\xd0\x31\x5d\x27\x29\x56\x50\x49\xb7\x88\x49\x5a\x53\xfc\xa5\x86\x3f\x3b\x10\x25\x6a\xb0\xe9\x16\x82\xf1\xe5\x09\x97\x82\xd5\x3c\xe3\x48\x68\x07\x9b\x57\x7f\x9a\xb3\xaa\x42\x74\x29\xaf\xbb\x44\x8e\x08\xcd\x33\xaa\x10\xa6\x20\x32\x8a\xaa\x90\x23\xe9\xa8\x03\x5a\xc8\xac\x2d\xf8\xb3\x6e\xb4\xcb\x5a\x7c\x69\x11\x18\xaa\xff\xa2\xf6\x28\xe8\x9c\x63\xb7\x64\xb4\x6b\x6b\xde\x52\x0b\x31\x93\x80\x44\xbe\xbf\x12\x9f\x55\x08\xd3\x18\xdd\x01\x55\xe2\xc8\x19\x6e\xfd\xe5\xd5\x39\x02\xd0\x43\x36\xe4\x92\x8b\xd5\x00\xf4\x80\x05\xa3\x55\x1f\x0d\x31\x09\x66\x48\xf2\x1a\xff\x99\x33\x09\xb6\x62\x2c\x01\xcd\xa5\x41\xd4\x91\x4e\x7a\x8c\xc7\x5e\xf0\x75\x92\xd2\xba\xda\x82\xd0\x3d\xec\x08\x72\xc7\x44\x85\x34\xb3\xfd\xde\xc6\xf2\x48\xd3\x0e\xcf\x33\x15\x68\xca\xa0\xcb\x3a\x22\x19\xc1\xf4\x69\x79\x17\x87\x67\x25\x50\xb6\x67\x52\xc5\xe7\x70\x03\x7d\x0f\x88\xa8\x7d\xbe\x87\xfc\x69\x06\xdd\x84\x1a\x61\x33\xa9\x62\x9c\x1c\x57\xa8\x0c\x03\xf1\x3c\x04\x42\xd0\x16\xc8\x55\x72\x2e\xaa\x7c\x83\x2c\x2b\x4b\x0d\xea\xf3\xb8\x49\xe7\xd2\x2d\x87\x6a\x7e\x21\xf0\x01\x44\x6c\x01\x67\xfc\xdc\x70\xd9\x8b\xe1\x06\x24\x09\x77\x9f\x23\xd0\x4f\xf7\x6d\xf3\x39\x13\x55\xcd\x7f\x84\xa4\x1b\xbb\x5d\x48\xac\xba\xef\xfa\x62\x49\x18\xd7\x50\x8c\xac\x52\xa1\x5c\xf7\x0d\x02\xa4\xc7\xae\x67\xd0\xee\x74\x93\x55\xac\xf0\x39\xe8\x04\xd8\xd6\x8d\x37\x53\x5f\x5c\x08\x93\xab\xfa\xc7\x28\xd3\x05\x0f\x10\x01\x69\x7c\xec\xc5\xb2\x79\x66\x37\xec\x62\x0d\x1c\x22\x18\x49\x08\x07\xbb\x57\x91\x23\x6a\x98\x1f\x3e\x44\xfa\x84\x0b\xf7\xb7\x59\x5c\x0f\xaa\x97\x66\x7c\x8f\x1c\x20\x75\x66\xa5\x09\x37\x17\x23\x9b\x40\xb4\xfd\xe0\x16\x9e\xe3\xc2\x9f\x2b\x9a\x0c\x61\x06\x18\x67\x42\x4d\xa2\xeb\xe7\x94\xfb\x76\xeb\x9b\xab\x3d\x17\xf8\x80\x09\x94\x30\x3e\xb5\x6c\x19\x23\x80\xe8\x28\xf5\x08\x40\x45\xc6\x28\x39\x46\x40\x4a\x85\x44\xf0\x40\x21\x21\xaf\x05\x56\xc7\x8c\x71\xb5\x78\x9f\x21\xf7\x55\x26\xf1\x37\x18\x5b\xf3\x9c\xef\x3b\x42\x1b\x8b\x21\x6b\x42\x72\xa5\x41\x7d\x29\x29\x1c\xc6\x8e\x44\x18\x4c\x54\xe1\x14\x95\x4a\x56\x8b\x3c\xf6\x80\xad\xf7\x44\xa2\x84\xd8\x23\xbc\x76\xb7\x71\xd8\xcc\x03\x97\x97\x00\x4f\x0a\x5d\x67\xc2\x50\x55\xb6\x7f\x9b\x79\xe5\xe4\x0c\x7d\x79\x94\xb9\xba\xae\x5b\x93\xaa\xc0\x34\x63\x1c\x68\x30\x36\xa4\x62\x3c\x2b\x05\xca\x21\xe3\x20\x30\x73\xaa\x62\x6d\x46\x7a\x51\x0b\xa4\xf7\x9f\x92\x91\xb8\xa4\x88\x84\xc2\x4c\x55\x7c\x77\xe5\xb1\x52\xa9\x70\xb0\xd7\x04\x57\xd8\x1f\x34\x0e\xaf\x8d\xe8\x00\xda\xea\xef\x2e\xfa\x33\x05\xff\xcc\x29\xa6\x0a\x4a\xed\x26\x53\xa7\x9a\xe9\x39\xe7\x5b\xce\x88\x5e\x73\x8f\xc4\xd8\xa0\x33\x7c\x24\x6d\x60\xee\x94\x1b\xc1\xd5\x89\x3a\xf9\x1a\xdd\x75\x34\xf4\xd6\x1d\x23\x1b\x27\xfc\x45\xc5\xdc\x66\x63\xe3\xad\xa7\xee\xa0\xaa\x65\xf0\x58\xd0\xc0\x50\x39\xd7\xd2\x0e\xa0\xc6\xd0\x7e\xd1\x6a\xa1\xdb\x64\x1d\x04\x05\x76\x73\xbb\xb2\x24\xbb\x60\xec\x6e\x9d\x58\x7b\x02\xae\x79\xb2\x09\x1a\x9c\xbf\xcf\xcf\xb6\x3b\x20\xef\xdc\x19\x4b\xb4\xb5\x26\xae\xae\xe0\xd6\xde\x28\x0e\xe1\x1c\x23\x40\x09\x6c\xd9\xa5\x4f\xd4\x66\x3e\x01\xf9\x3a\xc7\x46\x0a\x57\xc0\x6a\x77\xc1\x5b\x99\xfe\xdd\x21\xa5\xc6\x5c\x3e\x60\x54\x03\xd2\xb6\xe9\xe3\x60\xd4\xbe\xbb\x0c\x1a\x2e\x26\x48\x04\x70\x82\x73\x24\x43\x89\xe8\x86\xf1\x44\xcd\x0b\xa4\x20\x6b\xef\x65\x2f\x4a\xfd\x33\x39\x9f\x23\x81\x08\x01\x82\x65\x15\x93\x43\xd3\x02\x08\x3a\x5e\x55\x3e\x1b\xf4\x1d\xc2\xa4\x16\x90\xa1\x5c\x75\x57\xbf\x01\x9f\x4b\x2b\x46\xb1\x62\xce\x0c\x11\xb7\x65\x85\x9e\xb3\x7e\xdb\x06\x24\xd4\xd9\x8c\x9b\xfa\xd8\xc9\x82\xe1\x09\x6d\xe3\x77\x59\x75\x9e\x31\xd1\xb9\xd6\x7b\x3c\xa6\xdf\x71\x22\xba\x00\xa9\x33\xc9\x30\xf8\x09\xe2\x2f\xaa\x05\x7d\x1c\xc9\x38\x23\x38\x3f\x2e\xa5\x8a\x9c\xd1\x96\x8f\x18\xcf\xb9\xd1\x55\xb5\xdf\xe8\x9e\xa9\xe2\x2a\x18\xd5\x0d\xc2\x57\x4c\x0b\xf6\xf5\x82\x0d\x97\xd3\x36\x27\x28\x07\x2b\x31\xde\xaa\x68\xa9\x04\xc2\x54\x5d\x5c\xf7\x6f\x15\xeb\x86\xb2\x3f\x38\x72\xa0\x3c\x0c\x70\xe1\x0b\x77\x4f\x49\xc8\x79\x1d\x1c\x1b\x56\x50\x31\xe1\x74\xc0\x05\x5e\x84\x84\x44\xec\xc1\x16\x28\x7f\x51\x73\xe6\x0e\x2a\x63\x7c\xf9\x63\x49\x78\x96\xbc\x09\x37\xc5\x98\xa3\x6a\xa9\xe8\x88\x9e\xbc\xa7\xce\x62\x9d\xcc\x0f\x38\x12\xff\x90\x23\xc4\x75\x98\xf7\x0e\x42\xd6\x5b\xea\x99\x35\x4c\x8f\x23\xae\xe7\x00\xf1\xe7\x99\x93\xff\xf4\x72\x5b\xd2\xeb\x2f\xcd\x3c\x56\x7d\x1c\x9a\xeb\xf5\xa0\xab\x4d\xb4\x89\xbd\x37\x56\xcb\xf1\xdf\xf4\xf9\xf6\x2c\xc1\x75\x20\xb8\xb0\x65\xbc\x21\xb9\x74\x4f\x9f\x02\xb9\xa5\x83\xfa\x3f\xb5\xfc\x47\x1c\xf1\xe7\xf9\x57\xf7\xd2\x2c\xf8\xc4\xab\x81\xba\xba\x38\x47\xbc\x6b\x7a\x05\x36\x7b\x69\x53\x8c\x27\x90\x86\x49\xa6\xc3\x81\x39\x4d\x46\x5f\xbc\x75\x18\x9b\x31\x1b\x36\x98\xe3\x31\xf0\xb8\x42\xce\x4d\x9c\x7a\x10\xcf\x45\x8c\xb5\x69\xa7\xc4\x79\xc9\x17\x4c\x36\xf7\xef\x66\xfa\x80\xb9\x0b\xf2\x1f\x54\x40\x17\x98\xe6\xb9\x6d\x6a\x1d\x1e\x7a\xed\x4e\x1f\x78\x7a\xe2\xdf\xc0\x9f\x3c\xf7\xd4\x72\xd2\xe3\x64\x78\xf5\x7d\x3c\x91\x6d\x9f\x6a\x6e\x46\xfa\xb1\x40\xda\xe7\x26\x46\x76\xdf\x98\xe7\x29\x9f\x19\x9d\x8f\x40\xed\x79\x70\xff\x18\xd3\x73\xfd\xb1\x32\xff\x36\x0f\x67\x57\xa7\xd5\xbf\x01\x00\x00\xff\xff\x1c\xc9\xf2\x49\xb1\x2f\x00\x00") func dataConfig_schema_v31JsonBytes() ([]byte, error) { return bindataRead( @@ -112,7 +112,7 @@ func dataConfig_schema_v31Json() (*asset, error) { return a, nil } -var _dataConfig_schema_v32Json = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xec\x1b\x4d\x73\xdc\xa8\xf2\x3e\xbf\x42\xa5\xe4\x16\x7f\xa4\xde\x4b\xbd\xaa\x97\xdb\x3b\xbe\xd3\xee\x79\x5d\x13\x15\x83\x7a\x34\xc4\x12\x10\x40\x63\x4f\x52\xfe\xef\x5b\xfa\x1c\x40\x20\xd0\x8c\x1c\x67\xb7\xf6\x64\x5b\x74\x37\xf4\x77\x37\x8d\x7f\x6c\x92\x24\x7d\x2f\xf1\x01\x2a\x94\x7e\x4e\xd2\x83\x52\xfc\xf3\xfd\xfd\x57\xc9\xe8\x6d\xf7\xf5\x8e\x89\xe2\x3e\x17\x68\xaf\x6e\x3f\x7e\xba\xef\xbe\xbd\x4b\x6f\x1a\x3c\x92\x37\x28\x98\xd1\x3d\x29\xb2\x6e\x25\x3b\xfe\xfb\xee\x5f\x77\x0d\x7a\x07\xa2\x4e\x1c\x1a\x20\xb6\xfb\x0a\x58\x75\xdf\x04\x7c\xab\x89\x80\x06\xf9\x21\x3d\x82\x90\x84\xd1\x74\x7b\xb3\x69\xd6\xb8\x60\x1c\x84\x22\x20\xd3\xcf\x49\x73\xb8\x24\x19\x41\x86\x0f\x1a\x59\xa9\x04\xa1\x45\xda\x7e\x7e\x69\x29\x24\x49\x2a\x41\x1c\x09\xd6\x28\x8c\x47\x7d\x77\x7f\xa6\x7f\x3f\x82\xdd\xd8\x54\xb5\xc3\xb6\xdf\x39\x52\x0a\x04\xfd\x7d\x7a\xb6\x76\xf9\xcb\x03\xba\xfd\xfe\xbf\xdb\x3f\x3e\xde\xfe\xf7\x2e\xbb\xdd\x7e\x78\x6f\x2c\x37\xf2\x15\xb0\xef\xb6\xcf\x61\x4f\x28\x51\x84\xd1\x71\xff\x74\x84\x7c\xe9\x7f\x7b\x19\x37\x46\x79\xde\x02\xa3\xd2\xd8\x7b\x8f\x4a\x09\x26\xcf\x14\xd4\x13\x13\x8f\x21\x9e\x47\xb0\x37\xe2\xb9\xdf\xdf\xc1\xb3\xc9\xce\x91\x95\x75\x15\xd4\xe0\x00\xf5\x46\xcc\x74\xdb\xaf\xa3\x3f\x09\x58\x80\x0a\x9b\x6c\x07\xf5\x66\x16\xdb\x6c\x7f\x1d\xc3\x9b\x81\xe9\x59\xd8\x0e\x42\xdb\xbb\x3d\xa0\xe1\xde\x2e\x51\xb9\xdc\xcb\x2f\xab\x51\x58\x1e\x29\xe5\xc0\x4b\x76\x6a\xbe\x79\xe4\xd1\x01\x54\x40\x55\x3a\x8a\x20\x49\xd2\x5d\x4d\xca\xdc\x96\x28\xa3\xf0\x5b\x43\xe2\x41\xfb\x98\x24\x3f\xec\x48\xa6\xd1\x69\xd7\x8d\xbf\xfc\x0a\x1f\xd7\x3d\xbc\x8c\xeb\x98\x51\x05\xcf\xaa\x65\x6a\x7e\xeb\x4e\x04\x0c\x3f\x82\xd8\x93\x12\x62\x31\x90\x28\xe4\x8c\xc8\x4a\x22\x55\xc6\x44\x96\x13\xac\x9c\xf8\x18\xe1\x03\x64\x7b\xc1\xaa\x20\x95\x7d\xd6\x9d\x43\xa6\x2f\x16\x9d\x09\xe1\xb0\x61\x8e\xa8\xda\x5f\xdb\x8d\x83\x60\x8a\x11\xcf\x50\x9e\x1b\x02\x41\x42\xa0\x53\x7a\x93\xa4\x44\x41\x25\xdd\xb2\x4a\xd2\x9a\x92\x6f\x35\xfc\xbf\x07\x51\xa2\x06\x9b\x6e\x2e\x18\x5f\x9f\x70\x21\x58\xcd\x33\x8e\x44\x63\xa9\xf3\x7a\x4c\x31\xab\x2a\x44\xd7\x32\xdf\x25\x7c\x44\x48\x9e\x51\x85\x08\x05\x91\x51\x54\x85\x2c\xb2\x71\x5f\xa0\xb9\xcc\xba\xca\x21\xd6\x92\x0c\x02\x63\x19\xb1\xaa\x3e\x72\x3a\xe7\x21\x1d\x99\xc6\x47\x9a\xb3\xa5\x16\x62\x26\x01\x09\x7c\xb8\x10\x9f\x55\x88\xd0\x18\xd9\x01\x55\xe2\xc4\x19\xe9\xec\xe5\x97\x33\x04\xa0\xc7\x6c\x0c\x4a\x8b\xc5\x00\xf4\x48\x04\xa3\xd5\xe0\x0d\x71\x91\x4a\xc3\x7f\xe6\x4c\x82\x2d\x18\x8b\x41\x7d\x69\x64\xd5\x90\xc9\x80\xf1\x30\x30\x7e\x93\xa4\xb4\xae\x76\x20\x9a\x62\xd8\x80\xdc\x33\x51\xa1\xe6\xb0\xc3\xde\xda\xb2\x21\x69\x87\xe5\xe9\x02\xd4\x79\x68\xea\x03\x54\x66\x25\xa1\x8f\xeb\x9b\x38\x3c\x2b\x81\xb2\x03\x93\xea\x92\x64\x90\x1e\x00\x95\xea\x80\x0f\x80\x1f\x67\xd0\x75\x28\x03\x9b\x49\x15\x63\xe4\xa4\x42\x45\x18\x88\xe3\x10\x48\x89\x76\x50\x5e\xc4\xe7\xaa\xc2\xd7\xc8\xb2\xa2\x68\x40\x7d\x16\x37\x29\x81\xfa\xe5\x50\xf1\x90\x0b\x72\x04\x11\x5b\x09\x30\x7e\xae\xdc\xec\xc5\x70\x25\x93\x84\xcb\x58\x03\xf4\xcb\x5d\x57\xc5\xce\x78\x55\xfb\x5b\x59\xa6\x5b\xbb\x5c\x48\xac\xbc\xef\xfa\x62\x71\x18\x57\x50\x18\x5a\xa9\x10\x6e\xea\x06\x01\xd2\xa3\xd7\x33\x68\xdf\x26\x65\x15\xcb\x7d\x06\x3a\x01\xb6\x65\xe3\x8d\xd4\x8b\x13\x61\x72\x51\x21\x1a\xa5\xba\x60\x27\x12\xe0\xc6\x77\xbc\xd8\x63\x9e\x8f\x1b\x36\xb1\x16\x0e\x95\x04\x49\x08\x3b\xbb\x57\x90\x06\x35\xc2\x8f\x9f\x22\x6d\xc2\x85\xfb\x9f\x59\x5c\x0f\xaa\x97\x66\x7c\x8d\x1c\x20\x75\x3e\x4a\xeb\x6e\xae\x83\x6c\x03\xde\xf6\xca\x25\x3c\x27\xb9\x3f\x56\xb4\x11\x42\x77\x30\xce\x84\x9a\x78\xd7\xf2\x74\xef\xb3\x60\x5d\x5c\x43\x9c\x3a\x27\xfc\x6e\xf3\x89\x34\x26\xea\x8e\x42\x9a\xfa\x5f\xd0\x3f\xc2\x9e\x91\xce\x44\x29\x07\xb4\x42\xa2\x00\xb3\x0d\x21\x54\x41\x01\xc2\x83\xc0\xeb\x5d\x49\xe4\x01\xf2\x25\x38\x82\x29\x86\x59\x19\xe7\x18\xce\x3e\x36\xde\x19\x4c\x82\xdb\xab\x6b\x33\x2e\xc8\x91\x94\x50\x58\x1c\xef\x18\x2b\x01\x51\x23\x51\x08\x40\x79\xc6\x68\x79\x8a\x80\x94\x0a\x89\x60\xfb\x27\x01\xd7\x82\xa8\x53\xc6\xb8\x5a\xbd\x2a\x94\x87\x2a\x93\xe4\x3b\x98\xbe\x77\xb6\xfa\x9e\xd0\xd6\x3a\x90\x75\x31\x96\xbc\x96\xfb\xf9\xcc\xf6\x95\xdc\x46\xb2\x5a\xe0\xeb\x1c\x67\x16\xbe\x36\x83\xdc\x3c\x70\xb1\x04\x78\xe2\xf0\xbd\x0a\x43\x35\xd4\xac\xab\x38\x03\xb5\x3c\x49\xac\x2e\xab\xad\xa5\xca\x09\xcd\x18\x07\x1a\xf4\x0d\xa9\x18\xcf\x0a\x81\x30\x64\x1c\x04\x61\x4e\x51\x18\x01\x36\xaf\x05\x6a\xf6\x9f\x92\x91\xa4\xa0\xc8\x1d\x77\x34\x50\x55\xf1\xfd\x85\x97\x00\x4a\x85\x9d\xbd\x2e\x49\x45\xfc\x4e\xe3\xb0\xda\x88\x7a\xad\xab\xd5\xdc\x25\xda\x4c\x79\x16\x15\xb2\x67\x3a\x84\xf9\x06\x21\xa2\x33\x38\x20\xb1\x20\x75\xb4\x8e\xb9\xf7\xe4\x27\x57\xdf\xe0\x3c\x97\x31\xe2\x6a\xe9\xdd\xf4\x07\xd9\x3a\xe1\x17\x95\x5e\xf6\x31\xb6\xde\xea\xc7\xed\x54\xb5\x0c\x36\x71\x2d\x0c\x95\x73\x0d\xc8\x08\x3a\x9d\xd5\x24\x7f\x89\x08\x6d\xe8\xa8\x05\x77\xe8\x26\x22\x8e\xf7\x3b\x45\xc6\xce\xd7\x8e\xfa\xd1\x15\x81\x86\x83\x19\x95\x44\x2a\xa0\xf8\x14\xbf\xd1\x8e\x4c\x6e\x89\xa7\x42\x99\xef\xbb\xe2\xba\xae\x16\x0a\x15\x5d\xbc\x8d\x6e\x74\xe2\x7d\xb5\x1f\xe3\xfd\x14\x56\x28\xc3\x8c\x7b\x54\x13\xcf\xc6\xd2\x34\x6b\x5d\x5d\xcc\xd4\xa1\xbe\x90\xf1\xc4\xc4\x63\x93\x90\x72\xe2\x8e\x1c\x1b\x0b\x65\xc1\xe4\xd3\xba\xeb\x1b\x08\xb8\x46\x7a\x3a\x68\x70\x04\x3a\x3f\x5e\xec\x81\xbc\xa3\x3f\x22\xd1\xce\x1a\x7a\xb9\x12\x6d\x93\x19\xc4\x31\x9c\xef\x05\x28\x41\xac\x51\xc2\x50\x34\xe9\xb9\x1d\xe4\xaf\x79\xe1\xae\x48\x05\xac\x76\x87\xa1\x8d\x6e\x38\x3d\x52\xaa\x8d\x46\x03\x4a\xd5\x20\x6d\x9d\x3e\x8c\x4a\x1d\xfa\xf2\xa0\xe2\x62\x12\x16\xd0\xbc\x1d\x6d\x44\x65\x37\x01\xbc\x24\x18\xc9\x50\x05\x71\xc5\x2d\x70\xcd\x73\xa4\x20\xeb\xde\xd1\x2c\xaa\xd9\x66\x8a\x35\x8e\x04\x2a\x4b\x28\x89\xac\x62\x8a\x9f\x34\x87\x12\x39\xa3\x7f\xb0\xee\x6d\xd1\xf7\x88\x94\xb5\x80\x0c\x61\x6f\x98\xb6\x30\x2a\x46\x89\x62\xce\x70\x12\xb7\x65\x85\x9e\xb3\x61\xdb\x16\x24\xd4\x92\x98\xdd\x78\xec\x05\xae\x66\x09\x5d\xee\x5e\x56\x56\xcf\xa8\xe8\x5c\xa4\x7b\x2c\x66\xd8\x71\xc2\xba\x00\xd9\x84\x9d\xf1\x7e\x3d\x88\x1f\x0c\xf0\xfd\xf5\x40\xc6\x59\x49\xba\x2a\x60\x0d\x0e\x31\xa3\x9d\x90\x63\x0c\xe2\x4a\x0b\x6c\xcc\xa1\xe9\x61\x2a\xae\x82\xce\xda\x22\x3c\x11\x9a\xb3\xa7\x05\x1b\xae\x67\x4a\xbc\x44\x18\xac\xe0\x78\xad\xa0\xa5\x12\x88\x50\xb5\x78\x9c\x74\x2d\x5b\x57\xa4\xfe\xd1\x3e\x03\x29\x62\x84\x0b\x26\x7d\x5f\x5a\xc0\xbc\x0e\x0e\x5d\x2a\xa8\x98\x70\x17\xc0\x57\xf0\x38\xbc\x78\x0b\xb0\x38\x80\xad\x90\x02\xa3\xa6\x74\x3d\x54\xc6\xf8\xfa\xd7\x04\xe1\x49\xdc\x36\x1c\x90\x08\x47\xd5\x5a\xde\x11\x3d\xb7\x4c\x9d\x39\x38\x99\x6f\x67\x13\x7f\x4b\x1b\x3a\x75\xf8\xec\x3d\x84\xac\x77\xd4\xd3\x05\x4e\x9b\x81\x35\x6f\xb3\x57\x0c\x7a\xc3\x93\x03\x8f\x56\x1f\xc6\x02\xfb\x66\x94\xd5\x36\x5a\xc5\xde\x79\xff\x7a\xe7\x6f\x6b\x7d\xfb\x6e\xcf\xd5\x14\x20\xa5\x10\x3e\x44\xf5\x0f\x0b\x8b\xc6\x2b\xe2\xd0\xa4\xcb\x75\x86\xa1\x1e\xea\x9f\x28\xf4\x37\xb1\xd9\x9f\x67\x5f\xfd\xdb\xe0\xe0\xa3\xdc\x16\xea\xe2\x3c\x1e\xf1\x12\xf5\x17\xd0\xd9\x5b\xab\xc2\x1c\x1e\x68\x2a\x99\xde\x25\xcc\x49\x72\xe9\xeb\xdb\xad\x79\x0c\x1b\xcc\xf1\xef\x1b\x66\x32\x9d\x1b\x2d\x0e\x20\x9e\xbb\x2b\x6b\xd3\x5e\x88\xf3\x9c\xaf\x18\x6c\xee\x3e\xcc\x94\x0c\x73\x2f\x91\x5e\x29\xd7\xae\x30\xb6\x75\xeb\xd4\xea\x33\x06\xe9\x4e\x9f\xe4\x7b\xfc\x5f\xc3\x9f\x3c\xd0\x6f\xf8\xa4\xa7\xc9\x5d\xd7\x0f\xf3\xa2\xbe\x7b\x5c\xbf\x35\xe4\x63\x81\x74\xef\xfa\xb4\xe8\xbe\xd5\x5b\x2f\x9f\x1a\x9d\xcf\xf6\xed\x31\xc1\xf0\x7c\xde\x33\xb9\xdc\xe8\x3f\xdb\x7f\x75\xd8\xbc\x6c\xfe\x0c\x00\x00\xff\xff\xa9\x16\x7b\x3d\x63\x35\x00\x00") +var _dataConfig_schema_v32Json = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xec\x5b\xcd\x73\xdc\x28\x16\xbf\xf7\x5f\xa1\x52\x72\x8b\x3f\x52\xbb\xa9\xad\xda\xdc\xf6\xb8\xa7\x99\xf3\xb8\x3a\x2a\x1a\xbd\x56\x13\x4b\x40\x00\xb5\xdd\x49\xf9\x7f\x9f\xd2\x67\x03\x02\x81\xba\xe5\x38\x33\x35\x27\xdb\xe2\xf7\x80\xf7\xfd\x1e\xe0\x1f\x9b\x24\x49\xdf\x4b\x7c\x80\x0a\xa5\x9f\x93\xf4\xa0\x14\xff\x7c\x7f\xff\x55\x32\x7a\xdb\x7d\xbd\x63\xa2\xb8\xcf\x05\xda\xab\xdb\x8f\x9f\xee\xbb\x6f\xef\xd2\x9b\x86\x8e\xe4\x0d\x09\x66\x74\x4f\x8a\xac\x1b\xc9\x8e\xff\xbe\xfb\xd7\x5d\x43\xde\x41\xd4\x89\x43\x03\x62\xbb\xaf\x80\x55\xf7\x4d\xc0\xb7\x9a\x08\x68\x88\x1f\xd2\x23\x08\x49\x18\x4d\xb7\x37\x9b\x66\x8c\x0b\xc6\x41\x28\x02\x32\xfd\x9c\x34\x9b\x4b\x92\x11\x32\x7c\xd0\xa6\x95\x4a\x10\x5a\xa4\xed\xe7\x97\x76\x86\x24\x49\x25\x88\x23\xc1\xda\x0c\xe3\x56\xdf\xdd\x9f\xe7\xbf\x1f\x61\x37\xf6\xac\xda\x66\xdb\xef\x1c\x29\x05\x82\xfe\x3e\xdd\x5b\x3b\xfc\xe5\x01\xdd\x7e\xff\xdf\xed\x1f\x1f\x6f\xff\x7b\x97\xdd\x6e\x3f\xbc\x37\x86\x1b\xf9\x0a\xd8\x77\xcb\xe7\xb0\x27\x94\x28\xc2\xe8\xb8\x7e\x3a\x22\x5f\xfa\xdf\x5e\xc6\x85\x51\x9e\xb7\x60\x54\x1a\x6b\xef\x51\x29\xc1\xe4\x99\x82\x7a\x62\xe2\x31\xc4\xf3\x08\x7b\x23\x9e\xfb\xf5\x1d\x3c\x9b\xec\x1c\x59\x59\x57\x41\x0d\x0e\xa8\x37\x62\xa6\x5b\x7e\x1d\xfd\x49\xc0\x02\x54\xd8\x64\x3b\xd4\x9b\x59\x6c\xb3\xfc\x75\x0c\x6f\x06\xa6\x67\xb1\x1d\x42\x5b\xbb\xdd\xa0\xe1\xde\x2e\x51\xb9\xdc\xcb\x2f\xab\x51\x58\x1e\x29\xe5\xc0\x4b\x76\x6a\xbe\x79\xe4\xd1\x01\x2a\xa0\x2a\x1d\x45\x90\x24\xe9\xae\x26\x65\x6e\x4b\x94\x51\xf8\xad\x99\xe2\x41\xfb\x98\x24\x3f\xec\x48\xa6\xcd\xd3\x8e\x1b\x7f\xf9\x15\x3e\x8e\x7b\x78\x19\xc7\x31\xa3\x0a\x9e\x55\xcb\xd4\xfc\xd2\x9d\x08\x18\x7e\x04\xb1\x27\x25\xc4\x52\x20\x51\xc8\x19\x91\x95\x44\xaa\x8c\x89\x2c\x27\x58\x39\xe9\x31\xc2\x07\xc8\xf6\x82\x55\xc1\x59\xf6\x59\xb7\x0f\x99\xbe\x58\xf3\x4c\x26\x0e\x1b\xe6\x48\xaa\xfd\xb5\xdd\x38\x26\x4c\x31\xe2\x19\xca\x73\x43\x20\x48\x08\x74\x4a\x6f\x92\x94\x28\xa8\xa4\x5b\x56\x49\x5a\x53\xf2\xad\x86\xff\xf7\x10\x25\x6a\xb0\xe7\xcd\x05\xe3\xeb\x4f\x5c\x08\x56\xf3\x8c\x23\xd1\x58\xea\xbc\x1e\x53\xcc\xaa\x0a\xd1\xb5\xcc\x77\x09\x1f\x11\x92\x67\x54\x21\x42\x41\x64\x14\x55\x21\x8b\x6c\xdc\x17\x68\x2e\xb3\xae\x72\x88\xb5\x24\x63\x82\xb1\x8c\x58\x55\x1f\x39\x9d\xf3\x90\x6e\x9a\xc6\x47\x9a\xbd\xa5\x16\x61\x26\x01\x09\x7c\xb8\x90\x9e\x55\x88\xd0\x18\xd9\x01\x55\xe2\xc4\x19\xe9\xec\xe5\x97\x33\x04\xa0\xc7\x6c\x0c\x4a\x8b\xc5\x00\xf4\x48\x04\xa3\xd5\xe0\x0d\x71\x91\x4a\xa3\x7f\xe6\x4c\x82\x2d\x18\x8b\x41\x7d\x68\x64\xd5\x90\xc9\x40\xf1\x30\x30\x7e\x93\xa4\xb4\xae\x76\x20\x9a\x62\xd8\x40\xee\x99\xa8\x50\xb3\xd9\x61\x6d\x6d\xd8\x90\xb4\xc3\xf2\x74\x01\xea\x3c\x34\xf5\x01\x2a\xb3\x92\xd0\xc7\xf5\x4d\x1c\x9e\x95\x40\xd9\x81\x49\x75\x49\x32\x48\x0f\x80\x4a\x75\xc0\x07\xc0\x8f\x33\xe4\x3a\xca\xa0\x66\x52\xc5\x18\x39\xa9\x50\x11\x06\x71\x1c\x82\x94\x68\x07\xe5\x45\x7c\xae\x2a\x7c\x6d\x5a\x56\x14\x0d\xd4\x67\x71\x93\x12\xa8\x1f\x0e\x15\x0f\xb9\x20\x47\x10\xb1\x95\x00\xe3\xe7\xca\xcd\x1e\x0c\x57\x32\x49\xb8\x8c\x35\xa0\x5f\xee\xba\x2a\x76\xc6\xab\xda\xdf\xca\x32\xdd\xda\xe5\x42\x62\xe5\x7d\xd7\x17\x8b\xc3\xb8\x82\xc2\xd0\x4a\x85\x70\x53\x37\x08\x90\x1e\xbd\x9e\xa1\x7d\x9b\x94\x55\x2c\xf7\x19\xe8\x04\x6c\xcb\xc6\x1b\xa9\x17\x27\xc2\xe4\xa2\x42\x34\x4a\x75\xc1\x4e\x24\xc0\x8d\x6f\x7b\xb1\xdb\x3c\x6f\x37\x6c\x62\x2d\x0e\x95\x04\x49\x08\x3b\xbb\x57\x90\xc6\x6c\x84\x1f\x3f\x45\xda\x84\x8b\xf6\x3f\xb3\xb4\x1e\x52\xef\x9c\xf1\x35\x72\x60\xaa\xf3\x56\x5a\x77\x73\x6d\x64\x1b\xf0\xb6\x57\x2e\xe1\x39\xc9\xfd\xb1\xa2\x8d\x10\xba\x83\x71\x26\xd4\xc4\xbb\x96\xa7\x7b\x9f\x05\xeb\xe2\x1a\xe2\xd4\x39\xe1\x77\x8b\x4f\xa4\x31\x51\x77\x14\xd1\xd4\xff\x82\xfe\x11\xf6\x8c\x74\x26\x4a\x39\xd0\x0a\x89\x02\xcc\x36\x84\x50\x05\x05\x08\x0f\x01\xaf\x77\x25\x91\x07\xc8\x97\xd0\x08\xa6\x18\x66\x65\x9c\x63\x38\xfb\xd8\x78\x67\x30\x27\xdc\x5e\x5d\x9b\x71\x41\x8e\xa4\x84\xc2\xe2\x78\xc7\x58\x09\x88\x1a\x89\x42\x00\xca\x33\x46\xcb\x53\x04\x52\x2a\x24\x82\xed\x9f\x04\x5c\x0b\xa2\x4e\x19\xe3\x6a\xf5\xaa\x50\x1e\xaa\x4c\x92\xef\x60\xfa\xde\xd9\xea\xfb\x89\xb6\xd6\x86\xac\x83\xb1\xe4\xb5\xdc\xcf\x67\xb6\xaf\xe4\x36\x92\xd5\x02\x5f\xe7\x38\xb3\xf8\xda\x0c\x72\xf3\xe0\x62\x09\x78\xe2\xf0\xbd\x0a\x43\x35\xd4\xac\xab\x38\x03\xb5\x3c\x49\xac\x2e\xab\xad\xa5\xca\x09\xcd\x18\x07\x1a\xf4\x0d\xa9\x18\xcf\x0a\x81\x30\x64\x1c\x04\x61\x4e\x51\x18\x01\x36\xaf\x05\x6a\xd6\x9f\x4e\x23\x49\x41\x91\x3b\xee\x68\x50\x55\xf1\xfd\x85\x87\x00\x4a\x85\x9d\xbd\x2e\x49\x45\xfc\x4e\xe3\xb0\xda\x88\x7a\xad\xab\xd5\xdc\x25\xda\x4c\x79\x16\x15\xb2\x67\x3a\x84\xf9\x06\x21\xa2\x33\x38\x20\xb1\x20\x75\xb4\x8e\xb9\xf7\xe4\x27\x57\xdf\xe0\xdc\x97\x71\xc5\xd5\xce\x77\xd3\x6f\x64\xeb\xc4\x2f\x2a\xbd\xec\x6d\x6c\xbd\xd5\x8f\xdb\xa9\x6a\x19\x6c\xe2\x5a\x0c\x95\x73\x0d\xc8\x08\x9d\xde\xd5\x24\x7f\x89\x08\x6d\xe8\xa8\x85\x3b\x74\x13\x11\xc7\xfb\x95\x22\x63\xe7\x6b\x47\xfd\xe8\x8a\x40\xa3\xc1\x8c\x4a\x22\x15\x50\x7c\x8a\x5f\x68\x47\x26\xa7\xc4\x53\xa1\xcc\xf7\x5d\x71\x5d\x57\x8b\x42\x45\x17\x6f\xa3\x1b\x9d\x78\x5f\xed\xaf\xf1\x7e\x0a\x2b\x94\x61\xc6\x3d\xaa\x89\x67\x63\x69\x9a\xb5\x8e\x2e\x66\xea\x50\x5f\xc8\x78\x62\xe2\xb1\x49\x48\x39\x71\x47\x8e\x8d\x45\xb2\xe0\xe6\xd3\x3a\xeb\x1b\x26\x70\x5d\xe9\xe9\xd0\xe0\x15\xe8\xfc\xf5\x62\x0f\xf2\x5e\xfd\x11\x89\x76\xd6\xa5\x97\x2b\xd1\x36\x99\x41\x1c\xc3\xf9\x5e\x80\x12\xc4\xba\x4a\x18\x8a\x26\x3d\xb7\x83\xfc\x35\x0f\xdc\x15\xa9\x80\xd5\xee\x30\xb4\xd1\x0d\xa7\x27\x4a\xb5\xab\xd1\x80\x52\x35\xa4\xad\xd3\x87\x51\xa9\x43\x5f\x1e\x54\x5c\x4c\xc2\x02\x9a\xb7\x57\x1b\x51\xd9\x4d\x00\x2f\x09\x46\x32\x54\x41\x5c\x71\x0a\x5c\xf3\x1c\x29\xc8\xba\x77\x34\x8b\x6a\xb6\x99\x62\x8d\x23\x81\xca\x12\x4a\x22\xab\x98\xe2\x27\xcd\xa1\x44\xce\xe8\x1f\xac\x7b\x5b\xf2\x3d\x22\x65\x2d\x20\x43\xd8\x1b\xa6\x2d\x8a\x8a\x51\xa2\x98\x33\x9c\xc4\x2d\x59\xa1\xe7\x6c\x58\xb6\x85\x84\x5a\x12\xb3\x1b\x8f\x3d\xc0\xd5\x2c\xa1\xcb\xdd\xcb\xca\xea\x19\x15\x9d\x8b\x74\x8f\xc5\x0c\x2b\x4e\x58\x17\x20\x9b\xb0\x33\x9e\xaf\x07\xe9\x57\x95\x82\x42\x42\x65\x9c\x95\xa4\x2b\x17\xd6\x10\x05\x66\xb4\xdb\x47\x8c\xe5\x5c\x69\xaa\x8d\xdd\x34\xcd\x4e\xc5\x55\xd0\xab\x5b\x82\x27\x42\x73\xf6\xb4\x60\xc1\xf5\xa4\xcd\x4b\x84\xc1\x8a\xa2\xd7\x0a\x5a\x2a\x81\x08\x55\x8b\xef\x9d\xae\x65\xeb\x8a\x1a\x61\x34\xe4\x40\x2e\x19\x71\xc1\xea\xc0\x97\x3f\x30\xaf\x83\xb7\x33\x15\x54\x4c\xb8\x2b\xe5\x2b\x78\x1c\x9e\xc6\x05\x58\x1c\x60\x2b\xe4\xca\xa8\xeb\xbc\x1e\x95\x31\xbe\xfe\x79\x42\xf8\xca\x6e\x1b\xee\x66\x09\x47\xd5\x5a\xde\x11\x7d\xc1\x99\x3a\x93\x75\x32\xdf\xf7\x26\xfe\xde\x37\xb4\xeb\xf0\xde\x7b\x84\xac\x77\xd4\xd3\x2e\x4e\xbb\x86\x35\x8f\xbd\x57\x0c\x7a\xc3\xdb\x04\x8f\x56\x1f\xc6\x4a\xfc\x66\x94\xd5\x36\x5a\xc5\xde\x87\x01\xeb\xed\xbf\x6d\x0a\xec\x43\x40\x57\xf7\x80\x94\x42\xf8\x10\xd5\x68\x2c\xac\x2e\xaf\x88\x43\x93\x76\xd8\x19\x86\x7a\xd4\x3f\x51\xe8\x6f\x62\xb3\x3f\xcf\xbe\xfa\x47\xc4\xc1\xd7\xbb\x2d\xea\xe2\x3c\x1e\xf1\x64\xf5\x17\xd0\xd9\x5b\xab\xc2\xbc\x65\xd0\x54\x32\x3d\x74\x98\x93\xe4\xd2\x67\xba\x5b\x73\x1b\x36\xcc\xf1\x7f\x1e\x66\x32\x9d\xbb\x83\x1c\x20\x9e\x43\x2e\x6b\xd1\x5e\x88\xf3\x9c\xaf\x18\x6c\xee\x3e\xcc\x94\x0c\x73\x4f\x96\x5e\x29\xd7\xae\x70\xbf\xeb\xd6\xa9\xd5\x67\x0c\xd2\x9d\xbe\xdd\xf7\xf8\xbf\x46\x3f\x79\xc9\xdf\xf0\x49\x4f\x93\x43\xb1\x1f\xe6\x89\x7e\xf7\x0a\x7f\x6b\xc8\xc7\x82\x74\x0f\x00\xb5\xe8\xbe\xd5\x5b\x2f\x9f\x1a\x9d\xef\xfb\xed\xfb\x84\xe1\x9d\xbd\xe7\x8a\x73\xa3\xff\x6c\xff\x27\x62\xf3\xb2\xf9\x33\x00\x00\xff\xff\x33\x66\x86\x98\x8c\x35\x00\x00") func dataConfig_schema_v32JsonBytes() ([]byte, error) { return bindataRead( @@ -132,7 +132,7 @@ func dataConfig_schema_v32Json() (*asset, error) { return a, nil } -var _dataConfig_schema_v33Json = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xec\x5b\x4b\x93\xdb\x2a\x16\xde\xfb\x57\xa8\x74\xef\x2e\xfd\x48\x55\x52\x53\x35\xd9\xcd\x72\x56\x33\xeb\xe9\x72\x54\x18\x1d\xdb\xa4\x11\x10\x40\xee\x76\x52\xfd\xdf\xa7\xf4\x34\x20\x10\xd8\x56\xa7\x7b\xe6\x66\xd5\x6d\xe9\x3b\xc0\x79\x9f\x03\xe8\xe7\x2a\xcb\xf2\x3f\x15\xde\x43\x85\xf2\x2f\x59\xbe\xd7\x5a\x7c\xb9\xbf\xff\xa6\x38\xbb\xed\x9e\xde\x71\xb9\xbb\x2f\x25\xda\xea\xdb\x8f\x9f\xef\xbb\x67\x7f\xe4\x37\x0d\x1d\x29\x1b\x12\xcc\xd9\x96\xec\x8a\xee\x4d\x71\xf8\x74\xf7\xe9\xae\x21\xef\x20\xfa\x28\xa0\x01\xf1\xcd\x37\xc0\xba\x7b\x26\xe1\x7b\x4d\x24\x34\xc4\x0f\xf9\x01\xa4\x22\x9c\xe5\xeb\x9b\x55\xf3\x4e\x48\x2e\x40\x6a\x02\x2a\xff\x92\x35\x8b\xcb\xb2\x11\x32\x3c\x30\x86\x55\x5a\x12\xb6\xcb\xdb\xc7\x2f\xed\x08\x59\x96\x2b\x90\x07\x82\x8d\x11\xc6\xa5\xfe\x71\x7f\x1a\xff\x7e\x84\xdd\xb8\xa3\x1a\x8b\x6d\x9f\x0b\xa4\x35\x48\xf6\xef\xe9\xda\xda\xd7\x5f\x1f\xd0\xed\x8f\x7f\xdc\xfe\xe7\xe3\xed\xdf\xef\x8a\xdb\xf5\x87\x3f\xad\xd7\x8d\x7c\x25\x6c\xbb\xe9\x4b\xd8\x12\x46\x34\xe1\x6c\x9c\x3f\x1f\x91\x2f\xfd\x7f\x2f\xe3\xc4\xa8\x2c\x5b\x30\xa2\xd6\xdc\x5b\x44\x15\xd8\x3c\x33\xd0\x4f\x5c\x3e\xc6\x78\x1e\x61\x6f\xc4\x73\x3f\xbf\x87\x67\x9b\x9d\x03\xa7\x75\x15\xd5\xe0\x80\x7a\x23\x66\xba\xe9\x97\xd1\x9f\x02\x2c\x41\xc7\x4d\xb6\x43\xbd\x99\xc5\x36\xd3\x2f\xc3\x70\x17\x35\x62\x0c\x0f\xa8\x37\x62\xb8\x9b\xfe\x3a\x86\x57\x03\xd3\xb3\xd8\x0e\x61\xcc\xdd\x2e\xd0\x8a\x67\x3e\x51\xf9\xe2\x49\x58\x56\xa3\xb0\x02\x52\x2a\x41\x50\x7e\x6c\x9e\x05\xe4\xd1\x01\x2a\x60\x3a\x1f\x45\x90\x65\xf9\xa6\x26\xb4\x74\x25\xca\x19\xfc\xab\x19\xe2\xc1\x78\x98\x65\x3f\xdd\xd0\x6d\x8c\xd3\xbe\xb7\x7e\x85\x15\x3e\xbe\x0f\xf0\x32\xbe\xc7\x9c\x69\x78\xd6\x2d\x53\xf3\x53\x77\x22\xe0\xf8\x11\xe4\x96\x50\x48\xa5\x40\xb2\xb3\xe2\x80\xc8\x28\x51\xba\xe0\xb2\x28\x09\xd6\x5e\x7a\x8a\x36\x40\xaf\x1a\x01\x23\xbc\x87\x62\x2b\x79\x15\x1d\x65\x5b\x74\x9c\xa8\xfc\xc5\x19\x67\x32\x70\xdc\xb4\x47\x52\xe3\xd7\x7a\xe5\x19\x30\xc7\x48\x14\xa8\x2c\x2d\x91\x22\x29\xd1\x31\xbf\xc9\x72\xa2\xa1\x52\x7e\x69\x67\x79\xcd\xc8\xf7\x1a\xfe\xd9\x43\xb4\xac\xc1\x1d\xb7\x94\x5c\x2c\x3f\xf0\x4e\xf2\x5a\x14\x02\xc9\xc6\xd6\xe7\x2d\x21\xc7\xbc\xaa\x10\x5b\xca\x01\xce\xe1\x23\x41\xf2\x93\x30\x9b\x99\x5e\xd5\xcf\x61\xbe\x1a\x67\xb3\x96\x15\xe0\x26\xce\xcf\xd4\xa5\xe3\x4e\x1d\x77\xeb\x26\x2a\xf2\x5a\xe2\x54\x2f\x6d\xe6\x44\x72\x07\xa9\x71\x20\xcb\xf2\x9a\x94\xe9\xe0\xdd\x39\xe0\x8a\x97\xf6\xba\x59\x5d\x6d\x40\x4e\x5c\xd2\xf6\xac\xe9\xef\xf5\xca\xf7\xc6\xd1\xbe\x46\x84\x81\x2c\x18\xaa\x62\xb2\xca\xb1\x84\x12\x98\x26\x88\x16\x4a\x00\xb6\xe0\x83\xa6\x66\x34\x93\x27\x45\xcd\x5c\xc2\x8e\x28\x2d\x8f\x5e\xe4\x89\x0b\x73\x61\x25\x08\x60\xa5\x2a\xba\x1e\x20\x35\xc0\x59\x03\x8c\x0d\xc1\xa2\x61\xa2\x64\x73\x81\xbb\x1b\xa6\x09\xdd\xcd\xda\x72\x87\xb0\x50\x80\x24\xde\x5f\x48\xcf\x2b\x44\x58\x8a\x52\x81\x69\x79\x14\x9c\x74\x61\xec\xdd\xc5\x27\x60\x87\x62\xb4\x9b\xb3\xc5\x00\xec\x40\x24\x67\xd5\x10\xa4\xd3\x12\xa8\x41\xff\x2c\xb8\x82\xeb\x83\x63\x4f\xf1\x30\x30\x7e\x33\xfa\xf4\xda\x96\x5e\xbe\xe5\xb2\x42\xcd\x62\x87\xb9\x4d\x1f\xb6\xa6\x9a\x5a\x9e\x29\x40\x93\x87\xa6\xf0\x45\xb4\xa0\x84\x3d\x2e\x6f\xe2\xf0\xac\x25\x2a\xf6\x5c\xe9\x4b\x6a\x94\x7c\x0f\x88\xea\x3d\xde\x03\x7e\x9c\x21\x37\x51\x16\x35\x57\x3a\xc5\xc8\x49\x85\x76\x71\x90\xc0\x31\xc8\xc5\xb5\x58\xbe\xa8\xf0\x8d\x61\xf9\x6e\xd7\x40\x43\x16\x37\xa9\xed\xfb\xd7\xb1\xaa\xb8\x94\xe4\x00\x32\xb5\xc4\xe5\xe2\xd4\x92\xb8\x2f\x53\xb2\x79\xb4\x3f\xb3\xa0\x5f\xef\xba\xf6\x6c\xc6\xab\xda\xff\x28\xcd\xd7\xd3\x94\x39\x4d\x9a\xee\x13\x87\xc3\xb4\x3a\xd7\xd2\x4a\x85\x70\x53\xce\x4a\x50\x01\xbd\x9e\xa0\xfd\x86\x47\x31\xc9\xf9\x27\xec\x04\x3c\x49\xac\xa1\x48\x7d\x76\x22\xcc\x2e\xea\xb0\x92\x54\x17\x6d\xb1\x23\xdc\x84\x96\x97\xba\xcc\xd3\x72\xe3\x26\xd6\xe2\x10\x25\x48\x41\xdc\xd9\x83\x82\xb4\x46\x23\xe2\xf0\x39\xd1\x26\x7c\xb4\x7f\x9b\xa5\x0d\x90\x06\xc7\x4c\x6f\xdd\x22\x43\x99\x25\x2a\xa5\xde\x85\xac\xe3\x45\xeb\x6b\x76\x96\xc2\x2e\xbc\xed\x58\xd1\x46\x08\xd3\xc1\x04\x97\xfa\x97\xf4\x42\xa7\x38\x75\x4a\xf8\xdd\xe4\xd3\xf6\xc8\x55\x77\x12\xd1\xeb\xf4\x54\x33\x51\xca\x83\xf6\x74\x54\x84\x69\xd8\x35\xad\x8c\x3f\x09\xd4\x1b\x4a\xd4\x1e\xca\x73\x68\x24\xd7\x1c\x73\x9a\xe6\x18\xde\x0d\x9a\x74\x67\x98\xe9\xaf\x2e\xaa\xcd\x84\x24\x07\x42\x61\xe7\x70\xbc\xe1\x9c\x02\x62\x56\xa2\x90\x80\xca\x82\x33\x7a\x4c\x40\x2a\x8d\x64\x74\x57\x42\x01\xae\x25\xd1\xc7\x82\x0b\xbd\x78\x55\xa8\xf6\x55\xa1\xc8\x0f\xb0\x7d\xef\x64\xf5\xfd\x40\x6b\x67\x41\xce\x16\x77\xf6\x7b\x2b\xe2\x2f\xb3\x15\xa1\x8e\x0a\xeb\xcb\x6a\x6b\xa5\x4b\xc2\x0a\x2e\x80\x45\x7d\x43\x69\x2e\x8a\x9d\x44\x18\x0a\x01\x92\x70\xaf\x28\xac\x00\x5b\xd6\x12\x35\xf3\x4f\x87\x51\x64\xc7\x90\x3f\xee\x18\x50\x5d\x89\xed\x85\x9b\x00\x5a\xc7\x9d\xbd\xa6\xa4\x22\x61\xa7\xf1\x58\x6d\x42\xbd\xd6\xd5\x6a\xfe\x12\x6d\xa6\x3c\x4b\x0a\xd9\x33\x1d\xc2\x7c\x83\x90\xd0\x19\xec\x91\x3c\x23\x75\xb4\x8e\xb9\x0d\xe4\x27\x5f\xdf\xe0\x5d\x97\x75\x58\xdd\x8e\x77\xd3\x2f\x64\xed\xc5\x9f\x55\x7a\xb9\xcb\x58\x07\xab\x1f\xbf\x53\xd5\x2a\xda\xc4\xb5\x18\xa6\xe6\x1a\x90\x11\x3a\x3d\x75\xcd\xfe\x27\x22\xb4\xa5\xa3\x16\xee\xd1\x4d\x42\x1c\xef\x67\x4a\x8c\x9d\xaf\x1d\xf5\x93\x2b\x02\x83\x06\x73\xa6\x88\xd2\xc0\xb0\x7f\x7f\xd5\x4b\xb4\x21\x93\xc3\x8b\xa9\x50\xe6\xfb\xae\xb4\xae\xab\x45\xa1\x5d\x17\x6f\x93\x1b\x9d\x74\x5f\xed\x0f\xe4\x7f\x09\x2b\x8c\x63\x2e\x02\xaa\x49\x67\xe3\xdc\x34\xeb\x6c\x5d\xcc\xd4\xa1\xa1\x90\xf1\xc4\xe5\x63\x93\x90\x4a\xe2\x8f\x1c\x2b\x87\xe4\x8c\x23\x7d\x67\xaf\x6f\x18\xc0\x77\x56\x6d\x42\xa3\x67\xfb\xf3\xe7\xe6\x3d\x28\x78\xa6\x4d\x14\xda\x38\xe7\x12\xbe\x44\xdb\x64\x06\x79\x88\xe7\x7b\x09\x5a\x12\xe7\x28\x61\x28\x9a\xcc\xdc\x0e\xea\x7d\x6e\xb8\x6b\x52\x01\xaf\xfd\x61\x68\x65\x1a\x4e\x4f\x94\x1b\x67\xfe\x11\xa5\x1a\x48\x57\xa7\x0f\xc6\x01\x52\xd7\x97\x47\x15\x97\x92\xb0\x80\x95\xed\xd1\x46\x52\x76\x93\x20\x28\xc1\x48\xc5\x2a\x88\x2b\x76\x81\x6b\x51\x22\x0d\x45\x7f\x6d\xe4\x9c\x9a\x6d\xa6\x58\x13\x48\x22\x4a\x81\x12\x55\xa5\x14\x3f\x79\x09\x14\x79\xa3\x7f\xb4\xee\x6d\xc9\xb7\x88\xd0\x5a\x42\x81\x70\x30\x4c\x3b\x14\x15\x67\x44\x73\x6f\x38\x49\x9b\xb2\x42\xcf\xc5\x30\x6d\x0b\x89\xb5\x24\x76\x37\x9e\xba\x81\x6b\x58\x42\x97\xbb\xcf\x2b\xab\x67\x54\x74\x2a\xd2\x03\x16\x33\xcc\x38\x61\x5d\x82\x6a\xc2\xce\xb8\xbf\x1e\xa5\x8f\x06\xf8\x7e\x7b\xa0\x10\x9c\x92\xae\x0a\x58\x82\x43\xcc\x59\x27\xe4\x14\x83\xb8\xd2\x02\x1b\x73\x68\x7a\x98\x4a\xe8\xa8\xb3\xb6\x04\x4f\x84\x95\xfc\xe9\x8c\x09\x97\x33\x25\x41\x11\x06\x27\x38\x5e\x2b\x68\xa5\x25\x22\x4c\x9f\x7d\x9c\xe4\x8a\x45\x48\xd8\x82\x04\x36\x35\xf4\x6c\xbe\xac\xcf\xc2\xa5\x7d\x8c\xb7\x38\x87\x3d\x42\x89\xa6\xbe\x7d\x83\x5d\xbd\x6b\x95\x7f\x45\x81\x34\x7a\x71\x24\x91\x8e\xb8\x68\x69\x14\x4a\x9e\x58\xd4\xd1\xa3\xa9\x0a\x2a\x3e\x7f\x0d\xe3\x8a\x8b\xc8\x31\x16\x07\xd8\x02\x85\x42\xd2\x59\x66\x8f\x2a\xb8\x58\x7e\x33\x25\x7e\x5e\xb9\x8e\x87\x6d\x22\x50\xb5\x54\x0c\x49\x3e\xdd\xcd\xbd\x95\x4a\xf6\x0e\xa2\x43\xbd\x61\x81\x5e\xf9\x7d\x47\x07\xfb\xe6\x44\x7b\x31\x23\xa0\xd5\x87\xb1\x0d\xb9\x19\x65\xb5\x4e\x56\x71\xf0\x56\xc4\x72\xeb\x6f\x3b\x22\x77\x07\xd4\xd7\x3a\x21\xad\x11\xde\x27\x75\x59\x67\x96\xd6\x57\xc4\xa1\xc9\x5e\x80\x37\x0c\xf5\xa8\xdf\x51\xe8\xff\xc4\x66\x7f\x9d\x7d\xf5\xdf\x42\x44\xef\xe4\xb7\xa8\x8b\xf3\x78\xc2\x95\xca\x77\xa0\xb3\x37\x56\xc5\x24\x89\x79\x55\xd1\xa3\x7e\xab\xe2\x55\xbd\xc2\x3e\xed\x32\x54\x32\xdd\xfc\x9a\x93\xe4\xb9\x5f\x31\xac\xed\x65\xb8\x30\xcf\x97\x83\x76\x5d\x33\x77\x16\x3e\x40\x02\x9b\xad\xce\xa4\xbd\x10\xe7\x39\x5f\x30\xee\xdf\x7d\x98\xa9\xde\xe6\xae\xce\xbd\x52\xd9\xb3\xc0\x3d\x03\xbf\x4e\x9d\xc6\x78\x90\xee\xf4\xe3\xa8\xb0\xff\x0f\xf4\x93\x4f\xa5\x1a\x3e\xd9\x71\xb2\x39\xfb\xd3\x3e\x59\xea\x3e\x73\x5a\x5b\xf2\x71\x20\xdd\x45\x54\x23\xd1\xae\xcd\xbd\x82\xe0\xcd\x79\xdf\x07\x54\xee\xb9\xd6\xf0\x21\x53\xe0\xa8\x7d\x65\xfe\x6d\x3f\x3a\x5b\xbd\xac\xfe\x1b\x00\x00\xff\xff\x88\x06\xbb\x83\xde\x3b\x00\x00") +var _dataConfig_schema_v33Json = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xec\x5b\xcb\x93\xdb\x2c\x12\xbf\xfb\xaf\x50\xe9\xfb\x6e\x99\x47\xaa\x92\xda\xaa\xcd\x6d\x8f\x7b\xda\x3d\xef\x94\xa3\xc2\xa8\x6d\x93\x41\x40\x00\x79\xc6\x49\xcd\xff\xbe\xa5\xa7\x01\x81\xc0\xb6\x26\x33\xbb\x5f\x4e\x33\x96\x7e\x0d\x74\x37\xfd\xa2\xd1\xcf\x55\x96\xe5\x7f\x2a\xbc\x87\x0a\xe5\x5f\xb2\x7c\xaf\xb5\xf8\x72\x7f\xff\x4d\x71\x76\xdb\x3d\xbd\xe3\x72\x77\x5f\x4a\xb4\xd5\xb7\x1f\x3f\xdf\x77\xcf\xfe\xc8\x6f\x1a\x3a\x52\x36\x24\x98\xb3\x2d\xd9\x15\xdd\x9b\xe2\xf0\xe9\xee\xd3\x5d\x43\xde\x41\xf4\x51\x40\x03\xe2\x9b\x6f\x80\x75\xf7\x4c\xc2\xf7\x9a\x48\x68\x88\x1f\xf2\x03\x48\x45\x38\xcb\xd7\x37\xab\xe6\x9d\x90\x5c\x80\xd4\x04\x54\xfe\x25\x6b\x16\x97\x65\x23\x64\x78\x60\x0c\xab\xb4\x24\x6c\x97\xb7\x8f\x5f\xda\x11\xb2\x2c\x57\x20\x0f\x04\x1b\x23\x8c\x4b\xfd\xe3\xfe\x34\xfe\xfd\x08\xbb\x71\x47\x35\x16\xdb\x3e\x17\x48\x6b\x90\xec\xdf\xd3\xb5\xb5\xaf\xbf\x3e\xa0\xdb\x1f\xff\xb8\xfd\xcf\xc7\xdb\xbf\xdf\x15\xb7\xeb\x0f\x7f\x5a\xaf\x1b\xf9\x4a\xd8\x76\xd3\x97\xb0\x25\x8c\x68\xc2\xd9\x38\x7f\x3e\x22\x5f\xfa\xff\x5e\xc6\x89\x51\x59\xb6\x60\x44\xad\xb9\xb7\x88\x2a\xb0\x79\x66\xa0\x9f\xb8\x7c\x8c\xf1\x3c\xc2\xde\x88\xe7\x7e\x7e\x0f\xcf\x36\x3b\x07\x4e\xeb\x2a\xaa\xc1\x01\xf5\x46\xcc\x74\xd3\x2f\xa3\x3f\x05\x58\x82\x8e\x6f\xd9\x0e\xf5\x66\x3b\xb6\x99\x7e\x19\x86\x3b\xaf\x11\x63\x78\x40\xbd\x11\xc3\xdd\xf4\xd7\x31\xbc\x1a\x98\x9e\xc5\x76\x08\x63\xee\x76\x81\x96\x3f\xf3\x89\xca\xe7\x4f\xc2\xb2\x1a\x85\x15\x90\x52\x09\x82\xf2\x63\xf3\x2c\x20\x8f\x0e\x50\x01\xd3\xf9\x28\x82\x2c\xcb\x37\x35\xa1\xa5\x2b\x51\xce\xe0\x5f\xcd\x10\x0f\xc6\xc3\x2c\xfb\xe9\xba\x6e\x63\x9c\xf6\xbd\xf5\x2b\xac\xf0\xf1\x7d\x80\x97\xf1\x3d\xe6\x4c\xc3\xb3\x6e\x99\x9a\x9f\xba\x13\x01\xc7\x8f\x20\xb7\x84\x42\x2a\x05\x92\xdd\x2e\x0e\x88\x8c\x12\xa5\x0b\x2e\x8b\x92\x60\xed\xa5\xa7\x68\x03\xf4\xaa\x11\x30\xc2\x7b\x28\xb6\x92\x57\xd1\x51\xb6\x45\xc7\x89\xca\x5f\x9c\x71\x26\x03\xc7\xb7\xf6\x48\x6a\xfc\x5a\xaf\x3c\x03\xe6\x18\x89\x02\x95\xa5\x25\x52\x24\x25\x3a\xe6\x37\x59\x4e\x34\x54\xca\x2f\xed\x2c\xaf\x19\xf9\x5e\xc3\x3f\x7b\x88\x96\x35\xb8\xe3\x96\x92\x8b\xe5\x07\xde\x49\x5e\x8b\x42\x20\xd9\xec\xf5\xf9\x9d\x90\x63\x5e\x55\x88\x2d\x65\x00\xe7\xf0\x91\x20\xf9\x89\x9b\xcd\x4c\xab\xea\xe7\x30\x5f\x8d\xb3\x59\xcb\x0a\x70\x13\xe7\x67\x6a\xd2\x71\xa3\x8e\x9b\x75\xe3\x15\x79\x2d\x71\xaa\x95\x36\x73\x22\xb9\x83\x54\x3f\x90\x65\x79\x4d\xca\x74\xf0\xee\x1c\x70\xc5\x4b\x7b\xdd\xac\xae\x36\x20\x27\x26\x69\x5b\xd6\xf4\xf7\x7a\xe5\x7b\xe3\x68\x5f\x23\xc2\x40\x16\x0c\x55\x31\x59\xe5\x58\x42\x09\x4c\x13\x44\x0b\x25\x00\x5b\xf0\x41\x53\x33\x9a\xc9\x93\xbc\x66\x2e\x61\x47\x94\x96\x47\x2f\xf2\xc4\x85\xb9\xb0\x12\x04\xb0\x52\x15\x5d\x0d\x90\xea\xe0\xac\x01\xc6\x82\x60\x51\x37\x51\xb2\x39\xc7\xdd\x0d\xd3\xb8\xee\x66\x6d\xb9\x43\x58\x28\x40\x12\xef\x2f\xa4\xe7\x15\x22\x2c\x45\xa9\xc0\xb4\x3c\x0a\x4e\x3a\x37\xf6\xee\xfc\x13\xb0\x43\x31\xee\x9b\xb3\xc5\x00\xec\x40\x24\x67\xd5\xe0\xa4\xd3\x02\xa8\x41\xff\x2c\xb8\x82\xeb\x9d\x63\x4f\xf1\x30\x30\x7e\x33\xda\xf4\xda\x96\x5e\xbe\xe5\xb2\x42\xcd\x62\x87\xb9\x4d\x1b\xb6\xa6\x9a\xee\x3c\x53\x80\x26\x0f\x4d\xe2\x8b\x68\x41\x09\x7b\x5c\x7e\x8b\xc3\xb3\x96\xa8\xd8\x73\xa5\x2f\xc9\x51\xf2\x3d\x20\xaa\xf7\x78\x0f\xf8\x71\x86\xdc\x44\x59\xd4\x5c\xe9\x94\x4d\x4e\x2a\xb4\x8b\x83\x04\x8e\x41\x2e\xce\xc5\xf2\x45\x85\x6f\x0c\xcb\x77\xbb\x06\x1a\xda\x71\x93\xdc\xbe\x7f\x1d\xcb\x8a\x4b\x49\x0e\x20\x53\x53\x5c\x2e\x4e\x25\x89\xfb\x32\x25\x9a\x47\xeb\x33\x0b\xfa\xf5\xae\x2b\xcf\x66\xac\xaa\xfd\x8f\xd2\x7c\x3d\x0d\x99\xd3\xa0\xe9\x3e\x71\x38\x4c\xcb\x73\x2d\xad\x54\x08\x37\xe9\xac\x04\x15\xd0\xeb\x09\xda\x1f\x78\x14\x93\x98\x7f\xc2\x4e\xc0\x93\xc0\x1a\xf2\xd4\x67\x07\xc2\xec\xa2\x0a\x2b\x49\x75\xd1\x12\x3b\xc2\x4d\x68\x79\xa9\xcb\x3c\x2d\x37\xbe\xc5\x5a\x1c\xa2\x04\x29\x88\x1b\x7b\x50\x90\xd6\x68\x44\x1c\x3e\x27\xee\x09\x1f\xed\xdf\x66\x69\x03\xa4\xc1\x31\xd3\x4b\xb7\xc8\x50\x66\x8a\x4a\xa9\x77\x21\xeb\x78\xd2\xfa\x9a\x95\xa5\xb0\x13\x6f\xdb\x57\xb4\x1e\xc2\x34\x30\xc1\xa5\xfe\x25\xb5\xd0\xc9\x4f\x9d\x02\x7e\x37\xf9\xb4\x3c\x72\xd5\x9d\x44\xf4\x3a\x35\xd5\x8c\x97\xf2\xa0\x3d\x15\x15\x61\x1a\x76\x4d\x29\xe3\x0f\x02\xf5\x86\x12\xb5\x87\xf2\x1c\x1a\xc9\x35\xc7\x9c\xa6\x19\x86\xf7\x80\x26\xdd\x18\x66\xea\xab\x8b\x72\x33\x21\xc9\x81\x50\xd8\x39\x1c\x6f\x38\xa7\x80\x98\x15\x28\x24\xa0\xb2\xe0\x8c\x1e\x13\x90\x4a\x23\x19\x3d\x95\x50\x80\x6b\x49\xf4\xb1\xe0\x42\x2f\x9e\x15\xaa\x7d\x55\x28\xf2\x03\x6c\xdb\x3b\xed\xfa\x7e\xa0\xb5\xb3\x20\xe7\x88\x3b\xfb\x7d\x14\xf1\x97\x39\x8a\x50\x47\x85\xf5\x65\xb9\xb5\xd2\x25\x61\x05\x17\xc0\xa2\xb6\xa1\x34\x17\xc5\x4e\x22\x0c\x85\x00\x49\xb8\x57\x14\x96\x83\x2d\x6b\x89\x9a\xf9\xa7\xc3\x28\xb2\x63\xc8\xef\x77\x0c\xa8\xae\xc4\xf6\xc2\x43\x00\xad\xe3\xc6\x5e\x53\x52\x91\xb0\xd1\x78\x76\x6d\x42\xbe\xd6\xe5\x6a\xfe\x14\x6d\x26\x3d\x4b\x72\xd9\x33\x15\xc2\x7c\x81\x90\x50\x19\xec\x91\x3c\x23\x74\xb4\x86\xb9\x0d\xc4\x27\x5f\xdd\xe0\x5d\x97\xd5\xac\x6e\xc7\xbb\xe9\x17\xb2\xf6\xe2\xcf\x4a\xbd\xdc\x65\xac\x83\xd9\x8f\xdf\xa8\x6a\x15\x2d\xe2\x5a\x0c\x53\x73\x05\xc8\x08\x9d\x76\x5d\xb3\xff\x09\x0f\x6d\xe9\xa8\x85\x7b\x74\x93\xe0\xc7\xfb\x99\x12\x7d\xe7\x6b\x7b\xfd\xe4\x8c\xc0\xa0\xc1\x9c\x29\xa2\x34\x30\xec\x3f\x5f\xf5\x12\x6d\xc8\xa4\x79\x31\x15\xca\x7c\xdd\x95\x56\x75\xb5\x28\xb4\xeb\xfc\x6d\x72\xa1\x93\x6e\xab\x7d\x43\xfe\x97\xb0\xc2\x38\xe6\x22\xa0\x9a\x74\x36\xce\x0d\xb3\xce\xd1\xc5\x4c\x1e\x1a\x72\x19\x4f\x5c\x3e\x36\x01\xa9\x24\x7e\xcf\xb1\x72\x48\xce\x68\xe9\x3b\x67\x7d\xc3\x00\xbe\x5e\xb5\x09\x8d\xf6\xf6\xe7\xfb\xe6\x3d\x28\xd8\xd3\x26\x0a\x6d\x9c\xbe\x84\x2f\xd0\x36\x91\x41\x1e\xe2\xf1\x5e\x82\x96\xc4\x69\x25\x0c\x49\x93\x19\xdb\x41\xbd\xcf\x03\x77\x4d\x2a\xe0\xb5\xdf\x0d\xad\xcc\x8d\xd3\x13\xe5\x46\xcf\x3f\xa2\x54\x03\xe9\xea\xf4\xc1\x68\x20\x75\x75\x79\x54\x71\x29\x01\x0b\x58\xd9\xb6\x36\x92\xa2\x9b\x04\x41\x09\x46\x2a\x96\x41\x5c\x71\x0a\x5c\x8b\x12\x69\x28\xfa\x6b\x23\xe7\xe4\x6c\x33\xc9\x9a\x40\x12\x51\x0a\x94\xa8\x2a\x25\xf9\xc9\x4b\xa0\xc8\xeb\xfd\xa3\x79\x6f\x4b\xbe\x45\x84\xd6\x12\x0a\x84\x83\x6e\xda\xa1\xa8\x38\x23\x9a\x7b\xdd\x49\xda\x94\x15\x7a\x2e\x86\x69\x5b\x48\xac\x24\xb1\xab\xf1\xd4\x03\x5c\x63\x27\x74\xb1\xfb\xbc\xb4\x7a\x46\x45\xa7\x24\x3d\xb0\x63\x86\x19\x27\xac\x4b\x50\x8d\xdb\x19\xcf\xd7\xa3\xf4\x8b\x4a\x41\x23\xa9\x0b\xc1\x29\xe9\xd2\x85\x25\x44\x81\x39\xeb\xd6\x91\xb2\x73\xae\xdc\xaa\xcd\xbe\x69\x8a\x9d\x4a\xe8\xa8\x55\xb7\x04\x4f\x84\x95\xfc\xe9\x8c\x09\x97\x93\xb6\xa0\x08\x83\xe3\x45\xaf\x15\xb4\xd2\x12\x11\xa6\xcf\xee\x3b\xb9\x62\x11\x12\xb6\x20\x81\x4d\x2d\x22\x9b\xcf\xff\xb3\x70\x0d\x10\xe3\x2d\xce\x61\x8f\x50\xa2\x49\x84\xdf\xe0\xf8\xef\x5a\xe5\x5f\x91\x49\x8d\xe6\x1e\x89\xb8\x23\x2e\x9a\x43\x85\xa2\x2c\x16\x75\xb4\x87\x55\x41\xc5\xe7\xef\x6b\x5c\x71\x63\x39\xc6\xe2\x00\x5b\x20\xa3\x48\x6a\x7a\xf6\xa8\x82\x8b\xe5\x4f\x5d\xe2\x8d\xcd\x75\xbc\xe6\x27\x02\x55\x4b\xf9\x90\xe4\x36\x70\xee\x4d\x69\xb2\x77\xe0\x1d\xea\x0d\x0b\x14\xd5\xef\xdb\x3b\xd8\x57\x2c\xda\x1b\x1c\x01\xad\x3e\x8c\xf5\xca\xcd\x28\xab\x75\xb2\x8a\x83\xd7\x27\x96\x5b\x7f\x5b\x3a\xb9\x47\xa5\xbe\x1a\x0b\x69\x8d\xf0\x3e\xa9\x1c\x3b\x33\x07\xbf\xc2\x0f\x4d\x0e\x0d\xbc\x6e\xa8\x47\xfd\xf6\x42\xff\x27\x7b\xf6\xd7\xed\xaf\xfe\xa3\x89\xe8\xe5\xfd\x16\x75\x71\x1c\x4f\xb8\x7b\xf9\x0e\x74\xf6\xc6\xaa\x98\x04\x31\xaf\x2a\x7a\xd4\x6f\x55\xbc\xaa\x55\xd8\x6d\x31\x43\x25\xd3\x53\xb2\x39\x49\x9e\xfb\xb9\xc3\xda\x5e\x86\x0b\xf3\x7c\x62\x68\xe7\x35\x73\x4d\xf3\x01\x12\x38\x95\x75\x26\xed\x85\x38\xcf\xf9\x82\x7e\xff\xee\xc3\x4c\xf6\x36\x77\xc7\xee\x95\xd2\x9e\x05\x2e\x24\xf8\x75\xea\x14\xc6\x83\x74\xa7\x5f\x51\x85\xed\x7f\xa0\x9f\x7c\x53\xd5\xf0\xc9\x8e\x93\x53\xdc\x9f\x76\x0b\xaa\xfb\x1e\x6a\x6d\xc9\xc7\x81\x74\x37\x56\x8d\x40\xbb\x36\xcf\x0a\x82\x57\xec\x7d\x5f\x5a\xb9\x0d\xb0\xe1\x8b\xa7\x40\x4f\x7e\x65\xfe\x6d\xbf\x4e\x5b\xbd\xac\xfe\x1b\x00\x00\xff\xff\x45\x8a\x1d\x5b\x07\x3c\x00\x00") func dataConfig_schema_v33JsonBytes() ([]byte, error) { return bindataRead( @@ -152,7 +152,7 @@ func dataConfig_schema_v33Json() (*asset, error) { return a, nil } -var _dataConfig_schema_v34Json = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xec\x5b\xcd\x72\xdb\x38\x12\xbe\xeb\x29\x58\x4c\x6e\x91\xed\x54\x6d\x6a\xab\x36\xb7\x3d\xee\x69\xe7\x3c\x2e\x85\x05\x81\x2d\x09\x31\x08\x20\x0d\x50\xb6\x92\xf2\xbb\x4f\xf1\x57\xfc\x01\x01\x50\xa2\x63\x67\x26\x27\x5b\xe4\xd7\x00\xba\x1b\xf8\xba\x1b\x00\x7f\xac\xa2\x28\x7e\xaf\xe9\x01\x32\x12\x7f\x8e\xe2\x83\x31\xea\xf3\xdd\xdd\x57\x2d\xc5\x4d\xf5\xf4\x56\xe2\xfe\x2e\x45\xb2\x33\x37\x1f\x3f\xdd\x55\xcf\xde\xc5\xeb\x42\x8e\xa5\x85\x08\x95\x62\xc7\xf6\x49\xf5\x26\x39\xfe\xeb\xf6\xd3\x6d\x21\x5e\x41\xcc\x49\x41\x01\x92\xdb\xaf\x40\x4d\xf5\x0c\xe1\x5b\xce\x10\x0a\xe1\xfb\xf8\x08\xa8\x99\x14\xf1\x66\xbd\x2a\xde\x29\x94\x0a\xd0\x30\xd0\xf1\xe7\xa8\x18\x5c\x14\xb5\x90\xe6\x41\xa7\x59\x6d\x90\x89\x7d\x5c\x3e\x7e\x2e\x5b\x88\xa2\x58\x03\x1e\x19\xed\xb4\xd0\x0e\xf5\xdd\xdd\xb9\xfd\xbb\x16\xb6\x1e\xb6\xda\x19\x6c\xf9\x5c\x11\x63\x00\xc5\x1f\xe3\xb1\x95\xaf\xbf\xdc\x93\x9b\xef\xff\xbd\xf9\xf3\xe3\xcd\x7f\x6e\x93\x9b\xcd\x87\xf7\xbd\xd7\x85\x7d\x11\x76\x55\xf7\x29\xec\x98\x60\x86\x49\xd1\xf6\x1f\xb7\xc8\xe7\xfa\xbf\xe7\xb6\x63\x92\xa6\x25\x98\xf0\x5e\xdf\x3b\xc2\x35\xf4\x75\x16\x60\x1e\x25\x3e\xf8\x74\x6e\x61\xaf\xa4\x73\xdd\xbf\x45\xe7\xbe\x3a\x47\xc9\xf3\xcc\xeb\xc1\x06\xf5\x4a\xca\x54\xdd\x2f\xe3\x3f\x0d\x14\xc1\xf8\xa7\x6c\x85\x7a\xb5\x19\x5b\x74\xbf\x8c\xc2\x15\x6b\xf8\x14\x6e\x50\xaf\xa4\x70\xd5\xfd\x75\x0a\xaf\x1a\xa5\x9d\xd8\x0a\xd1\xe9\xbb\x1c\x60\x8f\xcf\x6c\xa6\xb2\xf1\xc9\xb4\xad\x5a\x63\x4d\x58\x29\x05\xc5\xe5\xa9\x78\x36\x61\x8f\x0a\x90\x81\x30\x71\x6b\x82\x28\x8a\xb7\x39\xe3\xe9\xd0\xa2\x52\xc0\xff\x8b\x26\xee\x3b\x0f\xa3\xe8\xc7\x90\xba\x3b\xed\x94\xef\x7b\xbf\xa6\x1d\xde\xbe\x9f\xd0\xa5\x7d\x4f\xa5\x30\xf0\x64\x4a\xa5\xdc\x5d\x57\x26\x90\xf4\x01\x70\xc7\x38\x84\x4a\x10\xac\x66\xf1\x84\xc9\x38\xd3\x26\x91\x98\xa4\x8c\x1a\xab\x3c\x27\x5b\xe0\x57\xb5\x40\x09\x3d\x40\xb2\x43\x99\x79\x5b\xd9\x25\x95\x26\xda\xda\x50\xc3\xce\x81\x9a\x1b\x82\x7b\xb0\x5b\x76\x00\x1e\x49\xfb\xd7\x4d\x2b\xda\xf9\xb5\x59\x59\x1a\x8c\x29\x51\x09\x49\xd3\xde\x38\x08\x22\x39\xc5\xeb\x28\x66\x06\x32\x6d\x57\x28\x8a\x73\xc1\xbe\xe5\xf0\xbf\x1a\x62\x30\x87\x61\xbb\x29\x4a\xb5\x7c\xc3\x7b\x94\xb9\x4a\x14\xc1\x62\x21\xb9\x8d\x1d\x53\x99\x65\x44\x2c\xb5\xba\xe6\xe8\x11\x60\xf9\x11\x87\x47\xdd\x25\x5b\xf7\xd1\x7d\xd5\xf6\xd6\x1b\xd6\x84\x36\x7e\x7d\xc6\x7c\xe1\x67\x0c\x3f\x67\x14\x94\x2b\x73\xa4\xa1\x14\xe0\x5e\x0a\x56\x7c\xce\xd2\x70\xf0\x7e\x0e\x38\x93\x69\x7f\xdc\x22\xcf\xb6\x80\xa3\x25\xd9\x5f\x59\xe3\xdf\x9b\x95\xed\xcd\xc0\xfb\x86\x30\x01\x98\x08\x92\xf9\x6c\x15\x53\x84\x14\x84\x61\x84\x27\x5a\x01\xed\xc1\x1b\x4f\x39\x3c\x13\x07\x51\x72\x8c\xb0\x67\xda\xe0\xc9\x4d\x4a\xcf\xdd\x81\xa5\xa0\x40\xa4\x3a\xa9\x0a\x8c\xf9\xec\x19\xa7\xd0\x56\x1b\x8b\xd2\x44\x2a\x5c\x51\xa1\x6a\xa6\x88\x0b\xc5\xd8\xe2\x81\x60\xa2\x81\x20\x3d\x5c\x28\x2f\x33\xc2\x44\x88\x53\x41\x18\x3c\x29\xc9\x2a\x1a\x7b\x73\xfc\x04\xe2\x98\xb4\xf3\x66\xb6\x19\x40\x1c\x19\x4a\x91\x35\x24\x1d\x16\x9d\x3b\xf2\x4f\x4a\x6a\xb8\x9e\x1c\x6b\x89\xfb\x46\xf1\x75\xbb\xa6\x37\x7d\xeb\xc5\x3b\x89\x19\x29\x06\xdb\xf4\xdd\x5d\xc3\xbd\xae\xc6\x33\xaf\x6b\xc0\xae\x0e\x45\x56\x4d\x78\xc2\x99\x78\x58\x7e\x8a\xc3\x93\x41\x92\x1c\xa4\x36\x97\x24\x40\xf1\x01\x08\x37\x07\x7a\x00\xfa\xe0\x10\xef\xa2\x7a\xd2\x52\x9b\x90\x49\xce\x32\xb2\xf7\x83\x14\xf5\x41\x2e\x4e\xf4\xe2\x45\x8d\xdf\x69\x56\xee\xf7\x05\x74\x6a\xc6\x8d\x0a\x87\xfa\xb5\x2f\xe5\x4e\x91\x1d\x01\x43\xb3\x48\xa9\xce\xf5\xce\xf0\x65\x48\x34\xf7\x16\x7f\x3d\xe8\x97\xdb\xaa\xf6\x73\xac\xaa\xf2\x3f\xce\xe3\xcd\x38\x64\x8e\x83\xe6\xf0\xc9\x40\xc3\xb0\x3c\xb7\xe7\x95\x8c\xd0\x22\x9d\x45\xd0\x13\x7e\x3d\x43\xeb\x7c\x3d\x19\xc5\xfc\x33\x76\x04\x1e\x05\xd6\x29\xa6\xbe\xa8\x8c\x98\x5f\xbe\x05\xb9\xce\x5b\xbf\x7b\xb4\x99\x1a\x5e\xe8\x30\xcf\xc3\xf5\x4f\xb1\x12\x47\x38\x23\x1a\xfc\x8b\xdd\x59\x8f\xb5\xad\x31\x75\xfc\x14\x38\x27\x6c\xb2\xff\x76\xca\x4e\x88\x4e\xb6\x19\x5e\xba\x79\x9a\xea\xa6\xa8\x9c\x5b\x07\xb2\xf1\x27\xad\x2f\x59\x59\xaa\x7e\xe2\xdd\xe7\x8a\x92\x21\xba\x0b\x4c\x49\x34\x3f\xa5\x16\x3a\xf3\xd4\x39\xe0\x57\x9d\x8f\xcb\xa3\xa1\xbb\x83\x84\x5e\xa6\xa6\x72\xb0\x94\x05\x6d\xa9\xa8\x98\x30\xb0\x2f\x4a\x19\x7b\x10\xc8\xb7\x9c\xe9\x03\xa4\x73\x64\x50\x1a\x49\x25\x0f\x5b\x18\xd6\xdd\x9f\xf0\xc5\xe0\xa8\xaf\x2e\xca\xcd\x14\xb2\x23\xe3\xb0\x1f\x68\xbc\x95\x92\x03\x11\xbd\x40\x81\x40\xd2\x44\x0a\x7e\x0a\x40\x6a\x43\xd0\xbb\x2b\xa1\x81\xe6\xc8\xcc\x29\x91\xca\x2c\x9e\x15\xea\x43\x96\x68\xf6\x1d\xfa\x6b\xef\x3c\xeb\xeb\x86\x36\x83\x01\x0d\xf6\xcf\xa3\xdf\x5b\x11\xff\x98\xad\x08\x7d\xd2\xd4\x5c\x96\x5b\x6b\x93\x32\x91\x48\x05\xc2\xbb\x36\xb4\x91\x2a\xd9\x23\xa1\x90\x28\x40\x26\xad\xa6\xe8\x11\x6c\x9a\x23\x29\xfa\x1f\x37\xa3\xd9\x5e\x10\x3b\xef\x74\xa0\x26\x53\xbb\x0b\x37\x01\x8c\xf1\x2f\xf6\x9c\xb3\x8c\x4d\x2f\x1a\xcb\xac\x0d\xc8\xd7\xaa\x5c\xcd\x9e\xa2\x39\xd2\xb3\x20\xca\x76\x54\x08\xee\x02\x21\xa0\x32\x38\x10\x9c\x11\x3a\xca\x85\xb9\x9b\x88\x4f\xb6\xba\xc1\x3a\xae\xde\x49\x78\xd9\xde\xba\x1e\xc8\xc6\x8a\x9f\x95\x7a\x0d\x87\xb1\x99\xcc\x7e\xec\x8b\x2a\xd7\xde\x22\xae\xc4\x08\xed\x2a\x40\x5a\xe8\xf8\x48\x37\xfa\x25\x18\xba\xe7\xa3\x12\x6e\xf1\x4d\x00\x8f\xd7\x3d\x05\x72\xe7\x4b\xb3\x7e\x70\x46\xd0\x91\xa1\x52\x68\xa6\x0d\x08\x6a\xdf\x5f\xb5\x0a\x6d\xd9\xe8\xf0\x62\x6c\x14\x77\xdd\x15\x56\x75\x95\x28\xb2\xaf\xf8\x36\xb8\xd0\x09\x5f\xab\xf5\x69\xff\x4f\x51\x45\x48\x2a\xd5\x84\x6b\xc2\xd5\x98\x1b\x66\x07\x5b\x17\x8e\x3c\x74\x8a\x32\x1e\x25\x3e\x14\x01\x29\x65\x76\xe6\x58\x0d\x44\x66\xdc\x17\x18\xec\xf5\x35\x0d\xd8\x0e\xc2\xbb\x50\xef\xc5\x01\xf7\xa1\x7c\x0d\x9a\x3c\x30\x67\x9a\x6c\x07\xe7\x12\xb6\x40\x5b\x44\x06\x3c\xfa\xe3\x3d\x82\x41\x36\x38\x4a\x68\x92\xa6\x6e\x6c\x07\xfd\x36\x37\xdc\x0d\xcb\x40\xe6\xce\x23\xe1\xf6\xa2\x4f\x65\xc0\xf3\x85\x02\x8f\x53\x3b\xc8\xa1\x4f\xef\x3b\x07\x48\x55\x5d\xee\x75\x5c\x48\xc0\x02\x91\x96\x47\x1b\x41\xd1\x0d\x41\x71\x46\x89\xf6\x65\x10\x57\xec\x02\xe7\x2a\x25\x06\x92\xfa\x4e\xca\x9c\x9c\xcd\x91\xac\x29\x82\x84\x73\xe0\x4c\x67\x21\xc9\x4f\x9c\x02\x27\x56\xf6\xf7\xe6\xbd\xa5\xf8\x8e\x30\x9e\x23\x24\x84\x4e\xd2\xf4\x40\x22\x93\x82\x19\x69\xa5\x93\xb0\x2e\x33\xf2\x94\x34\xdd\x96\x10\xcf\xea\x2a\x85\x24\xa6\xf6\xe4\x67\x5d\xcc\x8b\x3c\xb3\xa4\x1f\x71\x59\x38\xdf\xec\x18\x6a\x53\x55\xa9\x52\xd5\xbf\xfa\x34\xfb\x3c\x59\xf9\x87\x6e\x16\x77\x66\x5d\x95\x27\xcc\x4b\xe1\x1d\xd3\xe1\x5c\x10\x4c\xcc\xce\xa6\xc7\x91\xc5\x10\x74\x41\x71\xed\x5e\xbe\x57\xde\x1b\x4c\xea\xad\x88\x44\x49\xce\xaa\x8c\x63\x09\x0d\xa9\x14\x95\x91\x43\x26\xdf\x95\xb3\xbd\x98\x7a\x45\xbd\x94\x29\xe3\x25\x86\x52\xe0\x91\x89\x54\x3e\xce\xe8\x70\xb9\xa9\xa4\x38\xa1\x30\x20\xe2\x6b\x0d\xad\x0d\x12\x26\xcc\xec\xa3\xab\xa1\x59\x14\xc2\x0e\x10\xc4\x78\xa2\x47\xee\x12\x22\x9a\x2e\x23\x7c\xba\xf9\x35\xac\x11\x5a\x15\xb9\xf4\x2b\xec\x20\x5e\xeb\xfc\x2b\x92\xb1\x76\x15\x7b\x82\x76\x8b\xf3\xa6\x61\x53\x81\x9a\xaa\xdc\x7b\x0c\x96\x41\x26\xdd\x57\x3e\xae\xb8\x51\xed\x53\xb1\x81\x2d\x90\x94\x04\x9d\x9b\xd6\xa8\x44\xaa\xe5\x37\x6e\xfc\x67\xa3\x1b\x3f\x6d\x33\x45\xb2\xa5\x38\x24\xf8\x24\x39\xb6\x66\x45\xd1\x1b\x60\x87\x7c\x2b\xc2\xee\x48\xbe\x31\x76\xe8\xdf\xd2\x28\x2f\x81\x4c\x78\xf5\xbe\x2d\x79\xd6\xad\xad\x36\xc1\x2e\x9e\xbc\x81\xb1\xdc\xf8\xcb\xea\x6b\xb8\xdb\x6a\x2b\xd3\x88\x31\x84\x1e\x82\x2a\xba\x99\x69\xfc\x15\x3c\x34\xda\x77\xb0\xd2\x50\x8d\x5a\x80\x85\x42\xae\xc4\xfc\x3d\x98\xea\x57\x9f\xd7\x3f\x6f\x0e\xd6\x1f\x7e\x78\x3f\x40\x28\x51\x17\xc7\xfa\x80\x2b\x9e\x6f\xc0\x67\xaf\xec\x8a\x51\xa0\xb3\xba\xa2\x46\xfd\x76\xc5\x8b\xae\x8a\xfe\xe9\x5b\xc7\x25\xe3\xcd\x38\x97\x25\x83\xaf\x08\xd5\x12\x9b\xfe\x30\x86\x30\xcb\x67\x92\xfd\xdc\xc7\x75\x36\xdf\x40\x26\x36\x7f\x07\x9d\xd6\x46\x74\x6b\xbe\x20\xef\xdf\x7e\x70\x64\x78\xae\xab\x7c\x2f\x94\x1a\x2d\x70\xef\xc1\xee\xd3\x41\xf1\xdc\x58\x77\xfc\x25\xd8\xf4\xfa\x6f\xe4\x47\xdf\x85\x15\x7a\x8a\xd3\x68\xb3\xf8\x47\xff\xa4\xab\xfa\xa6\x6b\xd3\xb3\xcf\x00\x52\x5d\x8c\xed\x04\xda\x4d\x77\x3f\x61\xf2\x26\xbf\xed\x6b\xb1\xe1\x39\x5b\xf3\xd5\xd6\xc4\xd1\xff\xaa\xfb\xb7\xfc\xc2\x6e\xf5\xbc\xfa\x2b\x00\x00\xff\xff\x54\x48\x04\xd1\xcb\x3c\x00\x00") +var _dataConfig_schema_v34Json = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xec\x5b\xcd\x72\xdb\x38\x12\xbe\xeb\x29\x58\x4c\x6e\x91\xed\x54\x6d\x6a\xab\x36\xb7\x3d\xee\x69\xe7\x3c\x2e\x85\x05\x81\x2d\x09\x31\x08\x20\x0d\x50\xb6\x92\xf2\xbb\x4f\xf1\x57\xfc\x01\x01\x50\xa2\x63\x67\x26\x27\x5b\xe4\xd7\x00\xba\x81\xfe\xba\x1b\x00\x7f\xac\xa2\x28\x7e\xaf\xe9\x01\x32\x12\x7f\x8e\xe2\x83\x31\xea\xf3\xdd\xdd\x57\x2d\xc5\x4d\xf5\xf4\x56\xe2\xfe\x2e\x45\xb2\x33\x37\x1f\x3f\xdd\x55\xcf\xde\xc5\xeb\x42\x8e\xa5\x85\x08\x95\x62\xc7\xf6\x49\xf5\x26\x39\xfe\xeb\xf6\xd3\x6d\x21\x5e\x41\xcc\x49\x41\x01\x92\xdb\xaf\x40\x4d\xf5\x0c\xe1\x5b\xce\x10\x0a\xe1\xfb\xf8\x08\xa8\x99\x14\xf1\x66\xbd\x2a\xde\x29\x94\x0a\xd0\x30\xd0\xf1\xe7\xa8\x18\x5c\x14\xb5\x90\xe6\x41\xa7\x59\x6d\x90\x89\x7d\x5c\x3e\x7e\x2e\x5b\x88\xa2\x58\x03\x1e\x19\xed\xb4\xd0\x0e\xf5\xdd\xdd\xb9\xfd\xbb\x16\xb6\x1e\xb6\xda\x19\x6c\xf9\x5c\x11\x63\x00\xc5\x1f\xe3\xb1\x95\xaf\xbf\xdc\x93\x9b\xef\xff\xbd\xf9\xf3\xe3\xcd\x7f\x6e\x93\x9b\xcd\x87\xf7\xbd\xd7\x85\x7d\x11\x76\x55\xf7\x29\xec\x98\x60\x86\x49\xd1\xf6\x1f\xb7\xc8\xe7\xfa\xbf\xe7\xb6\x63\x92\xa6\x25\x98\xf0\x5e\xdf\x3b\xc2\x35\xf4\x75\x16\x60\x1e\x25\x3e\xf8\x74\x6e\x61\xaf\xa4\x73\xdd\xbf\x45\xe7\xbe\x3a\x47\xc9\xf3\xcc\x3b\x83\x0d\xea\x95\x94\xa9\xba\x5f\x66\xfe\x34\x50\x04\xe3\x5f\xb2\x15\xea\xd5\x56\x6c\xd1\xfd\x32\x0a\x57\xac\xe1\x53\xb8\x41\xbd\x92\xc2\x55\xf7\xd7\x29\xbc\x6a\x94\x76\x62\x2b\x44\xa7\xef\x72\x80\x3d\x3e\xb3\x99\xca\xc6\x27\xd3\xb6\x6a\x8d\x35\x61\xa5\x14\x14\x97\xa7\xe2\xd9\x84\x3d\x2a\x40\x06\xc2\xc4\xad\x09\xa2\x28\xde\xe6\x8c\xa7\x43\x8b\x4a\x01\xff\x2f\x9a\xb8\xef\x3c\x8c\xa2\x1f\x43\xea\xee\xb4\x53\xbe\xef\xfd\x9a\x9e\xf0\xf6\xfd\x84\x2e\xed\x7b\x2a\x85\x81\x27\x53\x2a\xe5\xee\xba\x32\x81\xa4\x0f\x80\x3b\xc6\x21\x54\x82\x60\xb5\x8a\x27\x4c\xc6\x99\x36\x89\xc4\x24\x65\xd4\x58\xe5\x39\xd9\x02\xbf\xaa\x05\x4a\xe8\x01\x92\x1d\xca\xcc\xdb\xca\x2e\xa9\x34\xd1\xd6\x86\x1a\x76\x0e\xd4\xdc\x10\xdc\x83\xdd\xb2\x03\xf0\x48\xda\xef\x37\xad\x68\xe7\xd7\x66\x65\x69\x30\xa6\x44\x25\x24\x4d\x7b\xe3\x20\x88\xe4\x14\xaf\xa3\x98\x19\xc8\xb4\x5d\xa1\x28\xce\x05\xfb\x96\xc3\xff\x6a\x88\xc1\x1c\x86\xed\xa6\x28\xd5\xf2\x0d\xef\x51\xe6\x2a\x51\x04\x0b\x47\x72\x1b\x3b\xa6\x32\xcb\x88\x58\xca\xbb\xe6\xe8\x11\x60\xf9\x11\x87\x47\x5d\x97\xad\xfb\xe8\xbe\x6a\x7b\xeb\x0d\x6b\x42\x1b\xbf\x3e\x63\xbe\xf0\x33\x86\x9f\x33\x0a\xca\x95\x39\xd2\x50\x0a\x70\xbb\x82\x15\x9f\xb3\x34\x1c\xbc\x9f\x03\xce\x64\xda\x1f\xb7\xc8\xb3\x2d\xe0\xc8\x25\xfb\x9e\x35\xfe\xbd\x59\xd9\xde\x0c\x66\xdf\x10\x26\x00\x13\x41\x32\x9f\xad\x62\x8a\x90\x82\x30\x8c\xf0\x44\x2b\xa0\x3d\x78\x33\x53\x8e\x99\x89\x83\x28\x39\x46\xd8\x33\x6d\xf0\xe4\x26\xa5\xe7\xee\xc0\x52\x50\x20\x52\x9d\x54\x05\xc6\x7c\xf6\x8c\x53\x68\xab\x8d\x45\x69\x22\x15\xae\xa8\x50\x35\x53\xc4\x85\x62\x6c\xf1\x40\x30\xd1\x40\x90\x1e\x2e\x94\x97\x19\x61\x22\x64\x52\x41\x18\x3c\x29\xc9\x2a\x1a\x7b\x73\xfc\x04\xe2\x98\xb4\xeb\x66\xb6\x19\x40\x1c\x19\x4a\x91\x35\x24\x1d\x16\x9d\x3b\xf2\x4f\x4a\x6a\xb8\x9e\x1c\x6b\x89\xfb\x46\xf1\x75\xeb\xd3\x9b\xbe\xf5\xe2\x9d\xc4\x8c\x14\x83\x6d\xfa\xee\xfa\x70\xaf\xab\xf1\xca\xeb\x1a\xb0\xab\x43\x91\x55\x13\x9e\x70\x26\x1e\x96\x5f\xe2\xf0\x64\x90\x24\x07\xa9\xcd\x25\x09\x50\x7c\x00\xc2\xcd\x81\x1e\x80\x3e\x38\xc4\xbb\xa8\x9e\xb4\xd4\x26\x64\x91\xb3\x8c\xec\xfd\x20\x45\x7d\x90\x8b\x13\xbd\x78\x51\xe3\x77\x9a\x95\xfb\x7d\x01\x9d\x5a\x71\xa3\xc2\xa1\x7e\xed\x4b\xb9\x53\x64\x47\xc0\xd0\x2c\x52\xaa\x73\xbd\x33\x7c\x19\x12\xcd\xbd\xc5\x5f\x0f\xfa\xe5\xb6\xaa\xfd\x1c\x5e\x55\xfe\xc7\x79\xbc\x19\x87\xcc\x71\xd0\x1c\x3e\x19\x68\x18\x96\xe7\xf6\x66\x25\x23\xb4\x48\x67\x11\xf4\xc4\xbc\x9e\xa1\x75\xbe\x9e\x8c\x62\xfe\x19\x3b\x02\x8f\x02\xeb\x14\x53\x5f\x54\x46\xcc\x2f\xdf\x82\xa6\xce\x5b\xbf\x7b\xb4\x99\x1a\x5e\xe8\x30\xcf\xc3\xf5\x2f\xb1\x12\x47\x38\x23\x1a\xfc\xce\xee\xac\xc7\xda\xd6\x98\x3a\x7e\x0a\x5c\x13\x36\xd9\x7f\x3b\x65\x27\x44\x27\xdb\x0c\x2f\xdd\x3c\x4d\x75\x53\x54\xce\xad\x03\xd9\xf8\x93\xd6\x97\xac\x2c\x55\x3f\xf1\xee\x73\x45\xc9\x10\x5d\x07\x53\x12\xcd\x4f\xa9\x85\xce\x3c\x75\x0e\xf8\x55\xe7\xe3\xf2\x68\x38\xdd\x41\x42\x2f\x53\x53\x39\x58\xca\x82\xb6\x54\x54\x4c\x18\xd8\x17\xa5\x8c\x3d\x08\xe4\x5b\xce\xf4\x01\xd2\x39\x32\x28\x8d\xa4\x92\x87\x39\x86\x75\xf7\x27\xdc\x19\x1c\xf5\xd5\x45\xb9\x99\x42\x76\x64\x1c\xf6\x03\x8d\xb7\x52\x72\x20\xa2\x17\x28\x10\x48\x9a\x48\xc1\x4f\x01\x48\x6d\x08\x7a\x77\x25\x34\xd0\x1c\x99\x39\x25\x52\x99\xc5\xb3\x42\x7d\xc8\x12\xcd\xbe\x43\xdf\xf7\xce\xab\xbe\x6e\x68\x33\x18\xd0\x60\xff\x3c\xfa\xbd\x15\xf1\x8f\xd9\x8a\xd0\x27\x4d\xcd\x65\xb9\xb5\x36\x29\x13\x89\x54\x20\xbc\xbe\xa1\x8d\x54\xc9\x1e\x09\x85\x44\x01\x32\x69\x35\x45\x8f\x60\xd3\x1c\x49\xd1\xff\xb8\x19\xcd\xf6\x82\xd8\x79\xa7\x03\x35\x99\xda\x5d\xb8\x09\x60\x8c\xdf\xd9\x73\xce\x32\x36\xed\x34\x96\x55\x1b\x90\xaf\x55\xb9\x9a\x3d\x45\x73\xa4\x67\x41\x94\xed\xa8\x10\xdc\x05\x42\x40\x65\x70\x20\x38\x23\x74\x94\x8e\xb9\x9b\x88\x4f\xb6\xba\xc1\x3a\xae\xde\x49\x78\xd9\xde\xba\x1e\xc8\xc6\x8a\x9f\x95\x7a\x0d\x87\xb1\x99\xcc\x7e\xec\x4e\x95\x6b\x6f\x11\x57\x62\x84\x76\x15\x20\x2d\x74\x7c\xa4\x1b\xfd\x12\x0c\xdd\x9b\xa3\x12\x6e\x99\x9b\x00\x1e\xaf\x7b\x0a\xe4\xce\x97\x66\xfd\xe0\x8c\xa0\x23\x43\xa5\xd0\x4c\x1b\x10\xd4\xbe\xbf\x6a\x15\xda\xb2\xd1\xe1\xc5\xd8\x28\xee\xba\x2b\xac\xea\x2a\x51\x64\x5f\xf1\x6d\x70\xa1\x13\xee\xab\xf5\x69\xff\x4f\x51\x45\x48\x2a\xd5\xc4\xd4\x84\xab\x31\x37\xcc\x0e\xb6\x2e\x1c\x79\xe8\x14\x65\x3c\x4a\x7c\x28\x02\x52\xca\xec\xcc\xb1\x1a\x88\xcc\xb8\x2f\x30\xd8\xeb\x6b\x1a\xb0\x1d\x84\x77\xa1\xde\x8b\x03\xee\x43\xf9\x1a\x34\x79\x60\xce\x34\xd9\x0e\xce\x25\x6c\x81\xb6\x88\x0c\x78\xf4\xc7\x7b\x04\x83\x6c\x70\x94\xd0\x24\x4d\xdd\xd8\x0e\xfa\x6d\x6e\xb8\x1b\x96\x81\xcc\x9d\x47\xc2\xed\x45\x9f\xca\x80\xe7\x0b\x05\x9e\x49\xed\x20\x87\x73\x7a\xdf\x39\x40\xaa\xea\x72\xef\xc4\x85\x04\x2c\x10\x69\x79\xb4\x11\x14\xdd\x10\x14\x67\x94\x68\x5f\x06\x71\xc5\x2e\x70\xae\x52\x62\x20\xa9\xef\xa4\xcc\xc9\xd9\x1c\xc9\x9a\x22\x48\x38\x07\xce\x74\x16\x92\xfc\xc4\x29\x70\x62\x65\x7f\x6f\xde\x5b\x8a\xef\x08\xe3\x39\x42\x42\xe8\x24\x4d\x0f\x24\x32\x29\x98\x91\x56\x3a\x09\xeb\x32\x23\x4f\x49\xd3\x6d\x09\xf1\x78\x57\x29\x24\x31\xb5\x27\x3f\xeb\x62\x5d\xe4\x99\x25\xfd\x88\xcb\xc2\xf9\x66\xc7\x50\x9b\xaa\x4a\x95\xaa\xfe\xd5\xa7\xd9\xe7\xc9\xca\x3f\x74\xb3\xb8\xb3\xea\xaa\x3c\x61\x5e\x0a\xef\x58\x0e\xe7\x82\x60\x62\x75\x36\x3d\x8e\x2c\x86\xa0\x0b\x8a\x6b\xf7\xf2\xbd\xf2\x8b\x5a\xa1\x30\x7d\xa2\x24\x67\x55\x6a\xb2\x84\x29\xa8\x14\xd5\x38\x42\x56\xe9\x95\x6e\x51\xac\xd1\xa2\xb0\xca\x94\xf1\x32\x48\x29\xf0\xc8\x44\x2a\x1f\x67\x74\xb8\x9c\xb5\x15\x27\x14\x06\x8c\x7d\xad\xa1\xb5\x41\xc2\x84\x99\x7d\xc6\x35\x34\x8b\x42\xd8\x01\x82\x18\x7b\x44\xe4\xae\x35\xa2\xe9\x7a\xc3\xa7\x9b\x5f\xc3\x1a\xa1\x55\x91\x74\xbf\xc2\x56\xe3\xb5\x93\x7f\x45\xd6\xd6\xba\xbb\x27\xba\xb7\x38\x6f\xbe\x36\x15\xd1\xa9\xca\xbd\xe7\x65\x19\x64\xd2\x7d\x37\xe4\x8a\xab\xd7\x3e\x15\x1b\xd8\x02\xd9\x4b\xd0\x01\x6b\x8d\x4a\xa4\x5a\x7e\x87\xc7\x7f\x88\xba\xf1\xef\x2f\x30\x45\xb2\xa5\x38\x24\xf8\xc8\x39\xb6\xa6\x4f\xd1\x1b\x60\x87\x7c\x2b\xc2\x2e\x53\xbe\x31\x76\xe8\x5f\xe7\x28\x6f\x8b\x4c\xcc\xea\x7d\x5b\x1b\xad\x5b\x5b\x6d\x82\xa7\x78\xf2\xaa\xc6\x72\xe3\x2f\xcb\xb4\xe1\xb6\xac\xad\x9e\x23\xc6\x10\x7a\x08\x2a\xfd\x66\xe6\xfb\x57\xf0\xd0\x68\x83\xc2\x4a\x43\x35\x6a\x01\x16\x0a\xb9\x3b\xf3\xf7\x60\xaa\x5f\x7d\x5d\xff\xbc\x35\x58\x7f\x21\xe2\xfd\x52\xa1\x44\x5d\x1c\xeb\x03\xee\x82\xbe\x81\x39\x7b\xe5\xa9\x18\x05\x3a\xeb\x54\xd4\xa8\xdf\x53\xf1\xa2\x5e\xd1\x3f\xa6\xeb\x4c\xc9\x78\xd7\xce\x65\xc9\xe0\xbb\x44\xb5\xc4\xa6\x3f\x8c\x21\xcc\xf2\x3d\x65\x3f\xf7\x71\x1d\xe2\x37\x90\x89\x5d\xe2\x41\xa7\xb5\x11\xdd\x9a\x2f\xc8\xfb\xb7\x1f\x1c\x19\x9e\xeb\xce\xdf\x0b\xa5\x46\x0b\x5c\x90\xb0\xcf\xe9\xa0\x78\x6e\xac\x3b\xfe\x64\x6c\xda\xff\x1b\xf9\xd1\x07\x64\x85\x9e\xe2\x34\xda\x55\xfe\xd1\x3f\x12\xab\x3e\xfe\xda\xf4\xec\x33\x80\x54\x37\x68\x3b\x81\x76\xd3\xdd\x4f\x98\xbc\xf2\x6f\xfb\xac\x6c\x78\x20\xd7\x7c\xde\x35\x71\x47\x60\xd5\xfd\x5b\x7e\x8a\xb7\x7a\x5e\xfd\x15\x00\x00\xff\xff\xfa\xb6\x96\x65\xf4\x3c\x00\x00") func dataConfig_schema_v34JsonBytes() ([]byte, error) { return bindataRead( diff --git a/components/cli/cli/compose/schema/data/config_schema_v3.0.json b/components/cli/cli/compose/schema/data/config_schema_v3.0.json index fbcd8bb859..f39344cfbe 100644 --- a/components/cli/cli/compose/schema/data/config_schema_v3.0.json +++ b/components/cli/cli/compose/schema/data/config_schema_v3.0.json @@ -240,7 +240,8 @@ "properties": { "limits": {"$ref": "#/definitions/resource"}, "reservations": {"$ref": "#/definitions/resource"} - } + }, + "additionalProperties": false }, "restart_policy": { "type": "object", diff --git a/components/cli/cli/compose/schema/data/config_schema_v3.1.json b/components/cli/cli/compose/schema/data/config_schema_v3.1.json index b7037485f9..719c0fa7ac 100644 --- a/components/cli/cli/compose/schema/data/config_schema_v3.1.json +++ b/components/cli/cli/compose/schema/data/config_schema_v3.1.json @@ -269,7 +269,8 @@ "properties": { "limits": {"$ref": "#/definitions/resource"}, "reservations": {"$ref": "#/definitions/resource"} - } + }, + "additionalProperties": false }, "restart_policy": { "type": "object", diff --git a/components/cli/cli/compose/schema/data/config_schema_v3.2.json b/components/cli/cli/compose/schema/data/config_schema_v3.2.json index a5bd3686fa..8d850d5d2e 100644 --- a/components/cli/cli/compose/schema/data/config_schema_v3.2.json +++ b/components/cli/cli/compose/schema/data/config_schema_v3.2.json @@ -314,7 +314,8 @@ "properties": { "limits": {"$ref": "#/definitions/resource"}, "reservations": {"$ref": "#/definitions/resource"} - } + }, + "additionalProperties": false }, "restart_policy": { "type": "object", diff --git a/components/cli/cli/compose/schema/data/config_schema_v3.3.json b/components/cli/cli/compose/schema/data/config_schema_v3.3.json index e69116c388..f1eb9a6610 100644 --- a/components/cli/cli/compose/schema/data/config_schema_v3.3.json +++ b/components/cli/cli/compose/schema/data/config_schema_v3.3.json @@ -348,7 +348,8 @@ "properties": { "limits": {"$ref": "#/definitions/resource"}, "reservations": {"$ref": "#/definitions/resource"} - } + }, + "additionalProperties": false }, "restart_policy": { "type": "object", diff --git a/components/cli/cli/compose/schema/data/config_schema_v3.4.json b/components/cli/cli/compose/schema/data/config_schema_v3.4.json index 7edf9d6a55..5a110a8880 100644 --- a/components/cli/cli/compose/schema/data/config_schema_v3.4.json +++ b/components/cli/cli/compose/schema/data/config_schema_v3.4.json @@ -353,7 +353,8 @@ "properties": { "limits": {"$ref": "#/definitions/resource"}, "reservations": {"$ref": "#/definitions/resource"} - } + }, + "additionalProperties": false }, "restart_policy": { "type": "object", From 2e782847eb7c94ce998acfb125fe72a32e92ca3b Mon Sep 17 00:00:00 2001 From: Daniel Nephin Date: Fri, 18 Aug 2017 12:49:23 -0400 Subject: [PATCH 26/47] Add unit tests for initializing the client. Signed-off-by: Daniel Nephin Upstream-commit: 930f97dd09380a4c7e93590abeaa3f34ac6b00e6 Component: cli --- components/cli/cli/command/cli_test.go | 57 ++++++++++++++++++++++++++ 1 file changed, 57 insertions(+) create mode 100644 components/cli/cli/command/cli_test.go diff --git a/components/cli/cli/command/cli_test.go b/components/cli/cli/command/cli_test.go new file mode 100644 index 0000000000..ca73a05e38 --- /dev/null +++ b/components/cli/cli/command/cli_test.go @@ -0,0 +1,57 @@ +package command + +import ( + "os" + "testing" + + "github.com/docker/cli/cli/config/configfile" + "github.com/docker/cli/cli/flags" + "github.com/docker/docker/api" + "github.com/docker/docker/client" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func TestNewAPIClientFromFlags(t *testing.T) { + host := "unix://path" + opts := &flags.CommonOptions{Hosts: []string{host}} + configFile := &configfile.ConfigFile{ + HTTPHeaders: map[string]string{ + "My-Header": "Custom-Value", + }, + } + apiclient, err := NewAPIClientFromFlags(opts, configFile) + require.NoError(t, err) + assert.Equal(t, host, apiclient.DaemonHost()) + + expectedHeaders := map[string]string{ + "My-Header": "Custom-Value", + "User-Agent": UserAgent(), + } + assert.Equal(t, expectedHeaders, apiclient.(*client.Client).CustomHTTPHeaders()) + assert.Equal(t, api.DefaultVersion, apiclient.ClientVersion()) +} + +func TestNewAPIClientFromFlagsWithAPIVersionFromEnv(t *testing.T) { + customVersion := "v3.3.3" + defer patchEnvVariable(t, "DOCKER_API_VERSION", customVersion)() + + opts := &flags.CommonOptions{} + configFile := &configfile.ConfigFile{} + apiclient, err := NewAPIClientFromFlags(opts, configFile) + require.NoError(t, err) + assert.Equal(t, customVersion, apiclient.ClientVersion()) +} + +// TODO: move to gotestyourself +func patchEnvVariable(t *testing.T, key, value string) func() { + oldValue, ok := os.LookupEnv(key) + require.NoError(t, os.Setenv(key, value)) + return func() { + if !ok { + require.NoError(t, os.Unsetenv(key)) + return + } + require.NoError(t, os.Setenv(key, oldValue)) + } +} From 31162a9a25b39752bb35a3e1a3a87779957e4aa5 Mon Sep 17 00:00:00 2001 From: Christophe Vidal Date: Sat, 19 Aug 2017 21:13:29 +0700 Subject: [PATCH 27/47] Dropped hyphen in bind mount where appropriate Signed-off-by: Christophe Vidal Upstream-commit: 037029414dafb208fb08ab4126cdf8f29ee6cffa Component: cli --- .../cli/cli/command/container/opts_test.go | 6 ++--- .../cli/docs/reference/commandline/run.md | 4 ++-- .../reference/commandline/service_create.md | 22 +++++++++---------- .../reference/commandline/service_update.md | 4 ++-- components/cli/docs/reference/run.md | 2 +- components/cli/man/docker-run.1.md | 4 ++-- components/cli/man/src/container/create.md | 4 ++-- 7 files changed, 23 insertions(+), 23 deletions(-) diff --git a/components/cli/cli/command/container/opts_test.go b/components/cli/cli/command/container/opts_test.go index 25e5b04fc8..b3a59d3999 100644 --- a/components/cli/cli/command/container/opts_test.go +++ b/components/cli/cli/command/container/opts_test.go @@ -135,19 +135,19 @@ func TestParseRunVolumes(t *testing.T) { t.Fatalf("Error parsing volume flags, %s is missing from volumes. Received %v", arr[1], config.Volumes) } - // A single bind-mount + // A single bind mount arr, tryit = setupPlatformVolume([]string{`/hostTmp:/containerTmp`}, []string{os.Getenv("TEMP") + `:c:\containerTmp`}) if config, hostConfig := mustParse(t, tryit); hostConfig.Binds == nil || hostConfig.Binds[0] != arr[0] { t.Fatalf("Error parsing volume flags, %q should mount-bind the path before the colon into the path after the colon. Received %v %v", arr[0], hostConfig.Binds, config.Volumes) } - // Two bind-mounts. + // Two bind mounts. arr, tryit = setupPlatformVolume([]string{`/hostTmp:/containerTmp`, `/hostVar:/containerVar`}, []string{os.Getenv("ProgramData") + `:c:\ContainerPD`, os.Getenv("TEMP") + `:c:\containerTmp`}) if _, hostConfig := mustParse(t, tryit); hostConfig.Binds == nil || compareRandomizedStrings(hostConfig.Binds[0], hostConfig.Binds[1], arr[0], arr[1]) != nil { t.Fatalf("Error parsing volume flags, `%s and %s` did not mount-bind correctly. Received %v", arr[0], arr[1], hostConfig.Binds) } - // Two bind-mounts, first read-only, second read-write. + // Two bind mounts, first read-only, second read-write. // TODO Windows: The Windows version uses read-write as that's the only mode it supports. Can change this post TP4 arr, tryit = setupPlatformVolume( []string{`/hostTmp:/containerTmp:ro`, `/hostVar:/containerVar:rw`}, diff --git a/components/cli/docs/reference/commandline/run.md b/components/cli/docs/reference/commandline/run.md index 77bac7d2ae..37282a2847 100644 --- a/components/cli/docs/reference/commandline/run.md +++ b/components/cli/docs/reference/commandline/run.md @@ -302,7 +302,7 @@ Contents of file ``` The following examples will fail when using Windows-based containers, as the -destination of a volume or bind-mount inside the container must be one of: +destination of a volume or bind mount inside the container must be one of: a non-existing or empty directory; or a drive other than C:. Further, the source of a bind mount must be a local directory, not a file. @@ -318,7 +318,7 @@ docker run -v c:\foo:c:\existing-directory-with-contents ... For in-depth information about volumes, refer to [manage data in containers](https://docs.docker.com/engine/tutorials/dockervolumes/) -### Add bind-mounts or volumes using the --mount flag +### Add bind mounts or volumes using the --mount flag The `--mount` flag allows you to mount volumes, host-directories and `tmpfs` mounts in a container. diff --git a/components/cli/docs/reference/commandline/service_create.md b/components/cli/docs/reference/commandline/service_create.md index 6950935b82..f82c030993 100644 --- a/components/cli/docs/reference/commandline/service_create.md +++ b/components/cli/docs/reference/commandline/service_create.md @@ -243,19 +243,19 @@ $ docker service create \ For more information about labels, refer to [apply custom metadata](https://docs.docker.com/engine/userguide/labels-custom-metadata/). -### Add bind-mounts, volumes or memory filesystems +### Add bind mounts, volumes or memory filesystems Docker supports three different kinds of mounts, which allow containers to read from or write to files or directories, either on the host operating system, or on memory filesystems. These types are _data volumes_ (often referred to simply -as volumes), _bind-mounts_, and _tmpfs_. +as volumes), _bind mounts_, and _tmpfs_. -A **bind-mount** makes a file or directory on the host available to the -container it is mounted within. A bind-mount may be either read-only or +A **bind mount** makes a file or directory on the host available to the +container it is mounted within. A bind mount may be either read-only or read-write. For example, a container might share its host's DNS information by -means of a bind-mount of the host's `/etc/resolv.conf` or a container might +means of a bind mount of the host's `/etc/resolv.conf` or a container might write logs to its host's `/var/log/myContainerLogs` directory. If you use -bind-mounts and your host and containers have different notions of permissions, +bind mounts and your host and containers have different notions of permissions, access controls, or other such details, you will run into portability issues. A **named volume** is a mechanism for decoupling persistent data needed by your @@ -279,7 +279,7 @@ update the named volume. For more information about named volumes, see [Data Volumes](https://docs.docker.com/engine/tutorials/dockervolumes/). -The following table describes options which apply to both bind-mounts and named +The following table describes options which apply to both bind mounts and named volumes in a service: @@ -328,7 +328,7 @@ volumes in a service: @@ -362,15 +362,15 @@ volumes in a service: #### Bind Propagation Bind propagation refers to whether or not mounts created within a given -bind-mount or named volume can be propagated to replicas of that mount. Consider +bind mount or named volume can be propagated to replicas of that mount. Consider a mount point `/mnt`, which is also mounted on `/tmp`. The propation settings control whether a mount on `/tmp/a` would also be available on `/mnt/a`. Each propagation setting has a recursive counterpoint. In the case of recursion, consider that `/tmp/a` is also mounted as `/foo`. The propagation settings control whether `/mnt/a` and/or `/tmp/a` would exist. -The `bind-propagation` option defaults to `rprivate` for both bind-mounts and -volume mounts, and is only configurable for bind-mounts. In other words, named +The `bind-propagation` option defaults to `rprivate` for both bind mounts and +volume mounts, and is only configurable for bind mounts. In other words, named volumes do not support bind propagation. - **`shared`**: Sub-mounts of the original mount are exposed to replica mounts, diff --git a/components/cli/docs/reference/commandline/service_update.md b/components/cli/docs/reference/commandline/service_update.md index ffadb54955..1c6dd973e3 100644 --- a/components/cli/docs/reference/commandline/service_update.md +++ b/components/cli/docs/reference/commandline/service_update.md @@ -136,7 +136,7 @@ that the rolling restart happens gradually. ### Add or remove mounts -Use the `--mount-add` or `--mount-rm` options add or remove a service's bind-mounts +Use the `--mount-add` or `--mount-rm` options add or remove a service's bind mounts or volumes. The following example creates a service which mounts the `test-data` volume to @@ -147,7 +147,7 @@ service name. - The `--mount-add` flag takes the same parameters as the `--mount` flag on `service create`. Refer to the [volumes and - bind-mounts](service_create.md#volumes-and-bind-mounts-mount) section in the + bind mounts](service_create.md#volumes-and-bind-mounts-mount) section in the `service create` reference for details. - The `--mount-rm` flag takes the `target` path of the mount. diff --git a/components/cli/docs/reference/run.md b/components/cli/docs/reference/run.md index 4a1a4c1cb9..7446740c32 100644 --- a/components/cli/docs/reference/run.md +++ b/components/cli/docs/reference/run.md @@ -1577,7 +1577,7 @@ followed by `a-z0-9`, `_` (underscore), `.` (period) or `-` (hyphen). An absolute path starts with a `/` (forward slash). For example, you can specify either `/foo` or `foo` for a `host-src` value. -If you supply the `/foo` value, Docker creates a bind-mount. If you supply +If you supply the `/foo` value, Docker creates a bind mount. If you supply the `foo` specification, Docker creates a named volume. ### USER diff --git a/components/cli/man/docker-run.1.md b/components/cli/man/docker-run.1.md index 2a743c134e..6dbe8945b2 100644 --- a/components/cli/man/docker-run.1.md +++ b/components/cli/man/docker-run.1.md @@ -671,14 +671,14 @@ alphanumeric character, followed by `a-z0-9`, `_` (underscore), `.` (period) or If you supply a `HOST-DIR` that is an absolute path, Docker bind-mounts to the path you specify. If you supply a `name`, Docker creates a named volume by that `name`. For example, you can specify either `/foo` or `foo` for a `HOST-DIR` -value. If you supply the `/foo` value, Docker creates a bind-mount. If you +value. If you supply the `/foo` value, Docker creates a bind mount. If you supply the `foo` specification, Docker creates a named volume. You can specify multiple **-v** options to mount one or more mounts to a container. To use these same mounts in other containers, specify the **--volumes-from** option also. -You can supply additional options for each bind-mount following an additional +You can supply additional options for each bind mount following an additional colon. A `:ro` or `:rw` suffix mounts a volume in read-only or read-write mode, respectively. By default, volumes are mounted in read-write mode. You can also specify the consistency requirement for the mount, either diff --git a/components/cli/man/src/container/create.md b/components/cli/man/src/container/create.md index e47bb38db1..8df663a8a6 100644 --- a/components/cli/man/src/container/create.md +++ b/components/cli/man/src/container/create.md @@ -16,14 +16,14 @@ alphanumeric character, followed by `a-z0-9`, `_` (underscore), `.` (period) or If you supply a `HOST-DIR` that is an absolute path, Docker bind-mounts to the path you specify. If you supply a `name`, Docker creates a named volume by that `name`. For example, you can specify either `/foo` or `foo` for a `HOST-DIR` -value. If you supply the `/foo` value, Docker creates a bind-mount. If you +value. If you supply the `/foo` value, Docker creates a bind mount. If you supply the `foo` specification, Docker creates a named volume. You can specify multiple **-v** options to mount one or more mounts to a container. To use these same mounts in other containers, specify the **--volumes-from** option also. -You can supply additional options for each bind-mount following an additional +You can supply additional options for each bind mount following an additional colon. A `:ro` or `:rw` suffix mounts a volume in read-only or read-write mode, respectively. By default, volumes are mounted in read-write mode. You can also specify the consistency requirement for the mount, either From 53a6b2ff696d1465d23f2c999576e7026b5e320c Mon Sep 17 00:00:00 2001 From: Jean-Pierre Huynh Date: Sun, 20 Aug 2017 20:30:38 +0100 Subject: [PATCH 28/47] Add zsh completion for `service rollback` Signed-off-by: Jean-Pierre Huynh Upstream-commit: 8929c49c3acbf765f0a94b329c7fa8a144f6f102 Component: cli --- components/cli/contrib/completion/zsh/_docker | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/components/cli/contrib/completion/zsh/_docker b/components/cli/contrib/completion/zsh/_docker index 6e0c55b4dd..4150a85fe9 100644 --- a/components/cli/contrib/completion/zsh/_docker +++ b/components/cli/contrib/completion/zsh/_docker @@ -1931,6 +1931,7 @@ __docker_service_commands() { "logs:Fetch the logs of a service or task" "ls:List services" "rm:Remove one or more services" + "rollback:Revert changes to a service's configuration" "scale:Scale one or multiple replicated services" "ps:List the tasks of a service" "update:Update a service" @@ -2037,6 +2038,13 @@ __docker_service_subcommand() { $opts_help \ "($help -)*:service:__docker_complete_services" && ret=0 ;; + (rollback) + _arguments $(__docker_arguments) \ + $opts_help \ + "($help -d --detach)"{-d=false,--detach=false}"[Disable detached mode]" \ + "($help -q --quiet)"{-q,--quiet}"[Suppress progress output]" \ + "($help -)*:service:__docker_complete_services" && ret=0 + ;; (scale) _arguments $(__docker_arguments) \ $opts_help \ From 9724d4044a3fe6ae92a5201d9c958df7104c8f0a Mon Sep 17 00:00:00 2001 From: Harald Albers Date: Mon, 21 Aug 2017 14:50:46 +0200 Subject: [PATCH 29/47] Add bash completion for `service rollback` Signed-off-by: Harald Albers Upstream-commit: d1ed8008606d4cee46a4e24a87e61235bd61cc38 Component: cli --- components/cli/contrib/completion/bash/docker | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/components/cli/contrib/completion/bash/docker b/components/cli/contrib/completion/bash/docker index 542b0013ba..c0f92afca5 100644 --- a/components/cli/contrib/completion/bash/docker +++ b/components/cli/contrib/completion/bash/docker @@ -3101,6 +3101,7 @@ _docker_service() { logs ls rm + rollback scale ps update @@ -3215,6 +3216,20 @@ _docker_service_rm() { esac } +_docker_service_rollback() { + case "$cur" in + -*) + COMPREPLY=( $( compgen -W "--detach=false -d --help --quit -q" -- "$cur" ) ) + ;; + *) + local counter=$( __docker_pos_first_nonflag ) + if [ "$cword" -eq "$counter" ]; then + __docker_complete_services + fi + ;; + esac +} + _docker_service_scale() { case "$cur" in -*) From 0b20e1c511548a62fd6ab84f37af776b73445899 Mon Sep 17 00:00:00 2001 From: Boaz Shuster Date: Mon, 14 Aug 2017 12:06:31 +0300 Subject: [PATCH 30/47] Show images digests when "{{.Digest}}" is in format This patch fixes the following bug: Running "docker image ls --digests" will add images digests to the image table. However, when using "format" to display images digests all of them are "". Signed-off-by: Boaz Shuster Upstream-commit: 83112f634371dde5bf68f1f0ddce0f94bd98cf21 Component: cli --- components/cli/cli/command/formatter/image.go | 7 ++++++- components/cli/cli/command/formatter/image_test.go | 8 ++++++++ 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/components/cli/cli/command/formatter/image.go b/components/cli/cli/command/formatter/image.go index cbd3edad3c..aaf8ff1aa1 100644 --- a/components/cli/cli/command/formatter/image.go +++ b/components/cli/cli/command/formatter/image.go @@ -79,6 +79,11 @@ func ImageWrite(ctx ImageContext, images []types.ImageSummary) error { return ctx.Write(newImageContext(), render) } +// needDigest determines whether the image digest should be ignored or not when writing image context +func needDigest(ctx ImageContext) bool { + return ctx.Digest || ctx.Format.Contains("{{.Digest}}") +} + func imageFormat(ctx ImageContext, images []types.ImageSummary, format func(subContext subContext) error) error { for _, image := range images { images := []*imageContext{} @@ -121,7 +126,7 @@ func imageFormat(ctx ImageContext, images []types.ImageSummary, format func(subC // Do not display digests as their own row delete(repoDigests, repo) - if !ctx.Digest { + if !needDigest(ctx) { // Ignore digest references, just show tag once digests = nil } diff --git a/components/cli/cli/command/formatter/image_test.go b/components/cli/cli/command/formatter/image_test.go index b3c4cc8094..be7b084e3c 100644 --- a/components/cli/cli/command/formatter/image_test.go +++ b/components/cli/cli/command/formatter/image_test.go @@ -137,6 +137,14 @@ image }, "REPOSITORY\nimage\nimage\n\n", }, + { + ImageContext{ + Context: Context{ + Format: NewImageFormat("table {{.Digest}}", true, false), + }, + }, + "DIGEST\nsha256:cbbf2f9a99b47fc460d422812b6a5adff7dfee951d8fa2e4a98caa0382cfbdbf\n\n\n", + }, { ImageContext{ Context: Context{ From b141cbce57d9234a1a9899b0039a4405bf39fdff Mon Sep 17 00:00:00 2001 From: Daniel Nephin Date: Mon, 21 Aug 2017 16:30:09 -0400 Subject: [PATCH 31/47] Move internal/test package out of cli. Signed-off-by: Daniel Nephin Upstream-commit: b3f843afe29e3fbdc19c99f50ca6261878179d53 Component: cli --- .../cli/cli/command/checkpoint/create_test.go | 2 +- .../cli/cli/command/checkpoint/list_test.go | 2 +- .../cli/cli/command/checkpoint/remove_test.go | 2 +- components/cli/cli/command/config/create_test.go | 2 +- components/cli/cli/command/config/inspect_test.go | 4 ++-- components/cli/cli/command/config/ls_test.go | 4 ++-- components/cli/cli/command/config/remove_test.go | 2 +- .../cli/cli/command/container/attach_test.go | 2 +- components/cli/cli/command/container/exec_test.go | 2 +- .../cli/cli/command/idresolver/idresolver_test.go | 2 +- components/cli/cli/command/image/build_test.go | 2 +- components/cli/cli/command/image/history_test.go | 2 +- components/cli/cli/command/image/import_test.go | 2 +- components/cli/cli/command/image/inspect_test.go | 2 +- components/cli/cli/command/image/list_test.go | 2 +- components/cli/cli/command/image/load_test.go | 2 +- components/cli/cli/command/image/prune_test.go | 2 +- components/cli/cli/command/image/pull_test.go | 2 +- components/cli/cli/command/image/push_test.go | 2 +- components/cli/cli/command/image/remove_test.go | 2 +- components/cli/cli/command/image/save_test.go | 2 +- components/cli/cli/command/image/tag_test.go | 2 +- .../cli/cli/command/network/connect_test.go | 2 +- components/cli/cli/command/network/create_test.go | 2 +- .../cli/cli/command/network/disconnect_test.go | 2 +- components/cli/cli/command/node/demote_test.go | 4 ++-- components/cli/cli/command/node/inspect_test.go | 4 ++-- components/cli/cli/command/node/list_test.go | 4 ++-- components/cli/cli/command/node/promote_test.go | 4 ++-- components/cli/cli/command/node/ps_test.go | 4 ++-- components/cli/cli/command/node/remove_test.go | 2 +- components/cli/cli/command/node/update_test.go | 4 ++-- components/cli/cli/command/registry_test.go | 4 ++-- components/cli/cli/command/secret/create_test.go | 2 +- components/cli/cli/command/secret/inspect_test.go | 4 ++-- components/cli/cli/command/secret/ls_test.go | 4 ++-- components/cli/cli/command/secret/remove_test.go | 2 +- components/cli/cli/command/service/client_test.go | 2 +- components/cli/cli/command/service/list_test.go | 2 +- components/cli/cli/command/service/ps_test.go | 2 +- .../cli/cli/command/service/rollback_test.go | 2 +- .../cli/command/stack/deploy_composefile_test.go | 2 +- components/cli/cli/command/stack/deploy_test.go | 2 +- components/cli/cli/command/stack/list_test.go | 4 ++-- components/cli/cli/command/stack/ps_test.go | 4 ++-- components/cli/cli/command/stack/remove_test.go | 2 +- components/cli/cli/command/stack/services_test.go | 4 ++-- components/cli/cli/command/swarm/ca_test.go | 2 +- components/cli/cli/command/swarm/init_test.go | 2 +- components/cli/cli/command/swarm/join_test.go | 2 +- .../cli/cli/command/swarm/join_token_test.go | 4 ++-- components/cli/cli/command/swarm/leave_test.go | 2 +- .../cli/cli/command/swarm/unlock_key_test.go | 4 ++-- components/cli/cli/command/swarm/unlock_test.go | 2 +- components/cli/cli/command/swarm/update_test.go | 4 ++-- components/cli/cli/command/system/prune_test.go | 2 +- components/cli/cli/command/task/print_test.go | 4 ++-- components/cli/cli/command/volume/create_test.go | 2 +- components/cli/cli/command/volume/inspect_test.go | 4 ++-- components/cli/cli/command/volume/list_test.go | 4 ++-- components/cli/cli/command/volume/prune_test.go | 2 +- components/cli/cli/command/volume/remove_test.go | 2 +- .../{cli => }/internal/test/builders/config.go | 0 .../cli/{cli => }/internal/test/builders/doc.go | 0 .../cli/{cli => }/internal/test/builders/node.go | 0 .../{cli => }/internal/test/builders/secret.go | 0 .../{cli => }/internal/test/builders/service.go | 0 .../cli/{cli => }/internal/test/builders/swarm.go | 0 .../cli/{cli => }/internal/test/builders/task.go | 0 .../{cli => }/internal/test/builders/volume.go | 0 components/cli/{cli => }/internal/test/cli.go | 0 components/cli/{cli => }/internal/test/doc.go | 0 .../cli/{cli => }/internal/test/network/client.go | 0 components/cli/{cli => }/internal/test/store.go | 0 components/cli/internal/test/testutil/assert.go | 15 +++++++++++++++ 75 files changed, 97 insertions(+), 82 deletions(-) rename components/cli/{cli => }/internal/test/builders/config.go (100%) rename components/cli/{cli => }/internal/test/builders/doc.go (100%) rename components/cli/{cli => }/internal/test/builders/node.go (100%) rename components/cli/{cli => }/internal/test/builders/secret.go (100%) rename components/cli/{cli => }/internal/test/builders/service.go (100%) rename components/cli/{cli => }/internal/test/builders/swarm.go (100%) rename components/cli/{cli => }/internal/test/builders/task.go (100%) rename components/cli/{cli => }/internal/test/builders/volume.go (100%) rename components/cli/{cli => }/internal/test/cli.go (100%) rename components/cli/{cli => }/internal/test/doc.go (100%) rename components/cli/{cli => }/internal/test/network/client.go (100%) rename components/cli/{cli => }/internal/test/store.go (100%) create mode 100644 components/cli/internal/test/testutil/assert.go diff --git a/components/cli/cli/command/checkpoint/create_test.go b/components/cli/cli/command/checkpoint/create_test.go index 32c9d88a6f..8aae6eba5c 100644 --- a/components/cli/cli/command/checkpoint/create_test.go +++ b/components/cli/cli/command/checkpoint/create_test.go @@ -5,7 +5,7 @@ import ( "strings" "testing" - "github.com/docker/cli/cli/internal/test" + "github.com/docker/cli/internal/test" "github.com/docker/docker/api/types" "github.com/docker/docker/pkg/testutil" "github.com/pkg/errors" diff --git a/components/cli/cli/command/checkpoint/list_test.go b/components/cli/cli/command/checkpoint/list_test.go index 26dd963a8c..dd934cd590 100644 --- a/components/cli/cli/command/checkpoint/list_test.go +++ b/components/cli/cli/command/checkpoint/list_test.go @@ -4,7 +4,7 @@ import ( "io/ioutil" "testing" - "github.com/docker/cli/cli/internal/test" + "github.com/docker/cli/internal/test" "github.com/docker/docker/api/types" "github.com/docker/docker/pkg/testutil" "github.com/gotestyourself/gotestyourself/golden" diff --git a/components/cli/cli/command/checkpoint/remove_test.go b/components/cli/cli/command/checkpoint/remove_test.go index 976aa07892..174a389eef 100644 --- a/components/cli/cli/command/checkpoint/remove_test.go +++ b/components/cli/cli/command/checkpoint/remove_test.go @@ -4,7 +4,7 @@ import ( "io/ioutil" "testing" - "github.com/docker/cli/cli/internal/test" + "github.com/docker/cli/internal/test" "github.com/docker/docker/api/types" "github.com/docker/docker/pkg/testutil" "github.com/pkg/errors" diff --git a/components/cli/cli/command/config/create_test.go b/components/cli/cli/command/config/create_test.go index 7a6b2f54d3..a5bdce2dad 100644 --- a/components/cli/cli/command/config/create_test.go +++ b/components/cli/cli/command/config/create_test.go @@ -7,7 +7,7 @@ import ( "strings" "testing" - "github.com/docker/cli/cli/internal/test" + "github.com/docker/cli/internal/test" "github.com/docker/docker/api/types" "github.com/docker/docker/api/types/swarm" "github.com/docker/docker/pkg/testutil" diff --git a/components/cli/cli/command/config/inspect_test.go b/components/cli/cli/command/config/inspect_test.go index 0431ffd652..320df70aaf 100644 --- a/components/cli/cli/command/config/inspect_test.go +++ b/components/cli/cli/command/config/inspect_test.go @@ -6,11 +6,11 @@ import ( "testing" "time" - "github.com/docker/cli/cli/internal/test" + "github.com/docker/cli/internal/test" "github.com/docker/docker/api/types/swarm" "github.com/pkg/errors" // Import builders to get the builder function as package function - . "github.com/docker/cli/cli/internal/test/builders" + . "github.com/docker/cli/internal/test/builders" "github.com/docker/docker/pkg/testutil" "github.com/gotestyourself/gotestyourself/golden" "github.com/stretchr/testify/assert" diff --git a/components/cli/cli/command/config/ls_test.go b/components/cli/cli/command/config/ls_test.go index f58e815a5b..dfe79dc3c4 100644 --- a/components/cli/cli/command/config/ls_test.go +++ b/components/cli/cli/command/config/ls_test.go @@ -6,12 +6,12 @@ import ( "time" "github.com/docker/cli/cli/config/configfile" - "github.com/docker/cli/cli/internal/test" + "github.com/docker/cli/internal/test" "github.com/docker/docker/api/types" "github.com/docker/docker/api/types/swarm" "github.com/pkg/errors" // Import builders to get the builder function as package function - . "github.com/docker/cli/cli/internal/test/builders" + . "github.com/docker/cli/internal/test/builders" "github.com/docker/docker/pkg/testutil" "github.com/gotestyourself/gotestyourself/golden" "github.com/stretchr/testify/assert" diff --git a/components/cli/cli/command/config/remove_test.go b/components/cli/cli/command/config/remove_test.go index 28cc41f670..2b7245167e 100644 --- a/components/cli/cli/command/config/remove_test.go +++ b/components/cli/cli/command/config/remove_test.go @@ -5,7 +5,7 @@ import ( "strings" "testing" - "github.com/docker/cli/cli/internal/test" + "github.com/docker/cli/internal/test" "github.com/docker/docker/pkg/testutil" "github.com/pkg/errors" "github.com/stretchr/testify/assert" diff --git a/components/cli/cli/command/container/attach_test.go b/components/cli/cli/command/container/attach_test.go index a33eeeeb54..e4caa473af 100644 --- a/components/cli/cli/command/container/attach_test.go +++ b/components/cli/cli/command/container/attach_test.go @@ -4,7 +4,7 @@ import ( "io/ioutil" "testing" - "github.com/docker/cli/cli/internal/test" + "github.com/docker/cli/internal/test" "github.com/docker/docker/api/types" "github.com/docker/docker/pkg/testutil" "github.com/pkg/errors" diff --git a/components/cli/cli/command/container/exec_test.go b/components/cli/cli/command/container/exec_test.go index 0eed2ff0f7..acfe250d3b 100644 --- a/components/cli/cli/command/container/exec_test.go +++ b/components/cli/cli/command/container/exec_test.go @@ -4,7 +4,7 @@ import ( "io/ioutil" "testing" - "github.com/docker/cli/cli/internal/test" + "github.com/docker/cli/internal/test" "github.com/docker/docker/api/types" "github.com/docker/docker/pkg/testutil" "github.com/pkg/errors" diff --git a/components/cli/cli/command/idresolver/idresolver_test.go b/components/cli/cli/command/idresolver/idresolver_test.go index f740c13eff..98bd306d16 100644 --- a/components/cli/cli/command/idresolver/idresolver_test.go +++ b/components/cli/cli/command/idresolver/idresolver_test.go @@ -5,7 +5,7 @@ import ( "github.com/docker/docker/api/types/swarm" // Import builders to get the builder function as package function - . "github.com/docker/cli/cli/internal/test/builders" + . "github.com/docker/cli/internal/test/builders" "github.com/pkg/errors" "github.com/stretchr/testify/assert" "golang.org/x/net/context" diff --git a/components/cli/cli/command/image/build_test.go b/components/cli/cli/command/image/build_test.go index 3664b91b7c..325c82343e 100644 --- a/components/cli/cli/command/image/build_test.go +++ b/components/cli/cli/command/image/build_test.go @@ -10,7 +10,7 @@ import ( "testing" "github.com/docker/cli/cli/command" - "github.com/docker/cli/cli/internal/test" + "github.com/docker/cli/internal/test" "github.com/docker/docker/api/types" "github.com/docker/docker/pkg/archive" "github.com/stretchr/testify/assert" diff --git a/components/cli/cli/command/image/history_test.go b/components/cli/cli/command/image/history_test.go index 7053735aa3..c0a7ef3139 100644 --- a/components/cli/cli/command/image/history_test.go +++ b/components/cli/cli/command/image/history_test.go @@ -6,7 +6,7 @@ import ( "testing" "time" - "github.com/docker/cli/cli/internal/test" + "github.com/docker/cli/internal/test" "github.com/docker/docker/api/types/image" "github.com/docker/docker/pkg/testutil" "github.com/gotestyourself/gotestyourself/golden" diff --git a/components/cli/cli/command/image/import_test.go b/components/cli/cli/command/image/import_test.go index 87cc89693c..0e45e7887f 100644 --- a/components/cli/cli/command/image/import_test.go +++ b/components/cli/cli/command/image/import_test.go @@ -6,7 +6,7 @@ import ( "strings" "testing" - "github.com/docker/cli/cli/internal/test" + "github.com/docker/cli/internal/test" "github.com/docker/docker/api/types" "github.com/docker/docker/pkg/testutil" "github.com/pkg/errors" diff --git a/components/cli/cli/command/image/inspect_test.go b/components/cli/cli/command/image/inspect_test.go index 0bcb65836c..d1de685610 100644 --- a/components/cli/cli/command/image/inspect_test.go +++ b/components/cli/cli/command/image/inspect_test.go @@ -5,7 +5,7 @@ import ( "io/ioutil" "testing" - "github.com/docker/cli/cli/internal/test" + "github.com/docker/cli/internal/test" "github.com/docker/docker/api/types" "github.com/docker/docker/pkg/testutil" "github.com/gotestyourself/gotestyourself/golden" diff --git a/components/cli/cli/command/image/list_test.go b/components/cli/cli/command/image/list_test.go index 58b7a71bdb..9be4c379bc 100644 --- a/components/cli/cli/command/image/list_test.go +++ b/components/cli/cli/command/image/list_test.go @@ -6,7 +6,7 @@ import ( "testing" "github.com/docker/cli/cli/config/configfile" - "github.com/docker/cli/cli/internal/test" + "github.com/docker/cli/internal/test" "github.com/docker/docker/api/types" "github.com/docker/docker/pkg/testutil" "github.com/gotestyourself/gotestyourself/golden" diff --git a/components/cli/cli/command/image/load_test.go b/components/cli/cli/command/image/load_test.go index bebe40cb07..d3002aa1cd 100644 --- a/components/cli/cli/command/image/load_test.go +++ b/components/cli/cli/command/image/load_test.go @@ -7,7 +7,7 @@ import ( "strings" "testing" - "github.com/docker/cli/cli/internal/test" + "github.com/docker/cli/internal/test" "github.com/docker/docker/api/types" "github.com/docker/docker/pkg/testutil" "github.com/gotestyourself/gotestyourself/golden" diff --git a/components/cli/cli/command/image/prune_test.go b/components/cli/cli/command/image/prune_test.go index b52601608f..90845e4bb4 100644 --- a/components/cli/cli/command/image/prune_test.go +++ b/components/cli/cli/command/image/prune_test.go @@ -5,7 +5,7 @@ import ( "io/ioutil" "testing" - "github.com/docker/cli/cli/internal/test" + "github.com/docker/cli/internal/test" "github.com/docker/docker/api/types" "github.com/docker/docker/api/types/filters" "github.com/docker/docker/pkg/testutil" diff --git a/components/cli/cli/command/image/pull_test.go b/components/cli/cli/command/image/pull_test.go index 7b24cdbb08..57cd0ac772 100644 --- a/components/cli/cli/command/image/pull_test.go +++ b/components/cli/cli/command/image/pull_test.go @@ -5,7 +5,7 @@ import ( "io/ioutil" "testing" - "github.com/docker/cli/cli/internal/test" + "github.com/docker/cli/internal/test" "github.com/docker/docker/pkg/testutil" "github.com/gotestyourself/gotestyourself/golden" "github.com/stretchr/testify/assert" diff --git a/components/cli/cli/command/image/push_test.go b/components/cli/cli/command/image/push_test.go index 1ead5b1549..8f8b35d292 100644 --- a/components/cli/cli/command/image/push_test.go +++ b/components/cli/cli/command/image/push_test.go @@ -6,7 +6,7 @@ import ( "strings" "testing" - "github.com/docker/cli/cli/internal/test" + "github.com/docker/cli/internal/test" "github.com/docker/docker/api/types" "github.com/docker/docker/pkg/testutil" "github.com/pkg/errors" diff --git a/components/cli/cli/command/image/remove_test.go b/components/cli/cli/command/image/remove_test.go index a813f8f107..7bf0434d6e 100644 --- a/components/cli/cli/command/image/remove_test.go +++ b/components/cli/cli/command/image/remove_test.go @@ -5,7 +5,7 @@ import ( "io/ioutil" "testing" - "github.com/docker/cli/cli/internal/test" + "github.com/docker/cli/internal/test" "github.com/docker/docker/api/types" "github.com/docker/docker/pkg/testutil" "github.com/gotestyourself/gotestyourself/golden" diff --git a/components/cli/cli/command/image/save_test.go b/components/cli/cli/command/image/save_test.go index 424c2c9a42..9e3ff147ab 100644 --- a/components/cli/cli/command/image/save_test.go +++ b/components/cli/cli/command/image/save_test.go @@ -7,7 +7,7 @@ import ( "strings" "testing" - "github.com/docker/cli/cli/internal/test" + "github.com/docker/cli/internal/test" "github.com/docker/docker/pkg/testutil" "github.com/pkg/errors" "github.com/stretchr/testify/assert" diff --git a/components/cli/cli/command/image/tag_test.go b/components/cli/cli/command/image/tag_test.go index c86bd22b36..bb0c71cae5 100644 --- a/components/cli/cli/command/image/tag_test.go +++ b/components/cli/cli/command/image/tag_test.go @@ -4,7 +4,7 @@ import ( "io/ioutil" "testing" - "github.com/docker/cli/cli/internal/test" + "github.com/docker/cli/internal/test" "github.com/docker/docker/pkg/testutil" "github.com/stretchr/testify/assert" ) diff --git a/components/cli/cli/command/network/connect_test.go b/components/cli/cli/command/network/connect_test.go index 577dd8c25a..2343c7efbb 100644 --- a/components/cli/cli/command/network/connect_test.go +++ b/components/cli/cli/command/network/connect_test.go @@ -4,7 +4,7 @@ import ( "io/ioutil" "testing" - "github.com/docker/cli/cli/internal/test" + "github.com/docker/cli/internal/test" "github.com/docker/docker/api/types/network" "github.com/docker/docker/pkg/testutil" "github.com/pkg/errors" diff --git a/components/cli/cli/command/network/create_test.go b/components/cli/cli/command/network/create_test.go index 76c760d0ad..b06febb4ea 100644 --- a/components/cli/cli/command/network/create_test.go +++ b/components/cli/cli/command/network/create_test.go @@ -5,7 +5,7 @@ import ( "strings" "testing" - "github.com/docker/cli/cli/internal/test" + "github.com/docker/cli/internal/test" "github.com/docker/docker/api/types" "github.com/docker/docker/api/types/network" "github.com/docker/docker/pkg/testutil" diff --git a/components/cli/cli/command/network/disconnect_test.go b/components/cli/cli/command/network/disconnect_test.go index 9b915a19b5..04a5ab4378 100644 --- a/components/cli/cli/command/network/disconnect_test.go +++ b/components/cli/cli/command/network/disconnect_test.go @@ -4,7 +4,7 @@ import ( "io/ioutil" "testing" - "github.com/docker/cli/cli/internal/test" + "github.com/docker/cli/internal/test" "github.com/docker/docker/pkg/testutil" "github.com/pkg/errors" "golang.org/x/net/context" diff --git a/components/cli/cli/command/node/demote_test.go b/components/cli/cli/command/node/demote_test.go index d786cd47a2..ccdbb59904 100644 --- a/components/cli/cli/command/node/demote_test.go +++ b/components/cli/cli/command/node/demote_test.go @@ -4,11 +4,11 @@ import ( "io/ioutil" "testing" - "github.com/docker/cli/cli/internal/test" + "github.com/docker/cli/internal/test" "github.com/docker/docker/api/types/swarm" "github.com/pkg/errors" // Import builders to get the builder function as package function - . "github.com/docker/cli/cli/internal/test/builders" + . "github.com/docker/cli/internal/test/builders" "github.com/docker/docker/pkg/testutil" "github.com/stretchr/testify/assert" ) diff --git a/components/cli/cli/command/node/inspect_test.go b/components/cli/cli/command/node/inspect_test.go index b841b0639d..1ce6ebd441 100644 --- a/components/cli/cli/command/node/inspect_test.go +++ b/components/cli/cli/command/node/inspect_test.go @@ -5,12 +5,12 @@ import ( "io/ioutil" "testing" - "github.com/docker/cli/cli/internal/test" + "github.com/docker/cli/internal/test" "github.com/docker/docker/api/types" "github.com/docker/docker/api/types/swarm" "github.com/pkg/errors" // Import builders to get the builder function as package function - . "github.com/docker/cli/cli/internal/test/builders" + . "github.com/docker/cli/internal/test/builders" "github.com/docker/docker/pkg/testutil" "github.com/gotestyourself/gotestyourself/golden" "github.com/stretchr/testify/assert" diff --git a/components/cli/cli/command/node/list_test.go b/components/cli/cli/command/node/list_test.go index fee29e284b..b3a42df460 100644 --- a/components/cli/cli/command/node/list_test.go +++ b/components/cli/cli/command/node/list_test.go @@ -5,13 +5,13 @@ import ( "testing" "github.com/docker/cli/cli/config/configfile" - "github.com/docker/cli/cli/internal/test" + "github.com/docker/cli/internal/test" "github.com/docker/docker/api/types" "github.com/docker/docker/api/types/swarm" "github.com/gotestyourself/gotestyourself/golden" "github.com/pkg/errors" // Import builders to get the builder function as package function - . "github.com/docker/cli/cli/internal/test/builders" + . "github.com/docker/cli/internal/test/builders" "github.com/stretchr/testify/assert" ) diff --git a/components/cli/cli/command/node/promote_test.go b/components/cli/cli/command/node/promote_test.go index 2399b2ee8c..e0e228e860 100644 --- a/components/cli/cli/command/node/promote_test.go +++ b/components/cli/cli/command/node/promote_test.go @@ -4,11 +4,11 @@ import ( "io/ioutil" "testing" - "github.com/docker/cli/cli/internal/test" + "github.com/docker/cli/internal/test" "github.com/docker/docker/api/types/swarm" "github.com/pkg/errors" // Import builders to get the builder function as package function - . "github.com/docker/cli/cli/internal/test/builders" + . "github.com/docker/cli/internal/test/builders" "github.com/docker/docker/pkg/testutil" "github.com/stretchr/testify/assert" ) diff --git a/components/cli/cli/command/node/ps_test.go b/components/cli/cli/command/node/ps_test.go index 8733e5e0f4..836a130f76 100644 --- a/components/cli/cli/command/node/ps_test.go +++ b/components/cli/cli/command/node/ps_test.go @@ -6,12 +6,12 @@ import ( "testing" "time" - "github.com/docker/cli/cli/internal/test" + "github.com/docker/cli/internal/test" "github.com/docker/docker/api/types" "github.com/docker/docker/api/types/swarm" "github.com/pkg/errors" // Import builders to get the builder function as package function - . "github.com/docker/cli/cli/internal/test/builders" + . "github.com/docker/cli/internal/test/builders" "github.com/gotestyourself/gotestyourself/golden" "github.com/stretchr/testify/assert" ) diff --git a/components/cli/cli/command/node/remove_test.go b/components/cli/cli/command/node/remove_test.go index e0f3f238e6..84d09c70e2 100644 --- a/components/cli/cli/command/node/remove_test.go +++ b/components/cli/cli/command/node/remove_test.go @@ -4,7 +4,7 @@ import ( "io/ioutil" "testing" - "github.com/docker/cli/cli/internal/test" + "github.com/docker/cli/internal/test" "github.com/docker/docker/pkg/testutil" "github.com/pkg/errors" "github.com/stretchr/testify/assert" diff --git a/components/cli/cli/command/node/update_test.go b/components/cli/cli/command/node/update_test.go index 3abb720c1c..4544cd12cb 100644 --- a/components/cli/cli/command/node/update_test.go +++ b/components/cli/cli/command/node/update_test.go @@ -4,11 +4,11 @@ import ( "io/ioutil" "testing" - "github.com/docker/cli/cli/internal/test" + "github.com/docker/cli/internal/test" "github.com/docker/docker/api/types/swarm" "github.com/pkg/errors" // Import builders to get the builder function as package function - . "github.com/docker/cli/cli/internal/test/builders" + . "github.com/docker/cli/internal/test/builders" "github.com/docker/docker/pkg/testutil" "github.com/stretchr/testify/assert" ) diff --git a/components/cli/cli/command/registry_test.go b/components/cli/cli/command/registry_test.go index 5e52e470a1..3f3d5f579f 100644 --- a/components/cli/cli/command/registry_test.go +++ b/components/cli/cli/command/registry_test.go @@ -7,9 +7,9 @@ import ( "github.com/stretchr/testify/assert" "golang.org/x/net/context" - // Prevents a circular import with "github.com/docker/cli/cli/internal/test" + // Prevents a circular import with "github.com/docker/cli/internal/test" . "github.com/docker/cli/cli/command" - "github.com/docker/cli/cli/internal/test" + "github.com/docker/cli/internal/test" "github.com/docker/docker/api/types" "github.com/docker/docker/client" ) diff --git a/components/cli/cli/command/secret/create_test.go b/components/cli/cli/command/secret/create_test.go index 0887601ab6..cc9eaa1067 100644 --- a/components/cli/cli/command/secret/create_test.go +++ b/components/cli/cli/command/secret/create_test.go @@ -7,7 +7,7 @@ import ( "strings" "testing" - "github.com/docker/cli/cli/internal/test" + "github.com/docker/cli/internal/test" "github.com/docker/docker/api/types" "github.com/docker/docker/api/types/swarm" "github.com/docker/docker/pkg/testutil" diff --git a/components/cli/cli/command/secret/inspect_test.go b/components/cli/cli/command/secret/inspect_test.go index eef789d80b..4a38a18f5d 100644 --- a/components/cli/cli/command/secret/inspect_test.go +++ b/components/cli/cli/command/secret/inspect_test.go @@ -6,11 +6,11 @@ import ( "testing" "time" - "github.com/docker/cli/cli/internal/test" + "github.com/docker/cli/internal/test" "github.com/docker/docker/api/types/swarm" "github.com/pkg/errors" // Import builders to get the builder function as package function - . "github.com/docker/cli/cli/internal/test/builders" + . "github.com/docker/cli/internal/test/builders" "github.com/docker/docker/pkg/testutil" "github.com/gotestyourself/gotestyourself/golden" "github.com/stretchr/testify/assert" diff --git a/components/cli/cli/command/secret/ls_test.go b/components/cli/cli/command/secret/ls_test.go index cced136106..af72effe94 100644 --- a/components/cli/cli/command/secret/ls_test.go +++ b/components/cli/cli/command/secret/ls_test.go @@ -7,12 +7,12 @@ import ( "time" "github.com/docker/cli/cli/config/configfile" - "github.com/docker/cli/cli/internal/test" + "github.com/docker/cli/internal/test" "github.com/docker/docker/api/types" "github.com/docker/docker/api/types/swarm" "github.com/pkg/errors" // Import builders to get the builder function as package function - . "github.com/docker/cli/cli/internal/test/builders" + . "github.com/docker/cli/internal/test/builders" "github.com/docker/docker/pkg/testutil" "github.com/gotestyourself/gotestyourself/golden" "github.com/stretchr/testify/assert" diff --git a/components/cli/cli/command/secret/remove_test.go b/components/cli/cli/command/secret/remove_test.go index f3e427f7d7..51622136ab 100644 --- a/components/cli/cli/command/secret/remove_test.go +++ b/components/cli/cli/command/secret/remove_test.go @@ -5,7 +5,7 @@ import ( "strings" "testing" - "github.com/docker/cli/cli/internal/test" + "github.com/docker/cli/internal/test" "github.com/docker/docker/pkg/testutil" "github.com/pkg/errors" "github.com/stretchr/testify/assert" diff --git a/components/cli/cli/command/service/client_test.go b/components/cli/cli/command/service/client_test.go index a886ff6a6d..ebdfe7ea74 100644 --- a/components/cli/cli/command/service/client_test.go +++ b/components/cli/cli/command/service/client_test.go @@ -6,7 +6,7 @@ import ( "github.com/docker/docker/client" "golang.org/x/net/context" // Import builders to get the builder function as package function - . "github.com/docker/cli/cli/internal/test/builders" + . "github.com/docker/cli/internal/test/builders" ) type fakeClient struct { diff --git a/components/cli/cli/command/service/list_test.go b/components/cli/cli/command/service/list_test.go index 297f5f9b17..679c733701 100644 --- a/components/cli/cli/command/service/list_test.go +++ b/components/cli/cli/command/service/list_test.go @@ -3,7 +3,7 @@ package service import ( "testing" - "github.com/docker/cli/cli/internal/test" + "github.com/docker/cli/internal/test" "github.com/docker/docker/api/types" "github.com/docker/docker/api/types/swarm" "github.com/gotestyourself/gotestyourself/golden" diff --git a/components/cli/cli/command/service/ps_test.go b/components/cli/cli/command/service/ps_test.go index 083c58f91f..1913202d33 100644 --- a/components/cli/cli/command/service/ps_test.go +++ b/components/cli/cli/command/service/ps_test.go @@ -3,7 +3,7 @@ package service import ( "testing" - "github.com/docker/cli/cli/internal/test" + "github.com/docker/cli/internal/test" "github.com/docker/cli/opts" "github.com/docker/docker/api/types" "github.com/docker/docker/api/types/filters" diff --git a/components/cli/cli/command/service/rollback_test.go b/components/cli/cli/command/service/rollback_test.go index 48be5076d7..f4183dae23 100644 --- a/components/cli/cli/command/service/rollback_test.go +++ b/components/cli/cli/command/service/rollback_test.go @@ -6,7 +6,7 @@ import ( "strings" "testing" - "github.com/docker/cli/cli/internal/test" + "github.com/docker/cli/internal/test" "github.com/docker/docker/api/types" "github.com/docker/docker/api/types/swarm" "github.com/docker/docker/pkg/testutil" diff --git a/components/cli/cli/command/stack/deploy_composefile_test.go b/components/cli/cli/command/stack/deploy_composefile_test.go index 8d09ab056c..28edb2c137 100644 --- a/components/cli/cli/command/stack/deploy_composefile_test.go +++ b/components/cli/cli/command/stack/deploy_composefile_test.go @@ -5,7 +5,7 @@ import ( "path/filepath" "testing" - "github.com/docker/cli/cli/internal/test/network" + "github.com/docker/cli/internal/test/network" "github.com/docker/docker/api/types" "github.com/docker/docker/pkg/testutil" "github.com/gotestyourself/gotestyourself/fs" diff --git a/components/cli/cli/command/stack/deploy_test.go b/components/cli/cli/command/stack/deploy_test.go index f91a825f9b..f10fecd1af 100644 --- a/components/cli/cli/command/stack/deploy_test.go +++ b/components/cli/cli/command/stack/deploy_test.go @@ -4,7 +4,7 @@ import ( "testing" "github.com/docker/cli/cli/compose/convert" - "github.com/docker/cli/cli/internal/test" + "github.com/docker/cli/internal/test" "github.com/docker/docker/api/types" "github.com/docker/docker/api/types/swarm" "github.com/stretchr/testify/assert" diff --git a/components/cli/cli/command/stack/list_test.go b/components/cli/cli/command/stack/list_test.go index 0ae5bc78ce..f194d04fcd 100644 --- a/components/cli/cli/command/stack/list_test.go +++ b/components/cli/cli/command/stack/list_test.go @@ -4,9 +4,9 @@ import ( "io/ioutil" "testing" - "github.com/docker/cli/cli/internal/test" + "github.com/docker/cli/internal/test" // Import builders to get the builder function as package function - . "github.com/docker/cli/cli/internal/test/builders" + . "github.com/docker/cli/internal/test/builders" "github.com/docker/docker/api/types" "github.com/docker/docker/api/types/swarm" "github.com/docker/docker/pkg/testutil" diff --git a/components/cli/cli/command/stack/ps_test.go b/components/cli/cli/command/stack/ps_test.go index 249e1b656a..b98c445f28 100644 --- a/components/cli/cli/command/stack/ps_test.go +++ b/components/cli/cli/command/stack/ps_test.go @@ -6,9 +6,9 @@ import ( "time" "github.com/docker/cli/cli/config/configfile" - "github.com/docker/cli/cli/internal/test" + "github.com/docker/cli/internal/test" // Import builders to get the builder function as package function - . "github.com/docker/cli/cli/internal/test/builders" + . "github.com/docker/cli/internal/test/builders" "github.com/docker/docker/api/types" "github.com/docker/docker/api/types/swarm" "github.com/docker/docker/pkg/testutil" diff --git a/components/cli/cli/command/stack/remove_test.go b/components/cli/cli/command/stack/remove_test.go index 88ad8a07d3..c44977c0c6 100644 --- a/components/cli/cli/command/stack/remove_test.go +++ b/components/cli/cli/command/stack/remove_test.go @@ -6,7 +6,7 @@ import ( "strings" "testing" - "github.com/docker/cli/cli/internal/test" + "github.com/docker/cli/internal/test" "github.com/stretchr/testify/assert" ) diff --git a/components/cli/cli/command/stack/services_test.go b/components/cli/cli/command/stack/services_test.go index fcc82ec885..d1d6c24081 100644 --- a/components/cli/cli/command/stack/services_test.go +++ b/components/cli/cli/command/stack/services_test.go @@ -5,9 +5,9 @@ import ( "testing" "github.com/docker/cli/cli/config/configfile" - "github.com/docker/cli/cli/internal/test" + "github.com/docker/cli/internal/test" // Import builders to get the builder function as package function - . "github.com/docker/cli/cli/internal/test/builders" + . "github.com/docker/cli/internal/test/builders" "github.com/docker/docker/api/types" "github.com/docker/docker/api/types/swarm" "github.com/docker/docker/pkg/testutil" diff --git a/components/cli/cli/command/swarm/ca_test.go b/components/cli/cli/command/swarm/ca_test.go index a1a77d59c2..1271da1270 100644 --- a/components/cli/cli/command/swarm/ca_test.go +++ b/components/cli/cli/command/swarm/ca_test.go @@ -7,7 +7,7 @@ import ( "testing" "time" - "github.com/docker/cli/cli/internal/test" + "github.com/docker/cli/internal/test" "github.com/docker/docker/api/types/swarm" "github.com/docker/docker/pkg/testutil" "github.com/stretchr/testify/assert" diff --git a/components/cli/cli/command/swarm/init_test.go b/components/cli/cli/command/swarm/init_test.go index 5991c3dd54..24a1b90717 100644 --- a/components/cli/cli/command/swarm/init_test.go +++ b/components/cli/cli/command/swarm/init_test.go @@ -5,7 +5,7 @@ import ( "io/ioutil" "testing" - "github.com/docker/cli/cli/internal/test" + "github.com/docker/cli/internal/test" "github.com/docker/docker/api/types" "github.com/docker/docker/api/types/swarm" "github.com/gotestyourself/gotestyourself/golden" diff --git a/components/cli/cli/command/swarm/join_test.go b/components/cli/cli/command/swarm/join_test.go index d9f5215b7b..ed8eff8571 100644 --- a/components/cli/cli/command/swarm/join_test.go +++ b/components/cli/cli/command/swarm/join_test.go @@ -5,7 +5,7 @@ import ( "strings" "testing" - "github.com/docker/cli/cli/internal/test" + "github.com/docker/cli/internal/test" "github.com/docker/docker/api/types" "github.com/docker/docker/api/types/swarm" "github.com/docker/docker/pkg/testutil" diff --git a/components/cli/cli/command/swarm/join_token_test.go b/components/cli/cli/command/swarm/join_token_test.go index da1b795321..89f7ab22b9 100644 --- a/components/cli/cli/command/swarm/join_token_test.go +++ b/components/cli/cli/command/swarm/join_token_test.go @@ -5,12 +5,12 @@ import ( "io/ioutil" "testing" - "github.com/docker/cli/cli/internal/test" + "github.com/docker/cli/internal/test" "github.com/docker/docker/api/types" "github.com/docker/docker/api/types/swarm" "github.com/pkg/errors" // Import builders to get the builder function as package function - . "github.com/docker/cli/cli/internal/test/builders" + . "github.com/docker/cli/internal/test/builders" "github.com/docker/docker/pkg/testutil" "github.com/gotestyourself/gotestyourself/golden" "github.com/stretchr/testify/assert" diff --git a/components/cli/cli/command/swarm/leave_test.go b/components/cli/cli/command/swarm/leave_test.go index b5b672fe47..d2f5d57bbb 100644 --- a/components/cli/cli/command/swarm/leave_test.go +++ b/components/cli/cli/command/swarm/leave_test.go @@ -5,7 +5,7 @@ import ( "strings" "testing" - "github.com/docker/cli/cli/internal/test" + "github.com/docker/cli/internal/test" "github.com/docker/docker/pkg/testutil" "github.com/pkg/errors" "github.com/stretchr/testify/assert" diff --git a/components/cli/cli/command/swarm/unlock_key_test.go b/components/cli/cli/command/swarm/unlock_key_test.go index 0dc9fb5f08..e377e80c7b 100644 --- a/components/cli/cli/command/swarm/unlock_key_test.go +++ b/components/cli/cli/command/swarm/unlock_key_test.go @@ -5,12 +5,12 @@ import ( "io/ioutil" "testing" - "github.com/docker/cli/cli/internal/test" + "github.com/docker/cli/internal/test" "github.com/docker/docker/api/types" "github.com/docker/docker/api/types/swarm" "github.com/pkg/errors" // Import builders to get the builder function as package function - . "github.com/docker/cli/cli/internal/test/builders" + . "github.com/docker/cli/internal/test/builders" "github.com/docker/docker/pkg/testutil" "github.com/gotestyourself/gotestyourself/golden" "github.com/stretchr/testify/assert" diff --git a/components/cli/cli/command/swarm/unlock_test.go b/components/cli/cli/command/swarm/unlock_test.go index 6663df1dba..5151d6ba5e 100644 --- a/components/cli/cli/command/swarm/unlock_test.go +++ b/components/cli/cli/command/swarm/unlock_test.go @@ -6,7 +6,7 @@ import ( "testing" "github.com/docker/cli/cli/command" - "github.com/docker/cli/cli/internal/test" + "github.com/docker/cli/internal/test" "github.com/docker/docker/api/types" "github.com/docker/docker/api/types/swarm" "github.com/docker/docker/pkg/testutil" diff --git a/components/cli/cli/command/swarm/update_test.go b/components/cli/cli/command/swarm/update_test.go index 3c928a2e0d..e1cd8d7c4d 100644 --- a/components/cli/cli/command/swarm/update_test.go +++ b/components/cli/cli/command/swarm/update_test.go @@ -6,12 +6,12 @@ import ( "testing" "time" - "github.com/docker/cli/cli/internal/test" + "github.com/docker/cli/internal/test" "github.com/docker/docker/api/types" "github.com/docker/docker/api/types/swarm" "github.com/pkg/errors" // Import builders to get the builder function as package function - . "github.com/docker/cli/cli/internal/test/builders" + . "github.com/docker/cli/internal/test/builders" "github.com/docker/docker/pkg/testutil" "github.com/gotestyourself/gotestyourself/golden" "github.com/stretchr/testify/assert" diff --git a/components/cli/cli/command/system/prune_test.go b/components/cli/cli/command/system/prune_test.go index 669166c998..0d694ce066 100644 --- a/components/cli/cli/command/system/prune_test.go +++ b/components/cli/cli/command/system/prune_test.go @@ -3,7 +3,7 @@ package system import ( "testing" - "github.com/docker/cli/cli/internal/test" + "github.com/docker/cli/internal/test" "github.com/stretchr/testify/assert" ) diff --git a/components/cli/cli/command/task/print_test.go b/components/cli/cli/command/task/print_test.go index 19e02c6d18..04ae1bb0ef 100644 --- a/components/cli/cli/command/task/print_test.go +++ b/components/cli/cli/command/task/print_test.go @@ -6,10 +6,10 @@ import ( "github.com/docker/cli/cli/command/formatter" "github.com/docker/cli/cli/command/idresolver" - "github.com/docker/cli/cli/internal/test" + "github.com/docker/cli/internal/test" "golang.org/x/net/context" // Import builders to get the builder function as package function - . "github.com/docker/cli/cli/internal/test/builders" + . "github.com/docker/cli/internal/test/builders" "github.com/docker/docker/api/types" "github.com/docker/docker/api/types/swarm" "github.com/gotestyourself/gotestyourself/golden" diff --git a/components/cli/cli/command/volume/create_test.go b/components/cli/cli/command/volume/create_test.go index cf84195f45..de534053b1 100644 --- a/components/cli/cli/command/volume/create_test.go +++ b/components/cli/cli/command/volume/create_test.go @@ -6,7 +6,7 @@ import ( "strings" "testing" - "github.com/docker/cli/cli/internal/test" + "github.com/docker/cli/internal/test" "github.com/docker/docker/api/types" volumetypes "github.com/docker/docker/api/types/volume" "github.com/docker/docker/pkg/testutil" diff --git a/components/cli/cli/command/volume/inspect_test.go b/components/cli/cli/command/volume/inspect_test.go index fccccf4442..57949305e5 100644 --- a/components/cli/cli/command/volume/inspect_test.go +++ b/components/cli/cli/command/volume/inspect_test.go @@ -5,11 +5,11 @@ import ( "io/ioutil" "testing" - "github.com/docker/cli/cli/internal/test" + "github.com/docker/cli/internal/test" "github.com/docker/docker/api/types" "github.com/pkg/errors" // Import builders to get the builder function as package function - . "github.com/docker/cli/cli/internal/test/builders" + . "github.com/docker/cli/internal/test/builders" "github.com/docker/docker/pkg/testutil" "github.com/gotestyourself/gotestyourself/golden" "github.com/stretchr/testify/assert" diff --git a/components/cli/cli/command/volume/list_test.go b/components/cli/cli/command/volume/list_test.go index 0eab71dc45..5f5654d5af 100644 --- a/components/cli/cli/command/volume/list_test.go +++ b/components/cli/cli/command/volume/list_test.go @@ -5,13 +5,13 @@ import ( "testing" "github.com/docker/cli/cli/config/configfile" - "github.com/docker/cli/cli/internal/test" + "github.com/docker/cli/internal/test" "github.com/docker/docker/api/types" "github.com/docker/docker/api/types/filters" volumetypes "github.com/docker/docker/api/types/volume" "github.com/pkg/errors" // Import builders to get the builder function as package function - . "github.com/docker/cli/cli/internal/test/builders" + . "github.com/docker/cli/internal/test/builders" "github.com/docker/docker/pkg/testutil" "github.com/gotestyourself/gotestyourself/golden" "github.com/stretchr/testify/assert" diff --git a/components/cli/cli/command/volume/prune_test.go b/components/cli/cli/command/volume/prune_test.go index ccb5b15e39..788c02b342 100644 --- a/components/cli/cli/command/volume/prune_test.go +++ b/components/cli/cli/command/volume/prune_test.go @@ -8,7 +8,7 @@ import ( "testing" "github.com/docker/cli/cli/command" - "github.com/docker/cli/cli/internal/test" + "github.com/docker/cli/internal/test" "github.com/docker/docker/api/types" "github.com/docker/docker/api/types/filters" "github.com/docker/docker/pkg/testutil" diff --git a/components/cli/cli/command/volume/remove_test.go b/components/cli/cli/command/volume/remove_test.go index c10b18cc47..348714f4fe 100644 --- a/components/cli/cli/command/volume/remove_test.go +++ b/components/cli/cli/command/volume/remove_test.go @@ -4,7 +4,7 @@ import ( "io/ioutil" "testing" - "github.com/docker/cli/cli/internal/test" + "github.com/docker/cli/internal/test" "github.com/docker/docker/pkg/testutil" "github.com/pkg/errors" "github.com/stretchr/testify/assert" diff --git a/components/cli/cli/internal/test/builders/config.go b/components/cli/internal/test/builders/config.go similarity index 100% rename from components/cli/cli/internal/test/builders/config.go rename to components/cli/internal/test/builders/config.go diff --git a/components/cli/cli/internal/test/builders/doc.go b/components/cli/internal/test/builders/doc.go similarity index 100% rename from components/cli/cli/internal/test/builders/doc.go rename to components/cli/internal/test/builders/doc.go diff --git a/components/cli/cli/internal/test/builders/node.go b/components/cli/internal/test/builders/node.go similarity index 100% rename from components/cli/cli/internal/test/builders/node.go rename to components/cli/internal/test/builders/node.go diff --git a/components/cli/cli/internal/test/builders/secret.go b/components/cli/internal/test/builders/secret.go similarity index 100% rename from components/cli/cli/internal/test/builders/secret.go rename to components/cli/internal/test/builders/secret.go diff --git a/components/cli/cli/internal/test/builders/service.go b/components/cli/internal/test/builders/service.go similarity index 100% rename from components/cli/cli/internal/test/builders/service.go rename to components/cli/internal/test/builders/service.go diff --git a/components/cli/cli/internal/test/builders/swarm.go b/components/cli/internal/test/builders/swarm.go similarity index 100% rename from components/cli/cli/internal/test/builders/swarm.go rename to components/cli/internal/test/builders/swarm.go diff --git a/components/cli/cli/internal/test/builders/task.go b/components/cli/internal/test/builders/task.go similarity index 100% rename from components/cli/cli/internal/test/builders/task.go rename to components/cli/internal/test/builders/task.go diff --git a/components/cli/cli/internal/test/builders/volume.go b/components/cli/internal/test/builders/volume.go similarity index 100% rename from components/cli/cli/internal/test/builders/volume.go rename to components/cli/internal/test/builders/volume.go diff --git a/components/cli/cli/internal/test/cli.go b/components/cli/internal/test/cli.go similarity index 100% rename from components/cli/cli/internal/test/cli.go rename to components/cli/internal/test/cli.go diff --git a/components/cli/cli/internal/test/doc.go b/components/cli/internal/test/doc.go similarity index 100% rename from components/cli/cli/internal/test/doc.go rename to components/cli/internal/test/doc.go diff --git a/components/cli/cli/internal/test/network/client.go b/components/cli/internal/test/network/client.go similarity index 100% rename from components/cli/cli/internal/test/network/client.go rename to components/cli/internal/test/network/client.go diff --git a/components/cli/cli/internal/test/store.go b/components/cli/internal/test/store.go similarity index 100% rename from components/cli/cli/internal/test/store.go rename to components/cli/internal/test/store.go diff --git a/components/cli/internal/test/testutil/assert.go b/components/cli/internal/test/testutil/assert.go new file mode 100644 index 0000000000..cf5d2c9876 --- /dev/null +++ b/components/cli/internal/test/testutil/assert.go @@ -0,0 +1,15 @@ +package testutil + +import ( + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +// ErrorContains checks that the error is not nil, and contains the expected +// substring. +// TODO: replace with testify if https://github.com/stretchr/testify/pull/486 +// is accepted. +func ErrorContains(t require.TestingT, err error, expectedError string) { + require.Error(t, err) + assert.Contains(t, err.Error(), expectedError) +} From 01f2e768d758dfd93f031088ed9e2d937256e785 Mon Sep 17 00:00:00 2001 From: Daniel Nephin Date: Mon, 21 Aug 2017 16:39:35 -0400 Subject: [PATCH 32/47] Use new internal testutil.ErrorContains() Signed-off-by: Daniel Nephin Upstream-commit: 846a31aa50ec2186d958cf296241caa0d7e4e087 Component: cli --- .../cli/cli/command/checkpoint/create_test.go | 2 +- .../cli/cli/command/checkpoint/list_test.go | 2 +- .../cli/cli/command/checkpoint/remove_test.go | 2 +- .../cli/cli/command/config/create_test.go | 2 +- .../cli/cli/command/config/inspect_test.go | 2 +- components/cli/cli/command/config/ls_test.go | 2 +- .../cli/cli/command/config/remove_test.go | 2 +- .../cli/cli/command/container/attach_test.go | 2 +- .../cli/cli/command/container/exec_test.go | 2 +- .../cli/cli/command/container/opts_test.go | 2 +- .../cli/command/image/build/context_test.go | 2 +- .../cli/cli/command/image/history_test.go | 2 +- .../cli/cli/command/image/import_test.go | 2 +- .../cli/cli/command/image/inspect_test.go | 2 +- components/cli/cli/command/image/list_test.go | 2 +- components/cli/cli/command/image/load_test.go | 2 +- .../cli/cli/command/image/prune_test.go | 2 +- components/cli/cli/command/image/pull_test.go | 2 +- components/cli/cli/command/image/push_test.go | 2 +- .../cli/cli/command/image/remove_test.go | 2 +- components/cli/cli/command/image/save_test.go | 2 +- components/cli/cli/command/image/tag_test.go | 2 +- .../cli/cli/command/network/connect_test.go | 2 +- .../cli/cli/command/network/create_test.go | 2 +- .../cli/command/network/disconnect_test.go | 2 +- .../cli/cli/command/node/demote_test.go | 2 +- .../cli/cli/command/node/inspect_test.go | 2 +- .../cli/cli/command/node/promote_test.go | 2 +- .../cli/cli/command/node/remove_test.go | 2 +- .../cli/cli/command/node/update_test.go | 2 +- .../cli/cli/command/secret/create_test.go | 2 +- .../cli/cli/command/secret/inspect_test.go | 2 +- components/cli/cli/command/secret/ls_test.go | 2 +- .../cli/cli/command/secret/remove_test.go | 2 +- .../cli/cli/command/service/rollback_test.go | 2 +- .../command/stack/deploy_composefile_test.go | 2 +- components/cli/cli/command/stack/list_test.go | 2 +- components/cli/cli/command/stack/ps_test.go | 2 +- .../cli/cli/command/stack/services_test.go | 2 +- components/cli/cli/command/swarm/ca_test.go | 2 +- components/cli/cli/command/swarm/join_test.go | 2 +- .../cli/cli/command/swarm/join_token_test.go | 2 +- .../cli/cli/command/swarm/leave_test.go | 2 +- .../cli/cli/command/swarm/unlock_key_test.go | 2 +- .../cli/cli/command/swarm/unlock_test.go | 2 +- .../cli/cli/command/swarm/update_test.go | 2 +- .../cli/cli/command/volume/create_test.go | 2 +- .../cli/cli/command/volume/inspect_test.go | 2 +- .../cli/cli/command/volume/list_test.go | 2 +- .../cli/cli/command/volume/prune_test.go | 2 +- .../cli/cli/command/volume/remove_test.go | 2 +- .../cli/cli/compose/loader/volume_test.go | 2 +- components/cli/cli/config/config_test.go | 2 +- .../config/credentials/native_store_test.go | 2 +- components/cli/opts/mount_test.go | 2 +- components/cli/opts/network_test.go | 2 +- components/cli/opts/port_test.go | 2 +- .../docker/docker/pkg/testutil/helpers.go | 33 --- .../docker/docker/pkg/testutil/pkg.go | 1 - .../docker/docker/pkg/testutil/utils.go | 218 ------------------ 60 files changed, 57 insertions(+), 309 deletions(-) delete mode 100644 components/cli/vendor/github.com/docker/docker/pkg/testutil/helpers.go delete mode 100644 components/cli/vendor/github.com/docker/docker/pkg/testutil/pkg.go delete mode 100644 components/cli/vendor/github.com/docker/docker/pkg/testutil/utils.go diff --git a/components/cli/cli/command/checkpoint/create_test.go b/components/cli/cli/command/checkpoint/create_test.go index 8aae6eba5c..19bd3920c0 100644 --- a/components/cli/cli/command/checkpoint/create_test.go +++ b/components/cli/cli/command/checkpoint/create_test.go @@ -6,8 +6,8 @@ import ( "testing" "github.com/docker/cli/internal/test" + "github.com/docker/cli/internal/test/testutil" "github.com/docker/docker/api/types" - "github.com/docker/docker/pkg/testutil" "github.com/pkg/errors" "github.com/stretchr/testify/assert" ) diff --git a/components/cli/cli/command/checkpoint/list_test.go b/components/cli/cli/command/checkpoint/list_test.go index dd934cd590..373460d3be 100644 --- a/components/cli/cli/command/checkpoint/list_test.go +++ b/components/cli/cli/command/checkpoint/list_test.go @@ -5,8 +5,8 @@ import ( "testing" "github.com/docker/cli/internal/test" + "github.com/docker/cli/internal/test/testutil" "github.com/docker/docker/api/types" - "github.com/docker/docker/pkg/testutil" "github.com/gotestyourself/gotestyourself/golden" "github.com/pkg/errors" "github.com/stretchr/testify/assert" diff --git a/components/cli/cli/command/checkpoint/remove_test.go b/components/cli/cli/command/checkpoint/remove_test.go index 174a389eef..6100d75e41 100644 --- a/components/cli/cli/command/checkpoint/remove_test.go +++ b/components/cli/cli/command/checkpoint/remove_test.go @@ -5,8 +5,8 @@ import ( "testing" "github.com/docker/cli/internal/test" + "github.com/docker/cli/internal/test/testutil" "github.com/docker/docker/api/types" - "github.com/docker/docker/pkg/testutil" "github.com/pkg/errors" "github.com/stretchr/testify/assert" ) diff --git a/components/cli/cli/command/config/create_test.go b/components/cli/cli/command/config/create_test.go index a5bdce2dad..7bde47e694 100644 --- a/components/cli/cli/command/config/create_test.go +++ b/components/cli/cli/command/config/create_test.go @@ -8,9 +8,9 @@ import ( "testing" "github.com/docker/cli/internal/test" + "github.com/docker/cli/internal/test/testutil" "github.com/docker/docker/api/types" "github.com/docker/docker/api/types/swarm" - "github.com/docker/docker/pkg/testutil" "github.com/gotestyourself/gotestyourself/golden" "github.com/pkg/errors" "github.com/stretchr/testify/assert" diff --git a/components/cli/cli/command/config/inspect_test.go b/components/cli/cli/command/config/inspect_test.go index 320df70aaf..5ff280fd2a 100644 --- a/components/cli/cli/command/config/inspect_test.go +++ b/components/cli/cli/command/config/inspect_test.go @@ -11,7 +11,7 @@ import ( "github.com/pkg/errors" // Import builders to get the builder function as package function . "github.com/docker/cli/internal/test/builders" - "github.com/docker/docker/pkg/testutil" + "github.com/docker/cli/internal/test/testutil" "github.com/gotestyourself/gotestyourself/golden" "github.com/stretchr/testify/assert" ) diff --git a/components/cli/cli/command/config/ls_test.go b/components/cli/cli/command/config/ls_test.go index dfe79dc3c4..ac351cc725 100644 --- a/components/cli/cli/command/config/ls_test.go +++ b/components/cli/cli/command/config/ls_test.go @@ -12,7 +12,7 @@ import ( "github.com/pkg/errors" // Import builders to get the builder function as package function . "github.com/docker/cli/internal/test/builders" - "github.com/docker/docker/pkg/testutil" + "github.com/docker/cli/internal/test/testutil" "github.com/gotestyourself/gotestyourself/golden" "github.com/stretchr/testify/assert" ) diff --git a/components/cli/cli/command/config/remove_test.go b/components/cli/cli/command/config/remove_test.go index 2b7245167e..f7142a2566 100644 --- a/components/cli/cli/command/config/remove_test.go +++ b/components/cli/cli/command/config/remove_test.go @@ -6,7 +6,7 @@ import ( "testing" "github.com/docker/cli/internal/test" - "github.com/docker/docker/pkg/testutil" + "github.com/docker/cli/internal/test/testutil" "github.com/pkg/errors" "github.com/stretchr/testify/assert" ) diff --git a/components/cli/cli/command/container/attach_test.go b/components/cli/cli/command/container/attach_test.go index e4caa473af..8f87463af7 100644 --- a/components/cli/cli/command/container/attach_test.go +++ b/components/cli/cli/command/container/attach_test.go @@ -5,8 +5,8 @@ import ( "testing" "github.com/docker/cli/internal/test" + "github.com/docker/cli/internal/test/testutil" "github.com/docker/docker/api/types" - "github.com/docker/docker/pkg/testutil" "github.com/pkg/errors" ) diff --git a/components/cli/cli/command/container/exec_test.go b/components/cli/cli/command/container/exec_test.go index acfe250d3b..bf4fd3f35c 100644 --- a/components/cli/cli/command/container/exec_test.go +++ b/components/cli/cli/command/container/exec_test.go @@ -5,8 +5,8 @@ import ( "testing" "github.com/docker/cli/internal/test" + "github.com/docker/cli/internal/test/testutil" "github.com/docker/docker/api/types" - "github.com/docker/docker/pkg/testutil" "github.com/pkg/errors" "github.com/stretchr/testify/require" ) diff --git a/components/cli/cli/command/container/opts_test.go b/components/cli/cli/command/container/opts_test.go index b3a59d3999..6758751e99 100644 --- a/components/cli/cli/command/container/opts_test.go +++ b/components/cli/cli/command/container/opts_test.go @@ -11,9 +11,9 @@ import ( "testing" "time" + "github.com/docker/cli/internal/test/testutil" "github.com/docker/docker/api/types/container" networktypes "github.com/docker/docker/api/types/network" - "github.com/docker/docker/pkg/testutil" "github.com/docker/docker/runconfig" "github.com/docker/go-connections/nat" "github.com/pkg/errors" diff --git a/components/cli/cli/command/image/build/context_test.go b/components/cli/cli/command/image/build/context_test.go index 8bcbea48dd..a15b535ad7 100644 --- a/components/cli/cli/command/image/build/context_test.go +++ b/components/cli/cli/command/image/build/context_test.go @@ -11,8 +11,8 @@ import ( "strings" "testing" + "github.com/docker/cli/internal/test/testutil" "github.com/docker/docker/pkg/archive" - "github.com/docker/docker/pkg/testutil" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) diff --git a/components/cli/cli/command/image/history_test.go b/components/cli/cli/command/image/history_test.go index c0a7ef3139..eb656e5cf4 100644 --- a/components/cli/cli/command/image/history_test.go +++ b/components/cli/cli/command/image/history_test.go @@ -7,8 +7,8 @@ import ( "time" "github.com/docker/cli/internal/test" + "github.com/docker/cli/internal/test/testutil" "github.com/docker/docker/api/types/image" - "github.com/docker/docker/pkg/testutil" "github.com/gotestyourself/gotestyourself/golden" "github.com/pkg/errors" "github.com/stretchr/testify/assert" diff --git a/components/cli/cli/command/image/import_test.go b/components/cli/cli/command/image/import_test.go index 0e45e7887f..7f9bc2d8dc 100644 --- a/components/cli/cli/command/image/import_test.go +++ b/components/cli/cli/command/image/import_test.go @@ -7,8 +7,8 @@ import ( "testing" "github.com/docker/cli/internal/test" + "github.com/docker/cli/internal/test/testutil" "github.com/docker/docker/api/types" - "github.com/docker/docker/pkg/testutil" "github.com/pkg/errors" "github.com/stretchr/testify/assert" ) diff --git a/components/cli/cli/command/image/inspect_test.go b/components/cli/cli/command/image/inspect_test.go index d1de685610..4e94d06231 100644 --- a/components/cli/cli/command/image/inspect_test.go +++ b/components/cli/cli/command/image/inspect_test.go @@ -6,8 +6,8 @@ import ( "testing" "github.com/docker/cli/internal/test" + "github.com/docker/cli/internal/test/testutil" "github.com/docker/docker/api/types" - "github.com/docker/docker/pkg/testutil" "github.com/gotestyourself/gotestyourself/golden" "github.com/stretchr/testify/assert" ) diff --git a/components/cli/cli/command/image/list_test.go b/components/cli/cli/command/image/list_test.go index 9be4c379bc..1755bb3e3d 100644 --- a/components/cli/cli/command/image/list_test.go +++ b/components/cli/cli/command/image/list_test.go @@ -7,8 +7,8 @@ import ( "github.com/docker/cli/cli/config/configfile" "github.com/docker/cli/internal/test" + "github.com/docker/cli/internal/test/testutil" "github.com/docker/docker/api/types" - "github.com/docker/docker/pkg/testutil" "github.com/gotestyourself/gotestyourself/golden" "github.com/pkg/errors" "github.com/stretchr/testify/assert" diff --git a/components/cli/cli/command/image/load_test.go b/components/cli/cli/command/image/load_test.go index d3002aa1cd..5f05bca47b 100644 --- a/components/cli/cli/command/image/load_test.go +++ b/components/cli/cli/command/image/load_test.go @@ -8,8 +8,8 @@ import ( "testing" "github.com/docker/cli/internal/test" + "github.com/docker/cli/internal/test/testutil" "github.com/docker/docker/api/types" - "github.com/docker/docker/pkg/testutil" "github.com/gotestyourself/gotestyourself/golden" "github.com/pkg/errors" "github.com/stretchr/testify/assert" diff --git a/components/cli/cli/command/image/prune_test.go b/components/cli/cli/command/image/prune_test.go index 90845e4bb4..12f51b60fe 100644 --- a/components/cli/cli/command/image/prune_test.go +++ b/components/cli/cli/command/image/prune_test.go @@ -6,9 +6,9 @@ import ( "testing" "github.com/docker/cli/internal/test" + "github.com/docker/cli/internal/test/testutil" "github.com/docker/docker/api/types" "github.com/docker/docker/api/types/filters" - "github.com/docker/docker/pkg/testutil" "github.com/gotestyourself/gotestyourself/golden" "github.com/pkg/errors" "github.com/stretchr/testify/assert" diff --git a/components/cli/cli/command/image/pull_test.go b/components/cli/cli/command/image/pull_test.go index 57cd0ac772..157b391fdd 100644 --- a/components/cli/cli/command/image/pull_test.go +++ b/components/cli/cli/command/image/pull_test.go @@ -6,7 +6,7 @@ import ( "testing" "github.com/docker/cli/internal/test" - "github.com/docker/docker/pkg/testutil" + "github.com/docker/cli/internal/test/testutil" "github.com/gotestyourself/gotestyourself/golden" "github.com/stretchr/testify/assert" ) diff --git a/components/cli/cli/command/image/push_test.go b/components/cli/cli/command/image/push_test.go index 8f8b35d292..48d78b7d03 100644 --- a/components/cli/cli/command/image/push_test.go +++ b/components/cli/cli/command/image/push_test.go @@ -7,8 +7,8 @@ import ( "testing" "github.com/docker/cli/internal/test" + "github.com/docker/cli/internal/test/testutil" "github.com/docker/docker/api/types" - "github.com/docker/docker/pkg/testutil" "github.com/pkg/errors" "github.com/stretchr/testify/assert" ) diff --git a/components/cli/cli/command/image/remove_test.go b/components/cli/cli/command/image/remove_test.go index 7bf0434d6e..e89e6ddaf8 100644 --- a/components/cli/cli/command/image/remove_test.go +++ b/components/cli/cli/command/image/remove_test.go @@ -6,8 +6,8 @@ import ( "testing" "github.com/docker/cli/internal/test" + "github.com/docker/cli/internal/test/testutil" "github.com/docker/docker/api/types" - "github.com/docker/docker/pkg/testutil" "github.com/gotestyourself/gotestyourself/golden" "github.com/pkg/errors" "github.com/stretchr/testify/assert" diff --git a/components/cli/cli/command/image/save_test.go b/components/cli/cli/command/image/save_test.go index 9e3ff147ab..f402da7e84 100644 --- a/components/cli/cli/command/image/save_test.go +++ b/components/cli/cli/command/image/save_test.go @@ -8,7 +8,7 @@ import ( "testing" "github.com/docker/cli/internal/test" - "github.com/docker/docker/pkg/testutil" + "github.com/docker/cli/internal/test/testutil" "github.com/pkg/errors" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" diff --git a/components/cli/cli/command/image/tag_test.go b/components/cli/cli/command/image/tag_test.go index bb0c71cae5..0698522969 100644 --- a/components/cli/cli/command/image/tag_test.go +++ b/components/cli/cli/command/image/tag_test.go @@ -5,7 +5,7 @@ import ( "testing" "github.com/docker/cli/internal/test" - "github.com/docker/docker/pkg/testutil" + "github.com/docker/cli/internal/test/testutil" "github.com/stretchr/testify/assert" ) diff --git a/components/cli/cli/command/network/connect_test.go b/components/cli/cli/command/network/connect_test.go index 2343c7efbb..064aa041c8 100644 --- a/components/cli/cli/command/network/connect_test.go +++ b/components/cli/cli/command/network/connect_test.go @@ -5,8 +5,8 @@ import ( "testing" "github.com/docker/cli/internal/test" + "github.com/docker/cli/internal/test/testutil" "github.com/docker/docker/api/types/network" - "github.com/docker/docker/pkg/testutil" "github.com/pkg/errors" "github.com/stretchr/testify/assert" "golang.org/x/net/context" diff --git a/components/cli/cli/command/network/create_test.go b/components/cli/cli/command/network/create_test.go index b06febb4ea..dda68046db 100644 --- a/components/cli/cli/command/network/create_test.go +++ b/components/cli/cli/command/network/create_test.go @@ -6,9 +6,9 @@ import ( "testing" "github.com/docker/cli/internal/test" + "github.com/docker/cli/internal/test/testutil" "github.com/docker/docker/api/types" "github.com/docker/docker/api/types/network" - "github.com/docker/docker/pkg/testutil" "github.com/pkg/errors" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" diff --git a/components/cli/cli/command/network/disconnect_test.go b/components/cli/cli/command/network/disconnect_test.go index 04a5ab4378..e3920e9777 100644 --- a/components/cli/cli/command/network/disconnect_test.go +++ b/components/cli/cli/command/network/disconnect_test.go @@ -5,7 +5,7 @@ import ( "testing" "github.com/docker/cli/internal/test" - "github.com/docker/docker/pkg/testutil" + "github.com/docker/cli/internal/test/testutil" "github.com/pkg/errors" "golang.org/x/net/context" ) diff --git a/components/cli/cli/command/node/demote_test.go b/components/cli/cli/command/node/demote_test.go index ccdbb59904..bf86e5227e 100644 --- a/components/cli/cli/command/node/demote_test.go +++ b/components/cli/cli/command/node/demote_test.go @@ -9,7 +9,7 @@ import ( "github.com/pkg/errors" // Import builders to get the builder function as package function . "github.com/docker/cli/internal/test/builders" - "github.com/docker/docker/pkg/testutil" + "github.com/docker/cli/internal/test/testutil" "github.com/stretchr/testify/assert" ) diff --git a/components/cli/cli/command/node/inspect_test.go b/components/cli/cli/command/node/inspect_test.go index 1ce6ebd441..739a4783be 100644 --- a/components/cli/cli/command/node/inspect_test.go +++ b/components/cli/cli/command/node/inspect_test.go @@ -11,7 +11,7 @@ import ( "github.com/pkg/errors" // Import builders to get the builder function as package function . "github.com/docker/cli/internal/test/builders" - "github.com/docker/docker/pkg/testutil" + "github.com/docker/cli/internal/test/testutil" "github.com/gotestyourself/gotestyourself/golden" "github.com/stretchr/testify/assert" ) diff --git a/components/cli/cli/command/node/promote_test.go b/components/cli/cli/command/node/promote_test.go index e0e228e860..4c66342346 100644 --- a/components/cli/cli/command/node/promote_test.go +++ b/components/cli/cli/command/node/promote_test.go @@ -9,7 +9,7 @@ import ( "github.com/pkg/errors" // Import builders to get the builder function as package function . "github.com/docker/cli/internal/test/builders" - "github.com/docker/docker/pkg/testutil" + "github.com/docker/cli/internal/test/testutil" "github.com/stretchr/testify/assert" ) diff --git a/components/cli/cli/command/node/remove_test.go b/components/cli/cli/command/node/remove_test.go index 84d09c70e2..78fc4f76fa 100644 --- a/components/cli/cli/command/node/remove_test.go +++ b/components/cli/cli/command/node/remove_test.go @@ -5,7 +5,7 @@ import ( "testing" "github.com/docker/cli/internal/test" - "github.com/docker/docker/pkg/testutil" + "github.com/docker/cli/internal/test/testutil" "github.com/pkg/errors" "github.com/stretchr/testify/assert" ) diff --git a/components/cli/cli/command/node/update_test.go b/components/cli/cli/command/node/update_test.go index 4544cd12cb..e1aa28a806 100644 --- a/components/cli/cli/command/node/update_test.go +++ b/components/cli/cli/command/node/update_test.go @@ -9,7 +9,7 @@ import ( "github.com/pkg/errors" // Import builders to get the builder function as package function . "github.com/docker/cli/internal/test/builders" - "github.com/docker/docker/pkg/testutil" + "github.com/docker/cli/internal/test/testutil" "github.com/stretchr/testify/assert" ) diff --git a/components/cli/cli/command/secret/create_test.go b/components/cli/cli/command/secret/create_test.go index cc9eaa1067..f9f70cfedd 100644 --- a/components/cli/cli/command/secret/create_test.go +++ b/components/cli/cli/command/secret/create_test.go @@ -8,9 +8,9 @@ import ( "testing" "github.com/docker/cli/internal/test" + "github.com/docker/cli/internal/test/testutil" "github.com/docker/docker/api/types" "github.com/docker/docker/api/types/swarm" - "github.com/docker/docker/pkg/testutil" "github.com/gotestyourself/gotestyourself/golden" "github.com/pkg/errors" "github.com/stretchr/testify/assert" diff --git a/components/cli/cli/command/secret/inspect_test.go b/components/cli/cli/command/secret/inspect_test.go index 4a38a18f5d..188f6a7c4c 100644 --- a/components/cli/cli/command/secret/inspect_test.go +++ b/components/cli/cli/command/secret/inspect_test.go @@ -11,7 +11,7 @@ import ( "github.com/pkg/errors" // Import builders to get the builder function as package function . "github.com/docker/cli/internal/test/builders" - "github.com/docker/docker/pkg/testutil" + "github.com/docker/cli/internal/test/testutil" "github.com/gotestyourself/gotestyourself/golden" "github.com/stretchr/testify/assert" ) diff --git a/components/cli/cli/command/secret/ls_test.go b/components/cli/cli/command/secret/ls_test.go index af72effe94..2509e24dc3 100644 --- a/components/cli/cli/command/secret/ls_test.go +++ b/components/cli/cli/command/secret/ls_test.go @@ -13,7 +13,7 @@ import ( "github.com/pkg/errors" // Import builders to get the builder function as package function . "github.com/docker/cli/internal/test/builders" - "github.com/docker/docker/pkg/testutil" + "github.com/docker/cli/internal/test/testutil" "github.com/gotestyourself/gotestyourself/golden" "github.com/stretchr/testify/assert" ) diff --git a/components/cli/cli/command/secret/remove_test.go b/components/cli/cli/command/secret/remove_test.go index 51622136ab..accb3ea042 100644 --- a/components/cli/cli/command/secret/remove_test.go +++ b/components/cli/cli/command/secret/remove_test.go @@ -6,7 +6,7 @@ import ( "testing" "github.com/docker/cli/internal/test" - "github.com/docker/docker/pkg/testutil" + "github.com/docker/cli/internal/test/testutil" "github.com/pkg/errors" "github.com/stretchr/testify/assert" ) diff --git a/components/cli/cli/command/service/rollback_test.go b/components/cli/cli/command/service/rollback_test.go index f4183dae23..c063676645 100644 --- a/components/cli/cli/command/service/rollback_test.go +++ b/components/cli/cli/command/service/rollback_test.go @@ -7,9 +7,9 @@ import ( "testing" "github.com/docker/cli/internal/test" + "github.com/docker/cli/internal/test/testutil" "github.com/docker/docker/api/types" "github.com/docker/docker/api/types/swarm" - "github.com/docker/docker/pkg/testutil" "github.com/stretchr/testify/assert" "golang.org/x/net/context" ) diff --git a/components/cli/cli/command/stack/deploy_composefile_test.go b/components/cli/cli/command/stack/deploy_composefile_test.go index 28edb2c137..dacb7660f7 100644 --- a/components/cli/cli/command/stack/deploy_composefile_test.go +++ b/components/cli/cli/command/stack/deploy_composefile_test.go @@ -6,8 +6,8 @@ import ( "testing" "github.com/docker/cli/internal/test/network" + "github.com/docker/cli/internal/test/testutil" "github.com/docker/docker/api/types" - "github.com/docker/docker/pkg/testutil" "github.com/gotestyourself/gotestyourself/fs" "github.com/pkg/errors" "github.com/stretchr/testify/assert" diff --git a/components/cli/cli/command/stack/list_test.go b/components/cli/cli/command/stack/list_test.go index f194d04fcd..90d32e0f99 100644 --- a/components/cli/cli/command/stack/list_test.go +++ b/components/cli/cli/command/stack/list_test.go @@ -7,9 +7,9 @@ import ( "github.com/docker/cli/internal/test" // Import builders to get the builder function as package function . "github.com/docker/cli/internal/test/builders" + "github.com/docker/cli/internal/test/testutil" "github.com/docker/docker/api/types" "github.com/docker/docker/api/types/swarm" - "github.com/docker/docker/pkg/testutil" "github.com/gotestyourself/gotestyourself/golden" "github.com/pkg/errors" "github.com/stretchr/testify/assert" diff --git a/components/cli/cli/command/stack/ps_test.go b/components/cli/cli/command/stack/ps_test.go index b98c445f28..282e5e01da 100644 --- a/components/cli/cli/command/stack/ps_test.go +++ b/components/cli/cli/command/stack/ps_test.go @@ -9,9 +9,9 @@ import ( "github.com/docker/cli/internal/test" // Import builders to get the builder function as package function . "github.com/docker/cli/internal/test/builders" + "github.com/docker/cli/internal/test/testutil" "github.com/docker/docker/api/types" "github.com/docker/docker/api/types/swarm" - "github.com/docker/docker/pkg/testutil" "github.com/gotestyourself/gotestyourself/golden" "github.com/pkg/errors" "github.com/stretchr/testify/assert" diff --git a/components/cli/cli/command/stack/services_test.go b/components/cli/cli/command/stack/services_test.go index d1d6c24081..2f6d6e0e00 100644 --- a/components/cli/cli/command/stack/services_test.go +++ b/components/cli/cli/command/stack/services_test.go @@ -8,9 +8,9 @@ import ( "github.com/docker/cli/internal/test" // Import builders to get the builder function as package function . "github.com/docker/cli/internal/test/builders" + "github.com/docker/cli/internal/test/testutil" "github.com/docker/docker/api/types" "github.com/docker/docker/api/types/swarm" - "github.com/docker/docker/pkg/testutil" "github.com/gotestyourself/gotestyourself/golden" "github.com/pkg/errors" "github.com/stretchr/testify/assert" diff --git a/components/cli/cli/command/swarm/ca_test.go b/components/cli/cli/command/swarm/ca_test.go index 1271da1270..cb2668293a 100644 --- a/components/cli/cli/command/swarm/ca_test.go +++ b/components/cli/cli/command/swarm/ca_test.go @@ -8,8 +8,8 @@ import ( "time" "github.com/docker/cli/internal/test" + "github.com/docker/cli/internal/test/testutil" "github.com/docker/docker/api/types/swarm" - "github.com/docker/docker/pkg/testutil" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) diff --git a/components/cli/cli/command/swarm/join_test.go b/components/cli/cli/command/swarm/join_test.go index ed8eff8571..69546cd8cf 100644 --- a/components/cli/cli/command/swarm/join_test.go +++ b/components/cli/cli/command/swarm/join_test.go @@ -6,9 +6,9 @@ import ( "testing" "github.com/docker/cli/internal/test" + "github.com/docker/cli/internal/test/testutil" "github.com/docker/docker/api/types" "github.com/docker/docker/api/types/swarm" - "github.com/docker/docker/pkg/testutil" "github.com/pkg/errors" "github.com/stretchr/testify/assert" ) diff --git a/components/cli/cli/command/swarm/join_token_test.go b/components/cli/cli/command/swarm/join_token_test.go index 89f7ab22b9..6ab503113a 100644 --- a/components/cli/cli/command/swarm/join_token_test.go +++ b/components/cli/cli/command/swarm/join_token_test.go @@ -11,7 +11,7 @@ import ( "github.com/pkg/errors" // Import builders to get the builder function as package function . "github.com/docker/cli/internal/test/builders" - "github.com/docker/docker/pkg/testutil" + "github.com/docker/cli/internal/test/testutil" "github.com/gotestyourself/gotestyourself/golden" "github.com/stretchr/testify/assert" ) diff --git a/components/cli/cli/command/swarm/leave_test.go b/components/cli/cli/command/swarm/leave_test.go index d2f5d57bbb..cd8aeb8297 100644 --- a/components/cli/cli/command/swarm/leave_test.go +++ b/components/cli/cli/command/swarm/leave_test.go @@ -6,7 +6,7 @@ import ( "testing" "github.com/docker/cli/internal/test" - "github.com/docker/docker/pkg/testutil" + "github.com/docker/cli/internal/test/testutil" "github.com/pkg/errors" "github.com/stretchr/testify/assert" ) diff --git a/components/cli/cli/command/swarm/unlock_key_test.go b/components/cli/cli/command/swarm/unlock_key_test.go index e377e80c7b..97c04fc628 100644 --- a/components/cli/cli/command/swarm/unlock_key_test.go +++ b/components/cli/cli/command/swarm/unlock_key_test.go @@ -11,7 +11,7 @@ import ( "github.com/pkg/errors" // Import builders to get the builder function as package function . "github.com/docker/cli/internal/test/builders" - "github.com/docker/docker/pkg/testutil" + "github.com/docker/cli/internal/test/testutil" "github.com/gotestyourself/gotestyourself/golden" "github.com/stretchr/testify/assert" ) diff --git a/components/cli/cli/command/swarm/unlock_test.go b/components/cli/cli/command/swarm/unlock_test.go index 5151d6ba5e..c7aee0a3c7 100644 --- a/components/cli/cli/command/swarm/unlock_test.go +++ b/components/cli/cli/command/swarm/unlock_test.go @@ -7,9 +7,9 @@ import ( "github.com/docker/cli/cli/command" "github.com/docker/cli/internal/test" + "github.com/docker/cli/internal/test/testutil" "github.com/docker/docker/api/types" "github.com/docker/docker/api/types/swarm" - "github.com/docker/docker/pkg/testutil" "github.com/pkg/errors" "github.com/stretchr/testify/assert" ) diff --git a/components/cli/cli/command/swarm/update_test.go b/components/cli/cli/command/swarm/update_test.go index e1cd8d7c4d..e2a0033916 100644 --- a/components/cli/cli/command/swarm/update_test.go +++ b/components/cli/cli/command/swarm/update_test.go @@ -12,7 +12,7 @@ import ( "github.com/pkg/errors" // Import builders to get the builder function as package function . "github.com/docker/cli/internal/test/builders" - "github.com/docker/docker/pkg/testutil" + "github.com/docker/cli/internal/test/testutil" "github.com/gotestyourself/gotestyourself/golden" "github.com/stretchr/testify/assert" ) diff --git a/components/cli/cli/command/volume/create_test.go b/components/cli/cli/command/volume/create_test.go index de534053b1..d7c6cb5857 100644 --- a/components/cli/cli/command/volume/create_test.go +++ b/components/cli/cli/command/volume/create_test.go @@ -7,9 +7,9 @@ import ( "testing" "github.com/docker/cli/internal/test" + "github.com/docker/cli/internal/test/testutil" "github.com/docker/docker/api/types" volumetypes "github.com/docker/docker/api/types/volume" - "github.com/docker/docker/pkg/testutil" "github.com/pkg/errors" "github.com/stretchr/testify/assert" ) diff --git a/components/cli/cli/command/volume/inspect_test.go b/components/cli/cli/command/volume/inspect_test.go index 57949305e5..934e9b27d8 100644 --- a/components/cli/cli/command/volume/inspect_test.go +++ b/components/cli/cli/command/volume/inspect_test.go @@ -10,7 +10,7 @@ import ( "github.com/pkg/errors" // Import builders to get the builder function as package function . "github.com/docker/cli/internal/test/builders" - "github.com/docker/docker/pkg/testutil" + "github.com/docker/cli/internal/test/testutil" "github.com/gotestyourself/gotestyourself/golden" "github.com/stretchr/testify/assert" ) diff --git a/components/cli/cli/command/volume/list_test.go b/components/cli/cli/command/volume/list_test.go index 5f5654d5af..264e1010a1 100644 --- a/components/cli/cli/command/volume/list_test.go +++ b/components/cli/cli/command/volume/list_test.go @@ -12,7 +12,7 @@ import ( "github.com/pkg/errors" // Import builders to get the builder function as package function . "github.com/docker/cli/internal/test/builders" - "github.com/docker/docker/pkg/testutil" + "github.com/docker/cli/internal/test/testutil" "github.com/gotestyourself/gotestyourself/golden" "github.com/stretchr/testify/assert" ) diff --git a/components/cli/cli/command/volume/prune_test.go b/components/cli/cli/command/volume/prune_test.go index 788c02b342..d913f535db 100644 --- a/components/cli/cli/command/volume/prune_test.go +++ b/components/cli/cli/command/volume/prune_test.go @@ -9,9 +9,9 @@ import ( "github.com/docker/cli/cli/command" "github.com/docker/cli/internal/test" + "github.com/docker/cli/internal/test/testutil" "github.com/docker/docker/api/types" "github.com/docker/docker/api/types/filters" - "github.com/docker/docker/pkg/testutil" "github.com/gotestyourself/gotestyourself/golden" "github.com/gotestyourself/gotestyourself/skip" "github.com/pkg/errors" diff --git a/components/cli/cli/command/volume/remove_test.go b/components/cli/cli/command/volume/remove_test.go index 348714f4fe..fdfb1d788f 100644 --- a/components/cli/cli/command/volume/remove_test.go +++ b/components/cli/cli/command/volume/remove_test.go @@ -5,7 +5,7 @@ import ( "testing" "github.com/docker/cli/internal/test" - "github.com/docker/docker/pkg/testutil" + "github.com/docker/cli/internal/test/testutil" "github.com/pkg/errors" "github.com/stretchr/testify/assert" ) diff --git a/components/cli/cli/compose/loader/volume_test.go b/components/cli/cli/compose/loader/volume_test.go index f1b90fe8ea..a116683327 100644 --- a/components/cli/cli/compose/loader/volume_test.go +++ b/components/cli/cli/compose/loader/volume_test.go @@ -5,7 +5,7 @@ import ( "testing" "github.com/docker/cli/cli/compose/types" - "github.com/docker/docker/pkg/testutil" + "github.com/docker/cli/internal/test/testutil" "github.com/stretchr/testify/assert" ) diff --git a/components/cli/cli/config/config_test.go b/components/cli/cli/config/config_test.go index c885d3e724..25ed97cdf1 100644 --- a/components/cli/cli/config/config_test.go +++ b/components/cli/cli/config/config_test.go @@ -10,8 +10,8 @@ import ( "github.com/docker/cli/cli/config/configfile" "github.com/docker/cli/cli/config/credentials" + "github.com/docker/cli/internal/test/testutil" "github.com/docker/docker/pkg/homedir" - "github.com/docker/docker/pkg/testutil" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) diff --git a/components/cli/cli/config/credentials/native_store_test.go b/components/cli/cli/config/credentials/native_store_test.go index 582c2bd598..c85e3f0d18 100644 --- a/components/cli/cli/config/credentials/native_store_test.go +++ b/components/cli/cli/config/credentials/native_store_test.go @@ -8,10 +8,10 @@ import ( "strings" "testing" + "github.com/docker/cli/internal/test/testutil" "github.com/docker/docker-credential-helpers/client" "github.com/docker/docker-credential-helpers/credentials" "github.com/docker/docker/api/types" - "github.com/docker/docker/pkg/testutil" "github.com/pkg/errors" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" diff --git a/components/cli/opts/mount_test.go b/components/cli/opts/mount_test.go index 72aaa6258e..aba18a226f 100644 --- a/components/cli/opts/mount_test.go +++ b/components/cli/opts/mount_test.go @@ -4,8 +4,8 @@ import ( "os" "testing" + "github.com/docker/cli/internal/test/testutil" mounttypes "github.com/docker/docker/api/types/mount" - "github.com/docker/docker/pkg/testutil" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) diff --git a/components/cli/opts/network_test.go b/components/cli/opts/network_test.go index ac0b2115a1..d19823dc1d 100644 --- a/components/cli/opts/network_test.go +++ b/components/cli/opts/network_test.go @@ -3,7 +3,7 @@ package opts import ( "testing" - "github.com/docker/docker/pkg/testutil" + "github.com/docker/cli/internal/test/testutil" "github.com/stretchr/testify/assert" ) diff --git a/components/cli/opts/port_test.go b/components/cli/opts/port_test.go index f84b58453b..fb4ffe47c2 100644 --- a/components/cli/opts/port_test.go +++ b/components/cli/opts/port_test.go @@ -3,8 +3,8 @@ package opts import ( "testing" + "github.com/docker/cli/internal/test/testutil" "github.com/docker/docker/api/types/swarm" - "github.com/docker/docker/pkg/testutil" "github.com/stretchr/testify/assert" ) diff --git a/components/cli/vendor/github.com/docker/docker/pkg/testutil/helpers.go b/components/cli/vendor/github.com/docker/docker/pkg/testutil/helpers.go deleted file mode 100644 index c291148712..0000000000 --- a/components/cli/vendor/github.com/docker/docker/pkg/testutil/helpers.go +++ /dev/null @@ -1,33 +0,0 @@ -package testutil - -import ( - "strings" - "unicode" - - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" -) - -// ErrorContains checks that the error is not nil, and contains the expected -// substring. -func ErrorContains(t require.TestingT, err error, expectedError string) { - require.Error(t, err) - assert.Contains(t, err.Error(), expectedError) -} - -// EqualNormalizedString compare the actual value to the expected value after applying the specified -// transform function. It fails the test if these two transformed string are not equal. -// For example `EqualNormalizedString(t, RemoveSpace, "foo\n", "foo")` wouldn't fail the test as -// spaces (and thus '\n') are removed before comparing the string. -func EqualNormalizedString(t require.TestingT, transformFun func(rune) rune, actual, expected string) { - require.Equal(t, strings.Map(transformFun, expected), strings.Map(transformFun, actual)) -} - -// RemoveSpace returns -1 if the specified runes is considered as a space (unicode) -// and the rune itself otherwise. -func RemoveSpace(r rune) rune { - if unicode.IsSpace(r) { - return -1 - } - return r -} diff --git a/components/cli/vendor/github.com/docker/docker/pkg/testutil/pkg.go b/components/cli/vendor/github.com/docker/docker/pkg/testutil/pkg.go deleted file mode 100644 index 110b2e6a79..0000000000 --- a/components/cli/vendor/github.com/docker/docker/pkg/testutil/pkg.go +++ /dev/null @@ -1 +0,0 @@ -package testutil diff --git a/components/cli/vendor/github.com/docker/docker/pkg/testutil/utils.go b/components/cli/vendor/github.com/docker/docker/pkg/testutil/utils.go deleted file mode 100644 index 0522dde2b1..0000000000 --- a/components/cli/vendor/github.com/docker/docker/pkg/testutil/utils.go +++ /dev/null @@ -1,218 +0,0 @@ -package testutil - -import ( - "archive/tar" - "errors" - "fmt" - "io" - "io/ioutil" - "os" - "os/exec" - "path/filepath" - "reflect" - "strings" - "syscall" - "time" - - "github.com/docker/docker/pkg/stringutils" - "github.com/docker/docker/pkg/system" -) - -// IsKilled process the specified error and returns whether the process was killed or not. -func IsKilled(err error) bool { - if exitErr, ok := err.(*exec.ExitError); ok { - status, ok := exitErr.Sys().(syscall.WaitStatus) - if !ok { - return false - } - // status.ExitStatus() is required on Windows because it does not - // implement Signal() nor Signaled(). Just check it had a bad exit - // status could mean it was killed (and in tests we do kill) - return (status.Signaled() && status.Signal() == os.Kill) || status.ExitStatus() != 0 - } - return false -} - -func runCommandWithOutput(cmd *exec.Cmd) (output string, exitCode int, err error) { - out, err := cmd.CombinedOutput() - exitCode = system.ProcessExitCode(err) - output = string(out) - return -} - -// RunCommandPipelineWithOutput runs the array of commands with the output -// of each pipelined with the following (like cmd1 | cmd2 | cmd3 would do). -// It returns the final output, the exitCode different from 0 and the error -// if something bad happened. -func RunCommandPipelineWithOutput(cmds ...*exec.Cmd) (output string, exitCode int, err error) { - if len(cmds) < 2 { - return "", 0, errors.New("pipeline does not have multiple cmds") - } - - // connect stdin of each cmd to stdout pipe of previous cmd - for i, cmd := range cmds { - if i > 0 { - prevCmd := cmds[i-1] - cmd.Stdin, err = prevCmd.StdoutPipe() - - if err != nil { - return "", 0, fmt.Errorf("cannot set stdout pipe for %s: %v", cmd.Path, err) - } - } - } - - // start all cmds except the last - for _, cmd := range cmds[:len(cmds)-1] { - if err = cmd.Start(); err != nil { - return "", 0, fmt.Errorf("starting %s failed with error: %v", cmd.Path, err) - } - } - - defer func() { - var pipeErrMsgs []string - // wait all cmds except the last to release their resources - for _, cmd := range cmds[:len(cmds)-1] { - if pipeErr := cmd.Wait(); pipeErr != nil { - pipeErrMsgs = append(pipeErrMsgs, fmt.Sprintf("command %s failed with error: %v", cmd.Path, pipeErr)) - } - } - if len(pipeErrMsgs) > 0 && err == nil { - err = fmt.Errorf("pipelineError from Wait: %v", strings.Join(pipeErrMsgs, ", ")) - } - }() - - // wait on last cmd - return runCommandWithOutput(cmds[len(cmds)-1]) -} - -// ConvertSliceOfStringsToMap converts a slices of string in a map -// with the strings as key and an empty string as values. -func ConvertSliceOfStringsToMap(input []string) map[string]struct{} { - output := make(map[string]struct{}) - for _, v := range input { - output[v] = struct{}{} - } - return output -} - -// CompareDirectoryEntries compares two sets of FileInfo (usually taken from a directory) -// and returns an error if different. -func CompareDirectoryEntries(e1 []os.FileInfo, e2 []os.FileInfo) error { - var ( - e1Entries = make(map[string]struct{}) - e2Entries = make(map[string]struct{}) - ) - for _, e := range e1 { - e1Entries[e.Name()] = struct{}{} - } - for _, e := range e2 { - e2Entries[e.Name()] = struct{}{} - } - if !reflect.DeepEqual(e1Entries, e2Entries) { - return fmt.Errorf("entries differ") - } - return nil -} - -// ListTar lists the entries of a tar. -func ListTar(f io.Reader) ([]string, error) { - tr := tar.NewReader(f) - var entries []string - - for { - th, err := tr.Next() - if err == io.EOF { - // end of tar archive - return entries, nil - } - if err != nil { - return entries, err - } - entries = append(entries, th.Name) - } -} - -// RandomTmpDirPath provides a temporary path with rand string appended. -// does not create or checks if it exists. -func RandomTmpDirPath(s string, platform string) string { - tmp := "/tmp" - if platform == "windows" { - tmp = os.Getenv("TEMP") - } - path := filepath.Join(tmp, fmt.Sprintf("%s.%s", s, stringutils.GenerateRandomAlphaOnlyString(10))) - if platform == "windows" { - return filepath.FromSlash(path) // Using \ - } - return filepath.ToSlash(path) // Using / -} - -// ConsumeWithSpeed reads chunkSize bytes from reader before sleeping -// for interval duration. Returns total read bytes. Send true to the -// stop channel to return before reading to EOF on the reader. -func ConsumeWithSpeed(reader io.Reader, chunkSize int, interval time.Duration, stop chan bool) (n int, err error) { - buffer := make([]byte, chunkSize) - for { - var readBytes int - readBytes, err = reader.Read(buffer) - n += readBytes - if err != nil { - if err == io.EOF { - err = nil - } - return - } - select { - case <-stop: - return - case <-time.After(interval): - } - } -} - -// ParseCgroupPaths parses 'procCgroupData', which is output of '/proc//cgroup', and returns -// a map which cgroup name as key and path as value. -func ParseCgroupPaths(procCgroupData string) map[string]string { - cgroupPaths := map[string]string{} - for _, line := range strings.Split(procCgroupData, "\n") { - parts := strings.Split(line, ":") - if len(parts) != 3 { - continue - } - cgroupPaths[parts[1]] = parts[2] - } - return cgroupPaths -} - -// ChannelBuffer holds a chan of byte array that can be populate in a goroutine. -type ChannelBuffer struct { - C chan []byte -} - -// Write implements Writer. -func (c *ChannelBuffer) Write(b []byte) (int, error) { - c.C <- b - return len(b), nil -} - -// Close closes the go channel. -func (c *ChannelBuffer) Close() error { - close(c.C) - return nil -} - -// ReadTimeout reads the content of the channel in the specified byte array with -// the specified duration as timeout. -func (c *ChannelBuffer) ReadTimeout(p []byte, n time.Duration) (int, error) { - select { - case b := <-c.C: - return copy(p[0:], b), nil - case <-time.After(n): - return -1, fmt.Errorf("timeout reading from channel") - } -} - -// ReadBody read the specified ReadCloser content and returns it -func ReadBody(b io.ReadCloser) ([]byte, error) { - defer b.Close() - return ioutil.ReadAll(b) -} From f71ceb67bcf04bd3792de2c061c73fbd0088397d Mon Sep 17 00:00:00 2001 From: Daniel Nephin Date: Thu, 17 Aug 2017 12:56:33 -0400 Subject: [PATCH 33/47] Allow extension fields in the v3.4 version of the compose format. Signed-off-by: Daniel Nephin Upstream-commit: 2a1857e899390a1a6c8033c663a4ea2709f81150 Component: cli --- components/cli/cli/compose/schema/bindata.go | 2 +- .../cli/compose/schema/data/config_schema_v3.4.json | 1 + components/cli/cli/compose/schema/schema_test.go | 10 ++++++++++ 3 files changed, 12 insertions(+), 1 deletion(-) diff --git a/components/cli/cli/compose/schema/bindata.go b/components/cli/cli/compose/schema/bindata.go index 7518735138..73aedf0495 100644 --- a/components/cli/cli/compose/schema/bindata.go +++ b/components/cli/cli/compose/schema/bindata.go @@ -152,7 +152,7 @@ func dataConfig_schema_v33Json() (*asset, error) { return a, nil } -var _dataConfig_schema_v34Json = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xec\x5b\xcd\x72\xdb\x38\x12\xbe\xeb\x29\x58\x4c\x6e\x91\xed\x54\x6d\x6a\xab\x36\xb7\x3d\xee\x69\xe7\x3c\x2e\x85\x05\x81\x2d\x09\x31\x08\x20\x0d\x50\xb6\x92\xf2\xbb\x4f\xf1\x57\xfc\x01\x01\x50\xa2\x63\x67\x26\x27\x5b\xe4\xd7\x00\xba\x81\xfe\xba\x1b\x00\x7f\xac\xa2\x28\x7e\xaf\xe9\x01\x32\x12\x7f\x8e\xe2\x83\x31\xea\xf3\xdd\xdd\x57\x2d\xc5\x4d\xf5\xf4\x56\xe2\xfe\x2e\x45\xb2\x33\x37\x1f\x3f\xdd\x55\xcf\xde\xc5\xeb\x42\x8e\xa5\x85\x08\x95\x62\xc7\xf6\x49\xf5\x26\x39\xfe\xeb\xf6\xd3\x6d\x21\x5e\x41\xcc\x49\x41\x01\x92\xdb\xaf\x40\x4d\xf5\x0c\xe1\x5b\xce\x10\x0a\xe1\xfb\xf8\x08\xa8\x99\x14\xf1\x66\xbd\x2a\xde\x29\x94\x0a\xd0\x30\xd0\xf1\xe7\xa8\x18\x5c\x14\xb5\x90\xe6\x41\xa7\x59\x6d\x90\x89\x7d\x5c\x3e\x7e\x2e\x5b\x88\xa2\x58\x03\x1e\x19\xed\xb4\xd0\x0e\xf5\xdd\xdd\xb9\xfd\xbb\x16\xb6\x1e\xb6\xda\x19\x6c\xf9\x5c\x11\x63\x00\xc5\x1f\xe3\xb1\x95\xaf\xbf\xdc\x93\x9b\xef\xff\xbd\xf9\xf3\xe3\xcd\x7f\x6e\x93\x9b\xcd\x87\xf7\xbd\xd7\x85\x7d\x11\x76\x55\xf7\x29\xec\x98\x60\x86\x49\xd1\xf6\x1f\xb7\xc8\xe7\xfa\xbf\xe7\xb6\x63\x92\xa6\x25\x98\xf0\x5e\xdf\x3b\xc2\x35\xf4\x75\x16\x60\x1e\x25\x3e\xf8\x74\x6e\x61\xaf\xa4\x73\xdd\xbf\x45\xe7\xbe\x3a\x47\xc9\xf3\xcc\x3b\x83\x0d\xea\x95\x94\xa9\xba\x5f\x66\xfe\x34\x50\x04\xe3\x5f\xb2\x15\xea\xd5\x56\x6c\xd1\xfd\x32\x0a\x57\xac\xe1\x53\xb8\x41\xbd\x92\xc2\x55\xf7\xd7\x29\xbc\x6a\x94\x76\x62\x2b\x44\xa7\xef\x72\x80\x3d\x3e\xb3\x99\xca\xc6\x27\xd3\xb6\x6a\x8d\x35\x61\xa5\x14\x14\x97\xa7\xe2\xd9\x84\x3d\x2a\x40\x06\xc2\xc4\xad\x09\xa2\x28\xde\xe6\x8c\xa7\x43\x8b\x4a\x01\xff\x2f\x9a\xb8\xef\x3c\x8c\xa2\x1f\x43\xea\xee\xb4\x53\xbe\xef\xfd\x9a\x9e\xf0\xf6\xfd\x84\x2e\xed\x7b\x2a\x85\x81\x27\x53\x2a\xe5\xee\xba\x32\x81\xa4\x0f\x80\x3b\xc6\x21\x54\x82\x60\xb5\x8a\x27\x4c\xc6\x99\x36\x89\xc4\x24\x65\xd4\x58\xe5\x39\xd9\x02\xbf\xaa\x05\x4a\xe8\x01\x92\x1d\xca\xcc\xdb\xca\x2e\xa9\x34\xd1\xd6\x86\x1a\x76\x0e\xd4\xdc\x10\xdc\x83\xdd\xb2\x03\xf0\x48\xda\xef\x37\xad\x68\xe7\xd7\x66\x65\x69\x30\xa6\x44\x25\x24\x4d\x7b\xe3\x20\x88\xe4\x14\xaf\xa3\x98\x19\xc8\xb4\x5d\xa1\x28\xce\x05\xfb\x96\xc3\xff\x6a\x88\xc1\x1c\x86\xed\xa6\x28\xd5\xf2\x0d\xef\x51\xe6\x2a\x51\x04\x0b\x47\x72\x1b\x3b\xa6\x32\xcb\x88\x58\xca\xbb\xe6\xe8\x11\x60\xf9\x11\x87\x47\x5d\x97\xad\xfb\xe8\xbe\x6a\x7b\xeb\x0d\x6b\x42\x1b\xbf\x3e\x63\xbe\xf0\x33\x86\x9f\x33\x0a\xca\x95\x39\xd2\x50\x0a\x70\xbb\x82\x15\x9f\xb3\x34\x1c\xbc\x9f\x03\xce\x64\xda\x1f\xb7\xc8\xb3\x2d\xe0\xc8\x25\xfb\x9e\x35\xfe\xbd\x59\xd9\xde\x0c\x66\xdf\x10\x26\x00\x13\x41\x32\x9f\xad\x62\x8a\x90\x82\x30\x8c\xf0\x44\x2b\xa0\x3d\x78\x33\x53\x8e\x99\x89\x83\x28\x39\x46\xd8\x33\x6d\xf0\xe4\x26\xa5\xe7\xee\xc0\x52\x50\x20\x52\x9d\x54\x05\xc6\x7c\xf6\x8c\x53\x68\xab\x8d\x45\x69\x22\x15\xae\xa8\x50\x35\x53\xc4\x85\x62\x6c\xf1\x40\x30\xd1\x40\x90\x1e\x2e\x94\x97\x19\x61\x22\x64\x52\x41\x18\x3c\x29\xc9\x2a\x1a\x7b\x73\xfc\x04\xe2\x98\xb4\xeb\x66\xb6\x19\x40\x1c\x19\x4a\x91\x35\x24\x1d\x16\x9d\x3b\xf2\x4f\x4a\x6a\xb8\x9e\x1c\x6b\x89\xfb\x46\xf1\x75\xeb\xd3\x9b\xbe\xf5\xe2\x9d\xc4\x8c\x14\x83\x6d\xfa\xee\xfa\x70\xaf\xab\xf1\xca\xeb\x1a\xb0\xab\x43\x91\x55\x13\x9e\x70\x26\x1e\x96\x5f\xe2\xf0\x64\x90\x24\x07\xa9\xcd\x25\x09\x50\x7c\x00\xc2\xcd\x81\x1e\x80\x3e\x38\xc4\xbb\xa8\x9e\xb4\xd4\x26\x64\x91\xb3\x8c\xec\xfd\x20\x45\x7d\x90\x8b\x13\xbd\x78\x51\xe3\x77\x9a\x95\xfb\x7d\x01\x9d\x5a\x71\xa3\xc2\xa1\x7e\xed\x4b\xb9\x53\x64\x47\xc0\xd0\x2c\x52\xaa\x73\xbd\x33\x7c\x19\x12\xcd\xbd\xc5\x5f\x0f\xfa\xe5\xb6\xaa\xfd\x1c\x5e\x55\xfe\xc7\x79\xbc\x19\x87\xcc\x71\xd0\x1c\x3e\x19\x68\x18\x96\xe7\xf6\x66\x25\x23\xb4\x48\x67\x11\xf4\xc4\xbc\x9e\xa1\x75\xbe\x9e\x8c\x62\xfe\x19\x3b\x02\x8f\x02\xeb\x14\x53\x5f\x54\x46\xcc\x2f\xdf\x82\xa6\xce\x5b\xbf\x7b\xb4\x99\x1a\x5e\xe8\x30\xcf\xc3\xf5\x2f\xb1\x12\x47\x38\x23\x1a\xfc\xce\xee\xac\xc7\xda\xd6\x98\x3a\x7e\x0a\x5c\x13\x36\xd9\x7f\x3b\x65\x27\x44\x27\xdb\x0c\x2f\xdd\x3c\x4d\x75\x53\x54\xce\xad\x03\xd9\xf8\x93\xd6\x97\xac\x2c\x55\x3f\xf1\xee\x73\x45\xc9\x10\x5d\x07\x53\x12\xcd\x4f\xa9\x85\xce\x3c\x75\x0e\xf8\x55\xe7\xe3\xf2\x68\x38\xdd\x41\x42\x2f\x53\x53\x39\x58\xca\x82\xb6\x54\x54\x4c\x18\xd8\x17\xa5\x8c\x3d\x08\xe4\x5b\xce\xf4\x01\xd2\x39\x32\x28\x8d\xa4\x92\x87\x39\x86\x75\xf7\x27\xdc\x19\x1c\xf5\xd5\x45\xb9\x99\x42\x76\x64\x1c\xf6\x03\x8d\xb7\x52\x72\x20\xa2\x17\x28\x10\x48\x9a\x48\xc1\x4f\x01\x48\x6d\x08\x7a\x77\x25\x34\xd0\x1c\x99\x39\x25\x52\x99\xc5\xb3\x42\x7d\xc8\x12\xcd\xbe\x43\xdf\xf7\xce\xab\xbe\x6e\x68\x33\x18\xd0\x60\xff\x3c\xfa\xbd\x15\xf1\x8f\xd9\x8a\xd0\x27\x4d\xcd\x65\xb9\xb5\x36\x29\x13\x89\x54\x20\xbc\xbe\xa1\x8d\x54\xc9\x1e\x09\x85\x44\x01\x32\x69\x35\x45\x8f\x60\xd3\x1c\x49\xd1\xff\xb8\x19\xcd\xf6\x82\xd8\x79\xa7\x03\x35\x99\xda\x5d\xb8\x09\x60\x8c\xdf\xd9\x73\xce\x32\x36\xed\x34\x96\x55\x1b\x90\xaf\x55\xb9\x9a\x3d\x45\x73\xa4\x67\x41\x94\xed\xa8\x10\xdc\x05\x42\x40\x65\x70\x20\x38\x23\x74\x94\x8e\xb9\x9b\x88\x4f\xb6\xba\xc1\x3a\xae\xde\x49\x78\xd9\xde\xba\x1e\xc8\xc6\x8a\x9f\x95\x7a\x0d\x87\xb1\x99\xcc\x7e\xec\x4e\x95\x6b\x6f\x11\x57\x62\x84\x76\x15\x20\x2d\x74\x7c\xa4\x1b\xfd\x12\x0c\xdd\x9b\xa3\x12\x6e\x99\x9b\x00\x1e\xaf\x7b\x0a\xe4\xce\x97\x66\xfd\xe0\x8c\xa0\x23\x43\xa5\xd0\x4c\x1b\x10\xd4\xbe\xbf\x6a\x15\xda\xb2\xd1\xe1\xc5\xd8\x28\xee\xba\x2b\xac\xea\x2a\x51\x64\x5f\xf1\x6d\x70\xa1\x13\xee\xab\xf5\x69\xff\x4f\x51\x45\x48\x2a\xd5\xc4\xd4\x84\xab\x31\x37\xcc\x0e\xb6\x2e\x1c\x79\xe8\x14\x65\x3c\x4a\x7c\x28\x02\x52\xca\xec\xcc\xb1\x1a\x88\xcc\xb8\x2f\x30\xd8\xeb\x6b\x1a\xb0\x1d\x84\x77\xa1\xde\x8b\x03\xee\x43\xf9\x1a\x34\x79\x60\xce\x34\xd9\x0e\xce\x25\x6c\x81\xb6\x88\x0c\x78\xf4\xc7\x7b\x04\x83\x6c\x70\x94\xd0\x24\x4d\xdd\xd8\x0e\xfa\x6d\x6e\xb8\x1b\x96\x81\xcc\x9d\x47\xc2\xed\x45\x9f\xca\x80\xe7\x0b\x05\x9e\x49\xed\x20\x87\x73\x7a\xdf\x39\x40\xaa\xea\x72\xef\xc4\x85\x04\x2c\x10\x69\x79\xb4\x11\x14\xdd\x10\x14\x67\x94\x68\x5f\x06\x71\xc5\x2e\x70\xae\x52\x62\x20\xa9\xef\xa4\xcc\xc9\xd9\x1c\xc9\x9a\x22\x48\x38\x07\xce\x74\x16\x92\xfc\xc4\x29\x70\x62\x65\x7f\x6f\xde\x5b\x8a\xef\x08\xe3\x39\x42\x42\xe8\x24\x4d\x0f\x24\x32\x29\x98\x91\x56\x3a\x09\xeb\x32\x23\x4f\x49\xd3\x6d\x09\xf1\x78\x57\x29\x24\x31\xb5\x27\x3f\xeb\x62\x5d\xe4\x99\x25\xfd\x88\xcb\xc2\xf9\x66\xc7\x50\x9b\xaa\x4a\x95\xaa\xfe\xd5\xa7\xd9\xe7\xc9\xca\x3f\x74\xb3\xb8\xb3\xea\xaa\x3c\x61\x5e\x0a\xef\x58\x0e\xe7\x82\x60\x62\x75\x36\x3d\x8e\x2c\x86\xa0\x0b\x8a\x6b\xf7\xf2\xbd\xf2\x8b\x5a\xa1\x30\x7d\xa2\x24\x67\x55\x6a\xb2\x84\x29\xa8\x14\xd5\x38\x42\x56\xe9\x95\x6e\x51\xac\xd1\xa2\xb0\xca\x94\xf1\x32\x48\x29\xf0\xc8\x44\x2a\x1f\x67\x74\xb8\x9c\xb5\x15\x27\x14\x06\x8c\x7d\xad\xa1\xb5\x41\xc2\x84\x99\x7d\xc6\x35\x34\x8b\x42\xd8\x01\x82\x18\x7b\x44\xe4\xae\x35\xa2\xe9\x7a\xc3\xa7\x9b\x5f\xc3\x1a\xa1\x55\x91\x74\xbf\xc2\x56\xe3\xb5\x93\x7f\x45\xd6\xd6\xba\xbb\x27\xba\xb7\x38\x6f\xbe\x36\x15\xd1\xa9\xca\xbd\xe7\x65\x19\x64\xd2\x7d\x37\xe4\x8a\xab\xd7\x3e\x15\x1b\xd8\x02\xd9\x4b\xd0\x01\x6b\x8d\x4a\xa4\x5a\x7e\x87\xc7\x7f\x88\xba\xf1\xef\x2f\x30\x45\xb2\xa5\x38\x24\xf8\xc8\x39\xb6\xa6\x4f\xd1\x1b\x60\x87\x7c\x2b\xc2\x2e\x53\xbe\x31\x76\xe8\x5f\xe7\x28\x6f\x8b\x4c\xcc\xea\x7d\x5b\x1b\xad\x5b\x5b\x6d\x82\xa7\x78\xf2\xaa\xc6\x72\xe3\x2f\xcb\xb4\xe1\xb6\xac\xad\x9e\x23\xc6\x10\x7a\x08\x2a\xfd\x66\xe6\xfb\x57\xf0\xd0\x68\x83\xc2\x4a\x43\x35\x6a\x01\x16\x0a\xb9\x3b\xf3\xf7\x60\xaa\x5f\x7d\x5d\xff\xbc\x35\x58\x7f\x21\xe2\xfd\x52\xa1\x44\x5d\x1c\xeb\x03\xee\x82\xbe\x81\x39\x7b\xe5\xa9\x18\x05\x3a\xeb\x54\xd4\xa8\xdf\x53\xf1\xa2\x5e\xd1\x3f\xa6\xeb\x4c\xc9\x78\xd7\xce\x65\xc9\xe0\xbb\x44\xb5\xc4\xa6\x3f\x8c\x21\xcc\xf2\x3d\x65\x3f\xf7\x71\x1d\xe2\x37\x90\x89\x5d\xe2\x41\xa7\xb5\x11\xdd\x9a\x2f\xc8\xfb\xb7\x1f\x1c\x19\x9e\xeb\xce\xdf\x0b\xa5\x46\x0b\x5c\x90\xb0\xcf\xe9\xa0\x78\x6e\xac\x3b\xfe\x64\x6c\xda\xff\x1b\xf9\xd1\x07\x64\x85\x9e\xe2\x34\xda\x55\xfe\xd1\x3f\x12\xab\x3e\xfe\xda\xf4\xec\x33\x80\x54\x37\x68\x3b\x81\x76\xd3\xdd\x4f\x98\xbc\xf2\x6f\xfb\xac\x6c\x78\x20\xd7\x7c\xde\x35\x71\x47\x60\xd5\xfd\x5b\x7e\x8a\xb7\x7a\x5e\xfd\x15\x00\x00\xff\xff\xfa\xb6\x96\x65\xf4\x3c\x00\x00") +var _dataConfig_schema_v34Json = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xec\x5b\x4f\x73\xdb\x3a\x0e\xbf\xfb\x53\x68\xf4\xde\xad\x76\xd2\x99\xed\xec\xcc\xf6\xb6\xc7\x3d\xed\x9e\x37\xe3\x6a\x68\x0a\xb6\xd9\x50\x24\x0b\x52\x4e\xdc\x4e\xbe\xfb\x8e\xfe\x5a\x7f\x28\x92\xb2\x95\x26\xdd\xd7\x53\x62\x09\x00\x09\x80\xf8\x01\x20\xa9\x1f\xab\x28\x8a\xff\xd4\xf4\x08\x19\x89\x3f\x47\xf1\xd1\x18\xf5\xf9\xfe\xfe\xab\x96\x62\x53\x3d\xbd\x93\x78\xb8\x4f\x91\xec\xcd\xe6\xe3\xa7\xfb\xea\xd9\x1f\xf1\xba\xe0\x63\x69\xc1\x42\xa5\xd8\xb3\x43\x52\xbd\x49\x4e\x7f\xbb\xfb\x74\x57\xb0\x57\x24\xe6\xac\xa0\x20\x92\xbb\xaf\x40\x4d\xf5\x0c\xe1\x5b\xce\x10\x0a\xe6\x87\xf8\x04\xa8\x99\x14\xf1\x76\xbd\x2a\xde\x29\x94\x0a\xd0\x30\xd0\xf1\xe7\xa8\x98\x5c\x14\xb5\x24\xcd\x83\x8e\x58\x6d\x90\x89\x43\x5c\x3e\x7e\x29\x25\x44\x51\xac\x01\x4f\x8c\x76\x24\xb4\x53\xfd\xe3\xfe\x22\xff\xbe\x25\x5b\x0f\xa5\x76\x26\x5b\x3e\x57\xc4\x18\x40\xf1\x9f\xf1\xdc\xca\xd7\x5f\x1e\xc8\xe6\xfb\x3f\x37\xff\xfd\xb8\xf9\xc7\x5d\xb2\xd9\x7e\xf8\xb3\xf7\xba\xb0\x2f\xc2\xbe\x1a\x3e\x85\x3d\x13\xcc\x30\x29\xda\xf1\xe3\x96\xf2\xa5\xfe\xef\xa5\x1d\x98\xa4\x69\x49\x4c\x78\x6f\xec\x3d\xe1\x1a\xfa\x3a\x0b\x30\x4f\x12\x1f\x7d\x3a\xb7\x64\x6f\xa4\x73\x3d\xbe\x45\xe7\xbe\x3a\x27\xc9\xf3\xcc\xeb\xc1\x86\xea\x8d\x94\xa9\x86\x5f\xc6\x7f\x1a\x28\x82\xf1\x2f\xd9\x8a\xea\xcd\x56\x6c\x31\xfc\x32\x0a\x57\xa8\xe1\x53\xb8\xa1\x7a\x23\x85\xab\xe1\x6f\x53\x78\xd5\x28\x6d\x9f\x63\xfc\xe5\x79\x53\xfc\x7d\x29\x65\x3a\xe5\x55\x52\x3a\xf3\x2b\x95\xe8\x61\x9e\xcd\x9c\x36\xcc\x99\xb6\x67\x6b\xd0\x09\x4b\xa6\xa0\xb8\x3c\x97\x33\xb7\xdb\xac\x22\xc8\x40\x98\xb8\x35\x53\x14\xc5\xbb\x9c\xf1\x74\x68\x75\x29\xe0\xdf\x85\x88\x87\xce\xc3\x28\xfa\x31\x84\xf7\x8e\x9c\xf2\x7d\xef\xd7\xf4\xa2\x68\xdf\x4f\xe8\xd2\xbe\xa7\x52\x18\x78\x36\xa5\x52\xee\xa1\x2b\x13\x48\xfa\x08\xb8\x67\x1c\x42\x39\x08\x56\x2b\x7d\xc2\x64\x9c\x69\x93\x48\x4c\x52\x46\x8d\x95\x9f\x93\x1d\xf0\x9b\x24\x50\x42\x8f\x90\xec\x51\x66\x5e\x29\xfb\xa4\xd2\x44\x5b\x05\x35\x08\x1e\xa8\xb9\x21\x78\x00\xbb\x65\x07\xc4\x23\x6e\x7f\x6c\xb5\xac\x9d\x5f\xdb\x95\x45\x60\x4c\x89\x4a\x48\x9a\xf6\xe6\x41\x10\xc9\x39\x5e\x47\x31\x33\x90\x69\xbb\x42\x51\x9c\x0b\xf6\x2d\x87\x7f\xd5\x24\x06\x73\x18\xca\x4d\x51\xaa\xe5\x05\x1f\x50\xe6\x2a\x51\x04\x8b\x40\x72\x1b\x3b\xa6\x32\xcb\x88\x58\x2a\xba\xe6\xe8\x11\x60\xf9\x11\xce\x47\xdd\x90\xad\xc7\xe8\xbe\x6a\x47\xeb\x4d\x6b\x42\x1b\xbf\x3e\x63\xbc\xf0\x23\x86\x1f\x33\x0a\xc8\x95\x39\xd2\x50\x08\x70\x87\x82\x95\x3e\x67\x69\x38\xf1\x61\x0e\x71\x26\xd3\xfe\xbc\x45\x9e\xed\x00\x47\x21\xd9\x8f\xac\xf1\xef\xed\xca\xf6\x66\xe0\x7d\x43\x98\x00\x4c\x04\xc9\x7c\xb6\x8a\x29\x42\x0a\xc2\x30\xc2\x13\xad\x80\xf6\xc8\x1b\x4f\x39\x3c\x13\x07\x41\x72\x8c\x70\x60\xda\xe0\xd9\x0d\x4a\x2f\xdd\x89\xa5\xa0\x40\xa4\x3a\xa9\x9a\x90\xf9\xe8\x19\xa7\xd0\x76\x24\x8b\xc2\x44\x2a\x5c\x59\xa1\x12\x53\xe4\x85\x62\x6e\xf1\x80\x31\xd1\x40\x90\x1e\xaf\xe4\x97\x19\x61\x22\xc4\xa9\x20\x0c\x9e\x95\x64\x15\x8c\xbd\x3b\x7c\x02\x71\x4a\xda\x75\x33\xdb\x0c\x20\x4e\x0c\xa5\xc8\x1a\x90\x0e\xcb\xce\x1d\xfe\x67\x25\x35\xdc\x0e\x8e\x35\xc7\x43\xa3\xf8\xba\x8d\xe9\x6d\xdf\x7a\xf1\x5e\x62\x46\x8a\xc9\x36\x63\x77\x63\xb8\x37\xd4\x78\xe5\x75\x0d\xd8\xd5\xa1\xa8\x6a\x09\x4f\x38\x13\x8f\xcb\x2f\x71\x78\x36\x48\x92\xa3\xd4\xe6\x9a\x02\x28\x3e\x02\xe1\xe6\x48\x8f\x40\x1f\x1d\xec\x5d\xaa\x1e\xb7\xd4\x26\x64\x91\xb3\x8c\x1c\xfc\x44\x8a\xfa\x48\xae\x2e\xf4\xe2\x45\x8d\xdf\x11\x2b\x0f\x87\x82\x74\x6a\xc5\x8d\x1a\x87\xfa\xb5\xaf\xe4\x4e\x91\x9d\x00\x43\xab\x48\xa9\x2e\xfd\xce\xf0\x65\x48\x36\xf7\x36\x88\x3d\xd2\x2f\x77\x55\x7f\xe8\x88\xaa\xf2\x3f\xce\xe3\xed\x38\x65\x8e\x93\xe6\xf0\xc9\x40\xc3\xb0\x3a\xb7\xe7\x95\x8c\xd0\xa2\x9c\x45\xd0\x13\x7e\xbd\x90\xd6\xf5\x7a\x32\xca\xf9\x17\xda\x11\xf1\x28\xb1\x4e\x21\xf5\x55\x6d\xc4\xfc\xf6\x2d\xc8\x75\xde\x1e\xdf\xa3\xcd\xd4\xf4\x42\xa7\x79\x99\xae\x7f\x89\x95\x74\x84\x33\xa2\xc1\x1f\xec\xce\x7e\xac\x95\xc6\xd4\xe9\x53\xe0\x9a\xb0\xf1\xfe\xdd\xc9\x3b\xc1\x3a\x29\x33\xbc\x75\xf3\x88\xea\x96\xa8\x9c\x5b\x27\xb2\xf5\x17\xad\xaf\xd9\x59\xaa\x7e\xe1\xdd\xc7\x8a\x12\x21\xba\x01\xa6\x24\x9a\x9f\xd2\x0b\x5d\x70\xea\x92\xf0\xab\xc1\xc7\xed\xd1\xd0\xdd\x41\x4c\xaf\xd3\x53\x39\x50\xca\x42\x6d\xe9\xa8\x98\x30\x70\x28\x5a\x19\x7b\x12\xc8\x77\x9c\xe9\x23\xa4\x73\x78\x50\x1a\x49\x25\x0f\x0b\x0c\xeb\xee\x4f\x78\x30\x38\xfa\xab\xab\x6a\x33\x85\xec\xc4\x38\x1c\x06\x1a\xef\xa4\xe4\x40\x44\x2f\x51\x20\x90\x34\x91\x82\x9f\x03\x28\xb5\x21\xe8\xdd\x95\xd0\x40\x73\x64\xe6\x9c\x48\x65\x16\xaf\x0a\xf5\x31\x4b\x34\xfb\x0e\xfd\xd8\xbb\xac\xfa\x5a\xd0\x76\x30\xa1\xc1\x1e\x7b\xf4\x7b\x2b\xe2\x2f\xb3\x15\xa1\xcf\x9a\x9a\xeb\x6a\x6b\x6d\x52\x26\x12\xa9\x40\x78\x63\x43\x1b\xa9\x92\x03\x12\x0a\x89\x02\x64\xd2\x6a\x8a\x1e\xc0\xa6\x39\x92\x62\xfc\xb1\x18\xcd\x0e\x82\xd8\x71\xa7\x43\x6a\x32\xb5\xbf\x72\x13\xc0\x18\x7f\xb0\xe7\x9c\x65\x6c\x3a\x68\x2c\xab\x36\xa0\x5e\xab\x6a\x35\x7b\x89\xe6\x28\xcf\x82\x20\xdb\xd1\x21\xb8\x1b\x84\x80\xce\xe0\x48\x70\x46\xea\x28\x03\x73\x3f\x91\x9f\x6c\x7d\x83\x75\x5e\xbd\xd3\xf2\x52\xde\xba\x9e\xc8\xd6\x4a\x3f\xab\xf4\x1a\x4e\x63\x3b\x59\xfd\xd8\x83\x2a\xd7\xde\x26\xae\xa4\x11\xda\xd5\x80\xb4\xa4\xe3\x63\xdf\xe8\x97\x40\xe8\x9e\x8f\x4a\x72\x8b\x6f\x02\x70\xbc\x1e\x29\x10\x3b\x5f\x1b\xf5\x83\x2b\x82\x0e\x0f\x95\x42\x33\x6d\x40\x50\xfb\xfe\xaa\x95\x69\xc7\x46\x87\x17\x63\xa3\xb8\xfb\xae\xb0\xae\xab\xa4\x22\x87\x0a\x6f\x83\x1b\x9d\xf0\x58\xad\x6f\x04\xfc\x14\x55\x84\xa4\x52\x4d\xb8\x26\x5c\x8d\xb9\x69\x76\xb0\x75\xe1\xa8\x43\xa7\x20\xe3\x49\xe2\x63\x91\x90\x52\x66\x47\x8e\xd5\x80\x65\xc6\x9d\x82\xc1\x5e\x5f\x23\xc0\x76\x10\xde\x25\xf5\x5e\x2e\x70\x1f\xca\xd7\x44\x93\x07\xe6\x4c\x93\xdd\xe0\x5c\xc2\x96\x68\x8b\xcc\x80\x27\x7f\xbe\x47\x30\xc8\x06\x47\x09\x4d\xd1\xd4\xcd\xed\xa0\xdf\xe7\x86\xbb\x61\x19\xc8\xdc\x79\x24\xdc\x5e\x06\xaa\x0c\x78\xb9\x50\xe0\x71\x6a\x87\x72\xe8\xd3\x87\xce\x01\x52\xd5\x97\x7b\x1d\x17\x92\xb0\x40\xa4\xe5\xd1\x46\x50\x76\x43\x50\x9c\x51\xa2\x7d\x15\xc4\x0d\xbb\xc0\xb9\x4a\x89\x81\xa4\xbe\xb7\x32\xa7\x66\x73\x14\x6b\x8a\x20\xe1\x1c\x38\xd3\x59\x48\xf1\x13\xa7\xc0\x89\x15\xfd\xbd\x75\x6f\xc9\xbe\x27\x8c\xe7\x08\x09\xa1\x93\x30\x3d\xe0\xc8\xa4\x60\x46\x5a\xe1\x24\x6c\xc8\x8c\x3c\x27\xcd\xb0\x25\x89\x27\xba\x4a\x26\x89\xa9\xbd\xf8\x59\x17\xeb\x22\xcf\x2c\xe5\x47\x5c\x36\xce\x9b\x3d\x43\x6d\xaa\x2e\x55\xaa\xfa\x57\x1f\x66\x5f\x26\x3b\xff\xd0\xcd\xe2\xce\xaa\xab\xea\x84\x79\x25\xbc\x63\x39\x5c\x1a\x82\x89\xd5\xd9\x8c\x38\xb2\x18\x82\x2e\x20\xae\xdd\xcb\xf7\xf2\x2f\x6a\x85\xc2\xf4\x89\x92\x9c\x55\xa5\xc9\x12\xa6\xa0\x52\x54\xf3\x08\x59\xa5\x37\x86\x45\xb1\x46\x8b\xc6\x2a\x53\xc6\x8b\x20\x25\xc3\x13\x13\xa9\x7c\x9a\x31\xe0\x72\xd6\x56\x9c\x50\x18\x20\xf6\xad\x86\xd6\x06\x09\x13\x66\xf6\x19\xd7\xd0\x2c\x0a\x61\x0f\x08\x62\x1c\x11\x91\xbb\xd7\x88\xa6\xfb\x0d\x9f\x6e\x7e\x0d\x6b\x0a\xad\x8a\xa2\xfb\x0d\xb6\x1a\x6f\x75\xfe\x0d\x55\x5b\x1b\xee\x9e\xec\xde\xd2\x79\xeb\xb5\xa9\x8c\x4e\x55\xee\x3d\x2f\xcb\x20\x93\xee\xbb\x21\x37\x5c\xcf\xf6\xa9\xd8\x90\x2d\x50\xbd\x04\x1d\xb0\xd6\x54\x89\x54\xcb\xef\xf0\xf8\x0f\x51\xb7\xfe\xfd\x05\xa6\x48\xb6\x14\x86\x04\x1f\x39\xc7\xd6\xf2\x29\x7a\x07\xe8\x90\xef\x44\xd8\x65\xca\x77\x86\x0e\xfd\xeb\x1c\xe5\x6d\x91\x09\xaf\x3e\xb4\xbd\xd1\xba\xb5\xd5\x36\xd8\xc5\x93\x57\x35\x96\x9b\x7f\xd9\xa6\x0d\xb7\x65\x6d\xfd\x1c\x31\x86\xd0\x63\x50\xeb\x37\xb3\xde\xbf\x01\x87\x46\x1b\x14\x56\x18\xaa\xa9\x16\x40\xa1\x90\xbb\x33\xff\x1f\x48\xf5\xab\xaf\xeb\x9f\xb7\x06\xeb\xaf\x48\xbc\x5f\x2a\x94\x54\x57\xe7\xfa\x80\xbb\xa0\xef\xc0\x67\x6f\xec\x8a\x51\xa2\xb3\xba\xa2\xa6\xfa\xed\x8a\x57\x8d\x8a\xfe\x31\x5d\xc7\x25\xe3\x5d\x3b\x97\x25\x83\xef\x12\xd5\x1c\xdb\xfe\x34\x86\x64\x96\x6f\x2e\xfb\xb5\x8f\xeb\x10\xbf\x21\x99\xd8\x25\x1e\x0c\x5a\x1b\xd1\xad\xf9\x82\xb8\x7f\xf7\xc1\x51\xe1\xb9\xee\xfc\xbd\x52\x69\xb4\xc0\x05\x09\xbb\x4f\x07\xcd\x73\x63\xdd\xf1\x27\x63\xd3\xf1\xdf\xf0\x8f\x3e\x20\x2b\xf4\x14\xe7\xd1\xae\xf2\x8f\xfe\x91\x58\xf5\xf1\xd7\xb6\x67\x9f\x01\x49\x75\x83\xb6\x93\x68\xb7\xdd\xfd\x84\xc9\x2b\xff\xb6\xcf\xca\x86\x07\x72\xcd\xe7\x5d\x13\x77\x04\x56\xdd\xbf\xe5\xe7\x7a\xab\x97\xd5\xff\x02\x00\x00\xff\xff\xee\x72\x8c\xda\x18\x3d\x00\x00") func dataConfig_schema_v34JsonBytes() ([]byte, error) { return bindataRead( diff --git a/components/cli/cli/compose/schema/data/config_schema_v3.4.json b/components/cli/cli/compose/schema/data/config_schema_v3.4.json index 5a110a8880..412f505d2b 100644 --- a/components/cli/cli/compose/schema/data/config_schema_v3.4.json +++ b/components/cli/cli/compose/schema/data/config_schema_v3.4.json @@ -64,6 +64,7 @@ } }, + "patternProperties": {"^x-": {}}, "additionalProperties": false, "definitions": { diff --git a/components/cli/cli/compose/schema/schema_test.go b/components/cli/cli/compose/schema/schema_test.go index f293fe7f68..6a761fddef 100644 --- a/components/cli/cli/compose/schema/schema_test.go +++ b/components/cli/cli/compose/schema/schema_test.go @@ -36,6 +36,16 @@ func TestValidateUndefinedTopLevelOption(t *testing.T) { assert.Contains(t, err.Error(), "Additional property helicopters is not allowed") } +func TestValidateAllowsXTopLevelFields(t *testing.T) { + config := dict{ + "version": "3.4", + "x-extra-stuff": dict{}, + } + + err := Validate(config, "3.4") + assert.NoError(t, err) +} + func TestValidateInvalidVersion(t *testing.T) { config := dict{ "version": "2.1", From cd24988c20fc94a346ba7ef081173d8057c7ccc4 Mon Sep 17 00:00:00 2001 From: Marco Mariani Date: Tue, 22 Aug 2017 17:41:12 +0200 Subject: [PATCH 34/47] support --compose-file - as stdin Signed-off-by: Marco Mariani Upstream-commit: 3a0b967c05a589850b4061fbb6036251628c93aa Component: cli --- .../cli/command/stack/deploy_composefile.go | 36 ++++++++++++++----- .../command/stack/deploy_composefile_test.go | 23 ++++++++++-- .../reference/commandline/stack_deploy.md | 17 +++++++++ 3 files changed, 65 insertions(+), 11 deletions(-) diff --git a/components/cli/cli/command/stack/deploy_composefile.go b/components/cli/cli/command/stack/deploy_composefile.go index 16d583ed99..e511a6f127 100644 --- a/components/cli/cli/command/stack/deploy_composefile.go +++ b/components/cli/cli/command/stack/deploy_composefile.go @@ -2,6 +2,7 @@ package stack import ( "fmt" + "io" "io/ioutil" "os" "path/filepath" @@ -22,7 +23,7 @@ import ( ) func deployCompose(ctx context.Context, dockerCli command.Cli, opts deployOptions) error { - configDetails, err := getConfigDetails(opts.composefile) + configDetails, err := getConfigDetails(opts.composefile, dockerCli.In()) if err != nil { return err } @@ -118,16 +119,24 @@ func propertyWarnings(properties map[string]string) string { return strings.Join(msgs, "\n\n") } -func getConfigDetails(composefile string) (composetypes.ConfigDetails, error) { +func getConfigDetails(composefile string, stdin io.Reader) (composetypes.ConfigDetails, error) { var details composetypes.ConfigDetails - absPath, err := filepath.Abs(composefile) - if err != nil { - return details, err + if composefile == "-" { + workingDir, err := os.Getwd() + if err != nil { + return details, err + } + details.WorkingDir = workingDir + } else { + absPath, err := filepath.Abs(composefile) + if err != nil { + return details, err + } + details.WorkingDir = filepath.Dir(absPath) } - details.WorkingDir = filepath.Dir(absPath) - configFile, err := getConfigFile(composefile) + configFile, err := getConfigFile(composefile, stdin) if err != nil { return details, err } @@ -150,15 +159,24 @@ func buildEnvironment(env []string) (map[string]string, error) { return result, nil } -func getConfigFile(filename string) (*composetypes.ConfigFile, error) { - bytes, err := ioutil.ReadFile(filename) +func getConfigFile(filename string, stdin io.Reader) (*composetypes.ConfigFile, error) { + var bytes []byte + var err error + + if filename == "-" { + bytes, err = ioutil.ReadAll(stdin) + } else { + bytes, err = ioutil.ReadFile(filename) + } if err != nil { return nil, err } + config, err := loader.ParseYAML(bytes) if err != nil { return nil, err } + return &composetypes.ConfigFile{ Filename: filename, Config: config, diff --git a/components/cli/cli/command/stack/deploy_composefile_test.go b/components/cli/cli/command/stack/deploy_composefile_test.go index 8d09ab056c..2e6906f69d 100644 --- a/components/cli/cli/command/stack/deploy_composefile_test.go +++ b/components/cli/cli/command/stack/deploy_composefile_test.go @@ -3,6 +3,7 @@ package stack import ( "os" "path/filepath" + "strings" "testing" "github.com/docker/cli/cli/internal/test/network" @@ -25,10 +26,28 @@ services: file := fs.NewFile(t, "test-get-config-details", fs.WithContent(content)) defer file.Remove() - details, err := getConfigDetails(file.Path()) + details, err := getConfigDetails(file.Path(), nil) require.NoError(t, err) assert.Equal(t, filepath.Dir(file.Path()), details.WorkingDir) - assert.Len(t, details.ConfigFiles, 1) + require.Len(t, details.ConfigFiles, 1) + assert.Equal(t, "3.0", details.ConfigFiles[0].Config["version"]) + assert.Len(t, details.Environment, len(os.Environ())) +} + +func TestGetConfigDetailsStdin(t *testing.T) { + content := ` +version: "3.0" +services: + foo: + image: alpine:3.5 +` + details, err := getConfigDetails("-", strings.NewReader(content)) + require.NoError(t, err) + cwd, err := os.Getwd() + require.NoError(t, err) + assert.Equal(t, cwd, details.WorkingDir) + require.Len(t, details.ConfigFiles, 1) + assert.Equal(t, "3.0", details.ConfigFiles[0].Config["version"]) assert.Len(t, details.Environment, len(os.Environ())) } diff --git a/components/cli/docs/reference/commandline/stack_deploy.md b/components/cli/docs/reference/commandline/stack_deploy.md index dd9a4cd65c..15feaa8519 100644 --- a/components/cli/docs/reference/commandline/stack_deploy.md +++ b/components/cli/docs/reference/commandline/stack_deploy.md @@ -57,6 +57,23 @@ Creating service vossibility_ghollector Creating service vossibility_lookupd ``` +The Compose file can also be provided as standard input with `--compose-file -`: + +```bash +$ cat docker-compose.yml | docker stack deploy --compose-file - vossibility + +Ignoring unsupported options: links + +Creating network vossibility_vossibility +Creating network vossibility_default +Creating service vossibility_nsqd +Creating service vossibility_logstash +Creating service vossibility_elasticsearch +Creating service vossibility_kibana +Creating service vossibility_ghollector +Creating service vossibility_lookupd +``` + Only a single Compose file is accepted. If your configuration is split between multiple Compose files, e.g. a base configuration and environment-specific overrides, you can combine these by passing them to `docker-compose config` with the `-f` option From 93c266f248b1ceeb3e780fad54b57e43e4d95b6b Mon Sep 17 00:00:00 2001 From: Boaz Shuster Date: Tue, 15 Aug 2017 13:58:49 +0300 Subject: [PATCH 35/47] Add --format to docker-search Signed-off-by: Jeremy Chambers Signed-off-by: Boaz Shuster Upstream-commit: 88cc47ad5cd051fe89f66aa6fdc085c617c0792b Component: cli --- .../cli/cli/command/formatter/search.go | 104 +++++++ .../cli/cli/command/formatter/search_test.go | 284 ++++++++++++++++++ components/cli/cli/command/registry/search.go | 37 +-- .../cli/docs/reference/commandline/search.md | 56 ++++ 4 files changed, 452 insertions(+), 29 deletions(-) create mode 100644 components/cli/cli/command/formatter/search.go create mode 100644 components/cli/cli/command/formatter/search_test.go diff --git a/components/cli/cli/command/formatter/search.go b/components/cli/cli/command/formatter/search.go new file mode 100644 index 0000000000..c19318a831 --- /dev/null +++ b/components/cli/cli/command/formatter/search.go @@ -0,0 +1,104 @@ +package formatter + +import ( + "strconv" + "strings" + + registry "github.com/docker/docker/api/types/registry" + "github.com/docker/docker/pkg/stringutils" +) + +const ( + defaultSearchTableFormat = "table {{.Name}}\t{{.Description}}\t{{.StarCount}}\t{{.IsOfficial}}\t{{.IsAutomated}}" + + starsHeader = "STARS" + officialHeader = "OFFICIAL" + automatedHeader = "AUTOMATED" +) + +// NewSearchFormat returns a Format for rendering using a network Context +func NewSearchFormat(source string) Format { + switch source { + case "": + return defaultSearchTableFormat + case TableFormatKey: + return defaultSearchTableFormat + } + return Format(source) +} + +// SearchWrite writes the context +func SearchWrite(ctx Context, results []registry.SearchResult, auto bool, stars int) error { + render := func(format func(subContext subContext) error) error { + for _, result := range results { + // --automated and -s, --stars are deprecated since Docker 1.12 + if (auto && !result.IsAutomated) || (stars > result.StarCount) { + continue + } + searchCtx := &searchContext{trunc: ctx.Trunc, s: result} + if err := format(searchCtx); err != nil { + return err + } + } + return nil + } + searchCtx := searchContext{} + searchCtx.header = map[string]string{ + "Name": nameHeader, + "Description": descriptionHeader, + "StarCount": starsHeader, + "IsOfficial": officialHeader, + "IsAutomated": automatedHeader, + } + return ctx.Write(&searchCtx, render) +} + +type searchContext struct { + HeaderContext + trunc bool + json bool + s registry.SearchResult +} + +func (c *searchContext) MarshalJSON() ([]byte, error) { + c.json = true + return marshalJSON(c) +} + +func (c *searchContext) Name() string { + return c.s.Name +} + +func (c *searchContext) Description() string { + desc := strings.Replace(c.s.Description, "\n", " ", -1) + desc = strings.Replace(desc, "\r", " ", -1) + if c.trunc { + desc = stringutils.Ellipsis(desc, 45) + } + return desc +} + +func (c *searchContext) StarCount() string { + return strconv.Itoa(c.s.StarCount) +} + +func (c *searchContext) formatBool(value bool) string { + switch { + case value && c.json: + return "true" + case value: + return "[OK]" + case c.json: + return "false" + default: + return "" + } +} + +func (c *searchContext) IsOfficial() string { + return c.formatBool(c.s.IsOfficial) +} + +func (c *searchContext) IsAutomated() string { + return c.formatBool(c.s.IsAutomated) +} diff --git a/components/cli/cli/command/formatter/search_test.go b/components/cli/cli/command/formatter/search_test.go new file mode 100644 index 0000000000..4fa96f8ae8 --- /dev/null +++ b/components/cli/cli/command/formatter/search_test.go @@ -0,0 +1,284 @@ +package formatter + +import ( + "bytes" + "encoding/json" + "strings" + "testing" + + registrytypes "github.com/docker/docker/api/types/registry" + "github.com/docker/docker/pkg/stringutils" + "github.com/stretchr/testify/assert" +) + +func TestSearchContext(t *testing.T) { + name := "nginx" + starCount := 5000 + + var ctx searchContext + cases := []struct { + searchCtx searchContext + expValue string + call func() string + }{ + {searchContext{ + s: registrytypes.SearchResult{Name: name}, + }, name, ctx.Name}, + {searchContext{ + s: registrytypes.SearchResult{StarCount: starCount}, + }, "5000", ctx.StarCount}, + {searchContext{ + s: registrytypes.SearchResult{IsOfficial: true}, + }, "[OK]", ctx.IsOfficial}, + {searchContext{ + s: registrytypes.SearchResult{IsOfficial: false}, + }, "", ctx.IsOfficial}, + {searchContext{ + s: registrytypes.SearchResult{IsAutomated: true}, + }, "[OK]", ctx.IsAutomated}, + {searchContext{ + s: registrytypes.SearchResult{IsAutomated: false}, + }, "", ctx.IsAutomated}, + } + + for _, c := range cases { + ctx = c.searchCtx + v := c.call() + if strings.Contains(v, ",") { + compareMultipleValues(t, v, c.expValue) + } else if v != c.expValue { + t.Fatalf("Expected %s, was %s\n", c.expValue, v) + } + } +} + +func TestSearchContextDescription(t *testing.T) { + shortDescription := "Official build of Nginx." + longDescription := "Automated Nginx reverse proxy for docker containers" + descriptionWReturns := "Automated\nNginx reverse\rproxy\rfor docker\ncontainers" + + var ctx searchContext + cases := []struct { + searchCtx searchContext + expValue string + call func() string + }{ + {searchContext{ + s: registrytypes.SearchResult{Description: shortDescription}, + trunc: true, + }, shortDescription, ctx.Description}, + {searchContext{ + s: registrytypes.SearchResult{Description: shortDescription}, + trunc: false, + }, shortDescription, ctx.Description}, + {searchContext{ + s: registrytypes.SearchResult{Description: longDescription}, + trunc: false, + }, longDescription, ctx.Description}, + {searchContext{ + s: registrytypes.SearchResult{Description: longDescription}, + trunc: true, + }, stringutils.Ellipsis(longDescription, 45), ctx.Description}, + {searchContext{ + s: registrytypes.SearchResult{Description: descriptionWReturns}, + trunc: false, + }, longDescription, ctx.Description}, + {searchContext{ + s: registrytypes.SearchResult{Description: descriptionWReturns}, + trunc: true, + }, stringutils.Ellipsis(longDescription, 45), ctx.Description}, + } + + for _, c := range cases { + ctx = c.searchCtx + v := c.call() + if strings.Contains(v, ",") { + compareMultipleValues(t, v, c.expValue) + } else if v != c.expValue { + t.Fatalf("Expected %s, was %s\n", c.expValue, v) + } + } +} + +func TestSearchContextWrite(t *testing.T) { + cases := []struct { + context Context + expected string + }{ + + // Errors + { + Context{Format: "{{InvalidFunction}}"}, + `Template parsing error: template: :1: function "InvalidFunction" not defined +`, + }, + { + Context{Format: "{{nil}}"}, + `Template parsing error: template: :1:2: executing "" at : nil is not a command +`, + }, + // Table format + { + Context{Format: NewSearchFormat("table")}, + `NAME DESCRIPTION STARS OFFICIAL AUTOMATED +result1 Official build 5000 [OK] +result2 Not official 5 [OK] +`, + }, + { + Context{Format: NewSearchFormat("table {{.Name}}")}, + `NAME +result1 +result2 +`, + }, + // Custom Format + { + Context{Format: NewSearchFormat("{{.Name}}")}, + `result1 +result2 +`, + }, + // Custom Format with CreatedAt + { + Context{Format: NewSearchFormat("{{.Name}} {{.StarCount}}")}, + `result1 5000 +result2 5 +`, + }, + } + + for _, testcase := range cases { + results := []registrytypes.SearchResult{ + {Name: "result1", Description: "Official build", StarCount: 5000, IsOfficial: true, IsAutomated: false}, + {Name: "result2", Description: "Not official", StarCount: 5, IsOfficial: false, IsAutomated: true}, + } + out := bytes.NewBufferString("") + testcase.context.Output = out + err := SearchWrite(testcase.context, results, false, 0) + if err != nil { + assert.Error(t, err, testcase.expected) + } else { + assert.Equal(t, out.String(), testcase.expected) + } + } +} + +func TestSearchContextWriteAutomated(t *testing.T) { + cases := []struct { + context Context + expected string + }{ + + // Table format + { + Context{Format: NewSearchFormat("table")}, + `NAME DESCRIPTION STARS OFFICIAL AUTOMATED +result2 Not official 5 [OK] +`, + }, + { + Context{Format: NewSearchFormat("table {{.Name}}")}, + `NAME +result2 +`, + }, + } + + for _, testcase := range cases { + results := []registrytypes.SearchResult{ + {Name: "result1", Description: "Official build", StarCount: 5000, IsOfficial: true, IsAutomated: false}, + {Name: "result2", Description: "Not official", StarCount: 5, IsOfficial: false, IsAutomated: true}, + } + out := bytes.NewBufferString("") + testcase.context.Output = out + err := SearchWrite(testcase.context, results, true, 0) + if err != nil { + assert.Error(t, err, testcase.expected) + } else { + assert.Equal(t, out.String(), testcase.expected) + } + } +} + +func TestSearchContextWriteStars(t *testing.T) { + cases := []struct { + context Context + expected string + }{ + + // Table format + { + Context{Format: NewSearchFormat("table")}, + `NAME DESCRIPTION STARS OFFICIAL AUTOMATED +result1 Official build 5000 [OK] +`, + }, + { + Context{Format: NewSearchFormat("table {{.Name}}")}, + `NAME +result1 +`, + }, + } + + for _, testcase := range cases { + results := []registrytypes.SearchResult{ + {Name: "result1", Description: "Official build", StarCount: 5000, IsOfficial: true, IsAutomated: false}, + {Name: "result2", Description: "Not official", StarCount: 5, IsOfficial: false, IsAutomated: true}, + } + out := bytes.NewBufferString("") + testcase.context.Output = out + err := SearchWrite(testcase.context, results, false, 6) + if err != nil { + assert.Error(t, err, testcase.expected) + } else { + assert.Equal(t, out.String(), testcase.expected) + } + } +} + +func TestSearchContextWriteJSON(t *testing.T) { + results := []registrytypes.SearchResult{ + {Name: "result1", Description: "Official build", StarCount: 5000, IsOfficial: true, IsAutomated: false}, + {Name: "result2", Description: "Not official", StarCount: 5, IsOfficial: false, IsAutomated: true}, + } + expectedJSONs := []map[string]interface{}{ + {"Name": "result1", "Description": "Official build", "StarCount": "5000", "IsOfficial": "true", "IsAutomated": "false"}, + {"Name": "result2", "Description": "Not official", "StarCount": "5", "IsOfficial": "false", "IsAutomated": "true"}, + } + + out := bytes.NewBufferString("") + err := SearchWrite(Context{Format: "{{json .}}", Output: out}, results, false, 0) + if err != nil { + t.Fatal(err) + } + for i, line := range strings.Split(strings.TrimSpace(out.String()), "\n") { + t.Logf("Output: line %d: %s", i, line) + var m map[string]interface{} + if err := json.Unmarshal([]byte(line), &m); err != nil { + t.Fatal(err) + } + assert.Equal(t, m, expectedJSONs[i]) + } +} + +func TestSearchContextWriteJSONField(t *testing.T) { + results := []registrytypes.SearchResult{ + {Name: "result1", Description: "Official build", StarCount: 5000, IsOfficial: true, IsAutomated: false}, + {Name: "result2", Description: "Not official", StarCount: 5, IsOfficial: false, IsAutomated: true}, + } + out := bytes.NewBufferString("") + err := SearchWrite(Context{Format: "{{json .Name}}", Output: out}, results, false, 0) + if err != nil { + t.Fatal(err) + } + for i, line := range strings.Split(strings.TrimSpace(out.String()), "\n") { + t.Logf("Output: line %d: %s", i, line) + var s string + if err := json.Unmarshal([]byte(line), &s); err != nil { + t.Fatal(err) + } + assert.Equal(t, s, results[i].Name) + } +} diff --git a/components/cli/cli/command/registry/search.go b/components/cli/cli/command/registry/search.go index 443c9a3fa8..49ac0f43cf 100644 --- a/components/cli/cli/command/registry/search.go +++ b/components/cli/cli/command/registry/search.go @@ -1,23 +1,21 @@ package registry import ( - "fmt" "sort" - "strings" - "text/tabwriter" "github.com/docker/cli/cli" "github.com/docker/cli/cli/command" + "github.com/docker/cli/cli/command/formatter" "github.com/docker/cli/opts" "github.com/docker/docker/api/types" registrytypes "github.com/docker/docker/api/types/registry" - "github.com/docker/docker/pkg/stringutils" "github.com/docker/docker/registry" "github.com/spf13/cobra" "golang.org/x/net/context" ) type searchOptions struct { + format string term string noTrunc bool limit int @@ -47,6 +45,7 @@ func NewSearchCommand(dockerCli command.Cli) *cobra.Command { flags.BoolVar(&options.noTrunc, "no-trunc", false, "Don't truncate output") flags.VarP(&options.filter, "filter", "f", "Filter output based on conditions provided") flags.IntVar(&options.limit, "limit", registry.DefaultSearchLimit, "Max number of search results") + flags.StringVar(&options.format, "format", "", "Pretty-print search using a Go template") flags.BoolVar(&options.automated, "automated", false, "Only show automated builds") flags.UintVarP(&options.stars, "stars", "s", 0, "Only displays with at least x stars") @@ -89,32 +88,12 @@ func runSearch(dockerCli command.Cli, options searchOptions) error { results := searchResultsByStars(unorderedResults) sort.Sort(results) - - w := tabwriter.NewWriter(dockerCli.Out(), 10, 1, 3, ' ', 0) - fmt.Fprintf(w, "NAME\tDESCRIPTION\tSTARS\tOFFICIAL\tAUTOMATED\n") - for _, res := range results { - // --automated and -s, --stars are deprecated since Docker 1.12 - if (options.automated && !res.IsAutomated) || (int(options.stars) > res.StarCount) { - continue - } - desc := strings.Replace(res.Description, "\n", " ", -1) - desc = strings.Replace(desc, "\r", " ", -1) - if !options.noTrunc { - desc = stringutils.Ellipsis(desc, 45) - } - fmt.Fprintf(w, "%s\t%s\t%d\t", res.Name, desc, res.StarCount) - if res.IsOfficial { - fmt.Fprint(w, "[OK]") - - } - fmt.Fprint(w, "\t") - if res.IsAutomated { - fmt.Fprint(w, "[OK]") - } - fmt.Fprint(w, "\n") + searchCtx := formatter.Context{ + Output: dockerCli.Out(), + Format: formatter.NewSearchFormat(options.format), + Trunc: !options.noTrunc, } - w.Flush() - return nil + return formatter.SearchWrite(searchCtx, results, options.automated, int(options.stars)) } // searchResultsByStars sorts search results in descending order by number of stars. diff --git a/components/cli/docs/reference/commandline/search.md b/components/cli/docs/reference/commandline/search.md index 0482dbb143..c33521e8da 100644 --- a/components/cli/docs/reference/commandline/search.md +++ b/components/cli/docs/reference/commandline/search.md @@ -25,6 +25,7 @@ Options: - is-automated=(true|false) - is-official=(true|false) - stars= - image has at least 'number' stars + --format string Pretty-print images using a Go template --help Print usage --limit int Max number of search results (default 25) --no-trunc Don't truncate output @@ -144,3 +145,58 @@ NAME DESCRIPTION STARS O progrium/busybox 50 [OK] radial/busyboxplus Full-chain, Internet enabled, busybox made... 8 [OK] ``` + +### Format the output + +The formatting option (`--format`) pretty-prints search output +using a Go template. + +Valid placeholders for the Go template are: + +| Placeholder | Description | +| -------------- | --------------------------------- | +| `.Name` | Image Name | +| `.Description` | Image description | +| `.StarCount` | Number of stars for the image | +| `.IsOfficial` | "OK" if image is official | +| `.IsAutomated` | "OK" if image build was automated | + +When you use the `--format` option, the `search` command will +output the data exactly as the template declares. If you use the +`table` directive, column headers are included as well. + +The following example uses a template without headers and outputs the +`Name` and `StarCount` entries separated by a colon for all images: + +```bash +{% raw %} +$ docker search --format "{{.Name}}: {{.StarCount}}" nginx + +nginx: 5441 +jwilder/nginx-proxy: 953 +richarvey/nginx-php-fpm: 353 +million12/nginx-php: 75 +webdevops/php-nginx: 70 +h3nrik/nginx-ldap: 35 +bitnami/nginx: 23 +evild/alpine-nginx: 14 +million12/nginx: 9 +maxexcloo/nginx: 7 +{% endraw %} +``` + +This example outputs a table format: + +```bash +{% raw %} +$ docker search --format "table {{.Name}}\t{{.IsAutomated}}\t{{.IsOfficial}}" nginx + +NAME AUTOMATED OFFICIAL +nginx [OK] +jwilder/nginx-proxy [OK] +richarvey/nginx-php-fpm [OK] +jrcs/letsencrypt-nginx-proxy-companion [OK] +million12/nginx-php [OK] +webdevops/php-nginx [OK] +{% endraw %} +``` From 881ab6b17fdfe52f9a953d1b8b71116ce62c972d Mon Sep 17 00:00:00 2001 From: Harald Albers Date: Wed, 23 Aug 2017 12:52:56 +0200 Subject: [PATCH 36/47] Remove bash completion for `stack ps --all|-a` This option was removed in https://github.com/moby/moby/pull/28885. Bash completion was only updated for `service ps`, though. See https://github.com/moby/moby/pull/29716 for the corresponding docs change. Signed-off-by: Harald Albers Upstream-commit: 328f4fbf060bb2728b2320839d000c66bb6002f4 Component: cli --- components/cli/contrib/completion/bash/docker | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/cli/contrib/completion/bash/docker b/components/cli/contrib/completion/bash/docker index c0f92afca5..31cb03ec47 100644 --- a/components/cli/contrib/completion/bash/docker +++ b/components/cli/contrib/completion/bash/docker @@ -4407,7 +4407,7 @@ _docker_stack_ps() { case "$cur" in -*) - COMPREPLY=( $( compgen -W "--all -a --filter -f --format --help --no-resolve --no-trunc --quiet -q" -- "$cur" ) ) + COMPREPLY=( $( compgen -W "--filter -f --format --help --no-resolve --no-trunc --quiet -q" -- "$cur" ) ) ;; *) local counter=$(__docker_pos_first_nonflag '--filter|-f') From 1d2c919b0295f5bf2a8c983338d9f4df33451fea Mon Sep 17 00:00:00 2001 From: Rubens Figueiredo Date: Wed, 23 Aug 2017 22:33:03 +0100 Subject: [PATCH 37/47] Added docker documentation for Expose Signed-off-by: Rubens Figueiredo Upstream-commit: dd95731a21534040cc130348255fb160f08efab9 Component: cli --- components/cli/docs/reference/.builder.md.swp | Bin 0 -> 16384 bytes components/cli/docs/reference/builder.md | 82 ++++++++++-------- 2 files changed, 44 insertions(+), 38 deletions(-) create mode 100644 components/cli/docs/reference/.builder.md.swp diff --git a/components/cli/docs/reference/.builder.md.swp b/components/cli/docs/reference/.builder.md.swp new file mode 100644 index 0000000000000000000000000000000000000000..c551264cda39b0eb72fd1c3657b064238471396a GIT binary patch literal 16384 zcmeHOS&SS<8LlJ{Ldbz~2q{s-?{Uc5)=tkJUfa8hSMsr&80~sj-nAX$buu;GH9MW{ z>2CVi*-1ip$rAzciWKq^o(KUUke_)0Atm9BOW}Co1qVn%E{2 zsmtE?c)_sdsm)pxt1yl7#8ovn@M~V=rnN*hRiZ*%YUF<4sl;h}mzuexl@=&1aOD=b zQA|#Z>!rT4vV(5D<>ZwQE$=KXP+Fk0Kxu)}0;L5?3zQZpEl^tEf8GLFe4F?(w7A-8 zvTDDt8v6dweu|2r_%81Iz|y~D$2~VR{(Vbdx7SDPz+(J+mcC}`Umv2sYw60;Um2qR z)6$Py`jS;>L-fB}`dLf=aESglOFv=hU%1BnDEPl)>4p5y57FPY^p+ie z-Ny#Uzh&vCEj=EhziH{qmj2Tr`Wu$MY3ZN&_#pqkT6%8jUmK#oZs`wN`qkGCj(^S4 z3%}Qg=&xFOq2Ku-x;2NGxBTz=#2|lrx%?_EP+Fk0Kxu)}0;L5?3zQZpEl^sZv_NTr z|B?kHp0Do&@29ws#q0&W4W0seB65EpW@;;=EEGs zqGx#mZDmMG>*AXm({7l_E%Mn8Zj>a-&1S@5)r=CQ8U2SA93?-aSS8@o#>*_QAYH6d z+Ujno)F?GG?unu4|g#mg^h?@W3|1M8#3+XHnuS*r*An`c}=whQOueXAwEHjK9*{ zb(Qkc8F2Gmdf}_B6?S10_z=+zyClSMO=&mHRNE0YNNgxN#6so>YgV9MZPuw7K&pZK_dHTW*kh$N`Xs*ON!Z3>-TRc-7O({USET z2U#SbC?cXS35^m&0%O@maE}s8aAaxu46N2mR1U31_?u<4p3(ISk{<1%u>!gI?`G) zfk_gd!`N^)aUf>*>^Uuy5UFs_o*Bdrg;Ay@*TdND+m=KG)ob-pk|tl*mk+JpU+2G& zRa^;eky8v;mfY$44HH2+EU3aMaQh*ojwlSe+p4A%Vs#?q*z8(6&d*R)xG-+Y$!i3z zCwO zPg2+`=nM%7 zCZ9NtqcigrZcwz(nHs0XkKCY;{fdaw2^Z7B2ka;7Kf zW?zJj-UmV~1-;Bo-qhB#f?_hd57F2sq|Rf=fQ~T99xKV@Hr|)*bci?2z<8#RfteK( zcM+;)Au+!|K+;~MV+|mPB<-;wx5x0&rbomUfe78%rm4z!RoX}tp|ic2~<+*zCi48lALPK{2ZOEOeJsRnJ*Nr*D0dmIx^7MY-`Kzq>3%wK}VF z6!I^oZ?M}R#&)hele+Nd7jw9lkAQrDvdfti4kPd_M*{TX_+o!X5T8%+y|bR-js4w^ zyh2(<5nRzp{4B$%(q>anHT@6=9PDb$&7tKy2+U}SeQba)b}tw$MWo}j!6`y|C?(AP zlORmZKE?{!>A|X}h+JoDbHax4SyqRR>8;hCe0utr(c9|aW%zW>TYSrXWW1W=Rn3p|`0Oie2Z={NY0V|Y8bG`#l_DNM#>EbucYa)T& z`Ly*AyLCovsBR}pa15r34iA-#T7IK_?uJ2ZxI`hgUVS>(s|G8nBFsvS`H%-Ty&y^L zp(pkE&_qX97HkMWIo=C+Df7~>i%v%_PQS6Cbo83Ssj{sj6g5Jwe`IVP4C}30Ess+X znV$t}Kms_&zG7d|CgJ-3Rn)^3)XrT0&)Wj^CDi-pfhU0bfX@N910SH?{~7RY;7Q;s zz)|2e)cHRIegL?@I4}lW4O|7hg1Y|#@H9{Xb^vz)w*$8VZ=(m^z;}ShfJcEEa1X#X+5wcG(gLLgN(+=0C@t{+Z-IKfj)QIu4YUmhKh8w? z2u^-z9#czq{W|FI@bL#7i0QHY(%a`w?4R7%G`)vfL*n?v_20hfDR2M&=}EVt_G%g* zpHK7o7~QNG4XrdnUsTuofsgad!Gi~92L=grr%AajG(e+>W{Cw7^Cy-TDR1Oqh8No| z&#zy=9>1pM2T6z7otitba%|~14SvR)aXd2FNsC2e*VYfVtQTxB{SSKSJo0R1YkYh& zbStA&siJwqHIx30LMiU(U*_aiIVa{GSYBG0qp9gJ{4Xt5xFORPRb3j=-PoG&=^-14Zmqwa6{f?j$ zk;Z{E-RXkImAZ3MyK~;mtm`N`b^J)rkL-s+>`N-*qo_i^yqZN(fOZ`k2wNB^-Ikgl z{oh^FRu#oD{4W*`9iCgDqq?Hkb;7}lF7!<$fpQ7KfzDge$YU=dOcA5#9&zz4Q8`!W z6xwr9aaq;&qG*GwIF^w~+`c($Y99X))3UZpOx;2M=^m6K!`lxP#83 z6x}o3yX{q0cuc_0go?6r1d^gK#KQ!XPu!(Pb{MGEi;3{05@Od^?w?ygE3b)OdXAwT zRJ-Vi>yftTqj6_^!ofpN)b5BB4}CY3?zpf1NZLZzx9*y+jK6ip(*<_w3{1dLZy)06 zMvDy6h#Lgj+h~+5_+h@qjY007pg|!6=n(SKNm~l5rGf5(3OD^E3i&Yt9-<{ahXSk; zqs)I>WJJICK}pba$6mXl`cB zl<#Z0{9e=(ZnSNPyv3sQL1xSY@ecVSh`^$=bU;>IxdXv*lw@)59JvG&s*f%lmPLAu# WT8O<`h(kw@((ueqoR0TPCjJFoe5m*U literal 0 HcmV?d00001 diff --git a/components/cli/docs/reference/builder.md b/components/cli/docs/reference/builder.md index cf4f79faea..f7f717d241 100644 --- a/components/cli/docs/reference/builder.md +++ b/components/cli/docs/reference/builder.md @@ -301,9 +301,9 @@ Results in: ---> Running in a2c157f842f5 Volume in drive C has no label. Volume Serial Number is 7E6D-E0F7 - + Directory of c:\ - + 10/05/2016 05:04 PM 1,894 License.txt 10/05/2016 02:22 PM Program Files 10/05/2016 02:14 PM Program Files (x86) @@ -381,7 +381,7 @@ throughout the entire instruction. In other words, in this example: ENV ghi=$abc will result in `def` having a value of `hello`, not `bye`. However, -`ghi` will have a value of `bye` because it is not part of the same instruction +`ghi` will have a value of `bye` because it is not part of the same instruction that set `abc` to `bye`. ## .dockerignore file @@ -415,12 +415,12 @@ temp? This file causes the following build behavior: -| Rule | Behavior | -|----------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| -| `# comment` | Ignored. | -| `*/temp*` | Exclude files and directories whose names start with `temp` in any immediate subdirectory of the root. For example, the plain file `/somedir/temporary.txt` is excluded, as is the directory `/somedir/temp`. | -| `*/*/temp*` | Exclude files and directories starting with `temp` from any subdirectory that is two levels below the root. For example, `/somedir/subdir/temporary.txt` is excluded. | -| `temp?` | Exclude files and directories in the root directory whose names are a one-character extension of `temp`. For example, `/tempa` and `/tempb` are excluded. +| Rule | Behavior | +|:------------|:---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| `# comment` | Ignored. | +| `*/temp*` | Exclude files and directories whose names start with `temp` in any immediate subdirectory of the root. For example, the plain file `/somedir/temporary.txt` is excluded, as is the directory `/somedir/temp`. | +| `*/*/temp*` | Exclude files and directories starting with `temp` from any subdirectory that is two levels below the root. For example, `/somedir/subdir/temporary.txt` is excluded. | +| `temp?` | Exclude files and directories in the root directory whose names are a one-character extension of `temp`. For example, `/tempa` and `/tempb` are excluded. | Matching is done using Go's @@ -493,32 +493,32 @@ Or FROM [@] [AS ] -The `FROM` instruction initializes a new build stage and sets the -[*Base Image*](glossary.md#base-image) for subsequent instructions. As such, a +The `FROM` instruction initializes a new build stage and sets the +[*Base Image*](glossary.md#base-image) for subsequent instructions. As such, a valid `Dockerfile` must start with a `FROM` instruction. The image can be -any valid image – it is especially easy to start by **pulling an image** from +any valid image – it is especially easy to start by **pulling an image** from the [*Public Repositories*](https://docs.docker.com/engine/tutorials/dockerrepos/). - `ARG` is the only instruction that may precede `FROM` in the `Dockerfile`. See [Understand how ARG and FROM interact](#understand-how-arg-and-from-interact). -- `FROM` can appear multiple times within a single `Dockerfile` to +- `FROM` can appear multiple times within a single `Dockerfile` to create multiple images or use one build stage as a dependency for another. - Simply make a note of the last image ID output by the commit before each new + Simply make a note of the last image ID output by the commit before each new `FROM` instruction. Each `FROM` instruction clears any state created by previous instructions. -- Optionally a name can be given to a new build stage by adding `AS name` to the +- Optionally a name can be given to a new build stage by adding `AS name` to the `FROM` instruction. The name can be used in subsequent `FROM` and `COPY --from=` instructions to refer to the image built in this stage. -- The `tag` or `digest` values are optional. If you omit either of them, the +- The `tag` or `digest` values are optional. If you omit either of them, the builder assumes a `latest` tag by default. The builder returns an error if it cannot find the `tag` value. ### Understand how ARG and FROM interact -`FROM` instructions support variables that are declared by any `ARG` +`FROM` instructions support variables that are declared by any `ARG` instructions that occur before the first `FROM`. ```Dockerfile @@ -754,20 +754,26 @@ This will then be visible from `docker inspect` with the other labels. ## EXPOSE - EXPOSE [...] + EXPOSE [/...] The `EXPOSE` instruction informs Docker that the container listens on the -specified network ports at runtime. `EXPOSE` does not make the ports of the -container accessible to the host. To do that, you must use either the `-p` flag -to publish a range of ports or the `-P` flag to publish all of the exposed -ports. You can expose one port number and publish it externally under another -number. +specified network ports at runtime. You can specify whether the port listens on +TCP or UDP, and the default is TCP if the protocol is not specified. + +The `EXPOSE` instruction does not actually publish the port. It functions as a +type of documentation between the person who builds the image and the person who +runs the container, about which ports are intended to be published. To actually +publish the port when running the container, use the `-p` flag on `docker run` +to publish and map one or more ports, or the `-P` flag to publish all exposed +ports and map them to to high-order ports. To set up port redirection on the host system, see [using the -P -flag](run.md#expose-incoming-ports). The Docker network feature supports -creating networks without the need to expose ports within the network, for -detailed information see the [overview of this -feature](https://docs.docker.com/engine/userguide/networking/)). +flag](run.md#expose-incoming-ports). The `docker network` command supports +creating networks for communication among containers without the need to +expose or publish specific ports, because the containers connected to the +network can communicate with each other over any port. For detailed information, +see the +[overview of this feature](https://docs.docker.com/engine/userguide/networking/)). ## ENV @@ -976,9 +982,9 @@ All new files and directories are created with a UID and GID of 0. Optionally `COPY` accepts a flag `--from=` that can be used to set the source location to a previous build stage (created with `FROM .. AS `) -that will be used instead of a build context sent by the user. The flag also -accepts a numeric index assigned for all previous build stages started with -`FROM` instruction. In case a build stage with a specified name can't be found an +that will be used instead of a build context sent by the user. The flag also +accepts a numeric index assigned for all previous build stages started with +`FROM` instruction. In case a build stage with a specified name can't be found an image with the same name is attempted to be used instead. `COPY` obeys the following rules: @@ -1250,7 +1256,7 @@ or for executing an ad-hoc command in a container. The table below shows what command is executed for different `ENTRYPOINT` / `CMD` combinations: | | No ENTRYPOINT | ENTRYPOINT exec_entry p1_entry | ENTRYPOINT ["exec_entry", "p1_entry"] | -|--------------------------------|----------------------------|--------------------------------|------------------------------------------------| +|:-------------------------------|:---------------------------|:-------------------------------|:-----------------------------------------------| | **No CMD** | *error, not allowed* | /bin/sh -c exec_entry p1_entry | exec_entry p1_entry | | **CMD ["exec_cmd", "p1_cmd"]** | exec_cmd p1_cmd | /bin/sh -c exec_entry p1_entry | exec_entry p1_entry exec_cmd p1_cmd | | **CMD ["p1_cmd", "p2_cmd"]** | p1_cmd p2_cmd | /bin/sh -c exec_entry p1_entry | exec_entry p1_entry p1_cmd p2_cmd | @@ -1288,7 +1294,7 @@ Keep the following things in mind about volumes in the `Dockerfile`. - **Volumes on Windows-based containers**: When using Windows-based containers, the destination of a volume inside the container must be one of: - + - a non-existing or empty directory - a drive other than `C:` @@ -1805,16 +1811,16 @@ Resulting in: Removing intermediate container 6fcdb6855ae2 Step 3/5 : RUN New-Item -ItemType Directory C:\Example ---> Running in d0eef8386e97 - - + + Directory: C:\ - - + + Mode LastWriteTime Length Name ---- ------------- ------ ---- d----- 10/28/2016 11:26 AM Example - - + + ---> 3f2fbf1395d9 Removing intermediate container d0eef8386e97 Step 4/5 : ADD Execute-MyCmdlet.ps1 c:\example\ From 3104a37598f89e48de2a8975c092c3d5b3719258 Mon Sep 17 00:00:00 2001 From: Daniel Nephin Date: Thu, 24 Aug 2017 14:37:35 -0400 Subject: [PATCH 38/47] Add TESTING document. Signed-off-by: Daniel Nephin Upstream-commit: ffed6f5ff9eec40c4c3da0c5455d79ccdbab1aa8 Component: cli --- components/cli/TESTING.md | 87 +++++++++++++++++++++++++++++ components/cli/internal/test/doc.go | 2 +- 2 files changed, 88 insertions(+), 1 deletion(-) create mode 100644 components/cli/TESTING.md diff --git a/components/cli/TESTING.md b/components/cli/TESTING.md new file mode 100644 index 0000000000..63bba1d3dc --- /dev/null +++ b/components/cli/TESTING.md @@ -0,0 +1,87 @@ +# Testing + +The following guidelines summarize the testing policy for docker/cli. + +## Unit Test Suite + +All code changes should have unit test coverage. + +Error cases should be tested with unit tests. + +Bug fixes should be covered by new unit tests or additional assertions in +existing unit tests. + +### Details + +The unit test suite follows the standard Go testing convention. Tests are +located in the package directory in `_test.go` files. + +Unit tests should be named using the convention: + +``` +Test +``` + +[Table tests](https://github.com/golang/go/wiki/TableDrivenTests) should be used +where appropriate, but may not be appropriate in all cases. + +Assertions should be made using +[testify/assert](https://godoc.org/github.com/stretchr/testify/assert) and test +requirements should be verified using +[testify/require](https://godoc.org/github.com/stretchr/testify/require). + +Fakes, and testing utilities can be found in +[internal/test](https://godoc.org/github.com/docker/cli/internal/test) and +[gotestyourself](https://godoc.org/github.com/gotestyourself/gotestyourself). + +## End-to-End Test Suite + +The end-to-end test suite tests a cli binary against a real API backend. + +### Guidelines + +Each feature (subcommand) should have a single end-to-end test for +the success case. The test should include all (or most) flags/options supported +by that feature. + +In some rare cases a couple additional end-to-end tests may be written for a +sufficiently complex and critical feature (ex: `container run`, `service +create`, `service update`, and `docker build` may have ~3-5 cases each). + +In some rare cases a sufficiently critical error paths may have a single +end-to-end test case. + +In all other cases the behaviour should be covered by unit tests. + +If a code change adds a new flag, that flag should be added to the existing +"success case" end-to-end test. + +If a code change fixes a bug, that bug fix should be covered either by adding +assertions to the existing end-to-end test, or with one or more unit test. + +### Details + +The end-to-end test suite is located in +[./e2e](https://github.com/docker/cli/tree/master/e2e). Each directory in `e2e` +corresponds to a directory in `cli/command` and contains the tests for that +subcommand. Files in each directory should be named `_test.go` where +command is the basename of the command (ex: the test for `docker stack deploy` +is found in `e2e/stack/deploy_test.go`). + +Tests should be named using the convention: + +``` +Test[] +``` + +where the test case name is only required when there are multiple test cases for +a single command. + +End-to-end test should run the `docker` binary using +[gotestyourself/icmd](https://godoc.org/github.com/gotestyourself/gotestyourself/icmd) +and make assertions about the exit code, stdout, stderr, and local file system. + +Any Docker image or registry operations should use `registry:5000/` +to communicate with the local instance of the Docker registry. To load +additional fixture images to the registry see +[scripts/test/e2e/run](https://github.com/docker/cli/blob/master/scripts/test/e2e/run). diff --git a/components/cli/internal/test/doc.go b/components/cli/internal/test/doc.go index 3a8609716f..342441d533 100644 --- a/components/cli/internal/test/doc.go +++ b/components/cli/internal/test/doc.go @@ -1,5 +1,5 @@ // Package test is a test-only package that can be used by other cli package to write unit test. // -// It as an internal package and cannot be used outside of github.com/docker/cli/cli package. +// It as an internal package and cannot be used outside of github.com/docker/cli package. // package test From 2d72ab2282a343609eb00ec5c3ff9cd71bbffa13 Mon Sep 17 00:00:00 2001 From: Misty Stanley-Jones Date: Thu, 17 Aug 2017 15:37:48 -0700 Subject: [PATCH 39/47] docker update does not work on Windows containers Signed-off-by: Misty Stanley-Jones Upstream-commit: 047d3c23a713c8cdc39017ae9da3c0d4f17e9feb Component: cli --- components/cli/docs/reference/commandline/update.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/components/cli/docs/reference/commandline/update.md b/components/cli/docs/reference/commandline/update.md index bcd83ddda3..9bb1f51aec 100644 --- a/components/cli/docs/reference/commandline/update.md +++ b/components/cli/docs/reference/commandline/update.md @@ -51,6 +51,10 @@ options on a running or a stopped container. On kernel version older than 4.6, you can only update `--kernel-memory` on a stopped container or on a running container with kernel memory initialized. +> **Warning**: The `docker update` and `docker container update` commands are +> not supported for Windows containers. +{: .warning } + ## Examples The following sections illustrate ways to use this command. From 6143a4613aa89e80f2296eb045abb514b9d4d679 Mon Sep 17 00:00:00 2001 From: Ying Li Date: Thu, 24 Aug 2017 15:42:11 -0700 Subject: [PATCH 40/47] Include whether the managers in the swarm are autolocked as part of `docker info`. Signed-off-by: Ying Li Upstream-commit: 3428b78e966954741325061800919984fb7257e9 Component: cli --- components/cli/cli/command/system/info.go | 7 +- .../cli/cli/command/system/info_test.go | 237 ++++++++++++++++++ .../testdata/docker-info-no-swarm.golden | 51 ++++ .../testdata/docker-info-warnings.golden | 11 + .../testdata/docker-info-with-swarm.golden | 73 ++++++ 5 files changed, 376 insertions(+), 3 deletions(-) create mode 100644 components/cli/cli/command/system/info_test.go create mode 100644 components/cli/cli/command/system/testdata/docker-info-no-swarm.golden create mode 100644 components/cli/cli/command/system/testdata/docker-info-warnings.golden create mode 100644 components/cli/cli/command/system/testdata/docker-info-with-swarm.golden diff --git a/components/cli/cli/command/system/info.go b/components/cli/cli/command/system/info.go index 73f1765435..e1b5b08c63 100644 --- a/components/cli/cli/command/system/info.go +++ b/components/cli/cli/command/system/info.go @@ -54,7 +54,7 @@ func runInfo(dockerCli *command.DockerCli, opts *infoOptions) error { } // nolint: gocyclo -func prettyPrintInfo(dockerCli *command.DockerCli, info types.Info) error { +func prettyPrintInfo(dockerCli command.Cli, info types.Info) error { fmt.Fprintf(dockerCli.Out(), "Containers: %d\n", info.Containers) fmt.Fprintf(dockerCli.Out(), " Running: %d\n", info.ContainersRunning) fmt.Fprintf(dockerCli.Out(), " Paused: %d\n", info.ContainersPaused) @@ -76,7 +76,7 @@ func prettyPrintInfo(dockerCli *command.DockerCli, info types.Info) error { fprintfIfNotEmpty(dockerCli.Out(), "Logging Driver: %s\n", info.LoggingDriver) fprintfIfNotEmpty(dockerCli.Out(), "Cgroup Driver: %s\n", info.CgroupDriver) - fmt.Fprintf(dockerCli.Out(), "Plugins: \n") + fmt.Fprintf(dockerCli.Out(), "Plugins:\n") fmt.Fprintf(dockerCli.Out(), " Volume:") fmt.Fprintf(dockerCli.Out(), " %s", strings.Join(info.Plugins.Volume, " ")) fmt.Fprintf(dockerCli.Out(), "\n") @@ -130,6 +130,7 @@ func prettyPrintInfo(dockerCli *command.DockerCli, info types.Info) error { fmt.Fprintf(dockerCli.Out(), " %s: %s\n", entry.Protocol, entry.URL) } } + fmt.Fprintf(dockerCli.Out(), " Autolock Managers: %v\n", info.Swarm.Cluster.Spec.EncryptionConfig.AutoLockManagers) fmt.Fprintf(dockerCli.Out(), " Root Rotation In Progress: %v\n", info.Swarm.Cluster.RootRotationInProgress) } fmt.Fprintf(dockerCli.Out(), " Node Address: %s\n", info.Swarm.NodeAddr) @@ -325,7 +326,7 @@ func prettyPrintInfo(dockerCli *command.DockerCli, info types.Info) error { return nil } -func printStorageDriverWarnings(dockerCli *command.DockerCli, info types.Info) { +func printStorageDriverWarnings(dockerCli command.Cli, info types.Info) { if info.DriverStatus == nil { return } diff --git a/components/cli/cli/command/system/info_test.go b/components/cli/cli/command/system/info_test.go new file mode 100644 index 0000000000..4291623d1a --- /dev/null +++ b/components/cli/cli/command/system/info_test.go @@ -0,0 +1,237 @@ +package system + +import ( + "encoding/base64" + "net" + "testing" + "time" + + "github.com/docker/cli/internal/test" + "github.com/docker/docker/api/types" + "github.com/docker/docker/api/types/registry" + "github.com/docker/docker/api/types/swarm" + "github.com/gotestyourself/gotestyourself/golden" + "github.com/stretchr/testify/assert" +) + +// helper function that base64 decodes a string and ignores the error +func base64Decode(val string) []byte { + decoded, _ := base64.StdEncoding.DecodeString(val) + return decoded +} + +var sampleInfoNoSwarm = types.Info{ + ID: "EKHL:QDUU:QZ7U:MKGD:VDXK:S27Q:GIPU:24B7:R7VT:DGN6:QCSF:2UBX", + Containers: 0, + ContainersRunning: 0, + ContainersPaused: 0, + ContainersStopped: 0, + Images: 0, + Driver: "aufs", + DriverStatus: [][2]string{ + {"Root Dir", "/var/lib/docker/aufs"}, + {"Backing Filesystem", "extfs"}, + {"Dirs", "0"}, + {"Dirperm1 Supported", "true"}, + }, + SystemStatus: nil, + Plugins: types.PluginsInfo{ + Volume: []string{"local"}, + Network: []string{"bridge", "host", "macvlan", "null", "overlay"}, + Authorization: nil, + Log: []string{"awslogs", "fluentd", "gcplogs", "gelf", "journald", "json-file", "logentries", "splunk", "syslog"}, + }, + MemoryLimit: true, + SwapLimit: true, + KernelMemory: true, + CPUCfsPeriod: true, + CPUCfsQuota: true, + CPUShares: true, + CPUSet: true, + IPv4Forwarding: true, + BridgeNfIptables: true, + BridgeNfIP6tables: true, + Debug: true, + NFd: 33, + OomKillDisable: true, + NGoroutines: 135, + SystemTime: "2017-08-24T17:44:34.077811894Z", + LoggingDriver: "json-file", + CgroupDriver: "cgroupfs", + NEventsListener: 0, + KernelVersion: "4.4.0-87-generic", + OperatingSystem: "Ubuntu 16.04.3 LTS", + OSType: "linux", + Architecture: "x86_64", + IndexServerAddress: "https://index.docker.io/v1/", + RegistryConfig: ®istry.ServiceConfig{ + AllowNondistributableArtifactsCIDRs: nil, + AllowNondistributableArtifactsHostnames: nil, + InsecureRegistryCIDRs: []*registry.NetIPNet{ + { + IP: net.ParseIP("127.0.0.0"), + Mask: net.IPv4Mask(255, 0, 0, 0), + }, + }, + IndexConfigs: map[string]*registry.IndexInfo{ + "docker.io": { + Name: "docker.io", + Mirrors: nil, + Secure: true, + Official: true, + }, + }, + Mirrors: nil, + }, + NCPU: 2, + MemTotal: 2097356800, + DockerRootDir: "/var/lib/docker", + HTTPProxy: "", + HTTPSProxy: "", + NoProxy: "", + Name: "system-sample", + Labels: []string{"provider=digitalocean"}, + ExperimentalBuild: false, + ServerVersion: "17.06.1-ce", + ClusterStore: "", + ClusterAdvertise: "", + Runtimes: map[string]types.Runtime{ + "runc": { + Path: "docker-runc", + Args: nil, + }, + }, + DefaultRuntime: "runc", + Swarm: swarm.Info{LocalNodeState: "inactive"}, + LiveRestoreEnabled: false, + Isolation: "", + InitBinary: "docker-init", + ContainerdCommit: types.Commit{ + ID: "6e23458c129b551d5c9871e5174f6b1b7f6d1170", + Expected: "6e23458c129b551d5c9871e5174f6b1b7f6d1170", + }, + RuncCommit: types.Commit{ + ID: "810190ceaa507aa2727d7ae6f4790c76ec150bd2", + Expected: "810190ceaa507aa2727d7ae6f4790c76ec150bd2", + }, + InitCommit: types.Commit{ + ID: "949e6fa", + Expected: "949e6fa", + }, + SecurityOptions: []string{"name=apparmor", "name=seccomp,profile=default"}, +} + +var sampleSwarmInfo = swarm.Info{ + NodeID: "qo2dfdig9mmxqkawulggepdih", + NodeAddr: "165.227.107.89", + LocalNodeState: "active", + ControlAvailable: true, + Error: "", + RemoteManagers: []swarm.Peer{ + { + NodeID: "qo2dfdig9mmxqkawulggepdih", + Addr: "165.227.107.89:2377", + }, + }, + Nodes: 1, + Managers: 1, + Cluster: &swarm.ClusterInfo{ + ID: "9vs5ygs0gguyyec4iqf2314c0", + Meta: swarm.Meta{ + Version: swarm.Version{Index: 11}, + CreatedAt: time.Date(2017, 8, 24, 17, 34, 19, 278062352, time.UTC), + UpdatedAt: time.Date(2017, 8, 24, 17, 34, 42, 398815481, time.UTC), + }, + Spec: swarm.Spec{ + Annotations: swarm.Annotations{ + Name: "default", + Labels: nil, + }, + Orchestration: swarm.OrchestrationConfig{ + TaskHistoryRetentionLimit: &[]int64{5}[0], + }, + Raft: swarm.RaftConfig{ + SnapshotInterval: 10000, + KeepOldSnapshots: &[]uint64{0}[0], + LogEntriesForSlowFollowers: 500, + ElectionTick: 3, + HeartbeatTick: 1, + }, + Dispatcher: swarm.DispatcherConfig{ + HeartbeatPeriod: 5000000000, + }, + CAConfig: swarm.CAConfig{ + NodeCertExpiry: 7776000000000000, + }, + TaskDefaults: swarm.TaskDefaults{}, + EncryptionConfig: swarm.EncryptionConfig{ + AutoLockManagers: true, + }, + }, + TLSInfo: swarm.TLSInfo{ + TrustRoot: ` +-----BEGIN CERTIFICATE----- +MIIBajCCARCgAwIBAgIUaFCW5xsq8eyiJ+Pmcv3MCflMLnMwCgYIKoZIzj0EAwIw +EzERMA8GA1UEAxMIc3dhcm0tY2EwHhcNMTcwODI0MTcyOTAwWhcNMzcwODE5MTcy +OTAwWjATMREwDwYDVQQDEwhzd2FybS1jYTBZMBMGByqGSM49AgEGCCqGSM49AwEH +A0IABDy7NebyUJyUjWJDBUdnZoV6GBxEGKO4TZPNDwnxDxJcUdLVaB7WGa4/DLrW +UfsVgh1JGik2VTiLuTMA1tLlNPOjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMB +Af8EBTADAQH/MB0GA1UdDgQWBBQl16XFtaaXiUAwEuJptJlDjfKskDAKBggqhkjO +PQQDAgNIADBFAiEAo9fTQNM5DP9bHVcTJYfl2Cay1bFu1E+lnpmN+EYJfeACIGKH +1pCUkZ+D0IB6CiEZGWSHyLuXPM1rlP+I5KuS7sB8 +-----END CERTIFICATE----- +`, + CertIssuerSubject: base64Decode("MBMxETAPBgNVBAMTCHN3YXJtLWNh"), + CertIssuerPublicKey: base64Decode( + "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEPLs15vJQnJSNYkMFR2dmhXoYHEQYo7hNk80PCfEPElxR0tVoHtYZrj8MutZR+xWCHUkaKTZVOIu5MwDW0uU08w=="), + }, + RootRotationInProgress: false, + }, +} + +func TestPrettyPrintInfo(t *testing.T) { + infoWithSwarm := sampleInfoNoSwarm + infoWithSwarm.Swarm = sampleSwarmInfo + + infoWithWarningsLinux := sampleInfoNoSwarm + infoWithWarningsLinux.MemoryLimit = false + infoWithWarningsLinux.SwapLimit = false + infoWithWarningsLinux.KernelMemory = false + infoWithWarningsLinux.OomKillDisable = false + infoWithWarningsLinux.CPUCfsQuota = false + infoWithWarningsLinux.CPUCfsPeriod = false + infoWithWarningsLinux.CPUShares = false + infoWithWarningsLinux.CPUSet = false + infoWithWarningsLinux.IPv4Forwarding = false + infoWithWarningsLinux.BridgeNfIptables = false + infoWithWarningsLinux.BridgeNfIP6tables = false + + for _, tc := range []struct { + dockerInfo types.Info + expectedGolden string + warningsGolden string + }{ + { + dockerInfo: sampleInfoNoSwarm, + expectedGolden: "docker-info-no-swarm", + }, + { + dockerInfo: infoWithSwarm, + expectedGolden: "docker-info-with-swarm", + }, + { + dockerInfo: infoWithWarningsLinux, + expectedGolden: "docker-info-no-swarm", + warningsGolden: "docker-info-warnings", + }, + } { + cli := test.NewFakeCli(&fakeClient{}) + assert.NoError(t, prettyPrintInfo(cli, tc.dockerInfo)) + golden.Assert(t, cli.OutBuffer().String(), tc.expectedGolden+".golden") + if tc.warningsGolden != "" { + golden.Assert(t, cli.ErrBuffer().String(), tc.warningsGolden+".golden") + } else { + assert.Equal(t, "", cli.ErrBuffer().String()) + } + } +} diff --git a/components/cli/cli/command/system/testdata/docker-info-no-swarm.golden b/components/cli/cli/command/system/testdata/docker-info-no-swarm.golden new file mode 100644 index 0000000000..7a3e966735 --- /dev/null +++ b/components/cli/cli/command/system/testdata/docker-info-no-swarm.golden @@ -0,0 +1,51 @@ +Containers: 0 + Running: 0 + Paused: 0 + Stopped: 0 +Images: 0 +Server Version: 17.06.1-ce +Storage Driver: aufs + Root Dir: /var/lib/docker/aufs + Backing Filesystem: extfs + Dirs: 0 + Dirperm1 Supported: true +Logging Driver: json-file +Cgroup Driver: cgroupfs +Plugins: + Volume: local + Network: bridge host macvlan null overlay + Log: awslogs fluentd gcplogs gelf journald json-file logentries splunk syslog +Swarm: inactive +Runtimes: runc +Default Runtime: runc +Init Binary: docker-init +containerd version: 6e23458c129b551d5c9871e5174f6b1b7f6d1170 +runc version: 810190ceaa507aa2727d7ae6f4790c76ec150bd2 +init version: 949e6fa +Security Options: + apparmor + seccomp + Profile: default +Kernel Version: 4.4.0-87-generic +Operating System: Ubuntu 16.04.3 LTS +OSType: linux +Architecture: x86_64 +CPUs: 2 +Total Memory: 1.953GiB +Name: system-sample +ID: EKHL:QDUU:QZ7U:MKGD:VDXK:S27Q:GIPU:24B7:R7VT:DGN6:QCSF:2UBX +Docker Root Dir: /var/lib/docker +Debug Mode (client): false +Debug Mode (server): true + File Descriptors: 33 + Goroutines: 135 + System Time: 2017-08-24T17:44:34.077811894Z + EventsListeners: 0 +Registry: https://index.docker.io/v1/ +Labels: + provider=digitalocean +Experimental: false +Insecure Registries: + 127.0.0.0/8 +Live Restore Enabled: false + diff --git a/components/cli/cli/command/system/testdata/docker-info-warnings.golden b/components/cli/cli/command/system/testdata/docker-info-warnings.golden new file mode 100644 index 0000000000..a7a4d792b0 --- /dev/null +++ b/components/cli/cli/command/system/testdata/docker-info-warnings.golden @@ -0,0 +1,11 @@ +WARNING: No memory limit support +WARNING: No swap limit support +WARNING: No kernel memory limit support +WARNING: No oom kill disable support +WARNING: No cpu cfs quota support +WARNING: No cpu cfs period support +WARNING: No cpu shares support +WARNING: No cpuset support +WARNING: IPv4 forwarding is disabled +WARNING: bridge-nf-call-iptables is disabled +WARNING: bridge-nf-call-ip6tables is disabled diff --git a/components/cli/cli/command/system/testdata/docker-info-with-swarm.golden b/components/cli/cli/command/system/testdata/docker-info-with-swarm.golden new file mode 100644 index 0000000000..17bb70fa7f --- /dev/null +++ b/components/cli/cli/command/system/testdata/docker-info-with-swarm.golden @@ -0,0 +1,73 @@ +Containers: 0 + Running: 0 + Paused: 0 + Stopped: 0 +Images: 0 +Server Version: 17.06.1-ce +Storage Driver: aufs + Root Dir: /var/lib/docker/aufs + Backing Filesystem: extfs + Dirs: 0 + Dirperm1 Supported: true +Logging Driver: json-file +Cgroup Driver: cgroupfs +Plugins: + Volume: local + Network: bridge host macvlan null overlay + Log: awslogs fluentd gcplogs gelf journald json-file logentries splunk syslog +Swarm: active + NodeID: qo2dfdig9mmxqkawulggepdih + Is Manager: true + ClusterID: 9vs5ygs0gguyyec4iqf2314c0 + Managers: 1 + Nodes: 1 + Orchestration: + Task History Retention Limit: 5 + Raft: + Snapshot Interval: 10000 + Number of Old Snapshots to Retain: 0 + Heartbeat Tick: 1 + Election Tick: 3 + Dispatcher: + Heartbeat Period: 5 seconds + CA Configuration: + Expiry Duration: 3 months + Force Rotate: 0 + Autolock Managers: true + Root Rotation In Progress: false + Node Address: 165.227.107.89 + Manager Addresses: + 165.227.107.89:2377 +Runtimes: runc +Default Runtime: runc +Init Binary: docker-init +containerd version: 6e23458c129b551d5c9871e5174f6b1b7f6d1170 +runc version: 810190ceaa507aa2727d7ae6f4790c76ec150bd2 +init version: 949e6fa +Security Options: + apparmor + seccomp + Profile: default +Kernel Version: 4.4.0-87-generic +Operating System: Ubuntu 16.04.3 LTS +OSType: linux +Architecture: x86_64 +CPUs: 2 +Total Memory: 1.953GiB +Name: system-sample +ID: EKHL:QDUU:QZ7U:MKGD:VDXK:S27Q:GIPU:24B7:R7VT:DGN6:QCSF:2UBX +Docker Root Dir: /var/lib/docker +Debug Mode (client): false +Debug Mode (server): true + File Descriptors: 33 + Goroutines: 135 + System Time: 2017-08-24T17:44:34.077811894Z + EventsListeners: 0 +Registry: https://index.docker.io/v1/ +Labels: + provider=digitalocean +Experimental: false +Insecure Registries: + 127.0.0.0/8 +Live Restore Enabled: false + From 83dbde20575955112f0d5183ba8fddb7558c8f09 Mon Sep 17 00:00:00 2001 From: Daniel Nephin Date: Tue, 9 May 2017 17:24:40 -0400 Subject: [PATCH 41/47] Reduce complexity of two formatters Signed-off-by: Daniel Nephin Upstream-commit: d318c4112b1e4e00a4c9c78acc59e57955e38d6a Component: cli --- .../cli/cli/command/formatter/custom_test.go | 7 +- components/cli/cli/command/formatter/image.go | 165 +++++++++--------- .../cli/cli/command/formatter/image_test.go | 24 ++- components/cli/cli/compose/loader/loader.go | 6 +- 4 files changed, 106 insertions(+), 96 deletions(-) diff --git a/components/cli/cli/command/formatter/custom_test.go b/components/cli/cli/command/formatter/custom_test.go index da42039dca..a9f6ccdac9 100644 --- a/components/cli/cli/command/formatter/custom_test.go +++ b/components/cli/cli/command/formatter/custom_test.go @@ -1,9 +1,10 @@ package formatter import ( - "reflect" "strings" "testing" + + "github.com/stretchr/testify/assert" ) func compareMultipleValues(t *testing.T, value, expected string) { @@ -22,7 +23,5 @@ func compareMultipleValues(t *testing.T, value, expected string) { keyval := strings.Split(expected, "=") expMap[keyval[0]] = keyval[1] } - if !reflect.DeepEqual(expMap, entriesMap) { - t.Fatalf("Expected entries: %v, got: %v", expected, value) - } + assert.Equal(t, expMap, entriesMap) } diff --git a/components/cli/cli/command/formatter/image.go b/components/cli/cli/command/formatter/image.go index aaf8ff1aa1..e94785ef08 100644 --- a/components/cli/cli/command/formatter/image.go +++ b/components/cli/cli/command/formatter/image.go @@ -86,9 +86,9 @@ func needDigest(ctx ImageContext) bool { func imageFormat(ctx ImageContext, images []types.ImageSummary, format func(subContext subContext) error) error { for _, image := range images { - images := []*imageContext{} + formatted := []*imageContext{} if isDangling(image) { - images = append(images, &imageContext{ + formatted = append(formatted, &imageContext{ trunc: ctx.Trunc, i: image, repo: "", @@ -96,90 +96,9 @@ func imageFormat(ctx ImageContext, images []types.ImageSummary, format func(subC digest: "", }) } else { - repoTags := map[string][]string{} - repoDigests := map[string][]string{} - - for _, refString := range image.RepoTags { - ref, err := reference.ParseNormalizedNamed(refString) - if err != nil { - continue - } - if nt, ok := ref.(reference.NamedTagged); ok { - familiarRef := reference.FamiliarName(ref) - repoTags[familiarRef] = append(repoTags[familiarRef], nt.Tag()) - } - } - for _, refString := range image.RepoDigests { - ref, err := reference.ParseNormalizedNamed(refString) - if err != nil { - continue - } - if c, ok := ref.(reference.Canonical); ok { - familiarRef := reference.FamiliarName(ref) - repoDigests[familiarRef] = append(repoDigests[familiarRef], c.Digest().String()) - } - } - - for repo, tags := range repoTags { - digests := repoDigests[repo] - - // Do not display digests as their own row - delete(repoDigests, repo) - - if !needDigest(ctx) { - // Ignore digest references, just show tag once - digests = nil - } - - for _, tag := range tags { - if len(digests) == 0 { - images = append(images, &imageContext{ - trunc: ctx.Trunc, - i: image, - repo: repo, - tag: tag, - digest: "", - }) - continue - } - // Display the digests for each tag - for _, dgst := range digests { - images = append(images, &imageContext{ - trunc: ctx.Trunc, - i: image, - repo: repo, - tag: tag, - digest: dgst, - }) - } - - } - } - - // Show rows for remaining digest only references - for repo, digests := range repoDigests { - // If digests are displayed, show row per digest - if ctx.Digest { - for _, dgst := range digests { - images = append(images, &imageContext{ - trunc: ctx.Trunc, - i: image, - repo: repo, - tag: "", - digest: dgst, - }) - } - } else { - images = append(images, &imageContext{ - trunc: ctx.Trunc, - i: image, - repo: repo, - tag: "", - }) - } - } + formatted = imageFormatTaggedAndDigest(ctx, image) } - for _, imageCtx := range images { + for _, imageCtx := range formatted { if err := format(imageCtx); err != nil { return err } @@ -188,6 +107,82 @@ func imageFormat(ctx ImageContext, images []types.ImageSummary, format func(subC return nil } +func imageFormatTaggedAndDigest(ctx ImageContext, image types.ImageSummary) []*imageContext { + repoTags := map[string][]string{} + repoDigests := map[string][]string{} + images := []*imageContext{} + + for _, refString := range image.RepoTags { + ref, err := reference.ParseNormalizedNamed(refString) + if err != nil { + continue + } + if nt, ok := ref.(reference.NamedTagged); ok { + familiarRef := reference.FamiliarName(ref) + repoTags[familiarRef] = append(repoTags[familiarRef], nt.Tag()) + } + } + for _, refString := range image.RepoDigests { + ref, err := reference.ParseNormalizedNamed(refString) + if err != nil { + continue + } + if c, ok := ref.(reference.Canonical); ok { + familiarRef := reference.FamiliarName(ref) + repoDigests[familiarRef] = append(repoDigests[familiarRef], c.Digest().String()) + } + } + + addImage := func(repo, tag, digest string) { + image := &imageContext{ + trunc: ctx.Trunc, + i: image, + repo: repo, + tag: tag, + digest: digest, + } + images = append(images, image) + } + + for repo, tags := range repoTags { + digests := repoDigests[repo] + + // Do not display digests as their own row + delete(repoDigests, repo) + + if !needDigest(ctx) { + // Ignore digest references, just show tag once + digests = nil + } + + for _, tag := range tags { + if len(digests) == 0 { + addImage(repo, tag, "") + continue + } + // Display the digests for each tag + for _, dgst := range digests { + addImage(repo, tag, dgst) + } + + } + } + + // Show rows for remaining digest only references + for repo, digests := range repoDigests { + // If digests are displayed, show row per digest + if ctx.Digest { + for _, dgst := range digests { + addImage(repo, "", dgst) + } + } else { + addImage(repo, "", "") + + } + } + return images +} + type imageContext struct { HeaderContext trunc bool diff --git a/components/cli/cli/command/formatter/image_test.go b/components/cli/cli/command/formatter/image_test.go index be7b084e3c..20b73a52c1 100644 --- a/components/cli/cli/command/formatter/image_test.go +++ b/components/cli/cli/command/formatter/image_test.go @@ -55,6 +55,26 @@ func TestImageContext(t *testing.T) { i: types.ImageSummary{}, digest: "sha256:d149ab53f8718e987c3a3024bb8aa0e2caadf6c0328f1d9d850b2a2a67f2819a", }, "sha256:d149ab53f8718e987c3a3024bb8aa0e2caadf6c0328f1d9d850b2a2a67f2819a", ctx.Digest}, + { + imageContext{ + i: types.ImageSummary{Containers: 10}, + }, "10", ctx.Containers, + }, + { + imageContext{ + i: types.ImageSummary{VirtualSize: 10000}, + }, "10kB", ctx.VirtualSize, + }, + { + imageContext{ + i: types.ImageSummary{SharedSize: 10000}, + }, "10kB", ctx.SharedSize, + }, + { + imageContext{ + i: types.ImageSummary{SharedSize: 5000, VirtualSize: 20000}, + }, "15kB", ctx.UniqueSize, + }, } for _, c := range cases { @@ -62,8 +82,8 @@ func TestImageContext(t *testing.T) { v := c.call() if strings.Contains(v, ",") { compareMultipleValues(t, v, c.expValue) - } else if v != c.expValue { - t.Fatalf("Expected %s, was %s\n", c.expValue, v) + } else { + assert.Equal(t, c.expValue, v) } } } diff --git a/components/cli/cli/compose/loader/loader.go b/components/cli/cli/compose/loader/loader.go index 2fb2630087..2bc941e652 100644 --- a/components/cli/cli/compose/loader/loader.go +++ b/components/cli/cli/compose/loader/loader.go @@ -93,11 +93,7 @@ func Load(configDetails types.ConfigDetails) (*types.Config, error) { } cfg.Configs, err = LoadConfigObjs(config["configs"], configDetails.WorkingDir) - if err != nil { - return nil, err - } - - return &cfg, nil + return &cfg, err } func interpolateConfig(configDict map[string]interface{}, lookupEnv template.Mapping) (map[string]map[string]interface{}, error) { From a4cd4da158103f7adf3804299d67c5f7496abeab Mon Sep 17 00:00:00 2001 From: Li Yi Date: Sun, 20 Aug 2017 10:39:05 +0800 Subject: [PATCH 42/47] Support start_period for healthcheck in Docker Compose Signed-off-by: Li Yi Upstream-commit: 0abdad615f0c48a01520c2c6211d787ac08966fc Component: cli --- components/cli/cli/compose/loader/full-example.yml | 1 + components/cli/cli/compose/loader/loader_test.go | 9 +++++---- components/cli/cli/compose/schema/bindata.go | 2 +- .../cli/cli/compose/schema/data/config_schema_v3.4.json | 3 ++- components/cli/cli/compose/types/types.go | 2 +- 5 files changed, 10 insertions(+), 7 deletions(-) diff --git a/components/cli/cli/compose/loader/full-example.yml b/components/cli/cli/compose/loader/full-example.yml index d193dccd31..70486e1bcc 100644 --- a/components/cli/cli/compose/loader/full-example.yml +++ b/components/cli/cli/compose/loader/full-example.yml @@ -114,6 +114,7 @@ services: interval: 10s timeout: 1s retries: 5 + start_period: 15s # Any valid image reference - repo, tag, id, sha image: redis diff --git a/components/cli/cli/compose/loader/loader_test.go b/components/cli/cli/compose/loader/loader_test.go index 295e91e1e7..7cee33313c 100644 --- a/components/cli/cli/compose/loader/loader_test.go +++ b/components/cli/cli/compose/loader/loader_test.go @@ -756,10 +756,11 @@ func TestFullExample(t *testing.T) { "somehost": "162.242.195.82", }, HealthCheck: &types.HealthCheckConfig{ - Test: types.HealthCheckTest([]string{"CMD-SHELL", "echo \"hello world\""}), - Interval: "10s", - Timeout: "1s", - Retries: uint64Ptr(5), + Test: types.HealthCheckTest([]string{"CMD-SHELL", "echo \"hello world\""}), + Interval: "10s", + Timeout: "1s", + Retries: uint64Ptr(5), + StartPeriod: "15s", }, Hostname: "foo", Image: "redis", diff --git a/components/cli/cli/compose/schema/bindata.go b/components/cli/cli/compose/schema/bindata.go index 73aedf0495..8f9b678d9c 100644 --- a/components/cli/cli/compose/schema/bindata.go +++ b/components/cli/cli/compose/schema/bindata.go @@ -152,7 +152,7 @@ func dataConfig_schema_v33Json() (*asset, error) { return a, nil } -var _dataConfig_schema_v34Json = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xec\x5b\x4f\x73\xdb\x3a\x0e\xbf\xfb\x53\x68\xf4\xde\xad\x76\xd2\x99\xed\xec\xcc\xf6\xb6\xc7\x3d\xed\x9e\x37\xe3\x6a\x68\x0a\xb6\xd9\x50\x24\x0b\x52\x4e\xdc\x4e\xbe\xfb\x8e\xfe\x5a\x7f\x28\x92\xb2\x95\x26\xdd\xd7\x53\x62\x09\x00\x09\x80\xf8\x01\x20\xa9\x1f\xab\x28\x8a\xff\xd4\xf4\x08\x19\x89\x3f\x47\xf1\xd1\x18\xf5\xf9\xfe\xfe\xab\x96\x62\x53\x3d\xbd\x93\x78\xb8\x4f\x91\xec\xcd\xe6\xe3\xa7\xfb\xea\xd9\x1f\xf1\xba\xe0\x63\x69\xc1\x42\xa5\xd8\xb3\x43\x52\xbd\x49\x4e\x7f\xbb\xfb\x74\x57\xb0\x57\x24\xe6\xac\xa0\x20\x92\xbb\xaf\x40\x4d\xf5\x0c\xe1\x5b\xce\x10\x0a\xe6\x87\xf8\x04\xa8\x99\x14\xf1\x76\xbd\x2a\xde\x29\x94\x0a\xd0\x30\xd0\xf1\xe7\xa8\x98\x5c\x14\xb5\x24\xcd\x83\x8e\x58\x6d\x90\x89\x43\x5c\x3e\x7e\x29\x25\x44\x51\xac\x01\x4f\x8c\x76\x24\xb4\x53\xfd\xe3\xfe\x22\xff\xbe\x25\x5b\x0f\xa5\x76\x26\x5b\x3e\x57\xc4\x18\x40\xf1\x9f\xf1\xdc\xca\xd7\x5f\x1e\xc8\xe6\xfb\x3f\x37\xff\xfd\xb8\xf9\xc7\x5d\xb2\xd9\x7e\xf8\xb3\xf7\xba\xb0\x2f\xc2\xbe\x1a\x3e\x85\x3d\x13\xcc\x30\x29\xda\xf1\xe3\x96\xf2\xa5\xfe\xef\xa5\x1d\x98\xa4\x69\x49\x4c\x78\x6f\xec\x3d\xe1\x1a\xfa\x3a\x0b\x30\x4f\x12\x1f\x7d\x3a\xb7\x64\x6f\xa4\x73\x3d\xbe\x45\xe7\xbe\x3a\x27\xc9\xf3\xcc\xeb\xc1\x86\xea\x8d\x94\xa9\x86\x5f\xc6\x7f\x1a\x28\x82\xf1\x2f\xd9\x8a\xea\xcd\x56\x6c\x31\xfc\x32\x0a\x57\xa8\xe1\x53\xb8\xa1\x7a\x23\x85\xab\xe1\x6f\x53\x78\xd5\x28\x6d\x9f\x63\xfc\xe5\x79\x53\xfc\x7d\x29\x65\x3a\xe5\x55\x52\x3a\xf3\x2b\x95\xe8\x61\x9e\xcd\x9c\x36\xcc\x99\xb6\x67\x6b\xd0\x09\x4b\xa6\xa0\xb8\x3c\x97\x33\xb7\xdb\xac\x22\xc8\x40\x98\xb8\x35\x53\x14\xc5\xbb\x9c\xf1\x74\x68\x75\x29\xe0\xdf\x85\x88\x87\xce\xc3\x28\xfa\x31\x84\xf7\x8e\x9c\xf2\x7d\xef\xd7\xf4\xa2\x68\xdf\x4f\xe8\xd2\xbe\xa7\x52\x18\x78\x36\xa5\x52\xee\xa1\x2b\x13\x48\xfa\x08\xb8\x67\x1c\x42\x39\x08\x56\x2b\x7d\xc2\x64\x9c\x69\x93\x48\x4c\x52\x46\x8d\x95\x9f\x93\x1d\xf0\x9b\x24\x50\x42\x8f\x90\xec\x51\x66\x5e\x29\xfb\xa4\xd2\x44\x5b\x05\x35\x08\x1e\xa8\xb9\x21\x78\x00\xbb\x65\x07\xc4\x23\x6e\x7f\x6c\xb5\xac\x9d\x5f\xdb\x95\x45\x60\x4c\x89\x4a\x48\x9a\xf6\xe6\x41\x10\xc9\x39\x5e\x47\x31\x33\x90\x69\xbb\x42\x51\x9c\x0b\xf6\x2d\x87\x7f\xd5\x24\x06\x73\x18\xca\x4d\x51\xaa\xe5\x05\x1f\x50\xe6\x2a\x51\x04\x8b\x40\x72\x1b\x3b\xa6\x32\xcb\x88\x58\x2a\xba\xe6\xe8\x11\x60\xf9\x11\xce\x47\xdd\x90\xad\xc7\xe8\xbe\x6a\x47\xeb\x4d\x6b\x42\x1b\xbf\x3e\x63\xbc\xf0\x23\x86\x1f\x33\x0a\xc8\x95\x39\xd2\x50\x08\x70\x87\x82\x95\x3e\x67\x69\x38\xf1\x61\x0e\x71\x26\xd3\xfe\xbc\x45\x9e\xed\x00\x47\x21\xd9\x8f\xac\xf1\xef\xed\xca\xf6\x66\xe0\x7d\x43\x98\x00\x4c\x04\xc9\x7c\xb6\x8a\x29\x42\x0a\xc2\x30\xc2\x13\xad\x80\xf6\xc8\x1b\x4f\x39\x3c\x13\x07\x41\x72\x8c\x70\x60\xda\xe0\xd9\x0d\x4a\x2f\xdd\x89\xa5\xa0\x40\xa4\x3a\xa9\x9a\x90\xf9\xe8\x19\xa7\xd0\x76\x24\x8b\xc2\x44\x2a\x5c\x59\xa1\x12\x53\xe4\x85\x62\x6e\xf1\x80\x31\xd1\x40\x90\x1e\xaf\xe4\x97\x19\x61\x22\xc4\xa9\x20\x0c\x9e\x95\x64\x15\x8c\xbd\x3b\x7c\x02\x71\x4a\xda\x75\x33\xdb\x0c\x20\x4e\x0c\xa5\xc8\x1a\x90\x0e\xcb\xce\x1d\xfe\x67\x25\x35\xdc\x0e\x8e\x35\xc7\x43\xa3\xf8\xba\x8d\xe9\x6d\xdf\x7a\xf1\x5e\x62\x46\x8a\xc9\x36\x63\x77\x63\xb8\x37\xd4\x78\xe5\x75\x0d\xd8\xd5\xa1\xa8\x6a\x09\x4f\x38\x13\x8f\xcb\x2f\x71\x78\x36\x48\x92\xa3\xd4\xe6\x9a\x02\x28\x3e\x02\xe1\xe6\x48\x8f\x40\x1f\x1d\xec\x5d\xaa\x1e\xb7\xd4\x26\x64\x91\xb3\x8c\x1c\xfc\x44\x8a\xfa\x48\xae\x2e\xf4\xe2\x45\x8d\xdf\x11\x2b\x0f\x87\x82\x74\x6a\xc5\x8d\x1a\x87\xfa\xb5\xaf\xe4\x4e\x91\x9d\x00\x43\xab\x48\xa9\x2e\xfd\xce\xf0\x65\x48\x36\xf7\x36\x88\x3d\xd2\x2f\x77\x55\x7f\xe8\x88\xaa\xf2\x3f\xce\xe3\xed\x38\x65\x8e\x93\xe6\xf0\xc9\x40\xc3\xb0\x3a\xb7\xe7\x95\x8c\xd0\xa2\x9c\x45\xd0\x13\x7e\xbd\x90\xd6\xf5\x7a\x32\xca\xf9\x17\xda\x11\xf1\x28\xb1\x4e\x21\xf5\x55\x6d\xc4\xfc\xf6\x2d\xc8\x75\xde\x1e\xdf\xa3\xcd\xd4\xf4\x42\xa7\x79\x99\xae\x7f\x89\x95\x74\x84\x33\xa2\xc1\x1f\xec\xce\x7e\xac\x95\xc6\xd4\xe9\x53\xe0\x9a\xb0\xf1\xfe\xdd\xc9\x3b\xc1\x3a\x29\x33\xbc\x75\xf3\x88\xea\x96\xa8\x9c\x5b\x27\xb2\xf5\x17\xad\xaf\xd9\x59\xaa\x7e\xe1\xdd\xc7\x8a\x12\x21\xba\x01\xa6\x24\x9a\x9f\xd2\x0b\x5d\x70\xea\x92\xf0\xab\xc1\xc7\xed\xd1\xd0\xdd\x41\x4c\xaf\xd3\x53\x39\x50\xca\x42\x6d\xe9\xa8\x98\x30\x70\x28\x5a\x19\x7b\x12\xc8\x77\x9c\xe9\x23\xa4\x73\x78\x50\x1a\x49\x25\x0f\x0b\x0c\xeb\xee\x4f\x78\x30\x38\xfa\xab\xab\x6a\x33\x85\xec\xc4\x38\x1c\x06\x1a\xef\xa4\xe4\x40\x44\x2f\x51\x20\x90\x34\x91\x82\x9f\x03\x28\xb5\x21\xe8\xdd\x95\xd0\x40\x73\x64\xe6\x9c\x48\x65\x16\xaf\x0a\xf5\x31\x4b\x34\xfb\x0e\xfd\xd8\xbb\xac\xfa\x5a\xd0\x76\x30\xa1\xc1\x1e\x7b\xf4\x7b\x2b\xe2\x2f\xb3\x15\xa1\xcf\x9a\x9a\xeb\x6a\x6b\x6d\x52\x26\x12\xa9\x40\x78\x63\x43\x1b\xa9\x92\x03\x12\x0a\x89\x02\x64\xd2\x6a\x8a\x1e\xc0\xa6\x39\x92\x62\xfc\xb1\x18\xcd\x0e\x82\xd8\x71\xa7\x43\x6a\x32\xb5\xbf\x72\x13\xc0\x18\x7f\xb0\xe7\x9c\x65\x6c\x3a\x68\x2c\xab\x36\xa0\x5e\xab\x6a\x35\x7b\x89\xe6\x28\xcf\x82\x20\xdb\xd1\x21\xb8\x1b\x84\x80\xce\xe0\x48\x70\x46\xea\x28\x03\x73\x3f\x91\x9f\x6c\x7d\x83\x75\x5e\xbd\xd3\xf2\x52\xde\xba\x9e\xc8\xd6\x4a\x3f\xab\xf4\x1a\x4e\x63\x3b\x59\xfd\xd8\x83\x2a\xd7\xde\x26\xae\xa4\x11\xda\xd5\x80\xb4\xa4\xe3\x63\xdf\xe8\x97\x40\xe8\x9e\x8f\x4a\x72\x8b\x6f\x02\x70\xbc\x1e\x29\x10\x3b\x5f\x1b\xf5\x83\x2b\x82\x0e\x0f\x95\x42\x33\x6d\x40\x50\xfb\xfe\xaa\x95\x69\xc7\x46\x87\x17\x63\xa3\xb8\xfb\xae\xb0\xae\xab\xa4\x22\x87\x0a\x6f\x83\x1b\x9d\xf0\x58\xad\x6f\x04\xfc\x14\x55\x84\xa4\x52\x4d\xb8\x26\x5c\x8d\xb9\x69\x76\xb0\x75\xe1\xa8\x43\xa7\x20\xe3\x49\xe2\x63\x91\x90\x52\x66\x47\x8e\xd5\x80\x65\xc6\x9d\x82\xc1\x5e\x5f\x23\xc0\x76\x10\xde\x25\xf5\x5e\x2e\x70\x1f\xca\xd7\x44\x93\x07\xe6\x4c\x93\xdd\xe0\x5c\xc2\x96\x68\x8b\xcc\x80\x27\x7f\xbe\x47\x30\xc8\x06\x47\x09\x4d\xd1\xd4\xcd\xed\xa0\xdf\xe7\x86\xbb\x61\x19\xc8\xdc\x79\x24\xdc\x5e\x06\xaa\x0c\x78\xb9\x50\xe0\x71\x6a\x87\x72\xe8\xd3\x87\xce\x01\x52\xd5\x97\x7b\x1d\x17\x92\xb0\x40\xa4\xe5\xd1\x46\x50\x76\x43\x50\x9c\x51\xa2\x7d\x15\xc4\x0d\xbb\xc0\xb9\x4a\x89\x81\xa4\xbe\xb7\x32\xa7\x66\x73\x14\x6b\x8a\x20\xe1\x1c\x38\xd3\x59\x48\xf1\x13\xa7\xc0\x89\x15\xfd\xbd\x75\x6f\xc9\xbe\x27\x8c\xe7\x08\x09\xa1\x93\x30\x3d\xe0\xc8\xa4\x60\x46\x5a\xe1\x24\x6c\xc8\x8c\x3c\x27\xcd\xb0\x25\x89\x27\xba\x4a\x26\x89\xa9\xbd\xf8\x59\x17\xeb\x22\xcf\x2c\xe5\x47\x5c\x36\xce\x9b\x3d\x43\x6d\xaa\x2e\x55\xaa\xfa\x57\x1f\x66\x5f\x26\x3b\xff\xd0\xcd\xe2\xce\xaa\xab\xea\x84\x79\x25\xbc\x63\x39\x5c\x1a\x82\x89\xd5\xd9\x8c\x38\xb2\x18\x82\x2e\x20\xae\xdd\xcb\xf7\xf2\x2f\x6a\x85\xc2\xf4\x89\x92\x9c\x55\xa5\xc9\x12\xa6\xa0\x52\x54\xf3\x08\x59\xa5\x37\x86\x45\xb1\x46\x8b\xc6\x2a\x53\xc6\x8b\x20\x25\xc3\x13\x13\xa9\x7c\x9a\x31\xe0\x72\xd6\x56\x9c\x50\x18\x20\xf6\xad\x86\xd6\x06\x09\x13\x66\xf6\x19\xd7\xd0\x2c\x0a\x61\x0f\x08\x62\x1c\x11\x91\xbb\xd7\x88\xa6\xfb\x0d\x9f\x6e\x7e\x0d\x6b\x0a\xad\x8a\xa2\xfb\x0d\xb6\x1a\x6f\x75\xfe\x0d\x55\x5b\x1b\xee\x9e\xec\xde\xd2\x79\xeb\xb5\xa9\x8c\x4e\x55\xee\x3d\x2f\xcb\x20\x93\xee\xbb\x21\x37\x5c\xcf\xf6\xa9\xd8\x90\x2d\x50\xbd\x04\x1d\xb0\xd6\x54\x89\x54\xcb\xef\xf0\xf8\x0f\x51\xb7\xfe\xfd\x05\xa6\x48\xb6\x14\x86\x04\x1f\x39\xc7\xd6\xf2\x29\x7a\x07\xe8\x90\xef\x44\xd8\x65\xca\x77\x86\x0e\xfd\xeb\x1c\xe5\x6d\x91\x09\xaf\x3e\xb4\xbd\xd1\xba\xb5\xd5\x36\xd8\xc5\x93\x57\x35\x96\x9b\x7f\xd9\xa6\x0d\xb7\x65\x6d\xfd\x1c\x31\x86\xd0\x63\x50\xeb\x37\xb3\xde\xbf\x01\x87\x46\x1b\x14\x56\x18\xaa\xa9\x16\x40\xa1\x90\xbb\x33\xff\x1f\x48\xf5\xab\xaf\xeb\x9f\xb7\x06\xeb\xaf\x48\xbc\x5f\x2a\x94\x54\x57\xe7\xfa\x80\xbb\xa0\xef\xc0\x67\x6f\xec\x8a\x51\xa2\xb3\xba\xa2\xa6\xfa\xed\x8a\x57\x8d\x8a\xfe\x31\x5d\xc7\x25\xe3\x5d\x3b\x97\x25\x83\xef\x12\xd5\x1c\xdb\xfe\x34\x86\x64\x96\x6f\x2e\xfb\xb5\x8f\xeb\x10\xbf\x21\x99\xd8\x25\x1e\x0c\x5a\x1b\xd1\xad\xf9\x82\xb8\x7f\xf7\xc1\x51\xe1\xb9\xee\xfc\xbd\x52\x69\xb4\xc0\x05\x09\xbb\x4f\x07\xcd\x73\x63\xdd\xf1\x27\x63\xd3\xf1\xdf\xf0\x8f\x3e\x20\x2b\xf4\x14\xe7\xd1\xae\xf2\x8f\xfe\x91\x58\xf5\xf1\xd7\xb6\x67\x9f\x01\x49\x75\x83\xb6\x93\x68\xb7\xdd\xfd\x84\xc9\x2b\xff\xb6\xcf\xca\x86\x07\x72\xcd\xe7\x5d\x13\x77\x04\x56\xdd\xbf\xe5\xe7\x7a\xab\x97\xd5\xff\x02\x00\x00\xff\xff\xee\x72\x8c\xda\x18\x3d\x00\x00") +var _dataConfig_schema_v34Json = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xec\x5b\x4f\x73\xdb\x3a\x0e\xbf\xfb\x53\x68\xf4\xde\xad\x76\xd2\x99\xed\xec\xcc\xf6\xb6\xc7\x3d\xed\x9e\x37\xe3\x6a\x68\x0a\xb6\xd9\x50\x24\x0b\x52\x4e\xdc\x4e\xbe\xfb\x8e\x44\x49\xd6\x1f\x4a\xa4\x6c\xa5\x49\xf7\xf5\x94\x58\x02\x40\x02\x20\x7e\x00\x48\xea\xc7\x2a\x8a\xe2\x3f\x35\x3d\x42\x46\xe2\xcf\x51\x7c\x34\x46\x7d\xbe\xbf\xff\xaa\xa5\xd8\xd8\xa7\x77\x12\x0f\xf7\x29\x92\xbd\xd9\x7c\xfc\x74\x6f\x9f\xfd\x11\xaf\x0b\x3e\x96\x16\x2c\x54\x8a\x3d\x3b\x24\xf6\x4d\x72\xfa\xdb\xdd\xa7\xbb\x82\xdd\x92\x98\xb3\x82\x82\x48\xee\xbe\x02\x35\xf6\x19\xc2\xb7\x9c\x21\x14\xcc\x0f\xf1\x09\x50\x33\x29\xe2\xed\x7a\x55\xbc\x53\x28\x15\xa0\x61\xa0\xe3\xcf\x51\x31\xb9\x28\x6a\x48\xea\x07\x2d\xb1\xda\x20\x13\x87\xb8\x7c\xfc\x52\x4a\x88\xa2\x58\x03\x9e\x18\x6d\x49\x68\xa6\xfa\xc7\xfd\x45\xfe\x7d\x43\xb6\xee\x4b\x6d\x4d\xb6\x7c\xae\x88\x31\x80\xe2\x3f\xc3\xb9\x95\xaf\xbf\x3c\x90\xcd\xf7\x7f\x6e\xfe\xfb\x71\xf3\x8f\xbb\x64\xb3\xfd\xf0\x67\xe7\x75\x61\x5f\x84\xbd\x1d\x3e\x85\x3d\x13\xcc\x30\x29\x9a\xf1\xe3\x86\xf2\xa5\xfa\xef\xa5\x19\x98\xa4\x69\x49\x4c\x78\x67\xec\x3d\xe1\x1a\xba\x3a\x0b\x30\x4f\x12\x1f\x7d\x3a\x37\x64\x6f\xa4\x73\x35\xbe\x43\xe7\xae\x3a\x27\xc9\xf3\xcc\xeb\xc1\x9a\xea\x8d\x94\xb1\xc3\x2f\xe3\x3f\x0d\x14\xc1\xf8\x97\xac\xa5\x7a\xb3\x15\x5b\x0c\xbf\x8c\xc2\x16\x35\x7c\x0a\xd7\x54\x6f\xa4\xb0\x1d\xfe\x36\x85\x57\xb5\xd2\xee\x39\xc6\x5f\x9e\x37\xc5\xdf\x97\x52\xe6\xa4\x3c\x2b\xa5\x35\xbf\x52\x89\x0e\xe6\xb9\xcc\xe9\xc2\x9c\x71\x7b\x36\x06\x1d\xb1\x64\x0a\x8a\xcb\x73\x39\x73\xb7\xcd\x2c\x41\x06\xc2\xc4\x8d\x99\xa2\x28\xde\xe5\x8c\xa7\x7d\xab\x4b\x01\xff\x2e\x44\x3c\xb4\x1e\x46\xd1\x8f\x3e\xbc\xb7\xe4\x94\xef\x3b\xbf\xc6\x17\x45\xf3\x7e\x44\x97\xe6\x3d\x95\xc2\xc0\xb3\x29\x95\x9a\x1e\xda\x9a\x40\xd2\x47\xc0\x3d\xe3\x10\xca\x41\xd0\xae\xf4\x11\x93\x71\xa6\x4d\x22\x31\x49\x19\x35\x4e\x7e\x4e\x76\xc0\x6f\x92\x40\x09\x3d\x42\xb2\x47\x99\x79\xa5\xec\x13\xab\x89\x76\x0a\xaa\x11\x3c\x50\x73\x43\xf0\x00\x6e\xcb\xf6\x88\x07\xdc\xfe\xd8\x6a\x58\x5b\xbf\xb6\x2b\x87\xc0\x98\x12\x95\x90\x34\xed\xcc\x83\x20\x92\x73\xbc\x8e\x62\x66\x20\xd3\x6e\x85\xa2\x38\x17\xec\x5b\x0e\xff\xaa\x48\x0c\xe6\xd0\x97\x9b\xa2\x54\xcb\x0b\x3e\xa0\xcc\x55\xa2\x08\x16\x81\x34\x6d\xec\x98\xca\x2c\x23\x62\xa9\xe8\x9a\xa3\x47\x80\xe5\x07\x38\x1f\xb5\x43\xb6\x1a\xa3\xfd\xaa\x19\xad\x33\xad\x11\x6d\xfc\xfa\x0c\xf1\xc2\x8f\x18\x7e\xcc\x28\x20\x57\xe6\x48\x43\x21\x60\x3a\x14\x9c\xf4\x39\x4b\xc3\x89\x0f\x73\x88\x33\x99\x76\xe7\x2d\xf2\x6c\x07\x38\x08\xc9\x6e\x64\x0d\x7f\x6f\x57\xae\x37\x3d\xef\x1b\xc2\x04\x60\x22\x48\xe6\xb3\x55\x4c\x11\x52\x10\x86\x11\x9e\x68\x05\xb4\x43\x5e\x7b\x6a\xc2\x33\x71\x10\x24\xc7\x08\x07\xa6\x0d\x9e\xa7\x41\xe9\xa5\x3d\xb1\x14\x14\x88\x54\x27\xb6\x09\x99\x8f\x9e\x71\x0a\x4d\x47\xb2\x28\x4c\xa4\x62\x2a\x2b\x58\x31\x45\x5e\x28\xe6\x16\xf7\x18\x13\x0d\x04\xe9\xf1\x4a\x7e\x99\x11\x26\x42\x9c\x0a\xc2\xe0\x59\x49\x66\x61\xec\xdd\xe1\x13\x88\x53\xd2\xac\x9b\xd9\x66\x00\x71\x62\x28\x45\x56\x83\x74\x58\x76\x6e\xf1\x3f\x2b\xa9\xe1\x76\x70\xac\x38\x1e\x6a\xc5\xd7\x4d\x4c\x6f\xbb\xd6\x8b\xf7\x12\x33\x52\x4c\xb6\x1e\xbb\x1d\xc3\x9d\xa1\x86\x2b\xaf\x6d\xc0\xb6\x0e\x45\x55\x4b\x78\xc2\x99\x78\x5c\x7e\x89\xc3\xb3\x41\x92\x1c\xa5\x36\xd7\x14\x40\xf1\x11\x08\x37\x47\x7a\x04\xfa\x38\xc1\xde\xa6\xea\x70\x4b\x6d\x42\x16\x39\xcb\xc8\xc1\x4f\xa4\xa8\x8f\xe4\xea\x42\x2f\x5e\xd4\xf8\x2d\xb1\xf2\x70\x28\x48\xc7\x56\xdc\xa0\x71\xa8\x5e\xfb\x4a\xee\x14\xd9\x09\x30\xb4\x8a\x94\xea\xd2\xef\xf4\x5f\x86\x64\x73\x6f\x83\xd8\x21\xfd\x72\x67\xfb\xc3\x89\xa8\x2a\xff\xe3\x3c\xde\x0e\x53\xe6\x30\x69\xf6\x9f\xf4\x34\x0c\xab\x73\x3b\x5e\xc9\x08\x2d\xca\x59\x04\x3d\xe2\xd7\x0b\x69\x55\xaf\x27\x83\x9c\x7f\xa1\x1d\x10\x0f\x12\xeb\x18\x52\x5f\xd5\x46\xcc\x6f\xdf\x82\x5c\xe7\xed\xf1\x3d\xda\x8c\x4d\x2f\x74\x9a\x97\xe9\xfa\x97\x58\x49\x47\x38\x23\x1a\xfc\xc1\x3e\xd9\x8f\x35\xd2\x98\x3a\x7d\x0a\x5c\x13\x2e\xde\xbf\x4f\xf2\x8e\xb0\x8e\xca\x0c\x6f\xdd\x3c\xa2\xda\x25\x2a\xe7\xce\x89\x6c\xfd\x45\xeb\x6b\x76\x96\xaa\x5b\x78\x77\xb1\xa2\x44\x88\x76\x80\x29\x89\xe6\xa7\xf4\x42\x17\x9c\xba\x24\x7c\x3b\xf8\xb0\x3d\xea\xbb\x3b\x88\xe9\x75\x7a\xaa\x09\x94\x72\x50\x3b\x3a\x2a\x26\x0c\x1c\x8a\x56\xc6\x9d\x04\xf2\x1d\x67\xfa\x08\xe9\x1c\x1e\x94\x46\x52\xc9\xc3\x02\xc3\xb9\xfb\x13\x1e\x0c\x13\xfd\xd5\x55\xb5\x99\x42\x76\x62\x1c\x0e\x3d\x8d\x77\x52\x72\x20\xa2\x93\x28\x10\x48\x9a\x48\xc1\xcf\x01\x94\xda\x10\xf4\xee\x4a\x68\xa0\x39\x32\x73\x4e\xa4\x32\x8b\x57\x85\xfa\x98\x25\x9a\x7d\x87\x6e\xec\x5d\x56\x7d\x25\x68\xdb\x9b\x50\x6f\x8f\x3d\xfa\xbd\x15\xf1\x97\xd9\x8a\xd0\x67\x4d\xcd\x75\xb5\xb5\x36\x29\x13\x89\x54\x20\xbc\xb1\xa1\x8d\x54\xc9\x01\x09\x85\x44\x01\x32\xe9\x34\x45\x07\x60\xd3\x1c\x49\x31\xfe\x50\x8c\x66\x07\x41\xdc\xb8\xd3\x22\x35\x99\xda\x5f\xb9\x09\x60\x8c\x3f\xd8\x73\xce\x32\x36\x1e\x34\x8e\x55\x1b\x50\xaf\xd9\x5a\xcd\x5d\xa2\x4d\x94\x67\x41\x90\x3d\xd1\x21\x4c\x37\x08\x01\x9d\xc1\x91\xe0\x8c\xd4\x51\x06\xe6\x7e\x24\x3f\xb9\xfa\x06\xe7\xbc\x3a\xa7\xe5\xa5\xbc\x75\x35\x91\xad\x93\x7e\x56\xe9\xd5\x9f\xc6\x76\xb4\xfa\x71\x07\x55\xae\xbd\x4d\x5c\x49\x23\xf4\x54\x03\xd2\x90\x0e\x8f\x7d\xa3\x5f\x02\xa1\x3b\x3e\x2a\xc9\x1d\xbe\x09\xc0\xf1\x6a\xa4\x40\xec\x7c\x6d\xd4\x0f\xae\x08\x5a\x3c\x54\x0a\xcd\xb4\x01\x41\xdd\xfb\xab\x4e\xa6\x1d\x1b\x1c\x5e\x0c\x8d\x32\xdd\x77\x85\x75\x5d\x25\x15\x39\x58\xbc\x0d\x6e\x74\xc2\x63\xb5\xba\x11\xf0\x53\x54\x11\x92\x4a\x35\xe2\x9a\x70\x35\xe6\xa6\xd9\xde\xd6\xc5\x44\x1d\x3a\x06\x19\x4f\x12\x1f\x8b\x84\x94\x32\x37\x72\xac\x7a\x2c\x33\xee\x14\xf4\xf6\xfa\x6a\x01\xae\x83\xf0\x36\xa9\xf7\x72\xc1\xf4\xa1\x7c\x45\x34\x7a\x60\xce\x34\xd9\xf5\xce\x25\x5c\x89\xb6\xc8\x0c\x78\xf2\xe7\x7b\x04\x83\xac\x77\x94\x50\x17\x4d\xed\xdc\x0e\xfa\x7d\x6e\xb8\x1b\x96\x81\xcc\xfd\xdd\x43\xd1\x62\x4c\xd4\x50\x83\x8b\x43\xd6\xd8\x97\xcb\x07\x9e\x05\xd0\xa2\xec\xfb\xff\xa1\x75\xd8\x64\x7b\x78\xaf\x93\x43\x92\x1b\x88\xb4\x3c\x06\x09\xca\x84\x08\x8a\x33\x4a\xb4\xaf\xda\xb8\x61\xc7\x38\x57\x29\x31\x90\x54\x77\x5c\xe6\xd4\x77\x13\x85\x9d\x22\x48\x38\x07\xce\x74\x16\x52\x28\xc5\x29\x70\xe2\xcc\x14\xde\x1a\xb9\x64\xdf\x13\xc6\x73\x84\x84\xd0\x51\x48\xef\x71\x64\x52\x30\x23\x9d\xd0\x13\x36\x64\x46\x9e\x93\x7a\xd8\x92\xc4\x13\x89\x25\x93\xc4\xd4\x5d\x28\xad\x8b\x75\x91\x67\x8e\x52\xc5\x46\xc0\x66\xcf\x50\x1b\xdb\xd1\x4a\x55\xfd\xea\x42\xf2\xcb\xe8\x2e\x41\xe8\xc6\x72\x6b\xd5\xd9\x9a\x62\x5e\xb9\x3f\xb1\x1c\x2e\xcd\xc3\xc8\xea\xac\x47\x1c\x58\x0c\x41\x17\x70\xd8\xec\xfb\x7b\xf9\x17\xb5\x82\x05\x1f\xc9\x99\x2d\x63\x96\x30\x05\x95\xc2\xce\x23\x64\x95\xde\x18\x16\xc5\x1a\x2d\x9a\xb0\x4c\x19\x2f\x82\x94\x0c\x4f\x4c\xa4\xf2\x69\xc6\x80\xcb\x59\x5b\x71\x42\xa1\x87\xd8\xb7\x1a\x5a\x1b\x24\x4c\x98\xd9\xe7\x61\x7d\xb3\x28\x84\x3d\x20\x88\x61\x44\x44\xd3\x7d\x49\x34\xde\x9b\xf8\x74\xf3\x6b\x58\x51\x68\x55\x14\xe8\x6f\xb0\x2d\x79\xab\xf3\x6f\xa8\xf0\x9a\x70\xf7\x64\xf7\x86\xce\x5b\xdb\x8d\x65\x74\xaa\x72\xef\xd9\x5a\x06\x99\x9c\xbe\x47\x72\xc3\x55\x6e\x9f\x8a\x35\xd9\x02\xd5\x4b\xd0\x61\x6c\x45\x95\x48\xb5\xfc\x6e\x90\xff\xc0\x75\xeb\xdf\x8b\x60\x8a\x64\x4b\x61\x48\xf0\xf1\x74\xec\x2c\x9f\xa2\x77\x80\x0e\xf9\x4e\x84\x5d\xbc\x7c\x67\xe8\xd0\xbd\xfa\x51\xde\x2c\x19\xf1\xea\x43\xd3\x47\xad\x1b\x5b\x6d\x83\x5d\x3c\x7a\xad\x63\xb9\xf9\x97\x2d\x5d\x7f\x0b\xd7\xd5\xfb\x11\x63\x08\x3d\x06\xb5\x89\x33\xeb\xfd\x1b\x70\x68\xb0\x99\xe1\x84\xa1\x8a\x6a\x01\x14\x0a\xb9\x67\xf3\xff\x81\x54\xbf\xfa\xba\xfe\x79\x6b\xb0\xfa\xe2\xc4\xfb\x55\x43\x49\x75\x75\xae\x0f\xb8\x37\xfa\x0e\x7c\xf6\xc6\xae\x18\x24\x3a\xa7\x2b\x2a\xaa\xdf\xae\x78\xd5\xa8\xe8\x1e\xe9\xb5\x5c\x32\xdc\xe1\x9b\xb2\x64\xf0\xbd\xa3\x8a\x63\xdb\x9d\x46\x9f\xcc\xf1\x7d\x66\xb7\xf6\x99\x3a\xf0\xaf\x49\x46\x76\x94\x7b\x83\x56\x46\x9c\xd6\x7c\x41\xdc\xbf\xfb\x30\x51\xe1\x4d\xdd\x0f\x7c\xa5\xd2\x68\x81\xcb\x14\x6e\x9f\xf6\x9a\xe7\xda\xba\xc3\xcf\xcb\xc6\xe3\xbf\xe6\x1f\x7c\x6c\x56\xe8\x29\xce\x83\x1d\xe8\x1f\xdd\xe3\x33\xfb\xa1\xd8\xb6\x63\x9f\x1e\x89\xbd\x6d\xdb\x4a\xb4\xdb\xf6\x7e\xc2\xe8\xe7\x01\xae\x4f\xd0\xfa\x87\x77\xf5\xa7\x60\x23\xf7\x09\x56\xed\xbf\xe5\xa7\x7d\xab\x97\xd5\xff\x02\x00\x00\xff\xff\x0a\xb3\x24\xb8\x44\x3d\x00\x00") func dataConfig_schema_v34JsonBytes() ([]byte, error) { return bindataRead( diff --git a/components/cli/cli/compose/schema/data/config_schema_v3.4.json b/components/cli/cli/compose/schema/data/config_schema_v3.4.json index 412f505d2b..79fc4cb614 100644 --- a/components/cli/cli/compose/schema/data/config_schema_v3.4.json +++ b/components/cli/cli/compose/schema/data/config_schema_v3.4.json @@ -324,7 +324,8 @@ {"type": "array", "items": {"type": "string"}} ] }, - "timeout": {"type": "string"} + "timeout": {"type": "string"}, + "start_period": {"type": "string"} } }, "deployment": { diff --git a/components/cli/cli/compose/types/types.go b/components/cli/cli/compose/types/types.go index 8feaf4289d..9686649682 100644 --- a/components/cli/cli/compose/types/types.go +++ b/components/cli/cli/compose/types/types.go @@ -172,7 +172,7 @@ type HealthCheckConfig struct { Timeout string Interval string Retries *uint64 - StartPeriod string + StartPeriod string `mapstructure:"start_period"` Disable bool } From ee93512169063e3316a477d67e23531245967629 Mon Sep 17 00:00:00 2001 From: Daniel Nephin Date: Tue, 29 Aug 2017 13:19:28 -0400 Subject: [PATCH 43/47] Remove test for code not in this repo. Signed-off-by: Daniel Nephin Upstream-commit: dae1b7112c28010be31b187aa578470d5ed6eabd Component: cli --- .../cli/cli/command/container/opts_test.go | 160 +----------------- 1 file changed, 1 insertion(+), 159 deletions(-) diff --git a/components/cli/cli/command/container/opts_test.go b/components/cli/cli/command/container/opts_test.go index 8417959790..08c1d07da3 100644 --- a/components/cli/cli/command/container/opts_test.go +++ b/components/cli/cli/command/container/opts_test.go @@ -1,8 +1,6 @@ package container import ( - "bytes" - "encoding/json" "fmt" "io/ioutil" "os" @@ -14,7 +12,6 @@ import ( "github.com/docker/cli/internal/test/testutil" "github.com/docker/docker/api/types/container" networktypes "github.com/docker/docker/api/types/network" - "github.com/docker/docker/runconfig" "github.com/docker/go-connections/nat" "github.com/pkg/errors" "github.com/spf13/pflag" @@ -115,7 +112,7 @@ func TestParseRunWithInvalidArgs(t *testing.T) { } // nolint: gocyclo -func TestParseRunVolumes(t *testing.T) { +func TestParseWithVolumes(t *testing.T) { // A single volume arr, tryit := setupPlatformVolume([]string{`/tmp`}, []string{`c:\tmp`}) @@ -584,161 +581,6 @@ func TestParseEntryPoint(t *testing.T) { } } -// This tests the cases for binds which are generated through -// DecodeContainerConfig rather than Parse() -// nolint: gocyclo -func TestDecodeContainerConfigVolumes(t *testing.T) { - - // Root to root - bindsOrVols, _ := setupPlatformVolume([]string{`/:/`}, []string{os.Getenv("SystemDrive") + `\:c:\`}) - if _, _, err := callDecodeContainerConfig(nil, bindsOrVols); err == nil { - t.Fatalf("binds %v should have failed", bindsOrVols) - } - if _, _, err := callDecodeContainerConfig(bindsOrVols, nil); err == nil { - t.Fatalf("volume %v should have failed", bindsOrVols) - } - - // No destination path - bindsOrVols, _ = setupPlatformVolume([]string{`/tmp:`}, []string{os.Getenv("TEMP") + `\:`}) - if _, _, err := callDecodeContainerConfig(nil, bindsOrVols); err == nil { - t.Fatalf("binds %v should have failed", bindsOrVols) - } - if _, _, err := callDecodeContainerConfig(bindsOrVols, nil); err == nil { - t.Fatalf("volume %v should have failed", bindsOrVols) - } - - // // No destination path or mode - bindsOrVols, _ = setupPlatformVolume([]string{`/tmp::`}, []string{os.Getenv("TEMP") + `\::`}) - if _, _, err := callDecodeContainerConfig(nil, bindsOrVols); err == nil { - t.Fatalf("binds %v should have failed", bindsOrVols) - } - if _, _, err := callDecodeContainerConfig(bindsOrVols, nil); err == nil { - t.Fatalf("volume %v should have failed", bindsOrVols) - } - - // A whole lot of nothing - bindsOrVols = []string{`:`} - if _, _, err := callDecodeContainerConfig(nil, bindsOrVols); err == nil { - t.Fatalf("binds %v should have failed", bindsOrVols) - } - if _, _, err := callDecodeContainerConfig(bindsOrVols, nil); err == nil { - t.Fatalf("volume %v should have failed", bindsOrVols) - } - - // A whole lot of nothing with no mode - bindsOrVols = []string{`::`} - if _, _, err := callDecodeContainerConfig(nil, bindsOrVols); err == nil { - t.Fatalf("binds %v should have failed", bindsOrVols) - } - if _, _, err := callDecodeContainerConfig(bindsOrVols, nil); err == nil { - t.Fatalf("volume %v should have failed", bindsOrVols) - } - - // Too much including an invalid mode - wTmp := os.Getenv("TEMP") - bindsOrVols, _ = setupPlatformVolume([]string{`/tmp:/tmp:/tmp:/tmp`}, []string{wTmp + ":" + wTmp + ":" + wTmp + ":" + wTmp}) - if _, _, err := callDecodeContainerConfig(nil, bindsOrVols); err == nil { - t.Fatalf("binds %v should have failed", bindsOrVols) - } - if _, _, err := callDecodeContainerConfig(bindsOrVols, nil); err == nil { - t.Fatalf("volume %v should have failed", bindsOrVols) - } - - // Windows specific error tests - if runtime.GOOS == "windows" { - // Volume which does not include a drive letter - bindsOrVols = []string{`\tmp`} - if _, _, err := callDecodeContainerConfig(nil, bindsOrVols); err == nil { - t.Fatalf("binds %v should have failed", bindsOrVols) - } - if _, _, err := callDecodeContainerConfig(bindsOrVols, nil); err == nil { - t.Fatalf("volume %v should have failed", bindsOrVols) - } - - // Root to C-Drive - bindsOrVols = []string{os.Getenv("SystemDrive") + `\:c:`} - if _, _, err := callDecodeContainerConfig(nil, bindsOrVols); err == nil { - t.Fatalf("binds %v should have failed", bindsOrVols) - } - if _, _, err := callDecodeContainerConfig(bindsOrVols, nil); err == nil { - t.Fatalf("volume %v should have failed", bindsOrVols) - } - - // Container path that does not include a drive letter - bindsOrVols = []string{`c:\windows:\somewhere`} - if _, _, err := callDecodeContainerConfig(nil, bindsOrVols); err == nil { - t.Fatalf("binds %v should have failed", bindsOrVols) - } - if _, _, err := callDecodeContainerConfig(bindsOrVols, nil); err == nil { - t.Fatalf("volume %v should have failed", bindsOrVols) - } - } - - // Linux-specific error tests - if runtime.GOOS != "windows" { - // Just root - bindsOrVols = []string{`/`} - if _, _, err := callDecodeContainerConfig(nil, bindsOrVols); err == nil { - t.Fatalf("binds %v should have failed", bindsOrVols) - } - if _, _, err := callDecodeContainerConfig(bindsOrVols, nil); err == nil { - t.Fatalf("volume %v should have failed", bindsOrVols) - } - - // A single volume that looks like a bind mount passed in Volumes. - // This should be handled as a bind mount, not a volume. - vols := []string{`/foo:/bar`} - if config, hostConfig, err := callDecodeContainerConfig(vols, nil); err != nil { - t.Fatal("Volume /foo:/bar should have succeeded as a volume name") - } else if hostConfig.Binds != nil { - t.Fatalf("Error parsing volume flags, /foo:/bar should not mount-bind anything. Received %v", hostConfig.Binds) - } else if _, exists := config.Volumes[vols[0]]; !exists { - t.Fatalf("Error parsing volume flags, /foo:/bar is missing from volumes. Received %v", config.Volumes) - } - - } -} - -// callDecodeContainerConfig is a utility function used by TestDecodeContainerConfigVolumes -// to call DecodeContainerConfig. It effectively does what a client would -// do when calling the daemon by constructing a JSON stream of a -// ContainerConfigWrapper which is populated by the set of volume specs -// passed into it. It returns a config and a hostconfig which can be -// validated to ensure DecodeContainerConfig has manipulated the structures -// correctly. -func callDecodeContainerConfig(volumes []string, binds []string) (*container.Config, *container.HostConfig, error) { - var ( - b []byte - err error - c *container.Config - h *container.HostConfig - ) - w := runconfig.ContainerConfigWrapper{ - Config: &container.Config{ - Volumes: map[string]struct{}{}, - }, - HostConfig: &container.HostConfig{ - NetworkMode: "none", - Binds: binds, - }, - } - for _, v := range volumes { - w.Config.Volumes[v] = struct{}{} - } - if b, err = json.Marshal(w); err != nil { - return nil, nil, errors.Errorf("Error on marshal %s", err.Error()) - } - c, h, _, err = runconfig.DecodeContainerConfig(bytes.NewReader(b)) - if err != nil { - return nil, nil, errors.Errorf("Error parsing %s: %v", string(b), err) - } - if c == nil || h == nil { - return nil, nil, errors.Errorf("Empty config or hostconfig") - } - - return c, h, err -} - func TestValidateDevice(t *testing.T) { valid := []string{ "/home", From 4ac950c1d077fbbb5fb04da7fb0bea7adcac12bc Mon Sep 17 00:00:00 2001 From: Daniel Nephin Date: Tue, 29 Aug 2017 13:22:17 -0400 Subject: [PATCH 44/47] Remove unused vendor. Signed-off-by: Daniel Nephin Upstream-commit: 8edd2dd3df2450d107ed332b6334644057c2238f Component: cli --- components/cli/vendor.conf | 1 - .../docker/docker/pkg/parsers/parsers.go | 69 -- .../docker/docker/pkg/sysinfo/README.md | 1 - .../docker/docker/pkg/sysinfo/numcpu.go | 12 - .../docker/docker/pkg/sysinfo/numcpu_linux.go | 43 -- .../docker/pkg/sysinfo/numcpu_windows.go | 37 -- .../docker/docker/pkg/sysinfo/sysinfo.go | 144 ----- .../docker/pkg/sysinfo/sysinfo_linux.go | 259 -------- .../docker/pkg/sysinfo/sysinfo_solaris.go | 121 ---- .../docker/docker/pkg/sysinfo/sysinfo_unix.go | 9 - .../docker/pkg/sysinfo/sysinfo_windows.go | 9 - .../docker/docker/runconfig/config.go | 108 ---- .../docker/docker/runconfig/config_unix.go | 59 -- .../docker/docker/runconfig/config_windows.go | 19 - .../docker/docker/runconfig/errors.go | 38 -- .../docker/docker/runconfig/hostconfig.go | 80 --- .../docker/runconfig/hostconfig_solaris.go | 46 -- .../docker/runconfig/hostconfig_unix.go | 110 ---- .../docker/runconfig/hostconfig_windows.go | 96 --- .../docker/docker/volume/validate.go | 140 ----- .../docker/volume/validate_test_unix.go | 8 - .../docker/volume/validate_test_windows.go | 6 - .../github.com/docker/docker/volume/volume.go | 374 ----------- .../docker/docker/volume/volume_copy.go | 23 - .../docker/docker/volume/volume_copy_unix.go | 8 - .../docker/volume/volume_copy_windows.go | 6 - .../docker/docker/volume/volume_linux.go | 56 -- .../docker/volume/volume_propagation_linux.go | 47 -- .../volume/volume_propagation_unsupported.go | 24 - .../docker/docker/volume/volume_unix.go | 148 ----- .../docker/volume/volume_unsupported.go | 16 - .../docker/docker/volume/volume_windows.go | 201 ------ .../runc/libcontainer/cgroups/cgroups.go | 64 -- .../cgroups/cgroups_unsupported.go | 3 - .../runc/libcontainer/cgroups/stats.go | 106 ---- .../runc/libcontainer/cgroups/utils.go | 436 ------------- .../runc/libcontainer/configs/blkio_device.go | 61 -- .../runc/libcontainer/configs/cgroup_unix.go | 124 ---- .../configs/cgroup_unsupported.go | 6 - .../libcontainer/configs/cgroup_windows.go | 6 - .../runc/libcontainer/configs/config.go | 332 ---------- .../runc/libcontainer/configs/config_unix.go | 51 -- .../runc/libcontainer/configs/device.go | 57 -- .../libcontainer/configs/device_defaults.go | 111 ---- .../libcontainer/configs/hugepage_limit.go | 9 - .../configs/interface_priority_map.go | 14 - .../runc/libcontainer/configs/mount.go | 39 -- .../runc/libcontainer/configs/namespaces.go | 5 - .../configs/namespaces_syscall.go | 31 - .../configs/namespaces_syscall_unsupported.go | 15 - .../libcontainer/configs/namespaces_unix.go | 127 ---- .../configs/namespaces_unsupported.go | 8 - .../runc/libcontainer/configs/network.go | 72 --- .../github.com/opencontainers/selinux/LICENSE | 201 ------ .../opencontainers/selinux/README.md | 7 - .../selinux/go-selinux/label/label.go | 84 --- .../selinux/go-selinux/label/label_selinux.go | 204 ------ .../selinux/go-selinux/selinux.go | 593 ------------------ .../selinux/go-selinux/xattrs.go | 78 --- 59 files changed, 5162 deletions(-) delete mode 100644 components/cli/vendor/github.com/docker/docker/pkg/parsers/parsers.go delete mode 100644 components/cli/vendor/github.com/docker/docker/pkg/sysinfo/README.md delete mode 100644 components/cli/vendor/github.com/docker/docker/pkg/sysinfo/numcpu.go delete mode 100644 components/cli/vendor/github.com/docker/docker/pkg/sysinfo/numcpu_linux.go delete mode 100644 components/cli/vendor/github.com/docker/docker/pkg/sysinfo/numcpu_windows.go delete mode 100644 components/cli/vendor/github.com/docker/docker/pkg/sysinfo/sysinfo.go delete mode 100644 components/cli/vendor/github.com/docker/docker/pkg/sysinfo/sysinfo_linux.go delete mode 100644 components/cli/vendor/github.com/docker/docker/pkg/sysinfo/sysinfo_solaris.go delete mode 100644 components/cli/vendor/github.com/docker/docker/pkg/sysinfo/sysinfo_unix.go delete mode 100644 components/cli/vendor/github.com/docker/docker/pkg/sysinfo/sysinfo_windows.go delete mode 100644 components/cli/vendor/github.com/docker/docker/runconfig/config.go delete mode 100644 components/cli/vendor/github.com/docker/docker/runconfig/config_unix.go delete mode 100644 components/cli/vendor/github.com/docker/docker/runconfig/config_windows.go delete mode 100644 components/cli/vendor/github.com/docker/docker/runconfig/errors.go delete mode 100644 components/cli/vendor/github.com/docker/docker/runconfig/hostconfig.go delete mode 100644 components/cli/vendor/github.com/docker/docker/runconfig/hostconfig_solaris.go delete mode 100644 components/cli/vendor/github.com/docker/docker/runconfig/hostconfig_unix.go delete mode 100644 components/cli/vendor/github.com/docker/docker/runconfig/hostconfig_windows.go delete mode 100644 components/cli/vendor/github.com/docker/docker/volume/validate.go delete mode 100644 components/cli/vendor/github.com/docker/docker/volume/validate_test_unix.go delete mode 100644 components/cli/vendor/github.com/docker/docker/volume/validate_test_windows.go delete mode 100644 components/cli/vendor/github.com/docker/docker/volume/volume.go delete mode 100644 components/cli/vendor/github.com/docker/docker/volume/volume_copy.go delete mode 100644 components/cli/vendor/github.com/docker/docker/volume/volume_copy_unix.go delete mode 100644 components/cli/vendor/github.com/docker/docker/volume/volume_copy_windows.go delete mode 100644 components/cli/vendor/github.com/docker/docker/volume/volume_linux.go delete mode 100644 components/cli/vendor/github.com/docker/docker/volume/volume_propagation_linux.go delete mode 100644 components/cli/vendor/github.com/docker/docker/volume/volume_propagation_unsupported.go delete mode 100644 components/cli/vendor/github.com/docker/docker/volume/volume_unix.go delete mode 100644 components/cli/vendor/github.com/docker/docker/volume/volume_unsupported.go delete mode 100644 components/cli/vendor/github.com/docker/docker/volume/volume_windows.go delete mode 100644 components/cli/vendor/github.com/opencontainers/runc/libcontainer/cgroups/cgroups.go delete mode 100644 components/cli/vendor/github.com/opencontainers/runc/libcontainer/cgroups/cgroups_unsupported.go delete mode 100644 components/cli/vendor/github.com/opencontainers/runc/libcontainer/cgroups/stats.go delete mode 100644 components/cli/vendor/github.com/opencontainers/runc/libcontainer/cgroups/utils.go delete mode 100644 components/cli/vendor/github.com/opencontainers/runc/libcontainer/configs/blkio_device.go delete mode 100644 components/cli/vendor/github.com/opencontainers/runc/libcontainer/configs/cgroup_unix.go delete mode 100644 components/cli/vendor/github.com/opencontainers/runc/libcontainer/configs/cgroup_unsupported.go delete mode 100644 components/cli/vendor/github.com/opencontainers/runc/libcontainer/configs/cgroup_windows.go delete mode 100644 components/cli/vendor/github.com/opencontainers/runc/libcontainer/configs/config.go delete mode 100644 components/cli/vendor/github.com/opencontainers/runc/libcontainer/configs/config_unix.go delete mode 100644 components/cli/vendor/github.com/opencontainers/runc/libcontainer/configs/device.go delete mode 100644 components/cli/vendor/github.com/opencontainers/runc/libcontainer/configs/device_defaults.go delete mode 100644 components/cli/vendor/github.com/opencontainers/runc/libcontainer/configs/hugepage_limit.go delete mode 100644 components/cli/vendor/github.com/opencontainers/runc/libcontainer/configs/interface_priority_map.go delete mode 100644 components/cli/vendor/github.com/opencontainers/runc/libcontainer/configs/mount.go delete mode 100644 components/cli/vendor/github.com/opencontainers/runc/libcontainer/configs/namespaces.go delete mode 100644 components/cli/vendor/github.com/opencontainers/runc/libcontainer/configs/namespaces_syscall.go delete mode 100644 components/cli/vendor/github.com/opencontainers/runc/libcontainer/configs/namespaces_syscall_unsupported.go delete mode 100644 components/cli/vendor/github.com/opencontainers/runc/libcontainer/configs/namespaces_unix.go delete mode 100644 components/cli/vendor/github.com/opencontainers/runc/libcontainer/configs/namespaces_unsupported.go delete mode 100644 components/cli/vendor/github.com/opencontainers/runc/libcontainer/configs/network.go delete mode 100644 components/cli/vendor/github.com/opencontainers/selinux/LICENSE delete mode 100644 components/cli/vendor/github.com/opencontainers/selinux/README.md delete mode 100644 components/cli/vendor/github.com/opencontainers/selinux/go-selinux/label/label.go delete mode 100644 components/cli/vendor/github.com/opencontainers/selinux/go-selinux/label/label_selinux.go delete mode 100644 components/cli/vendor/github.com/opencontainers/selinux/go-selinux/selinux.go delete mode 100644 components/cli/vendor/github.com/opencontainers/selinux/go-selinux/xattrs.go diff --git a/components/cli/vendor.conf b/components/cli/vendor.conf index d27abce96a..04fc658912 100755 --- a/components/cli/vendor.conf +++ b/components/cli/vendor.conf @@ -32,7 +32,6 @@ 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/opencontainers/selinux v1.0.0-rc1 github.com/pkg/errors 839d9e913e063e28dfd0e6c7b7512793e0a48be9 github.com/pmezard/go-difflib v1.0.0 github.com/russross/blackfriday 1d6b8e9301e720b08a8938b8c25c018285885438 diff --git a/components/cli/vendor/github.com/docker/docker/pkg/parsers/parsers.go b/components/cli/vendor/github.com/docker/docker/pkg/parsers/parsers.go deleted file mode 100644 index acc897168f..0000000000 --- a/components/cli/vendor/github.com/docker/docker/pkg/parsers/parsers.go +++ /dev/null @@ -1,69 +0,0 @@ -// Package parsers provides helper functions to parse and validate different type -// of string. It can be hosts, unix addresses, tcp addresses, filters, kernel -// operating system versions. -package parsers - -import ( - "fmt" - "strconv" - "strings" -) - -// ParseKeyValueOpt parses and validates the specified string as a key/value pair (key=value) -func ParseKeyValueOpt(opt string) (string, string, error) { - parts := strings.SplitN(opt, "=", 2) - if len(parts) != 2 { - return "", "", fmt.Errorf("Unable to parse key/value option: %s", opt) - } - return strings.TrimSpace(parts[0]), strings.TrimSpace(parts[1]), nil -} - -// ParseUintList parses and validates the specified string as the value -// found in some cgroup file (e.g. `cpuset.cpus`, `cpuset.mems`), which could be -// one of the formats below. Note that duplicates are actually allowed in the -// input string. It returns a `map[int]bool` with available elements from `val` -// set to `true`. -// Supported formats: -// 7 -// 1-6 -// 0,3-4,7,8-10 -// 0-0,0,1-7 -// 03,1-3 <- this is gonna get parsed as [1,2,3] -// 3,2,1 -// 0-2,3,1 -func ParseUintList(val string) (map[int]bool, error) { - if val == "" { - return map[int]bool{}, nil - } - - availableInts := make(map[int]bool) - split := strings.Split(val, ",") - errInvalidFormat := fmt.Errorf("invalid format: %s", val) - - for _, r := range split { - if !strings.Contains(r, "-") { - v, err := strconv.Atoi(r) - if err != nil { - return nil, errInvalidFormat - } - availableInts[v] = true - } else { - split := strings.SplitN(r, "-", 2) - min, err := strconv.Atoi(split[0]) - if err != nil { - return nil, errInvalidFormat - } - max, err := strconv.Atoi(split[1]) - if err != nil { - return nil, errInvalidFormat - } - if max < min { - return nil, errInvalidFormat - } - for i := min; i <= max; i++ { - availableInts[i] = true - } - } - } - return availableInts, nil -} diff --git a/components/cli/vendor/github.com/docker/docker/pkg/sysinfo/README.md b/components/cli/vendor/github.com/docker/docker/pkg/sysinfo/README.md deleted file mode 100644 index c1530cef0d..0000000000 --- a/components/cli/vendor/github.com/docker/docker/pkg/sysinfo/README.md +++ /dev/null @@ -1 +0,0 @@ -SysInfo stores information about which features a kernel supports. diff --git a/components/cli/vendor/github.com/docker/docker/pkg/sysinfo/numcpu.go b/components/cli/vendor/github.com/docker/docker/pkg/sysinfo/numcpu.go deleted file mode 100644 index aeb1a3a804..0000000000 --- a/components/cli/vendor/github.com/docker/docker/pkg/sysinfo/numcpu.go +++ /dev/null @@ -1,12 +0,0 @@ -// +build !linux,!windows - -package sysinfo - -import ( - "runtime" -) - -// NumCPU returns the number of CPUs -func NumCPU() int { - return runtime.NumCPU() -} diff --git a/components/cli/vendor/github.com/docker/docker/pkg/sysinfo/numcpu_linux.go b/components/cli/vendor/github.com/docker/docker/pkg/sysinfo/numcpu_linux.go deleted file mode 100644 index 5eacd35121..0000000000 --- a/components/cli/vendor/github.com/docker/docker/pkg/sysinfo/numcpu_linux.go +++ /dev/null @@ -1,43 +0,0 @@ -// +build linux - -package sysinfo - -import ( - "runtime" - "syscall" - "unsafe" -) - -// numCPU queries the system for the count of threads available -// for use to this process. -// -// Issues two syscalls. -// Returns 0 on errors. Use |runtime.NumCPU| in that case. -func numCPU() int { - // Gets the affinity mask for a process: The very one invoking this function. - pid, _, _ := syscall.RawSyscall(syscall.SYS_GETPID, 0, 0, 0) - - var mask [1024 / 64]uintptr - _, _, err := syscall.RawSyscall(syscall.SYS_SCHED_GETAFFINITY, pid, uintptr(len(mask)*8), uintptr(unsafe.Pointer(&mask[0]))) - if err != 0 { - return 0 - } - - // For every available thread a bit is set in the mask. - ncpu := 0 - for _, e := range mask { - if e == 0 { - continue - } - ncpu += int(popcnt(uint64(e))) - } - return ncpu -} - -// NumCPU returns the number of CPUs which are currently online -func NumCPU() int { - if ncpu := numCPU(); ncpu > 0 { - return ncpu - } - return runtime.NumCPU() -} diff --git a/components/cli/vendor/github.com/docker/docker/pkg/sysinfo/numcpu_windows.go b/components/cli/vendor/github.com/docker/docker/pkg/sysinfo/numcpu_windows.go deleted file mode 100644 index 1d89dd5503..0000000000 --- a/components/cli/vendor/github.com/docker/docker/pkg/sysinfo/numcpu_windows.go +++ /dev/null @@ -1,37 +0,0 @@ -// +build windows - -package sysinfo - -import ( - "runtime" - "unsafe" - - "golang.org/x/sys/windows" -) - -var ( - kernel32 = windows.NewLazySystemDLL("kernel32.dll") - getCurrentProcess = kernel32.NewProc("GetCurrentProcess") - getProcessAffinityMask = kernel32.NewProc("GetProcessAffinityMask") -) - -func numCPU() int { - // Gets the affinity mask for a process - var mask, sysmask uintptr - currentProcess, _, _ := getCurrentProcess.Call() - ret, _, _ := getProcessAffinityMask.Call(currentProcess, uintptr(unsafe.Pointer(&mask)), uintptr(unsafe.Pointer(&sysmask))) - if ret == 0 { - return 0 - } - // For every available thread a bit is set in the mask. - ncpu := int(popcnt(uint64(mask))) - return ncpu -} - -// NumCPU returns the number of CPUs which are currently online -func NumCPU() int { - if ncpu := numCPU(); ncpu > 0 { - return ncpu - } - return runtime.NumCPU() -} diff --git a/components/cli/vendor/github.com/docker/docker/pkg/sysinfo/sysinfo.go b/components/cli/vendor/github.com/docker/docker/pkg/sysinfo/sysinfo.go deleted file mode 100644 index f046de4b16..0000000000 --- a/components/cli/vendor/github.com/docker/docker/pkg/sysinfo/sysinfo.go +++ /dev/null @@ -1,144 +0,0 @@ -package sysinfo - -import "github.com/docker/docker/pkg/parsers" - -// SysInfo stores information about which features a kernel supports. -// TODO Windows: Factor out platform specific capabilities. -type SysInfo struct { - // Whether the kernel supports AppArmor or not - AppArmor bool - // Whether the kernel supports Seccomp or not - Seccomp bool - - cgroupMemInfo - cgroupCPUInfo - cgroupBlkioInfo - cgroupCpusetInfo - cgroupPids - - // Whether IPv4 forwarding is supported or not, if this was disabled, networking will not work - IPv4ForwardingDisabled bool - - // Whether bridge-nf-call-iptables is supported or not - BridgeNFCallIPTablesDisabled bool - - // Whether bridge-nf-call-ip6tables is supported or not - BridgeNFCallIP6TablesDisabled bool - - // Whether the cgroup has the mountpoint of "devices" or not - CgroupDevicesEnabled bool -} - -type cgroupMemInfo struct { - // Whether memory limit is supported or not - MemoryLimit bool - - // Whether swap limit is supported or not - SwapLimit bool - - // Whether soft limit is supported or not - MemoryReservation bool - - // Whether OOM killer disable is supported or not - OomKillDisable bool - - // Whether memory swappiness is supported or not - MemorySwappiness bool - - // Whether kernel memory limit is supported or not - KernelMemory bool -} - -type cgroupCPUInfo struct { - // Whether CPU shares is supported or not - CPUShares bool - - // Whether CPU CFS(Completely Fair Scheduler) period is supported or not - CPUCfsPeriod bool - - // Whether CPU CFS(Completely Fair Scheduler) quota is supported or not - CPUCfsQuota bool - - // Whether CPU real-time period is supported or not - CPURealtimePeriod bool - - // Whether CPU real-time runtime is supported or not - CPURealtimeRuntime bool -} - -type cgroupBlkioInfo struct { - // Whether Block IO weight is supported or not - BlkioWeight bool - - // Whether Block IO weight_device is supported or not - BlkioWeightDevice bool - - // Whether Block IO read limit in bytes per second is supported or not - BlkioReadBpsDevice bool - - // Whether Block IO write limit in bytes per second is supported or not - BlkioWriteBpsDevice bool - - // Whether Block IO read limit in IO per second is supported or not - BlkioReadIOpsDevice bool - - // Whether Block IO write limit in IO per second is supported or not - BlkioWriteIOpsDevice bool -} - -type cgroupCpusetInfo struct { - // Whether Cpuset is supported or not - Cpuset bool - - // Available Cpuset's cpus - Cpus string - - // Available Cpuset's memory nodes - Mems string -} - -type cgroupPids struct { - // Whether Pids Limit is supported or not - PidsLimit bool -} - -// IsCpusetCpusAvailable returns `true` if the provided string set is contained -// in cgroup's cpuset.cpus set, `false` otherwise. -// If error is not nil a parsing error occurred. -func (c cgroupCpusetInfo) IsCpusetCpusAvailable(provided string) (bool, error) { - return isCpusetListAvailable(provided, c.Cpus) -} - -// IsCpusetMemsAvailable returns `true` if the provided string set is contained -// in cgroup's cpuset.mems set, `false` otherwise. -// If error is not nil a parsing error occurred. -func (c cgroupCpusetInfo) IsCpusetMemsAvailable(provided string) (bool, error) { - return isCpusetListAvailable(provided, c.Mems) -} - -func isCpusetListAvailable(provided, available string) (bool, error) { - parsedProvided, err := parsers.ParseUintList(provided) - if err != nil { - return false, err - } - parsedAvailable, err := parsers.ParseUintList(available) - if err != nil { - return false, err - } - for k := range parsedProvided { - if !parsedAvailable[k] { - return false, nil - } - } - return true, nil -} - -// Returns bit count of 1, used by NumCPU -func popcnt(x uint64) (n byte) { - x -= (x >> 1) & 0x5555555555555555 - x = (x>>2)&0x3333333333333333 + x&0x3333333333333333 - x += x >> 4 - x &= 0x0f0f0f0f0f0f0f0f - x *= 0x0101010101010101 - return byte(x >> 56) -} diff --git a/components/cli/vendor/github.com/docker/docker/pkg/sysinfo/sysinfo_linux.go b/components/cli/vendor/github.com/docker/docker/pkg/sysinfo/sysinfo_linux.go deleted file mode 100644 index 7ad84a8309..0000000000 --- a/components/cli/vendor/github.com/docker/docker/pkg/sysinfo/sysinfo_linux.go +++ /dev/null @@ -1,259 +0,0 @@ -package sysinfo - -import ( - "fmt" - "io/ioutil" - "os" - "path" - "strings" - "syscall" - - "github.com/Sirupsen/logrus" - "github.com/opencontainers/runc/libcontainer/cgroups" -) - -const ( - // SeccompModeFilter refers to the syscall argument SECCOMP_MODE_FILTER. - SeccompModeFilter = uintptr(2) -) - -func findCgroupMountpoints() (map[string]string, error) { - cgMounts, err := cgroups.GetCgroupMounts(false) - if err != nil { - return nil, fmt.Errorf("Failed to parse cgroup information: %v", err) - } - mps := make(map[string]string) - for _, m := range cgMounts { - for _, ss := range m.Subsystems { - mps[ss] = m.Mountpoint - } - } - return mps, nil -} - -// New returns a new SysInfo, using the filesystem to detect which features -// the kernel supports. If `quiet` is `false` warnings are printed in logs -// whenever an error occurs or misconfigurations are present. -func New(quiet bool) *SysInfo { - sysInfo := &SysInfo{} - cgMounts, err := findCgroupMountpoints() - if err != nil { - logrus.Warnf("Failed to parse cgroup information: %v", err) - } else { - sysInfo.cgroupMemInfo = checkCgroupMem(cgMounts, quiet) - sysInfo.cgroupCPUInfo = checkCgroupCPU(cgMounts, quiet) - sysInfo.cgroupBlkioInfo = checkCgroupBlkioInfo(cgMounts, quiet) - sysInfo.cgroupCpusetInfo = checkCgroupCpusetInfo(cgMounts, quiet) - sysInfo.cgroupPids = checkCgroupPids(quiet) - } - - _, ok := cgMounts["devices"] - sysInfo.CgroupDevicesEnabled = ok - - sysInfo.IPv4ForwardingDisabled = !readProcBool("/proc/sys/net/ipv4/ip_forward") - sysInfo.BridgeNFCallIPTablesDisabled = !readProcBool("/proc/sys/net/bridge/bridge-nf-call-iptables") - sysInfo.BridgeNFCallIP6TablesDisabled = !readProcBool("/proc/sys/net/bridge/bridge-nf-call-ip6tables") - - // Check if AppArmor is supported. - if _, err := os.Stat("/sys/kernel/security/apparmor"); !os.IsNotExist(err) { - sysInfo.AppArmor = true - } - - // Check if Seccomp is supported, via CONFIG_SECCOMP. - if _, _, err := syscall.RawSyscall(syscall.SYS_PRCTL, syscall.PR_GET_SECCOMP, 0, 0); err != syscall.EINVAL { - // Make sure the kernel has CONFIG_SECCOMP_FILTER. - if _, _, err := syscall.RawSyscall(syscall.SYS_PRCTL, syscall.PR_SET_SECCOMP, SeccompModeFilter, 0); err != syscall.EINVAL { - sysInfo.Seccomp = true - } - } - - return sysInfo -} - -// checkCgroupMem reads the memory information from the memory cgroup mount point. -func checkCgroupMem(cgMounts map[string]string, quiet bool) cgroupMemInfo { - mountPoint, ok := cgMounts["memory"] - if !ok { - if !quiet { - logrus.Warn("Your kernel does not support cgroup memory limit") - } - return cgroupMemInfo{} - } - - swapLimit := cgroupEnabled(mountPoint, "memory.memsw.limit_in_bytes") - if !quiet && !swapLimit { - logrus.Warn("Your kernel does not support swap memory limit") - } - memoryReservation := cgroupEnabled(mountPoint, "memory.soft_limit_in_bytes") - if !quiet && !memoryReservation { - logrus.Warn("Your kernel does not support memory reservation") - } - oomKillDisable := cgroupEnabled(mountPoint, "memory.oom_control") - if !quiet && !oomKillDisable { - logrus.Warn("Your kernel does not support oom control") - } - memorySwappiness := cgroupEnabled(mountPoint, "memory.swappiness") - if !quiet && !memorySwappiness { - logrus.Warn("Your kernel does not support memory swappiness") - } - kernelMemory := cgroupEnabled(mountPoint, "memory.kmem.limit_in_bytes") - if !quiet && !kernelMemory { - logrus.Warn("Your kernel does not support kernel memory limit") - } - - return cgroupMemInfo{ - MemoryLimit: true, - SwapLimit: swapLimit, - MemoryReservation: memoryReservation, - OomKillDisable: oomKillDisable, - MemorySwappiness: memorySwappiness, - KernelMemory: kernelMemory, - } -} - -// checkCgroupCPU reads the cpu information from the cpu cgroup mount point. -func checkCgroupCPU(cgMounts map[string]string, quiet bool) cgroupCPUInfo { - mountPoint, ok := cgMounts["cpu"] - if !ok { - if !quiet { - logrus.Warn("Unable to find cpu cgroup in mounts") - } - return cgroupCPUInfo{} - } - - cpuShares := cgroupEnabled(mountPoint, "cpu.shares") - if !quiet && !cpuShares { - logrus.Warn("Your kernel does not support cgroup cpu shares") - } - - cpuCfsPeriod := cgroupEnabled(mountPoint, "cpu.cfs_period_us") - if !quiet && !cpuCfsPeriod { - logrus.Warn("Your kernel does not support cgroup cfs period") - } - - cpuCfsQuota := cgroupEnabled(mountPoint, "cpu.cfs_quota_us") - if !quiet && !cpuCfsQuota { - logrus.Warn("Your kernel does not support cgroup cfs quotas") - } - - cpuRealtimePeriod := cgroupEnabled(mountPoint, "cpu.rt_period_us") - if !quiet && !cpuRealtimePeriod { - logrus.Warn("Your kernel does not support cgroup rt period") - } - - cpuRealtimeRuntime := cgroupEnabled(mountPoint, "cpu.rt_runtime_us") - if !quiet && !cpuRealtimeRuntime { - logrus.Warn("Your kernel does not support cgroup rt runtime") - } - - return cgroupCPUInfo{ - CPUShares: cpuShares, - CPUCfsPeriod: cpuCfsPeriod, - CPUCfsQuota: cpuCfsQuota, - CPURealtimePeriod: cpuRealtimePeriod, - CPURealtimeRuntime: cpuRealtimeRuntime, - } -} - -// checkCgroupBlkioInfo reads the blkio information from the blkio cgroup mount point. -func checkCgroupBlkioInfo(cgMounts map[string]string, quiet bool) cgroupBlkioInfo { - mountPoint, ok := cgMounts["blkio"] - if !ok { - if !quiet { - logrus.Warn("Unable to find blkio cgroup in mounts") - } - return cgroupBlkioInfo{} - } - - weight := cgroupEnabled(mountPoint, "blkio.weight") - if !quiet && !weight { - logrus.Warn("Your kernel does not support cgroup blkio weight") - } - - weightDevice := cgroupEnabled(mountPoint, "blkio.weight_device") - if !quiet && !weightDevice { - logrus.Warn("Your kernel does not support cgroup blkio weight_device") - } - - readBpsDevice := cgroupEnabled(mountPoint, "blkio.throttle.read_bps_device") - if !quiet && !readBpsDevice { - logrus.Warn("Your kernel does not support cgroup blkio throttle.read_bps_device") - } - - writeBpsDevice := cgroupEnabled(mountPoint, "blkio.throttle.write_bps_device") - if !quiet && !writeBpsDevice { - logrus.Warn("Your kernel does not support cgroup blkio throttle.write_bps_device") - } - readIOpsDevice := cgroupEnabled(mountPoint, "blkio.throttle.read_iops_device") - if !quiet && !readIOpsDevice { - logrus.Warn("Your kernel does not support cgroup blkio throttle.read_iops_device") - } - - writeIOpsDevice := cgroupEnabled(mountPoint, "blkio.throttle.write_iops_device") - if !quiet && !writeIOpsDevice { - logrus.Warn("Your kernel does not support cgroup blkio throttle.write_iops_device") - } - return cgroupBlkioInfo{ - BlkioWeight: weight, - BlkioWeightDevice: weightDevice, - BlkioReadBpsDevice: readBpsDevice, - BlkioWriteBpsDevice: writeBpsDevice, - BlkioReadIOpsDevice: readIOpsDevice, - BlkioWriteIOpsDevice: writeIOpsDevice, - } -} - -// checkCgroupCpusetInfo reads the cpuset information from the cpuset cgroup mount point. -func checkCgroupCpusetInfo(cgMounts map[string]string, quiet bool) cgroupCpusetInfo { - mountPoint, ok := cgMounts["cpuset"] - if !ok { - if !quiet { - logrus.Warn("Unable to find cpuset cgroup in mounts") - } - return cgroupCpusetInfo{} - } - - cpus, err := ioutil.ReadFile(path.Join(mountPoint, "cpuset.cpus")) - if err != nil { - return cgroupCpusetInfo{} - } - - mems, err := ioutil.ReadFile(path.Join(mountPoint, "cpuset.mems")) - if err != nil { - return cgroupCpusetInfo{} - } - - return cgroupCpusetInfo{ - Cpuset: true, - Cpus: strings.TrimSpace(string(cpus)), - Mems: strings.TrimSpace(string(mems)), - } -} - -// checkCgroupPids reads the pids information from the pids cgroup mount point. -func checkCgroupPids(quiet bool) cgroupPids { - _, err := cgroups.FindCgroupMountpoint("pids") - if err != nil { - if !quiet { - logrus.Warn(err) - } - return cgroupPids{} - } - - return cgroupPids{ - PidsLimit: true, - } -} - -func cgroupEnabled(mountPoint, name string) bool { - _, err := os.Stat(path.Join(mountPoint, name)) - return err == nil -} - -func readProcBool(path string) bool { - val, err := ioutil.ReadFile(path) - if err != nil { - return false - } - return strings.TrimSpace(string(val)) == "1" -} diff --git a/components/cli/vendor/github.com/docker/docker/pkg/sysinfo/sysinfo_solaris.go b/components/cli/vendor/github.com/docker/docker/pkg/sysinfo/sysinfo_solaris.go deleted file mode 100644 index c858d57e08..0000000000 --- a/components/cli/vendor/github.com/docker/docker/pkg/sysinfo/sysinfo_solaris.go +++ /dev/null @@ -1,121 +0,0 @@ -// +build solaris,cgo - -package sysinfo - -import ( - "bytes" - "os/exec" - "strconv" - "strings" -) - -/* -#cgo LDFLAGS: -llgrp -#include -#include -#include -int getLgrpCount() { - lgrp_cookie_t lgrpcookie = LGRP_COOKIE_NONE; - uint_t nlgrps; - - if ((lgrpcookie = lgrp_init(LGRP_VIEW_OS)) == LGRP_COOKIE_NONE) { - return -1; - } - nlgrps = lgrp_nlgrps(lgrpcookie); - return nlgrps; -} -*/ -import "C" - -// IsCPUSharesAvailable returns whether CPUShares setting is supported. -// We need FSS to be set as default scheduling class to support CPU Shares -func IsCPUSharesAvailable() bool { - cmd := exec.Command("/usr/sbin/dispadmin", "-d") - outBuf := new(bytes.Buffer) - errBuf := new(bytes.Buffer) - cmd.Stderr = errBuf - cmd.Stdout = outBuf - - if err := cmd.Run(); err != nil { - return false - } - return (strings.Contains(outBuf.String(), "FSS")) -} - -// New returns a new SysInfo, using the filesystem to detect which features -// the kernel supports. -//NOTE Solaris: If we change the below capabilities be sure -// to update verifyPlatformContainerSettings() in daemon_solaris.go -func New(quiet bool) *SysInfo { - sysInfo := &SysInfo{} - sysInfo.cgroupMemInfo = setCgroupMem(quiet) - sysInfo.cgroupCPUInfo = setCgroupCPU(quiet) - sysInfo.cgroupBlkioInfo = setCgroupBlkioInfo(quiet) - sysInfo.cgroupCpusetInfo = setCgroupCPUsetInfo(quiet) - - sysInfo.IPv4ForwardingDisabled = false - - sysInfo.AppArmor = false - - return sysInfo -} - -// setCgroupMem reads the memory information for Solaris. -func setCgroupMem(quiet bool) cgroupMemInfo { - - return cgroupMemInfo{ - MemoryLimit: true, - SwapLimit: true, - MemoryReservation: false, - OomKillDisable: false, - MemorySwappiness: false, - KernelMemory: false, - } -} - -// setCgroupCPU reads the cpu information for Solaris. -func setCgroupCPU(quiet bool) cgroupCPUInfo { - - return cgroupCPUInfo{ - CPUShares: true, - CPUCfsPeriod: false, - CPUCfsQuota: true, - CPURealtimePeriod: false, - CPURealtimeRuntime: false, - } -} - -// blkio switches are not supported in Solaris. -func setCgroupBlkioInfo(quiet bool) cgroupBlkioInfo { - - return cgroupBlkioInfo{ - BlkioWeight: false, - BlkioWeightDevice: false, - } -} - -// setCgroupCPUsetInfo reads the cpuset information for Solaris. -func setCgroupCPUsetInfo(quiet bool) cgroupCpusetInfo { - - return cgroupCpusetInfo{ - Cpuset: true, - Cpus: getCPUCount(), - Mems: getLgrpCount(), - } -} - -func getCPUCount() string { - ncpus := C.sysconf(C._SC_NPROCESSORS_ONLN) - if ncpus <= 0 { - return "" - } - return strconv.FormatInt(int64(ncpus), 16) -} - -func getLgrpCount() string { - nlgrps := C.getLgrpCount() - if nlgrps <= 0 { - return "" - } - return strconv.FormatInt(int64(nlgrps), 16) -} diff --git a/components/cli/vendor/github.com/docker/docker/pkg/sysinfo/sysinfo_unix.go b/components/cli/vendor/github.com/docker/docker/pkg/sysinfo/sysinfo_unix.go deleted file mode 100644 index 45f3ef1c65..0000000000 --- a/components/cli/vendor/github.com/docker/docker/pkg/sysinfo/sysinfo_unix.go +++ /dev/null @@ -1,9 +0,0 @@ -// +build !linux,!solaris,!windows - -package sysinfo - -// New returns an empty SysInfo for non linux nor solaris for now. -func New(quiet bool) *SysInfo { - sysInfo := &SysInfo{} - return sysInfo -} diff --git a/components/cli/vendor/github.com/docker/docker/pkg/sysinfo/sysinfo_windows.go b/components/cli/vendor/github.com/docker/docker/pkg/sysinfo/sysinfo_windows.go deleted file mode 100644 index 4e6255bc59..0000000000 --- a/components/cli/vendor/github.com/docker/docker/pkg/sysinfo/sysinfo_windows.go +++ /dev/null @@ -1,9 +0,0 @@ -// +build windows - -package sysinfo - -// New returns an empty SysInfo for windows for now. -func New(quiet bool) *SysInfo { - sysInfo := &SysInfo{} - return sysInfo -} diff --git a/components/cli/vendor/github.com/docker/docker/runconfig/config.go b/components/cli/vendor/github.com/docker/docker/runconfig/config.go deleted file mode 100644 index c9dc6e96ea..0000000000 --- a/components/cli/vendor/github.com/docker/docker/runconfig/config.go +++ /dev/null @@ -1,108 +0,0 @@ -package runconfig - -import ( - "encoding/json" - "fmt" - "io" - - "github.com/docker/docker/api/types/container" - networktypes "github.com/docker/docker/api/types/network" - "github.com/docker/docker/pkg/sysinfo" - "github.com/docker/docker/volume" -) - -// ContainerDecoder implements httputils.ContainerDecoder -// calling DecodeContainerConfig. -type ContainerDecoder struct{} - -// DecodeConfig makes ContainerDecoder to implement httputils.ContainerDecoder -func (r ContainerDecoder) DecodeConfig(src io.Reader) (*container.Config, *container.HostConfig, *networktypes.NetworkingConfig, error) { - return DecodeContainerConfig(src) -} - -// DecodeHostConfig makes ContainerDecoder to implement httputils.ContainerDecoder -func (r ContainerDecoder) DecodeHostConfig(src io.Reader) (*container.HostConfig, error) { - return DecodeHostConfig(src) -} - -// DecodeContainerConfig decodes a json encoded config into a ContainerConfigWrapper -// struct and returns both a Config and a HostConfig struct -// Be aware this function is not checking whether the resulted structs are nil, -// it's your business to do so -func DecodeContainerConfig(src io.Reader) (*container.Config, *container.HostConfig, *networktypes.NetworkingConfig, error) { - var w ContainerConfigWrapper - - decoder := json.NewDecoder(src) - if err := decoder.Decode(&w); err != nil { - return nil, nil, nil, err - } - - hc := w.getHostConfig() - - // Perform platform-specific processing of Volumes and Binds. - if w.Config != nil && hc != nil { - - // Initialize the volumes map if currently nil - if w.Config.Volumes == nil { - w.Config.Volumes = make(map[string]struct{}) - } - - // Now validate all the volumes and binds - if err := validateMountSettings(w.Config, hc); err != nil { - return nil, nil, nil, err - } - } - - // Certain parameters need daemon-side validation that cannot be done - // on the client, as only the daemon knows what is valid for the platform. - if err := validateNetMode(w.Config, hc); err != nil { - return nil, nil, nil, err - } - - // Validate isolation - if err := validateIsolation(hc); err != nil { - return nil, nil, nil, err - } - - // Validate QoS - if err := validateQoS(hc); err != nil { - return nil, nil, nil, err - } - - // Validate Resources - if err := validateResources(hc, sysinfo.New(true)); err != nil { - return nil, nil, nil, err - } - - // Validate Privileged - if err := validatePrivileged(hc); err != nil { - return nil, nil, nil, err - } - - // Validate ReadonlyRootfs - if err := validateReadonlyRootfs(hc); err != nil { - return nil, nil, nil, err - } - - return w.Config, hc, w.NetworkingConfig, nil -} - -// validateMountSettings validates each of the volumes and bind settings -// passed by the caller to ensure they are valid. -func validateMountSettings(c *container.Config, hc *container.HostConfig) error { - // it is ok to have len(hc.Mounts) > 0 && (len(hc.Binds) > 0 || len (c.Volumes) > 0 || len (hc.Tmpfs) > 0 ) - - // Ensure all volumes and binds are valid. - for spec := range c.Volumes { - if _, err := volume.ParseMountRaw(spec, hc.VolumeDriver); err != nil { - return fmt.Errorf("invalid volume spec %q: %v", spec, err) - } - } - for _, spec := range hc.Binds { - if _, err := volume.ParseMountRaw(spec, hc.VolumeDriver); err != nil { - return fmt.Errorf("invalid bind mount spec %q: %v", spec, err) - } - } - - return nil -} diff --git a/components/cli/vendor/github.com/docker/docker/runconfig/config_unix.go b/components/cli/vendor/github.com/docker/docker/runconfig/config_unix.go deleted file mode 100644 index b4fbfb2799..0000000000 --- a/components/cli/vendor/github.com/docker/docker/runconfig/config_unix.go +++ /dev/null @@ -1,59 +0,0 @@ -// +build !windows - -package runconfig - -import ( - "github.com/docker/docker/api/types/container" - networktypes "github.com/docker/docker/api/types/network" -) - -// ContainerConfigWrapper is a Config wrapper that holds the container Config (portable) -// and the corresponding HostConfig (non-portable). -type ContainerConfigWrapper struct { - *container.Config - InnerHostConfig *container.HostConfig `json:"HostConfig,omitempty"` - Cpuset string `json:",omitempty"` // Deprecated. Exported for backwards compatibility. - NetworkingConfig *networktypes.NetworkingConfig `json:"NetworkingConfig,omitempty"` - *container.HostConfig // Deprecated. Exported to read attributes from json that are not in the inner host config structure. -} - -// getHostConfig gets the HostConfig of the Config. -// It's mostly there to handle Deprecated fields of the ContainerConfigWrapper -func (w *ContainerConfigWrapper) getHostConfig() *container.HostConfig { - hc := w.HostConfig - - if hc == nil && w.InnerHostConfig != nil { - hc = w.InnerHostConfig - } else if w.InnerHostConfig != nil { - if hc.Memory != 0 && w.InnerHostConfig.Memory == 0 { - w.InnerHostConfig.Memory = hc.Memory - } - if hc.MemorySwap != 0 && w.InnerHostConfig.MemorySwap == 0 { - w.InnerHostConfig.MemorySwap = hc.MemorySwap - } - if hc.CPUShares != 0 && w.InnerHostConfig.CPUShares == 0 { - w.InnerHostConfig.CPUShares = hc.CPUShares - } - if hc.CpusetCpus != "" && w.InnerHostConfig.CpusetCpus == "" { - w.InnerHostConfig.CpusetCpus = hc.CpusetCpus - } - - if hc.VolumeDriver != "" && w.InnerHostConfig.VolumeDriver == "" { - w.InnerHostConfig.VolumeDriver = hc.VolumeDriver - } - - hc = w.InnerHostConfig - } - - if hc != nil { - if w.Cpuset != "" && hc.CpusetCpus == "" { - hc.CpusetCpus = w.Cpuset - } - } - - // Make sure NetworkMode has an acceptable value. We do this to ensure - // backwards compatible API behavior. - SetDefaultNetModeIfBlank(hc) - - return hc -} diff --git a/components/cli/vendor/github.com/docker/docker/runconfig/config_windows.go b/components/cli/vendor/github.com/docker/docker/runconfig/config_windows.go deleted file mode 100644 index f2361b554b..0000000000 --- a/components/cli/vendor/github.com/docker/docker/runconfig/config_windows.go +++ /dev/null @@ -1,19 +0,0 @@ -package runconfig - -import ( - "github.com/docker/docker/api/types/container" - networktypes "github.com/docker/docker/api/types/network" -) - -// ContainerConfigWrapper is a Config wrapper that holds the container Config (portable) -// and the corresponding HostConfig (non-portable). -type ContainerConfigWrapper struct { - *container.Config - HostConfig *container.HostConfig `json:"HostConfig,omitempty"` - NetworkingConfig *networktypes.NetworkingConfig `json:"NetworkingConfig,omitempty"` -} - -// getHostConfig gets the HostConfig of the Config. -func (w *ContainerConfigWrapper) getHostConfig() *container.HostConfig { - return w.HostConfig -} diff --git a/components/cli/vendor/github.com/docker/docker/runconfig/errors.go b/components/cli/vendor/github.com/docker/docker/runconfig/errors.go deleted file mode 100644 index c95a2919e8..0000000000 --- a/components/cli/vendor/github.com/docker/docker/runconfig/errors.go +++ /dev/null @@ -1,38 +0,0 @@ -package runconfig - -import ( - "fmt" -) - -var ( - // ErrConflictContainerNetworkAndLinks conflict between --net=container and links - ErrConflictContainerNetworkAndLinks = fmt.Errorf("conflicting options: container type network can't be used with links. This would result in undefined behavior") - // ErrConflictSharedNetwork conflict between private and other networks - ErrConflictSharedNetwork = fmt.Errorf("container sharing network namespace with another container or host cannot be connected to any other network") - // ErrConflictHostNetwork conflict from being disconnected from host network or connected to host network. - ErrConflictHostNetwork = fmt.Errorf("container cannot be disconnected from host network or connected to host network") - // ErrConflictNoNetwork conflict between private and other networks - ErrConflictNoNetwork = fmt.Errorf("container cannot be connected to multiple networks with one of the networks in private (none) mode") - // ErrConflictNetworkAndDNS conflict between --dns and the network mode - ErrConflictNetworkAndDNS = fmt.Errorf("conflicting options: dns and the network mode") - // ErrConflictNetworkHostname conflict between the hostname and the network mode - ErrConflictNetworkHostname = fmt.Errorf("conflicting options: hostname and the network mode") - // ErrConflictHostNetworkAndLinks conflict between --net=host and links - ErrConflictHostNetworkAndLinks = fmt.Errorf("conflicting options: host type networking can't be used with links. This would result in undefined behavior") - // ErrConflictContainerNetworkAndMac conflict between the mac address and the network mode - ErrConflictContainerNetworkAndMac = fmt.Errorf("conflicting options: mac-address and the network mode") - // ErrConflictNetworkHosts conflict between add-host and the network mode - ErrConflictNetworkHosts = fmt.Errorf("conflicting options: custom host-to-IP mapping and the network mode") - // ErrConflictNetworkPublishPorts conflict between the publish options and the network mode - ErrConflictNetworkPublishPorts = fmt.Errorf("conflicting options: port publishing and the container type network mode") - // ErrConflictNetworkExposePorts conflict between the expose option and the network mode - ErrConflictNetworkExposePorts = fmt.Errorf("conflicting options: port exposing and the container type network mode") - // ErrUnsupportedNetworkAndIP conflict between network mode and requested ip address - ErrUnsupportedNetworkAndIP = fmt.Errorf("user specified IP address is supported on user defined networks only") - // ErrUnsupportedNetworkNoSubnetAndIP conflict between network with no configured subnet and requested ip address - ErrUnsupportedNetworkNoSubnetAndIP = fmt.Errorf("user specified IP address is supported only when connecting to networks with user configured subnets") - // ErrUnsupportedNetworkAndAlias conflict between network mode and alias - ErrUnsupportedNetworkAndAlias = fmt.Errorf("network-scoped alias is supported only for containers in user defined networks") - // ErrConflictUTSHostname conflict between the hostname and the UTS mode - ErrConflictUTSHostname = fmt.Errorf("conflicting options: hostname and the UTS mode") -) diff --git a/components/cli/vendor/github.com/docker/docker/runconfig/hostconfig.go b/components/cli/vendor/github.com/docker/docker/runconfig/hostconfig.go deleted file mode 100644 index 24aed1935e..0000000000 --- a/components/cli/vendor/github.com/docker/docker/runconfig/hostconfig.go +++ /dev/null @@ -1,80 +0,0 @@ -package runconfig - -import ( - "encoding/json" - "fmt" - "io" - "strings" - - "github.com/docker/docker/api/types/container" -) - -// DecodeHostConfig creates a HostConfig based on the specified Reader. -// It assumes the content of the reader will be JSON, and decodes it. -func DecodeHostConfig(src io.Reader) (*container.HostConfig, error) { - decoder := json.NewDecoder(src) - - var w ContainerConfigWrapper - if err := decoder.Decode(&w); err != nil { - return nil, err - } - - hc := w.getHostConfig() - return hc, nil -} - -// SetDefaultNetModeIfBlank changes the NetworkMode in a HostConfig structure -// to default if it is not populated. This ensures backwards compatibility after -// the validation of the network mode was moved from the docker CLI to the -// docker daemon. -func SetDefaultNetModeIfBlank(hc *container.HostConfig) { - if hc != nil { - if hc.NetworkMode == container.NetworkMode("") { - hc.NetworkMode = container.NetworkMode("default") - } - } -} - -// validateNetContainerMode ensures that the various combinations of requested -// network settings wrt container mode are valid. -func validateNetContainerMode(c *container.Config, hc *container.HostConfig) error { - // We may not be passed a host config, such as in the case of docker commit - if hc == nil { - return nil - } - parts := strings.Split(string(hc.NetworkMode), ":") - if parts[0] == "container" { - if len(parts) < 2 || parts[1] == "" { - return fmt.Errorf("Invalid network mode: invalid container format container:") - } - } - - if hc.NetworkMode.IsContainer() && c.Hostname != "" { - return ErrConflictNetworkHostname - } - - if hc.NetworkMode.IsContainer() && len(hc.Links) > 0 { - return ErrConflictContainerNetworkAndLinks - } - - if hc.NetworkMode.IsContainer() && len(hc.DNS) > 0 { - return ErrConflictNetworkAndDNS - } - - if hc.NetworkMode.IsContainer() && len(hc.ExtraHosts) > 0 { - return ErrConflictNetworkHosts - } - - if (hc.NetworkMode.IsContainer() || hc.NetworkMode.IsHost()) && c.MacAddress != "" { - return ErrConflictContainerNetworkAndMac - } - - if hc.NetworkMode.IsContainer() && (len(hc.PortBindings) > 0 || hc.PublishAllPorts == true) { - return ErrConflictNetworkPublishPorts - } - - if hc.NetworkMode.IsContainer() && len(c.ExposedPorts) > 0 { - return ErrConflictNetworkExposePorts - } - return nil -} diff --git a/components/cli/vendor/github.com/docker/docker/runconfig/hostconfig_solaris.go b/components/cli/vendor/github.com/docker/docker/runconfig/hostconfig_solaris.go deleted file mode 100644 index 5b6e13dc9d..0000000000 --- a/components/cli/vendor/github.com/docker/docker/runconfig/hostconfig_solaris.go +++ /dev/null @@ -1,46 +0,0 @@ -package runconfig - -import ( - "github.com/docker/docker/api/types/container" - "github.com/docker/docker/pkg/sysinfo" -) - -// DefaultDaemonNetworkMode returns the default network stack the daemon should -// use. -func DefaultDaemonNetworkMode() container.NetworkMode { - return container.NetworkMode("bridge") -} - -// IsPreDefinedNetwork indicates if a network is predefined by the daemon -func IsPreDefinedNetwork(network string) bool { - return false -} - -// validateNetMode ensures that the various combinations of requested -// network settings are valid. -func validateNetMode(c *container.Config, hc *container.HostConfig) error { - // We may not be passed a host config, such as in the case of docker commit - return nil -} - -// validateIsolation performs platform specific validation of the -// isolation level in the hostconfig structure. -// This setting is currently discarded for Solaris so this is a no-op. -func validateIsolation(hc *container.HostConfig) error { - return nil -} - -// validateQoS performs platform specific validation of the QoS settings -func validateQoS(hc *container.HostConfig) error { - return nil -} - -// validateResources performs platform specific validation of the resource settings -func validateResources(hc *container.HostConfig, si *sysinfo.SysInfo) error { - return nil -} - -// validatePrivileged performs platform specific validation of the Privileged setting -func validatePrivileged(hc *container.HostConfig) error { - return nil -} diff --git a/components/cli/vendor/github.com/docker/docker/runconfig/hostconfig_unix.go b/components/cli/vendor/github.com/docker/docker/runconfig/hostconfig_unix.go deleted file mode 100644 index 55df5da3ff..0000000000 --- a/components/cli/vendor/github.com/docker/docker/runconfig/hostconfig_unix.go +++ /dev/null @@ -1,110 +0,0 @@ -// +build !windows,!solaris - -package runconfig - -import ( - "fmt" - "runtime" - - "github.com/docker/docker/api/types/container" - "github.com/docker/docker/pkg/sysinfo" -) - -// DefaultDaemonNetworkMode returns the default network stack the daemon should -// use. -func DefaultDaemonNetworkMode() container.NetworkMode { - return container.NetworkMode("bridge") -} - -// IsPreDefinedNetwork indicates if a network is predefined by the daemon -func IsPreDefinedNetwork(network string) bool { - n := container.NetworkMode(network) - return n.IsBridge() || n.IsHost() || n.IsNone() || n.IsDefault() -} - -// validateNetMode ensures that the various combinations of requested -// network settings are valid. -func validateNetMode(c *container.Config, hc *container.HostConfig) error { - // We may not be passed a host config, such as in the case of docker commit - if hc == nil { - return nil - } - - err := validateNetContainerMode(c, hc) - if err != nil { - return err - } - - if hc.UTSMode.IsHost() && c.Hostname != "" { - return ErrConflictUTSHostname - } - - if hc.NetworkMode.IsHost() && len(hc.Links) > 0 { - return ErrConflictHostNetworkAndLinks - } - - return nil -} - -// validateIsolation performs platform specific validation of -// isolation in the hostconfig structure. Linux only supports "default" -// which is LXC container isolation -func validateIsolation(hc *container.HostConfig) error { - // We may not be passed a host config, such as in the case of docker commit - if hc == nil { - return nil - } - if !hc.Isolation.IsValid() { - return fmt.Errorf("Invalid isolation: %q - %s only supports 'default'", hc.Isolation, runtime.GOOS) - } - return nil -} - -// validateQoS performs platform specific validation of the QoS settings -func validateQoS(hc *container.HostConfig) error { - // We may not be passed a host config, such as in the case of docker commit - if hc == nil { - return nil - } - - if hc.IOMaximumBandwidth != 0 { - return fmt.Errorf("Invalid QoS settings: %s does not support configuration of maximum bandwidth", runtime.GOOS) - } - - if hc.IOMaximumIOps != 0 { - return fmt.Errorf("Invalid QoS settings: %s does not support configuration of maximum IOPs", runtime.GOOS) - } - return nil -} - -// validateResources performs platform specific validation of the resource settings -// cpu-rt-runtime and cpu-rt-period can not be greater than their parent, cpu-rt-runtime requires sys_nice -func validateResources(hc *container.HostConfig, si *sysinfo.SysInfo) error { - // We may not be passed a host config, such as in the case of docker commit - if hc == nil { - return nil - } - - if hc.Resources.CPURealtimePeriod > 0 && !si.CPURealtimePeriod { - return fmt.Errorf("Your kernel does not support cgroup cpu real-time period") - } - - if hc.Resources.CPURealtimeRuntime > 0 && !si.CPURealtimeRuntime { - return fmt.Errorf("Your kernel does not support cgroup cpu real-time runtime") - } - - if hc.Resources.CPURealtimePeriod != 0 && hc.Resources.CPURealtimeRuntime != 0 && hc.Resources.CPURealtimeRuntime > hc.Resources.CPURealtimePeriod { - return fmt.Errorf("cpu real-time runtime cannot be higher than cpu real-time period") - } - return nil -} - -// validatePrivileged performs platform specific validation of the Privileged setting -func validatePrivileged(hc *container.HostConfig) error { - return nil -} - -// validateReadonlyRootfs performs platform specific validation of the ReadonlyRootfs setting -func validateReadonlyRootfs(hc *container.HostConfig) error { - return nil -} diff --git a/components/cli/vendor/github.com/docker/docker/runconfig/hostconfig_windows.go b/components/cli/vendor/github.com/docker/docker/runconfig/hostconfig_windows.go deleted file mode 100644 index 5eb956d1b4..0000000000 --- a/components/cli/vendor/github.com/docker/docker/runconfig/hostconfig_windows.go +++ /dev/null @@ -1,96 +0,0 @@ -package runconfig - -import ( - "fmt" - - "github.com/docker/docker/api/types/container" - "github.com/docker/docker/pkg/sysinfo" -) - -// DefaultDaemonNetworkMode returns the default network stack the daemon should -// use. -func DefaultDaemonNetworkMode() container.NetworkMode { - return container.NetworkMode("nat") -} - -// IsPreDefinedNetwork indicates if a network is predefined by the daemon -func IsPreDefinedNetwork(network string) bool { - return !container.NetworkMode(network).IsUserDefined() -} - -// validateNetMode ensures that the various combinations of requested -// network settings are valid. -func validateNetMode(c *container.Config, hc *container.HostConfig) error { - if hc == nil { - return nil - } - - err := validateNetContainerMode(c, hc) - if err != nil { - return err - } - - if hc.NetworkMode.IsContainer() && hc.Isolation.IsHyperV() { - return fmt.Errorf("Using the network stack of another container is not supported while using Hyper-V Containers") - } - - return nil -} - -// validateIsolation performs platform specific validation of the -// isolation in the hostconfig structure. Windows supports 'default' (or -// blank), 'process', or 'hyperv'. -func validateIsolation(hc *container.HostConfig) error { - // We may not be passed a host config, such as in the case of docker commit - if hc == nil { - return nil - } - if !hc.Isolation.IsValid() { - return fmt.Errorf("Invalid isolation: %q. Windows supports 'default', 'process', or 'hyperv'", hc.Isolation) - } - return nil -} - -// validateQoS performs platform specific validation of the Qos settings -func validateQoS(hc *container.HostConfig) error { - return nil -} - -// validateResources performs platform specific validation of the resource settings -func validateResources(hc *container.HostConfig, si *sysinfo.SysInfo) error { - // We may not be passed a host config, such as in the case of docker commit - if hc == nil { - return nil - } - if hc.Resources.CPURealtimePeriod != 0 { - return fmt.Errorf("Windows does not support CPU real-time period") - } - if hc.Resources.CPURealtimeRuntime != 0 { - return fmt.Errorf("Windows does not support CPU real-time runtime") - } - return nil -} - -// validatePrivileged performs platform specific validation of the Privileged setting -func validatePrivileged(hc *container.HostConfig) error { - // We may not be passed a host config, such as in the case of docker commit - if hc == nil { - return nil - } - if hc.Privileged { - return fmt.Errorf("Windows does not support privileged mode") - } - return nil -} - -// validateReadonlyRootfs performs platform specific validation of the ReadonlyRootfs setting -func validateReadonlyRootfs(hc *container.HostConfig) error { - // We may not be passed a host config, such as in the case of docker commit - if hc == nil { - return nil - } - if hc.ReadonlyRootfs { - return fmt.Errorf("Windows does not support root filesystem in read-only mode") - } - return nil -} diff --git a/components/cli/vendor/github.com/docker/docker/volume/validate.go b/components/cli/vendor/github.com/docker/docker/volume/validate.go deleted file mode 100644 index 42396a0dad..0000000000 --- a/components/cli/vendor/github.com/docker/docker/volume/validate.go +++ /dev/null @@ -1,140 +0,0 @@ -package volume - -import ( - "errors" - "fmt" - "os" - "path/filepath" - - "github.com/docker/docker/api/types/mount" -) - -var errBindNotExist = errors.New("bind source path does not exist") - -type validateOpts struct { - skipBindSourceCheck bool - skipAbsolutePathCheck bool -} - -func validateMountConfig(mnt *mount.Mount, options ...func(*validateOpts)) error { - opts := validateOpts{} - for _, o := range options { - o(&opts) - } - - if len(mnt.Target) == 0 { - return &errMountConfig{mnt, errMissingField("Target")} - } - - if err := validateNotRoot(mnt.Target); err != nil { - return &errMountConfig{mnt, err} - } - - if !opts.skipAbsolutePathCheck { - if err := validateAbsolute(mnt.Target); err != nil { - return &errMountConfig{mnt, err} - } - } - - switch mnt.Type { - case mount.TypeBind: - if len(mnt.Source) == 0 { - return &errMountConfig{mnt, errMissingField("Source")} - } - // Don't error out just because the propagation mode is not supported on the platform - if opts := mnt.BindOptions; opts != nil { - if len(opts.Propagation) > 0 && len(propagationModes) > 0 { - if _, ok := propagationModes[opts.Propagation]; !ok { - return &errMountConfig{mnt, fmt.Errorf("invalid propagation mode: %s", opts.Propagation)} - } - } - } - if mnt.VolumeOptions != nil { - return &errMountConfig{mnt, errExtraField("VolumeOptions")} - } - - if err := validateAbsolute(mnt.Source); err != nil { - return &errMountConfig{mnt, err} - } - - // Do not allow binding to non-existent path - if !opts.skipBindSourceCheck { - fi, err := os.Stat(mnt.Source) - if err != nil { - if !os.IsNotExist(err) { - return &errMountConfig{mnt, err} - } - return &errMountConfig{mnt, errBindNotExist} - } - if err := validateStat(fi); err != nil { - return &errMountConfig{mnt, err} - } - } - case mount.TypeVolume: - if mnt.BindOptions != nil { - return &errMountConfig{mnt, errExtraField("BindOptions")} - } - - if len(mnt.Source) == 0 && mnt.ReadOnly { - return &errMountConfig{mnt, fmt.Errorf("must not set ReadOnly mode when using anonymous volumes")} - } - - if len(mnt.Source) != 0 { - if valid, err := IsVolumeNameValid(mnt.Source); !valid { - if err == nil { - err = errors.New("invalid volume name") - } - return &errMountConfig{mnt, err} - } - } - case mount.TypeTmpfs: - if len(mnt.Source) != 0 { - return &errMountConfig{mnt, errExtraField("Source")} - } - if err := ValidateTmpfsMountDestination(mnt.Target); err != nil { - return &errMountConfig{mnt, err} - } - if _, err := ConvertTmpfsOptions(mnt.TmpfsOptions, mnt.ReadOnly); err != nil { - return &errMountConfig{mnt, err} - } - default: - return &errMountConfig{mnt, errors.New("mount type unknown")} - } - return nil -} - -type errMountConfig struct { - mount *mount.Mount - err error -} - -func (e *errMountConfig) Error() string { - return fmt.Sprintf("invalid mount config for type %q: %v", e.mount.Type, e.err.Error()) -} - -func errExtraField(name string) error { - return fmt.Errorf("field %s must not be specified", name) -} -func errMissingField(name string) error { - return fmt.Errorf("field %s must not be empty", name) -} - -func validateAbsolute(p string) error { - p = convertSlash(p) - if filepath.IsAbs(p) { - return nil - } - return fmt.Errorf("invalid mount path: '%s' mount path must be absolute", p) -} - -// ValidateTmpfsMountDestination validates the destination of tmpfs mount. -// Currently, we have only two obvious rule for validation: -// - path must not be "/" -// - path must be absolute -// We should add more rules carefully (#30166) -func ValidateTmpfsMountDestination(dest string) error { - if err := validateNotRoot(dest); err != nil { - return err - } - return validateAbsolute(dest) -} diff --git a/components/cli/vendor/github.com/docker/docker/volume/validate_test_unix.go b/components/cli/vendor/github.com/docker/docker/volume/validate_test_unix.go deleted file mode 100644 index dd1de2f643..0000000000 --- a/components/cli/vendor/github.com/docker/docker/volume/validate_test_unix.go +++ /dev/null @@ -1,8 +0,0 @@ -// +build !windows - -package volume - -var ( - testDestinationPath = "/foo" - testSourcePath = "/foo" -) diff --git a/components/cli/vendor/github.com/docker/docker/volume/validate_test_windows.go b/components/cli/vendor/github.com/docker/docker/volume/validate_test_windows.go deleted file mode 100644 index d5f86ac850..0000000000 --- a/components/cli/vendor/github.com/docker/docker/volume/validate_test_windows.go +++ /dev/null @@ -1,6 +0,0 @@ -package volume - -var ( - testDestinationPath = `c:\foo` - testSourcePath = `c:\foo` -) diff --git a/components/cli/vendor/github.com/docker/docker/volume/volume.go b/components/cli/vendor/github.com/docker/docker/volume/volume.go deleted file mode 100644 index 8598d4cb8f..0000000000 --- a/components/cli/vendor/github.com/docker/docker/volume/volume.go +++ /dev/null @@ -1,374 +0,0 @@ -package volume - -import ( - "fmt" - "os" - "path/filepath" - "strings" - "syscall" - "time" - - mounttypes "github.com/docker/docker/api/types/mount" - "github.com/docker/docker/pkg/idtools" - "github.com/docker/docker/pkg/stringid" - "github.com/opencontainers/selinux/go-selinux/label" - "github.com/pkg/errors" -) - -// DefaultDriverName is the driver name used for the driver -// implemented in the local package. -const DefaultDriverName = "local" - -// Scopes define if a volume has is cluster-wide (global) or local only. -// Scopes are returned by the volume driver when it is queried for capabilities and then set on a volume -const ( - LocalScope = "local" - GlobalScope = "global" -) - -// Driver is for creating and removing volumes. -type Driver interface { - // Name returns the name of the volume driver. - Name() string - // Create makes a new volume with the given name. - Create(name string, opts map[string]string) (Volume, error) - // Remove deletes the volume. - Remove(vol Volume) (err error) - // List lists all the volumes the driver has - List() ([]Volume, error) - // Get retrieves the volume with the requested name - Get(name string) (Volume, error) - // Scope returns the scope of the driver (e.g. `global` or `local`). - // Scope determines how the driver is handled at a cluster level - Scope() string -} - -// Capability defines a set of capabilities that a driver is able to handle. -type Capability struct { - // Scope is the scope of the driver, `global` or `local` - // A `global` scope indicates that the driver manages volumes across the cluster - // A `local` scope indicates that the driver only manages volumes resources local to the host - // Scope is declared by the driver - Scope string -} - -// Volume is a place to store data. It is backed by a specific driver, and can be mounted. -type Volume interface { - // Name returns the name of the volume - Name() string - // DriverName returns the name of the driver which owns this volume. - DriverName() string - // Path returns the absolute path to the volume. - Path() string - // Mount mounts the volume and returns the absolute path to - // where it can be consumed. - Mount(id string) (string, error) - // Unmount unmounts the volume when it is no longer in use. - Unmount(id string) error - // CreatedAt returns Volume Creation time - CreatedAt() (time.Time, error) - // Status returns low-level status information about a volume - Status() map[string]interface{} -} - -// DetailedVolume wraps a Volume with user-defined labels, options, and cluster scope (e.g., `local` or `global`) -type DetailedVolume interface { - Labels() map[string]string - Options() map[string]string - Scope() string - Volume -} - -// MountPoint is the intersection point between a volume and a container. It -// specifies which volume is to be used and where inside a container it should -// be mounted. -type MountPoint struct { - // Source is the source path of the mount. - // E.g. `mount --bind /foo /bar`, `/foo` is the `Source`. - Source string - // Destination is the path relative to the container root (`/`) to the mount point - // It is where the `Source` is mounted to - Destination string - // RW is set to true when the mountpoint should be mounted as read-write - RW bool - // Name is the name reference to the underlying data defined by `Source` - // e.g., the volume name - Name string - // Driver is the volume driver used to create the volume (if it is a volume) - Driver string - // Type of mount to use, see `Type` definitions in github.com/docker/docker/api/types/mount - Type mounttypes.Type `json:",omitempty"` - // Volume is the volume providing data to this mountpoint. - // This is nil unless `Type` is set to `TypeVolume` - Volume Volume `json:"-"` - - // Mode is the comma separated list of options supplied by the user when creating - // the bind/volume mount. - // Note Mode is not used on Windows - Mode string `json:"Relabel,omitempty"` // Originally field was `Relabel`" - - // Propagation describes how the mounts are propagated from the host into the - // mount point, and vice-versa. - // See https://www.kernel.org/doc/Documentation/filesystems/sharedsubtree.txt - // Note Propagation is not used on Windows - Propagation mounttypes.Propagation `json:",omitempty"` // Mount propagation string - - // Specifies if data should be copied from the container before the first mount - // Use a pointer here so we can tell if the user set this value explicitly - // This allows us to error out when the user explicitly enabled copy but we can't copy due to the volume being populated - CopyData bool `json:"-"` - // ID is the opaque ID used to pass to the volume driver. - // This should be set by calls to `Mount` and unset by calls to `Unmount` - ID string `json:",omitempty"` - - // Sepc is a copy of the API request that created this mount. - Spec mounttypes.Mount - - // Track usage of this mountpoint - // Specifically needed for containers which are running and calls to `docker cp` - // because both these actions require mounting the volumes. - active int -} - -// Cleanup frees resources used by the mountpoint -func (m *MountPoint) Cleanup() error { - if m.Volume == nil || m.ID == "" { - return nil - } - - if err := m.Volume.Unmount(m.ID); err != nil { - return errors.Wrapf(err, "error unmounting volume %s", m.Volume.Name()) - } - - m.active-- - if m.active == 0 { - m.ID = "" - } - return nil -} - -// Setup sets up a mount point by either mounting the volume if it is -// configured, or creating the source directory if supplied. -// The, optional, checkFun parameter allows doing additional checking -// before creating the source directory on the host. -func (m *MountPoint) Setup(mountLabel string, rootIDs idtools.IDPair, checkFun func(m *MountPoint) error) (path string, err error) { - defer func() { - if err != nil || !label.RelabelNeeded(m.Mode) { - return - } - - err = label.Relabel(m.Source, mountLabel, label.IsShared(m.Mode)) - if err == syscall.ENOTSUP { - err = nil - } - if err != nil { - path = "" - err = errors.Wrapf(err, "error setting label on mount source '%s'", m.Source) - } - }() - - if m.Volume != nil { - id := m.ID - if id == "" { - id = stringid.GenerateNonCryptoID() - } - path, err := m.Volume.Mount(id) - if err != nil { - return "", errors.Wrapf(err, "error while mounting volume '%s'", m.Source) - } - - m.ID = id - m.active++ - return path, nil - } - - if len(m.Source) == 0 { - return "", fmt.Errorf("Unable to setup mount point, neither source nor volume defined") - } - - // system.MkdirAll() produces an error if m.Source exists and is a file (not a directory), - if m.Type == mounttypes.TypeBind { - // Before creating the source directory on the host, invoke checkFun if it's not nil. One of - // the use case is to forbid creating the daemon socket as a directory if the daemon is in - // the process of shutting down. - if checkFun != nil { - if err := checkFun(m); err != nil { - return "", err - } - } - // idtools.MkdirAllNewAs() produces an error if m.Source exists and is a file (not a directory) - // also, makes sure that if the directory is created, the correct remapped rootUID/rootGID will own it - if err := idtools.MkdirAllAndChownNew(m.Source, 0755, rootIDs); err != nil { - if perr, ok := err.(*os.PathError); ok { - if perr.Err != syscall.ENOTDIR { - return "", errors.Wrapf(err, "error while creating mount source path '%s'", m.Source) - } - } - } - } - return m.Source, nil -} - -// Path returns the path of a volume in a mount point. -func (m *MountPoint) Path() string { - if m.Volume != nil { - return m.Volume.Path() - } - return m.Source -} - -// ParseVolumesFrom ensures that the supplied volumes-from is valid. -func ParseVolumesFrom(spec string) (string, string, error) { - if len(spec) == 0 { - return "", "", fmt.Errorf("volumes-from specification cannot be an empty string") - } - - specParts := strings.SplitN(spec, ":", 2) - id := specParts[0] - mode := "rw" - - if len(specParts) == 2 { - mode = specParts[1] - if !ValidMountMode(mode) { - return "", "", errInvalidMode(mode) - } - // For now don't allow propagation properties while importing - // volumes from data container. These volumes will inherit - // the same propagation property as of the original volume - // in data container. This probably can be relaxed in future. - if HasPropagation(mode) { - return "", "", errInvalidMode(mode) - } - // Do not allow copy modes on volumes-from - if _, isSet := getCopyMode(mode); isSet { - return "", "", errInvalidMode(mode) - } - } - return id, mode, nil -} - -// ParseMountRaw parses a raw volume spec (e.g. `-v /foo:/bar:shared`) into a -// structured spec. Once the raw spec is parsed it relies on `ParseMountSpec` to -// validate the spec and create a MountPoint -func ParseMountRaw(raw, volumeDriver string) (*MountPoint, error) { - arr, err := splitRawSpec(convertSlash(raw)) - if err != nil { - return nil, err - } - - var spec mounttypes.Mount - var mode string - switch len(arr) { - case 1: - // Just a destination path in the container - spec.Target = arr[0] - case 2: - if ValidMountMode(arr[1]) { - // Destination + Mode is not a valid volume - volumes - // cannot include a mode. e.g. /foo:rw - return nil, errInvalidSpec(raw) - } - // Host Source Path or Name + Destination - spec.Source = arr[0] - spec.Target = arr[1] - case 3: - // HostSourcePath+DestinationPath+Mode - spec.Source = arr[0] - spec.Target = arr[1] - mode = arr[2] - default: - return nil, errInvalidSpec(raw) - } - - if !ValidMountMode(mode) { - return nil, errInvalidMode(mode) - } - - if filepath.IsAbs(spec.Source) { - spec.Type = mounttypes.TypeBind - } else { - spec.Type = mounttypes.TypeVolume - } - - spec.ReadOnly = !ReadWrite(mode) - - // cannot assume that if a volume driver is passed in that we should set it - if volumeDriver != "" && spec.Type == mounttypes.TypeVolume { - spec.VolumeOptions = &mounttypes.VolumeOptions{ - DriverConfig: &mounttypes.Driver{Name: volumeDriver}, - } - } - - if copyData, isSet := getCopyMode(mode); isSet { - if spec.VolumeOptions == nil { - spec.VolumeOptions = &mounttypes.VolumeOptions{} - } - spec.VolumeOptions.NoCopy = !copyData - } - if HasPropagation(mode) { - spec.BindOptions = &mounttypes.BindOptions{ - Propagation: GetPropagation(mode), - } - } - - mp, err := ParseMountSpec(spec, platformRawValidationOpts...) - if mp != nil { - mp.Mode = mode - } - if err != nil { - err = fmt.Errorf("%v: %v", errInvalidSpec(raw), err) - } - return mp, err -} - -// ParseMountSpec reads a mount config, validates it, and configures a mountpoint from it. -func ParseMountSpec(cfg mounttypes.Mount, options ...func(*validateOpts)) (*MountPoint, error) { - if err := validateMountConfig(&cfg, options...); err != nil { - return nil, err - } - mp := &MountPoint{ - RW: !cfg.ReadOnly, - Destination: clean(convertSlash(cfg.Target)), - Type: cfg.Type, - Spec: cfg, - } - - switch cfg.Type { - case mounttypes.TypeVolume: - if cfg.Source == "" { - mp.Name = stringid.GenerateNonCryptoID() - } else { - mp.Name = cfg.Source - } - mp.CopyData = DefaultCopyMode - - if cfg.VolumeOptions != nil { - if cfg.VolumeOptions.DriverConfig != nil { - mp.Driver = cfg.VolumeOptions.DriverConfig.Name - } - if cfg.VolumeOptions.NoCopy { - mp.CopyData = false - } - } - case mounttypes.TypeBind: - mp.Source = clean(convertSlash(cfg.Source)) - if cfg.BindOptions != nil && len(cfg.BindOptions.Propagation) > 0 { - mp.Propagation = cfg.BindOptions.Propagation - } else { - // If user did not specify a propagation mode, get - // default propagation mode. - mp.Propagation = DefaultPropagationMode - } - case mounttypes.TypeTmpfs: - // NOP - } - return mp, nil -} - -func errInvalidMode(mode string) error { - return fmt.Errorf("invalid mode: %v", mode) -} - -func errInvalidSpec(spec string) error { - return fmt.Errorf("invalid volume specification: '%s'", spec) -} diff --git a/components/cli/vendor/github.com/docker/docker/volume/volume_copy.go b/components/cli/vendor/github.com/docker/docker/volume/volume_copy.go deleted file mode 100644 index 77f06a0d1f..0000000000 --- a/components/cli/vendor/github.com/docker/docker/volume/volume_copy.go +++ /dev/null @@ -1,23 +0,0 @@ -package volume - -import "strings" - -// {=isEnabled} -var copyModes = map[string]bool{ - "nocopy": false, -} - -func copyModeExists(mode string) bool { - _, exists := copyModes[mode] - return exists -} - -// GetCopyMode gets the copy mode from the mode string for mounts -func getCopyMode(mode string) (bool, bool) { - for _, o := range strings.Split(mode, ",") { - if isEnabled, exists := copyModes[o]; exists { - return isEnabled, true - } - } - return DefaultCopyMode, false -} diff --git a/components/cli/vendor/github.com/docker/docker/volume/volume_copy_unix.go b/components/cli/vendor/github.com/docker/docker/volume/volume_copy_unix.go deleted file mode 100644 index ad66e17637..0000000000 --- a/components/cli/vendor/github.com/docker/docker/volume/volume_copy_unix.go +++ /dev/null @@ -1,8 +0,0 @@ -// +build !windows - -package volume - -const ( - // DefaultCopyMode is the copy mode used by default for normal/named volumes - DefaultCopyMode = true -) diff --git a/components/cli/vendor/github.com/docker/docker/volume/volume_copy_windows.go b/components/cli/vendor/github.com/docker/docker/volume/volume_copy_windows.go deleted file mode 100644 index 798638c878..0000000000 --- a/components/cli/vendor/github.com/docker/docker/volume/volume_copy_windows.go +++ /dev/null @@ -1,6 +0,0 @@ -package volume - -const ( - // DefaultCopyMode is the copy mode used by default for normal/named volumes - DefaultCopyMode = false -) diff --git a/components/cli/vendor/github.com/docker/docker/volume/volume_linux.go b/components/cli/vendor/github.com/docker/docker/volume/volume_linux.go deleted file mode 100644 index fdf7b63e4b..0000000000 --- a/components/cli/vendor/github.com/docker/docker/volume/volume_linux.go +++ /dev/null @@ -1,56 +0,0 @@ -// +build linux - -package volume - -import ( - "fmt" - "strings" - - mounttypes "github.com/docker/docker/api/types/mount" -) - -// ConvertTmpfsOptions converts *mounttypes.TmpfsOptions to the raw option string -// for mount(2). -func ConvertTmpfsOptions(opt *mounttypes.TmpfsOptions, readOnly bool) (string, error) { - var rawOpts []string - if readOnly { - rawOpts = append(rawOpts, "ro") - } - - if opt != nil && opt.Mode != 0 { - rawOpts = append(rawOpts, fmt.Sprintf("mode=%o", opt.Mode)) - } - - if opt != nil && opt.SizeBytes != 0 { - // calculate suffix here, making this linux specific, but that is - // okay, since API is that way anyways. - - // we do this by finding the suffix that divides evenly into the - // value, returning the value itself, with no suffix, if it fails. - // - // For the most part, we don't enforce any semantic to this values. - // The operating system will usually align this and enforce minimum - // and maximums. - var ( - size = opt.SizeBytes - suffix string - ) - for _, r := range []struct { - suffix string - divisor int64 - }{ - {"g", 1 << 30}, - {"m", 1 << 20}, - {"k", 1 << 10}, - } { - if size%r.divisor == 0 { - size = size / r.divisor - suffix = r.suffix - break - } - } - - rawOpts = append(rawOpts, fmt.Sprintf("size=%d%s", size, suffix)) - } - return strings.Join(rawOpts, ","), nil -} diff --git a/components/cli/vendor/github.com/docker/docker/volume/volume_propagation_linux.go b/components/cli/vendor/github.com/docker/docker/volume/volume_propagation_linux.go deleted file mode 100644 index 1de57ab52b..0000000000 --- a/components/cli/vendor/github.com/docker/docker/volume/volume_propagation_linux.go +++ /dev/null @@ -1,47 +0,0 @@ -// +build linux - -package volume - -import ( - "strings" - - mounttypes "github.com/docker/docker/api/types/mount" -) - -// DefaultPropagationMode defines what propagation mode should be used by -// default if user has not specified one explicitly. -// propagation modes -const DefaultPropagationMode = mounttypes.PropagationRPrivate - -var propagationModes = map[mounttypes.Propagation]bool{ - mounttypes.PropagationPrivate: true, - mounttypes.PropagationRPrivate: true, - mounttypes.PropagationSlave: true, - mounttypes.PropagationRSlave: true, - mounttypes.PropagationShared: true, - mounttypes.PropagationRShared: true, -} - -// GetPropagation extracts and returns the mount propagation mode. If there -// are no specifications, then by default it is "private". -func GetPropagation(mode string) mounttypes.Propagation { - for _, o := range strings.Split(mode, ",") { - prop := mounttypes.Propagation(o) - if propagationModes[prop] { - return prop - } - } - return DefaultPropagationMode -} - -// HasPropagation checks if there is a valid propagation mode present in -// passed string. Returns true if a valid propagation mode specifier is -// present, false otherwise. -func HasPropagation(mode string) bool { - for _, o := range strings.Split(mode, ",") { - if propagationModes[mounttypes.Propagation(o)] { - return true - } - } - return false -} diff --git a/components/cli/vendor/github.com/docker/docker/volume/volume_propagation_unsupported.go b/components/cli/vendor/github.com/docker/docker/volume/volume_propagation_unsupported.go deleted file mode 100644 index 7311ffc2e0..0000000000 --- a/components/cli/vendor/github.com/docker/docker/volume/volume_propagation_unsupported.go +++ /dev/null @@ -1,24 +0,0 @@ -// +build !linux - -package volume - -import mounttypes "github.com/docker/docker/api/types/mount" - -// DefaultPropagationMode is used only in linux. In other cases it returns -// empty string. -const DefaultPropagationMode mounttypes.Propagation = "" - -// propagation modes not supported on this platform. -var propagationModes = map[mounttypes.Propagation]bool{} - -// GetPropagation is not supported. Return empty string. -func GetPropagation(mode string) mounttypes.Propagation { - return DefaultPropagationMode -} - -// HasPropagation checks if there is a valid propagation mode present in -// passed string. Returns true if a valid propagation mode specifier is -// present, false otherwise. -func HasPropagation(mode string) bool { - return false -} diff --git a/components/cli/vendor/github.com/docker/docker/volume/volume_unix.go b/components/cli/vendor/github.com/docker/docker/volume/volume_unix.go deleted file mode 100644 index e35b70c03b..0000000000 --- a/components/cli/vendor/github.com/docker/docker/volume/volume_unix.go +++ /dev/null @@ -1,148 +0,0 @@ -// +build linux freebsd darwin solaris - -package volume - -import ( - "fmt" - "os" - "path/filepath" - "strings" - - mounttypes "github.com/docker/docker/api/types/mount" -) - -var platformRawValidationOpts = []func(o *validateOpts){ - // need to make sure to not error out if the bind source does not exist on unix - // this is supported for historical reasons, the path will be automatically - // created later. - func(o *validateOpts) { o.skipBindSourceCheck = true }, -} - -// read-write modes -var rwModes = map[string]bool{ - "rw": true, - "ro": true, -} - -// label modes -var labelModes = map[string]bool{ - "Z": true, - "z": true, -} - -// consistency modes -var consistencyModes = map[mounttypes.Consistency]bool{ - mounttypes.ConsistencyFull: true, - mounttypes.ConsistencyCached: true, - mounttypes.ConsistencyDelegated: true, -} - -// BackwardsCompatible decides whether this mount point can be -// used in old versions of Docker or not. -// Only bind mounts and local volumes can be used in old versions of Docker. -func (m *MountPoint) BackwardsCompatible() bool { - return len(m.Source) > 0 || m.Driver == DefaultDriverName -} - -// HasResource checks whether the given absolute path for a container is in -// this mount point. If the relative path starts with `../` then the resource -// is outside of this mount point, but we can't simply check for this prefix -// because it misses `..` which is also outside of the mount, so check both. -func (m *MountPoint) HasResource(absolutePath string) bool { - relPath, err := filepath.Rel(m.Destination, absolutePath) - return err == nil && relPath != ".." && !strings.HasPrefix(relPath, fmt.Sprintf("..%c", filepath.Separator)) -} - -// IsVolumeNameValid checks a volume name in a platform specific manner. -func IsVolumeNameValid(name string) (bool, error) { - return true, nil -} - -// ValidMountMode will make sure the mount mode is valid. -// returns if it's a valid mount mode or not. -func ValidMountMode(mode string) bool { - if mode == "" { - return true - } - - rwModeCount := 0 - labelModeCount := 0 - propagationModeCount := 0 - copyModeCount := 0 - consistencyModeCount := 0 - - for _, o := range strings.Split(mode, ",") { - switch { - case rwModes[o]: - rwModeCount++ - case labelModes[o]: - labelModeCount++ - case propagationModes[mounttypes.Propagation(o)]: - propagationModeCount++ - case copyModeExists(o): - copyModeCount++ - case consistencyModes[mounttypes.Consistency(o)]: - consistencyModeCount++ - default: - return false - } - } - - // Only one string for each mode is allowed. - if rwModeCount > 1 || labelModeCount > 1 || propagationModeCount > 1 || copyModeCount > 1 || consistencyModeCount > 1 { - return false - } - return true -} - -// ReadWrite tells you if a mode string is a valid read-write mode or not. -// If there are no specifications w.r.t read write mode, then by default -// it returns true. -func ReadWrite(mode string) bool { - if !ValidMountMode(mode) { - return false - } - - for _, o := range strings.Split(mode, ",") { - if o == "ro" { - return false - } - } - return true -} - -func validateNotRoot(p string) error { - p = filepath.Clean(convertSlash(p)) - if p == "/" { - return fmt.Errorf("invalid specification: destination can't be '/'") - } - return nil -} - -func validateCopyMode(mode bool) error { - return nil -} - -func convertSlash(p string) string { - return filepath.ToSlash(p) -} - -func splitRawSpec(raw string) ([]string, error) { - if strings.Count(raw, ":") > 2 { - return nil, errInvalidSpec(raw) - } - - arr := strings.SplitN(raw, ":", 3) - if arr[0] == "" { - return nil, errInvalidSpec(raw) - } - return arr, nil -} - -func clean(p string) string { - return filepath.Clean(p) -} - -func validateStat(fi os.FileInfo) error { - return nil -} diff --git a/components/cli/vendor/github.com/docker/docker/volume/volume_unsupported.go b/components/cli/vendor/github.com/docker/docker/volume/volume_unsupported.go deleted file mode 100644 index ff9d6afa27..0000000000 --- a/components/cli/vendor/github.com/docker/docker/volume/volume_unsupported.go +++ /dev/null @@ -1,16 +0,0 @@ -// +build !linux - -package volume - -import ( - "fmt" - "runtime" - - mounttypes "github.com/docker/docker/api/types/mount" -) - -// ConvertTmpfsOptions converts *mounttypes.TmpfsOptions to the raw option string -// for mount(2). -func ConvertTmpfsOptions(opt *mounttypes.TmpfsOptions, readOnly bool) (string, error) { - return "", fmt.Errorf("%s does not support tmpfs", runtime.GOOS) -} diff --git a/components/cli/vendor/github.com/docker/docker/volume/volume_windows.go b/components/cli/vendor/github.com/docker/docker/volume/volume_windows.go deleted file mode 100644 index 22f6fc7a14..0000000000 --- a/components/cli/vendor/github.com/docker/docker/volume/volume_windows.go +++ /dev/null @@ -1,201 +0,0 @@ -package volume - -import ( - "fmt" - "os" - "path/filepath" - "regexp" - "strings" -) - -// read-write modes -var rwModes = map[string]bool{ - "rw": true, -} - -// read-only modes -var roModes = map[string]bool{ - "ro": true, -} - -var platformRawValidationOpts = []func(*validateOpts){ - // filepath.IsAbs is weird on Windows: - // `c:` is not considered an absolute path - // `c:\` is considered an absolute path - // In any case, the regex matching below ensures absolute paths - // TODO: consider this a bug with filepath.IsAbs (?) - func(o *validateOpts) { o.skipAbsolutePathCheck = true }, -} - -const ( - // Spec should be in the format [source:]destination[:mode] - // - // Examples: c:\foo bar:d:rw - // c:\foo:d:\bar - // myname:d: - // d:\ - // - // Explanation of this regex! Thanks @thaJeztah on IRC and gist for help. See - // https://gist.github.com/thaJeztah/6185659e4978789fb2b2. A good place to - // test is https://regex-golang.appspot.com/assets/html/index.html - // - // Useful link for referencing named capturing groups: - // http://stackoverflow.com/questions/20750843/using-named-matches-from-go-regex - // - // There are three match groups: source, destination and mode. - // - - // RXHostDir is the first option of a source - RXHostDir = `[a-z]:\\(?:[^\\/:*?"<>|\r\n]+\\?)*` - // RXName is the second option of a source - RXName = `[^\\/:*?"<>|\r\n]+` - // RXReservedNames are reserved names not possible on Windows - RXReservedNames = `(con)|(prn)|(nul)|(aux)|(com[1-9])|(lpt[1-9])` - - // RXSource is the combined possibilities for a source - RXSource = `((?P((` + RXHostDir + `)|(` + RXName + `))):)?` - - // Source. Can be either a host directory, a name, or omitted: - // HostDir: - // - Essentially using the folder solution from - // https://www.safaribooksonline.com/library/view/regular-expressions-cookbook/9781449327453/ch08s18.html - // but adding case insensitivity. - // - Must be an absolute path such as c:\path - // - Can include spaces such as `c:\program files` - // - And then followed by a colon which is not in the capture group - // - And can be optional - // Name: - // - Must not contain invalid NTFS filename characters (https://msdn.microsoft.com/en-us/library/windows/desktop/aa365247(v=vs.85).aspx) - // - And then followed by a colon which is not in the capture group - // - And can be optional - - // RXDestination is the regex expression for the mount destination - RXDestination = `(?P([a-z]):((?:\\[^\\/:*?"<>\r\n]+)*\\?))` - // Destination (aka container path): - // - Variation on hostdir but can be a drive followed by colon as well - // - If a path, must be absolute. Can include spaces - // - Drive cannot be c: (explicitly checked in code, not RegEx) - - // RXMode is the regex expression for the mode of the mount - // Mode (optional): - // - Hopefully self explanatory in comparison to above regex's. - // - Colon is not in the capture group - RXMode = `(:(?P(?i)ro|rw))?` -) - -// BackwardsCompatible decides whether this mount point can be -// used in old versions of Docker or not. -// Windows volumes are never backwards compatible. -func (m *MountPoint) BackwardsCompatible() bool { - return false -} - -func splitRawSpec(raw string) ([]string, error) { - specExp := regexp.MustCompile(`^` + RXSource + RXDestination + RXMode + `$`) - match := specExp.FindStringSubmatch(strings.ToLower(raw)) - - // Must have something back - if len(match) == 0 { - return nil, errInvalidSpec(raw) - } - - var split []string - matchgroups := make(map[string]string) - // Pull out the sub expressions from the named capture groups - for i, name := range specExp.SubexpNames() { - matchgroups[name] = strings.ToLower(match[i]) - } - if source, exists := matchgroups["source"]; exists { - if source != "" { - split = append(split, source) - } - } - if destination, exists := matchgroups["destination"]; exists { - if destination != "" { - split = append(split, destination) - } - } - if mode, exists := matchgroups["mode"]; exists { - if mode != "" { - split = append(split, mode) - } - } - // Fix #26329. If the destination appears to be a file, and the source is null, - // it may be because we've fallen through the possible naming regex and hit a - // situation where the user intention was to map a file into a container through - // a local volume, but this is not supported by the platform. - if matchgroups["source"] == "" && matchgroups["destination"] != "" { - validName, err := IsVolumeNameValid(matchgroups["destination"]) - if err != nil { - return nil, err - } - if !validName { - if fi, err := os.Stat(matchgroups["destination"]); err == nil { - if !fi.IsDir() { - return nil, fmt.Errorf("file '%s' cannot be mapped. Only directories can be mapped on this platform", matchgroups["destination"]) - } - } - } - } - return split, nil -} - -// IsVolumeNameValid checks a volume name in a platform specific manner. -func IsVolumeNameValid(name string) (bool, error) { - nameExp := regexp.MustCompile(`^` + RXName + `$`) - if !nameExp.MatchString(name) { - return false, nil - } - nameExp = regexp.MustCompile(`^` + RXReservedNames + `$`) - if nameExp.MatchString(name) { - return false, fmt.Errorf("volume name %q cannot be a reserved word for Windows filenames", name) - } - return true, nil -} - -// ValidMountMode will make sure the mount mode is valid. -// returns if it's a valid mount mode or not. -func ValidMountMode(mode string) bool { - if mode == "" { - return true - } - return roModes[strings.ToLower(mode)] || rwModes[strings.ToLower(mode)] -} - -// ReadWrite tells you if a mode string is a valid read-write mode or not. -func ReadWrite(mode string) bool { - return rwModes[strings.ToLower(mode)] || mode == "" -} - -func validateNotRoot(p string) error { - p = strings.ToLower(convertSlash(p)) - if p == "c:" || p == `c:\` { - return fmt.Errorf("destination path cannot be `c:` or `c:\\`: %v", p) - } - return nil -} - -func validateCopyMode(mode bool) error { - if mode { - return fmt.Errorf("Windows does not support copying image path content") - } - return nil -} - -func convertSlash(p string) string { - return filepath.FromSlash(p) -} - -func clean(p string) string { - if match, _ := regexp.MatchString("^[a-z]:$", p); match { - return p - } - return filepath.Clean(p) -} - -func validateStat(fi os.FileInfo) error { - if !fi.IsDir() { - return fmt.Errorf("source path must be a directory") - } - return nil -} diff --git a/components/cli/vendor/github.com/opencontainers/runc/libcontainer/cgroups/cgroups.go b/components/cli/vendor/github.com/opencontainers/runc/libcontainer/cgroups/cgroups.go deleted file mode 100644 index 35fc8eb961..0000000000 --- a/components/cli/vendor/github.com/opencontainers/runc/libcontainer/cgroups/cgroups.go +++ /dev/null @@ -1,64 +0,0 @@ -// +build linux - -package cgroups - -import ( - "fmt" - - "github.com/opencontainers/runc/libcontainer/configs" -) - -type Manager interface { - // Applies cgroup configuration to the process with the specified pid - Apply(pid int) error - - // Returns the PIDs inside the cgroup set - GetPids() ([]int, error) - - // Returns the PIDs inside the cgroup set & all sub-cgroups - GetAllPids() ([]int, error) - - // Returns statistics for the cgroup set - GetStats() (*Stats, error) - - // Toggles the freezer cgroup according with specified state - Freeze(state configs.FreezerState) error - - // Destroys the cgroup set - Destroy() error - - // NewCgroupManager() and LoadCgroupManager() require following attributes: - // Paths map[string]string - // Cgroups *cgroups.Cgroup - // Paths maps cgroup subsystem to path at which it is mounted. - // Cgroups specifies specific cgroup settings for the various subsystems - - // Returns cgroup paths to save in a state file and to be able to - // restore the object later. - GetPaths() map[string]string - - // Sets the cgroup as configured. - Set(container *configs.Config) error -} - -type NotFoundError struct { - Subsystem string -} - -func (e *NotFoundError) Error() string { - return fmt.Sprintf("mountpoint for %s not found", e.Subsystem) -} - -func NewNotFoundError(sub string) error { - return &NotFoundError{ - Subsystem: sub, - } -} - -func IsNotFound(err error) bool { - if err == nil { - return false - } - _, ok := err.(*NotFoundError) - return ok -} diff --git a/components/cli/vendor/github.com/opencontainers/runc/libcontainer/cgroups/cgroups_unsupported.go b/components/cli/vendor/github.com/opencontainers/runc/libcontainer/cgroups/cgroups_unsupported.go deleted file mode 100644 index 278d507e28..0000000000 --- a/components/cli/vendor/github.com/opencontainers/runc/libcontainer/cgroups/cgroups_unsupported.go +++ /dev/null @@ -1,3 +0,0 @@ -// +build !linux - -package cgroups diff --git a/components/cli/vendor/github.com/opencontainers/runc/libcontainer/cgroups/stats.go b/components/cli/vendor/github.com/opencontainers/runc/libcontainer/cgroups/stats.go deleted file mode 100644 index b483f1bf98..0000000000 --- a/components/cli/vendor/github.com/opencontainers/runc/libcontainer/cgroups/stats.go +++ /dev/null @@ -1,106 +0,0 @@ -// +build linux - -package cgroups - -type ThrottlingData struct { - // Number of periods with throttling active - Periods uint64 `json:"periods,omitempty"` - // Number of periods when the container hit its throttling limit. - ThrottledPeriods uint64 `json:"throttled_periods,omitempty"` - // Aggregate time the container was throttled for in nanoseconds. - ThrottledTime uint64 `json:"throttled_time,omitempty"` -} - -// CpuUsage denotes the usage of a CPU. -// All CPU stats are aggregate since container inception. -type CpuUsage struct { - // Total CPU time consumed. - // Units: nanoseconds. - TotalUsage uint64 `json:"total_usage,omitempty"` - // Total CPU time consumed per core. - // Units: nanoseconds. - PercpuUsage []uint64 `json:"percpu_usage,omitempty"` - // Time spent by tasks of the cgroup in kernel mode. - // Units: nanoseconds. - UsageInKernelmode uint64 `json:"usage_in_kernelmode"` - // Time spent by tasks of the cgroup in user mode. - // Units: nanoseconds. - UsageInUsermode uint64 `json:"usage_in_usermode"` -} - -type CpuStats struct { - CpuUsage CpuUsage `json:"cpu_usage,omitempty"` - ThrottlingData ThrottlingData `json:"throttling_data,omitempty"` -} - -type MemoryData struct { - Usage uint64 `json:"usage,omitempty"` - MaxUsage uint64 `json:"max_usage,omitempty"` - Failcnt uint64 `json:"failcnt"` - Limit uint64 `json:"limit"` -} - -type MemoryStats struct { - // memory used for cache - Cache uint64 `json:"cache,omitempty"` - // usage of memory - Usage MemoryData `json:"usage,omitempty"` - // usage of memory + swap - SwapUsage MemoryData `json:"swap_usage,omitempty"` - // usage of kernel memory - KernelUsage MemoryData `json:"kernel_usage,omitempty"` - // usage of kernel TCP memory - KernelTCPUsage MemoryData `json:"kernel_tcp_usage,omitempty"` - - Stats map[string]uint64 `json:"stats,omitempty"` -} - -type PidsStats struct { - // number of pids in the cgroup - Current uint64 `json:"current,omitempty"` - // active pids hard limit - Limit uint64 `json:"limit,omitempty"` -} - -type BlkioStatEntry struct { - Major uint64 `json:"major,omitempty"` - Minor uint64 `json:"minor,omitempty"` - Op string `json:"op,omitempty"` - Value uint64 `json:"value,omitempty"` -} - -type BlkioStats struct { - // number of bytes tranferred to and from the block device - IoServiceBytesRecursive []BlkioStatEntry `json:"io_service_bytes_recursive,omitempty"` - IoServicedRecursive []BlkioStatEntry `json:"io_serviced_recursive,omitempty"` - IoQueuedRecursive []BlkioStatEntry `json:"io_queue_recursive,omitempty"` - IoServiceTimeRecursive []BlkioStatEntry `json:"io_service_time_recursive,omitempty"` - IoWaitTimeRecursive []BlkioStatEntry `json:"io_wait_time_recursive,omitempty"` - IoMergedRecursive []BlkioStatEntry `json:"io_merged_recursive,omitempty"` - IoTimeRecursive []BlkioStatEntry `json:"io_time_recursive,omitempty"` - SectorsRecursive []BlkioStatEntry `json:"sectors_recursive,omitempty"` -} - -type HugetlbStats struct { - // current res_counter usage for hugetlb - Usage uint64 `json:"usage,omitempty"` - // maximum usage ever recorded. - MaxUsage uint64 `json:"max_usage,omitempty"` - // number of times hugetlb usage allocation failure. - Failcnt uint64 `json:"failcnt"` -} - -type Stats struct { - CpuStats CpuStats `json:"cpu_stats,omitempty"` - MemoryStats MemoryStats `json:"memory_stats,omitempty"` - PidsStats PidsStats `json:"pids_stats,omitempty"` - BlkioStats BlkioStats `json:"blkio_stats,omitempty"` - // the map is in the format "size of hugepage: stats of the hugepage" - HugetlbStats map[string]HugetlbStats `json:"hugetlb_stats,omitempty"` -} - -func NewStats() *Stats { - memoryStats := MemoryStats{Stats: make(map[string]uint64)} - hugetlbStats := make(map[string]HugetlbStats) - return &Stats{MemoryStats: memoryStats, HugetlbStats: hugetlbStats} -} diff --git a/components/cli/vendor/github.com/opencontainers/runc/libcontainer/cgroups/utils.go b/components/cli/vendor/github.com/opencontainers/runc/libcontainer/cgroups/utils.go deleted file mode 100644 index c6db0039e6..0000000000 --- a/components/cli/vendor/github.com/opencontainers/runc/libcontainer/cgroups/utils.go +++ /dev/null @@ -1,436 +0,0 @@ -// +build linux - -package cgroups - -import ( - "bufio" - "fmt" - "io" - "io/ioutil" - "os" - "path/filepath" - "strconv" - "strings" - "time" - - "github.com/docker/go-units" -) - -const ( - cgroupNamePrefix = "name=" - CgroupProcesses = "cgroup.procs" -) - -// https://www.kernel.org/doc/Documentation/cgroup-v1/cgroups.txt -func FindCgroupMountpoint(subsystem string) (string, error) { - // We are not using mount.GetMounts() because it's super-inefficient, - // parsing it directly sped up x10 times because of not using Sscanf. - // It was one of two major performance drawbacks in container start. - if !isSubsystemAvailable(subsystem) { - return "", NewNotFoundError(subsystem) - } - f, err := os.Open("/proc/self/mountinfo") - if err != nil { - return "", err - } - defer f.Close() - - scanner := bufio.NewScanner(f) - for scanner.Scan() { - txt := scanner.Text() - fields := strings.Split(txt, " ") - for _, opt := range strings.Split(fields[len(fields)-1], ",") { - if opt == subsystem { - return fields[4], nil - } - } - } - if err := scanner.Err(); err != nil { - return "", err - } - - return "", NewNotFoundError(subsystem) -} - -func FindCgroupMountpointAndRoot(subsystem string) (string, string, error) { - if !isSubsystemAvailable(subsystem) { - return "", "", NewNotFoundError(subsystem) - } - f, err := os.Open("/proc/self/mountinfo") - if err != nil { - return "", "", err - } - defer f.Close() - - scanner := bufio.NewScanner(f) - for scanner.Scan() { - txt := scanner.Text() - fields := strings.Split(txt, " ") - for _, opt := range strings.Split(fields[len(fields)-1], ",") { - if opt == subsystem { - return fields[4], fields[3], nil - } - } - } - if err := scanner.Err(); err != nil { - return "", "", err - } - - return "", "", NewNotFoundError(subsystem) -} - -func isSubsystemAvailable(subsystem string) bool { - cgroups, err := ParseCgroupFile("/proc/self/cgroup") - if err != nil { - return false - } - _, avail := cgroups[subsystem] - return avail -} - -func FindCgroupMountpointDir() (string, error) { - f, err := os.Open("/proc/self/mountinfo") - if err != nil { - return "", err - } - defer f.Close() - - scanner := bufio.NewScanner(f) - for scanner.Scan() { - text := scanner.Text() - fields := strings.Split(text, " ") - // Safe as mountinfo encodes mountpoints with spaces as \040. - index := strings.Index(text, " - ") - postSeparatorFields := strings.Fields(text[index+3:]) - numPostFields := len(postSeparatorFields) - - // This is an error as we can't detect if the mount is for "cgroup" - if numPostFields == 0 { - return "", fmt.Errorf("Found no fields post '-' in %q", text) - } - - if postSeparatorFields[0] == "cgroup" { - // Check that the mount is properly formated. - if numPostFields < 3 { - return "", fmt.Errorf("Error found less than 3 fields post '-' in %q", text) - } - - return filepath.Dir(fields[4]), nil - } - } - if err := scanner.Err(); err != nil { - return "", err - } - - return "", NewNotFoundError("cgroup") -} - -type Mount struct { - Mountpoint string - Root string - Subsystems []string -} - -func (m Mount) GetThisCgroupDir(cgroups map[string]string) (string, error) { - if len(m.Subsystems) == 0 { - return "", fmt.Errorf("no subsystem for mount") - } - - return getControllerPath(m.Subsystems[0], cgroups) -} - -func getCgroupMountsHelper(ss map[string]bool, mi io.Reader, all bool) ([]Mount, error) { - res := make([]Mount, 0, len(ss)) - scanner := bufio.NewScanner(mi) - numFound := 0 - for scanner.Scan() && numFound < len(ss) { - txt := scanner.Text() - sepIdx := strings.Index(txt, " - ") - if sepIdx == -1 { - return nil, fmt.Errorf("invalid mountinfo format") - } - if txt[sepIdx+3:sepIdx+10] == "cgroup2" || txt[sepIdx+3:sepIdx+9] != "cgroup" { - continue - } - fields := strings.Split(txt, " ") - m := Mount{ - Mountpoint: fields[4], - Root: fields[3], - } - for _, opt := range strings.Split(fields[len(fields)-1], ",") { - if !ss[opt] { - continue - } - if strings.HasPrefix(opt, cgroupNamePrefix) { - m.Subsystems = append(m.Subsystems, opt[len(cgroupNamePrefix):]) - } else { - m.Subsystems = append(m.Subsystems, opt) - } - if !all { - numFound++ - } - } - res = append(res, m) - } - if err := scanner.Err(); err != nil { - return nil, err - } - return res, nil -} - -// GetCgroupMounts returns the mounts for the cgroup subsystems. -// all indicates whether to return just the first instance or all the mounts. -func GetCgroupMounts(all bool) ([]Mount, error) { - f, err := os.Open("/proc/self/mountinfo") - if err != nil { - return nil, err - } - defer f.Close() - - allSubsystems, err := ParseCgroupFile("/proc/self/cgroup") - if err != nil { - return nil, err - } - - allMap := make(map[string]bool) - for s := range allSubsystems { - allMap[s] = true - } - return getCgroupMountsHelper(allMap, f, all) -} - -// GetAllSubsystems returns all the cgroup subsystems supported by the kernel -func GetAllSubsystems() ([]string, error) { - f, err := os.Open("/proc/cgroups") - if err != nil { - return nil, err - } - defer f.Close() - - subsystems := []string{} - - s := bufio.NewScanner(f) - for s.Scan() { - if err := s.Err(); err != nil { - return nil, err - } - text := s.Text() - if text[0] != '#' { - parts := strings.Fields(text) - if len(parts) >= 4 && parts[3] != "0" { - subsystems = append(subsystems, parts[0]) - } - } - } - return subsystems, nil -} - -// GetThisCgroupDir returns the relative path to the cgroup docker is running in. -func GetThisCgroupDir(subsystem string) (string, error) { - cgroups, err := ParseCgroupFile("/proc/self/cgroup") - if err != nil { - return "", err - } - - return getControllerPath(subsystem, cgroups) -} - -func GetInitCgroupDir(subsystem string) (string, error) { - - cgroups, err := ParseCgroupFile("/proc/1/cgroup") - if err != nil { - return "", err - } - - return getControllerPath(subsystem, cgroups) -} - -func readProcsFile(dir string) ([]int, error) { - f, err := os.Open(filepath.Join(dir, CgroupProcesses)) - if err != nil { - return nil, err - } - defer f.Close() - - var ( - s = bufio.NewScanner(f) - out = []int{} - ) - - for s.Scan() { - if t := s.Text(); t != "" { - pid, err := strconv.Atoi(t) - if err != nil { - return nil, err - } - out = append(out, pid) - } - } - return out, nil -} - -// ParseCgroupFile parses the given cgroup file, typically from -// /proc//cgroup, into a map of subgroups to cgroup names. -func ParseCgroupFile(path string) (map[string]string, error) { - f, err := os.Open(path) - if err != nil { - return nil, err - } - defer f.Close() - - return parseCgroupFromReader(f) -} - -// helper function for ParseCgroupFile to make testing easier -func parseCgroupFromReader(r io.Reader) (map[string]string, error) { - s := bufio.NewScanner(r) - cgroups := make(map[string]string) - - for s.Scan() { - if err := s.Err(); err != nil { - return nil, err - } - - text := s.Text() - // from cgroups(7): - // /proc/[pid]/cgroup - // ... - // For each cgroup hierarchy ... there is one entry - // containing three colon-separated fields of the form: - // hierarchy-ID:subsystem-list:cgroup-path - parts := strings.SplitN(text, ":", 3) - if len(parts) < 3 { - return nil, fmt.Errorf("invalid cgroup entry: must contain at least two colons: %v", text) - } - - for _, subs := range strings.Split(parts[1], ",") { - cgroups[subs] = parts[2] - } - } - return cgroups, nil -} - -func getControllerPath(subsystem string, cgroups map[string]string) (string, error) { - - if p, ok := cgroups[subsystem]; ok { - return p, nil - } - - if p, ok := cgroups[cgroupNamePrefix+subsystem]; ok { - return p, nil - } - - return "", NewNotFoundError(subsystem) -} - -func PathExists(path string) bool { - if _, err := os.Stat(path); err != nil { - return false - } - return true -} - -func EnterPid(cgroupPaths map[string]string, pid int) error { - for _, path := range cgroupPaths { - if PathExists(path) { - if err := WriteCgroupProc(path, pid); err != nil { - return err - } - } - } - return nil -} - -// RemovePaths iterates over the provided paths removing them. -// We trying to remove all paths five times with increasing delay between tries. -// If after all there are not removed cgroups - appropriate error will be -// returned. -func RemovePaths(paths map[string]string) (err error) { - delay := 10 * time.Millisecond - for i := 0; i < 5; i++ { - if i != 0 { - time.Sleep(delay) - delay *= 2 - } - for s, p := range paths { - os.RemoveAll(p) - // TODO: here probably should be logging - _, err := os.Stat(p) - // We need this strange way of checking cgroups existence because - // RemoveAll almost always returns error, even on already removed - // cgroups - if os.IsNotExist(err) { - delete(paths, s) - } - } - if len(paths) == 0 { - return nil - } - } - return fmt.Errorf("Failed to remove paths: %v", paths) -} - -func GetHugePageSize() ([]string, error) { - var pageSizes []string - sizeList := []string{"B", "kB", "MB", "GB", "TB", "PB"} - files, err := ioutil.ReadDir("/sys/kernel/mm/hugepages") - if err != nil { - return pageSizes, err - } - for _, st := range files { - nameArray := strings.Split(st.Name(), "-") - pageSize, err := units.RAMInBytes(nameArray[1]) - if err != nil { - return []string{}, err - } - sizeString := units.CustomSize("%g%s", float64(pageSize), 1024.0, sizeList) - pageSizes = append(pageSizes, sizeString) - } - - return pageSizes, nil -} - -// GetPids returns all pids, that were added to cgroup at path. -func GetPids(path string) ([]int, error) { - return readProcsFile(path) -} - -// GetAllPids returns all pids, that were added to cgroup at path and to all its -// subcgroups. -func GetAllPids(path string) ([]int, error) { - var pids []int - // collect pids from all sub-cgroups - err := filepath.Walk(path, func(p string, info os.FileInfo, iErr error) error { - dir, file := filepath.Split(p) - if file != CgroupProcesses { - return nil - } - if iErr != nil { - return iErr - } - cPids, err := readProcsFile(dir) - if err != nil { - return err - } - pids = append(pids, cPids...) - return nil - }) - return pids, err -} - -// WriteCgroupProc writes the specified pid into the cgroup's cgroup.procs file -func WriteCgroupProc(dir string, pid int) error { - // Normally dir should not be empty, one case is that cgroup subsystem - // is not mounted, we will get empty dir, and we want it fail here. - if dir == "" { - return fmt.Errorf("no such directory for %s", CgroupProcesses) - } - - // Dont attach any pid to the cgroup if -1 is specified as a pid - if pid != -1 { - if err := ioutil.WriteFile(filepath.Join(dir, CgroupProcesses), []byte(strconv.Itoa(pid)), 0700); err != nil { - return fmt.Errorf("failed to write %v to %v: %v", pid, CgroupProcesses, err) - } - } - return nil -} diff --git a/components/cli/vendor/github.com/opencontainers/runc/libcontainer/configs/blkio_device.go b/components/cli/vendor/github.com/opencontainers/runc/libcontainer/configs/blkio_device.go deleted file mode 100644 index e0f3ca1653..0000000000 --- a/components/cli/vendor/github.com/opencontainers/runc/libcontainer/configs/blkio_device.go +++ /dev/null @@ -1,61 +0,0 @@ -package configs - -import "fmt" - -// blockIODevice holds major:minor format supported in blkio cgroup -type blockIODevice struct { - // Major is the device's major number - Major int64 `json:"major"` - // Minor is the device's minor number - Minor int64 `json:"minor"` -} - -// WeightDevice struct holds a `major:minor weight`|`major:minor leaf_weight` pair -type WeightDevice struct { - blockIODevice - // Weight is the bandwidth rate for the device, range is from 10 to 1000 - Weight uint16 `json:"weight"` - // LeafWeight is the bandwidth rate for the device while competing with the cgroup's child cgroups, range is from 10 to 1000, cfq scheduler only - LeafWeight uint16 `json:"leafWeight"` -} - -// NewWeightDevice returns a configured WeightDevice pointer -func NewWeightDevice(major, minor int64, weight, leafWeight uint16) *WeightDevice { - wd := &WeightDevice{} - wd.Major = major - wd.Minor = minor - wd.Weight = weight - wd.LeafWeight = leafWeight - return wd -} - -// WeightString formats the struct to be writable to the cgroup specific file -func (wd *WeightDevice) WeightString() string { - return fmt.Sprintf("%d:%d %d", wd.Major, wd.Minor, wd.Weight) -} - -// LeafWeightString formats the struct to be writable to the cgroup specific file -func (wd *WeightDevice) LeafWeightString() string { - return fmt.Sprintf("%d:%d %d", wd.Major, wd.Minor, wd.LeafWeight) -} - -// ThrottleDevice struct holds a `major:minor rate_per_second` pair -type ThrottleDevice struct { - blockIODevice - // Rate is the IO rate limit per cgroup per device - Rate uint64 `json:"rate"` -} - -// NewThrottleDevice returns a configured ThrottleDevice pointer -func NewThrottleDevice(major, minor int64, rate uint64) *ThrottleDevice { - td := &ThrottleDevice{} - td.Major = major - td.Minor = minor - td.Rate = rate - return td -} - -// String formats the struct to be writable to the cgroup specific file -func (td *ThrottleDevice) String() string { - return fmt.Sprintf("%d:%d %d", td.Major, td.Minor, td.Rate) -} diff --git a/components/cli/vendor/github.com/opencontainers/runc/libcontainer/configs/cgroup_unix.go b/components/cli/vendor/github.com/opencontainers/runc/libcontainer/configs/cgroup_unix.go deleted file mode 100644 index 14d6289816..0000000000 --- a/components/cli/vendor/github.com/opencontainers/runc/libcontainer/configs/cgroup_unix.go +++ /dev/null @@ -1,124 +0,0 @@ -// +build linux freebsd - -package configs - -type FreezerState string - -const ( - Undefined FreezerState = "" - Frozen FreezerState = "FROZEN" - Thawed FreezerState = "THAWED" -) - -type Cgroup struct { - // Deprecated, use Path instead - Name string `json:"name,omitempty"` - - // name of parent of cgroup or slice - // Deprecated, use Path instead - Parent string `json:"parent,omitempty"` - - // Path specifies the path to cgroups that are created and/or joined by the container. - // The path is assumed to be relative to the host system cgroup mountpoint. - Path string `json:"path"` - - // ScopePrefix describes prefix for the scope name - ScopePrefix string `json:"scope_prefix"` - - // Paths represent the absolute cgroups paths to join. - // This takes precedence over Path. - Paths map[string]string - - // Resources contains various cgroups settings to apply - *Resources -} - -type Resources struct { - // If this is true allow access to any kind of device within the container. If false, allow access only to devices explicitly listed in the allowed_devices list. - // Deprecated - AllowAllDevices *bool `json:"allow_all_devices,omitempty"` - // Deprecated - AllowedDevices []*Device `json:"allowed_devices,omitempty"` - // Deprecated - DeniedDevices []*Device `json:"denied_devices,omitempty"` - - Devices []*Device `json:"devices"` - - // Memory limit (in bytes) - Memory int64 `json:"memory"` - - // Memory reservation or soft_limit (in bytes) - MemoryReservation int64 `json:"memory_reservation"` - - // Total memory usage (memory + swap); set `-1` to enable unlimited swap - MemorySwap int64 `json:"memory_swap"` - - // Kernel memory limit (in bytes) - KernelMemory int64 `json:"kernel_memory"` - - // Kernel memory limit for TCP use (in bytes) - KernelMemoryTCP int64 `json:"kernel_memory_tcp"` - - // CPU shares (relative weight vs. other containers) - CpuShares int64 `json:"cpu_shares"` - - // CPU hardcap limit (in usecs). Allowed cpu time in a given period. - CpuQuota int64 `json:"cpu_quota"` - - // CPU period to be used for hardcapping (in usecs). 0 to use system default. - CpuPeriod int64 `json:"cpu_period"` - - // How many time CPU will use in realtime scheduling (in usecs). - CpuRtRuntime int64 `json:"cpu_rt_quota"` - - // CPU period to be used for realtime scheduling (in usecs). - CpuRtPeriod int64 `json:"cpu_rt_period"` - - // CPU to use - CpusetCpus string `json:"cpuset_cpus"` - - // MEM to use - CpusetMems string `json:"cpuset_mems"` - - // Process limit; set <= `0' to disable limit. - PidsLimit int64 `json:"pids_limit"` - - // Specifies per cgroup weight, range is from 10 to 1000. - BlkioWeight uint16 `json:"blkio_weight"` - - // Specifies tasks' weight in the given cgroup while competing with the cgroup's child cgroups, range is from 10 to 1000, cfq scheduler only - BlkioLeafWeight uint16 `json:"blkio_leaf_weight"` - - // Weight per cgroup per device, can override BlkioWeight. - BlkioWeightDevice []*WeightDevice `json:"blkio_weight_device"` - - // IO read rate limit per cgroup per device, bytes per second. - BlkioThrottleReadBpsDevice []*ThrottleDevice `json:"blkio_throttle_read_bps_device"` - - // IO write rate limit per cgroup per device, bytes per second. - BlkioThrottleWriteBpsDevice []*ThrottleDevice `json:"blkio_throttle_write_bps_device"` - - // IO read rate limit per cgroup per device, IO per second. - BlkioThrottleReadIOPSDevice []*ThrottleDevice `json:"blkio_throttle_read_iops_device"` - - // IO write rate limit per cgroup per device, IO per second. - BlkioThrottleWriteIOPSDevice []*ThrottleDevice `json:"blkio_throttle_write_iops_device"` - - // set the freeze value for the process - Freezer FreezerState `json:"freezer"` - - // Hugetlb limit (in bytes) - HugetlbLimit []*HugepageLimit `json:"hugetlb_limit"` - - // Whether to disable OOM Killer - OomKillDisable bool `json:"oom_kill_disable"` - - // Tuning swappiness behaviour per cgroup - MemorySwappiness *int64 `json:"memory_swappiness"` - - // Set priority of network traffic for container - NetPrioIfpriomap []*IfPrioMap `json:"net_prio_ifpriomap"` - - // Set class identifier for container's network packets - NetClsClassid uint32 `json:"net_cls_classid_u"` -} diff --git a/components/cli/vendor/github.com/opencontainers/runc/libcontainer/configs/cgroup_unsupported.go b/components/cli/vendor/github.com/opencontainers/runc/libcontainer/configs/cgroup_unsupported.go deleted file mode 100644 index 95e2830a43..0000000000 --- a/components/cli/vendor/github.com/opencontainers/runc/libcontainer/configs/cgroup_unsupported.go +++ /dev/null @@ -1,6 +0,0 @@ -// +build !windows,!linux,!freebsd - -package configs - -type Cgroup struct { -} diff --git a/components/cli/vendor/github.com/opencontainers/runc/libcontainer/configs/cgroup_windows.go b/components/cli/vendor/github.com/opencontainers/runc/libcontainer/configs/cgroup_windows.go deleted file mode 100644 index d74847b0db..0000000000 --- a/components/cli/vendor/github.com/opencontainers/runc/libcontainer/configs/cgroup_windows.go +++ /dev/null @@ -1,6 +0,0 @@ -package configs - -// TODO Windows: This can ultimately be entirely factored out on Windows as -// cgroups are a Unix-specific construct. -type Cgroup struct { -} diff --git a/components/cli/vendor/github.com/opencontainers/runc/libcontainer/configs/config.go b/components/cli/vendor/github.com/opencontainers/runc/libcontainer/configs/config.go deleted file mode 100644 index fdfe248c73..0000000000 --- a/components/cli/vendor/github.com/opencontainers/runc/libcontainer/configs/config.go +++ /dev/null @@ -1,332 +0,0 @@ -package configs - -import ( - "bytes" - "encoding/json" - "fmt" - "os/exec" - "time" - - "github.com/Sirupsen/logrus" -) - -type Rlimit struct { - Type int `json:"type"` - Hard uint64 `json:"hard"` - Soft uint64 `json:"soft"` -} - -// IDMap represents UID/GID Mappings for User Namespaces. -type IDMap struct { - ContainerID int `json:"container_id"` - HostID int `json:"host_id"` - Size int `json:"size"` -} - -// Seccomp represents syscall restrictions -// By default, only the native architecture of the kernel is allowed to be used -// for syscalls. Additional architectures can be added by specifying them in -// Architectures. -type Seccomp struct { - DefaultAction Action `json:"default_action"` - Architectures []string `json:"architectures"` - Syscalls []*Syscall `json:"syscalls"` -} - -// Action is taken upon rule match in Seccomp -type Action int - -const ( - Kill Action = iota + 1 - Errno - Trap - Allow - Trace -) - -// Operator is a comparison operator to be used when matching syscall arguments in Seccomp -type Operator int - -const ( - EqualTo Operator = iota + 1 - NotEqualTo - GreaterThan - GreaterThanOrEqualTo - LessThan - LessThanOrEqualTo - MaskEqualTo -) - -// Arg is a rule to match a specific syscall argument in Seccomp -type Arg struct { - Index uint `json:"index"` - Value uint64 `json:"value"` - ValueTwo uint64 `json:"value_two"` - Op Operator `json:"op"` -} - -// Syscall is a rule to match a syscall in Seccomp -type Syscall struct { - Name string `json:"name"` - Action Action `json:"action"` - Args []*Arg `json:"args"` -} - -// TODO Windows. Many of these fields should be factored out into those parts -// which are common across platforms, and those which are platform specific. - -// Config defines configuration options for executing a process inside a contained environment. -type Config struct { - // NoPivotRoot will use MS_MOVE and a chroot to jail the process into the container's rootfs - // This is a common option when the container is running in ramdisk - NoPivotRoot bool `json:"no_pivot_root"` - - // ParentDeathSignal specifies the signal that is sent to the container's process in the case - // that the parent process dies. - ParentDeathSignal int `json:"parent_death_signal"` - - // Path to a directory containing the container's root filesystem. - Rootfs string `json:"rootfs"` - - // Readonlyfs will remount the container's rootfs as readonly where only externally mounted - // bind mounts are writtable. - Readonlyfs bool `json:"readonlyfs"` - - // Specifies the mount propagation flags to be applied to /. - RootPropagation int `json:"rootPropagation"` - - // Mounts specify additional source and destination paths that will be mounted inside the container's - // rootfs and mount namespace if specified - Mounts []*Mount `json:"mounts"` - - // The device nodes that should be automatically created within the container upon container start. Note, make sure that the node is marked as allowed in the cgroup as well! - Devices []*Device `json:"devices"` - - MountLabel string `json:"mount_label"` - - // Hostname optionally sets the container's hostname if provided - Hostname string `json:"hostname"` - - // Namespaces specifies the container's namespaces that it should setup when cloning the init process - // If a namespace is not provided that namespace is shared from the container's parent process - Namespaces Namespaces `json:"namespaces"` - - // Capabilities specify the capabilities to keep when executing the process inside the container - // All capbilities not specified will be dropped from the processes capability mask - Capabilities []string `json:"capabilities"` - - // Networks specifies the container's network setup to be created - Networks []*Network `json:"networks"` - - // Routes can be specified to create entries in the route table as the container is started - Routes []*Route `json:"routes"` - - // Cgroups specifies specific cgroup settings for the various subsystems that the container is - // placed into to limit the resources the container has available - Cgroups *Cgroup `json:"cgroups"` - - // AppArmorProfile specifies the profile to apply to the process running in the container and is - // change at the time the process is execed - AppArmorProfile string `json:"apparmor_profile,omitempty"` - - // ProcessLabel specifies the label to apply to the process running in the container. It is - // commonly used by selinux - ProcessLabel string `json:"process_label,omitempty"` - - // Rlimits specifies the resource limits, such as max open files, to set in the container - // If Rlimits are not set, the container will inherit rlimits from the parent process - Rlimits []Rlimit `json:"rlimits,omitempty"` - - // OomScoreAdj specifies the adjustment to be made by the kernel when calculating oom scores - // for a process. Valid values are between the range [-1000, '1000'], where processes with - // higher scores are preferred for being killed. - // More information about kernel oom score calculation here: https://lwn.net/Articles/317814/ - OomScoreAdj int `json:"oom_score_adj"` - - // UidMappings is an array of User ID mappings for User Namespaces - UidMappings []IDMap `json:"uid_mappings"` - - // GidMappings is an array of Group ID mappings for User Namespaces - GidMappings []IDMap `json:"gid_mappings"` - - // MaskPaths specifies paths within the container's rootfs to mask over with a bind - // mount pointing to /dev/null as to prevent reads of the file. - MaskPaths []string `json:"mask_paths"` - - // ReadonlyPaths specifies paths within the container's rootfs to remount as read-only - // so that these files prevent any writes. - ReadonlyPaths []string `json:"readonly_paths"` - - // Sysctl is a map of properties and their values. It is the equivalent of using - // sysctl -w my.property.name value in Linux. - Sysctl map[string]string `json:"sysctl"` - - // Seccomp allows actions to be taken whenever a syscall is made within the container. - // A number of rules are given, each having an action to be taken if a syscall matches it. - // A default action to be taken if no rules match is also given. - Seccomp *Seccomp `json:"seccomp"` - - // NoNewPrivileges controls whether processes in the container can gain additional privileges. - NoNewPrivileges bool `json:"no_new_privileges,omitempty"` - - // Hooks are a collection of actions to perform at various container lifecycle events. - // CommandHooks are serialized to JSON, but other hooks are not. - Hooks *Hooks - - // Version is the version of opencontainer specification that is supported. - Version string `json:"version"` - - // Labels are user defined metadata that is stored in the config and populated on the state - Labels []string `json:"labels"` - - // NoNewKeyring will not allocated a new session keyring for the container. It will use the - // callers keyring in this case. - NoNewKeyring bool `json:"no_new_keyring"` -} - -type Hooks struct { - // Prestart commands are executed after the container namespaces are created, - // but before the user supplied command is executed from init. - Prestart []Hook - - // Poststart commands are executed after the container init process starts. - Poststart []Hook - - // Poststop commands are executed after the container init process exits. - Poststop []Hook -} - -func (hooks *Hooks) UnmarshalJSON(b []byte) error { - var state struct { - Prestart []CommandHook - Poststart []CommandHook - Poststop []CommandHook - } - - if err := json.Unmarshal(b, &state); err != nil { - return err - } - - deserialize := func(shooks []CommandHook) (hooks []Hook) { - for _, shook := range shooks { - hooks = append(hooks, shook) - } - - return hooks - } - - hooks.Prestart = deserialize(state.Prestart) - hooks.Poststart = deserialize(state.Poststart) - hooks.Poststop = deserialize(state.Poststop) - return nil -} - -func (hooks Hooks) MarshalJSON() ([]byte, error) { - serialize := func(hooks []Hook) (serializableHooks []CommandHook) { - for _, hook := range hooks { - switch chook := hook.(type) { - case CommandHook: - serializableHooks = append(serializableHooks, chook) - default: - logrus.Warnf("cannot serialize hook of type %T, skipping", hook) - } - } - - return serializableHooks - } - - return json.Marshal(map[string]interface{}{ - "prestart": serialize(hooks.Prestart), - "poststart": serialize(hooks.Poststart), - "poststop": serialize(hooks.Poststop), - }) -} - -// HookState is the payload provided to a hook on execution. -type HookState struct { - Version string `json:"ociVersion"` - ID string `json:"id"` - Pid int `json:"pid"` - Root string `json:"root"` - BundlePath string `json:"bundlePath"` -} - -type Hook interface { - // Run executes the hook with the provided state. - Run(HookState) error -} - -// NewFunctionHook will call the provided function when the hook is run. -func NewFunctionHook(f func(HookState) error) FuncHook { - return FuncHook{ - run: f, - } -} - -type FuncHook struct { - run func(HookState) error -} - -func (f FuncHook) Run(s HookState) error { - return f.run(s) -} - -type Command struct { - Path string `json:"path"` - Args []string `json:"args"` - Env []string `json:"env"` - Dir string `json:"dir"` - Timeout *time.Duration `json:"timeout"` -} - -// NewCommandHook will execute the provided command when the hook is run. -func NewCommandHook(cmd Command) CommandHook { - return CommandHook{ - Command: cmd, - } -} - -type CommandHook struct { - Command -} - -func (c Command) Run(s HookState) error { - b, err := json.Marshal(s) - if err != nil { - return err - } - var stdout, stderr bytes.Buffer - cmd := exec.Cmd{ - Path: c.Path, - Args: c.Args, - Env: c.Env, - Stdin: bytes.NewReader(b), - Stdout: &stdout, - Stderr: &stderr, - } - if err := cmd.Start(); err != nil { - return err - } - errC := make(chan error, 1) - go func() { - err := cmd.Wait() - if err != nil { - err = fmt.Errorf("error running hook: %v, stdout: %s, stderr: %s", err, stdout.String(), stderr.String()) - } - errC <- err - }() - var timerCh <-chan time.Time - if c.Timeout != nil { - timer := time.NewTimer(*c.Timeout) - defer timer.Stop() - timerCh = timer.C - } - select { - case err := <-errC: - return err - case <-timerCh: - cmd.Process.Kill() - cmd.Wait() - return fmt.Errorf("hook ran past specified timeout of %.1fs", c.Timeout.Seconds()) - } -} diff --git a/components/cli/vendor/github.com/opencontainers/runc/libcontainer/configs/config_unix.go b/components/cli/vendor/github.com/opencontainers/runc/libcontainer/configs/config_unix.go deleted file mode 100644 index a60554a7b9..0000000000 --- a/components/cli/vendor/github.com/opencontainers/runc/libcontainer/configs/config_unix.go +++ /dev/null @@ -1,51 +0,0 @@ -// +build freebsd linux - -package configs - -import "fmt" - -// HostUID gets the root uid for the process on host which could be non-zero -// when user namespaces are enabled. -func (c Config) HostUID() (int, error) { - if c.Namespaces.Contains(NEWUSER) { - if c.UidMappings == nil { - return -1, fmt.Errorf("User namespaces enabled, but no user mappings found.") - } - id, found := c.hostIDFromMapping(0, c.UidMappings) - if !found { - return -1, fmt.Errorf("User namespaces enabled, but no root user mapping found.") - } - return id, nil - } - // Return default root uid 0 - return 0, nil -} - -// HostGID gets the root gid for the process on host which could be non-zero -// when user namespaces are enabled. -func (c Config) HostGID() (int, error) { - if c.Namespaces.Contains(NEWUSER) { - if c.GidMappings == nil { - return -1, fmt.Errorf("User namespaces enabled, but no gid mappings found.") - } - id, found := c.hostIDFromMapping(0, c.GidMappings) - if !found { - return -1, fmt.Errorf("User namespaces enabled, but no root group mapping found.") - } - return id, nil - } - // Return default root gid 0 - return 0, nil -} - -// Utility function that gets a host ID for a container ID from user namespace map -// if that ID is present in the map. -func (c Config) hostIDFromMapping(containerID int, uMap []IDMap) (int, bool) { - for _, m := range uMap { - if (containerID >= m.ContainerID) && (containerID <= (m.ContainerID + m.Size - 1)) { - hostID := m.HostID + (containerID - m.ContainerID) - return hostID, true - } - } - return -1, false -} diff --git a/components/cli/vendor/github.com/opencontainers/runc/libcontainer/configs/device.go b/components/cli/vendor/github.com/opencontainers/runc/libcontainer/configs/device.go deleted file mode 100644 index 8701bb212d..0000000000 --- a/components/cli/vendor/github.com/opencontainers/runc/libcontainer/configs/device.go +++ /dev/null @@ -1,57 +0,0 @@ -package configs - -import ( - "fmt" - "os" -) - -const ( - Wildcard = -1 -) - -// TODO Windows: This can be factored out in the future - -type Device struct { - // Device type, block, char, etc. - Type rune `json:"type"` - - // Path to the device. - Path string `json:"path"` - - // Major is the device's major number. - Major int64 `json:"major"` - - // Minor is the device's minor number. - Minor int64 `json:"minor"` - - // Cgroup permissions format, rwm. - Permissions string `json:"permissions"` - - // FileMode permission bits for the device. - FileMode os.FileMode `json:"file_mode"` - - // Uid of the device. - Uid uint32 `json:"uid"` - - // Gid of the device. - Gid uint32 `json:"gid"` - - // Write the file to the allowed list - Allow bool `json:"allow"` -} - -func (d *Device) CgroupString() string { - return fmt.Sprintf("%c %s:%s %s", d.Type, deviceNumberString(d.Major), deviceNumberString(d.Minor), d.Permissions) -} - -func (d *Device) Mkdev() int { - return int((d.Major << 8) | (d.Minor & 0xff) | ((d.Minor & 0xfff00) << 12)) -} - -// deviceNumberString converts the device number to a string return result. -func deviceNumberString(number int64) string { - if number == Wildcard { - return "*" - } - return fmt.Sprint(number) -} diff --git a/components/cli/vendor/github.com/opencontainers/runc/libcontainer/configs/device_defaults.go b/components/cli/vendor/github.com/opencontainers/runc/libcontainer/configs/device_defaults.go deleted file mode 100644 index 4d348d217e..0000000000 --- a/components/cli/vendor/github.com/opencontainers/runc/libcontainer/configs/device_defaults.go +++ /dev/null @@ -1,111 +0,0 @@ -// +build linux freebsd - -package configs - -var ( - // DefaultSimpleDevices are devices that are to be both allowed and created. - DefaultSimpleDevices = []*Device{ - // /dev/null and zero - { - Path: "/dev/null", - Type: 'c', - Major: 1, - Minor: 3, - Permissions: "rwm", - FileMode: 0666, - }, - { - Path: "/dev/zero", - Type: 'c', - Major: 1, - Minor: 5, - Permissions: "rwm", - FileMode: 0666, - }, - - { - Path: "/dev/full", - Type: 'c', - Major: 1, - Minor: 7, - Permissions: "rwm", - FileMode: 0666, - }, - - // consoles and ttys - { - Path: "/dev/tty", - Type: 'c', - Major: 5, - Minor: 0, - Permissions: "rwm", - FileMode: 0666, - }, - - // /dev/urandom,/dev/random - { - Path: "/dev/urandom", - Type: 'c', - Major: 1, - Minor: 9, - Permissions: "rwm", - FileMode: 0666, - }, - { - Path: "/dev/random", - Type: 'c', - Major: 1, - Minor: 8, - Permissions: "rwm", - FileMode: 0666, - }, - } - DefaultAllowedDevices = append([]*Device{ - // allow mknod for any device - { - Type: 'c', - Major: Wildcard, - Minor: Wildcard, - Permissions: "m", - }, - { - Type: 'b', - Major: Wildcard, - Minor: Wildcard, - Permissions: "m", - }, - - { - Path: "/dev/console", - Type: 'c', - Major: 5, - Minor: 1, - Permissions: "rwm", - }, - // /dev/pts/ - pts namespaces are "coming soon" - { - Path: "", - Type: 'c', - Major: 136, - Minor: Wildcard, - Permissions: "rwm", - }, - { - Path: "", - Type: 'c', - Major: 5, - Minor: 2, - Permissions: "rwm", - }, - - // tuntap - { - Path: "", - Type: 'c', - Major: 10, - Minor: 200, - Permissions: "rwm", - }, - }, DefaultSimpleDevices...) - DefaultAutoCreatedDevices = append([]*Device{}, DefaultSimpleDevices...) -) diff --git a/components/cli/vendor/github.com/opencontainers/runc/libcontainer/configs/hugepage_limit.go b/components/cli/vendor/github.com/opencontainers/runc/libcontainer/configs/hugepage_limit.go deleted file mode 100644 index d30216380b..0000000000 --- a/components/cli/vendor/github.com/opencontainers/runc/libcontainer/configs/hugepage_limit.go +++ /dev/null @@ -1,9 +0,0 @@ -package configs - -type HugepageLimit struct { - // which type of hugepage to limit. - Pagesize string `json:"page_size"` - - // usage limit for hugepage. - Limit uint64 `json:"limit"` -} diff --git a/components/cli/vendor/github.com/opencontainers/runc/libcontainer/configs/interface_priority_map.go b/components/cli/vendor/github.com/opencontainers/runc/libcontainer/configs/interface_priority_map.go deleted file mode 100644 index 9a0395eaf5..0000000000 --- a/components/cli/vendor/github.com/opencontainers/runc/libcontainer/configs/interface_priority_map.go +++ /dev/null @@ -1,14 +0,0 @@ -package configs - -import ( - "fmt" -) - -type IfPrioMap struct { - Interface string `json:"interface"` - Priority int64 `json:"priority"` -} - -func (i *IfPrioMap) CgroupString() string { - return fmt.Sprintf("%s %d", i.Interface, i.Priority) -} diff --git a/components/cli/vendor/github.com/opencontainers/runc/libcontainer/configs/mount.go b/components/cli/vendor/github.com/opencontainers/runc/libcontainer/configs/mount.go deleted file mode 100644 index 670757ddb5..0000000000 --- a/components/cli/vendor/github.com/opencontainers/runc/libcontainer/configs/mount.go +++ /dev/null @@ -1,39 +0,0 @@ -package configs - -const ( - // EXT_COPYUP is a directive to copy up the contents of a directory when - // a tmpfs is mounted over it. - EXT_COPYUP = 1 << iota -) - -type Mount struct { - // Source path for the mount. - Source string `json:"source"` - - // Destination path for the mount inside the container. - Destination string `json:"destination"` - - // Device the mount is for. - Device string `json:"device"` - - // Mount flags. - Flags int `json:"flags"` - - // Propagation Flags - PropagationFlags []int `json:"propagation_flags"` - - // Mount data applied to the mount. - Data string `json:"data"` - - // Relabel source if set, "z" indicates shared, "Z" indicates unshared. - Relabel string `json:"relabel"` - - // Extensions are additional flags that are specific to runc. - Extensions int `json:"extensions"` - - // Optional Command to be run before Source is mounted. - PremountCmds []Command `json:"premount_cmds"` - - // Optional Command to be run after Source is mounted. - PostmountCmds []Command `json:"postmount_cmds"` -} diff --git a/components/cli/vendor/github.com/opencontainers/runc/libcontainer/configs/namespaces.go b/components/cli/vendor/github.com/opencontainers/runc/libcontainer/configs/namespaces.go deleted file mode 100644 index a3329a31a9..0000000000 --- a/components/cli/vendor/github.com/opencontainers/runc/libcontainer/configs/namespaces.go +++ /dev/null @@ -1,5 +0,0 @@ -package configs - -type NamespaceType string - -type Namespaces []Namespace diff --git a/components/cli/vendor/github.com/opencontainers/runc/libcontainer/configs/namespaces_syscall.go b/components/cli/vendor/github.com/opencontainers/runc/libcontainer/configs/namespaces_syscall.go deleted file mode 100644 index fb4b852222..0000000000 --- a/components/cli/vendor/github.com/opencontainers/runc/libcontainer/configs/namespaces_syscall.go +++ /dev/null @@ -1,31 +0,0 @@ -// +build linux - -package configs - -import "syscall" - -func (n *Namespace) Syscall() int { - return namespaceInfo[n.Type] -} - -var namespaceInfo = map[NamespaceType]int{ - NEWNET: syscall.CLONE_NEWNET, - NEWNS: syscall.CLONE_NEWNS, - NEWUSER: syscall.CLONE_NEWUSER, - NEWIPC: syscall.CLONE_NEWIPC, - NEWUTS: syscall.CLONE_NEWUTS, - NEWPID: syscall.CLONE_NEWPID, -} - -// CloneFlags parses the container's Namespaces options to set the correct -// flags on clone, unshare. This function returns flags only for new namespaces. -func (n *Namespaces) CloneFlags() uintptr { - var flag int - for _, v := range *n { - if v.Path != "" { - continue - } - flag |= namespaceInfo[v.Type] - } - return uintptr(flag) -} diff --git a/components/cli/vendor/github.com/opencontainers/runc/libcontainer/configs/namespaces_syscall_unsupported.go b/components/cli/vendor/github.com/opencontainers/runc/libcontainer/configs/namespaces_syscall_unsupported.go deleted file mode 100644 index 0547223a9d..0000000000 --- a/components/cli/vendor/github.com/opencontainers/runc/libcontainer/configs/namespaces_syscall_unsupported.go +++ /dev/null @@ -1,15 +0,0 @@ -// +build !linux,!windows - -package configs - -func (n *Namespace) Syscall() int { - panic("No namespace syscall support") - return 0 -} - -// CloneFlags parses the container's Namespaces options to set the correct -// flags on clone, unshare. This function returns flags only for new namespaces. -func (n *Namespaces) CloneFlags() uintptr { - panic("No namespace syscall support") - return uintptr(0) -} diff --git a/components/cli/vendor/github.com/opencontainers/runc/libcontainer/configs/namespaces_unix.go b/components/cli/vendor/github.com/opencontainers/runc/libcontainer/configs/namespaces_unix.go deleted file mode 100644 index 8beba9d300..0000000000 --- a/components/cli/vendor/github.com/opencontainers/runc/libcontainer/configs/namespaces_unix.go +++ /dev/null @@ -1,127 +0,0 @@ -// +build linux freebsd - -package configs - -import ( - "fmt" - "os" - "sync" -) - -const ( - NEWNET NamespaceType = "NEWNET" - NEWPID NamespaceType = "NEWPID" - NEWNS NamespaceType = "NEWNS" - NEWUTS NamespaceType = "NEWUTS" - NEWIPC NamespaceType = "NEWIPC" - NEWUSER NamespaceType = "NEWUSER" -) - -var ( - nsLock sync.Mutex - supportedNamespaces = make(map[NamespaceType]bool) -) - -// NsName converts the namespace type to its filename -func NsName(ns NamespaceType) string { - switch ns { - case NEWNET: - return "net" - case NEWNS: - return "mnt" - case NEWPID: - return "pid" - case NEWIPC: - return "ipc" - case NEWUSER: - return "user" - case NEWUTS: - return "uts" - } - return "" -} - -// IsNamespaceSupported returns whether a namespace is available or -// not -func IsNamespaceSupported(ns NamespaceType) bool { - nsLock.Lock() - defer nsLock.Unlock() - supported, ok := supportedNamespaces[ns] - if ok { - return supported - } - nsFile := NsName(ns) - // if the namespace type is unknown, just return false - if nsFile == "" { - return false - } - _, err := os.Stat(fmt.Sprintf("/proc/self/ns/%s", nsFile)) - // a namespace is supported if it exists and we have permissions to read it - supported = err == nil - supportedNamespaces[ns] = supported - return supported -} - -func NamespaceTypes() []NamespaceType { - return []NamespaceType{ - NEWNET, - NEWPID, - NEWNS, - NEWUTS, - NEWIPC, - NEWUSER, - } -} - -// Namespace defines configuration for each namespace. It specifies an -// alternate path that is able to be joined via setns. -type Namespace struct { - Type NamespaceType `json:"type"` - Path string `json:"path"` -} - -func (n *Namespace) GetPath(pid int) string { - if n.Path != "" { - return n.Path - } - return fmt.Sprintf("/proc/%d/ns/%s", pid, NsName(n.Type)) -} - -func (n *Namespaces) Remove(t NamespaceType) bool { - i := n.index(t) - if i == -1 { - return false - } - *n = append((*n)[:i], (*n)[i+1:]...) - return true -} - -func (n *Namespaces) Add(t NamespaceType, path string) { - i := n.index(t) - if i == -1 { - *n = append(*n, Namespace{Type: t, Path: path}) - return - } - (*n)[i].Path = path -} - -func (n *Namespaces) index(t NamespaceType) int { - for i, ns := range *n { - if ns.Type == t { - return i - } - } - return -1 -} - -func (n *Namespaces) Contains(t NamespaceType) bool { - return n.index(t) != -1 -} - -func (n *Namespaces) PathOf(t NamespaceType) string { - i := n.index(t) - if i == -1 { - return "" - } - return (*n)[i].Path -} diff --git a/components/cli/vendor/github.com/opencontainers/runc/libcontainer/configs/namespaces_unsupported.go b/components/cli/vendor/github.com/opencontainers/runc/libcontainer/configs/namespaces_unsupported.go deleted file mode 100644 index 9a74033cea..0000000000 --- a/components/cli/vendor/github.com/opencontainers/runc/libcontainer/configs/namespaces_unsupported.go +++ /dev/null @@ -1,8 +0,0 @@ -// +build !linux,!freebsd - -package configs - -// Namespace defines configuration for each namespace. It specifies an -// alternate path that is able to be joined via setns. -type Namespace struct { -} diff --git a/components/cli/vendor/github.com/opencontainers/runc/libcontainer/configs/network.go b/components/cli/vendor/github.com/opencontainers/runc/libcontainer/configs/network.go deleted file mode 100644 index ccdb228e14..0000000000 --- a/components/cli/vendor/github.com/opencontainers/runc/libcontainer/configs/network.go +++ /dev/null @@ -1,72 +0,0 @@ -package configs - -// Network defines configuration for a container's networking stack -// -// The network configuration can be omitted from a container causing the -// container to be setup with the host's networking stack -type Network struct { - // Type sets the networks type, commonly veth and loopback - Type string `json:"type"` - - // Name of the network interface - Name string `json:"name"` - - // The bridge to use. - Bridge string `json:"bridge"` - - // MacAddress contains the MAC address to set on the network interface - MacAddress string `json:"mac_address"` - - // Address contains the IPv4 and mask to set on the network interface - Address string `json:"address"` - - // Gateway sets the gateway address that is used as the default for the interface - Gateway string `json:"gateway"` - - // IPv6Address contains the IPv6 and mask to set on the network interface - IPv6Address string `json:"ipv6_address"` - - // IPv6Gateway sets the ipv6 gateway address that is used as the default for the interface - IPv6Gateway string `json:"ipv6_gateway"` - - // Mtu sets the mtu value for the interface and will be mirrored on both the host and - // container's interfaces if a pair is created, specifically in the case of type veth - // Note: This does not apply to loopback interfaces. - Mtu int `json:"mtu"` - - // TxQueueLen sets the tx_queuelen value for the interface and will be mirrored on both the host and - // container's interfaces if a pair is created, specifically in the case of type veth - // Note: This does not apply to loopback interfaces. - TxQueueLen int `json:"txqueuelen"` - - // HostInterfaceName is a unique name of a veth pair that resides on in the host interface of the - // container. - HostInterfaceName string `json:"host_interface_name"` - - // HairpinMode specifies if hairpin NAT should be enabled on the virtual interface - // bridge port in the case of type veth - // Note: This is unsupported on some systems. - // Note: This does not apply to loopback interfaces. - HairpinMode bool `json:"hairpin_mode"` -} - -// Routes can be specified to create entries in the route table as the container is started -// -// All of destination, source, and gateway should be either IPv4 or IPv6. -// One of the three options must be present, and omitted entries will use their -// IP family default for the route table. For IPv4 for example, setting the -// gateway to 1.2.3.4 and the interface to eth0 will set up a standard -// destination of 0.0.0.0(or *) when viewed in the route table. -type Route struct { - // Sets the destination and mask, should be a CIDR. Accepts IPv4 and IPv6 - Destination string `json:"destination"` - - // Sets the source and mask, should be a CIDR. Accepts IPv4 and IPv6 - Source string `json:"source"` - - // Sets the gateway. Accepts IPv4 and IPv6 - Gateway string `json:"gateway"` - - // The device to set this route up for, for example: eth0 - InterfaceName string `json:"interface_name"` -} diff --git a/components/cli/vendor/github.com/opencontainers/selinux/LICENSE b/components/cli/vendor/github.com/opencontainers/selinux/LICENSE deleted file mode 100644 index 8dada3edaf..0000000000 --- a/components/cli/vendor/github.com/opencontainers/selinux/LICENSE +++ /dev/null @@ -1,201 +0,0 @@ - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "{}" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright {yyyy} {name of copyright owner} - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. diff --git a/components/cli/vendor/github.com/opencontainers/selinux/README.md b/components/cli/vendor/github.com/opencontainers/selinux/README.md deleted file mode 100644 index 043a929371..0000000000 --- a/components/cli/vendor/github.com/opencontainers/selinux/README.md +++ /dev/null @@ -1,7 +0,0 @@ -# selinux - -[![GoDoc](https://godoc.org/github.com/opencontainers/selinux?status.svg)](https://godoc.org/github.com/opencontainers/selinux) [![Go Report Card](https://goreportcard.com/badge/github.com/opencontainers/selinux)](https://goreportcard.com/report/github.com/opencontainers/selinux) [![Build Status](https://travis-ci.org/opencontainers/selinux.svg?branch=master)](https://travis-ci.org/opencontainers/selinux) - -Common SELinux package used across the container ecosystem. - -Please see the [godoc](https://godoc.org/github.com/opencontainers/selinux) for more information. diff --git a/components/cli/vendor/github.com/opencontainers/selinux/go-selinux/label/label.go b/components/cli/vendor/github.com/opencontainers/selinux/go-selinux/label/label.go deleted file mode 100644 index 6cfc5fded8..0000000000 --- a/components/cli/vendor/github.com/opencontainers/selinux/go-selinux/label/label.go +++ /dev/null @@ -1,84 +0,0 @@ -// +build !selinux !linux - -package label - -// InitLabels returns the process label and file labels to be used within -// the container. A list of options can be passed into this function to alter -// the labels. -func InitLabels(options []string) (string, string, error) { - return "", "", nil -} - -func GetROMountLabel() string { - return "" -} - -func GenLabels(options string) (string, string, error) { - return "", "", nil -} - -func FormatMountLabel(src string, mountLabel string) string { - return src -} - -func SetProcessLabel(processLabel string) error { - return nil -} - -func GetFileLabel(path string) (string, error) { - return "", nil -} - -func SetFileLabel(path string, fileLabel string) error { - return nil -} - -func SetFileCreateLabel(fileLabel string) error { - return nil -} - -func Relabel(path string, fileLabel string, shared bool) error { - return nil -} - -func GetPidLabel(pid int) (string, error) { - return "", nil -} - -func Init() { -} - -func ReserveLabel(label string) error { - return nil -} - -func ReleaseLabel(label string) error { - return nil -} - -// DupSecOpt takes a process label and returns security options that -// can be used to set duplicate labels on future container processes -func DupSecOpt(src string) []string { - return nil -} - -// DisableSecOpt returns a security opt that can disable labeling -// support for future container processes -func DisableSecOpt() []string { - return nil -} - -// Validate checks that the label does not include unexpected options -func Validate(label string) error { - return nil -} - -// RelabelNeeded checks whether the user requested a relabel -func RelabelNeeded(label string) bool { - return false -} - -// IsShared checks that the label includes a "shared" mark -func IsShared(label string) bool { - return false -} diff --git a/components/cli/vendor/github.com/opencontainers/selinux/go-selinux/label/label_selinux.go b/components/cli/vendor/github.com/opencontainers/selinux/go-selinux/label/label_selinux.go deleted file mode 100644 index 569dcf0841..0000000000 --- a/components/cli/vendor/github.com/opencontainers/selinux/go-selinux/label/label_selinux.go +++ /dev/null @@ -1,204 +0,0 @@ -// +build selinux,linux - -package label - -import ( - "fmt" - "strings" - - "github.com/opencontainers/selinux/go-selinux" -) - -// Valid Label Options -var validOptions = map[string]bool{ - "disable": true, - "type": true, - "user": true, - "role": true, - "level": true, -} - -var ErrIncompatibleLabel = fmt.Errorf("Bad SELinux option z and Z can not be used together") - -// InitLabels returns the process label and file labels to be used within -// the container. A list of options can be passed into this function to alter -// the labels. The labels returned will include a random MCS String, that is -// guaranteed to be unique. -func InitLabels(options []string) (string, string, error) { - if !selinux.GetEnabled() { - return "", "", nil - } - processLabel, mountLabel := selinux.ContainerLabels() - if processLabel != "" { - pcon := selinux.NewContext(processLabel) - mcon := selinux.NewContext(mountLabel) - for _, opt := range options { - if opt == "disable" { - return "", "", nil - } - if i := strings.Index(opt, ":"); i == -1 { - return "", "", fmt.Errorf("Bad label option %q, valid options 'disable' or \n'user, role, level, type' followed by ':' and a value", opt) - } - con := strings.SplitN(opt, ":", 2) - if !validOptions[con[0]] { - return "", "", fmt.Errorf("Bad label option %q, valid options 'disable, user, role, level, type'", con[0]) - - } - pcon[con[0]] = con[1] - if con[0] == "level" || con[0] == "user" { - mcon[con[0]] = con[1] - } - } - processLabel = pcon.Get() - mountLabel = mcon.Get() - } - return processLabel, mountLabel, nil -} - -func ROMountLabel() string { - return selinux.ROFileLabel() -} - -// DEPRECATED: The GenLabels function is only to be used during the transition to the official API. -func GenLabels(options string) (string, string, error) { - return InitLabels(strings.Fields(options)) -} - -// FormatMountLabel returns a string to be used by the mount command. -// The format of this string will be used to alter the labeling of the mountpoint. -// The string returned is suitable to be used as the options field of the mount command. -// If you need to have additional mount point options, you can pass them in as -// the first parameter. Second parameter is the label that you wish to apply -// to all content in the mount point. -func FormatMountLabel(src, mountLabel string) string { - if mountLabel != "" { - switch src { - case "": - src = fmt.Sprintf("context=%q", mountLabel) - default: - src = fmt.Sprintf("%s,context=%q", src, mountLabel) - } - } - return src -} - -// SetProcessLabel takes a process label and tells the kernel to assign the -// label to the next program executed by the current process. -func SetProcessLabel(processLabel string) error { - if processLabel == "" { - return nil - } - return selinux.SetExecLabel(processLabel) -} - -// ProcessLabel returns the process label that the kernel will assign -// to the next program executed by the current process. If "" is returned -// this indicates that the default labeling will happen for the process. -func ProcessLabel() (string, error) { - return selinux.ExecLabel() -} - -// GetFileLabel returns the label for specified path -func FileLabel(path string) (string, error) { - return selinux.FileLabel(path) -} - -// SetFileLabel modifies the "path" label to the specified file label -func SetFileLabel(path string, fileLabel string) error { - if selinux.GetEnabled() && fileLabel != "" { - return selinux.SetFileLabel(path, fileLabel) - } - return nil -} - -// SetFileCreateLabel tells the kernel the label for all files to be created -func SetFileCreateLabel(fileLabel string) error { - if selinux.GetEnabled() { - return selinux.SetFSCreateLabel(fileLabel) - } - return nil -} - -// Relabel changes the label of path to the filelabel string. -// It changes the MCS label to s0 if shared is true. -// This will allow all containers to share the content. -func Relabel(path string, fileLabel string, shared bool) error { - if !selinux.GetEnabled() { - return nil - } - - if fileLabel == "" { - return nil - } - - exclude_paths := map[string]bool{"/": true, "/usr": true, "/etc": true} - if exclude_paths[path] { - return fmt.Errorf("SELinux relabeling of %s is not allowed", path) - } - - if shared { - c := selinux.NewContext(fileLabel) - c["level"] = "s0" - fileLabel = c.Get() - } - if err := selinux.Chcon(path, fileLabel, true); err != nil { - return err - } - return nil -} - -// PidLabel will return the label of the process running with the specified pid -func PidLabel(pid int) (string, error) { - return selinux.PidLabel(pid) -} - -// Init initialises the labeling system -func Init() { - selinux.GetEnabled() -} - -// ReserveLabel will record the fact that the MCS label has already been used. -// This will prevent InitLabels from using the MCS label in a newly created -// container -func ReserveLabel(label string) error { - selinux.ReserveLabel(label) - return nil -} - -// ReleaseLabel will remove the reservation of the MCS label. -// This will allow InitLabels to use the MCS label in a newly created -// containers -func ReleaseLabel(label string) error { - selinux.ReleaseLabel(label) - return nil -} - -// DupSecOpt takes a process label and returns security options that -// can be used to set duplicate labels on future container processes -func DupSecOpt(src string) []string { - return selinux.DupSecOpt(src) -} - -// DisableSecOpt returns a security opt that can disable labeling -// support for future container processes -func DisableSecOpt() []string { - return selinux.DisableSecOpt() -} - -// Validate checks that the label does not include unexpected options -func Validate(label string) error { - if strings.Contains(label, "z") && strings.Contains(label, "Z") { - return ErrIncompatibleLabel - } - return nil -} - -// RelabelNeeded checks whether the user requested a relabel -func RelabelNeeded(label string) bool { - return strings.Contains(label, "z") || strings.Contains(label, "Z") -} - -// IsShared checks that the label includes a "shared" mark -func IsShared(label string) bool { - return strings.Contains(label, "z") -} diff --git a/components/cli/vendor/github.com/opencontainers/selinux/go-selinux/selinux.go b/components/cli/vendor/github.com/opencontainers/selinux/go-selinux/selinux.go deleted file mode 100644 index 4cf2c45de7..0000000000 --- a/components/cli/vendor/github.com/opencontainers/selinux/go-selinux/selinux.go +++ /dev/null @@ -1,593 +0,0 @@ -// +build linux - -package selinux - -import ( - "bufio" - "crypto/rand" - "encoding/binary" - "fmt" - "io" - "os" - "path/filepath" - "regexp" - "strconv" - "strings" - "sync" - "syscall" -) - -const ( - // Enforcing constant indicate SELinux is in enforcing mode - Enforcing = 1 - // Permissive constant to indicate SELinux is in permissive mode - Permissive = 0 - // Disabled constant to indicate SELinux is disabled - Disabled = -1 - selinuxDir = "/etc/selinux/" - selinuxConfig = selinuxDir + "config" - selinuxTypeTag = "SELINUXTYPE" - selinuxTag = "SELINUX" - selinuxPath = "/sys/fs/selinux" - xattrNameSelinux = "security.selinux" - stRdOnly = 0x01 -) - -type selinuxState struct { - enabledSet bool - enabled bool - selinuxfsSet bool - selinuxfs string - mcsList map[string]bool - sync.Mutex -} - -var ( - assignRegex = regexp.MustCompile(`^([^=]+)=(.*)$`) - state = selinuxState{ - mcsList: make(map[string]bool), - } -) - -// Context is a representation of the SELinux label broken into 4 parts -type Context map[string]string - -func (s *selinuxState) setEnable(enabled bool) bool { - s.Lock() - defer s.Unlock() - s.enabledSet = true - s.enabled = enabled - return s.enabled -} - -func (s *selinuxState) getEnabled() bool { - s.Lock() - enabled := s.enabled - enabledSet := s.enabledSet - s.Unlock() - if enabledSet { - return enabled - } - - enabled = false - if fs := getSelinuxMountPoint(); fs != "" { - if con, _ := CurrentLabel(); con != "kernel" { - enabled = true - } - } - return s.setEnable(enabled) -} - -// SetDisabled disables selinux support for the package -func SetDisabled() { - state.setEnable(false) -} - -func (s *selinuxState) setSELinuxfs(selinuxfs string) string { - s.Lock() - defer s.Unlock() - s.selinuxfsSet = true - s.selinuxfs = selinuxfs - return s.selinuxfs -} - -func (s *selinuxState) getSELinuxfs() string { - s.Lock() - selinuxfs := s.selinuxfs - selinuxfsSet := s.selinuxfsSet - s.Unlock() - if selinuxfsSet { - return selinuxfs - } - - selinuxfs = "" - f, err := os.Open("/proc/self/mountinfo") - if err != nil { - return selinuxfs - } - defer f.Close() - - scanner := bufio.NewScanner(f) - for scanner.Scan() { - txt := scanner.Text() - // Safe as mountinfo encodes mountpoints with spaces as \040. - sepIdx := strings.Index(txt, " - ") - if sepIdx == -1 { - continue - } - if !strings.Contains(txt[sepIdx:], "selinuxfs") { - continue - } - fields := strings.Split(txt, " ") - if len(fields) < 5 { - continue - } - selinuxfs = fields[4] - break - } - - if selinuxfs != "" { - var buf syscall.Statfs_t - syscall.Statfs(selinuxfs, &buf) - if (buf.Flags & stRdOnly) == 1 { - selinuxfs = "" - } - } - return s.setSELinuxfs(selinuxfs) -} - -// getSelinuxMountPoint returns the path to the mountpoint of an selinuxfs -// filesystem or an empty string if no mountpoint is found. Selinuxfs is -// a proc-like pseudo-filesystem that exposes the selinux policy API to -// processes. The existence of an selinuxfs mount is used to determine -// whether selinux is currently enabled or not. -func getSelinuxMountPoint() string { - return state.getSELinuxfs() -} - -// GetEnabled returns whether selinux is currently enabled. -func GetEnabled() bool { - return state.getEnabled() -} - -func readConfig(target string) (value string) { - var ( - val, key string - bufin *bufio.Reader - ) - - in, err := os.Open(selinuxConfig) - if err != nil { - return "" - } - defer in.Close() - - bufin = bufio.NewReader(in) - - for done := false; !done; { - var line string - if line, err = bufin.ReadString('\n'); err != nil { - if err != io.EOF { - return "" - } - done = true - } - line = strings.TrimSpace(line) - if len(line) == 0 { - // Skip blank lines - continue - } - if line[0] == ';' || line[0] == '#' { - // Skip comments - continue - } - if groups := assignRegex.FindStringSubmatch(line); groups != nil { - key, val = strings.TrimSpace(groups[1]), strings.TrimSpace(groups[2]) - if key == target { - return strings.Trim(val, "\"") - } - } - } - return "" -} - -func getSELinuxPolicyRoot() string { - return selinuxDir + readConfig(selinuxTypeTag) -} - -func readCon(name string) (string, error) { - var val string - - in, err := os.Open(name) - if err != nil { - return "", err - } - defer in.Close() - - _, err = fmt.Fscanf(in, "%s", &val) - return val, err -} - -// SetFileLabel sets the SELinux label for this path or returns an error. -func SetFileLabel(path string, label string) error { - return lsetxattr(path, xattrNameSelinux, []byte(label), 0) -} - -// Filecon returns the SELinux label for this path or returns an error. -func FileLabel(path string) (string, error) { - label, err := lgetxattr(path, xattrNameSelinux) - if err != nil { - return "", err - } - // Trim the NUL byte at the end of the byte buffer, if present. - if len(label) > 0 && label[len(label)-1] == '\x00' { - label = label[:len(label)-1] - } - return string(label), nil -} - -/* -SetFSCreateLabel tells kernel the label to create all file system objects -created by this task. Setting label="" to return to default. -*/ -func SetFSCreateLabel(label string) error { - return writeCon(fmt.Sprintf("/proc/self/task/%d/attr/fscreate", syscall.Gettid()), label) -} - -/* -FSCreateLabel returns the default label the kernel which the kernel is using -for file system objects created by this task. "" indicates default. -*/ -func FSCreateLabel() (string, error) { - return readCon(fmt.Sprintf("/proc/self/task/%d/attr/fscreate", syscall.Gettid())) -} - -// CurrentLabel returns the SELinux label of the current process thread, or an error. -func CurrentLabel() (string, error) { - return readCon(fmt.Sprintf("/proc/self/task/%d/attr/current", syscall.Gettid())) -} - -// PidLabel returns the SELinux label of the given pid, or an error. -func PidLabel(pid int) (string, error) { - return readCon(fmt.Sprintf("/proc/%d/attr/current", pid)) -} - -/* -ExecLabel returns the SELinux label that the kernel will use for any programs -that are executed by the current process thread, or an error. -*/ -func ExecLabel() (string, error) { - return readCon(fmt.Sprintf("/proc/self/task/%d/attr/exec", syscall.Gettid())) -} - -func writeCon(name string, val string) error { - out, err := os.OpenFile(name, os.O_WRONLY, 0) - if err != nil { - return err - } - defer out.Close() - - if val != "" { - _, err = out.Write([]byte(val)) - } else { - _, err = out.Write(nil) - } - return err -} - -/* -SetExecLabel sets the SELinux label that the kernel will use for any programs -that are executed by the current process thread, or an error. -*/ -func SetExecLabel(label string) error { - return writeCon(fmt.Sprintf("/proc/self/task/%d/attr/exec", syscall.Gettid()), label) -} - -// Get returns the Context as a string -func (c Context) Get() string { - return fmt.Sprintf("%s:%s:%s:%s", c["user"], c["role"], c["type"], c["level"]) -} - -// NewContext creates a new Context struct from the specified label -func NewContext(label string) Context { - c := make(Context) - - if len(label) != 0 { - con := strings.SplitN(label, ":", 4) - c["user"] = con[0] - c["role"] = con[1] - c["type"] = con[2] - c["level"] = con[3] - } - return c -} - -// ReserveLabel reserves the MLS/MCS level component of the specified label -func ReserveLabel(label string) { - if len(label) != 0 { - con := strings.SplitN(label, ":", 4) - mcsAdd(con[3]) - } -} - -func selinuxEnforcePath() string { - return fmt.Sprintf("%s/enforce", selinuxPath) -} - -// EnforceMode returns the current SELinux mode Enforcing, Permissive, Disabled -func EnforceMode() int { - var enforce int - - enforceS, err := readCon(selinuxEnforcePath()) - if err != nil { - return -1 - } - - enforce, err = strconv.Atoi(string(enforceS)) - if err != nil { - return -1 - } - return enforce -} - -/* -SetEnforce sets the current SELinux mode Enforcing, Permissive. -Disabled is not valid, since this needs to be set at boot time. -*/ -func SetEnforceMode(mode int) error { - return writeCon(selinuxEnforcePath(), fmt.Sprintf("%d", mode)) -} - -/* -DefaultEnforceMode returns the systems default SELinux mode Enforcing, -Permissive or Disabled. Note this is is just the default at boot time. -EnforceMode tells you the systems current mode. -*/ -func DefaultEnforceMode() int { - switch readConfig(selinuxTag) { - case "enforcing": - return Enforcing - case "permissive": - return Permissive - } - return Disabled -} - -func mcsAdd(mcs string) error { - state.Lock() - defer state.Unlock() - if state.mcsList[mcs] { - return fmt.Errorf("MCS Label already exists") - } - state.mcsList[mcs] = true - return nil -} - -func mcsDelete(mcs string) { - state.Lock() - defer state.Unlock() - state.mcsList[mcs] = false -} - -func intToMcs(id int, catRange uint32) string { - var ( - SETSIZE = int(catRange) - TIER = SETSIZE - ORD = id - ) - - if id < 1 || id > 523776 { - return "" - } - - for ORD > TIER { - ORD = ORD - TIER - TIER-- - } - TIER = SETSIZE - TIER - ORD = ORD + TIER - return fmt.Sprintf("s0:c%d,c%d", TIER, ORD) -} - -func uniqMcs(catRange uint32) string { - var ( - n uint32 - c1, c2 uint32 - mcs string - ) - - for { - binary.Read(rand.Reader, binary.LittleEndian, &n) - c1 = n % catRange - binary.Read(rand.Reader, binary.LittleEndian, &n) - c2 = n % catRange - if c1 == c2 { - continue - } else { - if c1 > c2 { - c1, c2 = c2, c1 - } - } - mcs = fmt.Sprintf("s0:c%d,c%d", c1, c2) - if err := mcsAdd(mcs); err != nil { - continue - } - break - } - return mcs -} - -/* -ReleaseLabel will unreserve the MLS/MCS Level field of the specified label. -Allowing it to be used by another process. -*/ -func ReleaseLabel(label string) { - if len(label) != 0 { - con := strings.SplitN(label, ":", 4) - mcsDelete(con[3]) - } -} - -var roFileLabel string - -// ROFileLabel returns the specified SELinux readonly file label -func ROFileLabel() (fileLabel string) { - return roFileLabel -} - -/* -ContainerLabels returns an allocated processLabel and fileLabel to be used for -container labeling by the calling process. -*/ -func ContainerLabels() (processLabel string, fileLabel string) { - var ( - val, key string - bufin *bufio.Reader - ) - - if !GetEnabled() { - return "", "" - } - lxcPath := fmt.Sprintf("%s/contexts/lxc_contexts", getSELinuxPolicyRoot()) - in, err := os.Open(lxcPath) - if err != nil { - return "", "" - } - defer in.Close() - - bufin = bufio.NewReader(in) - - for done := false; !done; { - var line string - if line, err = bufin.ReadString('\n'); err != nil { - if err == io.EOF { - done = true - } else { - goto exit - } - } - line = strings.TrimSpace(line) - if len(line) == 0 { - // Skip blank lines - continue - } - if line[0] == ';' || line[0] == '#' { - // Skip comments - continue - } - if groups := assignRegex.FindStringSubmatch(line); groups != nil { - key, val = strings.TrimSpace(groups[1]), strings.TrimSpace(groups[2]) - if key == "process" { - processLabel = strings.Trim(val, "\"") - } - if key == "file" { - fileLabel = strings.Trim(val, "\"") - } - if key == "ro_file" { - roFileLabel = strings.Trim(val, "\"") - } - } - } - - if processLabel == "" || fileLabel == "" { - return "", "" - } - - if roFileLabel == "" { - roFileLabel = fileLabel - } -exit: - mcs := uniqMcs(1024) - scon := NewContext(processLabel) - scon["level"] = mcs - processLabel = scon.Get() - scon = NewContext(fileLabel) - scon["level"] = mcs - fileLabel = scon.Get() - return processLabel, fileLabel -} - -// SecurityCheckContext validates that the SELinux label is understood by the kernel -func SecurityCheckContext(val string) error { - return writeCon(fmt.Sprintf("%s.context", selinuxPath), val) -} - -/* -CopyLevel returns a label with the MLS/MCS level from src label replaces on -the dest label. -*/ -func CopyLevel(src, dest string) (string, error) { - if src == "" { - return "", nil - } - if err := SecurityCheckContext(src); err != nil { - return "", err - } - if err := SecurityCheckContext(dest); err != nil { - return "", err - } - scon := NewContext(src) - tcon := NewContext(dest) - mcsDelete(tcon["level"]) - mcsAdd(scon["level"]) - tcon["level"] = scon["level"] - return tcon.Get(), nil -} - -// Prevent users from relabing system files -func badPrefix(fpath string) error { - var badprefixes = []string{"/usr"} - - for _, prefix := range badprefixes { - if fpath == prefix || strings.HasPrefix(fpath, fmt.Sprintf("%s/", prefix)) { - return fmt.Errorf("relabeling content in %s is not allowed", prefix) - } - } - return nil -} - -// Chcon changes the fpath file object to the SELinux label label. -// If the fpath is a directory and recurse is true Chcon will walk the -// directory tree setting the label -func Chcon(fpath string, label string, recurse bool) error { - if label == "" { - return nil - } - if err := badPrefix(fpath); err != nil { - return err - } - callback := func(p string, info os.FileInfo, err error) error { - return SetFileLabel(p, label) - } - - if recurse { - return filepath.Walk(fpath, callback) - } - - return SetFileLabel(fpath, label) -} - -// DupSecOpt takes an SELinux process label and returns security options that -// can will set the SELinux Type and Level for future container processes -func DupSecOpt(src string) []string { - if src == "" { - return nil - } - con := NewContext(src) - if con["user"] == "" || - con["role"] == "" || - con["type"] == "" || - con["level"] == "" { - return nil - } - return []string{"user:" + con["user"], - "role:" + con["role"], - "type:" + con["type"], - "level:" + con["level"]} -} - -// DisableSecOpt returns a security opt that can be used to disabling SELinux -// labeling support for future container processes -func DisableSecOpt() []string { - return []string{"disable"} -} diff --git a/components/cli/vendor/github.com/opencontainers/selinux/go-selinux/xattrs.go b/components/cli/vendor/github.com/opencontainers/selinux/go-selinux/xattrs.go deleted file mode 100644 index 7f2ef85049..0000000000 --- a/components/cli/vendor/github.com/opencontainers/selinux/go-selinux/xattrs.go +++ /dev/null @@ -1,78 +0,0 @@ -// +build linux - -package selinux - -import ( - "syscall" - "unsafe" -) - -var _zero uintptr - -// Returns a []byte slice if the xattr is set and nil otherwise -// Requires path and its attribute as arguments -func lgetxattr(path string, attr string) ([]byte, error) { - var sz int - pathBytes, err := syscall.BytePtrFromString(path) - if err != nil { - return nil, err - } - attrBytes, err := syscall.BytePtrFromString(attr) - if err != nil { - return nil, err - } - - // Start with a 128 length byte array - sz = 128 - dest := make([]byte, sz) - destBytes := unsafe.Pointer(&dest[0]) - _sz, _, errno := syscall.Syscall6(syscall.SYS_LGETXATTR, uintptr(unsafe.Pointer(pathBytes)), uintptr(unsafe.Pointer(attrBytes)), uintptr(destBytes), uintptr(len(dest)), 0, 0) - - switch { - case errno == syscall.ENODATA: - return nil, errno - case errno == syscall.ENOTSUP: - return nil, errno - case errno == syscall.ERANGE: - // 128 byte array might just not be good enough, - // A dummy buffer is used ``uintptr(0)`` to get real size - // of the xattrs on disk - _sz, _, errno = syscall.Syscall6(syscall.SYS_LGETXATTR, uintptr(unsafe.Pointer(pathBytes)), uintptr(unsafe.Pointer(attrBytes)), uintptr(unsafe.Pointer(nil)), uintptr(0), 0, 0) - sz = int(_sz) - if sz < 0 { - return nil, errno - } - dest = make([]byte, sz) - destBytes := unsafe.Pointer(&dest[0]) - _sz, _, errno = syscall.Syscall6(syscall.SYS_LGETXATTR, uintptr(unsafe.Pointer(pathBytes)), uintptr(unsafe.Pointer(attrBytes)), uintptr(destBytes), uintptr(len(dest)), 0, 0) - if errno != 0 { - return nil, errno - } - case errno != 0: - return nil, errno - } - sz = int(_sz) - return dest[:sz], nil -} - -func lsetxattr(path string, attr string, data []byte, flags int) error { - pathBytes, err := syscall.BytePtrFromString(path) - if err != nil { - return err - } - attrBytes, err := syscall.BytePtrFromString(attr) - if err != nil { - return err - } - var dataBytes unsafe.Pointer - if len(data) > 0 { - dataBytes = unsafe.Pointer(&data[0]) - } else { - dataBytes = unsafe.Pointer(&_zero) - } - _, _, errno := syscall.Syscall6(syscall.SYS_LSETXATTR, uintptr(unsafe.Pointer(pathBytes)), uintptr(unsafe.Pointer(attrBytes)), uintptr(dataBytes), uintptr(len(data)), uintptr(flags), 0) - if errno != 0 { - return errno - } - return nil -} From 853b31143d3f83dc64c86b0fc46c761a3e695224 Mon Sep 17 00:00:00 2001 From: Daniel Nephin Date: Tue, 29 Aug 2017 17:05:16 -0400 Subject: [PATCH 45/47] Add ulimits to unsupported compose fields. Signed-off-by: Daniel Nephin Upstream-commit: bdc8cf364e00a16ecdedcb85bec3052ecbe90798 Component: cli --- components/cli/cli/compose/types/types.go | 1 + 1 file changed, 1 insertion(+) diff --git a/components/cli/cli/compose/types/types.go b/components/cli/cli/compose/types/types.go index 8feaf4289d..dd962b5453 100644 --- a/components/cli/cli/compose/types/types.go +++ b/components/cli/cli/compose/types/types.go @@ -23,6 +23,7 @@ var UnsupportedProperties = []string{ "shm_size", "sysctls", "tmpfs", + "ulimits", "userns_mode", } From 811eac43923c16c31fcecf0ca318826c970265dc Mon Sep 17 00:00:00 2001 From: Daniel Nephin Date: Tue, 9 May 2017 18:35:25 -0400 Subject: [PATCH 46/47] Reduce complexity in cli/command/container Add tests for exec and cleanup existing tests. Signed-off-by: Daniel Nephin Upstream-commit: e7f90b6b38bcfd198145a41a1ee13e7788fe2f5a Component: cli --- .../cli/cli/command/container/attach.go | 43 ++-- .../cli/cli/command/container/attach_test.go | 44 +++- .../cli/cli/command/container/client_test.go | 28 ++- .../cli/cli/command/container/create.go | 36 +-- .../cli/cli/command/container/create_test.go | 64 +++++ components/cli/cli/command/container/exec.go | 91 +++---- .../cli/cli/command/container/exec_test.go | 233 ++++++++++++------ components/cli/cli/command/container/utils.go | 15 -- .../cli/cli/command/service/client_test.go | 8 + components/cli/cli/command/service/ps.go | 11 +- components/cli/cli/command/service/ps_test.go | 22 ++ components/cli/cli/compose/loader/loader.go | 1 - .../cli/cli/compose/loader/volume_test.go | 10 + 13 files changed, 420 insertions(+), 186 deletions(-) create mode 100644 components/cli/cli/command/container/create_test.go diff --git a/components/cli/cli/command/container/attach.go b/components/cli/cli/command/container/attach.go index dce6432846..372fcbb348 100644 --- a/components/cli/cli/command/container/attach.go +++ b/components/cli/cli/command/container/attach.go @@ -120,18 +120,7 @@ func runAttach(dockerCli command.Cli, opts *attachOptions) error { } if c.Config.Tty && dockerCli.Out().IsTerminal() { - height, width := dockerCli.Out().GetTtySize() - // To handle the case where a user repeatedly attaches/detaches without resizing their - // terminal, the only way to get the shell prompt to display for attaches 2+ is to artificially - // resize it, then go back to normal. Without this, every attach after the first will - // require the user to manually resize or hit enter. - resizeTtyTo(ctx, client, opts.container, height+1, width+1, false) - - // After the above resizing occurs, the call to MonitorTtySize below will handle resetting back - // to the actual size. - if err := MonitorTtySize(ctx, dockerCli, opts.container, false); err != nil { - logrus.Debugf("Error monitoring TTY size: %s", err) - } + resizeTTY(ctx, dockerCli, opts.container) } streamer := hijackedIOStreamer{ @@ -151,14 +140,36 @@ func runAttach(dockerCli command.Cli, opts *attachOptions) error { if errAttach != nil { return errAttach } + return getExitStatus(ctx, dockerCli.Client(), opts.container) +} - _, status, err := getExitCode(ctx, dockerCli, opts.container) - if err != nil { - return err +func resizeTTY(ctx context.Context, dockerCli command.Cli, containerID string) { + height, width := dockerCli.Out().GetTtySize() + // To handle the case where a user repeatedly attaches/detaches without resizing their + // terminal, the only way to get the shell prompt to display for attaches 2+ is to artificially + // resize it, then go back to normal. Without this, every attach after the first will + // require the user to manually resize or hit enter. + resizeTtyTo(ctx, dockerCli.Client(), containerID, height+1, width+1, false) + + // After the above resizing occurs, the call to MonitorTtySize below will handle resetting back + // to the actual size. + if err := MonitorTtySize(ctx, dockerCli, containerID, false); err != nil { + logrus.Debugf("Error monitoring TTY size: %s", err) } +} + +func getExitStatus(ctx context.Context, apiclient client.ContainerAPIClient, containerID string) error { + container, err := apiclient.ContainerInspect(ctx, containerID) + if err != nil { + // If we can't connect, then the daemon probably died. + if !client.IsErrConnectionFailed(err) { + return err + } + return cli.StatusError{StatusCode: -1} + } + status := container.State.ExitCode if status != 0 { return cli.StatusError{StatusCode: status} } - return nil } diff --git a/components/cli/cli/command/container/attach_test.go b/components/cli/cli/command/container/attach_test.go index 8f87463af7..1ca775c6d5 100644 --- a/components/cli/cli/command/container/attach_test.go +++ b/components/cli/cli/command/container/attach_test.go @@ -4,10 +4,13 @@ import ( "io/ioutil" "testing" + "github.com/docker/cli/cli" "github.com/docker/cli/internal/test" "github.com/docker/cli/internal/test/testutil" "github.com/docker/docker/api/types" "github.com/pkg/errors" + "github.com/stretchr/testify/assert" + "golang.org/x/net/context" ) func TestNewAttachCommandErrors(t *testing.T) { @@ -67,9 +70,48 @@ func TestNewAttachCommandErrors(t *testing.T) { }, } for _, tc := range testCases { - cmd := NewAttachCommand(test.NewFakeCli(&fakeClient{containerInspectFunc: tc.containerInspectFunc})) + cmd := NewAttachCommand(test.NewFakeCli(&fakeClient{inspectFunc: tc.containerInspectFunc})) cmd.SetOutput(ioutil.Discard) cmd.SetArgs(tc.args) testutil.ErrorContains(t, cmd.Execute(), tc.expectedError) } } + +func TestGetExitStatus(t *testing.T) { + containerID := "the exec id" + expecatedErr := errors.New("unexpected error") + + testcases := []struct { + inspectError error + exitCode int + expectedError error + }{ + { + inspectError: nil, + exitCode: 0, + }, + { + inspectError: expecatedErr, + expectedError: expecatedErr, + }, + { + exitCode: 15, + expectedError: cli.StatusError{StatusCode: 15}, + }, + } + + for _, testcase := range testcases { + client := &fakeClient{ + inspectFunc: func(id string) (types.ContainerJSON, error) { + assert.Equal(t, containerID, id) + return types.ContainerJSON{ + ContainerJSONBase: &types.ContainerJSONBase{ + State: &types.ContainerState{ExitCode: testcase.exitCode}, + }, + }, testcase.inspectError + }, + } + err := getExitStatus(context.Background(), client, containerID) + assert.Equal(t, testcase.expectedError, err) + } +} diff --git a/components/cli/cli/command/container/client_test.go b/components/cli/cli/command/container/client_test.go index 1e2d5d9cf8..32f9a28fbf 100644 --- a/components/cli/cli/command/container/client_test.go +++ b/components/cli/cli/command/container/client_test.go @@ -8,12 +8,32 @@ import ( type fakeClient struct { client.Client - containerInspectFunc func(string) (types.ContainerJSON, error) + inspectFunc func(string) (types.ContainerJSON, error) + execInspectFunc func(execID string) (types.ContainerExecInspect, error) + execCreateFunc func(container string, config types.ExecConfig) (types.IDResponse, error) } -func (cli *fakeClient) ContainerInspect(_ context.Context, containerID string) (types.ContainerJSON, error) { - if cli.containerInspectFunc != nil { - return cli.containerInspectFunc(containerID) +func (f *fakeClient) ContainerInspect(_ context.Context, containerID string) (types.ContainerJSON, error) { + if f.inspectFunc != nil { + return f.inspectFunc(containerID) } return types.ContainerJSON{}, nil } + +func (f *fakeClient) ContainerExecCreate(_ context.Context, container string, config types.ExecConfig) (types.IDResponse, error) { + if f.execCreateFunc != nil { + return f.execCreateFunc(container, config) + } + return types.IDResponse{}, nil +} + +func (f *fakeClient) ContainerExecInspect(_ context.Context, execID string) (types.ContainerExecInspect, error) { + if f.execInspectFunc != nil { + return f.execInspectFunc(execID) + } + return types.ContainerExecInspect{}, nil +} + +func (f *fakeClient) ContainerExecStart(ctx context.Context, execID string, config types.ExecStartCheck) error { + return nil +} diff --git a/components/cli/cli/command/container/create.go b/components/cli/cli/command/container/create.go index 2795e4fed7..97bc1863f0 100644 --- a/components/cli/cli/command/container/create.go +++ b/components/cli/cli/command/container/create.go @@ -113,6 +113,9 @@ type cidFile struct { } func (cid *cidFile) Close() error { + if cid.file == nil { + return nil + } cid.file.Close() if cid.written { @@ -126,6 +129,9 @@ func (cid *cidFile) Close() error { } func (cid *cidFile) Write(id string) error { + if cid.file == nil { + return nil + } if _, err := cid.file.Write([]byte(id)); err != nil { return errors.Errorf("Failed to write the container ID to the file: %s", err) } @@ -134,6 +140,9 @@ func (cid *cidFile) Write(id string) error { } func newCIDFile(path string) (*cidFile, error) { + if path == "" { + return &cidFile{}, nil + } if _, err := os.Stat(path); err == nil { return nil, errors.Errorf("Container ID file found, make sure the other container isn't running or delete %s", path) } @@ -153,19 +162,15 @@ func createContainer(ctx context.Context, dockerCli command.Cli, containerConfig stderr := dockerCli.Err() var ( - containerIDFile *cidFile - trustedRef reference.Canonical - namedRef reference.Named + trustedRef reference.Canonical + namedRef reference.Named ) - cidfile := hostConfig.ContainerIDFile - if cidfile != "" { - var err error - if containerIDFile, err = newCIDFile(cidfile); err != nil { - return nil, err - } - defer containerIDFile.Close() + containerIDFile, err := newCIDFile(hostConfig.ContainerIDFile) + if err != nil { + return nil, err } + defer containerIDFile.Close() ref, err := reference.ParseAnyReference(config.Image) if err != nil { @@ -207,18 +212,13 @@ func createContainer(ctx context.Context, dockerCli command.Cli, containerConfig if retryErr != nil { return nil, retryErr } - } else { - return nil, err } + return nil, err } for _, warning := range response.Warnings { fmt.Fprintf(stderr, "WARNING: %s\n", warning) } - if containerIDFile != nil { - if err = containerIDFile.Write(response.ID); err != nil { - return nil, err - } - } - return &response, nil + err = containerIDFile.Write(response.ID) + return &response, err } diff --git a/components/cli/cli/command/container/create_test.go b/components/cli/cli/command/container/create_test.go new file mode 100644 index 0000000000..467cdb3a6e --- /dev/null +++ b/components/cli/cli/command/container/create_test.go @@ -0,0 +1,64 @@ +package container + +import ( + "os" + "testing" + + "io/ioutil" + + "github.com/docker/cli/internal/test/testutil" + "github.com/gotestyourself/gotestyourself/fs" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func TestCIDFileNoOPWithNoFilename(t *testing.T) { + file, err := newCIDFile("") + require.NoError(t, err) + assert.Equal(t, &cidFile{}, file) + + assert.NoError(t, file.Write("id")) + assert.NoError(t, file.Close()) +} + +func TestNewCIDFileWhenFileAlreadyExists(t *testing.T) { + tempfile := fs.NewFile(t, "test-cid-file") + defer tempfile.Remove() + + _, err := newCIDFile(tempfile.Path()) + testutil.ErrorContains(t, err, "Container ID file found") +} + +func TestCIDFileCloseWithNoWrite(t *testing.T) { + tempdir := fs.NewDir(t, "test-cid-file") + defer tempdir.Remove() + + path := tempdir.Join("cidfile") + file, err := newCIDFile(path) + require.NoError(t, err) + assert.Equal(t, file.path, path) + + assert.NoError(t, file.Close()) + _, err = os.Stat(path) + assert.True(t, os.IsNotExist(err)) +} + +func TestCIDFileCloseWithWrite(t *testing.T) { + tempdir := fs.NewDir(t, "test-cid-file") + defer tempdir.Remove() + + path := tempdir.Join("cidfile") + file, err := newCIDFile(path) + require.NoError(t, err) + + content := "id" + assert.NoError(t, file.Write(content)) + + actual, err := ioutil.ReadFile(path) + require.NoError(t, err) + assert.Equal(t, content, string(actual)) + + assert.NoError(t, file.Close()) + _, err = os.Stat(path) + require.NoError(t, err) +} diff --git a/components/cli/cli/command/container/exec.go b/components/cli/cli/command/container/exec.go index bbcd34ae0c..feb341a75d 100644 --- a/components/cli/cli/command/container/exec.go +++ b/components/cli/cli/command/container/exec.go @@ -7,10 +7,12 @@ import ( "github.com/Sirupsen/logrus" "github.com/docker/cli/cli" "github.com/docker/cli/cli/command" + "github.com/docker/cli/cli/config/configfile" "github.com/docker/cli/opts" "github.com/docker/docker/api/types" apiclient "github.com/docker/docker/client" "github.com/docker/docker/pkg/promise" + "github.com/pkg/errors" "github.com/spf13/cobra" "golang.org/x/net/context" ) @@ -22,14 +24,13 @@ type execOptions struct { detach bool user string privileged bool - env *opts.ListOpts + env opts.ListOpts + container string + command []string } -func newExecOptions() *execOptions { - var values []string - return &execOptions{ - env: opts.NewListOptsRef(&values, opts.ValidateEnv), - } +func newExecOptions() execOptions { + return execOptions{env: opts.NewListOpts(opts.ValidateEnv)} } // NewExecCommand creates a new cobra.Command for `docker exec` @@ -41,9 +42,9 @@ func NewExecCommand(dockerCli command.Cli) *cobra.Command { Short: "Run a command in a running container", Args: cli.RequiresMinArgs(2), RunE: func(cmd *cobra.Command, args []string) error { - container := args[0] - execCmd := args[1:] - return runExec(dockerCli, options, container, execCmd) + options.container = args[0] + options.command = args[1:] + return runExec(dockerCli, options) }, } @@ -56,27 +57,14 @@ func NewExecCommand(dockerCli command.Cli) *cobra.Command { flags.BoolVarP(&options.detach, "detach", "d", false, "Detached mode: run command in the background") flags.StringVarP(&options.user, "user", "u", "", "Username or UID (format: [:])") flags.BoolVarP(&options.privileged, "privileged", "", false, "Give extended privileges to the command") - flags.VarP(options.env, "env", "e", "Set environment variables") + flags.VarP(&options.env, "env", "e", "Set environment variables") flags.SetAnnotation("env", "version", []string{"1.25"}) return cmd } -// nolint: gocyclo -func runExec(dockerCli command.Cli, options *execOptions, container string, execCmd []string) error { - execConfig, err := parseExec(options, execCmd) - // just in case the ParseExec does not exit - if container == "" || err != nil { - return cli.StatusError{StatusCode: 1} - } - - if options.detachKeys != "" { - dockerCli.ConfigFile().DetachKeys = options.detachKeys - } - - // Send client escape keys - execConfig.DetachKeys = dockerCli.ConfigFile().DetachKeys - +func runExec(dockerCli command.Cli, options execOptions) error { + execConfig := parseExec(options, dockerCli.ConfigFile()) ctx := context.Background() client := dockerCli.Client() @@ -84,7 +72,7 @@ func runExec(dockerCli command.Cli, options *execOptions, container string, exec // otherwise if we error out we will leak execIDs on the server (and // there's no easy way to clean those up). But also in order to make "not // exist" errors take precedence we do a dummy inspect first. - if _, err := client.ContainerInspect(ctx, container); err != nil { + if _, err := client.ContainerInspect(ctx, options.container); err != nil { return err } if !execConfig.Detach { @@ -93,27 +81,27 @@ func runExec(dockerCli command.Cli, options *execOptions, container string, exec } } - response, err := client.ContainerExecCreate(ctx, container, *execConfig) + response, err := client.ContainerExecCreate(ctx, options.container, *execConfig) if err != nil { return err } execID := response.ID if execID == "" { - fmt.Fprintln(dockerCli.Out(), "exec ID empty") - return nil + return errors.New("exec ID empty") } - // Temp struct for execStart so that we don't need to transfer all the execConfig. if execConfig.Detach { execStartCheck := types.ExecStartCheck{ Detach: execConfig.Detach, Tty: execConfig.Tty, } - return client.ContainerExecStart(ctx, execID, execStartCheck) } + return interactiveExec(ctx, dockerCli, execConfig, execID) +} +func interactiveExec(ctx context.Context, dockerCli command.Cli, execConfig *types.ExecConfig, execID string) error { // Interactive exec requested. var ( out, stderr io.Writer @@ -135,6 +123,7 @@ func runExec(dockerCli command.Cli, options *execOptions, container string, exec } } + client := dockerCli.Client() resp, err := client.ContainerExecAttach(ctx, execID, *execConfig) if err != nil { return err @@ -165,42 +154,35 @@ func runExec(dockerCli command.Cli, options *execOptions, container string, exec return err } - var status int - if _, status, err = getExecExitCode(ctx, client, execID); err != nil { - return err - } - - if status != 0 { - return cli.StatusError{StatusCode: status} - } - - return nil + return getExecExitStatus(ctx, client, execID) } -// getExecExitCode perform an inspect on the exec command. It returns -// the running state and the exit code. -func getExecExitCode(ctx context.Context, client apiclient.ContainerAPIClient, execID string) (bool, int, error) { +func getExecExitStatus(ctx context.Context, client apiclient.ContainerAPIClient, execID string) error { resp, err := client.ContainerExecInspect(ctx, execID) if err != nil { // If we can't connect, then the daemon probably died. if !apiclient.IsErrConnectionFailed(err) { - return false, -1, err + return err } - return false, -1, nil + return cli.StatusError{StatusCode: -1} } - - return resp.Running, resp.ExitCode, nil + status := resp.ExitCode + if status != 0 { + return cli.StatusError{StatusCode: status} + } + return nil } // parseExec parses the specified args for the specified command and generates // an ExecConfig from it. -func parseExec(opts *execOptions, execCmd []string) (*types.ExecConfig, error) { +func parseExec(opts execOptions, configFile *configfile.ConfigFile) *types.ExecConfig { execConfig := &types.ExecConfig{ User: opts.user, Privileged: opts.privileged, Tty: opts.tty, - Cmd: execCmd, + Cmd: opts.command, Detach: opts.detach, + Env: opts.env.GetAll(), } // If -d is not set, attach to everything by default @@ -212,9 +194,10 @@ func parseExec(opts *execOptions, execCmd []string) (*types.ExecConfig, error) { } } - if opts.env != nil { - execConfig.Env = opts.env.GetAll() + if opts.detachKeys != "" { + execConfig.DetachKeys = opts.detachKeys + } else { + execConfig.DetachKeys = configFile.DetachKeys } - - return execConfig, nil + return execConfig } diff --git a/components/cli/cli/command/container/exec_test.go b/components/cli/cli/command/container/exec_test.go index bf4fd3f35c..492e3a558d 100644 --- a/components/cli/cli/command/container/exec_test.go +++ b/components/cli/cli/command/container/exec_test.go @@ -4,118 +4,201 @@ import ( "io/ioutil" "testing" + "github.com/docker/cli/cli" + "github.com/docker/cli/cli/config/configfile" "github.com/docker/cli/internal/test" "github.com/docker/cli/internal/test/testutil" + "github.com/docker/cli/opts" "github.com/docker/docker/api/types" "github.com/pkg/errors" - "github.com/stretchr/testify/require" + "github.com/stretchr/testify/assert" + "golang.org/x/net/context" ) -type arguments struct { - options execOptions - execCmd []string +func withDefaultOpts(options execOptions) execOptions { + options.env = opts.NewListOpts(opts.ValidateEnv) + if len(options.command) == 0 { + options.command = []string{"command"} + } + return options } func TestParseExec(t *testing.T) { - valids := map[*arguments]*types.ExecConfig{ + testcases := []struct { + options execOptions + configFile configfile.ConfigFile + expected types.ExecConfig + }{ { - execCmd: []string{"command"}, - }: { - Cmd: []string{"command"}, - AttachStdout: true, - AttachStderr: true, + expected: types.ExecConfig{ + Cmd: []string{"command"}, + AttachStdout: true, + AttachStderr: true, + }, + options: withDefaultOpts(execOptions{}), }, { - execCmd: []string{"command1", "command2"}, - }: { - Cmd: []string{"command1", "command2"}, - AttachStdout: true, - AttachStderr: true, + expected: types.ExecConfig{ + Cmd: []string{"command1", "command2"}, + AttachStdout: true, + AttachStderr: true, + }, + options: withDefaultOpts(execOptions{ + command: []string{"command1", "command2"}, + }), }, { - options: execOptions{ + options: withDefaultOpts(execOptions{ interactive: true, tty: true, user: "uid", + }), + expected: types.ExecConfig{ + User: "uid", + AttachStdin: true, + AttachStdout: true, + AttachStderr: true, + Tty: true, + Cmd: []string{"command"}, }, - execCmd: []string{"command"}, - }: { - User: "uid", - AttachStdin: true, - AttachStdout: true, - AttachStderr: true, - Tty: true, - Cmd: []string{"command"}, }, { - options: execOptions{ - detach: true, + options: withDefaultOpts(execOptions{detach: true}), + expected: types.ExecConfig{ + Detach: true, + Cmd: []string{"command"}, }, - execCmd: []string{"command"}, - }: { - AttachStdin: false, - AttachStdout: false, - AttachStderr: false, - Detach: true, - Cmd: []string{"command"}, }, { - options: execOptions{ + options: withDefaultOpts(execOptions{ tty: true, interactive: true, detach: true, + }), + expected: types.ExecConfig{ + Detach: true, + Tty: true, + Cmd: []string{"command"}, + }, + }, + { + options: withDefaultOpts(execOptions{detach: true}), + configFile: configfile.ConfigFile{DetachKeys: "de"}, + expected: types.ExecConfig{ + Cmd: []string{"command"}, + DetachKeys: "de", + Detach: true, + }, + }, + { + options: withDefaultOpts(execOptions{ + detach: true, + detachKeys: "ab", + }), + configFile: configfile.ConfigFile{DetachKeys: "de"}, + expected: types.ExecConfig{ + Cmd: []string{"command"}, + DetachKeys: "ab", + Detach: true, }, - execCmd: []string{"command"}, - }: { - AttachStdin: false, - AttachStdout: false, - AttachStderr: false, - Detach: true, - Tty: true, - Cmd: []string{"command"}, }, } - for valid, expectedExecConfig := range valids { - execConfig, err := parseExec(&valid.options, valid.execCmd) - require.NoError(t, err) - if !compareExecConfig(expectedExecConfig, execConfig) { - t.Fatalf("Expected [%v] for %v, got [%v]", expectedExecConfig, valid, execConfig) - } + for _, testcase := range testcases { + execConfig := parseExec(testcase.options, &testcase.configFile) + assert.Equal(t, testcase.expected, *execConfig) } } -func compareExecConfig(config1 *types.ExecConfig, config2 *types.ExecConfig) bool { - if config1.AttachStderr != config2.AttachStderr { - return false +func TestRunExec(t *testing.T) { + var testcases = []struct { + doc string + options execOptions + client fakeClient + expectedError string + expectedOut string + expectedErr string + }{ + { + doc: "successful detach", + options: withDefaultOpts(execOptions{ + container: "thecontainer", + detach: true, + }), + client: fakeClient{execCreateFunc: execCreateWithID}, + }, + { + doc: "inspect error", + options: newExecOptions(), + client: fakeClient{ + inspectFunc: func(string) (types.ContainerJSON, error) { + return types.ContainerJSON{}, errors.New("failed inspect") + }, + }, + expectedError: "failed inspect", + }, + { + doc: "missing exec ID", + options: newExecOptions(), + expectedError: "exec ID empty", + }, } - if config1.AttachStdin != config2.AttachStdin { - return false + + for _, testcase := range testcases { + t.Run(testcase.doc, func(t *testing.T) { + cli := test.NewFakeCli(&testcase.client) + + err := runExec(cli, testcase.options) + if testcase.expectedError != "" { + testutil.ErrorContains(t, err, testcase.expectedError) + } else { + if !assert.NoError(t, err) { + return + } + } + assert.Equal(t, testcase.expectedOut, cli.OutBuffer().String()) + assert.Equal(t, testcase.expectedErr, cli.ErrBuffer().String()) + }) } - if config1.AttachStdout != config2.AttachStdout { - return false +} + +func execCreateWithID(_ string, _ types.ExecConfig) (types.IDResponse, error) { + return types.IDResponse{ID: "execid"}, nil +} + +func TestGetExecExitStatus(t *testing.T) { + execID := "the exec id" + expecatedErr := errors.New("unexpected error") + + testcases := []struct { + inspectError error + exitCode int + expectedError error + }{ + { + inspectError: nil, + exitCode: 0, + }, + { + inspectError: expecatedErr, + expectedError: expecatedErr, + }, + { + exitCode: 15, + expectedError: cli.StatusError{StatusCode: 15}, + }, } - if config1.Detach != config2.Detach { - return false - } - if config1.Privileged != config2.Privileged { - return false - } - if config1.Tty != config2.Tty { - return false - } - if config1.User != config2.User { - return false - } - if len(config1.Cmd) != len(config2.Cmd) { - return false - } - for index, value := range config1.Cmd { - if value != config2.Cmd[index] { - return false + + for _, testcase := range testcases { + client := &fakeClient{ + execInspectFunc: func(id string) (types.ContainerExecInspect, error) { + assert.Equal(t, execID, id) + return types.ContainerExecInspect{ExitCode: testcase.exitCode}, testcase.inspectError + }, } + err := getExecExitStatus(context.Background(), client, execID) + assert.Equal(t, testcase.expectedError, err) } - return true } func TestNewExecCommandErrors(t *testing.T) { @@ -135,7 +218,7 @@ func TestNewExecCommandErrors(t *testing.T) { }, } for _, tc := range testCases { - cli := test.NewFakeCli(&fakeClient{containerInspectFunc: tc.containerInspectFunc}) + cli := test.NewFakeCli(&fakeClient{inspectFunc: tc.containerInspectFunc}) cmd := NewExecCommand(cli) cmd.SetOutput(ioutil.Discard) cmd.SetArgs(tc.args) diff --git a/components/cli/cli/command/container/utils.go b/components/cli/cli/command/container/utils.go index d9afe24163..1109b66b21 100644 --- a/components/cli/cli/command/container/utils.go +++ b/components/cli/cli/command/container/utils.go @@ -10,7 +10,6 @@ import ( "github.com/docker/docker/api/types/events" "github.com/docker/docker/api/types/filters" "github.com/docker/docker/api/types/versions" - clientapi "github.com/docker/docker/client" "golang.org/x/net/context" ) @@ -125,20 +124,6 @@ func legacyWaitExitOrRemoved(ctx context.Context, dockerCli *command.DockerCli, return statusChan } -// getExitCode performs an inspect on the container. It returns -// the running state and the exit code. -func getExitCode(ctx context.Context, dockerCli command.Cli, containerID string) (bool, int, error) { - c, err := dockerCli.Client().ContainerInspect(ctx, containerID) - if err != nil { - // If we can't connect, then the daemon probably died. - if !clientapi.IsErrConnectionFailed(err) { - return false, -1, err - } - return false, -1, nil - } - return c.State.Running, c.State.ExitCode, nil -} - func parallelOperation(ctx context.Context, containers []string, op func(ctx context.Context, container string) error) chan error { if len(containers) == 0 { return nil diff --git a/components/cli/cli/command/service/client_test.go b/components/cli/cli/command/service/client_test.go index ebdfe7ea74..69c76951f7 100644 --- a/components/cli/cli/command/service/client_test.go +++ b/components/cli/cli/command/service/client_test.go @@ -14,6 +14,7 @@ type fakeClient struct { serviceInspectWithRawFunc func(ctx context.Context, serviceID string, options types.ServiceInspectOptions) (swarm.Service, []byte, error) serviceUpdateFunc func(ctx context.Context, serviceID string, version swarm.Version, service swarm.ServiceSpec, options types.ServiceUpdateOptions) (types.ServiceUpdateResponse, error) serviceListFunc func(context.Context, types.ServiceListOptions) ([]swarm.Service, error) + infoFunc func(ctx context.Context) (types.Info, error) } func (f *fakeClient) NodeList(ctx context.Context, options types.NodeListOptions) ([]swarm.Node, error) { @@ -48,6 +49,13 @@ func (f *fakeClient) ServiceUpdate(ctx context.Context, serviceID string, versio return types.ServiceUpdateResponse{}, nil } +func (f *fakeClient) Info(ctx context.Context) (types.Info, error) { + if f.infoFunc == nil { + return types.Info{}, nil + } + return f.infoFunc(ctx) +} + func newService(id string, name string) swarm.Service { return swarm.Service{ ID: id, diff --git a/components/cli/cli/command/service/ps.go b/components/cli/cli/command/service/ps.go index 07dbba7230..e441f9e1aa 100644 --- a/components/cli/cli/command/service/ps.go +++ b/components/cli/cli/command/service/ps.go @@ -56,6 +56,9 @@ func runPS(dockerCli command.Cli, options psOptions) error { if err != nil { return err } + if err := updateNodeFilter(ctx, client, filter); err != nil { + return err + } tasks, err := client.TaskList(ctx, types.TaskListOptions{Filters: filter}) if err != nil { @@ -130,16 +133,20 @@ loop: if serviceCount == 0 { return filter, nil, errors.New(strings.Join(notfound, "\n")) } + return filter, notfound, err +} + +func updateNodeFilter(ctx context.Context, client client.APIClient, filter filters.Args) error { if filter.Include("node") { nodeFilters := filter.Get("node") for _, nodeFilter := range nodeFilters { nodeReference, err := node.Reference(ctx, client, nodeFilter) if err != nil { - return filter, nil, err + return err } filter.Del("node", nodeFilter) filter.Add("node", nodeReference) } } - return filter, notfound, err + return nil } diff --git a/components/cli/cli/command/service/ps_test.go b/components/cli/cli/command/service/ps_test.go index 1913202d33..be26870284 100644 --- a/components/cli/cli/command/service/ps_test.go +++ b/components/cli/cli/command/service/ps_test.go @@ -89,3 +89,25 @@ func TestRunPSWarnsOnNotFound(t *testing.T) { err := runPS(cli, options) assert.EqualError(t, err, "no such service: bar") } + +func TestUpdateNodeFilter(t *testing.T) { + selfNodeID := "foofoo" + filter := filters.NewArgs() + filter.Add("node", "one") + filter.Add("node", "two") + filter.Add("node", "self") + + client := &fakeClient{ + infoFunc: func(_ context.Context) (types.Info, error) { + return types.Info{Swarm: swarm.Info{NodeID: selfNodeID}}, nil + }, + } + + updateNodeFilter(context.Background(), client, filter) + + expected := filters.NewArgs() + expected.Add("node", "one") + expected.Add("node", "two") + expected.Add("node", selfNodeID) + assert.Equal(t, expected, filter) +} diff --git a/components/cli/cli/compose/loader/loader.go b/components/cli/cli/compose/loader/loader.go index 2fb2630087..450603e7dd 100644 --- a/components/cli/cli/compose/loader/loader.go +++ b/components/cli/cli/compose/loader/loader.go @@ -576,7 +576,6 @@ func transformServiceVolumeConfig(data interface{}) (interface{}, error) { default: return data, errors.Errorf("invalid type %T for service volume", value) } - } func transformServiceNetworkMap(value interface{}) (interface{}, error) { diff --git a/components/cli/cli/compose/loader/volume_test.go b/components/cli/cli/compose/loader/volume_test.go index a116683327..2f2e50a905 100644 --- a/components/cli/cli/compose/loader/volume_test.go +++ b/components/cli/cli/compose/loader/volume_test.go @@ -200,3 +200,13 @@ func TestParseVolumeSplitCases(t *testing.T) { assert.Equal(t, expected, parsed.Source != "", msg) } } + +func TestParseVolumeInvalidEmptySpec(t *testing.T) { + _, err := ParseVolume("") + testutil.ErrorContains(t, err, "invalid empty volume spec") +} + +func TestParseVolumeInvalidSections(t *testing.T) { + _, err := ParseVolume("/foo::rw") + testutil.ErrorContains(t, err, "invalid spec") +} From 73cf62aaae6dae6febef3164aa8b4933a448310b Mon Sep 17 00:00:00 2001 From: Li Yi Date: Wed, 30 Aug 2017 09:09:06 +0800 Subject: [PATCH 47/47] Change the type of interval, timeout and start_period of healthcheck from string to * time.Duration Signed-off-by: Li Yi Upstream-commit: e02fcfd34e666267bf229cc7f898f840a9ff58ec Component: cli --- components/cli/cli/compose/convert/service.go | 22 +++++-------------- .../cli/cli/compose/convert/service_test.go | 10 +++++---- .../cli/cli/compose/loader/loader_test.go | 6 ++--- components/cli/cli/compose/schema/bindata.go | 2 +- .../schema/data/config_schema_v3.4.json | 6 ++--- components/cli/cli/compose/types/types.go | 6 ++--- 6 files changed, 22 insertions(+), 30 deletions(-) diff --git a/components/cli/cli/compose/convert/service.go b/components/cli/cli/compose/convert/service.go index d4f14a7b16..48df2d7e02 100644 --- a/components/cli/cli/compose/convert/service.go +++ b/components/cli/cli/compose/convert/service.go @@ -366,7 +366,6 @@ func convertHealthcheck(healthcheck *composetypes.HealthCheckConfig) (*container return nil, nil } var ( - err error timeout, interval, startPeriod time.Duration retries int ) @@ -379,23 +378,14 @@ func convertHealthcheck(healthcheck *composetypes.HealthCheckConfig) (*container }, nil } - if healthcheck.Timeout != "" { - timeout, err = time.ParseDuration(healthcheck.Timeout) - if err != nil { - return nil, err - } + if healthcheck.Timeout != nil { + timeout = *healthcheck.Timeout } - if healthcheck.Interval != "" { - interval, err = time.ParseDuration(healthcheck.Interval) - if err != nil { - return nil, err - } + if healthcheck.Interval != nil { + interval = *healthcheck.Interval } - if healthcheck.StartPeriod != "" { - startPeriod, err = time.ParseDuration(healthcheck.StartPeriod) - if err != nil { - return nil, err - } + if healthcheck.StartPeriod != nil { + startPeriod = *healthcheck.StartPeriod } if healthcheck.Retries != nil { retries = int(*healthcheck.Retries) diff --git a/components/cli/cli/compose/convert/service_test.go b/components/cli/cli/compose/convert/service_test.go index 3a0bf0e75e..1945e22d09 100644 --- a/components/cli/cli/compose/convert/service_test.go +++ b/components/cli/cli/compose/convert/service_test.go @@ -109,16 +109,18 @@ func TestConvertResourcesOnlyMemory(t *testing.T) { func TestConvertHealthcheck(t *testing.T) { retries := uint64(10) + timeout := 30 * time.Second + interval := 2 * time.Millisecond source := &composetypes.HealthCheckConfig{ Test: []string{"EXEC", "touch", "/foo"}, - Timeout: "30s", - Interval: "2ms", + Timeout: &timeout, + Interval: &interval, Retries: &retries, } expected := &container.HealthConfig{ Test: source.Test, - Timeout: 30 * time.Second, - Interval: 2 * time.Millisecond, + Timeout: timeout, + Interval: interval, Retries: 10, } diff --git a/components/cli/cli/compose/loader/loader_test.go b/components/cli/cli/compose/loader/loader_test.go index 7cee33313c..fb866cf143 100644 --- a/components/cli/cli/compose/loader/loader_test.go +++ b/components/cli/cli/compose/loader/loader_test.go @@ -757,10 +757,10 @@ func TestFullExample(t *testing.T) { }, HealthCheck: &types.HealthCheckConfig{ Test: types.HealthCheckTest([]string{"CMD-SHELL", "echo \"hello world\""}), - Interval: "10s", - Timeout: "1s", + Interval: durationPtr(10 * time.Second), + Timeout: durationPtr(1 * time.Second), Retries: uint64Ptr(5), - StartPeriod: "15s", + StartPeriod: durationPtr(15 * time.Second), }, Hostname: "foo", Image: "redis", diff --git a/components/cli/cli/compose/schema/bindata.go b/components/cli/cli/compose/schema/bindata.go index 8f9b678d9c..f295006ed5 100644 --- a/components/cli/cli/compose/schema/bindata.go +++ b/components/cli/cli/compose/schema/bindata.go @@ -152,7 +152,7 @@ func dataConfig_schema_v33Json() (*asset, error) { return a, nil } -var _dataConfig_schema_v34Json = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xec\x5b\x4f\x73\xdb\x3a\x0e\xbf\xfb\x53\x68\xf4\xde\xad\x76\xd2\x99\xed\xec\xcc\xf6\xb6\xc7\x3d\xed\x9e\x37\xe3\x6a\x68\x0a\xb6\xd9\x50\x24\x0b\x52\x4e\xdc\x4e\xbe\xfb\x8e\x44\x49\xd6\x1f\x4a\xa4\x6c\xa5\x49\xf7\xf5\x94\x58\x02\x40\x02\x20\x7e\x00\x48\xea\xc7\x2a\x8a\xe2\x3f\x35\x3d\x42\x46\xe2\xcf\x51\x7c\x34\x46\x7d\xbe\xbf\xff\xaa\xa5\xd8\xd8\xa7\x77\x12\x0f\xf7\x29\x92\xbd\xd9\x7c\xfc\x74\x6f\x9f\xfd\x11\xaf\x0b\x3e\x96\x16\x2c\x54\x8a\x3d\x3b\x24\xf6\x4d\x72\xfa\xdb\xdd\xa7\xbb\x82\xdd\x92\x98\xb3\x82\x82\x48\xee\xbe\x02\x35\xf6\x19\xc2\xb7\x9c\x21\x14\xcc\x0f\xf1\x09\x50\x33\x29\xe2\xed\x7a\x55\xbc\x53\x28\x15\xa0\x61\xa0\xe3\xcf\x51\x31\xb9\x28\x6a\x48\xea\x07\x2d\xb1\xda\x20\x13\x87\xb8\x7c\xfc\x52\x4a\x88\xa2\x58\x03\x9e\x18\x6d\x49\x68\xa6\xfa\xc7\xfd\x45\xfe\x7d\x43\xb6\xee\x4b\x6d\x4d\xb6\x7c\xae\x88\x31\x80\xe2\x3f\xc3\xb9\x95\xaf\xbf\x3c\x90\xcd\xf7\x7f\x6e\xfe\xfb\x71\xf3\x8f\xbb\x64\xb3\xfd\xf0\x67\xe7\x75\x61\x5f\x84\xbd\x1d\x3e\x85\x3d\x13\xcc\x30\x29\x9a\xf1\xe3\x86\xf2\xa5\xfa\xef\xa5\x19\x98\xa4\x69\x49\x4c\x78\x67\xec\x3d\xe1\x1a\xba\x3a\x0b\x30\x4f\x12\x1f\x7d\x3a\x37\x64\x6f\xa4\x73\x35\xbe\x43\xe7\xae\x3a\x27\xc9\xf3\xcc\xeb\xc1\x9a\xea\x8d\x94\xb1\xc3\x2f\xe3\x3f\x0d\x14\xc1\xf8\x97\xac\xa5\x7a\xb3\x15\x5b\x0c\xbf\x8c\xc2\x16\x35\x7c\x0a\xd7\x54\x6f\xa4\xb0\x1d\xfe\x36\x85\x57\xb5\xd2\xee\x39\xc6\x5f\x9e\x37\xc5\xdf\x97\x52\xe6\xa4\x3c\x2b\xa5\x35\xbf\x52\x89\x0e\xe6\xb9\xcc\xe9\xc2\x9c\x71\x7b\x36\x06\x1d\xb1\x64\x0a\x8a\xcb\x73\x39\x73\xb7\xcd\x2c\x41\x06\xc2\xc4\x8d\x99\xa2\x28\xde\xe5\x8c\xa7\x7d\xab\x4b\x01\xff\x2e\x44\x3c\xb4\x1e\x46\xd1\x8f\x3e\xbc\xb7\xe4\x94\xef\x3b\xbf\xc6\x17\x45\xf3\x7e\x44\x97\xe6\x3d\x95\xc2\xc0\xb3\x29\x95\x9a\x1e\xda\x9a\x40\xd2\x47\xc0\x3d\xe3\x10\xca\x41\xd0\xae\xf4\x11\x93\x71\xa6\x4d\x22\x31\x49\x19\x35\x4e\x7e\x4e\x76\xc0\x6f\x92\x40\x09\x3d\x42\xb2\x47\x99\x79\xa5\xec\x13\xab\x89\x76\x0a\xaa\x11\x3c\x50\x73\x43\xf0\x00\x6e\xcb\xf6\x88\x07\xdc\xfe\xd8\x6a\x58\x5b\xbf\xb6\x2b\x87\xc0\x98\x12\x95\x90\x34\xed\xcc\x83\x20\x92\x73\xbc\x8e\x62\x66\x20\xd3\x6e\x85\xa2\x38\x17\xec\x5b\x0e\xff\xaa\x48\x0c\xe6\xd0\x97\x9b\xa2\x54\xcb\x0b\x3e\xa0\xcc\x55\xa2\x08\x16\x81\x34\x6d\xec\x98\xca\x2c\x23\x62\xa9\xe8\x9a\xa3\x47\x80\xe5\x07\x38\x1f\xb5\x43\xb6\x1a\xa3\xfd\xaa\x19\xad\x33\xad\x11\x6d\xfc\xfa\x0c\xf1\xc2\x8f\x18\x7e\xcc\x28\x20\x57\xe6\x48\x43\x21\x60\x3a\x14\x9c\xf4\x39\x4b\xc3\x89\x0f\x73\x88\x33\x99\x76\xe7\x2d\xf2\x6c\x07\x38\x08\xc9\x6e\x64\x0d\x7f\x6f\x57\xae\x37\x3d\xef\x1b\xc2\x04\x60\x22\x48\xe6\xb3\x55\x4c\x11\x52\x10\x86\x11\x9e\x68\x05\xb4\x43\x5e\x7b\x6a\xc2\x33\x71\x10\x24\xc7\x08\x07\xa6\x0d\x9e\xa7\x41\xe9\xa5\x3d\xb1\x14\x14\x88\x54\x27\xb6\x09\x99\x8f\x9e\x71\x0a\x4d\x47\xb2\x28\x4c\xa4\x62\x2a\x2b\x58\x31\x45\x5e\x28\xe6\x16\xf7\x18\x13\x0d\x04\xe9\xf1\x4a\x7e\x99\x11\x26\x42\x9c\x0a\xc2\xe0\x59\x49\x66\x61\xec\xdd\xe1\x13\x88\x53\xd2\xac\x9b\xd9\x66\x00\x71\x62\x28\x45\x56\x83\x74\x58\x76\x6e\xf1\x3f\x2b\xa9\xe1\x76\x70\xac\x38\x1e\x6a\xc5\xd7\x4d\x4c\x6f\xbb\xd6\x8b\xf7\x12\x33\x52\x4c\xb6\x1e\xbb\x1d\xc3\x9d\xa1\x86\x2b\xaf\x6d\xc0\xb6\x0e\x45\x55\x4b\x78\xc2\x99\x78\x5c\x7e\x89\xc3\xb3\x41\x92\x1c\xa5\x36\xd7\x14\x40\xf1\x11\x08\x37\x47\x7a\x04\xfa\x38\xc1\xde\xa6\xea\x70\x4b\x6d\x42\x16\x39\xcb\xc8\xc1\x4f\xa4\xa8\x8f\xe4\xea\x42\x2f\x5e\xd4\xf8\x2d\xb1\xf2\x70\x28\x48\xc7\x56\xdc\xa0\x71\xa8\x5e\xfb\x4a\xee\x14\xd9\x09\x30\xb4\x8a\x94\xea\xd2\xef\xf4\x5f\x86\x64\x73\x6f\x83\xd8\x21\xfd\x72\x67\xfb\xc3\x89\xa8\x2a\xff\xe3\x3c\xde\x0e\x53\xe6\x30\x69\xf6\x9f\xf4\x34\x0c\xab\x73\x3b\x5e\xc9\x08\x2d\xca\x59\x04\x3d\xe2\xd7\x0b\x69\x55\xaf\x27\x83\x9c\x7f\xa1\x1d\x10\x0f\x12\xeb\x18\x52\x5f\xd5\x46\xcc\x6f\xdf\x82\x5c\xe7\xed\xf1\x3d\xda\x8c\x4d\x2f\x74\x9a\x97\xe9\xfa\x97\x58\x49\x47\x38\x23\x1a\xfc\xc1\x3e\xd9\x8f\x35\xd2\x98\x3a\x7d\x0a\x5c\x13\x2e\xde\xbf\x4f\xf2\x8e\xb0\x8e\xca\x0c\x6f\xdd\x3c\xa2\xda\x25\x2a\xe7\xce\x89\x6c\xfd\x45\xeb\x6b\x76\x96\xaa\x5b\x78\x77\xb1\xa2\x44\x88\x76\x80\x29\x89\xe6\xa7\xf4\x42\x17\x9c\xba\x24\x7c\x3b\xf8\xb0\x3d\xea\xbb\x3b\x88\xe9\x75\x7a\xaa\x09\x94\x72\x50\x3b\x3a\x2a\x26\x0c\x1c\x8a\x56\xc6\x9d\x04\xf2\x1d\x67\xfa\x08\xe9\x1c\x1e\x94\x46\x52\xc9\xc3\x02\xc3\xb9\xfb\x13\x1e\x0c\x13\xfd\xd5\x55\xb5\x99\x42\x76\x62\x1c\x0e\x3d\x8d\x77\x52\x72\x20\xa2\x93\x28\x10\x48\x9a\x48\xc1\xcf\x01\x94\xda\x10\xf4\xee\x4a\x68\xa0\x39\x32\x73\x4e\xa4\x32\x8b\x57\x85\xfa\x98\x25\x9a\x7d\x87\x6e\xec\x5d\x56\x7d\x25\x68\xdb\x9b\x50\x6f\x8f\x3d\xfa\xbd\x15\xf1\x97\xd9\x8a\xd0\x67\x4d\xcd\x75\xb5\xb5\x36\x29\x13\x89\x54\x20\xbc\xb1\xa1\x8d\x54\xc9\x01\x09\x85\x44\x01\x32\xe9\x34\x45\x07\x60\xd3\x1c\x49\x31\xfe\x50\x8c\x66\x07\x41\xdc\xb8\xd3\x22\x35\x99\xda\x5f\xb9\x09\x60\x8c\x3f\xd8\x73\xce\x32\x36\x1e\x34\x8e\x55\x1b\x50\xaf\xd9\x5a\xcd\x5d\xa2\x4d\x94\x67\x41\x90\x3d\xd1\x21\x4c\x37\x08\x01\x9d\xc1\x91\xe0\x8c\xd4\x51\x06\xe6\x7e\x24\x3f\xb9\xfa\x06\xe7\xbc\x3a\xa7\xe5\xa5\xbc\x75\x35\x91\xad\x93\x7e\x56\xe9\xd5\x9f\xc6\x76\xb4\xfa\x71\x07\x55\xae\xbd\x4d\x5c\x49\x23\xf4\x54\x03\xd2\x90\x0e\x8f\x7d\xa3\x5f\x02\xa1\x3b\x3e\x2a\xc9\x1d\xbe\x09\xc0\xf1\x6a\xa4\x40\xec\x7c\x6d\xd4\x0f\xae\x08\x5a\x3c\x54\x0a\xcd\xb4\x01\x41\xdd\xfb\xab\x4e\xa6\x1d\x1b\x1c\x5e\x0c\x8d\x32\xdd\x77\x85\x75\x5d\x25\x15\x39\x58\xbc\x0d\x6e\x74\xc2\x63\xb5\xba\x11\xf0\x53\x54\x11\x92\x4a\x35\xe2\x9a\x70\x35\xe6\xa6\xd9\xde\xd6\xc5\x44\x1d\x3a\x06\x19\x4f\x12\x1f\x8b\x84\x94\x32\x37\x72\xac\x7a\x2c\x33\xee\x14\xf4\xf6\xfa\x6a\x01\xae\x83\xf0\x36\xa9\xf7\x72\xc1\xf4\xa1\x7c\x45\x34\x7a\x60\xce\x34\xd9\xf5\xce\x25\x5c\x89\xb6\xc8\x0c\x78\xf2\xe7\x7b\x04\x83\xac\x77\x94\x50\x17\x4d\xed\xdc\x0e\xfa\x7d\x6e\xb8\x1b\x96\x81\xcc\xfd\xdd\x43\xd1\x62\x4c\xd4\x50\x83\x8b\x43\xd6\xd8\x97\xcb\x07\x9e\x05\xd0\xa2\xec\xfb\xff\xa1\x75\xd8\x64\x7b\x78\xaf\x93\x43\x92\x1b\x88\xb4\x3c\x06\x09\xca\x84\x08\x8a\x33\x4a\xb4\xaf\xda\xb8\x61\xc7\x38\x57\x29\x31\x90\x54\x77\x5c\xe6\xd4\x77\x13\x85\x9d\x22\x48\x38\x07\xce\x74\x16\x52\x28\xc5\x29\x70\xe2\xcc\x14\xde\x1a\xb9\x64\xdf\x13\xc6\x73\x84\x84\xd0\x51\x48\xef\x71\x64\x52\x30\x23\x9d\xd0\x13\x36\x64\x46\x9e\x93\x7a\xd8\x92\xc4\x13\x89\x25\x93\xc4\xd4\x5d\x28\xad\x8b\x75\x91\x67\x8e\x52\xc5\x46\xc0\x66\xcf\x50\x1b\xdb\xd1\x4a\x55\xfd\xea\x42\xf2\xcb\xe8\x2e\x41\xe8\xc6\x72\x6b\xd5\xd9\x9a\x62\x5e\xb9\x3f\xb1\x1c\x2e\xcd\xc3\xc8\xea\xac\x47\x1c\x58\x0c\x41\x17\x70\xd8\xec\xfb\x7b\xf9\x17\xb5\x82\x05\x1f\xc9\x99\x2d\x63\x96\x30\x05\x95\xc2\xce\x23\x64\x95\xde\x18\x16\xc5\x1a\x2d\x9a\xb0\x4c\x19\x2f\x82\x94\x0c\x4f\x4c\xa4\xf2\x69\xc6\x80\xcb\x59\x5b\x71\x42\xa1\x87\xd8\xb7\x1a\x5a\x1b\x24\x4c\x98\xd9\xe7\x61\x7d\xb3\x28\x84\x3d\x20\x88\x61\x44\x44\xd3\x7d\x49\x34\xde\x9b\xf8\x74\xf3\x6b\x58\x51\x68\x55\x14\xe8\x6f\xb0\x2d\x79\xab\xf3\x6f\xa8\xf0\x9a\x70\xf7\x64\xf7\x86\xce\x5b\xdb\x8d\x65\x74\xaa\x72\xef\xd9\x5a\x06\x99\x9c\xbe\x47\x72\xc3\x55\x6e\x9f\x8a\x35\xd9\x02\xd5\x4b\xd0\x61\x6c\x45\x95\x48\xb5\xfc\x6e\x90\xff\xc0\x75\xeb\xdf\x8b\x60\x8a\x64\x4b\x61\x48\xf0\xf1\x74\xec\x2c\x9f\xa2\x77\x80\x0e\xf9\x4e\x84\x5d\xbc\x7c\x67\xe8\xd0\xbd\xfa\x51\xde\x2c\x19\xf1\xea\x43\xd3\x47\xad\x1b\x5b\x6d\x83\x5d\x3c\x7a\xad\x63\xb9\xf9\x97\x2d\x5d\x7f\x0b\xd7\xd5\xfb\x11\x63\x08\x3d\x06\xb5\x89\x33\xeb\xfd\x1b\x70\x68\xb0\x99\xe1\x84\xa1\x8a\x6a\x01\x14\x0a\xb9\x67\xf3\xff\x81\x54\xbf\xfa\xba\xfe\x79\x6b\xb0\xfa\xe2\xc4\xfb\x55\x43\x49\x75\x75\xae\x0f\xb8\x37\xfa\x0e\x7c\xf6\xc6\xae\x18\x24\x3a\xa7\x2b\x2a\xaa\xdf\xae\x78\xd5\xa8\xe8\x1e\xe9\xb5\x5c\x32\xdc\xe1\x9b\xb2\x64\xf0\xbd\xa3\x8a\x63\xdb\x9d\x46\x9f\xcc\xf1\x7d\x66\xb7\xf6\x99\x3a\xf0\xaf\x49\x46\x76\x94\x7b\x83\x56\x46\x9c\xd6\x7c\x41\xdc\xbf\xfb\x30\x51\xe1\x4d\xdd\x0f\x7c\xa5\xd2\x68\x81\xcb\x14\x6e\x9f\xf6\x9a\xe7\xda\xba\xc3\xcf\xcb\xc6\xe3\xbf\xe6\x1f\x7c\x6c\x56\xe8\x29\xce\x83\x1d\xe8\x1f\xdd\xe3\x33\xfb\xa1\xd8\xb6\x63\x9f\x1e\x89\xbd\x6d\xdb\x4a\xb4\xdb\xf6\x7e\xc2\xe8\xe7\x01\xae\x4f\xd0\xfa\x87\x77\xf5\xa7\x60\x23\xf7\x09\x56\xed\xbf\xe5\xa7\x7d\xab\x97\xd5\xff\x02\x00\x00\xff\xff\x0a\xb3\x24\xb8\x44\x3d\x00\x00") +var _dataConfig_schema_v34Json = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xec\x5b\x4f\x73\xdb\x3a\x0e\xbf\xfb\x53\x68\xf4\xde\xad\x76\xd2\x99\xed\xec\xcc\xf6\xb6\xc7\x3d\xed\x9e\x37\xe3\x6a\x68\x0a\xb6\xd9\x50\x24\x0b\x52\x4e\xdc\x4e\xbe\xfb\x8e\xfe\x9a\x92\x28\x91\xb2\x95\x26\xdd\xd7\x53\x62\x09\x00\x09\x10\xf8\x01\x20\xa9\x1f\xab\x28\x8a\xff\xd4\xf4\x08\x19\x89\x3f\x47\xf1\xd1\x18\xf5\xf9\xfe\xfe\xab\x96\x62\x53\x3d\xbd\x93\x78\xb8\x4f\x91\xec\xcd\xe6\xe3\xa7\xfb\xea\xd9\x1f\xf1\xba\xe0\x63\x69\xc1\x42\xa5\xd8\xb3\x43\x52\xbd\x49\x4e\x7f\xbb\xfb\x74\x57\xb0\x57\x24\xe6\xac\xa0\x20\x92\xbb\xaf\x40\x4d\xf5\x0c\xe1\x5b\xce\x10\x0a\xe6\x87\xf8\x04\xa8\x99\x14\xf1\x76\xbd\x2a\xde\x29\x94\x0a\xd0\x30\xd0\xf1\xe7\xa8\x98\x5c\x14\xb5\x24\xcd\x03\x4b\xac\x36\xc8\xc4\x21\x2e\x1f\xbf\x94\x12\xa2\x28\xd6\x80\x27\x46\x2d\x09\xed\x54\xff\xb8\xbf\xc8\xbf\x6f\xc9\xd6\x7d\xa9\xd6\x64\xcb\xe7\x8a\x18\x03\x28\xfe\x33\x9c\x5b\xf9\xfa\xcb\x03\xd9\x7c\xff\xe7\xe6\xbf\x1f\x37\xff\xb8\x4b\x36\xdb\x0f\x7f\x76\x5e\x17\xf6\x45\xd8\x57\xc3\xa7\xb0\x67\x82\x19\x26\x45\x3b\x7e\xdc\x52\xbe\xd4\xff\xbd\xb4\x03\x93\x34\x2d\x89\x09\xef\x8c\xbd\x27\x5c\x43\x57\x67\x01\xe6\x49\xe2\xa3\x4f\xe7\x96\xec\x8d\x74\xae\xc7\x77\xe8\xdc\x55\xe7\x24\x79\x9e\x79\x57\xb0\xa1\x7a\x23\x65\xaa\xe1\x97\x59\x3f\x0d\x14\xc1\xf8\x5d\xb6\xa2\x7a\x33\x8f\x2d\x86\x5f\x46\xe1\x0a\x35\x7c\x0a\x37\x54\x6f\xa4\x70\x35\xfc\x6d\x0a\xaf\x1a\xa5\xdd\x73\x8c\xbf\x3c\x6f\x8a\xbf\x2f\xa5\xcc\x49\x79\x95\x14\x6b\x7e\xa5\x12\x1d\xcc\x73\x99\xd3\x85\x39\xe3\xf6\x6c\x0d\x3a\x62\xc9\x14\x14\x97\xe7\x72\xe6\x6e\x9b\x55\x04\x19\x08\x13\xb7\x66\x8a\xa2\x78\x97\x33\x9e\xf6\xad\x2e\x05\xfc\xbb\x10\xf1\x60\x3d\x8c\xa2\x1f\x7d\x78\xb7\xe4\x94\xef\x3b\xbf\xc6\x9d\xa2\x7d\x3f\xa2\x4b\xfb\x9e\x4a\x61\xe0\xd9\x94\x4a\x4d\x0f\x5d\x99\x40\xd2\x47\xc0\x3d\xe3\x10\xca\x41\xb0\xf2\xf4\x11\x93\x71\xa6\x4d\x22\x31\x49\x19\x35\x4e\x7e\x4e\x76\xc0\x6f\x92\x40\x09\x3d\x42\xb2\x47\x99\x79\xa5\xec\x93\x4a\x13\xed\x14\xd4\x20\x78\xa0\xe6\x86\xe0\x01\xdc\x96\xed\x11\x0f\xb8\xfd\xb1\xd5\xb2\x5a\xbf\xb6\x2b\x87\xc0\x98\x12\x95\x90\x34\xed\xcc\x83\x20\x92\x73\xbc\x8e\x62\x66\x20\xd3\x6e\x85\xa2\x38\x17\xec\x5b\x0e\xff\xaa\x49\x0c\xe6\xd0\x97\x9b\xa2\x54\xcb\x0b\x3e\xa0\xcc\x55\xa2\x08\x16\x81\x34\x6d\xec\x98\xca\x2c\x23\x62\xa9\xe8\x9a\xa3\x47\x80\xe5\x07\x38\x1f\xd9\x21\x5b\x8f\x61\xbf\x6a\x47\xeb\x4c\x6b\x44\x1b\xbf\x3e\x43\xbc\xf0\x23\x86\x1f\x33\x0a\xc8\x95\x39\xd2\x50\x08\x98\x0e\x05\x27\x7d\xce\xd2\x70\xe2\xc3\x1c\xe2\x4c\xa6\xdd\x79\x8b\x3c\xdb\x01\x0e\x42\xb2\x1b\x59\xc3\xdf\xdb\x95\xeb\x4d\x6f\xf5\x0d\x61\x02\x30\x11\x24\xf3\xd9\x2a\xa6\x08\x29\x08\xc3\x08\x4f\xb4\x02\xda\x21\x6f\x56\x6a\x62\x65\xe2\x20\x48\x8e\x11\x0e\x4c\x1b\x3c\x4f\x83\xd2\x8b\x3d\xb1\x14\x14\x88\x54\x27\x55\x13\x32\x1f\x3d\xe3\x14\xda\x8e\x64\x51\x98\x48\xc5\x54\x56\xa8\xc4\x14\x79\xa1\x98\x5b\xdc\x63\x4c\x34\x10\xa4\xc7\x2b\xf9\x65\x46\x98\x08\x59\x54\x10\x06\xcf\x4a\xb2\x0a\xc6\xde\x1d\x3e\x81\x38\x25\xad\xdf\xcc\x36\x03\x88\x13\x43\x29\xb2\x06\xa4\xc3\xb2\xb3\xc5\xff\xac\xa4\x86\xdb\xc1\xb1\xe6\x78\x68\x14\x5f\xb7\x31\xbd\xed\x5a\x2f\xde\x4b\xcc\x48\x31\xd9\x66\x6c\x3b\x86\x3b\x43\x0d\x3d\xcf\x36\xa0\xad\x43\x51\xd5\x12\x9e\x70\x26\x1e\x97\x77\x71\x78\x36\x48\x92\xa3\xd4\xe6\x9a\x02\x28\x3e\x02\xe1\xe6\x48\x8f\x40\x1f\x27\xd8\x6d\xaa\x0e\xb7\xd4\x26\xc4\xc9\x59\x46\x0e\x7e\x22\x45\x7d\x24\x57\x17\x7a\xf1\xa2\xc6\xb7\xc4\xca\xc3\xa1\x20\x1d\xf3\xb8\x41\xe3\x50\xbf\xf6\x95\xdc\x29\xb2\x13\x60\x68\x15\x29\xd5\xa5\xdf\xe9\xbf\x0c\xc9\xe6\xde\x06\xb1\x43\xfa\xe5\xae\xea\x0f\x27\xa2\xaa\xfc\x8f\xf3\x78\x3b\x4c\x99\xc3\xa4\xd9\x7f\xd2\xd3\x30\xac\xce\xed\xac\x4a\x46\x68\x51\xce\x22\xe8\x91\x75\xbd\x90\xd6\xf5\x7a\x32\xc8\xf9\x17\xda\x01\xf1\x20\xb1\x8e\x21\xf5\x55\x6d\xc4\xfc\xf6\x2d\x68\xe9\xbc\x3d\xbe\x47\x9b\xb1\xe9\x85\x4e\xf3\x32\x5d\xbf\x8b\x95\x74\x84\x33\xa2\xc1\x1f\xec\x93\xfd\x58\x2b\x8d\xa9\xd3\xa7\x40\x9f\x70\xf1\xfe\x7d\x92\x77\x84\x75\x54\x66\x78\xeb\xe6\x11\x65\x97\xa8\x9c\x3b\x27\xb2\xf5\x17\xad\xaf\xd9\x59\xaa\x6e\xe1\xdd\xc5\x8a\x12\x21\xec\x00\x53\x12\xcd\x4f\xe9\x85\x2e\x38\x75\x49\xf8\xd5\xe0\xc3\xf6\xa8\xbf\xdc\x41\x4c\xaf\xd3\x53\x4d\xa0\x94\x83\xda\xd1\x51\x31\x61\xe0\x50\xb4\x32\xee\x24\x90\xef\x38\xd3\x47\x48\xe7\xf0\xa0\x34\x92\x4a\x1e\x16\x18\xce\xdd\x9f\xf0\x60\x98\xe8\xaf\xae\xaa\xcd\x14\xb2\x13\xe3\x70\xe8\x69\xbc\x93\x92\x03\x11\x9d\x44\x81\x40\xd2\x44\x0a\x7e\x0e\xa0\xd4\x86\xa0\x77\x57\x42\x03\xcd\x91\x99\x73\x22\x95\x59\xbc\x2a\xd4\xc7\x2c\xd1\xec\x3b\x74\x63\xef\xe2\xf5\xb5\xa0\x6d\x6f\x42\xbd\x3d\xf6\xe8\xf7\x56\xc4\x5f\x66\x2b\x42\x9f\x35\x35\xd7\xd5\xd6\xda\xa4\x4c\x24\x52\x81\xf0\xc6\x86\x36\x52\x25\x07\x24\x14\x12\x05\xc8\xa4\xd3\x14\x1d\x80\x4d\x73\x24\xc5\xf8\x43\x31\x9a\x1d\x04\x71\xe3\x8e\x45\x6a\x32\xb5\xbf\x72\x13\xc0\x18\x7f\xb0\xe7\x9c\x65\x6c\x3c\x68\x1c\x5e\x1b\x50\xaf\x55\xb5\x9a\xbb\x44\x9b\x28\xcf\x82\x20\x7b\xa2\x43\x98\x6e\x10\x02\x3a\x83\x23\xc1\x19\xa9\xa3\x0c\xcc\xfd\x48\x7e\x72\xf5\x0d\xce\x79\x75\x4e\xcb\x4b\x79\xeb\x7a\x22\x5b\x27\xfd\xac\xd2\xab\x3f\x8d\xed\x68\xf5\xe3\x0e\xaa\x5c\x7b\x9b\xb8\x92\x46\xe8\xa9\x06\xa4\x25\x1d\x1e\xfb\x46\xbf\x04\x42\x77\xd6\xa8\x24\x77\xac\x4d\x00\x8e\xd7\x23\x05\x62\xe7\x6b\xa3\x7e\x70\x45\x60\xf1\x50\x29\x34\xd3\x06\x04\x75\xef\xaf\x3a\x99\x76\x6c\x70\x78\x31\x34\xca\x74\xdf\x15\xd6\x75\x95\x54\xe4\x50\xe1\x6d\x70\xa3\x13\x1e\xab\xf5\x8d\x80\x9f\xa2\x8a\x90\x54\xaa\x91\xa5\x09\x57\x63\x6e\x9a\xed\x6d\x5d\x4c\xd4\xa1\x63\x90\xf1\x24\xf1\xb1\x48\x48\x29\x73\x23\xc7\xaa\xc7\x32\xe3\x4e\x41\x6f\xaf\xaf\x11\xe0\x3a\x08\xb7\x49\xbd\x97\x0b\xa6\x0f\xe5\x6b\xa2\xd1\x03\x73\xa6\xc9\xae\x77\x2e\xe1\x4a\xb4\x45\x66\xc0\x93\x3b\xdf\xfb\x0b\x06\x04\x83\xac\x77\xc0\xd0\x94\x52\x76\xc6\x07\xfd\x3e\xb7\xe1\x0d\xcb\x40\xe6\x4e\x70\x0a\xa9\x96\x08\x9a\xf9\xf5\xd6\xca\x76\xd3\x5a\x5e\x6c\x5d\x5f\xf0\xb8\x90\x45\xd9\xf7\xa0\x07\xeb\xb8\xaa\xda\x05\xf0\xba\x49\x48\x7a\x04\x91\x96\x07\x29\x41\xb9\x14\x41\x71\x46\x89\xf6\xd5\x2b\x37\xec\x39\xe7\x2a\x25\x06\x92\xfa\x96\xcc\x9c\x0a\x71\xa2\x34\x54\x04\x09\xe7\xc0\x99\xce\x42\x4a\xad\x38\x05\x4e\x9c\xb9\xc6\xeb\x37\x25\xfb\x9e\x30\x9e\x23\x24\x84\x8e\x26\x85\x1e\x47\x26\x05\x33\xd2\x09\x5e\x61\x43\x66\xe4\x39\x69\x86\x2d\x49\x3c\x51\x5b\x32\x49\x4c\xdd\xa5\xd6\xba\xf0\x8b\x3c\x73\x14\x3b\x55\x5c\x6c\xf6\x0c\xb5\xa9\x7a\x62\xa9\xea\x5f\x5d\x50\x7f\x19\xdd\x67\x08\xdd\x9a\xb6\xbc\xae\xaa\x4a\xe6\x35\x0c\x13\xee\x70\x69\x3f\x46\xbc\xb3\x19\x71\x60\x31\x04\x5d\x00\x6a\x7b\x72\xe0\xe5\x5f\xd4\x0a\x15\x24\x49\xce\xaa\x42\x68\x09\x53\x50\x29\xaa\x79\x84\x78\xe9\x8d\x61\x51\xf8\x68\xd1\xc6\x65\xca\x78\x11\xa4\x64\x78\x62\x22\x95\x4f\xf3\xd1\x77\x01\x6b\x2b\x4e\x28\xf4\x10\xfb\x56\x43\x6b\x83\x84\x09\x33\xfb\x44\xad\x6f\x16\x85\xb0\x07\x04\x31\x8c\x88\x68\xba\xb3\x89\xc6\xbb\x1b\x9f\x6e\x7e\x0d\x6b\x0a\xad\x8a\x12\xff\x0d\x36\x36\x6f\x5d\xfc\x1b\x6a\xc4\x36\xdc\x3d\xd9\xbd\xa5\xf3\x56\x87\x63\x19\x9d\xaa\xdc\x7b\x3a\x97\x41\x26\xa7\x6f\xa2\xdc\x70\x19\xdc\xa7\x62\x43\xb6\x40\xf5\x12\x74\x9c\x5b\x53\x25\x52\x2d\xbf\x9f\xe4\x3f\xb2\xdd\xfa\x77\x33\x98\x22\xd9\x52\x18\x12\x7c\xc0\x1d\x3b\xcb\xa7\xe8\x1d\xa0\x43\xbe\x13\x61\x57\x37\xdf\x19\x3a\x74\x2f\x8f\x94\x77\x53\x46\x56\xf5\xa1\xed\xc4\xd6\xad\xad\xb6\xc1\x4b\x3c\x7a\x31\x64\xb9\xf9\x97\x4d\x61\x7f\x13\xd8\xd5\x3d\x12\x63\x08\x3d\x06\x35\x9a\x33\xeb\xfd\x1b\x70\x68\xb0\x1d\xe2\x84\xa1\x9a\x6a\x01\x14\x0a\xb9\xa9\xf3\xff\x81\x54\xbf\xba\x5f\xff\x3c\x1f\xac\xbf\x59\xf1\x7e\x17\x51\x52\x5d\x9d\xeb\x03\x6e\x9e\xbe\x83\x35\x7b\xe3\xa5\x18\x24\x3a\xe7\x52\xd4\x54\xbf\x97\xe2\x55\xa3\xa2\x7b\x28\x68\x2d\xc9\x70\x37\x70\xca\x92\xc1\x37\x97\x6a\x8e\x6d\x77\x1a\x7d\x32\xc7\x17\x9e\xdd\xda\x67\xea\xca\x40\x43\x32\xb2\x27\xdd\x1b\xb4\x36\xe2\xb4\xe6\x0b\xe2\xfe\xdd\x87\x89\x0a\x6f\xea\x86\xe1\x2b\x95\x46\x0b\x5c\xc7\x70\xaf\x69\xaf\x79\x6e\xac\x3b\xfc\x40\x6d\x3c\xfe\x1b\xfe\xc1\xe7\x6a\x85\x9e\xe2\x3c\xd8\xad\xfe\xd1\x3d\x80\xab\x3e\x35\xdb\x76\xec\xd3\x23\xa9\xee\xeb\x5a\x89\x76\x6b\xef\x27\x8c\x7e\x60\xe0\xfa\x88\xad\x7f\xfc\xd7\x7c\x4c\x36\x72\x23\x61\x65\xff\x2d\x3f\x0e\x5c\xbd\xac\xfe\x17\x00\x00\xff\xff\xf4\xc7\x3d\x6c\x86\x3d\x00\x00") func dataConfig_schema_v34JsonBytes() ([]byte, error) { return bindataRead( diff --git a/components/cli/cli/compose/schema/data/config_schema_v3.4.json b/components/cli/cli/compose/schema/data/config_schema_v3.4.json index 79fc4cb614..f2e315ba8e 100644 --- a/components/cli/cli/compose/schema/data/config_schema_v3.4.json +++ b/components/cli/cli/compose/schema/data/config_schema_v3.4.json @@ -316,7 +316,7 @@ "additionalProperties": false, "properties": { "disable": {"type": "boolean"}, - "interval": {"type": "string"}, + "interval": {"type": "string", "format": "duration"}, "retries": {"type": "number"}, "test": { "oneOf": [ @@ -324,8 +324,8 @@ {"type": "array", "items": {"type": "string"}} ] }, - "timeout": {"type": "string"}, - "start_period": {"type": "string"} + "timeout": {"type": "string", "format": "duration"}, + "start_period": {"type": "string", "format": "duration"} } }, "deployment": { diff --git a/components/cli/cli/compose/types/types.go b/components/cli/cli/compose/types/types.go index 9686649682..a360a8a9b9 100644 --- a/components/cli/cli/compose/types/types.go +++ b/components/cli/cli/compose/types/types.go @@ -169,10 +169,10 @@ type DeployConfig struct { // HealthCheckConfig the healthcheck configuration for a service type HealthCheckConfig struct { Test HealthCheckTest - Timeout string - Interval string + Timeout *time.Duration + Interval *time.Duration Retries *uint64 - StartPeriod string `mapstructure:"start_period"` + StartPeriod *time.Duration `mapstructure:"start_period"` Disable bool }

Mount path inside the container, for example /some/path/in/container/. If the path does not exist in the container's filesystem, the Engine creates - a directory at the specified location before mounting the volume or bind-mount.

+ a directory at the specified location before mounting the volume or bind mount.