From e1ed4a2ea469fa0dea78f1d0d7ce5a5c128221ef Mon Sep 17 00:00:00 2001 From: Derek McGowan Date: Tue, 23 May 2017 13:00:30 -0700 Subject: [PATCH] Add json storage for container storage This is just a temporary storage solution to get containers running on the new code. Signed-off-by: Derek McGowan --- cmd/ctr/delete.go | 9 +++- cmd/ctr/list.go | 9 +++- cmd/ctr/run.go | 6 +++ containers/storage.go | 99 +++++++++++++++++++++++++++++++++-- linux/runtime.go | 2 +- services/execution/service.go | 4 +- 6 files changed, 118 insertions(+), 11 deletions(-) diff --git a/cmd/ctr/delete.go b/cmd/ctr/delete.go index 64075e139..2d9500578 100644 --- a/cmd/ctr/delete.go +++ b/cmd/ctr/delete.go @@ -3,6 +3,9 @@ package main import ( gocontext "context" + "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" @@ -43,7 +46,11 @@ var deleteCommand = cli.Command{ ContainerID: id, }) if err != nil { - return errors.Wrap(err, "failed to delete container") + // 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 err := snapshotter.Remove(ctx, id); err != nil { diff --git a/cmd/ctr/list.go b/cmd/ctr/list.go index 0aa66d68f..16e52c5df 100644 --- a/cmd/ctr/list.go +++ b/cmd/ctr/list.go @@ -65,18 +65,23 @@ var listCommand = cli.Command{ w := tabwriter.NewWriter(os.Stdout, 10, 1, 3, ' ', 0) fmt.Fprintln(w, "ID\tIMAGE\tPID\tSTATUS") for _, c := range response.Containers { - var status string + var ( + status string + pid uint32 + ) task, ok := tasksByContainerID[c.ID] if ok { 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, - task.Pid, + pid, status, ); err != nil { return err diff --git a/cmd/ctr/run.go b/cmd/ctr/run.go index 19b75df0f..cacd83e27 100644 --- a/cmd/ctr/run.go +++ b/cmd/ctr/run.go @@ -10,6 +10,7 @@ import ( "github.com/Sirupsen/logrus" "github.com/containerd/console" + containersapi "github.com/containerd/containerd/api/services/containers" "github.com/containerd/containerd/api/services/execution" "github.com/containerd/containerd/images" "github.com/containerd/containerd/mount" @@ -294,6 +295,11 @@ var runCommand = cli.Command{ }); err != nil { return err } + if context.Bool("rm") { + if _, err := containers.Delete(ctx, &containersapi.DeleteContainerRequest{ID: id}); err != nil { + return err + } + } if status != 0 { return cli.NewExitError("", int(status)) } diff --git a/containers/storage.go b/containers/storage.go index 95fa2e086..f780c301d 100644 --- a/containers/storage.go +++ b/containers/storage.go @@ -2,6 +2,7 @@ package containers import ( "context" + "encoding/json" "github.com/boltdb/bolt" "github.com/pkg/errors" @@ -37,21 +38,109 @@ func NewStore(tx *bolt.Tx) Store { } func (s *storage) Get(ctx context.Context, id string) (Container, error) { - panic("not implemented") + bkt := s.bucket() + if bkt == nil { + return Container{}, errors.Wrap(ErrNotFound, "bucket does not exist") + } + + cb := bkt.Get([]byte(id)) + if len(cb) == 0 { + return Container{}, errors.Wrap(ErrNotFound, "no content for id") + } + + var container Container + if err := json.Unmarshal(cb, &container); err != nil { + return Container{}, errors.Wrap(err, "failed to unmarshal container") + } + + return container, nil } func (s *storage) List(ctx context.Context, filter string) ([]Container, error) { - panic("not implemented") + containers := []Container{} + bkt := s.bucket() + if bkt == nil { + return containers, nil + } + err := bkt.ForEach(func(k, v []byte) error { + container := Container{ID: string(k)} + if err := json.Unmarshal(v, &container); err != nil { + return errors.Wrap(err, "failed to unmarshal container") + } + containers = append(containers, container) + return nil + }) + if err != nil { + return nil, err + } + + return containers, nil } func (s *storage) Create(ctx context.Context, container Container) (Container, error) { - panic("not implemented") + bkt, err := s.createBucket() + if err != nil { + return Container{}, err + } + + b := bkt.Get([]byte(container.ID)) + if len(b) > 0 { + return Container{}, errors.Wrap(ErrExists, "content for id already exists") + } + + b, err = json.Marshal(container) + if err != nil { + return Container{}, err + } + + return container, bkt.Put([]byte(container.ID), b) } func (s *storage) Update(ctx context.Context, container Container) (Container, error) { - panic("not implemented") + bkt, err := s.createBucket() + if err != nil { + return Container{}, err + } + + b := bkt.Get([]byte(container.ID)) + if len(b) == 0 { + return Container{}, errors.Wrap(ErrNotFound, "no content for id") + } + + b, err = json.Marshal(container) + if err != nil { + return Container{}, err + } + + return container, bkt.Put([]byte(container.ID), b) } func (s *storage) Delete(ctx context.Context, id string) error { - panic("not implemented") + bkt, err := s.createBucket() + if err != nil { + return err + } + + b := bkt.Get([]byte(id)) + if len(b) == 0 { + return errors.Wrap(ErrNotFound, "no content for id") + } + + return bkt.Delete([]byte(id)) +} + +func (s *storage) bucket() *bolt.Bucket { + bkt := s.tx.Bucket(bucketKeyStorageVersion) + if bkt == nil { + return nil + } + return bkt.Bucket(bucketKeyContainers) +} + +func (s *storage) createBucket() (*bolt.Bucket, error) { + bkt, err := s.tx.CreateBucketIfNotExists(bucketKeyStorageVersion) + if err != nil { + return nil, err + } + return bkt.CreateBucketIfNotExists(bucketKeyContainers) } diff --git a/linux/runtime.go b/linux/runtime.go index 65220a613..cf1094ab4 100644 --- a/linux/runtime.go +++ b/linux/runtime.go @@ -128,7 +128,7 @@ func (r *Runtime) Create(ctx context.Context, id string, opts plugin.CreateOpts) return nil, err } c := newTask(id, opts.Spec, s) - // after the task is create add it to the monitor + // after the task is created, add it to the monitor if err = r.monitor.Monitor(c); err != nil { return nil, err } diff --git a/services/execution/service.go b/services/execution/service.go index ae68d9cb1..4a4483501 100644 --- a/services/execution/service.go +++ b/services/execution/service.go @@ -144,7 +144,7 @@ func (s *Service) Create(ctx context.Context, r *api.CreateRequest) (*api.Create s.mu.Lock() if _, ok := s.tasks[r.ContainerID]; ok { s.mu.Unlock() - return nil, plugin.ErrContainerExists + return nil, grpc.Errorf(codes.AlreadyExists, "task %v already exists", r.ContainerID) } c, err := runtime.Create(ctx, r.ContainerID, opts) if err != nil { @@ -457,7 +457,7 @@ func (s *Service) getTask(id string) (plugin.Task, error) { c, ok := s.tasks[id] s.mu.Unlock() if !ok { - return nil, plugin.ErrContainerNotExist + return nil, grpc.Errorf(codes.NotFound, "task %v not found", id) } return c, nil }