rusty_cdk_core/appconfig/
builder.rs

1use serde_json::Value;
2use crate::appconfig::{Application, ApplicationProperties, ApplicationRef, ConfigurationProfile, ConfigurationProfileProperties, ConfigurationProfileRef, DeploymentStrategy, DeploymentStrategyProperties, DeploymentStrategyRef, Environment, EnvironmentProperties, EnvironmentRef, Validator};
3use crate::shared::Id;
4use crate::stack::{Resource, StackBuilder};
5use crate::wrappers::{AppConfigName, DeploymentDurationInMinutes, GrowthFactor, LocationUri};
6
7/// Builder for AWS AppConfig applications.
8///
9/// # Example
10///
11/// ```rust
12/// use rusty_cdk_core::stack::StackBuilder;
13/// use rusty_cdk_core::appconfig::ApplicationBuilder;
14/// use rusty_cdk_core::wrappers::*;
15/// use rusty_cdk_macros::app_config_name;
16///
17/// let mut stack_builder = StackBuilder::new();
18///
19/// let app = ApplicationBuilder::new("my-app", app_config_name!("MyApplication"))
20///     .build(&mut stack_builder);
21/// ```
22pub struct ApplicationBuilder {
23    id: Id,
24    name: String,
25}
26
27impl ApplicationBuilder {
28    /// Creates a new AppConfig application builder.
29    ///
30    /// # Arguments
31    /// * `id` - Unique identifier for the application
32    /// * `name` - Name of the AppConfig application
33    pub fn new(id: &str, name: AppConfigName) -> Self {
34        Self {
35            id: Id(id.to_string()),
36            name: name.0,
37        }
38    }
39
40    pub fn build(self, stack_builder: &mut StackBuilder) -> ApplicationRef {
41        let resource_id = Resource::generate_id("AppConfigApp");
42
43        stack_builder.add_resource(Application {
44            id: self.id,
45            resource_id: resource_id.clone(),
46            r#type: "AWS::AppConfig::Application".to_string(),
47            properties: ApplicationProperties { name: self.name },
48        });
49
50        ApplicationRef::new(resource_id)
51    }
52}
53
54// pub enum LocationUri {
55//     Hosted,
56//     CodePipeline(String), // codepipeline://<pipeline name>.
57//     SecretsManager(String), // secretsmanager://<secret name>
58//     S3(String) // s3://<bucket>/<objectKey>
59//     // SSM, AWS Systems Manager Parameter Store
60// }
61// 
62// impl From<LocationUri> for String {
63//     fn from(value: LocationUri) -> Self {
64//         match value {
65//             LocationUri::Hosted => "hosted".to_string(),
66//             LocationUri::CodePipeline(l) => l.to_string(),
67//             LocationUri::SecretsManager(l) => l.to_string(),
68//             LocationUri::S3(l) => l.to_string(),
69//         }
70//     }
71// }
72
73pub enum ConfigType {
74    FeatureFlags,
75    Freeform,
76}
77
78impl From<ConfigType> for String {
79    fn from(value: ConfigType) -> Self {
80        match value {
81            ConfigType::FeatureFlags => "AWS.AppConfig.FeatureFlags".to_string(),
82            ConfigType::Freeform => "AWS.Freeform".to_string(),
83        }
84    }
85}
86
87pub enum DeletionProtectionCheck {
88    AccountDefault,
89    Apply,
90    Bypass,
91}
92
93impl From<DeletionProtectionCheck> for String {
94    fn from(value: DeletionProtectionCheck) -> Self {
95        match value {
96            DeletionProtectionCheck::AccountDefault => "ACCOUNT_DEFAULT".to_string(),
97            DeletionProtectionCheck::Apply => "APPLY".to_string(),
98            DeletionProtectionCheck::Bypass => "BYPASS".to_string(),
99        }
100    }
101}
102
103/// Builder for AWS AppConfig configuration profiles.
104///
105/// # Example
106///
107/// ```rust,no_run
108/// use rusty_cdk_core::stack::StackBuilder;
109/// use rusty_cdk_core::appconfig::{ApplicationBuilder, ConfigurationProfileBuilder};
110/// use rusty_cdk_core::wrappers::*;
111/// use rusty_cdk_macros::{app_config_name, location_uri};
112///
113/// let mut stack_builder = StackBuilder::new();
114///
115/// let app = unimplemented!("create an application");
116/// let location_uri = location_uri!("hosted");
117///
118/// let profile = ConfigurationProfileBuilder::new(
119///     "my-profile",
120///     app_config_name!("MyProfile"),
121///     &app,
122///     location_uri,
123/// )
124/// .build(&mut stack_builder);
125/// ```
126pub struct ConfigurationProfileBuilder {
127    id: Id,
128    name: String,
129    application_id: Value,
130    location_uri: String,
131    deletion_protection_check: Option<String>,
132    config_type: Option<String>,
133    validators: Option<Vec<Validator>>
134}
135
136impl ConfigurationProfileBuilder {
137    /// Creates a new AppConfig configuration profile builder.
138    ///
139    /// # Arguments
140    /// * `id` - Unique identifier for the configuration profile
141    /// * `name` - Name of the configuration profile
142    /// * `application` - Reference to the parent AppConfig application
143    /// * `location_uri` - Location where the configuration is stored
144    pub fn new(id: &str, name: AppConfigName, application: &ApplicationRef, location_uri: LocationUri) -> Self {
145        Self {
146            id: Id(id.to_string()),
147            name: name.0,
148            application_id: application.get_ref(),
149            location_uri: location_uri.0,
150            deletion_protection_check: None,
151            config_type: None,
152            validators: None,
153        }
154    }
155
156    pub fn deletion_protection_check(self, deletion_protection_check: DeletionProtectionCheck) -> Self {
157        Self {
158            deletion_protection_check: Some(deletion_protection_check.into()),
159            ..self
160        }
161    }
162
163    pub fn config_type(self, config_type: ConfigType) -> Self {
164        Self {
165            config_type: Some(config_type.into()),
166            ..self
167        }
168    }
169
170    pub fn add_validator(mut self, validator: Validator) -> Self {
171        if let Some(mut validators) = self.validators {
172            validators.push(validator);
173            self.validators = Some(validators);
174        } else {
175            self.validators = Some(vec![validator]);
176        }
177
178        self
179    }
180
181    pub fn build(self, stack_builder: &mut StackBuilder) -> ConfigurationProfileRef {
182        let resource_id = Resource::generate_id("ConfigurationProfile");
183
184        stack_builder.add_resource(ConfigurationProfile {
185            id: self.id,
186            resource_id: resource_id.clone(),
187            r#type: "AWS::AppConfig::ConfigurationProfile".to_string(),
188            properties: ConfigurationProfileProperties {
189                name: self.name,
190                application_id: self.application_id,
191                deletion_protection_check: self.deletion_protection_check,
192                location_uri: self.location_uri,
193                config_type: self.config_type,
194                validators: self.validators,
195            },
196        });
197
198        ConfigurationProfileRef::new(resource_id)
199    }
200}
201
202/// Builder for configuration profile validators.
203pub struct ValidatorBuilder {
204    content: String,
205    validator_type: String,
206}
207
208impl ValidatorBuilder {
209    // could validate better with a macro, but for JSON that would require passing in the entire schema in the macro...
210    pub fn new(content: String, validator_type: ValidatorType) -> Self {
211        Self {
212            content,
213            validator_type: validator_type.into(),
214        }
215    }
216
217    pub fn build(self) -> Validator {
218        Validator {
219            content: self.content,
220            validator_type: self.validator_type,
221        }
222    }
223}
224
225
226pub enum ValidatorType {
227    JsonSchema,
228    Lambda,
229}
230
231impl From<ValidatorType> for String {
232    fn from(value: ValidatorType) -> Self {
233        match value {
234            ValidatorType::JsonSchema => "JSON_SCHEMA".to_string(),
235            ValidatorType::Lambda => "LAMBDA".to_string(),
236        }
237    }
238}
239
240pub enum GrowthType {
241    Linear,
242    Exponential,
243}
244
245impl From<GrowthType> for String {
246    fn from(value: GrowthType) -> Self {
247        match value {
248            GrowthType::Linear => "LINEAR".to_string(),
249            GrowthType::Exponential => "EXPONENTIAL".to_string()
250        }
251    }
252}
253
254pub enum ReplicateTo {
255    None,
256    SsmDocument,
257}
258
259impl From<ReplicateTo> for String {
260    fn from(value: ReplicateTo) -> Self {
261        match value {
262            ReplicateTo::None => "NONE".to_string(),
263            ReplicateTo::SsmDocument => "SSM_DOCUMENT".to_string(),
264        }
265    }
266}
267
268/// Builder for AWS AppConfig deployment strategies.
269pub struct DeploymentStrategyBuilder {
270    id: Id,
271    name: String,
272    deployment_duration_in_minutes: u16,
273    growth_factor: u8,
274    growth_type: Option<String>,
275    replicate_to: String,
276}
277
278impl DeploymentStrategyBuilder {
279    /// Creates a new AppConfig deployment strategy builder.
280    ///
281    /// # Arguments
282    /// * `id` - Unique identifier for the deployment strategy
283    /// * `name` - Name of the deployment strategy
284    /// * `deployment_duration_in_minutes` - Time to deploy the configuration
285    /// * `growth_factor` - Percentage of targets to receive the deployment during each interval
286    /// * `replicate_to` - Where to replicate the configuration
287    pub fn new(id: &str, name: AppConfigName, deployment_duration_in_minutes: DeploymentDurationInMinutes, growth_factor: GrowthFactor, replicate_to: ReplicateTo) -> Self {
288        Self {
289            id: Id(id.to_string()),
290            name: name.0,
291            deployment_duration_in_minutes: deployment_duration_in_minutes.0,
292            growth_factor: growth_factor.0,
293            growth_type: None,
294            replicate_to: replicate_to.into(),
295        }
296    }
297    
298    pub fn growth_type(self, growth_type: GrowthType) -> Self {
299        Self {
300            growth_type: Some(growth_type.into()),
301            ..self
302        }
303    }
304    
305    pub fn build(self, stack_builder: &mut StackBuilder) -> DeploymentStrategyRef {
306        let resource_id = Resource::generate_id("DeploymentStrategy");
307        
308        stack_builder.add_resource(DeploymentStrategy {
309            id: self.id,
310            resource_id: resource_id.clone(),
311            r#type: "AWS::AppConfig::DeploymentStrategy".to_string(),
312            properties: DeploymentStrategyProperties {
313                name: self.name,
314                deployment_duration_in_minutes: self.deployment_duration_in_minutes,
315                growth_factor: self.growth_factor,
316                replicate_to: self.replicate_to,
317                growth_type: self.growth_type,
318            },
319        });
320        
321        DeploymentStrategyRef::new(resource_id)
322    }
323}
324
325/// Builder for AWS AppConfig environments.
326pub struct EnvironmentBuilder {
327    id: Id,
328    name: String,
329    application_id: Value,
330    deletion_protection_check: Option<String>
331}
332
333impl EnvironmentBuilder {
334    /// Creates a new AppConfig environment builder.
335    ///
336    /// # Arguments
337    /// * `id` - Unique identifier for the environment
338    /// * `name` - Name of the environment
339    /// * `application` - Reference to the parent AppConfig application
340    pub fn new(id: &str, name: AppConfigName, application: &ApplicationRef) -> Self {
341        Self {
342            id: Id(id.to_string()),
343            name: name.0,
344            application_id: application.get_ref(),
345            deletion_protection_check: None,
346        }
347    }
348
349    pub fn deletion_protection_check(self, deletion_protection_check: DeletionProtectionCheck) -> Self {
350        Self {
351            deletion_protection_check: Some(deletion_protection_check.into()),
352            ..self
353        }
354    }
355    
356    pub fn build(self, stack_builder: &mut StackBuilder) -> EnvironmentRef {
357        let resource_id = Resource::generate_id("Environment");
358        
359        stack_builder.add_resource(Environment {
360            id: self.id,
361            resource_id: resource_id.clone(),
362            r#type: "AWS::AppConfig::Environment".to_string(),
363            properties: EnvironmentProperties {
364                name: self.name,
365                application_id: self.application_id,
366                deletion_protection_check: self.deletion_protection_check,
367            },
368        });
369        
370        EnvironmentRef::new(resource_id)
371    }
372}