mirror of
				https://github.com/moby/moby.git
				synced 2022-11-09 12:21:53 -05:00 
			
		
		
		
	'docker rmi -f IMAGE_ID' untag all names and delete the image
If an image has been tagged to multiple repos and tags, 'docker
rmi -f IMAGE_ID' will just untag one random repo instead of
untagging all and deleting the image. This patch implement
this. This commit is composed of:
        *untag all names and delete the image
        *add test to this feature
        *modify commandline/cli.md to explain this
Signed-off-by: Deng Guangxing <dengguangxing@huawei.com>
			
			
This commit is contained in:
		
							parent
							
								
									418195a4fb
								
							
						
					
					
						commit
						795a58fb44
					
				
					 3 changed files with 74 additions and 13 deletions
				
			
		| 
						 | 
				
			
			@ -30,6 +30,7 @@ func (daemon *Daemon) imgDeleteHelper(name string, list *[]types.ImageDelete, fi
 | 
			
		|||
		repoName, tag string
 | 
			
		||||
		tags          = []string{}
 | 
			
		||||
	)
 | 
			
		||||
	repoAndTags := make(map[string][]string)
 | 
			
		||||
 | 
			
		||||
	// FIXME: please respect DRY and centralize repo+tag parsing in a single central place! -- shykes
 | 
			
		||||
	repoName, tag = parsers.ParseRepositoryTag(name)
 | 
			
		||||
| 
						 | 
				
			
			@ -68,19 +69,25 @@ func (daemon *Daemon) imgDeleteHelper(name string, list *[]types.ImageDelete, fi
 | 
			
		|||
			if repoName == "" || repoName == parsedRepo {
 | 
			
		||||
				repoName = parsedRepo
 | 
			
		||||
				if parsedTag != "" {
 | 
			
		||||
					tags = append(tags, parsedTag)
 | 
			
		||||
					repoAndTags[repoName] = append(repoAndTags[repoName], parsedTag)
 | 
			
		||||
				}
 | 
			
		||||
			} else if repoName != parsedRepo && !force && first {
 | 
			
		||||
				// the id belongs to multiple repos, like base:latest and user:test,
 | 
			
		||||
				// in that case return conflict
 | 
			
		||||
				return fmt.Errorf("Conflict, cannot delete image %s because it is tagged in multiple repositories, use -f to force", name)
 | 
			
		||||
			} else {
 | 
			
		||||
				//the id belongs to multiple repos, with -f just delete all
 | 
			
		||||
				repoName = parsedRepo
 | 
			
		||||
				if parsedTag != "" {
 | 
			
		||||
					repoAndTags[repoName] = append(repoAndTags[repoName], parsedTag)
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	} else {
 | 
			
		||||
		tags = append(tags, tag)
 | 
			
		||||
		repoAndTags[repoName] = append(repoAndTags[repoName], tag)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if !first && len(tags) > 0 {
 | 
			
		||||
	if !first && len(repoAndTags) > 0 {
 | 
			
		||||
		return nil
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -91,16 +98,18 @@ func (daemon *Daemon) imgDeleteHelper(name string, list *[]types.ImageDelete, fi
 | 
			
		|||
	}
 | 
			
		||||
 | 
			
		||||
	// Untag the current image
 | 
			
		||||
	for _, tag := range tags {
 | 
			
		||||
		tagDeleted, err := daemon.Repositories().Delete(repoName, tag)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return err
 | 
			
		||||
		}
 | 
			
		||||
		if tagDeleted {
 | 
			
		||||
			*list = append(*list, types.ImageDelete{
 | 
			
		||||
				Untagged: utils.ImageReference(repoName, tag),
 | 
			
		||||
			})
 | 
			
		||||
			daemon.EventsService.Log("untag", img.ID, "")
 | 
			
		||||
	for repoName, tags := range repoAndTags {
 | 
			
		||||
		for _, tag := range tags {
 | 
			
		||||
			tagDeleted, err := daemon.Repositories().Delete(repoName, tag)
 | 
			
		||||
			if err != nil {
 | 
			
		||||
				return err
 | 
			
		||||
			}
 | 
			
		||||
			if tagDeleted {
 | 
			
		||||
				*list = append(*list, types.ImageDelete{
 | 
			
		||||
					Untagged: utils.ImageReference(repoName, tag),
 | 
			
		||||
				})
 | 
			
		||||
				daemon.EventsService.Log("untag", img.ID, "")
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	tags = daemon.Repositories().ByID()[img.ID]
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1794,6 +1794,21 @@ before the image is removed.
 | 
			
		|||
    Untagged: test:latest
 | 
			
		||||
    Deleted: fd484f19954f4920da7ff372b5067f5b7ddb2fd3830cecd17b96ea9e286ba5b8
 | 
			
		||||
 | 
			
		||||
If you use the `-f` flag and specify the image's short or long ID, then this
 | 
			
		||||
command untags and removes all images that match the specified ID.
 | 
			
		||||
 | 
			
		||||
    $ docker images
 | 
			
		||||
    REPOSITORY                TAG                 IMAGE ID            CREATED             SIZE
 | 
			
		||||
    test1                     latest              fd484f19954f        23 seconds ago      7 B (virtual 4.964 MB)
 | 
			
		||||
    test                      latest              fd484f19954f        23 seconds ago      7 B (virtual 4.964 MB)
 | 
			
		||||
    test2                     latest              fd484f19954f        23 seconds ago      7 B (virtual 4.964 MB)
 | 
			
		||||
 | 
			
		||||
    $ docker rmi -f fd484f19954f
 | 
			
		||||
    Untagged: test1:latest
 | 
			
		||||
    Untagged: test:latest
 | 
			
		||||
    Untagged: test2:latest
 | 
			
		||||
    Deleted: fd484f19954f4920da7ff372b5067f5b7ddb2fd3830cecd17b96ea9e286ba5b8
 | 
			
		||||
 | 
			
		||||
An image pulled by digest has no tag associated with it:
 | 
			
		||||
 | 
			
		||||
    $ docker images --digests
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -77,6 +77,43 @@ func TestRmiTag(t *testing.T) {
 | 
			
		|||
	logDone("rmi - tag,rmi - tagging the same images multiple times then removing tags")
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestRmiImgIDForce(t *testing.T) {
 | 
			
		||||
	runCmd := exec.Command(dockerBinary, "run", "-d", "busybox", "/bin/sh", "-c", "mkdir '/busybox-test'")
 | 
			
		||||
	out, _, err := runCommandWithOutput(runCmd)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		t.Fatalf("failed to create a container:%s, %v", out, err)
 | 
			
		||||
	}
 | 
			
		||||
	containerID := strings.TrimSpace(out)
 | 
			
		||||
	runCmd = exec.Command(dockerBinary, "commit", containerID, "busybox-test")
 | 
			
		||||
	out, _, err = runCommandWithOutput(runCmd)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		t.Fatalf("failed to commit a new busybox-test:%s, %v", out, err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	imagesBefore, _, _ := dockerCmd(t, "images", "-a")
 | 
			
		||||
	dockerCmd(t, "tag", "busybox-test", "utest:tag1")
 | 
			
		||||
	dockerCmd(t, "tag", "busybox-test", "utest:tag2")
 | 
			
		||||
	dockerCmd(t, "tag", "busybox-test", "utest/docker:tag3")
 | 
			
		||||
	dockerCmd(t, "tag", "busybox-test", "utest:5000/docker:tag4")
 | 
			
		||||
	{
 | 
			
		||||
		imagesAfter, _, _ := dockerCmd(t, "images", "-a")
 | 
			
		||||
		if strings.Count(imagesAfter, "\n") != strings.Count(imagesBefore, "\n")+4 {
 | 
			
		||||
			t.Fatalf("tag busybox to create 4 more images with same imageID; docker images shows: %q\n", imagesAfter)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	out, _, _ = dockerCmd(t, "inspect", "-f", "{{.Id}}", "busybox-test")
 | 
			
		||||
	imgID := strings.TrimSpace(out)
 | 
			
		||||
	dockerCmd(t, "rmi", "-f", imgID)
 | 
			
		||||
	{
 | 
			
		||||
		imagesAfter, _, _ := dockerCmd(t, "images", "-a")
 | 
			
		||||
		if strings.Contains(imagesAfter, imgID[:12]) {
 | 
			
		||||
			t.Fatalf("rmi -f %s failed, image still exists: %q\n\n", imgID, imagesAfter)
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
	}
 | 
			
		||||
	logDone("rmi - imgID,rmi -f imgID  delete all tagged repos of specific imgID")
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestRmiTagWithExistingContainers(t *testing.T) {
 | 
			
		||||
	defer deleteAllContainers()
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue