Skip to main content

fakecloud_ssm/service/
mod.rs

1mod associations;
2mod automation;
3mod commands;
4mod compliance;
5mod documents;
6mod instances;
7mod inventory;
8mod maintenance;
9mod misc;
10mod ops;
11mod parameters;
12mod patches;
13mod resource_sync;
14mod sessions;
15mod tags;
16
17use std::sync::Arc;
18
19use async_trait::async_trait;
20use http::StatusCode;
21use tokio::sync::Mutex as AsyncMutex;
22
23use fakecloud_core::service::{AwsRequest, AwsResponse, AwsService, AwsServiceError};
24use fakecloud_persistence::SnapshotStore;
25
26use crate::state::{SharedSsmState, SsmSnapshot, SSM_SNAPSHOT_SCHEMA_VERSION};
27
28use fakecloud_secretsmanager::SharedSecretsManagerState;
29
30const PARAMETER_VERSION_LIMIT: i64 = 100;
31
32pub struct SsmService {
33    state: SharedSsmState,
34    secretsmanager_state: Option<SharedSecretsManagerState>,
35    snapshot_store: Option<Arc<dyn SnapshotStore>>,
36    snapshot_lock: Arc<AsyncMutex<()>>,
37    pub(crate) kms_hook: Option<Arc<dyn fakecloud_core::delivery::KmsHook>>,
38}
39
40impl SsmService {
41    pub fn new(state: SharedSsmState) -> Self {
42        Self {
43            state,
44            secretsmanager_state: None,
45            snapshot_store: None,
46            snapshot_lock: Arc::new(AsyncMutex::new(())),
47            kms_hook: None,
48        }
49    }
50
51    pub fn with_secretsmanager(mut self, sm_state: SharedSecretsManagerState) -> Self {
52        self.secretsmanager_state = Some(sm_state);
53        self
54    }
55
56    pub fn with_snapshot_store(mut self, store: Arc<dyn SnapshotStore>) -> Self {
57        self.snapshot_store = Some(store);
58        self
59    }
60
61    pub fn with_kms_hook(mut self, hook: Arc<dyn fakecloud_core::delivery::KmsHook>) -> Self {
62        self.kms_hook = Some(hook);
63        self
64    }
65
66    /// Admin: force a SendCommand result to a specific terminal status
67    /// (e.g. "Failed", "Cancelled", "TimedOut"). Used by tests to
68    /// simulate command failures without waiting on a real SSM agent.
69    /// All invocations on the command move to the same status so
70    /// `GetCommandInvocation` reflects the override on the next read.
71    /// Returns `true` when the command was found and updated.
72    pub fn set_command_status(&self, account_id: &str, command_id: &str, status: &str) -> bool {
73        let mut accounts = self.state.write();
74        let state = accounts.get_or_create(account_id);
75        if let Some(c) = state
76            .commands
77            .iter_mut()
78            .find(|c| c.command_id == command_id)
79        {
80            let now = chrono::Utc::now();
81            let details = commands::friendly_status_details(status);
82            for inv in c.invocations.iter_mut() {
83                inv.status = status.to_string();
84                inv.status_details = details.clone();
85                inv.response_code = match status {
86                    "Success" => 0,
87                    "Pending" | "InProgress" | "Delayed" => -1,
88                    _ => 1,
89                };
90                inv.last_update_at = now;
91            }
92            c.status = status.to_string();
93            return true;
94        }
95        false
96    }
97
98    /// Admin: force a single invocation (or all if `instance_id` is
99    /// `None`) to `Failed` with optional friendlier `status_details`
100    /// and `standard_error_content` overrides. Mirrors what a real SSM
101    /// agent would report when a runShellScript step exits non-zero.
102    /// Returns the number of invocations that were updated.
103    pub fn fail_command_invocation(
104        &self,
105        account_id: &str,
106        command_id: &str,
107        instance_id: Option<&str>,
108        status_details: Option<&str>,
109        standard_error_content: Option<&str>,
110    ) -> usize {
111        let mut accounts = self.state.write();
112        let state = accounts.get_or_create(account_id);
113        let Some(cmd) = state
114            .commands
115            .iter_mut()
116            .find(|c| c.command_id == command_id)
117        else {
118            return 0;
119        };
120        let now = chrono::Utc::now();
121        let mut updated = 0;
122        for inv in cmd.invocations.iter_mut() {
123            if let Some(iid) = instance_id {
124                if inv.instance_id != iid {
125                    continue;
126                }
127            }
128            inv.status = "Failed".to_string();
129            inv.status_details = status_details
130                .map(|s| s.to_string())
131                .unwrap_or_else(|| commands::friendly_status_details("Failed"));
132            if let Some(err) = standard_error_content {
133                inv.standard_error_content = err.to_string();
134            }
135            inv.response_code = 1;
136            inv.last_update_at = now;
137            updated += 1;
138        }
139        if updated > 0 {
140            cmd.status = commands::aggregate_command_status(&cmd.invocations);
141        }
142        updated
143    }
144
145    /// Admin: read out the parameter-policy event log for the given
146    /// account. Used by tests to verify that Expiration deletions and
147    /// notification windows actually fired without standing up an
148    /// EventBridge target. Reads also tick the lazy policy evaluator so
149    /// callers don't have to issue a Get* call first.
150    pub fn parameter_policy_events(
151        &self,
152        account_id: &str,
153    ) -> Vec<crate::state::ParameterPolicyEvent> {
154        let mut accounts = self.state.write();
155        let state = accounts.get_or_create(account_id);
156        parameters::purge_expired_params(state);
157        parameters::tick_policy_notifications(state);
158        state.parameter_policy_events.clone()
159    }
160
161    /// Admin: drop the recorded parameter-policy event log for the
162    /// given account. Tests use this to reset between assertions.
163    pub fn clear_parameter_policy_events(&self, account_id: &str) {
164        let mut accounts = self.state.write();
165        let state = accounts.get_or_create(account_id);
166        state.parameter_policy_events.clear();
167    }
168
169    /// Admin: inject a fake SSM session record so DescribeSessions /
170    /// TerminateSession round-trip without going through StartSession (which
171    /// returns the Smithy-declared `TargetNotConnected` unless
172    /// `FAKECLOUD_SSM_SESSION_ECHO=1`). The injected
173    /// session is otherwise indistinguishable from one created by StartSession
174    /// in echo mode. Returns the assigned `SessionId`.
175    #[allow(clippy::too_many_arguments)]
176    pub fn inject_session(
177        &self,
178        account_id: &str,
179        target: &str,
180        status: Option<&str>,
181        owner: Option<&str>,
182        reason: Option<&str>,
183        session_id: Option<&str>,
184    ) -> String {
185        let now = chrono::Utc::now();
186        let mut accounts = self.state.write();
187        let state = accounts.get_or_create(account_id);
188        let id = match session_id {
189            Some(s) if !s.is_empty() => s.to_string(),
190            _ => {
191                state.session_counter += 1;
192                format!("session-{:012x}", state.session_counter)
193            }
194        };
195        let resolved_status = status.unwrap_or("Connected").to_string();
196        let end_date = if resolved_status == "Terminated" {
197            Some(now)
198        } else {
199            None
200        };
201        let resolved_owner = owner.map(|s| s.to_string()).unwrap_or_else(|| {
202            fakecloud_aws::arn::Arn::global("iam", &state.account_id, "root").to_string()
203        });
204        let session = crate::state::SsmSession {
205            session_id: id.clone(),
206            target: target.to_string(),
207            status: resolved_status,
208            start_date: now,
209            end_date,
210            owner: resolved_owner,
211            reason: reason.map(|s| s.to_string()),
212        };
213        state.sessions.insert(id.clone(), session);
214        id
215    }
216
217    /// Persist current state as a snapshot. Held across the
218    /// clone-serialize-write sequence to prevent stale-last writes,
219    /// with serde + file I/O offloaded to the blocking pool.
220    async fn save_snapshot(&self) {
221        let Some(store) = self.snapshot_store.clone() else {
222            return;
223        };
224        let _guard = self.snapshot_lock.lock().await;
225        let snapshot = SsmSnapshot {
226            schema_version: SSM_SNAPSHOT_SCHEMA_VERSION,
227            state: None,
228            accounts: Some(self.state.read().clone()),
229        };
230        let join = tokio::task::spawn_blocking(move || -> std::io::Result<()> {
231            let bytes = serde_json::to_vec(&snapshot)
232                .map_err(|e| std::io::Error::new(std::io::ErrorKind::InvalidData, e.to_string()))?;
233            store.save(&bytes)
234        })
235        .await;
236        match join {
237            Ok(Ok(())) => {}
238            Ok(Err(err)) => tracing::error!(%err, "failed to write ssm snapshot"),
239            Err(err) => tracing::error!(%err, "ssm snapshot task panicked"),
240        }
241    }
242}
243
244#[async_trait]
245impl AwsService for SsmService {
246    fn service_name(&self) -> &str {
247        "ssm"
248    }
249
250    async fn handle(&self, req: AwsRequest) -> Result<AwsResponse, AwsServiceError> {
251        let mutates = !is_read_only_action(req.action.as_str());
252        let result = match req.action.as_str() {
253            "PutParameter" => self.put_parameter(&req),
254            "GetParameter" => self.get_parameter(&req),
255            "GetParameters" => self.get_parameters(&req),
256            "GetParametersByPath" => self.get_parameters_by_path(&req),
257            "DeleteParameter" => self.delete_parameter(&req),
258            "DeleteParameters" => self.delete_parameters(&req),
259            "DescribeParameters" => self.describe_parameters(&req),
260            "GetParameterHistory" => self.get_parameter_history(&req),
261            "AddTagsToResource" => self.add_tags_to_resource(&req),
262            "RemoveTagsFromResource" => self.remove_tags_from_resource(&req),
263            "ListTagsForResource" => self.list_tags_for_resource(&req),
264            "LabelParameterVersion" => self.label_parameter_version(&req),
265            "UnlabelParameterVersion" => self.unlabel_parameter_version(&req),
266            "CreateDocument" => self.create_document(&req),
267            "GetDocument" => self.get_document(&req),
268            "DeleteDocument" => self.delete_document(&req),
269            "UpdateDocument" => self.update_document(&req),
270            "DescribeDocument" => self.describe_document(&req),
271            "UpdateDocumentDefaultVersion" => self.update_document_default_version(&req),
272            "ListDocuments" => self.list_documents(&req),
273            "DescribeDocumentPermission" => self.describe_document_permission(&req),
274            "ModifyDocumentPermission" => self.modify_document_permission(&req),
275            "SendCommand" => self.send_command(&req),
276            "ListCommands" => self.list_commands(&req),
277            "GetCommandInvocation" => self.get_command_invocation(&req),
278            "ListCommandInvocations" => self.list_command_invocations(&req),
279            "CancelCommand" => self.cancel_command(&req),
280            "CreateMaintenanceWindow" => self.create_maintenance_window(&req),
281            "DescribeMaintenanceWindows" => self.describe_maintenance_windows(&req),
282            "GetMaintenanceWindow" => self.get_maintenance_window(&req),
283            "DeleteMaintenanceWindow" => self.delete_maintenance_window(&req),
284            "UpdateMaintenanceWindow" => self.update_maintenance_window(&req),
285            "RegisterTargetWithMaintenanceWindow" => {
286                self.register_target_with_maintenance_window(&req)
287            }
288            "DeregisterTargetFromMaintenanceWindow" => {
289                self.deregister_target_from_maintenance_window(&req)
290            }
291            "DescribeMaintenanceWindowTargets" => self.describe_maintenance_window_targets(&req),
292            "RegisterTaskWithMaintenanceWindow" => self.register_task_with_maintenance_window(&req),
293            "DeregisterTaskFromMaintenanceWindow" => {
294                self.deregister_task_from_maintenance_window(&req)
295            }
296            "DescribeMaintenanceWindowTasks" => self.describe_maintenance_window_tasks(&req),
297            "CreatePatchBaseline" => self.create_patch_baseline(&req),
298            "DeletePatchBaseline" => self.delete_patch_baseline(&req),
299            "DescribePatchBaselines" => self.describe_patch_baselines(&req),
300            "GetPatchBaseline" => self.get_patch_baseline(&req),
301            "RegisterPatchBaselineForPatchGroup" => {
302                self.register_patch_baseline_for_patch_group(&req)
303            }
304            "DeregisterPatchBaselineForPatchGroup" => {
305                self.deregister_patch_baseline_for_patch_group(&req)
306            }
307            "GetPatchBaselineForPatchGroup" => self.get_patch_baseline_for_patch_group(&req),
308            "DescribePatchGroups" => self.describe_patch_groups(&req),
309            // Associations
310            "CreateAssociation" => self.create_association(&req),
311            "DescribeAssociation" => self.describe_association(&req),
312            "DeleteAssociation" => self.delete_association(&req),
313            "ListAssociations" => self.list_associations(&req),
314            "UpdateAssociation" => self.update_association(&req),
315            "ListAssociationVersions" => self.list_association_versions(&req),
316            "UpdateAssociationStatus" => self.update_association_status(&req),
317            "StartAssociationsOnce" => self.start_associations_once(&req),
318            "CreateAssociationBatch" => self.create_association_batch(&req),
319            "DescribeAssociationExecutions" => self.describe_association_executions(&req),
320            "DescribeAssociationExecutionTargets" => {
321                self.describe_association_execution_targets(&req)
322            }
323            // OpsItems
324            "CreateOpsItem" => self.create_ops_item(&req),
325            "GetOpsItem" => self.get_ops_item(&req),
326            "UpdateOpsItem" => self.update_ops_item(&req),
327            "DeleteOpsItem" => self.delete_ops_item(&req),
328            "DescribeOpsItems" => self.describe_ops_items(&req),
329            // Document extras
330            "ListDocumentVersions" => self.list_document_versions(&req),
331            "ListDocumentMetadataHistory" => self.list_document_metadata_history(&req),
332            "UpdateDocumentMetadata" => self.update_document_metadata(&req),
333            // Resource policies
334            "PutResourcePolicy" => self.put_resource_policy(&req),
335            "GetResourcePolicies" => self.get_resource_policies(&req),
336            "DeleteResourcePolicy" => self.delete_resource_policy(&req),
337            // Inventory
338            "PutInventory" => self.put_inventory(&req),
339            "GetInventory" => self.get_inventory(&req),
340            "GetInventorySchema" => self.get_inventory_schema(&req),
341            "ListInventoryEntries" => self.list_inventory_entries(&req),
342            "DeleteInventory" => self.delete_inventory(&req),
343            "DescribeInventoryDeletions" => self.describe_inventory_deletions(&req),
344            // Compliance
345            "PutComplianceItems" => self.put_compliance_items(&req),
346            "ListComplianceItems" => self.list_compliance_items(&req),
347            "ListComplianceSummaries" => self.list_compliance_summaries(&req),
348            "ListResourceComplianceSummaries" => self.list_resource_compliance_summaries(&req),
349            // Maintenance window details
350            "UpdateMaintenanceWindowTarget" => self.update_maintenance_window_target(&req),
351            "UpdateMaintenanceWindowTask" => self.update_maintenance_window_task(&req),
352            "GetMaintenanceWindowTask" => self.get_maintenance_window_task(&req),
353            "GetMaintenanceWindowExecution" => self.get_maintenance_window_execution(&req),
354            "GetMaintenanceWindowExecutionTask" => self.get_maintenance_window_execution_task(&req),
355            "GetMaintenanceWindowExecutionTaskInvocation" => {
356                self.get_maintenance_window_execution_task_invocation(&req)
357            }
358            "DescribeMaintenanceWindowExecutions" => {
359                self.describe_maintenance_window_executions(&req)
360            }
361            "DescribeMaintenanceWindowExecutionTasks" => {
362                self.describe_maintenance_window_execution_tasks(&req)
363            }
364            "DescribeMaintenanceWindowExecutionTaskInvocations" => {
365                self.describe_maintenance_window_execution_task_invocations(&req)
366            }
367            "DescribeMaintenanceWindowSchedule" => self.describe_maintenance_window_schedule(&req),
368            "DescribeMaintenanceWindowsForTarget" => {
369                self.describe_maintenance_windows_for_target(&req)
370            }
371            "CancelMaintenanceWindowExecution" => self.cancel_maintenance_window_execution(&req),
372            // Patch management details
373            "UpdatePatchBaseline" => self.update_patch_baseline(&req),
374            "DescribeInstancePatchStates" => self.describe_instance_patch_states(&req),
375            "DescribeInstancePatchStatesForPatchGroup" => {
376                self.describe_instance_patch_states_for_patch_group(&req)
377            }
378            "DescribeInstancePatches" => self.describe_instance_patches(&req),
379            "DescribeEffectivePatchesForPatchBaseline" => {
380                self.describe_effective_patches_for_patch_baseline(&req)
381            }
382            "GetDeployablePatchSnapshotForInstance" => {
383                self.get_deployable_patch_snapshot_for_instance(&req)
384            }
385            // Resource data sync
386            "CreateResourceDataSync" => self.create_resource_data_sync(&req),
387            "DeleteResourceDataSync" => self.delete_resource_data_sync(&req),
388            "ListResourceDataSync" => self.list_resource_data_sync(&req),
389            "UpdateResourceDataSync" => self.update_resource_data_sync(&req),
390            // OpsItem related items
391            "AssociateOpsItemRelatedItem" => self.associate_ops_item_related_item(&req),
392            "DisassociateOpsItemRelatedItem" => self.disassociate_ops_item_related_item(&req),
393            "ListOpsItemRelatedItems" => self.list_ops_item_related_items(&req),
394            "ListOpsItemEvents" => self.list_ops_item_events(&req),
395            // OpsMetadata
396            "CreateOpsMetadata" => self.create_ops_metadata(&req),
397            "GetOpsMetadata" => self.get_ops_metadata(&req),
398            "UpdateOpsMetadata" => self.update_ops_metadata(&req),
399            "DeleteOpsMetadata" => self.delete_ops_metadata(&req),
400            "ListOpsMetadata" => self.list_ops_metadata(&req),
401            // OpsMetadata extras
402            "GetOpsSummary" => self.get_ops_summary(&req),
403            // Automation
404            "StartAutomationExecution" => self.start_automation_execution(&req),
405            "StopAutomationExecution" => self.stop_automation_execution(&req),
406            "GetAutomationExecution" => self.get_automation_execution(&req),
407            "DescribeAutomationExecutions" => self.describe_automation_executions(&req),
408            "DescribeAutomationStepExecutions" => self.describe_automation_step_executions(&req),
409            "SendAutomationSignal" => self.send_automation_signal(&req),
410            "StartChangeRequestExecution" => self.start_change_request_execution(&req),
411            "StartExecutionPreview" => self.start_execution_preview(&req),
412            "GetExecutionPreview" => self.get_execution_preview(&req),
413            // Sessions
414            "StartSession" => self.start_session(&req),
415            "ResumeSession" => self.resume_session(&req),
416            "TerminateSession" => self.terminate_session(&req),
417            "DescribeSessions" => self.describe_sessions(&req),
418            "StartAccessRequest" => self.start_access_request(&req),
419            "GetAccessToken" => self.get_access_token(&req),
420            // Managed instances
421            "CreateActivation" => self.create_activation(&req),
422            "DeleteActivation" => self.delete_activation(&req),
423            "DescribeActivations" => self.describe_activations(&req),
424            "DeregisterManagedInstance" => self.deregister_managed_instance(&req),
425            "DescribeInstanceInformation" => self.describe_instance_information(&req),
426            "DescribeInstanceProperties" => self.describe_instance_properties(&req),
427            "UpdateManagedInstanceRole" => self.update_managed_instance_role(&req),
428            // Other
429            "ListNodes" => self.list_nodes(&req),
430            "ListNodesSummary" => self.list_nodes_summary(&req),
431            "DescribeEffectiveInstanceAssociations" => {
432                self.describe_effective_instance_associations(&req)
433            }
434            "DescribeInstanceAssociationsStatus" => {
435                self.describe_instance_associations_status(&req)
436            }
437            // Synthetic defaults (no managed-instance fleet to track) and
438            // service settings backed by real per-account state.
439            "GetConnectionStatus" => self.get_connection_status(&req),
440            "GetCalendarState" => self.get_calendar_state(&req),
441            "DescribePatchGroupState" => self.describe_patch_group_state(&req),
442            "DescribePatchProperties" => self.describe_patch_properties(&req),
443            "GetDefaultPatchBaseline" => self.get_default_patch_baseline(&req),
444            "RegisterDefaultPatchBaseline" => self.register_default_patch_baseline(&req),
445            "DescribeAvailablePatches" => self.describe_available_patches(&req),
446            "GetServiceSetting" => self.get_service_setting(&req),
447            "ResetServiceSetting" => self.reset_service_setting(&req),
448            "UpdateServiceSetting" => self.update_service_setting(&req),
449            _ => Err(AwsServiceError::action_not_implemented("ssm", &req.action)),
450        };
451        if mutates && matches!(result.as_ref(), Ok(resp) if resp.status.is_success()) {
452            self.save_snapshot().await;
453        }
454        result
455    }
456
457    fn supported_actions(&self) -> &[&str] {
458        &[
459            "PutParameter",
460            "GetParameter",
461            "GetParameters",
462            "GetParametersByPath",
463            "DeleteParameter",
464            "DeleteParameters",
465            "DescribeParameters",
466            "GetParameterHistory",
467            "AddTagsToResource",
468            "RemoveTagsFromResource",
469            "ListTagsForResource",
470            "LabelParameterVersion",
471            "UnlabelParameterVersion",
472            "CreateDocument",
473            "GetDocument",
474            "DeleteDocument",
475            "UpdateDocument",
476            "DescribeDocument",
477            "UpdateDocumentDefaultVersion",
478            "ListDocuments",
479            "DescribeDocumentPermission",
480            "ModifyDocumentPermission",
481            "SendCommand",
482            "ListCommands",
483            "GetCommandInvocation",
484            "ListCommandInvocations",
485            "CancelCommand",
486            "CreateMaintenanceWindow",
487            "DescribeMaintenanceWindows",
488            "GetMaintenanceWindow",
489            "DeleteMaintenanceWindow",
490            "UpdateMaintenanceWindow",
491            "RegisterTargetWithMaintenanceWindow",
492            "DeregisterTargetFromMaintenanceWindow",
493            "DescribeMaintenanceWindowTargets",
494            "RegisterTaskWithMaintenanceWindow",
495            "DeregisterTaskFromMaintenanceWindow",
496            "DescribeMaintenanceWindowTasks",
497            "CreatePatchBaseline",
498            "DeletePatchBaseline",
499            "DescribePatchBaselines",
500            "GetPatchBaseline",
501            "RegisterPatchBaselineForPatchGroup",
502            "DeregisterPatchBaselineForPatchGroup",
503            "GetPatchBaselineForPatchGroup",
504            "DescribePatchGroups",
505            // Associations
506            "CreateAssociation",
507            "DescribeAssociation",
508            "DeleteAssociation",
509            "ListAssociations",
510            "UpdateAssociation",
511            "ListAssociationVersions",
512            "UpdateAssociationStatus",
513            "StartAssociationsOnce",
514            "CreateAssociationBatch",
515            "DescribeAssociationExecutions",
516            "DescribeAssociationExecutionTargets",
517            // OpsItems
518            "CreateOpsItem",
519            "GetOpsItem",
520            "UpdateOpsItem",
521            "DeleteOpsItem",
522            "DescribeOpsItems",
523            // Document extras
524            "ListDocumentVersions",
525            "ListDocumentMetadataHistory",
526            "UpdateDocumentMetadata",
527            // Resource policies
528            "PutResourcePolicy",
529            "GetResourcePolicies",
530            "DeleteResourcePolicy",
531            // Inventory
532            "PutInventory",
533            "GetInventory",
534            "GetInventorySchema",
535            "ListInventoryEntries",
536            "DeleteInventory",
537            "DescribeInventoryDeletions",
538            // Compliance
539            "PutComplianceItems",
540            "ListComplianceItems",
541            "ListComplianceSummaries",
542            "ListResourceComplianceSummaries",
543            // Maintenance window details
544            "UpdateMaintenanceWindowTarget",
545            "UpdateMaintenanceWindowTask",
546            "GetMaintenanceWindowTask",
547            "GetMaintenanceWindowExecution",
548            "GetMaintenanceWindowExecutionTask",
549            "GetMaintenanceWindowExecutionTaskInvocation",
550            "DescribeMaintenanceWindowExecutions",
551            "DescribeMaintenanceWindowExecutionTasks",
552            "DescribeMaintenanceWindowExecutionTaskInvocations",
553            "DescribeMaintenanceWindowSchedule",
554            "DescribeMaintenanceWindowsForTarget",
555            "CancelMaintenanceWindowExecution",
556            // Patch management details
557            "UpdatePatchBaseline",
558            "DescribeInstancePatchStates",
559            "DescribeInstancePatchStatesForPatchGroup",
560            "DescribeInstancePatches",
561            "DescribeEffectivePatchesForPatchBaseline",
562            "GetDeployablePatchSnapshotForInstance",
563            // Resource data sync
564            "CreateResourceDataSync",
565            "DeleteResourceDataSync",
566            "ListResourceDataSync",
567            "UpdateResourceDataSync",
568            // OpsItem related items
569            "AssociateOpsItemRelatedItem",
570            "DisassociateOpsItemRelatedItem",
571            "ListOpsItemRelatedItems",
572            "ListOpsItemEvents",
573            // OpsMetadata
574            "CreateOpsMetadata",
575            "GetOpsMetadata",
576            "UpdateOpsMetadata",
577            "DeleteOpsMetadata",
578            "ListOpsMetadata",
579            // OpsMetadata extras
580            "GetOpsSummary",
581            // Automation
582            "StartAutomationExecution",
583            "StopAutomationExecution",
584            "GetAutomationExecution",
585            "DescribeAutomationExecutions",
586            "DescribeAutomationStepExecutions",
587            "SendAutomationSignal",
588            "StartChangeRequestExecution",
589            "StartExecutionPreview",
590            "GetExecutionPreview",
591            // Sessions
592            "StartSession",
593            "ResumeSession",
594            "TerminateSession",
595            "DescribeSessions",
596            "StartAccessRequest",
597            "GetAccessToken",
598            // Managed instances
599            "CreateActivation",
600            "DeleteActivation",
601            "DescribeActivations",
602            "DeregisterManagedInstance",
603            "DescribeInstanceInformation",
604            "DescribeInstanceProperties",
605            "UpdateManagedInstanceRole",
606            // Other
607            "ListNodes",
608            "ListNodesSummary",
609            "DescribeEffectiveInstanceAssociations",
610            "DescribeInstanceAssociationsStatus",
611            // Synthetic defaults + service settings
612            "GetConnectionStatus",
613            "GetCalendarState",
614            "DescribePatchGroupState",
615            "DescribePatchProperties",
616            "GetDefaultPatchBaseline",
617            "RegisterDefaultPatchBaseline",
618            "DescribeAvailablePatches",
619            "GetServiceSetting",
620            "ResetServiceSetting",
621            "UpdateServiceSetting",
622        ]
623    }
624}
625
626mod helpers;
627pub(crate) use helpers::*;
628
629#[cfg(test)]
630mod tests;