From f7c8dd5836002f3bf85a7bbe6c949cdece5194df Mon Sep 17 00:00:00 2001 From: baude Date: Thu, 22 Mar 2018 10:17:50 -0500 Subject: Stage 4 Image cleanup Cull funcs from runtime_img.go which are no longer needed. Also, fix any remaining spots that use the old image technique. Signed-off-by: baude Closes: #532 Approved by: mheon --- libpod/container_api.go | 2 +- libpod/diff.go | 4 +- libpod/image/filters.go | 82 ++++ libpod/image/image.go | 6 +- libpod/runtime_img.go | 1142 +---------------------------------------------- libpod/util.go | 5 - 6 files changed, 106 insertions(+), 1135 deletions(-) create mode 100644 libpod/image/filters.go (limited to 'libpod') diff --git a/libpod/container_api.go b/libpod/container_api.go index 27c7994f4..6b30141a5 100644 --- a/libpod/container_api.go +++ b/libpod/container_api.go @@ -565,7 +565,7 @@ func (c *Container) Commit(pause bool, reference string, writer io.Writer, signi if err := c.export(tempFile.Name()); err != nil { return nil, err } - return image.Import(tempFile.Name(), reference, writer, signingOptions, imageConfig, c.runtime.imageRuntime) + return c.runtime.imageRuntime.Import(tempFile.Name(), reference, writer, signingOptions, imageConfig) } // Wait blocks on a container to exit and returns its exit code diff --git a/libpod/diff.go b/libpod/diff.go index 3d95a8e41..6e07f3049 100644 --- a/libpod/diff.go +++ b/libpod/diff.go @@ -27,7 +27,7 @@ func (r *Runtime) GetDiff(from, to string) ([]archive.Change, error) { // If the id matches a layer, the top layer id is returned func (r *Runtime) getLayerID(id string) (string, error) { var toLayer string - toImage, err := r.GetImage(id) + toImage, err := r.imageRuntime.NewFromLocal(id) if err != nil { toCtr, err := r.store.Container(id) if err != nil { @@ -39,7 +39,7 @@ func (r *Runtime) getLayerID(id string) (string, error) { toLayer = toCtr.LayerID } } else { - toLayer = toImage.TopLayer + toLayer = toImage.TopLayer() } return toLayer, nil } diff --git a/libpod/image/filters.go b/libpod/image/filters.go new file mode 100644 index 000000000..20a9efc97 --- /dev/null +++ b/libpod/image/filters.go @@ -0,0 +1,82 @@ +package image + +import ( + "strings" + "time" + + "github.com/projectatomic/libpod/pkg/inspect" +) + +// ResultFilter is a mock function for image filtering +type ResultFilter func(*Image) bool + +// Filter is a function to determine whether an image is included in +// command output. Images to be outputted are tested using the function. A true +// return will include the image, a false return will exclude it. +type Filter func(*Image, *inspect.ImageData) bool + +// CreatedBeforeFilter allows you to filter on images created before +// the given time.Time +func CreatedBeforeFilter(createTime time.Time) ResultFilter { + return func(i *Image) bool { + return i.Created().Before(createTime) + } +} + +// CreatedAfterFilter allows you to filter on images created after +// the given time.Time +func CreatedAfterFilter(createTime time.Time) ResultFilter { + return func(i *Image) bool { + return i.Created().After(createTime) + } +} + +// DanglingFilter allows you to filter images for dangling images +func DanglingFilter() ResultFilter { + return func(i *Image) bool { + return i.Dangling() + } +} + +// LabelFilter allows you to filter by images labels key and/or value +func LabelFilter(labelfilter string) ResultFilter { + // We need to handle both label=key and label=key=value + return func(i *Image) bool { + var value string + splitFilter := strings.Split(labelfilter, "=") + key := splitFilter[0] + if len(splitFilter) > 1 { + value = splitFilter[1] + } + labels, err := i.Labels() + if err != nil { + return false + } + if len(strings.TrimSpace(labels[key])) > 0 && len(strings.TrimSpace(value)) == 0 { + return true + } + return labels[key] == value + } +} + +// OutputImageFilter allows you to filter by an a specific image name +func OutputImageFilter(userImage *Image) ResultFilter { + return func(i *Image) bool { + return userImage.ID() == i.ID() + } +} + +// FilterImages filters images using a set of predefined fitler funcs +func FilterImages(images []*Image, filters []ResultFilter) []*Image { + var filteredImages []*Image + for _, image := range images { + include := true + for _, filter := range filters { + include = include && filter(image) + } + if include { + filteredImages = append(filteredImages, image) + } + } + return filteredImages +} diff --git a/libpod/image/image.go b/libpod/image/image.go index b6e15e361..ac2431a56 100644 --- a/libpod/image/image.go +++ b/libpod/image/image.go @@ -641,7 +641,7 @@ func (i *Image) Inspect() (*inspect.ImageData, error) { } // Import imports and image into the store and returns an image -func Import(path, reference string, writer io.Writer, signingOptions SigningOptions, imageConfig ociv1.Image, runtime *Runtime) (*Image, error) { +func (ir *Runtime) Import(path, reference string, writer io.Writer, signingOptions SigningOptions, imageConfig ociv1.Image) (*Image, error) { file := TarballTransport + ":" + path src, err := alltransports.ParseImageName(file) if err != nil { @@ -676,14 +676,14 @@ func Import(path, reference string, writer io.Writer, signingOptions SigningOpti } defer policyContext.Destroy() copyOptions := getCopyOptions(writer, "", nil, nil, signingOptions, "", "", false) - dest, err := is.Transport.ParseStoreReference(runtime.store, reference) + dest, err := is.Transport.ParseStoreReference(ir.store, reference) if err != nil { errors.Wrapf(err, "error getting image reference for %q", reference) } if err = cp.Image(policyContext, dest, src, copyOptions); err != nil { return nil, err } - return runtime.NewFromLocal(reference) + return ir.NewFromLocal(reference) } // MatchRepoTag takes a string and tries to match it against an diff --git a/libpod/runtime_img.go b/libpod/runtime_img.go index c830304ae..215c0afed 100644 --- a/libpod/runtime_img.go +++ b/libpod/runtime_img.go @@ -3,33 +3,20 @@ package libpod import ( "fmt" "io" - "net" "os" - "strings" - "syscall" - "time" - cp "github.com/containers/image/copy" "github.com/containers/image/directory" "github.com/containers/image/docker" dockerarchive "github.com/containers/image/docker/archive" - "github.com/containers/image/docker/reference" - "github.com/containers/image/docker/tarfile" ociarchive "github.com/containers/image/oci/archive" "github.com/containers/image/pkg/sysregistries" - "github.com/containers/image/signature" - is "github.com/containers/image/storage" "github.com/containers/image/tarball" - "github.com/containers/image/transports/alltransports" "github.com/containers/image/types" - "github.com/containers/storage" "github.com/containers/storage/pkg/archive" ociv1 "github.com/opencontainers/image-spec/specs-go/v1" "github.com/pkg/errors" "github.com/projectatomic/libpod/libpod/common" "github.com/projectatomic/libpod/libpod/image" - "github.com/projectatomic/libpod/pkg/inspect" - "github.com/projectatomic/libpod/pkg/util" ) // Runtime API @@ -86,752 +73,6 @@ type CopyOptions struct { ForceCompress bool } -// Image API - -// ImageFilterParams contains the filter options that may be given when outputting images -type ImageFilterParams struct { - Dangling string - Label string - BeforeImage time.Time - SinceImage time.Time - ReferencePattern string - ImageName string - ImageInput string -} - -// struct for when a user passes a short or incomplete -// image name -type imageDecomposeStruct struct { - imageName string - tag string - registry string - hasRegistry bool - transport string -} - -// ImageResultFilter is a mock function for image filtering -type ImageResultFilter func(*image.Image) bool - -func (k *Image) assembleFqName() string { - return fmt.Sprintf("%s/%s:%s", k.Registry, k.ImageName, k.Tag) -} - -func (k *Image) assembleFqNameTransport() string { - return fmt.Sprintf("%s%s/%s:%s", k.Transport, k.Registry, k.ImageName, k.Tag) -} - -//Image describes basic attributes of an image -type Image struct { - Name string - ID string - fqname string - runtime *Runtime - Registry string - ImageName string - Tag string - HasRegistry bool - Transport string - beenDecomposed bool - PullName string - LocalName string -} - -// NewImage creates a new image object based on its name -func (r *Runtime) NewImage(name string) Image { - return Image{ - Name: name, - runtime: r, - } -} - -// IsImageID determines if the input is a valid image ID. -// The input can be a full or partial image ID -func (r *Runtime) IsImageID(input string) (bool, error) { - images, err := r.GetImages(&ImageFilterParams{}) - if err != nil { - return false, errors.Wrapf(err, "unable to get images") - } - for _, image := range images { - if strings.HasPrefix(image.ID(), input) { - return true, nil - } - } - return false, nil -} - -// GetNameByID returns the name of the image when supplied -// the full or partion ID -func (k *Image) GetNameByID() (string, error) { - images, err := k.runtime.GetImages(&ImageFilterParams{}) - if err != nil { - return "", errors.Wrapf(err, "unable to get images") - } - for _, image := range images { - if strings.HasPrefix(image.ID(), k.Name) { - return image.Names()[0], nil - } - } - return "", errors.Errorf("unable to determine image for %s", k.Name) -} - -// GetImageID returns the image ID of the image -func (k *Image) GetImageID() (string, error) { - // If the ID field is already populated, then - // return it. - if k.ID != "" { - return k.ID, nil - } - // If we have the name of the image locally, then - // get the image and returns its ID - if k.LocalName != "" { - img, err := k.runtime.GetImage(k.LocalName) - if err == nil { - return img.ID, nil - } - } - // If the user input is an ID - images, err := k.runtime.GetImages(&ImageFilterParams{}) - if err != nil { - return "", errors.Wrapf(err, "unable to get images") - } - for _, image := range images { - // Check if we have an ID match - if strings.HasPrefix(image.ID(), k.Name) { - return image.ID(), nil - } - // Check if we have a name match, perhaps a tagged name - for _, name := range image.Names() { - if k.Name == name { - return image.ID(), nil - } - } - } - - // If neither the ID is known and no local name - // is know, we search it out. - image, _ := k.GetFQName() - img, err := k.runtime.GetImage(image) - if err != nil { - return "", err - } - return img.ID, nil -} - -// GetFQName returns the fully qualified image name if it can be determined -func (k *Image) GetFQName() (string, error) { - // Check if the fqname has already been found - if k.fqname != "" { - return k.fqname, nil - } - if err := k.Decompose(); err != nil { - return "", err - } - k.fqname = k.assembleFqName() - return k.fqname, nil -} - -func (k *Image) findImageOnRegistry() error { - searchRegistries, err := GetRegistries() - - if err != nil { - return errors.Wrapf(err, " the image name '%s' is incomplete.", k.Name) - } - - for _, searchRegistry := range searchRegistries { - k.Registry = searchRegistry - err = k.GetManifest() - if err == nil { - k.fqname = k.assembleFqName() - return nil - - } - } - return errors.Errorf("unable to find image on any configured registries") - -} - -// GetManifest tries to GET an images manifest, returns nil on success and err on failure -func (k *Image) GetManifest() error { - pullRef, err := alltransports.ParseImageName(k.assembleFqNameTransport()) - if err != nil { - return errors.Errorf("unable to parse1 '%s'", k.assembleFqName()) - } - imageSource, err := pullRef.NewImageSource(nil) - if err != nil { - return errors.Wrapf(err, "unable to create new image source") - } - _, _, err = imageSource.GetManifest(nil) - if err == nil { - return nil - } - return err -} - -//Decompose breaks up an image name into its parts -func (k *Image) Decompose() error { - if k.beenDecomposed { - return nil - } - k.beenDecomposed = true - k.Transport = k.runtime.config.ImageDefaultTransport - decomposeName := k.Name - for _, transport := range TransportNames { - if strings.HasPrefix(k.Name, transport) { - k.Transport = transport - decomposeName = strings.Replace(k.Name, transport, "", -1) - break - } - } - if k.Transport == "dir:" { - return nil - } - var imageError = fmt.Sprintf("unable to parse '%s'\n", decomposeName) - imgRef, err := reference.Parse(decomposeName) - if err != nil { - return errors.Wrapf(err, imageError) - } - tagged, isTagged := imgRef.(reference.NamedTagged) - k.Tag = "latest" - if isTagged { - k.Tag = tagged.Tag() - } - k.HasRegistry = true - registry := reference.Domain(imgRef.(reference.Named)) - if registry == "" { - k.HasRegistry = false - } - k.ImageName = reference.Path(imgRef.(reference.Named)) - - // account for image names with directories in them like - // umohnani/get-started:part1 - if k.HasRegistry { - k.Registry = registry - k.fqname = k.assembleFqName() - k.PullName = k.assembleFqName() - - registries, err := getRegistries() - if err != nil { - return nil - } - if util.StringInSlice(k.Registry, registries) { - return nil - } - // We need to check if the registry name is legit - _, err = net.LookupHost(k.Registry) - if err == nil { - return nil - } - // Combine the Registry and Image Name together and blank out the Registry Name - k.ImageName = fmt.Sprintf("%s/%s", k.Registry, k.ImageName) - k.Registry = "" - - } - // No Registry means we check the globals registries configuration file - // and assemble a list of candidate sources to try - //searchRegistries, err := GetRegistries() - err = k.findImageOnRegistry() - k.PullName = k.assembleFqName() - if err != nil { - return errors.Wrapf(err, " the image name '%s' is incomplete.", k.Name) - } - return nil -} - -func getTags(nameInput string) (reference.NamedTagged, bool, error) { - inputRef, err := reference.Parse(nameInput) - if err != nil { - return nil, false, errors.Wrapf(err, "unable to obtain tag from input name") - } - tagged, isTagged := inputRef.(reference.NamedTagged) - - return tagged, isTagged, nil -} - -// GetLocalImageName returns the name of the image if it is local as well -// as the image's ID. It will return an empty strings and error if not found. -func (k *Image) GetLocalImageName() (string, string, error) { - localImage, err := k.runtime.GetImage(k.Name) - if err == nil { - k.LocalName = k.Name - return k.Name, localImage.ID, nil - } - localImages, err := k.runtime.GetImages(&ImageFilterParams{}) - if err != nil { - return "", "", errors.Wrapf(err, "unable to find local images") - } - _, isTagged, err := getTags(k.Name) - if err != nil { - return "", "", err - } - for _, image := range localImages { - for _, name := range image.Names() { - imgRef, err := reference.Parse(name) - if err != nil { - continue - } - var imageName string - imageNameOnly := reference.Path(imgRef.(reference.Named)) - if isTagged { - imageNameTag, _, err := getTags(name) - if err != nil { - continue - } - imageName = fmt.Sprintf("%s:%s", imageNameOnly, imageNameTag.Tag()) - } else { - imageName = imageNameOnly - } - - if imageName == k.Name { - k.LocalName = name - return name, image.ID(), nil - } - imageSplit := strings.Split(imageName, "/") - baseName := imageSplit[len(imageSplit)-1] - if baseName == k.Name { - k.LocalName = name - return name, image.ID(), nil - } - } - } - return "", "", errors.Wrapf(storage.ErrImageUnknown, "unable to find image locally") -} - -// HasLatest determines if we have the latest image local -func (k *Image) HasLatest() (bool, error) { - localName, _, err := k.GetLocalImageName() - if err != nil { - return false, err - } - if localName == "" { - return false, nil - } - - fqname, err := k.GetFQName() - if err != nil { - return false, err - } - pullRef, err := alltransports.ParseImageName(fqname) - if err != nil { - return false, err - } - _, _, err = pullRef.(types.ImageSource).GetManifest(nil) - return false, err -} - -// Pull is a wrapper function to pull and image -func (k *Image) Pull(writer io.Writer) error { - // If the image hasn't been decomposed yet - if !k.beenDecomposed { - err := k.Decompose() - if err != nil { - return err - } - } - k.runtime.PullImage(k.PullName, CopyOptions{Writer: writer, SignaturePolicyPath: k.runtime.config.SignaturePolicyPath}) - return nil -} - -// GetRegistries gets the searchable registries from the global registration file. -func GetRegistries() ([]string, error) { - registryConfigPath := "" - envOverride := os.Getenv("REGISTRIES_CONFIG_PATH") - if len(envOverride) > 0 { - registryConfigPath = envOverride - } - searchRegistries, err := sysregistries.GetRegistries(&types.SystemContext{SystemRegistriesConfPath: registryConfigPath}) - if err != nil { - return nil, errors.Errorf("unable to parse the registries.conf file") - } - return searchRegistries, nil -} - -// GetInsecureRegistries obtains the list of inseure registries from the global registration file. -func GetInsecureRegistries() ([]string, error) { - registryConfigPath := "" - envOverride := os.Getenv("REGISTRIES_CONFIG_PATH") - if len(envOverride) > 0 { - registryConfigPath = envOverride - } - registries, err := sysregistries.GetInsecureRegistries(&types.SystemContext{SystemRegistriesConfPath: registryConfigPath}) - if err != nil { - return nil, errors.Errorf("unable to parse the registries.conf file") - } - return registries, nil -} - -// getRegistries returns both searchable and insecure registries from the global conf file. -func getRegistries() ([]string, error) { - var r []string - registries, err := GetRegistries() - if err != nil { - return r, err - } - insecureRegistries, err := GetInsecureRegistries() - if err != nil { - return r, err - } - r = append(registries, insecureRegistries...) - return r, nil -} - -// ImageFilter is a function to determine whether an image is included in -// command output. Images to be outputted are tested using the function. A true -// return will include the image, a false return will exclude it. -type ImageFilter func(*image.Image, *inspect.ImageData) bool - -func (ips imageDecomposeStruct) returnFQName() string { - return fmt.Sprintf("%s%s/%s:%s", ips.transport, ips.registry, ips.imageName, ips.tag) -} - -func getRegistriesToTry(image string, store storage.Store, defaultTransport string) ([]*pullStruct, error) { - var pStructs []*pullStruct - var imageError = fmt.Sprintf("unable to parse '%s'\n", image) - imgRef, err := reference.Parse(image) - if err != nil { - return nil, errors.Wrapf(err, imageError) - } - tagged, isTagged := imgRef.(reference.NamedTagged) - tag := "latest" - if isTagged { - tag = tagged.Tag() - } - hasDomain := true - registry := reference.Domain(imgRef.(reference.Named)) - if registry == "" { - hasDomain = false - } - imageName := reference.Path(imgRef.(reference.Named)) - pImage := imageDecomposeStruct{ - imageName, - tag, - registry, - hasDomain, - defaultTransport, - } - if pImage.hasRegistry { - // If input has a registry, we have to assume they included an image - // name but maybe not a tag - srcRef, err := alltransports.ParseImageName(pImage.returnFQName()) - if err != nil { - return nil, errors.Errorf(imageError) - } - pStruct := &pullStruct{ - image: srcRef.DockerReference().String(), - srcRef: srcRef, - } - pStructs = append(pStructs, pStruct) - } else { - // No registry means we check the globals registries configuration file - // and assemble a list of candidate sources to try - registryConfigPath := "" - envOverride := os.Getenv("REGISTRIES_CONFIG_PATH") - if len(envOverride) > 0 { - registryConfigPath = envOverride - } - searchRegistries, err := sysregistries.GetRegistries(&types.SystemContext{SystemRegistriesConfPath: registryConfigPath}) - if err != nil { - return nil, errors.Wrapf(err, "unable to parse the registries.conf file and"+ - " the image name '%s' is incomplete.", imageName) - } - for _, searchRegistry := range searchRegistries { - pImage.registry = searchRegistry - srcRef, err := alltransports.ParseImageName(pImage.returnFQName()) - if err != nil { - return nil, errors.Errorf("unable to parse '%s'", pImage.returnFQName()) - } - pStruct := &pullStruct{ - image: srcRef.DockerReference().String(), - srcRef: srcRef, - } - pStructs = append(pStructs, pStruct) - } - } - - for _, pStruct := range pStructs { - destRef, err := is.Transport.ParseStoreReference(store, pStruct.image) - if err != nil { - return nil, errors.Errorf("error parsing dest reference name: %v", err) - } - pStruct.dstRef = destRef - } - return pStructs, nil -} - -type pullStruct struct { - image string - srcRef types.ImageReference - dstRef types.ImageReference -} - -func (r *Runtime) getPullStruct(srcRef types.ImageReference, destName string) (*pullStruct, error) { - reference := destName - if srcRef.DockerReference() != nil { - reference = srcRef.DockerReference().String() - } - destRef, err := is.Transport.ParseStoreReference(r.store, reference) - if err != nil { - return nil, errors.Errorf("error parsing dest reference name: %v", err) - } - return &pullStruct{ - image: destName, - srcRef: srcRef, - dstRef: destRef, - }, nil -} - -// returns a list of pullStruct with the srcRef and DstRef based on the transport being used -func (r *Runtime) getPullListFromRef(srcRef types.ImageReference, imgName string, sc *types.SystemContext) ([]*pullStruct, error) { - var pullStructs []*pullStruct - splitArr := strings.Split(imgName, ":") - archFile := splitArr[len(splitArr)-1] - - // supports pulling from docker-archive, oci, and registries - if srcRef.Transport().Name() == DockerArchive { - tarSource, err := tarfile.NewSourceFromFile(archFile) - if err != nil { - return nil, err - } - manifest, err := tarSource.LoadTarManifest() - if err != nil { - return nil, errors.Errorf("error retrieving manifest.json: %v", err) - } - // to pull the first image stored in the tar file - if len(manifest) == 0 { - // use the hex of the digest if no manifest is found - reference, err := getImageDigest(srcRef, sc) - if err != nil { - return nil, err - } - pullInfo, err := r.getPullStruct(srcRef, reference) - if err != nil { - return nil, err - } - pullStructs = append(pullStructs, pullInfo) - } else { - var dest string - if len(manifest[0].RepoTags) > 0 { - dest = manifest[0].RepoTags[0] - } else { - // If the input image has no repotags, we need to feed it a dest anyways - dest, err = getImageDigest(srcRef, sc) - if err != nil { - return nil, err - } - } - pullInfo, err := r.getPullStruct(srcRef, dest) - if err != nil { - return nil, err - } - pullStructs = append(pullStructs, pullInfo) - } - } else if srcRef.Transport().Name() == OCIArchive { - // retrieve the manifest from index.json to access the image name - manifest, err := ociarchive.LoadManifestDescriptor(srcRef) - if err != nil { - return nil, errors.Wrapf(err, "error loading manifest for %q", srcRef) - } - - if manifest.Annotations == nil || manifest.Annotations["org.opencontainers.image.ref.name"] == "" { - return nil, errors.Errorf("error, archive doesn't have a name annotation. Cannot store image with no name") - } - pullInfo, err := r.getPullStruct(srcRef, manifest.Annotations["org.opencontainers.image.ref.name"]) - if err != nil { - return nil, err - } - pullStructs = append(pullStructs, pullInfo) - } else if srcRef.Transport().Name() == DirTransport { - // supports pull from a directory - image := splitArr[1] - // remove leading "/" - if image[:1] == "/" { - image = image[1:] - } - pullInfo, err := r.getPullStruct(srcRef, image) - if err != nil { - return nil, err - } - pullStructs = append(pullStructs, pullInfo) - } else { - pullInfo, err := r.getPullStruct(srcRef, imgName) - if err != nil { - return nil, err - } - pullStructs = append(pullStructs, pullInfo) - } - return pullStructs, nil -} - -// PullImage pulls an image from configured registries -// By default, only the latest tag (or a specific tag if requested) will be -// pulled. If allTags is true, all tags for the requested image will be pulled. -// Signature validation will be performed if the Runtime has been appropriately -// configured -func (r *Runtime) PullImage(imgName string, options CopyOptions) (string, error) { - r.lock.Lock() - defer r.lock.Unlock() - - if !r.valid { - return "", ErrRuntimeStopped - } - - // PullImage copies the image from the source to the destination - var pullStructs []*pullStruct - - signaturePolicyPath := r.config.SignaturePolicyPath - if options.SignaturePolicyPath != "" { - signaturePolicyPath = options.SignaturePolicyPath - } - - sc := common.GetSystemContext(signaturePolicyPath, options.AuthFile, false) - - srcRef, err := alltransports.ParseImageName(imgName) - if err != nil { - // could be trying to pull from registry with short name - pullStructs, err = getRegistriesToTry(imgName, r.store, r.config.ImageDefaultTransport) - if err != nil { - return "", errors.Wrap(err, "error getting default registries to try") - } - } else { - pullStructs, err = r.getPullListFromRef(srcRef, imgName, sc) - if err != nil { - return "", errors.Wrapf(err, "error getting pullStruct info to pull image %q", imgName) - } - } - policyContext, err := getPolicyContext(sc) - if err != nil { - return "", err - } - defer policyContext.Destroy() - - copyOptions := common.GetCopyOptions(options.Writer, signaturePolicyPath, &options.DockerRegistryOptions, nil, options.SigningOptions, options.AuthFile, "", false) - - for _, imageInfo := range pullStructs { - // Print the following statement only when pulling from a docker or atomic registry - if options.Writer != nil && (imageInfo.srcRef.Transport().Name() == Docker || imageInfo.srcRef.Transport().Name() == Atomic) { - io.WriteString(options.Writer, fmt.Sprintf("Trying to pull %s...\n", imageInfo.image)) - } - if err = cp.Image(policyContext, imageInfo.dstRef, imageInfo.srcRef, copyOptions); err != nil { - if options.Writer != nil { - io.WriteString(options.Writer, "Failed\n") - } - } else { - return imageInfo.image, nil - } - } - return "", errors.Wrapf(err, "error pulling image from %q", imgName) -} - -// PushImage pushes the given image to a location described by the given path -func (r *Runtime) PushImage(source string, destination string, options CopyOptions) error { - r.lock.Lock() - defer r.lock.Unlock() - - if !r.valid { - return ErrRuntimeStopped - } - - // PushImage pushes the src image to the destination - //func PushImage(source, destination string, options CopyOptions) error { - if source == "" || destination == "" { - return errors.Wrapf(syscall.EINVAL, "source and destination image names must be specified") - } - - // Get the destination Image Reference - dest, err := alltransports.ParseImageName(destination) - if err != nil { - if hasTransport(destination) { - return errors.Wrapf(err, "error getting destination imageReference for %q", destination) - } - // Try adding the images default transport - destination2 := r.config.ImageDefaultTransport + destination - dest, err = alltransports.ParseImageName(destination2) - if err != nil { - // One last try with docker:// as the transport - destination2 = DefaultTransport + destination - dest, err = alltransports.ParseImageName(destination2) - if err != nil { - return errors.Wrapf(err, "error getting destination imageReference for %q", destination) - } - } - } - - signaturePolicyPath := r.config.SignaturePolicyPath - if options.SignaturePolicyPath != "" { - signaturePolicyPath = options.SignaturePolicyPath - } - - sc := common.GetSystemContext(signaturePolicyPath, options.AuthFile, options.ForceCompress) - - policyContext, err := getPolicyContext(sc) - if err != nil { - return err - } - defer policyContext.Destroy() - - // Look up the source image, expecting it to be in local storage - src, err := is.Transport.ParseStoreReference(r.store, source) - if err != nil { - return errors.Wrapf(err, "error getting source imageReference for %q", source) - } - - copyOptions := common.GetCopyOptions(options.Writer, signaturePolicyPath, nil, &options.DockerRegistryOptions, options.SigningOptions, options.AuthFile, options.ManifestMIMEType, options.ForceCompress) - - // Copy the image to the remote destination - err = cp.Image(policyContext, dest, src, copyOptions) - if err != nil { - return errors.Wrapf(err, "Error copying image to the remote destination") - } - return nil -} - -// TagImage adds a tag to the given image -func (r *Runtime) TagImage(image *storage.Image, tag string) error { - r.lock.Lock() - defer r.lock.Unlock() - - if !r.valid { - return ErrRuntimeStopped - } - - tags, err := r.store.Names(image.ID) - if err != nil { - return err - } - for _, key := range tags { - if key == tag { - return nil - } - } - tags = append(tags, tag) - return r.store.SetNames(image.ID, tags) -} - -// UntagImage removes a tag from the given image -func (r *Runtime) UntagImage(image *storage.Image, tag string) (string, error) { - r.lock.Lock() - defer r.lock.Unlock() - - if !r.valid { - return "", ErrRuntimeStopped - } - - tags, err := r.store.Names(image.ID) - if err != nil { - return "", err - } - for i, key := range tags { - if key == tag { - tags[i] = tags[len(tags)-1] - tags = tags[:len(tags)-1] - break - } - } - if err = r.store.SetNames(image.ID, tags); err != nil { - return "", err - } - return tag, nil -} - // RemoveImage deletes an image from local storage // Images being used by running containers can only be removed if force=true func (r *Runtime) RemoveImage(image *image.Image, force bool) (string, error) { @@ -886,377 +127,30 @@ func (r *Runtime) RemoveImage(image *image.Image, force bool) (string, error) { return image.ID(), image.Remove(force) } -// GetImage retrieves an image matching the given name or hash from system -// storage -// If no matching image can be found, an error is returned -func (r *Runtime) GetImage(image string) (*storage.Image, error) { - r.lock.Lock() - defer r.lock.Unlock() - - if !r.valid { - return nil, ErrRuntimeStopped - } - return r.getImage(image) -} - -func (r *Runtime) getImage(image string) (*storage.Image, error) { - var img *storage.Image - ref, err := is.Transport.ParseStoreReference(r.store, image) - if err == nil { - img, err = is.Transport.GetStoreImage(r.store, ref) - } - if err != nil { - img2, err2 := r.store.Image(image) - if err2 != nil { - if ref == nil { - return nil, errors.Wrapf(err, "error parsing reference to image %q", image) - } - return nil, errors.Wrapf(err, "unable to locate image %q", image) - } - img = img2 - } - return img, nil -} - -// GetImageRef searches for and returns a new types.Image matching the given name or ID in the given store. -func (r *Runtime) GetImageRef(image string) (types.Image, error) { - r.lock.Lock() - defer r.lock.Unlock() - - if !r.valid { - return nil, ErrRuntimeStopped - } - return r.getImageRef(image) - -} - -func (r *Runtime) getImageRef(image string) (types.Image, error) { - img, err := r.getImage(image) - if err != nil { - return nil, errors.Wrapf(err, "unable to locate image %q", image) - } - ref, err := is.Transport.ParseStoreReference(r.store, "@"+img.ID) - if err != nil { - return nil, errors.Wrapf(err, "error parsing reference to image %q", img.ID) - } - imgRef, err := ref.NewImage(nil) - if err != nil { - return nil, errors.Wrapf(err, "error reading image %q", img.ID) - } - return imgRef, nil -} - -// GetImages retrieves all images present in storage -// Filters can be provided which will determine which images are included in the -// output. Multiple filters are handled by ANDing their output, so only images -// matching all filters are included -func (r *Runtime) GetImages(params *ImageFilterParams, filters ...ImageFilter) ([]*image.Image, error) { - r.lock.RLock() - defer r.lock.RUnlock() - - if !r.valid { - return nil, ErrRuntimeStopped - } - - images, err := r.imageRuntime.GetImages() - if err != nil { - return nil, err - } - var imagesFiltered []*image.Image - - for _, img := range images { - info, err := img.Inspect() - - if err != nil { - return nil, err - } - var names []string - if len(img.Names()) > 0 { - names = img.Names() - } else { - names = append(names, "") - } - for _, name := range names { - include := true - if params != nil { - params.ImageName = name - } - for _, filter := range filters { - include = include && filter(img, info) - } - - if include { - newImage := img - imagesFiltered = append(imagesFiltered, newImage) - } - } - } - - return imagesFiltered, nil -} - -// GetHistory gets the history of an image and information about its layers -func (r *Runtime) GetHistory(image string) ([]ociv1.History, []types.BlobInfo, string, error) { - r.lock.RLock() - defer r.lock.RUnlock() - - if !r.valid { - return nil, nil, "", ErrRuntimeStopped - } - - img, err := r.getImage(image) - if err != nil { - return nil, nil, "", errors.Wrapf(err, "no such image %q", image) - } - - src, err := r.getImageRef(image) - if err != nil { - return nil, nil, "", errors.Wrapf(err, "error instantiating image %q", image) - } - - oci, err := src.OCIConfig() - if err != nil { - return nil, nil, "", err - } - - return oci.History, src.LayerInfos(), img.ID, nil -} - -//Import imports an oci format image archive into storage as an image -func (r *Runtime) Import(path, reference string, writer io.Writer, signingOptions image.SigningOptions, imageConfig ociv1.Image) (*image.Image, error) { - return image.Import(path, reference, writer, signingOptions, imageConfig, r.imageRuntime) -} - -// ParseImageFilter takes a set of images and a filter string as input, and returns the libpod.ImageFilterParams struct -func (r *Runtime) ParseImageFilter(imageInput, filter string) (*ImageFilterParams, error) { - r.lock.RLock() - defer r.lock.RUnlock() - - if !r.valid { - return nil, ErrRuntimeStopped - } - - if filter == "" && imageInput == "" { - return nil, nil - } - - var params ImageFilterParams - params.ImageInput = imageInput - - if filter == "" && imageInput != "" { - return ¶ms, nil - } - - images, err := r.imageRuntime.GetImages() - if err != nil { - return nil, err - } - - filterStrings := strings.Split(filter, ",") - for _, param := range filterStrings { - pair := strings.SplitN(param, "=", 2) - switch strings.TrimSpace(pair[0]) { - case "dangling": - if common.IsValidBool(pair[1]) { - params.Dangling = pair[1] - } else { - return nil, fmt.Errorf("invalid filter: '%s=[%s]'", pair[0], pair[1]) - } - case "label": - params.Label = pair[1] - case "before": - if img, err := findImageInSlice(images, pair[1]); err == nil { - info, err := img.Inspect() - if err != nil { - return nil, err - } - params.BeforeImage = *info.Created - } else { - return nil, fmt.Errorf("no such id: %s", pair[0]) - } - case "since": - if img, err := findImageInSlice(images, pair[1]); err == nil { - info, err := img.Inspect() - if err != nil { - return nil, err - } - params.SinceImage = *info.Created - } else { - return nil, fmt.Errorf("no such id: %s``", pair[0]) - } - case "reference": - params.ReferencePattern = pair[1] - default: - return nil, fmt.Errorf("invalid filter: '%s'", pair[0]) - } - } - return ¶ms, nil -} - -// MatchesID returns true if argID is a full or partial match for id -func MatchesID(id, argID string) bool { - return strings.HasPrefix(argID, id) -} - -// MatchesReference returns true if argName is a full or partial match for name -// Partial matches will register only if they match the most specific part of the name available -// For example, take the image docker.io/library/redis:latest -// redis, library/redis, docker.io/library/redis, redis:latest, etc. will match -// But redis:alpine, ry/redis, library, and io/library/redis will not -func MatchesReference(name, argName string) bool { - if argName == "" { - return false - } - splitName := strings.Split(name, ":") - // If the arg contains a tag, we handle it differently than if it does not - if strings.Contains(argName, ":") { - splitArg := strings.Split(argName, ":") - return strings.HasSuffix(splitName[0], splitArg[0]) && (splitName[1] == splitArg[1]) - } - return strings.HasSuffix(splitName[0], argName) -} - -// ParseImageNames parses the names we've stored with an image into a list of -// tagged references and a list of references which contain digests. -func ParseImageNames(names []string) (tags, digests []string, err error) { - for _, name := range names { - if named, err := reference.ParseNamed(name); err == nil { - if digested, ok := named.(reference.Digested); ok { - canonical, err := reference.WithDigest(named, digested.Digest()) - if err == nil { - digests = append(digests, canonical.String()) - } - } else { - if reference.IsNameOnly(named) { - named = reference.TagNameOnly(named) - } - if tagged, ok := named.(reference.Tagged); ok { - namedTagged, err := reference.WithTag(named, tagged.Tag()) - if err == nil { - tags = append(tags, namedTagged.String()) - } - } - } - } - } - return tags, digests, nil -} - -func findImageInSlice(images []*image.Image, ref string) (*image.Image, error) { - for _, image := range images { - if MatchesID(image.ID(), ref) { - return image, nil - } - for _, name := range image.Names() { - if MatchesReference(name, ref) { - return image, nil - } - } +// GetRegistries gets the searchable registries from the global registration file. +func GetRegistries() ([]string, error) { + registryConfigPath := "" + envOverride := os.Getenv("REGISTRIES_CONFIG_PATH") + if len(envOverride) > 0 { + registryConfigPath = envOverride } - return nil, errors.New("could not find image") -} - -// getImageDigest creates an image object and uses the hex value of the digest as the image ID -// for parsing the store reference -func getImageDigest(src types.ImageReference, ctx *types.SystemContext) (string, error) { - newImg, err := src.NewImage(ctx) + searchRegistries, err := sysregistries.GetRegistries(&types.SystemContext{SystemRegistriesConfPath: registryConfigPath}) if err != nil { - return "", err - } - defer newImg.Close() - - digest := newImg.ConfigInfo().Digest - if err = digest.Validate(); err != nil { - return "", errors.Wrapf(err, "error getting config info") + return nil, errors.Errorf("unable to parse the registries.conf file") } - return "@" + digest.Hex(), nil + return searchRegistries, nil } -// getPolicyContext sets up, intializes and returns a new context for the specified policy -func getPolicyContext(ctx *types.SystemContext) (*signature.PolicyContext, error) { - policy, err := signature.DefaultPolicy(ctx) - if err != nil { - return nil, err +// GetInsecureRegistries obtains the list of inseure registries from the global registration file. +func GetInsecureRegistries() ([]string, error) { + registryConfigPath := "" + envOverride := os.Getenv("REGISTRIES_CONFIG_PATH") + if len(envOverride) > 0 { + registryConfigPath = envOverride } - - policyContext, err := signature.NewPolicyContext(policy) + registries, err := sysregistries.GetInsecureRegistries(&types.SystemContext{SystemRegistriesConfPath: registryConfigPath}) if err != nil { - return nil, err - } - return policyContext, nil -} - -// ImageCreatedBefore allows you to filter on images created before -// the given time.Time -func ImageCreatedBefore(createTime time.Time) ImageResultFilter { - return func(i *image.Image) bool { - if i.Created().Before(createTime) { - return true - } - return false - } -} - -// ImageCreatedAfter allows you to filter on images created after -// the given time.Time -func ImageCreatedAfter(createTime time.Time) ImageResultFilter { - return func(i *image.Image) bool { - if i.Created().After(createTime) { - return true - } - return false - } -} - -// ImageDangling allows you to filter images for dangling images -func ImageDangling() ImageResultFilter { - return func(i *image.Image) bool { - if i.Dangling() { - return true - } - return false - } -} - -// ImageLabel allows you to filter by images labels key and/or value -func ImageLabel(labelfilter string) ImageResultFilter { - // We need to handle both label=key and label=key=value - return func(i *image.Image) bool { - var value string - splitFilter := strings.Split(labelfilter, "=") - key := splitFilter[0] - if len(splitFilter) > 1 { - value = splitFilter[1] - } - labels, err := i.Labels() - if err != nil { - return false - } - if len(strings.TrimSpace(labels[key])) > 0 && len(strings.TrimSpace(value)) == 0 { - return true - } - return labels[key] == value - } -} - -// OutputImageFilter allows you to filter by an a specific image name -func OutputImageFilter(userImage *image.Image) ImageResultFilter { - return func(i *image.Image) bool { - return userImage.ID() == i.ID() - } -} - -// FilterImages filters images using a set of predefined fitler funcs -func FilterImages(images []*image.Image, filters []ImageResultFilter) []*image.Image { - var filteredImages []*image.Image - for _, image := range images { - include := true - for _, filter := range filters { - include = include && filter(image) - } - if include { - filteredImages = append(filteredImages, image) - } + return nil, errors.Errorf("unable to parse the registries.conf file") } - return filteredImages + return registries, nil } diff --git a/libpod/util.go b/libpod/util.go index c258af307..106dd4666 100644 --- a/libpod/util.go +++ b/libpod/util.go @@ -47,11 +47,6 @@ func FuncTimer(funcName string) { fmt.Printf("%s executed in %d ms\n", funcName, elapsed) } -// hasTransport determines if the image string contains '://', returns bool -func hasTransport(image string) bool { - return strings.Contains(image, "://") -} - // CopyStringStringMap deep copies a map[string]string and returns the result func CopyStringStringMap(m map[string]string) map[string]string { n := map[string]string{} -- cgit v1.2.3-54-g00ecf