1use std::collections::BTreeMap;
9use std::sync::Arc;
10
11use parking_lot::RwLock;
12use serde::{Deserialize, Serialize};
13
14pub type SharedEc2State = Arc<RwLock<fakecloud_core::multi_account::MultiAccountState<Ec2State>>>;
16
17#[derive(Debug, Clone, Serialize, Deserialize)]
22pub struct Ec2Snapshot {
23 pub schema_version: u32,
24 #[serde(default)]
25 pub accounts: Option<fakecloud_core::multi_account::MultiAccountState<Ec2State>>,
26}
27
28pub const EC2_SNAPSHOT_SCHEMA_VERSION: u32 = 1;
29
30impl fakecloud_core::multi_account::AccountState for Ec2State {
31 fn new_for_account(account_id: &str, region: &str, _endpoint: &str) -> Self {
32 Self::new(account_id, region)
33 }
34}
35
36#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
38pub struct Tag {
39 pub key: String,
40 pub value: String,
41}
42
43#[derive(Clone, Debug, Serialize, Deserialize)]
45pub struct VpcCidrAssoc {
46 pub association_id: String,
47 pub cidr_block: String,
48 pub state: String,
50}
51
52#[derive(Clone, Debug, Serialize, Deserialize)]
54pub struct Vpc {
55 pub vpc_id: String,
56 pub cidr_block: String,
57 pub state: String,
59 pub dhcp_options_id: String,
60 pub instance_tenancy: String,
62 pub is_default: bool,
63 pub enable_dns_support: bool,
64 pub enable_dns_hostnames: bool,
65 #[serde(default)]
66 pub cidr_associations: Vec<VpcCidrAssoc>,
67 #[serde(default)]
72 pub ipv6_cidr_block: Option<String>,
73}
74
75#[derive(Clone, Debug, Serialize, Deserialize)]
77pub struct DhcpConfig {
78 pub key: String,
79 pub values: Vec<String>,
80}
81
82#[derive(Clone, Debug, Serialize, Deserialize)]
84pub struct DhcpOptions {
85 pub dhcp_options_id: String,
86 pub configurations: Vec<DhcpConfig>,
87}
88
89#[derive(Clone, Debug, Serialize, Deserialize)]
91pub struct Subnet {
92 pub subnet_id: String,
93 pub vpc_id: String,
94 pub cidr_block: String,
95 pub availability_zone: String,
96 pub availability_zone_id: String,
97 pub state: String,
99 pub available_ip_address_count: i32,
100 pub default_for_az: bool,
101 pub map_public_ip_on_launch: bool,
102 pub assign_ipv6_address_on_creation: bool,
103 pub map_customer_owned_ip_on_launch: bool,
104 pub enable_dns64: bool,
105 pub private_dns_hostname_type: String,
107 #[serde(default)]
111 pub ipv6_cidr_block: Option<String>,
112}
113
114#[derive(Clone, Debug, Serialize, Deserialize)]
116pub struct SubnetCidrReservation {
117 pub subnet_cidr_reservation_id: String,
118 pub subnet_id: String,
119 pub cidr: String,
120 pub reservation_type: String,
122 pub description: String,
123}
124
125#[derive(Clone, Debug, Serialize, Deserialize)]
127pub struct SecurityGroupRule {
128 pub rule_id: String,
129 pub group_id: String,
130 pub is_egress: bool,
131 pub ip_protocol: String,
132 pub from_port: i64,
133 pub to_port: i64,
134 pub cidr_ipv4: Option<String>,
135 pub cidr_ipv6: Option<String>,
136 pub prefix_list_id: Option<String>,
137 pub referenced_group_id: Option<String>,
138 pub description: String,
139}
140
141#[derive(Clone, Debug, Serialize, Deserialize)]
143pub struct SecurityGroup {
144 pub group_id: String,
145 pub group_name: String,
146 pub description: String,
147 pub vpc_id: String,
148 #[serde(default)]
149 pub rules: Vec<SecurityGroupRule>,
150}
151
152#[derive(Clone, Debug, Default, Serialize, Deserialize)]
154pub struct Route {
155 pub destination_cidr_block: Option<String>,
156 pub destination_ipv6_cidr_block: Option<String>,
157 pub destination_prefix_list_id: Option<String>,
158 pub gateway_id: Option<String>,
159 pub nat_gateway_id: Option<String>,
160 pub network_interface_id: Option<String>,
161 pub instance_id: Option<String>,
162 pub vpc_peering_connection_id: Option<String>,
163 pub transit_gateway_id: Option<String>,
164 pub egress_only_internet_gateway_id: Option<String>,
165 pub state: String,
167 pub origin: String,
169}
170
171#[derive(Clone, Debug, Serialize, Deserialize)]
173pub struct RouteTableAssociation {
174 pub association_id: String,
175 pub route_table_id: String,
176 pub subnet_id: Option<String>,
177 pub gateway_id: Option<String>,
178 pub main: bool,
179}
180
181#[derive(Clone, Debug, Serialize, Deserialize)]
183pub struct RouteTable {
184 pub route_table_id: String,
185 pub vpc_id: String,
186 #[serde(default)]
187 pub routes: Vec<Route>,
188 #[serde(default)]
189 pub associations: Vec<RouteTableAssociation>,
190}
191
192#[derive(Clone, Debug, Serialize, Deserialize)]
194pub struct InternetGateway {
195 pub internet_gateway_id: String,
196 #[serde(default)]
198 pub attachments: Vec<(String, String)>,
199}
200
201#[derive(Clone, Debug, Serialize, Deserialize)]
203pub struct NatGateway {
204 pub nat_gateway_id: String,
205 pub subnet_id: String,
206 pub vpc_id: String,
207 pub state: String,
209 pub connectivity_type: String,
211 pub allocation_id: Option<String>,
212}
213
214#[derive(Clone, Debug, Serialize, Deserialize)]
216pub struct ElasticIp {
217 pub allocation_id: String,
218 pub public_ip: String,
219 pub domain: String,
221 pub association_id: Option<String>,
222 pub instance_id: Option<String>,
223 pub network_interface_id: Option<String>,
224 pub private_ip_address: Option<String>,
225}
226
227#[derive(Clone, Debug, Serialize, Deserialize)]
229pub struct KeyPair {
230 pub key_pair_id: String,
231 pub key_name: String,
232 pub key_type: String,
234 pub key_fingerprint: String,
235}
236
237#[derive(Clone, Debug, Serialize, Deserialize)]
239pub struct PlacementGroup {
240 pub group_id: String,
241 pub group_name: String,
242 pub strategy: String,
244 pub state: String,
246 pub partition_count: Option<i64>,
247 pub spread_level: Option<String>,
248}
249
250#[derive(Clone, Debug, Serialize, Deserialize)]
252pub struct EniAttachment {
253 pub attachment_id: String,
254 pub instance_id: String,
255 pub device_index: i64,
256 pub status: String,
258}
259
260#[derive(Clone, Debug, Serialize, Deserialize)]
262pub struct NetworkInterface {
263 pub network_interface_id: String,
264 pub subnet_id: String,
265 pub vpc_id: String,
266 pub availability_zone: String,
267 pub description: String,
268 pub mac_address: String,
269 pub private_ip_address: String,
270 pub status: String,
272 pub interface_type: String,
273 pub source_dest_check: bool,
274 #[serde(default)]
275 pub group_ids: Vec<String>,
276 #[serde(default)]
277 pub private_ips: Vec<String>,
278 #[serde(default)]
279 pub ipv6_addresses: Vec<String>,
280 pub attachment: Option<EniAttachment>,
281}
282
283#[derive(Clone, Debug, Serialize, Deserialize)]
285pub struct NetworkInterfacePermission {
286 pub permission_id: String,
287 pub network_interface_id: String,
288 pub aws_account_id: String,
289 pub permission: String,
291}
292
293#[derive(Clone, Debug, Serialize, Deserialize)]
295pub struct Instance {
296 pub instance_id: String,
297 pub image_id: String,
298 pub instance_type: String,
299 pub state_code: i64,
302 pub state_name: String,
303 pub private_ip: String,
304 pub public_ip: Option<String>,
305 pub subnet_id: Option<String>,
306 pub vpc_id: Option<String>,
307 pub key_name: Option<String>,
308 #[serde(default)]
309 pub security_group_ids: Vec<String>,
310 pub reservation_id: String,
311 pub ami_launch_index: i64,
312 pub monitoring: bool,
313 pub az: String,
314 pub launch_time: String,
315 #[serde(default)]
318 pub container_id: Option<String>,
319 #[serde(default)]
322 pub disable_api_termination: bool,
323 #[serde(default)]
325 pub disable_api_stop: bool,
326 #[serde(default = "default_true")]
328 pub source_dest_check: bool,
329 #[serde(default)]
331 pub ebs_optimized: bool,
332 #[serde(default = "default_shutdown_behavior")]
334 pub instance_initiated_shutdown_behavior: String,
335 #[serde(default)]
337 pub user_data: Option<String>,
338 #[serde(default)]
341 pub metadata_options: MetadataOptions,
342 #[serde(default)]
344 pub cpu_options: Option<CpuOptions>,
345 #[serde(default)]
347 pub bandwidth_weighting: Option<String>,
348 #[serde(default)]
350 pub maintenance_options: MaintenanceOptions,
351 #[serde(default)]
353 pub placement_tenancy: Option<String>,
354 #[serde(default)]
355 pub placement_affinity: Option<String>,
356 #[serde(default)]
357 pub placement_group_name: Option<String>,
358}
359
360fn default_true() -> bool {
361 true
362}
363
364fn default_shutdown_behavior() -> String {
365 "stop".to_string()
366}
367
368#[derive(Clone, Debug, Serialize, Deserialize)]
371pub struct MetadataOptions {
372 pub http_tokens: String,
374 pub http_endpoint: String,
376 pub http_put_response_hop_limit: i64,
377 pub http_protocol_ipv6: String,
379 pub instance_metadata_tags: String,
381}
382
383impl Default for MetadataOptions {
384 fn default() -> Self {
385 Self {
386 http_tokens: "optional".to_string(),
387 http_endpoint: "enabled".to_string(),
388 http_put_response_hop_limit: 1,
389 http_protocol_ipv6: "disabled".to_string(),
390 instance_metadata_tags: "disabled".to_string(),
391 }
392 }
393}
394
395#[derive(Clone, Debug, Serialize, Deserialize)]
397pub struct CpuOptions {
398 pub core_count: i64,
399 pub threads_per_core: i64,
400}
401
402#[derive(Clone, Debug, Serialize, Deserialize)]
404pub struct MaintenanceOptions {
405 pub auto_recovery: String,
407 pub reboot_migration: String,
409}
410
411impl Default for MaintenanceOptions {
412 fn default() -> Self {
413 Self {
414 auto_recovery: "default".to_string(),
415 reboot_migration: "default".to_string(),
416 }
417 }
418}
419
420#[derive(Clone, Debug, Serialize, Deserialize)]
422pub struct VolumeAttachment {
423 pub volume_id: String,
424 pub instance_id: String,
425 pub device: String,
426 pub status: String,
428 pub delete_on_termination: bool,
429}
430
431#[derive(Clone, Debug, Serialize, Deserialize)]
433pub struct Volume {
434 pub volume_id: String,
435 pub size: i64,
436 pub snapshot_id: Option<String>,
437 pub availability_zone: String,
438 pub state: String,
440 pub volume_type: String,
441 pub iops: Option<i64>,
442 pub throughput: Option<i64>,
443 pub encrypted: bool,
444 pub kms_key_id: Option<String>,
445 pub multi_attach_enabled: bool,
446 pub auto_enable_io: bool,
447 #[serde(default)]
448 pub attachments: Vec<VolumeAttachment>,
449 #[serde(default)]
450 pub in_recycle_bin: bool,
451}
452
453#[derive(Clone, Debug, Serialize, Deserialize)]
455pub struct Snapshot {
456 pub snapshot_id: String,
457 pub volume_id: String,
458 pub state: String,
460 pub volume_size: i64,
461 pub description: String,
462 pub encrypted: bool,
463 pub storage_tier: String,
465 #[serde(default)]
466 pub in_recycle_bin: bool,
467 #[serde(default)]
468 pub locked: bool,
469 pub lock_mode: Option<String>,
470}
471
472#[derive(Clone, Debug, Serialize, Deserialize)]
474pub struct Image {
475 pub image_id: String,
476 pub name: String,
477 pub description: String,
478 pub state: String,
480 pub architecture: String,
481 pub public: bool,
482 pub source_instance_id: Option<String>,
483 #[serde(default)]
484 pub in_recycle_bin: bool,
485 pub deprecation_time: Option<String>,
486 #[serde(default)]
487 pub deregistration_protection: bool,
488 #[serde(default)]
491 pub launch_permission_users: Vec<String>,
492 #[serde(default)]
494 pub launch_permission_groups: Vec<String>,
495 #[serde(default)]
498 pub boot_mode: Option<String>,
499 #[serde(default)]
504 pub owner_id: Option<String>,
505 #[serde(default)]
509 pub owner_alias: Option<String>,
510 #[serde(default)]
514 pub creation_date: Option<String>,
515 #[serde(default)]
518 pub root_device_name: Option<String>,
519 #[serde(default)]
521 pub platform: Option<String>,
522}
523
524#[derive(Clone, Debug, Serialize, Deserialize)]
526pub struct NetworkAclEntry {
527 pub rule_number: i64,
528 pub protocol: String,
529 pub rule_action: String,
531 pub egress: bool,
532 pub cidr_block: Option<String>,
533 pub ipv6_cidr_block: Option<String>,
534 pub port_range: Option<(i64, i64)>,
536 pub icmp_type_code: Option<(i64, i64)>,
538}
539
540#[derive(Clone, Debug, Serialize, Deserialize)]
542pub struct NetworkAclAssoc {
543 pub association_id: String,
544 pub subnet_id: String,
545}
546
547#[derive(Clone, Debug, Serialize, Deserialize)]
549pub struct NetworkAcl {
550 pub network_acl_id: String,
551 pub vpc_id: String,
552 pub is_default: bool,
553 #[serde(default)]
554 pub entries: Vec<NetworkAclEntry>,
555 #[serde(default)]
556 pub associations: Vec<NetworkAclAssoc>,
557}
558
559#[derive(Clone, Debug, Serialize, Deserialize)]
561pub struct VpcPeering {
562 pub id: String,
563 pub requester_vpc_id: String,
564 pub accepter_vpc_id: String,
565 pub status: String,
567 #[serde(default)]
569 pub requester_allow_dns: bool,
570 #[serde(default)]
572 pub accepter_allow_dns: bool,
573}
574
575#[derive(Clone, Debug, Serialize, Deserialize)]
577pub struct VpcEndpoint {
578 pub id: String,
579 pub endpoint_type: String,
581 pub vpc_id: String,
582 pub service_name: String,
583 pub state: String,
584 #[serde(default)]
585 pub subnet_ids: Vec<String>,
586 #[serde(default)]
587 pub route_table_ids: Vec<String>,
588 #[serde(default)]
589 pub private_dns_enabled: bool,
590}
591
592#[derive(Clone, Debug, Serialize, Deserialize)]
594pub struct EndpointService {
595 pub service_id: String,
596 pub service_name: String,
597 pub state: String,
598 pub acceptance_required: bool,
599 pub payer_responsibility: String,
600 #[serde(default)]
601 pub nlb_arns: Vec<String>,
602}
603
604#[derive(Clone, Debug, Serialize, Deserialize)]
606pub struct ConnectionNotification {
607 pub id: String,
608 pub arn: String,
609 pub service_id: Option<String>,
610 #[serde(default)]
611 pub events: Vec<String>,
612}
613
614#[derive(Clone, Debug, Serialize, Deserialize)]
616pub struct FlowLog {
617 pub id: String,
618 pub resource_id: String,
619 pub traffic_type: String,
620 pub log_destination_type: String,
621 pub log_group_name: Option<String>,
622 pub log_destination: Option<String>,
624 #[serde(default)]
627 pub deliver_logs_permission_arn: Option<String>,
628 #[serde(default = "default_max_aggregation_interval")]
631 pub max_aggregation_interval: i64,
632}
633
634fn default_max_aggregation_interval() -> i64 {
635 600
636}
637
638#[derive(Clone, Debug, Serialize, Deserialize)]
640pub struct LaunchTemplate {
641 pub id: String,
642 pub name: String,
643 pub default_version: i64,
644 pub latest_version: i64,
645}
646
647#[derive(Clone, Debug, Serialize, Deserialize)]
649pub struct SpotRequest {
650 pub id: String,
651 pub state: String,
653 pub request_type: String,
654 pub spot_price: String,
655}
656
657#[derive(Clone, Debug, Serialize, Deserialize)]
659pub struct SpotFleet {
660 pub id: String,
661 pub state: String,
662}
663
664#[derive(Clone, Debug, Serialize, Deserialize)]
666pub struct Fleet {
667 pub id: String,
668 pub state: String,
669 pub fleet_type: String,
670}
671
672#[derive(Clone, Debug, Serialize, Deserialize)]
674pub struct CapacityReservation {
675 pub id: String,
676 pub instance_type: String,
677 pub instance_platform: String,
678 pub availability_zone: String,
679 pub tenancy: String,
680 pub total_instance_count: i64,
681 pub available_instance_count: i64,
682 pub state: String,
684 pub end_date_type: String,
685 pub instance_match_criteria: String,
686}
687
688#[derive(Clone, Debug, Serialize, Deserialize)]
690pub struct ReservedInstances {
691 pub id: String,
692 pub instance_type: String,
693 pub availability_zone: String,
694 pub instance_count: i64,
695 pub product_description: String,
696 pub state: String,
697 pub duration: i64,
698 pub fixed_price: String,
699 pub usage_price: String,
700}
701
702#[derive(Clone, Debug, Serialize, Deserialize)]
704pub struct ReservedInstancesListing {
705 pub listing_id: String,
706 pub reserved_instances_id: String,
707 pub instance_count: i64,
708 pub client_token: String,
709 pub status: String,
711 pub status_message: String,
712}
713
714#[derive(Clone, Debug, Serialize, Deserialize)]
716pub struct ReservedInstancesModification {
717 pub modification_id: String,
718 pub reserved_instances_ids: Vec<String>,
719 pub status: String,
721 pub client_token: String,
722}
723
724#[derive(Clone, Debug, Serialize, Deserialize)]
726pub struct DedicatedHost {
727 pub id: String,
728 pub auto_placement: String,
729 pub availability_zone: String,
730 pub instance_type: String,
731 pub state: String,
732 pub host_recovery: String,
733 pub host_maintenance: String,
734}
735
736#[derive(Clone, Debug, Serialize, Deserialize)]
738pub struct TransitGateway {
739 pub id: String,
740 pub description: String,
741 #[serde(default = "tgw_default_state")]
743 pub state: String,
744}
745
746fn tgw_default_state() -> String {
747 "available".to_string()
748}
749
750#[derive(Clone, Debug, Serialize, Deserialize)]
752pub struct TgwAttachment {
753 pub id: String,
754 pub tgw_id: String,
755 pub resource_id: String,
756 pub resource_type: String,
757 #[serde(default)]
758 pub subnet_ids: Vec<String>,
759 pub state: String,
760}
761
762#[derive(Clone, Debug, Serialize, Deserialize)]
764pub struct TgwRouteTable {
765 pub id: String,
766 pub tgw_id: String,
767}
768
769#[derive(Clone, Debug, Serialize, Deserialize)]
771pub struct TgwRoute {
772 pub cidr: String,
773 pub attachment_id: String,
774 pub state: String,
775}
776
777#[derive(Clone, Debug, Serialize, Deserialize)]
779pub struct TgwMulticastDomain {
780 pub id: String,
781 pub tgw_id: String,
782}
783
784#[derive(Clone, Debug, Serialize, Deserialize)]
786pub struct TgwMeteringPolicy {
787 pub id: String,
788 pub tgw_id: String,
789}
790
791#[derive(Clone, Debug, Serialize, Deserialize)]
793pub struct CustomerGateway {
794 pub id: String,
795 pub state: String,
796 pub ip_address: String,
797 pub bgp_asn: String,
798}
799
800#[derive(Clone, Debug, Serialize, Deserialize)]
802pub struct VpnGateway {
803 pub id: String,
804 pub state: String,
805 #[serde(default)]
806 pub attachments: Vec<String>,
807}
808
809#[derive(Clone, Debug, Serialize, Deserialize)]
811pub struct VpnConnection {
812 pub id: String,
813 pub state: String,
814 pub customer_gateway_id: String,
815 pub vpn_gateway_id: Option<String>,
816 #[serde(default)]
817 pub routes: Vec<String>,
818}
819
820#[derive(Clone, Debug, Serialize, Deserialize)]
822pub struct VpnConcentrator {
823 pub id: String,
824 pub state: String,
825}
826
827#[derive(Clone, Debug, Serialize, Deserialize)]
829pub struct Ipam {
830 pub id: String,
831 pub public_scope_id: String,
832 pub private_scope_id: String,
833 pub tier: String,
834 #[serde(default)]
835 pub description: String,
836}
837
838#[derive(Clone, Debug, Serialize, Deserialize)]
840pub struct IpamScope {
841 pub id: String,
842 pub ipam_id: String,
843 #[serde(default)]
845 pub scope_type: String,
846 #[serde(default)]
847 pub description: String,
848}
849
850#[derive(Clone, Debug, Serialize, Deserialize)]
852pub struct IpamPool {
853 pub id: String,
854 pub scope_id: String,
855 pub address_family: String,
856 #[serde(default)]
857 pub description: String,
858}
859
860#[derive(Clone, Debug, Serialize, Deserialize)]
862pub struct IpamResourceDiscovery {
863 pub id: String,
864 #[serde(default)]
865 pub description: String,
866}
867
868#[derive(Clone, Debug, Serialize, Deserialize)]
870pub struct IpamPolicy {
871 pub id: String,
872 pub ipam_id: String,
873}
874
875#[derive(Clone, Debug, Serialize, Deserialize)]
877pub struct IpamPrefixListResolver {
878 pub id: String,
879 pub ipam_id: String,
880 pub address_family: String,
881 #[serde(default)]
882 pub description: String,
883}
884
885#[derive(Clone, Debug, Serialize, Deserialize)]
887pub struct IpamPrefixListResolverTarget {
888 pub id: String,
889 pub resolver_id: String,
890 pub prefix_list_id: String,
891 pub prefix_list_region: String,
892 #[serde(default)]
893 pub track_latest_version: bool,
894}
895
896#[derive(Clone, Debug, Serialize, Deserialize)]
898pub struct VerifiedAccessInstance {
899 pub id: String,
900 pub description: String,
901 #[serde(default)]
902 pub trust_providers: Vec<String>,
903}
904
905#[derive(Clone, Debug, Serialize, Deserialize)]
907pub struct VerifiedAccessTrustProvider {
908 pub id: String,
909 pub trust_provider_type: String,
910 pub policy_reference_name: String,
911 pub description: String,
912}
913
914#[derive(Clone, Debug, Serialize, Deserialize)]
916pub struct VerifiedAccessGroup {
917 pub id: String,
918 pub instance_id: String,
919 pub description: String,
920}
921
922#[derive(Clone, Debug, Serialize, Deserialize)]
924pub struct VerifiedAccessEndpoint {
925 pub id: String,
926 pub group_id: String,
927 pub instance_id: String,
928 pub endpoint_type: String,
929 pub attachment_type: String,
930}
931
932#[derive(Clone, Debug, Serialize, Deserialize)]
934pub struct NetworkInsightsPath {
935 pub id: String,
936 pub source: String,
937 pub destination: String,
938 pub protocol: String,
939}
940
941#[derive(Clone, Debug, Serialize, Deserialize)]
943pub struct NetworkInsightsAnalysis {
944 pub id: String,
945 pub path_id: String,
946}
947
948#[derive(Clone, Debug, Serialize, Deserialize)]
950pub struct NetworkInsightsAccessScope {
951 pub id: String,
952}
953
954#[derive(Clone, Debug, Serialize, Deserialize)]
956pub struct NetworkInsightsAccessScopeAnalysis {
957 pub id: String,
958 pub scope_id: String,
959}
960
961#[derive(Clone, Debug, Serialize, Deserialize)]
963pub struct CarrierGateway {
964 pub id: String,
965 pub vpc_id: String,
966}
967
968#[derive(Clone, Debug, Serialize, Deserialize)]
970pub struct InstanceConnectEndpoint {
971 pub id: String,
972 pub subnet_id: String,
973}
974
975#[derive(Clone, Debug, Serialize, Deserialize)]
977pub struct CoipPool {
978 pub id: String,
979 pub route_table_id: String,
980}
981
982#[derive(Clone, Debug, Serialize, Deserialize)]
984pub struct LocalGatewayRouteTable {
985 pub id: String,
986 pub local_gateway_id: String,
987 pub mode: String,
988}
989
990#[derive(Clone, Debug, Serialize, Deserialize)]
992pub struct LocalGatewayRouteTableVpcAssoc {
993 pub id: String,
994 pub route_table_id: String,
995 pub vpc_id: String,
996}
997
998#[derive(Clone, Debug, Serialize, Deserialize)]
1000pub struct LocalGatewayVif {
1001 pub id: String,
1002 pub group_id: String,
1003 pub vlan: String,
1004 pub local_address: String,
1005 pub peer_address: String,
1006}
1007
1008#[derive(Clone, Debug, Serialize, Deserialize)]
1010pub struct LocalGatewayVifGroup {
1011 pub id: String,
1012 pub local_gateway_id: String,
1013}
1014
1015#[derive(Clone, Debug, Serialize, Deserialize)]
1017pub struct LocalGatewayRouteTableVifgAssoc {
1018 pub id: String,
1019 pub route_table_id: String,
1020 pub vif_group_id: String,
1021}
1022
1023#[derive(Clone, Debug, Serialize, Deserialize)]
1025pub struct ClientVpnEndpoint {
1026 pub id: String,
1027 pub description: String,
1028 pub status: String,
1029 pub server_cert_arn: String,
1030 pub transport_protocol: String,
1031 pub client_cidr: String,
1032 #[serde(default)]
1033 pub routes: Vec<String>,
1034 #[serde(default)]
1036 pub target_networks: Vec<(String, String)>,
1037 #[serde(default)]
1039 pub auth_rules: Vec<String>,
1040}
1041
1042#[derive(Clone, Debug, Serialize, Deserialize)]
1044pub struct TgwPeering {
1045 pub id: String,
1046 pub tgw_id: String,
1047 pub peer_tgw_id: String,
1048 pub peer_account: String,
1049 pub peer_region: String,
1050 pub state: String,
1051}
1052
1053#[derive(Clone, Debug, Default, Serialize, Deserialize)]
1056pub struct Ec2State {
1057 pub account_id: String,
1058 pub region: String,
1059 #[serde(default)]
1061 pub tags: BTreeMap<String, Vec<Tag>>,
1062 #[serde(default)]
1063 pub vpcs: BTreeMap<String, Vpc>,
1064 #[serde(default)]
1065 pub dhcp_options: BTreeMap<String, DhcpOptions>,
1066 #[serde(default)]
1067 pub subnets: BTreeMap<String, Subnet>,
1068 #[serde(default)]
1069 pub subnet_cidr_reservations: BTreeMap<String, SubnetCidrReservation>,
1070 #[serde(default)]
1071 pub security_groups: BTreeMap<String, SecurityGroup>,
1072 #[serde(default)]
1073 pub route_tables: BTreeMap<String, RouteTable>,
1074 #[serde(default)]
1075 pub internet_gateways: BTreeMap<String, InternetGateway>,
1076 #[serde(default)]
1077 pub egress_only_igws: BTreeMap<String, InternetGateway>,
1078 #[serde(default)]
1079 pub nat_gateways: BTreeMap<String, NatGateway>,
1080 #[serde(default)]
1082 pub elastic_ips: BTreeMap<String, ElasticIp>,
1083 #[serde(default)]
1085 pub key_pairs: BTreeMap<String, KeyPair>,
1086 #[serde(default)]
1088 pub placement_groups: BTreeMap<String, PlacementGroup>,
1089 #[serde(default)]
1090 pub network_interfaces: BTreeMap<String, NetworkInterface>,
1091 #[serde(default)]
1093 pub eni_permissions: BTreeMap<String, NetworkInterfacePermission>,
1094 #[serde(default)]
1095 pub instances: BTreeMap<String, Instance>,
1096 #[serde(default)]
1097 pub volumes: BTreeMap<String, Volume>,
1098 #[serde(default)]
1100 pub ebs_encryption_default: bool,
1101 #[serde(default)]
1103 pub ebs_default_kms_key_id: Option<String>,
1104 #[serde(default)]
1105 pub snapshots: BTreeMap<String, Snapshot>,
1106 #[serde(default)]
1108 pub snapshot_block_public_access: String,
1109 #[serde(default)]
1110 pub images: BTreeMap<String, Image>,
1111 #[serde(default)]
1113 pub image_watermarks: BTreeMap<String, BTreeMap<String, String>>,
1114 #[serde(default)]
1116 pub image_block_public_access: String,
1117 #[serde(default)]
1119 pub allowed_images_settings: String,
1120 #[serde(default)]
1124 pub allowed_image_criteria: Vec<Vec<String>>,
1125 #[serde(default)]
1126 pub network_acls: BTreeMap<String, NetworkAcl>,
1127 #[serde(default)]
1128 pub vpc_peerings: BTreeMap<String, VpcPeering>,
1129 #[serde(default)]
1130 pub vpc_endpoints: BTreeMap<String, VpcEndpoint>,
1131 #[serde(default)]
1132 pub endpoint_services: BTreeMap<String, EndpointService>,
1133 #[serde(default)]
1134 pub connection_notifications: BTreeMap<String, ConnectionNotification>,
1135 #[serde(default)]
1136 pub flow_logs: BTreeMap<String, FlowLog>,
1137 #[serde(default)]
1138 pub launch_templates: BTreeMap<String, LaunchTemplate>,
1139 #[serde(default)]
1140 pub spot_requests: BTreeMap<String, SpotRequest>,
1141 #[serde(default)]
1142 pub spot_fleets: BTreeMap<String, SpotFleet>,
1143 #[serde(default)]
1144 pub fleets: BTreeMap<String, Fleet>,
1145 #[serde(default)]
1147 pub spot_datafeed: Option<(String, String)>,
1148 #[serde(default)]
1149 pub capacity_reservations: BTreeMap<String, CapacityReservation>,
1150 #[serde(default)]
1152 pub capacity_reservation_fleets: BTreeMap<String, String>,
1153 #[serde(default)]
1154 pub reserved_instances: BTreeMap<String, ReservedInstances>,
1155 #[serde(default)]
1156 pub reserved_instances_listings: BTreeMap<String, ReservedInstancesListing>,
1157 #[serde(default)]
1158 pub reserved_instances_modifications: BTreeMap<String, ReservedInstancesModification>,
1159 #[serde(default)]
1160 pub dedicated_hosts: BTreeMap<String, DedicatedHost>,
1161 #[serde(default)]
1162 pub transit_gateways: BTreeMap<String, TransitGateway>,
1163 #[serde(default)]
1164 pub tgw_attachments: BTreeMap<String, TgwAttachment>,
1165 #[serde(default)]
1166 pub tgw_route_tables: BTreeMap<String, TgwRouteTable>,
1167 #[serde(default)]
1169 pub tgw_routes: BTreeMap<String, Vec<TgwRoute>>,
1170 #[serde(default)]
1172 pub tgw_rt_associations: BTreeMap<String, Vec<String>>,
1173 #[serde(default)]
1175 pub tgw_rt_propagations: BTreeMap<String, Vec<String>>,
1176 #[serde(default)]
1178 pub tgw_prefix_list_refs: BTreeMap<String, Vec<String>>,
1179 #[serde(default)]
1180 pub tgw_peerings: BTreeMap<String, TgwPeering>,
1181 #[serde(default)]
1183 pub tgw_connects: BTreeMap<String, (String, String)>,
1184 #[serde(default)]
1186 pub tgw_connect_peers: BTreeMap<String, String>,
1187 #[serde(default)]
1189 pub tgw_policy_tables: BTreeMap<String, String>,
1190 #[serde(default)]
1192 pub tgw_policy_table_associations: BTreeMap<String, Vec<String>>,
1193 #[serde(default)]
1195 pub tgw_announcements: BTreeMap<String, (String, String)>,
1196 #[serde(default)]
1197 pub tgw_multicast_domains: BTreeMap<String, TgwMulticastDomain>,
1198 #[serde(default)]
1199 pub tgw_metering_policies: BTreeMap<String, TgwMeteringPolicy>,
1200 #[serde(default)]
1201 pub customer_gateways: BTreeMap<String, CustomerGateway>,
1202 #[serde(default)]
1203 pub vpn_gateways: BTreeMap<String, VpnGateway>,
1204 #[serde(default)]
1205 pub vpn_connections: BTreeMap<String, VpnConnection>,
1206 #[serde(default)]
1207 pub vpn_concentrators: BTreeMap<String, VpnConcentrator>,
1208 #[serde(default)]
1209 pub client_vpn_endpoints: BTreeMap<String, ClientVpnEndpoint>,
1210 #[serde(default)]
1211 pub ipams: BTreeMap<String, Ipam>,
1212 #[serde(default)]
1213 pub ipam_scopes: BTreeMap<String, IpamScope>,
1214 #[serde(default)]
1215 pub ipam_pools: BTreeMap<String, IpamPool>,
1216 #[serde(default)]
1218 pub ipam_pool_cidrs: BTreeMap<String, Vec<(String, String)>>,
1219 #[serde(default)]
1221 pub ipam_pool_allocations: BTreeMap<String, Vec<(String, String)>>,
1222 #[serde(default)]
1223 pub ipam_resource_discoveries: BTreeMap<String, IpamResourceDiscovery>,
1224 #[serde(default)]
1226 pub ipam_rd_associations: BTreeMap<String, (String, String)>,
1227 #[serde(default)]
1229 pub ipam_byoasns: BTreeMap<String, String>,
1230 #[serde(default)]
1232 pub ipam_ext_tokens: BTreeMap<String, String>,
1233 #[serde(default)]
1234 pub ipam_policies: BTreeMap<String, IpamPolicy>,
1235 #[serde(default)]
1236 pub ipam_pl_resolvers: BTreeMap<String, IpamPrefixListResolver>,
1237 #[serde(default)]
1238 pub ipam_pl_resolver_targets: BTreeMap<String, IpamPrefixListResolverTarget>,
1239 #[serde(default)]
1241 pub ipam_policy_alloc_rules: BTreeMap<String, Vec<(String, String)>>,
1242 #[serde(default)]
1244 pub ipam_enabled_policy: Option<String>,
1245 #[serde(default)]
1246 pub va_instances: BTreeMap<String, VerifiedAccessInstance>,
1247 #[serde(default)]
1248 pub va_trust_providers: BTreeMap<String, VerifiedAccessTrustProvider>,
1249 #[serde(default)]
1250 pub va_groups: BTreeMap<String, VerifiedAccessGroup>,
1251 #[serde(default)]
1252 pub va_endpoints: BTreeMap<String, VerifiedAccessEndpoint>,
1253 #[serde(default)]
1255 pub va_group_policies: BTreeMap<String, String>,
1256 #[serde(default)]
1258 pub va_endpoint_policies: BTreeMap<String, String>,
1259 #[serde(default)]
1260 pub ni_paths: BTreeMap<String, NetworkInsightsPath>,
1261 #[serde(default)]
1262 pub ni_analyses: BTreeMap<String, NetworkInsightsAnalysis>,
1263 #[serde(default)]
1264 pub ni_access_scopes: BTreeMap<String, NetworkInsightsAccessScope>,
1265 #[serde(default)]
1266 pub ni_scope_analyses: BTreeMap<String, NetworkInsightsAccessScopeAnalysis>,
1267 #[serde(default)]
1268 pub carrier_gateways: BTreeMap<String, CarrierGateway>,
1269 #[serde(default)]
1270 pub coip_pools: BTreeMap<String, CoipPool>,
1271 #[serde(default)]
1273 pub coip_pool_cidrs: BTreeMap<String, Vec<String>>,
1274 #[serde(default)]
1275 pub lg_route_tables: BTreeMap<String, LocalGatewayRouteTable>,
1276 #[serde(default)]
1278 pub lg_routes: BTreeMap<String, Vec<String>>,
1279 #[serde(default)]
1280 pub lg_rt_vpc_assocs: BTreeMap<String, LocalGatewayRouteTableVpcAssoc>,
1281 #[serde(default)]
1282 pub lg_virtual_interfaces: BTreeMap<String, LocalGatewayVif>,
1283 #[serde(default)]
1284 pub lg_vif_groups: BTreeMap<String, LocalGatewayVifGroup>,
1285 #[serde(default)]
1286 pub lg_rt_vifg_assocs: BTreeMap<String, LocalGatewayRouteTableVifgAssoc>,
1287 #[serde(default)]
1288 pub instance_connect_endpoints: BTreeMap<String, InstanceConnectEndpoint>,
1289 #[serde(default)]
1291 pub fast_launch_images: std::collections::HashSet<String>,
1292 #[serde(default)]
1293 pub serial_console_access: bool,
1294}
1295
1296impl Ec2State {
1297 pub fn new(account_id: &str, region: &str) -> Self {
1298 let mut state = Self {
1299 account_id: account_id.to_string(),
1300 region: region.to_string(),
1301 ..Default::default()
1302 };
1303 crate::defaults::bootstrap_default_network(&mut state);
1309 crate::defaults::seed_public_images(&mut state);
1313 state
1314 }
1315
1316 pub fn ensure_public_images_seeded(&mut self) {
1322 crate::defaults::seed_public_images(self);
1323 }
1324
1325 pub fn upsert_tags(&mut self, resource_id: &str, new_tags: &[Tag]) {
1328 let entry = self.tags.entry(resource_id.to_string()).or_default();
1329 for t in new_tags {
1330 if let Some(existing) = entry.iter_mut().find(|e| e.key == t.key) {
1331 existing.value = t.value.clone();
1332 } else {
1333 entry.push(t.clone());
1334 }
1335 }
1336 }
1337
1338 pub fn remove_tags(&mut self, resource_id: &str, to_remove: &[(String, Option<String>)]) {
1342 if let Some(entry) = self.tags.get_mut(resource_id) {
1343 for (key, value) in to_remove {
1344 entry.retain(|e| {
1345 if &e.key != key {
1346 return true;
1347 }
1348 match value {
1349 Some(v) => &e.value != v,
1350 None => false,
1351 }
1352 });
1353 }
1354 if entry.is_empty() {
1355 self.tags.remove(resource_id);
1356 }
1357 }
1358 }
1359
1360 pub fn tags_for(&self, resource_id: &str) -> &[Tag] {
1362 self.tags.get(resource_id).map(Vec::as_slice).unwrap_or(&[])
1363 }
1364}
1365
1366#[cfg(test)]
1367mod tests {
1368 use super::*;
1369
1370 fn tag(k: &str, v: &str) -> Tag {
1371 Tag {
1372 key: k.to_string(),
1373 value: v.to_string(),
1374 }
1375 }
1376
1377 #[test]
1378 fn upsert_tags_inserts_then_overwrites_by_key() {
1379 let mut s = Ec2State::new("123456789012", "us-east-1");
1380 s.upsert_tags("vpc-1", &[tag("Name", "a"), tag("env", "dev")]);
1381 s.upsert_tags("vpc-1", &[tag("Name", "b")]);
1382 let tags = s.tags_for("vpc-1");
1383 assert_eq!(tags.len(), 2);
1384 assert_eq!(tags.iter().find(|t| t.key == "Name").unwrap().value, "b");
1385 }
1386
1387 #[test]
1388 fn remove_tags_by_key_and_by_key_value() {
1389 let mut s = Ec2State::new("123456789012", "us-east-1");
1390 s.upsert_tags(
1391 "i-1",
1392 &[tag("Name", "x"), tag("env", "prod"), tag("team", "a")],
1393 );
1394 s.remove_tags("i-1", &[("Name".to_string(), None)]);
1396 s.remove_tags("i-1", &[("env".to_string(), Some("dev".to_string()))]);
1398 s.remove_tags("i-1", &[("team".to_string(), Some("a".to_string()))]);
1400 let tags = s.tags_for("i-1");
1401 assert_eq!(tags.len(), 1);
1402 assert_eq!(tags[0].key, "env");
1403 }
1404
1405 #[test]
1406 fn empty_tag_set_drops_resource_entry() {
1407 let mut s = Ec2State::new("123456789012", "us-east-1");
1408 s.upsert_tags("sg-1", &[tag("Name", "x")]);
1409 s.remove_tags("sg-1", &[("Name".to_string(), None)]);
1410 assert!(!s.tags.contains_key("sg-1"));
1411 }
1412
1413 fn sample_instance() -> Instance {
1414 Instance {
1415 instance_id: "i-1".to_string(),
1416 image_id: "ami-1".to_string(),
1417 instance_type: "t3.micro".to_string(),
1418 state_code: 16,
1419 state_name: "running".to_string(),
1420 private_ip: "10.0.0.1".to_string(),
1421 public_ip: Some("52.0.0.1".to_string()),
1422 subnet_id: Some("subnet-1".to_string()),
1423 vpc_id: Some("vpc-1".to_string()),
1424 key_name: None,
1425 security_group_ids: vec!["sg-1".to_string()],
1426 reservation_id: "r-1".to_string(),
1427 ami_launch_index: 0,
1428 monitoring: false,
1429 az: "us-east-1a".to_string(),
1430 launch_time: "2024-01-01T00:00:00.000Z".to_string(),
1431 container_id: Some("abc".to_string()),
1432 disable_api_termination: true,
1433 disable_api_stop: true,
1434 source_dest_check: false,
1435 ebs_optimized: true,
1436 instance_initiated_shutdown_behavior: "terminate".to_string(),
1437 user_data: Some("ZWNobyBoaQ==".to_string()),
1438 metadata_options: MetadataOptions {
1439 http_tokens: "required".to_string(),
1440 ..MetadataOptions::default()
1441 },
1442 cpu_options: Some(CpuOptions {
1443 core_count: 4,
1444 threads_per_core: 2,
1445 }),
1446 bandwidth_weighting: Some("vpc-1".to_string()),
1447 maintenance_options: MaintenanceOptions::default(),
1448 placement_tenancy: Some("dedicated".to_string()),
1449 placement_affinity: None,
1450 placement_group_name: Some("cluster-1".to_string()),
1451 }
1452 }
1453
1454 #[test]
1455 fn instance_attributes_round_trip_through_serde() {
1456 let inst = sample_instance();
1457 let json = serde_json::to_string(&inst).unwrap();
1458 let back: Instance = serde_json::from_str(&json).unwrap();
1459 assert!(back.disable_api_termination);
1460 assert!(back.disable_api_stop);
1461 assert!(!back.source_dest_check);
1462 assert!(back.ebs_optimized);
1463 assert_eq!(back.instance_initiated_shutdown_behavior, "terminate");
1464 assert_eq!(back.user_data.as_deref(), Some("ZWNobyBoaQ=="));
1465 assert_eq!(back.metadata_options.http_tokens, "required");
1466 assert_eq!(back.cpu_options.as_ref().unwrap().core_count, 4);
1467 assert_eq!(back.bandwidth_weighting.as_deref(), Some("vpc-1"));
1468 assert_eq!(back.placement_tenancy.as_deref(), Some("dedicated"));
1469 assert_eq!(back.placement_group_name.as_deref(), Some("cluster-1"));
1470 }
1471
1472 #[test]
1473 fn instance_attribute_defaults_load_from_legacy_snapshot() {
1474 let legacy = r#"{
1477 "instance_id":"i-1","image_id":"ami-1","instance_type":"t3.micro",
1478 "state_code":16,"state_name":"running","private_ip":"10.0.0.1",
1479 "public_ip":null,"subnet_id":null,"vpc_id":null,"key_name":null,
1480 "reservation_id":"r-1","ami_launch_index":0,"monitoring":false,
1481 "az":"us-east-1a","launch_time":"2024-01-01T00:00:00.000Z"
1482 }"#;
1483 let inst: Instance = serde_json::from_str(legacy).unwrap();
1484 assert!(!inst.disable_api_termination);
1485 assert!(inst.source_dest_check, "sourceDestCheck defaults to true");
1486 assert_eq!(inst.instance_initiated_shutdown_behavior, "stop");
1487 assert_eq!(inst.metadata_options.http_tokens, "optional");
1488 assert!(inst.cpu_options.is_none());
1489 }
1490}