On Thu, Feb 26, 2015 at 01:47:15PM +0100, Klaus Aehlig wrote:
LGTM

A suggestion for discussion: Adding the 'Bool' parameters obscures a
bit the code, as it needs to be dealt with at various places. What
about using

  WriterT All IO a

(perhaps as a type alias for easier refactoring, if needed) instead of

  IO (a, Bool)

? Reporting a failure is then just calling `tell (All False)` and a
lot of the existing code (foldM etc) would remain unchanged, without
needing to explicitly process the boolean part, making the &&
implicit. On the other hand, it requires adding liftIO at a few
places and also at the place where the whole query is run.

I was thinking about this when writing the patch as well, as this is
the more idiomatic type. But I decided that the additional increase
in patch sizes is not worth the nicer type. Below is the total
interdiff (over the whole patch series), which sums up as

Backend/MonD.hs |   33 +++++++++++++++++----------------
ExtLoader.hs    |   11 +++++++----
Program/Hail.hs |    7 ++++---
3 files changed, 28 insertions(+), 23 deletions(-)

I can distribute that to the appropriate patches if you think the
improvement in type justifies the additional complication.

LGTM, thank you. Please do, I believe it won't make them that much longer, and if we'll need to change the logic in the future some other way, we'll already have the `liftIO`s in place.




commit e289a15522c85be10d2164a2d28e22147d9b70d3
Author: Klaus Aehlig <[email protected]>
Date:   Thu Feb 26 13:41:50 2015 +0100

   Discussion: WriterT

diff --git a/src/Ganeti/HTools/Backend/MonD.hs 
b/src/Ganeti/HTools/Backend/MonD.hs
index fb684ee..f323ab3 100644
--- a/src/Ganeti/HTools/Backend/MonD.hs
+++ b/src/Ganeti/HTools/Backend/MonD.hs
@@ -44,6 +44,7 @@ module Ganeti.HTools.Backend.MonD
  ) where

import Control.Monad
+import Control.Monad.Writer
import qualified Data.List as L
import qualified Data.IntMap as IntMap
import qualified Data.Map as Map
@@ -268,39 +269,39 @@ queryAMonD m dc node =
-- | Query all MonDs for a single Data Collector. Return the updated
-- cluster, as well as a bit inidicating wether the collector succeeded.
queryAllMonDs :: Maybe MapMonDData -> (Node.List, Instance.List)
-                 -> DataCollector -> IO ((Node.List, Instance.List), Bool)
+                 -> DataCollector -> WriterT All IO (Node.List, Instance.List)
queryAllMonDs m (nl, il) dc = do
-  elems <- mapM (queryAMonD m dc) (Container.elems nl)
+  elems <- liftIO $ mapM (queryAMonD m dc) (Container.elems nl)
  let elems' = catMaybes elems
  if length elems == length elems'
    then
      let results = zip (Container.elems nl) elems'
      in case dUse dc results (nl, il) of
-        Ok (nl', il') -> return ((nl', il'), True)
+        Ok (nl', il') -> return (nl', il')
        Bad s -> do
-          logWarning s
-          return ((nl, il), False)
+          liftIO $ logWarning s
+          tell $ All False
+          return (nl, il)
    else do
-      logWarning $ "Didn't receive an answer by all MonDs, " ++ dName dc
-                   ++ "'s data will be ignored."
-      return ((nl,il), False)
+      liftIO . logWarning
+        $ "Didn't receive an answer by all MonDs, " ++ dName dc
+          ++ "'s data will be ignored."
+      tell $ All False
+      return (nl,il)

-- | Query all MonDs for all Data Collector. Return the cluster enriched
-- by dynamic data, as well as a bit indicating wether all collectors
-- could be queried successfully.
-queryAllMonDDCs :: ClusterData -> Options -> IO (ClusterData, Bool)
+queryAllMonDDCs :: ClusterData -> Options -> WriterT All IO ClusterData
queryAllMonDDCs cdata opts = do
  map_mDD <-
    case optMonDFile opts of
      Nothing -> return Nothing
      Just fp -> do
-        monDData_contents <- readFile fp
-        monDData <- exitIfBad "can't parse MonD data"
+        monDData_contents <- liftIO $ readFile fp
+        monDData <- liftIO . exitIfBad "can't parse MonD data"
                    . pMonDData $ monDData_contents
        return . Just $ Map.fromList monDData
-  let query (cluster, ok) collector  = do
-        (cluster', ok') <- queryAllMonDs map_mDD cluster collector
-        return (cluster', ok && ok')
  let (ClusterData _ nl il _ _) = cdata
-  ((nl', il'), ok) <- foldM query ((nl, il), True) (collectors opts)
-  return (cdata {cdNodes = nl', cdInstances = il'}, ok)
+  (nl', il') <- foldM (queryAllMonDs map_mDD) (nl, il) (collectors opts)
+  return $ cdata {cdNodes = nl', cdInstances = il'}
diff --git a/src/Ganeti/HTools/ExtLoader.hs b/src/Ganeti/HTools/ExtLoader.hs
index a922d54..cae481a 100644
--- a/src/Ganeti/HTools/ExtLoader.hs
+++ b/src/Ganeti/HTools/ExtLoader.hs
@@ -43,8 +43,10 @@ module Ganeti.HTools.ExtLoader
  ) where

import Control.Monad
+import Control.Monad.Writer (runWriterT)
import Control.Exception
import Data.Maybe (isJust, fromJust)
+import Data.Monoid (getAll)
import System.FilePath
import System.IO
import System.Time (getClockTime)
@@ -124,10 +126,11 @@ 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', ok) <- if optMonD opts
-                    then MonD.queryAllMonDDCs cdata opts
-                    else return (cdata, True)
-  exitWhen (optMonDExitMissing opts && not ok) "Not all required data 
available"
+  (cdata', ok) <- runWriterT $ if optMonD opts
+                                 then MonD.queryAllMonDDCs cdata opts
+                                 else return cdata
+  exitWhen (optMonDExitMissing opts && not (getAll ok))
+    "Not all required data available"
  let (fix_msgs, nl) = checkData (cdNodes cdata') (cdInstances cdata')

  unless (optVerbose opts == 0) $ maybeShowWarnings fix_msgs
diff --git a/src/Ganeti/HTools/Program/Hail.hs 
b/src/Ganeti/HTools/Program/Hail.hs
index 1d57f17..db1be29 100644
--- a/src/Ganeti/HTools/Program/Hail.hs
+++ b/src/Ganeti/HTools/Program/Hail.hs
@@ -39,6 +39,7 @@ module Ganeti.HTools.Program.Hail
  ) where

import Control.Monad
+import Control.Monad.Writer (runWriterT)
import Data.Maybe (fromMaybe, isJust)
import System.IO

@@ -87,9 +88,9 @@ wrapReadRequest opts args = do
      return $ Request rqt cdata
    else do
      let Request rqt cdata = r1
-      (cdata', _) <- if optMonD opts
-                       then MonD.queryAllMonDDCs cdata opts
-                       else return (cdata, True)
+      (cdata', _) <- runWriterT $ if optMonD opts
+                                    then MonD.queryAllMonDDCs cdata opts
+                                    else return cdata
      return $ Request rqt cdata'

-- | Main function.



--
Klaus Aehlig
Google Germany GmbH, Dienerstr. 12, 80331 Muenchen
Registergericht und -nummer: Hamburg, HRB 86891
Sitz der Gesellschaft: Hamburg
Geschaeftsfuehrer: Graham Law, Christine Elizabeth Flores

Reply via email to