diff --git a/lib/bootstrap.py b/lib/bootstrap.py
index 3e42eaee44a8599854a5f78751261ac0f616de23..66c166c9f11718e3168f945536ec770d88237639 100644
--- a/lib/bootstrap.py
+++ b/lib/bootstrap.py
@@ -421,8 +421,7 @@ def InitCluster(cluster_name, mac_prefix, # pylint: disable=R0913, R0914
     utils.ForceDictType(val, constants.ISPECS_PARAMETER_TYPES)
 
   objects.NIC.CheckParameterSyntax(nicparams)
-  full_ipolicy = objects.FillDictOfDicts(constants.IPOLICY_DEFAULTS,
-                                         ipolicy)
+  full_ipolicy = objects.FillIPolicy(constants.IPOLICY_DEFAULTS, ipolicy)
   objects.InstancePolicy.CheckParameterSyntax(full_ipolicy)
 
   if ndparams is not None:
diff --git a/lib/client/gnt_cluster.py b/lib/client/gnt_cluster.py
index d1ecbd538adeb0b8e9776ead59555c8f50b36e6d..6cbd4da86cbeab00cf25cb12714bf908dbcfc647 100644
--- a/lib/client/gnt_cluster.py
+++ b/lib/client/gnt_cluster.py
@@ -139,13 +139,16 @@ def InitCluster(opts, args):
     utils.ForceDictType(diskparams[templ], constants.DISK_DT_TYPES)
 
   # prepare ipolicy dict
+  ispecs_dts = opts.ispecs_disk_templates # hate long var names
   ipolicy_raw = \
     objects.CreateIPolicyFromOpts(ispecs_mem_size=opts.ispecs_mem_size,
                                   ispecs_cpu_count=opts.ispecs_cpu_count,
                                   ispecs_disk_count=opts.ispecs_disk_count,
                                   ispecs_disk_size=opts.ispecs_disk_size,
-                                  ispecs_nic_count=opts.ispecs_nic_count)
-  ipolicy = objects.FillDictOfDicts(constants.IPOLICY_DEFAULTS, ipolicy_raw)
+                                  ispecs_nic_count=opts.ispecs_nic_count,
+                                  ispecs_disk_templates=ispecs_dts,
+                                  fill_all=True)
+  ipolicy = objects.FillIPolicy(constants.IPOLICY_DEFAULTS, ipolicy_raw)
   for value in ipolicy.values():
     utils.ForceDictType(value, constants.ISPECS_PARAMETER_TYPES)
 
@@ -461,6 +464,8 @@ def ShowClusterConfig(opts, args):
   for key in constants.IPOLICY_PARAMETERS:
     ToStdout("  - %s", key)
     _PrintGroupedParams(result["ipolicy"][key], roman=opts.roman_integers)
+  ToStdout("  - enabled disk templates: %s",
+           utils.CommaJoin(result["ipolicy"][constants.ISPECS_DTS]))
 
   return 0
 
@@ -984,12 +989,14 @@ def SetClusterParams(opts, args):
   if ndparams is not None:
     utils.ForceDictType(ndparams, constants.NDS_PARAMETER_TYPES)
 
+  ispecs_dts = opts.ispecs_disk_templates
   ipolicy = \
     objects.CreateIPolicyFromOpts(ispecs_mem_size=opts.ispecs_mem_size,
                                   ispecs_cpu_count=opts.ispecs_cpu_count,
                                   ispecs_disk_count=opts.ispecs_disk_count,
                                   ispecs_disk_size=opts.ispecs_disk_size,
-                                  ispecs_nic_count=opts.ispecs_nic_count)
+                                  ispecs_nic_count=opts.ispecs_nic_count,
+                                  ispecs_disk_templates=ispecs_dts)
 
   mnh = opts.maintain_node_health
 
diff --git a/lib/client/gnt_group.py b/lib/client/gnt_group.py
index f39c6e5ef07e0a94a17a266b0bfb35aa0a0f8232..b8d823646a151dc27e3b1afbd27ae1039986d5f9 100644
--- a/lib/client/gnt_group.py
+++ b/lib/client/gnt_group.py
@@ -192,6 +192,7 @@ def SetGroupParams(opts, args):
     ispecs_disk_count=opts.ispecs_disk_count,
     ispecs_disk_size=opts.ispecs_disk_size,
     ispecs_nic_count=opts.ispecs_nic_count,
