diff options
author | baude <bbaude@redhat.com> | 2018-03-08 15:45:52 -0600 |
---|---|---|
committer | Atomic Bot <atomic-devel@projectatomic.io> | 2018-03-14 20:21:31 +0000 |
commit | b85b217f55993955da9ad0cae7735747b2f24390 (patch) | |
tree | 3e633600e50bf3bedc9bdc59abe789fa01f55601 /libpod/image/pull.go | |
parent | bc358eb396aa87f3122f0449945efc03ed64bfd2 (diff) | |
download | podman-b85b217f55993955da9ad0cae7735747b2f24390.tar.gz podman-b85b217f55993955da9ad0cae7735747b2f24390.tar.bz2 podman-b85b217f55993955da9ad0cae7735747b2f24390.zip |
Stage3 Image Library
This represents the stage3 implementation for the image library. At this point, we
are moving the image-centric functions to pkg/image including migration of args and
object-oriented references. This is a not a one-for-one migration of funcs and some
funcs will need to continue to reside in runtime_img as they are overly specific to
libpod and probably not useful to others.
Signed-off-by: baude <bbaude@redhat.com>
Closes: #484
Approved by: baude
Diffstat (limited to 'libpod/image/pull.go')
-rw-r--r-- | libpod/image/pull.go | 246 |
1 files changed, 246 insertions, 0 deletions
diff --git a/libpod/image/pull.go b/libpod/image/pull.go new file mode 100644 index 000000000..52ef175d4 --- /dev/null +++ b/libpod/image/pull.go @@ -0,0 +1,246 @@ +package image + +import ( + "fmt" + "io" + "os" + "strings" + + 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/tarfile" + ociarchive "github.com/containers/image/oci/archive" + "github.com/containers/image/pkg/sysregistries" + is "github.com/containers/image/storage" + "github.com/containers/image/tarball" + "github.com/containers/image/transports/alltransports" + "github.com/containers/image/types" + "github.com/pkg/errors" +) + +var ( + // DockerArchive is the transport we prepend to an image name + // when saving to docker-archive + DockerArchive = dockerarchive.Transport.Name() + // OCIArchive is the transport we prepend to an image name + // when saving to oci-archive + OCIArchive = ociarchive.Transport.Name() + // DirTransport is the transport for pushing and pulling + // images to and from a directory + DirTransport = directory.Transport.Name() + // TransportNames are the supported transports in string form + TransportNames = [...]string{DefaultTransport, DockerArchive, OCIArchive, "ostree:", "dir:"} + // TarballTransport is the transport for importing a tar archive + // and creating a filesystem image + TarballTransport = tarball.Transport.Name() + // DockerTransport is the transport for docker registries + DockerTransport = docker.Transport.Name() + "://" + // AtomicTransport is the transport for atomic registries + AtomicTransport = "atomic" + // DefaultTransport is a prefix that we apply to an image name + DefaultTransport = DockerTransport +) + +type pullStruct struct { + image string + srcRef types.ImageReference + dstRef types.ImageReference +} + +func (ir *Runtime) getPullStruct(srcRef types.ImageReference, destName string) (*pullStruct, error) { + reference := destName + if srcRef.DockerReference() != nil { + reference = srcRef.DockerReference().String() + } + destRef, err := is.Transport.ParseStoreReference(ir.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 (ir *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 := ir.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 := ir.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 := ir.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 := ir.getPullStruct(srcRef, image) + if err != nil { + return nil, err + } + pullStructs = append(pullStructs, pullInfo) + } else { + pullInfo, err := ir.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. +func (i *Image) pullImage(writer io.Writer, authfile, signaturePolicyPath string, signingOptions SigningOptions, dockerOptions *DockerRegistryOptions) (string, error) { + // pullImage copies the image from the source to the destination + var pullStructs []*pullStruct + sc := GetSystemContext(signaturePolicyPath, authfile, false) + srcRef, err := alltransports.ParseImageName(i.InputName) + if err != nil { + // could be trying to pull from registry with short name + pullStructs, err = i.createNamesToPull() + if err != nil { + return "", errors.Wrap(err, "error getting default registries to try") + } + } else { + pullStructs, err = i.imageruntime.getPullListFromRef(srcRef, i.InputName, sc) + if err != nil { + return "", errors.Wrapf(err, "error getting pullStruct info to pull image %q", i.InputName) + } + } + policyContext, err := getPolicyContext(sc) + if err != nil { + return "", err + } + defer policyContext.Destroy() + + copyOptions := getCopyOptions(writer, signaturePolicyPath, dockerOptions, nil, signingOptions, authfile, "", false) + for _, imageInfo := range pullStructs { + // Print the following statement only when pulling from a docker or atomic registry + if writer != nil && (imageInfo.srcRef.Transport().Name() == DockerTransport || imageInfo.srcRef.Transport().Name() == AtomicTransport) { + io.WriteString(writer, fmt.Sprintf("Trying to pull %s...\n", imageInfo.image)) + } + if err = cp.Image(policyContext, imageInfo.dstRef, imageInfo.srcRef, copyOptions); err != nil { + if writer != nil { + io.WriteString(writer, "Failed\n") + } + } else { + return imageInfo.image, nil + } + } + return "", errors.Wrapf(err, "error pulling image from") +} + +// createNamesToPull looks at a decomposed image and determines the possible +// images names to try pulling in combination with the registries.conf file as well +func (i *Image) createNamesToPull() ([]*pullStruct, error) { + var pullNames []*pullStruct + decomposedImage, err := decompose(i.InputName) + if err != nil { + return nil, err + } + if decomposedImage.hasRegistry { + srcRef, err := alltransports.ParseImageName(decomposedImage.assembleWithTransport()) + if err != nil { + return nil, errors.Errorf("unable to parse '%s'", i.InputName) + } + ps := pullStruct{ + image: i.InputName, + srcRef: srcRef, + } + pullNames = append(pullNames, &ps) + + } else { + 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, err + } + for _, registry := range searchRegistries { + decomposedImage.registry = registry + srcRef, err := alltransports.ParseImageName(decomposedImage.assembleWithTransport()) + if err != nil { + return nil, errors.Errorf("unable to parse '%s'", i.InputName) + } + ps := pullStruct{ + image: decomposedImage.assemble(), + srcRef: srcRef, + } + pullNames = append(pullNames, &ps) + } + } + + for _, pStruct := range pullNames { + destRef, err := is.Transport.ParseStoreReference(i.imageruntime.store, pStruct.image) + if err != nil { + return nil, errors.Errorf("error parsing dest reference name: %v", err) + } + pStruct.dstRef = destRef + } + + return pullNames, nil +} |