Merge "Change nexus_dict to accept port lists"

This commit is contained in:
Jenkins 2014-08-29 11:13:10 +00:00 committed by Gerrit Code Review
commit 2ffcb79117
3 changed files with 72 additions and 26 deletions

View File

@ -66,12 +66,13 @@ class CiscoNexusMechanismDriver(api.MechanismDriver):
host_connections = [] host_connections = []
for switch_ip, attr in self._nexus_switches: for switch_ip, attr in self._nexus_switches:
if str(attr) == str(host_id): if str(attr) == str(host_id):
port_id = self._nexus_switches[switch_ip, attr] for port_id in (
if ':' in port_id: self._nexus_switches[switch_ip, attr].split(',')):
intf_type, port = port_id.split(':') if ':' in port_id:
else: intf_type, port = port_id.split(':')
intf_type, port = 'ethernet', port_id else:
host_connections.append((switch_ip, intf_type, port)) intf_type, port = 'ethernet', port_id
host_connections.append((switch_ip, intf_type, port))
if host_connections: if host_connections:
return host_connections return host_connections
@ -100,18 +101,30 @@ class CiscoNexusMechanismDriver(api.MechanismDriver):
vlan_name = cfg.CONF.ml2_cisco.vlan_name_prefix + str(vlan_id) vlan_name = cfg.CONF.ml2_cisco.vlan_name_prefix + str(vlan_id)
host_connections = self._get_switch_info(host_id) host_connections = self._get_switch_info(host_id)
# (nexus_port,switch_ip) will be unique in each iteration.
# But switch_ip will repeat if host has >1 connection to same switch.
# So track which switch_ips already have vlan created in this loop.
vlan_already_created = []
for switch_ip, intf_type, nexus_port in host_connections: for switch_ip, intf_type, nexus_port in host_connections:
# Check to see if this is the first binding to use this vlan on the
# switch/port. Configure switch accordingly. # The VLAN needs to be created on the switch if no other
bindings = nxos_db.get_nexusvlan_binding(vlan_id, switch_ip) # instance has been placed in this VLAN on a different host
if len(bindings) == 1: # attached to this switch. Search the existing bindings in the
LOG.debug(_("Nexus: create & trunk vlan %s"), vlan_name) # database. If all the instance_id in the database match the
self.driver.create_and_trunk_vlan( # current device_id, then create the VLAN, but only once per
switch_ip, vlan_id, vlan_name, intf_type, nexus_port) # switch_ip. Otherwise, just trunk.
else: all_bindings = nxos_db.get_nexusvlan_binding(vlan_id, switch_ip)
LOG.debug(_("Nexus: trunk vlan %s"), vlan_name) previous_bindings = [row for row in all_bindings
if row.instance_id != device_id]
if previous_bindings or (switch_ip in vlan_already_created):
LOG.debug("Nexus: trunk vlan %s"), vlan_name
self.driver.enable_vlan_on_trunk_int(switch_ip, vlan_id, self.driver.enable_vlan_on_trunk_int(switch_ip, vlan_id,
intf_type, nexus_port) intf_type, nexus_port)
else:
vlan_already_created.append(switch_ip)
LOG.debug("Nexus: create & trunk vlan %s"), vlan_name
self.driver.create_and_trunk_vlan(
switch_ip, vlan_id, vlan_name, intf_type, nexus_port)
def _delete_nxos_db(self, vlan_id, device_id, host_id): def _delete_nxos_db(self, vlan_id, device_id, host_id):
"""Delete the nexus database entry. """Delete the nexus database entry.
@ -135,7 +148,13 @@ class CiscoNexusMechanismDriver(api.MechanismDriver):
Called during update postcommit port event. Called during update postcommit port event.
""" """
host_connections = self._get_switch_info(host_id) host_connections = self._get_switch_info(host_id)
# (nexus_port,switch_ip) will be unique in each iteration.
# But switch_ip will repeat if host has >1 connection to same switch.
# So track which switch_ips already have vlan removed in this loop.
vlan_already_removed = []
for switch_ip, intf_type, nexus_port in host_connections: for switch_ip, intf_type, nexus_port in host_connections:
# if there are no remaining db entries using this vlan on this # if there are no remaining db entries using this vlan on this
# nexus switch port then remove vlan from the switchport trunk. # nexus switch port then remove vlan from the switchport trunk.
port_id = '%s:%s' % (intf_type, nexus_port) port_id = '%s:%s' % (intf_type, nexus_port)
@ -151,7 +170,11 @@ class CiscoNexusMechanismDriver(api.MechanismDriver):
try: try:
nxos_db.get_nexusvlan_binding(vlan_id, switch_ip) nxos_db.get_nexusvlan_binding(vlan_id, switch_ip)
except excep.NexusPortBindingNotFound: except excep.NexusPortBindingNotFound:
self.driver.delete_vlan(switch_ip, vlan_id)
# Do not perform a second time on same switch
if switch_ip not in vlan_already_removed:
self.driver.delete_vlan(switch_ip, vlan_id)
vlan_already_removed.append(switch_ip)
def _is_vm_migration(self, context): def _is_vm_migration(self, context):
if not context.bound_segment and context.original_bound_segment: if not context.bound_segment and context.original_bound_segment:

