Merge "ZFSSA iSCSI implement get_manageable_volumes()"

This commit is contained in:
Zuul 2018-09-26 03:11:46 +00:00 committed by Gerrit Code Review
commit 5abe7c7fb4
4 changed files with 159 additions and 35 deletions

View File

@ -966,6 +966,66 @@ class TestZFSSAISCSIDriver(test.TestCase):
lcfg.zfssa_cache_project, lcfg.zfssa_cache_project,
volname) volname)
def test_get_manageable_volumes(self):
lcfg = self.configuration
self.drv.zfssa.get_all_luns.return_value = [
{'name': 'volume-11111111-1111-1111-1111-111111111111',
'size': 111 * units.Gi,
'cinder_managed': True},
{'name': 'volume2',
'size': 222 * units.Gi,
'cinder_managed': False},
{'name': 'volume-33333333-3333-3333-3333-333333333333',
'size': 333 * units.Gi,
'cinder_managed': True},
{'name': 'volume4',
'size': 444 * units.Gi}
]
cinder_vols = [{'id': '11111111-1111-1111-1111-111111111111'}]
args = (cinder_vols, None, 1000, 0, ['size'], ['asc'])
lcfg.zfssa_manage_policy = 'strict'
expected = [
{'reference': {'source-name':
'volume-11111111-1111-1111-1111-111111111111'},
'size': 111,
'safe_to_manage': False,
'reason_not_safe': 'already managed',
'cinder_id': '11111111-1111-1111-1111-111111111111',
'extra_info': None},
{'reference': {'source-name': 'volume2'},
'size': 222,
'safe_to_manage': True,
'reason_not_safe': None,
'cinder_id': None,
'extra_info': None},
{'reference': {'source-name':
'volume-33333333-3333-3333-3333-333333333333'},
'size': 333,
'safe_to_manage': False,
'reason_not_safe': 'managed by another cinder instance?',
'cinder_id': None,
'extra_info': None},
{'reference': {'source-name': 'volume4'},
'size': 444,
'safe_to_manage': False,
'reason_not_safe': 'cinder_managed schema not present',
'cinder_id': None,
'extra_info': None},
]
result = self.drv.get_manageable_volumes(*args)
self.assertEqual(expected, result)
lcfg.zfssa_manage_policy = 'loose'
expected[3]['safe_to_manage'] = True
expected[3]['reason_not_safe'] = None
result = self.drv.get_manageable_volumes(*args)
self.assertEqual(expected, result)
@mock.patch.object(iscsi.ZFSSAISCSIDriver, '_get_existing_vol') @mock.patch.object(iscsi.ZFSSAISCSIDriver, '_get_existing_vol')
@mock.patch.object(iscsi.ZFSSAISCSIDriver, '_verify_volume_to_manage') @mock.patch.object(iscsi.ZFSSAISCSIDriver, '_verify_volume_to_manage')
def test_volume_manage(self, _get_existing_vol, _verify_volume_to_manage): def test_volume_manage(self, _get_existing_vol, _verify_volume_to_manage):

View File

