Make add_tap_interface resillient to removal

This patch makes add_tap_interface safe to race conditions
where the interface is removed in the middle of processing
by catching exceptions and checking to see if the interface
still exists. If it no longer exists it assumes the exception
was caused by the missing interface and returns False as it
would if the interface did not exist to begin with.

Change-Id: Ie0d89fc2584490b6985aee66da70bae027a130ed
Closes-bug: #1542972
This commit is contained in:
Mr. Bojangles 2016-02-07 21:57:00 -07:00 committed by Mr. Bojangles
parent df4966081a
commit 59d815c704
2 changed files with 33 additions and 0 deletions

View File

@ -407,6 +407,22 @@ class LinuxBridgeManager(amb.CommonAgentManagerBase):
def add_tap_interface(self, network_id, network_type, physical_network,
segmentation_id, tap_device_name, device_owner):
"""Add tap interface and handle interface missing exeptions."""
try:
return self._add_tap_interface(network_id, network_type,
physical_network, segmentation_id,
tap_device_name, device_owner)
except Exception:
with excutils.save_and_reraise_exception() as ctx:
if not ip_lib.device_exists(tap_device_name):
# the exception was likely a side effect of the tap device
# being removed during handling so we just return false
# like we would if it didn't exist to begin with.
ctx.reraise = False
return False
def _add_tap_interface(self, network_id, network_type, physical_network,
segmentation_id, tap_device_name, device_owner):
"""Add tap interface.
If a VIF has been plugged into a network, this function will

View File

@ -909,6 +909,23 @@ class TestLinuxBridgeManager(base.BaseTestCase):
"physnet9", "1")
self.assertEqual(1, log.call_count)
@mock.patch.object(ip_lib, "device_exists", return_value=False)
def test_add_tap_interface_with_interface_disappearing(self, exists):
with mock.patch.object(self.lbm, "_add_tap_interface",
side_effect=RuntimeError("No such dev")):
self.assertFalse(self.lbm.add_tap_interface("123",
p_const.TYPE_VLAN,
"physnet1", None,
"tap1", "foo"))
@mock.patch.object(ip_lib, "device_exists", return_value=True)
def test_add_tap_interface_with_other_error(self, exists):
with mock.patch.object(self.lbm, "_add_tap_interface",
side_effect=RuntimeError("No more fuel")):
self.assertRaises(RuntimeError, self.lbm.add_tap_interface, "123",
p_const.TYPE_VLAN, "physnet1", None, "tap1",
"foo")
def test_add_tap_interface_owner_other(self):
with mock.patch.object(ip_lib, "device_exists"):
with mock.patch.object(self.lbm, "ensure_local_bridge"):