Skip to content

Commit

Permalink
Add API to create instances with multiple network interfaces (#15)
Browse files Browse the repository at this point in the history
  • Loading branch information
rukai authored Oct 17, 2023
1 parent 84baafd commit c06cf57
Show file tree
Hide file tree
Showing 5 changed files with 224 additions and 28 deletions.
28 changes: 28 additions & 0 deletions aws-throwaway/examples/aws-throwaway-test-multiple-instances.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
use aws_throwaway::{Aws, CleanupResources, Ec2InstanceDefinition, InstanceType};
use tracing_subscriber::EnvFilter;

#[tokio::main]
async fn main() {
let (non_blocking, _guard) = tracing_appender::non_blocking(std::io::stdout());
tracing_subscriber::fmt()
.with_env_filter(EnvFilter::from_default_env())
.with_writer(non_blocking)
.init();

println!("Creating instances");
let aws = Aws::new(CleanupResources::AllResources).await;
let (instance1, instance2) = tokio::join!(
aws.create_ec2_instance(Ec2InstanceDefinition::new(InstanceType::T2Small)),
aws.create_ec2_instance(
Ec2InstanceDefinition::new(InstanceType::T2Small).network_interface_count(2)
)
);

println!("pinging instance2 from instance1");
let ip = instance2.private_ip();
let output = instance1.ssh().shell(&format!("ping {ip} -c 4")).await;
println!("{output}");

aws.cleanup_resources().await;
println!("\nAll AWS throwaway resources have been deleted")
}
5 changes: 5 additions & 0 deletions aws-throwaway/examples/create-instance.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,12 @@ async fn main() {

let aws = Aws::new(CleanupResources::WithAppTag(AWS_THROWAWAY_TAG.to_owned())).await;
let instance_type = InstanceType::from_str(&instance_type).unwrap();
let network_interface_count = args.network_interfaces;
let instance = aws
.create_ec2_instance(
Ec2InstanceDefinition::new(instance_type)
.volume_size_gigabytes(20)
.network_interface_count(network_interface_count)
.os(args.instance_os.to_aws()),
)
.await;
Expand All @@ -50,6 +52,9 @@ pub struct Args {
#[clap(long)]
pub instance_type: Option<String>,

#[clap(long, default_value_t = 1)]
pub network_interfaces: u32,

#[clap(long)]
pub instance_os: InstanceOs,

Expand Down
21 changes: 17 additions & 4 deletions aws-throwaway/src/ec2_instance.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
use std::{net::IpAddr, time::Duration};

use tokio::{net::TcpStream, time::Instant};

use crate::ssh::SshConnection;
use std::net::{IpAddr, Ipv4Addr};
use std::time::Duration;
use tokio::{net::TcpStream, time::Instant};

/// Represents a currently running EC2 instance and provides various methods for interacting with the instance.
pub struct Ec2Instance {
Expand All @@ -12,6 +11,12 @@ pub struct Ec2Instance {
host_public_key_bytes: Vec<u8>,
host_public_key: String,
ssh: SshConnection,
network_interfaces: Vec<NetworkInterface>,
}

pub struct NetworkInterface {
pub private_ipv4: Ipv4Addr,
pub device_index: i32,
}

impl Ec2Instance {
Expand All @@ -25,6 +30,12 @@ impl Ec2Instance {
self.private_ip
}

/// List of all network interfaces attached to this instance.
/// Includes the primary interface that has the ip returned by [`Ec2Instance::private_ip`] as well as all other interfaces attached to this instance at the time it was created.
pub fn network_interfaces(&self) -> &[NetworkInterface] {
&self.network_interfaces
}

/// Use this as the private key of your machine when connecting to this instance
pub fn client_private_key(&self) -> &str {
&self.client_private_key
Expand Down Expand Up @@ -67,6 +78,7 @@ TERM=xterm ssh -i key ubuntu@{} -o "UserKnownHostsFile known_hosts"
host_public_key_bytes: Vec<u8>,
host_public_key: String,
client_private_key: &str,
network_interfaces: Vec<NetworkInterface>,
) -> Self {
loop {
let start = Instant::now();
Expand Down Expand Up @@ -111,6 +123,7 @@ TERM=xterm ssh -i key ubuntu@{} -o "UserKnownHostsFile known_hosts"
host_public_key_bytes,
host_public_key,
client_private_key: client_private_key.to_owned(),
network_interfaces,
};
}
};
Expand Down
15 changes: 14 additions & 1 deletion aws-throwaway/src/ec2_instance_definition.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ use aws_sdk_ec2::types::InstanceType;
pub struct Ec2InstanceDefinition {
pub(crate) instance_type: InstanceType,
pub(crate) volume_size_gb: u32,
pub(crate) network_interface_count: u32,
pub(crate) os: InstanceOs,
}

Expand All @@ -13,7 +14,8 @@ impl Ec2InstanceDefinition {
Ec2InstanceDefinition {
instance_type,
volume_size_gb: 8,
os: InstanceOs::Ubuntu20_04,
network_interface_count: 1,
os: InstanceOs::Ubuntu22_04,
}
}

Expand All @@ -24,6 +26,17 @@ impl Ec2InstanceDefinition {
self
}

/// Sets the amount of network interfaces to use on this instance.
/// Defaults to 1
///
/// Setting this to a value other than 1 will result in the creation of an elastic ip to point at your instance.
/// This is an unfortunate requirement of AWS ECS, instances with multiple network interfaces do not get the automatically assigned ipv4 address given to instances with 1 network interface.
/// For most users there is a hard limit of 5 elastic ip addresses allowed at one time.
pub fn network_interface_count(mut self, count: u32) -> Self {
self.network_interface_count = count;
self
}

// Set the OS used by the instance.
// Defaults to `Ubuntu 22.04`
pub fn os(mut self, os: InstanceOs) -> Self {
Expand Down
Loading

0 comments on commit c06cf57

Please sign in to comment.