mirror of
https://github.com/netbirdio/gvisor.git
synced 2026-05-22 17:12:49 -07:00
runsc/restore: must be able to restore to prepared container
runsc restore <container id> must be able to restore into a
prepared container to allow the user to configure container
specific namespaces as otherwise there is no other means to
override different bundle parameters and especially namespaces
configuration.
Specifically, otherwise, it is impossible to configure networking
other than by cloning the bundle config and preparing special
netns for the container instead of just configuring it on the fly
without whole management complexity.
This fix allows to do the following:
- runsc create
- configure container netns (even with the netlink api)
- restore into the container with nice networking
It also fixes the restore command to behave exactly as it is
stated in the documentation:
runsc create <container id>
runsc restore --image-path=<path> <container id>
at
https://github.com/google/gvisor/blob/master/g3doc/user_guide/checkpoint_restore.md
Generally, user shall not try to do a checkpoint restore into
the void. If container is not found, we keep back compatibility,
but print a warning.
Signed-off-by: Ivan Prisyazhnyy <john.koepi@gmail.com>
This commit is contained in:
@@ -53,6 +53,7 @@ go_library(
|
||||
deps = [
|
||||
"//pkg/abi/linux",
|
||||
"//pkg/atomicbitops",
|
||||
"//pkg/cleanup",
|
||||
"//pkg/coretag",
|
||||
"//pkg/coverage",
|
||||
"//pkg/cpuid",
|
||||
|
||||
+56
-9
@@ -16,10 +16,13 @@ package cmd
|
||||
|
||||
import (
|
||||
"context"
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/google/subcommands"
|
||||
"golang.org/x/sys/unix"
|
||||
"gvisor.dev/gvisor/pkg/cleanup"
|
||||
"gvisor.dev/gvisor/pkg/log"
|
||||
"gvisor.dev/gvisor/runsc/cmd/util"
|
||||
"gvisor.dev/gvisor/runsc/config"
|
||||
"gvisor.dev/gvisor/runsc/container"
|
||||
@@ -89,32 +92,76 @@ func (r *Restore) Execute(_ context.Context, f *flag.FlagSet, args ...any) subco
|
||||
if bundleDir == "" {
|
||||
bundleDir = getwdOrDie()
|
||||
}
|
||||
spec, err := specutils.ReadSpec(bundleDir, conf)
|
||||
if err != nil {
|
||||
return util.Errorf("reading spec: %v", err)
|
||||
}
|
||||
specutils.LogSpecDebug(spec, conf.OCISeccomp)
|
||||
|
||||
if r.imagePath == "" {
|
||||
return util.Errorf("image-path flag must be provided")
|
||||
}
|
||||
|
||||
var cu cleanup.Cleanup
|
||||
defer cu.Clean()
|
||||
|
||||
conf.RestoreFile = filepath.Join(r.imagePath, checkpointFileName)
|
||||
|
||||
runArgs := container.Args{
|
||||
ID: id,
|
||||
Spec: spec,
|
||||
Spec: nil,
|
||||
BundleDir: bundleDir,
|
||||
ConsoleSocket: r.consoleSocket,
|
||||
PIDFile: r.pidFile,
|
||||
UserLog: r.userLog,
|
||||
Attached: !r.detach,
|
||||
}
|
||||
ws, err := container.Run(conf, runArgs)
|
||||
|
||||
log.Debugf("Restore container, cid: %s, rootDir: %q", id, conf.RootDir)
|
||||
c, err := container.Load(conf.RootDir, container.FullID{ContainerID: id}, container.LoadOpts{})
|
||||
if err != nil {
|
||||
return util.Errorf("running container: %v", err)
|
||||
if err != os.ErrNotExist {
|
||||
return util.Errorf("loading container: %v", err)
|
||||
}
|
||||
|
||||
log.Warningf("Container not found, creating new one, cid: %s, spec from: %s", id, bundleDir)
|
||||
|
||||
// Read the spec again here to ensure flag annotations from the spec are
|
||||
// applied to "conf".
|
||||
if runArgs.Spec, err = specutils.ReadSpec(bundleDir, conf); err != nil {
|
||||
return util.Errorf("reading spec: %v", err)
|
||||
}
|
||||
specutils.LogSpecDebug(runArgs.Spec, conf.OCISeccomp)
|
||||
|
||||
if c, err = container.New(conf, runArgs); err != nil {
|
||||
return util.Errorf("creating container: %v", err)
|
||||
}
|
||||
|
||||
// Clean up partially created container if an error occurs.
|
||||
// Any errors returned by Destroy() itself are ignored.
|
||||
cu.Add(func() {
|
||||
c.Destroy()
|
||||
})
|
||||
} else {
|
||||
runArgs.Spec = c.Spec
|
||||
}
|
||||
|
||||
log.Debugf("Restore: %v", conf.RestoreFile)
|
||||
if err := c.Restore(runArgs.Spec, conf, conf.RestoreFile); err != nil {
|
||||
return util.Errorf("starting container: %v", err)
|
||||
}
|
||||
|
||||
// If we allocate a terminal, forward signals to the sandbox process.
|
||||
// Otherwise, Ctrl+C will terminate this process and its children,
|
||||
// including the terminal.
|
||||
if c.Spec.Process.Terminal {
|
||||
stopForwarding := c.ForwardSignals(0, true /* fgProcess */)
|
||||
defer stopForwarding()
|
||||
}
|
||||
|
||||
var ws unix.WaitStatus
|
||||
if runArgs.Attached {
|
||||
if ws, err = c.Wait(); err != nil {
|
||||
return util.Errorf("running container: %v", err)
|
||||
}
|
||||
}
|
||||
*waitStatus = ws
|
||||
|
||||
cu.Release()
|
||||
|
||||
return subcommands.ExitSuccess
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user