avoid-disk-moves=*FACTOR* option was introduced in the "Migration speed
accounting in Hbal" design document. This option will admit disk moves
only if the gain in the cluster metrics is FACTOR times higher than the
gain achievable by non disk moves.

Signed-off-by: Oleg Ponomarev <[email protected]>
---
 src/Ganeti/HTools/AlgorithmParams.hs |  4 ++++
 src/Ganeti/HTools/CLI.hs             | 13 +++++++++++++
 src/Ganeti/HTools/Cluster.hs         | 26 +++++++++++++++++++++-----
 src/Ganeti/HTools/Program/Hbal.hs    |  1 +
 src/Ganeti/HTools/Program/Hcheck.hs  |  1 +
 5 files changed, 40 insertions(+), 5 deletions(-)

diff --git a/src/Ganeti/HTools/AlgorithmParams.hs 
b/src/Ganeti/HTools/AlgorithmParams.hs
index 8531458..2bbfda1 100644
--- a/src/Ganeti/HTools/AlgorithmParams.hs
+++ b/src/Ganeti/HTools/AlgorithmParams.hs
@@ -45,6 +45,9 @@ import qualified Ganeti.HTools.CLI as CLI
 
 data AlgorithmOptions = AlgorithmOptions
   { algDiskMoves :: Bool            -- ^ Whether disk moves are allowed
+  , algDiskMovesFactor :: Double    -- ^ Allow only disk moves improving
+                                    -- cluster score in more than
+                                    -- algDiskMoves times
   , algInstanceMoves :: Bool        -- ^ Whether instance moves are allowed
   , algRestrictedMigration :: Bool  -- ^ Whether migration is restricted
   , algIgnoreSoftErrors :: Bool     -- ^ Whether to always ignore soft errors
@@ -60,6 +63,7 @@ data AlgorithmOptions = AlgorithmOptions
 fromCLIOptions :: CLI.Options -> AlgorithmOptions
 fromCLIOptions opts = AlgorithmOptions
   { algDiskMoves = CLI.optDiskMoves opts
+  , algDiskMovesFactor = CLI.optAvoidDiskMoves opts
   , algInstanceMoves = CLI.optInstMoves opts
   , algRestrictedMigration = CLI.optRestrictedMigrate opts
   , algIgnoreSoftErrors = CLI.optIgnoreSoftErrors opts
diff --git a/src/Ganeti/HTools/CLI.hs b/src/Ganeti/HTools/CLI.hs
index bf291d7..bcdded6 100644
--- a/src/Ganeti/HTools/CLI.hs
+++ b/src/Ganeti/HTools/CLI.hs
@@ -55,6 +55,7 @@ module Ganeti.HTools.CLI
   -- * The options
   , oDataFile
   , oDiskMoves
+  , oAvoidDiskMoves
   , oDiskTemplate
   , oSpindleUse
   , oDynuFile
@@ -142,6 +143,9 @@ import Ganeti.Utils
 data Options = Options
   { optDataFile    :: Maybe FilePath -- ^ Path to the cluster data file
   , optDiskMoves   :: Bool           -- ^ Allow disk moves
+  , optAvoidDiskMoves :: Double      -- ^ Allow only disk moves improving
+                                     -- cluster score in more than
+                                     -- optAvoidDiskMoves times
   , optInstMoves   :: Bool           -- ^ Allow instance moves
   , optDiskTemplate :: Maybe DiskTemplate  -- ^ Override for the disk template
   , optSpindleUse  :: Maybe Int      -- ^ Override for the spindle usage
@@ -216,6 +220,7 @@ defaultOptions :: Options
 defaultOptions  = Options
   { optDataFile    = Nothing
   , optDiskMoves   = True
+  , optAvoidDiskMoves = 1.0
   , optInstMoves   = True
   , optIndependentGroups = False
   , optAcceptExisting = False
@@ -337,6 +342,14 @@ oDiskMoves =
    \ thus allowing only the 'cheap' failover/migrate operations",
    OptComplNone)
 
+oAvoidDiskMoves :: OptType
+oAvoidDiskMoves =
+  (Option "" ["avoid-disk-moves"]
+   (reqWithConversion (tryRead "disk moves avoiding factor")
+    (\f opts -> Ok opts { optAvoidDiskMoves = f }) "FACTOR")
+   "minimal cluster metrics improvement FACTOR required to admit disk moves",
+   OptComplFloat)
+
 oMonD :: OptType
 oMonD =
   (Option "" ["mond"]
diff --git a/src/Ganeti/HTools/Cluster.hs b/src/Ganeti/HTools/Cluster.hs
index 98b4731..a0acd95 100644
--- a/src/Ganeti/HTools/Cluster.hs
+++ b/src/Ganeti/HTools/Cluster.hs
@@ -308,6 +308,17 @@ getOnline = filter (not . Node.offline) . Container.elems
 
 -- * Balancing functions
 
+-- | Check if move is allowed in terms of avoid disk moves factor
+isMoveAllowed :: IMove  -- ^ Move to check
+              -> Double -- ^ Avoid disk moves factor (see algDiskMovesFactor)
+              -> Table  -- ^ The original table
+              -> Table  -- ^ The final table
+              -> Bool   -- ^ Is move allowd or not
+isMoveAllowed Failover _ _ _ = True -- No disk moves in this case.
+isMoveAllowed _ factor (Table _ _ a_cv _) (Table _ _ b_cv _) =
+  a_cv > b_cv * factor
+-- Disk move is allowed it results in score that is factor times lower.
+
 -- | Compute best table. Note that the ordering of the arguments is important.
 compareTables :: Table -> Table -> Table
 compareTables a@(Table _ _ a_cv _) b@(Table _ _ b_cv _ ) =
@@ -316,12 +327,13 @@ compareTables a@(Table _ _ a_cv _) b@(Table _ _ b_cv _ ) =
 -- | Tries to perform an instance move and returns the best table
 -- between the original one and the new one.
 checkSingleStep :: Bool -- ^ Whether to unconditionally ignore soft errors
+                -> Double -- ^ avoid disk moves factor (see algDiskMovesFactor)
                 -> Table -- ^ The original table
                 -> Instance.Instance -- ^ The instance to move
                 -> Table -- ^ The current best table
                 -> IMove -- ^ The move to apply
                 -> Table -- ^ The final best table
-checkSingleStep force ini_tbl target cur_tbl move =
+checkSingleStep force disk_move_factor ini_tbl target cur_tbl move =
   let Table ini_nl ini_il _ ini_plc = ini_tbl
       tmp_resu = applyMoveEx force ini_nl target move
   in case tmp_resu of
@@ -332,7 +344,9 @@ checkSingleStep force ini_tbl target cur_tbl move =
              upd_il = Container.add tgt_idx new_inst ini_il
              upd_plc = (tgt_idx, pri_idx, sec_idx, move, upd_cvar):ini_plc
              upd_tbl = Table upd_nl upd_il upd_cvar upd_plc
-         in compareTables cur_tbl upd_tbl
+         in if isMoveAllowed move disk_move_factor cur_tbl upd_tbl
+              then compareTables cur_tbl upd_tbl
+              else cur_tbl
 
 -- | Given the status of the current secondary as a valid new node and
 -- the current candidate target node, generate the possible moves for
@@ -386,6 +400,7 @@ checkInstanceMove ::  AlgorithmOptions -- ^ Algorithmic 
options for balancing
 checkInstanceMove opts nodes_idx ini_tbl@(Table nl _ _ _) target =
   let force = algIgnoreSoftErrors opts
       disk_moves = algDiskMoves opts
+      disk_moves_factor = algDiskMovesFactor opts
       inst_moves = algInstanceMoves opts
       rest_mig = algRestrictedMigration opts
       opdx = Instance.pNode target
@@ -396,8 +411,8 @@ checkInstanceMove opts nodes_idx ini_tbl@(Table nl _ _ _) 
target =
       use_secondary = elem osdx nodes_idx && inst_moves
       aft_failover = if mir_type == MirrorInternal && use_secondary
                        -- if drbd and allowed to failover
-                       then checkSingleStep force ini_tbl target ini_tbl
-                              Failover
+                       then checkSingleStep force disk_moves_factor ini_tbl
+                              target ini_tbl Failover
                        else ini_tbl
       primary_drained = Node.offline
                         . flip Container.find nl
@@ -410,7 +425,8 @@ checkInstanceMove opts nodes_idx ini_tbl@(Table nl _ _ _) 
target =
           else []
     in
       -- iterate over the possible nodes for this instance
-      foldl' (checkSingleStep force ini_tbl target) aft_failover all_moves
+      foldl' (checkSingleStep force disk_moves_factor ini_tbl target)
+        aft_failover all_moves
 
 -- | Compute the best next move.
 checkMove :: AlgorithmOptions       -- ^ Algorithmic options for balancing
diff --git a/src/Ganeti/HTools/Program/Hbal.hs 
b/src/Ganeti/HTools/Program/Hbal.hs
index 084433a..21b9e03 100644
--- a/src/Ganeti/HTools/Program/Hbal.hs
+++ b/src/Ganeti/HTools/Program/Hbal.hs
@@ -101,6 +101,7 @@ options = do
     , oMinGain
     , oMinGainLim
     , oDiskMoves
+    , oAvoidDiskMoves
     , oSelInst
     , oInstMoves
     , oIgnoreSoftErrors
diff --git a/src/Ganeti/HTools/Program/Hcheck.hs 
b/src/Ganeti/HTools/Program/Hcheck.hs
index a2251ff..4bf4401 100644
--- a/src/Ganeti/HTools/Program/Hcheck.hs
+++ b/src/Ganeti/HTools/Program/Hcheck.hs
@@ -70,6 +70,7 @@ options = do
   return
     [ oDataFile
     , oDiskMoves
+    , oAvoidDiskMoves
     , oDynuFile
     , oIgnoreDyn
     , oEvacMode
-- 
1.9.1

Reply via email to