Revision c62bec27

b/src/Ganeti/HTools/CLI.hs
49 49
  , oSpindleUse
50 50
  , oDynuFile
51 51
  , oMonD
52
  , oMonDDataFile
52 53
  , oEvacMode
53 54
  , oExInst
54 55
  , oExTags
......
125 126
  , optDynuFile    :: Maybe FilePath -- ^ Optional file with dynamic use data
126 127
  , optIgnoreDynu  :: Bool           -- ^ Do not use dynamic use data
127 128
  , optMonD        :: Bool           -- ^ Query MonDs
129
  , optMonDFile    :: Maybe FilePath -- ^ Optional file with data provided
130
                                     -- ^ by MonDs
128 131
  , optEvacMode    :: Bool           -- ^ Enable evacuation mode
129 132
  , optExInst      :: [String]       -- ^ Instances to be excluded
130 133
  , optExTags      :: Maybe [String] -- ^ Tags to use for exclusion
......
181 184
  , optIgnoreDynu  = False
182 185
  , optDynuFile    = Nothing
183 186
  , optMonD        = False
187
  , optMonDFile = Nothing
184 188
  , optEvacMode    = False
185 189
  , optExInst      = []
186 190
  , optExTags      = Nothing
......
290 294
   "Query MonDs",
291 295
   OptComplNone)
292 296

  
297
oMonDDataFile :: OptType
298
oMonDDataFile =
299
  (Option "" ["mond-data"]
300
   (ReqArg (\ f opts -> Ok opts { optMonDFile = Just f }) "FILE")
301
   "Import data provided by MonDs from the given FILE",
302
   OptComplFile)
303

  
293 304
oDiskTemplate :: OptType
294 305
oDiskTemplate =
295 306
  (Option "" ["disk-template"]
b/src/Ganeti/HTools/ExtLoader.hs
46 46
import Text.Printf (hPrintf)
47 47

  
48 48
import qualified Text.JSON as J
49
import qualified Data.Map as Map
50
import qualified Data.List as L
49 51

  
50 52
import qualified Ganeti.Constants as C
51 53
import qualified Ganeti.DataCollectors.CPUload as CPUload
......
167 169
    then []
168 170
    else [ DataCollector CPUload.dcName CPUload.dcCategory ]
169 171

  
172
-- | MonDs Data parsed by a mock file. Representing (node name, list of reports
173
-- produced by MonDs Data Collectors).
174
type MonDData = (String, [DCReport])
175

  
176
-- | A map storing MonDs data.
177
type MapMonDData = Map.Map String [DCReport]
178

  
179
-- | Parse MonD data file contents.
180
pMonDData :: String -> Result [MonDData]
181
pMonDData input =
182
  loadJSArray "Parsing MonD's answer" input >>=
183
  mapM (pMonDN . J.fromJSObject)
184

  
185
-- | Parse a node's JSON record.
186
pMonDN :: JSRecord -> Result MonDData
187
pMonDN a = do
188
  node <- tryFromObj "Parsing node's name" a "node"
189
  reports <- tryFromObj "Parsing node's reports" a "reports"
190
  return (node, reports)
191

  
170 192
-- | Query all MonDs for all Data Collector.
171
queryAllMonDDCs :: ClusterData -> IO ClusterData
172
queryAllMonDDCs cdata = do
193
queryAllMonDDCs :: ClusterData -> Options -> IO ClusterData
194
queryAllMonDDCs cdata opts = do
195
  map_mDD <-
196
    case optMonDFile opts of
197
      Nothing -> return Nothing
198
      Just fp -> do
199
        monDData_contents <- readFile fp
200
        monDData <- exitIfBad "can't parse MonD data"
201
                    . pMonDData $ monDData_contents
202
        return . Just $ Map.fromList monDData
173 203
  let (ClusterData _ nl il _ _) = cdata
174
  (nl', il') <- foldM queryAllMonDs (nl, il) (collectors opts)
204
  (nl', il') <- foldM (queryAllMonDs map_mDD) (nl, il) (collectors opts)
175 205
  return $ cdata {cdNodes = nl', cdInstances = il'}
176 206

  
177 207
-- | Query all MonDs for a single Data Collector.
178
queryAllMonDs :: (Node.List, Instance.List) -> DataCollector
179
                 -> IO (Node.List, Instance.List)
180
queryAllMonDs (nl, il) dc = do
181
  elems <- mapM (queryAMonD dc) (Container.elems nl)
208
queryAllMonDs :: Maybe MapMonDData -> (Node.List, Instance.List)
209
                 -> DataCollector -> IO (Node.List, Instance.List)
210
queryAllMonDs m (nl, il) dc = do
211
  elems <- mapM (queryAMonD m dc) (Container.elems nl)
182 212
  let elems' = catMaybes elems
183 213
  if length elems == length elems'
184 214
    then
......
218 248
                   Bad _ -> Nothing
219 249
             | otherwise -> Nothing
220 250

  
251
-- | Get data report for the specified Data Collector and Node from the map.
252
fromFile :: DataCollector -> Node.Node -> MapMonDData -> Maybe DCReport
253
fromFile dc node m =
254
  let matchDCName dcr = dName dc == dcReportName dcr
255
  in maybe Nothing (L.find matchDCName) $ Map.lookup (Node.name node) m
256

  
221 257
-- | Query a MonD for a single Data Collector.
222
queryAMonD :: DataCollector -> Node.Node -> IO (Maybe Node.Node)
223
queryAMonD dc node = do
224
  dcReport <- fromCurl dc node
258
queryAMonD :: Maybe MapMonDData -> DataCollector -> Node.Node
259
              -> IO (Maybe Node.Node)
260
queryAMonD m dc node = do
261
  dcReport <-
262
    case m of
263
      Nothing -> fromCurl dc node
264
      Just m' -> return $ fromFile dc node m'
225 265
  case mkReport dc dcReport of
226 266
    Nothing -> return Nothing
227 267
    Just report ->
b/src/Ganeti/HTools/Program/Hbal.hs
93 93
    , oDynuFile
94 94
    , oIgnoreDyn 
95 95
    , oMonD
96
    , oMonDDataFile
96 97
    , oExTags
97 98
    , oExInst
98 99
    , oSaveCluster
b/src/Ganeti/HTools/Program/Hinfo.hs
63 63
    , oOfflineNode
64 64
    , oIgnoreDyn
65 65
    , oMonD
66
    , oMonDDataFile
66 67
    ]
67 68

  
68 69
-- | The list of arguments supported by the program.

Also available in: Unified diff