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