简体   繁体   中英

How to wait stack to complete before executing code in AWS CDK?

I'm trying AWS CDK and got stuck when I tried to execute a code block that depends on the stack completion.

Here's my current code:

class Application extends cdk.Construct {
    constructor(scope: cdk.Construct, id: string) {
        super(scope, id);
        const webStack = new WebsiteStack(app, `website-stack-${id}`, { stage: id })
        const buildStack = new CodeBuildStack(app, `codebuild-stack-${id}`, { stage:id, bucket: webStack.websiteBucket, distribution: webStack.websiteDistribution });
        this.generateBuildParameter(id, webStack, buildStack)
    }

    generateBuildParameter(id: string, webStack: WebsiteStack, buildStack: CodeBuildStack) {
        const buildParam = {
            projectName: buildStack.buildProject.projectName,
            sourceVersion: id,
            environmentVariablesOverride: [
              { name: "STAGE", value: id, type: "PLAINTEXT" },
              { name: "WEBSITE_BUCKET", value: webStack.websiteBucket.bucketName, type: "PLAINTEXT" },
              { name: "CLOUDFRONT_DISTRIBUTION_ID", value: webStack.websiteDistribution.distributionId, "type": "PLAINTEXT" }
            ],
            buildspecOverride: "./buildspec.yml"
        }
        fse.outputJson(`./cdk.out/build-parameters/build-${id}.json`, buildParam, (err: Error) => {
            if (err) {
                throw err
            };
            console.log(`build parameter has been created in "../cdk.out/build-parameters/build-${id}.json"`);
        })
    }
}

I'm just trying to generate a json file that depends on the buildStack . However, it seems that it's not waiting for the stack to complete.

Here's my current output:

{
   "projectName":"${Token[TOKEN.41]}",
   "sourceVersion":"master",
   "environmentVariablesOverride":[{"name":"STAGE","value":"master","type":"PLAINTEXT"},{"name":"WEBSITE_BUCKET","value":"${Token[TOKEN.17]}","type":"PLAINTEXT"},{"name":"CLOUDFRONT_DISTRIBUTION_ID","value":"${Token[TOKEN.26]}","type":"PLAINTEXT"}],
   "buildspecOverride":"./buildspec.yml"
}

Does AWS CDK support Promise or some sort to wait the stack to be completed?

If you're trying to reference 'dynamic' things like the CloudFront distribution Id that will be generated, I would probably try to have 2 different stacks, and have one depend on the other.

I'm not sure I understand your use case correctly. But maybe check out the Core package readme that contains how to parameterize certain things and pass in information across stacks.

https://docs.aws.amazon.com/cdk/api/latest/docs/core-readme.html

EDIT: you can do something like:

var s1 = new stackOne();
var s2 = new stackTwo().addDependency(s1);

This blog post was helpful for me: https://lanwen.ru/posts/aws-cdk-edge-lambda/

Edit: Some practical examples of sharing resources between stacks. StackA creates a CloudFront distribution (The ID of the distribution is dynamic)

StackB needs the CloudFront distribution Id to set up the alarm.

// stackA
export class CloudFrontStack extends cdk.Stack {
  readonly distribution: cf.CloudFrontWebDistribution;
  constructor(scope: cdk.Construct, id: string, props?: cdk.StackProps) {
    super(scope, id, props);
 distribution = new cf.CloudFrontWebDistribution(this, 'my-cloud-front-dist', {//props here...} );
 }
}

// stack B
export class AlarmStack extends cdk.Stack {
constructor(scope: cdk.Construct, id: string, cloudfrontDistributionId: string, props?: cdk.StackProps) {
    super(scope, id, props);   
    new alarm.Alarm()// alarm definition, need ID of CF Distribution here.
 }
}

//index.ts where everything is linked:
const app = new cdk.App();
const stack1= new CloudFrontStack(app, 'CFStack1');
const stack2= new AlarmStack(app, 'AlarmStack', stack1.distribution.distributionId);
// you can even specify that stack2 cannot be created unless stack1 succeeds.
stack2.addDependency(stack1);

EDIT2 : For using resources that have been created after a stack is built and outside of the CDK, the easiest way I can think of is to define CfnOutputs and then query the AWS api using the CLI, either manually or in the CI/CD pipeline if we're automating more things after.

Example2: using the previous example we will define an output called CloudFront-DistributioId and query it using the CLI.

// stackA
export class CloudFrontStack extends cdk.Stack {
  readonly distribution: cf.CloudFrontWebDistribution;
  constructor(scope: cdk.Construct, id: string, props?: cdk.StackProps) {
    super(scope, id, props);
 distribution = new cf.CloudFrontWebDistribution(this, 'my-cloud-front-dist', {//props here...} );

// define a cloud formation output so we can query later  
new CfnOutput(this, 'CloudFront-DistributionId', {
  exportName: 'CloudFront-DistributionId',
  value: cloudFrontDistribution.distributionId,
  description: 'The dynamic value created by aws of our CloudFront distribution id. '
});
 }
}

After the stack is created, in the pipeline/cli, use the following command to get the value of the variable:

aws cloudformation describe-stacks --stack-name CloudFrontStack --query "Stacks[0].Outputs[?OutputKey=='CloudFront-DistributionId'].OutputValue"

This will produce the Distribution ID that was created after the stack built.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM