Sono disponibili altri esempi AWS SDK nel repository AWS Doc SDK
Le traduzioni sono generate tramite traduzione automatica. In caso di conflitto tra il contenuto di una traduzione e la versione originale in Inglese, quest'ultima prevarrà.
EC2 Esempi di Amazon che utilizzano SDK per Rust
I seguenti esempi di codice mostrano come eseguire azioni e implementare scenari comuni utilizzando l' AWS SDK per Rust con Amazon EC2.
Le nozioni di base sono esempi di codice che mostrano come eseguire le operazioni essenziali all'interno di un servizio.
Le operazioni sono estratti di codice da programmi più grandi e devono essere eseguite nel contesto. Sebbene le operazioni mostrino come richiamare le singole funzioni del servizio, è possibile visualizzarle contestualizzate negli scenari correlati.
Ogni esempio include un collegamento al codice sorgente completo, dove puoi trovare istruzioni su come configurare ed eseguire il codice nel contesto.
Nozioni di base
I seguenti esempi di codice mostrano come iniziare a usare Amazon EC2.
- SDK per Rust
-
Nota
C'è altro su GitHub. Trova l'esempio completo e scopri di più sulla configurazione e l'esecuzione nel Repository di esempi di codice AWS
. async fn show_security_groups(client: &aws_sdk_ec2::Client, group_ids: Vec<String>) { let response = client .describe_security_groups() .set_group_ids(Some(group_ids)) .send() .await; match response { Ok(output) => { for group in output.security_groups() { println!( "Found Security Group {} ({}), vpc id {} and description {}", group.group_name().unwrap_or("unknown"), group.group_id().unwrap_or("id-unknown"), group.vpc_id().unwrap_or("vpcid-unknown"), group.description().unwrap_or("(none)") ); } } Err(err) => { let err = err.into_service_error(); let meta = err.meta(); let message = meta.message().unwrap_or("unknown"); let code = meta.code().unwrap_or("unknown"); eprintln!("Error listing EC2 Security Groups: ({code}) {message}"); } } }
-
Per i dettagli sulle API, consulta il riferimento DescribeSecurityGroups
all'API AWS SDK for Rust.
-
Argomenti
Nozioni di base
L'esempio di codice seguente mostra come:
Creare una coppia di chiavi e un gruppo di sicurezza.
Selezionare un'Amazon Machine Image (AMI) e un tipo di istanza compatibile e quindi creare un'istanza.
Arrestare e riavviare l'istanza.
Associazione di un indirizzo IP elastico all'istanza
Connettiti alla tua istanza con SSH, quindi elimina le risorse.
- SDK per Rust
-
Nota
C'è altro su. GitHub Trova l'esempio completo e scopri di più sulla configurazione e l'esecuzione nel Repository di esempi di codice AWS
. L' EC2InstanceScenario implementazione contiene la logica per eseguire l'esempio nel suo insieme.
//! Scenario that uses the AWS SDK for Rust (the SDK) with Amazon Elastic Compute Cloud //! (Amazon EC2) to do the following: //! //! * Create a key pair that is used to secure SSH communication between your computer and //! an EC2 instance. //! * Create a security group that acts as a virtual firewall for your EC2 instances to //! control incoming and outgoing traffic. //! * Find an Amazon Machine Image (AMI) and a compatible instance type. //! * Create an instance that is created from the instance type and AMI you select, and //! is configured to use the security group and key pair created in this example. //! * Stop and restart the instance. //! * Create an Elastic IP address and associate it as a consistent IP address for your instance. //! * Connect to your instance with SSH, using both its public IP address and your Elastic IP //! address. //! * Clean up all of the resources created by this example. use std::net::Ipv4Addr; use crate::{ ec2::{EC2Error, EC2}, getting_started::{key_pair::KeyPairManager, util::Util}, ssm::SSM, }; use aws_sdk_ssm::types::Parameter; use super::{ elastic_ip::ElasticIpManager, instance::InstanceManager, security_group::SecurityGroupManager, util::ScenarioImage, }; pub struct Ec2InstanceScenario { ec2: EC2, ssm: SSM, util: Util, key_pair_manager: KeyPairManager, security_group_manager: SecurityGroupManager, instance_manager: InstanceManager, elastic_ip_manager: ElasticIpManager, } impl Ec2InstanceScenario { pub fn new(ec2: EC2, ssm: SSM, util: Util) -> Self { Ec2InstanceScenario { ec2, ssm, util, key_pair_manager: Default::default(), security_group_manager: Default::default(), instance_manager: Default::default(), elastic_ip_manager: Default::default(), } } pub async fn run(&mut self) -> Result<(), EC2Error> { self.create_and_list_key_pairs().await?; self.create_security_group().await?; self.create_instance().await?; self.stop_and_start_instance().await?; self.associate_elastic_ip().await?; self.stop_and_start_instance().await?; Ok(()) } /// 1. Creates an RSA key pair and saves its private key data as a .pem file in secure /// temporary storage. The private key data is deleted after the example completes. /// 2. Optionally, lists the first five key pairs for the current account. pub async fn create_and_list_key_pairs(&mut self) -> Result<(), EC2Error> { println!( "Let's create an RSA key pair that you can be use to securely connect to your EC2 instance."); let key_name = self.util.prompt_key_name()?; self.key_pair_manager .create(&self.ec2, &self.util, key_name) .await?; println!( "Created a key pair {} and saved the private key to {:?}.", self.key_pair_manager .key_pair() .key_name() .ok_or_else(|| EC2Error::new("No key name after creating key"))?, self.key_pair_manager .key_file_path() .ok_or_else(|| EC2Error::new("No key file after creating key"))? ); if self.util.should_list_key_pairs()? { for pair in self.key_pair_manager.list(&self.ec2).await? { println!( "Found {:?} key {} with fingerprint:\t{:?}", pair.key_type(), pair.key_name().unwrap_or("Unknown"), pair.key_fingerprint() ); } } Ok(()) } /// 1. Creates a security group for the default VPC. /// 2. Adds an inbound rule to allow SSH. The SSH rule allows only /// inbound traffic from the current computer’s public IPv4 address. /// 3. Displays information about the security group. /// /// This function uses <http://checkip.amazonaws.com> to get the current public IP /// address of the computer that is running the example. This method works in most /// cases. However, depending on how your computer connects to the internet, you /// might have to manually add your public IP address to the security group by using /// the AWS Management Console. pub async fn create_security_group(&mut self) -> Result<(), EC2Error> { println!("Let's create a security group to manage access to your instance."); let group_name = self.util.prompt_security_group_name()?; self.security_group_manager .create( &self.ec2, &group_name, "Security group for example: get started with instances.", ) .await?; println!( "Created security group {} in your default VPC {}.", self.security_group_manager.group_name(), self.security_group_manager .vpc_id() .unwrap_or("(unknown vpc)") ); let check_ip = self.util.do_get("https://checkip.amazonaws.com").await?; let current_ip_address: Ipv4Addr = check_ip.trim().parse().map_err(|e| { EC2Error::new(format!( "Failed to convert response {} to IP Address: {e:?}", check_ip )) })?; println!("Your public IP address seems to be {current_ip_address}"); if self.util.should_add_to_security_group() { match self .security_group_manager .authorize_ingress(&self.ec2, current_ip_address) .await { Ok(_) => println!("Security group rules updated"), Err(err) => eprintln!("Couldn't update security group rules: {err:?}"), } } println!("{}", self.security_group_manager); Ok(()) } /// 1. Gets a list of Amazon Linux 2 AMIs from AWS Systems Manager. Specifying the /// '/aws/service/ami-amazon-linux-latest' path returns only the latest AMIs. /// 2. Gets and displays information about the available AMIs and lets you select one. /// 3. Gets a list of instance types that are compatible with the selected AMI and /// lets you select one. /// 4. Creates an instance with the previously created key pair and security group, /// and the selected AMI and instance type. /// 5. Waits for the instance to be running and then displays its information. pub async fn create_instance(&mut self) -> Result<(), EC2Error> { let ami = self.find_image().await?; let instance_types = self .ec2 .list_instance_types(&ami.0) .await .map_err(|e| e.add_message("Could not find instance types"))?; println!( "There are several instance types that support the {} architecture of the image.", ami.0 .architecture .as_ref() .ok_or_else(|| EC2Error::new(format!("Missing architecture in {:?}", ami.0)))? ); let instance_type = self.util.select_instance_type(instance_types)?; println!("Creating your instance and waiting for it to start..."); self.instance_manager .create( &self.ec2, ami.0 .image_id() .ok_or_else(|| EC2Error::new("Could not find image ID"))?, instance_type, self.key_pair_manager.key_pair(), self.security_group_manager .security_group() .map(|sg| vec![sg]) .ok_or_else(|| EC2Error::new("Could not find security group"))?, ) .await .map_err(|e| e.add_message("Scenario failed to create instance"))?; while let Err(err) = self .ec2 .wait_for_instance_ready(self.instance_manager.instance_id(), None) .await { println!("{err}"); if !self.util.should_continue_waiting() { return Err(err); } } println!("Your instance is ready:\n{}", self.instance_manager); self.display_ssh_info(); Ok(()) } async fn find_image(&mut self) -> Result<ScenarioImage, EC2Error> { let params: Vec<Parameter> = self .ssm .list_path("/aws/service/ami-amazon-linux-latest") .await .map_err(|e| e.add_message("Could not find parameters for available images"))? .into_iter() .filter(|param| param.name().is_some_and(|name| name.contains("amzn2"))) .collect(); let amzn2_images: Vec<ScenarioImage> = self .ec2 .list_images(params) .await .map_err(|e| e.add_message("Could not find images"))? .into_iter() .map(ScenarioImage::from) .collect(); println!("We will now create an instance from an Amazon Linux 2 AMI"); let ami = self.util.select_scenario_image(amzn2_images)?; Ok(ami) } // 1. Stops the instance and waits for it to stop. // 2. Starts the instance and waits for it to start. // 3. Displays information about the instance. // 4. Displays an SSH connection string. When an Elastic IP address is associated // with the instance, the IP address stays consistent when the instance stops // and starts. pub async fn stop_and_start_instance(&self) -> Result<(), EC2Error> { println!("Let's stop and start your instance to see what changes."); println!("Stopping your instance and waiting until it's stopped..."); self.instance_manager.stop(&self.ec2).await?; println!("Your instance is stopped. Restarting..."); self.instance_manager.start(&self.ec2).await?; println!("Your instance is running."); println!("{}", self.instance_manager); if self.elastic_ip_manager.public_ip() == "0.0.0.0" { println!("Every time your instance is restarted, its public IP address changes."); } else { println!( "Because you have associated an Elastic IP with your instance, you can connect by using a consistent IP address after the instance restarts." ); } self.display_ssh_info(); Ok(()) } /// 1. Allocates an Elastic IP address and associates it with the instance. /// 2. Displays an SSH connection string that uses the Elastic IP address. async fn associate_elastic_ip(&mut self) -> Result<(), EC2Error> { self.elastic_ip_manager.allocate(&self.ec2).await?; println!( "Allocated static Elastic IP address: {}", self.elastic_ip_manager.public_ip() ); self.elastic_ip_manager .associate(&self.ec2, self.instance_manager.instance_id()) .await?; println!("Associated your Elastic IP with your instance."); println!("You can now use SSH to connect to your instance by using the Elastic IP."); self.display_ssh_info(); Ok(()) } /// Displays an SSH connection string that can be used to connect to a running /// instance. fn display_ssh_info(&self) { let ip_addr = if self.elastic_ip_manager.has_allocation() { self.elastic_ip_manager.public_ip() } else { self.instance_manager.instance_ip() }; let key_file_path = self.key_pair_manager.key_file_path().unwrap(); println!("To connect, open another command prompt and run the following command:"); println!("\nssh -i {} ec2-user@{ip_addr}\n", key_file_path.display()); let _ = self.util.enter_to_continue(); } /// 1. Disassociate and delete the previously created Elastic IP. /// 2. Terminate the previously created instance. /// 3. Delete the previously created security group. /// 4. Delete the previously created key pair. pub async fn clean_up(self) { println!("Let's clean everything up. This example created these resources:"); println!( "\tKey pair: {}", self.key_pair_manager .key_pair() .key_name() .unwrap_or("(unknown key pair)") ); println!( "\tSecurity group: {}", self.security_group_manager.group_name() ); println!( "\tInstance: {}", self.instance_manager.instance_display_name() ); if self.util.should_clean_resources() { if let Err(err) = self.elastic_ip_manager.remove(&self.ec2).await { eprintln!("{err}") } if let Err(err) = self.instance_manager.delete(&self.ec2).await { eprintln!("{err}") } if let Err(err) = self.security_group_manager.delete(&self.ec2).await { eprintln!("{err}"); } if let Err(err) = self.key_pair_manager.delete(&self.ec2, &self.util).await { eprintln!("{err}"); } } else { println!("Ok, not cleaning up any resources!"); } } } pub async fn run(mut scenario: Ec2InstanceScenario) { println!("--------------------------------------------------------------------------------"); println!( "Welcome to the Amazon Elastic Compute Cloud (Amazon EC2) get started with instances demo." ); println!("--------------------------------------------------------------------------------"); if let Err(err) = scenario.run().await { eprintln!("There was an error running the scenario: {err}") } println!("--------------------------------------------------------------------------------"); scenario.clean_up().await; println!("Thanks for running!"); println!("--------------------------------------------------------------------------------"); }
La struttura EC2 Impl funge da punto di automazione per i test e le sue funzioni racchiudono le chiamate EC2 SDK.
use std::{net::Ipv4Addr, time::Duration}; use aws_sdk_ec2::{ client::Waiters, error::ProvideErrorMetadata, operation::{ allocate_address::AllocateAddressOutput, associate_address::AssociateAddressOutput, }, types::{ DomainType, Filter, Image, Instance, InstanceType, IpPermission, IpRange, KeyPairInfo, SecurityGroup, Tag, }, Client as EC2Client, }; use aws_sdk_ssm::types::Parameter; use aws_smithy_runtime_api::client::waiters::error::WaiterError; #[cfg(test)] use mockall::automock; #[cfg(not(test))] pub use EC2Impl as EC2; #[cfg(test)] pub use MockEC2Impl as EC2; #[derive(Clone)] pub struct EC2Impl { pub client: EC2Client, } #[cfg_attr(test, automock)] impl EC2Impl { pub fn new(client: EC2Client) -> Self { EC2Impl { client } } pub async fn create_key_pair(&self, name: String) -> Result<(KeyPairInfo, String), EC2Error> { tracing::info!("Creating key pair {name}"); let output = self.client.create_key_pair().key_name(name).send().await?; let info = KeyPairInfo::builder() .set_key_name(output.key_name) .set_key_fingerprint(output.key_fingerprint) .set_key_pair_id(output.key_pair_id) .build(); let material = output .key_material .ok_or_else(|| EC2Error::new("Create Key Pair has no key material"))?; Ok((info, material)) } pub async fn list_key_pair(&self) -> Result<Vec<KeyPairInfo>, EC2Error> { let output = self.client.describe_key_pairs().send().await?; Ok(output.key_pairs.unwrap_or_default()) } pub async fn delete_key_pair(&self, key_name: &str) -> Result<(), EC2Error> { let key_name: String = key_name.into(); tracing::info!("Deleting key pair {key_name}"); self.client .delete_key_pair() .key_name(key_name) .send() .await?; Ok(()) } pub async fn create_security_group( &self, name: &str, description: &str, ) -> Result<SecurityGroup, EC2Error> { tracing::info!("Creating security group {name}"); let create_output = self .client .create_security_group() .group_name(name) .description(description) .send() .await .map_err(EC2Error::from)?; let group_id = create_output .group_id .ok_or_else(|| EC2Error::new("Missing security group id after creation"))?; let group = self .describe_security_group(&group_id) .await? .ok_or_else(|| { EC2Error::new(format!("Could not find security group with id {group_id}")) })?; tracing::info!("Created security group {name} as {group_id}"); Ok(group) } /// Find a single security group, by ID. Returns Err if multiple groups are found. pub async fn describe_security_group( &self, group_id: &str, ) -> Result<Option<SecurityGroup>, EC2Error> { let group_id: String = group_id.into(); let describe_output = self .client .describe_security_groups() .group_ids(&group_id) .send() .await?; let mut groups = describe_output.security_groups.unwrap_or_default(); match groups.len() { 0 => Ok(None), 1 => Ok(Some(groups.remove(0))), _ => Err(EC2Error::new(format!( "Expected single group for {group_id}" ))), } } /// Add an ingress rule to a security group explicitly allowing IPv4 address /// as {ip}/32 over TCP port 22. pub async fn authorize_security_group_ssh_ingress( &self, group_id: &str, ingress_ips: Vec<Ipv4Addr>, ) -> Result<(), EC2Error> { tracing::info!("Authorizing ingress for security group {group_id}"); self.client .authorize_security_group_ingress() .group_id(group_id) .set_ip_permissions(Some( ingress_ips .into_iter() .map(|ip| { IpPermission::builder() .ip_protocol("tcp") .from_port(22) .to_port(22) .ip_ranges(IpRange::builder().cidr_ip(format!("{ip}/32")).build()) .build() }) .collect(), )) .send() .await?; Ok(()) } pub async fn delete_security_group(&self, group_id: &str) -> Result<(), EC2Error> { tracing::info!("Deleting security group {group_id}"); self.client .delete_security_group() .group_id(group_id) .send() .await?; Ok(()) } pub async fn list_images(&self, ids: Vec<Parameter>) -> Result<Vec<Image>, EC2Error> { let image_ids = ids.into_iter().filter_map(|p| p.value).collect(); let output = self .client .describe_images() .set_image_ids(Some(image_ids)) .send() .await?; let images = output.images.unwrap_or_default(); if images.is_empty() { Err(EC2Error::new("No images for selected AMIs")) } else { Ok(images) } } /// List instance types that match an image's architecture and are free tier eligible. pub async fn list_instance_types(&self, image: &Image) -> Result<Vec<InstanceType>, EC2Error> { let architecture = format!( "{}", image.architecture().ok_or_else(|| EC2Error::new(format!( "Image {:?} does not have a listed architecture", image.image_id() )))? ); let free_tier_eligible_filter = Filter::builder() .name("free-tier-eligible") .values("false") .build(); let supported_architecture_filter = Filter::builder() .name("processor-info.supported-architecture") .values(architecture) .build(); let response = self .client .describe_instance_types() .filters(free_tier_eligible_filter) .filters(supported_architecture_filter) .send() .await?; Ok(response .instance_types .unwrap_or_default() .into_iter() .filter_map(|iti| iti.instance_type) .collect()) } pub async fn create_instance<'a>( &self, image_id: &'a str, instance_type: InstanceType, key_pair: &'a KeyPairInfo, security_groups: Vec<&'a SecurityGroup>, ) -> Result<String, EC2Error> { let run_instances = self .client .run_instances() .image_id(image_id) .instance_type(instance_type) .key_name( key_pair .key_name() .ok_or_else(|| EC2Error::new("Missing key name when launching instance"))?, ) .set_security_group_ids(Some( security_groups .iter() .filter_map(|sg| sg.group_id.clone()) .collect(), )) .min_count(1) .max_count(1) .send() .await?; if run_instances.instances().is_empty() { return Err(EC2Error::new("Failed to create instance")); } let instance_id = run_instances.instances()[0].instance_id().unwrap(); let response = self .client .create_tags() .resources(instance_id) .tags( Tag::builder() .key("Name") .value("From SDK Examples") .build(), ) .send() .await; match response { Ok(_) => tracing::info!("Created {instance_id} and applied tags."), Err(err) => { tracing::info!("Error applying tags to {instance_id}: {err:?}"); return Err(err.into()); } } tracing::info!("Instance is created."); Ok(instance_id.to_string()) } /// Wait for an instance to be ready and status ok (default wait 60 seconds) pub async fn wait_for_instance_ready( &self, instance_id: &str, duration: Option<Duration>, ) -> Result<(), EC2Error> { self.client .wait_until_instance_status_ok() .instance_ids(instance_id) .wait(duration.unwrap_or(Duration::from_secs(60))) .await .map_err(|err| match err { WaiterError::ExceededMaxWait(exceeded) => EC2Error(format!( "Exceeded max time ({}s) waiting for instance to start.", exceeded.max_wait().as_secs() )), _ => EC2Error::from(err), })?; Ok(()) } pub async fn describe_instance(&self, instance_id: &str) -> Result<Instance, EC2Error> { let response = self .client .describe_instances() .instance_ids(instance_id) .send() .await?; let instance = response .reservations() .first() .ok_or_else(|| EC2Error::new(format!("No instance reservations for {instance_id}")))? .instances() .first() .ok_or_else(|| { EC2Error::new(format!("No instances in reservation for {instance_id}")) })?; Ok(instance.clone()) } pub async fn start_instance(&self, instance_id: &str) -> Result<(), EC2Error> { tracing::info!("Starting instance {instance_id}"); self.client .start_instances() .instance_ids(instance_id) .send() .await?; tracing::info!("Started instance."); Ok(()) } pub async fn stop_instance(&self, instance_id: &str) -> Result<(), EC2Error> { tracing::info!("Stopping instance {instance_id}"); self.client .stop_instances() .instance_ids(instance_id) .send() .await?; self.wait_for_instance_stopped(instance_id, None).await?; tracing::info!("Stopped instance."); Ok(()) } pub async fn reboot_instance(&self, instance_id: &str) -> Result<(), EC2Error> { tracing::info!("Rebooting instance {instance_id}"); self.client .reboot_instances() .instance_ids(instance_id) .send() .await?; Ok(()) } pub async fn wait_for_instance_stopped( &self, instance_id: &str, duration: Option<Duration>, ) -> Result<(), EC2Error> { self.client .wait_until_instance_stopped() .instance_ids(instance_id) .wait(duration.unwrap_or(Duration::from_secs(60))) .await .map_err(|err| match err { WaiterError::ExceededMaxWait(exceeded) => EC2Error(format!( "Exceeded max time ({}s) waiting for instance to stop.", exceeded.max_wait().as_secs(), )), _ => EC2Error::from(err), })?; Ok(()) } pub async fn delete_instance(&self, instance_id: &str) -> Result<(), EC2Error> { tracing::info!("Deleting instance with id {instance_id}"); self.stop_instance(instance_id).await?; self.client .terminate_instances() .instance_ids(instance_id) .send() .await?; self.wait_for_instance_terminated(instance_id).await?; tracing::info!("Terminated instance with id {instance_id}"); Ok(()) } async fn wait_for_instance_terminated(&self, instance_id: &str) -> Result<(), EC2Error> { self.client .wait_until_instance_terminated() .instance_ids(instance_id) .wait(Duration::from_secs(60)) .await .map_err(|err| match err { WaiterError::ExceededMaxWait(exceeded) => EC2Error(format!( "Exceeded max time ({}s) waiting for instance to terminate.", exceeded.max_wait().as_secs(), )), _ => EC2Error::from(err), })?; Ok(()) } pub async fn allocate_ip_address(&self) -> Result<AllocateAddressOutput, EC2Error> { self.client .allocate_address() .domain(DomainType::Vpc) .send() .await .map_err(EC2Error::from) } pub async fn deallocate_ip_address(&self, allocation_id: &str) -> Result<(), EC2Error> { self.client .release_address() .allocation_id(allocation_id) .send() .await?; Ok(()) } pub async fn associate_ip_address( &self, allocation_id: &str, instance_id: &str, ) -> Result<AssociateAddressOutput, EC2Error> { let response = self .client .associate_address() .allocation_id(allocation_id) .instance_id(instance_id) .send() .await?; Ok(response) } pub async fn disassociate_ip_address(&self, association_id: &str) -> Result<(), EC2Error> { self.client .disassociate_address() .association_id(association_id) .send() .await?; Ok(()) } } #[derive(Debug)] pub struct EC2Error(String); impl EC2Error { pub fn new(value: impl Into<String>) -> Self { EC2Error(value.into()) } pub fn add_message(self, message: impl Into<String>) -> Self { EC2Error(format!("{}: {}", message.into(), self.0)) } } impl<T: ProvideErrorMetadata> From<T> for EC2Error { fn from(value: T) -> Self { EC2Error(format!( "{}: {}", value .code() .map(String::from) .unwrap_or("unknown code".into()), value .message() .map(String::from) .unwrap_or("missing reason".into()), )) } } impl std::error::Error for EC2Error {} impl std::fmt::Display for EC2Error { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { write!(f, "{}", self.0) } }
La struttura SSM funge da punto di automazione per i test e le sue funzioni racchiudono le chiamate SSM SDK.
use aws_sdk_ssm::{types::Parameter, Client}; use aws_smithy_async::future::pagination_stream::TryFlatMap; use crate::ec2::EC2Error; #[cfg(test)] use mockall::automock; #[cfg(not(test))] pub use SSMImpl as SSM; #[cfg(test)] pub use MockSSMImpl as SSM; pub struct SSMImpl { inner: Client, } #[cfg_attr(test, automock)] impl SSMImpl { pub fn new(inner: Client) -> Self { SSMImpl { inner } } pub async fn list_path(&self, path: &str) -> Result<Vec<Parameter>, EC2Error> { let maybe_params: Vec<Result<Parameter, _>> = TryFlatMap::new( self.inner .get_parameters_by_path() .path(path) .into_paginator() .send(), ) .flat_map(|item| item.parameters.unwrap_or_default()) .collect() .await; // Fail on the first error let params = maybe_params .into_iter() .collect::<Result<Vec<Parameter>, _>>()?; Ok(params) } }
Lo scenario utilizza diverse strutture in stile «Manager» per gestire l'accesso alle risorse che vengono create ed eliminate durante lo scenario.
use aws_sdk_ec2::operation::{ allocate_address::AllocateAddressOutput, associate_address::AssociateAddressOutput, }; use crate::ec2::{EC2Error, EC2}; /// ElasticIpManager tracks the lifecycle of a public IP address, including its /// allocation from the global pool and association with a specific instance. #[derive(Debug, Default)] pub struct ElasticIpManager { elastic_ip: Option<AllocateAddressOutput>, association: Option<AssociateAddressOutput>, } impl ElasticIpManager { pub fn has_allocation(&self) -> bool { self.elastic_ip.is_some() } pub fn public_ip(&self) -> &str { if let Some(allocation) = &self.elastic_ip { if let Some(addr) = allocation.public_ip() { return addr; } } "0.0.0.0" } pub async fn allocate(&mut self, ec2: &EC2) -> Result<(), EC2Error> { let allocation = ec2.allocate_ip_address().await?; self.elastic_ip = Some(allocation); Ok(()) } pub async fn associate(&mut self, ec2: &EC2, instance_id: &str) -> Result<(), EC2Error> { if let Some(allocation) = &self.elastic_ip { if let Some(allocation_id) = allocation.allocation_id() { let association = ec2.associate_ip_address(allocation_id, instance_id).await?; self.association = Some(association); return Ok(()); } } Err(EC2Error::new("No ip address allocation to associate")) } pub async fn remove(mut self, ec2: &EC2) -> Result<(), EC2Error> { if let Some(association) = &self.association { if let Some(association_id) = association.association_id() { ec2.disassociate_ip_address(association_id).await?; } } self.association = None; if let Some(allocation) = &self.elastic_ip { if let Some(allocation_id) = allocation.allocation_id() { ec2.deallocate_ip_address(allocation_id).await?; } } self.elastic_ip = None; Ok(()) } } use std::fmt::Display; use aws_sdk_ec2::types::{Instance, InstanceType, KeyPairInfo, SecurityGroup}; use crate::ec2::{EC2Error, EC2}; /// InstanceManager wraps the lifecycle of an EC2 Instance. #[derive(Debug, Default)] pub struct InstanceManager { instance: Option<Instance>, } impl InstanceManager { pub fn instance_id(&self) -> &str { if let Some(instance) = &self.instance { if let Some(id) = instance.instance_id() { return id; } } "Unknown" } pub fn instance_name(&self) -> &str { if let Some(instance) = &self.instance { if let Some(tag) = instance.tags().iter().find(|e| e.key() == Some("Name")) { if let Some(value) = tag.value() { return value; } } } "Unknown" } pub fn instance_ip(&self) -> &str { if let Some(instance) = &self.instance { if let Some(public_ip_address) = instance.public_ip_address() { return public_ip_address; } } "0.0.0.0" } pub fn instance_display_name(&self) -> String { format!("{} ({})", self.instance_name(), self.instance_id()) } /// Create an EC2 instance with the given ID on a given type, using a /// generated KeyPair and applying a list of security groups. pub async fn create( &mut self, ec2: &EC2, image_id: &str, instance_type: InstanceType, key_pair: &KeyPairInfo, security_groups: Vec<&SecurityGroup>, ) -> Result<(), EC2Error> { let instance_id = ec2 .create_instance(image_id, instance_type, key_pair, security_groups) .await?; let instance = ec2.describe_instance(&instance_id).await?; self.instance = Some(instance); Ok(()) } /// Start the managed EC2 instance, if present. pub async fn start(&self, ec2: &EC2) -> Result<(), EC2Error> { if self.instance.is_some() { ec2.start_instance(self.instance_id()).await?; } Ok(()) } /// Stop the managed EC2 instance, if present. pub async fn stop(&self, ec2: &EC2) -> Result<(), EC2Error> { if self.instance.is_some() { ec2.stop_instance(self.instance_id()).await?; } Ok(()) } pub async fn reboot(&self, ec2: &EC2) -> Result<(), EC2Error> { if self.instance.is_some() { ec2.reboot_instance(self.instance_id()).await?; ec2.wait_for_instance_stopped(self.instance_id(), None) .await?; ec2.wait_for_instance_ready(self.instance_id(), None) .await?; } Ok(()) } /// Terminate and delete the managed EC2 instance, if present. pub async fn delete(self, ec2: &EC2) -> Result<(), EC2Error> { if self.instance.is_some() { ec2.delete_instance(self.instance_id()).await?; } Ok(()) } } impl Display for InstanceManager { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { if let Some(instance) = &self.instance { writeln!(f, "\tID: {}", instance.instance_id().unwrap_or("(Unknown)"))?; writeln!( f, "\tImage ID: {}", instance.image_id().unwrap_or("(Unknown)") )?; writeln!( f, "\tInstance type: {}", instance .instance_type() .map(|it| format!("{it}")) .unwrap_or("(Unknown)".to_string()) )?; writeln!( f, "\tKey name: {}", instance.key_name().unwrap_or("(Unknown)") )?; writeln!(f, "\tVPC ID: {}", instance.vpc_id().unwrap_or("(Unknown)"))?; writeln!( f, "\tPublic IP: {}", instance.public_ip_address().unwrap_or("(Unknown)") )?; let instance_state = instance .state .as_ref() .map(|is| { is.name() .map(|isn| format!("{isn}")) .unwrap_or("(Unknown)".to_string()) }) .unwrap_or("(Unknown)".to_string()); writeln!(f, "\tState: {instance_state}")?; } else { writeln!(f, "\tNo loaded instance")?; } Ok(()) } } use std::{env, path::PathBuf}; use aws_sdk_ec2::types::KeyPairInfo; use crate::ec2::{EC2Error, EC2}; use super::util::Util; /// KeyPairManager tracks a KeyPairInfo and the path the private key has been /// written to, if it's been created. #[derive(Debug)] pub struct KeyPairManager { key_pair: KeyPairInfo, key_file_path: Option<PathBuf>, key_file_dir: PathBuf, } impl KeyPairManager { pub fn new() -> Self { Self::default() } pub fn key_pair(&self) -> &KeyPairInfo { &self.key_pair } pub fn key_file_path(&self) -> Option<&PathBuf> { self.key_file_path.as_ref() } pub fn key_file_dir(&self) -> &PathBuf { &self.key_file_dir } /// Creates a key pair that can be used to securely connect to an EC2 instance. /// The returned key pair contains private key information that cannot be retrieved /// again. The private key data is stored as a .pem file. /// /// :param key_name: The name of the key pair to create. pub async fn create( &mut self, ec2: &EC2, util: &Util, key_name: String, ) -> Result<KeyPairInfo, EC2Error> { let (key_pair, material) = ec2.create_key_pair(key_name.clone()).await.map_err(|e| { self.key_pair = KeyPairInfo::builder().key_name(key_name.clone()).build(); e.add_message(format!("Couldn't create key {key_name}")) })?; let path = self.key_file_dir.join(format!("{key_name}.pem")); // Save the key_pair information immediately, so it can get cleaned up if write_secure fails. self.key_file_path = Some(path.clone()); self.key_pair = key_pair.clone(); util.write_secure(&key_name, &path, material)?; Ok(key_pair) } pub async fn delete(self, ec2: &EC2, util: &Util) -> Result<(), EC2Error> { if let Some(key_name) = self.key_pair.key_name() { ec2.delete_key_pair(key_name).await?; if let Some(key_path) = self.key_file_path() { if let Err(err) = util.remove(key_path) { eprintln!("Failed to remove {key_path:?} ({err:?})"); } } } Ok(()) } pub async fn list(&self, ec2: &EC2) -> Result<Vec<KeyPairInfo>, EC2Error> { ec2.list_key_pair().await } } impl Default for KeyPairManager { fn default() -> Self { KeyPairManager { key_pair: KeyPairInfo::builder().build(), key_file_path: Default::default(), key_file_dir: env::temp_dir(), } } } use std::net::Ipv4Addr; use aws_sdk_ec2::types::SecurityGroup; use crate::ec2::{EC2Error, EC2}; /// SecurityGroupManager tracks the lifecycle of a SecurityGroup for an instance, /// including adding a rule to allow SSH from a public IP address. #[derive(Debug, Default)] pub struct SecurityGroupManager { group_name: String, group_description: String, security_group: Option<SecurityGroup>, } impl SecurityGroupManager { pub async fn create( &mut self, ec2: &EC2, group_name: &str, group_description: &str, ) -> Result<(), EC2Error> { self.group_name = group_name.into(); self.group_description = group_description.into(); self.security_group = Some( ec2.create_security_group(group_name, group_description) .await .map_err(|e| e.add_message("Couldn't create security group"))?, ); Ok(()) } pub async fn authorize_ingress(&self, ec2: &EC2, ip_address: Ipv4Addr) -> Result<(), EC2Error> { if let Some(sg) = &self.security_group { ec2.authorize_security_group_ssh_ingress( sg.group_id() .ok_or_else(|| EC2Error::new("Missing security group ID"))?, vec![ip_address], ) .await?; }; Ok(()) } pub async fn delete(self, ec2: &EC2) -> Result<(), EC2Error> { if let Some(sg) = &self.security_group { ec2.delete_security_group( sg.group_id() .ok_or_else(|| EC2Error::new("Missing security group ID"))?, ) .await?; }; Ok(()) } pub fn group_name(&self) -> &str { &self.group_name } pub fn vpc_id(&self) -> Option<&str> { self.security_group.as_ref().and_then(|sg| sg.vpc_id()) } pub fn security_group(&self) -> Option<&SecurityGroup> { self.security_group.as_ref() } } impl std::fmt::Display for SecurityGroupManager { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match &self.security_group { Some(sg) => { writeln!( f, "Security group: {}", sg.group_name().unwrap_or("(unknown group)") )?; writeln!(f, "\tID: {}", sg.group_id().unwrap_or("(unknown group id)"))?; writeln!(f, "\tVPC: {}", sg.vpc_id().unwrap_or("(unknown group vpc)"))?; if !sg.ip_permissions().is_empty() { writeln!(f, "\tInbound Permissions:")?; for permission in sg.ip_permissions() { writeln!(f, "\t\t{permission:?}")?; } } Ok(()) } None => writeln!(f, "No security group loaded."), } } }
Il punto di ingresso principale per lo scenario.
use ec2_code_examples::{ ec2::EC2, getting_started::{ scenario::{run, Ec2InstanceScenario}, util::UtilImpl, }, ssm::SSM, }; #[tokio::main] async fn main() { tracing_subscriber::fmt::init(); let sdk_config = aws_config::load_from_env().await; let ec2 = EC2::new(aws_sdk_ec2::Client::new(&sdk_config)); let ssm = SSM::new(aws_sdk_ssm::Client::new(&sdk_config)); let util = UtilImpl {}; let scenario = Ec2InstanceScenario::new(ec2, ssm, util); run(scenario).await; }
-
Per informazioni dettagliate sulle API, consulta i seguenti argomenti nella Documentazione di riferimento delle API SDK AWS per Rust.
-
Operazioni
Il seguente esempio di codice mostra come utilizzareAllocateAddress
.
- SDK per Rust
-
Nota
C'è altro da fare GitHub. Trova l'esempio completo e scopri di più sulla configurazione e l'esecuzione nel Repository di esempi di codice AWS
. pub async fn allocate_ip_address(&self) -> Result<AllocateAddressOutput, EC2Error> { self.client .allocate_address() .domain(DomainType::Vpc) .send() .await .map_err(EC2Error::from) }
-
Per i dettagli sulle API, consulta il riferimento AllocateAddress
all'API AWS SDK for Rust.
-
Il seguente esempio di codice mostra come utilizzareAssociateAddress
.
- SDK per Rust
-
Nota
C'è altro da fare GitHub. Trova l'esempio completo e scopri di più sulla configurazione e l'esecuzione nel Repository di esempi di codice AWS
. pub async fn associate_ip_address( &self, allocation_id: &str, instance_id: &str, ) -> Result<AssociateAddressOutput, EC2Error> { let response = self .client .associate_address() .allocation_id(allocation_id) .instance_id(instance_id) .send() .await?; Ok(response) }
-
Per i dettagli sulle API, consulta il riferimento AssociateAddress
all'API AWS SDK for Rust.
-
Il seguente esempio di codice mostra come utilizzareAuthorizeSecurityGroupIngress
.
- SDK per Rust
-
Nota
C'è altro da fare GitHub. Trova l'esempio completo e scopri di più sulla configurazione e l'esecuzione nel Repository di esempi di codice AWS
. /// Add an ingress rule to a security group explicitly allowing IPv4 address /// as {ip}/32 over TCP port 22. pub async fn authorize_security_group_ssh_ingress( &self, group_id: &str, ingress_ips: Vec<Ipv4Addr>, ) -> Result<(), EC2Error> { tracing::info!("Authorizing ingress for security group {group_id}"); self.client .authorize_security_group_ingress() .group_id(group_id) .set_ip_permissions(Some( ingress_ips .into_iter() .map(|ip| { IpPermission::builder() .ip_protocol("tcp") .from_port(22) .to_port(22) .ip_ranges(IpRange::builder().cidr_ip(format!("{ip}/32")).build()) .build() }) .collect(), )) .send() .await?; Ok(()) }
-
Per i dettagli sulle API, consulta il riferimento AuthorizeSecurityGroupIngress
all'API AWS SDK for Rust.
-
Il seguente esempio di codice mostra come utilizzareCreateKeyPair
.
- SDK per Rust
-
Nota
C'è altro da fare GitHub. Trova l'esempio completo e scopri di più sulla configurazione e l'esecuzione nel Repository di esempi di codice AWS
. Implementazione di Rust che chiama la create_key_pair del EC2 Client ed estrae il materiale restituito.
pub async fn create_key_pair(&self, name: String) -> Result<(KeyPairInfo, String), EC2Error> { tracing::info!("Creating key pair {name}"); let output = self.client.create_key_pair().key_name(name).send().await?; let info = KeyPairInfo::builder() .set_key_name(output.key_name) .set_key_fingerprint(output.key_fingerprint) .set_key_pair_id(output.key_pair_id) .build(); let material = output .key_material .ok_or_else(|| EC2Error::new("Create Key Pair has no key material"))?; Ok((info, material)) }
Una funzione che chiama l'impl create_key e salva in modo sicuro la chiave privata PEM.
/// Creates a key pair that can be used to securely connect to an EC2 instance. /// The returned key pair contains private key information that cannot be retrieved /// again. The private key data is stored as a .pem file. /// /// :param key_name: The name of the key pair to create. pub async fn create( &mut self, ec2: &EC2, util: &Util, key_name: String, ) -> Result<KeyPairInfo, EC2Error> { let (key_pair, material) = ec2.create_key_pair(key_name.clone()).await.map_err(|e| { self.key_pair = KeyPairInfo::builder().key_name(key_name.clone()).build(); e.add_message(format!("Couldn't create key {key_name}")) })?; let path = self.key_file_dir.join(format!("{key_name}.pem")); // Save the key_pair information immediately, so it can get cleaned up if write_secure fails. self.key_file_path = Some(path.clone()); self.key_pair = key_pair.clone(); util.write_secure(&key_name, &path, material)?; Ok(key_pair) }
-
Per i dettagli sulle API, consulta la guida di riferimento all'API SDK for CreateKeyPair
Rust AWS .
-
Il seguente esempio di codice mostra come utilizzareCreateSecurityGroup
.
- SDK per Rust
-
Nota
C'è altro da fare GitHub. Trova l'esempio completo e scopri di più sulla configurazione e l'esecuzione nel Repository di esempi di codice AWS
. pub async fn create_security_group( &self, name: &str, description: &str, ) -> Result<SecurityGroup, EC2Error> { tracing::info!("Creating security group {name}"); let create_output = self .client .create_security_group() .group_name(name) .description(description) .send() .await .map_err(EC2Error::from)?; let group_id = create_output .group_id .ok_or_else(|| EC2Error::new("Missing security group id after creation"))?; let group = self .describe_security_group(&group_id) .await? .ok_or_else(|| { EC2Error::new(format!("Could not find security group with id {group_id}")) })?; tracing::info!("Created security group {name} as {group_id}"); Ok(group) }
-
Per i dettagli sulle API, consulta il riferimento CreateSecurityGroup
all'API AWS SDK for Rust.
-
Il seguente esempio di codice mostra come utilizzareCreateTags
.
- SDK per Rust
-
Nota
C'è altro da fare GitHub. Trova l'esempio completo e scopri di più sulla configurazione e l'esecuzione nel Repository di esempi di codice AWS
. Questo esempio applica il tag Name dopo aver creato un'istanza.
pub async fn create_instance<'a>( &self, image_id: &'a str, instance_type: InstanceType, key_pair: &'a KeyPairInfo, security_groups: Vec<&'a SecurityGroup>, ) -> Result<String, EC2Error> { let run_instances = self .client .run_instances() .image_id(image_id) .instance_type(instance_type) .key_name( key_pair .key_name() .ok_or_else(|| EC2Error::new("Missing key name when launching instance"))?, ) .set_security_group_ids(Some( security_groups .iter() .filter_map(|sg| sg.group_id.clone()) .collect(), )) .min_count(1) .max_count(1) .send() .await?; if run_instances.instances().is_empty() { return Err(EC2Error::new("Failed to create instance")); } let instance_id = run_instances.instances()[0].instance_id().unwrap(); let response = self .client .create_tags() .resources(instance_id) .tags( Tag::builder() .key("Name") .value("From SDK Examples") .build(), ) .send() .await; match response { Ok(_) => tracing::info!("Created {instance_id} and applied tags."), Err(err) => { tracing::info!("Error applying tags to {instance_id}: {err:?}"); return Err(err.into()); } } tracing::info!("Instance is created."); Ok(instance_id.to_string()) }
-
Per i dettagli sull'API, consulta il riferimento CreateTags
all'API AWS SDK for Rust.
-
Il seguente esempio di codice mostra come utilizzareDeleteKeyPair
.
- SDK per Rust
-
Nota
C'è altro da fare GitHub. Trova l'esempio completo e scopri di più sulla configurazione e l'esecuzione nel Repository di esempi di codice AWS
. Wrapper around delete_key che rimuove anche la chiave PEM privata di supporto.
pub async fn delete(self, ec2: &EC2, util: &Util) -> Result<(), EC2Error> { if let Some(key_name) = self.key_pair.key_name() { ec2.delete_key_pair(key_name).await?; if let Some(key_path) = self.key_file_path() { if let Err(err) = util.remove(key_path) { eprintln!("Failed to remove {key_path:?} ({err:?})"); } } } Ok(()) }
pub async fn delete_key_pair(&self, key_name: &str) -> Result<(), EC2Error> { let key_name: String = key_name.into(); tracing::info!("Deleting key pair {key_name}"); self.client .delete_key_pair() .key_name(key_name) .send() .await?; Ok(()) }
-
Per i dettagli sull'API, consulta il riferimento all'API SDK for DeleteKeyPair
Rust AWS .
-
Il seguente esempio di codice mostra come utilizzareDeleteSecurityGroup
.
- SDK per Rust
-
Nota
C'è altro da fare GitHub. Trova l'esempio completo e scopri di più sulla configurazione e l'esecuzione nel Repository di esempi di codice AWS
. pub async fn delete_security_group(&self, group_id: &str) -> Result<(), EC2Error> { tracing::info!("Deleting security group {group_id}"); self.client .delete_security_group() .group_id(group_id) .send() .await?; Ok(()) }
-
Per i dettagli sulle API, consulta il riferimento DeleteSecurityGroup
all'API AWS SDK for Rust.
-
Il seguente esempio di codice mostra come utilizzareDeleteSnapshot
.
- SDK per Rust
-
Nota
C'è altro da fare GitHub. Trova l'esempio completo e scopri di più sulla configurazione e l'esecuzione nel Repository di esempi di codice AWS
. async fn delete_snapshot(client: &Client, id: &str) -> Result<(), Error> { client.delete_snapshot().snapshot_id(id).send().await?; println!("Deleted"); Ok(()) }
-
Per i dettagli sulle API, consulta il riferimento DeleteSnapshot
all'API AWS SDK for Rust.
-
Il seguente esempio di codice mostra come utilizzareDescribeImages
.
- SDK per Rust
-
Nota
C'è altro da fare GitHub. Trova l'esempio completo e scopri di più sulla configurazione e l'esecuzione nel Repository di esempi di codice AWS
. pub async fn list_images(&self, ids: Vec<Parameter>) -> Result<Vec<Image>, EC2Error> { let image_ids = ids.into_iter().filter_map(|p| p.value).collect(); let output = self .client .describe_images() .set_image_ids(Some(image_ids)) .send() .await?; let images = output.images.unwrap_or_default(); if images.is_empty() { Err(EC2Error::new("No images for selected AMIs")) } else { Ok(images) } }
Utilizzo della funzione list_images con SSM per limitare in base all'ambiente. Per maggiori dettagli su SSM, consulta _ssm_ _section.html. https://docs.aws.amazon.com/systems-manager/ latest/userguide/example GetParameters
async fn find_image(&mut self) -> Result<ScenarioImage, EC2Error> { let params: Vec<Parameter> = self .ssm .list_path("/aws/service/ami-amazon-linux-latest") .await .map_err(|e| e.add_message("Could not find parameters for available images"))? .into_iter() .filter(|param| param.name().is_some_and(|name| name.contains("amzn2"))) .collect(); let amzn2_images: Vec<ScenarioImage> = self .ec2 .list_images(params) .await .map_err(|e| e.add_message("Could not find images"))? .into_iter() .map(ScenarioImage::from) .collect(); println!("We will now create an instance from an Amazon Linux 2 AMI"); let ami = self.util.select_scenario_image(amzn2_images)?; Ok(ami) }
-
Per i dettagli sulle API, consulta la guida di riferimento DescribeImages
all'API AWS SDK for Rust.
-
Il seguente esempio di codice mostra come utilizzareDescribeInstanceStatus
.
- SDK per Rust
-
Nota
C'è altro da fare GitHub. Trova l'esempio completo e scopri di più sulla configurazione e l'esecuzione nel Repository di esempi di codice AWS
. async fn show_all_events(client: &Client) -> Result<(), Error> { let resp = client.describe_regions().send().await.unwrap(); for region in resp.regions.unwrap_or_default() { let reg: &'static str = Box::leak(Box::from(region.region_name().unwrap())); let region_provider = RegionProviderChain::default_provider().or_else(reg); let config = aws_config::from_env().region(region_provider).load().await; let new_client = Client::new(&config); let resp = new_client.describe_instance_status().send().await; println!("Instances in region {}:", reg); println!(); for status in resp.unwrap().instance_statuses() { println!( " Events scheduled for instance ID: {}", status.instance_id().unwrap_or_default() ); for event in status.events() { println!(" Event ID: {}", event.instance_event_id().unwrap()); println!(" Description: {}", event.description().unwrap()); println!(" Event code: {}", event.code().unwrap().as_ref()); println!(); } } } Ok(()) }
-
Per i dettagli sulle API, consulta il riferimento DescribeInstanceStatus
all'API AWS SDK for Rust.
-
Il seguente esempio di codice mostra come utilizzareDescribeInstanceTypes
.
- SDK per Rust
-
Nota
C'è altro da fare GitHub. Trova l'esempio completo e scopri di più sulla configurazione e l'esecuzione nel Repository di esempi di codice AWS
. /// List instance types that match an image's architecture and are free tier eligible. pub async fn list_instance_types(&self, image: &Image) -> Result<Vec<InstanceType>, EC2Error> { let architecture = format!( "{}", image.architecture().ok_or_else(|| EC2Error::new(format!( "Image {:?} does not have a listed architecture", image.image_id() )))? ); let free_tier_eligible_filter = Filter::builder() .name("free-tier-eligible") .values("false") .build(); let supported_architecture_filter = Filter::builder() .name("processor-info.supported-architecture") .values(architecture) .build(); let response = self .client .describe_instance_types() .filters(free_tier_eligible_filter) .filters(supported_architecture_filter) .send() .await?; Ok(response .instance_types .unwrap_or_default() .into_iter() .filter_map(|iti| iti.instance_type) .collect()) }
-
Per i dettagli sulle API, consulta il riferimento DescribeInstanceTypes
all'API AWS SDK for Rust.
-
Il seguente esempio di codice mostra come utilizzareDescribeInstances
.
- SDK per Rust
-
Nota
C'è altro da fare GitHub. Trova l'esempio completo e scopri di più sulla configurazione e l'esecuzione nel Repository di esempi di codice AWS
. Recupera i dettagli di un' EC2 istanza.
pub async fn describe_instance(&self, instance_id: &str) -> Result<Instance, EC2Error> { let response = self .client .describe_instances() .instance_ids(instance_id) .send() .await?; let instance = response .reservations() .first() .ok_or_else(|| EC2Error::new(format!("No instance reservations for {instance_id}")))? .instances() .first() .ok_or_else(|| { EC2Error::new(format!("No instances in reservation for {instance_id}")) })?; Ok(instance.clone()) }
Dopo aver creato un' EC2 istanza, recuperate e memorizzate i relativi dettagli.
/// Create an EC2 instance with the given ID on a given type, using a /// generated KeyPair and applying a list of security groups. pub async fn create( &mut self, ec2: &EC2, image_id: &str, instance_type: InstanceType, key_pair: &KeyPairInfo, security_groups: Vec<&SecurityGroup>, ) -> Result<(), EC2Error> { let instance_id = ec2 .create_instance(image_id, instance_type, key_pair, security_groups) .await?; let instance = ec2.describe_instance(&instance_id).await?; self.instance = Some(instance); Ok(()) }
-
Per i dettagli sull'API, consulta la DescribeInstances
guida di riferimento all'API AWS SDK for Rust.
-
Il seguente esempio di codice mostra come utilizzareDescribeKeyPairs
.
- SDK per Rust
-
Nota
C'è altro da fare GitHub. Trova l'esempio completo e scopri di più sulla configurazione e l'esecuzione nel Repository di esempi di codice AWS
. pub async fn list_key_pair(&self) -> Result<Vec<KeyPairInfo>, EC2Error> { let output = self.client.describe_key_pairs().send().await?; Ok(output.key_pairs.unwrap_or_default()) }
-
Per i dettagli sulle API, consulta il riferimento DescribeKeyPairs
all'API AWS SDK for Rust.
-
Il seguente esempio di codice mostra come utilizzareDescribeRegions
.
- SDK per Rust
-
Nota
C'è altro da fare GitHub. Trova l'esempio completo e scopri di più sulla configurazione e l'esecuzione nel Repository di esempi di codice AWS
. async fn show_regions(client: &Client) -> Result<(), Error> { let rsp = client.describe_regions().send().await?; println!("Regions:"); for region in rsp.regions() { println!(" {}", region.region_name().unwrap()); } Ok(()) }
-
Per i dettagli sulle API, consulta il riferimento DescribeRegions
all'API AWS SDK for Rust.
-
Il seguente esempio di codice mostra come utilizzareDescribeSecurityGroups
.
- SDK per Rust
-
Nota
C'è altro da fare GitHub. Trova l'esempio completo e scopri di più sulla configurazione e l'esecuzione nel Repository di esempi di codice AWS
. async fn show_security_groups(client: &aws_sdk_ec2::Client, group_ids: Vec<String>) { let response = client .describe_security_groups() .set_group_ids(Some(group_ids)) .send() .await; match response { Ok(output) => { for group in output.security_groups() { println!( "Found Security Group {} ({}), vpc id {} and description {}", group.group_name().unwrap_or("unknown"), group.group_id().unwrap_or("id-unknown"), group.vpc_id().unwrap_or("vpcid-unknown"), group.description().unwrap_or("(none)") ); } } Err(err) => { let err = err.into_service_error(); let meta = err.meta(); let message = meta.message().unwrap_or("unknown"); let code = meta.code().unwrap_or("unknown"); eprintln!("Error listing EC2 Security Groups: ({code}) {message}"); } } }
-
Per i dettagli sulle API, consulta il riferimento DescribeSecurityGroups
all'API AWS SDK for Rust.
-
Il seguente esempio di codice mostra come utilizzareDescribeSnapshots
.
- SDK per Rust
-
Nota
C'è altro da fare GitHub. Trova l'esempio completo e scopri di più sulla configurazione e l'esecuzione nel Repository di esempi di codice AWS
. Mostra lo stato di uno snapshot.
async fn show_state(client: &Client, id: &str) -> Result<(), Error> { let resp = client .describe_snapshots() .filters(Filter::builder().name("snapshot-id").values(id).build()) .send() .await?; println!( "State: {}", resp.snapshots().first().unwrap().state().unwrap().as_ref() ); Ok(()) }
async fn show_snapshots(client: &Client) -> Result<(), Error> { // "self" represents your account ID. // You can list the snapshots for any account by replacing // "self" with that account ID. let resp = client.describe_snapshots().owner_ids("self").send().await?; let snapshots = resp.snapshots(); let length = snapshots.len(); for snapshot in snapshots { println!( "ID: {}", snapshot.snapshot_id().unwrap_or_default() ); println!( "Description: {}", snapshot.description().unwrap_or_default() ); println!("State: {}", snapshot.state().unwrap().as_ref()); println!(); } println!(); println!("Found {} snapshot(s)", length); println!(); Ok(()) }
-
Per i dettagli sulle API, consulta il riferimento DescribeSnapshots
all'API AWS SDK for Rust.
-
Il seguente esempio di codice mostra come utilizzareDisassociateAddress
.
- SDK per Rust
-
Nota
C'è altro da fare GitHub. Trova l'esempio completo e scopri di più sulla configurazione e l'esecuzione nel Repository di esempi di codice AWS
. pub async fn disassociate_ip_address(&self, association_id: &str) -> Result<(), EC2Error> { self.client .disassociate_address() .association_id(association_id) .send() .await?; Ok(()) }
-
Per i dettagli sulle API, consulta il riferimento DisassociateAddress
all'API AWS SDK for Rust.
-
Il seguente esempio di codice mostra come utilizzareRebootInstances
.
- SDK per Rust
-
Nota
C'è altro da fare GitHub. Trova l'esempio completo e scopri di più sulla configurazione e l'esecuzione nel Repository di esempi di codice AWS
. pub async fn reboot(&self, ec2: &EC2) -> Result<(), EC2Error> { if self.instance.is_some() { ec2.reboot_instance(self.instance_id()).await?; ec2.wait_for_instance_stopped(self.instance_id(), None) .await?; ec2.wait_for_instance_ready(self.instance_id(), None) .await?; } Ok(()) }
pub async fn reboot_instance(&self, instance_id: &str) -> Result<(), EC2Error> { tracing::info!("Rebooting instance {instance_id}"); self.client .reboot_instances() .instance_ids(instance_id) .send() .await?; Ok(()) }
I camerieri, ad esempio, devono trovarsi negli stati stop e ready, utilizzando l'API Waiters. L'utilizzo dell'API Waiters richiede `use aws_sdk_ec2: :client: :Waiters` nel file rust.
/// Wait for an instance to be ready and status ok (default wait 60 seconds) pub async fn wait_for_instance_ready( &self, instance_id: &str, duration: Option<Duration>, ) -> Result<(), EC2Error> { self.client .wait_until_instance_status_ok() .instance_ids(instance_id) .wait(duration.unwrap_or(Duration::from_secs(60))) .await .map_err(|err| match err { WaiterError::ExceededMaxWait(exceeded) => EC2Error(format!( "Exceeded max time ({}s) waiting for instance to start.", exceeded.max_wait().as_secs() )), _ => EC2Error::from(err), })?; Ok(()) } pub async fn wait_for_instance_stopped( &self, instance_id: &str, duration: Option<Duration>, ) -> Result<(), EC2Error> { self.client .wait_until_instance_stopped() .instance_ids(instance_id) .wait(duration.unwrap_or(Duration::from_secs(60))) .await .map_err(|err| match err { WaiterError::ExceededMaxWait(exceeded) => EC2Error(format!( "Exceeded max time ({}s) waiting for instance to stop.", exceeded.max_wait().as_secs(), )), _ => EC2Error::from(err), })?; Ok(()) }
-
Per i dettagli RebootInstances
sull'API AWS , consulta il riferimento all'API SDK for Rust.
-
Il seguente esempio di codice mostra come utilizzareReleaseAddress
.
- SDK per Rust
-
Nota
C'è altro da fare GitHub. Trova l'esempio completo e scopri di più sulla configurazione e l'esecuzione nel Repository di esempi di codice AWS
. pub async fn deallocate_ip_address(&self, allocation_id: &str) -> Result<(), EC2Error> { self.client .release_address() .allocation_id(allocation_id) .send() .await?; Ok(()) }
-
Per i dettagli sulle API, consulta il riferimento ReleaseAddress
all'API AWS SDK for Rust.
-
Il seguente esempio di codice mostra come utilizzareRunInstances
.
- SDK per Rust
-
Nota
C'è altro da fare GitHub. Trova l'esempio completo e scopri di più sulla configurazione e l'esecuzione nel Repository di esempi di codice AWS
. pub async fn create_instance<'a>( &self, image_id: &'a str, instance_type: InstanceType, key_pair: &'a KeyPairInfo, security_groups: Vec<&'a SecurityGroup>, ) -> Result<String, EC2Error> { let run_instances = self .client .run_instances() .image_id(image_id) .instance_type(instance_type) .key_name( key_pair .key_name() .ok_or_else(|| EC2Error::new("Missing key name when launching instance"))?, ) .set_security_group_ids(Some( security_groups .iter() .filter_map(|sg| sg.group_id.clone()) .collect(), )) .min_count(1) .max_count(1) .send() .await?; if run_instances.instances().is_empty() { return Err(EC2Error::new("Failed to create instance")); } let instance_id = run_instances.instances()[0].instance_id().unwrap(); let response = self .client .create_tags() .resources(instance_id) .tags( Tag::builder() .key("Name") .value("From SDK Examples") .build(), ) .send() .await; match response { Ok(_) => tracing::info!("Created {instance_id} and applied tags."), Err(err) => { tracing::info!("Error applying tags to {instance_id}: {err:?}"); return Err(err.into()); } } tracing::info!("Instance is created."); Ok(instance_id.to_string()) }
-
Per i dettagli sulle API, consulta il riferimento RunInstances
all'API AWS SDK for Rust.
-
Il seguente esempio di codice mostra come utilizzareStartInstances
.
- SDK per Rust
-
Nota
C'è altro da fare GitHub. Trova l'esempio completo e scopri di più sulla configurazione e l'esecuzione nel Repository di esempi di codice AWS
. Avvia un' EC2 istanza per ID di istanza.
pub async fn start_instance(&self, instance_id: &str) -> Result<(), EC2Error> { tracing::info!("Starting instance {instance_id}"); self.client .start_instances() .instance_ids(instance_id) .send() .await?; tracing::info!("Started instance."); Ok(()) }
Attendi che un'istanza sia negli stati ready e status ok, utilizzando l'API Waiters. L'utilizzo dell'API Waiters richiede `use aws_sdk_ec2: :client: :Waiters` nel file rust.
/// Wait for an instance to be ready and status ok (default wait 60 seconds) pub async fn wait_for_instance_ready( &self, instance_id: &str, duration: Option<Duration>, ) -> Result<(), EC2Error> { self.client .wait_until_instance_status_ok() .instance_ids(instance_id) .wait(duration.unwrap_or(Duration::from_secs(60))) .await .map_err(|err| match err { WaiterError::ExceededMaxWait(exceeded) => EC2Error(format!( "Exceeded max time ({}s) waiting for instance to start.", exceeded.max_wait().as_secs() )), _ => EC2Error::from(err), })?; Ok(()) }
-
Per i dettagli StartInstances
sull'API AWS , consulta il riferimento all'API SDK for Rust.
-
Il seguente esempio di codice mostra come utilizzareStopInstances
.
- SDK per Rust
-
Nota
C'è altro da fare GitHub. Trova l'esempio completo e scopri di più sulla configurazione e l'esecuzione nel Repository di esempi di codice AWS
. pub async fn stop_instance(&self, instance_id: &str) -> Result<(), EC2Error> { tracing::info!("Stopping instance {instance_id}"); self.client .stop_instances() .instance_ids(instance_id) .send() .await?; self.wait_for_instance_stopped(instance_id, None).await?; tracing::info!("Stopped instance."); Ok(()) }
Attendi che un'istanza si trovi nello stato interrotto, utilizzando l'API Waiters. L'utilizzo dell'API Waiters richiede `use aws_sdk_ec2: :client: :Waiters` nel file rust.
pub async fn stop_instance(&self, instance_id: &str) -> Result<(), EC2Error> { tracing::info!("Stopping instance {instance_id}"); self.client .stop_instances() .instance_ids(instance_id) .send() .await?; self.wait_for_instance_stopped(instance_id, None).await?; tracing::info!("Stopped instance."); Ok(()) }
-
Per i dettagli StopInstances
sull'API AWS , consulta il riferimento all'API SDK for Rust.
-
Il seguente esempio di codice mostra come utilizzareTerminateInstances
.
- SDK per Rust
-
Nota
C'è altro da fare GitHub. Trova l'esempio completo e scopri di più sulla configurazione e l'esecuzione nel Repository di esempi di codice AWS
. pub async fn delete_instance(&self, instance_id: &str) -> Result<(), EC2Error> { tracing::info!("Deleting instance with id {instance_id}"); self.stop_instance(instance_id).await?; self.client .terminate_instances() .instance_ids(instance_id) .send() .await?; self.wait_for_instance_terminated(instance_id).await?; tracing::info!("Terminated instance with id {instance_id}"); Ok(()) }
Attendi che un'istanza sia terminata, utilizzando l'API Waiters. L'utilizzo dell'API Waiters richiede `use aws_sdk_ec2: :client: :Waiters` nel file rust.
async fn wait_for_instance_terminated(&self, instance_id: &str) -> Result<(), EC2Error> { self.client .wait_until_instance_terminated() .instance_ids(instance_id) .wait(Duration::from_secs(60)) .await .map_err(|err| match err { WaiterError::ExceededMaxWait(exceeded) => EC2Error(format!( "Exceeded max time ({}s) waiting for instance to terminate.", exceeded.max_wait().as_secs(), )), _ => EC2Error::from(err), })?; Ok(()) }
-
Per i dettagli TerminateInstances
sull'API AWS , consulta il riferimento all'API SDK for Rust.
-