module Ganeti.Monitoring.Server
( main
, checkMain
, prepMain
) where
import Control.Applicative
import Control.Monad
import Control.Monad.IO.Class
import Data.ByteString.Char8 hiding (map, filter, find)
import Data.List
import Snap.Core
import Snap.Http.Server
import qualified Text.JSON as J
import qualified Ganeti.BasicTypes as BT
import Ganeti.Daemon
import qualified Ganeti.DataCollectors.Drbd as Drbd
import Ganeti.DataCollectors.Types
import qualified Ganeti.Constants as C
type CheckResult = ()
type PrepResult = Config Snap ()
latestAPIVersion :: Int
latestAPIVersion = 1
data DataCollector = DataCollector
{ dName :: String
, dCategory :: Maybe DCCategory
, dKind :: DCKind
, dReport :: IO DCReport
}
collectors :: [DataCollector]
collectors =
[ DataCollector Drbd.dcName Drbd.dcCategory Drbd.dcKind Drbd.dcReport
]
defaultHttpConf :: Config Snap ()
defaultHttpConf =
setAccessLog (ConfigFileLog C.daemonsExtraLogfilesGanetiMondAccess) .
setCompression False .
setErrorLog (ConfigFileLog C.daemonsExtraLogfilesGanetiMondError) $
setVerbose False
emptyConfig
checkMain :: CheckFn CheckResult
checkMain _ = return $ Right ()
prepMain :: PrepFn CheckResult PrepResult
prepMain opts _ =
return $
setPort (maybe C.defaultMondPort fromIntegral (optPort opts))
defaultHttpConf
versionQ :: Snap ()
versionQ = writeBS . pack $ J.encode [latestAPIVersion]
version1Api :: Snap ()
version1Api =
let returnNull = writeBS . pack $ J.encode J.JSNull :: Snap ()
in ifTop returnNull <|>
route
[ ("list", listHandler)
, ("report", reportHandler)
]
dcListItem :: DataCollector -> J.JSValue
dcListItem dc =
J.JSArray
[ J.showJSON $ dName dc
, maybe J.JSNull J.showJSON $ dCategory dc
, J.showJSON $ dKind dc
]
listHandler :: Snap ()
listHandler =
dir "collectors" . writeBS . pack . J.encode $ map dcListItem collectors
reportHandler :: Snap ()
reportHandler =
route
[ ("all", allReports)
, (":category/:collector", oneReport)
] <|>
errorReport
allReports :: Snap ()
allReports = do
reports <- mapM (liftIO . dReport) collectors
writeBS . pack . J.encode $ reports
catFromName :: String -> BT.Result (Maybe DCCategory)
catFromName "instance" = BT.Ok $ Just DCInstance
catFromName "storage" = BT.Ok $ Just DCStorage
catFromName "daemon" = BT.Ok $ Just DCDaemon
catFromName "hypervisor" = BT.Ok $ Just DCHypervisor
catFromName "default" = BT.Ok Nothing
catFromName _ = BT.Bad "No such category"
errorReport :: Snap ()
errorReport = do
modifyResponse $ setResponseStatus 404 "Not found"
writeBS "Unable to produce a report for the requested resource"
error404 :: Snap ()
error404 = do
modifyResponse $ setResponseStatus 404 "Not found"
writeBS "Resource not found"
oneReport :: Snap ()
oneReport = do
categoryName <- fmap (maybe mzero unpack) $ getParam "category"
collectorName <- fmap (maybe mzero unpack) $ getParam "collector"
category <-
case catFromName categoryName of
BT.Ok cat -> return cat
BT.Bad msg -> fail msg
collector <-
case
find (\col -> collectorName == dName col) $
filter (\c -> category == dCategory c) collectors of
Just col -> return col
Nothing -> fail "Unable to find the requested collector"
report <- liftIO $ dReport collector
writeBS . pack . J.encode $ report
monitoringApi :: Snap ()
monitoringApi =
ifTop versionQ <|>
dir "1" version1Api <|>
error404
main :: MainFn CheckResult PrepResult
main _ _ httpConf =
httpServe httpConf $ method GET monitoringApi