Merge "Brocade: Fix AttributeError when raising exception"
This commit is contained in:
commit
5f7a698cec
|
@ -0,0 +1,298 @@
|
|||
# Copyright 2020 Red Hat, 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.
|
||||
|
||||
from unittest import mock
|
||||
|
||||
import ddt
|
||||
|
||||
from cinder.tests.unit import test
|
||||
from cinder.zonemanager.drivers.brocade import brcd_rest_fc_zone_client as \
|
||||
rest_client
|
||||
from cinder.zonemanager.drivers.brocade import fc_zone_constants
|
||||
|
||||
|
||||
@ddt.ddt
|
||||
class TestBrcdRestClient(test.TestCase):
|
||||
def setUp(self):
|
||||
super(TestBrcdRestClient, self).setUp()
|
||||
self.client = self._get_client()
|
||||
|
||||
@mock.patch.object(rest_client.BrcdRestFCZoneClient, '_login', mock.Mock())
|
||||
def _get_client(self,
|
||||
ip=mock.sentinel.ipaddress,
|
||||
user=mock.sentinel.username,
|
||||
password=mock.sentinel.password,
|
||||
port=mock.sentinel.port,
|
||||
vfid=mock.sentinel.vfid,
|
||||
protocol=mock.sentinel.protocol):
|
||||
return rest_client.BrcdRestFCZoneClient(ip, user, password, port, vfid,
|
||||
protocol)
|
||||
|
||||
@mock.patch.object(rest_client.BrcdRestFCZoneClient, '_login')
|
||||
def test_init(self, login_mock):
|
||||
res = rest_client.BrcdRestFCZoneClient(mock.sentinel.ipaddress,
|
||||
mock.sentinel.username,
|
||||
mock.sentinel.password,
|
||||
mock.sentinel.port,
|
||||
mock.sentinel.vfid,
|
||||
mock.sentinel.protocol)
|
||||
|
||||
self.assertEqual(mock.sentinel.ipaddress, res.sw_ip)
|
||||
self.assertEqual(mock.sentinel.username, res.sw_user)
|
||||
self.assertEqual(mock.sentinel.password, res.sw_pwd)
|
||||
self.assertEqual(mock.sentinel.vfid, res.vfid)
|
||||
self.assertEqual(mock.sentinel.protocol, res.protocol)
|
||||
# Port parameter is not used by the class
|
||||
self.assertEqual('', res.status_code)
|
||||
self.assertIsNone(res.session)
|
||||
login_mock.assert_called_once_with()
|
||||
|
||||
@ddt.data((False, '7.4.0'), (False, '8.2.0'),
|
||||
(True, '8.2.1'), (True, '9.0.0'))
|
||||
@ddt.unpack
|
||||
@mock.patch.object(rest_client.BrcdRestFCZoneClient,
|
||||
'_get_firmware_version')
|
||||
def test_is_supported_firmware(self, expected, version, mock_get_fw):
|
||||
mock_get_fw.return_value = version
|
||||
|
||||
res = self.client.is_supported_firmware()
|
||||
|
||||
self.assertIs(expected, res)
|
||||
mock_get_fw.assert_called_once_with()
|
||||
|
||||
@mock.patch.object(rest_client.BrcdRestFCZoneClient,
|
||||
'_get_effective_zone_set')
|
||||
def test_get_active_zone_set(self, get_effective_mock):
|
||||
get_effective_mock.return_value = (mock.sentinel.active_zone_set,
|
||||
mock.sentinel.checksum)
|
||||
res = self.client.get_active_zone_set()
|
||||
self.assertEqual(mock.sentinel.active_zone_set, res)
|
||||
get_effective_mock.assert_called_once_with()
|
||||
|
||||
@mock.patch.object(rest_client.BrcdRestFCZoneClient, '_get_name_server')
|
||||
def test_get_nameserver_info(self, get_ns_mock):
|
||||
res = self.client.get_nameserver_info()
|
||||
self.assertEqual(get_ns_mock.return_value, res)
|
||||
get_ns_mock.assert_called_once_with()
|
||||
|
||||
@mock.patch.object(rest_client.BrcdRestFCZoneClient, '_add_zones')
|
||||
def test_add_zones(self, add_mock):
|
||||
self.client.add_zones(mock.sentinel.add_zone_map,
|
||||
mock.sentinel.activate,
|
||||
mock.sentinel.active_zone_set__not_used)
|
||||
add_mock.assert_called_once_with(mock.sentinel.add_zone_map,
|
||||
mock.sentinel.activate)
|
||||
|
||||
@mock.patch.object(rest_client.BrcdRestFCZoneClient, '_update_zones')
|
||||
def test_update_zones(self, update_mock):
|
||||
self.client.update_zones(mock.sentinel.zone_map,
|
||||
mock.sentinel.activate,
|
||||
mock.sentinel.operation,
|
||||
mock.sentinel.active_zone_set__not_used)
|
||||
update_mock.assert_called_once_with(mock.sentinel.zone_map,
|
||||
mock.sentinel.activate,
|
||||
mock.sentinel.operation)
|
||||
|
||||
@mock.patch.object(rest_client.BrcdRestFCZoneClient, '_delete_zones')
|
||||
def test_delete_zones(self, delete_mock):
|
||||
self.client.delete_zones(mock.sentinel.zone_names,
|
||||
mock.sentinel.activate,
|
||||
mock.sentinel.active_zone_set__not_used)
|
||||
delete_mock.assert_called_once_with(mock.sentinel.zone_names,
|
||||
mock.sentinel.activate)
|
||||
|
||||
@mock.patch.object(rest_client.BrcdRestFCZoneClient, '_logout')
|
||||
def test_cleanup(self, logout_mock):
|
||||
self.client.cleanup()
|
||||
logout_mock.assert_called_once_with()
|
||||
|
||||
@ddt.data(200, 400)
|
||||
@mock.patch.object(rest_client.BrcdRestFCZoneClient, '_build_url')
|
||||
@mock.patch.object(rest_client, 'requests')
|
||||
def test__login(self, status_code, requests_mock, url_mock):
|
||||
session_mock = requests_mock.Session
|
||||
post_mock = session_mock.return_value.post
|
||||
post_mock.return_value.status_code = status_code
|
||||
post_mock.return_value.headers = {'Authorization': mock.sentinel.auth}
|
||||
|
||||
adapter_mock = requests_mock.adapters.HTTPAdapter
|
||||
adapter_mock.return_value = 'adapter'
|
||||
|
||||
client = self._get_client(protocol=fc_zone_constants.REST_HTTPS,
|
||||
user='username', password='password')
|
||||
expected_headers = {'User-Agent': 'OpenStack Zone Driver',
|
||||
'Accept': 'application/yang-data+json',
|
||||
'Content-Type': 'application/yang-data+json',
|
||||
'Authorization': mock.sentinel.auth}
|
||||
try:
|
||||
res = client._login()
|
||||
self.assertEqual(200, res)
|
||||
except rest_client.exception.BrocadeZoningRestException:
|
||||
self.assertNotEqual(200, status_code)
|
||||
expected_headers['Authorization'] = ('Basic '
|
||||
'dXNlcm5hbWU6cGFzc3dvcmQ=')
|
||||
del expected_headers['Content-Type']
|
||||
|
||||
self.assertEqual(fc_zone_constants.HTTPS, client.protocol)
|
||||
session_mock.assert_called_once_with()
|
||||
self.assertEqual(requests_mock.Session.return_value, client.session)
|
||||
adapter_mock.assert_called_once_with(pool_connections=1,
|
||||
pool_maxsize=1)
|
||||
session_mock.return_value.mount.assert_called_once_with('https://',
|
||||
'adapter')
|
||||
|
||||
url_mock.assert_called_once_with('/rest/login')
|
||||
post_mock.assert_called_once_with(url_mock.return_value)
|
||||
|
||||
self.assertEqual(expected_headers,
|
||||
session_mock.return_value.headers)
|
||||
|
||||
@mock.patch.object(rest_client.BrcdRestFCZoneClient, '_build_url')
|
||||
def test_logout(self, url_mock):
|
||||
session = mock.Mock()
|
||||
session.post.return_value.status_code = 204
|
||||
self.client.session = session
|
||||
|
||||
self.client._logout()
|
||||
|
||||
url_mock.assert_called_once_with('/rest/logout')
|
||||
session.post.assert_called_once_with(url_mock.return_value)
|
||||
|
||||
@mock.patch.object(rest_client.BrcdRestFCZoneClient, '_build_url')
|
||||
def test_logout_fail(self, url_mock):
|
||||
session = mock.Mock()
|
||||
session.post.return_value.status_code = 400
|
||||
self.client.session = session
|
||||
|
||||
self.assertRaises(rest_client.exception.BrocadeZoningRestException,
|
||||
self.client._logout)
|
||||
url_mock.assert_called_once_with('/rest/logout')
|
||||
session.post.assert_called_once_with(url_mock.return_value)
|
||||
|
||||
@mock.patch.object(rest_client.BrcdRestFCZoneClient, '_build_url')
|
||||
def test_get_firmware_version(self, url_mock):
|
||||
session = mock.Mock()
|
||||
session.get.return_value.status_code = 200
|
||||
session.get.return_value.json.return_value = {
|
||||
'Response': {
|
||||
'fibrechannel-switch': {
|
||||
'firmware-version': mock.sentinel.fw_version}}}
|
||||
self.client.session = session
|
||||
|
||||
res = self.client._get_firmware_version()
|
||||
|
||||
self.assertEqual(mock.sentinel.fw_version, res)
|
||||
|
||||
url_mock.assert_called_once_with(
|
||||
'/rest/running/switch/fibrechannel-switch')
|
||||
session.get.assert_called_once_with(url_mock.return_value)
|
||||
session.get.return_value.json.assert_called_once_with()
|
||||
|
||||
@mock.patch.object(rest_client.BrcdRestFCZoneClient, '_build_url')
|
||||
def test_get_firmware_version_fail(self, url_mock):
|
||||
session = mock.Mock()
|
||||
session.get.return_value.status_code = 400
|
||||
self.client.session = session
|
||||
|
||||
self.assertRaises(rest_client.exception.BrocadeZoningRestException,
|
||||
self.client._get_firmware_version)
|
||||
|
||||
url_mock.assert_called_once_with(
|
||||
'/rest/running/switch/fibrechannel-switch')
|
||||
session.get.assert_called_once_with(url_mock.return_value)
|
||||
session.get.return_value.json.assert_not_called()
|
||||
|
||||
@mock.patch.object(rest_client.BrcdRestFCZoneClient, '_build_url')
|
||||
def test__get_name_server(self, url_mock):
|
||||
session = mock.Mock()
|
||||
session.get.return_value.status_code = 200
|
||||
session.get.return_value.json.return_value = {
|
||||
'Response': {
|
||||
'fibrechannel-name-server': [
|
||||
{'port-name': mock.sentinel.port1},
|
||||
{'port-name': mock.sentinel.port2}]}}
|
||||
self.client.session = session
|
||||
|
||||
res = self.client._get_name_server()
|
||||
|
||||
self.assertEqual([mock.sentinel.port1, mock.sentinel.port2], res)
|
||||
|
||||
url_mock.assert_called_once_with(
|
||||
'/rest/running/brocade-name-server/fibrechannel-name-server')
|
||||
session.get.assert_called_once_with(url_mock.return_value)
|
||||
session.get.return_value.json.assert_called_once_with()
|
||||
|
||||
@mock.patch.object(rest_client.BrcdRestFCZoneClient, '_build_url')
|
||||
def test__get_name_server_fail(self, url_mock):
|
||||
session = mock.Mock()
|
||||
session.get.return_value.status_code = 400
|
||||
self.client.session = session
|
||||
|
||||
self.assertRaises(rest_client.exception.BrocadeZoningRestException,
|
||||
self.client._get_name_server)
|
||||
|
||||
url_mock.assert_called_once_with(
|
||||
'/rest/running/brocade-name-server/fibrechannel-name-server')
|
||||
session.get.assert_called_once_with(url_mock.return_value)
|
||||
session.get.return_value.json.assert_not_called()
|
||||
|
||||
@ddt.data(([{'zone-name': 'zone1',
|
||||
'member-entry': {'entry-name': 'entry1'}},
|
||||
{'zone-name': 'zone2',
|
||||
'member-entry': {'entry-name': 'entry2'}}],
|
||||
{'zone1': 'entry1', 'zone2': 'entry2'}),
|
||||
({'zone-name': 'zone1',
|
||||
'member-entry': {'entry-name': 'entry1'}},
|
||||
{'zone1': 'entry1'}),
|
||||
({}, {}))
|
||||
@ddt.unpack
|
||||
@mock.patch.object(rest_client.BrcdRestFCZoneClient, '_build_url')
|
||||
def test_get_effective_zone_set(self, enabled_zone, expected_zones,
|
||||
url_mock):
|
||||
session = mock.Mock()
|
||||
session.get.return_value.status_code = 200
|
||||
session.get.return_value.json.return_value = {
|
||||
'Response': {
|
||||
'effective-configuration': {
|
||||
'checksum': mock.sentinel.checksum,
|
||||
'cfg-name': 'my-cfg',
|
||||
'enabled-zone': enabled_zone}}}
|
||||
self.client.session = session
|
||||
|
||||
res = self.client._get_effective_zone_set()
|
||||
|
||||
expected = ({'active_zone_config': 'my-cfg' if expected_zones else '',
|
||||
'zones': expected_zones},
|
||||
mock.sentinel.checksum)
|
||||
self.assertEqual(expected, res)
|
||||
|
||||
url_mock.assert_called_once_with(
|
||||
'/rest/running/zoning/effective-configuration')
|
||||
session.get.assert_called_once_with(url_mock.return_value)
|
||||
session.get.return_value.json.assert_called_once_with()
|
||||
|
||||
@mock.patch.object(rest_client.BrcdRestFCZoneClient, '_build_url')
|
||||
def test_get_effective_zone_set_fail(self, url_mock):
|
||||
session = mock.Mock()
|
||||
session.get.return_value.status_code = 400
|
||||
self.client.session = session
|
||||
|
||||
self.assertRaises(rest_client.exception.BrocadeZoningRestException,
|
||||
self.client._get_effective_zone_set)
|
||||
|
||||
url_mock.assert_called_once_with(
|
||||
'/rest/running/zoning/effective-configuration')
|
||||
session.get.assert_called_once_with(url_mock.return_value)
|
||||
session.get.return_value.json.assert_not_called()
|
|
@ -25,8 +25,8 @@ from oslo_serialization import base64
|
|||
import requests
|
||||
import six
|
||||
|
||||
from cinder import exception
|
||||
from cinder.i18n import _
|
||||
from cinder.zonemanager.drivers.brocade import exception
|
||||
from cinder.zonemanager.drivers.brocade import fc_zone_constants
|
||||
from cinder.zonemanager.drivers.brocade import rest_constants
|
||||
|
||||
|
|
|
@ -0,0 +1,6 @@
|
|||
---
|
||||
fixes:
|
||||
- |
|
||||
Fix `AttributeError` on the Brocade ZM driver when using setting REST_HTTP
|
||||
or REST_HTTPS as the fc_southbound_protocol option and an exception is
|
||||
raised by the client (Bug #1866860).
|
Loading…
Reference in New Issue