Skip to main content

fakecloud_appconfig/
state.rs

1//! Account-partitioned, serializable state for AWS AppConfig.
2//!
3//! Models the AppConfig control plane (applications with their environments and
4//! configuration profiles, hosted configuration versions storing raw bytes,
5//! deployment strategies, deployments, extensions and their associations,
6//! experiment definitions and runs, account settings, tags) plus the AppConfig
7//! Data plane (configuration sessions resolved to deployed content).
8//!
9//! Complex request members (validators, monitors, extension action maps,
10//! experiment treatments) are stored as the JSON objects the caller sent so
11//! Get / List round-trip faithfully, the same store-the-`Value` pattern the
12//! Backup and EKS handlers use.
13
14use std::collections::BTreeMap;
15use std::sync::Arc;
16
17use parking_lot::RwLock;
18use serde::{Deserialize, Serialize};
19use serde_json::Value;
20
21use fakecloud_core::multi_account::{AccountState, MultiAccountState};
22
23pub const APPCONFIG_SNAPSHOT_SCHEMA_VERSION: u32 = 1;
24
25pub type TagMap = BTreeMap<String, String>;
26
27/// A hosted configuration version: raw configuration bytes plus metadata.
28#[derive(Debug, Clone, Serialize, Deserialize)]
29pub struct HostedVersionRecord {
30    pub version_number: i64,
31    pub description: Option<String>,
32    pub content: Vec<u8>,
33    pub content_type: String,
34    pub version_label: Option<String>,
35}
36
37/// A configuration profile, nested under an application.
38#[derive(Debug, Clone, Serialize, Deserialize)]
39pub struct ProfileRecord {
40    pub id: String,
41    pub application_id: String,
42    pub name: String,
43    pub description: Option<String>,
44    pub location_uri: String,
45    pub retrieval_role_arn: Option<String>,
46    pub validators: Value,
47    pub profile_type: String,
48    pub kms_key_arn: Option<String>,
49    pub kms_key_identifier: Option<String>,
50    #[serde(default)]
51    pub hosted_versions: BTreeMap<i64, HostedVersionRecord>,
52    #[serde(default)]
53    pub next_version_number: i64,
54}
55
56/// A deployment, nested under an environment (keyed by DeploymentNumber).
57#[derive(Debug, Clone, Serialize, Deserialize)]
58pub struct DeploymentRecord {
59    pub deployment_number: i64,
60    /// The full `Deployment` output object, settled to a terminal state.
61    pub deployment: Value,
62}
63
64/// An environment, nested under an application.
65#[derive(Debug, Clone, Serialize, Deserialize)]
66pub struct EnvironmentRecord {
67    pub id: String,
68    pub application_id: String,
69    pub name: String,
70    pub description: Option<String>,
71    pub state: String,
72    pub monitors: Value,
73    #[serde(default)]
74    pub deployments: BTreeMap<i64, DeploymentRecord>,
75    #[serde(default)]
76    pub next_deployment_number: i64,
77}
78
79/// An application with its nested environments, profiles and experiments.
80#[derive(Debug, Clone, Serialize, Deserialize)]
81pub struct ApplicationRecord {
82    pub id: String,
83    pub name: String,
84    pub description: Option<String>,
85    #[serde(default)]
86    pub environments: BTreeMap<String, EnvironmentRecord>,
87    #[serde(default)]
88    pub profiles: BTreeMap<String, ProfileRecord>,
89    /// Experiment definitions keyed by id, each storing its runs.
90    #[serde(default)]
91    pub experiments: BTreeMap<String, ExperimentRecord>,
92}
93
94/// An experiment definition plus its runs (stored as JSON for round-trip).
95#[derive(Debug, Clone, Serialize, Deserialize)]
96pub struct ExperimentRecord {
97    pub id: String,
98    /// The `ExperimentDefinition` output object.
99    pub definition: Value,
100    /// Runs keyed by run number; each value is an `ExperimentRun` object.
101    #[serde(default)]
102    pub runs: BTreeMap<i64, Value>,
103    #[serde(default)]
104    pub next_run_number: i64,
105}
106
107/// An AppConfig Data configuration session (control-plane token binding).
108#[derive(Debug, Clone, Serialize, Deserialize)]
109pub struct SessionRecord {
110    pub token: String,
111    pub application_id: String,
112    pub environment_id: String,
113    pub configuration_profile_id: String,
114}
115
116/// The account-scoped AppConfig state for one AWS account.
117#[derive(Debug, Clone, Default, Serialize, Deserialize)]
118pub struct AppConfigState {
119    #[serde(default)]
120    pub applications: BTreeMap<String, ApplicationRecord>,
121    /// Customer-created deployment strategies (predefined ones are synthesized).
122    #[serde(default)]
123    pub deployment_strategies: BTreeMap<String, Value>,
124    /// Extensions keyed by id; each value is the `Extension` object.
125    #[serde(default)]
126    pub extensions: BTreeMap<String, Value>,
127    /// Extension associations keyed by id; each value is the object.
128    #[serde(default)]
129    pub extension_associations: BTreeMap<String, Value>,
130    /// Extensions referenced by an association's `ExtensionIdentifier` that
131    /// were not created locally (e.g. AWS-authored extensions). Keyed by the
132    /// identifier used on the association so `GetExtension` can resolve them.
133    #[serde(default)]
134    pub referenced_extensions: BTreeMap<String, Value>,
135    /// Account settings (deletion protection + vended metrics), applied lazily.
136    #[serde(default)]
137    pub account_settings: Option<Value>,
138    /// AppConfig Data sessions keyed by their token.
139    #[serde(default)]
140    pub sessions: BTreeMap<String, SessionRecord>,
141    /// Tags keyed by resource ARN.
142    #[serde(default)]
143    pub tags: BTreeMap<String, TagMap>,
144}
145
146impl AccountState for AppConfigState {
147    fn new_for_account(_account_id: &str, _region: &str, _endpoint: &str) -> Self {
148        Self::default()
149    }
150}
151
152pub type SharedAppConfigState = Arc<RwLock<MultiAccountState<AppConfigState>>>;
153
154#[derive(Debug, Serialize, Deserialize)]
155pub struct AppConfigSnapshot {
156    pub schema_version: u32,
157    pub accounts: MultiAccountState<AppConfigState>,
158}
159
160// ---------------------------------------------------------------------------
161// ARN builders
162// ---------------------------------------------------------------------------
163
164pub fn application_arn(region: &str, account_id: &str, id: &str) -> String {
165    format!("arn:aws:appconfig:{region}:{account_id}:application/{id}")
166}
167
168pub fn environment_arn(region: &str, account_id: &str, app: &str, env: &str) -> String {
169    format!("arn:aws:appconfig:{region}:{account_id}:application/{app}/environment/{env}")
170}
171
172pub fn profile_arn(region: &str, account_id: &str, app: &str, profile: &str) -> String {
173    format!(
174        "arn:aws:appconfig:{region}:{account_id}:application/{app}/configurationprofile/{profile}"
175    )
176}
177
178pub fn deployment_strategy_arn(region: &str, account_id: &str, id: &str) -> String {
179    format!("arn:aws:appconfig:{region}:{account_id}:deploymentstrategy/{id}")
180}
181
182pub fn extension_arn(region: &str, account_id: &str, id: &str, version: i64) -> String {
183    format!("arn:aws:appconfig:{region}:{account_id}:extension/{id}/{version}")
184}
185
186pub fn extension_association_arn(region: &str, account_id: &str, id: &str) -> String {
187    format!("arn:aws:appconfig:{region}:{account_id}:extensionassociation/{id}")
188}