Skip to main content

fakecloud_backup/
state.rs

1//! Account-partitioned, serializable state for AWS Backup.
2//!
3//! Models the Backup control plane: backup plans (with their versions and
4//! backup selections), backup vaults (standard, logically-air-gapped, and
5//! restore-access) plus their notifications / access policies / lock config,
6//! recovery points, backup / copy / restore / scan jobs, frameworks, report
7//! plans and report jobs, legal holds, restore-testing plans and selections,
8//! tiering configurations, and the account-scoped global / region settings.
9//!
10//! Complex request members (a `BackupPlan` rule set, a `BackupSelection`, a
11//! `RestoreTestingPlan`, ...) are stored as the JSON objects the caller sent so
12//! Get / Describe / List round-trip faithfully, following the same
13//! store-the-`Value` pattern the EKS handler uses for its nested members.
14
15use std::collections::BTreeMap;
16use std::sync::Arc;
17
18use chrono::{DateTime, Utc};
19use parking_lot::RwLock;
20use serde::{Deserialize, Serialize};
21use serde_json::Value;
22
23use fakecloud_core::multi_account::{AccountState, MultiAccountState};
24
25pub const BACKUP_SNAPSHOT_SCHEMA_VERSION: u32 = 1;
26
27pub type TagMap = BTreeMap<String, String>;
28
29/// A single backup selection attached to a plan.
30#[derive(Debug, Clone, Serialize, Deserialize)]
31pub struct SelectionRecord {
32    pub selection_id: String,
33    pub creation_date: DateTime<Utc>,
34    pub creator_request_id: Option<String>,
35    /// The `BackupSelection` object as sent, echoed back on Get.
36    pub selection: Value,
37}
38
39/// A backup plan, keyed by its generated `BackupPlanId`.
40#[derive(Debug, Clone, Serialize, Deserialize)]
41pub struct PlanRecord {
42    pub id: String,
43    pub arn: String,
44    pub version_id: String,
45    pub creation_date: DateTime<Utc>,
46    pub deletion_date: Option<DateTime<Utc>>,
47    pub last_execution_date: Option<DateTime<Utc>>,
48    pub creator_request_id: Option<String>,
49    /// The `BackupPlan` object (rules, advanced settings) as sent.
50    pub plan: Value,
51    pub advanced_backup_settings: Value,
52    pub selections: BTreeMap<String, SelectionRecord>,
53    /// Prior version metadata for `ListBackupPlanVersions`, newest last.
54    pub versions: Vec<PlanVersion>,
55}
56
57#[derive(Debug, Clone, Serialize, Deserialize)]
58pub struct PlanVersion {
59    pub version_id: String,
60    pub creation_date: DateTime<Utc>,
61    pub deletion_date: Option<DateTime<Utc>>,
62    pub plan_name: String,
63}
64
65/// A backup vault (standard / logically-air-gapped / restore-access).
66#[derive(Debug, Clone, Serialize, Deserialize)]
67pub struct VaultRecord {
68    pub name: String,
69    pub arn: String,
70    pub vault_type: String,
71    pub vault_state: String,
72    pub encryption_key_arn: Option<String>,
73    pub creation_date: DateTime<Utc>,
74    pub creator_request_id: Option<String>,
75    pub min_retention_days: Option<i64>,
76    pub max_retention_days: Option<i64>,
77    pub locked: bool,
78    pub lock_date: Option<DateTime<Utc>>,
79    pub changeable_for_days: Option<i64>,
80    pub source_backup_vault_arn: Option<String>,
81    pub access_policy: Option<String>,
82    /// `{ SNSTopicArn, BackupVaultEvents }` when notifications are configured.
83    pub notifications: Option<Value>,
84    /// Recovery points keyed by RecoveryPointArn.
85    pub recovery_points: BTreeMap<String, Value>,
86}
87
88/// A restore-testing plan with its selections.
89#[derive(Debug, Clone, Serialize, Deserialize)]
90pub struct RestoreTestingPlanRecord {
91    pub name: String,
92    pub arn: String,
93    pub creation_time: DateTime<Utc>,
94    pub update_time: Option<DateTime<Utc>>,
95    pub last_execution_time: Option<DateTime<Utc>>,
96    pub creator_request_id: Option<String>,
97    /// The `RestoreTestingPlanForCreate` object as sent.
98    pub plan: Value,
99    pub selections: BTreeMap<String, RestoreTestingSelectionRecord>,
100}
101
102#[derive(Debug, Clone, Serialize, Deserialize)]
103pub struct RestoreTestingSelectionRecord {
104    pub name: String,
105    pub creation_time: DateTime<Utc>,
106    pub update_time: Option<DateTime<Utc>>,
107    pub creator_request_id: Option<String>,
108    /// The `RestoreTestingSelectionForCreate` object as sent.
109    pub selection: Value,
110}
111
112/// The account-scoped Backup state for one AWS account.
113#[derive(Debug, Clone, Default, Serialize, Deserialize)]
114pub struct BackupState {
115    #[serde(default)]
116    pub plans: BTreeMap<String, PlanRecord>,
117    #[serde(default)]
118    pub vaults: BTreeMap<String, VaultRecord>,
119    #[serde(default)]
120    pub frameworks: BTreeMap<String, Value>,
121    #[serde(default)]
122    pub report_plans: BTreeMap<String, Value>,
123    #[serde(default)]
124    pub report_jobs: BTreeMap<String, Value>,
125    #[serde(default)]
126    pub legal_holds: BTreeMap<String, Value>,
127    #[serde(default)]
128    pub restore_testing_plans: BTreeMap<String, RestoreTestingPlanRecord>,
129    #[serde(default)]
130    pub tiering_configs: BTreeMap<String, Value>,
131    #[serde(default)]
132    pub backup_jobs: BTreeMap<String, Value>,
133    #[serde(default)]
134    pub copy_jobs: BTreeMap<String, Value>,
135    #[serde(default)]
136    pub restore_jobs: BTreeMap<String, Value>,
137    #[serde(default)]
138    pub scan_jobs: BTreeMap<String, Value>,
139    /// A flat map of every recovery point across vaults for resource-scoped
140    /// lookups (`ListRecoveryPointsByResource`, `DescribeProtectedResource`):
141    /// resourceArn -> list of recoveryPointArn (in creation order).
142    #[serde(default)]
143    pub resource_recovery_points: BTreeMap<String, Vec<String>>,
144    #[serde(default)]
145    pub global_settings: BTreeMap<String, String>,
146    /// Per-resource-type opt-in preference (defaults applied on read).
147    #[serde(default)]
148    pub region_optin: BTreeMap<String, bool>,
149    #[serde(default)]
150    pub region_mgmt: BTreeMap<String, bool>,
151    /// Tags keyed by resource ARN.
152    #[serde(default)]
153    pub tags: BTreeMap<String, TagMap>,
154}
155
156impl AccountState for BackupState {
157    fn new_for_account(_account_id: &str, _region: &str, _endpoint: &str) -> Self {
158        Self::default()
159    }
160}
161
162pub type SharedBackupState = Arc<RwLock<MultiAccountState<BackupState>>>;
163
164#[derive(Debug, Serialize, Deserialize)]
165pub struct BackupSnapshot {
166    pub schema_version: u32,
167    pub accounts: MultiAccountState<BackupState>,
168}
169
170// ---------------------------------------------------------------------------
171// ARN builders
172// ---------------------------------------------------------------------------
173
174pub fn vault_arn(region: &str, account_id: &str, name: &str) -> String {
175    format!("arn:aws:backup:{region}:{account_id}:backup-vault:{name}")
176}
177
178pub fn plan_arn(region: &str, account_id: &str, id: &str) -> String {
179    format!("arn:aws:backup:{region}:{account_id}:backup-plan:{id}")
180}
181
182pub fn recovery_point_arn(region: &str, account_id: &str, id: &str) -> String {
183    format!("arn:aws:backup:{region}:{account_id}:recovery-point:{id}")
184}
185
186pub fn framework_arn(region: &str, account_id: &str, name: &str, id: &str) -> String {
187    format!("arn:aws:backup:{region}:{account_id}:framework:{name}-{id}")
188}
189
190pub fn report_plan_arn(region: &str, account_id: &str, name: &str, id: &str) -> String {
191    format!("arn:aws:backup:{region}:{account_id}:report-plan:{name}-{id}")
192}
193
194pub fn legal_hold_arn(region: &str, account_id: &str, id: &str) -> String {
195    format!("arn:aws:backup:{region}:{account_id}:legal-hold:{id}")
196}
197
198pub fn restore_testing_plan_arn(region: &str, account_id: &str, name: &str) -> String {
199    format!("arn:aws:backup:{region}:{account_id}:restore-testing-plan:{name}")
200}
201
202pub fn tiering_configuration_arn(region: &str, account_id: &str, name: &str) -> String {
203    format!("arn:aws:backup:{region}:{account_id}:tiering-configuration:{name}")
204}