Update godoc for client package

Signed-off-by: Michael Crosby <crosbymichael@gmail.com>
This commit is contained in:
Michael Crosby 2017-08-03 15:19:31 -04:00
parent 7e0063320c
commit 0a85f6e47d
8 changed files with 135 additions and 23 deletions

View File

@ -64,8 +64,13 @@ type clientOpts struct {
dialOptions []grpc.DialOption dialOptions []grpc.DialOption
} }
// ClientOpt allows callers to set options on the containerd client
type ClientOpt func(c *clientOpts) error type ClientOpt func(c *clientOpts) error
// WithDefaultNamespace sets the default namespace on the client
//
// Any operation that does not have a namespace set on the context will
// be provided the default namespace
func WithDefaultNamespace(ns string) ClientOpt { func WithDefaultNamespace(ns string) ClientOpt {
return func(c *clientOpts) error { return func(c *clientOpts) error {
c.defaultns = ns c.defaultns = ns
@ -132,6 +137,8 @@ type Client struct {
runtime string runtime string
} }
// IsServing returns true if the client can successfully connect to the containerd daemon
// and the healthcheck service returns the SERVING response
func (c *Client) IsServing(ctx context.Context) (bool, error) { func (c *Client) IsServing(ctx context.Context) (bool, error) {
r, err := c.HealthService().Check(ctx, &grpc_health_v1.HealthCheckRequest{}) r, err := c.HealthService().Check(ctx, &grpc_health_v1.HealthCheckRequest{})
if err != nil { if err != nil {
@ -153,6 +160,7 @@ func (c *Client) Containers(ctx context.Context, filters ...string) ([]Container
return out, nil return out, nil
} }
// NewContainerOpts allows the caller to set additional options when creating a container
type NewContainerOpts func(ctx context.Context, client *Client, c *containers.Container) error type NewContainerOpts func(ctx context.Context, client *Client, c *containers.Container) error
// WithContainerLabels adds the provided labels to the container // WithContainerLabels adds the provided labels to the container
@ -220,6 +228,7 @@ func WithRuntime(name string) NewContainerOpts {
} }
} }
// WithSnapshotter sets the provided snapshotter for use by the container
func WithSnapshotter(name string) NewContainerOpts { func WithSnapshotter(name string) NewContainerOpts {
return func(ctx context.Context, client *Client, c *containers.Container) error { return func(ctx context.Context, client *Client, c *containers.Container) error {
c.Snapshotter = name c.Snapshotter = name
@ -227,6 +236,7 @@ func WithSnapshotter(name string) NewContainerOpts {
} }
} }
// WithImage sets the provided image as the base for the container
func WithImage(i Image) NewContainerOpts { func WithImage(i Image) NewContainerOpts {
return func(ctx context.Context, client *Client, c *containers.Container) error { return func(ctx context.Context, client *Client, c *containers.Container) error {
c.Image = i.Name() c.Image = i.Name()
@ -255,6 +265,7 @@ func (c *Client) NewContainer(ctx context.Context, id string, opts ...NewContain
return containerFromRecord(c, r), nil return containerFromRecord(c, r), nil
} }
// LoadContainer loads an existing container from metadata
func (c *Client) LoadContainer(ctx context.Context, id string) (Container, error) { func (c *Client) LoadContainer(ctx context.Context, id string) (Container, error) {
r, err := c.ContainerService().Get(ctx, id) r, err := c.ContainerService().Get(ctx, id)
if err != nil { if err != nil {
@ -263,6 +274,7 @@ func (c *Client) LoadContainer(ctx context.Context, id string) (Container, error
return containerFromRecord(c, r), nil return containerFromRecord(c, r), nil
} }
// RemoteOpts allows the caller to set distribution options for a remote
type RemoteOpts func(*Client, *RemoteContext) error type RemoteOpts func(*Client, *RemoteContext) error
// RemoteContext is used to configure object resolutions and transfers with // RemoteContext is used to configure object resolutions and transfers with
@ -339,6 +351,7 @@ func WithImageHandler(h images.Handler) RemoteOpts {
} }
} }
// Pull downloads the provided content into containerd's content store
func (c *Client) Pull(ctx context.Context, ref string, opts ...RemoteOpts) (Image, error) { func (c *Client) Pull(ctx context.Context, ref string, opts ...RemoteOpts) (Image, error) {
pullCtx := defaultRemoteContext() pullCtx := defaultRemoteContext()
for _, o := range opts { for _, o := range opts {
@ -414,6 +427,7 @@ func (c *Client) Pull(ctx context.Context, ref string, opts ...RemoteOpts) (Imag
return img, nil return img, nil
} }
// Push uploads the provided content to a remote resource
func (c *Client) Push(ctx context.Context, ref string, desc ocispec.Descriptor, opts ...RemoteOpts) error { func (c *Client) Push(ctx context.Context, ref string, desc ocispec.Descriptor, opts ...RemoteOpts) error {
pushCtx := defaultRemoteContext() pushCtx := defaultRemoteContext()
for _, o := range opts { for _, o := range opts {
@ -539,11 +553,15 @@ func (c *Client) VersionService() versionservice.VersionClient {
return versionservice.NewVersionClient(c.conn) return versionservice.NewVersionClient(c.conn)
} }
// Version of containerd
type Version struct { type Version struct {
Version string // Version number
Version string
// Revision from git that was built
Revision string Revision string
} }
// Version returns the version of containerd that the client is connected to
func (c *Client) Version(ctx context.Context) (Version, error) { func (c *Client) Version(ctx context.Context) (Version, error) {
response, err := c.VersionService().Version(ctx, &pempty.Empty{}) response, err := c.VersionService().Version(ctx, &pempty.Empty{})
if err != nil { if err != nil {
@ -566,8 +584,10 @@ type importOpts struct {
refObject string refObject string
} }
// ImportOpt allows the caller to specify import specific options
type ImportOpt func(c *importOpts) error type ImportOpt func(c *importOpts) error
// WithOCIImportFormat sets the import format for an OCI image format
func WithOCIImportFormat() ImportOpt { func WithOCIImportFormat() ImportOpt {
return func(c *importOpts) error { return func(c *importOpts) error {
if c.format != "" { if c.format != "" {
@ -630,8 +650,10 @@ type exportOpts struct {
format imageFormat format imageFormat
} }
// ExportOpt allows callers to set export options
type ExportOpt func(c *exportOpts) error type ExportOpt func(c *exportOpts) error
// WithOCIExportFormat sets the OCI image format as the export target
func WithOCIExportFormat() ExportOpt { func WithOCIExportFormat() ExportOpt {
return func(c *exportOpts) error { return func(c *exportOpts) error {
if c.format != "" { if c.format != "" {

View File

@ -17,17 +17,31 @@ import (
"github.com/pkg/errors" "github.com/pkg/errors"
) )
// DeleteOpts allows the caller to set options for the deletion of a container
type DeleteOpts func(context.Context, *Client, containers.Container) error type DeleteOpts func(context.Context, *Client, containers.Container) error
// Container is a metadata object for container resources and task creation
type Container interface { type Container interface {
// ID identifies the container
ID() string ID() string
// Info returns the underlying container record type
Info() containers.Container Info() containers.Container
// Delete removes the container
Delete(context.Context, ...DeleteOpts) error Delete(context.Context, ...DeleteOpts) error
// NewTask creates a new task based on the container metadata
NewTask(context.Context, IOCreation, ...NewTaskOpts) (Task, error) NewTask(context.Context, IOCreation, ...NewTaskOpts) (Task, error)
// Spec returns the OCI runtime specification
Spec() (*specs.Spec, error) Spec() (*specs.Spec, error)
// Task returns the current task for the container
//
// If IOAttach options are passed the client will reattach to the IO for the running
// task. If no task exists for the container a NotFound error is returned
Task(context.Context, IOAttach) (Task, error) Task(context.Context, IOAttach) (Task, error)
// Image returns the image that the container is based on
Image(context.Context) (Image, error) Image(context.Context) (Image, error)
// Labels returns the labels set on the container
Labels(context.Context) (map[string]string, error) Labels(context.Context) (map[string]string, error)
// SetLabels sets the provided labels for the container and returns the final label set
SetLabels(context.Context, map[string]string) (map[string]string, error) SetLabels(context.Context, map[string]string) (map[string]string, error)
} }
@ -153,8 +167,10 @@ func (c *container) Image(ctx context.Context) (Image, error) {
}, nil }, nil
} }
// NewTaskOpts allows the caller to set options on a new task
type NewTaskOpts func(context.Context, *Client, *TaskInfo) error type NewTaskOpts func(context.Context, *Client, *TaskInfo) error
// WithRootFS allows a task to be created without a snapshot being allocated to its container
func WithRootFS(mounts []mount.Mount) NewTaskOpts { func WithRootFS(mounts []mount.Mount) NewTaskOpts {
return func(ctx context.Context, c *Client, ti *TaskInfo) error { return func(ctx context.Context, c *Client, ti *TaskInfo) error {
ti.RootFS = mounts ti.RootFS = mounts

View File

@ -20,6 +20,9 @@ import (
"github.com/opencontainers/image-spec/specs-go/v1" "github.com/opencontainers/image-spec/specs-go/v1"
) )
// WithCheckpoint allows a container to be created from the checkpointed information
// provided by the descriptor. The image, snapshot, and runtime specifications are
// restored on the container
func WithCheckpoint(desc v1.Descriptor, rootfsID string) NewContainerOpts { func WithCheckpoint(desc v1.Descriptor, rootfsID string) NewContainerOpts {
// set image and rw, and spec // set image and rw, and spec
return func(ctx context.Context, client *Client, c *containers.Container) error { return func(ctx context.Context, client *Client, c *containers.Container) error {
@ -82,6 +85,9 @@ func WithCheckpoint(desc v1.Descriptor, rootfsID string) NewContainerOpts {
} }
} }
// WithTaskCheckpoint allows a task to be created with live runtime and memory data from a
// previous checkpoint. Additional software such as CRIU may be required to
// restore a task from a checkpoint
func WithTaskCheckpoint(desc v1.Descriptor) NewTaskOpts { func WithTaskCheckpoint(desc v1.Descriptor) NewTaskOpts {
return func(ctx context.Context, c *Client, info *TaskInfo) error { return func(ctx context.Context, c *Client, info *TaskInfo) error {
id := desc.Digest id := desc.Digest

View File

@ -12,10 +12,13 @@ import (
"github.com/pkg/errors" "github.com/pkg/errors"
) )
// Image describes an image used by containers
type Image interface { type Image interface {
// Name of the image
Name() string Name() string
// Target descriptor for the image content
Target() ocispec.Descriptor Target() ocispec.Descriptor
// Unpack unpacks the image's content into a snapshot
Unpack(context.Context, string) error Unpack(context.Context, string) error
} }

28
io.go
View File

@ -8,15 +8,21 @@ import (
"sync" "sync"
) )
// IO holds the io information for a task or process
type IO struct { type IO struct {
// Terminal is true if one has been allocated
Terminal bool Terminal bool
Stdin string // Stdin path
Stdout string Stdin string
Stderr string // Stdout path
Stdout string
// Stderr path
Stderr string
closer *wgCloser closer *wgCloser
} }
// Cancel aborts all current io operations
func (i *IO) Cancel() { func (i *IO) Cancel() {
if i.closer == nil { if i.closer == nil {
return return
@ -24,6 +30,7 @@ func (i *IO) Cancel() {
i.closer.Cancel() i.closer.Cancel()
} }
// Wait blocks until all io copy operations have completed
func (i *IO) Wait() { func (i *IO) Wait() {
if i.closer == nil { if i.closer == nil {
return return
@ -31,6 +38,7 @@ func (i *IO) Wait() {
i.closer.Wait() i.closer.Wait()
} }
// Close cleans up all open io resources
func (i *IO) Close() error { func (i *IO) Close() error {
if i.closer == nil { if i.closer == nil {
return nil return nil
@ -38,14 +46,18 @@ func (i *IO) Close() error {
return i.closer.Close() return i.closer.Close()
} }
// IOCreation creates new IO sets for a task
type IOCreation func(id string) (*IO, error) type IOCreation func(id string) (*IO, error)
// IOAttach allows callers to reattach to running tasks
type IOAttach func(*FIFOSet) (*IO, error) type IOAttach func(*FIFOSet) (*IO, error)
// NewIO returns an IOCreation that will provide IO sets without a terminal
func NewIO(stdin io.Reader, stdout, stderr io.Writer) IOCreation { func NewIO(stdin io.Reader, stdout, stderr io.Writer) IOCreation {
return NewIOWithTerminal(stdin, stdout, stderr, false) return NewIOWithTerminal(stdin, stdout, stderr, false)
} }
// NewIOWithTerminal creates a new io set with the provied io.Reader/Writers for use with a terminal
func NewIOWithTerminal(stdin io.Reader, stdout, stderr io.Writer, terminal bool) IOCreation { func NewIOWithTerminal(stdin io.Reader, stdout, stderr io.Writer, terminal bool) IOCreation {
return func(id string) (*IO, error) { return func(id string) (*IO, error) {
paths, err := NewFifos(id) paths, err := NewFifos(id)
@ -72,6 +84,7 @@ func NewIOWithTerminal(stdin io.Reader, stdout, stderr io.Writer, terminal bool)
} }
} }
// WithAttach attaches the existing io for a task to the provided io.Reader/Writers
func WithAttach(stdin io.Reader, stdout, stderr io.Writer) IOAttach { func WithAttach(stdin io.Reader, stdout, stderr io.Writer) IOAttach {
return func(paths *FIFOSet) (*IO, error) { return func(paths *FIFOSet) (*IO, error) {
if paths == nil { if paths == nil {
@ -97,7 +110,7 @@ func WithAttach(stdin io.Reader, stdout, stderr io.Writer) IOAttach {
} }
} }
// Stdio returns an IO implementation to be used for a task // Stdio returns an IO set to be used for a task
// that outputs the container's IO as the current processes Stdio // that outputs the container's IO as the current processes Stdio
func Stdio(id string) (*IO, error) { func Stdio(id string) (*IO, error) {
return NewIO(os.Stdin, os.Stdout, os.Stderr)(id) return NewIO(os.Stdin, os.Stdout, os.Stderr)(id)
@ -108,11 +121,14 @@ func StdioTerminal(id string) (*IO, error) {
return NewIOWithTerminal(os.Stdin, os.Stdout, os.Stderr, true)(id) return NewIOWithTerminal(os.Stdin, os.Stdout, os.Stderr, true)(id)
} }
// FIFOSet is a set of fifos for use with tasks
type FIFOSet struct { type FIFOSet struct {
// Dir is the directory holding the task fifos // Dir is the directory holding the task fifos
Dir string Dir string
// In, Out, and Err fifo paths
In, Out, Err string In, Out, Err string
Terminal bool // Terminal returns true if a terminal is being used for the task
Terminal bool
} }
type ioSet struct { type ioSet struct {

View File

@ -13,15 +13,25 @@ import (
specs "github.com/opencontainers/runtime-spec/specs-go" specs "github.com/opencontainers/runtime-spec/specs-go"
) )
// Process represents a system process
type Process interface { type Process interface {
// Pid is the system specific process id
Pid() uint32 Pid() uint32
// Start starts the process executing the user's defined binary
Start(context.Context) error Start(context.Context) error
// Delete removes the process and any resources allocated returning the exit status
Delete(context.Context) (uint32, error) Delete(context.Context) (uint32, error)
// Kill sends the provided signal to the process
Kill(context.Context, syscall.Signal) error Kill(context.Context, syscall.Signal) error
// Wait blocks until the process has exited returning the exit status
Wait(context.Context) (uint32, error) Wait(context.Context) (uint32, error)
// CloseIO allows various pipes to be closed on the process
CloseIO(context.Context, ...IOCloserOpts) error CloseIO(context.Context, ...IOCloserOpts) error
// Resize changes the width and heigh of the process's terminal
Resize(ctx context.Context, w, h uint32) error Resize(ctx context.Context, w, h uint32) error
// IO returns the io set for the process
IO() *IO IO() *IO
// Status returns the executing status of the process
Status(context.Context) (Status, error) Status(context.Context) (Status, error)
} }

View File

@ -162,12 +162,15 @@ func createDefaultSpec() (*specs.Spec, error) {
return s, nil return s, nil
} }
// WithTTY sets the information on the spec as well as the environment variables for
// using a TTY
func WithTTY(s *specs.Spec) error { func WithTTY(s *specs.Spec) error {
s.Process.Terminal = true s.Process.Terminal = true
s.Process.Env = append(s.Process.Env, "TERM=xterm") s.Process.Env = append(s.Process.Env, "TERM=xterm")
return nil return nil
} }
// WithHostNamespace allows a task to run inside the host's linux namespace
func WithHostNamespace(ns specs.LinuxNamespaceType) SpecOpts { func WithHostNamespace(ns specs.LinuxNamespaceType) SpecOpts {
return func(s *specs.Spec) error { return func(s *specs.Spec) error {
for i, n := range s.Linux.Namespaces { for i, n := range s.Linux.Namespaces {
@ -198,6 +201,7 @@ func WithLinuxNamespace(ns specs.LinuxNamespace) SpecOpts {
} }
} }
// WithImageConfig configures the spec to from the configuration of an Image
func WithImageConfig(ctx context.Context, i Image) SpecOpts { func WithImageConfig(ctx context.Context, i Image) SpecOpts {
return func(s *specs.Spec) error { return func(s *specs.Spec) error {
var ( var (
@ -304,7 +308,8 @@ func WithNoNewPrivileges(s *specs.Spec) error {
return nil return nil
} }
func WithHostHosts(s *specs.Spec) error { // WithHostHostsFile bind-mounts the host's /etc/hosts into the container as readonly
func WithHostHostsFile(s *specs.Spec) error {
s.Mounts = append(s.Mounts, specs.Mount{ s.Mounts = append(s.Mounts, specs.Mount{
Destination: "/etc/hosts", Destination: "/etc/hosts",
Type: "bind", Type: "bind",
@ -314,6 +319,7 @@ func WithHostHosts(s *specs.Spec) error {
return nil return nil
} }
// WithHostResoveconf bind-mounts the host's /etc/resolv.conf into the container as readonly
func WithHostResoveconf(s *specs.Spec) error { func WithHostResoveconf(s *specs.Spec) error {
s.Mounts = append(s.Mounts, specs.Mount{ s.Mounts = append(s.Mounts, specs.Mount{
Destination: "/etc/resolv.conf", Destination: "/etc/resolv.conf",
@ -324,6 +330,7 @@ func WithHostResoveconf(s *specs.Spec) error {
return nil return nil
} }
// WithHostLocaltime bind-mounts the host's /etc/localtime into the container as readonly
func WithHostLocaltime(s *specs.Spec) error { func WithHostLocaltime(s *specs.Spec) error {
s.Mounts = append(s.Mounts, specs.Mount{ s.Mounts = append(s.Mounts, specs.Mount{
Destination: "/etc/localtime", Destination: "/etc/localtime",

60
task.go
View File

@ -27,61 +27,89 @@ import (
"github.com/pkg/errors" "github.com/pkg/errors"
) )
// UnknownExitStatus is returned when containerd is unable to
// determine the exit status of a process. This can happen if the process never starts
// or if an error was encountered when obtaining the exit status, it is set to 255.
const UnknownExitStatus = 255 const UnknownExitStatus = 255
// Status returns process status and exit information
type Status struct { type Status struct {
Status ProcessStatus // Status of the process
Status ProcessStatus
// ExitStatus returned by the process
ExitStatus uint32 ExitStatus uint32
} }
type ProcessStatus string type ProcessStatus string
const ( const (
// Running indicates the process is currently executing
Running ProcessStatus = "running" Running ProcessStatus = "running"
// Created indicates the process has been created within containerd but the
// user's defined process has not started
Created ProcessStatus = "created" Created ProcessStatus = "created"
// Stopped indicates that the process has ran and exited
Stopped ProcessStatus = "stopped" Stopped ProcessStatus = "stopped"
Paused ProcessStatus = "paused" // Paused indicates that the process is currently paused
Paused ProcessStatus = "paused"
// Pausing indicates that the process is currently switching from a
// running state into a paused state
Pausing ProcessStatus = "pausing" Pausing ProcessStatus = "pausing"
) )
// IOCloseInfo allows specific io pipes to be closed on a process
type IOCloseInfo struct { type IOCloseInfo struct {
Stdin bool Stdin bool
} }
// IOCloserOpts allows the caller to set specific pipes as closed on a process
type IOCloserOpts func(*IOCloseInfo) type IOCloserOpts func(*IOCloseInfo)
// WithStdinCloser closes the stdin of a process
func WithStdinCloser(r *IOCloseInfo) { func WithStdinCloser(r *IOCloseInfo) {
r.Stdin = true r.Stdin = true
} }
// CheckpointTaskInfo allows specific checkpoint information to be set for the task
type CheckpointTaskInfo struct { type CheckpointTaskInfo struct {
// ParentCheckpoint is the digest of a parent checkpoint
ParentCheckpoint digest.Digest ParentCheckpoint digest.Digest
Options interface{} // Options hold runtime specific settings for checkpointing a task
Options interface{}
} }
// CheckpointTaskOpts allows the caller to set checkpoint options
type CheckpointTaskOpts func(*CheckpointTaskInfo) error type CheckpointTaskOpts func(*CheckpointTaskInfo) error
// TaskInfo sets options for task creation
type TaskInfo struct { type TaskInfo struct {
// Checkpoint is the Descriptor for an existing checkpoint that can be used
// to restore a task's runtime and memory state
Checkpoint *types.Descriptor Checkpoint *types.Descriptor
RootFS []mount.Mount // RootFS is a list of mounts to use as the task's root filesystem
Options interface{} RootFS []mount.Mount
// Options hold runtime specific settings for task creation
Options interface{}
} }
// Task is the executable object within containerd
type Task interface { type Task interface {
Pid() uint32 Process
Delete(context.Context) (uint32, error)
Kill(context.Context, syscall.Signal) error // Pause suspends the execution of the task
Pause(context.Context) error Pause(context.Context) error
// Resume the execution of the task
Resume(context.Context) error Resume(context.Context) error
Start(context.Context) error // Exec creates a new process inside the task
Status(context.Context) (Status, error)
Wait(context.Context) (uint32, error)
Exec(context.Context, string, *specs.Process, IOCreation) (Process, error) Exec(context.Context, string, *specs.Process, IOCreation) (Process, error)
// Pids returns a list of system specific process ids inside the task
Pids(context.Context) ([]uint32, error) Pids(context.Context) ([]uint32, error)
CloseIO(context.Context, ...IOCloserOpts) error // Checkpoint serializes the runtime and memory information of a task into an
Resize(ctx context.Context, w, h uint32) error // OCI Index that can be push and pulled from a remote resource.
IO() *IO //
// Additional software like CRIU maybe required to checkpoint and restore tasks
Checkpoint(context.Context, ...CheckpointTaskOpts) (v1.Descriptor, error) Checkpoint(context.Context, ...CheckpointTaskOpts) (v1.Descriptor, error)
// Update modifies executing tasks with updated settings
Update(context.Context, ...UpdateTaskOpts) error Update(context.Context, ...UpdateTaskOpts) error
} }
@ -335,10 +363,13 @@ func (t *task) Checkpoint(ctx context.Context, opts ...CheckpointTaskOpts) (d v1
return t.writeIndex(ctx, &index) return t.writeIndex(ctx, &index)
} }
// UpdateTaskInfo allows updated specific settings to be changed on a task
type UpdateTaskInfo struct { type UpdateTaskInfo struct {
// Resources updates a tasks resource constraints
Resources interface{} Resources interface{}
} }
// UpdateTaskOpts allows a caller to update task settings
type UpdateTaskOpts func(context.Context, *Client, *UpdateTaskInfo) error type UpdateTaskOpts func(context.Context, *Client, *UpdateTaskInfo) error
func (t *task) Update(ctx context.Context, opts ...UpdateTaskOpts) error { func (t *task) Update(ctx context.Context, opts ...UpdateTaskOpts) error {
@ -435,6 +466,7 @@ func writeContent(ctx context.Context, store content.Store, mediaType, ref strin
}, nil }, nil
} }
// WithExit causes the task to exit after a successful checkpoint
func WithExit(r *CheckpointTaskInfo) error { func WithExit(r *CheckpointTaskInfo) error {
r.Options = &runcopts.CheckpointOptions{ r.Options = &runcopts.CheckpointOptions{
Exit: true, Exit: true,