Merge "Rework Storwize/SVC protocol to fix add_vdisk_copy"

This commit is contained in:
Jenkins 2016-03-17 02:52:41 +00:00 committed by Gerrit Code Review
commit 76a19863df
4 changed files with 60 additions and 107 deletions

View File

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

View File

@ -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'))

View File

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

View File

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