commit 8bc34c7b62c0eb5fbbad70e0e8f19b011b346db2
Author: Iustin Pop <iustin@google.com>
Date:   Thu Feb 16 12:52:54 2012 +0100

    htools: add spindle-related attribute to nodes
    
    This adds the spindleCount, hiSpindles and instSpindles attributes.
    
    The spindleCount is equivalent to spindle_count on the ganeti side (a
    node parameter). hiSpindles is the maximum instance-used spindles, and
    instSpindles will be used to track spindles as used by instances (in
    later patches).
    
    The patch also reads spindleCount from the live backends. The text and
    simu backends currently set it to 1, hard-coded.
    
    Signed-off-by: Iustin Pop <iustin@google.com>
    Reviewed-by: René Nussbaumer <rn@google.com>

diff --git a/htools/Ganeti/HTools/IAlloc.hs b/htools/Ganeti/HTools/IAlloc.hs
index aa8a39c..9ccc8ec 100644
--- a/htools/Ganeti/HTools/IAlloc.hs
+++ b/htools/Ganeti/HTools/IAlloc.hs
@@ -4,7 +4,7 @@
 
 {-
 
-Copyright (C) 2009, 2010, 2011 Google Inc.
+Copyright (C) 2009, 2010, 2011, 2012 Google Inc.
 
 This program is free software; you can redistribute it and/or modify
 it under the terms of the GNU General Public License as published by
@@ -105,7 +105,7 @@ parseNode ktg n a = do
   let vm_capable' = fromMaybe True vm_capable
   gidx <- lookupGroup ktg n guuid
   node <- if offline || drained || not vm_capable'
-            then return $ Node.create n 0 0 0 0 0 0 True gidx
+            then return $ Node.create n 0 0 0 0 0 0 True 0 gidx
             else do
               mtotal <- extract "total_memory"
               mnode  <- extract "reserved_memory"
@@ -113,8 +113,11 @@ parseNode ktg n a = do
               dtotal <- extract "total_disk"
               dfree  <- extract "free_disk"
               ctotal <- extract "total_cpus"
+              ndparams <- extract "ndparams" >>= asJSObject
+              spindles <- tryFromObj desc (fromJSObject ndparams)
+                          "spindle_count"
               return $ Node.create n mtotal mnode mfree
-                     dtotal dfree ctotal False gidx
+                     dtotal dfree ctotal False spindles gidx
   return (n, node)
 
 -- | Parses a group as found in the cluster group list.
diff --git a/htools/Ganeti/HTools/Luxi.hs b/htools/Ganeti/HTools/Luxi.hs
index cd80996..77d5614 100644
--- a/htools/Ganeti/HTools/Luxi.hs
+++ b/htools/Ganeti/HTools/Luxi.hs
@@ -4,7 +4,7 @@
 
 {-
 
-Copyright (C) 2009, 2010, 2011 Google Inc.
+Copyright (C) 2009, 2010, 2011, 2012 Google Inc.
 
 This program is free software; you can redistribute it and/or modify
 it under the terms of the GNU General Public License as published by
@@ -99,7 +99,7 @@ queryNodesMsg :: L.LuxiOp
 queryNodesMsg =
   L.Query L.QRNode ["name", "mtotal", "mnode", "mfree", "dtotal", "dfree",
                     "ctotal", "offline", "drained", "vm_capable",
-                    "group.uuid"] ()
+                    "ndp/spindle_count", "group.uuid"] ()
 
 -- | The input data for instance query.
 queryInstancesMsg :: L.LuxiOp
@@ -175,16 +175,17 @@ getNodes ktg arr = extractArray arr >>= mapM (parseNode ktg)
 -- | Construct a node from a JSON object.
 parseNode :: NameAssoc -> [(JSValue, JSValue)] -> Result (String, Node.Node)
 parseNode ktg [ name, mtotal, mnode, mfree, dtotal, dfree
-              , ctotal, offline, drained, vm_capable, g_uuid ]
+              , ctotal, offline, drained, vm_capable, spindles, g_uuid ]
     = do
   xname <- annotateResult "Parsing new node" (fromJValWithStatus name)
   let convert a = genericConvert "Node" xname a
   xoffline <- convert "offline" offline
   xdrained <- convert "drained" drained
   xvm_capable <- convert "vm_capable" vm_capable
+  xspindles <- convert "spindles" spindles
   xgdx   <- convert "group.uuid" g_uuid >>= lookupGroup ktg xname
   node <- if xoffline || xdrained || not xvm_capable
-            then return $ Node.create xname 0 0 0 0 0 0 True xgdx
+            then return $ Node.create xname 0 0 0 0 0 0 True xspindles xgdx
             else do
               xmtotal  <- convert "mtotal" mtotal
               xmnode   <- convert "mnode" mnode