@ -32,6 +32,7 @@ from cinder.volume import configuration
from cinder.volume import driver from cinder.volume import driver
from cinder.volume.drivers.san import san from cinder.volume.drivers.san import san
from cinder.volume.drivers.zfssa import zfssarest from cinder.volume.drivers.zfssa import zfssarest
from cinder.volume import utils as volume_utils
from cinder.volume import volume_types from cinder.volume import volume_types
import taskflow.engines import taskflow.engines
@ -121,8 +122,10 @@ class ZFSSAISCSIDriver(driver.ISCSIDriver):
Volume manage/unmanage support. Volume manage/unmanage support.
1.0.3: 1.0.3:
Fix multi-connect to enable live-migration (LP#1565051). Fix multi-connect to enable live-migration (LP#1565051).
1.0.4:
Implement get_manageable_volumes().
""" """
VERSION = '1.0.3' VERSION = '1.0.4'
protocol = 'iSCSI' protocol = 'iSCSI'
# ThirdPartySystems wiki page # ThirdPartySystems wiki page
@ -1088,6 +1091,41 @@ class ZFSSAISCSIDriver(driver.ISCSIDriver):
LOG.warning("Volume %s exists but can't be deleted.", LOG.warning("Volume %s exists but can't be deleted.",
cache['share']) cache['share'])
def get_manageable_volumes(self, cinder_volumes, marker, limit, offset,
sort_keys, sort_dirs):
lcfg = self.configuration
manageable_volumes = []
managed_vols = [vol['id'] for vol in cinder_volumes]
for lun in self.zfssa.get_all_luns(lcfg.zfssa_pool,
lcfg.zfssa_project):
lun_info = {
'reference': {'source-name': lun['name']},
'size': int(math.ceil(float(lun['size']) / units.Gi)),
'cinder_id': None,
'extra_info': None,
'safe_to_manage': True,
'reason_not_safe': None,
}
if ('cinder_managed' not in lun and
lcfg.zfssa_manage_policy != 'loose'):
lun_info['safe_to_manage'] = False
lun_info['reason_not_safe'] = 'cinder_managed schema ' \
'not present'
elif lun.get('cinder_managed', False):
lun_info['safe_to_manage'] = False
vol_id = volume_utils.extract_id_from_volume_name(lun['name'])
if vol_id in managed_vols:
lun_info['reason_not_safe'] = 'already managed'
lun_info['cinder_id'] = vol_id
else:
lun_info['reason_not_safe'] = \
'managed by another cinder instance?'
manageable_volumes.append(lun_info)
return volume_utils.paginate_entries_list(
manageable_volumes, marker, limit, offset, sort_keys, sort_dirs)
def manage_existing(self, volume, existing_ref): def manage_existing(self, volume, existing_ref):
"""Manage an existing volume in the ZFSSA backend. """Manage an existing volume in the ZFSSA backend.

View File

@ -754,6 +754,62 @@ class ZFSSAApi(object):
val = json.loads(ret.data) val = json.loads(ret.data)
return val return val
def _canonify_lun_info(self, lun):
def _listify(item):
return item if isinstance(item, list) else [item]
if 'com.sun.ms.vss.hg.maskAll' in lun['initiatorgroup']:
# Hide special maskAll value when LUN is not currently presented
# to any initiatorgroups:
initiatorgroup = []
number = []
else:
# For backward-compatibility with 2013.1.2.x, convert
# initiatorgroup and number to lists if they're not already
initiatorgroup = _listify(lun['initiatorgroup'])
number = _listify(lun['assignednumber'])
canonical = {
'name': lun['name'],
'guid': lun['lunguid'],
'number': number,
'initiatorgroup': initiatorgroup,
'size': lun['volsize'],
'nodestroy': lun['nodestroy'],
'targetgroup': lun['targetgroup']
}
if 'origin' in lun:
canonical['origin'] = lun['origin']
for custom in ['image_id', 'updated_at', 'cinder_managed']:
custom_value = lun.get('custom:' + custom)
if custom_value:
canonical[custom] = custom_value
return canonical
def get_all_luns(self, pool, project):
"""return all luns in project."""
svc = '/api/storage/v1/pools/' + pool + '/projects/' + \
project + "/luns"
ret = self.rclient.get(svc)
if ret.status != restclient.Status.OK:
exception_msg = (_('Error Getting LUNs on '
'Pool: %(pool)s '
'Project: %(project)s '
'Return code: %(ret.status)d '
'Message: %(ret.data)s.')
% {'pool': pool,
'project': project,
'ret.status': ret.status,
'ret.data': ret.data})
LOG.error(exception_msg)
raise exception.VolumeBackendAPIException(data=exception_msg)
canonical = []
for lun in json.loads(ret.data)['luns']:
canonical.append(self._canonify_lun_info(lun))
return canonical
def get_lun(self, pool, project, lun): def get_lun(self, pool, project, lun):
"""return iscsi lun properties.""" """return iscsi lun properties."""
svc = '/api/storage/v1/pools/' + pool + '/projects/' + \ svc = '/api/storage/v1/pools/' + pool + '/projects/' + \
@ -785,40 +841,7 @@ class ZFSSAApi(object):
LOG.error(exception_msg) LOG.error(exception_msg)
raise exception.VolumeBackendAPIException(data=exception_msg) raise exception.VolumeBackendAPIException(data=exception_msg)
val = json.loads(ret.data) return self._canonify_lun_info(json.loads(ret.data)['lun'])
# For backward-compatibility with 2013.1.2.x, convert initiatorgroup
# and number to lists if they're not already
def _listify(item):
return item if isinstance(item, list) else [item]
initiatorgroup = _listify(val['lun']['initiatorgroup'])
number = _listify(val['lun']['assignednumber'])
# Hide special maskAll value when LUN is not currently presented to
# any initiatorgroups:
if 'com.sun.ms.vss.hg.maskAll' in initiatorgroup:
initiatorgroup = []
number = []
ret = {
'name': val['lun']['name'],
'guid': val['lun']['lunguid'],
'number': number,
'initiatorgroup': initiatorgroup,
'size': val['lun']['volsize'],
'nodestroy': val['lun']['nodestroy'],
'targetgroup': val['lun']['targetgroup']
}
if 'origin' in val['lun']:
ret.update({'origin': val['lun']['origin']})
if 'custom:image_id' in val['lun']:
ret.update({'image_id': val['lun']['custom:image_id']})
ret.update({'updated_at': val['lun']['custom:updated_at']})
if 'custom:cinder_managed' in val['lun']:
ret.update({'cinder_managed': val['lun']['custom:cinder_managed']})
return ret
def get_lun_snapshot(self, pool, project, lun, snapshot): def get_lun_snapshot(self, pool, project, lun, snapshot):
"""Return iscsi lun snapshot properties.""" """Return iscsi lun snapshot properties."""

View File

@ -0,0 +1,3 @@
---
features:
- Oracle ZFSSA iSCSI volume driver implements ``get_manageable_volumes()``