Merge "Dell SC: Error attaching after LV-AFO"
This commit is contained in:
commit
860c183e82
|
@ -262,7 +262,8 @@ class DellSCSanFCDriverTestCase(test.TestCase):
|
|||
sclivevol = {'instanceId': '101.101',
|
||||
'secondaryVolume': {'instanceId': '102.101',
|
||||
'instanceName': fake.VOLUME_ID},
|
||||
'secondaryScSerialNumber': 102}
|
||||
'secondaryScSerialNumber': 102,
|
||||
'secondaryRole': 'Secondary'}
|
||||
mock_is_live_volume.return_value = True
|
||||
mock_find_wwns.return_value = (
|
||||
1, [u'5000D31000FCBE3D', u'5000D31000FCBE35'],
|
||||
|
@ -272,7 +273,7 @@ class DellSCSanFCDriverTestCase(test.TestCase):
|
|||
1, [u'5000D31000FCBE3E', u'5000D31000FCBE36'],
|
||||
{u'21000024FF30441E': [u'5000D31000FCBE36'],
|
||||
u'21000024FF30441F': [u'5000D31000FCBE3E']})
|
||||
mock_get_live_volume.return_value = (sclivevol, False)
|
||||
mock_get_live_volume.return_value = sclivevol
|
||||
res = self.driver.initialize_connection(volume, connector)
|
||||
expected = {'data':
|
||||
{'discard': True,
|
||||
|
@ -292,6 +293,74 @@ class DellSCSanFCDriverTestCase(test.TestCase):
|
|||
mock_find_volume.assert_called_once_with(fake.VOLUME_ID, None, True)
|
||||
mock_get_volume.assert_called_once_with(self.VOLUME[u'instanceId'])
|
||||
|
||||
@mock.patch.object(dell_storagecenter_api.StorageCenterApi,
|
||||
'find_server',
|
||||
return_value=SCSERVER)
|
||||
@mock.patch.object(dell_storagecenter_api.StorageCenterApi,
|
||||
'find_volume')
|
||||
@mock.patch.object(dell_storagecenter_api.StorageCenterApi,
|
||||
'get_volume')
|
||||
@mock.patch.object(dell_storagecenter_api.StorageCenterApi,
|
||||
'map_volume',
|
||||
return_value=MAPPING)
|
||||
@mock.patch.object(dell_storagecenter_fc.DellStorageCenterFCDriver,
|
||||
'_is_live_vol')
|
||||
@mock.patch.object(dell_storagecenter_api.StorageCenterApi,
|
||||
'find_wwns')
|
||||
@mock.patch.object(dell_storagecenter_fc.DellStorageCenterFCDriver,
|
||||
'initialize_secondary')
|
||||
@mock.patch.object(dell_storagecenter_api.StorageCenterApi,
|
||||
'get_live_volume')
|
||||
def test_initialize_connection_live_vol_afo(self,
|
||||
mock_get_live_volume,
|
||||
mock_initialize_secondary,
|
||||
mock_find_wwns,
|
||||
mock_is_live_volume,
|
||||
mock_map_volume,
|
||||
mock_get_volume,
|
||||
mock_find_volume,
|
||||
mock_find_server,
|
||||
mock_close_connection,
|
||||
mock_open_connection,
|
||||
mock_init):
|
||||
volume = {'id': fake.VOLUME_ID, 'provider_id': '101.101'}
|
||||
scvol = {'instanceId': '102.101'}
|
||||
mock_find_volume.return_value = scvol
|
||||
mock_get_volume.return_value = scvol
|
||||
connector = self.connector
|
||||
sclivevol = {'instanceId': '101.10001',
|
||||
'primaryVolume': {'instanceId': '102.101',
|
||||
'instanceName': fake.VOLUME_ID},
|
||||
'primaryScSerialNumber': 102,
|
||||
'secondaryVolume': {'instanceId': '101.101',
|
||||
'instanceName': fake.VOLUME_ID},
|
||||
'secondaryScSerialNumber': 101,
|
||||
'secondaryRole': 'Activated'}
|
||||
|
||||
mock_is_live_volume.return_value = True
|
||||
mock_find_wwns.return_value = (
|
||||
1, [u'5000D31000FCBE3D', u'5000D31000FCBE35'],
|
||||
{u'21000024FF30441C': [u'5000D31000FCBE35'],
|
||||
u'21000024FF30441D': [u'5000D31000FCBE3D']})
|
||||
mock_get_live_volume.return_value = sclivevol
|
||||
res = self.driver.initialize_connection(volume, connector)
|
||||
expected = {'data':
|
||||
{'discard': True,
|
||||
'initiator_target_map':
|
||||
{u'21000024FF30441C': [u'5000D31000FCBE35'],
|
||||
u'21000024FF30441D': [u'5000D31000FCBE3D']},
|
||||
'target_discovered': True,
|
||||
'target_lun': 1,
|
||||
'target_wwn': [u'5000D31000FCBE3D', u'5000D31000FCBE35']},
|
||||
'driver_volume_type': 'fibre_channel'}
|
||||
|
||||
self.assertEqual(expected, res, 'Unexpected return data')
|
||||
# verify find_volume has been called and that is has been called twice
|
||||
self.assertFalse(mock_initialize_secondary.called)
|
||||
mock_find_volume.assert_called_once_with(
|
||||
fake.VOLUME_ID, '101.101', True)
|
||||
mock_get_volume.assert_called_once_with('102.101')
|
||||
|
||||
@mock.patch.object(dell_storagecenter_api.StorageCenterApi,
|
||||
'find_server',
|
||||
return_value=SCSERVER)
|
||||
|
@ -581,11 +650,7 @@ class DellSCSanFCDriverTestCase(test.TestCase):
|
|||
volume = {'id': fake.VOLUME_ID}
|
||||
connector = self.connector
|
||||
mock_terminate_secondary.return_value = (None, [], {})
|
||||
sclivevol = {'instanceId': '101.101',
|
||||
'secondaryVolume': {'instanceId': '102.101',
|
||||
'instanceName': fake.VOLUME_ID},
|
||||
'secondaryScSerialNumber': 102}
|
||||
mock_is_live_vol.return_value = sclivevol
|
||||
mock_is_live_vol.return_value = True
|
||||
res = self.driver.terminate_connection(volume, connector)
|
||||
mock_unmap_volume.assert_called_once_with(self.VOLUME, self.SCSERVER)
|
||||
expected = {'driver_volume_type': 'fibre_channel',
|
||||
|
|
|
@ -518,9 +518,9 @@ class DellSCSanISCSIDriverTestCase(test.TestCase):
|
|||
sclivevol = {'instanceId': '101.101',
|
||||
'secondaryVolume': {'instanceId': '102.101',
|
||||
'instanceName': fake.VOLUME_ID},
|
||||
'secondaryScSerialNumber': 102}
|
||||
mock_api.get_live_volume = mock.MagicMock(return_value=(sclivevol,
|
||||
False))
|
||||
'secondaryScSerialNumber': 102,
|
||||
'secondaryRole': 'Secondary'}
|
||||
mock_api.get_live_volume = mock.MagicMock(return_value=sclivevol)
|
||||
# No replication driver data.
|
||||
ret = self.driver._delete_live_volume(mock_api, vol)
|
||||
self.assertFalse(ret)
|
||||
|
@ -538,7 +538,7 @@ class DellSCSanISCSIDriverTestCase(test.TestCase):
|
|||
ret = self.driver._delete_live_volume(mock_api, vol)
|
||||
self.assertFalse(ret)
|
||||
# No live volume found.
|
||||
mock_api.get_live_volume.return_value = (None, False)
|
||||
mock_api.get_live_volume.return_value = None
|
||||
ret = self.driver._delete_live_volume(mock_api, vol)
|
||||
self.assertFalse(ret)
|
||||
|
||||
|
@ -786,7 +786,8 @@ class DellSCSanISCSIDriverTestCase(test.TestCase):
|
|||
data = self.driver.initialize_connection(volume, connector)
|
||||
self.assertEqual('iscsi', data['driver_volume_type'])
|
||||
# verify find_volume has been called and that is has been called twice
|
||||
mock_find_volume.assert_called_once_with(fake.VOLUME_ID, provider_id)
|
||||
mock_find_volume.assert_called_once_with(
|
||||
fake.VOLUME_ID, provider_id, False)
|
||||
mock_get_volume.assert_called_once_with(provider_id)
|
||||
expected = {'data': self.ISCSI_PROPERTIES,
|
||||
'driver_volume_type': 'iscsi'}
|
||||
|
@ -990,11 +991,7 @@ class DellSCSanISCSIDriverTestCase(test.TestCase):
|
|||
mock_init):
|
||||
volume = {'id': fake.VOLUME_ID}
|
||||
connector = self.connector
|
||||
sclivevol = {'instanceId': '101.101',
|
||||
'secondaryVolume': {'instanceId': '102.101',
|
||||
'instanceName': fake.VOLUME_ID},
|
||||
'secondaryScSerialNumber': 102}
|
||||
mock_is_live_vol.return_value = sclivevol
|
||||
mock_is_live_vol.return_value = True
|
||||
lvol_properties = {'access_mode': 'rw',
|
||||
'target_discovered': False,
|
||||
'target_iqn':
|
||||
|
@ -1018,6 +1015,75 @@ class DellSCSanISCSIDriverTestCase(test.TestCase):
|
|||
'driver_volume_type': 'iscsi'}
|
||||
self.assertEqual(expected, ret)
|
||||
|
||||
@mock.patch.object(dell_storagecenter_api.StorageCenterApi,
|
||||
'find_server',
|
||||
return_value=None)
|
||||
@mock.patch.object(dell_storagecenter_api.StorageCenterApi,
|
||||
'create_server',
|
||||
return_value=SCSERVER)
|
||||
@mock.patch.object(dell_storagecenter_api.StorageCenterApi,
|
||||
'find_volume')
|
||||
@mock.patch.object(dell_storagecenter_api.StorageCenterApi,
|
||||
'get_volume')
|
||||
@mock.patch.object(dell_storagecenter_api.StorageCenterApi,
|
||||
'map_volume',
|
||||
return_value=MAPPINGS[0])
|
||||
@mock.patch.object(dell_storagecenter_api.StorageCenterApi,
|
||||
'find_iscsi_properties')
|
||||
@mock.patch.object(dell_storagecenter_api.StorageCenterApi,
|
||||
'get_live_volume')
|
||||
@mock.patch.object(dell_storagecenter_iscsi.DellStorageCenterISCSIDriver,
|
||||
'_is_live_vol')
|
||||
@mock.patch.object(dell_storagecenter_iscsi.DellStorageCenterISCSIDriver,
|
||||
'initialize_secondary')
|
||||
def test_initialize_connection_live_volume_afo(self,
|
||||
mock_initialize_secondary,
|
||||
mock_is_live_vol,
|
||||
mock_get_live_vol,
|
||||
mock_find_iscsi_props,
|
||||
mock_map_volume,
|
||||
mock_get_volume,
|
||||
mock_find_volume,
|
||||
mock_create_server,
|
||||
mock_find_server,
|
||||
mock_close_connection,
|
||||
mock_open_connection,
|
||||
mock_init):
|
||||
volume = {'id': fake.VOLUME_ID, 'provider_id': '101.101'}
|
||||
scvol = {'instanceId': '102.101'}
|
||||
mock_find_volume.return_value = scvol
|
||||
mock_get_volume.return_value = scvol
|
||||
connector = self.connector
|
||||
sclivevol = {'instanceId': '101.10001',
|
||||
'primaryVolume': {'instanceId': '101.101',
|
||||
'instanceName': fake.VOLUME_ID},
|
||||
'primaryScSerialNumber': 101,
|
||||
'secondaryVolume': {'instanceId': '102.101',
|
||||
'instanceName': fake.VOLUME_ID},
|
||||
'secondaryScSerialNumber': 102,
|
||||
'secondaryRole': 'Activated'}
|
||||
mock_is_live_vol.return_value = True
|
||||
mock_get_live_vol.return_value = sclivevol
|
||||
props = {
|
||||
'access_mode': 'rw',
|
||||
'target_discovered': False,
|
||||
'target_iqn': u'iqn:1',
|
||||
'target_iqns': [u'iqn:1',
|
||||
u'iqn:2'],
|
||||
'target_lun': 1,
|
||||
'target_luns': [1, 1],
|
||||
'target_portal': u'192.168.1.21:3260',
|
||||
'target_portals': [u'192.168.1.21:3260',
|
||||
u'192.168.1.22:3260']
|
||||
}
|
||||
mock_find_iscsi_props.return_value = props
|
||||
ret = self.driver.initialize_connection(volume, connector)
|
||||
expected = {'data': props,
|
||||
'driver_volume_type': 'iscsi'}
|
||||
expected['data']['discard'] = True
|
||||
self.assertEqual(expected, ret)
|
||||
self.assertFalse(mock_initialize_secondary.called)
|
||||
|
||||
@mock.patch.object(dell_storagecenter_iscsi.DellStorageCenterISCSIDriver,
|
||||
'_get_replication_specs',
|
||||
return_value={'enabled': True, 'live': True})
|
||||
|
@ -1230,9 +1296,10 @@ class DellSCSanISCSIDriverTestCase(test.TestCase):
|
|||
sclivevol = {'instanceId': '101.101',
|
||||
'secondaryVolume': {'instanceId': '102.101',
|
||||
'instanceName': fake.VOLUME_ID},
|
||||
'secondaryScSerialNumber': 102}
|
||||
'secondaryScSerialNumber': 102,
|
||||
'secondaryRole': 'Secondary'}
|
||||
mock_is_live_vol.return_value = True
|
||||
mock_get_live_vol.return_value = (sclivevol, False)
|
||||
mock_get_live_vol.return_value = sclivevol
|
||||
connector = self.connector
|
||||
res = self.driver.terminate_connection(volume, connector)
|
||||
mock_unmap_volume.assert_called_once_with(self.VOLUME, self.SCSERVER)
|
||||
|
@ -2661,36 +2728,36 @@ class DellSCSanISCSIDriverTestCase(test.TestCase):
|
|||
'instanceName': fake.VOLUME2_ID},
|
||||
'secondaryVolume': {'instanceId': '102.101',
|
||||
'instanceName': fake.VOLUME_ID},
|
||||
'secondaryScSerialNumber': 102}
|
||||
'secondaryScSerialNumber': 102,
|
||||
'secondaryRole': 'Secondary'}
|
||||
postfail = {'instanceId': '101.100',
|
||||
'primaryVolume': {'instanceId': '102.101',
|
||||
'instanceName': fake.VOLUME_ID},
|
||||
'secondaryVolume': {'instanceId': '101.101',
|
||||
'instanceName': fake.VOLUME2_ID},
|
||||
'secondaryScSerialNumber': 102}
|
||||
'secondaryScSerialNumber': 102,
|
||||
'secondaryRole': 'Secondary'}
|
||||
mock_api.get_live_volume = mock.MagicMock()
|
||||
mock_api.get_live_volume.side_effect = [(sclivevol, False),
|
||||
(postfail, True),
|
||||
(sclivevol, False),
|
||||
(sclivevol, False)
|
||||
]
|
||||
mock_api.get_live_volume.side_effect = [sclivevol, postfail,
|
||||
sclivevol, sclivevol]
|
||||
# Good run.
|
||||
mock_api.is_swapped = mock.MagicMock(return_value=False)
|
||||
mock_api.swap_roles_live_volume = mock.MagicMock(return_value=True)
|
||||
model_update = {'provider_id': '102.101',
|
||||
'replication_status': 'failed-over'}
|
||||
ret = self.driver._failover_live_volume(mock_api, fake.VOLUME_ID,
|
||||
'101.100')
|
||||
'101.101')
|
||||
self.assertEqual(model_update, ret)
|
||||
# Swap fail
|
||||
mock_api.swap_roles_live_volume.return_value = False
|
||||
model_update = {'status': 'error'}
|
||||
ret = self.driver._failover_live_volume(mock_api, fake.VOLUME_ID,
|
||||
'101.100')
|
||||
'101.101')
|
||||
self.assertEqual(model_update, ret)
|
||||
# Can't find live volume.
|
||||
mock_api.get_live_volume.return_value = (None, False)
|
||||
mock_api.get_live_volume.return_value = None
|
||||
ret = self.driver._failover_live_volume(mock_api, fake.VOLUME_ID,
|
||||
'101.100')
|
||||
'101.101')
|
||||
self.assertEqual(model_update, ret)
|
||||
|
||||
def test__failover_replication(self,
|
||||
|
@ -3206,16 +3273,16 @@ class DellSCSanISCSIDriverTestCase(test.TestCase):
|
|||
{'id': fake.VOLUME2_ID,
|
||||
'replication_driver_data': '12345',
|
||||
'provider_id': '12345.2'}]
|
||||
mock_get_live_volume.side_effect = [(
|
||||
mock_get_live_volume.side_effect = [
|
||||
{'instanceId': '11111.101',
|
||||
'secondaryVolume': {'instanceId': '11111.1001',
|
||||
'instanceName': fake.VOLUME_ID},
|
||||
'secondaryScSerialNumber': 11111}, True), (
|
||||
'secondaryScSerialNumber': 11111},
|
||||
{'instanceId': '11111.102',
|
||||
'secondaryVolume': {'instanceId': '11111.1002',
|
||||
'instanceName': fake.VOLUME2_ID},
|
||||
'secondaryScSerialNumber': 11111}, True
|
||||
)]
|
||||
'secondaryScSerialNumber': 11111}
|
||||
]
|
||||
mock_get_replication_specs.return_value = {'enabled': True,
|
||||
'live': True}
|
||||
mock_swap_roles_live_volume.side_effect = [True, True]
|
||||
|
|
|
@ -21,6 +21,7 @@ import uuid
|
|||
from cinder import context
|
||||
from cinder import exception
|
||||
from cinder import test
|
||||
from cinder.tests.unit import fake_constants as fake
|
||||
from cinder.volume.drivers.dell import dell_storagecenter_api
|
||||
|
||||
|
||||
|
@ -6027,7 +6028,7 @@ class DellSCSanAPITestCase(test.TestCase):
|
|||
expected = 'StorageCenter/ScReplication/%s' % (
|
||||
self.SCREPL[0]['instanceId'])
|
||||
expected_payload = {'DeleteDestinationVolume': True,
|
||||
'RecycleDestinationVolume': False,
|
||||
'RecycleDestinationVolume': True,
|
||||
'DeleteRestorePoint': True}
|
||||
ret = self.scapi.delete_replication(self.VOLUME, destssn)
|
||||
mock_delete.assert_any_call(expected, payload=expected_payload,
|
||||
|
@ -6064,7 +6065,7 @@ class DellSCSanAPITestCase(test.TestCase):
|
|||
expected = 'StorageCenter/ScReplication/%s' % (
|
||||
self.SCREPL[0]['instanceId'])
|
||||
expected_payload = {'DeleteDestinationVolume': True,
|
||||
'RecycleDestinationVolume': False,
|
||||
'RecycleDestinationVolume': True,
|
||||
'DeleteRestorePoint': True}
|
||||
ret = self.scapi.delete_replication(self.VOLUME, destssn)
|
||||
mock_delete.assert_any_call(expected, payload=expected_payload,
|
||||
|
@ -6449,37 +6450,60 @@ class DellSCSanAPITestCase(test.TestCase):
|
|||
scvol,
|
||||
'a,b')
|
||||
|
||||
@mock.patch.object(dell_storagecenter_api.HttpClient,
|
||||
'get')
|
||||
@mock.patch.object(dell_storagecenter_api.StorageCenterApi,
|
||||
'_get_json')
|
||||
'_sc_live_volumes')
|
||||
@mock.patch.object(dell_storagecenter_api.StorageCenterApi,
|
||||
'_get_live_volumes')
|
||||
def test_get_live_volume(self,
|
||||
mock_get_json,
|
||||
mock_get,
|
||||
mock_get_live_volumes,
|
||||
mock_sc_live_volumes,
|
||||
mock_close_connection,
|
||||
mock_open_connection,
|
||||
mock_init):
|
||||
# Basic check
|
||||
retlv, retswapped = self.scapi.get_live_volume(None)
|
||||
retlv = self.scapi.get_live_volume(None)
|
||||
self.assertIsNone(retlv)
|
||||
self.assertFalse(retswapped)
|
||||
lv1 = {'primaryVolume': {'instanceId': '12345.1'},
|
||||
'secondaryVolume': {'instanceId': '67890.1'}}
|
||||
lv2 = {'primaryVolume': {'instanceId': '12345.2'}}
|
||||
mock_get_json.return_value = [lv1, lv2]
|
||||
mock_get.return_value = self.RESPONSE_200
|
||||
mock_sc_live_volumes.return_value = [lv1, lv2]
|
||||
# Good Run
|
||||
retlv, retswapped = self.scapi.get_live_volume('12345.2')
|
||||
retlv = self.scapi.get_live_volume('12345.2')
|
||||
self.assertEqual(lv2, retlv)
|
||||
self.assertFalse(retswapped)
|
||||
mock_sc_live_volumes.assert_called_once_with('12345')
|
||||
self.assertFalse(mock_get_live_volumes.called)
|
||||
|
||||
@mock.patch.object(dell_storagecenter_api.HttpClient,
|
||||
'get')
|
||||
@mock.patch.object(dell_storagecenter_api.StorageCenterApi,
|
||||
'_get_json')
|
||||
'_sc_live_volumes')
|
||||
@mock.patch.object(dell_storagecenter_api.StorageCenterApi,
|
||||
'_get_live_volumes')
|
||||
def test_get_live_volume_on_secondary(self,
|
||||
mock_get_live_volumes,
|
||||
mock_sc_live_volumes,
|
||||
mock_close_connection,
|
||||
mock_open_connection,
|
||||
mock_init):
|
||||
# Basic check
|
||||
retlv = self.scapi.get_live_volume(None)
|
||||
self.assertIsNone(retlv)
|
||||
lv1 = {'primaryVolume': {'instanceId': '12345.1'},
|
||||
'secondaryVolume': {'instanceId': '67890.1'}}
|
||||
lv2 = {'primaryVolume': {'instanceId': '12345.2'}}
|
||||
mock_sc_live_volumes.return_value = []
|
||||
mock_get_live_volumes.return_value = [lv1, lv2]
|
||||
# Good Run
|
||||
retlv = self.scapi.get_live_volume('12345.2')
|
||||
self.assertEqual(lv2, retlv)
|
||||
mock_sc_live_volumes.assert_called_once_with('12345')
|
||||
mock_get_live_volumes.assert_called_once_with()
|
||||
|
||||
@mock.patch.object(dell_storagecenter_api.StorageCenterApi,
|
||||
'_sc_live_volumes')
|
||||
@mock.patch.object(dell_storagecenter_api.StorageCenterApi,
|
||||
'_get_live_volumes')
|
||||
def test_get_live_volume_not_found(self,
|
||||
mock_get_json,
|
||||
mock_get,
|
||||
mock_get_live_volumes,
|
||||
mock_sc_live_volumes,
|
||||
mock_close_connection,
|
||||
mock_open_connection,
|
||||
mock_init):
|
||||
|
@ -6487,19 +6511,20 @@ class DellSCSanAPITestCase(test.TestCase):
|
|||
'secondaryVolume': {'instanceId': '67890.1'}}
|
||||
lv2 = {'primaryVolume': {'instanceId': '12345.2'},
|
||||
'secondaryVolume': {'instanceId': '67890.2'}}
|
||||
mock_get_json.return_value = [lv1, lv2]
|
||||
mock_get.return_value = self.RESPONSE_200
|
||||
retlv, retswapped = self.scapi.get_live_volume('12345.3')
|
||||
mock_get_live_volumes.return_value = [lv1, lv2]
|
||||
mock_sc_live_volumes.return_value = []
|
||||
retlv = self.scapi.get_live_volume('12345.3')
|
||||
self.assertIsNone(retlv)
|
||||
self.assertFalse(retswapped)
|
||||
mock_sc_live_volumes.assert_called_once_with('12345')
|
||||
mock_get_live_volumes.assert_called_once_with()
|
||||
|
||||
@mock.patch.object(dell_storagecenter_api.HttpClient,
|
||||
'get')
|
||||
@mock.patch.object(dell_storagecenter_api.StorageCenterApi,
|
||||
'_get_json')
|
||||
'_sc_live_volumes')
|
||||
@mock.patch.object(dell_storagecenter_api.StorageCenterApi,
|
||||
'_get_live_volumes')
|
||||
def test_get_live_volume_swapped(self,
|
||||
mock_get_json,
|
||||
mock_get,
|
||||
mock_get_live_volumes,
|
||||
mock_sc_live_volumes,
|
||||
mock_close_connection,
|
||||
mock_open_connection,
|
||||
mock_init):
|
||||
|
@ -6507,23 +6532,50 @@ class DellSCSanAPITestCase(test.TestCase):
|
|||
'secondaryVolume': {'instanceId': '67890.1'}}
|
||||
lv2 = {'primaryVolume': {'instanceId': '67890.2'},
|
||||
'secondaryVolume': {'instanceId': '12345.2'}}
|
||||
mock_get_json.return_value = [lv1, lv2]
|
||||
mock_get.return_value = self.RESPONSE_200
|
||||
retlv, retswapped = self.scapi.get_live_volume('12345.2')
|
||||
mock_get_live_volumes.return_value = [lv1, lv2]
|
||||
mock_sc_live_volumes.return_value = []
|
||||
retlv = self.scapi.get_live_volume('12345.2')
|
||||
self.assertEqual(lv2, retlv)
|
||||
self.assertTrue(retswapped)
|
||||
mock_sc_live_volumes.assert_called_once_with('12345')
|
||||
mock_get_live_volumes.assert_called_once_with()
|
||||
|
||||
@mock.patch.object(dell_storagecenter_api.HttpClient,
|
||||
'get')
|
||||
@mock.patch.object(dell_storagecenter_api.StorageCenterApi,
|
||||
'_sc_live_volumes')
|
||||
@mock.patch.object(dell_storagecenter_api.StorageCenterApi,
|
||||
'_get_live_volumes')
|
||||
def test_get_live_volume_error(self,
|
||||
mock_get,
|
||||
mock_get_live_volumes,
|
||||
mock_sc_live_volumes,
|
||||
mock_close_connection,
|
||||
mock_open_connection,
|
||||
mock_init):
|
||||
mock_get.return_value = self.RESPONSE_400
|
||||
retlv, retswapped = self.scapi.get_live_volume('12345.2')
|
||||
mock_get_live_volumes.return_value = []
|
||||
mock_sc_live_volumes.return_value = []
|
||||
retlv = self.scapi.get_live_volume('12345.2')
|
||||
self.assertIsNone(retlv)
|
||||
self.assertFalse(retswapped)
|
||||
|
||||
@mock.patch.object(dell_storagecenter_api.StorageCenterApi,
|
||||
'_sc_live_volumes')
|
||||
@mock.patch.object(dell_storagecenter_api.StorageCenterApi,
|
||||
'_get_live_volumes')
|
||||
def test_get_live_volume_by_name(self,
|
||||
mock_get_live_volumes,
|
||||
mock_sc_live_volumes,
|
||||
mock_close_connection,
|
||||
mock_open_connection,
|
||||
mock_init):
|
||||
lv1 = {'primaryVolume': {'instanceId': '12345.1'},
|
||||
'secondaryVolume': {'instanceId': '67890.1'},
|
||||
'instanceName': 'Live volume of ' + fake.VOLUME2_ID}
|
||||
lv2 = {'primaryVolume': {'instanceId': '67890.2'},
|
||||
'secondaryVolume': {'instanceId': '12345.2'},
|
||||
'instanceName': 'Live volume of ' + fake.VOLUME_ID}
|
||||
mock_get_live_volumes.return_value = [lv1, lv2]
|
||||
mock_sc_live_volumes.return_value = []
|
||||
retlv = self.scapi.get_live_volume('12345.2', fake.VOLUME_ID)
|
||||
self.assertEqual(lv2, retlv)
|
||||
mock_sc_live_volumes.assert_called_once_with('12345')
|
||||
mock_get_live_volumes.assert_called_once_with()
|
||||
|
||||
@mock.patch.object(dell_storagecenter_api.HttpClient,
|
||||
'post')
|
||||
|
|
|
@ -1091,20 +1091,26 @@ class StorageCenterApi(object):
|
|||
def _autofailback(self, lv):
|
||||
# if we have a working replication state.
|
||||
ret = False
|
||||
if (lv['ReplicationState'] == 'Up' and
|
||||
lv['failoverState'] == 'AutoFailedOver'):
|
||||
LOG.debug('Attempting autofailback of %s', lv)
|
||||
if (lv and lv['status'] == 'Up' and lv['replicationState'] == 'Up' and
|
||||
lv['failoverState'] == 'Protected' and lv['secondaryStatus'] == 'Up'
|
||||
and lv['primarySwapRoleState'] == 'NotSwapping'):
|
||||
ret = self.swap_roles_live_volume(lv)
|
||||
return ret
|
||||
|
||||
def _find_volume_primary(self, provider_id):
|
||||
def _find_volume_primary(self, provider_id, name):
|
||||
# if there is no live volume then we return our provider_id.
|
||||
primary_id = provider_id
|
||||
lv, swapped = self.get_live_volume(provider_id)
|
||||
# if we swapped see if we can autofailback. Unless the admin
|
||||
# failed us over, that is.
|
||||
if swapped and not self.failed_over:
|
||||
lv = self.get_live_volume(provider_id, name)
|
||||
LOG.info(_LI('Volume %(provider)s at primary %(primary)s.'),
|
||||
{'provider': provider_id, 'primary': primary_id})
|
||||
# If we have a live volume and are swapped and are not failed over
|
||||
# at least give failback a shot.
|
||||
if lv and self.is_swapped(provider_id, lv) and not self.failed_over:
|
||||
if self._autofailback(lv):
|
||||
ls, swapped = self.get_live_volume(provider_id)
|
||||
lv = self.get_live_volume(provider_id)
|
||||
LOG.info(_LI('After failback %s'), lv)
|
||||
|
||||
if lv:
|
||||
primary_id = lv['primaryVolume']['instanceId']
|
||||
return primary_id
|
||||
|
@ -1127,7 +1133,7 @@ class StorageCenterApi(object):
|
|||
scvolume = None
|
||||
if islivevol:
|
||||
# Just get the primary from the sc live vol.
|
||||
primary_id = self._find_volume_primary(provider_id)
|
||||
primary_id = self._find_volume_primary(provider_id, name)
|
||||
scvolume = self.get_volume(primary_id)
|
||||
elif self._use_provider_id(provider_id):
|
||||
# just get our volume
|
||||
|
@ -2747,7 +2753,7 @@ class StorageCenterApi(object):
|
|||
if replication:
|
||||
payload = {}
|
||||
payload['DeleteDestinationVolume'] = deletedestvolume
|
||||
payload['RecycleDestinationVolume'] = False
|
||||
payload['RecycleDestinationVolume'] = deletedestvolume
|
||||
payload['DeleteRestorePoint'] = True
|
||||
r = self.client.delete('StorageCenter/ScReplication/%s' %
|
||||
self._get_id(replication), payload=payload,
|
||||
|
@ -3067,24 +3073,73 @@ class StorageCenterApi(object):
|
|||
progress)
|
||||
return None, None
|
||||
|
||||
def get_live_volume(self, primaryid):
|
||||
def is_swapped(self, provider_id, sclivevolume):
|
||||
if (sclivevolume.get('primaryVolume') and
|
||||
sclivevolume['primaryVolume']['instanceId'] != provider_id):
|
||||
return True
|
||||
return False
|
||||
|
||||
def is_failed_over(self, provider_id, sclivevolume):
|
||||
# either the secondary is active or the secondary is now our primary.
|
||||
if (sclivevolume.get('secondaryRole') == 'Activated' or
|
||||
self.is_swapped(provider_id, sclivevolume)):
|
||||
return True
|
||||
return False
|
||||
|
||||
def _sc_live_volumes(self, ssn):
|
||||
if ssn:
|
||||
r = self.client.get('StorageCenter/StorageCenter/%s/LiveVolumeList'
|
||||
% ssn)
|
||||
if self._check_result(r):
|
||||
return self._get_json(r)
|
||||
return []
|
||||
|
||||
def _get_live_volumes(self):
|
||||
# Work around for a FW bug. Instead of grabbing the entire list at
|
||||
# once we have to Trundle through each SC's list.
|
||||
lvs = []
|
||||
pf = self._get_payload_filter()
|
||||
pf.append('connected', True)
|
||||
r = self.client.post('StorageCenter/StorageCenter/GetList',
|
||||
pf.payload)
|
||||
if self._check_result(r):
|
||||
# Should return [] if nothing there.
|
||||
# Just in case do the or.
|
||||
scs = self._get_json(r) or []
|
||||
for sc in scs:
|
||||
lvs += self._sc_live_volumes(self._get_id(sc))
|
||||
return lvs
|
||||
|
||||
def get_live_volume(self, primaryid, name=None):
|
||||
"""Get's the live ScLiveVolume object for the vol with primaryid.
|
||||
|
||||
:param primaryid: InstanceId of the primary volume.
|
||||
:return: ScLiveVolume object or None, swapped True/False.
|
||||
:parma name: Volume name associated with this live volume.
|
||||
:return: ScLiveVolume object or None
|
||||
"""
|
||||
sclivevol = None
|
||||
if primaryid:
|
||||
r = self.client.get('StorageCenter/ScLiveVolume')
|
||||
if self._check_result(r):
|
||||
lvs = self._get_json(r)
|
||||
# Try from our primary SSN. This would be the authoritay on the
|
||||
# Live Volume in question.
|
||||
lvs = self._sc_live_volumes(primaryid.split('.')[0])
|
||||
# No, grab them all and see if we are on the secondary.
|
||||
if not lvs:
|
||||
lvs = self._get_live_volumes()
|
||||
if lvs:
|
||||
# Look for our primaryid.
|
||||
for lv in lvs:
|
||||
if (lv.get('primaryVolume') and
|
||||
lv['primaryVolume']['instanceId'] == primaryid):
|
||||
return lv, False
|
||||
if (lv.get('secondaryVolume') and
|
||||
lv['secondaryVolume']['instanceId'] == primaryid):
|
||||
return lv, True
|
||||
return None, False
|
||||
if ((lv.get('primaryVolume') and
|
||||
lv['primaryVolume']['instanceId'] == primaryid) or
|
||||
(lv.get('secondaryVolume') and
|
||||
lv['secondaryVolume']['instanceId'] == primaryid)):
|
||||
sclivevol = lv
|
||||
break
|
||||
# Sometimes the lv object returns without a secondary
|
||||
# volume. Make sure we find this by name if we have to.
|
||||
if (name and sclivevol is None and
|
||||
lv['instanceName'].endswith(name)):
|
||||
sclivevol = lv
|
||||
return sclivevol
|
||||
|
||||
def _get_hbas(self, serverid):
|
||||
# Helper to get the hba's of a given server.
|
||||
|
@ -3184,6 +3239,7 @@ class StorageCenterApi(object):
|
|||
payload['ConvertToReplication'] = False
|
||||
payload['DeleteSecondaryVolume'] = deletesecondaryvolume
|
||||
payload['RecycleSecondaryVolume'] = deletesecondaryvolume
|
||||
payload['DeleteRestorePoint'] = deletesecondaryvolume
|
||||
r = self.client.delete('StorageCenter/ScLiveVolume/%s' %
|
||||
self._get_id(sclivevolume), payload, True)
|
||||
if self._check_result(r):
|
||||
|
|
|
@ -362,8 +362,7 @@ class DellCommonDriver(driver.ConsistencyGroupVD, driver.ManageableVD,
|
|||
ssnstrings = self._split_driver_data(replication_driver_data)
|
||||
if ssnstrings:
|
||||
ssn = int(ssnstrings[0])
|
||||
sclivevolume, swapped = api.get_live_volume(
|
||||
volume.get('provider_id'))
|
||||
sclivevolume = api.get_live_volume(volume.get('provider_id'))
|
||||
# Have we found the live volume?
|
||||
if (sclivevolume and
|
||||
sclivevolume.get('secondaryScSerialNumber') == ssn and
|
||||
|
@ -682,12 +681,7 @@ class DellCommonDriver(driver.ConsistencyGroupVD, driver.ManageableVD,
|
|||
def _update_volume_stats(self):
|
||||
"""Retrieve stats info from volume group."""
|
||||
with self._client.open_connection() as api:
|
||||
storageusage = api.get_storage_usage()
|
||||
if not storageusage:
|
||||
msg = _('Unable to retrieve volume stats.')
|
||||
raise exception.VolumeBackendAPIException(message=msg)
|
||||
|
||||
# all of this is basically static for now
|
||||
# Static stats.
|
||||
data = {}
|
||||
data['volume_backend_name'] = self.backend_name
|
||||
data['vendor_name'] = 'Dell'
|
||||
|
@ -696,12 +690,6 @@ class DellCommonDriver(driver.ConsistencyGroupVD, driver.ManageableVD,
|
|||
data['reserved_percentage'] = 0
|
||||
data['consistencygroup_support'] = True
|
||||
data['thin_provisioning_support'] = True
|
||||
totalcapacity = storageusage.get('availableSpace')
|
||||
totalcapacitygb = self._bytes_to_gb(totalcapacity)
|
||||
data['total_capacity_gb'] = totalcapacitygb
|
||||
freespace = storageusage.get('freeSpace')
|
||||
freespacegb = self._bytes_to_gb(freespace)
|
||||
data['free_capacity_gb'] = freespacegb
|
||||
data['QoS_support'] = False
|
||||
data['replication_enabled'] = self.replication_enabled
|
||||
if self.replication_enabled:
|
||||
|
@ -715,6 +703,22 @@ class DellCommonDriver(driver.ConsistencyGroupVD, driver.ManageableVD,
|
|||
replication_targets.append(target_device_id)
|
||||
data['replication_targets'] = replication_targets
|
||||
|
||||
# Get our capacity.
|
||||
storageusage = api.get_storage_usage()
|
||||
if storageusage:
|
||||
# Get actual stats.
|
||||
totalcapacity = storageusage.get('availableSpace')
|
||||
totalcapacitygb = self._bytes_to_gb(totalcapacity)
|
||||
data['total_capacity_gb'] = totalcapacitygb
|
||||
freespace = storageusage.get('freeSpace')
|
||||
freespacegb = self._bytes_to_gb(freespace)
|
||||
data['free_capacity_gb'] = freespacegb
|
||||
else:
|
||||
# Soldier on. Just return 0 for this iteration.
|
||||
LOG.error(_LE('Unable to retrieve volume stats.'))
|
||||
data['total_capacity_gb'] = 0
|
||||
data['free_capacity_gb'] = 0
|
||||
|
||||
self._stats = data
|
||||
LOG.debug('Total cap %(total)s Free cap %(free)s',
|
||||
{'total': data['total_capacity_gb'],
|
||||
|
@ -1390,7 +1394,10 @@ class DellCommonDriver(driver.ConsistencyGroupVD, driver.ManageableVD,
|
|||
:return: model_update dict
|
||||
"""
|
||||
model_update = {}
|
||||
sclivevolume, swapped = api.get_live_volume(provider_id)
|
||||
# We do not search by name. Only failback if we have a complete
|
||||
# LV object.
|
||||
sclivevolume = api.get_live_volume(provider_id)
|
||||
# TODO(tswanson): Check swapped state first.
|
||||
if sclivevolume and api.swap_roles_live_volume(sclivevolume):
|
||||
LOG.info(_LI('Success swapping sclivevolume roles %s'), id)
|
||||
model_update = {
|
||||
|
@ -1489,8 +1496,10 @@ class DellCommonDriver(driver.ConsistencyGroupVD, driver.ManageableVD,
|
|||
|
||||
def _failover_live_volume(self, api, id, provider_id):
|
||||
model_update = {}
|
||||
sclivevolume, swapped = api.get_live_volume(provider_id)
|
||||
# Search for volume by id if we have to.
|
||||
sclivevolume = api.get_live_volume(provider_id, id)
|
||||
if sclivevolume:
|
||||
swapped = api.is_swapped(provider_id, sclivevolume)
|
||||
# If we aren't swapped try it. If fail error out.
|
||||
if not swapped and not api.swap_roles_live_volume(sclivevolume):
|
||||
LOG.info(_LI('Failure swapping roles %s'), id)
|
||||
|
@ -1498,7 +1507,7 @@ class DellCommonDriver(driver.ConsistencyGroupVD, driver.ManageableVD,
|
|||
return model_update
|
||||
|
||||
LOG.info(_LI('Success swapping sclivevolume roles %s'), id)
|
||||
sclivevolume, swapped = api.get_live_volume(provider_id)
|
||||
sclivevolume = api.get_live_volume(provider_id)
|
||||
model_update = {
|
||||
'replication_status':
|
||||
fields.ReplicationStatus.FAILED_OVER,
|
||||
|
|
|
@ -90,52 +90,59 @@ class DellStorageCenterFCDriver(dell_storagecenter_common.DellCommonDriver,
|
|||
with self._client.open_connection() as api:
|
||||
try:
|
||||
wwpns = connector.get('wwpns')
|
||||
# Find our server.
|
||||
scserver = self._find_server(api, wwpns)
|
||||
|
||||
# No? Create it.
|
||||
if scserver is None:
|
||||
scserver = api.create_server(
|
||||
wwpns, self.configuration.dell_server_os)
|
||||
# Find the volume on the storage center.
|
||||
# Find the volume on the storage center. Note that if this
|
||||
# is live volume and we are swapped this will be the back
|
||||
# half of the live volume.
|
||||
scvolume = api.find_volume(volume_name, provider_id, islivevol)
|
||||
if scserver is not None and scvolume is not None:
|
||||
mapping = api.map_volume(scvolume, scserver)
|
||||
if mapping is not None:
|
||||
# Since we just mapped our volume we had best update
|
||||
# our sc volume object.
|
||||
scvolume = api.get_volume(scvolume['instanceId'])
|
||||
lun, targets, init_targ_map = api.find_wwns(scvolume,
|
||||
scserver)
|
||||
if scvolume:
|
||||
# Get the SSN it is on.
|
||||
ssn = scvolume['instanceId'].split('.')[0]
|
||||
# Find our server.
|
||||
scserver = self._find_server(api, wwpns, ssn)
|
||||
|
||||
# Do we have extra live volume work?
|
||||
if islivevol:
|
||||
# Get our volume and our swap state.
|
||||
sclivevolume, swapped = api.get_live_volume(
|
||||
provider_id)
|
||||
# Do not map to a failed over volume.
|
||||
if sclivevolume and not swapped:
|
||||
# Now map our secondary.
|
||||
lvlun, lvtargets, lvinit_targ_map = (
|
||||
self.initialize_secondary(api,
|
||||
sclivevolume,
|
||||
wwpns))
|
||||
# Unmapped. Add info to our list.
|
||||
targets += lvtargets
|
||||
init_targ_map.update(lvinit_targ_map)
|
||||
# No? Create it.
|
||||
if scserver is None:
|
||||
scserver = api.create_server(
|
||||
wwpns, self.configuration.dell_server_os, ssn)
|
||||
# We have a volume and a server. Map them.
|
||||
if scserver is not None:
|
||||
mapping = api.map_volume(scvolume, scserver)
|
||||
if mapping is not None:
|
||||
# Since we just mapped our volume we had
|
||||
# best update our sc volume object.
|
||||
scvolume = api.get_volume(scvolume['instanceId'])
|
||||
lun, targets, init_targ_map = api.find_wwns(
|
||||
scvolume, scserver)
|
||||
|
||||
# Roll up our return data.
|
||||
if lun is not None and len(targets) > 0:
|
||||
data = {'driver_volume_type': 'fibre_channel',
|
||||
'data': {'target_lun': lun,
|
||||
'target_discovered': True,
|
||||
'target_wwn': targets,
|
||||
'initiator_target_map':
|
||||
init_targ_map,
|
||||
'discard': True}}
|
||||
LOG.debug('Return FC data: %s', data)
|
||||
return data
|
||||
LOG.error(_LE('Lun mapping returned null!'))
|
||||
# Do we have extra live volume work?
|
||||
if islivevol:
|
||||
# Get our live volume.
|
||||
sclivevolume = api.get_live_volume(provider_id)
|
||||
# Do not map to a failed over volume.
|
||||
if (sclivevolume and not
|
||||
api.is_failed_over(provider_id,
|
||||
sclivevolume)):
|
||||
# Now map our secondary.
|
||||
lvlun, lvtargets, lvinit_targ_map = (
|
||||
self.initialize_secondary(api,
|
||||
sclivevolume,
|
||||
wwpns))
|
||||
# Unmapped. Add info to our list.
|
||||
targets += lvtargets
|
||||
init_targ_map.update(lvinit_targ_map)
|
||||
|
||||
# Roll up our return data.
|
||||
if lun is not None and len(targets) > 0:
|
||||
data = {'driver_volume_type': 'fibre_channel',
|
||||
'data': {'target_lun': lun,
|
||||
'target_discovered': True,
|
||||
'target_wwn': targets,
|
||||
'initiator_target_map':
|
||||
init_targ_map,
|
||||
'discard': True}}
|
||||
LOG.debug('Return FC data: %s', data)
|
||||
return data
|
||||
LOG.error(_LE('Lun mapping returned null!'))
|
||||
|
||||
except Exception:
|
||||
with excutils.save_and_reraise_exception():
|
||||
|
@ -191,46 +198,53 @@ class DellStorageCenterFCDriver(dell_storagecenter_common.DellCommonDriver,
|
|||
with self._client.open_connection() as api:
|
||||
try:
|
||||
wwpns = connector.get('wwpns')
|
||||
scserver = self._find_server(api, wwpns)
|
||||
|
||||
# Find the volume on the storage center.
|
||||
scvolume = api.find_volume(volume_name, provider_id, islivevol)
|
||||
# Get our target map so we can return it to free up a zone.
|
||||
lun, targets, init_targ_map = api.find_wwns(scvolume, scserver)
|
||||
if scvolume:
|
||||
# Get the SSN it is on.
|
||||
ssn = scvolume['instanceId'].split('.')[0]
|
||||
|
||||
# Do we have extra live volume work?
|
||||
if islivevol:
|
||||
# Get our volume and our swap state.
|
||||
sclivevolume, swapped = api.get_live_volume(
|
||||
provider_id)
|
||||
# Do not map to a failed over volume.
|
||||
if sclivevolume and not swapped:
|
||||
lvlun, lvtargets, lvinit_targ_map = (
|
||||
self.terminate_secondary(api, sclivevolume, wwpns))
|
||||
# Add to our return.
|
||||
if lvlun:
|
||||
targets += lvtargets
|
||||
init_targ_map.update(lvinit_targ_map)
|
||||
scserver = self._find_server(api, wwpns, ssn)
|
||||
|
||||
# If we have a server and a volume lets unmap them.
|
||||
if (scserver is not None and
|
||||
scvolume is not None and
|
||||
api.unmap_volume(scvolume, scserver) is True):
|
||||
LOG.debug('Connection terminated')
|
||||
else:
|
||||
raise exception.VolumeBackendAPIException(
|
||||
_('Terminate connection failed'))
|
||||
# Get our target map so we can return it to free up a zone.
|
||||
lun, targets, init_targ_map = api.find_wwns(scvolume,
|
||||
scserver)
|
||||
|
||||
# basic return info...
|
||||
info = {'driver_volume_type': 'fibre_channel',
|
||||
'data': {}}
|
||||
# Do we have extra live volume work?
|
||||
if islivevol:
|
||||
# Get our live volume.
|
||||
sclivevolume = api.get_live_volume(provider_id)
|
||||
# Do not map to a failed over volume.
|
||||
if (sclivevolume and not
|
||||
api.is_failed_over(provider_id,
|
||||
sclivevolume)):
|
||||
lvlun, lvtargets, lvinit_targ_map = (
|
||||
self.terminate_secondary(
|
||||
api, sclivevolume, wwpns))
|
||||
# Add to our return.
|
||||
if lvlun:
|
||||
targets += lvtargets
|
||||
init_targ_map.update(lvinit_targ_map)
|
||||
|
||||
# if not then we return the target map so that
|
||||
# the zone can be freed up.
|
||||
if api.get_volume_count(scserver) == 0:
|
||||
info['data'] = {'target_wwn': targets,
|
||||
'initiator_target_map': init_targ_map}
|
||||
return info
|
||||
# If we have a server and a volume lets unmap them.
|
||||
if (scserver is not None and
|
||||
scvolume is not None and
|
||||
api.unmap_volume(scvolume, scserver) is True):
|
||||
LOG.debug('Connection terminated')
|
||||
else:
|
||||
raise exception.VolumeBackendAPIException(
|
||||
_('Terminate connection failed'))
|
||||
|
||||
# basic return info...
|
||||
info = {'driver_volume_type': 'fibre_channel',
|
||||
'data': {}}
|
||||
|
||||
# if not then we return the target map so that
|
||||
# the zone can be freed up.
|
||||
if api.get_volume_count(scserver) == 0:
|
||||
info['data'] = {'target_wwn': targets,
|
||||
'initiator_target_map': init_targ_map}
|
||||
return info
|
||||
|
||||
except Exception:
|
||||
with excutils.save_and_reraise_exception():
|
||||
|
|
|
@ -96,59 +96,68 @@ class DellStorageCenterISCSIDriver(dell_storagecenter_common.DellCommonDriver,
|
|||
|
||||
with self._client.open_connection() as api:
|
||||
try:
|
||||
# Find our server.
|
||||
scserver = api.find_server(initiator_name)
|
||||
# No? Create it.
|
||||
if scserver is None:
|
||||
scserver = api.create_server(
|
||||
[initiator_name], self.configuration.dell_server_os)
|
||||
# Find the volume on the storage center.
|
||||
scvolume = api.find_volume(volume_name, provider_id)
|
||||
# Find the volume on the storage center. Note that if this
|
||||
# is live volume and we are swapped this will be the back
|
||||
# half of the live volume.
|
||||
scvolume = api.find_volume(volume_name, provider_id, islivevol)
|
||||
if scvolume:
|
||||
# Get the SSN it is on.
|
||||
ssn = scvolume['instanceId'].split('.')[0]
|
||||
# Find our server.
|
||||
scserver = api.find_server(initiator_name, ssn)
|
||||
# No? Create it.
|
||||
if scserver is None:
|
||||
scserver = api.create_server(
|
||||
[initiator_name],
|
||||
self.configuration.dell_server_os, ssn)
|
||||
|
||||
# if we have a server and a volume lets bring them together.
|
||||
if scserver is not None and scvolume is not None:
|
||||
mapping = api.map_volume(scvolume, scserver)
|
||||
if mapping is not None:
|
||||
# Since we just mapped our volume we had best update
|
||||
# our sc volume object.
|
||||
scvolume = api.get_volume(provider_id)
|
||||
# Our return.
|
||||
iscsiprops = {}
|
||||
# if we have a server and a volume lets bring them
|
||||
# together.
|
||||
if scserver is not None:
|
||||
mapping = api.map_volume(scvolume, scserver)
|
||||
if mapping is not None:
|
||||
# Since we just mapped our volume we had best
|
||||
# update our sc volume object.
|
||||
scvolume = api.get_volume(scvolume['instanceId'])
|
||||
# Our return.
|
||||
iscsiprops = {}
|
||||
|
||||
# Three cases that should all be satisfied with the
|
||||
# same return of Target_Portal and Target_Portals.
|
||||
# 1. Nova is calling us so we need to return the
|
||||
# Target_Portal stuff. It should ignore the
|
||||
# Target_Portals stuff.
|
||||
# 2. OS brick is calling us in multipath mode so we
|
||||
# want to return Target_Portals. It will ignore
|
||||
# the Target_Portal stuff.
|
||||
# 3. OS brick is calling us in single path mode so
|
||||
# we want to return Target_Portal and
|
||||
# Target_Portals as alternates.
|
||||
iscsiprops = api.find_iscsi_properties(scvolume)
|
||||
# Three cases that should all be satisfied with the
|
||||
# same return of Target_Portal and Target_Portals.
|
||||
# 1. Nova is calling us so we need to return the
|
||||
# Target_Portal stuff. It should ignore the
|
||||
# Target_Portals stuff.
|
||||
# 2. OS brick is calling us in multipath mode so we
|
||||
# want to return Target_Portals. It will ignore
|
||||
# the Target_Portal stuff.
|
||||
# 3. OS brick is calling us in single path mode so
|
||||
# we want to return Target_Portal and
|
||||
# Target_Portals as alternates.
|
||||
iscsiprops = api.find_iscsi_properties(scvolume)
|
||||
|
||||
# If this is a live volume we need to map up our
|
||||
# secondary volume.
|
||||
if islivevol:
|
||||
sclivevolume, swapped = api.get_live_volume(
|
||||
provider_id)
|
||||
# Only map if we are not swapped.
|
||||
if sclivevolume and not swapped:
|
||||
secondaryprops = self.initialize_secondary(
|
||||
api, sclivevolume, initiator_name)
|
||||
# Combine with iscsiprops
|
||||
iscsiprops['target_iqns'] += (
|
||||
secondaryprops['target_iqns'])
|
||||
iscsiprops['target_portals'] += (
|
||||
secondaryprops['target_portals'])
|
||||
iscsiprops['target_luns'] += (
|
||||
secondaryprops['target_luns'])
|
||||
# If this is a live volume we need to map up our
|
||||
# secondary volume. Note that if we have failed
|
||||
# over we do not wish to do this.
|
||||
if islivevol:
|
||||
sclivevolume = api.get_live_volume(provider_id)
|
||||
# Only map if we are not failed over.
|
||||
if (sclivevolume and not
|
||||
api.is_failed_over(provider_id,
|
||||
sclivevolume)):
|
||||
secondaryprops = self.initialize_secondary(
|
||||
api, sclivevolume, initiator_name)
|
||||
# Combine with iscsiprops
|
||||
iscsiprops['target_iqns'] += (
|
||||
secondaryprops['target_iqns'])
|
||||
iscsiprops['target_portals'] += (
|
||||
secondaryprops['target_portals'])
|
||||
iscsiprops['target_luns'] += (
|
||||
secondaryprops['target_luns'])
|
||||
|
||||
# Return our iscsi properties.
|
||||
iscsiprops['discard'] = True
|
||||
return {'driver_volume_type': 'iscsi',
|
||||
'data': iscsiprops}
|
||||
# Return our iscsi properties.
|
||||
iscsiprops['discard'] = True
|
||||
return {'driver_volume_type': 'iscsi',
|
||||
'data': iscsiprops}
|
||||
# Re-raise any backend exception.
|
||||
except exception.VolumeBackendAPIException:
|
||||
with excutils.save_and_reraise_exception():
|
||||
|
@ -214,23 +223,31 @@ class DellStorageCenterISCSIDriver(dell_storagecenter_common.DellCommonDriver,
|
|||
'initiator': initiator_name})
|
||||
with self._client.open_connection() as api:
|
||||
try:
|
||||
scserver = api.find_server(initiator_name)
|
||||
# Find the volume on the storage center.
|
||||
scvolume = api.find_volume(volume_name, provider_id)
|
||||
# Find the volume on the storage center. Note that if this
|
||||
# is live volume and we are swapped this will be the back
|
||||
# half of the live volume.
|
||||
scvolume = api.find_volume(volume_name, provider_id, islivevol)
|
||||
if scvolume:
|
||||
# Get the SSN it is on.
|
||||
ssn = scvolume['instanceId'].split('.')[0]
|
||||
# Find our server.
|
||||
scserver = api.find_server(initiator_name, ssn)
|
||||
|
||||
# Unmap our secondary if it isn't swapped.
|
||||
if islivevol:
|
||||
sclivevolume, swapped = api.get_live_volume(provider_id)
|
||||
if sclivevolume and not swapped:
|
||||
self.terminate_secondary(api, sclivevolume,
|
||||
initiator_name)
|
||||
# Unmap our secondary if not failed over..
|
||||
if islivevol:
|
||||
sclivevolume = api.get_live_volume(provider_id)
|
||||
if (sclivevolume and not
|
||||
api.is_failed_over(provider_id,
|
||||
sclivevolume)):
|
||||
self.terminate_secondary(api, sclivevolume,
|
||||
initiator_name)
|
||||
|
||||
# If we have a server and a volume lets pull them apart.
|
||||
if (scserver is not None and
|
||||
scvolume is not None and
|
||||
api.unmap_volume(scvolume, scserver) is True):
|
||||
LOG.debug('Connection terminated')
|
||||
return
|
||||
# If we have a server and a volume lets pull them apart.
|
||||
if (scserver is not None and
|
||||
scvolume is not None and
|
||||
api.unmap_volume(scvolume, scserver) is True):
|
||||
LOG.debug('Connection terminated')
|
||||
return
|
||||
except Exception:
|
||||
with excutils.save_and_reraise_exception():
|
||||
LOG.error(_LE('Failed to terminate connection '
|
||||
|
|
Loading…
Reference in New Issue