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, Default, Serialize, Deserialize)]
41pub struct RecycleBinRetention {
42 #[serde(default)]
43 pub volumes: bool,
44 #[serde(default)]
45 pub snapshots: bool,
46 #[serde(default)]
47 pub images: bool,
48}
49
50#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
52pub struct Tag {
53 pub key: String,
54 pub value: String,
55}
56
57#[derive(Clone, Debug, Serialize, Deserialize)]
59pub struct VpcCidrAssoc {
60 pub association_id: String,
61 pub cidr_block: String,
62 pub state: String,
64}
65
66#[derive(Clone, Debug, Serialize, Deserialize)]
68pub struct Vpc {
69 pub vpc_id: String,
70 pub cidr_block: String,
71 pub state: String,
73 pub dhcp_options_id: String,
74 pub instance_tenancy: String,
76 pub is_default: bool,
77 pub enable_dns_support: bool,
78 pub enable_dns_hostnames: bool,
79 #[serde(default)]
80 pub cidr_associations: Vec<VpcCidrAssoc>,
81 #[serde(default)]
86 pub ipv6_cidr_block: Option<String>,
87}
88
89#[derive(Clone, Debug, Serialize, Deserialize)]
91pub struct DhcpConfig {
92 pub key: String,
93 pub values: Vec<String>,
94}
95
96#[derive(Clone, Debug, Serialize, Deserialize)]
98pub struct DhcpOptions {
99 pub dhcp_options_id: String,
100 pub configurations: Vec<DhcpConfig>,
101}
102
103#[derive(Clone, Debug, Serialize, Deserialize)]
105pub struct Subnet {
106 pub subnet_id: String,
107 pub vpc_id: String,
108 pub cidr_block: String,
109 pub availability_zone: String,
110 pub availability_zone_id: String,
111 pub state: String,
113 pub available_ip_address_count: i32,
114 pub default_for_az: bool,
115 pub map_public_ip_on_launch: bool,
116 pub assign_ipv6_address_on_creation: bool,
117 pub map_customer_owned_ip_on_launch: bool,
118 pub enable_dns64: bool,
119 pub private_dns_hostname_type: String,
121 #[serde(default)]
125 pub ipv6_cidr_block: Option<String>,
126}
127
128#[derive(Clone, Debug, Serialize, Deserialize)]
130pub struct SubnetCidrReservation {
131 pub subnet_cidr_reservation_id: String,
132 pub subnet_id: String,
133 pub cidr: String,
134 pub reservation_type: String,
136 pub description: String,
137}
138
139#[derive(Clone, Debug, Serialize, Deserialize)]
141pub struct SecurityGroupRule {
142 pub rule_id: String,
143 pub group_id: String,
144 pub is_egress: bool,
145 pub ip_protocol: String,
146 pub from_port: i64,
147 pub to_port: i64,
148 pub cidr_ipv4: Option<String>,
149 pub cidr_ipv6: Option<String>,
150 pub prefix_list_id: Option<String>,
151 pub referenced_group_id: Option<String>,
152 pub description: String,
153}
154
155#[derive(Clone, Debug, Serialize, Deserialize)]
157pub struct SecurityGroup {
158 pub group_id: String,
159 pub group_name: String,
160 pub description: String,
161 pub vpc_id: String,
162 #[serde(default)]
163 pub rules: Vec<SecurityGroupRule>,
164}
165
166#[derive(Clone, Debug, Default, Serialize, Deserialize)]
168pub struct Route {
169 pub destination_cidr_block: Option<String>,
170 pub destination_ipv6_cidr_block: Option<String>,
171 pub destination_prefix_list_id: Option<String>,
172 pub gateway_id: Option<String>,
173 pub nat_gateway_id: Option<String>,
174 pub network_interface_id: Option<String>,
175 pub instance_id: Option<String>,
176 pub vpc_peering_connection_id: Option<String>,
177 pub transit_gateway_id: Option<String>,
178 pub egress_only_internet_gateway_id: Option<String>,
179 pub state: String,
181 pub origin: String,
183}
184
185#[derive(Clone, Debug, Serialize, Deserialize)]
187pub struct RouteTableAssociation {
188 pub association_id: String,
189 pub route_table_id: String,
190 pub subnet_id: Option<String>,
191 pub gateway_id: Option<String>,
192 pub main: bool,
193}
194
195#[derive(Clone, Debug, Serialize, Deserialize)]
197pub struct RouteTable {
198 pub route_table_id: String,
199 pub vpc_id: String,
200 #[serde(default)]
201 pub routes: Vec<Route>,
202 #[serde(default)]
203 pub associations: Vec<RouteTableAssociation>,
204}
205
206#[derive(Clone, Debug, Serialize, Deserialize)]
208pub struct InternetGateway {
209 pub internet_gateway_id: String,
210 #[serde(default)]
212 pub attachments: Vec<(String, String)>,
213}
214
215#[derive(Clone, Debug, Serialize, Deserialize)]
217pub struct NatGateway {
218 pub nat_gateway_id: String,
219 pub subnet_id: String,
220 pub vpc_id: String,
221 pub state: String,
223 pub connectivity_type: String,
225 pub allocation_id: Option<String>,
226}
227
228#[derive(Clone, Debug, Serialize, Deserialize)]
230pub struct ElasticIp {
231 pub allocation_id: String,
232 pub public_ip: String,
233 pub domain: String,
235 pub association_id: Option<String>,
236 pub instance_id: Option<String>,
237 pub network_interface_id: Option<String>,
238 pub private_ip_address: Option<String>,
239}
240
241#[derive(Clone, Debug, Serialize, Deserialize)]
243pub struct KeyPair {
244 pub key_pair_id: String,
245 pub key_name: String,
246 pub key_type: String,
248 pub key_fingerprint: String,
249}
250
251#[derive(Clone, Debug, Serialize, Deserialize)]
253pub struct PlacementGroup {
254 pub group_id: String,
255 pub group_name: String,
256 pub strategy: String,
258 pub state: String,
260 pub partition_count: Option<i64>,
261 pub spread_level: Option<String>,
262}
263
264#[derive(Clone, Debug, Serialize, Deserialize)]
266pub struct EniAttachment {
267 pub attachment_id: String,
268 pub instance_id: String,
269 pub device_index: i64,
270 pub status: String,
272}
273
274#[derive(Clone, Debug, Serialize, Deserialize)]
276pub struct NetworkInterface {
277 pub network_interface_id: String,
278 pub subnet_id: String,
279 pub vpc_id: String,
280 pub availability_zone: String,
281 pub description: String,
282 pub mac_address: String,
283 pub private_ip_address: String,
284 pub status: String,
286 pub interface_type: String,
287 pub source_dest_check: bool,
288 #[serde(default)]
289 pub group_ids: Vec<String>,
290 #[serde(default)]
291 pub private_ips: Vec<String>,
292 #[serde(default)]
293 pub ipv6_addresses: Vec<String>,
294 pub attachment: Option<EniAttachment>,
295 #[serde(default)]
300 pub public_ip_dns_hostname_type: Option<String>,
301}
302
303#[derive(Clone, Debug, Serialize, Deserialize)]
305pub struct NetworkInterfacePermission {
306 pub permission_id: String,
307 pub network_interface_id: String,
308 pub aws_account_id: String,
309 pub permission: String,
311}
312
313#[derive(Clone, Debug, Serialize, Deserialize)]
315pub struct Instance {
316 pub instance_id: String,
317 pub image_id: String,
318 pub instance_type: String,
319 pub state_code: i64,
322 pub state_name: String,
323 pub private_ip: String,
324 pub public_ip: Option<String>,
325 pub subnet_id: Option<String>,
326 pub vpc_id: Option<String>,
327 pub key_name: Option<String>,
328 #[serde(default)]
329 pub security_group_ids: Vec<String>,
330 pub reservation_id: String,
331 pub ami_launch_index: i64,
332 pub monitoring: bool,
333 pub az: String,
334 pub launch_time: String,
335 #[serde(default)]
338 pub container_id: Option<String>,
339 #[serde(default)]
342 pub disable_api_termination: bool,
343 #[serde(default)]
345 pub disable_api_stop: bool,
346 #[serde(default = "default_true")]
348 pub source_dest_check: bool,
349 #[serde(default)]
351 pub ebs_optimized: bool,
352 #[serde(default = "default_shutdown_behavior")]
354 pub instance_initiated_shutdown_behavior: String,
355 #[serde(default)]
357 pub user_data: Option<String>,
358 #[serde(default)]
361 pub metadata_options: MetadataOptions,
362 #[serde(default)]
364 pub cpu_options: Option<CpuOptions>,
365 #[serde(default)]
367 pub bandwidth_weighting: Option<String>,
368 #[serde(default)]
370 pub maintenance_options: MaintenanceOptions,
371 #[serde(default)]
373 pub placement_tenancy: Option<String>,
374 #[serde(default)]
375 pub placement_affinity: Option<String>,
376 #[serde(default)]
377 pub placement_group_name: Option<String>,
378 #[serde(default)]
382 pub private_dns_hostname_type: Option<String>,
383 #[serde(default)]
385 pub enable_resource_name_dns_a_record: bool,
386 #[serde(default)]
388 pub enable_resource_name_dns_aaaa_record: bool,
389}
390
391fn default_true() -> bool {
392 true
393}
394
395fn default_shutdown_behavior() -> String {
396 "stop".to_string()
397}
398
399#[derive(Clone, Debug, Serialize, Deserialize)]
402pub struct MetadataOptions {
403 pub http_tokens: String,
405 pub http_endpoint: String,
407 pub http_put_response_hop_limit: i64,
408 pub http_protocol_ipv6: String,
410 pub instance_metadata_tags: String,
412}
413
414#[derive(Clone, Debug, Default, Serialize, Deserialize)]
418pub struct InstanceMetadataDefaults {
419 #[serde(default)]
420 pub http_tokens: Option<String>,
421 #[serde(default)]
422 pub http_endpoint: Option<String>,
423 #[serde(default)]
424 pub http_put_response_hop_limit: Option<i64>,
425 #[serde(default)]
426 pub instance_metadata_tags: Option<String>,
427 #[serde(default)]
428 pub http_tokens_enforced: Option<String>,
429}
430
431impl Default for MetadataOptions {
432 fn default() -> Self {
433 Self {
434 http_tokens: "optional".to_string(),
435 http_endpoint: "enabled".to_string(),
436 http_put_response_hop_limit: 1,
437 http_protocol_ipv6: "disabled".to_string(),
438 instance_metadata_tags: "disabled".to_string(),
439 }
440 }
441}
442
443#[derive(Clone, Debug, Serialize, Deserialize)]
445pub struct CpuOptions {
446 pub core_count: i64,
447 pub threads_per_core: i64,
448}
449
450#[derive(Clone, Debug, Serialize, Deserialize)]
452pub struct MaintenanceOptions {
453 pub auto_recovery: String,
455 pub reboot_migration: String,
457}
458
459impl Default for MaintenanceOptions {
460 fn default() -> Self {
461 Self {
462 auto_recovery: "default".to_string(),
463 reboot_migration: "default".to_string(),
464 }
465 }
466}
467
468#[derive(Clone, Debug, Serialize, Deserialize)]
470pub struct VolumeAttachment {
471 pub volume_id: String,
472 pub instance_id: String,
473 pub device: String,
474 pub status: String,
476 pub delete_on_termination: bool,
477}
478
479#[derive(Clone, Debug, Serialize, Deserialize)]
481pub struct VolumeModification {
482 pub original_size: i64,
483 pub original_iops: Option<i64>,
484 pub original_throughput: Option<i64>,
485 pub original_volume_type: String,
486 pub target_size: i64,
487 pub target_iops: Option<i64>,
488 pub target_throughput: Option<i64>,
489 pub target_volume_type: String,
490 pub state: String,
492 pub start_time: String,
493}
494
495#[derive(Clone, Debug, Serialize, Deserialize)]
497pub struct Volume {
498 pub volume_id: String,
499 pub size: i64,
500 pub snapshot_id: Option<String>,
501 pub availability_zone: String,
502 pub state: String,
504 pub volume_type: String,
505 pub iops: Option<i64>,
506 pub throughput: Option<i64>,
507 pub encrypted: bool,
508 pub kms_key_id: Option<String>,
509 pub multi_attach_enabled: bool,
510 pub auto_enable_io: bool,
511 #[serde(default)]
512 pub attachments: Vec<VolumeAttachment>,
513 #[serde(default)]
514 pub in_recycle_bin: bool,
515 #[serde(default)]
517 pub modification: Option<VolumeModification>,
518}
519
520#[derive(Clone, Debug, Serialize, Deserialize)]
522pub struct Snapshot {
523 pub snapshot_id: String,
524 pub volume_id: String,
525 pub state: String,
527 pub volume_size: i64,
528 pub description: String,
529 pub encrypted: bool,
530 pub storage_tier: String,
532 #[serde(default)]
533 pub in_recycle_bin: bool,
534 #[serde(default)]
535 pub locked: bool,
536 pub lock_mode: Option<String>,
537 #[serde(default)]
540 pub create_volume_permissions: Vec<String>,
541}
542
543#[derive(Clone, Debug, Serialize, Deserialize)]
545pub struct Image {
546 pub image_id: String,
547 pub name: String,
548 pub description: String,
549 pub state: String,
551 pub architecture: String,
552 pub public: bool,
553 pub source_instance_id: Option<String>,
554 #[serde(default)]
555 pub in_recycle_bin: bool,
556 pub deprecation_time: Option<String>,
557 #[serde(default)]
558 pub deregistration_protection: bool,
559 #[serde(default)]
562 pub launch_permission_users: Vec<String>,
563 #[serde(default)]
565 pub launch_permission_groups: Vec<String>,
566 #[serde(default)]
569 pub boot_mode: Option<String>,
570 #[serde(default)]
575 pub owner_id: Option<String>,
576 #[serde(default)]
580 pub owner_alias: Option<String>,
581 #[serde(default)]
585 pub creation_date: Option<String>,
586 #[serde(default)]
589 pub root_device_name: Option<String>,
590 #[serde(default)]
592 pub platform: Option<String>,
593}
594
595#[derive(Clone, Debug, Serialize, Deserialize)]
597pub struct NetworkAclEntry {
598 pub rule_number: i64,
599 pub protocol: String,
600 pub rule_action: String,
602 pub egress: bool,
603 pub cidr_block: Option<String>,
604 pub ipv6_cidr_block: Option<String>,
605 pub port_range: Option<(i64, i64)>,
607 pub icmp_type_code: Option<(i64, i64)>,
609}
610
611#[derive(Clone, Debug, Serialize, Deserialize)]
613pub struct NetworkAclAssoc {
614 pub association_id: String,
615 pub subnet_id: String,
616}
617
618#[derive(Clone, Debug, Serialize, Deserialize)]
620pub struct NetworkAcl {
621 pub network_acl_id: String,
622 pub vpc_id: String,
623 pub is_default: bool,
624 #[serde(default)]
625 pub entries: Vec<NetworkAclEntry>,
626 #[serde(default)]
627 pub associations: Vec<NetworkAclAssoc>,
628}
629
630#[derive(Clone, Debug, Serialize, Deserialize)]
632pub struct VpcPeering {
633 pub id: String,
634 pub requester_vpc_id: String,
635 pub accepter_vpc_id: String,
636 pub status: String,
638 #[serde(default)]
640 pub requester_allow_dns: bool,
641 #[serde(default)]
643 pub accepter_allow_dns: bool,
644}
645
646#[derive(Clone, Debug, Serialize, Deserialize)]
648pub struct VpcEndpoint {
649 pub id: String,
650 pub endpoint_type: String,
652 pub vpc_id: String,
653 pub service_name: String,
654 pub state: String,
655 #[serde(default)]
656 pub subnet_ids: Vec<String>,
657 #[serde(default)]
658 pub route_table_ids: Vec<String>,
659 #[serde(default)]
660 pub private_dns_enabled: bool,
661 #[serde(default)]
663 pub security_group_ids: Vec<String>,
664 #[serde(default)]
667 pub payer_responsibility: String,
668}
669
670#[derive(Clone, Debug, Serialize, Deserialize)]
672pub struct EndpointService {
673 pub service_id: String,
674 pub service_name: String,
675 pub state: String,
676 pub acceptance_required: bool,
677 pub payer_responsibility: String,
678 #[serde(default)]
679 pub nlb_arns: Vec<String>,
680}
681
682#[derive(Clone, Debug, Serialize, Deserialize)]
684pub struct ConnectionNotification {
685 pub id: String,
686 pub arn: String,
687 pub service_id: Option<String>,
688 #[serde(default)]
689 pub events: Vec<String>,
690}
691
692#[derive(Clone, Debug, Serialize, Deserialize)]
694pub struct FlowLog {
695 pub id: String,
696 pub resource_id: String,
697 pub traffic_type: String,
698 pub log_destination_type: String,
699 pub log_group_name: Option<String>,
700 pub log_destination: Option<String>,
702 #[serde(default)]
705 pub deliver_logs_permission_arn: Option<String>,
706 #[serde(default = "default_max_aggregation_interval")]
709 pub max_aggregation_interval: i64,
710}
711
712fn default_max_aggregation_interval() -> i64 {
713 600
714}
715
716#[derive(Clone, Debug, Serialize, Deserialize)]
718pub struct LaunchTemplate {
719 pub id: String,
720 pub name: String,
721 pub default_version: i64,
722 pub latest_version: i64,
723}
724
725#[derive(Clone, Debug, Serialize, Deserialize)]
727pub struct SpotRequest {
728 pub id: String,
729 pub state: String,
731 pub request_type: String,
732 pub spot_price: String,
733}
734
735#[derive(Clone, Debug, Serialize, Deserialize)]
737pub struct SpotFleet {
738 pub id: String,
739 pub state: String,
740 #[serde(default)]
742 pub target_capacity: i64,
743}
744
745#[derive(Clone, Debug, Serialize, Deserialize)]
747pub struct Fleet {
748 pub id: String,
749 pub state: String,
750 pub fleet_type: String,
751 #[serde(default)]
753 pub target_capacity: i64,
754}
755
756#[derive(Clone, Debug, Serialize, Deserialize)]
758pub struct CapacityReservation {
759 pub id: String,
760 pub instance_type: String,
761 pub instance_platform: String,
762 pub availability_zone: String,
763 pub tenancy: String,
764 pub total_instance_count: i64,
765 pub available_instance_count: i64,
766 pub state: String,
768 pub end_date_type: String,
769 pub instance_match_criteria: String,
770}
771
772#[derive(Clone, Debug, Serialize, Deserialize)]
774pub struct ReservedInstances {
775 pub id: String,
776 pub instance_type: String,
777 pub availability_zone: String,
778 pub instance_count: i64,
779 pub product_description: String,
780 pub state: String,
781 pub duration: i64,
782 pub fixed_price: String,
783 pub usage_price: String,
784}
785
786#[derive(Clone, Debug, Serialize, Deserialize)]
788pub struct ReservedInstancesListing {
789 pub listing_id: String,
790 pub reserved_instances_id: String,
791 pub instance_count: i64,
792 pub client_token: String,
793 pub status: String,
795 pub status_message: String,
796}
797
798#[derive(Clone, Debug, Serialize, Deserialize)]
800pub struct ReservedInstancesModification {
801 pub modification_id: String,
802 pub reserved_instances_ids: Vec<String>,
803 pub status: String,
805 pub client_token: String,
806}
807
808#[derive(Clone, Debug, Serialize, Deserialize)]
810pub struct DedicatedHost {
811 pub id: String,
812 pub auto_placement: String,
813 pub availability_zone: String,
814 pub instance_type: String,
815 pub state: String,
816 pub host_recovery: String,
817 pub host_maintenance: String,
818}
819
820#[derive(Clone, Debug, Serialize, Deserialize)]
822pub struct TransitGateway {
823 pub id: String,
824 pub description: String,
825 #[serde(default = "tgw_default_state")]
827 pub state: String,
828}
829
830fn tgw_default_state() -> String {
831 "available".to_string()
832}
833
834#[derive(Clone, Debug, Serialize, Deserialize)]
836pub struct TgwAttachment {
837 pub id: String,
838 pub tgw_id: String,
839 pub resource_id: String,
840 pub resource_type: String,
841 #[serde(default)]
842 pub subnet_ids: Vec<String>,
843 pub state: String,
844}
845
846#[derive(Clone, Debug, Serialize, Deserialize)]
848pub struct TgwRouteTable {
849 pub id: String,
850 pub tgw_id: String,
851}
852
853#[derive(Clone, Debug, Serialize, Deserialize)]
855pub struct TgwRoute {
856 pub cidr: String,
857 pub attachment_id: String,
858 pub state: String,
859}
860
861#[derive(Clone, Debug, Serialize, Deserialize)]
863pub struct TgwMulticastDomain {
864 pub id: String,
865 pub tgw_id: String,
866}
867
868#[derive(Clone, Debug, Serialize, Deserialize)]
870pub struct TgwMeteringPolicy {
871 pub id: String,
872 pub tgw_id: String,
873}
874
875#[derive(Clone, Debug, Serialize, Deserialize)]
877pub struct CustomerGateway {
878 pub id: String,
879 pub state: String,
880 pub ip_address: String,
881 pub bgp_asn: String,
882}
883
884#[derive(Clone, Debug, Serialize, Deserialize)]
886pub struct VpnGateway {
887 pub id: String,
888 pub state: String,
889 #[serde(default)]
890 pub attachments: Vec<String>,
891}
892
893#[derive(Clone, Debug, Serialize, Deserialize)]
895pub struct VpnConnection {
896 pub id: String,
897 pub state: String,
898 pub customer_gateway_id: String,
899 pub vpn_gateway_id: Option<String>,
900 #[serde(default)]
901 pub routes: Vec<String>,
902}
903
904#[derive(Clone, Debug, Serialize, Deserialize)]
906pub struct VpnConcentrator {
907 pub id: String,
908 pub state: String,
909}
910
911#[derive(Clone, Debug, Serialize, Deserialize)]
913pub struct Ipam {
914 pub id: String,
915 pub public_scope_id: String,
916 pub private_scope_id: String,
917 pub tier: String,
918 #[serde(default)]
919 pub description: String,
920}
921
922#[derive(Clone, Debug, Serialize, Deserialize)]
924pub struct IpamScope {
925 pub id: String,
926 pub ipam_id: String,
927 #[serde(default)]
929 pub scope_type: String,
930 #[serde(default)]
931 pub description: String,
932}
933
934#[derive(Clone, Debug, Serialize, Deserialize)]
936pub struct IpamPool {
937 pub id: String,
938 pub scope_id: String,
939 pub address_family: String,
940 #[serde(default)]
941 pub description: String,
942}
943
944#[derive(Clone, Debug, Serialize, Deserialize)]
946pub struct IpamResourceDiscovery {
947 pub id: String,
948 #[serde(default)]
949 pub description: String,
950}
951
952#[derive(Clone, Debug, Serialize, Deserialize)]
954pub struct IpamPolicy {
955 pub id: String,
956 pub ipam_id: String,
957}
958
959#[derive(Clone, Debug, Serialize, Deserialize)]
961pub struct IpamPrefixListResolver {
962 pub id: String,
963 pub ipam_id: String,
964 pub address_family: String,
965 #[serde(default)]
966 pub description: String,
967}
968
969#[derive(Clone, Debug, Serialize, Deserialize)]
971pub struct IpamPrefixListResolverTarget {
972 pub id: String,
973 pub resolver_id: String,
974 pub prefix_list_id: String,
975 pub prefix_list_region: String,
976 #[serde(default)]
977 pub track_latest_version: bool,
978}
979
980#[derive(Clone, Debug, Serialize, Deserialize)]
982pub struct VerifiedAccessInstance {
983 pub id: String,
984 pub description: String,
985 #[serde(default)]
986 pub trust_providers: Vec<String>,
987}
988
989#[derive(Clone, Debug, Serialize, Deserialize)]
991pub struct VerifiedAccessTrustProvider {
992 pub id: String,
993 pub trust_provider_type: String,
994 pub policy_reference_name: String,
995 pub description: String,
996}
997
998#[derive(Clone, Debug, Serialize, Deserialize)]
1000pub struct VerifiedAccessGroup {
1001 pub id: String,
1002 pub instance_id: String,
1003 pub description: String,
1004}
1005
1006#[derive(Clone, Debug, Serialize, Deserialize)]
1008pub struct VerifiedAccessEndpoint {
1009 pub id: String,
1010 pub group_id: String,
1011 pub instance_id: String,
1012 pub endpoint_type: String,
1013 pub attachment_type: String,
1014}
1015
1016#[derive(Clone, Debug, Serialize, Deserialize)]
1018pub struct NetworkInsightsPath {
1019 pub id: String,
1020 pub source: String,
1021 pub destination: String,
1022 pub protocol: String,
1023}
1024
1025#[derive(Clone, Debug, Serialize, Deserialize)]
1027pub struct NetworkInsightsAnalysis {
1028 pub id: String,
1029 pub path_id: String,
1030}
1031
1032#[derive(Clone, Debug, Serialize, Deserialize)]
1034pub struct NetworkInsightsAccessScope {
1035 pub id: String,
1036}
1037
1038#[derive(Clone, Debug, Serialize, Deserialize)]
1040pub struct NetworkInsightsAccessScopeAnalysis {
1041 pub id: String,
1042 pub scope_id: String,
1043}
1044
1045#[derive(Clone, Debug, Serialize, Deserialize)]
1047pub struct CarrierGateway {
1048 pub id: String,
1049 pub vpc_id: String,
1050}
1051
1052#[derive(Clone, Debug, Serialize, Deserialize)]
1054pub struct InstanceConnectEndpoint {
1055 pub id: String,
1056 pub subnet_id: String,
1057}
1058
1059#[derive(Clone, Debug, Serialize, Deserialize)]
1061pub struct CoipPool {
1062 pub id: String,
1063 pub route_table_id: String,
1064}
1065
1066#[derive(Clone, Debug, Serialize, Deserialize)]
1068pub struct LocalGatewayRouteTable {
1069 pub id: String,
1070 pub local_gateway_id: String,
1071 pub mode: String,
1072}
1073
1074#[derive(Clone, Debug, Serialize, Deserialize)]
1076pub struct LocalGatewayRouteTableVpcAssoc {
1077 pub id: String,
1078 pub route_table_id: String,
1079 pub vpc_id: String,
1080}
1081
1082#[derive(Clone, Debug, Serialize, Deserialize)]
1084pub struct LocalGatewayVif {
1085 pub id: String,
1086 pub group_id: String,
1087 pub vlan: String,
1088 pub local_address: String,
1089 pub peer_address: String,
1090}
1091
1092#[derive(Clone, Debug, Serialize, Deserialize)]
1094pub struct LocalGatewayVifGroup {
1095 pub id: String,
1096 pub local_gateway_id: String,
1097}
1098
1099#[derive(Clone, Debug, Serialize, Deserialize)]
1101pub struct LocalGatewayRouteTableVifgAssoc {
1102 pub id: String,
1103 pub route_table_id: String,
1104 pub vif_group_id: String,
1105}
1106
1107#[derive(Clone, Debug, Serialize, Deserialize)]
1109pub struct ClientVpnEndpoint {
1110 pub id: String,
1111 pub description: String,
1112 pub status: String,
1113 pub server_cert_arn: String,
1114 pub transport_protocol: String,
1115 pub client_cidr: String,
1116 #[serde(default)]
1117 pub routes: Vec<String>,
1118 #[serde(default)]
1120 pub target_networks: Vec<(String, String)>,
1121 #[serde(default)]
1123 pub auth_rules: Vec<String>,
1124}
1125
1126#[derive(Clone, Debug, Serialize, Deserialize)]
1128pub struct TgwPeering {
1129 pub id: String,
1130 pub tgw_id: String,
1131 pub peer_tgw_id: String,
1132 pub peer_account: String,
1133 pub peer_region: String,
1134 pub state: String,
1135}
1136
1137#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
1139pub struct PrefixListEntry {
1140 pub cidr: String,
1141 #[serde(default)]
1142 pub description: Option<String>,
1143}
1144
1145#[derive(Clone, Debug, Serialize, Deserialize)]
1150pub struct ManagedPrefixList {
1151 pub prefix_list_id: String,
1152 pub prefix_list_name: String,
1153 pub address_family: String,
1154 pub max_entries: i64,
1155 pub version: i64,
1156 pub state: String,
1158 #[serde(default)]
1159 pub entries: Vec<PrefixListEntry>,
1160 #[serde(default)]
1162 pub version_history: BTreeMap<i64, Vec<PrefixListEntry>>,
1163}
1164
1165#[derive(Clone, Debug, Serialize, Deserialize)]
1167pub struct EventWindowTimeRange {
1168 pub start_week_day: String,
1169 pub start_hour: i64,
1170 pub end_week_day: String,
1171 pub end_hour: i64,
1172}
1173
1174#[derive(Clone, Debug, Serialize, Deserialize)]
1176pub struct InstanceEventWindow {
1177 pub id: String,
1178 #[serde(default)]
1179 pub name: Option<String>,
1180 #[serde(default)]
1181 pub cron_expression: Option<String>,
1182 #[serde(default)]
1183 pub time_ranges: Vec<EventWindowTimeRange>,
1184 pub state: String,
1186 #[serde(default)]
1189 pub assoc_instance_ids: Vec<String>,
1190 #[serde(default)]
1191 pub assoc_dedicated_host_ids: Vec<String>,
1192 #[serde(default)]
1193 pub assoc_tags: Vec<Tag>,
1194}
1195
1196#[derive(Clone, Debug, Serialize, Deserialize)]
1198pub struct TrafficMirrorTarget {
1199 pub id: String,
1200 pub network_interface_id: Option<String>,
1201 pub network_load_balancer_arn: Option<String>,
1202 pub gateway_lb_endpoint_id: Option<String>,
1203 pub target_type: String,
1205 pub description: Option<String>,
1206}
1207
1208#[derive(Clone, Debug, Serialize, Deserialize)]
1210pub struct TrafficMirrorFilter {
1211 pub id: String,
1212 pub description: Option<String>,
1213 #[serde(default)]
1214 pub network_services: Vec<String>,
1215}
1216
1217#[derive(Clone, Debug, Serialize, Deserialize)]
1219pub struct TrafficMirrorFilterRule {
1220 pub id: String,
1221 pub filter_id: String,
1222 pub traffic_direction: String,
1223 pub rule_number: i64,
1224 pub rule_action: String,
1225 pub protocol: Option<i64>,
1226 pub destination_cidr_block: Option<String>,
1227 pub source_cidr_block: Option<String>,
1228 pub destination_port_range: Option<(i64, i64)>,
1230 pub source_port_range: Option<(i64, i64)>,
1231 pub description: Option<String>,
1232}
1233
1234#[derive(Clone, Debug, Serialize, Deserialize)]
1236pub struct TrafficMirrorSession {
1237 pub id: String,
1238 pub target_id: String,
1239 pub filter_id: String,
1240 pub network_interface_id: String,
1241 pub packet_length: Option<i64>,
1242 pub session_number: i64,
1243 pub virtual_network_id: Option<i64>,
1244 pub description: Option<String>,
1245}
1246
1247#[derive(Clone, Debug, Serialize, Deserialize)]
1249pub struct RouteServer {
1250 pub id: String,
1251 pub amazon_side_asn: i64,
1252 pub state: String,
1255 pub persist_routes_state: String,
1257 pub persist_routes_duration: Option<i64>,
1258 pub sns_notifications_enabled: bool,
1259}
1260
1261#[derive(Clone, Debug, Serialize, Deserialize)]
1263pub struct VpcEncryptionControl {
1264 pub id: String,
1265 pub vpc_id: String,
1266 pub mode: String,
1268 pub state: String,
1270 #[serde(default)]
1272 pub exclusions: BTreeMap<String, String>,
1273}
1274
1275#[derive(Clone, Debug, Serialize, Deserialize)]
1279pub struct AccountVpcEncryptionControl {
1280 pub mode: String,
1282 pub state: String,
1284 #[serde(default)]
1287 pub exclusions: BTreeMap<String, String>,
1288}
1289
1290impl Default for AccountVpcEncryptionControl {
1291 fn default() -> Self {
1292 Self {
1293 mode: "unmanaged".to_string(),
1294 state: "default-state".to_string(),
1295 exclusions: BTreeMap::new(),
1296 }
1297 }
1298}
1299
1300#[derive(Clone, Debug, Serialize, Deserialize)]
1302pub struct VpcBpaExclusion {
1303 pub id: String,
1304 pub internet_gateway_exclusion_mode: String,
1306 pub resource_arn: Option<String>,
1307 pub state: String,
1309}
1310
1311#[derive(Clone, Debug, Serialize, Deserialize)]
1313pub struct FpgaImage {
1314 pub id: String,
1315 #[serde(default)]
1316 pub name: String,
1317 #[serde(default)]
1318 pub description: String,
1319 #[serde(default)]
1321 pub load_permission_users: Vec<String>,
1322 #[serde(default)]
1324 pub load_permission_groups: Vec<String>,
1325}
1326
1327#[derive(Clone, Debug, Default, Serialize, Deserialize)]
1330pub struct Ec2State {
1331 pub account_id: String,
1332 pub region: String,
1333 #[serde(default)]
1335 pub tags: BTreeMap<String, Vec<Tag>>,
1336 #[serde(default)]
1337 pub vpcs: BTreeMap<String, Vpc>,
1338 #[serde(default)]
1339 pub dhcp_options: BTreeMap<String, DhcpOptions>,
1340 #[serde(default)]
1341 pub subnets: BTreeMap<String, Subnet>,
1342 #[serde(default)]
1343 pub subnet_cidr_reservations: BTreeMap<String, SubnetCidrReservation>,
1344 #[serde(default)]
1345 pub security_groups: BTreeMap<String, SecurityGroup>,
1346 #[serde(default)]
1347 pub route_tables: BTreeMap<String, RouteTable>,
1348 #[serde(default)]
1349 pub internet_gateways: BTreeMap<String, InternetGateway>,
1350 #[serde(default)]
1351 pub egress_only_igws: BTreeMap<String, InternetGateway>,
1352 #[serde(default)]
1353 pub nat_gateways: BTreeMap<String, NatGateway>,
1354 #[serde(default)]
1356 pub elastic_ips: BTreeMap<String, ElasticIp>,
1357 #[serde(default)]
1359 pub key_pairs: BTreeMap<String, KeyPair>,
1360 #[serde(default)]
1362 pub placement_groups: BTreeMap<String, PlacementGroup>,
1363 #[serde(default)]
1364 pub network_interfaces: BTreeMap<String, NetworkInterface>,
1365 #[serde(default)]
1367 pub eni_permissions: BTreeMap<String, NetworkInterfacePermission>,
1368 #[serde(default)]
1369 pub instances: BTreeMap<String, Instance>,
1370 #[serde(default)]
1371 pub volumes: BTreeMap<String, Volume>,
1372 #[serde(default)]
1378 pub recycle_bin_retention: RecycleBinRetention,
1379 #[serde(default)]
1381 pub ebs_encryption_default: bool,
1382 #[serde(default)]
1384 pub ebs_default_kms_key_id: Option<String>,
1385 #[serde(default)]
1386 pub snapshots: BTreeMap<String, Snapshot>,
1387 #[serde(default)]
1389 pub snapshot_block_public_access: String,
1390 #[serde(default)]
1391 pub images: BTreeMap<String, Image>,
1392 #[serde(default)]
1394 pub image_watermarks: BTreeMap<String, BTreeMap<String, String>>,
1395 #[serde(default)]
1397 pub image_block_public_access: String,
1398 #[serde(default)]
1400 pub allowed_images_settings: String,
1401 #[serde(default)]
1405 pub allowed_image_criteria: Vec<Vec<String>>,
1406 #[serde(default)]
1407 pub network_acls: BTreeMap<String, NetworkAcl>,
1408 #[serde(default)]
1409 pub vpc_peerings: BTreeMap<String, VpcPeering>,
1410 #[serde(default)]
1411 pub vpc_endpoints: BTreeMap<String, VpcEndpoint>,
1412 #[serde(default)]
1415 pub account_vpc_encryption_control: Option<AccountVpcEncryptionControl>,
1416 #[serde(default)]
1417 pub endpoint_services: BTreeMap<String, EndpointService>,
1418 #[serde(default)]
1419 pub connection_notifications: BTreeMap<String, ConnectionNotification>,
1420 #[serde(default)]
1421 pub flow_logs: BTreeMap<String, FlowLog>,
1422 #[serde(default)]
1423 pub launch_templates: BTreeMap<String, LaunchTemplate>,
1424 #[serde(default)]
1425 pub spot_requests: BTreeMap<String, SpotRequest>,
1426 #[serde(default)]
1427 pub spot_fleets: BTreeMap<String, SpotFleet>,
1428 #[serde(default)]
1429 pub fleets: BTreeMap<String, Fleet>,
1430 #[serde(default)]
1432 pub spot_datafeed: Option<(String, String)>,
1433 #[serde(default)]
1434 pub capacity_reservations: BTreeMap<String, CapacityReservation>,
1435 #[serde(default)]
1437 pub capacity_reservation_fleets: BTreeMap<String, String>,
1438 #[serde(default)]
1439 pub reserved_instances: BTreeMap<String, ReservedInstances>,
1440 #[serde(default)]
1441 pub reserved_instances_listings: BTreeMap<String, ReservedInstancesListing>,
1442 #[serde(default)]
1443 pub reserved_instances_modifications: BTreeMap<String, ReservedInstancesModification>,
1444 #[serde(default)]
1445 pub dedicated_hosts: BTreeMap<String, DedicatedHost>,
1446 #[serde(default)]
1447 pub transit_gateways: BTreeMap<String, TransitGateway>,
1448 #[serde(default)]
1449 pub tgw_attachments: BTreeMap<String, TgwAttachment>,
1450 #[serde(default)]
1451 pub tgw_route_tables: BTreeMap<String, TgwRouteTable>,
1452 #[serde(default)]
1454 pub tgw_routes: BTreeMap<String, Vec<TgwRoute>>,
1455 #[serde(default)]
1457 pub tgw_rt_associations: BTreeMap<String, Vec<String>>,
1458 #[serde(default)]
1460 pub tgw_rt_propagations: BTreeMap<String, Vec<String>>,
1461 #[serde(default)]
1463 pub tgw_prefix_list_refs: BTreeMap<String, Vec<String>>,
1464 #[serde(default)]
1465 pub tgw_peerings: BTreeMap<String, TgwPeering>,
1466 #[serde(default)]
1468 pub tgw_connects: BTreeMap<String, (String, String)>,
1469 #[serde(default)]
1471 pub tgw_connect_peers: BTreeMap<String, String>,
1472 #[serde(default)]
1474 pub tgw_policy_tables: BTreeMap<String, String>,
1475 #[serde(default)]
1477 pub tgw_policy_table_associations: BTreeMap<String, Vec<String>>,
1478 #[serde(default)]
1480 pub tgw_announcements: BTreeMap<String, (String, String)>,
1481 #[serde(default)]
1482 pub tgw_multicast_domains: BTreeMap<String, TgwMulticastDomain>,
1483 #[serde(default)]
1484 pub tgw_metering_policies: BTreeMap<String, TgwMeteringPolicy>,
1485 #[serde(default)]
1486 pub customer_gateways: BTreeMap<String, CustomerGateway>,
1487 #[serde(default)]
1488 pub vpn_gateways: BTreeMap<String, VpnGateway>,
1489 #[serde(default)]
1490 pub vpn_connections: BTreeMap<String, VpnConnection>,
1491 #[serde(default)]
1492 pub vpn_concentrators: BTreeMap<String, VpnConcentrator>,
1493 #[serde(default)]
1494 pub client_vpn_endpoints: BTreeMap<String, ClientVpnEndpoint>,
1495 #[serde(default)]
1496 pub ipams: BTreeMap<String, Ipam>,
1497 #[serde(default)]
1498 pub ipam_scopes: BTreeMap<String, IpamScope>,
1499 #[serde(default)]
1500 pub ipam_pools: BTreeMap<String, IpamPool>,
1501 #[serde(default)]
1503 pub ipam_pool_cidrs: BTreeMap<String, Vec<(String, String)>>,
1504 #[serde(default)]
1506 pub ipam_pool_allocations: BTreeMap<String, Vec<(String, String)>>,
1507 #[serde(default)]
1508 pub ipam_resource_discoveries: BTreeMap<String, IpamResourceDiscovery>,
1509 #[serde(default)]
1511 pub ipam_rd_associations: BTreeMap<String, (String, String)>,
1512 #[serde(default)]
1514 pub ipam_byoasns: BTreeMap<String, String>,
1515 #[serde(default)]
1517 pub ipam_ext_tokens: BTreeMap<String, String>,
1518 #[serde(default)]
1519 pub ipam_policies: BTreeMap<String, IpamPolicy>,
1520 #[serde(default)]
1521 pub ipam_pl_resolvers: BTreeMap<String, IpamPrefixListResolver>,
1522 #[serde(default)]
1523 pub ipam_pl_resolver_targets: BTreeMap<String, IpamPrefixListResolverTarget>,
1524 #[serde(default)]
1526 pub ipam_policy_alloc_rules: BTreeMap<String, Vec<(String, String)>>,
1527 #[serde(default)]
1529 pub ipam_enabled_policy: Option<String>,
1530 #[serde(default)]
1531 pub va_instances: BTreeMap<String, VerifiedAccessInstance>,
1532 #[serde(default)]
1533 pub va_trust_providers: BTreeMap<String, VerifiedAccessTrustProvider>,
1534 #[serde(default)]
1535 pub va_groups: BTreeMap<String, VerifiedAccessGroup>,
1536 #[serde(default)]
1537 pub va_endpoints: BTreeMap<String, VerifiedAccessEndpoint>,
1538 #[serde(default)]
1540 pub va_group_policies: BTreeMap<String, String>,
1541 #[serde(default)]
1543 pub va_endpoint_policies: BTreeMap<String, String>,
1544 #[serde(default)]
1545 pub ni_paths: BTreeMap<String, NetworkInsightsPath>,
1546 #[serde(default)]
1547 pub ni_analyses: BTreeMap<String, NetworkInsightsAnalysis>,
1548 #[serde(default)]
1549 pub ni_access_scopes: BTreeMap<String, NetworkInsightsAccessScope>,
1550 #[serde(default)]
1551 pub ni_scope_analyses: BTreeMap<String, NetworkInsightsAccessScopeAnalysis>,
1552 #[serde(default)]
1553 pub carrier_gateways: BTreeMap<String, CarrierGateway>,
1554 #[serde(default)]
1555 pub coip_pools: BTreeMap<String, CoipPool>,
1556 #[serde(default)]
1558 pub coip_pool_cidrs: BTreeMap<String, Vec<String>>,
1559 #[serde(default)]
1560 pub lg_route_tables: BTreeMap<String, LocalGatewayRouteTable>,
1561 #[serde(default)]
1563 pub lg_routes: BTreeMap<String, Vec<String>>,
1564 #[serde(default)]
1565 pub lg_rt_vpc_assocs: BTreeMap<String, LocalGatewayRouteTableVpcAssoc>,
1566 #[serde(default)]
1567 pub lg_virtual_interfaces: BTreeMap<String, LocalGatewayVif>,
1568 #[serde(default)]
1569 pub lg_vif_groups: BTreeMap<String, LocalGatewayVifGroup>,
1570 #[serde(default)]
1571 pub lg_rt_vifg_assocs: BTreeMap<String, LocalGatewayRouteTableVifgAssoc>,
1572 #[serde(default)]
1573 pub instance_connect_endpoints: BTreeMap<String, InstanceConnectEndpoint>,
1574 #[serde(default)]
1576 pub fast_launch_images: std::collections::HashSet<String>,
1577 #[serde(default)]
1578 pub serial_console_access: bool,
1579 #[serde(default)]
1582 pub id_format: BTreeMap<String, bool>,
1583 #[serde(default)]
1585 pub identity_id_format: BTreeMap<String, BTreeMap<String, bool>>,
1586 #[serde(default)]
1589 pub default_credit_specs: BTreeMap<String, String>,
1590 #[serde(default)]
1593 pub instance_credit_specs: BTreeMap<String, String>,
1594 #[serde(default)]
1597 pub instance_metadata_defaults: Option<InstanceMetadataDefaults>,
1598 #[serde(default)]
1601 pub event_notification_tag_keys: Vec<String>,
1602 #[serde(default)]
1605 pub event_notification_include_all_tags: bool,
1606 #[serde(default)]
1609 pub vpc_bpa_internet_gateway_block_mode: Option<String>,
1610 #[serde(default)]
1613 pub managed_resource_default_visibility: Option<String>,
1614 #[serde(default)]
1617 pub az_group_optin: BTreeMap<String, String>,
1618 #[serde(default)]
1619 pub managed_prefix_lists: BTreeMap<String, ManagedPrefixList>,
1620 #[serde(default)]
1621 pub instance_event_windows: BTreeMap<String, InstanceEventWindow>,
1622 #[serde(default)]
1623 pub traffic_mirror_targets: BTreeMap<String, TrafficMirrorTarget>,
1624 #[serde(default)]
1625 pub traffic_mirror_filters: BTreeMap<String, TrafficMirrorFilter>,
1626 #[serde(default)]
1627 pub traffic_mirror_filter_rules: BTreeMap<String, TrafficMirrorFilterRule>,
1628 #[serde(default)]
1629 pub traffic_mirror_sessions: BTreeMap<String, TrafficMirrorSession>,
1630 #[serde(default)]
1631 pub route_servers: BTreeMap<String, RouteServer>,
1632 #[serde(default)]
1633 pub vpc_encryption_controls: BTreeMap<String, VpcEncryptionControl>,
1634 #[serde(default)]
1635 pub vpc_bpa_exclusions: BTreeMap<String, VpcBpaExclusion>,
1636 #[serde(default)]
1637 pub fpga_images: BTreeMap<String, FpgaImage>,
1638 #[serde(default)]
1641 pub ipam_allocation_descriptions: BTreeMap<String, String>,
1642}
1643
1644impl Ec2State {
1645 pub fn new(account_id: &str, region: &str) -> Self {
1646 let mut state = Self {
1647 account_id: account_id.to_string(),
1648 region: region.to_string(),
1649 ..Default::default()
1650 };
1651 crate::defaults::bootstrap_default_network(&mut state);
1657 crate::defaults::seed_public_images(&mut state);
1661 state
1662 }
1663
1664 pub fn ensure_public_images_seeded(&mut self) {
1670 crate::defaults::seed_public_images(self);
1671 }
1672
1673 pub fn upsert_tags(&mut self, resource_id: &str, new_tags: &[Tag]) {
1676 let entry = self.tags.entry(resource_id.to_string()).or_default();
1677 for t in new_tags {
1678 if let Some(existing) = entry.iter_mut().find(|e| e.key == t.key) {
1679 existing.value = t.value.clone();
1680 } else {
1681 entry.push(t.clone());
1682 }
1683 }
1684 }
1685
1686 pub fn remove_tags(&mut self, resource_id: &str, to_remove: &[(String, Option<String>)]) {
1690 if let Some(entry) = self.tags.get_mut(resource_id) {
1691 for (key, value) in to_remove {
1692 entry.retain(|e| {
1693 if &e.key != key {
1694 return true;
1695 }
1696 match value {
1697 Some(v) => &e.value != v,
1698 None => false,
1699 }
1700 });
1701 }
1702 if entry.is_empty() {
1703 self.tags.remove(resource_id);
1704 }
1705 }
1706 }
1707
1708 pub fn tags_for(&self, resource_id: &str) -> &[Tag] {
1710 self.tags.get(resource_id).map(Vec::as_slice).unwrap_or(&[])
1711 }
1712}
1713
1714#[cfg(test)]
1715mod tests {
1716 use super::*;
1717
1718 fn tag(k: &str, v: &str) -> Tag {
1719 Tag {
1720 key: k.to_string(),
1721 value: v.to_string(),
1722 }
1723 }
1724
1725 #[test]
1726 fn upsert_tags_inserts_then_overwrites_by_key() {
1727 let mut s = Ec2State::new("123456789012", "us-east-1");
1728 s.upsert_tags("vpc-1", &[tag("Name", "a"), tag("env", "dev")]);
1729 s.upsert_tags("vpc-1", &[tag("Name", "b")]);
1730 let tags = s.tags_for("vpc-1");
1731 assert_eq!(tags.len(), 2);
1732 assert_eq!(tags.iter().find(|t| t.key == "Name").unwrap().value, "b");
1733 }
1734
1735 #[test]
1736 fn remove_tags_by_key_and_by_key_value() {
1737 let mut s = Ec2State::new("123456789012", "us-east-1");
1738 s.upsert_tags(
1739 "i-1",
1740 &[tag("Name", "x"), tag("env", "prod"), tag("team", "a")],
1741 );
1742 s.remove_tags("i-1", &[("Name".to_string(), None)]);
1744 s.remove_tags("i-1", &[("env".to_string(), Some("dev".to_string()))]);
1746 s.remove_tags("i-1", &[("team".to_string(), Some("a".to_string()))]);
1748 let tags = s.tags_for("i-1");
1749 assert_eq!(tags.len(), 1);
1750 assert_eq!(tags[0].key, "env");
1751 }
1752
1753 #[test]
1754 fn empty_tag_set_drops_resource_entry() {
1755 let mut s = Ec2State::new("123456789012", "us-east-1");
1756 s.upsert_tags("sg-1", &[tag("Name", "x")]);
1757 s.remove_tags("sg-1", &[("Name".to_string(), None)]);
1758 assert!(!s.tags.contains_key("sg-1"));
1759 }
1760
1761 fn sample_instance() -> Instance {
1762 Instance {
1763 instance_id: "i-1".to_string(),
1764 image_id: "ami-1".to_string(),
1765 instance_type: "t3.micro".to_string(),
1766 state_code: 16,
1767 state_name: "running".to_string(),
1768 private_ip: "10.0.0.1".to_string(),
1769 public_ip: Some("52.0.0.1".to_string()),
1770 subnet_id: Some("subnet-1".to_string()),
1771 vpc_id: Some("vpc-1".to_string()),
1772 key_name: None,
1773 security_group_ids: vec!["sg-1".to_string()],
1774 reservation_id: "r-1".to_string(),
1775 ami_launch_index: 0,
1776 monitoring: false,
1777 az: "us-east-1a".to_string(),
1778 launch_time: "2024-01-01T00:00:00.000Z".to_string(),
1779 container_id: Some("abc".to_string()),
1780 disable_api_termination: true,
1781 disable_api_stop: true,
1782 source_dest_check: false,
1783 ebs_optimized: true,
1784 instance_initiated_shutdown_behavior: "terminate".to_string(),
1785 user_data: Some("ZWNobyBoaQ==".to_string()),
1786 metadata_options: MetadataOptions {
1787 http_tokens: "required".to_string(),
1788 ..MetadataOptions::default()
1789 },
1790 cpu_options: Some(CpuOptions {
1791 core_count: 4,
1792 threads_per_core: 2,
1793 }),
1794 bandwidth_weighting: Some("vpc-1".to_string()),
1795 maintenance_options: MaintenanceOptions::default(),
1796 placement_tenancy: Some("dedicated".to_string()),
1797 placement_affinity: None,
1798 placement_group_name: Some("cluster-1".to_string()),
1799 private_dns_hostname_type: Some("resource-name".to_string()),
1800 enable_resource_name_dns_a_record: true,
1801 enable_resource_name_dns_aaaa_record: false,
1802 }
1803 }
1804
1805 #[test]
1806 fn instance_attributes_round_trip_through_serde() {
1807 let inst = sample_instance();
1808 let json = serde_json::to_string(&inst).unwrap();
1809 let back: Instance = serde_json::from_str(&json).unwrap();
1810 assert!(back.disable_api_termination);
1811 assert!(back.disable_api_stop);
1812 assert!(!back.source_dest_check);
1813 assert!(back.ebs_optimized);
1814 assert_eq!(back.instance_initiated_shutdown_behavior, "terminate");
1815 assert_eq!(back.user_data.as_deref(), Some("ZWNobyBoaQ=="));
1816 assert_eq!(back.metadata_options.http_tokens, "required");
1817 assert_eq!(back.cpu_options.as_ref().unwrap().core_count, 4);
1818 assert_eq!(back.bandwidth_weighting.as_deref(), Some("vpc-1"));
1819 assert_eq!(back.placement_tenancy.as_deref(), Some("dedicated"));
1820 assert_eq!(back.placement_group_name.as_deref(), Some("cluster-1"));
1821 }
1822
1823 #[test]
1824 fn instance_attribute_defaults_load_from_legacy_snapshot() {
1825 let legacy = r#"{
1828 "instance_id":"i-1","image_id":"ami-1","instance_type":"t3.micro",
1829 "state_code":16,"state_name":"running","private_ip":"10.0.0.1",
1830 "public_ip":null,"subnet_id":null,"vpc_id":null,"key_name":null,
1831 "reservation_id":"r-1","ami_launch_index":0,"monitoring":false,
1832 "az":"us-east-1a","launch_time":"2024-01-01T00:00:00.000Z"
1833 }"#;
1834 let inst: Instance = serde_json::from_str(legacy).unwrap();
1835 assert!(!inst.disable_api_termination);
1836 assert!(inst.source_dest_check, "sourceDestCheck defaults to true");
1837 assert_eq!(inst.instance_initiated_shutdown_behavior, "stop");
1838 assert_eq!(inst.metadata_options.http_tokens, "optional");
1839 assert!(inst.cpu_options.is_none());
1840 }
1841}