Update Images() to allow retrieving specific image size data

Those data include:
 - size of data shared with other images
 - size of data unique to a given image
 - how many containers are using a given image

Signed-off-by: Kenfe-Mickael Laventure <mickael.laventure@gmail.com>
This commit is contained in:
Kenfe-Mickael Laventure 2016-08-23 16:19:37 -07:00
parent c6db1e9c1b
commit b717de5153
5 changed files with 74 additions and 7 deletions

View File

@ -25,7 +25,7 @@ type containerBackend interface {
type imageBackend interface {
ImageDelete(imageRef string, force, prune bool) ([]types.ImageDelete, error)
ImageHistory(imageName string) ([]*types.ImageHistory, error)
Images(filterArgs string, filter string, all bool) ([]*types.Image, error)
Images(filterArgs string, filter string, all bool, withExtraAttrs bool) ([]*types.Image, error)
LookupImage(name string) (*types.ImageInspect, error)
TagImage(imageName, repository, tag string) error
}

View File

@ -248,7 +248,7 @@ func (s *imageRouter) getImagesJSON(ctx context.Context, w http.ResponseWriter,
}
// FIXME: The filter parameter could just be a match filter
images, err := s.backend.Images(r.Form.Get("filters"), r.Form.Get("filter"), httputils.BoolValue(r, "all"))
images, err := s.backend.Images(r.Form.Get("filters"), r.Form.Get("filter"), httputils.BoolValue(r, "all"), false)
if err != nil {
return err
}

View File

@ -95,8 +95,10 @@ type Image struct {
RepoDigests []string
Created int64
Size int64
SharedSize int64
VirtualSize int64
Labels map[string]string
Containers int64
}
// GraphDriverData returns Image's graph driver config info

View File

@ -225,5 +225,6 @@ func (c *imageContext) CreatedAt() string {
func (c *imageContext) Size() string {
c.AddHeader(sizeHeader)
return units.HumanSizeWithPrecision(float64(c.i.Size), 3)
//NOTE: For backward compatibility we need to return VirtualSize
return units.HumanSizeWithPrecision(float64(c.i.VirtualSize), 3)
}

View File

@ -7,6 +7,7 @@ import (
"github.com/docker/docker/api/types"
"github.com/docker/docker/api/types/filters"
"github.com/docker/docker/container"
"github.com/docker/docker/image"
"github.com/docker/docker/layer"
"github.com/docker/docker/reference"
@ -37,7 +38,7 @@ func (daemon *Daemon) Map() map[image.ID]*image.Image {
// filter is a shell glob string applied to repository names. The argument
// named all controls whether all images in the graph are filtered, or just
// the heads.
func (daemon *Daemon) Images(filterArgs, filter string, all bool) ([]*types.Image, error) {
func (daemon *Daemon) Images(filterArgs, filter string, all bool, withExtraAttrs bool) ([]*types.Image, error) {
var (
allImages map[image.ID]*image.Image
err error
@ -83,6 +84,10 @@ func (daemon *Daemon) Images(filterArgs, filter string, all bool) ([]*types.Imag
}
images := []*types.Image{}
var imagesMap map[*image.Image]*types.Image
var layerRefs map[layer.ChainID]int
var allLayers map[layer.ChainID]layer.Layer
var allContainers []*container.Container
var filterTagged bool
if filter != "" {
@ -171,21 +176,80 @@ func (daemon *Daemon) Images(filterArgs, filter string, all bool) ([]*types.Imag
continue
}
if withExtraAttrs {
// lazyly init variables
if len(allContainers) == 0 {
allContainers = daemon.List()
allLayers = daemon.layerStore.Map()
imagesMap = make(map[*image.Image]*types.Image)
layerRefs = make(map[layer.ChainID]int)
}
// Get container count
newImage.Containers = 0
for _, c := range allContainers {
if c.ImageID == id {
newImage.Containers++
}
}
// count layer references
rootFS := *img.RootFS
rootFS.DiffIDs = nil
for _, id := range img.RootFS.DiffIDs {
rootFS.Append(id)
chid := rootFS.ChainID()
layerRefs[chid]++
if _, ok := allLayers[chid]; !ok {
return nil, fmt.Errorf("layer %v was not found (corruption?)", chid)
}
}
imagesMap[img] = newImage
}
images = append(images, newImage)
}
if withExtraAttrs {
// Get Shared and Unique sizes
for img, newImage := range imagesMap {
rootFS := *img.RootFS
rootFS.DiffIDs = nil
newImage.Size = 0
newImage.SharedSize = 0
for _, id := range img.RootFS.DiffIDs {
rootFS.Append(id)
chid := rootFS.ChainID()
diffSize, err := allLayers[chid].DiffSize()
if err != nil {
return nil, err
}
if layerRefs[chid] > 1 {
newImage.SharedSize += diffSize
} else {
newImage.Size += diffSize
}
}
}
}
sort.Sort(sort.Reverse(byCreated(images)))
return images, nil
}
func newImage(image *image.Image, size int64) *types.Image {
func newImage(image *image.Image, virtualSize int64) *types.Image {
newImage := new(types.Image)
newImage.ParentID = image.Parent.String()
newImage.ID = image.ID().String()
newImage.Created = image.Created.Unix()
newImage.Size = size
newImage.VirtualSize = size
newImage.Size = -1
newImage.VirtualSize = virtualSize
newImage.SharedSize = -1
newImage.Containers = -1
if image.Config != nil {
newImage.Labels = image.Config.Labels
}