diff --git a/Ganeti/HTools/CLI.hs b/Ganeti/HTools/CLI.hs
index 718440f9d42da4959b195028782c45e8248a9382..8dad35d5009e12f17d278fd81312c48f0ac58957 100644
--- a/Ganeti/HTools/CLI.hs
+++ b/Ganeti/HTools/CLI.hs
@@ -58,6 +58,7 @@ module Ganeti.HTools.CLI
     , oMinDisk
     , oDiskMoves
     , oDynuFile
+    , oTieredSpec
     , oShowVer
     , oShowHelp
     ) where
@@ -73,6 +74,7 @@ import Text.Printf (printf)
 
 import qualified Ganeti.HTools.Version as Version(version)
 import Ganeti.HTools.Types
+import Ganeti.HTools.Utils
 
 -- | The default value for the luxi socket
 defaultLuxiSocket :: FilePath
@@ -80,67 +82,65 @@ defaultLuxiSocket = "/var/run/ganeti/socket/ganeti-master"
 
 -- | Command line options structure.
 data Options = Options
-    { optShowNodes :: Bool           -- ^ Whether to show node status
-    , optShowInsts :: Bool           -- ^ Whether to show the instance map
-    , optShowCmds  :: Maybe FilePath -- ^ Whether to show the command list
-    , optOneline   :: Bool           -- ^ Switch output to a single line
-    , optOutPath   :: FilePath       -- ^ Path to the output directory
-    , optNoHeaders :: Bool           -- ^ Do not show a header line
-    , optNodeFile  :: FilePath       -- ^ Path to the nodes file
-    , optNodeSet   :: Bool           -- ^ The nodes have been set by options
-    , optInstFile  :: FilePath       -- ^ Path to the instances file
-    , optInstSet   :: Bool           -- ^ The insts have been set by options
-    , optNodeSim   :: Maybe String   -- ^ Cluster simulation mode
-    , optMaxLength :: Int            -- ^ Stop after this many steps
-    , optMaster    :: String         -- ^ Collect data from RAPI
-    , optLuxi      :: Maybe FilePath -- ^ Collect data from Luxi
-    , optExecJobs  :: Bool           -- ^ Execute the commands via Luxi
-    , optOffline   :: [String]       -- ^ Names of offline nodes
-    , optIMem      :: Int            -- ^ Instance memory
-    , optIDsk      :: Int            -- ^ Instance disk
-    , optIVCPUs    :: Int            -- ^ Instance VCPUs
-    , optINodes    :: Int            -- ^ Nodes required for an instance
-    , optMinScore  :: Score          -- ^ The minimum score we aim for
-    , optMcpu      :: Double         -- ^ Max cpu ratio for nodes
-    , optMdsk      :: Double         -- ^ Max disk usage ratio for nodes
-    , optDiskMoves :: Bool           -- ^ Allow disk moves
-    , optDynuFile  :: Maybe FilePath -- ^ Optional file with dynamic use data
-    , optVerbose   :: Int            -- ^ Verbosity level
-    , optShowVer   :: Bool           -- ^ Just show the program version
-    , optShowHelp  :: Bool           -- ^ Just show the help
+    { optShowNodes   :: Bool           -- ^ Whether to show node status
+    , optShowInsts   :: Bool           -- ^ Whether to show the instance map
+    , optShowCmds    :: Maybe FilePath -- ^ Whether to show the command list
+    , optOneline     :: Bool           -- ^ Switch output to a single line
+    , optOutPath     :: FilePath       -- ^ Path to the output directory
+    , optNoHeaders   :: Bool           -- ^ Do not show a header line
+    , optNodeFile    :: FilePath       -- ^ Path to the nodes file
+    , optNodeSet     :: Bool           -- ^ The nodes have been set by options
+    , optInstFile    :: FilePath       -- ^ Path to the instances file
+    , optInstSet     :: Bool           -- ^ The insts have been set by options
+    , optNodeSim     :: Maybe String   -- ^ Cluster simulation mode
+    , optMaxLength   :: Int            -- ^ Stop after this many steps
+    , optMaster      :: String         -- ^ Collect data from RAPI
+    , optLuxi        :: Maybe FilePath -- ^ Collect data from Luxi
+    , optExecJobs    :: Bool           -- ^ Execute the commands via Luxi
+    , optOffline     :: [String]       -- ^ Names of offline nodes
+    , optINodes      :: Int            -- ^ Nodes required for an instance
+    , optISpec       :: RSpec          -- ^ Requested instance specs
+    , optTieredSpec  :: Maybe RSpec    -- ^ Requested specs for tiered mode
+    , optMinScore    :: Score          -- ^ The minimum score we aim for
+    , optMcpu        :: Double         -- ^ Max cpu ratio for nodes
+    , optMdsk        :: Double         -- ^ Max disk usage ratio for nodes
+    , optDiskMoves   :: Bool           -- ^ Allow disk moves
+    , optDynuFile    :: Maybe FilePath -- ^ Optional file with dynamic use data
+    , optVerbose     :: Int            -- ^ Verbosity level
+    , optShowVer     :: Bool           -- ^ Just show the program version
+    , optShowHelp    :: Bool           -- ^ Just show the help
     } deriving Show
 
 -- | Default values for the command line options.
 defaultOptions :: Options
 defaultOptions  = Options
- { optShowNodes = False
- , optShowInsts = False
- , optShowCmds  = Nothing
- , optOneline   = False
- , optNoHeaders = False
- , optOutPath   = "."
- , optNodeFile  = "nodes"
- , optNodeSet   = False
- , optInstFile  = "instances"
- , optInstSet   = False
- , optNodeSim   = Nothing
- , optMaxLength = -1
- , optMaster    = ""
- , optLuxi      = Nothing
- , optExecJobs  = False
- , optOffline   = []
- , optIMem      = 4096
- , optIDsk      = 102400
- , optIVCPUs    = 1
- , optINodes    = 2
- , optMinScore  = 1e-9
- , optMcpu      = -1
- , optMdsk      = -1
- , optDiskMoves = True
- , optDynuFile  = Nothing
- , optVerbose   = 1
- , optShowVer   = False
- , optShowHelp  = False
+ { optShowNodes   = False
+ , optShowInsts   = False
+ , optShowCmds    = Nothing
+ , optOneline     = False
+ , optNoHeaders   = False
+ , optOutPath     = "."
+ , optNodeFile    = "nodes"
+ , optNodeSet     = False
+ , optInstFile    = "instances"
+ , optInstSet     = False
+ , optNodeSim     = Nothing
+ , optMaxLength   = -1
+ , optMaster      = ""
+ , optLuxi        = Nothing
+ , optExecJobs    = False
+ , optOffline     = []
+ , optINodes      = 2
+ , optISpec       = RSpec 1 4096 102400
+ , optTieredSpec  = Nothing
+ , optMinScore    = 1e-9
+ , optMcpu        = -1
+ , optMdsk        = -1
+ , optDiskMoves   = True
+ , optDynuFile    = Nothing
+ , optVerbose     = 1
+ , optShowVer     = False
+ , optShowHelp    = False
  }
 
 -- | Abrreviation for the option type
@@ -242,17 +242,26 @@ oMinScore = Option "e" ["min-score"]
 
 oIMem :: OptType
 oIMem = Option "" ["memory"]
-        (ReqArg (\ m opts -> Ok opts { optIMem = read m }) "MEMORY")
+        (ReqArg (\ m opts ->
+                     let ospec = optISpec opts
+                         nspec = ospec { rspecMem = read m }
+                     in Ok opts { optISpec = nspec }) "MEMORY")
         "memory size for instances"
 
 oIDisk :: OptType
 oIDisk = Option "" ["disk"]
-         (ReqArg (\ d opts -> Ok opts { optIDsk = read d }) "DISK")
+         (ReqArg (\ d opts ->
+                     let ospec = optISpec opts
+                         nspec = ospec { rspecDsk = read d }
+                     in Ok opts { optISpec = nspec }) "DISK")
          "disk size for instances"
 
 oIVcpus :: OptType
 oIVcpus = Option "" ["vcpus"]
-          (ReqArg (\ p opts -> Ok opts { optIVCPUs = read p }) "NUM")
+          (ReqArg (\ p opts ->
+                       let ospec = optISpec opts
+                           nspec = ospec { rspecCpu = read p }
+                       in Ok opts { optISpec = nspec }) "NUM")
           "number of virtual cpus for instances"
 
 oINodes :: OptType
@@ -281,6 +290,20 @@ oDynuFile = Option "U" ["dynu-file"]
             (ReqArg (\ f opts -> Ok opts { optDynuFile = Just f }) "FILE")
             "Import dynamic utilisation data from the given FILE"
 
+oTieredSpec :: OptType
+oTieredSpec = Option "" ["tiered-alloc"]
+             (ReqArg (\ inp opts -> do
+                          let sp = sepSplit ',' inp
+                          prs <- mapM (tryRead "tiered specs") sp
+                          tspec <-
+                              case prs of
+                                [cpu, ram, dsk] -> return $ RSpec cpu ram dsk
+                                _ -> Bad $ "Invalid specification: " ++ inp
+                          return $ opts { optTieredSpec = Just tspec } )
+              "TSPEC")
+             "enable tiered specs allocation, where we decrease the instance\
+             \ spec on failure to allocate and restart the allocation process"
+
 oShowVer :: OptType
 oShowVer = Option "V" ["version"]
            (NoArg (\ opts -> Ok opts { optShowVer = True}))
diff --git a/Ganeti/HTools/Types.hs b/Ganeti/HTools/Types.hs
index fe27287870b4137de14efd706be35792559c1503..ba0cf7dbaefbd0954ddc09f5f2ebc3c59d1dc94b 100644
--- a/Ganeti/HTools/Types.hs
+++ b/Ganeti/HTools/Types.hs
@@ -29,6 +29,7 @@ module Ganeti.HTools.Types
     , NameAssoc
     , Score
     , Weight
+    , RSpec(..)
     , DynUtil(..)
     , zeroUtil
     , baseUtil
@@ -62,6 +63,13 @@ type Score = Double
 -- | A separate name for a weight metric.
 type Weight = Double
 
+-- | The resource spec type.
+data RSpec = RSpec
+    { rspecCpu  :: Int  -- ^ Requested VCPUs
+    , rspecMem  :: Int  -- ^ Requested memory
+    , rspecDsk  :: Int  -- ^ Requested disk
+    } deriving (Show)
+
 -- | The dynamic resource specs of a machine (i.e. load or load
 -- capacity, as opposed to size).
 data DynUtil = DynUtil
diff --git a/hspace.hs b/hspace.hs
index bac0cfaec613795858c58395dbc51da5e1ce9e50..bb5a11b941c8d23bf8f68ea1c62a607c69959688 100644
--- a/hspace.hs
+++ b/hspace.hs
@@ -63,6 +63,7 @@ options =
     , oINodes
     , oMaxCpu
     , oMinDisk
+    , oTieredSpec
     , oShowVer
     , oShowHelp
     ]
@@ -98,11 +99,10 @@ statsData = [ ("SCORE", printf "%.8f" . Cluster.csScore)
             , ("MNODE_DSK_AVAIL", printf "%d" . Cluster.csMdsk)
             ]
 
-specData :: [(String, Options -> String)]
-specData = [ ("MEM", printf "%d" . optIMem)
-           , ("DSK", printf "%d" . optIDsk)
-           , ("CPU", printf "%d" . optIVCPUs)
-           , ("RQN", printf "%d" . optINodes)
+specData :: [(String, RSpec -> String)]
+specData = [ ("MEM", printf "%d" . rspecMem)
+           , ("DSK", printf "%d" . rspecDsk)
+           , ("CPU", printf "%d" . rspecCpu)
            ]
 
 clusterData :: [(String, Cluster.CStats -> String)]
@@ -179,10 +179,12 @@ main = do
          exitWith $ ExitFailure 1
 
   let verbose = optVerbose opts
+      ispec = optISpec opts
 
   (fixed_nl, il, csf) <- loadExternalData opts
 
-  printKeys $ map (\(a, fn) -> ("SPEC_" ++ a, fn opts)) specData
+  printKeys $ map (\(a, fn) -> ("SPEC_" ++ a, fn ispec)) specData
+  printKeys [ ("SPEC_RQN", printf "%d" (optINodes opts)) ]
 
   let num_instances = length $ Container.elems il
 
@@ -239,10 +241,10 @@ main = do
          exitWith ExitSuccess
 
   let nmlen = Container.maxNameLen nl
-      newinst = Instance.create "new" (optIMem opts) (optIDsk opts)
-                (optIVCPUs opts) "ADMIN_down" (-1) (-1)
+      reqinst = Instance.create "new" (rspecMem ispec) (rspecDsk ispec)
+                (rspecCpu ispec) "ADMIN_down" (-1) (-1)
 
-  let result = iterateDepth nl il newinst req_nodes []
+  let result = iterateDepth nl il reqinst req_nodes []
   (ereason, fin_nl, ixes) <- (case result of
                                 Bad s -> do
                                   hPrintf stderr "Failure: %s\n" s