packages feed

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

{-# LANGUAGE OverloadedStrings #-}

module Groot.CLI.Service
     ( ServiceSubCmd
     , serviceCmds
     , runServiceCmd
     ) where

import           Control.Exception.Lens
import           Control.Monad.Catch
import           Data.Semigroup            ((<>))
import qualified Data.Text                 as T
import           Options.Applicative

import           Groot.CLI.Service.Compose
import           Groot.CLI.Service.Events
import           Groot.CLI.Service.Inspect
import           Groot.Console
import           Groot.Core
import           Groot.Data.Text
import           Groot.Exception

data ServiceSubCmd =
    ServiceEventsCmd  ServiceEventOpts
  | ServiceUpCmd      ServiceComposeOpts
  | ServiceDeleteCmd  ServiceComposeOpts
  | ServiceInspectCmd ServiceInspectOpts
  deriving (Eq, Show)

-- CLI

serviceEventsCmd :: Parser ServiceSubCmd
serviceEventsCmd = ServiceEventsCmd <$> serviceEventsOpt

serviceUpCmd :: Parser ServiceSubCmd
serviceUpCmd = ServiceUpCmd <$> serviceComposeOpts

serviceDeleteCmd :: Parser ServiceSubCmd
serviceDeleteCmd = ServiceDeleteCmd <$> serviceComposeOpts

serviceInspectCmd :: Parser ServiceSubCmd
serviceInspectCmd = ServiceInspectCmd <$> serviceInspectOpts

serviceCmds :: Parser ServiceSubCmd
serviceCmds = hsubparser
  ( command "events"  (info serviceEventsCmd  (progDesc "Display events of the given services."))
 <> command "up"      (info serviceUpCmd      (progDesc "Deploy services as stated in a service file."))
 <> command "rm"      (info serviceDeleteCmd  (progDesc "Delete previously deployed services."))
 <> command "inspect" (info serviceInspectCmd (progDesc "Inspect details of a given service."))
  )

-- Error handlers

handleUndefinedService :: MonadConsole m => UndefinedService -> m ()
handleUndefinedService (UndefinedService' serviceName manifestFile) =
  putError $ "Service" <+> (styled yellowStyle serviceName)
    <+> "has not been defined in compose file:"
    <+> (styled yellowStyle $ T.pack manifestFile)

handleDeploymentFailed :: MonadConsole m => FailedServiceDeployment -> m ()
handleDeploymentFailed (FailedServiceDeployment' serviceRef clusterRef reason) =
  putError $ "Failed to deploy service" <+> (styled yellowStyle $ toText serviceRef)
    <+> "in cluster" <+> (styled yellowStyle $ toText clusterRef)
    <> (maybe "" (\x -> " because" <+> (styled yellowStyle x)) reason)

handleDeletionFailed :: MonadConsole m => FailedServiceDeletion -> m ()
handleDeletionFailed (FailedServiceDeletion' serviceRef clusterRef) =
  putError $ "Failed to delete service" <+> (styled yellowStyle $ toText serviceRef)
    <+> "from cluster" <+> (styled yellowStyle $ toText clusterRef)

handleErrors :: GrootIO () -> GrootIO ()
handleErrors act = catches act [
    handler _UndefinedService        handleUndefinedService
  , handler _FailedServiceDeployment handleDeploymentFailed
  , handler _FailedServiceDeletion   handleDeletionFailed
  ]

-- run function

runServiceCmd :: ServiceSubCmd -> GrootM IO ()
runServiceCmd (ServiceEventsCmd eventsOpts)   = runServiceEvents  eventsOpts
runServiceCmd (ServiceUpCmd     composeOpts)  = handleErrors $ runServiceUp      composeOpts
runServiceCmd (ServiceDeleteCmd composeOpts)  = handleErrors $ runServiceDelete  composeOpts
runServiceCmd (ServiceInspectCmd inspectOpts) = runServiceInspect inspectOpts