119 lines
4.4 KiB
Diff
119 lines
4.4 KiB
Diff
From c82ace920a743c6e6797536416018d9680b8fa7e Mon Sep 17 00:00:00 2001
|
|
From: Chris Patterson <cpatterson@microsoft.com>
|
|
Date: Wed, 29 Mar 2023 17:30:13 -0400
|
|
Subject: [PATCH] net/dhcp: catch dhclient failures and raise NoDHCPLeaseError
|
|
(#2083)
|
|
|
|
Some variants of dhclient will exit with non-zero codes on lease
|
|
failure. For example, on RHEL 8.7:
|
|
```
|
|
[cpatterson@test-rhel87 ~]$ sudo /usr/sbin/dhclient -1 -v -lf
|
|
/tmp/my.lease -pf /tmp/my.pid bridge2nowhere -sf /bin/
|
|
true
|
|
Internet Systems Consortium DHCP Client 4.3.6
|
|
Copyright 2004-2017 Internet Systems Consortium.
|
|
All rights reserved.
|
|
For info, please visit https://www.isc.org/software/dhcp/
|
|
|
|
Listening on LPF/bridge2nowhere/42:ef:d5:38:1d:19
|
|
Sending on LPF/bridge2nowhere/42:ef:d5:38:1d:19
|
|
Sending on Socket/fallback
|
|
Created duid "\000\004E<\225X\232\304J\337\243\026T\324\243O\270\177".
|
|
DHCPDISCOVER on bridge2nowhere to 255.255.255.255 port 67 interval 4
|
|
(xid=0x777bc142)
|
|
DHCPDISCOVER on bridge2nowhere to 255.255.255.255 port 67 interval 7
|
|
(xid=0x777bc142)
|
|
DHCPDISCOVER on bridge2nowhere to 255.255.255.255 port 67 interval 13
|
|
(xid=0x777bc142)
|
|
DHCPDISCOVER on bridge2nowhere to 255.255.255.255 port 67 interval 6
|
|
(xid=0x777bc142)
|
|
No DHCPOFFERS received.
|
|
Unable to obtain a lease on first try. Exiting.
|
|
|
|
[cpatterson@test-rhel87 ~]$ echo $?
|
|
2
|
|
```
|
|
|
|
This results in an unhandled subp.ProcessExecutionError exception.
|
|
Catch these failures and re-raise as NoDHCPLeaseError.
|
|
|
|
Signed-off-by: Chris Patterson <cpatterson@microsoft.com>
|
|
---
|
|
cloudinit/net/dhcp.py | 11 ++++++++++-
|
|
cloudinit/net/tests/test_dhcp.py | 23 +++++++++++++++++++++--
|
|
2 files changed, 31 insertions(+), 3 deletions(-)
|
|
|
|
diff --git a/cloudinit/net/dhcp.py b/cloudinit/net/dhcp.py
|
|
index 3f4b041..e5f36e1 100644
|
|
--- a/cloudinit/net/dhcp.py
|
|
+++ b/cloudinit/net/dhcp.py
|
|
@@ -239,7 +239,16 @@ def dhcp_discovery(dhclient_cmd_path, interface, cleandir, dhcp_log_func=None):
|
|
subp.subp(['ip', 'link', 'set', 'dev', interface, 'up'], capture=True)
|
|
cmd = [sandbox_dhclient_cmd, '-1', '-v', '-lf', lease_file,
|
|
'-pf', pid_file, interface, '-sf', '/bin/true']
|
|
- out, err = subp.subp(cmd, capture=True)
|
|
+ try:
|
|
+ out, err = subp.subp(cmd, capture=True)
|
|
+ except subp.ProcessExecutionError as error:
|
|
+ LOG.debug(
|
|
+ "dhclient exited with code: %s stderr: %r stdout: %r",
|
|
+ error.exit_code,
|
|
+ error.stderr,
|
|
+ error.stdout,
|
|
+ )
|
|
+ raise NoDHCPLeaseError from error
|
|
|
|
# Wait for pid file and lease file to appear, and for the process
|
|
# named by the pid file to daemonize (have pid 1 as its parent). If we
|
|
diff --git a/cloudinit/net/tests/test_dhcp.py b/cloudinit/net/tests/test_dhcp.py
|
|
index 28b4ecf..de4b461 100644
|
|
--- a/cloudinit/net/tests/test_dhcp.py
|
|
+++ b/cloudinit/net/tests/test_dhcp.py
|
|
@@ -3,14 +3,15 @@
|
|
import httpretty
|
|
import os
|
|
import signal
|
|
+import pytest
|
|
from textwrap import dedent
|
|
|
|
import cloudinit.net as net
|
|
from cloudinit.net.dhcp import (
|
|
- InvalidDHCPLeaseFileError, maybe_perform_dhcp_discovery,
|
|
+ InvalidDHCPLeaseFileError, NoDHCPLeaseError, maybe_perform_dhcp_discovery,
|
|
parse_dhcp_lease_file, dhcp_discovery, networkd_load_leases,
|
|
parse_static_routes)
|
|
-from cloudinit.util import ensure_file, write_file
|
|
+from cloudinit.util import ensure_file, subp, write_file
|
|
from cloudinit.tests.helpers import (
|
|
CiTestCase, HttprettyTestCase, mock, populate_dir, wrap_and_call)
|
|
|
|
@@ -268,6 +269,24 @@ class TestDHCPDiscoveryClean(CiTestCase):
|
|
'Skip dhcp_discovery: Unable to find fallback nic.',
|
|
self.logs.getvalue())
|
|
|
|
+ @mock.patch("cloudinit.net.dhcp.find_fallback_nic", return_value="eth9")
|
|
+ @mock.patch("cloudinit.net.dhcp.os.remove")
|
|
+ @mock.patch("cloudinit.net.dhcp.subp.subp")
|
|
+ def test_dhclient_exits_with_error(self, m_subp, m_remove, m_fallback):
|
|
+ """Log and do nothing when nic is absent and no fallback is found."""
|
|
+ m_subp.side_effect = [
|
|
+ ("", ""),
|
|
+ subp.ProcessExecutionError(exit_code=-5),
|
|
+ ]
|
|
+
|
|
+ with pytest.raises(NoDHCPLeaseError):
|
|
+ maybe_perform_dhcp_discovery()
|
|
+
|
|
+ self.assertIn(
|
|
+ "dhclient exited with code: -5",
|
|
+ self.logs.getvalue(),
|
|
+ )
|
|
+
|
|
def test_provided_nic_does_not_exist(self):
|
|
"""When the provided nic doesn't exist, log a message and no-op."""
|
|
self.assertEqual([], maybe_perform_dhcp_discovery('idontexist'))
|
|
--
|
|
2.33.0
|
|
|
|
|