korasi_cli/
create.rs

1use std::fs::read_to_string;
2
3use aws_sdk_ec2::types::{InstanceType, KeyFormat, KeyType};
4use base64::prelude::*;
5use petname::{Generator, Petnames};
6
7use crate::ec2::SSH_KEY_NAME;
8
9use super::ec2::{EC2Error, EC2Impl as EC2};
10use super::util::UtilImpl as Util;
11
12#[derive(Default)]
13pub struct CreateCommand;
14
15impl CreateCommand {
16    pub async fn launch(
17        &self,
18        ec2: &EC2,
19        machine: InstanceType,
20        ami_id: String,
21        ssh_path: String,
22        setup: String,
23    ) -> Result<(), EC2Error> {
24        let info = match ec2
25            .create_key_pair(SSH_KEY_NAME, KeyType::Ed25519, KeyFormat::Pem)
26            .await
27        {
28            Ok((info, material)) => {
29                tracing::info!("Saving PK to file...");
30
31                // Save private key.
32                Util::write_secure(&ssh_path.into(), material, 0o400)?;
33
34                Some(info)
35            }
36            Err(err) => {
37                // NOTE: This assumes user already saved the private key locally.
38                tracing::warn!("No key pair is created. Err = {}", err);
39                let output = ec2.list_key_pair(SSH_KEY_NAME).await?;
40                if !output.is_empty() {
41                    tracing::info!(
42                        "Reuse existing key pair: {:?}",
43                        output[0].key_name.as_ref().unwrap()
44                    );
45                    Some(output[0].clone())
46                } else {
47                    tracing::error!("No instance is created since no existing key pair is found.");
48                    None
49                }
50            }
51        };
52
53        let group = ec2.get_ssh_security_group().await?;
54        tracing::info!("Security Group used = {:?}", group.group_id);
55
56        let user_data = read_to_string(setup)
57            .map(|data| BASE64_STANDARD.encode(data.as_bytes()))
58            .ok();
59        tracing::info!("User data: {:?}", user_data);
60
61        let name = Petnames::default().generate_one(1, ":").unwrap();
62
63        let _instance_ids = ec2
64            .create_instances(
65                &name,
66                &ami_id,
67                machine,
68                &info.unwrap(),
69                vec![&group],
70                user_data,
71            )
72            .await?;
73        tracing::info!("Created instance with name = {}", name);
74
75        Ok(())
76    }
77}