diff --git a/cinder/tests/unit/test_macrosan_drivers.py b/cinder/tests/unit/test_macrosan_drivers.py index ea82986edf8..9762b809801 100644 --- a/cinder/tests/unit/test_macrosan_drivers.py +++ b/cinder/tests/unit/test_macrosan_drivers.py @@ -34,7 +34,6 @@ test_volume = ( UserDict({'name': 'volume-728ec287-bf30-4d2d-98a8-7f1bed3f59ce', 'volume_name': 'test', 'id': '728ec287-bf30-4d2d-98a8-7f1bed3f59ce', - 'volume_id': '728ec287-bf30-4d2d-98a8-7f1bed3f59ce', 'provider_auth': None, 'project_id': 'project', 'display_name': 'test', @@ -45,7 +44,7 @@ test_volume = ( 'macrosan uuid:0x00b34201-025b0000-46b35ae7-b7deec47'})) 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_migrate_volume = { @@ -58,7 +57,7 @@ test_migrate_volume = { 'project_id': 'project', 'display_name': 'test', 'display_description': 'test', - 'volume_type_id': None, + 'volume_type_id': '36674caf-5314-468a-a8cb-baab4f71fe44', '_name_id': None, 'host': 'controller@macrosan#MacroSAN', 'provider_location': @@ -73,7 +72,7 @@ test_snap = {'name': 'volume-728ec287-bf30-4d2d-98a8-7f1bed3f59ce', 'project_id': 'project', 'display_name': 'test', 'display_description': 'test volume', - 'volume_type_id': None, + 'volume_type_id': '36674caf-5314-468a-a8cb-baab4f71fe44', 'provider_location': 'pointid: 1', 'volume_size': 10, 'volume': test_volume} @@ -106,6 +105,17 @@ expected_iscsi_properties = {'target_discovered': False, '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 = { '21:00:00:24:ff:20:03:ec': [{'port_name': 'FC-Target-1:1:1', 'wwn': '50:0b:34:20:01:00:18:05'}, @@ -188,12 +198,10 @@ class FakeMacroSANISCSIDriver(driver.MacroSANISCSIDriver): def _get_client_name(self, host): return 'devstack' - @utils.synchronized('MacroSAN-Attach', external=True) def _attach_volume(self, context, volume, properties, remote=False): return super(FakeMacroSANISCSIDriver, self)._attach_volume( context, volume, properties, remote) - @utils.synchronized('MacroSAN-Attach', external=True) def _detach_volume(self, context, attach_info, volume, properties, force=False, remote=False, ignore_errors=True): @@ -383,8 +391,7 @@ class MacroSANISCSIDriverTestCase(test.TestCase): def setUp(self): super(MacroSANISCSIDriverTestCase, self).setUp() self.configuration = mock.Mock(spec=conf.Configuration) - self.configuration.san_ip = \ - "172.192.251.1, 172.192.251.2" + self.configuration.san_ip = "172.192.251.1, 172.192.251.2" self.configuration.san_login = "openstack" self.configuration.san_password = "passwd" 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_log_timing = True self.configuration.macrosan_client = \ - ['devstack; decive1; "eth-1:0:0"; "eth-2:0:0"'] - self.configuration.macrosan_client_default = \ - "eth-1:0:0;eth-2:0:0" + ['devstack; device1; "eth-1:0:0"; "eth-2:0:0"'] + self.configuration.macrosan_client_default = "eth-1:0:0;eth-2:0:0" self.driver = FakeMacroSANISCSIDriver(configuration=self.configuration) self.driver.do_setup() @@ -465,12 +471,19 @@ class MacroSANISCSIDriverTestCase(test.TestCase): actual = ret['provider_location'] 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(utils, 'brick_get_connector', return_value=DummyBrickGetConnector()) @mock.patch.object(volutils, 'copy_volume', 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_copy_volume, mock_os_path): @@ -514,7 +527,9 @@ class MacroSANISCSIDriverTestCase(test.TestCase): @mock.patch.object(qos_specs, 'get_qos_specs', return_value={'specs': {'qos-strategy': 'QoS-1'}}) 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): expected = ["RAID-1"] @@ -564,12 +579,19 @@ class MacroSANISCSIDriverTestCase(test.TestCase): self.driver.create_volume_from_snapshot, 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(utils, 'brick_get_connector', return_value=DummyBrickGetConnector()) @mock.patch.object(volutils, 'copy_volume', 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_copy_volume, mock_os_path): @@ -630,7 +652,7 @@ class MacroSANFCDriverTestCase(test.TestCase): self.configuration.macrosan_fc_keep_mapped_ports = True self.configuration.macrosan_host_name = 'devstack' 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 = \ "eth-1:0:0;eth-2:0:0" self.driver = FakeMacroSANFCDriver(configuration=self.configuration) @@ -647,19 +669,40 @@ class MacroSANFCDriverTestCase(test.TestCase): test_connector['wwpns']) 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) self.assertEqual(expected_fctgtexist_properties, ret['data']) - def test_terminate_connection(self): - self.driver.terminate_connection(test_volume, test_connector) + @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(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(utils, 'brick_get_connector', return_value=DummyBrickGetConnector()) @mock.patch.object(volutils, 'copy_volume', 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_copy_volume, mock_os_path): @@ -667,12 +710,20 @@ class MacroSANFCDriverTestCase(test.TestCase): actual = ret['provider_location'] 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(utils, 'brick_get_connector', return_value=DummyBrickGetConnector()) @mock.patch.object(volutils, 'copy_volume', 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_copy_volume, mock_os_path): @@ -681,12 +732,20 @@ class MacroSANFCDriverTestCase(test.TestCase): actual = ret['provider_location'] 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(utils, 'brick_get_connector', return_value=DummyBrickGetConnector()) @mock.patch.object(volutils, 'copy_volume', 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_copy_volume, mock_os_path): @@ -695,12 +754,19 @@ class MacroSANFCDriverTestCase(test.TestCase): self.driver.create_volume_from_snapshot, 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(utils, 'brick_get_connector', return_value=DummyBrickGetConnector()) @mock.patch.object(volutils, 'copy_volume', 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_copy_volume, mock_os_path): @@ -709,13 +775,25 @@ class MacroSANFCDriverTestCase(test.TestCase): self.driver.create_cloned_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.assertRaises(exception.VolumeBackendAPIException, self.driver.initialize_connection, 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.assertRaises(exception.VolumeBackendAPIException, self.driver.terminate_connection, diff --git a/cinder/volume/drivers/macrosan/config.py b/cinder/volume/drivers/macrosan/config.py index 70029b5f70e..b90eda429a3 100644 --- a/cinder/volume/drivers/macrosan/config.py +++ b/cinder/volume/drivers/macrosan/config.py @@ -20,33 +20,25 @@ from oslo_config import cfg macrosan_opts = [ # sdas login_info cfg.ListOpt('macrosan_sdas_ipaddrs', - default=None, help="MacroSAN sdas devices' ip addresses"), cfg.StrOpt('macrosan_sdas_username', - default=None, - help=""), + help="MacroSAN sdas devices' username"), cfg.StrOpt('macrosan_sdas_password', - default=None, - help="", - secret=True), + secret=True, + help="MacroSAN sdas devices' password"), # replication login_info cfg.ListOpt('macrosan_replication_ipaddrs', - default=None, help="MacroSAN replication devices' ip addresses"), cfg.StrOpt('macrosan_replication_username', - default=None, - help=""), + help="MacroSAN replication devices' username"), cfg.StrOpt('macrosan_replication_password', - default=None, - help="", - secret=True), + secret=True, + help="MacroSAN replication devices' password"), cfg.ListOpt('macrosan_replication_destination_ports', - default=None, sample_default="eth-1:0/eth-1:1, eth-2:0/eth-2:1", help="Slave device"), # device_features cfg.StrOpt('macrosan_pool', quotes=True, - default=None, help='Pool to use for volume creation'), cfg.IntOpt('macrosan_thin_lun_extent_size', default=8, @@ -80,21 +72,20 @@ macrosan_opts = [ "item associated with the port is maintained."), # iscsi connection cfg.ListOpt('macrosan_client', - default=None, help="""Macrosan iscsi_clients list. You can configure multiple clients. You can configure it in this format: (host; client_name; sp1_iscsi_port; sp2_iscsi_port), (host; client_name; sp1_iscsi_port; sp2_iscsi_port) 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: - (controller1; decive1; eth-1:0; eth-2:0), - (controller2; decive2; eth-1:0/eth-1:1; eth-2:0/eth-2:1), + (controller1; device1; eth-1:0; eth-2:0), + (controller2; device2; eth-1:0/eth-1:1; eth-2:0/eth-2:1), """), cfg.StrOpt('macrosan_client_default', - default=None, - help="This is the default connection information for iscsi. " + help="This is the default connection ports' name for iscsi. " "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") ] diff --git a/cinder/volume/drivers/macrosan/devop_client.py b/cinder/volume/drivers/macrosan/devop_client.py index 985bd3ecc13..7158c248f5d 100644 --- a/cinder/volume/drivers/macrosan/devop_client.py +++ b/cinder/volume/drivers/macrosan/devop_client.py @@ -109,7 +109,7 @@ class Client(object): 'attr': 'existence', '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): """Whether the snapshot point exists.""" diff --git a/cinder/volume/drivers/macrosan/driver.py b/cinder/volume/drivers/macrosan/driver.py index c722f5418f1..b2eb8175b94 100644 --- a/cinder/volume/drivers/macrosan/driver.py +++ b/cinder/volume/drivers/macrosan/driver.py @@ -14,17 +14,13 @@ # under the License. """Volume Drivers for MacroSAN SAN.""" -import base64 from contextlib import contextmanager import math import re -import six import socket import time import uuid -from os_brick.initiator import connector as cn -from os_brick.initiator import linuxfc from oslo_config import cfg from oslo_log import log as logging 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.zonemanager import utils as fczm_utils -version = '1.0.0' +version = '1.0.1' lock_name = 'MacroSAN' LOG = logging.getLogger(__name__) @@ -63,22 +59,6 @@ def ignored(*exceptions): 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(*vargs, **kv): ctx = context.context.get_current() @@ -93,14 +73,6 @@ def replication_synced(params): 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): """Base driver for MacroSAN SAN.""" @@ -182,15 +154,6 @@ class MacroSANBaseDriver(driver.VolumeDriver): 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): if int(size_in_g) == 0: return 1 @@ -254,7 +217,7 @@ class MacroSANBaseDriver(driver.VolumeDriver): self.replica_login_info)) self.device_uuid = self.client.get_device_uuid() self._do_setup() - LOG.info('MacroSAN Cinder Driver setup complete.') + LOG.debug('MacroSAN Cinder Driver setup complete.') def _do_setup(self): pass @@ -448,14 +411,9 @@ class MacroSANBaseDriver(driver.VolumeDriver): @synchronized(lock_name) @record_request_id - @_timing + @utils.trace def create_volume(self, 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'] size = self._size_str_to_int(volume['size']) params = self._parse_volume_params(volume) @@ -508,22 +466,21 @@ class MacroSANBaseDriver(driver.VolumeDriver): @synchronized(lock_name) @record_request_id - @_timing + @utils.trace def delete_volume(self, volume): """Delete a volume.""" - LOG.debug('========== delete volume, id: %s.', volume['id']) name = self._volume_name(volume) params = self._parse_volume_params(volume) 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): return super(MacroSANBaseDriver, self)._attach_volume(context, volume, properties, remote) - @utils.synchronized('MacroSAN-Attach', external=True) + @utils.synchronized('MacroSAN-Attach-Detach', external=True) def _detach_volume(self, context, attach_info, volume, properties, force=False, remote=False, ignore_errors=True): @@ -568,14 +525,10 @@ class MacroSANBaseDriver(driver.VolumeDriver): @synchronized(lock_name) @record_request_id - @_timing + @utils.trace def create_snapshot(self, snapshot): """Create a snapshot.""" 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']) volume_name = self._volume_name(volume) @@ -601,7 +554,7 @@ class MacroSANBaseDriver(driver.VolumeDriver): @synchronized(lock_name) @record_request_id - @_timing + @utils.trace def delete_snapshot(self, snapshot): """Delete a snapshot.""" volume = snapshot['volume'] @@ -612,10 +565,7 @@ class MacroSANBaseDriver(driver.VolumeDriver): m = re.findall(r'pointid: (\d+)', provider) if m is None: 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']) volume_name = self._volume_name(volume) self._delete_snapshot(snapshot_name, volume_name, m[0]) @@ -626,35 +576,6 @@ class MacroSANBaseDriver(driver.VolumeDriver): def _terminate_connection(self, name, host, wwns): 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, vol_params, snp_name, pointid, snp_vol_name, snp_vol_size): @@ -685,10 +606,9 @@ class MacroSANBaseDriver(driver.VolumeDriver): @synchronized(lock_name) @record_request_id - @_timing + @utils.trace def create_volume_from_snapshot(self, volume, snapshot): """Create a volume from a snapshot.""" - LOG.debug('========== create volume from snapshot.') snapshot_volume = snapshot['volume'] provider = snapshot['provider_location'] m = re.findall(r'pointid: (\d+)', provider) @@ -727,10 +647,9 @@ class MacroSANBaseDriver(driver.VolumeDriver): self._delete_snapshot(snp_name, src_vol_name, pointid) @record_request_id - @_timing + @utils.trace def create_cloned_volume(self, volume, src_vref): """Create a clone of the specified volume.""" - LOG.debug('========== create cloned volume.') vol_name = volume['id'] src_vol_name = self._volume_name(src_vref) snapshotid =\ @@ -768,13 +687,9 @@ class MacroSANBaseDriver(driver.VolumeDriver): @synchronized(lock_name) @record_request_id - @_timing + @utils.trace def extend_volume(self, volume, new_size): """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) moresize = self._size_str_to_int(new_size - int(volume['size'])) params = self._parse_volume_params(volume) @@ -839,14 +754,12 @@ class MacroSANBaseDriver(driver.VolumeDriver): self._stats = data @record_request_id + @utils.trace def update_migrated_volume(self, ctxt, volume, new_volume, original_volume_status=None): """Return model update for migrated volume.""" original_name = self._volume_name(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): self.client.backup_lun_name_to_rename_file(cur_name, original_name) @@ -866,7 +779,7 @@ class MacroSANBaseDriver(driver.VolumeDriver): @synchronized(lock_name) @record_request_id - @_timing + @utils.trace def initialize_connection_snapshot(self, snapshot, connector, **kwargs): volume = snapshot['volume'] provider = snapshot['provider_location'] @@ -905,13 +818,13 @@ class MacroSANBaseDriver(driver.VolumeDriver): @synchronized(lock_name) @record_request_id - @_timing + @utils.trace def manage_existing(self, volume, external_ref): vol_params = self._parse_volume_params(volume) self._check_volume_params(vol_params) if vol_params['qos-strategy']: raise exception.VolumeBackendAPIException( - data=_('Not support to import qos-strategy')) + data=_('Import qos-strategy not supported')) pool = volume_utils.extract_host(volume.host, 'pool') name, info, params = self._get_existing_lun_info(external_ref) @@ -995,7 +908,7 @@ class MacroSANBaseDriver(driver.VolumeDriver): @synchronized(lock_name) @record_request_id - @_timing + @utils.trace def manage_existing_snapshot(self, snapshot, existing_ref): volume = snapshot['volume'] src_name = self._get_existing_snapname(existing_ref).lstrip('_') @@ -1042,7 +955,7 @@ class MacroSANBaseDriver(driver.VolumeDriver): @synchronized(lock_name) @record_request_id - @_timing + @utils.trace def migrate_volume(self, ctxt, volume, host): if not self.migration_valid(volume, host): return False, None @@ -1054,8 +967,11 @@ class MacroSANBaseDriver(driver.VolumeDriver): owner = self.client.get_lun_sp(src_name) pool = host['capabilities'].get('pool_name', self.pool) - LOG.info('host: %(host)s, backend: %(volume_backend_name)s', - {'host': host, + LOG.info('Migrating volume: %(volume), ' + 'host: %(host)s, ' + 'backend: %(volume_backend_name)s', + {'volume': src_name, + 'host': host, 'volume_backend_name': self.volume_backend_name}) self._create_volume(name, size, params, owner, pool) @@ -1106,8 +1022,10 @@ class MacroSANISCSIDriver(MacroSANBaseDriver, driver.ISCSIDriver): .. code-block:: none 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): """Initialize the driver.""" @@ -1198,11 +1116,6 @@ class MacroSANISCSIDriver(MacroSANBaseDriver, driver.ISCSIDriver): 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): client_name = self._get_client_name(host) wwn = wwns[0] @@ -1242,11 +1155,9 @@ class MacroSANISCSIDriver(MacroSANBaseDriver, driver.ISCSIDriver): @synchronized(lock_name) @record_request_id - @_timing + @utils.trace def initialize_connection(self, volume, connector): """Allow connection to connector and return connection info.""" - LOG.debug('========== initialize_connection connector: %(connector)s', - {'connector': connector}) name = self._volume_name(volume) params = self._parse_volume_params(volume) @@ -1273,21 +1184,26 @@ class MacroSANISCSIDriver(MacroSANBaseDriver, driver.ISCSIDriver): if volume_params['sdas']: 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) @record_request_id - @_timing + @utils.trace def terminate_connection(self, volume, connector, **kwargs): """Disallow connection from connector.""" - LOG.debug('========== terminate_connection %(connector)s', - {'connector': connector}) name = self._volume_name(volume) + conn = None if not connector: self.force_terminate_connection(name, True) else: params = self._parse_volume_params(volume) - self._terminate_connection(name, params, connector['host'], - [connector['initiator']]) + conn = self._terminate_connection(name, params, connector['host'], + [connector['initiator']]) + return conn def _initialize_connection_snapshot(self, snp_name, connector): return self._initialize_connection(snp_name, None, connector['host'], @@ -1307,8 +1223,10 @@ class MacroSANFCDriver(MacroSANBaseDriver, driver.FibreChannelDriver): .. code-block:: none 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): """Initialize the driver.""" @@ -1333,11 +1251,6 @@ class MacroSANFCDriver(MacroSANBaseDriver, driver.FibreChannelDriver): if port['port_name'] == '': 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): return wwn_str.replace(':', '') @@ -1479,8 +1392,8 @@ class MacroSANFCDriver(MacroSANBaseDriver, driver.FibreChannelDriver): has_port_not_mapped, initr_port_map = ( self._map_initr_tgt(self.client, client_name, wwns)) - LOG.info('====================initr_port_map %(initr_port_map)s', - {'initr_port_map': initr_port_map}) + LOG.debug('initr_port_map: %(initr_port_map)s', + {'initr_port_map': initr_port_map}) if vol_params and vol_params['sdas']: sdas_has_port_not_mapped, sdas_initr_port_map = ( @@ -1488,9 +1401,8 @@ class MacroSANFCDriver(MacroSANBaseDriver, driver.FibreChannelDriver): lun_id = self._get_unused_lun_id(self.client, initr_port_map, self.sdas_client, sdas_initr_port_map) - LOG.info('%(fr)sdas_initr_port_map %(sdas_initr_port_map)s', - {'fr': '=' * 10, - 'sdas_initr_port_map': sdas_initr_port_map}) + LOG.debug('sdas_initr_port_map: %(sdas_initr_port_map)s', + {'sdas_initr_port_map': sdas_initr_port_map}) 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) @@ -1528,11 +1440,9 @@ class MacroSANFCDriver(MacroSANBaseDriver, driver.FibreChannelDriver): @synchronized(lock_name) @record_request_id - @_timing + @utils.trace def initialize_connection(self, volume, connector): """Allow connection to connector and return connection info.""" - LOG.debug('========== initialize_connection connector: %(connector)s', - {'connector': connector}) name = self._volume_name(volume) params = self._parse_volume_params(volume) @@ -1593,11 +1503,9 @@ class MacroSANFCDriver(MacroSANBaseDriver, driver.FibreChannelDriver): @synchronized(lock_name) @record_request_id - @_timing + @utils.trace def terminate_connection(self, volume, connector, **kwargs): """Disallow connection from connector.""" - LOG.debug('========== terminate_connection %(connector)s', - {'connector': connector}) name = self._volume_name(volume) conn = None diff --git a/doc/source/configuration/block-storage/drivers/MacroSAN-storage-driver.rst b/doc/source/configuration/block-storage/drivers/MacroSAN-storage-driver.rst index 68bd80b4bbf..9f8f3762b9f 100644 --- a/doc/source/configuration/block-storage/drivers/MacroSAN-storage-driver.rst +++ b/doc/source/configuration/block-storage/drivers/MacroSAN-storage-driver.rst @@ -3,8 +3,7 @@ MacroSAN Fibre Channel and iSCSI drivers ========================================== The ``MacroSANFCDriver`` and ``MacroSANISCSIDriver`` Cinder drivers allow the -MacroSAN Storage arrays to be used for Block Storage in -OpenStack deployments. +MacroSAN Storage arrays to be used for Block Storage in OpenStack deployments. System requirements ~~~~~~~~~~~~~~~~~~~ @@ -13,7 +12,10 @@ To use the MacroSAN drivers, the following are required: - MacroSAN Storage arrays with: - 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 interfaces @@ -28,22 +30,13 @@ the ``/etc/cinder/cinder.conf`` file: use_multipath_for_image_xfer = True -Add and change the following configuration keys of -the ``/etc/multipath.conf`` file: +When creating a instance from image, install the ``multipath`` tool and add the +following configuration keys in the ``[libvirt]`` configuration group of +the ``/etc/nova/nova.conf`` file: .. code-block:: ini - blacklist { - 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. + iscsi_use_multipath = True Supported operations ~~~~~~~~~~~~~~~~~~~~ @@ -55,13 +48,13 @@ Supported operations - Copy a volume to an image. - Clone a volume. - Extend a volume. -- Volume Migration (Host assisted). +- Volume Migration (Host Assisted). - Volume Migration (Storage Assisted). - Retype a volume. - Manage and unmanage a volume. - Manage and unmanage a snapshot. -- Volume Replication -- Thin Provisioning +- Volume Replication. +- Thin Provisioning. Configuring the array ~~~~~~~~~~~~~~~~~~~~~ @@ -109,7 +102,7 @@ Configuring the array # Name to give this storage back-end. 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 # IP address of the Storage if attaching directly. @@ -121,7 +114,7 @@ Configuring the array # Storage user password. 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. san_thin_provision = False @@ -130,7 +123,7 @@ Configuring the array #The default ports used for initializing connection. #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 #The switch to force detach volume when deleting @@ -158,7 +151,7 @@ Configuring the array macrosan_sdas_username = openstack macrosan_sdas_password = openstack - #The setting of Replication Storage.When you set ip, you must set + #The setting of Replication Storage. When you set ip, you must set #the macrosan_replication_destination_ports parameter. macrosan_replication_ipaddrs = 172.17.251.142, 172.17.251.143 macrosan_replication_username = openstack @@ -169,7 +162,7 @@ Configuring the array #Separate the ports by semicolons (``/``) macrosan_replication_destination_ports = eth-1:0:0/eth-1:0:1, eth-2:0:0/eth-2:0:1 - #Macrosan iscsi_clients list.You can configure multiple clients.Separate the ports by semicolons (``/``) + #Macrosan iscsi_clients list. You can configure multiple clients. Separate the ports by semicolons (``/``) macrosan_client = (devstack; controller1name; eth-1:0:0/eth-1:0:1; eth-2:0:0/eth-2:0:1), (dev; controller2name; eth-1:0:0/eth-1:0:1; eth-2:0:0/eth-2:0:1) [cinder-iscsi-b] @@ -342,7 +335,7 @@ of the MacroSAN volume driver. - iSCSI * - macrosan_client_default - ``None`` - - This is the default connection information for iscsi.This default configuration is used when no host related information is obtained. + - This is the default connection information for iscsi. This default configuration is used when no host related information is obtained. - iSCSI * - zoning_mode - ``True`` @@ -379,7 +372,7 @@ of the MacroSAN volume driver. - All * - macrosan_replication_ipaddrs - ``-`` - - The ip of replication Storage.When you set ip, you must set + - The ip of replication Storage. When you set ip, you must set the macrosan_replication_destination_ports parameter. - All * - macrosan_replication_username @@ -408,7 +401,7 @@ of the MacroSAN volume driver. - All * - macrosan_client - ``True`` - - Macrosan iscsi_clients list.You can configure multiple clients. + - Macrosan iscsi_clients list. You can configure multiple clients. You can configure it in this format: (hostname; client_name; sp1_iscsi_port; sp2_iscsi_port), E.g: