, parseOpts
, shTemplate
-- * The options
- , oPrintNodes
- , oPrintInsts
- , oPrintCommands
- , oOneline
- , oNoHeaders
- , oOutputDir
, oDataFile
- , oNodeSim
- , oRapiMaster
- , oLuxiSocket
+ , oDiskMoves
+ , oDynuFile
+ , oEvacMode
+ , oExTags
, oExecJobs
- , oMaxSolLength
- , oVerbose
- , oQuiet
- , oOfflineNode
- , oMinScore
- , oIMem
, oIDisk
- , oIVcpus
+ , oIMem
, oINodes
+ , oIVcpus
+ , oLuxiSocket
, oMaxCpu
+ , oMaxSolLength
, oMinDisk
- , oDiskMoves
- , oDynuFile
- , oTieredSpec
- , oExTags
- , oShowVer
+ , oMinScore
+ , oNoHeaders
+ , oNodeSim
+ , oOfflineNode
+ , oOneline
+ , oOutputDir
+ , oPrintCommands
+ , oPrintInsts
+ , oPrintNodes
+ , oQuiet
+ , oRapiMaster
, oShowHelp
+ , oShowVer
+ , oTieredSpec
+ , oVerbose
) where
import Data.Maybe (fromMaybe)
-- | Command line options structure.
data Options = Options
- { optShowNodes :: Maybe [String] -- ^ Whether to show node status
- , optShowInsts :: Bool -- ^ Whether to show the instance map
- , 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
- , optDataFile :: Maybe FilePath -- ^ Path to the cluster data file
- , optNodeSim :: Maybe String -- ^ Cluster simulation mode
- , optMaxLength :: Int -- ^ Stop after this many steps
- , optMaster :: String -- ^ Collect data from RAPI
- , optLuxi :: Maybe FilePath -- ^ Collect data from Luxi
+ { optDataFile :: Maybe FilePath -- ^ Path to the cluster data file
+ , optDiskMoves :: Bool -- ^ Allow disk moves
+ , optDynuFile :: Maybe FilePath -- ^ Optional file with dynamic use data
+ , optEvacMode :: Bool -- ^ Enable evacuation mode
+ , optExTags :: Maybe [String] -- ^ Tags to use for exclusion
, optExecJobs :: Bool -- ^ Execute the commands via Luxi
- , optOffline :: [String] -- ^ Names of offline nodes
, optINodes :: Int -- ^ Nodes required for an instance
, optISpec :: RSpec -- ^ Requested instance specs
- , optTieredSpec :: Maybe RSpec -- ^ Requested specs for tiered mode
- , optMinScore :: Score -- ^ The minimum score we aim for
+ , optLuxi :: Maybe FilePath -- ^ Collect data from Luxi
+ , optMaster :: String -- ^ Collect data from RAPI
+ , optMaxLength :: Int -- ^ Stop after this many steps
, optMcpu :: Double -- ^ Max cpu ratio for nodes
, optMdsk :: Double -- ^ Max disk usage ratio for nodes
- , optDiskMoves :: Bool -- ^ Allow disk moves
- , optDynuFile :: Maybe FilePath -- ^ Optional file with dynamic use data
- , optExTags :: Maybe [String] -- ^ Tags to use for exclusion
- , optVerbose :: Int -- ^ Verbosity level
- , optShowVer :: Bool -- ^ Just show the program version
+ , optMinScore :: Score -- ^ The minimum score we aim for
+ , optNoHeaders :: Bool -- ^ Do not show a header line
+ , optNodeSim :: Maybe String -- ^ Cluster simulation mode
+ , optOffline :: [String] -- ^ Names of offline nodes
+ , optOneline :: Bool -- ^ Switch output to a single line
+ , optOutPath :: FilePath -- ^ Path to the output directory
+ , optShowCmds :: Maybe FilePath -- ^ Whether to show the command list
, optShowHelp :: Bool -- ^ Just show the help
+ , optShowInsts :: Bool -- ^ Whether to show the instance map
+ , optShowNodes :: Maybe [String] -- ^ Whether to show node status
+ , optShowVer :: Bool -- ^ Just show the program version
+ , optTieredSpec :: Maybe RSpec -- ^ Requested specs for tiered mode
+ , optVerbose :: Int -- ^ Verbosity level
} deriving Show
-- | Default values for the command line options.
defaultOptions :: Options
defaultOptions = Options
- { optShowNodes = Nothing
- , optShowInsts = False
- , optShowCmds = Nothing
- , optOneline = False
- , optNoHeaders = False
- , optOutPath = "."
- , optDataFile = Nothing
- , optNodeSim = Nothing
- , optMaxLength = -1
- , optMaster = ""
- , optLuxi = Nothing
+ { optDataFile = Nothing
+ , optDiskMoves = True
+ , optDynuFile = Nothing
+ , optEvacMode = False
+ , optExTags = Nothing
, optExecJobs = False
- , optOffline = []
, optINodes = 2
, optISpec = RSpec 1 4096 102400
- , optTieredSpec = Nothing
- , optMinScore = 1e-9
+ , optLuxi = Nothing
+ , optMaster = ""
+ , optMaxLength = -1
, optMcpu = -1
, optMdsk = -1
- , optDiskMoves = True
- , optDynuFile = Nothing
- , optExTags = Nothing
- , optVerbose = 1
- , optShowVer = False
+ , optMinScore = 1e-9
+ , optNoHeaders = False
+ , optNodeSim = Nothing
+ , optOffline = []
+ , optOneline = False
+ , optOutPath = "."
+ , optShowCmds = Nothing
, optShowHelp = False
+ , optShowInsts = False
+ , optShowNodes = Nothing
+ , optShowVer = False
+ , optTieredSpec = Nothing
+ , optVerbose = 1
}
-- | Abrreviation for the option type
type OptType = OptDescr (Options -> Result Options)
-oPrintNodes :: OptType
-oPrintNodes = Option "p" ["print-nodes"]
- (OptArg ((\ f opts ->
- let splitted = sepSplit ',' f
- in Ok opts { optShowNodes = Just splitted }) .
- fromMaybe []) "FIELDS")
- "print the final node list"
-
-oPrintInsts :: OptType
-oPrintInsts = Option "" ["print-instances"]
- (NoArg (\ opts -> Ok opts { optShowInsts = True }))
- "print the final instance map"
-
-oPrintCommands :: OptType
-oPrintCommands = Option "C" ["print-commands"]
- (OptArg ((\ f opts -> Ok 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 -> Ok opts { optOneline = True }))
- "print the ganeti command list for reaching the solution"
-
-oNoHeaders :: OptType
-oNoHeaders = Option "" ["no-headers"]
- (NoArg (\ opts -> Ok opts { optNoHeaders = True }))
- "do not show a header line"
-
-oOutputDir :: OptType
-oOutputDir = Option "d" ["output-dir"]
- (ReqArg (\ d opts -> Ok opts { optOutPath = d }) "PATH")
- "directory in which to write output files"
-
oDataFile :: OptType
oDataFile = Option "t" ["text-data"]
(ReqArg (\ f o -> Ok o { optDataFile = Just f }) "FILE")
"the cluster data FILE"
-oNodeSim :: OptType
-oNodeSim = Option "" ["simulate"]
- (ReqArg (\ f o -> Ok o { optNodeSim = Just f }) "SPEC")
- "simulate an empty cluster, given as 'num_nodes,disk,ram,cpu'"
+oDiskMoves :: OptType
+oDiskMoves = Option "" ["no-disk-moves"]
+ (NoArg (\ opts -> Ok opts { optDiskMoves = False}))
+ "disallow disk moves from the list of allowed instance changes,\
+ \ thus allowing only the 'cheap' failover/migrate operations"
-oRapiMaster :: OptType
-oRapiMaster = Option "m" ["master"]
- (ReqArg (\ m opts -> Ok opts { optMaster = m }) "ADDRESS")
- "collect data via RAPI at the given ADDRESS"
+oDynuFile :: OptType
+oDynuFile = Option "U" ["dynu-file"]
+ (ReqArg (\ f opts -> Ok opts { optDynuFile = Just f }) "FILE")
+ "Import dynamic utilisation data from the given FILE"
-oLuxiSocket :: OptType
-oLuxiSocket = Option "L" ["luxi"]
- (OptArg ((\ f opts -> Ok opts { optLuxi = Just f }) .
- fromMaybe defaultLuxiSocket) "SOCKET")
- "collect data via Luxi, optionally using the given SOCKET path"
+oEvacMode :: OptType
+oEvacMode = Option "E" ["evac-mode"]
+ (NoArg (\opts -> Ok opts { optEvacMode = True }))
+ "enable evacuation mode, where the algorithm only moves \
+ \ instances away from offline and drained nodes"
+
+oExTags :: OptType
+oExTags = Option "" ["exclusion-tags"]
+ (ReqArg (\ f opts -> Ok opts { optExTags = Just $ sepSplit ',' f })
+ "TAG,...") "Enable instance exclusion based on given tag prefix"
oExecJobs :: OptType
oExecJobs = Option "X" ["exec"]
"execute the suggested moves via Luxi (only available when using\
\ it for data gathering)"
-oVerbose :: OptType
-oVerbose = Option "v" ["verbose"]
- (NoArg (\ opts -> Ok opts { optVerbose = optVerbose opts + 1 }))
- "increase the verbosity level"
-
-oQuiet :: OptType
-oQuiet = Option "q" ["quiet"]
- (NoArg (\ opts -> Ok opts { optVerbose = optVerbose opts - 1 }))
- "decrease the verbosity level"
-
-oOfflineNode :: OptType
-oOfflineNode = Option "O" ["offline"]
- (ReqArg (\ n o -> Ok o { optOffline = n:optOffline o }) "NODE")
- "set node as offline"
-
-oMaxSolLength :: OptType
-oMaxSolLength = Option "l" ["max-length"]
- (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 -> Ok opts { optMinScore = read e }) "EPSILON")
- " mininum score to aim for"
+oIDisk :: OptType
+oIDisk = Option "" ["disk"]
+ (ReqArg (\ d opts ->
+ let ospec = optISpec opts
+ nspec = ospec { rspecDsk = read d }
+ in Ok opts { optISpec = nspec }) "DISK")
+ "disk size for instances"
oIMem :: OptType
oIMem = Option "" ["memory"]
in Ok opts { optISpec = nspec }) "MEMORY")
"memory size for instances"
-oIDisk :: OptType
-oIDisk = Option "" ["disk"]
- (ReqArg (\ d opts ->
- let ospec = optISpec opts
- nspec = ospec { rspecDsk = read d }
- in Ok opts { optISpec = nspec }) "DISK")
- "disk size for instances"
+oINodes :: OptType
+oINodes = Option "" ["req-nodes"]
+ (ReqArg (\ n opts -> Ok opts { optINodes = read n }) "NODES")
+ "number of nodes for the new instances (1=plain, 2=mirrored)"
oIVcpus :: OptType
oIVcpus = Option "" ["vcpus"]
in Ok opts { optISpec = nspec }) "NUM")
"number of virtual cpus for instances"
-oINodes :: OptType
-oINodes = Option "" ["req-nodes"]
- (ReqArg (\ n opts -> Ok opts { optINodes = read n }) "NODES")
- "number of nodes for the new instances (1=plain, 2=mirrored)"
+oLuxiSocket :: OptType
+oLuxiSocket = Option "L" ["luxi"]
+ (OptArg ((\ f opts -> Ok opts { optLuxi = Just f }) .
+ fromMaybe defaultLuxiSocket) "SOCKET")
+ "collect data via Luxi, optionally using the given SOCKET path"
oMaxCpu :: OptType
oMaxCpu = Option "" ["max-cpu"]
(ReqArg (\ n opts -> Ok opts { optMcpu = read n }) "RATIO")
"maximum virtual-to-physical cpu ratio for nodes"
+oMaxSolLength :: OptType
+oMaxSolLength = Option "l" ["max-length"]
+ (ReqArg (\ i opts -> Ok opts { optMaxLength = read i }) "N")
+ "cap the solution at this many moves (useful for very\
+ \ unbalanced clusters)"
+
oMinDisk :: OptType
oMinDisk = Option "" ["min-disk"]
(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 -> Ok opts { optDiskMoves = False}))
- "disallow disk moves from the list of allowed instance changes,\
- \ thus allowing only the 'cheap' failover/migrate operations"
+oMinScore :: OptType
+oMinScore = Option "e" ["min-score"]
+ (ReqArg (\ e opts -> Ok opts { optMinScore = read e }) "EPSILON")
+ " mininum score to aim for"
-oDynuFile :: OptType
-oDynuFile = Option "U" ["dynu-file"]
- (ReqArg (\ f opts -> Ok opts { optDynuFile = Just f }) "FILE")
- "Import dynamic utilisation data from the given FILE"
+oNoHeaders :: OptType
+oNoHeaders = Option "" ["no-headers"]
+ (NoArg (\ opts -> Ok opts { optNoHeaders = True }))
+ "do not show a header line"
-oExTags :: OptType
-oExTags = Option "" ["exclusion-tags"]
- (ReqArg (\ f opts -> Ok opts { optExTags = Just $ sepSplit ',' f })
- "TAG,...") "Enable instance exclusion based on given tag prefix"
+oNodeSim :: OptType
+oNodeSim = Option "" ["simulate"]
+ (ReqArg (\ f o -> Ok o { optNodeSim = Just f }) "SPEC")
+ "simulate an empty cluster, given as 'num_nodes,disk,ram,cpu'"
+
+oOfflineNode :: OptType
+oOfflineNode = Option "O" ["offline"]
+ (ReqArg (\ n o -> Ok o { optOffline = n:optOffline o }) "NODE")
+ "set node as offline"
+
+oOneline :: OptType
+oOneline = Option "o" ["oneline"]
+ (NoArg (\ opts -> Ok opts { optOneline = True }))
+ "print the ganeti command list for reaching the solution"
+
+oOutputDir :: OptType
+oOutputDir = Option "d" ["output-dir"]
+ (ReqArg (\ d opts -> Ok opts { optOutPath = d }) "PATH")
+ "directory in which to write output files"
+
+oPrintCommands :: OptType
+oPrintCommands = Option "C" ["print-commands"]
+ (OptArg ((\ f opts -> Ok 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"
+
+oPrintInsts :: OptType
+oPrintInsts = Option "" ["print-instances"]
+ (NoArg (\ opts -> Ok opts { optShowInsts = True }))
+ "print the final instance map"
+
+oPrintNodes :: OptType
+oPrintNodes = Option "p" ["print-nodes"]
+ (OptArg ((\ f opts ->
+ let splitted = sepSplit ',' f
+ in Ok opts { optShowNodes = Just splitted }) .
+ fromMaybe []) "FIELDS")
+ "print the final node list"
+
+oQuiet :: OptType
+oQuiet = Option "q" ["quiet"]
+ (NoArg (\ opts -> Ok opts { optVerbose = optVerbose opts - 1 }))
+ "decrease the verbosity level"
+
+oRapiMaster :: OptType
+oRapiMaster = Option "m" ["master"]
+ (ReqArg (\ m opts -> Ok opts { optMaster = m }) "ADDRESS")
+ "collect data via RAPI at the given ADDRESS"
+
+oShowHelp :: OptType
+oShowHelp = Option "h" ["help"]
+ (NoArg (\ opts -> Ok opts { optShowHelp = True}))
+ "show help"
+
+oShowVer :: OptType
+oShowVer = Option "V" ["version"]
+ (NoArg (\ opts -> Ok opts { optShowVer = True}))
+ "show the version of the program"
oTieredSpec :: OptType
oTieredSpec = Option "" ["tiered-alloc"]
"TSPEC")
"enable tiered specs allocation, given as 'disk,ram,cpu'"
-oShowVer :: OptType
-oShowVer = Option "V" ["version"]
- (NoArg (\ opts -> Ok opts { optShowVer = True}))
- "show the version of the program"
-
-oShowHelp :: OptType
-oShowHelp = Option "h" ["help"]
- (NoArg (\ opts -> Ok opts { optShowHelp = True}))
- "show help"
+oVerbose :: OptType
+oVerbose = Option "v" ["verbose"]
+ (NoArg (\ opts -> Ok opts { optVerbose = optVerbose opts + 1 }))
+ "increase the verbosity level"
-- | Usage info
usageHelp :: String -> [OptType] -> String