mirror of
https://github.com/netbirdio/gvisor.git
synced 2026-05-22 17:12:49 -07:00
Added code for a pause command for a container process.
Like runc, the pause command will pause the processes of the given container. It will set that container's status to "paused." A resume command will be be added to unpause and continue running the process. PiperOrigin-RevId: 200789624 Change-Id: I72a5d7813d90ecfc4d01cc252d6018855016b1ea
This commit is contained in:
committed by
Shentubot
parent
bd2d1aaa16
commit
0786707cd9
@@ -37,6 +37,9 @@ const (
|
||||
// container..
|
||||
ContainerExecute = "containerManager.Execute"
|
||||
|
||||
// ContainerPause pauses the container.
|
||||
ContainerPause = "containerManager.Pause"
|
||||
|
||||
// ContainerProcesses is the URPC endpoint for getting the list of
|
||||
// processes running in a container.
|
||||
ContainerProcesses = "containerManager.Processes"
|
||||
@@ -153,6 +156,12 @@ func (cm *containerManager) Checkpoint(o *control.SaveOpts, _ *struct{}) error {
|
||||
return state.Save(o, nil)
|
||||
}
|
||||
|
||||
// Pause suspends the process in a container.
|
||||
func (cm *containerManager) Pause(_, _ *struct{}) error {
|
||||
cm.k.Pause()
|
||||
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
|
||||
|
||||
@@ -17,6 +17,7 @@ go_library(
|
||||
"kill.go",
|
||||
"list.go",
|
||||
"path.go",
|
||||
"pause.go",
|
||||
"ps.go",
|
||||
"restore.go",
|
||||
"run.go",
|
||||
|
||||
@@ -0,0 +1,67 @@
|
||||
// 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 cmd
|
||||
|
||||
import (
|
||||
"context"
|
||||
"flag"
|
||||
"github.com/google/subcommands"
|
||||
"gvisor.googlesource.com/gvisor/runsc/boot"
|
||||
"gvisor.googlesource.com/gvisor/runsc/container"
|
||||
)
|
||||
|
||||
// Pause implements subcommands.Command for the "pause" command.
|
||||
type Pause struct{}
|
||||
|
||||
// Name implements subcommands.Command.Name.
|
||||
func (*Pause) Name() string {
|
||||
return "pause"
|
||||
}
|
||||
|
||||
// Synopsis implements subcommands.Command.Synopsis.
|
||||
func (*Pause) Synopsis() string {
|
||||
return "pause suspends all processes in a container"
|
||||
}
|
||||
|
||||
// Usage implements subcommands.Command.Usage.
|
||||
func (*Pause) Usage() string {
|
||||
return `pause <container id> - pause process in instance of container.`
|
||||
}
|
||||
|
||||
// SetFlags implements subcommands.Command.SetFlags.
|
||||
func (*Pause) SetFlags(f *flag.FlagSet) {
|
||||
}
|
||||
|
||||
// Execute implements subcommands.Command.Execute.
|
||||
func (*Pause) Execute(_ context.Context, f *flag.FlagSet, args ...interface{}) subcommands.ExitStatus {
|
||||
if f.NArg() != 1 {
|
||||
f.Usage()
|
||||
return subcommands.ExitUsageError
|
||||
}
|
||||
|
||||
id := f.Arg(0)
|
||||
conf := args[0].(*boot.Config)
|
||||
|
||||
cont, err := container.Load(conf.RootDir, id)
|
||||
if err != nil {
|
||||
Fatalf("error loading container: %v", err)
|
||||
}
|
||||
|
||||
if err := cont.Pause(); err != nil {
|
||||
Fatalf("pause failed: %v", err)
|
||||
}
|
||||
|
||||
return subcommands.ExitSuccess
|
||||
}
|
||||
@@ -316,7 +316,7 @@ func (c *Container) Event() (*boot.Event, error) {
|
||||
// Pid returns the Pid of the sandbox the container is running in, or -1 if the
|
||||
// container is not running.
|
||||
func (c *Container) Pid() int {
|
||||
if c.Status != Running && c.Status != Created {
|
||||
if c.Status != Running && c.Status != Created && c.Status != Paused {
|
||||
return -1
|
||||
}
|
||||
return c.Sandbox.Pid
|
||||
@@ -349,6 +349,23 @@ func (c *Container) Checkpoint(f *os.File) error {
|
||||
return c.Sandbox.Checkpoint(c.ID, f)
|
||||
}
|
||||
|
||||
// Pause suspends the container and its kernel.
|
||||
// The call only succeeds if the container's status is created or running.
|
||||
func (c *Container) Pause() error {
|
||||
log.Debugf("Pausing container %q", c.ID)
|
||||
switch c.Status {
|
||||
case Created, Running:
|
||||
if err := c.Sandbox.Pause(c.ID); err != nil {
|
||||
return fmt.Errorf("error pausing container: %v", err)
|
||||
}
|
||||
c.Status = Paused
|
||||
return c.save()
|
||||
default:
|
||||
log.Warningf("container %q not created or running, not pausing", c.ID)
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// State returns the metadata of the container.
|
||||
func (c *Container) State() specs.State {
|
||||
return specs.State{
|
||||
|
||||
@@ -459,6 +459,40 @@ func TestCheckpoint(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
// TestPause tests that calling pause successfully pauses the container.
|
||||
// It checks that no errors are returned and that the state of the container
|
||||
// is in fact 'Paused.'
|
||||
func TestPause(t *testing.T) {
|
||||
spec := testutil.NewSpecWithArgs("sleep", "100")
|
||||
|
||||
rootDir, bundleDir, conf, err := testutil.SetupContainer(spec)
|
||||
if err != nil {
|
||||
t.Fatalf("error setting up container: %v", err)
|
||||
}
|
||||
defer os.RemoveAll(rootDir)
|
||||
defer os.RemoveAll(bundleDir)
|
||||
|
||||
// Create and start the container.
|
||||
cont, err := container.Create(testutil.UniqueContainerID(), spec, conf, bundleDir, "", "")
|
||||
if err != nil {
|
||||
t.Fatalf("error creating container: %v", err)
|
||||
}
|
||||
defer cont.Destroy()
|
||||
if err := cont.Start(conf); err != nil {
|
||||
t.Fatalf("error starting container: %v", err)
|
||||
}
|
||||
|
||||
// Pause the running container.
|
||||
if err := cont.Pause(); err != nil {
|
||||
t.Errorf("error pausing container: %v", err)
|
||||
}
|
||||
|
||||
// Confirm the status of the container is paused.
|
||||
if got, want := cont.Status, container.Paused; got != want {
|
||||
t.Errorf("container status got %v, want %v", got, want)
|
||||
}
|
||||
}
|
||||
|
||||
// TestCapabilities verifies that:
|
||||
// - Running exec as non-root UID and GID will result in an error (because the
|
||||
// executable file can't be read).
|
||||
|
||||
@@ -19,13 +19,17 @@ package container
|
||||
type Status int
|
||||
|
||||
const (
|
||||
// Creating indicates "the container is being created".
|
||||
Creating Status = iota
|
||||
|
||||
// Created indicates "the runtime has finished the create operation and
|
||||
// the container process has neither exited nor executed the
|
||||
// user-specified program".
|
||||
Created
|
||||
Created Status = iota
|
||||
|
||||
// Creating indicates "the container is being created".
|
||||
Creating
|
||||
|
||||
// Paused indicates that the process within the container has been
|
||||
// suspended.
|
||||
Paused
|
||||
|
||||
// Running indicates "the container process has executed the
|
||||
// user-specified program but has not exited".
|
||||
@@ -39,10 +43,12 @@ const (
|
||||
// CLI spec and should not be changed.
|
||||
func (s Status) String() string {
|
||||
switch s {
|
||||
case Creating:
|
||||
return "creating"
|
||||
case Created:
|
||||
return "created"
|
||||
case Creating:
|
||||
return "creating"
|
||||
case Paused:
|
||||
return "paused"
|
||||
case Running:
|
||||
return "running"
|
||||
case Stopped:
|
||||
|
||||
@@ -464,6 +464,21 @@ func (s *Sandbox) Checkpoint(cid string, f *os.File) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Pause sends the pause call for a container in the sandbox.
|
||||
func (s *Sandbox) Pause(cid string) error {
|
||||
log.Debugf("Pause sandbox %q", s.ID)
|
||||
conn, err := s.connect()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer conn.Close()
|
||||
|
||||
if err := conn.Call(boot.ContainerPause, nil, nil); err != nil {
|
||||
return fmt.Errorf("err pausing container %q: %v", cid, err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// IsRunning returns true if the sandbox or gofer process is running.
|
||||
func (s *Sandbox) IsRunning() bool {
|
||||
if s.Pid != 0 {
|
||||
|
||||
Reference in New Issue
Block a user