Skip to content
Open
Changes from 17 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
82 changes: 74 additions & 8 deletions libazureinit/src/provision/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -68,12 +68,20 @@ impl Provision {
.ok_or(Error::NoUserProvisioner)
}

/// Provisioning can fail if the host lacks the necessary tools. For example,
/// if there is no useradd command on the system's PATH, or if the command
/// returns an error, this will return an error. It does not attempt to undo
/// partial provisioning.
/// Sets the system hostname using the configured hostname provisioners.
///
/// Iterates through the configured hostname provisioner backends and attempts to set
/// the hostname with the first backend that succeeds. Currently supported
/// backends include:
/// - Hostnamectl
///
/// # Returns
///
/// Returns `Ok(())` if the hostname was set successfully.
/// Returns [`Error::NoHostnameProvisioner`] if no hostname provisioner backends are
/// configured or if all backends fail to set the hostname.
#[instrument(skip_all)]
pub fn provision(self) -> Result<(), Error> {
pub fn set_hostname(&self) -> Result<(), Error> {
self.config
.hostname_provisioners
.backends
Expand All @@ -85,7 +93,16 @@ impl Provision {
#[cfg(test)]
HostnameProvisioner::FakeHostnamectl => Some(()),
})
.ok_or(Error::NoHostnameProvisioner)?;
.ok_or(Error::NoHostnameProvisioner)
}

/// Provisioning can fail if the host lacks the necessary tools. For example,
/// if there is no useradd command on the system's PATH, or if the command
/// returns an error, this will return an error. It does not attempt to undo
/// partial provisioning.
#[instrument(skip_all)]
pub fn provision(self) -> Result<(), Error> {
self.set_hostname()?;

self.create_user()?;

Expand Down Expand Up @@ -166,7 +183,7 @@ mod tests {
use crate::config::{
HostnameProvisioners, PasswordProvisioners, UserProvisioners,
};
use crate::error;
use crate::error::Error;
use crate::User;

#[test]
Expand Down Expand Up @@ -299,8 +316,57 @@ mod tests {
"create_user should fail with no user provisioners"
);
assert!(
matches!(result.unwrap_err(), error::Error::NoUserProvisioner),
matches!(result.unwrap_err(), Error::NoUserProvisioner),
"Should return NoUserProvisioner error"
);
}

#[test]
fn test_set_hostname_success() {
let mock_config = Config {
hostname_provisioners: HostnameProvisioners {
backends: vec![HostnameProvisioner::FakeHostnamectl],
},
user_provisioners: UserProvisioners {
backends: vec![UserProvisioner::FakeUseradd],
},
password_provisioners: PasswordProvisioners {
backends: vec![PasswordProvisioner::FakePasswd],
},
..Config::default()
};
let p = Provision::new(
"test-hostname".to_string(),
User::new("testuser", vec![]),
mock_config,
false,
);

let result = p.set_hostname();
assert!(result.is_ok());
}

#[test]
fn test_set_hostname_failure() {
let mock_config = Config {
hostname_provisioners: HostnameProvisioners { backends: vec![] },
user_provisioners: UserProvisioners {
backends: vec![UserProvisioner::FakeUseradd],
},
password_provisioners: PasswordProvisioners {
backends: vec![PasswordProvisioner::FakePasswd],
},
..Config::default()
};
let p = Provision::new(
"test-hostname".to_string(),
User::new("testuser", vec![]),
mock_config,
false,
);

let result = p.set_hostname();
assert!(result.is_err());
assert!(matches!(result.unwrap_err(), Error::NoHostnameProvisioner));
}
}