1

I'm using the AWS CDK to deploy code and infrastructure from a monorepo that includes both my front and backend logic (along with the actual CDK constructs). I'm using the CDK Pipelines library to kick off a build on every commit to my main git branch. The pipeline should:

  1. deploy all the infrastructure. Which at the moment is just an API gateway with an endpoint powered by a Lambda function, and a S3 bucket that will hold the built frontend.
  2. configure and build the frontend by providing the API URL that was just created.
  3. move the built frontend files to the S3 bucket.

My Pipeline is in a different account than the actual deployed infrastructure. I've bootstrapped the environments and set up the correct trust policies. I've succeeded in the first two points by creating the constructs and saving the API URL as a CfnOutput. Here's a simplified version of the Stack:

class MyStack extends Stack {
  constructor(scope, id, props) {
    super(scope, id, props);
    
    const API = new aws_apigateway.LambdaRestApi(this, id, {
      handler: lambda,
    });

    this.apiURL = new CfnOutput(this, 'api_url', { value: api.url });

    const bucket = new aws_s3.Bucket(this, name, {
      bucketName: 'frontend-bucket',
      ...
    });

    this.bucketName = new CfnOutput(this, 'bucket_name', {
      exportName: 'frontend-bucket-name',
      value: bucket.bucketName
    })

}

Here's my pipeline stage:

export class MyStage extends Stage {
  public readonly apiURL: CfnOutput;
  public readonly bucketName: CfnOutput;

  constructor(scope, id, props) {
    super(scope, id, props);

    const newStack = new MyStack(this, 'demo-stack', props);

    this.apiURL = backendStack.apiURL;
    this.bucketName = backendStack.bucketName;
  }
}

And finally here's my pipeline:

export class MyPipelineStack extends Stack {
  constructor(scope, id, props) {
    super(scope, id, props);

    const pipeline = new CodePipeline(this, 'pipeline', { ... });
    const infrastructure = new MyStage(...);
    
    // I can use my output to configure my frontend build with the right URL to the API.
    // This seems to be working, or at least I don't receive an error

    const frontend = new ShellStep('FrontendBuild', {
      input: source,
      commands: [
        'cd frontend',
        'npm ci',
        'VITE_API_BASE_URL="$AWS_API_BASE_URL" npm run build'
      ],
      primaryOutputDirectory: 'frontend/dist',
      envFromCfnOutputs: {
        AWS_API_BASE_URL: infrastructure.apiURL
      }
    })

    // Now I need to move the built files to the S3 bucket
    // I cannot get the name of the bucket however, it errors with the message:
    // No export named frontend-bucket-name found. Rollback requested by user.

    const bucket = aws_s3.Bucket.fromBucketAttributes(this, 'frontend-bucket', {
      bucketName: infrastructure.bucketName.importValue,
      account: 'account-the-bucket-is-in'
    });

    const s3Deploy = new customPipelineActionIMade(frontend.primaryOutput, bucket)
    const postSteps = pipelines.Step.sequence([frontend, s3Deploy]);
    pipeline.addStage(infrastructure, {
      post: postSteps
    });
  }

}

I've tried everything I can think of to allow my pipeline to access that bucket name, but I always get the same thing: // No export named frontend-bucket-name found. Rollback requested by user. The value doesn't seem to get exported from my stack, even though I'm doing something very similar for the API URL in the frontend build step.

If I take away the 'exportName' of the bucket and try to access the CfnOutput value directly I get a dependency cannot cross stage boundaries error.

This seems like a pretty common use case - deploy infrastructure, then configure and deploy a frontend using those constructs, but I haven't been able to find anything that outlines this process. Any help is appreciated.

jhummel
  • 1,724
  • 14
  • 20
  • your cdk synth (or simple synth step) is performed as part of the pipeline yes? If its not, that output doesn't exist yet. Are you using Simple synth stage from the `Pipelines` library or something more akin to a codebuild with a cdk synth command internal? – lynkfox Aug 10 '22 at 15:15
  • @lynkfox Yes. `cdk synth` is part of the pipeline. It's specified as a command `command: ['npm install', 'npm run build', 'cdk synth']` – jhummel Aug 10 '22 at 15:35

0 Answers0