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