Storwize: modify hyperswap host_site configuration

The new configuration storwize_preferred_host_site was introduced in
volume type for hyperswap feature on Queens release. Actually, the
host_site is related to host rather than volume.

This patch removes the parameter storwzie_preferred_host_site from
volume type configuration and updates it from StrOpt to DictOpt in cinder
back-end configuration.

Closes-Bug:  1742866

Change-Id: Ie1df4cc45c2d1f72f33beea7ddc5bb3797a34728
This commit is contained in:
yixuanzhang 2018-01-12 15:33:25 +08:00
parent 831665f59a
commit b13a8f810b
6 changed files with 178 additions and 174 deletions

View File

@ -3038,6 +3038,7 @@ class StorwizeSVCISCSIDriverTestCase(test.TestCase):
if self.USESIM:
self.iscsi_driver = StorwizeSVCISCSIFakeDriver(
configuration=conf.Configuration([], conf.SHARED_CONF_GROUP))
self.host_site = {'site1': 'iqn.1993-08.org.debian:01:eac5ccc1aaa'}
self._def_flags = {'san_ip': 'hostname',
'san_login': 'user',
'san_password': 'pass',
@ -3045,7 +3046,8 @@ class StorwizeSVCISCSIDriverTestCase(test.TestCase):
'storwize_svc_flashcopy_timeout': 20,
'storwize_svc_flashcopy_rate': 49,
'storwize_svc_multipath_enabled': False,
'storwize_svc_allow_tenant_qos': True}
'storwize_svc_allow_tenant_qos': True,
'storwize_preferred_host_site': self.host_site}
wwpns = [
six.text_type(random.randint(0, 9999999999999999)).zfill(16),
six.text_type(random.randint(0, 9999999999999999)).zfill(16)]
@ -3210,73 +3212,37 @@ class StorwizeSVCISCSIDriverTestCase(test.TestCase):
'wwpns': ['ff00000000000000', 'ff00000000000001'],
'initiator': 'iqn.1993-08.org.debian:01:eac5ccc1aaa'}
# host_site is None
volume0_iSCSI = self._create_volume()
vol_type_iSCSI_0 = volume_types.create(self.ctxt, 'iSCSI0', None)
volume0_iSCSI['volume_type_id'] = vol_type_iSCSI_0['id']
self.iscsi_driver.initialize_connection(volume0_iSCSI, connector)
# host_site is site1
volume_iSCSI_1 = self._create_volume()
volume_iSCSI = self._create_volume()
extra_spec = {'drivers:volume_topology': 'hyperswap',
'peer_pool': 'openstack1',
'host_site': 'site1'}
'peer_pool': 'openstack1'}
vol_type_iSCSI = volume_types.create(self.ctxt, 'iSCSI', extra_spec)
volume_iSCSI['volume_type_id'] = vol_type_iSCSI['id']
volume_iSCSI_2 = self._create_volume()
volume_iSCSI_2['volume_type_id'] = vol_type_iSCSI['id']
self.iscsi_driver.initialize_connection(volume_iSCSI, connector)
# host_site is site2, different with site1.
volume1_iSCSI = self._create_volume()
extra_spec_1 = {'drivers:volume_topology': 'hyperswap',
'peer_pool': 'openstack1',
'host_site': 'site2'}
vol_type_iSCSI_1 = volume_types.create(self.ctxt, 'iSCSI1',
extra_spec_1)
volume1_iSCSI['volume_type_id'] = vol_type_iSCSI_1['id']
self.assertRaises(exception.VolumeDriverException,
self.iscsi_driver.initialize_connection,
volume1_iSCSI,
connector)
# host_site is None.
volume2_iSCSI = self._create_volume()
vol_type_iSCSI_2 = volume_types.create(self.ctxt, 'iSCSI2', None)
volume2_iSCSI['volume_type_id'] = vol_type_iSCSI_2['id']
self.iscsi_driver.initialize_connection(volume2_iSCSI, connector)
# create new host with host_site, the host site should be update
connector2 = {'host': 'STORWIZE-SVC-HOST',
'wwnns': ['30000090fa17311e', '30000090fa17311f'],
'wwpns': ['ffff000000000000', 'ffff000000000001'],
'initiator': 'iqn.1993-08.org.debian:01:eac5ccc1bbb'}
# attach hyperswap volume without host_site
volume3_iSCSI = self._create_volume()
extra_spec_3 = {'drivers:volume_topology': 'hyperswap',
'peer_pool': 'openstack1'}
vol_type_iSCSI_3 = volume_types.create(self.ctxt, 'iSCSI3',
extra_spec_3)
volume3_iSCSI['volume_type_id'] = vol_type_iSCSI_3['id']
with mock.patch.object(storwize_svc_common.StorwizeHelpers,
'is_volume_hyperswap') as hyperswap:
hyperswap.return_value = True
self.assertRaises(exception.VolumeDriverException,
self.iscsi_driver.initialize_connection,
volume3_iSCSI,
connector2)
'is_volume_hyperswap') as is_volume_hyperswap:
is_volume_hyperswap.return_value = True
self.iscsi_driver.initialize_connection(volume_iSCSI, connector)
host_name = self.iscsi_driver._helpers.get_host_from_connector(
connector, iscsi=True)
host_info = self.iscsi_driver._helpers.ssh.lshost(host=host_name)
self.assertEqual('site1', host_info[0]['site_name'])
self.iscsi_driver.terminate_connection(volume_iSCSI, connector)
self.iscsi_driver.initialize_connection(volume_iSCSI_1, connector)
with mock.patch.object(storwize_svc_common.StorwizeHelpers,
'is_volume_hyperswap') as is_volume_hyperswap:
is_volume_hyperswap.return_value = True
self.iscsi_driver.initialize_connection(volume_iSCSI, connector)
# attach hyperswap volume with host_site
volume4_iSCSI = self._create_volume()
extra_spec_4 = {'drivers:volume_topology': 'hyperswap',
'peer_pool': 'openstack1',
'host_site': 'site2'}
vol_type_iSCSI_4 = volume_types.create(self.ctxt, 'iSCSI4',
extra_spec_4)
volume4_iSCSI['volume_type_id'] = vol_type_iSCSI_4['id']
self.iscsi_driver.initialize_connection(volume4_iSCSI, connector2)
host_name = self.iscsi_driver._helpers.get_host_from_connector(
connector2, iscsi=True)
host_info = self.iscsi_driver._helpers.ssh.lshost(host=host_name)
self.assertEqual('site2', host_info[0]['site_name'])
host_site = {'site1': 'iqn.1993-08.org.debian:01:eac5ccc1aaa',
'site2': 'iqn.1993-08.org.debian:01:eac5ccc1aaa'}
self._set_flag('storwize_preferred_host_site', host_site)
self.assertRaises(exception.InvalidConfigurationValue,
self.iscsi_driver.initialize_connection,
volume_iSCSI_2,
connector)
@mock.patch.object(storwize_svc_iscsi.StorwizeSVCISCSIDriver,
'_do_terminate_connection')
@ -4040,73 +4006,60 @@ class StorwizeSVCFcDriverTestCase(test.TestCase):
def test_storwize_initialize_fc_connection_with_host_site(self):
connector = {'host': 'storwize-svc-host',
'wwnns': ['20000090fa17311e', '20000090fa17311f'],
'wwpns': ['ff00000000000000', 'ff00000000000001'],
'wwpns': ['ffff000000000000', 'ffff000000000001'],
'initiator': 'iqn.1993-08.org.debian:01:eac5ccc1aaa'}
# host_site is None
volume0_fc = self._create_volume()
vol_type_fc_0 = volume_types.create(self.ctxt, 'FC0', None)
volume0_fc['volume_type_id'] = vol_type_fc_0['id']
self.fc_driver.initialize_connection(volume0_fc, connector)
# host_site is site1
# attach hyperswap volume without host_site
volume_fc = self._create_volume()
extra_spec = {'drivers:volume_topology': 'hyperswap',
'peer_pool': 'openstack1',
'host_site': 'site1'}
'peer_pool': 'openstack1'}
vol_type_fc = volume_types.create(self.ctxt, 'FC', extra_spec)
volume_fc['volume_type_id'] = vol_type_fc['id']
self.fc_driver.initialize_connection(volume_fc, connector)
host_name = self.fc_driver._helpers.get_host_from_connector(
connector, iscsi=True)
host_info = self.fc_driver._helpers.ssh.lshost(host=host_name)
self.assertEqual('site1', host_info[0]['site_name'])
# host_site is site2, different with site1.
volume1_fc = self._create_volume()
extra_spec_1 = {'drivers:volume_topology': 'hyperswap',
'peer_pool': 'openstack1',
'host_site': 'site2'}
vol_type_fc_1 = volume_types.create(self.ctxt, 'FC1', extra_spec_1)
volume1_fc['volume_type_id'] = vol_type_fc_1['id']
self.assertRaises(exception.VolumeDriverException,
self.fc_driver.initialize_connection,
volume1_fc,
connector)
# host_site is None.
volume2_fc = self._create_volume()
vol_type_fc_2 = volume_types.create(self.ctxt, 'FC2', None)
volume2_fc['volume_type_id'] = vol_type_fc_2['id']
self.fc_driver.initialize_connection(volume2_fc, connector)
# create new host with host_site
connector2 = {'host': 'STORWIZE-SVC-HOST',
'wwnns': ['30000090fa17311e', '30000090fa17311f'],
'wwpns': ['ffff000000000000', 'ffff000000000001'],
'initiator': 'iqn.1993-08.org.debian:01:eac5ccc1bbb'}
# attach hyperswap volume without host_site
volume3_fc = self._create_volume()
extra_spec_3 = {'drivers:volume_topology': 'hyperswap',
'peer_pool': 'openstack1'}
vol_type_fc_3 = volume_types.create(self.ctxt, 'FC3', extra_spec_3)
volume3_fc['volume_type_id'] = vol_type_fc_3['id']
volume_fc_2 = self._create_volume()
volume_fc_2['volume_type_id'] = vol_type_fc['id']
with mock.patch.object(storwize_svc_common.StorwizeHelpers,
'is_volume_hyperswap') as is_volume_hyperswap:
is_volume_hyperswap.return_value = True
self.assertRaises(exception.VolumeDriverException,
self.fc_driver.initialize_connection,
volume3_fc,
connector2)
volume_fc,
connector)
# the wwpns of 1 host config to 2 different sites
host_site = {'site1': 'ffff000000000000',
'site2': 'ffff000000000001'}
self.fc_driver.configuration.set_override(
'storwize_preferred_host_site', host_site)
self.assertRaises(exception.InvalidConfigurationValue,
self.fc_driver.initialize_connection,
volume_fc,
connector)
# All the wwpns of this host are not configured.
host_site_2 = {'site1': 'ff00000000000000',
'site1': 'ff00000000000001'}
self.fc_driver.configuration.set_override(
'storwize_preferred_host_site', host_site_2)
self.assertRaises(exception.VolumeDriverException,
self.fc_driver.initialize_connection,
volume_fc,
connector)
# attach hyperswap volume with host_site
volume4_fc = self._create_volume()
extra_spec_4 = {'drivers:volume_topology': 'hyperswap',
'peer_pool': 'openstack1',
'host_site': 'site2'}
vol_type_fc_4 = volume_types.create(self.ctxt, 'FC4', extra_spec_4)
volume4_fc['volume_type_id'] = vol_type_fc_4['id']
self.fc_driver.initialize_connection(volume4_fc, connector2)
host_site_3 = {'site1': 'ffff000000000000',
'site1': 'ffff000000000001'}
self.fc_driver.configuration.set_override(
'storwize_preferred_host_site', host_site_3)
self.fc_driver.initialize_connection(volume_fc, connector)
host_name = self.fc_driver._helpers.get_host_from_connector(
connector, iscsi=True)
host_info = self.fc_driver._helpers.ssh.lshost(host=host_name)
self.assertEqual('site1', host_info[0]['site_name'])
host_site_4 = {'site2': 'ffff000000000000',
'site2': 'ffff000000000001'}
self.fc_driver.configuration.set_override(
'storwize_preferred_host_site', host_site_4)
self.assertRaises(exception.InvalidConfigurationValue,
self.fc_driver.initialize_connection,
volume_fc_2,
connector)
@mock.patch.object(storwize_svc_fc.StorwizeSVCFCDriver,
'_do_terminate_connection')
@ -4812,8 +4765,7 @@ class StorwizeSVCCommonDriverTestCase(test.TestCase):
def _create_hyperswap_type(self, type_name):
spec = {'drivers:volume_topology': 'hyperswap',
'peer_pool': 'hyperswap2',
'host_site': 'site1'}
'peer_pool': 'hyperswap2'}
hyper_type = self._create_volume_type(spec, type_name)
return hyper_type
@ -4939,7 +4891,6 @@ class StorwizeSVCCommonDriverTestCase(test.TestCase):
'mirror_pool': None,
'volume_topology': None,
'peer_pool': None,
'host_site': None,
'cycle_period_seconds': 300,
}
return opt

View File

@ -130,9 +130,14 @@ storwize_svc_opts = [
default=None,
help='Specifies the name of the peer pool for hyperswap '
'volume, the peer pool must exist on the other site.'),
cfg.StrOpt('storwize_preferred_host_site',
default=None,
help='Specifies the preferred host site name.'),
cfg.DictOpt('storwize_preferred_host_site',
default={},
help='Specifies the site information for host. '
'One WWPN or multi WWPNs used in the host can be '
'specified. For example: '
'storwize_preferred_host_site=site1:wwpn1,'
'site2:wwpn2&wwpn3 or '
'storwize_preferred_host_site=site1:iqn1,site2:iqn2'),
cfg.IntOpt('cycle_period_seconds',
default=300,
min=60, max=86400,
@ -866,6 +871,10 @@ class StorwizeHelpers(object):
site_iogrp = []
pool_data = self.get_pool_attrs(pool)
if pool_data is None:
msg = (_('Failed getting details for pool %s.') % pool)
LOG.error(msg)
raise exception.InvalidConfigurationValue(message=msg)
if 'site_id' in pool_data and pool_data['site_id']:
for node in state['storage_nodes'].values():
if pool_data['site_id'] == node['site_id']:
@ -1258,7 +1267,6 @@ class StorwizeHelpers(object):
'mirror_pool': config.storwize_svc_mirror_pool,
'volume_topology': None,
'peer_pool': config.storwize_peer_pool,
'host_site': config.storwize_preferred_host_site,
'cycle_period_seconds': config.cycle_period_seconds}
return opt
@ -5554,3 +5562,47 @@ class StorwizeSVCCommonDriver(san.SanDriver,
"from rccg. Exception: %(exception)s.",
{'vol': volume.name, 'exception': err})
return model_update, added_vols, removed_vols
def _get_volume_host_site_from_conf(self, volume, connector, iscsi=False):
host_site = self.configuration.safe_get('storwize_preferred_host_site')
select_site = None
if not host_site:
LOG.debug('There is no host_site configured for volume %s.',
volume.name)
return select_site
if iscsi:
for site, iqn in host_site.items():
if connector['initiator'].lower() in iqn.lower():
if select_site is None:
select_site = site
elif select_site != site:
msg = _('Configured the host IQN in both sites.')
LOG.error(msg)
raise exception.InvalidConfigurationValue(message=msg)
else:
for wwpn in connector['wwpns']:
for site, wwpn_list in host_site.items():
if wwpn.lower() in wwpn_list.lower():
if select_site is None:
select_site = site
elif select_site != site:
msg = _('Configured the host wwpns not in the'
' same site.')
LOG.error(msg)
raise exception.InvalidConfigurationValue(
message=msg)
return select_site
def _update_host_site_for_hyperswap_volume(self, host_name, host_site):
host_info = self._helpers.ssh.lshost(host=host_name)
if not host_info[0]['site_name'] and host_site:
self._helpers.update_host(host_name, host_site)
elif host_info[0]['site_name']:
ref_host_site = host_info[0]['site_name']
if host_site and host_site != ref_host_site:
msg = (_('The existing host site is %(ref_host_site)s,'
' but the new host site is %(host_site)s.') %
{'ref_host_site': ref_host_site,
'host_site': host_site})
LOG.error(msg)
raise exception.InvalidConfigurationValue(message=msg)

