From bbc4b9abd7c2034ef78f87abae143b9c7bfd7f56 Mon Sep 17 00:00:00 2001 From: Kurt Martin Date: Sun, 23 Dec 2012 16:47:58 -0800 Subject: [PATCH] Added extra-spec key scoping to the 3PAR drivers 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 --- .../volume/drivers/san/hp/hp_3par_common.py | 48 +++++++++++-------- 1 file changed, 29 insertions(+), 19 deletions(-) diff --git a/cinder/volume/drivers/san/hp/hp_3par_common.py b/cinder/volume/drivers/san/hp/hp_3par_common.py index 4c0ab2de4..f5b1ec2f9 100644 --- a/cinder/volume/drivers/san/hp/hp_3par_common.py +++ b/cinder/volume/drivers/san/hp/hp_3par_common.py @@ -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') -- 2.45.2