Commit e0eb63f0 authored by Iustin Pop's avatar Iustin Pop
Browse files

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.
parent 3d7cd10b
......@@ -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"
......@@ -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 -}
......
......@@ -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
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment