linux, linux/shim: remove error definitions

Since we now have a common set of error definitions, mapped to existing
error codes, we no longer need the specialized error codes used for
interaction with linux processes. The main issue was that string
matching was being used to map these to useful error codes. With this
change, we use errors defined in the `errdefs` package, which map
cleanly to GRPC error codes and are recoverable on either side of the
request.

The main focus of this PR was in removin these from the shim. We may
need follow ups to ensure error codes are preserved by the `Tasks`
service.

Signed-off-by: Stephen J Day <stephen.day@docker.com>
This commit is contained in:
Stephen J Day 2017-07-18 15:41:05 -07:00
parent 6d305c741e
commit 6d0bcd5aec
No known key found for this signature in database
GPG Key ID: 67B3DED84EDC823F
12 changed files with 82 additions and 97 deletions

View File

@ -11,6 +11,8 @@ import (
"testing" "testing"
"time" "time"
"github.com/Sirupsen/logrus"
"github.com/containerd/containerd/log"
"github.com/containerd/containerd/namespaces" "github.com/containerd/containerd/namespaces"
"github.com/containerd/containerd/testutil" "github.com/containerd/containerd/testutil"
) )
@ -78,13 +80,25 @@ func TestMain(m *testing.M) {
os.Exit(1) os.Exit(1)
} }
// print out the version in information
version, err := client.Version(ctx)
if err != nil {
fmt.Fprintf(os.Stderr, "error getting version: %s", err)
os.Exit(1)
}
// allow comparison with containerd under test
log.G(ctx).WithFields(logrus.Fields{
"version": version.Version,
"revision": version.Revision,
}).Info("running tests against containerd")
// pull a seed image // pull a seed image
if _, err = client.Pull(ctx, testImage, WithPullUnpack); err != nil { if _, err = client.Pull(ctx, testImage, WithPullUnpack); err != nil {
cmd.Process.Signal(syscall.SIGTERM) cmd.Process.Signal(syscall.SIGTERM)
cmd.Wait() cmd.Wait()
fmt.Fprintf(os.Stderr, "%s: %s", err, buf.String()) fmt.Fprintf(os.Stderr, "%s: %s", err, buf.String())
os.Exit(1) os.Exit(1)
} }
if err := client.Close(); err != nil { if err := client.Close(); err != nil {
fmt.Fprintln(os.Stderr, err) fmt.Fprintln(os.Stderr, err)

View File

@ -7,25 +7,15 @@ import (
"strings" "strings"
"sync" "sync"
"google.golang.org/grpc"
"google.golang.org/grpc/codes"
"github.com/containerd/containerd/api/services/tasks/v1" "github.com/containerd/containerd/api/services/tasks/v1"
"github.com/containerd/containerd/api/types" "github.com/containerd/containerd/api/types"
"github.com/containerd/containerd/containers" "github.com/containerd/containerd/containers"
"github.com/containerd/containerd/errdefs"
"github.com/containerd/containerd/typeurl" "github.com/containerd/containerd/typeurl"
specs "github.com/opencontainers/runtime-spec/specs-go" specs "github.com/opencontainers/runtime-spec/specs-go"
"github.com/pkg/errors" "github.com/pkg/errors"
) )
var (
ErrNoImage = errors.New("container does not have an image")
ErrNoRunningTask = errors.New("no running task")
ErrDeleteRunningTask = errors.New("cannot delete container with running task")
ErrProcessExited = errors.New("process already exited")
ErrNoExecID = errors.New("exec id must be provided")
)
type DeleteOpts func(context.Context, *Client, containers.Container) error type DeleteOpts func(context.Context, *Client, containers.Container) error
type Container interface { type Container interface {
@ -129,7 +119,7 @@ func WithRootFSDeletion(ctx context.Context, client *Client, c containers.Contai
// an error is returned if the container has running tasks // an error is returned if the container has running tasks
func (c *container) Delete(ctx context.Context, opts ...DeleteOpts) (err error) { func (c *container) Delete(ctx context.Context, opts ...DeleteOpts) (err error) {
if _, err := c.Task(ctx, nil); err == nil { if _, err := c.Task(ctx, nil); err == nil {
return ErrDeleteRunningTask return errors.Wrapf(errdefs.ErrFailedPrecondition, "cannot delete running task %v", c.ID())
} }
for _, o := range opts { for _, o := range opts {
if err := o(ctx, c.client, c.c); err != nil { if err := o(ctx, c.client, c.c); err != nil {
@ -150,11 +140,11 @@ func (c *container) Task(ctx context.Context, attach IOAttach) (Task, error) {
// Image returns the image that the container is based on // Image returns the image that the container is based on
func (c *container) Image(ctx context.Context) (Image, error) { func (c *container) Image(ctx context.Context) (Image, error) {
if c.c.Image == "" { if c.c.Image == "" {
return nil, ErrNoImage return nil, errors.Wrapf(errdefs.ErrNotFound, "container not created from an image")
} }
i, err := c.client.ImageService().Get(ctx, c.c.Image) i, err := c.client.ImageService().Get(ctx, c.c.Image)
if err != nil { if err != nil {
return nil, err return nil, errors.Wrapf(err, "failed to get image for container")
} }
return &image{ return &image{
client: c.client, client: c.client,
@ -229,8 +219,9 @@ func (c *container) loadTask(ctx context.Context, ioAttach IOAttach) (Task, erro
ContainerID: c.c.ID, ContainerID: c.c.ID,
}) })
if err != nil { if err != nil {
if grpc.Code(errors.Cause(err)) == codes.NotFound { err = errdefs.FromGRPC(err)
return nil, ErrNoRunningTask if errdefs.IsNotFound(err) {
return nil, errors.Wrapf(err, "no running task found")
} }
return nil, err return nil, err
} }

View File

@ -11,6 +11,7 @@ import (
"testing" "testing"
"github.com/containerd/cgroups" "github.com/containerd/cgroups"
"github.com/containerd/containerd/errdefs"
specs "github.com/opencontainers/runtime-spec/specs-go" specs "github.com/opencontainers/runtime-spec/specs-go"
) )
@ -632,8 +633,8 @@ func TestDeleteRunningContainer(t *testing.T) {
if err == nil { if err == nil {
t.Error("delete did not error with running task") t.Error("delete did not error with running task")
} }
if err != ErrDeleteRunningTask { if !errdefs.IsFailedPrecondition(err) {
t.Errorf("expected error %q but received %q", ErrDeleteRunningTask, err) t.Errorf("expected error %q but received %q", errdefs.ErrFailedPrecondition, err)
} }
if err := task.Kill(ctx, syscall.SIGKILL); err != nil { if err := task.Kill(ctx, syscall.SIGKILL); err != nil {
t.Error(err) t.Error(err)
@ -703,8 +704,8 @@ func TestContainerKill(t *testing.T) {
t.Error("second call to kill should return an error") t.Error("second call to kill should return an error")
return return
} }
if err != ErrProcessExited { if !errdefs.IsNotFound(err) {
t.Errorf("expected error %q but received %q", ErrProcessExited, err) t.Errorf("expected error %q but received %q", errdefs.ErrNotFound, err)
} }
} }

View File

@ -4,12 +4,11 @@ package linux
import ( import (
"context" "context"
"errors"
"github.com/containerd/containerd/api/types/task" "github.com/containerd/containerd/api/types/task"
"github.com/containerd/containerd/errdefs"
shim "github.com/containerd/containerd/linux/shim/v1" shim "github.com/containerd/containerd/linux/shim/v1"
"github.com/containerd/containerd/runtime" "github.com/containerd/containerd/runtime"
"google.golang.org/grpc"
) )
type Process struct { type Process struct {
@ -27,7 +26,7 @@ func (p *Process) Kill(ctx context.Context, signal uint32, _ bool) error {
ID: p.id, ID: p.id,
}) })
if err != nil { if err != nil {
err = errors.New(grpc.ErrorDesc(err)) return errdefs.FromGRPC(err)
} }
return err return err
} }
@ -38,7 +37,7 @@ func (p *Process) State(ctx context.Context) (runtime.State, error) {
ID: p.id, ID: p.id,
}) })
if err != nil { if err != nil {
return runtime.State{}, errors.New(grpc.ErrorDesc(err)) return runtime.State{}, errdefs.FromGRPC(err)
} }
var status runtime.Status var status runtime.Status
switch response.Status { switch response.Status {
@ -69,7 +68,7 @@ func (p *Process) ResizePty(ctx context.Context, size runtime.ConsoleSize) error
Height: size.Height, Height: size.Height,
}) })
if err != nil { if err != nil {
err = errors.New(grpc.ErrorDesc(err)) err = errdefs.FromGRPC(err)
} }
return err return err
} }
@ -80,7 +79,7 @@ func (p *Process) CloseIO(ctx context.Context) error {
Stdin: true, Stdin: true,
}) })
if err != nil { if err != nil {
err = errors.New(grpc.ErrorDesc(err)) err = errdefs.FromGRPC(err)
} }
return err return err
} }