@@ -193,7 +194,7 @@ parseNode ktg [ name, mtotal, mnode, mfree, dtotal, dfree
               xdfree   <- convert "dfree" dfree
               xctotal  <- convert "ctotal" ctotal
               return $ Node.create xname xmtotal xmnode xmfree
-                     xdtotal xdfree xctotal False xgdx
+                     xdtotal xdfree xctotal False xspindles xgdx
   return (xname, node)
 
 parseNode _ v = fail ("Invalid node query result: " ++ show v)
diff --git a/htools/Ganeti/HTools/Node.hs b/htools/Ganeti/HTools/Node.hs
index 0f686c0..c117a6a 100644
--- a/htools/Ganeti/HTools/Node.hs
+++ b/htools/Ganeti/HTools/Node.hs
@@ -101,6 +101,7 @@ data Node = Node
   , fDsk     :: Int       -- ^ Free disk space (MiB)
   , tCpu     :: Double    -- ^ Total CPU count
   , uCpu     :: Int       -- ^ Used VCPU count
+  , spindleCount :: Int   -- ^ Node spindles (spindle_count node parameter)
   , pList    :: [T.Idx]   -- ^ List of primary instance indices
   , sList    :: [T.Idx]   -- ^ List of secondary instance indices
   , idx      :: T.Ndx     -- ^ Internal index for book-keeping
@@ -117,6 +118,9 @@ data Node = Node
                           -- threshold
   , hiCpu    :: Int       -- ^ Autocomputed from mCpu high cpu
                           -- threshold
+  , hiSpindles :: Double  -- ^ Auto-computed from policy spindle_ratio
+                          -- and the node spindle count
+  , instSpindles :: Double -- ^ Spindles used by instances
   , offline  :: Bool      -- ^ Whether the node should not be used for
                           -- allocations and skipped from score
                           -- computations
@@ -188,9 +192,10 @@ conflictingPrimaries (Node { pTags = t }) = Foldable.sum t - Map.size t
 -- 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 -> Double -> Bool -> T.Gdx -> Node
+       -> Int -> Double -> Bool -> Int -> T.Gdx -> Node
 create name_init mem_t_init mem_n_init mem_f_init
-       dsk_t_init dsk_f_init cpu_t_init offline_init group_init =
+       dsk_t_init dsk_f_init cpu_t_init offline_init spindles_init
+       group_init =
   Node { name = name_init
        , alias = name_init
        , tMem = mem_t_init
@@ -199,6 +204,7 @@ create name_init mem_t_init mem_n_init mem_f_init
        , tDsk = dsk_t_init
        , fDsk = dsk_f_init
        , tCpu = cpu_t_init
+       , spindleCount = spindles_init
        , uCpu = 0
        , pList = []
        , sList = []
@@ -215,6 +221,9 @@ create name_init mem_t_init mem_n_init mem_f_init
        , mDsk = T.defReservedDiskRatio
        , loDsk = mDskToloDsk T.defReservedDiskRatio dsk_t_init
        , hiCpu = mCpuTohiCpu (T.iPolicyVcpuRatio T.defIPolicy) cpu_t_init
+       , hiSpindles = computeHiSpindles (T.iPolicySpindleRatio T.defIPolicy)
+                      spindles_init
+       , instSpindles = 0
        , utilPool = T.baseUtil
        , utilLoad = T.zeroUtil
        , pTags = Map.empty
@@ -230,6 +239,10 @@ mDskToloDsk mval = floor . (mval *)
 mCpuTohiCpu :: Double -> Double -> Int
 mCpuTohiCpu mval = floor . (mval *)
 
+-- | Conversiojn formula from spindles and spindle ratio to hiSpindles.
+computeHiSpindles :: Double -> Int -> Double
+computeHiSpindles spindle_ratio = (spindle_ratio *) . fromIntegral
+
 -- | Changes the index.
 --
 -- This is used only during the building of the data structures.
@@ -265,7 +278,10 @@ setMcpu t val =
 setPolicy :: T.IPolicy -> Node -> Node
 setPolicy pol node =
   node { iPolicy = pol
-       , hiCpu = mCpuTohiCpu (T.iPolicyVcpuRatio pol) (tCpu node) }
+       , hiCpu = mCpuTohiCpu (T.iPolicyVcpuRatio pol) (tCpu node)
+       , hiSpindles = computeHiSpindles (T.iPolicySpindleRatio pol)
+                      (spindleCount node)
+       }
 
 -- | Computes the maximum reserved memory for peers from a peer map.
 computeMaxRes :: P.PeerMap -> P.Elem
diff --git a/htools/Ganeti/HTools/QC.hs b/htools/Ganeti/HTools/QC.hs
index b41f1db..df1f552 100644
--- a/htools/Ganeti/HTools/QC.hs
+++ b/htools/Ganeti/HTools/QC.hs
@@ -342,7 +342,7 @@ genNode min_multiplier max_multiplier = do
   cpu_t <- choose (base_cpu, top_cpu)
   offl  <- arbitrary
   let n = Node.create name (fromIntegral mem_t) mem_n mem_f
-          (fromIntegral dsk_t) dsk_f (fromIntegral cpu_t) offl 0
+          (fromIntegral dsk_t) dsk_f (fromIntegral cpu_t) offl 1 0
       n' = Node.setPolicy nullIPolicy n
   return $ Node.buildPeers n' Container.empty
 
diff --git a/htools/Ganeti/HTools/Rapi.hs b/htools/Ganeti/HTools/Rapi.hs
index 9eb5c0a..e9f82a3 100644
--- a/htools/Ganeti/HTools/Rapi.hs
+++ b/htools/Ganeti/HTools/Rapi.hs
@@ -4,7 +4,7 @@
 
 {-
 
-Copyright (C) 2009, 2010, 2011 Google Inc.
+Copyright (C) 2009, 2010, 2011, 2012 Google Inc.
 
 This program is free software; you can redistribute it and/or modify
 it under the terms of the GNU General Public License as published by
@@ -137,10 +137,12 @@ parseNode ktg a = do
   drained <- extract "drained"
   vm_cap  <- annotateResult desc $ maybeFromObj a "vm_capable"
   let vm_cap' = fromMaybe True vm_cap
+  ndparams <- extract "ndparams" >>= asJSObject
+  spindles <- tryFromObj desc (fromJSObject ndparams) "spindle_count"
   guuid   <- annotateResult desc $ maybeFromObj a "group.uuid"
   guuid' <-  lookupGroup ktg name (fromMaybe defaultGroupID guuid)
   node <- if offline || drained || not vm_cap'
-            then return $ Node.create name 0 0 0 0 0 0 True guuid'
+            then return $ Node.create name 0 0 0 0 0 0 True 0 guuid'
             else do
               mtotal  <- extract "mtotal"
               mnode   <- extract "mnode"
@@ -149,7 +151,7 @@ parseNode ktg a = do
               dfree   <- extract "dfree"
               ctotal  <- extract "ctotal"
               return $ Node.create name mtotal mnode mfree
-                     dtotal dfree ctotal False guuid'
+                     dtotal dfree ctotal False spindles guuid'
   return (name, node)
 
 -- | Construct a group from a JSON object.
diff --git a/htools/Ganeti/HTools/Simu.hs b/htools/Ganeti/HTools/Simu.hs
index 68755ea..9434e6f 100644
--- a/htools/Ganeti/HTools/Simu.hs
+++ b/htools/Ganeti/HTools/Simu.hs
@@ -6,7 +6,7 @@ This module holds the code for parsing a cluster description.
 
 {-
 
-Copyright (C) 2009, 2010, 2011 Google Inc.
+Copyright (C) 2009, 2010, 2011, 2012 Google Inc.
 
 This program is free software; you can redistribute it and/or modify
 it under the terms of the GNU General Public License as published by
@@ -74,7 +74,7 @@ createGroup grpIndex spec = do
                      Node.create (printf "node-%02d-%03d" grpIndex idx)
                            (fromIntegral mem) 0 mem
                            (fromIntegral disk) disk
-                           (fromIntegral cpu) False grpIndex
+                           (fromIntegral cpu) False 1 grpIndex
                   ) [1..ncount]
       grp = Group.create (printf "group-%02d" grpIndex)
             (printf "fake-uuid-%02d" grpIndex) apol defIPolicy
diff --git a/htools/Ganeti/HTools/Text.hs b/htools/Ganeti/HTools/Text.hs
index 6aeb44a..c01376e 100644
--- a/htools/Ganeti/HTools/Text.hs
+++ b/htools/Ganeti/HTools/Text.hs
@@ -181,7 +181,7 @@ loadNode ktg [name, tm, nm, fm, td, fd, tc, fo, gu] = do
   gdx <- lookupGroup ktg name gu
   new_node <-
       if any (== "?") [tm,nm,fm,td,fd,tc] || fo == "Y" then
-          return $ Node.create name 0 0 0 0 0 0 True gdx
+          return $ Node.create name 0 0 0 0 0 0 True 0 gdx
       else do
         vtm <- tryRead name tm
         vnm <- tryRead name nm
@@ -189,7 +189,7 @@ loadNode ktg [name, tm, nm, fm, td, fd, tc, fo, gu] = do
         vtd <- tryRead name td
         vfd <- tryRead name fd
         vtc <- tryRead name tc
-        return $ Node.create name vtm vnm vfm vtd vfd vtc False gdx
+        return $ Node.create name vtm vnm vfm vtd vfd vtc False 1 gdx
   return (name, new_node)
 loadNode _ s = fail $ "Invalid/incomplete node data: '" ++ show s ++ "'"
 
