packages feed

groot-0.0.1.0: src/Groot/CLI/List/ContainerInstance.hs

{-# LANGUAGE DeriveDataTypeable    #-}
{-# LANGUAGE DeriveGeneric         #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE OverloadedStrings     #-}

module Groot.CLI.List.ContainerInstance
     ( printInstanceSummary
     ) where

import           Control.Lens
import           Control.Monad.IO.Class
import           Control.Monad.Trans.Reader
import           Data.Conduit
import qualified Data.Conduit.List          as CL
import           Data.Data
import           Data.List
import           Data.Text                  (Text)
import qualified Data.Text                  as T
import           GHC.Generics
import           Network.AWS
import qualified Network.AWS.ECS            as ECS
import           Numeric
import           Text.PrettyPrint.Tabulate  (CellValueFormatter, Tabulate,
                                             printTable)
import qualified Text.PrettyPrint.Tabulate  as Tabs

import           Groot.CLI.List.Common
import           Groot.Console
import           Groot.Core
import           Groot.Types

data ResourceType =
    Memory
  | CPU
  deriving (Eq, Show, Generic, Data)

data ResourceSummary = ResourceSummary
  { resourceType :: ResourceType
  , allocated    :: Int
  , available    :: Int
  } deriving (Eq, Generic, Data)

instance Show ResourceSummary where
  show (ResourceSummary resType alloc avail) = concat [show avail, "/", show alloc, " ", units, " ", percent]
    where units = case resType of
            Memory -> "mb"
            CPU    -> "units"
          percent =
            let pvalue = (fromIntegral avail) / (fromIntegral alloc) * 100.0 :: Float
            in concat ["(", showFFloat (Just 1) pvalue "", " %)"]

instance CellValueFormatter ResourceSummary

resourceSummary :: ResourceType -> ECS.ContainerInstance -> Maybe ResourceSummary
resourceSummary resType inst = (ResourceSummary resType) <$> rAlloc <*> rAvail
  where resName = case resType of
          Memory -> "MEMORY"
          CPU    -> "CPU"

        findResource :: [ECS.Resource] -> Maybe Int
        findResource rs = (view ECS.rIntegerValue) =<< find (\x -> maybe False (== resName) $ x ^. ECS.rName) rs

        rAlloc = findResource $ inst ^. ECS.ciRegisteredResources
        rAvail = findResource $ inst ^. ECS.ciRemainingResources

data InstanceSummary = InstanceSummary
  { instanceId    :: String
  , ec2InstaceId  :: String
  , status        :: String
  , runningTasks  :: Int
  , pendingTasks  :: Int
  , memory        :: ResourceSummary
  , cpu           :: ResourceSummary
  , agentVersion  :: String
  , dockerVersion :: String
  } deriving (Eq, Show, Generic, Data)

instance Tabulate InstanceSummary Tabs.ExpandWhenNested

instance HasSummary ECS.ContainerInstance InstanceSummary where
  summarize inst = InstanceSummary <$> iId <*> iEc2Id <*> iStatus <*> iRunning <*> iPending <*> iMem <*> iCpu <*> iAgentV <*> iDockerV
    where iId      = (asString . view arnContainerInstanceId) <$> viewArn (ECS.ciContainerInstanceARN . _Just) inst
          iEc2Id   = T.unpack <$> inst ^. ECS.ciEc2InstanceId
          iStatus  = T.unpack <$> inst ^. ECS.ciStatus
          iRunning = inst ^. ECS.ciRunningTasksCount
          iPending = inst ^. ECS.ciPendingTasksCount
          iMem     = resourceSummary Memory inst
          iCpu     = resourceSummary CPU inst
          iAgentV  = T.unpack <$> (inst ^. ECS.ciVersionInfo >>= view ECS.viAgentVersion)
          iDockerV = T.unpack <$> (inst ^. ECS.ciVersionInfo >>= view ECS.viDockerVersion)

summarizeInstances :: Maybe ClusterRef -> AWS [InstanceSummary]
summarizeInstances cId =
  sourceToList $ instanceSource cId =$= CL.mapMaybe summarize
  where instanceSource Nothing  = fetchAllInstances
        instanceSource (Just x) = fetchInstances x

printInstanceSummary :: Maybe ClusterRef -> GrootM IO ()
printInstanceSummary cId = do
  env  <- ask
  desc <- runResourceT . runAWS env $ summarizeInstances cId
  case desc of
    [] -> putWarn ("No container instances found" :: Text)
    xs -> liftIO $ printTable xs