Fix monitor with process events
Monitor was receiving multiple events for the process Signed-off-by: Michael Crosby <crosbymichael@gmail.com>
This commit is contained in:
parent
1911191f94
commit
a861ae9d18
6 changed files with 172 additions and 84 deletions
|
@ -83,7 +83,7 @@ func start(log *os.File) error {
|
||||||
}
|
}
|
||||||
defer func() {
|
defer func() {
|
||||||
if err := p.Close(); err != nil {
|
if err := p.Close(); err != nil {
|
||||||
writeMessage(log, "warn", err)
|
writeMessage(log, "warn", fmt.Errorf("close stdio %s", err))
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
if err := p.create(); err != nil {
|
if err := p.create(); err != nil {
|
||||||
|
@ -127,7 +127,6 @@ func start(log *os.File) error {
|
||||||
// Wait for all the childs this process may have
|
// Wait for all the childs this process may have
|
||||||
// created (needed for exec and init processes when
|
// created (needed for exec and init processes when
|
||||||
// they join another pid namespace)
|
// they join another pid namespace)
|
||||||
osutils.Reap(true)
|
|
||||||
p.Wait()
|
p.Wait()
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -151,7 +150,7 @@ func start(log *os.File) error {
|
||||||
case 2:
|
case 2:
|
||||||
// signal
|
// signal
|
||||||
if err := syscall.Kill(p.pid(), syscall.Signal(msg.Width)); err != nil {
|
if err := syscall.Kill(p.pid(), syscall.Signal(msg.Width)); err != nil {
|
||||||
writeMessage(log, "warn", err)
|
writeMessage(log, "warn", fmt.Errorf("signal pid %d: %s", msg.Width, err))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,7 +3,9 @@ package main
|
||||||
import (
|
import (
|
||||||
"flag"
|
"flag"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"io"
|
||||||
"os"
|
"os"
|
||||||
|
"strconv"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/Sirupsen/logrus"
|
"github.com/Sirupsen/logrus"
|
||||||
|
@ -33,9 +35,9 @@ func runContainer() error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
// setup some stdio for our container
|
// setup some stdio for our container
|
||||||
container.Stdin = Stdin()
|
container.Stdin = Stdin("")
|
||||||
container.Stdout = Stdout()
|
container.Stdout = Stdout("")
|
||||||
container.Stderr = Stderr()
|
container.Stderr = Stderr("")
|
||||||
|
|
||||||
// go ahead and set the container in the create state and have it ready to start
|
// go ahead and set the container in the create state and have it ready to start
|
||||||
logrus.Info("create container")
|
logrus.Info("create container")
|
||||||
|
@ -49,33 +51,36 @@ func runContainer() error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if exec {
|
for i := 0; i < exec; i++ {
|
||||||
// start 10 exec processes giving the go var i to exec to stdout
|
process, err := container.NewProcess(&specs.Process{
|
||||||
for i := 0; i < 10; i++ {
|
Args: []string{
|
||||||
process, err := container.NewProcess(&specs.Process{
|
"sh", "-c",
|
||||||
Args: []string{
|
"echo " + fmt.Sprintf("sup from itteration %d", i),
|
||||||
"echo", fmt.Sprintf("sup from itteration %d", i),
|
},
|
||||||
},
|
Env: env,
|
||||||
Env: env,
|
Terminal: false,
|
||||||
Terminal: false,
|
Cwd: "/",
|
||||||
Cwd: "/",
|
NoNewPrivileges: true,
|
||||||
NoNewPrivileges: true,
|
Capabilities: caps,
|
||||||
Capabilities: caps,
|
})
|
||||||
})
|
|
||||||
|
|
||||||
process.Stdin = os.Stdin
|
process.Stdin = Stdin(strconv.Itoa(i))
|
||||||
process.Stdout = os.Stdout
|
stdout := Stdout(strconv.Itoa(i))
|
||||||
process.Stderr = os.Stderr
|
|
||||||
|
|
||||||
if err := process.Start(); err != nil {
|
stderr := Stderr(strconv.Itoa(i))
|
||||||
return err
|
go io.Copy(os.Stdout, stdout)
|
||||||
}
|
go io.Copy(os.Stdout, stderr)
|
||||||
procStatus, err := process.Wait()
|
process.Stdout = stdout
|
||||||
if err != nil {
|
process.Stderr = stderr
|
||||||
return err
|
|
||||||
}
|
if err := process.Start(); err != nil {
|
||||||
logrus.Infof("process %d returned with %d", i, procStatus)
|
return err
|
||||||
}
|
}
|
||||||
|
procStatus, err := process.Wait()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
logrus.Infof("process %d returned with %d", i, procStatus)
|
||||||
}
|
}
|
||||||
|
|
||||||
if load {
|
if load {
|
||||||
|
@ -101,13 +106,13 @@ func runContainer() error {
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
exec bool
|
exec int
|
||||||
load bool
|
load bool
|
||||||
)
|
)
|
||||||
|
|
||||||
// "Hooks do optional work. Drivers do mandatory work"
|
// "Hooks do optional work. Drivers do mandatory work"
|
||||||
func main() {
|
func main() {
|
||||||
flag.BoolVar(&exec, "exec", false, "run the execs")
|
flag.IntVar(&exec, "exec", 0, "run n number of execs")
|
||||||
flag.BoolVar(&load, "load", false, "reload the container")
|
flag.BoolVar(&load, "load", false, "reload the container")
|
||||||
flag.Parse()
|
flag.Parse()
|
||||||
if err := osutils.SetSubreaper(1); err != nil {
|
if err := osutils.SetSubreaper(1); err != nil {
|
||||||
|
|
|
@ -182,8 +182,8 @@ func (t *testConfig) Spec(m *containerkit.Mount) (*specs.Spec, error) {
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func Stdin() *os.File {
|
func Stdin(n string) *os.File {
|
||||||
abs, err := filepath.Abs("stdin")
|
abs, err := filepath.Abs("stdin" + n)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
@ -197,8 +197,8 @@ func Stdin() *os.File {
|
||||||
return f
|
return f
|
||||||
}
|
}
|
||||||
|
|
||||||
func Stdout() *os.File {
|
func Stdout(n string) *os.File {
|
||||||
abs, err := filepath.Abs("stdout")
|
abs, err := filepath.Abs("stdout" + n)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
@ -212,8 +212,8 @@ func Stdout() *os.File {
|
||||||
return f
|
return f
|
||||||
}
|
}
|
||||||
|
|
||||||
func Stderr() *os.File {
|
func Stderr(n string) *os.File {
|
||||||
abs, err := filepath.Abs("stderr")
|
abs, err := filepath.Abs("stderr" + n)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
package monitor
|
package monitor
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"io"
|
||||||
"sync"
|
"sync"
|
||||||
"syscall"
|
"syscall"
|
||||||
|
|
||||||
|
@ -10,6 +11,9 @@ import (
|
||||||
|
|
||||||
type Monitorable interface {
|
type Monitorable interface {
|
||||||
FD() int
|
FD() int
|
||||||
|
// Remove returns true if the monitorable should be removed
|
||||||
|
// from the event monitor under the lock of when the event was received
|
||||||
|
Remove() bool
|
||||||
}
|
}
|
||||||
|
|
||||||
type Flusher interface {
|
type Flusher interface {
|
||||||
|
@ -63,6 +67,10 @@ func (m *Monitor) Add(ma Monitorable) error {
|
||||||
func (m *Monitor) Remove(ma Monitorable) error {
|
func (m *Monitor) Remove(ma Monitorable) error {
|
||||||
m.m.Lock()
|
m.m.Lock()
|
||||||
defer m.m.Unlock()
|
defer m.m.Unlock()
|
||||||
|
return m.remove(ma)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *Monitor) remove(ma Monitorable) error {
|
||||||
fd := ma.FD()
|
fd := ma.FD()
|
||||||
delete(m.receivers, fd)
|
delete(m.receivers, fd)
|
||||||
return syscall.EpollCtl(m.epollFd, syscall.EPOLL_CTL_DEL, fd, &syscall.EpollEvent{
|
return syscall.EpollCtl(m.epollFd, syscall.EPOLL_CTL_DEL, fd, &syscall.EpollEvent{
|
||||||
|
@ -84,18 +92,28 @@ func (m *Monitor) Run() {
|
||||||
if err == syscall.EINTR {
|
if err == syscall.EINTR {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
logrus.WithField("error", err).Fatal("containerd: epoll wait")
|
logrus.WithField("error", err).Fatal("shim: epoll wait")
|
||||||
}
|
}
|
||||||
for i := 0; i < n; i++ {
|
for i := 0; i < n; i++ {
|
||||||
fd := int(events[i].Fd)
|
fd := int(events[i].Fd)
|
||||||
m.m.Lock()
|
m.m.Lock()
|
||||||
r := m.receivers[fd]
|
r := m.receivers[fd]
|
||||||
m.m.Unlock()
|
|
||||||
if f, ok := r.(Flusher); ok {
|
if f, ok := r.(Flusher); ok {
|
||||||
if err := f.Flush(); err != nil {
|
if err := f.Flush(); err != nil {
|
||||||
logrus.WithField("error", err).Fatal("containerd: flush event FD")
|
logrus.WithField("error", err).Fatal("shim: flush event FD")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if r.Remove() {
|
||||||
|
if err := m.remove(r); err != nil {
|
||||||
|
logrus.WithField("error", err).Fatal("shim: remove event FD")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if f, ok := r.(io.Closer); ok {
|
||||||
|
if err := f.Close(); err != nil {
|
||||||
|
logrus.WithField("error", err).Fatal("shim: close event FD")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
m.m.Unlock()
|
||||||
m.events <- r
|
m.events <- r
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -31,12 +31,22 @@ var (
|
||||||
|
|
||||||
const UnknownStatus = 255
|
const UnknownStatus = 255
|
||||||
|
|
||||||
func newProcess(root string, noPivotRoot bool, checkpoint string, c *containerkit.Container, cmd *exec.Cmd) (*process, error) {
|
type processOpts struct {
|
||||||
if err := os.Mkdir(root, 0711); err != nil {
|
root string
|
||||||
return nil, err
|
noPivotRoot bool
|
||||||
}
|
checkpoint string
|
||||||
|
c *containerkit.Container
|
||||||
|
cmd *exec.Cmd
|
||||||
|
exec bool
|
||||||
|
spec specs.Process
|
||||||
|
stdin io.Reader
|
||||||
|
stdout io.Writer
|
||||||
|
stderr io.Writer
|
||||||
|
}
|
||||||
|
|
||||||
|
func newProcess(opts processOpts) (*process, error) {
|
||||||
var (
|
var (
|
||||||
spec = c.Spec()
|
spec = opts.c.Spec()
|
||||||
stdin, stdout, stderr string
|
stdin, stdout, stderr string
|
||||||
)
|
)
|
||||||
uid, gid, err := getRootIDs(spec)
|
uid, gid, err := getRootIDs(spec)
|
||||||
|
@ -49,15 +59,15 @@ func newProcess(root string, noPivotRoot bool, checkpoint string, c *containerki
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
path: &stdin,
|
path: &stdin,
|
||||||
v: c.Stdin,
|
v: opts.stdin,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: &stdout,
|
path: &stdout,
|
||||||
v: c.Stdout,
|
v: opts.stdout,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: &stderr,
|
path: &stderr,
|
||||||
v: c.Stderr,
|
v: opts.stderr,
|
||||||
},
|
},
|
||||||
} {
|
} {
|
||||||
p, err := getFifoPath(t.v)
|
p, err := getFifoPath(t.v)
|
||||||
|
@ -67,20 +77,20 @@ func newProcess(root string, noPivotRoot bool, checkpoint string, c *containerki
|
||||||
*t.path = p
|
*t.path = p
|
||||||
}
|
}
|
||||||
p := &process{
|
p := &process{
|
||||||
root: root,
|
root: opts.root,
|
||||||
cmd: cmd,
|
cmd: opts.cmd,
|
||||||
done: make(chan struct{}),
|
done: make(chan struct{}),
|
||||||
spec: spec.Process,
|
spec: opts.spec,
|
||||||
exec: false,
|
exec: opts.exec,
|
||||||
rootUid: uid,
|
rootUid: uid,
|
||||||
rootGid: gid,
|
rootGid: gid,
|
||||||
noPivotRoot: noPivotRoot,
|
noPivotRoot: opts.noPivotRoot,
|
||||||
checkpoint: checkpoint,
|
checkpoint: opts.checkpoint,
|
||||||
stdin: stdin,
|
stdin: stdin,
|
||||||
stdout: stdout,
|
stdout: stdout,
|
||||||
stderr: stderr,
|
stderr: stderr,
|
||||||
}
|
}
|
||||||
f, err := os.Create(filepath.Join(root, "process.json"))
|
f, err := os.Create(filepath.Join(opts.root, "process.json"))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -89,11 +99,11 @@ func newProcess(root string, noPivotRoot bool, checkpoint string, c *containerki
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
exit, err := getExitPipe(filepath.Join(root, "exit"))
|
exit, err := getExitPipe(filepath.Join(opts.root, "exit"))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
control, err := getControlPipe(filepath.Join(root, "control"))
|
control, err := getControlPipe(filepath.Join(opts.root, "control"))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -199,6 +209,14 @@ func (p *process) FD() int {
|
||||||
return int(p.exit.Fd())
|
return int(p.exit.Fd())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (p *process) Close() error {
|
||||||
|
return p.exit.Close()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *process) Remove() bool {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
func (p *process) Wait() (rst uint32, rerr error) {
|
func (p *process) Wait() (rst uint32, rerr error) {
|
||||||
<-p.done
|
<-p.done
|
||||||
data, err := ioutil.ReadFile(filepath.Join(p.root, "exitStatus"))
|
data, err := ioutil.ReadFile(filepath.Join(p.root, "exitStatus"))
|
||||||
|
@ -228,6 +246,8 @@ func (p *process) Signal(s os.Signal) error {
|
||||||
// same checks if the process is the same process originally launched
|
// same checks if the process is the same process originally launched
|
||||||
func (p *process) same() (bool, error) {
|
func (p *process) same() (bool, error) {
|
||||||
/// for backwards compat assume true if it is not set
|
/// for backwards compat assume true if it is not set
|
||||||
|
p.mu.Lock()
|
||||||
|
defer p.mu.Unlock()
|
||||||
if p.startTime == "" {
|
if p.startTime == "" {
|
||||||
return true, nil
|
return true, nil
|
||||||
}
|
}
|
||||||
|
@ -245,14 +265,19 @@ func (p *process) same() (bool, error) {
|
||||||
func (p *process) checkExited() {
|
func (p *process) checkExited() {
|
||||||
err := p.cmd.Wait()
|
err := p.cmd.Wait()
|
||||||
if err == nil {
|
if err == nil {
|
||||||
|
p.mu.Lock()
|
||||||
|
if p.success {
|
||||||
|
p.mu.Unlock()
|
||||||
|
return
|
||||||
|
}
|
||||||
p.success = true
|
p.success = true
|
||||||
|
p.mu.Unlock()
|
||||||
}
|
}
|
||||||
if same, _ := p.same(); same && p.hasPid() {
|
if same, _ := p.same(); same && p.hasPid() {
|
||||||
// The process changed its PR_SET_PDEATHSIG, so force kill it
|
// The process changed its PR_SET_PDEATHSIG, so force kill it
|
||||||
logrus.Infof("containerd: (pid %v) has become an orphan, killing it", p.pid)
|
logrus.Infof("containerd: (pid %v) has become an orphan, killing it", p.pid)
|
||||||
if err := unix.Kill(p.pid, syscall.SIGKILL); err != nil && err != syscall.ESRCH {
|
if err := unix.Kill(p.pid, syscall.SIGKILL); err != nil && err != syscall.ESRCH {
|
||||||
logrus.Errorf("containerd: unable to SIGKILL (pid %v): %v", p.pid, err)
|
logrus.Errorf("containerd: unable to SIGKILL (pid %v): %v", p.pid, err)
|
||||||
close(p.done)
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
// wait for the container process to exit
|
// wait for the container process to exit
|
||||||
|
@ -263,7 +288,6 @@ func (p *process) checkExited() {
|
||||||
time.Sleep(5 * time.Millisecond)
|
time.Sleep(5 * time.Millisecond)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
close(p.done)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *process) hasPid() bool {
|
func (p *process) hasPid() bool {
|
||||||
|
@ -273,12 +297,6 @@ func (p *process) hasPid() bool {
|
||||||
return r
|
return r
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *process) setPid(pid int) {
|
|
||||||
p.mu.Lock()
|
|
||||||
p.pid = pid
|
|
||||||
p.mu.Unlock()
|
|
||||||
}
|
|
||||||
|
|
||||||
type pidResponse struct {
|
type pidResponse struct {
|
||||||
pid int
|
pid int
|
||||||
err error
|
err error
|
||||||
|
@ -293,21 +311,30 @@ func (p *process) waitForCreate(timeout time.Duration) error {
|
||||||
if resp.err != nil {
|
if resp.err != nil {
|
||||||
return resp.err
|
return resp.err
|
||||||
}
|
}
|
||||||
p.setPid(resp.pid)
|
p.mu.Lock()
|
||||||
|
p.pid = resp.pid
|
||||||
started, err := readProcessStartTime(resp.pid)
|
started, err := readProcessStartTime(resp.pid)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
if os.IsNotExist(err) {
|
||||||
|
// process already exited
|
||||||
|
p.success = true
|
||||||
|
p.mu.Unlock()
|
||||||
|
return nil
|
||||||
|
}
|
||||||
logrus.Warnf("shim: unable to save starttime: %v", err)
|
logrus.Warnf("shim: unable to save starttime: %v", err)
|
||||||
}
|
}
|
||||||
p.startTime = started
|
p.startTime = started
|
||||||
f, err := os.Create(filepath.Join(p.root, "process.json"))
|
f, err := os.Create(filepath.Join(p.root, "process.json"))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logrus.Warnf("shim: unable to save starttime: %v", err)
|
logrus.Warnf("shim: unable to create process.json: %v", err)
|
||||||
|
p.mu.Unlock()
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
defer f.Close()
|
defer f.Close()
|
||||||
if err := json.NewEncoder(f).Encode(p); err != nil {
|
if err := json.NewEncoder(f).Encode(p); err != nil {
|
||||||
logrus.Warnf("shim: unable to save starttime: %v", err)
|
logrus.Warnf("shim: unable to encode process: %v", err)
|
||||||
}
|
}
|
||||||
|
p.mu.Unlock()
|
||||||
return nil
|
return nil
|
||||||
case <-time.After(timeout):
|
case <-time.After(timeout):
|
||||||
p.cmd.Process.Kill()
|
p.cmd.Process.Kill()
|
||||||
|
|
69
shim/shim.go
69
shim/shim.go
|
@ -12,7 +12,6 @@ import (
|
||||||
"syscall"
|
"syscall"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/Sirupsen/logrus"
|
|
||||||
"github.com/docker/containerd/monitor"
|
"github.com/docker/containerd/monitor"
|
||||||
"github.com/docker/containerd/oci"
|
"github.com/docker/containerd/oci"
|
||||||
"github.com/docker/containerkit"
|
"github.com/docker/containerkit"
|
||||||
|
@ -104,6 +103,7 @@ func Load(root string) (*Shim, error) {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
s.m = m
|
s.m = m
|
||||||
|
go s.startMonitor()
|
||||||
dirs, err := ioutil.ReadDir(root)
|
dirs, err := ioutil.ReadDir(root)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
@ -204,6 +204,9 @@ func (s *Shim) Create(c *containerkit.Container) (containerkit.ProcessDelegate,
|
||||||
root = filepath.Join(s.root, "init")
|
root = filepath.Join(s.root, "init")
|
||||||
cmd = s.command(c.ID(), c.Path(), s.runtime.Name())
|
cmd = s.command(c.ID(), c.Path(), s.runtime.Name())
|
||||||
)
|
)
|
||||||
|
if err := os.Mkdir(root, 0711); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
// exec the shim inside the state directory setup with the process
|
// exec the shim inside the state directory setup with the process
|
||||||
// information for what is being run
|
// information for what is being run
|
||||||
cmd.Dir = root
|
cmd.Dir = root
|
||||||
|
@ -211,17 +214,23 @@ func (s *Shim) Create(c *containerkit.Container) (containerkit.ProcessDelegate,
|
||||||
cmd.SysProcAttr = &syscall.SysProcAttr{
|
cmd.SysProcAttr = &syscall.SysProcAttr{
|
||||||
Setpgid: true,
|
Setpgid: true,
|
||||||
}
|
}
|
||||||
p, err := s.startCommand(c, cmd)
|
p, err := s.startCommand(processOpts{
|
||||||
|
spec: c.Spec().Process,
|
||||||
|
root: root,
|
||||||
|
noPivotRoot: s.noPivotRoot,
|
||||||
|
checkpoint: s.checkpoint,
|
||||||
|
c: c,
|
||||||
|
cmd: cmd,
|
||||||
|
stdin: c.Stdin,
|
||||||
|
stdout: c.Stdout,
|
||||||
|
stderr: c.Stderr,
|
||||||
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
if err := s.m.Add(p); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
s.pmu.Lock()
|
s.pmu.Lock()
|
||||||
s.processes["init"] = p
|
s.processes["init"] = p
|
||||||
s.pmu.Unlock()
|
s.pmu.Unlock()
|
||||||
|
|
||||||
f, err := os.Create(filepath.Join(s.root, "state.json"))
|
f, err := os.Create(filepath.Join(s.root, "state.json"))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
@ -276,10 +285,38 @@ func (s *Shim) Delete(c *containerkit.Container) error {
|
||||||
return os.RemoveAll(s.root)
|
return os.RemoveAll(s.root)
|
||||||
}
|
}
|
||||||
|
|
||||||
var errnotimpl = errors.New("NOT IMPL RIGHT NOW, CHILL")
|
|
||||||
|
|
||||||
func (s *Shim) Exec(c *containerkit.Container, p *containerkit.Process) (containerkit.ProcessDelegate, error) {
|
func (s *Shim) Exec(c *containerkit.Container, p *containerkit.Process) (containerkit.ProcessDelegate, error) {
|
||||||
return nil, errnotimpl
|
root, err := ioutil.TempDir(s.root, "")
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
cmd := s.command(c.ID(), c.Path(), s.runtime.Name())
|
||||||
|
// exec the shim inside the state directory setup with the process
|
||||||
|
// information for what is being run
|
||||||
|
cmd.Dir = root
|
||||||
|
// make sure the shim is in a new process group
|
||||||
|
cmd.SysProcAttr = &syscall.SysProcAttr{
|
||||||
|
Setpgid: true,
|
||||||
|
}
|
||||||
|
sp, err := s.startCommand(processOpts{
|
||||||
|
exec: true,
|
||||||
|
spec: *p.Spec(),
|
||||||
|
root: root,
|
||||||
|
noPivotRoot: s.noPivotRoot,
|
||||||
|
checkpoint: s.checkpoint,
|
||||||
|
c: c,
|
||||||
|
cmd: cmd,
|
||||||
|
stdin: p.Stdin,
|
||||||
|
stdout: p.Stdout,
|
||||||
|
stderr: p.Stderr,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
s.pmu.Lock()
|
||||||
|
s.processes[filepath.Base(root)] = sp
|
||||||
|
s.pmu.Unlock()
|
||||||
|
return sp, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Shim) Load(id string) (containerkit.ProcessDelegate, error) {
|
func (s *Shim) Load(id string) (containerkit.ProcessDelegate, error) {
|
||||||
|
@ -296,12 +333,15 @@ func (s *Shim) getContainerInit() (*process, error) {
|
||||||
return p, nil
|
return p, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Shim) startCommand(c *containerkit.Container, cmd *exec.Cmd) (*process, error) {
|
func (s *Shim) startCommand(opts processOpts) (*process, error) {
|
||||||
p, err := newProcess(filepath.Join(s.root, "init"), s.noPivotRoot, s.checkpoint, c, cmd)
|
p, err := newProcess(opts)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
if err := cmd.Start(); err != nil {
|
if err := s.m.Add(p); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if err := opts.cmd.Start(); err != nil {
|
||||||
close(p.done)
|
close(p.done)
|
||||||
if checkShimNotFound(err) {
|
if checkShimNotFound(err) {
|
||||||
return nil, fmt.Errorf("%s not install on system", s.name)
|
return nil, fmt.Errorf("%s not install on system", s.name)
|
||||||
|
@ -323,12 +363,11 @@ func (s *Shim) command(args ...string) *exec.Cmd {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Shim) startMonitor() {
|
func (s *Shim) startMonitor() {
|
||||||
|
go s.m.Run()
|
||||||
|
defer s.m.Close()
|
||||||
for m := range s.m.Events() {
|
for m := range s.m.Events() {
|
||||||
p := m.(*process)
|
p := m.(*process)
|
||||||
close(p.done)
|
close(p.done)
|
||||||
if err := s.m.Remove(p); err != nil {
|
|
||||||
logrus.Error(err)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue