mirror of
https://github.com/containers/podman.git
synced 2025-06-20 00:51:16 +08:00
Prefer read/write images over read/only images
With additional stores there is a risk that you could have multiple images with the same name. IE An older image in a read/only store versus a newer version in the read/write store. This patch will ignore multiple images with the same name iff one is read/write and all of the others are read/only. Fixes: https://github.com/containers/podman/issues/8176 Signed-off-by: Daniel J Walsh <dwalsh@redhat.com>
This commit is contained in:
@ -20,7 +20,11 @@ import (
|
|||||||
// a match on name:tag
|
// a match on name:tag
|
||||||
func findImageInRepotags(search imageParts, images []*Image) (*storage.Image, error) {
|
func findImageInRepotags(search imageParts, images []*Image) (*storage.Image, error) {
|
||||||
_, searchName, searchSuspiciousTagValueForSearch := search.suspiciousRefNameTagValuesForSearch()
|
_, searchName, searchSuspiciousTagValueForSearch := search.suspiciousRefNameTagValuesForSearch()
|
||||||
var results []*storage.Image
|
type Candidate struct {
|
||||||
|
name string
|
||||||
|
image *Image
|
||||||
|
}
|
||||||
|
var candidates []Candidate
|
||||||
for _, image := range images {
|
for _, image := range images {
|
||||||
for _, name := range image.Names() {
|
for _, name := range image.Names() {
|
||||||
d, err := decompose(name)
|
d, err := decompose(name)
|
||||||
@ -29,23 +33,52 @@ func findImageInRepotags(search imageParts, images []*Image) (*storage.Image, er
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
_, dName, dSuspiciousTagValueForSearch := d.suspiciousRefNameTagValuesForSearch()
|
_, dName, dSuspiciousTagValueForSearch := d.suspiciousRefNameTagValuesForSearch()
|
||||||
if dName == searchName && dSuspiciousTagValueForSearch == searchSuspiciousTagValueForSearch {
|
if dSuspiciousTagValueForSearch != searchSuspiciousTagValueForSearch {
|
||||||
results = append(results, image.image)
|
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
// account for registry:/somedir/image
|
if dName == searchName || strings.HasSuffix(dName, "/"+searchName) {
|
||||||
if strings.HasSuffix(dName, "/"+searchName) && dSuspiciousTagValueForSearch == searchSuspiciousTagValueForSearch {
|
candidates = append(candidates, Candidate{
|
||||||
results = append(results, image.image)
|
name: name,
|
||||||
continue
|
image: image,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if len(results) == 0 {
|
if len(candidates) == 0 {
|
||||||
return &storage.Image{}, errors.Errorf("unable to find a name and tag match for %s in repotags", searchName)
|
return nil, errors.Errorf("unable to find a name and tag match for %s in repotags", searchName)
|
||||||
} else if len(results) > 1 {
|
|
||||||
return &storage.Image{}, errors.Wrapf(define.ErrMultipleImages, searchName)
|
|
||||||
}
|
}
|
||||||
return results[0], nil
|
|
||||||
|
// If more then one candidate and the candidates all have same name
|
||||||
|
// and only one is read/write return it.
|
||||||
|
// Othewise return error with the list of candidates
|
||||||
|
if len(candidates) > 1 {
|
||||||
|
var (
|
||||||
|
rwImage *Image
|
||||||
|
rwImageCnt int
|
||||||
|
)
|
||||||
|
names := make(map[string]bool)
|
||||||
|
for _, c := range candidates {
|
||||||
|
names[c.name] = true
|
||||||
|
if !c.image.IsReadOnly() {
|
||||||
|
rwImageCnt++
|
||||||
|
rwImage = c.image
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// If only one name used and have read/write image return it
|
||||||
|
if len(names) == 1 && rwImageCnt == 1 {
|
||||||
|
return rwImage.image, nil
|
||||||
|
}
|
||||||
|
keys := []string{}
|
||||||
|
for k := range names {
|
||||||
|
keys = append(keys, k)
|
||||||
|
}
|
||||||
|
if rwImageCnt > 1 {
|
||||||
|
return nil, errors.Wrapf(define.ErrMultipleImages, "found multiple read/write images %s", strings.Join(keys, ","))
|
||||||
|
} else {
|
||||||
|
return nil, errors.Wrapf(define.ErrMultipleImages, "found multiple read/only images %s", strings.Join(keys, ","))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return candidates[0].image.image, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// getCopyOptions constructs a new containers/image/copy.Options{} struct from the given parameters, inheriting some from sc.
|
// getCopyOptions constructs a new containers/image/copy.Options{} struct from the given parameters, inheriting some from sc.
|
||||||
|
@ -38,7 +38,6 @@ var _ = Describe("Podman image|container exists", func() {
|
|||||||
Expect(session).Should(Exit(0))
|
Expect(session).Should(Exit(0))
|
||||||
})
|
})
|
||||||
It("podman image exists in local storage by short name", func() {
|
It("podman image exists in local storage by short name", func() {
|
||||||
Skip("FIXME-8165: shortnames don't seem to work with quay (#8176)")
|
|
||||||
session := podmanTest.Podman([]string{"image", "exists", "alpine"})
|
session := podmanTest.Podman([]string{"image", "exists", "alpine"})
|
||||||
session.WaitWithDefaultTimeout()
|
session.WaitWithDefaultTimeout()
|
||||||
Expect(session).Should(Exit(0))
|
Expect(session).Should(Exit(0))
|
||||||
|
Reference in New Issue
Block a user