summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDmitry Zykov <44090270+zykovd@users.noreply.github.com>2023-05-12 21:48:10 +0300
committerGitHub <noreply@github.com>2023-05-12 13:48:10 -0500
commit7c52b8a5fbcfe1e7442bbd011956b52e303745c5 (patch)
tree633b6e2e8dfa7f81ac6e3b5e629b7b14057899d1
parent73f34575da4f99a376998516a13c3a79cc640ae3 (diff)
downloadcloud-init-git-7c52b8a5fbcfe1e7442bbd011956b52e303745c5.tar.gz
Fix KeyError in iproute pformat (#3287)
This fixes KeyError on specific network configuration when running cloud-init on "network" stage. The same problem was mentioned in #746 and #1041.
-rw-r--r--cloudinit/netinfo.py44
-rw-r--r--tests/data/netinfo/route-formatted-output-missing-gateway19
-rw-r--r--tests/data/netinfo/sample-iproute-output-v4-missing-gateway1
-rw-r--r--tests/data/netinfo/sample-iproute-output-v6-missing-gateway10
-rw-r--r--tests/unittests/test_netinfo.py27
-rw-r--r--tools/.github-cla-signers1
6 files changed, 83 insertions, 19 deletions
diff --git a/cloudinit/netinfo.py b/cloudinit/netinfo.py
index 0daa27f7..fc25439c 100644
--- a/cloudinit/netinfo.py
+++ b/cloudinit/netinfo.py
@@ -598,16 +598,19 @@ 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.get("gateway", "0.0.0.0"),
+ 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)
@@ -625,15 +628,18 @@ 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.get("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 00000000..8bbd819d
--- /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 00000000..c1e0b3c8
--- /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 00000000..ffab1fa7
--- /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/tests/unittests/test_netinfo.py b/tests/unittests/test_netinfo.py
index 7612a28b..49c92f7e 100644
--- a/tests/unittests/test_netinfo.py
+++ b/tests/unittests/test_netinfo.py
@@ -26,8 +26,17 @@ SAMPLE_ROUTE_OUT_V4 = readResource("netinfo/sample-route-output-v4")
SAMPLE_ROUTE_OUT_V6 = readResource("netinfo/sample-route-output-v6")
SAMPLE_IPROUTE_OUT_V4 = readResource("netinfo/sample-iproute-output-v4")
SAMPLE_IPROUTE_OUT_V6 = readResource("netinfo/sample-iproute-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"
+)
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")
@@ -225,6 +234,24 @@ class TestNetInfo:
@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, caplog):
"""route_pformat warns when missing both ip and 'netstat'."""
m_which.return_value = None # Niether ip nor netstat found
diff --git a/tools/.github-cla-signers b/tools/.github-cla-signers
index a3d692b6..ab8a9283 100644
--- a/tools/.github-cla-signers
+++ b/tools/.github-cla-signers
@@ -156,3 +156,4 @@ yangzz-97
yawkat
zhan9san
zhuzaifangxuele
+zykovd