diff --git a/cinder/tests/unit/zonemanager/test_brcd_fc_san_lookup_service.py b/cinder/tests/unit/zonemanager/test_brcd_fc_san_lookup_service.py index 987980a7644..b4e1273bd24 100644 --- a/cinder/tests/unit/zonemanager/test_brcd_fc_san_lookup_service.py +++ b/cinder/tests/unit/zonemanager/test_brcd_fc_san_lookup_service.py @@ -1,4 +1,4 @@ -# (c) Copyright 2014 Brocade Communications Systems Inc. +# (c) Copyright 2016 Brocade Communications Systems Inc. # All Rights Reserved. # # Licensed under the Apache License, Version 2.0 (the "License"); you may @@ -18,16 +18,13 @@ """Unit tests for brcd fc san lookup service.""" import mock -from oslo_concurrency import processutils as putils from oslo_config import cfg +from oslo_utils import importutils -from cinder import exception -from cinder import ssh_utils from cinder import test from cinder.volume import configuration as conf import cinder.zonemanager.drivers.brocade.brcd_fc_san_lookup_service \ as brcd_lookup -from cinder.zonemanager.drivers.brocade import fc_zone_constants parsed_switch_port_wwns = ['20:1a:00:05:1e:e8:e3:29', @@ -76,6 +73,10 @@ class TestBrcdFCSanLookupService(brcd_lookup.BrcdFCSanLookupService, self.configuration.set_default('fc_fabric_names', 'BRCD_FAB_2', 'fc-zone-manager') self.configuration.fc_fabric_names = 'BRCD_FAB_2' + self.configuration.brcd_sb_connector = ('cinder.tests.unit.zonemanager' + '.test_brcd_fc_san_lookup_' + 'service' + '.FakeBrcdFCZoneClientCLI') self.create_configuration() # override some of the functions @@ -98,46 +99,57 @@ class TestBrcdFCSanLookupService(brcd_lookup.BrcdFCSanLookupService, config = conf.Configuration(fc_fabric_opts, 'BRCD_FAB_2') self.fabric_configs = {'BRCD_FAB_2': config} + def get_client(self, protocol='HTTPS'): + conn = ('cinder.tests.unit.zonemanager.' + 'test_brcd_fc_san_lookup_service.' + + ('FakeBrcdFCZoneClientCLI' if protocol == "CLI" + else 'FakeBrcdHttpFCZoneClient')) + client = importutils.import_object( + conn, + ipaddress="10.24.48.213", + username="admin", + password="password", + key="/home/stack/.ssh/id_rsa", + port=22, + vfid="2", + protocol=protocol + ) + return client + @mock.patch.object(brcd_lookup.BrcdFCSanLookupService, - 'get_nameserver_info') - @mock.patch('cinder.zonemanager.drivers.brocade.brcd_fc_san_lookup_service' - '.ssh_utils.SSHPool') - def test_get_device_mapping_from_network(self, mock_ssh_pool, - get_nameserver_info_mock): + '_get_southbound_client') + def test_get_device_mapping_from_network(self, get_southbound_client_mock): initiator_list = [parsed_switch_port_wwns[1]] target_list = [parsed_switch_port_wwns[0], '20240002ac000a40'] - get_nameserver_info_mock.return_value = parsed_switch_port_wwns + get_southbound_client_mock.return_value = self.get_client("HTTPS") device_map = self.get_device_mapping_from_network( initiator_list, target_list) self.assertDictMatch(_device_map_to_verify, device_map) - @mock.patch.object(brcd_lookup.BrcdFCSanLookupService, '_get_switch_data') - def test_get_nameserver_info(self, get_switch_data_mock): - ns_info_list = [] - get_switch_data_mock.return_value = (switch_data) - # get_switch_data will be called twice with the results appended - ns_info_list_expected = (parsed_switch_port_wwns + - parsed_switch_port_wwns) +class FakeClient(object): + def is_supported_firmware(self): + return True - ns_info_list = self.get_nameserver_info(None) - self.assertEqual(ns_info_list_expected, ns_info_list) + def get_nameserver_info(self): + ns_info_list_expected = (parsed_switch_port_wwns) + return ns_info_list_expected - @mock.patch.object(putils, 'ssh_execute', return_value=(switch_data, '')) - @mock.patch.object(ssh_utils.SSHPool, 'item') - def test__get_switch_data(self, ssh_pool_mock, ssh_execute_mock): - actual_switch_data = self._get_switch_data(ssh_pool_mock, - fc_zone_constants.NS_SHOW) - self.assertEqual(actual_switch_data, switch_data) - ssh_execute_mock.side_effect = putils.ProcessExecutionError() - self.assertRaises(exception.FCSanLookupServiceException, - self._get_switch_data, ssh_pool_mock, - fc_zone_constants.NS_SHOW) + def close_connection(self): + pass - def test__parse_ns_output(self): - invalid_switch_data = ' N 011a00;20:1a:00:05:1e:e8:e3:29' - return_wwn_list = [] - return_wwn_list = self._parse_ns_output(switch_data) - self.assertEqual(parsed_switch_port_wwns, return_wwn_list) - self.assertRaises(exception.InvalidParameterValue, - self._parse_ns_output, invalid_switch_data) + def cleanup(self): + pass + + +class FakeBrcdFCZoneClientCLI(FakeClient): + def __init__(self, ipaddress, username, + password, port, key, vfid, protocol): + self.firmware_supported = True + + +class FakeBrcdHttpFCZoneClient(FakeClient): + + def __init__(self, ipaddress, username, + password, port, key, vfid, protocol): + self.firmware_supported = True diff --git a/cinder/zonemanager/drivers/brocade/brcd_fc_san_lookup_service.py b/cinder/zonemanager/drivers/brocade/brcd_fc_san_lookup_service.py index e7ac96c354a..6e0e9a9f2ba 100644 --- a/cinder/zonemanager/drivers/brocade/brcd_fc_san_lookup_service.py +++ b/cinder/zonemanager/drivers/brocade/brcd_fc_san_lookup_service.py @@ -1,8 +1,6 @@ -# (c) Copyright 2014 Brocade Communications Systems Inc. +# (c) Copyright 2016 Brocade Communications Systems Inc. # All Rights Reserved. # -# Copyright 2014 OpenStack Foundation -# # Licensed under the Apache License, Version 2.0 (the "License"); you may # not use this file except in compliance with the License. You may obtain # a copy of the License at @@ -16,17 +14,13 @@ # under the License. # -from oslo_concurrency import processutils from oslo_log import log as logging from oslo_utils import excutils -import six +from oslo_utils import importutils from cinder import exception from cinder.i18n import _, _LE -from cinder import ssh_utils -from cinder import utils from cinder.zonemanager.drivers.brocade import brcd_fabric_opts as fabric_opts -import cinder.zonemanager.drivers.brocade.fc_zone_constants as zone_constant from cinder.zonemanager import fc_san_lookup_service as fc_service from cinder.zonemanager import utils as fczm_utils @@ -38,10 +32,11 @@ class BrcdFCSanLookupService(fc_service.FCSanLookupService): Version History: 1.0.0 - Initial version + 1.1 - Add support to use config option for switch southbound protocol """ - VERSION = "1.0.0" + VERSION = "1.1" def __init__(self, **kwargs): """Initializing the client.""" @@ -107,15 +102,6 @@ class BrcdFCSanLookupService(fc_service.FCSanLookupService): for fabric_name in fabrics: fabric_ip = self.fabric_configs[fabric_name].safe_get( 'fc_fabric_address') - fabric_user = self.fabric_configs[fabric_name].safe_get( - 'fc_fabric_user') - fabric_pwd = self.fabric_configs[fabric_name].safe_get( - 'fc_fabric_password') - fabric_port = self.fabric_configs[fabric_name].safe_get( - 'fc_fabric_port') - - ssh_pool = ssh_utils.SSHPool(fabric_ip, fabric_port, None, - fabric_user, password=fabric_pwd) # Get name server data from fabric and find the targets # logged in @@ -123,7 +109,8 @@ class BrcdFCSanLookupService(fc_service.FCSanLookupService): try: LOG.debug("Getting name server data for " "fabric %s", fabric_ip) - nsinfo = self.get_nameserver_info(ssh_pool) + conn = self._get_southbound_client(fabric_name) + nsinfo = conn.get_nameserver_info() except exception.FCSanLookupServiceException: with excutils.save_and_reraise_exception(): LOG.error(_LE("Failed collecting name server info from" @@ -172,69 +159,28 @@ class BrcdFCSanLookupService(fc_service.FCSanLookupService): LOG.debug("Device map for SAN context: %s", device_map) return device_map - def get_nameserver_info(self, ssh_pool): - """Get name server data from fabric. + def _get_southbound_client(self, fabric): + """Implementation to get SouthBound Connector. - This method will return the connected node port wwn list(local - and remote) for the given switch fabric + South bound connector will be + dynamically selected based on the configuration - :param ssh_pool: SSH connections for the current fabric + :param fabric: fabric information """ - cli_output = None - nsinfo_list = [] + fabric_info = self.fabric_configs[fabric] + fc_ip = fabric_info.safe_get('fc_fabric_address') + sb_connector = fabric_info.safe_get('fc_southbound_protocol') + if sb_connector is None: + sb_connector = self.configuration.brcd_sb_connector try: - cli_output = self._get_switch_data(ssh_pool, - zone_constant.NS_SHOW) - except exception.FCSanLookupServiceException: - with excutils.save_and_reraise_exception(): - LOG.error(_LE("Failed collecting nsshow info for fabric")) - if cli_output: - nsinfo_list = self._parse_ns_output(cli_output) - try: - cli_output = self._get_switch_data(ssh_pool, - zone_constant.NS_CAM_SHOW) - - except exception.FCSanLookupServiceException: - with excutils.save_and_reraise_exception(): - LOG.error(_LE("Failed collecting nscamshow")) - if cli_output: - nsinfo_list.extend(self._parse_ns_output(cli_output)) - LOG.debug("Connector returning nsinfo-%s", nsinfo_list) - return nsinfo_list - - def _get_switch_data(self, ssh_pool, cmd): - utils.check_ssh_injection([cmd]) - - with ssh_pool.item() as ssh: - try: - switch_data, err = processutils.ssh_execute(ssh, cmd) - except processutils.ProcessExecutionError as e: - msg = (_("SSH Command failed with error: '%(err)s', Command: " - "'%(command)s'") % {'err': six.text_type(e), - 'command': cmd}) - LOG.error(msg) - raise exception.FCSanLookupServiceException(message=msg) - - return switch_data - - def _parse_ns_output(self, switch_data): - """Parses name server data. - - Parses nameserver raw data and adds the device port wwns to the list - - :returns: list of device port wwn from ns info - """ - nsinfo_list = [] - lines = switch_data.split('\n') - for line in lines: - if not(" NL " in line or " N " in line): - continue - linesplit = line.split(';') - if len(linesplit) > 2: - node_port_wwn = linesplit[2].strip() - nsinfo_list.append(node_port_wwn) - else: - msg = _("Malformed nameserver string: %s") % line - LOG.error(msg) - raise exception.InvalidParameterValue(err=msg) - return nsinfo_list + conn_factory = importutils.import_object( + "cinder.zonemanager.drivers.brocade." + "brcd_fc_zone_connector_factory." + "BrcdFCZoneFactory") + client = conn_factory.get_connector(fabric_info, + sb_connector.upper()) + except Exception: + msg = _("Failed to create south bound connector for %s.") % fc_ip + LOG.exception(msg) + raise exception.FCZoneDriverException(msg) + return client diff --git a/releasenotes/notes/brcd_lookupservice_http_support-f6485b38a1feaa15.yaml b/releasenotes/notes/brcd_lookupservice_http_support-f6485b38a1feaa15.yaml new file mode 100644 index 00000000000..5cec223e0f2 --- /dev/null +++ b/releasenotes/notes/brcd_lookupservice_http_support-f6485b38a1feaa15.yaml @@ -0,0 +1,5 @@ +--- +features: + - Support for use of 'fc_southbound_protocol' + configuration setting in the Brocade FC SAN + lookup service.