Add shim start for shim creation

Signed-off-by: Michael Crosby <crosbymichael@gmail.com>
This commit is contained in:
Michael Crosby 2018-07-11 11:59:28 -04:00
parent da1b5470cd
commit 7e49c601a8
13 changed files with 1317 additions and 414 deletions

106
runtime/v2/binary.go Normal file
View File

@ -0,0 +1,106 @@
/*
Copyright The containerd Authors.
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 v2
import (
"context"
"strings"
eventstypes "github.com/containerd/containerd/api/events"
"github.com/containerd/containerd/events/exchange"
"github.com/containerd/containerd/runtime"
client "github.com/containerd/containerd/runtime/v2/shim"
"github.com/containerd/containerd/runtime/v2/task"
"github.com/containerd/ttrpc"
"github.com/pkg/errors"
)
func shimBinary(ctx context.Context, bundle *Bundle, runtime, containerdAddress string, events *exchange.Exchange, rt *runtime.TaskList) *binary {
return &binary{
bundle: bundle,
runtime: runtime,
containerdAddress: containerdAddress,
events: events,
rtTasks: rt,
}
}
type binary struct {
runtime string
containerdAddress string
bundle *Bundle
events *exchange.Exchange
rtTasks *runtime.TaskList
}
func (b *binary) Start(ctx context.Context) (*shim, error) {
cmd, err := client.Command(ctx, b.runtime, b.containerdAddress, b.bundle.Path, "-id", b.bundle.ID, "start")
if err != nil {
return nil, err
}
out, err := cmd.CombinedOutput()
if err != nil {
return nil, errors.Wrapf(err, "%s", out)
}
address := strings.TrimSpace(string(out))
conn, err := client.Connect(address, client.AnonDialer)
if err != nil {
return nil, err
}
client := ttrpc.NewClient(conn)
client.OnClose(func() { conn.Close() })
return &shim{
bundle: b.bundle,
client: client,
task: task.NewTaskClient(client),
events: b.events,
rtTasks: b.rtTasks,
}, nil
}
func (b *binary) Delete(ctx context.Context) (*runtime.Exit, error) {
cmd, err := client.Command(ctx, b.runtime, b.containerdAddress, b.bundle.Path, "-id", b.bundle.ID, "delete")
if err != nil {
return nil, err
}
out, err := cmd.CombinedOutput()
if err != nil {
return nil, errors.Wrapf(err, "%s", out)
}
var response task.DeleteResponse
if err := response.Unmarshal(out); err != nil {
return nil, err
}
if err := b.bundle.Delete(); err != nil {
return nil, err
}
// remove self from the runtime task list
// this seems dirty but it cleans up the API across runtimes, tasks, and the service
b.rtTasks.Delete(ctx, b.bundle.ID)
// shim will send the exit event
b.events.Publish(ctx, runtime.TaskDeleteEventTopic, &eventstypes.TaskDelete{
ContainerID: b.bundle.ID,
ExitStatus: response.ExitStatus,
ExitedAt: response.ExitedAt,
Pid: response.Pid,
})
return &runtime.Exit{
Status: response.ExitStatus,
Timestamp: response.ExitedAt,
Pid: response.Pid,
}, nil
}

View File

@ -33,13 +33,10 @@ import (
"github.com/containerd/containerd/platforms" "github.com/containerd/containerd/platforms"
"github.com/containerd/containerd/plugin" "github.com/containerd/containerd/plugin"
"github.com/containerd/containerd/runtime" "github.com/containerd/containerd/runtime"
ptypes "github.com/gogo/protobuf/types"
ocispec "github.com/opencontainers/image-spec/specs-go/v1" ocispec "github.com/opencontainers/image-spec/specs-go/v1"
"github.com/pkg/errors" "github.com/pkg/errors"
) )
var empty = &ptypes.Empty{}
func init() { func init() {
plugin.Register(&plugin.Registration{ plugin.Register(&plugin.Registration{
Type: plugin.RuntimePluginV2, Type: plugin.RuntimePluginV2,
@ -112,7 +109,8 @@ func (m *TaskManager) Create(ctx context.Context, id string, opts runtime.Create
bundle.Delete() bundle.Delete()
} }
}() }()
shim, err := newShim(ctx, bundle, opts.Runtime, m.containerdAddress, m.events, m.tasks) b := shimBinary(ctx, bundle, opts.Runtime, m.containerdAddress, m.events, m.tasks)
shim, err := b.Start(ctx)
if err != nil { if err != nil {
return nil, err return nil, err
} }

View File

@ -40,7 +40,8 @@ func (p *process) ID() string {
func (p *process) Kill(ctx context.Context, signal uint32, _ bool) error { func (p *process) Kill(ctx context.Context, signal uint32, _ bool) error {
_, err := p.shim.task.Kill(ctx, &task.KillRequest{ _, err := p.shim.task.Kill(ctx, &task.KillRequest{
Signal: signal, Signal: signal,
ID: p.id, ID: p.shim.ID(),
ExecID: p.id,
}) })
if err != nil { if err != nil {
return errdefs.FromGRPC(err) return errdefs.FromGRPC(err)
@ -50,7 +51,8 @@ func (p *process) Kill(ctx context.Context, signal uint32, _ bool) error {
func (p *process) State(ctx context.Context) (runtime.State, error) { func (p *process) State(ctx context.Context) (runtime.State, error) {
response, err := p.shim.task.State(ctx, &task.StateRequest{ response, err := p.shim.task.State(ctx, &task.StateRequest{
ID: p.id, ID: p.shim.ID(),
ExecID: p.id,
}) })
if err != nil { if err != nil {
if errors.Cause(err) != ttrpc.ErrClosed { if errors.Cause(err) != ttrpc.ErrClosed {
@ -86,7 +88,8 @@ func (p *process) State(ctx context.Context) (runtime.State, error) {
// ResizePty changes the side of the process's PTY to the provided width and height // ResizePty changes the side of the process's PTY to the provided width and height
func (p *process) ResizePty(ctx context.Context, size runtime.ConsoleSize) error { func (p *process) ResizePty(ctx context.Context, size runtime.ConsoleSize) error {
_, err := p.shim.task.ResizePty(ctx, &task.ResizePtyRequest{ _, err := p.shim.task.ResizePty(ctx, &task.ResizePtyRequest{
ID: p.id, ID: p.shim.ID(),
ExecID: p.id,
Width: size.Width, Width: size.Width,
Height: size.Height, Height: size.Height,
}) })
@ -99,8 +102,9 @@ func (p *process) ResizePty(ctx context.Context, size runtime.ConsoleSize) error
// CloseIO closes the provided IO pipe for the process // CloseIO closes the provided IO pipe for the process
func (p *process) CloseIO(ctx context.Context) error { func (p *process) CloseIO(ctx context.Context) error {
_, err := p.shim.task.CloseIO(ctx, &task.CloseIORequest{ _, err := p.shim.task.CloseIO(ctx, &task.CloseIORequest{
ID: p.id, ID: p.shim.ID(),
Stdin: true, ExecID: p.id,
Stdin: true,
}) })
if err != nil { if err != nil {
return errdefs.FromGRPC(err) return errdefs.FromGRPC(err)
@ -111,7 +115,8 @@ func (p *process) CloseIO(ctx context.Context) error {
// Start the process // Start the process
func (p *process) Start(ctx context.Context) error { func (p *process) Start(ctx context.Context) error {
response, err := p.shim.task.Start(ctx, &task.StartRequest{ response, err := p.shim.task.Start(ctx, &task.StartRequest{
ID: p.id, ID: p.shim.ID(),
ExecID: p.id,
}) })
if err != nil { if err != nil {
return errdefs.FromGRPC(err) return errdefs.FromGRPC(err)
@ -127,7 +132,8 @@ func (p *process) Start(ctx context.Context) error {
// Wait on the process to exit and return the exit status and timestamp // Wait on the process to exit and return the exit status and timestamp
func (p *process) Wait(ctx context.Context) (*runtime.Exit, error) { func (p *process) Wait(ctx context.Context) (*runtime.Exit, error) {
response, err := p.shim.task.Wait(ctx, &task.WaitRequest{ response, err := p.shim.task.Wait(ctx, &task.WaitRequest{
ID: p.id, ID: p.shim.ID(),
ExecID: p.id,
}) })
if err != nil { if err != nil {
return nil, errdefs.FromGRPC(err) return nil, errdefs.FromGRPC(err)
@ -140,7 +146,8 @@ func (p *process) Wait(ctx context.Context) (*runtime.Exit, error) {
func (p *process) Delete(ctx context.Context) (*runtime.Exit, error) { func (p *process) Delete(ctx context.Context) (*runtime.Exit, error) {
response, err := p.shim.task.Delete(ctx, &task.DeleteRequest{ response, err := p.shim.task.Delete(ctx, &task.DeleteRequest{
ID: p.id, ID: p.shim.ID(),
ExecID: p.id,
}) })
if err != nil { if err != nil {
return nil, errdefs.FromGRPC(err) return nil, errdefs.FromGRPC(err)

View File

@ -22,8 +22,10 @@ import (
"context" "context"
"io/ioutil" "io/ioutil"
"os" "os"
"os/exec"
"path/filepath" "path/filepath"
"sync" "sync"
"syscall"
"time" "time"
"github.com/containerd/cgroups" "github.com/containerd/cgroups"
@ -83,6 +85,7 @@ type service struct {
mu sync.Mutex mu sync.Mutex
context context.Context context context.Context
task rproc.Process
processes map[string]rproc.Process processes map[string]rproc.Process
events chan interface{} events chan interface{}
platform rproc.Platform platform rproc.Platform
@ -94,6 +97,77 @@ type service struct {
cg cgroups.Cgroup cg cgroups.Cgroup
} }
func newCommand(ctx context.Context, containerdBinary, containerdAddress string) (*exec.Cmd, error) {
ns, err := namespaces.NamespaceRequired(ctx)
if err != nil {
return nil, err
}
self, err := os.Executable()
if err != nil {
return nil, err
}
cwd, err := os.Getwd()
if err != nil {
return nil, err
}
args := []string{
"-namespace", ns,
"-address", containerdAddress,
"-publish-binary", containerdBinary,
}
cmd := exec.Command(self, args...)
cmd.Dir = cwd
cmd.Env = append(os.Environ(), "GOMAXPROCS=2")
cmd.SysProcAttr = &syscall.SysProcAttr{
Setpgid: true,
}
return cmd, nil
}
func (s *service) StartShim(ctx context.Context, id, containerdBinary, containerdAddress string) (string, error) {
cmd, err := newCommand(ctx, containerdBinary, containerdAddress)
if err != nil {
return "", err
}
address, err := shim.AbstractAddress(ctx, id)
if err != nil {
return "", err
}
socket, err := shim.NewSocket(address)
if err != nil {
return "", err
}
defer socket.Close()
f, err := socket.File()
if err != nil {
return "", err
}
defer f.Close()
cmd.ExtraFiles = append(cmd.ExtraFiles, f)
if err := cmd.Start(); err != nil {
return "", err
}
defer func() {
if err != nil {
cmd.Process.Kill()
}
}()
// make sure to wait after start
go cmd.Wait()
if err := shim.WritePidFile("shim.pid", cmd.Process.Pid); err != nil {
return "", err
}
if err := shim.WriteAddress("address", address); err != nil {
return "", err
}
if err := shim.SetScore(cmd.Process.Pid); err != nil {
return "", errors.Wrap(err, "failed to set OOM Score on shim")
}
return address, nil
}
func (s *service) Cleanup(ctx context.Context) (*taskAPI.DeleteResponse, error) { func (s *service) Cleanup(ctx context.Context) (*taskAPI.DeleteResponse, error) {
path, err := os.Getwd() path, err := os.Getwd()
if err != nil { if err != nil {
@ -221,7 +295,7 @@ func (s *service) Create(ctx context.Context, r *taskAPI.CreateTaskRequest) (_ *
} }
s.cg = cg s.cg = cg
} }
s.processes[r.ID] = process s.task = process
return &taskAPI.CreateTaskResponse{ return &taskAPI.CreateTaskResponse{
Pid: uint32(pid), Pid: uint32(pid),
}, nil }, nil
@ -232,9 +306,9 @@ func (s *service) Create(ctx context.Context, r *taskAPI.CreateTaskRequest) (_ *
func (s *service) Start(ctx context.Context, r *taskAPI.StartRequest) (*taskAPI.StartResponse, error) { func (s *service) Start(ctx context.Context, r *taskAPI.StartRequest) (*taskAPI.StartResponse, error) {
s.mu.Lock() s.mu.Lock()
defer s.mu.Unlock() defer s.mu.Unlock()
p := s.processes[r.ID] p, err := s.getProcess(r.ExecID)
if p == nil { if err != nil {
return nil, errdefs.ToGRPCf(errdefs.ErrNotFound, "process %s", r.ID) return nil, err
} }
if err := p.Start(ctx); err != nil { if err := p.Start(ctx); err != nil {
return nil, err return nil, err
@ -247,7 +321,6 @@ func (s *service) Start(ctx context.Context, r *taskAPI.StartRequest) (*taskAPI.
s.cg = cg s.cg = cg
} }
return &taskAPI.StartResponse{ return &taskAPI.StartResponse{
ID: p.ID(),
Pid: uint32(p.Pid()), Pid: uint32(p.Pid()),
}, nil }, nil
} }
@ -256,16 +329,21 @@ func (s *service) Start(ctx context.Context, r *taskAPI.StartRequest) (*taskAPI.
func (s *service) Delete(ctx context.Context, r *taskAPI.DeleteRequest) (*taskAPI.DeleteResponse, error) { func (s *service) Delete(ctx context.Context, r *taskAPI.DeleteRequest) (*taskAPI.DeleteResponse, error) {
s.mu.Lock() s.mu.Lock()
defer s.mu.Unlock() defer s.mu.Unlock()
p, err := s.getProcess(r.ExecID)
p := s.processes[r.ID] if err != nil {
return nil, err
}
if p == nil { if p == nil {
return nil, errors.Wrapf(errdefs.ErrNotFound, "process %s", r.ID) return nil, errdefs.ToGRPCf(errdefs.ErrFailedPrecondition, "container must be created")
} }
if err := p.Delete(ctx); err != nil { if err := p.Delete(ctx); err != nil {
return nil, err return nil, err
} }
delete(s.processes, r.ID) isTask := r.ExecID == ""
if r.ID == s.id && s.platform != nil { if !isTask {
delete(s.processes, r.ExecID)
}
if isTask && s.platform != nil {
s.platform.Close() s.platform.Close()
} }
return &taskAPI.DeleteResponse{ return &taskAPI.DeleteResponse{
@ -279,18 +357,15 @@ func (s *service) Delete(ctx context.Context, r *taskAPI.DeleteRequest) (*taskAP
func (s *service) Exec(ctx context.Context, r *taskAPI.ExecProcessRequest) (*ptypes.Empty, error) { func (s *service) Exec(ctx context.Context, r *taskAPI.ExecProcessRequest) (*ptypes.Empty, error) {
s.mu.Lock() s.mu.Lock()
defer s.mu.Unlock() defer s.mu.Unlock()
if p := s.processes[r.ExecID]; p != nil {
if p := s.processes[r.ID]; p != nil { return nil, errdefs.ToGRPCf(errdefs.ErrAlreadyExists, "id %s", r.ExecID)
return nil, errdefs.ToGRPCf(errdefs.ErrAlreadyExists, "id %s", r.ID)
} }
p := s.task
p := s.processes[s.id]
if p == nil { if p == nil {
return nil, errdefs.ToGRPCf(errdefs.ErrFailedPrecondition, "container must be created") return nil, errdefs.ToGRPCf(errdefs.ErrFailedPrecondition, "container must be created")
} }
process, err := p.(*proc.Init).Exec(ctx, s.bundle, &proc.ExecConfig{ process, err := p.(*proc.Init).Exec(ctx, s.bundle, &proc.ExecConfig{
ID: r.ID, ID: r.ExecID,
Terminal: r.Terminal, Terminal: r.Terminal,
Stdin: r.Stdin, Stdin: r.Stdin,
Stdout: r.Stdout, Stdout: r.Stdout,
@ -300,7 +375,7 @@ func (s *service) Exec(ctx context.Context, r *taskAPI.ExecProcessRequest) (*pty
if err != nil { if err != nil {
return nil, errdefs.ToGRPC(err) return nil, errdefs.ToGRPC(err)
} }
s.processes[r.ID] = process s.processes[r.ExecID] = process
return empty, nil return empty, nil
} }
@ -308,17 +383,14 @@ func (s *service) Exec(ctx context.Context, r *taskAPI.ExecProcessRequest) (*pty
func (s *service) ResizePty(ctx context.Context, r *taskAPI.ResizePtyRequest) (*ptypes.Empty, error) { func (s *service) ResizePty(ctx context.Context, r *taskAPI.ResizePtyRequest) (*ptypes.Empty, error) {
s.mu.Lock() s.mu.Lock()
defer s.mu.Unlock() defer s.mu.Unlock()
if r.ID == "" { p, err := s.getProcess(r.ExecID)
return nil, errdefs.ToGRPCf(errdefs.ErrInvalidArgument, "id not provided") if err != nil {
return nil, err
} }
ws := console.WinSize{ ws := console.WinSize{
Width: uint16(r.Width), Width: uint16(r.Width),
Height: uint16(r.Height), Height: uint16(r.Height),
} }
p := s.processes[r.ID]
if p == nil {
return nil, errors.Errorf("process does not exist %s", r.ID)
}
if err := p.Resize(ws); err != nil { if err := p.Resize(ws); err != nil {
return nil, errdefs.ToGRPC(err) return nil, errdefs.ToGRPC(err)
} }
@ -329,9 +401,9 @@ func (s *service) ResizePty(ctx context.Context, r *taskAPI.ResizePtyRequest) (*
func (s *service) State(ctx context.Context, r *taskAPI.StateRequest) (*taskAPI.StateResponse, error) { func (s *service) State(ctx context.Context, r *taskAPI.StateRequest) (*taskAPI.StateResponse, error) {
s.mu.Lock() s.mu.Lock()
defer s.mu.Unlock() defer s.mu.Unlock()
p := s.processes[r.ID] p, err := s.getProcess(r.ExecID)
if p == nil { if err != nil {
return nil, errdefs.ToGRPCf(errdefs.ErrNotFound, "process id %s", r.ID) return nil, err
} }
st, err := p.Status(ctx) st, err := p.Status(ctx)
if err != nil { if err != nil {
@ -366,10 +438,10 @@ func (s *service) State(ctx context.Context, r *taskAPI.StateRequest) (*taskAPI.
} }
// Pause the container // Pause the container
func (s *service) Pause(ctx context.Context, r *ptypes.Empty) (*ptypes.Empty, error) { func (s *service) Pause(ctx context.Context, r *taskAPI.PauseRequest) (*ptypes.Empty, error) {
s.mu.Lock() s.mu.Lock()
defer s.mu.Unlock() defer s.mu.Unlock()
p := s.processes[s.id] p := s.task
if p == nil { if p == nil {
return nil, errdefs.ToGRPCf(errdefs.ErrFailedPrecondition, "container must be created") return nil, errdefs.ToGRPCf(errdefs.ErrFailedPrecondition, "container must be created")
} }
@ -380,10 +452,10 @@ func (s *service) Pause(ctx context.Context, r *ptypes.Empty) (*ptypes.Empty, er
} }
// Resume the container // Resume the container
func (s *service) Resume(ctx context.Context, r *ptypes.Empty) (*ptypes.Empty, error) { func (s *service) Resume(ctx context.Context, r *taskAPI.ResumeRequest) (*ptypes.Empty, error) {
s.mu.Lock() s.mu.Lock()
defer s.mu.Unlock() defer s.mu.Unlock()
p := s.processes[s.id] p := s.task
if p == nil { if p == nil {
return nil, errdefs.ToGRPCf(errdefs.ErrFailedPrecondition, "container must be created") return nil, errdefs.ToGRPCf(errdefs.ErrFailedPrecondition, "container must be created")
} }
@ -397,20 +469,12 @@ func (s *service) Resume(ctx context.Context, r *ptypes.Empty) (*ptypes.Empty, e
func (s *service) Kill(ctx context.Context, r *taskAPI.KillRequest) (*ptypes.Empty, error) { func (s *service) Kill(ctx context.Context, r *taskAPI.KillRequest) (*ptypes.Empty, error) {
s.mu.Lock() s.mu.Lock()
defer s.mu.Unlock() defer s.mu.Unlock()
if r.ID == "" { p, err := s.getProcess(r.ExecID)
p := s.processes[s.id] if err != nil {
if p == nil { return nil, err
return nil, errdefs.ToGRPCf(errdefs.ErrFailedPrecondition, "container must be created")
}
if err := p.Kill(ctx, r.Signal, r.All); err != nil {
return nil, errdefs.ToGRPC(err)
}
return empty, nil
} }
p := s.processes[r.ID]
if p == nil { if p == nil {
return nil, errdefs.ToGRPCf(errdefs.ErrNotFound, "process id %s not found", r.ID) return nil, errdefs.ToGRPCf(errdefs.ErrFailedPrecondition, "container must be created")
} }
if err := p.Kill(ctx, r.Signal, r.All); err != nil { if err := p.Kill(ctx, r.Signal, r.All); err != nil {
return nil, errdefs.ToGRPC(err) return nil, errdefs.ToGRPC(err)
@ -453,9 +517,9 @@ func (s *service) Pids(ctx context.Context, r *taskAPI.PidsRequest) (*taskAPI.Pi
func (s *service) CloseIO(ctx context.Context, r *taskAPI.CloseIORequest) (*ptypes.Empty, error) { func (s *service) CloseIO(ctx context.Context, r *taskAPI.CloseIORequest) (*ptypes.Empty, error) {
s.mu.Lock() s.mu.Lock()
defer s.mu.Unlock() defer s.mu.Unlock()
p := s.processes[r.ID] p, err := s.getProcess(r.ExecID)
if p == nil { if err != nil {
return nil, errdefs.ToGRPCf(errdefs.ErrNotFound, "process does not exist %s", r.ID) return nil, err
} }
if stdin := p.Stdin(); stdin != nil { if stdin := p.Stdin(); stdin != nil {
if err := stdin.Close(); err != nil { if err := stdin.Close(); err != nil {
@ -469,7 +533,7 @@ func (s *service) CloseIO(ctx context.Context, r *taskAPI.CloseIORequest) (*ptyp
func (s *service) Checkpoint(ctx context.Context, r *taskAPI.CheckpointTaskRequest) (*ptypes.Empty, error) { func (s *service) Checkpoint(ctx context.Context, r *taskAPI.CheckpointTaskRequest) (*ptypes.Empty, error) {
s.mu.Lock() s.mu.Lock()
defer s.mu.Unlock() defer s.mu.Unlock()
p := s.processes[s.id] p := s.task
if p == nil { if p == nil {
return nil, errdefs.ToGRPCf(errdefs.ErrFailedPrecondition, "container must be created") return nil, errdefs.ToGRPCf(errdefs.ErrFailedPrecondition, "container must be created")
} }
@ -497,9 +561,13 @@ func (s *service) Checkpoint(ctx context.Context, r *taskAPI.CheckpointTaskReque
// Connect returns shim information such as the shim's pid // Connect returns shim information such as the shim's pid
func (s *service) Connect(ctx context.Context, r *taskAPI.ConnectRequest) (*taskAPI.ConnectResponse, error) { func (s *service) Connect(ctx context.Context, r *taskAPI.ConnectRequest) (*taskAPI.ConnectResponse, error) {
var pid int
if s.task != nil {
pid = s.task.Pid()
}
return &taskAPI.ConnectResponse{ return &taskAPI.ConnectResponse{
ShimPid: uint32(os.Getpid()), ShimPid: uint32(os.Getpid()),
TaskPid: uint32(s.processes[s.id].Pid()), TaskPid: uint32(pid),
}, nil }, nil
} }
@ -532,7 +600,7 @@ func (s *service) Stats(ctx context.Context, r *taskAPI.StatsRequest) (*taskAPI.
func (s *service) Update(ctx context.Context, r *taskAPI.UpdateTaskRequest) (*ptypes.Empty, error) { func (s *service) Update(ctx context.Context, r *taskAPI.UpdateTaskRequest) (*ptypes.Empty, error) {
s.mu.Lock() s.mu.Lock()
defer s.mu.Unlock() defer s.mu.Unlock()
p := s.processes[s.id] p := s.task
if p == nil { if p == nil {
return nil, errdefs.ToGRPCf(errdefs.ErrFailedPrecondition, "container must be created") return nil, errdefs.ToGRPCf(errdefs.ErrFailedPrecondition, "container must be created")
} }
@ -545,8 +613,11 @@ func (s *service) Update(ctx context.Context, r *taskAPI.UpdateTaskRequest) (*pt
// Wait for a process to exit // Wait for a process to exit
func (s *service) Wait(ctx context.Context, r *taskAPI.WaitRequest) (*taskAPI.WaitResponse, error) { func (s *service) Wait(ctx context.Context, r *taskAPI.WaitRequest) (*taskAPI.WaitResponse, error) {
s.mu.Lock() s.mu.Lock()
p := s.processes[r.ID] p, err := s.getProcess(r.ExecID)
s.mu.Unlock() s.mu.Unlock()
if err != nil {
return nil, err
}
if p == nil { if p == nil {
return nil, errdefs.ToGRPCf(errdefs.ErrFailedPrecondition, "container must be created") return nil, errdefs.ToGRPCf(errdefs.ErrFailedPrecondition, "container must be created")
} }
@ -567,7 +638,8 @@ func (s *service) processExits() {
func (s *service) checkProcesses(e runcC.Exit) { func (s *service) checkProcesses(e runcC.Exit) {
s.mu.Lock() s.mu.Lock()
defer s.mu.Unlock() defer s.mu.Unlock()
for _, p := range s.processes {
for _, p := range s.allProcesses() {
if p.Pid() == e.Pid { if p.Pid() == e.Pid {
if ip, ok := p.(*proc.Init); ok { if ip, ok := p.(*proc.Init); ok {
// Ensure all children are killed // Ensure all children are killed
@ -589,14 +661,23 @@ func (s *service) checkProcesses(e runcC.Exit) {
} }
} }
func (s *service) allProcesses() (o []rproc.Process) {
for _, p := range s.processes {
o = append(o, p)
}
if s.task != nil {
o = append(o, s.task)
}
return o
}
func (s *service) getContainerPids(ctx context.Context, id string) ([]uint32, error) { func (s *service) getContainerPids(ctx context.Context, id string) ([]uint32, error) {
s.mu.Lock() s.mu.Lock()
defer s.mu.Unlock() defer s.mu.Unlock()
p := s.processes[s.id] p := s.task
if p == nil { if p == nil {
return nil, errors.Wrapf(errdefs.ErrFailedPrecondition, "container must be created") return nil, errors.Wrapf(errdefs.ErrFailedPrecondition, "container must be created")
} }
ps, err := p.(*proc.Init).Runtime().Ps(ctx, id) ps, err := p.(*proc.Init).Runtime().Ps(ctx, id)
if err != nil { if err != nil {
return nil, err return nil, err
@ -616,6 +697,17 @@ func (s *service) forward(publisher events.Publisher) {
} }
} }
func (s *service) getProcess(execID string) (rproc.Process, error) {
if execID == "" {
return s.task, nil
}
p := s.processes[execID]
if p == nil {
return nil, errdefs.ToGRPCf(errdefs.ErrNotFound, "process does not exist %s", execID)
}
return p, nil
}
func getTopic(ctx context.Context, e interface{}) string { func getTopic(ctx context.Context, e interface{}) string {
switch e.(type) { switch e.(type) {
case *eventstypes.TaskCreate: case *eventstypes.TaskCreate:

View File

@ -18,6 +18,7 @@ package v2
import ( import (
"context" "context"
"io/ioutil"
"path/filepath" "path/filepath"
"time" "time"
@ -29,129 +30,27 @@ import (
"github.com/containerd/containerd/identifiers" "github.com/containerd/containerd/identifiers"
"github.com/containerd/containerd/log" "github.com/containerd/containerd/log"
"github.com/containerd/containerd/runtime" "github.com/containerd/containerd/runtime"
client "github.com/containerd/containerd/runtime/v2/shim"
"github.com/containerd/containerd/runtime/v2/task" "github.com/containerd/containerd/runtime/v2/task"
"github.com/containerd/ttrpc" "github.com/containerd/ttrpc"
ptypes "github.com/gogo/protobuf/types" ptypes "github.com/gogo/protobuf/types"
"github.com/pkg/errors" "github.com/pkg/errors"
"github.com/sirupsen/logrus"
) )
type binary struct { func loadAddress(path string) (string, error) {
runtime string data, err := ioutil.ReadFile(path)
containerdAddress string
bundle *Bundle
events *exchange.Exchange
rtTasks *runtime.TaskList
}
func (b *binary) Delete(ctx context.Context) (*runtime.Exit, error) {
cmd, err := shimCommand(ctx, b.runtime, b.containerdAddress, b.bundle, "-debug", "delete")
if err != nil { if err != nil {
return nil, err return "", err
} }
out, err := cmd.CombinedOutput() return string(data), nil
if err != nil {
return nil, errors.Wrapf(err, "%s", out)
}
var response task.DeleteResponse
if err := response.Unmarshal(out); err != nil {
return nil, err
}
if err := b.bundle.Delete(); err != nil {
return nil, err
}
// remove self from the runtime task list
// this seems dirty but it cleans up the API across runtimes, tasks, and the service
b.rtTasks.Delete(ctx, b.bundle.ID)
// shim will send the exit event
b.events.Publish(ctx, runtime.TaskDeleteEventTopic, &eventstypes.TaskDelete{
ContainerID: b.bundle.ID,
ExitStatus: response.ExitStatus,
ExitedAt: response.ExitedAt,
Pid: response.Pid,
})
return &runtime.Exit{
Status: response.ExitStatus,
Timestamp: response.ExitedAt,
Pid: response.Pid,
}, nil
}
func shimBinary(ctx context.Context, bundle *Bundle, runtime, containerdAddress string, events *exchange.Exchange, rt *runtime.TaskList) *binary {
return &binary{
bundle: bundle,
runtime: runtime,
containerdAddress: containerdAddress,
events: events,
rtTasks: rt,
}
}
// newShim starts and returns a new shim
func newShim(ctx context.Context, bundle *Bundle, runtime, containerdAddress string, events *exchange.Exchange, rt *runtime.TaskList) (_ *shim, err error) {
cmd, err := shimCommand(ctx, runtime, containerdAddress, bundle, "-debug")
if err != nil {
return nil, err
}
address, err := abstractAddress(ctx, bundle.ID)
if err != nil {
return nil, err
}
socket, err := newSocket(address)
if err != nil {
return nil, err
}
defer socket.Close()
f, err := socket.File()
if err != nil {
return nil, err
}
defer f.Close()
cmd.ExtraFiles = append(cmd.ExtraFiles, f)
if err := cmd.Start(); err != nil {
return nil, err
}
defer func() {
if err != nil {
cmd.Process.Kill()
}
}()
// make sure to wait after start
go cmd.Wait()
if err := writePidFile(filepath.Join(bundle.Path, "shim.pid"), cmd.Process.Pid); err != nil {
return nil, err
}
log.G(ctx).WithFields(logrus.Fields{
"pid": cmd.Process.Pid,
"address": address,
}).Infof("shim %s started", cmd.Args[0])
if err := setScore(cmd.Process.Pid); err != nil {
return nil, errors.Wrap(err, "failed to set OOM Score on shim")
}
conn, err := connect(address, annonDialer)
if err != nil {
return nil, err
}
client := ttrpc.NewClient(conn)
client.OnClose(func() { conn.Close() })
return &shim{
bundle: bundle,
client: client,
task: task.NewTaskClient(client),
shimPid: cmd.Process.Pid,
events: events,
rtTasks: rt,
}, nil
} }
func loadShim(ctx context.Context, bundle *Bundle, events *exchange.Exchange, rt *runtime.TaskList) (_ *shim, err error) { func loadShim(ctx context.Context, bundle *Bundle, events *exchange.Exchange, rt *runtime.TaskList) (_ *shim, err error) {
address, err := abstractAddress(ctx, bundle.ID) address, err := loadAddress(filepath.Join(bundle.Path, "address"))
if err != nil { if err != nil {
return nil, err return nil, err
} }
conn, err := connect(address, annonDialer) conn, err := client.Connect(address, client.AnonDialer)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -174,7 +73,6 @@ type shim struct {
bundle *Bundle bundle *Bundle
client *ttrpc.Client client *ttrpc.Client
task task.TaskService task task.TaskService
shimPid int
taskPid int taskPid int
events *exchange.Exchange events *exchange.Exchange
rtTasks *runtime.TaskList rtTasks *runtime.TaskList
@ -185,15 +83,15 @@ func (s *shim) Connect(ctx context.Context) error {
if err != nil { if err != nil {
return err return err
} }
s.shimPid = int(response.ShimPid)
s.taskPid = int(response.TaskPid) s.taskPid = int(response.TaskPid)
return nil return nil
} }
func (s *shim) Shutdown(ctx context.Context) error { func (s *shim) Shutdown(ctx context.Context) error {
_, err := s.task.Shutdown(ctx, &task.ShutdownRequest{}) _, err := s.task.Shutdown(ctx, &task.ShutdownRequest{
if err != nil { ID: s.ID(),
// handle conn closed error type })
if err != nil && err != ttrpc.ErrClosed {
return errdefs.FromGRPC(err) return errdefs.FromGRPC(err)
} }
return nil return nil
@ -208,12 +106,8 @@ func (s *shim) waitShutdown(ctx context.Context) error {
close(dead) close(dead)
}() }()
select { select {
case <-time.After(1 * time.Second): case <-time.After(3 * time.Second):
if err := terminate(s.shimPid); err != nil { return errors.New("failed to shutdown shim in time")
log.G(ctx).WithError(err).Error("terminate shim")
}
<-dead
return nil
case <-dead: case <-dead:
return nil return nil
} }
@ -292,7 +186,9 @@ func (s *shim) Create(ctx context.Context, opts runtime.CreateOpts) (runtime.Tas
} }
func (s *shim) Pause(ctx context.Context) error { func (s *shim) Pause(ctx context.Context) error {
if _, err := s.task.Pause(ctx, empty); err != nil { if _, err := s.task.Pause(ctx, &task.PauseRequest{
ID: s.ID(),
}); err != nil {
return errdefs.FromGRPC(err) return errdefs.FromGRPC(err)
} }
s.events.Publish(ctx, runtime.TaskPausedEventTopic, &eventstypes.TaskPaused{ s.events.Publish(ctx, runtime.TaskPausedEventTopic, &eventstypes.TaskPaused{
@ -302,7 +198,9 @@ func (s *shim) Pause(ctx context.Context) error {
} }
func (s *shim) Resume(ctx context.Context) error { func (s *shim) Resume(ctx context.Context) error {
if _, err := s.task.Resume(ctx, empty); err != nil { if _, err := s.task.Resume(ctx, &task.ResumeRequest{
ID: s.ID(),
}); err != nil {
return errdefs.FromGRPC(err) return errdefs.FromGRPC(err)
} }
s.events.Publish(ctx, runtime.TaskResumedEventTopic, &eventstypes.TaskResumed{ s.events.Publish(ctx, runtime.TaskResumedEventTopic, &eventstypes.TaskResumed{
@ -342,7 +240,8 @@ func (s *shim) Exec(ctx context.Context, id string, opts runtime.ExecOpts) (runt
return nil, errors.Wrapf(err, "invalid exec id %s", id) return nil, errors.Wrapf(err, "invalid exec id %s", id)
} }
request := &task.ExecProcessRequest{ request := &task.ExecProcessRequest{
ID: id, ID: s.ID(),
ExecID: id,
Stdin: opts.IO.Stdin, Stdin: opts.IO.Stdin,
Stdout: opts.IO.Stdout, Stdout: opts.IO.Stdout,
Stderr: opts.IO.Stderr, Stderr: opts.IO.Stderr,
@ -428,6 +327,7 @@ func (s *shim) Checkpoint(ctx context.Context, path string, options *ptypes.Any)
func (s *shim) Update(ctx context.Context, resources *ptypes.Any) error { func (s *shim) Update(ctx context.Context, resources *ptypes.Any) error {
if _, err := s.task.Update(ctx, &task.UpdateTaskRequest{ if _, err := s.task.Update(ctx, &task.UpdateTaskRequest{
ID: s.ID(),
Resources: resources, Resources: resources,
}); err != nil { }); err != nil {
return errdefs.FromGRPC(err) return errdefs.FromGRPC(err)
@ -436,7 +336,9 @@ func (s *shim) Update(ctx context.Context, resources *ptypes.Any) error {
} }
func (s *shim) Stats(ctx context.Context) (*ptypes.Any, error) { func (s *shim) Stats(ctx context.Context) (*ptypes.Any, error) {
response, err := s.task.Stats(ctx, &task.StatsRequest{}) response, err := s.task.Stats(ctx, &task.StatsRequest{
ID: s.ID(),
})
if err != nil { if err != nil {
return nil, errdefs.FromGRPC(err) return nil, errdefs.FromGRPC(err)
} }

View File

@ -57,6 +57,7 @@ type Init func(context.Context, string, events.Publisher) (Shim, error)
type Shim interface { type Shim interface {
shimapi.TaskService shimapi.TaskService
Cleanup(ctx context.Context) (*shimapi.DeleteResponse, error) Cleanup(ctx context.Context) (*shimapi.DeleteResponse, error)
StartShim(ctx context.Context, id, containerdBinary, containerdAddress string) (string, error)
} }
var ( var (
@ -72,7 +73,7 @@ var (
func parseFlags() { func parseFlags() {
flag.BoolVar(&debugFlag, "debug", false, "enable debug output in logs") flag.BoolVar(&debugFlag, "debug", false, "enable debug output in logs")
flag.StringVar(&namespaceFlag, "namespace", "", "namespace that owns the shim") flag.StringVar(&namespaceFlag, "namespace", "", "namespace that owns the shim")
flag.StringVar(&idFlag, "id", "", "id of the shim") flag.StringVar(&idFlag, "id", "", "id of the task")
flag.StringVar(&socketFlag, "socket", "", "abstract socket path to serve") flag.StringVar(&socketFlag, "socket", "", "abstract socket path to serve")
flag.StringVar(&addressFlag, "address", "", "grpc address back to main containerd") flag.StringVar(&addressFlag, "address", "", "grpc address back to main containerd")
@ -92,7 +93,7 @@ func setRuntime() {
if debugFlag { if debugFlag {
f, err := os.OpenFile("shim.log", os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0600) f, err := os.OpenFile("shim.log", os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0600)
if err != nil { if err != nil {
fmt.Fprintf(os.Stderr, "open should log %s", err) fmt.Fprintf(os.Stderr, "open shim log %s", err)
os.Exit(1) os.Exit(1)
} }
logrus.SetLevel(logrus.DebugLevel) logrus.SetLevel(logrus.DebugLevel)
@ -148,6 +149,15 @@ func Run(initFunc Init) error {
return err return err
} }
return nil return nil
case "start":
address, err := service.StartShim(ctx, idFlag, containerdBinaryFlag, addressFlag)
if err != nil {
return err
}
if _, err := os.Stdout.WriteString(address); err != nil {
return err
}
return nil
default: default:
client := NewShimClient(ctx, service, signals) client := NewShimClient(ctx, service, signals)
return client.Serve() return client.Serve()

View File

@ -14,7 +14,7 @@
limitations under the License. limitations under the License.
*/ */
package v2 package shim
import ( import (
"context" "context"
@ -32,7 +32,8 @@ import (
const shimBinaryFormat = "containerd-shim-%s-%s" const shimBinaryFormat = "containerd-shim-%s-%s"
func shimCommand(ctx context.Context, runtime, containerdAddress string, bundle *Bundle, cmdArgs ...string) (*exec.Cmd, error) { // Command returns the shim command with the provided args and configuration
func Command(ctx context.Context, runtime, containerdAddress, path string, cmdArgs ...string) (*exec.Cmd, error) {
ns, err := namespaces.NamespaceRequired(ctx) ns, err := namespaces.NamespaceRequired(ctx)
if err != nil { if err != nil {
return nil, err return nil, err
@ -47,7 +48,7 @@ func shimCommand(ctx context.Context, runtime, containerdAddress string, bundle
"-publish-binary", self, "-publish-binary", self,
} }
args = append(args, cmdArgs...) args = append(args, cmdArgs...)
name := getShimBinaryName(runtime) name := BinaryName(runtime)
if _, err := exec.LookPath(name); err != nil { if _, err := exec.LookPath(name); err != nil {
if eerr, ok := err.(*exec.Error); ok { if eerr, ok := err.(*exec.Error); ok {
if eerr.Err == exec.ErrNotFound { if eerr.Err == exec.ErrNotFound {
@ -56,19 +57,21 @@ func shimCommand(ctx context.Context, runtime, containerdAddress string, bundle
} }
} }
cmd := exec.Command(name, args...) cmd := exec.Command(name, args...)
cmd.Dir = bundle.Path cmd.Dir = path
cmd.Env = append(os.Environ(), "GOMAXPROCS=2") cmd.Env = append(os.Environ(), "GOMAXPROCS=2")
cmd.SysProcAttr = getSysProcAttr() cmd.SysProcAttr = getSysProcAttr()
return cmd, nil return cmd, nil
} }
func getShimBinaryName(runtime string) string { // BinaryName returns the shim binary name from the runtime name
func BinaryName(runtime string) string {
parts := strings.Split(runtime, ".") parts := strings.Split(runtime, ".")
// TODO: add validation for runtime // TODO: add validation for runtime
return fmt.Sprintf(shimBinaryFormat, parts[len(parts)-2], parts[len(parts)-1]) return fmt.Sprintf(shimBinaryFormat, parts[len(parts)-2], parts[len(parts)-1])
} }
func abstractAddress(ctx context.Context, id string) (string, error) { // AbstractAddress returns an abstract socket address
func AbstractAddress(ctx context.Context, id string) (string, error) {
ns, err := namespaces.NamespaceRequired(ctx) ns, err := namespaces.NamespaceRequired(ctx)
if err != nil { if err != nil {
return "", err return "", err
@ -76,16 +79,19 @@ func abstractAddress(ctx context.Context, id string) (string, error) {
return filepath.Join(string(filepath.Separator), "containerd-shim", ns, id, "shim.sock"), nil return filepath.Join(string(filepath.Separator), "containerd-shim", ns, id, "shim.sock"), nil
} }
func connect(address string, d func(string, time.Duration) (net.Conn, error)) (net.Conn, error) { // Connect to the provided address
func Connect(address string, d func(string, time.Duration) (net.Conn, error)) (net.Conn, error) {
return d(address, 100*time.Second) return d(address, 100*time.Second)
} }
func annonDialer(address string, timeout time.Duration) (net.Conn, error) { // AnonDialer returns a dialer for an abstract socket
func AnonDialer(address string, timeout time.Duration) (net.Conn, error) {
address = strings.TrimPrefix(address, "unix://") address = strings.TrimPrefix(address, "unix://")
return net.DialTimeout("unix", "\x00"+address, timeout) return net.DialTimeout("unix", "\x00"+address, timeout)
} }
func newSocket(address string) (*net.UnixListener, error) { // NewSocket returns a new socket
func NewSocket(address string) (*net.UnixListener, error) {
if len(address) > 106 { if len(address) > 106 {
return nil, errors.Errorf("%q: unix socket path too long (> 106)", address) return nil, errors.Errorf("%q: unix socket path too long (> 106)", address)
} }
@ -96,7 +102,8 @@ func newSocket(address string) (*net.UnixListener, error) {
return l.(*net.UnixListener), nil return l.(*net.UnixListener), nil
} }
func writePidFile(path string, pid int) error { // WritePidFile writes a pid file atomically
func WritePidFile(path string, pid int) error {
path, err := filepath.Abs(path) path, err := filepath.Abs(path)
if err != nil { if err != nil {
return err return err
@ -113,3 +120,22 @@ func writePidFile(path string, pid int) error {
} }
return os.Rename(tempPath, path) return os.Rename(tempPath, path)
} }
// WriteAddress writes a address file atomically
func WriteAddress(path, address string) error {
path, err := filepath.Abs(path)
if err != nil {
return err
}
tempPath := filepath.Join(filepath.Dir(path), fmt.Sprintf(".%s", filepath.Base(path)))
f, err := os.OpenFile(tempPath, os.O_RDWR|os.O_CREATE|os.O_EXCL|os.O_SYNC, 0666)
if err != nil {
return err
}
_, err = f.WriteString(address)
f.Close()
if err != nil {
return err
}
return os.Rename(tempPath, path)
}

View File

@ -14,13 +14,12 @@
limitations under the License. limitations under the License.
*/ */
package v2 package shim
import ( import (
"syscall" "syscall"
"github.com/containerd/containerd/sys" "github.com/containerd/containerd/sys"
"golang.org/x/sys/unix"
) )
func getSysProcAttr() *syscall.SysProcAttr { func getSysProcAttr() *syscall.SysProcAttr {
@ -29,10 +28,7 @@ func getSysProcAttr() *syscall.SysProcAttr {
} }
} }
func terminate(pid int) error { // SetScore sets the oom score for a process
return unix.Kill(pid, unix.SIGKILL) func SetScore(pid int) error {
}
func setScore(pid int) error {
return sys.SetOOMScore(pid, sys.OOMScoreMaxKillable) return sys.SetOOMScore(pid, sys.OOMScoreMaxKillable)
} }

View File

@ -16,12 +16,10 @@
limitations under the License. limitations under the License.
*/ */
package v2 package shim
import ( import (
"syscall" "syscall"
"golang.org/x/sys/unix"
) )
func getSysProcAttr() *syscall.SysProcAttr { func getSysProcAttr() *syscall.SysProcAttr {
@ -30,10 +28,7 @@ func getSysProcAttr() *syscall.SysProcAttr {
} }
} }
func terminate(pid int) error { // SetScore sets the oom score for a process
return unix.Kill(pid, unix.SIGKILL) func SetScore(pid int) error {
}
func setScore(pid int) error {
return nil return nil
} }

View File

@ -14,10 +14,9 @@
limitations under the License. limitations under the License.
*/ */
package v2 package shim
import ( import (
"os"
"syscall" "syscall"
) )
@ -25,14 +24,7 @@ func getSysProcAttr() *syscall.SysProcAttr {
return nil return nil
} }
func terminate(pid int) error { // SetScore sets the oom score for a process
p, err := os.FindProcess(pid) func SetScore(pid int) error {
if err != nil {
return err
}
return p.Kill()
}
func setScore(pid int) error {
return nil return nil
} }

File diff suppressed because it is too large Load Diff

View File

@ -21,8 +21,8 @@ service Task {
rpc Start(StartRequest) returns (StartResponse); rpc Start(StartRequest) returns (StartResponse);
rpc Delete(DeleteRequest) returns (DeleteResponse); rpc Delete(DeleteRequest) returns (DeleteResponse);
rpc Pids(PidsRequest) returns (PidsResponse); rpc Pids(PidsRequest) returns (PidsResponse);
rpc Pause(google.protobuf.Empty) returns (google.protobuf.Empty); rpc Pause(PauseRequest) returns (google.protobuf.Empty);
rpc Resume(google.protobuf.Empty) returns (google.protobuf.Empty); rpc Resume(ResumeRequest) returns (google.protobuf.Empty);
rpc Checkpoint(CheckpointTaskRequest) returns (google.protobuf.Empty); rpc Checkpoint(CheckpointTaskRequest) returns (google.protobuf.Empty);
rpc Kill(KillRequest) returns (google.protobuf.Empty); rpc Kill(KillRequest) returns (google.protobuf.Empty);
rpc Exec(ExecProcessRequest) returns (google.protobuf.Empty); rpc Exec(ExecProcessRequest) returns (google.protobuf.Empty);
@ -54,6 +54,7 @@ message CreateTaskResponse {
message DeleteRequest { message DeleteRequest {
string id = 1; string id = 1;
string exec_id = 2;
} }
message DeleteResponse { message DeleteResponse {
@ -64,11 +65,12 @@ message DeleteResponse {
message ExecProcessRequest { message ExecProcessRequest {
string id = 1; string id = 1;
bool terminal = 2; string exec_id = 2;
string stdin = 3; bool terminal = 3;
string stdout = 4; string stdin = 4;
string stderr = 5; string stdout = 5;
google.protobuf.Any spec = 6; string stderr = 6;
google.protobuf.Any spec = 7;
} }
message ExecProcessResponse { message ExecProcessResponse {
@ -76,12 +78,14 @@ message ExecProcessResponse {
message ResizePtyRequest { message ResizePtyRequest {
string id = 1; string id = 1;
uint32 width = 2; string exec_id = 2;
uint32 height = 3; uint32 width = 3;
uint32 height = 4;
} }
message StateRequest { message StateRequest {
string id = 1; string id = 1;
string exec_id = 2;
} }
message StateResponse { message StateResponse {
@ -99,13 +103,15 @@ message StateResponse {
message KillRequest { message KillRequest {
string id = 1; string id = 1;
uint32 signal = 2; string exec_id = 2;
bool all = 3; uint32 signal = 3;
bool all = 4;
} }
message CloseIORequest { message CloseIORequest {
string id = 1; string id = 1;
bool stdin = 2; string exec_id = 2;
bool stdin = 3;
} }
message PidsRequest { message PidsRequest {
@ -117,25 +123,28 @@ message PidsResponse {
} }
message CheckpointTaskRequest { message CheckpointTaskRequest {
string path = 1; string id = 1;
google.protobuf.Any options = 2; string path = 2;
google.protobuf.Any options = 3;
} }
message UpdateTaskRequest { message UpdateTaskRequest {
google.protobuf.Any resources = 1; string id = 1;
google.protobuf.Any resources = 2;
} }
message StartRequest { message StartRequest {
string id = 1; string id = 1;
string exec_id = 2;
} }
message StartResponse { message StartResponse {
string id = 1; uint32 pid = 1;
uint32 pid = 2;
} }
message WaitRequest { message WaitRequest {
string id = 1; string id = 1;
string exec_id = 2;
} }
message WaitResponse { message WaitResponse {
@ -144,7 +153,7 @@ message WaitResponse {
} }
message StatsRequest { message StatsRequest {
string id = 1;
} }
message StatsResponse { message StatsResponse {
@ -152,7 +161,7 @@ message StatsResponse {
} }
message ConnectRequest { message ConnectRequest {
string id = 1;
} }
message ConnectResponse { message ConnectResponse {
@ -162,5 +171,14 @@ message ConnectResponse {
} }
message ShutdownRequest { message ShutdownRequest {
bool now = 1; string id = 1;
bool now = 2;
}
message PauseRequest {
string id = 1;
}
message ResumeRequest {
string id = 1;
} }

View File

@ -585,9 +585,9 @@ func getTasksMetrics(ctx context.Context, filter filters.Filter, tasks []runtime
case "id": case "id":
return t.ID(), true return t.ID(), true
case "namespace": case "namespace":
// return t.Info().Namespace, true return t.Namespace(), true
case "runtime": case "runtime":
// return t.Info().Runtime, true // return t.Info().Runtime, true
} }
return "", false return "", false
})) { })) {