Merge "HPE 3PAR: Support duplicated FQDN in network"
This commit is contained in:
commit
0dab916125
@ -288,6 +288,7 @@ def list_opts():
|
||||
cinder_volume_driver.nvmet_opts,
|
||||
cinder_volume_driver.scst_opts,
|
||||
cinder_volume_driver.image_opts,
|
||||
cinder_volume_driver.fqdn_opts,
|
||||
cinder_volume_drivers_dell_emc_powermax_common.powermax_opts,
|
||||
cinder_volume_drivers_dell_emc_sc_storagecentercommon.
|
||||
common_opts,
|
||||
|
@ -18,6 +18,7 @@ import ast
|
||||
import copy
|
||||
from unittest import mock
|
||||
|
||||
from oslo_config import cfg
|
||||
from oslo_utils import units
|
||||
from oslo_utils import uuidutils
|
||||
|
||||
@ -28,6 +29,7 @@ from cinder import test
|
||||
from cinder.tests.unit import fake_volume
|
||||
from cinder.tests.unit.volume.drivers.hpe \
|
||||
import fake_hpe_3par_client as hpe3parclient
|
||||
from cinder.volume import configuration as cvol_cfg
|
||||
from cinder.volume.drivers.hpe import hpe_3par_base as hpedriverbase
|
||||
from cinder.volume.drivers.hpe import hpe_3par_common as hpecommon
|
||||
from cinder.volume.drivers.hpe import hpe_3par_fc as hpefcdriver
|
||||
@ -38,6 +40,8 @@ from cinder.volume import volume_utils
|
||||
|
||||
hpeexceptions = hpe3parclient.hpeexceptions
|
||||
|
||||
CONF = cfg.CONF
|
||||
|
||||
|
||||
HPE3PAR_CPG = 'OpenStackCPG'
|
||||
HPE3PAR_CPG2 = 'fakepool'
|
||||
@ -4984,9 +4988,53 @@ class TestHPE3PARDriverBase(HPE3PARBaseDriver):
|
||||
def test__safe_hostname(self):
|
||||
long_hostname = "abc123abc123abc123abc123abc123abc123"
|
||||
fixed_hostname = "abc123abc123abc123abc123abc123a"
|
||||
common = hpecommon.HPE3PARCommon(None)
|
||||
safe_host = common._safe_hostname(long_hostname)
|
||||
self.assertEqual(fixed_hostname, safe_host)
|
||||
mock_client = self.setup_driver()
|
||||
with mock.patch.object(hpecommon.HPE3PARCommon,
|
||||
'_create_client') as mock_create_client:
|
||||
mock_create_client.return_value = mock_client
|
||||
common = self.driver._login()
|
||||
safe_host = common._safe_hostname(long_hostname)
|
||||
self.assertEqual(fixed_hostname, safe_host)
|
||||
|
||||
def test__safe_hostname_unique(self):
|
||||
long_hostname = "abc123abc123abc123abc123abc123abc123"
|
||||
mock_client = self.setup_driver()
|
||||
with mock.patch.object(hpecommon.HPE3PARCommon,
|
||||
'_create_client') as mock_create_client:
|
||||
mock_create_client.return_value = mock_client
|
||||
common = self.driver._login()
|
||||
|
||||
self.addCleanup(CONF.clear_override,
|
||||
'unique_fqdn_network',
|
||||
group=cvol_cfg.SHARED_CONF_GROUP)
|
||||
CONF.set_override('unique_fqdn_network',
|
||||
False,
|
||||
group=cvol_cfg.SHARED_CONF_GROUP)
|
||||
my_connector = self.connector.copy()
|
||||
my_connector['initiator'] = 'iqn.1993-08.org.debian:01:222:12345'
|
||||
ret_name = '54321-222-10-naibed.gro.80-3991'
|
||||
safe_host = common._safe_hostname(long_hostname, my_connector)
|
||||
self.assertEqual(ret_name, safe_host)
|
||||
|
||||
def test__safe_hostname_unique_without_initiator(self):
|
||||
long_hostname = "abc123abc123abc123abc123abc123abc123"
|
||||
fixed_hostname = "abc123abc123abc123abc123abc123a"
|
||||
mock_client = self.setup_driver()
|
||||
with mock.patch.object(hpecommon.HPE3PARCommon,
|
||||
'_create_client') as mock_create_client:
|
||||
mock_create_client.return_value = mock_client
|
||||
common = self.driver._login()
|
||||
|
||||
self.addCleanup(CONF.clear_override,
|
||||
'unique_fqdn_network',
|
||||
group=cvol_cfg.SHARED_CONF_GROUP)
|
||||
CONF.set_override('unique_fqdn_network',
|
||||
False,
|
||||
group=cvol_cfg.SHARED_CONF_GROUP)
|
||||
my_connector = self.connector.copy()
|
||||
del(my_connector['initiator'])
|
||||
safe_host = common._safe_hostname(long_hostname, my_connector)
|
||||
self.assertEqual(fixed_hostname, safe_host)
|
||||
|
||||
@mock.patch('cinder.volume.drivers.hpe.hpe_3par_common.HPE3PARCommon.'
|
||||
'is_volume_group_snap_type')
|
||||
|
@ -18,6 +18,7 @@ import time
|
||||
from unittest import mock
|
||||
|
||||
import ddt
|
||||
from oslo_config import cfg
|
||||
from oslo_utils import units
|
||||
|
||||
from cinder import context
|
||||
@ -34,6 +35,8 @@ from cinder.volume.drivers.kaminario import kaminario_fc
|
||||
from cinder.volume.drivers.kaminario import kaminario_iscsi
|
||||
from cinder.volume import volume_utils
|
||||
|
||||
CONF = cfg.CONF
|
||||
|
||||
CONNECTOR = {'initiator': 'iqn.1993-08.org.debian:01:12aa12aa12aa',
|
||||
'ip': '192.168.2.5', 'platform': 'x86_64', 'host': 'test-k2',
|
||||
'wwpns': ['12341a2a00001234', '12341a2a00001235'],
|
||||
@ -141,7 +144,6 @@ class TestKaminarioCommon(test.TestCase):
|
||||
self.conf = mock.Mock(spec=configuration.Configuration)
|
||||
self.conf.kaminario_dedup_type_name = "dedup"
|
||||
self.conf.volume_dd_blocksize = 2
|
||||
self.conf.unique_fqdn_network = True
|
||||
self.conf.disable_discovery = False
|
||||
|
||||
def _setup_driver(self):
|
||||
@ -524,7 +526,12 @@ class TestKaminarioCommon(test.TestCase):
|
||||
self.assertEqual(CONNECTOR['host'], result)
|
||||
|
||||
def test_get_initiator_host_name_unique(self):
|
||||
self.driver.configuration.unique_fqdn_network = False
|
||||
self.addCleanup(CONF.clear_override,
|
||||
'unique_fqdn_network',
|
||||
group=configuration.SHARED_CONF_GROUP)
|
||||
CONF.set_override('unique_fqdn_network',
|
||||
False,
|
||||
group=configuration.SHARED_CONF_GROUP)
|
||||
result = self.driver.get_initiator_host_name(CONNECTOR)
|
||||
expected = re.sub('[:.]', '_', CONNECTOR['initiator'][::-1][:32])
|
||||
self.assertEqual(expected, result)
|
||||
@ -627,7 +634,12 @@ class TestKaminarioFC(TestKaminarioCommon):
|
||||
def test_get_initiator_host_name_unique(self):
|
||||
connector = CONNECTOR.copy()
|
||||
del connector['initiator']
|
||||
self.driver.configuration.unique_fqdn_network = False
|
||||
self.addCleanup(CONF.clear_override,
|
||||
'unique_fqdn_network',
|
||||
group=configuration.SHARED_CONF_GROUP)
|
||||
CONF.set_override('unique_fqdn_network',
|
||||
False,
|
||||
group=configuration.SHARED_CONF_GROUP)
|
||||
result = self.driver.get_initiator_host_name(connector)
|
||||
expected = re.sub('[:.]', '_', connector['wwnns'][0][::-1][:32])
|
||||
self.assertEqual(expected, result)
|
||||
|
@ -329,6 +329,16 @@ image_opts = [
|
||||
'section or in [backend_defaults] section as a common '
|
||||
'configuration for all backends.'),
|
||||
]
|
||||
fqdn_opts = [
|
||||
cfg.BoolOpt('unique_fqdn_network',
|
||||
default=True,
|
||||
help="Whether or not our private network has unique FQDN on "
|
||||
"each initiator or not. For example networks with QA "
|
||||
"systems usually have multiple servers/VMs with the same "
|
||||
"FQDN. When true this will create host entries on 3PAR "
|
||||
"using the FQDN, when false it will use the reversed "
|
||||
"IQN/WWNN."),
|
||||
]
|
||||
|
||||
|
||||
CONF = cfg.CONF
|
||||
@ -343,6 +353,7 @@ CONF.register_opts(nvmet_opts)
|
||||
CONF.register_opts(scst_opts)
|
||||
CONF.register_opts(backup_opts)
|
||||
CONF.register_opts(image_opts)
|
||||
CONF.register_opts(fqdn_opts, group=configuration.SHARED_CONF_GROUP)
|
||||
CONF.import_opt('backup_use_same_host', 'cinder.backup.api')
|
||||
|
||||
|
||||
@ -404,6 +415,7 @@ class BaseVD(object):
|
||||
self.configuration.append_config_values(scst_opts)
|
||||
self.configuration.append_config_values(backup_opts)
|
||||
self.configuration.append_config_values(image_opts)
|
||||
self.configuration.append_config_values(fqdn_opts)
|
||||
utils.setup_tracing(self.configuration.safe_get('trace_flags'))
|
||||
|
||||
# NOTE(geguileo): Don't allow to start if we are enabling
|
||||
|
@ -295,11 +295,12 @@ class HPE3PARCommon(object):
|
||||
4.0.13 - Fixed detaching issue for volume with type multiattach
|
||||
enabled. bug #1834660
|
||||
4.0.14 - Added Peer Persistence feature
|
||||
4.0.15 - Support duplicated FQDN in network. Bug #1834695
|
||||
|
||||
|
||||
"""
|
||||
|
||||
VERSION = "4.0.14"
|
||||
VERSION = "4.0.15"
|
||||
|
||||
stats = {}
|
||||
|
||||
@ -374,7 +375,7 @@ class HPE3PARCommon(object):
|
||||
'san_ip', 'san_login', 'san_password', 'reserved_percentage',
|
||||
'max_over_subscription_ratio', 'replication_device', 'target_port',
|
||||
'san_ssh_port', 'ssh_conn_timeout', 'san_private_key',
|
||||
'target_ip_address')
|
||||
'target_ip_address', 'unique_fqdn_network')
|
||||
return hpe3par_opts + additional_opts
|
||||
|
||||
def check_flags(self, options, required_flags):
|
||||
@ -1451,19 +1452,27 @@ class HPE3PARCommon(object):
|
||||
raise exception.VolumeBackendAPIException(
|
||||
data=e.get_description())
|
||||
|
||||
def _safe_hostname(self, hostname):
|
||||
def _safe_hostname(self, hostname, connector=None):
|
||||
"""We have to use a safe hostname length for 3PAR host names."""
|
||||
try:
|
||||
index = hostname.index('.')
|
||||
except ValueError:
|
||||
# couldn't find it
|
||||
index = len(hostname)
|
||||
SHARED_CONF_GROUP = 'backend_defaults'
|
||||
shared_backend_conf = CONF._get(SHARED_CONF_GROUP)
|
||||
unique_fqdn_network = shared_backend_conf.unique_fqdn_network
|
||||
if(not unique_fqdn_network and connector.get('initiator')):
|
||||
iqn = connector.get('initiator')
|
||||
iqn = iqn.replace(":", "-")
|
||||
return iqn[::-1][:31]
|
||||
else:
|
||||
try:
|
||||
index = hostname.index('.')
|
||||
except ValueError:
|
||||
# couldn't find it
|
||||
index = len(hostname)
|
||||
|
||||
# we'll just chop this off for now.
|
||||
if index > 31:
|
||||
index = 31
|
||||
# we'll just chop this off for now.
|
||||
if index > 31:
|
||||
index = 31
|
||||
|
||||
return hostname[:index]
|
||||
return hostname[:index]
|
||||
|
||||
def _get_3par_host(self, hostname):
|
||||
return self.client.getHost(hostname)
|
||||
|
@ -339,7 +339,7 @@ class HPE3PARFCDriver(hpebasedriver.HPE3PARDriverBase):
|
||||
# for now, do not remove zones
|
||||
zone_remove = False
|
||||
else:
|
||||
hostname = common._safe_hostname(connector['host'])
|
||||
hostname = common._safe_hostname(connector['host'], connector)
|
||||
common.terminate_connection(volume, hostname,
|
||||
wwn=connector['wwpns'],
|
||||
remote_client=remote_client)
|
||||
@ -528,7 +528,7 @@ class HPE3PARFCDriver(hpebasedriver.HPE3PARDriverBase):
|
||||
"""Creates or modifies existing 3PAR host."""
|
||||
host = None
|
||||
domain = None
|
||||
hostname = common._safe_hostname(connector['host'])
|
||||
hostname = common._safe_hostname(connector['host'], connector)
|
||||
if remote_target:
|
||||
cpg = common._get_cpg_from_cpg_map(
|
||||
remote_target['cpg_map'], src_cpg)
|
||||
|
@ -495,7 +495,7 @@ class HPE3PARISCSIDriver(hpebasedriver.HPE3PARDriverBase):
|
||||
if is_force_detach:
|
||||
common.terminate_connection(volume, None, None)
|
||||
else:
|
||||
hostname = common._safe_hostname(connector['host'])
|
||||
hostname = common._safe_hostname(connector['host'], connector)
|
||||
common.terminate_connection(
|
||||
volume,
|
||||
hostname,
|
||||
@ -601,7 +601,7 @@ class HPE3PARISCSIDriver(hpebasedriver.HPE3PARDriverBase):
|
||||
domain = None
|
||||
username = None
|
||||
password = None
|
||||
hostname = common._safe_hostname(connector['host'])
|
||||
hostname = common._safe_hostname(connector['host'], connector)
|
||||
|
||||
if remote_target:
|
||||
cpg = common._get_cpg_from_cpg_map(
|
||||
|
@ -51,14 +51,6 @@ kaminario_opts = [
|
||||
default=False,
|
||||
help="K2 driver will calculate max_oversubscription_ratio "
|
||||
"on setting this option as True."),
|
||||
cfg.BoolOpt('unique_fqdn_network',
|
||||
default=True,
|
||||
help="Whether or not our private network has unique FQDN on "
|
||||
"each initiator or not. For example networks with QA "
|
||||
"systems usually have multiple servers/VMs with the same "
|
||||
"FQDN. When true this will create host entries on K2 "
|
||||
"using the FQDN, when false it will use the reversed "
|
||||
"IQN/WWNN."),
|
||||
cfg.BoolOpt('disable_discovery',
|
||||
default=False,
|
||||
help="Disabling iSCSI discovery (sendtargets) for multipath "
|
||||
@ -139,7 +131,7 @@ class KaminarioCinderDriver(cinder.volume.driver.ISCSIDriver):
|
||||
def get_driver_options(cls):
|
||||
additional_opts = cls._get_oslo_driver_opts(
|
||||
'san_ip', 'san_login', 'san_password', 'replication_device',
|
||||
'volume_dd_blocksize')
|
||||
'volume_dd_blocksize', 'unique_fqdn_network')
|
||||
return kaminario_opts + additional_opts
|
||||
|
||||
@utils.trace
|
||||
@ -847,7 +839,10 @@ class KaminarioCinderDriver(cinder.volume.driver.ISCSIDriver):
|
||||
"""
|
||||
name = connector.get('initiator',
|
||||
connector.get('wwnns', [''])[0])[::-1]
|
||||
if self.configuration.unique_fqdn_network:
|
||||
SHARED_CONF_GROUP = 'backend_defaults'
|
||||
shared_backend_conf = CONF._get(SHARED_CONF_GROUP)
|
||||
unique_fqdn_network = shared_backend_conf.unique_fqdn_network
|
||||
if unique_fqdn_network:
|
||||
name = connector.get('host', name)
|
||||
return re.sub('[^0-9a-zA-Z-_]', '_', name[:32])
|
||||
|
||||
|
@ -539,3 +539,30 @@ Specify ip address of quorum witness server in ``/etc/cinder/cinder.conf``
|
||||
<other parameters>
|
||||
...
|
||||
|
||||
Support duplicated FQDN in network
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
The 3PAR driver uses the FQDN of the node that is doing the
|
||||
attach as an unique identifier to map the volume.
|
||||
|
||||
The problem is that the FQDN is not always unique, there are
|
||||
environments where the same FQDN can be found in different systems, and
|
||||
in those cases if both try to attach volumes the second system will
|
||||
fail.
|
||||
|
||||
One example of this happening would be on a QA environment where you are
|
||||
creating VMs and they all have names like controller-0.localdomain and
|
||||
compute-0.localdomain.
|
||||
|
||||
To support these kind of environments, the user can specify below flag
|
||||
in backend_defaults section of cinder.conf as follows:
|
||||
|
||||
``unique_fqdn_network = False``
|
||||
|
||||
When this flag is used, then during attach volume to instance,
|
||||
iscsi initiator name is used instead of FQDN.
|
||||
|
||||
If above mentioned flag is not specified in cinder.conf,
|
||||
then its value is considered as True (by default) and
|
||||
FQDN is used (existing behavior).
|
||||
|
||||
|
@ -0,0 +1,7 @@
|
||||
---
|
||||
issues:
|
||||
- |
|
||||
HPE 3PAR driver now supports networks with duplicated FQDNs via configuration
|
||||
option `unique_fqdn_network` so attaching in these networks will work
|
||||
(bug #1834695).
|
||||
|
Loading…
x
Reference in New Issue
Block a user