API: add sandbox winsizeprocess api

It sends tty resize request to the agent to resize a process's tty
window.

Signed-off-by: Peng Tao <bergwolf@gmail.com>
This commit is contained in:
Peng Tao 2018-04-25 22:22:06 +08:00
parent 55dc0b2995
commit bf4ef4324e
10 changed files with 112 additions and 0 deletions

View File

@ -165,6 +165,9 @@ type agent interface {
// the container will be sent the signal. // the container will be sent the signal.
signalProcess(c *Container, processID string, signal syscall.Signal, all bool) error signalProcess(c *Container, processID string, signal syscall.Signal, all bool) error
// winsizeProcess will tell the agent to set a process' tty size
winsizeProcess(c *Container, processID string, height, width uint32) error
// processListContainer will list the processes running inside the container // processListContainer will list the processes running inside the container
processListContainer(sandbox *Sandbox, c Container, options ProcessListOptions) (ProcessList, error) processListContainer(sandbox *Sandbox, c Container, options ProcessListOptions) (ProcessList, error)

View File

@ -750,6 +750,14 @@ func (c *Container) signalProcess(processID string, signal syscall.Signal, all b
return c.sandbox.agent.signalProcess(c, processID, signal, all) return c.sandbox.agent.signalProcess(c, processID, signal, all)
} }
func (c *Container) winsizeProcess(processID string, height, width uint32) error {
if c.state.State != StateReady && c.state.State != StateRunning {
return fmt.Errorf("Container not ready or running, impossible to signal the container")
}
return c.sandbox.agent.winsizeProcess(c, processID, height, width)
}
func (c *Container) processList(options ProcessListOptions) (ProcessList, error) { func (c *Container) processList(options ProcessListOptions) (ProcessList, error) {
if err := c.checkSandboxRunning("ps"); err != nil { if err := c.checkSandboxRunning("ps"); err != nil {
return nil, err return nil, err

View File

@ -409,3 +409,29 @@ func TestKillContainerErrorState(t *testing.T) {
err = c.kill(syscall.SIGKILL, true) err = c.kill(syscall.SIGKILL, true)
assert.Error(err) assert.Error(err)
} }
func TestWinsizeProcessErrorState(t *testing.T) {
assert := assert.New(t)
c := &Container{
sandbox: &Sandbox{
state: State{
State: StateRunning,
},
},
}
processID := "foobar"
// Container state undefined
err := c.winsizeProcess(processID, 100, 200)
assert.Error(err)
// Container paused
c.state.State = StatePaused
err = c.winsizeProcess(processID, 100, 200)
assert.Error(err)
// Container stopped
c.state.State = StateStopped
err = c.winsizeProcess(processID, 100, 200)
assert.Error(err)
}

View File

@ -811,3 +811,8 @@ func (h *hyper) waitProcess(c *Container, processID string) (int32, error) {
// cc-agent does not support wait process // cc-agent does not support wait process
return 0, nil return 0, nil
} }
func (h *hyper) winsizeProcess(c *Container, processID string, height, width uint32) error {
// cc-agent does not support winsize process
return nil
}

View File

@ -59,6 +59,7 @@ type VCSandbox interface {
EnterContainer(containerID string, cmd Cmd) (VCContainer, *Process, error) EnterContainer(containerID string, cmd Cmd) (VCContainer, *Process, error)
WaitProcess(containerID, processID string) (int32, error) WaitProcess(containerID, processID string) (int32, error)
SignalProcess(containerID, processID string, signal syscall.Signal, all bool) error SignalProcess(containerID, processID string, signal syscall.Signal, all bool) error
WinsizeProcess(containerID, processID string, height, width uint32) error
} }
// VCContainer is the Container interface // VCContainer is the Container interface

View File

@ -876,6 +876,18 @@ func (k *kataAgent) signalProcess(c *Container, processID string, signal syscall
return err return err
} }
func (k *kataAgent) winsizeProcess(c *Container, processID string, height, width uint32) error {
req := &grpc.TtyWinResizeRequest{
ContainerId: c.id,
ExecId: processID,
Row: height,
Column: width,
}
_, err := k.sendReq(req)
return err
}
func (k *kataAgent) processListContainer(sandbox *Sandbox, c Container, options ProcessListOptions) (ProcessList, error) { func (k *kataAgent) processListContainer(sandbox *Sandbox, c Container, options ProcessListOptions) (ProcessList, error) {
req := &grpc.ListProcessesRequest{ req := &grpc.ListProcessesRequest{
ContainerId: c.id, ContainerId: c.id,
@ -999,6 +1011,9 @@ func (k *kataAgent) installReqFunc(c *kataclient.AgentClient) {
k.reqHandlers["grpc.WaitProcessRequest"] = func(ctx context.Context, req interface{}, opts ...golangGrpc.CallOption) (interface{}, error) { k.reqHandlers["grpc.WaitProcessRequest"] = func(ctx context.Context, req interface{}, opts ...golangGrpc.CallOption) (interface{}, error) {
return k.client.WaitProcess(ctx, req.(*grpc.WaitProcessRequest), opts...) return k.client.WaitProcess(ctx, req.(*grpc.WaitProcessRequest), opts...)
} }
k.reqHandlers["grpc.TtyWinResizeRequest"] = func(ctx context.Context, req interface{}, opts ...golangGrpc.CallOption) (interface{}, error) {
return k.client.TtyWinResize(ctx, req.(*grpc.TtyWinResizeRequest), opts...)
}
} }
func (k *kataAgent) sendReq(request interface{}) (interface{}, error) { func (k *kataAgent) sendReq(request interface{}) (interface{}, error) {

View File

@ -88,3 +88,8 @@ func (n *noopAgent) check() error {
func (n *noopAgent) waitProcess(c *Container, processID string) (int32, error) { func (n *noopAgent) waitProcess(c *Container, processID string) (int32, error) {
return 0, nil return 0, nil
} }
// winsizeProcess is the Noop agent process tty resizer. It does nothing.
func (n *noopAgent) winsizeProcess(c *Container, processID string, height, width uint32) error {
return nil
}

View File

@ -116,3 +116,8 @@ func (p *Sandbox) WaitProcess(containerID, processID string) (int32, error) {
func (p *Sandbox) SignalProcess(containerID, processID string, signal syscall.Signal, all bool) error { func (p *Sandbox) SignalProcess(containerID, processID string, signal syscall.Signal, all bool) error {
return nil return nil
} }
// WinsizeProcess implements the VCSandbox function of the same name.
func (p *Sandbox) WinsizeProcess(containerID, processID string, height, width uint32) error {
return nil
}

View File

@ -616,6 +616,20 @@ func (s *Sandbox) SignalProcess(containerID, processID string, signal syscall.Si
return c.signalProcess(processID, signal, all) return c.signalProcess(processID, signal, all)
} }
// WinsizeProcess resizes the tty window of a process
func (s *Sandbox) WinsizeProcess(containerID, processID string, height, width uint32) error {
if s.state.State != StateRunning {
return fmt.Errorf("Sandbox not running")
}
c, err := s.findContainer(containerID)
if err != nil {
return err
}
return c.winsizeProcess(processID, height, width)
}
func createAssets(sandboxConfig *SandboxConfig) error { func createAssets(sandboxConfig *SandboxConfig) error {
kernel, err := newAsset(sandboxConfig, kernelAsset) kernel, err := newAsset(sandboxConfig, kernelAsset)
if err != nil { if err != nil {

View File

@ -1469,3 +1469,33 @@ func TestSignalProcess(t *testing.T) {
err = s.SignalProcess(contID, execID, syscall.SIGKILL, false) err = s.SignalProcess(contID, execID, syscall.SIGKILL, false)
assert.Nil(t, err, "Wait process failed: %v", err) assert.Nil(t, err, "Wait process failed: %v", err)
} }
func TestWinsizeProcess(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.WinsizeProcess(contID, execID, 100, 200)
assert.NotNil(t, err, "Winsize process in stopped sandbox should fail")
err = s.start()
assert.Nil(t, err, "Failed to start sandbox: %v", err)
err = s.WinsizeProcess(contID, execID, 100, 200)
assert.NotNil(t, err, "Winsize 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.WinsizeProcess(contID, execID, 100, 200)
assert.Nil(t, err, "Winsize process in ready container failed: %v", err)
_, err = s.StartContainer(contID)
assert.Nil(t, err, "Start container failed: %v", err)
err = s.WinsizeProcess(contID, execID, 100, 200)
assert.Nil(t, err, "Winsize process failed: %v", err)
}