View File

@ -165,36 +165,24 @@ class StorwizeSVCFCDriver(storwize_common.StorwizeSVCCommonDriver):
else:
volume_name, backend_helper, node_state = self._get_vol_sys_info(
volume)
opts = self._get_vdisk_params(volume.volume_type_id)
host_site = opts['host_site']
host_site = self._get_volume_host_site_from_conf(volume,
connector)
is_hyper_volume = backend_helper.is_volume_hyperswap(volume_name)
# The host_site is necessary for hyperswap volume.
if is_hyper_volume and host_site is None:
msg = (_('There is no correct storwize_preferred_host_site '
'configured for a hyperswap volume %s.') % volume.name)
LOG.error(msg)
raise exception.VolumeDriverException(message=msg)
# Check if a host object is defined for this host name
host_name = backend_helper.get_host_from_connector(connector)
if host_name is None:
# Host does not exist - add a new host to Storwize/SVC
# The host_site is necessary for hyperswap volume.
if backend_helper.is_volume_hyperswap(
volume_name) and host_site is None:
msg = (_('There is no host_site configured for a hyperswap'
' volume %s.') % volume_name)
LOG.error(msg)
raise exception.VolumeDriverException(message=msg)
host_name = backend_helper.create_host(connector, site=host_site)
else:
host_info = backend_helper.ssh.lshost(host=host_name)
if 'site_name' in host_info[0]:
if not host_info[0]['site_name'] and host_site:
backend_helper.update_host(host_name, host_site)
elif host_info[0]['site_name']:
ref_host_site = host_info[0]['site_name']
if host_site and host_site != ref_host_site:
msg = (_('The existing host site is %(ref_host_site)s,'
' but the new host site is %(host_site)s.') %
{'ref_host_site': ref_host_site,
'host_site': host_site})
LOG.error(msg)
raise exception.VolumeDriverException(message=msg)
elif is_hyper_volume:
self._update_host_site_for_hyperswap_volume(host_name, host_site)
volume_attributes = backend_helper.get_vdisk_attributes(volume_name)
if volume_attributes is None:

