Bladeren bron

Merge pull request #297 from mavenugo/chdr

Updating CallFunc to match the Docker CLI API changes
aboch 10 jaren geleden
bovenliggende
commit
e228afce04
56 gewijzigde bestanden met toevoegingen van 4368 en 51 verwijderingen
  1. 23 18
      libnetwork/Godeps/Godeps.json
  2. 83 0
      libnetwork/Godeps/_workspace/src/github.com/docker/docker/api/client/attach.go
  3. 310 0
      libnetwork/Godeps/_workspace/src/github.com/docker/docker/api/client/build.go
  4. 203 0
      libnetwork/Godeps/_workspace/src/github.com/docker/docker/api/client/cli.go
  5. 17 0
      libnetwork/Godeps/_workspace/src/github.com/docker/docker/api/client/client.go
  6. 80 0
      libnetwork/Godeps/_workspace/src/github.com/docker/docker/api/client/commit.go
  7. 57 0
      libnetwork/Godeps/_workspace/src/github.com/docker/docker/api/client/cp.go
  8. 160 0
      libnetwork/Godeps/_workspace/src/github.com/docker/docker/api/client/create.go
  9. 52 0
      libnetwork/Godeps/_workspace/src/github.com/docker/docker/api/client/diff.go
  10. 62 0
      libnetwork/Godeps/_workspace/src/github.com/docker/docker/api/client/events.go
  11. 131 0
      libnetwork/Godeps/_workspace/src/github.com/docker/docker/api/client/exec.go
  12. 46 0
      libnetwork/Godeps/_workspace/src/github.com/docker/docker/api/client/export.go
  13. 34 0
      libnetwork/Godeps/_workspace/src/github.com/docker/docker/api/client/help.go
  14. 257 0
      libnetwork/Godeps/_workspace/src/github.com/docker/docker/api/client/hijack.go
  15. 73 0
      libnetwork/Godeps/_workspace/src/github.com/docker/docker/api/client/history.go
  16. 126 0
      libnetwork/Godeps/_workspace/src/github.com/docker/docker/api/client/images.go
  17. 64 0
      libnetwork/Godeps/_workspace/src/github.com/docker/docker/api/client/import.go
  18. 91 0
      libnetwork/Godeps/_workspace/src/github.com/docker/docker/api/client/info.go
  19. 124 0
      libnetwork/Godeps/_workspace/src/github.com/docker/docker/api/client/inspect.go
  20. 32 0
      libnetwork/Godeps/_workspace/src/github.com/docker/docker/api/client/kill.go
  21. 41 0
      libnetwork/Godeps/_workspace/src/github.com/docker/docker/api/client/load.go
  22. 144 0
      libnetwork/Godeps/_workspace/src/github.com/docker/docker/api/client/login.go
  23. 36 0
      libnetwork/Godeps/_workspace/src/github.com/docker/docker/api/client/logout.go
  24. 69 0
      libnetwork/Godeps/_workspace/src/github.com/docker/docker/api/client/logs.go
  25. 30 0
      libnetwork/Godeps/_workspace/src/github.com/docker/docker/api/client/pause.go
  26. 64 0
      libnetwork/Godeps/_workspace/src/github.com/docker/docker/api/client/port.go
  27. 175 0
      libnetwork/Godeps/_workspace/src/github.com/docker/docker/api/client/ps.go
  28. 47 0
      libnetwork/Godeps/_workspace/src/github.com/docker/docker/api/client/pull.go
  29. 49 0
      libnetwork/Godeps/_workspace/src/github.com/docker/docker/api/client/push.go
  30. 25 0
      libnetwork/Godeps/_workspace/src/github.com/docker/docker/api/client/rename.go
  31. 38 0
      libnetwork/Godeps/_workspace/src/github.com/docker/docker/api/client/restart.go
  32. 54 0
      libnetwork/Godeps/_workspace/src/github.com/docker/docker/api/client/rm.go
  33. 59 0
      libnetwork/Godeps/_workspace/src/github.com/docker/docker/api/client/rmi.go
  34. 247 0
      libnetwork/Godeps/_workspace/src/github.com/docker/docker/api/client/run.go
  35. 57 0
      libnetwork/Godeps/_workspace/src/github.com/docker/docker/api/client/save.go
  36. 84 0
      libnetwork/Godeps/_workspace/src/github.com/docker/docker/api/client/search.go
  37. 167 0
      libnetwork/Godeps/_workspace/src/github.com/docker/docker/api/client/start.go
  38. 198 0
      libnetwork/Godeps/_workspace/src/github.com/docker/docker/api/client/stats.go
  39. 29 0
      libnetwork/Godeps/_workspace/src/github.com/docker/docker/api/client/stats_unit_test.go
  40. 40 0
      libnetwork/Godeps/_workspace/src/github.com/docker/docker/api/client/stop.go
  41. 41 0
      libnetwork/Godeps/_workspace/src/github.com/docker/docker/api/client/tag.go
  42. 46 0
      libnetwork/Godeps/_workspace/src/github.com/docker/docker/api/client/top.go
  43. 30 0
      libnetwork/Godeps/_workspace/src/github.com/docker/docker/api/client/unpause.go
  44. 345 0
      libnetwork/Godeps/_workspace/src/github.com/docker/docker/api/client/utils.go
  45. 61 0
      libnetwork/Godeps/_workspace/src/github.com/docker/docker/api/client/version.go
  46. 34 0
      libnetwork/Godeps/_workspace/src/github.com/docker/docker/api/client/wait.go
  47. 14 0
      libnetwork/Godeps/_workspace/src/github.com/docker/docker/pkg/ioutils/fmt.go
  48. 17 0
      libnetwork/Godeps/_workspace/src/github.com/docker/docker/pkg/ioutils/fmt_test.go
  49. 1 2
      libnetwork/Godeps/_workspace/src/github.com/docker/docker/pkg/ioutils/readers_test.go
  50. 22 7
      libnetwork/Godeps/_workspace/src/github.com/docker/docker/pkg/mflag/flag.go
  51. 18 5
      libnetwork/Godeps/_workspace/src/github.com/docker/docker/pkg/plugins/client.go
  52. 43 1
      libnetwork/Godeps/_workspace/src/github.com/docker/docker/pkg/plugins/client_test.go
  53. 1 5
      libnetwork/Godeps/_workspace/src/github.com/docker/docker/pkg/plugins/discovery_test.go
  54. 3 2
      libnetwork/client/client.go
  55. 7 4
      libnetwork/client/client_test.go
  56. 7 7
      libnetwork/cmd/dnet/dnet.go

+ 23 - 18
libnetwork/Godeps/Godeps.json

