github.com/containers/podman/v2@v2.2.2-0.20210501105131-c1e07d070c4c/libpod/image/layer_tree.go (about) 1 package image 2 3 import ( 4 "context" 5 6 ociv1 "github.com/opencontainers/image-spec/specs-go/v1" 7 "github.com/pkg/errors" 8 "github.com/sirupsen/logrus" 9 ) 10 11 // layerTree is an internal representation of local layers. 12 type layerTree struct { 13 // nodes is the actual layer tree with layer IDs being keys. 14 nodes map[string]*layerNode 15 // ociCache is a cache for Image.ID -> OCI Image. Translations are done 16 // on-demand. 17 ociCache map[string]*ociv1.Image 18 } 19 20 // node returns a layerNode for the specified layerID. 21 func (t *layerTree) node(layerID string) *layerNode { 22 node, exists := t.nodes[layerID] 23 if !exists { 24 node = &layerNode{} 25 t.nodes[layerID] = node 26 } 27 return node 28 } 29 30 // toOCI returns an OCI image for the specified image. 31 func (t *layerTree) toOCI(ctx context.Context, i *Image) (*ociv1.Image, error) { 32 var err error 33 oci, exists := t.ociCache[i.ID()] 34 if !exists { 35 oci, err = i.ociv1Image(ctx) 36 if err != nil { 37 logrus.Errorf("%v, ignoring the error", err) 38 return nil, nil 39 } 40 t.ociCache[i.ID()] = oci 41 } 42 return oci, err 43 } 44 45 // layerNode is a node in a layerTree. It's ID is the key in a layerTree. 46 type layerNode struct { 47 children []*layerNode 48 images []*Image 49 parent *layerNode 50 } 51 52 // layerTree extracts a layerTree from the layers in the local storage and 53 // relates them to the specified images. 54 func (ir *Runtime) layerTree() (*layerTree, error) { 55 layers, err := ir.store.Layers() 56 if err != nil { 57 return nil, err 58 } 59 60 images, err := ir.GetImages() 61 if err != nil { 62 return nil, err 63 } 64 65 tree := layerTree{ 66 nodes: make(map[string]*layerNode), 67 ociCache: make(map[string]*ociv1.Image), 68 } 69 70 // First build a tree purely based on layer information. 71 for _, layer := range layers { 72 node := tree.node(layer.ID) 73 if layer.Parent == "" { 74 continue 75 } 76 parent := tree.node(layer.Parent) 77 node.parent = parent 78 parent.children = append(parent.children, node) 79 } 80 81 // Now assign the images to each (top) layer. 82 for i := range images { 83 img := images[i] // do not leak loop variable outside the scope 84 topLayer := img.TopLayer() 85 if topLayer == "" { 86 continue 87 } 88 node, exists := tree.nodes[topLayer] 89 if !exists { 90 return nil, errors.Errorf("top layer %s of image %s not found in layer tree", img.TopLayer(), img.ID()) 91 } 92 node.images = append(node.images, img) 93 } 94 95 return &tree, nil 96 } 97 98 // children returns the image IDs of children . Child images are images 99 // with either the same top layer as parent or parent being the true parent 100 // layer. Furthermore, the history of the parent and child images must match 101 // with the parent having one history item less. 102 // If all is true, all images are returned. Otherwise, the first image is 103 // returned. 104 func (t *layerTree) children(ctx context.Context, parent *Image, all bool) ([]string, error) { 105 if parent.TopLayer() == "" { 106 return nil, nil 107 } 108 109 var children []string 110 111 parentNode, exists := t.nodes[parent.TopLayer()] 112 if !exists { 113 return nil, errors.Errorf("layer not found in layer tree: %q", parent.TopLayer()) 114 } 115 116 parentID := parent.ID() 117 parentOCI, err := t.toOCI(ctx, parent) 118 if err != nil { 119 return nil, err 120 } 121 122 // checkParent returns true if child and parent are in such a relation. 123 checkParent := func(child *Image) (bool, error) { 124 if parentID == child.ID() { 125 return false, nil 126 } 127 childOCI, err := t.toOCI(ctx, child) 128 if err != nil { 129 return false, err 130 } 131 // History check. 132 return areParentAndChild(parentOCI, childOCI), nil 133 } 134 135 // addChildrenFrom adds child images of parent to children. Returns 136 // true if any image is a child of parent. 137 addChildrenFromNode := func(node *layerNode) (bool, error) { 138 foundChildren := false 139 for _, childImage := range node.images { 140 isChild, err := checkParent(childImage) 141 if err != nil { 142 return foundChildren, err 143 } 144 if isChild { 145 foundChildren = true 146 children = append(children, childImage.ID()) 147 if all { 148 return foundChildren, nil 149 } 150 } 151 } 152 return foundChildren, nil 153 } 154 155 // First check images where parent's top layer is also the parent 156 // layer. 157 for _, childNode := range parentNode.children { 158 found, err := addChildrenFromNode(childNode) 159 if err != nil { 160 return nil, err 161 } 162 if found && all { 163 return children, nil 164 } 165 } 166 167 // Now check images with the same top layer. 168 if _, err := addChildrenFromNode(parentNode); err != nil { 169 return nil, err 170 } 171 172 return children, nil 173 } 174 175 // parent returns the parent image or nil if no parent image could be found. 176 func (t *layerTree) parent(ctx context.Context, child *Image) (*Image, error) { 177 if child.TopLayer() == "" { 178 return nil, nil 179 } 180 181 node, exists := t.nodes[child.TopLayer()] 182 if !exists { 183 return nil, errors.Errorf("layer not found in layer tree: %q", child.TopLayer()) 184 } 185 186 childOCI, err := t.toOCI(ctx, child) 187 if err != nil { 188 return nil, err 189 } 190 191 // Check images from the parent node (i.e., parent layer) and images 192 // with the same layer (i.e., same top layer). 193 childID := child.ID() 194 images := node.images 195 if node.parent != nil { 196 images = append(images, node.parent.images...) 197 } 198 for _, parent := range images { 199 if parent.ID() == childID { 200 continue 201 } 202 parentOCI, err := t.toOCI(ctx, parent) 203 if err != nil { 204 return nil, err 205 } 206 // History check. 207 if areParentAndChild(parentOCI, childOCI) { 208 return parent, nil 209 } 210 } 211 212 return nil, nil 213 } 214 215 // hasChildrenAndParent returns true if the specified image has children and a 216 // parent. 217 func (t *layerTree) hasChildrenAndParent(ctx context.Context, i *Image) (bool, error) { 218 children, err := t.children(ctx, i, false) 219 if err != nil { 220 return false, err 221 } 222 if len(children) == 0 { 223 return false, nil 224 } 225 parent, err := t.parent(ctx, i) 226 return parent != nil, err 227 }