+    ispecs_disk_templates=opts.ispecs_disk_templates,
     group_ipolicy=True,
     allowed_values=[constants.VALUE_DEFAULT])
 
diff --git a/lib/cmdlib.py b/lib/cmdlib.py
index b66bfbabe74b9dcd8b472e905d2e4e3ec5988fee..1b612f733c007a6fa19879d592bb9f829a29150e 100644
--- a/lib/cmdlib.py
+++ b/lib/cmdlib.py
@@ -721,6 +721,42 @@ def _GetUpdatedParams(old_params, update_dict,
   return params_copy
 
 
+def _GetUpdatedIPolicy(old_ipolicy, new_ipolicy, group_policy=False):
+  """Return the new version of a instance policy.
+
+  @param group_policy: whether this policy applies to a group and thus
+    we should support removal of policy entries
+
+  """
+  use_none = use_default = group_policy
+  ipolicy = copy.deepcopy(old_ipolicy)
+  for key, value in new_ipolicy.items():
+    if key in constants.IPOLICY_PARAMETERS:
+      utils.ForceDictType(value, constants.ISPECS_PARAMETER_TYPES)
+      ipolicy[key] = _GetUpdatedParams(old_ipolicy.get(key, {}), value,
+                                       use_none=use_none,
+                                       use_default=use_default)
+    else:
+      # FIXME: we assume all others are lists; this should be redone
+      # in a nicer way
+      if not value or value == [constants.VALUE_DEFAULT]:
+        if group_policy:
+          del ipolicy[key]
+        else:
+          raise errors.OpPrereqError("Can't unset ipolicy attribute '%s'"
+                                     " on the cluster'" % key,
+                                     errors.ECODE_INVAL)
+      else:
+        logging.info("Setting %s to %s", key, value)
+        ipolicy[key] = list(value)
+  try:
+    objects.InstancePolicy.CheckParameterSyntax(ipolicy)
+  except errors.ConfigurationError, err:
+    raise errors.OpPrereqError("Invalid instance policy: %s" % err,
+                               errors.ECODE_INVAL)
+  return ipolicy
+
+
 def _UpdateAndVerifySubDict(base, updates, type_check):
   """Updates and verifies a dict with sub dicts of the same type.
 
@@ -3830,17 +3866,8 @@ class LUClusterSetParams(LogicalUnit):
              for storage, svalues in new_disk_state.items())
 
     if self.op.ipolicy:
-      ipolicy = {}
-      for key, value in self.op.ipolicy.items():
-        utils.ForceDictType(value, constants.ISPECS_PARAMETER_TYPES)
-        ipolicy[key] = _GetUpdatedParams(cluster.ipolicy.get(key, {}),
-                                          value)
-      try:
-        objects.InstancePolicy.CheckParameterSyntax(ipolicy)
-      except errors.ConfigurationError, err:
-        raise errors.OpPrereqError("Invalid instance policy: %s" % err,
-                                   errors.ECODE_INVAL)
-      self.new_ipolicy = ipolicy
+      self.new_ipolicy = _GetUpdatedIPolicy(cluster.ipolicy, self.op.ipolicy,
+                                            group_policy=False)
 
     if self.op.nicparams:
       utils.ForceDictType(self.op.nicparams, constants.NICS_PARAMETER_TYPES)
@@ -13306,18 +13333,9 @@ class LUGroupSetParams(LogicalUnit):
                                  self.group.disk_state_static)
 
     if self.op.ipolicy:
-      g_ipolicy = {}
-      for key, value in self.op.ipolicy.iteritems():
-        g_ipolicy[key] = _GetUpdatedParams(self.group.ipolicy.get(key, {}),
-                                           value,
-                                           use_none=True)
-        utils.ForceDictType(g_ipolicy[key], constants.ISPECS_PARAMETER_TYPES)
-      self.new_ipolicy = g_ipolicy
-      try:
-        objects.InstancePolicy.CheckParameterSyntax(self.new_ipolicy)
-      except errors.ConfigurationError, err:
-        raise errors.OpPrereqError("Invalid instance policy: %s" % err,
-                                   errors.ECODE_INVAL)
+      self.new_ipolicy = _GetUpdatedIPolicy(self.group.ipolicy,
+                                            self.op.ipolicy,
+                                            group_policy=True)
 
   def BuildHooksEnv(self):
     """Build hooks env.
diff --git a/lib/config.py b/lib/config.py
index 03a3d5aeb0fbf59db40582ad6c464163270c3a99..7654ba1a70adfd43f12cb6b97ebe9efc9523f240 100644
--- a/lib/config.py
+++ b/lib/config.py
@@ -433,9 +433,16 @@ class ConfigWriter:
         result.append("%s has invalid instance policy: %s" % (owner, err))
 
     def _helper_ispecs(owner, params):
-      for key, value in params.iteritems():
-        fullkey = "ipolicy/" + key
-        _helper(owner, fullkey, value, constants.ISPECS_PARAMETER_TYPES)
+      for key, value in params.items():
+        if key in constants.IPOLICY_PARAMETERS:
+          fullkey = "ipolicy/" + key
+          _helper(owner, fullkey, value, constants.ISPECS_PARAMETER_TYPES)
+        else:
+          # FIXME: assuming list type
+          if not isinstance(value, list):
+            result.append("%s has invalid instance policy: for %s,"
+                          " expecting list, got %s" %
+                          (owner, key, type(value)))
 
     # check cluster parameters
     _helper("cluster", "beparams", cluster.SimpleFillBE({}),
diff --git a/lib/constants.py b/lib/constants.py
index 16931ac6c5e34d10965fa3c1865c033fa73ed56f..9216e0ab9c5ab2a7a60e9521c52c568306debf8f 100644
--- a/lib/constants.py
+++ b/lib/constants.py
@@ -941,12 +941,14 @@ ISPECS_PARAMETERS = frozenset(ISPECS_PARAMETER_TYPES.keys())
 ISPECS_MIN = "min"
 ISPECS_MAX = "max"
 ISPECS_STD = "std"
+ISPECS_DTS = "disk_templates"
 
 IPOLICY_PARAMETERS = frozenset([
   ISPECS_MIN,
   ISPECS_MAX,
   ISPECS_STD,
   ])
+IPOLICY_ALL_KEYS = IPOLICY_PARAMETERS.union([ISPECS_DTS])
 
 # Node parameter names
 ND_OOB_PROGRAM = "oob_program"
@@ -1885,7 +1887,8 @@ IPOLICY_DEFAULTS = {
     ISPEC_DISK_COUNT: 1,
     ISPEC_DISK_SIZE: 1024,
     ISPEC_NIC_COUNT: 1,
-    }
+    },
+  ISPECS_DTS: DISK_TEMPLATES,
   }
 
 MASTER_POOL_SIZE_DEFAULT = 10
