Commit 3792fa8e authored by Spyros Trigazis's avatar Spyros Trigazis Committed by Michele Tartara
Browse files

mond: Introduce a new threading mechanism



Change mond's interface in order to be able to call periodically the
collection functions of the data collectors that support such
functionality. The data of such a collector is stored in a map with the
data collector's name as the key.

Currently, only the CPUload data collector provides this kind of
functionality.
Signed-off-by: default avatarSpyros Trigazis <strigazi@gmail.com>
Signed-off-by: default avatarMichele Tartara <mtartara@google.com>
Reviewed-by: default avatarMichele Tartara <mtartara@google.com>
parent 2da679f7
......@@ -2547,5 +2547,8 @@ STAT_FILE = "/proc/stat"
CPUAVGLOAD_BUFFER_SIZE = 150
CPUAVGLOAD_WINDOW_SIZE = 600
# Mond's variable for periodical data collection
MOND_TIME_INTERVAL = 5
# Do not re-export imported modules
del re, _vcsversion, _autoconf, socket, pathutils, compat
......@@ -36,12 +36,15 @@ import Control.Monad
import Control.Monad.IO.Class
import Data.ByteString.Char8 hiding (map, filter, find)
import Data.List
import qualified Data.Map as Map
import Snap.Core
import Snap.Http.Server
import qualified Text.JSON as J
import Control.Concurrent
import qualified Ganeti.BasicTypes as BT
import Ganeti.Daemon
import qualified Ganeti.DataCollectors.CPUload as CPUload
import qualified Ganeti.DataCollectors.Diskstats as Diskstats
import qualified Ganeti.DataCollectors.Drbd as Drbd
import qualified Ganeti.DataCollectors.InstStatus as InstStatus
......@@ -61,6 +64,10 @@ type PrepResult = Config Snap ()
latestAPIVersion :: Int
latestAPIVersion = 1
-- | A report of a data collector might be stateful or stateless.
data Report = StatelessR (IO DCReport)
| StatefulR (Maybe CollectorData -> IO DCReport)
-- | Type describing a data collector basic information
data DataCollector = DataCollector
{ dName :: String -- ^ Name of the data collector
......@@ -68,18 +75,25 @@ data DataCollector = DataCollector
-- of the collector
, dKind :: DCKind -- ^ Kind (performance or status reporting) of
-- the data collector
, dReport :: IO DCReport -- ^ Report produced by the collector
, dReport :: Report -- ^ Report produced by the collector
, dUpdate :: Maybe (Maybe CollectorData -> IO CollectorData)
-- ^ Update operation for stateful collectors.
}
-- | The list of available builtin data collectors.
collectors :: [DataCollector]
collectors =
[ DataCollector Diskstats.dcName Diskstats.dcCategory Diskstats.dcKind
Diskstats.dcReport
, DataCollector Drbd.dcName Drbd.dcCategory Drbd.dcKind Drbd.dcReport
(StatelessR Diskstats.dcReport) Nothing
, DataCollector Drbd.dcName Drbd.dcCategory Drbd.dcKind
(StatelessR Drbd.dcReport) Nothing
, DataCollector InstStatus.dcName InstStatus.dcCategory InstStatus.dcKind
InstStatus.dcReport
, DataCollector Lv.dcName Lv.dcCategory Lv.dcKind Lv.dcReport
(StatelessR InstStatus.dcReport) Nothing
, DataCollector Lv.dcName Lv.dcCategory Lv.dcKind
(StatelessR Lv.dcReport) Nothing
, DataCollector CPUload.dcName CPUload.dcCategory CPUload.dcKind
(StatefulR CPUload.dcReport) (Just CPUload.dcUpdate)
]
-- * Configuration handling
......@@ -113,13 +127,13 @@ versionQ :: Snap ()
versionQ = writeBS . pack $ J.encode [latestAPIVersion]
-- | Version 1 of the monitoring HTTP API.
version1Api :: Snap ()
version1Api =
version1Api :: MVar CollectorMap -> Snap ()
version1Api mvar =
let returnNull = writeBS . pack $ J.encode J.JSNull :: Snap ()
in ifTop returnNull <|>
route
[ ("list", listHandler)
, ("report", reportHandler)
, ("report", reportHandler mvar)
]
-- | Get the JSON representation of a data collector to be used in the collector
......@@ -138,20 +152,36 @@ listHandler =
dir "collectors" . writeBS . pack . J.encode $ map dcListItem collectors
-- | Handler for returning data collector reports.
reportHandler :: Snap ()
reportHandler =
reportHandler :: MVar CollectorMap -> Snap ()
reportHandler mvar =
route
[ ("all", allReports)
, (":category/:collector", oneReport)
[ ("all", allReports mvar)
, (":category/:collector", oneReport mvar)
] <|>
errorReport
-- | Return the report of all the available collectors.
allReports :: Snap ()
allReports = do
reports <- mapM (liftIO . dReport) collectors
allReports :: MVar CollectorMap -> Snap ()
allReports mvar = do
reports <- mapM (liftIO . getReport mvar) collectors
writeBS . pack . J.encode $ reports
-- | Takes the CollectorMap and a DataCollector and returns the report for this
-- collector.
getReport :: MVar CollectorMap -> DataCollector -> IO DCReport
getReport mvar collector =
case dReport collector of
StatelessR r -> r
StatefulR r -> do
colData <- getColData (dName collector) mvar
r colData
-- | Returns the data for the corresponding collector.
getColData :: String -> MVar CollectorMap -> IO (Maybe CollectorData)
getColData name mvar = do
m <- readMVar mvar
return $ Map.lookup name m
-- | Returns a category given its name.
-- If "collector" is given as the name, the collector has no category, and
-- Nothing will be returned.
......@@ -173,9 +203,9 @@ error404 = do
modifyResponse $ setResponseStatus 404 "Not found"
writeBS "Resource not found"
-- | Return the report of one collector
oneReport :: Snap ()
oneReport = do
-- | Return the report of one collector.
oneReport :: MVar CollectorMap -> Snap ()
oneReport mvar = do
categoryName <- fmap (maybe mzero unpack) $ getParam "category"
collectorName <- fmap (maybe mzero unpack) $ getParam "collector"
category <-
......@@ -188,17 +218,45 @@ oneReport = do
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
dcr <- liftIO $ getReport mvar collector
writeBS . pack . J.encode $ dcr
-- | The function implementing the HTTP API of the monitoring agent.
monitoringApi :: Snap ()
monitoringApi =
monitoringApi :: MVar CollectorMap -> Snap ()
monitoringApi mvar =
ifTop versionQ <|>
dir "1" version1Api <|>
dir "1" (version1Api mvar) <|>
error404
-- | The function collecting data for each data collector providing a dcUpdate
-- function.
collect :: CollectorMap -> DataCollector -> IO CollectorMap
collect m collector =
case dUpdate collector of
Nothing -> return m
Just update -> do
let name = dName collector
existing = Map.lookup name m
new_data <- update existing
return $ Map.insert name new_data m
-- | Invokes collect for each data collector.
collection :: CollectorMap -> IO CollectorMap
collection m = foldM collect m collectors
-- | The thread responsible for the periodical collection of data for each data
-- data collector.
collectord :: MVar CollectorMap -> IO ()
collectord mvar = do
m <- takeMVar mvar
m' <- collection m
putMVar mvar m'
threadDelay $ 10^(6 :: Int) * C.mondTimeInterval
collectord mvar
-- | Main function.
main :: MainFn CheckResult PrepResult
main _ _ httpConf =
httpServe httpConf $ method GET monitoringApi
main _ _ httpConf = do
mvar <- newMVar Map.empty
_ <- forkIO $ collectord mvar
httpServe httpConf . method GET $ monitoringApi mvar
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment