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
This commit is contained in:
Angela Smith 2016-03-17 12:45:51 -07:00
parent 9567844f0e
commit b550cec9cd
3 changed files with 81 additions and 118 deletions

View File

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

View File

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

View File

@ -0,0 +1,5 @@
---
features:
- Support for use of 'fc_southbound_protocol'
configuration setting in the Brocade FC SAN
lookup service.