Prepare startContainer() to have more action
Currently startContainer() is used to create and to run a container. In the next patch it will be used to restore a container. Signed-off-by: Andrei Vagin <avagin@virtuozzo.com>
This commit is contained in:
parent
1a8b0aced5
commit
a4fcbfb704
|
@ -62,7 +62,7 @@ command(s) that get executed on start, edit the args parameter of the spec. See
|
|||
if err != nil {
|
||||
return err
|
||||
}
|
||||
status, err := startContainer(context, spec, true)
|
||||
status, err := startContainer(context, spec, CT_ACT_CREATE, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
1
exec.go
1
exec.go
|
@ -135,6 +135,7 @@ func execProcess(context *cli.Context) (int, error) {
|
|||
consoleSocket: context.String("console-socket"),
|
||||
detach: detach,
|
||||
pidFile: context.String("pid-file"),
|
||||
action: CT_ACT_RUN,
|
||||
}
|
||||
return r.run(p)
|
||||
}
|
||||
|
|
108
restore.go
108
restore.go
|
@ -5,13 +5,8 @@ package main
|
|||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"syscall"
|
||||
|
||||
"github.com/Sirupsen/logrus"
|
||||
"github.com/opencontainers/runc/libcontainer"
|
||||
"github.com/opencontainers/runc/libcontainer/configs"
|
||||
"github.com/opencontainers/runc/libcontainer/specconv"
|
||||
"github.com/opencontainers/runtime-spec/specs-go"
|
||||
"github.com/urfave/cli"
|
||||
)
|
||||
|
||||
|
@ -92,111 +87,22 @@ using the runc checkpoint command.`,
|
|||
return fmt.Errorf("runc restore requires root")
|
||||
}
|
||||
|
||||
imagePath := context.String("image-path")
|
||||
id := context.Args().First()
|
||||
if id == "" {
|
||||
return errEmptyID
|
||||
}
|
||||
if imagePath == "" {
|
||||
imagePath = getDefaultImagePath(context)
|
||||
}
|
||||
bundle := context.String("bundle")
|
||||
if bundle != "" {
|
||||
if err := os.Chdir(bundle); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
spec, err := loadSpec(specConfig)
|
||||
spec, err := setupSpec(context)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
config, err := specconv.CreateLibcontainerConfig(&specconv.CreateOpts{
|
||||
CgroupName: id,
|
||||
UseSystemdCgroup: context.GlobalBool("systemd-cgroup"),
|
||||
NoPivotRoot: context.Bool("no-pivot"),
|
||||
Spec: spec,
|
||||
})
|
||||
options := criuOptions(context)
|
||||
status, err := startContainer(context, spec, CT_ACT_RESTORE, options)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
status, err := restoreContainer(context, spec, config, imagePath)
|
||||
if err == nil {
|
||||
os.Exit(status)
|
||||
}
|
||||
return err
|
||||
// exit with the container's exit status so any external supervisor is
|
||||
// notified of the exit with the correct exit status.
|
||||
os.Exit(status)
|
||||
return nil
|
||||
},
|
||||
}
|
||||
|
||||
func restoreContainer(context *cli.Context, spec *specs.Spec, config *configs.Config, imagePath string) (int, error) {
|
||||
var (
|
||||
rootuid = 0
|
||||
rootgid = 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)
|
||||
|
||||
if err = setEmptyNsMask(context, options); err != nil {
|
||||
return -1, err
|
||||
}
|
||||
|
||||
// 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, rootgid, false, detach, "")
|
||||
if err != nil {
|
||||
return -1, err
|
||||
}
|
||||
|
||||
notifySocket := newNotifySocket(context, os.Getenv("NOTIFY_SOCKET"), id)
|
||||
if notifySocket != nil {
|
||||
notifySocket.setupSpec(context, spec)
|
||||
notifySocket.setupSocket()
|
||||
}
|
||||
|
||||
handler := newSignalHandler(!context.Bool("no-subreaper"), notifySocket)
|
||||
if err := container.Restore(process, options); err != nil {
|
||||
return -1, err
|
||||
}
|
||||
// We don't need to do a tty.recvtty because config.Terminal is always false.
|
||||
defer tty.Close()
|
||||
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
|
||||
}
|
||||
}
|
||||
return handler.forward(process, tty, detach)
|
||||
}
|
||||
|
||||
func criuOptions(context *cli.Context) *libcontainer.CriuOpts {
|
||||
imagePath := getCheckpointImagePath(context)
|
||||
if err := os.MkdirAll(imagePath, 0655); err != nil {
|
||||
|
|
2
run.go
2
run.go
|
@ -73,7 +73,7 @@ command(s) that get executed on start, edit the args parameter of the spec. See
|
|||
if err != nil {
|
||||
return err
|
||||
}
|
||||
status, err := startContainer(context, spec, false)
|
||||
status, err := startContainer(context, spec, CT_ACT_RUN, 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.
|
||||
|
|
|
@ -220,8 +220,9 @@ type runner struct {
|
|||
pidFile string
|
||||
consoleSocket string
|
||||
container libcontainer.Container
|
||||
create bool
|
||||
action CtAct
|
||||
notifySocket *notifySocket
|
||||
criuOpts *libcontainer.CriuOpts
|
||||
}
|
||||
|
||||
func (r *runner) run(config *specs.Process) (int, error) {
|
||||
|
@ -253,12 +254,8 @@ func (r *runner) run(config *specs.Process) (int, error) {
|
|||
return -1, err
|
||||
}
|
||||
var (
|
||||
detach = r.detach || r.create
|
||||
startFn = r.container.Start
|
||||
detach = r.detach || (r.action == CT_ACT_CREATE)
|
||||
)
|
||||
if !r.create {
|
||||
startFn = r.container.Run
|
||||
}
|
||||
// Setting up IO is a two stage process. We need to modify process to deal
|
||||
// with detaching containers, and then we get a tty after the container has
|
||||
// started.
|
||||
|
@ -269,7 +266,18 @@ func (r *runner) run(config *specs.Process) (int, error) {
|
|||
return -1, err
|
||||
}
|
||||
defer tty.Close()
|
||||
if err = startFn(process); err != nil {
|
||||
|
||||
switch r.action {
|
||||
case CT_ACT_CREATE:
|
||||
err = r.container.Start(process)
|
||||
case CT_ACT_RESTORE:
|
||||
err = r.container.Restore(process, r.criuOpts)
|
||||
case CT_ACT_RUN:
|
||||
err = r.container.Run(process)
|
||||
default:
|
||||
panic("Unknown action")
|
||||
}
|
||||
if err != nil {
|
||||
r.destroy()
|
||||
return -1, err
|
||||
}
|
||||
|
@ -313,7 +321,7 @@ func (r *runner) terminate(p *libcontainer.Process) {
|
|||
}
|
||||
|
||||
func (r *runner) checkTerminal(config *specs.Process) error {
|
||||
detach := r.detach || r.create
|
||||
detach := r.detach || (r.action == CT_ACT_CREATE)
|
||||
// Check command-line for sanity.
|
||||
if detach && config.Terminal && r.consoleSocket == "" {
|
||||
return fmt.Errorf("cannot allocate tty if runc will detach without setting console socket")
|
||||
|
@ -337,7 +345,15 @@ func validateProcessSpec(spec *specs.Process) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func startContainer(context *cli.Context, spec *specs.Spec, create bool) (int, error) {
|
||||
type CtAct uint8
|
||||
|
||||
const (
|
||||
CT_ACT_CREATE CtAct = iota + 1
|
||||
CT_ACT_RUN
|
||||
CT_ACT_RESTORE
|
||||
)
|
||||
|
||||
func startContainer(context *cli.Context, spec *specs.Spec, action CtAct, criuOpts *libcontainer.CriuOpts) (int, error) {
|
||||
id := context.Args().First()
|
||||
if id == "" {
|
||||
return -1, errEmptyID
|
||||
|
@ -372,7 +388,8 @@ func startContainer(context *cli.Context, spec *specs.Spec, create bool) (int, e
|
|||
detach: context.Bool("detach"),
|
||||
pidFile: context.String("pid-file"),
|
||||
preserveFDs: context.Int("preserve-fds"),
|
||||
create: create,
|
||||
action: action,
|
||||
criuOpts: criuOpts,
|
||||
}
|
||||
return r.run(&spec.Process)
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue