Skip to content

Commit cb95a5a

Browse files
Zuulopenstack-gerrit
authored andcommitted
Merge "Catch non-existent entry failures better in ip_lib" into stable/yoga
2 parents 8bdd9b4 + 2f7ecb9 commit cb95a5a

File tree

4 files changed

+92
-29
lines changed

4 files changed

+92
-29
lines changed

neutron/privileged/agent/linux/ip_lib.py

Lines changed: 22 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -474,6 +474,10 @@ def delete_neigh_entry(ip_version, ip_address, mac_address, device, namespace,
474474
if e.code == errno.ENOENT:
475475
return
476476
raise
477+
except OSError as e:
478+
if e.errno == errno.ENOENT:
479+
raise NetworkNamespaceNotFound(netns_name=namespace)
480+
raise
477481

478482

479483
@tenacity.retry(
@@ -683,6 +687,11 @@ def delete_ip_rule(namespace, **kwargs):
683687
try:
684688
with get_iproute(namespace) as ip:
685689
ip.rule('del', **kwargs)
690+
except netlink_exceptions.NetlinkError as e:
691+
# trying to delete a non-existent entry shouldn't raise an error
692+
if e.code == errno.ENOENT:
693+
return
694+
raise
686695
except OSError as e:
687696
if e.errno == errno.ENOENT:
688697
raise NetworkNamespaceNotFound(netns_name=namespace)
@@ -785,6 +794,11 @@ def delete_ip_route(namespace, cidr, ip_version, device=None, via=None,
785794
try:
786795
with get_iproute(namespace) as ip:
787796
ip.route('del', **kwargs)
797+
except netlink_exceptions.NetlinkError as e:
798+
# trying to delete a non-existent entry shouldn't raise an error
799+
if e.code == errno.ESRCH:
800+
return
801+
raise
788802
except OSError as e:
789803
if e.errno == errno.ENOENT:
790804
raise NetworkNamespaceNotFound(netns_name=namespace)
@@ -819,6 +833,11 @@ def _command_bridge_fdb(command, mac, device, dst_ip=None, namespace=None,
819833
kwargs['dst'] = dst_ip
820834
with get_iproute(namespace) as ip:
821835
return make_serializable(ip.fdb(command, **kwargs))
836+
except netlink_exceptions.NetlinkError as e:
837+
# trying to delete a non-existent entry shouldn't raise an error
838+
if command == 'del' and e.code == errno.ENOENT:
839+
return
840+
raise
822841
except OSError as e:
823842
if e.errno == errno.ENOENT:
824843
raise NetworkNamespaceNotFound(netns_name=namespace)
@@ -834,20 +853,20 @@ def add_bridge_fdb(mac, device, dst_ip=None, namespace=None, **kwargs):
834853

835854
@privileged.default.entrypoint
836855
def append_bridge_fdb(mac, device, dst_ip=None, namespace=None, **kwargs):
837-
"""Add a FDB entry"""
856+
"""Append a FDB entry"""
838857
return _command_bridge_fdb('append', mac, device, dst_ip=dst_ip,
839858
namespace=namespace, **kwargs)
840859

841860

842861
@privileged.default.entrypoint
843862
def replace_bridge_fdb(mac, device, dst_ip=None, namespace=None, **kwargs):
844-
"""Add a FDB entry"""
863+
"""Replace a FDB entry"""
845864
return _command_bridge_fdb('replace', mac, device, dst_ip=dst_ip,
846865
namespace=namespace, **kwargs)
847866

848867

849868
@privileged.default.entrypoint
850869
def delete_bridge_fdb(mac, device, dst_ip=None, namespace=None, **kwargs):
851-
"""Add a FDB entry"""
870+
"""Delete a FDB entry"""
852871
return _command_bridge_fdb('del', mac, device, dst_ip=dst_ip,
853872
namespace=namespace, **kwargs)

neutron/tests/functional/agent/linux/test_bridge_lib.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -211,6 +211,13 @@ def test_add_delete(self):
211211
namespace=self.namespace)
212212
self._assert_mac(self.MAC1, self.device, present=False)
213213

214+
try:
215+
# This should not raise for a non-existent entry
216+
bridge_lib.FdbInterface.delete(self.MAC1, self.device,
217+
namespace=self.namespace)
218+
except Exception:
219+
self.fail('Delete FDB entry threw unexpected exception')
220+
214221
def test_add_delete_dst(self):
215222
self._assert_mac(self.MAC1, self.device_vxlan, present=False)
216223
bridge_lib.FdbInterface.add(

neutron/tests/functional/privileged/agent/linux/test_ip_lib.py

Lines changed: 52 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -239,19 +239,34 @@ def test_get_devices_info_veth_same_namespaces(self):
239239
self.assertEqual(veth1_2['index'], veth1_1_link)
240240

241241

242-
class ListIpRulesTestCase(functional_base.BaseSudoTestCase):
243-
244-
RULE_TABLES = {'default': 253, 'main': 254, 'local': 255}
242+
class BaseIpRuleTestCase(functional_base.BaseSudoTestCase):
245243

246244
def setUp(self):
247-
super(ListIpRulesTestCase, self).setUp()
245+
super().setUp()
248246
self.namespace = 'ns_test-' + uuidutils.generate_uuid()
249247
self.ns = priv_ip_lib.create_netns(self.namespace)
250248
self.addCleanup(self._remove_ns)
251249

252250
def _remove_ns(self):
253251
priv_ip_lib.remove_netns(self.namespace)
254252

253+
def _check_rules(self, rules, parameters, values, exception_string=None,
254+
raise_exception=True):
255+
for rule in rules:
256+
if all(rule.get(parameter) == value
257+
for parameter, value in zip(parameters, values)):
258+
return True
259+
else:
260+
if raise_exception:
261+
self.fail('Rule with %s was expected' % exception_string)
262+
else:
263+
return False
264+
265+
266+
class ListIpRulesTestCase(BaseIpRuleTestCase):
267+
268+
RULE_TABLES = {'default': 253, 'main': 254, 'local': 255}
269+
255270
def test_list_default_rules_ipv4(self):
256271
rules_ipv4 = priv_ip_lib.list_ip_rules(self.namespace, 4)
257272
self.assertEqual(3, len(rules_ipv4))
@@ -291,28 +306,7 @@ def test_list_rules_ipv6(self):
291306
self.fail('Rule added (2001:db8::1/64, table 20) not found')
292307

293308

294-
class RuleTestCase(functional_base.BaseSudoTestCase):
295-
296-
def setUp(self):
297-
super(RuleTestCase, self).setUp()
298-
self.namespace = 'ns_test-' + uuidutils.generate_uuid()
299-
self.ns = priv_ip_lib.create_netns(self.namespace)
300-
self.addCleanup(self._remove_ns)
301-
302-
def _remove_ns(self):
303-
priv_ip_lib.remove_netns(self.namespace)
304-
305-
def _check_rules(self, rules, parameters, values, exception_string=None,
306-
raise_exception=True):
307-
for rule in rules:
308-
if all(rule.get(parameter) == value
309-
for parameter, value in zip(parameters, values)):
310-
return True
311-
else:
312-
if raise_exception:
313-
self.fail('Rule with %s was expected' % exception_string)
314-
else:
315-
return False
309+
class AddIpRulesTestCase(BaseIpRuleTestCase):
316310

317311
def test_add_rule_ip(self):
318312
ip_addresses = ['192.168.200.250', '2001::250']
@@ -433,6 +427,23 @@ def test_add_rule_exists(self):
433427
self.assertEqual(4, len(rules))
434428

435429

430+
class DeleteIpRulesTestCase(BaseIpRuleTestCase):
431+
432+
def test_delete_rule_no_entry(self):
433+
iif = 'iif_device'
434+
priv_ip_lib.create_interface(iif, self.namespace, 'dummy')
435+
436+
try:
437+
# This should not raise for a non-existent entry
438+
priv_ip_lib.delete_ip_rule(self.namespace, iifname=iif)
439+
except Exception:
440+
self.fail('Delete IP rule threw unexpected exception')
441+
442+
rules = ip_lib.list_ip_rules(self.namespace, 4)
443+
# There are always 3 rules by default
444+
self.assertEqual(3, len(rules))
445+
446+
436447
class GetIpAddressesTestCase(functional_base.BaseSudoTestCase):
437448

438449
def _remove_ns(self, namespace):
@@ -659,6 +670,21 @@ def test_add_multipath_route(self):
659670
n_cons.IP_VERSION_4, via=multipath)
660671
self._check_routes(['192.168.0.0/24'], gateway=multipath)
661672

673+
def test_delete_route_no_entry(self):
674+
cidr = '192.168.0.0/24'
675+
self.device.addr.add('10.1.0.1/24')
676+
try:
677+
# This should not raise for a non-existent entry
678+
priv_ip_lib.delete_ip_route(self.namespace, cidr,
679+
n_cons.IP_VERSION_4,
680+
device=self.device_name)
681+
except Exception:
682+
self.fail('Delete IP route threw unexpected exception')
683+
684+
routes = ip_lib.list_ip_routes(self.namespace, n_cons.IP_VERSION_4)
685+
# There will be a single interface route since we added an IP
686+
self.assertEqual(1, len(routes))
687+
662688

663689
class GetLinkAttributesTestCase(functional_base.BaseSudoTestCase):
664690

neutron/tests/unit/privileged/agent/linux/test_ip_lib.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -157,6 +157,17 @@ def test_run_iproute_neigh_namespace_not_exists(self):
157157
priv_lib._run_iproute_neigh,
158158
"test_cmd", "eth0", None, test_param="test_value")
159159

160+
def test_run_iproute_neigh_no_entry(self):
161+
with mock.patch.object(pyroute2, "IPRoute") as iproute_mock:
162+
iproute_mock.side_effect = netlink_exceptions.NetlinkError(
163+
code=errno.ENOENT)
164+
try:
165+
priv_lib._run_iproute_neigh(
166+
"test_cmd", "eth0", None, test_param="test_value")
167+
self.fail("NetlinkError exception not raised")
168+
except netlink_exceptions.NetlinkError as e:
169+
self.assertEqual(errno.ENOENT, e.code)
170+
160171
def test_run_iproute_neigh_error(self):
161172
with mock.patch.object(pyroute2, "IPRoute") as iproute_mock:
162173
iproute_mock.side_effect = OSError(

0 commit comments

Comments
 (0)