View File

@ -163,38 +163,26 @@ class StorwizeSVCISCSIDriver(storwize_common.StorwizeSVCCommonDriver):
else:
volume_name, backend_helper, node_state = self._get_vol_sys_info(
volume)
opts = self._get_vdisk_params(volume.volume_type_id)
host_site = opts['host_site']
host_site = self._get_volume_host_site_from_conf(volume,
connector,
iscsi=True)
is_hyper_volume = backend_helper.is_volume_hyperswap(volume_name)
if is_hyper_volume and host_site is None:
msg = (_('There is no correct storwize_preferred_host_site '
'configured for a hyperswap volume %s.') % volume.name)
LOG.error(msg)
raise exception.VolumeDriverException(message=msg)
# Check if a host object is defined for this host name
host_name = backend_helper.get_host_from_connector(connector,
iscsi=True)
if host_name is None:
# Host does not exist - add a new host to Storwize/SVC
# The host_site is necessary for hyperswap volume
if backend_helper.is_volume_hyperswap(
volume_name) and host_site is None:
msg = (_('There is no host_site configured for a hyperswap'
' volume %s.') % volume_name)
LOG.error(msg)
raise exception.VolumeDriverException(message=msg)
host_name = backend_helper.create_host(connector, iscsi=True,
site = host_site)
else:
host_info = backend_helper.ssh.lshost(host=host_name)
if 'site_name' in host_info[0]:
if not host_info[0]['site_name'] and host_site:
backend_helper.update_host(host_name, host_site)
elif host_info[0]['site_name']:
ref_host_site = host_info[0]['site_name']
if host_site and host_site != ref_host_site:
msg = (_('The existing host site is %(ref_host_site)s,'
' but the new host site is %(host_site)s.') %
{'ref_host_site': ref_host_site,
'host_site': host_site})
LOG.error(msg)
raise exception.VolumeDriverException(message=msg)
site=host_site)
elif is_hyper_volume:
self._update_host_site_for_hyperswap_volume(host_name, host_site)
chap_secret = backend_helper.get_chap_secret_for_host(host_name)
chap_enabled = self.configuration.storwize_svc_iscsi_chap_enabled

