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 Util::write_secure(&ssh_path.into(), material, 0o400)?;
33
34 Some(info)
35 }
36 Err(err) => {
37 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}