Ejemplos de Amazon EC2 usando SDK para Rust
En los siguientes ejemplos de código se muestra cómo realizar acciones e implementar escenarios comunes mediante AWS SDK para Rust con Amazon EC2.
Los conceptos básicos son ejemplos de código que muestran cómo realizar las operaciones esenciales dentro de un servicio.
Las acciones son extractos de código de programas más grandes y deben ejecutarse en contexto. Mientras las acciones muestran cómo llamar a las distintas funciones de servicio, es posible ver las acciones en contexto en los escenarios relacionados.
En cada ejemplo se incluye un enlace al código de origen completo, con instrucciones de configuración y ejecución del código en el contexto.
Introducción
En los siguientes ejemplos de código, se muestra cómo empezar a utilizar Amazon EC2.
- SDK para Rust
-
nota
Hay más en GitHub. Busque el ejemplo completo y aprenda a configurar y ejecutar en el Repositorio de ejemplos de código de 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}"); } } }-
Para obtener información sobre la API, consulte DescribeSecurityGroups
en Referencia de la API de AWS SDK para Rust.
-
Conceptos básicos
En el siguiente ejemplo de código, se muestra cómo:
Cree un par de claves y un grupo de seguridad.
Seleccione una Imagen de máquina de Amazon (AMI) y un tipo de instancia; a continuación, cree una instancia.
Detenga y vuelva a iniciar la instancia.
Asocie una dirección IP elástica a su instancia.
Conéctese a tu instancia con SSH y, a continuación, limpie los recursos.
- SDK para Rust
-
nota
Hay más en GitHub. Busque el ejemplo completo y aprenda a configurar y ejecutar en el Repositorio de ejemplos de código de AWS
. La implementación de EC2InstanceScenario contiene la lógica para ejecutar el ejemplo en su conjunto.
//! 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 estructura EC2Impl sirve como punto de automock para las pruebas y sus funciones encapsulan las llamadas al SDK de EC2.
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 estructura SSM sirve como punto de automock para las pruebas y sus funciones encapsulan las llamadas al SDK de SSM.
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) } }El escenario utiliza varias estructuras de tipo “Manager” para gestionar el acceso a los recursos que se crean y eliminan durante el escenario.
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."), } } }El punto de entrada principal del escenario.
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; }-
Para obtener información sobre la API, consulte los siguientes temas en la Referencia de la API de AWS SDK para Rust.
-
Acciones
En el siguiente ejemplo de código, se muestra cómo utilizar AllocateAddress.
- SDK para Rust
-
nota
Hay más en GitHub. Busque el ejemplo completo y aprenda a configurar y ejecutar en el Repositorio de ejemplos de código de AWS
. pub async fn allocate_ip_address(&self) -> Result<AllocateAddressOutput, EC2Error> { self.client .allocate_address() .domain(DomainType::Vpc) .send() .await .map_err(EC2Error::from) }-
Para obtener información sobre la API, consulte AllocateAddress
en la Referencia de la API de AWS SDK para Rust.
-
En el siguiente ejemplo de código, se muestra cómo utilizar AssociateAddress.
- SDK para Rust
-
nota
Hay más en GitHub. Busque el ejemplo completo y aprenda a configurar y ejecutar en el Repositorio de ejemplos de código de 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) }-
Para obtener información sobre la API, consulte AssociateAddress
en Referencia de la API de SDK de AWS para Rust.
-
En el siguiente ejemplo de código, se muestra cómo utilizar AuthorizeSecurityGroupIngress.
- SDK para Rust
-
nota
Hay más en GitHub. Busque el ejemplo completo y aprenda a configurar y ejecutar en el Repositorio de ejemplos de código de 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(()) }-
Para obtener información sobre la API, consulte AuthorizeSecurityGroupIngress
en la referencia de la API de AWS SDK para Rust.
-
En el siguiente ejemplo de código, se muestra cómo utilizar CreateKeyPair.
- SDK para Rust
-
nota
Hay más en GitHub. Busque el ejemplo completo y aprenda a configurar y ejecutar en el Repositorio de ejemplos de código de AWS
. Implementación de Rust que llama a create_key_pair del cliente de EC2 y extrae el material devuelto.
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 función que llama a impl create_key y guarda de forma segura la clave privada de 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) }-
Para obtener información sobre la API, consulte CreateKeyPair
en la Referencia de la API de AWS SDK para Rust.
-
En el siguiente ejemplo de código, se muestra cómo utilizar CreateSecurityGroup.
- SDK para Rust
-
nota
Hay más en GitHub. Busque el ejemplo completo y aprenda a configurar y ejecutar en el Repositorio de ejemplos de código de 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) }-
Para obtener información sobre la API, consulte CreateSecurityGroup
en la Referencia de la API de AWS SDK para Rust.
-
En el siguiente ejemplo de código, se muestra cómo utilizar CreateTags.
- SDK para Rust
-
nota
Hay más en GitHub. Busque el ejemplo completo y aprenda a configurar y ejecutar en el Repositorio de ejemplos de código de AWS
. En este ejemplo se aplica la etiqueta Name después de crear una instancia.
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()) }-
Para obtener información sobre la API, consulte CreateTags
en la Referencia de la API de AWS SDK para Rust.
-
En el siguiente ejemplo de código, se muestra cómo utilizar DeleteKeyPair.
- SDK para Rust
-
nota
Hay más en GitHub. Busque el ejemplo completo y aprenda a configurar y ejecutar en el Repositorio de ejemplos de código de AWS
. Encapsulador de delete_key que también elimina la clave de PEM privada de respaldo.
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(()) }-
Para obtener información sobre la API, consulte DeleteKeyPair
en la Referencia de la API de AWS SDK para Rust.
-
En el siguiente ejemplo de código, se muestra cómo utilizar DeleteSecurityGroup.
- SDK para Rust
-
nota
Hay más en GitHub. Busque el ejemplo completo y aprenda a configurar y ejecutar en el Repositorio de ejemplos de código de 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(()) }-
Para obtener información sobre la API, consulte DeleteSecurityGroup
en la Referencia de la API de AWS SDK para Rust.
-
En el siguiente ejemplo de código, se muestra cómo utilizar DeleteSnapshot.
- SDK para Rust
-
nota
Hay más en GitHub. Busque el ejemplo completo y aprenda a configurar y ejecutar en el Repositorio de ejemplos de código de AWS
. async fn delete_snapshot(client: &Client, id: &str) -> Result<(), Error> { client.delete_snapshot().snapshot_id(id).send().await?; println!("Deleted"); Ok(()) }-
Para obtener información sobre la API, consulte DeleteSnapshot
en la Referencia de la API de AWS SDK para Rust.
-
En el siguiente ejemplo de código, se muestra cómo utilizar DescribeImages.
- SDK para Rust
-
nota
Hay más en GitHub. Busque el ejemplo completo y aprenda a configurar y ejecutar en el Repositorio de ejemplos de código de 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) } }Usar la función list_images con SSM para establecer límites en función del entorno. Para obtener más información sobre SSM, consulte https://docs.aws.amazon.com/systems-manager/latest/userguide/example_ssm_GetParameters_section.html.
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) }-
Para obtener información sobre la API, consulte DescribeImages
en la Referencia de la API de AWS SDK para Rust.
-
En el siguiente ejemplo de código, se muestra cómo utilizar DescribeInstanceStatus.
- SDK para Rust
-
nota
Hay más en GitHub. Busque el ejemplo completo y aprenda a configurar y ejecutar en el Repositorio de ejemplos de código de 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(()) }-
Para obtener información sobre la API, consulte DescribeInstanceStatus
en la Referencia del SDK de AWS para la API de Rust.
-
En el siguiente ejemplo de código, se muestra cómo utilizar DescribeInstanceTypes.
- SDK para Rust
-
nota
Hay más en GitHub. Busque el ejemplo completo y aprenda a configurar y ejecutar en el Repositorio de ejemplos de código de 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()) }-
Para obtener información sobre la API, consulte DescribeInstanceTypes
en Referencia de la API de AWS SDK para Rust.
-
En el siguiente ejemplo de código, se muestra cómo utilizar DescribeInstances.
- SDK para Rust
-
nota
Hay más en GitHub. Busque el ejemplo completo y aprenda a configurar y ejecutar en el Repositorio de ejemplos de código de AWS
. Recupere detalles de una instancia de EC2.
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()) }Tras crear una instancia de EC2, recupere y almacene sus detalles.
/// 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(()) }-
Para obtener información sobre la API, consulte DescribeInstances
en Referencia de la API de AWS SDK para Rust.
-
En el siguiente ejemplo de código, se muestra cómo utilizar DescribeKeyPairs.
- SDK para Rust
-
nota
Hay más en GitHub. Busque el ejemplo completo y aprenda a configurar y ejecutar en el Repositorio de ejemplos de código de 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()) }-
Para obtener información sobre la API, consulte DescribeKeyPairs
en Referencia de la API de AWS SDK para Rust.
-
En el siguiente ejemplo de código, se muestra cómo utilizar DescribeRegions.
- SDK para Rust
-
nota
Hay más en GitHub. Busque el ejemplo completo y aprenda a configurar y ejecutar en el Repositorio de ejemplos de código de 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(()) }-
Para obtener información sobre la API, consulte DescribeRegions
en la Referencia de la API de AWS SDK para Rust.
-
En el siguiente ejemplo de código, se muestra cómo utilizar DescribeSecurityGroups.
- SDK para Rust
-
nota
Hay más en GitHub. Busque el ejemplo completo y aprenda a configurar y ejecutar en el Repositorio de ejemplos de código de 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}"); } } }-
Para obtener información sobre la API, consulte DescribeSecurityGroups
en Referencia de la API de AWS SDK para Rust.
-
En el siguiente ejemplo de código, se muestra cómo utilizar DescribeSnapshots.
- SDK para Rust
-
nota
Hay más en GitHub. Busque el ejemplo completo y aprenda a configurar y ejecutar en el Repositorio de ejemplos de código de AWS
. Muestra el estado de una instantánea.
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(()) }-
Para obtener información sobre la API, consulte DescribeSnapshots
en Referencia de la API de AWS SDK para Rust.
-
En el siguiente ejemplo de código, se muestra cómo utilizar DisassociateAddress.
- SDK para Rust
-
nota
Hay más en GitHub. Busque el ejemplo completo y aprenda a configurar y ejecutar en el Repositorio de ejemplos de código de AWS
. pub async fn disassociate_ip_address(&self, association_id: &str) -> Result<(), EC2Error> { self.client .disassociate_address() .association_id(association_id) .send() .await?; Ok(()) }-
Para obtener información sobre la API, consulte DisassociateAddress
en la Referencia de la API de AWS SDK para Rust.
-
En el siguiente ejemplo de código, se muestra cómo utilizar RebootInstances.
- SDK para Rust
-
nota
Hay más en GitHub. Busque el ejemplo completo y aprenda a configurar y ejecutar en el Repositorio de ejemplos de código de 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(()) }Los «waiters» de la instancia que van a tener los estados detenido y listo, mediante la API de Waiters. El uso de la API de Waiters requiere «use aws_sdk_ec2::client::Waiters» en el archivo 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(()) }-
Para obtener información sobre la API, consulte RebootInstances
en la Referencia de la API de AWS SDK para Rust.
-
En el siguiente ejemplo de código, se muestra cómo utilizar ReleaseAddress.
- SDK para Rust
-
nota
Hay más en GitHub. Busque el ejemplo completo y aprenda a configurar y ejecutar en el Repositorio de ejemplos de código de AWS
. pub async fn deallocate_ip_address(&self, allocation_id: &str) -> Result<(), EC2Error> { self.client .release_address() .allocation_id(allocation_id) .send() .await?; Ok(()) }-
Para obtener información sobre la API, consulte ReleaseAddress
en la Referencia de la API de AWS SDK para Rust.
-
En el siguiente ejemplo de código, se muestra cómo utilizar RunInstances.
- SDK para Rust
-
nota
Hay más en GitHub. Busque el ejemplo completo y aprenda a configurar y ejecutar en el Repositorio de ejemplos de código de 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()) }-
Para obtener información sobre la API, consulte RunInstances
en la Referencia de la API de AWS SDK para Rust.
-
En el siguiente ejemplo de código, se muestra cómo utilizar StartInstances.
- SDK para Rust
-
nota
Hay más en GitHub. Busque el ejemplo completo y aprenda a configurar y ejecutar en el Repositorio de ejemplos de código de AWS
. Inicie una instancia de EC2 por ID de instancia.
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(()) }Los «waiters» de una instancia que van a tener los estados detenido y listo, mediante la API de Waiters. El uso de la API de Waiters requiere «use aws_sdk_ec2::client::Waiters» en el archivo 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(()) }-
Para obtener información sobre la API, consulte StartInstances
en la Referencia de la API de AWS SDK para Rust.
-
En el siguiente ejemplo de código, se muestra cómo utilizar StopInstances.
- SDK para Rust
-
nota
Hay más en GitHub. Busque el ejemplo completo y aprenda a configurar y ejecutar en el Repositorio de ejemplos de código de 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(()) }Los «waiters» de una instancia que van a tener el estado detenido, mediante la API de Waiters. El uso de la API de Waiters requiere «use aws_sdk_ec2::client::Waiters» en el archivo 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(()) }-
Para obtener información sobre la API, consulte StopInstances
en la Referencia de la API de AWS SDK para Rust.
-
En el siguiente ejemplo de código, se muestra cómo utilizar TerminateInstances.
- SDK para Rust
-
nota
Hay más en GitHub. Busque el ejemplo completo y aprenda a configurar y ejecutar en el Repositorio de ejemplos de código de 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(()) }Los «waiters» de una instancia que van a tener el estado terminado, mediante la API de Waiters. El uso de la API de Waiters requiere «use aws_sdk_ec2::client::Waiters» en el archivo 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(()) }-
Para obtener información sobre la API, consulte TerminateInstances
en la Referencia de la API de AWS SDK para Rust.
-