Implement cpu/disk limits in instance moves
[ganeti-local] / Ganeti / HTools / Node.hs
index 2a8ee17..c9df51b 100644 (file)
@@ -26,8 +26,11 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
 -}
 
 module Ganeti.HTools.Node
-    ( Node(failN1, name, idx, t_mem, n_mem, f_mem, r_mem, t_dsk, f_dsk,
-           p_mem, p_dsk, p_rem,
+    ( Node(failN1, name, idx, t_mem, n_mem, f_mem, r_mem,
+           t_dsk, f_dsk,
+           t_cpu, u_cpu,
+           p_mem, p_dsk, p_rem, p_cpu,
+           m_dsk, m_cpu,
            plist, slist, offline)
     , List
     -- * Constructor
@@ -41,6 +44,9 @@ module Ganeti.HTools.Node
     , setFmem
     , setPri
     , setSec
+    , setMdsk
+    , setMcpu
+    , addCpus
     -- * Instance (re)location
     , removePri
     , removeSec
@@ -72,6 +78,8 @@ data Node = Node { name  :: String -- ^ The node name
                  , x_mem :: Int    -- ^ Unaccounted memory (MiB)
                  , t_dsk :: Double -- ^ Total disk space (MiB)
                  , f_dsk :: Int    -- ^ Free disk space (MiB)
+                 , t_cpu :: Double -- ^ Total CPU count
+                 , u_cpu :: Int    -- ^ Used VCPU count
                  , plist :: [T.Idx]-- ^ List of primary instance indices
                  , slist :: [T.Idx]-- ^ List of secondary instance indices
                  , idx :: T.Ndx    -- ^ Internal index for book-keeping
@@ -82,6 +90,9 @@ data Node = Node { name  :: String -- ^ The node name
                  , p_mem :: Double -- ^ Percent of free memory
                  , p_dsk :: Double -- ^ Percent of free disk
                  , p_rem :: Double -- ^ Percent of reserved memory
+                 , p_cpu :: Double -- ^ Ratio of virtual to physical CPUs
+                 , m_dsk :: Double -- ^ Minimum free disk ratio
+                 , m_cpu :: Double -- ^ Max ratio of virt-to-phys CPUs
                  , offline :: Bool -- ^ Whether the node should not be used
                                    -- for allocations and skipped from
                                    -- score computations
@@ -103,15 +114,20 @@ type List = Container.Container Node
 noSecondary :: T.Ndx
 noSecondary = -1
 
+-- | No limit value
+noLimit :: Double
+noLimit = -1
+
 -- * Initialization functions
 
 -- | Create a new node.
 --
 -- The index and the peers maps are empty, and will be need to be
 -- update later via the 'setIdx' and 'buildPeers' functions.
-create :: String -> Double -> Int -> Int -> Double -> Int -> Bool -> Node
+create :: String -> Double -> Int -> Int -> Double
+       -> Int -> Double -> Bool -> Node
 create name_init mem_t_init mem_n_init mem_f_init
-       dsk_t_init dsk_f_init offline_init =
+       dsk_t_init dsk_f_init cpu_t_init offline_init =
     Node
     {
       name  = name_init,
@@ -120,6 +136,8 @@ create name_init mem_t_init mem_n_init mem_f_init
       f_mem = mem_f_init,
       t_dsk = dsk_t_init,
       f_dsk = dsk_f_init,
+      t_cpu = cpu_t_init,
+      u_cpu = 0,
       plist = [],
       slist = [],
       failN1 = True,
@@ -129,8 +147,11 @@ create name_init mem_t_init mem_n_init mem_f_init
       p_mem = (fromIntegral mem_f_init) / mem_t_init,
       p_dsk = (fromIntegral dsk_f_init) / dsk_t_init,
       p_rem = 0,
+      p_cpu = 0,
       offline = offline_init,
-      x_mem = 0
+      x_mem = 0,
+      m_dsk = noLimit,
+      m_cpu = noLimit
     }
 
 -- | Changes the index.
@@ -153,6 +174,14 @@ setOffline t val = t { offline = val }
 setXmem :: Node -> Int -> Node
 setXmem t val = t { x_mem = val }
 
+-- | Sets the max disk usage ratio
+setMdsk :: Node -> Double -> Node
+setMdsk t val = t { m_dsk = val }
+
+-- | Sets the max cpu usage ratio
+setMcpu :: Node -> Double -> Node
+setMcpu t val = t { m_cpu = val }
+
 -- | Computes the maximum reserved memory for peers from a peer map.
 computeMaxRes :: PeerMap.PeerMap -> PeerMap.Elem
 computeMaxRes new_peers = PeerMap.maxElem new_peers
@@ -178,6 +207,12 @@ setPri t idx = t { plist = idx:(plist t) }
 setSec :: Node -> T.Idx -> Node
 setSec t idx = t { slist = idx:(slist t) }
 
+-- | Add primary cpus to a node
+addCpus :: Node -> Int -> Node
+addCpus t count =
+    let new_count = (u_cpu t) + count
+    in t { u_cpu = new_count, p_cpu = (fromIntegral new_count) / (t_cpu t) }
+
 -- * Update functions
 
 -- | Sets the free memory.
@@ -197,6 +232,13 @@ computeFailN1 new_rmem new_mem new_dsk =
 failHealth :: Int -> Int -> Bool
 failHealth new_mem new_dsk = new_mem <= 0 || new_dsk <= 0
 
+-- | Given new limits, check if any of them are overtaken
+failLimits :: Node -> Double -> Double -> Bool
+failLimits t new_dsk new_cpu =
+    let l_dsk = m_dsk t
+        l_cpu = m_cpu t
+    in (l_dsk > new_dsk) || (l_cpu >= 0 && l_cpu < new_cpu)
+
 -- | Removes a primary instance.
 removePri :: Node -> Instance.Instance -> Node
 removePri t inst =
@@ -207,8 +249,11 @@ removePri t inst =
         new_mp = (fromIntegral new_mem) / (t_mem t)
         new_dp = (fromIntegral new_dsk) / (t_dsk t)
         new_failn1 = computeFailN1 (r_mem t) new_mem new_dsk
+        new_ucpu = (u_cpu t) - (Instance.vcpus inst)
+        new_rcpu = (fromIntegral new_ucpu) / (t_cpu t)
     in t {plist = new_plist, f_mem = new_mem, f_dsk = new_dsk,
-          failN1 = new_failn1, p_mem = new_mp, p_dsk = new_dp}
+          failN1 = new_failn1, p_mem = new_mp, p_dsk = new_dp,
+          u_cpu = new_ucpu, p_cpu = new_rcpu}
 
 -- | Removes a secondary instance.
 removeSec :: Node -> Instance.Instance -> Node
@@ -239,16 +284,22 @@ addPri t inst =
     let iname = Instance.idx inst
         new_mem = f_mem t - Instance.mem inst
         new_dsk = f_dsk t - Instance.dsk inst
-        new_failn1 = computeFailN1 (r_mem t) new_mem new_dsk in
-      if (failHealth new_mem new_dsk) || (new_failn1 && not (failN1 t)) then
+        new_failn1 = computeFailN1 (r_mem t) new_mem new_dsk
+        new_ucpu = (u_cpu t) + (Instance.vcpus inst)
+        new_pcpu = (fromIntegral new_ucpu) / (t_cpu t)
+        new_dp = (fromIntegral new_dsk) / (t_dsk t)
+    in
+      if (failHealth new_mem new_dsk) || (new_failn1 && not (failN1 t)) ||
+         (failLimits t new_dp new_pcpu)
+      then
         Nothing
       else
         let new_plist = iname:(plist t)
             new_mp = (fromIntegral new_mem) / (t_mem t)
-            new_dp = (fromIntegral new_dsk) / (t_dsk t)
         in
         Just t {plist = new_plist, f_mem = new_mem, f_dsk = new_dsk,
-                failN1 = new_failn1, p_mem = new_mp, p_dsk = new_dp}
+                failN1 = new_failn1, p_mem = new_mp, p_dsk = new_dp,
+                u_cpu = new_ucpu, p_cpu = new_pcpu}
 
 -- | Adds a secondary instance.
 addSec :: Node -> Instance.Instance -> T.Ndx -> Maybe Node
@@ -261,27 +312,30 @@ addSec t inst pdx =
         new_peers = PeerMap.add pdx new_peem old_peers
         new_rmem = max (r_mem t) new_peem
         new_prem = (fromIntegral new_rmem) / (t_mem t)
-        new_failn1 = computeFailN1 new_rmem old_mem new_dsk in
-    if (failHealth old_mem new_dsk) || (new_failn1 && not (failN1 t)) then
-        Nothing
-    else
-        let new_slist = iname:(slist t)
-            new_dp = (fromIntegral new_dsk) / (t_dsk t)
-        in
-        Just t {slist = new_slist, f_dsk = new_dsk,
-                peers = new_peers, failN1 = new_failn1,
-                r_mem = new_rmem, p_dsk = new_dp,
-                p_rem = new_prem}
+        new_failn1 = computeFailN1 new_rmem old_mem new_dsk
+        new_dp = (fromIntegral new_dsk) / (t_dsk t)
+    in if (failHealth old_mem new_dsk) || (new_failn1 && not (failN1 t)) ||
+          (failLimits t new_dp noLimit)
+       then
+           Nothing
+       else
+           let new_slist = iname:(slist t)
+           in
+             Just t {slist = new_slist, f_dsk = new_dsk,
+                     peers = new_peers, failN1 = new_failn1,
+                     r_mem = new_rmem, p_dsk = new_dp,
+                     p_rem = new_prem}
 
 -- * Display functions
 
 -- | String converter for the node list functionality.
 list :: Int -> Node -> String
 list mname t =
-    let pl = plist t
-        sl = slist t
+    let pl = length $ plist t
+        sl = length $ slist t
         mp = p_mem t
         dp = p_dsk t
+        cp = p_cpu t
         off = offline t
         fn = failN1 t
         tmem = t_mem t
@@ -290,9 +344,14 @@ list mname t =
         fmem = f_mem t
         imem = (truncate tmem) - nmem - xmem - fmem
     in
-      printf " %c %-*s %5.0f %5d %5d %5d %5d %5d %5.0f %5d %3d %3d %.5f %.5f"
+      if off
+         then printf " - %-*s %57s %3d %3d"
+              mname (name t) "" pl sl
+         else
+             printf " %c %-*s %5.0f %5d %5d %5d %5d %5d %5.0f %5d\
+                    \ %4.0f %4d %3d %3d %6.4f %6.4f %5.2f"
                  (if off then '-' else if fn then '*' else ' ')
                  mname (name t) tmem nmem imem xmem fmem (r_mem t)
                  ((t_dsk t) / 1024) ((f_dsk t) `div` 1024)
-                 (length pl) (length sl)
-                 mp dp
+                 (t_cpu t) (u_cpu t)
+                 pl sl mp dp cp