torrust_tracker_deployer_lib/application/steps/validation/cloud_init.rs
1//! Cloud-init completion validation step
2//!
3//! This module provides the `ValidateCloudInitCompletionStep` which validates
4//! that cloud-init has completed successfully on remote instances. This step
5//! ensures instances are fully initialized before proceeding with deployment.
6//!
7//! ## Key Features
8//!
9//! - Cloud-init completion status verification via remote validation
10//! - System initialization readiness checking
11//! - Integration with SSH-based remote actions
12//! - Comprehensive error handling for initialization failures
13//!
14//! ## Validation Process
15//!
16//! The step uses the `CloudInitValidator` remote action to check cloud-init
17//! status and ensure all system initialization tasks have completed successfully,
18//! providing confidence that the instance is ready for configuration and
19//! software installation.
20
21use tracing::{info, instrument};
22
23use crate::adapters::ssh::SshConfig;
24use crate::infrastructure::remote_actions::{CloudInitValidator, RemoteAction, RemoteActionError};
25
26/// Step that validates cloud-init completion on a remote host
27pub struct ValidateCloudInitCompletionStep {
28 ssh_config: SshConfig,
29}
30
31impl ValidateCloudInitCompletionStep {
32 #[must_use]
33 pub fn new(ssh_config: SshConfig) -> Self {
34 Self { ssh_config }
35 }
36
37 /// Execute the cloud-init completion validation step
38 ///
39 /// This will validate that cloud-init has finished running on the remote host
40 /// by checking cloud-init status and ensuring all initialization is complete.
41 ///
42 /// # Errors
43 ///
44 /// Returns an error if:
45 /// * SSH connection to the remote host fails
46 /// * Cloud-init validation fails
47 /// * The remote action execution fails for any other reason
48 ///
49 /// # Notes
50 ///
51 /// - This validation ensures that all cloud-init modules have completed
52 /// - Critical for ensuring the system is ready for further configuration
53 /// - Checks both cloud-init status and completion markers
54 #[instrument(
55 name = "validate_cloud_init",
56 skip_all,
57 fields(step_type = "validation", component = "cloud_init")
58 )]
59 pub async fn execute(&self) -> Result<(), RemoteActionError> {
60 info!(component = "cloud_init", "Validating cloud-init completion");
61
62 let cloud_init_validator = CloudInitValidator::new(self.ssh_config.clone());
63
64 cloud_init_validator
65 .execute(&self.ssh_config.host_ip())
66 .await?;
67
68 Ok(())
69 }
70}
71
72#[cfg(test)]
73mod tests {
74 use std::net::{IpAddr, Ipv4Addr};
75 use std::path::PathBuf;
76
77 use crate::adapters::ssh::SshCredentials;
78 use crate::shared::Username;
79
80 use super::*;
81
82 #[test]
83 fn it_should_create_validate_cloud_init_completion_step() {
84 let ssh_credentials = SshCredentials::new(
85 PathBuf::from("test_key"),
86 PathBuf::from("test_key.pub"),
87 Username::new("test_user").unwrap(),
88 );
89 let host_ip = IpAddr::V4(Ipv4Addr::new(192, 168, 1, 1));
90 let ssh_config = SshConfig::with_default_port(ssh_credentials, host_ip);
91
92 let step = ValidateCloudInitCompletionStep::new(ssh_config);
93
94 // Test that the step can be created successfully
95 assert_eq!(step.ssh_config.host_ip(), host_ip);
96 }
97}