Skip to content

Commit

Permalink
vmware: default global pbm policy configuration
Browse files Browse the repository at this point in the history
Adding support for a global pbm policy configuration for the vmdk
driver. Setting the 'pbm_default_policy' in cinder.conf will be
used as the default storage profile name to be used when creating
a volume without associated vmware:storage_profile extra spec.

Also renaming 'vmware-pbm-wsdl' to 'pbm-wsdl-location' to use
nova driver's naming convention.

Implements: blueprint vmdk-storage-policy-volume-type
Change-Id: I7fad167b7be6a479db88fb4d15d07f29afd023b0
  • Loading branch information
subramanian-neelakantan committed Mar 3, 2014
1 parent 848ef00 commit 07ad47e
Show file tree
Hide file tree
Showing 4 changed files with 105 additions and 15 deletions.
38 changes: 34 additions & 4 deletions cinder/tests/test_vmware_vmdk.py
Expand Up @@ -1054,12 +1054,34 @@ class VMwareVcVmdkDriverTestCase(VMwareEsxVmdkDriverTestCase):
"""Test class for VMwareVcVmdkDriver."""

PBM_WSDL = '/fake/wsdl/path'
DEFAULT_PROFILE = 'fakeProfile'

def setUp(self):
super(VMwareVcVmdkDriverTestCase, self).setUp()
self.flags(vmware_pbm_wsdl=self.PBM_WSDL)
self._config.pbm_wsdl_location = self.PBM_WSDL
self._config.pbm_default_policy = self.DEFAULT_PROFILE
self._driver = vmdk.VMwareVcVmdkDriver(configuration=self._config)

@mock.patch('cinder.volume.drivers.vmware.vmdk.VMwareVcVmdkDriver.'
'session', new_callable=mock.PropertyMock)
@mock.patch('cinder.volume.drivers.vmware.vmdk.VMwareVcVmdkDriver.'
'volumeops', new_callable=mock.PropertyMock)
def test_do_setup(self, vol_ops, session):
"""Test do_setup."""
vol_ops = vol_ops.return_value
session = session.return_value
# pbm_wsdl_location is set and pbm_default_policy is used
self._driver.do_setup(mock.ANY)
default = self.DEFAULT_PROFILE
vol_ops.retrieve_profile_id.assert_called_once_with(default)
# pbm_wsdl_location is set and pbm_default_policy is wrong
vol_ops.retrieve_profile_id.return_value = None
self.assertRaises(error_util.PbmDefaultPolicyDoesNotExist,
self._driver.do_setup, mock.ANY)
# pbm_wsdl_location is not set
self._driver.configuration.pbm_wsdl_location = None
self._driver.do_setup(mock.ANY)

def test_init_conn_with_instance_and_backing(self):
"""Test initialize_connection with instance and backing."""
m = self.mox
Expand Down Expand Up @@ -1300,20 +1322,28 @@ def test_create_linked_cloned_volume_when_attached(self):
def test_get_storage_profile(self, get_volume_type_extra_specs):
"""Test vmdk _get_storage_profile."""

# Test volume with no type id returns None
# volume with no type id returns None
volume = FakeObject()
volume['volume_type_id'] = None
sp = self._driver._get_storage_profile(volume)
self.assertEqual(None, sp, "Without a volume_type_id no storage "
"profile should be returned.")

# Test volume with type id calls extra specs
# profile associated with the volume type should be returned
fake_id = 'fake_volume_id'
volume['volume_type_id'] = fake_id
self._driver._get_storage_profile(volume)
get_volume_type_extra_specs.return_value = 'fake_profile'
profile = self._driver._get_storage_profile(volume)
self.assertEqual('fake_profile', profile)
spec_key = 'vmware:storage_profile'
get_volume_type_extra_specs.assert_called_once_with(fake_id, spec_key)

# default profile should be returned when no storage profile is
# associated with the volume type
get_volume_type_extra_specs.return_value = False
profile = self._driver._get_storage_profile(volume)
self.assertEqual(self.DEFAULT_PROFILE, profile)

@mock.patch('cinder.volume.drivers.vmware.vim_util.'
'convert_datastores_to_hubs')
@mock.patch('cinder.volume.drivers.vmware.vim_util.'
Expand Down
22 changes: 22 additions & 0 deletions cinder/volume/drivers/vmware/error_util.py
Expand Up @@ -45,3 +45,25 @@ class VimFaultException(exception.VolumeBackendAPIException):
def __init__(self, fault_list, msg):
exception.VolumeBackendAPIException.__init__(self, msg)
self.fault_list = fault_list


class VMwareDriverException(exception.CinderException):
"""Base class for all exceptions raised by the VMDK driver.
All exceptions raised by the vmdk driver should raise an exception
descended from this class as a root. This will allow the driver to
potentially trap problems related to its own internal configuration
before halting the cinder-volume node.
"""
message = _("VMware VMDK driver exception.")


class VMwaredriverConfigurationException(VMwareDriverException):
"""Base class for all configuration exceptions.
"""
message = _("VMware VMDK driver configuration error.")


class PbmDefaultPolicyDoesNotExist(VMwaredriverConfigurationException):
message = _("The configured default PBM policy is not defined on "
"vCenter Server.")
43 changes: 38 additions & 5 deletions cinder/volume/drivers/vmware/vmdk.py
Expand Up @@ -80,15 +80,23 @@
'Query results will be obtained in batches from the '
'server and not in one shot. Server may still limit the '
'count to something less than the configured value.'),
cfg.StrOpt('vmware_pbm_wsdl',
]

