Browse code

- Runtime: ghost containers can be killed.

Solomon Hykes authored on 2013/04/23 14:30:33
Showing 3 changed files
... ...
@@ -836,6 +836,10 @@ func (srv *Server) CmdAttach(stdin io.ReadCloser, stdout rcli.DockerConn, args .
836 836
 		return fmt.Errorf("No such container: %s", name)
837 837
 	}
838 838
 
839
+	if container.State.Ghost {
840
+		return fmt.Errorf("Impossible to attach to a ghost container")
841
+	}
842
+
839 843
 	if container.Config.Tty {
840 844
 		stdout.SetOptionRawTerminal()
841 845
 	}
... ...
@@ -530,16 +530,42 @@ func (container *Container) releaseNetwork() {
530 530
 	container.NetworkSettings = &NetworkSettings{}
531 531
 }
532 532
 
533
+// FIXME: replace this with a control socket within docker-init
534
+func (container *Container) waitLxc() error {
535
+	for {
536
+		if output, err := exec.Command("lxc-info", "-n", container.Id).CombinedOutput(); err != nil {
537
+			return err
538
+		} else {
539
+			if !strings.Contains(string(output), "RUNNING") {
540
+				return nil
541
+			}
542
+		}
543
+		time.Sleep(500 * time.Millisecond)
544
+	}
545
+	return nil
546
+}
547
+
533 548
 func (container *Container) monitor() {
534 549
 	// Wait for the program to exit
535 550
 	Debugf("Waiting for process")
536
-	if err := container.cmd.Wait(); err != nil {
537
-		// Discard the error as any signals or non 0 returns will generate an error
538
-		Debugf("%s: Process: %s", container.Id, err)
551
+
552
+	// If the command does not exists, try to wait via lxc
553
+	if container.cmd == nil {
554
+		if err := container.waitLxc(); err != nil {
555
+			Debugf("%s: Process: %s", container.Id, err)
556
+		}
557
+	} else {
558
+		if err := container.cmd.Wait(); err != nil {
559
+			// Discard the error as any signals or non 0 returns will generate an error
560
+			Debugf("%s: Process: %s", container.Id, err)
561
+		}
539 562
 	}
540 563
 	Debugf("Process finished")
541 564
 
542
-	exitCode := container.cmd.ProcessState.Sys().(syscall.WaitStatus).ExitStatus()
565
+	var exitCode int = -1
566
+	if container.cmd != nil {
567
+		exitCode = container.cmd.ProcessState.Sys().(syscall.WaitStatus).ExitStatus()
568
+	}
543 569
 
544 570
 	// Cleanup
545 571
 	container.releaseNetwork()
... ...
@@ -588,7 +614,7 @@ func (container *Container) monitor() {
588 588
 }
589 589
 
590 590
 func (container *Container) kill() error {
591
-	if !container.State.Running || container.cmd == nil {
591
+	if !container.State.Running {
592 592
 		return nil
593 593
 	}
594 594
 
... ...
@@ -600,6 +626,9 @@ func (container *Container) kill() error {
600 600
 
601 601
 	// 2. Wait for the process to die, in last resort, try to kill the process directly
602 602
 	if err := container.WaitTimeout(10 * time.Second); err != nil {
603
+		if container.cmd == nil {
604
+			return fmt.Errorf("lxc-kill failed, impossible to kill the container %s", container.Id)
605
+		}
603 606
 		log.Printf("Container %s failed to exit within 10 seconds of lxc SIGKILL - trying direct SIGKILL", container.Id)
604 607
 		if err := container.cmd.Process.Kill(); err != nil {
605 608
 			return err
... ...
@@ -617,9 +646,6 @@ func (container *Container) Kill() error {
617 617
 	if !container.State.Running {
618 618
 		return nil
619 619
 	}
620
-	if container.State.Ghost {
621
-		return fmt.Errorf("Can't kill ghost container")
622
-	}
623 620
 	return container.kill()
624 621
 }
625 622
 
... ...
@@ -629,9 +655,6 @@ func (container *Container) Stop(seconds int) error {
629 629
 	if !container.State.Running {
630 630
 		return nil
631 631
 	}
632
-	if container.State.Ghost {
633
-		return fmt.Errorf("Can't stop ghost container")
634
-	}
635 632
 
636 633
 	// 1. Send a SIGTERM
637 634
 	if output, err := exec.Command("lxc-kill", "-n", container.Id, "15").CombinedOutput(); err != nil {
... ...
@@ -184,12 +184,6 @@ func (runtime *Runtime) Register(container *Container) error {
184 184
 		}
185 185
 	}
186 186
 
187
-	// If the container is not running or just has been flagged not running
188
-	// then close the wait lock chan (will be reset upon start)
189
-	if !container.State.Running {
190
-		close(container.waitLock)
191
-	}
192
-
193 187
 	// Even if not running, we init the lock (prevents races in start/stop/kill)
194 188
 	container.State.initLock()
195 189
 
... ...
@@ -207,6 +201,15 @@ func (runtime *Runtime) Register(container *Container) error {
207 207
 	// done
208 208
 	runtime.containers.PushBack(container)
209 209
 	runtime.idIndex.Add(container.Id)
210
+
211
+	// If the container is not running or just has been flagged not running
212
+	// then close the wait lock chan (will be reset upon start)
213
+	if !container.State.Running {
214
+		close(container.waitLock)
215
+	} else {
216
+		container.allocateNetwork()
217
+		go container.monitor()
218
+	}
210 219
 	return nil
211 220
 }
212 221