diff --git a/cmd/ctr/run.go b/cmd/ctr/run.go index ce2a959..ec9279e 100644 --- a/cmd/ctr/run.go +++ b/cmd/ctr/run.go @@ -4,6 +4,7 @@ import ( gocontext "context" "encoding/json" "fmt" + "os" "path/filepath" "runtime" "strconv" @@ -51,8 +52,13 @@ func spec(id string, config *ocispec.ImageConfig, context *cli.Context) (*specs. "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin", } env = append(env, config.Env...) + cmd := config.Cmd + if v := context.Args().Tail(); len(v) > 0 { + cmd = v + } var ( - args = append(config.Entrypoint, config.Cmd...) + // TODO: support overriding entrypoint + args = append(config.Entrypoint, cmd...) tty = context.Bool("tty") uid, gid uint32 ) @@ -214,8 +220,9 @@ func spec(id string, config *ocispec.ImageConfig, context *cli.Context) (*specs. } var runCommand = cli.Command{ - Name: "run", - Usage: "run a container", + Name: "run", + Usage: "run a container", + ArgsUsage: "IMAGE [COMMAND] [ARG...]", Flags: []cli.Flag{ cli.StringFlag{ Name: "id", @@ -254,6 +261,7 @@ var runCommand = cli.Command{ if err != nil { return err } + defer os.RemoveAll(tmpDir) events, err := containers.Events(ctx, &execution.EventsRequest{}) if err != nil { return err diff --git a/cmd/dist/images.go b/cmd/dist/images.go index be5a83d..fbc1e76 100644 --- a/cmd/dist/images.go +++ b/cmd/dist/images.go @@ -61,3 +61,41 @@ var imagesCommand = cli.Command{ return nil }, } + +var rmiCommand = cli.Command{ + Name: "rmi", + Usage: "Delete one or more images by reference.", + ArgsUsage: "[flags] [, ...]", + Description: `Delete one or more images by reference.`, + Flags: []cli.Flag{}, + Action: func(clicontext *cli.Context) error { + var ( + ctx = background + exitErr error + ) + + db, err := getDB(clicontext, false) + if err != nil { + return errors.Wrap(err, "failed to open database") + } + + tx, err := db.Begin(true) + if err != nil { + return errors.Wrap(err, "could not start transaction") + } + defer tx.Rollback() + + for _, target := range clicontext.Args() { + if err := images.Delete(tx, target); err != nil { + if exitErr == nil { + exitErr = errors.Wrapf(err, "unable to delete %v", target) + } + log.G(ctx).WithError(err).Errorf("unable to delete %v", target) + } + + fmt.Println(target) + } + + return exitErr + }, +} diff --git a/cmd/dist/main.go b/cmd/dist/main.go index d0070cf..c3fc54e 100644 --- a/cmd/dist/main.go +++ b/cmd/dist/main.go @@ -62,6 +62,7 @@ distribution tool } app.Commands = []cli.Command{ imagesCommand, + rmiCommand, pullCommand, fetchCommand, fetchObjectCommand, diff --git a/cmd/dist/pull.go b/cmd/dist/pull.go index 1c93f25..82423f8 100644 --- a/cmd/dist/pull.go +++ b/cmd/dist/pull.go @@ -67,6 +67,7 @@ command. As part of this process, we do the following: ingester := contentservice.NewIngesterFromClient(contentapi.NewContentClient(conn)) provider := contentservice.NewProviderFromClient(contentapi.NewContentClient(conn)) + cs, err := resolveContentStore(clicontext) if err != nil { return err diff --git a/docs/dockercon-summit.md b/docs/dockercon-summit.md index cb13581..87ca482 100644 --- a/docs/dockercon-summit.md +++ b/docs/dockercon-summit.md @@ -17,5 +17,7 @@ If you have not signed up to attend the summit you can do so in this [form](http The following are proposed discussion points for the containerd summit at Dockercon US 2017: + * Since containerd is one of the bottom bricks in the stack, how can we setup automated integration tests for consumers of containerd? * We'd like to propose an Authorization plugin to containerd that would allow an external component to police events like container start & stop (and have a discussion about the best way to go about it) +* Should containerd provide image filesystem metrics? If yes, what metrics should be included? How to implement that? \ No newline at end of file diff --git a/images/storage.go b/images/storage.go index 2f4382a..050addb 100644 --- a/images/storage.go +++ b/images/storage.go @@ -103,6 +103,12 @@ func List(tx *bolt.Tx) ([]Image, error) { return images, nil } +func Delete(tx *bolt.Tx, name string) error { + return withImagesBucket(tx, func(bkt *bolt.Bucket) error { + return bkt.DeleteBucket([]byte(name)) + }) +} + func readImage(image *Image, bkt *bolt.Bucket) error { return bkt.ForEach(func(k, v []byte) error { if v == nil { diff --git a/linux/shim/exec.go b/linux/shim/exec.go index 4b45273..5328a6e 100644 --- a/linux/shim/exec.go +++ b/linux/shim/exec.go @@ -4,14 +4,17 @@ import ( "context" "encoding/json" "fmt" + "io" "os" "path/filepath" "sync" + "syscall" "github.com/crosbymichael/console" runc "github.com/crosbymichael/go-runc" shimapi "github.com/docker/containerd/api/services/shim" specs "github.com/opencontainers/runtime-spec/specs-go" + "github.com/tonistiigi/fifo" ) type execProcess struct { @@ -22,6 +25,7 @@ type execProcess struct { io runc.IO status int pid int + closers []io.Closer parent *initProcess } @@ -66,6 +70,13 @@ func newExecProcess(context context.Context, path string, r *shimapi.ExecRequest if err := parent.runc.Exec(context, parent.id, spec, opts); err != nil { return nil, err } + if r.Stdin != "" { + sc, err := fifo.OpenFifo(context, r.Stdin, syscall.O_WRONLY|syscall.O_NONBLOCK, 0) + if err != nil { + return nil, err + } + e.closers = append(e.closers, sc) + } if socket != nil { console, err := socket.ReceiveMaster() if err != nil { @@ -111,6 +122,9 @@ func (e *execProcess) Exited(status int) { e.status = status e.Wait() if e.io != nil { + for _, c := range e.closers { + c.Close() + } e.io.Close() } } diff --git a/linux/shim/init.go b/linux/shim/init.go index aba5c60..d11669b 100644 --- a/linux/shim/init.go +++ b/linux/shim/init.go @@ -2,6 +2,7 @@ package shim import ( "context" + "io" "os" "path/filepath" "sync" @@ -11,6 +12,7 @@ import ( runc "github.com/crosbymichael/go-runc" "github.com/docker/containerd" shimapi "github.com/docker/containerd/api/services/shim" + "github.com/tonistiigi/fifo" ) type initProcess struct { @@ -23,6 +25,7 @@ type initProcess struct { runc *runc.Runc status int pid int + closers []io.Closer } func newInitProcess(context context.Context, path string, r *shimapi.CreateRequest) (*initProcess, error) { @@ -73,6 +76,13 @@ func newInitProcess(context context.Context, path string, r *shimapi.CreateReque if err := p.runc.Create(context, r.ID, r.Bundle, opts); err != nil { return nil, err } + if r.Stdin != "" { + sc, err := fifo.OpenFifo(context, r.Stdin, syscall.O_WRONLY|syscall.O_NONBLOCK, 0) + if err != nil { + return nil, err + } + p.closers = append(p.closers, sc) + } if socket != nil { console, err := socket.ReceiveMaster() if err != nil { @@ -125,6 +135,9 @@ func (p *initProcess) Delete(context context.Context) error { p.Wait() err := p.runc.Delete(context, p.id) if p.io != nil { + for _, c := range p.closers { + c.Close() + } p.io.Close() } return err diff --git a/linux/shim/io.go b/linux/shim/io.go index 8fbd647..8387c04 100644 --- a/linux/shim/io.go +++ b/linux/shim/io.go @@ -68,6 +68,9 @@ func copyPipes(ctx context.Context, rio runc.IO, stdin, stdout, stderr string, w } dest(fw, fr) } + if stdin == "" { + return nil + } f, err := fifo.OpenFifo(ctx, stdin, syscall.O_RDONLY, 0) if err != nil { return fmt.Errorf("containerd-shim: opening %s failed: %s", stdin, err)