mirror of
https://github.com/netbirdio/gvisor.git
synced 2026-05-22 17:12:49 -07:00
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:
@@ -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",
|
||||
],
|
||||
)
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
@@ -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
|
||||
|
||||
@@ -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,
|
||||
|
||||
Reference in New Issue
Block a user