Address review comments for MacroSAN driver
- Removing unnecessary os-brick code and refactor/optimize driver - Solve the modifications made by the reviewer in the 19th and 20th patches in the driver of the initial join. Link:https://review.opendev.org/#/c/612311/ Closes-Bug: #1837920 Implements: blueprint macrosan-cinder-driver Change-Id: I0a6b13941936cd9e8521e3fcbe8fb61d3da3c45c
This commit is contained in:
parent
0a0d55d8a9
commit
12096ee1d0
@ -34,7 +34,6 @@ test_volume = (
|
|||||||
UserDict({'name': 'volume-728ec287-bf30-4d2d-98a8-7f1bed3f59ce',
|
UserDict({'name': 'volume-728ec287-bf30-4d2d-98a8-7f1bed3f59ce',
|
||||||
'volume_name': 'test',
|
'volume_name': 'test',
|
||||||
'id': '728ec287-bf30-4d2d-98a8-7f1bed3f59ce',
|
'id': '728ec287-bf30-4d2d-98a8-7f1bed3f59ce',
|
||||||
'volume_id': '728ec287-bf30-4d2d-98a8-7f1bed3f59ce',
|
|
||||||
'provider_auth': None,
|
'provider_auth': None,
|
||||||
'project_id': 'project',
|
'project_id': 'project',
|
||||||
'display_name': 'test',
|
'display_name': 'test',
|
||||||
@ -45,7 +44,7 @@ test_volume = (
|
|||||||
'macrosan uuid:0x00b34201-025b0000-46b35ae7-b7deec47'}))
|
'macrosan uuid:0x00b34201-025b0000-46b35ae7-b7deec47'}))
|
||||||
|
|
||||||
test_volume.size = 10
|
test_volume.size = 10
|
||||||
test_volume.volume_type_id = None
|
test_volume.volume_type_id = '36674caf-5314-468a-a8cb-baab4f71fe44'
|
||||||
test_volume.volume_attachment = []
|
test_volume.volume_attachment = []
|
||||||
|
|
||||||
test_migrate_volume = {
|
test_migrate_volume = {
|
||||||
@ -58,7 +57,7 @@ test_migrate_volume = {
|
|||||||
'project_id': 'project',
|
'project_id': 'project',
|
||||||
'display_name': 'test',
|
'display_name': 'test',
|
||||||
'display_description': 'test',
|
'display_description': 'test',
|
||||||
'volume_type_id': None,
|
'volume_type_id': '36674caf-5314-468a-a8cb-baab4f71fe44',
|
||||||
'_name_id': None,
|
'_name_id': None,
|
||||||
'host': 'controller@macrosan#MacroSAN',
|
'host': 'controller@macrosan#MacroSAN',
|
||||||
'provider_location':
|
'provider_location':
|
||||||
@ -73,7 +72,7 @@ test_snap = {'name': 'volume-728ec287-bf30-4d2d-98a8-7f1bed3f59ce',
|
|||||||
'project_id': 'project',
|
'project_id': 'project',
|
||||||
'display_name': 'test',
|
'display_name': 'test',
|
||||||
'display_description': 'test volume',
|
'display_description': 'test volume',
|
||||||
'volume_type_id': None,
|
'volume_type_id': '36674caf-5314-468a-a8cb-baab4f71fe44',
|
||||||
'provider_location': 'pointid: 1',
|
'provider_location': 'pointid: 1',
|
||||||
'volume_size': 10,
|
'volume_size': 10,
|
||||||
'volume': test_volume}
|
'volume': test_volume}
|
||||||
@ -106,6 +105,17 @@ expected_iscsi_properties = {'target_discovered': False,
|
|||||||
'728ec287-bf30-4d2d-98a8-7f1bed3f59ce'
|
'728ec287-bf30-4d2d-98a8-7f1bed3f59ce'
|
||||||
}
|
}
|
||||||
|
|
||||||
|
expected_iscsi_connection_data = {
|
||||||
|
'client': 'devstack',
|
||||||
|
'ports': [{'ip': '192.168.251.1',
|
||||||
|
'port': 'eth-1:0:0',
|
||||||
|
'port_name': 'iSCSI-Target-1:0:0',
|
||||||
|
'target': 'iqn.2010-05.com.macrosan.target:controller'},
|
||||||
|
{'ip': '192.168.251.2',
|
||||||
|
'port': 'eth-2:0:0',
|
||||||
|
'port_name': 'iSCSI-Target-2:0:0',
|
||||||
|
'target': 'iqn.2010-05.com.macrosan.target:controller'}]}
|
||||||
|
|
||||||
expected_initr_port_map_tgtexist = {
|
expected_initr_port_map_tgtexist = {
|
||||||
'21:00:00:24:ff:20:03:ec': [{'port_name': 'FC-Target-1:1:1',
|
'21:00:00:24:ff:20:03:ec': [{'port_name': 'FC-Target-1:1:1',
|
||||||
'wwn': '50:0b:34:20:01:00:18:05'},
|
'wwn': '50:0b:34:20:01:00:18:05'},
|
||||||
@ -188,12 +198,10 @@ class FakeMacroSANISCSIDriver(driver.MacroSANISCSIDriver):
|
|||||||
def _get_client_name(self, host):
|
def _get_client_name(self, host):
|
||||||
return 'devstack'
|
return 'devstack'
|
||||||
|
|
||||||
@utils.synchronized('MacroSAN-Attach', external=True)
|
|
||||||
def _attach_volume(self, context, volume, properties, remote=False):
|
def _attach_volume(self, context, volume, properties, remote=False):
|
||||||
return super(FakeMacroSANISCSIDriver, self)._attach_volume(
|
return super(FakeMacroSANISCSIDriver, self)._attach_volume(
|
||||||
context, volume, properties, remote)
|
context, volume, properties, remote)
|
||||||
|
|
||||||
@utils.synchronized('MacroSAN-Attach', external=True)
|
|
||||||
def _detach_volume(self, context, attach_info, volume,
|
def _detach_volume(self, context, attach_info, volume,
|
||||||
properties, force=False, remote=False,
|
properties, force=False, remote=False,
|
||||||
ignore_errors=True):
|
ignore_errors=True):
|
||||||
@ -383,8 +391,7 @@ class MacroSANISCSIDriverTestCase(test.TestCase):
|
|||||||
def setUp(self):
|
def setUp(self):
|
||||||
super(MacroSANISCSIDriverTestCase, self).setUp()
|
super(MacroSANISCSIDriverTestCase, self).setUp()
|
||||||
self.configuration = mock.Mock(spec=conf.Configuration)
|
self.configuration = mock.Mock(spec=conf.Configuration)
|
||||||
self.configuration.san_ip = \
|
self.configuration.san_ip = "172.192.251.1, 172.192.251.2"
|
||||||
"172.192.251.1, 172.192.251.2"
|
|
||||||
self.configuration.san_login = "openstack"
|
self.configuration.san_login = "openstack"
|
||||||
self.configuration.san_password = "passwd"
|
self.configuration.san_password = "passwd"
|
||||||
self.configuration.macrosan_sdas_ipaddrs = None
|
self.configuration.macrosan_sdas_ipaddrs = None
|
||||||
@ -398,9 +405,8 @@ class MacroSANISCSIDriverTestCase(test.TestCase):
|
|||||||
self.configuration.macrosan_snapshot_resource_ratio = 0.3
|
self.configuration.macrosan_snapshot_resource_ratio = 0.3
|
||||||
self.configuration.macrosan_log_timing = True
|
self.configuration.macrosan_log_timing = True
|
||||||
self.configuration.macrosan_client = \
|
self.configuration.macrosan_client = \
|
||||||
['devstack; decive1; "eth-1:0:0"; "eth-2:0:0"']
|
['devstack; device1; "eth-1:0:0"; "eth-2:0:0"']
|
||||||
self.configuration.macrosan_client_default = \
|
self.configuration.macrosan_client_default = "eth-1:0:0;eth-2:0:0"
|
||||||
"eth-1:0:0;eth-2:0:0"
|
|
||||||
self.driver = FakeMacroSANISCSIDriver(configuration=self.configuration)
|
self.driver = FakeMacroSANISCSIDriver(configuration=self.configuration)
|
||||||
self.driver.do_setup()
|
self.driver.do_setup()
|
||||||
|
|
||||||
@ -465,12 +471,19 @@ class MacroSANISCSIDriverTestCase(test.TestCase):
|
|||||||
actual = ret['provider_location']
|
actual = ret['provider_location']
|
||||||
self.assertEqual(test_volume['provider_location'], actual)
|
self.assertEqual(test_volume['provider_location'], actual)
|
||||||
|
|
||||||
|
@mock.patch.object(volume_types, 'get_volume_type',
|
||||||
|
return_value={'qos_specs_id':
|
||||||
|
'99f3d240-1b20-4b7b-9321-c6b8b86243ff',
|
||||||
|
'extra_specs': {}})
|
||||||
|
@mock.patch.object(qos_specs, 'get_qos_specs',
|
||||||
|
return_value={'specs': {'qos-strategy': 'QoS-1'}})
|
||||||
@mock.patch.object(socket, 'gethostname', return_value='controller')
|
@mock.patch.object(socket, 'gethostname', return_value='controller')
|
||||||
@mock.patch.object(utils, 'brick_get_connector',
|
@mock.patch.object(utils, 'brick_get_connector',
|
||||||
return_value=DummyBrickGetConnector())
|
return_value=DummyBrickGetConnector())
|
||||||
@mock.patch.object(volutils, 'copy_volume', return_value=None)
|
@mock.patch.object(volutils, 'copy_volume', return_value=None)
|
||||||
@mock.patch.object(os.path, 'realpath', return_value=None)
|
@mock.patch.object(os.path, 'realpath', return_value=None)
|
||||||
def test_create_cloned_volume(self, mock_hostname,
|
def test_create_cloned_volume(self, mock_volume_types, mock_qos,
|
||||||
|
mock_hostname,
|
||||||
mock_brick_get_connector,
|
mock_brick_get_connector,
|
||||||
mock_copy_volume,
|
mock_copy_volume,
|
||||||
mock_os_path):
|
mock_os_path):
|
||||||
@ -514,7 +527,9 @@ class MacroSANISCSIDriverTestCase(test.TestCase):
|
|||||||
@mock.patch.object(qos_specs, 'get_qos_specs',
|
@mock.patch.object(qos_specs, 'get_qos_specs',
|
||||||
return_value={'specs': {'qos-strategy': 'QoS-1'}})
|
return_value={'specs': {'qos-strategy': 'QoS-1'}})
|
||||||
def test_terminate_connection(self, mock_volume_type, mock_qos):
|
def test_terminate_connection(self, mock_volume_type, mock_qos):
|
||||||
self.driver.terminate_connection(test_volume, test_connector)
|
ret = self.driver.terminate_connection(test_volume, test_connector)
|
||||||
|
self.assertEqual({'driver_volume_type': 'iSCSI',
|
||||||
|
'data': expected_iscsi_connection_data}, ret)
|
||||||
|
|
||||||
def test_get_raid_list(self):
|
def test_get_raid_list(self):
|
||||||
expected = ["RAID-1"]
|
expected = ["RAID-1"]
|
||||||
@ -564,12 +579,19 @@ class MacroSANISCSIDriverTestCase(test.TestCase):
|
|||||||
self.driver.create_volume_from_snapshot,
|
self.driver.create_volume_from_snapshot,
|
||||||
test_volume, test_snap)
|
test_volume, test_snap)
|
||||||
|
|
||||||
|
@mock.patch.object(volume_types, 'get_volume_type',
|
||||||
|
return_value={'qos_specs_id':
|
||||||
|
'99f3d240-1b20-4b7b-9321-c6b8b86243ff',
|
||||||
|
'extra_specs': {}})
|
||||||
|
@mock.patch.object(qos_specs, 'get_qos_specs',
|
||||||
|
return_value={'specs': {'qos-strategy': 'QoS-1'}})
|
||||||
@mock.patch.object(socket, 'gethostname', return_value='controller')
|
@mock.patch.object(socket, 'gethostname', return_value='controller')
|
||||||
@mock.patch.object(utils, 'brick_get_connector',
|
@mock.patch.object(utils, 'brick_get_connector',
|
||||||
return_value=DummyBrickGetConnector())
|
return_value=DummyBrickGetConnector())
|
||||||
@mock.patch.object(volutils, 'copy_volume', return_value=None)
|
@mock.patch.object(volutils, 'copy_volume', return_value=None)
|
||||||
@mock.patch.object(os.path, 'realpath', return_value=None)
|
@mock.patch.object(os.path, 'realpath', return_value=None)
|
||||||
def test_create_cloned_volume_fail(self, mock_hostname,
|
def test_create_cloned_volume_fail(self, mock_volume_types, mock_qos,
|
||||||
|
mock_hostname,
|
||||||
mock_brick_get_connector,
|
mock_brick_get_connector,
|
||||||
mock_copy_volume,
|
mock_copy_volume,
|
||||||
mock_os_path):
|
mock_os_path):
|
||||||
@ -630,7 +652,7 @@ class MacroSANFCDriverTestCase(test.TestCase):
|
|||||||
self.configuration.macrosan_fc_keep_mapped_ports = True
|
self.configuration.macrosan_fc_keep_mapped_ports = True
|
||||||
self.configuration.macrosan_host_name = 'devstack'
|
self.configuration.macrosan_host_name = 'devstack'
|
||||||
self.configuration.macrosan_client = \
|
self.configuration.macrosan_client = \
|
||||||
['devstack; decive1; "eth-1:0:0"; "eth-2:0:0"']
|
['devstack; device1; "eth-1:0:0"; "eth-2:0:0"']
|
||||||
self.configuration.macrosan_client_default = \
|
self.configuration.macrosan_client_default = \
|
||||||
"eth-1:0:0;eth-2:0:0"
|
"eth-1:0:0;eth-2:0:0"
|
||||||
self.driver = FakeMacroSANFCDriver(configuration=self.configuration)
|
self.driver = FakeMacroSANFCDriver(configuration=self.configuration)
|
||||||
@ -647,19 +669,40 @@ class MacroSANFCDriverTestCase(test.TestCase):
|
|||||||
test_connector['wwpns'])
|
test_connector['wwpns'])
|
||||||
self.assertEqual(expected_initr_port_map_tgtexist, ret)
|
self.assertEqual(expected_initr_port_map_tgtexist, ret)
|
||||||
|
|
||||||
def test_initialize_connection(self):
|
@mock.patch.object(volume_types, 'get_volume_type',
|
||||||
|
return_value={'qos_specs_id':
|
||||||
|
'99f3d240-1b20-4b7b-9321-c6b8b86243ff',
|
||||||
|
'extra_specs': {}})
|
||||||
|
@mock.patch.object(qos_specs, 'get_qos_specs',
|
||||||
|
return_value={'specs': {'qos-strategy': 'QoS-1'}})
|
||||||
|
def test_initialize_connection(self, mock_volume_types, mock_qos):
|
||||||
ret = self.driver.initialize_connection(test_volume, test_connector)
|
ret = self.driver.initialize_connection(test_volume, test_connector)
|
||||||
self.assertEqual(expected_fctgtexist_properties, ret['data'])
|
self.assertEqual(expected_fctgtexist_properties, ret['data'])
|
||||||
|
|
||||||
def test_terminate_connection(self):
|
@mock.patch.object(volume_types, 'get_volume_type',
|
||||||
self.driver.terminate_connection(test_volume, test_connector)
|
return_value={'qos_specs_id':
|
||||||
|
'99f3d240-1b20-4b7b-9321-c6b8b86243ff',
|
||||||
|
'extra_specs': {}})
|
||||||
|
@mock.patch.object(qos_specs, 'get_qos_specs',
|
||||||
|
return_value={'specs': {'qos-strategy': 'QoS-1'}})
|
||||||
|
def test_terminate_connection(self, mock_volume_types, mock_qos):
|
||||||
|
ret = self.driver.terminate_connection(test_volume, test_connector)
|
||||||
|
self.assertEqual({'driver_volume_type': 'fibre_channel', 'data': {}},
|
||||||
|
ret)
|
||||||
|
|
||||||
|
@mock.patch.object(volume_types, 'get_volume_type',
|
||||||
|
return_value={'qos_specs_id':
|
||||||
|
'99f3d240-1b20-4b7b-9321-c6b8b86243ff',
|
||||||
|
'extra_specs': {}})
|
||||||
|
@mock.patch.object(qos_specs, 'get_qos_specs',
|
||||||
|
return_value={'specs': {'qos-strategy': 'QoS-1'}})
|
||||||
@mock.patch.object(socket, 'gethostname', return_value='controller')
|
@mock.patch.object(socket, 'gethostname', return_value='controller')
|
||||||
@mock.patch.object(utils, 'brick_get_connector',
|
@mock.patch.object(utils, 'brick_get_connector',
|
||||||
return_value=DummyBrickGetConnector())
|
return_value=DummyBrickGetConnector())
|
||||||
@mock.patch.object(volutils, 'copy_volume', return_value=None)
|
@mock.patch.object(volutils, 'copy_volume', return_value=None)
|
||||||
@mock.patch.object(os.path, 'realpath', return_value=None)
|
@mock.patch.object(os.path, 'realpath', return_value=None)
|
||||||
def test_create_volume_from_snapshot(self, mock_hostname,
|
def test_create_volume_from_snapshot(self, mock_volume_types, mock_qos,
|
||||||
|
mock_hostname,
|
||||||
mock_brick_get_connector,
|
mock_brick_get_connector,
|
||||||
mock_copy_volume,
|
mock_copy_volume,
|
||||||
mock_os_path):
|
mock_os_path):
|
||||||
@ -667,12 +710,20 @@ class MacroSANFCDriverTestCase(test.TestCase):
|
|||||||
actual = ret['provider_location']
|
actual = ret['provider_location']
|
||||||
self.assertEqual(test_volume['provider_location'], actual)
|
self.assertEqual(test_volume['provider_location'], actual)
|
||||||
|
|
||||||
|
@mock.patch.object(volume_types, 'get_volume_type',
|
||||||
|
return_value={
|
||||||
|
'qos_specs_id':
|
||||||
|
'99f3d240-1b20-4b7b-9321-c6b8b86243ff',
|
||||||
|
'extra_specs': {}})
|
||||||
|
@mock.patch.object(qos_specs, 'get_qos_specs',
|
||||||
|
return_value={'specs': {'qos-strategy': 'QoS-1'}})
|
||||||
@mock.patch.object(socket, 'gethostname', return_value='controller')
|
@mock.patch.object(socket, 'gethostname', return_value='controller')
|
||||||
@mock.patch.object(utils, 'brick_get_connector',
|
@mock.patch.object(utils, 'brick_get_connector',
|
||||||
return_value=DummyBrickGetConnector())
|
return_value=DummyBrickGetConnector())
|
||||||
@mock.patch.object(volutils, 'copy_volume', return_value=None)
|
@mock.patch.object(volutils, 'copy_volume', return_value=None)
|
||||||
@mock.patch.object(os.path, 'realpath', return_value=None)
|
@mock.patch.object(os.path, 'realpath', return_value=None)
|
||||||
def test_create_cloned_volume(self, mock_hostname,
|
def test_create_cloned_volume(self, mock_volume_types, mock_qos,
|
||||||
|
mock_hostname,
|
||||||
mock_brick_get_connector,
|
mock_brick_get_connector,
|
||||||
mock_copy_volume,
|
mock_copy_volume,
|
||||||
mock_os_path):
|
mock_os_path):
|
||||||
@ -681,12 +732,20 @@ class MacroSANFCDriverTestCase(test.TestCase):
|
|||||||
actual = ret['provider_location']
|
actual = ret['provider_location']
|
||||||
self.assertEqual(test_volume['provider_location'], actual)
|
self.assertEqual(test_volume['provider_location'], actual)
|
||||||
|
|
||||||
|
@mock.patch.object(volume_types, 'get_volume_type',
|
||||||
|
return_value={'qos_specs_id':
|
||||||
|
'99f3d240-1b20-4b7b-9321-c6b8b86243ff',
|
||||||
|
'extra_specs': {}})
|
||||||
|
@mock.patch.object(qos_specs, 'get_qos_specs',
|
||||||
|
return_value={'specs': {'qos-strategy': 'QoS-1'}})
|
||||||
@mock.patch.object(socket, 'gethostname', return_value='controller')
|
@mock.patch.object(socket, 'gethostname', return_value='controller')
|
||||||
@mock.patch.object(utils, 'brick_get_connector',
|
@mock.patch.object(utils, 'brick_get_connector',
|
||||||
return_value=DummyBrickGetConnector())
|
return_value=DummyBrickGetConnector())
|
||||||
@mock.patch.object(volutils, 'copy_volume', return_value=None)
|
@mock.patch.object(volutils, 'copy_volume', return_value=None)
|
||||||
@mock.patch.object(os.path, 'realpath', return_value=None)
|
@mock.patch.object(os.path, 'realpath', return_value=None)
|
||||||
def test_create_volume_from_snapshot_fail(self, mock_hostname,
|
def test_create_volume_from_snapshot_fail(self, mock_volume_types,
|
||||||
|
mock_qos,
|
||||||
|
mock_hostname,
|
||||||
mock_brick_get_connector,
|
mock_brick_get_connector,
|
||||||
mock_copy_volume,
|
mock_copy_volume,
|
||||||
mock_os_path):
|
mock_os_path):
|
||||||
@ -695,12 +754,19 @@ class MacroSANFCDriverTestCase(test.TestCase):
|
|||||||
self.driver.create_volume_from_snapshot,
|
self.driver.create_volume_from_snapshot,
|
||||||
test_volume, test_snap)
|
test_volume, test_snap)
|
||||||
|
|
||||||
|
@mock.patch.object(volume_types, 'get_volume_type',
|
||||||
|
return_value={'qos_specs_id':
|
||||||
|
'99f3d240-1b20-4b7b-9321-c6b8b86243ff',
|
||||||
|
'extra_specs': {}})
|
||||||
|
@mock.patch.object(qos_specs, 'get_qos_specs',
|
||||||
|
return_value={'specs': {'qos-strategy': 'QoS-1'}})
|
||||||
@mock.patch.object(socket, 'gethostname', return_value='controller')
|
@mock.patch.object(socket, 'gethostname', return_value='controller')
|
||||||
@mock.patch.object(utils, 'brick_get_connector',
|
@mock.patch.object(utils, 'brick_get_connector',
|
||||||
return_value=DummyBrickGetConnector())
|
return_value=DummyBrickGetConnector())
|
||||||
@mock.patch.object(volutils, 'copy_volume', return_value=None)
|
@mock.patch.object(volutils, 'copy_volume', return_value=None)
|
||||||
@mock.patch.object(os.path, 'realpath', return_value=None)
|
@mock.patch.object(os.path, 'realpath', return_value=None)
|
||||||
def test_create_cloned_volume_fail(self, mock_hostname,
|
def test_create_cloned_volume_fail(self, mock_volume_types, mock_qos,
|
||||||
|
mock_hostname,
|
||||||
mock_brick_get_connector,
|
mock_brick_get_connector,
|
||||||
mock_copy_volume,
|
mock_copy_volume,
|
||||||
mock_os_path):
|
mock_os_path):
|
||||||
@ -709,13 +775,25 @@ class MacroSANFCDriverTestCase(test.TestCase):
|
|||||||
self.driver.create_cloned_volume,
|
self.driver.create_cloned_volume,
|
||||||
test_volume, test_volume)
|
test_volume, test_volume)
|
||||||
|
|
||||||
def test_initialize_connection_fail(self):
|
@mock.patch.object(volume_types, 'get_volume_type',
|
||||||
|
return_value={'qos_specs_id':
|
||||||
|
'99f3d240-1b20-4b7b-9321-c6b8b86243ff',
|
||||||
|
'extra_specs': {}})
|
||||||
|
@mock.patch.object(qos_specs, 'get_qos_specs',
|
||||||
|
return_value={'specs': {'qos-strategy': 'QoS-1'}})
|
||||||
|
def test_initialize_connection_fail(self, mock_volume_types, mock_qos):
|
||||||
self.driver.client.cmd_fail = True
|
self.driver.client.cmd_fail = True
|
||||||
self.assertRaises(exception.VolumeBackendAPIException,
|
self.assertRaises(exception.VolumeBackendAPIException,
|
||||||
self.driver.initialize_connection,
|
self.driver.initialize_connection,
|
||||||
test_volume, test_connector)
|
test_volume, test_connector)
|
||||||
|
|
||||||
def test_terminate_connection_fail(self):
|
@mock.patch.object(volume_types, 'get_volume_type',
|
||||||
|
return_value={'qos_specs_id':
|
||||||
|
'99f3d240-1b20-4b7b-9321-c6b8b86243ff',
|
||||||
|
'extra_specs': {}})
|
||||||
|
@mock.patch.object(qos_specs, 'get_qos_specs',
|
||||||
|
return_value={'specs': {'qos-strategy': 'QoS-1'}})
|
||||||
|
def test_terminate_connection_fail(self, mock_volume_types, mock_qos):
|
||||||
self.driver.client.cmd_fail = True
|
self.driver.client.cmd_fail = True
|
||||||
self.assertRaises(exception.VolumeBackendAPIException,
|
self.assertRaises(exception.VolumeBackendAPIException,
|
||||||
self.driver.terminate_connection,
|
self.driver.terminate_connection,
|
||||||
|
@ -20,33 +20,25 @@ from oslo_config import cfg
|
|||||||
macrosan_opts = [
|
macrosan_opts = [
|
||||||
# sdas login_info
|
# sdas login_info
|
||||||
cfg.ListOpt('macrosan_sdas_ipaddrs',
|
cfg.ListOpt('macrosan_sdas_ipaddrs',
|
||||||
default=None,
|
|
||||||
help="MacroSAN sdas devices' ip addresses"),
|
help="MacroSAN sdas devices' ip addresses"),
|
||||||
cfg.StrOpt('macrosan_sdas_username',
|
cfg.StrOpt('macrosan_sdas_username',
|
||||||
default=None,
|
help="MacroSAN sdas devices' username"),
|
||||||
help=""),
|
|
||||||
cfg.StrOpt('macrosan_sdas_password',
|
cfg.StrOpt('macrosan_sdas_password',
|
||||||
default=None,
|
secret=True,
|
||||||
help="",
|
help="MacroSAN sdas devices' password"),
|
||||||
secret=True),
|
|
||||||
# replication login_info
|
# replication login_info
|
||||||
cfg.ListOpt('macrosan_replication_ipaddrs',
|
cfg.ListOpt('macrosan_replication_ipaddrs',
|
||||||
default=None,
|
|
||||||
help="MacroSAN replication devices' ip addresses"),
|
help="MacroSAN replication devices' ip addresses"),
|
||||||
cfg.StrOpt('macrosan_replication_username',
|
cfg.StrOpt('macrosan_replication_username',
|
||||||
default=None,
|
help="MacroSAN replication devices' username"),
|
||||||
help=""),
|
|
||||||
cfg.StrOpt('macrosan_replication_password',
|
cfg.StrOpt('macrosan_replication_password',
|
||||||
default=None,
|
secret=True,
|
||||||
help="",
|
help="MacroSAN replication devices' password"),
|
||||||
secret=True),
|
|
||||||
cfg.ListOpt('macrosan_replication_destination_ports',
|
cfg.ListOpt('macrosan_replication_destination_ports',
|
||||||
default=None,
|
|
||||||
sample_default="eth-1:0/eth-1:1, eth-2:0/eth-2:1",
|
sample_default="eth-1:0/eth-1:1, eth-2:0/eth-2:1",
|
||||||
help="Slave device"),
|
help="Slave device"),
|
||||||
# device_features
|
# device_features
|
||||||
cfg.StrOpt('macrosan_pool', quotes=True,
|
cfg.StrOpt('macrosan_pool', quotes=True,
|
||||||
default=None,
|
|
||||||
help='Pool to use for volume creation'),
|
help='Pool to use for volume creation'),
|
||||||
cfg.IntOpt('macrosan_thin_lun_extent_size',
|
cfg.IntOpt('macrosan_thin_lun_extent_size',
|
||||||
default=8,
|
default=8,
|
||||||
@ -80,7 +72,6 @@ macrosan_opts = [
|
|||||||
"item associated with the port is maintained."),
|
"item associated with the port is maintained."),
|
||||||
# iscsi connection
|
# iscsi connection
|
||||||
cfg.ListOpt('macrosan_client',
|
cfg.ListOpt('macrosan_client',
|
||||||
default=None,
|
|
||||||
help="""Macrosan iscsi_clients list.
|
help="""Macrosan iscsi_clients list.
|
||||||
You can configure multiple clients.
|
You can configure multiple clients.
|
||||||
You can configure it in this format:
|
You can configure it in this format:
|
||||||
@ -89,12 +80,12 @@ macrosan_opts = [
|
|||||||
Important warning, Client_name has the following requirements:
|
Important warning, Client_name has the following requirements:
|
||||||
[a-zA-Z0-9.-_:], the maximum number of characters is 31
|
[a-zA-Z0-9.-_:], the maximum number of characters is 31
|
||||||
E.g:
|
E.g:
|
||||||
(controller1; decive1; eth-1:0; eth-2:0),
|
(controller1; device1; eth-1:0; eth-2:0),
|
||||||
(controller2; decive2; eth-1:0/eth-1:1; eth-2:0/eth-2:1),
|
(controller2; device2; eth-1:0/eth-1:1; eth-2:0/eth-2:1),
|
||||||
"""),
|
"""),
|
||||||
cfg.StrOpt('macrosan_client_default',
|
cfg.StrOpt('macrosan_client_default',
|
||||||
default=None,
|
help="This is the default connection ports' name for iscsi. "
|
||||||
help="This is the default connection information for iscsi. "
|
|
||||||
"This default configuration is used "
|
"This default configuration is used "
|
||||||
"when no host related information is obtained.")
|
"when no host related information is obtained."
|
||||||
|
"E.g: eth-1:0/eth-1:1; eth-2:0/eth-2:1")
|
||||||
]
|
]
|
||||||
|
@ -109,7 +109,7 @@ class Client(object):
|
|||||||
'attr': 'existence',
|
'attr': 'existence',
|
||||||
'name': name
|
'name': name
|
||||||
}
|
}
|
||||||
return self.send_request('get', '/lun', data=data)
|
return self.send_request(method='get', url='/lun', data=data)
|
||||||
|
|
||||||
def snapshot_point_exists(self, lun_name, pointid):
|
def snapshot_point_exists(self, lun_name, pointid):
|
||||||
"""Whether the snapshot point exists."""
|
"""Whether the snapshot point exists."""
|
||||||
|
@ -14,17 +14,13 @@
|
|||||||
# under the License.
|
# under the License.
|
||||||
"""Volume Drivers for MacroSAN SAN."""
|
"""Volume Drivers for MacroSAN SAN."""
|
||||||
|
|
||||||
import base64
|
|
||||||
from contextlib import contextmanager
|
from contextlib import contextmanager
|
||||||
import math
|
import math
|
||||||
import re
|
import re
|
||||||
import six
|
|
||||||
import socket
|
import socket
|
||||||
import time
|
import time
|
||||||
import uuid
|
import uuid
|
||||||
|
|
||||||
from os_brick.initiator import connector as cn
|
|
||||||
from os_brick.initiator import linuxfc
|
|
||||||
from oslo_config import cfg
|
from oslo_config import cfg
|
||||||
from oslo_log import log as logging
|
from oslo_log import log as logging
|
||||||
from oslo_utils import excutils
|
from oslo_utils import excutils
|
||||||
@ -47,7 +43,7 @@ from cinder.volume import utils as volume_utils
|
|||||||
from cinder.volume import volume_types
|
from cinder.volume import volume_types
|
||||||
from cinder.zonemanager import utils as fczm_utils
|
from cinder.zonemanager import utils as fczm_utils
|
||||||
|
|
||||||
version = '1.0.0'
|
version = '1.0.1'
|
||||||
lock_name = 'MacroSAN'
|
lock_name = 'MacroSAN'
|
||||||
|
|
||||||
LOG = logging.getLogger(__name__)
|
LOG = logging.getLogger(__name__)
|
||||||
@ -63,22 +59,6 @@ def ignored(*exceptions):
|
|||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
def _timing(fn):
|
|
||||||
def __timing(*vargs, **kv):
|
|
||||||
start = time.time()
|
|
||||||
if timing_on:
|
|
||||||
LOG.info('========== start %s', fn.__name__)
|
|
||||||
|
|
||||||
result = fn(*vargs, **kv)
|
|
||||||
|
|
||||||
if timing_on:
|
|
||||||
end = time.time()
|
|
||||||
LOG.info('========== end %(fname)s, cost: %(cost).2f secs',
|
|
||||||
{'fname': fn.__name__, 'cost': end - start})
|
|
||||||
return result
|
|
||||||
return __timing
|
|
||||||
|
|
||||||
|
|
||||||
def record_request_id(fn):
|
def record_request_id(fn):
|
||||||
def _record_request_id(*vargs, **kv):
|
def _record_request_id(*vargs, **kv):
|
||||||
ctx = context.context.get_current()
|
ctx = context.context.get_current()
|
||||||
@ -93,14 +73,6 @@ def replication_synced(params):
|
|||||||
params['replication_mode'] == 'sync')
|
params['replication_mode'] == 'sync')
|
||||||
|
|
||||||
|
|
||||||
def b64encode(s):
|
|
||||||
return base64.b64encode(six.b(s)).decode()
|
|
||||||
|
|
||||||
|
|
||||||
def b64decode(s):
|
|
||||||
return base64.b64decode(six.b(s)).decode()
|
|
||||||
|
|
||||||
|
|
||||||
class MacroSANBaseDriver(driver.VolumeDriver):
|
class MacroSANBaseDriver(driver.VolumeDriver):
|
||||||
"""Base driver for MacroSAN SAN."""
|
"""Base driver for MacroSAN SAN."""
|
||||||
|
|
||||||
@ -182,15 +154,6 @@ class MacroSANBaseDriver(driver.VolumeDriver):
|
|||||||
|
|
||||||
self.initialize_iscsi_info()
|
self.initialize_iscsi_info()
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def get_driver_options():
|
|
||||||
"""Return the oslo_config options specific to the driver."""
|
|
||||||
return config.macrosan_opts
|
|
||||||
|
|
||||||
@property
|
|
||||||
def _self_node_wwns(self):
|
|
||||||
return []
|
|
||||||
|
|
||||||
def _size_str_to_int(self, size_in_g):
|
def _size_str_to_int(self, size_in_g):
|
||||||
if int(size_in_g) == 0:
|
if int(size_in_g) == 0:
|
||||||
return 1
|
return 1
|
||||||
@ -254,7 +217,7 @@ class MacroSANBaseDriver(driver.VolumeDriver):
|
|||||||
self.replica_login_info))
|
self.replica_login_info))
|
||||||
self.device_uuid = self.client.get_device_uuid()
|
self.device_uuid = self.client.get_device_uuid()
|
||||||
self._do_setup()
|
self._do_setup()
|
||||||
LOG.info('MacroSAN Cinder Driver setup complete.')
|
LOG.debug('MacroSAN Cinder Driver setup complete.')
|
||||||
|
|
||||||
def _do_setup(self):
|
def _do_setup(self):
|
||||||
pass
|
pass
|
||||||
@ -448,14 +411,9 @@ class MacroSANBaseDriver(driver.VolumeDriver):
|
|||||||
|
|
||||||
@synchronized(lock_name)
|
@synchronized(lock_name)
|
||||||
@record_request_id
|
@record_request_id
|
||||||
@_timing
|
@utils.trace
|
||||||
def create_volume(self, volume):
|
def create_volume(self, volume):
|
||||||
"""Create a volume."""
|
"""Create a volume."""
|
||||||
LOG.debug(('========== create volume, name: %(name)s,'
|
|
||||||
'id: %(volume_id)s, size: %(size)s.'),
|
|
||||||
{'name': volume['name'], 'volume_id': volume['id'],
|
|
||||||
'size': volume['size']})
|
|
||||||
|
|
||||||
name = volume['name']
|
name = volume['name']
|
||||||
size = self._size_str_to_int(volume['size'])
|
size = self._size_str_to_int(volume['size'])
|
||||||
params = self._parse_volume_params(volume)
|
params = self._parse_volume_params(volume)
|
||||||
@ -508,22 +466,21 @@ class MacroSANBaseDriver(driver.VolumeDriver):
|
|||||||
|
|
||||||
@synchronized(lock_name)
|
@synchronized(lock_name)
|
||||||
@record_request_id
|
@record_request_id
|
||||||
@_timing
|
@utils.trace
|
||||||
def delete_volume(self, volume):
|
def delete_volume(self, volume):
|
||||||
"""Delete a volume."""
|
"""Delete a volume."""
|
||||||
LOG.debug('========== delete volume, id: %s.', volume['id'])
|
|
||||||
name = self._volume_name(volume)
|
name = self._volume_name(volume)
|
||||||
params = self._parse_volume_params(volume)
|
params = self._parse_volume_params(volume)
|
||||||
self._delete_volume(name, params)
|
self._delete_volume(name, params)
|
||||||
|
|
||||||
@utils.synchronized('MacroSAN-Attach', external=True)
|
@utils.synchronized('MacroSAN-Attach-Detach', external=True)
|
||||||
def _attach_volume(self, context, volume, properties, remote=False):
|
def _attach_volume(self, context, volume, properties, remote=False):
|
||||||
return super(MacroSANBaseDriver, self)._attach_volume(context,
|
return super(MacroSANBaseDriver, self)._attach_volume(context,
|
||||||
volume,
|
volume,
|
||||||
properties,
|
properties,
|
||||||
remote)
|
remote)
|
||||||
|
|
||||||
@utils.synchronized('MacroSAN-Attach', external=True)
|
@utils.synchronized('MacroSAN-Attach-Detach', external=True)
|
||||||
def _detach_volume(self, context, attach_info, volume,
|
def _detach_volume(self, context, attach_info, volume,
|
||||||
properties, force=False, remote=False,
|
properties, force=False, remote=False,
|
||||||
ignore_errors=True):
|
ignore_errors=True):
|
||||||
@ -568,14 +525,10 @@ class MacroSANBaseDriver(driver.VolumeDriver):
|
|||||||
|
|
||||||
@synchronized(lock_name)
|
@synchronized(lock_name)
|
||||||
@record_request_id
|
@record_request_id
|
||||||
@_timing
|
@utils.trace
|
||||||
def create_snapshot(self, snapshot):
|
def create_snapshot(self, snapshot):
|
||||||
"""Create a snapshot."""
|
"""Create a snapshot."""
|
||||||
volume = snapshot['volume']
|
volume = snapshot['volume']
|
||||||
LOG.debug(('========== create snapshot, snapshot id: %(snapshot_id)s,'
|
|
||||||
' volume id: %(volume_id)s, size: %(size)s.'),
|
|
||||||
{'snapshot_id': snapshot['id'], 'volume_id': volume['id'],
|
|
||||||
'size': volume['size']})
|
|
||||||
|
|
||||||
snapshot_name = self._snapshot_name(snapshot['name'])
|
snapshot_name = self._snapshot_name(snapshot['name'])
|
||||||
volume_name = self._volume_name(volume)
|
volume_name = self._volume_name(volume)
|
||||||
@ -601,7 +554,7 @@ class MacroSANBaseDriver(driver.VolumeDriver):
|
|||||||
|
|
||||||
@synchronized(lock_name)
|
@synchronized(lock_name)
|
||||||
@record_request_id
|
@record_request_id
|
||||||
@_timing
|
@utils.trace
|
||||||
def delete_snapshot(self, snapshot):
|
def delete_snapshot(self, snapshot):
|
||||||
"""Delete a snapshot."""
|
"""Delete a snapshot."""
|
||||||
volume = snapshot['volume']
|
volume = snapshot['volume']
|
||||||
@ -612,10 +565,7 @@ class MacroSANBaseDriver(driver.VolumeDriver):
|
|||||||
m = re.findall(r'pointid: (\d+)', provider)
|
m = re.findall(r'pointid: (\d+)', provider)
|
||||||
if m is None:
|
if m is None:
|
||||||
return
|
return
|
||||||
LOG.debug(('========== delete snapshot, snapshot id: %(snapshot_id)s,'
|
|
||||||
' pointid: %(point_id)s, volume id: %(volume_id)s.'),
|
|
||||||
{'snapshot_id': snapshot['id'], 'point_id': m[0],
|
|
||||||
'volume_id': volume['id']})
|
|
||||||
snapshot_name = self._snapshot_name(snapshot['id'])
|
snapshot_name = self._snapshot_name(snapshot['id'])
|
||||||
volume_name = self._volume_name(volume)
|
volume_name = self._volume_name(volume)
|
||||||
self._delete_snapshot(snapshot_name, volume_name, m[0])
|
self._delete_snapshot(snapshot_name, volume_name, m[0])
|
||||||
@ -626,35 +576,6 @@ class MacroSANBaseDriver(driver.VolumeDriver):
|
|||||||
def _terminate_connection(self, name, host, wwns):
|
def _terminate_connection(self, name, host, wwns):
|
||||||
raise NotImplementedError
|
raise NotImplementedError
|
||||||
|
|
||||||
def _connect(self, name):
|
|
||||||
host = socket.gethostname()
|
|
||||||
conn = self._initialize_connection(name, host,
|
|
||||||
self._self_node_wwns)
|
|
||||||
|
|
||||||
device_scan_attempts = self.configuration.num_volume_device_scan_tries
|
|
||||||
protocol = conn['driver_volume_type']
|
|
||||||
connector = utils.brick_get_connector(
|
|
||||||
protocol,
|
|
||||||
use_multipath=self.use_multipath,
|
|
||||||
device_scan_attempts=device_scan_attempts,
|
|
||||||
conn=conn)
|
|
||||||
device = None
|
|
||||||
try:
|
|
||||||
device = connector.connect_volume(conn['data'])
|
|
||||||
except Exception:
|
|
||||||
with excutils.save_and_reraise_exception():
|
|
||||||
self._terminate_connection(name, host, self._self_node_wwns)
|
|
||||||
|
|
||||||
return {'conn': conn, 'device': device, 'connector': connector}
|
|
||||||
|
|
||||||
def _disconnect(self, conn, name):
|
|
||||||
connector = conn['connector']
|
|
||||||
connector.disconnect_volume(conn['conn']['data'],
|
|
||||||
conn['device'])
|
|
||||||
|
|
||||||
self._terminate_connection(name, socket.gethostname(),
|
|
||||||
self._self_node_wwns)
|
|
||||||
|
|
||||||
def _create_volume_from_snapshot(self, vol_name, vol_size,
|
def _create_volume_from_snapshot(self, vol_name, vol_size,
|
||||||
vol_params, snp_name, pointid,
|
vol_params, snp_name, pointid,
|
||||||
snp_vol_name, snp_vol_size):
|
snp_vol_name, snp_vol_size):
|
||||||
@ -685,10 +606,9 @@ class MacroSANBaseDriver(driver.VolumeDriver):
|
|||||||
|
|
||||||
@synchronized(lock_name)
|
@synchronized(lock_name)
|
||||||
@record_request_id
|
@record_request_id
|
||||||
@_timing
|
@utils.trace
|
||||||
def create_volume_from_snapshot(self, volume, snapshot):
|
def create_volume_from_snapshot(self, volume, snapshot):
|
||||||
"""Create a volume from a snapshot."""
|
"""Create a volume from a snapshot."""
|
||||||
LOG.debug('========== create volume from snapshot.')
|
|
||||||
snapshot_volume = snapshot['volume']
|
snapshot_volume = snapshot['volume']
|
||||||
provider = snapshot['provider_location']
|
provider = snapshot['provider_location']
|
||||||
m = re.findall(r'pointid: (\d+)', provider)
|
m = re.findall(r'pointid: (\d+)', provider)
|
||||||
@ -727,10 +647,9 @@ class MacroSANBaseDriver(driver.VolumeDriver):
|
|||||||
self._delete_snapshot(snp_name, src_vol_name, pointid)
|
self._delete_snapshot(snp_name, src_vol_name, pointid)
|
||||||
|
|
||||||
@record_request_id
|
@record_request_id
|
||||||
@_timing
|
@utils.trace
|
||||||
def create_cloned_volume(self, volume, src_vref):
|
def create_cloned_volume(self, volume, src_vref):
|
||||||
"""Create a clone of the specified volume."""
|
"""Create a clone of the specified volume."""
|
||||||
LOG.debug('========== create cloned volume.')
|
|
||||||
vol_name = volume['id']
|
vol_name = volume['id']
|
||||||
src_vol_name = self._volume_name(src_vref)
|
src_vol_name = self._volume_name(src_vref)
|
||||||
snapshotid =\
|
snapshotid =\
|
||||||
@ -768,13 +687,9 @@ class MacroSANBaseDriver(driver.VolumeDriver):
|
|||||||
|
|
||||||
@synchronized(lock_name)
|
@synchronized(lock_name)
|
||||||
@record_request_id
|
@record_request_id
|
||||||
@_timing
|
@utils.trace
|
||||||
def extend_volume(self, volume, new_size):
|
def extend_volume(self, volume, new_size):
|
||||||
"""Extend a volume."""
|
"""Extend a volume."""
|
||||||
LOG.debug(('========== extend volume, id: %(volume_id)s,'
|
|
||||||
'size: %(size)s.'),
|
|
||||||
{'volume_id': volume['id'], 'size': new_size})
|
|
||||||
|
|
||||||
name = self._volume_name(volume)
|
name = self._volume_name(volume)
|
||||||
moresize = self._size_str_to_int(new_size - int(volume['size']))
|
moresize = self._size_str_to_int(new_size - int(volume['size']))
|
||||||
params = self._parse_volume_params(volume)
|
params = self._parse_volume_params(volume)
|
||||||
@ -839,14 +754,12 @@ class MacroSANBaseDriver(driver.VolumeDriver):
|
|||||||
self._stats = data
|
self._stats = data
|
||||||
|
|
||||||
@record_request_id
|
@record_request_id
|
||||||
|
@utils.trace
|
||||||
def update_migrated_volume(self, ctxt, volume, new_volume,
|
def update_migrated_volume(self, ctxt, volume, new_volume,
|
||||||
original_volume_status=None):
|
original_volume_status=None):
|
||||||
"""Return model update for migrated volume."""
|
"""Return model update for migrated volume."""
|
||||||
original_name = self._volume_name(volume)
|
original_name = self._volume_name(volume)
|
||||||
cur_name = self._volume_name(new_volume)
|
cur_name = self._volume_name(new_volume)
|
||||||
LOG.debug(('========== update migrated volume,'
|
|
||||||
'volume: %(original_name)s, new_volume: %(cur_name)s'),
|
|
||||||
{'original_name': original_name, 'cur_name': cur_name})
|
|
||||||
|
|
||||||
if self.client.lun_exists(original_name):
|
if self.client.lun_exists(original_name):
|
||||||
self.client.backup_lun_name_to_rename_file(cur_name, original_name)
|
self.client.backup_lun_name_to_rename_file(cur_name, original_name)
|
||||||
@ -866,7 +779,7 @@ class MacroSANBaseDriver(driver.VolumeDriver):
|
|||||||
|
|
||||||
@synchronized(lock_name)
|
@synchronized(lock_name)
|
||||||
@record_request_id
|
@record_request_id
|
||||||
@_timing
|
@utils.trace
|
||||||
def initialize_connection_snapshot(self, snapshot, connector, **kwargs):
|
def initialize_connection_snapshot(self, snapshot, connector, **kwargs):
|
||||||
volume = snapshot['volume']
|
volume = snapshot['volume']
|
||||||
provider = snapshot['provider_location']
|
provider = snapshot['provider_location']
|
||||||
@ -905,13 +818,13 @@ class MacroSANBaseDriver(driver.VolumeDriver):
|
|||||||
|
|
||||||
@synchronized(lock_name)
|
@synchronized(lock_name)
|
||||||
@record_request_id
|
@record_request_id
|
||||||
@_timing
|
@utils.trace
|
||||||
def manage_existing(self, volume, external_ref):
|
def manage_existing(self, volume, external_ref):
|
||||||
vol_params = self._parse_volume_params(volume)
|
vol_params = self._parse_volume_params(volume)
|
||||||
self._check_volume_params(vol_params)
|
self._check_volume_params(vol_params)
|
||||||
if vol_params['qos-strategy']:
|
if vol_params['qos-strategy']:
|
||||||
raise exception.VolumeBackendAPIException(
|
raise exception.VolumeBackendAPIException(
|
||||||
data=_('Not support to import qos-strategy'))
|
data=_('Import qos-strategy not supported'))
|
||||||
|
|
||||||
pool = volume_utils.extract_host(volume.host, 'pool')
|
pool = volume_utils.extract_host(volume.host, 'pool')
|
||||||
name, info, params = self._get_existing_lun_info(external_ref)
|
name, info, params = self._get_existing_lun_info(external_ref)
|
||||||
@ -995,7 +908,7 @@ class MacroSANBaseDriver(driver.VolumeDriver):
|
|||||||
|
|
||||||
@synchronized(lock_name)
|
@synchronized(lock_name)
|
||||||
@record_request_id
|
@record_request_id
|
||||||
@_timing
|
@utils.trace
|
||||||
def manage_existing_snapshot(self, snapshot, existing_ref):
|
def manage_existing_snapshot(self, snapshot, existing_ref):
|
||||||
volume = snapshot['volume']
|
volume = snapshot['volume']
|
||||||
src_name = self._get_existing_snapname(existing_ref).lstrip('_')
|
src_name = self._get_existing_snapname(existing_ref).lstrip('_')
|
||||||
@ -1042,7 +955,7 @@ class MacroSANBaseDriver(driver.VolumeDriver):
|
|||||||
|
|
||||||
@synchronized(lock_name)
|
@synchronized(lock_name)
|
||||||
@record_request_id
|
@record_request_id
|
||||||
@_timing
|
@utils.trace
|
||||||
def migrate_volume(self, ctxt, volume, host):
|
def migrate_volume(self, ctxt, volume, host):
|
||||||
if not self.migration_valid(volume, host):
|
if not self.migration_valid(volume, host):
|
||||||
return False, None
|
return False, None
|
||||||
@ -1054,8 +967,11 @@ class MacroSANBaseDriver(driver.VolumeDriver):
|
|||||||
owner = self.client.get_lun_sp(src_name)
|
owner = self.client.get_lun_sp(src_name)
|
||||||
pool = host['capabilities'].get('pool_name', self.pool)
|
pool = host['capabilities'].get('pool_name', self.pool)
|
||||||
|
|
||||||
LOG.info('host: %(host)s, backend: %(volume_backend_name)s',
|
LOG.info('Migrating volume: %(volume), '
|
||||||
{'host': host,
|
'host: %(host)s, '
|
||||||
|
'backend: %(volume_backend_name)s',
|
||||||
|
{'volume': src_name,
|
||||||
|
'host': host,
|
||||||
'volume_backend_name': self.volume_backend_name})
|
'volume_backend_name': self.volume_backend_name})
|
||||||
self._create_volume(name, size, params, owner, pool)
|
self._create_volume(name, size, params, owner, pool)
|
||||||
|
|
||||||
@ -1106,8 +1022,10 @@ class MacroSANISCSIDriver(MacroSANBaseDriver, driver.ISCSIDriver):
|
|||||||
.. code-block:: none
|
.. code-block:: none
|
||||||
|
|
||||||
1.0.0 - Initial driver
|
1.0.0 - Initial driver
|
||||||
|
1.0.1 - Adjust some log level and text prompts; Remove some useless
|
||||||
|
functions; Add Cinder trace decorator. #1837920
|
||||||
"""
|
"""
|
||||||
VERSION = "1.0.0"
|
VERSION = "1.0.1"
|
||||||
|
|
||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
"""Initialize the driver."""
|
"""Initialize the driver."""
|
||||||
@ -1198,11 +1116,6 @@ class MacroSANISCSIDriver(MacroSANBaseDriver, driver.ISCSIDriver):
|
|||||||
|
|
||||||
return id_list.pop()
|
return id_list.pop()
|
||||||
|
|
||||||
@property
|
|
||||||
def _self_node_wwns(self):
|
|
||||||
connector = cn.ISCSIConnector(utils.get_root_helper())
|
|
||||||
return [connector.get_initiator()]
|
|
||||||
|
|
||||||
def _initialize_connection(self, name, vol_params, host, wwns):
|
def _initialize_connection(self, name, vol_params, host, wwns):
|
||||||
client_name = self._get_client_name(host)
|
client_name = self._get_client_name(host)
|
||||||
wwn = wwns[0]
|
wwn = wwns[0]
|
||||||
@ -1242,11 +1155,9 @@ class MacroSANISCSIDriver(MacroSANBaseDriver, driver.ISCSIDriver):
|
|||||||
|
|
||||||
@synchronized(lock_name)
|
@synchronized(lock_name)
|
||||||
@record_request_id
|
@record_request_id
|
||||||
@_timing
|
@utils.trace
|
||||||
def initialize_connection(self, volume, connector):
|
def initialize_connection(self, volume, connector):
|
||||||
"""Allow connection to connector and return connection info."""
|
"""Allow connection to connector and return connection info."""
|
||||||
LOG.debug('========== initialize_connection connector: %(connector)s',
|
|
||||||
{'connector': connector})
|
|
||||||
|
|
||||||
name = self._volume_name(volume)
|
name = self._volume_name(volume)
|
||||||
params = self._parse_volume_params(volume)
|
params = self._parse_volume_params(volume)
|
||||||
@ -1273,21 +1184,26 @@ class MacroSANISCSIDriver(MacroSANBaseDriver, driver.ISCSIDriver):
|
|||||||
if volume_params['sdas']:
|
if volume_params['sdas']:
|
||||||
self._unmap_itl(self.sdas_client, client_name, wwns, ports, name)
|
self._unmap_itl(self.sdas_client, client_name, wwns, ports, name)
|
||||||
|
|
||||||
|
data = dict()
|
||||||
|
data['ports'] = ports
|
||||||
|
data['client'] = client_name
|
||||||
|
return {'driver_volume_type': 'iSCSI', 'data': data}
|
||||||
|
|
||||||
@synchronized(lock_name)
|
@synchronized(lock_name)
|
||||||
@record_request_id
|
@record_request_id
|
||||||
@_timing
|
@utils.trace
|
||||||
def terminate_connection(self, volume, connector, **kwargs):
|
def terminate_connection(self, volume, connector, **kwargs):
|
||||||
"""Disallow connection from connector."""
|
"""Disallow connection from connector."""
|
||||||
LOG.debug('========== terminate_connection %(connector)s',
|
|
||||||
{'connector': connector})
|
|
||||||
|
|
||||||
name = self._volume_name(volume)
|
name = self._volume_name(volume)
|
||||||
|
conn = None
|
||||||
if not connector:
|
if not connector:
|
||||||
self.force_terminate_connection(name, True)
|
self.force_terminate_connection(name, True)
|
||||||
else:
|
else:
|
||||||
params = self._parse_volume_params(volume)
|
params = self._parse_volume_params(volume)
|
||||||
self._terminate_connection(name, params, connector['host'],
|
conn = self._terminate_connection(name, params, connector['host'],
|
||||||
[connector['initiator']])
|
[connector['initiator']])
|
||||||
|
return conn
|
||||||
|
|
||||||
def _initialize_connection_snapshot(self, snp_name, connector):
|
def _initialize_connection_snapshot(self, snp_name, connector):
|
||||||
return self._initialize_connection(snp_name, None, connector['host'],
|
return self._initialize_connection(snp_name, None, connector['host'],
|
||||||
@ -1307,8 +1223,10 @@ class MacroSANFCDriver(MacroSANBaseDriver, driver.FibreChannelDriver):
|
|||||||
.. code-block:: none
|
.. code-block:: none
|
||||||
|
|
||||||
1.0.0 - Initial driver
|
1.0.0 - Initial driver
|
||||||
|
1.0.1 - Adjust some log level and text prompts; Remove some useless
|
||||||
|
functions; Add Cinder trace decorator. #1837920
|
||||||
"""
|
"""
|
||||||
VERSION = "1.0.0"
|
VERSION = "1.0.1"
|
||||||
|
|
||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
"""Initialize the driver."""
|
"""Initialize the driver."""
|
||||||
@ -1333,11 +1251,6 @@ class MacroSANFCDriver(MacroSANBaseDriver, driver.FibreChannelDriver):
|
|||||||
if port['port_name'] == '':
|
if port['port_name'] == '':
|
||||||
self.sdas_client.create_target(port['port'])
|
self.sdas_client.create_target(port['port'])
|
||||||
|
|
||||||
@property
|
|
||||||
def _self_node_wwns(self):
|
|
||||||
fc = linuxfc.LinuxFibreChannel(utils.get_root_helper())
|
|
||||||
return [self._format_wwn_with_colon(wwn) for wwn in fc.get_fc_wwpns()]
|
|
||||||
|
|
||||||
def _strip_wwn_colon(self, wwn_str):
|
def _strip_wwn_colon(self, wwn_str):
|
||||||
return wwn_str.replace(':', '')
|
return wwn_str.replace(':', '')
|
||||||
|
|
||||||
@ -1479,7 +1392,7 @@ class MacroSANFCDriver(MacroSANBaseDriver, driver.FibreChannelDriver):
|
|||||||
|
|
||||||
has_port_not_mapped, initr_port_map = (
|
has_port_not_mapped, initr_port_map = (
|
||||||
self._map_initr_tgt(self.client, client_name, wwns))
|
self._map_initr_tgt(self.client, client_name, wwns))
|
||||||
LOG.info('====================initr_port_map %(initr_port_map)s',
|
LOG.debug('initr_port_map: %(initr_port_map)s',
|
||||||
{'initr_port_map': initr_port_map})
|
{'initr_port_map': initr_port_map})
|
||||||
|
|
||||||
if vol_params and vol_params['sdas']:
|
if vol_params and vol_params['sdas']:
|
||||||
@ -1488,9 +1401,8 @@ class MacroSANFCDriver(MacroSANBaseDriver, driver.FibreChannelDriver):
|
|||||||
lun_id = self._get_unused_lun_id(self.client, initr_port_map,
|
lun_id = self._get_unused_lun_id(self.client, initr_port_map,
|
||||||
self.sdas_client,
|
self.sdas_client,
|
||||||
sdas_initr_port_map)
|
sdas_initr_port_map)
|
||||||
LOG.info('%(fr)sdas_initr_port_map %(sdas_initr_port_map)s',
|
LOG.debug('sdas_initr_port_map: %(sdas_initr_port_map)s',
|
||||||
{'fr': '=' * 10,
|
{'sdas_initr_port_map': sdas_initr_port_map})
|
||||||
'sdas_initr_port_map': sdas_initr_port_map})
|
|
||||||
self._map_itl(self.sdas_client, sdas_initr_port_map, name, lun_id)
|
self._map_itl(self.sdas_client, sdas_initr_port_map, name, lun_id)
|
||||||
|
|
||||||
lun_id = self._map_itl(self.client, initr_port_map, name, lun_id)
|
lun_id = self._map_itl(self.client, initr_port_map, name, lun_id)
|
||||||
@ -1528,11 +1440,9 @@ class MacroSANFCDriver(MacroSANBaseDriver, driver.FibreChannelDriver):
|
|||||||
|
|
||||||
@synchronized(lock_name)
|
@synchronized(lock_name)
|
||||||
@record_request_id
|
@record_request_id
|
||||||
@_timing
|
@utils.trace
|
||||||
def initialize_connection(self, volume, connector):
|
def initialize_connection(self, volume, connector):
|
||||||
"""Allow connection to connector and return connection info."""
|
"""Allow connection to connector and return connection info."""
|
||||||
LOG.debug('========== initialize_connection connector: %(connector)s',
|
|
||||||
{'connector': connector})
|
|
||||||
|
|
||||||
name = self._volume_name(volume)
|
name = self._volume_name(volume)
|
||||||
params = self._parse_volume_params(volume)
|
params = self._parse_volume_params(volume)
|
||||||
@ -1593,11 +1503,9 @@ class MacroSANFCDriver(MacroSANBaseDriver, driver.FibreChannelDriver):
|
|||||||
|
|
||||||
@synchronized(lock_name)
|
@synchronized(lock_name)
|
||||||
@record_request_id
|
@record_request_id
|
||||||
@_timing
|
@utils.trace
|
||||||
def terminate_connection(self, volume, connector, **kwargs):
|
def terminate_connection(self, volume, connector, **kwargs):
|
||||||
"""Disallow connection from connector."""
|
"""Disallow connection from connector."""
|
||||||
LOG.debug('========== terminate_connection %(connector)s',
|
|
||||||
{'connector': connector})
|
|
||||||
|
|
||||||
name = self._volume_name(volume)
|
name = self._volume_name(volume)
|
||||||
conn = None
|
conn = None
|
||||||
|
@ -3,8 +3,7 @@ MacroSAN Fibre Channel and iSCSI drivers
|
|||||||
==========================================
|
==========================================
|
||||||
|
|
||||||
The ``MacroSANFCDriver`` and ``MacroSANISCSIDriver`` Cinder drivers allow the
|
The ``MacroSANFCDriver`` and ``MacroSANISCSIDriver`` Cinder drivers allow the
|
||||||
MacroSAN Storage arrays to be used for Block Storage in
|
MacroSAN Storage arrays to be used for Block Storage in OpenStack deployments.
|
||||||
OpenStack deployments.
|
|
||||||
|
|
||||||
System requirements
|
System requirements
|
||||||
~~~~~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~~~~~
|
||||||
@ -13,7 +12,10 @@ To use the MacroSAN drivers, the following are required:
|
|||||||
|
|
||||||
- MacroSAN Storage arrays with:
|
- MacroSAN Storage arrays with:
|
||||||
- iSCSI or FC host interfaces
|
- iSCSI or FC host interfaces
|
||||||
- Enable RESTful service on the MacroSAN Storage Appliance.
|
- Enable RESTful service on the MacroSAN Storage Appliance. (The service is
|
||||||
|
automatically turned on in the device. You can check if
|
||||||
|
`python /odsp/scripts/devop/devop.py` is available via `ps -aux|grep python`.
|
||||||
|
)
|
||||||
|
|
||||||
- Network connectivity between the OpenStack host and the array management
|
- Network connectivity between the OpenStack host and the array management
|
||||||
interfaces
|
interfaces
|
||||||
@ -28,22 +30,13 @@ the ``/etc/cinder/cinder.conf`` file:
|
|||||||
|
|
||||||
use_multipath_for_image_xfer = True
|
use_multipath_for_image_xfer = True
|
||||||
|
|
||||||
Add and change the following configuration keys of
|
When creating a instance from image, install the ``multipath`` tool and add the
|
||||||
the ``/etc/multipath.conf`` file:
|
following configuration keys in the ``[libvirt]`` configuration group of
|
||||||
|
the ``/etc/nova/nova.conf`` file:
|
||||||
|
|
||||||
.. code-block:: ini
|
.. code-block:: ini
|
||||||
|
|
||||||
blacklist {
|
iscsi_use_multipath = True
|
||||||
devnode "^sda$"
|
|
||||||
devnode "^(ram|raw|loop|fd|md|dm-|sr|scd|st)[0-9]*"
|
|
||||||
devnode "^hd[a-z]"
|
|
||||||
devnode "^nbd*"
|
|
||||||
}
|
|
||||||
|
|
||||||
Need to set user_friendly_names to no in the multipath.conf file.
|
|
||||||
|
|
||||||
In addition, you need to delete the getuid_callout parameter in
|
|
||||||
the centos7 system.
|
|
||||||
|
|
||||||
Supported operations
|
Supported operations
|
||||||
~~~~~~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~~~~~~
|
||||||
@ -55,13 +48,13 @@ Supported operations
|
|||||||
- Copy a volume to an image.
|
- Copy a volume to an image.
|
||||||
- Clone a volume.
|
- Clone a volume.
|
||||||
- Extend a volume.
|
- Extend a volume.
|
||||||
- Volume Migration (Host assisted).
|
- Volume Migration (Host Assisted).
|
||||||
- Volume Migration (Storage Assisted).
|
- Volume Migration (Storage Assisted).
|
||||||
- Retype a volume.
|
- Retype a volume.
|
||||||
- Manage and unmanage a volume.
|
- Manage and unmanage a volume.
|
||||||
- Manage and unmanage a snapshot.
|
- Manage and unmanage a snapshot.
|
||||||
- Volume Replication
|
- Volume Replication.
|
||||||
- Thin Provisioning
|
- Thin Provisioning.
|
||||||
|
|
||||||
Configuring the array
|
Configuring the array
|
||||||
~~~~~~~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~~~~~~~
|
||||||
@ -109,7 +102,7 @@ Configuring the array
|
|||||||
# Name to give this storage back-end.
|
# Name to give this storage back-end.
|
||||||
volume_backend_name = macrosan
|
volume_backend_name = macrosan
|
||||||
|
|
||||||
#Chose attach/detach volumes in cinder using multipath for volume to image and image to volume transfers.
|
#Choose attach/detach volumes in cinder using multipath for volume to image and image to volume transfers.
|
||||||
use_multipath_for_image_xfer = True
|
use_multipath_for_image_xfer = True
|
||||||
|
|
||||||
# IP address of the Storage if attaching directly.
|
# IP address of the Storage if attaching directly.
|
||||||
@ -121,7 +114,7 @@ Configuring the array
|
|||||||
# Storage user password.
|
# Storage user password.
|
||||||
san_password = openstack
|
san_password = openstack
|
||||||
|
|
||||||
#Chose using thin-lun or thick lun.When set san_thin_provision to True,you must set
|
#Choose using thin-lun or thick lun. When set san_thin_provision to True,you must set
|
||||||
#macrosan_thin_lun_extent_size, macrosan_thin_lun_low_watermark, macrosan_thin_lun_high_watermark.
|
#macrosan_thin_lun_extent_size, macrosan_thin_lun_low_watermark, macrosan_thin_lun_high_watermark.
|
||||||
san_thin_provision = False
|
san_thin_provision = False
|
||||||
|
|
||||||
@ -130,7 +123,7 @@ Configuring the array
|
|||||||
|
|
||||||
#The default ports used for initializing connection.
|
#The default ports used for initializing connection.
|
||||||
#Separate the controller by semicolons (``;``)
|
#Separate the controller by semicolons (``;``)
|
||||||
#Separate the ports by semicolons (``,``)
|
#Separate the ports by comma (``,``)
|
||||||
macrosan_client_default = eth-1:0:0, eth-1:0:1; eth-2:0:0, eth-2:0:1
|
macrosan_client_default = eth-1:0:0, eth-1:0:1; eth-2:0:0, eth-2:0:1
|
||||||
|
|
||||||
#The switch to force detach volume when deleting
|
#The switch to force detach volume when deleting
|
||||||
|
Loading…
Reference in New Issue
Block a user