Skip to main content

torrust_tracker_deployer_lib/application/steps/infrastructure/
destroy.rs

1//! `OpenTofu` infrastructure destruction step
2//!
3//! This module provides the `DestroyInfrastructureStep` which handles `OpenTofu`
4//! destroy operations by executing `tofu destroy`. This step destroys all
5//! infrastructure resources managed by the `OpenTofu` configuration.
6//!
7//! ## Key Features
8//!
9//! - Infrastructure teardown and resource destruction
10//! - Configurable auto-approval for automation scenarios
11//! - Progress tracking and status reporting
12//! - Integration with `OpenTofuClient` for command execution
13//!
14//! ## Destroy Process
15//!
16//! The step executes `tofu destroy` which:
17//! - Destroys all resources managed by the `OpenTofu` state
18//! - Manages resource dependencies and proper destruction order
19//! - Removes infrastructure state after successful destruction
20//! - Provides detailed progress and completion status
21//!
22//! This step is where actual infrastructure destruction occurs.
23
24use std::sync::Arc;
25
26use tracing::{info, instrument};
27
28use crate::adapters::tofu::client::OpenTofuClient;
29use crate::shared::command::CommandError;
30
31/// Simple step that destroys `OpenTofu` infrastructure by executing `tofu destroy`
32pub struct DestroyInfrastructureStep {
33    opentofu_client: Arc<OpenTofuClient>,
34    auto_approve: bool,
35}
36
37impl DestroyInfrastructureStep {
38    #[must_use]
39    pub fn new(opentofu_client: Arc<OpenTofuClient>) -> Self {
40        Self {
41            opentofu_client,
42            auto_approve: true, // Default to auto-approve for automation
43        }
44    }
45
46    #[must_use]
47    pub fn with_auto_approve(mut self, auto_approve: bool) -> Self {
48        self.auto_approve = auto_approve;
49        self
50    }
51
52    /// Execute the `OpenTofu` destroy step
53    ///
54    /// # Errors
55    ///
56    /// Returns an error if:
57    /// * The `OpenTofu` destroy fails
58    /// * The working directory does not exist or is not accessible
59    /// * The `OpenTofu` command execution fails
60    #[instrument(
61        name = "destroy_infrastructure",
62        skip_all,
63        fields(
64            step_type = "infrastructure",
65            operation = "destroy",
66            auto_approve = %self.auto_approve
67        )
68    )]
69    pub fn execute(&self) -> Result<(), CommandError> {
70        info!(
71            step = "destroy_infrastructure",
72            auto_approve = self.auto_approve,
73            "Destroying OpenTofu infrastructure"
74        );
75
76        // Execute tofu destroy command with variables file
77        let output = self
78            .opentofu_client
79            .destroy(self.auto_approve, &["-var-file=variables.tfvars"])?;
80
81        info!(
82            step = "destroy_infrastructure",
83            status = "success",
84            "OpenTofu infrastructure destroyed successfully"
85        );
86
87        // Log output for debugging if needed
88        tracing::debug!(output = %output, "OpenTofu destroy output");
89
90        Ok(())
91    }
92}
93
94#[cfg(test)]
95mod tests {
96    use std::sync::Arc;
97
98    use crate::adapters::tofu::client::OpenTofuClient;
99
100    use super::*;
101
102    #[test]
103    fn it_should_create_destroy_infrastructure_step() {
104        let opentofu_client = Arc::new(OpenTofuClient::new("/tmp"));
105
106        let _step = DestroyInfrastructureStep::new(opentofu_client);
107
108        // If we reach this point, the step was created successfully
109    }
110
111    #[test]
112    fn it_should_create_step_with_custom_auto_approve() {
113        let opentofu_client = Arc::new(OpenTofuClient::new("/tmp"));
114
115        let step = DestroyInfrastructureStep::new(opentofu_client).with_auto_approve(false);
116
117        assert!(!step.auto_approve);
118    }
119
120    #[test]
121    fn it_should_default_to_auto_approve() {
122        let opentofu_client = Arc::new(OpenTofuClient::new("/tmp"));
123
124        let step = DestroyInfrastructureStep::new(opentofu_client);
125
126        assert!(step.auto_approve);
127    }
128}