github.com/containers/podman/v2@v2.2.2-0.20210501105131-c1e07d070c4c/libpod/image/image.go (about)

     1  package image
     2  
     3  import (
     4  	"context"
     5  	"encoding/json"
     6  	stderrors "errors"
     7  	"fmt"
     8  	"io"
     9  	"io/ioutil"
    10  	"os"
    11  	"path/filepath"
    12  	"sort"
    13  	"strings"
    14  	"syscall"
    15  	"time"
    16  
    17  	"github.com/containers/common/pkg/retry"
    18  	cp "github.com/containers/image/v5/copy"
    19  	"github.com/containers/image/v5/directory"
    20  	"github.com/containers/image/v5/docker/archive"
    21  	dockerarchive "github.com/containers/image/v5/docker/archive"
    22  	"github.com/containers/image/v5/docker/reference"
    23  	"github.com/containers/image/v5/image"
    24  	"github.com/containers/image/v5/manifest"
    25  	ociarchive "github.com/containers/image/v5/oci/archive"
    26  	"github.com/containers/image/v5/oci/layout"
    27  	"github.com/containers/image/v5/pkg/shortnames"
    28  	is "github.com/containers/image/v5/storage"
    29  	"github.com/containers/image/v5/tarball"
    30  	"github.com/containers/image/v5/transports"
    31  	"github.com/containers/image/v5/transports/alltransports"
    32  	"github.com/containers/image/v5/types"
    33  	"github.com/containers/podman/v2/libpod/driver"
    34  	"github.com/containers/podman/v2/libpod/events"
    35  	"github.com/containers/podman/v2/pkg/inspect"
    36  	"github.com/containers/podman/v2/pkg/registries"
    37  	"github.com/containers/podman/v2/pkg/util"
    38  	"github.com/containers/storage"
    39  	digest "github.com/opencontainers/go-digest"
    40  	imgspecv1 "github.com/opencontainers/image-spec/specs-go/v1"
    41  	ociv1 "github.com/opencontainers/image-spec/specs-go/v1"
    42  	opentracing "github.com/opentracing/opentracing-go"
    43  	"github.com/pkg/errors"
    44  	"github.com/sirupsen/logrus"
    45  )
    46  
    47  // Image is the primary struct for dealing with images
    48  // It is still very much a work in progress
    49  type Image struct {
    50  	// Adding these two structs for now but will cull when we near
    51  	// completion of this library.
    52  	imgRef    types.Image
    53  	imgSrcRef types.ImageSource
    54  	inspect.ImageData
    55  	inspect.ImageResult
    56  	inspectInfo  *types.ImageInspectInfo
    57  	InputName    string
    58  	image        *storage.Image
    59  	imageruntime *Runtime
    60  }
    61  
    62  // Runtime contains the store
    63  type Runtime struct {
    64  	store               storage.Store
    65  	SignaturePolicyPath string
    66  	EventsLogFilePath   string
    67  	EventsLogger        string
    68  	Eventer             events.Eventer
    69  }
    70  
    71  // InfoImage keep information of Image along with all associated layers
    72  type InfoImage struct {
    73  	// ID of image
    74  	ID string
    75  	// Tags of image
    76  	Tags []string
    77  	// Layers stores all layers of image.
    78  	Layers []LayerInfo
    79  }
    80  
    81  const maxRetry = 3
    82  
    83  // ImageFilter is a function to determine whether a image is included
    84  // in command output. Images to be outputted are tested using the function.
    85  // A true return will include the image, a false return will exclude it.
    86  type ImageFilter func(*Image) bool //nolint
    87  
    88  // ErrRepoTagNotFound is the error returned when the image id given doesn't match a rep tag in store
    89  var ErrRepoTagNotFound = stderrors.New("unable to match user input to any specific repotag")
    90  
    91  // ErrImageIsBareList is the error returned when the image is just a list or index
    92  var ErrImageIsBareList = stderrors.New("image contains a manifest list or image index, but no runnable image")
    93  
    94  // NewImageRuntimeFromStore creates an ImageRuntime based on a provided store
    95  func NewImageRuntimeFromStore(store storage.Store) *Runtime {
    96  	return &Runtime{
    97  		store: store,
    98  	}
    99  }
   100  
   101  // NewImageRuntimeFromOptions creates an Image Runtime including the store given
   102  // store options
   103  func NewImageRuntimeFromOptions(options storage.StoreOptions) (*Runtime, error) {
   104  	store, err := setStore(options)
   105  	if err != nil {
   106  		return nil, err
   107  	}
   108  	return NewImageRuntimeFromStore(store), nil
   109  }
   110  
   111  func setStore(options storage.StoreOptions) (storage.Store, error) {
   112  	store, err := storage.GetStore(options)
   113  	if err != nil {
   114  		return nil, err
   115  	}
   116  	is.Transport.SetStore(store)
   117  	return store, nil
   118  }
   119  
   120  // newImage creates a new image object given an "input name" and a storage.Image
   121  func (ir *Runtime) newImage(inputName string, img *storage.Image) *Image {
   122  	return &Image{
   123  		InputName:    inputName,
   124  		imageruntime: ir,
   125  		image:        img,
   126  	}
   127  }
   128  
   129  // newFromStorage creates a new image object from a storage.Image. Its "input name" will be its ID.
   130  func (ir *Runtime) newFromStorage(img *storage.Image) *Image {
   131  	return ir.newImage(img.ID, img)
   132  }
   133  
   134  // NewFromLocal creates a new image object that is intended
   135  // to only deal with local images already in the store (or
   136  // its aliases)
   137  func (ir *Runtime) NewFromLocal(name string) (*Image, error) {
   138  	updatedInputName, localImage, err := ir.getLocalImage(name)
   139  	if err != nil {
   140  		return nil, err
   141  	}
   142  	return ir.newImage(updatedInputName, localImage), nil
   143  }
   144  
   145  // New creates a new image object where the image could be local
   146  // or remote
   147  func (ir *Runtime) New(ctx context.Context, name, signaturePolicyPath, authfile string, writer io.Writer, dockeroptions *DockerRegistryOptions, signingoptions SigningOptions, label *string, pullType util.PullType) (*Image, error) {
   148  	span, _ := opentracing.StartSpanFromContext(ctx, "newImage")
   149  	span.SetTag("type", "runtime")
   150  	defer span.Finish()
   151  
   152  	// We don't know if the image is local or not ... check local first
   153  	if pullType != util.PullImageAlways {
   154  		newImage, err := ir.NewFromLocal(name)
   155  		if err == nil {
   156  			return newImage, nil
   157  		} else if pullType == util.PullImageNever {
   158  			return nil, err
   159  		}
   160  	}
   161  
   162  	// The image is not local
   163  	if signaturePolicyPath == "" {
   164  		signaturePolicyPath = ir.SignaturePolicyPath
   165  	}
   166  	imageName, err := ir.pullImageFromHeuristicSource(ctx, name, writer, authfile, signaturePolicyPath, signingoptions, dockeroptions, &retry.RetryOptions{MaxRetry: maxRetry}, label)
   167  	if err != nil {
   168  		return nil, err
   169  	}
   170  
   171  	newImage, err := ir.NewFromLocal(imageName[0])
   172  	if err != nil {
   173  		return nil, errors.Wrapf(err, "error retrieving local image after pulling %s", name)
   174  	}
   175  	return newImage, nil
   176  }
   177  
   178  // SaveImages stores one more images in a multi-image archive.
   179  // Note that only `docker-archive` supports storing multiple
   180  // image.
   181  func (ir *Runtime) SaveImages(ctx context.Context, namesOrIDs []string, format string, outputFile string, quiet, removeSignatures bool) (finalErr error) {
   182  	if format != DockerArchive {
   183  		return errors.Errorf("multi-image archives are only supported in in the %q format", DockerArchive)
   184  	}
   185  
   186  	sys := GetSystemContext("", "", false)
   187  
   188  	archWriter, err := archive.NewWriter(sys, outputFile)
   189  	if err != nil {
   190  		return err
   191  	}
   192  	defer func() {
   193  		err := archWriter.Close()
   194  		if err == nil {
   195  			return
   196  		}
   197  		if finalErr == nil {
   198  			finalErr = err
   199  			return
   200  		}
   201  		finalErr = errors.Wrap(finalErr, err.Error())
   202  	}()
   203  
   204  	// Decide whether c/image's progress bars should use stderr or stdout.
   205  	// Use stderr in case we need to be quiet or if the output is set to
   206  	// stdout.  If the output is set of stdout, any log message there would
   207  	// corrupt the tarfile.
   208  	writer := os.Stdout
   209  	if quiet {
   210  		writer = os.Stderr
   211  	}
   212  
   213  	// extend an image with additional tags
   214  	type imageData struct {
   215  		*Image
   216  		tags []reference.NamedTagged
   217  	}
   218  
   219  	// Look up the images (and their tags) in the local storage.
   220  	imageMap := make(map[string]*imageData) // to group tags for an image
   221  	imageQueue := []string{}                // to preserve relative image order
   222  	for _, nameOrID := range namesOrIDs {
   223  		// Look up the name or ID in the local image storage.
   224  		localImage, err := ir.NewFromLocal(nameOrID)
   225  		if err != nil {
   226  			return err
   227  		}
   228  		id := localImage.ID()
   229  
   230  		iData, exists := imageMap[id]
   231  		if !exists {
   232  			imageQueue = append(imageQueue, id)
   233  			iData = &imageData{Image: localImage}
   234  			imageMap[id] = iData
   235  		}
   236  
   237  		// Unless we referred to an ID, add the input as a tag.
   238  		if !strings.HasPrefix(id, nameOrID) {
   239  			tag, err := NormalizedTag(nameOrID)
   240  			if err != nil {
   241  				return err
   242  			}
   243  			refTagged, isTagged := tag.(reference.NamedTagged)
   244  			if isTagged {
   245  				iData.tags = append(iData.tags, refTagged)
   246  			}
   247  		}
   248  	}
   249  
   250  	policyContext, err := getPolicyContext(sys)
   251  	if err != nil {
   252  		return err
   253  	}
   254  	defer func() {
   255  		if err := policyContext.Destroy(); err != nil {
   256  			logrus.Errorf("failed to destroy policy context: %q", err)
   257  		}
   258  	}()
   259  
   260  	// Now copy the images one-by-one.
   261  	for _, id := range imageQueue {
   262  		dest, err := archWriter.NewReference(nil)
   263  		if err != nil {
   264  			return err
   265  		}
   266  
   267  		img := imageMap[id]
   268  		copyOptions := getCopyOptions(sys, writer, nil, nil, SigningOptions{RemoveSignatures: removeSignatures}, "", img.tags)
   269  		copyOptions.DestinationCtx.SystemRegistriesConfPath = registries.SystemRegistriesConfPath()
   270  
   271  		// For copying, we need a source reference that we can create
   272  		// from the image.
   273  		src, err := is.Transport.NewStoreReference(img.imageruntime.store, nil, id)
   274  		if err != nil {
   275  			return errors.Wrapf(err, "error getting source imageReference for %q", img.InputName)
   276  		}
   277  		_, err = cp.Image(ctx, policyContext, dest, src, copyOptions)
   278  		if err != nil {
   279  			return err
   280  		}
   281  	}
   282  
   283  	return nil
   284  }
   285  
   286  // LoadAllImagesFromDockerArchive loads all images from the docker archive that
   287  // fileName points to.
   288  func (ir *Runtime) LoadAllImagesFromDockerArchive(ctx context.Context, fileName string, signaturePolicyPath string, writer io.Writer) ([]*Image, error) {
   289  	if signaturePolicyPath == "" {
   290  		signaturePolicyPath = ir.SignaturePolicyPath
   291  	}
   292  
   293  	sc := GetSystemContext(signaturePolicyPath, "", false)
   294  	reader, err := archive.NewReader(sc, fileName)
   295  	if err != nil {
   296  		return nil, err
   297  	}
   298  
   299  	defer func() {
   300  		if err := reader.Close(); err != nil {
   301  			logrus.Errorf(err.Error())
   302  		}
   303  	}()
   304  
   305  	refLists, err := reader.List()
   306  	if err != nil {
   307  		return nil, err
   308  	}
   309  
   310  	refPairs := []pullRefPair{}
   311  	for _, refList := range refLists {
   312  		for _, ref := range refList {
   313  			pairs, err := ir.getPullRefPairsFromDockerArchiveReference(ctx, reader, ref, sc)
   314  			if err != nil {
   315  				return nil, err
   316  			}
   317  			refPairs = append(refPairs, pairs...)
   318  		}
   319  	}
   320  
   321  	goal := pullGoal{
   322  		pullAllPairs: true,
   323  		refPairs:     refPairs,
   324  	}
   325  
   326  	defer goal.cleanUp()
   327  	imageNames, err := ir.doPullImage(ctx, sc, goal, writer, SigningOptions{}, &DockerRegistryOptions{}, &retry.RetryOptions{}, nil)
   328  	if err != nil {
   329  		return nil, err
   330  	}
   331  
   332  	newImages := make([]*Image, 0, len(imageNames))
   333  	for _, name := range imageNames {
   334  		newImage, err := ir.NewFromLocal(name)
   335  		if err != nil {
   336  			return nil, errors.Wrapf(err, "error retrieving local image after pulling %s", name)
   337  		}
   338  		newImages = append(newImages, newImage)
   339  	}
   340  	ir.newImageEvent(events.LoadFromArchive, "")
   341  	return newImages, nil
   342  }
   343  
   344  // LoadFromArchiveReference creates a new image object for images pulled from a tar archive and the like (podman load)
   345  // This function is needed because it is possible for a tar archive to have multiple tags for one image
   346  func (ir *Runtime) LoadFromArchiveReference(ctx context.Context, srcRef types.ImageReference, signaturePolicyPath string, writer io.Writer) ([]*Image, error) {
   347  	if signaturePolicyPath == "" {
   348  		signaturePolicyPath = ir.SignaturePolicyPath
   349  	}
   350  
   351  	imageNames, err := ir.pullImageFromReference(ctx, srcRef, writer, "", signaturePolicyPath, SigningOptions{}, &DockerRegistryOptions{}, &retry.RetryOptions{})
   352  	if err != nil {
   353  		return nil, errors.Wrapf(err, "unable to pull %s", transports.ImageName(srcRef))
   354  	}
   355  
   356  	newImages := make([]*Image, 0, len(imageNames))
   357  	for _, name := range imageNames {
   358  		newImage, err := ir.NewFromLocal(name)
   359  		if err != nil {
   360  			return nil, errors.Wrapf(err, "error retrieving local image after pulling %s", name)
   361  		}
   362  		newImages = append(newImages, newImage)
   363  	}
   364  	ir.newImageEvent(events.LoadFromArchive, "")
   365  	return newImages, nil
   366  }
   367  
   368  // Shutdown closes down the storage and require a bool arg as to
   369  // whether it should do so forcibly.
   370  func (ir *Runtime) Shutdown(force bool) error {
   371  	_, err := ir.store.Shutdown(force)
   372  	return err
   373  }
   374  
   375  // GetImagesWithFilters gets images with a series of filters applied
   376  func (ir *Runtime) GetImagesWithFilters(filters []string) ([]*Image, error) {
   377  	filterFuncs, err := ir.createFilterFuncs(filters, nil)
   378  	if err != nil {
   379  		return nil, err
   380  	}
   381  	images, err := ir.GetImages()
   382  	if err != nil {
   383  		return nil, err
   384  	}
   385  	return FilterImages(images, filterFuncs), nil
   386  }
   387  
   388  func (i *Image) reloadImage() error {
   389  	newImage, err := i.imageruntime.getImage(i.ID())
   390  	if err != nil {
   391  		return errors.Wrapf(err, "unable to reload image")
   392  	}
   393  	i.image = newImage
   394  	return nil
   395  }
   396  
   397  // stringSha256 strips sha256 from user input
   398  func stripSha256(name string) string {
   399  	if strings.HasPrefix(name, "sha256:") && len(name) > 7 {
   400  		return name[7:]
   401  	}
   402  	return name
   403  }
   404  
   405  // getLocalImage resolves an unknown input describing an image and
   406  // returns an updated input name, and a storage.Image, or an error. It is used by NewFromLocal.
   407  func (ir *Runtime) getLocalImage(inputName string) (string, *storage.Image, error) {
   408  	imageError := fmt.Sprintf("unable to find '%s' in local storage", inputName)
   409  	if inputName == "" {
   410  		return "", nil, errors.Errorf("input name is blank")
   411  	}
   412  
   413  	// Check if the input name has a transport and if so strip it
   414  	dest, err := alltransports.ParseImageName(inputName)
   415  	if err == nil && dest.DockerReference() != nil {
   416  		inputName = dest.DockerReference().String()
   417  	}
   418  
   419  	// Early check for fully-qualified images and (short) IDs.
   420  	img, err := ir.store.Image(stripSha256(inputName))
   421  	if err == nil {
   422  		return inputName, img, nil
   423  	}
   424  
   425  	// Note that it's crucial to first decompose the image and check if
   426  	// it's a fully-qualified one or a "short name".  The latter requires
   427  	// some normalization with search registries and the
   428  	// "localhost/prefix".
   429  	decomposedImage, err := decompose(inputName)
   430  	if err != nil {
   431  		// We may have a storage reference.  We can't parse it to a
   432  		// reference before. Otherwise, we'd normalize "alpine" to
   433  		// "docker.io/library/alpine:latest" which would break the
   434  		// order in which we should query local images below.
   435  		if ref, err := is.Transport.ParseStoreReference(ir.store, inputName); err == nil {
   436  			img, err = is.Transport.GetStoreImage(ir.store, ref)
   437  			if err == nil {
   438  				return inputName, img, nil
   439  			}
   440  		}
   441  		return "", nil, err
   442  	}
   443  
   444  	// The specified image is fully qualified, so it doesn't exist in the
   445  	// storage.
   446  	if decomposedImage.hasRegistry {
   447  		// However ... we may still need to normalize to docker.io:
   448  		// `docker.io/foo` -> `docker.io/library/foo`
   449  		if ref, err := is.Transport.ParseStoreReference(ir.store, inputName); err == nil {
   450  			img, err = is.Transport.GetStoreImage(ir.store, ref)
   451  			if err == nil {
   452  				return inputName, img, nil
   453  			}
   454  		}
   455  		return "", nil, errors.Wrapf(ErrNoSuchImage, imageError)
   456  	}
   457  
   458  	sys := &types.SystemContext{
   459  		SystemRegistriesConfPath: registries.SystemRegistriesConfPath(),
   460  	}
   461  
   462  	candidates, err := shortnames.ResolveLocally(sys, inputName)
   463  	if err != nil {
   464  		return "", nil, err
   465  	}
   466  
   467  	for _, candidate := range candidates {
   468  		img, err := ir.store.Image(candidate.String())
   469  		if err == nil {
   470  			return candidate.String(), img, nil
   471  		}
   472  	}
   473  
   474  	// Backwards compat: normalize to docker.io as some users may very well
   475  	// rely on that.
   476  	ref, err := is.Transport.ParseStoreReference(ir.store, inputName)
   477  	if err == nil {
   478  		img, err = is.Transport.GetStoreImage(ir.store, ref)
   479  		if err == nil {
   480  			return inputName, img, nil
   481  		}
   482  	}
   483  
   484  	// Last resort: look at the repotags of all images and try to find a
   485  	// match.
   486  	images, err := ir.GetImages()
   487  	if err != nil {
   488  		return "", nil, err
   489  	}
   490  
   491  	decomposedImage, err = decompose(inputName)
   492  	if err != nil {
   493  		return "", nil, err
   494  	}
   495  	repoImage, err := findImageInRepotags(decomposedImage, images)
   496  	if err == nil {
   497  		return inputName, repoImage, nil
   498  	}
   499  
   500  	return "", nil, errors.Wrapf(ErrNoSuchImage, err.Error())
   501  }
   502  
   503  // ID returns the image ID as a string
   504  func (i *Image) ID() string {
   505  	return i.image.ID
   506  }
   507  
   508  // IsReadOnly returns whether the image ID comes from a local store
   509  func (i *Image) IsReadOnly() bool {
   510  	return i.image.ReadOnly
   511  }
   512  
   513  // Digest returns the image's digest
   514  func (i *Image) Digest() digest.Digest {
   515  	return i.image.Digest
   516  }
   517  
   518  // Digests returns the image's digests
   519  func (i *Image) Digests() []digest.Digest {
   520  	return i.image.Digests
   521  }
   522  
   523  // GetManifest returns the image's manifest as a byte array
   524  // and manifest type as a string.
   525  func (i *Image) GetManifest(ctx context.Context, instanceDigest *digest.Digest) ([]byte, string, error) {
   526  	imgSrcRef, err := i.toImageSourceRef(ctx)
   527  	if err != nil {
   528  		return nil, "", err
   529  	}
   530  	return imgSrcRef.GetManifest(ctx, instanceDigest)
   531  }
   532  
   533  // Manifest returns the image's manifest as a byte array
   534  // and manifest type as a string.
   535  func (i *Image) Manifest(ctx context.Context) ([]byte, string, error) {
   536  	imgRef, err := i.toImageRef(ctx)
   537  	if err != nil {
   538  		return nil, "", err
   539  	}
   540  	return imgRef.Manifest(ctx)
   541  }
   542  
   543  // Names returns a string array of names associated with the image, which may be a mixture of tags and digests
   544  func (i *Image) Names() []string {
   545  	return i.image.Names
   546  }
   547  
   548  // NamesHistory returns a string array of names previously associated with the
   549  // image, which may be a mixture of tags and digests
   550  func (i *Image) NamesHistory() []string {
   551  	if len(i.image.Names) > 0 && len(i.image.NamesHistory) > 0 &&
   552  		// We compare the latest (time-referenced) tags for equality and skip
   553  		// it in the history if they match to not display them twice.  We have
   554  		// to compare like this, because `i.image.Names` (latest last) gets
   555  		// appended on retag, whereas `i.image.NamesHistory` gets prepended
   556  		// (latest first)
   557  		i.image.Names[len(i.image.Names)-1] == i.image.NamesHistory[0] {
   558  		return i.image.NamesHistory[1:]
   559  	}
   560  	return i.image.NamesHistory
   561  }
   562  
   563  // RepoTags returns a string array of repotags associated with the image
   564  func (i *Image) RepoTags() ([]string, error) {
   565  	var repoTags []string
   566  	for _, name := range i.Names() {
   567  		named, err := reference.ParseNormalizedNamed(name)
   568  		if err != nil {
   569  			return nil, err
   570  		}
   571  		if tagged, isTagged := named.(reference.NamedTagged); isTagged {
   572  			repoTags = append(repoTags, tagged.String())
   573  		}
   574  	}
   575  	return repoTags, nil
   576  }
   577  
   578  // RepoDigests returns a string array of repodigests associated with the image
   579  func (i *Image) RepoDigests() ([]string, error) {
   580  	var repoDigests []string
   581  	added := make(map[string]struct{})
   582  
   583  	for _, name := range i.Names() {
   584  		for _, imageDigest := range append(i.Digests(), i.Digest()) {
   585  			if imageDigest == "" {
   586  				continue
   587  			}
   588  
   589  			named, err := reference.ParseNormalizedNamed(name)
   590  			if err != nil {
   591  				return nil, err
   592  			}
   593  
   594  			canonical, err := reference.WithDigest(reference.TrimNamed(named), imageDigest)
   595  			if err != nil {
   596  				return nil, err
   597  			}
   598  
   599  			if _, alreadyInList := added[canonical.String()]; !alreadyInList {
   600  				repoDigests = append(repoDigests, canonical.String())
   601  				added[canonical.String()] = struct{}{}
   602  			}
   603  		}
   604  	}
   605  	sort.Strings(repoDigests)
   606  	return repoDigests, nil
   607  }
   608  
   609  // Created returns the time the image was created
   610  func (i *Image) Created() time.Time {
   611  	return i.image.Created
   612  }
   613  
   614  // TopLayer returns the top layer id as a string
   615  func (i *Image) TopLayer() string {
   616  	return i.image.TopLayer
   617  }
   618  
   619  // Remove an image; container removal for the image must be done
   620  // outside the context of images
   621  // TODO: the force param does nothing as of now. Need to move container
   622  // handling logic here eventually.
   623  func (i *Image) Remove(ctx context.Context, force bool) error {
   624  	parent, err := i.GetParent(ctx)
   625  	if err != nil {
   626  		logrus.Warnf("error determining parent of image: %v, ignoring the error", err)
   627  		parent = nil
   628  	}
   629  	if _, err := i.imageruntime.store.DeleteImage(i.ID(), true); err != nil {
   630  		return err
   631  	}
   632  	i.newImageEvent(events.Remove)
   633  	for parent != nil {
   634  		nextParent, err := parent.GetParent(ctx)
   635  		if err != nil {
   636  			return err
   637  		}
   638  		children, err := parent.GetChildren(ctx)
   639  		if err != nil {
   640  			return err
   641  		}
   642  		// Do not remove if image is a base image and is not untagged, or if
   643  		// the image has more children.
   644  		if len(children) > 0 || len(parent.Names()) > 0 {
   645  			return nil
   646  		}
   647  		id := parent.ID()
   648  		if _, err := i.imageruntime.store.DeleteImage(id, true); err != nil {
   649  			logrus.Debugf("unable to remove intermediate image %q: %v", id, err)
   650  		} else {
   651  			fmt.Println(id)
   652  		}
   653  		parent = nextParent
   654  	}
   655  	return nil
   656  }
   657  
   658  // getImage retrieves an image matching the given name or hash from system
   659  // storage
   660  // If no matching image can be found, an error is returned
   661  func (ir *Runtime) getImage(image string) (*storage.Image, error) {
   662  	var img *storage.Image
   663  	ref, err := is.Transport.ParseStoreReference(ir.store, image)
   664  	if err == nil {
   665  		img, err = is.Transport.GetStoreImage(ir.store, ref)
   666  	}
   667  	if err != nil {
   668  		img2, err2 := ir.store.Image(image)
   669  		if err2 != nil {
   670  			if ref == nil {
   671  				return nil, errors.Wrapf(err, "error parsing reference to image %q", image)
   672  			}
   673  			return nil, errors.Wrapf(err, "unable to locate image %q", image)
   674  		}
   675  		img = img2
   676  	}
   677  	return img, nil
   678  }
   679  
   680  func (ir *Runtime) ImageNames(id string) ([]string, error) {
   681  	myImage, err := ir.getImage(id)
   682  	if err != nil {
   683  		return nil, errors.Wrapf(err, "error getting image %s ", id)
   684  	}
   685  	return myImage.Names, nil
   686  }
   687  
   688  // GetImages retrieves all images present in storage
   689  func (ir *Runtime) GetImages() ([]*Image, error) {
   690  	return ir.getImages(false)
   691  }
   692  
   693  // GetRWImages retrieves all read/write images present in storage
   694  func (ir *Runtime) GetRWImages() ([]*Image, error) {
   695  	return ir.getImages(true)
   696  }
   697  
   698  // getImages retrieves all images present in storage
   699  func (ir *Runtime) getImages(rwOnly bool) ([]*Image, error) {
   700  	images, err := ir.store.Images()
   701  	if err != nil {
   702  		return nil, err
   703  	}
   704  	newImages := []*Image{}
   705  	for _, i := range images {
   706  		if rwOnly && i.ReadOnly {
   707  			continue
   708  		}
   709  		// iterating over these, be careful to not iterate on the literal
   710  		// pointer.
   711  		image := i
   712  		img := ir.newFromStorage(&image)
   713  		newImages = append(newImages, img)
   714  	}
   715  	return newImages, nil
   716  }
   717  
   718  // getImageDigest creates an image object and uses the hex value of the digest as the image ID
   719  // for parsing the store reference
   720  func getImageDigest(ctx context.Context, src types.ImageReference, sc *types.SystemContext) (string, error) {
   721  	newImg, err := src.NewImage(ctx, sc)
   722  	if err != nil {
   723  		return "", err
   724  	}
   725  	defer func() {
   726  		if err := newImg.Close(); err != nil {
   727  			logrus.Errorf("failed to close image: %q", err)
   728  		}
   729  	}()
   730  	imageDigest := newImg.ConfigInfo().Digest
   731  	if err = imageDigest.Validate(); err != nil {
   732  		return "", errors.Wrapf(err, "error getting config info")
   733  	}
   734  	return "@" + imageDigest.Hex(), nil
   735  }
   736  
   737  // NormalizedTag returns the canonical version of tag for use in Image.Names()
   738  func NormalizedTag(tag string) (reference.Named, error) {
   739  	decomposedTag, err := decompose(tag)
   740  	if err != nil {
   741  		return nil, err
   742  	}
   743  	// If the input doesn't specify a registry, set the registry to localhost
   744  	var ref reference.Named
   745  	if !decomposedTag.hasRegistry {
   746  		ref, err = decomposedTag.referenceWithRegistry(DefaultLocalRegistry)
   747  		if err != nil {
   748  			return nil, err
   749  		}
   750  	} else {
   751  		ref, err = decomposedTag.normalizedReference()
   752  		if err != nil {
   753  			return nil, err
   754  		}
   755  	}
   756  	// If the input does not have a tag, we need to add one (latest)
   757  	ref = reference.TagNameOnly(ref)
   758  	return ref, nil
   759  }
   760  
   761  // TagImage adds a tag to the given image
   762  func (i *Image) TagImage(tag string) error {
   763  	if err := i.reloadImage(); err != nil {
   764  		return err
   765  	}
   766  	ref, err := NormalizedTag(tag)
   767  	if err != nil {
   768  		return err
   769  	}
   770  	tags := i.Names()
   771  	if util.StringInSlice(ref.String(), tags) {
   772  		return nil
   773  	}
   774  	tags = append(tags, ref.String())
   775  	if err := i.imageruntime.store.SetNames(i.ID(), tags); err != nil {
   776  		return err
   777  	}
   778  	if err := i.reloadImage(); err != nil {
   779  		return err
   780  	}
   781  	i.newImageEvent(events.Tag)
   782  	return nil
   783  }
   784  
   785  // UntagImage removes the specified tag from the image.
   786  // If the tag does not exist, ErrNoSuchTag is returned.
   787  func (i *Image) UntagImage(tag string) error {
   788  	if err := i.reloadImage(); err != nil {
   789  		return err
   790  	}
   791  
   792  	// Normalize the tag as we do with TagImage.
   793  	ref, err := NormalizedTag(tag)
   794  	if err != nil {
   795  		return err
   796  	}
   797  	tag = ref.String()
   798  
   799  	var newTags []string
   800  	tags := i.Names()
   801  	if !util.StringInSlice(tag, tags) {
   802  		return errors.Wrapf(ErrNoSuchTag, "%q", tag)
   803  	}
   804  	for _, t := range tags {
   805  		if tag != t {
   806  			newTags = append(newTags, t)
   807  		}
   808  	}
   809  	if err := i.imageruntime.store.SetNames(i.ID(), newTags); err != nil {
   810  		return err
   811  	}
   812  	if err := i.reloadImage(); err != nil {
   813  		return err
   814  	}
   815  	i.newImageEvent(events.Untag)
   816  	return nil
   817  }
   818  
   819  // PushImageToHeuristicDestination pushes the given image to "destination", which is heuristically parsed.
   820  // Use PushImageToReference if the destination is known precisely.
   821  func (i *Image) PushImageToHeuristicDestination(ctx context.Context, destination, manifestMIMEType, authFile, digestFile, signaturePolicyPath string, writer io.Writer, forceCompress bool, signingOptions SigningOptions, dockerRegistryOptions *DockerRegistryOptions, additionalDockerArchiveTags []reference.NamedTagged) error {
   822  	if destination == "" {
   823  		return errors.Wrapf(syscall.EINVAL, "destination image name must be specified")
   824  	}
   825  
   826  	// Get the destination Image Reference
   827  	dest, err := alltransports.ParseImageName(destination)
   828  	if err != nil {
   829  		if hasTransport(destination) {
   830  			return errors.Wrapf(err, "error getting destination imageReference for %q", destination)
   831  		}
   832  		// Try adding the images default transport
   833  		destination2 := DefaultTransport + destination
   834  		dest, err = alltransports.ParseImageName(destination2)
   835  		if err != nil {
   836  			return err
   837  		}
   838  	}
   839  	return i.PushImageToReference(ctx, dest, manifestMIMEType, authFile, digestFile, signaturePolicyPath, writer, forceCompress, signingOptions, dockerRegistryOptions, additionalDockerArchiveTags)
   840  }
   841  
   842  // PushImageToReference pushes the given image to a location described by the given path
   843  func (i *Image) PushImageToReference(ctx context.Context, dest types.ImageReference, manifestMIMEType, authFile, digestFile, signaturePolicyPath string, writer io.Writer, forceCompress bool, signingOptions SigningOptions, dockerRegistryOptions *DockerRegistryOptions, additionalDockerArchiveTags []reference.NamedTagged) error {
   844  	sc := GetSystemContext(signaturePolicyPath, authFile, forceCompress)
   845  	sc.BlobInfoCacheDir = filepath.Join(i.imageruntime.store.GraphRoot(), "cache")
   846  
   847  	policyContext, err := getPolicyContext(sc)
   848  	if err != nil {
   849  		return err
   850  	}
   851  	defer func() {
   852  		if err := policyContext.Destroy(); err != nil {
   853  			logrus.Errorf("failed to destroy policy context: %q", err)
   854  		}
   855  	}()
   856  
   857  	// Look up the source image, expecting it to be in local storage
   858  	src, err := is.Transport.ParseStoreReference(i.imageruntime.store, i.ID())
   859  	if err != nil {
   860  		return errors.Wrapf(err, "error getting source imageReference for %q", i.InputName)
   861  	}
   862  	copyOptions := getCopyOptions(sc, writer, nil, dockerRegistryOptions, signingOptions, manifestMIMEType, additionalDockerArchiveTags)
   863  	copyOptions.DestinationCtx.SystemRegistriesConfPath = registries.SystemRegistriesConfPath() // FIXME: Set this more globally.  Probably no reason not to have it in every types.SystemContext, and to compute the value just once in one place.
   864  	// Copy the image to the remote destination
   865  	manifestBytes, err := cp.Image(ctx, policyContext, dest, src, copyOptions)
   866  	if err != nil {
   867  		return errors.Wrapf(err, "error copying image to the remote destination")
   868  	}
   869  	digest, err := manifest.Digest(manifestBytes)
   870  	if err != nil {
   871  		return errors.Wrapf(err, "error computing digest of manifest of new image %q", transports.ImageName(dest))
   872  	}
   873  
   874  	logrus.Debugf("Successfully pushed %s with digest %s", transports.ImageName(dest), digest.String())
   875  
   876  	if digestFile != "" {
   877  		if err = ioutil.WriteFile(digestFile, []byte(digest.String()), 0644); err != nil {
   878  			return errors.Wrapf(err, "failed to write digest to file %q", digestFile)
   879  		}
   880  	}
   881  	i.newImageEvent(events.Push)
   882  	return nil
   883  }
   884  
   885  // MatchesID returns a bool based on if the input id
   886  // matches the image's id
   887  // TODO: This isn't used anywhere, so remove it
   888  func (i *Image) MatchesID(id string) bool {
   889  	return strings.HasPrefix(i.ID(), id)
   890  }
   891  
   892  // ToImageRef returns an image reference type from an image
   893  // TODO: Hopefully we can remove this exported function for mheon
   894  func (i *Image) ToImageRef(ctx context.Context) (types.Image, error) {
   895  	return i.toImageRef(ctx)
   896  }
   897  
   898  // toImageSourceRef returns an ImageSource Reference type from an image
   899  func (i *Image) toImageSourceRef(ctx context.Context) (types.ImageSource, error) {
   900  	if i == nil {
   901  		return nil, errors.Errorf("cannot convert nil image to image source reference")
   902  	}
   903  	if i.imgSrcRef == nil {
   904  		ref, err := is.Transport.ParseStoreReference(i.imageruntime.store, "@"+i.ID())
   905  		if err != nil {
   906  			return nil, errors.Wrapf(err, "error parsing reference to image %q", i.ID())
   907  		}
   908  		imgSrcRef, err := ref.NewImageSource(ctx, nil)
   909  		if err != nil {
   910  			return nil, errors.Wrapf(err, "error reading image %q as image source", i.ID())
   911  		}
   912  		i.imgSrcRef = imgSrcRef
   913  	}
   914  	return i.imgSrcRef, nil
   915  }
   916  
   917  //Size returns the size of the image
   918  func (i *Image) Size(ctx context.Context) (*uint64, error) {
   919  	sum, err := i.imageruntime.store.ImageSize(i.ID())
   920  	if err == nil && sum >= 0 {
   921  		usum := uint64(sum)
   922  		return &usum, nil
   923  	}
   924  	return nil, errors.Wrap(err, "unable to determine size")
   925  }
   926  
   927  // toImageRef returns an Image Reference type from an image
   928  func (i *Image) toImageRef(ctx context.Context) (types.Image, error) {
   929  	if i == nil {
   930  		return nil, errors.Errorf("cannot convert nil image to image reference")
   931  	}
   932  	imgSrcRef, err := i.toImageSourceRef(ctx)
   933  	if err != nil {
   934  		return nil, err
   935  	}
   936  	if i.imgRef == nil {
   937  		systemContext := &types.SystemContext{}
   938  		unparsedDefaultInstance := image.UnparsedInstance(imgSrcRef, nil)
   939  		imgRef, err := image.FromUnparsedImage(ctx, systemContext, unparsedDefaultInstance)
   940  		if err != nil {
   941  			// check for a "tried-to-treat-a-bare-list-like-a-runnable-image" problem, else
   942  			// return info about the not-a-bare-list runnable image part of this storage.Image
   943  			if manifestBytes, manifestType, err2 := imgSrcRef.GetManifest(ctx, nil); err2 == nil {
   944  				if manifest.MIMETypeIsMultiImage(manifestType) {
   945  					if list, err3 := manifest.ListFromBlob(manifestBytes, manifestType); err3 == nil {
   946  						switch manifestType {
   947  						case ociv1.MediaTypeImageIndex:
   948  							err = errors.Wrapf(ErrImageIsBareList, "%q is an image index", i.InputName)
   949  						case manifest.DockerV2ListMediaType:
   950  							err = errors.Wrapf(ErrImageIsBareList, "%q is a manifest list", i.InputName)
   951  						default:
   952  							err = errors.Wrapf(ErrImageIsBareList, "%q", i.InputName)
   953  						}
   954  						for _, instanceDigest := range list.Instances() {
   955  							instance := instanceDigest
   956  							unparsedInstance := image.UnparsedInstance(imgSrcRef, &instance)
   957  							if imgRef2, err4 := image.FromUnparsedImage(ctx, systemContext, unparsedInstance); err4 == nil {
   958  								imgRef = imgRef2
   959  								err = nil
   960  								break
   961  							}
   962  						}
   963  					}
   964  				}
   965  			}
   966  			if err != nil {
   967  				return nil, errors.Wrapf(err, "error reading image %q as image", i.ID())
   968  			}
   969  		}
   970  		i.imgRef = imgRef
   971  	}
   972  	return i.imgRef, nil
   973  }
   974  
   975  // DriverData gets the driver data from the store on a layer
   976  func (i *Image) DriverData() (*driver.Data, error) {
   977  	return driver.GetDriverData(i.imageruntime.store, i.TopLayer())
   978  }
   979  
   980  // Layer returns the image's top layer
   981  func (i *Image) Layer() (*storage.Layer, error) {
   982  	return i.imageruntime.store.Layer(i.image.TopLayer)
   983  }
   984  
   985  // History contains the history information of an image
   986  type History struct {
   987  	ID        string     `json:"id"`
   988  	Created   *time.Time `json:"created"`
   989  	CreatedBy string     `json:"createdBy"`
   990  	Size      int64      `json:"size"`
   991  	Comment   string     `json:"comment"`
   992  	Tags      []string   `json:"tags"`
   993  }
   994  
   995  // History gets the history of an image and the IDs of images that are part of
   996  // its history
   997  func (i *Image) History(ctx context.Context) ([]*History, error) {
   998  	img, err := i.toImageRef(ctx)
   999  	if err != nil {
  1000  		if errors.Cause(err) == ErrImageIsBareList {
  1001  			return nil, nil
  1002  		}
  1003  		return nil, err
  1004  	}
  1005  	oci, err := img.OCIConfig(ctx)
  1006  	if err != nil {
  1007  		return nil, err
  1008  	}
  1009  
  1010  	// Build a mapping from top-layer to image ID.
  1011  	images, err := i.imageruntime.GetImages()
  1012  	if err != nil {
  1013  		return nil, err
  1014  	}
  1015  	topLayerMap := make(map[string]string)
  1016  	for _, image := range images {
  1017  		if _, exists := topLayerMap[image.TopLayer()]; !exists {
  1018  			topLayerMap[image.TopLayer()] = image.ID()
  1019  		}
  1020  	}
  1021  
  1022  	var allHistory []*History
  1023  	var layer *storage.Layer
  1024  
  1025  	// Check if we have an actual top layer to prevent lookup errors.
  1026  	if i.TopLayer() != "" {
  1027  		layer, err = i.imageruntime.store.Layer(i.TopLayer())
  1028  		if err != nil {
  1029  			return nil, err
  1030  		}
  1031  	}
  1032  
  1033  	// Iterate in reverse order over the history entries, and lookup the
  1034  	// corresponding image ID, size and get the next later if needed.
  1035  	numHistories := len(oci.History) - 1
  1036  	for x := numHistories; x >= 0; x-- {
  1037  		var size int64
  1038  
  1039  		id := "<missing>"
  1040  		if x == numHistories {
  1041  			id = i.ID()
  1042  		}
  1043  		if layer != nil {
  1044  			if !oci.History[x].EmptyLayer {
  1045  				size = layer.UncompressedSize
  1046  			}
  1047  			if imageID, exists := topLayerMap[layer.ID]; exists {
  1048  				id = imageID
  1049  				// Delete the entry to avoid reusing it for following history items.
  1050  				delete(topLayerMap, layer.ID)
  1051  			}
  1052  		}
  1053  		h := History{
  1054  			ID:        id,
  1055  			Created:   oci.History[x].Created,
  1056  			CreatedBy: oci.History[x].CreatedBy,
  1057  			Size:      size,
  1058  			Comment:   oci.History[x].Comment,
  1059  		}
  1060  		if layer != nil {
  1061  			h.Tags = layer.Names
  1062  		}
  1063  		allHistory = append(allHistory, &h)
  1064  
  1065  		if layer != nil && layer.Parent != "" && !oci.History[x].EmptyLayer {
  1066  			layer, err = i.imageruntime.store.Layer(layer.Parent)
  1067  			if err != nil {
  1068  				return nil, err
  1069  			}
  1070  		}
  1071  	}
  1072  
  1073  	return allHistory, nil
  1074  }
  1075  
  1076  // Dangling returns a bool if the image is "dangling"
  1077  func (i *Image) Dangling() bool {
  1078  	return len(i.Names()) == 0
  1079  }
  1080  
  1081  // User returns the image's user
  1082  func (i *Image) User(ctx context.Context) (string, error) {
  1083  	imgInspect, err := i.inspect(ctx, false)
  1084  	if err != nil {
  1085  		return "", err
  1086  	}
  1087  	return imgInspect.Config.User, nil
  1088  }
  1089  
  1090  // StopSignal returns the image's StopSignal
  1091  func (i *Image) StopSignal(ctx context.Context) (string, error) {
  1092  	imgInspect, err := i.inspect(ctx, false)
  1093  	if err != nil {
  1094  		return "", err
  1095  	}
  1096  	return imgInspect.Config.StopSignal, nil
  1097  }
  1098  
  1099  // WorkingDir returns the image's WorkingDir
  1100  func (i *Image) WorkingDir(ctx context.Context) (string, error) {
  1101  	imgInspect, err := i.inspect(ctx, false)
  1102  	if err != nil {
  1103  		return "", err
  1104  	}
  1105  	return imgInspect.Config.WorkingDir, nil
  1106  }
  1107  
  1108  // Cmd returns the image's cmd
  1109  func (i *Image) Cmd(ctx context.Context) ([]string, error) {
  1110  	imgInspect, err := i.inspect(ctx, false)
  1111  	if err != nil {
  1112  		return nil, err
  1113  	}
  1114  	return imgInspect.Config.Cmd, nil
  1115  }
  1116  
  1117  // Entrypoint returns the image's entrypoint
  1118  func (i *Image) Entrypoint(ctx context.Context) ([]string, error) {
  1119  	imgInspect, err := i.inspect(ctx, false)
  1120  	if err != nil {
  1121  		return nil, err
  1122  	}
  1123  	return imgInspect.Config.Entrypoint, nil
  1124  }
  1125  
  1126  // Env returns the image's env
  1127  func (i *Image) Env(ctx context.Context) ([]string, error) {
  1128  	imgInspect, err := i.imageInspectInfo(ctx)
  1129  	if err != nil {
  1130  		return nil, err
  1131  	}
  1132  	return imgInspect.Env, nil
  1133  }
  1134  
  1135  // Labels returns the image's labels
  1136  func (i *Image) Labels(ctx context.Context) (map[string]string, error) {
  1137  	imgInspect, err := i.imageInspectInfo(ctx)
  1138  	if err != nil {
  1139  		return nil, err
  1140  	}
  1141  	return imgInspect.Labels, nil
  1142  }
  1143  
  1144  // GetLabel Returns a case-insensitive match of a given label
  1145  func (i *Image) GetLabel(ctx context.Context, label string) (string, error) {
  1146  	labels, err := i.Labels(ctx)
  1147  	if err != nil {
  1148  		return "", err
  1149  	}
  1150  
  1151  	for k, v := range labels {
  1152  		if strings.ToLower(k) == strings.ToLower(label) {
  1153  			return v, nil
  1154  		}
  1155  	}
  1156  	return "", nil
  1157  }
  1158  
  1159  // Annotations returns the annotations of an image
  1160  func (i *Image) Annotations(ctx context.Context) (map[string]string, error) {
  1161  	imageManifest, manifestType, err := i.Manifest(ctx)
  1162  	if err != nil {
  1163  		imageManifest, manifestType, err = i.GetManifest(ctx, nil)
  1164  		if err != nil {
  1165  			return nil, err
  1166  		}
  1167  	}
  1168  	annotations := make(map[string]string)
  1169  	if manifestType == ociv1.MediaTypeImageManifest {
  1170  		var m ociv1.Manifest
  1171  		if err := json.Unmarshal(imageManifest, &m); err == nil {
  1172  			for k, v := range m.Annotations {
  1173  				annotations[k] = v
  1174  			}
  1175  		}
  1176  	}
  1177  	return annotations, nil
  1178  }
  1179  
  1180  // ociv1Image converts an image to an imgref and then returns its config blob
  1181  // converted to an ociv1 image type
  1182  func (i *Image) ociv1Image(ctx context.Context) (*ociv1.Image, error) {
  1183  	imgRef, err := i.toImageRef(ctx)
  1184  	if err != nil {
  1185  		return nil, err
  1186  	}
  1187  	return imgRef.OCIConfig(ctx)
  1188  }
  1189  
  1190  func (i *Image) imageInspectInfo(ctx context.Context) (*types.ImageInspectInfo, error) {
  1191  	if i.inspectInfo == nil {
  1192  		ic, err := i.toImageRef(ctx)
  1193  		if err != nil {
  1194  			return nil, err
  1195  		}
  1196  		imgInspect, err := ic.Inspect(ctx)
  1197  		if err != nil {
  1198  			return nil, err
  1199  		}
  1200  		i.inspectInfo = imgInspect
  1201  	}
  1202  	return i.inspectInfo, nil
  1203  }
  1204  
  1205  func (i *Image) inspect(ctx context.Context, calculateSize bool) (*inspect.ImageData, error) {
  1206  	ociv1Img, err := i.ociv1Image(ctx)
  1207  	if err != nil {
  1208  		ociv1Img = &ociv1.Image{}
  1209  	}
  1210  	info, err := i.imageInspectInfo(ctx)
  1211  	if err != nil {
  1212  		info = &types.ImageInspectInfo{}
  1213  	}
  1214  	annotations, err := i.Annotations(ctx)
  1215  	if err != nil {
  1216  		return nil, err
  1217  	}
  1218  
  1219  	size := int64(-1)
  1220  	if calculateSize {
  1221  		if usize, err := i.Size(ctx); err == nil {
  1222  			size = int64(*usize)
  1223  		}
  1224  	}
  1225  
  1226  	repoTags, err := i.RepoTags()
  1227  	if err != nil {
  1228  		return nil, err
  1229  	}
  1230  
  1231  	repoDigests, err := i.RepoDigests()
  1232  	if err != nil {
  1233  		return nil, err
  1234  	}
  1235  
  1236  	driver, err := i.DriverData()
  1237  	if err != nil {
  1238  		return nil, err
  1239  	}
  1240  
  1241  	_, manifestType, err := i.GetManifest(ctx, nil)
  1242  	if err != nil {
  1243  		return nil, errors.Wrapf(err, "unable to determine manifest type")
  1244  	}
  1245  	comment, err := i.Comment(ctx, manifestType)
  1246  	if err != nil {
  1247  		return nil, err
  1248  	}
  1249  
  1250  	data := &inspect.ImageData{
  1251  		ID:           i.ID(),
  1252  		RepoTags:     repoTags,
  1253  		RepoDigests:  repoDigests,
  1254  		Comment:      comment,
  1255  		Created:      ociv1Img.Created,
  1256  		Author:       ociv1Img.Author,
  1257  		Architecture: ociv1Img.Architecture,
  1258  		Os:           ociv1Img.OS,
  1259  		Config:       &ociv1Img.Config,
  1260  		Version:      info.DockerVersion,
  1261  		Size:         size,
  1262  		VirtualSize:  size,
  1263  		Annotations:  annotations,
  1264  		Digest:       i.Digest(),
  1265  		Labels:       info.Labels,
  1266  		RootFS: &inspect.RootFS{
  1267  			Type:   ociv1Img.RootFS.Type,
  1268  			Layers: ociv1Img.RootFS.DiffIDs,
  1269  		},
  1270  		GraphDriver:  driver,
  1271  		ManifestType: manifestType,
  1272  		User:         ociv1Img.Config.User,
  1273  		History:      ociv1Img.History,
  1274  		NamesHistory: i.NamesHistory(),
  1275  	}
  1276  	if manifestType == manifest.DockerV2Schema2MediaType {
  1277  		hc, err := i.GetHealthCheck(ctx)
  1278  		if err != nil {
  1279  			return nil, err
  1280  		}
  1281  		if hc != nil {
  1282  			data.HealthCheck = hc
  1283  		}
  1284  	}
  1285  	return data, nil
  1286  }
  1287  
  1288  // Inspect returns an image's inspect data
  1289  func (i *Image) Inspect(ctx context.Context) (*inspect.ImageData, error) {
  1290  	span, _ := opentracing.StartSpanFromContext(ctx, "imageInspect")
  1291  
  1292  	span.SetTag("type", "image")
  1293  	defer span.Finish()
  1294  
  1295  	return i.inspect(ctx, true)
  1296  }
  1297  
  1298  // InspectNoSize returns an image's inspect data without calculating the size for the image
  1299  func (i *Image) InspectNoSize(ctx context.Context) (*inspect.ImageData, error) {
  1300  	span, _ := opentracing.StartSpanFromContext(ctx, "imageInspectNoSize")
  1301  
  1302  	span.SetTag("type", "image")
  1303  	defer span.Finish()
  1304  
  1305  	return i.inspect(ctx, false)
  1306  }
  1307  
  1308  // Import imports and image into the store and returns an image
  1309  func (ir *Runtime) Import(ctx context.Context, path, reference string, writer io.Writer, signingOptions SigningOptions, imageConfig ociv1.Image) (*Image, error) {
  1310  	src, err := tarball.Transport.ParseReference(path)
  1311  	if err != nil {
  1312  		return nil, errors.Wrapf(err, "error parsing image name %q", path)
  1313  	}
  1314  
  1315  	updater, ok := src.(tarball.ConfigUpdater)
  1316  	if !ok {
  1317  		return nil, errors.Wrapf(err, "unexpected type, a tarball reference should implement tarball.ConfigUpdater")
  1318  	}
  1319  
  1320  	annotations := make(map[string]string)
  1321  
  1322  	//	config imgspecv1.Image
  1323  	err = updater.ConfigUpdate(imageConfig, annotations)
  1324  	if err != nil {
  1325  		return nil, errors.Wrapf(err, "error updating image config")
  1326  	}
  1327  
  1328  	sc := GetSystemContext(ir.SignaturePolicyPath, "", false)
  1329  
  1330  	// if reference not given, get the image digest
  1331  	if reference == "" {
  1332  		reference, err = getImageDigest(ctx, src, sc)
  1333  		if err != nil {
  1334  			return nil, err
  1335  		}
  1336  	}
  1337  	policyContext, err := getPolicyContext(sc)
  1338  	if err != nil {
  1339  		return nil, err
  1340  	}
  1341  	defer func() {
  1342  		if err := policyContext.Destroy(); err != nil {
  1343  			logrus.Errorf("failed to destroy policy context: %q", err)
  1344  		}
  1345  	}()
  1346  	copyOptions := getCopyOptions(sc, writer, nil, nil, signingOptions, "", nil)
  1347  	dest, err := is.Transport.ParseStoreReference(ir.store, reference)
  1348  	if err != nil {
  1349  		return nil, errors.Wrapf(err, "error getting image reference for %q", reference)
  1350  	}
  1351  	_, err = cp.Image(ctx, policyContext, dest, src, copyOptions)
  1352  	if err != nil {
  1353  		return nil, err
  1354  	}
  1355  	newImage, err := ir.NewFromLocal(reference)
  1356  	if err == nil {
  1357  		newImage.newImageEvent(events.Import)
  1358  	}
  1359  	return newImage, err
  1360  }
  1361  
  1362  // MatchRepoTag takes a string and tries to match it against an
  1363  // image's repotags
  1364  func (i *Image) MatchRepoTag(input string) (string, error) {
  1365  	results := make(map[int][]string)
  1366  	var maxCount int
  1367  	// first check if we have an exact match with the input
  1368  	if util.StringInSlice(input, i.Names()) {
  1369  		return input, nil
  1370  	}
  1371  	// next check if we are missing the tag
  1372  	dcImage, err := decompose(input)
  1373  	if err != nil {
  1374  		return "", err
  1375  	}
  1376  	imageRegistry, imageName, imageSuspiciousTagValueForSearch := dcImage.suspiciousRefNameTagValuesForSearch()
  1377  	for _, repoName := range i.Names() {
  1378  		count := 0
  1379  		dcRepoName, err := decompose(repoName)
  1380  		if err != nil {
  1381  			return "", err
  1382  		}
  1383  		repoNameRegistry, repoNameName, repoNameSuspiciousTagValueForSearch := dcRepoName.suspiciousRefNameTagValuesForSearch()
  1384  		if repoNameRegistry == imageRegistry && imageRegistry != "" {
  1385  			count++
  1386  		}
  1387  		if repoNameName == imageName && imageName != "" {
  1388  			count++
  1389  		} else if splitString(repoNameName) == splitString(imageName) {
  1390  			count++
  1391  		}
  1392  		if repoNameSuspiciousTagValueForSearch == imageSuspiciousTagValueForSearch {
  1393  			count++
  1394  		}
  1395  		results[count] = append(results[count], repoName)
  1396  		if count > maxCount {
  1397  			maxCount = count
  1398  		}
  1399  	}
  1400  	if maxCount == 0 {
  1401  		return "", ErrRepoTagNotFound
  1402  	}
  1403  	if len(results[maxCount]) > 1 {
  1404  		return "", errors.Errorf("user input matched multiple repotags for the image")
  1405  	}
  1406  	return results[maxCount][0], nil
  1407  }
  1408  
  1409  // splitString splits input string by / and returns the last array item
  1410  func splitString(input string) string {
  1411  	split := strings.Split(input, "/")
  1412  	return split[len(split)-1]
  1413  }
  1414  
  1415  // IsParent goes through the layers in the store and checks if i.TopLayer is
  1416  // the parent of any other layer in store. Double check that image with that
  1417  // layer exists as well.
  1418  func (i *Image) IsParent(ctx context.Context) (bool, error) {
  1419  	children, err := i.getChildren(ctx, false)
  1420  	if err != nil {
  1421  		if errors.Cause(err) == ErrImageIsBareList {
  1422  			return false, nil
  1423  		}
  1424  		return false, err
  1425  	}
  1426  	return len(children) > 0, nil
  1427  }
  1428  
  1429  // historiesMatch returns the number of entries in the histories which have the
  1430  // same contents
  1431  func historiesMatch(a, b []imgspecv1.History) int {
  1432  	i := 0
  1433  	for i < len(a) && i < len(b) {
  1434  		if a[i].Created != nil && b[i].Created == nil {
  1435  			return i
  1436  		}
  1437  		if a[i].Created == nil && b[i].Created != nil {
  1438  			return i
  1439  		}
  1440  		if a[i].Created != nil && b[i].Created != nil {
  1441  			if !a[i].Created.Equal(*(b[i].Created)) {
  1442  				return i
  1443  			}
  1444  		}
  1445  		if a[i].CreatedBy != b[i].CreatedBy {
  1446  			return i
  1447  		}
  1448  		if a[i].Author != b[i].Author {
  1449  			return i
  1450  		}
  1451  		if a[i].Comment != b[i].Comment {
  1452  			return i
  1453  		}
  1454  		if a[i].EmptyLayer != b[i].EmptyLayer {
  1455  			return i
  1456  		}
  1457  		i++
  1458  	}
  1459  	return i
  1460  }
  1461  
  1462  // areParentAndChild checks diff ID and history in the two images and return
  1463  // true if the second should be considered to be directly based on the first
  1464  func areParentAndChild(parent, child *imgspecv1.Image) bool {
  1465  	// the child and candidate parent should share all of the
  1466  	// candidate parent's diff IDs, which together would have
  1467  	// controlled which layers were used
  1468  
  1469  	// Both, child and parent, may be nil when the storage is left in an
  1470  	// incoherent state.  Issue #7444 describes such a case when a build
  1471  	// has been killed.
  1472  	if child == nil || parent == nil {
  1473  		return false
  1474  	}
  1475  
  1476  	if len(parent.RootFS.DiffIDs) > len(child.RootFS.DiffIDs) {
  1477  		return false
  1478  	}
  1479  	childUsesCandidateDiffs := true
  1480  	for i := range parent.RootFS.DiffIDs {
  1481  		if child.RootFS.DiffIDs[i] != parent.RootFS.DiffIDs[i] {
  1482  			childUsesCandidateDiffs = false
  1483  			break
  1484  		}
  1485  	}
  1486  	if !childUsesCandidateDiffs {
  1487  		return false
  1488  	}
  1489  	// the child should have the same history as the parent, plus
  1490  	// one more entry
  1491  	if len(parent.History)+1 != len(child.History) {
  1492  		return false
  1493  	}
  1494  	if historiesMatch(parent.History, child.History) != len(parent.History) {
  1495  		return false
  1496  	}
  1497  	return true
  1498  }
  1499  
  1500  // GetParent returns the image ID of the parent. Return nil if a parent is not found.
  1501  func (i *Image) GetParent(ctx context.Context) (*Image, error) {
  1502  	tree, err := i.imageruntime.layerTree()
  1503  	if err != nil {
  1504  		return nil, err
  1505  	}
  1506  	return tree.parent(ctx, i)
  1507  }
  1508  
  1509  // GetChildren returns a list of the imageIDs that depend on the image
  1510  func (i *Image) GetChildren(ctx context.Context) ([]string, error) {
  1511  	children, err := i.getChildren(ctx, true)
  1512  	if err != nil {
  1513  		if errors.Cause(err) == ErrImageIsBareList {
  1514  			return nil, nil
  1515  		}
  1516  		return nil, err
  1517  	}
  1518  	return children, nil
  1519  }
  1520  
  1521  // getChildren returns a list of imageIDs that depend on the image. If all is
  1522  // false, only the first child image is returned.
  1523  func (i *Image) getChildren(ctx context.Context, all bool) ([]string, error) {
  1524  	tree, err := i.imageruntime.layerTree()
  1525  	if err != nil {
  1526  		return nil, err
  1527  	}
  1528  
  1529  	return tree.children(ctx, i, all)
  1530  }
  1531  
  1532  // InputIsID returns a bool if the user input for an image
  1533  // is the image's partial or full id
  1534  func (i *Image) InputIsID() bool {
  1535  	return strings.HasPrefix(i.ID(), i.InputName)
  1536  }
  1537  
  1538  // Containers a list of container IDs associated with the image
  1539  func (i *Image) Containers() ([]string, error) {
  1540  	containers, err := i.imageruntime.store.Containers()
  1541  	if err != nil {
  1542  		return nil, err
  1543  	}
  1544  	var imageContainers []string
  1545  	for _, c := range containers {
  1546  		if c.ImageID == i.ID() {
  1547  			imageContainers = append(imageContainers, c.ID)
  1548  		}
  1549  	}
  1550  	return imageContainers, err
  1551  }
  1552  
  1553  // Comment returns the Comment for an image depending on its ManifestType
  1554  func (i *Image) Comment(ctx context.Context, manifestType string) (string, error) {
  1555  	if manifestType == manifest.DockerV2Schema2MediaType {
  1556  		imgRef, err := i.toImageRef(ctx)
  1557  		if err != nil {
  1558  			return "", errors.Wrapf(err, "unable to create image reference from image")
  1559  		}
  1560  		blob, err := imgRef.ConfigBlob(ctx)
  1561  		if err != nil {
  1562  			return "", errors.Wrapf(err, "unable to get config blob from image")
  1563  		}
  1564  		b := manifest.Schema2Image{}
  1565  		if err := json.Unmarshal(blob, &b); err != nil {
  1566  			return "", err
  1567  		}
  1568  		return b.Comment, nil
  1569  	}
  1570  	ociv1Img, err := i.ociv1Image(ctx)
  1571  	if err != nil {
  1572  		if errors.Cause(err) == ErrImageIsBareList {
  1573  			return "", nil
  1574  		}
  1575  		return "", err
  1576  	}
  1577  	if len(ociv1Img.History) > 0 {
  1578  		return ociv1Img.History[0].Comment, nil
  1579  	}
  1580  	return "", nil
  1581  }
  1582  
  1583  // Save writes a container image to the filesystem
  1584  func (i *Image) Save(ctx context.Context, source, format, output string, moreTags []string, quiet, compress, removeSignatures bool) error {
  1585  	var (
  1586  		writer       io.Writer
  1587  		destRef      types.ImageReference
  1588  		manifestType string
  1589  		err          error
  1590  	)
  1591  
  1592  	if quiet {
  1593  		writer = os.Stderr
  1594  	}
  1595  	switch format {
  1596  	case "oci-archive":
  1597  		destImageName := imageNameForSaveDestination(i, source)
  1598  		destRef, err = ociarchive.NewReference(output, destImageName) // destImageName may be ""
  1599  		if err != nil {
  1600  			return errors.Wrapf(err, "error getting OCI archive ImageReference for (%q, %q)", output, destImageName)
  1601  		}
  1602  	case "oci-dir":
  1603  		destImageName := imageNameForSaveDestination(i, source)
  1604  		destRef, err = layout.NewReference(output, destImageName) // destImageName may be ""
  1605  		if err != nil {
  1606  			return errors.Wrapf(err, "error getting the OCI directory ImageReference for (%q, %q)", output, destImageName)
  1607  		}
  1608  		manifestType = imgspecv1.MediaTypeImageManifest
  1609  	case "docker-dir":
  1610  		destRef, err = directory.NewReference(output)
  1611  		if err != nil {
  1612  			return errors.Wrapf(err, "error getting directory ImageReference for %q", output)
  1613  		}
  1614  		manifestType = manifest.DockerV2Schema2MediaType
  1615  	case "docker-archive", "":
  1616  		destImageName := imageNameForSaveDestination(i, source)
  1617  		ref, err := dockerArchiveDstReference(destImageName)
  1618  		if err != nil {
  1619  			return err
  1620  		}
  1621  		destRef, err = dockerarchive.NewReference(output, ref)
  1622  		if err != nil {
  1623  			return errors.Wrapf(err, "error getting Docker archive ImageReference for %s:%v", output, ref)
  1624  		}
  1625  	default:
  1626  		return errors.Errorf("unknown format option %q", format)
  1627  	}
  1628  	// supports saving multiple tags to the same tar archive
  1629  	var additionaltags []reference.NamedTagged
  1630  	if len(moreTags) > 0 {
  1631  		additionaltags, err = GetAdditionalTags(moreTags)
  1632  		if err != nil {
  1633  			return err
  1634  		}
  1635  	}
  1636  	if err := i.PushImageToReference(ctx, destRef, manifestType, "", "", "", writer, compress, SigningOptions{RemoveSignatures: removeSignatures}, &DockerRegistryOptions{}, additionaltags); err != nil {
  1637  		return errors.Wrapf(err, "unable to save %q", source)
  1638  	}
  1639  	i.newImageEvent(events.Save)
  1640  	return nil
  1641  }
  1642  
  1643  // dockerArchiveDestReference returns a NamedTagged reference for a tagged image and nil for untagged image.
  1644  func dockerArchiveDstReference(normalizedInput string) (reference.NamedTagged, error) {
  1645  	if normalizedInput == "" {
  1646  		return nil, nil
  1647  	}
  1648  	ref, err := reference.ParseNormalizedNamed(normalizedInput)
  1649  	if err != nil {
  1650  		return nil, errors.Wrapf(err, "docker-archive parsing reference %s", normalizedInput)
  1651  	}
  1652  	ref = reference.TagNameOnly(ref)
  1653  	namedTagged, isTagged := ref.(reference.NamedTagged)
  1654  	if !isTagged {
  1655  		namedTagged = nil
  1656  	}
  1657  	return namedTagged, nil
  1658  }
  1659  
  1660  // GetConfigBlob returns a schema2image.  If the image is not a schema2, then
  1661  // it will return an error
  1662  func (i *Image) GetConfigBlob(ctx context.Context) (*manifest.Schema2Image, error) {
  1663  	imageRef, err := i.toImageRef(ctx)
  1664  	if err != nil {
  1665  		return nil, err
  1666  	}
  1667  	b, err := imageRef.ConfigBlob(ctx)
  1668  	if err != nil {
  1669  		return nil, errors.Wrapf(err, "unable to get config blob for %s", i.ID())
  1670  	}
  1671  	blob := manifest.Schema2Image{}
  1672  	if err := json.Unmarshal(b, &blob); err != nil {
  1673  		return nil, errors.Wrapf(err, "unable to parse image blob for %s", i.ID())
  1674  	}
  1675  	return &blob, nil
  1676  
  1677  }
  1678  
  1679  // GetHealthCheck returns a HealthConfig for an image.  This function only works with
  1680  // schema2 images.
  1681  func (i *Image) GetHealthCheck(ctx context.Context) (*manifest.Schema2HealthConfig, error) {
  1682  	configBlob, err := i.GetConfigBlob(ctx)
  1683  	if err != nil {
  1684  		return nil, err
  1685  	}
  1686  	return configBlob.ContainerConfig.Healthcheck, nil
  1687  }
  1688  
  1689  // newImageEvent creates a new event based on an image
  1690  func (ir *Runtime) newImageEvent(status events.Status, name string) {
  1691  	e := events.NewEvent(status)
  1692  	e.Type = events.Image
  1693  	e.Name = name
  1694  	if err := ir.Eventer.Write(e); err != nil {
  1695  		logrus.Infof("unable to write event to %s", ir.EventsLogFilePath)
  1696  	}
  1697  }
  1698  
  1699  // newImageEvent creates a new event based on an image
  1700  func (i *Image) newImageEvent(status events.Status) {
  1701  	e := events.NewEvent(status)
  1702  	e.ID = i.ID()
  1703  	e.Type = events.Image
  1704  	if len(i.Names()) > 0 {
  1705  		e.Name = i.Names()[0]
  1706  	}
  1707  	if err := i.imageruntime.Eventer.Write(e); err != nil {
  1708  		logrus.Infof("unable to write event to %s", i.imageruntime.EventsLogFilePath)
  1709  	}
  1710  }
  1711  
  1712  // Mount mounts a image's filesystem on the host
  1713  // The path where the image has been mounted is returned
  1714  func (i *Image) Mount(options []string, mountLabel string) (string, error) {
  1715  	defer i.newImageEvent(events.Mount)
  1716  	return i.mount(options, mountLabel)
  1717  }
  1718  
  1719  // Unmount unmounts a image's filesystem on the host
  1720  func (i *Image) Unmount(force bool) error {
  1721  	defer i.newImageEvent(events.Unmount)
  1722  	return i.unmount(force)
  1723  }
  1724  
  1725  // Mounted returns whether the image is mounted and the path it is mounted
  1726  // at (if it is mounted).
  1727  // If the image is not mounted, no error is returned, and the mountpoint
  1728  // will be set to "".
  1729  func (i *Image) Mounted() (bool, string, error) {
  1730  	mountedTimes, err := i.imageruntime.store.Mounted(i.TopLayer())
  1731  	if err != nil {
  1732  		return false, "", err
  1733  	}
  1734  
  1735  	if mountedTimes > 0 {
  1736  		layer, err := i.imageruntime.store.Layer(i.TopLayer())
  1737  		if err != nil {
  1738  			return false, "", err
  1739  		}
  1740  		return true, layer.MountPoint, nil
  1741  	}
  1742  
  1743  	return false, "", nil
  1744  }
  1745  
  1746  // mount mounts the container's root filesystem
  1747  func (i *Image) mount(options []string, mountLabel string) (string, error) {
  1748  	mountPoint, err := i.imageruntime.store.MountImage(i.ID(), options, mountLabel)
  1749  	if err != nil {
  1750  		return "", errors.Wrapf(err, "error mounting storage for image %s", i.ID())
  1751  	}
  1752  	mountPoint, err = filepath.EvalSymlinks(mountPoint)
  1753  	if err != nil {
  1754  		return "", errors.Wrapf(err, "error resolving storage path for image %s", i.ID())
  1755  	}
  1756  	return mountPoint, nil
  1757  }
  1758  
  1759  // unmount unmounts the image's root filesystem
  1760  func (i *Image) unmount(force bool) error {
  1761  	// Also unmount storage
  1762  	if _, err := i.imageruntime.store.UnmountImage(i.ID(), force); err != nil {
  1763  		return errors.Wrapf(err, "error unmounting image %s root filesystem", i.ID())
  1764  	}
  1765  
  1766  	return nil
  1767  }
  1768  
  1769  // LayerInfo keeps information of single layer
  1770  type LayerInfo struct {
  1771  	// Layer ID
  1772  	ID string
  1773  	// Parent ID of current layer.
  1774  	ParentID string
  1775  	// ChildID of current layer.
  1776  	// there can be multiple children in case of fork
  1777  	ChildID []string
  1778  	// RepoTag will have image repo names, if layer is top layer of image
  1779  	RepoTags []string
  1780  	// Size stores Uncompressed size of layer.
  1781  	Size int64
  1782  }
  1783  
  1784  // GetLayersMapWithImageInfo returns map of image-layers, with associated information like RepoTags, parent and list of child layers.
  1785  func GetLayersMapWithImageInfo(imageruntime *Runtime) (map[string]*LayerInfo, error) {
  1786  	// TODO: evaluate if we can reuse `layerTree` here.
  1787  
  1788  	// Memory allocated to store map of layers with key LayerID.
  1789  	// Map will build dependency chain with ParentID and ChildID(s)
  1790  	layerInfoMap := make(map[string]*LayerInfo)
  1791  
  1792  	// scan all layers & fill size and parent id for each layer in layerInfoMap
  1793  	layers, err := imageruntime.store.Layers()
  1794  	if err != nil {
  1795  		return nil, err
  1796  	}
  1797  	for _, layer := range layers {
  1798  		_, ok := layerInfoMap[layer.ID]
  1799  		if !ok {
  1800  			layerInfoMap[layer.ID] = &LayerInfo{
  1801  				ID:       layer.ID,
  1802  				Size:     layer.UncompressedSize,
  1803  				ParentID: layer.Parent,
  1804  			}
  1805  		} else {
  1806  			return nil, fmt.Errorf("detected multiple layers with the same ID %q", layer.ID)
  1807  		}
  1808  	}
  1809  
  1810  	// scan all layers & add all childid's for each layers to layerInfo
  1811  	for _, layer := range layers {
  1812  		_, ok := layerInfoMap[layer.ID]
  1813  		if ok {
  1814  			if layer.Parent != "" {
  1815  				layerInfoMap[layer.Parent].ChildID = append(layerInfoMap[layer.Parent].ChildID, layer.ID)
  1816  			}
  1817  		} else {
  1818  			return nil, fmt.Errorf("lookup error: layer-id  %s, not found", layer.ID)
  1819  		}
  1820  	}
  1821  
  1822  	// Add the Repo Tags to Top layer of each image.
  1823  	imgs, err := imageruntime.store.Images()
  1824  	if err != nil {
  1825  		return nil, err
  1826  	}
  1827  	layerInfoMap[""] = &LayerInfo{}
  1828  	for _, img := range imgs {
  1829  		e, ok := layerInfoMap[img.TopLayer]
  1830  		if !ok {
  1831  			return nil, fmt.Errorf("top-layer for image %s not found local store", img.ID)
  1832  		}
  1833  		e.RepoTags = append(e.RepoTags, img.Names...)
  1834  	}
  1835  	return layerInfoMap, nil
  1836  }
  1837  
  1838  // BuildImageHierarchyMap stores hierarchy of images such that all parent layers using which image is built are stored in imageInfo
  1839  // Layers are added such that  (Start)RootLayer->...intermediate Parent Layer(s)-> TopLayer(End)
  1840  func BuildImageHierarchyMap(imageInfo *InfoImage, layerMap map[string]*LayerInfo, layerID string) error {
  1841  	if layerID == "" {
  1842  		return nil
  1843  	}
  1844  	ll, ok := layerMap[layerID]
  1845  	if !ok {
  1846  		return fmt.Errorf("lookup error: layerid  %s not found", layerID)
  1847  	}
  1848  	if err := BuildImageHierarchyMap(imageInfo, layerMap, ll.ParentID); err != nil {
  1849  		return err
  1850  	}
  1851  
  1852  	imageInfo.Layers = append(imageInfo.Layers, *ll)
  1853  	return nil
  1854  }