Volume Manage/Unmanage Support for IBM FlashSystem
This patch introduce volume manage/unmanage feature for IBM FlashSystem. In this patch, * Add volume manage/unmanage feature for IBM FlashSystem driver. * Bump version to 1.0.12. DocImpact Change-Id: I97ad90756674851a4940015443394e7c99c3d9cb Implements: blueprint ibm-flashsystem-manage-unmanage
This commit is contained in:
parent
e89b0179e4
commit
5242d1f09f
@ -476,6 +476,24 @@ class FlashSystemManagementSimulator(object):
|
|||||||
return ('Virtual Disk, id [%s], successfully created' %
|
return ('Virtual Disk, id [%s], successfully created' %
|
||||||
(vdisk_info['id']), '')
|
(vdisk_info['id']), '')
|
||||||
|
|
||||||
|
def _cmd_chvdisk(self, **kwargs):
|
||||||
|
"""chvdisk command
|
||||||
|
|
||||||
|
svcask chvdisk -name <new_name_arg> -udid <vdisk_udid>
|
||||||
|
-open_access_scsi_id <vdisk_scsi_id> <vdisk_name> <vdisk_id>
|
||||||
|
"""
|
||||||
|
|
||||||
|
if 'obj' not in kwargs:
|
||||||
|
return self._errors['CMMVC50000']
|
||||||
|
|
||||||
|
source_name = kwargs['obj'].strip('\'\"')
|
||||||
|
dest_name = kwargs['name'].strip('\'\"')
|
||||||
|
vol = self._volumes_list[source_name]
|
||||||
|
vol['name'] = dest_name
|
||||||
|
del self._volumes_list[source_name]
|
||||||
|
self._volumes_list[dest_name] = vol
|
||||||
|
return ('', '')
|
||||||
|
|
||||||
def _cmd_rmvdisk(self, **kwargs):
|
def _cmd_rmvdisk(self, **kwargs):
|
||||||
"""svctask rmvdisk -force <vdisk_name>"""
|
"""svctask rmvdisk -force <vdisk_name>"""
|
||||||
|
|
||||||
@ -1270,3 +1288,78 @@ class FlashSystemDriverTestCase(test.TestCase):
|
|||||||
|
|
||||||
# case 4: If there is no vdisk mapped to host, host should be removed
|
# case 4: If there is no vdisk mapped to host, host should be removed
|
||||||
self.assertIsNone(self.driver._get_host_from_connector(self.connector))
|
self.assertIsNone(self.driver._get_host_from_connector(self.connector))
|
||||||
|
|
||||||
|
def test_flashsystem_manage_existing(self):
|
||||||
|
# case 1: manage a vdisk good path
|
||||||
|
kwargs = {'name': u'unmanage-vol-01', 'size': u'1', 'unit': 'gb'}
|
||||||
|
self.sim._cmd_mkvdisk(**kwargs)
|
||||||
|
vol1 = self._generate_vol_info(None)
|
||||||
|
existing_ref = {'source-name': u'unmanage-vol-01'}
|
||||||
|
self.driver.manage_existing(vol1, existing_ref)
|
||||||
|
self.driver.delete_volume(vol1)
|
||||||
|
|
||||||
|
# case 2: manage a vdisk not exist
|
||||||
|
vol1 = self._generate_vol_info(None)
|
||||||
|
existing_ref = {'source-name': u'unmanage-vol-01'}
|
||||||
|
self.assertRaises(exception.ManageExistingInvalidReference,
|
||||||
|
self.driver.manage_existing, vol1, existing_ref)
|
||||||
|
|
||||||
|
# case 3: manage a vdisk without name and uid
|
||||||
|
kwargs = {'name': u'unmanage-vol-01', 'size': u'1', 'unit': 'gb'}
|
||||||
|
self.sim._cmd_mkvdisk(**kwargs)
|
||||||
|
vol1 = self._generate_vol_info(None)
|
||||||
|
existing_ref = {}
|
||||||
|
self.assertRaises(exception.ManageExistingInvalidReference,
|
||||||
|
self.driver.manage_existing, vol1, existing_ref)
|
||||||
|
vdisk1 = {'obj': u'unmanage-vol-01'}
|
||||||
|
self.sim._cmd_rmvdisk(**vdisk1)
|
||||||
|
|
||||||
|
@mock.patch.object(flashsystem_fc.FlashSystemFCDriver,
|
||||||
|
'_get_vdiskhost_mappings')
|
||||||
|
def test_flashsystem_manage_existing_get_size_mapped(
|
||||||
|
self,
|
||||||
|
_get_vdiskhost_mappings_mock):
|
||||||
|
# manage a vdisk with mappings
|
||||||
|
_get_vdiskhost_mappings_mock.return_value = {'mapped': u'yes'}
|
||||||
|
kwargs = {'name': u'unmanage-vol-01', 'size': u'1', 'unit': 'gb'}
|
||||||
|
self.sim._cmd_mkvdisk(**kwargs)
|
||||||
|
vol1 = self._generate_vol_info(None)
|
||||||
|
existing_ref = {'source-name': u'unmanage-vol-01'}
|
||||||
|
self.assertRaises(exception.ManageExistingInvalidReference,
|
||||||
|
self.driver.manage_existing_get_size,
|
||||||
|
vol1,
|
||||||
|
existing_ref)
|
||||||
|
|
||||||
|
# clean environment
|
||||||
|
vdisk1 = {'obj': u'unmanage-vol-01'}
|
||||||
|
self.sim._cmd_rmvdisk(**vdisk1)
|
||||||
|
|
||||||
|
def test_flashsystem_manage_existing_get_size_bad_ref(self):
|
||||||
|
# bad existing_ref
|
||||||
|
vol1 = self._generate_vol_info(None, None)
|
||||||
|
existing_ref = {}
|
||||||
|
self.assertRaises(exception.ManageExistingInvalidReference,
|
||||||
|
self.driver.manage_existing_get_size, vol1,
|
||||||
|
existing_ref)
|
||||||
|
|
||||||
|
def test_flashsystem_manage_existing_get_size_vdisk_not_exist(self):
|
||||||
|
# vdisk not exist
|
||||||
|
vol1 = self._generate_vol_info(None)
|
||||||
|
existing_ref = {'source-name': u'unmanage-vol-01'}
|
||||||
|
self.assertRaises(exception.ManageExistingInvalidReference,
|
||||||
|
self.driver.manage_existing_get_size,
|
||||||
|
vol1,
|
||||||
|
existing_ref)
|
||||||
|
|
||||||
|
def test_flashsystem_manage_existing_get_size(self):
|
||||||
|
# good path
|
||||||
|
kwargs = {'name': u'unmanage-vol-01', 'size': u'10001', 'unit': 'gb'}
|
||||||
|
self.sim._cmd_mkvdisk(**kwargs)
|
||||||
|
vol1 = self._generate_vol_info(None)
|
||||||
|
existing_ref = {'source-name': u'unmanage-vol-01'}
|
||||||
|
vdisk_size = self.driver.manage_existing_get_size(vol1, existing_ref)
|
||||||
|
self.assertEqual(10001, vdisk_size)
|
||||||
|
|
||||||
|
# clean environment
|
||||||
|
vdisk1 = {'obj': u'unmanage-vol-01'}
|
||||||
|
self.sim._cmd_rmvdisk(**vdisk1)
|
||||||
|
@ -344,3 +344,78 @@ class FlashSystemISCSIDriverTestCase(test.TestCase):
|
|||||||
self.driver._delete_host(host2)
|
self.driver._delete_host(host2)
|
||||||
self.sim.set_protocol('iSCSI')
|
self.sim.set_protocol('iSCSI')
|
||||||
self._reset_flags()
|
self._reset_flags()
|
||||||
|
|
||||||
|
def test_flashsystem_manage_existing(self):
|
||||||
|
# case 1: manage a vdisk good path
|
||||||
|
kwargs = {'name': u'unmanage-vol-01', 'size': u'1', 'unit': 'gb'}
|
||||||
|
self.sim._cmd_mkvdisk(**kwargs)
|
||||||
|
vol1 = self._generate_vol_info(None)
|
||||||
|
existing_ref = {'source-name': u'unmanage-vol-01'}
|
||||||
|
self.driver.manage_existing(vol1, existing_ref)
|
||||||
|
self.driver.delete_volume(vol1)
|
||||||
|
|
||||||
|
# case 2: manage a vdisk not exist
|
||||||
|
vol1 = self._generate_vol_info(None)
|
||||||
|
existing_ref = {'source-name': u'unmanage-vol-01'}
|
||||||
|
self.assertRaises(exception.ManageExistingInvalidReference,
|
||||||
|
self.driver.manage_existing, vol1, existing_ref)
|
||||||
|
|
||||||
|
# case 3: manage a vdisk without name and uid
|
||||||
|
kwargs = {'name': u'unmanage-vol-01', 'size': u'1', 'unit': 'gb'}
|
||||||
|
self.sim._cmd_mkvdisk(**kwargs)
|
||||||
|
vol1 = self._generate_vol_info(None)
|
||||||
|
existing_ref = {}
|
||||||
|
self.assertRaises(exception.ManageExistingInvalidReference,
|
||||||
|
self.driver.manage_existing, vol1, existing_ref)
|
||||||
|
vdisk1 = {'obj': u'unmanage-vol-01'}
|
||||||
|
self.sim._cmd_rmvdisk(**vdisk1)
|
||||||
|
|
||||||
|
@mock.patch.object(flashsystem_iscsi.FlashSystemISCSIDriver,
|
||||||
|
'_get_vdiskhost_mappings')
|
||||||
|
def test_flashsystem_manage_existing_get_size_mapped(
|
||||||
|
self,
|
||||||
|
_get_vdiskhost_mappings_mock):
|
||||||
|
# case 2: manage a vdisk with mappings
|
||||||
|
_get_vdiskhost_mappings_mock.return_value = {'mapped': u'yes'}
|
||||||
|
kwargs = {'name': u'unmanage-vol-01', 'size': u'1', 'unit': 'gb'}
|
||||||
|
self.sim._cmd_mkvdisk(**kwargs)
|
||||||
|
vol1 = self._generate_vol_info(None)
|
||||||
|
existing_ref = {'source-name': u'unmanage-vol-01'}
|
||||||
|
self.assertRaises(exception.ManageExistingInvalidReference,
|
||||||
|
self.driver.manage_existing_get_size,
|
||||||
|
vol1,
|
||||||
|
existing_ref)
|
||||||
|
|
||||||
|
# clean environment
|
||||||
|
vdisk1 = {'obj': u'unmanage-vol-01'}
|
||||||
|
self.sim._cmd_rmvdisk(**vdisk1)
|
||||||
|
|
||||||
|
def test_flashsystem_manage_existing_get_size_bad_ref(self):
|
||||||
|
# bad existing_ref
|
||||||
|
vol1 = self._generate_vol_info(None, None)
|
||||||
|
existing_ref = {}
|
||||||
|
self.assertRaises(exception.ManageExistingInvalidReference,
|
||||||
|
self.driver.manage_existing_get_size, vol1,
|
||||||
|
existing_ref)
|
||||||
|
|
||||||
|
def test_flashsystem_manage_existing_get_size_vdisk_not_exist(self):
|
||||||
|
# vdisk not exist
|
||||||
|
vol1 = self._generate_vol_info(None)
|
||||||
|
existing_ref = {'source-name': u'unmanage-vol-01'}
|
||||||
|
self.assertRaises(exception.ManageExistingInvalidReference,
|
||||||
|
self.driver.manage_existing_get_size,
|
||||||
|
vol1,
|
||||||
|
existing_ref)
|
||||||
|
|
||||||
|
def test_flashsystem_manage_existing_get_size(self):
|
||||||
|
# good path
|
||||||
|
kwargs = {'name': u'unmanage-vol-01', 'size': u'10001', 'unit': 'gb'}
|
||||||
|
self.sim._cmd_mkvdisk(**kwargs)
|
||||||
|
vol1 = self._generate_vol_info(None)
|
||||||
|
existing_ref = {'source-name': u'unmanage-vol-01'}
|
||||||
|
vdisk_size = self.driver.manage_existing_get_size(vol1, existing_ref)
|
||||||
|
self.assertEqual(10001, vdisk_size)
|
||||||
|
|
||||||
|
# clean environment
|
||||||
|
vdisk1 = {'obj': u'unmanage-vol-01'}
|
||||||
|
self.sim._cmd_rmvdisk(**vdisk1)
|
||||||
|
@ -64,6 +64,7 @@ CONF.register_opts(flashsystem_opts)
|
|||||||
|
|
||||||
|
|
||||||
class FlashSystemDriver(san.SanDriver,
|
class FlashSystemDriver(san.SanDriver,
|
||||||
|
driver.ManageableVD,
|
||||||
driver.TransferVD,
|
driver.TransferVD,
|
||||||
driver.ExtendVD,
|
driver.ExtendVD,
|
||||||
driver.SnapshotVD,
|
driver.SnapshotVD,
|
||||||
@ -92,9 +93,11 @@ class FlashSystemDriver(san.SanDriver,
|
|||||||
1.0.10 - Fix bug #1585085, add host name check in
|
1.0.10 - Fix bug #1585085, add host name check in
|
||||||
_find_host_exhaustive for iSCSI
|
_find_host_exhaustive for iSCSI
|
||||||
1.0.11 - Update driver to use ABC metaclasses
|
1.0.11 - Update driver to use ABC metaclasses
|
||||||
|
1.0.12 - Update driver to support Manage/Unmanage
|
||||||
|
existing volume
|
||||||
"""
|
"""
|
||||||
|
|
||||||
VERSION = "1.0.11"
|
VERSION = "1.0.12"
|
||||||
|
|
||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
super(FlashSystemDriver, self).__init__(*args, **kwargs)
|
super(FlashSystemDriver, self).__init__(*args, **kwargs)
|
||||||
@ -542,15 +545,17 @@ class FlashSystemDriver(san.SanDriver,
|
|||||||
except KeyError:
|
except KeyError:
|
||||||
self._handle_keyerror('lsnode', header)
|
self._handle_keyerror('lsnode', header)
|
||||||
|
|
||||||
def _get_vdisk_attributes(self, vdisk_name):
|
def _get_vdisk_attributes(self, vdisk_ref):
|
||||||
"""Return vdisk attributes
|
"""Return vdisk attributes
|
||||||
|
|
||||||
Exception is raised if the information from system can not be
|
Exception is raised if the information from system can not be
|
||||||
parsed/matched to a single vdisk.
|
parsed/matched to a single vdisk.
|
||||||
|
|
||||||
|
:param vdisk_ref: vdisk name or vdisk id
|
||||||
"""
|
"""
|
||||||
|
|
||||||
ssh_cmd = [
|
ssh_cmd = [
|
||||||
'svcinfo', 'lsvdisk', '-bytes', '-delim', '!', vdisk_name]
|
'svcinfo', 'lsvdisk', '-bytes', '-delim', '!', vdisk_ref]
|
||||||
|
|
||||||
return self._execute_command_and_parse_attributes(ssh_cmd)
|
return self._execute_command_and_parse_attributes(ssh_cmd)
|
||||||
|
|
||||||
@ -700,6 +705,27 @@ class FlashSystemDriver(san.SanDriver,
|
|||||||
'out': six.text_type(out),
|
'out': six.text_type(out),
|
||||||
'err': six.text_type(err)})
|
'err': six.text_type(err)})
|
||||||
|
|
||||||
|
def _manage_input_check(self, existing_ref):
|
||||||
|
"""Verify the input of manage function."""
|
||||||
|
# Check that the reference is valid
|
||||||
|
if 'source-name' in existing_ref:
|
||||||
|
manage_source = existing_ref['source-name']
|
||||||
|
vdisk = self._get_vdisk_attributes(manage_source)
|
||||||
|
elif 'source-id' in existing_ref:
|
||||||
|
manage_source = existing_ref['source-id']
|
||||||
|
vdisk = self._get_vdisk_attributes(manage_source)
|
||||||
|
else:
|
||||||
|
reason = _('Reference must contain source-id or '
|
||||||
|
'source-name element.')
|
||||||
|
raise exception.ManageExistingInvalidReference(
|
||||||
|
existing_ref=existing_ref, reason=reason)
|
||||||
|
if vdisk is None:
|
||||||
|
reason = (_('No vdisk with the ID specified by ref %s.')
|
||||||
|
% manage_source)
|
||||||
|
raise exception.ManageExistingInvalidReference(
|
||||||
|
existing_ref=existing_ref, reason=reason)
|
||||||
|
return vdisk
|
||||||
|
|
||||||
@utils.synchronized('flashsystem-map', external=True)
|
@utils.synchronized('flashsystem-map', external=True)
|
||||||
def _map_vdisk_to_host(self, vdisk_name, connector):
|
def _map_vdisk_to_host(self, vdisk_name, connector):
|
||||||
"""Create a mapping between a vdisk to a host."""
|
"""Create a mapping between a vdisk to a host."""
|
||||||
@ -801,6 +827,26 @@ class FlashSystemDriver(san.SanDriver,
|
|||||||
|
|
||||||
LOG.debug('leave: _remove_device')
|
LOG.debug('leave: _remove_device')
|
||||||
|
|
||||||
|
def _rename_vdisk(self, vdisk_name, new_name):
|
||||||
|
"""Rename vdisk"""
|
||||||
|
# Try to rename volume only if found on the storage
|
||||||
|
vdisk_defined = self._is_vdisk_defined(vdisk_name)
|
||||||
|
if not vdisk_defined:
|
||||||
|
LOG.warning(_LW('warning: Tried to rename vdisk %s but '
|
||||||
|
'it does not exist.'), vdisk_name)
|
||||||
|
return
|
||||||
|
ssh_cmd = [
|
||||||
|
'svctask', 'chvdisk', '-name', new_name, vdisk_name]
|
||||||
|
out, err = self._ssh(ssh_cmd)
|
||||||
|
# No output should be returned from chvdisk
|
||||||
|
self._assert_ssh_return(
|
||||||
|
(not out.strip()),
|
||||||
|
'_rename_vdisk %(name)s' % {'name': vdisk_name},
|
||||||
|
ssh_cmd, out, err)
|
||||||
|
|
||||||
|
LOG.info(_LI('Renamed %(vdisk)s to %(newname)s .'),
|
||||||
|
{'vdisk': vdisk_name, 'newname': new_name})
|
||||||
|
|
||||||
def _scan_device(self, properties):
|
def _scan_device(self, properties):
|
||||||
LOG.debug('enter: _scan_device')
|
LOG.debug('enter: _scan_device')
|
||||||
|
|
||||||
@ -1110,3 +1156,32 @@ class FlashSystemDriver(san.SanDriver,
|
|||||||
self._update_volume_stats()
|
self._update_volume_stats()
|
||||||
|
|
||||||
return self._stats
|
return self._stats
|
||||||
|
|
||||||
|
def manage_existing(self, volume, existing_ref):
|
||||||
|
"""Manages an existing vdisk.
|
||||||
|
|
||||||
|
Renames the vdisk to match the expected name for the volume.
|
||||||
|
"""
|
||||||
|
LOG.debug('enter: manage_existing: volume %(vol)s ref %(ref)s.',
|
||||||
|
{'vol': volume, 'ref': existing_ref})
|
||||||
|
vdisk = self._manage_input_check(existing_ref)
|
||||||
|
new_name = 'volume-' + volume['id']
|
||||||
|
self._rename_vdisk(vdisk['name'], new_name)
|
||||||
|
LOG.debug('leave: manage_existing: volume %(vol)s ref %(ref)s.',
|
||||||
|
{'vol': volume, 'ref': existing_ref})
|
||||||
|
return
|
||||||
|
|
||||||
|
def manage_existing_get_size(self, volume, existing_ref):
|
||||||
|
"""Return size of volume to be managed by manage_existing."""
|
||||||
|
vdisk = self._manage_input_check(existing_ref)
|
||||||
|
if self._get_vdiskhost_mappings(vdisk['name']):
|
||||||
|
reason = _('The specified vdisk is mapped to a host.')
|
||||||
|
raise exception.ManageExistingInvalidReference(
|
||||||
|
existing_ref=existing_ref, reason=reason)
|
||||||
|
return int(vdisk['capacity']) / units.Gi
|
||||||
|
|
||||||
|
def unmanage(self, volume):
|
||||||
|
"""Removes the specified volume from Cinder management."""
|
||||||
|
LOG.debug('unmanage: volume %(vol)s is no longer managed by cinder.',
|
||||||
|
{'vol': volume})
|
||||||
|
pass
|
||||||
|
@ -79,9 +79,11 @@ class FlashSystemFCDriver(fscommon.FlashSystemDriver):
|
|||||||
1.0.10 - Fix bug #1585085, add host name check in
|
1.0.10 - Fix bug #1585085, add host name check in
|
||||||
_find_host_exhaustive for iSCSI
|
_find_host_exhaustive for iSCSI
|
||||||
1.0.11 - Update driver to use ABC metaclasses
|
1.0.11 - Update driver to use ABC metaclasses
|
||||||
|
1.0.12 - Update driver to support Manage/Unmanage
|
||||||
|
existing volume
|
||||||
"""
|
"""
|
||||||
|
|
||||||
VERSION = "1.0.11"
|
VERSION = "1.0.12"
|
||||||
|
|
||||||
# ThirdPartySystems wiki page
|
# ThirdPartySystems wiki page
|
||||||
CI_WIKI_NAME = "IBM_FlashSystem_CI"
|
CI_WIKI_NAME = "IBM_FlashSystem_CI"
|
||||||
|
@ -77,9 +77,11 @@ class FlashSystemISCSIDriver(fscommon.FlashSystemDriver):
|
|||||||
1.0.10 - Fix bug #1585085, add host name check in
|
1.0.10 - Fix bug #1585085, add host name check in
|
||||||
_find_host_exhaustive for iSCSI
|
_find_host_exhaustive for iSCSI
|
||||||
1.0.11 - Update driver to use ABC metaclasses
|
1.0.11 - Update driver to use ABC metaclasses
|
||||||
|
1.0.12 - Update driver to support Manage/Unmanage
|
||||||
|
existing volume
|
||||||
"""
|
"""
|
||||||
|
|
||||||
VERSION = "1.0.11"
|
VERSION = "1.0.12"
|
||||||
|
|
||||||
# ThirdPartySystems wiki page
|
# ThirdPartySystems wiki page
|
||||||
CI_WIKI_NAME = "IBM_FlashSystem_CI"
|
CI_WIKI_NAME = "IBM_FlashSystem_CI"
|
||||||
|
@ -0,0 +1,4 @@
|
|||||||
|
---
|
||||||
|
features:
|
||||||
|
- Volume manage/unmanage support for IBM FlashSystem FC and iSCSI drivers.
|
||||||
|
|
Loading…
Reference in New Issue
Block a user