Merge "ML2 Cisco Nexus MD: Improve Unit Test Coverage"
This commit is contained in:
commit
5141c1b0a0
@ -109,12 +109,6 @@ def get_port_switch_bindings(port_id, switch_ip):
|
|||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
def get_nexussvi_bindings():
|
|
||||||
"""Lists nexus svi bindings."""
|
|
||||||
LOG.debug(_("get_nexussvi_bindings() called"))
|
|
||||||
return _lookup_all_nexus_bindings(port_id='router')
|
|
||||||
|
|
||||||
|
|
||||||
def _lookup_nexus_bindings(query_type, session=None, **bfilter):
|
def _lookup_nexus_bindings(query_type, session=None, **bfilter):
|
||||||
"""Look up 'query_type' Nexus bindings matching the filter.
|
"""Look up 'query_type' Nexus bindings matching the filter.
|
||||||
|
|
||||||
|
@ -169,23 +169,3 @@ class CiscoNexusDriver(object):
|
|||||||
if nexus_port:
|
if nexus_port:
|
||||||
self.enable_vlan_on_trunk_int(nexus_host, vlan_id, intf_type,
|
self.enable_vlan_on_trunk_int(nexus_host, vlan_id, intf_type,
|
||||||
nexus_port)
|
nexus_port)
|
||||||
|
|
||||||
def delete_and_untrunk_vlan(self, nexus_host, vlan_id, intf_type,
|
|
||||||
nexus_port):
|
|
||||||
"""Delete VLAN and untrunk it from the specified ports."""
|
|
||||||
self.delete_vlan(nexus_host, vlan_id)
|
|
||||||
if nexus_port:
|
|
||||||
self.disable_vlan_on_trunk_int(nexus_host, vlan_id, intf_type,
|
|
||||||
nexus_port)
|
|
||||||
|
|
||||||
def create_vlan_svi(self, nexus_host, vlan_id, gateway_ip):
|
|
||||||
confstr = snipp.CMD_VLAN_SVI_SNIPPET % (vlan_id, gateway_ip)
|
|
||||||
confstr = self.create_xml_snippet(confstr)
|
|
||||||
LOG.debug(_("NexusDriver: %s"), confstr)
|
|
||||||
self._edit_config(nexus_host, target='running', config=confstr)
|
|
||||||
|
|
||||||
def delete_vlan_svi(self, nexus_host, vlan_id):
|
|
||||||
confstr = snipp.CMD_NO_VLAN_SVI_SNIPPET % vlan_id
|
|
||||||
confstr = self.create_xml_snippet(confstr)
|
|
||||||
LOG.debug(_("NexusDriver: %s"), confstr)
|
|
||||||
self._edit_config(nexus_host, target='running', config=confstr)
|
|
||||||
|
@ -0,0 +1,75 @@
|
|||||||
|
# Copyright (c) 2014 Cisco 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.
|
||||||
|
|
||||||
|
import mock
|
||||||
|
from oslo.config import cfg
|
||||||
|
|
||||||
|
from neutron.common import config as neutron_config
|
||||||
|
from neutron.plugins.ml2.drivers.cisco.nexus import config as cisco_config
|
||||||
|
from neutron.tests import base
|
||||||
|
from neutron.tests.unit import test_api_v2
|
||||||
|
|
||||||
|
|
||||||
|
class TestCiscoNexusPluginConfig(base.BaseTestCase):
|
||||||
|
|
||||||
|
def setUp(self):
|
||||||
|
# Point neutron config file to: neutron/tests/etc/neutron.conf.test
|
||||||
|
args = ['--config-file', test_api_v2.etcdir('neutron.conf.test')]
|
||||||
|
neutron_config.parse(args=args)
|
||||||
|
super(TestCiscoNexusPluginConfig, self).setUp()
|
||||||
|
|
||||||
|
def test_config_parse_error(self):
|
||||||
|
"""Check that config error is raised upon config parser failure."""
|
||||||
|
with mock.patch.object(cfg, 'MultiConfigParser') as parser:
|
||||||
|
parser.return_value.read.return_value = []
|
||||||
|
self.assertRaises(cfg.Error, cisco_config.ML2MechCiscoConfig)
|
||||||
|
|
||||||
|
def test_create_device_dictionary(self):
|
||||||
|
"""Test creation of the device dictionary based on nexus config."""
|
||||||
|
test_config = {
|
||||||
|
'ml2_mech_cisco_nexus:1.1.1.1': {
|
||||||
|
'username': ['admin'],
|
||||||
|
'password': ['mySecretPassword'],
|
||||||
|
'ssh_port': [22],
|
||||||
|
'compute1': ['1/1'],
|
||||||
|
'compute2': ['1/2'],
|
||||||
|
},
|
||||||
|
'ml2_mech_cisco_nexus:2.2.2.2': {
|
||||||
|
'username': ['admin'],
|
||||||
|
'password': ['mySecretPassword'],
|
||||||
|
'ssh_port': [22],
|
||||||
|
'compute3': ['1/1'],
|
||||||
|
'compute4': ['1/2'],
|
||||||
|
},
|
||||||
|
}
|
||||||
|
expected_dev_dict = {
|
||||||
|
('1.1.1.1', 'username'): 'admin',
|
||||||
|
('1.1.1.1', 'password'): 'mySecretPassword',
|
||||||
|
('1.1.1.1', 'ssh_port'): 22,
|
||||||
|
('1.1.1.1', 'compute1'): '1/1',
|
||||||
|
('1.1.1.1', 'compute2'): '1/2',
|
||||||
|
('2.2.2.2', 'username'): 'admin',
|
||||||
|
('2.2.2.2', 'password'): 'mySecretPassword',
|
||||||
|
('2.2.2.2', 'ssh_port'): 22,
|
||||||
|
('2.2.2.2', 'compute3'): '1/1',
|
||||||
|
('2.2.2.2', 'compute4'): '1/2',
|
||||||
|
}
|
||||||
|
with mock.patch.object(cfg, 'MultiConfigParser') as parser:
|
||||||
|
parser.return_value.read.return_value = cfg.CONF.config_file
|
||||||
|
parser.return_value.parsed = [test_config]
|
||||||
|
cisco_config.ML2MechCiscoConfig()
|
||||||
|
self.assertEqual(expected_dev_dict,
|
||||||
|
cisco_config.ML2MechCiscoConfig.nexus_dict)
|
@ -152,6 +152,29 @@ class CiscoML2MechanismTestCase(test_db_plugin.NeutronDbPluginV2TestCase):
|
|||||||
config = {attr: None}
|
config = {attr: None}
|
||||||
self.mock_ncclient.configure_mock(**config)
|
self.mock_ncclient.configure_mock(**config)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def _config_dependent_side_effect(match_config, exc):
|
||||||
|
"""Generates a config-dependent side effect for ncclient edit_config.
|
||||||
|
|
||||||
|
This method generates a mock side-effect function which can be
|
||||||
|
configured on the mock ncclient module for the edit_config method.
|
||||||
|
This side effect will cause a given exception to be raised whenever
|
||||||
|
the XML config string that is passed to edit_config contains all
|
||||||
|
words in a given match config string.
|
||||||
|
|
||||||
|
:param match_config: String containing keywords to be matched
|
||||||
|
:param exc: Exception to be raised when match is found
|
||||||
|
:return: Side effect function for the mock ncclient module's
|
||||||
|
edit_config method.
|
||||||
|
|
||||||
|
"""
|
||||||
|
keywords = match_config.split()
|
||||||
|
|
||||||
|
def _side_effect_function(target, config):
|
||||||
|
if all(word in config for word in keywords):
|
||||||
|
raise exc
|
||||||
|
return _side_effect_function
|
||||||
|
|
||||||
def _is_in_nexus_cfg(self, words):
|
def _is_in_nexus_cfg(self, words):
|
||||||
"""Check if any config sent to Nexus contains all words in a list."""
|
"""Check if any config sent to Nexus contains all words in a list."""
|
||||||
for call in (self.mock_ncclient.connect.return_value.
|
for call in (self.mock_ncclient.connect.return_value.
|
||||||
@ -333,6 +356,35 @@ class TestCiscoPortsV2(CiscoML2MechanismTestCase,
|
|||||||
# Return to first segment for delete port calls.
|
# Return to first segment for delete port calls.
|
||||||
self.mock_bound_segment.return_value = BOUND_SEGMENT1
|
self.mock_bound_segment.return_value = BOUND_SEGMENT1
|
||||||
|
|
||||||
|
def test_nexus_add_trunk(self):
|
||||||
|
"""Verify syntax to enable a vlan on an interface.
|
||||||
|
|
||||||
|
Test also verifies that the vlan interface is not created.
|
||||||
|
|
||||||
|
Test of the following ml2_conf_cisco_ini config:
|
||||||
|
[ml2_mech_cisco_nexus:1.1.1.1]
|
||||||
|
hostA=1/1
|
||||||
|
hostB=1/2
|
||||||
|
where vlan_id = 100
|
||||||
|
|
||||||
|
Confirm that for the first host configured on a Nexus interface,
|
||||||
|
the command string sent to the switch does not contain the
|
||||||
|
keyword 'add'.
|
||||||
|
|
||||||
|
Confirm that for the second host configured on a Nexus interface,
|
||||||
|
the command staring sent to the switch contains does not contain
|
||||||
|
the keyword 'name' [signifies vlan intf creation].
|
||||||
|
|
||||||
|
"""
|
||||||
|
with self._create_resources(name='net1', cidr=CIDR_1):
|
||||||
|
self.assertTrue(self._is_in_last_nexus_cfg(['allowed', 'vlan']))
|
||||||
|
self.assertFalse(self._is_in_last_nexus_cfg(['add']))
|
||||||
|
with self._create_resources(name='net2',
|
||||||
|
cidr=CIDR_2, host_id=COMP_HOST_NAME_2):
|
||||||
|
self.assertTrue(
|
||||||
|
self._is_in_last_nexus_cfg(['allowed', 'vlan']))
|
||||||
|
self.assertFalse(self._is_in_last_nexus_cfg(['name']))
|
||||||
|
|
||||||
def test_nexus_connect_fail(self):
|
def test_nexus_connect_fail(self):
|
||||||
"""Test failure to connect to a Nexus switch.
|
"""Test failure to connect to a Nexus switch.
|
||||||
|
|
||||||
@ -505,16 +557,17 @@ class TestCiscoPortsV2(CiscoML2MechanismTestCase,
|
|||||||
for the extended VLAN range).
|
for the extended VLAN range).
|
||||||
|
|
||||||
"""
|
"""
|
||||||
def mock_edit_config(target, config):
|
vlan_state_configs = ['state active', 'no shutdown']
|
||||||
if all(word in config for word in ['state', 'active']):
|
for config in vlan_state_configs:
|
||||||
raise ValueError
|
|
||||||
with self._patch_ncclient(
|
with self._patch_ncclient(
|
||||||
'connect.return_value.edit_config.side_effect',
|
'connect.return_value.edit_config.side_effect',
|
||||||
mock_edit_config):
|
self._config_dependent_side_effect(config, ValueError)):
|
||||||
with self._create_resources() as result:
|
with self._create_resources() as result:
|
||||||
# Confirm that the last configuration sent to the Nexus
|
# Confirm that the last configuration sent to the Nexus
|
||||||
# switch was deletion of the VLAN.
|
# switch was deletion of the VLAN.
|
||||||
self.assertTrue(self._is_in_last_nexus_cfg(['<no>', '<vlan>']))
|
self.assertTrue(
|
||||||
|
self._is_in_last_nexus_cfg(['<no>', '<vlan>'])
|
||||||
|
)
|
||||||
self._assertExpectedHTTP(result.status_int,
|
self._assertExpectedHTTP(result.status_int,
|
||||||
c_exc.NexusConfigFailed)
|
c_exc.NexusConfigFailed)
|
||||||
|
|
||||||
|
@ -181,21 +181,6 @@ class CiscoNexusDbTest(base.BaseTestCase):
|
|||||||
npb = nexus_db_v2.get_port_switch_bindings(npb21.port, "dummySwitch")
|
npb = nexus_db_v2.get_port_switch_bindings(npb21.port, "dummySwitch")
|
||||||
self.assertIsNone(npb)
|
self.assertIsNone(npb)
|
||||||
|
|
||||||
def test_nexussvibinding_get(self):
|
|
||||||
"""Tests get of switch virtual interface port bindings."""
|
|
||||||
npbr1 = self._npb_test_obj('router', 100)
|
|
||||||
npb21 = self._npb_test_obj(20, 100)
|
|
||||||
self._add_bindings_to_db([npbr1, npb21])
|
|
||||||
|
|
||||||
npb_svi = nexus_db_v2.get_nexussvi_bindings()
|
|
||||||
self.assertEqual(len(npb_svi), 1)
|
|
||||||
self._assert_bindings_match(npb_svi[0], npbr1)
|
|
||||||
|
|
||||||
npbr2 = self._npb_test_obj('router', 200)
|
|
||||||
self._add_binding_to_db(npbr2)
|
|
||||||
npb_svi = nexus_db_v2.get_nexussvi_bindings()
|
|
||||||
self.assertEqual(len(npb_svi), 2)
|
|
||||||
|
|
||||||
def test_nexusbinding_update(self):
|
def test_nexusbinding_update(self):
|
||||||
"""Tests update of vlan IDs for port bindings."""
|
"""Tests update of vlan IDs for port bindings."""
|
||||||
npb11 = self._npb_test_obj(10, 100, switch='1.1.1.1', instance='test')
|
npb11 = self._npb_test_obj(10, 100, switch='1.1.1.1', instance='test')
|
||||||
|
Loading…
Reference in New Issue
Block a user