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