Skip to main content

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}