use std::path::Path;
pub mod client;
pub mod json_parser;
pub use client::{InstanceInfo, OpenTofuClient, OpenTofuError};
pub use json_parser::ParseError;
#[derive(Debug)]
pub enum EmergencyDestroyError {
CommandExecution { source: std::io::Error },
DestroyFailed { stderr: String },
}
impl std::fmt::Display for EmergencyDestroyError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::CommandExecution { source } => {
write!(f, "Failed to execute OpenTofu destroy command: {source}")
}
Self::DestroyFailed { stderr } => {
write!(f, "OpenTofu destroy failed: {stderr}")
}
}
}
}
impl std::error::Error for EmergencyDestroyError {
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
match self {
Self::CommandExecution { source } => Some(source),
Self::DestroyFailed { .. } => None,
}
}
}
pub fn emergency_destroy<P: AsRef<Path>>(working_dir: P) -> Result<(), EmergencyDestroyError> {
use std::process::Command;
tracing::debug!(
"Emergency destroy: Executing `OpenTofu` destroy in directory: {}",
working_dir.as_ref().display()
);
let output = Command::new("tofu")
.args(["destroy", "-auto-approve"])
.current_dir(&working_dir)
.output()
.map_err(|source| EmergencyDestroyError::CommandExecution { source })?;
if output.status.success() {
tracing::debug!("Emergency destroy: `OpenTofu` destroy completed successfully");
Ok(())
} else {
let stderr = String::from_utf8_lossy(&output.stderr).to_string();
tracing::error!("Emergency destroy: `OpenTofu` destroy failed: {stderr}");
Err(EmergencyDestroyError::DestroyFailed { stderr })
}
}