In this demo, we will show how to conditionally deploy resources using environment variables.
Passing Environment Variables
This CDK uses a Stack with several inputs. Besides the standard env
input, we are also defining StackProps
that will be used to pass the bucketName
from the environment to the Stack.
const devEnv = { account: process.env.CDK_DEFAULT_ACCOUNT, region: process.env.CDK_DEFAULT_REGION, }; const stackProps = { bucketName: process.env.BUCKET_NAME || '', }; new ConditionalDeployment(app, 'ConditionalDeployment', { ...stackProps, env: devEnv, });
Here we see the standard projen
created devEnv
and the App that is being deployed. We are additionally adding stackProps
to the Stack that is being created and passing the environment variable BUCKET_NAME
to it if it is present.
Stack and StackProps
interface ConditionalDeploymentProps extends StackProps { bucketName?: string; } let deploymentBucket: IBucket; export class ConditionalDeployment extends Stack { constructor(scope: Construct, id: string, props: ConditionalDeploymentProps) { super(scope, id, props);
Here we have defined ConditionalDeploymentProps
as a StackProps
to be passed to the Stack as well as deploymentBucket
. This will be used later with either a new bucket or the existing bucket.
Condition
if (props.bucketName) { deploymentBucket = Bucket.fromBucketName(this, 'Bucket', props.bucketName); } else { deploymentBucket = new Bucket(this, 'Bucket', { encryption: BucketEncryption.S3_MANAGED, blockPublicAccess: BlockPublicAccess.BLOCK_ALL, removalPolicy: RemovalPolicy.DESTROY, autoDeleteObjects: true, }); }
This is where we will check to see if a string has been passed as a prop named bucketName
to the Stack. It is not required to be passed, but if it is, we want to use that bucket as the deployment destination. To do that, we need to get the IBucket
using Bucket.fromBucketName
.
If no prop named bucketName
was passed to the Stack, we will create a bucket. In either case, the bucket that we will be deploying to is referenced by deploymentBucket
.
Deploying to the Bucket
const data = { bucketName: deploymentBucket.bucketName, text: 'Hello World', }; new BucketDeployment(this, 'Deployment', { sources: [Source.jsonData('config.json', data)], destinationBucket: deploymentBucket, });
Now, we will create a simple JSON file using Source.jsonData
and upload this file to the bucket. This will either be an existing bucket referenced in the environment variables, or a newly created bucket. In either case, we can use deplyomentBucket
as the destinationBucket
because we are always creating an IBucket
. If the bucket already exists, we use fromBucketName
and if the bucket does not exist, new Bucket
will return an IBucket
.
Deploying with Environment Variables
Note: You must replace
conditional-cdk-deploy-demo
with a unique name
export BUCKET_NAME=conditional-cdk-deploy-demo yarn launch
or
BUCKET_NAME=conditional-cdk-deploy-demo yarn launch
Once completed, we can see that an existing S3 bucket has the config.json
file in it.
aws s3 ls s3://conditional-cdk-deploy-demo aws s3 cp s3://conditional-cdk-deploy-demo/config.json ./ cat config.json
Deploying without Environment Variables
unset BUCKET_NAME
yarn launch
When the CDK is deployed, a new bucket will be created. This bucket name will be in the output of the CDK and can be used to verify the creation of the bucket and the deployment of the config.json
file.
Testing the CDK
In order to verify that our CDK is correct, we should test it. This is done as part of a projen build. In this demo, we are using Snapshots to test.
test('Snapshot', () => { const app = new App(); const stack = new ConditionalDeployment(app, 'test', {}); const template = Template.fromStack(stack); expect(template.toJSON()).toMatchSnapshot(); }); test('SnapshotWithBucketName', () => { const app = new App(); const stack = new ConditionalDeployment(app, 'test', { bucketName: 'test-bucket', }); const template = Template.fromStack(stack); expect(template.toJSON()).toMatchSnapshot(); });
This will now create snapshots for both scenarios. Without the second snapshot, we would have uncovered lines in the test.