]> review.fuel-infra Code Review - openstack-build/cinder-build.git/commitdiff
Added extra-spec key scoping to the 3PAR drivers
authorKurt Martin <kurt.f.martin@hp.com>
Mon, 24 Dec 2012 00:47:58 +0000 (16:47 -0800)
committerKurt Martin <kurt.f.martin@hp.com>
Mon, 24 Dec 2012 19:02:28 +0000 (11:02 -0800)
The Filter scheduler uses the extra-specs data to determine capabilities
and back-end, and it also enforces strict checking. As a result previous
method of setting all the 3PAR settings(cpg, snap_cpg, persona, provisioning)
on the 3PAR volume using extra-specs on a volume type will not work with the
default scheduler. The filter scheduler will look at these keys and fail to
schedule deployment of the volume because no suitable back-end reports those
capabilities.

This fix will allow the custom keys (ie: hp3par:cpg=TEST_CPG,
hp3par:provisioning=full,...) to be scoped, unfortunately this requires
additional checks in the common driver to parse the keys.

I'll update the 3PAR driver section of the OpenStack Block Storage Admin
Guide in a follow-up patch.
DocImpact
Fixes: bug 1194289
Change-Id: Id3fde3b3a185eedf2b8193fd0dc6324d904e8834

cinder/volume/drivers/san/hp/hp_3par_common.py

index 4c0ab2de46cdb11e6be4e9d298cab3457c3aebfe..f5b1ec2f9db8d2d880d7e7ba63b913349f99ffe5 100644 (file)
@@ -113,6 +113,7 @@ class HP3PARCommon(object):
                             '9 - EGENERA',
                             '10 - ONTAP-legacy',
                             '11 - VMware']
+    hp3par_valid_keys = ['cpg', 'snap_cpg', 'provisioning', 'persona']
 
     def __init__(self, config):
         self.sshpool = None
@@ -525,24 +526,33 @@ exit
         ctxt = context.get_admin_context()
         return volume_types.get_volume_type(ctxt, type_id)
 
-    def _get_volume_type_value(self, volume_type, key, default=None):
-        if volume_type is not None:
-            specs = volume_type.get('extra_specs')
-            if key in specs:
-                return specs[key]
-            else:
-                return default
+    def _get_key_value(self, hp3par_keys, key, default=None):
+        if hp3par_keys is not None and key in hp3par_keys:
+            return hp3par_keys[key]
         else:
             return default
 
-    def get_persona_type(self, volume):
+    def _get_keys_by_volume_type(self, volume_type):
+        hp3par_keys = {}
+        specs = volume_type.get('extra_specs')
+        for key, value in specs.iteritems():
+            if ':' in key:
+                fields = key.split(':')
+                key = fields[1]
+            if key in self.hp3par_valid_keys:
+                hp3par_keys[key] = value
+        return hp3par_keys
+
+    def get_persona_type(self, volume, hp3par_keys=None):
         default_persona = self.valid_persona_values[0]
         type_id = volume.get('volume_type_id', None)
         volume_type = None
         if type_id is not None:
             volume_type = self._get_volume_type(type_id)
-        persona_value = self._get_volume_type_value(volume_type, 'persona',
-                                                    default_persona)
+            if hp3par_keys is None:
+                hp3par_keys = self._get_keys_by_volume_type(volume_type)
+        persona_value = self._get_key_value(hp3par_keys, 'persona',
+                                            default_persona)
         if persona_value not in self.valid_persona_values:
             err = _("Must specify a valid persona %(valid)s, "
                     "value '%(persona)s' is invalid.") % \
@@ -569,12 +579,14 @@ exit
 
             # get the options supported by volume types
             volume_type = None
+            hp3par_keys = {}
             type_id = volume.get('volume_type_id', None)
             if type_id is not None:
                 volume_type = self._get_volume_type(type_id)
+                hp3par_keys = self._get_keys_by_volume_type(volume_type)
 
-            cpg = self._get_volume_type_value(volume_type, 'cpg',
-                                              self.config.hp3par_cpg)
+            cpg = self._get_key_value(hp3par_keys, 'cpg',
+                                      self.config.hp3par_cpg)
             if cpg is not self.config.hp3par_cpg:
                 # The cpg was specified in a volume type extra spec so it
                 # needs to be validiated that it's in the correct domain.
@@ -582,8 +594,7 @@ exit
                 # Also, look to see if the snap_cpg was specified in volume
                 # type extra spec, if not use the extra spec cpg as the
                 # default.
-                snap_cpg = self._get_volume_type_value(volume_type,
-                                                       'snap_cpg', cpg)
+                snap_cpg = self._get_key_value(hp3par_keys, 'snap_cpg', cpg)
             else:
                 # default snap_cpg to hp3par_cpg_snap if it's not specified
                 # in the volume type extra specs.
@@ -595,9 +606,8 @@ exit
 
             # if provisioning is not set use thin
             default_prov = self.valid_prov_values[0]
-            prov_value = self._get_volume_type_value(volume_type,
-                                                     'provisioning',
-                                                     default_prov)
+            prov_value = self._get_key_value(hp3par_keys, 'provisioning',
+                                             default_prov)
             # check for valid provisioning type
             if prov_value not in self.valid_prov_values:
                 err = _("Must specify a valid provisioning type %(valid)s, "
@@ -611,9 +621,9 @@ exit
                 ttpv = False
 
             # check for valid persona even if we don't use it until
-            # attach time, this will given end user notice that the
+            # attach time, this will give the end user notice that the
             # persona type is invalid at volume creation time
-            self.get_persona_type(volume)
+            self.get_persona_type(volume, hp3par_keys)
 
             if type_id is not None:
                 comments['volume_type_name'] = volume_type.get('name')