mirror of
https://github.com/moby/moby.git
synced 2022-11-09 12:21:53 -05:00
Merge pull request #4488 from crosbymichael/return-correct-lxc-pid
Return correct process pid for lxc
This commit is contained in:
commit
e4ebe6a12f
5 changed files with 106 additions and 17 deletions
|
@ -116,15 +116,13 @@ type Command struct {
|
||||||
Config []string `json:"config"` // generic values that specific drivers can consume
|
Config []string `json:"config"` // generic values that specific drivers can consume
|
||||||
Resources *Resources `json:"resources"`
|
Resources *Resources `json:"resources"`
|
||||||
|
|
||||||
Terminal Terminal `json:"-"` // standard or tty terminal
|
Terminal Terminal `json:"-"` // standard or tty terminal
|
||||||
Console string `json:"-"` // dev/console path
|
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
|
// Return the pid of the process
|
||||||
// If the process is nil -1 will be returned
|
// If the process is nil -1 will be returned
|
||||||
func (c *Command) Pid() int {
|
func (c *Command) Pid() int {
|
||||||
if c.Process == nil {
|
return c.ContainerPid
|
||||||
return -1
|
|
||||||
}
|
|
||||||
return c.Process.Pid
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -166,9 +166,11 @@ func (d *driver) Run(c *execdriver.Command, pipes *execdriver.Pipes, startCallba
|
||||||
}()
|
}()
|
||||||
|
|
||||||
// Poll lxc for RUNNING status
|
// 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
|
return -1, err
|
||||||
}
|
}
|
||||||
|
c.ContainerPid = pid
|
||||||
|
|
||||||
if startCallback != nil {
|
if startCallback != nil {
|
||||||
startCallback(c)
|
startCallback(c)
|
||||||
|
@ -242,7 +244,8 @@ func (d *driver) kill(c *execdriver.Command, sig int) error {
|
||||||
return nil
|
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 (
|
var (
|
||||||
err error
|
err error
|
||||||
output []byte
|
output []byte
|
||||||
|
@ -255,10 +258,7 @@ func (d *driver) waitForStart(c *execdriver.Command, waitLock chan struct{}) err
|
||||||
select {
|
select {
|
||||||
case <-waitLock:
|
case <-waitLock:
|
||||||
// If the process dies while waiting for it, just return
|
// If the process dies while waiting for it, just return
|
||||||
return nil
|
return -1, nil
|
||||||
if c.ProcessState != nil && c.ProcessState.Exited() {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
default:
|
default:
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -266,19 +266,23 @@ func (d *driver) waitForStart(c *execdriver.Command, waitLock chan struct{}) err
|
||||||
if err != nil {
|
if err != nil {
|
||||||
output, err = d.getInfo(c.ID)
|
output, err = d.getInfo(c.ID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return -1, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if strings.Contains(string(output), "RUNNING") {
|
info, err := parseLxcInfo(string(output))
|
||||||
return nil
|
if err != nil {
|
||||||
|
return -1, err
|
||||||
|
}
|
||||||
|
if info.Running {
|
||||||
|
return info.Pid, nil
|
||||||
}
|
}
|
||||||
time.Sleep(50 * time.Millisecond)
|
time.Sleep(50 * time.Millisecond)
|
||||||
}
|
}
|
||||||
return execdriver.ErrNotRunning
|
return -1, execdriver.ErrNotRunning
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *driver) getInfo(id string) ([]byte, error) {
|
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 {
|
type info struct {
|
||||||
|
|
50
execdriver/lxc/info.go
Normal file
50
execdriver/lxc/info.go
Normal 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
|
||||||
|
}
|
36
execdriver/lxc/info_test.go
Normal file
36
execdriver/lxc/info_test.go
Normal 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)
|
||||||
|
}
|
||||||
|
}
|
|
@ -271,6 +271,7 @@ type dockerStateWriter struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *dockerStateWriter) WritePid(pid int) error {
|
func (d *dockerStateWriter) WritePid(pid int) error {
|
||||||
|
d.c.ContainerPid = pid
|
||||||
err := d.dsw.WritePid(pid)
|
err := d.dsw.WritePid(pid)
|
||||||
if d.callback != nil {
|
if d.callback != nil {
|
||||||
d.callback(d.c)
|
d.callback(d.c)
|
||||||
|
|
Loading…
Add table
Reference in a new issue