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
This commit is contained in:
Jason Zhang 2012-12-06 11:39:34 -08:00
parent dee13cdc14
commit 53ebb63410
5 changed files with 70 additions and 26 deletions

View File

@ -265,18 +265,22 @@ class MetaInterfaceDriver(LinuxInterfaceDriver):
self.conf.meta_flavor_driver_mappings.split(',')]: self.conf.meta_flavor_driver_mappings.split(',')]:
self.flavor_driver_map[flavor] = self._load_driver(driver_name) 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) 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] return self.flavor_driver_map[flavor]
def _get_driver_by_device_name(self, device_name, namespace=None): def _set_device_plugin_tag(self, network_id, device_name, namespace=None):
device = ip_lib.IPDevice(device_name, self.root_helper, namespace) plugin_tag = self._get_flavor_by_network_id(network_id)
mac_address = device.link.address device = ip_lib.IPDevice(device_name, self.conf.root_helper, namespace)
ports = self.quantum.list_ports(mac_address=mac_address) device.link.set_alias(plugin_tag)
if not ports.get('ports'):
raise Exception(_('No port for this device %s') % device_name) def _get_device_plugin_tag(self, device_name, namespace=None):
return self._get_driver_by_network_id(ports['ports'][0]['network_id']) device = ip_lib.IPDevice(device_name, self.conf.root_helper, namespace)
return device.link.alias
def get_device_name(self, port): def get_device_name(self, port):
driver = self._get_driver_by_network_id(port.network_id) 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, def plug(self, network_id, port_id, device_name, mac_address,
bridge=None, namespace=None, prefix=None): bridge=None, namespace=None, prefix=None):
driver = self._get_driver_by_network_id(network_id) driver = self._get_driver_by_network_id(network_id)
return driver.plug(network_id, port_id, device_name, mac_address, ret = driver.plug(network_id, port_id, device_name, mac_address,
bridge=bridge, namespace=namespace, prefix=prefix) 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): 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) return driver.unplug(device_name, bridge, namespace, prefix)
def _load_driver(self, driver_provider): def _load_driver(self, driver_provider):

View File

@ -189,6 +189,9 @@ class IpLinkCommand(IpDeviceCommandBase):
self._as_root('set', self.name, 'name', name) self._as_root('set', self.name, 'name', name)
self._parent.name = name self._parent.name = name
def set_alias(self, alias_name):
self._as_root('set', self.name, 'alias', alias_name)
def delete(self): def delete(self):
self._as_root('delete', self.name) self._as_root('delete', self.name)
@ -212,6 +215,10 @@ class IpLinkCommand(IpDeviceCommandBase):
def qlen(self): def qlen(self):
return self.attributes.get('qlen') return self.attributes.get('qlen')
@property
def alias(self):
return self.attributes.get('alias')
@property @property
def attributes(self): def attributes(self):
return self._parse_line(self._run('show', self.name, options='o')) return self._parse_line(self._run('show', self.name, options='o'))

View File

@ -258,7 +258,7 @@ class MetaPluginV2(db_base_plugin_v2.QuantumDbPluginV2,
if l3_port_check: if l3_port_check:
self.prevent_l3_port_deletion(context, id) self.prevent_l3_port_deletion(context, id)
self.disassociate_floatingips(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): def create_subnet(self, context, subnet):
s = subnet['subnet'] s = subnet['subnet']

View File

@ -380,15 +380,35 @@ class TestMetaInterfaceDriver(TestBase):
driver, driver,
interface.OVSInterfaceDriver)) interface.OVSInterfaceDriver))
def test_get_driver_by_device_name(self): def test_set_device_plugin_tag(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'
meta_interface = interface.MetaInterfaceDriver(self.conf) meta_interface = interface.MetaInterfaceDriver(self.conf)
driver = meta_interface._get_driver_by_device_name('test') driver = meta_interface._get_driver_by_network_id('test')
self.assertTrue(isinstance( meta_interface._set_device_plugin_tag(driver,
driver, 'tap0',
interface.OVSInterfaceDriver)) namespace=None)
device_address_p.stop() 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)

View File

@ -30,7 +30,8 @@ LINK_SAMPLE = [
'1: lo: <LOOPBACK,UP,LOWER_UP> mtu 16436 qdisc noqueue state UNKNOWN \\' '1: lo: <LOOPBACK,UP,LOWER_UP> mtu 16436 qdisc noqueue state UNKNOWN \\'
'link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00', 'link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00',
'2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq state UP ' '2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> 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: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN ' '3: br-int: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN '
'\ link/ether aa:bb:cc:dd:ee:ff brd ff:ff:ff:ff:ff:ff', '\ link/ether aa:bb:cc:dd:ee:ff brd ff:ff:ff:ff:ff:ff',
'4: gw-ddc717df-49: <BROADCAST,MULTICAST> mtu 1500 qdisc noop ' '4: gw-ddc717df-49: <BROADCAST,MULTICAST> mtu 1500 qdisc noop '
@ -426,6 +427,10 @@ class TestIpLinkCommand(TestIPCmdBase):
self._assert_sudo([], ('set', 'eth0', 'name', 'tap1')) self._assert_sudo([], ('set', 'eth0', 'name', 'tap1'))
self.assertEqual(self.parent.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): def test_delete(self):
self.link_cmd.delete() self.link_cmd.delete()
self._assert_sudo([], ('delete', 'eth0')) self._assert_sudo([], ('delete', 'eth0'))
@ -446,6 +451,10 @@ class TestIpLinkCommand(TestIPCmdBase):
self.parent._execute = mock.Mock(return_value=LINK_SAMPLE[1]) self.parent._execute = mock.Mock(return_value=LINK_SAMPLE[1])
self.assertEqual(self.link_cmd.qlen, 1000) 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): def test_state_property(self):
self.parent._execute = mock.Mock(return_value=LINK_SAMPLE[1]) self.parent._execute = mock.Mock(return_value=LINK_SAMPLE[1])
self.assertEqual(self.link_cmd.state, 'UP') self.assertEqual(self.link_cmd.state, 'UP')
@ -456,7 +465,8 @@ class TestIpLinkCommand(TestIPCmdBase):
'state': 'UP', 'state': 'UP',
'qdisc': 'mq', 'qdisc': 'mq',
'brd': 'ff:ff:ff:ff:ff:ff', '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.parent._execute = mock.Mock(return_value=LINK_SAMPLE[1])
self.assertEqual(self.link_cmd.attributes, expected) self.assertEqual(self.link_cmd.attributes, expected)
self._assert_call('o', ('show', 'eth0')) self._assert_call('o', ('show', 'eth0'))