diff --git a/Ganeti/HTools/CLI.hs b/Ganeti/HTools/CLI.hs index df68b996003e91a61a1803be61400af9fe4ca3d9..718440f9d42da4959b195028782c45e8248a9382 100644 --- a/Ganeti/HTools/CLI.hs +++ b/Ganeti/HTools/CLI.hs @@ -144,21 +144,21 @@ defaultOptions = Options } -- | Abrreviation for the option type -type OptType = OptDescr (Options -> Options) +type OptType = OptDescr (Options -> Result Options) oPrintNodes :: OptType oPrintNodes = Option "p" ["print-nodes"] - (NoArg (\ opts -> opts { optShowNodes = True })) + (NoArg (\ opts -> Ok opts { optShowNodes = True })) "print the final node list" oPrintInsts :: OptType oPrintInsts = Option "" ["print-instances"] - (NoArg (\ opts -> opts { optShowInsts = True })) + (NoArg (\ opts -> Ok opts { optShowInsts = True })) "print the final instance map" oPrintCommands :: OptType oPrintCommands = Option "C" ["print-commands"] - (OptArg ((\ f opts -> opts { optShowCmds = Just f }) . + (OptArg ((\ f opts -> Ok opts { optShowCmds = Just f }) . fromMaybe "-") "FILE") "print the ganeti command list for reaching the solution,\ @@ -167,126 +167,128 @@ oPrintCommands = Option "C" ["print-commands"] oOneline :: OptType oOneline = Option "o" ["oneline"] - (NoArg (\ opts -> opts { optOneline = True })) + (NoArg (\ opts -> Ok opts { optOneline = True })) "print the ganeti command list for reaching the solution" oNoHeaders :: OptType oNoHeaders = Option "" ["no-headers"] - (NoArg (\ opts -> opts { optNoHeaders = True })) + (NoArg (\ opts -> Ok opts { optNoHeaders = True })) "do not show a header line" oOutputDir :: OptType oOutputDir = Option "d" ["output-dir"] - (ReqArg (\ d opts -> opts { optOutPath = d }) "PATH") + (ReqArg (\ d opts -> Ok 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") + (ReqArg (\ f o -> Ok 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") + (ReqArg (\ f o -> Ok o { optInstFile = f, + optInstSet = True }) "FILE") "the instance list FILE" oNodeSim :: OptType oNodeSim = Option "" ["simulate"] - (ReqArg (\ f o -> o { optNodeSim = Just f }) "SPEC") + (ReqArg (\ f o -> Ok o { optNodeSim = Just f }) "SPEC") "simulate an empty cluster, given as 'num_nodes,disk,memory,cpus'" oRapiMaster :: OptType oRapiMaster = Option "m" ["master"] - (ReqArg (\ m opts -> opts { optMaster = m }) "ADDRESS") + (ReqArg (\ m opts -> Ok 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 }) . + (OptArg ((\ f opts -> Ok opts { optLuxi = Just f }) . fromMaybe defaultLuxiSocket) "SOCKET") "collect data via Luxi, optionally using the given SOCKET path" oExecJobs :: OptType oExecJobs = Option "X" ["exec"] - (NoArg (\ opts -> opts { optExecJobs = True})) + (NoArg (\ opts -> Ok opts { optExecJobs = True})) "execute the suggested moves via Luxi (only available when using\ \ it for data gathering" oVerbose :: OptType oVerbose = Option "v" ["verbose"] - (NoArg (\ opts -> opts { optVerbose = optVerbose opts + 1 })) + (NoArg (\ opts -> Ok opts { optVerbose = optVerbose opts + 1 })) "increase the verbosity level" oQuiet :: OptType oQuiet = Option "q" ["quiet"] - (NoArg (\ opts -> opts { optVerbose = optVerbose opts - 1 })) + (NoArg (\ opts -> Ok opts { optVerbose = optVerbose opts - 1 })) "decrease the verbosity level" oOfflineNode :: OptType oOfflineNode = Option "O" ["offline"] - (ReqArg (\ n o -> o { optOffline = n:optOffline o }) "NODE") + (ReqArg (\ n o -> Ok 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") + (ReqArg (\ i opts -> Ok opts { optMaxLength = read i }) "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") + (ReqArg (\ e opts -> Ok opts { optMinScore = read e }) "EPSILON") " mininum score to aim for" oIMem :: OptType oIMem = Option "" ["memory"] - (ReqArg (\ m opts -> opts { optIMem = read m }) "MEMORY") + (ReqArg (\ m opts -> Ok opts { optIMem = read m }) "MEMORY") "memory size for instances" oIDisk :: OptType oIDisk = Option "" ["disk"] - (ReqArg (\ d opts -> opts { optIDsk = read d }) "DISK") + (ReqArg (\ d opts -> Ok opts { optIDsk = read d }) "DISK") "disk size for instances" oIVcpus :: OptType oIVcpus = Option "" ["vcpus"] - (ReqArg (\ p opts -> opts { optIVCPUs = read p }) "NUM") + (ReqArg (\ p opts -> Ok 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") + (ReqArg (\ n opts -> Ok 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") + (ReqArg (\ n opts -> Ok 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") + (ReqArg (\ n opts -> Ok opts { optMdsk = read n }) "RATIO") "minimum free disk space for nodes (between 0 and 1)" oDiskMoves :: OptType oDiskMoves = Option "" ["no-disk-moves"] - (NoArg (\ opts -> opts { optDiskMoves = False})) + (NoArg (\ opts -> Ok opts { optDiskMoves = False})) "disallow disk moves from the list of allowed instance changes,\ \ thus allowing only the 'cheap' failover/migrate operations" oDynuFile :: OptType oDynuFile = Option "U" ["dynu-file"] - (ReqArg (\ f opts -> opts { optDynuFile = Just f }) "FILE") + (ReqArg (\ f opts -> Ok opts { optDynuFile = Just f }) "FILE") "Import dynamic utilisation data from the given FILE" oShowVer :: OptType oShowVer = Option "V" ["version"] - (NoArg (\ opts -> opts { optShowVer = True})) + (NoArg (\ opts -> Ok opts { optShowVer = True})) "show the version of the program" oShowHelp :: OptType oShowHelp = Option "h" ["help"] - (NoArg (\ opts -> opts { optShowHelp = True})) + (NoArg (\ opts -> Ok opts { optShowHelp = True})) "show help" -- | Usage info @@ -305,7 +307,14 @@ parseOpts argv progname options = case getOpt Permute options argv of (o, n, []) -> do - let resu@(po, _) = (foldl (flip id) defaultOptions o, n) + let (pr, args) = (foldM (flip id) defaultOptions o, n) + po <- (case pr of + Bad msg -> do + hPutStrLn stderr "Error while parsing command\ + \line arguments:" + hPutStrLn stderr msg + exitWith $ ExitFailure 1 + Ok val -> return val) when (optShowHelp po) $ do putStr $ usageHelp progname options exitWith ExitSuccess @@ -315,7 +324,7 @@ parseOpts argv progname options = compilerName (Data.Version.showVersion compilerVersion) os arch exitWith ExitSuccess - return resu + return (po, args) (_, _, errs) -> do hPutStrLn stderr $ "Command line error: " ++ concat errs hPutStrLn stderr $ usageHelp progname options