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