158 lines
8.0 KiB
Diff
158 lines
8.0 KiB
Diff
From 7c52b8a5fbcfe1e7442bbd011956b52e303745c5 Mon Sep 17 00:00:00 2001
|
|
From: Dmitry Zykov <44090270+zykovd@users.noreply.github.com>
|
|
Date: Fri, 12 May 2023 21:48:10 +0300
|
|
Subject: [PATCH] Fix KeyError in iproute pformat (#3287)
|
|
|
|
Reference:https://github.com/canonical/cloud-init/commit/7c52b8a5fbcfe1e7442bbd011956b52e303745c5
|
|
Conflict:format diff.
|
|
|
|
This fixes KeyError on specific network configuration when running
|
|
cloud-init on "network" stage. The same problem was mentioned in
|
|
#746 and #1041.
|
|
---
|
|
cloudinit/netinfo.py | 16 +++++++----
|
|
.../route-formatted-output-missing-gateway | 19 +++++++++++++
|
|
.../sample-iproute-output-v4-missing-gateway | 1 +
|
|
.../sample-iproute-output-v6-missing-gateway | 10 +++++++
|
|
cloudinit/tests/test_netinfo.py | 27 +++++++++++++++++++
|
|
5 files changed, 68 insertions(+), 5 deletions(-)
|
|
create mode 100644 tests/data/netinfo/route-formatted-output-missing-gateway
|
|
create mode 100644 tests/data/netinfo/sample-iproute-output-v4-missing-gateway
|
|
create mode 100644 tests/data/netinfo/sample-iproute-output-v6-missing-gateway
|
|
|
|
diff --git a/cloudinit/netinfo.py b/cloudinit/netinfo.py
|
|
index 628e290..f26399a 100644
|
|
--- a/cloudinit/netinfo.py
|
|
+++ b/cloudinit/netinfo.py
|
|
@@ -460,9 +460,12 @@ def route_pformat():
|
|
tbl_v4 = SimpleTable(fields_v4)
|
|
for (n, r) in enumerate(routes.get('ipv4')):
|
|
route_id = str(n)
|
|
- tbl_v4.add_row([route_id, r['destination'],
|
|
- r['gateway'], r['genmask'],
|
|
- r['iface'], r['flags']])
|
|
+ try:
|
|
+ tbl_v4.add_row([route_id, r['destination'],
|
|
+ r['gateway'], r['genmask'],
|
|
+ r['iface'], r['flags']])
|
|
+ except KeyError as e:
|
|
+ util.logexc(LOG, "Route info formatting error: %s" % e)
|
|
route_s = tbl_v4.get_string()
|
|
max_len = len(max(route_s.splitlines(), key=len))
|
|
header = util.center("Route IPv4 info", "+", max_len)
|
|
@@ -475,8 +478,11 @@ def route_pformat():
|
|
route_id = str(n)
|
|
if r['iface'] == 'lo':
|
|
continue
|
|
- tbl_v6.add_row([route_id, r['destination'],
|
|
- r['gateway'], r['iface'], r['flags']])
|
|
+ try:
|
|
+ tbl_v6.add_row([route_id, r['destination'],
|
|
+ r['gateway'], r['iface'], r['flags']])
|
|
+ except KeyError as e:
|
|
+ util.logexc(LOG, "Route info formatting error: %s" % e)
|
|
route_s = tbl_v6.get_string()
|
|
max_len = len(max(route_s.splitlines(), key=len))
|
|
header = util.center("Route IPv6 info", "+", max_len)
|
|
diff --git a/tests/data/netinfo/route-formatted-output-missing-gateway b/tests/data/netinfo/route-formatted-output-missing-gateway
|
|
new file mode 100644
|
|
index 0000000..8bbd819
|
|
--- /dev/null
|
|
+++ b/tests/data/netinfo/route-formatted-output-missing-gateway
|
|
@@ -0,0 +1,19 @@
|
|
++++++++++++++++++++++++++++Route IPv4 info+++++++++++++++++++++++++++
|
|
++-------+-------------+---------+---------------+-----------+-------+
|
|
+| Route | Destination | Gateway | Genmask | Interface | Flags |
|
|
++-------+-------------+---------+---------------+-----------+-------+
|
|
+| 0 | 192.168.2.0 | 0.0.0.0 | 255.255.255.0 | enp0s25 | U |
|
|
++-------+-------------+---------+---------------+-----------+-------+
|
|
+++++++++++++++++++++++++++Route IPv6 info++++++++++++++++++++++++++
|
|
++-------+---------------------------+---------+-----------+-------+
|
|
+| Route | Destination | Gateway | Interface | Flags |
|
|
++-------+---------------------------+---------+-----------+-------+
|
|
+| 0 | 2a00:abcd:82ae:cd33::657 | :: | enp0s25 | Ue |
|
|
+| 1 | 2a00:abcd:82ae:cd33::/64 | :: | enp0s25 | U |
|
|
+| 2 | 2a00:abcd:82ae:cd33::/56 | :: | enp0s25 | U |
|
|
+| 3 | fd81:123f:654::657 | :: | enp0s25 | U |
|
|
+| 4 | fd81:123f:654::/64 | :: | enp0s25 | U |
|
|
+| 5 | fd81:123f:654::/48 | :: | enp0s25 | U |
|
|
+| 6 | fe80::abcd:ef12:bc34:da21 | :: | enp0s25 | U |
|
|
+| 7 | fe80::/64 | :: | enp0s25 | U |
|
|
++-------+---------------------------+---------+-----------+-------+
|
|
diff --git a/tests/data/netinfo/sample-iproute-output-v4-missing-gateway b/tests/data/netinfo/sample-iproute-output-v4-missing-gateway
|
|
new file mode 100644
|
|
index 0000000..c1e0b3c
|
|
--- /dev/null
|
|
+++ b/tests/data/netinfo/sample-iproute-output-v4-missing-gateway
|
|
@@ -0,0 +1 @@
|
|
+192.168.2.0/24 dev enp0s25 proto kernel scope link src 192.168.2.18 metric 100
|
|
diff --git a/tests/data/netinfo/sample-iproute-output-v6-missing-gateway b/tests/data/netinfo/sample-iproute-output-v6-missing-gateway
|
|
new file mode 100644
|
|
index 0000000..ffab1fa
|
|
--- /dev/null
|
|
+++ b/tests/data/netinfo/sample-iproute-output-v6-missing-gateway
|
|
@@ -0,0 +1,10 @@
|
|
+2a00:abcd:82ae:cd33::657 dev enp0s25 proto kernel metric 256 expires 2334sec pref medium
|
|
+2a00:abcd:82ae:cd33::/64 dev enp0s25 proto ra metric 100 pref medium
|
|
+2a00:abcd:82ae:cd33::/56 dev enp0s25 proto ra metric 100 pref medium
|
|
+fd81:123f:654::657 dev enp0s25 proto kernel metric 256 pref medium
|
|
+fd81:123f:654::/64 dev enp0s25 proto ra metric 100 pref medium
|
|
+fd81:123f:654::/48 dev enp0s25 proto ra metric 100 pref medium
|
|
+fe80::abcd:ef12:bc34:da21 dev enp0s25 proto static metric 100 pref medium
|
|
+fe80::/64 dev enp0s25 proto kernel metric 256 pref medium
|
|
+local ::1 dev lo table local proto none metric 0 pref medium
|
|
+local 2600:1f16:b80:ad00:90a:c915:bca6:5ff2 dev lo table local proto none metric 0 pref medium
|
|
diff --git a/cloudinit/tests/test_netinfo.py b/cloudinit/tests/test_netinfo.py
|
|
index e44b16d..6619e0d 100644
|
|
--- a/cloudinit/tests/test_netinfo.py
|
|
+++ b/cloudinit/tests/test_netinfo.py
|
|
@@ -15,10 +15,19 @@ SAMPLE_FREEBSD_IFCONFIG_OUT = readResource("netinfo/freebsd-ifconfig-output")
|
|
SAMPLE_IPADDRSHOW_OUT = readResource("netinfo/sample-ipaddrshow-output")
|
|
SAMPLE_ROUTE_OUT_V4 = readResource("netinfo/sample-route-output-v4")
|
|
SAMPLE_ROUTE_OUT_V6 = readResource("netinfo/sample-route-output-v6")
|
|
+SAMPLE_IPROUTE_OUT_V6_MISSING_GATEWAY = readResource(
|
|
+ "netinfo/sample-iproute-output-v6-missing-gateway"
|
|
+)
|
|
+SAMPLE_IPROUTE_OUT_V4_MISSING_GATEWAY = readResource(
|
|
+ "netinfo/sample-iproute-output-v4-missing-gateway"
|
|
+)
|
|
SAMPLE_IPROUTE_OUT_V4 = readResource("netinfo/sample-iproute-output-v4")
|
|
SAMPLE_IPROUTE_OUT_V6 = readResource("netinfo/sample-iproute-output-v6")
|
|
NETDEV_FORMATTED_OUT = readResource("netinfo/netdev-formatted-output")
|
|
ROUTE_FORMATTED_OUT = readResource("netinfo/route-formatted-output")
|
|
+ROUTE_FORMATTED_OUT_MISSING_GATEWAY = readResource(
|
|
+ "netinfo/route-formatted-output-missing-gateway"
|
|
+)
|
|
FREEBSD_NETDEV_OUT = readResource("netinfo/freebsd-netdev-formatted-output")
|
|
|
|
|
|
@@ -165,6 +174,24 @@ class TestNetInfo(CiTestCase):
|
|
content = route_pformat()
|
|
self.assertEqual(ROUTE_FORMATTED_OUT, content)
|
|
|
|
+ @mock.patch("cloudinit.netinfo.subp.which")
|
|
+ @mock.patch("cloudinit.netinfo.subp.subp")
|
|
+ def test_route_iproute_pformat_missing_gateway(self, m_subp, m_which):
|
|
+ """route_pformat properly rendering info with missing gateway."""
|
|
+
|
|
+ def subp_iproute_selector(*args, **kwargs):
|
|
+ if ["ip", "-o", "route", "list"] == args[0]:
|
|
+ return (SAMPLE_IPROUTE_OUT_V4_MISSING_GATEWAY, "")
|
|
+ v6cmd = ["ip", "--oneline", "-6", "route", "list", "table", "all"]
|
|
+ if v6cmd == args[0]:
|
|
+ return (SAMPLE_IPROUTE_OUT_V6_MISSING_GATEWAY, "")
|
|
+ raise RuntimeError("Unexpected subp call %s" % args[0])
|
|
+
|
|
+ m_subp.side_effect = subp_iproute_selector
|
|
+ m_which.side_effect = lambda x: x if x == "ip" else None
|
|
+ content = route_pformat()
|
|
+ assert ROUTE_FORMATTED_OUT_MISSING_GATEWAY == content
|
|
+
|
|
@mock.patch('cloudinit.netinfo.subp.which')
|
|
@mock.patch('cloudinit.netinfo.subp.subp')
|
|
def test_route_warn_on_missing_commands(self, m_subp, m_which):
|
|
--
|
|
2.33.0
|
|
|
|
|