From 4188449c680d1adb999cee4b71f85980c3ac229d Mon Sep 17 00:00:00 2001
From: Iustin Pop <iustin@google.com>
Date: Tue, 21 Dec 2010 13:31:43 +0100
Subject: [PATCH] Add maybeSaveData for cluster state saving

This functionality was replicated in multiple places (hbal & hspace),
so we abstract it for better clarity.

Additionally, in hbal we now save the state both before and after
balancing.

Signed-off-by: Iustin Pop <iustin@google.com>
Reviewed-by: Balazs Lecz <leczb@google.com>
---
 Ganeti/HTools/ExtLoader.hs | 16 ++++++++++++++++
 hbal.hs                    | 14 +++++---------
 hspace.hs                  | 24 +++++-------------------
 man/hbal.rst               | 11 +++++++----
 4 files changed, 33 insertions(+), 32 deletions(-)

diff --git a/Ganeti/HTools/ExtLoader.hs b/Ganeti/HTools/ExtLoader.hs
index 17726d106..0412c1bb3 100644
--- a/Ganeti/HTools/ExtLoader.hs
+++ b/Ganeti/HTools/ExtLoader.hs
@@ -32,10 +32,12 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
 module Ganeti.HTools.ExtLoader
     ( loadExternalData
     , commonSuffix
+    , maybeSaveData
     ) where
 
 import Data.Maybe (isJust, fromJust)
 import Monad
+import System.FilePath
 import System.IO
 import System
 import Text.Printf (printf, hPrintf)
@@ -134,3 +136,17 @@ loadExternalData opts = do
          hPutStrLn stderr . unlines . map (printf "  - %s") $ fix_msgs
 
   return cdata {cdNodes = nl}
+
+-- | Function to save the cluster data to a file.
+maybeSaveData :: Maybe FilePath -- ^ The file prefix to save to
+              -> String         -- ^ The suffix (extension) to add
+              -> String         -- ^ Informational message
+              -> ClusterData    -- ^ The cluster data
+              -> IO ()
+maybeSaveData Nothing _ _ _ = return ()
+maybeSaveData (Just path) ext msg cdata = do
+  let adata = Text.serializeCluster cdata
+      out_path = path <.> ext
+  writeFile out_path adata
+  hPrintf stderr "The cluster state %s has been written to file '%s'\n"
+          msg out_path
diff --git a/hbal.hs b/hbal.hs
index ddbb6bcd9..4f2039796 100644
--- a/hbal.hs
+++ b/hbal.hs
@@ -51,8 +51,6 @@ import Ganeti.HTools.Utils
 import Ganeti.HTools.Types
 import Ganeti.HTools.Loader (ClusterData(..))
 
-import Ganeti.HTools.Text (serializeCluster)
-
 import qualified Ganeti.Luxi as L
 import Ganeti.Jobs
 
@@ -236,7 +234,7 @@ main = do
       verbose = optVerbose opts
       shownodes = optShowNodes opts
 
-  (ClusterData gl fixed_nl ilf ctags) <- loadExternalData opts
+  ini_cdata@(ClusterData gl fixed_nl ilf ctags) <- loadExternalData opts
 
   let offline_names = optOffline opts
       all_nodes = Container.elems fixed_nl
@@ -285,6 +283,8 @@ main = do
     hPutStrLn stderr "Aborting."
     exitWith $ ExitFailure 1
 
+  maybeSaveData (optSaveCluster opts) "original" "before balancing" ini_cdata
+
   unless oneline $ printf "Loaded %d nodes, %d instances\n"
              (Container.size nlf)
              (Container.size ilf)
@@ -397,12 +397,8 @@ main = do
             writeFile out_path (shTemplate ++ cmd_data)
             printf "The commands have been written to file '%s'\n" out_path)
 
