#
device_dictionary = {}
+#
+# first_device_ip - IP address of first switch discovered in config
+#
+# Used for SVI placement when round-robin placement is disabled
+#
+first_device_ip = None
+
class CiscoConfigOptions():
"""Cisco Configuration Options Class."""
device supported sections. Ex. NEXUS_SWITCH, N1KV.
"""
+ global first_device_ip
+
multi_parser = cfg.MultiConfigParser()
read_ok = multi_parser.read(CONF.config_file)
if len(read_ok) != len(CONF.config_file):
raise cfg.Error(_("Some config files were not parsed properly"))
+ first_device_ip = None
for parsed_file in multi_parser.parsed:
for parsed_item in parsed_file.keys():
dev_id, sep, dev_ip = parsed_item.partition(':')
if dev_id.lower() in ['nexus_switch', 'n1kv']:
for dev_key, value in parsed_file[parsed_item].items():
+ if dev_ip and not first_device_ip:
+ first_device_ip = dev_ip
device_dictionary[dev_id, dev_ip, dev_key] = value[0]
switch_dict[switch_ip] += 1
# Search for the lowest value in the dict
if switch_dict:
- switch_ip = min(switch_dict.items(), key=switch_dict.get)
- return switch_ip[0]
+ switch_ip = min(switch_dict, key=switch_dict.get)
+ return switch_ip
except cisco_exc.NexusPortBindingNotFound:
pass
LOG.debug(_("No round robin or zero weights, using first switch"))
# Return the first switch in the config
- for switch_ip, attr in nexus_switches:
- return switch_ip
+ return conf.first_device_ip
def delete_network(self, tenant_id, net_id, **kwargs):
"""Delete network.
# under the License.
import collections
+import mock
import testtools
from neutron.db import api as db
from neutron.plugins.cisco.common import cisco_exceptions as c_exc
+from neutron.plugins.cisco.common import config
from neutron.plugins.cisco.db import nexus_db_v2 as nxdb
+from neutron.plugins.cisco.nexus import cisco_nexus_plugin_v2
from neutron.tests import base
npb_svi = nxdb.get_nexussvi_bindings()
self.assertEqual(len(npb_svi), 2)
+ def test_nexussviswitch_find(self):
+ """Test Nexus switch selection for SVI placement."""
+ # Configure 2 Nexus switches
+ nexus_switches = {
+ ('1.1.1.1', 'username'): 'admin',
+ ('1.1.1.1', 'password'): 'password1',
+ ('1.1.1.1', 'host1'): '1/1',
+ ('2.2.2.2', 'username'): 'admin',
+ ('2.2.2.2', 'password'): 'password2',
+ ('2.2.2.2', 'host2'): '1/1',
+ }
+ nexus_plugin = cisco_nexus_plugin_v2.NexusPlugin()
+ nexus_plugin._client = mock.Mock()
+ nexus_plugin._client.nexus_switches = nexus_switches
+
+ # Set the Cisco config module's first configured device IP address
+ # according to the preceding switch config
+ with mock.patch.object(config, 'first_device_ip', new='1.1.1.1'):
+
+ # Enable round-robin mode with no SVIs configured on any of the
+ # Nexus switches (i.e. no entries in the SVI database). The
+ # plugin should select the first switch in the configuration.
+ config.CONF.set_override('svi_round_robin', True, 'CISCO')
+ switch_ip = nexus_plugin._find_switch_for_svi()
+ self.assertEqual(switch_ip, '1.1.1.1')
+
+ # Keep round-robin mode enabled, and add entries to the SVI
+ # database. The plugin should select the switch with the least
+ # number of entries in the SVI database.
+ vlan = 100
+ npbr11 = self._npb_test_obj('router', vlan, switch='1.1.1.1',
+ instance='instance11')
+ npbr12 = self._npb_test_obj('router', vlan, switch='1.1.1.1',
+ instance='instance12')
+ npbr21 = self._npb_test_obj('router', vlan, switch='2.2.2.2',
+ instance='instance21')
+ self._add_to_db([npbr11, npbr12, npbr21])
+ switch_ip = nexus_plugin._find_switch_for_svi()
+ self.assertEqual(switch_ip, '2.2.2.2')
+
+ # Disable round-robin mode. The plugin should select the
+ # first switch in the configuration.
+ config.CONF.clear_override('svi_round_robin', 'CISCO')
+ switch_ip = nexus_plugin._find_switch_for_svi()
+ self.assertEqual(switch_ip, '1.1.1.1')
+
def test_nexusbinding_update(self):
npb11 = self._npb_test_obj(10, 100, switch='1.1.1.1', instance='test')
npb21 = self._npb_test_obj(20, 100, switch='1.1.1.1', instance='test')
from neutron.openstack.common import importutils
from neutron.plugins.cisco.common import cisco_constants as const
from neutron.plugins.cisco.common import cisco_exceptions as cisco_exc
+from neutron.plugins.cisco.common import config as cisco_config
from neutron.plugins.cisco.db import network_db_v2 as cdb
from neutron.plugins.cisco.nexus import cisco_nexus_plugin_v2
from neutron.tests import base
self.patch_obj = mock.patch.dict('sys.modules',
{'ncclient': self.mock_ncclient})
self.patch_obj.start()
+ self.addCleanup(self.patch_obj.stop)
with mock.patch.object(cisco_nexus_plugin_v2.NexusPlugin,
'__init__', new=new_nexus_init):
self._cisco_nexus_plugin = cisco_nexus_plugin_v2.NexusPlugin()
- self.addCleanup(self.patch_obj.stop)
+ # Set the Cisco config module's first configured device IP address
+ # according to the preceding switch config.
+ mock.patch.object(cisco_config, 'first_device_ip',
+ new=NEXUS_IP_ADDRESS).start()
+ self.addCleanup(mock.patch.stopall)
def test_create_delete_networks(self):
"""Tests creation of two new Virtual Networks."""