summaryrefslogtreecommitdiffhomepage
path: root/runsc/boot
diff options
context:
space:
mode:
authorNicolas Lacasse <nlacasse@google.com>2018-05-17 11:54:36 -0700
committerShentubot <shentubot@google.com>2018-05-17 11:55:28 -0700
commit31386185fe7c2079ee412a411e536a5bf9e9eb25 (patch)
treeb74f2fa66e0b95b705b27f2e335910091961bcd6 /runsc/boot
parent8e1deb2ab8fb67da9a1f6521e31c5635ac587e71 (diff)
Push signal-delivery and wait into the sandbox.
This is another step towards multi-container support. Previously, we delivered signals directly to the sandbox process (which then forwarded the signal to PID 1 inside the sandbox). Similarly, we waited on a container by waiting on the sandbox process itself. This approach will not work when there are multiple containers inside the sandbox, and we need to signal/wait on individual containers. This CL adds two new messages, ContainerSignal and ContainerWait. These messages include the id of the container to signal/wait. The controller inside the sandbox receives these messages and signals/waits on the appropriate process inside the sandbox. The container id is plumbed into the sandbox, but it currently is not used. We still end up signaling/waiting on PID 1 in all cases. Once we actually have multiple containers inside the sandbox, we will need to keep some sort of map of container id -> pid (or possibly pid namespace), and signal/kill the appropriate process for the container. PiperOrigin-RevId: 197028366 Change-Id: I07b4d5dc91ecd2affc1447e6b4bdd6b0b7360895
Diffstat (limited to 'runsc/boot')
-rw-r--r--runsc/boot/BUILD1
-rw-r--r--runsc/boot/controller.go112
-rw-r--r--runsc/boot/events.go7
-rw-r--r--runsc/boot/loader.go21
-rw-r--r--runsc/boot/loader_test.go14
5 files changed, 100 insertions, 55 deletions
diff --git a/runsc/boot/BUILD b/runsc/boot/BUILD
index 16522c668..1746df988 100644
--- a/runsc/boot/BUILD
+++ b/runsc/boot/BUILD
@@ -25,6 +25,7 @@ go_library(
"//pkg/control/server",
"//pkg/cpuid",
"//pkg/log",
+ "//pkg/sentry/arch",
"//pkg/sentry/context",
"//pkg/sentry/control",
"//pkg/sentry/fs",
diff --git a/runsc/boot/controller.go b/runsc/boot/controller.go
index 60c42fc19..8fc0a9076 100644
--- a/runsc/boot/controller.go
+++ b/runsc/boot/controller.go
@@ -18,30 +18,39 @@ import (
"fmt"
"gvisor.googlesource.com/gvisor/pkg/control/server"
+ "gvisor.googlesource.com/gvisor/pkg/sentry/arch"
"gvisor.googlesource.com/gvisor/pkg/sentry/control"
"gvisor.googlesource.com/gvisor/pkg/sentry/kernel"
"gvisor.googlesource.com/gvisor/pkg/sentry/socket/epsocket"
)
const (
- // ApplicationStart is the URPC endpoint for starting a sandboxed app.
- ApplicationStart = "application.Start"
+ // ContainerEvent is the URPC endpoint for getting stats about the
+ // container used by "runsc events".
+ ContainerEvent = "containerManager.Event"
- // ApplicationProcesses is the URPC endpoint for getting the list of
- // processes running in a sandbox.
- ApplicationProcesses = "application.Processes"
+ // ContainerExecute is the URPC endpoint for executing a command in a
+ // container..
+ ContainerExecute = "containerManager.Execute"
- // ApplicationExecute is the URPC endpoint for executing a command in a
- // sandbox.
- ApplicationExecute = "application.Execute"
+ // ContainerProcesses is the URPC endpoint for getting the list of
+ // processes running in a container.
+ ContainerProcesses = "containerManager.Processes"
- // ApplicationEvent is the URPC endpoint for getting stats about the
- // container used by "runsc events".
- ApplicationEvent = "application.Event"
+ // ContainerSignal is used to send a signal to a container.
+ ContainerSignal = "containerManager.Signal"
+
+ // ContainerWait is used to wait on the init process of the container
+ // and return its ExitStatus.
+ ContainerWait = "containerManager.Wait"
// NetworkCreateLinksAndRoutes is the URPC endpoint for creating links
// and routes in a network stack.
NetworkCreateLinksAndRoutes = "Network.CreateLinksAndRoutes"
+
+ // RootContainerStart is the URPC endpoint for starting a new sandbox
+ // with root container.
+ RootContainerStart = "containerManager.StartRoot"
)
// ControlSocketAddr generates an abstract unix socket name for the given id.
@@ -55,8 +64,8 @@ type controller struct {
// srv is the contorl server.
srv *server.Server
- // app holds the application methods.
- app *application
+ // manager holds the containerManager methods.
+ manager *containerManager
}
// newController creates a new controller and starts it listening.
@@ -66,12 +75,12 @@ func newController(fd int, k *kernel.Kernel) (*controller, error) {
return nil, err
}
- app := &application{
+ manager := &containerManager{
startChan: make(chan struct{}),
startResultChan: make(chan error),
k: k,
}
- srv.Register(app)
+ srv.Register(manager)
if eps, ok := k.NetworkStack().(*epsocket.Stack); ok {
net := &Network{
@@ -85,44 +94,79 @@ func newController(fd int, k *kernel.Kernel) (*controller, error) {
}
return &controller{
- srv: srv,
- app: app,
+ srv: srv,
+ manager: manager,
}, nil
}
-// application contains methods that control the sandboxed application.
-type application struct {
- // startChan is used to signal when the application process should be
- // started.
+// containerManager manages sandboes containers.
+type containerManager struct {
+ // startChan is used to signal when the root container process should
+ // be started.
startChan chan struct{}
- // startResultChan is used to signal when the application has started. Any
- // errors encountered during startup will be sent to the channel. A nil value
- // indicates success.
+ // startResultChan is used to signal when the root container has
+ // started. Any errors encountered during startup will be sent to the
+ // channel. A nil value indicates success.
startResultChan chan error
// k is the emulated linux kernel on which the sandboxed
- // application runs.
+ // containers run.
k *kernel.Kernel
}
-// Start will start the application process.
-func (a *application) Start(_, _ *struct{}) error {
- // Tell the application to start and wait for the result.
- a.startChan <- struct{}{}
- return <-a.startResultChan
+// StartRoot will start the root container process.
+func (cm *containerManager) StartRoot(_, _ *struct{}) error {
+ // Tell the root container to start and wait for the result.
+ cm.startChan <- struct{}{}
+ return <-cm.startResultChan
}
// Processes retrieves information about processes running in the sandbox.
-func (a *application) Processes(_, out *[]*control.Process) error {
- return control.Processes(a.k, out)
+func (cm *containerManager) Processes(_, out *[]*control.Process) error {
+ return control.Processes(cm.k, out)
}
// Execute runs a command on a created or running sandbox.
-func (a *application) Execute(e *control.ExecArgs, waitStatus *uint32) error {
- proc := control.Proc{Kernel: a.k}
+func (cm *containerManager) Execute(e *control.ExecArgs, waitStatus *uint32) error {
+ proc := control.Proc{Kernel: cm.k}
if err := proc.Exec(e, waitStatus); err != nil {
return fmt.Errorf("error executing: %+v: %v", e, err)
}
return 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
+ // container. Currently we just wait on PID 1 in the sandbox.
+ tg := cm.k.TaskSet().Root.ThreadGroupWithID(1)
+ if tg == nil {
+ return fmt.Errorf("cannot wait: no thread group with id 1")
+ }
+ tg.WaitExited()
+ *waitStatus = tg.ExitStatus().Status()
+ return nil
+}
+
+// SignalArgs are arguments to the Signal method.
+type SignalArgs struct {
+ // CID is the container id.
+ CID string
+
+ // Signo is the signal to send to the process.
+ Signo int32
+}
+
+// Signal sends a signal to the init process of the container.
+func (cm *containerManager) Signal(args *SignalArgs, _ *struct{}) error {
+ // TODO: Use the cid and send the signal to the init
+ // process in theat container. Currently we just signal PID 1 in the
+ // sandbox.
+ si := arch.SignalInfo{Signo: args.Signo}
+ t := cm.k.TaskSet().Root.TaskWithID(1)
+ if t == nil {
+ return fmt.Errorf("cannot signal: no task with id 1")
+ }
+ return t.SendSignal(&si)
+}
diff --git a/runsc/boot/events.go b/runsc/boot/events.go
index ef6459b01..0eb75c14c 100644
--- a/runsc/boot/events.go
+++ b/runsc/boot/events.go
@@ -59,10 +59,11 @@ type Memory struct {
Raw map[string]uint64 `json:"raw,omitempty"`
}
-func (a *application) Event(_ *struct{}, out *Event) error {
+// Event gets the events from the container.
+func (cm *containerManager) Event(_ *struct{}, out *Event) error {
stats := &Stats{}
- stats.populateMemory(a.k)
- stats.populatePIDs(a.k)
+ stats.populateMemory(cm.k)
+ stats.populatePIDs(cm.k)
*out = Event{Type: "stats", Data: stats}
return nil
}
diff --git a/runsc/boot/loader.go b/runsc/boot/loader.go
index 34a25241f..0ff54d349 100644
--- a/runsc/boot/loader.go
+++ b/runsc/boot/loader.go
@@ -12,7 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-// Package boot loads the kernel and runs the application.
+// Package boot loads the kernel and runs a container..
package boot
import (
@@ -57,7 +57,7 @@ import (
_ "gvisor.googlesource.com/gvisor/pkg/sentry/socket/unix"
)
-// Loader keeps state needed to start the kernel and run the application.
+// Loader keeps state needed to start the kernel and run the container..
type Loader struct {
// k is the kernel.
k *kernel.Kernel
@@ -73,10 +73,10 @@ type Loader struct {
watchdog *watchdog.Watchdog
// stopSignalForwarding disables forwarding of signals to the sandboxed
- // app. It should be called when a sandbox is destroyed.
+ // container. It should be called when a sandbox is destroyed.
stopSignalForwarding func()
- // procArgs refers to the initial application task.
+ // procArgs refers to the root container task.
procArgs kernel.CreateProcessArgs
}
@@ -283,10 +283,10 @@ func createPlatform(conf *Config) (platform.Platform, error) {
}
}
-// Run runs the application.
+// Run runs the root container..
func (l *Loader) Run() error {
err := l.run()
- l.ctrl.app.startResultChan <- err
+ l.ctrl.manager.startResultChan <- err
if err != nil {
// Give the controller some time to send the error to the
// runtime. If we return too quickly here the process will exit
@@ -321,7 +321,7 @@ func (l *Loader) run() error {
}
}
- // Create the initial application task.
+ // Create the root container init task.
if _, err := l.k.CreateProcess(l.procArgs); err != nil {
return fmt.Errorf("failed to create init process: %v", err)
}
@@ -335,13 +335,12 @@ func (l *Loader) run() error {
// WaitForStartSignal waits for a start signal from the control server.
func (l *Loader) WaitForStartSignal() {
- <-l.ctrl.app.startChan
+ <-l.ctrl.manager.startChan
}
-// WaitExit waits for the application to exit, and returns the application's
-// exit status.
+// WaitExit waits for the root container to exit, and returns its exit status.
func (l *Loader) WaitExit() kernel.ExitStatus {
- // Wait for application.
+ // Wait for container.
l.k.WaitExited()
return l.k.GlobalInit().ExitStatus()
diff --git a/runsc/boot/loader_test.go b/runsc/boot/loader_test.go
index c3d9887fa..d2e5fe74e 100644
--- a/runsc/boot/loader_test.go
+++ b/runsc/boot/loader_test.go
@@ -72,13 +72,13 @@ func TestRun(t *testing.T) {
var wg sync.WaitGroup
wg.Add(1)
go func() {
- resultChanErr = <-s.ctrl.app.startResultChan
+ resultChanErr = <-s.ctrl.manager.startResultChan
wg.Done()
}()
- // Run the application.
+ // Run the container..
if err := s.Run(); err != nil {
- t.Errorf("error running application: %v", err)
+ t.Errorf("error running container: %v", err)
}
// We should have not gotten an error on the startResultChan.
@@ -112,7 +112,7 @@ func TestStartSignal(t *testing.T) {
go func() {
s.WaitForStartSignal()
// Pretend that Run() executed and returned no error.
- s.ctrl.app.startResultChan <- nil
+ s.ctrl.manager.startResultChan <- nil
waitFinished <- struct{}{}
}()
@@ -126,9 +126,9 @@ func TestStartSignal(t *testing.T) {
// OK.
}
- // Trigger the control server Start method.
- if err := s.ctrl.app.Start(nil, nil); err != nil {
- t.Errorf("error calling Start: %v", err)
+ // Trigger the control server StartRoot method.
+ if err := s.ctrl.manager.StartRoot(nil, nil); err != nil {
+ t.Errorf("error calling StartRoot: %v", err)
}
// Now WaitForStartSignal should return (within a short amount of