summaryrefslogtreecommitdiff
path: root/libpod/image/pull.go
diff options
context:
space:
mode:
authorValentin Rothberg <rothberg@redhat.com>2020-10-07 16:58:53 +0200
committerValentin Rothberg <rothberg@redhat.com>2020-11-13 15:40:06 +0100
commit8e4a42aa429c6dec0d5face7c69554d8a0677e96 (patch)
treebbfff77e7b32a8b46af6f57d42965a7751bec18e /libpod/image/pull.go
parent0b1a60ec27928a40ac827148c1517098612616bd (diff)
downloadpodman-8e4a42aa429c6dec0d5face7c69554d8a0677e96.tar.gz
podman-8e4a42aa429c6dec0d5face7c69554d8a0677e96.tar.bz2
podman-8e4a42aa429c6dec0d5face7c69554d8a0677e96.zip
short-name aliasing
Add support for short-name aliasing. Signed-off-by: Valentin Rothberg <rothberg@redhat.com>
Diffstat (limited to 'libpod/image/pull.go')
-rw-r--r--libpod/image/pull.go129
1 files changed, 70 insertions, 59 deletions
diff --git a/libpod/image/pull.go b/libpod/image/pull.go
index 65acdf427..2a2d16252 100644
--- a/libpod/image/pull.go
+++ b/libpod/image/pull.go
@@ -4,6 +4,7 @@ import (
"context"
"fmt"
"io"
+ "os"
"path/filepath"
"strings"
@@ -15,13 +16,14 @@ import (
dockerarchive "github.com/containers/image/v5/docker/archive"
ociarchive "github.com/containers/image/v5/oci/archive"
oci "github.com/containers/image/v5/oci/layout"
+ "github.com/containers/image/v5/pkg/shortnames"
is "github.com/containers/image/v5/storage"
"github.com/containers/image/v5/transports"
"github.com/containers/image/v5/transports/alltransports"
"github.com/containers/image/v5/types"
"github.com/containers/podman/v2/libpod/events"
+ "github.com/containers/podman/v2/pkg/errorhandling"
"github.com/containers/podman/v2/pkg/registries"
- "github.com/hashicorp/go-multierror"
"github.com/opentracing/opentracing-go"
"github.com/pkg/errors"
"github.com/sirupsen/logrus"
@@ -56,9 +58,10 @@ var (
// pullRefPair records a pair of prepared image references to pull.
type pullRefPair struct {
- image string
- srcRef types.ImageReference
- dstRef types.ImageReference
+ image string
+ srcRef types.ImageReference
+ dstRef types.ImageReference
+ resolvedShortname *shortnames.PullCandidate // if set, must be recorded after successful pull
}
// cleanUpFunc is a function prototype for clean-up functions.
@@ -66,11 +69,11 @@ type cleanUpFunc func() error
// pullGoal represents the prepared image references and decided behavior to be executed by imagePull
type pullGoal struct {
- refPairs []pullRefPair
- 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
- cleanUpFuncs []cleanUpFunc // Mainly used to close long-lived objects (e.g., an archive.Reader)
+ refPairs []pullRefPair
+ pullAllPairs bool // Pull all refPairs instead of stopping on first success.
+ cleanUpFuncs []cleanUpFunc // Mainly used to close long-lived objects (e.g., an archive.Reader)
+ shortName string // Set when pulling a short name
+ resolved *shortnames.Resolved // Set when pulling a short name
}
// cleanUp invokes all cleanUpFuncs. Certain resources may not be available
@@ -86,10 +89,8 @@ func (p *pullGoal) cleanUp() {
// 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,
+ refPairs: []pullRefPair{rp},
+ pullAllPairs: false, // Does not really make a difference.
}
}
@@ -193,11 +194,9 @@ func (ir *Runtime) pullGoalFromImageReference(ctx context.Context, srcRef types.
}
return &pullGoal{
- pullAllPairs: true,
- usedSearchRegistries: false,
- refPairs: pairs,
- searchedRegistries: nil,
- cleanUpFuncs: []cleanUpFunc{reader.Close},
+ pullAllPairs: true,
+ refPairs: pairs,
+ cleanUpFuncs: []cleanUpFunc{reader.Close},
}, nil
case OCIArchive:
@@ -267,7 +266,7 @@ func (ir *Runtime) pullImageFromHeuristicSource(ctx context.Context, inputName s
if srcTransport != nil && srcTransport.Name() != DockerTransport {
return nil, err
}
- goal, err = ir.pullGoalFromPossiblyUnqualifiedName(inputName)
+ goal, err = ir.pullGoalFromPossiblyUnqualifiedName(sc, writer, inputName)
if err != nil {
return nil, errors.Wrap(err, "error getting default registries to try")
}
@@ -325,7 +324,7 @@ func (ir *Runtime) doPullImage(ctx context.Context, sc *types.SystemContext, goa
var (
images []string
- pullErrors *multierror.Error
+ pullErrors []error
)
for _, imageInfo := range goal.refPairs {
@@ -348,12 +347,17 @@ func (ir *Runtime) doPullImage(ctx context.Context, sc *types.SystemContext, goa
_, err = cp.Image(ctx, policyContext, imageInfo.dstRef, imageInfo.srcRef, copyOptions)
return err
}, retryOptions); err != nil {
- pullErrors = multierror.Append(pullErrors, err)
+ pullErrors = append(pullErrors, err)
logrus.Debugf("Error pulling image ref %s: %v", imageInfo.srcRef.StringWithinTransport(), err)
if writer != nil {
_, _ = io.WriteString(writer, cleanErrorMessage(err))
}
} else {
+ if imageInfo.resolvedShortname != nil {
+ if err := imageInfo.resolvedShortname.Record(); err != nil {
+ logrus.Errorf("Error recording short-name alias %q: %v", imageInfo.resolvedShortname.Value.String(), err)
+ }
+ }
if !goal.pullAllPairs {
ir.newImageEvent(events.Pull, "")
return []string{imageInfo.image}, nil
@@ -361,68 +365,75 @@ func (ir *Runtime) doPullImage(ctx context.Context, sc *types.SystemContext, goa
images = append(images, imageInfo.image)
}
}
- // If no image was found, we should handle. Lets be nicer to the user and see if we can figure out why.
+ // 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 {
- if goal.usedSearchRegistries && len(goal.searchedRegistries) == 0 {
- return nil, errors.Errorf("image name provided is a short name and no search registries are defined in the registries config file.")
- }
- // If the image passed in was fully-qualified, we will have 1 refpair. Bc the image is fq'd, we don't need to yap about registries.
- if !goal.usedSearchRegistries {
- if pullErrors != nil && len(pullErrors.Errors) > 0 { // this should always be true
- return nil, pullErrors.Errors[0]
- }
- return nil, errors.Errorf("unable to pull image, or you do not have pull access")
+ if goal.resolved != nil {
+ return nil, goal.resolved.FormatPullErrors(pullErrors)
}
- return nil, errors.Cause(pullErrors)
- }
- if len(images) > 0 {
- ir.newImageEvent(events.Pull, images[0])
+ return nil, errorhandling.JoinErrors(pullErrors)
}
+
+ ir.newImageEvent(events.Pull, images[0])
return images, nil
}
+// getShortNameMode looks up the `CONTAINERS_SHORT_NAME_ALIASING` environment
+// variable. If it's "on", return `nil` to use the defaults from
+// containers/image and the registries.conf files on the system. If it's
+// "off", empty or unset, return types.ShortNameModeDisabled to turn off
+// short-name aliasing by default.
+//
+// TODO: remove this function once we want to default to short-name aliasing.
+func getShortNameMode() *types.ShortNameMode {
+ env := os.Getenv("CONTAINERS_SHORT_NAME_ALIASING")
+ if strings.ToLower(env) == "on" {
+ return nil // default to whatever registries.conf and c/image decide
+ }
+ mode := types.ShortNameModeDisabled
+ return &mode
+}
+
// 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) {
- decomposedImage, err := decompose(inputName)
+func (ir *Runtime) pullGoalFromPossiblyUnqualifiedName(sys *types.SystemContext, writer io.Writer, inputName string) (*pullGoal, error) {
+ if sys == nil {
+ sys = &types.SystemContext{}
+ }
+ sys.ShortNameMode = getShortNameMode()
+
+ resolved, err := shortnames.Resolve(sys, inputName)
if err != nil {
return nil, err
}
- if decomposedImage.hasRegistry {
- srcRef, err := docker.ParseReference("//" + inputName)
- if err != nil {
- return nil, errors.Wrapf(err, "unable to parse '%s'", inputName)
+ if desc := resolved.Description(); len(desc) > 0 {
+ logrus.Debug(desc)
+ if writer != nil {
+ if _, err := writer.Write([]byte(desc + "\n")); err != nil {
+ return nil, err
+ }
}
- return ir.getSinglePullRefPairGoal(srcRef, inputName)
}
- searchRegistries, err := registries.GetRegistries()
- if err != nil {
- return nil, err
- }
- refPairs := make([]pullRefPair, 0, len(searchRegistries))
- for _, registry := range searchRegistries {
- ref, err := decomposedImage.referenceWithRegistry(registry)
+ refPairs := []pullRefPair{}
+ for i, candidate := range resolved.PullCandidates {
+ srcRef, err := docker.NewReference(candidate.Value)
if err != nil {
return nil, err
}
- imageName := ref.String()
- srcRef, err := docker.ParseReference("//" + imageName)
- if err != nil {
- return nil, errors.Wrapf(err, "unable to parse '%s'", imageName)
- }
- ps, err := ir.getPullRefPair(srcRef, imageName)
+ ps, err := ir.getPullRefPair(srcRef, candidate.Value.String())
if err != nil {
return nil, err
}
+ ps.resolvedShortname = &resolved.PullCandidates[i]
refPairs = append(refPairs, ps)
}
return &pullGoal{
- refPairs: refPairs,
- pullAllPairs: false,
- usedSearchRegistries: true,
- searchedRegistries: searchRegistries,
+ refPairs: refPairs,
+ pullAllPairs: false,
+ shortName: inputName,
+ resolved: resolved,
}, nil
}