Skip to main content

stack_deploy/
cli.rs

1use crate::instance_spec::{Registry, TemplateUploader};
2
3#[derive(Clone, Debug, clap::Parser)]
4pub struct App {
5    #[clap(subcommand)]
6    command: Command,
7}
8
9impl App {
10    pub async fn run(&self, config: &Config<'_>) {
11        self.command.run(config).await
12    }
13}
14
15pub struct Config<'a> {
16    pub cloudformation: &'a aws_sdk_cloudformation::client::Client,
17    pub registry: &'a Registry,
18    pub template_uploader: Option<&'a TemplateUploader<'a>>,
19}
20
21#[derive(Clone, Debug, Eq, PartialEq, clap::Parser)]
22pub enum Command {
23    Instance(Box<crate::cli::instance::App>),
24}
25
26impl Command {
27    pub async fn run(&self, config: &Config<'_>) {
28        match self {
29            Self::Instance(command) => command.run(config).await,
30        }
31    }
32}
33
34mod instance {
35    use crate::instance_spec::ReviewChangeSet;
36    use crate::types::*;
37
38    #[derive(Clone, Debug, Eq, PartialEq, clap::Parser)]
39    pub struct App {
40        #[clap(subcommand)]
41        command: Command,
42    }
43
44    impl App {
45        pub async fn run(&self, config: &super::Config<'_>) {
46            self.command.run(config).await
47        }
48    }
49
50    #[derive(Clone, Debug, Eq, PartialEq, clap::Parser)]
51    pub enum ChangeSetCommand {
52        Create {
53            #[arg(long)]
54            change_set_name: ChangeSetName,
55            #[arg(long = "parameter")]
56            parameters: Vec<Parameter>,
57        },
58        Delete {
59            #[arg(long)]
60            change_set_name: ChangeSetName,
61        },
62        Describe {
63            #[arg(long)]
64            change_set_name: ChangeSetName,
65        },
66        List,
67    }
68
69    #[derive(Clone, Debug, Eq, PartialEq, clap::Parser)]
70    pub enum Command {
71        ChangeSet {
72            #[arg(long = "stack-name")]
73            name: StackName,
74            #[clap(subcommand)]
75            command: ChangeSetCommand,
76        },
77        /// Delete stack instance
78        Delete {
79            #[arg(long = "stack-name")]
80            name: StackName,
81        },
82        /// List registered stack instances
83        List,
84        /// Update stack template, fails if absent
85        Update {
86            #[arg(long = "stack-name")]
87            name: StackName,
88            #[arg(long = "parameter")]
89            parameters: Vec<Parameter>,
90            #[arg(long, default_value = "interactive")]
91            review_change_set: ReviewChangeSet,
92        },
93        /// Update stack template, fails if absent
94        /// Sync stack instance, creates if absent, template updates is missing
95        Sync {
96            #[arg(long = "stack-name")]
97            name: StackName,
98            #[arg(long = "parameter")]
99            parameters: Vec<Parameter>,
100            #[arg(long, default_value = "interactive")]
101            review_change_set: ReviewChangeSet,
102        },
103        /// Watch stack events
104        Watch {
105            #[arg(long = "stack-name")]
106            name: StackName,
107        },
108    }
109
110    impl Command {
111        pub async fn run(&self, config: &super::Config<'_>) {
112            let fetch_context = |name| {
113                config
114                    .registry
115                    .find(name)
116                    .expect("registered instance spec")
117                    .context(config.cloudformation, config.template_uploader)
118            };
119
120            match self {
121                Self::ChangeSet {
122                    name,
123                    command:
124                        ChangeSetCommand::Create {
125                            change_set_name,
126                            parameters,
127                        },
128                } => {
129                    let parameter_map = ParameterMap::parse(parameters).unwrap();
130                    fetch_context(name)
131                        .create_change_set(change_set_name, &parameter_map)
132                        .await;
133                }
134                Self::ChangeSet {
135                    name,
136                    command: ChangeSetCommand::Delete { change_set_name },
137                } => {
138                    fetch_context(name).delete_change_set(change_set_name).await;
139                }
140                Self::ChangeSet {
141                    name,
142                    command: ChangeSetCommand::Describe { change_set_name },
143                } => {
144                    fetch_context(name)
145                        .describe_change_set(change_set_name)
146                        .await;
147                }
148                Self::ChangeSet {
149                    name,
150                    command: ChangeSetCommand::List,
151                } => fetch_context(name).list_change_sets().await,
152                Self::Delete { name } => fetch_context(name).delete().await,
153                Self::List => config
154                    .registry
155                    .0
156                    .iter()
157                    .for_each(|instance_spec| println!("{}", instance_spec.stack_name.0)),
158                Self::Sync {
159                    name,
160                    parameters,
161                    review_change_set,
162                } => {
163                    let parameter_map = ParameterMap::parse(parameters).unwrap();
164
165                    fetch_context(name)
166                        .sync(review_change_set, &parameter_map)
167                        .await
168                }
169                Self::Update {
170                    name,
171                    parameters,
172                    review_change_set,
173                } => {
174                    let parameter_map = ParameterMap::parse(parameters).unwrap();
175
176                    fetch_context(name)
177                        .update(review_change_set, &parameter_map)
178                        .await
179                }
180                Self::Watch { name } => {
181                    crate::instance_spec::InstanceSpec::watch(
182                        config.cloudformation,
183                        crate::stack::load_stack_id(config.cloudformation, name).await,
184                    )
185                    .await
186                }
187            }
188        }
189    }
190}