Handle images which contain no layers

This fixes some of our handling of images which have no layers, i.e.,
those whose TopLayer is set to an empty value.

Signed-off-by: Nalin Dahyabhai <nalin@redhat.com>
This commit is contained in:
Nalin Dahyabhai 2019-06-24 17:59:08 -04:00
parent 8e79de2848
commit 1ebb84b58e
2 changed files with 53 additions and 47 deletions

View File

@ -72,7 +72,11 @@ func printTree(imageInfo *image.InfoImage, layerInfoMap map[string]*image.LayerI
fmt.Printf("Image ID: %s\n", imageInfo.ID[:12]) fmt.Printf("Image ID: %s\n", imageInfo.ID[:12])
fmt.Printf("Tags:\t %s\n", imageInfo.Tags) fmt.Printf("Tags:\t %s\n", imageInfo.Tags)
fmt.Printf("Size:\t %v\n", units.HumanSizeWithPrecision(float64(*size), 4)) fmt.Printf("Size:\t %v\n", units.HumanSizeWithPrecision(float64(*size), 4))
fmt.Printf(fmt.Sprintf("Image Layers\n")) if img.TopLayer() != "" {
fmt.Printf("Image Layers\n")
} else {
fmt.Printf("No Image Layers\n")
}
if !whatRequires { if !whatRequires {
// fill imageInfo with layers associated with image. // fill imageInfo with layers associated with image.

View File

@ -660,11 +660,7 @@ func (i *Image) Size(ctx context.Context) (*uint64, error) {
// DriverData gets the driver data from the store on a layer // DriverData gets the driver data from the store on a layer
func (i *Image) DriverData() (*driver.Data, error) { func (i *Image) DriverData() (*driver.Data, error) {
topLayer, err := i.Layer() return driver.GetDriverData(i.imageruntime.store, i.TopLayer())
if err != nil {
return nil, err
}
return driver.GetDriverData(i.imageruntime.store, topLayer.ID)
} }
// Layer returns the image's top layer // Layer returns the image's top layer
@ -693,13 +689,17 @@ func (i *Image) History(ctx context.Context) ([]*History, error) {
return nil, err return nil, err
} }
// Use our layers list to find images that use one of them as its // Use our layers list to find images that use any of them (or no
// layer, since every base layer is derived from an empty layer) as its
// topmost layer. // topmost layer.
interestingLayers := make(map[string]bool) interestingLayers := make(map[string]bool)
layer, err := i.imageruntime.store.Layer(i.TopLayer()) var layer *storage.Layer
if err != nil { if i.TopLayer() != "" {
if layer, err = i.imageruntime.store.Layer(i.TopLayer()); err != nil {
return nil, err return nil, err
} }
}
interestingLayers[""] = true
for layer != nil { for layer != nil {
interestingLayers[layer.ID] = true interestingLayers[layer.ID] = true
if layer.Parent == "" { if layer.Parent == "" {
@ -795,27 +795,6 @@ func (i *Image) History(ctx context.Context) ([]*History, error) {
return allHistory, nil return allHistory, nil
} }
// historyLayerIDs goes through the images in store and checks if the top layer of an image
// is the same as the parent of topLayerID
func (i *Image) historyLayerIDs(topLayerID string, images []*Image, IDs *[]string) error {
for _, image := range images {
// Get the layer info of topLayerID
layer, err := i.imageruntime.store.Layer(topLayerID)
if err != nil {
return errors.Wrapf(err, "error getting layer info %q", topLayerID)
}
// Check if the parent of layer is equal to the image's top layer
// If so add the image ID to the list of IDs and find the parent of
// the top layer of the image ID added to the list
// Since we are checking for parent, each top layer can only have one parent
if layer.Parent == image.TopLayer() {
*IDs = append(*IDs, image.ID())
return i.historyLayerIDs(image.TopLayer(), images, IDs)
}
}
return nil
}
// Dangling returns a bool if the image is "dangling" // Dangling returns a bool if the image is "dangling"
func (i *Image) Dangling() bool { func (i *Image) Dangling() bool {
return len(i.Names()) == 0 return len(i.Names()) == 0
@ -1143,14 +1122,16 @@ func areParentAndChild(parent, child *imgspecv1.Image) bool {
// GetParent returns the image ID of the parent. Return nil if a parent is not found. // GetParent returns the image ID of the parent. Return nil if a parent is not found.
func (i *Image) GetParent(ctx context.Context) (*Image, error) { func (i *Image) GetParent(ctx context.Context) (*Image, error) {
var childLayer *storage.Layer
images, err := i.imageruntime.GetImages() images, err := i.imageruntime.GetImages()
if err != nil { if err != nil {
return nil, err return nil, err
} }
childLayer, err := i.imageruntime.store.Layer(i.TopLayer()) if i.TopLayer() != "" {
if err != nil { if childLayer, err = i.imageruntime.store.Layer(i.TopLayer()); err != nil {
return nil, err return nil, err
} }
}
// fetch the configuration for the child image // fetch the configuration for the child image
child, err := i.ociv1Image(ctx) child, err := i.ociv1Image(ctx)
if err != nil { if err != nil {
@ -1161,12 +1142,24 @@ func (i *Image) GetParent(ctx context.Context) (*Image, error) {
continue continue
} }
candidateLayer := img.TopLayer() candidateLayer := img.TopLayer()
// as a child, our top layer is either the candidate parent's // as a child, our top layer, if we have one, is either the
// layer, or one that's derived from it, so skip over any // candidate parent's layer, or one that's derived from it, so
// candidate image where we know that isn't the case // skip over any candidate image where we know that isn't the
// case
if childLayer != nil {
// The child has at least one layer, so a parent would
// have a top layer that's either the same as the child's
// top layer or the top layer's recorded parent layer,
// which could be an empty value.
if candidateLayer != childLayer.Parent && candidateLayer != childLayer.ID { if candidateLayer != childLayer.Parent && candidateLayer != childLayer.ID {
continue continue
} }
} else {
// The child has no layers, but the candidate does.
if candidateLayer != "" {
continue
}
}
// fetch the configuration for the candidate image // fetch the configuration for the candidate image
candidate, err := img.ociv1Image(ctx) candidate, err := img.ociv1Image(ctx)
if err != nil { if err != nil {
@ -1204,6 +1197,13 @@ func (i *Image) getChildren(ctx context.Context, max int) ([]string, error) {
if img.ID() == i.ID() { if img.ID() == i.ID() {
continue continue
} }
if img.TopLayer() == "" {
if parentLayer != "" {
// this image has no layers, but we do, so
// it can't be derived from this one
continue
}
} else {
candidateLayer, err := img.Layer() candidateLayer, err := img.Layer()
if err != nil { if err != nil {
return nil, err return nil, err
@ -1213,6 +1213,7 @@ func (i *Image) getChildren(ctx context.Context, max int) ([]string, error) {
if candidateLayer.Parent != parentLayer && candidateLayer.ID != parentLayer { if candidateLayer.Parent != parentLayer && candidateLayer.ID != parentLayer {
continue continue
} }
}
// fetch the configuration for the candidate image // fetch the configuration for the candidate image
candidate, err := img.ociv1Image(ctx) candidate, err := img.ociv1Image(ctx)
if err != nil { if err != nil {
@ -1443,6 +1444,7 @@ func GetLayersMapWithImageInfo(imageruntime *Runtime) (map[string]*LayerInfo, er
if err != nil { if err != nil {
return nil, err return nil, err
} }
layerInfoMap[""] = &LayerInfo{}
for _, img := range imgs { for _, img := range imgs {
e, ok := layerInfoMap[img.TopLayer] e, ok := layerInfoMap[img.TopLayer]
if !ok { if !ok {