2014-09-09 20:32:14 -04:00
package main
import (
2015-04-22 17:12:46 -04:00
"fmt"
2014-09-09 20:32:14 -04:00
"strings"
2016-01-26 15:22:37 -05:00
"time"
2015-04-18 12:46:47 -04:00
2016-12-30 12:23:00 -05:00
"github.com/docker/docker/integration-cli/checker"
2017-04-11 15:18:30 -04:00
"github.com/docker/docker/integration-cli/cli"
2017-03-23 13:35:22 -04:00
"github.com/docker/docker/integration-cli/cli/build"
2015-11-18 17:20:54 -05:00
"github.com/docker/docker/pkg/stringid"
2015-04-18 12:46:47 -04:00
"github.com/go-check/check"
2019-04-04 09:23:19 -04:00
"gotest.tools/assert"
2018-06-11 09:32:11 -04:00
"gotest.tools/icmd"
2014-09-09 20:32:14 -04:00
)
2015-04-18 12:46:47 -04:00
func ( s * DockerSuite ) TestRmiWithContainerFails ( c * check . C ) {
2014-09-09 20:32:14 -04:00
errSubstr := "is using it"
// create a container
2015-10-09 23:32:55 -04:00
out , _ := dockerCmd ( c , "run" , "-d" , "busybox" , "true" )
2014-09-09 20:32:14 -04:00
2015-04-06 09:21:18 -04:00
cleanedContainerID := strings . TrimSpace ( out )
2014-09-09 20:32:14 -04:00
// try to delete the image
2015-10-09 23:32:55 -04:00
out , _ , err := dockerCmdWithError ( "rmi" , "busybox" )
// Container is using image, should not be able to rmi
2019-04-04 09:23:19 -04:00
assert . ErrorContains ( c , err , "" )
2015-10-09 23:32:55 -04:00
// Container is using image, error message should contain errSubstr
c . Assert ( out , checker . Contains , errSubstr , check . Commentf ( "Container: %q" , cleanedContainerID ) )
2014-09-09 20:32:14 -04:00
// make sure it didn't delete the busybox name
2015-04-18 12:46:47 -04:00
images , _ := dockerCmd ( c , "images" )
2015-10-09 23:32:55 -04:00
// The name 'busybox' should not have been removed from images
c . Assert ( images , checker . Contains , "busybox" )
2014-09-09 20:32:14 -04:00
}
2015-04-18 12:46:47 -04:00
func ( s * DockerSuite ) TestRmiTag ( c * check . C ) {
imagesBefore , _ := dockerCmd ( c , "images" , "-a" )
dockerCmd ( c , "tag" , "busybox" , "utest:tag1" )
dockerCmd ( c , "tag" , "busybox" , "utest/docker:tag2" )
dockerCmd ( c , "tag" , "busybox" , "utest:5000/docker:tag3" )
2014-09-09 20:32:14 -04:00
{
2015-04-18 12:46:47 -04:00
imagesAfter , _ := dockerCmd ( c , "images" , "-a" )
2015-10-09 23:32:55 -04:00
c . Assert ( strings . Count ( imagesAfter , "\n" ) , checker . Equals , strings . Count ( imagesBefore , "\n" ) + 3 , check . Commentf ( "before: %q\n\nafter: %q\n" , imagesBefore , imagesAfter ) )
2014-09-09 20:32:14 -04:00
}
2015-04-18 12:46:47 -04:00
dockerCmd ( c , "rmi" , "utest/docker:tag2" )
2014-09-09 20:32:14 -04:00
{
2015-04-18 12:46:47 -04:00
imagesAfter , _ := dockerCmd ( c , "images" , "-a" )
2015-10-09 23:32:55 -04:00
c . Assert ( strings . Count ( imagesAfter , "\n" ) , checker . Equals , strings . Count ( imagesBefore , "\n" ) + 2 , check . Commentf ( "before: %q\n\nafter: %q\n" , imagesBefore , imagesAfter ) )
2014-09-09 20:32:14 -04:00
}
2015-04-18 12:46:47 -04:00
dockerCmd ( c , "rmi" , "utest:5000/docker:tag3" )
2014-09-09 20:32:14 -04:00
{
2015-04-18 12:46:47 -04:00
imagesAfter , _ := dockerCmd ( c , "images" , "-a" )
2015-10-09 23:32:55 -04:00
c . Assert ( strings . Count ( imagesAfter , "\n" ) , checker . Equals , strings . Count ( imagesBefore , "\n" ) + 1 , check . Commentf ( "before: %q\n\nafter: %q\n" , imagesBefore , imagesAfter ) )
2014-09-09 20:32:14 -04:00
}
2015-04-18 12:46:47 -04:00
dockerCmd ( c , "rmi" , "utest:tag1" )
2014-09-09 20:32:14 -04:00
{
2015-04-18 12:46:47 -04:00
imagesAfter , _ := dockerCmd ( c , "images" , "-a" )
2015-10-09 23:32:55 -04:00
c . Assert ( strings . Count ( imagesAfter , "\n" ) , checker . Equals , strings . Count ( imagesBefore , "\n" ) , check . Commentf ( "before: %q\n\nafter: %q\n" , imagesBefore , imagesAfter ) )
2014-09-09 20:32:14 -04:00
}
}
2014-10-02 19:39:39 -04:00
2015-05-29 14:12:58 -04:00
func ( s * DockerSuite ) TestRmiImgIDMultipleTag ( c * check . C ) {
2017-04-11 15:18:30 -04:00
out := cli . DockerCmd ( c , "run" , "-d" , "busybox" , "/bin/sh" , "-c" , "mkdir '/busybox-one'" ) . Combined ( )
2015-05-29 14:12:58 -04:00
containerID := strings . TrimSpace ( out )
2016-01-26 15:22:37 -05:00
// Wait for it to exit as cannot commit a running container on Windows, and
// it will take a few seconds to exit
2018-01-15 09:32:06 -05:00
if testEnv . OSType == "windows" {
2017-04-11 15:18:30 -04:00
cli . WaitExited ( c , containerID , 60 * time . Second )
2016-01-26 15:22:37 -05:00
}
2017-04-11 15:18:30 -04:00
cli . DockerCmd ( c , "commit" , containerID , "busybox-one" )
2015-05-29 14:12:58 -04:00
2017-04-11 15:18:30 -04:00
imagesBefore := cli . DockerCmd ( c , "images" , "-a" ) . Combined ( )
cli . DockerCmd ( c , "tag" , "busybox-one" , "busybox-one:tag1" )
cli . DockerCmd ( c , "tag" , "busybox-one" , "busybox-one:tag2" )
2015-05-29 14:12:58 -04:00
2017-04-11 15:18:30 -04:00
imagesAfter := cli . DockerCmd ( c , "images" , "-a" ) . Combined ( )
2015-10-09 23:32:55 -04:00
// tag busybox to create 2 more images with same imageID
c . Assert ( strings . Count ( imagesAfter , "\n" ) , checker . Equals , strings . Count ( imagesBefore , "\n" ) + 2 , check . Commentf ( "docker images shows: %q\n" , imagesAfter ) )
2015-05-29 14:12:58 -04:00
2016-01-28 09:19:25 -05:00
imgID := inspectField ( c , "busybox-one:tag1" , "Id" )
2015-05-29 14:12:58 -04:00
// run a container with the image
2017-04-16 17:39:30 -04:00
out = runSleepingContainerInImage ( c , "busybox-one" )
2015-05-29 14:12:58 -04:00
containerID = strings . TrimSpace ( out )
// first checkout without force it fails
2015-10-09 23:32:55 -04:00
// rmi tagged in multiple repos should have failed without force
2017-04-11 15:18:30 -04:00
cli . Docker ( cli . Args ( "rmi" , imgID ) ) . Assert ( c , icmd . Expected {
ExitCode : 1 ,
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 ) ) ,
} )
2015-05-29 14:12:58 -04:00
2017-04-11 15:18:30 -04:00
cli . DockerCmd ( c , "stop" , containerID )
cli . DockerCmd ( c , "rmi" , "-f" , imgID )
2015-05-29 14:12:58 -04:00
2017-04-11 15:18:30 -04:00
imagesAfter = cli . DockerCmd ( c , "images" , "-a" ) . Combined ( )
2015-10-09 23:32:55 -04:00
// rmi -f failed, image still exists
c . Assert ( imagesAfter , checker . Not ( checker . Contains ) , imgID [ : 12 ] , check . Commentf ( "ImageID:%q; ImagesAfter: %q" , imgID , imagesAfter ) )
2015-05-29 14:12:58 -04:00
}
2015-04-18 12:46:47 -04:00
func ( s * DockerSuite ) TestRmiImgIDForce ( c * check . C ) {
2017-04-11 15:18:30 -04:00
out := cli . DockerCmd ( c , "run" , "-d" , "busybox" , "/bin/sh" , "-c" , "mkdir '/busybox-test'" ) . Combined ( )
2015-04-10 21:24:21 -04:00
containerID := strings . TrimSpace ( out )
2016-01-26 15:22:37 -05:00
// Wait for it to exit as cannot commit a running container on Windows, and
// it will take a few seconds to exit
2018-01-15 09:32:06 -05:00
if testEnv . OSType == "windows" {
2017-04-11 15:18:30 -04:00
cli . WaitExited ( c , containerID , 60 * time . Second )
2016-01-26 15:22:37 -05:00
}
2017-04-11 15:18:30 -04:00
cli . DockerCmd ( c , "commit" , containerID , "busybox-test" )
2015-04-10 21:24:21 -04:00
2017-04-11 15:18:30 -04:00
imagesBefore := cli . DockerCmd ( c , "images" , "-a" ) . Combined ( )
cli . DockerCmd ( c , "tag" , "busybox-test" , "utest:tag1" )
cli . DockerCmd ( c , "tag" , "busybox-test" , "utest:tag2" )
cli . DockerCmd ( c , "tag" , "busybox-test" , "utest/docker:tag3" )
cli . DockerCmd ( c , "tag" , "busybox-test" , "utest:5000/docker:tag4" )
2015-04-10 21:24:21 -04:00
{
2017-04-11 15:18:30 -04:00
imagesAfter := cli . DockerCmd ( c , "images" , "-a" ) . Combined ( )
2015-10-09 23:32:55 -04:00
c . Assert ( strings . Count ( imagesAfter , "\n" ) , checker . Equals , strings . Count ( imagesBefore , "\n" ) + 4 , check . Commentf ( "before: %q\n\nafter: %q\n" , imagesBefore , imagesAfter ) )
2015-04-10 21:24:21 -04:00
}
2016-01-28 09:19:25 -05:00
imgID := inspectField ( c , "busybox-test" , "Id" )
2015-04-22 17:12:46 -04:00
// first checkout without force it fails
2017-04-11 15:18:30 -04:00
cli . Docker ( cli . Args ( "rmi" , imgID ) ) . Assert ( c , icmd . Expected {
ExitCode : 1 ,
Err : "(must be forced) - image is referenced in multiple repositories" ,
} )
2015-04-22 17:12:46 -04:00
2017-04-11 15:18:30 -04:00
cli . DockerCmd ( c , "rmi" , "-f" , imgID )
2015-04-10 21:24:21 -04:00
{
2017-04-11 15:18:30 -04:00
imagesAfter := cli . DockerCmd ( c , "images" , "-a" ) . Combined ( )
2015-10-09 23:32:55 -04:00
// rmi failed, image still exists
c . Assert ( imagesAfter , checker . Not ( checker . Contains ) , imgID [ : 12 ] )
2015-04-10 21:24:21 -04:00
}
}
2015-06-23 06:38:50 -04:00
// See https://github.com/docker/docker/issues/14116
func ( s * DockerSuite ) TestRmiImageIDForceWithRunningContainersAndMultipleTags ( c * check . C ) {
dockerfile := "FROM busybox\nRUN echo test 14116\n"
2017-03-23 13:35:22 -04:00
buildImageSuccessfully ( c , "test-14116" , build . WithDockerfile ( dockerfile ) )
2017-01-16 05:30:14 -05:00
imgID := getIDByName ( c , "test-14116" )
2015-06-23 06:38:50 -04:00
newTag := "newtag"
dockerCmd ( c , "tag" , imgID , newTag )
2016-01-26 23:16:36 -05:00
runSleepingContainerInImage ( c , imgID )
2015-06-23 06:38:50 -04:00
2015-07-27 14:13:25 -04:00
out , _ , err := dockerCmdWithError ( "rmi" , "-f" , imgID )
2015-10-09 23:32:55 -04:00
// rmi -f should not delete image with running containers
2019-04-04 09:23:19 -04:00
assert . ErrorContains ( c , err , "" )
2015-10-09 23:32:55 -04:00
c . Assert ( out , checker . Contains , "(cannot be forced) - image is being used by running container" )
2015-06-23 06:38:50 -04:00
}
2015-04-18 12:46:47 -04:00
func ( s * DockerSuite ) TestRmiTagWithExistingContainers ( c * check . C ) {
2014-10-02 19:39:39 -04:00
container := "test-delete-tag"
newtag := "busybox:newtag"
bb := "busybox:latest"
2015-10-09 23:32:55 -04:00
dockerCmd ( c , "tag" , bb , newtag )
dockerCmd ( c , "run" , "--name" , container , bb , "/bin/true" )
out , _ := dockerCmd ( c , "rmi" , newtag )
c . Assert ( strings . Count ( out , "Untagged: " ) , checker . Equals , 1 )
2014-10-02 19:39:39 -04:00
}
2014-11-17 15:49:29 -05:00
2015-04-18 12:46:47 -04:00
func ( s * DockerSuite ) TestRmiForceWithExistingContainers ( c * check . C ) {
2014-11-17 15:49:29 -05:00
image := "busybox-clone"
2015-02-14 05:44:56 -05:00
2017-01-05 06:38:34 -05:00
icmd . RunCmd ( icmd . Cmd {
Command : [ ] string { dockerBinary , "build" , "--no-cache" , "-t" , image , "-" } ,
Stdin : strings . NewReader ( ` FROM busybox
2017-01-05 13:08:24 -05:00
MAINTAINER foo ` ) ,
2017-01-05 06:38:34 -05:00
} ) . Assert ( c , icmd . Success )
2014-11-17 15:49:29 -05:00
2015-10-09 23:32:55 -04:00
dockerCmd ( c , "run" , "--name" , "test-force-rmi" , image , "/bin/true" )
2014-11-17 15:49:29 -05:00
2015-10-09 23:32:55 -04:00
dockerCmd ( c , "rmi" , "-f" , image )
2014-11-17 15:49:29 -05:00
}
2015-02-25 23:01:35 -05:00
2015-04-18 12:46:47 -04:00
func ( s * DockerSuite ) TestRmiWithMultipleRepositories ( c * check . C ) {
2015-02-25 23:01:35 -05:00
newRepo := "127.0.0.1:5000/busybox"
oldRepo := "busybox"
newTag := "busybox:test"
2015-10-09 23:32:55 -04:00
dockerCmd ( c , "tag" , oldRepo , newRepo )
2015-07-14 16:15:00 -04:00
2016-01-26 15:22:37 -05:00
dockerCmd ( c , "run" , "--name" , "test" , oldRepo , "touch" , "/abcd" )
2015-07-14 16:15:00 -04:00
2015-10-09 23:32:55 -04:00
dockerCmd ( c , "commit" , "test" , newTag )
2015-07-14 16:15:00 -04:00
2015-10-09 23:32:55 -04:00
out , _ := dockerCmd ( c , "rmi" , newTag )
c . Assert ( out , checker . Contains , "Untagged: " + newTag )
2015-03-04 16:18:45 -05:00
}
2015-10-28 19:07:02 -04:00
func ( s * DockerSuite ) TestRmiForceWithMultipleRepositories ( c * check . C ) {
imageName := "rmiimage"
tag1 := imageName + ":tag1"
tag2 := imageName + ":tag2"
2017-03-23 13:35:22 -04:00
buildImageSuccessfully ( c , tag1 , build . WithDockerfile ( ` FROM busybox
2017-01-16 05:30:14 -05:00
MAINTAINER "docker" ` ) )
2015-10-28 19:07:02 -04:00
dockerCmd ( c , "tag" , tag1 , tag2 )
out , _ := dockerCmd ( c , "rmi" , "-f" , tag2 )
c . Assert ( out , checker . Contains , "Untagged: " + tag2 )
c . Assert ( out , checker . Not ( checker . Contains ) , "Untagged: " + tag1 )
// Check built image still exists
images , _ := dockerCmd ( c , "images" , "-a" )
c . Assert ( images , checker . Contains , imageName , check . Commentf ( "Built image missing %q; Images: %q" , imageName , images ) )
}
2015-04-18 12:46:47 -04:00
func ( s * DockerSuite ) TestRmiBlank ( c * check . C ) {
2016-06-05 16:40:35 -04:00
out , _ , err := dockerCmdWithError ( "rmi" , " " )
// Should have failed to delete ' ' image
2019-04-04 09:23:19 -04:00
assert . ErrorContains ( c , err , "" )
2015-10-09 23:32:55 -04:00
// Wrong error message generated
c . Assert ( out , checker . Not ( checker . Contains ) , "no such id" , check . Commentf ( "out: %s" , out ) )
// Expected error message not generated
c . Assert ( out , checker . Contains , "image name cannot be blank" , check . Commentf ( "out: %s" , out ) )
2015-02-25 23:01:35 -05:00
}
2015-07-10 09:35:44 -04:00
func ( s * DockerSuite ) TestRmiContainerImageNotFound ( c * check . C ) {
// Build 2 images for testing.
imageNames := [ ] string { "test1" , "test2" }
imageIds := make ( [ ] string , 2 )
for i , name := range imageNames {
dockerfile := fmt . Sprintf ( "FROM busybox\nMAINTAINER %s\nRUN echo %s\n" , name , name )
2017-03-23 13:35:22 -04:00
buildImageSuccessfully ( c , name , build . WithoutCache , build . WithDockerfile ( dockerfile ) )
2017-01-16 05:30:14 -05:00
id := getIDByName ( c , name )
2015-07-10 09:35:44 -04:00
imageIds [ i ] = id
}
// Create a long-running container.
2016-01-26 23:16:36 -05:00
runSleepingContainerInImage ( c , imageNames [ 0 ] )
2015-07-10 09:35:44 -04:00
// Create a stopped container, and then force remove its image.
dockerCmd ( c , "run" , imageNames [ 1 ] , "true" )
dockerCmd ( c , "rmi" , "-f" , imageIds [ 1 ] )
// Try to remove the image of the running container and see if it fails as expected.
2015-07-27 14:13:25 -04:00
out , _ , err := dockerCmdWithError ( "rmi" , "-f" , imageIds [ 0 ] )
2015-10-09 23:32:55 -04:00
// The image of the running container should not be removed.
2019-04-04 09:23:19 -04:00
assert . ErrorContains ( c , err , "" )
2015-10-09 23:32:55 -04:00
c . Assert ( out , checker . Contains , "image is being used by running container" , check . Commentf ( "out: %s" , out ) )
2015-07-10 09:35:44 -04:00
}
2015-08-15 03:30:25 -04:00
// #13422
func ( s * DockerSuite ) TestRmiUntagHistoryLayer ( c * check . C ) {
image := "tmp1"
2016-05-07 21:36:10 -04:00
// Build an image for testing.
2015-08-15 03:30:25 -04:00
dockerfile := ` FROM busybox
MAINTAINER foo
RUN echo 0 # layer0
RUN echo 1 # layer1
RUN echo 2 # layer2
`
2017-03-23 13:35:22 -04:00
buildImageSuccessfully ( c , image , build . WithoutCache , build . WithDockerfile ( dockerfile ) )
2015-08-15 03:30:25 -04:00
out , _ := dockerCmd ( c , "history" , "-q" , image )
ids := strings . Split ( out , "\n" )
idToTag := ids [ 2 ]
// Tag layer0 to "tmp2".
newTag := "tmp2"
dockerCmd ( c , "tag" , idToTag , newTag )
// Create a container based on "tmp1".
dockerCmd ( c , "run" , "-d" , image , "true" )
// See if the "tmp2" can be untagged.
out , _ = dockerCmd ( c , "rmi" , newTag )
2015-10-09 23:32:55 -04:00
// Expected 1 untagged entry
c . Assert ( strings . Count ( out , "Untagged: " ) , checker . Equals , 1 , check . Commentf ( "out: %s" , out ) )
2015-08-15 03:30:25 -04:00
// Now let's add the tag again and create a container based on it.
dockerCmd ( c , "tag" , idToTag , newTag )
out , _ = dockerCmd ( c , "run" , "-d" , newTag , "true" )
cid := strings . TrimSpace ( out )
// At this point we have 2 containers, one based on layer2 and another based on layer0.
// Try to untag "tmp2" without the -f flag.
2017-01-16 05:30:14 -05:00
out , _ , err := dockerCmdWithError ( "rmi" , newTag )
2015-10-09 23:32:55 -04:00
// should not be untagged without the -f flag
2019-04-04 09:23:19 -04:00
assert . ErrorContains ( c , err , "" )
2015-10-09 23:32:55 -04:00
c . Assert ( out , checker . Contains , cid [ : 12 ] )
c . Assert ( out , checker . Contains , "(must force)" )
2015-08-15 03:30:25 -04:00
// Add the -f flag and test again.
out , _ = dockerCmd ( c , "rmi" , "-f" , newTag )
2015-10-09 23:32:55 -04:00
// should be allowed to untag with the -f flag
c . Assert ( out , checker . Contains , fmt . Sprintf ( "Untagged: %s:latest" , newTag ) )
2015-08-15 03:30:25 -04:00
}
2015-10-09 13:13:45 -04:00
func ( * DockerSuite ) TestRmiParentImageFail ( c * check . C ) {
2017-03-23 13:35:22 -04:00
buildImageSuccessfully ( c , "test" , build . WithDockerfile ( `
2016-08-31 15:31:06 -04:00
FROM busybox
2017-01-16 05:30:14 -05:00
RUN echo hello ` ) )
2016-08-31 15:31:06 -04:00
id := inspectField ( c , "busybox" , "ID" )
out , _ , err := dockerCmdWithError ( "rmi" , id )
2019-04-04 09:23:19 -04:00
assert . ErrorContains ( c , err , "" )
2015-10-09 13:13:45 -04:00
if ! strings . Contains ( out , "image has dependent child images" ) {
c . Fatalf ( "rmi should have failed because it's a parent image, got %s" , out )
}
}
2015-11-25 20:57:20 -05:00
func ( s * DockerSuite ) TestRmiWithParentInUse ( c * check . C ) {
out , _ := dockerCmd ( c , "create" , "busybox" )
cID := strings . TrimSpace ( out )
2016-01-26 15:22:37 -05:00
2015-11-25 20:57:20 -05:00
out , _ = dockerCmd ( c , "commit" , cID )
imageID := strings . TrimSpace ( out )
out , _ = dockerCmd ( c , "create" , imageID )
cID = strings . TrimSpace ( out )
2016-01-26 15:22:37 -05:00
2015-11-25 20:57:20 -05:00
out , _ = dockerCmd ( c , "commit" , cID )
imageID = strings . TrimSpace ( out )
dockerCmd ( c , "rmi" , imageID )
}
2016-01-12 13:55:34 -05:00
// #18873
func ( s * DockerSuite ) TestRmiByIDHardConflict ( c * check . C ) {
dockerCmd ( c , "create" , "busybox" )
2016-01-28 09:19:25 -05:00
imgID := inspectField ( c , "busybox:latest" , "Id" )
2016-01-12 13:55:34 -05:00
2016-01-28 09:19:25 -05:00
_ , _ , err := dockerCmdWithError ( "rmi" , imgID [ : 12 ] )
2019-04-04 09:23:19 -04:00
assert . ErrorContains ( c , err , "" )
2016-01-12 13:55:34 -05:00
// check that tag was not removed
2016-01-28 09:19:25 -05:00
imgID2 := inspectField ( c , "busybox:latest" , "Id" )
2016-01-12 13:55:34 -05:00
c . Assert ( imgID , checker . Equals , imgID2 )
}