diff --git a/executor/runcexecutor/executor_linux.go b/executor/runcexecutor/executor_linux.go index 91d6cd785cca..b01040ce9f0d 100644 --- a/executor/runcexecutor/executor_linux.go +++ b/executor/runcexecutor/executor_linux.go @@ -1,14 +1,9 @@ package runcexecutor import ( - "bufio" "context" - "fmt" "io" - "io/ioutil" "os" - "strconv" - "strings" "syscall" "time" @@ -28,10 +23,10 @@ func updateRuncFieldsForHostOS(runtime *runc.Runc) { } func (w *runcExecutor) run(ctx context.Context, id, bundle string, process executor.ProcessInfo) error { - return w.callWithIO(ctx, id, bundle, process, func(ctx context.Context, pidfile string, io runc.IO) error { + return w.callWithIO(ctx, id, bundle, process, func(ctx context.Context, started chan<- int, io runc.IO) error { _, err := w.runc.Run(ctx, id, bundle, &runc.CreateOpts{ NoPivot: w.noPivot, - PidFile: pidfile, + Started: started, IO: io, }) return err @@ -39,29 +34,22 @@ func (w *runcExecutor) run(ctx context.Context, id, bundle string, process execu } func (w *runcExecutor) exec(ctx context.Context, id, bundle string, specsProcess *specs.Process, process executor.ProcessInfo) error { - return w.callWithIO(ctx, id, bundle, process, func(ctx context.Context, pidfile string, io runc.IO) error { + return w.callWithIO(ctx, id, bundle, process, func(ctx context.Context, started chan<- int, io runc.IO) error { return w.runc.Exec(ctx, id, *specsProcess, &runc.ExecOpts{ - PidFile: pidfile, + Started: started, IO: io, }) }) } -type runcCall func(ctx context.Context, pidfile string, io runc.IO) error +type runcCall func(ctx context.Context, started chan<- int, io runc.IO) error func (w *runcExecutor) callWithIO(ctx context.Context, id, bundle string, process executor.ProcessInfo, call runcCall) error { ctx, cancel := context.WithCancel(ctx) defer cancel() - pidfile, err := ioutil.TempFile(bundle, "*.pid") - if err != nil { - return errors.Wrap(err, "failed to create pidfile") - } - defer os.Remove(pidfile.Name()) - pidfile.Close() - if !process.Meta.Tty { - return call(ctx, pidfile.Name(), &forwardIO{stdin: process.Stdin, stdout: process.Stdout, stderr: process.Stderr}) + return call(ctx, nil, &forwardIO{stdin: process.Stdin, stdout: process.Stdout, stderr: process.Stderr}) } ptm, ptsName, err := console.NewPty() @@ -117,37 +105,26 @@ func (w *runcExecutor) callWithIO(ctx context.Context, id, bundle string, proces }) } + started := make(chan int, 1) + eg.Go(func() error { - // need to poll until the pidfile has the pid written to it - pidfileCtx, timeout := context.WithTimeout(ctx, 10*time.Second) + startedCtx, timeout := context.WithTimeout(ctx, 10*time.Second) defer timeout() - var runcProcess *os.Process - for { - st, err := os.Stat(pidfile.Name()) - if err == nil && st.Size() > 0 { - pid, err := runc.ReadPidFile(pidfile.Name()) - if err != nil { - return errors.Wrapf(err, "unable to read pid file: %s", pidfile.Name()) - } - // pid will be for the process in process.Meta, not the parent runc process. - // We need to send SIGWINCH to the runc process, not the process.Meta process. - ppid, err := getppid(pid) - if err != nil { - return errors.Wrapf(err, "unable to find runc process (parent of %d)", pid) - } - runcProcess, err = os.FindProcess(ppid) - if err != nil { - return errors.Wrapf(err, "unable to find process for pid %d", ppid) - } - break + select { + case <-startedCtx.Done(): + return errors.New("runc started message never received") + case pid, ok := <-started: + if !ok { + return errors.New("runc process failed to send pid") } - select { - case <-pidfileCtx.Done(): - return errors.New("pidfile never updated") - case <-time.After(100 * time.Microsecond): + runcProcess, err = os.FindProcess(pid) + if err != nil { + return errors.Wrapf(err, "unable to find runc process for pid %d", pid) } + defer runcProcess.Release() } + for { select { case <-ctx.Done(): @@ -179,24 +156,5 @@ func (w *runcExecutor) callWithIO(ctx context.Context, id, bundle string, proces runcIO.stderr = pts } - return call(ctx, pidfile.Name(), runcIO) -} - -const PPidStatusPrefix = "PPid:\t" - -func getppid(pid int) (int, error) { - fh, err := os.Open(fmt.Sprintf("/proc/%d/status", pid)) - if err != nil { - return -1, err - } - - defer fh.Close() - scanner := bufio.NewScanner(fh) - for scanner.Scan() { - line := scanner.Text() - if strings.HasPrefix(line, PPidStatusPrefix) { - return strconv.Atoi(strings.TrimPrefix(line, PPidStatusPrefix)) - } - } - return -1, errors.Errorf("PPid line not found in /proc/%d/status", pid) + return call(ctx, started, runcIO) } diff --git a/go.mod b/go.mod index ee7bfa15ec7e..9fc21873ea3e 100644 --- a/go.mod +++ b/go.mod @@ -12,7 +12,7 @@ require ( github.com/containerd/containerd v1.4.1-0.20200903181227-d4e78200d6da github.com/containerd/continuity v0.0.0-20200710164510-efbc4488d8fe github.com/containerd/go-cni v1.0.1 - github.com/containerd/go-runc v0.0.0-20201017060547-8c4be61c2e34 + github.com/containerd/go-runc v0.0.0-20201020171139-16b287bc67d0 github.com/containerd/stargz-snapshotter v0.0.0-20200903042824-2ee75e91f8f9 github.com/containerd/typeurl v1.0.1 github.com/coreos/go-systemd/v22 v22.1.0 diff --git a/go.sum b/go.sum index 4b05c7c57bbb..c98a47237214 100644 --- a/go.sum +++ b/go.sum @@ -127,8 +127,8 @@ github.com/containerd/go-cni v1.0.1/go.mod h1:+vUpYxKvAF72G9i1WoDOiPGRtQpqsNW/ZH github.com/containerd/go-runc v0.0.0-20180907222934-5a6d9f37cfa3/go.mod h1:IV7qH3hrUgRmyYrtgEeGWJfWbgcHL9CSRruz2Vqcph0= github.com/containerd/go-runc v0.0.0-20200220073739-7016d3ce2328 h1:PRTagVMbJcCezLcHXe8UJvR1oBzp2lG3CEumeFOLOds= github.com/containerd/go-runc v0.0.0-20200220073739-7016d3ce2328/go.mod h1:PpyHrqVs8FTi9vpyHwPwiNEGaACDxT/N/pLcvMSRA9g= -github.com/containerd/go-runc v0.0.0-20201017060547-8c4be61c2e34 h1:jFRg/hwx0DPpcg23MNusAppCDJa5nndN3/RAxSblN58= -github.com/containerd/go-runc v0.0.0-20201017060547-8c4be61c2e34/go.mod h1:1CDPys/h0SMZoki7dv3bPQ1wJWnmaeZIO026WPts2xM= +github.com/containerd/go-runc v0.0.0-20201020171139-16b287bc67d0 h1:e+50zk22gvHLJKe8+d+xSMyA88PPQk/XfWuUw1BdnPA= +github.com/containerd/go-runc v0.0.0-20201020171139-16b287bc67d0/go.mod h1:cNU0ZbCgCQVZK4lgG3P+9tn9/PaJNmoDXPpoJhDR+Ok= github.com/containerd/stargz-snapshotter v0.0.0-20200903042824-2ee75e91f8f9 h1:JEcj3rNCg0Ho5t9kiOa4LV/vaNXbRQ9l2PIRzz2LWCQ= github.com/containerd/stargz-snapshotter v0.0.0-20200903042824-2ee75e91f8f9/go.mod h1:f+gZLtYcuNQWxucWyfVEQXSBoGbXNpQ76+XWVMgp+34= github.com/containerd/ttrpc v0.0.0-20190828154514-0e0f228740de/go.mod h1:PvCDdDGpgqzQIzDW1TphrGLssLDZp2GuS+X5DkEJB8o= diff --git a/vendor/github.com/containerd/go-runc/go.mod b/vendor/github.com/containerd/go-runc/go.mod index 6329c7683a4d..f69c26fd68fb 100644 --- a/vendor/github.com/containerd/go-runc/go.mod +++ b/vendor/github.com/containerd/go-runc/go.mod @@ -3,9 +3,9 @@ module github.com/containerd/go-runc go 1.13 require ( - github.com/containerd/console v0.0.0-20191206165004-02ecf6a7291e - github.com/opencontainers/runtime-spec v1.0.1 - github.com/pkg/errors v0.8.1 - github.com/sirupsen/logrus v1.6.0 - golang.org/x/sys v0.0.0-20191210023423-ac6580df4449 + github.com/containerd/console v1.0.1 + github.com/opencontainers/runtime-spec v1.0.2 + github.com/pkg/errors v0.9.1 + github.com/sirupsen/logrus v1.7.0 + golang.org/x/sys v0.0.0-20200916030750-2334cc1a136f ) diff --git a/vendor/github.com/containerd/go-runc/go.sum b/vendor/github.com/containerd/go-runc/go.sum index 47ecf5ad2191..afc9198e09ae 100644 --- a/vendor/github.com/containerd/go-runc/go.sum +++ b/vendor/github.com/containerd/go-runc/go.sum @@ -1,16 +1,17 @@ -github.com/containerd/console v0.0.0-20191206165004-02ecf6a7291e h1:GdiIYd8ZDOrT++e1NjhSD4rGt9zaJukHm4rt5F4mRQc= -github.com/containerd/console v0.0.0-20191206165004-02ecf6a7291e/go.mod h1:8Pf4gM6VEbTNRIT26AyyU7hxdQU3MvAvxVI0sc00XBE= +github.com/containerd/console v1.0.1 h1:u7SFAJyRqWcG6ogaMAx3KjSTy1e3hT9QxqX7Jco7dRc= +github.com/containerd/console v1.0.1/go.mod h1:XUsP6YE/mKtz6bxc+I8UiKKTP04qjQL4qcS3XoQ5xkw= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= -github.com/opencontainers/runtime-spec v1.0.1 h1:wY4pOY8fBdSIvs9+IDHC55thBuEulhzfSgKeC1yFvzQ= -github.com/opencontainers/runtime-spec v1.0.1/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0= -github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I= -github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/opencontainers/runtime-spec v1.0.2 h1:UfAcuLBJB9Coz72x1hgl8O5RVzTdNiaglX6v2DM6FI0= +github.com/opencontainers/runtime-spec v1.0.2/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0= +github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= +github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/sirupsen/logrus v1.6.0 h1:UBcNElsrwanuuMsnGSlYmtmgbb23qDR5dG+6X6Oo89I= -github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88= +github.com/sirupsen/logrus v1.7.0 h1:ShrD1U9pZB12TX0cVy0DtePoCH97K8EtX+mg7ZARUtM= +github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= +github.com/stretchr/testify v1.2.2 h1:bSDNvY7ZPG5RlJ8otE/7V6gMiyenm9RtJ7IUVIAoJ1w= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= -golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191210023423-ac6580df4449 h1:gSbV7h1NRL2G1xTg/owz62CST1oJBmxy4QpMMregXVQ= -golang.org/x/sys v0.0.0-20191210023423-ac6580df4449/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200916030750-2334cc1a136f h1:6Sc1XOXTulBN6imkqo6XoAXDEzoQ4/ro6xy7Vn8+rOM= +golang.org/x/sys v0.0.0-20200916030750-2334cc1a136f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= diff --git a/vendor/github.com/containerd/go-runc/runc.go b/vendor/github.com/containerd/go-runc/runc.go index 2a515d2a2183..f5f03ae95eb4 100644 --- a/vendor/github.com/containerd/go-runc/runc.go +++ b/vendor/github.com/containerd/go-runc/runc.go @@ -56,7 +56,7 @@ const ( // List returns all containers created inside the provided runc root directory func (r *Runc) List(context context.Context) ([]*Container, error) { - data, err := cmdOutput(r.command(context, "list", "--format=json"), false) + data, err := cmdOutput(r.command(context, "list", "--format=json"), false, nil) defer putBuf(data) if err != nil { return nil, err @@ -70,7 +70,7 @@ func (r *Runc) List(context context.Context) ([]*Container, error) { // State returns the state for the container provided by id func (r *Runc) State(context context.Context, id string) (*Container, error) { - data, err := cmdOutput(r.command(context, "state", id), true) + data, err := cmdOutput(r.command(context, "state", id), true, nil) defer putBuf(data) if err != nil { return nil, fmt.Errorf("%s: %s", err, data.String()) @@ -95,6 +95,7 @@ type CreateOpts struct { NoPivot bool NoNewKeyring bool ExtraFiles []*os.File + Started chan<- int } func (o *CreateOpts) args() (out []string, err error) { @@ -140,7 +141,7 @@ func (r *Runc) Create(context context.Context, id, bundle string, opts *CreateOp cmd.ExtraFiles = opts.ExtraFiles if cmd.Stdout == nil && cmd.Stderr == nil { - data, err := cmdOutput(cmd, true) + data, err := cmdOutput(cmd, true, nil) defer putBuf(data) if err != nil { return fmt.Errorf("%s: %s", err, data.String()) @@ -175,6 +176,7 @@ type ExecOpts struct { PidFile string ConsoleSocket ConsoleSocket Detach bool + Started chan<- int } func (o *ExecOpts) args() (out []string, err error) { @@ -197,6 +199,9 @@ func (o *ExecOpts) args() (out []string, err error) { // Exec executes an additional process inside the container based on a full // OCI Process specification func (r *Runc) Exec(context context.Context, id string, spec specs.Process, opts *ExecOpts) error { + if opts.Started != nil { + defer close(opts.Started) + } f, err := ioutil.TempFile(os.Getenv("XDG_RUNTIME_DIR"), "runc-process") if err != nil { return err @@ -220,7 +225,7 @@ func (r *Runc) Exec(context context.Context, id string, spec specs.Process, opts opts.Set(cmd) } if cmd.Stdout == nil && cmd.Stderr == nil { - data, err := cmdOutput(cmd, true) + data, err := cmdOutput(cmd, true, opts.Started) defer putBuf(data) if err != nil { return fmt.Errorf("%w: %s", err, data.String()) @@ -231,6 +236,9 @@ func (r *Runc) Exec(context context.Context, id string, spec specs.Process, opts if err != nil { return err } + if opts.Started != nil { + opts.Started <- cmd.Process.Pid + } if opts != nil && opts.IO != nil { if c, ok := opts.IO.(StartCloser); ok { if err := c.CloseAfterStart(); err != nil { @@ -248,6 +256,9 @@ func (r *Runc) Exec(context context.Context, id string, spec specs.Process, opts // Run runs the create, start, delete lifecycle of the container // and returns its exit status after it has exited func (r *Runc) Run(context context.Context, id, bundle string, opts *CreateOpts) (int, error) { + if opts.Started != nil { + defer close(opts.Started) + } args := []string{"run", "--bundle", bundle} if opts != nil { oargs, err := opts.args() @@ -264,6 +275,9 @@ func (r *Runc) Run(context context.Context, id, bundle string, opts *CreateOpts) if err != nil { return -1, err } + if opts.Started != nil { + opts.Started <- cmd.Process.Pid + } status, err := Monitor.Wait(cmd, ec) if err == nil && status != 0 { err = fmt.Errorf("%s did not terminate successfully: %w", cmd.Args[0], &ExitError{status}) @@ -387,7 +401,7 @@ func (r *Runc) Resume(context context.Context, id string) error { // Ps lists all the processes inside the container returning their pids func (r *Runc) Ps(context context.Context, id string) ([]int, error) { - data, err := cmdOutput(r.command(context, "ps", "--format", "json", id), true) + data, err := cmdOutput(r.command(context, "ps", "--format", "json", id), true, nil) defer putBuf(data) if err != nil { return nil, fmt.Errorf("%s: %s", err, data.String()) @@ -401,7 +415,7 @@ func (r *Runc) Ps(context context.Context, id string) ([]int, error) { // Top lists all the processes inside the container returning the full ps data func (r *Runc) Top(context context.Context, id string, psOptions string) (*TopResults, error) { - data, err := cmdOutput(r.command(context, "ps", "--format", "table", id, psOptions), true) + data, err := cmdOutput(r.command(context, "ps", "--format", "table", id, psOptions), true, nil) defer putBuf(data) if err != nil { return nil, fmt.Errorf("%s: %s", err, data.String()) @@ -613,7 +627,7 @@ type Version struct { // Version returns the runc and runtime-spec versions func (r *Runc) Version(context context.Context) (Version, error) { - data, err := cmdOutput(r.command(context, "--version"), false) + data, err := cmdOutput(r.command(context, "--version"), false, nil) defer putBuf(data) if err != nil { return Version{}, err @@ -685,7 +699,7 @@ func (r *Runc) runOrError(cmd *exec.Cmd) error { } return err } - data, err := cmdOutput(cmd, true) + data, err := cmdOutput(cmd, true, nil) defer putBuf(data) if err != nil { return fmt.Errorf("%s: %s", err, data.String()) @@ -695,7 +709,7 @@ func (r *Runc) runOrError(cmd *exec.Cmd) error { // callers of cmdOutput are expected to call putBuf on the returned Buffer // to ensure it is released back to the shared pool after use. -func cmdOutput(cmd *exec.Cmd, combined bool) (*bytes.Buffer, error) { +func cmdOutput(cmd *exec.Cmd, combined bool, started chan<- int) (*bytes.Buffer, error) { b := getBuf() cmd.Stdout = b @@ -706,6 +720,9 @@ func cmdOutput(cmd *exec.Cmd, combined bool) (*bytes.Buffer, error) { if err != nil { return nil, err } + if started != nil { + started <- cmd.Process.Pid + } status, err := Monitor.Wait(cmd, ec) if err == nil && status != 0 { diff --git a/vendor/modules.txt b/vendor/modules.txt index f12b736cda84..8b0c3ec5c742 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -117,7 +117,7 @@ github.com/containerd/continuity/sysx github.com/containerd/fifo # github.com/containerd/go-cni v1.0.1 github.com/containerd/go-cni -# github.com/containerd/go-runc v0.0.0-20201017060547-8c4be61c2e34 +# github.com/containerd/go-runc v0.0.0-20201020171139-16b287bc67d0 github.com/containerd/go-runc # github.com/containerd/stargz-snapshotter v0.0.0-20200903042824-2ee75e91f8f9 github.com/containerd/stargz-snapshotter/cache