Add checks for missing disk space
[ganeti-local] / Ganeti / HTools / Cluster.hs
index 3dc52d2..c64f9df 100644 (file)
@@ -32,6 +32,7 @@ module Ganeti.HTools.Cluster
     , printStats
     -- * Loading functions
     , loadData
+    , checkData
     ) where
 
 import Data.List
@@ -642,8 +643,10 @@ printNodes ktn nl =
         snl' = map (\ n -> ((fromJust $ lookup (Node.idx n) ktn), n)) snl
         m_name = maximum . (map length) . fst . unzip $ snl'
         helper = Node.list m_name
-        header = printf "%2s %-*s %5s %5s %5s %5s %5s %5s %3s %3s %7s %7s"
-                 " F" m_name "Name" "t_mem" "n_mem" "f_mem" "r_mem"
+        header = printf
+                 "%2s %-*s %5s %5s %5s %5s %5s %5s %5s %5s %3s %3s %7s %7s"
+                 " F" m_name "Name"
+                 "t_mem" "n_mem" "i_mem" "x_mem" "f_mem" "r_mem"
                  "t_dsk" "f_dsk"
                  "pri" "sec" "p_fmem" "p_fdsk"
     in unlines $ (header:map (uncurry helper) snl')
@@ -757,11 +760,12 @@ loadData ndata idata =
                           Node.create (read tm) (read nm)
                                   (read fm) (read td) (read fd)))
                     Node.setIdx
-    {- instance file: name mem disk pnode snode -}
+    {- instance file: name mem disk status pnode snode -}
         (kti, il) = loadTabular idata
-                    (\ (name:mem:dsk:pnode:snode:[]) ->
+                    (\ (name:mem:dsk:status:pnode:snode:[]) ->
                          (name,
                           Instance.create (read mem) (read dsk)
+                              status
                               (fromJust $ lookup pnode ktn)
                               (fromJust $ lookup snode ktn)))
                     Instance.setIdx
@@ -776,3 +780,47 @@ loadData ndata idata =
         sti = stripSuffix common_suffix xti
     in
       (nl3, il3, common_suffix, stn, sti)
+
+-- | Compute the amount of memory used by primary instances on a node.
+nodeImem :: Node.Node -> InstanceList -> Int
+nodeImem node il =
+    let rfind = flip Container.find $ il
+    in sum . map Instance.mem .
+       map rfind $ Node.plist node
+
+-- | Compute the amount of disk used by instances on a node (either primary
+-- or secondary).
+nodeIdsk :: Node.Node -> InstanceList -> Int
+nodeIdsk node il =
+    let rfind = flip Container.find $ il
+    in sum . map Instance.dsk .
+       map rfind $ (Node.plist node) ++ (Node.slist node)
+
+
+-- | Check cluster data for consistency
+checkData :: NodeList -> InstanceList -> NameList -> NameList
+          -> ([String], NodeList)
+checkData nl il ktn _ =
+    Container.mapAccum
+        (\ msgs node ->
+             let nname = fromJust $ lookup (Node.idx node) ktn
+                 nilst = map (flip Container.find $ il) (Node.plist node)
+                 dilst = filter (not . Instance.running) nilst
+                 adj_mem = sum . map Instance.mem $ dilst
+                 delta_mem = (truncate $ Node.t_mem node)
+                             - (Node.n_mem node)
+                             - (Node.f_mem node)
+                             - (nodeImem node il)
+                             + adj_mem
+                 delta_dsk = (truncate $ Node.t_dsk node)
+                             - (Node.f_dsk node)
+                             - (nodeIdsk node il)
+                 newn = Node.setFmem (Node.setXmem node delta_mem)
+                        (Node.f_mem node - adj_mem)
+                 umsg1 = if delta_mem > 16 || delta_dsk > 1024
+                         then [printf "node %s is missing %d MB ram \
+                                     \and %d GB disk"
+                                     nname delta_mem (delta_dsk `div` 1024)]
+                         else []
+             in (msgs ++ umsg1, newn)
+        ) [] nl