Merge "Address review comments for MacroSAN driver"

This commit is contained in:
Zuul 2019-09-08 20:21:02 +00:00 committed by Gerrit Code Review
commit a7f1301914
5 changed files with 181 additions and 211 deletions

View File

@ -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,

View File

@ -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,21 +72,20 @@ 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:
(host; client_name; sp1_iscsi_port; sp2_iscsi_port), (host; client_name; sp1_iscsi_port; sp2_iscsi_port),
(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: 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")
] ]

View File

@ -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."""

View File

@ -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,8 +1392,8 @@ 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']:
sdas_has_port_not_mapped, sdas_initr_port_map = ( 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, 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

View File

@ -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
@ -158,7 +151,7 @@ Configuring the array
macrosan_sdas_username = openstack macrosan_sdas_username = openstack
macrosan_sdas_password = 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. #the macrosan_replication_destination_ports parameter.
macrosan_replication_ipaddrs = 172.17.251.142, 172.17.251.143 macrosan_replication_ipaddrs = 172.17.251.142, 172.17.251.143
macrosan_replication_username = openstack macrosan_replication_username = openstack
@ -169,7 +162,7 @@ Configuring the array
#Separate the ports by semicolons (``/``) #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_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) 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] [cinder-iscsi-b]
@ -342,7 +335,7 @@ of the MacroSAN volume driver.
- iSCSI - iSCSI
* - macrosan_client_default * - macrosan_client_default
- ``None`` - ``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 - iSCSI
* - zoning_mode * - zoning_mode
- ``True`` - ``True``
@ -379,7 +372,7 @@ of the MacroSAN volume driver.
- All - All
* - macrosan_replication_ipaddrs * - 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. the macrosan_replication_destination_ports parameter.
- All - All
* - macrosan_replication_username * - macrosan_replication_username
@ -408,7 +401,7 @@ of the MacroSAN volume driver.
- All - All
* - macrosan_client * - macrosan_client
- ``True`` - ``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: You can configure it in this format:
(hostname; client_name; sp1_iscsi_port; sp2_iscsi_port), (hostname; client_name; sp1_iscsi_port; sp2_iscsi_port),
E.g: E.g: