Skip to content

Commit c8c9030

Browse files
openshift-merge-robotvrothberg
authored andcommitted
Merge pull request containers#1503 from vrothberg/fix-podman-18445
libimage: fix reference filters Signed-off-by: Valentin Rothberg <vrothberg@redhat.com>
2 parents e1ea4d9 + a146adf commit c8c9030

File tree

7 files changed

+57
-55
lines changed

7 files changed

+57
-55
lines changed

libimage/filters.go

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -178,7 +178,7 @@ func (r *Runtime) compileImageFilters(ctx context.Context, options *ListImagesOp
178178
filter = filterManifest(ctx, manifest)
179179

180180
case "reference":
181-
filter = filterReferences(value)
181+
filter = filterReferences(r, value)
182182

183183
case "until":
184184
until, err := r.until(value)
@@ -268,8 +268,15 @@ func filterManifest(ctx context.Context, value bool) filterFunc {
268268
}
269269

270270
// filterReferences creates a reference filter for matching the specified value.
271-
func filterReferences(value string) filterFunc {
271+
func filterReferences(r *Runtime, value string) filterFunc {
272+
lookedUp, _, _ := r.LookupImage(value, nil)
272273
return func(img *Image) (bool, error) {
274+
if lookedUp != nil {
275+
if lookedUp.ID() == img.ID() {
276+
return true, nil
277+
}
278+
}
279+
273280
refs, err := img.NamesReferences()
274281
if err != nil {
275282
return false, err
@@ -306,6 +313,7 @@ func filterReferences(value string) filterFunc {
306313
}
307314
}
308315
}
316+
309317
return false, nil
310318
}
311319
}
@@ -389,7 +397,12 @@ func filterID(value string) filterFunc {
389397
// filterDigest creates an digest filter for matching the specified value.
390398
func filterDigest(value string) filterFunc {
391399
return func(img *Image) (bool, error) {
392-
return string(img.Digest()) == value, nil
400+
for _, d := range img.Digests() {
401+
if string(d) == value {
402+
return true, nil
403+
}
404+
}
405+
return false, nil
393406
}
394407
}
395408

libimage/filters_test.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,8 @@ func TestFilterReference(t *testing.T) {
6262
{"quay.io/libpod/*", 2},
6363
{"busybox", 1},
6464
{"alpine", 1},
65+
{"alpine@" + alpine.Digest().String(), 0},
66+
{"quay.io/libpod/alpine@" + alpine.Digest().String(), 1},
6567
} {
6668
listOptions := &ListImagesOptions{
6769
Filters: []string{"reference=" + test.filter},

libimage/image_test.go

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -58,10 +58,7 @@ func TestImageFunctions(t *testing.T) {
5858
// Just make sure that the ID has 64 characters.
5959
require.True(t, len(image.ID()) == 64, "ID should be 64 characters long")
6060

61-
// Make sure that the image we pulled by digest is the same one we
62-
// pulled by tag.
6361
require.Equal(t, origDigest.String(), image.Digest().String(), "digests of pulled images should match")
64-
6562
// NOTE: we're recording two digests. One for the image and one for the
6663
// manifest list we chose it from.
6764
digests := image.Digests()

libimage/normalize.go

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -100,22 +100,22 @@ func ToNameTagPairs(repoTags []reference.Named) ([]NameTagPair, error) {
100100
// normalizeTaggedDigestedString strips the tag off the specified string iff it
101101
// is tagged and digested. Note that the tag is entirely ignored to match
102102
// Docker behavior.
103-
func normalizeTaggedDigestedString(s string) (string, error) {
103+
func normalizeTaggedDigestedString(s string) (string, reference.Named, error) {
104104
// Note that the input string is not expected to be parseable, so we
105105
// return it verbatim in error cases.
106106
ref, err := reference.Parse(s)
107107
if err != nil {
108-
return "", err
108+
return "", nil, err
109109
}
110110
named, ok := ref.(reference.Named)
111111
if !ok {
112-
return s, nil
112+
return s, nil, nil
113113
}
114114
named, err = normalizeTaggedDigestedNamed(named)
115115
if err != nil {
116-
return "", err
116+
return "", nil, err
117117
}
118-
return named.String(), nil
118+
return named.String(), named, nil
119119
}
120120

121121
// normalizeTaggedDigestedNamed strips the tag off the specified named

libimage/normalize_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -132,7 +132,7 @@ func TestNormalizeTaggedDigestedString(t *testing.T) {
132132
{"localhost/fedora:anothertag" + digestSuffix, "localhost/fedora" + digestSuffix},
133133
{"localhost:5000/fedora:v1.2.3.4.5" + digestSuffix, "localhost:5000/fedora" + digestSuffix},
134134
} {
135-
res, err := normalizeTaggedDigestedString(test.input)
135+
res, _, err := normalizeTaggedDigestedString(test.input)
136136
if test.expected == "" {
137137
assert.Error(t, err, "%v", test)
138138
} else {

libimage/pull.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,7 @@ func (r *Runtime) Pull(ctx context.Context, name string, pullPolicy config.PullP
8686
// Docker compat: strip off the tag iff name is tagged and digested
8787
// (e.g., fedora:latest@sha256...). In that case, the tag is stripped
8888
// off and entirely ignored. The digest is the sole source of truth.
89-
normalizedName, normalizeError := normalizeTaggedDigestedString(name)
89+
normalizedName, _, normalizeError := normalizeTaggedDigestedString(name)
9090
if normalizeError != nil {
9191
return nil, normalizeError
9292
}

libimage/runtime.go

Lines changed: 32 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -239,7 +239,7 @@ func (r *Runtime) LookupImage(name string, options *LookupImageOptions) (*Image,
239239
// Docker compat: strip off the tag iff name is tagged and digested
240240
// (e.g., fedora:latest@sha256...). In that case, the tag is stripped
241241
// off and entirely ignored. The digest is the sole source of truth.
242-
normalizedName, err := normalizeTaggedDigestedString(name)
242+
normalizedName, namedName, err := normalizeTaggedDigestedString(name)
243243
if err != nil {
244244
return nil, "", err
245245
}
@@ -316,19 +316,36 @@ func (r *Runtime) LookupImage(name string, options *LookupImageOptions) (*Image,
316316
return img, name, err
317317
}
318318

319-
return r.lookupImageInDigestsAndRepoTags(name, options)
319+
return r.lookupImageInRepoTags(name, namedName, options)
320320
}
321321

322322
// lookupImageInLocalStorage looks up the specified candidate for name in the
323323
// storage and checks whether it's matching the system context.
324324
func (r *Runtime) lookupImageInLocalStorage(name, candidate string, options *LookupImageOptions) (*Image, error) {
325325
logrus.Debugf("Trying %q ...", candidate)
326+
327+
// First, try store.Image() which will properly work on IDs (but not on
328+
// digests).
326329
img, err := r.store.Image(candidate)
327330
if err != nil && !errors.Is(err, storage.ErrImageUnknown) {
328331
return nil, err
329332
}
330333
if img == nil {
331-
return nil, nil
334+
// Second, try parsing the candidate into a storage reference
335+
// which will work with digests. However, we must reparse the
336+
// reference another time below since an ordinary image may
337+
// have been referenced via its parent (manifest list) digest.
338+
ref, err := storageTransport.Transport.ParseStoreReference(r.store, candidate)
339+
if err != nil {
340+
return nil, nil
341+
}
342+
img, err = storageTransport.Transport.GetStoreImage(r.store, ref)
343+
if err != nil && !errors.Is(err, storage.ErrImageUnknown) {
344+
return nil, err
345+
}
346+
if img == nil {
347+
return nil, nil
348+
}
332349
}
333350
ref, err := storageTransport.Transport.ParseStoreReference(r.store, img.ID)
334351
if err != nil {
@@ -414,61 +431,34 @@ func (r *Runtime) lookupImageInLocalStorage(name, candidate string, options *Loo
414431
return image, nil
415432
}
416433

417-
// lookupImageInDigestsAndRepoTags attempts to match name against any image in
418-
// the local containers storage. If name is digested, it will be compared
419-
// against image digests. Otherwise, it will be looked up in the repo tags.
420-
func (r *Runtime) lookupImageInDigestsAndRepoTags(name string, options *LookupImageOptions) (*Image, string, error) {
421-
// Until now, we've tried very hard to find an image but now it is time
422-
// for limbo. If the image includes a digest that we couldn't detect
423-
// verbatim in the storage, we must have a look at all digests of all
424-
// images. Those may change over time (e.g., via manifest lists).
425-
// Both Podman and Buildah want us to do that dance.
426-
allImages, err := r.ListImages(context.Background(), nil, nil)
427-
if err != nil {
428-
return nil, "", err
429-
}
430-
431-
ref, err := reference.Parse(name) // Warning! This is not ParseNormalizedNamed
432-
if err != nil {
433-
return nil, "", err
434-
}
435-
named, isNamed := ref.(reference.Named)
436-
if !isNamed {
434+
// lookupImageInRepoTags attempts to match named against any image in the local
435+
// containers storage by comparing the name to all known repo tags.
436+
func (r *Runtime) lookupImageInRepoTags(name string, namedName reference.Named, options *LookupImageOptions) (*Image, string, error) {
437+
if namedName == nil {
437438
return nil, "", fmt.Errorf("%s: %w", name, storage.ErrImageUnknown)
438439
}
439440

440-
digested, isDigested := named.(reference.Digested)
441-
if isDigested {
442-
logrus.Debug("Looking for image with matching recorded digests")
443-
digest := digested.Digest()
444-
for _, image := range allImages {
445-
for _, d := range image.Digests() {
446-
if d != digest {
447-
continue
448-
}
449-
// Also make sure that the matching image fits all criteria (e.g., manifest list).
450-
if _, err := r.lookupImageInLocalStorage(name, image.ID(), options); err != nil {
451-
return nil, "", err
452-
}
453-
return image, name, nil
454-
455-
}
456-
}
441+
if _, isDigested := namedName.(reference.Digested); isDigested {
457442
return nil, "", fmt.Errorf("%s: %w", name, storage.ErrImageUnknown)
458443
}
459444

460445
if !shortnames.IsShortName(name) {
461446
return nil, "", fmt.Errorf("%s: %w", name, storage.ErrImageUnknown)
462447
}
463448

464-
named = reference.TagNameOnly(named) // Make sure to add ":latest" if needed
465-
namedTagged, isNammedTagged := named.(reference.NamedTagged)
449+
namedName = reference.TagNameOnly(namedName) // Docker compat: make sure to add ":latest" if needed
450+
namedTagged, isNammedTagged := namedName.(reference.NamedTagged)
466451
if !isNammedTagged {
467452
// NOTE: this should never happen since we already know it's
468453
// not a digested reference.
469454
return nil, "", fmt.Errorf("%s: %w (could not cast to tagged)", name, storage.ErrImageUnknown)
470455
}
471456

457+
allImages, err := r.ListImages(context.Background(), nil, nil)
458+
if err != nil {
459+
return nil, "", err
460+
}
461+
472462
for _, image := range allImages {
473463
named, err := image.inRepoTags(namedTagged)
474464
if err != nil {

0 commit comments

Comments
 (0)