View File

@ -42,6 +42,7 @@ class TestCiscoNexusPluginConfig(base.BaseTestCase):
'ssh_port': [22], 'ssh_port': [22],
'compute1': ['1/1'], 'compute1': ['1/1'],
'compute2': ['1/2'], 'compute2': ['1/2'],
'compute5': ['1/3,1/4']
}, },
'ml2_mech_cisco_nexus:2.2.2.2': { 'ml2_mech_cisco_nexus:2.2.2.2': {
'username': ['admin'], 'username': ['admin'],
@ -49,6 +50,7 @@ class TestCiscoNexusPluginConfig(base.BaseTestCase):
'ssh_port': [22], 'ssh_port': [22],
'compute3': ['1/1'], 'compute3': ['1/1'],
'compute4': ['1/2'], 'compute4': ['1/2'],
'compute5': ['portchannel:20,portchannel:30']
}, },
} }
expected_dev_dict = { expected_dev_dict = {
@ -57,11 +59,13 @@ class TestCiscoNexusPluginConfig(base.BaseTestCase):
('1.1.1.1', 'ssh_port'): 22, ('1.1.1.1', 'ssh_port'): 22,
('1.1.1.1', 'compute1'): '1/1', ('1.1.1.1', 'compute1'): '1/1',
('1.1.1.1', 'compute2'): '1/2', ('1.1.1.1', 'compute2'): '1/2',
('1.1.1.1', 'compute5'): '1/3,1/4',
('2.2.2.2', 'username'): 'admin', ('2.2.2.2', 'username'): 'admin',
('2.2.2.2', 'password'): 'mySecretPassword', ('2.2.2.2', 'password'): 'mySecretPassword',
('2.2.2.2', 'ssh_port'): 22, ('2.2.2.2', 'ssh_port'): 22,
('2.2.2.2', 'compute3'): '1/1', ('2.2.2.2', 'compute3'): '1/1',
('2.2.2.2', 'compute4'): '1/2', ('2.2.2.2', 'compute4'): '1/2',
('2.2.2.2', 'compute5'): 'portchannel:20,portchannel:30',
} }
with mock.patch.object(cfg, 'MultiConfigParser') as parser: with mock.patch.object(cfg, 'MultiConfigParser') as parser:
parser.return_value.read.return_value = cfg.CONF.config_file parser.return_value.read.return_value = cfg.CONF.config_file

View File