diff --git a/lib/objects.py b/lib/objects.py
index 47fe527dfbc47c86772109394b0b0a78d261af0b..3da52edd8791c3d203a20bc210671f1179e05e13 100644
--- a/lib/objects.py
+++ b/lib/objects.py
@@ -1,7 +1,7 @@
 #
 #
 
-# Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011 Google Inc.
+# Copyright (C) 2006, 2007, 2008, 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
@@ -59,7 +59,7 @@ _UUID = ["uuid"]
 TISPECS_GROUP_TYPES = {
   constants.ISPECS_MIN: constants.VTYPE_INT,
   constants.ISPECS_MAX: constants.VTYPE_INT,
-}
+  }
 
 TISPECS_CLUSTER_TYPES = {
   constants.ISPECS_MIN: constants.VTYPE_INT,
@@ -92,15 +92,20 @@ def FillDict(defaults_dict, custom_dict, skip_keys=None):
   return ret_dict
 
 
-def FillDictOfDicts(defaults_dict, custom_dict, skip_keys=None):
-  """Run FillDict for each key in dictionary.
+def FillIPolicy(default_ipolicy, custom_ipolicy, skip_keys=None):
+  """Fills an instance policy with defaults.
 
   """
+  assert frozenset(default_ipolicy.keys()) == constants.IPOLICY_ALL_KEYS
   ret_dict = {}
-  for key in defaults_dict:
-    ret_dict[key] = FillDict(defaults_dict[key],
-                             custom_dict.get(key, {}),
+  for key in constants.IPOLICY_PARAMETERS:
+    ret_dict[key] = FillDict(default_ipolicy[key],
+                             custom_ipolicy.get(key, {}),
                              skip_keys=skip_keys)
+  # list items
+  for key in [constants.ISPECS_DTS]:
+    ret_dict[key] = list(custom_ipolicy.get(key, default_ipolicy[key]))
+
   return ret_dict
 
 
@@ -166,9 +171,9 @@ def MakeEmptyIPolicy():
 
   """
   return dict([
-    (constants.ISPECS_MIN, dict()),
-    (constants.ISPECS_MAX, dict()),
-    (constants.ISPECS_STD, dict()),
+    (constants.ISPECS_MIN, {}),
+    (constants.ISPECS_MAX, {}),
+    (constants.ISPECS_STD, {}),
     ])
 
 
@@ -177,9 +182,14 @@ def CreateIPolicyFromOpts(ispecs_mem_size=None,
                           ispecs_disk_count=None,
                           ispecs_disk_size=None,
                           ispecs_nic_count=None,
+                          ispecs_disk_templates=None,
                           group_ipolicy=False,
-                          allowed_values=None):
-  """Creation of instane policy based on command line options.
+                          allowed_values=None,
+                          fill_all=False):
+  """Creation of instance policy based on command line options.
+
+  @param fill_all: whether for cluster policies we should ensure that
+    all values are filled
 
 
   """
@@ -208,6 +218,12 @@ def CreateIPolicyFromOpts(ispecs_mem_size=None,
     for key, val in specs.items(): # {min: .. ,max: .., std: ..}
       ipolicy_out[key][name] = val
 
+  # no filldict for lists
+  if not group_ipolicy and fill_all and ispecs_disk_templates is None:
+    ispecs_disk_templates = constants.DISK_TEMPLATES
+  if ispecs_disk_templates is not None:
+    ipolicy_out[constants.ISPECS_DTS] = list(ispecs_disk_templates)
+
   return ipolicy_out
 
 
@@ -857,7 +873,7 @@ class Disk(ConfigObject):
 
 class InstancePolicy(ConfigObject):
   """Config object representing instance policy limits dictionary."""
-  __slots__ = ["min", "max", "std"]
+  __slots__ = ["min", "max", "std", "disk_templates"]
 
   @classmethod
   def CheckParameterSyntax(cls, ipolicy):
@@ -866,6 +882,8 @@ class InstancePolicy(ConfigObject):
     """
     for param in constants.ISPECS_PARAMETERS:
       InstancePolicy.CheckISpecSyntax(ipolicy, param)
+    if constants.ISPECS_DTS in ipolicy:
+      InstancePolicy.CheckDiskTemplates(ipolicy[constants.ISPECS_DTS])
 
   @classmethod
   def CheckISpecSyntax(cls, ipolicy, name):
@@ -892,6 +910,16 @@ class InstancePolicy(ConfigObject):
     if min_v > std_v or std_v > max_v:
       raise errors.ConfigurationError(err)
 
+  @classmethod
+  def CheckDiskTemplates(cls, disk_templates):
+    """Checks the disk templates for validity.
+
+    """
+    wrong = frozenset(disk_templates).difference(constants.DISK_TEMPLATES)
+    if wrong:
+      raise errors.ConfigurationError("Invalid disk template(s) %s" %
+                                      utils.CommaJoin(wrong))
+
 
 class Instance(TaggableObject):
   """Config object representing an instance."""
@@ -1473,7 +1501,7 @@ class Cluster(TaggableObject):
 
     # instance policy added before 2.6
     if self.ipolicy is None:
-      self.ipolicy = FillDictOfDicts(constants.IPOLICY_DEFAULTS, {})
+      self.ipolicy = FillIPolicy(constants.IPOLICY_DEFAULTS, {})
 
   @property
   def primary_hypervisor(self):
@@ -1668,7 +1696,7 @@ class Cluster(TaggableObject):
       the cluster defaults
 
     """
-    return FillDictOfDicts(self.ipolicy, ipolicy)
+    return FillIPolicy(self.ipolicy, ipolicy)
 
 
 class BlockDevStatus(ConfigObject):