korasi_cli/
create.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
use std::fs::read_to_string;

use aws_sdk_ec2::types::{InstanceType, KeyFormat, KeyType};
use base64::prelude::*;
use petname::{Generator, Petnames};

use crate::ec2::SSH_KEY_NAME;

use super::ec2::{EC2Error, EC2Impl as EC2};
use super::util::UtilImpl as Util;

#[derive(Default)]
pub struct CreateCommand;

impl CreateCommand {
    pub async fn launch(
        &self,
        ec2: &EC2,
        machine: InstanceType,
        ami_id: String,
        ssh_path: String,
        setup: String,
    ) -> Result<(), EC2Error> {
        let info = match ec2
            .create_key_pair(SSH_KEY_NAME, KeyType::Ed25519, KeyFormat::Pem)
            .await
        {
            Ok((info, material)) => {
                tracing::info!("Saving PK to file...");

                // Save private key.
                Util::write_secure(&ssh_path.into(), material, 0o400)?;

                Some(info)
            }
            Err(err) => {
                // NOTE: This assumes user already saved the private key locally.
                tracing::warn!("No key pair is created. Err = {}", err);
                let output = ec2.list_key_pair(SSH_KEY_NAME).await?;
                if !output.is_empty() {
                    tracing::info!(
                        "Reuse existing key pair: {:?}",
                        output[0].key_name.as_ref().unwrap()
                    );
                    Some(output[0].clone())
                } else {
                    tracing::error!("No instance is created since no existing key pair is found.");
                    None
                }
            }
        };

        let group = ec2.get_ssh_security_group().await?;
        tracing::info!("Security Group used = {:?}", group.group_id);

        let user_data = read_to_string(setup)
            .map(|data| BASE64_STANDARD.encode(data.as_bytes()))
            .ok();
        tracing::info!("User data: {:?}", user_data);

        let name = Petnames::default().generate_one(1, ":").unwrap();

        let _instance_ids = ec2
            .create_instances(
                &name,
                &ami_id,
                machine,
                &info.unwrap(),
                vec![&group],
                user_data,
            )
            .await?;
        tracing::info!("Created instance with name = {}", name);

        Ok(())
    }
}