cinder/cinder/tests/unit/zonemanager/test_brcd_fc_zone_driver.py

279 lines
11 KiB
Python

# (c) Copyright 2014 Brocade Communications Systems Inc.
# All Rights Reserved.
#
# 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
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
#
"""Unit tests for Brocade fc zone driver."""
from unittest import mock
from oslo_utils import importutils
import paramiko
import requests
from cinder import exception
from cinder.tests.unit import test
from cinder.volume import configuration as conf
from cinder.zonemanager.drivers.brocade import brcd_fabric_opts as fabric_opts
from cinder.zonemanager.drivers.brocade import brcd_fc_zone_driver as driver
from cinder.zonemanager import fc_zone_manager as zmanager
_zone_name = 'openstack_fab1_10008c7cff523b0120240002ac000a50'
_zone_name_initiator_mode = 'openstack_fab1_10008c7cff523b01'
WWNS = ['10:00:8c:7c:ff:52:3b:01', '20:24:00:02:ac:00:0a:50']
_active_cfg_before_add = {}
_activate = True
_target_ns_map = {'100000051e55a100': ['20240002ac000a50']}
_initiator_ns_map = {'100000051e55a100': ['10008c7cff523b01']}
_zone_map_to_add = {_zone_name: WWNS}
_initiator_target_map = {'10008c7cff523b01': ['20240002ac000a50']}
_device_map_to_verify = {
'100000051e55a100': {
'initiator_port_wwn_list': [
'10008c7cff523b01'], 'target_port_wwn_list': ['20240002ac000a50']}}
_fabric_wwn = '100000051e55a100'
class BrcdFcZoneDriverBaseTest(object):
def _set_conf_overrides(self, group, **kwargs):
for name, value in kwargs.items():
self.override_config(name, value, group)
def setup_config(self, is_normal, mode):
self.override_config('zoning_mode', 'fabric')
fabric_group_name = 'BRCD_FAB_1'
self._set_conf_overrides(
'fc-zone-manager',
zone_driver=('cinder.tests.unit.zonemanager.'
'test_brcd_fc_zone_driver.FakeBrcdFCZoneDriver'),
brcd_sb_connector=('cinder.tests.unit.zonemanager.'
'test_brcd_fc_zone_driver.'
'FakeBrcdFCZoneClientCLI'),
zoning_policy='initiator-target',
fc_san_lookup_service=('cinder.tests.unit.zonemanager.'
'test_brcd_fc_zone_driver.'
'FakeBrcdFCSanLookupService'),
fc_fabric_names=fabric_group_name,
)
# Ensure that we have the fabric_name group
conf.Configuration(fabric_opts.brcd_zone_opts, fabric_group_name)
self._set_conf_overrides(
fabric_group_name,
fc_fabric_address='10.24.48.213',
fc_fabric_password='password',
fc_fabric_user='admin' if is_normal else 'invaliduser',
zoning_policy='initiator' if mode == 2 else 'initiator-target',
zone_activate=True,
zone_name_prefix='openstack_fab1_',
fc_southbound_protocol='SSH',
)
configuration = conf.Configuration(zmanager.zone_manager_opts,
'fc-zone-manager')
return configuration
class TestBrcdFcZoneDriver(BrcdFcZoneDriverBaseTest, test.TestCase):
def setUp(self):
super(TestBrcdFcZoneDriver, self).setUp()
# setup config for normal flow
self.setup_driver(self.setup_config(True, 1))
GlobalVars._zone_state = []
def setup_driver(self, config):
self.driver = importutils.import_object(
'cinder.zonemanager.drivers.brocade.brcd_fc_zone_driver'
'.BrcdFCZoneDriver', configuration=config)
def fake__get_active_zone_set(self, brcd_sb_connector, fabric_ip):
return GlobalVars._active_cfg
def get_client(self, protocol='HTTPS'):
conn = ('cinder.tests.unit.zonemanager.test_brcd_fc_zone_driver.' +
('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(driver.BrcdFCZoneDriver, '_get_southbound_client')
def test_add_connection(self, get_southbound_client_mock):
"""Normal flow for i-t mode."""
GlobalVars._is_normal_test = True
GlobalVars._zone_state = []
GlobalVars._active_cfg = _active_cfg_before_add
get_southbound_client_mock.return_value = self.get_client("HTTPS")
self.driver.add_connection('BRCD_FAB_1', _initiator_target_map)
self.assertIn(_zone_name, GlobalVars._zone_state)
def _active_cfg_before_delete(self, mode):
zone_name = _zone_name if mode == 1 else _zone_name_initiator_mode
return {'zones': {zone_name: WWNS, 't_zone': ['1,0']},
'active_zone_config': 'cfg1'}
@mock.patch.object(driver.BrcdFCZoneDriver, '_get_southbound_client')
def test_delete_connection(self, get_southbound_client_mock):
GlobalVars._is_normal_test = True
GlobalVars._zone_state.append(_zone_name)
get_southbound_client_mock.return_value = self.get_client("CLI")
GlobalVars._active_cfg = self._active_cfg_before_delete(mode=1)
self.driver.delete_connection(
'BRCD_FAB_1', _initiator_target_map)
self.assertNotIn(_zone_name, GlobalVars._zone_state)
@mock.patch.object(driver.BrcdFCZoneDriver, '_get_southbound_client')
def test_add_connection_for_initiator_mode(self, get_southbound_client_mk):
"""Normal flow for i mode."""
GlobalVars._is_normal_test = True
get_southbound_client_mk.return_value = self.get_client("CLI")
GlobalVars._active_cfg = _active_cfg_before_add
self.setup_driver(self.setup_config(True, 2))
self.driver.add_connection('BRCD_FAB_1', _initiator_target_map)
self.assertIn(_zone_name_initiator_mode, GlobalVars._zone_state)
@mock.patch.object(driver.BrcdFCZoneDriver, '_get_southbound_client')
def test_delete_connection_for_initiator_mode(self,
get_southbound_client_mk):
GlobalVars._is_normal_test = True
GlobalVars._zone_state.append(_zone_name_initiator_mode)
get_southbound_client_mk.return_value = self.get_client("HTTPS")
GlobalVars._active_cfg = self._active_cfg_before_delete(mode=2)
self.setup_driver(self.setup_config(True, 2))
self.driver.delete_connection(
'BRCD_FAB_1', _initiator_target_map)
self.assertNotIn(_zone_name_initiator_mode, GlobalVars._zone_state)
@mock.patch('cinder.zonemanager.drivers.brocade.brcd_fc_zone_client_cli.'
'BrcdFCZoneClientCLI.__init__', side_effect=Exception)
def test_add_connection_for_invalid_fabric(self, create_client_mock):
"""Test abnormal flows."""
GlobalVars._active_cfg = _active_cfg_before_add
self.setup_driver(self.setup_config(False, 1))
self.assertRaises(exception.FCZoneDriverException,
self.driver.add_connection,
'BRCD_FAB_1',
_initiator_target_map)
@mock.patch('cinder.zonemanager.drivers.brocade.brcd_fc_zone_client_cli.'
'BrcdFCZoneClientCLI.__init__', side_effect=Exception)
def test_delete_connection_for_invalid_fabric(self, create_client_mock):
GlobalVars._active_cfg = self._active_cfg_before_delete(mode=1)
GlobalVars._is_normal_test = False
self.setup_driver(self.setup_config(False, 1))
self.assertRaises(exception.FCZoneDriverException,
self.driver.delete_connection,
'BRCD_FAB_1',
_initiator_target_map)
@mock.patch.object(driver.BrcdFCZoneDriver, '_get_southbound_client')
def test_get_san_context(self, client_mock):
GlobalVars._is_normal_test = True
self.setup_driver(self.setup_config(True, 1))
get_ns_mock = client_mock.return_value.get_nameserver_info
wwn = '20:24:00:02:ac:00:0a:50'
get_ns_mock.return_value = [wwn]
expected = {'BRCD_FAB_1': ['20240002ac000a50']}
res = self.driver.get_san_context([WWNS[0], wwn.upper()])
client_mock.assert_called_once_with('BRCD_FAB_1')
client_mock.return_value.cleanup.assert_called_once_with()
get_ns_mock.assert_called_once_with()
self.assertEqual(expected, res)
class FakeClient(object):
def get_active_zone_set(self):
return GlobalVars._active_cfg
def add_zones(self, zones, isActivate, active_zone_set):
GlobalVars._zone_state.extend(zones.keys())
def delete_zones(self, zone_names, isActivate, active_zone_set):
zone_list = zone_names.split(';')
GlobalVars._zone_state = [
x for x in GlobalVars._zone_state if x not in zone_list]
def is_supported_firmware(self):
return True
def get_nameserver_info(self):
return _target_ns_map
def close_connection(self):
pass
def cleanup(self):
pass
class FakeBrcdFCZoneClientCLI(FakeClient):
def __init__(self, ipaddress, username,
password, port, key, vfid, protocol):
self.firmware_supported = True
if not GlobalVars._is_normal_test:
raise paramiko.SSHException("Unable to connect to fabric.")
class FakeBrcdHttpFCZoneClient(FakeClient):
def __init__(self, ipaddress, username,
password, port, key, vfid, protocol):
self.firmware_supported = True
if not GlobalVars._is_normal_test:
raise requests.exception.HTTPError("Unable to connect to fabric")
class FakeBrcdFCSanLookupService(object):
def get_device_mapping_from_network(self,
initiator_wwn_list,
target_wwn_list):
device_map = {}
initiators = []
targets = []
for i in initiator_wwn_list:
if i in _initiator_ns_map[_fabric_wwn]:
initiators.append(i)
for t in target_wwn_list:
if t in _target_ns_map[_fabric_wwn]:
targets.append(t)
device_map[_fabric_wwn] = {
'initiator_port_wwn_list': initiators,
'target_port_wwn_list': targets}
return device_map
class GlobalVars(object):
global _active_cfg
_active_cfg = {}
global _zone_state
_zone_state = list()
global _is_normal_test
_is_normal_test = True