update go-runc to use runc.ExitError for container exec status
Signed-off-by: Cory Bennett <cbennett@netflix.com>v0.8
parent
5eaecb905c
commit
b464f1e315
|
@ -271,9 +271,8 @@ func testClientGatewayContainerCancelOnRelease(t *testing.T, sb integration.Sand
|
|||
// We are mimicing: `echo testing | cat | cat > /tmp/foo && cat /tmp/foo`
|
||||
func testClientGatewayContainerExecPipe(t *testing.T, sb integration.Sandbox) {
|
||||
if sb.Rootless() {
|
||||
// TODO fix this
|
||||
// We get `panic: cannot statfs cgroup root` from runc when when running
|
||||
// this test with runc-rootless, no idea why.
|
||||
// TODO remove when https://github.com/opencontainers/runc/pull/2634
|
||||
// is merged and released
|
||||
t.Skip("Skipping oci-rootless for cgroup error")
|
||||
}
|
||||
requiresLinux(t)
|
||||
|
@ -467,9 +466,8 @@ func testClientGatewayContainerPID1Fail(t *testing.T, sb integration.Sandbox) {
|
|||
// via `Exec` are shutdown when the primary pid1 process exits
|
||||
func testClientGatewayContainerPID1Exit(t *testing.T, sb integration.Sandbox) {
|
||||
if sb.Rootless() {
|
||||
// TODO fix this
|
||||
// We get `panic: cannot statfs cgroup root` when running this test
|
||||
// with runc-rootless
|
||||
// TODO remove when https://github.com/opencontainers/runc/pull/2634
|
||||
// is merged and released
|
||||
t.Skip("Skipping runc-rootless for cgroup error")
|
||||
}
|
||||
requiresLinux(t)
|
||||
|
@ -535,10 +533,9 @@ func testClientGatewayContainerPID1Exit(t *testing.T, sb integration.Sandbox) {
|
|||
}
|
||||
|
||||
_, err = c.Build(ctx, SolveOpt{}, product, b, nil)
|
||||
// pid2 should error with `buildkit-runc did not terminate successfully` on runc or
|
||||
// `exit code: 137` (ie sigkill) on containerd
|
||||
require.Error(t, err)
|
||||
require.Regexp(t, "exit code: 137|buildkit-runc did not terminate successfully", err.Error())
|
||||
// `exit code: 137` (ie sigkill)
|
||||
require.Regexp(t, "exit code: 137", err.Error())
|
||||
|
||||
checkAllReleasable(t, c, sb, true)
|
||||
}
|
||||
|
@ -547,9 +544,8 @@ func testClientGatewayContainerPID1Exit(t *testing.T, sb integration.Sandbox) {
|
|||
// llb.States
|
||||
func testClientGatewayContainerMounts(t *testing.T, sb integration.Sandbox) {
|
||||
if sb.Rootless() {
|
||||
// TODO fix this
|
||||
// We get `panic: cannot statfs cgroup root` when running this test
|
||||
// with runc-rootless
|
||||
// TODO remove when https://github.com/opencontainers/runc/pull/2634
|
||||
// is merged and released
|
||||
t.Skip("Skipping runc-rootless for cgroup error")
|
||||
}
|
||||
requiresLinux(t)
|
||||
|
@ -864,9 +860,8 @@ func (p *testPrompt) wait(msg string) string {
|
|||
// executor.Exec (secondary process)
|
||||
func testClientGatewayContainerExecTty(t *testing.T, sb integration.Sandbox) {
|
||||
if sb.Rootless() {
|
||||
// TODO fix this
|
||||
// We get `panic: cannot statfs cgroup root` when running this test
|
||||
// with runc-rootless
|
||||
// TODO remove when https://github.com/opencontainers/runc/pull/2634
|
||||
// is merged and released
|
||||
t.Skip("Skipping runc-rootless for cgroup error")
|
||||
}
|
||||
requiresLinux(t)
|
||||
|
@ -937,12 +932,17 @@ func testClientGatewayContainerExecTty(t *testing.T, sb integration.Sandbox) {
|
|||
prompt.SendExpect("ttysize", "100 60")
|
||||
prompt.SendExit(99)
|
||||
|
||||
return &client.Result{}, pid2.Wait()
|
||||
err = pid2.Wait()
|
||||
var exitError *errdefs.ExitError
|
||||
require.True(t, errors.As(err, &exitError))
|
||||
require.Equal(t, uint32(99), exitError.ExitCode)
|
||||
|
||||
return &client.Result{}, err
|
||||
}
|
||||
|
||||
_, err = c.Build(ctx, SolveOpt{}, product, b, nil)
|
||||
require.Error(t, err)
|
||||
require.Regexp(t, "exit code: 99|runc did not terminate successfully", err.Error())
|
||||
require.Regexp(t, "exit code: 99", err.Error())
|
||||
|
||||
inputW.Close()
|
||||
inputR.Close()
|
||||
|
|
|
@ -12,6 +12,7 @@ import (
|
|||
"syscall"
|
||||
"time"
|
||||
|
||||
"github.com/containerd/containerd"
|
||||
"github.com/containerd/containerd/mount"
|
||||
containerdoci "github.com/containerd/containerd/oci"
|
||||
"github.com/containerd/continuity/fs"
|
||||
|
@ -103,15 +104,16 @@ func New(opt Opt, networkProviders map[pb.NetMode]network.Provider) (executor.Ex
|
|||
os.RemoveAll(filepath.Join(root, "resolv.conf"))
|
||||
|
||||
runtime := &runc.Runc{
|
||||
Command: cmd,
|
||||
Log: filepath.Join(root, "runc-log.json"),
|
||||
LogFormat: runc.JSON,
|
||||
PdeathSignal: syscall.SIGKILL, // this can still leak the process
|
||||
Setpgid: true,
|
||||
Command: cmd,
|
||||
Log: filepath.Join(root, "runc-log.json"),
|
||||
LogFormat: runc.JSON,
|
||||
Setpgid: true,
|
||||
// we don't execute runc with --rootless=(true|false) explicitly,
|
||||
// so as to support non-runc runtimes
|
||||
}
|
||||
|
||||
updateRuncFieldsForHostOS(runtime)
|
||||
|
||||
w := &runcExecutor{
|
||||
runc: runtime,
|
||||
root: root,
|
||||
|
@ -324,21 +326,29 @@ func (w *runcExecutor) Run(ctx context.Context, id string, root cache.Mountable,
|
|||
})
|
||||
}
|
||||
|
||||
status, err := w.run(runCtx, id, bundle, process)
|
||||
err = w.run(runCtx, id, bundle, process)
|
||||
close(ended)
|
||||
return exitError(ctx, err)
|
||||
}
|
||||
|
||||
if status != 0 || err != nil {
|
||||
func exitError(ctx context.Context, err error) error {
|
||||
if err != nil {
|
||||
exitErr := &errdefs.ExitError{
|
||||
ExitCode: uint32(status),
|
||||
ExitCode: containerd.UnknownExitStatus,
|
||||
Err: err,
|
||||
}
|
||||
err = exitErr
|
||||
var runcExitError *runc.ExitError
|
||||
if errors.As(err, &runcExitError) {
|
||||
exitErr = &errdefs.ExitError{
|
||||
ExitCode: uint32(runcExitError.Status),
|
||||
}
|
||||
}
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
exitErr.Err = errors.Wrapf(ctx.Err(), exitErr.Error())
|
||||
return exitErr
|
||||
default:
|
||||
return stack.Enable(err)
|
||||
return stack.Enable(exitErr)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -408,14 +418,8 @@ func (w *runcExecutor) Exec(ctx context.Context, id string, process executor.Pro
|
|||
spec.Process.Env = process.Meta.Env
|
||||
}
|
||||
|
||||
status, err := w.exec(ctx, id, state.Bundle, spec.Process, process)
|
||||
if status == 0 && err == nil {
|
||||
return nil
|
||||
}
|
||||
return &errdefs.ExitError{
|
||||
ExitCode: uint32(status),
|
||||
Err: err,
|
||||
}
|
||||
err = w.exec(ctx, id, state.Bundle, spec.Process, process)
|
||||
return exitError(ctx, err)
|
||||
}
|
||||
|
||||
type forwardIO struct {
|
||||
|
|
|
@ -4,9 +4,7 @@ package runcexecutor
|
|||
|
||||
import (
|
||||
"context"
|
||||
"os/exec"
|
||||
|
||||
"github.com/containerd/containerd"
|
||||
runc "github.com/containerd/go-runc"
|
||||
"github.com/moby/buildkit/executor"
|
||||
"github.com/opencontainers/runtime-spec/specs-go"
|
||||
|
@ -15,30 +13,24 @@ import (
|
|||
|
||||
var unsupportedConsoleError = errors.New("tty for runc is only supported on linux")
|
||||
|
||||
func (w *runcExecutor) run(ctx context.Context, id, bundle string, process executor.ProcessInfo) (int, error) {
|
||||
func updateRuncFieldsForHostOS(runtime *runc.Runc) {}
|
||||
|
||||
func (w *runcExecutor) run(ctx context.Context, id, bundle string, process executor.ProcessInfo) error {
|
||||
if process.Meta.Tty {
|
||||
return 0, unsupportedConsoleError
|
||||
return unsupportedConsoleError
|
||||
}
|
||||
return w.runc.Run(ctx, id, bundle, &runc.CreateOpts{
|
||||
_, err := w.runc.Run(ctx, id, bundle, &runc.CreateOpts{
|
||||
IO: &forwardIO{stdin: process.Stdin, stdout: process.Stdout, stderr: process.Stderr},
|
||||
NoPivot: w.noPivot,
|
||||
})
|
||||
return err
|
||||
}
|
||||
|
||||
func (w *runcExecutor) exec(ctx context.Context, id, bundle string, specsProcess *specs.Process, process executor.ProcessInfo) (int, error) {
|
||||
func (w *runcExecutor) exec(ctx context.Context, id, bundle string, specsProcess *specs.Process, process executor.ProcessInfo) error {
|
||||
if process.Meta.Tty {
|
||||
return 0, unsupportedConsoleError
|
||||
return unsupportedConsoleError
|
||||
}
|
||||
err := w.runc.Exec(ctx, id, *specsProcess, &runc.ExecOpts{
|
||||
return w.runc.Exec(ctx, id, *specsProcess, &runc.ExecOpts{
|
||||
IO: &forwardIO{stdin: process.Stdin, stdout: process.Stdout, stderr: process.Stderr},
|
||||
})
|
||||
|
||||
var exitError *exec.ExitError
|
||||
if errors.As(err, &exitError) {
|
||||
return exitError.ExitCode(), err
|
||||
}
|
||||
if err != nil {
|
||||
return containerd.UnknownExitStatus, err
|
||||
}
|
||||
return 0, nil
|
||||
}
|
||||
|
|
|
@ -7,14 +7,12 @@ import (
|
|||
"io"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"os/exec"
|
||||
"strconv"
|
||||
"strings"
|
||||
"syscall"
|
||||
"time"
|
||||
|
||||
"github.com/containerd/console"
|
||||
"github.com/containerd/containerd"
|
||||
runc "github.com/containerd/go-runc"
|
||||
"github.com/docker/docker/pkg/signal"
|
||||
"github.com/moby/buildkit/executor"
|
||||
|
@ -24,42 +22,40 @@ import (
|
|||
"golang.org/x/sync/errgroup"
|
||||
)
|
||||
|
||||
func (w *runcExecutor) run(ctx context.Context, id, bundle string, process executor.ProcessInfo) (int, error) {
|
||||
return w.callWithIO(ctx, id, bundle, process, func(ctx context.Context, pidfile string, io runc.IO) (int, error) {
|
||||
return w.runc.Run(ctx, id, bundle, &runc.CreateOpts{
|
||||
func updateRuncFieldsForHostOS(runtime *runc.Runc) {
|
||||
// PdeathSignal only supported on unix platforms
|
||||
runtime.PdeathSignal = syscall.SIGKILL // this can still leak the process
|
||||
}
|
||||
|
||||
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 {
|
||||
_, err := w.runc.Run(ctx, id, bundle, &runc.CreateOpts{
|
||||
NoPivot: w.noPivot,
|
||||
PidFile: pidfile,
|
||||
IO: io,
|
||||
})
|
||||
return err
|
||||
})
|
||||
}
|
||||
|
||||
func (w *runcExecutor) exec(ctx context.Context, id, bundle string, specsProcess *specs.Process, process executor.ProcessInfo) (int, error) {
|
||||
return w.callWithIO(ctx, id, bundle, process, func(ctx context.Context, pidfile string, io runc.IO) (int, error) {
|
||||
err := w.runc.Exec(ctx, id, *specsProcess, &runc.ExecOpts{
|
||||
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.runc.Exec(ctx, id, *specsProcess, &runc.ExecOpts{
|
||||
PidFile: pidfile,
|
||||
IO: io,
|
||||
})
|
||||
var exitError *exec.ExitError
|
||||
if errors.As(err, &exitError) {
|
||||
return exitError.ExitCode(), err
|
||||
}
|
||||
if err != nil {
|
||||
return containerd.UnknownExitStatus, err
|
||||
}
|
||||
return 0, nil
|
||||
})
|
||||
}
|
||||
|
||||
type runcCall func(ctx context.Context, pidfile string, io runc.IO) (int, error)
|
||||
type runcCall func(ctx context.Context, pidfile string, io runc.IO) error
|
||||
|
||||
func (w *runcExecutor) callWithIO(ctx context.Context, id, bundle string, process executor.ProcessInfo, call runcCall) (int, 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 containerd.UnknownExitStatus, errors.Wrap(err, "failed to create pidfile")
|
||||
return errors.Wrap(err, "failed to create pidfile")
|
||||
}
|
||||
defer os.Remove(pidfile.Name())
|
||||
pidfile.Close()
|
||||
|
@ -70,13 +66,13 @@ func (w *runcExecutor) callWithIO(ctx context.Context, id, bundle string, proces
|
|||
|
||||
ptm, ptsName, err := console.NewPty()
|
||||
if err != nil {
|
||||
return containerd.UnknownExitStatus, err
|
||||
return err
|
||||
}
|
||||
|
||||
pts, err := os.OpenFile(ptsName, os.O_RDWR|syscall.O_NOCTTY, 0)
|
||||
if err != nil {
|
||||
ptm.Close()
|
||||
return containerd.UnknownExitStatus, err
|
||||
return err
|
||||
}
|
||||
|
||||
eg, ctx := errgroup.WithContext(ctx)
|
||||
|
|
2
go.mod
2
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-20200220073739-7016d3ce2328
|
||||
github.com/containerd/go-runc v0.0.0-20201017060547-8c4be61c2e34
|
||||
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
|
||||
|
|
2
go.sum
2
go.sum
|
@ -127,6 +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/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=
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
language: go
|
||||
go:
|
||||
- 1.12.x
|
||||
- 1.13.x
|
||||
- 1.14.x
|
||||
- 1.15.x
|
||||
|
||||
install:
|
||||
- go get -t ./...
|
||||
|
|
|
@ -6,5 +6,6 @@ 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
|
||||
)
|
||||
|
|
|
@ -1,9 +1,16 @@
|
|||
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/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/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/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=
|
||||
|
|
|
@ -20,7 +20,9 @@ package runc
|
|||
|
||||
import (
|
||||
"github.com/pkg/errors"
|
||||
"github.com/sirupsen/logrus"
|
||||
"golang.org/x/sys/unix"
|
||||
"runtime"
|
||||
)
|
||||
|
||||
// NewPipeIO creates pipe pairs to be used with runc
|
||||
|
@ -47,7 +49,13 @@ func NewPipeIO(uid, gid int, opts ...IOOpt) (i IO, err error) {
|
|||
}
|
||||
pipes = append(pipes, stdin)
|
||||
if err = unix.Fchown(int(stdin.r.Fd()), uid, gid); err != nil {
|
||||
return nil, errors.Wrap(err, "failed to chown stdin")
|
||||
// TODO: revert with proper darwin solution, skipping for now
|
||||
// as darwin chown is returning EINVAL on anonymous pipe
|
||||
if runtime.GOOS == "darwin" {
|
||||
logrus.WithError(err).Debug("failed to chown stdin, ignored")
|
||||
} else {
|
||||
return nil, errors.Wrap(err, "failed to chown stdin")
|
||||
}
|
||||
}
|
||||
}
|
||||
if option.OpenStdout {
|
||||
|
@ -56,7 +64,13 @@ func NewPipeIO(uid, gid int, opts ...IOOpt) (i IO, err error) {
|
|||
}
|
||||
pipes = append(pipes, stdout)
|
||||
if err = unix.Fchown(int(stdout.w.Fd()), uid, gid); err != nil {
|
||||
return nil, errors.Wrap(err, "failed to chown stdout")
|
||||
// TODO: revert with proper darwin solution, skipping for now
|
||||
// as darwin chown is returning EINVAL on anonymous pipe
|
||||
if runtime.GOOS == "darwin" {
|
||||
logrus.WithError(err).Debug("failed to chown stdout, ignored")
|
||||
} else {
|
||||
return nil, errors.Wrap(err, "failed to chown stdout")
|
||||
}
|
||||
}
|
||||
}
|
||||
if option.OpenStderr {
|
||||
|
@ -65,7 +79,13 @@ func NewPipeIO(uid, gid int, opts ...IOOpt) (i IO, err error) {
|
|||
}
|
||||
pipes = append(pipes, stderr)
|
||||
if err = unix.Fchown(int(stderr.w.Fd()), uid, gid); err != nil {
|
||||
return nil, errors.Wrap(err, "failed to chown stderr")
|
||||
// TODO: revert with proper darwin solution, skipping for now
|
||||
// as darwin chown is returning EINVAL on anonymous pipe
|
||||
if runtime.GOOS == "darwin" {
|
||||
logrus.WithError(err).Debug("failed to chown stderr, ignored")
|
||||
} else {
|
||||
return nil, errors.Wrap(err, "failed to chown stderr")
|
||||
}
|
||||
}
|
||||
}
|
||||
return &pipeIO{
|
||||
|
|
|
@ -29,7 +29,6 @@ import (
|
|||
"path/filepath"
|
||||
"strconv"
|
||||
"strings"
|
||||
"syscall"
|
||||
"time"
|
||||
|
||||
specs "github.com/opencontainers/runtime-spec/specs-go"
|
||||
|
@ -55,21 +54,6 @@ const (
|
|||
DefaultCommand = "runc"
|
||||
)
|
||||
|
||||
// Runc is the client to the runc cli
|
||||
type Runc struct {
|
||||
//If command is empty, DefaultCommand is used
|
||||
Command string
|
||||
Root string
|
||||
Debug bool
|
||||
Log string
|
||||
LogFormat Format
|
||||
PdeathSignal syscall.Signal
|
||||
Setpgid bool
|
||||
Criu string
|
||||
SystemdCgroup bool
|
||||
Rootless *bool // nil stands for "auto"
|
||||
}
|
||||
|
||||
// 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)
|
||||
|
@ -176,7 +160,7 @@ func (r *Runc) Create(context context.Context, id, bundle string, opts *CreateOp
|
|||
}
|
||||
status, err := Monitor.Wait(cmd, ec)
|
||||
if err == nil && status != 0 {
|
||||
err = fmt.Errorf("%s did not terminate successfully", cmd.Args[0])
|
||||
err = fmt.Errorf("%s did not terminate successfully: %w", cmd.Args[0], &ExitError{status})
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
@ -210,7 +194,7 @@ func (o *ExecOpts) args() (out []string, err error) {
|
|||
return out, nil
|
||||
}
|
||||
|
||||
// Exec executres and additional process inside the container based on a full
|
||||
// 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 {
|
||||
f, err := ioutil.TempFile(os.Getenv("XDG_RUNTIME_DIR"), "runc-process")
|
||||
|
@ -239,7 +223,7 @@ func (r *Runc) Exec(context context.Context, id string, spec specs.Process, opts
|
|||
data, err := cmdOutput(cmd, true)
|
||||
defer putBuf(data)
|
||||
if err != nil {
|
||||
return fmt.Errorf("%s: %s", err, data.String())
|
||||
return fmt.Errorf("%w: %s", err, data.String())
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
@ -256,7 +240,7 @@ func (r *Runc) Exec(context context.Context, id string, spec specs.Process, opts
|
|||
}
|
||||
status, err := Monitor.Wait(cmd, ec)
|
||||
if err == nil && status != 0 {
|
||||
err = fmt.Errorf("%s did not terminate successfully", cmd.Args[0])
|
||||
err = fmt.Errorf("%s did not terminate successfully: %w", cmd.Args[0], &ExitError{status})
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
@ -282,7 +266,7 @@ func (r *Runc) Run(context context.Context, id, bundle string, opts *CreateOpts)
|
|||
}
|
||||
status, err := Monitor.Wait(cmd, ec)
|
||||
if err == nil && status != 0 {
|
||||
err = fmt.Errorf("%s did not terminate successfully", cmd.Args[0])
|
||||
err = fmt.Errorf("%s did not terminate successfully: %w", cmd.Args[0], &ExitError{status})
|
||||
}
|
||||
return status, err
|
||||
}
|
||||
|
@ -452,6 +436,10 @@ type CheckpointOpts struct {
|
|||
// EmptyNamespaces creates a namespace for the container but does not save its properties
|
||||
// Provide the namespaces you wish to be checkpointed without their settings on restore
|
||||
EmptyNamespaces []string
|
||||
// LazyPages uses userfaultfd to lazily restore memory pages
|
||||
LazyPages bool
|
||||
// StatusFile is the file criu writes \0 to once lazy-pages is ready
|
||||
StatusFile *os.File
|
||||
}
|
||||
|
||||
type CgroupMode string
|
||||
|
@ -493,6 +481,9 @@ func (o *CheckpointOpts) args() (out []string) {
|
|||
for _, ns := range o.EmptyNamespaces {
|
||||
out = append(out, "--empty-ns", ns)
|
||||
}
|
||||
if o.LazyPages {
|
||||
out = append(out, "--lazy-pages")
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
|
@ -511,13 +502,23 @@ func PreDump(args []string) []string {
|
|||
// Checkpoint allows you to checkpoint a container using criu
|
||||
func (r *Runc) Checkpoint(context context.Context, id string, opts *CheckpointOpts, actions ...CheckpointAction) error {
|
||||
args := []string{"checkpoint"}
|
||||
extraFiles := []*os.File{}
|
||||
if opts != nil {
|
||||
args = append(args, opts.args()...)
|
||||
if opts.StatusFile != nil {
|
||||
// pass the status file to the child process
|
||||
extraFiles = []*os.File{opts.StatusFile}
|
||||
// set status-fd to 3 as this will be the file descriptor
|
||||
// of the first file passed with cmd.ExtraFiles
|
||||
args = append(args, "--status-fd", "3")
|
||||
}
|
||||
}
|
||||
for _, a := range actions {
|
||||
args = a(args)
|
||||
}
|
||||
return r.runOrError(r.command(context, append(args, id)...))
|
||||
cmd := r.command(context, append(args, id)...)
|
||||
cmd.ExtraFiles = extraFiles
|
||||
return r.runOrError(cmd)
|
||||
}
|
||||
|
||||
type RestoreOpts struct {
|
||||
|
@ -583,7 +584,7 @@ func (r *Runc) Restore(context context.Context, id, bundle string, opts *Restore
|
|||
}
|
||||
status, err := Monitor.Wait(cmd, ec)
|
||||
if err == nil && status != 0 {
|
||||
err = fmt.Errorf("%s did not terminate successfully", cmd.Args[0])
|
||||
err = fmt.Errorf("%s did not terminate successfully: %w", cmd.Args[0], &ExitError{status})
|
||||
}
|
||||
return status, err
|
||||
}
|
||||
|
@ -680,7 +681,7 @@ func (r *Runc) runOrError(cmd *exec.Cmd) error {
|
|||
}
|
||||
status, err := Monitor.Wait(cmd, ec)
|
||||
if err == nil && status != 0 {
|
||||
err = fmt.Errorf("%s did not terminate successfully", cmd.Args[0])
|
||||
err = fmt.Errorf("%s did not terminate successfully: %w", cmd.Args[0], &ExitError{status})
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
@ -708,8 +709,16 @@ func cmdOutput(cmd *exec.Cmd, combined bool) (*bytes.Buffer, error) {
|
|||
|
||||
status, err := Monitor.Wait(cmd, ec)
|
||||
if err == nil && status != 0 {
|
||||
err = fmt.Errorf("%s did not terminate successfully", cmd.Args[0])
|
||||
err = fmt.Errorf("%s did not terminate successfully: %w", cmd.Args[0], &ExitError{status})
|
||||
}
|
||||
|
||||
return b, err
|
||||
}
|
||||
|
||||
type ExitError struct {
|
||||
Status int
|
||||
}
|
||||
|
||||
func (e *ExitError) Error() string {
|
||||
return fmt.Sprintf("exit status %d", e.Status)
|
||||
}
|
||||
|
|
|
@ -0,0 +1,38 @@
|
|||
//+build !windows
|
||||
|
||||
/*
|
||||
Copyright The containerd Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package runc
|
||||
|
||||
import (
|
||||
"golang.org/x/sys/unix"
|
||||
)
|
||||
|
||||
// Runc is the client to the runc cli
|
||||
type Runc struct {
|
||||
//If command is empty, DefaultCommand is used
|
||||
Command string
|
||||
Root string
|
||||
Debug bool
|
||||
Log string
|
||||
LogFormat Format
|
||||
PdeathSignal unix.Signal
|
||||
Setpgid bool
|
||||
Criu string
|
||||
SystemdCgroup bool
|
||||
Rootless *bool // nil stands for "auto"
|
||||
}
|
|
@ -0,0 +1,31 @@
|
|||
/*
|
||||
Copyright The containerd Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package runc
|
||||
|
||||
// Runc is the client to the runc cli
|
||||
type Runc struct {
|
||||
//If command is empty, DefaultCommand is used
|
||||
Command string
|
||||
Root string
|
||||
Debug bool
|
||||
Log string
|
||||
LogFormat Format
|
||||
Setpgid bool
|
||||
Criu string
|
||||
SystemdCgroup bool
|
||||
Rootless *bool // nil stands for "auto"
|
||||
}
|
|
@ -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-20200220073739-7016d3ce2328
|
||||
# github.com/containerd/go-runc v0.0.0-20201017060547-8c4be61c2e34
|
||||
github.com/containerd/go-runc
|
||||
# github.com/containerd/stargz-snapshotter v0.0.0-20200903042824-2ee75e91f8f9
|
||||
github.com/containerd/stargz-snapshotter/cache
|
||||
|
|
Loading…
Reference in New Issue