diff --git a/cmd/ctr/task_delete.go b/cmd/ctr/task_delete.go index 932cc3b80..73b50616f 100644 --- a/cmd/ctr/task_delete.go +++ b/cmd/ctr/task_delete.go @@ -25,8 +25,8 @@ var taskDeleteCommand = cli.Command{ if err != nil { return err } - if status != 0 { - return cli.NewExitError("", int(status)) + if ec := status.ExitCode(); ec != 0 { + return cli.NewExitError("", int(ec)) } return nil }, diff --git a/container_test.go b/container_test.go index 0c0d8416c..ffd7583ae 100644 --- a/container_test.go +++ b/container_test.go @@ -155,8 +155,8 @@ func TestContainerStart(t *testing.T) { t.Error(err) return } - if deleteStatus != 7 { - t.Errorf("expected status 7 from delete but received %d", deleteStatus) + if ec := deleteStatus.ExitCode(); ec != 7 { + t.Errorf("expected status 7 from delete but received %d", ec) } } @@ -324,8 +324,8 @@ func TestContainerExec(t *testing.T) { t.Error(err) return } - if deleteStatus != 6 { - t.Errorf("expected delete exit code e6 but received %d", deleteStatus) + if ec := deleteStatus.ExitCode(); ec != 6 { + t.Errorf("expected delete exit code 6 but received %d", ec) } if err := task.Kill(ctx, syscall.SIGKILL); err != nil { t.Error(err) @@ -823,8 +823,8 @@ func TestUserNamespaces(t *testing.T) { t.Error(err) return } - if deleteStatus != 7 { - t.Errorf("expected status 7 from delete but received %d", deleteStatus) + if ec := deleteStatus.ExitCode(); ec != 7 { + t.Errorf("expected status 7 from delete but received %d", ec) } } @@ -1358,8 +1358,8 @@ func TestDeleteContainerExecCreated(t *testing.T) { t.Error(err) return } - if deleteStatus != 0 { - t.Errorf("expected delete exit code 0 but received %d", deleteStatus) + if ec := deleteStatus.ExitCode(); ec != 0 { + t.Errorf("expected delete exit code 0 but received %d", ec) } if err := task.Kill(ctx, syscall.SIGKILL); err != nil { t.Error(err) diff --git a/process.go b/process.go index 4a341dc37..276869564 100644 --- a/process.go +++ b/process.go @@ -22,7 +22,7 @@ type Process interface { // Start starts the process executing the user's defined binary Start(context.Context) error // Delete removes the process and any resources allocated returning the exit status - Delete(context.Context, ...ProcessDeleteOpts) (uint32, error) + Delete(context.Context, ...ProcessDeleteOpts) (*ExitStatus, error) // Kill sends the provided signal to the process Kill(context.Context, syscall.Signal) error // Wait asynchronously waits for the process to exit, and sends the exit code to the returned channel @@ -54,6 +54,24 @@ func (s ExitStatus) Result() (uint32, time.Time, error) { return s.code, s.exitedAt, s.err } +// ExitCode returns the exit code of the process. +// This is only valid is Error() returns nil +func (s ExitStatus) ExitCode() uint32 { + return s.code +} + +// ExitTime returns the exit time of the process +// This is only valid is Error() returns nil +func (s ExitStatus) ExitTime() time.Time { + return s.exitedAt +} + +// Error returns the error, if any, that occured while waiting for the +// process. +func (s ExitStatus) Error() error { + return s.err +} + type process struct { id string task *task @@ -176,32 +194,32 @@ func (p *process) Resize(ctx context.Context, w, h uint32) error { return errdefs.FromGRPC(err) } -func (p *process) Delete(ctx context.Context, opts ...ProcessDeleteOpts) (uint32, error) { +func (p *process) Delete(ctx context.Context, opts ...ProcessDeleteOpts) (*ExitStatus, error) { for _, o := range opts { if err := o(ctx, p); err != nil { - return UnknownExitStatus, err + return nil, err } } status, err := p.Status(ctx) if err != nil { - return UnknownExitStatus, err + return nil, err } switch status.Status { case Running, Paused, Pausing: - return UnknownExitStatus, errors.Wrapf(errdefs.ErrFailedPrecondition, "process must be stopped before deletion") + return nil, errors.Wrapf(errdefs.ErrFailedPrecondition, "process must be stopped before deletion") } r, err := p.task.client.TaskService().DeleteProcess(ctx, &tasks.DeleteProcessRequest{ ContainerID: p.task.id, ExecID: p.id, }) if err != nil { - return UnknownExitStatus, errdefs.FromGRPC(err) + return nil, errdefs.FromGRPC(err) } if p.io != nil { p.io.Wait() p.io.Close() } - return r.ExitStatus, nil + return &ExitStatus{code: r.ExitStatus, exitedAt: r.ExitedAt}, nil } func (p *process) Status(ctx context.Context) (Status, error) { diff --git a/task.go b/task.go index e55aab6ed..ea85d6742 100644 --- a/task.go +++ b/task.go @@ -261,15 +261,15 @@ func (t *task) Wait(ctx context.Context) (<-chan ExitStatus, error) { // Delete deletes the task and its runtime state // it returns the exit status of the task and any errors that were encountered // during cleanup -func (t *task) Delete(ctx context.Context, opts ...ProcessDeleteOpts) (uint32, error) { +func (t *task) Delete(ctx context.Context, opts ...ProcessDeleteOpts) (*ExitStatus, error) { for _, o := range opts { if err := o(ctx, t); err != nil { - return UnknownExitStatus, err + return nil, err } } status, err := t.Status(ctx) if err != nil && errdefs.IsNotFound(err) { - return UnknownExitStatus, err + return nil, err } switch status.Status { case Stopped, Unknown, "": @@ -280,7 +280,7 @@ func (t *task) Delete(ctx context.Context, opts ...ProcessDeleteOpts) (uint32, e } fallthrough default: - return UnknownExitStatus, errors.Wrapf(errdefs.ErrFailedPrecondition, "task must be stopped before deletion: %s", status.Status) + return nil, errors.Wrapf(errdefs.ErrFailedPrecondition, "task must be stopped before deletion: %s", status.Status) } if t.io != nil { t.io.Cancel() @@ -291,9 +291,9 @@ func (t *task) Delete(ctx context.Context, opts ...ProcessDeleteOpts) (uint32, e ContainerID: t.id, }) if err != nil { - return UnknownExitStatus, errdefs.FromGRPC(err) + return nil, errdefs.FromGRPC(err) } - return r.ExitStatus, nil + return &ExitStatus{code: r.ExitStatus, exitedAt: r.ExitedAt}, nil } func (t *task) Exec(ctx context.Context, id string, spec *specs.Process, ioCreate IOCreation) (Process, error) {