summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorGoogler <noreply@google.com>2018-06-06 11:43:01 -0700
committerShentubot <shentubot@google.com>2018-06-06 11:43:55 -0700
commit722275c3d1a7b420915e6e6a3d623ae941c494cf (patch)
treef38faf0a5cc1dcd57815ea71973c9487c2913e9d
parentff7b4a156f95a587b5df4de89a22c200fceabb96 (diff)
Added a function to the controller to checkpoint a container.
Functionality for checkpoint is not complete, more to come. PiperOrigin-RevId: 199500803 Change-Id: Iafb0fcde68c584270000fea898e6657a592466f7
-rw-r--r--pkg/sentry/control/BUILD4
-rw-r--r--pkg/sentry/control/state.go73
-rw-r--r--runsc/boot/controller.go19
-rw-r--r--runsc/boot/loader.go6
4 files changed, 99 insertions, 3 deletions
diff --git a/pkg/sentry/control/BUILD b/pkg/sentry/control/BUILD
index 4d1d0d019..6169891f7 100644
--- a/pkg/sentry/control/BUILD
+++ b/pkg/sentry/control/BUILD
@@ -7,6 +7,7 @@ go_library(
srcs = [
"control.go",
"proc.go",
+ "state.go",
],
importpath = "gvisor.googlesource.com/gvisor/pkg/sentry/control",
visibility = [
@@ -14,6 +15,7 @@ go_library(
],
deps = [
"//pkg/abi/linux",
+ "//pkg/log",
"//pkg/sentry/fs",
"//pkg/sentry/fs/host",
"//pkg/sentry/kernel",
@@ -21,7 +23,9 @@ go_library(
"//pkg/sentry/kernel/kdefs",
"//pkg/sentry/kernel/time",
"//pkg/sentry/limits",
+ "//pkg/sentry/state",
"//pkg/sentry/usage",
+ "//pkg/sentry/watchdog",
"//pkg/urpc",
],
)
diff --git a/pkg/sentry/control/state.go b/pkg/sentry/control/state.go
new file mode 100644
index 000000000..cee4db636
--- /dev/null
+++ b/pkg/sentry/control/state.go
@@ -0,0 +1,73 @@
+// Copyright 2018 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package control
+
+import (
+ "errors"
+
+ "gvisor.googlesource.com/gvisor/pkg/log"
+ "gvisor.googlesource.com/gvisor/pkg/sentry/kernel"
+ "gvisor.googlesource.com/gvisor/pkg/sentry/state"
+ "gvisor.googlesource.com/gvisor/pkg/sentry/watchdog"
+ "gvisor.googlesource.com/gvisor/pkg/urpc"
+)
+
+// ErrInvalidFiles is returned when the urpc call to Save does not include an
+// appropriate file payload (e.g. there is no output file!).
+var ErrInvalidFiles = errors.New("exactly one file must be provided")
+
+// State includes state-related functions.
+type State struct {
+ Kernel *kernel.Kernel
+ Watchdog *watchdog.Watchdog
+}
+
+// SaveOpts contains options for the Save RPC call.
+type SaveOpts struct {
+ // Key is used for state integrity check.
+ Key []byte `json:"key"`
+
+ // Metadata is the set of metadata to prepend to the state file.
+ Metadata map[string]string `json:"metadata"`
+
+ // FilePayload contains the destination for the state.
+ urpc.FilePayload
+}
+
+// Save saves the running system.
+func (s *State) Save(o *SaveOpts, _ *struct{}) error {
+ // Create an output stream.
+ if len(o.FilePayload.Files) != 1 {
+ return ErrInvalidFiles
+ }
+ defer o.FilePayload.Files[0].Close()
+
+ // Save to the first provided stream.
+ saveOpts := state.SaveOpts{
+ Destination: o.FilePayload.Files[0],
+ Key: o.Key,
+ Metadata: o.Metadata,
+ Callback: func(err error) {
+ if err == nil {
+ log.Infof("Save succeeded: exiting...")
+ } else {
+ log.Warningf("Save failed: exiting...")
+ s.Kernel.SetExitError(err)
+ }
+ s.Kernel.Kill(kernel.ExitStatus{})
+ },
+ }
+ return saveOpts.Save(s.Kernel, s.Watchdog)
+}
diff --git a/runsc/boot/controller.go b/runsc/boot/controller.go
index 8fc0a9076..095b0a9b9 100644
--- a/runsc/boot/controller.go
+++ b/runsc/boot/controller.go
@@ -22,9 +22,13 @@ import (
"gvisor.googlesource.com/gvisor/pkg/sentry/control"
"gvisor.googlesource.com/gvisor/pkg/sentry/kernel"
"gvisor.googlesource.com/gvisor/pkg/sentry/socket/epsocket"
+ "gvisor.googlesource.com/gvisor/pkg/sentry/watchdog"
)
const (
+ // ContainerCheckpoint checkpoints a container.
+ ContainerCheckpoint = "containerManager.Checkpoint"
+
// ContainerEvent is the URPC endpoint for getting stats about the
// container used by "runsc events".
ContainerEvent = "containerManager.Event"
@@ -69,7 +73,7 @@ type controller struct {
}
// newController creates a new controller and starts it listening.
-func newController(fd int, k *kernel.Kernel) (*controller, error) {
+func newController(fd int, k *kernel.Kernel, w *watchdog.Watchdog) (*controller, error) {
srv, err := server.CreateFromFD(fd)
if err != nil {
return nil, err
@@ -79,6 +83,7 @@ func newController(fd int, k *kernel.Kernel) (*controller, error) {
startChan: make(chan struct{}),
startResultChan: make(chan error),
k: k,
+ watchdog: w,
}
srv.Register(manager)
@@ -113,6 +118,9 @@ type containerManager struct {
// k is the emulated linux kernel on which the sandboxed
// containers run.
k *kernel.Kernel
+
+ // watchdog is the kernel watchdog.
+ watchdog *watchdog.Watchdog
}
// StartRoot will start the root container process.
@@ -136,6 +144,15 @@ func (cm *containerManager) Execute(e *control.ExecArgs, waitStatus *uint32) err
return nil
}
+// Checkpoint pauses a sandbox and saves its state.
+func (cm *containerManager) Checkpoint(o *control.SaveOpts, _ *struct{}) error {
+ state := control.State{
+ Kernel: cm.k,
+ Watchdog: cm.watchdog,
+ }
+ return state.Save(o, nil)
+}
+
// Wait waits for the init process in the given container.
func (cm *containerManager) Wait(cid *string, waitStatus *uint32) error {
// TODO: Use the cid and wait on the init process in that
diff --git a/runsc/boot/loader.go b/runsc/boot/loader.go
index 76edbb905..41d1ee50d 100644
--- a/runsc/boot/loader.go
+++ b/runsc/boot/loader.go
@@ -186,6 +186,9 @@ func New(spec *specs.Spec, conf *Config, controllerFD int, ioFDs []int, console
atomic.StoreUint32(&sniffer.LogPackets, 0)
}
+ // Create a watchdog.
+ watchdog := watchdog.New(k, watchdog.DefaultTimeout, watchdog.LogWarning)
+
// Create the control server using the provided FD.
//
// This must be done *after* we have initialized the kernel since the
@@ -195,7 +198,7 @@ func New(spec *specs.Spec, conf *Config, controllerFD int, ioFDs []int, console
// misconfigured process will cause an error, and we want the control
// server up before that so that we don't time out trying to connect to
// it.
- ctrl, err := newController(controllerFD, k)
+ ctrl, err := newController(controllerFD, k, watchdog)
if err != nil {
return nil, fmt.Errorf("error creating control server: %v", err)
}
@@ -254,7 +257,6 @@ func New(spec *specs.Spec, conf *Config, controllerFD int, ioFDs []int, console
// the emulated kernel.
stopSignalForwarding := sighandling.StartForwarding(k)
- watchdog := watchdog.New(k, watchdog.DefaultTimeout, watchdog.LogWarning)
return &Loader{
k: k,
ctrl: ctrl,