mirror of
https://github.com/containers/podman.git
synced 2025-08-06 03:19:52 +08:00
Removing tagged images change in behavior
An image name is really just a tag. When an image has multiple tags, we should be able to "delete" the one of its tags without harm. In this case, the "delete' is really a form of Untag (removing the tag from the image). If an image has multiple tags and the user tries to delete by ID without force, this should be denied because when you delete by ID there is no distinguishing it like image tags. Signed-off-by: baude <bbaude@redhat.com> Closes: #528 Approved by: mheon
This commit is contained in:
@ -685,3 +685,60 @@ func Import(path, reference string, writer io.Writer, signingOptions SigningOpti
|
||||
}
|
||||
return runtime.NewFromLocal(reference)
|
||||
}
|
||||
|
||||
// MatchRepoTag takes a string and tries to match it against an
|
||||
// image's repotags
|
||||
func (i *Image) MatchRepoTag(input string) (string, error) {
|
||||
results := make(map[int][]string)
|
||||
var maxCount int
|
||||
// first check if we have an exact match with the input
|
||||
if util.StringInSlice(input, i.Names()) {
|
||||
return input, nil
|
||||
}
|
||||
// next check if we are missing the tag
|
||||
dcImage, err := decompose(input)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
for _, repoName := range i.Names() {
|
||||
count := 0
|
||||
dcRepoName, err := decompose(repoName)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
if dcRepoName.registry == dcImage.registry && dcImage.registry != "" {
|
||||
count++
|
||||
}
|
||||
if dcRepoName.name == dcImage.name && dcImage.name != "" {
|
||||
count++
|
||||
} else if splitString(dcRepoName.name) == splitString(dcImage.name) {
|
||||
count++
|
||||
}
|
||||
if dcRepoName.tag == dcImage.tag {
|
||||
count++
|
||||
}
|
||||
results[count] = append(results[count], repoName)
|
||||
if count > maxCount {
|
||||
maxCount = count
|
||||
}
|
||||
}
|
||||
if maxCount == 0 {
|
||||
return "", errors.Errorf("unable to match user input to any specific repotag")
|
||||
}
|
||||
if len(results[maxCount]) > 1 {
|
||||
return "", errors.Errorf("user input matched multiple repotags for the image")
|
||||
}
|
||||
return results[maxCount][0], nil
|
||||
}
|
||||
|
||||
// splitString splits input string by / and returns the last array item
|
||||
func splitString(input string) string {
|
||||
split := strings.Split(input, "/")
|
||||
return split[len(split)-1]
|
||||
}
|
||||
|
||||
// InputIsID returns a bool if the user input for an image
|
||||
// is the image's partial or full id
|
||||
func (i *Image) InputIsID() bool {
|
||||
return strings.HasPrefix(i.ID(), i.InputName)
|
||||
}
|
||||
|
@ -136,3 +136,52 @@ func TestImage_New(t *testing.T) {
|
||||
// Shutdown the runtime and remove the temporary storage
|
||||
cleanup(workdir, ir)
|
||||
}
|
||||
|
||||
// TestImage_MatchRepoTag tests the various inputs we need to match
|
||||
// against an image's reponames
|
||||
func TestImage_MatchRepoTag(t *testing.T) {
|
||||
//Set up
|
||||
workdir, err := mkWorkDir()
|
||||
assert.NoError(t, err)
|
||||
|
||||
so := storage.StoreOptions{
|
||||
RunRoot: workdir,
|
||||
GraphRoot: workdir,
|
||||
}
|
||||
ir, err := NewImageRuntimeFromOptions(so)
|
||||
assert.NoError(t, err)
|
||||
newImage, err := ir.New("busybox", "", "", os.Stdout, nil, SigningOptions{})
|
||||
assert.NoError(t, err)
|
||||
err = newImage.TagImage("foo:latest")
|
||||
assert.NoError(t, err)
|
||||
err = newImage.TagImage("foo:bar")
|
||||
assert.NoError(t, err)
|
||||
|
||||
// Tests start here.
|
||||
for _, name := range bbNames {
|
||||
repoTag, err := newImage.MatchRepoTag(name)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, "docker.io/library/busybox:latest", repoTag)
|
||||
}
|
||||
|
||||
// Test against tagged images of busybox
|
||||
// foo should resolve to foo:latest
|
||||
repoTag, err := newImage.MatchRepoTag("foo")
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, "foo:latest", repoTag)
|
||||
|
||||
// foo:bar should resolve to foo:bar
|
||||
repoTag, err = newImage.MatchRepoTag("foo:bar")
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, "foo:bar", repoTag)
|
||||
// Shutdown the runtime and remove the temporary storage
|
||||
cleanup(workdir, ir)
|
||||
}
|
||||
|
||||
// Test_splitString tests the splitString function in image that
|
||||
// takes input and splits on / and returns the last array item
|
||||
func Test_splitString(t *testing.T) {
|
||||
assert.Equal(t, splitString("foo/bar"), "bar")
|
||||
assert.Equal(t, splitString("a/foo/bar"), "bar")
|
||||
assert.Equal(t, splitString("bar"), "bar")
|
||||
}
|
||||
|
Reference in New Issue
Block a user