2018-03-08 21:45:52 +00:00
|
|
|
|
package image
|
|
|
|
|
|
|
|
|
|
import (
|
2018-04-18 20:48:35 +00:00
|
|
|
|
"context"
|
2018-03-08 21:45:52 +00:00
|
|
|
|
"fmt"
|
|
|
|
|
"io"
|
|
|
|
|
"strings"
|
|
|
|
|
|
|
|
|
|
cp "github.com/containers/image/copy"
|
|
|
|
|
"github.com/containers/image/directory"
|
|
|
|
|
"github.com/containers/image/docker"
|
|
|
|
|
dockerarchive "github.com/containers/image/docker/archive"
|
2018-04-16 18:39:00 +00:00
|
|
|
|
"github.com/containers/image/docker/reference"
|
2018-03-08 21:45:52 +00:00
|
|
|
|
"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"
|
2018-07-28 00:36:12 +00:00
|
|
|
|
"github.com/containers/image/transports"
|
2018-03-08 21:45:52 +00:00
|
|
|
|
"github.com/containers/image/transports/alltransports"
|
|
|
|
|
"github.com/containers/image/types"
|
2018-08-16 10:41:15 +00:00
|
|
|
|
"github.com/containers/libpod/pkg/registries"
|
|
|
|
|
"github.com/containers/libpod/pkg/util"
|
2018-09-12 23:44:58 +00:00
|
|
|
|
multierror "github.com/hashicorp/go-multierror"
|
2018-03-08 21:45:52 +00:00
|
|
|
|
"github.com/pkg/errors"
|
2018-04-16 18:39:00 +00:00
|
|
|
|
"github.com/sirupsen/logrus"
|
2018-03-08 21:45:52 +00:00
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
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()
|
|
|
|
|
// DockerTransport is the transport for docker registries
|
2018-07-28 00:58:56 +00:00
|
|
|
|
DockerTransport = docker.Transport.Name()
|
2018-03-08 21:45:52 +00:00
|
|
|
|
// AtomicTransport is the transport for atomic registries
|
|
|
|
|
AtomicTransport = "atomic"
|
|
|
|
|
// DefaultTransport is a prefix that we apply to an image name
|
2018-07-28 00:40:41 +00:00
|
|
|
|
// NOTE: This is a string prefix, not actually a transport name usable for transports.Get();
|
|
|
|
|
// and because syntaxes of image names are transport-dependent, the prefix is not really interchangeable;
|
|
|
|
|
// each user implicitly assumes the appended string is a Docker-like reference.
|
2018-07-28 00:58:56 +00:00
|
|
|
|
DefaultTransport = DockerTransport + "://"
|
2018-07-23 16:56:24 +00:00
|
|
|
|
// DefaultLocalRegistry is the default local registry for local image operations
|
2018-07-13 21:45:55 +00:00
|
|
|
|
// Remote pulls will still use defined registries
|
2018-07-23 16:56:24 +00:00
|
|
|
|
DefaultLocalRegistry = "localhost"
|
2018-03-08 21:45:52 +00:00
|
|
|
|
)
|
|
|
|
|
|
2018-07-28 04:25:23 +00:00
|
|
|
|
// pullRefPair records a pair of prepared image references to pull.
|
2018-07-18 21:46:14 +00:00
|
|
|
|
type pullRefPair struct {
|
2018-07-18 21:20:36 +00:00
|
|
|
|
image string
|
|
|
|
|
srcRef types.ImageReference
|
|
|
|
|
dstRef types.ImageReference
|
2018-03-08 21:45:52 +00:00
|
|
|
|
}
|
|
|
|
|
|
2018-07-28 03:36:47 +00:00
|
|
|
|
// pullGoal represents the prepared image references and decided behavior to be executed by imagePull
|
|
|
|
|
type pullGoal struct {
|
2018-07-28 04:33:11 +00:00
|
|
|
|
refPairs []pullRefPair
|
2018-07-28 04:42:43 +00:00
|
|
|
|
pullAllPairs bool // Pull all refPairs instead of stopping on first success.
|
|
|
|
|
usedSearchRegistries bool // refPairs construction has depended on registries.GetRegistries()
|
|
|
|
|
searchedRegistries []string // The list of search registries used; set only if usedSearchRegistries
|
2018-07-28 03:36:47 +00:00
|
|
|
|
}
|
|
|
|
|
|
2018-08-01 22:05:52 +00:00
|
|
|
|
// singlePullRefPairGoal returns a no-frills pull goal for the specified reference pair.
|
|
|
|
|
func singlePullRefPairGoal(rp pullRefPair) *pullGoal {
|
|
|
|
|
return &pullGoal{
|
|
|
|
|
refPairs: []pullRefPair{rp},
|
|
|
|
|
pullAllPairs: false, // Does not really make a difference.
|
|
|
|
|
usedSearchRegistries: false,
|
|
|
|
|
searchedRegistries: nil,
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (ir *Runtime) getPullRefPair(srcRef types.ImageReference, destName string) (pullRefPair, error) {
|
2018-07-23 16:56:24 +00:00
|
|
|
|
decomposedDest, err := decompose(destName)
|
|
|
|
|
if err == nil && !decomposedDest.hasRegistry {
|
2018-07-13 21:45:55 +00:00
|
|
|
|
// If the image doesn't have a registry, set it as the default repo
|
2018-07-23 16:56:24 +00:00
|
|
|
|
decomposedDest.registry = DefaultLocalRegistry
|
|
|
|
|
decomposedDest.hasRegistry = true
|
|
|
|
|
destName = decomposedDest.assemble()
|
2018-07-13 21:45:55 +00:00
|
|
|
|
}
|
|
|
|
|
|
2018-03-08 21:45:52 +00:00
|
|
|
|
reference := destName
|
|
|
|
|
if srcRef.DockerReference() != nil {
|
|
|
|
|
reference = srcRef.DockerReference().String()
|
|
|
|
|
}
|
2018-08-01 22:05:52 +00:00
|
|
|
|
destRef, err := is.Transport.ParseStoreReference(ir.store, reference)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return pullRefPair{}, errors.Wrapf(err, "error parsing dest reference name %#v", destName)
|
2018-07-27 00:47:43 +00:00
|
|
|
|
}
|
2018-08-01 22:05:52 +00:00
|
|
|
|
return pullRefPair{
|
|
|
|
|
image: destName,
|
|
|
|
|
srcRef: srcRef,
|
|
|
|
|
dstRef: destRef,
|
|
|
|
|
}, nil
|
2018-03-08 21:45:52 +00:00
|
|
|
|
}
|
|
|
|
|
|
2018-08-01 22:05:52 +00:00
|
|
|
|
// getSinglePullRefPairGoal calls getPullRefPair with the specified parameters, and returns a single-pair goal for the return value.
|
|
|
|
|
func (ir *Runtime) getSinglePullRefPairGoal(srcRef types.ImageReference, destName string) (*pullGoal, error) {
|
|
|
|
|
rp, err := ir.getPullRefPair(srcRef, destName)
|
2018-08-01 21:46:35 +00:00
|
|
|
|
if err != nil {
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
2018-08-01 22:05:52 +00:00
|
|
|
|
return singlePullRefPairGoal(rp), nil
|
2018-08-01 21:36:07 +00:00
|
|
|
|
}
|
|
|
|
|
|
2018-08-01 21:46:35 +00:00
|
|
|
|
// pullGoalFromImageReference returns a pull goal for a single ImageReference, depending on the used transport.
|
|
|
|
|
func (ir *Runtime) pullGoalFromImageReference(ctx context.Context, srcRef types.ImageReference, imgName string, sc *types.SystemContext) (*pullGoal, error) {
|
2018-03-08 21:45:52 +00:00
|
|
|
|
// supports pulling from docker-archive, oci, and registries
|
2018-07-27 00:50:43 +00:00
|
|
|
|
switch srcRef.Transport().Name() {
|
|
|
|
|
case DockerArchive:
|
2018-07-27 00:56:57 +00:00
|
|
|
|
archivePath := srcRef.StringWithinTransport()
|
|
|
|
|
tarSource, err := tarfile.NewSourceFromFile(archivePath)
|
2018-03-08 21:45:52 +00:00
|
|
|
|
if err != nil {
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
|
|
|
|
manifest, err := tarSource.LoadTarManifest()
|
|
|
|
|
|
|
|
|
|
if err != nil {
|
2018-04-24 21:32:07 +00:00
|
|
|
|
return nil, errors.Wrapf(err, "error retrieving manifest.json")
|
2018-03-08 21:45:52 +00:00
|
|
|
|
}
|
|
|
|
|
// 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
|
2018-04-18 20:48:35 +00:00
|
|
|
|
reference, err := getImageDigest(ctx, srcRef, sc)
|
2018-03-08 21:45:52 +00:00
|
|
|
|
if err != nil {
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
2018-08-01 22:05:52 +00:00
|
|
|
|
return ir.getSinglePullRefPairGoal(srcRef, reference)
|
2018-07-27 01:20:25 +00:00
|
|
|
|
}
|
|
|
|
|
|
2018-07-27 01:34:04 +00:00
|
|
|
|
if len(manifest[0].RepoTags) == 0 {
|
2018-07-27 01:20:25 +00:00
|
|
|
|
// If the input image has no repotags, we need to feed it a dest anyways
|
|
|
|
|
digest, err := getImageDigest(ctx, srcRef, sc)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return nil, err
|
2018-03-08 21:45:52 +00:00
|
|
|
|
}
|
2018-08-01 22:05:52 +00:00
|
|
|
|
return ir.getSinglePullRefPairGoal(srcRef, digest)
|
2018-07-27 01:20:25 +00:00
|
|
|
|
}
|
2018-07-27 01:36:25 +00:00
|
|
|
|
|
|
|
|
|
// Need to load in all the repo tags from the manifest
|
2018-08-01 22:05:52 +00:00
|
|
|
|
res := []pullRefPair{}
|
2018-07-28 00:28:23 +00:00
|
|
|
|
for _, dst := range manifest[0].RepoTags {
|
2018-08-01 22:05:52 +00:00
|
|
|
|
pullInfo, err := ir.getPullRefPair(srcRef, dst)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
2018-07-27 01:20:25 +00:00
|
|
|
|
res = append(res, pullInfo)
|
2018-03-08 21:45:52 +00:00
|
|
|
|
}
|
2018-08-01 22:05:52 +00:00
|
|
|
|
return &pullGoal{
|
|
|
|
|
refPairs: res,
|
2018-07-28 04:33:11 +00:00
|
|
|
|
pullAllPairs: true,
|
|
|
|
|
usedSearchRegistries: false,
|
2018-07-28 04:42:43 +00:00
|
|
|
|
searchedRegistries: nil,
|
2018-08-01 22:05:52 +00:00
|
|
|
|
}, nil
|
2018-07-27 01:20:25 +00:00
|
|
|
|
|
2018-07-27 00:50:43 +00:00
|
|
|
|
case OCIArchive:
|
2018-03-08 21:45:52 +00:00
|
|
|
|
// 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)
|
|
|
|
|
}
|
|
|
|
|
|
2018-05-16 15:41:08 +00:00
|
|
|
|
var dest string
|
2018-03-08 21:45:52 +00:00
|
|
|
|
if manifest.Annotations == nil || manifest.Annotations["org.opencontainers.image.ref.name"] == "" {
|
2018-05-16 15:41:08 +00:00
|
|
|
|
// If the input image has no image.ref.name, we need to feed it a dest anyways
|
|
|
|
|
// use the hex of the digest
|
|
|
|
|
dest, err = getImageDigest(ctx, srcRef, sc)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return nil, errors.Wrapf(err, "error getting image digest; image reference not found")
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
dest = manifest.Annotations["org.opencontainers.image.ref.name"]
|
2018-03-08 21:45:52 +00:00
|
|
|
|
}
|
2018-08-01 22:05:52 +00:00
|
|
|
|
return ir.getSinglePullRefPairGoal(srcRef, dest)
|
2018-07-27 01:20:25 +00:00
|
|
|
|
|
2018-07-27 00:50:43 +00:00
|
|
|
|
case DirTransport:
|
2018-07-27 00:56:57 +00:00
|
|
|
|
path := srcRef.StringWithinTransport()
|
|
|
|
|
image := path
|
2018-03-08 21:45:52 +00:00
|
|
|
|
if image[:1] == "/" {
|
2018-07-23 16:56:24 +00:00
|
|
|
|
// Set localhost as the registry so docker.io isn't prepended, and the path becomes the repository
|
|
|
|
|
image = DefaultLocalRegistry + image
|
2018-03-08 21:45:52 +00:00
|
|
|
|
}
|
2018-08-01 22:05:52 +00:00
|
|
|
|
return ir.getSinglePullRefPairGoal(srcRef, image)
|
2018-07-27 01:20:25 +00:00
|
|
|
|
|
2018-07-27 00:50:43 +00:00
|
|
|
|
default:
|
2018-08-01 22:05:52 +00:00
|
|
|
|
return ir.getSinglePullRefPairGoal(srcRef, imgName)
|
2018-03-08 21:45:52 +00:00
|
|
|
|
}
|
2018-07-26 23:16:00 +00:00
|
|
|
|
}
|
|
|
|
|
|
2018-07-28 06:45:11 +00:00
|
|
|
|
// pullImageFromHeuristicSource pulls an image based on inputName, which is heuristically parsed and may involve configured registries.
|
2018-07-28 06:18:57 +00:00
|
|
|
|
// Use pullImageFromReference if the source is known precisely.
|
2018-07-28 06:45:11 +00:00
|
|
|
|
func (ir *Runtime) pullImageFromHeuristicSource(ctx context.Context, inputName string, writer io.Writer, authfile, signaturePolicyPath string, signingOptions SigningOptions, dockerOptions *DockerRegistryOptions, forceSecure bool) ([]string, error) {
|
2018-08-01 22:20:18 +00:00
|
|
|
|
var goal *pullGoal
|
2018-03-08 21:45:52 +00:00
|
|
|
|
sc := GetSystemContext(signaturePolicyPath, authfile, false)
|
2018-07-28 04:54:34 +00:00
|
|
|
|
srcRef, err := alltransports.ParseImageName(inputName)
|
2018-03-08 21:45:52 +00:00
|
|
|
|
if err != nil {
|
|
|
|
|
// could be trying to pull from registry with short name
|
2018-07-28 04:54:34 +00:00
|
|
|
|
goal, err = ir.pullGoalFromPossiblyUnqualifiedName(inputName)
|
2018-03-08 21:45:52 +00:00
|
|
|
|
if err != nil {
|
2018-05-21 17:53:19 +00:00
|
|
|
|
return nil, errors.Wrap(err, "error getting default registries to try")
|
2018-03-08 21:45:52 +00:00
|
|
|
|
}
|
|
|
|
|
} else {
|
2018-08-01 22:20:18 +00:00
|
|
|
|
goal, err = ir.pullGoalFromImageReference(ctx, srcRef, inputName, sc)
|
2018-03-08 21:45:52 +00:00
|
|
|
|
if err != nil {
|
2018-07-28 04:54:34 +00:00
|
|
|
|
return nil, errors.Wrapf(err, "error determining pull goal for image %q", inputName)
|
2018-03-08 21:45:52 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
2018-08-01 22:20:18 +00:00
|
|
|
|
return ir.doPullImage(ctx, sc, *goal, writer, signingOptions, dockerOptions, forceSecure)
|
2018-07-28 05:41:05 +00:00
|
|
|
|
}
|
|
|
|
|
|
2018-07-28 06:18:57 +00:00
|
|
|
|
// pullImageFromReference pulls an image from a types.imageReference.
|
|
|
|
|
func (ir *Runtime) pullImageFromReference(ctx context.Context, srcRef types.ImageReference, writer io.Writer, authfile, signaturePolicyPath string, signingOptions SigningOptions, dockerOptions *DockerRegistryOptions, forceSecure bool) ([]string, error) {
|
|
|
|
|
sc := GetSystemContext(signaturePolicyPath, authfile, false)
|
|
|
|
|
goal, err := ir.pullGoalFromImageReference(ctx, srcRef, transports.ImageName(srcRef), sc)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return nil, errors.Wrapf(err, "error determining pull goal for image %q", transports.ImageName(srcRef))
|
|
|
|
|
}
|
2018-08-01 21:46:35 +00:00
|
|
|
|
return ir.doPullImage(ctx, sc, *goal, writer, signingOptions, dockerOptions, forceSecure)
|
2018-07-28 06:18:57 +00:00
|
|
|
|
}
|
|
|
|
|
|
2018-07-28 05:41:05 +00:00
|
|
|
|
// doPullImage is an internal helper interpreting pullGoal. Almost everyone should call one of the callers of doPullImage instead.
|
|
|
|
|
func (ir *Runtime) doPullImage(ctx context.Context, sc *types.SystemContext, goal pullGoal, writer io.Writer, signingOptions SigningOptions, dockerOptions *DockerRegistryOptions, forceSecure bool) ([]string, error) {
|
2018-03-08 21:45:52 +00:00
|
|
|
|
policyContext, err := getPolicyContext(sc)
|
|
|
|
|
if err != nil {
|
2018-05-21 17:53:19 +00:00
|
|
|
|
return nil, err
|
2018-03-08 21:45:52 +00:00
|
|
|
|
}
|
|
|
|
|
defer policyContext.Destroy()
|
|
|
|
|
|
2018-04-16 18:39:00 +00:00
|
|
|
|
insecureRegistries, err := registries.GetInsecureRegistries()
|
|
|
|
|
if err != nil {
|
2018-05-21 17:53:19 +00:00
|
|
|
|
return nil, err
|
2018-04-16 18:39:00 +00:00
|
|
|
|
}
|
2018-05-21 17:53:19 +00:00
|
|
|
|
var images []string
|
2018-09-12 23:44:58 +00:00
|
|
|
|
var pullErrors *multierror.Error
|
2018-07-28 03:36:47 +00:00
|
|
|
|
for _, imageInfo := range goal.refPairs {
|
2018-07-28 05:34:46 +00:00
|
|
|
|
copyOptions := getCopyOptions(sc, writer, dockerOptions, nil, signingOptions, "", nil)
|
2018-07-28 00:58:56 +00:00
|
|
|
|
if imageInfo.srcRef.Transport().Name() == DockerTransport {
|
2018-07-28 00:36:12 +00:00
|
|
|
|
imgRef := imageInfo.srcRef.DockerReference()
|
|
|
|
|
if imgRef == nil { // This should never happen; such references can’t be created.
|
|
|
|
|
return nil, fmt.Errorf("internal error: DockerTransport reference %s does not have a DockerReference",
|
|
|
|
|
transports.ImageName(imageInfo.srcRef))
|
2018-04-16 18:39:00 +00:00
|
|
|
|
}
|
2018-07-28 00:36:12 +00:00
|
|
|
|
registry := reference.Domain(imgRef)
|
2018-04-16 18:39:00 +00:00
|
|
|
|
|
|
|
|
|
if util.StringInSlice(registry, insecureRegistries) && !forceSecure {
|
|
|
|
|
copyOptions.SourceCtx.DockerInsecureSkipTLSVerify = true
|
|
|
|
|
logrus.Info(fmt.Sprintf("%s is an insecure registry; pulling with tls-verify=false", registry))
|
|
|
|
|
}
|
|
|
|
|
}
|
2018-03-08 21:45:52 +00:00
|
|
|
|
// Print the following statement only when pulling from a docker or atomic registry
|
2018-07-28 00:58:56 +00:00
|
|
|
|
if writer != nil && (imageInfo.srcRef.Transport().Name() == DockerTransport || imageInfo.srcRef.Transport().Name() == AtomicTransport) {
|
2018-03-15 15:06:49 +00:00
|
|
|
|
io.WriteString(writer, fmt.Sprintf("Trying to pull %s...", imageInfo.image))
|
2018-03-08 21:45:52 +00:00
|
|
|
|
}
|
2018-10-17 21:42:05 +00:00
|
|
|
|
_, err = cp.Image(ctx, policyContext, imageInfo.dstRef, imageInfo.srcRef, copyOptions)
|
|
|
|
|
if err != nil {
|
2018-09-12 23:44:58 +00:00
|
|
|
|
pullErrors = multierror.Append(pullErrors, err)
|
2018-09-05 15:01:24 +00:00
|
|
|
|
logrus.Debugf("Error pulling image ref %s: %v", imageInfo.srcRef.StringWithinTransport(), err)
|
2018-03-08 21:45:52 +00:00
|
|
|
|
if writer != nil {
|
|
|
|
|
io.WriteString(writer, "Failed\n")
|
|
|
|
|
}
|
|
|
|
|
} else {
|
2018-07-28 04:25:23 +00:00
|
|
|
|
if !goal.pullAllPairs {
|
2018-05-21 17:53:19 +00:00
|
|
|
|
return []string{imageInfo.image}, nil
|
|
|
|
|
}
|
|
|
|
|
images = append(images, imageInfo.image)
|
2018-03-08 21:45:52 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
2018-05-29 16:32:41 +00:00
|
|
|
|
// If no image was found, we should handle. Lets be nicer to the user and see if we can figure out why.
|
|
|
|
|
if len(images) == 0 {
|
|
|
|
|
registryPath := sysregistries.RegistriesConfPath(&types.SystemContext{})
|
2018-07-28 04:42:43 +00:00
|
|
|
|
if goal.usedSearchRegistries && len(goal.searchedRegistries) == 0 {
|
2018-05-29 16:32:41 +00:00
|
|
|
|
return nil, errors.Errorf("image name provided is a short name and no search registries are defined in %s.", registryPath)
|
|
|
|
|
}
|
2018-08-04 15:30:16 +00:00
|
|
|
|
// If the image passed in was fully-qualified, we will have 1 refpair. Bc the image is fq'd, we dont need to yap about registries.
|
|
|
|
|
if !goal.usedSearchRegistries {
|
2018-09-12 23:44:58 +00:00
|
|
|
|
if pullErrors != nil && len(pullErrors.Errors) > 0 { // this should always be true
|
|
|
|
|
return nil, errors.Wrap(pullErrors.Errors[0], "unable to pull image")
|
|
|
|
|
}
|
2018-08-04 15:30:16 +00:00
|
|
|
|
return nil, errors.Errorf("unable to pull image, or you do not have pull access")
|
|
|
|
|
}
|
2018-09-12 23:44:58 +00:00
|
|
|
|
return nil, pullErrors
|
2018-05-29 16:32:41 +00:00
|
|
|
|
}
|
|
|
|
|
return images, nil
|
2018-03-08 21:45:52 +00:00
|
|
|
|
}
|
|
|
|
|
|
2018-07-18 22:11:15 +00:00
|
|
|
|
// hasShaInInputName returns a bool as to whether the user provided an image name that includes
|
|
|
|
|
// a reference to a specific sha
|
|
|
|
|
func hasShaInInputName(inputName string) bool {
|
|
|
|
|
return strings.Contains(inputName, "@sha256:")
|
|
|
|
|
}
|
|
|
|
|
|
2018-08-01 22:20:18 +00:00
|
|
|
|
// pullGoalFromPossiblyUnqualifiedName looks at inputName and determines the possible
|
|
|
|
|
// image references to try pulling in combination with the registries.conf file as well
|
|
|
|
|
func (ir *Runtime) pullGoalFromPossiblyUnqualifiedName(inputName string) (*pullGoal, error) {
|
2018-07-18 22:58:26 +00:00
|
|
|
|
decomposedImage, err := decompose(inputName)
|
2018-03-08 21:45:52 +00:00
|
|
|
|
if err != nil {
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
|
|
|
|
if decomposedImage.hasRegistry {
|
2018-08-01 22:20:18 +00:00
|
|
|
|
var imageName, destName string
|
2018-07-18 22:58:26 +00:00
|
|
|
|
if hasShaInInputName(inputName) {
|
|
|
|
|
imageName = fmt.Sprintf("%s%s", decomposedImage.transport, inputName)
|
2018-07-12 18:44:26 +00:00
|
|
|
|
} else {
|
|
|
|
|
imageName = decomposedImage.assembleWithTransport()
|
|
|
|
|
}
|
|
|
|
|
srcRef, err := alltransports.ParseImageName(imageName)
|
2018-03-08 21:45:52 +00:00
|
|
|
|
if err != nil {
|
2018-07-18 22:58:26 +00:00
|
|
|
|
return nil, errors.Wrapf(err, "unable to parse '%s'", inputName)
|
2018-03-08 21:45:52 +00:00
|
|
|
|
}
|
2018-07-18 22:58:26 +00:00
|
|
|
|
if hasShaInInputName(inputName) {
|
2018-08-01 22:20:18 +00:00
|
|
|
|
destName = decomposedImage.assemble()
|
2018-07-18 21:27:48 +00:00
|
|
|
|
} else {
|
2018-08-01 22:20:18 +00:00
|
|
|
|
destName = inputName
|
|
|
|
|
}
|
|
|
|
|
destRef, err := is.Transport.ParseStoreReference(ir.store, destName)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return nil, errors.Wrapf(err, "error parsing dest reference name %#v", destName)
|
|
|
|
|
}
|
|
|
|
|
ps := pullRefPair{
|
|
|
|
|
image: inputName,
|
|
|
|
|
srcRef: srcRef,
|
|
|
|
|
dstRef: destRef,
|
2018-07-12 18:44:26 +00:00
|
|
|
|
}
|
2018-08-01 22:20:18 +00:00
|
|
|
|
return singlePullRefPairGoal(ps), nil
|
2018-07-28 04:05:53 +00:00
|
|
|
|
}
|
2018-03-08 21:45:52 +00:00
|
|
|
|
|
2018-07-28 04:05:53 +00:00
|
|
|
|
searchRegistries, err := registries.GetRegistries()
|
|
|
|
|
if err != nil {
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
2018-08-01 22:20:18 +00:00
|
|
|
|
var refPairs []pullRefPair
|
2018-07-28 04:05:53 +00:00
|
|
|
|
for _, registry := range searchRegistries {
|
|
|
|
|
decomposedImage.registry = registry
|
|
|
|
|
imageName := decomposedImage.assembleWithTransport()
|
|
|
|
|
if hasShaInInputName(inputName) {
|
|
|
|
|
imageName = fmt.Sprintf("%s%s/%s", decomposedImage.transport, registry, inputName)
|
|
|
|
|
}
|
|
|
|
|
srcRef, err := alltransports.ParseImageName(imageName)
|
2018-03-08 21:45:52 +00:00
|
|
|
|
if err != nil {
|
2018-07-28 04:05:53 +00:00
|
|
|
|
return nil, errors.Wrapf(err, "unable to parse '%s'", inputName)
|
2018-03-08 21:45:52 +00:00
|
|
|
|
}
|
2018-08-01 22:20:18 +00:00
|
|
|
|
ps := pullRefPair{
|
2018-07-28 04:05:53 +00:00
|
|
|
|
image: decomposedImage.assemble(),
|
|
|
|
|
srcRef: srcRef,
|
2018-03-08 21:45:52 +00:00
|
|
|
|
}
|
2018-08-01 22:20:18 +00:00
|
|
|
|
ps.dstRef, err = is.Transport.ParseStoreReference(ir.store, ps.image)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return nil, errors.Wrapf(err, "error parsing dest reference name %#v", ps.image)
|
|
|
|
|
}
|
|
|
|
|
refPairs = append(refPairs, ps)
|
2018-03-08 21:45:52 +00:00
|
|
|
|
}
|
2018-08-01 22:20:18 +00:00
|
|
|
|
return &pullGoal{
|
|
|
|
|
refPairs: refPairs,
|
2018-07-28 04:33:11 +00:00
|
|
|
|
pullAllPairs: false,
|
|
|
|
|
usedSearchRegistries: true,
|
2018-07-28 04:42:43 +00:00
|
|
|
|
searchedRegistries: searchRegistries,
|
2018-07-28 04:02:49 +00:00
|
|
|
|
}, nil
|
2018-07-18 22:07:15 +00:00
|
|
|
|
}
|