1
0
Fork 0
mirror of https://github.com/moby/moby.git synced 2022-11-09 12:21:53 -05:00

Return correct process pid for lxc

Fixes #2875
Docker-DCO-1.1-Signed-off-by: Michael Crosby <michael@crosbymichael.com> (github: crosbymichael)
This commit is contained in:
Michael Crosby 2014-03-05 17:57:27 -08:00
parent d03be9d7cf
commit 69e3d30bb6
5 changed files with 106 additions and 17 deletions

View file

@ -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
}

View file

@ -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
execdriver/lxc/info.go Normal file
View file

@ -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
}

View file

@ -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)
}
}

View file

@ -266,6 +266,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)