CDK Stacks
Stacks define complete Elements (Infrastructure, Purpose or Component) of the Runtime Architecture in a reusable way. In this repository it is expected that it will contain mostly Infrastructure and Purpose stacks, although components may be included if they are utility or testing components, or temporarily to avoid duplicating/copying Construct Code in multiple repositories.
Stacks are defined in the src/cdk/stacks directory of this repository. In it, there are three subdirectories for each kind of element (Infrastructure, Purpose, Component) that stacks instantiate.
Stacks are defined to follow best practices so that they can be easily integrated in the deployment of concrete instances of runtime elements.
Standard Stack Pattern¶
Each stack defines:
Configuration: A typescript interface that defines the configuration parameters of the stack. These are true configuration parameters that affect the behavior of the resources defined by the stack. SeePropsfor other parameters.Props: A typescript interface that provides information about the context where the stack will be used like bindings to other resources, etc. These are different than the ones in theConfigurationinterface and are usuallyaws-cdktypes likeecs.IVpcthat inform the stack about resources that it needs to bind to. This interface extends theConfigurationinterface to capture all the parameters for a stack. All the members of this interface should bereadonlyBuilt: A typescript interface that defines a subset of the values and resources that the Stack creates and builds when instantiated. These may represent values needed by other stacks or external tools (e.g. the authentication url of a Cognito User Pool). All the members of this interface should bereadonlyExportKeys: A string enumeration type that defined the keys of values that will can be exported from the stack as CloudFormation Outputs so that they can be used by other stack.ExportDefinition: An interface that extends (acts as an alias)Record<ExportKeys, stackTypes.StackIODefinition>. This interface defines the key and exportName of the CloudFormation Outputs.ExportValues: An interface that extends (acts as an alias)Record<ExportKeys, stackTypes.StackIOValue>. This interface defines the key and value of the CloudFormation Outputs.function importValues(for<Element>: <ElementLocatorType>): ExportValues: A function that imports the values defined inExportKeysfrom a stack that is part of the element provided in the argument. the type of the argument ispurposeUtils.PurposeLocatororinfraUtils.InfrastructureLocator, which reference the Purpose or Infrastructure that owns the resources of the stack. Note that in the future we’ll need to add a Component locator or use directly an FQN in Technical Documentation Repo to locate the element owning the stack.function exportDefinition(locator: <ElementTypeLocator>): ExportDefinition: A function that defines the concrete Export Definition for a stack provided its locator.
The stack itself that extends the cdk.Stack class. The constructor of this class should accept the arguments:
scope: cdk.App: The parent App that instantiates it. (Formally this can be acdk.Constructbut Stacks should be instantiated only by an App).id: string: The Id of the stack as AWS CDK defines it.locator: <ElementLocatorType>: The locator for the stack element. This is used to name and tag AWS resources according to the Runtime Element that owns themprops: Props: The configuration and context parameters of the stack.
The stack has public members:
readonly build: Built: to capture the results of the instantiation of the stack.readonly exportDefinition: ExportDefinition: to capture the export definition of the stack.readonly exportValues: ExportValues: to capture the export values of the stack.function publish(): That publishes the ExportValues of the stack as CloudFormation Outputs.
In addition, it is best practices, similar to constructs to have a static validateProps method to validate the inputs upon creation before any resources are created.
Template of a Stack¶
import * as cdk from 'aws-cdk-lib';
import { Construct } from 'constructs';
import { stackTypes } from '../types';
export interface Configuration {
// Configuration parameters of the stack
}
export interface Props extends Configuration {
// Props parameters of the stack
}
export interface Built {
// Built resources of the stack
}
export type ExportKeys = 'Key1' | 'Key2' | 'Key3';
export type ExportDefinition = Record<ExportKeys, stackTypes.StackIODefinition>;
export type ExportValues = Record<ExportKeys, stackTypes.StackIOValue>;
export function importValues(for<Element>: <ElementLocatorType>): ExportValues {
// import the values from cloud formation
}
export function exportDefinition(locator: <ElementTypeLocator>): ExportDefinition {
return {
Key1: {
exportName: `${locator.fqn}-Key1`,
value: 'Value1',
},
[...]
};
}
export class MyStack extends cdk.Stack {
public readonly build: Built;
public readonly exportDefinition: ExportDefinition;
public readonly exportValues: ExportValues;
static validateProps(prefix: string, id: string, props: Props): boolean {
// Validate the props and throw an error if they are not valid
return true;
}
constructor(scope: cdk.App, id: string, locator: <ElementLocatorType>, props: Props) {
validateProps(prefix, id, props);
super(scope, id);
this.exportDefinition = exportDefinition(locator);
// Define the resources of the stack here
// Use the props to configure the resources
this.exportValues = {
Key1: {
...this.exportDefinition.Key1,
value: 'Value1',
},
[...]
};
}
public publish(): void {
// Publish the export values as CloudFormation Outputs
}
}
Outputs of Stacks¶
Stacks publish CloudFormation Outputs that can be used by other stacks, AWS CLI or AWS SDK programs. The outputs have a shape of:
Where:
- key: Is a unique name within the stack that produces the output.
- exportName: Is the name of the CloudFormation output that can be used to retrieve it globally in the context of an AWS account and region. Outputs generated by Arda Runtime elements follow the pattern:
^[A-Z][a-zA-Z0-9]*(-[A-Z][a-zA-Z0-9]*)?-[A-Z][a-zA-Z0-9]*$. It is a combination of thefqnof the element that owns the stack and a unique name for the output. For outputs of an Infrastructure stack, it corresponds to<infrastructureName>-<outputName>. For outputs of a Purpose stack, it corresponds to<infrastructureName>-<purposeName>-<outputName>. - value: A String representing the value of the output. Following the convention of CloudFormation, this value may represent a single atomic value that is interpreted by the consumer of the output, or a
,separated list of strings, each representing an atomic value. As of now, there is no fixed convention for how to represent more complex values, like typed atomic values (boolean, number) or complex JSON-style objects or nested arrays.
Using Cloud Formation capabilities through AWS’s SDK, CLI or CDK, these values can be accessed using the Stack name in the Account+Region where the stack was deployed or the full Export Name as defined above, again in the given Account+Region.