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