Skip to content

Commit

Permalink
Added extra-spec key scoping to the 3PAR drivers
Browse files Browse the repository at this point in the history
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
  • Loading branch information
kumartin committed Dec 24, 2012
1 parent 1bf8bfa commit bbc4b9a
Showing 1 changed file with 29 additions and 19 deletions.
48 changes: 29 additions & 19 deletions cinder/volume/drivers/san/hp/hp_3par_common.py
Expand Up @@ -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
Expand Down Expand Up @@ -525,24 +526,33 @@ def _get_volume_type(self, type_id):
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.") % \
Expand All @@ -569,21 +579,22 @@ def create_volume(self, volume):

# 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.
self.validate_cpg(cpg)
# 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.
Expand All @@ -595,9 +606,8 @@ def create_volume(self, volume):

# 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, "
Expand All @@ -611,9 +621,9 @@ def create_volume(self, volume):
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')
Expand Down

0 comments on commit bbc4b9a

Please sign in to comment.