From: Iustin Pop Date: Sat, 18 Apr 2009 22:17:05 +0000 (+0200) Subject: Implement writing the command list to a script X-Git-Tag: htools-v0.0.8~7 X-Git-Url: https://code.grnet.gr/git/ganeti-local/commitdiff_plain/e0eb63f07dca0dcfb323fca28085cf2774fcc707?ds=sidebyside Implement writing the command list to a script This patch adds support in hbal for writing the command list to a shell script, with error checking and allowing for early exit. --- diff --git a/Ganeti/HTools/CLI.hs b/Ganeti/HTools/CLI.hs index ba16766..1a30f58 100644 --- a/Ganeti/HTools/CLI.hs +++ b/Ganeti/HTools/CLI.hs @@ -10,6 +10,7 @@ module Ganeti.HTools.CLI ( parseOpts , showVersion + , shTemplate ) where import System.Console.GetOpt @@ -54,3 +55,17 @@ showVersion name = name Version.version compilerName (Data.Version.showVersion compilerVersion) os arch + +-- | A shell script template for autogenerated scripts +shTemplate :: String +shTemplate = + printf "#!/bin/sh\n\n\ + \# Auto-generated script for executing cluster rebalancing\n\n\ + \# To stop, touch the file /tmp/stop-htools\n\n\ + \set -e\n\n\ + \check() {\n\ + \ if [ -f /tmp/stop-htools ]; then\n\ + \ echo 'Stop requested, exiting'\n\ + \ exit 0\n\ + \ fi\n\ + \}\n\n" diff --git a/Ganeti/HTools/Cluster.hs b/Ganeti/HTools/Cluster.hs index c64f9df..4153af6 100644 --- a/Ganeti/HTools/Cluster.hs +++ b/Ganeti/HTools/Cluster.hs @@ -563,27 +563,27 @@ computeMoves i a b c d = else if c == b then {- Failover and ... -} if d == a then {- that's all -} - ("f", [printf "migrate %s" i]) + ("f", [printf "migrate -f %s" i]) else (printf "f r:%s" d, - [printf "migrate %s" i, + [printf "migrate -f %s" i, printf "replace-disks -n %s %s" d i]) else if d == a then {- ... and keep primary as secondary -} (printf "r:%s f" c, [printf "replace-disks -n %s %s" c i, - printf "migrate %s" i]) + printf "migrate -f %s" i]) else if d == b then {- ... keep same secondary -} (printf "f r:%s f" c, - [printf "migrate %s" i, + [printf "migrate -f %s" i, printf "replace-disks -n %s %s" c i, - printf "migrate %s" i]) + printf "migrate -f %s" i]) else {- Nothing in common -} (printf "r:%s f r:%s" c d, [printf "replace-disks -n %s %s" c i, - printf "migrate %s" i, + printf "migrate -f %s" i, printf "replace-disks -n %s %s" d i]) {-| Converts a placement to string format -} @@ -616,9 +616,11 @@ printSolutionLine il ktn kti nmlen imlen plc pos = formatCmds :: [[String]] -> String formatCmds cmd_strs = - unlines $ map (" echo " ++) $ + unlines $ concat $ map (\(a, b) -> - (printf "step %d" (a::Int)):(map ("gnt-instance " ++) b)) $ + (printf "echo step %d" (a::Int)): + (printf "check"): + (map ("gnt-instance " ++) b)) $ zip [1..] cmd_strs {-| Converts a solution to string format -} diff --git a/hbal.hs b/hbal.hs index 65c5e3f..a606077 100644 --- a/hbal.hs +++ b/hbal.hs @@ -6,6 +6,7 @@ module Main (main) where import Data.List import Data.Function +import Data.Maybe (isJust, fromJust, fromMaybe) import Monad import System import System.IO @@ -23,24 +24,24 @@ import Ganeti.HTools.Utils -- | Command line options structure. data Options = Options - { optShowNodes :: Bool -- ^ Whether to show node status - , optShowCmds :: Bool -- ^ Whether to show the command list - , optOneline :: Bool -- ^ Switch output to a single line - , optNodef :: FilePath -- ^ Path to the nodes file - , optInstf :: FilePath -- ^ Path to the instances file - , optMaxLength :: Int -- ^ Stop after this many steps - , optMaster :: String -- ^ Collect data from RAPI - , optVerbose :: Int -- ^ Verbosity level - , optOffline :: [String] -- ^ Names of offline nodes - , optShowVer :: Bool -- ^ Just show the program version - , optShowHelp :: Bool -- ^ Just show the help + { optShowNodes :: Bool -- ^ Whether to show node status + , optShowCmds :: Maybe FilePath -- ^ Whether to show the command list + , optOneline :: Bool -- ^ Switch output to a single line + , optNodef :: FilePath -- ^ Path to the nodes file + , optInstf :: FilePath -- ^ Path to the instances file + , optMaxLength :: Int -- ^ Stop after this many steps + , optMaster :: String -- ^ Collect data from RAPI + , optVerbose :: Int -- ^ Verbosity level + , optOffline :: [String] -- ^ Names of offline nodes + , optShowVer :: Bool -- ^ Just show the program version + , optShowHelp :: Bool -- ^ Just show the help } deriving Show -- | Default values for the command line options. defaultOptions :: Options defaultOptions = Options { optShowNodes = False - , optShowCmds = False + , optShowCmds = Nothing , optOneline = False , optNodef = "nodes" , optInstf = "instances" @@ -59,8 +60,11 @@ options = (NoArg (\ opts -> opts { optShowNodes = True })) "print the final node list" , Option ['C'] ["print-commands"] - (NoArg (\ opts -> opts { optShowCmds = True })) - "print the ganeti command list for reaching the solution" + (OptArg ((\ f opts -> opts { optShowCmds = Just f }) . fromMaybe "-") + "FILE") + "print the ganeti command list for reaching the solution,\ + \if an argument is passed then write the commands to a file named\ + \ as such" , Option ['o'] ["oneline"] (NoArg (\ opts -> opts { optOneline = True })) "print the ganeti command list for reaching the solution" @@ -226,11 +230,21 @@ main = do unless (oneline || verbose == 0) $ printf "Solution length=%d\n" (length ord_plc) - when (optShowCmds opts) $ + let cmd_data = Cluster.formatCmds . reverse $ cmd_strs + + when (isJust $ optShowCmds opts) $ do + let out_path = fromJust $ optShowCmds opts putStrLn "" - putStrLn "Commands to run to reach the above solution:" - putStr . Cluster.formatCmds . reverse $ cmd_strs + (if out_path == "-" then + printf "Commands to run to reach the above solution:\n%s" + (unlines . map (" " ++) . + filter (/= "check") . + lines $ cmd_data) + else do + writeFile out_path (CLI.shTemplate ++ cmd_data) + printf "The commands have been written to file '%s'\n" out_path) + when (optShowNodes opts) $ do let (orig_mem, orig_disk) = Cluster.totalResources nl