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
