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
17impl fakecloud_core::multi_account::AccountState for Ec2State {
18 fn new_for_account(account_id: &str, region: &str, _endpoint: &str) -> Self {
19 Self::new(account_id, region)
20 }
21}
22
23#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
25pub struct Tag {
26 pub key: String,
27 pub value: String,
28}
29
30#[derive(Clone, Debug, Serialize, Deserialize)]
32pub struct VpcCidrAssoc {
33 pub association_id: String,
34 pub cidr_block: String,
35 pub state: String,
37}
38
39#[derive(Clone, Debug, Serialize, Deserialize)]
41pub struct Vpc {
42 pub vpc_id: String,
43 pub cidr_block: String,
44 pub state: String,
46 pub dhcp_options_id: String,
47 pub instance_tenancy: String,
49 pub is_default: bool,
50 pub enable_dns_support: bool,
51 pub enable_dns_hostnames: bool,
52 #[serde(default)]
53 pub cidr_associations: Vec<VpcCidrAssoc>,
54}
55
56#[derive(Clone, Debug, Serialize, Deserialize)]
58pub struct DhcpConfig {
59 pub key: String,
60 pub values: Vec<String>,
61}
62
63#[derive(Clone, Debug, Serialize, Deserialize)]
65pub struct DhcpOptions {
66 pub dhcp_options_id: String,
67 pub configurations: Vec<DhcpConfig>,
68}
69
70#[derive(Clone, Debug, Serialize, Deserialize)]
72pub struct Subnet {
73 pub subnet_id: String,
74 pub vpc_id: String,
75 pub cidr_block: String,
76 pub availability_zone: String,
77 pub availability_zone_id: String,
78 pub state: String,
80 pub available_ip_address_count: i32,
81 pub default_for_az: bool,
82 pub map_public_ip_on_launch: bool,
83 pub assign_ipv6_address_on_creation: bool,
84 pub map_customer_owned_ip_on_launch: bool,
85 pub enable_dns64: bool,
86 pub private_dns_hostname_type: String,
88}
89
90#[derive(Clone, Debug, Serialize, Deserialize)]
92pub struct SubnetCidrReservation {
93 pub subnet_cidr_reservation_id: String,
94 pub subnet_id: String,
95 pub cidr: String,
96 pub reservation_type: String,
98 pub description: String,
99}
100
101#[derive(Clone, Debug, Serialize, Deserialize)]
103pub struct SecurityGroupRule {
104 pub rule_id: String,
105 pub group_id: String,
106 pub is_egress: bool,
107 pub ip_protocol: String,
108 pub from_port: i64,
109 pub to_port: i64,
110 pub cidr_ipv4: Option<String>,
111 pub cidr_ipv6: Option<String>,
112 pub prefix_list_id: Option<String>,
113 pub referenced_group_id: Option<String>,
114 pub description: String,
115}
116
117#[derive(Clone, Debug, Serialize, Deserialize)]
119pub struct SecurityGroup {
120 pub group_id: String,
121 pub group_name: String,
122 pub description: String,
123 pub vpc_id: String,
124 #[serde(default)]
125 pub rules: Vec<SecurityGroupRule>,
126}
127
128#[derive(Clone, Debug, Default, Serialize, Deserialize)]
130pub struct Route {
131 pub destination_cidr_block: Option<String>,
132 pub destination_ipv6_cidr_block: Option<String>,
133 pub destination_prefix_list_id: Option<String>,
134 pub gateway_id: Option<String>,
135 pub nat_gateway_id: Option<String>,
136 pub network_interface_id: Option<String>,
137 pub instance_id: Option<String>,
138 pub vpc_peering_connection_id: Option<String>,
139 pub transit_gateway_id: Option<String>,
140 pub egress_only_internet_gateway_id: Option<String>,
141 pub state: String,
143 pub origin: String,
145}
146
147#[derive(Clone, Debug, Serialize, Deserialize)]
149pub struct RouteTableAssociation {
150 pub association_id: String,
151 pub route_table_id: String,
152 pub subnet_id: Option<String>,
153 pub gateway_id: Option<String>,
154 pub main: bool,
155}
156
157#[derive(Clone, Debug, Serialize, Deserialize)]
159pub struct RouteTable {
160 pub route_table_id: String,
161 pub vpc_id: String,
162 #[serde(default)]
163 pub routes: Vec<Route>,
164 #[serde(default)]
165 pub associations: Vec<RouteTableAssociation>,
166}
167
168#[derive(Clone, Debug, Serialize, Deserialize)]
170pub struct InternetGateway {
171 pub internet_gateway_id: String,
172 #[serde(default)]
174 pub attachments: Vec<(String, String)>,
175}
176
177#[derive(Clone, Debug, Serialize, Deserialize)]
179pub struct NatGateway {
180 pub nat_gateway_id: String,
181 pub subnet_id: String,
182 pub vpc_id: String,
183 pub state: String,
185 pub connectivity_type: String,
187 pub allocation_id: Option<String>,
188}
189
190#[derive(Clone, Debug, Serialize, Deserialize)]
192pub struct ElasticIp {
193 pub allocation_id: String,
194 pub public_ip: String,
195 pub domain: String,
197 pub association_id: Option<String>,
198 pub instance_id: Option<String>,
199 pub network_interface_id: Option<String>,
200 pub private_ip_address: Option<String>,
201}
202
203#[derive(Clone, Debug, Serialize, Deserialize)]
205pub struct KeyPair {
206 pub key_pair_id: String,
207 pub key_name: String,
208 pub key_type: String,
210 pub key_fingerprint: String,
211}
212
213#[derive(Clone, Debug, Serialize, Deserialize)]
215pub struct PlacementGroup {
216 pub group_id: String,
217 pub group_name: String,
218 pub strategy: String,
220 pub state: String,
222 pub partition_count: Option<i64>,
223 pub spread_level: Option<String>,
224}
225
226#[derive(Clone, Debug, Serialize, Deserialize)]
228pub struct EniAttachment {
229 pub attachment_id: String,
230 pub instance_id: String,
231 pub device_index: i64,
232 pub status: String,
234}
235
236#[derive(Clone, Debug, Serialize, Deserialize)]
238pub struct NetworkInterface {
239 pub network_interface_id: String,
240 pub subnet_id: String,
241 pub vpc_id: String,
242 pub availability_zone: String,
243 pub description: String,
244 pub mac_address: String,
245 pub private_ip_address: String,
246 pub status: String,
248 pub interface_type: String,
249 pub source_dest_check: bool,
250 #[serde(default)]
251 pub group_ids: Vec<String>,
252 #[serde(default)]
253 pub private_ips: Vec<String>,
254 #[serde(default)]
255 pub ipv6_addresses: Vec<String>,
256 pub attachment: Option<EniAttachment>,
257}
258
259#[derive(Clone, Debug, Serialize, Deserialize)]
261pub struct NetworkInterfacePermission {
262 pub permission_id: String,
263 pub network_interface_id: String,
264 pub aws_account_id: String,
265 pub permission: String,
267}
268
269#[derive(Clone, Debug, Serialize, Deserialize)]
271pub struct Instance {
272 pub instance_id: String,
273 pub image_id: String,
274 pub instance_type: String,
275 pub state_code: i64,
278 pub state_name: String,
279 pub private_ip: String,
280 pub public_ip: Option<String>,
281 pub subnet_id: Option<String>,
282 pub vpc_id: Option<String>,
283 pub key_name: Option<String>,
284 #[serde(default)]
285 pub security_group_ids: Vec<String>,
286 pub reservation_id: String,
287 pub ami_launch_index: i64,
288 pub monitoring: bool,
289 pub az: String,
290 pub launch_time: String,
291 #[serde(default)]
294 pub container_id: Option<String>,
295 #[serde(default)]
298 pub disable_api_termination: bool,
299 #[serde(default)]
301 pub disable_api_stop: bool,
302 #[serde(default = "default_true")]
304 pub source_dest_check: bool,
305 #[serde(default)]
307 pub ebs_optimized: bool,
308 #[serde(default = "default_shutdown_behavior")]
310 pub instance_initiated_shutdown_behavior: String,
311 #[serde(default)]
313 pub user_data: Option<String>,
314 #[serde(default)]
317 pub metadata_options: MetadataOptions,
318 #[serde(default)]
320 pub cpu_options: Option<CpuOptions>,
321 #[serde(default)]
323 pub bandwidth_weighting: Option<String>,
324 #[serde(default)]
326 pub maintenance_options: MaintenanceOptions,
327 #[serde(default)]
329 pub placement_tenancy: Option<String>,
330 #[serde(default)]
331 pub placement_affinity: Option<String>,
332 #[serde(default)]
333 pub placement_group_name: Option<String>,
334}
335
336fn default_true() -> bool {
337 true
338}
339
340fn default_shutdown_behavior() -> String {
341 "stop".to_string()
342}
343
344#[derive(Clone, Debug, Serialize, Deserialize)]
347pub struct MetadataOptions {
348 pub http_tokens: String,
350 pub http_endpoint: String,
352 pub http_put_response_hop_limit: i64,
353 pub http_protocol_ipv6: String,
355 pub instance_metadata_tags: String,
357}
358
359impl Default for MetadataOptions {
360 fn default() -> Self {
361 Self {
362 http_tokens: "optional".to_string(),
363 http_endpoint: "enabled".to_string(),
364 http_put_response_hop_limit: 1,
365 http_protocol_ipv6: "disabled".to_string(),
366 instance_metadata_tags: "disabled".to_string(),
367 }
368 }
369}
370
371#[derive(Clone, Debug, Serialize, Deserialize)]
373pub struct CpuOptions {
374 pub core_count: i64,
375 pub threads_per_core: i64,
376}
377
378#[derive(Clone, Debug, Serialize, Deserialize)]
380pub struct MaintenanceOptions {
381 pub auto_recovery: String,
383 pub reboot_migration: String,
385}
386
387impl Default for MaintenanceOptions {
388 fn default() -> Self {
389 Self {
390 auto_recovery: "default".to_string(),
391 reboot_migration: "default".to_string(),
392 }
393 }
394}
395
396#[derive(Clone, Debug, Serialize, Deserialize)]
398pub struct VolumeAttachment {
399 pub volume_id: String,
400 pub instance_id: String,
401 pub device: String,
402 pub status: String,
404 pub delete_on_termination: bool,
405}
406
407#[derive(Clone, Debug, Serialize, Deserialize)]
409pub struct Volume {
410 pub volume_id: String,
411 pub size: i64,
412 pub snapshot_id: Option<String>,
413 pub availability_zone: String,
414 pub state: String,
416 pub volume_type: String,
417 pub iops: Option<i64>,
418 pub throughput: Option<i64>,
419 pub encrypted: bool,
420 pub kms_key_id: Option<String>,
421 pub multi_attach_enabled: bool,
422 pub auto_enable_io: bool,
423 #[serde(default)]
424 pub attachments: Vec<VolumeAttachment>,
425 #[serde(default)]
426 pub in_recycle_bin: bool,
427}
428
429#[derive(Clone, Debug, Serialize, Deserialize)]
431pub struct Snapshot {
432 pub snapshot_id: String,
433 pub volume_id: String,
434 pub state: String,
436 pub volume_size: i64,
437 pub description: String,
438 pub encrypted: bool,
439 pub storage_tier: String,
441 #[serde(default)]
442 pub in_recycle_bin: bool,
443 #[serde(default)]
444 pub locked: bool,
445 pub lock_mode: Option<String>,
446}
447
448#[derive(Clone, Debug, Serialize, Deserialize)]
450pub struct Image {
451 pub image_id: String,
452 pub name: String,
453 pub description: String,
454 pub state: String,
456 pub architecture: String,
457 pub public: bool,
458 pub source_instance_id: Option<String>,
459 #[serde(default)]
460 pub in_recycle_bin: bool,
461 pub deprecation_time: Option<String>,
462 #[serde(default)]
463 pub deregistration_protection: bool,
464 #[serde(default)]
467 pub launch_permission_users: Vec<String>,
468 #[serde(default)]
470 pub launch_permission_groups: Vec<String>,
471 #[serde(default)]
474 pub boot_mode: Option<String>,
475}
476
477#[derive(Clone, Debug, Serialize, Deserialize)]
479pub struct NetworkAclEntry {
480 pub rule_number: i64,
481 pub protocol: String,
482 pub rule_action: String,
484 pub egress: bool,
485 pub cidr_block: Option<String>,
486 pub ipv6_cidr_block: Option<String>,
487 pub port_range: Option<(i64, i64)>,
489 pub icmp_type_code: Option<(i64, i64)>,
491}
492
493#[derive(Clone, Debug, Serialize, Deserialize)]
495pub struct NetworkAclAssoc {
496 pub association_id: String,
497 pub subnet_id: String,
498}
499
500#[derive(Clone, Debug, Serialize, Deserialize)]
502pub struct NetworkAcl {
503 pub network_acl_id: String,
504 pub vpc_id: String,
505 pub is_default: bool,
506 #[serde(default)]
507 pub entries: Vec<NetworkAclEntry>,
508 #[serde(default)]
509 pub associations: Vec<NetworkAclAssoc>,
510}
511
512#[derive(Clone, Debug, Serialize, Deserialize)]
514pub struct VpcPeering {
515 pub id: String,
516 pub requester_vpc_id: String,
517 pub accepter_vpc_id: String,
518 pub status: String,
520 #[serde(default)]
522 pub requester_allow_dns: bool,
523 #[serde(default)]
525 pub accepter_allow_dns: bool,
526}
527
528#[derive(Clone, Debug, Serialize, Deserialize)]
530pub struct VpcEndpoint {
531 pub id: String,
532 pub endpoint_type: String,
534 pub vpc_id: String,
535 pub service_name: String,
536 pub state: String,
537 #[serde(default)]
538 pub subnet_ids: Vec<String>,
539 #[serde(default)]
540 pub route_table_ids: Vec<String>,
541 #[serde(default)]
542 pub private_dns_enabled: bool,
543}
544
545#[derive(Clone, Debug, Serialize, Deserialize)]
547pub struct EndpointService {
548 pub service_id: String,
549 pub service_name: String,
550 pub state: String,
551 pub acceptance_required: bool,
552 pub payer_responsibility: String,
553 #[serde(default)]
554 pub nlb_arns: Vec<String>,
555}
556
557#[derive(Clone, Debug, Serialize, Deserialize)]
559pub struct ConnectionNotification {
560 pub id: String,
561 pub arn: String,
562 pub service_id: Option<String>,
563 #[serde(default)]
564 pub events: Vec<String>,
565}
566
567#[derive(Clone, Debug, Serialize, Deserialize)]
569pub struct FlowLog {
570 pub id: String,
571 pub resource_id: String,
572 pub traffic_type: String,
573 pub log_destination_type: String,
574 pub log_group_name: Option<String>,
575 pub log_destination: Option<String>,
577}
578
579#[derive(Clone, Debug, Serialize, Deserialize)]
581pub struct LaunchTemplate {
582 pub id: String,
583 pub name: String,
584 pub default_version: i64,
585 pub latest_version: i64,
586}
587
588#[derive(Clone, Debug, Serialize, Deserialize)]
590pub struct SpotRequest {
591 pub id: String,
592 pub state: String,
594 pub request_type: String,
595 pub spot_price: String,
596}
597
598#[derive(Clone, Debug, Serialize, Deserialize)]
600pub struct SpotFleet {
601 pub id: String,
602 pub state: String,
603}
604
605#[derive(Clone, Debug, Serialize, Deserialize)]
607pub struct Fleet {
608 pub id: String,
609 pub state: String,
610 pub fleet_type: String,
611}
612
613#[derive(Clone, Debug, Serialize, Deserialize)]
615pub struct CapacityReservation {
616 pub id: String,
617 pub instance_type: String,
618 pub instance_platform: String,
619 pub availability_zone: String,
620 pub tenancy: String,
621 pub total_instance_count: i64,
622 pub available_instance_count: i64,
623 pub state: String,
625 pub end_date_type: String,
626 pub instance_match_criteria: String,
627}
628
629#[derive(Clone, Debug, Serialize, Deserialize)]
631pub struct ReservedInstances {
632 pub id: String,
633 pub instance_type: String,
634 pub availability_zone: String,
635 pub instance_count: i64,
636 pub product_description: String,
637 pub state: String,
638 pub duration: i64,
639 pub fixed_price: String,
640 pub usage_price: String,
641}
642
643#[derive(Clone, Debug, Serialize, Deserialize)]
645pub struct ReservedInstancesListing {
646 pub listing_id: String,
647 pub reserved_instances_id: String,
648 pub instance_count: i64,
649 pub client_token: String,
650 pub status: String,
652 pub status_message: String,
653}
654
655#[derive(Clone, Debug, Serialize, Deserialize)]
657pub struct ReservedInstancesModification {
658 pub modification_id: String,
659 pub reserved_instances_ids: Vec<String>,
660 pub status: String,
662 pub client_token: String,
663}
664
665#[derive(Clone, Debug, Serialize, Deserialize)]
667pub struct DedicatedHost {
668 pub id: String,
669 pub auto_placement: String,
670 pub availability_zone: String,
671 pub instance_type: String,
672 pub state: String,
673 pub host_recovery: String,
674 pub host_maintenance: String,
675}
676
677#[derive(Clone, Debug, Serialize, Deserialize)]
679pub struct TransitGateway {
680 pub id: String,
681 pub description: String,
682 #[serde(default = "tgw_default_state")]
684 pub state: String,
685}
686
687fn tgw_default_state() -> String {
688 "available".to_string()
689}
690
691#[derive(Clone, Debug, Serialize, Deserialize)]
693pub struct TgwAttachment {
694 pub id: String,
695 pub tgw_id: String,
696 pub resource_id: String,
697 pub resource_type: String,
698 #[serde(default)]
699 pub subnet_ids: Vec<String>,
700 pub state: String,
701}
702
703#[derive(Clone, Debug, Serialize, Deserialize)]
705pub struct TgwRouteTable {
706 pub id: String,
707 pub tgw_id: String,
708}
709
710#[derive(Clone, Debug, Serialize, Deserialize)]
712pub struct TgwRoute {
713 pub cidr: String,
714 pub attachment_id: String,
715 pub state: String,
716}
717
718#[derive(Clone, Debug, Serialize, Deserialize)]
720pub struct TgwMulticastDomain {
721 pub id: String,
722 pub tgw_id: String,
723}
724
725#[derive(Clone, Debug, Serialize, Deserialize)]
727pub struct TgwMeteringPolicy {
728 pub id: String,
729 pub tgw_id: String,
730}
731
732#[derive(Clone, Debug, Serialize, Deserialize)]
734pub struct CustomerGateway {
735 pub id: String,
736 pub state: String,
737 pub ip_address: String,
738 pub bgp_asn: String,
739}
740
741#[derive(Clone, Debug, Serialize, Deserialize)]
743pub struct VpnGateway {
744 pub id: String,
745 pub state: String,
746 #[serde(default)]
747 pub attachments: Vec<String>,
748}
749
750#[derive(Clone, Debug, Serialize, Deserialize)]
752pub struct VpnConnection {
753 pub id: String,
754 pub state: String,
755 pub customer_gateway_id: String,
756 pub vpn_gateway_id: Option<String>,
757 #[serde(default)]
758 pub routes: Vec<String>,
759}
760
761#[derive(Clone, Debug, Serialize, Deserialize)]
763pub struct VpnConcentrator {
764 pub id: String,
765 pub state: String,
766}
767
768#[derive(Clone, Debug, Serialize, Deserialize)]
770pub struct Ipam {
771 pub id: String,
772 pub public_scope_id: String,
773 pub private_scope_id: String,
774 pub tier: String,
775 #[serde(default)]
776 pub description: String,
777}
778
779#[derive(Clone, Debug, Serialize, Deserialize)]
781pub struct IpamScope {
782 pub id: String,
783 pub ipam_id: String,
784 #[serde(default)]
786 pub scope_type: String,
787 #[serde(default)]
788 pub description: String,
789}
790
791#[derive(Clone, Debug, Serialize, Deserialize)]
793pub struct IpamPool {
794 pub id: String,
795 pub scope_id: String,
796 pub address_family: String,
797 #[serde(default)]
798 pub description: String,
799}
800
801#[derive(Clone, Debug, Serialize, Deserialize)]
803pub struct IpamResourceDiscovery {
804 pub id: String,
805 #[serde(default)]
806 pub description: String,
807}
808
809#[derive(Clone, Debug, Serialize, Deserialize)]
811pub struct IpamPolicy {
812 pub id: String,
813 pub ipam_id: String,
814}
815
816#[derive(Clone, Debug, Serialize, Deserialize)]
818pub struct IpamPrefixListResolver {
819 pub id: String,
820 pub ipam_id: String,
821 pub address_family: String,
822 #[serde(default)]
823 pub description: String,
824}
825
826#[derive(Clone, Debug, Serialize, Deserialize)]
828pub struct IpamPrefixListResolverTarget {
829 pub id: String,
830 pub resolver_id: String,
831 pub prefix_list_id: String,
832 pub prefix_list_region: String,
833 #[serde(default)]
834 pub track_latest_version: bool,
835}
836
837#[derive(Clone, Debug, Serialize, Deserialize)]
839pub struct VerifiedAccessInstance {
840 pub id: String,
841 pub description: String,
842 #[serde(default)]
843 pub trust_providers: Vec<String>,
844}
845
846#[derive(Clone, Debug, Serialize, Deserialize)]
848pub struct VerifiedAccessTrustProvider {
849 pub id: String,
850 pub trust_provider_type: String,
851 pub policy_reference_name: String,
852 pub description: String,
853}
854
855#[derive(Clone, Debug, Serialize, Deserialize)]
857pub struct VerifiedAccessGroup {
858 pub id: String,
859 pub instance_id: String,
860 pub description: String,
861}
862
863#[derive(Clone, Debug, Serialize, Deserialize)]
865pub struct VerifiedAccessEndpoint {
866 pub id: String,
867 pub group_id: String,
868 pub instance_id: String,
869 pub endpoint_type: String,
870 pub attachment_type: String,
871}
872
873#[derive(Clone, Debug, Serialize, Deserialize)]
875pub struct NetworkInsightsPath {
876 pub id: String,
877 pub source: String,
878 pub destination: String,
879 pub protocol: String,
880}
881
882#[derive(Clone, Debug, Serialize, Deserialize)]
884pub struct NetworkInsightsAnalysis {
885 pub id: String,
886 pub path_id: String,
887}
888
889#[derive(Clone, Debug, Serialize, Deserialize)]
891pub struct NetworkInsightsAccessScope {
892 pub id: String,
893}
894
895#[derive(Clone, Debug, Serialize, Deserialize)]
897pub struct NetworkInsightsAccessScopeAnalysis {
898 pub id: String,
899 pub scope_id: String,
900}
901
902#[derive(Clone, Debug, Serialize, Deserialize)]
904pub struct CarrierGateway {
905 pub id: String,
906 pub vpc_id: String,
907}
908
909#[derive(Clone, Debug, Serialize, Deserialize)]
911pub struct InstanceConnectEndpoint {
912 pub id: String,
913 pub subnet_id: String,
914}
915
916#[derive(Clone, Debug, Serialize, Deserialize)]
918pub struct CoipPool {
919 pub id: String,
920 pub route_table_id: String,
921}
922
923#[derive(Clone, Debug, Serialize, Deserialize)]
925pub struct LocalGatewayRouteTable {
926 pub id: String,
927 pub local_gateway_id: String,
928 pub mode: String,
929}
930
931#[derive(Clone, Debug, Serialize, Deserialize)]
933pub struct LocalGatewayRouteTableVpcAssoc {
934 pub id: String,
935 pub route_table_id: String,
936 pub vpc_id: String,
937}
938
939#[derive(Clone, Debug, Serialize, Deserialize)]
941pub struct LocalGatewayVif {
942 pub id: String,
943 pub group_id: String,
944 pub vlan: String,
945 pub local_address: String,
946 pub peer_address: String,
947}
948
949#[derive(Clone, Debug, Serialize, Deserialize)]
951pub struct LocalGatewayVifGroup {
952 pub id: String,
953 pub local_gateway_id: String,
954}
955
956#[derive(Clone, Debug, Serialize, Deserialize)]
958pub struct LocalGatewayRouteTableVifgAssoc {
959 pub id: String,
960 pub route_table_id: String,
961 pub vif_group_id: String,
962}
963
964#[derive(Clone, Debug, Serialize, Deserialize)]
966pub struct ClientVpnEndpoint {
967 pub id: String,
968 pub description: String,
969 pub status: String,
970 pub server_cert_arn: String,
971 pub transport_protocol: String,
972 pub client_cidr: String,
973 #[serde(default)]
974 pub routes: Vec<String>,
975 #[serde(default)]
977 pub target_networks: Vec<(String, String)>,
978 #[serde(default)]
980 pub auth_rules: Vec<String>,
981}
982
983#[derive(Clone, Debug, Serialize, Deserialize)]
985pub struct TgwPeering {
986 pub id: String,
987 pub tgw_id: String,
988 pub peer_tgw_id: String,
989 pub peer_account: String,
990 pub peer_region: String,
991 pub state: String,
992}
993
994#[derive(Clone, Debug, Default, Serialize, Deserialize)]
997pub struct Ec2State {
998 pub account_id: String,
999 pub region: String,
1000 #[serde(default)]
1002 pub tags: BTreeMap<String, Vec<Tag>>,
1003 #[serde(default)]
1004 pub vpcs: BTreeMap<String, Vpc>,
1005 #[serde(default)]
1006 pub dhcp_options: BTreeMap<String, DhcpOptions>,
1007 #[serde(default)]
1008 pub subnets: BTreeMap<String, Subnet>,
1009 #[serde(default)]
1010 pub subnet_cidr_reservations: BTreeMap<String, SubnetCidrReservation>,
1011 #[serde(default)]
1012 pub security_groups: BTreeMap<String, SecurityGroup>,
1013 #[serde(default)]
1014 pub route_tables: BTreeMap<String, RouteTable>,
1015 #[serde(default)]
1016 pub internet_gateways: BTreeMap<String, InternetGateway>,
1017 #[serde(default)]
1018 pub egress_only_igws: BTreeMap<String, InternetGateway>,
1019 #[serde(default)]
1020 pub nat_gateways: BTreeMap<String, NatGateway>,
1021 #[serde(default)]
1023 pub elastic_ips: BTreeMap<String, ElasticIp>,
1024 #[serde(default)]
1026 pub key_pairs: BTreeMap<String, KeyPair>,
1027 #[serde(default)]
1029 pub placement_groups: BTreeMap<String, PlacementGroup>,
1030 #[serde(default)]
1031 pub network_interfaces: BTreeMap<String, NetworkInterface>,
1032 #[serde(default)]
1034 pub eni_permissions: BTreeMap<String, NetworkInterfacePermission>,
1035 #[serde(default)]
1036 pub instances: BTreeMap<String, Instance>,
1037 #[serde(default)]
1038 pub volumes: BTreeMap<String, Volume>,
1039 #[serde(default)]
1041 pub ebs_encryption_default: bool,
1042 #[serde(default)]
1044 pub ebs_default_kms_key_id: Option<String>,
1045 #[serde(default)]
1046 pub snapshots: BTreeMap<String, Snapshot>,
1047 #[serde(default)]
1049 pub snapshot_block_public_access: String,
1050 #[serde(default)]
1051 pub images: BTreeMap<String, Image>,
1052 #[serde(default)]
1054 pub image_watermarks: BTreeMap<String, BTreeMap<String, String>>,
1055 #[serde(default)]
1057 pub image_block_public_access: String,
1058 #[serde(default)]
1060 pub allowed_images_settings: String,
1061 #[serde(default)]
1062 pub network_acls: BTreeMap<String, NetworkAcl>,
1063 #[serde(default)]
1064 pub vpc_peerings: BTreeMap<String, VpcPeering>,
1065 #[serde(default)]
1066 pub vpc_endpoints: BTreeMap<String, VpcEndpoint>,
1067 #[serde(default)]
1068 pub endpoint_services: BTreeMap<String, EndpointService>,
1069 #[serde(default)]
1070 pub connection_notifications: BTreeMap<String, ConnectionNotification>,
1071 #[serde(default)]
1072 pub flow_logs: BTreeMap<String, FlowLog>,
1073 #[serde(default)]
1074 pub launch_templates: BTreeMap<String, LaunchTemplate>,
1075 #[serde(default)]
1076 pub spot_requests: BTreeMap<String, SpotRequest>,
1077 #[serde(default)]
1078 pub spot_fleets: BTreeMap<String, SpotFleet>,
1079 #[serde(default)]
1080 pub fleets: BTreeMap<String, Fleet>,
1081 #[serde(default)]
1083 pub spot_datafeed: Option<(String, String)>,
1084 #[serde(default)]
1085 pub capacity_reservations: BTreeMap<String, CapacityReservation>,
1086 #[serde(default)]
1088 pub capacity_reservation_fleets: BTreeMap<String, String>,
1089 #[serde(default)]
1090 pub reserved_instances: BTreeMap<String, ReservedInstances>,
1091 #[serde(default)]
1092 pub reserved_instances_listings: BTreeMap<String, ReservedInstancesListing>,
1093 #[serde(default)]
1094 pub reserved_instances_modifications: BTreeMap<String, ReservedInstancesModification>,
1095 #[serde(default)]
1096 pub dedicated_hosts: BTreeMap<String, DedicatedHost>,
1097 #[serde(default)]
1098 pub transit_gateways: BTreeMap<String, TransitGateway>,
1099 #[serde(default)]
1100 pub tgw_attachments: BTreeMap<String, TgwAttachment>,
1101 #[serde(default)]
1102 pub tgw_route_tables: BTreeMap<String, TgwRouteTable>,
1103 #[serde(default)]
1105 pub tgw_routes: BTreeMap<String, Vec<TgwRoute>>,
1106 #[serde(default)]
1108 pub tgw_rt_associations: BTreeMap<String, Vec<String>>,
1109 #[serde(default)]
1111 pub tgw_rt_propagations: BTreeMap<String, Vec<String>>,
1112 #[serde(default)]
1114 pub tgw_prefix_list_refs: BTreeMap<String, Vec<String>>,
1115 #[serde(default)]
1116 pub tgw_peerings: BTreeMap<String, TgwPeering>,
1117 #[serde(default)]
1119 pub tgw_connects: BTreeMap<String, (String, String)>,
1120 #[serde(default)]
1122 pub tgw_connect_peers: BTreeMap<String, String>,
1123 #[serde(default)]
1125 pub tgw_policy_tables: BTreeMap<String, String>,
1126 #[serde(default)]
1128 pub tgw_policy_table_associations: BTreeMap<String, Vec<String>>,
1129 #[serde(default)]
1131 pub tgw_announcements: BTreeMap<String, (String, String)>,
1132 #[serde(default)]
1133 pub tgw_multicast_domains: BTreeMap<String, TgwMulticastDomain>,
1134 #[serde(default)]
1135 pub tgw_metering_policies: BTreeMap<String, TgwMeteringPolicy>,
1136 #[serde(default)]
1137 pub customer_gateways: BTreeMap<String, CustomerGateway>,
1138 #[serde(default)]
1139 pub vpn_gateways: BTreeMap<String, VpnGateway>,
1140 #[serde(default)]
1141 pub vpn_connections: BTreeMap<String, VpnConnection>,
1142 #[serde(default)]
1143 pub vpn_concentrators: BTreeMap<String, VpnConcentrator>,
1144 #[serde(default)]
1145 pub client_vpn_endpoints: BTreeMap<String, ClientVpnEndpoint>,
1146 #[serde(default)]
1147 pub ipams: BTreeMap<String, Ipam>,
1148 #[serde(default)]
1149 pub ipam_scopes: BTreeMap<String, IpamScope>,
1150 #[serde(default)]
1151 pub ipam_pools: BTreeMap<String, IpamPool>,
1152 #[serde(default)]
1154 pub ipam_pool_cidrs: BTreeMap<String, Vec<(String, String)>>,
1155 #[serde(default)]
1157 pub ipam_pool_allocations: BTreeMap<String, Vec<(String, String)>>,
1158 #[serde(default)]
1159 pub ipam_resource_discoveries: BTreeMap<String, IpamResourceDiscovery>,
1160 #[serde(default)]
1162 pub ipam_rd_associations: BTreeMap<String, (String, String)>,
1163 #[serde(default)]
1165 pub ipam_byoasns: BTreeMap<String, String>,
1166 #[serde(default)]
1168 pub ipam_ext_tokens: BTreeMap<String, String>,
1169 #[serde(default)]
1170 pub ipam_policies: BTreeMap<String, IpamPolicy>,
1171 #[serde(default)]
1172 pub ipam_pl_resolvers: BTreeMap<String, IpamPrefixListResolver>,
1173 #[serde(default)]
1174 pub ipam_pl_resolver_targets: BTreeMap<String, IpamPrefixListResolverTarget>,
1175 #[serde(default)]
1177 pub ipam_policy_alloc_rules: BTreeMap<String, Vec<(String, String)>>,
1178 #[serde(default)]
1180 pub ipam_enabled_policy: Option<String>,
1181 #[serde(default)]
1182 pub va_instances: BTreeMap<String, VerifiedAccessInstance>,
1183 #[serde(default)]
1184 pub va_trust_providers: BTreeMap<String, VerifiedAccessTrustProvider>,
1185 #[serde(default)]
1186 pub va_groups: BTreeMap<String, VerifiedAccessGroup>,
1187 #[serde(default)]
1188 pub va_endpoints: BTreeMap<String, VerifiedAccessEndpoint>,
1189 #[serde(default)]
1191 pub va_group_policies: BTreeMap<String, String>,
1192 #[serde(default)]
1194 pub va_endpoint_policies: BTreeMap<String, String>,
1195 #[serde(default)]
1196 pub ni_paths: BTreeMap<String, NetworkInsightsPath>,
1197 #[serde(default)]
1198 pub ni_analyses: BTreeMap<String, NetworkInsightsAnalysis>,
1199 #[serde(default)]
1200 pub ni_access_scopes: BTreeMap<String, NetworkInsightsAccessScope>,
1201 #[serde(default)]
1202 pub ni_scope_analyses: BTreeMap<String, NetworkInsightsAccessScopeAnalysis>,
1203 #[serde(default)]
1204 pub carrier_gateways: BTreeMap<String, CarrierGateway>,
1205 #[serde(default)]
1206 pub coip_pools: BTreeMap<String, CoipPool>,
1207 #[serde(default)]
1209 pub coip_pool_cidrs: BTreeMap<String, Vec<String>>,
1210 #[serde(default)]
1211 pub lg_route_tables: BTreeMap<String, LocalGatewayRouteTable>,
1212 #[serde(default)]
1214 pub lg_routes: BTreeMap<String, Vec<String>>,
1215 #[serde(default)]
1216 pub lg_rt_vpc_assocs: BTreeMap<String, LocalGatewayRouteTableVpcAssoc>,
1217 #[serde(default)]
1218 pub lg_virtual_interfaces: BTreeMap<String, LocalGatewayVif>,
1219 #[serde(default)]
1220 pub lg_vif_groups: BTreeMap<String, LocalGatewayVifGroup>,
1221 #[serde(default)]
1222 pub lg_rt_vifg_assocs: BTreeMap<String, LocalGatewayRouteTableVifgAssoc>,
1223 #[serde(default)]
1224 pub instance_connect_endpoints: BTreeMap<String, InstanceConnectEndpoint>,
1225 #[serde(default)]
1227 pub fast_launch_images: std::collections::HashSet<String>,
1228 #[serde(default)]
1229 pub serial_console_access: bool,
1230}
1231
1232impl Ec2State {
1233 pub fn new(account_id: &str, region: &str) -> Self {
1234 let mut state = Self {
1235 account_id: account_id.to_string(),
1236 region: region.to_string(),
1237 ..Default::default()
1238 };
1239 crate::defaults::bootstrap_default_network(&mut state);
1245 state
1246 }
1247
1248 pub fn upsert_tags(&mut self, resource_id: &str, new_tags: &[Tag]) {
1251 let entry = self.tags.entry(resource_id.to_string()).or_default();
1252 for t in new_tags {
1253 if let Some(existing) = entry.iter_mut().find(|e| e.key == t.key) {
1254 existing.value = t.value.clone();
1255 } else {
1256 entry.push(t.clone());
1257 }
1258 }
1259 }
1260
1261 pub fn remove_tags(&mut self, resource_id: &str, to_remove: &[(String, Option<String>)]) {
1265 if let Some(entry) = self.tags.get_mut(resource_id) {
1266 for (key, value) in to_remove {
1267 entry.retain(|e| {
1268 if &e.key != key {
1269 return true;
1270 }
1271 match value {
1272 Some(v) => &e.value != v,
1273 None => false,
1274 }
1275 });
1276 }
1277 if entry.is_empty() {
1278 self.tags.remove(resource_id);
1279 }
1280 }
1281 }
1282
1283 pub fn tags_for(&self, resource_id: &str) -> &[Tag] {
1285 self.tags.get(resource_id).map(Vec::as_slice).unwrap_or(&[])
1286 }
1287}
1288
1289#[cfg(test)]
1290mod tests {
1291 use super::*;
1292
1293 fn tag(k: &str, v: &str) -> Tag {
1294 Tag {
1295 key: k.to_string(),
1296 value: v.to_string(),
1297 }
1298 }
1299
1300 #[test]
1301 fn upsert_tags_inserts_then_overwrites_by_key() {
1302 let mut s = Ec2State::new("123456789012", "us-east-1");
1303 s.upsert_tags("vpc-1", &[tag("Name", "a"), tag("env", "dev")]);
1304 s.upsert_tags("vpc-1", &[tag("Name", "b")]);
1305 let tags = s.tags_for("vpc-1");
1306 assert_eq!(tags.len(), 2);
1307 assert_eq!(tags.iter().find(|t| t.key == "Name").unwrap().value, "b");
1308 }
1309
1310 #[test]
1311 fn remove_tags_by_key_and_by_key_value() {
1312 let mut s = Ec2State::new("123456789012", "us-east-1");
1313 s.upsert_tags(
1314 "i-1",
1315 &[tag("Name", "x"), tag("env", "prod"), tag("team", "a")],
1316 );
1317 s.remove_tags("i-1", &[("Name".to_string(), None)]);
1319 s.remove_tags("i-1", &[("env".to_string(), Some("dev".to_string()))]);
1321 s.remove_tags("i-1", &[("team".to_string(), Some("a".to_string()))]);
1323 let tags = s.tags_for("i-1");
1324 assert_eq!(tags.len(), 1);
1325 assert_eq!(tags[0].key, "env");
1326 }
1327
1328 #[test]
1329 fn empty_tag_set_drops_resource_entry() {
1330 let mut s = Ec2State::new("123456789012", "us-east-1");
1331 s.upsert_tags("sg-1", &[tag("Name", "x")]);
1332 s.remove_tags("sg-1", &[("Name".to_string(), None)]);
1333 assert!(!s.tags.contains_key("sg-1"));
1334 }
1335
1336 fn sample_instance() -> Instance {
1337 Instance {
1338 instance_id: "i-1".to_string(),
1339 image_id: "ami-1".to_string(),
1340 instance_type: "t3.micro".to_string(),
1341 state_code: 16,
1342 state_name: "running".to_string(),
1343 private_ip: "10.0.0.1".to_string(),
1344 public_ip: Some("52.0.0.1".to_string()),
1345 subnet_id: Some("subnet-1".to_string()),
1346 vpc_id: Some("vpc-1".to_string()),
1347 key_name: None,
1348 security_group_ids: vec!["sg-1".to_string()],
1349 reservation_id: "r-1".to_string(),
1350 ami_launch_index: 0,
1351 monitoring: false,
1352 az: "us-east-1a".to_string(),
1353 launch_time: "2024-01-01T00:00:00.000Z".to_string(),
1354 container_id: Some("abc".to_string()),
1355 disable_api_termination: true,
1356 disable_api_stop: true,
1357 source_dest_check: false,
1358 ebs_optimized: true,
1359 instance_initiated_shutdown_behavior: "terminate".to_string(),
1360 user_data: Some("ZWNobyBoaQ==".to_string()),
1361 metadata_options: MetadataOptions {
1362 http_tokens: "required".to_string(),
1363 ..MetadataOptions::default()
1364 },
1365 cpu_options: Some(CpuOptions {
1366 core_count: 4,
1367 threads_per_core: 2,
1368 }),
1369 bandwidth_weighting: Some("vpc-1".to_string()),
1370 maintenance_options: MaintenanceOptions::default(),
1371 placement_tenancy: Some("dedicated".to_string()),
1372 placement_affinity: None,
1373 placement_group_name: Some("cluster-1".to_string()),
1374 }
1375 }
1376
1377 #[test]
1378 fn instance_attributes_round_trip_through_serde() {
1379 let inst = sample_instance();
1380 let json = serde_json::to_string(&inst).unwrap();
1381 let back: Instance = serde_json::from_str(&json).unwrap();
1382 assert!(back.disable_api_termination);
1383 assert!(back.disable_api_stop);
1384 assert!(!back.source_dest_check);
1385 assert!(back.ebs_optimized);
1386 assert_eq!(back.instance_initiated_shutdown_behavior, "terminate");
1387 assert_eq!(back.user_data.as_deref(), Some("ZWNobyBoaQ=="));
1388 assert_eq!(back.metadata_options.http_tokens, "required");
1389 assert_eq!(back.cpu_options.as_ref().unwrap().core_count, 4);
1390 assert_eq!(back.bandwidth_weighting.as_deref(), Some("vpc-1"));
1391 assert_eq!(back.placement_tenancy.as_deref(), Some("dedicated"));
1392 assert_eq!(back.placement_group_name.as_deref(), Some("cluster-1"));
1393 }
1394
1395 #[test]
1396 fn instance_attribute_defaults_load_from_legacy_snapshot() {
1397 let legacy = r#"{
1400 "instance_id":"i-1","image_id":"ami-1","instance_type":"t3.micro",
1401 "state_code":16,"state_name":"running","private_ip":"10.0.0.1",
1402 "public_ip":null,"subnet_id":null,"vpc_id":null,"key_name":null,
1403 "reservation_id":"r-1","ami_launch_index":0,"monitoring":false,
1404 "az":"us-east-1a","launch_time":"2024-01-01T00:00:00.000Z"
1405 }"#;
1406 let inst: Instance = serde_json::from_str(legacy).unwrap();
1407 assert!(!inst.disable_api_termination);
1408 assert!(inst.source_dest_check, "sourceDestCheck defaults to true");
1409 assert_eq!(inst.instance_initiated_shutdown_behavior, "stop");
1410 assert_eq!(inst.metadata_options.http_tokens, "optional");
1411 assert!(inst.cpu_options.is_none());
1412 }
1413}