on master help sign in
Adds pulling images from docker hub
5ce3fb0Deni Bertovic
src/Docker/Client/Api.hs+27−11
@@ -21,9 +21,10 @@ module Docker.Client.Api (
21 , buildImageFromDockerfile
21 , buildImageFromDockerfile
22 -- * Other
22 -- * Other
23 , getDockerVersion
23 , getDockerVersion
24+ , pullImage
24 ) where
25 ) where
25
26
26−import Control.Monad.Catch (MonadMask(..))
27+import Control.Monad.Catch (MonadMask (..))
27import Control.Monad.IO.Class
28import Control.Monad.IO.Class
28import Control.Monad.Reader (ask, lift)
29import Control.Monad.Reader (ask, lift)
29import Data.Aeson (FromJSON, eitherDecode')
30import Data.Aeson (FromJSON, eitherDecode')
@@ -31,10 +32,11 @@ import qualified Data.ByteString as BS
31import qualified Data.ByteString.Lazy as BSL
32import qualified Data.ByteString.Lazy as BSL
32import Data.Conduit (Sink)
33import Data.Conduit (Sink)
33import qualified Data.Conduit.Binary as Conduit
34import qualified Data.Conduit.Binary as Conduit
35+import qualified Data.Text as T
34import qualified Data.Text as Text
36import qualified Data.Text as Text
35−import Network.HTTP.Client (responseStatus)
37+import Network.HTTP.Client (responseStatus)
36−import Network.HTTP.Types (StdMethod (..))
38+import Network.HTTP.Types (StdMethod (..))
37−import System.Exit (ExitCode(..))
39+import System.Exit (ExitCode (..))
38
40
39import Docker.Client.Http
41import Docker.Client.Http
40import Docker.Client.Types
42import Docker.Client.Types
@@ -54,8 +56,8 @@ requestHelper' verb endpoint sink = do
54 return $ Left $ DockerInvalidRequest endpoint
56 return $ Left $ DockerInvalidRequest endpoint
55 Just request -> do
57 Just request -> do
56 -- JP: Do we need runResourceT?
58 -- JP: Do we need runResourceT?
57− -- lift $ NHS.httpSink request $ \response ->
59+ -- lift $ NHS.httpSink request $ \response ->
58− lift $ httpHandler request $ \response ->
60+ lift $ httpHandler request $ \response ->
59 -- Check status code.
61 -- Check status code.
60 let status = responseStatus response in
62 let status = responseStatus response in
61 case statusCodeToError endpoint status of
63 case statusCodeToError endpoint status of
@@ -149,21 +151,25 @@ inspectContainer cid = requestHelper GET (InspectContainerEndpoint cid) >>= pars
149-- See 'LogOpts' for options that you can pass and
151-- See 'LogOpts' for options that you can pass and
150-- 'defaultLogOpts' for sane defaults.
152-- 'defaultLogOpts' for sane defaults.
151--
153--
152−-- __NOTE__: Currently streaming logs is
153−-- not supported and this function will fetch the entire log that the
154+-- __NOTE__: his function will fetch the entire log that the
154-- container produced in the json-file on disk. Depending on the logging
155-- container produced in the json-file on disk. Depending on the logging
155-- setup of the process in your container this can be a significant amount
156-- setup of the process in your container this can be a significant amount
156-- which might block your application...so use with caution.
157-- which might block your application...so use with caution.
157--
158--
159+-- If you want to stream the logs from the container continuosly then use
160+-- 'getContainerLogsStream'
161+--
158−-- The recommended method is to use one of the other 'LogDriverType's available (like
162+-- __NOTE__: It's recommended to use one of the other 'LogDriverType's available (like
159-- syslog) for creating your containers.
163-- syslog) for creating your containers.
160getContainerLogs :: forall m. (MonadIO m, MonadMask m) => LogOpts -> ContainerID -> DockerT m (Either DockerError BSL.ByteString)
164getContainerLogs :: forall m. (MonadIO m, MonadMask m) => LogOpts -> ContainerID -> DockerT m (Either DockerError BSL.ByteString)
161getContainerLogs logopts cid = requestHelper GET (ContainerLogsEndpoint logopts False cid)
165getContainerLogs logopts cid = requestHelper GET (ContainerLogsEndpoint logopts False cid)
162
166
167+-- | Continuosly gets the container's logs as a stream. Uses conduit.
163getContainerLogsStream :: forall m b . (MonadIO m, MonadMask m) => LogOpts -> ContainerID -> Sink BS.ByteString m b -> DockerT m (Either DockerError b)
168getContainerLogsStream :: forall m b . (MonadIO m, MonadMask m) => LogOpts -> ContainerID -> Sink BS.ByteString m b -> DockerT m (Either DockerError b)
164−getContainerLogsStream logopts cid sink = requestHelper' GET (ContainerLogsEndpoint logopts True cid) sink
169+getContainerLogsStream logopts cid = requestHelper' GET (ContainerLogsEndpoint logopts True cid)
165-- JP: Should the second (follow) argument be True? XXX
170-- JP: Should the second (follow) argument be True? XXX
166
171
172+-- | Build an Image from a Dockerfile
167-- TODO: Add X-Registry-Config
173-- TODO: Add X-Registry-Config
168-- TODO: Add support for remote URLs to a Dockerfile
174-- TODO: Add support for remote URLs to a Dockerfile
169-- TODO: Clean up temp tar.gz file after the image is built
175-- TODO: Clean up temp tar.gz file after the image is built
@@ -171,5 +177,15 @@ buildImageFromDockerfile :: forall m. (MonadIO m, MonadMask m) => BuildOpts -> F
171buildImageFromDockerfile opts base = do
177buildImageFromDockerfile opts base = do
172 ctx <- makeBuildContext $ BuildContextRootDir base
178 ctx <- makeBuildContext $ BuildContextRootDir base
173 case ctx of
179 case ctx of
174− Left e -> return $ Left e
180+ Left e -> return $ Left e
175 Right c -> requestUnit POST (BuildImageEndpoint opts c)
181 Right c -> requestUnit POST (BuildImageEndpoint opts c)
182+
183+-- | Pulls an image from Docker Hub (by default).
184+-- TODO: Add support for X-Registry-Auth and pulling from private docker
185+-- registries.
186+-- TODO: Implement importImage function that uses he same
187+-- CreateImageEndpoint but rather than pulling from docker hub it imports
188+-- the image from a tarball or a URL.
189+pullImage :: forall m b . (MonadIO m, MonadMask m) => T.Text -> Tag -> Sink BS.ByteString m b -> DockerT m (Either DockerError b)
190+pullImage name tag = requestHelper' POST (CreateImageEndpoint name tag Nothing)
191+
src/Docker/Client/Http.hs+5
@@ -249,4 +249,9 @@ statusCodeToError (BuildImageEndpoint _ _) st =
249 Nothing
249 Nothing
250 else
250 else
251 Just $ DockerInvalidStatusCode st
251 Just $ DockerInvalidStatusCode st
252+statusCodeToError (CreateImageEndpoint _ _ _) st =
253+ if st == status200 then
254+ Nothing
255+ else
256+ Just $ DockerInvalidStatusCode st
252
257
src/Docker/Client/Internal.hs+6
@@ -70,6 +70,10 @@ getEndpoint (BuildImageEndpoint o _) = encodeURLWithQuery ["build"] query
70 rm = encodeQ $ show $ buildRemoveItermediate o
70 rm = encodeQ $ show $ buildRemoveItermediate o
71 forcerm = encodeQ $ show $ buildForceRemoveIntermediate o
71 forcerm = encodeQ $ show $ buildForceRemoveIntermediate o
72 pull = encodeQ $ show $ buildPullParent o
72 pull = encodeQ $ show $ buildPullParent o
73+getEndpoint (CreateImageEndpoint name tag _) = encodeURLWithQuery ["images", "create"] query
74+ where query = [("fromImage", Just n), ("tag", Just t)]
75+ n = encodeQ $ T.unpack name
76+ t = encodeQ $ T.unpack tag
73
77
74getEndpointRequestBody :: Endpoint -> Maybe HTTP.RequestBody
78getEndpointRequestBody :: Endpoint -> Maybe HTTP.RequestBody
75getEndpointRequestBody VersionEndpoint = Nothing
79getEndpointRequestBody VersionEndpoint = Nothing
@@ -86,7 +90,9 @@ getEndpointRequestBody (UnpauseContainerEndpoint _) = Nothing
86getEndpointRequestBody (ContainerLogsEndpoint _ _ _) = Nothing
90getEndpointRequestBody (ContainerLogsEndpoint _ _ _) = Nothing
87getEndpointRequestBody (DeleteContainerEndpoint _ _) = Nothing
91getEndpointRequestBody (DeleteContainerEndpoint _ _) = Nothing
88getEndpointRequestBody (InspectContainerEndpoint _) = Nothing
92getEndpointRequestBody (InspectContainerEndpoint _) = Nothing
93+
89getEndpointRequestBody (BuildImageEndpoint _ fp) = Just $ requestBodySourceChunked $ CB.sourceFile fp
94getEndpointRequestBody (BuildImageEndpoint _ fp) = Just $ requestBodySourceChunked $ CB.sourceFile fp
95+getEndpointRequestBody (CreateImageEndpoint _ _) = Nothing
90
96
91getEndpointContentType :: Endpoint -> BSC.ByteString
97getEndpointContentType :: Endpoint -> BSC.ByteString
92getEndpointContentType (BuildImageEndpoint _ _) = BSC.pack "application/tar"
98getEndpointContentType (BuildImageEndpoint _ _) = BSC.pack "application/tar"
src/Docker/Client/Types.hs+1
@@ -124,6 +124,7 @@ data Endpoint =
124 | DeleteContainerEndpoint DeleteOpts ContainerID
124 | DeleteContainerEndpoint DeleteOpts ContainerID
125 | InspectContainerEndpoint ContainerID
125 | InspectContainerEndpoint ContainerID
126 | BuildImageEndpoint BuildOpts FilePath
126 | BuildImageEndpoint BuildOpts FilePath
127+ | CreateImageEndpoint T.Text Tag (Maybe T.Text) -- ^ Either pull an image from docker hub or imports an image from a tarball (or URL)
127 deriving (Eq, Show)
128 deriving (Eq, Show)
128
129
129-- | We should newtype this
130-- | We should newtype this