View File

@ -9,10 +9,9 @@ import (
"os" "os"
"path/filepath" "path/filepath"
"google.golang.org/grpc"
"github.com/boltdb/bolt" "github.com/boltdb/bolt"
"github.com/containerd/containerd/api/types" "github.com/containerd/containerd/api/types"
"github.com/containerd/containerd/errdefs"
"github.com/containerd/containerd/identifiers" "github.com/containerd/containerd/identifiers"
client "github.com/containerd/containerd/linux/shim" client "github.com/containerd/containerd/linux/shim"
shim "github.com/containerd/containerd/linux/shim/v1" shim "github.com/containerd/containerd/linux/shim/v1"
@ -170,7 +169,7 @@ func (r *Runtime) Create(ctx context.Context, id string, opts runtime.CreateOpts
}) })
} }
if _, err = s.Create(ctx, sopts); err != nil { if _, err = s.Create(ctx, sopts); err != nil {
return nil, errors.New(grpc.ErrorDesc(err)) return nil, errdefs.FromGRPC(err)
} }
t := newTask(id, namespace, s) t := newTask(id, namespace, s)
if err := r.tasks.Add(ctx, t); err != nil { if err := r.tasks.Add(ctx, t); err != nil {
@ -197,7 +196,7 @@ func (r *Runtime) Delete(ctx context.Context, c runtime.Task) (*runtime.Exit, er
} }
rsp, err := lc.shim.Delete(ctx, empty) rsp, err := lc.shim.Delete(ctx, empty)
if err != nil { if err != nil {
return nil, errors.New(grpc.ErrorDesc(err)) return nil, errdefs.FromGRPC(err)
} }
if err := lc.shim.KillShim(ctx); err != nil { if err := lc.shim.KillShim(ctx); err != nil {
log.G(ctx).WithError(err).Error("failed to kill shim") log.G(ctx).WithError(err).Error("failed to kill shim")

View File

@ -164,7 +164,7 @@ func (e *execProcess) Resize(ws console.WinSize) error {
func (e *execProcess) Kill(ctx context.Context, sig uint32, _ bool) error { func (e *execProcess) Kill(ctx context.Context, sig uint32, _ bool) error {
if err := unix.Kill(e.pid, syscall.Signal(sig)); err != nil { if err := unix.Kill(e.pid, syscall.Signal(sig)); err != nil {
return checkKillError(err) return errors.Wrapf(checkKillError(err), "exec kill error")
} }
return nil return nil
} }

View File

@ -17,12 +17,12 @@ import (
"golang.org/x/sys/unix" "golang.org/x/sys/unix"
"github.com/containerd/console" "github.com/containerd/console"
"github.com/containerd/containerd/errdefs"
"github.com/containerd/containerd/identifiers" "github.com/containerd/containerd/identifiers"
"github.com/containerd/containerd/linux/runcopts" "github.com/containerd/containerd/linux/runcopts"
shimapi "github.com/containerd/containerd/linux/shim/v1" shimapi "github.com/containerd/containerd/linux/shim/v1"
"github.com/containerd/containerd/log" "github.com/containerd/containerd/log"
"github.com/containerd/containerd/mount" "github.com/containerd/containerd/mount"
"github.com/containerd/containerd/runtime"
"github.com/containerd/containerd/typeurl" "github.com/containerd/containerd/typeurl"
"github.com/containerd/fifo" "github.com/containerd/fifo"
runc "github.com/containerd/go-runc" runc "github.com/containerd/go-runc"
@ -388,7 +388,7 @@ func checkKillError(err error) error {
return nil return nil
} }
if strings.Contains(err.Error(), "os: process already finished") || err == unix.ESRCH { if strings.Contains(err.Error(), "os: process already finished") || err == unix.ESRCH {
return runtime.ErrProcessExited return errors.Wrapf(errdefs.ErrNotFound, "process already finished")
} }
return err return errors.Wrapf(err, "unknown error after kill")
} }

View File

@ -26,10 +26,6 @@ import (
"golang.org/x/net/context" "golang.org/x/net/context"
) )
const (
ErrContainerNotCreated = "container hasn't been created yet"
)
var empty = &google_protobuf.Empty{} var empty = &google_protobuf.Empty{}
const RuncRoot = "/run/containerd/runc" const RuncRoot = "/run/containerd/runc"
@ -115,7 +111,7 @@ func (s *Service) Create(ctx context.Context, r *shimapi.CreateTaskRequest) (*sh
func (s *Service) Start(ctx context.Context, r *google_protobuf.Empty) (*google_protobuf.Empty, error) { func (s *Service) Start(ctx context.Context, r *google_protobuf.Empty) (*google_protobuf.Empty, error) {
if s.initProcess == nil { if s.initProcess == nil {
return nil, errors.New(ErrContainerNotCreated) return nil, errdefs.ToGRPCf(errdefs.ErrFailedPrecondition, "container must be created")
} }
if err := s.initProcess.Start(ctx); err != nil { if err := s.initProcess.Start(ctx); err != nil {
return nil, err return nil, err
@ -129,7 +125,7 @@ func (s *Service) Start(ctx context.Context, r *google_protobuf.Empty) (*google_
func (s *Service) Delete(ctx context.Context, r *google_protobuf.Empty) (*shimapi.DeleteResponse, error) { func (s *Service) Delete(ctx context.Context, r *google_protobuf.Empty) (*shimapi.DeleteResponse, error) {
if s.initProcess == nil { if s.initProcess == nil {
return nil, errors.New(ErrContainerNotCreated) return nil, errdefs.ToGRPCf(errdefs.ErrFailedPrecondition, "container must be created")
} }
p := s.initProcess p := s.initProcess
// TODO (@crosbymichael): how to handle errors here // TODO (@crosbymichael): how to handle errors here
@ -152,7 +148,7 @@ func (s *Service) Delete(ctx context.Context, r *google_protobuf.Empty) (*shimap
func (s *Service) DeleteProcess(ctx context.Context, r *shimapi.DeleteProcessRequest) (*shimapi.DeleteResponse, error) { func (s *Service) DeleteProcess(ctx context.Context, r *shimapi.DeleteProcessRequest) (*shimapi.DeleteResponse, error) {
if s.initProcess == nil { if s.initProcess == nil {
return nil, errors.New(ErrContainerNotCreated) return nil, errdefs.ToGRPCf(errdefs.ErrFailedPrecondition, "container must be created")
} }
if r.ID == s.initProcess.id { if r.ID == s.initProcess.id {
return nil, grpc.Errorf(codes.InvalidArgument, "cannot delete init process with DeleteProcess") return nil, grpc.Errorf(codes.InvalidArgument, "cannot delete init process with DeleteProcess")
@ -161,7 +157,7 @@ func (s *Service) DeleteProcess(ctx context.Context, r *shimapi.DeleteProcessReq
p, ok := s.processes[r.ID] p, ok := s.processes[r.ID]
s.mu.Unlock() s.mu.Unlock()
if !ok { if !ok {
return nil, fmt.Errorf("process %s not found", r.ID) return nil, errors.Wrapf(errdefs.ErrNotFound, "process %s not found", r.ID)
} }
// TODO (@crosbymichael): how to handle errors here // TODO (@crosbymichael): how to handle errors here
p.Delete(ctx) p.Delete(ctx)
@ -177,14 +173,14 @@ func (s *Service) DeleteProcess(ctx context.Context, r *shimapi.DeleteProcessReq
func (s *Service) Exec(ctx context.Context, r *shimapi.ExecProcessRequest) (*shimapi.ExecProcessResponse, error) { func (s *Service) Exec(ctx context.Context, r *shimapi.ExecProcessRequest) (*shimapi.ExecProcessResponse, error) {
if s.initProcess == nil { if s.initProcess == nil {
return nil, errors.New(ErrContainerNotCreated) return nil, errdefs.ToGRPCf(errdefs.ErrFailedPrecondition, "container must be created")
} }
s.mu.Lock() s.mu.Lock()
defer s.mu.Unlock() defer s.mu.Unlock()
process, err := newExecProcess(ctx, s.path, r, s.initProcess, r.ID) process, err := newExecProcess(ctx, s.path, r, s.initProcess, r.ID)
if err != nil { if err != nil {
return nil, err return nil, errdefs.ToGRPC(err)
} }
pid := process.Pid() pid := process.Pid()
cmd := &reaper.Cmd{ cmd := &reaper.Cmd{
@ -206,7 +202,7 @@ func (s *Service) Exec(ctx context.Context, r *shimapi.ExecProcessRequest) (*shi
func (s *Service) ResizePty(ctx context.Context, r *shimapi.ResizePtyRequest) (*google_protobuf.Empty, error) { func (s *Service) ResizePty(ctx context.Context, r *shimapi.ResizePtyRequest) (*google_protobuf.Empty, error) {
if r.ID == "" { if r.ID == "" {
return nil, grpc.Errorf(codes.InvalidArgument, "id not provided") return nil, errdefs.ToGRPCf(errdefs.ErrInvalidArgument, "id not provided")
} }
ws := console.WinSize{ ws := console.WinSize{
Width: uint16(r.Width), Width: uint16(r.Width),
@ -219,18 +215,18 @@ func (s *Service) ResizePty(ctx context.Context, r *shimapi.ResizePtyRequest) (*
return nil, errors.Errorf("process does not exist %s", r.ID) 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, err return nil, errdefs.ToGRPC(err)
} }
return empty, nil return empty, nil
} }
func (s *Service) State(ctx context.Context, r *shimapi.StateRequest) (*shimapi.StateResponse, error) { func (s *Service) State(ctx context.Context, r *shimapi.StateRequest) (*shimapi.StateResponse, error) {
if s.initProcess == nil { if s.initProcess == nil {
return nil, errors.New(ErrContainerNotCreated) return nil, errdefs.ToGRPCf(errdefs.ErrFailedPrecondition, "container must be created")
} }
p, ok := s.processes[r.ID] p, ok := s.processes[r.ID]
if !ok { if !ok {
return nil, grpc.Errorf(codes.NotFound, "process id %s not found", r.ID) return nil, errdefs.ToGRPCf(errdefs.ErrNotFound, "process id %s not found", r.ID)
} }
st, err := s.initProcess.ContainerStatus(ctx) st, err := s.initProcess.ContainerStatus(ctx)
if err != nil { if err != nil {
@ -262,7 +258,7 @@ func (s *Service) State(ctx context.Context, r *shimapi.StateRequest) (*shimapi.
func (s *Service) Pause(ctx context.Context, r *google_protobuf.Empty) (*google_protobuf.Empty, error) { func (s *Service) Pause(ctx context.Context, r *google_protobuf.Empty) (*google_protobuf.Empty, error) {
if s.initProcess == nil { if s.initProcess == nil {
return nil, errors.New(ErrContainerNotCreated) return nil, errdefs.ToGRPCf(errdefs.ErrFailedPrecondition, "container must be created")
} }
if err := s.initProcess.Pause(ctx); err != nil { if err := s.initProcess.Pause(ctx); err != nil {
return nil, err return nil, err
@ -275,7 +271,7 @@ func (s *Service) Pause(ctx context.Context, r *google_protobuf.Empty) (*google_
func (s *Service) Resume(ctx context.Context, r *google_protobuf.Empty) (*google_protobuf.Empty, error) { func (s *Service) Resume(ctx context.Context, r *google_protobuf.Empty) (*google_protobuf.Empty, error) {
if s.initProcess == nil { if s.initProcess == nil {
return nil, errors.New(ErrContainerNotCreated) return nil, errdefs.ToGRPCf(errdefs.ErrFailedPrecondition, "container must be created")
} }
if err := s.initProcess.Resume(ctx); err != nil { if err := s.initProcess.Resume(ctx); err != nil {
return nil, err return nil, err
@ -288,20 +284,20 @@ func (s *Service) Resume(ctx context.Context, r *google_protobuf.Empty) (*google
func (s *Service) Kill(ctx context.Context, r *shimapi.KillRequest) (*google_protobuf.Empty, error) { func (s *Service) Kill(ctx context.Context, r *shimapi.KillRequest) (*google_protobuf.Empty, error) {
if s.initProcess == nil { if s.initProcess == nil {
return nil, errors.New(ErrContainerNotCreated) return nil, errdefs.ToGRPCf(errdefs.ErrFailedPrecondition, "container must be created")
} }
if r.ID == "" { if r.ID == "" {
if err := s.initProcess.Kill(ctx, r.Signal, r.All); err != nil { if err := s.initProcess.Kill(ctx, r.Signal, r.All); err != nil {
return nil, err return nil, errdefs.ToGRPC(err)
} }
return empty, nil return empty, nil
} }
p, ok := s.processes[r.ID] p, ok := s.processes[r.ID]
if !ok { if !ok {
return nil, grpc.Errorf(codes.NotFound, "process id %s not found", r.ID) return nil, errdefs.ToGRPCf(errdefs.ErrNotFound, "process id %s not found", r.ID)
} }
if err := p.Kill(ctx, r.Signal, r.All); err != nil { if err := p.Kill(ctx, r.Signal, r.All); err != nil {
return nil, err return nil, errdefs.ToGRPC(err)
} }
return empty, nil return empty, nil
} }
@ -309,7 +305,7 @@ func (s *Service) Kill(ctx context.Context, r *shimapi.KillRequest) (*google_pro
func (s *Service) ListPids(ctx context.Context, r *shimapi.ListPidsRequest) (*shimapi.ListPidsResponse, error) { func (s *Service) ListPids(ctx context.Context, r *shimapi.ListPidsRequest) (*shimapi.ListPidsResponse, error) {
pids, err := s.getContainerPids(ctx, r.ID) pids, err := s.getContainerPids(ctx, r.ID)
if err != nil { if err != nil {
return nil, err return nil, errdefs.ToGRPC(err)
} }
return &shimapi.ListPidsResponse{ return &shimapi.ListPidsResponse{
Pids: pids, Pids: pids,
@ -319,7 +315,7 @@ func (s *Service) ListPids(ctx context.Context, r *shimapi.ListPidsRequest) (*sh
func (s *Service) CloseIO(ctx context.Context, r *shimapi.CloseIORequest) (*google_protobuf.Empty, error) { func (s *Service) CloseIO(ctx context.Context, r *shimapi.CloseIORequest) (*google_protobuf.Empty, error) {
p, ok := s.processes[r.ID] p, ok := s.processes[r.ID]
if !ok { if !ok {
return nil, grpc.Errorf(codes.NotFound, "process does not exist %s", r.ID) return nil, errdefs.ToGRPCf(errdefs.ErrNotFound, "process does not exist %s", r.ID)
} }
if err := p.Stdin().Close(); err != nil { if err := p.Stdin().Close(); err != nil {
return nil, err return nil, err
@ -329,10 +325,10 @@ func (s *Service) CloseIO(ctx context.Context, r *shimapi.CloseIORequest) (*goog
func (s *Service) Checkpoint(ctx context.Context, r *shimapi.CheckpointTaskRequest) (*google_protobuf.Empty, error) { func (s *Service) Checkpoint(ctx context.Context, r *shimapi.CheckpointTaskRequest) (*google_protobuf.Empty, error) {
if s.initProcess == nil { if s.initProcess == nil {
return nil, errors.New(ErrContainerNotCreated) return nil, errdefs.ToGRPCf(errdefs.ErrFailedPrecondition, "container must be created")
} }
if err := s.initProcess.Checkpoint(ctx, r); err != nil { if err := s.initProcess.Checkpoint(ctx, r); err != nil {
return nil, err return nil, errdefs.ToGRPC(err)
} }
s.events <- &events.TaskCheckpointed{ s.events <- &events.TaskCheckpointed{
ContainerID: s.id, ContainerID: s.id,
@ -348,10 +344,10 @@ func (s *Service) ShimInfo(ctx context.Context, r *google_protobuf.Empty) (*shim
func (s *Service) Update(ctx context.Context, r *shimapi.UpdateTaskRequest) (*google_protobuf.Empty, error) { func (s *Service) Update(ctx context.Context, r *shimapi.UpdateTaskRequest) (*google_protobuf.Empty, error) {
if s.initProcess == nil { if s.initProcess == nil {
return nil, errors.New(ErrContainerNotCreated) return nil, errdefs.ToGRPCf(errdefs.ErrFailedPrecondition, "container must be created")
} }
if err := s.initProcess.Update(ctx, r); err != nil { if err := s.initProcess.Update(ctx, r); err != nil {
return nil, err return nil, errdefs.ToGRPC(err)
} }
return empty, nil return empty, nil
} }

View File

@ -5,14 +5,12 @@ package linux
import ( import (
"context" "context"
"google.golang.org/grpc"
"github.com/containerd/containerd/api/types/task" "github.com/containerd/containerd/api/types/task"
"github.com/containerd/containerd/errdefs"
client "github.com/containerd/containerd/linux/shim" client "github.com/containerd/containerd/linux/shim"
shim "github.com/containerd/containerd/linux/shim/v1" shim "github.com/containerd/containerd/linux/shim/v1"
"github.com/containerd/containerd/runtime" "github.com/containerd/containerd/runtime"
"github.com/gogo/protobuf/types" "github.com/gogo/protobuf/types"
"github.com/pkg/errors"
) )
type Task struct { type Task struct {
@ -44,7 +42,7 @@ func (t *Task) Info() runtime.TaskInfo {
func (t *Task) Start(ctx context.Context) error { func (t *Task) Start(ctx context.Context) error {
_, err := t.shim.Start(ctx, empty) _, err := t.shim.Start(ctx, empty)
if err != nil { if err != nil {
err = errors.New(grpc.ErrorDesc(err)) err = errdefs.FromGRPC(err)
} }
return err return err
} }
@ -54,7 +52,7 @@ func (t *Task) State(ctx context.Context) (runtime.State, error) {
ID: t.id, ID: t.id,
}) })
if err != nil { if err != nil {
return runtime.State{}, errors.New(grpc.ErrorDesc(err)) return runtime.State{}, errdefs.FromGRPC(err)
} }
var status runtime.Status var status runtime.Status
switch response.Status { switch response.Status {
@ -81,7 +79,7 @@ func (t *Task) State(ctx context.Context) (runtime.State, error) {
func (t *Task) Pause(ctx context.Context) error { func (t *Task) Pause(ctx context.Context) error {
_, err := t.shim.Pause(ctx, empty) _, err := t.shim.Pause(ctx, empty)
if err != nil { if err != nil {
err = errors.New(grpc.ErrorDesc(err)) err = errdefs.FromGRPC(err)
} }
return err return err
} }
@ -89,7 +87,7 @@ func (t *Task) Pause(ctx context.Context) error {
func (t *Task) Resume(ctx context.Context) error { func (t *Task) Resume(ctx context.Context) error {
_, err := t.shim.Resume(ctx, empty) _, err := t.shim.Resume(ctx, empty)
if err != nil { if err != nil {
err = errors.New(grpc.ErrorDesc(err)) err = errdefs.FromGRPC(err)
} }
return err return err
} }
@ -101,7 +99,7 @@ func (t *Task) Kill(ctx context.Context, signal uint32, all bool) error {
All: all, All: all,
}) })
if err != nil { if err != nil {
err = errors.New(grpc.ErrorDesc(err)) return errdefs.FromGRPC(err)
} }
return err return err
} }
@ -116,7 +114,7 @@ func (t *Task) Exec(ctx context.Context, id string, opts runtime.ExecOpts) (runt
Spec: opts.Spec, Spec: opts.Spec,
} }
if _, err := t.shim.Exec(ctx, request); err != nil { if _, err := t.shim.Exec(ctx, request); err != nil {
return nil, errors.New(grpc.ErrorDesc(err)) return nil, errdefs.FromGRPC(err)
} }
return &Process{ return &Process{
id: id, id: id,
@ -130,7 +128,7 @@ func (t *Task) Pids(ctx context.Context) ([]uint32, error) {
ID: t.id, ID: t.id,
}) })
if err != nil { if err != nil {
return nil, errors.New(grpc.ErrorDesc(err)) return nil, errdefs.FromGRPC(err)
} }
return resp.Pids, nil return resp.Pids, nil
} }
@ -142,7 +140,7 @@ func (t *Task) ResizePty(ctx context.Context, size runtime.ConsoleSize) error {
Height: size.Height, Height: size.Height,
}) })
if err != nil { if err != nil {
err = errors.New(grpc.ErrorDesc(err)) err = errdefs.FromGRPC(err)
} }
return err return err
} }
@ -153,7 +151,7 @@ func (t *Task) CloseIO(ctx context.Context) error {
Stdin: true, Stdin: true,
}) })
if err != nil { if err != nil {
err = errors.New(grpc.ErrorDesc(err)) err = errdefs.FromGRPC(err)
} }
return err return err
} }
@ -164,7 +162,7 @@ func (t *Task) Checkpoint(ctx context.Context, path string, options *types.Any)
Options: options, Options: options,
} }
if _, err := t.shim.Checkpoint(ctx, r); err != nil { if _, err := t.shim.Checkpoint(ctx, r); err != nil {
return errors.New(grpc.ErrorDesc(err)) return errdefs.FromGRPC(err)
} }
return nil return nil
} }
@ -174,7 +172,7 @@ func (t *Task) DeleteProcess(ctx context.Context, id string) (*runtime.Exit, err
ID: id, ID: id,
}) })
if err != nil { if err != nil {
return nil, errors.New(grpc.ErrorDesc(err)) return nil, errdefs.FromGRPC(err)
} }
return &runtime.Exit{ return &runtime.Exit{
Status: r.ExitStatus, Status: r.ExitStatus,

View File

@ -1,10 +0,0 @@
package runtime
import "errors"
var (
ErrContainerExists = errors.New("runtime: container with id already exists")
ErrContainerNotExist = errors.New("runtime: container does not exist")
ErrRuntimeNotExist = errors.New("runtime: runtime does not exist")
ErrProcessExited = errors.New("runtime: process already exited")
)

View File

@ -319,7 +319,7 @@ func (s *Service) Kill(ctx context.Context, r *api.KillRequest) (*google_protobu
} }
} }
if err := p.Kill(ctx, r.Signal, r.All); err != nil { if err := p.Kill(ctx, r.Signal, r.All); err != nil {
return nil, err return nil, errdefs.ToGRPC(err)
} }
return empty, nil return empty, nil
} }

19
task.go
View File

@ -14,14 +14,14 @@ import (
"github.com/containerd/containerd/api/services/tasks/v1" "github.com/containerd/containerd/api/services/tasks/v1"
"github.com/containerd/containerd/api/types" "github.com/containerd/containerd/api/types"
"github.com/containerd/containerd/content" "github.com/containerd/containerd/content"
"github.com/containerd/containerd/errdefs"
"github.com/containerd/containerd/linux/runcopts" "github.com/containerd/containerd/linux/runcopts"
"github.com/containerd/containerd/rootfs" "github.com/containerd/containerd/rootfs"
"github.com/containerd/containerd/runtime"
"github.com/containerd/containerd/typeurl" "github.com/containerd/containerd/typeurl"
digest "github.com/opencontainers/go-digest" digest "github.com/opencontainers/go-digest"
"github.com/opencontainers/image-spec/specs-go/v1" "github.com/opencontainers/image-spec/specs-go/v1"
specs "github.com/opencontainers/runtime-spec/specs-go" specs "github.com/opencontainers/runtime-spec/specs-go"
"google.golang.org/grpc" "github.com/pkg/errors"
) )
const UnknownExitStatus = 255 const UnknownExitStatus = 255
@ -130,10 +130,7 @@ func (t *task) Kill(ctx context.Context, s syscall.Signal) error {
ContainerID: t.id, ContainerID: t.id,
}) })
if err != nil { if err != nil {
if strings.Contains(grpc.ErrorDesc(err), runtime.ErrProcessExited.Error()) { return errdefs.FromGRPC(err)
return ErrProcessExited
}
return err
} }
return nil return nil
} }
@ -142,14 +139,14 @@ func (t *task) Pause(ctx context.Context) error {
_, err := t.client.TaskService().Pause(ctx, &tasks.PauseTaskRequest{ _, err := t.client.TaskService().Pause(ctx, &tasks.PauseTaskRequest{
ContainerID: t.id, ContainerID: t.id,
}) })
return err return errdefs.FromGRPC(err)
} }
func (t *task) Resume(ctx context.Context) error { func (t *task) Resume(ctx context.Context) error {
_, err := t.client.TaskService().Resume(ctx, &tasks.ResumeTaskRequest{ _, err := t.client.TaskService().Resume(ctx, &tasks.ResumeTaskRequest{
ContainerID: t.id, ContainerID: t.id,
}) })
return err return errdefs.FromGRPC(err)
} }
func (t *task) Status(ctx context.Context) (TaskStatus, error) { func (t *task) Status(ctx context.Context) (TaskStatus, error) {
@ -157,7 +154,7 @@ func (t *task) Status(ctx context.Context) (TaskStatus, error) {
ContainerID: t.id, ContainerID: t.id,
}) })
if err != nil { if err != nil {
return "", err return "", errdefs.FromGRPC(err)
} }
return TaskStatus(strings.ToLower(r.Task.Status.String())), nil return TaskStatus(strings.ToLower(r.Task.Status.String())), nil
} }
@ -166,7 +163,7 @@ func (t *task) Status(ctx context.Context) (TaskStatus, error) {
func (t *task) Wait(ctx context.Context) (uint32, error) { func (t *task) Wait(ctx context.Context) (uint32, error) {
eventstream, err := t.client.EventService().Stream(ctx, &eventsapi.StreamEventsRequest{}) eventstream, err := t.client.EventService().Stream(ctx, &eventsapi.StreamEventsRequest{})
if err != nil { if err != nil {
return UnknownExitStatus, err return UnknownExitStatus, errdefs.FromGRPC(err)
} }
for { for {
evt, err := eventstream.Recv() evt, err := eventstream.Recv()
@ -205,7 +202,7 @@ func (t *task) Delete(ctx context.Context) (uint32, error) {
func (t *task) Exec(ctx context.Context, id string, spec *specs.Process, ioCreate IOCreation) (Process, error) { func (t *task) Exec(ctx context.Context, id string, spec *specs.Process, ioCreate IOCreation) (Process, error) {
if id == "" { if id == "" {
return nil, ErrNoExecID return nil, errors.Wrapf(errdefs.ErrInvalidArgument, "exec id must not be empty")
} }
i, err := ioCreate() i, err := ioCreate()
if err != nil { if err != nil {