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:
parent
9567844f0e
commit
b550cec9cd
@ -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
|
||||
|
@ -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
|
||||
|
@ -0,0 +1,5 @@
|
||||
---
|
||||
features:
|
||||
- Support for use of 'fc_southbound_protocol'
|
||||
configuration setting in the Brocade FC SAN
|
||||
lookup service.
|
Loading…
Reference in New Issue
Block a user