Skip to main content

rusty_cdk/
diff.rs

1use std::process::exit;
2use aws_sdk_cloudformation::Client;
3use rusty_cdk_core::stack::{Stack, StackDiff};
4use rusty_cdk_core::wrappers::StringWithOnlyAlphaNumericsAndHyphens;
5use crate::util::{get_existing_template, load_config};
6
7/// Creates a diff that will show what ids are being added / removed to an existing stack, as well as showing ids that remain without being added or removed.
8/// Currently, the diff does not show modifications to resources.
9/// 
10/// # Parameters
11///
12/// * `name` - The existing CloudFormation stack name
13/// * `stack` - The new stack
14///
15/// # AWS Credentials
16///
17/// This function requires valid AWS credentials.
18/// The AWS credentials must have permissions for:
19/// - `cloudformation:DescribeStacks`, `cloudformation:GetTemplate`
20#[allow(unused)]
21pub async fn diff(name: StringWithOnlyAlphaNumericsAndHyphens, stack: Stack) {
22    match diff_with_result(name, stack).await {
23        Ok(res) => {
24            println!("{res}");
25        }
26        Err(e) => {
27            eprintln!("{e}");
28            exit(1);
29        }
30    }
31}
32
33pub async fn diff_with_result(name: StringWithOnlyAlphaNumericsAndHyphens, stack: Stack) -> Result<String, String> {
34    let config = load_config(false).await;
35    let cloudformation_client = Client::new(&config);
36
37    match get_existing_template(&cloudformation_client, &name.0).await {
38        None => {
39            Err(format!("could not find existing stack with name {}", name.0))
40        }
41        Some(existing) => {
42            let diff = stack.get_diff(&existing);
43
44            match diff {
45                Ok(diff) => {
46                    let StackDiff { new_ids, unchanged_ids, ids_to_be_removed} = diff;
47                    let output = format!("- added ids: {}\n- removed ids: {}\n- ids that stay: {}", print_ids(new_ids), print_ids(ids_to_be_removed), print_ids(unchanged_ids));
48                    Ok(output)
49                }
50                Err(e) => {
51                    Err(e)
52                }
53            }
54        }
55    }
56}
57
58fn print_ids(ids: Vec<(String, String)>) -> String {
59    if ids.is_empty() {
60        "(none)".to_string()
61    } else {
62        ids.into_iter().map(|v| format!("{} (resource {})", v.0, v.1)).collect::<Vec<_>>().join(", ")
63    }
64}