Skip to main content

fakecloud_ec2/service/
mod.rs

1//! EC2 service entrypoint: `ec2Query` dispatch over the per-account state.
2
3mod capacity;
4mod cvpn;
5mod dhcp;
6mod eip;
7mod endpoint;
8mod eni;
9mod firewall_model;
10mod fleet;
11mod ice;
12mod image;
13pub(crate) mod instance;
14mod ipam;
15mod ipam_discovery;
16mod ipam_policy;
17mod lgw;
18mod meta;
19mod nacl;
20mod ni;
21mod reserved;
22mod rest;
23mod routing;
24mod sg;
25mod snapshot;
26mod subnet;
27mod tags;
28mod tgw;
29mod tgw_mcast;
30mod tgw_peering;
31mod va;
32mod volume;
33mod vpc;
34mod vpn;
35
36use async_trait::async_trait;
37use http::StatusCode;
38use parking_lot::RwLock;
39use std::sync::Arc;
40
41use tokio::sync::Mutex as AsyncMutex;
42
43use fakecloud_core::multi_account::MultiAccountState;
44use fakecloud_core::service::{AwsRequest, AwsResponse, AwsService, AwsServiceError};
45use fakecloud_persistence::SnapshotStore;
46
47use crate::runtime::Ec2Runtime;
48use crate::state::{Ec2Snapshot, SharedEc2State, EC2_SNAPSHOT_SCHEMA_VERSION};
49
50/// EC2 read actions all start with `Describe`, `Get`, `Search`, or `List`;
51/// every other action mutates state. The inverse formulation guarantees no
52/// mutation is ever missed, and the hot-path reads (Describe*) are excluded so
53/// polling never triggers a snapshot write.
54fn is_mutating_action(action: &str) -> bool {
55    !(action.starts_with("Describe")
56        || action.starts_with("Get")
57        || action.starts_with("Search")
58        || action.starts_with("List"))
59}
60
61/// Every EC2 action this build implements. The conformance audit cross-checks
62/// this list against the handwritten `#[test_action("ec2", …)]` tests, so an
63/// action added here without a test fails the build. Grows one resource-family
64/// batch at a time toward full 767-op parity.
65pub const SUPPORTED_ACTIONS: &[&str] = &[
66    // Tagging subsystem (shared by every resource family)
67    "CreateTags",
68    "DeleteTags",
69    "DescribeTags",
70    // Region / AZ / account describe primitives
71    "DescribeRegions",
72    "DescribeAvailabilityZones",
73    "DescribeAccountAttributes",
74    // VPCs
75    "CreateVpc",
76    "CreateDefaultVpc",
77    "DeleteVpc",
78    "DescribeVpcs",
79    "ModifyVpcAttribute",
80    "DescribeVpcAttribute",
81    "ModifyVpcTenancy",
82    "AssociateVpcCidrBlock",
83    "DisassociateVpcCidrBlock",
84    // DHCP options
85    "CreateDhcpOptions",
86    "DeleteDhcpOptions",
87    "DescribeDhcpOptions",
88    "AssociateDhcpOptions",
89    // Subnets
90    "CreateSubnet",
91    "CreateDefaultSubnet",
92    "CreateSecondarySubnet",
93    "DeleteSubnet",
94    "DeleteSecondarySubnet",
95    "DescribeSubnets",
96    "DescribeSecondarySubnets",
97    "ModifySubnetAttribute",
98    "AssociateSubnetCidrBlock",
99    "DisassociateSubnetCidrBlock",
100    "CreateSubnetCidrReservation",
101    "DeleteSubnetCidrReservation",
102    "GetSubnetCidrReservations",
103    // Security groups
104    "CreateSecurityGroup",
105    "DeleteSecurityGroup",
106    "DescribeSecurityGroups",
107    "AuthorizeSecurityGroupIngress",
108    "AuthorizeSecurityGroupEgress",
109    "RevokeSecurityGroupIngress",
110    "RevokeSecurityGroupEgress",
111    "DescribeSecurityGroupRules",
112    "ModifySecurityGroupRules",
113    "UpdateSecurityGroupRuleDescriptionsIngress",
114    "UpdateSecurityGroupRuleDescriptionsEgress",
115    "AssociateSecurityGroupVpc",
116    "DisassociateSecurityGroupVpc",
117    "DescribeSecurityGroupVpcAssociations",
118    "GetSecurityGroupsForVpc",
119    "DescribeStaleSecurityGroups",
120    "DescribeSecurityGroupReferences",
121    // Route tables
122    "CreateRouteTable",
123    "DeleteRouteTable",
124    "DescribeRouteTables",
125    "CreateRoute",
126    "DeleteRoute",
127    "ReplaceRoute",
128    "AssociateRouteTable",
129    "DisassociateRouteTable",
130    "ReplaceRouteTableAssociation",
131    // Internet gateways
132    "CreateInternetGateway",
133    "DeleteInternetGateway",
134    "DescribeInternetGateways",
135    "AttachInternetGateway",
136    "DetachInternetGateway",
137    // Egress-only internet gateways
138    "CreateEgressOnlyInternetGateway",
139    "DeleteEgressOnlyInternetGateway",
140    "DescribeEgressOnlyInternetGateways",
141    // NAT gateways
142    "CreateNatGateway",
143    "DeleteNatGateway",
144    "DescribeNatGateways",
145    "AssignPrivateNatGatewayAddress",
146    "AssociateNatGatewayAddress",
147    "DisassociateNatGatewayAddress",
148    "UnassignPrivateNatGatewayAddress",
149    // Elastic IPs
150    "AllocateAddress",
151    "ReleaseAddress",
152    "DescribeAddresses",
153    "AssociateAddress",
154    "DisassociateAddress",
155    "DescribeAddressesAttribute",
156    "ModifyAddressAttribute",
157    "ResetAddressAttribute",
158    "MoveAddressToVpc",
159    "RestoreAddressToClassic",
160    "AcceptAddressTransfer",
161    "EnableAddressTransfer",
162    "DisableAddressTransfer",
163    "DescribeAddressTransfers",
164    "DescribeMovingAddresses",
165    // Key pairs
166    "CreateKeyPair",
167    "ImportKeyPair",
168    "DeleteKeyPair",
169    "DescribeKeyPairs",
170    // Placement groups
171    "CreatePlacementGroup",
172    "DeletePlacementGroup",
173    "DescribePlacementGroups",
174    "GetGroupsForCapacityReservation",
175    // Network interfaces
176    "CreateNetworkInterface",
177    "DeleteNetworkInterface",
178    "DescribeNetworkInterfaces",
179    "AttachNetworkInterface",
180    "DetachNetworkInterface",
181    "ModifyNetworkInterfaceAttribute",
182    "ResetNetworkInterfaceAttribute",
183    "DescribeNetworkInterfaceAttribute",
184    "CreateNetworkInterfacePermission",
185    "DeleteNetworkInterfacePermission",
186    "DescribeNetworkInterfacePermissions",
187    "AssignPrivateIpAddresses",
188    "UnassignPrivateIpAddresses",
189    "AssignIpv6Addresses",
190    "UnassignIpv6Addresses",
191    // Instances
192    "RunInstances",
193    "StartInstances",
194    "StopInstances",
195    "RebootInstances",
196    "TerminateInstances",
197    "MonitorInstances",
198    "UnmonitorInstances",
199    "DescribeInstances",
200    "DescribeInstanceStatus",
201    "DescribeInstanceTypes",
202    "GetInstanceTypesFromInstanceRequirements",
203    "DescribeInstanceAttribute",
204    "ModifyInstanceAttribute",
205    "ResetInstanceAttribute",
206    "ModifyInstancePlacement",
207    "ModifyInstanceMetadataOptions",
208    "ModifyInstanceMaintenanceOptions",
209    "ModifyInstanceCpuOptions",
210    "ModifyInstanceNetworkPerformanceOptions",
211    "ModifyInstanceEventStartTime",
212    "DescribeInstanceCreditSpecifications",
213    "ModifyInstanceCreditSpecification",
214    "GetInstanceMetadataDefaults",
215    "ModifyInstanceMetadataDefaults",
216    "RegisterInstanceEventNotificationAttributes",
217    "DeregisterInstanceEventNotificationAttributes",
218    "DescribeInstanceEventNotificationAttributes",
219    "ReportInstanceStatus",
220    "DescribeInstanceTopology",
221    // EBS volumes
222    "CreateVolume",
223    "DeleteVolume",
224    "DescribeVolumes",
225    "AttachVolume",
226    "DetachVolume",
227    "ModifyVolume",
228    "DescribeVolumesModifications",
229    "DescribeVolumeStatus",
230    "DescribeVolumeAttribute",
231    "ModifyVolumeAttribute",
232    "EnableVolumeIO",
233    "ListVolumesInRecycleBin",
234    "RestoreVolumeFromRecycleBin",
235    // EBS encryption defaults
236    "GetEbsEncryptionByDefault",
237    "EnableEbsEncryptionByDefault",
238    "DisableEbsEncryptionByDefault",
239    "GetEbsDefaultKmsKeyId",
240    "ModifyEbsDefaultKmsKeyId",
241    "ResetEbsDefaultKmsKeyId",
242    // EBS snapshots
243    "CreateSnapshot",
244    "CreateSnapshots",
245    "DeleteSnapshot",
246    "DescribeSnapshots",
247    "CopySnapshot",
248    "DescribeSnapshotAttribute",
249    "ModifySnapshotAttribute",
250    "ResetSnapshotAttribute",
251    "ModifySnapshotTier",
252    "DescribeSnapshotTierStatus",
253    "RestoreSnapshotTier",
254    "ListSnapshotsInRecycleBin",
255    "RestoreSnapshotFromRecycleBin",
256    "LockSnapshot",
257    "UnlockSnapshot",
258    "DescribeLockedSnapshots",
259    "GetSnapshotBlockPublicAccessState",
260    "EnableSnapshotBlockPublicAccess",
261    "DisableSnapshotBlockPublicAccess",
262    "EnableFastSnapshotRestores",
263    "DisableFastSnapshotRestores",
264    "DescribeFastSnapshotRestores",
265    // AMIs (images)
266    "CreateImage",
267    "RegisterImage",
268    "DeregisterImage",
269    "DescribeImages",
270    "CopyImage",
271    "DescribeImageAttribute",
272    "ModifyImageAttribute",
273    "ResetImageAttribute",
274    "EnableImage",
275    "DisableImage",
276    "AttachImageWatermark",
277    "DetachImageWatermark",
278    "EnableImageDeprecation",
279    "DisableImageDeprecation",
280    "EnableImageDeregistrationProtection",
281    "DisableImageDeregistrationProtection",
282    "CancelImageLaunchPermission",
283    "RestoreImageFromRecycleBin",
284    "ListImagesInRecycleBin",
285    "EnableImageBlockPublicAccess",
286    "DisableImageBlockPublicAccess",
287    "GetImageBlockPublicAccessState",
288    "EnableAllowedImagesSettings",
289    "DisableAllowedImagesSettings",
290    "GetAllowedImagesSettings",
291    "ReplaceImageCriteriaInAllowedImagesSettings",
292    "CreateStoreImageTask",
293    "DescribeStoreImageTasks",
294    "CreateRestoreImageTask",
295    "DescribeFastLaunchImages",
296    // Network ACLs
297    "CreateNetworkAcl",
298    "DeleteNetworkAcl",
299    "DescribeNetworkAcls",
300    "CreateNetworkAclEntry",
301    "DeleteNetworkAclEntry",
302    "ReplaceNetworkAclEntry",
303    "ReplaceNetworkAclAssociation",
304    // VPC peering
305    "CreateVpcPeeringConnection",
306    "DeleteVpcPeeringConnection",
307    "DescribeVpcPeeringConnections",
308    "AcceptVpcPeeringConnection",
309    "RejectVpcPeeringConnection",
310    "ModifyVpcPeeringConnectionOptions",
311    // VPC endpoints
312    "CreateVpcEndpoint",
313    "DeleteVpcEndpoints",
314    "DescribeVpcEndpoints",
315    "ModifyVpcEndpoint",
316    "DescribeVpcEndpointServices",
317    "DescribeVpcEndpointConnections",
318    "AcceptVpcEndpointConnections",
319    "RejectVpcEndpointConnections",
320    "CreateVpcEndpointServiceConfiguration",
321    "DeleteVpcEndpointServiceConfigurations",
322    "DescribeVpcEndpointServiceConfigurations",
323    "ModifyVpcEndpointServiceConfiguration",
324    "DescribeVpcEndpointServicePermissions",
325    "ModifyVpcEndpointServicePermissions",
326    "ModifyVpcEndpointServicePayerResponsibility",
327    "StartVpcEndpointServicePrivateDnsVerification",
328    "CreateVpcEndpointConnectionNotification",
329    "DeleteVpcEndpointConnectionNotifications",
330    "DescribeVpcEndpointConnectionNotifications",
331    "ModifyVpcEndpointConnectionNotification",
332    "DescribeVpcEndpointAssociations",
333    // Flow logs
334    "CreateFlowLogs",
335    "DeleteFlowLogs",
336    "DescribeFlowLogs",
337    "GetFlowLogsIntegrationTemplate",
338    // Launch templates
339    "CreateLaunchTemplate",
340    "CreateLaunchTemplateVersion",
341    "DeleteLaunchTemplate",
342    "DeleteLaunchTemplateVersions",
343    "DescribeLaunchTemplates",
344    "DescribeLaunchTemplateVersions",
345    "GetLaunchTemplateData",
346    "ModifyLaunchTemplate",
347    // Spot instances + fleet
348    "RequestSpotInstances",
349    "DescribeSpotInstanceRequests",
350    "CancelSpotInstanceRequests",
351    "RequestSpotFleet",
352    "DescribeSpotFleetRequests",
353    "CancelSpotFleetRequests",
354    "ModifySpotFleetRequest",
355    "DescribeSpotFleetInstances",
356    "DescribeSpotFleetRequestHistory",
357    "DescribeSpotPriceHistory",
358    "GetSpotPlacementScores",
359    "CreateSpotDatafeedSubscription",
360    "DeleteSpotDatafeedSubscription",
361    "DescribeSpotDatafeedSubscription",
362    // EC2 fleets
363    "CreateFleet",
364    "DeleteFleets",
365    "DescribeFleets",
366    "ModifyFleet",
367    "DescribeFleetHistory",
368    "DescribeFleetInstances",
369    // Capacity reservations
370    "CreateCapacityReservation",
371    "CancelCapacityReservation",
372    "DescribeCapacityReservations",
373    "ModifyCapacityReservation",
374    "GetCapacityReservationUsage",
375    "CreateCapacityReservationFleet",
376    "CancelCapacityReservationFleets",
377    "DescribeCapacityReservationFleets",
378    "ModifyCapacityReservationFleet",
379    "ModifyInstanceCapacityReservationAttributes",
380    "CreateCapacityReservationBySplitting",
381    "MoveCapacityReservationInstances",
382    "DescribeCapacityReservationBillingRequests",
383    "AssociateCapacityReservationBillingOwner",
384    "DisassociateCapacityReservationBillingOwner",
385    "AcceptCapacityReservationBillingOwnership",
386    "RejectCapacityReservationBillingOwnership",
387    "DescribeCapacityBlockOfferings",
388    "DescribeCapacityBlocks",
389    "PurchaseCapacityBlock",
390    "DescribeCapacityBlockStatus",
391    "DescribeCapacityBlockExtensionHistory",
392    "DescribeCapacityBlockExtensionOfferings",
393    "PurchaseCapacityBlockExtension",
394    "DescribeCapacityReservationTopology",
395    "CreateInterruptibleCapacityReservationAllocation",
396    "UpdateInterruptibleCapacityReservationAllocation",
397    // Reserved instances
398    "DescribeReservedInstances",
399    "DescribeReservedInstancesOfferings",
400    "PurchaseReservedInstancesOffering",
401    "DescribeReservedInstancesListings",
402    "CreateReservedInstancesListing",
403    "CancelReservedInstancesListing",
404    "DescribeReservedInstancesModifications",
405    "ModifyReservedInstances",
406    "GetReservedInstancesExchangeQuote",
407    "AcceptReservedInstancesExchangeQuote",
408    "DeleteQueuedReservedInstances",
409    // Dedicated hosts
410    "AllocateHosts",
411    "DescribeHosts",
412    "ModifyHosts",
413    "ReleaseHosts",
414    "DescribeMacHosts",
415    // Transit gateway core
416    "CreateTransitGateway",
417    "DeleteTransitGateway",
418    "DescribeTransitGateways",
419    "ModifyTransitGateway",
420    "CreateTransitGatewayVpcAttachment",
421    "DeleteTransitGatewayVpcAttachment",
422    "DescribeTransitGatewayVpcAttachments",
423    "ModifyTransitGatewayVpcAttachment",
424    "AcceptTransitGatewayVpcAttachment",
425    "RejectTransitGatewayVpcAttachment",
426    "DescribeTransitGatewayAttachments",
427    "CreateTransitGatewayRouteTable",
428    "DeleteTransitGatewayRouteTable",
429    "DescribeTransitGatewayRouteTables",
430    "AssociateTransitGatewayRouteTable",
431    "DisassociateTransitGatewayRouteTable",
432    "EnableTransitGatewayRouteTablePropagation",
433    "DisableTransitGatewayRouteTablePropagation",
434    "CreateTransitGatewayRoute",
435    "DeleteTransitGatewayRoute",
436    "ReplaceTransitGatewayRoute",
437    "SearchTransitGatewayRoutes",
438    "ExportTransitGatewayRoutes",
439    "GetTransitGatewayRouteTableAssociations",
440    "GetTransitGatewayRouteTablePropagations",
441    "GetTransitGatewayAttachmentPropagations",
442    "CreateTransitGatewayPrefixListReference",
443    "DeleteTransitGatewayPrefixListReference",
444    "ModifyTransitGatewayPrefixListReference",
445    "GetTransitGatewayPrefixListReferences",
446    // Transit gateway peering / connect / policy / announcements
447    "CreateTransitGatewayPeeringAttachment",
448    "DeleteTransitGatewayPeeringAttachment",
449    "DescribeTransitGatewayPeeringAttachments",
450    "AcceptTransitGatewayPeeringAttachment",
451    "RejectTransitGatewayPeeringAttachment",
452    "CreateTransitGatewayConnect",
453    "DeleteTransitGatewayConnect",
454    "DescribeTransitGatewayConnects",
455    "CreateTransitGatewayConnectPeer",
456    "DeleteTransitGatewayConnectPeer",
457    "DescribeTransitGatewayConnectPeers",
458    "CreateTransitGatewayPolicyTable",
459    "DeleteTransitGatewayPolicyTable",
460    "DescribeTransitGatewayPolicyTables",
461    "AssociateTransitGatewayPolicyTable",
462    "DisassociateTransitGatewayPolicyTable",
463    "GetTransitGatewayPolicyTableAssociations",
464    "GetTransitGatewayPolicyTableEntries",
465    "CreateTransitGatewayRouteTableAnnouncement",
466    "DeleteTransitGatewayRouteTableAnnouncement",
467    "DescribeTransitGatewayRouteTableAnnouncements",
468    // Transit gateway multicast / metering / client-vpn-attach
469    "CreateTransitGatewayMulticastDomain",
470    "DeleteTransitGatewayMulticastDomain",
471    "DescribeTransitGatewayMulticastDomains",
472    "AssociateTransitGatewayMulticastDomain",
473    "DisassociateTransitGatewayMulticastDomain",
474    "AcceptTransitGatewayMulticastDomainAssociations",
475    "RejectTransitGatewayMulticastDomainAssociations",
476    "GetTransitGatewayMulticastDomainAssociations",
477    "RegisterTransitGatewayMulticastGroupMembers",
478    "RegisterTransitGatewayMulticastGroupSources",
479    "DeregisterTransitGatewayMulticastGroupMembers",
480    "DeregisterTransitGatewayMulticastGroupSources",
481    "SearchTransitGatewayMulticastGroups",
482    "CreateTransitGatewayMeteringPolicy",
483    "DeleteTransitGatewayMeteringPolicy",
484    "DescribeTransitGatewayMeteringPolicies",
485    "ModifyTransitGatewayMeteringPolicy",
486    "CreateTransitGatewayMeteringPolicyEntry",
487    "DeleteTransitGatewayMeteringPolicyEntry",
488    "GetTransitGatewayMeteringPolicyEntries",
489    "AcceptTransitGatewayClientVpnAttachment",
490    "DeleteTransitGatewayClientVpnAttachment",
491    "RejectTransitGatewayClientVpnAttachment",
492    // Site-to-Site VPN
493    "CreateCustomerGateway",
494    "DeleteCustomerGateway",
495    "DescribeCustomerGateways",
496    "CreateVpnGateway",
497    "DeleteVpnGateway",
498    "DescribeVpnGateways",
499    "AttachVpnGateway",
500    "DetachVpnGateway",
501    "CreateVpnConnection",
502    "DeleteVpnConnection",
503    "DescribeVpnConnections",
504    "ModifyVpnConnection",
505    "ModifyVpnConnectionOptions",
506    "CreateVpnConnectionRoute",
507    "DeleteVpnConnectionRoute",
508    "ModifyVpnTunnelOptions",
509    "ModifyVpnTunnelCertificate",
510    "ReplaceVpnTunnel",
511    "GetActiveVpnTunnelStatus",
512    "GetVpnTunnelReplacementStatus",
513    "GetVpnConnectionDeviceTypes",
514    "GetVpnConnectionDeviceSampleConfiguration",
515    "CreateVpnConcentrator",
516    "DeleteVpnConcentrator",
517    "DescribeVpnConcentrators",
518    // Client VPN
519    "CreateClientVpnEndpoint",
520    "DeleteClientVpnEndpoint",
521    "DescribeClientVpnEndpoints",
522    "ModifyClientVpnEndpoint",
523    "CreateClientVpnRoute",
524    "DeleteClientVpnRoute",
525    "DescribeClientVpnRoutes",
526    "AuthorizeClientVpnIngress",
527    "RevokeClientVpnIngress",
528    "DescribeClientVpnAuthorizationRules",
529    "AssociateClientVpnTargetNetwork",
530    "DisassociateClientVpnTargetNetwork",
531    "DescribeClientVpnTargetNetworks",
532    "ApplySecurityGroupsToClientVpnTargetNetwork",
533    "DescribeClientVpnConnections",
534    "TerminateClientVpnConnections",
535    "ExportClientVpnClientCertificateRevocationList",
536    "ExportClientVpnClientConfiguration",
537    "ImportClientVpnClientCertificateRevocationList",
538    // IPAM core
539    "CreateIpam",
540    "DeleteIpam",
541    "DescribeIpams",
542    "ModifyIpam",
543    "CreateIpamScope",
544    "DeleteIpamScope",
545    "DescribeIpamScopes",
546    "ModifyIpamScope",
547    "CreateIpamPool",
548    "DeleteIpamPool",
549    "DescribeIpamPools",
550    "ModifyIpamPool",
551    "ProvisionIpamPoolCidr",
552    "DeprovisionIpamPoolCidr",
553    "GetIpamPoolCidrs",
554    "AllocateIpamPoolCidr",
555    "ReleaseIpamPoolAllocation",
556    "GetIpamPoolAllocations",
557    "GetIpamResourceCidrs",
558    "ModifyIpamResourceCidr",
559    "GetIpamAddressHistory",
560    "EnableIpamOrganizationAdminAccount",
561    "DisableIpamOrganizationAdminAccount",
562    // IPAM resource discovery / BYOASN / BYOIP / external tokens
563    "CreateIpamResourceDiscovery",
564    "DeleteIpamResourceDiscovery",
565    "DescribeIpamResourceDiscoveries",
566    "ModifyIpamResourceDiscovery",
567    "AssociateIpamResourceDiscovery",
568    "DisassociateIpamResourceDiscovery",
569    "DescribeIpamResourceDiscoveryAssociations",
570    "GetIpamDiscoveredAccounts",
571    "GetIpamDiscoveredPublicAddresses",
572    "GetIpamDiscoveredResourceCidrs",
573    "AssociateIpamByoasn",
574    "DisassociateIpamByoasn",
575    "ProvisionIpamByoasn",
576    "DeprovisionIpamByoasn",
577    "DescribeIpamByoasn",
578    "MoveByoipCidrToIpam",
579    "CreateIpamExternalResourceVerificationToken",
580    "DeleteIpamExternalResourceVerificationToken",
581    "DescribeIpamExternalResourceVerificationTokens",
582    // IPAM policies + prefix-list resolvers
583    "CreateIpamPolicy",
584    "DeleteIpamPolicy",
585    "DescribeIpamPolicies",
586    "EnableIpamPolicy",
587    "DisableIpamPolicy",
588    "GetEnabledIpamPolicy",
589    "GetIpamPolicyAllocationRules",
590    "ModifyIpamPolicyAllocationRules",
591    "GetIpamPolicyOrganizationTargets",
592    "CreateIpamPrefixListResolver",
593    "DeleteIpamPrefixListResolver",
594    "DescribeIpamPrefixListResolvers",
595    "ModifyIpamPrefixListResolver",
596    "CreateIpamPrefixListResolverTarget",
597    "DeleteIpamPrefixListResolverTarget",
598    "DescribeIpamPrefixListResolverTargets",
599    "ModifyIpamPrefixListResolverTarget",
600    "GetIpamPrefixListResolverRules",
601    "GetIpamPrefixListResolverVersions",
602    "GetIpamPrefixListResolverVersionEntries",
603    // Verified Access
604    "CreateVerifiedAccessInstance",
605    "DeleteVerifiedAccessInstance",
606    "DescribeVerifiedAccessInstances",
607    "ModifyVerifiedAccessInstance",
608    "CreateVerifiedAccessTrustProvider",
609    "DeleteVerifiedAccessTrustProvider",
610    "DescribeVerifiedAccessTrustProviders",
611    "ModifyVerifiedAccessTrustProvider",
612    "AttachVerifiedAccessTrustProvider",
613    "DetachVerifiedAccessTrustProvider",
614    "CreateVerifiedAccessGroup",
615    "DeleteVerifiedAccessGroup",
616    "DescribeVerifiedAccessGroups",
617    "ModifyVerifiedAccessGroup",
618    "GetVerifiedAccessGroupPolicy",
619    "ModifyVerifiedAccessGroupPolicy",
620    "CreateVerifiedAccessEndpoint",
621    "DeleteVerifiedAccessEndpoint",
622    "DescribeVerifiedAccessEndpoints",
623    "ModifyVerifiedAccessEndpoint",
624    "GetVerifiedAccessEndpointPolicy",
625    "ModifyVerifiedAccessEndpointPolicy",
626    "GetVerifiedAccessEndpointTargets",
627    "DescribeVerifiedAccessInstanceLoggingConfigurations",
628    "ModifyVerifiedAccessInstanceLoggingConfiguration",
629    "ExportVerifiedAccessInstanceClientConfiguration",
630    // Network Insights
631    "CreateNetworkInsightsPath",
632    "DeleteNetworkInsightsPath",
633    "DescribeNetworkInsightsPaths",
634    "StartNetworkInsightsAnalysis",
635    "DeleteNetworkInsightsAnalysis",
636    "DescribeNetworkInsightsAnalyses",
637    "CreateNetworkInsightsAccessScope",
638    "DeleteNetworkInsightsAccessScope",
639    "DescribeNetworkInsightsAccessScopes",
640    "GetNetworkInsightsAccessScopeContent",
641    "StartNetworkInsightsAccessScopeAnalysis",
642    "DeleteNetworkInsightsAccessScopeAnalysis",
643    "DescribeNetworkInsightsAccessScopeAnalyses",
644    "GetNetworkInsightsAccessScopeAnalysisFindings",
645    // Outpost / local gateway / CoIP / carrier
646    "CreateCarrierGateway",
647    "DeleteCarrierGateway",
648    "DescribeCarrierGateways",
649    "CreateCoipPool",
650    "DeleteCoipPool",
651    "DescribeCoipPools",
652    "CreateCoipCidr",
653    "DeleteCoipCidr",
654    "GetCoipPoolUsage",
655    "CreateLocalGatewayRouteTable",
656    "DeleteLocalGatewayRouteTable",
657    "DescribeLocalGatewayRouteTables",
658    "CreateLocalGatewayRoute",
659    "DeleteLocalGatewayRoute",
660    "ModifyLocalGatewayRoute",
661    "SearchLocalGatewayRoutes",
662    "CreateLocalGatewayRouteTableVpcAssociation",
663    "DeleteLocalGatewayRouteTableVpcAssociation",
664    "DescribeLocalGatewayRouteTableVpcAssociations",
665    "CreateLocalGatewayVirtualInterface",
666    "DeleteLocalGatewayVirtualInterface",
667    "DescribeLocalGatewayVirtualInterfaces",
668    "CreateLocalGatewayVirtualInterfaceGroup",
669    "DeleteLocalGatewayVirtualInterfaceGroup",
670    "DescribeLocalGatewayVirtualInterfaceGroups",
671    "CreateLocalGatewayRouteTableVirtualInterfaceGroupAssociation",
672    "DeleteLocalGatewayRouteTableVirtualInterfaceGroupAssociation",
673    "DescribeLocalGatewayRouteTableVirtualInterfaceGroupAssociations",
674    "DescribeLocalGateways",
675    // Instance Connect / fast launch / serial console / console output
676    "CreateInstanceConnectEndpoint",
677    "DeleteInstanceConnectEndpoint",
678    "DescribeInstanceConnectEndpoints",
679    "ModifyInstanceConnectEndpoint",
680    "EnableFastLaunch",
681    "DisableFastLaunch",
682    "EnableSerialConsoleAccess",
683    "DisableSerialConsoleAccess",
684    "GetSerialConsoleAccessStatus",
685    "GetConsoleOutput",
686    "GetConsoleScreenshot",
687    "GetPasswordData",
688    // Remainder sweep (long tail -> full 767-op parity)
689    "CreateCapacityReservationCancellationQuote",
690    "DescribeCapacityReservationCancellationQuotes",
691    "DescribeIpamPoolAllocations",
692    "ModifyIpamPoolAllocation",
693    "DescribeAccountVpcEncryptionControl",
694    "ModifyAccountVpcEncryptionControl",
695    "ModifyVpcEndpointPayerResponsibility",
696    "AdvertiseByoipCidr",
697    "AssociateEnclaveCertificateIamRole",
698    "AssociateIamInstanceProfile",
699    "AssociateInstanceEventWindow",
700    "AssociateRouteServer",
701    "AssociateTrunkInterface",
702    "AttachClassicLinkVpc",
703    "BundleInstance",
704    "CancelBundleTask",
705    "CancelConversionTask",
706    "CancelDeclarativePoliciesReport",
707    "CancelExportTask",
708    "CancelImportTask",
709    "ConfirmProductInstance",
710    "CopyFpgaImage",
711    "CopyVolumes",
712    "CreateCapacityManagerDataExport",
713    "CreateDelegateMacVolumeOwnershipTask",
714    "CreateFpgaImage",
715    "CreateImageUsageReport",
716    "CreateInstanceEventWindow",
717    "CreateInstanceExportTask",
718    "CreateMacSystemIntegrityProtectionModificationTask",
719    "CreateManagedPrefixList",
720    "CreatePublicIpv4Pool",
721    "CreateReplaceRootVolumeTask",
722    "CreateRouteServer",
723    "CreateRouteServerEndpoint",
724    "CreateRouteServerPeer",
725    "CreateSecondaryNetwork",
726    "CreateTrafficMirrorFilter",
727    "CreateTrafficMirrorFilterRule",
728    "CreateTrafficMirrorSession",
729    "CreateTrafficMirrorTarget",
730    "CreateVpcBlockPublicAccessExclusion",
731    "CreateVpcEncryptionControl",
732    "DeleteCapacityManagerDataExport",
733    "DeleteFpgaImage",
734    "DeleteImageUsageReport",
735    "DeleteInstanceEventWindow",
736    "DeleteManagedPrefixList",
737    "DeletePublicIpv4Pool",
738    "DeleteRouteServer",
739    "DeleteRouteServerEndpoint",
740    "DeleteRouteServerPeer",
741    "DeleteSecondaryNetwork",
742    "DeleteTrafficMirrorFilter",
743    "DeleteTrafficMirrorFilterRule",
744    "DeleteTrafficMirrorSession",
745    "DeleteTrafficMirrorTarget",
746    "DeleteVpcBlockPublicAccessExclusion",
747    "DeleteVpcEncryptionControl",
748    "DeprovisionByoipCidr",
749    "DeprovisionPublicIpv4PoolCidr",
750    "DescribeAggregateIdFormat",
751    "DescribeAwsNetworkPerformanceMetricSubscriptions",
752    "DescribeBundleTasks",
753    "DescribeByoipCidrs",
754    "DescribeCapacityManagerDataExports",
755    "DescribeClassicLinkInstances",
756    "DescribeConversionTasks",
757    "DescribeDeclarativePoliciesReports",
758    "DescribeElasticGpus",
759    "DescribeExportImageTasks",
760    "DescribeExportTasks",
761    "DescribeFpgaImageAttribute",
762    "DescribeFpgaImages",
763    "DescribeHostReservationOfferings",
764    "DescribeHostReservations",
765    "DescribeIamInstanceProfileAssociations",
766    "DescribeIdFormat",
767    "DescribeIdentityIdFormat",
768    "DescribeImageReferences",
769    "DescribeImageUsageReportEntries",
770    "DescribeImageUsageReports",
771    "DescribeImportImageTasks",
772    "DescribeImportSnapshotTasks",
773    "DescribeInstanceEventWindows",
774    "DescribeInstanceImageMetadata",
775    "DescribeInstanceSqlHaHistoryStates",
776    "DescribeInstanceSqlHaStates",
777    "DescribeInstanceTypeOfferings",
778    "DescribeIpv6Pools",
779    "DescribeMacModificationTasks",
780    "DescribeManagedPrefixLists",
781    "DescribeOutpostLags",
782    "DescribePrefixLists",
783    "DescribePrincipalIdFormat",
784    "DescribePublicIpv4Pools",
785    "DescribeReplaceRootVolumeTasks",
786    "DescribeRouteServerEndpoints",
787    "DescribeRouteServerPeers",
788    "DescribeRouteServers",
789    "DescribeScheduledInstanceAvailability",
790    "DescribeScheduledInstances",
791    "DescribeSecondaryInterfaces",
792    "DescribeSecondaryNetworks",
793    "DescribeServiceLinkVirtualInterfaces",
794    "DescribeTrafficMirrorFilterRules",
795    "DescribeTrafficMirrorFilters",
796    "DescribeTrafficMirrorSessions",
797    "DescribeTrafficMirrorTargets",
798    "DescribeTrunkInterfaceAssociations",
799    "DescribeVpcBlockPublicAccessExclusions",
800    "DescribeVpcBlockPublicAccessOptions",
801    "DescribeVpcClassicLink",
802    "DescribeVpcClassicLinkDnsSupport",
803    "DescribeVpcEncryptionControls",
804    "DetachClassicLinkVpc",
805    "DisableAwsNetworkPerformanceMetricSubscription",
806    "DisableCapacityManager",
807    "DisableInstanceSqlHaStandbyDetections",
808    "DisableRouteServerPropagation",
809    "DisableVgwRoutePropagation",
810    "DisableVpcClassicLink",
811    "DisableVpcClassicLinkDnsSupport",
812    "DisassociateEnclaveCertificateIamRole",
813    "DisassociateIamInstanceProfile",
814    "DisassociateInstanceEventWindow",
815    "DisassociateRouteServer",
816    "DisassociateTrunkInterface",
817    "EnableAwsNetworkPerformanceMetricSubscription",
818    "EnableCapacityManager",
819    "EnableInstanceSqlHaStandbyDetections",
820    "EnableReachabilityAnalyzerOrganizationSharing",
821    "EnableRouteServerPropagation",
822    "EnableVgwRoutePropagation",
823    "EnableVpcClassicLink",
824    "EnableVpcClassicLinkDnsSupport",
825    "ExportImage",
826    "GetAssociatedEnclaveCertificateIamRoles",
827    "GetAssociatedIpv6PoolCidrs",
828    "GetAwsNetworkPerformanceData",
829    "GetCapacityManagerAttributes",
830    "GetCapacityManagerMetricData",
831    "GetCapacityManagerMetricDimensions",
832    "GetCapacityManagerMonitoredTagKeys",
833    "GetDeclarativePoliciesReportSummary",
834    "GetDefaultCreditSpecification",
835    "GetHostReservationPurchasePreview",
836    "GetImageAncestry",
837    "GetInstanceTpmEkPub",
838    "GetInstanceUefiData",
839    "GetManagedPrefixListAssociations",
840    "GetManagedPrefixListEntries",
841    "GetManagedResourceVisibility",
842    "GetRouteServerAssociations",
843    "GetRouteServerPropagations",
844    "GetRouteServerRoutingDatabase",
845    "GetVpcResourcesBlockingEncryptionEnforcement",
846    "ImportImage",
847    "ImportInstance",
848    "ImportSnapshot",
849    "ImportVolume",
850    "ModifyAvailabilityZoneGroup",
851    "ModifyDefaultCreditSpecification",
852    "ModifyFpgaImageAttribute",
853    "ModifyIdFormat",
854    "ModifyIdentityIdFormat",
855    "ModifyInstanceEventWindow",
856    "ModifyManagedPrefixList",
857    "ModifyManagedResourceVisibility",
858    "ModifyPrivateDnsNameOptions",
859    "ModifyPublicIpDnsNameOptions",
860    "ModifyRouteServer",
861    "ModifyTrafficMirrorFilterNetworkServices",
862    "ModifyTrafficMirrorFilterRule",
863    "ModifyTrafficMirrorSession",
864    "ModifyVpcBlockPublicAccessExclusion",
865    "ModifyVpcBlockPublicAccessOptions",
866    "ModifyVpcEncryptionControl",
867    "ProvisionByoipCidr",
868    "ProvisionPublicIpv4PoolCidr",
869    "PurchaseHostReservation",
870    "PurchaseScheduledInstances",
871    "ReplaceIamInstanceProfileAssociation",
872    "ResetFpgaImageAttribute",
873    "RestoreManagedPrefixListVersion",
874    "RunScheduledInstances",
875    "SendDiagnosticInterrupt",
876    "StartDeclarativePoliciesReport",
877    "UpdateCapacityManagerMonitoredTagKeys",
878    "UpdateCapacityManagerOrganizationsAccess",
879    "WithdrawByoipCidr",
880];
881
882/// Amazon EC2 service.
883pub struct Ec2Service {
884    pub(crate) state: SharedEc2State,
885    /// Optional container runtime backing instances with real containers.
886    /// `None` runs the metadata-only control plane (no Docker/Podman/k8s).
887    pub(crate) runtime: Option<Arc<Ec2Runtime>>,
888    pub(crate) snapshot_store: Option<Arc<dyn SnapshotStore>>,
889    pub(crate) snapshot_lock: Arc<AsyncMutex<()>>,
890}
891
892impl Ec2Service {
893    /// Construct a service over a fresh, empty account-partitioned state.
894    pub fn new() -> Self {
895        Self {
896            state: Arc::new(RwLock::new(MultiAccountState::new(
897                "000000000000",
898                "us-east-1",
899                "",
900            ))),
901            runtime: None,
902            snapshot_store: None,
903            snapshot_lock: Arc::new(AsyncMutex::new(())),
904        }
905    }
906
907    /// Construct a service over a shared state handle (used by the server so
908    /// persistence/snapshots can be wired in later batches).
909    pub fn with_state(state: SharedEc2State) -> Self {
910        Self {
911            state,
912            runtime: None,
913            snapshot_store: None,
914            snapshot_lock: Arc::new(AsyncMutex::new(())),
915        }
916    }
917
918    /// Synchronous dispatch for the subset of EC2 control-plane actions the
919    /// CloudFormation provisioner needs (VPC/Subnet/SecurityGroup/RouteTable/
920    /// InternetGateway create + delete). Routing through the real handlers
921    /// keeps CFN-provisioned EC2 resources identical to API-created ones
922    /// (default SG/NACL/route-table, id formats, tags) instead of re-deriving
923    /// them. None of these actions need the container runtime.
924    pub fn provision_sync(&self, request: &AwsRequest) -> Result<AwsResponse, AwsServiceError> {
925        match request.action.as_str() {
926            "CreateVpc" => vpc::create_vpc(self, request),
927            "DeleteVpc" => vpc::delete_vpc(self, request),
928            "CreateSubnet" => subnet::create_subnet(self, request),
929            "DeleteSubnet" => subnet::delete_subnet(self, request),
930            "CreateSecurityGroup" => sg::create_security_group(self, request),
931            "DeleteSecurityGroup" => sg::delete_security_group(self, request),
932            "CreateRouteTable" => routing::create_route_table(self, request),
933            "DeleteRouteTable" => routing::delete_route_table(self, request),
934            "CreateInternetGateway" => routing::create_internet_gateway(self, request),
935            "DeleteInternetGateway" => routing::delete_internet_gateway(self, request),
936            // Attribute / rule application the CloudFormation provisioner issues
937            // after a Create so VPC DNS attributes, subnet MapPublicIpOnLaunch,
938            // and inline SecurityGroup ingress/egress rules from a template are
939            // actually applied (not silently dropped).
940            "ModifyVpcAttribute" => vpc::modify_vpc_attribute(self, request),
941            "ModifySubnetAttribute" => subnet::modify_subnet_attribute(self, request),
942            "AuthorizeSecurityGroupIngress" => sg::authorize_security_group_ingress(self, request),
943            "AuthorizeSecurityGroupEgress" => sg::authorize_security_group_egress(self, request),
944            other => Err(AwsServiceError::action_not_implemented("ec2", other)),
945        }
946    }
947
948    /// Attach a container runtime so `RunInstances` boots real containers.
949    /// Passing `None` leaves the service in metadata-only mode.
950    pub fn with_runtime(mut self, runtime: Option<Arc<Ec2Runtime>>) -> Self {
951        self.runtime = runtime;
952        self
953    }
954
955    /// Attach a persistence snapshot store so control-plane mutations are
956    /// written through to disk. Backing containers are reconciled separately on
957    /// restart via [`Ec2Service::recover_persisted_containers`].
958    pub fn with_snapshot_store(mut self, store: Arc<dyn SnapshotStore>) -> Self {
959        self.snapshot_store = Some(store);
960        self
961    }
962
963    /// Persist current state as a snapshot. Held across the
964    /// clone-serialize-write sequence to prevent stale-last writes, with serde
965    /// + file I/O offloaded to the blocking pool.
966    async fn save_snapshot(&self) {
967        save_ec2_snapshot(
968            &self.state,
969            self.snapshot_store.clone(),
970            &self.snapshot_lock,
971        )
972        .await;
973    }
974
975    /// Build a hook that persists the current EC2 state when invoked, or `None`
976    /// in memory mode. The CloudFormation provisioner mutates `state` directly
977    /// and uses this to write a CFN-provisioned resource through to disk, the
978    /// same way a direct mutating API call would.
979    pub fn snapshot_hook(&self) -> Option<fakecloud_persistence::SnapshotHook> {
980        let store = self.snapshot_store.clone()?;
981        let state = self.state.clone();
982        let lock = self.snapshot_lock.clone();
983        Some(Arc::new(move || {
984            let state = state.clone();
985            let store = store.clone();
986            let lock = lock.clone();
987            Box::pin(async move {
988                save_ec2_snapshot(&state, Some(store), &lock).await;
989            })
990        }))
991    }
992
993    /// Clone the shared state handle so the server can expose read-only
994    /// introspection endpoints (`GET /_fakecloud/ec2/instances`).
995    pub fn shared_state(&self) -> SharedEc2State {
996        self.state.clone()
997    }
998
999    /// Re-derive the security-group/NACL firewall model from current state and
1000    /// (re)apply it via the runtime's nftables enforcer (#1745 phase 3).
1001    ///
1002    /// Cheap no-op when there's no runtime or enforcement is disabled — the
1003    /// common case — so it's safe to call liberally after any mutation that can
1004    /// change the ruleset (RunInstances, Terminate, Authorize/Revoke,
1005    /// network-ACL edits). Runs in the background so it never blocks the API
1006    /// response.
1007    pub(crate) fn spawn_firewall_reconcile(&self) {
1008        let Some(runtime) = self.runtime.clone() else {
1009            return;
1010        };
1011        if !runtime.network_isolation_enforced() {
1012            return;
1013        }
1014        let state = self.state.clone();
1015        tokio::spawn(async move {
1016            firewall_model::reconcile(&state, &runtime).await;
1017        });
1018    }
1019
1020    /// Rebuild the backing-container runtime state for persisted instances
1021    /// after a fakecloud restart, mirroring RDS/ElastiCache
1022    /// `recover_persisted_containers`.
1023    ///
1024    /// On an ungraceful restart the new process has a new PID, so the shared
1025    /// reaper removes every EC2 container labeled with the *previous* PID; an
1026    /// instance that persisted as `running` with a `container_id` would
1027    /// otherwise be left pointing at a removed container, with every
1028    /// subsequent Stop/Start/Reboot/Terminate a silent no-op (bug-hunt
1029    /// 2026-06-15 finding 0.3). For each such instance we flip it to `pending`
1030    /// and spawn a fresh backing container in the background, reconciling it to
1031    /// `running` (with the new id/IP) when it's up, or `stopped` on failure.
1032    /// Instances persisted as `stopped`/`terminated` are left as-is —
1033    /// StartInstances revives the former. No-op when no runtime is configured
1034    /// or there are no instances to recover.
1035    /// Flip every `pending` (code 0) instance to `running` (code 16) in
1036    /// metadata-only mode, then persist. Used on restart so an instance whose
1037    /// background boot flip was lost across a restart still reaches `running`,
1038    /// and directly by the RunInstances background task when no runtime is
1039    /// wired so the persisted snapshot captures `running`, not `pending` (M12).
1040    pub(crate) async fn reconcile_pending_metadata_only(&self) {
1041        let flipped = {
1042            let mut accounts = self.state.write();
1043            let mut n = 0;
1044            for (_, state) in accounts.iter_mut() {
1045                for inst in state.instances.values_mut() {
1046                    if inst.state_code == 0 {
1047                        inst.state_code = 16;
1048                        inst.state_name = "running".to_string();
1049                        n += 1;
1050                    }
1051                }
1052            }
1053            n
1054        };
1055        if flipped > 0 {
1056            self.save_snapshot().await;
1057        }
1058    }
1059
1060    // (helper `recovery_terminal_wins` is defined at module scope below.)
1061
1062    pub async fn recover_persisted_containers(&self) {
1063        let Some(runtime) = self.runtime.clone() else {
1064            // Metadata-only mode: there is no container to reconcile, but an
1065            // instance persisted mid-boot (state `pending`, code 0) would stay
1066            // stuck pending forever because the background flip-to-running that
1067            // RunInstances spawned never ran in this process. Flip any such
1068            // instance to `running` so a restart self-heals (M12).
1069            self.reconcile_pending_metadata_only().await;
1070            return;
1071        };
1072
1073        struct Pending {
1074            account_id: String,
1075            id: String,
1076            user_data: Option<String>,
1077            tags: std::collections::BTreeMap<String, String>,
1078            network: Option<crate::runtime::InstanceNetwork>,
1079        }
1080
1081        let pending: Vec<Pending> = {
1082            let mut accounts = self.state.write();
1083            let mut out = Vec::new();
1084            for (_, state) in accounts.iter_mut() {
1085                let account_id = state.account_id.clone();
1086                // Snapshot the tag map first so we don't hold two borrows of
1087                // `state` at once when re-deriving per-instance Pod tags.
1088                let tag_snapshot: std::collections::BTreeMap<String, Vec<crate::state::Tag>> =
1089                    state.tags.clone();
1090                // Which subnets are public (have an IGW default route), computed
1091                // before the mutable instance loop so we can re-derive each
1092                // recovered instance's `internal` flag without a second borrow.
1093                let public_subnets: std::collections::HashSet<String> = state
1094                    .subnets
1095                    .keys()
1096                    .filter(|sid| crate::defaults::subnet_is_public(state, sid))
1097                    .cloned()
1098                    .collect();
1099                for (id, inst) in state.instances.iter_mut() {
1100                    // Only running/pending instances need a live container; the
1101                    // stale container_id is dropped (the reaper removed it).
1102                    if !matches!(inst.state_name.as_str(), "running" | "pending") {
1103                        continue;
1104                    }
1105                    let tags = tag_snapshot
1106                        .get(id)
1107                        .map(|t| {
1108                            t.iter()
1109                                .map(|tag| (tag.key.clone(), tag.value.clone()))
1110                                .collect()
1111                        })
1112                        .unwrap_or_default();
1113                    let network =
1114                        inst.subnet_id
1115                            .clone()
1116                            .map(|sid| crate::runtime::InstanceNetwork {
1117                                internal: !public_subnets.contains(&sid),
1118                                subnet_id: sid,
1119                            });
1120                    inst.state_code = 0;
1121                    inst.state_name = "pending".to_string();
1122                    inst.container_id = None;
1123                    out.push(Pending {
1124                        account_id: account_id.clone(),
1125                        id: id.clone(),
1126                        user_data: inst.user_data.clone(),
1127                        tags,
1128                        network,
1129                    });
1130                }
1131            }
1132            out
1133        };
1134
1135        if pending.is_empty() {
1136            return;
1137        }
1138        tracing::info!(
1139            count = pending.len(),
1140            "recovering backing containers for persisted ec2 instances",
1141        );
1142
1143        let mut handles = Vec::new();
1144        for p in pending {
1145            let runtime = runtime.clone();
1146            let state = self.state.clone();
1147            handles.push(tokio::spawn(async move {
1148                let running = runtime
1149                    .run_instance(
1150                        &p.account_id,
1151                        &p.id,
1152                        p.user_data.as_deref(),
1153                        &p.tags,
1154                        p.network.as_ref(),
1155                    )
1156                    .await;
1157                let reap = {
1158                    let mut accounts = state.write();
1159                    match (
1160                        accounts
1161                            .get_mut(&p.account_id)
1162                            .and_then(|s| s.instances.get_mut(&p.id)),
1163                        running,
1164                    ) {
1165                        (Some(inst), Ok(r)) => {
1166                            // A concurrent Terminate (code 48) or Stop (code 80)
1167                            // during the recovery window wins: don't resurrect the
1168                            // instance to `running`, and drop the container we just
1169                            // started (a terminated/stopped instance owns none).
1170                            // Mirrors the both-terminal guard in
1171                            // `instance::reconcile_started`. Guarding only code 48
1172                            // let a concurrent StopInstances get clobbered back to
1173                            // `running` with a fresh container (bug-hunt
1174                            // restart-dataloss).
1175                            if recovery_terminal_wins(inst.state_code) {
1176                                true
1177                            } else {
1178                                inst.state_code = 16;
1179                                inst.state_name = "running".to_string();
1180                                inst.private_ip = r.private_ip;
1181                                inst.container_id = Some(r.container_id);
1182                                false
1183                            }
1184                        }
1185                        (Some(inst), Err(error)) => {
1186                            // A concurrent Terminate (code 48) or Stop (code 80)
1187                            // wins over a boot failure too: leave the terminal
1188                            // state as-is rather than overwriting it to `stopped`.
1189                            // The unguarded write here previously clobbered a
1190                            // concurrent TerminateInstances (code 48) to `stopped`
1191                            // (bug-hunt restart-dataloss).
1192                            if recovery_terminal_wins(inst.state_code) {
1193                                false
1194                            } else {
1195                                tracing::error!(
1196                                    %error,
1197                                    instance_id = %p.id,
1198                                    "failed to recover ec2 backing container after restart",
1199                                );
1200                                inst.state_code = 80;
1201                                inst.state_name = "stopped".to_string();
1202                                inst.container_id = None;
1203                                false
1204                            }
1205                        }
1206                        // Deleted during recovery: stop the container we just
1207                        // started so it isn't orphaned (mirrors ElastiCache).
1208                        (None, Ok(_)) => true,
1209                        (None, Err(_)) => false,
1210                    }
1211                };
1212                if reap {
1213                    runtime.terminate_instance(&p.id).await;
1214                }
1215            }));
1216        }
1217
1218        // Once every instance is back up, (re)apply the security-group
1219        // firewall. The startup reaper cleared the previous process's nft
1220        // table / NetworkPolicies, and the per-instance recovery tasks above
1221        // don't reconcile — without this, recovered instances would run
1222        // unfiltered until some unrelated later op happened to trigger a
1223        // reconcile (#1745; bug-hunt 2026-06-18 finding 4.1). No-op when
1224        // enforcement is disabled.
1225        {
1226            let runtime = runtime.clone();
1227            let state = self.state.clone();
1228            let store = self.snapshot_store.clone();
1229            let lock = self.snapshot_lock.clone();
1230            tokio::spawn(async move {
1231                for h in handles {
1232                    let _ = h.await;
1233                }
1234                if runtime.network_isolation_enforced() {
1235                    firewall_model::reconcile(&state, &runtime).await;
1236                }
1237                // Persist the recovered fleet: each instance now carries a
1238                // fresh container_id and a settled running/stopped state that
1239                // the recovery loop wrote back in memory. Without this flush the
1240                // snapshot still held the pre-restart container_ids (nulled at
1241                // the top of this fn), so every restart re-drove recovery from
1242                // stale data instead of reusing the freshly booted containers —
1243                // unlike the RDS/ElastiCache siblings, which save after recover.
1244                save_ec2_snapshot(&state, store, &lock).await;
1245            });
1246        }
1247    }
1248}
1249
1250impl Default for Ec2Service {
1251    fn default() -> Self {
1252        Self::new()
1253    }
1254}
1255
1256/// Persist the current EC2 state as a snapshot. Offloads the serde + blocking
1257/// file write to the Tokio blocking pool. Noop when `store` is `None` (memory
1258/// mode). Shared by `Ec2Service::save_snapshot` and the CloudFormation
1259/// provisioner persist hook so both route through the same serialize-and-write
1260/// path. Backing containers are not serialized; they are reconciled on restart
1261/// via `Ec2Service::recover_persisted_containers`.
1262pub async fn save_ec2_snapshot(
1263    state: &SharedEc2State,
1264    store: Option<Arc<dyn SnapshotStore>>,
1265    lock: &AsyncMutex<()>,
1266) {
1267    let Some(store) = store else {
1268        return;
1269    };
1270    let _guard = lock.lock().await;
1271    let snapshot = Ec2Snapshot {
1272        schema_version: EC2_SNAPSHOT_SCHEMA_VERSION,
1273        accounts: Some(state.read().clone()),
1274    };
1275    let join = tokio::task::spawn_blocking(move || -> std::io::Result<()> {
1276        let bytes = serde_json::to_vec(&snapshot)
1277            .map_err(|e| std::io::Error::new(std::io::ErrorKind::InvalidData, e.to_string()))?;
1278        store.save(&bytes)
1279    })
1280    .await;
1281    match join {
1282        Ok(Ok(())) => {}
1283        Ok(Err(err)) => tracing::error!(%err, "failed to write ec2 snapshot"),
1284        Err(err) => tracing::error!(%err, "ec2 snapshot task panicked"),
1285    }
1286}
1287
1288/// True if a concurrent Terminate (code 48) or Stop (code 80) has already
1289/// claimed an instance during the restart recovery window, so
1290/// `recover_persisted_containers` must NOT overwrite that terminal state with a
1291/// recovered `running`/`stopped` row. Mirrors the both-terminal guard in
1292/// [`instance::reconcile_started`]; applies to BOTH the boot-success and
1293/// boot-failure arms (a boot failure previously clobbered a concurrent
1294/// Terminate to `stopped`; a boot success clobbered a concurrent Stop back to
1295/// `running` with a fresh container). bug-hunt restart-dataloss.
1296fn recovery_terminal_wins(state_code: i64) -> bool {
1297    state_code == 48 || state_code == 80
1298}
1299
1300#[async_trait]
1301impl AwsService for Ec2Service {
1302    fn service_name(&self) -> &str {
1303        "ec2"
1304    }
1305
1306    fn supported_actions(&self) -> &[&str] {
1307        SUPPORTED_ACTIONS
1308    }
1309
1310    async fn handle(&self, request: AwsRequest) -> Result<AwsResponse, AwsServiceError> {
1311        let mutates = is_mutating_action(&request.action);
1312        let result = match request.action.as_str() {
1313            "CreateTags" => tags::create_tags(self, &request),
1314            "DeleteTags" => tags::delete_tags(self, &request),
1315            "DescribeTags" => tags::describe_tags(self, &request),
1316            "DescribeRegions" => meta::describe_regions(self, &request),
1317            "DescribeAvailabilityZones" => meta::describe_availability_zones(self, &request),
1318            "DescribeAccountAttributes" => meta::describe_account_attributes(self, &request),
1319            "CreateVpc" => vpc::create_vpc(self, &request),
1320            "CreateDefaultVpc" => vpc::create_default_vpc(self, &request),
1321            "DeleteVpc" => vpc::delete_vpc(self, &request),
1322            "DescribeVpcs" => vpc::describe_vpcs(self, &request),
1323            "ModifyVpcAttribute" => vpc::modify_vpc_attribute(self, &request),
1324            "DescribeVpcAttribute" => vpc::describe_vpc_attribute(self, &request),
1325            "ModifyVpcTenancy" => vpc::modify_vpc_tenancy(self, &request),
1326            "AssociateVpcCidrBlock" => vpc::associate_vpc_cidr_block(self, &request),
1327            "DisassociateVpcCidrBlock" => vpc::disassociate_vpc_cidr_block(self, &request),
1328            "CreateDhcpOptions" => dhcp::create_dhcp_options(self, &request),
1329            "DeleteDhcpOptions" => dhcp::delete_dhcp_options(self, &request),
1330            "DescribeDhcpOptions" => dhcp::describe_dhcp_options(self, &request),
1331            "AssociateDhcpOptions" => dhcp::associate_dhcp_options(self, &request),
1332            "CreateSubnet" => subnet::create_subnet(self, &request),
1333            "CreateDefaultSubnet" => subnet::create_default_subnet(self, &request),
1334            "CreateSecondarySubnet" => subnet::create_secondary_subnet(self, &request),
1335            "DeleteSubnet" => subnet::delete_subnet(self, &request),
1336            "DeleteSecondarySubnet" => subnet::delete_secondary_subnet(self, &request),
1337            "DescribeSubnets" => subnet::describe_subnets(self, &request),
1338            "DescribeSecondarySubnets" => subnet::describe_secondary_subnets(self, &request),
1339            "ModifySubnetAttribute" => subnet::modify_subnet_attribute(self, &request),
1340            "AssociateSubnetCidrBlock" => subnet::associate_subnet_cidr_block(self, &request),
1341            "DisassociateSubnetCidrBlock" => subnet::disassociate_subnet_cidr_block(self, &request),
1342            "CreateSubnetCidrReservation" => subnet::create_subnet_cidr_reservation(self, &request),
1343            "DeleteSubnetCidrReservation" => subnet::delete_subnet_cidr_reservation(self, &request),
1344            "GetSubnetCidrReservations" => subnet::get_subnet_cidr_reservations(self, &request),
1345            "CreateSecurityGroup" => sg::create_security_group(self, &request),
1346            "DeleteSecurityGroup" => sg::delete_security_group(self, &request),
1347            "DescribeSecurityGroups" => sg::describe_security_groups(self, &request),
1348            "AuthorizeSecurityGroupIngress" => sg::authorize_security_group_ingress(self, &request),
1349            "AuthorizeSecurityGroupEgress" => sg::authorize_security_group_egress(self, &request),
1350            "RevokeSecurityGroupIngress" => sg::revoke_security_group_ingress(self, &request),
1351            "RevokeSecurityGroupEgress" => sg::revoke_security_group_egress(self, &request),
1352            "DescribeSecurityGroupRules" => sg::describe_security_group_rules(self, &request),
1353            "ModifySecurityGroupRules" => sg::modify_security_group_rules(self, &request),
1354            "UpdateSecurityGroupRuleDescriptionsIngress" => {
1355                sg::update_rule_descriptions_ingress(self, &request)
1356            }
1357            "UpdateSecurityGroupRuleDescriptionsEgress" => {
1358                sg::update_rule_descriptions_egress(self, &request)
1359            }
1360            "AssociateSecurityGroupVpc" => sg::associate_security_group_vpc(self, &request),
1361            "DisassociateSecurityGroupVpc" => sg::disassociate_security_group_vpc(self, &request),
1362            "DescribeSecurityGroupVpcAssociations" => {
1363                sg::describe_security_group_vpc_associations(self, &request)
1364            }
1365            "GetSecurityGroupsForVpc" => sg::get_security_groups_for_vpc(self, &request),
1366            "DescribeStaleSecurityGroups" => sg::describe_stale_security_groups(self, &request),
1367            "DescribeSecurityGroupReferences" => {
1368                sg::describe_security_group_references(self, &request)
1369            }
1370            "CreateRouteTable" => routing::create_route_table(self, &request),
1371            "DeleteRouteTable" => routing::delete_route_table(self, &request),
1372            "DescribeRouteTables" => routing::describe_route_tables(self, &request),
1373            "CreateRoute" => routing::create_route(self, &request),
1374            "DeleteRoute" => routing::delete_route(self, &request),
1375            "ReplaceRoute" => routing::replace_route(self, &request),
1376            "AssociateRouteTable" => routing::associate_route_table(self, &request),
1377            "DisassociateRouteTable" => routing::disassociate_route_table(self, &request),
1378            "ReplaceRouteTableAssociation" => {
1379                routing::replace_route_table_association(self, &request)
1380            }
1381            "CreateInternetGateway" => routing::create_internet_gateway(self, &request),
1382            "DeleteInternetGateway" => routing::delete_internet_gateway(self, &request),
1383            "DescribeInternetGateways" => routing::describe_internet_gateways(self, &request),
1384            "AttachInternetGateway" => routing::attach_internet_gateway(self, &request),
1385            "DetachInternetGateway" => routing::detach_internet_gateway(self, &request),
1386            "CreateEgressOnlyInternetGateway" => routing::create_egress_only_igw(self, &request),
1387            "DeleteEgressOnlyInternetGateway" => routing::delete_egress_only_igw(self, &request),
1388            "DescribeEgressOnlyInternetGateways" => {
1389                routing::describe_egress_only_igws(self, &request)
1390            }
1391            "CreateNatGateway" => routing::create_nat_gateway(self, &request),
1392            "DeleteNatGateway" => routing::delete_nat_gateway(self, &request),
1393            "DescribeNatGateways" => routing::describe_nat_gateways(self, &request),
1394            "AssignPrivateNatGatewayAddress" => {
1395                routing::assign_private_nat_gateway_address(self, &request)
1396            }
1397            "AssociateNatGatewayAddress" => routing::associate_nat_gateway_address(self, &request),
1398            "DisassociateNatGatewayAddress" => {
1399                routing::disassociate_nat_gateway_address(self, &request)
1400            }
1401            "UnassignPrivateNatGatewayAddress" => {
1402                routing::unassign_private_nat_gateway_address(self, &request)
1403            }
1404            "AllocateAddress" => eip::allocate_address(self, &request),
1405            "ReleaseAddress" => eip::release_address(self, &request),
1406            "DescribeAddresses" => eip::describe_addresses(self, &request),
1407            "AssociateAddress" => eip::associate_address(self, &request),
1408            "DisassociateAddress" => eip::disassociate_address(self, &request),
1409            "DescribeAddressesAttribute" => eip::describe_addresses_attribute(self, &request),
1410            "ModifyAddressAttribute" => eip::modify_address_attribute(self, &request),
1411            "ResetAddressAttribute" => eip::reset_address_attribute(self, &request),
1412            "MoveAddressToVpc" => eip::move_address_to_vpc(self, &request),
1413            "RestoreAddressToClassic" => eip::restore_address_to_classic(self, &request),
1414            "AcceptAddressTransfer" => eip::accept_address_transfer(self, &request),
1415            "EnableAddressTransfer" => eip::enable_address_transfer(self, &request),
1416            "DisableAddressTransfer" => eip::disable_address_transfer(self, &request),
1417            "DescribeAddressTransfers" => eip::describe_address_transfers(self, &request),
1418            "DescribeMovingAddresses" => eip::describe_moving_addresses(self, &request),
1419            "CreateKeyPair" => eip::create_key_pair(self, &request),
1420            "ImportKeyPair" => eip::import_key_pair(self, &request),
1421            "DeleteKeyPair" => eip::delete_key_pair(self, &request),
1422            "DescribeKeyPairs" => eip::describe_key_pairs(self, &request),
1423            "CreatePlacementGroup" => eip::create_placement_group(self, &request),
1424            "DeletePlacementGroup" => eip::delete_placement_group(self, &request),
1425            "DescribePlacementGroups" => eip::describe_placement_groups(self, &request),
1426            "GetGroupsForCapacityReservation" => {
1427                eip::get_groups_for_capacity_reservation(self, &request)
1428            }
1429            "CreateNetworkInterface" => eni::create_network_interface(self, &request),
1430            "DeleteNetworkInterface" => eni::delete_network_interface(self, &request),
1431            "DescribeNetworkInterfaces" => eni::describe_network_interfaces(self, &request),
1432            "AttachNetworkInterface" => eni::attach_network_interface(self, &request),
1433            "DetachNetworkInterface" => eni::detach_network_interface(self, &request),
1434            "ModifyNetworkInterfaceAttribute" => {
1435                eni::modify_network_interface_attribute(self, &request)
1436            }
1437            "ResetNetworkInterfaceAttribute" => {
1438                eni::reset_network_interface_attribute(self, &request)
1439            }
1440            "DescribeNetworkInterfaceAttribute" => {
1441                eni::describe_network_interface_attribute(self, &request)
1442            }
1443            "CreateNetworkInterfacePermission" => {
1444                eni::create_network_interface_permission(self, &request)
1445            }
1446            "DeleteNetworkInterfacePermission" => {
1447                eni::delete_network_interface_permission(self, &request)
1448            }
1449            "DescribeNetworkInterfacePermissions" => {
1450                eni::describe_network_interface_permissions(self, &request)
1451            }
1452            "AssignPrivateIpAddresses" => eni::assign_private_ip_addresses(self, &request),
1453            "UnassignPrivateIpAddresses" => eni::unassign_private_ip_addresses(self, &request),
1454            "AssignIpv6Addresses" => eni::assign_ipv6_addresses(self, &request),
1455            "UnassignIpv6Addresses" => eni::unassign_ipv6_addresses(self, &request),
1456            "RunInstances" => instance::run_instances(self, &request).await,
1457            "StartInstances" => instance::start_instances(self, &request).await,
1458            "StopInstances" => instance::stop_instances(self, &request).await,
1459            "RebootInstances" => instance::reboot_instances(self, &request).await,
1460            "TerminateInstances" => instance::terminate_instances(self, &request).await,
1461            "MonitorInstances" => instance::monitor_instances(self, &request),
1462            "UnmonitorInstances" => instance::unmonitor_instances(self, &request),
1463            "DescribeInstances" => instance::describe_instances(self, &request),
1464            "DescribeInstanceStatus" => instance::describe_instance_status(self, &request),
1465            "DescribeInstanceTypes" => instance::describe_instance_types(self, &request),
1466            "GetInstanceTypesFromInstanceRequirements" => {
1467                instance::get_instance_types_from_requirements(self, &request)
1468            }
1469            "DescribeInstanceAttribute" => instance::describe_instance_attribute(self, &request),
1470            "ModifyInstanceAttribute" => instance::modify_instance_attribute(self, &request),
1471            "ResetInstanceAttribute" => instance::reset_instance_attribute(self, &request),
1472            "ModifyInstancePlacement" => instance::modify_instance_placement(self, &request),
1473            "ModifyInstanceMetadataOptions" => {
1474                instance::modify_instance_metadata_options(self, &request)
1475            }
1476            "ModifyInstanceMaintenanceOptions" => {
1477                instance::modify_instance_maintenance_options(self, &request)
1478            }
1479            "ModifyInstanceCpuOptions" => instance::modify_instance_cpu_options(self, &request),
1480            "ModifyInstanceNetworkPerformanceOptions" => {
1481                instance::modify_instance_network_performance_options(self, &request)
1482            }
1483            "ModifyInstanceEventStartTime" => {
1484                instance::modify_instance_event_start_time(self, &request)
1485            }
1486            "DescribeInstanceCreditSpecifications" => {
1487                instance::describe_instance_credit_specifications(self, &request)
1488            }
1489            "ModifyInstanceCreditSpecification" => {
1490                instance::modify_instance_credit_specification(self, &request)
1491            }
1492            "GetInstanceMetadataDefaults" => {
1493                instance::get_instance_metadata_defaults(self, &request)
1494            }
1495            "ModifyInstanceMetadataDefaults" => {
1496                instance::modify_instance_metadata_defaults(self, &request)
1497            }
1498            "RegisterInstanceEventNotificationAttributes" => {
1499                instance::register_event_notification_attributes(self, &request)
1500            }
1501            "DeregisterInstanceEventNotificationAttributes" => {
1502                instance::deregister_event_notification_attributes(self, &request)
1503            }
1504            "DescribeInstanceEventNotificationAttributes" => {
1505                instance::describe_event_notification_attributes(self, &request)
1506            }
1507            "ReportInstanceStatus" => instance::report_instance_status(self, &request),
1508            "DescribeInstanceTopology" => instance::describe_instance_topology(self, &request),
1509            "CreateVolume" => volume::create_volume(self, &request),
1510            "DeleteVolume" => volume::delete_volume(self, &request),
1511            "DescribeVolumes" => volume::describe_volumes(self, &request),
1512            "AttachVolume" => volume::attach_volume(self, &request),
1513            "DetachVolume" => volume::detach_volume(self, &request),
1514            "ModifyVolume" => volume::modify_volume(self, &request),
1515            "DescribeVolumesModifications" => {
1516                volume::describe_volumes_modifications(self, &request)
1517            }
1518            "DescribeVolumeStatus" => volume::describe_volume_status(self, &request),
1519            "DescribeVolumeAttribute" => volume::describe_volume_attribute(self, &request),
1520            "ModifyVolumeAttribute" => volume::modify_volume_attribute(self, &request),
1521            "EnableVolumeIO" => volume::enable_volume_io(self, &request),
1522            "ListVolumesInRecycleBin" => volume::list_volumes_in_recycle_bin(self, &request),
1523            "RestoreVolumeFromRecycleBin" => {
1524                volume::restore_volume_from_recycle_bin(self, &request)
1525            }
1526            "GetEbsEncryptionByDefault" => volume::get_ebs_encryption_by_default(self, &request),
1527            "EnableEbsEncryptionByDefault" => {
1528                volume::enable_ebs_encryption_by_default(self, &request)
1529            }
1530            "DisableEbsEncryptionByDefault" => {
1531                volume::disable_ebs_encryption_by_default(self, &request)
1532            }
1533            "GetEbsDefaultKmsKeyId" => volume::get_ebs_default_kms_key_id(self, &request),
1534            "ModifyEbsDefaultKmsKeyId" => volume::modify_ebs_default_kms_key_id(self, &request),
1535            "ResetEbsDefaultKmsKeyId" => volume::reset_ebs_default_kms_key_id(self, &request),
1536            "CreateSnapshot" => snapshot::create_snapshot(self, &request),
1537            "CreateSnapshots" => snapshot::create_snapshots(self, &request),
1538            "DeleteSnapshot" => snapshot::delete_snapshot(self, &request),
1539            "DescribeSnapshots" => snapshot::describe_snapshots(self, &request),
1540            "CopySnapshot" => snapshot::copy_snapshot(self, &request),
1541            "DescribeSnapshotAttribute" => snapshot::describe_snapshot_attribute(self, &request),
1542            "ModifySnapshotAttribute" => snapshot::modify_snapshot_attribute(self, &request),
1543            "ResetSnapshotAttribute" => snapshot::reset_snapshot_attribute(self, &request),
1544            "ModifySnapshotTier" => snapshot::modify_snapshot_tier(self, &request),
1545            "DescribeSnapshotTierStatus" => snapshot::describe_snapshot_tier_status(self, &request),
1546            "RestoreSnapshotTier" => snapshot::restore_snapshot_tier(self, &request),
1547            "ListSnapshotsInRecycleBin" => snapshot::list_snapshots_in_recycle_bin(self, &request),
1548            "RestoreSnapshotFromRecycleBin" => {
1549                snapshot::restore_snapshot_from_recycle_bin(self, &request)
1550            }
1551            "LockSnapshot" => snapshot::lock_snapshot(self, &request),
1552            "UnlockSnapshot" => snapshot::unlock_snapshot(self, &request),
1553            "DescribeLockedSnapshots" => snapshot::describe_locked_snapshots(self, &request),
1554            "GetSnapshotBlockPublicAccessState" => {
1555                snapshot::get_snapshot_block_public_access_state(self, &request)
1556            }
1557            "EnableSnapshotBlockPublicAccess" => {
1558                snapshot::enable_snapshot_block_public_access(self, &request)
1559            }
1560            "DisableSnapshotBlockPublicAccess" => {
1561                snapshot::disable_snapshot_block_public_access(self, &request)
1562            }
1563            "EnableFastSnapshotRestores" => snapshot::enable_fast_snapshot_restores(self, &request),
1564            "DisableFastSnapshotRestores" => {
1565                snapshot::disable_fast_snapshot_restores(self, &request)
1566            }
1567            "DescribeFastSnapshotRestores" => {
1568                snapshot::describe_fast_snapshot_restores(self, &request)
1569            }
1570            "CreateImage" => image::create_image(self, &request),
1571            "RegisterImage" => image::register_image(self, &request),
1572            "DeregisterImage" => image::deregister_image(self, &request),
1573            "DescribeImages" => image::describe_images(self, &request),
1574            "CopyImage" => image::copy_image(self, &request),
1575            "DescribeImageAttribute" => image::describe_image_attribute(self, &request),
1576            "ModifyImageAttribute" => image::modify_image_attribute(self, &request),
1577            "ResetImageAttribute" => image::reset_image_attribute(self, &request),
1578            "EnableImage" => image::enable_image(self, &request),
1579            "DisableImage" => image::disable_image(self, &request),
1580            "AttachImageWatermark" => image::attach_image_watermark(self, &request),
1581            "DetachImageWatermark" => image::detach_image_watermark(self, &request),
1582            "EnableImageDeprecation" => image::enable_image_deprecation(self, &request),
1583            "DisableImageDeprecation" => image::disable_image_deprecation(self, &request),
1584            "EnableImageDeregistrationProtection" => {
1585                image::enable_image_deregistration_protection(self, &request)
1586            }
1587            "DisableImageDeregistrationProtection" => {
1588                image::disable_image_deregistration_protection(self, &request)
1589            }
1590            "CancelImageLaunchPermission" => image::cancel_image_launch_permission(self, &request),
1591            "RestoreImageFromRecycleBin" => image::restore_image_from_recycle_bin(self, &request),
1592            "ListImagesInRecycleBin" => image::list_images_in_recycle_bin(self, &request),
1593            "EnableImageBlockPublicAccess" => {
1594                image::enable_image_block_public_access(self, &request)
1595            }
1596            "DisableImageBlockPublicAccess" => {
1597                image::disable_image_block_public_access(self, &request)
1598            }
1599            "GetImageBlockPublicAccessState" => {
1600                image::get_image_block_public_access_state(self, &request)
1601            }
1602            "EnableAllowedImagesSettings" => image::enable_allowed_images_settings(self, &request),
1603            "DisableAllowedImagesSettings" => {
1604                image::disable_allowed_images_settings(self, &request)
1605            }
1606            "GetAllowedImagesSettings" => image::get_allowed_images_settings(self, &request),
1607            "ReplaceImageCriteriaInAllowedImagesSettings" => {
1608                image::replace_image_criteria_in_allowed_images_settings(self, &request)
1609            }
1610            "CreateStoreImageTask" => image::create_store_image_task(self, &request),
1611            "DescribeStoreImageTasks" => image::describe_store_image_tasks(self, &request),
1612            "CreateRestoreImageTask" => image::create_restore_image_task(self, &request),
1613            "DescribeFastLaunchImages" => image::describe_fast_launch_images(self, &request),
1614            "CreateNetworkAcl" => nacl::create_network_acl(self, &request),
1615            "DeleteNetworkAcl" => nacl::delete_network_acl(self, &request),
1616            "DescribeNetworkAcls" => nacl::describe_network_acls(self, &request),
1617            "CreateNetworkAclEntry" => nacl::create_network_acl_entry(self, &request),
1618            "DeleteNetworkAclEntry" => nacl::delete_network_acl_entry(self, &request),
1619            "ReplaceNetworkAclEntry" => nacl::replace_network_acl_entry(self, &request),
1620            "ReplaceNetworkAclAssociation" => nacl::replace_network_acl_association(self, &request),
1621            "CreateVpcPeeringConnection" => nacl::create_vpc_peering_connection(self, &request),
1622            "DeleteVpcPeeringConnection" => nacl::delete_vpc_peering_connection(self, &request),
1623            "DescribeVpcPeeringConnections" => {
1624                nacl::describe_vpc_peering_connections(self, &request)
1625            }
1626            "AcceptVpcPeeringConnection" => nacl::accept_vpc_peering_connection(self, &request),
1627            "RejectVpcPeeringConnection" => nacl::reject_vpc_peering_connection(self, &request),
1628            "ModifyVpcPeeringConnectionOptions" => {
1629                nacl::modify_vpc_peering_connection_options(self, &request)
1630            }
1631            "CreateVpcEndpoint" => endpoint::create_vpc_endpoint(self, &request),
1632            "DeleteVpcEndpoints" => endpoint::delete_vpc_endpoints(self, &request),
1633            "DescribeVpcEndpoints" => endpoint::describe_vpc_endpoints(self, &request),
1634            "ModifyVpcEndpoint" => endpoint::modify_vpc_endpoint(self, &request),
1635            "DescribeVpcEndpointServices" => {
1636                endpoint::describe_vpc_endpoint_services(self, &request)
1637            }
1638            "DescribeVpcEndpointConnections" => {
1639                endpoint::describe_vpc_endpoint_connections(self, &request)
1640            }
1641            "AcceptVpcEndpointConnections" => {
1642                endpoint::accept_vpc_endpoint_connections(self, &request)
1643            }
1644            "RejectVpcEndpointConnections" => {
1645                endpoint::reject_vpc_endpoint_connections(self, &request)
1646            }
1647            "CreateVpcEndpointServiceConfiguration" => {
1648                endpoint::create_vpc_endpoint_service_configuration(self, &request)
1649            }
1650            "DeleteVpcEndpointServiceConfigurations" => {
1651                endpoint::delete_vpc_endpoint_service_configurations(self, &request)
1652            }
1653            "DescribeVpcEndpointServiceConfigurations" => {
1654                endpoint::describe_vpc_endpoint_service_configurations(self, &request)
1655            }
1656            "ModifyVpcEndpointServiceConfiguration" => {
1657                endpoint::modify_vpc_endpoint_service_configuration(self, &request)
1658            }
1659            "DescribeVpcEndpointServicePermissions" => {
1660                endpoint::describe_vpc_endpoint_service_permissions(self, &request)
1661            }
1662            "ModifyVpcEndpointServicePermissions" => {
1663                endpoint::modify_vpc_endpoint_service_permissions(self, &request)
1664            }
1665            "ModifyVpcEndpointServicePayerResponsibility" => {
1666                endpoint::modify_vpc_endpoint_service_payer_responsibility(self, &request)
1667            }
1668            "StartVpcEndpointServicePrivateDnsVerification" => {
1669                endpoint::start_vpc_endpoint_service_private_dns_verification(self, &request)
1670            }
1671            "CreateVpcEndpointConnectionNotification" => {
1672                endpoint::create_vpc_endpoint_connection_notification(self, &request)
1673            }
1674            "DeleteVpcEndpointConnectionNotifications" => {
1675                endpoint::delete_vpc_endpoint_connection_notifications(self, &request)
1676            }
1677            "DescribeVpcEndpointConnectionNotifications" => {
1678                endpoint::describe_vpc_endpoint_connection_notifications(self, &request)
1679            }
1680            "ModifyVpcEndpointConnectionNotification" => {
1681                endpoint::modify_vpc_endpoint_connection_notification(self, &request)
1682            }
1683            "DescribeVpcEndpointAssociations" => {
1684                endpoint::describe_vpc_endpoint_associations(self, &request)
1685            }
1686            "CreateFlowLogs" => endpoint::create_flow_logs(self, &request),
1687            "DeleteFlowLogs" => endpoint::delete_flow_logs(self, &request),
1688            "DescribeFlowLogs" => endpoint::describe_flow_logs(self, &request),
1689            "GetFlowLogsIntegrationTemplate" => {
1690                endpoint::get_flow_logs_integration_template(self, &request)
1691            }
1692            "CreateLaunchTemplate" => fleet::create_launch_template(self, &request),
1693            "CreateLaunchTemplateVersion" => fleet::create_launch_template_version(self, &request),
1694            "DeleteLaunchTemplate" => fleet::delete_launch_template(self, &request),
1695            "DeleteLaunchTemplateVersions" => {
1696                fleet::delete_launch_template_versions(self, &request)
1697            }
1698            "DescribeLaunchTemplates" => fleet::describe_launch_templates(self, &request),
1699            "DescribeLaunchTemplateVersions" => {
1700                fleet::describe_launch_template_versions(self, &request)
1701            }
1702            "GetLaunchTemplateData" => fleet::get_launch_template_data(self, &request),
1703            "ModifyLaunchTemplate" => fleet::modify_launch_template(self, &request),
1704            "RequestSpotInstances" => fleet::request_spot_instances(self, &request),
1705            "DescribeSpotInstanceRequests" => {
1706                fleet::describe_spot_instance_requests(self, &request)
1707            }
1708            "CancelSpotInstanceRequests" => fleet::cancel_spot_instance_requests(self, &request),
1709            "RequestSpotFleet" => fleet::request_spot_fleet(self, &request),
1710            "DescribeSpotFleetRequests" => fleet::describe_spot_fleet_requests(self, &request),
1711            "CancelSpotFleetRequests" => fleet::cancel_spot_fleet_requests(self, &request),
1712            "ModifySpotFleetRequest" => fleet::modify_spot_fleet_request(self, &request),
1713            "DescribeSpotFleetInstances" => fleet::describe_spot_fleet_instances(self, &request),
1714            "DescribeSpotFleetRequestHistory" => {
1715                fleet::describe_spot_fleet_request_history(self, &request)
1716            }
1717            "DescribeSpotPriceHistory" => fleet::describe_spot_price_history(self, &request),
1718            "GetSpotPlacementScores" => fleet::get_spot_placement_scores(self, &request),
1719            "CreateSpotDatafeedSubscription" => {
1720                fleet::create_spot_datafeed_subscription(self, &request)
1721            }
1722            "DeleteSpotDatafeedSubscription" => {
1723                fleet::delete_spot_datafeed_subscription(self, &request)
1724            }
1725            "DescribeSpotDatafeedSubscription" => {
1726                fleet::describe_spot_datafeed_subscription(self, &request)
1727            }
1728            "CreateFleet" => fleet::create_fleet(self, &request),
1729            "DeleteFleets" => fleet::delete_fleets(self, &request),
1730            "DescribeFleets" => fleet::describe_fleets(self, &request),
1731            "ModifyFleet" => fleet::modify_fleet(self, &request),
1732            "DescribeFleetHistory" => fleet::describe_fleet_history(self, &request),
1733            "DescribeFleetInstances" => fleet::describe_fleet_instances(self, &request),
1734            "CreateCapacityReservation" => capacity::create_capacity_reservation(self, &request),
1735            "CancelCapacityReservation" => capacity::cancel_capacity_reservation(self, &request),
1736            "DescribeCapacityReservations" => {
1737                capacity::describe_capacity_reservations(self, &request)
1738            }
1739            "ModifyCapacityReservation" => capacity::modify_capacity_reservation(self, &request),
1740            "GetCapacityReservationUsage" => {
1741                capacity::get_capacity_reservation_usage(self, &request)
1742            }
1743            "CreateCapacityReservationFleet" => {
1744                capacity::create_capacity_reservation_fleet(self, &request)
1745            }
1746            "CancelCapacityReservationFleets" => {
1747                capacity::cancel_capacity_reservation_fleets(self, &request)
1748            }
1749            "DescribeCapacityReservationFleets" => {
1750                capacity::describe_capacity_reservation_fleets(self, &request)
1751            }
1752            "ModifyCapacityReservationFleet" => {
1753                capacity::modify_capacity_reservation_fleet(self, &request)
1754            }
1755            "ModifyInstanceCapacityReservationAttributes" => {
1756                capacity::modify_instance_capacity_reservation_attributes(self, &request)
1757            }
1758            "CreateCapacityReservationBySplitting" => {
1759                capacity::create_capacity_reservation_by_splitting(self, &request)
1760            }
1761            "MoveCapacityReservationInstances" => {
1762                capacity::move_capacity_reservation_instances(self, &request)
1763            }
1764            "DescribeCapacityReservationBillingRequests" => {
1765                capacity::describe_capacity_reservation_billing_requests(self, &request)
1766            }
1767            "AssociateCapacityReservationBillingOwner" => {
1768                capacity::associate_capacity_reservation_billing_owner(self, &request)
1769            }
1770            "DisassociateCapacityReservationBillingOwner" => {
1771                capacity::disassociate_capacity_reservation_billing_owner(self, &request)
1772            }
1773            "AcceptCapacityReservationBillingOwnership" => {
1774                capacity::accept_capacity_reservation_billing_ownership(self, &request)
1775            }
1776            "RejectCapacityReservationBillingOwnership" => {
1777                capacity::reject_capacity_reservation_billing_ownership(self, &request)
1778            }
1779            "DescribeCapacityBlockOfferings" => {
1780                capacity::describe_capacity_block_offerings(self, &request)
1781            }
1782            "DescribeCapacityBlocks" => capacity::describe_capacity_blocks(self, &request),
1783            "PurchaseCapacityBlock" => capacity::purchase_capacity_block(self, &request),
1784            "DescribeCapacityBlockStatus" => {
1785                capacity::describe_capacity_block_status(self, &request)
1786            }
1787            "DescribeCapacityBlockExtensionHistory" => {
1788                capacity::describe_capacity_block_extension_history(self, &request)
1789            }
1790            "DescribeCapacityBlockExtensionOfferings" => {
1791                capacity::describe_capacity_block_extension_offerings(self, &request)
1792            }
1793            "PurchaseCapacityBlockExtension" => {
1794                capacity::purchase_capacity_block_extension(self, &request)
1795            }
1796            "DescribeCapacityReservationTopology" => {
1797                capacity::describe_capacity_reservation_topology(self, &request)
1798            }
1799            "CreateInterruptibleCapacityReservationAllocation" => {
1800                capacity::create_interruptible_capacity_reservation_allocation(self, &request)
1801            }
1802            "UpdateInterruptibleCapacityReservationAllocation" => {
1803                capacity::update_interruptible_capacity_reservation_allocation(self, &request)
1804            }
1805            "DescribeReservedInstances" => reserved::describe_reserved_instances(self, &request),
1806            "DescribeReservedInstancesOfferings" => {
1807                reserved::describe_reserved_instances_offerings(self, &request)
1808            }
1809            "PurchaseReservedInstancesOffering" => {
1810                reserved::purchase_reserved_instances_offering(self, &request)
1811            }
1812            "DescribeReservedInstancesListings" => {
1813                reserved::describe_reserved_instances_listings(self, &request)
1814            }
1815            "CreateReservedInstancesListing" => {
1816                reserved::create_reserved_instances_listing(self, &request)
1817            }
1818            "CancelReservedInstancesListing" => {
1819                reserved::cancel_reserved_instances_listing(self, &request)
1820            }
1821            "DescribeReservedInstancesModifications" => {
1822                reserved::describe_reserved_instances_modifications(self, &request)
1823            }
1824            "ModifyReservedInstances" => reserved::modify_reserved_instances(self, &request),
1825            "GetReservedInstancesExchangeQuote" => {
1826                reserved::get_reserved_instances_exchange_quote(self, &request)
1827            }
1828            "AcceptReservedInstancesExchangeQuote" => {
1829                reserved::accept_reserved_instances_exchange_quote(self, &request)
1830            }
1831            "DeleteQueuedReservedInstances" => {
1832                reserved::delete_queued_reserved_instances(self, &request)
1833            }
1834            "AllocateHosts" => reserved::allocate_hosts(self, &request),
1835            "DescribeHosts" => reserved::describe_hosts(self, &request),
1836            "ModifyHosts" => reserved::modify_hosts(self, &request),
1837            "ReleaseHosts" => reserved::release_hosts(self, &request),
1838            "DescribeMacHosts" => reserved::describe_mac_hosts(self, &request),
1839            "CreateTransitGateway" => tgw::create_transit_gateway(self, &request),
1840            "DeleteTransitGateway" => tgw::delete_transit_gateway(self, &request),
1841            "DescribeTransitGateways" => tgw::describe_transit_gateways(self, &request),
1842            "ModifyTransitGateway" => tgw::modify_transit_gateway(self, &request),
1843            "CreateTransitGatewayVpcAttachment" => {
1844                tgw::create_transit_gateway_vpc_attachment(self, &request)
1845            }
1846            "DeleteTransitGatewayVpcAttachment" => {
1847                tgw::delete_transit_gateway_vpc_attachment(self, &request)
1848            }
1849            "DescribeTransitGatewayVpcAttachments" => {
1850                tgw::describe_transit_gateway_vpc_attachments(self, &request)
1851            }
1852            "ModifyTransitGatewayVpcAttachment" => {
1853                tgw::modify_transit_gateway_vpc_attachment(self, &request)
1854            }
1855            "AcceptTransitGatewayVpcAttachment" => {
1856                tgw::accept_transit_gateway_vpc_attachment(self, &request)
1857            }
1858            "RejectTransitGatewayVpcAttachment" => {
1859                tgw::reject_transit_gateway_vpc_attachment(self, &request)
1860            }
1861            "DescribeTransitGatewayAttachments" => {
1862                tgw::describe_transit_gateway_attachments(self, &request)
1863            }
1864            "CreateTransitGatewayRouteTable" => {
1865                tgw::create_transit_gateway_route_table(self, &request)
1866            }
1867            "DeleteTransitGatewayRouteTable" => {
1868                tgw::delete_transit_gateway_route_table(self, &request)
1869            }
1870            "DescribeTransitGatewayRouteTables" => {
1871                tgw::describe_transit_gateway_route_tables(self, &request)
1872            }
1873            "AssociateTransitGatewayRouteTable" => {
1874                tgw::associate_transit_gateway_route_table(self, &request)
1875            }
1876            "DisassociateTransitGatewayRouteTable" => {
1877                tgw::disassociate_transit_gateway_route_table(self, &request)
1878            }
1879            "EnableTransitGatewayRouteTablePropagation" => {
1880                tgw::enable_transit_gateway_route_table_propagation(self, &request)
1881            }
1882            "DisableTransitGatewayRouteTablePropagation" => {
1883                tgw::disable_transit_gateway_route_table_propagation(self, &request)
1884            }
1885            "CreateTransitGatewayRoute" => tgw::create_transit_gateway_route(self, &request),
1886            "DeleteTransitGatewayRoute" => tgw::delete_transit_gateway_route(self, &request),
1887            "ReplaceTransitGatewayRoute" => tgw::replace_transit_gateway_route(self, &request),
1888            "SearchTransitGatewayRoutes" => tgw::search_transit_gateway_routes(self, &request),
1889            "ExportTransitGatewayRoutes" => tgw::export_transit_gateway_routes(self, &request),
1890            "GetTransitGatewayRouteTableAssociations" => {
1891                tgw::get_transit_gateway_route_table_associations(self, &request)
1892            }
1893            "GetTransitGatewayRouteTablePropagations" => {
1894                tgw::get_transit_gateway_route_table_propagations(self, &request)
1895            }
1896            "GetTransitGatewayAttachmentPropagations" => {
1897                tgw::get_transit_gateway_attachment_propagations(self, &request)
1898            }
1899            "CreateTransitGatewayPrefixListReference" => {
1900                tgw::create_transit_gateway_prefix_list_reference(self, &request)
1901            }
1902            "DeleteTransitGatewayPrefixListReference" => {
1903                tgw::delete_transit_gateway_prefix_list_reference(self, &request)
1904            }
1905            "ModifyTransitGatewayPrefixListReference" => {
1906                tgw::modify_transit_gateway_prefix_list_reference(self, &request)
1907            }
1908            "GetTransitGatewayPrefixListReferences" => {
1909                tgw::get_transit_gateway_prefix_list_references(self, &request)
1910            }
1911            "CreateTransitGatewayPeeringAttachment" => {
1912                tgw_peering::create_transit_gateway_peering_attachment(self, &request)
1913            }
1914            "DeleteTransitGatewayPeeringAttachment" => {
1915                tgw_peering::delete_transit_gateway_peering_attachment(self, &request)
1916            }
1917            "DescribeTransitGatewayPeeringAttachments" => {
1918                tgw_peering::describe_transit_gateway_peering_attachments(self, &request)
1919            }
1920            "AcceptTransitGatewayPeeringAttachment" => {
1921                tgw_peering::accept_transit_gateway_peering_attachment(self, &request)
1922            }
1923            "RejectTransitGatewayPeeringAttachment" => {
1924                tgw_peering::reject_transit_gateway_peering_attachment(self, &request)
1925            }
1926            "CreateTransitGatewayConnect" => {
1927                tgw_peering::create_transit_gateway_connect(self, &request)
1928            }
1929            "DeleteTransitGatewayConnect" => {
1930                tgw_peering::delete_transit_gateway_connect(self, &request)
1931            }
1932            "DescribeTransitGatewayConnects" => {
1933                tgw_peering::describe_transit_gateway_connects(self, &request)
1934            }
1935            "CreateTransitGatewayConnectPeer" => {
1936                tgw_peering::create_transit_gateway_connect_peer(self, &request)
1937            }
1938            "DeleteTransitGatewayConnectPeer" => {
1939                tgw_peering::delete_transit_gateway_connect_peer(self, &request)
1940            }
1941            "DescribeTransitGatewayConnectPeers" => {
1942                tgw_peering::describe_transit_gateway_connect_peers(self, &request)
1943            }
1944            "CreateTransitGatewayPolicyTable" => {
1945                tgw_peering::create_transit_gateway_policy_table(self, &request)
1946            }
1947            "DeleteTransitGatewayPolicyTable" => {
1948                tgw_peering::delete_transit_gateway_policy_table(self, &request)
1949            }
1950            "DescribeTransitGatewayPolicyTables" => {
1951                tgw_peering::describe_transit_gateway_policy_tables(self, &request)
1952            }
1953            "AssociateTransitGatewayPolicyTable" => {
1954                tgw_peering::associate_transit_gateway_policy_table(self, &request)
1955            }
1956            "DisassociateTransitGatewayPolicyTable" => {
1957                tgw_peering::disassociate_transit_gateway_policy_table(self, &request)
1958            }
1959            "GetTransitGatewayPolicyTableAssociations" => {
1960                tgw_peering::get_transit_gateway_policy_table_associations(self, &request)
1961            }
1962            "GetTransitGatewayPolicyTableEntries" => {
1963                tgw_peering::get_transit_gateway_policy_table_entries(self, &request)
1964            }
1965            "CreateTransitGatewayRouteTableAnnouncement" => {
1966                tgw_peering::create_transit_gateway_route_table_announcement(self, &request)
1967            }
1968            "DeleteTransitGatewayRouteTableAnnouncement" => {
1969                tgw_peering::delete_transit_gateway_route_table_announcement(self, &request)
1970            }
1971            "DescribeTransitGatewayRouteTableAnnouncements" => {
1972                tgw_peering::describe_transit_gateway_route_table_announcements(self, &request)
1973            }
1974            "CreateTransitGatewayMulticastDomain" => {
1975                tgw_mcast::create_transit_gateway_multicast_domain(self, &request)
1976            }
1977            "DeleteTransitGatewayMulticastDomain" => {
1978                tgw_mcast::delete_transit_gateway_multicast_domain(self, &request)
1979            }
1980            "DescribeTransitGatewayMulticastDomains" => {
1981                tgw_mcast::describe_transit_gateway_multicast_domains(self, &request)
1982            }
1983            "AssociateTransitGatewayMulticastDomain" => {
1984                tgw_mcast::associate_transit_gateway_multicast_domain(self, &request)
1985            }
1986            "DisassociateTransitGatewayMulticastDomain" => {
1987                tgw_mcast::disassociate_transit_gateway_multicast_domain(self, &request)
1988            }
1989            "AcceptTransitGatewayMulticastDomainAssociations" => {
1990                tgw_mcast::accept_transit_gateway_multicast_domain_associations(self, &request)
1991            }
1992            "RejectTransitGatewayMulticastDomainAssociations" => {
1993                tgw_mcast::reject_transit_gateway_multicast_domain_associations(self, &request)
1994            }
1995            "GetTransitGatewayMulticastDomainAssociations" => {
1996                tgw_mcast::get_transit_gateway_multicast_domain_associations(self, &request)
1997            }
1998            "RegisterTransitGatewayMulticastGroupMembers" => {
1999                tgw_mcast::register_transit_gateway_multicast_group_members(self, &request)
2000            }
2001            "RegisterTransitGatewayMulticastGroupSources" => {
2002                tgw_mcast::register_transit_gateway_multicast_group_sources(self, &request)
2003            }
2004            "DeregisterTransitGatewayMulticastGroupMembers" => {
2005                tgw_mcast::deregister_transit_gateway_multicast_group_members(self, &request)
2006            }
2007            "DeregisterTransitGatewayMulticastGroupSources" => {
2008                tgw_mcast::deregister_transit_gateway_multicast_group_sources(self, &request)
2009            }
2010            "SearchTransitGatewayMulticastGroups" => {
2011                tgw_mcast::search_transit_gateway_multicast_groups(self, &request)
2012            }
2013            "CreateTransitGatewayMeteringPolicy" => {
2014                tgw_mcast::create_transit_gateway_metering_policy(self, &request)
2015            }
2016            "DeleteTransitGatewayMeteringPolicy" => {
2017                tgw_mcast::delete_transit_gateway_metering_policy(self, &request)
2018            }
2019            "DescribeTransitGatewayMeteringPolicies" => {
2020                tgw_mcast::describe_transit_gateway_metering_policies(self, &request)
2021            }
2022            "ModifyTransitGatewayMeteringPolicy" => {
2023                tgw_mcast::modify_transit_gateway_metering_policy(self, &request)
2024            }
2025            "CreateTransitGatewayMeteringPolicyEntry" => {
2026                tgw_mcast::create_transit_gateway_metering_policy_entry(self, &request)
2027            }
2028            "DeleteTransitGatewayMeteringPolicyEntry" => {
2029                tgw_mcast::delete_transit_gateway_metering_policy_entry(self, &request)
2030            }
2031            "GetTransitGatewayMeteringPolicyEntries" => {
2032                tgw_mcast::get_transit_gateway_metering_policy_entries(self, &request)
2033            }
2034            "AcceptTransitGatewayClientVpnAttachment" => {
2035                tgw_mcast::accept_transit_gateway_client_vpn_attachment(self, &request)
2036            }
2037            "DeleteTransitGatewayClientVpnAttachment" => {
2038                tgw_mcast::delete_transit_gateway_client_vpn_attachment(self, &request)
2039            }
2040            "RejectTransitGatewayClientVpnAttachment" => {
2041                tgw_mcast::reject_transit_gateway_client_vpn_attachment(self, &request)
2042            }
2043            "CreateCustomerGateway" => vpn::create_customer_gateway(self, &request),
2044            "DeleteCustomerGateway" => vpn::delete_customer_gateway(self, &request),
2045            "DescribeCustomerGateways" => vpn::describe_customer_gateways(self, &request),
2046            "CreateVpnGateway" => vpn::create_vpn_gateway(self, &request),
2047            "DeleteVpnGateway" => vpn::delete_vpn_gateway(self, &request),
2048            "DescribeVpnGateways" => vpn::describe_vpn_gateways(self, &request),
2049            "AttachVpnGateway" => vpn::attach_vpn_gateway(self, &request),
2050            "DetachVpnGateway" => vpn::detach_vpn_gateway(self, &request),
2051            "CreateVpnConnection" => vpn::create_vpn_connection(self, &request),
2052            "DeleteVpnConnection" => vpn::delete_vpn_connection(self, &request),
2053            "DescribeVpnConnections" => vpn::describe_vpn_connections(self, &request),
2054            "ModifyVpnConnection" => vpn::modify_vpn_connection(self, &request),
2055            "ModifyVpnConnectionOptions" => vpn::modify_vpn_connection_options(self, &request),
2056            "CreateVpnConnectionRoute" => vpn::create_vpn_connection_route(self, &request),
2057            "DeleteVpnConnectionRoute" => vpn::delete_vpn_connection_route(self, &request),
2058            "ModifyVpnTunnelOptions" => vpn::modify_vpn_tunnel_options(self, &request),
2059            "ModifyVpnTunnelCertificate" => vpn::modify_vpn_tunnel_certificate(self, &request),
2060            "ReplaceVpnTunnel" => vpn::replace_vpn_tunnel(self, &request),
2061            "GetActiveVpnTunnelStatus" => vpn::get_active_vpn_tunnel_status(self, &request),
2062            "GetVpnTunnelReplacementStatus" => {
2063                vpn::get_vpn_tunnel_replacement_status(self, &request)
2064            }
2065            "GetVpnConnectionDeviceTypes" => vpn::get_vpn_connection_device_types(self, &request),
2066            "GetVpnConnectionDeviceSampleConfiguration" => {
2067                vpn::get_vpn_connection_device_sample_configuration(self, &request)
2068            }
2069            "CreateVpnConcentrator" => vpn::create_vpn_concentrator(self, &request),
2070            "DeleteVpnConcentrator" => vpn::delete_vpn_concentrator(self, &request),
2071            "DescribeVpnConcentrators" => vpn::describe_vpn_concentrators(self, &request),
2072            "CreateClientVpnEndpoint" => cvpn::create_client_vpn_endpoint(self, &request),
2073            "DeleteClientVpnEndpoint" => cvpn::delete_client_vpn_endpoint(self, &request),
2074            "DescribeClientVpnEndpoints" => cvpn::describe_client_vpn_endpoints(self, &request),
2075            "ModifyClientVpnEndpoint" => cvpn::modify_client_vpn_endpoint(self, &request),
2076            "CreateClientVpnRoute" => cvpn::create_client_vpn_route(self, &request),
2077            "DeleteClientVpnRoute" => cvpn::delete_client_vpn_route(self, &request),
2078            "DescribeClientVpnRoutes" => cvpn::describe_client_vpn_routes(self, &request),
2079            "AuthorizeClientVpnIngress" => cvpn::authorize_client_vpn_ingress(self, &request),
2080            "RevokeClientVpnIngress" => cvpn::revoke_client_vpn_ingress(self, &request),
2081            "DescribeClientVpnAuthorizationRules" => {
2082                cvpn::describe_client_vpn_authorization_rules(self, &request)
2083            }
2084            "AssociateClientVpnTargetNetwork" => {
2085                cvpn::associate_client_vpn_target_network(self, &request)
2086            }
2087            "DisassociateClientVpnTargetNetwork" => {
2088                cvpn::disassociate_client_vpn_target_network(self, &request)
2089            }
2090            "DescribeClientVpnTargetNetworks" => {
2091                cvpn::describe_client_vpn_target_networks(self, &request)
2092            }
2093            "ApplySecurityGroupsToClientVpnTargetNetwork" => {
2094                cvpn::apply_security_groups_to_client_vpn_target_network(self, &request)
2095            }
2096            "DescribeClientVpnConnections" => cvpn::describe_client_vpn_connections(self, &request),
2097            "TerminateClientVpnConnections" => {
2098                cvpn::terminate_client_vpn_connections(self, &request)
2099            }
2100            "ExportClientVpnClientCertificateRevocationList" => {
2101                cvpn::export_client_vpn_client_certificate_revocation_list(self, &request)
2102            }
2103            "ExportClientVpnClientConfiguration" => {
2104                cvpn::export_client_vpn_client_configuration(self, &request)
2105            }
2106            "ImportClientVpnClientCertificateRevocationList" => {
2107                cvpn::import_client_vpn_client_certificate_revocation_list(self, &request)
2108            }
2109            "CreateIpam" => ipam::create_ipam(self, &request),
2110            "DeleteIpam" => ipam::delete_ipam(self, &request),
2111            "DescribeIpams" => ipam::describe_ipams(self, &request),
2112            "ModifyIpam" => ipam::modify_ipam(self, &request),
2113            "CreateIpamScope" => ipam::create_ipam_scope(self, &request),
2114            "DeleteIpamScope" => ipam::delete_ipam_scope(self, &request),
2115            "DescribeIpamScopes" => ipam::describe_ipam_scopes(self, &request),
2116            "ModifyIpamScope" => ipam::modify_ipam_scope(self, &request),
2117            "CreateIpamPool" => ipam::create_ipam_pool(self, &request),
2118            "DeleteIpamPool" => ipam::delete_ipam_pool(self, &request),
2119            "DescribeIpamPools" => ipam::describe_ipam_pools(self, &request),
2120            "ModifyIpamPool" => ipam::modify_ipam_pool(self, &request),
2121            "ProvisionIpamPoolCidr" => ipam::provision_ipam_pool_cidr(self, &request),
2122            "DeprovisionIpamPoolCidr" => ipam::deprovision_ipam_pool_cidr(self, &request),
2123            "GetIpamPoolCidrs" => ipam::get_ipam_pool_cidrs(self, &request),
2124            "AllocateIpamPoolCidr" => ipam::allocate_ipam_pool_cidr(self, &request),
2125            "ReleaseIpamPoolAllocation" => ipam::release_ipam_pool_allocation(self, &request),
2126            "GetIpamPoolAllocations" => ipam::get_ipam_pool_allocations(self, &request),
2127            "GetIpamResourceCidrs" => ipam::get_ipam_resource_cidrs(self, &request),
2128            "ModifyIpamResourceCidr" => ipam::modify_ipam_resource_cidr(self, &request),
2129            "GetIpamAddressHistory" => ipam::get_ipam_address_history(self, &request),
2130            "EnableIpamOrganizationAdminAccount" => {
2131                ipam::enable_ipam_organization_admin_account(self, &request)
2132            }
2133            "DisableIpamOrganizationAdminAccount" => {
2134                ipam::disable_ipam_organization_admin_account(self, &request)
2135            }
2136            "CreateIpamResourceDiscovery" => {
2137                ipam_discovery::create_ipam_resource_discovery(self, &request)
2138            }
2139            "DeleteIpamResourceDiscovery" => {
2140                ipam_discovery::delete_ipam_resource_discovery(self, &request)
2141            }
2142            "DescribeIpamResourceDiscoveries" => {
2143                ipam_discovery::describe_ipam_resource_discoveries(self, &request)
2144            }
2145            "ModifyIpamResourceDiscovery" => {
2146                ipam_discovery::modify_ipam_resource_discovery(self, &request)
2147            }
2148            "AssociateIpamResourceDiscovery" => {
2149                ipam_discovery::associate_ipam_resource_discovery(self, &request)
2150            }
2151            "DisassociateIpamResourceDiscovery" => {
2152                ipam_discovery::disassociate_ipam_resource_discovery(self, &request)
2153            }
2154            "DescribeIpamResourceDiscoveryAssociations" => {
2155                ipam_discovery::describe_ipam_resource_discovery_associations(self, &request)
2156            }
2157            "GetIpamDiscoveredAccounts" => {
2158                ipam_discovery::get_ipam_discovered_accounts(self, &request)
2159            }
2160            "GetIpamDiscoveredPublicAddresses" => {
2161                ipam_discovery::get_ipam_discovered_public_addresses(self, &request)
2162            }
2163            "GetIpamDiscoveredResourceCidrs" => {
2164                ipam_discovery::get_ipam_discovered_resource_cidrs(self, &request)
2165            }
2166            "AssociateIpamByoasn" => ipam_discovery::associate_ipam_byoasn(self, &request),
2167            "DisassociateIpamByoasn" => ipam_discovery::disassociate_ipam_byoasn(self, &request),
2168            "ProvisionIpamByoasn" => ipam_discovery::provision_ipam_byoasn(self, &request),
2169            "DeprovisionIpamByoasn" => ipam_discovery::deprovision_ipam_byoasn(self, &request),
2170            "DescribeIpamByoasn" => ipam_discovery::describe_ipam_byoasn(self, &request),
2171            "MoveByoipCidrToIpam" => ipam_discovery::move_byoip_cidr_to_ipam(self, &request),
2172            "CreateIpamExternalResourceVerificationToken" => {
2173                ipam_discovery::create_ipam_external_resource_verification_token(self, &request)
2174            }
2175            "DeleteIpamExternalResourceVerificationToken" => {
2176                ipam_discovery::delete_ipam_external_resource_verification_token(self, &request)
2177            }
2178            "DescribeIpamExternalResourceVerificationTokens" => {
2179                ipam_discovery::describe_ipam_external_resource_verification_tokens(self, &request)
2180            }
2181            "CreateIpamPolicy" => ipam_policy::create_ipam_policy(self, &request),
2182            "DeleteIpamPolicy" => ipam_policy::delete_ipam_policy(self, &request),
2183            "DescribeIpamPolicies" => ipam_policy::describe_ipam_policies(self, &request),
2184            "EnableIpamPolicy" => ipam_policy::enable_ipam_policy(self, &request),
2185            "DisableIpamPolicy" => ipam_policy::disable_ipam_policy(self, &request),
2186            "GetEnabledIpamPolicy" => ipam_policy::get_enabled_ipam_policy(self, &request),
2187            "GetIpamPolicyAllocationRules" => {
2188                ipam_policy::get_ipam_policy_allocation_rules(self, &request)
2189            }
2190            "ModifyIpamPolicyAllocationRules" => {
2191                ipam_policy::modify_ipam_policy_allocation_rules(self, &request)
2192            }
2193            "GetIpamPolicyOrganizationTargets" => {
2194                ipam_policy::get_ipam_policy_organization_targets(self, &request)
2195            }
2196            "CreateIpamPrefixListResolver" => {
2197                ipam_policy::create_ipam_prefix_list_resolver(self, &request)
2198            }
2199            "DeleteIpamPrefixListResolver" => {
2200                ipam_policy::delete_ipam_prefix_list_resolver(self, &request)
2201            }
2202            "DescribeIpamPrefixListResolvers" => {
2203                ipam_policy::describe_ipam_prefix_list_resolvers(self, &request)
2204            }
2205            "ModifyIpamPrefixListResolver" => {
2206                ipam_policy::modify_ipam_prefix_list_resolver(self, &request)
2207            }
2208            "CreateIpamPrefixListResolverTarget" => {
2209                ipam_policy::create_ipam_prefix_list_resolver_target(self, &request)
2210            }
2211            "DeleteIpamPrefixListResolverTarget" => {
2212                ipam_policy::delete_ipam_prefix_list_resolver_target(self, &request)
2213            }
2214            "DescribeIpamPrefixListResolverTargets" => {
2215                ipam_policy::describe_ipam_prefix_list_resolver_targets(self, &request)
2216            }
2217            "ModifyIpamPrefixListResolverTarget" => {
2218                ipam_policy::modify_ipam_prefix_list_resolver_target(self, &request)
2219            }
2220            "GetIpamPrefixListResolverRules" => {
2221                ipam_policy::get_ipam_prefix_list_resolver_rules(self, &request)
2222            }
2223            "GetIpamPrefixListResolverVersions" => {
2224                ipam_policy::get_ipam_prefix_list_resolver_versions(self, &request)
2225            }
2226            "GetIpamPrefixListResolverVersionEntries" => {
2227                ipam_policy::get_ipam_prefix_list_resolver_version_entries(self, &request)
2228            }
2229            "CreateVerifiedAccessInstance" => va::create_verified_access_instance(self, &request),
2230            "DeleteVerifiedAccessInstance" => va::delete_verified_access_instance(self, &request),
2231            "DescribeVerifiedAccessInstances" => {
2232                va::describe_verified_access_instances(self, &request)
2233            }
2234            "ModifyVerifiedAccessInstance" => va::modify_verified_access_instance(self, &request),
2235            "CreateVerifiedAccessTrustProvider" => {
2236                va::create_verified_access_trust_provider(self, &request)
2237            }
2238            "DeleteVerifiedAccessTrustProvider" => {
2239                va::delete_verified_access_trust_provider(self, &request)
2240            }
2241            "DescribeVerifiedAccessTrustProviders" => {
2242                va::describe_verified_access_trust_providers(self, &request)
2243            }
2244            "ModifyVerifiedAccessTrustProvider" => {
2245                va::modify_verified_access_trust_provider(self, &request)
2246            }
2247            "AttachVerifiedAccessTrustProvider" => {
2248                va::attach_verified_access_trust_provider(self, &request)
2249            }
2250            "DetachVerifiedAccessTrustProvider" => {
2251                va::detach_verified_access_trust_provider(self, &request)
2252            }
2253            "CreateVerifiedAccessGroup" => va::create_verified_access_group(self, &request),
2254            "DeleteVerifiedAccessGroup" => va::delete_verified_access_group(self, &request),
2255            "DescribeVerifiedAccessGroups" => va::describe_verified_access_groups(self, &request),
2256            "ModifyVerifiedAccessGroup" => va::modify_verified_access_group(self, &request),
2257            "GetVerifiedAccessGroupPolicy" => va::get_verified_access_group_policy(self, &request),
2258            "ModifyVerifiedAccessGroupPolicy" => {
2259                va::modify_verified_access_group_policy(self, &request)
2260            }
2261            "CreateVerifiedAccessEndpoint" => va::create_verified_access_endpoint(self, &request),
2262            "DeleteVerifiedAccessEndpoint" => va::delete_verified_access_endpoint(self, &request),
2263            "DescribeVerifiedAccessEndpoints" => {
2264                va::describe_verified_access_endpoints(self, &request)
2265            }
2266            "ModifyVerifiedAccessEndpoint" => va::modify_verified_access_endpoint(self, &request),
2267            "GetVerifiedAccessEndpointPolicy" => {
2268                va::get_verified_access_endpoint_policy(self, &request)
2269            }
2270            "ModifyVerifiedAccessEndpointPolicy" => {
2271                va::modify_verified_access_endpoint_policy(self, &request)
2272            }
2273            "GetVerifiedAccessEndpointTargets" => {
2274                va::get_verified_access_endpoint_targets(self, &request)
2275            }
2276            "DescribeVerifiedAccessInstanceLoggingConfigurations" => {
2277                va::describe_verified_access_instance_logging_configurations(self, &request)
2278            }
2279            "ModifyVerifiedAccessInstanceLoggingConfiguration" => {
2280                va::modify_verified_access_instance_logging_configuration(self, &request)
2281            }
2282            "ExportVerifiedAccessInstanceClientConfiguration" => {
2283                va::export_verified_access_instance_client_configuration(self, &request)
2284            }
2285            "CreateNetworkInsightsPath" => ni::create_network_insights_path(self, &request),
2286            "DeleteNetworkInsightsPath" => ni::delete_network_insights_path(self, &request),
2287            "DescribeNetworkInsightsPaths" => ni::describe_network_insights_paths(self, &request),
2288            "StartNetworkInsightsAnalysis" => ni::start_network_insights_analysis(self, &request),
2289            "DeleteNetworkInsightsAnalysis" => ni::delete_network_insights_analysis(self, &request),
2290            "DescribeNetworkInsightsAnalyses" => {
2291                ni::describe_network_insights_analyses(self, &request)
2292            }
2293            "CreateNetworkInsightsAccessScope" => {
2294                ni::create_network_insights_access_scope(self, &request)
2295            }
2296            "DeleteNetworkInsightsAccessScope" => {
2297                ni::delete_network_insights_access_scope(self, &request)
2298            }
2299            "DescribeNetworkInsightsAccessScopes" => {
2300                ni::describe_network_insights_access_scopes(self, &request)
2301            }
2302            "GetNetworkInsightsAccessScopeContent" => {
2303                ni::get_network_insights_access_scope_content(self, &request)
2304            }
2305            "StartNetworkInsightsAccessScopeAnalysis" => {
2306                ni::start_network_insights_access_scope_analysis(self, &request)
2307            }
2308            "DeleteNetworkInsightsAccessScopeAnalysis" => {
2309                ni::delete_network_insights_access_scope_analysis(self, &request)
2310            }
2311            "DescribeNetworkInsightsAccessScopeAnalyses" => {
2312                ni::describe_network_insights_access_scope_analyses(self, &request)
2313            }
2314            "GetNetworkInsightsAccessScopeAnalysisFindings" => {
2315                ni::get_network_insights_access_scope_analysis_findings(self, &request)
2316            }
2317            "CreateCarrierGateway" => lgw::create_carrier_gateway(self, &request),
2318            "DeleteCarrierGateway" => lgw::delete_carrier_gateway(self, &request),
2319            "DescribeCarrierGateways" => lgw::describe_carrier_gateways(self, &request),
2320            "CreateCoipPool" => lgw::create_coip_pool(self, &request),
2321            "DeleteCoipPool" => lgw::delete_coip_pool(self, &request),
2322            "DescribeCoipPools" => lgw::describe_coip_pools(self, &request),
2323            "CreateCoipCidr" => lgw::create_coip_cidr(self, &request),
2324            "DeleteCoipCidr" => lgw::delete_coip_cidr(self, &request),
2325            "GetCoipPoolUsage" => lgw::get_coip_pool_usage(self, &request),
2326            "CreateLocalGatewayRouteTable" => lgw::create_local_gateway_route_table(self, &request),
2327            "DeleteLocalGatewayRouteTable" => lgw::delete_local_gateway_route_table(self, &request),
2328            "DescribeLocalGatewayRouteTables" => {
2329                lgw::describe_local_gateway_route_tables(self, &request)
2330            }
2331            "CreateLocalGatewayRoute" => lgw::create_local_gateway_route(self, &request),
2332            "DeleteLocalGatewayRoute" => lgw::delete_local_gateway_route(self, &request),
2333            "ModifyLocalGatewayRoute" => lgw::modify_local_gateway_route(self, &request),
2334            "SearchLocalGatewayRoutes" => lgw::search_local_gateway_routes(self, &request),
2335            "CreateLocalGatewayRouteTableVpcAssociation" => {
2336                lgw::create_local_gateway_route_table_vpc_association(self, &request)
2337            }
2338            "DeleteLocalGatewayRouteTableVpcAssociation" => {
2339                lgw::delete_local_gateway_route_table_vpc_association(self, &request)
2340            }
2341            "DescribeLocalGatewayRouteTableVpcAssociations" => {
2342                lgw::describe_local_gateway_route_table_vpc_associations(self, &request)
2343            }
2344            "CreateLocalGatewayVirtualInterface" => {
2345                lgw::create_local_gateway_virtual_interface(self, &request)
2346            }
2347            "DeleteLocalGatewayVirtualInterface" => {
2348                lgw::delete_local_gateway_virtual_interface(self, &request)
2349            }
2350            "DescribeLocalGatewayVirtualInterfaces" => {
2351                lgw::describe_local_gateway_virtual_interfaces(self, &request)
2352            }
2353            "CreateLocalGatewayVirtualInterfaceGroup" => {
2354                lgw::create_local_gateway_virtual_interface_group(self, &request)
2355            }
2356            "DeleteLocalGatewayVirtualInterfaceGroup" => {
2357                lgw::delete_local_gateway_virtual_interface_group(self, &request)
2358            }
2359            "DescribeLocalGatewayVirtualInterfaceGroups" => {
2360                lgw::describe_local_gateway_virtual_interface_groups(self, &request)
2361            }
2362            "CreateLocalGatewayRouteTableVirtualInterfaceGroupAssociation" => {
2363                lgw::create_local_gateway_route_table_virtual_interface_group_association(
2364                    self, &request,
2365                )
2366            }
2367            "DeleteLocalGatewayRouteTableVirtualInterfaceGroupAssociation" => {
2368                lgw::delete_local_gateway_route_table_virtual_interface_group_association(
2369                    self, &request,
2370                )
2371            }
2372            "DescribeLocalGatewayRouteTableVirtualInterfaceGroupAssociations" => {
2373                lgw::describe_local_gateway_route_table_virtual_interface_group_associations(
2374                    self, &request,
2375                )
2376            }
2377            "DescribeLocalGateways" => lgw::describe_local_gateways(self, &request),
2378            "CreateInstanceConnectEndpoint" => {
2379                ice::create_instance_connect_endpoint(self, &request)
2380            }
2381            "DeleteInstanceConnectEndpoint" => {
2382                ice::delete_instance_connect_endpoint(self, &request)
2383            }
2384            "DescribeInstanceConnectEndpoints" => {
2385                ice::describe_instance_connect_endpoints(self, &request)
2386            }
2387            "ModifyInstanceConnectEndpoint" => {
2388                ice::modify_instance_connect_endpoint(self, &request)
2389            }
2390            "EnableFastLaunch" => ice::enable_fast_launch(self, &request),
2391            "DisableFastLaunch" => ice::disable_fast_launch(self, &request),
2392            "EnableSerialConsoleAccess" => ice::enable_serial_console_access(self, &request),
2393            "DisableSerialConsoleAccess" => ice::disable_serial_console_access(self, &request),
2394            "GetSerialConsoleAccessStatus" => ice::get_serial_console_access_status(self, &request),
2395            "GetConsoleOutput" => ice::get_console_output(self, &request).await,
2396            "GetConsoleScreenshot" => ice::get_console_screenshot(self, &request),
2397            "GetPasswordData" => ice::get_password_data(self, &request),
2398            "AdvertiseByoipCidr" => rest::advertise_byoip_cidr(self, &request),
2399            "AssociateEnclaveCertificateIamRole" => {
2400                rest::associate_enclave_certificate_iam_role(self, &request)
2401            }
2402            "AssociateIamInstanceProfile" => rest::associate_iam_instance_profile(self, &request),
2403            "AssociateInstanceEventWindow" => rest::associate_instance_event_window(self, &request),
2404            "AssociateRouteServer" => rest::associate_route_server(self, &request),
2405            "AssociateTrunkInterface" => rest::associate_trunk_interface(self, &request),
2406            "AttachClassicLinkVpc" => rest::attach_classic_link_vpc(self, &request),
2407            "BundleInstance" => rest::bundle_instance(self, &request),
2408            "CancelBundleTask" => rest::cancel_bundle_task(self, &request),
2409            "CancelConversionTask" => rest::cancel_conversion_task(self, &request),
2410            "CancelDeclarativePoliciesReport" => {
2411                rest::cancel_declarative_policies_report(self, &request)
2412            }
2413            "CancelExportTask" => rest::cancel_export_task(self, &request),
2414            "CancelImportTask" => rest::cancel_import_task(self, &request),
2415            "ConfirmProductInstance" => rest::confirm_product_instance(self, &request),
2416            "CopyFpgaImage" => rest::copy_fpga_image(self, &request),
2417            "CopyVolumes" => rest::copy_volumes(self, &request),
2418            "CreateCapacityManagerDataExport" => {
2419                rest::create_capacity_manager_data_export(self, &request)
2420            }
2421            "CreateDelegateMacVolumeOwnershipTask" => {
2422                rest::create_delegate_mac_volume_ownership_task(self, &request)
2423            }
2424            "CreateFpgaImage" => rest::create_fpga_image(self, &request),
2425            "CreateImageUsageReport" => rest::create_image_usage_report(self, &request),
2426            "CreateInstanceEventWindow" => rest::create_instance_event_window(self, &request),
2427            "CreateInstanceExportTask" => rest::create_instance_export_task(self, &request),
2428            "CreateMacSystemIntegrityProtectionModificationTask" => {
2429                rest::create_mac_system_integrity_protection_modification_task(self, &request)
2430            }
2431            "CreateManagedPrefixList" => rest::create_managed_prefix_list(self, &request),
2432            "CreatePublicIpv4Pool" => rest::create_public_ipv4_pool(self, &request),
2433            "CreateReplaceRootVolumeTask" => rest::create_replace_root_volume_task(self, &request),
2434            "CreateRouteServer" => rest::create_route_server(self, &request),
2435            "CreateRouteServerEndpoint" => rest::create_route_server_endpoint(self, &request),
2436            "CreateRouteServerPeer" => rest::create_route_server_peer(self, &request),
2437            "CreateSecondaryNetwork" => rest::create_secondary_network(self, &request),
2438            "CreateTrafficMirrorFilter" => rest::create_traffic_mirror_filter(self, &request),
2439            "CreateTrafficMirrorFilterRule" => {
2440                rest::create_traffic_mirror_filter_rule(self, &request)
2441            }
2442            "CreateTrafficMirrorSession" => rest::create_traffic_mirror_session(self, &request),
2443            "CreateTrafficMirrorTarget" => rest::create_traffic_mirror_target(self, &request),
2444            "CreateVpcBlockPublicAccessExclusion" => {
2445                rest::create_vpc_block_public_access_exclusion(self, &request)
2446            }
2447            "CreateVpcEncryptionControl" => rest::create_vpc_encryption_control(self, &request),
2448            "DeleteCapacityManagerDataExport" => {
2449                rest::delete_capacity_manager_data_export(self, &request)
2450            }
2451            "DeleteFpgaImage" => rest::delete_fpga_image(self, &request),
2452            "DeleteImageUsageReport" => rest::delete_image_usage_report(self, &request),
2453            "DeleteInstanceEventWindow" => rest::delete_instance_event_window(self, &request),
2454            "DeleteManagedPrefixList" => rest::delete_managed_prefix_list(self, &request),
2455            "DeletePublicIpv4Pool" => rest::delete_public_ipv4_pool(self, &request),
2456            "DeleteRouteServer" => rest::delete_route_server(self, &request),
2457            "DeleteRouteServerEndpoint" => rest::delete_route_server_endpoint(self, &request),
2458            "DeleteRouteServerPeer" => rest::delete_route_server_peer(self, &request),
2459            "DeleteSecondaryNetwork" => rest::delete_secondary_network(self, &request),
2460            "DeleteTrafficMirrorFilter" => rest::delete_traffic_mirror_filter(self, &request),
2461            "DeleteTrafficMirrorFilterRule" => {
2462                rest::delete_traffic_mirror_filter_rule(self, &request)
2463            }
2464            "DeleteTrafficMirrorSession" => rest::delete_traffic_mirror_session(self, &request),
2465            "DeleteTrafficMirrorTarget" => rest::delete_traffic_mirror_target(self, &request),
2466            "DeleteVpcBlockPublicAccessExclusion" => {
2467                rest::delete_vpc_block_public_access_exclusion(self, &request)
2468            }
2469            "DeleteVpcEncryptionControl" => rest::delete_vpc_encryption_control(self, &request),
2470            "DeprovisionByoipCidr" => rest::deprovision_byoip_cidr(self, &request),
2471            "DeprovisionPublicIpv4PoolCidr" => {
2472                rest::deprovision_public_ipv4_pool_cidr(self, &request)
2473            }
2474            "DescribeAggregateIdFormat" => rest::describe_aggregate_id_format(self, &request),
2475            "DescribeAwsNetworkPerformanceMetricSubscriptions" => {
2476                rest::describe_aws_network_performance_metric_subscriptions(self, &request)
2477            }
2478            "DescribeBundleTasks" => rest::describe_bundle_tasks(self, &request),
2479            "DescribeByoipCidrs" => rest::describe_byoip_cidrs(self, &request),
2480            "DescribeCapacityManagerDataExports" => {
2481                rest::describe_capacity_manager_data_exports(self, &request)
2482            }
2483            "DescribeClassicLinkInstances" => rest::describe_classic_link_instances(self, &request),
2484            "DescribeConversionTasks" => rest::describe_conversion_tasks(self, &request),
2485            "DescribeDeclarativePoliciesReports" => {
2486                rest::describe_declarative_policies_reports(self, &request)
2487            }
2488            "DescribeElasticGpus" => rest::describe_elastic_gpus(self, &request),
2489            "DescribeExportImageTasks" => rest::describe_export_image_tasks(self, &request),
2490            "DescribeExportTasks" => rest::describe_export_tasks(self, &request),
2491            "DescribeFpgaImageAttribute" => rest::describe_fpga_image_attribute(self, &request),
2492            "DescribeFpgaImages" => rest::describe_fpga_images(self, &request),
2493            "DescribeHostReservationOfferings" => {
2494                rest::describe_host_reservation_offerings(self, &request)
2495            }
2496            "DescribeHostReservations" => rest::describe_host_reservations(self, &request),
2497            "DescribeIamInstanceProfileAssociations" => {
2498                rest::describe_iam_instance_profile_associations(self, &request)
2499            }
2500            "DescribeIdFormat" => rest::describe_id_format(self, &request),
2501            "DescribeIdentityIdFormat" => rest::describe_identity_id_format(self, &request),
2502            "DescribeImageReferences" => rest::describe_image_references(self, &request),
2503            "DescribeImageUsageReportEntries" => {
2504                rest::describe_image_usage_report_entries(self, &request)
2505            }
2506            "DescribeImageUsageReports" => rest::describe_image_usage_reports(self, &request),
2507            "DescribeImportImageTasks" => rest::describe_import_image_tasks(self, &request),
2508            "DescribeImportSnapshotTasks" => rest::describe_import_snapshot_tasks(self, &request),
2509            "DescribeInstanceEventWindows" => rest::describe_instance_event_windows(self, &request),
2510            "DescribeInstanceImageMetadata" => {
2511                rest::describe_instance_image_metadata(self, &request)
2512            }
2513            "DescribeInstanceSqlHaHistoryStates" => {
2514                rest::describe_instance_sql_ha_history_states(self, &request)
2515            }
2516            "DescribeInstanceSqlHaStates" => rest::describe_instance_sql_ha_states(self, &request),
2517            "DescribeInstanceTypeOfferings" => {
2518                rest::describe_instance_type_offerings(self, &request)
2519            }
2520            "DescribeIpv6Pools" => rest::describe_ipv6_pools(self, &request),
2521            "DescribeMacModificationTasks" => rest::describe_mac_modification_tasks(self, &request),
2522            "DescribeManagedPrefixLists" => rest::describe_managed_prefix_lists(self, &request),
2523            "DescribeOutpostLags" => rest::describe_outpost_lags(self, &request),
2524            "DescribePrefixLists" => rest::describe_prefix_lists(self, &request),
2525            "DescribePrincipalIdFormat" => rest::describe_principal_id_format(self, &request),
2526            "DescribePublicIpv4Pools" => rest::describe_public_ipv4_pools(self, &request),
2527            "DescribeReplaceRootVolumeTasks" => {
2528                rest::describe_replace_root_volume_tasks(self, &request)
2529            }
2530            "DescribeRouteServerEndpoints" => rest::describe_route_server_endpoints(self, &request),
2531            "DescribeRouteServerPeers" => rest::describe_route_server_peers(self, &request),
2532            "DescribeRouteServers" => rest::describe_route_servers(self, &request),
2533            "DescribeScheduledInstanceAvailability" => {
2534                rest::describe_scheduled_instance_availability(self, &request)
2535            }
2536            "DescribeScheduledInstances" => rest::describe_scheduled_instances(self, &request),
2537            "DescribeSecondaryInterfaces" => rest::describe_secondary_interfaces(self, &request),
2538            "DescribeSecondaryNetworks" => rest::describe_secondary_networks(self, &request),
2539            "DescribeServiceLinkVirtualInterfaces" => {
2540                rest::describe_service_link_virtual_interfaces(self, &request)
2541            }
2542            "DescribeTrafficMirrorFilterRules" => {
2543                rest::describe_traffic_mirror_filter_rules(self, &request)
2544            }
2545            "DescribeTrafficMirrorFilters" => rest::describe_traffic_mirror_filters(self, &request),
2546            "DescribeTrafficMirrorSessions" => {
2547                rest::describe_traffic_mirror_sessions(self, &request)
2548            }
2549            "DescribeTrafficMirrorTargets" => rest::describe_traffic_mirror_targets(self, &request),
2550            "DescribeTrunkInterfaceAssociations" => {
2551                rest::describe_trunk_interface_associations(self, &request)
2552            }
2553            "DescribeVpcBlockPublicAccessExclusions" => {
2554                rest::describe_vpc_block_public_access_exclusions(self, &request)
2555            }
2556            "DescribeVpcBlockPublicAccessOptions" => {
2557                rest::describe_vpc_block_public_access_options(self, &request)
2558            }
2559            "DescribeVpcClassicLink" => rest::describe_vpc_classic_link(self, &request),
2560            "DescribeVpcClassicLinkDnsSupport" => {
2561                rest::describe_vpc_classic_link_dns_support(self, &request)
2562            }
2563            "DescribeVpcEncryptionControls" => {
2564                rest::describe_vpc_encryption_controls(self, &request)
2565            }
2566            "DetachClassicLinkVpc" => rest::detach_classic_link_vpc(self, &request),
2567            "DisableAwsNetworkPerformanceMetricSubscription" => {
2568                rest::disable_aws_network_performance_metric_subscription(self, &request)
2569            }
2570            "DisableCapacityManager" => rest::disable_capacity_manager(self, &request),
2571            "DisableInstanceSqlHaStandbyDetections" => {
2572                rest::disable_instance_sql_ha_standby_detections(self, &request)
2573            }
2574            "DisableRouteServerPropagation" => {
2575                rest::disable_route_server_propagation(self, &request)
2576            }
2577            "DisableVgwRoutePropagation" => rest::disable_vgw_route_propagation(self, &request),
2578            "DisableVpcClassicLink" => rest::disable_vpc_classic_link(self, &request),
2579            "DisableVpcClassicLinkDnsSupport" => {
2580                rest::disable_vpc_classic_link_dns_support(self, &request)
2581            }
2582            "DisassociateEnclaveCertificateIamRole" => {
2583                rest::disassociate_enclave_certificate_iam_role(self, &request)
2584            }
2585            "DisassociateIamInstanceProfile" => {
2586                rest::disassociate_iam_instance_profile(self, &request)
2587            }
2588            "DisassociateInstanceEventWindow" => {
2589                rest::disassociate_instance_event_window(self, &request)
2590            }
2591            "DisassociateRouteServer" => rest::disassociate_route_server(self, &request),
2592            "DisassociateTrunkInterface" => rest::disassociate_trunk_interface(self, &request),
2593            "EnableAwsNetworkPerformanceMetricSubscription" => {
2594                rest::enable_aws_network_performance_metric_subscription(self, &request)
2595            }
2596            "EnableCapacityManager" => rest::enable_capacity_manager(self, &request),
2597            "EnableInstanceSqlHaStandbyDetections" => {
2598                rest::enable_instance_sql_ha_standby_detections(self, &request)
2599            }
2600            "EnableReachabilityAnalyzerOrganizationSharing" => {
2601                rest::enable_reachability_analyzer_organization_sharing(self, &request)
2602            }
2603            "EnableRouteServerPropagation" => rest::enable_route_server_propagation(self, &request),
2604            "EnableVgwRoutePropagation" => rest::enable_vgw_route_propagation(self, &request),
2605            "EnableVpcClassicLink" => rest::enable_vpc_classic_link(self, &request),
2606            "EnableVpcClassicLinkDnsSupport" => {
2607                rest::enable_vpc_classic_link_dns_support(self, &request)
2608            }
2609            "ExportImage" => rest::export_image(self, &request),
2610            "GetAssociatedEnclaveCertificateIamRoles" => {
2611                rest::get_associated_enclave_certificate_iam_roles(self, &request)
2612            }
2613            "GetAssociatedIpv6PoolCidrs" => rest::get_associated_ipv6_pool_cidrs(self, &request),
2614            "GetAwsNetworkPerformanceData" => {
2615                rest::get_aws_network_performance_data(self, &request)
2616            }
2617            "GetCapacityManagerAttributes" => rest::get_capacity_manager_attributes(self, &request),
2618            "GetCapacityManagerMetricData" => {
2619                rest::get_capacity_manager_metric_data(self, &request)
2620            }
2621            "GetCapacityManagerMetricDimensions" => {
2622                rest::get_capacity_manager_metric_dimensions(self, &request)
2623            }
2624            "GetCapacityManagerMonitoredTagKeys" => {
2625                rest::get_capacity_manager_monitored_tag_keys(self, &request)
2626            }
2627            "GetDeclarativePoliciesReportSummary" => {
2628                rest::get_declarative_policies_report_summary(self, &request)
2629            }
2630            "GetDefaultCreditSpecification" => {
2631                rest::get_default_credit_specification(self, &request)
2632            }
2633            "GetHostReservationPurchasePreview" => {
2634                rest::get_host_reservation_purchase_preview(self, &request)
2635            }
2636            "GetImageAncestry" => rest::get_image_ancestry(self, &request),
2637            "GetInstanceTpmEkPub" => rest::get_instance_tpm_ek_pub(self, &request),
2638            "GetInstanceUefiData" => rest::get_instance_uefi_data(self, &request),
2639            "GetManagedPrefixListAssociations" => {
2640                rest::get_managed_prefix_list_associations(self, &request)
2641            }
2642            "GetManagedPrefixListEntries" => rest::get_managed_prefix_list_entries(self, &request),
2643            "GetManagedResourceVisibility" => rest::get_managed_resource_visibility(self, &request),
2644            "GetRouteServerAssociations" => rest::get_route_server_associations(self, &request),
2645            "GetRouteServerPropagations" => rest::get_route_server_propagations(self, &request),
2646            "GetRouteServerRoutingDatabase" => {
2647                rest::get_route_server_routing_database(self, &request)
2648            }
2649            "GetVpcResourcesBlockingEncryptionEnforcement" => {
2650                rest::get_vpc_resources_blocking_encryption_enforcement(self, &request)
2651            }
2652            "ImportImage" => rest::import_image(self, &request),
2653            "ImportInstance" => rest::import_instance(self, &request),
2654            "ImportSnapshot" => rest::import_snapshot(self, &request),
2655            "ImportVolume" => rest::import_volume(self, &request),
2656            "ModifyAvailabilityZoneGroup" => rest::modify_availability_zone_group(self, &request),
2657            "ModifyDefaultCreditSpecification" => {
2658                rest::modify_default_credit_specification(self, &request)
2659            }
2660            "ModifyFpgaImageAttribute" => rest::modify_fpga_image_attribute(self, &request),
2661            "ModifyIdFormat" => rest::modify_id_format(self, &request),
2662            "ModifyIdentityIdFormat" => rest::modify_identity_id_format(self, &request),
2663            "ModifyInstanceEventWindow" => rest::modify_instance_event_window(self, &request),
2664            "ModifyManagedPrefixList" => rest::modify_managed_prefix_list(self, &request),
2665            "ModifyManagedResourceVisibility" => {
2666                rest::modify_managed_resource_visibility(self, &request)
2667            }
2668            "ModifyPrivateDnsNameOptions" => rest::modify_private_dns_name_options(self, &request),
2669            "ModifyPublicIpDnsNameOptions" => {
2670                rest::modify_public_ip_dns_name_options(self, &request)
2671            }
2672            "ModifyRouteServer" => rest::modify_route_server(self, &request),
2673            "ModifyTrafficMirrorFilterNetworkServices" => {
2674                rest::modify_traffic_mirror_filter_network_services(self, &request)
2675            }
2676            "ModifyTrafficMirrorFilterRule" => {
2677                rest::modify_traffic_mirror_filter_rule(self, &request)
2678            }
2679            "ModifyTrafficMirrorSession" => rest::modify_traffic_mirror_session(self, &request),
2680            "ModifyVpcBlockPublicAccessExclusion" => {
2681                rest::modify_vpc_block_public_access_exclusion(self, &request)
2682            }
2683            "ModifyVpcBlockPublicAccessOptions" => {
2684                rest::modify_vpc_block_public_access_options(self, &request)
2685            }
2686            "ModifyVpcEncryptionControl" => rest::modify_vpc_encryption_control(self, &request),
2687            "ProvisionByoipCidr" => rest::provision_byoip_cidr(self, &request),
2688            "ProvisionPublicIpv4PoolCidr" => rest::provision_public_ipv4_pool_cidr(self, &request),
2689            "PurchaseHostReservation" => rest::purchase_host_reservation(self, &request),
2690            "PurchaseScheduledInstances" => rest::purchase_scheduled_instances(self, &request),
2691            "ReplaceIamInstanceProfileAssociation" => {
2692                rest::replace_iam_instance_profile_association(self, &request)
2693            }
2694            "ResetFpgaImageAttribute" => rest::reset_fpga_image_attribute(self, &request),
2695            "RestoreManagedPrefixListVersion" => {
2696                rest::restore_managed_prefix_list_version(self, &request)
2697            }
2698            "RunScheduledInstances" => rest::run_scheduled_instances(self, &request),
2699            "SendDiagnosticInterrupt" => rest::send_diagnostic_interrupt(self, &request),
2700            "StartDeclarativePoliciesReport" => {
2701                rest::start_declarative_policies_report(self, &request)
2702            }
2703            "UpdateCapacityManagerMonitoredTagKeys" => {
2704                rest::update_capacity_manager_monitored_tag_keys(self, &request)
2705            }
2706            "UpdateCapacityManagerOrganizationsAccess" => {
2707                rest::update_capacity_manager_organizations_access(self, &request)
2708            }
2709            "WithdrawByoipCidr" => rest::withdraw_byoip_cidr(self, &request),
2710            // Model ops absent from the vendored SDK client; tested via raw query.
2711            "CreateCapacityReservationCancellationQuote" => {
2712                rest::create_capacity_reservation_cancellation_quote(self, &request)
2713            }
2714            "DescribeCapacityReservationCancellationQuotes" => {
2715                rest::describe_capacity_reservation_cancellation_quotes(self, &request)
2716            }
2717            "DescribeIpamPoolAllocations" => rest::describe_ipam_pool_allocations(self, &request),
2718            "ModifyIpamPoolAllocation" => rest::modify_ipam_pool_allocation(self, &request),
2719            "DescribeAccountVpcEncryptionControl" => {
2720                rest::describe_account_vpc_encryption_control(self, &request)
2721            }
2722            "ModifyAccountVpcEncryptionControl" => {
2723                rest::modify_account_vpc_encryption_control(self, &request)
2724            }
2725            "ModifyVpcEndpointPayerResponsibility" => {
2726                endpoint::modify_vpc_endpoint_payer_responsibility(self, &request)
2727            }
2728            other => Err(AwsServiceError::aws_error(
2729                StatusCode::BAD_REQUEST,
2730                "InvalidAction",
2731                format!("The action {other} is not valid for this web service."),
2732            )),
2733        };
2734        if mutates && matches!(result.as_ref(), Ok(resp) if resp.status.is_success()) {
2735            self.save_snapshot().await;
2736        }
2737        result
2738    }
2739}
2740
2741impl Ec2Service {
2742    /// Render an `ec2Query` response for `action` with `body` as the inner XML.
2743    pub(crate) fn respond(action: &str, request_id: &str, body: &str) -> AwsResponse {
2744        AwsResponse::xml(
2745            StatusCode::OK,
2746            fakecloud_aws::ec2query::ec2_response(action, request_id, body),
2747        )
2748    }
2749}
2750
2751#[cfg(test)]
2752mod recover_guard_tests {
2753    use super::recovery_terminal_wins;
2754
2755    // A minimal stand-in for the `state_code`/`state_name` fields the recovery
2756    // closure mutates. Kept independent of the full `Instance` struct so this
2757    // regression stays pinned to the guard behavior, not to unrelated field
2758    // churn (the struct-field repo-wide-ctor hazard).
2759    struct Row {
2760        state_code: i64,
2761        state_name: &'static str,
2762    }
2763
2764    // Boot-success arm of `recover_persisted_containers`, driven by the guard.
2765    // Returns whether the just-started container must be reaped.
2766    fn apply_boot_success(row: &mut Row) -> bool {
2767        if recovery_terminal_wins(row.state_code) {
2768            true
2769        } else {
2770            row.state_code = 16;
2771            row.state_name = "running";
2772            false
2773        }
2774    }
2775
2776    // Boot-failure arm of `recover_persisted_containers`, driven by the guard.
2777    fn apply_boot_failure(row: &mut Row) -> bool {
2778        if recovery_terminal_wins(row.state_code) {
2779            false
2780        } else {
2781            row.state_code = 80;
2782            row.state_name = "stopped";
2783            false
2784        }
2785    }
2786
2787    // Instance state codes: 0 pending, 16 running, 48 terminated, 80 stopped.
2788    #[test]
2789    fn terminal_states_win_over_recovery() {
2790        assert!(recovery_terminal_wins(48), "terminated wins");
2791        assert!(recovery_terminal_wins(80), "stopped wins");
2792        assert!(!recovery_terminal_wins(16), "running is recoverable");
2793        assert!(!recovery_terminal_wins(0), "pending is recoverable");
2794    }
2795
2796    #[test]
2797    fn boot_success_does_not_resurrect_concurrent_stop() {
2798        // Concurrent StopInstances set code 80 during the recovery window.
2799        let mut row = Row {
2800            state_code: 80,
2801            state_name: "stopped",
2802        };
2803        let reap = apply_boot_success(&mut row);
2804        assert!(reap, "the just-started container must be reaped");
2805        assert_eq!(row.state_code, 80, "stop must not be clobbered to running");
2806        assert_eq!(row.state_name, "stopped");
2807    }
2808
2809    #[test]
2810    fn boot_failure_does_not_clobber_concurrent_terminate() {
2811        // Concurrent TerminateInstances set code 48 during the recovery window,
2812        // and the backing container failed to boot.
2813        let mut row = Row {
2814            state_code: 48,
2815            state_name: "terminated",
2816        };
2817        let reap = apply_boot_failure(&mut row);
2818        assert!(!reap, "boot failed: nothing to reap");
2819        assert_eq!(
2820            row.state_code, 48,
2821            "terminate must not be overwritten to stopped"
2822        );
2823        assert_eq!(row.state_name, "terminated");
2824    }
2825
2826    #[test]
2827    fn boot_success_recovers_a_still_pending_instance() {
2828        // No concurrent op: a persisted pending row recovers to running.
2829        let mut row = Row {
2830            state_code: 0,
2831            state_name: "pending",
2832        };
2833        let reap = apply_boot_success(&mut row);
2834        assert!(!reap);
2835        assert_eq!(row.state_code, 16, "pending recovers to running");
2836        assert_eq!(row.state_name, "running");
2837    }
2838
2839    #[test]
2840    fn boot_failure_stops_a_still_pending_instance() {
2841        // No concurrent op, boot failed: a pending row is marked stopped.
2842        let mut row = Row {
2843            state_code: 0,
2844            state_name: "pending",
2845        };
2846        let reap = apply_boot_failure(&mut row);
2847        assert!(!reap);
2848        assert_eq!(row.state_code, 80, "failed boot marks stopped");
2849    }
2850}
2851
2852#[cfg(test)]
2853mod recover_persist_tests {
2854    use super::*;
2855    use crate::state::Instance;
2856
2857    /// Captures the last serialized snapshot (into a shared buffer the test also
2858    /// holds) so a recovery flush is observable.
2859    struct RecordingStore(Arc<std::sync::Mutex<Option<Vec<u8>>>>);
2860    impl SnapshotStore for RecordingStore {
2861        fn load(&self) -> std::io::Result<Option<Vec<u8>>> {
2862            Ok(None)
2863        }
2864        fn save(&self, bytes: &[u8]) -> std::io::Result<()> {
2865            *self.0.lock().unwrap() = Some(bytes.to_vec());
2866            Ok(())
2867        }
2868    }
2869
2870    fn pending_instance(id: &str) -> Instance {
2871        Instance {
2872            instance_id: id.into(),
2873            image_id: "ami-1".into(),
2874            instance_type: "t3.micro".into(),
2875            // state_code 0 == pending: a persisted mid-boot instance.
2876            state_code: 0,
2877            state_name: "pending".into(),
2878            private_ip: "10.0.0.5".into(),
2879            public_ip: None,
2880            subnet_id: None,
2881            vpc_id: Some("vpc-1".into()),
2882            key_name: None,
2883            security_group_ids: vec![],
2884            reservation_id: "r-1".into(),
2885            ami_launch_index: 0,
2886            monitoring: false,
2887            az: "us-east-1a".into(),
2888            launch_time: "2024-01-01T00:00:00.000Z".into(),
2889            container_id: None,
2890            disable_api_termination: false,
2891            disable_api_stop: false,
2892            source_dest_check: true,
2893            ebs_optimized: false,
2894            instance_initiated_shutdown_behavior: "stop".into(),
2895            user_data: None,
2896            metadata_options: Default::default(),
2897            cpu_options: None,
2898            bandwidth_weighting: None,
2899            maintenance_options: Default::default(),
2900            placement_tenancy: None,
2901            placement_affinity: None,
2902            placement_group_name: None,
2903            private_dns_hostname_type: None,
2904            enable_resource_name_dns_a_record: false,
2905            enable_resource_name_dns_aaaa_record: false,
2906        }
2907    }
2908
2909    /// Restart recovery must persist the recovered fleet, not just fix it in
2910    /// memory. Exercised via the metadata-only recovery path (reachable without
2911    /// a container runtime): a persisted `pending` instance is flipped to
2912    /// `running` AND the snapshot is flushed so a subsequent restart doesn't
2913    /// re-drive recovery from stale data. Same persist-after-recover guarantee
2914    /// the runtime-backed path now honours.
2915    #[tokio::test]
2916    async fn recovery_persists_recovered_state() {
2917        let recorded = Arc::new(std::sync::Mutex::new(None));
2918        let svc = Ec2Service::new().with_snapshot_store(Arc::new(RecordingStore(recorded.clone())));
2919        {
2920            let mut accounts = svc.state.write();
2921            let state = accounts.get_or_create("000000000000");
2922            state
2923                .instances
2924                .insert("i-1".into(), pending_instance("i-1"));
2925        }
2926
2927        // No runtime wired -> metadata-only recovery, which flips pending
2928        // instances to running and persists.
2929        svc.recover_persisted_containers().await;
2930
2931        // In-memory state recovered to running.
2932        {
2933            let accounts = svc.state.read();
2934            let inst = accounts
2935                .get("000000000000")
2936                .unwrap()
2937                .instances
2938                .get("i-1")
2939                .unwrap();
2940            assert_eq!(inst.state_code, 16);
2941            assert_eq!(inst.state_name, "running");
2942        }
2943
2944        // ...and that recovered state was flushed to the snapshot store.
2945        let bytes = recorded
2946            .lock()
2947            .unwrap()
2948            .clone()
2949            .expect("recovery should have flushed a snapshot");
2950        let snap: crate::Ec2Snapshot = serde_json::from_slice(&bytes).unwrap();
2951        let persisted = snap.accounts.expect("accounts present");
2952        let inst = persisted
2953            .get("000000000000")
2954            .unwrap()
2955            .instances
2956            .get("i-1")
2957            .unwrap();
2958        assert_eq!(
2959            inst.state_code, 16,
2960            "persisted snapshot must reflect the recovered running state"
2961        );
2962    }
2963}