From c3d789d659840a3e0ddf78a5523d535866a98657 Mon Sep 17 00:00:00 2001 From: Jason Zhang Date: Thu, 6 Dec 2012 11:39:34 -0800 Subject: [PATCH] Setup device alias by device flavor information. The router interface cannot be deleted since the MetaPlugin cannot get the flavor information from the port which has been deleted. The solution is setting up the alias for each device based on the flavor information, so the MetaPlugin still can get the flavor information from the device itself even the port has been deleted. Also the router interface cannot be deleted since the l3_port_check flag is not passed by MetaPlugin. Fixes: bug #1085276 Change-Id: I670aa45c804e660ee4afb5359e0ab1347f369986 --- quantum/agent/linux/interface.py | 31 ++++++++------ quantum/agent/linux/ip_lib.py | 7 ++++ .../plugins/metaplugin/meta_quantum_plugin.py | 2 +- quantum/tests/unit/test_linux_interface.py | 42 ++++++++++++++----- quantum/tests/unit/test_linux_ip_lib.py | 14 ++++++- 5 files changed, 70 insertions(+), 26 deletions(-) diff --git a/quantum/agent/linux/interface.py b/quantum/agent/linux/interface.py index 21a251a0d..496f09054 100644 --- a/quantum/agent/linux/interface.py +++ b/quantum/agent/linux/interface.py @@ -265,18 +265,22 @@ class MetaInterfaceDriver(LinuxInterfaceDriver): self.conf.meta_flavor_driver_mappings.split(',')]: self.flavor_driver_map[flavor] = self._load_driver(driver_name) - def _get_driver_by_network_id(self, network_id): + def _get_flavor_by_network_id(self, network_id): network = self.quantum.show_network(network_id) - flavor = network['network'][FLAVOR_NETWORK] + return network['network'][FLAVOR_NETWORK] + + def _get_driver_by_network_id(self, network_id): + flavor = self._get_flavor_by_network_id(network_id) return self.flavor_driver_map[flavor] - def _get_driver_by_device_name(self, device_name, namespace=None): - device = ip_lib.IPDevice(device_name, self.root_helper, namespace) - mac_address = device.link.address - ports = self.quantum.list_ports(mac_address=mac_address) - if not ports.get('ports'): - raise Exception(_('No port for this device %s') % device_name) - return self._get_driver_by_network_id(ports['ports'][0]['network_id']) + def _set_device_plugin_tag(self, network_id, device_name, namespace=None): + plugin_tag = self._get_flavor_by_network_id(network_id) + device = ip_lib.IPDevice(device_name, self.conf.root_helper, namespace) + device.link.set_alias(plugin_tag) + + def _get_device_plugin_tag(self, device_name, namespace=None): + device = ip_lib.IPDevice(device_name, self.conf.root_helper, namespace) + return device.link.alias def get_device_name(self, port): driver = self._get_driver_by_network_id(port.network_id) @@ -285,11 +289,14 @@ class MetaInterfaceDriver(LinuxInterfaceDriver): def plug(self, network_id, port_id, device_name, mac_address, bridge=None, namespace=None, prefix=None): driver = self._get_driver_by_network_id(network_id) - return driver.plug(network_id, port_id, device_name, mac_address, - bridge=bridge, namespace=namespace, prefix=prefix) + ret = driver.plug(network_id, port_id, device_name, mac_address, + bridge=bridge, namespace=namespace, prefix=prefix) + self._set_device_plugin_tag(network_id, device_name, namespace) + return ret def unplug(self, device_name, bridge=None, namespace=None, prefix=None): - driver = self._get_driver_by_device_name(device_name, namespace=None) + plugin_tag = self._get_device_plugin_tag(device_name, namespace) + driver = self.flavor_driver_map[plugin_tag] return driver.unplug(device_name, bridge, namespace, prefix) def _load_driver(self, driver_provider): diff --git a/quantum/agent/linux/ip_lib.py b/quantum/agent/linux/ip_lib.py index 31337087e..1f618c3f9 100644 --- a/quantum/agent/linux/ip_lib.py +++ b/quantum/agent/linux/ip_lib.py @@ -189,6 +189,9 @@ class IpLinkCommand(IpDeviceCommandBase): self._as_root('set', self.name, 'name', name) self._parent.name = name + def set_alias(self, alias_name): + self._as_root('set', self.name, 'alias', alias_name) + def delete(self): self._as_root('delete', self.name) @@ -212,6 +215,10 @@ class IpLinkCommand(IpDeviceCommandBase): def qlen(self): return self.attributes.get('qlen') + @property + def alias(self): + return self.attributes.get('alias') + @property def attributes(self): return self._parse_line(self._run('show', self.name, options='o')) diff --git a/quantum/plugins/metaplugin/meta_quantum_plugin.py b/quantum/plugins/metaplugin/meta_quantum_plugin.py index 7ec3ffe8f..3c9cde6e6 100644 --- a/quantum/plugins/metaplugin/meta_quantum_plugin.py +++ b/quantum/plugins/metaplugin/meta_quantum_plugin.py @@ -258,7 +258,7 @@ class MetaPluginV2(db_base_plugin_v2.QuantumDbPluginV2, if l3_port_check: self.prevent_l3_port_deletion(context, id) self.disassociate_floatingips(context, id) - return plugin.delete_port(context, id) + return plugin.delete_port(context, id, l3_port_check) def create_subnet(self, context, subnet): s = subnet['subnet'] diff --git a/quantum/tests/unit/test_linux_interface.py b/quantum/tests/unit/test_linux_interface.py index 9e3ed5262..f1c60f23b 100644 --- a/quantum/tests/unit/test_linux_interface.py +++ b/quantum/tests/unit/test_linux_interface.py @@ -380,15 +380,35 @@ class TestMetaInterfaceDriver(TestBase): driver, interface.OVSInterfaceDriver)) - def test_get_driver_by_device_name(self): - device_address_p = mock.patch( - 'quantum.agent.linux.ip_lib.IpLinkCommand.address') - device_address = device_address_p.start() - device_address.return_value = 'aa:bb:cc:dd:ee:ffa' - + def test_set_device_plugin_tag(self): meta_interface = interface.MetaInterfaceDriver(self.conf) - driver = meta_interface._get_driver_by_device_name('test') - self.assertTrue(isinstance( - driver, - interface.OVSInterfaceDriver)) - device_address_p.stop() + driver = meta_interface._get_driver_by_network_id('test') + meta_interface._set_device_plugin_tag(driver, + 'tap0', + namespace=None) + expected = [mock.call('tap0', 'sudo', None), + mock.call().link.set_alias('fake1')] + self.ip_dev.assert_has_calls(expected) + namespace = '01234567-1234-1234-99' + meta_interface._set_device_plugin_tag(driver, + 'tap1', + namespace=namespace) + expected = [mock.call('tap1', 'sudo', '01234567-1234-1234-99'), + mock.call().link.set_alias('fake1')] + self.ip_dev.assert_has_calls(expected) + + def test_get_device_plugin_tag(self): + meta_interface = interface.MetaInterfaceDriver(self.conf) + self.ip_dev().link.alias = 'fake1' + plugin_tag0 = meta_interface._get_device_plugin_tag('tap0', + namespace=None) + expected = [mock.call('tap0', 'sudo', None)] + self.ip_dev.assert_has_calls(expected) + self.assertEquals('fake1', plugin_tag0) + namespace = '01234567-1234-1234-99' + expected = [mock.call('tap1', 'sudo', '01234567-1234-1234-99')] + plugin_tag1 = meta_interface._get_device_plugin_tag( + 'tap1', + namespace=namespace) + self.ip_dev.assert_has_calls(expected) + self.assertEquals('fake1', plugin_tag1) diff --git a/quantum/tests/unit/test_linux_ip_lib.py b/quantum/tests/unit/test_linux_ip_lib.py index cc54ff23c..9d97a3a09 100644 --- a/quantum/tests/unit/test_linux_ip_lib.py +++ b/quantum/tests/unit/test_linux_ip_lib.py @@ -30,7 +30,8 @@ LINK_SAMPLE = [ '1: lo: mtu 16436 qdisc noqueue state UNKNOWN \\' 'link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00', '2: eth0: mtu 1500 qdisc mq state UP ' - 'qlen 1000\ link/ether cc:dd:ee:ff:ab:cd brd ff:ff:ff:ff:ff:ff', + 'qlen 1000\ link/ether cc:dd:ee:ff:ab:cd brd ff:ff:ff:ff:ff:ff' + '\ alias openvswitch', '3: br-int: mtu 1500 qdisc noop state DOWN ' '\ link/ether aa:bb:cc:dd:ee:ff brd ff:ff:ff:ff:ff:ff', '4: gw-ddc717df-49: mtu 1500 qdisc noop ' @@ -426,6 +427,10 @@ class TestIpLinkCommand(TestIPCmdBase): self._assert_sudo([], ('set', 'eth0', 'name', 'tap1')) self.assertEqual(self.parent.name, 'tap1') + def test_set_alias(self): + self.link_cmd.set_alias('openvswitch') + self._assert_sudo([], ('set', 'eth0', 'alias', 'openvswitch')) + def test_delete(self): self.link_cmd.delete() self._assert_sudo([], ('delete', 'eth0')) @@ -446,6 +451,10 @@ class TestIpLinkCommand(TestIPCmdBase): self.parent._execute = mock.Mock(return_value=LINK_SAMPLE[1]) self.assertEqual(self.link_cmd.qlen, 1000) + def test_alias_property(self): + self.parent._execute = mock.Mock(return_value=LINK_SAMPLE[1]) + self.assertEqual(self.link_cmd.alias, 'openvswitch') + def test_state_property(self): self.parent._execute = mock.Mock(return_value=LINK_SAMPLE[1]) self.assertEqual(self.link_cmd.state, 'UP') @@ -456,7 +465,8 @@ class TestIpLinkCommand(TestIPCmdBase): 'state': 'UP', 'qdisc': 'mq', 'brd': 'ff:ff:ff:ff:ff:ff', - 'link/ether': 'cc:dd:ee:ff:ab:cd'} + 'link/ether': 'cc:dd:ee:ff:ab:cd', + 'alias': 'openvswitch'} self.parent._execute = mock.Mock(return_value=LINK_SAMPLE[1]) self.assertEqual(self.link_cmd.attributes, expected) self._assert_call('o', ('show', 'eth0')) -- 2.45.2