Merge "Rework Storwize/SVC protocol to fix add_vdisk_copy"
This commit is contained in:
commit
76a19863df
@ -2130,6 +2130,13 @@ class StorwizeSVCISCSIDriverTestCase(test.TestCase):
|
|||||||
self.iscsi_driver.terminate_connection(volume, conn2)
|
self.iscsi_driver.terminate_connection(volume, conn2)
|
||||||
self.iscsi_driver.terminate_connection(volume, self._connector)
|
self.iscsi_driver.terminate_connection(volume, self._connector)
|
||||||
|
|
||||||
|
def test_add_vdisk_copy_iscsi(self):
|
||||||
|
# Ensure only iSCSI is available
|
||||||
|
self.iscsi_driver._state['enabled_protocols'] = set(['iSCSI'])
|
||||||
|
volume = self._generate_vol_info(None, None)
|
||||||
|
self.iscsi_driver.create_volume(volume)
|
||||||
|
self.iscsi_driver.add_vdisk_copy(volume['name'], 'fake-pool', None)
|
||||||
|
|
||||||
|
|
||||||
class StorwizeSVCFcDriverTestCase(test.TestCase):
|
class StorwizeSVCFcDriverTestCase(test.TestCase):
|
||||||
@mock.patch.object(time, 'sleep')
|
@mock.patch.object(time, 'sleep')
|
||||||
@ -2563,6 +2570,13 @@ class StorwizeSVCFcDriverTestCase(test.TestCase):
|
|||||||
self.fc_driver.terminate_connection(volume, conn2)
|
self.fc_driver.terminate_connection(volume, conn2)
|
||||||
self.fc_driver.terminate_connection(volume, self._connector)
|
self.fc_driver.terminate_connection(volume, self._connector)
|
||||||
|
|
||||||
|
def test_add_vdisk_copy_fc(self):
|
||||||
|
# Ensure only FC is available
|
||||||
|
self.fc_driver._state['enabled_protocols'] = set(['FC'])
|
||||||
|
volume = self._generate_vol_info(None, None)
|
||||||
|
self.fc_driver.create_volume(volume)
|
||||||
|
self.fc_driver.add_vdisk_copy(volume['name'], 'fake-pool', None)
|
||||||
|
|
||||||
|
|
||||||
class StorwizeSVCCommonDriverTestCase(test.TestCase):
|
class StorwizeSVCCommonDriverTestCase(test.TestCase):
|
||||||
@mock.patch.object(time, 'sleep')
|
@mock.patch.object(time, 'sleep')
|
||||||
@ -2875,7 +2889,6 @@ class StorwizeSVCCommonDriverTestCase(test.TestCase):
|
|||||||
'grainsize': 256,
|
'grainsize': 256,
|
||||||
'compression': False,
|
'compression': False,
|
||||||
'easytier': True,
|
'easytier': True,
|
||||||
'protocol': 'iSCSI',
|
|
||||||
'iogrp': 0,
|
'iogrp': 0,
|
||||||
'qos': None,
|
'qos': None,
|
||||||
'replication': False,
|
'replication': False,
|
||||||
|
@ -888,7 +888,7 @@ class StorwizeHelpers(object):
|
|||||||
return self.ssh.lshostvdiskmap(host_name)
|
return self.ssh.lshostvdiskmap(host_name)
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def build_default_opts(config, protocol):
|
def build_default_opts(config):
|
||||||
# Ignore capitalization
|
# Ignore capitalization
|
||||||
|
|
||||||
cluster_partner = config.storwize_svc_stretched_cluster_partner
|
cluster_partner = config.storwize_svc_stretched_cluster_partner
|
||||||
@ -898,7 +898,6 @@ class StorwizeHelpers(object):
|
|||||||
'grainsize': config.storwize_svc_vol_grainsize,
|
'grainsize': config.storwize_svc_vol_grainsize,
|
||||||
'compression': config.storwize_svc_vol_compression,
|
'compression': config.storwize_svc_vol_compression,
|
||||||
'easytier': config.storwize_svc_vol_easytier,
|
'easytier': config.storwize_svc_vol_easytier,
|
||||||
'protocol': protocol,
|
|
||||||
'iogrp': config.storwize_svc_vol_iogrp,
|
'iogrp': config.storwize_svc_vol_iogrp,
|
||||||
'qos': None,
|
'qos': None,
|
||||||
'stretched_cluster': cluster_partner,
|
'stretched_cluster': cluster_partner,
|
||||||
@ -926,14 +925,6 @@ class StorwizeHelpers(object):
|
|||||||
reason=_('If compression is set to True, rsize must '
|
reason=_('If compression is set to True, rsize must '
|
||||||
'also be set (not equal to -1).'))
|
'also be set (not equal to -1).'))
|
||||||
|
|
||||||
# Check that the requested protocol is enabled
|
|
||||||
if opts['protocol'] not in state['enabled_protocols']:
|
|
||||||
raise exception.InvalidInput(
|
|
||||||
reason=_('The storage device does not support %(prot)s. '
|
|
||||||
'Please configure the device to support %(prot)s or '
|
|
||||||
'switch to a driver using a different protocol.')
|
|
||||||
% {'prot': opts['protocol']})
|
|
||||||
|
|
||||||
if opts['iogrp'] not in state['available_iogrps']:
|
if opts['iogrp'] not in state['available_iogrps']:
|
||||||
avail_grps = ''.join(str(e) for e in state['available_iogrps'])
|
avail_grps = ''.join(str(e) for e in state['available_iogrps'])
|
||||||
raise exception.InvalidInput(
|
raise exception.InvalidInput(
|
||||||
@ -959,21 +950,6 @@ class StorwizeHelpers(object):
|
|||||||
scope = key_split[0]
|
scope = key_split[0]
|
||||||
key = key_split[1]
|
key = key_split[1]
|
||||||
|
|
||||||
# We generally do not look at capabilities in the driver, but
|
|
||||||
# protocol is a special case where the user asks for a given
|
|
||||||
# protocol and we want both the scheduler and the driver to act
|
|
||||||
# on the value.
|
|
||||||
if ((not scope or scope == 'capabilities') and
|
|
||||||
key == 'storage_protocol'):
|
|
||||||
scope = None
|
|
||||||
key = 'protocol'
|
|
||||||
words = value.split()
|
|
||||||
if not (words and len(words) == 2 and words[0] == '<in>'):
|
|
||||||
LOG.error(_LE('Protocol must be specified as '
|
|
||||||
'\'<in> iSCSI\' or \'<in> FC\'.'))
|
|
||||||
del words[0]
|
|
||||||
value = words[0]
|
|
||||||
|
|
||||||
# We generally do not look at capabilities in the driver, but
|
# We generally do not look at capabilities in the driver, but
|
||||||
# replication is a special case where the user asks for
|
# replication is a special case where the user asks for
|
||||||
# a volume to be replicated, and we want both the scheduler and
|
# a volume to be replicated, and we want both the scheduler and
|
||||||
@ -1066,13 +1042,13 @@ class StorwizeHelpers(object):
|
|||||||
timer = loopingcall.FixedIntervalLoopingCall(_inner)
|
timer = loopingcall.FixedIntervalLoopingCall(_inner)
|
||||||
timer.start(interval=interval).wait()
|
timer.start(interval=interval).wait()
|
||||||
|
|
||||||
def get_vdisk_params(self, config, state, type_id, protocol = 'iSCSI',
|
def get_vdisk_params(self, config, state, type_id,
|
||||||
volume_type=None, volume_metadata=None):
|
volume_type=None, volume_metadata=None):
|
||||||
"""Return the parameters for creating the vdisk.
|
"""Return the parameters for creating the vdisk.
|
||||||
|
|
||||||
Takes volume type and defaults from config options into account.
|
Takes volume type and defaults from config options into account.
|
||||||
"""
|
"""
|
||||||
opts = self.build_default_opts(config, protocol)
|
opts = self.build_default_opts(config)
|
||||||
ctxt = context.get_admin_context()
|
ctxt = context.get_admin_context()
|
||||||
if volume_type is None and type_id is not None:
|
if volume_type is None and type_id is not None:
|
||||||
volume_type = volume_types.get_volume_type(ctxt, type_id)
|
volume_type = volume_types.get_volume_type(ctxt, type_id)
|
||||||
@ -1870,7 +1846,7 @@ class StorwizeSVCCommonDriver(san.SanDriver,
|
|||||||
self._helpers = StorwizeHelpers(self._run_ssh)
|
self._helpers = StorwizeHelpers(self._run_ssh)
|
||||||
self._vdiskcopyops = {}
|
self._vdiskcopyops = {}
|
||||||
self._vdiskcopyops_loop = None
|
self._vdiskcopyops_loop = None
|
||||||
self.protocol = ''
|
self.protocol = None
|
||||||
self.replication = None
|
self.replication = None
|
||||||
self._state = {'storage_nodes': {},
|
self._state = {'storage_nodes': {},
|
||||||
'enabled_protocols': set(),
|
'enabled_protocols': set(),
|
||||||
@ -1926,6 +1902,26 @@ class StorwizeSVCCommonDriver(san.SanDriver,
|
|||||||
# Get the iSCSI and FC names of the Storwize/SVC nodes
|
# Get the iSCSI and FC names of the Storwize/SVC nodes
|
||||||
self._state['storage_nodes'] = self._helpers.get_node_info()
|
self._state['storage_nodes'] = self._helpers.get_node_info()
|
||||||
|
|
||||||
|
# Add the iSCSI IP addresses and WWPNs to the storage node info
|
||||||
|
self._helpers.add_iscsi_ip_addrs(self._state['storage_nodes'])
|
||||||
|
self._helpers.add_fc_wwpns(self._state['storage_nodes'])
|
||||||
|
|
||||||
|
# For each node, check what connection modes it supports. Delete any
|
||||||
|
# nodes that do not support any types (may be partially configured).
|
||||||
|
to_delete = []
|
||||||
|
for k, node in self._state['storage_nodes'].items():
|
||||||
|
if ((len(node['ipv4']) or len(node['ipv6']))
|
||||||
|
and len(node['iscsi_name'])):
|
||||||
|
node['enabled_protocols'].append('iSCSI')
|
||||||
|
self._state['enabled_protocols'].add('iSCSI')
|
||||||
|
if len(node['WWPN']):
|
||||||
|
node['enabled_protocols'].append('FC')
|
||||||
|
self._state['enabled_protocols'].add('FC')
|
||||||
|
if not len(node['enabled_protocols']):
|
||||||
|
to_delete.append(k)
|
||||||
|
for delkey in to_delete:
|
||||||
|
del self._state['storage_nodes'][delkey]
|
||||||
|
|
||||||
# Build the list of in-progress vdisk copy operations
|
# Build the list of in-progress vdisk copy operations
|
||||||
if ctxt is None:
|
if ctxt is None:
|
||||||
admin_context = context.get_admin_context()
|
admin_context = context.get_admin_context()
|
||||||
@ -1946,6 +1942,7 @@ class StorwizeSVCCommonDriver(san.SanDriver,
|
|||||||
self._vdiskcopyops_loop = loopingcall.FixedIntervalLoopingCall(
|
self._vdiskcopyops_loop = loopingcall.FixedIntervalLoopingCall(
|
||||||
self._check_volume_copy_ops)
|
self._check_volume_copy_ops)
|
||||||
self._vdiskcopyops_loop.start(interval=self.VDISKCOPYOPS_INTERVAL)
|
self._vdiskcopyops_loop.start(interval=self.VDISKCOPYOPS_INTERVAL)
|
||||||
|
LOG.debug('leave: do_setup')
|
||||||
|
|
||||||
# v2 replication setup
|
# v2 replication setup
|
||||||
self._do_replication_setup()
|
self._do_replication_setup()
|
||||||
@ -1972,6 +1969,21 @@ class StorwizeSVCCommonDriver(san.SanDriver,
|
|||||||
exception_msg = (_('Unable to determine system id.'))
|
exception_msg = (_('Unable to determine system id.'))
|
||||||
raise exception.VolumeBackendAPIException(data=exception_msg)
|
raise exception.VolumeBackendAPIException(data=exception_msg)
|
||||||
|
|
||||||
|
# Make sure we have at least one node configured
|
||||||
|
if not len(self._state['storage_nodes']):
|
||||||
|
msg = _('do_setup: No configured nodes.')
|
||||||
|
LOG.error(msg)
|
||||||
|
raise exception.VolumeDriverException(message=msg)
|
||||||
|
|
||||||
|
if self.protocol not in self._state['enabled_protocols']:
|
||||||
|
# TODO(mc_nair): improve this error message by looking at
|
||||||
|
# self._state['enabled_protocols'] to tell user what driver to use
|
||||||
|
raise exception.InvalidInput(
|
||||||
|
reason=_('The storage device does not support %(prot)s. '
|
||||||
|
'Please configure the device to support %(prot)s or '
|
||||||
|
'switch to a driver using a different protocol.')
|
||||||
|
% {'prot': self.protocol})
|
||||||
|
|
||||||
required_flags = ['san_ip', 'san_ssh_port', 'san_login',
|
required_flags = ['san_ip', 'san_ssh_port', 'san_login',
|
||||||
'storwize_svc_volpool_name']
|
'storwize_svc_volpool_name']
|
||||||
for flag in required_flags:
|
for flag in required_flags:
|
||||||
@ -1986,8 +1998,7 @@ class StorwizeSVCCommonDriver(san.SanDriver,
|
|||||||
'authentication: set either san_password or '
|
'authentication: set either san_password or '
|
||||||
'san_private_key option.'))
|
'san_private_key option.'))
|
||||||
|
|
||||||
opts = self._helpers.build_default_opts(self.configuration,
|
opts = self._helpers.build_default_opts(self.configuration)
|
||||||
self.protocol)
|
|
||||||
self._helpers.check_vdisk_opts(self._state, opts)
|
self._helpers.check_vdisk_opts(self._state, opts)
|
||||||
|
|
||||||
LOG.debug('leave: check_for_setup_error')
|
LOG.debug('leave: check_for_setup_error')
|
||||||
@ -2119,7 +2130,6 @@ class StorwizeSVCCommonDriver(san.SanDriver,
|
|||||||
volume_metadata=None):
|
volume_metadata=None):
|
||||||
return self._helpers.get_vdisk_params(self.configuration,
|
return self._helpers.get_vdisk_params(self.configuration,
|
||||||
self._state, type_id,
|
self._state, type_id,
|
||||||
self.protocol,
|
|
||||||
volume_type=volume_type,
|
volume_type=volume_type,
|
||||||
volume_metadata=volume_metadata)
|
volume_metadata=volume_metadata)
|
||||||
|
|
||||||
@ -2722,10 +2732,9 @@ class StorwizeSVCCommonDriver(san.SanDriver,
|
|||||||
'diff': diff,
|
'diff': diff,
|
||||||
'host': host})
|
'host': host})
|
||||||
|
|
||||||
ignore_keys = ['protocol']
|
|
||||||
no_copy_keys = ['warning', 'autoexpand', 'easytier']
|
no_copy_keys = ['warning', 'autoexpand', 'easytier']
|
||||||
copy_keys = ['rsize', 'grainsize', 'compression']
|
copy_keys = ['rsize', 'grainsize', 'compression']
|
||||||
all_keys = ignore_keys + no_copy_keys + copy_keys
|
all_keys = no_copy_keys + copy_keys
|
||||||
old_opts = self._get_vdisk_params(volume['volume_type_id'],
|
old_opts = self._get_vdisk_params(volume['volume_type_id'],
|
||||||
volume_metadata=
|
volume_metadata=
|
||||||
volume.get('volume_matadata'))
|
volume.get('volume_matadata'))
|
||||||
|
@ -89,42 +89,10 @@ class StorwizeSVCFCDriver(storwize_common.StorwizeSVCCommonDriver):
|
|||||||
|
|
||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
super(StorwizeSVCFCDriver, self).__init__(*args, **kwargs)
|
super(StorwizeSVCFCDriver, self).__init__(*args, **kwargs)
|
||||||
|
self.protocol = 'FC'
|
||||||
self.configuration.append_config_values(
|
self.configuration.append_config_values(
|
||||||
storwize_svc_fc_opts)
|
storwize_svc_fc_opts)
|
||||||
|
|
||||||
def do_setup(self, ctxt):
|
|
||||||
# Set protocol
|
|
||||||
self.protocol = 'FC'
|
|
||||||
|
|
||||||
# Setup common functionality between FC
|
|
||||||
super(StorwizeSVCFCDriver, self).do_setup(ctxt)
|
|
||||||
|
|
||||||
# Add WWPNs to the storage node info
|
|
||||||
self._helpers.add_fc_wwpns(self._state['storage_nodes'])
|
|
||||||
|
|
||||||
# For each node, check what connection modes it supports. Delete any
|
|
||||||
# nodes that do not support any types (may be partially configured).
|
|
||||||
to_delete = []
|
|
||||||
for k, node in self._state['storage_nodes'].items():
|
|
||||||
if len(node['WWPN']):
|
|
||||||
node['enabled_protocols'].append('FC')
|
|
||||||
self._state['enabled_protocols'].add('FC')
|
|
||||||
if not len(node['enabled_protocols']):
|
|
||||||
LOG.info(_LI("%(node)s will be removed since "
|
|
||||||
"it is not supported by the"
|
|
||||||
" FC driver."), {'node': node['name']})
|
|
||||||
to_delete.append(k)
|
|
||||||
for delkey in to_delete:
|
|
||||||
del self._state['storage_nodes'][delkey]
|
|
||||||
|
|
||||||
# Make sure we have at least one node configured
|
|
||||||
if not len(self._state['storage_nodes']):
|
|
||||||
msg = _('do_setup: No configured nodes.')
|
|
||||||
LOG.error(msg)
|
|
||||||
raise exception.VolumeDriverException(message=msg)
|
|
||||||
|
|
||||||
LOG.debug('leave: do_setup')
|
|
||||||
|
|
||||||
def validate_connector(self, connector):
|
def validate_connector(self, connector):
|
||||||
"""Check connector for at least one enabled FC protocol."""
|
"""Check connector for at least one enabled FC protocol."""
|
||||||
if 'wwpns' not in connector:
|
if 'wwpns' not in connector:
|
||||||
|
@ -39,7 +39,7 @@ from oslo_log import log as logging
|
|||||||
from oslo_utils import excutils
|
from oslo_utils import excutils
|
||||||
|
|
||||||
from cinder import exception
|
from cinder import exception
|
||||||
from cinder.i18n import _, _LE, _LI, _LW
|
from cinder.i18n import _, _LE, _LW
|
||||||
from cinder import utils
|
from cinder import utils
|
||||||
|
|
||||||
from cinder.volume.drivers.ibm.storwize_svc import (
|
from cinder.volume.drivers.ibm.storwize_svc import (
|
||||||
@ -89,46 +89,10 @@ class StorwizeSVCISCSIDriver(storwize_common.StorwizeSVCCommonDriver):
|
|||||||
|
|
||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
super(StorwizeSVCISCSIDriver, self).__init__(*args, **kwargs)
|
super(StorwizeSVCISCSIDriver, self).__init__(*args, **kwargs)
|
||||||
|
self.protocol = 'iSCSI'
|
||||||
self.configuration.append_config_values(
|
self.configuration.append_config_values(
|
||||||
storwize_svc_iscsi_opts)
|
storwize_svc_iscsi_opts)
|
||||||
|
|
||||||
def do_setup(self, ctxt):
|
|
||||||
# Set protocol
|
|
||||||
self.protocol = 'iSCSI'
|
|
||||||
|
|
||||||
# Setup common functionality between FC and iSCSI
|
|
||||||
super(StorwizeSVCISCSIDriver, self).do_setup(ctxt)
|
|
||||||
|
|
||||||
# Get the iSCSI names of the Storwize/SVC nodes
|
|
||||||
self._state['storage_nodes'] = self._helpers.get_node_info()
|
|
||||||
|
|
||||||
# Add the iSCSI IP addresses to the storage node info
|
|
||||||
self._helpers.add_iscsi_ip_addrs(self._state['storage_nodes'])
|
|
||||||
|
|
||||||
# For each node, check what connection modes it supports. Delete any
|
|
||||||
# nodes that do not support any types (may be partially configured).
|
|
||||||
to_delete = []
|
|
||||||
for k, node in self._state['storage_nodes'].items():
|
|
||||||
if ((len(node['ipv4']) or len(node['ipv6']))
|
|
||||||
and len(node['iscsi_name'])):
|
|
||||||
node['enabled_protocols'].append('iSCSI')
|
|
||||||
self._state['enabled_protocols'].add('iSCSI')
|
|
||||||
if not len(node['enabled_protocols']):
|
|
||||||
LOG.info(_LI("%(node)s will be removed since "
|
|
||||||
"it is not supported by the "
|
|
||||||
"iSCSI driver."), {'node': node['name']})
|
|
||||||
to_delete.append(k)
|
|
||||||
for delkey in to_delete:
|
|
||||||
del self._state['storage_nodes'][delkey]
|
|
||||||
|
|
||||||
# Make sure we have at least one node configured
|
|
||||||
if not len(self._state['storage_nodes']):
|
|
||||||
msg = _('do_setup: No configured nodes.')
|
|
||||||
LOG.error(msg)
|
|
||||||
raise exception.VolumeDriverException(message=msg)
|
|
||||||
|
|
||||||
LOG.debug('leave: do_setup')
|
|
||||||
|
|
||||||
def validate_connector(self, connector):
|
def validate_connector(self, connector):
|
||||||
"""Check connector for at least one enabled iSCSI protocol."""
|
"""Check connector for at least one enabled iSCSI protocol."""
|
||||||
if 'initiator' not in connector:
|
if 'initiator' not in connector:
|
||||||
@ -152,7 +116,6 @@ class StorwizeSVCISCSIDriver(storwize_common.StorwizeSVCCommonDriver):
|
|||||||
LOG.debug('enter: initialize_connection: volume %(vol)s with connector'
|
LOG.debug('enter: initialize_connection: volume %(vol)s with connector'
|
||||||
' %(conn)s', {'vol': volume['id'], 'conn': connector})
|
' %(conn)s', {'vol': volume['id'], 'conn': connector})
|
||||||
|
|
||||||
vol_opts = self._get_vdisk_params(volume['volume_type_id'])
|
|
||||||
volume_name = volume['name']
|
volume_name = volume['name']
|
||||||
|
|
||||||
# Check if a host object is defined for this host name
|
# Check if a host object is defined for this host name
|
||||||
@ -194,7 +157,7 @@ class StorwizeSVCISCSIDriver(storwize_common.StorwizeSVCCommonDriver):
|
|||||||
preferred_node_entry = None
|
preferred_node_entry = None
|
||||||
io_group_nodes = []
|
io_group_nodes = []
|
||||||
for node in self._state['storage_nodes'].values():
|
for node in self._state['storage_nodes'].values():
|
||||||
if vol_opts['protocol'] not in node['enabled_protocols']:
|
if self.protocol not in node['enabled_protocols']:
|
||||||
continue
|
continue
|
||||||
if node['id'] == preferred_node:
|
if node['id'] == preferred_node:
|
||||||
preferred_node_entry = node
|
preferred_node_entry = node
|
||||||
|
Loading…
Reference in New Issue
Block a user