diff --git a/htools/Ganeti/HTools/IAlloc.hs b/htools/Ganeti/HTools/IAlloc.hs
index aa8a39c5b5323143d0f03bd20125dcae08935ff6..9ccc8ecb8a729502af11cbed1cdd0612d9b8fb60 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 cd80996bb9b7c079c90ad944ea99c532da7e1026..77d561472845ce6b4cbbdbe148e6081914ab5816 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 0f686c09b1272d1fc4a2240e4568be762cf59cd0..c117a6ae18c0f334638da04b5507e7b4aae64b23 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 b41f1db467add06537a22246c41d1601eedf5549..df1f5521e3d7bb87095df10aa4e28fb6728345fa 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 9eb5c0a99e6974fdffa290e5233445485f2de75a..e9f82a310147f957edef007ba1e547cd73f8fb5f 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 68755ea97ec640f87ab6150103305446f0eca4c2..9434e6fbf169ac9fada7ebdd5ce17aa620ab69c9 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 6aeb44a0204aef219bb9fdc598585598c883123a..c01376e590a8e1f224a3662244aadc5de3b5c7b8 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 ++ "'"