From b550cec9cd54b06a1945794ef60dde6215b2f4a3 Mon Sep 17 00:00:00 2001 From: Angela Smith Date: Thu, 17 Mar 2016 12:45:51 -0700 Subject: [PATCH] Fix Brcd lookup service to use defined southbound protocol Adds support to the lookup service to use the config option for southbound communication to the FC switch which is already being used by the brcd driver. Closes-Bug: #1557737 Change-Id: Ie3189832641ceca9d38298bafb68e6e4860b0a08 --- .../test_brcd_fc_san_lookup_service.py | 86 ++++++++------ .../brocade/brcd_fc_san_lookup_service.py | 108 +++++------------- ...service_http_support-f6485b38a1feaa15.yaml | 5 + 3 files changed, 81 insertions(+), 118 deletions(-) create mode 100644 releasenotes/notes/brcd_lookupservice_http_support-f6485b38a1feaa15.yaml 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.