hbal: Implement grouping of moves into jobsets
[ganeti-local] / Ganeti / HTools / CLI.hs
index c859784..e53e080 100644 (file)
@@ -31,10 +31,7 @@ module Ganeti.HTools.CLI
     ( Options(..)
     , OptType
     , parseOpts
-    , parseEnv
     , shTemplate
-    , loadExternalData
-    , defaultLuxiSocket
     -- * The options
     , oPrintNodes
     , oPrintCommands
@@ -43,6 +40,7 @@ module Ganeti.HTools.CLI
     , oOutputDir
     , oNodeFile
     , oInstFile
+    , oNodeSim
     , oRapiMaster
     , oLuxiSocket
     , oMaxSolLength
@@ -56,31 +54,23 @@ module Ganeti.HTools.CLI
     , oINodes
     , oMaxCpu
     , oMinDisk
+    , oDiskMoves
     , oShowVer
     , oShowHelp
     ) where
 
-import Data.Maybe (isJust, fromJust, fromMaybe)
+import Data.Maybe (fromMaybe)
 import qualified Data.Version
 import Monad
 import System.Console.GetOpt
-import System.Posix.Env
 import System.IO
 import System.Info
 import System
-import Text.Printf (printf, hPrintf)
+import Text.Printf (printf)
 
 import qualified Ganeti.HTools.Version as Version(version)
-import qualified Ganeti.HTools.Luxi as Luxi
-import qualified Ganeti.HTools.Rapi as Rapi
-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
-
 -- | The default value for the luxi socket
 defaultLuxiSocket :: FilePath
 defaultLuxiSocket = "/var/run/ganeti/socket/ganeti-master"
@@ -96,6 +86,7 @@ data Options = Options
     , 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
+    , 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
@@ -107,6 +98,7 @@ data Options = Options
     , optMinScore  :: Cluster.Score  -- ^ The minimum score we aim for
     , optMcpu      :: Double         -- ^ Max cpu ratio for nodes
     , optMdsk      :: Double         -- ^ Max disk usage ratio for nodes
+    , optDiskMoves :: Bool           -- ^ Allow disk moves
     , optVerbose   :: Int            -- ^ Verbosity level
     , optShowVer   :: Bool           -- ^ Just show the program version
     , optShowHelp  :: Bool           -- ^ Just show the help
@@ -124,6 +116,7 @@ defaultOptions  = Options
  , optNodeSet   = False
  , optInstFile  = "instances"
  , optInstSet   = False
+ , optNodeSim   = Nothing
  , optMaxLength = -1
  , optMaster    = ""
  , optLuxi      = Nothing
@@ -135,6 +128,7 @@ defaultOptions  = Options
  , optMinScore  = 1e-9
  , optMcpu      = -1
  , optMdsk      = -1
+ , optDiskMoves = True
  , optVerbose   = 1
  , optShowVer   = False
  , optShowHelp  = False
@@ -182,6 +176,11 @@ oInstFile = Option "i" ["instances"]
             (ReqArg (\ f o -> o { optInstFile = f, optInstSet = True }) "FILE")
             "the instance list FILE"
 
+oNodeSim :: OptType
+oNodeSim = Option "" ["simulate"]
+            (ReqArg (\ f o -> 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")
@@ -249,6 +248,12 @@ oMinDisk = Option "" ["min-disk"]
            (ReqArg (\ n opts -> 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}))
+             "disallow disk moves from the list of allowed instance changes,\
+             \ thus allowing only the 'cheap' failover/migrate operations"
+
 oShowVer :: OptType
 oShowVer = Option "V" ["version"]
            (NoArg (\ opts -> opts { optShowVer = True}))
@@ -286,17 +291,10 @@ parseOpts argv progname options =
                      os arch
               exitWith ExitSuccess
             return resu
-      (_, _, errs) ->
-          ioError (userError (concat errs ++ usageHelp progname options))
-
--- | Parse the environment and return the node\/instance names.
---
--- This also hardcodes here the default node\/instance file names.
-parseEnv :: () -> IO (String, String)
-parseEnv () = do
-  a <- getEnvDefault "HTOOLS_NODES" "nodes"
-  b <- getEnvDefault "HTOOLS_INSTANCES" "instances"
-  return (a, b)
+      (_, _, errs) -> do
+        hPutStrLn stderr $ "Command line error: "  ++ concat errs
+        hPutStrLn stderr $ usageHelp progname options
+        exitWith $ ExitFailure 2
 
 -- | A shell script template for autogenerated scripts.
 shTemplate :: String
@@ -311,46 +309,3 @@ shTemplate =
            \    exit 0\n\
            \  fi\n\
            \}\n\n"
-
--- | External tool data loader from a variety of sources.
-loadExternalData :: Options
-                 -> IO (Node.List, Instance.List, String)
-loadExternalData opts = do
-  (env_node, env_inst) <- parseEnv ()
-  let nodef = if optNodeSet opts then optNodeFile opts
-              else env_node
-      instf = if optInstSet opts then optInstFile opts
-              else env_inst
-      mhost = optMaster opts
-      lsock = optLuxi opts
-      setRapi = mhost /= ""
-      setLuxi = isJust lsock
-      setFiles = optNodeSet opts || optInstSet opts
-      allSet = filter id [setRapi, setLuxi, setFiles]
-  when (length allSet > 1) $
-       do
-         hPutStrLn stderr "Error: Only one of the rapi, luxi, and data\
-                          \ files options should be given."
-         exitWith $ ExitFailure 1
-
-  input_data <-
-      case () of
-        _ | mhost /= "" -> Rapi.loadData mhost
-          | isJust lsock -> Luxi.loadData $ fromJust lsock
-          | otherwise -> Text.loadData nodef instf
-
-  let ldresult = input_data >>= Loader.mergeData
-  (loaded_nl, il, csf) <-
-      (case ldresult of
-         Ok x -> return x
-         Bad s -> do
-           hPrintf stderr "Error: failed to load data. Details:\n%s\n" s
-           exitWith $ ExitFailure 1
-      )
-  let (fix_msgs, fixed_nl) = Loader.checkData loaded_nl il
-
-  unless (null fix_msgs || optVerbose opts == 0) $ do
-         hPutStrLn stderr "Warning: cluster has inconsistent data:"
-         hPutStrLn stderr . unlines . map (printf "  - %s") $ fix_msgs
-
-  return (fixed_nl, il, csf)