@ -31,18 +31,23 @@ from neutron.tests.unit import testlib_api
NEXUS_IP_ADDRESS = '1.1.1.1' NEXUS_IP_ADDRESS = '1.1.1.1'
NEXUS_IP_ADDRESS_PC = '2.2.2.2' NEXUS_IP_ADDRESS_PC = '2.2.2.2'
NEXUS_IP_ADDRESS_DUAL = '3.3.3.3'
HOST_NAME_1 = 'testhost1' HOST_NAME_1 = 'testhost1'
HOST_NAME_2 = 'testhost2' HOST_NAME_2 = 'testhost2'
HOST_NAME_PC = 'testpchost' HOST_NAME_PC = 'testpchost'
HOST_NAME_DUAL = 'testdualhost'
INSTANCE_1 = 'testvm1' INSTANCE_1 = 'testvm1'
INSTANCE_2 = 'testvm2' INSTANCE_2 = 'testvm2'
INSTANCE_PC = 'testpcvm' INSTANCE_PC = 'testpcvm'
INSTANCE_DUAL = 'testdualvm'
NEXUS_PORT_1 = 'ethernet:1/10' NEXUS_PORT_1 = 'ethernet:1/10'
NEXUS_PORT_2 = 'ethernet:1/20' NEXUS_PORT_2 = 'ethernet:1/20'
NEXUS_PORTCHANNELS = 'portchannel:2' NEXUS_PORTCHANNELS = 'portchannel:2'
NEXUS_DUAL = 'ethernet:1/3,portchannel:2'
VLAN_ID_1 = 267 VLAN_ID_1 = 267
VLAN_ID_2 = 265 VLAN_ID_2 = 265
VLAN_ID_PC = 268 VLAN_ID_PC = 268
VLAN_ID_DUAL = 269
DEVICE_OWNER = 'compute:test' DEVICE_OWNER = 'compute:test'
NEXUS_SSH_PORT = '22' NEXUS_SSH_PORT = '22'
PORT_STATE = n_const.PORT_STATUS_ACTIVE PORT_STATE = n_const.PORT_STATUS_ACTIVE
@ -119,6 +124,12 @@ class TestCiscoNexusDevice(testlib_api.SqlTestCase):
NEXUS_PORTCHANNELS, NEXUS_PORTCHANNELS,
INSTANCE_PC, INSTANCE_PC,
VLAN_ID_PC), VLAN_ID_PC),
'test_config_dual': TestConfigObj(
NEXUS_IP_ADDRESS_DUAL,
HOST_NAME_DUAL,
NEXUS_DUAL,
INSTANCE_DUAL,
VLAN_ID_DUAL),
} }
def setUp(self): def setUp(self):
@ -169,19 +180,22 @@ class TestCiscoNexusDevice(testlib_api.SqlTestCase):
self._cisco_mech_driver.update_port_precommit(port_context) self._cisco_mech_driver.update_port_precommit(port_context)
self._cisco_mech_driver.update_port_postcommit(port_context) self._cisco_mech_driver.update_port_postcommit(port_context)
bindings = nexus_db_v2.get_nexusport_binding(nexus_port, for port_id in nexus_port.split(','):
vlan_id, bindings = nexus_db_v2.get_nexusport_binding(port_id,
nexus_ip_addr, vlan_id,
instance_id) nexus_ip_addr,
self.assertEqual(len(bindings), 1) instance_id)
self.assertEqual(len(bindings), 1)
self._cisco_mech_driver.delete_port_precommit(port_context) self._cisco_mech_driver.delete_port_precommit(port_context)
self._cisco_mech_driver.delete_port_postcommit(port_context) self._cisco_mech_driver.delete_port_postcommit(port_context)
with testtools.ExpectedException(exceptions.NexusPortBindingNotFound): for port_id in nexus_port.split(','):
nexus_db_v2.get_nexusport_binding(nexus_port, with testtools.ExpectedException(
vlan_id, exceptions.NexusPortBindingNotFound):
nexus_ip_addr, nexus_db_v2.get_nexusport_binding(port_id,
instance_id) vlan_id,
nexus_ip_addr,
instance_id)
def test_create_delete_ports(self): def test_create_delete_ports(self):
"""Tests creation and deletion of two new virtual Ports.""" """Tests creation and deletion of two new virtual Ports."""
@ -195,3 +209,8 @@ class TestCiscoNexusDevice(testlib_api.SqlTestCase):
"""Tests creation of a port over a portchannel.""" """Tests creation of a port over a portchannel."""
self._create_delete_port( self._create_delete_port(
TestCiscoNexusDevice.test_configs['test_config_portchannel']) TestCiscoNexusDevice.test_configs['test_config_portchannel'])
def test_create_delete_dual(self):
"""Tests creation and deletion of dual ports for single server"""
self._create_delete_port(
TestCiscoNexusDevice.test_configs['test_config_dual'])