diff --git a/components/engine/hack/vendor.sh b/components/engine/hack/vendor.sh index 3036b638b0..003dfec59b 100755 --- a/components/engine/hack/vendor.sh +++ b/components/engine/hack/vendor.sh @@ -45,8 +45,6 @@ clone git github.com/gorilla/context 14f550f51a clone git github.com/gorilla/mux 136d54f81f -clone git github.com/syndtr/gocapability 3c85049eae - clone git github.com/tchap/go-patricia v1.0.1 clone hg code.google.com/p/go.net 84a4013f96e0 @@ -61,6 +59,8 @@ rm -rf src/code.google.com/p/go mkdir -p src/code.google.com/p/go/src/pkg/archive mv tmp-tar src/code.google.com/p/go/src/pkg/archive/tar -clone git github.com/godbus/dbus v1 -clone git github.com/coreos/go-systemd v2 -clone git github.com/docker/libcontainer 68ea1234a0b046803aacb2562df0da12eec2b2f9 +clone git github.com/docker/libcontainer 5589d4d879f1d7e31967a927d3e8b98144fbe06b +# see src/github.com/docker/libcontainer/update-vendor.sh which is the "source of truth" for libcontainer deps (just like this file) +rm -rf src/github.com/docker/libcontainer/vendor +eval "$(grep '^clone ' src/github.com/docker/libcontainer/update-vendor.sh | grep -v 'github.com/codegangsta/cli')" +# we exclude "github.com/codegangsta/cli" here because it's only needed for "nsinit", which Docker doesn't include diff --git a/components/engine/vendor/src/github.com/docker/libcontainer/.travis.yml b/components/engine/vendor/src/github.com/docker/libcontainer/.travis.yml index 331227af01..3ce0e27e45 100644 --- a/components/engine/vendor/src/github.com/docker/libcontainer/.travis.yml +++ b/components/engine/vendor/src/github.com/docker/libcontainer/.travis.yml @@ -13,13 +13,15 @@ env: - _GOOS=linux _GOARCH=arm CGO_ENABLED=0 install: + - go get code.google.com/p/go.tools/cmd/cover - mkdir -pv "${GOPATH%%:*}/src/github.com/docker" && [ -d "${GOPATH%%:*}/src/github.com/docker/libcontainer" ] || ln -sv "$(readlink -f .)" "${GOPATH%%:*}/src/github.com/docker/libcontainer" - if [ -z "$TRAVIS_GLOBAL_WTF" ]; then gvm cross "$_GOOS" "$_GOARCH"; export GOOS="$_GOOS" GOARCH="$_GOARCH"; fi + - export GOPATH="$GOPATH:$(pwd)/vendor" - if [ -z "$TRAVIS_GLOBAL_WTF" ]; then go env; fi - - go get -d -v ./... + - go get -d -v ./... # TODO remove this if /docker/docker gets purged from our includes - if [ "$TRAVIS_GLOBAL_WTF" ]; then export DOCKER_PATH="${GOPATH%%:*}/src/github.com/docker/docker"; mkdir -p "$DOCKER_PATH/hack/make"; @@ -30,5 +32,5 @@ install: script: - if [ "$TRAVIS_GLOBAL_WTF" ]; then bash "$DOCKER_PATH/hack/make/validate-dco"; fi - if [ "$TRAVIS_GLOBAL_WTF" ]; then bash "$DOCKER_PATH/hack/make/validate-gofmt"; fi - - if [ -z "$TRAVIS_GLOBAL_WTF" ]; then go build -v ./...; fi - - if [ -z "$TRAVIS_GLOBAL_WTF" -a "$GOARCH" != 'arm' ]; then go test -test.short -v ./...; fi + - if [ -z "$TRAVIS_GLOBAL_WTF" ]; then make direct-build; fi + - if [ -z "$TRAVIS_GLOBAL_WTF" -a "$GOARCH" != 'arm' ]; then make direct-test-short; fi diff --git a/components/engine/vendor/src/github.com/docker/libcontainer/Dockerfile b/components/engine/vendor/src/github.com/docker/libcontainer/Dockerfile index 1fbba3e531..65bf5731d2 100644 --- a/components/engine/vendor/src/github.com/docker/libcontainer/Dockerfile +++ b/components/engine/vendor/src/github.com/docker/libcontainer/Dockerfile @@ -1,6 +1,6 @@ FROM crosbymichael/golang -RUN apt-get update && apt-get install -y gcc +RUN apt-get update && apt-get install -y gcc make RUN go get code.google.com/p/go.tools/cmd/cover # setup a playground for us to spawn containers in @@ -14,8 +14,10 @@ COPY . /go/src/github.com/docker/libcontainer WORKDIR /go/src/github.com/docker/libcontainer RUN cp sample_configs/minimal.json /busybox/container.json +ENV GOPATH $GOPATH:/go/src/github.com/docker/libcontainer/vendor + RUN go get -d -v ./... -RUN go install -v ./... +RUN make direct-install ENTRYPOINT ["/dind"] -CMD ["go", "test", "-cover", "./..."] +CMD ["make", "direct-test"] diff --git a/components/engine/vendor/src/github.com/docker/libcontainer/MAINTAINERS b/components/engine/vendor/src/github.com/docker/libcontainer/MAINTAINERS index 8c36d096c1..798d3ca6bf 100644 --- a/components/engine/vendor/src/github.com/docker/libcontainer/MAINTAINERS +++ b/components/engine/vendor/src/github.com/docker/libcontainer/MAINTAINERS @@ -2,3 +2,4 @@ Michael Crosby (@crosbymichael) Rohit Jnagal (@rjnagal) Victor Marmol (@vmarmol) .travis.yml: Tianon Gravi (@tianon) +update-vendor.sh: Tianon Gravi (@tianon) diff --git a/components/engine/vendor/src/github.com/docker/libcontainer/Makefile b/components/engine/vendor/src/github.com/docker/libcontainer/Makefile index 843b761eda..f7b3031bbd 100644 --- a/components/engine/vendor/src/github.com/docker/libcontainer/Makefile +++ b/components/engine/vendor/src/github.com/docker/libcontainer/Makefile @@ -4,7 +4,21 @@ all: test: # we need NET_ADMIN for the netlink tests and SYS_ADMIN for mounting - docker run --rm --cap-add NET_ADMIN --cap-add SYS_ADMIN docker/libcontainer + docker run --rm -it --cap-add NET_ADMIN --cap-add SYS_ADMIN docker/libcontainer sh: - docker run --rm -ti -w /busybox --rm --cap-add NET_ADMIN --cap-add SYS_ADMIN docker/libcontainer nsinit exec sh + docker run --rm -it --cap-add NET_ADMIN --cap-add SYS_ADMIN -w /busybox docker/libcontainer nsinit exec sh + +GO_PACKAGES = $(shell find . -not \( -wholename ./vendor -prune \) -name '*.go' -print0 | xargs -0n1 dirname | sort -u) + +direct-test: + go test -cover -v $(GO_PACKAGES) + +direct-test-short: + go test -cover -test.short -v $(GO_PACKAGES) + +direct-build: + go build -v $(GO_PACKAGES) + +direct-install: + go install -v $(GO_PACKAGES) diff --git a/components/engine/vendor/src/github.com/docker/libcontainer/cgroups/cgutil/cgutil.go b/components/engine/vendor/src/github.com/docker/libcontainer/cgroups/cgutil/cgutil.go index f4a541eab2..d1a66117f1 100644 --- a/components/engine/vendor/src/github.com/docker/libcontainer/cgroups/cgutil/cgutil.go +++ b/components/engine/vendor/src/github.com/docker/libcontainer/cgroups/cgutil/cgutil.go @@ -18,8 +18,8 @@ var createCommand = cli.Command{ Name: "create", Usage: "Create a cgroup container using the supplied configuration and initial process.", Flags: []cli.Flag{ - cli.StringFlag{"config, c", "cgroup.json", "path to container configuration (cgroups.Cgroup object)"}, - cli.IntFlag{"pid, p", 0, "pid of the initial process in the container"}, + cli.StringFlag{Name: "config, c", Value: "cgroup.json", Usage: "path to container configuration (cgroups.Cgroup object)"}, + cli.IntFlag{Name: "pid, p", Value: 0, Usage: "pid of the initial process in the container"}, }, Action: createAction, } @@ -28,8 +28,8 @@ var destroyCommand = cli.Command{ Name: "destroy", Usage: "Destroy an existing cgroup container.", Flags: []cli.Flag{ - cli.StringFlag{"name, n", "", "container name"}, - cli.StringFlag{"parent, p", "", "container parent"}, + cli.StringFlag{Name: "name, n", Value: "", Usage: "container name"}, + cli.StringFlag{Name: "parent, p", Value: "", Usage: "container parent"}, }, Action: destroyAction, } @@ -38,8 +38,8 @@ var statsCommand = cli.Command{ Name: "stats", Usage: "Get stats for cgroup", Flags: []cli.Flag{ - cli.StringFlag{"name, n", "", "container name"}, - cli.StringFlag{"parent, p", "", "container parent"}, + cli.StringFlag{Name: "name, n", Value: "", Usage: "container name"}, + cli.StringFlag{Name: "parent, p", Value: "", Usage: "container parent"}, }, Action: statsAction, } @@ -48,8 +48,8 @@ var pauseCommand = cli.Command{ Name: "pause", Usage: "Pause cgroup", Flags: []cli.Flag{ - cli.StringFlag{"name, n", "", "container name"}, - cli.StringFlag{"parent, p", "", "container parent"}, + cli.StringFlag{Name: "name, n", Value: "", Usage: "container name"}, + cli.StringFlag{Name: "parent, p", Value: "", Usage: "container parent"}, }, Action: pauseAction, } @@ -58,8 +58,8 @@ var resumeCommand = cli.Command{ Name: "resume", Usage: "Resume a paused cgroup", Flags: []cli.Flag{ - cli.StringFlag{"name, n", "", "container name"}, - cli.StringFlag{"parent, p", "", "container parent"}, + cli.StringFlag{Name: "name, n", Value: "", Usage: "container name"}, + cli.StringFlag{Name: "parent, p", Value: "", Usage: "container parent"}, }, Action: resumeAction, } @@ -68,8 +68,8 @@ var psCommand = cli.Command{ Name: "ps", Usage: "Get list of pids for a cgroup", Flags: []cli.Flag{ - cli.StringFlag{"name, n", "", "container name"}, - cli.StringFlag{"parent, p", "", "container parent"}, + cli.StringFlag{Name: "name, n", Value: "", Usage: "container name"}, + cli.StringFlag{Name: "parent, p", Value: "", Usage: "container parent"}, }, Action: psAction, } diff --git a/components/engine/vendor/src/github.com/docker/libcontainer/namespaces/execin.go b/components/engine/vendor/src/github.com/docker/libcontainer/namespaces/execin.go index 3a385cb77f..369431e84e 100644 --- a/components/engine/vendor/src/github.com/docker/libcontainer/namespaces/execin.go +++ b/components/engine/vendor/src/github.com/docker/libcontainer/namespaces/execin.go @@ -4,52 +4,18 @@ package namespaces import ( "encoding/json" + "os" + "strconv" + "github.com/docker/libcontainer" "github.com/docker/libcontainer/label" "github.com/docker/libcontainer/system" - "io" - "os" - "os/exec" - "strconv" - "syscall" ) -// Runs the command under 'args' inside an existing container referred to by 'container'. -// Returns the exitcode of the command upon success and appropriate error on failure. -func RunIn(container *libcontainer.Config, state *libcontainer.State, args []string, nsinitPath string, stdin io.Reader, stdout, stderr io.Writer, console string, startCallback func(*exec.Cmd)) (int, error) { - initArgs, err := getNsEnterCommand(strconv.Itoa(state.InitPid), container, console, args) - if err != nil { - return -1, err - } - - cmd := exec.Command(nsinitPath, initArgs...) - // Note: these are only used in non-tty mode - // if there is a tty for the container it will be opened within the namespace and the - // fds will be duped to stdin, stdiout, and stderr - cmd.Stdin = stdin - cmd.Stdout = stdout - cmd.Stderr = stderr - - if err := cmd.Start(); err != nil { - return -1, err - } - if startCallback != nil { - startCallback(cmd) - } - - if err := cmd.Wait(); err != nil { - if _, ok := err.(*exec.ExitError); !ok { - return -1, err - } - } - - return cmd.ProcessState.Sys().(syscall.WaitStatus).ExitStatus(), nil -} - // ExecIn uses an existing pid and joins the pid's namespaces with the new command. func ExecIn(container *libcontainer.Config, state *libcontainer.State, args []string) error { // Enter the namespace and then finish setup - args, err := getNsEnterCommand(strconv.Itoa(state.InitPid), container, "", args) + args, err := GetNsEnterCommand(strconv.Itoa(state.InitPid), container, "", args) if err != nil { return err } @@ -73,14 +39,13 @@ func getContainerJson(container *libcontainer.Config) (string, error) { return string(containerJson), nil } -func getNsEnterCommand(initPid string, container *libcontainer.Config, console string, args []string) ([]string, error) { +func GetNsEnterCommand(initPid string, container *libcontainer.Config, console string, args []string) ([]string, error) { containerJson, err := getContainerJson(container) if err != nil { return nil, err } out := []string{ - "nsenter", "--nspid", initPid, "--containerjson", containerJson, } @@ -88,6 +53,7 @@ func getNsEnterCommand(initPid string, container *libcontainer.Config, console s if console != "" { out = append(out, "--console", console) } + out = append(out, "nsenter") out = append(out, "--") out = append(out, args...) diff --git a/components/engine/vendor/src/github.com/docker/libcontainer/namespaces/nsenter.c b/components/engine/vendor/src/github.com/docker/libcontainer/namespaces/nsenter.c new file mode 100644 index 0000000000..28be5ff889 --- /dev/null +++ b/components/engine/vendor/src/github.com/docker/libcontainer/namespaces/nsenter.c @@ -0,0 +1,235 @@ +// +build cgo +// +// formated with indent -linux nsenter.c + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static const kBufSize = 256; +static const char *kNsEnter = "nsenter"; + +void get_args(int *argc, char ***argv) +{ + // Read argv + int fd = open("/proc/self/cmdline", O_RDONLY); + + // Read the whole commandline. + ssize_t contents_size = 0; + ssize_t contents_offset = 0; + char *contents = NULL; + ssize_t bytes_read = 0; + do { + contents_size += kBufSize; + contents = (char *)realloc(contents, contents_size); + bytes_read = + read(fd, contents + contents_offset, + contents_size - contents_offset); + contents_offset += bytes_read; + } + while (bytes_read > 0); + close(fd); + + // Parse the commandline into an argv. /proc/self/cmdline has \0 delimited args. + ssize_t i; + *argc = 0; + for (i = 0; i < contents_offset; i++) { + if (contents[i] == '\0') { + (*argc)++; + } + } + *argv = (char **)malloc(sizeof(char *) * ((*argc) + 1)); + int idx; + for (idx = 0; idx < (*argc); idx++) { + (*argv)[idx] = contents; + contents += strlen(contents) + 1; + } + (*argv)[*argc] = NULL; +} + +// Use raw setns syscall for versions of glibc that don't include it (namely glibc-2.12) +#if __GLIBC__ == 2 && __GLIBC_MINOR__ < 14 +#define _GNU_SOURCE +#include +#include "syscall.h" +#ifdef SYS_setns +int setns(int fd, int nstype) +{ + return syscall(SYS_setns, fd, nstype); +} +#endif +#endif + +void print_usage() +{ + fprintf(stderr, + " nsenter --nspid --containerjson -- cmd1 arg1 arg2...\n"); +} + +void nsenter() +{ + int argc, c; + char **argv; + get_args(&argc, &argv); + + // Ignore if this is not for us. + if (argc < 6) { + return; + } + int found_nsenter = 0; + for (c = 0; c < argc; ++c) { + if (strcmp(argv[c], kNsEnter) == 0) { + found_nsenter = 1; + break; + } + } + if (!found_nsenter) { + return; + } + static const struct option longopts[] = { + {"nspid", required_argument, NULL, 'n'}, + {"containerjson", required_argument, NULL, 'c'}, + {"console", optional_argument, NULL, 't'}, + {NULL, 0, NULL, 0} + }; + + pid_t init_pid = -1; + char *init_pid_str = NULL; + char *container_json = NULL; + char *console = NULL; + opterr = 0; + while ((c = + getopt_long_only(argc, argv, "-n:s:c:", longopts, + NULL)) != -1) { + switch (c) { + case 'n': + init_pid_str = optarg; + break; + case 'c': + container_json = optarg; + break; + case 't': + console = optarg; + break; + } + } + + if (strcmp(argv[optind - 2], kNsEnter) != 0) { + return; + } + + if (container_json == NULL || init_pid_str == NULL) { + print_usage(); + exit(1); + } + + init_pid = strtol(init_pid_str, NULL, 10); + if ((init_pid == 0 && errno == EINVAL) || errno == ERANGE) { + fprintf(stderr, + "nsenter: Failed to parse PID from \"%s\" with output \"%d\" and error: \"%s\"\n", + init_pid_str, init_pid, strerror(errno)); + print_usage(); + exit(1); + } + + argc -= 3; + argv += 3; + + if (setsid() == -1) { + fprintf(stderr, "setsid failed. Error: %s\n", strerror(errno)); + exit(1); + } + // before we setns we need to dup the console + int consolefd = -1; + if (console != NULL) { + consolefd = open(console, O_RDWR); + if (consolefd < 0) { + fprintf(stderr, + "nsenter: failed to open console %s %s\n", + console, strerror(errno)); + exit(1); + } + } + // Setns on all supported namespaces. + char ns_dir[PATH_MAX]; + memset(ns_dir, 0, PATH_MAX); + snprintf(ns_dir, PATH_MAX - 1, "/proc/%d/ns/", init_pid); + + char *namespaces[] = { "ipc", "uts", "net", "pid", "mnt" }; + const int num = sizeof(namespaces) / sizeof(char *); + int i; + for (i = 0; i < num; i++) { + char buf[PATH_MAX]; + memset(buf, 0, PATH_MAX); + snprintf(buf, PATH_MAX - 1, "%s%s", ns_dir, namespaces[i]); + int fd = open(buf, O_RDONLY); + if (fd == -1) { + // Ignore nonexistent namespaces. + if (errno == ENOENT) + continue; + + fprintf(stderr, + "nsenter: Failed to open ns file \"%s\" for ns \"%s\" with error: \"%s\"\n", + buf, namespaces[i], strerror(errno)); + exit(1); + } + // Set the namespace. + if (setns(fd, 0) == -1) { + fprintf(stderr, + "nsenter: Failed to setns for \"%s\" with error: \"%s\"\n", + namespaces[i], strerror(errno)); + exit(1); + } + close(fd); + } + + // We must fork to actually enter the PID namespace. + int child = fork(); + if (child == 0) { + if (consolefd != -1) { + if (dup2(consolefd, STDIN_FILENO) != 0) { + fprintf(stderr, "nsenter: failed to dup 0 %s\n", + strerror(errno)); + exit(1); + } + if (dup2(consolefd, STDOUT_FILENO) != STDOUT_FILENO) { + fprintf(stderr, "nsenter: failed to dup 1 %s\n", + strerror(errno)); + exit(1); + } + if (dup2(consolefd, STDERR_FILENO) != STDERR_FILENO) { + fprintf(stderr, "nsenter: failed to dup 2 %s\n", + strerror(errno)); + exit(1); + } + } + // Finish executing, let the Go runtime take over. + return; + } else { + // Parent, wait for the child. + int status = 0; + if (waitpid(child, &status, 0) == -1) { + fprintf(stderr, + "nsenter: Failed to waitpid with error: \"%s\"\n", + strerror(errno)); + exit(1); + } + // Forward the child's exit code or re-send its death signal. + if (WIFEXITED(status)) { + exit(WEXITSTATUS(status)); + } else if (WIFSIGNALED(status)) { + kill(getpid(), WTERMSIG(status)); + } + exit(1); + } + + return; +} diff --git a/components/engine/vendor/src/github.com/docker/libcontainer/namespaces/nsenter.go b/components/engine/vendor/src/github.com/docker/libcontainer/namespaces/nsenter.go index bf05628ce4..0211aec917 100644 --- a/components/engine/vendor/src/github.com/docker/libcontainer/namespaces/nsenter.go +++ b/components/engine/vendor/src/github.com/docker/libcontainer/namespaces/nsenter.go @@ -3,212 +3,6 @@ package namespaces /* -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -static const kBufSize = 256; - -void get_args(int *argc, char ***argv) { - // Read argv - int fd = open("/proc/self/cmdline", O_RDONLY); - - // Read the whole commandline. - ssize_t contents_size = 0; - ssize_t contents_offset = 0; - char *contents = NULL; - ssize_t bytes_read = 0; - do { - contents_size += kBufSize; - contents = (char *) realloc(contents, contents_size); - bytes_read = read(fd, contents + contents_offset, contents_size - contents_offset); - contents_offset += bytes_read; - } while (bytes_read > 0); - close(fd); - - // Parse the commandline into an argv. /proc/self/cmdline has \0 delimited args. - ssize_t i; - *argc = 0; - for (i = 0; i < contents_offset; i++) { - if (contents[i] == '\0') { - (*argc)++; - } - } - *argv = (char **) malloc(sizeof(char *) * ((*argc) + 1)); - int idx; - for (idx = 0; idx < (*argc); idx++) { - (*argv)[idx] = contents; - contents += strlen(contents) + 1; - } - (*argv)[*argc] = NULL; -} - -// Use raw setns syscall for versions of glibc that don't include it (namely glibc-2.12) -#if __GLIBC__ == 2 && __GLIBC_MINOR__ < 14 -#define _GNU_SOURCE -#include -#include "syscall.h" -#ifdef SYS_setns -int setns(int fd, int nstype) { - return syscall(SYS_setns, fd, nstype); -} -#endif -#endif - -void print_usage() { - fprintf(stderr, " nsenter --nspid --containerjson -- cmd1 arg1 arg2...\n"); -} - -void nsenter() { - int argc; - char **argv; - get_args(&argc, &argv); - - // Ignore if this is not for us. - if (argc < 2 || strcmp(argv[1], "nsenter") != 0) { - return; - } - - // USAGE: nsenter ... - if (argc < 6) { - fprintf(stderr, "nsenter: Incorrect usage, not enough arguments\n"); - exit(1); - } - - static const struct option longopts[] = { - { "nspid", required_argument, NULL, 'n' }, - { "containerjson", required_argument, NULL, 'c' }, - { "console", required_argument, NULL, 't' }, - { NULL, 0, NULL, 0 } - }; - - int c; - pid_t init_pid = -1; - char *init_pid_str = NULL; - char *container_json = NULL; - char *console = NULL; - while ((c = getopt_long_only(argc, argv, "n:s:c:", longopts, NULL)) != -1) { - switch (c) { - case 'n': - init_pid_str = optarg; - break; - case 'c': - container_json = optarg; - break; - case 't': - console = optarg; - break; - } - } - - if (container_json == NULL || init_pid_str == NULL) { - print_usage(); - exit(1); - } - - init_pid = strtol(init_pid_str, NULL, 10); - if (errno != 0 || init_pid <= 0) { - fprintf(stderr, "nsenter: Failed to parse PID from \"%s\" with error: \"%s\"\n", init_pid_str, strerror(errno)); - print_usage(); - exit(1); - } - - argc -= 3; - argv += 3; - - if (setsid() == -1) { - fprintf(stderr, "setsid failed. Error: %s\n", strerror(errno)); - exit(1); - } - - // before we setns we need to dup the console - int consolefd = -1; - if (console != NULL) { - consolefd = open(console, O_RDWR); - if (consolefd < 0) { - fprintf(stderr, "nsenter: failed to open console %s %s\n", console, strerror(errno)); - exit(1); - } - } - - // Setns on all supported namespaces. - char ns_dir[PATH_MAX]; - memset(ns_dir, 0, PATH_MAX); - snprintf(ns_dir, PATH_MAX - 1, "/proc/%d/ns/", init_pid); - - char* namespaces[] = {"ipc", "uts", "net", "pid", "mnt"}; - const int num = sizeof(namespaces) / sizeof(char*); - int i; - for (i = 0; i < num; i++) { - char buf[PATH_MAX]; - memset(buf, 0, PATH_MAX); - snprintf(buf, PATH_MAX - 1, "%s%s", ns_dir, namespaces[i]); - int fd = open(buf, O_RDONLY); - if (fd == -1) { - // Ignore nonexistent namespaces. - if (errno == ENOENT) - continue; - - fprintf(stderr, "nsenter: Failed to open ns file \"%s\" for ns \"%s\" with error: \"%s\"\n", buf, namespaces[i], strerror(errno)); - exit(1); - } - - // Set the namespace. - if (setns(fd, 0) == -1) { - fprintf(stderr, "nsenter: Failed to setns for \"%s\" with error: \"%s\"\n", namespaces[i], strerror(errno)); - exit(1); - } - close(fd); - } - - // We must fork to actually enter the PID namespace. - int child = fork(); - if (child == 0) { - if (consolefd != -1) { - if (dup2(consolefd, STDIN_FILENO) != 0) { - fprintf(stderr, "nsenter: failed to dup 0 %s\n", strerror(errno)); - exit(1); - } - if (dup2(consolefd, STDOUT_FILENO) != STDOUT_FILENO) { - fprintf(stderr, "nsenter: failed to dup 1 %s\n", strerror(errno)); - exit(1); - } - if (dup2(consolefd, STDERR_FILENO) != STDERR_FILENO) { - fprintf(stderr, "nsenter: failed to dup 2 %s\n", strerror(errno)); - exit(1); - } -} - - // Finish executing, let the Go runtime take over. - return; - } else { - // Parent, wait for the child. - int status = 0; - if (waitpid(child, &status, 0) == -1) { - fprintf(stderr, "nsenter: Failed to waitpid with error: \"%s\"\n", strerror(errno)); - exit(1); - } - - // Forward the child's exit code or re-send its death signal. - if (WIFEXITED(status)) { - exit(WEXITSTATUS(status)); - } else if (WIFSIGNALED(status)) { - kill(getpid(), WTERMSIG(status)); - } - exit(1); - } - - return; -} - __attribute__((constructor)) init() { nsenter(); } diff --git a/components/engine/vendor/src/github.com/docker/libcontainer/netlink/netlink_linux.go b/components/engine/vendor/src/github.com/docker/libcontainer/netlink/netlink_linux.go index 6b43fdf067..5fcc817aff 100644 --- a/components/engine/vendor/src/github.com/docker/libcontainer/netlink/netlink_linux.go +++ b/components/engine/vendor/src/github.com/docker/libcontainer/netlink/netlink_linux.go @@ -189,13 +189,15 @@ func newRtAttrChild(parent *RtAttr, attrType int, data []byte) *RtAttr { } func (a *RtAttr) Len() int { + if len(a.children) == 0 { + return (syscall.SizeofRtAttr + len(a.Data)) + } + l := 0 for _, child := range a.children { - l += child.Len() + syscall.SizeofRtAttr - } - if l == 0 { - l++ + l += child.Len() } + l += syscall.SizeofRtAttr return rtaAlignOf(l + len(a.Data)) } @@ -203,7 +205,7 @@ func (a *RtAttr) ToWireFormat() []byte { native := nativeEndian() length := a.Len() - buf := make([]byte, rtaAlignOf(length+syscall.SizeofRtAttr)) + buf := make([]byte, rtaAlignOf(length)) if a.Data != nil { copy(buf[4:], a.Data) @@ -216,11 +218,10 @@ func (a *RtAttr) ToWireFormat() []byte { } } - if l := uint16(rtaAlignOf(length)); l != 0 { - native.PutUint16(buf[0:2], l+1) + if l := uint16(length); l != 0 { + native.PutUint16(buf[0:2], l) } native.PutUint16(buf[2:4], a.Type) - return buf } @@ -700,6 +701,10 @@ func nonZeroTerminated(s string) []byte { // Add a new network link of a specified type. This is identical to // running: ip add link $name type $linkType func NetworkLinkAdd(name string, linkType string) error { + if name == "" || linkType == "" { + return fmt.Errorf("Neither link name nor link type can be empty!") + } + s, err := getNetlinkSocket() if err != nil { return err @@ -711,15 +716,43 @@ func NetworkLinkAdd(name string, linkType string) error { msg := newIfInfomsg(syscall.AF_UNSPEC) wb.AddData(msg) - if name != "" { - nameData := newRtAttr(syscall.IFLA_IFNAME, zeroTerminated(name)) - wb.AddData(nameData) + linkInfo := newRtAttr(syscall.IFLA_LINKINFO, nil) + newRtAttrChild(linkInfo, IFLA_INFO_KIND, nonZeroTerminated(linkType)) + wb.AddData(linkInfo) + + nameData := newRtAttr(syscall.IFLA_IFNAME, zeroTerminated(name)) + wb.AddData(nameData) + + if err := s.Send(wb); err != nil { + return err } - kindData := newRtAttr(IFLA_INFO_KIND, nonZeroTerminated(linkType)) + return s.HandleAck(wb.Seq) +} - infoData := newRtAttr(syscall.IFLA_LINKINFO, kindData.ToWireFormat()) - wb.AddData(infoData) +// Delete a network link. This is identical to +// running: ip link del $name +func NetworkLinkDel(name string) error { + if name == "" { + return fmt.Errorf("Network link name can not be empty!") + } + + s, err := getNetlinkSocket() + if err != nil { + return err + } + defer s.Close() + + iface, err := net.InterfaceByName(name) + if err != nil { + return err + } + + wb := newNetlinkRequest(syscall.RTM_DELLINK, syscall.NLM_F_ACK) + + msg := newIfInfomsg(syscall.AF_UNSPEC) + msg.Index = int32(iface.Index) + wb.AddData(msg) if err := s.Send(wb); err != nil { return err diff --git a/components/engine/vendor/src/github.com/docker/libcontainer/netlink/netlink_linux_test.go b/components/engine/vendor/src/github.com/docker/libcontainer/netlink/netlink_linux_test.go index ee61d5e266..a25f286138 100644 --- a/components/engine/vendor/src/github.com/docker/libcontainer/netlink/netlink_linux_test.go +++ b/components/engine/vendor/src/github.com/docker/libcontainer/netlink/netlink_linux_test.go @@ -27,10 +27,35 @@ func TestCreateBridgeWithMac(t *testing.T) { } if _, err := net.InterfaceByName(name); err == nil { - t.Fatal("expected error getting interface because bridge was deleted") + t.Fatalf("expected error getting interface because %s bridge was deleted", name) } } +func TestCreateBridgeLink(t *testing.T) { + if testing.Short() { + return + } + + name := "mybrlink" + + if err := NetworkLinkAdd(name, "bridge"); err != nil { + t.Fatal(err) + } + + if _, err := net.InterfaceByName(name); err != nil { + t.Fatal(err) + } + + if err := NetworkLinkDel(name); err != nil { + t.Fatal(err) + } + + if _, err := net.InterfaceByName(name); err == nil { + t.Fatalf("expected error getting interface because %s bridge was deleted", name) + } + +} + func TestCreateVethPair(t *testing.T) { if testing.Short() { return diff --git a/components/engine/vendor/src/github.com/docker/libcontainer/netlink/netlink_unsupported.go b/components/engine/vendor/src/github.com/docker/libcontainer/netlink/netlink_unsupported.go index f428933c13..783e68cae5 100644 --- a/components/engine/vendor/src/github.com/docker/libcontainer/netlink/netlink_unsupported.go +++ b/components/engine/vendor/src/github.com/docker/libcontainer/netlink/netlink_unsupported.go @@ -19,6 +19,10 @@ func NetworkLinkAdd(name string, linkType string) error { return ErrNotImplemented } +func NetworkLinkDel(name string) error { + return ErrNotImplemented +} + func NetworkLinkUp(iface *net.Interface) error { return ErrNotImplemented } diff --git a/components/engine/vendor/src/github.com/docker/libcontainer/nsinit/cli.go b/components/engine/vendor/src/github.com/docker/libcontainer/nsinit/cli.go index d4235aef86..1c770edbd8 100644 --- a/components/engine/vendor/src/github.com/docker/libcontainer/nsinit/cli.go +++ b/components/engine/vendor/src/github.com/docker/libcontainer/nsinit/cli.go @@ -24,7 +24,10 @@ func NsInit() { app.Name = "nsinit" app.Version = "0.1" app.Author = "libcontainer maintainers" - + app.Flags = []cli.Flag{ + cli.StringFlag{Name: "nspid"}, + cli.StringFlag{Name: "containerjson"}, + cli.StringFlag{Name: "console"}} app.Before = preload app.Commands = []cli.Command{ execCommand, diff --git a/components/engine/vendor/src/github.com/docker/libcontainer/nsinit/exec.go b/components/engine/vendor/src/github.com/docker/libcontainer/nsinit/exec.go index 5d41046656..abb245bd04 100644 --- a/components/engine/vendor/src/github.com/docker/libcontainer/nsinit/exec.go +++ b/components/engine/vendor/src/github.com/docker/libcontainer/nsinit/exec.go @@ -36,7 +36,7 @@ func execAction(context *cli.Context) { } if state != nil { - exitCode, err = runIn(container, state, []string(context.Args())) + err = namespaces.ExecIn(container, state, []string(context.Args())) } else { exitCode, err = startContainer(container, dataPath, []string(context.Args())) } @@ -48,59 +48,6 @@ func execAction(context *cli.Context) { os.Exit(exitCode) } -func runIn(container *libcontainer.Config, state *libcontainer.State, args []string) (int, error) { - var ( - master *os.File - console string - err error - - stdin = os.Stdin - stdout = os.Stdout - stderr = os.Stderr - sigc = make(chan os.Signal, 10) - ) - - signal.Notify(sigc) - - if container.Tty { - stdin = nil - stdout = nil - stderr = nil - - master, console, err = consolepkg.CreateMasterAndConsole() - if err != nil { - log.Fatal(err) - } - - go io.Copy(master, os.Stdin) - go io.Copy(os.Stdout, master) - - state, err := term.SetRawTerminal(os.Stdin.Fd()) - if err != nil { - log.Fatal(err) - } - - defer term.RestoreTerminal(os.Stdin.Fd(), state) - } - - startCallback := func(cmd *exec.Cmd) { - go func() { - resizeTty(master) - - for sig := range sigc { - switch sig { - case syscall.SIGWINCH: - resizeTty(master) - default: - cmd.Process.Signal(sig) - } - } - }() - } - - return namespaces.RunIn(container, state, args, os.Args[0], stdin, stdout, stderr, console, startCallback) -} - // startContainer starts the container. Returns the exit status or -1 and an // error. // diff --git a/components/engine/vendor/src/github.com/docker/libcontainer/nsinit/nsenter.go b/components/engine/vendor/src/github.com/docker/libcontainer/nsinit/nsenter.go index 11d646ebea..323706c281 100644 --- a/components/engine/vendor/src/github.com/docker/libcontainer/nsinit/nsenter.go +++ b/components/engine/vendor/src/github.com/docker/libcontainer/nsinit/nsenter.go @@ -2,6 +2,7 @@ package nsinit import ( "log" + "strconv" "github.com/codegangsta/cli" "github.com/docker/libcontainer/namespaces" @@ -11,11 +12,6 @@ var nsenterCommand = cli.Command{ Name: "nsenter", Usage: "init process for entering an existing namespace", Action: nsenterAction, - Flags: []cli.Flag{ - cli.IntFlag{Name: "nspid"}, - cli.StringFlag{Name: "containerjson"}, - cli.StringFlag{Name: "console"}, - }, } func nsenterAction(context *cli.Context) { @@ -25,14 +21,14 @@ func nsenterAction(context *cli.Context) { args = []string{"/bin/bash"} } - container, err := loadContainerFromJson(context.String("containerjson")) + container, err := loadContainerFromJson(context.GlobalString("containerjson")) if err != nil { log.Fatalf("unable to load container: %s", err) } - nspid := context.Int("nspid") - if nspid <= 0 { - log.Fatalf("cannot enter into namespaces without valid pid: %q", nspid) + nspid, err := strconv.Atoi(context.GlobalString("nspid")) + if nspid <= 0 || err != nil { + log.Fatalf("cannot enter into namespaces without valid pid: %q - %s", nspid, err) } if err := namespaces.NsEnter(container, args); err != nil { diff --git a/components/engine/vendor/src/github.com/docker/libcontainer/update-vendor.sh b/components/engine/vendor/src/github.com/docker/libcontainer/update-vendor.sh new file mode 100755 index 0000000000..df66a0a8d5 --- /dev/null +++ b/components/engine/vendor/src/github.com/docker/libcontainer/update-vendor.sh @@ -0,0 +1,48 @@ +#!/usr/bin/env bash +set -e + +cd "$(dirname "$BASH_SOURCE")" + +# Downloads dependencies into vendor/ directory +mkdir -p vendor +cd vendor + +clone() { + vcs=$1 + pkg=$2 + rev=$3 + + pkg_url=https://$pkg + target_dir=src/$pkg + + echo -n "$pkg @ $rev: " + + if [ -d $target_dir ]; then + echo -n 'rm old, ' + rm -fr $target_dir + fi + + echo -n 'clone, ' + case $vcs in + git) + git clone --quiet --no-checkout $pkg_url $target_dir + ( cd $target_dir && git reset --quiet --hard $rev ) + ;; + hg) + hg clone --quiet --updaterev $rev $pkg_url $target_dir + ;; + esac + + echo -n 'rm VCS, ' + ( cd $target_dir && rm -rf .{git,hg} ) + + echo done +} + +# the following lines are in sorted order, FYI +clone git github.com/codegangsta/cli 1.1.0 +clone git github.com/coreos/go-systemd v2 +clone git github.com/godbus/dbus v1 +clone git github.com/syndtr/gocapability 3c85049eae + +# intentionally not vendoring Docker itself... that'd be a circle :)