Skip to content

Commit d1867e3

Browse files
committed
Add a DHCP runner to restart networking
1 parent 45728f6 commit d1867e3

File tree

1 file changed

+79
-2
lines changed
  • libazureinit/src/provision

1 file changed

+79
-2
lines changed

libazureinit/src/provision/mod.rs

Lines changed: 79 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,9 @@ use crate::config::{
1010
};
1111
use crate::error::Error;
1212
use crate::User;
13+
use std::io;
14+
use std::process::{Command, Output};
15+
1316
use tracing::instrument;
1417

1518
/// The interface for applying the desired configuration to the host.
@@ -68,21 +71,61 @@ impl Provision {
6871
.ok_or(Error::NoUserProvisioner)
6972
}
7073

74+
/// Sets the system hostname with a custom DHCP renewer function.
75+
///
76+
/// This version allows dependency injection of the DHCP renewal command for testing.
77+
///
78+
/// # Arguments
79+
///
80+
/// * `dhcp_renew_command_runner` - A function that runs the DHCP renewal command and returns its output.
81+
///
82+
/// # Returns
83+
///
84+
/// Returns `Ok(())` if the hostname was set successfully and DHCP leases were renewed.
85+
/// Returns an error if hostname setting fails or DHCP renewal fails.
86+
///
87+
#[instrument(skip_all)]
88+
pub fn set_hostname(self) -> Result<(), Error> {
89+
#[cfg(not(test))]
90+
{
91+
self.set_hostname_with_dhcp_renewer(|| {
92+
Command::new("systemctl")
93+
.arg("restart")
94+
.arg("systemd-networkd")
95+
.output()
96+
})
97+
}
98+
#[cfg(test)]
99+
{
100+
self.set_hostname_with_dhcp_renewer(|| {
101+
Ok(Output {
102+
status: std::os::unix::process::ExitStatusExt::from_raw(0),
103+
stdout: b"DHCP renewal successful".to_vec(),
104+
stderr: b"".to_vec(),
105+
})
106+
})
107+
}
108+
}
109+
71110
/// Sets the system hostname using the hostname found in either IMDS or the OVF.
72111
///
73112
/// This function iterates over a list of available backends and attempts to
74113
/// set the hostname until one succeeds. Currently supported backends include:
75114
/// - `Hostnamectl`
76115
///
77116
/// Additional hostname provisioners can be set through config files.
117+
/// This function ends by renewing all DHCP leases.
78118
///
79119
/// # Returns
80120
///
81121
/// Returns `Ok(())` if the hostname was set successfully by any of the backends.
82122
/// Returns `Err(Error::NoHostnameProvisioner)` if no backends was able to set
83123
/// the hostname.
84124
#[instrument(skip_all)]
85-
pub fn set_hostname(self) -> Result<(), Error> {
125+
fn set_hostname_with_dhcp_renewer(
126+
self,
127+
dhcp_renew_command_runner: impl Fn() -> io::Result<Output>,
128+
) -> Result<(), Error> {
86129
self.config
87130
.hostname_provisioners
88131
.backends
@@ -94,7 +137,41 @@ impl Provision {
94137
#[cfg(test)]
95138
HostnameProvisioner::FakeHostnamectl => Some(()),
96139
})
97-
.ok_or(Error::NoHostnameProvisioner)
140+
.ok_or(Error::NoHostnameProvisioner)?;
141+
142+
Self::renew_dhcp_leases_with_runner(dhcp_renew_command_runner)?;
143+
144+
Ok(())
145+
}
146+
147+
/// Renews DHCP leases using a custom command runner.
148+
///
149+
/// # Arguments
150+
///
151+
/// * `dhcp_renew_command_runner` - A function that runs the DHCP renewal command and returns its output.
152+
///
153+
/// # Returns
154+
///
155+
/// Returns `Ok(())` if DHCP leases were renewed successfully.
156+
/// Returns an error if the command fails.
157+
#[instrument(skip_all)]
158+
fn renew_dhcp_leases_with_runner(
159+
dhcp_renew_command_runner: impl Fn() -> io::Result<Output>,
160+
) -> Result<(), Error> {
161+
let output = dhcp_renew_command_runner()?;
162+
163+
if !output.status.success() {
164+
tracing::error!(
165+
"Failed to renew DHCP leases: {}",
166+
String::from_utf8_lossy(&output.stderr)
167+
);
168+
return Err(Error::SubprocessFailed {
169+
command: "networkctl renew".to_string(),
170+
status: output.status,
171+
});
172+
}
173+
174+
Ok(())
98175
}
99176

100177
/// Provisioning can fail if the host lacks the necessary tools. For example,

0 commit comments

Comments
 (0)