commit 1cf9ade21765662579bb137cdb4ed2e19072fee1
Author: Ilias Tsitsimpis <iliastsi@grnet.gr>
Date:   Tue May 13 16:34:38 2014 +0300

    (2.13) Make 'access' an optional disk parameter
    
    This patch makes 'access' an optional disk parameter just like
    spindles, mode, name, vg and metavg. This option can only be set to
    'kernelspace' or 'userspace'. When 'userspace' is used, the instance
    will access this disk directly without going through a block device.
    
    If 'access' is not specified, the default value of the node-group
    (possibly inherited from the cluster-wide settings) will be used. This
    behavior is similar to what 'vg' and 'metavg' parameters do.
    
    Currently this option works only for RBD and Gluster devices, since
    these are the only templates that actually support the parameter.
    
    Signed-off-by: Ilias Tsitsimpis <iliastsi@grnet.gr>
    Signed-off-by: Klaus Aehlig <aehlig@google.com>
    Reviewed-by: Klaus Aehlig <aehlig@google.com>
    Signed-off-by: Dimitris Aragiorgis <dimara@grnet.gr>

diff --git a/lib/cmdlib/instance.py b/lib/cmdlib/instance.py
index 7231dec..dfcef6c 100644
--- a/lib/cmdlib/instance.py
+++ b/lib/cmdlib/instance.py
@@ -1221,18 +1221,19 @@ class LUInstanceCreate(LogicalUnit):
     # Check disk access param to be compatible with specified hypervisor
     node_info = self.cfg.GetNodeInfo(self.op.pnode_uuid)
     node_group = self.cfg.GetNodeGroup(node_info.group)
-    disk_params = self.cfg.GetGroupDiskParams(node_group)
-    access_type = disk_params[self.op.disk_template].get(
+    group_disk_params = self.cfg.GetGroupDiskParams(node_group)
+    group_access_type = group_disk_params[self.op.disk_template].get(
       constants.RBD_ACCESS, constants.DISK_KERNELSPACE
     )
-
-    if not IsValidDiskAccessModeCombination(self.op.hypervisor,
-                                            self.op.disk_template,
-                                            access_type):
-      raise errors.OpPrereqError("Selected hypervisor (%s) cannot be"
-                                 " used with %s disk access param" %
-                                 (self.op.hypervisor, access_type),
-                                  errors.ECODE_STATE)
+    for dsk in self.disks:
+      access_type = dsk.get(constants.IDISK_ACCESS, group_access_type)
+      if not IsValidDiskAccessModeCombination(self.op.hypervisor,
+                                              self.op.disk_template,
+                                              access_type):
+        raise errors.OpPrereqError("Selected hypervisor (%s) cannot be"
+                                   " used with %s disk access param" %
+                                   (self.op.hypervisor, access_type),
+                                    errors.ECODE_STATE)
 
     # Verify instance specs
     spindle_use = self.be_full.get(constants.BE_SPINDLE_USE, None)
@@ -2368,7 +2369,7 @@ class LUInstanceSetParams(LogicalUnit):
       else:
         raise errors.ProgrammerError("Unhandled operation '%s'" % op)
 
-  def _VerifyDiskModification(self, op, params, excl_stor):
+  def _VerifyDiskModification(self, op, params, excl_stor, group_access_type):
     """Verifies a disk modification.
 
     """
@@ -2391,6 +2392,17 @@ class LUInstanceSetParams(LogicalUnit):
 
       CheckSpindlesExclusiveStorage(params, excl_stor, True)
 
+      # Check disk access param (only for specific disks)
+      if self.instance.disk_template in constants.DTS_HAVE_ACCESS:
+        access_type = params.get(constants.IDISK_ACCESS, group_access_type)
+        if not IsValidDiskAccessModeCombination(self.instance.hypervisor,
+                                                self.instance.disk_template,
+                                                access_type):
+          raise errors.OpPrereqError("Selected hypervisor (%s) cannot be"
+                                     " used with %s disk access param" %
+                                     (self.op.hypervisor, access_type),
+                                      errors.ECODE_STATE)
+
     elif op == constants.DDM_MODIFY:
       if constants.IDISK_SIZE in params:
         raise errors.OpPrereqError("Disk size change not possible, use"
@@ -2400,6 +2412,11 @@ class LUInstanceSetParams(LogicalUnit):
       # Changing arbitrary parameters is allowed only for ext disk template",
       if self.instance.disk_template != constants.DT_EXT:
         utils.ForceDictType(params, constants.MODIFIABLE_IDISK_PARAMS_TYPES)
+      else:
+        # We have to check that 'access' parameter can not be modified
+        if constants.IDISK_ACCESS in params:
+          raise errors.OpPrereqError("Disk 'access' parameter change is"
+                                     " not possible", errors.ECODE_INVAL)
 
       name = params.get(constants.IDISK_NAME, None)
       if name is not None and name.lower() == constants.VALUE_NONE:
@@ -2781,9 +2798,18 @@ class LUInstanceSetParams(LogicalUnit):
                                       self.instance.all_nodes).values()
       )
 
+    # Get the group access type
+    node_info = self.cfg.GetNodeInfo(self.instance.primary_node)
+    node_group = self.cfg.GetNodeGroup(node_info.group)
+    group_disk_params = self.cfg.GetGroupDiskParams(node_group)
+    group_access_type = group_disk_params[self.instance.disk_template].get(
+      constants.RBD_ACCESS, constants.DISK_KERNELSPACE
+    )
+
     # Check disk modifications. This is done here and not in CheckArguments
     # (as with NICs), because we need to know the instance's disk template
-    ver_fn = lambda op, par: self._VerifyDiskModification(op, par, excl_stor)
+    ver_fn = lambda op, par: self._VerifyDiskModification(op, par, excl_stor,
+                                                          group_access_type)
     if self.instance.disk_template == constants.DT_EXT:
       self._CheckMods("disk", self.op.disks, {}, ver_fn)
     else:
