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
This commit is contained in:
Googler
2018-06-06 11:43:55 -07:00
committed by Shentubot
parent ff7b4a156f
commit 722275c3d1
4 changed files with 99 additions and 3 deletions
+4
View File
@@ -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",
],
)
+73
View File
@@ -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)
}
+18 -1
View File
@@ -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
+4 -2
View File
@@ -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,