Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ GIT_BRANCH := $(shell git rev-parse --abbrev-ref HEAD 2>/dev/null)
GIT_BRANCH_CLEAN := $(shell echo $(GIT_BRANCH) | sed -e "s/[^[:alnum:]]/-/g")
RUNC_IMAGE := runc_dev$(if $(GIT_BRANCH_CLEAN),:$(GIT_BRANCH_CLEAN))
PROJECT := github.com/opencontainers/runc
BUILDTAGS := seccomp urfave_cli_no_docs libpathrs
BUILDTAGS := seccomp libpathrs
# Tags prefixed with - in RUNC_BUILDTAGS are removed from BUILDTAGS; others are added.
RUNC_BUILDTAGS ?=
BUILDTAGS_REMOVE := $(patsubst -%,%,$(filter -%,$(RUNC_BUILDTAGS)))
Expand Down
93 changes: 47 additions & 46 deletions checkpoint.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package main

import (
"context"
"errors"
"fmt"
"net"
Expand All @@ -11,13 +12,13 @@ import (
"github.com/moby/sys/userns"
"github.com/opencontainers/runtime-spec/specs-go"
"github.com/sirupsen/logrus"
"github.com/urfave/cli"
"github.com/urfave/cli/v3"
"golang.org/x/sys/unix"

"github.com/opencontainers/runc/libcontainer"
)

var checkpointCommand = cli.Command{
var checkpointCommand = &cli.Command{
Name: "checkpoint",
Usage: "checkpoint a running container",
ArgsUsage: `<container-id>
Expand All @@ -26,34 +27,34 @@ Where "<container-id>" is the name for the instance of the container to be
checkpointed.`,
Description: `The checkpoint command saves the state of the container instance.`,
Flags: []cli.Flag{
cli.StringFlag{Name: "image-path", Value: "", Usage: "path for saving criu image files"},
cli.StringFlag{Name: "work-path", Value: "", Usage: "path for saving work files and logs"},
cli.StringFlag{Name: "parent-path", Value: "", Usage: "path for previous criu image files in pre-dump"},
cli.BoolFlag{Name: "leave-running", Usage: "leave the process running after checkpointing"},
cli.BoolFlag{Name: "tcp-established", Usage: "allow open tcp connections"},
cli.BoolFlag{Name: "tcp-skip-in-flight", Usage: "skip in-flight tcp connections"},
cli.BoolFlag{Name: "link-remap", Usage: "allow one to link unlinked files back when possible"},
cli.BoolFlag{Name: "ext-unix-sk", Usage: "allow external unix sockets"},
cli.BoolFlag{Name: "shell-job", Usage: "allow shell jobs"},
cli.BoolFlag{Name: "lazy-pages", Usage: "use userfaultfd to lazily restore memory pages"},
cli.IntFlag{Name: "status-fd", Value: -1, Usage: "criu writes \\0 to this FD once lazy-pages is ready"},
cli.StringFlag{Name: "page-server", Value: "", Usage: "ADDRESS:PORT of the page server"},
cli.BoolFlag{Name: "file-locks", Usage: "handle file locks, for safety"},
cli.BoolFlag{Name: "pre-dump", Usage: "dump container's memory information only, leave the container running after this"},
cli.StringFlag{Name: "manage-cgroups-mode", Value: "", Usage: "cgroups mode: soft|full|strict|ignore (default: soft)"},
cli.StringSliceFlag{Name: "empty-ns", Usage: "create a namespace, but don't restore its properties"},
cli.BoolFlag{Name: "auto-dedup", Usage: "enable auto deduplication of memory images"},
&cli.StringFlag{Name: "image-path", Value: "", Usage: "path for saving criu image files"},
&cli.StringFlag{Name: "work-path", Value: "", Usage: "path for saving work files and logs"},
&cli.StringFlag{Name: "parent-path", Value: "", Usage: "path for previous criu image files in pre-dump"},
&cli.BoolFlag{Name: "leave-running", Usage: "leave the process running after checkpointing"},
&cli.BoolFlag{Name: "tcp-established", Usage: "allow open tcp connections"},
&cli.BoolFlag{Name: "tcp-skip-in-flight", Usage: "skip in-flight tcp connections"},
&cli.BoolFlag{Name: "link-remap", Usage: "allow one to link unlinked files back when possible"},
&cli.BoolFlag{Name: "ext-unix-sk", Usage: "allow external unix sockets"},
&cli.BoolFlag{Name: "shell-job", Usage: "allow shell jobs"},
&cli.BoolFlag{Name: "lazy-pages", Usage: "use userfaultfd to lazily restore memory pages"},
&cli.IntFlag{Name: "status-fd", Value: -1, Usage: "criu writes \\0 to this FD once lazy-pages is ready"},
&cli.StringFlag{Name: "page-server", Value: "", Usage: "ADDRESS:PORT of the page server"},
&cli.BoolFlag{Name: "file-locks", Usage: "handle file locks, for safety"},
&cli.BoolFlag{Name: "pre-dump", Usage: "dump container's memory information only, leave the container running after this"},
&cli.StringFlag{Name: "manage-cgroups-mode", Value: "", Usage: "cgroups mode: soft|full|strict|ignore (default: soft)"},
&cli.StringSliceFlag{Name: "empty-ns", Usage: "create a namespace, but don't restore its properties"},
&cli.BoolFlag{Name: "auto-dedup", Usage: "enable auto deduplication of memory images"},
},
Action: func(context *cli.Context) error {
if err := checkArgs(context, 1, exactArgs); err != nil {
Action: func(_ context.Context, cmd *cli.Command) error {
if err := checkArgs(cmd, 1, exactArgs); err != nil {
return err
}
// XXX: Currently this is untested with rootless containers.
if os.Geteuid() != 0 || userns.RunningInUserNS() {
logrus.Warn("runc checkpoint is untested with rootless containers")
}

container, err := getContainer(context)
container, err := getContainer(cmd)
if err != nil {
return err
}
Expand All @@ -64,7 +65,7 @@ checkpointed.`,
if status == libcontainer.Created || status == libcontainer.Stopped {
return fmt.Errorf("Container cannot be checkpointed in %s state", status.String())
}
options, err := criuOptions(context)
options, err := criuOptions(cmd)
if err != nil {
return err
}
Expand All @@ -80,8 +81,8 @@ checkpointed.`,
},
}

func prepareImagePaths(context *cli.Context) (string, string, error) {
imagePath := context.String("image-path")
func prepareImagePaths(cmd *cli.Command) (string, string, error) {
imagePath := cmd.String("image-path")
if imagePath == "" {
imagePath = getDefaultImagePath()
}
Expand All @@ -90,7 +91,7 @@ func prepareImagePaths(context *cli.Context) (string, string, error) {
return "", "", err
}

parentPath := context.String("parent-path")
parentPath := cmd.String("parent-path")
if parentPath == "" {
return imagePath, parentPath, nil
}
Expand All @@ -112,35 +113,35 @@ func prepareImagePaths(context *cli.Context) (string, string, error) {
return imagePath, parentPath, nil
}

func criuOptions(context *cli.Context) (*libcontainer.CriuOpts, error) {
imagePath, parentPath, err := prepareImagePaths(context)
func criuOptions(cmd *cli.Command) (*libcontainer.CriuOpts, error) {
imagePath, parentPath, err := prepareImagePaths(cmd)
if err != nil {
return nil, err
}

opts := &libcontainer.CriuOpts{
ImagesDirectory: imagePath,
WorkDirectory: context.String("work-path"),
WorkDirectory: cmd.String("work-path"),
ParentImage: parentPath,
LeaveRunning: context.Bool("leave-running"),
TcpEstablished: context.Bool("tcp-established"),
TcpSkipInFlight: context.Bool("tcp-skip-in-flight"),
LinkRemap: context.Bool("link-remap"),
ExternalUnixConnections: context.Bool("ext-unix-sk"),
ShellJob: context.Bool("shell-job"),
FileLocks: context.Bool("file-locks"),
PreDump: context.Bool("pre-dump"),
AutoDedup: context.Bool("auto-dedup"),
LazyPages: context.Bool("lazy-pages"),
StatusFd: context.Int("status-fd"),
LsmProfile: context.String("lsm-profile"),
LsmMountContext: context.String("lsm-mount-context"),
ManageCgroupsMode: context.String("manage-cgroups-mode"),
LeaveRunning: cmd.Bool("leave-running"),
TcpEstablished: cmd.Bool("tcp-established"),
TcpSkipInFlight: cmd.Bool("tcp-skip-in-flight"),
LinkRemap: cmd.Bool("link-remap"),
ExternalUnixConnections: cmd.Bool("ext-unix-sk"),
ShellJob: cmd.Bool("shell-job"),
FileLocks: cmd.Bool("file-locks"),
PreDump: cmd.Bool("pre-dump"),
AutoDedup: cmd.Bool("auto-dedup"),
LazyPages: cmd.Bool("lazy-pages"),
StatusFd: cmd.Int("status-fd"),
LsmProfile: cmd.String("lsm-profile"),
LsmMountContext: cmd.String("lsm-mount-context"),
ManageCgroupsMode: cmd.String("manage-cgroups-mode"),
}

// CRIU options below may or may not be set.

if psOpt := context.String("page-server"); psOpt != "" {
if psOpt := cmd.String("page-server"); psOpt != "" {
address, port, err := net.SplitHostPort(psOpt)

if err != nil || address == "" || port == "" {
Expand All @@ -159,12 +160,12 @@ func criuOptions(context *cli.Context) (*libcontainer.CriuOpts, error) {
// runc doesn't manage network devices and their configuration.
nsmask := unix.CLONE_NEWNET

if context.IsSet("empty-ns") {
if cmd.IsSet("empty-ns") {
namespaceMapping := map[specs.LinuxNamespaceType]int{
specs.NetworkNamespace: unix.CLONE_NEWNET,
}

for _, ns := range context.StringSlice("empty-ns") {
for _, ns := range cmd.StringSlice("empty-ns") {
f, exists := namespaceMapping[specs.LinuxNamespaceType(ns)]
if !exists {
return nil, fmt.Errorf("namespace %q is not supported", ns)
Expand Down
34 changes: 19 additions & 15 deletions create.go
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
package main

import (
"context"
"fmt"
"os"

"github.com/urfave/cli"
"github.com/urfave/cli/v3"
)

var createCommand = cli.Command{
var createCommand = &cli.Command{
Name: "create",
Usage: "create a container",
ArgsUsage: `<container-id>
Expand All @@ -23,44 +24,47 @@ The specification file includes an args parameter. The args parameter is used
to specify command(s) that get run when the container is started. To change the
command(s) that get executed on start, edit the args parameter of the spec. See
"runc spec --help" for more explanation.`,
// Disable comma as separator for slice flags.
DisableSliceFlagSeparator: true,
Flags: []cli.Flag{
cli.StringFlag{
Name: "bundle, b",
Value: "",
Usage: `path to the root of the bundle directory, defaults to the current directory`,
&cli.StringFlag{
Name: "bundle",
Aliases: []string{"b"},
Value: "",
Usage: `path to the root of the bundle directory, defaults to the current directory`,
},
cli.StringFlag{
&cli.StringFlag{
Name: "console-socket",
Value: "",
Usage: "path to an AF_UNIX socket which will receive a file descriptor referencing the master end of the console's pseudoterminal",
},
cli.StringFlag{
&cli.StringFlag{
Name: "pidfd-socket",
Usage: "path to an AF_UNIX socket which will receive a file descriptor referencing the init process",
},
cli.StringFlag{
&cli.StringFlag{
Name: "pid-file",
Value: "",
Usage: "specify the file to write the process id to",
},
cli.BoolFlag{
&cli.BoolFlag{
Name: "no-pivot",
Usage: "do not use pivot root to jail process inside rootfs. This should be used whenever the rootfs is on top of a ramdisk",
},
cli.BoolFlag{
&cli.BoolFlag{
Name: "no-new-keyring",
Usage: "do not create a new session keyring for the container. This will cause the container to inherit the calling processes session key",
},
cli.IntFlag{
&cli.IntFlag{
Name: "preserve-fds",
Usage: "Pass N additional file descriptors to the container (stdio + $LISTEN_FDS + N in total)",
},
},
Action: func(context *cli.Context) error {
if err := checkArgs(context, 1, exactArgs); err != nil {
Action: func(_ context.Context, cmd *cli.Command) error {
if err := checkArgs(cmd, 1, exactArgs); err != nil {
return err
}
status, err := startContainer(context, CT_ACT_CREATE, nil)
status, err := startContainer(cmd, CT_ACT_CREATE, nil)
if err == nil {
// exit with the container's exit status so any external supervisor
// is notified of the exit with the correct exit status.
Expand Down
26 changes: 15 additions & 11 deletions delete.go
Original file line number Diff line number Diff line change
@@ -1,14 +1,15 @@
package main

import (
"context"
"errors"
"fmt"
"os"
"path/filepath"
"time"

"github.com/opencontainers/runc/libcontainer"
"github.com/urfave/cli"
"github.com/urfave/cli/v3"

"golang.org/x/sys/unix"
)
Expand All @@ -24,7 +25,7 @@ func killContainer(container *libcontainer.Container) error {
return errors.New("container init still running")
}

var deleteCommand = cli.Command{
var deleteCommand = &cli.Command{
Name: "delete",
Usage: "delete any resources held by the container often used with detached container",
ArgsUsage: `<container-id>
Expand All @@ -37,25 +38,28 @@ status of "ubuntu01" as "stopped" the following will delete resources held for
"ubuntu01" removing "ubuntu01" from the runc list of containers:

# runc delete ubuntu01`,
// Disable comma as separator for slice flags.
DisableSliceFlagSeparator: true,
Flags: []cli.Flag{
cli.BoolFlag{
Name: "force, f",
Usage: "Forcibly deletes the container if it is still running (uses SIGKILL)",
&cli.BoolFlag{
Name: "force",
Aliases: []string{"f"},
Usage: "Forcibly deletes the container if it is still running (uses SIGKILL)",
},
},
Action: func(context *cli.Context) error {
if err := checkArgs(context, 1, exactArgs); err != nil {
Action: func(_ context.Context, cmd *cli.Command) error {
if err := checkArgs(cmd, 1, exactArgs); err != nil {
return err
}

id := context.Args().First()
force := context.Bool("force")
container, err := getContainer(context)
id := cmd.Args().First()
force := cmd.Bool("force")
container, err := getContainer(cmd)
if err != nil {
if errors.Is(err, libcontainer.ErrNotExist) {
// if there was an aborted start or something of the sort then the container's directory could exist but
// libcontainer does not see it because the state.json file inside that directory was never created.
path := filepath.Join(context.GlobalString("root"), id)
path := filepath.Join(cmd.String("root"), id)
if e := os.RemoveAll(path); e != nil {
fmt.Fprintf(os.Stderr, "remove %s: %v\n", path, e)
}
Expand Down
23 changes: 13 additions & 10 deletions events.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package main

import (
"context"
"encoding/json"
"errors"
"fmt"
Expand All @@ -14,30 +15,32 @@ import (
"github.com/opencontainers/runc/types"

"github.com/sirupsen/logrus"
"github.com/urfave/cli"
"github.com/urfave/cli/v3"
)

var eventsCommand = cli.Command{
var eventsCommand = &cli.Command{
Name: "events",
Usage: "display container events such as OOM notifications, cpu, memory, and IO usage statistics",
ArgsUsage: `<container-id>

Where "<container-id>" is the name for the instance of the container.`,
Description: `The events command displays information about the container. By default the
information is displayed once every 5 seconds.`,
// Disable comma as separator for slice flags.
DisableSliceFlagSeparator: true,
Flags: []cli.Flag{
cli.DurationFlag{Name: "interval", Value: 5 * time.Second, Usage: "set the stats collection interval"},
cli.BoolFlag{Name: "stats", Usage: "display the container's stats then exit"},
&cli.DurationFlag{Name: "interval", Value: 5 * time.Second, Usage: "set the stats collection interval"},
&cli.BoolFlag{Name: "stats", Usage: "display the container's stats then exit"},
},
Action: func(context *cli.Context) error {
if err := checkArgs(context, 1, exactArgs); err != nil {
Action: func(_ context.Context, cmd *cli.Command) error {
if err := checkArgs(cmd, 1, exactArgs); err != nil {
return err
}
container, err := getContainer(context)
container, err := getContainer(cmd)
if err != nil {
return err
}
duration := context.Duration("interval")
duration := cmd.Duration("interval")
if duration <= 0 {
return errors.New("duration interval must be greater than 0")
}
Expand All @@ -61,7 +64,7 @@ information is displayed once every 5 seconds.`,
}
}
})
if context.Bool("stats") {
if cmd.Bool("stats") {
s, err := container.Stats()
if err != nil {
return err
Expand All @@ -72,7 +75,7 @@ information is displayed once every 5 seconds.`,
return nil
}
go func() {
for range time.Tick(context.Duration("interval")) {
for range time.Tick(cmd.Duration("interval")) {
s, err := container.Stats()
if err != nil {
logrus.Error(err)
Expand Down
Loading
Loading