dotmindlabs
dotmindlabs

Reputation: 908

CDK not updating

Running cdk deploy after updating my Stack:

export function createTaskXXXX (stackScope: Construct, workflowContext: WorkflowContext) {
  const lambdaXXXX = new lambda.Function(stackScope, 'XXXXFunction', {
    runtime: Globals.LAMBDA_RUNTIME,
    memorySize: Globals.LAMBDA_MEMORY_MAX,
    code: lambda.Code.fromAsset(CDK_MODULE_ASSETS_PATH),
    handler: 'xxxx-handler.handler',
    timeout: Duration.minutes(Globals.LAMBDA_DURATION_2MIN),
    environment: {
      YYYY_ENV: (workflowContext.production) ? 'prod' : 'test',
      YYYY_A_LOCATION: `s3://${workflowContext.S3ImportDataBucket}/adata-workflow/split-input/`,
      YYYY_B_LOCATION: `s3://${workflowContext.S3ImportDataBucket}/bdata-workflow/split-input/`  <--- added
    }
  })
  lambdaXXXX.addToRolePolicy(new iam.PolicyStatement({
    effect: Effect.ALLOW,
    actions: ['s3:PutObject'],
    resources: [
        `arn:aws:s3:::${workflowContext.S3ImportDataBucket}/adata-workflow/split-input/*`,
        `arn:aws:s3:::${workflowContext.S3ImportDataBucket}/bdata-workflow/split-input/*` <---- added
    ]
  }))

I realize that those changes are not updated at stack.template.json:

...
        "Runtime": "nodejs12.x",
        "Environment": {
          "Variables": {
            "YYYY_ENV": "test",
            "YYYY_A_LOCATION": "s3://.../adata-workflow/split-input/"
          }
        },
        "MemorySize": 3008,
        "Timeout": 120
      }
...

I have cleaned cdk.out and tried the deploy --force, but never see any updates.

Is it deleting the stack and redeploying the only final alternative, or am I missing something? I think at least at synth should generate different results.

(I also changed to cdk 1.65.0 in my local system to match the package.json) Thanks.

EDITED: I git clone the project, and did npm install and cdk synth again and finally saw the changes, I would like not to do this every time, any light of what could be blocking the correct synth generation?

EDITED 2: After a diff between the bad old project and the new from git where synth worked, i realized that some of my project files that had .ts (for example cdk.ts my App definition) also had replicas with .js and .d.ts., such as cdk.js and cdk.d.ts. Could i have runned some command by mistake that compiled Typescript, i will continue to investigate, thanks to all answers.

Upvotes: 5

Views: 15407

Answers (3)

VenVig
VenVig

Reputation: 915

I have the latest cdk 2.95.1. But I still seem to be running into the problem. I cleared out my cdk.out, did a synth and then deployed, but in vain. What worked for me was to deploy the cloudformation template that I got after synthesizing. Here is the command

 cdk deploy MyStack  --template .\cdk.out\MyStack.template.json

Upvotes: 0

Tucker
Tucker

Reputation: 7362

This is how I do it. Works nicely so far. Basically you can do the following:

  1. Push your lambda code as a zip file to an s3 bucket. The bucket must have versioning enabled. .

  2. The CDK code below will do the following:

    1. Create a custom resource. It basically calls s3.listObjectVersions for my lambda zip file in S3. I grab the first returned value, which seems to be the most recent object version all the time (I cannot confirm this with the documentation though). I also create a role for the custom resource.
    2. Create the lambda and specify the code as the zip file in s3 AND THE OBJECT VERSION RETURNED BY THE CUSTOM RESOURCE! That is the most important part.
    3. Create a new lambda version.

Then the lambda's code updates when you deploy the CDK stack!

const versionIdKey = 'Versions.0.VersionId';
const isLatestKey = 'Versions.0.IsLatest'
const now = new Date().toISOString();

const role = new Role(this, 'custom-resource-role', {
    assumedBy: new ServicePrincipal('lambda.amazonaws.com'),
});
role.addManagedPolicy(ManagedPolicy.fromAwsManagedPolicyName('AdministratorAccess')); // you can make this more specific


// I'm not 100% sure this gives you the most recent first, but it seems to be doing that every time for me.  I can't find anything in the docs about it...
const awsSdkCall: AwsSdkCall = {
    action: "listObjectVersions",
    parameters: {
        Bucket: buildOutputBucket.bucketName, // s3 bucket with zip file containing lambda code.
        MaxKeys: 1,
        Prefix: LAMBDA_S3_KEY, // S3 key of zip file containing lambda code
    },
    physicalResourceId: PhysicalResourceId.of(buildOutputBucket.bucketName),
    region: 'us-east-1', // or whatever region
    service: "S3",
    outputPaths: [versionIdKey, isLatestKey]
};

const customResourceName = 'get-object-version'
const customResourceId = `${customResourceName}-${now}` // not sure if `now` is neccessary...

const response = new AwsCustomResource(this, customResourceId, {
    functionName: customResourceName,
    installLatestAwsSdk: true,
    onCreate: awsSdkCall,
    onUpdate: awsSdkCall,
    policy: AwsCustomResourcePolicy.fromSdkCalls({resources: AwsCustomResourcePolicy.ANY_RESOURCE}), // you can make this more specific
    resourceType: "Custom::ListObjectVersions",
    role: role 
})

const fn = new Function(this, 'my-lambda', {
    functionName: 'my-lambda',
    description: `${response.getResponseField(versionIdKey)}-${now}`,
    runtime: Runtime.NODEJS_14_X,
    memorySize: 1024,
    timeout: Duration.seconds(5),
    handler: 'index.handler',
    code: Code.fromBucket(buildOutputBucket, LAMBDA_S3_KEY, response.getResponseField(versionIdKey)),  // This is where the magic happens. You tell CDK to use a specific S3 object version when updating the lambda.
    currentVersionOptions: {
        removalPolicy: RemovalPolicy.DESTROY,
    },
});

new Version(this, `version-${now}`, { // not sure if `now` is neccessary...
    lambda: fn,
    removalPolicy: RemovalPolicy.DESTROY
})

Do note: For this to work, you have to upload your lambda zip code to S3 before each cdk deploy. This can be the same code as before, but the s3 bucket versioning will create a new version. I use code pipeline to do this as part of additional automation.

Upvotes: 0

lynkfox
lynkfox

Reputation: 2400

because CDK uses Cloudformation, it performs an action to determine a ChangeSet. This is to say, if it doesn't think anything has changed, it wont change that resource.

This can, of course, be very annoying as sometimes it thinks it is the same and doesn't update when there is actually a change - I find this most often with Layers and using some form of make file to generate the zips for the layers. Even tho it makes a 'new' zip whatever it uses to determine that the zip is updated recalls it as the same because of ... whatever compression/hash/ect changes are used.

You can get around this by updating the description with a datetime. Its assigned at synth (which is part of the cdk deploy) and so if you do a current now() of datetime

You can also use cdk diff to see what it thinks the changes are.

And finally... always remember to save your file before deployments as, depending on your IDE, it may not be available to the command line ;)

Upvotes: 5

Related Questions