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