Browse code

Merge pull request #3724 from creack/extract-lxc-phase-2

Refactor process to command

Victor Vieux authored on 2014/01/24 08:28:45
Showing 7 changed files
... ...
@@ -54,7 +54,7 @@ type Container struct {
54 54
 	Name           string
55 55
 	Driver         string
56 56
 
57
-	process   *execdriver.Process
57
+	command   *execdriver.Command
58 58
 	stdout    *utils.WriteBroadcaster
59 59
 	stderr    *utils.WriteBroadcaster
60 60
 	stdin     io.ReadCloser
... ...
@@ -307,8 +307,8 @@ func (container *Container) setupPty() error {
307 307
 		return err
308 308
 	}
309 309
 	container.ptyMaster = ptyMaster
310
-	container.process.Stdout = ptySlave
311
-	container.process.Stderr = ptySlave
310
+	container.command.Stdout = ptySlave
311
+	container.command.Stderr = ptySlave
312 312
 
313 313
 	// Copy the PTYs to our broadcasters
314 314
 	go func() {
... ...
@@ -320,8 +320,8 @@ func (container *Container) setupPty() error {
320 320
 
321 321
 	// stdin
322 322
 	if container.Config.OpenStdin {
323
-		container.process.Stdin = ptySlave
324
-		container.process.SysProcAttr.Setctty = true
323
+		container.command.Stdin = ptySlave
324
+		container.command.SysProcAttr.Setctty = true
325 325
 		go func() {
326 326
 			defer container.stdin.Close()
327 327
 			utils.Debugf("startPty: begin of stdin pipe")
... ...
@@ -333,10 +333,10 @@ func (container *Container) setupPty() error {
333 333
 }
334 334
 
335 335
 func (container *Container) setupStd() error {
336
-	container.process.Stdout = container.stdout
337
-	container.process.Stderr = container.stderr
336
+	container.command.Stdout = container.stdout
337
+	container.command.Stderr = container.stderr
338 338
 	if container.Config.OpenStdin {
339
-		stdin, err := container.process.StdinPipe()
339
+		stdin, err := container.command.StdinPipe()
340 340
 		if err != nil {
341 341
 			return err
342 342
 		}
... ...
@@ -494,6 +494,49 @@ func (container *Container) Attach(stdin io.ReadCloser, stdinCloser io.Closer, s
494 494
 	})
495 495
 }
496 496
 
497
+func populateCommand(c *Container) {
498
+	var (
499
+		en           *execdriver.Network
500
+		driverConfig []string
501
+	)
502
+	if !c.Config.NetworkDisabled {
503
+		network := c.NetworkSettings
504
+		en = &execdriver.Network{
505
+			Gateway:     network.Gateway,
506
+			Bridge:      network.Bridge,
507
+			IPAddress:   network.IPAddress,
508
+			IPPrefixLen: network.IPPrefixLen,
509
+			Mtu:         c.runtime.config.Mtu,
510
+		}
511
+	}
512
+
513
+	if lxcConf := c.hostConfig.LxcConf; lxcConf != nil {
514
+		for _, pair := range lxcConf {
515
+			driverConfig = append(driverConfig, fmt.Sprintf("%s = %s", pair.Key, pair.Value))
516
+		}
517
+	}
518
+	resources := &execdriver.Resources{
519
+		Memory:     c.Config.Memory,
520
+		MemorySwap: c.Config.MemorySwap,
521
+		CpuShares:  c.Config.CpuShares,
522
+	}
523
+	c.command = &execdriver.Command{
524
+		ID:         c.ID,
525
+		Privileged: c.hostConfig.Privileged,
526
+		Rootfs:     c.RootfsPath(),
527
+		InitPath:   "/.dockerinit",
528
+		Entrypoint: c.Path,
529
+		Arguments:  c.Args,
530
+		WorkingDir: c.Config.WorkingDir,
531
+		Network:    en,
532
+		Tty:        c.Config.Tty,
533
+		User:       c.Config.User,
534
+		Config:     driverConfig,
535
+		Resources:  resources,
536
+	}
537
+	c.command.SysProcAttr = &syscall.SysProcAttr{Setsid: true}
538
+}
539
+
497 540
 func (container *Container) Start() (err error) {
498 541
 	container.Lock()
499 542
 	defer container.Unlock()
... ...
@@ -605,15 +648,15 @@ func (container *Container) Start() (err error) {
605 605
 		return err
606 606
 	}
607 607
 
608
-	var workingDir string
608
+	root := container.RootfsPath()
609
+
609 610
 	if container.Config.WorkingDir != "" {
610
-		workingDir = path.Clean(container.Config.WorkingDir)
611
-		if err := os.MkdirAll(path.Join(container.RootfsPath(), workingDir), 0755); err != nil {
611
+		container.Config.WorkingDir = path.Clean(container.Config.WorkingDir)
612
+		if err := os.MkdirAll(path.Join(root, container.Config.WorkingDir), 0755); err != nil {
612 613
 			return nil
613 614
 		}
614 615
 	}
615 616
 
616
-	root := container.RootfsPath()
617 617
 	envPath, err := container.EnvConfigPath()
618 618
 	if err != nil {
619 619
 		return err
... ...
@@ -658,48 +701,7 @@ func (container *Container) Start() (err error) {
658 658
 		}
659 659
 	}
660 660
 
661
-	var (
662
-		en           *execdriver.Network
663
-		driverConfig []string
664
-	)
665
-
666
-	if !container.Config.NetworkDisabled {
667
-		network := container.NetworkSettings
668
-		en = &execdriver.Network{
669
-			Gateway:     network.Gateway,
670
-			Bridge:      network.Bridge,
671
-			IPAddress:   network.IPAddress,
672
-			IPPrefixLen: network.IPPrefixLen,
673
-			Mtu:         container.runtime.config.Mtu,
674
-		}
675
-	}
676
-
677
-	if lxcConf := container.hostConfig.LxcConf; lxcConf != nil {
678
-		for _, pair := range lxcConf {
679
-			driverConfig = append(driverConfig, fmt.Sprintf("%s = %s", pair.Key, pair.Value))
680
-		}
681
-	}
682
-	resources := &execdriver.Resources{
683
-		Memory:     container.Config.Memory,
684
-		MemorySwap: container.Config.MemorySwap,
685
-		CpuShares:  container.Config.CpuShares,
686
-	}
687
-
688
-	container.process = &execdriver.Process{
689
-		ID:         container.ID,
690
-		Privileged: container.hostConfig.Privileged,
691
-		Rootfs:     root,
692
-		InitPath:   "/.dockerinit",
693
-		Entrypoint: container.Path,
694
-		Arguments:  container.Args,
695
-		WorkingDir: workingDir,
696
-		Network:    en,
697
-		Tty:        container.Config.Tty,
698
-		User:       container.Config.User,
699
-		Config:     driverConfig,
700
-		Resources:  resources,
701
-	}
702
-	container.process.SysProcAttr = &syscall.SysProcAttr{Setsid: true}
661
+	populateCommand(container)
703 662
 
704 663
 	// Setup logging of stdout and stderr to disk
705 664
 	if err := container.runtime.LogToDisk(container.stdout, container.logPath("json"), "stdout"); err != nil {
... ...
@@ -722,13 +724,13 @@ func (container *Container) Start() (err error) {
722 722
 	}
723 723
 
724 724
 	callbackLock := make(chan struct{})
725
-	callback := func(process *execdriver.Process) {
726
-		container.State.SetRunning(process.Pid())
727
-		if process.Tty {
725
+	callback := func(command *execdriver.Command) {
726
+		container.State.SetRunning(command.Pid())
727
+		if command.Tty {
728 728
 			// The callback is called after the process Start()
729 729
 			// so we are in the parent process. In TTY mode, stdin/out/err is the PtySlace
730 730
 			// which we close here.
731
-			if c, ok := process.Stdout.(io.Closer); ok {
731
+			if c, ok := command.Stdout.(io.Closer); ok {
732 732
 				c.Close()
733 733
 			}
734 734
 		}
... ...
@@ -1134,9 +1136,10 @@ func (container *Container) monitor(callback execdriver.StartCallback) error {
1134 1134
 		exitCode int
1135 1135
 	)
1136 1136
 
1137
-	if container.process == nil {
1137
+	if container.command == nil {
1138 1138
 		// This happends when you have a GHOST container with lxc
1139
-		err = container.runtime.WaitGhost(container)
1139
+		populateCommand(container)
1140
+		err = container.runtime.RestoreCommand(container)
1140 1141
 	} else {
1141 1142
 		exitCode, err = container.runtime.Run(container, callback)
1142 1143
 	}
... ...
@@ -1228,7 +1231,7 @@ func (container *Container) Kill() error {
1228 1228
 
1229 1229
 	// 2. Wait for the process to die, in last resort, try to kill the process directly
1230 1230
 	if err := container.WaitTimeout(10 * time.Second); err != nil {
1231
-		if container.process == nil {
1231
+		if container.command == nil {
1232 1232
 			return fmt.Errorf("lxc-kill failed, impossible to kill the container %s", utils.TruncateID(container.ID))
1233 1233
 		}
1234 1234
 		log.Printf("Container %s failed to exit within 10 seconds of lxc-kill %s - trying direct SIGKILL", "SIGKILL", utils.TruncateID(container.ID))
... ...
@@ -36,7 +36,7 @@ func NewDriver() (*driver, error) {
36 36
 	return &driver{}, nil
37 37
 }
38 38
 
39
-func (d *driver) Run(c *execdriver.Process, startCallback execdriver.StartCallback) (int, error) {
39
+func (d *driver) Run(c *execdriver.Command, startCallback execdriver.StartCallback) (int, error) {
40 40
 	params := []string{
41 41
 		"chroot",
42 42
 		c.Rootfs,
... ...
@@ -70,11 +70,11 @@ func (d *driver) Run(c *execdriver.Process, startCallback execdriver.StartCallba
70 70
 	return c.GetExitCode(), err
71 71
 }
72 72
 
73
-func (d *driver) Kill(p *execdriver.Process, sig int) error {
73
+func (d *driver) Kill(p *execdriver.Command, sig int) error {
74 74
 	return p.Process.Kill()
75 75
 }
76 76
 
77
-func (d *driver) Wait(id string) error {
77
+func (d *driver) Restore(c *execdriver.Command) error {
78 78
 	panic("Not Implemented")
79 79
 }
80 80
 
... ...
@@ -16,7 +16,7 @@ var (
16 16
 var dockerInitFcts map[string]InitFunc
17 17
 
18 18
 type (
19
-	StartCallback func(*Process)
19
+	StartCallback func(*Command)
20 20
 	InitFunc      func(i *InitArgs) error
21 21
 )
22 22
 
... ...
@@ -59,11 +59,11 @@ type Info interface {
59 59
 }
60 60
 
61 61
 type Driver interface {
62
-	Run(c *Process, startCallback StartCallback) (int, error) // Run executes the process and blocks until the process exits and returns the exit code
63
-	Kill(c *Process, sig int) error
64
-	Wait(id string) error // Wait on an out of process...process - lxc ghosts TODO: Rename to reattach, reconnect
65
-	Name() string         // Driver name
66
-	Info(id string) Info  // "temporary" hack (until we move state from core to plugins)
62
+	Run(c *Command, startCallback StartCallback) (int, error) // Run executes the process and blocks until the process exits and returns the exit code
63
+	Kill(c *Command, sig int) error
64
+	Restore(c *Command) error // Wait and try to re-attach on an out of process command
65
+	Name() string             // Driver name
66
+	Info(id string) Info      // "temporary" hack (until we move state from core to plugins)
67 67
 }
68 68
 
69 69
 // Network settings of the container
... ...
@@ -83,8 +83,8 @@ type Resources struct {
83 83
 
84 84
 // Process wrapps an os/exec.Cmd to add more metadata
85 85
 // TODO: Rename to Command
86
-type Process struct {
87
-	exec.Cmd
86
+type Command struct {
87
+	exec.Cmd `json:"-"`
88 88
 
89 89
 	ID         string     `json:"id"`
90 90
 	Privileged bool       `json:"privileged"`
... ...
@@ -103,7 +103,7 @@ type Process struct {
103 103
 
104 104
 // Return the pid of the process
105 105
 // If the process is nil -1 will be returned
106
-func (c *Process) Pid() int {
106
+func (c *Command) Pid() int {
107 107
 	if c.Process == nil {
108 108
 		return -1
109 109
 	}
... ...
@@ -112,7 +112,7 @@ func (c *Process) Pid() int {
112 112
 
113 113
 // Return the exit code of the process
114 114
 // if the process has not exited -1 will be returned
115
-func (c *Process) GetExitCode() int {
115
+func (c *Command) GetExitCode() int {
116 116
 	if c.ProcessState == nil {
117 117
 		return -1
118 118
 	}
... ...
@@ -30,6 +30,7 @@ func init() {
30 30
 		if err := setupCapabilities(args); err != nil {
31 31
 			return err
32 32
 		}
33
+
33 34
 		if err := setupWorkingDirectory(args); err != nil {
34 35
 			return err
35 36
 		}
... ...
@@ -37,6 +38,7 @@ func init() {
37 37
 		if err := changeUser(args); err != nil {
38 38
 			return err
39 39
 		}
40
+
40 41
 		path, err := exec.LookPath(args.Args[0])
41 42
 		if err != nil {
42 43
 			log.Printf("Unable to locate %v", args.Args[0])
... ...
@@ -72,7 +74,7 @@ func (d *driver) Name() string {
72 72
 	return fmt.Sprintf("%s-%s", DriverName, version)
73 73
 }
74 74
 
75
-func (d *driver) Run(c *execdriver.Process, startCallback execdriver.StartCallback) (int, error) {
75
+func (d *driver) Run(c *execdriver.Command, startCallback execdriver.StartCallback) (int, error) {
76 76
 	configPath, err := d.generateLXCConfig(c)
77 77
 	if err != nil {
78 78
 		return -1, err
... ...
@@ -170,13 +172,13 @@ func (d *driver) Run(c *execdriver.Process, startCallback execdriver.StartCallba
170 170
 	return c.GetExitCode(), waitErr
171 171
 }
172 172
 
173
-func (d *driver) Kill(c *execdriver.Process, sig int) error {
173
+func (d *driver) Kill(c *execdriver.Command, sig int) error {
174 174
 	return d.kill(c, sig)
175 175
 }
176 176
 
177
-func (d *driver) Wait(id string) error {
177
+func (d *driver) Restore(c *execdriver.Command) error {
178 178
 	for {
179
-		output, err := exec.Command("lxc-info", "-n", id).CombinedOutput()
179
+		output, err := exec.Command("lxc-info", "-n", c.ID).CombinedOutput()
180 180
 		if err != nil {
181 181
 			return err
182 182
 		}
... ...
@@ -198,7 +200,7 @@ func (d *driver) version() string {
198 198
 	return version
199 199
 }
200 200
 
201
-func (d *driver) kill(c *execdriver.Process, sig int) error {
201
+func (d *driver) kill(c *execdriver.Command, sig int) error {
202 202
 	output, err := exec.Command("lxc-kill", "-n", c.ID, strconv.Itoa(sig)).CombinedOutput()
203 203
 	if err != nil {
204 204
 		return fmt.Errorf("Err: %s Output: %s", err, output)
... ...
@@ -206,7 +208,7 @@ func (d *driver) kill(c *execdriver.Process, sig int) error {
206 206
 	return nil
207 207
 }
208 208
 
209
-func (d *driver) waitForStart(c *execdriver.Process, waitLock chan struct{}) error {
209
+func (d *driver) waitForStart(c *execdriver.Command, waitLock chan struct{}) error {
210 210
 	var (
211 211
 		err    error
212 212
 		output []byte
... ...
@@ -302,8 +304,8 @@ func rootIsShared() bool {
302 302
 	return true
303 303
 }
304 304
 
305
-func (d *driver) generateLXCConfig(p *execdriver.Process) (string, error) {
306
-	root := path.Join(d.root, "containers", p.ID, "config.lxc")
305
+func (d *driver) generateLXCConfig(c *execdriver.Command) (string, error) {
306
+	root := path.Join(d.root, "containers", c.ID, "config.lxc")
307 307
 	fo, err := os.Create(root)
308 308
 	if err != nil {
309 309
 		return "", err
... ...
@@ -311,10 +313,10 @@ func (d *driver) generateLXCConfig(p *execdriver.Process) (string, error) {
311 311
 	defer fo.Close()
312 312
 
313 313
 	if err := LxcTemplateCompiled.Execute(fo, struct {
314
-		*execdriver.Process
314
+		*execdriver.Command
315 315
 		AppArmor bool
316 316
 	}{
317
-		Process:  p,
317
+		Command:  c,
318 318
 		AppArmor: d.apparmor,
319 319
 	}); err != nil {
320 320
 		return "", err
... ...
@@ -37,14 +37,14 @@ func TestLXCConfig(t *testing.T) {
37 37
 	if err != nil {
38 38
 		t.Fatal(err)
39 39
 	}
40
-	process := &execdriver.Process{
40
+	command := &execdriver.Command{
41 41
 		ID: "1",
42 42
 		Resources: &execdriver.Resources{
43 43
 			Memory:    int64(mem),
44 44
 			CpuShares: int64(cpu),
45 45
 		},
46 46
 	}
47
-	p, err := driver.generateLXCConfig(process)
47
+	p, err := driver.generateLXCConfig(command)
48 48
 	if err != nil {
49 49
 		t.Fatal(err)
50 50
 	}
... ...
@@ -68,7 +68,7 @@ func TestCustomLxcConfig(t *testing.T) {
68 68
 	if err != nil {
69 69
 		t.Fatal(err)
70 70
 	}
71
-	process := &execdriver.Process{
71
+	command := &execdriver.Command{
72 72
 		ID:         "1",
73 73
 		Privileged: false,
74 74
 		Config: []string{
... ...
@@ -77,7 +77,7 @@ func TestCustomLxcConfig(t *testing.T) {
77 77
 		},
78 78
 	}
79 79
 
80
-	p, err := driver.generateLXCConfig(process)
80
+	p, err := driver.generateLXCConfig(command)
81 81
 	if err != nil {
82 82
 		t.Fatal(err)
83 83
 	}
... ...
@@ -817,15 +817,15 @@ func (runtime *Runtime) Diff(container *Container) (archive.Archive, error) {
817 817
 }
818 818
 
819 819
 func (runtime *Runtime) Run(c *Container, startCallback execdriver.StartCallback) (int, error) {
820
-	return runtime.execDriver.Run(c.process, startCallback)
820
+	return runtime.execDriver.Run(c.command, startCallback)
821 821
 }
822 822
 
823 823
 func (runtime *Runtime) Kill(c *Container, sig int) error {
824
-	return runtime.execDriver.Kill(c.process, sig)
824
+	return runtime.execDriver.Kill(c.command, sig)
825 825
 }
826 826
 
827
-func (runtime *Runtime) WaitGhost(c *Container) error {
828
-	return runtime.execDriver.Wait(c.ID)
827
+func (runtime *Runtime) RestoreCommand(c *Container) error {
828
+	return runtime.execDriver.Restore(c.command)
829 829
 }
830 830
 
831 831
 // Nuke kills all containers then removes all content
... ...
@@ -50,14 +50,16 @@ func SysInit() {
50 50
 		os.Exit(1)
51 51
 	}
52 52
 
53
-	// Get cmdline arguments
54
-	user := flag.String("u", "", "username or uid")
55
-	gateway := flag.String("g", "", "gateway address")
56
-	ip := flag.String("i", "", "ip address")
57
-	workDir := flag.String("w", "", "workdir")
58
-	privileged := flag.Bool("privileged", false, "privileged mode")
59
-	mtu := flag.Int("mtu", 1500, "interface mtu")
60
-	driver := flag.String("driver", "", "exec driver")
53
+	var (
54
+		// Get cmdline arguments
55
+		user       = flag.String("u", "", "username or uid")
56
+		gateway    = flag.String("g", "", "gateway address")
57
+		ip         = flag.String("i", "", "ip address")
58
+		workDir    = flag.String("w", "", "workdir")
59
+		privileged = flag.Bool("privileged", false, "privileged mode")
60
+		mtu        = flag.Int("mtu", 1500, "interface mtu")
61
+		driver     = flag.String("driver", "", "exec driver")
62
+	)
61 63
 	flag.Parse()
62 64
 
63 65
 	// Get env