@@ -27,48 +27,53 @@
 		},
 		{
 			"ImportPath": "github.com/docker/docker/pkg/homedir",
-			"Comment": "v1.4.1-3479-ga9172f5",
-			"Rev": "a9172f572e13086859c652e2d581950e910d63d4"
+			"Comment": "v1.4.1-4106-g637023a",
+			"Rev": "637023a5f8d8347a0e271c09d5c9bc84fbc97693"
 		},
 		{
 			"ImportPath": "github.com/docker/docker/pkg/ioutils",
-			"Comment": "v1.4.1-3479-ga9172f5",
-			"Rev": "a9172f572e13086859c652e2d581950e910d63d4"
+			"Comment": "v1.4.1-4106-g637023a",
+			"Rev": "637023a5f8d8347a0e271c09d5c9bc84fbc97693"
 		},
 		{
 			"ImportPath": "github.com/docker/docker/pkg/mflag",
-			"Comment": "v1.4.1-3479-ga9172f5",
-			"Rev": "a9172f572e13086859c652e2d581950e910d63d4"
+			"Comment": "v1.4.1-4106-g637023a",
+			"Rev": "637023a5f8d8347a0e271c09d5c9bc84fbc97693"
 		},
 		{
 			"ImportPath": "github.com/docker/docker/pkg/parsers",
-			"Comment": "v1.4.1-3479-ga9172f5",
-			"Rev": "a9172f572e13086859c652e2d581950e910d63d4"
+			"Comment": "v1.4.1-4106-g637023a",
+			"Rev": "637023a5f8d8347a0e271c09d5c9bc84fbc97693"
 		},
 		{
 			"ImportPath": "github.com/docker/docker/pkg/plugins",
-			"Comment": "v1.4.1-3479-ga9172f5",
-			"Rev": "a9172f572e13086859c652e2d581950e910d63d4"
+			"Comment": "v1.4.1-4106-g637023a",
+			"Rev": "637023a5f8d8347a0e271c09d5c9bc84fbc97693"
 		},
 		{
 			"ImportPath": "github.com/docker/docker/pkg/proxy",
-			"Comment": "v1.4.1-3479-ga9172f5",
-			"Rev": "a9172f572e13086859c652e2d581950e910d63d4"
+			"Comment": "v1.4.1-4106-g637023a",
+			"Rev": "637023a5f8d8347a0e271c09d5c9bc84fbc97693"
 		},
 		{
 			"ImportPath": "github.com/docker/docker/pkg/reexec",
-			"Comment": "v1.4.1-3479-ga9172f5",
-			"Rev": "a9172f572e13086859c652e2d581950e910d63d4"
+			"Comment": "v1.4.1-4106-g637023a",
+			"Rev": "637023a5f8d8347a0e271c09d5c9bc84fbc97693"
 		},
 		{
 			"ImportPath": "github.com/docker/docker/pkg/stringid",
-			"Comment": "v1.4.1-3479-ga9172f5",
-			"Rev": "a9172f572e13086859c652e2d581950e910d63d4"
+			"Comment": "v1.4.1-4106-g637023a",
+			"Rev": "637023a5f8d8347a0e271c09d5c9bc84fbc97693"
 		},
 		{
 			"ImportPath": "github.com/docker/docker/pkg/term",
-			"Comment": "v1.4.1-3479-ga9172f5",
-			"Rev": "a9172f572e13086859c652e2d581950e910d63d4"
+			"Comment": "v1.4.1-4106-g637023a",
+			"Rev": "637023a5f8d8347a0e271c09d5c9bc84fbc97693"
+		},
+		{
+			"ImportPath": "github.com/docker/docker/api/client",
+			"Comment": "v1.4.1-4106-g637023a",
+			"Rev": "637023a5f8d8347a0e271c09d5c9bc84fbc97693"
 		},
 		{
 			"ImportPath": "github.com/docker/libcontainer/user",

+ 83 - 0
libnetwork/Godeps/_workspace/src/github.com/docker/docker/api/client/attach.go

@@ -0,0 +1,83 @@
+package client
+
+import (
+	"encoding/json"
+	"fmt"
+	"io"
+	"net/url"
+
+	"github.com/Sirupsen/logrus"
+	"github.com/docker/docker/api/types"
+	flag "github.com/docker/docker/pkg/mflag"
+	"github.com/docker/docker/pkg/signal"
+)
+
+// CmdAttach attaches to a running container.
+//
+// Usage: docker attach [OPTIONS] CONTAINER
+func (cli *DockerCli) CmdAttach(args ...string) error {
+	var (
+		cmd     = cli.Subcmd("attach", "CONTAINER", "Attach to a running container", true)
+		noStdin = cmd.Bool([]string{"#nostdin", "-no-stdin"}, false, "Do not attach STDIN")
+		proxy   = cmd.Bool([]string{"#sig-proxy", "-sig-proxy"}, true, "Proxy all received signals to the process")
+	)
+	cmd.Require(flag.Exact, 1)
+
+	cmd.ParseFlags(args, true)
+	name := cmd.Arg(0)
+
+	stream, _, _, err := cli.call("GET", "/containers/"+name+"/json", nil, nil)
+	if err != nil {
+		return err
+	}
+
+	var c types.ContainerJSON
+	if err := json.NewDecoder(stream).Decode(&c); err != nil {
+		return err
+	}
+
+	if !c.State.Running {
+		return fmt.Errorf("You cannot attach to a stopped container, start it first")
+	}
+
+	if err := cli.CheckTtyInput(!*noStdin, c.Config.Tty); err != nil {
+		return err
+	}
+
+	if c.Config.Tty && cli.isTerminalOut {
+		if err := cli.monitorTtySize(cmd.Arg(0), false); err != nil {
+			logrus.Debugf("Error monitoring TTY size: %s", err)
+		}
+	}
+
+	var in io.ReadCloser
+
+	v := url.Values{}
+	v.Set("stream", "1")
+	if !*noStdin && c.Config.OpenStdin {
+		v.Set("stdin", "1")
+		in = cli.in
+	}
+
+	v.Set("stdout", "1")
+	v.Set("stderr", "1")
+
+	if *proxy && !c.Config.Tty {
+		sigc := cli.forwardAllSignals(cmd.Arg(0))
+		defer signal.StopCatch(sigc)
+	}
+
+	if err := cli.hijack("POST", "/containers/"+cmd.Arg(0)+"/attach?"+v.Encode(), c.Config.Tty, in, cli.out, cli.err, nil, nil); err != nil {
+		return err
+	}
+
+	_, status, err := getExitCode(cli, cmd.Arg(0))
+	if err != nil {
+		return err
+	}
+	if status != 0 {
+		return StatusError{StatusCode: status}
+	}
+
+	return nil
+}

+ 310 - 0
libnetwork/Godeps/_workspace/src/github.com/docker/docker/api/client/build.go

@@ -0,0 +1,310 @@
+package client
+
+import (
+	"bufio"
+	"encoding/base64"
+	"encoding/json"
+	"fmt"
+	"io"
+	"io/ioutil"
+	"net/http"
+	"net/url"
+	"os"
+	"os/exec"
+	"path"
+	"path/filepath"
+	"runtime"
+	"strconv"
+	"strings"
+
+	"github.com/docker/docker/api"
+	"github.com/docker/docker/graph/tags"
+	"github.com/docker/docker/pkg/archive"
+	"github.com/docker/docker/pkg/fileutils"
+	"github.com/docker/docker/pkg/jsonmessage"
+	flag "github.com/docker/docker/pkg/mflag"
+	"github.com/docker/docker/pkg/parsers"
+	"github.com/docker/docker/pkg/progressreader"
+	"github.com/docker/docker/pkg/streamformatter"
+	"github.com/docker/docker/pkg/symlink"
+	"github.com/docker/docker/pkg/units"
+	"github.com/docker/docker/pkg/urlutil"
+	"github.com/docker/docker/registry"
+	"github.com/docker/docker/utils"
+)
+
+const (
+	tarHeaderSize = 512
+)
+
+// CmdBuild builds a new image from the source code at a given path.
+//
+// If '-' is provided instead of a path or URL, Docker will build an image from either a Dockerfile or tar archive read from STDIN.
+//
+// Usage: docker build [OPTIONS] PATH | URL | -
+func (cli *DockerCli) CmdBuild(args ...string) error {
+	cmd := cli.Subcmd("build", "PATH | URL | -", "Build a new image from the source code at PATH", true)
+	tag := cmd.String([]string{"t", "-tag"}, "", "Repository name (and optionally a tag) for the image")
+	suppressOutput := cmd.Bool([]string{"q", "-quiet"}, false, "Suppress the verbose output generated by the containers")
+	noCache := cmd.Bool([]string{"#no-cache", "-no-cache"}, false, "Do not use cache when building the image")
+	rm := cmd.Bool([]string{"#rm", "-rm"}, true, "Remove intermediate containers after a successful build")
+	forceRm := cmd.Bool([]string{"-force-rm"}, false, "Always remove intermediate containers")
+	pull := cmd.Bool([]string{"-pull"}, false, "Always attempt to pull a newer version of the image")
+	dockerfileName := cmd.String([]string{"f", "-file"}, "", "Name of the Dockerfile (Default is 'PATH/Dockerfile')")
+	flMemoryString := cmd.String([]string{"m", "-memory"}, "", "Memory limit")
+	flMemorySwap := cmd.String([]string{"-memory-swap"}, "", "Total memory (memory + swap), '-1' to disable swap")
+	flCPUShares := cmd.Int64([]string{"c", "-cpu-shares"}, 0, "CPU shares (relative weight)")
+	flCpuPeriod := cmd.Int64([]string{"-cpu-period"}, 0, "Limit the CPU CFS (Completely Fair Scheduler) period")
+	flCpuQuota := cmd.Int64([]string{"-cpu-quota"}, 0, "Limit the CPU CFS (Completely Fair Scheduler) quota")
+	flCPUSetCpus := cmd.String([]string{"-cpuset-cpus"}, "", "CPUs in which to allow execution (0-3, 0,1)")
+	flCPUSetMems := cmd.String([]string{"-cpuset-mems"}, "", "MEMs in which to allow execution (0-3, 0,1)")
+	flCgroupParent := cmd.String([]string{"-cgroup-parent"}, "", "Optional parent cgroup for the container")
+
+	cmd.Require(flag.Exact, 1)
+	cmd.ParseFlags(args, true)
+
+	var (
+		context  archive.Archive
+		isRemote bool
+		err      error
+	)
+
+	_, err = exec.LookPath("git")
+	hasGit := err == nil
+	if cmd.Arg(0) == "-" {
+		// As a special case, 'docker build -' will build from either an empty context with the
+		// contents of stdin as a Dockerfile, or a tar-ed context from stdin.
+		buf := bufio.NewReader(cli.in)
+		magic, err := buf.Peek(tarHeaderSize)
+		if err != nil && err != io.EOF {
+			return fmt.Errorf("failed to peek context header from STDIN: %v", err)
+		}
+		if !archive.IsArchive(magic) {
+			dockerfile, err := ioutil.ReadAll(buf)
+			if err != nil {
+				return fmt.Errorf("failed to read Dockerfile from STDIN: %v", err)
+			}
+
+			// -f option has no meaning when we're reading it from stdin,
+			// so just use our default Dockerfile name
+			*dockerfileName = api.DefaultDockerfileName
+			context, err = archive.Generate(*dockerfileName, string(dockerfile))
+		} else {
+			context = ioutil.NopCloser(buf)
+		}
+	} else if urlutil.IsURL(cmd.Arg(0)) && (!urlutil.IsGitURL(cmd.Arg(0)) || !hasGit) {
+		isRemote = true
+	} else {
+		root := cmd.Arg(0)
+		if urlutil.IsGitURL(root) {
+			root, err = utils.GitClone(root)
+			if err != nil {
+				return err
+			}
+			defer os.RemoveAll(root)
+		}
+		if _, err := os.Stat(root); err != nil {
+			return err
+		}
+
+		absRoot, err := filepath.Abs(root)
+		if err != nil {
+			return err
+		}
+
+		filename := *dockerfileName // path to Dockerfile
+
+		if *dockerfileName == "" {
+			// No -f/--file was specified so use the default
+			*dockerfileName = api.DefaultDockerfileName
+			filename = filepath.Join(absRoot, *dockerfileName)
+
+			// Just to be nice ;-) look for 'dockerfile' too but only
+			// use it if we found it, otherwise ignore this check
+			if _, err = os.Lstat(filename); os.IsNotExist(err) {
+				tmpFN := path.Join(absRoot, strings.ToLower(*dockerfileName))
+				if _, err = os.Lstat(tmpFN); err == nil {
+					*dockerfileName = strings.ToLower(*dockerfileName)
+					filename = tmpFN
+				}
+			}
+		}
+
+		origDockerfile := *dockerfileName // used for error msg
+		if filename, err = filepath.Abs(filename); err != nil {
+			return err
+		}
+
+		// Verify that 'filename' is within the build context
+		filename, err = symlink.FollowSymlinkInScope(filename, absRoot)
+		if err != nil {
+			return fmt.Errorf("The Dockerfile (%s) must be within the build context (%s)", origDockerfile, root)
+		}
+
+		// Now reset the dockerfileName to be relative to the build context
+		*dockerfileName, err = filepath.Rel(absRoot, filename)
+		if err != nil {
+			return err
+		}
+		// And canonicalize dockerfile name to a platform-independent one
+		*dockerfileName, err = archive.CanonicalTarNameForPath(*dockerfileName)
+		if err != nil {
+			return fmt.Errorf("Cannot canonicalize dockerfile path %s: %v", *dockerfileName, err)
+		}
+
+		if _, err = os.Lstat(filename); os.IsNotExist(err) {
+			return fmt.Errorf("Cannot locate Dockerfile: %s", origDockerfile)
+		}
+		var includes = []string{"."}
+
+		excludes, err := utils.ReadDockerIgnore(path.Join(root, ".dockerignore"))
+		if err != nil {
+			return err
+		}
+
+		// If .dockerignore mentions .dockerignore or the Dockerfile
+		// then make sure we send both files over to the daemon
+		// because Dockerfile is, obviously, needed no matter what, and
+		// .dockerignore is needed to know if either one needs to be
+		// removed.  The deamon will remove them for us, if needed, after it
+		// parses the Dockerfile.
+		keepThem1, _ := fileutils.Matches(".dockerignore", excludes)
+		keepThem2, _ := fileutils.Matches(*dockerfileName, excludes)
+		if keepThem1 || keepThem2 {
+			includes = append(includes, ".dockerignore", *dockerfileName)
+		}
+
+		if err := utils.ValidateContextDirectory(root, excludes); err != nil {
+			return fmt.Errorf("Error checking context: '%s'.", err)
+		}
+		options := &archive.TarOptions{
+			Compression:     archive.Uncompressed,
+			ExcludePatterns: excludes,
+			IncludeFiles:    includes,
+		}
+		context, err = archive.TarWithOptions(root, options)
+		if err != nil {
+			return err
+		}
+	}
+
+	// windows: show error message about modified file permissions
+	// FIXME: this is not a valid warning when the daemon is running windows. should be removed once docker engine for windows can build.
+	if runtime.GOOS == "windows" {
+		fmt.Fprintln(cli.err, `SECURITY WARNING: You are building a Docker image from Windows against a Linux Docker host. All files and directories added to build context will have '-rwxr-xr-x' permissions. It is recommended to double check and reset permissions for sensitive files and directories.`)
+	}
+
+	var body io.Reader
+	// Setup an upload progress bar
+	// FIXME: ProgressReader shouldn't be this annoying to use
+	if context != nil {
+		sf := streamformatter.NewStreamFormatter()
+		body = progressreader.New(progressreader.Config{
+			In:        context,
+			Out:       cli.out,
+			Formatter: sf,
+			NewLines:  true,
+			ID:        "",
+			Action:    "Sending build context to Docker daemon",
+		})
+	}
+
+	var memory int64
+	if *flMemoryString != "" {
+		parsedMemory, err := units.RAMInBytes(*flMemoryString)
+		if err != nil {
+			return err
+		}
+		memory = parsedMemory
+	}
+
+	var memorySwap int64
+	if *flMemorySwap != "" {
+		if *flMemorySwap == "-1" {
+			memorySwap = -1
+		} else {
+			parsedMemorySwap, err := units.RAMInBytes(*flMemorySwap)
+			if err != nil {
+				return err
+			}
+			memorySwap = parsedMemorySwap
+		}
+	}
+	// Send the build context
+	v := &url.Values{}
+
+	//Check if the given image name can be resolved
+	if *tag != "" {
+		repository, tag := parsers.ParseRepositoryTag(*tag)
+		if err := registry.ValidateRepositoryName(repository); err != nil {
+			return err
+		}
+		if len(tag) > 0 {
+			if err := tags.ValidateTagName(tag); err != nil {
+				return err
+			}
+		}
+	}
+
+	v.Set("t", *tag)
+
+	if *suppressOutput {
+		v.Set("q", "1")
+	}
+	if isRemote {
+		v.Set("remote", cmd.Arg(0))
+	}
+	if *noCache {
+		v.Set("nocache", "1")
+	}
+	if *rm {
+		v.Set("rm", "1")
+	} else {
+		v.Set("rm", "0")
+	}
+
+	if *forceRm {
+		v.Set("forcerm", "1")
+	}
+
+	if *pull {
+		v.Set("pull", "1")
+	}
+
+	v.Set("cpusetcpus", *flCPUSetCpus)
+	v.Set("cpusetmems", *flCPUSetMems)
+	v.Set("cpushares", strconv.FormatInt(*flCPUShares, 10))
+	v.Set("cpuquota", strconv.FormatInt(*flCpuQuota, 10))
+	v.Set("cpuperiod", strconv.FormatInt(*flCpuPeriod, 10))
+	v.Set("memory", strconv.FormatInt(memory, 10))
+	v.Set("memswap", strconv.FormatInt(memorySwap, 10))
+	v.Set("cgroupparent", *flCgroupParent)
+
+	v.Set("dockerfile", *dockerfileName)
+
+	headers := http.Header(make(map[string][]string))
+	buf, err := json.Marshal(cli.configFile.AuthConfigs)
+	if err != nil {
+		return err
+	}
+	headers.Add("X-Registry-Config", base64.URLEncoding.EncodeToString(buf))
+
+	if context != nil {
+		headers.Set("Content-Type", "application/tar")
+	}
+	sopts := &streamOpts{
+		rawTerminal: true,
+		in:          body,
+		out:         cli.out,
+		headers:     headers,
+	}
+	err = cli.stream("POST", fmt.Sprintf("/build?%s", v.Encode()), sopts)
+	if jerr, ok := err.(*jsonmessage.JSONError); ok {
+		// If no error code is set, default to 1
+		if jerr.Code == 0 {
+			jerr.Code = 1
+		}
+		return StatusError{Status: jerr.Message, StatusCode: jerr.Code}
+	}
+	return err
+}

+ 203 - 0
libnetwork/Godeps/_workspace/src/github.com/docker/docker/api/client/cli.go

@@ -0,0 +1,203 @@
+package client
+
+import (
+	"crypto/tls"
+	"encoding/json"
+	"errors"
+	"fmt"
+	"io"
+	"net/http"
+	"path/filepath"
+	"reflect"
+	"strings"
+	"text/template"
+
+	"github.com/docker/docker/cliconfig"
+	"github.com/docker/docker/pkg/homedir"
+	flag "github.com/docker/docker/pkg/mflag"
+	"github.com/docker/docker/pkg/term"
+	"github.com/docker/docker/utils"
+)
+
+// DockerCli represents the docker command line client.
+// Instances of the client can be returned from NewDockerCli.
+type DockerCli struct {
+	// proto holds the client protocol i.e. unix.
+	proto string
+	// addr holds the client address.
+	addr string
+
+	// configFile has the client configuration file
+	configFile *cliconfig.ConfigFile
+	// in holds the input stream and closer (io.ReadCloser) for the client.
+	in io.ReadCloser
+	// out holds the output stream (io.Writer) for the client.
+	out io.Writer
+	// err holds the error stream (io.Writer) for the client.
+	err io.Writer
+	// keyFile holds the key file as a string.
+	keyFile string
+	// tlsConfig holds the TLS configuration for the client, and will
+	// set the scheme to https in NewDockerCli if present.
+	tlsConfig *tls.Config
+	// scheme holds the scheme of the client i.e. https.
+	scheme string
+	// inFd holds the file descriptor of the client's STDIN (if valid).
+	inFd uintptr
+	// outFd holds file descriptor of the client's STDOUT (if valid).
+	outFd uintptr
+	// isTerminalIn indicates whether the client's STDIN is a TTY
+	isTerminalIn bool
+	// isTerminalOut dindicates whether the client's STDOUT is a TTY
+	isTerminalOut bool
+	// transport holds the client transport instance.
+	transport *http.Transport
+}
+
+var funcMap = template.FuncMap{
+	"json": func(v interface{}) string {
+		a, _ := json.Marshal(v)
+		return string(a)
+	},
+}
+
+func (cli *DockerCli) Out() io.Writer {
+	return cli.out
+}
+
+func (cli *DockerCli) Err() io.Writer {
+	return cli.err
+}
+
+func (cli *DockerCli) getMethod(args ...string) (func(...string) error, bool) {
+	camelArgs := make([]string, len(args))
+	for i, s := range args {
+		if len(s) == 0 {
+			return nil, false
+		}
+		camelArgs[i] = strings.ToUpper(s[:1]) + strings.ToLower(s[1:])
+	}
+	methodName := "Cmd" + strings.Join(camelArgs, "")
+	method := reflect.ValueOf(cli).MethodByName(methodName)
+	if !method.IsValid() {
+		return nil, false
+	}
+	return method.Interface().(func(...string) error), true
+}
+
+// Cmd executes the specified command.
+func (cli *DockerCli) Cmd(args ...string) error {
+	if len(args) > 1 {
+		method, exists := cli.getMethod(args[:2]...)
+		if exists {
+			return method(args[2:]...)
+		}
+	}
+	if len(args) > 0 {
+		method, exists := cli.getMethod(args[0])
+		if !exists {
+			return fmt.Errorf("docker: '%s' is not a docker command.\nSee 'docker --help'.", args[0])
+		}
+		return method(args[1:]...)
+	}
+	return cli.CmdHelp()
+}
+
+// Subcmd is a subcommand of the main "docker" command.
+// A subcommand represents an action that can be performed
+// from the Docker command line client.
+//
+// To see all available subcommands, run "docker --help".
+func (cli *DockerCli) Subcmd(name, signature, description string, exitOnError bool) *flag.FlagSet {
+	var errorHandling flag.ErrorHandling
+	if exitOnError {
+		errorHandling = flag.ExitOnError
+	} else {
+		errorHandling = flag.ContinueOnError
+	}
+	flags := flag.NewFlagSet(name, errorHandling)
+	if signature != "" {
+		signature = " " + signature
+	}
+	flags.Usage = func() {
+		flags.ShortUsage()
+		flags.PrintDefaults()
+	}
+	flags.ShortUsage = func() {
+		options := ""
+		if flags.FlagCountUndeprecated() > 0 {
+			options = " [OPTIONS]"
+		}
+		fmt.Fprintf(flags.Out(), "\nUsage: docker %s%s%s\n\n%s\n", name, options, signature, description)
+	}
+	return flags
+}
+
+// CheckTtyInput checks if we are trying to attach to a container tty
+// from a non-tty client input stream, and if so, returns an error.
+func (cli *DockerCli) CheckTtyInput(attachStdin, ttyMode bool) error {
+	// In order to attach to a container tty, input stream for the client must
+	// be a tty itself: redirecting or piping the client standard input is
+	// incompatible with `docker run -t`, `docker exec -t` or `docker attach`.
+	if ttyMode && attachStdin && !cli.isTerminalIn {
+		return errors.New("cannot enable tty mode on non tty input")
+	}
+	return nil
+}
+
+// NewDockerCli returns a DockerCli instance with IO output and error streams set by in, out and err.
+// The key file, protocol (i.e. unix) and address are passed in as strings, along with the tls.Config. If the tls.Config
+// is set the client scheme will be set to https.
+// The client will be given a 32-second timeout (see https://github.com/docker/docker/pull/8035).
+func NewDockerCli(in io.ReadCloser, out, err io.Writer, keyFile string, proto, addr string, tlsConfig *tls.Config) *DockerCli {
+	var (
+		inFd          uintptr
+		outFd         uintptr
+		isTerminalIn  = false
+		isTerminalOut = false
+		scheme        = "http"
+	)
+
+	if tlsConfig != nil {
+		scheme = "https"
+	}
+	if in != nil {
+		inFd, isTerminalIn = term.GetFdInfo(in)
+	}
+
+	if out != nil {
+		outFd, isTerminalOut = term.GetFdInfo(out)
+	}
+
+	if err == nil {
+		err = out
+	}
+
+	// The transport is created here for reuse during the client session.
+	tr := &http.Transport{
+		TLSClientConfig: tlsConfig,
+	}
+	utils.ConfigureTCPTransport(tr, proto, addr)
+
+	configFile, e := cliconfig.Load(filepath.Join(homedir.Get(), ".docker"))
+	if e != nil {
+		fmt.Fprintf(err, "WARNING: Error loading config file:%v\n", e)
+	}
+
+	return &DockerCli{
+		proto:         proto,
+		addr:          addr,
+		configFile:    configFile,
+		in:            in,
+		out:           out,
+		err:           err,
+		keyFile:       keyFile,
+		inFd:          inFd,
+		outFd:         outFd,
+		isTerminalIn:  isTerminalIn,
+		isTerminalOut: isTerminalOut,
+		tlsConfig:     tlsConfig,
+		scheme:        scheme,
+		transport:     tr,
+	}
+}

+ 17 - 0
libnetwork/Godeps/_workspace/src/github.com/docker/docker/api/client/client.go

@@ -0,0 +1,17 @@
+// Package client provides a command-line interface for Docker.
+//
+// Run "docker help SUBCOMMAND" or "docker SUBCOMMAND --help" to see more information on any Docker subcommand, including the full list of options supported for the subcommand.
+// See https://docs.docker.com/installation/ for instructions on installing Docker.
+package client
+
+import "fmt"
+
+// An StatusError reports an unsuccessful exit by a command.
+type StatusError struct {
+	Status     string
+	StatusCode int
+}
+
+func (e StatusError) Error() string {
+	return fmt.Sprintf("Status: %s, Code: %d", e.Status, e.StatusCode)
+}

+ 80 - 0
libnetwork/Godeps/_workspace/src/github.com/docker/docker/api/client/commit.go

@@ -0,0 +1,80 @@
+package client
+
+import (
+	"encoding/json"
+	"fmt"
+	"net/url"
+
+	"github.com/docker/docker/api/types"
+	"github.com/docker/docker/opts"
+	flag "github.com/docker/docker/pkg/mflag"
+	"github.com/docker/docker/pkg/parsers"
+	"github.com/docker/docker/registry"
+	"github.com/docker/docker/runconfig"
+)
+
+// CmdCommit creates a new image from a container's changes.
+//
+// Usage: docker commit [OPTIONS] CONTAINER [REPOSITORY[:TAG]]
+func (cli *DockerCli) CmdCommit(args ...string) error {
+	cmd := cli.Subcmd("commit", "CONTAINER [REPOSITORY[:TAG]]", "Create a new image from a container's changes", true)
+	flPause := cmd.Bool([]string{"p", "-pause"}, true, "Pause container during commit")
+	flComment := cmd.String([]string{"m", "-message"}, "", "Commit message")
+	flAuthor := cmd.String([]string{"a", "#author", "-author"}, "", "Author (e.g., \"John Hannibal Smith <hannibal@a-team.com>\")")
+	flChanges := opts.NewListOpts(nil)
+	cmd.Var(&flChanges, []string{"c", "-change"}, "Apply Dockerfile instruction to the created image")
+	// FIXME: --run is deprecated, it will be replaced with inline Dockerfile commands.
+	flConfig := cmd.String([]string{"#run", "#-run"}, "", "This option is deprecated and will be removed in a future version in favor of inline Dockerfile-compatible commands")
+	cmd.Require(flag.Max, 2)
+	cmd.Require(flag.Min, 1)
+	cmd.ParseFlags(args, true)
+
+	var (
+		name            = cmd.Arg(0)
+		repository, tag = parsers.ParseRepositoryTag(cmd.Arg(1))
+	)
+
+	//Check if the given image name can be resolved
+	if repository != "" {
+		if err := registry.ValidateRepositoryName(repository); err != nil {
+			return err
+		}
+	}
+
+	v := url.Values{}
+	v.Set("container", name)
+	v.Set("repo", repository)
+	v.Set("tag", tag)
+	v.Set("comment", *flComment)
+	v.Set("author", *flAuthor)
+	for _, change := range flChanges.GetAll() {
+		v.Add("changes", change)
+	}
+
+	if *flPause != true {
+		v.Set("pause", "0")
+	}
+
+	var (
+		config   *runconfig.Config
+		response types.ContainerCommitResponse
+	)
+
+	if *flConfig != "" {
+		config = &runconfig.Config{}
+		if err := json.Unmarshal([]byte(*flConfig), config); err != nil {
+			return err
+		}
+	}
+	stream, _, _, err := cli.call("POST", "/commit?"+v.Encode(), config, nil)
+	if err != nil {
+		return err
+	}
+
+	if err := json.NewDecoder(stream).Decode(&response); err != nil {
+		return err
+	}
+
+	fmt.Fprintln(cli.out, response.ID)
+	return nil
+}

+ 57 - 0
libnetwork/Godeps/_workspace/src/github.com/docker/docker/api/client/cp.go

@@ -0,0 +1,57 @@
+package client
+
+import (
+	"fmt"
+	"io"
+	"strings"
+
+	"github.com/docker/docker/api/types"
+	"github.com/docker/docker/pkg/archive"
+	flag "github.com/docker/docker/pkg/mflag"
+)
+
+// CmdCp copies files/folders from a path on the container to a directory on the host running the command.
+//
+// If HOSTDIR is '-', the data is written as a tar file to STDOUT.
+//
+// Usage: docker cp CONTAINER:PATH HOSTDIR
+func (cli *DockerCli) CmdCp(args ...string) error {
+	cmd := cli.Subcmd("cp", "CONTAINER:PATH HOSTDIR|-", "Copy files/folders from a PATH on the container to a HOSTDIR on the host\nrunning the command. Use '-' to write the data as a tar file to STDOUT.", true)
+	cmd.Require(flag.Exact, 2)
+
+	cmd.ParseFlags(args, true)
+
+	// deal with path name with `:`
+	info := strings.SplitN(cmd.Arg(0), ":", 2)
+
+	if len(info) != 2 {
+		return fmt.Errorf("Error: Path not specified")
+	}
+
+	cfg := &types.CopyConfig{
+		Resource: info[1],
+	}
+	stream, _, statusCode, err := cli.call("POST", "/containers/"+info[0]+"/copy", cfg, nil)
+	if stream != nil {
+		defer stream.Close()
+	}
+	if statusCode == 404 {
+		return fmt.Errorf("No such container: %v", info[0])
+	}
+	if err != nil {
+		return err
+	}
+
+	hostPath := cmd.Arg(1)
+	if statusCode == 200 {
+		if hostPath == "-" {
+			_, err = io.Copy(cli.out, stream)
+		} else {
+			err = archive.Untar(stream, hostPath, &archive.TarOptions{NoLchown: true})
+		}
+		if err != nil {
+			return err
+		}
+	}
+	return nil
+}

+ 160 - 0
libnetwork/Godeps/_workspace/src/github.com/docker/docker/api/client/create.go

@@ -0,0 +1,160 @@
+package client
+
+import (
+	"encoding/base64"
+	"encoding/json"
+	"fmt"
+	"io"
+	"net/url"
+	"os"
+	"strings"
+
+	"github.com/docker/docker/api/types"
+	"github.com/docker/docker/graph/tags"
+	"github.com/docker/docker/pkg/parsers"
+	"github.com/docker/docker/registry"
+	"github.com/docker/docker/runconfig"
+	"github.com/docker/docker/utils"
+)
+
+func (cli *DockerCli) pullImage(image string) error {
+	return cli.pullImageCustomOut(image, cli.out)
+}
+
+func (cli *DockerCli) pullImageCustomOut(image string, out io.Writer) error {
+	v := url.Values{}
+	repos, tag := parsers.ParseRepositoryTag(image)
+	// pull only the image tagged 'latest' if no tag was specified
+	if tag == "" {
+		tag = tags.DEFAULTTAG
+	}
+	v.Set("fromImage", repos)
+	v.Set("tag", tag)
+
+	// Resolve the Repository name from fqn to RepositoryInfo
+	repoInfo, err := registry.ParseRepositoryInfo(repos)
+	if err != nil {
+		return err
+	}
+
+	// Resolve the Auth config relevant for this server
+	authConfig := registry.ResolveAuthConfig(cli.configFile, repoInfo.Index)
+	buf, err := json.Marshal(authConfig)
+	if err != nil {
+		return err
+	}
+
+	registryAuthHeader := []string{
+		base64.URLEncoding.EncodeToString(buf),
+	}
+	sopts := &streamOpts{
+		rawTerminal: true,
+		out:         out,
+		headers:     map[string][]string{"X-Registry-Auth": registryAuthHeader},
+	}
+	if err := cli.stream("POST", "/images/create?"+v.Encode(), sopts); err != nil {
+		return err
+	}
+	return nil
+}
+
+type cidFile struct {
+	path    string
+	file    *os.File
+	written bool
+}
+
+func newCIDFile(path string) (*cidFile, error) {
+	if _, err := os.Stat(path); err == nil {
+		return nil, fmt.Errorf("Container ID file found, make sure the other container isn't running or delete %s", path)
+	}
+
+	f, err := os.Create(path)
+	if err != nil {
+		return nil, fmt.Errorf("Failed to create the container ID file: %s", err)
+	}
+
+	return &cidFile{path: path, file: f}, nil
+}
+
+func (cli *DockerCli) createContainer(config *runconfig.Config, hostConfig *runconfig.HostConfig, cidfile, name string) (*types.ContainerCreateResponse, error) {
+	containerValues := url.Values{}
+	if name != "" {
+		containerValues.Set("name", name)
+	}
+
+	mergedConfig := runconfig.MergeConfigs(config, hostConfig)
+
+	var containerIDFile *cidFile
+	if cidfile != "" {
+		var err error
+		if containerIDFile, err = newCIDFile(cidfile); err != nil {
+			return nil, err
+		}
+		defer containerIDFile.Close()
+	}
+
+	//create the container
+	stream, _, statusCode, err := cli.call("POST", "/containers/create?"+containerValues.Encode(), mergedConfig, nil)
+	//if image not found try to pull it
+	if statusCode == 404 && strings.Contains(err.Error(), config.Image) {
+		repo, tag := parsers.ParseRepositoryTag(config.Image)
+		if tag == "" {
+			tag = tags.DEFAULTTAG
+		}
+		fmt.Fprintf(cli.err, "Unable to find image '%s' locally\n", utils.ImageReference(repo, tag))
+
+		// we don't want to write to stdout anything apart from container.ID
+		if err = cli.pullImageCustomOut(config.Image, cli.err); err != nil {
+			return nil, err
+		}
+		// Retry
+		if stream, _, _, err = cli.call("POST", "/containers/create?"+containerValues.Encode(), mergedConfig, nil); err != nil {
+			return nil, err
+		}
+	} else if err != nil {
+		return nil, err
+	}
+
+	var response types.ContainerCreateResponse
+	if err := json.NewDecoder(stream).Decode(&response); err != nil {
+		return nil, err
+	}
+	for _, warning := range response.Warnings {
+		fmt.Fprintf(cli.err, "WARNING: %s\n", warning)
+	}
+	if containerIDFile != nil {
+		if err = containerIDFile.Write(response.ID); err != nil {
+			return nil, err
+		}
+	}
+	return &response, nil
+}
+
+// CmdCreate creates a new container from a given image.
+//
+// Usage: docker create [OPTIONS] IMAGE [COMMAND] [ARG...]
+func (cli *DockerCli) CmdCreate(args ...string) error {
+	cmd := cli.Subcmd("create", "IMAGE [COMMAND] [ARG...]", "Create a new container", true)
+
+	// These are flags not stored in Config/HostConfig
+	var (
+		flName = cmd.String([]string{"-name"}, "", "Assign a name to the container")
+	)
+
+	config, hostConfig, cmd, err := runconfig.Parse(cmd, args)
+	if err != nil {
+		cmd.ReportError(err.Error(), true)
+		os.Exit(1)
+	}
+	if config.Image == "" {
+		cmd.Usage()
+		return nil
+	}
+	response, err := cli.createContainer(config, hostConfig, hostConfig.ContainerIDFile, *flName)
+	if err != nil {
+		return err
+	}
+	fmt.Fprintf(cli.out, "%s\n", response.ID)
+	return nil
+}

+ 52 - 0
libnetwork/Godeps/_workspace/src/github.com/docker/docker/api/client/diff.go

@@ -0,0 +1,52 @@
+package client
+
+import (
+	"encoding/json"
+	"fmt"
+
+	"github.com/docker/docker/api/types"
+	"github.com/docker/docker/pkg/archive"
+	flag "github.com/docker/docker/pkg/mflag"
+)
+
+// CmdDiff shows changes on a container's filesystem.
+//
+// Each changed file is printed on a separate line, prefixed with a single
+// character that indicates the status of the file: C (modified), A (added),
+// or D (deleted).
+//
+// Usage: docker diff CONTAINER
+func (cli *DockerCli) CmdDiff(args ...string) error {
+	cmd := cli.Subcmd("diff", "CONTAINER", "Inspect changes on a container's filesystem", true)
+	cmd.Require(flag.Exact, 1)
+	cmd.ParseFlags(args, true)
+
+	if cmd.Arg(0) == "" {
+		return fmt.Errorf("Container name cannot be empty")
+	}
+
+	rdr, _, _, err := cli.call("GET", "/containers/"+cmd.Arg(0)+"/changes", nil, nil)
+	if err != nil {
+		return err
+	}
+
+	changes := []types.ContainerChange{}
+	if err := json.NewDecoder(rdr).Decode(&changes); err != nil {
+		return err
+	}
+
+	for _, change := range changes {
+		var kind string
+		switch change.Kind {
+		case archive.ChangeModify:
+			kind = "C"
+		case archive.ChangeAdd:
+			kind = "A"
+		case archive.ChangeDelete:
+			kind = "D"
+		}
+		fmt.Fprintf(cli.out, "%s %s\n", kind, change.Path)
+	}
+
+	return nil
+}

+ 62 - 0
libnetwork/Godeps/_workspace/src/github.com/docker/docker/api/client/events.go

@@ -0,0 +1,62 @@
+package client
+
+import (
+	"net/url"
+	"time"
+
+	"github.com/docker/docker/opts"
+	flag "github.com/docker/docker/pkg/mflag"
+	"github.com/docker/docker/pkg/parsers/filters"
+	"github.com/docker/docker/pkg/timeutils"
+)
+
+// CmdEvents prints a live stream of real time events from the server.
+//
+// Usage: docker events [OPTIONS]
+func (cli *DockerCli) CmdEvents(args ...string) error {
+	cmd := cli.Subcmd("events", "", "Get real time events from the server", true)
+	since := cmd.String([]string{"#since", "-since"}, "", "Show all events created since timestamp")
+	until := cmd.String([]string{"-until"}, "", "Stream events until this timestamp")
+	flFilter := opts.NewListOpts(nil)
+	cmd.Var(&flFilter, []string{"f", "-filter"}, "Filter output based on conditions provided")
+	cmd.Require(flag.Exact, 0)
+
+	cmd.ParseFlags(args, true)
+
+	var (
+		v               = url.Values{}
+		eventFilterArgs = filters.Args{}
+	)
+
+	// Consolidate all filter flags, and sanity check them early.
+	// They'll get process in the daemon/server.
+	for _, f := range flFilter.GetAll() {
+		var err error
+		eventFilterArgs, err = filters.ParseFlag(f, eventFilterArgs)
+		if err != nil {
+			return err
+		}
+	}
+	ref := time.Now()
+	if *since != "" {
+		v.Set("since", timeutils.GetTimestamp(*since, ref))
+	}
+	if *until != "" {
+		v.Set("until", timeutils.GetTimestamp(*until, ref))
+	}
+	if len(eventFilterArgs) > 0 {
+		filterJSON, err := filters.ToParam(eventFilterArgs)
+		if err != nil {
+			return err
+		}
+		v.Set("filters", filterJSON)
+	}
+	sopts := &streamOpts{
+		rawTerminal: true,
+		out:         cli.out,
+	}
+	if err := cli.stream("GET", "/events?"+v.Encode(), sopts); err != nil {
+		return err
+	}
+	return nil
+}

+ 131 - 0
libnetwork/Godeps/_workspace/src/github.com/docker/docker/api/client/exec.go

@@ -0,0 +1,131 @@
+package client
+
+import (
+	"encoding/json"
+	"fmt"
+	"io"
+
+	"github.com/Sirupsen/logrus"
+	"github.com/docker/docker/api/types"
+	"github.com/docker/docker/pkg/promise"
+	"github.com/docker/docker/runconfig"
+)
+
+// CmdExec runs a command in a running container.
+//
+// Usage: docker exec [OPTIONS] CONTAINER COMMAND [ARG...]
+func (cli *DockerCli) CmdExec(args ...string) error {
+	cmd := cli.Subcmd("exec", "CONTAINER COMMAND [ARG...]", "Run a command in a running container", true)
+
+	execConfig, err := runconfig.ParseExec(cmd, args)
+	// just in case the ParseExec does not exit
+	if execConfig.Container == "" || err != nil {
+		return StatusError{StatusCode: 1}
+	}
+
+	stream, _, _, err := cli.call("POST", "/containers/"+execConfig.Container+"/exec", execConfig, nil)
+	if err != nil {
+		return err
+	}
+
+	var response types.ContainerExecCreateResponse
+	if err := json.NewDecoder(stream).Decode(&response); err != nil {
+		return err
+	}
+
+	execID := response.ID
+
+	if execID == "" {
+		fmt.Fprintf(cli.out, "exec ID empty")
+		return nil
+	}
+
+	//Temp struct for execStart so that we don't need to transfer all the execConfig
+	execStartCheck := &types.ExecStartCheck{
+		Detach: execConfig.Detach,
+		Tty:    execConfig.Tty,
+	}
+
+	if !execConfig.Detach {
+		if err := cli.CheckTtyInput(execConfig.AttachStdin, execConfig.Tty); err != nil {
+			return err
+		}
+	} else {
+		if _, _, err := readBody(cli.call("POST", "/exec/"+execID+"/start", execStartCheck, nil)); err != nil {
+			return err
+		}
+		// For now don't print this - wait for when we support exec wait()
+		// fmt.Fprintf(cli.out, "%s\n", execID)
+		return nil
+	}
+
+	// Interactive exec requested.
+	var (
+		out, stderr io.Writer
+		in          io.ReadCloser
+		hijacked    = make(chan io.Closer)
+		errCh       chan error
+	)
+
+	// Block the return until the chan gets closed
+	defer func() {
+		logrus.Debugf("End of CmdExec(), Waiting for hijack to finish.")
+		if _, ok := <-hijacked; ok {
+			fmt.Fprintln(cli.err, "Hijack did not finish (chan still open)")
+		}
+	}()
+
+	if execConfig.AttachStdin {
+		in = cli.in
+	}
+	if execConfig.AttachStdout {
+		out = cli.out
+	}
+	if execConfig.AttachStderr {
+		if execConfig.Tty {
+			stderr = cli.out
+		} else {
+			stderr = cli.err
+		}
+	}
+	errCh = promise.Go(func() error {
+		return cli.hijack("POST", "/exec/"+execID+"/start", execConfig.Tty, in, out, stderr, hijacked, execConfig)
+	})
+
+	// Acknowledge the hijack before starting
+	select {
+	case closer := <-hijacked:
+		// Make sure that hijack gets closed when returning. (result
+		// in closing hijack chan and freeing server's goroutines.
+		if closer != nil {
+			defer closer.Close()
+		}
+	case err := <-errCh:
+		if err != nil {
+			logrus.Debugf("Error hijack: %s", err)
+			return err
+		}
+	}
+
+	if execConfig.Tty && cli.isTerminalIn {
+		if err := cli.monitorTtySize(execID, true); err != nil {
+			fmt.Fprintf(cli.err, "Error monitoring TTY size: %s\n", err)
+		}
+	}
+
+	if err := <-errCh; err != nil {
+		logrus.Debugf("Error hijack: %s", err)
+		return err
+	}
+
+	var status int
+	if _, status, err = getExecExitCode(cli, execID); err != nil {
+		return err
+	}
+
+	if status != 0 {
+		return StatusError{StatusCode: status}
+	}
+
+	return nil
+}

+ 46 - 0
libnetwork/Godeps/_workspace/src/github.com/docker/docker/api/client/export.go

@@ -0,0 +1,46 @@
+package client
+
+import (
+	"errors"
+	"io"
+	"os"
+
+	flag "github.com/docker/docker/pkg/mflag"
+)
+
+// CmdExport exports a filesystem as a tar archive.
+//
+// The tar archive is streamed to STDOUT by default or written to a file.
+//
+// Usage: docker export [OPTIONS] CONTAINER
+func (cli *DockerCli) CmdExport(args ...string) error {
+	cmd := cli.Subcmd("export", "CONTAINER", "Export a filesystem as a tar archive (streamed to STDOUT by default)", true)
+	outfile := cmd.String([]string{"o", "-output"}, "", "Write to a file, instead of STDOUT")
+	cmd.Require(flag.Exact, 1)
+
+	cmd.ParseFlags(args, true)
+
+	var (
+		output io.Writer = cli.out
+		err    error
+	)
+	if *outfile != "" {
+		output, err = os.Create(*outfile)
+		if err != nil {
+			return err
+		}
+	} else if cli.isTerminalOut {
+		return errors.New("Cowardly refusing to save to a terminal. Use the -o flag or redirect.")
+	}
+
+	image := cmd.Arg(0)
+	sopts := &streamOpts{
+		rawTerminal: true,
+		out:         output,
+	}
+	if err := cli.stream("GET", "/containers/"+image+"/export", sopts); err != nil {
+		return err
+	}
+
+	return nil
+}

+ 34 - 0
libnetwork/Godeps/_workspace/src/github.com/docker/docker/api/client/help.go

@@ -0,0 +1,34 @@
+package client
+
+import (
+	"fmt"
+
+	flag "github.com/docker/docker/pkg/mflag"
+)
+
+// CmdHelp displays information on a Docker command.
+//
+// If more than one command is specified, information is only shown for the first command.
+//
+// Usage: docker help COMMAND or docker COMMAND --help
+func (cli *DockerCli) CmdHelp(args ...string) error {
+	if len(args) > 1 {
+		method, exists := cli.getMethod(args[:2]...)
+		if exists {
+			method("--help")
+			return nil
+		}
+	}
+	if len(args) > 0 {
+		method, exists := cli.getMethod(args[0])
+		if !exists {
+			return fmt.Errorf("docker: '%s' is not a docker command. See 'docker --help'.", args[0])
+		}
+		method("--help")
+		return nil
+	}
+
+	flag.Usage()
+
+	return nil
+}

+ 257 - 0
libnetwork/Godeps/_workspace/src/github.com/docker/docker/api/client/hijack.go

@@ -0,0 +1,257 @@
+package client
+
+import (
+	"crypto/tls"
+	"errors"
+	"fmt"
+	"io"
+	"net"
+	"net/http"
+	"net/http/httputil"
+	"os"
+	"runtime"
+	"strings"
+	"time"
+
+	"github.com/Sirupsen/logrus"
+	"github.com/docker/docker/api"
+	"github.com/docker/docker/autogen/dockerversion"
+	"github.com/docker/docker/pkg/promise"
+	"github.com/docker/docker/pkg/stdcopy"
+	"github.com/docker/docker/pkg/term"
+)
+
+type tlsClientCon struct {
+	*tls.Conn
+	rawConn net.Conn
+}
+
+func (c *tlsClientCon) CloseWrite() error {
+	// Go standard tls.Conn doesn't provide the CloseWrite() method so we do it
+	// on its underlying connection.
+	if cwc, ok := c.rawConn.(interface {
+		CloseWrite() error
+	}); ok {
+		return cwc.CloseWrite()
+	}
+	return nil
+}
+
+func tlsDial(network, addr string, config *tls.Config) (net.Conn, error) {
+	return tlsDialWithDialer(new(net.Dialer), network, addr, config)
+}
+
+// We need to copy Go's implementation of tls.Dial (pkg/cryptor/tls/tls.go) in
+// order to return our custom tlsClientCon struct which holds both the tls.Conn
+// object _and_ its underlying raw connection. The rationale for this is that
+// we need to be able to close the write end of the connection when attaching,
+// which tls.Conn does not provide.
+func tlsDialWithDialer(dialer *net.Dialer, network, addr string, config *tls.Config) (net.Conn, error) {
+	// We want the Timeout and Deadline values from dialer to cover the
+	// whole process: TCP connection and TLS handshake. This means that we
+	// also need to start our own timers now.
+	timeout := dialer.Timeout
+
+	if !dialer.Deadline.IsZero() {
+		deadlineTimeout := dialer.Deadline.Sub(time.Now())
+		if timeout == 0 || deadlineTimeout < timeout {
+			timeout = deadlineTimeout
+		}
+	}
+
+	var errChannel chan error
+
+	if timeout != 0 {
+		errChannel = make(chan error, 2)
+		time.AfterFunc(timeout, func() {
+			errChannel <- errors.New("")
+		})
+	}
+
+	rawConn, err := dialer.Dial(network, addr)
+	if err != nil {
+		return nil, err
+	}
+	// When we set up a TCP connection for hijack, there could be long periods
+	// of inactivity (a long running command with no output) that in certain
+	// network setups may cause ECONNTIMEOUT, leaving the client in an unknown
+	// state. Setting TCP KeepAlive on the socket connection will prohibit
+	// ECONNTIMEOUT unless the socket connection truly is broken
+	if tcpConn, ok := rawConn.(*net.TCPConn); ok {
+		tcpConn.SetKeepAlive(true)
+		tcpConn.SetKeepAlivePeriod(30 * time.Second)
+	}
+
+	colonPos := strings.LastIndex(addr, ":")
+	if colonPos == -1 {
+		colonPos = len(addr)
+	}
+	hostname := addr[:colonPos]
+
+	// If no ServerName is set, infer the ServerName
+	// from the hostname we're connecting to.
+	if config.ServerName == "" {
+		// Make a copy to avoid polluting argument or default.
+		c := *config
+		c.ServerName = hostname
+		config = &c
+	}
+
+	conn := tls.Client(rawConn, config)
+
+	if timeout == 0 {
+		err = conn.Handshake()
+	} else {
+		go func() {
+			errChannel <- conn.Handshake()
+		}()
+
+		err = <-errChannel
+	}
+
+	if err != nil {
+		rawConn.Close()
+		return nil, err
+	}
+
+	// This is Docker difference with standard's crypto/tls package: returned a
+	// wrapper which holds both the TLS and raw connections.
+	return &tlsClientCon{conn, rawConn}, nil
+}
+
+func (cli *DockerCli) dial() (net.Conn, error) {
+	if cli.tlsConfig != nil && cli.proto != "unix" {
+		// Notice this isn't Go standard's tls.Dial function
+		return tlsDial(cli.proto, cli.addr, cli.tlsConfig)
+	}
+	return net.Dial(cli.proto, cli.addr)
+}
+
+func (cli *DockerCli) hijack(method, path string, setRawTerminal bool, in io.ReadCloser, stdout, stderr io.Writer, started chan io.Closer, data interface{}) error {
+	defer func() {
+		if started != nil {
+			close(started)
+		}
+	}()
+
+	params, err := cli.encodeData(data)
+	if err != nil {
+		return err
+	}
+	req, err := http.NewRequest(method, fmt.Sprintf("/v%s%s", api.APIVERSION, path), params)
+	if err != nil {
+		return err
+	}
+
+	// Add CLI Config's HTTP Headers BEFORE we set the Docker headers
+	// then the user can't change OUR headers
+	for k, v := range cli.configFile.HttpHeaders {
+		req.Header.Set(k, v)
+	}
+
+	req.Header.Set("User-Agent", "Docker-Client/"+dockerversion.VERSION+" ("+runtime.GOOS+")")
+	req.Header.Set("Content-Type", "text/plain")
+	req.Header.Set("Connection", "Upgrade")
+	req.Header.Set("Upgrade", "tcp")
+	req.Host = cli.addr
+
+	dial, err := cli.dial()
+	// When we set up a TCP connection for hijack, there could be long periods
+	// of inactivity (a long running command with no output) that in certain
+	// network setups may cause ECONNTIMEOUT, leaving the client in an unknown
+	// state. Setting TCP KeepAlive on the socket connection will prohibit
+	// ECONNTIMEOUT unless the socket connection truly is broken
+	if tcpConn, ok := dial.(*net.TCPConn); ok {
+		tcpConn.SetKeepAlive(true)
+		tcpConn.SetKeepAlivePeriod(30 * time.Second)
+	}
+	if err != nil {
+		if strings.Contains(err.Error(), "connection refused") {
+			return fmt.Errorf("Cannot connect to the Docker daemon. Is 'docker -d' running on this host?")
+		}
+		return err
+	}
+	clientconn := httputil.NewClientConn(dial, nil)
+	defer clientconn.Close()
+
+	// Server hijacks the connection, error 'connection closed' expected
+	clientconn.Do(req)
+
+	rwc, br := clientconn.Hijack()
+	defer rwc.Close()
+
+	if started != nil {
+		started <- rwc
+	}
+
+	var receiveStdout chan error
+
+	var oldState *term.State
+
+	if in != nil && setRawTerminal && cli.isTerminalIn && os.Getenv("NORAW") == "" {
+		oldState, err = term.SetRawTerminal(cli.inFd)
+		if err != nil {
+			return err
+		}
+		defer term.RestoreTerminal(cli.inFd, oldState)
+	}
+
+	if stdout != nil || stderr != nil {
+		receiveStdout = promise.Go(func() (err error) {
+			defer func() {
+				if in != nil {
+					if setRawTerminal && cli.isTerminalIn {
+						term.RestoreTerminal(cli.inFd, oldState)
+					}
+					// For some reason this Close call blocks on darwin..
+					// As the client exists right after, simply discard the close
+					// until we find a better solution.
+					if runtime.GOOS != "darwin" {
+						in.Close()
+					}
+				}
+			}()
+
+			// When TTY is ON, use regular copy
+			if setRawTerminal && stdout != nil {
+				_, err = io.Copy(stdout, br)
+			} else {
+				_, err = stdcopy.StdCopy(stdout, stderr, br)
+			}
+			logrus.Debugf("[hijack] End of stdout")
+			return err
+		})
+	}
+
+	sendStdin := promise.Go(func() error {
+		if in != nil {
+			io.Copy(rwc, in)
+			logrus.Debugf("[hijack] End of stdin")
+		}
+
+		if conn, ok := rwc.(interface {
+			CloseWrite() error
+		}); ok {
+			if err := conn.CloseWrite(); err != nil {
+				logrus.Debugf("Couldn't send EOF: %s", err)
+			}
+		}
+		// Discard errors due to pipe interruption
+		return nil
+	})
+
+	if stdout != nil || stderr != nil {
+		if err := <-receiveStdout; err != nil {
+			logrus.Debugf("Error receiveStdout: %s", err)
+			return err
+		}
+	}
+
+	if !cli.isTerminalIn {
+		if err := <-sendStdin; err != nil {
+			logrus.Debugf("Error sendStdin: %s", err)
+			return err
+		}
+	}
+	return nil
+}

+ 73 - 0
libnetwork/Godeps/_workspace/src/github.com/docker/docker/api/client/history.go

@@ -0,0 +1,73 @@
+package client
+
+import (
+	"encoding/json"
+	"fmt"
+	"text/tabwriter"
+	"time"
+
+	"github.com/docker/docker/api/types"
+	flag "github.com/docker/docker/pkg/mflag"
+	"github.com/docker/docker/pkg/stringid"
+	"github.com/docker/docker/pkg/stringutils"
+	"github.com/docker/docker/pkg/units"
+)
+
+// CmdHistory shows the history of an image.
+//
+// Usage: docker history [OPTIONS] IMAGE
+func (cli *DockerCli) CmdHistory(args ...string) error {
+	cmd := cli.Subcmd("history", "IMAGE", "Show the history of an image", true)
+	human := cmd.Bool([]string{"H", "-human"}, true, "Print sizes and dates in human readable format")
+	quiet := cmd.Bool([]string{"q", "-quiet"}, false, "Only show numeric IDs")
+	noTrunc := cmd.Bool([]string{"#notrunc", "-no-trunc"}, false, "Don't truncate output")
+	cmd.Require(flag.Exact, 1)
+	cmd.ParseFlags(args, true)
+
+	rdr, _, _, err := cli.call("GET", "/images/"+cmd.Arg(0)+"/history", nil, nil)
+	if err != nil {
+		return err
+	}
+
+	history := []types.ImageHistory{}
+	if err := json.NewDecoder(rdr).Decode(&history); err != nil {
+		return err
+	}
+
+	w := tabwriter.NewWriter(cli.out, 20, 1, 3, ' ', 0)
+	if !*quiet {
+		fmt.Fprintln(w, "IMAGE\tCREATED\tCREATED BY\tSIZE\tCOMMENT")
+	}
+
+	for _, entry := range history {
+		if *noTrunc {
+			fmt.Fprintf(w, entry.ID)
+		} else {
+			fmt.Fprintf(w, stringid.TruncateID(entry.ID))
+		}
+		if !*quiet {
+			if *human {
+				fmt.Fprintf(w, "\t%s ago\t", units.HumanDuration(time.Now().UTC().Sub(time.Unix(entry.Created, 0))))
+			} else {
+				fmt.Fprintf(w, "\t%s\t", time.Unix(entry.Created, 0).Format(time.RFC3339))
+			}
+
+			if *noTrunc {
+				fmt.Fprintf(w, "%s\t", entry.CreatedBy)
+			} else {
+				fmt.Fprintf(w, "%s\t", stringutils.Truncate(entry.CreatedBy, 45))
+			}
+
+			if *human {
+				fmt.Fprintf(w, "%s\t", units.HumanSize(float64(entry.Size)))
+			} else {
+				fmt.Fprintf(w, "%d\t", entry.Size)
+			}
+
+			fmt.Fprintf(w, "%s", entry.Comment)
+		}
+		fmt.Fprintf(w, "\n")
+	}
+	w.Flush()
+	return nil
+}

+ 126 - 0
libnetwork/Godeps/_workspace/src/github.com/docker/docker/api/client/images.go

@@ -0,0 +1,126 @@
+package client
+
+import (
+	"encoding/json"
+	"fmt"
+	"net/url"
+	"text/tabwriter"
+	"time"
+
+	"github.com/docker/docker/api/types"
+	"github.com/docker/docker/opts"
+	flag "github.com/docker/docker/pkg/mflag"
+	"github.com/docker/docker/pkg/parsers"
+	"github.com/docker/docker/pkg/parsers/filters"
+	"github.com/docker/docker/pkg/stringid"
+	"github.com/docker/docker/pkg/units"
+	"github.com/docker/docker/utils"
+)
+
+// CmdImages lists the images in a specified repository, or all top-level images if no repository is specified.
+//
+// Usage: docker images [OPTIONS] [REPOSITORY]
+func (cli *DockerCli) CmdImages(args ...string) error {
+	cmd := cli.Subcmd("images", "[REPOSITORY]", "List images", true)
+	quiet := cmd.Bool([]string{"q", "-quiet"}, false, "Only show numeric IDs")
+	all := cmd.Bool([]string{"a", "-all"}, false, "Show all images (default hides intermediate images)")
+	noTrunc := cmd.Bool([]string{"#notrunc", "-no-trunc"}, false, "Don't truncate output")
+	showDigests := cmd.Bool([]string{"-digests"}, false, "Show digests")
+
+	flFilter := opts.NewListOpts(nil)
+	cmd.Var(&flFilter, []string{"f", "-filter"}, "Filter output based on conditions provided")
+	cmd.Require(flag.Max, 1)
+	cmd.ParseFlags(args, true)
+
+	// Consolidate all filter flags, and sanity check them early.
+	// They'll get process in the daemon/server.
+	imageFilterArgs := filters.Args{}
+	for _, f := range flFilter.GetAll() {
+		var err error
+		imageFilterArgs, err = filters.ParseFlag(f, imageFilterArgs)
+		if err != nil {
+			return err
+		}
+	}
+
+	matchName := cmd.Arg(0)
+	v := url.Values{}
+	if len(imageFilterArgs) > 0 {
+		filterJSON, err := filters.ToParam(imageFilterArgs)
+		if err != nil {
+			return err
+		}
+		v.Set("filters", filterJSON)
+	}
+
+	if cmd.NArg() == 1 {
+		// FIXME rename this parameter, to not be confused with the filters flag
+		v.Set("filter", matchName)
+	}
+	if *all {
+		v.Set("all", "1")
+	}
+
+	rdr, _, _, err := cli.call("GET", "/images/json?"+v.Encode(), nil, nil)
+	if err != nil {
+		return err
+	}
+
+	images := []types.Image{}
+	if err := json.NewDecoder(rdr).Decode(&images); err != nil {
+		return err
+	}
+
+	w := tabwriter.NewWriter(cli.out, 20, 1, 3, ' ', 0)
+	if !*quiet {
+		if *showDigests {
+			fmt.Fprintln(w, "REPOSITORY\tTAG\tDIGEST\tIMAGE ID\tCREATED\tVIRTUAL SIZE")
+		} else {
+			fmt.Fprintln(w, "REPOSITORY\tTAG\tIMAGE ID\tCREATED\tVIRTUAL SIZE")
+		}
+	}
+
+	for _, image := range images {
+		ID := image.ID
+		if !*noTrunc {
+			ID = stringid.TruncateID(ID)
+		}
+
+		repoTags := image.RepoTags
+		repoDigests := image.RepoDigests
+
+		if len(repoTags) == 1 && repoTags[0] == "<none>:<none>" && len(repoDigests) == 1 && repoDigests[0] == "<none>@<none>" {
+			// dangling image - clear out either repoTags or repoDigsts so we only show it once below
+			repoDigests = []string{}
+		}
+
+		// combine the tags and digests lists
+		tagsAndDigests := append(repoTags, repoDigests...)
+		for _, repoAndRef := range tagsAndDigests {
+			repo, ref := parsers.ParseRepositoryTag(repoAndRef)
+			// default tag and digest to none - if there's a value, it'll be set below
+			tag := "<none>"
+			digest := "<none>"
+			if utils.DigestReference(ref) {
+				digest = ref
+			} else {
+				tag = ref
+			}
+
+			if !*quiet {
+				if *showDigests {
+					fmt.Fprintf(w, "%s\t%s\t%s\t%s\t%s ago\t%s\n", repo, tag, digest, ID, units.HumanDuration(time.Now().UTC().Sub(time.Unix(int64(image.Created), 0))), units.HumanSize(float64(image.VirtualSize)))
+				} else {
+					fmt.Fprintf(w, "%s\t%s\t%s\t%s ago\t%s\n", repo, tag, ID, units.HumanDuration(time.Now().UTC().Sub(time.Unix(int64(image.Created), 0))), units.HumanSize(float64(image.VirtualSize)))
+				}
+			} else {
+				fmt.Fprintln(w, ID)
+			}
+		}
+	}
+
+	if !*quiet {
+		w.Flush()
+	}
+	return nil
+}

+ 64 - 0
libnetwork/Godeps/_workspace/src/github.com/docker/docker/api/client/import.go

@@ -0,0 +1,64 @@
+package client
+
+import (
+	"fmt"
+	"io"
+	"net/url"
+
+	"github.com/docker/docker/opts"
+	flag "github.com/docker/docker/pkg/mflag"
+	"github.com/docker/docker/pkg/parsers"
+	"github.com/docker/docker/registry"
+)
+
+// CmdImport creates an empty filesystem image, imports the contents of the tarball into the image, and optionally tags the image.
+//
+// The URL argument is the address of a tarball (.tar, .tar.gz, .tgz, .bzip, .tar.xz, .txz) file. If the URL is '-', then the tar file is read from STDIN.
+//
+// Usage: docker import [OPTIONS] URL [REPOSITORY[:TAG]]
+func (cli *DockerCli) CmdImport(args ...string) error {
+	cmd := cli.Subcmd("import", "URL|- [REPOSITORY[:TAG]]", "Create an empty filesystem image and import the contents of the\ntarball (.tar, .tar.gz, .tgz, .bzip, .tar.xz, .txz) into it, then\noptionally tag it.", true)
+	flChanges := opts.NewListOpts(nil)
+	cmd.Var(&flChanges, []string{"c", "-change"}, "Apply Dockerfile instruction to the created image")
+	cmd.Require(flag.Min, 1)
+
+	cmd.ParseFlags(args, true)
+
+	var (
+		v          = url.Values{}
+		src        = cmd.Arg(0)
+		repository = cmd.Arg(1)
+	)
+
+	v.Set("fromSrc", src)
+	v.Set("repo", repository)
+	for _, change := range flChanges.GetAll() {
+		v.Add("changes", change)
+	}
+	if cmd.NArg() == 3 {
+		fmt.Fprintf(cli.err, "[DEPRECATED] The format 'URL|- [REPOSITORY [TAG]]' has been deprecated. Please use URL|- [REPOSITORY[:TAG]]\n")
+		v.Set("tag", cmd.Arg(2))
+	}
+
+	if repository != "" {
+		//Check if the given image name can be resolved
+		repo, _ := parsers.ParseRepositoryTag(repository)
+		if err := registry.ValidateRepositoryName(repo); err != nil {
+			return err
+		}
+	}
+
+	var in io.Reader
+
+	if src == "-" {
+		in = cli.in
+	}
+
+	sopts := &streamOpts{
+		rawTerminal: true,
+		in:          in,
+		out:         cli.out,
+	}
+
+	return cli.stream("POST", "/images/create?"+v.Encode(), sopts)
+}

+ 91 - 0
libnetwork/Godeps/_workspace/src/github.com/docker/docker/api/client/info.go

@@ -0,0 +1,91 @@
+package client
+
+import (
+	"encoding/json"
+	"fmt"
+
+	"github.com/docker/docker/api/types"
+	"github.com/docker/docker/pkg/ioutils"
+	flag "github.com/docker/docker/pkg/mflag"
+	"github.com/docker/docker/pkg/units"
+)
+
+// CmdInfo displays system-wide information.
+//
+// Usage: docker info
+func (cli *DockerCli) CmdInfo(args ...string) error {
+	cmd := cli.Subcmd("info", "", "Display system-wide information", true)
+	cmd.Require(flag.Exact, 0)
+	cmd.ParseFlags(args, true)
+
+	rdr, _, _, err := cli.call("GET", "/info", nil, nil)
+	if err != nil {
+		return err
+	}
+
+	info := &types.Info{}
+	if err := json.NewDecoder(rdr).Decode(info); err != nil {
+		return fmt.Errorf("Error reading remote info: %v", err)
+	}
+
+	fmt.Fprintf(cli.out, "Containers: %d\n", info.Containers)
+	fmt.Fprintf(cli.out, "Images: %d\n", info.Images)
+	ioutils.FprintfIfNotEmpty(cli.out, "Storage Driver: %s\n", info.Driver)
+	if info.DriverStatus != nil {
+		for _, pair := range info.DriverStatus {
+			fmt.Fprintf(cli.out, " %s: %s\n", pair[0], pair[1])
+		}
+	}
+	ioutils.FprintfIfNotEmpty(cli.out, "Execution Driver: %s\n", info.ExecutionDriver)
+	ioutils.FprintfIfNotEmpty(cli.out, "Logging Driver: %s\n", info.LoggingDriver)
+	ioutils.FprintfIfNotEmpty(cli.out, "Kernel Version: %s\n", info.KernelVersion)
+	ioutils.FprintfIfNotEmpty(cli.out, "Operating System: %s\n", info.OperatingSystem)
+	fmt.Fprintf(cli.out, "CPUs: %d\n", info.NCPU)
+	fmt.Fprintf(cli.out, "Total Memory: %s\n", units.BytesSize(float64(info.MemTotal)))
+	ioutils.FprintfIfNotEmpty(cli.out, "Name: %s\n", info.Name)
+	ioutils.FprintfIfNotEmpty(cli.out, "ID: %s\n", info.ID)
+
+	if info.Debug {
+		fmt.Fprintf(cli.out, "Debug mode (server): %v\n", info.Debug)
+		fmt.Fprintf(cli.out, "File Descriptors: %d\n", info.NFd)
+		fmt.Fprintf(cli.out, "Goroutines: %d\n", info.NGoroutines)
+		fmt.Fprintf(cli.out, "System Time: %s\n", info.SystemTime)
+		fmt.Fprintf(cli.out, "EventsListeners: %d\n", info.NEventsListener)
+		fmt.Fprintf(cli.out, "Init SHA1: %s\n", info.InitSha1)
+		fmt.Fprintf(cli.out, "Init Path: %s\n", info.InitPath)
+		fmt.Fprintf(cli.out, "Docker Root Dir: %s\n", info.DockerRootDir)
+	}
+
+	ioutils.FprintfIfNotEmpty(cli.out, "Http Proxy: %s\n", info.HttpProxy)
+	ioutils.FprintfIfNotEmpty(cli.out, "Https Proxy: %s\n", info.HttpsProxy)
+	ioutils.FprintfIfNotEmpty(cli.out, "No Proxy: %s\n", info.NoProxy)
+
+	if info.IndexServerAddress != "" {
+		u := cli.configFile.AuthConfigs[info.IndexServerAddress].Username
+		if len(u) > 0 {
+			fmt.Fprintf(cli.out, "Username: %v\n", u)
+			fmt.Fprintf(cli.out, "Registry: %v\n", info.IndexServerAddress)
+		}
+	}
+	if !info.MemoryLimit {
+		fmt.Fprintf(cli.err, "WARNING: No memory limit support\n")
+	}
+	if !info.SwapLimit {
+		fmt.Fprintf(cli.err, "WARNING: No swap limit support\n")
+	}
+	if !info.IPv4Forwarding {
+		fmt.Fprintf(cli.err, "WARNING: IPv4 forwarding is disabled.\n")
+	}
+	if info.Labels != nil {
+		fmt.Fprintln(cli.out, "Labels:")
+		for _, attribute := range info.Labels {
+			fmt.Fprintf(cli.out, " %s\n", attribute)
+		}
+	}
+
+	if info.ExperimentalBuild {
+		fmt.Fprintf(cli.out, "Experimental: true\n")
+	}
+
+	return nil
+}

+ 124 - 0
libnetwork/Godeps/_workspace/src/github.com/docker/docker/api/client/inspect.go

@@ -0,0 +1,124 @@
+package client
+
+import (
+	"bytes"
+	"encoding/json"
+	"fmt"
+	"io"
+	"strings"
+	"text/template"
+
+	"github.com/docker/docker/api/types"
+	flag "github.com/docker/docker/pkg/mflag"
+)
+
+// CmdInspect displays low-level information on one or more containers or images.
+//
+// Usage: docker inspect [OPTIONS] CONTAINER|IMAGE [CONTAINER|IMAGE...]
+func (cli *DockerCli) CmdInspect(args ...string) error {
+	cmd := cli.Subcmd("inspect", "CONTAINER|IMAGE [CONTAINER|IMAGE...]", "Return low-level information on a container or image", true)
+	tmplStr := cmd.String([]string{"f", "#format", "-format"}, "", "Format the output using the given go template")
+	cmd.Require(flag.Min, 1)
+
+	cmd.ParseFlags(args, true)
+
+	var tmpl *template.Template
+	if *tmplStr != "" {
+		var err error
+		if tmpl, err = template.New("").Funcs(funcMap).Parse(*tmplStr); err != nil {
+			return StatusError{StatusCode: 64,
+				Status: "Template parsing error: " + err.Error()}
+		}
+	}
+
+	indented := new(bytes.Buffer)
+	indented.WriteString("[\n")
+	status := 0
+	isImage := false
+
+	for _, name := range cmd.Args() {
+		obj, _, err := readBody(cli.call("GET", "/containers/"+name+"/json", nil, nil))
+		if err != nil {
+			obj, _, err = readBody(cli.call("GET", "/images/"+name+"/json", nil, nil))
+			isImage = true
+			if err != nil {
+				if strings.Contains(err.Error(), "No such") {
+					fmt.Fprintf(cli.err, "Error: No such image or container: %s\n", name)
+				} else {
+					fmt.Fprintf(cli.err, "%s", err)
+				}
+				status = 1
+				continue
+			}
+		}
+
+		if tmpl == nil {
+			if err = json.Indent(indented, obj, "", "    "); err != nil {
+				fmt.Fprintf(cli.err, "%s\n", err)
+				status = 1
+				continue
+			}
+		} else {
+			rdr := bytes.NewReader(obj)
+			dec := json.NewDecoder(rdr)
+
+			if isImage {
+				inspPtr := types.ImageInspect{}
+				if err := dec.Decode(&inspPtr); err != nil {
+					fmt.Fprintf(cli.err, "%s\n", err)
+					status = 1
+					continue
+				}
+				if err := tmpl.Execute(cli.out, inspPtr); err != nil {
+					rdr.Seek(0, 0)
+					var raw interface{}
+					if err := dec.Decode(&raw); err != nil {
+						return err
+					}
+					if err = tmpl.Execute(cli.out, raw); err != nil {
+						return err
+					}
+				}
+			} else {
+				inspPtr := types.ContainerJSON{}
+				if err := dec.Decode(&inspPtr); err != nil {
+					fmt.Fprintf(cli.err, "%s\n", err)
+					status = 1
+					continue
+				}
+				if err := tmpl.Execute(cli.out, inspPtr); err != nil {
+					rdr.Seek(0, 0)
+					var raw interface{}
+					if err := dec.Decode(&raw); err != nil {
+						return err
+					}
+					if err = tmpl.Execute(cli.out, raw); err != nil {
+						return err
+					}
+				}
+			}
+			cli.out.Write([]byte{'\n'})
+		}
+		indented.WriteString(",")
+	}
+
+	if indented.Len() > 1 {
+		// Remove trailing ','
+		indented.Truncate(indented.Len() - 1)
+	}
+	indented.WriteString("]\n")
+
+	if tmpl == nil {
+		// Note that we will always write "[]" when "-f" isn't specified,
+		// to make sure the output would always be array, see
+		// https://github.com/docker/docker/pull/9500#issuecomment-65846734
+		if _, err := io.Copy(cli.out, indented); err != nil {
+			return err
+		}
+	}
+
+	if status != 0 {
+		return StatusError{StatusCode: status}
+	}
+	return nil
+}

+ 32 - 0
libnetwork/Godeps/_workspace/src/github.com/docker/docker/api/client/kill.go

@@ -0,0 +1,32 @@
+package client
+
+import (
+	"fmt"
+
+	flag "github.com/docker/docker/pkg/mflag"
+)
+
+// CmdKill kills one or more running container using SIGKILL or a specified signal.
+//
+// Usage: docker kill [OPTIONS] CONTAINER [CONTAINER...]
+func (cli *DockerCli) CmdKill(args ...string) error {
+	cmd := cli.Subcmd("kill", "CONTAINER [CONTAINER...]", "Kill a running container using SIGKILL or a specified signal", true)
+	signal := cmd.String([]string{"s", "-signal"}, "KILL", "Signal to send to the container")
+	cmd.Require(flag.Min, 1)
+
+	cmd.ParseFlags(args, true)
+
+	var errNames []string
+	for _, name := range cmd.Args() {
+		if _, _, err := readBody(cli.call("POST", fmt.Sprintf("/containers/%s/kill?signal=%s", name, *signal), nil, nil)); err != nil {
+			fmt.Fprintf(cli.err, "%s\n", err)
+			errNames = append(errNames, name)
+		} else {
+			fmt.Fprintf(cli.out, "%s\n", name)
+		}
+	}
+	if len(errNames) > 0 {
+		return fmt.Errorf("Error: failed to kill containers: %v", errNames)
+	}
+	return nil
+}

+ 41 - 0
libnetwork/Godeps/_workspace/src/github.com/docker/docker/api/client/load.go

@@ -0,0 +1,41 @@
+package client
+
+import (
+	"io"
+	"os"
+
+	flag "github.com/docker/docker/pkg/mflag"
+)
+
+// CmdLoad loads an image from a tar archive.
+//
+// The tar archive is read from STDIN by default, or from a tar archive file.
+//
+// Usage: docker load [OPTIONS]
+func (cli *DockerCli) CmdLoad(args ...string) error {
+	cmd := cli.Subcmd("load", "", "Load an image from a tar archive on STDIN", true)
+	infile := cmd.String([]string{"i", "-input"}, "", "Read from a tar archive file, instead of STDIN")
+	cmd.Require(flag.Exact, 0)
+
+	cmd.ParseFlags(args, true)
+
+	var (
+		input io.Reader = cli.in
+		err   error
+	)
+	if *infile != "" {
+		input, err = os.Open(*infile)
+		if err != nil {
+			return err
+		}
+	}
+	sopts := &streamOpts{
+		rawTerminal: true,
+		in:          input,
+		out:         cli.out,
+	}
+	if err := cli.stream("POST", "/images/load", sopts); err != nil {
+		return err
+	}
+	return nil
+}

+ 144 - 0
libnetwork/Godeps/_workspace/src/github.com/docker/docker/api/client/login.go

@@ -0,0 +1,144 @@
+package client
+
+import (
+	"bufio"
+	"encoding/json"
+	"fmt"
+	"io"
+	"os"
+	"strings"
+
+	"github.com/docker/docker/api/types"
+	"github.com/docker/docker/cliconfig"
+	flag "github.com/docker/docker/pkg/mflag"
+	"github.com/docker/docker/pkg/term"
+	"github.com/docker/docker/registry"
+)
+
+// CmdLogin logs in or registers a user to a Docker registry service.
+//
+// If no server is specified, the user will be logged into or registered to the registry's index server.
+//
+// Usage: docker login SERVER
+func (cli *DockerCli) CmdLogin(args ...string) error {
+	cmd := cli.Subcmd("login", "[SERVER]", "Register or log in to a Docker registry server, if no server is\nspecified \""+registry.IndexServerAddress()+"\" is the default.", true)
+	cmd.Require(flag.Max, 1)
+
+	var username, password, email string
+
+	cmd.StringVar(&username, []string{"u", "-username"}, "", "Username")
+	cmd.StringVar(&password, []string{"p", "-password"}, "", "Password")
+	cmd.StringVar(&email, []string{"e", "-email"}, "", "Email")
+
+	cmd.ParseFlags(args, true)
+
+	serverAddress := registry.IndexServerAddress()
+	if len(cmd.Args()) > 0 {
+		serverAddress = cmd.Arg(0)
+	}
+
+	promptDefault := func(prompt string, configDefault string) {
+		if configDefault == "" {
+			fmt.Fprintf(cli.out, "%s: ", prompt)
+		} else {
+			fmt.Fprintf(cli.out, "%s (%s): ", prompt, configDefault)
+		}
+	}
+
+	readInput := func(in io.Reader, out io.Writer) string {
+		reader := bufio.NewReader(in)
+		line, _, err := reader.ReadLine()
+		if err != nil {
+			fmt.Fprintln(out, err.Error())
+			os.Exit(1)
+		}
+		return string(line)
+	}
+
+	authconfig, ok := cli.configFile.AuthConfigs[serverAddress]
+	if !ok {
+		authconfig = cliconfig.AuthConfig{}
+	}
+
+	if username == "" {
+		promptDefault("Username", authconfig.Username)
+		username = readInput(cli.in, cli.out)
+		username = strings.Trim(username, " ")
+		if username == "" {
+			username = authconfig.Username
+		}
+	}
+	// Assume that a different username means they may not want to use
+	// the password or email from the config file, so prompt them
+	if username != authconfig.Username {
+		if password == "" {
+			oldState, err := term.SaveState(cli.inFd)
+			if err != nil {
+				return err
+			}
+			fmt.Fprintf(cli.out, "Password: ")
+			term.DisableEcho(cli.inFd, oldState)
+
+			password = readInput(cli.in, cli.out)
+			fmt.Fprint(cli.out, "\n")
+
+			term.RestoreTerminal(cli.inFd, oldState)
+			if password == "" {
+				return fmt.Errorf("Error : Password Required")
+			}
+		}
+
+		if email == "" {
+			promptDefault("Email", authconfig.Email)
+			email = readInput(cli.in, cli.out)
+			if email == "" {
+				email = authconfig.Email
+			}
+		}
+	} else {
+		// However, if they don't override the username use the
+		// password or email from the cmd line if specified. IOW, allow
+		// then to change/override them.  And if not specified, just
+		// use what's in the config file
+		if password == "" {
+			password = authconfig.Password
+		}
+		if email == "" {
+			email = authconfig.Email
+		}
+	}
+	authconfig.Username = username
+	authconfig.Password = password
+	authconfig.Email = email
+	authconfig.ServerAddress = serverAddress
+	cli.configFile.AuthConfigs[serverAddress] = authconfig
+
+	stream, _, statusCode, err := cli.call("POST", "/auth", cli.configFile.AuthConfigs[serverAddress], nil)
+	if statusCode == 401 {
+		delete(cli.configFile.AuthConfigs, serverAddress)
+		if err2 := cli.configFile.Save(); err2 != nil {
+			fmt.Fprintf(cli.out, "WARNING: could not save config file: %v\n", err2)
+		}
+		return err
+	}
+	if err != nil {
+		return err
+	}
+
+	var response types.AuthResponse
+	if err := json.NewDecoder(stream).Decode(&response); err != nil {
+		// Upon error, remove entry
+		delete(cli.configFile.AuthConfigs, serverAddress)
+		return err
+	}
+
+	if err := cli.configFile.Save(); err != nil {
+		return fmt.Errorf("Error saving config file: %v", err)
+	}
+	fmt.Fprintf(cli.out, "WARNING: login credentials saved in %s\n", cli.configFile.Filename())
+
+	if response.Status != "" {
+		fmt.Fprintf(cli.out, "%s\n", response.Status)
+	}
+	return nil
+}

+ 36 - 0
libnetwork/Godeps/_workspace/src/github.com/docker/docker/api/client/logout.go

@@ -0,0 +1,36 @@
+package client
+
+import (
+	"fmt"
+
+	flag "github.com/docker/docker/pkg/mflag"
+	"github.com/docker/docker/registry"
+)
+
+// CmdLogout logs a user out from a Docker registry.
+//
+// If no server is specified, the user will be logged out from the registry's index server.
+//
+// Usage: docker logout [SERVER]
+func (cli *DockerCli) CmdLogout(args ...string) error {
+	cmd := cli.Subcmd("logout", "[SERVER]", "Log out from a Docker registry, if no server is\nspecified \""+registry.IndexServerAddress()+"\" is the default.", true)
+	cmd.Require(flag.Max, 1)
+
+	cmd.ParseFlags(args, true)
+	serverAddress := registry.IndexServerAddress()
+	if len(cmd.Args()) > 0 {
+		serverAddress = cmd.Arg(0)
+	}
+
+	if _, ok := cli.configFile.AuthConfigs[serverAddress]; !ok {
+		fmt.Fprintf(cli.out, "Not logged in to %s\n", serverAddress)
+	} else {
+		fmt.Fprintf(cli.out, "Remove login credentials for %s\n", serverAddress)
+		delete(cli.configFile.AuthConfigs, serverAddress)
+
+		if err := cli.configFile.Save(); err != nil {
+			return fmt.Errorf("Failed to save docker config: %v", err)
+		}
+	}
+	return nil
+}

+ 69 - 0
libnetwork/Godeps/_workspace/src/github.com/docker/docker/api/client/logs.go

@@ -0,0 +1,69 @@
+package client
+
+import (
+	"encoding/json"
+	"fmt"
+	"net/url"
+	"time"
+
+	"github.com/docker/docker/api/types"
+	flag "github.com/docker/docker/pkg/mflag"
+	"github.com/docker/docker/pkg/timeutils"
+)
+
+// CmdLogs fetches the logs of a given container.
+//
+// docker logs [OPTIONS] CONTAINER
+func (cli *DockerCli) CmdLogs(args ...string) error {
+	var (
+		cmd    = cli.Subcmd("logs", "CONTAINER", "Fetch the logs of a container", true)
+		follow = cmd.Bool([]string{"f", "-follow"}, false, "Follow log output")
+		since  = cmd.String([]string{"-since"}, "", "Show logs since timestamp")
+		times  = cmd.Bool([]string{"t", "-timestamps"}, false, "Show timestamps")
+		tail   = cmd.String([]string{"-tail"}, "all", "Number of lines to show from the end of the logs")
+	)
+	cmd.Require(flag.Exact, 1)
+
+	cmd.ParseFlags(args, true)
+
+	name := cmd.Arg(0)
+
+	stream, _, _, err := cli.call("GET", "/containers/"+name+"/json", nil, nil)
+	if err != nil {
+		return err
+	}
+
+	var c types.ContainerJSON
+	if err := json.NewDecoder(stream).Decode(&c); err != nil {
+		return err
+	}
+
+	if logType := c.HostConfig.LogConfig.Type; logType != "json-file" {
+		return fmt.Errorf("\"logs\" command is supported only for \"json-file\" logging driver (got: %s)", logType)
+	}
+
+	v := url.Values{}
+	v.Set("stdout", "1")
+	v.Set("stderr", "1")
+
+	if *since != "" {
+		v.Set("since", timeutils.GetTimestamp(*since, time.Now()))
+	}
+
+	if *times {
+		v.Set("timestamps", "1")
+	}
+
+	if *follow {
+		v.Set("follow", "1")
+	}
+	v.Set("tail", *tail)
+
+	sopts := &streamOpts{
+		rawTerminal: c.Config.Tty,
+		out:         cli.out,
+		err:         cli.err,
+	}
+
+	return cli.stream("GET", "/containers/"+name+"/logs?"+v.Encode(), sopts)
+}

+ 30 - 0
libnetwork/Godeps/_workspace/src/github.com/docker/docker/api/client/pause.go

@@ -0,0 +1,30 @@
+package client
+
+import (
+	"fmt"
+
+	flag "github.com/docker/docker/pkg/mflag"
+)
+
+// CmdPause pauses all processes within one or more containers.
+//
+// Usage: docker pause CONTAINER [CONTAINER...]
+func (cli *DockerCli) CmdPause(args ...string) error {
+	cmd := cli.Subcmd("pause", "CONTAINER [CONTAINER...]", "Pause all processes within a container", true)
+	cmd.Require(flag.Min, 1)
+	cmd.ParseFlags(args, true)
+
+	var errNames []string
+	for _, name := range cmd.Args() {
+		if _, _, err := readBody(cli.call("POST", fmt.Sprintf("/containers/%s/pause", name), nil, nil)); err != nil {
+			fmt.Fprintf(cli.err, "%s\n", err)
+			errNames = append(errNames, name)
+		} else {
+			fmt.Fprintf(cli.out, "%s\n", name)
+		}
+	}
+	if len(errNames) > 0 {
+		return fmt.Errorf("Error: failed to pause containers: %v", errNames)
+	}
+	return nil
+}

+ 64 - 0
libnetwork/Godeps/_workspace/src/github.com/docker/docker/api/client/port.go

@@ -0,0 +1,64 @@
+package client
+
+import (
+	"encoding/json"
+	"fmt"
+	"strings"
+
+	"github.com/docker/docker/nat"
+	flag "github.com/docker/docker/pkg/mflag"
+)
+
+// CmdPort lists port mappings for a container.
+// If a private port is specified, it also shows the public-facing port that is NATed to the private port.
+//
+// Usage: docker port CONTAINER [PRIVATE_PORT[/PROTO]]
+func (cli *DockerCli) CmdPort(args ...string) error {
+	cmd := cli.Subcmd("port", "CONTAINER [PRIVATE_PORT[/PROTO]]", "List port mappings for the CONTAINER, or lookup the public-facing port that\nis NAT-ed to the PRIVATE_PORT", true)
+	cmd.Require(flag.Min, 1)
+	cmd.ParseFlags(args, true)
+
+	stream, _, _, err := cli.call("GET", "/containers/"+cmd.Arg(0)+"/json", nil, nil)
+	if err != nil {
+		return err
+	}
+
+	var c struct {
+		NetworkSettings struct {
+			Ports nat.PortMap
+		}
+	}
+
+	if err := json.NewDecoder(stream).Decode(&c); err != nil {
+		return err
+	}
+
+	if cmd.NArg() == 2 {
+		var (
+			port  = cmd.Arg(1)
+			proto = "tcp"
+			parts = strings.SplitN(port, "/", 2)
+		)
+
+		if len(parts) == 2 && len(parts[1]) != 0 {
+			port = parts[0]
+			proto = parts[1]
+		}
+		natPort := port + "/" + proto
+		if frontends, exists := c.NetworkSettings.Ports[nat.Port(port+"/"+proto)]; exists && frontends != nil {
+			for _, frontend := range frontends {
+				fmt.Fprintf(cli.out, "%s:%s\n", frontend.HostIp, frontend.HostPort)
+			}
+			return nil
+		}
+		return fmt.Errorf("Error: No public port '%s' published for %s", natPort, cmd.Arg(0))
+	}
+
+	for from, frontends := range c.NetworkSettings.Ports {
+		for _, frontend := range frontends {
+			fmt.Fprintf(cli.out, "%s -> %s:%s\n", from, frontend.HostIp, frontend.HostPort)
+		}
+	}
+
+	return nil
+}

+ 175 - 0
libnetwork/Godeps/_workspace/src/github.com/docker/docker/api/client/ps.go

@@ -0,0 +1,175 @@
+package client
+
+import (
+	"encoding/json"
+	"fmt"
+	"net/url"
+	"strconv"
+	"strings"
+	"text/tabwriter"
+	"time"
+
+	"github.com/docker/docker/api"
+	"github.com/docker/docker/api/types"
+	"github.com/docker/docker/opts"
+	flag "github.com/docker/docker/pkg/mflag"
+	"github.com/docker/docker/pkg/parsers/filters"
+	"github.com/docker/docker/pkg/stringid"
+	"github.com/docker/docker/pkg/stringutils"
+	"github.com/docker/docker/pkg/units"
+)
+
+// CmdPs outputs a list of Docker containers.
+//
+// Usage: docker ps [OPTIONS]
+func (cli *DockerCli) CmdPs(args ...string) error {
+	var (
+		err error
+
+		psFilterArgs = filters.Args{}
+		v            = url.Values{}
+
+		cmd      = cli.Subcmd("ps", "", "List containers", true)
+		quiet    = cmd.Bool([]string{"q", "-quiet"}, false, "Only display numeric IDs")
+		size     = cmd.Bool([]string{"s", "-size"}, false, "Display total file sizes")
+		all      = cmd.Bool([]string{"a", "-all"}, false, "Show all containers (default shows just running)")
+		noTrunc  = cmd.Bool([]string{"#notrunc", "-no-trunc"}, false, "Don't truncate output")
+		nLatest  = cmd.Bool([]string{"l", "-latest"}, false, "Show the latest created container, include non-running")
+		since    = cmd.String([]string{"#sinceId", "#-since-id", "-since"}, "", "Show created since Id or Name, include non-running")
+		before   = cmd.String([]string{"#beforeId", "#-before-id", "-before"}, "", "Show only container created before Id or Name")
+		last     = cmd.Int([]string{"n"}, -1, "Show n last created containers, include non-running")
+		flFilter = opts.NewListOpts(nil)
+	)
+	cmd.Require(flag.Exact, 0)
+
+	cmd.Var(&flFilter, []string{"f", "-filter"}, "Filter output based on conditions provided")
+
+	cmd.ParseFlags(args, true)
+	if *last == -1 && *nLatest {
+		*last = 1
+	}
+
+	if *all {
+		v.Set("all", "1")
+	}
+
+	if *last != -1 {
+		v.Set("limit", strconv.Itoa(*last))
+	}
+
+	if *since != "" {
+		v.Set("since", *since)
+	}
+
+	if *before != "" {
+		v.Set("before", *before)
+	}
+
+	if *size {
+		v.Set("size", "1")
+	}
+
+	// Consolidate all filter flags, and sanity check them.
+	// They'll get processed in the daemon/server.
+	for _, f := range flFilter.GetAll() {
+		if psFilterArgs, err = filters.ParseFlag(f, psFilterArgs); err != nil {
+			return err
+		}
+	}
+
+	if len(psFilterArgs) > 0 {
+		filterJSON, err := filters.ToParam(psFilterArgs)
+		if err != nil {
+			return err
+		}
+
+		v.Set("filters", filterJSON)
+	}
+
+	rdr, _, _, err := cli.call("GET", "/containers/json?"+v.Encode(), nil, nil)
+	if err != nil {
+		return err
+	}
+
+	containers := []types.Container{}
+	if err := json.NewDecoder(rdr).Decode(&containers); err != nil {
+		return err
+	}
+
+	w := tabwriter.NewWriter(cli.out, 20, 1, 3, ' ', 0)
+	if !*quiet {
+		fmt.Fprint(w, "CONTAINER ID\tIMAGE\tCOMMAND\tCREATED\tSTATUS\tPORTS\tNAMES")
+
+		if *size {
+			fmt.Fprintln(w, "\tSIZE")
+		} else {
+			fmt.Fprint(w, "\n")
+		}
+	}
+
+	stripNamePrefix := func(ss []string) []string {
+		for i, s := range ss {
+			ss[i] = s[1:]
+		}
+
+		return ss
+	}
+
+	for _, container := range containers {
+		ID := container.ID
+
+		if !*noTrunc {
+			ID = stringid.TruncateID(ID)
+		}
+
+		if *quiet {
+			fmt.Fprintln(w, ID)
+
+			continue
+		}
+
+		var (
+			names   = stripNamePrefix(container.Names)
+			command = strconv.Quote(container.Command)
+		)
+
+		if !*noTrunc {
+			command = stringutils.Truncate(command, 20)
+
+			// only display the default name for the container with notrunc is passed
+			for _, name := range names {
+				if len(strings.Split(name, "/")) == 1 {
+					names = []string{name}
+					break
+				}
+			}
+		}
+
+		image := container.Image
+		if image == "" {
+			image = "<no image>"
+		}
+
+		fmt.Fprintf(w, "%s\t%s\t%s\t%s ago\t%s\t%s\t%s\t", ID, image, command,
+			units.HumanDuration(time.Now().UTC().Sub(time.Unix(int64(container.Created), 0))),
+			container.Status, api.DisplayablePorts(container.Ports), strings.Join(names, ","))
+
+		if *size {
+			if container.SizeRootFs > 0 {
+				fmt.Fprintf(w, "%s (virtual %s)\n", units.HumanSize(float64(container.SizeRw)), units.HumanSize(float64(container.SizeRootFs)))
+			} else {
+				fmt.Fprintf(w, "%s\n", units.HumanSize(float64(container.SizeRw)))
+			}
+
+			continue
+		}
+
+		fmt.Fprint(w, "\n")
+	}
+
+	if !*quiet {
+		w.Flush()
+	}
+
+	return nil
+}

+ 47 - 0
libnetwork/Godeps/_workspace/src/github.com/docker/docker/api/client/pull.go

@@ -0,0 +1,47 @@
+package client
+
+import (
+	"fmt"
+	"net/url"
+
+	"github.com/docker/docker/graph/tags"
+	flag "github.com/docker/docker/pkg/mflag"
+	"github.com/docker/docker/pkg/parsers"
+	"github.com/docker/docker/registry"
+	"github.com/docker/docker/utils"
+)
+
+// CmdPull pulls an image or a repository from the registry.
+//
+// Usage: docker pull [OPTIONS] IMAGENAME[:TAG|@DIGEST]
+func (cli *DockerCli) CmdPull(args ...string) error {
+	cmd := cli.Subcmd("pull", "NAME[:TAG|@DIGEST]", "Pull an image or a repository from the registry", true)
+	allTags := cmd.Bool([]string{"a", "-all-tags"}, false, "Download all tagged images in the repository")
+	cmd.Require(flag.Exact, 1)
+
+	cmd.ParseFlags(args, true)
+
+	var (
+		v         = url.Values{}
+		remote    = cmd.Arg(0)
+		newRemote = remote
+	)
+	taglessRemote, tag := parsers.ParseRepositoryTag(remote)
+	if tag == "" && !*allTags {
+		newRemote = utils.ImageReference(taglessRemote, tags.DEFAULTTAG)
+	}
+	if tag != "" && *allTags {
+		return fmt.Errorf("tag can't be used with --all-tags/-a")
+	}
+
+	v.Set("fromImage", newRemote)
+
+	// Resolve the Repository name from fqn to RepositoryInfo
+	repoInfo, err := registry.ParseRepositoryInfo(taglessRemote)
+	if err != nil {
+		return err
+	}
+
+	_, _, err = cli.clientRequestAttemptLogin("POST", "/images/create?"+v.Encode(), nil, cli.out, repoInfo.Index, "pull")
+	return err
+}

+ 49 - 0
libnetwork/Godeps/_workspace/src/github.com/docker/docker/api/client/push.go

@@ -0,0 +1,49 @@
+package client
+
+import (
+	"fmt"
+	"net/url"
+
+	flag "github.com/docker/docker/pkg/mflag"
+	"github.com/docker/docker/pkg/parsers"
+	"github.com/docker/docker/registry"
+)
+
+// CmdPush pushes an image or repository to the registry.
+//
+// Usage: docker push NAME[:TAG]
+func (cli *DockerCli) CmdPush(args ...string) error {
+	cmd := cli.Subcmd("push", "NAME[:TAG]", "Push an image or a repository to the registry", true)
+	cmd.Require(flag.Exact, 1)
+
+	cmd.ParseFlags(args, true)
+
+	name := cmd.Arg(0)
+
+	remote, tag := parsers.ParseRepositoryTag(name)
+
+	// Resolve the Repository name from fqn to RepositoryInfo
+	repoInfo, err := registry.ParseRepositoryInfo(remote)
+	if err != nil {
+		return err
+	}
+	// Resolve the Auth config relevant for this server
+	authConfig := registry.ResolveAuthConfig(cli.configFile, repoInfo.Index)
+	// If we're not using a custom registry, we know the restrictions
+	// applied to repository names and can warn the user in advance.
+	// Custom repositories can have different rules, and we must also
+	// allow pushing by image ID.
+	if repoInfo.Official {
+		username := authConfig.Username
+		if username == "" {
+			username = "<user>"
+		}
+		return fmt.Errorf("You cannot push a \"root\" repository. Please rename your repository to <user>/<repo> (ex: %s/%s)", username, repoInfo.LocalName)
+	}
+
+	v := url.Values{}
+	v.Set("tag", tag)
+
+	_, _, err = cli.clientRequestAttemptLogin("POST", "/images/"+remote+"/push?"+v.Encode(), nil, cli.out, repoInfo.Index, "push")
+	return err
+}

+ 25 - 0
libnetwork/Godeps/_workspace/src/github.com/docker/docker/api/client/rename.go

@@ -0,0 +1,25 @@
+package client
+
+import (
+	"fmt"
+
+	flag "github.com/docker/docker/pkg/mflag"
+)
+
+// CmdRename renames a container.
+//
+// Usage: docker rename OLD_NAME NEW_NAME
+func (cli *DockerCli) CmdRename(args ...string) error {
+	cmd := cli.Subcmd("rename", "OLD_NAME NEW_NAME", "Rename a container", true)
+	cmd.Require(flag.Exact, 2)
+	cmd.ParseFlags(args, true)
+
+	oldName := cmd.Arg(0)
+	newName := cmd.Arg(1)
+
+	if _, _, err := readBody(cli.call("POST", fmt.Sprintf("/containers/%s/rename?name=%s", oldName, newName), nil, nil)); err != nil {
+		fmt.Fprintf(cli.err, "%s\n", err)
+		return fmt.Errorf("Error: failed to rename container named %s", oldName)
+	}
+	return nil
+}

+ 38 - 0
libnetwork/Godeps/_workspace/src/github.com/docker/docker/api/client/restart.go

@@ -0,0 +1,38 @@
+package client
+
+import (
+	"fmt"
+	"net/url"
+	"strconv"
+
+	flag "github.com/docker/docker/pkg/mflag"
+)
+
+// CmdRestart restarts one or more running containers.
+//
+// Usage: docker stop [OPTIONS] CONTAINER [CONTAINER...]
+func (cli *DockerCli) CmdRestart(args ...string) error {
+	cmd := cli.Subcmd("restart", "CONTAINER [CONTAINER...]", "Restart a running container", true)
+	nSeconds := cmd.Int([]string{"t", "-time"}, 10, "Seconds to wait for stop before killing the container")
+	cmd.Require(flag.Min, 1)
+
+	cmd.ParseFlags(args, true)
+
+	v := url.Values{}
+	v.Set("t", strconv.Itoa(*nSeconds))
+
+	var errNames []string
+	for _, name := range cmd.Args() {
+		_, _, err := readBody(cli.call("POST", "/containers/"+name+"/restart?"+v.Encode(), nil, nil))
+		if err != nil {
+			fmt.Fprintf(cli.err, "%s\n", err)
+			errNames = append(errNames, name)
+		} else {
+			fmt.Fprintf(cli.out, "%s\n", name)
+		}
+	}
+	if len(errNames) > 0 {
+		return fmt.Errorf("Error: failed to restart containers: %v", errNames)
+	}
+	return nil
+}

+ 54 - 0
libnetwork/Godeps/_workspace/src/github.com/docker/docker/api/client/rm.go

@@ -0,0 +1,54 @@
+package client
+
+import (
+	"fmt"
+	"net/url"
+	"strings"
+
+	flag "github.com/docker/docker/pkg/mflag"
+)
+
+// CmdRm removes one or more containers.
+//
+// Usage: docker rm [OPTIONS] CONTAINER [CONTAINER...]
+func (cli *DockerCli) CmdRm(args ...string) error {
+	cmd := cli.Subcmd("rm", "CONTAINER [CONTAINER...]", "Remove one or more containers", true)
+	v := cmd.Bool([]string{"v", "-volumes"}, false, "Remove the volumes associated with the container")
+	link := cmd.Bool([]string{"l", "#link", "-link"}, false, "Remove the specified link")
+	force := cmd.Bool([]string{"f", "-force"}, false, "Force the removal of a running container (uses SIGKILL)")
+	cmd.Require(flag.Min, 1)
+
+	cmd.ParseFlags(args, true)
+
+	val := url.Values{}
+	if *v {
+		val.Set("v", "1")
+	}
+	if *link {
+		val.Set("link", "1")
+	}
+
+	if *force {
+		val.Set("force", "1")
+	}
+
+	var errNames []string
+	for _, name := range cmd.Args() {
+		if name == "" {
+			return fmt.Errorf("Container name cannot be empty")
+		}
+		name = strings.Trim(name, "/")
+
+		_, _, err := readBody(cli.call("DELETE", "/containers/"+name+"?"+val.Encode(), nil, nil))
+		if err != nil {
+			fmt.Fprintf(cli.err, "%s\n", err)
+			errNames = append(errNames, name)
+		} else {
+			fmt.Fprintf(cli.out, "%s\n", name)
+		}
+	}
+	if len(errNames) > 0 {
+		return fmt.Errorf("Error: failed to remove containers: %v", errNames)
+	}
+	return nil
+}

+ 59 - 0
libnetwork/Godeps/_workspace/src/github.com/docker/docker/api/client/rmi.go

@@ -0,0 +1,59 @@
+package client
+
+import (
+	"encoding/json"
+	"fmt"
+	"net/url"
+
+	"github.com/docker/docker/api/types"
+	flag "github.com/docker/docker/pkg/mflag"
+)
+
+// CmdRmi removes all images with the specified name(s).
+//
+// Usage: docker rmi [OPTIONS] IMAGE [IMAGE...]
+func (cli *DockerCli) CmdRmi(args ...string) error {
+	var (
+		cmd     = cli.Subcmd("rmi", "IMAGE [IMAGE...]", "Remove one or more images", true)
+		force   = cmd.Bool([]string{"f", "-force"}, false, "Force removal of the image")
+		noprune = cmd.Bool([]string{"-no-prune"}, false, "Do not delete untagged parents")
+	)
+	cmd.Require(flag.Min, 1)
+	cmd.ParseFlags(args, true)
+
+	v := url.Values{}
+	if *force {
+		v.Set("force", "1")
+	}
+	if *noprune {
+		v.Set("noprune", "1")
+	}
+
+	var errNames []string
+	for _, name := range cmd.Args() {
+		rdr, _, _, err := cli.call("DELETE", "/images/"+name+"?"+v.Encode(), nil, nil)
+		if err != nil {
+			fmt.Fprintf(cli.err, "%s\n", err)
+			errNames = append(errNames, name)
+		} else {
+			dels := []types.ImageDelete{}
+			if err := json.NewDecoder(rdr).Decode(&dels); err != nil {
+				fmt.Fprintf(cli.err, "%s\n", err)
+				errNames = append(errNames, name)
+				continue
+			}
+
+			for _, del := range dels {
+				if del.Deleted != "" {
+					fmt.Fprintf(cli.out, "Deleted: %s\n", del.Deleted)
+				} else {
+					fmt.Fprintf(cli.out, "Untagged: %s\n", del.Untagged)
+				}
+			}
+		}
+	}
+	if len(errNames) > 0 {
+		return fmt.Errorf("Error: failed to remove images: %v", errNames)
+	}
+	return nil
+}

+ 247 - 0
libnetwork/Godeps/_workspace/src/github.com/docker/docker/api/client/run.go

@@ -0,0 +1,247 @@
+package client
+
+import (
+	"fmt"
+	"io"
+	"net/url"
+	"os"
+
+	"github.com/Sirupsen/logrus"
+	"github.com/docker/docker/opts"
+	"github.com/docker/docker/pkg/promise"
+	"github.com/docker/docker/pkg/signal"
+	"github.com/docker/docker/runconfig"
+	"github.com/docker/libnetwork/resolvconf/dns"
+)
+
+func (cid *cidFile) Close() error {
+	cid.file.Close()
+
+	if !cid.written {
+		if err := os.Remove(cid.path); err != nil {
+			return fmt.Errorf("failed to remove the CID file '%s': %s \n", cid.path, err)
+		}
+	}
+
+	return nil
+}
+
+func (cid *cidFile) Write(id string) error {
+	if _, err := cid.file.Write([]byte(id)); err != nil {
+		return fmt.Errorf("Failed to write the container ID to the file: %s", err)
+	}
+	cid.written = true
+	return nil
+}
+
+// CmdRun runs a command in a new container.
+//
+// Usage: docker run [OPTIONS] IMAGE [COMMAND] [ARG...]
+func (cli *DockerCli) CmdRun(args ...string) error {
+	cmd := cli.Subcmd("run", "IMAGE [COMMAND] [ARG...]", "Run a command in a new container", true)
+
+	// These are flags not stored in Config/HostConfig
+	var (
+		flAutoRemove = cmd.Bool([]string{"-rm"}, false, "Automatically remove the container when it exits")
+		flDetach     = cmd.Bool([]string{"d", "-detach"}, false, "Run container in background and print container ID")
+		flSigProxy   = cmd.Bool([]string{"-sig-proxy"}, true, "Proxy received signals to the process")
+		flName       = cmd.String([]string{"-name"}, "", "Assign a name to the container")
+		flAttach     *opts.ListOpts
+
+		ErrConflictAttachDetach               = fmt.Errorf("Conflicting options: -a and -d")
+		ErrConflictRestartPolicyAndAutoRemove = fmt.Errorf("Conflicting options: --restart and --rm")
+		ErrConflictDetachAutoRemove           = fmt.Errorf("Conflicting options: --rm and -d")
+	)
+
+	config, hostConfig, cmd, err := runconfig.Parse(cmd, args)
+	// just in case the Parse does not exit
+	if err != nil {
+		cmd.ReportError(err.Error(), true)
+		os.Exit(1)
+	}
+
+	if len(hostConfig.Dns) > 0 {
+		// check the DNS settings passed via --dns against
+		// localhost regexp to warn if they are trying to
+		// set a DNS to a localhost address
+		for _, dnsIP := range hostConfig.Dns {
+			if dns.IsLocalhost(dnsIP) {
+				fmt.Fprintf(cli.err, "WARNING: Localhost DNS setting (--dns=%s) may fail in containers.\n", dnsIP)
+				break
+			}
+		}
+	}
+	if config.Image == "" {
+		cmd.Usage()
+		return nil
+	}
+
+	if !*flDetach {
+		if err := cli.CheckTtyInput(config.AttachStdin, config.Tty); err != nil {
+			return err
+		}
+	} else {
+		if fl := cmd.Lookup("-attach"); fl != nil {
+			flAttach = fl.Value.(*opts.ListOpts)
+			if flAttach.Len() != 0 {
+				return ErrConflictAttachDetach
+			}
+		}
+		if *flAutoRemove {
+			return ErrConflictDetachAutoRemove
+		}
+
+		config.AttachStdin = false
+		config.AttachStdout = false
+		config.AttachStderr = false
+		config.StdinOnce = false
+	}
+
+	// Disable flSigProxy when in TTY mode
+	sigProxy := *flSigProxy
+	if config.Tty {
+		sigProxy = false
+	}
+
+	createResponse, err := cli.createContainer(config, hostConfig, hostConfig.ContainerIDFile, *flName)
+	if err != nil {
+		return err
+	}
+	if sigProxy {
+		sigc := cli.forwardAllSignals(createResponse.ID)
+		defer signal.StopCatch(sigc)
+	}
+	var (
+		waitDisplayID chan struct{}
+		errCh         chan error
+	)
+	if !config.AttachStdout && !config.AttachStderr {
+		// Make this asynchronous to allow the client to write to stdin before having to read the ID
+		waitDisplayID = make(chan struct{})
+		go func() {
+			defer close(waitDisplayID)
+			fmt.Fprintf(cli.out, "%s\n", createResponse.ID)
+		}()
+	}
+	if *flAutoRemove && (hostConfig.RestartPolicy.IsAlways() || hostConfig.RestartPolicy.IsOnFailure()) {
+		return ErrConflictRestartPolicyAndAutoRemove
+	}
+	// We need to instantiate the chan because the select needs it. It can
+	// be closed but can't be uninitialized.
+	hijacked := make(chan io.Closer)
+	// Block the return until the chan gets closed
+	defer func() {
+		logrus.Debugf("End of CmdRun(), Waiting for hijack to finish.")
+		if _, ok := <-hijacked; ok {
+			fmt.Fprintln(cli.err, "Hijack did not finish (chan still open)")
+		}
+	}()
+	if config.AttachStdin || config.AttachStdout || config.AttachStderr {
+		var (
+			out, stderr io.Writer
+			in          io.ReadCloser
+			v           = url.Values{}
+		)
+		v.Set("stream", "1")
+		if config.AttachStdin {
+			v.Set("stdin", "1")
+			in = cli.in
+		}
+		if config.AttachStdout {
+			v.Set("stdout", "1")
+			out = cli.out
+		}
+		if config.AttachStderr {
+			v.Set("stderr", "1")
+			if config.Tty {
+				stderr = cli.out
+			} else {
+				stderr = cli.err
+			}
+		}
+		errCh = promise.Go(func() error {
+			return cli.hijack("POST", "/containers/"+createResponse.ID+"/attach?"+v.Encode(), config.Tty, in, out, stderr, hijacked, nil)
+		})
+	} else {
+		close(hijacked)
+	}
+	// Acknowledge the hijack before starting
+	select {
+	case closer := <-hijacked:
+		// Make sure that the hijack gets closed when returning (results
+		// in closing the hijack chan and freeing server's goroutines)
+		if closer != nil {
+			defer closer.Close()
+		}
+	case err := <-errCh:
+		if err != nil {
+			logrus.Debugf("Error hijack: %s", err)
+			return err
+		}
+	}
+
+	defer func() {
+		if *flAutoRemove {
+			if _, _, err = readBody(cli.call("DELETE", "/containers/"+createResponse.ID+"?v=1", nil, nil)); err != nil {
+				fmt.Fprintf(cli.err, "Error deleting container: %s\n", err)
+			}
+		}
+	}()
+
+	//start the container
+	if _, _, err = readBody(cli.call("POST", "/containers/"+createResponse.ID+"/start", nil, nil)); err != nil {
+		return err
+	}
+
+	if (config.AttachStdin || config.AttachStdout || config.AttachStderr) && config.Tty && cli.isTerminalOut {
+		if err := cli.monitorTtySize(createResponse.ID, false); err != nil {
+			fmt.Fprintf(cli.err, "Error monitoring TTY size: %s\n", err)
+		}
+	}
+
+	if errCh != nil {
+		if err := <-errCh; err != nil {
+			logrus.Debugf("Error hijack: %s", err)
+			return err
+		}
+	}
+
+	// Detached mode: wait for the id to be displayed and return.
+	if !config.AttachStdout && !config.AttachStderr {
+		// Detached mode
+		<-waitDisplayID
+		return nil
+	}
+
+	var status int
+
+	// Attached mode
+	if *flAutoRemove {
+		// Autoremove: wait for the container to finish, retrieve
+		// the exit code and remove the container
+		if _, _, err := readBody(cli.call("POST", "/containers/"+createResponse.ID+"/wait", nil, nil)); err != nil {
+			return err
+		}
+		if _, status, err = getExitCode(cli, createResponse.ID); err != nil {
+			return err
+		}
+	} else {
+		// No Autoremove: Simply retrieve the exit code
+		if !config.Tty {
+			// In non-TTY mode, we can't detach, so we must wait for container exit
+			if status, err = waitForExit(cli, createResponse.ID); err != nil {
+				return err
+			}
+		} else {
+			// In TTY mode, there is a race: if the process dies too slowly, the state could
+			// be updated after the getExitCode call and result in the wrong exit code being reported
+			if _, status, err = getExitCode(cli, createResponse.ID); err != nil {
+				return err
+			}
+		}
+	}
+	if status != 0 {
+		return StatusError{StatusCode: status}
+	}
+	return nil
+}

+ 57 - 0
libnetwork/Godeps/_workspace/src/github.com/docker/docker/api/client/save.go

@@ -0,0 +1,57 @@
+package client
+
+import (
+	"errors"
+	"io"
+	"net/url"
+	"os"
+
+	flag "github.com/docker/docker/pkg/mflag"
+)
+
+// CmdSave saves one or more images to a tar archive.
+//
+// The tar archive is written to STDOUT by default, or written to a file.
+//
+// Usage: docker save [OPTIONS] IMAGE [IMAGE...]
+func (cli *DockerCli) CmdSave(args ...string) error {
+	cmd := cli.Subcmd("save", "IMAGE [IMAGE...]", "Save an image(s) to a tar archive (streamed to STDOUT by default)", true)
+	outfile := cmd.String([]string{"o", "-output"}, "", "Write to an file, instead of STDOUT")
+	cmd.Require(flag.Min, 1)
+
+	cmd.ParseFlags(args, true)
+
+	var (
+		output io.Writer = cli.out
+		err    error
+	)
+	if *outfile != "" {
+		output, err = os.Create(*outfile)
+		if err != nil {
+			return err
+		}
+	} else if cli.isTerminalOut {
+		return errors.New("Cowardly refusing to save to a terminal. Use the -o flag or redirect.")
+	}
+
+	sopts := &streamOpts{
+		rawTerminal: true,
+		out:         output,
+	}
+
+	if len(cmd.Args()) == 1 {
+		image := cmd.Arg(0)
+		if err := cli.stream("GET", "/images/"+image+"/get", sopts); err != nil {
+			return err
+		}
+	} else {
+		v := url.Values{}
+		for _, arg := range cmd.Args() {
+			v.Add("names", arg)
+		}
+		if err := cli.stream("GET", "/images/get?"+v.Encode(), sopts); err != nil {
+			return err
+		}
+	}
+	return nil
+}

+ 84 - 0
libnetwork/Godeps/_workspace/src/github.com/docker/docker/api/client/search.go

@@ -0,0 +1,84 @@
+package client
+
+import (
+	"encoding/json"
+	"fmt"
+	"net/url"
+	"sort"
+	"strings"
+	"text/tabwriter"
+
+	flag "github.com/docker/docker/pkg/mflag"
+	"github.com/docker/docker/pkg/parsers"
+	"github.com/docker/docker/pkg/stringutils"
+	"github.com/docker/docker/registry"
+)
+
+// ByStars sorts search results in ascending order by number of stars.
+type ByStars []registry.SearchResult
+
+func (r ByStars) Len() int           { return len(r) }
+func (r ByStars) Swap(i, j int)      { r[i], r[j] = r[j], r[i] }
+func (r ByStars) Less(i, j int) bool { return r[i].StarCount < r[j].StarCount }
+
+// CmdSearch searches the Docker Hub for images.
+//
+// Usage: docker search [OPTIONS] TERM
+func (cli *DockerCli) CmdSearch(args ...string) error {
+	cmd := cli.Subcmd("search", "TERM", "Search the Docker Hub for images", true)
+	noTrunc := cmd.Bool([]string{"#notrunc", "-no-trunc"}, false, "Don't truncate output")
+	trusted := cmd.Bool([]string{"#t", "#trusted", "#-trusted"}, false, "Only show trusted builds")
+	automated := cmd.Bool([]string{"-automated"}, false, "Only show automated builds")
+	stars := cmd.Uint([]string{"s", "#stars", "-stars"}, 0, "Only displays with at least x stars")
+	cmd.Require(flag.Exact, 1)
+
+	cmd.ParseFlags(args, true)
+
+	name := cmd.Arg(0)
+	v := url.Values{}
+	v.Set("term", name)
+
+	// Resolve the Repository name from fqn to hostname + name
+	taglessRemote, _ := parsers.ParseRepositoryTag(name)
+	repoInfo, err := registry.ParseRepositoryInfo(taglessRemote)
+	if err != nil {
+		return err
+	}
+
+	rdr, _, err := cli.clientRequestAttemptLogin("GET", "/images/search?"+v.Encode(), nil, nil, repoInfo.Index, "search")
+	if err != nil {
+		return err
+	}
+
+	results := ByStars{}
+	if err := json.NewDecoder(rdr).Decode(&results); err != nil {
+		return err
+	}
+
+	sort.Sort(sort.Reverse(results))
+
+	w := tabwriter.NewWriter(cli.out, 10, 1, 3, ' ', 0)
+	fmt.Fprintf(w, "NAME\tDESCRIPTION\tSTARS\tOFFICIAL\tAUTOMATED\n")
+	for _, res := range results {
+		if ((*automated || *trusted) && (!res.IsTrusted && !res.IsAutomated)) || (int(*stars) > res.StarCount) {
+			continue
+		}
+		desc := strings.Replace(res.Description, "\n", " ", -1)
+		desc = strings.Replace(desc, "\r", " ", -1)
+		if !*noTrunc && len(desc) > 45 {
+			desc = stringutils.Truncate(desc, 42) + "..."
+		}
+		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 || res.IsTrusted {
+			fmt.Fprint(w, "[OK]")
+		}
+		fmt.Fprint(w, "\n")
+	}
+	w.Flush()
+	return nil
+}

+ 167 - 0
libnetwork/Godeps/_workspace/src/github.com/docker/docker/api/client/start.go

@@ -0,0 +1,167 @@
+package client
+
+import (
+	"encoding/json"
+	"fmt"
+	"io"
+	"net/url"
+	"os"
+
+	"github.com/Sirupsen/logrus"
+	"github.com/docker/docker/api/types"
+	flag "github.com/docker/docker/pkg/mflag"
+	"github.com/docker/docker/pkg/promise"
+	"github.com/docker/docker/pkg/signal"
+)
+
+func (cli *DockerCli) forwardAllSignals(cid string) chan os.Signal {
+	sigc := make(chan os.Signal, 128)
+	signal.CatchAll(sigc)
+	go func() {
+		for s := range sigc {
+			if s == signal.SIGCHLD {
+				continue
+			}
+			var sig string
+			for sigStr, sigN := range signal.SignalMap {
+				if sigN == s {
+					sig = sigStr
+					break
+				}
+			}
+			if sig == "" {
+				fmt.Fprintf(cli.err, "Unsupported signal: %v. Discarding.\n", s)
+			}
+			if _, _, err := readBody(cli.call("POST", fmt.Sprintf("/containers/%s/kill?signal=%s", cid, sig), nil, nil)); err != nil {
+				logrus.Debugf("Error sending signal: %s", err)
+			}
+		}
+	}()
+	return sigc
+}
+
+// CmdStart starts one or more stopped containers.
+//
+// Usage: docker start [OPTIONS] CONTAINER [CONTAINER...]
+func (cli *DockerCli) CmdStart(args ...string) error {
+	var (
+		cErr chan error
+		tty  bool
+
+		cmd       = cli.Subcmd("start", "CONTAINER [CONTAINER...]", "Start one or more stopped containers", true)
+		attach    = cmd.Bool([]string{"a", "-attach"}, false, "Attach STDOUT/STDERR and forward signals")
+		openStdin = cmd.Bool([]string{"i", "-interactive"}, false, "Attach container's STDIN")
+	)
+
+	cmd.Require(flag.Min, 1)
+	cmd.ParseFlags(args, true)
+
+	if *attach || *openStdin {
+		if cmd.NArg() > 1 {
+			return fmt.Errorf("You cannot start and attach multiple containers at once.")
+		}
+
+		stream, _, _, err := cli.call("GET", "/containers/"+cmd.Arg(0)+"/json", nil, nil)
+		if err != nil {
+			return err
+		}
+
+		var c types.ContainerJSON
+		if err := json.NewDecoder(stream).Decode(&c); err != nil {
+			return err
+		}
+
+		tty = c.Config.Tty
+
+		if !tty {
+			sigc := cli.forwardAllSignals(cmd.Arg(0))
+			defer signal.StopCatch(sigc)
+		}
+
+		var in io.ReadCloser
+
+		v := url.Values{}
+		v.Set("stream", "1")
+
+		if *openStdin && c.Config.OpenStdin {
+			v.Set("stdin", "1")
+			in = cli.in
+		}
+
+		v.Set("stdout", "1")
+		v.Set("stderr", "1")
+
+		hijacked := make(chan io.Closer)
+		// Block the return until the chan gets closed
+		defer func() {
+			logrus.Debugf("CmdStart() returned, defer waiting for hijack to finish.")
+			if _, ok := <-hijacked; ok {
+				fmt.Fprintln(cli.err, "Hijack did not finish (chan still open)")
+			}
+			cli.in.Close()
+		}()
+		cErr = promise.Go(func() error {
+			return cli.hijack("POST", "/containers/"+cmd.Arg(0)+"/attach?"+v.Encode(), tty, in, cli.out, cli.err, hijacked, nil)
+		})
+
+		// Acknowledge the hijack before starting
+		select {
+		case closer := <-hijacked:
+			// Make sure that the hijack gets closed when returning (results
+			// in closing the hijack chan and freeing server's goroutines)
+			if closer != nil {
+				defer closer.Close()
+			}
+		case err := <-cErr:
+			if err != nil {
+				return err
+			}
+		}
+	}
+
+	var encounteredError error
+	var errNames []string
+	for _, name := range cmd.Args() {
+		_, _, err := readBody(cli.call("POST", "/containers/"+name+"/start", nil, nil))
+		if err != nil {
+			if !*attach && !*openStdin {
+				// attach and openStdin is false means it could be starting multiple containers
+				// when a container start failed, show the error message and start next
+				fmt.Fprintf(cli.err, "%s\n", err)
+				errNames = append(errNames, name)
+			} else {
+				encounteredError = err
+			}
+		} else {
+			if !*attach && !*openStdin {
+				fmt.Fprintf(cli.out, "%s\n", name)
+			}
+		}
+	}
+
+	if len(errNames) > 0 {
+		encounteredError = fmt.Errorf("Error: failed to start containers: %v", errNames)
+	}
+	if encounteredError != nil {
+		return encounteredError
+	}
+
+	if *openStdin || *attach {
+		if tty && cli.isTerminalOut {
+			if err := cli.monitorTtySize(cmd.Arg(0), false); err != nil {
+				fmt.Fprintf(cli.err, "Error monitoring TTY size: %s\n", err)
+			}
+		}
+		if attchErr := <-cErr; attchErr != nil {
+			return attchErr
+		}
+		_, status, err := getExitCode(cli, cmd.Arg(0))
+		if err != nil {
+			return err
+		}
+		if status != 0 {
+			return StatusError{StatusCode: status}
+		}
+	}
+	return nil
+}

+ 198 - 0
libnetwork/Godeps/_workspace/src/github.com/docker/docker/api/client/stats.go

@@ -0,0 +1,198 @@
+package client
+
+import (
+	"encoding/json"
+	"fmt"
+	"io"
+	"net/url"
+	"sort"
+	"strings"
+	"sync"
+	"text/tabwriter"
+	"time"
+
+	"github.com/docker/docker/api/types"
+	flag "github.com/docker/docker/pkg/mflag"
+	"github.com/docker/docker/pkg/units"
+)
+
+type containerStats struct {
+	Name             string
+	CPUPercentage    float64
+	Memory           float64
+	MemoryLimit      float64
+	MemoryPercentage float64
+	NetworkRx        float64
+	NetworkTx        float64
+	mu               sync.RWMutex
+	err              error
+}
+
+func (s *containerStats) Collect(cli *DockerCli, streamStats bool) {
+	v := url.Values{}
+	if streamStats {
+		v.Set("stream", "1")
+	} else {
+		v.Set("stream", "0")
+	}
+	stream, _, _, err := cli.call("GET", "/containers/"+s.Name+"/stats?"+v.Encode(), nil, nil)
+	if err != nil {
+		s.mu.Lock()
+		s.err = err
+		s.mu.Unlock()
+		return
+	}
+	defer stream.Close()
+	var (
+		previousCPU    uint64
+		previousSystem uint64
+		dec            = json.NewDecoder(stream)
+		u              = make(chan error, 1)
+	)
+	go func() {
+		for {
+			var v *types.Stats
+			if err := dec.Decode(&v); err != nil {
+				u <- err
+				return
+			}
+			var (
+				memPercent = float64(v.MemoryStats.Usage) / float64(v.MemoryStats.Limit) * 100.0
+				cpuPercent = 0.0
+			)
+			previousCPU = v.PreCpuStats.CpuUsage.TotalUsage
+			previousSystem = v.PreCpuStats.SystemUsage
+			cpuPercent = calculateCPUPercent(previousCPU, previousSystem, v)
+			s.mu.Lock()
+			s.CPUPercentage = cpuPercent
+			s.Memory = float64(v.MemoryStats.Usage)
+			s.MemoryLimit = float64(v.MemoryStats.Limit)
+			s.MemoryPercentage = memPercent
+			s.NetworkRx = float64(v.Network.RxBytes)
+			s.NetworkTx = float64(v.Network.TxBytes)
+			s.mu.Unlock()
+			u <- nil
+			if !streamStats {
+				return
+			}
+		}
+	}()
+	for {
+		select {
+		case <-time.After(2 * time.Second):
+			// zero out the values if we have not received an update within
+			// the specified duration.
+			s.mu.Lock()
+			s.CPUPercentage = 0
+			s.Memory = 0
+			s.MemoryPercentage = 0
+			s.mu.Unlock()
+		case err := <-u:
+			if err != nil {
+				s.mu.Lock()
+				s.err = err
+				s.mu.Unlock()
+				return
+			}
+		}
+		if !streamStats {
+			return
+		}
+	}
+}
+
+func (s *containerStats) Display(w io.Writer) error {
+	s.mu.RLock()
+	defer s.mu.RUnlock()
+	if s.err != nil {
+		return s.err
+	}
+	fmt.Fprintf(w, "%s\t%.2f%%\t%s/%s\t%.2f%%\t%s/%s\n",
+		s.Name,
+		s.CPUPercentage,
+		units.HumanSize(s.Memory), units.HumanSize(s.MemoryLimit),
+		s.MemoryPercentage,
+		units.HumanSize(s.NetworkRx), units.HumanSize(s.NetworkTx))
+	return nil
+}
+
+// CmdStats displays a live stream of resource usage statistics for one or more containers.
+//
+// This shows real-time information on CPU usage, memory usage, and network I/O.
+//
+// Usage: docker stats CONTAINER [CONTAINER...]
+func (cli *DockerCli) CmdStats(args ...string) error {
+	cmd := cli.Subcmd("stats", "CONTAINER [CONTAINER...]", "Display a live stream of one or more containers' resource usage statistics", true)
+	noStream := cmd.Bool([]string{"-no-stream"}, false, "Disable streaming stats and only pull the first result")
+	cmd.Require(flag.Min, 1)
+	cmd.ParseFlags(args, true)
+
+	names := cmd.Args()
+	sort.Strings(names)
+	var (
+		cStats []*containerStats
+		w      = tabwriter.NewWriter(cli.out, 20, 1, 3, ' ', 0)
+	)
+	printHeader := func() {
+		if !*noStream {
+			fmt.Fprint(cli.out, "\033[2J")
+			fmt.Fprint(cli.out, "\033[H")
+		}
+		io.WriteString(w, "CONTAINER\tCPU %\tMEM USAGE/LIMIT\tMEM %\tNET I/O\n")
+	}
+	for _, n := range names {
+		s := &containerStats{Name: n}
+		cStats = append(cStats, s)
+		go s.Collect(cli, !*noStream)
+	}
+	// do a quick pause so that any failed connections for containers that do not exist are able to be
+	// evicted before we display the initial or default values.
+	time.Sleep(1500 * time.Millisecond)
+	var errs []string
+	for _, c := range cStats {
+		c.mu.Lock()
+		if c.err != nil {
+			errs = append(errs, fmt.Sprintf("%s: %v", c.Name, c.err))
+		}
+		c.mu.Unlock()
+	}
+	if len(errs) > 0 {
+		return fmt.Errorf("%s", strings.Join(errs, ", "))
+	}
+	for range time.Tick(500 * time.Millisecond) {
+		printHeader()
+		toRemove := []int{}
+		for i, s := range cStats {
+			if err := s.Display(w); err != nil && !*noStream {
+				toRemove = append(toRemove, i)
+			}
+		}
+		for j := len(toRemove) - 1; j >= 0; j-- {
+			i := toRemove[j]
+			cStats = append(cStats[:i], cStats[i+1:]...)
+		}
+		if len(cStats) == 0 {
+			return nil
+		}
+		w.Flush()
+		if *noStream {
+			break
+		}
+	}
+	return nil
+}
+
+func calculateCPUPercent(previousCPU, previousSystem uint64, v *types.Stats) float64 {
+	var (
+		cpuPercent = 0.0
+		// calculate the change for the cpu usage of the container in between readings
+		cpuDelta = float64(v.CpuStats.CpuUsage.TotalUsage - previousCPU)
+		// calculate the change for the entire system between readings
+		systemDelta = float64(v.CpuStats.SystemUsage - previousSystem)
+	)
+
+	if systemDelta > 0.0 && cpuDelta > 0.0 {
+		cpuPercent = (cpuDelta / systemDelta) * float64(len(v.CpuStats.CpuUsage.PercpuUsage)) * 100.0
+	}
+	return cpuPercent
+}

+ 29 - 0
libnetwork/Godeps/_workspace/src/github.com/docker/docker/api/client/stats_unit_test.go

@@ -0,0 +1,29 @@
+package client
+
+import (
+	"bytes"
+	"sync"
+	"testing"
+)
+
+func TestDisplay(t *testing.T) {
+	c := &containerStats{
+		Name:             "app",
+		CPUPercentage:    30.0,
+		Memory:           100 * 1024 * 1024.0,
+		MemoryLimit:      2048 * 1024 * 1024.0,
+		MemoryPercentage: 100.0 / 2048.0 * 100.0,
+		NetworkRx:        100 * 1024 * 1024,
+		NetworkTx:        800 * 1024 * 1024,
+		mu:               sync.RWMutex{},
+	}
+	var b bytes.Buffer
+	if err := c.Display(&b); err != nil {
+		t.Fatalf("c.Display() gave error: %s", err)
+	}
+	got := b.String()
+	want := "app\t30.00%\t104.9 MB/2.147 GB\t4.88%\t104.9 MB/838.9 MB\n"
+	if got != want {
+		t.Fatalf("c.Display() = %q, want %q", got, want)
+	}
+}

+ 40 - 0
libnetwork/Godeps/_workspace/src/github.com/docker/docker/api/client/stop.go

@@ -0,0 +1,40 @@
+package client
+
+import (
+	"fmt"
+	"net/url"
+	"strconv"
+
+	flag "github.com/docker/docker/pkg/mflag"
+)
+
+// CmdStop stops one or more running containers.
+//
+// A running container is stopped by first sending SIGTERM and then SIGKILL if the container fails to stop within a grace period (the default is 10 seconds).
+//
+// Usage: docker stop [OPTIONS] CONTAINER [CONTAINER...]
+func (cli *DockerCli) CmdStop(args ...string) error {
+	cmd := cli.Subcmd("stop", "CONTAINER [CONTAINER...]", "Stop a running container by sending SIGTERM and then SIGKILL after a\ngrace period", true)
+	nSeconds := cmd.Int([]string{"t", "-time"}, 10, "Seconds to wait for stop before killing it")
+	cmd.Require(flag.Min, 1)
+
+	cmd.ParseFlags(args, true)
+
+	v := url.Values{}
+	v.Set("t", strconv.Itoa(*nSeconds))
+
+	var errNames []string
+	for _, name := range cmd.Args() {
+		_, _, err := readBody(cli.call("POST", "/containers/"+name+"/stop?"+v.Encode(), nil, nil))
+		if err != nil {
+			fmt.Fprintf(cli.err, "%s\n", err)
+			errNames = append(errNames, name)
+		} else {
+			fmt.Fprintf(cli.out, "%s\n", name)
+		}
+	}
+	if len(errNames) > 0 {
+		return fmt.Errorf("Error: failed to stop containers: %v", errNames)
+	}
+	return nil
+}

+ 41 - 0
libnetwork/Godeps/_workspace/src/github.com/docker/docker/api/client/tag.go

@@ -0,0 +1,41 @@
+package client
+
+import (
+	"net/url"
+
+	flag "github.com/docker/docker/pkg/mflag"
+	"github.com/docker/docker/pkg/parsers"
+	"github.com/docker/docker/registry"
+)
+
+// CmdTag tags an image into a repository.
+//
+// Usage: docker tag [OPTIONS] IMAGE[:TAG] [REGISTRYHOST/][USERNAME/]NAME[:TAG]
+func (cli *DockerCli) CmdTag(args ...string) error {
+	cmd := cli.Subcmd("tag", "IMAGE[:TAG] [REGISTRYHOST/][USERNAME/]NAME[:TAG]", "Tag an image into a repository", true)
+	force := cmd.Bool([]string{"f", "#force", "-force"}, false, "Force")
+	cmd.Require(flag.Exact, 2)
+
+	cmd.ParseFlags(args, true)
+
+	var (
+		repository, tag = parsers.ParseRepositoryTag(cmd.Arg(1))
+		v               = url.Values{}
+	)
+
+	//Check if the given image name can be resolved
+	if err := registry.ValidateRepositoryName(repository); err != nil {
+		return err
+	}
+	v.Set("repo", repository)
+	v.Set("tag", tag)
+
+	if *force {
+		v.Set("force", "1")
+	}
+
+	if _, _, err := readBody(cli.call("POST", "/images/"+cmd.Arg(0)+"/tag?"+v.Encode(), nil, nil)); err != nil {
+		return err
+	}
+	return nil
+}

+ 46 - 0
libnetwork/Godeps/_workspace/src/github.com/docker/docker/api/client/top.go

@@ -0,0 +1,46 @@
+package client
+
+import (
+	"encoding/json"
+	"fmt"
+	"net/url"
+	"strings"
+	"text/tabwriter"
+
+	"github.com/docker/docker/api/types"
+	flag "github.com/docker/docker/pkg/mflag"
+)
+
+// CmdTop displays the running processes of a container.
+//
+// Usage: docker top CONTAINER
+func (cli *DockerCli) CmdTop(args ...string) error {
+	cmd := cli.Subcmd("top", "CONTAINER [ps OPTIONS]", "Display the running processes of a container", true)
+	cmd.Require(flag.Min, 1)
+
+	cmd.ParseFlags(args, true)
+
+	val := url.Values{}
+	if cmd.NArg() > 1 {
+		val.Set("ps_args", strings.Join(cmd.Args()[1:], " "))
+	}
+
+	stream, _, _, err := cli.call("GET", "/containers/"+cmd.Arg(0)+"/top?"+val.Encode(), nil, nil)
+	if err != nil {
+		return err
+	}
+
+	procList := types.ContainerProcessList{}
+	if err := json.NewDecoder(stream).Decode(&procList); err != nil {
+		return err
+	}
+
+	w := tabwriter.NewWriter(cli.out, 20, 1, 3, ' ', 0)
+	fmt.Fprintln(w, strings.Join(procList.Titles, "\t"))
+
+	for _, proc := range procList.Processes {
+		fmt.Fprintln(w, strings.Join(proc, "\t"))
+	}
+	w.Flush()
+	return nil
+}

+ 30 - 0
libnetwork/Godeps/_workspace/src/github.com/docker/docker/api/client/unpause.go

@@ -0,0 +1,30 @@
+package client
+
+import (
+	"fmt"
+
+	flag "github.com/docker/docker/pkg/mflag"
+)
+
+// CmdUnpause unpauses all processes within a container, for one or more containers.
+//
+// Usage: docker unpause CONTAINER [CONTAINER...]
+func (cli *DockerCli) CmdUnpause(args ...string) error {
+	cmd := cli.Subcmd("unpause", "CONTAINER [CONTAINER...]", "Unpause all processes within a container", true)
+	cmd.Require(flag.Min, 1)
+	cmd.ParseFlags(args, true)
+
+	var errNames []string
+	for _, name := range cmd.Args() {
+		if _, _, err := readBody(cli.call("POST", fmt.Sprintf("/containers/%s/unpause", name), nil, nil)); err != nil {
+			fmt.Fprintf(cli.err, "%s\n", err)
+			errNames = append(errNames, name)
+		} else {
+			fmt.Fprintf(cli.out, "%s\n", name)
+		}
+	}
+	if len(errNames) > 0 {
+		return fmt.Errorf("Error: failed to unpause containers: %v", errNames)
+	}
+	return nil
+}

+ 345 - 0
libnetwork/Godeps/_workspace/src/github.com/docker/docker/api/client/utils.go

@@ -0,0 +1,345 @@
+package client
+
+import (
+	"bytes"
+	"encoding/base64"
+	"encoding/json"
+	"errors"
+	"fmt"
+	"io"
+	"io/ioutil"
+	"net/http"
+	"net/url"
+	"os"
+	gosignal "os/signal"
+	"runtime"
+	"strconv"
+	"strings"
+	"time"
+
+	"github.com/Sirupsen/logrus"
+	"github.com/docker/docker/api"
+	"github.com/docker/docker/api/types"
+	"github.com/docker/docker/autogen/dockerversion"
+	"github.com/docker/docker/cliconfig"
+	"github.com/docker/docker/pkg/jsonmessage"
+	"github.com/docker/docker/pkg/signal"
+	"github.com/docker/docker/pkg/stdcopy"
+	"github.com/docker/docker/pkg/term"
+	"github.com/docker/docker/registry"
+)
+
+var (
+	errConnectionRefused = errors.New("Cannot connect to the Docker daemon. Is 'docker -d' running on this host?")
+)
+
+// HTTPClient creates a new HTTP client with the cli's client transport instance.
+func (cli *DockerCli) HTTPClient() *http.Client {
+	return &http.Client{Transport: cli.transport}
+}
+
+func (cli *DockerCli) encodeData(data interface{}) (*bytes.Buffer, error) {
+	params := bytes.NewBuffer(nil)
+	if data != nil {
+		if err := json.NewEncoder(params).Encode(data); err != nil {
+			return nil, err
+		}
+	}
+	return params, nil
+}
+
+func (cli *DockerCli) clientRequest(method, path string, in io.Reader, headers map[string][]string) (io.ReadCloser, http.Header, int, error) {
+	expectedPayload := (method == "POST" || method == "PUT")
+	if expectedPayload && in == nil {
+		in = bytes.NewReader([]byte{})
+	}
+	req, err := http.NewRequest(method, fmt.Sprintf("/v%s%s", api.APIVERSION, path), in)
+	if err != nil {
+		return nil, nil, -1, err
+	}
+
+	// Add CLI Config's HTTP Headers BEFORE we set the Docker headers
+	// then the user can't change OUR headers
+	for k, v := range cli.configFile.HttpHeaders {
+		req.Header.Set(k, v)
+	}
+
+	req.Header.Set("User-Agent", "Docker-Client/"+dockerversion.VERSION+" ("+runtime.GOOS+")")
+	req.URL.Host = cli.addr
+	req.URL.Scheme = cli.scheme
+
+	if headers != nil {
+		for k, v := range headers {
+			req.Header[k] = v
+		}
+	}
+
+	if expectedPayload && req.Header.Get("Content-Type") == "" {
+		req.Header.Set("Content-Type", "text/plain")
+	}
+
+	resp, err := cli.HTTPClient().Do(req)
+	statusCode := -1
+	if resp != nil {
+		statusCode = resp.StatusCode
+	}
+	if err != nil {
+		if strings.Contains(err.Error(), "connection refused") {
+			return nil, nil, statusCode, errConnectionRefused
+		}
+
+		if cli.tlsConfig == nil {
+			return nil, nil, statusCode, fmt.Errorf("%v. Are you trying to connect to a TLS-enabled daemon without TLS?", err)
+		}
+		return nil, nil, statusCode, fmt.Errorf("An error occurred trying to connect: %v", err)
+	}
+
+	if statusCode < 200 || statusCode >= 400 {
+		body, err := ioutil.ReadAll(resp.Body)
+		if err != nil {
+			return nil, nil, statusCode, err
+		}
+		if len(body) == 0 {
+			return nil, nil, statusCode, fmt.Errorf("Error: request returned %s for API route and version %s, check if the server supports the requested API version", http.StatusText(statusCode), req.URL)
+		}
+		return nil, nil, statusCode, fmt.Errorf("Error response from daemon: %s", bytes.TrimSpace(body))
+	}
+
+	return resp.Body, resp.Header, statusCode, nil
+}
+
+func (cli *DockerCli) clientRequestAttemptLogin(method, path string, in io.Reader, out io.Writer, index *registry.IndexInfo, cmdName string) (io.ReadCloser, int, error) {
+	cmdAttempt := func(authConfig cliconfig.AuthConfig) (io.ReadCloser, int, error) {
+		buf, err := json.Marshal(authConfig)
+		if err != nil {
+			return nil, -1, err
+		}
+		registryAuthHeader := []string{
+			base64.URLEncoding.EncodeToString(buf),
+		}
+
+		// begin the request
+		body, hdr, statusCode, err := cli.clientRequest(method, path, in, map[string][]string{
+			"X-Registry-Auth": registryAuthHeader,
+		})
+		if err == nil && out != nil {
+			// If we are streaming output, complete the stream since
+			// errors may not appear until later.
+			err = cli.streamBody(body, hdr.Get("Content-Type"), true, out, nil)
+		}
+		if err != nil {
+			// Since errors in a stream appear after status 200 has been written,
+			// we may need to change the status code.
+			if strings.Contains(err.Error(), "Authentication is required") ||
+				strings.Contains(err.Error(), "Status 401") ||
+				strings.Contains(err.Error(), "status code 401") {
+				statusCode = http.StatusUnauthorized
+			}
+		}
+		return body, statusCode, err
+	}
+
+	// Resolve the Auth config relevant for this server
+	authConfig := registry.ResolveAuthConfig(cli.configFile, index)
+	body, statusCode, err := cmdAttempt(authConfig)
+	if statusCode == http.StatusUnauthorized {
+		fmt.Fprintf(cli.out, "\nPlease login prior to %s:\n", cmdName)
+		if err = cli.CmdLogin(index.GetAuthConfigKey()); err != nil {
+			return nil, -1, err
+		}
+		authConfig = registry.ResolveAuthConfig(cli.configFile, index)
+		return cmdAttempt(authConfig)
+	}
+	return body, statusCode, err
+}
+
+func (cli *DockerCli) call(method, path string, data interface{}, headers map[string][]string) (io.ReadCloser, http.Header, int, error) {
+	params, err := cli.encodeData(data)
+	if err != nil {
+		return nil, nil, -1, err
+	}
+
+	if data != nil {
+		if headers == nil {
+			headers = make(map[string][]string)
+		}
+		headers["Content-Type"] = []string{"application/json"}
+	}
+
+	body, hdr, statusCode, err := cli.clientRequest(method, path, params, headers)
+	return body, hdr, statusCode, err
+}
+
+type streamOpts struct {
+	rawTerminal bool
+	in          io.Reader
+	out         io.Writer
+	err         io.Writer
+	headers     map[string][]string
+}
+
+func (cli *DockerCli) stream(method, path string, opts *streamOpts) error {
+	body, hdr, _, err := cli.clientRequest(method, path, opts.in, opts.headers)
+	if err != nil {
+		return err
+	}
+	return cli.streamBody(body, hdr.Get("Content-Type"), opts.rawTerminal, opts.out, opts.err)
+}
+
+func (cli *DockerCli) streamBody(body io.ReadCloser, contentType string, rawTerminal bool, stdout, stderr io.Writer) error {
+	defer body.Close()
+
+	if api.MatchesContentType(contentType, "application/json") {
+		return jsonmessage.DisplayJSONMessagesStream(body, stdout, cli.outFd, cli.isTerminalOut)
+	}
+	if stdout != nil || stderr != nil {
+		// When TTY is ON, use regular copy
+		var err error
+		if rawTerminal {
+			_, err = io.Copy(stdout, body)
+		} else {
+			_, err = stdcopy.StdCopy(stdout, stderr, body)
+		}
+		logrus.Debugf("[stream] End of stdout")
+		return err
+	}
+	return nil
+}
+
+func (cli *DockerCli) resizeTty(id string, isExec bool) {
+	height, width := cli.getTtySize()
+	if height == 0 && width == 0 {
+		return
+	}
+	v := url.Values{}
+	v.Set("h", strconv.Itoa(height))
+	v.Set("w", strconv.Itoa(width))
+
+	path := ""
+	if !isExec {
+		path = "/containers/" + id + "/resize?"
+	} else {
+		path = "/exec/" + id + "/resize?"
+	}
+
+	if _, _, err := readBody(cli.call("POST", path+v.Encode(), nil, nil)); err != nil {
+		logrus.Debugf("Error resize: %s", err)
+	}
+}
+
+func waitForExit(cli *DockerCli, containerID string) (int, error) {
+	stream, _, _, err := cli.call("POST", "/containers/"+containerID+"/wait", nil, nil)
+	if err != nil {
+		return -1, err
+	}
+
+	var res types.ContainerWaitResponse
+	if err := json.NewDecoder(stream).Decode(&res); err != nil {
+		return -1, err
+	}
+
+	return res.StatusCode, nil
+}
+
+// getExitCode perform an inspect on the container. It returns
+// the running state and the exit code.
+func getExitCode(cli *DockerCli, containerID string) (bool, int, error) {
+	stream, _, _, err := cli.call("GET", "/containers/"+containerID+"/json", nil, nil)
+	if err != nil {
+		// If we can't connect, then the daemon probably died.
+		if err != errConnectionRefused {
+			return false, -1, err
+		}
+		return false, -1, nil
+	}
+
+	var c types.ContainerJSON
+	if err := json.NewDecoder(stream).Decode(&c); err != nil {
+		return false, -1, err
+	}
+
+	return c.State.Running, c.State.ExitCode, nil
+}
+
+// getExecExitCode perform an inspect on the exec command. It returns
+// the running state and the exit code.
+func getExecExitCode(cli *DockerCli, execID string) (bool, int, error) {
+	stream, _, _, err := cli.call("GET", "/exec/"+execID+"/json", nil, nil)
+	if err != nil {
+		// If we can't connect, then the daemon probably died.
+		if err != errConnectionRefused {
+			return false, -1, err
+		}
+		return false, -1, nil
+	}
+
+	//TODO: Should we reconsider having a type in api/types?
+	//this is a response to exex/id/json not container
+	var c struct {
+		Running  bool
+		ExitCode int
+	}
+
+	if err := json.NewDecoder(stream).Decode(&c); err != nil {
+		return false, -1, err
+	}
+
+	return c.Running, c.ExitCode, nil
+}
+
+func (cli *DockerCli) monitorTtySize(id string, isExec bool) error {
+	cli.resizeTty(id, isExec)
+
+	if runtime.GOOS == "windows" {
+		go func() {
+			prevH, prevW := cli.getTtySize()
+			for {
+				time.Sleep(time.Millisecond * 250)
+				h, w := cli.getTtySize()
+
+				if prevW != w || prevH != h {
+					cli.resizeTty(id, isExec)
+				}
+				prevH = h
+				prevW = w
+			}
+		}()
+	} else {
+		sigchan := make(chan os.Signal, 1)
+		gosignal.Notify(sigchan, signal.SIGWINCH)
+		go func() {
+			for range sigchan {
+				cli.resizeTty(id, isExec)
+			}
+		}()
+	}
+	return nil
+}
+
+func (cli *DockerCli) getTtySize() (int, int) {
+	if !cli.isTerminalOut {
+		return 0, 0
+	}
+	ws, err := term.GetWinsize(cli.outFd)
+	if err != nil {
+		logrus.Debugf("Error getting size: %s", err)
+		if ws == nil {
+			return 0, 0
+		}
+	}
+	return int(ws.Height), int(ws.Width)
+}
+
+func readBody(stream io.ReadCloser, hdr http.Header, statusCode int, err error) ([]byte, int, error) {
+	if stream != nil {
+		defer stream.Close()
+	}
+	if err != nil {
+		return nil, statusCode, err
+	}
+	body, err := ioutil.ReadAll(stream)
+	if err != nil {
+		return nil, -1, err
+	}
+	return body, statusCode, nil
+}

+ 61 - 0
libnetwork/Godeps/_workspace/src/github.com/docker/docker/api/client/version.go

@@ -0,0 +1,61 @@
+package client
+
+import (
+	"encoding/json"
+	"fmt"
+	"runtime"
+
+	"github.com/docker/docker/api"
+	"github.com/docker/docker/api/types"
+	"github.com/docker/docker/autogen/dockerversion"
+	flag "github.com/docker/docker/pkg/mflag"
+	"github.com/docker/docker/utils"
+)
+
+// CmdVersion shows Docker version information.
+//
+// Available version information is shown for: client Docker version, client API version, client Go version, client Git commit, client OS/Arch, server Docker version, server API version, server Go version, server Git commit, and server OS/Arch.
+//
+// Usage: docker version
+func (cli *DockerCli) CmdVersion(args ...string) error {
+	cmd := cli.Subcmd("version", "", "Show the Docker version information.", true)
+	cmd.Require(flag.Exact, 0)
+
+	cmd.ParseFlags(args, true)
+
+	if dockerversion.VERSION != "" {
+		fmt.Fprintf(cli.out, "Client version: %s\n", dockerversion.VERSION)
+	}
+	fmt.Fprintf(cli.out, "Client API version: %s\n", api.APIVERSION)
+	fmt.Fprintf(cli.out, "Go version (client): %s\n", runtime.Version())
+	if dockerversion.GITCOMMIT != "" {
+		fmt.Fprintf(cli.out, "Git commit (client): %s\n", dockerversion.GITCOMMIT)
+	}
+	fmt.Fprintf(cli.out, "OS/Arch (client): %s/%s\n", runtime.GOOS, runtime.GOARCH)
+	if utils.ExperimentalBuild() {
+		fmt.Fprintf(cli.out, "Experimental (client): true\n")
+	}
+
+	stream, _, _, err := cli.call("GET", "/version", nil, nil)
+	if err != nil {
+		return err
+	}
+
+	var v types.Version
+	if err := json.NewDecoder(stream).Decode(&v); err != nil {
+		fmt.Fprintf(cli.err, "Error reading remote version: %s\n", err)
+		return err
+	}
+
+	fmt.Fprintf(cli.out, "Server version: %s\n", v.Version)
+	if v.ApiVersion != "" {
+		fmt.Fprintf(cli.out, "Server API version: %s\n", v.ApiVersion)
+	}
+	fmt.Fprintf(cli.out, "Go version (server): %s\n", v.GoVersion)
+	fmt.Fprintf(cli.out, "Git commit (server): %s\n", v.GitCommit)
+	fmt.Fprintf(cli.out, "OS/Arch (server): %s/%s\n", v.Os, v.Arch)
+	if v.Experimental {
+		fmt.Fprintf(cli.out, "Experimental (server): true\n")
+	}
+	return nil
+}

+ 34 - 0
libnetwork/Godeps/_workspace/src/github.com/docker/docker/api/client/wait.go

@@ -0,0 +1,34 @@
+package client
+
+import (
+	"fmt"
+
+	flag "github.com/docker/docker/pkg/mflag"
+)
+
+// CmdWait blocks until a container stops, then prints its exit code.
+//
+// If more than one container is specified, this will wait synchronously on each container.
+//
+// Usage: docker wait CONTAINER [CONTAINER...]
+func (cli *DockerCli) CmdWait(args ...string) error {
+	cmd := cli.Subcmd("wait", "CONTAINER [CONTAINER...]", "Block until a container stops, then print its exit code.", true)
+	cmd.Require(flag.Min, 1)
+
+	cmd.ParseFlags(args, true)
+
+	var errNames []string
+	for _, name := range cmd.Args() {
+		status, err := waitForExit(cli, name)
+		if err != nil {
+			fmt.Fprintf(cli.err, "%s\n", err)
+			errNames = append(errNames, name)
+		} else {
+			fmt.Fprintf(cli.out, "%d\n", status)
+		}
+	}
+	if len(errNames) > 0 {
+		return fmt.Errorf("Error: failed to wait containers: %v", errNames)
+	}
+	return nil
+}

+ 14 - 0
libnetwork/Godeps/_workspace/src/github.com/docker/docker/pkg/ioutils/fmt.go

@@ -0,0 +1,14 @@
+package ioutils
+
+import (
+	"fmt"
+	"io"
+)
+
+// FprintfIfNotEmpty prints the string value if it's not empty
+func FprintfIfNotEmpty(w io.Writer, format, value string) (int, error) {
+	if value != "" {
+		return fmt.Fprintf(w, format, value)
+	}
+	return 0, nil
+}

+ 17 - 0
libnetwork/Godeps/_workspace/src/github.com/docker/docker/pkg/ioutils/fmt_test.go

@@ -0,0 +1,17 @@
+package ioutils
+
+import "testing"
+
+func TestFprintfIfNotEmpty(t *testing.T) {
+	wc := NewWriteCounter(&NopWriter{})
+	n, _ := FprintfIfNotEmpty(wc, "foo%s", "")
+
+	if wc.Count != 0 || n != 0 {
+		t.Errorf("Wrong count: %v vs. %v vs. 0", wc.Count, n)
+	}
+
+	n, _ = FprintfIfNotEmpty(wc, "foo%s", "bar")
+	if wc.Count != 6 || n != 6 {
+		t.Errorf("Wrong count: %v vs. %v vs. 6", wc.Count, n)
+	}
+}

+ 1 - 2
libnetwork/Godeps/_workspace/src/github.com/docker/docker/pkg/ioutils/readers_test.go

@@ -43,10 +43,9 @@ func TestReaderErrWrapperReadOnError(t *testing.T) {
 }
 
 func TestReaderErrWrapperRead(t *testing.T) {
-	called := false
 	reader := strings.NewReader("a string reader.")
 	wrapper := NewReaderErrWrapper(reader, func() {
-		called = true // Should not be called
+		t.Fatalf("readErrWrapper should not have called the anonymous function on failure")
 	})
 	// Read 20 byte (should be ok with the string above)
 	num, err := wrapper.Read(make([]byte, 20))

+ 22 - 7
libnetwork/Godeps/_workspace/src/github.com/docker/docker/pkg/mflag/flag.go

@@ -289,7 +289,8 @@ type FlagSet struct {
 	// Usage is the function called when an error occurs while parsing flags.
 	// The field is a function (not a method) that may be changed to point to
 	// a custom error handler.
-	Usage func()
+	Usage      func()
+	ShortUsage func()
 
 	name             string
 	parsed           bool
@@ -511,6 +512,12 @@ func (f *FlagSet) PrintDefaults() {
 	if runtime.GOOS != "windows" && home == "/" {
 		home = ""
 	}
+
+	// Add a blank line between cmd description and list of options
+	if f.FlagCount() > 0 {
+		fmt.Fprintln(writer, "")
+	}
+
 	f.VisitAll(func(flag *Flag) {
 		format := "  -%s=%s"
 		names := []string{}
@@ -560,10 +567,16 @@ func defaultUsage(f *FlagSet) {
 // Usage prints to standard error a usage message documenting all defined command-line flags.
 // The function is a variable that may be changed to point to a custom function.
 var Usage = func() {
-	fmt.Fprintf(CommandLine.output, "Usage of %s:\n", os.Args[0])
+	fmt.Fprintf(CommandLine.Out(), "Usage of %s:\n", os.Args[0])
 	PrintDefaults()
 }
 
+// Usage prints to standard error a usage message documenting the standard command layout
+// The function is a variable that may be changed to point to a custom function.
+var ShortUsage = func() {
+	fmt.Fprintf(CommandLine.output, "Usage of %s:\n", os.Args[0])
+}
+
 // FlagCount returns the number of flags that have been defined.
 func (f *FlagSet) FlagCount() int { return len(sortFlags(f.formal)) }
 
@@ -1067,12 +1080,15 @@ func (cmd *FlagSet) ParseFlags(args []string, withHelp bool) error {
 		return err
 	}
 	if help != nil && *help {
+		cmd.SetOutput(os.Stdout)
 		cmd.Usage()
-		// just in case Usage does not exit
 		os.Exit(0)
 	}
 	if str := cmd.CheckArgs(); str != "" {
+		cmd.SetOutput(os.Stderr)
 		cmd.ReportError(str, withHelp)
+		cmd.ShortUsage()
+		os.Exit(1)
 	}
 	return nil
 }
@@ -1080,13 +1096,12 @@ func (cmd *FlagSet) ParseFlags(args []string, withHelp bool) error {
 func (cmd *FlagSet) ReportError(str string, withHelp bool) {
 	if withHelp {
 		if os.Args[0] == cmd.Name() {
-			str += ". See '" + os.Args[0] + " --help'"
+			str += ".\nSee '" + os.Args[0] + " --help'"
 		} else {
-			str += ". See '" + os.Args[0] + " " + cmd.Name() + " --help'"
+			str += ".\nSee '" + os.Args[0] + " " + cmd.Name() + " --help'"
 		}
 	}
-	fmt.Fprintf(cmd.Out(), "docker: %s\n", str)
-	os.Exit(1)
+	fmt.Fprintf(cmd.Out(), "docker: %s.\n", str)
 }
 
 // Parsed reports whether f.Parse has been called.

+ 18 - 5
libnetwork/Godeps/_workspace/src/github.com/docker/docker/pkg/plugins/client.go

@@ -31,6 +31,10 @@ type Client struct {
 }
 
 func (c *Client) Call(serviceMethod string, args interface{}, ret interface{}) error {
+	return c.callWithRetry(serviceMethod, args, ret, true)
+}
+
+func (c *Client) callWithRetry(serviceMethod string, args interface{}, ret interface{}, retry bool) error {
 	var buf bytes.Buffer
 	if err := json.NewEncoder(&buf).Encode(args); err != nil {
 		return err
@@ -50,20 +54,25 @@ func (c *Client) Call(serviceMethod string, args interface{}, ret interface{}) e
 	for {
 		resp, err := c.http.Do(req)
 		if err != nil {
+			if !retry {
+				return err
+			}
+
 			timeOff := backoff(retries)
-			if timeOff+time.Since(start) > defaultTimeOut {
+			if abort(start, timeOff) {
 				return err
 			}
 			retries++
-			logrus.Warn("Unable to connect to plugin: %s, retrying in %ds\n", c.addr, timeOff)
+			logrus.Warnf("Unable to connect to plugin: %s, retrying in %v", c.addr, timeOff)
 			time.Sleep(timeOff)
 			continue
 		}
 
+		defer resp.Body.Close()
 		if resp.StatusCode != http.StatusOK {
 			remoteErr, err := ioutil.ReadAll(resp.Body)
 			if err != nil {
-				return nil
+				return fmt.Errorf("Plugin Error: %s", err)
 			}
 			return fmt.Errorf("Plugin Error: %s", remoteErr)
 		}
@@ -73,7 +82,7 @@ func (c *Client) Call(serviceMethod string, args interface{}, ret interface{}) e
 }
 
 func backoff(retries int) time.Duration {
-	b, max := float64(1), float64(defaultTimeOut)
+	b, max := 1, defaultTimeOut
 	for b < max && retries > 0 {
 		b *= 2
 		retries--
@@ -81,7 +90,11 @@ func backoff(retries int) time.Duration {
 	if b > max {
 		b = max
 	}
-	return time.Duration(b)
+	return time.Duration(b) * time.Second
+}
+
+func abort(start time.Time, timeOff time.Duration) bool {
+	return timeOff+time.Since(start) > time.Duration(defaultTimeOut)*time.Second
 }
 
 func configureTCPTransport(tr *http.Transport, proto, addr string) {

+ 43 - 1
libnetwork/Godeps/_workspace/src/github.com/docker/docker/pkg/plugins/client_test.go

@@ -6,6 +6,7 @@ import (
 	"net/http/httptest"
 	"reflect"
 	"testing"
+	"time"
 )
 
 var (
@@ -27,7 +28,7 @@ func teardownRemotePluginServer() {
 
 func TestFailedConnection(t *testing.T) {
 	c := NewClient("tcp://127.0.0.1:1")
-	err := c.Call("Service.Method", nil, nil)
+	err := c.callWithRetry("Service.Method", nil, nil, false)
 	if err == nil {
 		t.Fatal("Unexpected successful connection")
 	}
@@ -61,3 +62,44 @@ func TestEchoInputOutput(t *testing.T) {
 		t.Fatalf("Expected %v, was %v\n", m, output)
 	}
 }
+
+func TestBackoff(t *testing.T) {
+	cases := []struct {
+		retries    int
+		expTimeOff time.Duration
+	}{
+		{0, time.Duration(1)},
+		{1, time.Duration(2)},
+		{2, time.Duration(4)},
+		{4, time.Duration(16)},
+		{6, time.Duration(30)},
+		{10, time.Duration(30)},
+	}
+
+	for _, c := range cases {
+		s := c.expTimeOff * time.Second
+		if d := backoff(c.retries); d != s {
+			t.Fatalf("Retry %v, expected %v, was %v\n", c.retries, s, d)
+		}
+	}
+}
+
+func TestAbortRetry(t *testing.T) {
+	cases := []struct {
+		timeOff  time.Duration
+		expAbort bool
+	}{
+		{time.Duration(1), false},
+		{time.Duration(2), false},
+		{time.Duration(10), false},
+		{time.Duration(30), true},
+		{time.Duration(40), true},
+	}
+
+	for _, c := range cases {
+		s := c.timeOff * time.Second
+		if a := abort(time.Now(), s); a != c.expAbort {
+			t.Fatalf("Duration %v, expected %v, was %v\n", c.timeOff, s, a)
+		}
+	}
+}

+ 1 - 5
libnetwork/Godeps/_workspace/src/github.com/docker/docker/pkg/plugins/discovery_test.go

@@ -5,7 +5,6 @@ import (
 	"io/ioutil"
 	"net"
 	"os"
-	"path"
 	"path/filepath"
 	"reflect"
 	"testing"
@@ -66,6 +65,7 @@ func TestFileSpecPlugin(t *testing.T) {
 	if err != nil {
 		t.Fatal(err)
 	}
+	defer os.RemoveAll(tmpdir)
 
 	cases := []struct {
 		path string
@@ -79,9 +79,6 @@ func TestFileSpecPlugin(t *testing.T) {
 	}
 
 	for _, c := range cases {
-		if err = os.MkdirAll(path.Dir(c.path), 0755); err != nil {
-			t.Fatal(err)
-		}
 		if err = ioutil.WriteFile(c.path, []byte(c.addr), 0644); err != nil {
 			t.Fatal(err)
 		}
@@ -103,6 +100,5 @@ func TestFileSpecPlugin(t *testing.T) {
 		if p.Addr != c.addr {
 			t.Fatalf("Expected plugin addr `%s`, got %s\n", c.addr, p.Addr)
 		}
-		os.Remove(c.path)
 	}
 }

+ 3 - 2
libnetwork/client/client.go

@@ -4,6 +4,7 @@ import (
 	"fmt"
 	"io"
 	"io/ioutil"
+	"net/http"
 	"reflect"
 	"strings"
 
@@ -11,7 +12,7 @@ import (
 )
 
 // CallFunc provides environment specific call utility to invoke backend functions from UI
-type CallFunc func(string, string, interface{}, map[string][]string) (io.ReadCloser, int, error)
+type CallFunc func(string, string, interface{}, map[string][]string) (io.ReadCloser, http.Header, int, error)
 
 // NetworkCli is the UI object for network subcmds
 type NetworkCli struct {
@@ -96,7 +97,7 @@ func (cli *NetworkCli) Subcmd(chain, name, signature, description string, exitOn
 	return flags
 }
 
-func readBody(stream io.ReadCloser, statusCode int, err error) ([]byte, int, error) {
+func readBody(stream io.ReadCloser, hdr http.Header, statusCode int, err error) ([]byte, int, error) {
 	if stream != nil {
 		defer stream.Close()
 	}

+ 7 - 4
libnetwork/client/client_test.go

@@ -5,6 +5,7 @@ import (
 	"encoding/json"
 	"fmt"
 	"io"
+	"net/http"
 	"os"
 	"strings"
 	"testing"
@@ -24,7 +25,7 @@ func TestMain(m *testing.M) {
 	os.Exit(m.Run())
 }
 
-var callbackFunc func(method, path string, data interface{}, headers map[string][]string) (io.ReadCloser, int, error)
+var callbackFunc func(method, path string, data interface{}, headers map[string][]string) (io.ReadCloser, http.Header, int, error)
 var mockNwJSON, mockNwListJSON, mockServiceJSON, mockServiceListJSON []byte
 var mockNwName = "test"
 var mockNwID = "2a3456789"
@@ -45,7 +46,9 @@ func setupMockHTTPCallback() {
 	srvList = append(srvList, ep)
 	mockServiceListJSON, _ = json.Marshal(srvList)
 
-	callbackFunc = func(method, path string, data interface{}, headers map[string][]string) (io.ReadCloser, int, error) {
+	dummyHTTPHdr := http.Header{}
+
+	callbackFunc = func(method, path string, data interface{}, headers map[string][]string) (io.ReadCloser, http.Header, int, error) {
 		var rsp string
 		switch method {
 		case "GET":
@@ -74,7 +77,7 @@ func setupMockHTTPCallback() {
 			} else if strings.HasSuffix(path, "services/"+mockServiceID) {
 				rsp = string(mockServiceJSON)
 			} else if strings.Contains(path, "containers") {
-				return nopCloser{bytes.NewBufferString("")}, 400, fmt.Errorf("Bad Request")
+				return nopCloser{bytes.NewBufferString("")}, dummyHTTPHdr, 400, fmt.Errorf("Bad Request")
 			}
 		case "POST":
 			var data []byte
@@ -90,7 +93,7 @@ func setupMockHTTPCallback() {
 		case "DELETE":
 			rsp = ""
 		}
-		return nopCloser{bytes.NewBufferString(rsp)}, 200, nil
+		return nopCloser{bytes.NewBufferString(rsp)}, dummyHTTPHdr, 200, nil
 	}
 }
 

+ 7 - 7
libnetwork/cmd/dnet/dnet.go

@@ -218,16 +218,16 @@ func newDnetConnection(val string) (*dnetConnection, error) {
 	return &dnetConnection{protoAddrParts[0], protoAddrParts[1]}, nil
 }
 
-func (d *dnetConnection) httpCall(method, path string, data interface{}, headers map[string][]string) (io.ReadCloser, int, error) {
+func (d *dnetConnection) httpCall(method, path string, data interface{}, headers map[string][]string) (io.ReadCloser, http.Header, int, error) {
 	var in io.Reader
 	in, err := encodeData(data)
 	if err != nil {
-		return nil, -1, err
+		return nil, nil, -1, err
 	}
 
 	req, err := http.NewRequest(method, fmt.Sprintf("%s", path), in)
 	if err != nil {
-		return nil, -1, err
+		return nil, nil, -1, err
 	}
 
 	setupRequestHeaders(method, data, req, headers)
@@ -242,18 +242,18 @@ func (d *dnetConnection) httpCall(method, path string, data interface{}, headers
 		statusCode = resp.StatusCode
 	}
 	if err != nil {
-		return nil, statusCode, fmt.Errorf("error when trying to connect: %v", err)
+		return nil, nil, statusCode, fmt.Errorf("error when trying to connect: %v", err)
 	}
 
 	if statusCode < 200 || statusCode >= 400 {
 		body, err := ioutil.ReadAll(resp.Body)
 		if err != nil {
-			return nil, statusCode, err
+			return nil, nil, statusCode, err
 		}
-		return nil, statusCode, fmt.Errorf("error : %s", bytes.TrimSpace(body))
+		return nil, nil, statusCode, fmt.Errorf("error : %s", bytes.TrimSpace(body))
 	}
 
-	return resp.Body, statusCode, nil
+	return resp.Body, resp.Header, statusCode, nil
 }
 
 func setupRequestHeaders(method string, data interface{}, req *http.Request, headers map[string][]string) {