Merge "ZFSSA iSCSI implement get_manageable_volumes()"
This commit is contained in:
commit
5abe7c7fb4
@ -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):
|
||||
|
@ -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.
|
||||
|
||||
|
@ -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."""
|
||||
|
@ -0,0 +1,3 @@
|
||||
---
|
||||
features:
|
||||
- Oracle ZFSSA iSCSI volume driver implements ``get_manageable_volumes()``
|
Loading…
Reference in New Issue
Block a user