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>
| ... | ... |
@@ -25,7 +25,7 @@ type containerBackend interface {
|
| 25 | 25 |
type imageBackend interface {
|
| 26 | 26 |
ImageDelete(imageRef string, force, prune bool) ([]types.ImageDelete, error) |
| 27 | 27 |
ImageHistory(imageName string) ([]*types.ImageHistory, error) |
| 28 |
- Images(filterArgs string, filter string, all bool) ([]*types.Image, error) |
|
| 28 |
+ Images(filterArgs string, filter string, all bool, withExtraAttrs bool) ([]*types.Image, error) |
|
| 29 | 29 |
LookupImage(name string) (*types.ImageInspect, error) |
| 30 | 30 |
TagImage(imageName, repository, tag string) error |
| 31 | 31 |
} |
| ... | ... |
@@ -248,7 +248,7 @@ func (s *imageRouter) getImagesJSON(ctx context.Context, w http.ResponseWriter, |
| 248 | 248 |
} |
| 249 | 249 |
|
| 250 | 250 |
// FIXME: The filter parameter could just be a match filter |
| 251 |
- images, err := s.backend.Images(r.Form.Get("filters"), r.Form.Get("filter"), httputils.BoolValue(r, "all"))
|
|
| 251 |
+ images, err := s.backend.Images(r.Form.Get("filters"), r.Form.Get("filter"), httputils.BoolValue(r, "all"), false)
|
|
| 252 | 252 |
if err != nil {
|
| 253 | 253 |
return err |
| 254 | 254 |
} |
| ... | ... |
@@ -225,5 +225,6 @@ func (c *imageContext) CreatedAt() string {
|
| 225 | 225 |
|
| 226 | 226 |
func (c *imageContext) Size() string {
|
| 227 | 227 |
c.AddHeader(sizeHeader) |
| 228 |
- return units.HumanSizeWithPrecision(float64(c.i.Size), 3) |
|
| 228 |
+ //NOTE: For backward compatibility we need to return VirtualSize |
|
| 229 |
+ return units.HumanSizeWithPrecision(float64(c.i.VirtualSize), 3) |
|
| 229 | 230 |
} |
| ... | ... |
@@ -7,6 +7,7 @@ import ( |
| 7 | 7 |
|
| 8 | 8 |
"github.com/docker/docker/api/types" |
| 9 | 9 |
"github.com/docker/docker/api/types/filters" |
| 10 |
+ "github.com/docker/docker/container" |
|
| 10 | 11 |
"github.com/docker/docker/image" |
| 11 | 12 |
"github.com/docker/docker/layer" |
| 12 | 13 |
"github.com/docker/docker/reference" |
| ... | ... |
@@ -37,7 +38,7 @@ func (daemon *Daemon) Map() map[image.ID]*image.Image {
|
| 37 | 37 |
// filter is a shell glob string applied to repository names. The argument |
| 38 | 38 |
// named all controls whether all images in the graph are filtered, or just |
| 39 | 39 |
// the heads. |
| 40 |
-func (daemon *Daemon) Images(filterArgs, filter string, all bool) ([]*types.Image, error) {
|
|
| 40 |
+func (daemon *Daemon) Images(filterArgs, filter string, all bool, withExtraAttrs bool) ([]*types.Image, error) {
|
|
| 41 | 41 |
var ( |
| 42 | 42 |
allImages map[image.ID]*image.Image |
| 43 | 43 |
err error |
| ... | ... |
@@ -83,6 +84,10 @@ func (daemon *Daemon) Images(filterArgs, filter string, all bool) ([]*types.Imag |
| 83 | 83 |
} |
| 84 | 84 |
|
| 85 | 85 |
images := []*types.Image{}
|
| 86 |
+ var imagesMap map[*image.Image]*types.Image |
|
| 87 |
+ var layerRefs map[layer.ChainID]int |
|
| 88 |
+ var allLayers map[layer.ChainID]layer.Layer |
|
| 89 |
+ var allContainers []*container.Container |
|
| 86 | 90 |
|
| 87 | 91 |
var filterTagged bool |
| 88 | 92 |
if filter != "" {
|
| ... | ... |
@@ -171,21 +176,80 @@ func (daemon *Daemon) Images(filterArgs, filter string, all bool) ([]*types.Imag |
| 171 | 171 |
continue |
| 172 | 172 |
} |
| 173 | 173 |
|
| 174 |
+ if withExtraAttrs {
|
|
| 175 |
+ // lazyly init variables |
|
| 176 |
+ if len(allContainers) == 0 {
|
|
| 177 |
+ allContainers = daemon.List() |
|
| 178 |
+ allLayers = daemon.layerStore.Map() |
|
| 179 |
+ imagesMap = make(map[*image.Image]*types.Image) |
|
| 180 |
+ layerRefs = make(map[layer.ChainID]int) |
|
| 181 |
+ } |
|
| 182 |
+ |
|
| 183 |
+ // Get container count |
|
| 184 |
+ newImage.Containers = 0 |
|
| 185 |
+ for _, c := range allContainers {
|
|
| 186 |
+ if c.ImageID == id {
|
|
| 187 |
+ newImage.Containers++ |
|
| 188 |
+ } |
|
| 189 |
+ } |
|
| 190 |
+ |
|
| 191 |
+ // count layer references |
|
| 192 |
+ rootFS := *img.RootFS |
|
| 193 |
+ rootFS.DiffIDs = nil |
|
| 194 |
+ for _, id := range img.RootFS.DiffIDs {
|
|
| 195 |
+ rootFS.Append(id) |
|
| 196 |
+ chid := rootFS.ChainID() |
|
| 197 |
+ layerRefs[chid]++ |
|
| 198 |
+ if _, ok := allLayers[chid]; !ok {
|
|
| 199 |
+ return nil, fmt.Errorf("layer %v was not found (corruption?)", chid)
|
|
| 200 |
+ } |
|
| 201 |
+ } |
|
| 202 |
+ imagesMap[img] = newImage |
|
| 203 |
+ } |
|
| 204 |
+ |
|
| 174 | 205 |
images = append(images, newImage) |
| 175 | 206 |
} |
| 176 | 207 |
|
| 208 |
+ if withExtraAttrs {
|
|
| 209 |
+ // Get Shared and Unique sizes |
|
| 210 |
+ for img, newImage := range imagesMap {
|
|
| 211 |
+ rootFS := *img.RootFS |
|
| 212 |
+ rootFS.DiffIDs = nil |
|
| 213 |
+ |
|
| 214 |
+ newImage.Size = 0 |
|
| 215 |
+ newImage.SharedSize = 0 |
|
| 216 |
+ for _, id := range img.RootFS.DiffIDs {
|
|
| 217 |
+ rootFS.Append(id) |
|
| 218 |
+ chid := rootFS.ChainID() |
|
| 219 |
+ |
|
| 220 |
+ diffSize, err := allLayers[chid].DiffSize() |
|
| 221 |
+ if err != nil {
|
|
| 222 |
+ return nil, err |
|
| 223 |
+ } |
|
| 224 |
+ |
|
| 225 |
+ if layerRefs[chid] > 1 {
|
|
| 226 |
+ newImage.SharedSize += diffSize |
|
| 227 |
+ } else {
|
|
| 228 |
+ newImage.Size += diffSize |
|
| 229 |
+ } |
|
| 230 |
+ } |
|
| 231 |
+ } |
|
| 232 |
+ } |
|
| 233 |
+ |
|
| 177 | 234 |
sort.Sort(sort.Reverse(byCreated(images))) |
| 178 | 235 |
|
| 179 | 236 |
return images, nil |
| 180 | 237 |
} |
| 181 | 238 |
|
| 182 |
-func newImage(image *image.Image, size int64) *types.Image {
|
|
| 239 |
+func newImage(image *image.Image, virtualSize int64) *types.Image {
|
|
| 183 | 240 |
newImage := new(types.Image) |
| 184 | 241 |
newImage.ParentID = image.Parent.String() |
| 185 | 242 |
newImage.ID = image.ID().String() |
| 186 | 243 |
newImage.Created = image.Created.Unix() |
| 187 |
- newImage.Size = size |
|
| 188 |
- newImage.VirtualSize = size |
|
| 244 |
+ newImage.Size = -1 |
|
| 245 |
+ newImage.VirtualSize = virtualSize |
|
| 246 |
+ newImage.SharedSize = -1 |
|
| 247 |
+ newImage.Containers = -1 |
|
| 189 | 248 |
if image.Config != nil {
|
| 190 | 249 |
newImage.Labels = image.Config.Labels |
| 191 | 250 |
} |