From ce29575946765ed724395428001e7b48d5bc8584 Mon Sep 17 00:00:00 2001 From: Vitaly Kuznetsov Date: Tue, 7 Jan 2025 17:19:37 +0100 Subject: [PATCH] Set DHCP hostname with nmcli for modern RHEL distros RHEL8+ uses NetworkManager and the most recent RHEL10 switched to using built-in dhcp client making DefaultOSUtil.set_dhcp_hostname() unsuitable. In fact, RHEL distos had been carrying RHEL-only downstream patch replacing RedhatOSModernUtil.set_dhcp_hostname() with nmcli device modify ipv4.dhcp-hostname since RHEL8 but this is also not ideal as 'nmcli device modify' does not persist the change. Complement this with 'nmcli connection modify' to both make the immediate change and persist it. Signed-off-by: Vitaly Kuznetsov --- azurelinuxagent/common/osutil/redhat.py | 36 ++++++++++++++++++++----- 1 file changed, 30 insertions(+), 6 deletions(-) diff --git a/azurelinuxagent/common/osutil/redhat.py b/azurelinuxagent/common/osutil/redhat.py index a9a103477..37fa6e592 100644 --- a/azurelinuxagent/common/osutil/redhat.py +++ b/azurelinuxagent/common/osutil/redhat.py @@ -266,9 +266,33 @@ def check_and_recover_nic_state(self, ifname): # TODO: Implement and test a way to recover the network interface for RedhatOSModernUtil pass - def publish_hostname(self, hostname, recover_nic=False): - # RedhatOSUtil was updated to conditionally run NetworkManager restart in response to a race condition between - # NetworkManager restart and the agent restarting the network interface during publish_hostname. Keeping the - # NetworkManager restart in RedhatOSModernUtil because the issue was not reproduced on these versions. - shellutil.run("service NetworkManager restart") - DefaultOSUtil.publish_hostname(self, hostname) + def set_dhcp_hostname(self, hostname): + """ + RHEL8+ distributions use NetworkManager to configure network interfaces, set DHCP hostname + in NM device and connection settings. + """ + ifname = self.get_if_name() + retry_limit = 4 + wait = 5 + + ret, con = shellutil.run_get_output("nmcli -g GENERAL.CONNECTION device show '{0}'".format(ifname)) + if ret != 0: + logger.error("failed to get NetworkManager connection for {0}: return code {1}".format(ifname, ret)) + return + else: + con = con.split('\n')[0] + logger.verbose("Using NetworkManager connection '{0}' for {1}".format(con, ifname)) + + ret = shellutil.run("nmcli connection modify '{0}' ipv4.dhcp-hostname '{1}' ipv6.dhcp-hostname '{1}'".format(con, hostname)) + if ret != 0: + logger.error("failed to persist DHCP hostname for interface {0}: return code {1}".format(ifname, ret)) + + for attempt in range(1, retry_limit): + ret = shellutil.run("nmcli device modify '{0}' ipv4.dhcp-hostname '{1}' ipv6.dhcp-hostname '{1}'".format(ifname, hostname)) + if ret == 0: + return + logger.warn("failed to modify DHCP hostname for interface {0}: return code {1}".format(ifname, ret)) + logger.info("retrying in {0} seconds".format(wait)) + time.sleep(wait) + + logger.error("failed to modify DHCP hostname for interface {0}: no more tries".format(ifname))