Merge "Additional VAG support for SolidFire"
This commit is contained in:
commit
b981262064
@ -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()
|
||||
|
@ -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)
|
||||
|
Loading…
Reference in New Issue
Block a user