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.Diskstats as Diskstats
import qualified Ganeti.DataCollectors.Drbd as Drbd
import qualified Ganeti.DataCollectors.InstStatus as InstStatus
import qualified Ganeti.DataCollectors.Lv as Lv
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 Diskstats.dcName Diskstats.dcCategory Diskstats.dcKind
Diskstats.dcReport
, DataCollector Drbd.dcName Drbd.dcCategory Drbd.dcKind Drbd.dcReport
, DataCollector InstStatus.dcName InstStatus.dcCategory InstStatus.dcKind
InstStatus.dcReport
, DataCollector Lv.dcName Lv.dcCategory Lv.dcKind Lv.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 <- maybe mzero unpack <$> getParam "category"
collectorName <- 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