2
votes

How can I get "nice" stack names when executing npx cdk synth in an AWS CDK application that is made up of multiple stacks that I would like to deploy to multiple environments?

#!/usr/bin/env node
import * as cdk from '@aws-cdk/core';
import * as s3 from '@aws-cdk/aws-s3';
import * as lambda from '@aws-cdk/aws-lambda';


class PersistenceStack extends cdk.Stack {
    public readonly bucket: s3.Bucket;
    constructor(scope: cdk.Construct, id: string, props?: cdk.StackProps) {
        super(scope, id, props);
        this.bucket = new s3.Bucket(this, 'bucket');
    }
}


interface ApplicationStackProps extends cdk.StackProps {
    bucket: s3.Bucket;
}


class ApplicationStack extends cdk.Stack {
    constructor(scope: cdk.Construct, id: string, props: ApplicationStackProps) {
        super(scope, id, props);
        const myLambda = new lambda.Function(this, 'my-lambda', {
            runtime: lambda.Runtime.NODEJS_12_X,
            code: new lambda.AssetCode('my-lambda'),
            handler: 'index.handler'
        });
        props.bucket.grantReadWrite(myLambda);
    }
}


class MyApp extends cdk.Construct {

    constructor(scope: cdk.Construct, id: string, props: cdk.StackProps) {
        super(scope, id);

        const persistenceStack = new PersistenceStack(this, 'persistence-stack', {
            ...props,
            description: 'persistence stack',
            stackName: `${id}-persistence-stack`,
        });

        const applicationStack = new ApplicationStack(this, 'application-stack', {
            ...props,
            description: 'application stack',
            stackName: `${id}-application-stack`,
            bucket: persistenceStack.bucket,
        });
        applicationStack.addDependency(persistenceStack);
    }
}


const app = new cdk.App();

new MyApp(app, `test`, { env: { account: '111111111111', region: 'eu-west-1' } });
new MyApp(app, `prod`, { env: { account: '222222222222', region: 'eu-west-1' } });

The problem that I am facing is that this generates outputs similar to:

Successfully synthesized to [...]/my-app/cdk.out
Supply a stack id (prodpersistencestackFE36DF49, testpersistencestack6C35C777, prodapplicationstackA0A96586, testapplicationstackE19450AB) to display its template.

What I expected to see is "nice" stack names (since I have specified the stackName properties when calling the constructors):

Successfully synthesized to [...]/my-app/cdk.out
Supply a stack id (prodpersistencestack, testpersistencestack, prodapplicationstack, testapplicationstack) to display its template.

Motivation: I need "nice" (or at least predictable) stack names to feed into the next step our CI/CD pipeline so that the build server can deploy the CDK app.

AWS CDK version: 1.21.1

1
Can you provide the full stack? or at least part of it.. since the stack is empty there are no resources to rename - Amit Baranes
@AmitBaranes The resources in each stack are not important to reproduce the problem. I have updated the example to contain an S3 bucket and a Lambda function, but they could be anything. I need the stack names to be predictable so that I can configure our deployment pipeline with each name respectively - matsev
To be honest, I've spent around 5 hours on this issue... still no luck - Amit Baranes
The only solution I found was this npm package: npmjs.com/package/@tokkiyaa/… which need some customizations cdkMonkeyPatch.patch(require('@aws-cdk/cdk/lib/util/uniqueid')); imgur.com/t2IQyga - Amit Baranes
@AmitBaranes Thanks. I have filed and issue to the AWS CDK team regarding the matter and I plan to report back here if I get a good answer. After all, the CDK it is still early days for the CDK - matsev

1 Answers

1
votes

This AWS CDK issue addresses this concern. In its response it is stated that the stack ids are like this by design (since one can have the same stack name in multiple environments).

In order to use the stack name as a deployment parameter, one can implement a reverse lookup of the cdk.out/manifest.json file because the mapping information between stack ids and stack names is available there. Below is an excerpt of how such a lookup can be implemented using jq:

# get stack name from somewhere, e.g. test-persistence-stack, prod-persistence-stack, test-application-stack or prod-application-stack from the question above
stackName=    

# extract stack id from ./cdk.out/manifest.json
stackId=$(jq -r --arg stackName "$stackName" \
   '.artifacts
   | to_entries[]
   | select(.value.properties.stackName == $stackName)
   | .key
   ' \
   < "./cdk.out/manifest.json" \
   )

# call cdk deploy with stack id as parameter
npx cdk deploy \
  --app cdk.out \
  --require-approval never \
  "$stackId"