rusty_cdk/
destroy.rs

1use aws_sdk_cloudformation::Client;
2use rusty_cdk_core::wrappers::StringWithOnlyAlphaNumericsAndHyphens;
3use std::error::Error;
4use std::fmt::{Display, Formatter};
5use std::process::exit;
6use std::time::Duration;
7use aws_sdk_cloudformation::types::StackStatus;
8use tokio::time::sleep;
9use crate::util::{get_stack_status, load_config};
10
11#[derive(Debug)]
12pub enum DestroyError {
13    StackDeleteError(String),
14    UnknownError(String),
15}
16
17impl Error for DestroyError {}
18
19impl Display for DestroyError {
20    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
21        match self {
22            DestroyError::StackDeleteError(_) => f.write_str("unable to delete stack"),
23            DestroyError::UnknownError(_) => f.write_str("unknown error"),
24        }
25    }
26}
27
28/// Destroy a deployed stack
29pub async fn destroy(name: StringWithOnlyAlphaNumericsAndHyphens) {
30    let name = name.0;
31    let config = load_config().await;
32    let cloudformation_client = Client::new(&config);
33
34    match destroy_stack(&name, &cloudformation_client).await {
35        Ok(()) => {},
36        Err(e) => {
37            eprintln!("{:?}", e);
38            exit(1);
39        }
40    }
41
42    loop {
43        let status = get_stack_status(&name, &cloudformation_client).await;
44
45        if let Some(status) = status {
46            match status {
47                StackStatus::DeleteComplete => {
48                    println!("destroy completed successfully!");
49                    exit(0);
50                }
51                StackStatus::DeleteInProgress => {
52                    println!("destroying...");
53                }
54                StackStatus::DeleteFailed => {
55                    println!("destroy failed");
56                    exit(1);
57                }
58                _ => {
59                    println!("encountered unexpected cloudformation status: {status}");
60                    exit(1);
61                }
62            }
63        } else {
64            // no status, so stack should be gone
65            println!("destroy completed successfully!");
66            exit(0);
67        }
68
69        sleep(Duration::from_secs(10)).await;
70    }
71}
72
73/// Destroy a deployed stack
74///
75/// It returns a `Result`. In case of error, a `DestroyError` is returned.
76pub async fn destroy_with_result(name: StringWithOnlyAlphaNumericsAndHyphens) -> Result<(), DestroyError> {
77    let name = name.0;
78    let config = load_config().await;
79    let cloudformation_client = Client::new(&config);
80
81    destroy_stack(&name, &cloudformation_client).await?;
82
83    loop {
84        let status = get_stack_status(&name, &cloudformation_client).await;
85        
86        if let Some(status) = status {
87            match status {
88                StackStatus::DeleteComplete => {
89                    return Ok(())
90                }
91                StackStatus::DeleteInProgress => {}
92                StackStatus::DeleteFailed => {
93                    return Err(DestroyError::StackDeleteError(format!("{status}")));
94                }
95                _ => {
96                    return Err(DestroyError::UnknownError(format!("{status}")));
97                }
98            }
99        } else {
100            // no status, so stack should be gone
101            return Ok(())
102        }
103
104        sleep(Duration::from_secs(10)).await;
105    }
106}
107
108async fn destroy_stack(name: &String, cloudformation_client: &Client) -> Result<(), DestroyError> {
109    let delete_result = cloudformation_client
110        .delete_stack()
111        .stack_name(name)
112        .send()
113        .await;
114    match delete_result {
115        Ok(_) => Ok(()),
116        Err(e) => Err(DestroyError::StackDeleteError(e.to_string()))
117    }
118}