Skip to content
This repository has been archived by the owner on May 12, 2021. It is now read-only.

Commit

Permalink
API: add sandbox signalprocess api
Browse files Browse the repository at this point in the history
It sends the signal to a process of a container, or all processes
inside a container.

Signed-off-by: Peng Tao <[email protected]>
  • Loading branch information
bergwolf committed May 4, 2018
1 parent 45970ba commit 55dc0b2
Show file tree
Hide file tree
Showing 10 changed files with 99 additions and 12 deletions.
6 changes: 3 additions & 3 deletions virtcontainers/agent.go
Original file line number Diff line number Diff line change
Expand Up @@ -160,10 +160,10 @@ type agent interface {
// stopContainer will tell the agent to stop a container related to a Sandbox.
stopContainer(sandbox *Sandbox, c Container) error

// killContainer will tell the agent to send a signal to a
// container related to a Sandbox. If all is true, all processes in
// signalProcess will tell the agent to send a signal to a
// container or a process related to a Sandbox. If all is true, all processes in
// the container will be sent the signal.
killContainer(sandbox *Sandbox, c Container, signal syscall.Signal, all bool) error
signalProcess(c *Container, processID string, signal syscall.Signal, all bool) error

// processListContainer will list the processes running inside the container
processListContainer(sandbox *Sandbox, c Container, options ProcessListOptions) (ProcessList, error)
Expand Down
10 changes: 7 additions & 3 deletions virtcontainers/container.go
Original file line number Diff line number Diff line change
Expand Up @@ -663,7 +663,7 @@ func (c *Container) stop() error {
// return an error, but instead try to kill it forcefully.
if err := waitForShim(c.process.Pid); err != nil {
// Force the container to be killed.
if err := c.sandbox.agent.killContainer(c.sandbox, *c, syscall.SIGKILL, true); err != nil {
if err := c.kill(syscall.SIGKILL, true); err != nil {
return err
}

Expand All @@ -684,7 +684,7 @@ func (c *Container) stop() error {
// this signal will ensure the container will get killed to match
// the state of the shim. This will allow the following call to
// stopContainer() to succeed in such particular case.
c.sandbox.agent.killContainer(c.sandbox, *c, syscall.SIGKILL, true)
c.kill(syscall.SIGKILL, true)

if err := c.sandbox.agent.stopContainer(c.sandbox, *c); err != nil {
return err
Expand Down Expand Up @@ -735,6 +735,10 @@ func (c *Container) wait(processID string) (int32, error) {
}

func (c *Container) kill(signal syscall.Signal, all bool) error {
return c.signalProcess(c.process.Token, signal, all)
}

func (c *Container) signalProcess(processID string, signal syscall.Signal, all bool) error {
if c.sandbox.state.State != StateReady && c.sandbox.state.State != StateRunning {
return fmt.Errorf("Sandbox not ready or running, impossible to signal the container")
}
Expand All @@ -743,7 +747,7 @@ func (c *Container) kill(signal syscall.Signal, all bool) error {
return fmt.Errorf("Container not ready or running, impossible to signal the container")
}

return c.sandbox.agent.killContainer(c.sandbox, *c, signal, all)
return c.sandbox.agent.signalProcess(c, processID, signal, all)
}

func (c *Container) processList(options ProcessListOptions) (ProcessList, error) {
Expand Down
24 changes: 24 additions & 0 deletions virtcontainers/container_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -385,3 +385,27 @@ func TestContainerWaitErrorState(t *testing.T) {
_, err = c.wait(processID)
assert.Error(err)
}

func TestKillContainerErrorState(t *testing.T) {
assert := assert.New(t)
c := &Container{
sandbox: &Sandbox{
state: State{
State: StateRunning,
},
},
}
// Container state undefined
err := c.kill(syscall.SIGKILL, true)
assert.Error(err)

// Container paused
c.state.State = StatePaused
err = c.kill(syscall.SIGKILL, false)
assert.Error(err)

// Container stopped
c.state.State = StateStopped
err = c.kill(syscall.SIGKILL, true)
assert.Error(err)
}
4 changes: 2 additions & 2 deletions virtcontainers/hyperstart_agent.go
Original file line number Diff line number Diff line change
Expand Up @@ -571,8 +571,8 @@ func (h *hyper) stopOneContainer(sandboxID string, c Container) error {
return nil
}

// killContainer is the agent process signal implementation for hyperstart.
func (h *hyper) killContainer(sandbox *Sandbox, c Container, signal syscall.Signal, all bool) error {
// signalProcess is the agent process signal implementation for hyperstart.
func (h *hyper) signalProcess(c *Container, processID string, signal syscall.Signal, all bool) error {
// Send the signal to the shim directly in case the container has not
// been started yet.
if c.state.State == StateReady {
Expand Down
1 change: 1 addition & 0 deletions virtcontainers/interfaces.go
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ type VCSandbox interface {
StatusContainer(containerID string) (ContainerStatus, error)
EnterContainer(containerID string, cmd Cmd) (VCContainer, *Process, error)
WaitProcess(containerID, processID string) (int32, error)
SignalProcess(containerID, processID string, signal syscall.Signal, all bool) error
}

// VCContainer is the Container interface
Expand Down
9 changes: 7 additions & 2 deletions virtcontainers/kata_agent.go
Original file line number Diff line number Diff line change
Expand Up @@ -860,10 +860,15 @@ func (k *kataAgent) stopContainer(sandbox *Sandbox, c Container) error {
return bindUnmountContainerRootfs(kataHostSharedDir, sandbox.id, c.id)
}

func (k *kataAgent) killContainer(sandbox *Sandbox, c Container, signal syscall.Signal, all bool) error {
func (k *kataAgent) signalProcess(c *Container, processID string, signal syscall.Signal, all bool) error {
execID := processID
if all {
// kata agent uses empty execId to signal all processes in a container
execID = ""
}
req := &grpc.SignalProcessRequest{
ContainerId: c.id,
ExecId: c.process.Token,
ExecId: execID,
Signal: uint32(signal),
}

Expand Down
4 changes: 2 additions & 2 deletions virtcontainers/noop_agent.go
Original file line number Diff line number Diff line change
Expand Up @@ -64,8 +64,8 @@ func (n *noopAgent) stopContainer(sandbox *Sandbox, c Container) error {
return nil
}

// killContainer is the Noop agent Container signaling implementation. It does nothing.
func (n *noopAgent) killContainer(sandbox *Sandbox, c Container, signal syscall.Signal, all bool) error {
// signalProcess is the Noop agent Container signaling implementation. It does nothing.
func (n *noopAgent) signalProcess(c *Container, processID string, signal syscall.Signal, all bool) error {
return nil
}

Expand Down
7 changes: 7 additions & 0 deletions virtcontainers/pkg/vcmock/sandbox.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@
package vcmock

import (
"syscall"

vc "github.com/kata-containers/runtime/virtcontainers"
)

Expand Down Expand Up @@ -109,3 +111,8 @@ func (p *Sandbox) Monitor() (chan error, error) {
func (p *Sandbox) WaitProcess(containerID, processID string) (int32, error) {
return 0, nil
}

// SignalProcess implements the VCSandbox function of the same name.
func (p *Sandbox) SignalProcess(containerID, processID string, signal syscall.Signal, all bool) error {
return nil
}
15 changes: 15 additions & 0 deletions virtcontainers/sandbox.go
Original file line number Diff line number Diff line change
Expand Up @@ -601,6 +601,21 @@ func (s *Sandbox) WaitProcess(containerID, processID string) (int32, error) {
return c.wait(processID)
}

// SignalProcess sends a signal to a process of a container when all is false.
// When all is true, it sends the signal to all processes of a container.
func (s *Sandbox) SignalProcess(containerID, processID string, signal syscall.Signal, all bool) error {
if s.state.State != StateRunning {
return fmt.Errorf("Sandbox not running")
}

c, err := s.findContainer(containerID)
if err != nil {
return err
}

return c.signalProcess(processID, signal, all)
}

func createAssets(sandboxConfig *SandboxConfig) error {
kernel, err := newAsset(sandboxConfig, kernelAsset)
if err != nil {
Expand Down
31 changes: 31 additions & 0 deletions virtcontainers/sandbox_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import (
"path/filepath"
"reflect"
"sync"
"syscall"
"testing"

"github.com/kata-containers/runtime/virtcontainers/pkg/annotations"
Expand Down Expand Up @@ -1438,3 +1439,33 @@ func TestWaitProcess(t *testing.T) {
_, err = s.WaitProcess(contID, execID)
assert.Nil(t, err, "Wait process failed: %v", err)
}

func TestSignalProcess(t *testing.T) {
s, err := testCreateSandbox(t, testSandboxID, MockHypervisor, newHypervisorConfig(nil, nil), NoopAgentType, NoopNetworkModel, NetworkConfig{}, nil, nil)
assert.Nil(t, err, "VirtContainers should not allow empty sandboxes")
defer cleanUp()

contID := "foo"
execID := "bar"
err = s.SignalProcess(contID, execID, syscall.SIGKILL, true)
assert.NotNil(t, err, "Wait process in stopped sandbox should fail")

err = s.start()
assert.Nil(t, err, "Failed to start sandbox: %v", err)

err = s.SignalProcess(contID, execID, syscall.SIGKILL, false)
assert.NotNil(t, err, "Wait process in non-existing container should fail")

contConfig := newTestContainerConfigNoop(contID)
_, err = s.CreateContainer(contConfig)
assert.Nil(t, err, "Failed to create container %+v in sandbox %+v: %v", contConfig, s, err)

err = s.SignalProcess(contID, execID, syscall.SIGKILL, true)
assert.Nil(t, err, "Wait process in ready container failed: %v", err)

_, err = s.StartContainer(contID)
assert.Nil(t, err, "Start container failed: %v", err)

err = s.SignalProcess(contID, execID, syscall.SIGKILL, false)
assert.Nil(t, err, "Wait process failed: %v", err)
}

0 comments on commit 55dc0b2

Please sign in to comment.