-  when (isJust $ optSaveCluster opts) $
-       do
-         let out_path = fromJust $ optSaveCluster opts
-             adata = serializeCluster (ClusterData gl fin_nl fin_il ctags)
-         writeFile out_path adata
-         printf "The cluster state has been written to file '%s'\n" out_path
+  maybeSaveData (optSaveCluster opts) "balanced" "after balancing"
+                (ClusterData gl fin_nl fin_il ctags)
 
   when (optShowInsts opts) $ do
          putStrLn ""
diff --git a/hspace.hs b/hspace.hs
index 76c454ef8..9343240a5 100644
--- a/hspace.hs
+++ b/hspace.hs
@@ -31,7 +31,6 @@ import Data.Maybe (isJust, fromJust)
 import Data.Ord (comparing)
 import Monad
 import System (exitWith, ExitCode(..))
-import System.FilePath
 import System.IO
 import qualified System
 
@@ -46,7 +45,6 @@ import Ganeti.HTools.Utils
 import Ganeti.HTools.Types
 import Ganeti.HTools.CLI
 import Ganeti.HTools.ExtLoader
-import Ganeti.HTools.Text (serializeCluster)
 import Ganeti.HTools.Loader (ClusterData(..))
 
 -- | Options list and functions
@@ -302,15 +300,9 @@ main = do
          hPutStrLn stderr "Tiered allocation status:"
          hPutStrLn stderr $ Cluster.printNodes trl_nl (fromJust shownodes)
 
-       when (isJust $ optSaveCluster opts) $
-            do
-              let out_path = (fromJust $ optSaveCluster opts) <.> "tiered"
-                  adata = serializeCluster
-                          (ClusterData gl trl_nl trl_il ctags)
-              writeFile out_path adata
-              hPrintf stderr "The cluster state after tiered allocation\
-                             \ has been written to file '%s'\n"
-                             out_path
+       maybeSaveData (optSaveCluster opts) "tiered" "after tiered allocation"
+                     (ClusterData gl trl_nl trl_il ctags)
+
        printKeys $ printStats PTiered (Cluster.totalResources trl_nl)
        printKeys [("TSPEC", intercalate " " spec_map')]
        printAllocationStats m_cpu nl trl_nl)
@@ -337,13 +329,7 @@ main = do
          hPutStrLn stderr "Final cluster status:"
          hPutStrLn stderr $ Cluster.printNodes fin_nl (fromJust shownodes)
 
-  when (isJust $ optSaveCluster opts) $
-       do
-         let out_path = (fromJust $ optSaveCluster opts) <.> "alloc"
-             adata = serializeCluster (ClusterData gl fin_nl fin_il ctags)
-         writeFile out_path adata
-         hPrintf stderr "The cluster state after standard allocation\
-                        \ has been written to file '%s'\n"
-                 out_path
+  maybeSaveData (optSaveCluster opts) "alloc" "after standard allocation"
+       (ClusterData gl fin_nl fin_il ctags)
 
   printResults fin_nl num_instances allocs sreason
diff --git a/man/hbal.rst b/man/hbal.rst
index 7988aa3a1..f88ab963c 100644
--- a/man/hbal.rst
+++ b/man/hbal.rst
@@ -390,10 +390,13 @@ The options that can be passed to the program are as follows:
   collecting via RAPI or LUXI). This or one of the other backends must
   be selected.
 
--S *datafile*, --save-cluster=*datafile*
-  If given, the state of the cluster at the end of the balancing is
-  saved to the given file. This allows re-feeding the cluster state to
-  either hbal itself or for example hspace.
+-S *filename*, --save-cluster=*filename*
+  If given, the state of the cluster before the balancing is saved to
+  the given file plus the extension "original"
+  (i.e. *filename*.original), and the state at the end of the
+  balancing is saved to the given file plus the extension "balanced"
+  (i.e. *filename*.balanced). This allows re-feeding the cluster state
+  to either hbal itself or for example hspace.
 
 -m *cluster*
  Collect data directly from the *cluster* given as an argument via
-- 
GitLab