Skip to content

Commit

Permalink
Remove main package dependency on criurpc
Browse files Browse the repository at this point in the history
Commit 7f64fb4 made the main package, and runc/libcontainer's CriuOpts
depend on criu/rpc. This is not good; among the other things, it makes
it complicated to make c/r optional.

Let's switch CriuOpts.ManageCgroupsMode to a string (yes, it's an APIt
breaking change) and move the cgroup mode string parsing to
libcontainer.

While at it, let's better document ManageCgroupsMode.

Signed-off-by: Kir Kolyshkin <[email protected]>
  • Loading branch information
kolyshkin committed Dec 6, 2024
1 parent 67c8a28 commit 09888dc
Show file tree
Hide file tree
Showing 4 changed files with 84 additions and 63 deletions.
17 changes: 1 addition & 16 deletions checkpoint.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ import (
"path/filepath"
"strconv"

criu "github.com/checkpoint-restore/go-criu/v6/rpc"
"github.com/moby/sys/userns"
"github.com/opencontainers/runtime-spec/specs-go"
"github.com/sirupsen/logrus"
Expand Down Expand Up @@ -132,6 +131,7 @@ func criuOptions(context *cli.Context) (*libcontainer.CriuOpts, error) {
StatusFd: context.Int("status-fd"),
LsmProfile: context.String("lsm-profile"),
LsmMountContext: context.String("lsm-mount-context"),
ManageCgroupsMode: context.String("manage-cgroups-mode"),
}

// CRIU options below may or may not be set.
Expand All @@ -152,21 +152,6 @@ func criuOptions(context *cli.Context) (*libcontainer.CriuOpts, error) {
}
}

switch context.String("manage-cgroups-mode") {
case "":
// do nothing
case "soft":
opts.ManageCgroupsMode = criu.CriuCgMode_SOFT
case "full":
opts.ManageCgroupsMode = criu.CriuCgMode_FULL
case "strict":
opts.ManageCgroupsMode = criu.CriuCgMode_STRICT
case "ignore":
opts.ManageCgroupsMode = criu.CriuCgMode_IGNORE
default:
return nil, errors.New("Invalid manage-cgroups-mode value")
}

// runc doesn't manage network devices and their configuration.
nsmask := unix.CLONE_NEWNET

Expand Down
15 changes: 15 additions & 0 deletions libcontainer/criu_disabled_linux.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
//go:build runc_nocr

package libcontainer

import "errors"

var ErrNoCR = errors.New("checkpoint/restore support not compiled in")

func (c *Container) Restore(process *Process, criuOpts *CriuOpts) error {
return ErrNoCR
}

func (c *Container) Checkpoint(criuOpts *CriuOpts) error {
return ErrNoCR
}
106 changes: 62 additions & 44 deletions libcontainer/criu_linux.go
Original file line number Diff line number Diff line change
Expand Up @@ -295,6 +295,11 @@ func (c *Container) Checkpoint(criuOpts *CriuOpts) error {
return errors.New("invalid directory to save checkpoint")
}

cgMode, err := criuCgMode(criuOpts.ManageCgroupsMode)
if err != nil {
return err
}

