mirror of
https://github.com/opencontainers/runc.git
synced 2026-07-10 21:53:57 +08:00
044e298507
The error handling on the runc cli is currenly pretty messy because messages to the user are split between regular stderr format and logrus message format. This changes all the error reporting to the cli to only output on stderr and exit(1) for consumers of the api. By default logrus logs to /dev/null so that it is not seen by the user. If the user wants extra and/or structured loggging/errors from runc they can use the `--log` flag to provide a path to the file where they want this information. This allows a consistent behavior on the cli but extra power and information when debugging with logs. This also includes a change to enable the same logging information inside the container's init by adding an init cli command that can share the existing flags for all other runc commands. Signed-off-by: Michael Crosby <crosbymichael@gmail.com>
179 lines
4.2 KiB
Go
179 lines
4.2 KiB
Go
// +build linux
|
|
|
|
package main
|
|
|
|
import (
|
|
"os"
|
|
"syscall"
|
|
|
|
"github.com/Sirupsen/logrus"
|
|
"github.com/codegangsta/cli"
|
|
"github.com/opencontainers/runc/libcontainer"
|
|
"github.com/opencontainers/runc/libcontainer/configs"
|
|
"github.com/opencontainers/specs"
|
|
)
|
|
|
|
var restoreCommand = cli.Command{
|
|
Name: "restore",
|
|
Usage: "restore a container from a previous checkpoint",
|
|
ArgsUsage: `<container-id>
|
|
|
|
Where "<container-id>" is the name for the instance of the container to be
|
|
restored.`,
|
|
Description: `Restores the saved state of the container instance that was previously saved
|
|
using the runc checkpoint command.`,
|
|
Flags: []cli.Flag{
|
|
cli.StringFlag{
|
|
Name: "image-path",
|
|
Value: "",
|
|
Usage: "path to criu image files for restoring",
|
|
},
|
|
cli.StringFlag{
|
|
Name: "work-path",
|
|
Value: "",
|
|
Usage: "path for saving work files and logs",
|
|
},
|
|
cli.BoolFlag{
|
|
Name: "tcp-established",
|
|
Usage: "allow open tcp connections",
|
|
},
|
|
cli.BoolFlag{
|
|
Name: "ext-unix-sk",
|
|
Usage: "allow external unix sockets",
|
|
},
|
|
cli.BoolFlag{
|
|
Name: "shell-job",
|
|
Usage: "allow shell jobs",
|
|
},
|
|
cli.BoolFlag{
|
|
Name: "file-locks",
|
|
Usage: "handle file locks, for safety",
|
|
},
|
|
cli.StringFlag{
|
|
Name: "manage-cgroups-mode",
|
|
Value: "",
|
|
Usage: "cgroups mode: 'soft' (default), 'full' and 'strict'.",
|
|
},
|
|
cli.StringFlag{
|
|
Name: "bundle, b",
|
|
Value: "",
|
|
Usage: "path to the root of the bundle directory",
|
|
},
|
|
cli.BoolFlag{
|
|
Name: "detach,d",
|
|
Usage: "detach from the container's process",
|
|
},
|
|
cli.StringFlag{
|
|
Name: "pid-file",
|
|
Value: "",
|
|
Usage: "specify the file to write the process id to",
|
|
},
|
|
},
|
|
Action: func(context *cli.Context) {
|
|
imagePath := context.String("image-path")
|
|
id := context.Args().First()
|
|
if id == "" {
|
|
fatal(errEmptyID)
|
|
}
|
|
if imagePath == "" {
|
|
imagePath = getDefaultImagePath(context)
|
|
}
|
|
bundle := context.String("bundle")
|
|
if bundle != "" {
|
|
if err := os.Chdir(bundle); err != nil {
|
|
fatal(err)
|
|
}
|
|
}
|
|
spec, err := loadSpec(specConfig)
|
|
if err != nil {
|
|
fatal(err)
|
|
}
|
|
config, err := createLibcontainerConfig(id, spec)
|
|
if err != nil {
|
|
fatal(err)
|
|
}
|
|
status, err := restoreContainer(context, spec, config, imagePath)
|
|
if err != nil {
|
|
fatal(err)
|
|
}
|
|
os.Exit(status)
|
|
},
|
|
}
|
|
|
|
func restoreContainer(context *cli.Context, spec *specs.LinuxSpec, config *configs.Config, imagePath string) (code int, err error) {
|
|
var (
|
|
rootuid = 0
|
|
id = context.Args().First()
|
|
)
|
|
factory, err := loadFactory(context)
|
|
if err != nil {
|
|
return -1, err
|
|
}
|
|
container, err := factory.Load(id)
|
|
if err != nil {
|
|
container, err = factory.Create(id, config)
|
|
if err != nil {
|
|
return -1, err
|
|
}
|
|
}
|
|
options := criuOptions(context)
|
|
|
|
status, err := container.Status()
|
|
if err != nil {
|
|
logrus.Error(err)
|
|
}
|
|
if status == libcontainer.Running {
|
|
fatalf("Container with id %s already running", id)
|
|
}
|
|
|
|
setManageCgroupsMode(context, options)
|
|
|
|
// ensure that the container is always removed if we were the process
|
|
// that created it.
|
|
detach := context.Bool("detach")
|
|
if !detach {
|
|
defer destroy(container)
|
|
}
|
|
process := &libcontainer.Process{}
|
|
tty, err := setupIO(process, rootuid, "", false, detach)
|
|
if err != nil {
|
|
return -1, err
|
|
}
|
|
defer tty.Close()
|
|
handler := newSignalHandler(tty)
|
|
defer handler.Close()
|
|
if err := container.Restore(process, options); err != nil {
|
|
return -1, err
|
|
}
|
|
if err := tty.ClosePostStart(); err != nil {
|
|
return -1, err
|
|
}
|
|
if pidFile := context.String("pid-file"); pidFile != "" {
|
|
if err := createPidFile(pidFile, process); err != nil {
|
|
process.Signal(syscall.SIGKILL)
|
|
process.Wait()
|
|
return -1, err
|
|
}
|
|
}
|
|
if detach {
|
|
return 0, nil
|
|
}
|
|
return handler.forward(process)
|
|
}
|
|
|
|
func criuOptions(context *cli.Context) *libcontainer.CriuOpts {
|
|
imagePath := getCheckpointImagePath(context)
|
|
if err := os.MkdirAll(imagePath, 0655); err != nil {
|
|
fatal(err)
|
|
}
|
|
return &libcontainer.CriuOpts{
|
|
ImagesDirectory: imagePath,
|
|
WorkDirectory: context.String("work-path"),
|
|
LeaveRunning: context.Bool("leave-running"),
|
|
TcpEstablished: context.Bool("tcp-established"),
|
|
ExternalUnixConnections: context.Bool("ext-unix-sk"),
|
|
ShellJob: context.Bool("shell-job"),
|
|
FileLocks: context.Bool("file-locks"),
|
|
}
|
|
}
|