Merge "Implement import/export for SolidFire Driver"

This commit is contained in:
Jenkins 2014-08-15 18:59:39 +00:00 committed by Gerrit Code Review
commit da93b87b60
2 changed files with 143 additions and 2 deletions

View File

@ -130,6 +130,21 @@ class SolidFireVolumeTestCase(test.TestCase):
'iqn': test_name}]}}
return result
elif method is 'ListActiveVolumes':
test_name = "existing_volume"
result = {'result': {
'volumes': [{'volumeID': 5,
'name': test_name,
'accountID': 8,
'sliceCount': 1,
'totalSize': 1 * units.Gi,
'enable512e': True,
'access': "readWrite",
'status': "active",
'attributes': {},
'qos': None,
'iqn': test_name}]}}
return result
else:
LOG.error('Crap, unimplemented API call in Fake:%s' % method)
@ -572,3 +587,17 @@ class SolidFireVolumeTestCase(test.TestCase):
sfv._update_cluster_status()
self.assertEqual(sfv.cluster_stats['free_capacity_gb'], 99.0)
self.assertEqual(sfv.cluster_stats['total_capacity_gb'], 100.0)
def test_manage_existing_volume(self):
external_ref = {'name': 'existing volume', 'source-id': 5}
testvol = {'project_id': 'testprjid',
'name': 'testvol',
'size': 1,
'id': 'a720b3c0-d1f0-11e1-9b23-0800200c9a66',
'created_at': timeutils.utcnow()}
self.stubs.Set(SolidFireDriver, '_issue_api_request',
self.fake_issue_api_request)
sfv = SolidFireDriver(configuration=self.configuration)
model_update = sfv.manage_existing(testvol, external_ref)
self.assertIsNotNone(model_update)
self.assertIsNone(model_update.get('provider_geometry', None))

View File

@ -68,10 +68,12 @@ class SolidFireDriver(SanISCSIDriver):
Version history:
1.0 - Initial driver
1.1 - Refactor, clone support, qos by type and minor bug fixes
1.2 - Add xfr and retype support
1.2.1 - Add export/import support
"""
VERSION = '1.2.0'
VERSION = '1.2.1'
sf_qos_dict = {'slow': {'minIOPS': 100,
'maxIOPS': 200,
@ -462,7 +464,13 @@ class SolidFireDriver(SanISCSIDriver):
found_count = 0
sf_volref = None
for v in data['result']['volumes']:
if uuid in v['name']:
# NOTE(jdg): In the case of "name" we can't
# update that on manage/import, so we use
# the uuid attribute
meta = v.get('attributes')
alt_id = meta.get('uuid', 'empty')
if uuid in v['name'] or uuid in alt_id:
found_count += 1
sf_volref = v
LOG.debug("Mapped SolidFire volumeID %(sfid)s "
@ -813,3 +821,107 @@ class SolidFireDriver(SanISCSIDriver):
self._issue_api_request('ModifyVolume', params)
return True
def manage_existing(self, volume, external_ref):
"""Manages an existing SolidFire Volume (import to Cinder).
Renames the Volume to match the expected name for the volume.
Also need to consider things like QoS, Emulation, account/tenant.
"""
sfid = external_ref.get('source-id', None)
sfname = external_ref.get('name', None)
if sfid is None:
raise exception.SolidFireAPIException("Manage existing volume "
"requires 'source-id'.")
# First get the volume on the SF cluster (MUST be active)
params = {'startVolumeID': sfid,
'limit': 1}
data = self._issue_api_request('ListActiveVolumes', params)
if 'result' not in data:
raise exception.SolidFireAPIDataException(data=data)
sf_ref = data['result']['volumes'][0]
sfaccount = self._create_sfaccount(volume['project_id'])
attributes = {}
qos = {}
if (self.configuration.sf_allow_tenant_qos and
volume.get('volume_metadata')is not None):
qos = self._set_qos_presets(volume)
ctxt = context.get_admin_context()
type_id = volume.get('volume_type_id', None)
if type_id is not None:
qos = self._set_qos_by_volume_type(ctxt, type_id)
import_time = timeutils.strtime(volume['created_at'])
attributes = {'uuid': volume['id'],
'is_clone': 'False',
'os_imported_at': import_time,
'old_name': sfname}
if qos:
for k, v in qos.items():
attributes[k] = str(v)
params = {'name': volume['name'],
'volumeID': sf_ref['volumeID'],
'accountID': sfaccount['accountID'],
'enable512e': self.configuration.sf_emulate_512,
'attributes': attributes,
'qos': qos}
data = self._issue_api_request('ModifyVolume',
params, version='5.0')
if 'result' not in data:
raise exception.SolidFireAPIDataException(data=data)
return self._get_model_info(sfaccount, sf_ref['volumeID'])
def manage_existing_get_size(self, volume, external_ref):
"""Return size of an existing LV for manage_existing.
existing_ref is a dictionary of the form:
{'name': <name of existing volume on SF Cluster>}
"""
sfid = external_ref.get('source-id', None)
if sfid is None:
raise exception.SolidFireAPIException("Manage existing get size "
"requires 'id'.")
params = {'startVolumeID': int(sfid),
'limit': 1}
data = self._issue_api_request('ListActiveVolumes', params)
if 'result' not in data:
raise exception.SolidFireAPIDataException(data=data)
sf_ref = data['result']['volumes'][0]
return int(sf_ref['totalSize']) / int(units.Gi)
def unmanage(self, volume):
"""Mark SolidFire Volume as unmanaged (export from Cinder)."""
LOG.debug("Enter SolidFire unmanage...")
sfaccount = self._get_sfaccount(volume['project_id'])
if sfaccount is None:
LOG.error(_("Account for Volume ID %s was not found on "
"the SolidFire Cluster!") % volume['id'])
raise exception.SolidFireAPIException("Failed to find account "
"for volume.")
params = {'accountID': sfaccount['accountID']}
sf_vol = self._get_sf_volume(volume['id'], params)
if sf_vol is None:
raise exception.VolumeNotFound(volume_id=volume['id'])
export_time = timeutils.strtime()
attributes = sf_vol['attributes']
attributes['os_exported_at'] = export_time
params = {'volumeID': int(sf_vol['volumeID']),
'attributes': attributes}
data = self._issue_api_request('ModifyVolume',
params, version='5.0')
if 'result' not in data:
raise exception.SolidFireAPIDataException(data=data)