github.com/robertojrojas/docker@v1.9.1/graph/history.go (about) 1 package graph 2 3 import ( 4 "fmt" 5 "strings" 6 7 "github.com/docker/docker/api/types" 8 "github.com/docker/docker/image" 9 "github.com/docker/docker/utils" 10 ) 11 12 // WalkHistory calls the handler function for each image in the 13 // provided images lineage starting from immediate parent. 14 func (graph *Graph) WalkHistory(img *image.Image, handler func(image.Image) error) (err error) { 15 currentImg := img 16 for currentImg != nil { 17 if handler != nil { 18 if err := handler(*currentImg); err != nil { 19 return err 20 } 21 } 22 currentImg, err = graph.GetParent(currentImg) 23 if err != nil { 24 return fmt.Errorf("Error while getting parent image: %v", err) 25 } 26 } 27 return nil 28 } 29 30 // depth returns the number of parents for the current image 31 func (graph *Graph) depth(img *image.Image) (int, error) { 32 var ( 33 count = 0 34 parent = img 35 err error 36 ) 37 38 for parent != nil { 39 count++ 40 if parent, err = graph.GetParent(parent); err != nil { 41 return -1, err 42 } 43 } 44 return count, nil 45 } 46 47 // Set the max depth to the aufs default that most 48 // kernels are compiled with 49 // For more information see: http://sourceforge.net/p/aufs/aufs3-standalone/ci/aufs3.12/tree/config.mk 50 const MaxImageDepth = 127 51 52 // CheckDepth returns an error if the depth of an image, as returned 53 // by ImageDepth, is too large to support creating a container from it 54 // on this daemon. 55 func (graph *Graph) CheckDepth(img *image.Image) error { 56 // We add 2 layers to the depth because the container's rw and 57 // init layer add to the restriction 58 depth, err := graph.depth(img) 59 if err != nil { 60 return err 61 } 62 if depth+2 >= MaxImageDepth { 63 return fmt.Errorf("Cannot create container with more than %d parents", MaxImageDepth) 64 } 65 return nil 66 } 67 68 // History returns a slice of ImageHistory structures for the specified image 69 // name by walking the image lineage. 70 func (s *TagStore) History(name string) ([]*types.ImageHistory, error) { 71 foundImage, err := s.LookupImage(name) 72 if err != nil { 73 return nil, err 74 } 75 76 lookupMap := make(map[string][]string) 77 for name, repository := range s.Repositories { 78 for tag, id := range repository { 79 // If the ID already has a reverse lookup, do not update it unless for "latest" 80 if _, exists := lookupMap[id]; !exists { 81 lookupMap[id] = []string{} 82 } 83 lookupMap[id] = append(lookupMap[id], utils.ImageReference(name, tag)) 84 } 85 } 86 87 history := []*types.ImageHistory{} 88 89 err = s.graph.WalkHistory(foundImage, func(img image.Image) error { 90 history = append(history, &types.ImageHistory{ 91 ID: img.ID, 92 Created: img.Created.Unix(), 93 CreatedBy: strings.Join(img.ContainerConfig.Cmd.Slice(), " "), 94 Tags: lookupMap[img.ID], 95 Size: img.Size, 96 Comment: img.Comment, 97 }) 98 return nil 99 }) 100 101 return history, err 102 } 103 104 // GetParent returns the parent image for the specified image. 105 func (graph *Graph) GetParent(img *image.Image) (*image.Image, error) { 106 if img.Parent == "" { 107 return nil, nil 108 } 109 return graph.Get(img.Parent) 110 } 111 112 // GetParentsSize returns the combined size of all parent images. If there is 113 // no parent image or it's unavailable, it returns 0. 114 func (graph *Graph) GetParentsSize(img *image.Image) int64 { 115 parentImage, err := graph.GetParent(img) 116 if err != nil || parentImage == nil { 117 return 0 118 } 119 return parentImage.Size + graph.GetParentsSize(parentImage) 120 }