Browse code

Remove the ghosts and kill everything Docker-DCO-1.1-Signed-off-by: Michael Crosby <michael@crosbymichael.com> (github: crosbymichael)

Michael Crosby authored on 2014/03/07 07:14:25
Showing 7 changed files
... ...
@@ -55,6 +55,7 @@ type Container struct {
55 55
 	HostsPath      string
56 56
 	Name           string
57 57
 	Driver         string
58
+	ExecDriver     string
58 59
 
59 60
 	command   *execdriver.Command
60 61
 	stdout    *utils.WriteBroadcaster
... ...
@@ -777,15 +778,8 @@ func (container *Container) monitor(callback execdriver.StartCallback) error {
777 777
 		exitCode int
778 778
 	)
779 779
 
780
-	if container.command == nil {
781
-		// This happends when you have a GHOST container with lxc
782
-		populateCommand(container)
783
-		err = container.runtime.RestoreCommand(container)
784
-	} else {
785
-		pipes := execdriver.NewPipes(container.stdin, container.stdout, container.stderr, container.Config.OpenStdin)
786
-		exitCode, err = container.runtime.Run(container, pipes, callback)
787
-	}
788
-
780
+	pipes := execdriver.NewPipes(container.stdin, container.stdout, container.stderr, container.Config.OpenStdin)
781
+	exitCode, err = container.runtime.Run(container, pipes, callback)
789 782
 	if err != nil {
790 783
 		utils.Errorf("Error running container: %s", err)
791 784
 	}
... ...
@@ -77,7 +77,6 @@ type TtyTerminal interface {
77 77
 type Driver interface {
78 78
 	Run(c *Command, pipes *Pipes, startCallback StartCallback) (int, error) // Run executes the process and blocks until the process exits and returns the exit code
79 79
 	Kill(c *Command, sig int) error
80
-	Restore(c *Command) error                     // Wait and try to re-attach on an out of process command
81 80
 	Name() string                                 // Driver name
82 81
 	Info(id string) Info                          // "temporary" hack (until we move state from core to plugins)
83 82
 	GetPidsForContainer(id string) ([]int, error) // Returns a list of pids for the given container.
... ...
@@ -189,20 +189,7 @@ func getExitCode(c *execdriver.Command) int {
189 189
 }
190 190
 
191 191
 func (d *driver) Kill(c *execdriver.Command, sig int) error {
192
-	return d.kill(c, sig)
193
-}
194
-
195
-func (d *driver) Restore(c *execdriver.Command) error {
196
-	for {
197
-		output, err := exec.Command("lxc-info", "-n", c.ID).CombinedOutput()
198
-		if err != nil {
199
-			return err
200
-		}
201
-		if !strings.Contains(string(output), "RUNNING") {
202
-			return nil
203
-		}
204
-		time.Sleep(500 * time.Millisecond)
205
-	}
192
+	return KillLxc(c.ID, sig)
206 193
 }
207 194
 
208 195
 func (d *driver) version() string {
... ...
@@ -225,16 +212,16 @@ func (d *driver) version() string {
225 225
 	return version
226 226
 }
227 227
 
228
-func (d *driver) kill(c *execdriver.Command, sig int) error {
228
+func KillLxc(id string, sig int) error {
229 229
 	var (
230 230
 		err    error
231 231
 		output []byte
232 232
 	)
233 233
 	_, err = exec.LookPath("lxc-kill")
234 234
 	if err == nil {
235
-		output, err = exec.Command("lxc-kill", "-n", c.ID, strconv.Itoa(sig)).CombinedOutput()
235
+		output, err = exec.Command("lxc-kill", "-n", id, strconv.Itoa(sig)).CombinedOutput()
236 236
 	} else {
237
-		output, err = exec.Command("lxc-stop", "-k", "-n", c.ID, strconv.Itoa(sig)).CombinedOutput()
237
+		output, err = exec.Command("lxc-stop", "-k", "-n", id, strconv.Itoa(sig)).CombinedOutput()
238 238
 	}
239 239
 	if err != nil {
240 240
 		return fmt.Errorf("Err: %s Output: %s", err, output)
... ...
@@ -16,7 +16,6 @@ import (
16 16
 	"strconv"
17 17
 	"strings"
18 18
 	"syscall"
19
-	"time"
20 19
 )
21 20
 
22 21
 const (
... ...
@@ -109,41 +108,9 @@ func (d *driver) Run(c *execdriver.Command, pipes *execdriver.Pipes, startCallba
109 109
 }
110 110
 
111 111
 func (d *driver) Kill(p *execdriver.Command, sig int) error {
112
-	return syscall.Kill(p.Process.Pid, syscall.Signal(sig))
113
-}
114
-
115
-func (d *driver) Restore(c *execdriver.Command) error {
116
-	var nspid int
117
-	f, err := os.Open(filepath.Join(d.root, c.ID, "pid"))
118
-	if err != nil {
119
-		return err
120
-	}
121
-	defer d.removeContainerRoot(c.ID)
122
-
123
-	if _, err := fmt.Fscanf(f, "%d", &nspid); err != nil {
124
-		f.Close()
125
-		return err
126
-	}
127
-	f.Close()
128
-
129
-	if _, err := os.FindProcess(nspid); err != nil {
130
-		return fmt.Errorf("finding existing pid %d %s", nspid, err)
131
-	}
132
-	c.Process = &os.Process{
133
-		Pid: nspid,
134
-	}
135
-	ticker := time.NewTicker(500 * time.Millisecond)
136
-	defer ticker.Stop()
137
-
138
-	for _ = range ticker.C {
139
-		if err := syscall.Kill(nspid, 0); err != nil {
140
-			if strings.Contains(err.Error(), "no such process") {
141
-				return nil
142
-			}
143
-			return fmt.Errorf("signal error %s", err)
144
-		}
145
-	}
146
-	return nil
112
+	err := syscall.Kill(p.Process.Pid, syscall.Signal(sig))
113
+	d.removeContainerRoot(p.ID)
114
+	return err
147 115
 }
148 116
 
149 117
 func (d *driver) Info(id string) execdriver.Info {
... ...
@@ -589,90 +589,6 @@ func TestRestore(t *testing.T) {
589 589
 	container2.State.SetStopped(0)
590 590
 }
591 591
 
592
-func TestReloadContainerLinks(t *testing.T) {
593
-	root, err := newTestDirectory(unitTestStoreBase)
594
-	if err != nil {
595
-		t.Fatal(err)
596
-	}
597
-	// FIXME: here we don't use NewTestEngine because it calls initserver with Autorestart=false,
598
-	// and we want to set it to true.
599
-
600
-	eng := newTestEngine(t, true, root)
601
-
602
-	runtime1 := mkRuntimeFromEngine(eng, t)
603
-	defer nuke(runtime1)
604
-	// Create a container with one instance of docker
605
-	container1, _, _ := mkContainer(runtime1, []string{"-i", "_", "/bin/sh"}, t)
606
-	defer runtime1.Destroy(container1)
607
-
608
-	// Create a second container meant to be killed
609
-	container2, _, _ := mkContainer(runtime1, []string{"-i", "_", "/bin/cat"}, t)
610
-	defer runtime1.Destroy(container2)
611
-
612
-	// Start the container non blocking
613
-	if err := container2.Start(); err != nil {
614
-		t.Fatal(err)
615
-	}
616
-	// Add a link to container 2
617
-	// FIXME @shykes: setting hostConfig.Links seems redundant with calling RegisterLink().
618
-	// Why do we need it @crosbymichael?
619
-	// container1.hostConfig.Links = []string{"/" + container2.ID + ":first"}
620
-	if err := runtime1.RegisterLink(container1, container2, "first"); err != nil {
621
-		t.Fatal(err)
622
-	}
623
-	if err := container1.Start(); err != nil {
624
-		t.Fatal(err)
625
-	}
626
-
627
-	if !container2.State.IsRunning() {
628
-		t.Fatalf("Container %v should appear as running but isn't", container2.ID)
629
-	}
630
-
631
-	if !container1.State.IsRunning() {
632
-		t.Fatalf("Container %s should appear as running but isn't", container1.ID)
633
-	}
634
-
635
-	if len(runtime1.List()) != 2 {
636
-		t.Errorf("Expected 2 container, %v found", len(runtime1.List()))
637
-	}
638
-
639
-	// Here are are simulating a docker restart - that is, reloading all containers
640
-	// from scratch
641
-	eng = newTestEngine(t, false, root)
642
-	runtime2 := mkRuntimeFromEngine(eng, t)
643
-	if len(runtime2.List()) != 2 {
644
-		t.Errorf("Expected 2 container, %v found", len(runtime2.List()))
645
-	}
646
-	runningCount := 0
647
-	for _, c := range runtime2.List() {
648
-		if c.State.IsRunning() {
649
-			runningCount++
650
-		}
651
-	}
652
-	if runningCount != 2 {
653
-		t.Fatalf("Expected 2 container alive, %d found", runningCount)
654
-	}
655
-
656
-	// FIXME: we no longer test if containers were registered in the right order,
657
-	// because there is no public
658
-	// Make sure container 2 ( the child of container 1 ) was registered and started first
659
-	// with the runtime
660
-	//
661
-	containers := runtime2.List()
662
-	if len(containers) == 0 {
663
-		t.Fatalf("Runtime has no containers")
664
-	}
665
-	first := containers[0]
666
-	if first.ID != container2.ID {
667
-		t.Fatalf("Container 2 %s should be registered first in the runtime", container2.ID)
668
-	}
669
-
670
-	// Verify that the link is still registered in the runtime
671
-	if c := runtime2.Get(container1.Name); c == nil {
672
-		t.Fatal("Named container is no longer registered after restart")
673
-	}
674
-}
675
-
676 592
 func TestDefaultContainerName(t *testing.T) {
677 593
 	eng := NewTestEngine(t)
678 594
 	runtime := mkRuntimeFromEngine(eng, t)
... ...
@@ -48,17 +48,14 @@ func (ns *linuxNs) Init(container *libcontainer.Container, uncleanRootfs, consol
48 48
 			return fmt.Errorf("setctty %s", err)
49 49
 		}
50 50
 	}
51
-
52
-	/* this is commented out so that we get the current Ghost functionality
53
-	if err := system.ParentDeathSignal(); err != nil {
54
-		return fmt.Errorf("parent death signal %s", err)
55
-	}
51
+	/*
52
+		if err := system.ParentDeathSignal(); err != nil {
53
+			return fmt.Errorf("parent death signal %s", err)
54
+		}
56 55
 	*/
57
-
58 56
 	if err := setupNewMountNamespace(rootfs, console, container.ReadonlyFs); err != nil {
59 57
 		return fmt.Errorf("setup mount namespace %s", err)
60 58
 	}
61
-
62 59
 	if err := setupNetwork(container, context); err != nil {
63 60
 		return fmt.Errorf("setup networking %s", err)
64 61
 	}
... ...
@@ -154,12 +154,39 @@ func (runtime *Runtime) Register(container *Container) error {
154 154
 	//        if so, then we need to restart monitor and init a new lock
155 155
 	// If the container is supposed to be running, make sure of it
156 156
 	if container.State.IsRunning() {
157
-		info := runtime.execDriver.Info(container.ID)
157
+		if container.State.IsGhost() {
158
+			utils.Debugf("killing ghost %s", container.ID)
159
+
160
+			existingPid := container.State.Pid
161
+			container.State.SetGhost(false)
162
+			container.State.SetStopped(0)
158 163
 
164
+			if container.ExecDriver == "" || strings.Contains(container.ExecDriver, "lxc") {
165
+				lxc.KillLxc(container.ID, 9)
166
+			} else {
167
+				command := &execdriver.Command{
168
+					ID: container.ID,
169
+				}
170
+				command.Process = &os.Process{Pid: existingPid}
171
+				runtime.execDriver.Kill(command, 9)
172
+			}
173
+			// ensure that the filesystem is also unmounted
174
+			unmountVolumesForContainer(container)
175
+			if err := container.Unmount(); err != nil {
176
+				utils.Debugf("ghost unmount error %s", err)
177
+			}
178
+		}
179
+
180
+		info := runtime.execDriver.Info(container.ID)
159 181
 		if !info.IsRunning() {
160 182
 			utils.Debugf("Container %s was supposed to be running but is not.", container.ID)
161 183
 			if runtime.config.AutoRestart {
162 184
 				utils.Debugf("Restarting")
185
+				unmountVolumesForContainer(container)
186
+				if err := container.Unmount(); err != nil {
187
+					utils.Debugf("restart unmount error %s", err)
188
+				}
189
+
163 190
 				container.State.SetGhost(false)
164 191
 				container.State.SetStopped(0)
165 192
 				if err := container.Start(); err != nil {
... ...
@@ -172,15 +199,6 @@ func (runtime *Runtime) Register(container *Container) error {
172 172
 					return err
173 173
 				}
174 174
 			}
175
-		} else {
176
-			utils.Debugf("Reconnecting to container %v", container.ID)
177
-
178
-			if err := container.allocateNetwork(); err != nil {
179
-				return err
180
-			}
181
-
182
-			container.waitLock = make(chan struct{})
183
-			go container.monitor(nil)
184 175
 		}
185 176
 	} else {
186 177
 		// When the container is not running, we still initialize the waitLock
... ...
@@ -447,6 +465,7 @@ func (runtime *Runtime) Create(config *runconfig.Config, name string) (*Containe
447 447
 		NetworkSettings: &NetworkSettings{},
448 448
 		Name:            name,
449 449
 		Driver:          runtime.driver.String(),
450
+		ExecDriver:      runtime.execDriver.Name(),
450 451
 	}
451 452
 	container.root = runtime.containerRoot(container.ID)
452 453
 	// Step 1: create the container directory.
... ...
@@ -834,10 +853,6 @@ func (runtime *Runtime) Kill(c *Container, sig int) error {
834 834
 	return runtime.execDriver.Kill(c.command, sig)
835 835
 }
836 836
 
837
-func (runtime *Runtime) RestoreCommand(c *Container) error {
838
-	return runtime.execDriver.Restore(c.command)
839
-}
840
-
841 837
 // Nuke kills all containers then removes all content
842 838
 // from the content root, including images, volumes and
843 839
 // container filesystems.