Browse code

Merge branch 'master' of github.com:docker/docker into kill

Docker-DCO-1.1-Signed-off-by: Dan Walsh <dwalsh@redhat.com> (github: rhatdan)

Dan Walsh authored on 2015/05/28 05:31:54
Showing 10 changed files
... ...
@@ -244,8 +244,6 @@ func (s *Server) postAuth(version version.Version, w http.ResponseWriter, r *htt
244 244
 }
245 245
 
246 246
 func (s *Server) getVersion(version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
247
-	w.Header().Set("Content-Type", "application/json")
248
-
249 247
 	v := &types.Version{
250 248
 		Version:    dockerversion.VERSION,
251 249
 		ApiVersion: api.APIVERSION,
... ...
@@ -359,8 +357,6 @@ func (s *Server) getImagesJSON(version version.Version, w http.ResponseWriter, r
359 359
 }
360 360
 
361 361
 func (s *Server) getInfo(version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
362
-	w.Header().Set("Content-Type", "application/json")
363
-
364 362
 	info, err := s.daemon.SystemInfo()
365 363
 	if err != nil {
366 364
 		return err
... ...
@@ -863,7 +859,7 @@ func (s *Server) postImagesLoad(version version.Version, w http.ResponseWriter,
863 863
 
864 864
 func (s *Server) postContainersCreate(version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
865 865
 	if err := parseForm(r); err != nil {
866
-		return nil
866
+		return err
867 867
 	}
868 868
 	if err := checkForJson(r); err != nil {
869 869
 		return err
... ...
@@ -1288,7 +1284,7 @@ func (s *Server) postContainersCopy(version version.Version, w http.ResponseWrit
1288 1288
 
1289 1289
 func (s *Server) postContainerExecCreate(version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
1290 1290
 	if err := parseForm(r); err != nil {
1291
-		return nil
1291
+		return err
1292 1292
 	}
1293 1293
 	name := vars["name"]
1294 1294
 
... ...
@@ -1317,7 +1313,7 @@ func (s *Server) postContainerExecCreate(version version.Version, w http.Respons
1317 1317
 // TODO(vishh): Refactor the code to avoid having to specify stream config as part of both create and start.
1318 1318
 func (s *Server) postContainerExecStart(version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
1319 1319
 	if err := parseForm(r); err != nil {
1320
-		return nil
1320
+		return err
1321 1321
 	}
1322 1322
 	var (
1323 1323
 		execName = vars["name"]
... ...
@@ -437,7 +437,23 @@ func (container *Container) Kill() error {
437 437
 
438 438
 	// 1. Send SIGKILL
439 439
 	if err := container.killPossiblyDeadProcess(9); err != nil {
440
-		return err
440
+		// While normally we might "return err" here we're not going to
441
+		// because if we can't stop the container by this point then
442
+		// its probably because its already stopped. Meaning, between
443
+		// the time of the IsRunning() call above and now it stopped.
444
+		// Also, since the err return will be exec driver specific we can't
445
+		// look for any particular (common) error that would indicate
446
+		// that the process is already dead vs something else going wrong.
447
+		// So, instead we'll give it up to 2 more seconds to complete and if
448
+		// by that time the container is still running, then the error
449
+		// we got is probably valid and so we return it to the caller.
450
+
451
+		if container.IsRunning() {
452
+			container.WaitStop(2 * time.Second)
453
+			if container.IsRunning() {
454
+				return err
455
+			}
456
+		}
441 457
 	}
442 458
 
443 459
 	// 2. Wait for the process to die, in last resort, try to kill the process directly
... ...
@@ -959,21 +959,37 @@ func (container *Container) DisableLink(name string) {
959 959
 }
960 960
 
961 961
 func (container *Container) UnmountVolumes(forceSyscall bool) error {
962
-	for _, m := range container.MountPoints {
963
-		dest, err := container.GetResourcePath(m.Destination)
962
+	var volumeMounts []mountPoint
963
+
964
+	for _, mntPoint := range container.MountPoints {
965
+		dest, err := container.GetResourcePath(mntPoint.Destination)
966
+		if err != nil {
967
+			return err
968
+		}
969
+
970
+		volumeMounts = append(volumeMounts, mountPoint{Destination: dest, Volume: mntPoint.Volume})
971
+	}
972
+
973
+	for _, mnt := range container.networkMounts() {
974
+		dest, err := container.GetResourcePath(mnt.Destination)
964 975
 		if err != nil {
965 976
 			return err
966 977
 		}
967 978
 
979
+		volumeMounts = append(volumeMounts, mountPoint{Destination: dest})
980
+	}
981
+
982
+	for _, volumeMount := range volumeMounts {
968 983
 		if forceSyscall {
969
-			syscall.Unmount(dest, 0)
984
+			syscall.Unmount(volumeMount.Destination, 0)
970 985
 		}
971 986
 
972
-		if m.Volume != nil {
973
-			if err := m.Volume.Unmount(); err != nil {
987
+		if volumeMount.Volume != nil {
988
+			if err := volumeMount.Volume.Unmount(); err != nil {
974 989
 				return err
975 990
 			}
976 991
 		}
977 992
 	}
993
+
978 994
 	return nil
979 995
 }
... ...
@@ -58,10 +58,6 @@ func (daemon *Daemon) ContainerRm(name string, config *ContainerRmConfig) error
58 58
 
59 59
 // Destroy unregisters a container from the daemon and cleanly removes its contents from the filesystem.
60 60
 func (daemon *Daemon) rm(container *Container, forceRemove bool) (err error) {
61
-	// stop collection of stats for the container regardless
62
-	// if stats are currently getting collected.
63
-	daemon.statsCollector.stopCollection(container)
64
-
65 61
 	if container.IsRunning() {
66 62
 		if !forceRemove {
67 63
 			return fmt.Errorf("Conflict, You cannot remove a running container. Stop the container before attempting removal or use -f")
... ...
@@ -71,6 +67,10 @@ func (daemon *Daemon) rm(container *Container, forceRemove bool) (err error) {
71 71
 		}
72 72
 	}
73 73
 
74
+	// stop collection of stats for the container regardless
75
+	// if stats are currently getting collected.
76
+	daemon.statsCollector.stopCollection(container)
77
+
74 78
 	element := daemon.containers.Get(container.ID)
75 79
 	if element == nil {
76 80
 		return fmt.Errorf("Container %v not found - maybe it was already destroyed?", container.ID)
... ...
@@ -8,7 +8,6 @@ import (
8 8
 	"path/filepath"
9 9
 	"strings"
10 10
 
11
-	"github.com/docker/docker/daemon/execdriver"
12 11
 	"github.com/docker/docker/pkg/chrootarchive"
13 12
 	"github.com/docker/docker/runconfig"
14 13
 	"github.com/docker/docker/volume"
... ...
@@ -115,20 +114,6 @@ func validMountMode(mode string) bool {
115 115
 	return validModes[mode]
116 116
 }
117 117
 
118
-func (container *Container) specialMounts() []execdriver.Mount {
119
-	var mounts []execdriver.Mount
120
-	if container.ResolvConfPath != "" {
121
-		mounts = append(mounts, execdriver.Mount{Source: container.ResolvConfPath, Destination: "/etc/resolv.conf", Writable: !container.hostConfig.ReadonlyRootfs, Private: true})
122
-	}
123
-	if container.HostnamePath != "" {
124
-		mounts = append(mounts, execdriver.Mount{Source: container.HostnamePath, Destination: "/etc/hostname", Writable: !container.hostConfig.ReadonlyRootfs, Private: true})
125
-	}
126
-	if container.HostsPath != "" {
127
-		mounts = append(mounts, execdriver.Mount{Source: container.HostsPath, Destination: "/etc/hosts", Writable: !container.hostConfig.ReadonlyRootfs, Private: true})
128
-	}
129
-	return mounts
130
-}
131
-
132 118
 func copyExistingContents(source, destination string) error {
133 119
 	volList, err := ioutil.ReadDir(source)
134 120
 	if err != nil {
... ...
@@ -254,6 +254,42 @@ func (s *DockerSuite) TestGetContainerStats(c *check.C) {
254 254
 	}
255 255
 }
256 256
 
257
+func (s *DockerSuite) TestContainerStatsRmRunning(c *check.C) {
258
+	out, _ := dockerCmd(c, "run", "-d", "busybox", "top")
259
+	id := strings.TrimSpace(out)
260
+
261
+	buf := &channelBuffer{make(chan []byte, 1)}
262
+	defer buf.Close()
263
+	chErr := make(chan error)
264
+	go func() {
265
+		_, body, err := sockRequestRaw("GET", "/containers/"+id+"/stats?stream=1", nil, "application/json")
266
+		if err != nil {
267
+			chErr <- err
268
+		}
269
+		defer body.Close()
270
+		_, err = io.Copy(buf, body)
271
+		chErr <- err
272
+	}()
273
+	defer func() {
274
+		c.Assert(<-chErr, check.IsNil)
275
+	}()
276
+
277
+	b := make([]byte, 32)
278
+	// make sure we've got some stats
279
+	_, err := buf.ReadTimeout(b, 2*time.Second)
280
+	c.Assert(err, check.IsNil)
281
+
282
+	// Now remove without `-f` and make sure we are still pulling stats
283
+	_, err = runCommand(exec.Command(dockerBinary, "rm", id))
284
+	c.Assert(err, check.Not(check.IsNil), check.Commentf("rm should have failed but didn't"))
285
+	_, err = buf.ReadTimeout(b, 2*time.Second)
286
+	c.Assert(err, check.IsNil)
287
+	dockerCmd(c, "rm", "-f", id)
288
+
289
+	_, err = buf.ReadTimeout(b, 2*time.Second)
290
+	c.Assert(err, check.Not(check.IsNil))
291
+}
292
+
257 293
 func (s *DockerSuite) TestGetStoppedContainerStats(c *check.C) {
258 294
 	// TODO: this test does nothing because we are c.Assert'ing in goroutine
259 295
 	var (
... ...
@@ -595,3 +595,40 @@ func (s *DockerSuite) TestCpNameHasColon(c *check.C) {
595 595
 		c.Fatalf("Wrong content in copied file %q, should be %q", content, "lololol\n")
596 596
 	}
597 597
 }
598
+
599
+func (s *DockerSuite) TestCopyAndRestart(c *check.C) {
600
+	expectedMsg := "hello"
601
+	out, err := exec.Command(dockerBinary, "run", "-d", "busybox", "echo", expectedMsg).CombinedOutput()
602
+	if err != nil {
603
+		c.Fatal(string(out), err)
604
+	}
605
+	id := strings.TrimSpace(string(out))
606
+
607
+	if out, err = exec.Command(dockerBinary, "wait", id).CombinedOutput(); err != nil {
608
+		c.Fatalf("unable to wait for container: %s", err)
609
+	}
610
+
611
+	status := strings.TrimSpace(string(out))
612
+	if status != "0" {
613
+		c.Fatalf("container exited with status %s", status)
614
+	}
615
+
616
+	tmpDir, err := ioutil.TempDir("", "test-docker-restart-after-copy-")
617
+	if err != nil {
618
+		c.Fatalf("unable to make temporary directory: %s", err)
619
+	}
620
+	defer os.RemoveAll(tmpDir)
621
+
622
+	if _, err = exec.Command(dockerBinary, "cp", fmt.Sprintf("%s:/etc/issue", id), tmpDir).CombinedOutput(); err != nil {
623
+		c.Fatalf("unable to copy from busybox container: %s", err)
624
+	}
625
+
626
+	if out, err = exec.Command(dockerBinary, "start", "-a", id).CombinedOutput(); err != nil {
627
+		c.Fatalf("unable to start busybox container after copy: %s - %s", err, out)
628
+	}
629
+
630
+	msg := strings.TrimSpace(string(out))
631
+	if msg != expectedMsg {
632
+		c.Fatalf("expected %q but got %q", expectedMsg, msg)
633
+	}
634
+}
... ...
@@ -42,11 +42,11 @@ func (s *DockerSuite) TestKillofStoppedContainer(c *check.C) {
42 42
 
43 43
 	stopCmd := exec.Command(dockerBinary, "stop", cleanedContainerID)
44 44
 	out, _, err = runCommandWithOutput(stopCmd)
45
-	c.Assert(err, check.IsNil, check.Commentf("failed to stop container: %s, %v", out, err))
45
+	c.Assert(err, check.IsNil)
46 46
 
47 47
 	killCmd := exec.Command(dockerBinary, "kill", "-s", "30", cleanedContainerID)
48 48
 	_, _, err = runCommandWithOutput(killCmd)
49
-	c.Assert(err, check.Not(check.IsNil), check.Commentf("Kill succeeded on a stopped container"))
49
+	c.Assert(err, check.Not(check.IsNil), check.Commentf("Container %s is not running", cleanedContainerID))
50 50
 }
51 51
 
52 52
 func (s *DockerSuite) TestKillDifferentUserContainer(c *check.C) {
... ...
@@ -3172,7 +3172,7 @@ func (s *DockerSuite) TestTwoContainersInNetHost(c *check.C) {
3172 3172
 }
3173 3173
 
3174 3174
 func (s *DockerSuite) TestRunUnshareProc(c *check.C) {
3175
-	testRequires(c, Apparmor)
3175
+	testRequires(c, Apparmor, NativeExecDriver)
3176 3176
 
3177 3177
 	name := "acidburn"
3178 3178
 	runCmd := exec.Command(dockerBinary, "run", "--name", name, "jess/unshare", "unshare", "-p", "-m", "-f", "-r", "--mount-proc=/proc", "mount")
... ...
@@ -7,7 +7,6 @@ import (
7 7
 	"errors"
8 8
 	"fmt"
9 9
 	"io"
10
-	"net/http"
11 10
 	"net/http/httptest"
12 11
 	"os"
13 12
 	"os/exec"
... ...
@@ -275,26 +274,6 @@ type FileServer struct {
275 275
 	*httptest.Server
276 276
 }
277 277
 
278
-func fileServer(files map[string]string) (*FileServer, error) {
279
-	var handler http.HandlerFunc = func(w http.ResponseWriter, r *http.Request) {
280
-		if filePath, found := files[r.URL.Path]; found {
281
-			http.ServeFile(w, r, filePath)
282
-		} else {
283
-			http.Error(w, http.StatusText(404), 404)
284
-		}
285
-	}
286
-
287
-	for _, file := range files {
288
-		if _, err := os.Stat(file); err != nil {
289
-			return nil, err
290
-		}
291
-	}
292
-	server := httptest.NewServer(handler)
293
-	return &FileServer{
294
-		Server: server,
295
-	}, nil
296
-}
297
-
298 278
 // randomUnixTmpDirPath provides a temporary unix path with rand string appended.
299 279
 // does not create or checks if it exists.
300 280
 func randomUnixTmpDirPath(s string) string {
... ...
@@ -337,3 +316,26 @@ func parseCgroupPaths(procCgroupData string) map[string]string {
337 337
 	}
338 338
 	return cgroupPaths
339 339
 }
340
+
341
+type channelBuffer struct {
342
+	c chan []byte
343
+}
344
+
345
+func (c *channelBuffer) Write(b []byte) (int, error) {
346
+	c.c <- b
347
+	return len(b), nil
348
+}
349
+
350
+func (c *channelBuffer) Close() error {
351
+	close(c.c)
352
+	return nil
353
+}
354
+
355
+func (c *channelBuffer) ReadTimeout(p []byte, n time.Duration) (int, error) {
356
+	select {
357
+	case b := <-c.c:
358
+		return copy(p[0:], b), nil
359
+	case <-time.After(n):
360
+		return -1, fmt.Errorf("timeout reading from channel")
361
+	}
362
+}