// Since a container can be C/R'ed multiple times,
// the checkpoint directory may already exist.
if err := os.Mkdir(criuOpts.ImagesDirectory, 0o700); err != nil && !os.IsExist(err) {
Expand All @@ -309,22 +314,23 @@ func (c *Container) Checkpoint(criuOpts *CriuOpts) error {
defer imageDir.Close()

rpcOpts := criurpc.CriuOpts{
ImagesDirFd: proto.Int32(int32(imageDir.Fd())),
LogLevel: proto.Int32(4),
LogFile: proto.String(logFile),
Root: proto.String(c.config.Rootfs),
ManageCgroups: proto.Bool(true),
NotifyScripts: proto.Bool(true),
Pid: proto.Int32(int32(c.initProcess.pid())),
ShellJob: proto.Bool(criuOpts.ShellJob),
LeaveRunning: proto.Bool(criuOpts.LeaveRunning),
TcpEstablished: proto.Bool(criuOpts.TcpEstablished),
ExtUnixSk: proto.Bool(criuOpts.ExternalUnixConnections),
FileLocks: proto.Bool(criuOpts.FileLocks),
EmptyNs: proto.Uint32(criuOpts.EmptyNs),
OrphanPtsMaster: proto.Bool(true),
AutoDedup: proto.Bool(criuOpts.AutoDedup),
LazyPages: proto.Bool(criuOpts.LazyPages),
ImagesDirFd: proto.Int32(int32(imageDir.Fd())),
LogLevel: proto.Int32(4),
LogFile: proto.String(logFile),
Root: proto.String(c.config.Rootfs),
ManageCgroups: proto.Bool(true), // Obsoleted by ManageCgroupsMode.
ManageCgroupsMode: &cgMode,
NotifyScripts: proto.Bool(true),
Pid: proto.Int32(int32(c.initProcess.pid())),
ShellJob: proto.Bool(criuOpts.ShellJob),
LeaveRunning: proto.Bool(criuOpts.LeaveRunning),
TcpEstablished: proto.Bool(criuOpts.TcpEstablished),
ExtUnixSk: proto.Bool(criuOpts.ExternalUnixConnections),
FileLocks: proto.Bool(criuOpts.FileLocks),
EmptyNs: proto.Uint32(criuOpts.EmptyNs),
OrphanPtsMaster: proto.Bool(true),
AutoDedup: proto.Bool(criuOpts.AutoDedup),
LazyPages: proto.Bool(criuOpts.LazyPages),
}

// if criuOpts.WorkDirectory is not set, criu default is used.
Expand Down Expand Up @@ -381,12 +387,6 @@ func (c *Container) Checkpoint(criuOpts *CriuOpts) error {
rpcOpts.TrackMem = proto.Bool(true)
}

// append optional manage cgroups mode
if criuOpts.ManageCgroupsMode != 0 {
mode := criuOpts.ManageCgroupsMode
rpcOpts.ManageCgroupsMode = &mode
}

var t criurpc.CriuReqType
if criuOpts.PreDump {
feat := criurpc.CriuFeatures{
Expand Down Expand Up @@ -634,6 +634,12 @@ func (c *Container) Restore(process *Process, criuOpts *CriuOpts) error {
if criuOpts.ImagesDirectory == "" {
return errors.New("invalid directory to restore checkpoint")
}

cgMode, err := criuCgMode(criuOpts.ManageCgroupsMode)
if err != nil {
return err
}

logDir := criuOpts.ImagesDirectory
imageDir, err := os.Open(criuOpts.ImagesDirectory)
if err != nil {
Expand Down Expand Up @@ -663,22 +669,23 @@ func (c *Container) Restore(process *Process, criuOpts *CriuOpts) error {
req := &criurpc.CriuReq{
Type: &t,
Opts: &criurpc.CriuOpts{
ImagesDirFd: proto.Int32(int32(imageDir.Fd())),
EvasiveDevices: proto.Bool(true),
LogLevel: proto.Int32(4),
LogFile: proto.String(logFile),
RstSibling: proto.Bool(true),
Root: proto.String(root),
ManageCgroups: proto.Bool(true),
NotifyScripts: proto.Bool(true),
ShellJob: proto.Bool(criuOpts.ShellJob),
ExtUnixSk: proto.Bool(criuOpts.ExternalUnixConnections),
TcpEstablished: proto.Bool(criuOpts.TcpEstablished),
FileLocks: proto.Bool(criuOpts.FileLocks),
EmptyNs: proto.Uint32(criuOpts.EmptyNs),
OrphanPtsMaster: proto.Bool(true),
AutoDedup: proto.Bool(criuOpts.AutoDedup),
LazyPages: proto.Bool(criuOpts.LazyPages),
ImagesDirFd: proto.Int32(int32(imageDir.Fd())),
EvasiveDevices: proto.Bool(true),
LogLevel: proto.Int32(4),
LogFile: proto.String(logFile),
RstSibling: proto.Bool(true),
Root: proto.String(root),
ManageCgroups: proto.Bool(true), // Obsoleted by ManageCgroupsMode.
ManageCgroupsMode: &cgMode,
NotifyScripts: proto.Bool(true),
ShellJob: proto.Bool(criuOpts.ShellJob),
ExtUnixSk: proto.Bool(criuOpts.ExternalUnixConnections),
TcpEstablished: proto.Bool(criuOpts.TcpEstablished),
FileLocks: proto.Bool(criuOpts.FileLocks),
EmptyNs: proto.Uint32(criuOpts.EmptyNs),
OrphanPtsMaster: proto.Bool(true),
AutoDedup: proto.Bool(criuOpts.AutoDedup),
LazyPages: proto.Bool(criuOpts.LazyPages),
},
}

Expand Down Expand Up @@ -757,12 +764,6 @@ func (c *Container) Restore(process *Process, criuOpts *CriuOpts) error {
c.restoreNetwork(req, criuOpts)
}

// append optional manage cgroups mode
if criuOpts.ManageCgroupsMode != 0 {
mode := criuOpts.ManageCgroupsMode
req.Opts.ManageCgroupsMode = &mode
}

var (
fds []string
fdJSON []byte
Expand Down Expand Up @@ -1184,3 +1185,20 @@ func (c *Container) criuNotifications(resp *criurpc.CriuResp, process *Process,
}
return nil
}

func criuCgMode(mode string) (criurpc.CriuCgMode, error) {
switch mode {
case "":
return criurpc.CriuCgMode_DEFAULT, nil
case "soft":
return criurpc.CriuCgMode_SOFT, nil
case "full":
return criurpc.CriuCgMode_FULL, nil
case "strict":
return criurpc.CriuCgMode_STRICT, nil
case "ignore":
return criurpc.CriuCgMode_IGNORE, nil
default:
return 0, errors.New("invalid manage-cgroups-mode value")
}
}
9 changes: 6 additions & 3 deletions libcontainer/criu_opts_linux.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
package libcontainer

import criu "github.com/checkpoint-restore/go-criu/v6/rpc"

type CriuPageServerInfo struct {
Address string // IP address of CRIU page server
Port int32 // port number of CRIU page server
Expand All @@ -24,11 +22,16 @@ type CriuOpts struct {
PreDump bool // call criu predump to perform iterative checkpoint
PageServer CriuPageServerInfo // allow to dump to criu page server
VethPairs []VethPairName // pass the veth to criu when restore
ManageCgroupsMode criu.CriuCgMode // dump or restore cgroup mode
EmptyNs uint32 // don't c/r properties for namespace from this mask
AutoDedup bool // auto deduplication for incremental dumps
LazyPages bool // restore memory pages lazily using userfaultfd
StatusFd int // fd for feedback when lazy server is ready
LsmProfile string // LSM profile used to restore the container
LsmMountContext string // LSM mount context value to use during restore

// ManageCgroupsMode tells how criu should manage cgroups during
// checkpoint or restore. Possible values are: "soft", "full",
// "strict", "ignore", or "" (empty string) for criu default.
// See https://criu.org/CGroups for more details.
ManageCgroupsMode string
}

0 comments on commit 09888dc

Please sign in to comment.