Merge "Additional VAG support for SolidFire"

This commit is contained in:
Jenkins 2015-11-19 01:40:41 +00:00 committed by Gerrit Code Review
commit b981262064
2 changed files with 126 additions and 0 deletions

View File

@ -1170,3 +1170,79 @@ class SolidFireVolumeTestCase(test.TestCase):
side_effect=add_volume_to_vag_check):
sfv.initialize_connection(testvol, connector)
def test_remove_vag(self):
vag = {'attributes': {},
'deletedVolumes': [],
'initiators': [],
'name': 'TESTIQN',
'volumeAccessGroupID': 1,
'volumes': [1],
'virtualNetworkIDs': []}
testvol = {'project_id': 'testprjid',
'name': 'testvol',
'size': 1,
'id': 'a720b3c0-d1f0-11e1-9b23-0800200c9a66',
'volume_type_id': None,
'provider_location': '10.10.7.1:3260 iqn.2010-01.com.'
'solidfire:87hg.uuid-2cc06226-cc'
'74-4cb7-bd55-14aed659a0cc.4060 0',
'provider_auth': 'CHAP stack-1-a60e2611875f40199931f2'
'c76370d66b 2FE0CQ8J196R',
'provider_geometry': '4096 4096',
'created_at': timeutils.utcnow(),
'provider_id': "1 1 1"
}
connector = {'initiator': 'iqn.2012-07.org.fake:01'}
mod_conf = self.configuration
mod_conf.sf_enable_vag = True
sfv = solidfire.SolidFireDriver(configuration=mod_conf)
with mock.patch.object(sfv,
'_get_vags',
return_value=[vag]), \
mock.patch.object(sfv,
'_remove_vag') as mock_rem_vag:
sfv.terminate_connection(testvol, connector, force=False)
mock_rem_vag.assert_called_with(vag['volumeAccessGroupID'])
def test_remove_volume_from_vag(self):
vag = {'attributes': {},
'deletedVolumes': [],
'initiators': [],
'name': 'TESTIQN',
'volumeAccessGroupID': 1,
'volumes': [1, 2],
'virtualNetworkIDs': []}
testvol = {'project_id': 'testprjid',
'name': 'testvol',
'size': 1,
'id': 'a720b3c0-d1f0-11e1-9b23-0800200c9a66',
'volume_type_id': None,
'provider_location': '10.10.7.1:3260 iqn.2010-01.com.'
'solidfire:87hg.uuid-2cc06226-cc'
'74-4cb7-bd55-14aed659a0cc.4060 0',
'provider_auth': 'CHAP stack-1-a60e2611875f40199931f2'
'c76370d66b 2FE0CQ8J196R',
'provider_geometry': '4096 4096',
'created_at': timeutils.utcnow(),
'provider_id': "1 1 1"
}
connector = {'initiator': 'iqn.2012-07.org.fake:01'}
mod_conf = self.configuration
mod_conf.sf_enable_vag = True
sfv = solidfire.SolidFireDriver(configuration=mod_conf)
provider_id = testvol['provider_id']
vol_id = int(sfv._parse_provider_id_string(provider_id)[0])
with mock.patch.object(sfv,
'_get_vags',
return_value=[vag]), \
mock.patch.object(sfv,
'_remove_vag') as mock_rem_vag, \
mock.patch.object(sfv,
'_remove_volume_from_vag') as mock_rem_vol_vag:
sfv.terminate_connection(testvol, connector, force=False)
mock_rem_vol_vag.assert_called_with(vol_id,
vag['volumeAccessGroupID'])
mock_rem_vag.assert_not_called()

View File

@ -858,6 +858,19 @@ class SolidFireDriver(san.SanISCSIDriver):
params,
version='7.0')
def _remove_volume_from_vag(self, vol_id, vag_id):
params = {"volumeAccessGroupID": vag_id,
"volumes": [vol_id]}
self._issue_api_request('RemoveVolumesFromVolumeAccessGroup',
params,
version='7.0')
def _remove_vag(self, vag_id):
params = {"volumeAccessGroupID": vag_id}
self._issue_api_request('DeleteVolumeAccessGroup',
params,
version='7.0')
def clone_image(self, context,
volume, image_location,
image_meta, image_service):
@ -1165,6 +1178,11 @@ class SolidFireDriver(san.SanISCSIDriver):
self._issue_api_request('ModifyVolume', params)
def terminate_connection(self, volume, properties, force):
return self._sf_terminate_connection(volume,
properties,
force)
def detach_volume(self, context, volume, attachment=None):
sfaccount = self._get_sfaccount(volume['project_id'])
params = {'accountID': sfaccount['accountID']}
@ -1404,6 +1422,13 @@ class SolidFireISCSI(iscsi_driver.SanISCSITarget):
vag_id = self._create_vag(vag_name)
vag = self._get_vags(vag_name)[0]
# TODO(chrismorrell): There is a potential race condition if a
# volume is attached and another is detached on the same
# host/initiator. The detach may purge the VAG before the attach
# has a chance to add the volume to the VAG. Propose combining
# add_initiator_to_vag and add_volume_to_vag with a retry on
# SFAPI exception regarding nonexistent VAG.
# Verify IQN matches.
if raw_iqn not in vag['initiators']:
self._add_initiator_to_vag(raw_iqn,
@ -1415,3 +1440,28 @@ class SolidFireISCSI(iscsi_driver.SanISCSITarget):
# Continue along with default behavior
return super(SolidFireISCSI, self).initialize_connection(volume,
connector)
def _sf_terminate_connection(self, volume, properties, force):
"""Terminate the volume connection.
Optionally remove volume from volume access group.
If the VAG is empty then the VAG is also removed.
"""
if self.configuration.sf_enable_vag:
raw_iqn = properties['initiator']
vag_name = re.sub('[^0-9a-zA-Z]+', '-', raw_iqn)
vag = self._get_vags(vag_name)
provider_id = volume['provider_id']
vol_id = int(self._parse_provider_id_string(provider_id)[0])
if vag:
vag = vag[0]
vag_id = vag['volumeAccessGroupID']
if [vol_id] == vag['volumes']:
self._remove_vag(vag_id)
elif vol_id in vag['volumes']:
self._remove_volume_from_vag(vol_id, vag_id)
return super(SolidFireISCSI, self).terminate_connection(volume,
properties,
force=force)