On Tue, Sep 24, 2013 at 1:10 PM, Michele Tartara <[email protected]>wrote:
> On Fri, Sep 20, 2013 at 3:14 PM, Spyros Trigazis <[email protected]>wrote: > >> Implement functionality to import MonD data from a mock file to >> HTools (mainly for testing purposes) with the --mond-data >> option. >> >> Signed-off-by: Spyros Trigazis <[email protected]> >> --- >> src/Ganeti/HTools/CLI.hs | 11 +++++++ >> src/Ganeti/HTools/ExtLoader.hs | 65 >> ++++++++++++++++++++++++++++++------- >> src/Ganeti/HTools/Program/Hail.hs | 2 +- >> src/Ganeti/HTools/Program/Hbal.hs | 1 + >> 4 files changed, 67 insertions(+), 12 deletions(-) >> >> diff --git a/src/Ganeti/HTools/CLI.hs b/src/Ganeti/HTools/CLI.hs >> index 12c3914..f4ca9fe 100644 >> --- a/src/Ganeti/HTools/CLI.hs >> +++ b/src/Ganeti/HTools/CLI.hs >> @@ -48,6 +48,7 @@ module Ganeti.HTools.CLI >> , oDiskTemplate >> , oSpindleUse >> , oDynuFile >> + , oMonDDataFile >> , oEvacMode >> , oExInst >> , oExTags >> @@ -123,6 +124,8 @@ data Options = Options >> , optSpindleUse :: Maybe Int -- ^ Override for the spindle usage >> , optDynuFile :: Maybe FilePath -- ^ Optional file with dynamic use >> data >> , optIgnoreDynu :: Bool -- ^ Do not use dynamic use data >> + , optMonDDataFile :: Maybe FilePath -- ^ Optional file with data >> provided >> + -- ^ by MonDs >> , optEvacMode :: Bool -- ^ Enable evacuation mode >> , optExInst :: [String] -- ^ Instances to be excluded >> , optExTags :: Maybe [String] -- ^ Tags to use for exclusion >> @@ -178,6 +181,7 @@ defaultOptions = Options >> , optSpindleUse = Nothing >> , optIgnoreDynu = False >> , optDynuFile = Nothing >> + , optMonDDataFile = Nothing >> , optEvacMode = False >> , optExInst = [] >> , optExTags = Nothing >> @@ -280,6 +284,13 @@ oDiskMoves = >> \ thus allowing only the 'cheap' failover/migrate operations", >> OptComplNone) >> >> +oMonDDataFile :: OptType >> +oMonDDataFile = >> + (Option "" ["mond-data"] >> + (ReqArg (\ f opts -> Ok opts { optMonDDataFile = Just f }) "FILE") >> + "Import data provided by MonDs from the given FILE", >> + OptComplFile) >> + >> oDiskTemplate :: OptType >> oDiskTemplate = >> (Option "" ["disk-template"] >> diff --git a/src/Ganeti/HTools/ExtLoader.hs >> b/src/Ganeti/HTools/ExtLoader.hs >> index d42c833..9086e91 100644 >> --- a/src/Ganeti/HTools/ExtLoader.hs >> +++ b/src/Ganeti/HTools/ExtLoader.hs >> @@ -47,6 +47,8 @@ import System.Time (getClockTime) >> import Text.Printf (hPrintf) >> >> import qualified Text.JSON as J >> +import qualified Data.Map as Map >> +import qualified Data.List as L >> >> import qualified Ganeti.Constants as C >> import qualified Ganeti.DataCollectors.CPUload as CPUload >> @@ -131,7 +133,7 @@ loadExternalData opts = do >> ldresult = input_data >>= (if ignoreDynU then clearDynU else >> return) >> >>= mergeData eff_u exTags selInsts exInsts >> now >> cdata <- exitIfBad "failed to load data, aborting" ldresult >> - cdata' <- if ignoreDynU then return cdata else queryAllMonDDCs cdata >> + cdata' <- if ignoreDynU then return cdata else queryAllMonDDCs cdata >> opts >> > > This will have to be changed as in the other patches. > > >> let (fix_msgs, nl) = checkData (cdNodes cdata') (cdInstances cdata') >> >> unless (optVerbose opts == 0) $ maybeShowWarnings fix_msgs >> @@ -166,18 +168,46 @@ collectors :: [DataCollector] >> collectors = >> [ DataCollector CPUload.dcName CPUload.dcCategory ] >> >> +-- | MonDs Data parsed by a mock file. Representing (node name, list of >> reports >> +-- produced by MonDs Data Collectors). >> +type MonDData = (String, [DCReport]) >> + >> +-- | A map storing MonDs data. >> +type MapMonDData = Map.Map String [DCReport] >> + >> +-- | Parse MonD data file contents. >> +pMonDData :: String -> Result [MonDData] >> +pMonDData input = >> + loadJSArray "Parsing MonD's answer" input >>= >> + mapM (pMonDN . J.fromJSObject) >> + >> +-- | Parse a node's JSON record. >> +pMonDN :: JSRecord -> Result MonDData >> +pMonDN a = do >> + node <- tryFromObj "Parsing node's name" a "node" >> + reports <- tryFromObj "Parsing node's reports" a "reports" >> + return (node, reports) >> + >> -- | Query all MonDs for all Data Collector. >> -queryAllMonDDCs :: ClusterData -> IO ClusterData >> -queryAllMonDDCs cdata = do >> +queryAllMonDDCs :: ClusterData -> Options -> IO ClusterData >> +queryAllMonDDCs cdata opts = do >> + map_mDD <- >> + case optMonDDataFile opts of >> + Nothing -> return Nothing >> + Just fp -> do >> + monDData_contents <- readFile fp >> + monDData <- exitIfBad "can't parse MonD data" >> + . pMonDData $ monDData_contents >> + return . Just $ Map.fromList monDData >> let (ClusterData _ nl il _ _) = cdata >> - (nl', il') <- foldM queryAllMonDs (nl, il) collectors >> + (nl', il') <- foldM (queryAllMonDs map_mDD) (nl, il) collectors >> return $ cdata {cdNodes = nl', cdInstances = il'} >> >> -- | Query all MonDs for a single Data Collector. >> -queryAllMonDs :: (Node.List, Instance.List) -> DataCollector >> - -> IO (Node.List, Instance.List) >> -queryAllMonDs (nl, il) dc = do >> - elems <- mapM (queryAMonD dc) (Container.elems nl) >> +queryAllMonDs :: Maybe MapMonDData -> (Node.List, Instance.List) >> + -> DataCollector -> IO (Node.List, Instance.List) >> +queryAllMonDs m (nl, il) dc = do >> + elems <- mapM (queryAMonD m dc) (Container.elems nl) >> let elems' = catMaybes elems >> if length elems == length elems' >> then do >> @@ -214,10 +244,23 @@ mkReport dc dcr = >> Bad _ -> Nothing >> | otherwise -> Nothing >> >> +-- | Get data report for the specified Data Collector and Node from the >> map. >> +fromFile :: DataCollector -> Node.Node -> MapMonDData -> Maybe DCReport >> +fromFile dc node m = >> + case Map.lookup (Node.name node) m of >> + Nothing -> Nothing >> + Just reports -> >> + let matchDCName dcr = dName dc == dcReportName dcr >> + in L.find matchDCName reports >> + >> -- | Query a MonD for a single Data Collector. >> -queryAMonD :: DataCollector -> Node.Node -> IO (Maybe Node.Node) >> -queryAMonD dc node = do >> - dcReport <- fromCurl dc node >> +queryAMonD :: Maybe MapMonDData -> DataCollector -> Node.Node >> + -> IO (Maybe Node.Node) >> +queryAMonD m dc node = do >> + dcReport <- >> + case m of >> + Nothing -> fromCurl dc node >> + Just m' -> return $ fromFile dc node m' >> case mkReport dc dcReport of >> Nothing -> return Nothing >> Just report -> >> diff --git a/src/Ganeti/HTools/Program/Hail.hs >> b/src/Ganeti/HTools/Program/Hail.hs >> index 507192c..b1e3653 100644 >> --- a/src/Ganeti/HTools/Program/Hail.hs >> +++ b/src/Ganeti/HTools/Program/Hail.hs >> @@ -74,7 +74,7 @@ wrapReadRequest opts args = do >> else do >> let Request rqt cdata = r1 >> cdata' <- >> - if optIgnoreDynu opts then return cdata else queryAllMonDDCs >> cdata >> + if optIgnoreDynu opts then return cdata else queryAllMonDDCs >> cdata opts >> return $ Request rqt cdata' >> >> -- | Main function. >> diff --git a/src/Ganeti/HTools/Program/Hbal.hs >> b/src/Ganeti/HTools/Program/Hbal.hs >> index f863ad1..c385642 100644 >> --- a/src/Ganeti/HTools/Program/Hbal.hs >> +++ b/src/Ganeti/HTools/Program/Hbal.hs >> @@ -92,6 +92,7 @@ options = do >> , oInstMoves >> , oDynuFile >> , oIgnoreDyn >> + , oMonDDataFile >> , oExTags >> , oExInst >> , oSaveCluster >> -- >> 1.7.10.4 >> >> > Rest LGTM. > > Thanks, > Michele > > -- > Google Germany GmbH > Dienerstr. 12 > 80331 München > > Registergericht und -nummer: Hamburg, HRB 86891 > Sitz der Gesellschaft: Hamburg > Geschäftsführer: Graham Law, Christine Elizabeth Flores > Also, please add tests. Thanks! Michele -- Google Germany GmbH Dienerstr. 12 80331 München Registergericht und -nummer: Hamburg, HRB 86891 Sitz der Gesellschaft: Hamburg Geschäftsführer: Graham Law, Christine Elizabeth Flores
