vendor: cadvisor v0.39.0
Main upgrades: - github.com/opencontainers/runc v1.0.0-rc93 - github.com/containerd/containerd v1.4.4 - github.com/docker/docker v20.10.2 - github.com/mrunalp/fileutils v0.5.0 - github.com/opencontainers/selinux v1.8.0 - github.com/cilium/ebpf v0.2.0
This commit is contained in:
133
vendor/github.com/opencontainers/runc/libcontainer/container_linux.go
generated
vendored
133
vendor/github.com/opencontainers/runc/libcontainer/container_linux.go
generated
vendored
@@ -14,6 +14,7 @@ import (
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"reflect"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
@@ -363,24 +364,10 @@ func (c *linuxContainer) start(process *Process) error {
|
||||
}
|
||||
parent.forwardChildLogs()
|
||||
if err := parent.start(); err != nil {
|
||||
// terminate the process to ensure that it properly is reaped.
|
||||
if err := ignoreTerminateErrors(parent.terminate()); err != nil {
|
||||
logrus.Warn(err)
|
||||
}
|
||||
return newSystemErrorWithCause(err, "starting container process")
|
||||
}
|
||||
// generate a timestamp indicating when the container was started
|
||||
c.created = time.Now().UTC()
|
||||
if process.Init {
|
||||
c.state = &createdState{
|
||||
c: c,
|
||||
}
|
||||
state, err := c.updateState(parent)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
c.initProcessStartTime = state.InitProcessStartTime
|
||||
|
||||
if process.Init {
|
||||
if c.config.Hooks != nil {
|
||||
s, err := c.currentOCIState()
|
||||
if err != nil {
|
||||
@@ -463,7 +450,7 @@ func (c *linuxContainer) includeExecFifo(cmd *exec.Cmd) error {
|
||||
|
||||
cmd.ExtraFiles = append(cmd.ExtraFiles, os.NewFile(uintptr(fifoFd), fifoName))
|
||||
cmd.Env = append(cmd.Env,
|
||||
fmt.Sprintf("_LIBCONTAINER_FIFOFD=%d", stdioFdCount+len(cmd.ExtraFiles)-1))
|
||||
"_LIBCONTAINER_FIFOFD="+strconv.Itoa(stdioFdCount+len(cmd.ExtraFiles)-1))
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -506,24 +493,24 @@ func (c *linuxContainer) commandTemplate(p *Process, childInitPipe *os.File, chi
|
||||
if cmd.SysProcAttr == nil {
|
||||
cmd.SysProcAttr = &unix.SysProcAttr{}
|
||||
}
|
||||
cmd.Env = append(cmd.Env, fmt.Sprintf("GOMAXPROCS=%s", os.Getenv("GOMAXPROCS")))
|
||||
cmd.Env = append(cmd.Env, "GOMAXPROCS="+os.Getenv("GOMAXPROCS"))
|
||||
cmd.ExtraFiles = append(cmd.ExtraFiles, p.ExtraFiles...)
|
||||
if p.ConsoleSocket != nil {
|
||||
cmd.ExtraFiles = append(cmd.ExtraFiles, p.ConsoleSocket)
|
||||
cmd.Env = append(cmd.Env,
|
||||
fmt.Sprintf("_LIBCONTAINER_CONSOLE=%d", stdioFdCount+len(cmd.ExtraFiles)-1),
|
||||
"_LIBCONTAINER_CONSOLE="+strconv.Itoa(stdioFdCount+len(cmd.ExtraFiles)-1),
|
||||
)
|
||||
}
|
||||
cmd.ExtraFiles = append(cmd.ExtraFiles, childInitPipe)
|
||||
cmd.Env = append(cmd.Env,
|
||||
fmt.Sprintf("_LIBCONTAINER_INITPIPE=%d", stdioFdCount+len(cmd.ExtraFiles)-1),
|
||||
fmt.Sprintf("_LIBCONTAINER_STATEDIR=%s", c.root),
|
||||
"_LIBCONTAINER_INITPIPE="+strconv.Itoa(stdioFdCount+len(cmd.ExtraFiles)-1),
|
||||
"_LIBCONTAINER_STATEDIR="+c.root,
|
||||
)
|
||||
|
||||
cmd.ExtraFiles = append(cmd.ExtraFiles, childLogPipe)
|
||||
cmd.Env = append(cmd.Env,
|
||||
fmt.Sprintf("_LIBCONTAINER_LOGPIPE=%d", stdioFdCount+len(cmd.ExtraFiles)-1),
|
||||
fmt.Sprintf("_LIBCONTAINER_LOGLEVEL=%s", p.LogLevel),
|
||||
"_LIBCONTAINER_LOGPIPE="+strconv.Itoa(stdioFdCount+len(cmd.ExtraFiles)-1),
|
||||
"_LIBCONTAINER_LOGLEVEL="+p.LogLevel,
|
||||
)
|
||||
|
||||
// NOTE: when running a container with no PID namespace and the parent process spawning the container is
|
||||
@@ -693,8 +680,7 @@ var criuFeatures *criurpc.CriuFeatures
|
||||
|
||||
func (c *linuxContainer) checkCriuFeatures(criuOpts *CriuOpts, rpcOpts *criurpc.CriuOpts, criuFeat *criurpc.CriuFeatures) error {
|
||||
|
||||
var t criurpc.CriuReqType
|
||||
t = criurpc.CriuReqType_FEATURE_CHECK
|
||||
t := criurpc.CriuReqType_FEATURE_CHECK
|
||||
|
||||
// make sure the features we are looking for are really not from
|
||||
// some previous check
|
||||
@@ -777,11 +763,7 @@ func (c *linuxContainer) checkCriuVersion(minVersion int) error {
|
||||
const descriptorsFilename = "descriptors.json"
|
||||
|
||||
func (c *linuxContainer) addCriuDumpMount(req *criurpc.CriuReq, m *configs.Mount) {
|
||||
mountDest := m.Destination
|
||||
if strings.HasPrefix(mountDest, c.config.Rootfs) {
|
||||
mountDest = mountDest[len(c.config.Rootfs):]
|
||||
}
|
||||
|
||||
mountDest := strings.TrimPrefix(m.Destination, c.config.Rootfs)
|
||||
extMnt := &criurpc.ExtMountMap{
|
||||
Key: proto.String(mountDest),
|
||||
Val: proto.String(mountDest),
|
||||
@@ -853,7 +835,7 @@ func (c *linuxContainer) criuSupportsExtNS(t configs.NamespaceType) bool {
|
||||
return c.checkCriuVersion(minVersion) == nil
|
||||
}
|
||||
|
||||
func (c *linuxContainer) criuNsToKey(t configs.NamespaceType) string {
|
||||
func criuNsToKey(t configs.NamespaceType) string {
|
||||
return "extRoot" + strings.Title(configs.NsName(t)) + "NS"
|
||||
}
|
||||
|
||||
@@ -873,12 +855,50 @@ func (c *linuxContainer) handleCheckpointingExternalNamespaces(rpcOpts *criurpc.
|
||||
if err := unix.Stat(nsPath, &ns); err != nil {
|
||||
return err
|
||||
}
|
||||
criuExternal := fmt.Sprintf("%s[%d]:%s", configs.NsName(t), ns.Ino, c.criuNsToKey(t))
|
||||
criuExternal := fmt.Sprintf("%s[%d]:%s", configs.NsName(t), ns.Ino, criuNsToKey(t))
|
||||
rpcOpts.External = append(rpcOpts.External, criuExternal)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *linuxContainer) handleRestoringNamespaces(rpcOpts *criurpc.CriuOpts, extraFiles *[]*os.File) error {
|
||||
for _, ns := range c.config.Namespaces {
|
||||
switch ns.Type {
|
||||
case configs.NEWNET, configs.NEWPID:
|
||||
// If the container is running in a network or PID namespace and has
|
||||
// a path to the network or PID namespace configured, we will dump
|
||||
// that network or PID namespace as an external namespace and we
|
||||
// will expect that the namespace exists during restore.
|
||||
// This basically means that CRIU will ignore the namespace
|
||||
// and expect it to be setup correctly.
|
||||
if err := c.handleRestoringExternalNamespaces(rpcOpts, extraFiles, ns.Type); err != nil {
|
||||
return err
|
||||
}
|
||||
default:
|
||||
// For all other namespaces except NET and PID CRIU has
|
||||
// a simpler way of joining the existing namespace if set
|
||||
nsPath := c.config.Namespaces.PathOf(ns.Type)
|
||||
if nsPath == "" {
|
||||
continue
|
||||
}
|
||||
if ns.Type == configs.NEWCGROUP {
|
||||
// CRIU has no code to handle NEWCGROUP
|
||||
return fmt.Errorf("Do not know how to handle namespace %v", ns.Type)
|
||||
}
|
||||
// CRIU has code to handle NEWTIME, but it does not seem to be defined in runc
|
||||
|
||||
// CRIU will issue a warning for NEWUSER:
|
||||
// criu/namespaces.c: 'join-ns with user-namespace is not fully tested and dangerous'
|
||||
rpcOpts.JoinNs = append(rpcOpts.JoinNs, &criurpc.JoinNamespace{
|
||||
Ns: proto.String(configs.NsName(ns.Type)),
|
||||
NsFile: proto.String(nsPath),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *linuxContainer) handleRestoringExternalNamespaces(rpcOpts *criurpc.CriuOpts, extraFiles *[]*os.File, t configs.NamespaceType) error {
|
||||
if !c.criuSupportsExtNS(t) {
|
||||
return nil
|
||||
@@ -897,11 +917,12 @@ func (c *linuxContainer) handleRestoringExternalNamespaces(rpcOpts *criurpc.Criu
|
||||
logrus.Errorf("If a specific network namespace is defined it must exist: %s", err)
|
||||
return fmt.Errorf("Requested network namespace %v does not exist", nsPath)
|
||||
}
|
||||
inheritFd := new(criurpc.InheritFd)
|
||||
inheritFd.Key = proto.String(c.criuNsToKey(t))
|
||||
// The offset of four is necessary because 0, 1, 2 and 3 is already
|
||||
// used by stdin, stdout, stderr, 'criu swrk' socket.
|
||||
inheritFd.Fd = proto.Int32(int32(4 + len(*extraFiles)))
|
||||
inheritFd := &criurpc.InheritFd{
|
||||
Key: proto.String(criuNsToKey(t)),
|
||||
// The offset of four is necessary because 0, 1, 2 and 3 are
|
||||
// already used by stdin, stdout, stderr, 'criu swrk' socket.
|
||||
Fd: proto.Int32(int32(4 + len(*extraFiles))),
|
||||
}
|
||||
rpcOpts.InheritFd = append(rpcOpts.InheritFd, inheritFd)
|
||||
// All open FDs need to be transferred to CRIU via extraFiles
|
||||
*extraFiles = append(*extraFiles, nsFd)
|
||||
@@ -1120,11 +1141,7 @@ func (c *linuxContainer) Checkpoint(criuOpts *CriuOpts) error {
|
||||
}
|
||||
|
||||
func (c *linuxContainer) addCriuRestoreMount(req *criurpc.CriuReq, m *configs.Mount) {
|
||||
mountDest := m.Destination
|
||||
if strings.HasPrefix(mountDest, c.config.Rootfs) {
|
||||
mountDest = mountDest[len(c.config.Rootfs):]
|
||||
}
|
||||
|
||||
mountDest := strings.TrimPrefix(m.Destination, c.config.Rootfs)
|
||||
extMnt := &criurpc.ExtMountMap{
|
||||
Key: proto.String(mountDest),
|
||||
Val: proto.String(m.Source),
|
||||
@@ -1309,15 +1326,7 @@ func (c *linuxContainer) Restore(process *Process, criuOpts *CriuOpts) error {
|
||||
|
||||
c.handleCriuConfigurationFile(req.Opts)
|
||||
|
||||
// Same as during checkpointing. If the container has a specific network namespace
|
||||
// assigned to it, this now expects that the checkpoint will be restored in a
|
||||
// already created network namespace.
|
||||
if err := c.handleRestoringExternalNamespaces(req.Opts, &extraFiles, configs.NEWNET); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Same for PID namespaces.
|
||||
if err := c.handleRestoringExternalNamespaces(req.Opts, &extraFiles, configs.NEWPID); err != nil {
|
||||
if err := c.handleRestoringNamespaces(req.Opts, &extraFiles); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -1540,7 +1549,7 @@ func (c *linuxContainer) criuSwrk(process *Process, req *criurpc.CriuReq, opts *
|
||||
|
||||
buf := make([]byte, 10*4096)
|
||||
oob := make([]byte, 4096)
|
||||
for true {
|
||||
for {
|
||||
n, oobn, _, _, err := criuClientCon.ReadMsgUnix(buf, oob)
|
||||
if req.Opts != nil && req.Opts.StatusFd != nil {
|
||||
// Close status_fd as soon as we got something back from criu,
|
||||
@@ -1792,10 +1801,6 @@ func (c *linuxContainer) saveState(s *State) (retErr error) {
|
||||
return os.Rename(tmpFile.Name(), stateFilePath)
|
||||
}
|
||||
|
||||
func (c *linuxContainer) deleteState() error {
|
||||
return os.Remove(filepath.Join(c.root, stateFilename))
|
||||
}
|
||||
|
||||
func (c *linuxContainer) currentStatus() (Status, error) {
|
||||
if err := c.refreshState(); err != nil {
|
||||
return -1, err
|
||||
@@ -2042,7 +2047,7 @@ func (c *linuxContainer) bootstrapData(cloneFlags uintptr, nsMaps map[configs.Na
|
||||
// write oom_score_adj
|
||||
r.AddData(&Bytemsg{
|
||||
Type: OomScoreAdjAttr,
|
||||
Value: []byte(fmt.Sprintf("%d", *c.config.OomScoreAdj)),
|
||||
Value: []byte(strconv.Itoa(*c.config.OomScoreAdj)),
|
||||
})
|
||||
}
|
||||
|
||||
@@ -2062,9 +2067,21 @@ func ignoreTerminateErrors(err error) error {
|
||||
if err == nil {
|
||||
return nil
|
||||
}
|
||||
// terminate() might return an error from ether Kill or Wait.
|
||||
// The (*Cmd).Wait documentation says: "If the command fails to run
|
||||
// or doesn't complete successfully, the error is of type *ExitError".
|
||||
// Filter out such errors (like "exit status 1" or "signal: killed").
|
||||
var exitErr *exec.ExitError
|
||||
if errors.As(err, &exitErr) {
|
||||
return nil
|
||||
}
|
||||
// TODO: use errors.Is(err, os.ErrProcessDone) here and
|
||||
// remove "process already finished" string comparison below
|
||||
// once go 1.16 is minimally supported version.
|
||||
|
||||
s := err.Error()
|
||||
switch {
|
||||
case strings.Contains(s, "process already finished"), strings.Contains(s, "Wait was already called"):
|
||||
if strings.Contains(s, "process already finished") ||
|
||||
strings.Contains(s, "Wait was already called") {
|
||||
return nil
|
||||
}
|
||||
return err
|
||||
|
Reference in New Issue
Block a user