funflow-1.0.0: src/Control/Funflow/External/Docker.hs
{-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE OverloadedStrings #-}
-- | Module supporting the use of docker containers as external tasks.
--
-- In general, an external task can be any command. This module just makes it
-- easier to specify certain tasks which will run inside docker containers. It
-- handles constructing the call to docker, mounting input and output
-- directories, and specifying the docker image and version to use.
module Control.Funflow.External.Docker where
import Control.Funflow.ContentHashable
import Control.Funflow.External
import Data.Map.Strict (Map)
import qualified Data.Map.Strict as Map
import Data.Semigroup ((<>))
import qualified Data.Text as T
import GHC.Generics (Generic)
import System.FilePath
data Bind
-- | Single input, will get mounted to @/input@ on the image.
= SingleInput InputPath
-- | Multiple inputs, each gets mouted into a subdirectory under
-- @/input@ as described by the given mapping.
| MultiInput (Map FilePath InputPath)
deriving Generic
instance ContentHashable IO Bind
data Config = Config
{ image :: T.Text
, optImageID :: Maybe T.Text
, input :: Bind
, command :: FilePath
, args :: [T.Text]
} deriving Generic
instance ContentHashable IO Config
toExternal :: Config -> ExternalTask
toExternal cfg = ExternalTask
-- XXX: Allow to configure the path to the docker executable.
{ _etCommand = "docker"
, _etParams =
[ "run"
, "--user=" <> uidParam
] ++ mounts ++
[ imageArg
, stringParam (command cfg)
] ++ map textParam (args cfg)
, _etWriteToStdOut = False
}
where
mounts = outputMount : inputMounts
mount src dst =
"--volume=" <> pathParam src <> ":" <> stringParam dst
outputMount = "--volume=" <> outParam <> ":/output"
inputMounts = case input cfg of
SingleInput chash -> [ mount chash "/input" ]
MultiInput cmap ->
[ mount chash ("/input" </> dest)
| (dest, chash) <- Map.toList cmap
]
imageArg = textParam $ case optImageID cfg of
Nothing -> image cfg
Just id' -> image cfg <> ":" <> id'