From 889843574bf43cafa5335d8bdd40ccac17620405 Mon Sep 17 00:00:00 2001 From: Antonio Murdaca Date: Sat, 9 Sep 2017 01:22:09 +0200 Subject: [PATCH 1/8] volume: evaluate symlinks before relabeling mount source Simple reproducer: ```sh $ mkdir /var/foo $ touch /var/foo/test $ ln -s /var/foo /var/bar $ docker run -ti -v /var/bar:/var/bar:Z fedora sh sh-4.3# ls -lZ /var/bar/ ls: cannot open directory '/var/bar/': Permission denied ``` Signed-off-by: Antonio Murdaca Upstream-commit: e0b22c0b9e013527ef121250b51ae780d2d2912d Component: engine --- components/engine/volume/volume.go | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/components/engine/volume/volume.go b/components/engine/volume/volume.go index 4aa4de513d..b8ec1e5a00 100644 --- a/components/engine/volume/volume.go +++ b/components/engine/volume/volume.go @@ -3,6 +3,7 @@ package volume import ( "fmt" "os" + "path/filepath" "syscall" "time" @@ -155,13 +156,20 @@ func (m *MountPoint) Setup(mountLabel string, rootIDs idtools.IDPair, checkFun f return } - err = label.Relabel(m.Source, mountLabel, label.IsShared(m.Mode)) + var sourcePath string + sourcePath, err = filepath.EvalSymlinks(m.Source) + if err != nil { + path = "" + err = errors.Wrapf(err, "error evaluating symlinks from mount source %q", m.Source) + return + } + err = label.Relabel(sourcePath, 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) + err = errors.Wrapf(err, "error setting label on mount source '%s'", sourcePath) } }() From e55d5634bfededf522ad41e2f592c1bd52224f40 Mon Sep 17 00:00:00 2001 From: Daniel Nephin Date: Tue, 19 Sep 2017 18:14:41 -0400 Subject: [PATCH 2/8] Add a new entrypoint for CI Signed-off-by: Daniel Nephin Upstream-commit: dbf580be57a4bb854d7ce20d313e3a22ea337be5 Component: engine --- components/engine/Makefile | 5 +---- components/engine/daemon/daemon.go | 5 +---- components/engine/hack/ci/arm | 10 ++++++++++ components/engine/hack/ci/experimental | 9 +++++++++ components/engine/hack/ci/janky | 13 +++++++++++++ components/engine/hack/ci/powerpc | 6 ++++++ components/engine/hack/ci/z | 6 ++++++ components/engine/hack/make.sh | 2 -- components/engine/hack/make/test-unit | 6 ------ components/engine/hack/make/tgz | 2 -- .../engine/integration-cli/requirements_test.go | 4 ---- 11 files changed, 46 insertions(+), 22 deletions(-) create mode 100755 components/engine/hack/ci/arm create mode 100755 components/engine/hack/ci/experimental create mode 100755 components/engine/hack/ci/janky create mode 100755 components/engine/hack/ci/powerpc create mode 100755 components/engine/hack/ci/z delete mode 100644 components/engine/hack/make/test-unit delete mode 100644 components/engine/hack/make/tgz diff --git a/components/engine/Makefile b/components/engine/Makefile index d9fb68b1de..7d50afa7d4 100644 --- a/components/engine/Makefile +++ b/components/engine/Makefile @@ -1,4 +1,4 @@ -.PHONY: all binary dynbinary build cross deb help init-go-pkg-cache install manpages rpm run shell test test-docker-py test-integration test-unit tgz validate win +.PHONY: all binary dynbinary build cross deb help init-go-pkg-cache install manpages rpm run shell test test-docker-py test-integration test-unit validate win # set the graph driver as the current graphdriver if not set DOCKER_GRAPHDRIVER := $(if $(DOCKER_GRAPHDRIVER),$(DOCKER_GRAPHDRIVER),$(shell docker info 2>&1 | grep "Storage Driver" | sed 's/.*: //')) @@ -164,9 +164,6 @@ test-integration: build ## run the integration tests test-unit: build ## run the unit tests $(DOCKER_RUN_DOCKER) hack/test/unit -tgz: build ## build the archives (.zip on windows and .tgz\notherwise) containing the binaries - $(DOCKER_RUN_DOCKER) hack/make.sh dynbinary binary cross tgz - validate: build ## validate DCO, Seccomp profile generation, gofmt,\n./pkg/ isolation, golint, tests, tomls, go vet and vendor $(DOCKER_RUN_DOCKER) hack/validate/all diff --git a/components/engine/daemon/daemon.go b/components/engine/daemon/daemon.go index 19d22bf702..cb9e8eeacc 100644 --- a/components/engine/daemon/daemon.go +++ b/components/engine/daemon/daemon.go @@ -140,10 +140,7 @@ func (daemon *Daemon) StoreHosts(hosts []string) { // HasExperimental returns whether the experimental features of the daemon are enabled or not func (daemon *Daemon) HasExperimental() bool { - if daemon.configStore != nil && daemon.configStore.Experimental { - return true - } - return false + return daemon.configStore != nil && daemon.configStore.Experimental } func (daemon *Daemon) restore() error { diff --git a/components/engine/hack/ci/arm b/components/engine/hack/ci/arm new file mode 100755 index 0000000000..e60332a608 --- /dev/null +++ b/components/engine/hack/ci/arm @@ -0,0 +1,10 @@ +#!/usr/bin/env bash +# Entrypoint for jenkins arm CI build +set -eu -o pipefail + +hack/test/unit + +hack/make.sh \ + binary-daemon \ + dynbinary \ + test-integration diff --git a/components/engine/hack/ci/experimental b/components/engine/hack/ci/experimental new file mode 100755 index 0000000000..9ccbc8425f --- /dev/null +++ b/components/engine/hack/ci/experimental @@ -0,0 +1,9 @@ +#!/usr/bin/env bash +# Entrypoint for jenkins experimental CI +set -eu -o pipefail + +export DOCKER_EXPERIMENTAL=y + +hack/make.sh \ + binary-daemon \ + test-integration diff --git a/components/engine/hack/ci/janky b/components/engine/hack/ci/janky new file mode 100755 index 0000000000..fe04908cbc --- /dev/null +++ b/components/engine/hack/ci/janky @@ -0,0 +1,13 @@ +#!/usr/bin/env bash +# Entrypoint for jenkins janky CI build +set -eu -o pipefail + +hack/validate/default +hack/test/unit + +hack/make.sh \ + binary-daemon \ + dynbinary \ + test-integration \ + test-docker-py \ + cross diff --git a/components/engine/hack/ci/powerpc b/components/engine/hack/ci/powerpc new file mode 100755 index 0000000000..c36cf37dbf --- /dev/null +++ b/components/engine/hack/ci/powerpc @@ -0,0 +1,6 @@ +#!/usr/bin/env bash +# Entrypoint for jenkins powerpc CI build +set -eu -o pipefail + +hack/test/unit +hack/make.sh dynbinary test-integration diff --git a/components/engine/hack/ci/z b/components/engine/hack/ci/z new file mode 100755 index 0000000000..5ba868e816 --- /dev/null +++ b/components/engine/hack/ci/z @@ -0,0 +1,6 @@ +#!/usr/bin/env bash +# Entrypoint for jenkins s390x (z) CI build +set -eu -o pipefail + +hack/test/unit +hack/make.sh dynbinary test-integration diff --git a/components/engine/hack/make.sh b/components/engine/hack/make.sh index c52e634f97..bc18c066b6 100755 --- a/components/engine/hack/make.sh +++ b/components/engine/hack/make.sh @@ -59,12 +59,10 @@ DEFAULT_BUNDLES=( binary-daemon dynbinary - test-unit test-integration test-docker-py cross - tgz ) VERSION=${VERSION:-$(< ./VERSION)} diff --git a/components/engine/hack/make/test-unit b/components/engine/hack/make/test-unit deleted file mode 100644 index d985a6ec2d..0000000000 --- a/components/engine/hack/make/test-unit +++ /dev/null @@ -1,6 +0,0 @@ -#!/usr/bin/env bash -set -e - -echo "DEPRECATED: use hack/test/unit instead of hack/make.sh test-unit" >&2 - -$SCRIPTDIR/test/unit 2>&1 | tee -a "$DEST/test.log" diff --git a/components/engine/hack/make/tgz b/components/engine/hack/make/tgz deleted file mode 100644 index 1fd37b6b54..0000000000 --- a/components/engine/hack/make/tgz +++ /dev/null @@ -1,2 +0,0 @@ -#!/usr/bin/env bash -echo "tgz is deprecated" diff --git a/components/engine/integration-cli/requirements_test.go b/components/engine/integration-cli/requirements_test.go index 411248195b..f0bb969b24 100644 --- a/components/engine/integration-cli/requirements_test.go +++ b/components/engine/integration-cli/requirements_test.go @@ -56,10 +56,6 @@ func ExperimentalDaemon() bool { return testEnv.DaemonInfo.ExperimentalBuild } -func NotExperimentalDaemon() bool { - return !testEnv.DaemonInfo.ExperimentalBuild -} - func IsAmd64() bool { return os.Getenv("DOCKER_ENGINE_GOARCH") == "amd64" } From 3c4574bac3b24f6389952a02733c1dbb102f32e6 Mon Sep 17 00:00:00 2001 From: Darren Stahl Date: Thu, 21 Sep 2017 15:09:41 -0700 Subject: [PATCH 3/8] Ensure Host Network Service exists If HNS does not exist on the Docker host, the daemon may fail with unexpected and difficult to diagnose errors. This check prevents the daemon from starting on a system that does not have the correct prerequisites. Signed-off-by: Darren Stahl Upstream-commit: 1edcc63560cb1286f452565754092bc2eb428ffa Component: engine --- components/engine/daemon/daemon_windows.go | 25 +++++++ .../engine/daemon/daemon_windows_test.go | 72 +++++++++++++++++++ 2 files changed, 97 insertions(+) create mode 100644 components/engine/daemon/daemon_windows_test.go diff --git a/components/engine/daemon/daemon_windows.go b/components/engine/daemon/daemon_windows.go index c85a1483f2..42391df99c 100644 --- a/components/engine/daemon/daemon_windows.go +++ b/components/engine/daemon/daemon_windows.go @@ -27,8 +27,10 @@ import ( "github.com/docker/libnetwork/netlabel" "github.com/docker/libnetwork/options" blkiodev "github.com/opencontainers/runc/libcontainer/configs" + "github.com/pkg/errors" "github.com/sirupsen/logrus" "golang.org/x/sys/windows" + "golang.org/x/sys/windows/svc/mgr" ) const ( @@ -238,6 +240,29 @@ func checkSystem() error { return fmt.Errorf("Failed to load vmcompute.dll. Ensure that the Containers role is installed.") } + // Ensure that the required Host Network Service and vmcompute services + // are running. Docker will fail in unexpected ways if this is not present. + var requiredServices = []string{"hns", "vmcompute"} + if err := ensureServicesInstalled(requiredServices); err != nil { + return errors.Wrap(err, "a required service is not installed, ensure the Containers feature is installed") + } + + return nil +} + +func ensureServicesInstalled(services []string) error { + m, err := mgr.Connect() + if err != nil { + return err + } + defer m.Disconnect() + for _, service := range services { + s, err := m.OpenService(service) + if err != nil { + return errors.Wrapf(err, "failed to open service %s", service) + } + s.Close() + } return nil } diff --git a/components/engine/daemon/daemon_windows_test.go b/components/engine/daemon/daemon_windows_test.go new file mode 100644 index 0000000000..8b350cf20f --- /dev/null +++ b/components/engine/daemon/daemon_windows_test.go @@ -0,0 +1,72 @@ +// +build windows + +package daemon + +import ( + "strings" + "testing" + + "golang.org/x/sys/windows/svc/mgr" +) + +const existingService = "Power" + +func TestEnsureServicesExist(t *testing.T) { + m, err := mgr.Connect() + if err != nil { + t.Fatal("failed to connect to service manager, this test needs admin") + } + defer m.Disconnect() + s, err := m.OpenService(existingService) + if err != nil { + t.Fatalf("expected to find known inbox service %q, this test needs a known inbox service to run correctly", existingService) + } + defer s.Close() + + input := []string{existingService} + err = ensureServicesInstalled(input) + if err != nil { + t.Fatalf("unexpected error for input %q: %q", input, err) + } +} + +func TestEnsureServicesExistErrors(t *testing.T) { + m, err := mgr.Connect() + if err != nil { + t.Fatal("failed to connect to service manager, this test needs admin") + } + defer m.Disconnect() + s, err := m.OpenService(existingService) + if err != nil { + t.Fatalf("expected to find known inbox service %q, this test needs a known inbox service to run correctly", existingService) + } + defer s.Close() + + for _, testcase := range []struct { + input []string + expectedError string + }{ + { + input: []string{"daemon_windows_test_fakeservice"}, + expectedError: "failed to open service daemon_windows_test_fakeservice", + }, + { + input: []string{"daemon_windows_test_fakeservice1", "daemon_windows_test_fakeservice2"}, + expectedError: "failed to open service daemon_windows_test_fakeservice1", + }, + { + input: []string{existingService, "daemon_windows_test_fakeservice"}, + expectedError: "failed to open service daemon_windows_test_fakeservice", + }, + } { + t.Run(strings.Join(testcase.input, ";"), func(t *testing.T) { + err := ensureServicesInstalled(testcase.input) + if err == nil { + t.Fatalf("expected error for input %v", testcase.input) + } + if !strings.Contains(err.Error(), testcase.expectedError) { + t.Fatalf("expected error %q to contain %q", err.Error(), testcase.expectedError) + } + }) + } +} From 401172966f6082329f1860ab1761d3e6140e5585 Mon Sep 17 00:00:00 2001 From: yangchenliang Date: Mon, 18 Sep 2017 14:47:19 +0800 Subject: [PATCH 4/8] "docker swarm init --force-new-cluster" use limit Signed-off-by: yangchenliang When worker executor `docker swarm init --force-new-cluster`,docker would hang.So only manager can process it. Signed-off-by: yangchenliang Upstream-commit: 12e947efdba5481020f6543514ade83d87c69a28 Component: engine --- components/engine/daemon/cluster/errors.go | 3 +++ components/engine/daemon/cluster/swarm.go | 4 ++++ 2 files changed, 7 insertions(+) diff --git a/components/engine/daemon/cluster/errors.go b/components/engine/daemon/cluster/errors.go index 1698229427..0ffe78b98b 100644 --- a/components/engine/daemon/cluster/errors.go +++ b/components/engine/daemon/cluster/errors.go @@ -15,6 +15,9 @@ const ( // errSwarmCertificatesExpired is returned if docker was not started for the whole validity period and they had no chance to renew automatically. errSwarmCertificatesExpired notAvailableError = "Swarm certificates have expired. To replace them, leave the swarm and join again." + + // errSwarmNotManager is returned if the node is not a swarm manager. + errSwarmNotManager notAvailableError = "This node is not a swarm manager. Worker nodes can't be used to view or modify cluster state. Please run this command on a manager node or promote the current node to a manager." ) type notFoundError struct { diff --git a/components/engine/daemon/cluster/swarm.go b/components/engine/daemon/cluster/swarm.go index 1fa62920e3..e3fffe983d 100644 --- a/components/engine/daemon/cluster/swarm.go +++ b/components/engine/daemon/cluster/swarm.go @@ -26,9 +26,13 @@ func (c *Cluster) Init(req types.InitRequest) (string, error) { defer c.controlMutex.Unlock() if c.nr != nil { if req.ForceNewCluster { + // Take c.mu temporarily to wait for presently running // API handlers to finish before shutting down the node. c.mu.Lock() + if !c.nr.nodeState.IsManager() { + return "", errSwarmNotManager + } c.mu.Unlock() if err := c.nr.Stop(); err != nil { From b987e635726d4147fe57dae7ae8bf059921c04a0 Mon Sep 17 00:00:00 2001 From: Yong Tang Date: Tue, 26 Sep 2017 11:07:27 +0000 Subject: [PATCH 5/8] Update runc to 0351df1c5a66838d0c392b4ac4cf9450de844e2d This fix updates runc to 0351df1c5a66838d0c392b4ac4cf9450de844e2d With this fix the warnings generated by netgo and dlopen by go 1.9 are addressed. See - opencontainers/runc#1577 - opencontainers/runc#1579 This fix is part of the efforts for go 1.9 (#33892) Signed-off-by: Yong Tang Upstream-commit: e0ff1d147bc12234f1be25a620bf6b3bf3179d97 Component: engine --- .../engine/hack/dockerfile/binaries-commits | 2 +- components/engine/vendor.conf | 2 +- .../runc/libcontainer/configs/config.go | 4 + .../runc/libcontainer/configs/intelrdt.go | 7 + .../runc/libcontainer/nsenter/nsexec.c | 121 ++++++++++++++++-- .../opencontainers/runc/vendor.conf | 6 +- 6 files changed, 127 insertions(+), 15 deletions(-) create mode 100644 components/engine/vendor/github.com/opencontainers/runc/libcontainer/configs/intelrdt.go diff --git a/components/engine/hack/dockerfile/binaries-commits b/components/engine/hack/dockerfile/binaries-commits index 4338a3b48b..fde89d24e4 100644 --- a/components/engine/hack/dockerfile/binaries-commits +++ b/components/engine/hack/dockerfile/binaries-commits @@ -3,7 +3,7 @@ TOMLV_COMMIT=9baf8a8a9f2ed20a8e54160840c492f937eeaf9a # When updating RUNC_COMMIT, also update runc in vendor.conf accordingly -RUNC_COMMIT=1c81e2a794c6e26a4c650142ae8893c47f619764 +RUNC_COMMIT=0351df1c5a66838d0c392b4ac4cf9450de844e2d CONTAINERD_COMMIT=06b9cb35161009dcb7123345749fef02f7cea8e0 TINI_COMMIT=949e6facb77383876aeff8a6944dde66b3089574 LIBNETWORK_COMMIT=7b2b1feb1de4817d522cc372af149ff48d25028e diff --git a/components/engine/vendor.conf b/components/engine/vendor.conf index 246fdc14cc..854adcb372 100644 --- a/components/engine/vendor.conf +++ b/components/engine/vendor.conf @@ -66,7 +66,7 @@ github.com/pborman/uuid v1.0 google.golang.org/grpc v1.3.0 # When updating, also update RUNC_COMMIT in hack/dockerfile/binaries-commits accordingly -github.com/opencontainers/runc 1c81e2a794c6e26a4c650142ae8893c47f619764 +github.com/opencontainers/runc 0351df1c5a66838d0c392b4ac4cf9450de844e2d github.com/opencontainers/image-spec 372ad780f63454fbbbbcc7cf80e5b90245c13e13 github.com/opencontainers/runtime-spec v1.0.0 diff --git a/components/engine/vendor/github.com/opencontainers/runc/libcontainer/configs/config.go b/components/engine/vendor/github.com/opencontainers/runc/libcontainer/configs/config.go index 269fffff35..3cae4fd8d9 100644 --- a/components/engine/vendor/github.com/opencontainers/runc/libcontainer/configs/config.go +++ b/components/engine/vendor/github.com/opencontainers/runc/libcontainer/configs/config.go @@ -187,6 +187,10 @@ type Config struct { // Rootless specifies whether the container is a rootless container. Rootless bool `json:"rootless"` + + // IntelRdt specifies settings for Intel RDT/CAT group that the container is placed into + // to limit the resources (e.g., L3 cache) the container has available + IntelRdt *IntelRdt `json:"intel_rdt,omitempty"` } type Hooks struct { diff --git a/components/engine/vendor/github.com/opencontainers/runc/libcontainer/configs/intelrdt.go b/components/engine/vendor/github.com/opencontainers/runc/libcontainer/configs/intelrdt.go new file mode 100644 index 0000000000..36bd5f96a1 --- /dev/null +++ b/components/engine/vendor/github.com/opencontainers/runc/libcontainer/configs/intelrdt.go @@ -0,0 +1,7 @@ +package configs + +type IntelRdt struct { + // The schema for L3 cache id and capacity bitmask (CBM) + // Format: "L3:=;=;..." + L3CacheSchema string `json:"l3_cache_schema,omitempty"` +} diff --git a/components/engine/vendor/github.com/opencontainers/runc/libcontainer/nsenter/nsexec.c b/components/engine/vendor/github.com/opencontainers/runc/libcontainer/nsenter/nsexec.c index 6814a5abbf..a6a107e6e6 100644 --- a/components/engine/vendor/github.com/opencontainers/runc/libcontainer/nsenter/nsexec.c +++ b/components/engine/vendor/github.com/opencontainers/runc/libcontainer/nsenter/nsexec.c @@ -1,3 +1,4 @@ + #define _GNU_SOURCE #include #include @@ -19,6 +20,8 @@ #include #include #include +#include + #include #include @@ -64,7 +67,13 @@ struct clone_t { struct nlconfig_t { char *data; + + /* Process settings. */ uint32_t cloneflags; + char *oom_score_adj; + size_t oom_score_adj_len; + + /* User namespace settings.*/ char *uidmap; size_t uidmap_len; char *gidmap; @@ -72,9 +81,13 @@ struct nlconfig_t { char *namespaces; size_t namespaces_len; uint8_t is_setgroup; + + /* Rootless container settings.*/ uint8_t is_rootless; - char *oom_score_adj; - size_t oom_score_adj_len; + char *uidmappath; + size_t uidmappath_len; + char *gidmappath; + size_t gidmappath_len; }; /* @@ -89,6 +102,8 @@ struct nlconfig_t { #define SETGROUP_ATTR 27285 #define OOM_SCORE_ADJ_ATTR 27286 #define ROOTLESS_ATTR 27287 +#define UIDMAPPATH_ATTR 27288 +#define GIDMAPPATH_ATTR 27289 /* * Use the raw syscall for versions of glibc which don't include a function for @@ -191,22 +206,96 @@ static void update_setgroups(int pid, enum policy_t setgroup) } } -static void update_uidmap(int pid, char *map, size_t map_len) +static int try_mapping_tool(const char *app, int pid, char *map, size_t map_len) { - if (map == NULL || map_len <= 0) - return; + int child; - if (write_file(map, map_len, "/proc/%d/uid_map", pid) < 0) - bail("failed to update /proc/%d/uid_map", pid); + /* + * If @app is NULL, execve will segfault. Just check it here and bail (if + * we're in this path, the caller is already getting desparate and there + * isn't a backup to this failing). This usually would be a configuration + * or programming issue. + */ + if (!app) + bail("mapping tool not present"); + + child = fork(); + if (child < 0) + bail("failed to fork"); + + if (!child) { +#define MAX_ARGV 20 + char *argv[MAX_ARGV]; + char *envp[] = {NULL}; + char pid_fmt[16]; + int argc = 0; + char *next; + + snprintf(pid_fmt, 16, "%d", pid); + + argv[argc++] = (char *) app; + argv[argc++] = pid_fmt; + /* + * Convert the map string into a list of argument that + * newuidmap/newgidmap can understand. + */ + + while (argc < MAX_ARGV) { + if (*map == '\0') { + argv[argc++] = NULL; + break; + } + argv[argc++] = map; + next = strpbrk(map, "\n "); + if (next == NULL) + break; + *next++ = '\0'; + map = next + strspn(next, "\n "); + } + + execve(app, argv, envp); + bail("failed to execv"); + } else { + int status; + + while (true) { + if (waitpid(child, &status, 0) < 0) { + if (errno == EINTR) + continue; + bail("failed to waitpid"); + } + if (WIFEXITED(status) || WIFSIGNALED(status)) + return WEXITSTATUS(status); + } + } + + return -1; } -static void update_gidmap(int pid, char *map, size_t map_len) +static void update_uidmap(const char *path, int pid, char *map, size_t map_len) { if (map == NULL || map_len <= 0) return; - if (write_file(map, map_len, "/proc/%d/gid_map", pid) < 0) - bail("failed to update /proc/%d/gid_map", pid); + if (write_file(map, map_len, "/proc/%d/uid_map", pid) < 0) { + if (errno != EPERM) + bail("failed to update /proc/%d/uid_map", pid); + if (try_mapping_tool(path, pid, map, map_len)) + bail("failed to use newuid map on %d", pid); + } +} + +static void update_gidmap(const char *path, int pid, char *map, size_t map_len) +{ + if (map == NULL || map_len <= 0) + return; + + if (write_file(map, map_len, "/proc/%d/gid_map", pid) < 0) { + if (errno != EPERM) + bail("failed to update /proc/%d/gid_map", pid); + if (try_mapping_tool(path, pid, map, map_len)) + bail("failed to use newgid map on %d", pid); + } } static void update_oom_score_adj(char *data, size_t len) @@ -350,6 +439,14 @@ static void nl_parse(int fd, struct nlconfig_t *config) config->gidmap = current; config->gidmap_len = payload_len; break; + case UIDMAPPATH_ATTR: + config->uidmappath = current; + config->uidmappath_len = payload_len; + break; + case GIDMAPPATH_ATTR: + config->gidmappath = current; + config->gidmappath_len = payload_len; + break; case SETGROUP_ATTR: config->is_setgroup = readint8(current); break; @@ -596,8 +693,8 @@ void nsexec(void) update_setgroups(child, SETGROUPS_DENY); /* Set up mappings. */ - update_uidmap(child, config.uidmap, config.uidmap_len); - update_gidmap(child, config.gidmap, config.gidmap_len); + update_uidmap(config.uidmappath, child, config.uidmap, config.uidmap_len); + update_gidmap(config.gidmappath, child, config.gidmap, config.gidmap_len); s = SYNC_USERMAP_ACK; if (write(syncfd, &s, sizeof(s)) != sizeof(s)) { diff --git a/components/engine/vendor/github.com/opencontainers/runc/vendor.conf b/components/engine/vendor/github.com/opencontainers/runc/vendor.conf index 9506b5c67c..1266ee485f 100644 --- a/components/engine/vendor/github.com/opencontainers/runc/vendor.conf +++ b/components/engine/vendor/github.com/opencontainers/runc/vendor.conf @@ -18,4 +18,8 @@ github.com/golang/protobuf 18c9bb3261723cd5401db4d0c9fbc5c3b6c70fe8 github.com/docker/docker 0f5c9d301b9b1cca66b3ea0f9dec3b5317d3686d github.com/docker/go-units v0.2.0 github.com/urfave/cli d53eb991652b1d438abdd34ce4bfa3ef1539108e -golang.org/x/sys 0e0164865330d5cf1c00247be08330bf96e2f87c https://github.com/golang/sys +golang.org/x/sys 7ddbeae9ae08c6a06a59597f0c9edbc5ff2444ce https://github.com/golang/sys + +# console dependencies +github.com/containerd/console 84eeaae905fa414d03e07bcd6c8d3f19e7cf180e +github.com/pkg/errors v0.8.0 From c4c68bf81941cf34a088d4ee2aa3404921156d1a Mon Sep 17 00:00:00 2001 From: Sebastiaan van Stijn Date: Tue, 26 Sep 2017 13:39:56 +0200 Subject: [PATCH 6/8] Replace uses of filters.Include() with filters.Contains() The `filters.Include()` method was deprecated in favor of `filters.Contains()` in 065118390a3ecaf0dbd2fa752d54d43f8f1e8ec6, but still used in various locations. This patch replaces uses of `filters.Include()` with `filters.Contains()`. Signed-off-by: Sebastiaan van Stijn Upstream-commit: 97c5ae25c4d857563acd1f3467afc760145b1d55 Component: engine --- .../engine/api/server/router/network/filter.go | 12 ++++++------ .../engine/api/types/filters/parse_test.go | 11 +++++++++++ components/engine/daemon/cluster/services.go | 2 +- components/engine/daemon/events/filter.go | 4 ++-- components/engine/daemon/images.go | 10 +++++----- components/engine/daemon/list.go | 16 ++++++++-------- components/engine/daemon/prune.go | 8 ++++---- components/engine/daemon/search.go | 12 ++++++------ components/engine/plugin/backend_linux.go | 4 ++-- 9 files changed, 45 insertions(+), 34 deletions(-) diff --git a/components/engine/api/server/router/network/filter.go b/components/engine/api/server/router/network/filter.go index 21fc828b8b..6a5fce6892 100644 --- a/components/engine/api/server/router/network/filter.go +++ b/components/engine/api/server/router/network/filter.go @@ -45,27 +45,27 @@ func filterNetworks(nws []types.NetworkResource, filter filters.Args) ([]types.N displayNet := []types.NetworkResource{} for _, nw := range nws { - if filter.Include("driver") { + if filter.Contains("driver") { if !filter.ExactMatch("driver", nw.Driver) { continue } } - if filter.Include("name") { + if filter.Contains("name") { if !filter.Match("name", nw.Name) { continue } } - if filter.Include("id") { + if filter.Contains("id") { if !filter.Match("id", nw.ID) { continue } } - if filter.Include("label") { + if filter.Contains("label") { if !filter.MatchKVList("label", nw.Labels) { continue } } - if filter.Include("scope") { + if filter.Contains("scope") { if !filter.ExactMatch("scope", nw.Scope) { continue } @@ -73,7 +73,7 @@ func filterNetworks(nws []types.NetworkResource, filter filters.Args) ([]types.N displayNet = append(displayNet, nw) } - if filter.Include("type") { + if filter.Contains("type") { typeNet := []types.NetworkResource{} errFilter := filter.WalkValues("type", func(fval string) error { passList, err := filterNetworkByType(displayNet, fval) diff --git a/components/engine/api/types/filters/parse_test.go b/components/engine/api/types/filters/parse_test.go index 5279054854..a0a4f2a8d5 100644 --- a/components/engine/api/types/filters/parse_test.go +++ b/components/engine/api/types/filters/parse_test.go @@ -337,6 +337,17 @@ func TestOnlyOneExactMatch(t *testing.T) { } } +func TestContains(t *testing.T) { + f := NewArgs() + if f.Contains("status") { + t.Fatal("Expected to not contain a status key, got true") + } + f.Add("status", "running") + if !f.Contains("status") { + t.Fatal("Expected to contain a status key, got false") + } +} + func TestInclude(t *testing.T) { f := NewArgs() if f.Include("status") { diff --git a/components/engine/daemon/cluster/services.go b/components/engine/daemon/cluster/services.go index 0edb407d3a..f3fba8d9d1 100644 --- a/components/engine/daemon/cluster/services.go +++ b/components/engine/daemon/cluster/services.go @@ -74,7 +74,7 @@ func (c *Cluster) GetServices(options apitypes.ServiceListOptions) ([]types.Serv services := make([]types.Service, 0, len(r.Services)) for _, service := range r.Services { - if options.Filters.Include("mode") { + if options.Filters.Contains("mode") { var mode string switch service.Spec.GetMode().(type) { case *swarmapi.ServiceSpec_Global: diff --git a/components/engine/daemon/events/filter.go b/components/engine/daemon/events/filter.go index 645f1ca917..ea6ce4d287 100644 --- a/components/engine/daemon/events/filter.go +++ b/components/engine/daemon/events/filter.go @@ -49,14 +49,14 @@ func (ef *Filter) filterContains(field string, values map[string]struct{}) bool } func (ef *Filter) matchScope(scope string) bool { - if !ef.filter.Include("scope") { + if !ef.filter.Contains("scope") { return true } return ef.filter.ExactMatch("scope", scope) } func (ef *Filter) matchLabels(attributes map[string]string) bool { - if !ef.filter.Include("label") { + if !ef.filter.Contains("label") { return true } return ef.filter.MatchKVList("label", attributes) diff --git a/components/engine/daemon/images.go b/components/engine/daemon/images.go index f4110ce789..27860d9b92 100644 --- a/components/engine/daemon/images.go +++ b/components/engine/daemon/images.go @@ -67,7 +67,7 @@ func (daemon *Daemon) Images(imageFilters filters.Args, all bool, withExtraAttrs return nil, err } - if imageFilters.Include("dangling") { + if imageFilters.Contains("dangling") { if imageFilters.ExactMatch("dangling", "true") { danglingOnly = true } else if !imageFilters.ExactMatch("dangling", "false") { @@ -116,7 +116,7 @@ func (daemon *Daemon) Images(imageFilters filters.Args, all bool, withExtraAttrs } } - if imageFilters.Include("label") { + if imageFilters.Contains("label") { // Very old image that do not have image.Config (or even labels) if img.Config == nil { continue @@ -150,7 +150,7 @@ func (daemon *Daemon) Images(imageFilters filters.Args, all bool, withExtraAttrs newImage := newImage(img, size) for _, ref := range daemon.referenceStore.References(id.Digest()) { - if imageFilters.Include("reference") { + if imageFilters.Contains("reference") { var found bool var matchErr error for _, pattern := range imageFilters.Get("reference") { @@ -173,11 +173,11 @@ func (daemon *Daemon) Images(imageFilters filters.Args, all bool, withExtraAttrs if newImage.RepoDigests == nil && newImage.RepoTags == nil { if all || len(daemon.stores[platform].imageStore.Children(id)) == 0 { - if imageFilters.Include("dangling") && !danglingOnly { + if imageFilters.Contains("dangling") && !danglingOnly { //dangling=false case, so dangling image is not needed continue } - if imageFilters.Include("reference") { // skip images with no references if filtering by reference + if imageFilters.Contains("reference") { // skip images with no references if filtering by reference continue } newImage.RepoDigests = []string{"@"} diff --git a/components/engine/daemon/list.go b/components/engine/daemon/list.go index b171ffb1b8..417f7b253d 100644 --- a/components/engine/daemon/list.go +++ b/components/engine/daemon/list.go @@ -276,7 +276,7 @@ func (daemon *Daemon) foldFilter(view container.View, config *types.ContainerLis } var taskFilter, isTask bool - if psFilters.Include("is-task") { + if psFilters.Contains("is-task") { if psFilters.ExactMatch("is-task", "true") { taskFilter = true isTask = true @@ -319,7 +319,7 @@ func (daemon *Daemon) foldFilter(view container.View, config *types.ContainerLis imagesFilter := map[image.ID]bool{} var ancestorFilter bool - if psFilters.Include("ancestor") { + if psFilters.Contains("ancestor") { ancestorFilter = true psFilters.WalkValues("ancestor", func(ancestor string) error { id, platform, err := daemon.GetImageIDAndPlatform(ancestor) @@ -465,7 +465,7 @@ func includeContainerInList(container *container.Snapshot, ctx *listContext) ite return excludeContainer } - if ctx.filters.Include("volume") { + if ctx.filters.Contains("volume") { volumesByName := make(map[string]types.MountPoint) for _, m := range container.Mounts { if m.Name != "" { @@ -509,7 +509,7 @@ func includeContainerInList(container *container.Snapshot, ctx *listContext) ite networkExist = errors.New("container part of network") noNetworks = errors.New("container is not part of any networks") ) - if ctx.filters.Include("network") { + if ctx.filters.Contains("network") { err := ctx.filters.WalkValues("network", func(value string) error { if container.NetworkSettings == nil { return noNetworks @@ -627,17 +627,17 @@ func (daemon *Daemon) filterVolumes(vols []volume.Volume, filter filters.Args) ( var retVols []volume.Volume for _, vol := range vols { - if filter.Include("name") { + if filter.Contains("name") { if !filter.Match("name", vol.Name()) { continue } } - if filter.Include("driver") { + if filter.Contains("driver") { if !filter.ExactMatch("driver", vol.DriverName()) { continue } } - if filter.Include("label") { + if filter.Contains("label") { v, ok := vol.(volume.DetailedVolume) if !ok { continue @@ -649,7 +649,7 @@ func (daemon *Daemon) filterVolumes(vols []volume.Volume, filter filters.Args) ( retVols = append(retVols, vol) } danglingOnly := false - if filter.Include("dangling") { + if filter.Contains("dangling") { if filter.ExactMatch("dangling", "true") || filter.ExactMatch("dangling", "1") { danglingOnly = true } else if !filter.ExactMatch("dangling", "false") && !filter.ExactMatch("dangling", "0") { diff --git a/components/engine/daemon/prune.go b/components/engine/daemon/prune.go index 66eca2b6e5..837cb83941 100644 --- a/components/engine/daemon/prune.go +++ b/components/engine/daemon/prune.go @@ -182,7 +182,7 @@ func (daemon *Daemon) ImagesPrune(ctx context.Context, pruneFilters filters.Args rep := &types.ImagesPruneReport{} danglingOnly := true - if pruneFilters.Include("dangling") { + if pruneFilters.Contains("dangling") { if pruneFilters.ExactMatch("dangling", "false") || pruneFilters.ExactMatch("dangling", "0") { danglingOnly = false } else if !pruneFilters.ExactMatch("dangling", "true") && !pruneFilters.ExactMatch("dangling", "1") { @@ -440,7 +440,7 @@ func (daemon *Daemon) NetworksPrune(ctx context.Context, pruneFilters filters.Ar func getUntilFromPruneFilters(pruneFilters filters.Args) (time.Time, error) { until := time.Time{} - if !pruneFilters.Include("until") { + if !pruneFilters.Contains("until") { return until, nil } untilFilters := pruneFilters.Get("until") @@ -464,8 +464,8 @@ func matchLabels(pruneFilters filters.Args, labels map[string]string) bool { return false } // By default MatchKVList will return true if field (like 'label!') does not exist - // So we have to add additional Include("label!") check - if pruneFilters.Include("label!") { + // So we have to add additional Contains("label!") check + if pruneFilters.Contains("label!") { if pruneFilters.MatchKVList("label!", labels) { return false } diff --git a/components/engine/daemon/search.go b/components/engine/daemon/search.go index 540e247fe4..45484f3a10 100644 --- a/components/engine/daemon/search.go +++ b/components/engine/daemon/search.go @@ -33,21 +33,21 @@ func (daemon *Daemon) SearchRegistryForImages(ctx context.Context, filtersArgs s var isAutomated, isOfficial bool var hasStarFilter = 0 - if searchFilters.Include("is-automated") { + if searchFilters.Contains("is-automated") { if searchFilters.UniqueExactMatch("is-automated", "true") { isAutomated = true } else if !searchFilters.UniqueExactMatch("is-automated", "false") { return nil, invalidFilter{"is-automated", searchFilters.Get("is-automated")} } } - if searchFilters.Include("is-official") { + if searchFilters.Contains("is-official") { if searchFilters.UniqueExactMatch("is-official", "true") { isOfficial = true } else if !searchFilters.UniqueExactMatch("is-official", "false") { return nil, invalidFilter{"is-official", searchFilters.Get("is-official")} } } - if searchFilters.Include("stars") { + if searchFilters.Contains("stars") { hasStars := searchFilters.Get("stars") for _, hasStar := range hasStars { iHasStar, err := strconv.Atoi(hasStar) @@ -67,17 +67,17 @@ func (daemon *Daemon) SearchRegistryForImages(ctx context.Context, filtersArgs s filteredResults := []registrytypes.SearchResult{} for _, result := range unfilteredResult.Results { - if searchFilters.Include("is-automated") { + if searchFilters.Contains("is-automated") { if isAutomated != result.IsAutomated { continue } } - if searchFilters.Include("is-official") { + if searchFilters.Contains("is-official") { if isOfficial != result.IsOfficial { continue } } - if searchFilters.Include("stars") { + if searchFilters.Contains("stars") { if result.StarCount < hasStarFilter { continue } diff --git a/components/engine/plugin/backend_linux.go b/components/engine/plugin/backend_linux.go index 8a31e97e51..66de6cb993 100644 --- a/components/engine/plugin/backend_linux.go +++ b/components/engine/plugin/backend_linux.go @@ -365,7 +365,7 @@ func (pm *Manager) List(pluginFilters filters.Args) ([]types.Plugin, error) { enabledOnly := false disabledOnly := false - if pluginFilters.Include("enabled") { + if pluginFilters.Contains("enabled") { if pluginFilters.ExactMatch("enabled", "true") { enabledOnly = true } else if pluginFilters.ExactMatch("enabled", "false") { @@ -386,7 +386,7 @@ next: if disabledOnly && p.PluginObj.Enabled { continue } - if pluginFilters.Include("capability") { + if pluginFilters.Contains("capability") { for _, f := range p.GetTypes() { if !pluginFilters.Match("capability", f.Capability) { continue next From 5dbfedf3f9439df12abdb5ef4449b26fb6d90cf9 Mon Sep 17 00:00:00 2001 From: Sebastiaan van Stijn Date: Tue, 26 Sep 2017 13:59:45 +0200 Subject: [PATCH 7/8] Replace uses of filters.ToParam(), FromParam() with filters.ToJSON(), FromJSON() `filters.ToParam()` and `filters.FromParam()` were deprecated in favor of `filters.ToJSON()` and `filters.FromJSON()` in 065118390a3ecaf0dbd2fa752d54d43f8f1e8ec6, but still used in various locations. This patch replaces uses of `filters.ToParam()` and `filters.FromParam()` with `filters.ToJSON()` and `filters.FromJSON()`. Signed-off-by: Sebastiaan van Stijn Upstream-commit: a4efe66cf2a7648dbcf5b9993bf351925b905b5b Component: engine --- .../server/router/container/container_routes.go | 4 ++-- .../engine/api/server/router/image/image_routes.go | 4 ++-- .../api/server/router/network/network_routes.go | 4 ++-- .../api/server/router/plugin/plugin_routes.go | 2 +- .../api/server/router/swarm/cluster_routes.go | 10 +++++----- .../api/server/router/system/system_routes.go | 2 +- .../api/server/router/volume/volume_routes.go | 2 +- components/engine/api/types/filters/parse_test.go | 14 +++++++------- components/engine/client/config_list.go | 2 +- components/engine/client/image_search.go | 2 +- components/engine/client/node_list.go | 2 +- components/engine/client/secret_list.go | 2 +- components/engine/client/service_list.go | 2 +- components/engine/client/task_list.go | 2 +- components/engine/client/utils.go | 2 +- components/engine/daemon/cluster/tasks.go | 6 +++--- components/engine/daemon/list.go | 2 +- components/engine/daemon/search.go | 2 +- .../integration-cli/docker_api_network_test.go | 2 +- 19 files changed, 34 insertions(+), 34 deletions(-) diff --git a/components/engine/api/server/router/container/container_routes.go b/components/engine/api/server/router/container/container_routes.go index 30fd3a15bf..95bbe0e533 100644 --- a/components/engine/api/server/router/container/container_routes.go +++ b/components/engine/api/server/router/container/container_routes.go @@ -28,7 +28,7 @@ func (s *containerRouter) getContainersJSON(ctx context.Context, w http.Response if err := httputils.ParseForm(r); err != nil { return err } - filter, err := filters.FromParam(r.Form.Get("filters")) + filter, err := filters.FromJSON(r.Form.Get("filters")) if err != nil { return err } @@ -588,7 +588,7 @@ func (s *containerRouter) postContainersPrune(ctx context.Context, w http.Respon return err } - pruneFilters, err := filters.FromParam(r.Form.Get("filters")) + pruneFilters, err := filters.FromJSON(r.Form.Get("filters")) if err != nil { return validationError{err} } diff --git a/components/engine/api/server/router/image/image_routes.go b/components/engine/api/server/router/image/image_routes.go index 86d73df0e1..7214f4eb7e 100644 --- a/components/engine/api/server/router/image/image_routes.go +++ b/components/engine/api/server/router/image/image_routes.go @@ -302,7 +302,7 @@ func (s *imageRouter) getImagesJSON(ctx context.Context, w http.ResponseWriter, return err } - imageFilters, err := filters.FromParam(r.Form.Get("filters")) + imageFilters, err := filters.FromJSON(r.Form.Get("filters")) if err != nil { return err } @@ -385,7 +385,7 @@ func (s *imageRouter) postImagesPrune(ctx context.Context, w http.ResponseWriter return err } - pruneFilters, err := filters.FromParam(r.Form.Get("filters")) + pruneFilters, err := filters.FromJSON(r.Form.Get("filters")) if err != nil { return err } diff --git a/components/engine/api/server/router/network/network_routes.go b/components/engine/api/server/router/network/network_routes.go index ad3e74e6eb..ebf4bf635e 100644 --- a/components/engine/api/server/router/network/network_routes.go +++ b/components/engine/api/server/router/network/network_routes.go @@ -37,7 +37,7 @@ func (n *networkRouter) getNetworksList(ctx context.Context, w http.ResponseWrit } filter := r.Form.Get("filters") - netFilters, err := filters.FromParam(filter) + netFilters, err := filters.FromJSON(filter) if err != nil { return err } @@ -489,7 +489,7 @@ func (n *networkRouter) postNetworksPrune(ctx context.Context, w http.ResponseWr return err } - pruneFilters, err := filters.FromParam(r.Form.Get("filters")) + pruneFilters, err := filters.FromJSON(r.Form.Get("filters")) if err != nil { return err } diff --git a/components/engine/api/server/router/plugin/plugin_routes.go b/components/engine/api/server/router/plugin/plugin_routes.go index 79e3cf5de8..d74a01f300 100644 --- a/components/engine/api/server/router/plugin/plugin_routes.go +++ b/components/engine/api/server/router/plugin/plugin_routes.go @@ -290,7 +290,7 @@ func (pr *pluginRouter) listPlugins(ctx context.Context, w http.ResponseWriter, return err } - pluginFilters, err := filters.FromParam(r.Form.Get("filters")) + pluginFilters, err := filters.FromJSON(r.Form.Get("filters")) if err != nil { return err } diff --git a/components/engine/api/server/router/swarm/cluster_routes.go b/components/engine/api/server/router/swarm/cluster_routes.go index 55743a6218..5b6c19d9c1 100644 --- a/components/engine/api/server/router/swarm/cluster_routes.go +++ b/components/engine/api/server/router/swarm/cluster_routes.go @@ -151,7 +151,7 @@ func (sr *swarmRouter) getServices(ctx context.Context, w http.ResponseWriter, r if err := httputils.ParseForm(r); err != nil { return err } - filter, err := filters.FromParam(r.Form.Get("filters")) + filter, err := filters.FromJSON(r.Form.Get("filters")) if err != nil { return invalidRequestError{err} } @@ -277,7 +277,7 @@ func (sr *swarmRouter) getNodes(ctx context.Context, w http.ResponseWriter, r *h if err := httputils.ParseForm(r); err != nil { return err } - filter, err := filters.FromParam(r.Form.Get("filters")) + filter, err := filters.FromJSON(r.Form.Get("filters")) if err != nil { return err } @@ -339,7 +339,7 @@ func (sr *swarmRouter) getTasks(ctx context.Context, w http.ResponseWriter, r *h if err := httputils.ParseForm(r); err != nil { return err } - filter, err := filters.FromParam(r.Form.Get("filters")) + filter, err := filters.FromJSON(r.Form.Get("filters")) if err != nil { return err } @@ -367,7 +367,7 @@ func (sr *swarmRouter) getSecrets(ctx context.Context, w http.ResponseWriter, r if err := httputils.ParseForm(r); err != nil { return err } - filters, err := filters.FromParam(r.Form.Get("filters")) + filters, err := filters.FromJSON(r.Form.Get("filters")) if err != nil { return err } @@ -434,7 +434,7 @@ func (sr *swarmRouter) getConfigs(ctx context.Context, w http.ResponseWriter, r if err := httputils.ParseForm(r); err != nil { return err } - filters, err := filters.FromParam(r.Form.Get("filters")) + filters, err := filters.FromJSON(r.Form.Get("filters")) if err != nil { return err } diff --git a/components/engine/api/server/router/system/system_routes.go b/components/engine/api/server/router/system/system_routes.go index 5884388ebe..62060a4ccf 100644 --- a/components/engine/api/server/router/system/system_routes.go +++ b/components/engine/api/server/router/system/system_routes.go @@ -127,7 +127,7 @@ func (s *systemRouter) getEvents(ctx context.Context, w http.ResponseWriter, r * } } - ef, err := filters.FromParam(r.Form.Get("filters")) + ef, err := filters.FromJSON(r.Form.Get("filters")) if err != nil { return err } diff --git a/components/engine/api/server/router/volume/volume_routes.go b/components/engine/api/server/router/volume/volume_routes.go index f0f490119b..bfff51ab1e 100644 --- a/components/engine/api/server/router/volume/volume_routes.go +++ b/components/engine/api/server/router/volume/volume_routes.go @@ -72,7 +72,7 @@ func (v *volumeRouter) postVolumesPrune(ctx context.Context, w http.ResponseWrit return err } - pruneFilters, err := filters.FromParam(r.Form.Get("filters")) + pruneFilters, err := filters.FromJSON(r.Form.Get("filters")) if err != nil { return err } diff --git a/components/engine/api/types/filters/parse_test.go b/components/engine/api/types/filters/parse_test.go index a0a4f2a8d5..67b2ec930c 100644 --- a/components/engine/api/types/filters/parse_test.go +++ b/components/engine/api/types/filters/parse_test.go @@ -42,14 +42,14 @@ func TestParseArgsEdgeCase(t *testing.T) { } } -func TestToParam(t *testing.T) { +func TestToJSON(t *testing.T) { fields := map[string]map[string]bool{ "created": {"today": true}, "image.name": {"ubuntu*": true, "*untu": true}, } a := Args{fields: fields} - _, err := ToParam(a) + _, err := ToJSON(a) if err != nil { t.Errorf("failed to marshal the filters: %s", err) } @@ -80,7 +80,7 @@ func TestToParamWithVersion(t *testing.T) { } } -func TestFromParam(t *testing.T) { +func TestFromJSON(t *testing.T) { invalids := []string{ "anything", "['a','list']", @@ -103,14 +103,14 @@ func TestFromParam(t *testing.T) { } for _, invalid := range invalids { - if _, err := FromParam(invalid); err == nil { + if _, err := FromJSON(invalid); err == nil { t.Fatalf("Expected an error with %v, got nothing", invalid) } } for expectedArgs, matchers := range valid { for _, json := range matchers { - args, err := FromParam(json) + args, err := FromJSON(json) if err != nil { t.Fatal(err) } @@ -136,11 +136,11 @@ func TestFromParam(t *testing.T) { func TestEmpty(t *testing.T) { a := Args{} - v, err := ToParam(a) + v, err := ToJSON(a) if err != nil { t.Errorf("failed to marshal the filters: %s", err) } - v1, err := FromParam(v) + v1, err := FromJSON(v) if err != nil { t.Errorf("%s", err) } diff --git a/components/engine/client/config_list.go b/components/engine/client/config_list.go index 8483ca14d1..57febc9ffb 100644 --- a/components/engine/client/config_list.go +++ b/components/engine/client/config_list.go @@ -18,7 +18,7 @@ func (cli *Client) ConfigList(ctx context.Context, options types.ConfigListOptio query := url.Values{} if options.Filters.Len() > 0 { - filterJSON, err := filters.ToParam(options.Filters) + filterJSON, err := filters.ToJSON(options.Filters) if err != nil { return nil, err } diff --git a/components/engine/client/image_search.go b/components/engine/client/image_search.go index b0fcd5c23d..5566e92555 100644 --- a/components/engine/client/image_search.go +++ b/components/engine/client/image_search.go @@ -21,7 +21,7 @@ func (cli *Client) ImageSearch(ctx context.Context, term string, options types.I query.Set("limit", fmt.Sprintf("%d", options.Limit)) if options.Filters.Len() > 0 { - filterJSON, err := filters.ToParam(options.Filters) + filterJSON, err := filters.ToJSON(options.Filters) if err != nil { return results, err } diff --git a/components/engine/client/node_list.go b/components/engine/client/node_list.go index 3e8440f08e..fed22992c9 100644 --- a/components/engine/client/node_list.go +++ b/components/engine/client/node_list.go @@ -15,7 +15,7 @@ func (cli *Client) NodeList(ctx context.Context, options types.NodeListOptions) query := url.Values{} if options.Filters.Len() > 0 { - filterJSON, err := filters.ToParam(options.Filters) + filterJSON, err := filters.ToJSON(options.Filters) if err != nil { return nil, err diff --git a/components/engine/client/secret_list.go b/components/engine/client/secret_list.go index 0d33ecfbc9..fdee6e2e0b 100644 --- a/components/engine/client/secret_list.go +++ b/components/engine/client/secret_list.go @@ -18,7 +18,7 @@ func (cli *Client) SecretList(ctx context.Context, options types.SecretListOptio query := url.Values{} if options.Filters.Len() > 0 { - filterJSON, err := filters.ToParam(options.Filters) + filterJSON, err := filters.ToJSON(options.Filters) if err != nil { return nil, err } diff --git a/components/engine/client/service_list.go b/components/engine/client/service_list.go index c29e6d407d..eb3ff9739c 100644 --- a/components/engine/client/service_list.go +++ b/components/engine/client/service_list.go @@ -15,7 +15,7 @@ func (cli *Client) ServiceList(ctx context.Context, options types.ServiceListOpt query := url.Values{} if options.Filters.Len() > 0 { - filterJSON, err := filters.ToParam(options.Filters) + filterJSON, err := filters.ToJSON(options.Filters) if err != nil { return nil, err } diff --git a/components/engine/client/task_list.go b/components/engine/client/task_list.go index 66324da959..01bd695257 100644 --- a/components/engine/client/task_list.go +++ b/components/engine/client/task_list.go @@ -15,7 +15,7 @@ func (cli *Client) TaskList(ctx context.Context, options types.TaskListOptions) query := url.Values{} if options.Filters.Len() > 0 { - filterJSON, err := filters.ToParam(options.Filters) + filterJSON, err := filters.ToJSON(options.Filters) if err != nil { return nil, err } diff --git a/components/engine/client/utils.go b/components/engine/client/utils.go index f3d8877df7..137705065c 100644 --- a/components/engine/client/utils.go +++ b/components/engine/client/utils.go @@ -24,7 +24,7 @@ func getDockerOS(serverHeader string) string { func getFiltersQuery(f filters.Args) (url.Values, error) { query := url.Values{} if f.Len() > 0 { - filterJSON, err := filters.ToParam(f) + filterJSON, err := filters.ToJSON(f) if err != nil { return query, err } diff --git a/components/engine/daemon/cluster/tasks.go b/components/engine/daemon/cluster/tasks.go index 26706a2fa5..f52301fe47 100644 --- a/components/engine/daemon/cluster/tasks.go +++ b/components/engine/daemon/cluster/tasks.go @@ -15,7 +15,7 @@ func (c *Cluster) GetTasks(options apitypes.TaskListOptions) ([]types.Task, erro if err := c.lockedManagerAction(func(ctx context.Context, state nodeState) error { filterTransform := func(filter filters.Args) error { - if filter.Include("service") { + if filter.Contains("service") { serviceFilters := filter.Get("service") for _, serviceFilter := range serviceFilters { service, err := getService(ctx, state.controlClient, serviceFilter, false) @@ -26,7 +26,7 @@ func (c *Cluster) GetTasks(options apitypes.TaskListOptions) ([]types.Task, erro filter.Add("service", service.ID) } } - if filter.Include("node") { + if filter.Contains("node") { nodeFilters := filter.Get("node") for _, nodeFilter := range nodeFilters { node, err := getNode(ctx, state.controlClient, nodeFilter) @@ -37,7 +37,7 @@ func (c *Cluster) GetTasks(options apitypes.TaskListOptions) ([]types.Task, erro filter.Add("node", node.ID) } } - if !filter.Include("runtime") { + if !filter.Contains("runtime") { // default to only showing container tasks filter.Add("runtime", "container") filter.Add("runtime", "") diff --git a/components/engine/daemon/list.go b/components/engine/daemon/list.go index 417f7b253d..9d43be2720 100644 --- a/components/engine/daemon/list.go +++ b/components/engine/daemon/list.go @@ -585,7 +585,7 @@ func (daemon *Daemon) Volumes(filter string) ([]*types.Volume, []string, error) var ( volumesOut []*types.Volume ) - volFilters, err := filters.FromParam(filter) + volFilters, err := filters.FromJSON(filter) if err != nil { return nil, nil, err } diff --git a/components/engine/daemon/search.go b/components/engine/daemon/search.go index 45484f3a10..25744cb723 100644 --- a/components/engine/daemon/search.go +++ b/components/engine/daemon/search.go @@ -23,7 +23,7 @@ func (daemon *Daemon) SearchRegistryForImages(ctx context.Context, filtersArgs s authConfig *types.AuthConfig, headers map[string][]string) (*registrytypes.SearchResults, error) { - searchFilters, err := filters.FromParam(filtersArgs) + searchFilters, err := filters.FromJSON(filtersArgs) if err != nil { return nil, err } diff --git a/components/engine/integration-cli/docker_api_network_test.go b/components/engine/integration-cli/docker_api_network_test.go index a49fbae3d4..108dd4c6ac 100644 --- a/components/engine/integration-cli/docker_api_network_test.go +++ b/components/engine/integration-cli/docker_api_network_test.go @@ -282,7 +282,7 @@ func getNetworkIDByName(c *check.C, name string) string { filterArgs = filters.NewArgs() ) filterArgs.Add("name", name) - filterJSON, err := filters.ToParam(filterArgs) + filterJSON, err := filters.ToJSON(filterArgs) c.Assert(err, checker.IsNil) v.Set("filters", filterJSON) From 2a54e5d16eab48d97698cf254fc29ec7b6ce467b Mon Sep 17 00:00:00 2001 From: Allen Sun Date: Sat, 23 Sep 2017 12:08:38 +0800 Subject: [PATCH 8/8] add node/service/secret/config specific event filter Signed-off-by: Allen Sun Upstream-commit: 4611ecd3cdc9b2738f58a136b79f752add223f3f Component: engine --- components/engine/api/swagger.yaml | 8 ++++++-- components/engine/daemon/events/filter.go | 4 ++++ components/engine/docs/api/version-history.md | 3 ++- 3 files changed, 12 insertions(+), 3 deletions(-) diff --git a/components/engine/api/swagger.yaml b/components/engine/api/swagger.yaml index 275c2e9cec..afec91e72a 100644 --- a/components/engine/api/swagger.yaml +++ b/components/engine/api/swagger.yaml @@ -6941,16 +6941,20 @@ paths: description: | A JSON encoded value of filters (a `map[string][]string`) to process on the event list. Available filters: + - `config=` config name or ID - `container=` container name or ID - `daemon=` daemon name or ID - `event=` event type - `image=` image name or ID - `label=` image or container label - `network=` network name or ID + - `node=` node ID - `plugin`= plugin name or ID - `scope`= local or swarm - - `type=` object to filter by, one of `container`, `image`, `volume`, `network`, `daemon`, `plugin`, `node`, `service` or `secret` - - `volume=` volume name or ID + - `secret=` secret name or ID + - `service=` service name or ID + - `type=` object to filter by, one of `container`, `image`, `volume`, `network`, `daemon`, `plugin`, `node`, `service`, `secret` or `config` + - `volume=` volume name type: "string" tags: ["System"] /system/df: diff --git a/components/engine/daemon/events/filter.go b/components/engine/daemon/events/filter.go index 645f1ca917..5a3163deda 100644 --- a/components/engine/daemon/events/filter.go +++ b/components/engine/daemon/events/filter.go @@ -27,6 +27,10 @@ func (ef *Filter) Include(ev events.Message) bool { ef.matchVolume(ev) && ef.matchNetwork(ev) && ef.matchImage(ev) && + ef.matchNode(ev) && + ef.matchService(ev) && + ef.matchSecret(ev) && + ef.matchConfig(ev) && ef.matchLabels(ev.Actor.Attributes) } diff --git a/components/engine/docs/api/version-history.md b/components/engine/docs/api/version-history.md index 1144e95447..a8507ce465 100644 --- a/components/engine/docs/api/version-history.md +++ b/components/engine/docs/api/version-history.md @@ -18,7 +18,8 @@ keywords: "API, Docker, rcli, REST, documentation" [Docker Engine API v1.33](https://docs.docker.com/engine/api/v1.33/) documentation - +* `GET /events` now supports filtering 4 more kinds of events: `config`, `node`, +`secret` and `service`. ## v1.32 API changes