packages feed

groot-0.0.1.0: src/Groot/CLI/Service/Compose.hs

{-# LANGUAGE OverloadedStrings #-}

module Groot.CLI.Service.Compose
     ( ServiceComposeOpts(..)
     , serviceComposeOpts
     , runServiceUp
     , runServiceDelete
     ) where

import           Control.Lens        hiding (argument)
import           Control.Monad.Catch
import           Data.HashMap.Strict (HashMap)
import qualified Data.HashMap.Strict as Map
import           Data.Semigroup      ((<>))
import           Data.String
import           Data.Text           (Text)
import           Options.Applicative

import           Groot.CLI.Common
import           Groot.Compose
import           Groot.Core
import           Groot.Exception
import           Groot.Manifest
import           Groot.Types

-- Command Line

data ServiceComposeOpts = ServiceComposeOpts
  { manifestFile :: Maybe FilePath
  , cluster      :: ClusterRef
  , runMode      :: Maybe RunMode
  , serviceNames :: [Text]
  } deriving (Eq, Show)

dryRunOpt :: Parser RunMode
dryRunOpt = flag' DryRun
          ( long "dryRun"
         <> short 't'
         <> help "Just emulate but do not perform any changes" )

unattendedOpt :: Parser RunMode
unattendedOpt = flag' Unattended
              ( long "yes"
             <> short 'y'
             <> help "Answer 'yes' to all questions." )

runModeOpt :: Parser RunMode
runModeOpt = dryRunOpt <|> unattendedOpt

serviceNameArg :: Parser Text
serviceNameArg = fromString <$> argument str (metavar "SERVICES")

serviceComposeOpts :: Parser ServiceComposeOpts
serviceComposeOpts = ServiceComposeOpts
                 <$> optional manifestFileOpt
                 <*> clusterOpt
                 <*> optional runModeOpt
                 <*> many serviceNameArg

-- Main functions

selectServices :: MonadThrow m => FilePath -> [Text] -> HashMap Text ServiceDeployment -> m [NamedServiceDeployment]
selectServices _        [] m = pure $ Map.toList m
selectServices manifest xs m = traverse selectService xs
  where selectService :: MonadThrow m => Text -> m NamedServiceDeployment
        selectService serviceName =
          let dep = maybe (throwM $ undefinedService serviceName manifest) pure $ Map.lookup serviceName m
              pairUp x = (serviceName,x)
          in pairUp <$> dep

performAction :: Text -> (ServiceComposeCfg -> ServiceComposeM ()) -> ServiceComposeOpts -> GrootM IO ()
performAction userMsg buildComposeAction opts = do
  let manifestFileName = maybe defaultManifestFilePath id $ manifestFile opts
  manifest      <- loadManifest manifestFileName
  serviceList   <- selectServices manifestFileName (serviceNames opts) $ manifest ^. gmServices
  cfg           <- pure $ ServiceComposeCfg manifest (cluster opts) serviceList (runMode opts)
  composeAction <- pure $ buildComposeAction cfg
  interpretServiceComposeM userMsg composeAction cfg

doDeployServices :: ServiceComposeCfg -> ServiceComposeM ()
doDeployServices (ServiceComposeCfg _ clusterRef serviceList _) =
  deployServices clusterRef serviceList

doDeleteServices :: ServiceComposeCfg -> ServiceComposeM ()
doDeleteServices (ServiceComposeCfg _ clusterRef serviceList _) =
  deleteServices clusterRef serviceList

runServiceUp :: ServiceComposeOpts -> GrootM IO ()
runServiceUp = performAction "This will start deployment of the following services:" doDeployServices

runServiceDelete :: ServiceComposeOpts -> GrootM IO ()
runServiceDelete = performAction "This will delete the following services:" doDeleteServices