From 37134f5e77d72f58e8a25f1551f13024978cca47 Mon Sep 17 00:00:00 2001 From: Lucas Kent Date: Mon, 22 Jul 2024 11:08:01 +1000 Subject: [PATCH] Tweaks for running on our system (#57) --- aws-throwaway/src/backend/cli/mod.rs | 24 ++++++++++++++---------- aws-throwaway/src/backend/sdk/aws.rs | 26 ++++++++++++++++++-------- aws-throwaway/src/lib.rs | 15 +++++++++++++-- 3 files changed, 45 insertions(+), 20 deletions(-) diff --git a/aws-throwaway/src/backend/cli/mod.rs b/aws-throwaway/src/backend/cli/mod.rs index be2aa6f..8d15c30 100644 --- a/aws-throwaway/src/backend/cli/mod.rs +++ b/aws-throwaway/src/backend/cli/mod.rs @@ -38,8 +38,6 @@ struct Subnet { map_public_ip_on_launch: Option, } -const AZ: &str = "us-east-1c"; - struct Tags { pub user_name: String, pub cleanup: CleanupResources, @@ -103,6 +101,7 @@ impl Tags { pub struct Aws { tags: Tags, keyname: String, + az_name: String, client_private_key: String, host_public_key: String, host_public_key_bytes: Vec, @@ -125,6 +124,7 @@ impl Aws { let keyname = format!("aws-throwaway-{user_name}-{}", Uuid::new_v4()); let security_group_name = format!("aws-throwaway-{user_name}-{}", Uuid::new_v4()); let placement_group_name = format!("aws-throwaway-{user_name}-{}", Uuid::new_v4()); + let az_name = builder.az_name.unwrap_or_else(|| "us-east-1c".into()); let tags = Tags { user_name, @@ -143,7 +143,7 @@ impl Aws { &builder.expose_ports_to_internet ), Aws::create_placement_group(&tags, &placement_group_name, builder.placement_strategy), - Aws::get_subnet(builder.subnet_id) + Aws::get_subnet(builder.subnet_id, az_name.clone()) ); let subnet_id = subnet.subnet_id.unwrap(); @@ -158,6 +158,7 @@ impl Aws { Aws { use_public_addresses, + az_name, keyname, client_private_key, host_public_key_bytes, @@ -300,13 +301,13 @@ impl Aws { tracing::info!("created placement group"); } - async fn get_subnet(subnet_id: Option) -> Subnet { + async fn get_subnet(subnet_id: Option, az_name: String) -> Subnet { let mut command = vec!["ec2", "describe-subnets", "--filters"]; // this is needed to keep the string values alive for the length of the borrow let value; - match subnet_id { + match &subnet_id { Some(subnet_id) => command.push({ value = format!("Name=subnet-id,Values={subnet_id}"); &value @@ -314,7 +315,7 @@ impl Aws { None => { command.push("Name=default-for-az,Values=true"); command.push({ - value = format!("Name=availability-zone,Values={AZ}"); + value = format!("Name=availability-zone,Values={az_name}"); &value }); } @@ -326,7 +327,10 @@ impl Aws { } let Response::Subnets(mut result) = run_command(&command).await.unwrap(); - result.pop().unwrap() + result.pop().unwrap_or_else(|| match subnet_id { + Some(subnet) => panic!("Subnet {subnet} could not be found"), + None => panic!("No default subnet configured for {az_name}"), + }) } /// Call before dropping [`Aws`] @@ -583,8 +587,8 @@ impl Aws { let tag_specifications = self.tags.create_tags("instance", "aws-throwaway"); let placement = format!( - "AvailabilityZone={AZ},GroupName={}", - self.placement_group_name + "AvailabilityZone={},GroupName={}", + self.az_name, self.placement_group_name ); // Secondary interfaces should not be used until they are configured. let mut bring_down_secondary_interfaces = String::new(); @@ -609,7 +613,7 @@ sudo systemctl start ssh self.host_public_key, self.host_private_key ); let block_device_mappings = format!( - "DeviceName=/dev/sda1,Ebs={{DeleteOnTermination=true,VolumeSize={},VolumeType=gp2}}", + "DeviceName=/dev/sda1,Ebs={{DeleteOnTermination=true,VolumeSize={},VolumeType=gp2,Encrypted=true}}", definition.volume_size_gb ); diff --git a/aws-throwaway/src/backend/sdk/aws.rs b/aws-throwaway/src/backend/sdk/aws.rs index 9faf558..704ade2 100644 --- a/aws-throwaway/src/backend/sdk/aws.rs +++ b/aws-throwaway/src/backend/sdk/aws.rs @@ -24,8 +24,6 @@ use std::pin::Pin; use std::time::{Duration, Instant}; use uuid::Uuid; -const AZ: &str = "us-east-1c"; - async fn config() -> SdkConfig { let region_provider = RegionProviderChain::first_try(Region::new("us-east-1")); aws_config::defaults(BehaviorVersion::latest()) @@ -37,6 +35,7 @@ async fn config() -> SdkConfig { /// Construct this type to create and cleanup aws resources. pub struct Aws { client: aws_sdk_ec2::Client, + az_name: String, keyname: String, client_private_key: String, host_public_key: String, @@ -57,6 +56,7 @@ impl Aws { let keyname = format!("aws-throwaway-{user_name}-{}", Uuid::new_v4()); let security_group_name = format!("aws-throwaway-{user_name}-{}", Uuid::new_v4()); let placement_group_name = format!("aws-throwaway-{user_name}-{}", Uuid::new_v4()); + let az_name = builder.az_name.unwrap_or_else(|| "us-east-1c".into()); let client = aws_sdk_ec2::Client::new(&config); let tags = Tags { @@ -83,7 +83,7 @@ impl Aws { &placement_group_name, builder.placement_strategy ), - Aws::get_subnet(&client, builder.subnet_id) + Aws::get_subnet(&client, builder.subnet_id, az_name.clone()) ); let subnet_id = subnet.subnet_id.unwrap(); @@ -99,6 +99,7 @@ impl Aws { Aws { use_public_addresses, client, + az_name, keyname, client_private_key, host_public_key_bytes, @@ -111,6 +112,7 @@ impl Aws { tags, } } + /// Returns an [`AwsBuilder`] that will build a new [`Aws`]. /// /// Before building the [`Aws`], all preexisting resources conforming to the specified [`CleanupResources`] approach are destroyed. @@ -248,8 +250,12 @@ impl Aws { tracing::info!("created placement group"); } - async fn get_subnet(client: &aws_sdk_ec2::Client, subnet_id: Option) -> Subnet { - match subnet_id { + async fn get_subnet( + client: &aws_sdk_ec2::Client, + subnet_id: Option, + az_name: String, + ) -> Subnet { + match &subnet_id { Some(subnet_id) => client.describe_subnets().filters( Filter::builder() .name("subnet-id") @@ -267,7 +273,7 @@ impl Aws { .filters( Filter::builder() .name("availability-zone") - .values(AZ) + .values(&az_name) .build(), ), } @@ -278,7 +284,10 @@ impl Aws { .subnets .unwrap() .pop() - .unwrap() + .unwrap_or_else(|| match subnet_id { + Some(subnet) => panic!("Subnet {subnet} could not be found"), + None => panic!("No default subnet configured for {az_name}"), + }) } /// Call before dropping [`Aws`] @@ -500,7 +509,7 @@ impl Aws { .set_placement(Some( Placement::builder() .group_name(&self.placement_group_name) - .availability_zone(AZ) + .availability_zone(&self.az_name) .build(), )) .set_subnet_id(if definition.network_interface_count == 1 { @@ -518,6 +527,7 @@ impl Aws { .delete_on_termination(true) .volume_size(definition.volume_size_gb as i32) .volume_type(VolumeType::Gp2) + .encrypted(true) .build(), ) .build(), diff --git a/aws-throwaway/src/lib.rs b/aws-throwaway/src/lib.rs index 798a8fc..74e9755 100644 --- a/aws-throwaway/src/lib.rs +++ b/aws-throwaway/src/lib.rs @@ -16,6 +16,7 @@ pub struct AwsBuilder { cleanup: CleanupResources, use_public_addresses: bool, vpc_id: Option, + az_name: Option, subnet_id: Option, placement_strategy: PlacementStrategy, security_group_id: Option, @@ -28,8 +29,8 @@ pub struct AwsBuilder { /// * you want to connect directly from within the VPC /// * you have already created a specific VPC, subnet or security group that you want aws-throwaway to make use of. /// -/// All resources will be created in us-east-1c. -/// This is hardcoded so that aws-throawaway only has to look into one region when cleaning up. +/// All resources will be created in us-east-1. +/// This is hardcoded so that aws-throwaway only has to look into one region when cleaning up. /// All instances are created in a single spread placement group in a single AZ to ensure consistent latency between instances. // TODO: document minimum required access for default configuration. impl AwsBuilder { @@ -38,6 +39,7 @@ impl AwsBuilder { cleanup, use_public_addresses: true, vpc_id: None, + az_name: None, subnet_id: None, // refer to: https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/placement-groups.html // I believe Spread is the best default since it is the easiest for amazon to fulfill and gives the most realistic results in benchmarks. @@ -71,6 +73,15 @@ impl AwsBuilder { self } + /// * Some(_) => All resources will go into the specified AZ + /// * None => All resources will go into the default AZ (us-east-1c) + /// + /// The default is `None` + pub fn use_az(mut self, az_name: Option) -> Self { + self.az_name = az_name; + self + } + /// * Some(_) => All instances will go into the specified subnet /// * None => All instances will go into the default subnet for the specified or default vpc ///