github.com/daaku/docker@v1.5.0/api/client/commands.go (about)

     1  package client
     2  
     3  import (
     4  	"bufio"
     5  	"bytes"
     6  	"encoding/base64"
     7  	"encoding/json"
     8  	"errors"
     9  	"fmt"
    10  	"io"
    11  	"io/ioutil"
    12  	"net/http"
    13  	"net/url"
    14  	"os"
    15  	"os/exec"
    16  	"path"
    17  	"path/filepath"
    18  	"runtime"
    19  	"sort"
    20  	"strconv"
    21  	"strings"
    22  	"sync"
    23  	"text/tabwriter"
    24  	"text/template"
    25  	"time"
    26  
    27  	log "github.com/Sirupsen/logrus"
    28  	"github.com/docker/docker/api"
    29  	"github.com/docker/docker/api/stats"
    30  	"github.com/docker/docker/dockerversion"
    31  	"github.com/docker/docker/engine"
    32  	"github.com/docker/docker/graph"
    33  	"github.com/docker/docker/nat"
    34  	"github.com/docker/docker/opts"
    35  	"github.com/docker/docker/pkg/archive"
    36  	"github.com/docker/docker/pkg/fileutils"
    37  	flag "github.com/docker/docker/pkg/mflag"
    38  	"github.com/docker/docker/pkg/parsers"
    39  	"github.com/docker/docker/pkg/parsers/filters"
    40  	"github.com/docker/docker/pkg/promise"
    41  	"github.com/docker/docker/pkg/signal"
    42  	"github.com/docker/docker/pkg/symlink"
    43  	"github.com/docker/docker/pkg/term"
    44  	"github.com/docker/docker/pkg/timeutils"
    45  	"github.com/docker/docker/pkg/units"
    46  	"github.com/docker/docker/pkg/urlutil"
    47  	"github.com/docker/docker/registry"
    48  	"github.com/docker/docker/runconfig"
    49  	"github.com/docker/docker/utils"
    50  )
    51  
    52  const (
    53  	tarHeaderSize = 512
    54  )
    55  
    56  func (cli *DockerCli) CmdHelp(args ...string) error {
    57  	if len(args) > 1 {
    58  		method, exists := cli.getMethod(args[:2]...)
    59  		if exists {
    60  			method("--help")
    61  			return nil
    62  		}
    63  	}
    64  	if len(args) > 0 {
    65  		method, exists := cli.getMethod(args[0])
    66  		if !exists {
    67  			fmt.Fprintf(cli.err, "docker: '%s' is not a docker command. See 'docker --help'.\n", args[0])
    68  			os.Exit(1)
    69  		} else {
    70  			method("--help")
    71  			return nil
    72  		}
    73  	}
    74  
    75  	flag.Usage()
    76  
    77  	return nil
    78  }
    79  
    80  func (cli *DockerCli) CmdBuild(args ...string) error {
    81  	cmd := cli.Subcmd("build", "PATH | URL | -", "Build a new image from the source code at PATH", true)
    82  	tag := cmd.String([]string{"t", "-tag"}, "", "Repository name (and optionally a tag) to be applied to the resulting image in case of success")
    83  	suppressOutput := cmd.Bool([]string{"q", "-quiet"}, false, "Suppress the verbose output generated by the containers")
    84  	noCache := cmd.Bool([]string{"#no-cache", "-no-cache"}, false, "Do not use cache when building the image")
    85  	rm := cmd.Bool([]string{"#rm", "-rm"}, true, "Remove intermediate containers after a successful build")
    86  	forceRm := cmd.Bool([]string{"-force-rm"}, false, "Always remove intermediate containers, even after unsuccessful builds")
    87  	pull := cmd.Bool([]string{"-pull"}, false, "Always attempt to pull a newer version of the image")
    88  	dockerfileName := cmd.String([]string{"f", "-file"}, "", "Name of the Dockerfile(Default is 'Dockerfile' at context root)")
    89  
    90  	cmd.Require(flag.Exact, 1)
    91  
    92  	utils.ParseFlags(cmd, args, true)
    93  
    94  	var (
    95  		context  archive.Archive
    96  		isRemote bool
    97  		err      error
    98  	)
    99  
   100  	_, err = exec.LookPath("git")
   101  	hasGit := err == nil
   102  	if cmd.Arg(0) == "-" {
   103  		// As a special case, 'docker build -' will build from either an empty context with the
   104  		// contents of stdin as a Dockerfile, or a tar-ed context from stdin.
   105  		buf := bufio.NewReader(cli.in)
   106  		magic, err := buf.Peek(tarHeaderSize)
   107  		if err != nil && err != io.EOF {
   108  			return fmt.Errorf("failed to peek context header from STDIN: %v", err)
   109  		}
   110  		if !archive.IsArchive(magic) {
   111  			dockerfile, err := ioutil.ReadAll(buf)
   112  			if err != nil {
   113  				return fmt.Errorf("failed to read Dockerfile from STDIN: %v", err)
   114  			}
   115  			if *dockerfileName == "" {
   116  				*dockerfileName = api.DefaultDockerfileName
   117  			}
   118  			context, err = archive.Generate(*dockerfileName, string(dockerfile))
   119  		} else {
   120  			context = ioutil.NopCloser(buf)
   121  		}
   122  	} else if urlutil.IsURL(cmd.Arg(0)) && (!urlutil.IsGitURL(cmd.Arg(0)) || !hasGit) {
   123  		isRemote = true
   124  	} else {
   125  		root := cmd.Arg(0)
   126  		if urlutil.IsGitURL(root) {
   127  			remoteURL := cmd.Arg(0)
   128  			if !urlutil.IsGitTransport(remoteURL) {
   129  				remoteURL = "https://" + remoteURL
   130  			}
   131  
   132  			root, err = ioutil.TempDir("", "docker-build-git")
   133  			if err != nil {
   134  				return err
   135  			}
   136  			defer os.RemoveAll(root)
   137  
   138  			if output, err := exec.Command("git", "clone", "--recursive", remoteURL, root).CombinedOutput(); err != nil {
   139  				return fmt.Errorf("Error trying to use git: %s (%s)", err, output)
   140  			}
   141  		}
   142  		if _, err := os.Stat(root); err != nil {
   143  			return err
   144  		}
   145  
   146  		absRoot, err := filepath.Abs(root)
   147  		if err != nil {
   148  			return err
   149  		}
   150  
   151  		filename := *dockerfileName // path to Dockerfile
   152  
   153  		if *dockerfileName == "" {
   154  			// No -f/--file was specified so use the default
   155  			*dockerfileName = api.DefaultDockerfileName
   156  			filename = path.Join(absRoot, *dockerfileName)
   157  		}
   158  
   159  		origDockerfile := *dockerfileName // used for error msg
   160  
   161  		if filename, err = filepath.Abs(filename); err != nil {
   162  			return err
   163  		}
   164  
   165  		// Verify that 'filename' is within the build context
   166  		filename, err = symlink.FollowSymlinkInScope(filename, absRoot)
   167  		if err != nil {
   168  			return fmt.Errorf("The Dockerfile (%s) must be within the build context (%s)", origDockerfile, root)
   169  		}
   170  
   171  		// Now reset the dockerfileName to be relative to the build context
   172  		*dockerfileName, err = filepath.Rel(absRoot, filename)
   173  		if err != nil {
   174  			return err
   175  		}
   176  
   177  		if _, err = os.Lstat(filename); os.IsNotExist(err) {
   178  			return fmt.Errorf("Cannot locate Dockerfile: %s", origDockerfile)
   179  		}
   180  		var includes = []string{"."}
   181  
   182  		excludes, err := utils.ReadDockerIgnore(path.Join(root, ".dockerignore"))
   183  		if err != nil {
   184  			return err
   185  		}
   186  
   187  		// If .dockerignore mentions .dockerignore or the Dockerfile
   188  		// then make sure we send both files over to the daemon
   189  		// because Dockerfile is, obviously, needed no matter what, and
   190  		// .dockerignore is needed to know if either one needs to be
   191  		// removed.  The deamon will remove them for us, if needed, after it
   192  		// parses the Dockerfile.
   193  		keepThem1, _ := fileutils.Matches(".dockerignore", excludes)
   194  		keepThem2, _ := fileutils.Matches(*dockerfileName, excludes)
   195  		if keepThem1 || keepThem2 {
   196  			includes = append(includes, ".dockerignore", *dockerfileName)
   197  		}
   198  
   199  		if err = utils.ValidateContextDirectory(root, excludes); err != nil {
   200  			return fmt.Errorf("Error checking context is accessible: '%s'. Please check permissions and try again.", err)
   201  		}
   202  		options := &archive.TarOptions{
   203  			Compression:     archive.Uncompressed,
   204  			ExcludePatterns: excludes,
   205  			IncludeFiles:    includes,
   206  		}
   207  		context, err = archive.TarWithOptions(root, options)
   208  		if err != nil {
   209  			return err
   210  		}
   211  	}
   212  	var body io.Reader
   213  	// Setup an upload progress bar
   214  	// FIXME: ProgressReader shouldn't be this annoying to use
   215  	if context != nil {
   216  		sf := utils.NewStreamFormatter(false)
   217  		body = utils.ProgressReader(context, 0, cli.out, sf, true, "", "Sending build context to Docker daemon")
   218  	}
   219  	// Send the build context
   220  	v := &url.Values{}
   221  
   222  	//Check if the given image name can be resolved
   223  	if *tag != "" {
   224  		repository, tag := parsers.ParseRepositoryTag(*tag)
   225  		if err := registry.ValidateRepositoryName(repository); err != nil {
   226  			return err
   227  		}
   228  		if len(tag) > 0 {
   229  			if err := graph.ValidateTagName(tag); err != nil {
   230  				return err
   231  			}
   232  		}
   233  	}
   234  
   235  	v.Set("t", *tag)
   236  
   237  	if *suppressOutput {
   238  		v.Set("q", "1")
   239  	}
   240  	if isRemote {
   241  		v.Set("remote", cmd.Arg(0))
   242  	}
   243  	if *noCache {
   244  		v.Set("nocache", "1")
   245  	}
   246  	if *rm {
   247  		v.Set("rm", "1")
   248  	} else {
   249  		v.Set("rm", "0")
   250  	}
   251  
   252  	if *forceRm {
   253  		v.Set("forcerm", "1")
   254  	}
   255  
   256  	if *pull {
   257  		v.Set("pull", "1")
   258  	}
   259  
   260  	v.Set("dockerfile", *dockerfileName)
   261  
   262  	cli.LoadConfigFile()
   263  
   264  	headers := http.Header(make(map[string][]string))
   265  	buf, err := json.Marshal(cli.configFile)
   266  	if err != nil {
   267  		return err
   268  	}
   269  	headers.Add("X-Registry-Config", base64.URLEncoding.EncodeToString(buf))
   270  
   271  	if context != nil {
   272  		headers.Set("Content-Type", "application/tar")
   273  	}
   274  	err = cli.stream("POST", fmt.Sprintf("/build?%s", v.Encode()), body, cli.out, headers)
   275  	if jerr, ok := err.(*utils.JSONError); ok {
   276  		// If no error code is set, default to 1
   277  		if jerr.Code == 0 {
   278  			jerr.Code = 1
   279  		}
   280  		return &utils.StatusError{Status: jerr.Message, StatusCode: jerr.Code}
   281  	}
   282  	return err
   283  }
   284  
   285  // 'docker login': login / register a user to registry service.
   286  func (cli *DockerCli) CmdLogin(args ...string) error {
   287  	cmd := cli.Subcmd("login", "[SERVER]", "Register or log in to a Docker registry server, if no server is specified \""+registry.IndexServerAddress()+"\" is the default.", true)
   288  	cmd.Require(flag.Max, 1)
   289  
   290  	var username, password, email string
   291  
   292  	cmd.StringVar(&username, []string{"u", "-username"}, "", "Username")
   293  	cmd.StringVar(&password, []string{"p", "-password"}, "", "Password")
   294  	cmd.StringVar(&email, []string{"e", "-email"}, "", "Email")
   295  
   296  	utils.ParseFlags(cmd, args, true)
   297  
   298  	serverAddress := registry.IndexServerAddress()
   299  	if len(cmd.Args()) > 0 {
   300  		serverAddress = cmd.Arg(0)
   301  	}
   302  
   303  	promptDefault := func(prompt string, configDefault string) {
   304  		if configDefault == "" {
   305  			fmt.Fprintf(cli.out, "%s: ", prompt)
   306  		} else {
   307  			fmt.Fprintf(cli.out, "%s (%s): ", prompt, configDefault)
   308  		}
   309  	}
   310  
   311  	readInput := func(in io.Reader, out io.Writer) string {
   312  		reader := bufio.NewReader(in)
   313  		line, _, err := reader.ReadLine()
   314  		if err != nil {
   315  			fmt.Fprintln(out, err.Error())
   316  			os.Exit(1)
   317  		}
   318  		return string(line)
   319  	}
   320  
   321  	cli.LoadConfigFile()
   322  	authconfig, ok := cli.configFile.Configs[serverAddress]
   323  	if !ok {
   324  		authconfig = registry.AuthConfig{}
   325  	}
   326  
   327  	if username == "" {
   328  		promptDefault("Username", authconfig.Username)
   329  		username = readInput(cli.in, cli.out)
   330  		if username == "" {
   331  			username = authconfig.Username
   332  		}
   333  	}
   334  	// Assume that a different username means they may not want to use
   335  	// the password or email from the config file, so prompt them
   336  	if username != authconfig.Username {
   337  		if password == "" {
   338  			oldState, err := term.SaveState(cli.inFd)
   339  			if err != nil {
   340  				return err
   341  			}
   342  			fmt.Fprintf(cli.out, "Password: ")
   343  			term.DisableEcho(cli.inFd, oldState)
   344  
   345  			password = readInput(cli.in, cli.out)
   346  			fmt.Fprint(cli.out, "\n")
   347  
   348  			term.RestoreTerminal(cli.inFd, oldState)
   349  			if password == "" {
   350  				return fmt.Errorf("Error : Password Required")
   351  			}
   352  		}
   353  
   354  		if email == "" {
   355  			promptDefault("Email", authconfig.Email)
   356  			email = readInput(cli.in, cli.out)
   357  			if email == "" {
   358  				email = authconfig.Email
   359  			}
   360  		}
   361  	} else {
   362  		// However, if they don't override the username use the
   363  		// password or email from the cmd line if specified. IOW, allow
   364  		// then to change/overide them.  And if not specified, just
   365  		// use what's in the config file
   366  		if password == "" {
   367  			password = authconfig.Password
   368  		}
   369  		if email == "" {
   370  			email = authconfig.Email
   371  		}
   372  	}
   373  	authconfig.Username = username
   374  	authconfig.Password = password
   375  	authconfig.Email = email
   376  	authconfig.ServerAddress = serverAddress
   377  	cli.configFile.Configs[serverAddress] = authconfig
   378  
   379  	stream, statusCode, err := cli.call("POST", "/auth", cli.configFile.Configs[serverAddress], false)
   380  	if statusCode == 401 {
   381  		delete(cli.configFile.Configs, serverAddress)
   382  		registry.SaveConfig(cli.configFile)
   383  		return err
   384  	}
   385  	if err != nil {
   386  		return err
   387  	}
   388  	var out2 engine.Env
   389  	err = out2.Decode(stream)
   390  	if err != nil {
   391  		cli.configFile, _ = registry.LoadConfig(os.Getenv("HOME"))
   392  		return err
   393  	}
   394  	registry.SaveConfig(cli.configFile)
   395  	if out2.Get("Status") != "" {
   396  		fmt.Fprintf(cli.out, "%s\n", out2.Get("Status"))
   397  	}
   398  	return nil
   399  }
   400  
   401  // log out from a Docker registry
   402  func (cli *DockerCli) CmdLogout(args ...string) error {
   403  	cmd := cli.Subcmd("logout", "[SERVER]", "Log out from a Docker registry, if no server is specified \""+registry.IndexServerAddress()+"\" is the default.", true)
   404  	cmd.Require(flag.Max, 1)
   405  
   406  	utils.ParseFlags(cmd, args, false)
   407  	serverAddress := registry.IndexServerAddress()
   408  	if len(cmd.Args()) > 0 {
   409  		serverAddress = cmd.Arg(0)
   410  	}
   411  
   412  	cli.LoadConfigFile()
   413  	if _, ok := cli.configFile.Configs[serverAddress]; !ok {
   414  		fmt.Fprintf(cli.out, "Not logged in to %s\n", serverAddress)
   415  	} else {
   416  		fmt.Fprintf(cli.out, "Remove login credentials for %s\n", serverAddress)
   417  		delete(cli.configFile.Configs, serverAddress)
   418  
   419  		if err := registry.SaveConfig(cli.configFile); err != nil {
   420  			return fmt.Errorf("Failed to save docker config: %v", err)
   421  		}
   422  	}
   423  	return nil
   424  }
   425  
   426  // 'docker wait': block until a container stops
   427  func (cli *DockerCli) CmdWait(args ...string) error {
   428  	cmd := cli.Subcmd("wait", "CONTAINER [CONTAINER...]", "Block until a container stops, then print its exit code.", true)
   429  	cmd.Require(flag.Min, 1)
   430  
   431  	utils.ParseFlags(cmd, args, true)
   432  
   433  	var encounteredError error
   434  	for _, name := range cmd.Args() {
   435  		status, err := waitForExit(cli, name)
   436  		if err != nil {
   437  			fmt.Fprintf(cli.err, "%s\n", err)
   438  			encounteredError = fmt.Errorf("Error: failed to wait one or more containers")
   439  		} else {
   440  			fmt.Fprintf(cli.out, "%d\n", status)
   441  		}
   442  	}
   443  	return encounteredError
   444  }
   445  
   446  // 'docker version': show version information
   447  func (cli *DockerCli) CmdVersion(args ...string) error {
   448  	cmd := cli.Subcmd("version", "", "Show the Docker version information.", true)
   449  	cmd.Require(flag.Exact, 0)
   450  
   451  	utils.ParseFlags(cmd, args, false)
   452  
   453  	if dockerversion.VERSION != "" {
   454  		fmt.Fprintf(cli.out, "Client version: %s\n", dockerversion.VERSION)
   455  	}
   456  	fmt.Fprintf(cli.out, "Client API version: %s\n", api.APIVERSION)
   457  	fmt.Fprintf(cli.out, "Go version (client): %s\n", runtime.Version())
   458  	if dockerversion.GITCOMMIT != "" {
   459  		fmt.Fprintf(cli.out, "Git commit (client): %s\n", dockerversion.GITCOMMIT)
   460  	}
   461  	fmt.Fprintf(cli.out, "OS/Arch (client): %s/%s\n", runtime.GOOS, runtime.GOARCH)
   462  
   463  	body, _, err := readBody(cli.call("GET", "/version", nil, false))
   464  	if err != nil {
   465  		return err
   466  	}
   467  
   468  	out := engine.NewOutput()
   469  	remoteVersion, err := out.AddEnv()
   470  	if err != nil {
   471  		log.Errorf("Error reading remote version: %s", err)
   472  		return err
   473  	}
   474  	if _, err := out.Write(body); err != nil {
   475  		log.Errorf("Error reading remote version: %s", err)
   476  		return err
   477  	}
   478  	out.Close()
   479  	fmt.Fprintf(cli.out, "Server version: %s\n", remoteVersion.Get("Version"))
   480  	if apiVersion := remoteVersion.Get("ApiVersion"); apiVersion != "" {
   481  		fmt.Fprintf(cli.out, "Server API version: %s\n", apiVersion)
   482  	}
   483  	fmt.Fprintf(cli.out, "Go version (server): %s\n", remoteVersion.Get("GoVersion"))
   484  	fmt.Fprintf(cli.out, "Git commit (server): %s\n", remoteVersion.Get("GitCommit"))
   485  	return nil
   486  }
   487  
   488  // 'docker info': display system-wide information.
   489  func (cli *DockerCli) CmdInfo(args ...string) error {
   490  	cmd := cli.Subcmd("info", "", "Display system-wide information", true)
   491  	cmd.Require(flag.Exact, 0)
   492  	utils.ParseFlags(cmd, args, false)
   493  
   494  	body, _, err := readBody(cli.call("GET", "/info", nil, false))
   495  	if err != nil {
   496  		return err
   497  	}
   498  
   499  	out := engine.NewOutput()
   500  	remoteInfo, err := out.AddEnv()
   501  	if err != nil {
   502  		return err
   503  	}
   504  
   505  	if _, err := out.Write(body); err != nil {
   506  		log.Errorf("Error reading remote info: %s", err)
   507  		return err
   508  	}
   509  	out.Close()
   510  
   511  	if remoteInfo.Exists("Containers") {
   512  		fmt.Fprintf(cli.out, "Containers: %d\n", remoteInfo.GetInt("Containers"))
   513  	}
   514  	if remoteInfo.Exists("Images") {
   515  		fmt.Fprintf(cli.out, "Images: %d\n", remoteInfo.GetInt("Images"))
   516  	}
   517  	if remoteInfo.Exists("Driver") {
   518  		fmt.Fprintf(cli.out, "Storage Driver: %s\n", remoteInfo.Get("Driver"))
   519  	}
   520  	if remoteInfo.Exists("DriverStatus") {
   521  		var driverStatus [][2]string
   522  		if err := remoteInfo.GetJson("DriverStatus", &driverStatus); err != nil {
   523  			return err
   524  		}
   525  		for _, pair := range driverStatus {
   526  			fmt.Fprintf(cli.out, " %s: %s\n", pair[0], pair[1])
   527  		}
   528  	}
   529  	if remoteInfo.Exists("ExecutionDriver") {
   530  		fmt.Fprintf(cli.out, "Execution Driver: %s\n", remoteInfo.Get("ExecutionDriver"))
   531  	}
   532  	if remoteInfo.Exists("KernelVersion") {
   533  		fmt.Fprintf(cli.out, "Kernel Version: %s\n", remoteInfo.Get("KernelVersion"))
   534  	}
   535  	if remoteInfo.Exists("OperatingSystem") {
   536  		fmt.Fprintf(cli.out, "Operating System: %s\n", remoteInfo.Get("OperatingSystem"))
   537  	}
   538  	if remoteInfo.Exists("NCPU") {
   539  		fmt.Fprintf(cli.out, "CPUs: %d\n", remoteInfo.GetInt("NCPU"))
   540  	}
   541  	if remoteInfo.Exists("MemTotal") {
   542  		fmt.Fprintf(cli.out, "Total Memory: %s\n", units.BytesSize(float64(remoteInfo.GetInt64("MemTotal"))))
   543  	}
   544  	if remoteInfo.Exists("Name") {
   545  		fmt.Fprintf(cli.out, "Name: %s\n", remoteInfo.Get("Name"))
   546  	}
   547  	if remoteInfo.Exists("ID") {
   548  		fmt.Fprintf(cli.out, "ID: %s\n", remoteInfo.Get("ID"))
   549  	}
   550  
   551  	if remoteInfo.GetBool("Debug") || os.Getenv("DEBUG") != "" {
   552  		if remoteInfo.Exists("Debug") {
   553  			fmt.Fprintf(cli.out, "Debug mode (server): %v\n", remoteInfo.GetBool("Debug"))
   554  		}
   555  		fmt.Fprintf(cli.out, "Debug mode (client): %v\n", os.Getenv("DEBUG") != "")
   556  		if remoteInfo.Exists("NFd") {
   557  			fmt.Fprintf(cli.out, "Fds: %d\n", remoteInfo.GetInt("NFd"))
   558  		}
   559  		if remoteInfo.Exists("NGoroutines") {
   560  			fmt.Fprintf(cli.out, "Goroutines: %d\n", remoteInfo.GetInt("NGoroutines"))
   561  		}
   562  		if remoteInfo.Exists("NEventsListener") {
   563  			fmt.Fprintf(cli.out, "EventsListeners: %d\n", remoteInfo.GetInt("NEventsListener"))
   564  		}
   565  		if initSha1 := remoteInfo.Get("InitSha1"); initSha1 != "" {
   566  			fmt.Fprintf(cli.out, "Init SHA1: %s\n", initSha1)
   567  		}
   568  		if initPath := remoteInfo.Get("InitPath"); initPath != "" {
   569  			fmt.Fprintf(cli.out, "Init Path: %s\n", initPath)
   570  		}
   571  		if root := remoteInfo.Get("DockerRootDir"); root != "" {
   572  			fmt.Fprintf(cli.out, "Docker Root Dir: %s\n", root)
   573  		}
   574  	}
   575  
   576  	if len(remoteInfo.GetList("IndexServerAddress")) != 0 {
   577  		cli.LoadConfigFile()
   578  		u := cli.configFile.Configs[remoteInfo.Get("IndexServerAddress")].Username
   579  		if len(u) > 0 {
   580  			fmt.Fprintf(cli.out, "Username: %v\n", u)
   581  			fmt.Fprintf(cli.out, "Registry: %v\n", remoteInfo.GetList("IndexServerAddress"))
   582  		}
   583  	}
   584  	if remoteInfo.Exists("MemoryLimit") && !remoteInfo.GetBool("MemoryLimit") {
   585  		fmt.Fprintf(cli.err, "WARNING: No memory limit support\n")
   586  	}
   587  	if remoteInfo.Exists("SwapLimit") && !remoteInfo.GetBool("SwapLimit") {
   588  		fmt.Fprintf(cli.err, "WARNING: No swap limit support\n")
   589  	}
   590  	if remoteInfo.Exists("IPv4Forwarding") && !remoteInfo.GetBool("IPv4Forwarding") {
   591  		fmt.Fprintf(cli.err, "WARNING: IPv4 forwarding is disabled.\n")
   592  	}
   593  	if remoteInfo.Exists("Labels") {
   594  		fmt.Fprintln(cli.out, "Labels:")
   595  		for _, attribute := range remoteInfo.GetList("Labels") {
   596  			fmt.Fprintf(cli.out, " %s\n", attribute)
   597  		}
   598  	}
   599  
   600  	return nil
   601  }
   602  
   603  func (cli *DockerCli) CmdStop(args ...string) error {
   604  	cmd := cli.Subcmd("stop", "CONTAINER [CONTAINER...]", "Stop a running container by sending SIGTERM and then SIGKILL after a grace period", true)
   605  	nSeconds := cmd.Int([]string{"t", "-time"}, 10, "Number of seconds to wait for the container to stop before killing it. Default is 10 seconds.")
   606  	cmd.Require(flag.Min, 1)
   607  
   608  	utils.ParseFlags(cmd, args, true)
   609  
   610  	v := url.Values{}
   611  	v.Set("t", strconv.Itoa(*nSeconds))
   612  
   613  	var encounteredError error
   614  	for _, name := range cmd.Args() {
   615  		_, _, err := readBody(cli.call("POST", "/containers/"+name+"/stop?"+v.Encode(), nil, false))
   616  		if err != nil {
   617  			fmt.Fprintf(cli.err, "%s\n", err)
   618  			encounteredError = fmt.Errorf("Error: failed to stop one or more containers")
   619  		} else {
   620  			fmt.Fprintf(cli.out, "%s\n", name)
   621  		}
   622  	}
   623  	return encounteredError
   624  }
   625  
   626  func (cli *DockerCli) CmdRestart(args ...string) error {
   627  	cmd := cli.Subcmd("restart", "CONTAINER [CONTAINER...]", "Restart a running container", true)
   628  	nSeconds := cmd.Int([]string{"t", "-time"}, 10, "Number of seconds to try to stop for before killing the container. Once killed it will then be restarted. Default is 10 seconds.")
   629  	cmd.Require(flag.Min, 1)
   630  
   631  	utils.ParseFlags(cmd, args, true)
   632  
   633  	v := url.Values{}
   634  	v.Set("t", strconv.Itoa(*nSeconds))
   635  
   636  	var encounteredError error
   637  	for _, name := range cmd.Args() {
   638  		_, _, err := readBody(cli.call("POST", "/containers/"+name+"/restart?"+v.Encode(), nil, false))
   639  		if err != nil {
   640  			fmt.Fprintf(cli.err, "%s\n", err)
   641  			encounteredError = fmt.Errorf("Error: failed to restart one or more containers")
   642  		} else {
   643  			fmt.Fprintf(cli.out, "%s\n", name)
   644  		}
   645  	}
   646  	return encounteredError
   647  }
   648  
   649  func (cli *DockerCli) forwardAllSignals(cid string) chan os.Signal {
   650  	sigc := make(chan os.Signal, 128)
   651  	signal.CatchAll(sigc)
   652  	go func() {
   653  		for s := range sigc {
   654  			if s == signal.SIGCHLD {
   655  				continue
   656  			}
   657  			var sig string
   658  			for sigStr, sigN := range signal.SignalMap {
   659  				if sigN == s {
   660  					sig = sigStr
   661  					break
   662  				}
   663  			}
   664  			if sig == "" {
   665  				log.Errorf("Unsupported signal: %v. Discarding.", s)
   666  			}
   667  			if _, _, err := readBody(cli.call("POST", fmt.Sprintf("/containers/%s/kill?signal=%s", cid, sig), nil, false)); err != nil {
   668  				log.Debugf("Error sending signal: %s", err)
   669  			}
   670  		}
   671  	}()
   672  	return sigc
   673  }
   674  
   675  func (cli *DockerCli) CmdStart(args ...string) error {
   676  	var (
   677  		cErr chan error
   678  		tty  bool
   679  
   680  		cmd       = cli.Subcmd("start", "CONTAINER [CONTAINER...]", "Restart a stopped container", true)
   681  		attach    = cmd.Bool([]string{"a", "-attach"}, false, "Attach container's STDOUT and STDERR and forward all signals to the process")
   682  		openStdin = cmd.Bool([]string{"i", "-interactive"}, false, "Attach container's STDIN")
   683  	)
   684  
   685  	cmd.Require(flag.Min, 1)
   686  	utils.ParseFlags(cmd, args, true)
   687  
   688  	hijacked := make(chan io.Closer)
   689  
   690  	if *attach || *openStdin {
   691  		if cmd.NArg() > 1 {
   692  			return fmt.Errorf("You cannot start and attach multiple containers at once.")
   693  		}
   694  
   695  		stream, _, err := cli.call("GET", "/containers/"+cmd.Arg(0)+"/json", nil, false)
   696  		if err != nil {
   697  			return err
   698  		}
   699  
   700  		env := engine.Env{}
   701  		if err := env.Decode(stream); err != nil {
   702  			return err
   703  		}
   704  		config := env.GetSubEnv("Config")
   705  		tty = config.GetBool("Tty")
   706  
   707  		if !tty {
   708  			sigc := cli.forwardAllSignals(cmd.Arg(0))
   709  			defer signal.StopCatch(sigc)
   710  		}
   711  
   712  		var in io.ReadCloser
   713  
   714  		v := url.Values{}
   715  		v.Set("stream", "1")
   716  
   717  		if *openStdin && config.GetBool("OpenStdin") {
   718  			v.Set("stdin", "1")
   719  			in = cli.in
   720  		}
   721  
   722  		v.Set("stdout", "1")
   723  		v.Set("stderr", "1")
   724  
   725  		cErr = promise.Go(func() error {
   726  			return cli.hijack("POST", "/containers/"+cmd.Arg(0)+"/attach?"+v.Encode(), tty, in, cli.out, cli.err, hijacked, nil)
   727  		})
   728  	} else {
   729  		close(hijacked)
   730  	}
   731  
   732  	// Acknowledge the hijack before starting
   733  	select {
   734  	case closer := <-hijacked:
   735  		// Make sure that the hijack gets closed when returning (results
   736  		// in closing the hijack chan and freeing server's goroutines)
   737  		if closer != nil {
   738  			defer closer.Close()
   739  		}
   740  	case err := <-cErr:
   741  		if err != nil {
   742  			return err
   743  		}
   744  	}
   745  
   746  	var encounteredError error
   747  	for _, name := range cmd.Args() {
   748  		_, _, err := readBody(cli.call("POST", "/containers/"+name+"/start", nil, false))
   749  		if err != nil {
   750  			if !*attach && !*openStdin {
   751  				fmt.Fprintf(cli.err, "%s\n", err)
   752  			}
   753  			encounteredError = fmt.Errorf("Error: failed to start one or more containers")
   754  		} else {
   755  			if !*attach && !*openStdin {
   756  				fmt.Fprintf(cli.out, "%s\n", name)
   757  			}
   758  		}
   759  	}
   760  	if encounteredError != nil {
   761  		if *openStdin || *attach {
   762  			cli.in.Close()
   763  		}
   764  		return encounteredError
   765  	}
   766  
   767  	if *openStdin || *attach {
   768  		if tty && cli.isTerminalOut {
   769  			if err := cli.monitorTtySize(cmd.Arg(0), false); err != nil {
   770  				log.Errorf("Error monitoring TTY size: %s", err)
   771  			}
   772  		}
   773  		if attchErr := <-cErr; attchErr != nil {
   774  			return attchErr
   775  		}
   776  		_, status, err := getExitCode(cli, cmd.Arg(0))
   777  		if err != nil {
   778  			return err
   779  		}
   780  		if status != 0 {
   781  			return &utils.StatusError{StatusCode: status}
   782  		}
   783  	}
   784  	return nil
   785  }
   786  
   787  func (cli *DockerCli) CmdUnpause(args ...string) error {
   788  	cmd := cli.Subcmd("unpause", "CONTAINER", "Unpause all processes within a container", true)
   789  	cmd.Require(flag.Exact, 1)
   790  	utils.ParseFlags(cmd, args, false)
   791  
   792  	var encounteredError error
   793  	for _, name := range cmd.Args() {
   794  		if _, _, err := readBody(cli.call("POST", fmt.Sprintf("/containers/%s/unpause", name), nil, false)); err != nil {
   795  			fmt.Fprintf(cli.err, "%s\n", err)
   796  			encounteredError = fmt.Errorf("Error: failed to unpause container named %s", name)
   797  		} else {
   798  			fmt.Fprintf(cli.out, "%s\n", name)
   799  		}
   800  	}
   801  	return encounteredError
   802  }
   803  
   804  func (cli *DockerCli) CmdPause(args ...string) error {
   805  	cmd := cli.Subcmd("pause", "CONTAINER", "Pause all processes within a container", true)
   806  	cmd.Require(flag.Exact, 1)
   807  	utils.ParseFlags(cmd, args, false)
   808  
   809  	var encounteredError error
   810  	for _, name := range cmd.Args() {
   811  		if _, _, err := readBody(cli.call("POST", fmt.Sprintf("/containers/%s/pause", name), nil, false)); err != nil {
   812  			fmt.Fprintf(cli.err, "%s\n", err)
   813  			encounteredError = fmt.Errorf("Error: failed to pause container named %s", name)
   814  		} else {
   815  			fmt.Fprintf(cli.out, "%s\n", name)
   816  		}
   817  	}
   818  	return encounteredError
   819  }
   820  
   821  func (cli *DockerCli) CmdRename(args ...string) error {
   822  	cmd := cli.Subcmd("rename", "OLD_NAME NEW_NAME", "Rename a container", true)
   823  	if err := cmd.Parse(args); err != nil {
   824  		return nil
   825  	}
   826  
   827  	if cmd.NArg() != 2 {
   828  		cmd.Usage()
   829  		return nil
   830  	}
   831  	old_name := cmd.Arg(0)
   832  	new_name := cmd.Arg(1)
   833  
   834  	if _, _, err := readBody(cli.call("POST", fmt.Sprintf("/containers/%s/rename?name=%s", old_name, new_name), nil, false)); err != nil {
   835  		fmt.Fprintf(cli.err, "%s\n", err)
   836  		return fmt.Errorf("Error: failed to rename container named %s", old_name)
   837  	}
   838  	return nil
   839  }
   840  
   841  func (cli *DockerCli) CmdInspect(args ...string) error {
   842  	cmd := cli.Subcmd("inspect", "CONTAINER|IMAGE [CONTAINER|IMAGE...]", "Return low-level information on a container or image", true)
   843  	tmplStr := cmd.String([]string{"f", "#format", "-format"}, "", "Format the output using the given go template.")
   844  	cmd.Require(flag.Min, 1)
   845  
   846  	utils.ParseFlags(cmd, args, true)
   847  
   848  	var tmpl *template.Template
   849  	if *tmplStr != "" {
   850  		var err error
   851  		if tmpl, err = template.New("").Funcs(funcMap).Parse(*tmplStr); err != nil {
   852  			fmt.Fprintf(cli.err, "Template parsing error: %v\n", err)
   853  			return &utils.StatusError{StatusCode: 64,
   854  				Status: "Template parsing error: " + err.Error()}
   855  		}
   856  	}
   857  
   858  	indented := new(bytes.Buffer)
   859  	indented.WriteByte('[')
   860  	status := 0
   861  
   862  	for _, name := range cmd.Args() {
   863  		obj, _, err := readBody(cli.call("GET", "/containers/"+name+"/json", nil, false))
   864  		if err != nil {
   865  			obj, _, err = readBody(cli.call("GET", "/images/"+name+"/json", nil, false))
   866  			if err != nil {
   867  				if strings.Contains(err.Error(), "No such") {
   868  					fmt.Fprintf(cli.err, "Error: No such image or container: %s\n", name)
   869  				} else {
   870  					fmt.Fprintf(cli.err, "%s", err)
   871  				}
   872  				status = 1
   873  				continue
   874  			}
   875  		}
   876  
   877  		if tmpl == nil {
   878  			if err = json.Indent(indented, obj, "", "    "); err != nil {
   879  				fmt.Fprintf(cli.err, "%s\n", err)
   880  				status = 1
   881  				continue
   882  			}
   883  		} else {
   884  			// Has template, will render
   885  			var value interface{}
   886  			if err := json.Unmarshal(obj, &value); err != nil {
   887  				fmt.Fprintf(cli.err, "%s\n", err)
   888  				status = 1
   889  				continue
   890  			}
   891  			if err := tmpl.Execute(cli.out, value); err != nil {
   892  				return err
   893  			}
   894  			cli.out.Write([]byte{'\n'})
   895  		}
   896  		indented.WriteString(",")
   897  	}
   898  
   899  	if indented.Len() > 1 {
   900  		// Remove trailing ','
   901  		indented.Truncate(indented.Len() - 1)
   902  	}
   903  	indented.WriteString("]\n")
   904  
   905  	if tmpl == nil {
   906  		if _, err := io.Copy(cli.out, indented); err != nil {
   907  			return err
   908  		}
   909  	}
   910  
   911  	if status != 0 {
   912  		return &utils.StatusError{StatusCode: status}
   913  	}
   914  	return nil
   915  }
   916  
   917  func (cli *DockerCli) CmdTop(args ...string) error {
   918  	cmd := cli.Subcmd("top", "CONTAINER [ps OPTIONS]", "Display the running processes of a container", true)
   919  	cmd.Require(flag.Min, 1)
   920  
   921  	utils.ParseFlags(cmd, args, true)
   922  
   923  	val := url.Values{}
   924  	if cmd.NArg() > 1 {
   925  		val.Set("ps_args", strings.Join(cmd.Args()[1:], " "))
   926  	}
   927  
   928  	stream, _, err := cli.call("GET", "/containers/"+cmd.Arg(0)+"/top?"+val.Encode(), nil, false)
   929  	if err != nil {
   930  		return err
   931  	}
   932  	var procs engine.Env
   933  	if err := procs.Decode(stream); err != nil {
   934  		return err
   935  	}
   936  	w := tabwriter.NewWriter(cli.out, 20, 1, 3, ' ', 0)
   937  	fmt.Fprintln(w, strings.Join(procs.GetList("Titles"), "\t"))
   938  	processes := [][]string{}
   939  	if err := procs.GetJson("Processes", &processes); err != nil {
   940  		return err
   941  	}
   942  	for _, proc := range processes {
   943  		fmt.Fprintln(w, strings.Join(proc, "\t"))
   944  	}
   945  	w.Flush()
   946  	return nil
   947  }
   948  
   949  func (cli *DockerCli) CmdPort(args ...string) error {
   950  	cmd := cli.Subcmd("port", "CONTAINER [PRIVATE_PORT[/PROTO]]", "List port mappings for the CONTAINER, or lookup the public-facing port that is NAT-ed to the PRIVATE_PORT", true)
   951  	cmd.Require(flag.Min, 1)
   952  	utils.ParseFlags(cmd, args, true)
   953  
   954  	stream, _, err := cli.call("GET", "/containers/"+cmd.Arg(0)+"/json", nil, false)
   955  	if err != nil {
   956  		return err
   957  	}
   958  
   959  	env := engine.Env{}
   960  	if err := env.Decode(stream); err != nil {
   961  		return err
   962  	}
   963  	ports := nat.PortMap{}
   964  	if err := env.GetSubEnv("NetworkSettings").GetJson("Ports", &ports); err != nil {
   965  		return err
   966  	}
   967  
   968  	if cmd.NArg() == 2 {
   969  		var (
   970  			port  = cmd.Arg(1)
   971  			proto = "tcp"
   972  			parts = strings.SplitN(port, "/", 2)
   973  		)
   974  
   975  		if len(parts) == 2 && len(parts[1]) != 0 {
   976  			port = parts[0]
   977  			proto = parts[1]
   978  		}
   979  		natPort := port + "/" + proto
   980  		if frontends, exists := ports[nat.Port(port+"/"+proto)]; exists && frontends != nil {
   981  			for _, frontend := range frontends {
   982  				fmt.Fprintf(cli.out, "%s:%s\n", frontend.HostIp, frontend.HostPort)
   983  			}
   984  			return nil
   985  		}
   986  		return fmt.Errorf("Error: No public port '%s' published for %s", natPort, cmd.Arg(0))
   987  	}
   988  
   989  	for from, frontends := range ports {
   990  		for _, frontend := range frontends {
   991  			fmt.Fprintf(cli.out, "%s -> %s:%s\n", from, frontend.HostIp, frontend.HostPort)
   992  		}
   993  	}
   994  
   995  	return nil
   996  }
   997  
   998  // 'docker rmi IMAGE' removes all images with the name IMAGE
   999  func (cli *DockerCli) CmdRmi(args ...string) error {
  1000  	var (
  1001  		cmd     = cli.Subcmd("rmi", "IMAGE [IMAGE...]", "Remove one or more images", true)
  1002  		force   = cmd.Bool([]string{"f", "-force"}, false, "Force removal of the image")
  1003  		noprune = cmd.Bool([]string{"-no-prune"}, false, "Do not delete untagged parents")
  1004  	)
  1005  	cmd.Require(flag.Min, 1)
  1006  
  1007  	utils.ParseFlags(cmd, args, true)
  1008  
  1009  	v := url.Values{}
  1010  	if *force {
  1011  		v.Set("force", "1")
  1012  	}
  1013  	if *noprune {
  1014  		v.Set("noprune", "1")
  1015  	}
  1016  
  1017  	var encounteredError error
  1018  	for _, name := range cmd.Args() {
  1019  		body, _, err := readBody(cli.call("DELETE", "/images/"+name+"?"+v.Encode(), nil, false))
  1020  		if err != nil {
  1021  			fmt.Fprintf(cli.err, "%s\n", err)
  1022  			encounteredError = fmt.Errorf("Error: failed to remove one or more images")
  1023  		} else {
  1024  			outs := engine.NewTable("Created", 0)
  1025  			if _, err := outs.ReadListFrom(body); err != nil {
  1026  				fmt.Fprintf(cli.err, "%s\n", err)
  1027  				encounteredError = fmt.Errorf("Error: failed to remove one or more images")
  1028  				continue
  1029  			}
  1030  			for _, out := range outs.Data {
  1031  				if out.Get("Deleted") != "" {
  1032  					fmt.Fprintf(cli.out, "Deleted: %s\n", out.Get("Deleted"))
  1033  				} else {
  1034  					fmt.Fprintf(cli.out, "Untagged: %s\n", out.Get("Untagged"))
  1035  				}
  1036  			}
  1037  		}
  1038  	}
  1039  	return encounteredError
  1040  }
  1041  
  1042  func (cli *DockerCli) CmdHistory(args ...string) error {
  1043  	cmd := cli.Subcmd("history", "IMAGE", "Show the history of an image", true)
  1044  	quiet := cmd.Bool([]string{"q", "-quiet"}, false, "Only show numeric IDs")
  1045  	noTrunc := cmd.Bool([]string{"#notrunc", "-no-trunc"}, false, "Don't truncate output")
  1046  	cmd.Require(flag.Exact, 1)
  1047  
  1048  	utils.ParseFlags(cmd, args, true)
  1049  
  1050  	body, _, err := readBody(cli.call("GET", "/images/"+cmd.Arg(0)+"/history", nil, false))
  1051  	if err != nil {
  1052  		return err
  1053  	}
  1054  
  1055  	outs := engine.NewTable("Created", 0)
  1056  	if _, err := outs.ReadListFrom(body); err != nil {
  1057  		return err
  1058  	}
  1059  
  1060  	w := tabwriter.NewWriter(cli.out, 20, 1, 3, ' ', 0)
  1061  	if !*quiet {
  1062  		fmt.Fprintln(w, "IMAGE\tCREATED\tCREATED BY\tSIZE")
  1063  	}
  1064  
  1065  	for _, out := range outs.Data {
  1066  		outID := out.Get("Id")
  1067  		if !*quiet {
  1068  			if *noTrunc {
  1069  				fmt.Fprintf(w, "%s\t", outID)
  1070  			} else {
  1071  				fmt.Fprintf(w, "%s\t", utils.TruncateID(outID))
  1072  			}
  1073  
  1074  			fmt.Fprintf(w, "%s ago\t", units.HumanDuration(time.Now().UTC().Sub(time.Unix(out.GetInt64("Created"), 0))))
  1075  
  1076  			if *noTrunc {
  1077  				fmt.Fprintf(w, "%s\t", out.Get("CreatedBy"))
  1078  			} else {
  1079  				fmt.Fprintf(w, "%s\t", utils.Trunc(out.Get("CreatedBy"), 45))
  1080  			}
  1081  			fmt.Fprintf(w, "%s\n", units.HumanSize(float64(out.GetInt64("Size"))))
  1082  		} else {
  1083  			if *noTrunc {
  1084  				fmt.Fprintln(w, outID)
  1085  			} else {
  1086  				fmt.Fprintln(w, utils.TruncateID(outID))
  1087  			}
  1088  		}
  1089  	}
  1090  	w.Flush()
  1091  	return nil
  1092  }
  1093  
  1094  func (cli *DockerCli) CmdRm(args ...string) error {
  1095  	cmd := cli.Subcmd("rm", "CONTAINER [CONTAINER...]", "Remove one or more containers", true)
  1096  	v := cmd.Bool([]string{"v", "-volumes"}, false, "Remove the volumes associated with the container")
  1097  	link := cmd.Bool([]string{"l", "#link", "-link"}, false, "Remove the specified link and not the underlying container")
  1098  	force := cmd.Bool([]string{"f", "-force"}, false, "Force the removal of a running container (uses SIGKILL)")
  1099  	cmd.Require(flag.Min, 1)
  1100  
  1101  	utils.ParseFlags(cmd, args, true)
  1102  
  1103  	val := url.Values{}
  1104  	if *v {
  1105  		val.Set("v", "1")
  1106  	}
  1107  	if *link {
  1108  		val.Set("link", "1")
  1109  	}
  1110  
  1111  	if *force {
  1112  		val.Set("force", "1")
  1113  	}
  1114  
  1115  	var encounteredError error
  1116  	for _, name := range cmd.Args() {
  1117  		_, _, err := readBody(cli.call("DELETE", "/containers/"+name+"?"+val.Encode(), nil, false))
  1118  		if err != nil {
  1119  			fmt.Fprintf(cli.err, "%s\n", err)
  1120  			encounteredError = fmt.Errorf("Error: failed to remove one or more containers")
  1121  		} else {
  1122  			fmt.Fprintf(cli.out, "%s\n", name)
  1123  		}
  1124  	}
  1125  	return encounteredError
  1126  }
  1127  
  1128  // 'docker kill NAME' kills a running container
  1129  func (cli *DockerCli) CmdKill(args ...string) error {
  1130  	cmd := cli.Subcmd("kill", "CONTAINER [CONTAINER...]", "Kill a running container using SIGKILL or a specified signal", true)
  1131  	signal := cmd.String([]string{"s", "-signal"}, "KILL", "Signal to send to the container")
  1132  	cmd.Require(flag.Min, 1)
  1133  
  1134  	utils.ParseFlags(cmd, args, true)
  1135  
  1136  	var encounteredError error
  1137  	for _, name := range cmd.Args() {
  1138  		if _, _, err := readBody(cli.call("POST", fmt.Sprintf("/containers/%s/kill?signal=%s", name, *signal), nil, false)); err != nil {
  1139  			fmt.Fprintf(cli.err, "%s\n", err)
  1140  			encounteredError = fmt.Errorf("Error: failed to kill one or more containers")
  1141  		} else {
  1142  			fmt.Fprintf(cli.out, "%s\n", name)
  1143  		}
  1144  	}
  1145  	return encounteredError
  1146  }
  1147  
  1148  func (cli *DockerCli) CmdImport(args ...string) error {
  1149  	cmd := cli.Subcmd("import", "URL|- [REPOSITORY[:TAG]]", "Create an empty filesystem image and import the contents of the tarball (.tar, .tar.gz, .tgz, .bzip, .tar.xz, .txz) into it, then optionally tag it.", true)
  1150  	cmd.Require(flag.Min, 1)
  1151  
  1152  	utils.ParseFlags(cmd, args, true)
  1153  
  1154  	var (
  1155  		v          = url.Values{}
  1156  		src        = cmd.Arg(0)
  1157  		repository = cmd.Arg(1)
  1158  	)
  1159  
  1160  	v.Set("fromSrc", src)
  1161  	v.Set("repo", repository)
  1162  
  1163  	if cmd.NArg() == 3 {
  1164  		fmt.Fprintf(cli.err, "[DEPRECATED] The format 'URL|- [REPOSITORY [TAG]]' has been deprecated. Please use URL|- [REPOSITORY[:TAG]]\n")
  1165  		v.Set("tag", cmd.Arg(2))
  1166  	}
  1167  
  1168  	if repository != "" {
  1169  		//Check if the given image name can be resolved
  1170  		repo, _ := parsers.ParseRepositoryTag(repository)
  1171  		if err := registry.ValidateRepositoryName(repo); err != nil {
  1172  			return err
  1173  		}
  1174  	}
  1175  
  1176  	var in io.Reader
  1177  
  1178  	if src == "-" {
  1179  		in = cli.in
  1180  	}
  1181  
  1182  	return cli.stream("POST", "/images/create?"+v.Encode(), in, cli.out, nil)
  1183  }
  1184  
  1185  func (cli *DockerCli) CmdPush(args ...string) error {
  1186  	cmd := cli.Subcmd("push", "NAME[:TAG]", "Push an image or a repository to the registry", true)
  1187  	cmd.Require(flag.Exact, 1)
  1188  
  1189  	utils.ParseFlags(cmd, args, true)
  1190  
  1191  	name := cmd.Arg(0)
  1192  
  1193  	cli.LoadConfigFile()
  1194  
  1195  	remote, tag := parsers.ParseRepositoryTag(name)
  1196  
  1197  	// Resolve the Repository name from fqn to RepositoryInfo
  1198  	repoInfo, err := registry.ParseRepositoryInfo(remote)
  1199  	if err != nil {
  1200  		return err
  1201  	}
  1202  	// Resolve the Auth config relevant for this server
  1203  	authConfig := cli.configFile.ResolveAuthConfig(repoInfo.Index)
  1204  	// If we're not using a custom registry, we know the restrictions
  1205  	// applied to repository names and can warn the user in advance.
  1206  	// Custom repositories can have different rules, and we must also
  1207  	// allow pushing by image ID.
  1208  	if repoInfo.Official {
  1209  		username := authConfig.Username
  1210  		if username == "" {
  1211  			username = "<user>"
  1212  		}
  1213  		return fmt.Errorf("You cannot push a \"root\" repository. Please rename your repository to <user>/<repo> (ex: %s/%s)", username, repoInfo.LocalName)
  1214  	}
  1215  
  1216  	v := url.Values{}
  1217  	v.Set("tag", tag)
  1218  
  1219  	push := func(authConfig registry.AuthConfig) error {
  1220  		buf, err := json.Marshal(authConfig)
  1221  		if err != nil {
  1222  			return err
  1223  		}
  1224  		registryAuthHeader := []string{
  1225  			base64.URLEncoding.EncodeToString(buf),
  1226  		}
  1227  
  1228  		return cli.stream("POST", "/images/"+remote+"/push?"+v.Encode(), nil, cli.out, map[string][]string{
  1229  			"X-Registry-Auth": registryAuthHeader,
  1230  		})
  1231  	}
  1232  
  1233  	if err := push(authConfig); err != nil {
  1234  		if strings.Contains(err.Error(), "Status 401") {
  1235  			fmt.Fprintln(cli.out, "\nPlease login prior to push:")
  1236  			if err := cli.CmdLogin(repoInfo.Index.GetAuthConfigKey()); err != nil {
  1237  				return err
  1238  			}
  1239  			authConfig := cli.configFile.ResolveAuthConfig(repoInfo.Index)
  1240  			return push(authConfig)
  1241  		}
  1242  		return err
  1243  	}
  1244  	return nil
  1245  }
  1246  
  1247  func (cli *DockerCli) CmdPull(args ...string) error {
  1248  	cmd := cli.Subcmd("pull", "NAME[:TAG]", "Pull an image or a repository from the registry", true)
  1249  	allTags := cmd.Bool([]string{"a", "-all-tags"}, false, "Download all tagged images in the repository")
  1250  	cmd.Require(flag.Exact, 1)
  1251  
  1252  	utils.ParseFlags(cmd, args, true)
  1253  
  1254  	var (
  1255  		v         = url.Values{}
  1256  		remote    = cmd.Arg(0)
  1257  		newRemote = remote
  1258  	)
  1259  	taglessRemote, tag := parsers.ParseRepositoryTag(remote)
  1260  	if tag == "" && !*allTags {
  1261  		newRemote = taglessRemote + ":" + graph.DEFAULTTAG
  1262  	}
  1263  	if tag != "" && *allTags {
  1264  		return fmt.Errorf("tag can't be used with --all-tags/-a")
  1265  	}
  1266  
  1267  	v.Set("fromImage", newRemote)
  1268  
  1269  	// Resolve the Repository name from fqn to RepositoryInfo
  1270  	repoInfo, err := registry.ParseRepositoryInfo(taglessRemote)
  1271  	if err != nil {
  1272  		return err
  1273  	}
  1274  
  1275  	cli.LoadConfigFile()
  1276  
  1277  	// Resolve the Auth config relevant for this server
  1278  	authConfig := cli.configFile.ResolveAuthConfig(repoInfo.Index)
  1279  
  1280  	pull := func(authConfig registry.AuthConfig) error {
  1281  		buf, err := json.Marshal(authConfig)
  1282  		if err != nil {
  1283  			return err
  1284  		}
  1285  		registryAuthHeader := []string{
  1286  			base64.URLEncoding.EncodeToString(buf),
  1287  		}
  1288  
  1289  		return cli.stream("POST", "/images/create?"+v.Encode(), nil, cli.out, map[string][]string{
  1290  			"X-Registry-Auth": registryAuthHeader,
  1291  		})
  1292  	}
  1293  
  1294  	if err := pull(authConfig); err != nil {
  1295  		if strings.Contains(err.Error(), "Status 401") {
  1296  			fmt.Fprintln(cli.out, "\nPlease login prior to pull:")
  1297  			if err := cli.CmdLogin(repoInfo.Index.GetAuthConfigKey()); err != nil {
  1298  				return err
  1299  			}
  1300  			authConfig := cli.configFile.ResolveAuthConfig(repoInfo.Index)
  1301  			return pull(authConfig)
  1302  		}
  1303  		return err
  1304  	}
  1305  
  1306  	return nil
  1307  }
  1308  
  1309  func (cli *DockerCli) CmdImages(args ...string) error {
  1310  	cmd := cli.Subcmd("images", "[REPOSITORY]", "List images", true)
  1311  	quiet := cmd.Bool([]string{"q", "-quiet"}, false, "Only show numeric IDs")
  1312  	all := cmd.Bool([]string{"a", "-all"}, false, "Show all images (by default filter out the intermediate image layers)")
  1313  	noTrunc := cmd.Bool([]string{"#notrunc", "-no-trunc"}, false, "Don't truncate output")
  1314  	// FIXME: --viz and --tree are deprecated. Remove them in a future version.
  1315  	flViz := cmd.Bool([]string{"#v", "#viz", "#-viz"}, false, "Output graph in graphviz format")
  1316  	flTree := cmd.Bool([]string{"#t", "#tree", "#-tree"}, false, "Output graph in tree format")
  1317  
  1318  	flFilter := opts.NewListOpts(nil)
  1319  	cmd.Var(&flFilter, []string{"f", "-filter"}, "Provide filter values (i.e., 'dangling=true')")
  1320  	cmd.Require(flag.Max, 1)
  1321  
  1322  	utils.ParseFlags(cmd, args, true)
  1323  
  1324  	// Consolidate all filter flags, and sanity check them early.
  1325  	// They'll get process in the daemon/server.
  1326  	imageFilterArgs := filters.Args{}
  1327  	for _, f := range flFilter.GetAll() {
  1328  		var err error
  1329  		imageFilterArgs, err = filters.ParseFlag(f, imageFilterArgs)
  1330  		if err != nil {
  1331  			return err
  1332  		}
  1333  	}
  1334  
  1335  	matchName := cmd.Arg(0)
  1336  	// FIXME: --viz and --tree are deprecated. Remove them in a future version.
  1337  	if *flViz || *flTree {
  1338  		v := url.Values{
  1339  			"all": []string{"1"},
  1340  		}
  1341  		if len(imageFilterArgs) > 0 {
  1342  			filterJson, err := filters.ToParam(imageFilterArgs)
  1343  			if err != nil {
  1344  				return err
  1345  			}
  1346  			v.Set("filters", filterJson)
  1347  		}
  1348  
  1349  		body, _, err := readBody(cli.call("GET", "/images/json?"+v.Encode(), nil, false))
  1350  		if err != nil {
  1351  			return err
  1352  		}
  1353  
  1354  		outs := engine.NewTable("Created", 0)
  1355  		if _, err := outs.ReadListFrom(body); err != nil {
  1356  			return err
  1357  		}
  1358  
  1359  		var (
  1360  			printNode  func(cli *DockerCli, noTrunc bool, image *engine.Env, prefix string)
  1361  			startImage *engine.Env
  1362  
  1363  			roots    = engine.NewTable("Created", outs.Len())
  1364  			byParent = make(map[string]*engine.Table)
  1365  		)
  1366  
  1367  		for _, image := range outs.Data {
  1368  			if image.Get("ParentId") == "" {
  1369  				roots.Add(image)
  1370  			} else {
  1371  				if children, exists := byParent[image.Get("ParentId")]; exists {
  1372  					children.Add(image)
  1373  				} else {
  1374  					byParent[image.Get("ParentId")] = engine.NewTable("Created", 1)
  1375  					byParent[image.Get("ParentId")].Add(image)
  1376  				}
  1377  			}
  1378  
  1379  			if matchName != "" {
  1380  				if matchName == image.Get("Id") || matchName == utils.TruncateID(image.Get("Id")) {
  1381  					startImage = image
  1382  				}
  1383  
  1384  				for _, repotag := range image.GetList("RepoTags") {
  1385  					if repotag == matchName {
  1386  						startImage = image
  1387  					}
  1388  				}
  1389  			}
  1390  		}
  1391  
  1392  		if *flViz {
  1393  			fmt.Fprintf(cli.out, "digraph docker {\n")
  1394  			printNode = (*DockerCli).printVizNode
  1395  		} else {
  1396  			printNode = (*DockerCli).printTreeNode
  1397  		}
  1398  
  1399  		if startImage != nil {
  1400  			root := engine.NewTable("Created", 1)
  1401  			root.Add(startImage)
  1402  			cli.WalkTree(*noTrunc, root, byParent, "", printNode)
  1403  		} else if matchName == "" {
  1404  			cli.WalkTree(*noTrunc, roots, byParent, "", printNode)
  1405  		}
  1406  		if *flViz {
  1407  			fmt.Fprintf(cli.out, " base [style=invisible]\n}\n")
  1408  		}
  1409  	} else {
  1410  		v := url.Values{}
  1411  		if len(imageFilterArgs) > 0 {
  1412  			filterJson, err := filters.ToParam(imageFilterArgs)
  1413  			if err != nil {
  1414  				return err
  1415  			}
  1416  			v.Set("filters", filterJson)
  1417  		}
  1418  
  1419  		if cmd.NArg() == 1 {
  1420  			// FIXME rename this parameter, to not be confused with the filters flag
  1421  			v.Set("filter", matchName)
  1422  		}
  1423  		if *all {
  1424  			v.Set("all", "1")
  1425  		}
  1426  
  1427  		body, _, err := readBody(cli.call("GET", "/images/json?"+v.Encode(), nil, false))
  1428  
  1429  		if err != nil {
  1430  			return err
  1431  		}
  1432  
  1433  		outs := engine.NewTable("Created", 0)
  1434  		if _, err := outs.ReadListFrom(body); err != nil {
  1435  			return err
  1436  		}
  1437  
  1438  		w := tabwriter.NewWriter(cli.out, 20, 1, 3, ' ', 0)
  1439  		if !*quiet {
  1440  			fmt.Fprintln(w, "REPOSITORY\tTAG\tIMAGE ID\tCREATED\tVIRTUAL SIZE")
  1441  		}
  1442  
  1443  		for _, out := range outs.Data {
  1444  			for _, repotag := range out.GetList("RepoTags") {
  1445  
  1446  				repo, tag := parsers.ParseRepositoryTag(repotag)
  1447  				outID := out.Get("Id")
  1448  				if !*noTrunc {
  1449  					outID = utils.TruncateID(outID)
  1450  				}
  1451  
  1452  				if !*quiet {
  1453  					fmt.Fprintf(w, "%s\t%s\t%s\t%s ago\t%s\n", repo, tag, outID, units.HumanDuration(time.Now().UTC().Sub(time.Unix(out.GetInt64("Created"), 0))), units.HumanSize(float64(out.GetInt64("VirtualSize"))))
  1454  				} else {
  1455  					fmt.Fprintln(w, outID)
  1456  				}
  1457  			}
  1458  		}
  1459  
  1460  		if !*quiet {
  1461  			w.Flush()
  1462  		}
  1463  	}
  1464  	return nil
  1465  }
  1466  
  1467  // FIXME: --viz and --tree are deprecated. Remove them in a future version.
  1468  func (cli *DockerCli) WalkTree(noTrunc bool, images *engine.Table, byParent map[string]*engine.Table, prefix string, printNode func(cli *DockerCli, noTrunc bool, image *engine.Env, prefix string)) {
  1469  	length := images.Len()
  1470  	if length > 1 {
  1471  		for index, image := range images.Data {
  1472  			if index+1 == length {
  1473  				printNode(cli, noTrunc, image, prefix+"└─")
  1474  				if subimages, exists := byParent[image.Get("Id")]; exists {
  1475  					cli.WalkTree(noTrunc, subimages, byParent, prefix+"  ", printNode)
  1476  				}
  1477  			} else {
  1478  				printNode(cli, noTrunc, image, prefix+"\u251C─")
  1479  				if subimages, exists := byParent[image.Get("Id")]; exists {
  1480  					cli.WalkTree(noTrunc, subimages, byParent, prefix+"\u2502 ", printNode)
  1481  				}
  1482  			}
  1483  		}
  1484  	} else {
  1485  		for _, image := range images.Data {
  1486  			printNode(cli, noTrunc, image, prefix+"└─")
  1487  			if subimages, exists := byParent[image.Get("Id")]; exists {
  1488  				cli.WalkTree(noTrunc, subimages, byParent, prefix+"  ", printNode)
  1489  			}
  1490  		}
  1491  	}
  1492  }
  1493  
  1494  // FIXME: --viz and --tree are deprecated. Remove them in a future version.
  1495  func (cli *DockerCli) printVizNode(noTrunc bool, image *engine.Env, prefix string) {
  1496  	var (
  1497  		imageID  string
  1498  		parentID string
  1499  	)
  1500  	if noTrunc {
  1501  		imageID = image.Get("Id")
  1502  		parentID = image.Get("ParentId")
  1503  	} else {
  1504  		imageID = utils.TruncateID(image.Get("Id"))
  1505  		parentID = utils.TruncateID(image.Get("ParentId"))
  1506  	}
  1507  	if parentID == "" {
  1508  		fmt.Fprintf(cli.out, " base -> \"%s\" [style=invis]\n", imageID)
  1509  	} else {
  1510  		fmt.Fprintf(cli.out, " \"%s\" -> \"%s\"\n", parentID, imageID)
  1511  	}
  1512  	if image.GetList("RepoTags")[0] != "<none>:<none>" {
  1513  		fmt.Fprintf(cli.out, " \"%s\" [label=\"%s\\n%s\",shape=box,fillcolor=\"paleturquoise\",style=\"filled,rounded\"];\n",
  1514  			imageID, imageID, strings.Join(image.GetList("RepoTags"), "\\n"))
  1515  	}
  1516  }
  1517  
  1518  // FIXME: --viz and --tree are deprecated. Remove them in a future version.
  1519  func (cli *DockerCli) printTreeNode(noTrunc bool, image *engine.Env, prefix string) {
  1520  	var imageID string
  1521  	if noTrunc {
  1522  		imageID = image.Get("Id")
  1523  	} else {
  1524  		imageID = utils.TruncateID(image.Get("Id"))
  1525  	}
  1526  
  1527  	fmt.Fprintf(cli.out, "%s%s Virtual Size: %s", prefix, imageID, units.HumanSize(float64(image.GetInt64("VirtualSize"))))
  1528  	if image.GetList("RepoTags")[0] != "<none>:<none>" {
  1529  		fmt.Fprintf(cli.out, " Tags: %s\n", strings.Join(image.GetList("RepoTags"), ", "))
  1530  	} else {
  1531  		fmt.Fprint(cli.out, "\n")
  1532  	}
  1533  }
  1534  
  1535  func (cli *DockerCli) CmdPs(args ...string) error {
  1536  	var (
  1537  		err error
  1538  
  1539  		psFilterArgs = filters.Args{}
  1540  		v            = url.Values{}
  1541  
  1542  		cmd      = cli.Subcmd("ps", "", "List containers", true)
  1543  		quiet    = cmd.Bool([]string{"q", "-quiet"}, false, "Only display numeric IDs")
  1544  		size     = cmd.Bool([]string{"s", "-size"}, false, "Display total file sizes")
  1545  		all      = cmd.Bool([]string{"a", "-all"}, false, "Show all containers. Only running containers are shown by default.")
  1546  		noTrunc  = cmd.Bool([]string{"#notrunc", "-no-trunc"}, false, "Don't truncate output")
  1547  		nLatest  = cmd.Bool([]string{"l", "-latest"}, false, "Show only the latest created container, include non-running ones.")
  1548  		since    = cmd.String([]string{"#sinceId", "#-since-id", "-since"}, "", "Show only containers created since Id or Name, include non-running ones.")
  1549  		before   = cmd.String([]string{"#beforeId", "#-before-id", "-before"}, "", "Show only container created before Id or Name, include non-running ones.")
  1550  		last     = cmd.Int([]string{"n"}, -1, "Show n last created containers, include non-running ones.")
  1551  		flFilter = opts.NewListOpts(nil)
  1552  	)
  1553  	cmd.Require(flag.Exact, 0)
  1554  
  1555  	cmd.Var(&flFilter, []string{"f", "-filter"}, "Provide filter values. Valid filters:\nexited=<int> - containers with exit code of <int>\nstatus=(restarting|running|paused|exited)")
  1556  
  1557  	utils.ParseFlags(cmd, args, true)
  1558  	if *last == -1 && *nLatest {
  1559  		*last = 1
  1560  	}
  1561  
  1562  	if *all {
  1563  		v.Set("all", "1")
  1564  	}
  1565  
  1566  	if *last != -1 {
  1567  		v.Set("limit", strconv.Itoa(*last))
  1568  	}
  1569  
  1570  	if *since != "" {
  1571  		v.Set("since", *since)
  1572  	}
  1573  
  1574  	if *before != "" {
  1575  		v.Set("before", *before)
  1576  	}
  1577  
  1578  	if *size {
  1579  		v.Set("size", "1")
  1580  	}
  1581  
  1582  	// Consolidate all filter flags, and sanity check them.
  1583  	// They'll get processed in the daemon/server.
  1584  	for _, f := range flFilter.GetAll() {
  1585  		if psFilterArgs, err = filters.ParseFlag(f, psFilterArgs); err != nil {
  1586  			return err
  1587  		}
  1588  	}
  1589  
  1590  	if len(psFilterArgs) > 0 {
  1591  		filterJson, err := filters.ToParam(psFilterArgs)
  1592  		if err != nil {
  1593  			return err
  1594  		}
  1595  
  1596  		v.Set("filters", filterJson)
  1597  	}
  1598  
  1599  	body, _, err := readBody(cli.call("GET", "/containers/json?"+v.Encode(), nil, false))
  1600  	if err != nil {
  1601  		return err
  1602  	}
  1603  
  1604  	outs := engine.NewTable("Created", 0)
  1605  	if _, err := outs.ReadListFrom(body); err != nil {
  1606  		return err
  1607  	}
  1608  
  1609  	w := tabwriter.NewWriter(cli.out, 20, 1, 3, ' ', 0)
  1610  	if !*quiet {
  1611  		fmt.Fprint(w, "CONTAINER ID\tIMAGE\tCOMMAND\tCREATED\tSTATUS\tPORTS\tNAMES")
  1612  
  1613  		if *size {
  1614  			fmt.Fprintln(w, "\tSIZE")
  1615  		} else {
  1616  			fmt.Fprint(w, "\n")
  1617  		}
  1618  	}
  1619  
  1620  	stripNamePrefix := func(ss []string) []string {
  1621  		for i, s := range ss {
  1622  			ss[i] = s[1:]
  1623  		}
  1624  
  1625  		return ss
  1626  	}
  1627  
  1628  	for _, out := range outs.Data {
  1629  		outID := out.Get("Id")
  1630  
  1631  		if !*noTrunc {
  1632  			outID = utils.TruncateID(outID)
  1633  		}
  1634  
  1635  		if *quiet {
  1636  			fmt.Fprintln(w, outID)
  1637  
  1638  			continue
  1639  		}
  1640  
  1641  		var (
  1642  			outNames   = stripNamePrefix(out.GetList("Names"))
  1643  			outCommand = strconv.Quote(out.Get("Command"))
  1644  			ports      = engine.NewTable("", 0)
  1645  		)
  1646  
  1647  		if !*noTrunc {
  1648  			outCommand = utils.Trunc(outCommand, 20)
  1649  
  1650  			// only display the default name for the container with notrunc is passed
  1651  			for _, name := range outNames {
  1652  				if len(strings.Split(name, "/")) == 1 {
  1653  					outNames = []string{name}
  1654  
  1655  					break
  1656  				}
  1657  			}
  1658  		}
  1659  
  1660  		ports.ReadListFrom([]byte(out.Get("Ports")))
  1661  
  1662  		image := out.Get("Image")
  1663  		if image == "" {
  1664  			image = "<no image>"
  1665  		}
  1666  
  1667  		fmt.Fprintf(w, "%s\t%s\t%s\t%s ago\t%s\t%s\t%s\t", outID, image, outCommand,
  1668  			units.HumanDuration(time.Now().UTC().Sub(time.Unix(out.GetInt64("Created"), 0))),
  1669  			out.Get("Status"), api.DisplayablePorts(ports), strings.Join(outNames, ","))
  1670  
  1671  		if *size {
  1672  			if out.GetInt("SizeRootFs") > 0 {
  1673  				fmt.Fprintf(w, "%s (virtual %s)\n", units.HumanSize(float64(out.GetInt64("SizeRw"))), units.HumanSize(float64(out.GetInt64("SizeRootFs"))))
  1674  			} else {
  1675  				fmt.Fprintf(w, "%s\n", units.HumanSize(float64(out.GetInt64("SizeRw"))))
  1676  			}
  1677  
  1678  			continue
  1679  		}
  1680  
  1681  		fmt.Fprint(w, "\n")
  1682  	}
  1683  
  1684  	if !*quiet {
  1685  		w.Flush()
  1686  	}
  1687  
  1688  	return nil
  1689  }
  1690  
  1691  func (cli *DockerCli) CmdCommit(args ...string) error {
  1692  	cmd := cli.Subcmd("commit", "CONTAINER [REPOSITORY[:TAG]]", "Create a new image from a container's changes", true)
  1693  	flPause := cmd.Bool([]string{"p", "-pause"}, true, "Pause container during commit")
  1694  	flComment := cmd.String([]string{"m", "-message"}, "", "Commit message")
  1695  	flAuthor := cmd.String([]string{"a", "#author", "-author"}, "", "Author (e.g., \"John Hannibal Smith <hannibal@a-team.com>\")")
  1696  	// FIXME: --run is deprecated, it will be replaced with inline Dockerfile commands.
  1697  	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")
  1698  	cmd.Require(flag.Max, 2)
  1699  	cmd.Require(flag.Min, 1)
  1700  	utils.ParseFlags(cmd, args, true)
  1701  
  1702  	var (
  1703  		name            = cmd.Arg(0)
  1704  		repository, tag = parsers.ParseRepositoryTag(cmd.Arg(1))
  1705  	)
  1706  
  1707  	//Check if the given image name can be resolved
  1708  	if repository != "" {
  1709  		if err := registry.ValidateRepositoryName(repository); err != nil {
  1710  			return err
  1711  		}
  1712  	}
  1713  
  1714  	v := url.Values{}
  1715  	v.Set("container", name)
  1716  	v.Set("repo", repository)
  1717  	v.Set("tag", tag)
  1718  	v.Set("comment", *flComment)
  1719  	v.Set("author", *flAuthor)
  1720  
  1721  	if *flPause != true {
  1722  		v.Set("pause", "0")
  1723  	}
  1724  
  1725  	var (
  1726  		config *runconfig.Config
  1727  		env    engine.Env
  1728  	)
  1729  	if *flConfig != "" {
  1730  		config = &runconfig.Config{}
  1731  		if err := json.Unmarshal([]byte(*flConfig), config); err != nil {
  1732  			return err
  1733  		}
  1734  	}
  1735  	stream, _, err := cli.call("POST", "/commit?"+v.Encode(), config, false)
  1736  	if err != nil {
  1737  		return err
  1738  	}
  1739  	if err := env.Decode(stream); err != nil {
  1740  		return err
  1741  	}
  1742  
  1743  	fmt.Fprintf(cli.out, "%s\n", env.Get("Id"))
  1744  	return nil
  1745  }
  1746  
  1747  func (cli *DockerCli) CmdEvents(args ...string) error {
  1748  	cmd := cli.Subcmd("events", "", "Get real time events from the server", true)
  1749  	since := cmd.String([]string{"#since", "-since"}, "", "Show all events created since timestamp")
  1750  	until := cmd.String([]string{"-until"}, "", "Stream events until this timestamp")
  1751  	flFilter := opts.NewListOpts(nil)
  1752  	cmd.Var(&flFilter, []string{"f", "-filter"}, "Provide filter values (i.e., 'event=stop')")
  1753  	cmd.Require(flag.Exact, 0)
  1754  
  1755  	utils.ParseFlags(cmd, args, true)
  1756  
  1757  	var (
  1758  		v               = url.Values{}
  1759  		loc             = time.FixedZone(time.Now().Zone())
  1760  		eventFilterArgs = filters.Args{}
  1761  	)
  1762  
  1763  	// Consolidate all filter flags, and sanity check them early.
  1764  	// They'll get process in the daemon/server.
  1765  	for _, f := range flFilter.GetAll() {
  1766  		var err error
  1767  		eventFilterArgs, err = filters.ParseFlag(f, eventFilterArgs)
  1768  		if err != nil {
  1769  			return err
  1770  		}
  1771  	}
  1772  	var setTime = func(key, value string) {
  1773  		format := timeutils.RFC3339NanoFixed
  1774  		if len(value) < len(format) {
  1775  			format = format[:len(value)]
  1776  		}
  1777  		if t, err := time.ParseInLocation(format, value, loc); err == nil {
  1778  			v.Set(key, strconv.FormatInt(t.Unix(), 10))
  1779  		} else {
  1780  			v.Set(key, value)
  1781  		}
  1782  	}
  1783  	if *since != "" {
  1784  		setTime("since", *since)
  1785  	}
  1786  	if *until != "" {
  1787  		setTime("until", *until)
  1788  	}
  1789  	if len(eventFilterArgs) > 0 {
  1790  		filterJson, err := filters.ToParam(eventFilterArgs)
  1791  		if err != nil {
  1792  			return err
  1793  		}
  1794  		v.Set("filters", filterJson)
  1795  	}
  1796  	if err := cli.stream("GET", "/events?"+v.Encode(), nil, cli.out, nil); err != nil {
  1797  		return err
  1798  	}
  1799  	return nil
  1800  }
  1801  
  1802  func (cli *DockerCli) CmdExport(args ...string) error {
  1803  	cmd := cli.Subcmd("export", "CONTAINER", "Export the contents of a filesystem as a tar archive to STDOUT", true)
  1804  	cmd.Require(flag.Exact, 1)
  1805  
  1806  	utils.ParseFlags(cmd, args, true)
  1807  
  1808  	if err := cli.stream("GET", "/containers/"+cmd.Arg(0)+"/export", nil, cli.out, nil); err != nil {
  1809  		return err
  1810  	}
  1811  	return nil
  1812  }
  1813  
  1814  func (cli *DockerCli) CmdDiff(args ...string) error {
  1815  	cmd := cli.Subcmd("diff", "CONTAINER", "Inspect changes on a container's filesystem", true)
  1816  	cmd.Require(flag.Exact, 1)
  1817  
  1818  	utils.ParseFlags(cmd, args, true)
  1819  
  1820  	body, _, err := readBody(cli.call("GET", "/containers/"+cmd.Arg(0)+"/changes", nil, false))
  1821  
  1822  	if err != nil {
  1823  		return err
  1824  	}
  1825  
  1826  	outs := engine.NewTable("", 0)
  1827  	if _, err := outs.ReadListFrom(body); err != nil {
  1828  		return err
  1829  	}
  1830  	for _, change := range outs.Data {
  1831  		var kind string
  1832  		switch change.GetInt("Kind") {
  1833  		case archive.ChangeModify:
  1834  			kind = "C"
  1835  		case archive.ChangeAdd:
  1836  			kind = "A"
  1837  		case archive.ChangeDelete:
  1838  			kind = "D"
  1839  		}
  1840  		fmt.Fprintf(cli.out, "%s %s\n", kind, change.Get("Path"))
  1841  	}
  1842  	return nil
  1843  }
  1844  
  1845  func (cli *DockerCli) CmdLogs(args ...string) error {
  1846  	var (
  1847  		cmd    = cli.Subcmd("logs", "CONTAINER", "Fetch the logs of a container", true)
  1848  		follow = cmd.Bool([]string{"f", "-follow"}, false, "Follow log output")
  1849  		times  = cmd.Bool([]string{"t", "-timestamps"}, false, "Show timestamps")
  1850  		tail   = cmd.String([]string{"-tail"}, "all", "Output the specified number of lines at the end of logs (defaults to all logs)")
  1851  	)
  1852  	cmd.Require(flag.Exact, 1)
  1853  
  1854  	utils.ParseFlags(cmd, args, true)
  1855  
  1856  	name := cmd.Arg(0)
  1857  
  1858  	stream, _, err := cli.call("GET", "/containers/"+name+"/json", nil, false)
  1859  	if err != nil {
  1860  		return err
  1861  	}
  1862  
  1863  	env := engine.Env{}
  1864  	if err := env.Decode(stream); err != nil {
  1865  		return err
  1866  	}
  1867  
  1868  	v := url.Values{}
  1869  	v.Set("stdout", "1")
  1870  	v.Set("stderr", "1")
  1871  
  1872  	if *times {
  1873  		v.Set("timestamps", "1")
  1874  	}
  1875  
  1876  	if *follow {
  1877  		v.Set("follow", "1")
  1878  	}
  1879  	v.Set("tail", *tail)
  1880  
  1881  	return cli.streamHelper("GET", "/containers/"+name+"/logs?"+v.Encode(), env.GetSubEnv("Config").GetBool("Tty"), nil, cli.out, cli.err, nil)
  1882  }
  1883  
  1884  func (cli *DockerCli) CmdAttach(args ...string) error {
  1885  	var (
  1886  		cmd     = cli.Subcmd("attach", "CONTAINER", "Attach to a running container", true)
  1887  		noStdin = cmd.Bool([]string{"#nostdin", "-no-stdin"}, false, "Do not attach STDIN")
  1888  		proxy   = cmd.Bool([]string{"#sig-proxy", "-sig-proxy"}, true, "Proxy all received signals to the process (non-TTY mode only). SIGCHLD, SIGKILL, and SIGSTOP are not proxied.")
  1889  	)
  1890  	cmd.Require(flag.Exact, 1)
  1891  
  1892  	utils.ParseFlags(cmd, args, true)
  1893  	name := cmd.Arg(0)
  1894  
  1895  	stream, _, err := cli.call("GET", "/containers/"+name+"/json", nil, false)
  1896  	if err != nil {
  1897  		return err
  1898  	}
  1899  
  1900  	env := engine.Env{}
  1901  	if err := env.Decode(stream); err != nil {
  1902  		return err
  1903  	}
  1904  
  1905  	if !env.GetSubEnv("State").GetBool("Running") {
  1906  		return fmt.Errorf("You cannot attach to a stopped container, start it first")
  1907  	}
  1908  
  1909  	var (
  1910  		config = env.GetSubEnv("Config")
  1911  		tty    = config.GetBool("Tty")
  1912  	)
  1913  
  1914  	if err := cli.CheckTtyInput(!*noStdin, tty); err != nil {
  1915  		return err
  1916  	}
  1917  
  1918  	if tty && cli.isTerminalOut {
  1919  		if err := cli.monitorTtySize(cmd.Arg(0), false); err != nil {
  1920  			log.Debugf("Error monitoring TTY size: %s", err)
  1921  		}
  1922  	}
  1923  
  1924  	var in io.ReadCloser
  1925  
  1926  	v := url.Values{}
  1927  	v.Set("stream", "1")
  1928  	if !*noStdin && config.GetBool("OpenStdin") {
  1929  		v.Set("stdin", "1")
  1930  		in = cli.in
  1931  	}
  1932  
  1933  	v.Set("stdout", "1")
  1934  	v.Set("stderr", "1")
  1935  
  1936  	if *proxy && !tty {
  1937  		sigc := cli.forwardAllSignals(cmd.Arg(0))
  1938  		defer signal.StopCatch(sigc)
  1939  	}
  1940  
  1941  	if err := cli.hijack("POST", "/containers/"+cmd.Arg(0)+"/attach?"+v.Encode(), tty, in, cli.out, cli.err, nil, nil); err != nil {
  1942  		return err
  1943  	}
  1944  
  1945  	_, status, err := getExitCode(cli, cmd.Arg(0))
  1946  	if err != nil {
  1947  		return err
  1948  	}
  1949  	if status != 0 {
  1950  		return &utils.StatusError{StatusCode: status}
  1951  	}
  1952  
  1953  	return nil
  1954  }
  1955  
  1956  func (cli *DockerCli) CmdSearch(args ...string) error {
  1957  	cmd := cli.Subcmd("search", "TERM", "Search the Docker Hub for images", true)
  1958  	noTrunc := cmd.Bool([]string{"#notrunc", "-no-trunc"}, false, "Don't truncate output")
  1959  	trusted := cmd.Bool([]string{"#t", "#trusted", "#-trusted"}, false, "Only show trusted builds")
  1960  	automated := cmd.Bool([]string{"-automated"}, false, "Only show automated builds")
  1961  	stars := cmd.Int([]string{"s", "#stars", "-stars"}, 0, "Only displays with at least x stars")
  1962  	cmd.Require(flag.Exact, 1)
  1963  
  1964  	utils.ParseFlags(cmd, args, true)
  1965  
  1966  	v := url.Values{}
  1967  	v.Set("term", cmd.Arg(0))
  1968  
  1969  	body, _, err := readBody(cli.call("GET", "/images/search?"+v.Encode(), nil, true))
  1970  
  1971  	if err != nil {
  1972  		return err
  1973  	}
  1974  	outs := engine.NewTable("star_count", 0)
  1975  	if _, err := outs.ReadListFrom(body); err != nil {
  1976  		return err
  1977  	}
  1978  	w := tabwriter.NewWriter(cli.out, 10, 1, 3, ' ', 0)
  1979  	fmt.Fprintf(w, "NAME\tDESCRIPTION\tSTARS\tOFFICIAL\tAUTOMATED\n")
  1980  	for _, out := range outs.Data {
  1981  		if ((*automated || *trusted) && (!out.GetBool("is_trusted") && !out.GetBool("is_automated"))) || (*stars > out.GetInt("star_count")) {
  1982  			continue
  1983  		}
  1984  		desc := strings.Replace(out.Get("description"), "\n", " ", -1)
  1985  		desc = strings.Replace(desc, "\r", " ", -1)
  1986  		if !*noTrunc && len(desc) > 45 {
  1987  			desc = utils.Trunc(desc, 42) + "..."
  1988  		}
  1989  		fmt.Fprintf(w, "%s\t%s\t%d\t", out.Get("name"), desc, out.GetInt("star_count"))
  1990  		if out.GetBool("is_official") {
  1991  			fmt.Fprint(w, "[OK]")
  1992  
  1993  		}
  1994  		fmt.Fprint(w, "\t")
  1995  		if out.GetBool("is_automated") || out.GetBool("is_trusted") {
  1996  			fmt.Fprint(w, "[OK]")
  1997  		}
  1998  		fmt.Fprint(w, "\n")
  1999  	}
  2000  	w.Flush()
  2001  	return nil
  2002  }
  2003  
  2004  // Ports type - Used to parse multiple -p flags
  2005  type ports []int
  2006  
  2007  func (cli *DockerCli) CmdTag(args ...string) error {
  2008  	cmd := cli.Subcmd("tag", "IMAGE[:TAG] [REGISTRYHOST/][USERNAME/]NAME[:TAG]", "Tag an image into a repository", true)
  2009  	force := cmd.Bool([]string{"f", "#force", "-force"}, false, "Force")
  2010  	cmd.Require(flag.Exact, 2)
  2011  
  2012  	utils.ParseFlags(cmd, args, true)
  2013  
  2014  	var (
  2015  		repository, tag = parsers.ParseRepositoryTag(cmd.Arg(1))
  2016  		v               = url.Values{}
  2017  	)
  2018  
  2019  	//Check if the given image name can be resolved
  2020  	if err := registry.ValidateRepositoryName(repository); err != nil {
  2021  		return err
  2022  	}
  2023  	v.Set("repo", repository)
  2024  	v.Set("tag", tag)
  2025  
  2026  	if *force {
  2027  		v.Set("force", "1")
  2028  	}
  2029  
  2030  	if _, _, err := readBody(cli.call("POST", "/images/"+cmd.Arg(0)+"/tag?"+v.Encode(), nil, false)); err != nil {
  2031  		return err
  2032  	}
  2033  	return nil
  2034  }
  2035  
  2036  func (cli *DockerCli) pullImage(image string) error {
  2037  	return cli.pullImageCustomOut(image, cli.out)
  2038  }
  2039  
  2040  func (cli *DockerCli) pullImageCustomOut(image string, out io.Writer) error {
  2041  	v := url.Values{}
  2042  	repos, tag := parsers.ParseRepositoryTag(image)
  2043  	// pull only the image tagged 'latest' if no tag was specified
  2044  	if tag == "" {
  2045  		tag = graph.DEFAULTTAG
  2046  	}
  2047  	v.Set("fromImage", repos)
  2048  	v.Set("tag", tag)
  2049  
  2050  	// Resolve the Repository name from fqn to RepositoryInfo
  2051  	repoInfo, err := registry.ParseRepositoryInfo(repos)
  2052  	if err != nil {
  2053  		return err
  2054  	}
  2055  
  2056  	// Load the auth config file, to be able to pull the image
  2057  	cli.LoadConfigFile()
  2058  
  2059  	// Resolve the Auth config relevant for this server
  2060  	authConfig := cli.configFile.ResolveAuthConfig(repoInfo.Index)
  2061  	buf, err := json.Marshal(authConfig)
  2062  	if err != nil {
  2063  		return err
  2064  	}
  2065  
  2066  	registryAuthHeader := []string{
  2067  		base64.URLEncoding.EncodeToString(buf),
  2068  	}
  2069  	if err = cli.stream("POST", "/images/create?"+v.Encode(), nil, out, map[string][]string{"X-Registry-Auth": registryAuthHeader}); err != nil {
  2070  		return err
  2071  	}
  2072  	return nil
  2073  }
  2074  
  2075  type cidFile struct {
  2076  	path    string
  2077  	file    *os.File
  2078  	written bool
  2079  }
  2080  
  2081  func newCIDFile(path string) (*cidFile, error) {
  2082  	if _, err := os.Stat(path); err == nil {
  2083  		return nil, fmt.Errorf("Container ID file found, make sure the other container isn't running or delete %s", path)
  2084  	}
  2085  
  2086  	f, err := os.Create(path)
  2087  	if err != nil {
  2088  		return nil, fmt.Errorf("Failed to create the container ID file: %s", err)
  2089  	}
  2090  
  2091  	return &cidFile{path: path, file: f}, nil
  2092  }
  2093  
  2094  func (cid *cidFile) Close() error {
  2095  	cid.file.Close()
  2096  
  2097  	if !cid.written {
  2098  		if err := os.Remove(cid.path); err != nil {
  2099  			return fmt.Errorf("failed to remove the CID file '%s': %s \n", cid.path, err)
  2100  		}
  2101  	}
  2102  
  2103  	return nil
  2104  }
  2105  
  2106  func (cid *cidFile) Write(id string) error {
  2107  	if _, err := cid.file.Write([]byte(id)); err != nil {
  2108  		return fmt.Errorf("Failed to write the container ID to the file: %s", err)
  2109  	}
  2110  	cid.written = true
  2111  	return nil
  2112  }
  2113  
  2114  func (cli *DockerCli) createContainer(config *runconfig.Config, hostConfig *runconfig.HostConfig, cidfile, name string) (engine.Env, error) {
  2115  	containerValues := url.Values{}
  2116  	if name != "" {
  2117  		containerValues.Set("name", name)
  2118  	}
  2119  
  2120  	mergedConfig := runconfig.MergeConfigs(config, hostConfig)
  2121  
  2122  	var containerIDFile *cidFile
  2123  	if cidfile != "" {
  2124  		var err error
  2125  		if containerIDFile, err = newCIDFile(cidfile); err != nil {
  2126  			return nil, err
  2127  		}
  2128  		defer containerIDFile.Close()
  2129  	}
  2130  
  2131  	//create the container
  2132  	stream, statusCode, err := cli.call("POST", "/containers/create?"+containerValues.Encode(), mergedConfig, false)
  2133  	//if image not found try to pull it
  2134  	if statusCode == 404 {
  2135  		repo, tag := parsers.ParseRepositoryTag(config.Image)
  2136  		if tag == "" {
  2137  			tag = graph.DEFAULTTAG
  2138  		}
  2139  		fmt.Fprintf(cli.err, "Unable to find image '%s:%s' locally\n", repo, tag)
  2140  
  2141  		// we don't want to write to stdout anything apart from container.ID
  2142  		if err = cli.pullImageCustomOut(config.Image, cli.err); err != nil {
  2143  			return nil, err
  2144  		}
  2145  		// Retry
  2146  		if stream, _, err = cli.call("POST", "/containers/create?"+containerValues.Encode(), mergedConfig, false); err != nil {
  2147  			return nil, err
  2148  		}
  2149  	} else if err != nil {
  2150  		return nil, err
  2151  	}
  2152  
  2153  	var result engine.Env
  2154  	if err := result.Decode(stream); err != nil {
  2155  		return nil, err
  2156  	}
  2157  
  2158  	for _, warning := range result.GetList("Warnings") {
  2159  		fmt.Fprintf(cli.err, "WARNING: %s\n", warning)
  2160  	}
  2161  
  2162  	if containerIDFile != nil {
  2163  		if err = containerIDFile.Write(result.Get("Id")); err != nil {
  2164  			return nil, err
  2165  		}
  2166  	}
  2167  
  2168  	return result, nil
  2169  
  2170  }
  2171  
  2172  func (cli *DockerCli) CmdCreate(args ...string) error {
  2173  	cmd := cli.Subcmd("create", "IMAGE [COMMAND] [ARG...]", "Create a new container", true)
  2174  
  2175  	// These are flags not stored in Config/HostConfig
  2176  	var (
  2177  		flName = cmd.String([]string{"-name"}, "", "Assign a name to the container")
  2178  	)
  2179  
  2180  	config, hostConfig, cmd, err := runconfig.Parse(cmd, args)
  2181  	if err != nil {
  2182  		utils.ReportError(cmd, err.Error(), true)
  2183  	}
  2184  	if config.Image == "" {
  2185  		cmd.Usage()
  2186  		return nil
  2187  	}
  2188  
  2189  	createResult, err := cli.createContainer(config, hostConfig, hostConfig.ContainerIDFile, *flName)
  2190  	if err != nil {
  2191  		return err
  2192  	}
  2193  
  2194  	fmt.Fprintf(cli.out, "%s\n", createResult.Get("Id"))
  2195  
  2196  	return nil
  2197  }
  2198  
  2199  func (cli *DockerCli) CmdRun(args ...string) error {
  2200  	// FIXME: just use runconfig.Parse already
  2201  	cmd := cli.Subcmd("run", "IMAGE [COMMAND] [ARG...]", "Run a command in a new container", true)
  2202  
  2203  	// These are flags not stored in Config/HostConfig
  2204  	var (
  2205  		flAutoRemove = cmd.Bool([]string{"#rm", "-rm"}, false, "Automatically remove the container when it exits (incompatible with -d)")
  2206  		flDetach     = cmd.Bool([]string{"d", "-detach"}, false, "Detached mode: run the container in the background and print the new container ID")
  2207  		flSigProxy   = cmd.Bool([]string{"#sig-proxy", "-sig-proxy"}, true, "Proxy received signals to the process (non-TTY mode only). SIGCHLD, SIGSTOP, and SIGKILL are not proxied.")
  2208  		flName       = cmd.String([]string{"#name", "-name"}, "", "Assign a name to the container")
  2209  		flAttach     *opts.ListOpts
  2210  
  2211  		ErrConflictAttachDetach               = fmt.Errorf("Conflicting options: -a and -d")
  2212  		ErrConflictRestartPolicyAndAutoRemove = fmt.Errorf("Conflicting options: --restart and --rm")
  2213  		ErrConflictDetachAutoRemove           = fmt.Errorf("Conflicting options: --rm and -d")
  2214  	)
  2215  
  2216  	config, hostConfig, cmd, err := runconfig.Parse(cmd, args)
  2217  	// just in case the Parse does not exit
  2218  	if err != nil {
  2219  		utils.ReportError(cmd, err.Error(), true)
  2220  	}
  2221  	if config.Image == "" {
  2222  		cmd.Usage()
  2223  		return nil
  2224  	}
  2225  
  2226  	if !*flDetach {
  2227  		if err := cli.CheckTtyInput(config.AttachStdin, config.Tty); err != nil {
  2228  			return err
  2229  		}
  2230  	} else {
  2231  		if fl := cmd.Lookup("attach"); fl != nil {
  2232  			flAttach = fl.Value.(*opts.ListOpts)
  2233  			if flAttach.Len() != 0 {
  2234  				return ErrConflictAttachDetach
  2235  			}
  2236  		}
  2237  		if *flAutoRemove {
  2238  			return ErrConflictDetachAutoRemove
  2239  		}
  2240  
  2241  		config.AttachStdin = false
  2242  		config.AttachStdout = false
  2243  		config.AttachStderr = false
  2244  		config.StdinOnce = false
  2245  	}
  2246  
  2247  	// Disable flSigProxy when in TTY mode
  2248  	sigProxy := *flSigProxy
  2249  	if config.Tty {
  2250  		sigProxy = false
  2251  	}
  2252  
  2253  	runResult, err := cli.createContainer(config, hostConfig, hostConfig.ContainerIDFile, *flName)
  2254  	if err != nil {
  2255  		return err
  2256  	}
  2257  
  2258  	if sigProxy {
  2259  		sigc := cli.forwardAllSignals(runResult.Get("Id"))
  2260  		defer signal.StopCatch(sigc)
  2261  	}
  2262  
  2263  	var (
  2264  		waitDisplayId chan struct{}
  2265  		errCh         chan error
  2266  	)
  2267  
  2268  	if !config.AttachStdout && !config.AttachStderr {
  2269  		// Make this asynchronous to allow the client to write to stdin before having to read the ID
  2270  		waitDisplayId = make(chan struct{})
  2271  		go func() {
  2272  			defer close(waitDisplayId)
  2273  			fmt.Fprintf(cli.out, "%s\n", runResult.Get("Id"))
  2274  		}()
  2275  	}
  2276  
  2277  	if *flAutoRemove && (hostConfig.RestartPolicy.Name == "always" || hostConfig.RestartPolicy.Name == "on-failure") {
  2278  		return ErrConflictRestartPolicyAndAutoRemove
  2279  	}
  2280  
  2281  	// We need to instantiate the chan because the select needs it. It can
  2282  	// be closed but can't be uninitialized.
  2283  	hijacked := make(chan io.Closer)
  2284  
  2285  	// Block the return until the chan gets closed
  2286  	defer func() {
  2287  		log.Debugf("End of CmdRun(), Waiting for hijack to finish.")
  2288  		if _, ok := <-hijacked; ok {
  2289  			log.Errorf("Hijack did not finish (chan still open)")
  2290  		}
  2291  	}()
  2292  
  2293  	if config.AttachStdin || config.AttachStdout || config.AttachStderr {
  2294  		var (
  2295  			out, stderr io.Writer
  2296  			in          io.ReadCloser
  2297  			v           = url.Values{}
  2298  		)
  2299  		v.Set("stream", "1")
  2300  
  2301  		if config.AttachStdin {
  2302  			v.Set("stdin", "1")
  2303  			in = cli.in
  2304  		}
  2305  		if config.AttachStdout {
  2306  			v.Set("stdout", "1")
  2307  			out = cli.out
  2308  		}
  2309  		if config.AttachStderr {
  2310  			v.Set("stderr", "1")
  2311  			if config.Tty {
  2312  				stderr = cli.out
  2313  			} else {
  2314  				stderr = cli.err
  2315  			}
  2316  		}
  2317  
  2318  		errCh = promise.Go(func() error {
  2319  			return cli.hijack("POST", "/containers/"+runResult.Get("Id")+"/attach?"+v.Encode(), config.Tty, in, out, stderr, hijacked, nil)
  2320  		})
  2321  	} else {
  2322  		close(hijacked)
  2323  	}
  2324  
  2325  	// Acknowledge the hijack before starting
  2326  	select {
  2327  	case closer := <-hijacked:
  2328  		// Make sure that the hijack gets closed when returning (results
  2329  		// in closing the hijack chan and freeing server's goroutines)
  2330  		if closer != nil {
  2331  			defer closer.Close()
  2332  		}
  2333  	case err := <-errCh:
  2334  		if err != nil {
  2335  			log.Debugf("Error hijack: %s", err)
  2336  			return err
  2337  		}
  2338  	}
  2339  
  2340  	//start the container
  2341  	if _, _, err = readBody(cli.call("POST", "/containers/"+runResult.Get("Id")+"/start", nil, false)); err != nil {
  2342  		return err
  2343  	}
  2344  
  2345  	if (config.AttachStdin || config.AttachStdout || config.AttachStderr) && config.Tty && cli.isTerminalOut {
  2346  		if err := cli.monitorTtySize(runResult.Get("Id"), false); err != nil {
  2347  			log.Errorf("Error monitoring TTY size: %s", err)
  2348  		}
  2349  	}
  2350  
  2351  	if errCh != nil {
  2352  		if err := <-errCh; err != nil {
  2353  			log.Debugf("Error hijack: %s", err)
  2354  			return err
  2355  		}
  2356  	}
  2357  
  2358  	// Detached mode: wait for the id to be displayed and return.
  2359  	if !config.AttachStdout && !config.AttachStderr {
  2360  		// Detached mode
  2361  		<-waitDisplayId
  2362  		return nil
  2363  	}
  2364  
  2365  	var status int
  2366  
  2367  	// Attached mode
  2368  	if *flAutoRemove {
  2369  		// Autoremove: wait for the container to finish, retrieve
  2370  		// the exit code and remove the container
  2371  		if _, _, err := readBody(cli.call("POST", "/containers/"+runResult.Get("Id")+"/wait", nil, false)); err != nil {
  2372  			return err
  2373  		}
  2374  		if _, status, err = getExitCode(cli, runResult.Get("Id")); err != nil {
  2375  			return err
  2376  		}
  2377  		if _, _, err := readBody(cli.call("DELETE", "/containers/"+runResult.Get("Id")+"?v=1", nil, false)); err != nil {
  2378  			return err
  2379  		}
  2380  	} else {
  2381  		// No Autoremove: Simply retrieve the exit code
  2382  		if !config.Tty {
  2383  			// In non-TTY mode, we can't detach, so we must wait for container exit
  2384  			if status, err = waitForExit(cli, runResult.Get("Id")); err != nil {
  2385  				return err
  2386  			}
  2387  		} else {
  2388  			// In TTY mode, there is a race: if the process dies too slowly, the state could
  2389  			// be updated after the getExitCode call and result in the wrong exit code being reported
  2390  			if _, status, err = getExitCode(cli, runResult.Get("Id")); err != nil {
  2391  				return err
  2392  			}
  2393  		}
  2394  	}
  2395  	if status != 0 {
  2396  		return &utils.StatusError{StatusCode: status}
  2397  	}
  2398  	return nil
  2399  }
  2400  
  2401  func (cli *DockerCli) CmdCp(args ...string) error {
  2402  	cmd := cli.Subcmd("cp", "CONTAINER:PATH HOSTPATH", "Copy files/folders from the PATH to the HOSTPATH", true)
  2403  	cmd.Require(flag.Exact, 2)
  2404  
  2405  	utils.ParseFlags(cmd, args, true)
  2406  
  2407  	var copyData engine.Env
  2408  	info := strings.Split(cmd.Arg(0), ":")
  2409  
  2410  	if len(info) != 2 {
  2411  		return fmt.Errorf("Error: Path not specified")
  2412  	}
  2413  
  2414  	copyData.Set("Resource", info[1])
  2415  	copyData.Set("HostPath", cmd.Arg(1))
  2416  
  2417  	stream, statusCode, err := cli.call("POST", "/containers/"+info[0]+"/copy", copyData, false)
  2418  	if stream != nil {
  2419  		defer stream.Close()
  2420  	}
  2421  	if statusCode == 404 {
  2422  		return fmt.Errorf("No such container: %v", info[0])
  2423  	}
  2424  	if err != nil {
  2425  		return err
  2426  	}
  2427  
  2428  	if statusCode == 200 {
  2429  		if err := archive.Untar(stream, copyData.Get("HostPath"), &archive.TarOptions{NoLchown: true}); err != nil {
  2430  			return err
  2431  		}
  2432  	}
  2433  	return nil
  2434  }
  2435  
  2436  func (cli *DockerCli) CmdSave(args ...string) error {
  2437  	cmd := cli.Subcmd("save", "IMAGE [IMAGE...]", "Save an image(s) to a tar archive (streamed to STDOUT by default)", true)
  2438  	outfile := cmd.String([]string{"o", "-output"}, "", "Write to an file, instead of STDOUT")
  2439  	cmd.Require(flag.Min, 1)
  2440  
  2441  	utils.ParseFlags(cmd, args, true)
  2442  
  2443  	var (
  2444  		output io.Writer = cli.out
  2445  		err    error
  2446  	)
  2447  	if *outfile != "" {
  2448  		output, err = os.Create(*outfile)
  2449  		if err != nil {
  2450  			return err
  2451  		}
  2452  	} else if cli.isTerminalOut {
  2453  		return errors.New("Cowardly refusing to save to a terminal. Use the -o flag or redirect.")
  2454  	}
  2455  
  2456  	if len(cmd.Args()) == 1 {
  2457  		image := cmd.Arg(0)
  2458  		if err := cli.stream("GET", "/images/"+image+"/get", nil, output, nil); err != nil {
  2459  			return err
  2460  		}
  2461  	} else {
  2462  		v := url.Values{}
  2463  		for _, arg := range cmd.Args() {
  2464  			v.Add("names", arg)
  2465  		}
  2466  		if err := cli.stream("GET", "/images/get?"+v.Encode(), nil, output, nil); err != nil {
  2467  			return err
  2468  		}
  2469  	}
  2470  	return nil
  2471  }
  2472  
  2473  func (cli *DockerCli) CmdLoad(args ...string) error {
  2474  	cmd := cli.Subcmd("load", "", "Load an image from a tar archive on STDIN", true)
  2475  	infile := cmd.String([]string{"i", "-input"}, "", "Read from a tar archive file, instead of STDIN")
  2476  	cmd.Require(flag.Exact, 0)
  2477  
  2478  	utils.ParseFlags(cmd, args, true)
  2479  
  2480  	var (
  2481  		input io.Reader = cli.in
  2482  		err   error
  2483  	)
  2484  	if *infile != "" {
  2485  		input, err = os.Open(*infile)
  2486  		if err != nil {
  2487  			return err
  2488  		}
  2489  	}
  2490  	if err := cli.stream("POST", "/images/load", input, cli.out, nil); err != nil {
  2491  		return err
  2492  	}
  2493  	return nil
  2494  }
  2495  
  2496  func (cli *DockerCli) CmdExec(args ...string) error {
  2497  	cmd := cli.Subcmd("exec", "CONTAINER COMMAND [ARG...]", "Run a command in a running container", true)
  2498  
  2499  	execConfig, err := runconfig.ParseExec(cmd, args)
  2500  	// just in case the ParseExec does not exit
  2501  	if execConfig.Container == "" || err != nil {
  2502  		return &utils.StatusError{StatusCode: 1}
  2503  	}
  2504  
  2505  	stream, _, err := cli.call("POST", "/containers/"+execConfig.Container+"/exec", execConfig, false)
  2506  	if err != nil {
  2507  		return err
  2508  	}
  2509  
  2510  	var execResult engine.Env
  2511  	if err := execResult.Decode(stream); err != nil {
  2512  		return err
  2513  	}
  2514  
  2515  	execID := execResult.Get("Id")
  2516  
  2517  	if execID == "" {
  2518  		fmt.Fprintf(cli.out, "exec ID empty")
  2519  		return nil
  2520  	}
  2521  
  2522  	if !execConfig.Detach {
  2523  		if err := cli.CheckTtyInput(execConfig.AttachStdin, execConfig.Tty); err != nil {
  2524  			return err
  2525  		}
  2526  	} else {
  2527  		if _, _, err := readBody(cli.call("POST", "/exec/"+execID+"/start", execConfig, false)); err != nil {
  2528  			return err
  2529  		}
  2530  		// For now don't print this - wait for when we support exec wait()
  2531  		// fmt.Fprintf(cli.out, "%s\n", execID)
  2532  		return nil
  2533  	}
  2534  
  2535  	// Interactive exec requested.
  2536  	var (
  2537  		out, stderr io.Writer
  2538  		in          io.ReadCloser
  2539  		hijacked    = make(chan io.Closer)
  2540  		errCh       chan error
  2541  	)
  2542  
  2543  	// Block the return until the chan gets closed
  2544  	defer func() {
  2545  		log.Debugf("End of CmdExec(), Waiting for hijack to finish.")
  2546  		if _, ok := <-hijacked; ok {
  2547  			log.Errorf("Hijack did not finish (chan still open)")
  2548  		}
  2549  	}()
  2550  
  2551  	if execConfig.AttachStdin {
  2552  		in = cli.in
  2553  	}
  2554  	if execConfig.AttachStdout {
  2555  		out = cli.out
  2556  	}
  2557  	if execConfig.AttachStderr {
  2558  		if execConfig.Tty {
  2559  			stderr = cli.out
  2560  		} else {
  2561  			stderr = cli.err
  2562  		}
  2563  	}
  2564  	errCh = promise.Go(func() error {
  2565  		return cli.hijack("POST", "/exec/"+execID+"/start", execConfig.Tty, in, out, stderr, hijacked, execConfig)
  2566  	})
  2567  
  2568  	// Acknowledge the hijack before starting
  2569  	select {
  2570  	case closer := <-hijacked:
  2571  		// Make sure that hijack gets closed when returning. (result
  2572  		// in closing hijack chan and freeing server's goroutines.
  2573  		if closer != nil {
  2574  			defer closer.Close()
  2575  		}
  2576  	case err := <-errCh:
  2577  		if err != nil {
  2578  			log.Debugf("Error hijack: %s", err)
  2579  			return err
  2580  		}
  2581  	}
  2582  
  2583  	if execConfig.Tty && cli.isTerminalIn {
  2584  		if err := cli.monitorTtySize(execID, true); err != nil {
  2585  			log.Errorf("Error monitoring TTY size: %s", err)
  2586  		}
  2587  	}
  2588  
  2589  	if err := <-errCh; err != nil {
  2590  		log.Debugf("Error hijack: %s", err)
  2591  		return err
  2592  	}
  2593  
  2594  	var status int
  2595  	if _, status, err = getExecExitCode(cli, execID); err != nil {
  2596  		return err
  2597  	}
  2598  
  2599  	if status != 0 {
  2600  		return &utils.StatusError{StatusCode: status}
  2601  	}
  2602  
  2603  	return nil
  2604  }
  2605  
  2606  type containerStats struct {
  2607  	Name             string
  2608  	CpuPercentage    float64
  2609  	Memory           float64
  2610  	MemoryLimit      float64
  2611  	MemoryPercentage float64
  2612  	NetworkRx        float64
  2613  	NetworkTx        float64
  2614  	mu               sync.RWMutex
  2615  	err              error
  2616  }
  2617  
  2618  func (s *containerStats) Collect(cli *DockerCli) {
  2619  	stream, _, err := cli.call("GET", "/containers/"+s.Name+"/stats", nil, false)
  2620  	if err != nil {
  2621  		s.err = err
  2622  		return
  2623  	}
  2624  	defer stream.Close()
  2625  	var (
  2626  		previousCpu    uint64
  2627  		previousSystem uint64
  2628  		start          = true
  2629  		dec            = json.NewDecoder(stream)
  2630  		u              = make(chan error, 1)
  2631  	)
  2632  	go func() {
  2633  		for {
  2634  			var v *stats.Stats
  2635  			if err := dec.Decode(&v); err != nil {
  2636  				u <- err
  2637  				return
  2638  			}
  2639  			var (
  2640  				memPercent = float64(v.MemoryStats.Usage) / float64(v.MemoryStats.Limit) * 100.0
  2641  				cpuPercent = 0.0
  2642  			)
  2643  			if !start {
  2644  				cpuPercent = calcuateCpuPercent(previousCpu, previousSystem, v)
  2645  			}
  2646  			start = false
  2647  			s.mu.Lock()
  2648  			s.CpuPercentage = cpuPercent
  2649  			s.Memory = float64(v.MemoryStats.Usage)
  2650  			s.MemoryLimit = float64(v.MemoryStats.Limit)
  2651  			s.MemoryPercentage = memPercent
  2652  			s.NetworkRx = float64(v.Network.RxBytes)
  2653  			s.NetworkTx = float64(v.Network.TxBytes)
  2654  			s.mu.Unlock()
  2655  			previousCpu = v.CpuStats.CpuUsage.TotalUsage
  2656  			previousSystem = v.CpuStats.SystemUsage
  2657  			u <- nil
  2658  		}
  2659  	}()
  2660  	for {
  2661  		select {
  2662  		case <-time.After(2 * time.Second):
  2663  			// zero out the values if we have not received an update within
  2664  			// the specified duration.
  2665  			s.mu.Lock()
  2666  			s.CpuPercentage = 0
  2667  			s.Memory = 0
  2668  			s.MemoryPercentage = 0
  2669  			s.mu.Unlock()
  2670  		case err := <-u:
  2671  			if err != nil {
  2672  				s.mu.Lock()
  2673  				s.err = err
  2674  				s.mu.Unlock()
  2675  				return
  2676  			}
  2677  		}
  2678  	}
  2679  }
  2680  
  2681  func (s *containerStats) Display(w io.Writer) error {
  2682  	s.mu.RLock()
  2683  	defer s.mu.RUnlock()
  2684  	if s.err != nil {
  2685  		return s.err
  2686  	}
  2687  	fmt.Fprintf(w, "%s\t%.2f%%\t%s/%s\t%.2f%%\t%s/%s\n",
  2688  		s.Name,
  2689  		s.CpuPercentage,
  2690  		units.BytesSize(s.Memory), units.BytesSize(s.MemoryLimit),
  2691  		s.MemoryPercentage,
  2692  		units.BytesSize(s.NetworkRx), units.BytesSize(s.NetworkTx))
  2693  	return nil
  2694  }
  2695  
  2696  func (cli *DockerCli) CmdStats(args ...string) error {
  2697  	cmd := cli.Subcmd("stats", "CONTAINER", "Display a live stream of one or more containers' resource usage statistics", true)
  2698  	cmd.Require(flag.Min, 1)
  2699  	utils.ParseFlags(cmd, args, true)
  2700  
  2701  	names := cmd.Args()
  2702  	sort.Strings(names)
  2703  	var (
  2704  		cStats []*containerStats
  2705  		w      = tabwriter.NewWriter(cli.out, 20, 1, 3, ' ', 0)
  2706  	)
  2707  	printHeader := func() {
  2708  		fmt.Fprint(cli.out, "\033[2J")
  2709  		fmt.Fprint(cli.out, "\033[H")
  2710  		fmt.Fprintln(w, "CONTAINER\tCPU %\tMEM USAGE/LIMIT\tMEM %\tNET I/O")
  2711  	}
  2712  	for _, n := range names {
  2713  		s := &containerStats{Name: n}
  2714  		cStats = append(cStats, s)
  2715  		go s.Collect(cli)
  2716  	}
  2717  	// do a quick pause so that any failed connections for containers that do not exist are able to be
  2718  	// evicted before we display the initial or default values.
  2719  	time.Sleep(500 * time.Millisecond)
  2720  	var errs []string
  2721  	for _, c := range cStats {
  2722  		c.mu.Lock()
  2723  		if c.err != nil {
  2724  			errs = append(errs, fmt.Sprintf("%s: %s", c.Name, c.err.Error()))
  2725  		}
  2726  		c.mu.Unlock()
  2727  	}
  2728  	if len(errs) > 0 {
  2729  		return fmt.Errorf("%s", strings.Join(errs, ", "))
  2730  	}
  2731  	for _ = range time.Tick(500 * time.Millisecond) {
  2732  		printHeader()
  2733  		toRemove := []int{}
  2734  		for i, s := range cStats {
  2735  			if err := s.Display(w); err != nil {
  2736  				toRemove = append(toRemove, i)
  2737  			}
  2738  		}
  2739  		for j := len(toRemove) - 1; j >= 0; j-- {
  2740  			i := toRemove[j]
  2741  			cStats = append(cStats[:i], cStats[i+1:]...)
  2742  		}
  2743  		if len(cStats) == 0 {
  2744  			return nil
  2745  		}
  2746  		w.Flush()
  2747  	}
  2748  	return nil
  2749  }
  2750  
  2751  func calcuateCpuPercent(previousCpu, previousSystem uint64, v *stats.Stats) float64 {
  2752  	var (
  2753  		cpuPercent = 0.0
  2754  		// calculate the change for the cpu usage of the container in between readings
  2755  		cpuDelta = float64(v.CpuStats.CpuUsage.TotalUsage - previousCpu)
  2756  		// calculate the change for the entire system between readings
  2757  		systemDelta = float64(v.CpuStats.SystemUsage - previousSystem)
  2758  	)
  2759  
  2760  	if systemDelta > 0.0 && cpuDelta > 0.0 {
  2761  		cpuPercent = (cpuDelta / systemDelta) * float64(len(v.CpuStats.CpuUsage.PercpuUsage)) * 100.0
  2762  	}
  2763  	return cpuPercent
  2764  }