2014-08-05 04:50:25 +00:00
|
|
|
package graph
|
|
|
|
|
|
|
|
import (
|
2015-06-05 22:31:10 +00:00
|
|
|
"fmt"
|
2014-08-05 04:50:25 +00:00
|
|
|
"strings"
|
|
|
|
|
2015-04-03 15:31:30 +00:00
|
|
|
"github.com/docker/docker/api/types"
|
2014-08-05 04:50:25 +00:00
|
|
|
"github.com/docker/docker/image"
|
2015-02-27 02:23:50 +00:00
|
|
|
"github.com/docker/docker/utils"
|
2014-08-05 04:50:25 +00:00
|
|
|
)
|
|
|
|
|
2015-06-05 22:31:10 +00:00
|
|
|
// History returns the list of all images used to create this image.
|
|
|
|
func (graph *Graph) History(img *image.Image) ([]*image.Image, error) {
|
|
|
|
var parents []*image.Image
|
|
|
|
if err := graph.WalkHistory(img,
|
|
|
|
func(img *image.Image) error {
|
|
|
|
parents = append(parents, img)
|
|
|
|
return nil
|
|
|
|
},
|
|
|
|
); err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
return parents, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// WalkHistory calls the handler function for each image in the
|
|
|
|
// provided images lineage starting from immediate parent.
|
|
|
|
func (graph *Graph) WalkHistory(img *image.Image, handler func(*image.Image) error) (err error) {
|
|
|
|
currentImg := img
|
|
|
|
for currentImg != nil {
|
|
|
|
if handler != nil {
|
|
|
|
if err := handler(currentImg); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
currentImg, err = graph.GetParent(currentImg)
|
|
|
|
if err != nil {
|
|
|
|
return fmt.Errorf("Error while getting parent image: %v", err)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// depth returns the number of parents for a
|
|
|
|
// current image
|
|
|
|
func (graph *Graph) depth(img *image.Image) (int, error) {
|
|
|
|
var (
|
|
|
|
count = 0
|
|
|
|
parent = img
|
|
|
|
err error
|
|
|
|
)
|
|
|
|
|
|
|
|
for parent != nil {
|
|
|
|
count++
|
|
|
|
parent, err = graph.GetParent(parent)
|
|
|
|
if err != nil {
|
|
|
|
return -1, err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return count, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// Set the max depth to the aufs default that most
|
|
|
|
// kernels are compiled with
|
|
|
|
// For more information see: http://sourceforge.net/p/aufs/aufs3-standalone/ci/aufs3.12/tree/config.mk
|
|
|
|
const MaxImageDepth = 127
|
|
|
|
|
|
|
|
// CheckDepth returns an error if the depth of an image, as returned
|
|
|
|
// by ImageDepth, is too large to support creating a container from it
|
|
|
|
// on this daemon.
|
|
|
|
func (graph *Graph) CheckDepth(img *image.Image) error {
|
|
|
|
// We add 2 layers to the depth because the container's rw and
|
|
|
|
// init layer add to the restriction
|
|
|
|
depth, err := graph.depth(img)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
if depth+2 >= MaxImageDepth {
|
|
|
|
return fmt.Errorf("Cannot create container with more than %d parents", MaxImageDepth)
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2015-04-10 10:55:07 +00:00
|
|
|
func (s *TagStore) History(name string) ([]*types.ImageHistory, error) {
|
2014-08-05 04:50:25 +00:00
|
|
|
foundImage, err := s.LookupImage(name)
|
|
|
|
if err != nil {
|
2015-04-10 10:55:07 +00:00
|
|
|
return nil, err
|
2014-08-05 04:50:25 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
lookupMap := make(map[string][]string)
|
|
|
|
for name, repository := range s.Repositories {
|
|
|
|
for tag, id := range repository {
|
|
|
|
// If the ID already has a reverse lookup, do not update it unless for "latest"
|
|
|
|
if _, exists := lookupMap[id]; !exists {
|
|
|
|
lookupMap[id] = []string{}
|
|
|
|
}
|
2015-02-27 02:23:50 +00:00
|
|
|
lookupMap[id] = append(lookupMap[id], utils.ImageReference(name, tag))
|
2014-08-05 04:50:25 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-04-10 10:55:07 +00:00
|
|
|
history := []*types.ImageHistory{}
|
2015-04-03 15:31:30 +00:00
|
|
|
|
2015-06-05 22:31:10 +00:00
|
|
|
err = s.graph.WalkHistory(foundImage, func(img *image.Image) error {
|
2015-04-10 10:55:07 +00:00
|
|
|
history = append(history, &types.ImageHistory{
|
2015-04-03 15:31:30 +00:00
|
|
|
ID: img.ID,
|
2015-05-15 00:31:34 +00:00
|
|
|
Created: img.Created.Unix(),
|
2015-04-11 00:05:21 +00:00
|
|
|
CreatedBy: strings.Join(img.ContainerConfig.Cmd.Slice(), " "),
|
2015-04-03 15:31:30 +00:00
|
|
|
Tags: lookupMap[img.ID],
|
|
|
|
Size: img.Size,
|
2015-01-04 06:47:01 +00:00
|
|
|
Comment: img.Comment,
|
2015-04-03 15:31:30 +00:00
|
|
|
})
|
2014-08-05 04:50:25 +00:00
|
|
|
return nil
|
|
|
|
})
|
2015-04-03 15:31:30 +00:00
|
|
|
|
2015-04-10 10:55:07 +00:00
|
|
|
return history, err
|
2014-08-05 04:50:25 +00:00
|
|
|
}
|
2015-06-05 22:31:10 +00:00
|
|
|
|
|
|
|
func (graph *Graph) GetParent(img *image.Image) (*image.Image, error) {
|
|
|
|
if img.Parent == "" {
|
|
|
|
return nil, nil
|
|
|
|
}
|
|
|
|
return graph.Get(img.Parent)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (graph *Graph) GetParentsSize(img *image.Image, size int64) int64 {
|
|
|
|
parentImage, err := graph.GetParent(img)
|
|
|
|
if err != nil || parentImage == nil {
|
|
|
|
return size
|
|
|
|
}
|
|
|
|
size += parentImage.Size
|
|
|
|
return graph.GetParentsSize(parentImage, size)
|
|
|
|
}
|