Skip to content

Commit a956879

Browse files
Zuulopenstack-gerrit
authored andcommitted
Merge "Catch non-existent entry failures better in ip_lib" into stable/zed
2 parents b2100c6 + 61ad633 commit a956879

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
@@ -473,6 +473,10 @@ def delete_neigh_entry(ip_version, ip_address, mac_address, device, namespace,
473473
if e.code == errno.ENOENT:
474474
return
475475
raise
476+
except OSError as e:
477+
if e.errno == errno.ENOENT:
478+
raise NetworkNamespaceNotFound(netns_name=namespace)
479+
raise
476480

477481

478482
@tenacity.retry(
@@ -682,6 +686,11 @@ def delete_ip_rule(namespace, **kwargs):
682686
try:
683687
with get_iproute(namespace) as ip:
684688
ip.rule('del', **kwargs)
689+
except netlink_exceptions.NetlinkError as e:
690+
# trying to delete a non-existent entry shouldn't raise an error
691+
if e.code == errno.ENOENT:
692+
return
693+
raise
685694
except OSError as e:
686695
if e.errno == errno.ENOENT:
687696
raise NetworkNamespaceNotFound(netns_name=namespace)
@@ -787,6 +796,11 @@ def delete_ip_route(namespace, cidr, ip_version, device=None, via=None,
787796
try:
788797
with get_iproute(namespace) as ip:
789798
ip.route('del', **kwargs)
799+
except netlink_exceptions.NetlinkError as e:
800+
# trying to delete a non-existent entry shouldn't raise an error
801+
if e.code == errno.ESRCH:
802+
return
803+
raise
790804
except OSError as e:
791805
if e.errno == errno.ENOENT:
792806
raise NetworkNamespaceNotFound(netns_name=namespace)
@@ -821,6 +835,11 @@ def _command_bridge_fdb(command, mac, device, dst_ip=None, namespace=None,
821835
kwargs['dst'] = dst_ip
822836
with get_iproute(namespace) as ip:
823837
return make_serializable(ip.fdb(command, **kwargs))
838+
except netlink_exceptions.NetlinkError as e:
839+
# trying to delete a non-existent entry shouldn't raise an error
840+
if command == 'del' and e.code == errno.ENOENT:
841+
return
842+
raise
824843
except OSError as e:
825844
if e.errno == errno.ENOENT:
826845
raise NetworkNamespaceNotFound(netns_name=namespace)
@@ -836,20 +855,20 @@ def add_bridge_fdb(mac, device, dst_ip=None, namespace=None, **kwargs):
836855

837856
@privileged.default.entrypoint
838857
def append_bridge_fdb(mac, device, dst_ip=None, namespace=None, **kwargs):
839-
"""Add a FDB entry"""
858+
"""Append a FDB entry"""
840859
_command_bridge_fdb('append', mac, device, dst_ip=dst_ip,
841860
namespace=namespace, **kwargs)
842861

843862

844863
@privileged.default.entrypoint
845864
def replace_bridge_fdb(mac, device, dst_ip=None, namespace=None, **kwargs):
846-
"""Add a FDB entry"""
865+
"""Replace a FDB entry"""
847866
_command_bridge_fdb('replace', mac, device, dst_ip=dst_ip,
848867
namespace=namespace, **kwargs)
849868

850869

851870
@privileged.default.entrypoint
852871
def delete_bridge_fdb(mac, device, dst_ip=None, namespace=None, **kwargs):
853-
"""Add a FDB entry"""
872+
"""Delete a FDB entry"""
854873
_command_bridge_fdb('del', mac, device, dst_ip=dst_ip,
855874
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']
@@ -439,6 +433,23 @@ def test_add_rule_exists(self):
439433
self.assertEqual(4, len(rules))
440434

441435

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

444455
def _remove_ns(self, namespace):
@@ -665,6 +676,21 @@ def test_add_multipath_route(self):
665676
n_cons.IP_VERSION_4, via=multipath)
666677
self._check_routes(['192.168.0.0/24'], gateway=multipath)
667678

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

669695
class GetLinkAttributesTestCase(functional_base.BaseSudoTestCase):
670696

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)