use std::collections::BTreeMap;
use std::sync::Arc;
use parking_lot::RwLock;
use serde::{Deserialize, Serialize};
pub type SharedEc2State = Arc<RwLock<fakecloud_core::multi_account::MultiAccountState<Ec2State>>>;
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Ec2Snapshot {
pub schema_version: u32,
#[serde(default)]
pub accounts: Option<fakecloud_core::multi_account::MultiAccountState<Ec2State>>,
}
pub const EC2_SNAPSHOT_SCHEMA_VERSION: u32 = 1;
impl fakecloud_core::multi_account::AccountState for Ec2State {
fn new_for_account(account_id: &str, region: &str, _endpoint: &str) -> Self {
Self::new(account_id, region)
}
}
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
pub struct Tag {
pub key: String,
pub value: String,
}
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct VpcCidrAssoc {
pub association_id: String,
pub cidr_block: String,
pub state: String,
}
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct Vpc {
pub vpc_id: String,
pub cidr_block: String,
pub state: String,
pub dhcp_options_id: String,
pub instance_tenancy: String,
pub is_default: bool,
pub enable_dns_support: bool,
pub enable_dns_hostnames: bool,
#[serde(default)]
pub cidr_associations: Vec<VpcCidrAssoc>,
#[serde(default)]
pub ipv6_cidr_block: Option<String>,
}
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct DhcpConfig {
pub key: String,
pub values: Vec<String>,
}
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct DhcpOptions {
pub dhcp_options_id: String,
pub configurations: Vec<DhcpConfig>,
}
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct Subnet {
pub subnet_id: String,
pub vpc_id: String,
pub cidr_block: String,
pub availability_zone: String,
pub availability_zone_id: String,
pub state: String,
pub available_ip_address_count: i32,
pub default_for_az: bool,
pub map_public_ip_on_launch: bool,
pub assign_ipv6_address_on_creation: bool,
pub map_customer_owned_ip_on_launch: bool,
pub enable_dns64: bool,
pub private_dns_hostname_type: String,
#[serde(default)]
pub ipv6_cidr_block: Option<String>,
}
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct SubnetCidrReservation {
pub subnet_cidr_reservation_id: String,
pub subnet_id: String,
pub cidr: String,
pub reservation_type: String,
pub description: String,
}
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct SecurityGroupRule {
pub rule_id: String,
pub group_id: String,
pub is_egress: bool,
pub ip_protocol: String,
pub from_port: i64,
pub to_port: i64,
pub cidr_ipv4: Option<String>,
pub cidr_ipv6: Option<String>,
pub prefix_list_id: Option<String>,
pub referenced_group_id: Option<String>,
pub description: String,
}
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct SecurityGroup {
pub group_id: String,
pub group_name: String,
pub description: String,
pub vpc_id: String,
#[serde(default)]
pub rules: Vec<SecurityGroupRule>,
}
#[derive(Clone, Debug, Default, Serialize, Deserialize)]
pub struct Route {
pub destination_cidr_block: Option<String>,
pub destination_ipv6_cidr_block: Option<String>,
pub destination_prefix_list_id: Option<String>,
pub gateway_id: Option<String>,
pub nat_gateway_id: Option<String>,
pub network_interface_id: Option<String>,
pub instance_id: Option<String>,
pub vpc_peering_connection_id: Option<String>,
pub transit_gateway_id: Option<String>,
pub egress_only_internet_gateway_id: Option<String>,
pub state: String,
pub origin: String,
}
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct RouteTableAssociation {
pub association_id: String,
pub route_table_id: String,
pub subnet_id: Option<String>,
pub gateway_id: Option<String>,
pub main: bool,
}
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct RouteTable {
pub route_table_id: String,
pub vpc_id: String,
#[serde(default)]
pub routes: Vec<Route>,
#[serde(default)]
pub associations: Vec<RouteTableAssociation>,
}
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct InternetGateway {
pub internet_gateway_id: String,
#[serde(default)]
pub attachments: Vec<(String, String)>,
}
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct NatGateway {
pub nat_gateway_id: String,
pub subnet_id: String,
pub vpc_id: String,
pub state: String,
pub connectivity_type: String,
pub allocation_id: Option<String>,
}
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct ElasticIp {
pub allocation_id: String,
pub public_ip: String,
pub domain: String,
pub association_id: Option<String>,
pub instance_id: Option<String>,
pub network_interface_id: Option<String>,
pub private_ip_address: Option<String>,
}
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct KeyPair {
pub key_pair_id: String,
pub key_name: String,
pub key_type: String,
pub key_fingerprint: String,
}
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct PlacementGroup {
pub group_id: String,
pub group_name: String,
pub strategy: String,
pub state: String,
pub partition_count: Option<i64>,
pub spread_level: Option<String>,
}
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct EniAttachment {
pub attachment_id: String,
pub instance_id: String,
pub device_index: i64,
pub status: String,
}
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct NetworkInterface {
pub network_interface_id: String,
pub subnet_id: String,
pub vpc_id: String,
pub availability_zone: String,
pub description: String,
pub mac_address: String,
pub private_ip_address: String,
pub status: String,
pub interface_type: String,
pub source_dest_check: bool,
#[serde(default)]
pub group_ids: Vec<String>,
#[serde(default)]
pub private_ips: Vec<String>,
#[serde(default)]
pub ipv6_addresses: Vec<String>,
pub attachment: Option<EniAttachment>,
}
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct NetworkInterfacePermission {
pub permission_id: String,
pub network_interface_id: String,
pub aws_account_id: String,
pub permission: String,
}
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct Instance {
pub instance_id: String,
pub image_id: String,
pub instance_type: String,
pub state_code: i64,
pub state_name: String,
pub private_ip: String,
pub public_ip: Option<String>,
pub subnet_id: Option<String>,
pub vpc_id: Option<String>,
pub key_name: Option<String>,
#[serde(default)]
pub security_group_ids: Vec<String>,
pub reservation_id: String,
pub ami_launch_index: i64,
pub monitoring: bool,
pub az: String,
pub launch_time: String,
#[serde(default)]
pub container_id: Option<String>,
#[serde(default)]
pub disable_api_termination: bool,
#[serde(default)]
pub disable_api_stop: bool,
#[serde(default = "default_true")]
pub source_dest_check: bool,
#[serde(default)]
pub ebs_optimized: bool,
#[serde(default = "default_shutdown_behavior")]
pub instance_initiated_shutdown_behavior: String,
#[serde(default)]
pub user_data: Option<String>,
#[serde(default)]
pub metadata_options: MetadataOptions,
#[serde(default)]
pub cpu_options: Option<CpuOptions>,
#[serde(default)]
pub bandwidth_weighting: Option<String>,
#[serde(default)]
pub maintenance_options: MaintenanceOptions,
#[serde(default)]
pub placement_tenancy: Option<String>,
#[serde(default)]
pub placement_affinity: Option<String>,
#[serde(default)]
pub placement_group_name: Option<String>,
}
fn default_true() -> bool {
true
}
fn default_shutdown_behavior() -> String {
"stop".to_string()
}
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct MetadataOptions {
pub http_tokens: String,
pub http_endpoint: String,
pub http_put_response_hop_limit: i64,
pub http_protocol_ipv6: String,
pub instance_metadata_tags: String,
}
impl Default for MetadataOptions {
fn default() -> Self {
Self {
http_tokens: "optional".to_string(),
http_endpoint: "enabled".to_string(),
http_put_response_hop_limit: 1,
http_protocol_ipv6: "disabled".to_string(),
instance_metadata_tags: "disabled".to_string(),
}
}
}
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct CpuOptions {
pub core_count: i64,
pub threads_per_core: i64,
}
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct MaintenanceOptions {
pub auto_recovery: String,
pub reboot_migration: String,
}
impl Default for MaintenanceOptions {
fn default() -> Self {
Self {
auto_recovery: "default".to_string(),
reboot_migration: "default".to_string(),
}
}
}
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct VolumeAttachment {
pub volume_id: String,
pub instance_id: String,
pub device: String,
pub status: String,
pub delete_on_termination: bool,
}
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct Volume {
pub volume_id: String,
pub size: i64,
pub snapshot_id: Option<String>,
pub availability_zone: String,
pub state: String,
pub volume_type: String,
pub iops: Option<i64>,
pub throughput: Option<i64>,
pub encrypted: bool,
pub kms_key_id: Option<String>,
pub multi_attach_enabled: bool,
pub auto_enable_io: bool,
#[serde(default)]
pub attachments: Vec<VolumeAttachment>,
#[serde(default)]
pub in_recycle_bin: bool,
}
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct Snapshot {
pub snapshot_id: String,
pub volume_id: String,
pub state: String,
pub volume_size: i64,
pub description: String,
pub encrypted: bool,
pub storage_tier: String,
#[serde(default)]
pub in_recycle_bin: bool,
#[serde(default)]
pub locked: bool,
pub lock_mode: Option<String>,
}
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct Image {
pub image_id: String,
pub name: String,
pub description: String,
pub state: String,
pub architecture: String,
pub public: bool,
pub source_instance_id: Option<String>,
#[serde(default)]
pub in_recycle_bin: bool,
pub deprecation_time: Option<String>,
#[serde(default)]
pub deregistration_protection: bool,
#[serde(default)]
pub launch_permission_users: Vec<String>,
#[serde(default)]
pub launch_permission_groups: Vec<String>,
#[serde(default)]
pub boot_mode: Option<String>,
}
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct NetworkAclEntry {
pub rule_number: i64,
pub protocol: String,
pub rule_action: String,
pub egress: bool,
pub cidr_block: Option<String>,
pub ipv6_cidr_block: Option<String>,
pub port_range: Option<(i64, i64)>,
pub icmp_type_code: Option<(i64, i64)>,
}
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct NetworkAclAssoc {
pub association_id: String,
pub subnet_id: String,
}
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct NetworkAcl {
pub network_acl_id: String,
pub vpc_id: String,
pub is_default: bool,
#[serde(default)]
pub entries: Vec<NetworkAclEntry>,
#[serde(default)]
pub associations: Vec<NetworkAclAssoc>,
}
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct VpcPeering {
pub id: String,
pub requester_vpc_id: String,
pub accepter_vpc_id: String,
pub status: String,
#[serde(default)]
pub requester_allow_dns: bool,
#[serde(default)]
pub accepter_allow_dns: bool,
}
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct VpcEndpoint {
pub id: String,
pub endpoint_type: String,
pub vpc_id: String,
pub service_name: String,
pub state: String,
#[serde(default)]
pub subnet_ids: Vec<String>,
#[serde(default)]
pub route_table_ids: Vec<String>,
#[serde(default)]
pub private_dns_enabled: bool,
}
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct EndpointService {
pub service_id: String,
pub service_name: String,
pub state: String,
pub acceptance_required: bool,
pub payer_responsibility: String,
#[serde(default)]
pub nlb_arns: Vec<String>,
}
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct ConnectionNotification {
pub id: String,
pub arn: String,
pub service_id: Option<String>,
#[serde(default)]
pub events: Vec<String>,
}
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct FlowLog {
pub id: String,
pub resource_id: String,
pub traffic_type: String,
pub log_destination_type: String,
pub log_group_name: Option<String>,
pub log_destination: Option<String>,
}
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct LaunchTemplate {
pub id: String,
pub name: String,
pub default_version: i64,
pub latest_version: i64,
}
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct SpotRequest {
pub id: String,
pub state: String,
pub request_type: String,
pub spot_price: String,
}
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct SpotFleet {
pub id: String,
pub state: String,
}
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct Fleet {
pub id: String,
pub state: String,
pub fleet_type: String,
}
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct CapacityReservation {
pub id: String,
pub instance_type: String,
pub instance_platform: String,
pub availability_zone: String,
pub tenancy: String,
pub total_instance_count: i64,
pub available_instance_count: i64,
pub state: String,
pub end_date_type: String,
pub instance_match_criteria: String,
}
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct ReservedInstances {
pub id: String,
pub instance_type: String,
pub availability_zone: String,
pub instance_count: i64,
pub product_description: String,
pub state: String,
pub duration: i64,
pub fixed_price: String,
pub usage_price: String,
}
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct ReservedInstancesListing {
pub listing_id: String,
pub reserved_instances_id: String,
pub instance_count: i64,
pub client_token: String,
pub status: String,
pub status_message: String,
}
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct ReservedInstancesModification {
pub modification_id: String,
pub reserved_instances_ids: Vec<String>,
pub status: String,
pub client_token: String,
}
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct DedicatedHost {
pub id: String,
pub auto_placement: String,
pub availability_zone: String,
pub instance_type: String,
pub state: String,
pub host_recovery: String,
pub host_maintenance: String,
}
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct TransitGateway {
pub id: String,
pub description: String,
#[serde(default = "tgw_default_state")]
pub state: String,
}
fn tgw_default_state() -> String {
"available".to_string()
}
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct TgwAttachment {
pub id: String,
pub tgw_id: String,
pub resource_id: String,
pub resource_type: String,
#[serde(default)]
pub subnet_ids: Vec<String>,
pub state: String,
}
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct TgwRouteTable {
pub id: String,
pub tgw_id: String,
}
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct TgwRoute {
pub cidr: String,
pub attachment_id: String,
pub state: String,
}
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct TgwMulticastDomain {
pub id: String,
pub tgw_id: String,
}
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct TgwMeteringPolicy {
pub id: String,
pub tgw_id: String,
}
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct CustomerGateway {
pub id: String,
pub state: String,
pub ip_address: String,
pub bgp_asn: String,
}
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct VpnGateway {
pub id: String,
pub state: String,
#[serde(default)]
pub attachments: Vec<String>,
}
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct VpnConnection {
pub id: String,
pub state: String,
pub customer_gateway_id: String,
pub vpn_gateway_id: Option<String>,
#[serde(default)]
pub routes: Vec<String>,
}
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct VpnConcentrator {
pub id: String,
pub state: String,
}
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct Ipam {
pub id: String,
pub public_scope_id: String,
pub private_scope_id: String,
pub tier: String,
#[serde(default)]
pub description: String,
}
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct IpamScope {
pub id: String,
pub ipam_id: String,
#[serde(default)]
pub scope_type: String,
#[serde(default)]
pub description: String,
}
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct IpamPool {
pub id: String,
pub scope_id: String,
pub address_family: String,
#[serde(default)]
pub description: String,
}
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct IpamResourceDiscovery {
pub id: String,
#[serde(default)]
pub description: String,
}
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct IpamPolicy {
pub id: String,
pub ipam_id: String,
}
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct IpamPrefixListResolver {
pub id: String,
pub ipam_id: String,
pub address_family: String,
#[serde(default)]
pub description: String,
}
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct IpamPrefixListResolverTarget {
pub id: String,
pub resolver_id: String,
pub prefix_list_id: String,
pub prefix_list_region: String,
#[serde(default)]
pub track_latest_version: bool,
}
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct VerifiedAccessInstance {
pub id: String,
pub description: String,
#[serde(default)]
pub trust_providers: Vec<String>,
}
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct VerifiedAccessTrustProvider {
pub id: String,
pub trust_provider_type: String,
pub policy_reference_name: String,
pub description: String,
}
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct VerifiedAccessGroup {
pub id: String,
pub instance_id: String,
pub description: String,
}
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct VerifiedAccessEndpoint {
pub id: String,
pub group_id: String,
pub instance_id: String,
pub endpoint_type: String,
pub attachment_type: String,
}
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct NetworkInsightsPath {
pub id: String,
pub source: String,
pub destination: String,
pub protocol: String,
}
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct NetworkInsightsAnalysis {
pub id: String,
pub path_id: String,
}
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct NetworkInsightsAccessScope {
pub id: String,
}
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct NetworkInsightsAccessScopeAnalysis {
pub id: String,
pub scope_id: String,
}
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct CarrierGateway {
pub id: String,
pub vpc_id: String,
}
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct InstanceConnectEndpoint {
pub id: String,
pub subnet_id: String,
}
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct CoipPool {
pub id: String,
pub route_table_id: String,
}
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct LocalGatewayRouteTable {
pub id: String,
pub local_gateway_id: String,
pub mode: String,
}
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct LocalGatewayRouteTableVpcAssoc {
pub id: String,
pub route_table_id: String,
pub vpc_id: String,
}
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct LocalGatewayVif {
pub id: String,
pub group_id: String,
pub vlan: String,
pub local_address: String,
pub peer_address: String,
}
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct LocalGatewayVifGroup {
pub id: String,
pub local_gateway_id: String,
}
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct LocalGatewayRouteTableVifgAssoc {
pub id: String,
pub route_table_id: String,
pub vif_group_id: String,
}
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct ClientVpnEndpoint {
pub id: String,
pub description: String,
pub status: String,
pub server_cert_arn: String,
pub transport_protocol: String,
pub client_cidr: String,
#[serde(default)]
pub routes: Vec<String>,
#[serde(default)]
pub target_networks: Vec<(String, String)>,
#[serde(default)]
pub auth_rules: Vec<String>,
}
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct TgwPeering {
pub id: String,
pub tgw_id: String,
pub peer_tgw_id: String,
pub peer_account: String,
pub peer_region: String,
pub state: String,
}
#[derive(Clone, Debug, Default, Serialize, Deserialize)]
pub struct Ec2State {
pub account_id: String,
pub region: String,
#[serde(default)]
pub tags: BTreeMap<String, Vec<Tag>>,
#[serde(default)]
pub vpcs: BTreeMap<String, Vpc>,
#[serde(default)]
pub dhcp_options: BTreeMap<String, DhcpOptions>,
#[serde(default)]
pub subnets: BTreeMap<String, Subnet>,
#[serde(default)]
pub subnet_cidr_reservations: BTreeMap<String, SubnetCidrReservation>,
#[serde(default)]
pub security_groups: BTreeMap<String, SecurityGroup>,
#[serde(default)]
pub route_tables: BTreeMap<String, RouteTable>,
#[serde(default)]
pub internet_gateways: BTreeMap<String, InternetGateway>,
#[serde(default)]
pub egress_only_igws: BTreeMap<String, InternetGateway>,
#[serde(default)]
pub nat_gateways: BTreeMap<String, NatGateway>,
#[serde(default)]
pub elastic_ips: BTreeMap<String, ElasticIp>,
#[serde(default)]
pub key_pairs: BTreeMap<String, KeyPair>,
#[serde(default)]
pub placement_groups: BTreeMap<String, PlacementGroup>,
#[serde(default)]
pub network_interfaces: BTreeMap<String, NetworkInterface>,
#[serde(default)]
pub eni_permissions: BTreeMap<String, NetworkInterfacePermission>,
#[serde(default)]
pub instances: BTreeMap<String, Instance>,
#[serde(default)]
pub volumes: BTreeMap<String, Volume>,
#[serde(default)]
pub ebs_encryption_default: bool,
#[serde(default)]
pub ebs_default_kms_key_id: Option<String>,
#[serde(default)]
pub snapshots: BTreeMap<String, Snapshot>,
#[serde(default)]
pub snapshot_block_public_access: String,
#[serde(default)]
pub images: BTreeMap<String, Image>,
#[serde(default)]
pub image_watermarks: BTreeMap<String, BTreeMap<String, String>>,
#[serde(default)]
pub image_block_public_access: String,
#[serde(default)]
pub allowed_images_settings: String,
#[serde(default)]
pub network_acls: BTreeMap<String, NetworkAcl>,
#[serde(default)]
pub vpc_peerings: BTreeMap<String, VpcPeering>,
#[serde(default)]
pub vpc_endpoints: BTreeMap<String, VpcEndpoint>,
#[serde(default)]
pub endpoint_services: BTreeMap<String, EndpointService>,
#[serde(default)]
pub connection_notifications: BTreeMap<String, ConnectionNotification>,
#[serde(default)]
pub flow_logs: BTreeMap<String, FlowLog>,
#[serde(default)]
pub launch_templates: BTreeMap<String, LaunchTemplate>,
#[serde(default)]
pub spot_requests: BTreeMap<String, SpotRequest>,
#[serde(default)]
pub spot_fleets: BTreeMap<String, SpotFleet>,
#[serde(default)]
pub fleets: BTreeMap<String, Fleet>,
#[serde(default)]
pub spot_datafeed: Option<(String, String)>,
#[serde(default)]
pub capacity_reservations: BTreeMap<String, CapacityReservation>,
#[serde(default)]
pub capacity_reservation_fleets: BTreeMap<String, String>,
#[serde(default)]
pub reserved_instances: BTreeMap<String, ReservedInstances>,
#[serde(default)]
pub reserved_instances_listings: BTreeMap<String, ReservedInstancesListing>,
#[serde(default)]
pub reserved_instances_modifications: BTreeMap<String, ReservedInstancesModification>,
#[serde(default)]
pub dedicated_hosts: BTreeMap<String, DedicatedHost>,
#[serde(default)]
pub transit_gateways: BTreeMap<String, TransitGateway>,
#[serde(default)]
pub tgw_attachments: BTreeMap<String, TgwAttachment>,
#[serde(default)]
pub tgw_route_tables: BTreeMap<String, TgwRouteTable>,
#[serde(default)]
pub tgw_routes: BTreeMap<String, Vec<TgwRoute>>,
#[serde(default)]
pub tgw_rt_associations: BTreeMap<String, Vec<String>>,
#[serde(default)]
pub tgw_rt_propagations: BTreeMap<String, Vec<String>>,
#[serde(default)]
pub tgw_prefix_list_refs: BTreeMap<String, Vec<String>>,
#[serde(default)]
pub tgw_peerings: BTreeMap<String, TgwPeering>,
#[serde(default)]
pub tgw_connects: BTreeMap<String, (String, String)>,
#[serde(default)]
pub tgw_connect_peers: BTreeMap<String, String>,
#[serde(default)]
pub tgw_policy_tables: BTreeMap<String, String>,
#[serde(default)]
pub tgw_policy_table_associations: BTreeMap<String, Vec<String>>,
#[serde(default)]
pub tgw_announcements: BTreeMap<String, (String, String)>,
#[serde(default)]
pub tgw_multicast_domains: BTreeMap<String, TgwMulticastDomain>,
#[serde(default)]
pub tgw_metering_policies: BTreeMap<String, TgwMeteringPolicy>,
#[serde(default)]
pub customer_gateways: BTreeMap<String, CustomerGateway>,
#[serde(default)]
pub vpn_gateways: BTreeMap<String, VpnGateway>,
#[serde(default)]
pub vpn_connections: BTreeMap<String, VpnConnection>,
#[serde(default)]
pub vpn_concentrators: BTreeMap<String, VpnConcentrator>,
#[serde(default)]
pub client_vpn_endpoints: BTreeMap<String, ClientVpnEndpoint>,
#[serde(default)]
pub ipams: BTreeMap<String, Ipam>,
#[serde(default)]
pub ipam_scopes: BTreeMap<String, IpamScope>,
#[serde(default)]
pub ipam_pools: BTreeMap<String, IpamPool>,
#[serde(default)]
pub ipam_pool_cidrs: BTreeMap<String, Vec<(String, String)>>,
#[serde(default)]
pub ipam_pool_allocations: BTreeMap<String, Vec<(String, String)>>,
#[serde(default)]
pub ipam_resource_discoveries: BTreeMap<String, IpamResourceDiscovery>,
#[serde(default)]
pub ipam_rd_associations: BTreeMap<String, (String, String)>,
#[serde(default)]
pub ipam_byoasns: BTreeMap<String, String>,
#[serde(default)]
pub ipam_ext_tokens: BTreeMap<String, String>,
#[serde(default)]
pub ipam_policies: BTreeMap<String, IpamPolicy>,
#[serde(default)]
pub ipam_pl_resolvers: BTreeMap<String, IpamPrefixListResolver>,
#[serde(default)]
pub ipam_pl_resolver_targets: BTreeMap<String, IpamPrefixListResolverTarget>,
#[serde(default)]
pub ipam_policy_alloc_rules: BTreeMap<String, Vec<(String, String)>>,
#[serde(default)]
pub ipam_enabled_policy: Option<String>,
#[serde(default)]
pub va_instances: BTreeMap<String, VerifiedAccessInstance>,
#[serde(default)]
pub va_trust_providers: BTreeMap<String, VerifiedAccessTrustProvider>,
#[serde(default)]
pub va_groups: BTreeMap<String, VerifiedAccessGroup>,
#[serde(default)]
pub va_endpoints: BTreeMap<String, VerifiedAccessEndpoint>,
#[serde(default)]
pub va_group_policies: BTreeMap<String, String>,
#[serde(default)]
pub va_endpoint_policies: BTreeMap<String, String>,
#[serde(default)]
pub ni_paths: BTreeMap<String, NetworkInsightsPath>,
#[serde(default)]
pub ni_analyses: BTreeMap<String, NetworkInsightsAnalysis>,
#[serde(default)]
pub ni_access_scopes: BTreeMap<String, NetworkInsightsAccessScope>,
#[serde(default)]
pub ni_scope_analyses: BTreeMap<String, NetworkInsightsAccessScopeAnalysis>,
#[serde(default)]
pub carrier_gateways: BTreeMap<String, CarrierGateway>,
#[serde(default)]
pub coip_pools: BTreeMap<String, CoipPool>,
#[serde(default)]
pub coip_pool_cidrs: BTreeMap<String, Vec<String>>,
#[serde(default)]
pub lg_route_tables: BTreeMap<String, LocalGatewayRouteTable>,
#[serde(default)]
pub lg_routes: BTreeMap<String, Vec<String>>,
#[serde(default)]
pub lg_rt_vpc_assocs: BTreeMap<String, LocalGatewayRouteTableVpcAssoc>,
#[serde(default)]
pub lg_virtual_interfaces: BTreeMap<String, LocalGatewayVif>,
#[serde(default)]
pub lg_vif_groups: BTreeMap<String, LocalGatewayVifGroup>,
#[serde(default)]
pub lg_rt_vifg_assocs: BTreeMap<String, LocalGatewayRouteTableVifgAssoc>,
#[serde(default)]
pub instance_connect_endpoints: BTreeMap<String, InstanceConnectEndpoint>,
#[serde(default)]
pub fast_launch_images: std::collections::HashSet<String>,
#[serde(default)]
pub serial_console_access: bool,
}
impl Ec2State {
pub fn new(account_id: &str, region: &str) -> Self {
let mut state = Self {
account_id: account_id.to_string(),
region: region.to_string(),
..Default::default()
};
crate::defaults::bootstrap_default_network(&mut state);
state
}
pub fn upsert_tags(&mut self, resource_id: &str, new_tags: &[Tag]) {
let entry = self.tags.entry(resource_id.to_string()).or_default();
for t in new_tags {
if let Some(existing) = entry.iter_mut().find(|e| e.key == t.key) {
existing.value = t.value.clone();
} else {
entry.push(t.clone());
}
}
}
pub fn remove_tags(&mut self, resource_id: &str, to_remove: &[(String, Option<String>)]) {
if let Some(entry) = self.tags.get_mut(resource_id) {
for (key, value) in to_remove {
entry.retain(|e| {
if &e.key != key {
return true;
}
match value {
Some(v) => &e.value != v,
None => false,
}
});
}
if entry.is_empty() {
self.tags.remove(resource_id);
}
}
}
pub fn tags_for(&self, resource_id: &str) -> &[Tag] {
self.tags.get(resource_id).map(Vec::as_slice).unwrap_or(&[])
}
}
#[cfg(test)]
mod tests {
use super::*;
fn tag(k: &str, v: &str) -> Tag {
Tag {
key: k.to_string(),
value: v.to_string(),
}
}
#[test]
fn upsert_tags_inserts_then_overwrites_by_key() {
let mut s = Ec2State::new("123456789012", "us-east-1");
s.upsert_tags("vpc-1", &[tag("Name", "a"), tag("env", "dev")]);
s.upsert_tags("vpc-1", &[tag("Name", "b")]);
let tags = s.tags_for("vpc-1");
assert_eq!(tags.len(), 2);
assert_eq!(tags.iter().find(|t| t.key == "Name").unwrap().value, "b");
}
#[test]
fn remove_tags_by_key_and_by_key_value() {
let mut s = Ec2State::new("123456789012", "us-east-1");
s.upsert_tags(
"i-1",
&[tag("Name", "x"), tag("env", "prod"), tag("team", "a")],
);
s.remove_tags("i-1", &[("Name".to_string(), None)]);
s.remove_tags("i-1", &[("env".to_string(), Some("dev".to_string()))]);
s.remove_tags("i-1", &[("team".to_string(), Some("a".to_string()))]);
let tags = s.tags_for("i-1");
assert_eq!(tags.len(), 1);
assert_eq!(tags[0].key, "env");
}
#[test]
fn empty_tag_set_drops_resource_entry() {
let mut s = Ec2State::new("123456789012", "us-east-1");
s.upsert_tags("sg-1", &[tag("Name", "x")]);
s.remove_tags("sg-1", &[("Name".to_string(), None)]);
assert!(!s.tags.contains_key("sg-1"));
}
fn sample_instance() -> Instance {
Instance {
instance_id: "i-1".to_string(),
image_id: "ami-1".to_string(),
instance_type: "t3.micro".to_string(),
state_code: 16,
state_name: "running".to_string(),
private_ip: "10.0.0.1".to_string(),
public_ip: Some("52.0.0.1".to_string()),
subnet_id: Some("subnet-1".to_string()),
vpc_id: Some("vpc-1".to_string()),
key_name: None,
security_group_ids: vec!["sg-1".to_string()],
reservation_id: "r-1".to_string(),
ami_launch_index: 0,
monitoring: false,
az: "us-east-1a".to_string(),
launch_time: "2024-01-01T00:00:00.000Z".to_string(),
container_id: Some("abc".to_string()),
disable_api_termination: true,
disable_api_stop: true,
source_dest_check: false,
ebs_optimized: true,
instance_initiated_shutdown_behavior: "terminate".to_string(),
user_data: Some("ZWNobyBoaQ==".to_string()),
metadata_options: MetadataOptions {
http_tokens: "required".to_string(),
..MetadataOptions::default()
},
cpu_options: Some(CpuOptions {
core_count: 4,
threads_per_core: 2,
}),
bandwidth_weighting: Some("vpc-1".to_string()),
maintenance_options: MaintenanceOptions::default(),
placement_tenancy: Some("dedicated".to_string()),
placement_affinity: None,
placement_group_name: Some("cluster-1".to_string()),
}
}
#[test]
fn instance_attributes_round_trip_through_serde() {
let inst = sample_instance();
let json = serde_json::to_string(&inst).unwrap();
let back: Instance = serde_json::from_str(&json).unwrap();
assert!(back.disable_api_termination);
assert!(back.disable_api_stop);
assert!(!back.source_dest_check);
assert!(back.ebs_optimized);
assert_eq!(back.instance_initiated_shutdown_behavior, "terminate");
assert_eq!(back.user_data.as_deref(), Some("ZWNobyBoaQ=="));
assert_eq!(back.metadata_options.http_tokens, "required");
assert_eq!(back.cpu_options.as_ref().unwrap().core_count, 4);
assert_eq!(back.bandwidth_weighting.as_deref(), Some("vpc-1"));
assert_eq!(back.placement_tenancy.as_deref(), Some("dedicated"));
assert_eq!(back.placement_group_name.as_deref(), Some("cluster-1"));
}
#[test]
fn instance_attribute_defaults_load_from_legacy_snapshot() {
let legacy = r#"{
"instance_id":"i-1","image_id":"ami-1","instance_type":"t3.micro",
"state_code":16,"state_name":"running","private_ip":"10.0.0.1",
"public_ip":null,"subnet_id":null,"vpc_id":null,"key_name":null,
"reservation_id":"r-1","ami_launch_index":0,"monitoring":false,
"az":"us-east-1a","launch_time":"2024-01-01T00:00:00.000Z"
}"#;
let inst: Instance = serde_json::from_str(legacy).unwrap();
assert!(!inst.disable_api_termination);
assert!(inst.source_dest_check, "sourceDestCheck defaults to true");
assert_eq!(inst.instance_initiated_shutdown_behavior, "stop");
assert_eq!(inst.metadata_options.http_tokens, "optional");
assert!(inst.cpu_options.is_none());
}
}