mirror of
https://github.com/moby/moby.git
synced 2022-11-09 12:21:53 -05:00
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:
parent
c6db1e9c1b
commit
b717de5153
5 changed files with 74 additions and 7 deletions
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue