From: Avishay Traeger Date: Thu, 22 Aug 2013 20:17:57 +0000 (+0300) Subject: Storwize/SVC: allow setting of I/O group X-Git-Url: https://review.fuel-infra.org/gitweb?a=commitdiff_plain;h=bba098c8319fe9b3b11d04e65e7f1d0945987301;p=openstack-build%2Fcinder-build.git Storwize/SVC: allow setting of I/O group Allow setting the I/O group via config option or volume type. Also updated comments and checks regarding iSCSI multipath, which is in Nova and is not controlled by the driver. Fixes: bug 1215363 Change-Id: Ia67fcb9991e21990cc81830145b8fd934a23488e --- diff --git a/cinder/tests/test_storwize_svc.py b/cinder/tests/test_storwize_svc.py index 4192a37ce..b2a4949e5 100644 --- a/cinder/tests/test_storwize_svc.py +++ b/cinder/tests/test_storwize_svc.py @@ -29,7 +29,6 @@ import random import re import socket -from cinder.brick.initiator import connector from cinder import context from cinder import exception from cinder.openstack.common import excutils @@ -514,6 +513,8 @@ port_speed!N/A capacity = int(kwargs['size']) unit = kwargs['unit'] volume_info['capacity'] = self._convert_units_bytes(capacity, unit) + volume_info['IO_group_id'] = kwargs['iogrp'] + volume_info['IO_group_name'] = 'io_grp%s' % kwargs['iogrp'] if 'easytier' in kwargs: if kwargs['easytier'] == 'on': @@ -631,8 +632,8 @@ port_speed!N/A cap = self._convert_bytes_units(vol['capacity']) else: cap = vol['capacity'] - rows.append([str(vol['id']), vol['name'], '0', 'io_grp0', - 'online', '0', + rows.append([str(vol['id']), vol['name'], vol['IO_group_id'], + vol['IO_group_name'], 'online', '0', self._flags['storwize_svc_volpool_name'], cap, 'striped', fcmap_info['fc_id'], fcmap_info['fc_name'], @@ -658,8 +659,8 @@ port_speed!N/A rows.append(['id', str(vol['id'])]) rows.append(['name', vol['name']]) - rows.append(['IO_group_id', '0']) - rows.append(['IO_group_name', 'io_grp0']) + rows.append(['IO_group_id', vol['IO_group_id']]) + rows.append(['IO_group_name', vol['IO_group_name']]) rows.append(['status', 'online']) rows.append(['mdisk_grp_id', '0']) rows.append([ @@ -712,6 +713,16 @@ port_speed!N/A return ('%s' % '\n'.join(rows), '') + def _cmd_lsiogrp(self, **kwargs): + rows = [None] * 6 + rows[0] = ['id', 'name', 'node_count', 'vdisk_count', 'host_count'] + rows[1] = ['0', 'io_grp0', '2', '22', '4'] + rows[2] = ['1', 'io_grp1', '2', '22', '4'] + rows[3] = ['2', 'io_grp2', '0', '0', '4'] + rows[4] = ['3', 'io_grp3', '0', '0', '4'] + rows[5] = ['4', 'recovery_io_grp', '0', '0', '0'] + return self._print_info_cmd(rows=rows, **kwargs) + def _add_port_to_host(self, host_info, **kwargs): if 'iscsiname' in kwargs: added_key = 'iscsi_names' @@ -1178,6 +1189,8 @@ port_speed!N/A out, err = self._cmd_expandvdisksize(**kwargs) elif command == 'lsvdisk': out, err = self._cmd_lsvdisk(**kwargs) + elif command == 'lsiogrp': + out, err = self._cmd_lsiogrp(**kwargs) elif command == 'mkhost': out, err = self._cmd_mkhost(**kwargs) elif command == 'addhostport': @@ -1297,7 +1310,7 @@ class StorwizeSVCDriverTestCase(test.TestCase): self.driver.configuration.set_override('rootwrap_config', '/etc/cinder/rootwrap.conf', config_group) - self._connector = connector.get_connector_properties() + self._connector = utils.brick_get_connector_properties() self._reset_flags() self.driver.db = StorwizeSVCFakeDB() @@ -1385,8 +1398,7 @@ class StorwizeSVCDriverTestCase(test.TestCase): self.driver.check_for_setup_error) self._reset_flags() - self._set_flag('storwize_svc_connection_protocol', 'iSCSI') - self._set_flag('storwize_svc_multipath_enabled', True) + self._set_flag('storwize_svc_vol_iogrp', 5) self.assertRaises(exception.InvalidInput, self.driver.check_for_setup_error) self._reset_flags() @@ -1590,17 +1602,22 @@ class StorwizeSVCDriverTestCase(test.TestCase): # compression False 2,3 # easytier True 1,3 # easytier False 2 + # iogrp 0 1 + # iogrp 1 2 opts_list = [] chck_list = [] - opts_list.append({'rsize': -1, 'easytier': True}) - chck_list.append({'free_capacity': '0', 'easy_tier': 'on'}) + opts_list.append({'rsize': -1, 'easytier': True, 'iogrp': 0}) + chck_list.append({'free_capacity': '0', 'easy_tier': 'on', + 'IO_group_id': '0'}) + test_iogrp = 1 if self.USESIM else 0 opts_list.append({'rsize': 2, 'compression': False, 'warning': 0, 'autoexpand': True, 'grainsize': 32, - 'easytier': False}) + 'easytier': False, 'iogrp': test_iogrp}) chck_list.append({'-free_capacity': '0', 'compressed_copy': 'no', 'warning': '0', 'autoexpand': 'on', - 'grainsize': '32', 'easy_tier': 'off'}) + 'grainsize': '32', 'easy_tier': 'off', + 'IO_group_id': str(test_iogrp)}) opts_list.append({'rsize': 2, 'compression': False, 'warning': 80, 'autoexpand': False, 'grainsize': 256, 'easytier': True}) diff --git a/cinder/volume/drivers/storwize_svc.py b/cinder/volume/drivers/storwize_svc.py index 345e8e1c5..a6350796e 100644 --- a/cinder/volume/drivers/storwize_svc.py +++ b/cinder/volume/drivers/storwize_svc.py @@ -84,16 +84,20 @@ storwize_svc_opts = [ cfg.BoolOpt('storwize_svc_vol_easytier', default=True, help='Enable Easy Tier for volumes'), + cfg.IntOpt('storwize_svc_vol_iogrp', + default=0, + help='The I/O group in which to allocate volumes'), cfg.IntOpt('storwize_svc_flashcopy_timeout', default=120, help='Maximum number of seconds to wait for FlashCopy to be ' - 'prepared. Maximum value is 600 seconds (10 minutes).'), + 'prepared. Maximum value is 600 seconds (10 minutes)'), cfg.StrOpt('storwize_svc_connection_protocol', default='iSCSI', help='Connection protocol (iSCSI/FC)'), cfg.BoolOpt('storwize_svc_multipath_enabled', default=False, - help='Connect with multipath (currently FC-only)'), + help='Connect with multipath (FC only; iSCSI multipath is ' + 'controlled by Nova)'), cfg.BoolOpt('storwize_svc_multihostmap_enabled', default=True, help='Allows vdisk to multi host mapping'), @@ -125,6 +129,7 @@ class StorwizeSVCDriver(san.SanDriver): self._storage_nodes = {} self._enabled_protocols = set() self._compression_enabled = False + self._available_iogrps = [] self._context = None # Build cleanup translation tables for host names @@ -209,6 +214,34 @@ class StorwizeSVCDriver(san.SanDriver): except exception.ProcessExecutionError: LOG.exception(_('Failed to get license information.')) + # Get the available I/O groups + ssh_cmd = ['svcinfo', 'lsiogrp', '-delim', '!'] + out, err = self._run_ssh(ssh_cmd) + self._assert_ssh_return(len(out.strip()), 'do_setup', + ssh_cmd, out, err) + iogrps = out.strip().split('\n') + self._assert_ssh_return(len(iogrps), 'do_setup', ssh_cmd, out, err) + header = iogrps.pop(0) + for iogrp_line in iogrps: + try: + iogrp_data = self._get_hdr_dic(header, iogrp_line, '!') + if (int(iogrp_data['node_count']) > 0 and + int(iogrp_data['vdisk_count']) > 0): + self._available_iogrps.append(int(iogrp_data['id'])) + except exception.VolumeBackendAPIException: + with excutils.save_and_reraise_exception(): + self._log_cli_output_error('do_setup', + ssh_cmd, out, err) + except KeyError: + self._handle_keyerror('lsnode', header) + except ValueError: + msg = (_('Expected integers for node_count and vdisk_count, ' + 'svcinfo lsiogrp returned: %(node)s and %(vdisk)s') % + {'node': iogrp_data['node_count'], + 'vdisk': iogrp_data['vdisk_count']}) + LOG.error(msg) + raise exception.VolumeBackendAPIException(data=msg) + # Get the iSCSI and FC names of the Storwize/SVC nodes ssh_cmd = ['svcinfo', 'lsnode', '-delim', '!'] out, err = self._run_ssh(ssh_cmd) @@ -216,8 +249,7 @@ class StorwizeSVCDriver(san.SanDriver): ssh_cmd, out, err) nodes = out.strip().split('\n') - self._assert_ssh_return(len(nodes), - 'do_setup', ssh_cmd, out, err) + self._assert_ssh_return(len(nodes), 'do_setup', ssh_cmd, out, err) header = nodes.pop(0) for node_line in nodes: try: @@ -285,7 +317,8 @@ class StorwizeSVCDriver(san.SanDriver): 'compression': self.configuration.storwize_svc_vol_compression, 'easytier': self.configuration.storwize_svc_vol_easytier, 'protocol': protocol, - 'multipath': self.configuration.storwize_svc_multipath_enabled} + 'multipath': self.configuration.storwize_svc_multipath_enabled, + 'iogrp': self.configuration.storwize_svc_vol_iogrp} return opt def check_for_setup_error(self): @@ -760,8 +793,6 @@ class StorwizeSVCDriver(san.SanDriver): properties['volume_id'] = volume['id'] if vol_opts['protocol'] == 'iSCSI': type_str = 'iscsi' - # We take the first IP address for now. Ideally, OpenStack will - # support iSCSI multipath for improved performance. if len(preferred_node_entry['ipv4']): ipaddr = preferred_node_entry['ipv4'][0] else: @@ -949,7 +980,7 @@ class StorwizeSVCDriver(san.SanDriver): ssh_cmd = ['svctask', 'mkvdisk', '-name', name, '-mdiskgrp', self.configuration.storwize_svc_volpool_name, - '-iogrp', '0', '-size', size, '-unit', + '-iogrp', str(opts['iogrp']), '-size', size, '-unit', units, '-easytier', easytier] + ssh_cmd_se_opt out, err = self._run_ssh(ssh_cmd) self._assert_ssh_return(len(out.strip()), '_create_vdisk', @@ -1476,12 +1507,12 @@ class StorwizeSVCDriver(san.SanDriver): % {'prot': opts['protocol'], 'enabled': ','.join(self._enabled_protocols)}) - # Check that multipath is only enabled for fc - if opts['protocol'] != 'FC' and opts['multipath']: + if opts['iogrp'] not in self._available_iogrps: raise exception.InvalidInput( - reason=_('Multipath is currently only supported for FC ' - 'connections and not iSCSI. (This is a Nova ' - 'limitation.)')) + reason=_('I/O group %(iogrp)d is not valid; available ' + 'I/O groups are %(avail)s') + % {'iogrp': opts['iogrp'], + 'avail': ''.join(str(e) for e in self._available_iogrps)}) def _execute_command_and_parse_attributes(self, ssh_cmd): """Execute command on the Storwize/SVC and parse attributes.