on master help sign in
Image deletion implementation
commitd44ca8bb5fe1eb5b0b19beacced0a654b645ea76 authorIvan Kasatenko <sky.31338@gmail.com> dateSun 24 Jun 2018, 17:44 (8 years ago) parent940eb34
5 files changed+58−14
src/Docker/Client/Api.hs+9−2 src/Docker/Client/Http.hs+5−1 src/Docker/Client/Internal.hs+4−1 src/Docker/Client/Types.hs+16−6 tests/tests.hs+24−4
src/Docker/Client/Api.hs+9−2
@@ -18,6 +18,7 @@ module Docker.Client.Api (
1818 , getContainerLogsStream
1919 -- * Images
2020 , listImages
21+ , deleteImage
2122 , buildImageFromDockerfile
2223 , pullImage
2324 -- * Network
@@ -93,6 +94,12 @@ listContainers opts = requestHelper GET (ListContainersEndpoint opts) >>= parseR
9394listImages :: forall m. (MonadIO m, MonadMask m) => ListOpts -> DockerT m (Either DockerError [Image])
9495listImages opts = requestHelper GET (ListImagesEndpoint opts) >>= parseResponse
9596
97+-- | Deletes an image with the given 'ImageID'.
98+-- See "ImageDeleteOpts" for options and use 'defaultImageDeleteOpts' for sane
99+-- defaults.
100+deleteImage :: forall m. (MonadIO m, MonadMask m) => ImageDeleteOpts -> ImageID -> DockerT m (Either DockerError ())
101+deleteImage dopts iid = requestUnit DELETE $ DeleteImageEndpoint dopts iid
102+
96103-- | Creates a docker container but does __not__ start it. See
97104-- 'CreateOpts' for a list of options and you can use 'defaultCreateOpts'
98105-- for some sane defaults.
@@ -138,9 +145,9 @@ unpauseContainer :: forall m. (MonadIO m, MonadMask m) => ContainerID -> DockerT
138145unpauseContainer cid = requestUnit GET $ UnpauseContainerEndpoint cid
139146
140147-- | Deletes a container with the given 'ContainerID'.
141−-- See "DeleteOpts" for options and use 'defaultDeleteOpts' for sane
148+-- See "ContainerDeleteOpts" for options and use 'defaultContainerDeleteOpts' for sane
142149-- defaults.
143−deleteContainer :: forall m. (MonadIO m, MonadMask m) => DeleteOpts -> ContainerID -> DockerT m (Either DockerError ())
150+deleteContainer :: forall m. (MonadIO m, MonadMask m) => ContainerDeleteOpts -> ContainerID -> DockerT m (Either DockerError ())
144151deleteContainer dopts cid = requestUnit DELETE $ DeleteContainerEndpoint dopts cid
145152
146153-- | Gets 'ContainerDetails' for a given 'ContainerID'.
src/Docker/Client/Http.hs+5−1
@@ -273,6 +273,11 @@ statusCodeToError (CreateImageEndpoint _ _ _) st =
273273 Nothing
274274 else
275275 Just $ DockerInvalidStatusCode st
276+statusCodeToError (DeleteImageEndpoint _ _) st =
277+ if st == status200 then
278+ Nothing
279+ else
280+ Just $ DockerInvalidStatusCode st
276281statusCodeToError (CreateNetworkEndpoint _) st =
277282 if st == status201 then
278283 Nothing
@@ -283,4 +288,3 @@ statusCodeToError (RemoveNetworkEndpoint _) st =
283288 Nothing
284289 else
285290 Just $ DockerInvalidStatusCode st
286−
src/Docker/Client/Internal.hs+4−1
@@ -57,7 +57,7 @@ getEndpoint v (UnpauseContainerEndpoint cid) = encodeURL [v, "containers", fromC
5757getEndpoint v (ContainerLogsEndpoint (LogOpts stdout stderr _ _ _) follow cid) =
5858 encodeURLWithQuery [v, "containers", fromContainerID cid, "logs"] query
5959 where query = [("stdout", Just (encodeQ $ show stdout)), ("stderr", Just (encodeQ $ show stderr)), ("follow", Just (encodeQ $ show follow))]
60−getEndpoint v (DeleteContainerEndpoint (DeleteOpts removeVolumes force) cid) =
60+getEndpoint v (DeleteContainerEndpoint (ContainerDeleteOpts removeVolumes force) cid) =
6161 encodeURLWithQuery [v, "containers", fromContainerID cid] query
6262 where query = [("v", Just (encodeQ $ show removeVolumes)), ("force", Just (encodeQ $ show force))]
6363getEndpoint v (InspectContainerEndpoint cid) =
@@ -75,6 +75,7 @@ getEndpoint v (CreateImageEndpoint name tag _) = encodeURLWithQuery [v, "images"
7575 where query = [("fromImage", Just n), ("tag", Just t)]
7676 n = encodeQ $ T.unpack name
7777 t = encodeQ $ T.unpack tag
78+getEndpoint v (DeleteImageEndpoint _ cid) = encodeURL [v, "images", fromImageID cid]
7879getEndpoint v (CreateNetworkEndpoint _) = encodeURL [v, "networks", "create"]
7980getEndpoint v (RemoveNetworkEndpoint nid) = encodeURL [v, "networks", fromNetworkID nid]
8081
@@ -96,6 +97,8 @@ getEndpointRequestBody (InspectContainerEndpoint _) = Nothing
9697
9798getEndpointRequestBody (BuildImageEndpoint _ fp) = Just $ requestBodySourceChunked $ CB.sourceFile fp
9899getEndpointRequestBody (CreateImageEndpoint _ _ _) = Nothing
100+getEndpointRequestBody (DeleteImageEndpoint _ _) = Nothing
101+
99102getEndpointRequestBody (CreateNetworkEndpoint opts) = Just $ HTTP.RequestBodyLBS (JSON.encode opts)
100103getEndpointRequestBody (RemoveNetworkEndpoint _) = Nothing
101104
src/Docker/Client/Types.hs+16−6
@@ -40,8 +40,10 @@ module Docker.Client.Types (
4040 , DetachKeys(..)
4141 , StartOpts(..)
4242 , defaultStartOpts
43− , DeleteOpts(..)
44− , defaultDeleteOpts
43+ , ContainerDeleteOpts(..)
44+ , defaultContainerDeleteOpts
45+ , ImageDeleteOpts(..)
46+ , defaultImageDeleteOpts
4547 , Timestamp
4648 , TailLogOpt(..)
4749 , LogOpts(..)
@@ -130,10 +132,11 @@ data Endpoint =
130132 | UnpauseContainerEndpoint ContainerID
131133 | ContainerLogsEndpoint LogOpts Bool ContainerID -- ^ Second argument (Bool) is whether to follow which is currently hardcoded to False.
132134 -- See note in 'Docker.Client.Api.getContainerLogs' for explanation why.
133− | DeleteContainerEndpoint DeleteOpts ContainerID
135+ | DeleteContainerEndpoint ContainerDeleteOpts ContainerID
134136 | InspectContainerEndpoint ContainerID
135137 | BuildImageEndpoint BuildOpts FilePath
136138 | CreateImageEndpoint T.Text Tag (Maybe T.Text) -- ^ Either pull an image from docker hub or imports an image from a tarball (or URL)
139+ | DeleteImageEndpoint ImageDeleteOpts ImageID
137140 | CreateNetworkEndpoint CreateNetworkOpts
138141 | RemoveNetworkEndpoint NetworkID
139142 deriving (Eq, Show)
@@ -759,7 +762,7 @@ defaultStartOpts :: StartOpts
759762defaultStartOpts = StartOpts { detachKeys = DefaultDetachKey }
760763
761764-- | Options for deleting a container.
762−data DeleteOpts = DeleteOpts {
765+data ContainerDeleteOpts = ContainerDeleteOpts {
763766 deleteVolumes :: Bool -- ^ Automatically cleanup volumes that the container created as well.
764767 , force :: Bool -- ^ If the container is still running force deletion anyway.
765768 } deriving (Eq, Show)
@@ -789,8 +792,15 @@ defaultBuildOpts nameTag = BuildOpts { buildImageName = nameTag
789792-- | Default options for deleting a container. Most of the time we DON'T
790793-- want to delete the container's volumes or force delete it if it's
791794-- running.
792−defaultDeleteOpts :: DeleteOpts
793−defaultDeleteOpts = DeleteOpts { deleteVolumes = False, force = False }
795+defaultContainerDeleteOpts :: ContainerDeleteOpts
796+defaultContainerDeleteOpts = ContainerDeleteOpts { deleteVolumes = False, force = False }
797+
798+-- | Image delete opts
799+data ImageDeleteOpts = ImageDeleteOpts deriving (Eq, Show)
800+
801+-- | Sane image deletion defaults
802+defaultImageDeleteOpts :: ImageDeleteOpts
803+defaultImageDeleteOpts = ImageDeleteOpts
794804
795805-- | Timestamp alias.
796806type Timestamp = Integer
tests/tests.hs+24−4
@@ -24,7 +24,7 @@ import qualified Data.ByteString.Lazy as BL
2424import qualified Data.HashMap.Strict as HM
2525import Data.Int (Int)
2626import qualified Data.Map as M
27−import Data.Maybe (fromJust, isJust)
27+import Data.Maybe (fromJust, isJust, isNothing, listToMaybe)
2828import Data.Monoid
2929import Data.Text (Text, unpack)
3030import qualified Data.Vector as V
@@ -40,6 +40,7 @@ import Docker.Client
4040
4141-- opts = defaultClientOpts
4242testImageName = "docker-hs/test"
43+imageToDeleteFullName = "hello-world:latest"
4344
4445toStrict1 = B.concat . BL.toChunks
4546
@@ -73,13 +74,27 @@ testFindImage =
7374 where
7475 imageFullName = testImageName <> ":latest"
7576
77+testDeleteImage :: IO ()
78+testDeleteImage = runDocker $ do
79+ (Just img) <- findTestImage
80+ result <- deleteImage defaultImageDeleteOpts (imageId img)
81+ lift $ assert $ isRight result
82+ maybeTestImageAfter <- findTestImage
83+ lift $ assert $ isNothing maybeTestImageAfter
84+ where
85+ findTestImage =
86+ do
87+ images <- listImages defaultListOpts >>= fromRight
88+ return $ listToMaybe
89+ $ filter (elem imageToDeleteFullName . imageRepoTags) images
90+
7691testListContainers :: IO ()
7792testListContainers =
7893 runDocker $
7994 do containerId <- createContainer (defaultCreateOpts (testImageName <> ":latest")) Nothing
8095 c <- fromRight containerId
8196 res <- listContainers $ ListOpts { all=True }
82− deleteContainer (DeleteOpts True True) c
97+ deleteContainer (ContainerDeleteOpts True True) c
8398 lift $ assert $ isRight res
8499
85100testBuildFromDockerfile :: IO ()
@@ -110,7 +125,7 @@ testRunAndReadLogHelper networkingConfig =
110125 lift $ assertBool ("starting the container, unexpected status: " ++ show status1) $ isRightUnit status1
111126 logs <- getContainerLogs defaultLogOpts c >>= fromRight
112127 lift $ assert $ (C.pack "123") `C.isInfixOf` (toStrict1 logs)
113− status3 <- deleteContainer (DeleteOpts True True) c
128+ status3 <- deleteContainer (ContainerDeleteOpts True True) c
114129 lift $ assertBool ("deleting container, unexpected status: " ++ show status3) $ isRightUnit status3
115130 mapM_ removeNetwork createdNetworks
116131 where
@@ -228,6 +243,7 @@ integrationTests =
228243 [ testCase "Get docker version" testDockerVersion
229244 , testCase "Build image from Dockerfile" testBuildFromDockerfile
230245 , testCase "Find image by name" testFindImage
246+ , testCase "Delete image" testDeleteImage
231247 , testCase "List containers" testListContainers
232248 , testCase "Run a dummy container and read its log" testRunAndReadLog
233249 , testCase "Run a dummy container with networking and read its log" testRunAndReadLogWithNetworking
@@ -249,7 +265,11 @@ jsonTests =
249265 ]
250266
251267setup :: IO ()
252−setup = system ("docker build -t " ++ unpack testImageName ++ " tests") >> return ()
268+setup =
269+ mapM_ system
270+ [ "docker pull " ++ unpack imageToDeleteFullName
271+ , "docker build -t " ++ unpack testImageName ++ " tests"
272+ ]
253273
254274isLeft = not . isRight
255275