From 0427285d1a548b8ad4469ed8eaf5f661bf942461 Mon Sep 17 00:00:00 2001 From: Iustin Pop Date: Wed, 15 Jul 2009 10:31:51 +0200 Subject: [PATCH] Unify the command line options and structures This patch moves all the command line options and their internal representation into CLI.hs. This means that duplicated options between any two binaries are no longer declared twice, and that we no longer need the two *Option classes. --- Ganeti/HTools/CLI.hs | 261 +++++++++++++++++++++++++++++++++++++++++--------- hail.hs | 35 +------ hbal.hs | 138 +++++--------------------- hscan.hs | 60 +++--------- hspace.hs | 131 ++++--------------------- 5 files changed, 274 insertions(+), 351 deletions(-) diff --git a/Ganeti/HTools/CLI.hs b/Ganeti/HTools/CLI.hs index 61edc35..c859784 100644 --- a/Ganeti/HTools/CLI.hs +++ b/Ganeti/HTools/CLI.hs @@ -28,16 +28,39 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA -} module Ganeti.HTools.CLI - ( CLIOptions(..) - , EToolOptions(..) + ( Options(..) + , OptType , parseOpts , parseEnv , shTemplate , loadExternalData , defaultLuxiSocket + -- * The options + , oPrintNodes + , oPrintCommands + , oOneline + , oNoHeaders + , oOutputDir + , oNodeFile + , oInstFile + , oRapiMaster + , oLuxiSocket + , oMaxSolLength + , oVerbose + , oQuiet + , oOfflineNode + , oMinScore + , oIMem + , oIDisk + , oIVcpus + , oINodes + , oMaxCpu + , oMinDisk + , oShowVer + , oShowHelp ) where -import Data.Maybe (isJust, fromJust) +import Data.Maybe (isJust, fromJust, fromMaybe) import qualified Data.Version import Monad import System.Console.GetOpt @@ -54,6 +77,7 @@ import qualified Ganeti.HTools.Text as Text import qualified Ganeti.HTools.Loader as Loader import qualified Ganeti.HTools.Instance as Instance import qualified Ganeti.HTools.Node as Node +import qualified Ganeti.HTools.Cluster as Cluster import Ganeti.HTools.Types @@ -61,53 +85,201 @@ import Ganeti.HTools.Types defaultLuxiSocket :: FilePath defaultLuxiSocket = "/var/run/ganeti/socket/ganeti-master" --- | Class for types which support show help and show version. -class CLIOptions a where - -- | Denotes whether the show help option has been passed. - showHelp :: a -> Bool - -- | Denotes whether the show version option has been passed. - showVersion :: a -> Bool - --- | Class for types which support the -i\/-n\/-m options. -class EToolOptions a where - -- | Returns the node file name. - nodeFile :: a -> FilePath - -- | Tells whether the node file has been passed as an option. - nodeSet :: a -> Bool - -- | Returns the instance file name. - instFile :: a -> FilePath - -- | Tells whether the instance file has been passed as an option. - instSet :: a -> Bool - -- | Rapi target, if one has been passed. - masterName :: a -> String - -- | Whether to connect to a local luxi socket. - luxiSocket :: a -> Maybe FilePath - -- | Whether to be less verbose. - silent :: a -> Bool +-- | Command line options structure. +data Options = Options + { optShowNodes :: Bool -- ^ Whether to show node status + , optShowCmds :: Maybe FilePath -- ^ Whether to show the command list + , optOneline :: Bool -- ^ Switch output to a single line + , optOutPath :: FilePath -- ^ Path to the output directory + , optNoHeaders :: Bool -- ^ Do not show a header line + , optNodeFile :: FilePath -- ^ Path to the nodes file + , optNodeSet :: Bool -- ^ The nodes have been set by options + , optInstFile :: FilePath -- ^ Path to the instances file + , optInstSet :: Bool -- ^ The insts have been set by options + , optMaxLength :: Int -- ^ Stop after this many steps + , optMaster :: String -- ^ Collect data from RAPI + , optLuxi :: Maybe FilePath -- ^ Collect data from Luxi + , optOffline :: [String] -- ^ Names of offline nodes + , optIMem :: Int -- ^ Instance memory + , optIDsk :: Int -- ^ Instance disk + , optIVCPUs :: Int -- ^ Instance VCPUs + , optINodes :: Int -- ^ Nodes required for an instance + , optMinScore :: Cluster.Score -- ^ The minimum score we aim for + , optMcpu :: Double -- ^ Max cpu ratio for nodes + , optMdsk :: Double -- ^ Max disk usage ratio for nodes + , optVerbose :: Int -- ^ Verbosity level + , 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 = Nothing + , optOneline = False + , optNoHeaders = False + , optOutPath = "." + , optNodeFile = "nodes" + , optNodeSet = False + , optInstFile = "instances" + , optInstSet = False + , optMaxLength = -1 + , optMaster = "" + , optLuxi = Nothing + , optOffline = [] + , optIMem = 4096 + , optIDsk = 102400 + , optIVCPUs = 1 + , optINodes = 2 + , optMinScore = 1e-9 + , optMcpu = -1 + , optMdsk = -1 + , optVerbose = 1 + , optShowVer = False + , optShowHelp = False + } + +-- | Abrreviation for the option type +type OptType = OptDescr (Options -> Options) + +oPrintNodes :: OptType +oPrintNodes = Option "p" ["print-nodes"] + (NoArg (\ opts -> opts { optShowNodes = True })) + "print the final node list" + +oPrintCommands :: OptType +oPrintCommands = Option "C" ["print-commands"] + (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" + +oOneline :: OptType +oOneline = Option "o" ["oneline"] + (NoArg (\ opts -> opts { optOneline = True })) + "print the ganeti command list for reaching the solution" + +oNoHeaders :: OptType +oNoHeaders = Option "" ["no-headers"] + (NoArg (\ opts -> opts { optNoHeaders = True })) + "do not show a header line" + +oOutputDir :: OptType +oOutputDir = Option "d" ["output-dir"] + (ReqArg (\ d opts -> opts { optOutPath = d }) "PATH") + "directory in which to write output files" + +oNodeFile :: OptType +oNodeFile = Option "n" ["nodes"] + (ReqArg (\ f o -> o { optNodeFile = f, optNodeSet = True }) "FILE") + "the node list FILE" + +oInstFile :: OptType +oInstFile = Option "i" ["instances"] + (ReqArg (\ f o -> o { optInstFile = f, optInstSet = True }) "FILE") + "the instance list FILE" + +oRapiMaster :: OptType +oRapiMaster = Option "m" ["master"] + (ReqArg (\ m opts -> opts { optMaster = m }) "ADDRESS") + "collect data via RAPI at the given ADDRESS" + +oLuxiSocket :: OptType +oLuxiSocket = Option "L" ["luxi"] + (OptArg ((\ f opts -> opts { optLuxi = Just f }) . + fromMaybe defaultLuxiSocket) "SOCKET") + "collect data via Luxi, optionally using the given SOCKET path" + +oVerbose :: OptType +oVerbose = Option "v" ["verbose"] + (NoArg (\ opts -> opts { optVerbose = optVerbose opts + 1 })) + "increase the verbosity level" + +oQuiet :: OptType +oQuiet = Option "q" ["quiet"] + (NoArg (\ opts -> opts { optVerbose = optVerbose opts - 1 })) + "decrease the verbosity level" + +oOfflineNode :: OptType +oOfflineNode = Option "O" ["offline"] + (ReqArg (\ n o -> o { optOffline = n:optOffline o }) "NODE") + "set node as offline" + +oMaxSolLength :: OptType +oMaxSolLength = Option "l" ["max-length"] + (ReqArg (\ i opts -> opts { optMaxLength = read i::Int }) "N") + "cap the solution at this many moves (useful for very\ + \ unbalanced clusters)" + +oMinScore :: OptType +oMinScore = Option "e" ["min-score"] + (ReqArg (\ e opts -> opts { optMinScore = read e }) "EPSILON") + " mininum score to aim for" + +oIMem :: OptType +oIMem = Option "" ["memory"] + (ReqArg (\ m opts -> opts { optIMem = read m }) "MEMORY") + "memory size for instances" + +oIDisk :: OptType +oIDisk = Option "" ["disk"] + (ReqArg (\ d opts -> opts { optIDsk = read d }) "DISK") + "disk size for instances" + +oIVcpus :: OptType +oIVcpus = Option "" ["vcpus"] + (ReqArg (\ p opts -> opts { optIVCPUs = read p }) "NUM") + "number of virtual cpus for instances" + +oINodes :: OptType +oINodes = Option "" ["req-nodes"] + (ReqArg (\ n opts -> opts { optINodes = read n }) "NODES") + "number of nodes for the new instances (1=plain, 2=mirrored)" + +oMaxCpu :: OptType +oMaxCpu = Option "" ["max-cpu"] + (ReqArg (\ n opts -> opts { optMcpu = read n }) "RATIO") + "maximum virtual-to-physical cpu ratio for nodes" + +oMinDisk :: OptType +oMinDisk = Option "" ["min-disk"] + (ReqArg (\ n opts -> opts { optMdsk = read n }) "RATIO") + "minimum free disk space for nodes (between 0 and 1)" + +oShowVer :: OptType +oShowVer = Option "V" ["version"] + (NoArg (\ opts -> opts { optShowVer = True})) + "show the version of the program" + +oShowHelp :: OptType +oShowHelp = Option "h" ["help"] + (NoArg (\ opts -> opts { optShowHelp = True})) + "show help" -- | Usage info -usageHelp :: (CLIOptions a) => String -> [OptDescr (a -> a)] -> String +usageHelp :: String -> [OptType] -> String usageHelp progname = usageInfo (printf "%s %s\nUsage: %s [OPTION...]" progname Version.version progname) -- | Command line parser, using the 'options' structure. -parseOpts :: (CLIOptions b) => - [String] -- ^ The command line arguments - -> String -- ^ The program name - -> [OptDescr (b -> b)] -- ^ The supported command line options - -> b -- ^ The default options record - -> IO (b, [String]) -- ^ The resulting options a leftover - -- arguments -parseOpts argv progname options defaultOptions = +parseOpts :: [String] -- ^ The command line arguments + -> String -- ^ The program name + -> [OptType] -- ^ The supported command line options + -> IO (Options, [String]) -- ^ The resulting options and leftover + -- arguments +parseOpts argv progname options = case getOpt Permute options argv of (o, n, []) -> do let resu@(po, _) = (foldl (flip id) defaultOptions o, n) - when (showHelp po) $ do + when (optShowHelp po) $ do putStr $ usageHelp progname options exitWith ExitSuccess - when (showVersion po) $ do + when (optShowVer po) $ do printf "%s %s\ncompiled with %s %s\nrunning on %s %s\n" progname Version.version compilerName (Data.Version.showVersion compilerVersion) @@ -141,20 +313,19 @@ shTemplate = \}\n\n" -- | External tool data loader from a variety of sources. -loadExternalData :: (EToolOptions a) => - a +loadExternalData :: Options -> IO (Node.List, Instance.List, String) loadExternalData opts = do (env_node, env_inst) <- parseEnv () - let nodef = if nodeSet opts then nodeFile opts + let nodef = if optNodeSet opts then optNodeFile opts else env_node - instf = if instSet opts then instFile opts + instf = if optInstSet opts then optInstFile opts else env_inst - mhost = masterName opts - lsock = luxiSocket opts + mhost = optMaster opts + lsock = optLuxi opts setRapi = mhost /= "" setLuxi = isJust lsock - setFiles = nodeSet opts || instSet opts + setFiles = optNodeSet opts || optInstSet opts allSet = filter id [setRapi, setLuxi, setFiles] when (length allSet > 1) $ do @@ -178,7 +349,7 @@ loadExternalData opts = do ) let (fix_msgs, fixed_nl) = Loader.checkData loaded_nl il - unless (null fix_msgs || silent opts) $ do + unless (null fix_msgs || optVerbose opts == 0) $ do hPutStrLn stderr "Warning: cluster has inconsistent data:" hPutStrLn stderr . unlines . map (printf " - %s") $ fix_msgs diff --git a/hail.hs b/hail.hs index 0167d55..7690f44 100644 --- a/hail.hs +++ b/hail.hs @@ -30,46 +30,21 @@ import Data.Function import Monad import System import System.IO -import System.Console.GetOpt import qualified System import Text.Printf (printf) import qualified Ganeti.HTools.Cluster as Cluster import qualified Ganeti.HTools.Node as Node -import qualified Ganeti.HTools.CLI as CLI + +import Ganeti.HTools.CLI import Ganeti.HTools.IAlloc import Ganeti.HTools.Types import Ganeti.HTools.Loader (RqType(..), Request(..)) --- | Command line options structure. -data Options = Options - { 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 - { optShowVer = False - , optShowHelp = False - } - -instance CLI.CLIOptions Options where - showVersion = optShowVer - showHelp = optShowHelp - -- | Options list and functions -options :: [OptDescr (Options -> Options)] -options = - [ Option ['V'] ["version"] - (NoArg (\ opts -> opts { optShowVer = True})) - "show the version of the program" - , Option ['h'] ["help"] - (NoArg (\ opts -> opts { optShowHelp = True})) - "show help" - ] - +options :: [OptType] +options = [oShowVer, oShowHelp] processResults :: (Monad m) => Cluster.AllocSolution -> m (String, [Node.Node]) processResults (fstats, succ, sols) = @@ -96,7 +71,7 @@ processRequest request = main :: IO () main = do cmd_args <- System.getArgs - (_, args) <- CLI.parseOpts cmd_args "hail" options defaultOptions + (_, args) <- parseOpts cmd_args "hail" options when (null args) $ do hPutStrLn stderr "Error: this program needs an input file." diff --git a/hbal.hs b/hbal.hs index 21d9c74..788dc9a 100644 --- a/hbal.hs +++ b/hbal.hs @@ -27,11 +27,10 @@ module Main (main) where import Data.List import Data.Function -import Data.Maybe (isJust, fromJust, fromMaybe) +import Data.Maybe (isJust, fromJust) import Monad import System import System.IO -import System.Console.GetOpt import qualified System import Text.Printf (printf, hPrintf) @@ -39,122 +38,29 @@ import Text.Printf (printf, hPrintf) import qualified Ganeti.HTools.Container as Container import qualified Ganeti.HTools.Cluster as Cluster import qualified Ganeti.HTools.Node as Node -import qualified Ganeti.HTools.CLI as CLI +import Ganeti.HTools.CLI import Ganeti.HTools.Utils --- | Command line options structure. -data Options = Options - { 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 - , optNodeSet :: Bool -- ^ The nodes have been set by options - , optInstf :: FilePath -- ^ Path to the instances file - , optInstSet :: Bool -- ^ The insts have been set by options - , optMaxLength :: Int -- ^ Stop after this many steps - , optMaster :: String -- ^ Collect data from RAPI - , optLuxi :: Maybe FilePath -- ^ Collect data from Luxi - , optVerbose :: Int -- ^ Verbosity level - , optOffline :: [String] -- ^ Names of offline nodes - , optMinScore :: Cluster.Score -- ^ The minimum score we aim for - , optMcpu :: Double -- ^ Max cpu ratio for nodes - , optMdsk :: Double -- ^ Max disk usage ratio for nodes - , optShowVer :: Bool -- ^ Just show the program version - , optShowHelp :: Bool -- ^ Just show the help - } deriving Show - -instance CLI.CLIOptions Options where - showVersion = optShowVer - showHelp = optShowHelp - -instance CLI.EToolOptions Options where - nodeFile = optNodef - nodeSet = optNodeSet - instFile = optInstf - instSet = optInstSet - masterName = optMaster - luxiSocket = optLuxi - silent a = optVerbose a == 0 - --- | Default values for the command line options. -defaultOptions :: Options -defaultOptions = Options - { optShowNodes = False - , optShowCmds = Nothing - , optOneline = False - , optNodef = "nodes" - , optNodeSet = False - , optInstf = "instances" - , optInstSet = False - , optMaxLength = -1 - , optMaster = "" - , optLuxi = Nothing - , optVerbose = 1 - , optOffline = [] - , optMinScore = 1e-9 - , optMcpu = -1 - , optMdsk = -1 - , optShowVer = False - , optShowHelp = False - } - -- | Options list and functions -options :: [OptDescr (Options -> Options)] +options :: [OptType] options = - [ Option ['p'] ["print-nodes"] - (NoArg (\ opts -> opts { optShowNodes = True })) - "print the final node list" - , Option ['C'] ["print-commands"] - (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" - , Option ['n'] ["nodes"] - (ReqArg (\ f opts -> opts { optNodef = f, optNodeSet = True }) "FILE") - "the node list FILE" - , Option ['i'] ["instances"] - (ReqArg (\ f opts -> opts { optInstf = f, optInstSet = True }) "FILE") - "the instance list FILE" - , Option ['m'] ["master"] - (ReqArg (\ m opts -> opts { optMaster = m }) "ADDRESS") - "collect data via RAPI at the given ADDRESS" - , Option ['L'] ["luxi"] - (OptArg ((\ f opts -> opts { optLuxi = Just f }) . - fromMaybe CLI.defaultLuxiSocket) "SOCKET") - "collect data via Luxi, optionally using the given SOCKET path" - , Option ['l'] ["max-length"] - (ReqArg (\ i opts -> opts { optMaxLength = read i::Int }) "N") - "cap the solution at this many moves (useful for very unbalanced \ - \clusters)" - , Option ['v'] ["verbose"] - (NoArg (\ opts -> opts { optVerbose = optVerbose opts + 1 })) - "increase the verbosity level" - , Option ['q'] ["quiet"] - (NoArg (\ opts -> opts { optVerbose = optVerbose opts - 1 })) - "decrease the verbosity level" - , Option ['O'] ["offline"] - (ReqArg (\ n opts -> opts { optOffline = n:optOffline opts }) "NODE") - " set node as offline" - , Option ['e'] ["min-score"] - (ReqArg (\ e opts -> opts { optMinScore = read e }) "EPSILON") - " mininum score to aim for" - , Option [] ["max-cpu"] - (ReqArg (\ n opts -> opts { optMcpu = read n }) "RATIO") - "maximum virtual-to-physical cpu ratio for nodes" - , Option [] ["min-disk"] - (ReqArg (\ n opts -> opts { optMdsk = read n }) "RATIO") - "minimum free disk space for nodes (between 0 and 1)" - , Option ['V'] ["version"] - (NoArg (\ opts -> opts { optShowVer = True})) - "show the version of the program" - , Option ['h'] ["help"] - (NoArg (\ opts -> opts { optShowHelp = True})) - "show help" + [ oPrintNodes + , oPrintCommands + , oOneline + , oNodeFile + , oInstFile + , oRapiMaster + , oLuxiSocket + , oMaxSolLength + , oVerbose + , oQuiet + , oOfflineNode + , oMinScore + , oMaxCpu + , oMinDisk + , oShowVer + , oShowHelp ] {- | Start computing the solution at the given depth and recurse until @@ -209,7 +115,7 @@ formatOneline ini_cv plc_len fin_cv = main :: IO () main = do cmd_args <- System.getArgs - (opts, args) <- CLI.parseOpts cmd_args "hbal" options defaultOptions + (opts, args) <- parseOpts cmd_args "hbal" options unless (null args) $ do hPutStrLn stderr "Error: this program doesn't take any arguments." @@ -218,7 +124,7 @@ main = do let oneline = optOneline opts verbose = optVerbose opts - (fixed_nl, il, csf) <- CLI.loadExternalData opts + (fixed_nl, il, csf) <- loadExternalData opts let offline_names = optOffline opts all_nodes = Container.elems fixed_nl @@ -319,7 +225,7 @@ main = do filter (/= "check") . lines $ cmd_data) else do - writeFile out_path (CLI.shTemplate ++ cmd_data) + writeFile out_path (shTemplate ++ cmd_data) printf "The commands have been written to file '%s'\n" out_path) when (optShowNodes opts) $ diff --git a/hscan.hs b/hscan.hs index 6e69912..deac4e4 100644 --- a/hscan.hs +++ b/hscan.hs @@ -31,7 +31,6 @@ import Monad import System import System.IO import System.FilePath -import System.Console.GetOpt import qualified System import Text.Printf (printf) @@ -40,57 +39,21 @@ import qualified Ganeti.HTools.Container as Container import qualified Ganeti.HTools.Cluster as Cluster import qualified Ganeti.HTools.Node as Node import qualified Ganeti.HTools.Instance as Instance -import qualified Ganeti.HTools.CLI as CLI import qualified Ganeti.HTools.Rapi as Rapi import qualified Ganeti.HTools.Loader as Loader -import Ganeti.HTools.Types --- | Command line options structure. -data Options = Options - { optShowNodes :: Bool -- ^ Whether to show node status - , optOutPath :: FilePath -- ^ Path to the output directory - , optVerbose :: Int -- ^ Verbosity level - , optNoHeader :: Bool -- ^ Do not show a header line - , optShowVer :: Bool -- ^ Just show the program version - , optShowHelp :: Bool -- ^ Just show the help - } deriving Show - -instance CLI.CLIOptions Options where - showVersion = optShowVer - showHelp = optShowHelp - --- | Default values for the command line options. -defaultOptions :: Options -defaultOptions = Options - { optShowNodes = False - , optOutPath = "." - , optVerbose = 0 - , optNoHeader = False - , optShowVer = False - , optShowHelp = False - } +import Ganeti.HTools.CLI +import Ganeti.HTools.Types -- | Options list and functions -options :: [OptDescr (Options -> Options)] +options :: [OptType] options = - [ Option ['p'] ["print-nodes"] - (NoArg (\ opts -> opts { optShowNodes = True })) - "print the final node list" - , Option ['d'] ["output-dir"] - (ReqArg (\ d opts -> opts { optOutPath = d }) "PATH") - "directory in which to write output files" - , Option ['v'] ["verbose"] - (NoArg (\ opts -> opts { optVerbose = optVerbose opts + 1 })) - "increase the verbosity level" - , Option [] ["no-headers"] - (NoArg (\ opts -> opts { optNoHeader = True })) - "do not show a header line" - , Option ['V'] ["version"] - (NoArg (\ opts -> opts { optShowVer = True})) - "show the version of the program" - , Option ['h'] ["help"] - (NoArg (\ opts -> opts { optShowHelp = True})) - "show help" + [ oPrintNodes + , oOutputDir + , oVerbose + , oNoHeaders + , oShowVer + , oShowHelp ] -- | Serialize a single node @@ -157,13 +120,12 @@ fixSlash = map (\x -> if x == '/' then '_' else x) main :: IO () main = do cmd_args <- System.getArgs - (opts, clusters) <- CLI.parseOpts cmd_args "hscan" options - defaultOptions + (opts, clusters) <- parseOpts cmd_args "hscan" options let odir = optOutPath opts nlen = maximum . map length $ clusters - unless (optNoHeader opts) $ + unless (optNoHeaders opts) $ printf "%-*s %5s %5s %5s %5s %6s %6s %6s %6s %10s\n" nlen "Name" "Nodes" "Inst" "BNode" "BInst" "t_mem" "f_mem" "t_disk" "f_disk" "Score" diff --git a/hspace.hs b/hspace.hs index 9f9f012..41daebf 100644 --- a/hspace.hs +++ b/hspace.hs @@ -28,11 +28,9 @@ module Main (main) where import Data.Char (toUpper) import Data.List import Data.Function -import Data.Maybe (fromMaybe) import Monad import System import System.IO -import System.Console.GetOpt import qualified System import Text.Printf (printf, hPrintf) @@ -41,119 +39,30 @@ import qualified Ganeti.HTools.Container as Container import qualified Ganeti.HTools.Cluster as Cluster import qualified Ganeti.HTools.Node as Node import qualified Ganeti.HTools.Instance as Instance -import qualified Ganeti.HTools.CLI as CLI import Ganeti.HTools.Utils import Ganeti.HTools.Types - --- | Command line options structure. -data Options = Options - { optShowNodes :: Bool -- ^ Whether to show node status - , optNodef :: FilePath -- ^ Path to the nodes file - , optNodeSet :: Bool -- ^ The nodes have been set by options - , optInstf :: FilePath -- ^ Path to the instances file - , optInstSet :: Bool -- ^ The insts have been set by options - , optMaster :: String -- ^ Collect data from RAPI - , optLuxi :: Maybe FilePath -- ^ Collect data from Luxi - , optVerbose :: Int -- ^ Verbosity level - , optOffline :: [String] -- ^ Names of offline nodes - , optIMem :: Int -- ^ Instance memory - , optIDsk :: Int -- ^ Instance disk - , optIVCPUs :: Int -- ^ Instance VCPUs - , optINodes :: Int -- ^ Nodes required for an instance - , optMcpu :: Double -- ^ Max cpu ratio for nodes - , optMdsk :: Double -- ^ Max disk usage ratio for nodes - , optShowVer :: Bool -- ^ Just show the program version - , optShowHelp :: Bool -- ^ Just show the help - } deriving Show - -instance CLI.CLIOptions Options where - showVersion = optShowVer - showHelp = optShowHelp - -instance CLI.EToolOptions Options where - nodeFile = optNodef - nodeSet = optNodeSet - instFile = optInstf - instSet = optInstSet - masterName = optMaster - luxiSocket = optLuxi - silent a = optVerbose a == 0 - --- | Default values for the command line options. -defaultOptions :: Options -defaultOptions = Options - { optShowNodes = False - , optNodef = "nodes" - , optNodeSet = False - , optInstf = "instances" - , optInstSet = False - , optMaster = "" - , optLuxi = Nothing - , optVerbose = 1 - , optOffline = [] - , optIMem = 4096 - , optIDsk = 102400 - , optIVCPUs = 1 - , optINodes = 2 - , optMcpu = -1 - , optMdsk = -1 - , optShowVer = False - , optShowHelp = False - } +import Ganeti.HTools.CLI -- | Options list and functions -options :: [OptDescr (Options -> Options)] +options :: [OptType] options = - [ Option ['p'] ["print-nodes"] - (NoArg (\ opts -> opts { optShowNodes = True })) - "print the final node list" - , Option ['n'] ["nodes"] - (ReqArg (\ f opts -> opts { optNodef = f, optNodeSet = True }) "FILE") - "the node list FILE" - , Option ['i'] ["instances"] - (ReqArg (\ f opts -> opts { optInstf = f, optInstSet = True }) "FILE") - "the instance list FILE" - , Option ['m'] ["master"] - (ReqArg (\ m opts -> opts { optMaster = m }) "ADDRESS") - "collect data via RAPI at the given ADDRESS" - , Option ['L'] ["luxi"] - (OptArg ((\ f opts -> opts { optLuxi = Just f }) . - fromMaybe CLI.defaultLuxiSocket) "SOCKET") - "collect data via Luxi, optionally using the given SOCKET path" - , Option ['v'] ["verbose"] - (NoArg (\ opts -> opts { optVerbose = optVerbose opts + 1 })) - "increase the verbosity level" - , Option ['q'] ["quiet"] - (NoArg (\ opts -> opts { optVerbose = optVerbose opts - 1 })) - "decrease the verbosity level" - , Option ['O'] ["offline"] - (ReqArg (\ n opts -> opts { optOffline = n:optOffline opts }) "NODE") - "set node as offline" - , Option [] ["memory"] - (ReqArg (\ m opts -> opts { optIMem = read m }) "MEMORY") - "memory size for instances" - , Option [] ["disk"] - (ReqArg (\ d opts -> opts { optIDsk = read d }) "DISK") - "disk size for instances" - , Option [] ["vcpus"] - (ReqArg (\ p opts -> opts { optIVCPUs = read p }) "NUM") - "number of virtual cpus for instances" - , Option [] ["req-nodes"] - (ReqArg (\ n opts -> opts { optINodes = read n }) "NODES") - "number of nodes for the new instances (1=plain, 2=mirrored)" - , Option [] ["max-cpu"] - (ReqArg (\ n opts -> opts { optMcpu = read n }) "RATIO") - "maximum virtual-to-physical cpu ratio for nodes" - , Option [] ["min-disk"] - (ReqArg (\ n opts -> opts { optMdsk = read n }) "RATIO") - "minimum free disk space for nodes (between 0 and 1)" - , Option ['V'] ["version"] - (NoArg (\ opts -> opts { optShowVer = True})) - "show the version of the program" - , Option ['h'] ["help"] - (NoArg (\ opts -> opts { optShowHelp = True})) - "show help" + [ oPrintNodes + , oNodeFile + , oInstFile + , oRapiMaster + , oLuxiSocket + , oVerbose + , oQuiet + , oOfflineNode + , oIMem + , oIDisk + , oIVcpus + , oINodes + , oMaxCpu + , oMinDisk + , oShowVer + , oShowHelp ] data Phase = PInitial | PFinal @@ -261,7 +170,7 @@ printKeys = mapM_ (\(k, v) -> printf "HTS_%s=%s\n" (map toUpper k) v) main :: IO () main = do cmd_args <- System.getArgs - (opts, args) <- CLI.parseOpts cmd_args "hspace" options defaultOptions + (opts, args) <- parseOpts cmd_args "hspace" options unless (null args) $ do hPutStrLn stderr "Error: this program doesn't take any arguments." @@ -269,7 +178,7 @@ main = do let verbose = optVerbose opts - (fixed_nl, il, csf) <- CLI.loadExternalData opts + (fixed_nl, il, csf) <- loadExternalData opts printKeys $ map (\(a, fn) -> ("SPEC_" ++ a, fn opts)) specData -- 1.7.10.4