github.com/zhouyu0/docker-note@v0.0.0-20190722021225-b8d3825084db/integration-cli/docker_cli_rmi_test.go (about) 1 package main 2 3 import ( 4 "fmt" 5 "strings" 6 "time" 7 8 "github.com/docker/docker/integration-cli/checker" 9 "github.com/docker/docker/integration-cli/cli" 10 "github.com/docker/docker/integration-cli/cli/build" 11 "github.com/docker/docker/pkg/stringid" 12 "github.com/go-check/check" 13 "gotest.tools/assert" 14 "gotest.tools/icmd" 15 ) 16 17 func (s *DockerSuite) TestRmiWithContainerFails(c *check.C) { 18 errSubstr := "is using it" 19 20 // create a container 21 out, _ := dockerCmd(c, "run", "-d", "busybox", "true") 22 23 cleanedContainerID := strings.TrimSpace(out) 24 25 // try to delete the image 26 out, _, err := dockerCmdWithError("rmi", "busybox") 27 // Container is using image, should not be able to rmi 28 assert.ErrorContains(c, err, "") 29 // Container is using image, error message should contain errSubstr 30 c.Assert(out, checker.Contains, errSubstr, check.Commentf("Container: %q", cleanedContainerID)) 31 32 // make sure it didn't delete the busybox name 33 images, _ := dockerCmd(c, "images") 34 // The name 'busybox' should not have been removed from images 35 c.Assert(images, checker.Contains, "busybox") 36 } 37 38 func (s *DockerSuite) TestRmiTag(c *check.C) { 39 imagesBefore, _ := dockerCmd(c, "images", "-a") 40 dockerCmd(c, "tag", "busybox", "utest:tag1") 41 dockerCmd(c, "tag", "busybox", "utest/docker:tag2") 42 dockerCmd(c, "tag", "busybox", "utest:5000/docker:tag3") 43 { 44 imagesAfter, _ := dockerCmd(c, "images", "-a") 45 c.Assert(strings.Count(imagesAfter, "\n"), checker.Equals, strings.Count(imagesBefore, "\n")+3, check.Commentf("before: %q\n\nafter: %q\n", imagesBefore, imagesAfter)) 46 } 47 dockerCmd(c, "rmi", "utest/docker:tag2") 48 { 49 imagesAfter, _ := dockerCmd(c, "images", "-a") 50 c.Assert(strings.Count(imagesAfter, "\n"), checker.Equals, strings.Count(imagesBefore, "\n")+2, check.Commentf("before: %q\n\nafter: %q\n", imagesBefore, imagesAfter)) 51 } 52 dockerCmd(c, "rmi", "utest:5000/docker:tag3") 53 { 54 imagesAfter, _ := dockerCmd(c, "images", "-a") 55 c.Assert(strings.Count(imagesAfter, "\n"), checker.Equals, strings.Count(imagesBefore, "\n")+1, check.Commentf("before: %q\n\nafter: %q\n", imagesBefore, imagesAfter)) 56 57 } 58 dockerCmd(c, "rmi", "utest:tag1") 59 { 60 imagesAfter, _ := dockerCmd(c, "images", "-a") 61 c.Assert(strings.Count(imagesAfter, "\n"), checker.Equals, strings.Count(imagesBefore, "\n"), check.Commentf("before: %q\n\nafter: %q\n", imagesBefore, imagesAfter)) 62 63 } 64 } 65 66 func (s *DockerSuite) TestRmiImgIDMultipleTag(c *check.C) { 67 out := cli.DockerCmd(c, "run", "-d", "busybox", "/bin/sh", "-c", "mkdir '/busybox-one'").Combined() 68 containerID := strings.TrimSpace(out) 69 70 // Wait for it to exit as cannot commit a running container on Windows, and 71 // it will take a few seconds to exit 72 if testEnv.OSType == "windows" { 73 cli.WaitExited(c, containerID, 60*time.Second) 74 } 75 76 cli.DockerCmd(c, "commit", containerID, "busybox-one") 77 78 imagesBefore := cli.DockerCmd(c, "images", "-a").Combined() 79 cli.DockerCmd(c, "tag", "busybox-one", "busybox-one:tag1") 80 cli.DockerCmd(c, "tag", "busybox-one", "busybox-one:tag2") 81 82 imagesAfter := cli.DockerCmd(c, "images", "-a").Combined() 83 // tag busybox to create 2 more images with same imageID 84 c.Assert(strings.Count(imagesAfter, "\n"), checker.Equals, strings.Count(imagesBefore, "\n")+2, check.Commentf("docker images shows: %q\n", imagesAfter)) 85 86 imgID := inspectField(c, "busybox-one:tag1", "Id") 87 88 // run a container with the image 89 out = runSleepingContainerInImage(c, "busybox-one") 90 containerID = strings.TrimSpace(out) 91 92 // first checkout without force it fails 93 // rmi tagged in multiple repos should have failed without force 94 cli.Docker(cli.Args("rmi", imgID)).Assert(c, icmd.Expected{ 95 ExitCode: 1, 96 Err: fmt.Sprintf("conflict: unable to delete %s (cannot be forced) - image is being used by running container %s", stringid.TruncateID(imgID), stringid.TruncateID(containerID)), 97 }) 98 99 cli.DockerCmd(c, "stop", containerID) 100 cli.DockerCmd(c, "rmi", "-f", imgID) 101 102 imagesAfter = cli.DockerCmd(c, "images", "-a").Combined() 103 // rmi -f failed, image still exists 104 c.Assert(imagesAfter, checker.Not(checker.Contains), imgID[:12], check.Commentf("ImageID:%q; ImagesAfter: %q", imgID, imagesAfter)) 105 } 106 107 func (s *DockerSuite) TestRmiImgIDForce(c *check.C) { 108 out := cli.DockerCmd(c, "run", "-d", "busybox", "/bin/sh", "-c", "mkdir '/busybox-test'").Combined() 109 containerID := strings.TrimSpace(out) 110 111 // Wait for it to exit as cannot commit a running container on Windows, and 112 // it will take a few seconds to exit 113 if testEnv.OSType == "windows" { 114 cli.WaitExited(c, containerID, 60*time.Second) 115 } 116 117 cli.DockerCmd(c, "commit", containerID, "busybox-test") 118 119 imagesBefore := cli.DockerCmd(c, "images", "-a").Combined() 120 cli.DockerCmd(c, "tag", "busybox-test", "utest:tag1") 121 cli.DockerCmd(c, "tag", "busybox-test", "utest:tag2") 122 cli.DockerCmd(c, "tag", "busybox-test", "utest/docker:tag3") 123 cli.DockerCmd(c, "tag", "busybox-test", "utest:5000/docker:tag4") 124 { 125 imagesAfter := cli.DockerCmd(c, "images", "-a").Combined() 126 c.Assert(strings.Count(imagesAfter, "\n"), checker.Equals, strings.Count(imagesBefore, "\n")+4, check.Commentf("before: %q\n\nafter: %q\n", imagesBefore, imagesAfter)) 127 } 128 imgID := inspectField(c, "busybox-test", "Id") 129 130 // first checkout without force it fails 131 cli.Docker(cli.Args("rmi", imgID)).Assert(c, icmd.Expected{ 132 ExitCode: 1, 133 Err: "(must be forced) - image is referenced in multiple repositories", 134 }) 135 136 cli.DockerCmd(c, "rmi", "-f", imgID) 137 { 138 imagesAfter := cli.DockerCmd(c, "images", "-a").Combined() 139 // rmi failed, image still exists 140 c.Assert(imagesAfter, checker.Not(checker.Contains), imgID[:12]) 141 } 142 } 143 144 // See https://github.com/docker/docker/issues/14116 145 func (s *DockerSuite) TestRmiImageIDForceWithRunningContainersAndMultipleTags(c *check.C) { 146 dockerfile := "FROM busybox\nRUN echo test 14116\n" 147 buildImageSuccessfully(c, "test-14116", build.WithDockerfile(dockerfile)) 148 imgID := getIDByName(c, "test-14116") 149 150 newTag := "newtag" 151 dockerCmd(c, "tag", imgID, newTag) 152 runSleepingContainerInImage(c, imgID) 153 154 out, _, err := dockerCmdWithError("rmi", "-f", imgID) 155 // rmi -f should not delete image with running containers 156 assert.ErrorContains(c, err, "") 157 c.Assert(out, checker.Contains, "(cannot be forced) - image is being used by running container") 158 } 159 160 func (s *DockerSuite) TestRmiTagWithExistingContainers(c *check.C) { 161 container := "test-delete-tag" 162 newtag := "busybox:newtag" 163 bb := "busybox:latest" 164 dockerCmd(c, "tag", bb, newtag) 165 166 dockerCmd(c, "run", "--name", container, bb, "/bin/true") 167 168 out, _ := dockerCmd(c, "rmi", newtag) 169 c.Assert(strings.Count(out, "Untagged: "), checker.Equals, 1) 170 } 171 172 func (s *DockerSuite) TestRmiForceWithExistingContainers(c *check.C) { 173 image := "busybox-clone" 174 175 icmd.RunCmd(icmd.Cmd{ 176 Command: []string{dockerBinary, "build", "--no-cache", "-t", image, "-"}, 177 Stdin: strings.NewReader(`FROM busybox 178 MAINTAINER foo`), 179 }).Assert(c, icmd.Success) 180 181 dockerCmd(c, "run", "--name", "test-force-rmi", image, "/bin/true") 182 183 dockerCmd(c, "rmi", "-f", image) 184 } 185 186 func (s *DockerSuite) TestRmiWithMultipleRepositories(c *check.C) { 187 newRepo := "127.0.0.1:5000/busybox" 188 oldRepo := "busybox" 189 newTag := "busybox:test" 190 dockerCmd(c, "tag", oldRepo, newRepo) 191 192 dockerCmd(c, "run", "--name", "test", oldRepo, "touch", "/abcd") 193 194 dockerCmd(c, "commit", "test", newTag) 195 196 out, _ := dockerCmd(c, "rmi", newTag) 197 c.Assert(out, checker.Contains, "Untagged: "+newTag) 198 } 199 200 func (s *DockerSuite) TestRmiForceWithMultipleRepositories(c *check.C) { 201 imageName := "rmiimage" 202 tag1 := imageName + ":tag1" 203 tag2 := imageName + ":tag2" 204 205 buildImageSuccessfully(c, tag1, build.WithDockerfile(`FROM busybox 206 MAINTAINER "docker"`)) 207 dockerCmd(c, "tag", tag1, tag2) 208 209 out, _ := dockerCmd(c, "rmi", "-f", tag2) 210 c.Assert(out, checker.Contains, "Untagged: "+tag2) 211 c.Assert(out, checker.Not(checker.Contains), "Untagged: "+tag1) 212 213 // Check built image still exists 214 images, _ := dockerCmd(c, "images", "-a") 215 c.Assert(images, checker.Contains, imageName, check.Commentf("Built image missing %q; Images: %q", imageName, images)) 216 } 217 218 func (s *DockerSuite) TestRmiBlank(c *check.C) { 219 out, _, err := dockerCmdWithError("rmi", " ") 220 // Should have failed to delete ' ' image 221 assert.ErrorContains(c, err, "") 222 // Wrong error message generated 223 c.Assert(out, checker.Not(checker.Contains), "no such id", check.Commentf("out: %s", out)) 224 // Expected error message not generated 225 c.Assert(out, checker.Contains, "image name cannot be blank", check.Commentf("out: %s", out)) 226 } 227 228 func (s *DockerSuite) TestRmiContainerImageNotFound(c *check.C) { 229 // Build 2 images for testing. 230 imageNames := []string{"test1", "test2"} 231 imageIds := make([]string, 2) 232 for i, name := range imageNames { 233 dockerfile := fmt.Sprintf("FROM busybox\nMAINTAINER %s\nRUN echo %s\n", name, name) 234 buildImageSuccessfully(c, name, build.WithoutCache, build.WithDockerfile(dockerfile)) 235 id := getIDByName(c, name) 236 imageIds[i] = id 237 } 238 239 // Create a long-running container. 240 runSleepingContainerInImage(c, imageNames[0]) 241 242 // Create a stopped container, and then force remove its image. 243 dockerCmd(c, "run", imageNames[1], "true") 244 dockerCmd(c, "rmi", "-f", imageIds[1]) 245 246 // Try to remove the image of the running container and see if it fails as expected. 247 out, _, err := dockerCmdWithError("rmi", "-f", imageIds[0]) 248 // The image of the running container should not be removed. 249 assert.ErrorContains(c, err, "") 250 c.Assert(out, checker.Contains, "image is being used by running container", check.Commentf("out: %s", out)) 251 } 252 253 // #13422 254 func (s *DockerSuite) TestRmiUntagHistoryLayer(c *check.C) { 255 image := "tmp1" 256 // Build an image for testing. 257 dockerfile := `FROM busybox 258 MAINTAINER foo 259 RUN echo 0 #layer0 260 RUN echo 1 #layer1 261 RUN echo 2 #layer2 262 ` 263 buildImageSuccessfully(c, image, build.WithoutCache, build.WithDockerfile(dockerfile)) 264 out, _ := dockerCmd(c, "history", "-q", image) 265 ids := strings.Split(out, "\n") 266 idToTag := ids[2] 267 268 // Tag layer0 to "tmp2". 269 newTag := "tmp2" 270 dockerCmd(c, "tag", idToTag, newTag) 271 // Create a container based on "tmp1". 272 dockerCmd(c, "run", "-d", image, "true") 273 274 // See if the "tmp2" can be untagged. 275 out, _ = dockerCmd(c, "rmi", newTag) 276 // Expected 1 untagged entry 277 c.Assert(strings.Count(out, "Untagged: "), checker.Equals, 1, check.Commentf("out: %s", out)) 278 279 // Now let's add the tag again and create a container based on it. 280 dockerCmd(c, "tag", idToTag, newTag) 281 out, _ = dockerCmd(c, "run", "-d", newTag, "true") 282 cid := strings.TrimSpace(out) 283 284 // At this point we have 2 containers, one based on layer2 and another based on layer0. 285 // Try to untag "tmp2" without the -f flag. 286 out, _, err := dockerCmdWithError("rmi", newTag) 287 // should not be untagged without the -f flag 288 assert.ErrorContains(c, err, "") 289 c.Assert(out, checker.Contains, cid[:12]) 290 c.Assert(out, checker.Contains, "(must force)") 291 292 // Add the -f flag and test again. 293 out, _ = dockerCmd(c, "rmi", "-f", newTag) 294 // should be allowed to untag with the -f flag 295 c.Assert(out, checker.Contains, fmt.Sprintf("Untagged: %s:latest", newTag)) 296 } 297 298 func (*DockerSuite) TestRmiParentImageFail(c *check.C) { 299 buildImageSuccessfully(c, "test", build.WithDockerfile(` 300 FROM busybox 301 RUN echo hello`)) 302 303 id := inspectField(c, "busybox", "ID") 304 out, _, err := dockerCmdWithError("rmi", id) 305 assert.ErrorContains(c, err, "") 306 if !strings.Contains(out, "image has dependent child images") { 307 c.Fatalf("rmi should have failed because it's a parent image, got %s", out) 308 } 309 } 310 311 func (s *DockerSuite) TestRmiWithParentInUse(c *check.C) { 312 out, _ := dockerCmd(c, "create", "busybox") 313 cID := strings.TrimSpace(out) 314 315 out, _ = dockerCmd(c, "commit", cID) 316 imageID := strings.TrimSpace(out) 317 318 out, _ = dockerCmd(c, "create", imageID) 319 cID = strings.TrimSpace(out) 320 321 out, _ = dockerCmd(c, "commit", cID) 322 imageID = strings.TrimSpace(out) 323 324 dockerCmd(c, "rmi", imageID) 325 } 326 327 // #18873 328 func (s *DockerSuite) TestRmiByIDHardConflict(c *check.C) { 329 dockerCmd(c, "create", "busybox") 330 331 imgID := inspectField(c, "busybox:latest", "Id") 332 333 _, _, err := dockerCmdWithError("rmi", imgID[:12]) 334 assert.ErrorContains(c, err, "") 335 336 // check that tag was not removed 337 imgID2 := inspectField(c, "busybox:latest", "Id") 338 c.Assert(imgID, checker.Equals, imgID2) 339 }