diff --git a/cmd/dist/images.go b/cmd/dist/images.go index 800df2e..be5a83d 100644 --- a/cmd/dist/images.go +++ b/cmd/dist/images.go @@ -5,8 +5,11 @@ import ( "os" "text/tabwriter" + contentapi "github.com/docker/containerd/api/services/content" "github.com/docker/containerd/images" + "github.com/docker/containerd/log" "github.com/docker/containerd/progress" + contentservice "github.com/docker/containerd/services/content" "github.com/pkg/errors" "github.com/urfave/cli" ) @@ -18,17 +21,26 @@ var imagesCommand = cli.Command{ Description: `List images registered with containerd.`, Flags: []cli.Flag{}, Action: func(clicontext *cli.Context) error { + var ( + ctx = background + ) + db, err := getDB(clicontext, true) if err != nil { return errors.Wrap(err, "failed to open database") } - tx, err := db.Begin(false) if err != nil { return errors.Wrap(err, "could not start transaction") } defer tx.Rollback() + conn, err := connectGRPC(clicontext) + if err != nil { + return err + } + provider := contentservice.NewProviderFromClient(contentapi.NewContentClient(conn)) + images, err := images.List(tx) if err != nil { return errors.Wrap(err, "failed to list images") @@ -37,7 +49,12 @@ var imagesCommand = cli.Command{ tw := tabwriter.NewWriter(os.Stdout, 1, 8, 1, ' ', 0) fmt.Fprintln(tw, "REF\tTYPE\tDIGEST\tSIZE\t") for _, image := range images { - fmt.Fprintf(tw, "%v\t%v\t%v\t%v\t\n", image.Name, image.Descriptor.MediaType, image.Descriptor.Digest, progress.Bytes(image.Descriptor.Size)) + size, err := image.Size(ctx, provider) + if err != nil { + log.G(ctx).WithError(err).Errorf("failed calculating size for image %s", image.Name) + } + + fmt.Fprintf(tw, "%v\t%v\t%v\t%v\t\n", image.Name, image.Descriptor.MediaType, image.Descriptor.Digest, progress.Bytes(size)) } tw.Flush() diff --git a/images/image.go b/images/image.go index 7e79664..cdbf61d 100644 --- a/images/image.go +++ b/images/image.go @@ -86,3 +86,40 @@ func (image *Image) RootFS(ctx context.Context, provider content.Provider) ([]di return diffIDs, nil } + +// Size returns the total size of an image's packed resources. +func (image *Image) Size(ctx context.Context, provider content.Provider) (int64, error) { + var size int64 + return size, Walk(ctx, HandlerFunc(func(ctx context.Context, desc ocispec.Descriptor) ([]ocispec.Descriptor, error) { + switch image.Descriptor.MediaType { + case MediaTypeDockerSchema2Manifest, ocispec.MediaTypeImageManifest: + size += desc.Size + rc, err := provider.Reader(ctx, image.Descriptor.Digest) + if err != nil { + return nil, err + } + defer rc.Close() + + p, err := ioutil.ReadAll(rc) + if err != nil { + return nil, err + } + + var manifest ocispec.Manifest + if err := json.Unmarshal(p, &manifest); err != nil { + return nil, err + } + + size += manifest.Config.Size + + for _, layer := range manifest.Layers { + size += layer.Size + } + + return nil, nil + default: + return nil, errors.New("unsupported type") + } + + }), image.Descriptor) +} diff --git a/images/storage.go b/images/storage.go index 02ceebe..2f4382a 100644 --- a/images/storage.go +++ b/images/storage.go @@ -12,7 +12,6 @@ import ( var ( errImageUnknown = fmt.Errorf("image: unknown") - errNoTx = fmt.Errorf("no transaction available") ) var (