root / src / Ganeti / Monitoring / Server.hs @ e10c4a69
History | View | Annotate | Download (8.5 kB)
1 | 13cc7b84 | Michele Tartara | {-# LANGUAGE OverloadedStrings #-} |
---|---|---|---|
2 | 13cc7b84 | Michele Tartara | |
3 | 13cc7b84 | Michele Tartara | {-| Implementation of the Ganeti confd server functionality. |
4 | 13cc7b84 | Michele Tartara | |
5 | 13cc7b84 | Michele Tartara | -} |
6 | 13cc7b84 | Michele Tartara | |
7 | 13cc7b84 | Michele Tartara | {- |
8 | 13cc7b84 | Michele Tartara | |
9 | 13cc7b84 | Michele Tartara | Copyright (C) 2013 Google Inc. |
10 | 13cc7b84 | Michele Tartara | |
11 | 13cc7b84 | Michele Tartara | This program is free software; you can redistribute it and/or modify |
12 | 13cc7b84 | Michele Tartara | it under the terms of the GNU General Public License as published by |
13 | 13cc7b84 | Michele Tartara | the Free Software Foundation; either version 2 of the License, or |
14 | 13cc7b84 | Michele Tartara | (at your option) any later version. |
15 | 13cc7b84 | Michele Tartara | |
16 | 13cc7b84 | Michele Tartara | This program is distributed in the hope that it will be useful, but |
17 | 13cc7b84 | Michele Tartara | WITHOUT ANY WARRANTY; without even the implied warranty of |
18 | 13cc7b84 | Michele Tartara | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
19 | 13cc7b84 | Michele Tartara | General Public License for more details. |
20 | 13cc7b84 | Michele Tartara | |
21 | 13cc7b84 | Michele Tartara | You should have received a copy of the GNU General Public License |
22 | 13cc7b84 | Michele Tartara | along with this program; if not, write to the Free Software |
23 | 13cc7b84 | Michele Tartara | Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA |
24 | 13cc7b84 | Michele Tartara | 02110-1301, USA. |
25 | 13cc7b84 | Michele Tartara | |
26 | 13cc7b84 | Michele Tartara | -} |
27 | 13cc7b84 | Michele Tartara | |
28 | 13cc7b84 | Michele Tartara | module Ganeti.Monitoring.Server |
29 | 13cc7b84 | Michele Tartara | ( main |
30 | 13cc7b84 | Michele Tartara | , checkMain |
31 | 13cc7b84 | Michele Tartara | , prepMain |
32 | 13cc7b84 | Michele Tartara | ) where |
33 | 13cc7b84 | Michele Tartara | |
34 | 423b2dd5 | Michele Tartara | import Control.Applicative |
35 | 423b2dd5 | Michele Tartara | import Control.Monad |
36 | db1ad1d5 | Michele Tartara | import Control.Monad.IO.Class |
37 | db1ad1d5 | Michele Tartara | import Data.ByteString.Char8 hiding (map, filter, find) |
38 | db1ad1d5 | Michele Tartara | import Data.List |
39 | 3792fa8e | Spyros Trigazis | import qualified Data.Map as Map |
40 | eb65c915 | Michele Tartara | import Snap.Core |
41 | eb65c915 | Michele Tartara | import Snap.Http.Server |
42 | eb65c915 | Michele Tartara | import qualified Text.JSON as J |
43 | 3792fa8e | Spyros Trigazis | import Control.Concurrent |
44 | eb65c915 | Michele Tartara | |
45 | db1ad1d5 | Michele Tartara | import qualified Ganeti.BasicTypes as BT |
46 | 13cc7b84 | Michele Tartara | import Ganeti.Daemon |
47 | 3792fa8e | Spyros Trigazis | import qualified Ganeti.DataCollectors.CPUload as CPUload |
48 | aab0927c | Michele Tartara | import qualified Ganeti.DataCollectors.Diskstats as Diskstats |
49 | ecb783f0 | Michele Tartara | import qualified Ganeti.DataCollectors.Drbd as Drbd |
50 | 8a049311 | Michele Tartara | import qualified Ganeti.DataCollectors.InstStatus as InstStatus |
51 | 006d6bc9 | Michele Tartara | import qualified Ganeti.DataCollectors.Lv as Lv |
52 | ecb783f0 | Michele Tartara | import Ganeti.DataCollectors.Types |
53 | eb65c915 | Michele Tartara | import qualified Ganeti.Constants as C |
54 | 34be621a | Jose A. Lopes | import Ganeti.Runtime |
55 | 13cc7b84 | Michele Tartara | |
56 | 13cc7b84 | Michele Tartara | -- * Types and constants definitions |
57 | 13cc7b84 | Michele Tartara | |
58 | 13cc7b84 | Michele Tartara | -- | Type alias for checkMain results. |
59 | 13cc7b84 | Michele Tartara | type CheckResult = () |
60 | 13cc7b84 | Michele Tartara | |
61 | 13cc7b84 | Michele Tartara | -- | Type alias for prepMain results. |
62 | eb65c915 | Michele Tartara | type PrepResult = Config Snap () |
63 | eb65c915 | Michele Tartara | |
64 | eb65c915 | Michele Tartara | -- | Version of the latest supported http API. |
65 | eb65c915 | Michele Tartara | latestAPIVersion :: Int |
66 | 690e509d | Spyros Trigazis | latestAPIVersion = C.mondLatestApiVersion |
67 | eb65c915 | Michele Tartara | |
68 | 3792fa8e | Spyros Trigazis | -- | A report of a data collector might be stateful or stateless. |
69 | 3792fa8e | Spyros Trigazis | data Report = StatelessR (IO DCReport) |
70 | 3792fa8e | Spyros Trigazis | | StatefulR (Maybe CollectorData -> IO DCReport) |
71 | 3792fa8e | Spyros Trigazis | |
72 | ecb783f0 | Michele Tartara | -- | Type describing a data collector basic information |
73 | ecb783f0 | Michele Tartara | data DataCollector = DataCollector |
74 | ecb783f0 | Michele Tartara | { dName :: String -- ^ Name of the data collector |
75 | ecb783f0 | Michele Tartara | , dCategory :: Maybe DCCategory -- ^ Category (storage, instance, ecc) |
76 | ecb783f0 | Michele Tartara | -- of the collector |
77 | ecb783f0 | Michele Tartara | , dKind :: DCKind -- ^ Kind (performance or status reporting) of |
78 | ecb783f0 | Michele Tartara | -- the data collector |
79 | 3792fa8e | Spyros Trigazis | , dReport :: Report -- ^ Report produced by the collector |
80 | 3792fa8e | Spyros Trigazis | , dUpdate :: Maybe (Maybe CollectorData -> IO CollectorData) |
81 | 3792fa8e | Spyros Trigazis | -- ^ Update operation for stateful collectors. |
82 | ecb783f0 | Michele Tartara | } |
83 | ecb783f0 | Michele Tartara | |
84 | 3792fa8e | Spyros Trigazis | |
85 | ecb783f0 | Michele Tartara | -- | The list of available builtin data collectors. |
86 | ecb783f0 | Michele Tartara | collectors :: [DataCollector] |
87 | ecb783f0 | Michele Tartara | collectors = |
88 | aab0927c | Michele Tartara | [ DataCollector Diskstats.dcName Diskstats.dcCategory Diskstats.dcKind |
89 | 3792fa8e | Spyros Trigazis | (StatelessR Diskstats.dcReport) Nothing |
90 | 3792fa8e | Spyros Trigazis | , DataCollector Drbd.dcName Drbd.dcCategory Drbd.dcKind |
91 | 3792fa8e | Spyros Trigazis | (StatelessR Drbd.dcReport) Nothing |
92 | 8a049311 | Michele Tartara | , DataCollector InstStatus.dcName InstStatus.dcCategory InstStatus.dcKind |
93 | 3792fa8e | Spyros Trigazis | (StatelessR InstStatus.dcReport) Nothing |
94 | 3792fa8e | Spyros Trigazis | , DataCollector Lv.dcName Lv.dcCategory Lv.dcKind |
95 | 3792fa8e | Spyros Trigazis | (StatelessR Lv.dcReport) Nothing |
96 | 3792fa8e | Spyros Trigazis | , DataCollector CPUload.dcName CPUload.dcCategory CPUload.dcKind |
97 | 3792fa8e | Spyros Trigazis | (StatefulR CPUload.dcReport) (Just CPUload.dcUpdate) |
98 | ecb783f0 | Michele Tartara | ] |
99 | ecb783f0 | Michele Tartara | |
100 | eb65c915 | Michele Tartara | -- * Configuration handling |
101 | eb65c915 | Michele Tartara | |
102 | eb65c915 | Michele Tartara | -- | The default configuration for the HTTP server. |
103 | 34be621a | Jose A. Lopes | defaultHttpConf :: FilePath -> FilePath -> Config Snap () |
104 | 34be621a | Jose A. Lopes | defaultHttpConf accessLog errorLog = |
105 | 34be621a | Jose A. Lopes | setAccessLog (ConfigFileLog accessLog) . |
106 | eb65c915 | Michele Tartara | setCompression False . |
107 | 34be621a | Jose A. Lopes | setErrorLog (ConfigFileLog errorLog) $ |
108 | eb65c915 | Michele Tartara | setVerbose False |
109 | eb65c915 | Michele Tartara | emptyConfig |
110 | 13cc7b84 | Michele Tartara | |
111 | 13cc7b84 | Michele Tartara | -- * Helper functions |
112 | 13cc7b84 | Michele Tartara | |
113 | 13cc7b84 | Michele Tartara | -- | Check function for the monitoring agent. |
114 | 13cc7b84 | Michele Tartara | checkMain :: CheckFn CheckResult |
115 | 13cc7b84 | Michele Tartara | checkMain _ = return $ Right () |
116 | 13cc7b84 | Michele Tartara | |
117 | 13cc7b84 | Michele Tartara | -- | Prepare function for monitoring agent. |
118 | 13cc7b84 | Michele Tartara | prepMain :: PrepFn CheckResult PrepResult |
119 | 34be621a | Jose A. Lopes | prepMain opts _ = do |
120 | 1c31b263 | Jose A. Lopes | accessLog <- daemonsExtraLogFile GanetiMond AccessLog |
121 | 1c31b263 | Jose A. Lopes | errorLog <- daemonsExtraLogFile GanetiMond ErrorLog |
122 | 1c31b263 | Jose A. Lopes | return $ |
123 | 1c31b263 | Jose A. Lopes | setPort |
124 | 1c31b263 | Jose A. Lopes | (maybe C.defaultMondPort fromIntegral (optPort opts)) |
125 | 1c31b263 | Jose A. Lopes | (defaultHttpConf accessLog errorLog) |
126 | eb65c915 | Michele Tartara | |
127 | eb65c915 | Michele Tartara | -- * Query answers |
128 | eb65c915 | Michele Tartara | |
129 | eb65c915 | Michele Tartara | -- | Reply to the supported API version numbers query. |
130 | eb65c915 | Michele Tartara | versionQ :: Snap () |
131 | 423b2dd5 | Michele Tartara | versionQ = writeBS . pack $ J.encode [latestAPIVersion] |
132 | 423b2dd5 | Michele Tartara | |
133 | 423b2dd5 | Michele Tartara | -- | Version 1 of the monitoring HTTP API. |
134 | 3792fa8e | Spyros Trigazis | version1Api :: MVar CollectorMap -> Snap () |
135 | 3792fa8e | Spyros Trigazis | version1Api mvar = |
136 | 423b2dd5 | Michele Tartara | let returnNull = writeBS . pack $ J.encode J.JSNull :: Snap () |
137 | 423b2dd5 | Michele Tartara | in ifTop returnNull <|> |
138 | 423b2dd5 | Michele Tartara | route |
139 | 423b2dd5 | Michele Tartara | [ ("list", listHandler) |
140 | 3792fa8e | Spyros Trigazis | , ("report", reportHandler mvar) |
141 | 423b2dd5 | Michele Tartara | ] |
142 | 423b2dd5 | Michele Tartara | |
143 | ecb783f0 | Michele Tartara | -- | Get the JSON representation of a data collector to be used in the collector |
144 | ecb783f0 | Michele Tartara | -- list. |
145 | ecb783f0 | Michele Tartara | dcListItem :: DataCollector -> J.JSValue |
146 | ecb783f0 | Michele Tartara | dcListItem dc = |
147 | ecb783f0 | Michele Tartara | J.JSArray |
148 | ecb783f0 | Michele Tartara | [ J.showJSON $ dName dc |
149 | ecb783f0 | Michele Tartara | , maybe J.JSNull J.showJSON $ dCategory dc |
150 | ecb783f0 | Michele Tartara | , J.showJSON $ dKind dc |
151 | ecb783f0 | Michele Tartara | ] |
152 | ecb783f0 | Michele Tartara | |
153 | 423b2dd5 | Michele Tartara | -- | Handler for returning lists. |
154 | 423b2dd5 | Michele Tartara | listHandler :: Snap () |
155 | 423b2dd5 | Michele Tartara | listHandler = |
156 | ecb783f0 | Michele Tartara | dir "collectors" . writeBS . pack . J.encode $ map dcListItem collectors |
157 | 423b2dd5 | Michele Tartara | |
158 | 423b2dd5 | Michele Tartara | -- | Handler for returning data collector reports. |
159 | 3792fa8e | Spyros Trigazis | reportHandler :: MVar CollectorMap -> Snap () |
160 | 3792fa8e | Spyros Trigazis | reportHandler mvar = |
161 | 423b2dd5 | Michele Tartara | route |
162 | 3792fa8e | Spyros Trigazis | [ ("all", allReports mvar) |
163 | 3792fa8e | Spyros Trigazis | , (":category/:collector", oneReport mvar) |
164 | e580e9f7 | Michele Tartara | ] <|> |
165 | e580e9f7 | Michele Tartara | errorReport |
166 | 423b2dd5 | Michele Tartara | |
167 | db1ad1d5 | Michele Tartara | -- | Return the report of all the available collectors. |
168 | 3792fa8e | Spyros Trigazis | allReports :: MVar CollectorMap -> Snap () |
169 | 3792fa8e | Spyros Trigazis | allReports mvar = do |
170 | 3792fa8e | Spyros Trigazis | reports <- mapM (liftIO . getReport mvar) collectors |
171 | 6327828e | Michele Tartara | writeBS . pack . J.encode $ reports |
172 | 423b2dd5 | Michele Tartara | |
173 | 3792fa8e | Spyros Trigazis | -- | Takes the CollectorMap and a DataCollector and returns the report for this |
174 | 3792fa8e | Spyros Trigazis | -- collector. |
175 | 3792fa8e | Spyros Trigazis | getReport :: MVar CollectorMap -> DataCollector -> IO DCReport |
176 | 3792fa8e | Spyros Trigazis | getReport mvar collector = |
177 | 3792fa8e | Spyros Trigazis | case dReport collector of |
178 | 3792fa8e | Spyros Trigazis | StatelessR r -> r |
179 | 3792fa8e | Spyros Trigazis | StatefulR r -> do |
180 | 3792fa8e | Spyros Trigazis | colData <- getColData (dName collector) mvar |
181 | 3792fa8e | Spyros Trigazis | r colData |
182 | 3792fa8e | Spyros Trigazis | |
183 | 3792fa8e | Spyros Trigazis | -- | Returns the data for the corresponding collector. |
184 | 3792fa8e | Spyros Trigazis | getColData :: String -> MVar CollectorMap -> IO (Maybe CollectorData) |
185 | 3792fa8e | Spyros Trigazis | getColData name mvar = do |
186 | 3792fa8e | Spyros Trigazis | m <- readMVar mvar |
187 | 3792fa8e | Spyros Trigazis | return $ Map.lookup name m |
188 | 3792fa8e | Spyros Trigazis | |
189 | db1ad1d5 | Michele Tartara | -- | Returns a category given its name. |
190 | db1ad1d5 | Michele Tartara | -- If "collector" is given as the name, the collector has no category, and |
191 | db1ad1d5 | Michele Tartara | -- Nothing will be returned. |
192 | db1ad1d5 | Michele Tartara | catFromName :: String -> BT.Result (Maybe DCCategory) |
193 | db1ad1d5 | Michele Tartara | catFromName "instance" = BT.Ok $ Just DCInstance |
194 | db1ad1d5 | Michele Tartara | catFromName "storage" = BT.Ok $ Just DCStorage |
195 | db1ad1d5 | Michele Tartara | catFromName "daemon" = BT.Ok $ Just DCDaemon |
196 | db1ad1d5 | Michele Tartara | catFromName "hypervisor" = BT.Ok $ Just DCHypervisor |
197 | db1ad1d5 | Michele Tartara | catFromName "default" = BT.Ok Nothing |
198 | db1ad1d5 | Michele Tartara | catFromName _ = BT.Bad "No such category" |
199 | db1ad1d5 | Michele Tartara | |
200 | e580e9f7 | Michele Tartara | errorReport :: Snap () |
201 | e580e9f7 | Michele Tartara | errorReport = do |
202 | e580e9f7 | Michele Tartara | modifyResponse $ setResponseStatus 404 "Not found" |
203 | e580e9f7 | Michele Tartara | writeBS "Unable to produce a report for the requested resource" |
204 | e580e9f7 | Michele Tartara | |
205 | e580e9f7 | Michele Tartara | error404 :: Snap () |
206 | e580e9f7 | Michele Tartara | error404 = do |
207 | e580e9f7 | Michele Tartara | modifyResponse $ setResponseStatus 404 "Not found" |
208 | e580e9f7 | Michele Tartara | writeBS "Resource not found" |
209 | e580e9f7 | Michele Tartara | |
210 | 3792fa8e | Spyros Trigazis | -- | Return the report of one collector. |
211 | 3792fa8e | Spyros Trigazis | oneReport :: MVar CollectorMap -> Snap () |
212 | 3792fa8e | Spyros Trigazis | oneReport mvar = do |
213 | db1ad1d5 | Michele Tartara | categoryName <- fmap (maybe mzero unpack) $ getParam "category" |
214 | db1ad1d5 | Michele Tartara | collectorName <- fmap (maybe mzero unpack) $ getParam "collector" |
215 | db1ad1d5 | Michele Tartara | category <- |
216 | db1ad1d5 | Michele Tartara | case catFromName categoryName of |
217 | db1ad1d5 | Michele Tartara | BT.Ok cat -> return cat |
218 | db1ad1d5 | Michele Tartara | BT.Bad msg -> fail msg |
219 | db1ad1d5 | Michele Tartara | collector <- |
220 | db1ad1d5 | Michele Tartara | case |
221 | db1ad1d5 | Michele Tartara | find (\col -> collectorName == dName col) $ |
222 | db1ad1d5 | Michele Tartara | filter (\c -> category == dCategory c) collectors of |
223 | db1ad1d5 | Michele Tartara | Just col -> return col |
224 | db1ad1d5 | Michele Tartara | Nothing -> fail "Unable to find the requested collector" |
225 | 3792fa8e | Spyros Trigazis | dcr <- liftIO $ getReport mvar collector |
226 | 3792fa8e | Spyros Trigazis | writeBS . pack . J.encode $ dcr |
227 | eb65c915 | Michele Tartara | |
228 | eb65c915 | Michele Tartara | -- | The function implementing the HTTP API of the monitoring agent. |
229 | 3792fa8e | Spyros Trigazis | monitoringApi :: MVar CollectorMap -> Snap () |
230 | 3792fa8e | Spyros Trigazis | monitoringApi mvar = |
231 | 423b2dd5 | Michele Tartara | ifTop versionQ <|> |
232 | 3792fa8e | Spyros Trigazis | dir "1" (version1Api mvar) <|> |
233 | e580e9f7 | Michele Tartara | error404 |
234 | 13cc7b84 | Michele Tartara | |
235 | 3792fa8e | Spyros Trigazis | -- | The function collecting data for each data collector providing a dcUpdate |
236 | 3792fa8e | Spyros Trigazis | -- function. |
237 | 3792fa8e | Spyros Trigazis | collect :: CollectorMap -> DataCollector -> IO CollectorMap |
238 | 3792fa8e | Spyros Trigazis | collect m collector = |
239 | 3792fa8e | Spyros Trigazis | case dUpdate collector of |
240 | 3792fa8e | Spyros Trigazis | Nothing -> return m |
241 | 3792fa8e | Spyros Trigazis | Just update -> do |
242 | 3792fa8e | Spyros Trigazis | let name = dName collector |
243 | 3792fa8e | Spyros Trigazis | existing = Map.lookup name m |
244 | 3792fa8e | Spyros Trigazis | new_data <- update existing |
245 | 3792fa8e | Spyros Trigazis | return $ Map.insert name new_data m |
246 | 3792fa8e | Spyros Trigazis | |
247 | 3792fa8e | Spyros Trigazis | -- | Invokes collect for each data collector. |
248 | 3792fa8e | Spyros Trigazis | collection :: CollectorMap -> IO CollectorMap |
249 | 3792fa8e | Spyros Trigazis | collection m = foldM collect m collectors |
250 | 3792fa8e | Spyros Trigazis | |
251 | 3792fa8e | Spyros Trigazis | -- | The thread responsible for the periodical collection of data for each data |
252 | 3792fa8e | Spyros Trigazis | -- data collector. |
253 | 3792fa8e | Spyros Trigazis | collectord :: MVar CollectorMap -> IO () |
254 | 3792fa8e | Spyros Trigazis | collectord mvar = do |
255 | 3792fa8e | Spyros Trigazis | m <- takeMVar mvar |
256 | 3792fa8e | Spyros Trigazis | m' <- collection m |
257 | 3792fa8e | Spyros Trigazis | putMVar mvar m' |
258 | 3792fa8e | Spyros Trigazis | threadDelay $ 10^(6 :: Int) * C.mondTimeInterval |
259 | 3792fa8e | Spyros Trigazis | collectord mvar |
260 | 3792fa8e | Spyros Trigazis | |
261 | 13cc7b84 | Michele Tartara | -- | Main function. |
262 | 13cc7b84 | Michele Tartara | main :: MainFn CheckResult PrepResult |
263 | 3792fa8e | Spyros Trigazis | main _ _ httpConf = do |
264 | 3792fa8e | Spyros Trigazis | mvar <- newMVar Map.empty |
265 | 3792fa8e | Spyros Trigazis | _ <- forkIO $ collectord mvar |
266 | 3792fa8e | Spyros Trigazis | httpServe httpConf . method GET $ monitoringApi mvar |