1 {-# LANGUAGE TemplateHaskell #-}
3 {-| Implementation of the Ganeti data collector types.
9 Copyright (C) 2012, 2013 Google Inc.
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.
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.
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
28 module Ganeti.DataCollectors.Types
45 import qualified Data.Map as Map
46 import qualified Data.Sequence as Seq
49 import Ganeti.Constants as C
51 import Ganeti.Utils (getCurrentTime)
53 -- | The possible classes a data collector can belong to.
54 data DCCategory = DCInstance | DCStorage | DCDaemon | DCHypervisor
55 deriving (Show, Eq, Read)
57 -- | Get the category name and return it as a string.
58 getCategoryName :: DCCategory -> String
59 getCategoryName dcc = map toLower . drop 2 . show $ dcc
61 categoryNames :: Map.Map String DCCategory
63 let l = [DCInstance, DCStorage, DCDaemon, DCHypervisor]
64 in Map.fromList $ zip (map getCategoryName l) l
66 -- | The JSON instance for DCCategory.
67 instance JSON DCCategory where
68 showJSON = showJSON . getCategoryName
69 readJSON (JSString s) =
70 let s' = fromJSString s
71 in case Map.lookup s' categoryNames of
72 Just category -> Ok category
73 Nothing -> fail $ "Invalid category name " ++ s' ++ " for type\
75 readJSON v = fail $ "Invalid JSON value " ++ show v ++ " for type DCCategory"
77 -- | The possible status codes of a data collector.
78 data DCStatusCode = DCSCOk -- ^ Everything is OK
79 | DCSCTempBad -- ^ Bad, but being automatically fixed
80 | DCSCUnknown -- ^ Unable to determine the status
81 | DCSCBad -- ^ Bad. External intervention required
82 deriving (Show, Eq, Ord)
84 -- | The JSON instance for CollectorStatus.
85 instance JSON DCStatusCode where
86 showJSON DCSCOk = showJSON (0 :: Int)
87 showJSON DCSCTempBad = showJSON (1 :: Int)
88 showJSON DCSCUnknown = showJSON (2 :: Int)
89 showJSON DCSCBad = showJSON (4 :: Int)
90 readJSON = error "JSON read instance not implemented for type DCStatusCode"
92 -- | The status of a \"status reporting data collector\".
93 $(buildObject "DCStatus" "dcStatus"
94 [ simpleField "code" [t| DCStatusCode |]
95 , simpleField "message" [t| String |]
98 -- | The type representing the kind of the collector.
99 data DCKind = DCKPerf -- ^ Performance reporting collector
100 | DCKStatus -- ^ Status reporting collector
103 -- | The JSON instance for CollectorKind.
104 instance JSON DCKind where
105 showJSON DCKPerf = showJSON (0 :: Int)
106 showJSON DCKStatus = showJSON (1 :: Int)
107 readJSON (JSRational _ x) =
108 if denominator x /= 1
109 then fail $ "Invalid JSON value " ++ show x ++ " for type DCKind"
111 let x' = (fromIntegral . numerator $ x) :: Int
112 in if x' == 0 then Ok DCKPerf
113 else if x' == 1 then Ok DCKStatus
114 else fail $ "Invalid JSON value " ++ show x' ++ " for type DCKind"
115 readJSON v = fail $ "Invalid JSON value " ++ show v ++ " for type DCKind"
117 -- | Type representing the version number of a data collector.
118 data DCVersion = DCVerBuiltin | DCVersion String deriving (Show, Eq)
120 -- | The JSON instance for DCVersion.
121 instance JSON DCVersion where
122 showJSON DCVerBuiltin = showJSON C.builtinDataCollectorVersion
123 showJSON (DCVersion v) = showJSON v
124 readJSON (JSString s) =
125 if fromJSString s == C.builtinDataCollectorVersion
126 then Ok DCVerBuiltin else Ok . DCVersion $ fromJSString s
127 readJSON v = fail $ "Invalid JSON value " ++ show v ++ " for type DCVersion"
129 -- | Type for the value field of the above map.
130 data CollectorData = CPULoadData (Seq.Seq (Integer, [Int]))
132 -- | Type for the map storing the data of the statefull DataCollectors.
133 type CollectorMap = Map.Map String CollectorData
135 -- | This is the format of the report produced by each data collector.
136 $(buildObject "DCReport" "dcReport"
137 [ simpleField "name" [t| String |]
138 , simpleField "version" [t| DCVersion |]
139 , simpleField "format_version" [t| Int |]
140 , simpleField "timestamp" [t| Integer |]
141 , optionalNullSerField $
142 simpleField "category" [t| DCCategory |]
143 , simpleField "kind" [t| DCKind |]
144 , simpleField "data" [t| JSValue |]
147 -- | Add the data collector status information to the JSON representation of
148 -- the collector data.
149 addStatus :: DCStatus -> JSValue -> JSValue
150 addStatus dcStatus (JSObject obj) =
151 makeObj $ ("status", showJSON dcStatus) : fromJSObject obj
152 addStatus dcStatus value = makeObj
153 [ ("status", showJSON dcStatus)
157 -- | Helper function for merging statuses.
158 mergeStatuses :: (DCStatusCode, String) -> (DCStatusCode, [String])
159 -> (DCStatusCode, [String])
160 mergeStatuses (newStat, newStr) (storedStat, storedStrs) =
161 let resStat = max newStat storedStat
165 else storedStrs ++ [newStr]
166 in (resStat, resStrs)
168 -- | Utility function for building a report automatically adding the current
169 -- timestamp (rounded up to seconds).
170 -- If the version is not specified, it will be set to the value indicating
171 -- a builtin collector.
172 buildReport :: String -> DCVersion -> Int -> Maybe DCCategory -> DCKind
173 -> JSValue -> IO DCReport
174 buildReport name version format_version category kind jsonData = do
175 now <- getCurrentTime
176 let timestamp = now * 1000000000 :: Integer
178 DCReport name version format_version timestamp category kind