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