spbm_opts = [
cfg.StrOpt('pbm_wsdl_location',
help='PBM service WSDL file location URL. '
'e.g. file:///opt/SDK/spbm/wsdl/pbmService.wsdl. '
'Not setting this will disable storage policy based '
'placement of volumes.'),
cfg.StrOpt('pbm_default_policy',
help='The PBM default policy. If pbm_wsdl_location is set and '
'there is no defined storage policy for the specific '
'request then this policy will be used.'),
]

CONF = cfg.CONF
CONF.register_opts(vmdk_opts)
CONF.register_opts(spbm_opts)


def _get_volume_type_extra_spec(type_id, spec_key, possible_values=None,
Expand Down Expand Up @@ -317,12 +325,15 @@ def _get_storage_profile(self, volume):
:param volume: volume whose storage profile should be queried
:return: string value of storage profile if volume type is associated,
default global profile if configured in pbm_default_profile,
None otherwise
"""
type_id = volume['volume_type_id']
if not type_id:
return
return _get_volume_type_extra_spec(type_id, 'storage_profile')
default_policy = self.configuration.pbm_default_policy
return _get_volume_type_extra_spec(type_id, 'storage_profile',
default_value=default_policy)

def _filter_ds_by_profile(self, datastores, storage_profile):
"""Filter out datastores that do not match given storage profile.
Expand Down Expand Up @@ -951,6 +962,7 @@ class VMwareVcVmdkDriver(VMwareEsxVmdkDriver):

def __init__(self, *args, **kwargs):
super(VMwareVcVmdkDriver, self).__init__(*args, **kwargs)
self.configuration.append_config_values(spbm_opts)
self._session = None

@property
Expand All @@ -962,16 +974,37 @@ def session(self):
api_retry_count = self.configuration.vmware_api_retry_count
task_poll_interval = self.configuration.vmware_task_poll_interval
wsdl_loc = self.configuration.safe_get('vmware_wsdl_location')
pbm_wsdl = self.configuration.vmware_pbm_wsdl
pbm_wsdl = self.configuration.pbm_wsdl_location
self._session = api.VMwareAPISession(ip, username,
password, api_retry_count,
task_poll_interval,
wsdl_loc=wsdl_loc,
pbm_wsdl=pbm_wsdl)
if pbm_wsdl:
self._storage_policy_enabled = True
return self._session

def do_setup(self, context):
"""Any initialization the volume driver does while starting."""
super(VMwareVcVmdkDriver, self).do_setup(context)
# VC specific setup is done here
pbm_wsdl = self.configuration.pbm_wsdl_location
default_policy = self.configuration.pbm_default_policy
if not pbm_wsdl:
if default_policy:
LOG.warn(_("Ignoring %s since pbm_wsdl_location is not "
"set."), default_policy)
return
# pbm_wsdl is set, so storage policy should be enabled
self._storage_policy_enabled = True
# now verify the default policy exists in VC
if default_policy:
if not self.volumeops.retrieve_profile_id(default_policy):
msg = _("The configured default PBM policy '%s' is not "
"defined on vCenter Server.") % default_policy
raise error_util.PbmDefaultPolicyDoesNotExist(message=msg)
else:
LOG.info(_("Successfully verified existence of "
"pbm_default_policy: %s."), default_policy)

def _get_volume_group_folder(self, datacenter):
"""Get volume group folder.
Expand Down
17 changes: 11 additions & 6 deletions etc/cinder/cinder.conf.sample
Expand Up @@ -1661,6 +1661,17 @@
# Options defined in cinder.volume.drivers.vmware.vmdk
#

# PBM service WSDL file location URL. e.g.
# file:///opt/SDK/spbm/wsdl/pbmService.wsdl. Not setting this
# will disable storage policy based placement of volumes.
# (string value)
#pbm_wsdl_location=<None>

# The PBM default policy. If pbm_wsdl_location is set and
# there is no defined storage policy for the specific request
# then this policy will be used. (string value)
#pbm_default_policy=<None>

# IP address for connecting to VMware ESX/VC server. (string
# value)
#vmware_host_ip=<None>
Expand Down Expand Up @@ -1700,12 +1711,6 @@
# less than the configured value. (integer value)
#vmware_max_objects_retrieval=100

# PBM service WSDL file location URL. e.g.
# file:///opt/SDK/spbm/wsdl/pbmService.wsdl. Not setting this
# will disable storage policy based placement of volumes.
# (string value)
#vmware_pbm_wsdl=<None>


#
# Options defined in cinder.volume.drivers.windows.windows
Expand Down

0 comments on commit 07ad47e

Please sign in to comment.