Port ctr to use client
Signed-off-by: Michael Crosby <crosbymichael@gmail.com>
This commit is contained in:
		
							
								
								
									
										22
									
								
								client.go
									
									
									
									
									
								
							
							
						
						
									
										22
									
								
								client.go
									
									
									
									
									
								
							@@ -17,6 +17,7 @@ import (
 | 
				
			|||||||
	imagesapi "github.com/containerd/containerd/api/services/images"
 | 
						imagesapi "github.com/containerd/containerd/api/services/images"
 | 
				
			||||||
	namespacesapi "github.com/containerd/containerd/api/services/namespaces"
 | 
						namespacesapi "github.com/containerd/containerd/api/services/namespaces"
 | 
				
			||||||
	snapshotapi "github.com/containerd/containerd/api/services/snapshot"
 | 
						snapshotapi "github.com/containerd/containerd/api/services/snapshot"
 | 
				
			||||||
 | 
						versionservice "github.com/containerd/containerd/api/services/version"
 | 
				
			||||||
	"github.com/containerd/containerd/content"
 | 
						"github.com/containerd/containerd/content"
 | 
				
			||||||
	"github.com/containerd/containerd/images"
 | 
						"github.com/containerd/containerd/images"
 | 
				
			||||||
	"github.com/containerd/containerd/remotes"
 | 
						"github.com/containerd/containerd/remotes"
 | 
				
			||||||
@@ -28,6 +29,7 @@ import (
 | 
				
			|||||||
	imagesservice "github.com/containerd/containerd/services/images"
 | 
						imagesservice "github.com/containerd/containerd/services/images"
 | 
				
			||||||
	snapshotservice "github.com/containerd/containerd/services/snapshot"
 | 
						snapshotservice "github.com/containerd/containerd/services/snapshot"
 | 
				
			||||||
	"github.com/containerd/containerd/snapshot"
 | 
						"github.com/containerd/containerd/snapshot"
 | 
				
			||||||
 | 
						pempty "github.com/golang/protobuf/ptypes/empty"
 | 
				
			||||||
	"github.com/opencontainers/image-spec/identity"
 | 
						"github.com/opencontainers/image-spec/identity"
 | 
				
			||||||
	"github.com/opencontainers/image-spec/specs-go/v1"
 | 
						"github.com/opencontainers/image-spec/specs-go/v1"
 | 
				
			||||||
	ocispec "github.com/opencontainers/image-spec/specs-go/v1"
 | 
						ocispec "github.com/opencontainers/image-spec/specs-go/v1"
 | 
				
			||||||
@@ -462,3 +464,23 @@ func (c *Client) DiffService() diff.DiffService {
 | 
				
			|||||||
func (c *Client) HealthService() grpc_health_v1.HealthClient {
 | 
					func (c *Client) HealthService() grpc_health_v1.HealthClient {
 | 
				
			||||||
	return grpc_health_v1.NewHealthClient(c.conn)
 | 
						return grpc_health_v1.NewHealthClient(c.conn)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (c *Client) VersionService() versionservice.VersionClient {
 | 
				
			||||||
 | 
						return versionservice.NewVersionClient(c.conn)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type Version struct {
 | 
				
			||||||
 | 
						Version  string
 | 
				
			||||||
 | 
						Revision string
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (c *Client) Version(ctx context.Context) (Version, error) {
 | 
				
			||||||
 | 
						response, err := c.VersionService().Version(ctx, &pempty.Empty{})
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return Version{}, err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return Version{
 | 
				
			||||||
 | 
							Version:  response.Version,
 | 
				
			||||||
 | 
							Revision: response.Revision,
 | 
				
			||||||
 | 
						}, nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,22 +1,9 @@
 | 
				
			|||||||
package main
 | 
					package main
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import (
 | 
					import (
 | 
				
			||||||
	"bytes"
 | 
					 | 
				
			||||||
	gocontext "context"
 | 
					 | 
				
			||||||
	"encoding/json"
 | 
					 | 
				
			||||||
	"fmt"
 | 
						"fmt"
 | 
				
			||||||
	"io"
 | 
					 | 
				
			||||||
	"runtime"
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	"github.com/Sirupsen/logrus"
 | 
						"github.com/containerd/containerd"
 | 
				
			||||||
	"github.com/containerd/containerd/api/services/execution"
 | 
					 | 
				
			||||||
	"github.com/containerd/containerd/api/types/descriptor"
 | 
					 | 
				
			||||||
	"github.com/containerd/containerd/archive"
 | 
					 | 
				
			||||||
	"github.com/containerd/containerd/content"
 | 
					 | 
				
			||||||
	"github.com/containerd/containerd/images"
 | 
					 | 
				
			||||||
	"github.com/containerd/containerd/rootfs"
 | 
					 | 
				
			||||||
	ocispec "github.com/opencontainers/image-spec/specs-go/v1"
 | 
					 | 
				
			||||||
	specs "github.com/opencontainers/runtime-spec/specs-go"
 | 
					 | 
				
			||||||
	"github.com/pkg/errors"
 | 
						"github.com/pkg/errors"
 | 
				
			||||||
	"github.com/urfave/cli"
 | 
						"github.com/urfave/cli"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
@@ -25,169 +12,42 @@ var checkpointCommand = cli.Command{
 | 
				
			|||||||
	Name:  "checkpoint",
 | 
						Name:  "checkpoint",
 | 
				
			||||||
	Usage: "checkpoint a container",
 | 
						Usage: "checkpoint a container",
 | 
				
			||||||
	Flags: []cli.Flag{
 | 
						Flags: []cli.Flag{
 | 
				
			||||||
		cli.StringFlag{
 | 
					 | 
				
			||||||
			Name:  "id",
 | 
					 | 
				
			||||||
			Usage: "id of the container",
 | 
					 | 
				
			||||||
		},
 | 
					 | 
				
			||||||
		cli.BoolFlag{
 | 
							cli.BoolFlag{
 | 
				
			||||||
			Name:  "exit",
 | 
								Name:  "exit",
 | 
				
			||||||
			Usage: "stop the container after the checkpoint",
 | 
								Usage: "stop the container after the checkpoint",
 | 
				
			||||||
		},
 | 
							},
 | 
				
			||||||
		cli.BoolFlag{
 | 
					 | 
				
			||||||
			Name:  "binds",
 | 
					 | 
				
			||||||
			Usage: "checkpoint bind mounts with the checkpoint",
 | 
					 | 
				
			||||||
		},
 | 
					 | 
				
			||||||
	},
 | 
						},
 | 
				
			||||||
	Action: func(context *cli.Context) error {
 | 
						Action: func(context *cli.Context) error {
 | 
				
			||||||
		var (
 | 
							var (
 | 
				
			||||||
			id          = context.String("id")
 | 
					 | 
				
			||||||
			ctx, cancel = appContext(context)
 | 
								ctx, cancel = appContext(context)
 | 
				
			||||||
 | 
								id          = context.Args().First()
 | 
				
			||||||
		)
 | 
							)
 | 
				
			||||||
		defer cancel()
 | 
							defer cancel()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if id == "" {
 | 
							if id == "" {
 | 
				
			||||||
			return errors.New("container id must be provided")
 | 
								return errors.New("container id must be provided")
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
							client, err := newClient(context)
 | 
				
			||||||
		tasks, err := getTasksService(context)
 | 
					 | 
				
			||||||
		if err != nil {
 | 
							if err != nil {
 | 
				
			||||||
			return err
 | 
								return err
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		content, err := getContentStore(context)
 | 
							container, err := client.LoadContainer(ctx, id)
 | 
				
			||||||
		if err != nil {
 | 
							if err != nil {
 | 
				
			||||||
			return err
 | 
								return err
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		imageStore, err := getImageStore(context)
 | 
							task, err := container.Task(ctx, nil)
 | 
				
			||||||
		if err != nil {
 | 
					 | 
				
			||||||
			return errors.Wrap(err, "failed resolving image store")
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		var spec specs.Spec
 | 
					 | 
				
			||||||
		info, err := tasks.Info(ctx, &execution.InfoRequest{
 | 
					 | 
				
			||||||
			ContainerID: id,
 | 
					 | 
				
			||||||
		})
 | 
					 | 
				
			||||||
		if err != nil {
 | 
							if err != nil {
 | 
				
			||||||
			return err
 | 
								return err
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		if err := json.Unmarshal(info.Task.Spec.Value, &spec); err != nil {
 | 
							var opts []containerd.CheckpointOpts
 | 
				
			||||||
			return err
 | 
							if context.Bool("exit") {
 | 
				
			||||||
 | 
								opts = append(opts, containerd.WithExit)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		stopped := context.Bool("exit")
 | 
							checkpoint, err := task.Checkpoint(ctx, opts...)
 | 
				
			||||||
		// if the container will still be running after the checkpoint make sure that
 | 
					 | 
				
			||||||
		// we pause the container and give us time to checkpoint the filesystem before
 | 
					 | 
				
			||||||
		// it resumes execution
 | 
					 | 
				
			||||||
		if !stopped {
 | 
					 | 
				
			||||||
			if _, err := tasks.Pause(ctx, &execution.PauseRequest{
 | 
					 | 
				
			||||||
				ContainerID: id,
 | 
					 | 
				
			||||||
			}); err != nil {
 | 
					 | 
				
			||||||
				return err
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
			defer func() {
 | 
					 | 
				
			||||||
				if _, err := tasks.Resume(ctx, &execution.ResumeRequest{
 | 
					 | 
				
			||||||
					ContainerID: id,
 | 
					 | 
				
			||||||
				}); err != nil {
 | 
					 | 
				
			||||||
					logrus.WithError(err).Error("ctr: unable to resume container")
 | 
					 | 
				
			||||||
				}
 | 
					 | 
				
			||||||
			}()
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		checkpoint, err := tasks.Checkpoint(ctx, &execution.CheckpointRequest{
 | 
					 | 
				
			||||||
			ContainerID: id,
 | 
					 | 
				
			||||||
			Exit:        context.Bool("exit"),
 | 
					 | 
				
			||||||
		})
 | 
					 | 
				
			||||||
		if err != nil {
 | 
							if err != nil {
 | 
				
			||||||
			return err
 | 
								return err
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		image, err := imageStore.Get(ctx, spec.Annotations["image"])
 | 
							fmt.Println(checkpoint.Digest.String())
 | 
				
			||||||
		if err != nil {
 | 
					 | 
				
			||||||
			return err
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		var additionalDescriptors []*descriptor.Descriptor
 | 
					 | 
				
			||||||
		if context.Bool("binds") {
 | 
					 | 
				
			||||||
			if additionalDescriptors, err = checkpointBinds(ctx, &spec, content); err != nil {
 | 
					 | 
				
			||||||
				return err
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		var index ocispec.Index
 | 
					 | 
				
			||||||
		for _, d := range append(checkpoint.Descriptors, additionalDescriptors...) {
 | 
					 | 
				
			||||||
			index.Manifests = append(index.Manifests, ocispec.Descriptor{
 | 
					 | 
				
			||||||
				MediaType: d.MediaType,
 | 
					 | 
				
			||||||
				Size:      d.Size_,
 | 
					 | 
				
			||||||
				Digest:    d.Digest,
 | 
					 | 
				
			||||||
				Platform: &ocispec.Platform{
 | 
					 | 
				
			||||||
					OS:           runtime.GOOS,
 | 
					 | 
				
			||||||
					Architecture: runtime.GOARCH,
 | 
					 | 
				
			||||||
				},
 | 
					 | 
				
			||||||
			})
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		// add image to the index
 | 
					 | 
				
			||||||
		index.Manifests = append(index.Manifests, image.Target)
 | 
					 | 
				
			||||||
		// checkpoint rw layer
 | 
					 | 
				
			||||||
		snapshotter, err := getSnapshotter(context)
 | 
					 | 
				
			||||||
		if err != nil {
 | 
					 | 
				
			||||||
			return err
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		differ, err := getDiffService(context)
 | 
					 | 
				
			||||||
		if err != nil {
 | 
					 | 
				
			||||||
			return err
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		rw, err := rootfs.Diff(ctx, id, fmt.Sprintf("checkpoint-rw-%s", id), snapshotter, differ)
 | 
					 | 
				
			||||||
		if err != nil {
 | 
					 | 
				
			||||||
			return err
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		rw.Platform = &ocispec.Platform{
 | 
					 | 
				
			||||||
			OS:           runtime.GOOS,
 | 
					 | 
				
			||||||
			Architecture: runtime.GOARCH,
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		index.Manifests = append(index.Manifests, rw)
 | 
					 | 
				
			||||||
		data, err := json.Marshal(index)
 | 
					 | 
				
			||||||
		if err != nil {
 | 
					 | 
				
			||||||
			return err
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		// write the index to the content store
 | 
					 | 
				
			||||||
		buf := bytes.NewReader(data)
 | 
					 | 
				
			||||||
		desc, err := writeContent(ctx, content, ocispec.MediaTypeImageIndex, id, buf)
 | 
					 | 
				
			||||||
		if err != nil {
 | 
					 | 
				
			||||||
			return err
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		fmt.Println(desc.Digest.String())
 | 
					 | 
				
			||||||
		return nil
 | 
							return nil
 | 
				
			||||||
	},
 | 
						},
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					 | 
				
			||||||
func checkpointBinds(ctx gocontext.Context, s *specs.Spec, store content.Store) ([]*descriptor.Descriptor, error) {
 | 
					 | 
				
			||||||
	var out []*descriptor.Descriptor
 | 
					 | 
				
			||||||
	for _, m := range s.Mounts {
 | 
					 | 
				
			||||||
		if m.Type != "bind" {
 | 
					 | 
				
			||||||
			continue
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		tar := archive.Diff(ctx, "", m.Source)
 | 
					 | 
				
			||||||
		d, err := writeContent(ctx, store, images.MediaTypeContainerd1Resource, m.Source, tar)
 | 
					 | 
				
			||||||
		if err := tar.Close(); err != nil {
 | 
					 | 
				
			||||||
			return nil, err
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		if err != nil {
 | 
					 | 
				
			||||||
			return nil, err
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		out = append(out, d)
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	return out, nil
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func writeContent(ctx gocontext.Context, store content.Store, mediaType, ref string, r io.Reader) (*descriptor.Descriptor, error) {
 | 
					 | 
				
			||||||
	writer, err := store.Writer(ctx, ref, 0, "")
 | 
					 | 
				
			||||||
	if err != nil {
 | 
					 | 
				
			||||||
		return nil, err
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	defer writer.Close()
 | 
					 | 
				
			||||||
	size, err := io.Copy(writer, r)
 | 
					 | 
				
			||||||
	if err != nil {
 | 
					 | 
				
			||||||
		return nil, err
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	if err := writer.Commit(0, ""); err != nil {
 | 
					 | 
				
			||||||
		return nil, err
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	return &descriptor.Descriptor{
 | 
					 | 
				
			||||||
		MediaType: mediaType,
 | 
					 | 
				
			||||||
		Digest:    writer.Digest(),
 | 
					 | 
				
			||||||
		Size_:     size,
 | 
					 | 
				
			||||||
	}, nil
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,14 +1,8 @@
 | 
				
			|||||||
package main
 | 
					package main
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import (
 | 
					import (
 | 
				
			||||||
	"runtime"
 | 
						"fmt"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	"google.golang.org/grpc"
 | 
					 | 
				
			||||||
	"google.golang.org/grpc/codes"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	containersapi "github.com/containerd/containerd/api/services/containers"
 | 
					 | 
				
			||||||
	"github.com/containerd/containerd/api/services/execution"
 | 
					 | 
				
			||||||
	"github.com/pkg/errors"
 | 
					 | 
				
			||||||
	"github.com/urfave/cli"
 | 
						"github.com/urfave/cli"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -19,49 +13,17 @@ var deleteCommand = cli.Command{
 | 
				
			|||||||
	Action: func(context *cli.Context) error {
 | 
						Action: func(context *cli.Context) error {
 | 
				
			||||||
		ctx, cancel := appContext(context)
 | 
							ctx, cancel := appContext(context)
 | 
				
			||||||
		defer cancel()
 | 
							defer cancel()
 | 
				
			||||||
 | 
							client, err := newClient(context)
 | 
				
			||||||
		containers, err := getContainersService(context)
 | 
					 | 
				
			||||||
		if err != nil {
 | 
							if err != nil {
 | 
				
			||||||
			return err
 | 
								return err
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		tasks, err := getTasksService(context)
 | 
							container, err := client.LoadContainer(ctx, context.Args().First())
 | 
				
			||||||
		if err != nil {
 | 
							if err != nil {
 | 
				
			||||||
			return err
 | 
								return err
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
							if _, err := container.Task(ctx, nil); err == nil {
 | 
				
			||||||
		snapshotter, err := getSnapshotter(context)
 | 
								return fmt.Errorf("cannot delete a container with a running task")
 | 
				
			||||||
		if err != nil {
 | 
					 | 
				
			||||||
			return err
 | 
					 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		id := context.Args().First()
 | 
							return container.Delete(ctx)
 | 
				
			||||||
		if id == "" {
 | 
					 | 
				
			||||||
			return errors.New("container id must be provided")
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		_, err = containers.Delete(ctx, &containersapi.DeleteContainerRequest{
 | 
					 | 
				
			||||||
			ID: id,
 | 
					 | 
				
			||||||
		})
 | 
					 | 
				
			||||||
		if err != nil {
 | 
					 | 
				
			||||||
			return errors.Wrap(err, "failed to delete container")
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		_, err = tasks.Delete(ctx, &execution.DeleteRequest{
 | 
					 | 
				
			||||||
			ContainerID: id,
 | 
					 | 
				
			||||||
		})
 | 
					 | 
				
			||||||
		if err != nil {
 | 
					 | 
				
			||||||
			// Ignore error if task has already been removed, task is
 | 
					 | 
				
			||||||
			// removed by default after run
 | 
					 | 
				
			||||||
			if grpc.Code(errors.Cause(err)) != codes.NotFound {
 | 
					 | 
				
			||||||
				return errors.Wrap(err, "failed to task container")
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		if runtime.GOOS != "windows" {
 | 
					 | 
				
			||||||
			if err := snapshotter.Remove(ctx, id); err != nil {
 | 
					 | 
				
			||||||
				return errors.Wrapf(err, "failed to remove snapshot %q", id)
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		return nil
 | 
					 | 
				
			||||||
	},
 | 
						},
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,48 +0,0 @@
 | 
				
			|||||||
package main
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
import (
 | 
					 | 
				
			||||||
	"fmt"
 | 
					 | 
				
			||||||
	"os"
 | 
					 | 
				
			||||||
	"text/tabwriter"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	"github.com/containerd/containerd/api/services/execution"
 | 
					 | 
				
			||||||
	"github.com/urfave/cli"
 | 
					 | 
				
			||||||
)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
var eventsCommand = cli.Command{
 | 
					 | 
				
			||||||
	Name:  "events",
 | 
					 | 
				
			||||||
	Usage: "display containerd events",
 | 
					 | 
				
			||||||
	Action: func(context *cli.Context) error {
 | 
					 | 
				
			||||||
		ctx, cancel := appContext(context)
 | 
					 | 
				
			||||||
		defer cancel()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		tasks, err := getTasksService(context)
 | 
					 | 
				
			||||||
		if err != nil {
 | 
					 | 
				
			||||||
			return err
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		events, err := tasks.Events(ctx, &execution.EventsRequest{})
 | 
					 | 
				
			||||||
		if err != nil {
 | 
					 | 
				
			||||||
			return err
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		w := tabwriter.NewWriter(os.Stdout, 10, 1, 3, ' ', 0)
 | 
					 | 
				
			||||||
		fmt.Fprintln(w, "TYPE\tID\tPID\tEXIT_STATUS")
 | 
					 | 
				
			||||||
		for {
 | 
					 | 
				
			||||||
			e, err := events.Recv()
 | 
					 | 
				
			||||||
			if err != nil {
 | 
					 | 
				
			||||||
				return err
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
			if _, err := fmt.Fprintf(w,
 | 
					 | 
				
			||||||
				"%s\t%s\t%d\t%d\n",
 | 
					 | 
				
			||||||
				e.Type.String(),
 | 
					 | 
				
			||||||
				e.ID,
 | 
					 | 
				
			||||||
				e.Pid,
 | 
					 | 
				
			||||||
				e.ExitStatus,
 | 
					 | 
				
			||||||
			); err != nil {
 | 
					 | 
				
			||||||
				return err
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
			if err := w.Flush(); err != nil {
 | 
					 | 
				
			||||||
				return err
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	},
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
@@ -1,12 +1,11 @@
 | 
				
			|||||||
package main
 | 
					package main
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import (
 | 
					import (
 | 
				
			||||||
	"os"
 | 
						"errors"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	"github.com/Sirupsen/logrus"
 | 
						"github.com/Sirupsen/logrus"
 | 
				
			||||||
	"github.com/containerd/console"
 | 
						"github.com/containerd/console"
 | 
				
			||||||
	"github.com/containerd/containerd/api/services/execution"
 | 
						"github.com/containerd/containerd"
 | 
				
			||||||
	"github.com/pkg/errors"
 | 
					 | 
				
			||||||
	"github.com/urfave/cli"
 | 
						"github.com/urfave/cli"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -14,10 +13,6 @@ var execCommand = cli.Command{
 | 
				
			|||||||
	Name:  "exec",
 | 
						Name:  "exec",
 | 
				
			||||||
	Usage: "execute additional processes in an existing container",
 | 
						Usage: "execute additional processes in an existing container",
 | 
				
			||||||
	Flags: []cli.Flag{
 | 
						Flags: []cli.Flag{
 | 
				
			||||||
		cli.StringFlag{
 | 
					 | 
				
			||||||
			Name:  "id",
 | 
					 | 
				
			||||||
			Usage: "id of the container",
 | 
					 | 
				
			||||||
		},
 | 
					 | 
				
			||||||
		cli.StringFlag{
 | 
							cli.StringFlag{
 | 
				
			||||||
			Name:  "cwd",
 | 
								Name:  "cwd",
 | 
				
			||||||
			Usage: "working directory of the new process",
 | 
								Usage: "working directory of the new process",
 | 
				
			||||||
@@ -29,61 +24,75 @@ var execCommand = cli.Command{
 | 
				
			|||||||
	},
 | 
						},
 | 
				
			||||||
	Action: func(context *cli.Context) error {
 | 
						Action: func(context *cli.Context) error {
 | 
				
			||||||
		var (
 | 
							var (
 | 
				
			||||||
			id          = context.String("id")
 | 
					 | 
				
			||||||
			ctx, cancel = appContext(context)
 | 
								ctx, cancel = appContext(context)
 | 
				
			||||||
 | 
								id          = context.Args().First()
 | 
				
			||||||
 | 
								args        = context.Args().Tail()
 | 
				
			||||||
 | 
								tty         = context.Bool("tty")
 | 
				
			||||||
		)
 | 
							)
 | 
				
			||||||
		defer cancel()
 | 
							defer cancel()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if id == "" {
 | 
							if id == "" {
 | 
				
			||||||
			return errors.New("container id must be provided")
 | 
								return errors.New("container id must be provided")
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
							client, err := newClient(context)
 | 
				
			||||||
 | 
							if err != nil {
 | 
				
			||||||
 | 
								return err
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							container, err := client.LoadContainer(ctx, id)
 | 
				
			||||||
 | 
							if err != nil {
 | 
				
			||||||
 | 
								return err
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							spec, err := container.Spec()
 | 
				
			||||||
 | 
							if err != nil {
 | 
				
			||||||
 | 
								return err
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							task, err := container.Task(ctx, nil)
 | 
				
			||||||
 | 
							if err != nil {
 | 
				
			||||||
 | 
								return err
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		tasks, err := getTasksService(context)
 | 
							pspec := &spec.Process
 | 
				
			||||||
		if err != nil {
 | 
							pspec.Terminal = tty
 | 
				
			||||||
			return err
 | 
							pspec.Args = args
 | 
				
			||||||
		}
 | 
					
 | 
				
			||||||
		events, err := tasks.Events(ctx, &execution.EventsRequest{})
 | 
							io := containerd.Stdio
 | 
				
			||||||
		if err != nil {
 | 
							if tty {
 | 
				
			||||||
			return err
 | 
								io = containerd.StdioTerminal
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		tmpDir, err := getTempDir(id)
 | 
							process, err := task.Exec(ctx, pspec, io)
 | 
				
			||||||
		if err != nil {
 | 
					 | 
				
			||||||
			return err
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		defer os.RemoveAll(tmpDir)
 | 
					 | 
				
			||||||
		request, err := newExecRequest(context, tmpDir, id)
 | 
					 | 
				
			||||||
		if err != nil {
 | 
							if err != nil {
 | 
				
			||||||
			return err
 | 
								return err
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
							defer process.Delete()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							statusC := make(chan uint32, 1)
 | 
				
			||||||
 | 
							go func() {
 | 
				
			||||||
 | 
								status, err := process.Wait(ctx)
 | 
				
			||||||
 | 
								if err != nil {
 | 
				
			||||||
 | 
									logrus.WithError(err).Error("wait process")
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								statusC <- status
 | 
				
			||||||
 | 
							}()
 | 
				
			||||||
		var con console.Console
 | 
							var con console.Console
 | 
				
			||||||
		if request.Terminal {
 | 
							if tty {
 | 
				
			||||||
			con = console.Current()
 | 
								con = console.Current()
 | 
				
			||||||
			defer con.Reset()
 | 
								defer con.Reset()
 | 
				
			||||||
			if err := con.SetRaw(); err != nil {
 | 
								if err := con.SetRaw(); err != nil {
 | 
				
			||||||
				return err
 | 
									return err
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		fwg, err := prepareStdio(request.Stdin, request.Stdout, request.Stderr, request.Terminal)
 | 
							if err := process.Start(ctx); err != nil {
 | 
				
			||||||
		if err != nil {
 | 
					 | 
				
			||||||
			return err
 | 
								return err
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		response, err := tasks.Exec(ctx, request)
 | 
							if tty {
 | 
				
			||||||
		if err != nil {
 | 
								if err := handleConsoleResize(ctx, process, con); err != nil {
 | 
				
			||||||
			return err
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		if request.Terminal {
 | 
					 | 
				
			||||||
			if err := handleConsoleResize(ctx, tasks, id, response.Pid, con); err != nil {
 | 
					 | 
				
			||||||
				logrus.WithError(err).Error("console resize")
 | 
									logrus.WithError(err).Error("console resize")
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
 | 
							} else {
 | 
				
			||||||
 | 
								sigc := forwardAllSignals(ctx, process)
 | 
				
			||||||
 | 
								defer stopCatch(sigc)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
							status := <-statusC
 | 
				
			||||||
		// Ensure we read all io only if container started successfully.
 | 
					 | 
				
			||||||
		defer fwg.Wait()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		status, err := waitContainer(events, id, response.Pid)
 | 
					 | 
				
			||||||
		if err != nil {
 | 
					 | 
				
			||||||
			return err
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		if status != 0 {
 | 
							if status != 0 {
 | 
				
			||||||
			return cli.NewExitError("", int(status))
 | 
								return cli.NewExitError("", int(status))
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,69 +0,0 @@
 | 
				
			|||||||
// +build !windows
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
package main
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
import (
 | 
					 | 
				
			||||||
	"encoding/json"
 | 
					 | 
				
			||||||
	"path/filepath"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	"github.com/containerd/containerd/api/services/execution"
 | 
					 | 
				
			||||||
	protobuf "github.com/gogo/protobuf/types"
 | 
					 | 
				
			||||||
	specs "github.com/opencontainers/runtime-spec/specs-go"
 | 
					 | 
				
			||||||
	"github.com/urfave/cli"
 | 
					 | 
				
			||||||
)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func createProcessSpec(args []string, cwd string, tty bool) specs.Process {
 | 
					 | 
				
			||||||
	env := []string{
 | 
					 | 
				
			||||||
		"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin",
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	if tty {
 | 
					 | 
				
			||||||
		env = append(env, "TERM=xterm")
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	if cwd == "" {
 | 
					 | 
				
			||||||
		cwd = "/"
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	return specs.Process{
 | 
					 | 
				
			||||||
		Args:            args,
 | 
					 | 
				
			||||||
		Env:             env,
 | 
					 | 
				
			||||||
		Terminal:        tty,
 | 
					 | 
				
			||||||
		Cwd:             cwd,
 | 
					 | 
				
			||||||
		NoNewPrivileges: true,
 | 
					 | 
				
			||||||
		User: specs.User{
 | 
					 | 
				
			||||||
			UID: 0,
 | 
					 | 
				
			||||||
			GID: 0,
 | 
					 | 
				
			||||||
		},
 | 
					 | 
				
			||||||
		Capabilities: &specs.LinuxCapabilities{
 | 
					 | 
				
			||||||
			Bounding:    capabilities,
 | 
					 | 
				
			||||||
			Permitted:   capabilities,
 | 
					 | 
				
			||||||
			Inheritable: capabilities,
 | 
					 | 
				
			||||||
			Effective:   capabilities,
 | 
					 | 
				
			||||||
			Ambient:     capabilities,
 | 
					 | 
				
			||||||
		},
 | 
					 | 
				
			||||||
		Rlimits: []specs.LinuxRlimit{
 | 
					 | 
				
			||||||
			{
 | 
					 | 
				
			||||||
				Type: "RLIMIT_NOFILE",
 | 
					 | 
				
			||||||
				Hard: uint64(1024),
 | 
					 | 
				
			||||||
				Soft: uint64(1024),
 | 
					 | 
				
			||||||
			},
 | 
					 | 
				
			||||||
		},
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func newExecRequest(context *cli.Context, tmpDir, id string) (*execution.ExecRequest, error) {
 | 
					 | 
				
			||||||
	process := createProcessSpec(context.Args(), context.String("cwd"), context.Bool("tty"))
 | 
					 | 
				
			||||||
	data, err := json.Marshal(process)
 | 
					 | 
				
			||||||
	if err != nil {
 | 
					 | 
				
			||||||
		return nil, err
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	return &execution.ExecRequest{
 | 
					 | 
				
			||||||
		ContainerID: id,
 | 
					 | 
				
			||||||
		Spec: &protobuf.Any{
 | 
					 | 
				
			||||||
			TypeUrl: specs.Version,
 | 
					 | 
				
			||||||
			Value:   data,
 | 
					 | 
				
			||||||
		},
 | 
					 | 
				
			||||||
		Terminal: context.Bool("tty"),
 | 
					 | 
				
			||||||
		Stdin:    filepath.Join(tmpDir, "stdin"),
 | 
					 | 
				
			||||||
		Stdout:   filepath.Join(tmpDir, "stdout"),
 | 
					 | 
				
			||||||
		Stderr:   filepath.Join(tmpDir, "stderr"),
 | 
					 | 
				
			||||||
	}, nil
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
@@ -1,40 +0,0 @@
 | 
				
			|||||||
package main
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
import (
 | 
					 | 
				
			||||||
	"encoding/json"
 | 
					 | 
				
			||||||
	"fmt"
 | 
					 | 
				
			||||||
	"time"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	"github.com/containerd/containerd/api/services/execution"
 | 
					 | 
				
			||||||
	protobuf "github.com/gogo/protobuf/types"
 | 
					 | 
				
			||||||
	specs "github.com/opencontainers/runtime-spec/specs-go"
 | 
					 | 
				
			||||||
	"github.com/urfave/cli"
 | 
					 | 
				
			||||||
)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func newExecRequest(context *cli.Context, tmpDir, id string) (*execution.ExecRequest, error) {
 | 
					 | 
				
			||||||
	process := specs.Process{
 | 
					 | 
				
			||||||
		Args:     context.Args(),
 | 
					 | 
				
			||||||
		Terminal: context.Bool("tty"),
 | 
					 | 
				
			||||||
		Cwd:      context.String("cwd"),
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	data, err := json.Marshal(process)
 | 
					 | 
				
			||||||
	if err != nil {
 | 
					 | 
				
			||||||
		return nil, err
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	now := time.Now().UnixNano()
 | 
					 | 
				
			||||||
	request := &execution.ExecRequest{
 | 
					 | 
				
			||||||
		ContainerID: id,
 | 
					 | 
				
			||||||
		Spec: &protobuf.Any{
 | 
					 | 
				
			||||||
			TypeUrl: specs.Version,
 | 
					 | 
				
			||||||
			Value:   data,
 | 
					 | 
				
			||||||
		},
 | 
					 | 
				
			||||||
		Terminal: context.Bool("tty"),
 | 
					 | 
				
			||||||
		Stdin:    fmt.Sprintf(`%s\ctr-%s-stdin-%d`, pipeRoot, id, now),
 | 
					 | 
				
			||||||
		Stdout:   fmt.Sprintf(`%s\ctr-%s-stdout-%d`, pipeRoot, id, now),
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	if !request.Terminal {
 | 
					 | 
				
			||||||
		request.Stderr = fmt.Sprintf(`%s\ctr-%s-stderr-%d`, pipeRoot, id, now)
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return request, nil
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
@@ -3,11 +3,8 @@ package main
 | 
				
			|||||||
import (
 | 
					import (
 | 
				
			||||||
	"encoding/json"
 | 
						"encoding/json"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	gocontext "context"
 | 
					 | 
				
			||||||
	"fmt"
 | 
						"fmt"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	containersapi "github.com/containerd/containerd/api/services/containers"
 | 
					 | 
				
			||||||
	"github.com/containerd/containerd/api/services/execution"
 | 
					 | 
				
			||||||
	"github.com/pkg/errors"
 | 
						"github.com/pkg/errors"
 | 
				
			||||||
	"github.com/urfave/cli"
 | 
						"github.com/urfave/cli"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
@@ -15,55 +12,29 @@ import (
 | 
				
			|||||||
var infoCommand = cli.Command{
 | 
					var infoCommand = cli.Command{
 | 
				
			||||||
	Name:  "info",
 | 
						Name:  "info",
 | 
				
			||||||
	Usage: "get info about a container",
 | 
						Usage: "get info about a container",
 | 
				
			||||||
	Flags: []cli.Flag{
 | 
					 | 
				
			||||||
		cli.StringFlag{
 | 
					 | 
				
			||||||
			Name:  "id",
 | 
					 | 
				
			||||||
			Usage: "id of the container",
 | 
					 | 
				
			||||||
		},
 | 
					 | 
				
			||||||
	},
 | 
					 | 
				
			||||||
	Action: func(context *cli.Context) error {
 | 
						Action: func(context *cli.Context) error {
 | 
				
			||||||
		var (
 | 
							var (
 | 
				
			||||||
			id          = context.String("id")
 | 
					 | 
				
			||||||
			ctx, cancel = appContext(context)
 | 
								ctx, cancel = appContext(context)
 | 
				
			||||||
 | 
								id          = context.Args().First()
 | 
				
			||||||
		)
 | 
							)
 | 
				
			||||||
		defer cancel()
 | 
							defer cancel()
 | 
				
			||||||
 | 
					 | 
				
			||||||
		if id == "" {
 | 
							if id == "" {
 | 
				
			||||||
			return errors.New("container id must be provided")
 | 
								return errors.New("container id must be provided")
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
							client, err := newClient(context)
 | 
				
			||||||
		containers, err := getContainersService(context)
 | 
					 | 
				
			||||||
		if err != nil {
 | 
					 | 
				
			||||||
			return err
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		tasks, err := getTasksService(context)
 | 
					 | 
				
			||||||
		if err != nil {
 | 
							if err != nil {
 | 
				
			||||||
			return err
 | 
								return err
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		containerResponse, err := containers.Get(ctx, &containersapi.GetContainerRequest{ID: id})
 | 
							container, err := client.LoadContainer(ctx, id)
 | 
				
			||||||
		if err != nil {
 | 
							if err != nil {
 | 
				
			||||||
			return err
 | 
								return err
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
							cjson, err := json.MarshalIndent(container, "", "    ")
 | 
				
			||||||
		// TODO(stevvooe): Just dumping the container and the task, for now. We
 | 
					 | 
				
			||||||
		// should split this into two separate commands.
 | 
					 | 
				
			||||||
		cjson, err := json.MarshalIndent(containerResponse, "", "    ")
 | 
					 | 
				
			||||||
		if err != nil {
 | 
							if err != nil {
 | 
				
			||||||
			return err
 | 
								return err
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					 | 
				
			||||||
		fmt.Println(string(cjson))
 | 
							fmt.Println(string(cjson))
 | 
				
			||||||
 | 
					 | 
				
			||||||
		response, err := tasks.Info(gocontext.Background(), &execution.InfoRequest{ContainerID: id})
 | 
					 | 
				
			||||||
		if err != nil {
 | 
					 | 
				
			||||||
			return err
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		json, err := json.MarshalIndent(response, "", "    ")
 | 
					 | 
				
			||||||
		if err != nil {
 | 
					 | 
				
			||||||
			return err
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		fmt.Println(string(json))
 | 
					 | 
				
			||||||
		return nil
 | 
							return nil
 | 
				
			||||||
	},
 | 
						},
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,7 +1,6 @@
 | 
				
			|||||||
package main
 | 
					package main
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import (
 | 
					import (
 | 
				
			||||||
	"github.com/containerd/containerd/api/services/execution"
 | 
					 | 
				
			||||||
	"github.com/pkg/errors"
 | 
						"github.com/pkg/errors"
 | 
				
			||||||
	"github.com/urfave/cli"
 | 
						"github.com/urfave/cli"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
@@ -11,8 +10,9 @@ var killCommand = cli.Command{
 | 
				
			|||||||
	Usage: "signal a container (default: SIGTERM)",
 | 
						Usage: "signal a container (default: SIGTERM)",
 | 
				
			||||||
	Flags: []cli.Flag{
 | 
						Flags: []cli.Flag{
 | 
				
			||||||
		cli.StringFlag{
 | 
							cli.StringFlag{
 | 
				
			||||||
			Name:  "id",
 | 
								Name:  "signal, s",
 | 
				
			||||||
			Usage: "id of the container",
 | 
								Value: "SIGTERM",
 | 
				
			||||||
 | 
								Usage: "signal to send to the container",
 | 
				
			||||||
		},
 | 
							},
 | 
				
			||||||
		cli.IntFlag{
 | 
							cli.IntFlag{
 | 
				
			||||||
			Name:  "pid",
 | 
								Name:  "pid",
 | 
				
			||||||
@@ -26,53 +26,36 @@ var killCommand = cli.Command{
 | 
				
			|||||||
	},
 | 
						},
 | 
				
			||||||
	Action: func(context *cli.Context) error {
 | 
						Action: func(context *cli.Context) error {
 | 
				
			||||||
		var (
 | 
							var (
 | 
				
			||||||
			id          = context.String("id")
 | 
								id          = context.Args().First()
 | 
				
			||||||
			ctx, cancel = appContext(context)
 | 
								ctx, cancel = appContext(context)
 | 
				
			||||||
		)
 | 
							)
 | 
				
			||||||
		defer cancel()
 | 
							defer cancel()
 | 
				
			||||||
 | 
					 | 
				
			||||||
		if id == "" {
 | 
							if id == "" {
 | 
				
			||||||
			return errors.New("container id must be provided")
 | 
								return errors.New("container id must be provided")
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
							signal, err := parseSignal(context.String("signal"))
 | 
				
			||||||
		sigstr := context.Args().First()
 | 
					 | 
				
			||||||
		if sigstr == "" {
 | 
					 | 
				
			||||||
			sigstr = "SIGTERM"
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		signal, err := parseSignal(sigstr)
 | 
					 | 
				
			||||||
		if err != nil {
 | 
							if err != nil {
 | 
				
			||||||
			return err
 | 
								return err
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
							var (
 | 
				
			||||||
		pid := context.Int("pid")
 | 
								pid = context.Int("pid")
 | 
				
			||||||
		all := context.Bool("all")
 | 
								all = context.Bool("all")
 | 
				
			||||||
 | 
							)
 | 
				
			||||||
		if pid > 0 && all {
 | 
							if pid > 0 && all {
 | 
				
			||||||
			return errors.New("enter a pid or all; not both")
 | 
								return errors.New("enter a pid or all; not both")
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
							client, err := newClient(context)
 | 
				
			||||||
		killRequest := &execution.KillRequest{
 | 
					 | 
				
			||||||
			ContainerID: id,
 | 
					 | 
				
			||||||
			Signal:      uint32(signal),
 | 
					 | 
				
			||||||
			PidOrAll: &execution.KillRequest_Pid{
 | 
					 | 
				
			||||||
				Pid: uint32(pid),
 | 
					 | 
				
			||||||
			},
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		if all {
 | 
					 | 
				
			||||||
			killRequest.PidOrAll = &execution.KillRequest_All{
 | 
					 | 
				
			||||||
				All: true,
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		tasks, err := getTasksService(context)
 | 
					 | 
				
			||||||
		if err != nil {
 | 
							if err != nil {
 | 
				
			||||||
			return err
 | 
								return err
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		_, err = tasks.Kill(ctx, killRequest)
 | 
							container, err := client.LoadContainer(ctx, id)
 | 
				
			||||||
		if err != nil {
 | 
							if err != nil {
 | 
				
			||||||
			return err
 | 
								return err
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		return nil
 | 
							task, err := container.Task(ctx, nil)
 | 
				
			||||||
 | 
							if err != nil {
 | 
				
			||||||
 | 
								return err
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							return task.Kill(ctx, signal)
 | 
				
			||||||
	},
 | 
						},
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,14 +1,11 @@
 | 
				
			|||||||
package main
 | 
					package main
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import (
 | 
					import (
 | 
				
			||||||
	gocontext "context"
 | 
					 | 
				
			||||||
	"fmt"
 | 
						"fmt"
 | 
				
			||||||
	"os"
 | 
						"os"
 | 
				
			||||||
	"text/tabwriter"
 | 
						"text/tabwriter"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	containersapi "github.com/containerd/containerd/api/services/containers"
 | 
						"github.com/containerd/containerd"
 | 
				
			||||||
	"github.com/containerd/containerd/api/services/execution"
 | 
					 | 
				
			||||||
	tasktypes "github.com/containerd/containerd/api/types/task"
 | 
					 | 
				
			||||||
	"github.com/urfave/cli"
 | 
						"github.com/urfave/cli"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -33,69 +30,59 @@ var listCommand = cli.Command{
 | 
				
			|||||||
		)
 | 
							)
 | 
				
			||||||
		defer cancel()
 | 
							defer cancel()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		tasks, err := getTasksService(context)
 | 
							client, err := newClient(context)
 | 
				
			||||||
		if err != nil {
 | 
							if err != nil {
 | 
				
			||||||
			return err
 | 
								return err
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
							containers, err := client.Containers(ctx)
 | 
				
			||||||
		containers, err := getContainersService(context)
 | 
					 | 
				
			||||||
		if err != nil {
 | 
							if err != nil {
 | 
				
			||||||
			return err
 | 
								return err
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					 | 
				
			||||||
		response, err := containers.List(gocontext.Background(), &containersapi.ListContainersRequest{})
 | 
					 | 
				
			||||||
		if err != nil {
 | 
					 | 
				
			||||||
			return err
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		if quiet {
 | 
							if quiet {
 | 
				
			||||||
			for _, c := range response.Containers {
 | 
								for _, c := range containers {
 | 
				
			||||||
				fmt.Println(c.ID)
 | 
									fmt.Println(c.ID())
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
		} else {
 | 
								return nil
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			tasksResponse, err := tasks.List(ctx, &execution.ListRequest{})
 | 
							w := tabwriter.NewWriter(os.Stdout, 10, 1, 3, ' ', 0)
 | 
				
			||||||
 | 
							fmt.Fprintln(w, "ID\tIMAGE\tPID\tSTATUS")
 | 
				
			||||||
 | 
							for _, c := range containers {
 | 
				
			||||||
 | 
								image, err := c.Image(ctx)
 | 
				
			||||||
			if err != nil {
 | 
								if err != nil {
 | 
				
			||||||
				return err
 | 
									return err
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
 | 
								var (
 | 
				
			||||||
			// Join with tasks to get status.
 | 
									status string
 | 
				
			||||||
			tasksByContainerID := map[string]*tasktypes.Task{}
 | 
									pid    uint32
 | 
				
			||||||
			for _, task := range tasksResponse.Tasks {
 | 
								)
 | 
				
			||||||
				task.Descriptor()
 | 
								task, err := c.Task(ctx, nil)
 | 
				
			||||||
				tasksByContainerID[task.ContainerID] = task
 | 
								if err == nil {
 | 
				
			||||||
 | 
									s, err := task.Status(ctx)
 | 
				
			||||||
 | 
									if err != nil {
 | 
				
			||||||
 | 
										return err
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
									status = string(s)
 | 
				
			||||||
 | 
									pid = task.Pid()
 | 
				
			||||||
 | 
								} else {
 | 
				
			||||||
 | 
									if err != containerd.ErrNoRunningTask {
 | 
				
			||||||
 | 
										return err
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
									status = string(containerd.Stopped)
 | 
				
			||||||
 | 
									pid = 0
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
 | 
								if _, err := fmt.Fprintf(w, "%s\t%s\t%d\t%s\n",
 | 
				
			||||||
			w := tabwriter.NewWriter(os.Stdout, 10, 1, 3, ' ', 0)
 | 
									c.ID(),
 | 
				
			||||||
			fmt.Fprintln(w, "ID\tIMAGE\tPID\tSTATUS")
 | 
									image.Name(),
 | 
				
			||||||
			for _, c := range response.Containers {
 | 
									pid,
 | 
				
			||||||
				var (
 | 
									status,
 | 
				
			||||||
					status string
 | 
								); err != nil {
 | 
				
			||||||
					pid    uint32
 | 
									return err
 | 
				
			||||||
				)
 | 
								}
 | 
				
			||||||
				task, ok := tasksByContainerID[c.ID]
 | 
								if err := w.Flush(); err != nil {
 | 
				
			||||||
				if ok {
 | 
									return err
 | 
				
			||||||
					status = task.Status.String()
 | 
					 | 
				
			||||||
					pid = task.Pid
 | 
					 | 
				
			||||||
				} else {
 | 
					 | 
				
			||||||
					status = "STOPPED" // TODO(stevvooe): Is this assumption correct?
 | 
					 | 
				
			||||||
					pid = 0
 | 
					 | 
				
			||||||
				}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
				if _, err := fmt.Fprintf(w, "%s\t%s\t%d\t%s\n",
 | 
					 | 
				
			||||||
					c.ID,
 | 
					 | 
				
			||||||
					c.Image,
 | 
					 | 
				
			||||||
					pid,
 | 
					 | 
				
			||||||
					status,
 | 
					 | 
				
			||||||
				); err != nil {
 | 
					 | 
				
			||||||
					return err
 | 
					 | 
				
			||||||
				}
 | 
					 | 
				
			||||||
				if err := w.Flush(); err != nil {
 | 
					 | 
				
			||||||
					return err
 | 
					 | 
				
			||||||
				}
 | 
					 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					 | 
				
			||||||
		return nil
 | 
							return nil
 | 
				
			||||||
	},
 | 
						},
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -9,9 +9,7 @@ import (
 | 
				
			|||||||
	"github.com/urfave/cli"
 | 
						"github.com/urfave/cli"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
var (
 | 
					var extraCmds = []cli.Command{}
 | 
				
			||||||
	extraCmds = []cli.Command{}
 | 
					 | 
				
			||||||
)
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
func init() {
 | 
					func init() {
 | 
				
			||||||
	cli.VersionPrinter = func(c *cli.Context) {
 | 
						cli.VersionPrinter = func(c *cli.Context) {
 | 
				
			||||||
@@ -30,7 +28,7 @@ func main() {
 | 
				
			|||||||
/ /__/ /_/ /
 | 
					/ /__/ /_/ /
 | 
				
			||||||
\___/\__/_/
 | 
					\___/\__/_/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
containerd client
 | 
					containerd CLI
 | 
				
			||||||
`
 | 
					`
 | 
				
			||||||
	app.Flags = []cli.Flag{
 | 
						app.Flags = []cli.Flag{
 | 
				
			||||||
		cli.BoolFlag{
 | 
							cli.BoolFlag{
 | 
				
			||||||
@@ -53,10 +51,9 @@ containerd client
 | 
				
			|||||||
			EnvVar: "CONTAINERD_NAMESPACE",
 | 
								EnvVar: "CONTAINERD_NAMESPACE",
 | 
				
			||||||
		},
 | 
							},
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	app.Commands = []cli.Command{
 | 
						app.Commands = append([]cli.Command{
 | 
				
			||||||
		checkpointCommand,
 | 
							checkpointCommand,
 | 
				
			||||||
		runCommand,
 | 
							runCommand,
 | 
				
			||||||
		eventsCommand,
 | 
					 | 
				
			||||||
		deleteCommand,
 | 
							deleteCommand,
 | 
				
			||||||
		namespacesCommand,
 | 
							namespacesCommand,
 | 
				
			||||||
		listCommand,
 | 
							listCommand,
 | 
				
			||||||
@@ -69,8 +66,7 @@ containerd client
 | 
				
			|||||||
		snapshotCommand,
 | 
							snapshotCommand,
 | 
				
			||||||
		versionCommand,
 | 
							versionCommand,
 | 
				
			||||||
		psCommand,
 | 
							psCommand,
 | 
				
			||||||
	}
 | 
						}, extraCmds...)
 | 
				
			||||||
	app.Commands = append(app.Commands, extraCmds...)
 | 
					 | 
				
			||||||
	app.Before = func(context *cli.Context) error {
 | 
						app.Before = func(context *cli.Context) error {
 | 
				
			||||||
		if context.GlobalBool("debug") {
 | 
							if context.GlobalBool("debug") {
 | 
				
			||||||
			logrus.SetLevel(logrus.DebugLevel)
 | 
								logrus.SetLevel(logrus.DebugLevel)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,11 +1,6 @@
 | 
				
			|||||||
package main
 | 
					package main
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import (
 | 
					import "github.com/urfave/cli"
 | 
				
			||||||
	"errors"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	"github.com/containerd/containerd/api/services/execution"
 | 
					 | 
				
			||||||
	"github.com/urfave/cli"
 | 
					 | 
				
			||||||
)
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
var pauseCommand = cli.Command{
 | 
					var pauseCommand = cli.Command{
 | 
				
			||||||
	Name:      "pause",
 | 
						Name:      "pause",
 | 
				
			||||||
@@ -15,17 +10,18 @@ var pauseCommand = cli.Command{
 | 
				
			|||||||
		ctx, cancel := appContext(context)
 | 
							ctx, cancel := appContext(context)
 | 
				
			||||||
		defer cancel()
 | 
							defer cancel()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		tasks, err := getTasksService(context)
 | 
							client, err := newClient(context)
 | 
				
			||||||
		if err != nil {
 | 
							if err != nil {
 | 
				
			||||||
			return err
 | 
								return err
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		id := context.Args().First()
 | 
							container, err := client.LoadContainer(ctx, context.Args().First())
 | 
				
			||||||
		if id == "" {
 | 
							if err != nil {
 | 
				
			||||||
			return errors.New("container id must be provided")
 | 
								return err
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		_, err = tasks.Pause(ctx, &execution.PauseRequest{
 | 
							task, err := container.Task(ctx, nil)
 | 
				
			||||||
			ContainerID: id,
 | 
							if err != nil {
 | 
				
			||||||
		})
 | 
								return err
 | 
				
			||||||
		return err
 | 
							}
 | 
				
			||||||
 | 
							return task.Pause(ctx)
 | 
				
			||||||
	},
 | 
						},
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -5,7 +5,6 @@ import (
 | 
				
			|||||||
	"os"
 | 
						"os"
 | 
				
			||||||
	"text/tabwriter"
 | 
						"text/tabwriter"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	"github.com/containerd/containerd/api/services/execution"
 | 
					 | 
				
			||||||
	"github.com/pkg/errors"
 | 
						"github.com/pkg/errors"
 | 
				
			||||||
	"github.com/urfave/cli"
 | 
						"github.com/urfave/cli"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
@@ -13,15 +12,9 @@ import (
 | 
				
			|||||||
var psCommand = cli.Command{
 | 
					var psCommand = cli.Command{
 | 
				
			||||||
	Name:  "ps",
 | 
						Name:  "ps",
 | 
				
			||||||
	Usage: "list processes for container",
 | 
						Usage: "list processes for container",
 | 
				
			||||||
	Flags: []cli.Flag{
 | 
					 | 
				
			||||||
		cli.StringFlag{
 | 
					 | 
				
			||||||
			Name:  "id",
 | 
					 | 
				
			||||||
			Usage: "id of the container",
 | 
					 | 
				
			||||||
		},
 | 
					 | 
				
			||||||
	},
 | 
					 | 
				
			||||||
	Action: func(context *cli.Context) error {
 | 
						Action: func(context *cli.Context) error {
 | 
				
			||||||
		var (
 | 
							var (
 | 
				
			||||||
			id          = context.String("id")
 | 
								id          = context.Args().First()
 | 
				
			||||||
			ctx, cancel = appContext(context)
 | 
								ctx, cancel = appContext(context)
 | 
				
			||||||
		)
 | 
							)
 | 
				
			||||||
		defer cancel()
 | 
							defer cancel()
 | 
				
			||||||
@@ -29,34 +22,33 @@ var psCommand = cli.Command{
 | 
				
			|||||||
		if id == "" {
 | 
							if id == "" {
 | 
				
			||||||
			return errors.New("container id must be provided")
 | 
								return errors.New("container id must be provided")
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
							client, err := newClient(context)
 | 
				
			||||||
		pr := &execution.ProcessesRequest{
 | 
							if err != nil {
 | 
				
			||||||
			ContainerID: id,
 | 
								return err
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
							container, err := client.LoadContainer(ctx, id)
 | 
				
			||||||
		tasks, err := getTasksService(context)
 | 
					 | 
				
			||||||
		if err != nil {
 | 
							if err != nil {
 | 
				
			||||||
			return err
 | 
								return err
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		resp, err := tasks.Processes(ctx, pr)
 | 
							task, err := container.Task(ctx, nil)
 | 
				
			||||||
 | 
							if err != nil {
 | 
				
			||||||
 | 
								return err
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							processes, err := task.Processes(ctx)
 | 
				
			||||||
		if err != nil {
 | 
							if err != nil {
 | 
				
			||||||
			return err
 | 
								return err
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					 | 
				
			||||||
		w := tabwriter.NewWriter(os.Stdout, 10, 1, 3, ' ', 0)
 | 
							w := tabwriter.NewWriter(os.Stdout, 10, 1, 3, ' ', 0)
 | 
				
			||||||
		fmt.Fprintln(w, "PID")
 | 
							fmt.Fprintln(w, "PID")
 | 
				
			||||||
		for _, ps := range resp.Processes {
 | 
							for _, ps := range processes {
 | 
				
			||||||
			if _, err := fmt.Fprintf(w, "%d\n",
 | 
								if _, err := fmt.Fprintf(w, "%d\n", ps); err != nil {
 | 
				
			||||||
				ps.Pid,
 | 
					 | 
				
			||||||
			); err != nil {
 | 
					 | 
				
			||||||
				return err
 | 
									return err
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		if err := w.Flush(); err != nil {
 | 
							if err := w.Flush(); err != nil {
 | 
				
			||||||
			return err
 | 
								return err
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					 | 
				
			||||||
		return nil
 | 
							return nil
 | 
				
			||||||
	},
 | 
						},
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,11 +1,6 @@
 | 
				
			|||||||
package main
 | 
					package main
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import (
 | 
					import "github.com/urfave/cli"
 | 
				
			||||||
	"errors"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	"github.com/containerd/containerd/api/services/execution"
 | 
					 | 
				
			||||||
	"github.com/urfave/cli"
 | 
					 | 
				
			||||||
)
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
var resumeCommand = cli.Command{
 | 
					var resumeCommand = cli.Command{
 | 
				
			||||||
	Name:      "resume",
 | 
						Name:      "resume",
 | 
				
			||||||
@@ -15,17 +10,18 @@ var resumeCommand = cli.Command{
 | 
				
			|||||||
		ctx, cancel := appContext(context)
 | 
							ctx, cancel := appContext(context)
 | 
				
			||||||
		defer cancel()
 | 
							defer cancel()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		tasks, err := getTasksService(context)
 | 
							client, err := newClient(context)
 | 
				
			||||||
		if err != nil {
 | 
							if err != nil {
 | 
				
			||||||
			return err
 | 
								return err
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		id := context.Args().First()
 | 
							container, err := client.LoadContainer(ctx, context.Args().First())
 | 
				
			||||||
		if id == "" {
 | 
							if err != nil {
 | 
				
			||||||
			return errors.New("container id must be provided")
 | 
								return err
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		_, err = tasks.Resume(ctx, &execution.ResumeRequest{
 | 
							task, err := container.Task(ctx, nil)
 | 
				
			||||||
			ContainerID: id,
 | 
							if err != nil {
 | 
				
			||||||
		})
 | 
								return err
 | 
				
			||||||
		return err
 | 
							}
 | 
				
			||||||
 | 
							return task.Resume(ctx)
 | 
				
			||||||
	},
 | 
						},
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										294
									
								
								cmd/ctr/run.go
									
									
									
									
									
								
							
							
						
						
									
										294
									
								
								cmd/ctr/run.go
									
									
									
									
									
								
							@@ -1,52 +1,63 @@
 | 
				
			|||||||
package main
 | 
					package main
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import (
 | 
					import (
 | 
				
			||||||
	"encoding/json"
 | 
						gocontext "context"
 | 
				
			||||||
	"fmt"
 | 
						"syscall"
 | 
				
			||||||
	"io/ioutil"
 | 
					 | 
				
			||||||
	"os"
 | 
					 | 
				
			||||||
	"runtime"
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	"github.com/Sirupsen/logrus"
 | 
						"github.com/Sirupsen/logrus"
 | 
				
			||||||
	"github.com/containerd/console"
 | 
						"github.com/containerd/console"
 | 
				
			||||||
	containersapi "github.com/containerd/containerd/api/services/containers"
 | 
						"github.com/containerd/containerd"
 | 
				
			||||||
	"github.com/containerd/containerd/api/services/execution"
 | 
					 | 
				
			||||||
	"github.com/containerd/containerd/images"
 | 
					 | 
				
			||||||
	"github.com/containerd/containerd/mount"
 | 
					 | 
				
			||||||
	"github.com/containerd/containerd/snapshot"
 | 
					 | 
				
			||||||
	digest "github.com/opencontainers/go-digest"
 | 
						digest "github.com/opencontainers/go-digest"
 | 
				
			||||||
	"github.com/opencontainers/image-spec/identity"
 | 
						specs "github.com/opencontainers/runtime-spec/specs-go"
 | 
				
			||||||
	ocispec "github.com/opencontainers/image-spec/specs-go/v1"
 | 
					 | 
				
			||||||
	"github.com/pkg/errors"
 | 
						"github.com/pkg/errors"
 | 
				
			||||||
	"github.com/urfave/cli"
 | 
						"github.com/urfave/cli"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type resizer interface {
 | 
				
			||||||
 | 
						Resize(ctx gocontext.Context, w, h uint32) error
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type killer interface {
 | 
				
			||||||
 | 
						Kill(gocontext.Context, syscall.Signal) error
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func withEnv(context *cli.Context) containerd.SpecOpts {
 | 
				
			||||||
 | 
						return func(s *specs.Spec) error {
 | 
				
			||||||
 | 
							env := context.StringSlice("env")
 | 
				
			||||||
 | 
							if len(env) > 0 {
 | 
				
			||||||
 | 
								s.Process.Env = append(s.Process.Env, env...)
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							return nil
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func withMounts(context *cli.Context) containerd.SpecOpts {
 | 
				
			||||||
 | 
						return func(s *specs.Spec) error {
 | 
				
			||||||
 | 
							for _, mount := range context.StringSlice("mount") {
 | 
				
			||||||
 | 
								m, err := parseMountFlag(mount)
 | 
				
			||||||
 | 
								if err != nil {
 | 
				
			||||||
 | 
									return err
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								s.Mounts = append(s.Mounts, m)
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							return nil
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
var runCommand = cli.Command{
 | 
					var runCommand = cli.Command{
 | 
				
			||||||
	Name:      "run",
 | 
						Name:      "run",
 | 
				
			||||||
	Usage:     "run a container",
 | 
						Usage:     "run a container",
 | 
				
			||||||
	ArgsUsage: "IMAGE [COMMAND] [ARG...]",
 | 
						ArgsUsage: "IMAGE ID [COMMAND] [ARG...]",
 | 
				
			||||||
	Flags: []cli.Flag{
 | 
						Flags: []cli.Flag{
 | 
				
			||||||
		cli.StringFlag{
 | 
					 | 
				
			||||||
			Name:  "id",
 | 
					 | 
				
			||||||
			Usage: "id of the container",
 | 
					 | 
				
			||||||
		},
 | 
					 | 
				
			||||||
		cli.BoolFlag{
 | 
							cli.BoolFlag{
 | 
				
			||||||
			Name:  "tty,t",
 | 
								Name:  "tty,t",
 | 
				
			||||||
			Usage: "allocate a TTY for the container",
 | 
								Usage: "allocate a TTY for the container",
 | 
				
			||||||
		},
 | 
							},
 | 
				
			||||||
		cli.StringFlag{
 | 
					 | 
				
			||||||
			Name:  "rootfs",
 | 
					 | 
				
			||||||
			Usage: "path to rootfs",
 | 
					 | 
				
			||||||
		},
 | 
					 | 
				
			||||||
		cli.StringFlag{
 | 
							cli.StringFlag{
 | 
				
			||||||
			Name:  "runtime",
 | 
								Name:  "runtime",
 | 
				
			||||||
			Usage: "runtime name (linux, windows, vmware-linux)",
 | 
								Usage: "runtime name (linux, windows, vmware-linux)",
 | 
				
			||||||
			Value: "linux",
 | 
								Value: "linux",
 | 
				
			||||||
		},
 | 
							},
 | 
				
			||||||
		cli.StringFlag{
 | 
					 | 
				
			||||||
			Name:  "runtime-config",
 | 
					 | 
				
			||||||
			Usage: "set the OCI config file for the container",
 | 
					 | 
				
			||||||
		},
 | 
					 | 
				
			||||||
		cli.BoolFlag{
 | 
							cli.BoolFlag{
 | 
				
			||||||
			Name:  "readonly",
 | 
								Name:  "readonly",
 | 
				
			||||||
			Usage: "set the containers filesystem as readonly",
 | 
								Usage: "set the containers filesystem as readonly",
 | 
				
			||||||
@@ -74,237 +85,72 @@ var runCommand = cli.Command{
 | 
				
			|||||||
	},
 | 
						},
 | 
				
			||||||
	Action: func(context *cli.Context) error {
 | 
						Action: func(context *cli.Context) error {
 | 
				
			||||||
		var (
 | 
							var (
 | 
				
			||||||
			err         error
 | 
								err             error
 | 
				
			||||||
			mounts      []mount.Mount
 | 
								checkpointIndex digest.Digest
 | 
				
			||||||
			imageConfig ocispec.Image
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
			ctx, cancel = appContext(context)
 | 
								ctx, cancel = appContext(context)
 | 
				
			||||||
			id          = context.String("id")
 | 
								id          = context.Args().Get(1)
 | 
				
			||||||
 | 
								tty         = context.Bool("tty")
 | 
				
			||||||
		)
 | 
							)
 | 
				
			||||||
		defer cancel()
 | 
							defer cancel()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if id == "" {
 | 
							if id == "" {
 | 
				
			||||||
			return errors.New("container id must be provided")
 | 
								return errors.New("container id must be provided")
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		containers, err := getContainersService(context)
 | 
					 | 
				
			||||||
		if err != nil {
 | 
					 | 
				
			||||||
			return err
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		tasks, err := getTasksService(context)
 | 
					 | 
				
			||||||
		if err != nil {
 | 
					 | 
				
			||||||
			return err
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		tmpDir, err := getTempDir(id)
 | 
					 | 
				
			||||||
		if err != nil {
 | 
					 | 
				
			||||||
			return err
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		defer os.RemoveAll(tmpDir)
 | 
					 | 
				
			||||||
		events, err := tasks.Events(ctx, &execution.EventsRequest{})
 | 
					 | 
				
			||||||
		if err != nil {
 | 
					 | 
				
			||||||
			return err
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		content, err := getContentStore(context)
 | 
					 | 
				
			||||||
		if err != nil {
 | 
					 | 
				
			||||||
			return err
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		snapshotter, err := getSnapshotter(context)
 | 
					 | 
				
			||||||
		if err != nil {
 | 
					 | 
				
			||||||
			return err
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		imageStore, err := getImageStore(context)
 | 
					 | 
				
			||||||
		if err != nil {
 | 
					 | 
				
			||||||
			return errors.Wrap(err, "failed resolving image store")
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		differ, err := getDiffService(context)
 | 
					 | 
				
			||||||
		if err != nil {
 | 
					 | 
				
			||||||
			return err
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		var (
 | 
					 | 
				
			||||||
			checkpoint      *ocispec.Descriptor
 | 
					 | 
				
			||||||
			checkpointIndex digest.Digest
 | 
					 | 
				
			||||||
			ref             = context.Args().First()
 | 
					 | 
				
			||||||
		)
 | 
					 | 
				
			||||||
		if raw := context.String("checkpoint"); raw != "" {
 | 
							if raw := context.String("checkpoint"); raw != "" {
 | 
				
			||||||
			if checkpointIndex, err = digest.Parse(raw); err != nil {
 | 
								if checkpointIndex, err = digest.Parse(raw); err != nil {
 | 
				
			||||||
				return err
 | 
									return err
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		var spec []byte
 | 
							client, err := newClient(context)
 | 
				
			||||||
		if checkpointIndex != "" {
 | 
							if err != nil {
 | 
				
			||||||
			var index ocispec.Index
 | 
								return err
 | 
				
			||||||
			r, err := content.Reader(ctx, checkpointIndex)
 | 
							}
 | 
				
			||||||
 | 
							container, err := newContainer(ctx, client, context)
 | 
				
			||||||
 | 
							if err != nil {
 | 
				
			||||||
 | 
								return err
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							if context.Bool("rm") {
 | 
				
			||||||
 | 
								defer container.Delete(ctx)
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							task, err := newTask(ctx, container, checkpointIndex, tty)
 | 
				
			||||||
 | 
							if err != nil {
 | 
				
			||||||
 | 
								return err
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							defer task.Delete(ctx)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							statusC := make(chan uint32, 1)
 | 
				
			||||||
 | 
							go func() {
 | 
				
			||||||
 | 
								status, err := task.Wait(ctx)
 | 
				
			||||||
			if err != nil {
 | 
								if err != nil {
 | 
				
			||||||
				return err
 | 
									logrus.WithError(err).Error("wait process")
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
			err = json.NewDecoder(r).Decode(&index)
 | 
								statusC <- status
 | 
				
			||||||
			r.Close()
 | 
							}()
 | 
				
			||||||
			if err != nil {
 | 
					 | 
				
			||||||
				return err
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
			var rw ocispec.Descriptor
 | 
					 | 
				
			||||||
			for _, m := range index.Manifests {
 | 
					 | 
				
			||||||
				switch m.MediaType {
 | 
					 | 
				
			||||||
				case images.MediaTypeContainerd1Checkpoint:
 | 
					 | 
				
			||||||
					fkingo := m
 | 
					 | 
				
			||||||
					checkpoint = &fkingo
 | 
					 | 
				
			||||||
				case images.MediaTypeContainerd1CheckpointConfig:
 | 
					 | 
				
			||||||
					if r, err = content.Reader(ctx, m.Digest); err != nil {
 | 
					 | 
				
			||||||
						return err
 | 
					 | 
				
			||||||
					}
 | 
					 | 
				
			||||||
					spec, err = ioutil.ReadAll(r)
 | 
					 | 
				
			||||||
					r.Close()
 | 
					 | 
				
			||||||
					if err != nil {
 | 
					 | 
				
			||||||
						return err
 | 
					 | 
				
			||||||
					}
 | 
					 | 
				
			||||||
				case images.MediaTypeDockerSchema2Manifest:
 | 
					 | 
				
			||||||
					// make sure we have the original image that was used during checkpoint
 | 
					 | 
				
			||||||
					diffIDs, err := images.RootFS(ctx, content, m)
 | 
					 | 
				
			||||||
					if err != nil {
 | 
					 | 
				
			||||||
						return err
 | 
					 | 
				
			||||||
					}
 | 
					 | 
				
			||||||
					if _, err := snapshotter.Prepare(ctx, id, identity.ChainID(diffIDs).String()); err != nil {
 | 
					 | 
				
			||||||
						if !snapshot.IsExist(err) {
 | 
					 | 
				
			||||||
							return err
 | 
					 | 
				
			||||||
						}
 | 
					 | 
				
			||||||
					}
 | 
					 | 
				
			||||||
				case ocispec.MediaTypeImageLayer:
 | 
					 | 
				
			||||||
					rw = m
 | 
					 | 
				
			||||||
				}
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
			if mounts, err = snapshotter.Mounts(ctx, id); err != nil {
 | 
					 | 
				
			||||||
				return err
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
			if _, err := differ.Apply(ctx, rw, mounts); err != nil {
 | 
					 | 
				
			||||||
				return err
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
		} else {
 | 
					 | 
				
			||||||
			if runtime.GOOS != "windows" && context.String("rootfs") == "" {
 | 
					 | 
				
			||||||
				image, err := imageStore.Get(ctx, ref)
 | 
					 | 
				
			||||||
				if err != nil {
 | 
					 | 
				
			||||||
					return errors.Wrapf(err, "could not resolve %q", ref)
 | 
					 | 
				
			||||||
				}
 | 
					 | 
				
			||||||
				// let's close out our db and tx so we don't hold the lock whilst running.
 | 
					 | 
				
			||||||
				diffIDs, err := image.RootFS(ctx, content)
 | 
					 | 
				
			||||||
				if err != nil {
 | 
					 | 
				
			||||||
					return err
 | 
					 | 
				
			||||||
				}
 | 
					 | 
				
			||||||
				if context.Bool("readonly") {
 | 
					 | 
				
			||||||
					mounts, err = snapshotter.View(ctx, id, identity.ChainID(diffIDs).String())
 | 
					 | 
				
			||||||
				} else {
 | 
					 | 
				
			||||||
					mounts, err = snapshotter.Prepare(ctx, id, identity.ChainID(diffIDs).String())
 | 
					 | 
				
			||||||
				}
 | 
					 | 
				
			||||||
				defer func() {
 | 
					 | 
				
			||||||
					if err != nil || context.Bool("rm") {
 | 
					 | 
				
			||||||
						if err := snapshotter.Remove(ctx, id); err != nil {
 | 
					 | 
				
			||||||
							logrus.WithError(err).Errorf("failed to remove snapshot %q", id)
 | 
					 | 
				
			||||||
						}
 | 
					 | 
				
			||||||
					}
 | 
					 | 
				
			||||||
				}()
 | 
					 | 
				
			||||||
				if err != nil {
 | 
					 | 
				
			||||||
					if !snapshot.IsExist(err) {
 | 
					 | 
				
			||||||
						return err
 | 
					 | 
				
			||||||
					}
 | 
					 | 
				
			||||||
					mounts, err = snapshotter.Mounts(ctx, id)
 | 
					 | 
				
			||||||
					if err != nil {
 | 
					 | 
				
			||||||
						return err
 | 
					 | 
				
			||||||
					}
 | 
					 | 
				
			||||||
				}
 | 
					 | 
				
			||||||
				ic, err := image.Config(ctx, content)
 | 
					 | 
				
			||||||
				if err != nil {
 | 
					 | 
				
			||||||
					return err
 | 
					 | 
				
			||||||
				}
 | 
					 | 
				
			||||||
				switch ic.MediaType {
 | 
					 | 
				
			||||||
				case ocispec.MediaTypeImageConfig, images.MediaTypeDockerSchema2Config:
 | 
					 | 
				
			||||||
					r, err := content.Reader(ctx, ic.Digest)
 | 
					 | 
				
			||||||
					if err != nil {
 | 
					 | 
				
			||||||
						return err
 | 
					 | 
				
			||||||
					}
 | 
					 | 
				
			||||||
					if err := json.NewDecoder(r).Decode(&imageConfig); err != nil {
 | 
					 | 
				
			||||||
						r.Close()
 | 
					 | 
				
			||||||
						return err
 | 
					 | 
				
			||||||
					}
 | 
					 | 
				
			||||||
					r.Close()
 | 
					 | 
				
			||||||
				default:
 | 
					 | 
				
			||||||
					return fmt.Errorf("unknown image config media type %s", ic.MediaType)
 | 
					 | 
				
			||||||
				}
 | 
					 | 
				
			||||||
			} else {
 | 
					 | 
				
			||||||
				// TODO: get the image / rootfs through the API once windows has a snapshotter
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		if err != nil {
 | 
					 | 
				
			||||||
			return err
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		if len(spec) == 0 {
 | 
					 | 
				
			||||||
			if spec, err = newContainerSpec(context, &imageConfig.Config, ref); err != nil {
 | 
					 | 
				
			||||||
				return err
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		createContainer, err := newCreateContainerRequest(context, id, id, ref, spec)
 | 
					 | 
				
			||||||
		if err != nil {
 | 
					 | 
				
			||||||
			return err
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		_, err = containers.Create(ctx, createContainer)
 | 
					 | 
				
			||||||
		if err != nil {
 | 
					 | 
				
			||||||
			return err
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		create, err := newCreateTaskRequest(context, id, tmpDir, checkpoint, mounts)
 | 
					 | 
				
			||||||
		if err != nil {
 | 
					 | 
				
			||||||
			return err
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		var con console.Console
 | 
							var con console.Console
 | 
				
			||||||
		if create.Terminal {
 | 
							if tty {
 | 
				
			||||||
			con = console.Current()
 | 
								con = console.Current()
 | 
				
			||||||
			defer con.Reset()
 | 
								defer con.Reset()
 | 
				
			||||||
			if err := con.SetRaw(); err != nil {
 | 
								if err := con.SetRaw(); err != nil {
 | 
				
			||||||
				return err
 | 
									return err
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		fwg, err := prepareStdio(create.Stdin, create.Stdout, create.Stderr, create.Terminal)
 | 
							if err := task.Start(ctx); err != nil {
 | 
				
			||||||
		if err != nil {
 | 
					 | 
				
			||||||
			return err
 | 
								return err
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		response, err := tasks.Create(ctx, create)
 | 
							if tty {
 | 
				
			||||||
		if err != nil {
 | 
								if err := handleConsoleResize(ctx, task, con); err != nil {
 | 
				
			||||||
			return err
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		pid := response.Pid
 | 
					 | 
				
			||||||
		if create.Terminal {
 | 
					 | 
				
			||||||
			if err := handleConsoleResize(ctx, tasks, id, pid, con); err != nil {
 | 
					 | 
				
			||||||
				logrus.WithError(err).Error("console resize")
 | 
									logrus.WithError(err).Error("console resize")
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
		} else {
 | 
							} else {
 | 
				
			||||||
			sigc := forwardAllSignals(tasks, id)
 | 
								sigc := forwardAllSignals(ctx, task)
 | 
				
			||||||
			defer stopCatch(sigc)
 | 
								defer stopCatch(sigc)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		if checkpoint == nil {
 | 
					 | 
				
			||||||
			if _, err := tasks.Start(ctx, &execution.StartRequest{
 | 
					 | 
				
			||||||
				ContainerID: id,
 | 
					 | 
				
			||||||
			}); err != nil {
 | 
					 | 
				
			||||||
				return err
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		// Ensure we read all io only if container started successfully.
 | 
					 | 
				
			||||||
		defer fwg.Wait()
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
		status, err := waitContainer(events, id, pid)
 | 
							status := <-statusC
 | 
				
			||||||
		if err != nil {
 | 
							if _, err := task.Delete(ctx); err != nil {
 | 
				
			||||||
			return err
 | 
								return err
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		if _, err := tasks.Delete(ctx, &execution.DeleteRequest{
 | 
					 | 
				
			||||||
			ContainerID: response.ContainerID,
 | 
					 | 
				
			||||||
		}); err != nil {
 | 
					 | 
				
			||||||
			return err
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		if context.Bool("rm") {
 | 
					 | 
				
			||||||
			if _, err := containers.Delete(ctx, &containersapi.DeleteContainerRequest{ID: id}); err != nil {
 | 
					 | 
				
			||||||
				return err
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		if status != 0 {
 | 
							if status != 0 {
 | 
				
			||||||
			return cli.NewExitError("", int(status))
 | 
								return cli.NewExitError("", int(status))
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -3,343 +3,29 @@
 | 
				
			|||||||
package main
 | 
					package main
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import (
 | 
					import (
 | 
				
			||||||
	"context"
 | 
						gocontext "context"
 | 
				
			||||||
	"encoding/json"
 | 
					 | 
				
			||||||
	"fmt"
 | 
					 | 
				
			||||||
	"io/ioutil"
 | 
					 | 
				
			||||||
	"os"
 | 
						"os"
 | 
				
			||||||
	"os/signal"
 | 
						"os/signal"
 | 
				
			||||||
	"path/filepath"
 | 
					 | 
				
			||||||
	"runtime"
 | 
					 | 
				
			||||||
	"strconv"
 | 
					 | 
				
			||||||
	"strings"
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	"golang.org/x/sys/unix"
 | 
						"golang.org/x/sys/unix"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	"github.com/Sirupsen/logrus"
 | 
						"github.com/Sirupsen/logrus"
 | 
				
			||||||
	"github.com/containerd/console"
 | 
						"github.com/containerd/console"
 | 
				
			||||||
	containersapi "github.com/containerd/containerd/api/services/containers"
 | 
						"github.com/containerd/containerd"
 | 
				
			||||||
	"github.com/containerd/containerd/api/services/execution"
 | 
						digest "github.com/opencontainers/go-digest"
 | 
				
			||||||
	"github.com/containerd/containerd/api/types/descriptor"
 | 
						"github.com/opencontainers/image-spec/specs-go/v1"
 | 
				
			||||||
	"github.com/containerd/containerd/api/types/mount"
 | 
					 | 
				
			||||||
	mountt "github.com/containerd/containerd/mount"
 | 
					 | 
				
			||||||
	protobuf "github.com/gogo/protobuf/types"
 | 
					 | 
				
			||||||
	ocispec "github.com/opencontainers/image-spec/specs-go/v1"
 | 
					 | 
				
			||||||
	specs "github.com/opencontainers/runtime-spec/specs-go"
 | 
						specs "github.com/opencontainers/runtime-spec/specs-go"
 | 
				
			||||||
	"github.com/urfave/cli"
 | 
						"github.com/urfave/cli"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const (
 | 
					func handleConsoleResize(ctx gocontext.Context, task resizer, con console.Console) error {
 | 
				
			||||||
	rwm               = "rwm"
 | 
					 | 
				
			||||||
	defaultRootfsPath = "rootfs"
 | 
					 | 
				
			||||||
)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
var capabilities = []string{
 | 
					 | 
				
			||||||
	"CAP_CHOWN",
 | 
					 | 
				
			||||||
	"CAP_DAC_OVERRIDE",
 | 
					 | 
				
			||||||
	"CAP_FSETID",
 | 
					 | 
				
			||||||
	"CAP_FOWNER",
 | 
					 | 
				
			||||||
	"CAP_MKNOD",
 | 
					 | 
				
			||||||
	"CAP_NET_RAW",
 | 
					 | 
				
			||||||
	"CAP_SETGID",
 | 
					 | 
				
			||||||
	"CAP_SETUID",
 | 
					 | 
				
			||||||
	"CAP_SETFCAP",
 | 
					 | 
				
			||||||
	"CAP_SETPCAP",
 | 
					 | 
				
			||||||
	"CAP_NET_BIND_SERVICE",
 | 
					 | 
				
			||||||
	"CAP_SYS_CHROOT",
 | 
					 | 
				
			||||||
	"CAP_KILL",
 | 
					 | 
				
			||||||
	"CAP_AUDIT_WRITE",
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func spec(id string, config *ocispec.ImageConfig, context *cli.Context, rootfs string) (*specs.Spec, error) {
 | 
					 | 
				
			||||||
	defaultEnv := []string{
 | 
					 | 
				
			||||||
		"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin",
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	defaultEnv = append(defaultEnv, config.Env...)
 | 
					 | 
				
			||||||
	cmd := config.Cmd
 | 
					 | 
				
			||||||
	if v := context.Args().Tail(); len(v) > 0 {
 | 
					 | 
				
			||||||
		cmd = v
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	var (
 | 
					 | 
				
			||||||
		// TODO: support overriding entrypoint
 | 
					 | 
				
			||||||
		args     = append(config.Entrypoint, cmd...)
 | 
					 | 
				
			||||||
		tty      = context.Bool("tty")
 | 
					 | 
				
			||||||
		uid, gid uint32
 | 
					 | 
				
			||||||
	)
 | 
					 | 
				
			||||||
	if config.User != "" {
 | 
					 | 
				
			||||||
		parts := strings.Split(config.User, ":")
 | 
					 | 
				
			||||||
		switch len(parts) {
 | 
					 | 
				
			||||||
		case 1:
 | 
					 | 
				
			||||||
			v, err := strconv.ParseUint(parts[0], 0, 10)
 | 
					 | 
				
			||||||
			if err != nil {
 | 
					 | 
				
			||||||
				return nil, err
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
			uid, gid = uint32(v), uint32(v)
 | 
					 | 
				
			||||||
		case 2:
 | 
					 | 
				
			||||||
			v, err := strconv.ParseUint(parts[0], 0, 10)
 | 
					 | 
				
			||||||
			if err != nil {
 | 
					 | 
				
			||||||
				return nil, err
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
			uid = uint32(v)
 | 
					 | 
				
			||||||
			if v, err = strconv.ParseUint(parts[1], 0, 10); err != nil {
 | 
					 | 
				
			||||||
				return nil, err
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
			gid = uint32(v)
 | 
					 | 
				
			||||||
		default:
 | 
					 | 
				
			||||||
			return nil, fmt.Errorf("invalid USER value %s", config.User)
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	if tty {
 | 
					 | 
				
			||||||
		defaultEnv = append(defaultEnv, "TERM=xterm")
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	// additional environment vars
 | 
					 | 
				
			||||||
	env := replaceOrAppendEnvValues(defaultEnv, context.StringSlice("env"))
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	cwd := config.WorkingDir
 | 
					 | 
				
			||||||
	if cwd == "" {
 | 
					 | 
				
			||||||
		cwd = "/"
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	if rootfs == "" {
 | 
					 | 
				
			||||||
		rootfs = defaultRootfsPath
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	s := &specs.Spec{
 | 
					 | 
				
			||||||
		Version: specs.Version,
 | 
					 | 
				
			||||||
		Platform: specs.Platform{
 | 
					 | 
				
			||||||
			OS:   runtime.GOOS,
 | 
					 | 
				
			||||||
			Arch: runtime.GOARCH,
 | 
					 | 
				
			||||||
		},
 | 
					 | 
				
			||||||
		Root: specs.Root{
 | 
					 | 
				
			||||||
			Path:     rootfs,
 | 
					 | 
				
			||||||
			Readonly: context.Bool("readonly"),
 | 
					 | 
				
			||||||
		},
 | 
					 | 
				
			||||||
		Process: specs.Process{
 | 
					 | 
				
			||||||
			Args:            args,
 | 
					 | 
				
			||||||
			Env:             env,
 | 
					 | 
				
			||||||
			Terminal:        tty,
 | 
					 | 
				
			||||||
			Cwd:             cwd,
 | 
					 | 
				
			||||||
			NoNewPrivileges: true,
 | 
					 | 
				
			||||||
			User: specs.User{
 | 
					 | 
				
			||||||
				UID: uid,
 | 
					 | 
				
			||||||
				GID: gid,
 | 
					 | 
				
			||||||
			},
 | 
					 | 
				
			||||||
			Capabilities: &specs.LinuxCapabilities{
 | 
					 | 
				
			||||||
				Bounding:    capabilities,
 | 
					 | 
				
			||||||
				Permitted:   capabilities,
 | 
					 | 
				
			||||||
				Inheritable: capabilities,
 | 
					 | 
				
			||||||
				Effective:   capabilities,
 | 
					 | 
				
			||||||
				Ambient:     capabilities,
 | 
					 | 
				
			||||||
			},
 | 
					 | 
				
			||||||
			Rlimits: []specs.LinuxRlimit{
 | 
					 | 
				
			||||||
				{
 | 
					 | 
				
			||||||
					Type: "RLIMIT_NOFILE",
 | 
					 | 
				
			||||||
					Hard: uint64(1024),
 | 
					 | 
				
			||||||
					Soft: uint64(1024),
 | 
					 | 
				
			||||||
				},
 | 
					 | 
				
			||||||
			},
 | 
					 | 
				
			||||||
		},
 | 
					 | 
				
			||||||
		Mounts: []specs.Mount{
 | 
					 | 
				
			||||||
			{
 | 
					 | 
				
			||||||
				Destination: "/proc",
 | 
					 | 
				
			||||||
				Type:        "proc",
 | 
					 | 
				
			||||||
				Source:      "proc",
 | 
					 | 
				
			||||||
			},
 | 
					 | 
				
			||||||
			{
 | 
					 | 
				
			||||||
				Destination: "/dev",
 | 
					 | 
				
			||||||
				Type:        "tmpfs",
 | 
					 | 
				
			||||||
				Source:      "tmpfs",
 | 
					 | 
				
			||||||
				Options:     []string{"nosuid", "strictatime", "mode=755", "size=65536k"},
 | 
					 | 
				
			||||||
			},
 | 
					 | 
				
			||||||
			{
 | 
					 | 
				
			||||||
				Destination: "/dev/pts",
 | 
					 | 
				
			||||||
				Type:        "devpts",
 | 
					 | 
				
			||||||
				Source:      "devpts",
 | 
					 | 
				
			||||||
				Options:     []string{"nosuid", "noexec", "newinstance", "ptmxmode=0666", "mode=0620", "gid=5"},
 | 
					 | 
				
			||||||
			},
 | 
					 | 
				
			||||||
			{
 | 
					 | 
				
			||||||
				Destination: "/dev/shm",
 | 
					 | 
				
			||||||
				Type:        "tmpfs",
 | 
					 | 
				
			||||||
				Source:      "shm",
 | 
					 | 
				
			||||||
				Options:     []string{"nosuid", "noexec", "nodev", "mode=1777", "size=65536k"},
 | 
					 | 
				
			||||||
			},
 | 
					 | 
				
			||||||
			{
 | 
					 | 
				
			||||||
				Destination: "/dev/mqueue",
 | 
					 | 
				
			||||||
				Type:        "mqueue",
 | 
					 | 
				
			||||||
				Source:      "mqueue",
 | 
					 | 
				
			||||||
				Options:     []string{"nosuid", "noexec", "nodev"},
 | 
					 | 
				
			||||||
			},
 | 
					 | 
				
			||||||
			{
 | 
					 | 
				
			||||||
				Destination: "/sys",
 | 
					 | 
				
			||||||
				Type:        "sysfs",
 | 
					 | 
				
			||||||
				Source:      "sysfs",
 | 
					 | 
				
			||||||
				Options:     []string{"nosuid", "noexec", "nodev", "ro"},
 | 
					 | 
				
			||||||
			},
 | 
					 | 
				
			||||||
			{
 | 
					 | 
				
			||||||
				Destination: "/run",
 | 
					 | 
				
			||||||
				Type:        "tmpfs",
 | 
					 | 
				
			||||||
				Source:      "tmpfs",
 | 
					 | 
				
			||||||
				Options:     []string{"nosuid", "strictatime", "mode=755", "size=65536k"},
 | 
					 | 
				
			||||||
			},
 | 
					 | 
				
			||||||
			{
 | 
					 | 
				
			||||||
				Destination: "/etc/resolv.conf",
 | 
					 | 
				
			||||||
				Type:        "bind",
 | 
					 | 
				
			||||||
				Source:      "/etc/resolv.conf",
 | 
					 | 
				
			||||||
				Options:     []string{"rbind", "ro"},
 | 
					 | 
				
			||||||
			},
 | 
					 | 
				
			||||||
			{
 | 
					 | 
				
			||||||
				Destination: "/etc/hosts",
 | 
					 | 
				
			||||||
				Type:        "bind",
 | 
					 | 
				
			||||||
				Source:      "/etc/hosts",
 | 
					 | 
				
			||||||
				Options:     []string{"rbind", "ro"},
 | 
					 | 
				
			||||||
			},
 | 
					 | 
				
			||||||
			{
 | 
					 | 
				
			||||||
				Destination: "/etc/localtime",
 | 
					 | 
				
			||||||
				Type:        "bind",
 | 
					 | 
				
			||||||
				Source:      "/etc/localtime",
 | 
					 | 
				
			||||||
				Options:     []string{"rbind", "ro"},
 | 
					 | 
				
			||||||
			},
 | 
					 | 
				
			||||||
		},
 | 
					 | 
				
			||||||
		Hostname: id,
 | 
					 | 
				
			||||||
		Linux: &specs.Linux{
 | 
					 | 
				
			||||||
			Resources: &specs.LinuxResources{
 | 
					 | 
				
			||||||
				Devices: []specs.LinuxDeviceCgroup{
 | 
					 | 
				
			||||||
					{
 | 
					 | 
				
			||||||
						Allow:  false,
 | 
					 | 
				
			||||||
						Access: rwm,
 | 
					 | 
				
			||||||
					},
 | 
					 | 
				
			||||||
				},
 | 
					 | 
				
			||||||
			},
 | 
					 | 
				
			||||||
			Namespaces: []specs.LinuxNamespace{
 | 
					 | 
				
			||||||
				{
 | 
					 | 
				
			||||||
					Type: "pid",
 | 
					 | 
				
			||||||
				},
 | 
					 | 
				
			||||||
				{
 | 
					 | 
				
			||||||
					Type: "ipc",
 | 
					 | 
				
			||||||
				},
 | 
					 | 
				
			||||||
				{
 | 
					 | 
				
			||||||
					Type: "uts",
 | 
					 | 
				
			||||||
				},
 | 
					 | 
				
			||||||
				{
 | 
					 | 
				
			||||||
					Type: "mount",
 | 
					 | 
				
			||||||
				},
 | 
					 | 
				
			||||||
			},
 | 
					 | 
				
			||||||
		},
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	if !context.Bool("net-host") {
 | 
					 | 
				
			||||||
		s.Linux.Namespaces = append(s.Linux.Namespaces, specs.LinuxNamespace{
 | 
					 | 
				
			||||||
			Type: "network",
 | 
					 | 
				
			||||||
		})
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	for _, mount := range context.StringSlice("mount") {
 | 
					 | 
				
			||||||
		m, err := parseMountFlag(mount)
 | 
					 | 
				
			||||||
		if err != nil {
 | 
					 | 
				
			||||||
			return nil, err
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		s.Mounts = append(s.Mounts, m)
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	return s, nil
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func customSpec(configPath string, rootfs string) (*specs.Spec, error) {
 | 
					 | 
				
			||||||
	b, err := ioutil.ReadFile(configPath)
 | 
					 | 
				
			||||||
	if err != nil {
 | 
					 | 
				
			||||||
		return nil, err
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	var s specs.Spec
 | 
					 | 
				
			||||||
	if err := json.Unmarshal(b, &s); err != nil {
 | 
					 | 
				
			||||||
		return nil, err
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	if rootfs == "" {
 | 
					 | 
				
			||||||
		if s.Root.Path != defaultRootfsPath {
 | 
					 | 
				
			||||||
			logrus.Warnf("ignoring Root.Path %q, setting %q forcibly", s.Root.Path, defaultRootfsPath)
 | 
					 | 
				
			||||||
			s.Root.Path = defaultRootfsPath
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	} else {
 | 
					 | 
				
			||||||
		s.Root.Path = rootfs
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	return &s, nil
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func getConfig(context *cli.Context, imageConfig *ocispec.ImageConfig, rootfs string) (*specs.Spec, error) {
 | 
					 | 
				
			||||||
	config := context.String("runtime-config")
 | 
					 | 
				
			||||||
	if config == "" {
 | 
					 | 
				
			||||||
		return spec(context.String("id"), imageConfig, context, rootfs)
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return customSpec(config, rootfs)
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func newContainerSpec(context *cli.Context, config *ocispec.ImageConfig, imageRef string) ([]byte, error) {
 | 
					 | 
				
			||||||
	s, err := getConfig(context, config, context.String("rootfs"))
 | 
					 | 
				
			||||||
	if err != nil {
 | 
					 | 
				
			||||||
		return nil, err
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	if s.Annotations == nil {
 | 
					 | 
				
			||||||
		s.Annotations = make(map[string]string)
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	s.Annotations["image"] = imageRef
 | 
					 | 
				
			||||||
	return json.Marshal(s)
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func newCreateContainerRequest(context *cli.Context, id, snapshot, image string, spec []byte) (*containersapi.CreateContainerRequest, error) {
 | 
					 | 
				
			||||||
	create := &containersapi.CreateContainerRequest{
 | 
					 | 
				
			||||||
		Container: containersapi.Container{
 | 
					 | 
				
			||||||
			ID:    id,
 | 
					 | 
				
			||||||
			Image: image,
 | 
					 | 
				
			||||||
			Spec: &protobuf.Any{
 | 
					 | 
				
			||||||
				TypeUrl: specs.Version,
 | 
					 | 
				
			||||||
				Value:   spec,
 | 
					 | 
				
			||||||
			},
 | 
					 | 
				
			||||||
			Runtime: context.String("runtime"),
 | 
					 | 
				
			||||||
			RootFS:  snapshot,
 | 
					 | 
				
			||||||
		},
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return create, nil
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func newCreateTaskRequest(context *cli.Context, id, tmpDir string, checkpoint *ocispec.Descriptor, mounts []mountt.Mount) (*execution.CreateRequest, error) {
 | 
					 | 
				
			||||||
	create := &execution.CreateRequest{
 | 
					 | 
				
			||||||
		ContainerID: id,
 | 
					 | 
				
			||||||
		Terminal:    context.Bool("tty"),
 | 
					 | 
				
			||||||
		Stdin:       filepath.Join(tmpDir, "stdin"),
 | 
					 | 
				
			||||||
		Stdout:      filepath.Join(tmpDir, "stdout"),
 | 
					 | 
				
			||||||
		Stderr:      filepath.Join(tmpDir, "stderr"),
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	for _, m := range mounts {
 | 
					 | 
				
			||||||
		create.Rootfs = append(create.Rootfs, &mount.Mount{
 | 
					 | 
				
			||||||
			Type:    m.Type,
 | 
					 | 
				
			||||||
			Source:  m.Source,
 | 
					 | 
				
			||||||
			Options: m.Options,
 | 
					 | 
				
			||||||
		})
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if checkpoint != nil {
 | 
					 | 
				
			||||||
		create.Checkpoint = &descriptor.Descriptor{
 | 
					 | 
				
			||||||
			MediaType: checkpoint.MediaType,
 | 
					 | 
				
			||||||
			Size_:     checkpoint.Size,
 | 
					 | 
				
			||||||
			Digest:    checkpoint.Digest,
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return create, nil
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func handleConsoleResize(ctx context.Context, service execution.TasksClient, id string, pid uint32, con console.Console) error {
 | 
					 | 
				
			||||||
	// do an initial resize of the console
 | 
						// do an initial resize of the console
 | 
				
			||||||
	size, err := con.Size()
 | 
						size, err := con.Size()
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		return err
 | 
							return err
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	if _, err := service.Pty(ctx, &execution.PtyRequest{
 | 
						if err := task.Resize(ctx, uint32(size.Width), uint32(size.Height)); err != nil {
 | 
				
			||||||
		ContainerID: id,
 | 
							logrus.WithError(err).Error("resize pty")
 | 
				
			||||||
		Pid:         pid,
 | 
					 | 
				
			||||||
		Width:       uint32(size.Width),
 | 
					 | 
				
			||||||
		Height:      uint32(size.Height),
 | 
					 | 
				
			||||||
	}); err != nil {
 | 
					 | 
				
			||||||
		return err
 | 
					 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	s := make(chan os.Signal, 16)
 | 
						s := make(chan os.Signal, 16)
 | 
				
			||||||
	signal.Notify(s, unix.SIGWINCH)
 | 
						signal.Notify(s, unix.SIGWINCH)
 | 
				
			||||||
@@ -350,15 +36,86 @@ func handleConsoleResize(ctx context.Context, service execution.TasksClient, id
 | 
				
			|||||||
				logrus.WithError(err).Error("get pty size")
 | 
									logrus.WithError(err).Error("get pty size")
 | 
				
			||||||
				continue
 | 
									continue
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
			if _, err := service.Pty(ctx, &execution.PtyRequest{
 | 
								if err := task.Resize(ctx, uint32(size.Width), uint32(size.Height)); err != nil {
 | 
				
			||||||
				ContainerID: id,
 | 
					 | 
				
			||||||
				Pid:         pid,
 | 
					 | 
				
			||||||
				Width:       uint32(size.Width),
 | 
					 | 
				
			||||||
				Height:      uint32(size.Height),
 | 
					 | 
				
			||||||
			}); err != nil {
 | 
					 | 
				
			||||||
				logrus.WithError(err).Error("resize pty")
 | 
									logrus.WithError(err).Error("resize pty")
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}()
 | 
						}()
 | 
				
			||||||
	return nil
 | 
						return nil
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func withTTY() containerd.SpecOpts {
 | 
				
			||||||
 | 
						return containerd.WithTTY
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func setHostNetworking() containerd.SpecOpts {
 | 
				
			||||||
 | 
						return containerd.WithHostNamespace(specs.NetworkNamespace)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func newContainer(ctx gocontext.Context, client *containerd.Client, context *cli.Context) (containerd.Container, error) {
 | 
				
			||||||
 | 
						var (
 | 
				
			||||||
 | 
							err             error
 | 
				
			||||||
 | 
							checkpointIndex digest.Digest
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							ref  = context.Args().First()
 | 
				
			||||||
 | 
							id   = context.Args().Get(1)
 | 
				
			||||||
 | 
							args = context.Args()[2:]
 | 
				
			||||||
 | 
							tty  = context.Bool("tty")
 | 
				
			||||||
 | 
						)
 | 
				
			||||||
 | 
						if raw := context.String("checkpoint"); raw != "" {
 | 
				
			||||||
 | 
							if checkpointIndex, err = digest.Parse(raw); err != nil {
 | 
				
			||||||
 | 
								return nil, err
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						image, err := client.GetImage(ctx, ref)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return nil, err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if checkpointIndex == "" {
 | 
				
			||||||
 | 
							opts := []containerd.SpecOpts{
 | 
				
			||||||
 | 
								containerd.WithImageConfig(ctx, image),
 | 
				
			||||||
 | 
								withEnv(context),
 | 
				
			||||||
 | 
								withMounts(context),
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							if len(args) > 0 {
 | 
				
			||||||
 | 
								opts = append(opts, containerd.WithProcessArgs(args...))
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							if tty {
 | 
				
			||||||
 | 
								opts = append(opts, withTTY())
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							if context.Bool("net-host") {
 | 
				
			||||||
 | 
								opts = append(opts, setHostNetworking())
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							spec, err := containerd.GenerateSpec(opts...)
 | 
				
			||||||
 | 
							if err != nil {
 | 
				
			||||||
 | 
								return nil, err
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							var rootfs containerd.NewContainerOpts
 | 
				
			||||||
 | 
							if context.Bool("readonly") {
 | 
				
			||||||
 | 
								rootfs = containerd.WithNewReadonlyRootFS(id, image)
 | 
				
			||||||
 | 
							} else {
 | 
				
			||||||
 | 
								rootfs = containerd.WithNewRootFS(id, image)
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							return client.NewContainer(ctx, id,
 | 
				
			||||||
 | 
								containerd.WithSpec(spec),
 | 
				
			||||||
 | 
								containerd.WithImage(image),
 | 
				
			||||||
 | 
								rootfs,
 | 
				
			||||||
 | 
							)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return client.NewContainer(ctx, id, containerd.WithCheckpoint(v1.Descriptor{
 | 
				
			||||||
 | 
							Digest: checkpointIndex,
 | 
				
			||||||
 | 
						}, id))
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func newTask(ctx gocontext.Context, container containerd.Container, checkpoint digest.Digest, tty bool) (containerd.Task, error) {
 | 
				
			||||||
 | 
						if checkpoint == "" {
 | 
				
			||||||
 | 
							io := containerd.Stdio
 | 
				
			||||||
 | 
							if tty {
 | 
				
			||||||
 | 
								io = containerd.StdioTerminal
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							return container.NewTask(ctx, io)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return container.NewTask(ctx, containerd.Stdio, containerd.WithTaskCheckpoint(v1.Descriptor{
 | 
				
			||||||
 | 
							Digest: checkpoint,
 | 
				
			||||||
 | 
						}))
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,7 +1,7 @@
 | 
				
			|||||||
package main
 | 
					package main
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import (
 | 
					import (
 | 
				
			||||||
	"context"
 | 
						gocontext "context"
 | 
				
			||||||
	"encoding/json"
 | 
						"encoding/json"
 | 
				
			||||||
	"fmt"
 | 
						"fmt"
 | 
				
			||||||
	"io/ioutil"
 | 
						"io/ioutil"
 | 
				
			||||||
@@ -10,6 +10,7 @@ import (
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	"github.com/Sirupsen/logrus"
 | 
						"github.com/Sirupsen/logrus"
 | 
				
			||||||
	"github.com/containerd/console"
 | 
						"github.com/containerd/console"
 | 
				
			||||||
 | 
						"github.com/containerd/containerd"
 | 
				
			||||||
	containersapi "github.com/containerd/containerd/api/services/containers"
 | 
						containersapi "github.com/containerd/containerd/api/services/containers"
 | 
				
			||||||
	"github.com/containerd/containerd/api/services/execution"
 | 
						"github.com/containerd/containerd/api/services/execution"
 | 
				
			||||||
	"github.com/containerd/containerd/log"
 | 
						"github.com/containerd/containerd/log"
 | 
				
			||||||
@@ -17,6 +18,7 @@ import (
 | 
				
			|||||||
	"github.com/containerd/containerd/windows"
 | 
						"github.com/containerd/containerd/windows"
 | 
				
			||||||
	"github.com/containerd/containerd/windows/hcs"
 | 
						"github.com/containerd/containerd/windows/hcs"
 | 
				
			||||||
	protobuf "github.com/gogo/protobuf/types"
 | 
						protobuf "github.com/gogo/protobuf/types"
 | 
				
			||||||
 | 
						digest "github.com/opencontainers/go-digest"
 | 
				
			||||||
	ocispec "github.com/opencontainers/image-spec/specs-go/v1"
 | 
						ocispec "github.com/opencontainers/image-spec/specs-go/v1"
 | 
				
			||||||
	specs "github.com/opencontainers/runtime-spec/specs-go"
 | 
						specs "github.com/opencontainers/runtime-spec/specs-go"
 | 
				
			||||||
	"github.com/urfave/cli"
 | 
						"github.com/urfave/cli"
 | 
				
			||||||
@@ -169,7 +171,7 @@ func newCreateTaskRequest(context *cli.Context, id, tmpDir string, checkpoint *o
 | 
				
			|||||||
	return create, nil
 | 
						return create, nil
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func handleConsoleResize(ctx context.Context, service execution.TasksClient, id string, pid uint32, con console.Console) error {
 | 
					func handleConsoleResize(ctx gocontext.Context, task resizer, con console.Console) error {
 | 
				
			||||||
	// do an initial resize of the console
 | 
						// do an initial resize of the console
 | 
				
			||||||
	size, err := con.Size()
 | 
						size, err := con.Size()
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
@@ -187,13 +189,8 @@ func handleConsoleResize(ctx context.Context, service execution.TasksClient, id
 | 
				
			|||||||
			}
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			if size.Width != prevSize.Width || size.Height != prevSize.Height {
 | 
								if size.Width != prevSize.Width || size.Height != prevSize.Height {
 | 
				
			||||||
				if _, err := service.Pty(ctx, &execution.PtyRequest{
 | 
									if err := task.Resize(ctx, uint32(size.Width), uint32(size.Height)); err != nil {
 | 
				
			||||||
					ContainerID: id,
 | 
										logrus.WithError(err).Error("resize pty")
 | 
				
			||||||
					Pid:         pid,
 | 
					 | 
				
			||||||
					Width:       uint32(size.Width),
 | 
					 | 
				
			||||||
					Height:      uint32(size.Height),
 | 
					 | 
				
			||||||
				}); err != nil {
 | 
					 | 
				
			||||||
					log.G(ctx).WithError(err).Error("resize pty")
 | 
					 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
				prevSize = size
 | 
									prevSize = size
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
@@ -201,3 +198,68 @@ func handleConsoleResize(ctx context.Context, service execution.TasksClient, id
 | 
				
			|||||||
	}()
 | 
						}()
 | 
				
			||||||
	return nil
 | 
						return nil
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func withTTY() containerd.SpecOpts {
 | 
				
			||||||
 | 
						con := console.Current()
 | 
				
			||||||
 | 
						size, err := con.Size()
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							logrus.WithError(err).Error("console size")
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return containerd.WithTTY(int(size.Width), int(size.Height))
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func setHostNetworking() containerd.SpecOpts {
 | 
				
			||||||
 | 
						return nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func newContainer(ctx gocontext.Context, client *containerd.Client, context *cli.Context) (containerd.Container, error) {
 | 
				
			||||||
 | 
						var (
 | 
				
			||||||
 | 
							err error
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							ref  = context.Args().First()
 | 
				
			||||||
 | 
							id   = context.Args().Get(1)
 | 
				
			||||||
 | 
							args = context.Args()[2:]
 | 
				
			||||||
 | 
							tty  = context.Bool("tty")
 | 
				
			||||||
 | 
						)
 | 
				
			||||||
 | 
						image, err := client.GetImage(ctx, ref)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return nil, err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						opts := []containerd.SpecOpts{
 | 
				
			||||||
 | 
							containerd.WithImageConfig(ctx, image),
 | 
				
			||||||
 | 
							withEnv(context),
 | 
				
			||||||
 | 
							withMounts(context),
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if len(args) > 0 {
 | 
				
			||||||
 | 
							opts = append(opts, containerd.WithProcessArgs(args...))
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if tty {
 | 
				
			||||||
 | 
							opts = append(opts, withTTY())
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if context.Bool("net-host") {
 | 
				
			||||||
 | 
							opts = append(opts, setHostNetworking())
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						spec, err := containerd.GenerateSpec(opts...)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return nil, err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						var rootfs containerd.NewContainerOpts
 | 
				
			||||||
 | 
						if context.Bool("readonly") {
 | 
				
			||||||
 | 
							rootfs = containerd.WithNewReadonlyRootFS(id, image)
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							rootfs = containerd.WithNewRootFS(id, image)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return client.NewContainer(ctx, id,
 | 
				
			||||||
 | 
							containerd.WithSpec(spec),
 | 
				
			||||||
 | 
							containerd.WithImage(image),
 | 
				
			||||||
 | 
							rootfs,
 | 
				
			||||||
 | 
						)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func newTask(ctx gocontext.Context, container containerd.Container, _ digest.Digest, tty bool) (containerd.Task, error) {
 | 
				
			||||||
 | 
						io := containerd.Stdio
 | 
				
			||||||
 | 
						if tty {
 | 
				
			||||||
 | 
							io = containerd.StdioTerminal
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return container.NewTask(ctx, io)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -13,6 +13,7 @@ import (
 | 
				
			|||||||
	"syscall"
 | 
						"syscall"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	"github.com/Sirupsen/logrus"
 | 
						"github.com/Sirupsen/logrus"
 | 
				
			||||||
 | 
						"github.com/containerd/containerd"
 | 
				
			||||||
	containersapi "github.com/containerd/containerd/api/services/containers"
 | 
						containersapi "github.com/containerd/containerd/api/services/containers"
 | 
				
			||||||
	contentapi "github.com/containerd/containerd/api/services/content"
 | 
						contentapi "github.com/containerd/containerd/api/services/content"
 | 
				
			||||||
	diffapi "github.com/containerd/containerd/api/services/diff"
 | 
						diffapi "github.com/containerd/containerd/api/services/diff"
 | 
				
			||||||
@@ -70,6 +71,10 @@ func getNamespacesService(clicontext *cli.Context) (namespaces.Store, error) {
 | 
				
			|||||||
	return namespacesservice.NewStoreFromClient(namespacesapi.NewNamespacesClient(conn)), nil
 | 
						return namespacesservice.NewStoreFromClient(namespacesapi.NewNamespacesClient(conn)), nil
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func newClient(context *cli.Context) (*containerd.Client, error) {
 | 
				
			||||||
 | 
						return containerd.New(context.GlobalString("address"))
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func getContainersService(context *cli.Context) (containersapi.ContainersClient, error) {
 | 
					func getContainersService(context *cli.Context) (containersapi.ContainersClient, error) {
 | 
				
			||||||
	conn, err := getGRPCConnection(context)
 | 
						conn, err := getGRPCConnection(context)
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
@@ -153,23 +158,14 @@ func waitContainer(events execution.Tasks_EventsClient, id string, pid uint32) (
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func forwardAllSignals(containers execution.TasksClient, id string) chan os.Signal {
 | 
					func forwardAllSignals(ctx gocontext.Context, task killer) chan os.Signal {
 | 
				
			||||||
	sigc := make(chan os.Signal, 128)
 | 
						sigc := make(chan os.Signal, 128)
 | 
				
			||||||
	signal.Notify(sigc)
 | 
						signal.Notify(sigc)
 | 
				
			||||||
 | 
					 | 
				
			||||||
	go func() {
 | 
						go func() {
 | 
				
			||||||
		for s := range sigc {
 | 
							for s := range sigc {
 | 
				
			||||||
			logrus.Debug("Forwarding signal ", s)
 | 
								logrus.Debug("forwarding signal ", s)
 | 
				
			||||||
			killRequest := &execution.KillRequest{
 | 
								if err := task.Kill(ctx, s.(syscall.Signal)); err != nil {
 | 
				
			||||||
				ContainerID: id,
 | 
									logrus.WithError(err).Errorf("forward signal %s", s)
 | 
				
			||||||
				Signal:      uint32(s.(syscall.Signal)),
 | 
					 | 
				
			||||||
				PidOrAll: &execution.KillRequest_All{
 | 
					 | 
				
			||||||
					All: false,
 | 
					 | 
				
			||||||
				},
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
			_, err := containers.Kill(gocontext.Background(), killRequest)
 | 
					 | 
				
			||||||
			if err != nil {
 | 
					 | 
				
			||||||
				logrus.Fatalln(err)
 | 
					 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}()
 | 
						}()
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -6,7 +6,6 @@ import (
 | 
				
			|||||||
	"os"
 | 
						"os"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	"github.com/containerd/containerd/version"
 | 
						"github.com/containerd/containerd/version"
 | 
				
			||||||
	empty "github.com/golang/protobuf/ptypes/empty"
 | 
					 | 
				
			||||||
	"github.com/urfave/cli"
 | 
						"github.com/urfave/cli"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -21,14 +20,15 @@ var versionCommand = cli.Command{
 | 
				
			|||||||
		fmt.Printf("  Version: %s\n", version.Version)
 | 
							fmt.Printf("  Version: %s\n", version.Version)
 | 
				
			||||||
		fmt.Printf("  Revision: %s\n", version.Revision)
 | 
							fmt.Printf("  Revision: %s\n", version.Revision)
 | 
				
			||||||
		fmt.Println("")
 | 
							fmt.Println("")
 | 
				
			||||||
		vs, err := getVersionService(context)
 | 
							client, err := newClient(context)
 | 
				
			||||||
		if err != nil {
 | 
							if err != nil {
 | 
				
			||||||
			return err
 | 
								return err
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		v, err := vs.Version(gocontext.Background(), &empty.Empty{})
 | 
							v, err := client.Version(gocontext.Background())
 | 
				
			||||||
		if err != nil {
 | 
							if err != nil {
 | 
				
			||||||
			return err
 | 
								return err
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		fmt.Println("Server:")
 | 
							fmt.Println("Server:")
 | 
				
			||||||
		fmt.Printf("  Version: %s\n", v.Version)
 | 
							fmt.Printf("  Version: %s\n", v.Version)
 | 
				
			||||||
		fmt.Printf("  Revision: %s\n", v.Revision)
 | 
							fmt.Printf("  Revision: %s\n", v.Revision)
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										92
									
								
								container.go
									
									
									
									
									
								
							
							
						
						
									
										92
									
								
								container.go
									
									
									
									
									
								
							@@ -3,21 +3,30 @@ package containerd
 | 
				
			|||||||
import (
 | 
					import (
 | 
				
			||||||
	"context"
 | 
						"context"
 | 
				
			||||||
	"encoding/json"
 | 
						"encoding/json"
 | 
				
			||||||
 | 
						"fmt"
 | 
				
			||||||
	"path/filepath"
 | 
						"path/filepath"
 | 
				
			||||||
 | 
						"sync"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						"google.golang.org/grpc"
 | 
				
			||||||
 | 
						"google.golang.org/grpc/codes"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	"github.com/containerd/containerd/api/services/containers"
 | 
						"github.com/containerd/containerd/api/services/containers"
 | 
				
			||||||
	"github.com/containerd/containerd/api/services/execution"
 | 
						"github.com/containerd/containerd/api/services/execution"
 | 
				
			||||||
	"github.com/containerd/containerd/api/types/mount"
 | 
						"github.com/containerd/containerd/api/types/mount"
 | 
				
			||||||
	specs "github.com/opencontainers/runtime-spec/specs-go"
 | 
						specs "github.com/opencontainers/runtime-spec/specs-go"
 | 
				
			||||||
 | 
						"github.com/pkg/errors"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					var ErrNoRunningTask = errors.New("no running task")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type Container interface {
 | 
					type Container interface {
 | 
				
			||||||
	ID() string
 | 
						ID() string
 | 
				
			||||||
 | 
						Proto() containers.Container
 | 
				
			||||||
	Delete(context.Context) error
 | 
						Delete(context.Context) error
 | 
				
			||||||
	NewTask(context.Context, IOCreation, ...NewTaskOpts) (Task, error)
 | 
						NewTask(context.Context, IOCreation, ...NewTaskOpts) (Task, error)
 | 
				
			||||||
	Spec() (*specs.Spec, error)
 | 
						Spec() (*specs.Spec, error)
 | 
				
			||||||
	Task() Task
 | 
						Task(context.Context, IOAttach) (Task, error)
 | 
				
			||||||
	LoadTask(context.Context, IOAttach) (Task, error)
 | 
						Image(context.Context) (Image, error)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func containerFromProto(client *Client, c containers.Container) *container {
 | 
					func containerFromProto(client *Client, c containers.Container) *container {
 | 
				
			||||||
@@ -30,10 +39,11 @@ func containerFromProto(client *Client, c containers.Container) *container {
 | 
				
			|||||||
var _ = (Container)(&container{})
 | 
					var _ = (Container)(&container{})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type container struct {
 | 
					type container struct {
 | 
				
			||||||
	client *Client
 | 
						mu sync.Mutex
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	c    containers.Container
 | 
						client *Client
 | 
				
			||||||
	task *task
 | 
						c      containers.Container
 | 
				
			||||||
 | 
						task   *task
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// ID returns the container's unique id
 | 
					// ID returns the container's unique id
 | 
				
			||||||
@@ -41,6 +51,10 @@ func (c *container) ID() string {
 | 
				
			|||||||
	return c.c.ID
 | 
						return c.c.ID
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (c *container) Proto() containers.Container {
 | 
				
			||||||
 | 
						return c.c
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Spec returns the current OCI specification for the container
 | 
					// Spec returns the current OCI specification for the container
 | 
				
			||||||
func (c *container) Spec() (*specs.Spec, error) {
 | 
					func (c *container) Spec() (*specs.Spec, error) {
 | 
				
			||||||
	var s specs.Spec
 | 
						var s specs.Spec
 | 
				
			||||||
@@ -58,7 +72,6 @@ func (c *container) Delete(ctx context.Context) (err error) {
 | 
				
			|||||||
	if c.c.RootFS != "" {
 | 
						if c.c.RootFS != "" {
 | 
				
			||||||
		err = c.client.SnapshotService().Remove(ctx, c.c.RootFS)
 | 
							err = c.client.SnapshotService().Remove(ctx, c.c.RootFS)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					 | 
				
			||||||
	if _, cerr := c.client.ContainerService().Delete(ctx, &containers.DeleteContainerRequest{
 | 
						if _, cerr := c.client.ContainerService().Delete(ctx, &containers.DeleteContainerRequest{
 | 
				
			||||||
		ID: c.c.ID,
 | 
							ID: c.c.ID,
 | 
				
			||||||
	}); err == nil {
 | 
						}); err == nil {
 | 
				
			||||||
@@ -67,13 +80,39 @@ func (c *container) Delete(ctx context.Context) (err error) {
 | 
				
			|||||||
	return err
 | 
						return err
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (c *container) Task() Task {
 | 
					func (c *container) Task(ctx context.Context, attach IOAttach) (Task, error) {
 | 
				
			||||||
	return c.task
 | 
						c.mu.Lock()
 | 
				
			||||||
 | 
						defer c.mu.Unlock()
 | 
				
			||||||
 | 
						if c.task == nil {
 | 
				
			||||||
 | 
							t, err := c.loadTask(ctx, attach)
 | 
				
			||||||
 | 
							if err != nil {
 | 
				
			||||||
 | 
								return nil, err
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							c.task = t.(*task)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return c.task, nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Image returns the image that the container is based on
 | 
				
			||||||
 | 
					func (c *container) Image(ctx context.Context) (Image, error) {
 | 
				
			||||||
 | 
						if c.c.Image == "" {
 | 
				
			||||||
 | 
							return nil, fmt.Errorf("container is not based on an image")
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						i, err := c.client.ImageService().Get(ctx, c.c.Image)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return nil, err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return &image{
 | 
				
			||||||
 | 
							client: c.client,
 | 
				
			||||||
 | 
							i:      i,
 | 
				
			||||||
 | 
						}, nil
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type NewTaskOpts func(context.Context, *Client, *execution.CreateRequest) error
 | 
					type NewTaskOpts func(context.Context, *Client, *execution.CreateRequest) error
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (c *container) NewTask(ctx context.Context, ioCreate IOCreation, opts ...NewTaskOpts) (Task, error) {
 | 
					func (c *container) NewTask(ctx context.Context, ioCreate IOCreation, opts ...NewTaskOpts) (Task, error) {
 | 
				
			||||||
 | 
						c.mu.Lock()
 | 
				
			||||||
 | 
						defer c.mu.Unlock()
 | 
				
			||||||
	i, err := ioCreate()
 | 
						i, err := ioCreate()
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		return nil, err
 | 
							return nil, err
 | 
				
			||||||
@@ -126,28 +165,33 @@ func (c *container) NewTask(ctx context.Context, ioCreate IOCreation, opts ...Ne
 | 
				
			|||||||
	return t, nil
 | 
						return t, nil
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (c *container) LoadTask(ctx context.Context, ioAttach IOAttach) (Task, error) {
 | 
					func (c *container) loadTask(ctx context.Context, ioAttach IOAttach) (Task, error) {
 | 
				
			||||||
	response, err := c.client.TaskService().Info(ctx, &execution.InfoRequest{
 | 
						response, err := c.client.TaskService().Info(ctx, &execution.InfoRequest{
 | 
				
			||||||
		ContainerID: c.c.ID,
 | 
							ContainerID: c.c.ID,
 | 
				
			||||||
	})
 | 
						})
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
 | 
							if grpc.Code(errors.Cause(err)) == codes.NotFound {
 | 
				
			||||||
 | 
								return nil, ErrNoRunningTask
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
		return nil, err
 | 
							return nil, err
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	// get the existing fifo paths from the task information stored by the daemon
 | 
						var i *IO
 | 
				
			||||||
	paths := &FifoSet{
 | 
						if ioAttach != nil {
 | 
				
			||||||
		Dir: getFifoDir([]string{
 | 
							// get the existing fifo paths from the task information stored by the daemon
 | 
				
			||||||
			response.Task.Stdin,
 | 
							paths := &FifoSet{
 | 
				
			||||||
			response.Task.Stdout,
 | 
								Dir: getFifoDir([]string{
 | 
				
			||||||
			response.Task.Stderr,
 | 
									response.Task.Stdin,
 | 
				
			||||||
		}),
 | 
									response.Task.Stdout,
 | 
				
			||||||
		In:       response.Task.Stdin,
 | 
									response.Task.Stderr,
 | 
				
			||||||
		Out:      response.Task.Stdout,
 | 
								}),
 | 
				
			||||||
		Err:      response.Task.Stderr,
 | 
								In:       response.Task.Stdin,
 | 
				
			||||||
		Terminal: response.Task.Terminal,
 | 
								Out:      response.Task.Stdout,
 | 
				
			||||||
	}
 | 
								Err:      response.Task.Stderr,
 | 
				
			||||||
	i, err := ioAttach(paths)
 | 
								Terminal: response.Task.Terminal,
 | 
				
			||||||
	if err != nil {
 | 
							}
 | 
				
			||||||
		return nil, err
 | 
							if i, err = ioAttach(paths); err != nil {
 | 
				
			||||||
 | 
								return nil, err
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	t := &task{
 | 
						t := &task{
 | 
				
			||||||
		client:      c.client,
 | 
							client:      c.client,
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -558,7 +558,7 @@ func TestContainerAttach(t *testing.T) {
 | 
				
			|||||||
		t.Error(err)
 | 
							t.Error(err)
 | 
				
			||||||
		return
 | 
							return
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	if task, err = container.LoadTask(ctx, WithAttach(r, ow, ioutil.Discard)); err != nil {
 | 
						if task, err = container.Task(ctx, WithAttach(r, ow, ioutil.Discard)); err != nil {
 | 
				
			||||||
		t.Error(err)
 | 
							t.Error(err)
 | 
				
			||||||
		return
 | 
							return
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,3 +1,5 @@
 | 
				
			|||||||
 | 
					// +build !windows
 | 
				
			||||||
 | 
					
 | 
				
			||||||
package containerd
 | 
					package containerd
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import (
 | 
					import (
 | 
				
			||||||
@@ -19,20 +21,6 @@ import (
 | 
				
			|||||||
	specs "github.com/opencontainers/runtime-spec/specs-go"
 | 
						specs "github.com/opencontainers/runtime-spec/specs-go"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func WithSpec(spec *specs.Spec) NewContainerOpts {
 | 
					 | 
				
			||||||
	return func(ctx context.Context, client *Client, c *containers.Container) error {
 | 
					 | 
				
			||||||
		data, err := json.Marshal(spec)
 | 
					 | 
				
			||||||
		if err != nil {
 | 
					 | 
				
			||||||
			return err
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		c.Spec = &protobuf.Any{
 | 
					 | 
				
			||||||
			TypeUrl: spec.Version,
 | 
					 | 
				
			||||||
			Value:   data,
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		return nil
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
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 {
 | 
				
			||||||
@@ -110,3 +110,7 @@ func (p *process) Resize(ctx context.Context, w, h uint32) error {
 | 
				
			|||||||
	})
 | 
						})
 | 
				
			||||||
	return err
 | 
						return err
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (p *process) Delete() error {
 | 
				
			||||||
 | 
						return p.io.Close()
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										16
									
								
								spec_unix.go
									
									
									
									
									
								
							
							
						
						
									
										16
									
								
								spec_unix.go
									
									
									
									
									
								
							@@ -10,7 +10,9 @@ import (
 | 
				
			|||||||
	"strconv"
 | 
						"strconv"
 | 
				
			||||||
	"strings"
 | 
						"strings"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						"github.com/containerd/containerd/api/services/containers"
 | 
				
			||||||
	"github.com/containerd/containerd/images"
 | 
						"github.com/containerd/containerd/images"
 | 
				
			||||||
 | 
						protobuf "github.com/gogo/protobuf/types"
 | 
				
			||||||
	"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"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
@@ -255,3 +257,17 @@ func WithImageConfig(ctx context.Context, i Image) SpecOpts {
 | 
				
			|||||||
		return nil
 | 
							return nil
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func WithSpec(spec *specs.Spec) NewContainerOpts {
 | 
				
			||||||
 | 
						return func(ctx context.Context, client *Client, c *containers.Container) error {
 | 
				
			||||||
 | 
							data, err := json.Marshal(spec)
 | 
				
			||||||
 | 
							if err != nil {
 | 
				
			||||||
 | 
								return err
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							c.Spec = &protobuf.Any{
 | 
				
			||||||
 | 
								TypeUrl: spec.Version,
 | 
				
			||||||
 | 
								Value:   data,
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							return nil
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -6,7 +6,9 @@ import (
 | 
				
			|||||||
	"fmt"
 | 
						"fmt"
 | 
				
			||||||
	"runtime"
 | 
						"runtime"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						"github.com/containerd/containerd/api/services/containers"
 | 
				
			||||||
	"github.com/containerd/containerd/images"
 | 
						"github.com/containerd/containerd/images"
 | 
				
			||||||
 | 
						protobuf "github.com/gogo/protobuf/types"
 | 
				
			||||||
	"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"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
@@ -76,3 +78,17 @@ func WithTTY(width, height int) SpecOpts {
 | 
				
			|||||||
		return nil
 | 
							return nil
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func WithSpec(spec *specs.Spec) NewContainerOpts {
 | 
				
			||||||
 | 
						return func(ctx context.Context, client *Client, c *containers.Container) error {
 | 
				
			||||||
 | 
							data, err := json.Marshal(spec)
 | 
				
			||||||
 | 
							if err != nil {
 | 
				
			||||||
 | 
								return err
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							c.Spec = &protobuf.Any{
 | 
				
			||||||
 | 
								TypeUrl: spec.Version,
 | 
				
			||||||
 | 
								Value:   data,
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							return nil
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										1
									
								
								task.go
									
									
									
									
									
								
							
							
						
						
									
										1
									
								
								task.go
									
									
									
									
									
								
							@@ -52,6 +52,7 @@ type Task interface {
 | 
				
			|||||||
type Process interface {
 | 
					type Process interface {
 | 
				
			||||||
	Pid() uint32
 | 
						Pid() uint32
 | 
				
			||||||
	Start(context.Context) error
 | 
						Start(context.Context) error
 | 
				
			||||||
 | 
						Delete() error
 | 
				
			||||||
	Kill(context.Context, syscall.Signal) error
 | 
						Kill(context.Context, syscall.Signal) error
 | 
				
			||||||
	Wait(context.Context) (uint32, error)
 | 
						Wait(context.Context) (uint32, error)
 | 
				
			||||||
	CloseStdin(context.Context) error
 | 
						CloseStdin(context.Context) error
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user