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,
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, '_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.drivers.san import san
from cinder.volume.drivers.zfssa import zfssarest
from cinder.volume import utils as volume_utils
from cinder.volume import volume_types
import taskflow.engines
@ -121,8 +122,10 @@ class ZFSSAISCSIDriver(driver.ISCSIDriver):
Volume manage/unmanage support.
1.0.3:
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'
# ThirdPartySystems wiki page
@ -1088,6 +1091,41 @@ class ZFSSAISCSIDriver(driver.ISCSIDriver):
LOG.warning("Volume %s exists but can't be deleted.",
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):
"""Manage an existing volume in the ZFSSA backend.

View File

@ -754,6 +754,62 @@ class ZFSSAApi(object):
val = json.loads(ret.data)
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):
"""return iscsi lun properties."""
svc = '/api/storage/v1/pools/' + pool + '/projects/' + \
@ -785,40 +841,7 @@ class ZFSSAApi(object):
LOG.error(exception_msg)
raise exception.VolumeBackendAPIException(data=exception_msg)
val = json.loads(ret.data)
# 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
return self._canonify_lun_info(json.loads(ret.data)['lun'])
def get_lun_snapshot(self, pool, project, lun, snapshot):
"""Return iscsi lun snapshot properties."""

View File

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