Просмотр исходного кода

Merge pull request #4488 from crosbymichael/return-correct-lxc-pid

Return correct process pid for lxc
unclejack 11 лет назад
Родитель
Сommit
e4ebe6a12f
5 измененных файлов с 106 добавлено и 17 удалено
  1. 4 6
      execdriver/driver.go
  2. 15 11
      execdriver/lxc/driver.go
  3. 50 0
      execdriver/lxc/info.go
  4. 36 0
      execdriver/lxc/info_test.go
  5. 1 0
      execdriver/native/driver.go

+ 4 - 6
execdriver/driver.go

@@ -116,15 +116,13 @@ type Command struct {
 	Config     []string   `json:"config"`  //  generic values that specific drivers can consume
 	Resources  *Resources `json:"resources"`
 
-	Terminal Terminal `json:"-"` // standard or tty terminal
-	Console  string   `json:"-"` // dev/console path
+	Terminal     Terminal `json:"-"`             // standard or tty terminal
+	Console      string   `json:"-"`             // dev/console path
+	ContainerPid int      `json:"container_pid"` // the pid for the process inside a container
 }
 
 // Return the pid of the process
 // If the process is nil -1 will be returned
 func (c *Command) Pid() int {
-	if c.Process == nil {
-		return -1
-	}
-	return c.Process.Pid
+	return c.ContainerPid
 }

+ 15 - 11
execdriver/lxc/driver.go

@@ -166,9 +166,11 @@ func (d *driver) Run(c *execdriver.Command, pipes *execdriver.Pipes, startCallba
 	}()
 
 	// Poll lxc for RUNNING status
-	if err := d.waitForStart(c, waitLock); err != nil {
+	pid, err := d.waitForStart(c, waitLock)
+	if err != nil {
 		return -1, err
 	}
+	c.ContainerPid = pid
 
 	if startCallback != nil {
 		startCallback(c)
@@ -242,7 +244,8 @@ func (d *driver) kill(c *execdriver.Command, sig int) error {
 	return nil
 }
 
-func (d *driver) waitForStart(c *execdriver.Command, waitLock chan struct{}) error {
+// wait for the process to start and return the pid for the process
+func (d *driver) waitForStart(c *execdriver.Command, waitLock chan struct{}) (int, error) {
 	var (
 		err    error
 		output []byte
@@ -255,10 +258,7 @@ func (d *driver) waitForStart(c *execdriver.Command, waitLock chan struct{}) err
 		select {
 		case <-waitLock:
 			// If the process dies while waiting for it, just return
-			return nil
-			if c.ProcessState != nil && c.ProcessState.Exited() {
-				return nil
-			}
+			return -1, nil
 		default:
 		}
 
@@ -266,19 +266,23 @@ func (d *driver) waitForStart(c *execdriver.Command, waitLock chan struct{}) err
 		if err != nil {
 			output, err = d.getInfo(c.ID)
 			if err != nil {
-				return err
+				return -1, err
 			}
 		}
-		if strings.Contains(string(output), "RUNNING") {
-			return nil
+		info, err := parseLxcInfo(string(output))
+		if err != nil {
+			return -1, err
+		}
+		if info.Running {
+			return info.Pid, nil
 		}
 		time.Sleep(50 * time.Millisecond)
 	}
-	return execdriver.ErrNotRunning
+	return -1, execdriver.ErrNotRunning
 }
 
 func (d *driver) getInfo(id string) ([]byte, error) {
-	return exec.Command("lxc-info", "-s", "-n", id).CombinedOutput()
+	return exec.Command("lxc-info", "-n", id).CombinedOutput()
 }
 
 type info struct {

+ 50 - 0
execdriver/lxc/info.go

@@ -0,0 +1,50 @@
+package lxc
+
+import (
+	"bufio"
+	"errors"
+	"strconv"
+	"strings"
+)
+
+var (
+	ErrCannotParse = errors.New("cannot parse raw input")
+)
+
+type lxcInfo struct {
+	Running bool
+	Pid     int
+}
+
+func parseLxcInfo(raw string) (*lxcInfo, error) {
+	if raw == "" {
+		return nil, ErrCannotParse
+	}
+	var (
+		err  error
+		s    = bufio.NewScanner(strings.NewReader(raw))
+		info = &lxcInfo{}
+	)
+	for s.Scan() {
+		text := s.Text()
+
+		if s.Err() != nil {
+			return nil, s.Err()
+		}
+
+		parts := strings.Split(text, ":")
+		if len(parts) < 2 {
+			continue
+		}
+		switch strings.TrimSpace(parts[0]) {
+		case "state":
+			info.Running = strings.TrimSpace(parts[1]) == "RUNNING"
+		case "pid":
+			info.Pid, err = strconv.Atoi(strings.TrimSpace(parts[1]))
+			if err != nil {
+				return nil, err
+			}
+		}
+	}
+	return info, nil
+}

+ 36 - 0
execdriver/lxc/info_test.go

@@ -0,0 +1,36 @@
+package lxc
+
+import (
+	"testing"
+)
+
+func TestParseRunningInfo(t *testing.T) {
+	raw := `
+    state: RUNNING
+    pid:    50`
+
+	info, err := parseLxcInfo(raw)
+	if err != nil {
+		t.Fatal(err)
+	}
+	if !info.Running {
+		t.Fatal("info should return a running state")
+	}
+	if info.Pid != 50 {
+		t.Fatalf("info should have pid 50 got %d", info.Pid)
+	}
+}
+
+func TestEmptyInfo(t *testing.T) {
+	_, err := parseLxcInfo("")
+	if err == nil {
+		t.Fatal("error should not be nil")
+	}
+}
+
+func TestBadInfo(t *testing.T) {
+	_, err := parseLxcInfo("state")
+	if err != nil {
+		t.Fatal(err)
+	}
+}

+ 1 - 0
execdriver/native/driver.go

@@ -271,6 +271,7 @@ type dockerStateWriter struct {
 }
 
 func (d *dockerStateWriter) WritePid(pid int) error {
+	d.c.ContainerPid = pid
 	err := d.dsw.WritePid(pid)
 	if d.callback != nil {
 		d.callback(d.c)