use thiserror::Error;
use tracing::info;
use crate::application::command_handlers::destroy::DestroyCommandHandlerError;
use crate::application::command_handlers::DestroyCommandHandler;
use crate::testing::e2e::context::TestContext;
#[derive(Debug, Error)]
pub enum DestroyTaskError {
#[error(
"Failed to destroy infrastructure: {source}
Tip: Check OpenTofu logs in the build directory for detailed error information"
)]
DestructionFailed {
#[source]
source: DestroyCommandHandlerError,
},
}
impl DestroyTaskError {
#[must_use]
pub fn help(&self) -> &'static str {
match self {
Self::DestructionFailed { .. } => {
"Destruction Failed - Detailed Troubleshooting:
1. Check OpenTofu logs in the build directory:
- Review terraform.log for detailed error messages
- Look for resource deletion conflicts or permission errors
2. Verify infrastructure state:
- Ensure infrastructure resources still exist
- Check that OpenTofu state files are intact
- Verify network connectivity to infrastructure providers
3. Check for resource locks:
- Ensure no other processes are accessing the resources
- Verify that no manual holds exist on resources
- Check for dependency issues preventing deletion
4. Manual cleanup may be required if destroy fails:
- Review OpenTofu state to identify remaining resources
- Use provider-specific tools (e.g., lxc commands) for manual cleanup
- Remove state files after manual cleanup is complete
For more information, see docs/e2e-testing/ and docs/vm-providers.md."
}
}
}
}
pub fn run_destroy_command(test_context: &mut TestContext) -> Result<(), DestroyTaskError> {
if test_context.keep_env {
let instance_name = &test_context.environment.instance_name();
info!(
operation = "destroy",
action = "keep_environment",
instance = %instance_name,
connect_command = format!("lxc exec {} -- /bin/bash", instance_name),
"Keeping test environment as requested (destruction skipped)"
);
return Ok(());
}
info!("Destroying test infrastructure");
let repository = test_context.create_repository();
let clock = std::sync::Arc::new(crate::shared::SystemClock);
let destroy_command_handler = DestroyCommandHandler::new(repository, clock);
let env_name = test_context.environment.name();
let destroyed_env = destroy_command_handler
.execute(env_name)
.map_err(|source| DestroyTaskError::DestructionFailed { source })?;
info!(
status = "complete",
environment = %destroyed_env.name(),
"Infrastructure destroyed successfully"
);
test_context.update_from_destroyed(destroyed_env);
Ok(())
}