View File

@ -584,12 +584,31 @@ A hyperswap volume is created with a volume-type that has the extra spec
``drivers:volume_topology`` set to ``hyperswap``.
To support hyperswap volumes, IBM Storwize/SVC firmware version 7.6.0 or
later is required.
Add the following to the back-end configuration to specify the host preferred
site for hyperswap volume.
FC:
.. code-block:: ini
storwize_preferred_host_site = site1:20000090fa17311e&ff00000000000001,
site2:20000089762sedce&ff00000000000000
iSCSI:
.. code-block:: ini
storwize_preferred_host_site = site1:iqn.1993-08.org.debian:01:eac5ccc1aaa&iqn.1993-08.org.debian:01:be53b7e236be,
site2:iqn.1993-08.org.debian:01:eac5ccc1bbb&iqn.1993-08.org.debian:01:abcdefg9876w
The site1 and site2 are names of the two host sites used in Storwize
storage. The WWPNs and IQNs are the connectors used for host mapping in
Storwize.
.. code-block:: console
$ cinder type-create hyper_type
$ cinder type-key hyper_type set drivers:volume_topology=hyperswap \
drivers:peer_pool=Pool_site2 drivers:host_site=site1
drivers:peer_pool=Pool_site2
.. note::

View File

@ -0,0 +1,6 @@
---
fixes:
- |
Updated the parameter storwzie_preferred_host_site from StrOpt to DictOpt
in cinder back-end configuration, and removed it from volume type
configuration.