Skip to content

Commit 397db59

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 397db59

File tree

7 files changed

+46
-57
lines changed

7 files changed

+46
-57
lines changed

libimage/filters.go

Lines changed: 10 additions & 2 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
}

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: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -58,15 +58,11 @@ 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.
63-
require.Equal(t, origDigest.String(), image.Digest().String(), "digests of pulled images should match")
64-
6561
// NOTE: we're recording two digests. One for the image and one for the
6662
// manifest list we chose it from.
6763
digests := image.Digests()
6864
require.Len(t, digests, 2)
69-
require.Equal(t, origDigest.String(), digests[0].String(), "first recoreded digest should be the one of the image")
65+
require.Equal(t, origDigest.String(), digests[1].String(), "second recoreded digest should be the one of the image")
7066

7167
// containers/podman/issues/12729: make sure manifest lookup returns
7268
// the correct error for both 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: 26 additions & 43 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,21 +316,31 @@ 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-
img, err := r.store.Image(candidate)
326+
327+
// First parse the reference and then look up the image to properly
328+
// support digests.
329+
ref, err := storageTransport.Transport.ParseStoreReference(r.store, candidate)
330+
if err != nil {
331+
return nil, nil
332+
}
333+
img, err := storageTransport.Transport.GetStoreImage(r.store, ref)
327334
if err != nil && !errors.Is(err, storage.ErrImageUnknown) {
328335
return nil, err
329336
}
330337
if img == nil {
331338
return nil, nil
332339
}
333-
ref, err := storageTransport.Transport.ParseStoreReference(r.store, img.ID)
340+
// The image may have been looked up by digest which may have referred
341+
// to the parent manifest list. Hence, reparse the reference with the
342+
// ID to make sure we resolve the correct object.
343+
ref, err = storageTransport.Transport.ParseStoreReference(r.store, img.ID)
334344
if err != nil {
335345
return nil, err
336346
}
@@ -414,61 +424,34 @@ func (r *Runtime) lookupImageInLocalStorage(name, candidate string, options *Loo
414424
return image, nil
415425
}
416426

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 {
427+
// lookupImageInRepoTags attempts to match named against any image in the local
428+
// containers storage by comparing the name to all known repo tags.
429+
func (r *Runtime) lookupImageInRepoTags(name string, namedName reference.Named, options *LookupImageOptions) (*Image, string, error) {
430+
if namedName == nil {
437431
return nil, "", fmt.Errorf("%s: %w", name, storage.ErrImageUnknown)
438432
}
439433

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-
}
434+
if _, isDigested := namedName.(reference.Digested); isDigested {
457435
return nil, "", fmt.Errorf("%s: %w", name, storage.ErrImageUnknown)
458436
}
459437

460438
if !shortnames.IsShortName(name) {
461439
return nil, "", fmt.Errorf("%s: %w", name, storage.ErrImageUnknown)
462440
}
463441

464-
named = reference.TagNameOnly(named) // Make sure to add ":latest" if needed
465-
namedTagged, isNammedTagged := named.(reference.NamedTagged)
442+
namedName = reference.TagNameOnly(namedName) // Docker compat: make sure to add ":latest" if needed
443+
namedTagged, isNammedTagged := namedName.(reference.NamedTagged)
466444
if !isNammedTagged {
467445
// NOTE: this should never happen since we already know it's
468446
// not a digested reference.
469447
return nil, "", fmt.Errorf("%s: %w (could not cast to tagged)", name, storage.ErrImageUnknown)
470448
}
471449

450+
allImages, err := r.ListImages(context.Background(), nil, nil)
451+
if err != nil {
452+
return nil, "", err
453+
}
454+
472455
for _, image := range allImages {
473456
named, err := image.inRepoTags(namedTagged)
474457
if err != nil {

0 commit comments

Comments
 (0)