Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion client-sdks/platform/openapi.json

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion client-sdks/platform/rust/openapi-3.0.json

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion client-sdks/platform/rust/openapi.json

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions crates/alien-cli/src/commands/render.rs
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,7 @@ async fn prepare_stack_for_render(

let stack_state = StackState::new(platform);
let config = DeploymentConfig {
input_values: Default::default(),
deployment_name: Some(stack.id().to_string()),
stack_settings: stack_settings.clone(),
management_config: None,
Expand Down
13 changes: 13 additions & 0 deletions crates/alien-cloudformation/src/emitter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,19 @@ pub trait CfEmitter: Send + Sync {
/// into the setup registration payload by the generator.
fn emit_import_ref(&self, ctx: &EmitContext<'_>) -> Result<CfExpression>;

/// Whether this emitter renders correctly for a resource gated by
/// `.enabled(input)`.
///
/// Opting in means the emitter leaves the generator free to stamp the gate's
/// `Condition` onto its resources, and folds its own import ref through
/// `Fn::If` so nothing references a resource the condition skipped. The
/// generator refuses to render a gated resource whose emitter has not, so a
/// half-converted emitter fails loudly instead of silently creating the
/// resource the deployer declined.
fn supports_enabled_when(&self) -> bool {
false
}

/// Expression that resolves to this resource's runtime binding payload.
/// Import data feeds the manager; binding data feeds user code.
fn emit_binding_ref(&self, _ctx: &EmitContext<'_>) -> Result<Option<CfExpression>> {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -341,6 +341,7 @@ mod tests {
lifecycle: ResourceLifecycle::Live,
dependencies: Vec::new(),
remote_access: false,
enabled_when: None,
}
}

Expand Down
42 changes: 42 additions & 0 deletions crates/alien-cloudformation/src/emitters/enabled.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
//! Rendering for a resource whose creation follows a deployer input.
//!
//! `.enabled(input)` in the SDK means the deployer decides whether the resource
//! exists. CloudFormation learns that answer as a parameter at deploy time, not
//! when we render, so the decision has to live in the template: the resource
//! carries a `Condition`, and nothing that outlives it may reference it.
//!
//! Two things follow, and the generator does both:
//!
//! - every resource the emitter returns gets the gate's `Condition`
//! - the resource's registration entry is dropped from the payload entirely
//!
//! Dropping the whole entry is the part that is easy to get wrong. Registration
//! runs the typed importer over every entry it receives, so an entry that is
//! present but null — or present with null fields — fails deserialization
//! instead of being skipped. There is no skip-on-null anywhere in that path.
//! `AWS::NoValue` removes the list element outright, which is the only shape
//! that leaves nothing to deserialize.

use crate::{generator::stack_input_parameter_name_for_id, template::CfExpression};

/// Name of the condition carrying the gate's value. The generator declares it
/// and stamps it onto resources, so both derive it from the input id alone.
pub fn condition_name(input_id: &str) -> String {
format!("{}IsTrue", stack_input_parameter_name_for_id(input_id))
}

/// Yields `value` while the gate is on and `when_disabled` while it is off.
///
/// Pass `CfExpression::no_value()` as `when_disabled` to delete the value rather
/// than blank it: inside a list that removes the element, and inside an object
/// it removes the key.
pub fn when_enabled(
enabled_when: Option<&str>,
value: CfExpression,
when_disabled: CfExpression,
) -> CfExpression {
match enabled_when {
Some(input_id) => CfExpression::if_(condition_name(input_id), value, when_disabled),
None => value,
}
}
1 change: 1 addition & 0 deletions crates/alien-cloudformation/src/emitters/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,3 +10,4 @@
//! top of [`crate::CfRegistry::built_in`].

pub mod aws;
pub mod enabled;
Loading
Loading