Beispiel #1
0
// CmdTop displays the running processes of a container.
//
// Usage: docker top CONTAINER
func (cli *DockerCli) CmdTop(args ...string) error {
	cmd := cli.Subcmd("top", "CONTAINER [ps OPTIONS]", "Display the running processes of a container", true)
	cmd.Require(flag.Min, 1)

	utils.ParseFlags(cmd, args, true)

	val := url.Values{}
	if cmd.NArg() > 1 {
		val.Set("ps_args", strings.Join(cmd.Args()[1:], " "))
	}

	stream, _, err := cli.call("GET", "/containers/"+cmd.Arg(0)+"/top?"+val.Encode(), nil, nil)
	if err != nil {
		return err
	}
	var procs engine.Env
	if err := procs.Decode(stream); err != nil {
		return err
	}
	w := tabwriter.NewWriter(cli.out, 20, 1, 3, ' ', 0)
	fmt.Fprintln(w, strings.Join(procs.GetList("Titles"), "\t"))
	processes := [][]string{}
	if err := procs.GetJson("Processes", &processes); err != nil {
		return err
	}
	for _, proc := range processes {
		fmt.Fprintln(w, strings.Join(proc, "\t"))
	}
	w.Flush()
	return nil
}
Beispiel #2
0
func TestPostCommit(t *testing.T) {
	eng := NewTestEngine(t)
	defer mkDaemonFromEngine(eng, t).Nuke()

	// Create a container and remove a file
	containerID := createTestContainer(eng,
		&runconfig.Config{
			Image: unitTestImageID,
			Cmd:   []string{"touch", "/test"},
		},
		t,
	)

	containerRun(eng, containerID, t)

	req, err := http.NewRequest("POST", "/commit?repo=testrepo&testtag=tag&container="+containerID, bytes.NewReader([]byte{}))
	if err != nil {
		t.Fatal(err)
	}

	r := httptest.NewRecorder()
	server.ServeRequest(eng, api.APIVERSION, r, req)
	assertHttpNotError(r, t)
	if r.Code != http.StatusCreated {
		t.Fatalf("%d Created expected, received %d\n", http.StatusCreated, r.Code)
	}

	var env engine.Env
	if err := env.Decode(r.Body); err != nil {
		t.Fatal(err)
	}
	if err := eng.Job("image_inspect", env.Get("Id")).Run(); err != nil {
		t.Fatalf("The image has not been committed")
	}
}
Beispiel #3
0
// CmdCommit creates a new image from a container's changes.
//
// Usage: docker commit [OPTIONS] CONTAINER [REPOSITORY[:TAG]]
func (cli *DockerCli) CmdCommit(args ...string) error {
	cmd := cli.Subcmd("commit", "CONTAINER [REPOSITORY[:TAG]]", "Create a new image from a container's changes", true)
	flPause := cmd.Bool([]string{"p", "-pause"}, true, "Pause container during commit")
	flComment := cmd.String([]string{"m", "-message"}, "", "Commit message")
	flAuthor := cmd.String([]string{"a", "#author", "-author"}, "", "Author (e.g., \"John Hannibal Smith <*****@*****.**>\")")
	flChanges := opts.NewListOpts(nil)
	cmd.Var(&flChanges, []string{"c", "-change"}, "Apply Dockerfile instruction to the created image")
	// FIXME: --run is deprecated, it will be replaced with inline Dockerfile commands.
	flConfig := cmd.String([]string{"#run", "#-run"}, "", "This option is deprecated and will be removed in a future version in favor of inline Dockerfile-compatible commands")
	cmd.Require(flag.Max, 2)
	cmd.Require(flag.Min, 1)
	utils.ParseFlags(cmd, args, true)

	var (
		name            = cmd.Arg(0)
		repository, tag = parsers.ParseRepositoryTag(cmd.Arg(1))
	)

	//Check if the given image name can be resolved
	if repository != "" {
		if err := registry.ValidateRepositoryName(repository); err != nil {
			return err
		}
	}

	v := url.Values{}
	v.Set("container", name)
	v.Set("repo", repository)
	v.Set("tag", tag)
	v.Set("comment", *flComment)
	v.Set("author", *flAuthor)
	for _, change := range flChanges.GetAll() {
		v.Add("changes", change)
	}

	if *flPause != true {
		v.Set("pause", "0")
	}

	var (
		config *runconfig.Config
		env    engine.Env
	)
	if *flConfig != "" {
		config = &runconfig.Config{}
		if err := json.Unmarshal([]byte(*flConfig), config); err != nil {
			return err
		}
	}
	stream, _, err := cli.call("POST", "/commit?"+v.Encode(), config, nil)
	if err != nil {
		return err
	}
	if err := env.Decode(stream); err != nil {
		return err
	}

	fmt.Fprintf(cli.out, "%s\n", env.Get("Id"))
	return nil
}
Beispiel #4
0
func postContainersSet(eng *engine.Engine, version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
	if vars == nil {
		return fmt.Errorf("Missing parameter")
	}

	var (
		setData engine.Env
		config  []struct {
			Key   string
			Value string
		}
	)
	if contentType := r.Header.Get("Content-Type"); api.MatchesContentType(contentType, "application/json") {
		if err := setData.Decode(r.Body); err != nil {
			return err
		}
	} else {
		return fmt.Errorf("Content-Type not supported: %s", contentType)
	}

	if err := setData.GetJson("config", &config); err != nil {
		return err
	}
	job := eng.Job("container_set", vars["name"])
	job.SetenvJson("config", config)

	job.Stdout.Add(w)
	if err := job.Run(); err != nil {
		return err
	}

	return nil
}
Beispiel #5
0
func TestPostContainersWait(t *testing.T) {
	eng := NewTestEngine(t)
	defer mkDaemonFromEngine(eng, t).Nuke()

	containerID := createTestContainer(eng,
		&runconfig.Config{
			Image:     unitTestImageID,
			Cmd:       []string{"/bin/sleep", "1"},
			OpenStdin: true,
		},
		t,
	)
	startContainer(eng, containerID, t)

	setTimeout(t, "Wait timed out", 3*time.Second, func() {
		r := httptest.NewRecorder()
		req, err := http.NewRequest("POST", "/containers/"+containerID+"/wait", bytes.NewReader([]byte{}))
		if err != nil {
			t.Fatal(err)
		}
		server.ServeRequest(eng, api.APIVERSION, r, req)
		assertHttpNotError(r, t)
		var apiWait engine.Env
		if err := apiWait.Decode(r.Body); err != nil {
			t.Fatal(err)
		}
		if apiWait.GetInt("StatusCode") != 0 {
			t.Fatalf("Non zero exit code for sleep: %d\n", apiWait.GetInt("StatusCode"))
		}
	})

	if containerRunning(eng, containerID, t) {
		t.Fatalf("The container should be stopped after wait")
	}
}
Beispiel #6
0
func postCommit(eng *engine.Engine, version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
	if err := parseForm(r); err != nil {
		return err
	}
	var (
		config       engine.Env
		env          engine.Env
		job          = eng.Job("commit", r.Form.Get("container"))
		stdoutBuffer = bytes.NewBuffer(nil)
	)
	if err := config.Decode(r.Body); err != nil {
		utils.Errorf("%s", err)
	}

	if r.FormValue("pause") == "" && version.GreaterThanOrEqualTo("1.13") {
		job.Setenv("pause", "1")
	} else {
		job.Setenv("pause", r.FormValue("pause"))
	}

	job.Setenv("repo", r.Form.Get("repo"))
	job.Setenv("tag", r.Form.Get("tag"))
	job.Setenv("author", r.Form.Get("author"))
	job.Setenv("comment", r.Form.Get("comment"))
	job.SetenvSubEnv("config", &config)

	job.Stdout.Add(stdoutBuffer)
	if err := job.Run(); err != nil {
		return err
	}
	env.Set("Id", engine.Tail(stdoutBuffer, 1))
	return writeJSON(w, http.StatusCreated, env)
}
Beispiel #7
0
// Issue 7941 - test to make sure a "null" in JSON is just ignored.
// W/o this fix a null in JSON would be parsed into a string var as "null"
func TestPostCreateNull(t *testing.T) {
	eng := NewTestEngine(t)
	daemon := mkDaemonFromEngine(eng, t)
	defer daemon.Nuke()

	configStr := fmt.Sprintf(`{
		"Hostname":"",
		"Domainname":"",
		"Memory":0,
		"MemorySwap":0,
		"CpuShares":0,
		"Cpuset":null,
		"AttachStdin":true,
		"AttachStdout":true,
		"AttachStderr":true,
		"PortSpecs":null,
		"ExposedPorts":{},
		"Tty":true,
		"OpenStdin":true,
		"StdinOnce":true,
		"Env":[],
		"Cmd":"ls",
		"Image":"%s",
		"Volumes":{},
		"WorkingDir":"",
		"Entrypoint":null,
		"NetworkDisabled":false,
		"OnBuild":null}`, unitTestImageID)

	req, err := http.NewRequest("POST", "/containers/create", strings.NewReader(configStr))
	if err != nil {
		t.Fatal(err)
	}

	req.Header.Set("Content-Type", "application/json")

	r := httptest.NewRecorder()
	if err := server.ServeRequest(eng, api.APIVERSION, r, req); err != nil {
		t.Fatal(err)
	}
	assertHttpNotError(r, t)
	if r.Code != http.StatusCreated {
		t.Fatalf("%d Created expected, received %d\n", http.StatusCreated, r.Code)
	}

	var apiRun engine.Env
	if err := apiRun.Decode(r.Body); err != nil {
		t.Fatal(err)
	}
	containerID := apiRun.Get("Id")

	containerAssertExists(eng, containerID, t)

	c := daemon.Get(containerID)
	if c.Config.Cpuset != "" {
		t.Fatalf("Cpuset should have been empty - instead its:" + c.Config.Cpuset)
	}
}
Beispiel #8
0
// TODO: Krane clean up because i needed to add Ship to String
func (cli *KraneCli) createContainer(config *runconfig.Config, hostConfig *runconfig.HostConfig, cidfile, name string, ship string) (engine.Env, error) {
	containerValues := url.Values{}
	if name != "" {
		containerValues.Set("name", name)
	}

	if ship != "" {
		containerValues.Set("ship", ship)
	}

	mergedConfig := runconfig.MergeConfigs(config, hostConfig)

	var containerIDFile *cidFile
	if cidfile != "" {
		var err error
		if containerIDFile, err = newCIDFile(cidfile); err != nil {
			return nil, err
		}
		defer containerIDFile.Close()
	}

	//create the container
	stream, statusCode, err := cli.call("POST", "/containers/create?"+containerValues.Encode(), mergedConfig, false)
	//if image not found try to pull it
	if statusCode == 404 {
		fmt.Fprintf(cli.err, "Unable to find image '%s' locally\n", config.Image)

		// we don't want to write to stdout anything apart from container.ID
		if err = cli.pullImageCustomOut(config.Image, cli.err); err != nil {
			return nil, err
		}
		// Retry
		if stream, _, err = cli.call("POST", "/containers/create?"+containerValues.Encode(), mergedConfig, false); err != nil {
			return nil, err
		}
	} else if err != nil {
		return nil, err
	}

	var result engine.Env
	if err := result.Decode(stream); err != nil {
		return nil, err
	}

	for _, warning := range result.GetList("Warnings") {
		fmt.Fprintf(cli.err, "WARNING: %s\n", warning)
	}

	if containerIDFile != nil {
		if err = containerIDFile.Write(result.Get("Id")); err != nil {
			return nil, err
		}
	}

	return result, nil

}
Beispiel #9
0
func waitForExit(cli *DockerCli, containerId string) (int, error) {
	stream, _, err := cli.call("POST", "/containers/"+containerId+"/wait", nil, false)
	if err != nil {
		return -1, err
	}

	var out engine.Env
	if err := out.Decode(stream); err != nil {
		return -1, err
	}
	return out.GetInt("StatusCode"), nil
}
Beispiel #10
0
// CmdPort lists port mappings for a container.
// If a private port is specified, it also shows the public-facing port that is NATed to the private port.
//
// Usage: docker port CONTAINER [PRIVATE_PORT[/PROTO]]
func (cli *DockerCli) CmdPort(args ...string) error {
	cmd := cli.Subcmd("port", "CONTAINER [PRIVATE_PORT[/PROTO]]", "List port mappings for the CONTAINER, or lookup the public-facing port that\nis NAT-ed to the PRIVATE_PORT", true)
	cmd.Require(flag.Min, 1)
	utils.ParseFlags(cmd, args, true)

	stream, _, err := cli.call("GET", "/containers/"+cmd.Arg(0)+"/json", nil, nil)
	if err != nil {
		return err
	}

	env := engine.Env{}
	if err := env.Decode(stream); err != nil {
		return err
	}
	ports := nat.PortMap{}
	if err := env.GetSubEnv("NetworkSettings").GetJson("Ports", &ports); err != nil {
		return err
	}

	if cmd.NArg() == 2 {
		var (
			port  = cmd.Arg(1)
			proto = "tcp"
			parts = strings.SplitN(port, "/", 2)
		)

		if len(parts) == 2 && len(parts[1]) != 0 {
			port = parts[0]
			proto = parts[1]
		}
		natPort := port + "/" + proto
		if frontends, exists := ports[nat.Port(port+"/"+proto)]; exists && frontends != nil {
			for _, frontend := range frontends {
				fmt.Fprintf(cli.out, "%s:%s\n", frontend.HostIp, frontend.HostPort)
			}
			return nil
		}
		return fmt.Errorf("Error: No public port '%s' published for %s", natPort, cmd.Arg(0))
	}

	for from, frontends := range ports {
		for _, frontend := range frontends {
			fmt.Fprintf(cli.out, "%s -> %s:%s\n", from, frontend.HostIp, frontend.HostPort)
		}
	}

	return nil
}
Beispiel #11
0
// getExecExitCode perform an inspect on the exec command. It returns
// the running state and the exit code.
func getExecExitCode(cli *DockerCli, execId string) (bool, int, error) {
	stream, _, err := cli.call("GET", "/exec/"+execId+"/json", nil, false)
	if err != nil {
		// If we can't connect, then the daemon probably died.
		if err != ErrConnectionRefused {
			return false, -1, err
		}
		return false, -1, nil
	}

	var result engine.Env
	if err := result.Decode(stream); err != nil {
		return false, -1, err
	}

	return result.GetBool("Running"), result.GetInt("ExitCode"), nil
}
Beispiel #12
0
// getExitCode perform an inspect on the container. It returns
// the running state and the exit code.
func getExitCode(cli *DockerCli, containerId string) (bool, int, error) {
	steam, _, err := cli.call("GET", "/containers/"+containerId+"/json", nil, false)
	if err != nil {
		// If we can't connect, then the daemon probably died.
		if err != ErrConnectionRefused {
			return false, -1, err
		}
		return false, -1, nil
	}

	var result engine.Env
	if err := result.Decode(steam); err != nil {
		return false, -1, err
	}

	state := result.GetSubEnv("State")
	return state.GetBool("Running"), state.GetInt("ExitCode"), nil
}
Beispiel #13
0
func ContainerCreate(job *engine.Job) engine.Status {
	configuration := job.Eng.Hack_GetGlobalVar("configuration").(types.KraneConfiguration)
	config := runconfig.ContainerConfigFromJob(job)

	if len(job.Args) != 2 {
		return job.Errorf("Usage: %s CONTAINER\n", job.Name)
	}

	ship := configuration.Production.Fleet.Find(job.Args[1])

	containerValues := url.Values{}
	containerValues.Set("name", job.Args[0])

	cli := client.NewKraneClientApi(ship, false, job)

	stream, statusCode, err := cli.Call("POST", "/containers/create?"+containerValues.Encode(), config, false)

	if statusCode == 404 {
		job.Printf("Unable to find image '%s' in %s://%s:%d\n", config.Image, ship.Schema, ship.Fqdn, ship.Port)

		if err = pullImage(job, config.Image, ship); err != nil {
			return job.Errorf("Cannot pull image %s: %s\n", config.Image, err)
		}
		if stream, _, err = cli.Call("POST", "/containers/create?"+containerValues.Encode(), config, false); err != nil {
			return job.Errorf("Cannot create container: %s\n", err)
		}
	} else if err != nil {
		return job.Errorf("Cannot create container: %s\n", err)
	}

	var runResult engine.Env

	if err := runResult.Decode(stream); err != nil {
		return job.Errorf("Error with container: %s\n", err)
	}

	for _, warning := range runResult.GetList("Warnings") {
		job.Stdout.Write([]byte(fmt.Sprintf("WARNING: %s\n", warning)))
	}

	job.Stdout.Write([]byte(runResult.Get("Id")))

	return engine.StatusOK
}
Beispiel #14
0
func postContainersCgroup(eng *engine.Engine, version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
	if vars == nil {
		return fmt.Errorf("Missing parameter")
	}

	saveToFile, err := getBoolParam(r.FormValue("w"))
	if err != nil {
		return err
	}

	var (
		cgroupData     engine.Env
		readSubsystem  []string
		writeSubsystem []struct {
			Key   string
			Value string
		}
	)

	if contentType := r.Header.Get("Content-Type"); api.MatchesContentType(contentType, "application/json") {
		if err := cgroupData.Decode(r.Body); err != nil {
			return err
		}
	} else {
		return fmt.Errorf("Content-Type not supported: %s", contentType)
	}

	readSubsystem = cgroupData.GetList("ReadSubsystem")
	if err := cgroupData.GetJson("WriteSubsystem", &writeSubsystem); err != nil {
		return err
	}

	job := eng.Job("cgroup", vars["name"])
	job.SetenvList("readSubsystem", readSubsystem)
	job.SetenvJson("writeSubsystem", writeSubsystem)
	job.SetenvBool("saveToFile", saveToFile)

	job.Stdout.Add(w)
	if err := job.Run(); err != nil {
		return err
	}

	return nil
}
Beispiel #15
0
func TestPostContainersCreate(t *testing.T) {
	eng := NewTestEngine(t)
	defer mkDaemonFromEngine(eng, t).Nuke()

	configJSON, err := json.Marshal(&runconfig.Config{
		Image:  unitTestImageID,
		Memory: 33554432,
		Cmd:    []string{"touch", "/test"},
	})
	if err != nil {
		t.Fatal(err)
	}

	req, err := http.NewRequest("POST", "/containers/create", bytes.NewReader(configJSON))
	if err != nil {
		t.Fatal(err)
	}

	req.Header.Set("Content-Type", "application/json")

	r := httptest.NewRecorder()
	if err := server.ServeRequest(eng, api.APIVERSION, r, req); err != nil {
		t.Fatal(err)
	}
	assertHttpNotError(r, t)
	if r.Code != http.StatusCreated {
		t.Fatalf("%d Created expected, received %d\n", http.StatusCreated, r.Code)
	}

	var apiRun engine.Env
	if err := apiRun.Decode(r.Body); err != nil {
		t.Fatal(err)
	}
	containerID := apiRun.Get("Id")

	containerAssertExists(eng, containerID, t)
	containerRun(eng, containerID, t)

	if !containerFileExists(eng, containerID, "test", t) {
		t.Fatal("Test file was not created")
	}
}
Beispiel #16
0
// CmdLogs fetches the logs of a given container.
//
// docker logs [OPTIONS] CONTAINER
func (cli *DockerCli) CmdLogs(args ...string) error {
	var (
		cmd    = cli.Subcmd("logs", "CONTAINER", "Fetch the logs of a container", true)
		follow = cmd.Bool([]string{"f", "-follow"}, false, "Follow log output")
		times  = cmd.Bool([]string{"t", "-timestamps"}, false, "Show timestamps")
		tail   = cmd.String([]string{"-tail"}, "all", "Number of lines to show from the end of the logs")
	)
	cmd.Require(flag.Exact, 1)

	utils.ParseFlags(cmd, args, true)

	name := cmd.Arg(0)

	stream, _, err := cli.call("GET", "/containers/"+name+"/json", nil, nil)
	if err != nil {
		return err
	}

	env := engine.Env{}
	if err := env.Decode(stream); err != nil {
		return err
	}

	if env.GetSubEnv("HostConfig").GetSubEnv("LogConfig").Get("Type") != "json-file" {
		return fmt.Errorf("\"logs\" command is supported only for \"json-file\" logging driver")
	}

	v := url.Values{}
	v.Set("stdout", "1")
	v.Set("stderr", "1")

	if *times {
		v.Set("timestamps", "1")
	}

	if *follow {
		v.Set("follow", "1")
	}
	v.Set("tail", *tail)

	return cli.streamHelper("GET", "/containers/"+name+"/logs?"+v.Encode(), env.GetSubEnv("Config").GetBool("Tty"), nil, cli.out, cli.err, nil)
}
Beispiel #17
0
func (daemon *Daemon) ContainerCommit(name string, c *ContainerCommitConfig) (string, error) {
	container, err := daemon.Get(name)
	if err != nil {
		return "", err
	}

	var (
		subenv       engine.Env
		config       = container.Config
		stdoutBuffer = bytes.NewBuffer(nil)
		newConfig    runconfig.Config
	)

	if err := subenv.Decode(c.Config); err != nil {
		logrus.Errorf("%s", err)
	}

	buildConfigJob := daemon.eng.Job("build_config")
	buildConfigJob.Stdout.Add(stdoutBuffer)
	buildConfigJob.SetenvList("changes", c.Changes)
	// FIXME this should be remove when we remove deprecated config param
	buildConfigJob.SetenvSubEnv("config", &subenv)

	if err := buildConfigJob.Run(); err != nil {
		return "", err
	}
	if err := json.NewDecoder(stdoutBuffer).Decode(&newConfig); err != nil {
		return "", err
	}

	if err := runconfig.Merge(&newConfig, config); err != nil {
		return "", err
	}

	img, err := daemon.Commit(container, c.Repo, c.Tag, c.Comment, c.Author, c.Pause, &newConfig)
	if err != nil {
		return "", err
	}

	return img.ID, nil
}
Beispiel #18
0
func postContainersCopy(eng *engine.Engine, version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
	if vars == nil {
		return fmt.Errorf("Missing parameter")
	}

	var copyData engine.Env

	if err := checkForJson(r); err != nil {
		return err
	}

	if err := copyData.Decode(r.Body); err != nil {
		return err
	}

	if copyData.Get("Resource") == "" {
		return fmt.Errorf("Path cannot be empty")
	}

	origResource := copyData.Get("Resource")

	if copyData.Get("Resource")[0] == '/' {
		copyData.Set("Resource", copyData.Get("Resource")[1:])
	}

	job := eng.Job("container_copy", vars["name"], copyData.Get("Resource"))
	job.Stdout.Add(w)
	w.Header().Set("Content-Type", "application/x-tar")
	if err := job.Run(); err != nil {
		log.Errorf("%s", err.Error())
		if strings.Contains(strings.ToLower(err.Error()), "no such id") {
			w.WriteHeader(http.StatusNotFound)
		} else if strings.Contains(err.Error(), "no such file or directory") {
			return fmt.Errorf("Could not find the file %s in container %s", origResource, vars["name"])
		}
	}
	return nil
}
Beispiel #19
0
func TestGetContainersTop(t *testing.T) {
	eng := NewTestEngine(t)
	defer mkDaemonFromEngine(eng, t).Nuke()

	containerID := createTestContainer(eng,
		&runconfig.Config{
			Image:     unitTestImageID,
			Cmd:       []string{"/bin/sh", "-c", "cat"},
			OpenStdin: true,
		},
		t,
	)
	defer func() {
		// Make sure the process dies before destroying daemon
		containerKill(eng, containerID, t)
		containerWait(eng, containerID, t)
	}()

	startContainer(eng, containerID, t)

	setTimeout(t, "Waiting for the container to be started timed out", 10*time.Second, func() {
		for {
			if containerRunning(eng, containerID, t) {
				break
			}
			time.Sleep(10 * time.Millisecond)
		}
	})

	if !containerRunning(eng, containerID, t) {
		t.Fatalf("Container should be running")
	}

	// Make sure sh spawn up cat
	setTimeout(t, "read/write assertion timed out", 2*time.Second, func() {
		in, out := containerAttach(eng, containerID, t)
		if err := assertPipe("hello\n", "hello", out, in, 150); err != nil {
			t.Fatal(err)
		}
	})

	r := httptest.NewRecorder()
	req, err := http.NewRequest("GET", "/containers/"+containerID+"/top?ps_args=aux", nil)
	if err != nil {
		t.Fatal(err)
	}
	if err := server.ServeRequest(eng, api.APIVERSION, r, req); err != nil {
		t.Fatal(err)
	}
	assertHttpNotError(r, t)
	var procs engine.Env
	if err := procs.Decode(r.Body); err != nil {
		t.Fatal(err)
	}

	if len(procs.GetList("Titles")) != 11 {
		t.Fatalf("Expected 11 titles, found %d.", len(procs.GetList("Titles")))
	}
	if procs.GetList("Titles")[0] != "USER" || procs.GetList("Titles")[10] != "COMMAND" {
		t.Fatalf("Expected Titles[0] to be USER and Titles[10] to be COMMAND, found %s and %s.", procs.GetList("Titles")[0], procs.GetList("Titles")[10])
	}
	processes := [][]string{}
	if err := procs.GetJson("Processes", &processes); err != nil {
		t.Fatal(err)
	}
	if len(processes) != 2 {
		t.Fatalf("Expected 2 processes, found %d.", len(processes))
	}
	if processes[0][10] != "/bin/sh -c cat" {
		t.Fatalf("Expected `/bin/sh -c cat`, found %s.", processes[0][10])
	}
	if processes[1][10] != "/bin/sh -c cat" {
		t.Fatalf("Expected `/bin/sh -c cat`, found %s.", processes[1][10])
	}
}
Beispiel #20
0
// CmdAttach attaches to a running container.
//
// Usage: docker attach [OPTIONS] CONTAINER
func (cli *DockerCli) CmdAttach(args ...string) error {
	var (
		cmd     = cli.Subcmd("attach", "CONTAINER", "Attach to a running container", true)
		noStdin = cmd.Bool([]string{"#nostdin", "-no-stdin"}, false, "Do not attach STDIN")
		proxy   = cmd.Bool([]string{"#sig-proxy", "-sig-proxy"}, true, "Proxy all received signals to the process")
	)
	cmd.Require(flag.Exact, 1)

	utils.ParseFlags(cmd, args, true)
	name := cmd.Arg(0)

	stream, _, err := cli.call("GET", "/containers/"+name+"/json", nil, nil)
	if err != nil {
		return err
	}

	env := engine.Env{}
	if err := env.Decode(stream); err != nil {
		return err
	}

	if !env.GetSubEnv("State").GetBool("Running") {
		return fmt.Errorf("You cannot attach to a stopped container, start it first")
	}

	var (
		config = env.GetSubEnv("Config")
		tty    = config.GetBool("Tty")
	)

	if err := cli.CheckTtyInput(!*noStdin, tty); err != nil {
		return err
	}

	if tty && cli.isTerminalOut {
		if err := cli.monitorTtySize(cmd.Arg(0), false); err != nil {
			logrus.Debugf("Error monitoring TTY size: %s", err)
		}
	}

	var in io.ReadCloser

	v := url.Values{}
	v.Set("stream", "1")
	if !*noStdin && config.GetBool("OpenStdin") {
		v.Set("stdin", "1")
		in = cli.in
	}

	v.Set("stdout", "1")
	v.Set("stderr", "1")

	if *proxy && !tty {
		sigc := cli.forwardAllSignals(cmd.Arg(0))
		defer signal.StopCatch(sigc)
	}

	if err := cli.hijack("POST", "/containers/"+cmd.Arg(0)+"/attach?"+v.Encode(), tty, in, cli.out, cli.err, nil, nil); err != nil {
		return err
	}

	_, status, err := getExitCode(cli, cmd.Arg(0))
	if err != nil {
		return err
	}
	if status != 0 {
		return &utils.StatusError{StatusCode: status}
	}

	return nil
}
Beispiel #21
0
// CmdStart starts one or more stopped containers.
//
// Usage: docker start [OPTIONS] CONTAINER [CONTAINER...]
func (cli *DockerCli) CmdStart(args ...string) error {
	var (
		cErr chan error
		tty  bool

		cmd       = cli.Subcmd("start", "CONTAINER [CONTAINER...]", "Start one or more stopped containers", true)
		attach    = cmd.Bool([]string{"a", "-attach"}, false, "Attach STDOUT/STDERR and forward signals")
		openStdin = cmd.Bool([]string{"i", "-interactive"}, false, "Attach container's STDIN")
	)

	cmd.Require(flag.Min, 1)
	cmd.ParseFlags(args, true)

	if *attach || *openStdin {
		if cmd.NArg() > 1 {
			return fmt.Errorf("You cannot start and attach multiple containers at once.")
		}

		stream, _, err := cli.call("GET", "/containers/"+cmd.Arg(0)+"/json", nil, nil)
		if err != nil {
			return err
		}

		env := engine.Env{}
		if err := env.Decode(stream); err != nil {
			return err
		}
		config := env.GetSubEnv("Config")
		tty = config.GetBool("Tty")

		if !tty {
			sigc := cli.forwardAllSignals(cmd.Arg(0))
			defer signal.StopCatch(sigc)
		}

		var in io.ReadCloser

		v := url.Values{}
		v.Set("stream", "1")

		if *openStdin && config.GetBool("OpenStdin") {
			v.Set("stdin", "1")
			in = cli.in
		}

		v.Set("stdout", "1")
		v.Set("stderr", "1")

		hijacked := make(chan io.Closer)
		// Block the return until the chan gets closed
		defer func() {
			logrus.Debugf("CmdStart() returned, defer waiting for hijack to finish.")
			if _, ok := <-hijacked; ok {
				logrus.Errorf("Hijack did not finish (chan still open)")
			}
			cli.in.Close()
		}()
		cErr = promise.Go(func() error {
			return cli.hijack("POST", "/containers/"+cmd.Arg(0)+"/attach?"+v.Encode(), tty, in, cli.out, cli.err, hijacked, nil)
		})

		// Acknowledge the hijack before starting
		select {
		case closer := <-hijacked:
			// Make sure that the hijack gets closed when returning (results
			// in closing the hijack chan and freeing server's goroutines)
			if closer != nil {
				defer closer.Close()
			}
		case err := <-cErr:
			if err != nil {
				return err
			}
		}
	}

	var encounteredError error
	for _, name := range cmd.Args() {
		_, _, err := readBody(cli.call("POST", "/containers/"+name+"/start", nil, nil))
		if err != nil {
			if !*attach && !*openStdin {
				// attach and openStdin is false means it could be starting multiple containers
				// when a container start failed, show the error message and start next
				fmt.Fprintf(cli.err, "%s\n", err)
				encounteredError = fmt.Errorf("Error: failed to start one or more containers")
			} else {
				encounteredError = err
			}
		} else {
			if !*attach && !*openStdin {
				fmt.Fprintf(cli.out, "%s\n", name)
			}
		}
	}

	if encounteredError != nil {
		return encounteredError
	}

	if *openStdin || *attach {
		if tty && cli.isTerminalOut {
			if err := cli.monitorTtySize(cmd.Arg(0), false); err != nil {
				logrus.Errorf("Error monitoring TTY size: %s", err)
			}
		}
		if attchErr := <-cErr; attchErr != nil {
			return attchErr
		}
		_, status, err := getExitCode(cli, cmd.Arg(0))
		if err != nil {
			return err
		}
		if status != 0 {
			return StatusError{StatusCode: status}
		}
	}
	return nil
}