Statistics
| Branch: | Tag: | Revision:

root / src / Ganeti / Monitoring / Server.hs @ aab0927c

History | View | Annotate | Download (6 kB)

1
{-# LANGUAGE OverloadedStrings #-}
2

    
3
{-| Implementation of the Ganeti confd server functionality.
4

    
5
-}
6

    
7
{-
8

    
9
Copyright (C) 2013 Google Inc.
10

    
11
This program is free software; you can redistribute it and/or modify
12
it under the terms of the GNU General Public License as published by
13
the Free Software Foundation; either version 2 of the License, or
14
(at your option) any later version.
15

    
16
This program is distributed in the hope that it will be useful, but
17
WITHOUT ANY WARRANTY; without even the implied warranty of
18
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
19
General Public License for more details.
20

    
21
You should have received a copy of the GNU General Public License
22
along with this program; if not, write to the Free Software
23
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
24
02110-1301, USA.
25

    
26
-}
27

    
28
module Ganeti.Monitoring.Server
29
  ( main
30
  , checkMain
31
  , prepMain
32
  ) where
33

    
34
import Control.Applicative
35
import Control.Monad
36
import Control.Monad.IO.Class
37
import Data.ByteString.Char8 hiding (map, filter, find)
38
import Data.List
39
import Snap.Core
40
import Snap.Http.Server
41
import qualified Text.JSON as J
42

    
43
import qualified Ganeti.BasicTypes as BT
44
import Ganeti.Daemon
45
import qualified Ganeti.DataCollectors.Diskstats as Diskstats
46
import qualified Ganeti.DataCollectors.Drbd as Drbd
47
import qualified Ganeti.DataCollectors.InstStatus as InstStatus
48
import Ganeti.DataCollectors.Types
49
import qualified Ganeti.Constants as C
50

    
51
-- * Types and constants definitions
52

    
53
-- | Type alias for checkMain results.
54
type CheckResult = ()
55

    
56
-- | Type alias for prepMain results.
57
type PrepResult = Config Snap ()
58

    
59
-- | Version of the latest supported http API.
60
latestAPIVersion :: Int
61
latestAPIVersion = 1
62

    
63
-- | Type describing a data collector basic information
64
data DataCollector = DataCollector
65
  { dName     :: String           -- ^ Name of the data collector
66
  , dCategory :: Maybe DCCategory -- ^ Category (storage, instance, ecc)
67
                                  --   of the collector
68
  , dKind     :: DCKind           -- ^ Kind (performance or status reporting) of
69
                                  --   the data collector
70
  , dReport   :: IO DCReport      -- ^ Report produced by the collector
71
  }
72

    
73
-- | The list of available builtin data collectors.
74
collectors :: [DataCollector]
75
collectors =
76
  [ DataCollector Diskstats.dcName Diskstats.dcCategory Diskstats.dcKind
77
      Diskstats.dcReport
78
  , DataCollector Drbd.dcName Drbd.dcCategory Drbd.dcKind Drbd.dcReport
79
  , DataCollector InstStatus.dcName InstStatus.dcCategory InstStatus.dcKind
80
      InstStatus.dcReport
81
  ]
82

    
83
-- * Configuration handling
84

    
85
-- | The default configuration for the HTTP server.
86
defaultHttpConf :: Config Snap ()
87
defaultHttpConf =
88
  setAccessLog (ConfigFileLog C.daemonsExtraLogfilesGanetiMondAccess) .
89
  setCompression False .
90
  setErrorLog (ConfigFileLog C.daemonsExtraLogfilesGanetiMondError) $
91
  setVerbose False
92
  emptyConfig
93

    
94
-- * Helper functions
95

    
96
-- | Check function for the monitoring agent.
97
checkMain :: CheckFn CheckResult
98
checkMain _ = return $ Right ()
99

    
100
-- | Prepare function for monitoring agent.
101
prepMain :: PrepFn CheckResult PrepResult
102
prepMain opts _ =
103
  return $
104
    setPort (maybe C.defaultMondPort fromIntegral (optPort opts))
105
      defaultHttpConf
106

    
107
-- * Query answers
108

    
109
-- | Reply to the supported API version numbers query.
110
versionQ :: Snap ()
111
versionQ = writeBS . pack $ J.encode [latestAPIVersion]
112

    
113
-- | Version 1 of the monitoring HTTP API.
114
version1Api :: Snap ()
115
version1Api =
116
  let returnNull = writeBS . pack $ J.encode J.JSNull :: Snap ()
117
  in ifTop returnNull <|>
118
     route
119
       [ ("list", listHandler)
120
       , ("report", reportHandler)
121
       ]
122

    
123
-- | Get the JSON representation of a data collector to be used in the collector
124
-- list.
125
dcListItem :: DataCollector -> J.JSValue
126
dcListItem dc =
127
  J.JSArray
128
    [ J.showJSON $ dName dc
129
    , maybe J.JSNull J.showJSON $ dCategory dc
130
    , J.showJSON $ dKind dc
131
    ]
132

    
133
-- | Handler for returning lists.
134
listHandler :: Snap ()
135
listHandler =
136
  dir "collectors" . writeBS . pack . J.encode $ map dcListItem collectors
137

    
138
-- | Handler for returning data collector reports.
139
reportHandler :: Snap ()
140
reportHandler =
141
  route
142
    [ ("all", allReports)
143
    , (":category/:collector", oneReport)
144
    ] <|>
145
  errorReport
146

    
147
-- | Return the report of all the available collectors.
148
allReports :: Snap ()
149
allReports = do
150
  reports <- mapM (liftIO . dReport) collectors
151
  writeBS . pack . J.encode $ reports
152

    
153
-- | Returns a category given its name.
154
-- If "collector" is given as the name, the collector has no category, and
155
-- Nothing will be returned.
156
catFromName :: String -> BT.Result (Maybe DCCategory)
157
catFromName "instance"   = BT.Ok $ Just DCInstance
158
catFromName "storage"    = BT.Ok $ Just DCStorage
159
catFromName "daemon"     = BT.Ok $ Just DCDaemon
160
catFromName "hypervisor" = BT.Ok $ Just DCHypervisor
161
catFromName "default"    = BT.Ok Nothing
162
catFromName _            = BT.Bad "No such category"
163

    
164
errorReport :: Snap ()
165
errorReport = do
166
  modifyResponse $ setResponseStatus 404 "Not found"
167
  writeBS "Unable to produce a report for the requested resource"
168

    
169
error404 :: Snap ()
170
error404 = do
171
  modifyResponse $ setResponseStatus 404 "Not found"
172
  writeBS "Resource not found"
173

    
174
-- | Return the report of one collector
175
oneReport :: Snap ()
176
oneReport = do
177
  categoryName <- fmap (maybe mzero unpack) $ getParam "category"
178
  collectorName <- fmap (maybe mzero unpack) $ getParam "collector"
179
  category <-
180
    case catFromName categoryName of
181
      BT.Ok cat -> return cat
182
      BT.Bad msg -> fail msg
183
  collector <-
184
    case
185
      find (\col -> collectorName == dName col) $
186
        filter (\c -> category == dCategory c) collectors of
187
      Just col -> return col
188
      Nothing -> fail "Unable to find the requested collector"
189
  report <- liftIO $ dReport collector
190
  writeBS . pack . J.encode $ report
191

    
192
-- | The function implementing the HTTP API of the monitoring agent.
193
monitoringApi :: Snap ()
194
monitoringApi =
195
  ifTop versionQ <|>
196
  dir "1" version1Api <|>
197
  error404
198

    
199
-- | Main function.
200
main :: MainFn CheckResult PrepResult
201
main _ _ httpConf =
202
  httpServe httpConf $ method GET monitoringApi