{-# LANGUAGE ExplicitForAll      #-}
{-# LANGUAGE ScopedTypeVariables #-}

module Docker.Client.Api (
    -- * Containers
      listContainers
    , createContainer
    , startContainer
    , stopContainer
    , waitContainer
    , killContainer
    , restartContainer
    , pauseContainer
    , unpauseContainer
    , deleteContainer
    , inspectContainer
    , getContainerLogs
    , getContainerLogsStream
    -- * Images
    , listImages
    , deleteImage
    , buildImageFromDockerfile
    , pullImage
    -- * Network
    , createNetwork
    , removeNetwork
    -- * Other
    , getDockerVersion
    ) where

import           Control.Monad.Catch    (MonadMask (..))
import           Control.Monad.IO.Class
import           Control.Monad.Reader   (ask, lift)
import           Data.Aeson             (FromJSON, eitherDecode')
import qualified Data.ByteString        as BS
import qualified Data.ByteString.Lazy   as BSL
import           Data.Conduit           (Sink)
import qualified Data.Conduit.Binary    as Conduit
import qualified Data.Text              as T
import qualified Data.Text              as Text
import           Network.HTTP.Client    (responseStatus)
import           Network.HTTP.Types     (StdMethod (..))
import           System.Exit            (ExitCode (..))

import           Docker.Client.Http
import           Docker.Client.Types
import           Docker.Client.Utils

requestUnit :: (MonadIO m, MonadMask m) => HttpVerb -> Endpoint -> DockerT m (Either DockerError ())
requestUnit :: HttpVerb -> Endpoint -> DockerT m (Either DockerError ())
requestUnit HttpVerb
verb Endpoint
endpoint = (ByteString -> ())
-> Either DockerError ByteString -> Either DockerError ()
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (() -> ByteString -> ()
forall a b. a -> b -> a
const ()) (Either DockerError ByteString -> Either DockerError ())
-> DockerT m (Either DockerError ByteString)
-> DockerT m (Either DockerError ())
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> HttpVerb -> Endpoint -> DockerT m (Either DockerError ByteString)
forall (m :: * -> *).
(MonadIO m, MonadMask m) =>
HttpVerb -> Endpoint -> DockerT m (Either DockerError ByteString)
requestHelper HttpVerb
verb Endpoint
endpoint

requestHelper :: (MonadIO m, MonadMask m) => HttpVerb -> Endpoint -> DockerT m (Either DockerError BSL.ByteString)
requestHelper :: HttpVerb -> Endpoint -> DockerT m (Either DockerError ByteString)
requestHelper HttpVerb
verb Endpoint
endpoint = HttpVerb
-> Endpoint
-> Sink ByteString m ByteString
-> DockerT m (Either DockerError ByteString)
forall (m :: * -> *) a.
(MonadIO m, MonadMask m) =>
HttpVerb
-> Endpoint
-> Sink ByteString m a
-> DockerT m (Either DockerError a)
requestHelper' HttpVerb
verb Endpoint
endpoint Sink ByteString m ByteString
forall (m :: * -> *) o.
Monad m =>
ConduitT ByteString o m ByteString
Conduit.sinkLbs

requestHelper' :: (MonadIO m, MonadMask m) => HttpVerb -> Endpoint -> Sink BS.ByteString m a -> DockerT m (Either DockerError a)
requestHelper' :: HttpVerb
-> Endpoint
-> Sink ByteString m a
-> DockerT m (Either DockerError a)
requestHelper' HttpVerb
verb Endpoint
endpoint Sink ByteString m a
sink = do
    (DockerClientOpts
opts, HttpHandler forall a.
Request
-> (Response () -> Sink ByteString m (Either DockerError a))
-> m (Either DockerError a)
httpHandler) <- DockerT m (DockerClientOpts, HttpHandler m)
forall r (m :: * -> *). MonadReader r m => m r
ask
    case HttpVerb -> Endpoint -> DockerClientOpts -> Maybe Request
mkHttpRequest HttpVerb
verb Endpoint
endpoint DockerClientOpts
opts of
        Maybe Request
Nothing ->
            Either DockerError a -> DockerT m (Either DockerError a)
forall (m :: * -> *) a. Monad m => a -> m a
return (Either DockerError a -> DockerT m (Either DockerError a))
-> Either DockerError a -> DockerT m (Either DockerError a)
forall a b. (a -> b) -> a -> b
$ DockerError -> Either DockerError a
forall a b. a -> Either a b
Left (DockerError -> Either DockerError a)
-> DockerError -> Either DockerError a
forall a b. (a -> b) -> a -> b
$ Endpoint -> DockerError
DockerInvalidRequest Endpoint
endpoint
        Just Request
request -> do
            -- JP: Do we need runResourceT?
            -- lift $ NHS.httpSink request $ \response ->
            m (Either DockerError a) -> DockerT m (Either DockerError a)
forall (t :: (* -> *) -> * -> *) (m :: * -> *) a.
(MonadTrans t, Monad m) =>
m a -> t m a
lift (m (Either DockerError a) -> DockerT m (Either DockerError a))
-> m (Either DockerError a) -> DockerT m (Either DockerError a)
forall a b. (a -> b) -> a -> b
$ Request
-> (Response () -> Sink ByteString m (Either DockerError a))
-> m (Either DockerError a)
forall a.
Request
-> (Response () -> Sink ByteString m (Either DockerError a))
-> m (Either DockerError a)
httpHandler Request
request ((Response () -> Sink ByteString m (Either DockerError a))
 -> m (Either DockerError a))
-> (Response () -> Sink ByteString m (Either DockerError a))
-> m (Either DockerError a)
forall a b. (a -> b) -> a -> b
$ \Response ()
response ->
                -- Check status code.
                let status :: Status
status = Response () -> Status
forall body. Response body -> Status
responseStatus Response ()
response in
                case Endpoint -> Status -> Maybe DockerError
statusCodeToError Endpoint
endpoint Status
status of
                    Just DockerError
err ->
                        Either DockerError a -> Sink ByteString m (Either DockerError a)
forall (m :: * -> *) a. Monad m => a -> m a
return (Either DockerError a -> Sink ByteString m (Either DockerError a))
-> Either DockerError a -> Sink ByteString m (Either DockerError a)
forall a b. (a -> b) -> a -> b
$ DockerError -> Either DockerError a
forall a b. a -> Either a b
Left DockerError
err
                    Maybe DockerError
Nothing ->
                        (a -> Either DockerError a)
-> Sink ByteString m a -> Sink ByteString m (Either DockerError a)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap a -> Either DockerError a
forall a b. b -> Either a b
Right Sink ByteString m a
sink

parseResponse :: (FromJSON a, Monad m) => Either DockerError BSL.ByteString -> DockerT m (Either DockerError a)
parseResponse :: Either DockerError ByteString -> DockerT m (Either DockerError a)
parseResponse (Left DockerError
err) =
    Either DockerError a -> DockerT m (Either DockerError a)
forall (m :: * -> *) a. Monad m => a -> m a
return (Either DockerError a -> DockerT m (Either DockerError a))
-> Either DockerError a -> DockerT m (Either DockerError a)
forall a b. (a -> b) -> a -> b
$ DockerError -> Either DockerError a
forall a b. a -> Either a b
Left DockerError
err
parseResponse (Right ByteString
response) =
    -- Parse request body.
    case ByteString -> Either String a
forall a. FromJSON a => ByteString -> Either String a
eitherDecode' ByteString
response of
        Left String
err ->
            Either DockerError a -> DockerT m (Either DockerError a)
forall (m :: * -> *) a. Monad m => a -> m a
return (Either DockerError a -> DockerT m (Either DockerError a))
-> Either DockerError a -> DockerT m (Either DockerError a)
forall a b. (a -> b) -> a -> b
$ DockerError -> Either DockerError a
forall a b. a -> Either a b
Left (DockerError -> Either DockerError a)
-> DockerError -> Either DockerError a
forall a b. (a -> b) -> a -> b
$ Text -> DockerError
DockerClientDecodeError (Text -> DockerError) -> Text -> DockerError
forall a b. (a -> b) -> a -> b
$ String -> Text
Text.pack String
err
        Right a
r ->
            Either DockerError a -> DockerT m (Either DockerError a)
forall (m :: * -> *) a. Monad m => a -> m a
return (Either DockerError a -> DockerT m (Either DockerError a))
-> Either DockerError a -> DockerT m (Either DockerError a)
forall a b. (a -> b) -> a -> b
$ a -> Either DockerError a
forall a b. b -> Either a b
Right a
r

-- | Gets the version of the docker engine remote API.
getDockerVersion :: forall m. (MonadIO m, MonadMask m) => DockerT m (Either DockerError DockerVersion)
getDockerVersion :: DockerT m (Either DockerError DockerVersion)
getDockerVersion = HttpVerb -> Endpoint -> DockerT m (Either DockerError ByteString)
forall (m :: * -> *).
(MonadIO m, MonadMask m) =>
HttpVerb -> Endpoint -> DockerT m (Either DockerError ByteString)
requestHelper HttpVerb
GET Endpoint
VersionEndpoint DockerT m (Either DockerError ByteString)
-> (Either DockerError ByteString
    -> DockerT m (Either DockerError DockerVersion))
-> DockerT m (Either DockerError DockerVersion)
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= Either DockerError ByteString
-> DockerT m (Either DockerError DockerVersion)
forall a (m :: * -> *).
(FromJSON a, Monad m) =>
Either DockerError ByteString -> DockerT m (Either DockerError a)
parseResponse

-- | Lists all running docker containers. Pass in @'defaultListOpts' {all
-- = True}@ to get a list of stopped containers as well.
listContainers :: forall m. (MonadIO m, MonadMask m) => ListOpts -> DockerT m (Either DockerError [Container])
listContainers :: ListOpts -> DockerT m (Either DockerError [Container])
listContainers ListOpts
opts = HttpVerb -> Endpoint -> DockerT m (Either DockerError ByteString)
forall (m :: * -> *).
(MonadIO m, MonadMask m) =>
HttpVerb -> Endpoint -> DockerT m (Either DockerError ByteString)
requestHelper HttpVerb
GET (ListOpts -> Endpoint
ListContainersEndpoint ListOpts
opts) DockerT m (Either DockerError ByteString)
-> (Either DockerError ByteString
    -> DockerT m (Either DockerError [Container]))
-> DockerT m (Either DockerError [Container])
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= Either DockerError ByteString
-> DockerT m (Either DockerError [Container])
forall a (m :: * -> *).
(FromJSON a, Monad m) =>
Either DockerError ByteString -> DockerT m (Either DockerError a)
parseResponse

-- | Lists all docker images.
listImages :: forall m. (MonadIO m, MonadMask m) => ListOpts -> DockerT m (Either DockerError [Image])
listImages :: ListOpts -> DockerT m (Either DockerError [Image])
listImages ListOpts
opts = HttpVerb -> Endpoint -> DockerT m (Either DockerError ByteString)
forall (m :: * -> *).
(MonadIO m, MonadMask m) =>
HttpVerb -> Endpoint -> DockerT m (Either DockerError ByteString)
requestHelper HttpVerb
GET (ListOpts -> Endpoint
ListImagesEndpoint ListOpts
opts) DockerT m (Either DockerError ByteString)
-> (Either DockerError ByteString
    -> DockerT m (Either DockerError [Image]))
-> DockerT m (Either DockerError [Image])
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= Either DockerError ByteString
-> DockerT m (Either DockerError [Image])
forall a (m :: * -> *).
(FromJSON a, Monad m) =>
Either DockerError ByteString -> DockerT m (Either DockerError a)
parseResponse

-- | Deletes an image with the given 'ImageID'.
-- See "ImageDeleteOpts" for options and use 'defaultImageDeleteOpts' for sane
-- defaults.
deleteImage :: forall m. (MonadIO m, MonadMask m) => ImageDeleteOpts -> ImageID -> DockerT m (Either DockerError ())
deleteImage :: ImageDeleteOpts -> ImageID -> DockerT m (Either DockerError ())
deleteImage ImageDeleteOpts
dopts ImageID
iid = HttpVerb -> Endpoint -> DockerT m (Either DockerError ())
forall (m :: * -> *).
(MonadIO m, MonadMask m) =>
HttpVerb -> Endpoint -> DockerT m (Either DockerError ())
requestUnit HttpVerb
DELETE (Endpoint -> DockerT m (Either DockerError ()))
-> Endpoint -> DockerT m (Either DockerError ())
forall a b. (a -> b) -> a -> b
$ ImageDeleteOpts -> ImageID -> Endpoint
DeleteImageEndpoint ImageDeleteOpts
dopts ImageID
iid

-- | Creates a docker container but does __not__ start it. See
-- 'CreateOpts' for a list of options and you can use 'defaultCreateOpts'
-- for some sane defaults.
createContainer :: forall m. (MonadIO m, MonadMask m) => CreateOpts -> Maybe ContainerName -> DockerT m (Either DockerError ContainerID)
createContainer :: CreateOpts
-> Maybe Text -> DockerT m (Either DockerError ContainerID)
createContainer CreateOpts
opts Maybe Text
cn = HttpVerb -> Endpoint -> DockerT m (Either DockerError ByteString)
forall (m :: * -> *).
(MonadIO m, MonadMask m) =>
HttpVerb -> Endpoint -> DockerT m (Either DockerError ByteString)
requestHelper HttpVerb
POST (CreateOpts -> Maybe Text -> Endpoint
CreateContainerEndpoint CreateOpts
opts Maybe Text
cn) DockerT m (Either DockerError ByteString)
-> (Either DockerError ByteString
    -> DockerT m (Either DockerError ContainerID))
-> DockerT m (Either DockerError ContainerID)
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= Either DockerError ByteString
-> DockerT m (Either DockerError ContainerID)
forall a (m :: * -> *).
(FromJSON a, Monad m) =>
Either DockerError ByteString -> DockerT m (Either DockerError a)
parseResponse

-- | Start a container from a given 'ContainerID' that we get from
-- 'createContainer'. See 'StartOpts' for a list of configuration options
-- for starting a container. Use 'defaultStartOpts' for sane defaults.
startContainer :: forall m. (MonadIO m, MonadMask m) => StartOpts -> ContainerID -> DockerT m (Either DockerError ())
startContainer :: StartOpts -> ContainerID -> DockerT m (Either DockerError ())
startContainer StartOpts
sopts ContainerID
cid = HttpVerb -> Endpoint -> DockerT m (Either DockerError ())
forall (m :: * -> *).
(MonadIO m, MonadMask m) =>
HttpVerb -> Endpoint -> DockerT m (Either DockerError ())
requestUnit HttpVerb
POST (Endpoint -> DockerT m (Either DockerError ()))
-> Endpoint -> DockerT m (Either DockerError ())
forall a b. (a -> b) -> a -> b
$ StartOpts -> ContainerID -> Endpoint
StartContainerEndpoint StartOpts
sopts ContainerID
cid

-- | Attempts to stop a container with the given 'ContainerID' gracefully
-- (SIGTERM).
-- The docker daemon will wait for the given 'Timeout' and then send
-- a SIGKILL killing the container.
stopContainer :: forall m. (MonadIO m, MonadMask m) => Timeout -> ContainerID -> DockerT m (Either DockerError ())
stopContainer :: Timeout -> ContainerID -> DockerT m (Either DockerError ())
stopContainer Timeout
t ContainerID
cid = HttpVerb -> Endpoint -> DockerT m (Either DockerError ())
forall (m :: * -> *).
(MonadIO m, MonadMask m) =>
HttpVerb -> Endpoint -> DockerT m (Either DockerError ())
requestUnit HttpVerb
POST (Endpoint -> DockerT m (Either DockerError ()))
-> Endpoint -> DockerT m (Either DockerError ())
forall a b. (a -> b) -> a -> b
$ Timeout -> ContainerID -> Endpoint
StopContainerEndpoint Timeout
t ContainerID
cid

-- | Blocks until a container with the given 'ContainerID' stops,
-- then returns the exit code
waitContainer :: forall m. (MonadIO m, MonadMask m) => ContainerID -> DockerT m (Either DockerError ExitCode)
waitContainer :: ContainerID -> DockerT m (Either DockerError ExitCode)
waitContainer ContainerID
cid = (Either DockerError StatusCode -> Either DockerError ExitCode)
-> DockerT m (Either DockerError StatusCode)
-> DockerT m (Either DockerError ExitCode)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap ((StatusCode -> ExitCode)
-> Either DockerError StatusCode -> Either DockerError ExitCode
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap StatusCode -> ExitCode
statusCodeToExitCode) (HttpVerb -> Endpoint -> DockerT m (Either DockerError ByteString)
forall (m :: * -> *).
(MonadIO m, MonadMask m) =>
HttpVerb -> Endpoint -> DockerT m (Either DockerError ByteString)
requestHelper HttpVerb
POST (ContainerID -> Endpoint
WaitContainerEndpoint ContainerID
cid) DockerT m (Either DockerError ByteString)
-> (Either DockerError ByteString
    -> DockerT m (Either DockerError StatusCode))
-> DockerT m (Either DockerError StatusCode)
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= Either DockerError ByteString
-> DockerT m (Either DockerError StatusCode)
forall a (m :: * -> *).
(FromJSON a, Monad m) =>
Either DockerError ByteString -> DockerT m (Either DockerError a)
parseResponse)
  where
    statusCodeToExitCode :: StatusCode -> ExitCode
statusCodeToExitCode (StatusCode Int
0) = ExitCode
ExitSuccess
    statusCodeToExitCode (StatusCode Int
x) = Int -> ExitCode
ExitFailure Int
x

-- | Sends a 'Signal' to the container with the given 'ContainerID'. Same
-- as 'stopContainer' but you choose the signal directly.
killContainer :: forall m. (MonadIO m, MonadMask m) => Signal -> ContainerID -> DockerT m (Either DockerError ())
killContainer :: Signal -> ContainerID -> DockerT m (Either DockerError ())
killContainer Signal
s ContainerID
cid = HttpVerb -> Endpoint -> DockerT m (Either DockerError ())
forall (m :: * -> *).
(MonadIO m, MonadMask m) =>
HttpVerb -> Endpoint -> DockerT m (Either DockerError ())
requestUnit HttpVerb
POST (Endpoint -> DockerT m (Either DockerError ()))
-> Endpoint -> DockerT m (Either DockerError ())
forall a b. (a -> b) -> a -> b
$ Signal -> ContainerID -> Endpoint
KillContainerEndpoint Signal
s ContainerID
cid

-- | Restarts a container with the given 'ContainerID'.
restartContainer :: forall m. (MonadIO m, MonadMask m) => Timeout -> ContainerID -> DockerT m (Either DockerError ())
restartContainer :: Timeout -> ContainerID -> DockerT m (Either DockerError ())
restartContainer Timeout
t ContainerID
cid = HttpVerb -> Endpoint -> DockerT m (Either DockerError ())
forall (m :: * -> *).
(MonadIO m, MonadMask m) =>
HttpVerb -> Endpoint -> DockerT m (Either DockerError ())
requestUnit HttpVerb
POST (Endpoint -> DockerT m (Either DockerError ()))
-> Endpoint -> DockerT m (Either DockerError ())
forall a b. (a -> b) -> a -> b
$ Timeout -> ContainerID -> Endpoint
RestartContainerEndpoint Timeout
t ContainerID
cid

-- | Pauses a container with the given 'ContainerID'.
pauseContainer :: forall m. (MonadIO m, MonadMask m) => ContainerID -> DockerT m (Either DockerError ())
pauseContainer :: ContainerID -> DockerT m (Either DockerError ())
pauseContainer ContainerID
cid = HttpVerb -> Endpoint -> DockerT m (Either DockerError ())
forall (m :: * -> *).
(MonadIO m, MonadMask m) =>
HttpVerb -> Endpoint -> DockerT m (Either DockerError ())
requestUnit HttpVerb
POST (Endpoint -> DockerT m (Either DockerError ()))
-> Endpoint -> DockerT m (Either DockerError ())
forall a b. (a -> b) -> a -> b
$ ContainerID -> Endpoint
PauseContainerEndpoint ContainerID
cid

-- | Unpauses a container with the given 'ContainerID'.
unpauseContainer :: forall m. (MonadIO m, MonadMask m) => ContainerID -> DockerT m (Either DockerError ())
unpauseContainer :: ContainerID -> DockerT m (Either DockerError ())
unpauseContainer ContainerID
cid = HttpVerb -> Endpoint -> DockerT m (Either DockerError ())
forall (m :: * -> *).
(MonadIO m, MonadMask m) =>
HttpVerb -> Endpoint -> DockerT m (Either DockerError ())
requestUnit HttpVerb
GET (Endpoint -> DockerT m (Either DockerError ()))
-> Endpoint -> DockerT m (Either DockerError ())
forall a b. (a -> b) -> a -> b
$ ContainerID -> Endpoint
UnpauseContainerEndpoint ContainerID
cid

-- | Deletes a container with the given 'ContainerID'.
-- See "ContainerDeleteOpts" for options and use 'defaultContainerDeleteOpts' for sane
-- defaults.
deleteContainer :: forall m. (MonadIO m, MonadMask m) => ContainerDeleteOpts -> ContainerID -> DockerT m (Either DockerError ())
deleteContainer :: ContainerDeleteOpts
-> ContainerID -> DockerT m (Either DockerError ())
deleteContainer ContainerDeleteOpts
dopts ContainerID
cid = HttpVerb -> Endpoint -> DockerT m (Either DockerError ())
forall (m :: * -> *).
(MonadIO m, MonadMask m) =>
HttpVerb -> Endpoint -> DockerT m (Either DockerError ())
requestUnit HttpVerb
DELETE (Endpoint -> DockerT m (Either DockerError ()))
-> Endpoint -> DockerT m (Either DockerError ())
forall a b. (a -> b) -> a -> b
$ ContainerDeleteOpts -> ContainerID -> Endpoint
DeleteContainerEndpoint ContainerDeleteOpts
dopts ContainerID
cid

-- | Gets 'ContainerDetails' for a given 'ContainerID'.
inspectContainer :: forall m . (MonadIO m, MonadMask m) => ContainerID -> DockerT m (Either DockerError ContainerDetails)
inspectContainer :: ContainerID -> DockerT m (Either DockerError ContainerDetails)
inspectContainer ContainerID
cid = HttpVerb -> Endpoint -> DockerT m (Either DockerError ByteString)
forall (m :: * -> *).
(MonadIO m, MonadMask m) =>
HttpVerb -> Endpoint -> DockerT m (Either DockerError ByteString)
requestHelper HttpVerb
GET (ContainerID -> Endpoint
InspectContainerEndpoint ContainerID
cid) DockerT m (Either DockerError ByteString)
-> (Either DockerError ByteString
    -> DockerT m (Either DockerError ContainerDetails))
-> DockerT m (Either DockerError ContainerDetails)
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= Either DockerError ByteString
-> DockerT m (Either DockerError ContainerDetails)
forall a (m :: * -> *).
(FromJSON a, Monad m) =>
Either DockerError ByteString -> DockerT m (Either DockerError a)
parseResponse

-- | Get's container's logs for a given 'ContainerID'.
-- This will only work with the 'JsonFile' 'LogDriverType' as the other driver types disable
-- this endpoint and it will return a 'DockerError'.
--
-- See 'LogOpts' for options that you can pass and
-- 'defaultLogOpts' for sane defaults.
--
-- __NOTE__: his function will fetch the entire log that the
-- container produced in the json-file on disk. Depending on the logging
-- setup of the process in your container this can be a significant amount
-- which might block your application...so use with caution.
--
-- If you want to stream the logs from the container continuosly then use
-- 'getContainerLogsStream'
--
-- __NOTE__: It's recommended to use one of the other 'LogDriverType's available (like
-- syslog) for creating your containers.
getContainerLogs ::  forall m. (MonadIO m, MonadMask m) => LogOpts -> ContainerID -> DockerT m (Either DockerError BSL.ByteString)
getContainerLogs :: LogOpts -> ContainerID -> DockerT m (Either DockerError ByteString)
getContainerLogs LogOpts
logopts ContainerID
cid = HttpVerb -> Endpoint -> DockerT m (Either DockerError ByteString)
forall (m :: * -> *).
(MonadIO m, MonadMask m) =>
HttpVerb -> Endpoint -> DockerT m (Either DockerError ByteString)
requestHelper HttpVerb
GET (LogOpts -> Bool -> ContainerID -> Endpoint
ContainerLogsEndpoint LogOpts
logopts Bool
False ContainerID
cid)

{-| Continuously gets the container's logs as a stream. Uses conduit.

__Example__:

@
>>> import Docker.Client
>>> import Data.Maybe
>>> import Conduit
>>> h <- defaultHttpHanlder
>>> let cid = fromJust $ toContainerID "fee86e1d522b"
>>> runDockerT (defaultClientOpts, h) $ getContainerLogsStream defaultLogOpts cid stdoutC
@

-}
getContainerLogsStream :: forall m b . (MonadIO m, MonadMask m) => LogOpts -> ContainerID -> Sink BS.ByteString m b -> DockerT m (Either DockerError b)
getContainerLogsStream :: LogOpts
-> ContainerID
-> Sink ByteString m b
-> DockerT m (Either DockerError b)
getContainerLogsStream LogOpts
logopts ContainerID
cid = HttpVerb
-> Endpoint
-> Sink ByteString m b
-> DockerT m (Either DockerError b)
forall (m :: * -> *) a.
(MonadIO m, MonadMask m) =>
HttpVerb
-> Endpoint
-> Sink ByteString m a
-> DockerT m (Either DockerError a)
requestHelper' HttpVerb
GET (LogOpts -> Bool -> ContainerID -> Endpoint
ContainerLogsEndpoint LogOpts
logopts Bool
True ContainerID
cid)
-- JP: Should the second (follow) argument be True? XXX

-- | Build an Image from a Dockerfile
--
-- TODO: Add X-Registry-Config
--
-- TODO: Add support for remote URLs to a Dockerfile
--
-- TODO: Clean up temp tar.gz file after the image is built
buildImageFromDockerfile :: forall m. (MonadIO m, MonadMask m) => BuildOpts -> FilePath -> DockerT m (Either DockerError ())
buildImageFromDockerfile :: BuildOpts -> String -> DockerT m (Either DockerError ())
buildImageFromDockerfile BuildOpts
opts String
base = do
    Either DockerError String
ctx <- BuildContextRootDir -> DockerT m (Either DockerError String)
forall (m :: * -> *).
MonadIO m =>
BuildContextRootDir -> m (Either DockerError String)
makeBuildContext (BuildContextRootDir -> DockerT m (Either DockerError String))
-> BuildContextRootDir -> DockerT m (Either DockerError String)
forall a b. (a -> b) -> a -> b
$ String -> BuildContextRootDir
BuildContextRootDir String
base
    case Either DockerError String
ctx of
        Left DockerError
e  -> Either DockerError () -> DockerT m (Either DockerError ())
forall (m :: * -> *) a. Monad m => a -> m a
return (Either DockerError () -> DockerT m (Either DockerError ()))
-> Either DockerError () -> DockerT m (Either DockerError ())
forall a b. (a -> b) -> a -> b
$ DockerError -> Either DockerError ()
forall a b. a -> Either a b
Left DockerError
e
        Right String
c -> HttpVerb -> Endpoint -> DockerT m (Either DockerError ())
forall (m :: * -> *).
(MonadIO m, MonadMask m) =>
HttpVerb -> Endpoint -> DockerT m (Either DockerError ())
requestUnit HttpVerb
POST (BuildOpts -> String -> Endpoint
BuildImageEndpoint BuildOpts
opts String
c)

-- | Pulls an image from Docker Hub (by default).
--
-- TODO: Add support for X-Registry-Auth and pulling from private docker
-- registries.
--
-- TODO: Implement importImage function that uses he same
-- CreateImageEndpoint but rather than pulling from docker hub it imports
-- the image from a tarball or a URL.
pullImage :: forall m b . (MonadIO m, MonadMask m) => T.Text -> Tag -> Sink BS.ByteString m b -> DockerT m (Either DockerError b)
pullImage :: Text
-> Text -> Sink ByteString m b -> DockerT m (Either DockerError b)
pullImage Text
name Text
tag = HttpVerb
-> Endpoint
-> Sink ByteString m b
-> DockerT m (Either DockerError b)
forall (m :: * -> *) a.
(MonadIO m, MonadMask m) =>
HttpVerb
-> Endpoint
-> Sink ByteString m a
-> DockerT m (Either DockerError a)
requestHelper' HttpVerb
POST (Text -> Text -> Maybe Text -> Endpoint
CreateImageEndpoint Text
name Text
tag Maybe Text
forall a. Maybe a
Nothing)

-- | Creates network
createNetwork :: forall m. (MonadIO m, MonadMask m) => CreateNetworkOpts -> DockerT m (Either DockerError NetworkID)
createNetwork :: CreateNetworkOpts -> DockerT m (Either DockerError NetworkID)
createNetwork CreateNetworkOpts
opts = HttpVerb -> Endpoint -> DockerT m (Either DockerError ByteString)
forall (m :: * -> *).
(MonadIO m, MonadMask m) =>
HttpVerb -> Endpoint -> DockerT m (Either DockerError ByteString)
requestHelper HttpVerb
POST (CreateNetworkOpts -> Endpoint
CreateNetworkEndpoint CreateNetworkOpts
opts)  DockerT m (Either DockerError ByteString)
-> (Either DockerError ByteString
    -> DockerT m (Either DockerError NetworkID))
-> DockerT m (Either DockerError NetworkID)
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= Either DockerError ByteString
-> DockerT m (Either DockerError NetworkID)
forall a (m :: * -> *).
(FromJSON a, Monad m) =>
Either DockerError ByteString -> DockerT m (Either DockerError a)
parseResponse

-- | Removes a network
removeNetwork :: forall m. (MonadIO m, MonadMask m) => NetworkID -> DockerT m (Either DockerError ())
removeNetwork :: NetworkID -> DockerT m (Either DockerError ())
removeNetwork NetworkID
nid = HttpVerb -> Endpoint -> DockerT m (Either DockerError ())
forall (m :: * -> *).
(MonadIO m, MonadMask m) =>
HttpVerb -> Endpoint -> DockerT m (Either DockerError ())
requestUnit HttpVerb
DELETE (Endpoint -> DockerT m (Either DockerError ()))
-> Endpoint -> DockerT m (Either DockerError ())
forall a b. (a -> b) -> a -> b
$ NetworkID -> Endpoint
RemoveNetworkEndpoint NetworkID
nid