DEV Community

Cover image for πŸ„ AWS CDK 101 🌸 - lambda & CDK watch
Aravind V
Aravind V

Posted on • Updated on • Originally published at devpost.hashnode.dev

πŸ„ AWS CDK 101 🌸 - lambda & CDK watch

In this article let us build necessary components which we need to setup a basic lambda stack which will be used in later in subsequent articles to act us a web hook taking some data into our ecosystem from other demo projects.

Beginners new to AWS CDK, please do look at my previous articles in this series.

If incase missed the previous article do find it with the below links.

πŸ” Original previous post at πŸ”— Dev Post

πŸ” Reposted previous post at πŸ”— dev to @aravindvcyber

First before we start moving forward let us try to do some cleanup on the current demo workshop stack and understand how it reflects this changes. This will give us good understanding on certain concepts before we move forward.

Removing the unwanted resources βŒ›

Open lib/cdk-workshop-stack.ts.

Here let us simply comment out the components initially created which is the SQS queue and the SNS topic with subscriptions, it should look like the below.


export class CdkWorkshopStack extends Stack {
  constructor(scope: Construct, id: string, props?: StackProps) {
    super(scope, id, props);

    // const queue = new sqs.Queue(this, 'CdkWorkshopQueue', {
    //   visibilityTimeout: Duration.seconds(300)
    // });

    // const topic = new sns.Topic(this, 'CdkWorkshopTopic');

    // topic.addSubscription(new subs.SqsSubscription(queue));
  }
}

Enter fullscreen mode Exit fullscreen mode

What we have achieved is like something we can understand with the cdk diff command.

IAM Statement Changes
β”Œβ”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚   β”‚ Resource                        β”‚ Effect β”‚ Action          β”‚ Principal                 β”‚ Condition                                                       β”‚
β”œβ”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚ - β”‚ ${CdkWorkshopQueue50D9D426.Arn} β”‚ Allow  β”‚ sqs:SendMessage β”‚ Service:sns.amazonaws.com β”‚ "ArnEquals": {                                                  β”‚
β”‚   β”‚                                 β”‚        β”‚                 β”‚                           β”‚   "aws:SourceArn": "${CdkWorkshopTopicD368A42F}"                β”‚
β”‚   β”‚                                 β”‚        β”‚                 β”‚                           β”‚ }                                                               β”‚
β””β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
(NOTE: There may be security-related changes not in this list. See https://github.com/aws/aws-cdk/issues/1299)

Resources
[-] AWS::SQS::Queue CdkWorkshopQueue50D9D426 destroy
[-] AWS::SQS::QueuePolicy CdkWorkshopQueuePolicyAF2494A5 destroy
[-] AWS::SNS::Subscription CdkWorkshopQueueCdkWork
[-] AWS::SNS::Topic CdkWorkshopTopicD368A42F destroy
Enter fullscreen mode Exit fullscreen mode

This signifies that while we delete the SQS and SNS, it eventually removes the newly created queue policy and the topic subscription associated to this.

Make sure you run cdk deploy to cleanup the environment changes.

Simple lambda stack πŸ”­

Now we have cleaned our environment, let us start now from basics by trying to build a simple lambda stack which will be acting as a common gateway for the messages coming into our environment as we build this forward.

import { Construct } from 'constructs';

The AWS CDK is shipped with an extensive library of constructs called the AWS Construct Library. The construct library is divided into modules, one for each AWS service. For example, if you want to define an AWS Lambda function, we will need to use the AWS Lambda construct library.

Before we proceed let us create a new stack by following the below steps

In the lib folder create a new file like CommonEventStack.ts, where we will add the basic template as follows.


import { Stack, StackProps } from 'aws-cdk-lib';
import { Construct } from 'constructs';

export class CommonEventStack extends Stack {
  constructor(scope: Construct, id: string, props?: StackProps) {
    super(scope, id, props);


  }
}

Enter fullscreen mode Exit fullscreen mode

Then go to your bin\cdk-workshop.ts and import the new stack we just created.

#!/usr/bin/env node
import * as cdk from 'aws-cdk-lib';
import { CdkWorkshopStack } from '../lib/cdk-workshop-stack';
// importing our new stack
import { CommonEventStack } from '../lib/common-event-stack';

const app = new cdk.App();
new CdkWorkshopStack(app, 'CdkWorkshopStack');
// initializing our new stack
new CommonEventStack(app, 'CommonEventStack');

Enter fullscreen mode Exit fullscreen mode

It is time to run npm run build to make sure we never introduced any error in the process.

Finally we can run cdk ls to see the below output.

CdkWorkshopStack
CommonEventStack
Enter fullscreen mode Exit fullscreen mode

And by the way I just gave the prefix CommonEvent* to our new stack resources, which we are about create also to demonstrate that we can have multiple stacks in the same project.

It is now time to create our lambda function, let us create a folder called lambda in the root of the project and add a new file event-entry.ts, as shown below. Note I have started with TypeScript file and it needs to be transpiled to JavaScript when we deploy it into lambda.

exports.receiver = async function(event:any) {
  console.log("request:", JSON.stringify(event, undefined, 2));
  return {
    statusCode: 200,
    headers: { "Content-Type": "text/plain" },
    body: `Message Received: ${event}\n`
  };
};
Enter fullscreen mode Exit fullscreen mode

Once you run npm build, you can notice the javascript files are created in the same folder, event-entry.js

"use strict";
exports.receiver = async function (event) {
    console.log("request:", JSON.stringify(event, undefined, 2));
    return {
        statusCode: 200,
        headers: { "Content-Type": "text/plain" },
        body: `Message Received: ${event}\n`
    };
};
//# sourceMappingURL*********

Enter fullscreen mode Exit fullscreen mode

Let us use this function to build our lambda function inside our new stack CommonEventStack.ts.

    //  A simple lambda Lambda resource definition
    const eventEntry = new lambda.Function(this, 'EventEntryHandler', {
      runtime: lambda.Runtime.NODEJS_14_X,    // execution environment
      code: lambda.Code.fromAsset('lambda'),  // code loaded from "lambda" directory
      handler: 'event-entry.receiver'                // file is "event-entry", function is "receiver"
    });
  }
Enter fullscreen mode Exit fullscreen mode

Don't forget to add the necessary imports if it complains πŸ“Ž

import * as lambda from 'aws-cdk-lib/aws-lambda'
Enter fullscreen mode Exit fullscreen mode

Here we are using NodeJs 14x runtime and specifying the handler function to be from the file named event-entry with function name like receiver.

It is time to run cdk synth CommonEventStack, to find the changes in the yaml template or run cdk diff CommonEventStack to find the changes more readable.

This to lookout for is listed below in the log below:

IAM Statement Changes
β”Œβ”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚   β”‚ Resource                             β”‚ Effect β”‚ Action         β”‚ Principal                    β”‚ Condition β”‚
β”œβ”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚ + β”‚ ${EventEntryHandler/ServiceRole.Arn} β”‚ Allow  β”‚ sts:AssumeRole β”‚ Service:lambda.amazonaws.com β”‚           β”‚
β””β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
IAM Policy Changes
β”Œβ”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚   β”‚ Resource                         β”‚ Managed Policy ARN                                                             β”‚
β”œβ”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚ + β”‚ ${EventEntryHandler/ServiceRole} β”‚ arn:${AWS::Partition}:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole β”‚
β””β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Resources
[+] AWS::IAM::Role EventEntryHandler/ServiceRole EventEntryHandlerServiceRoleF9517B59 
[+] AWS::Lambda::Function EventEntryHandler EventEntryHandler0826D724 
Enter fullscreen mode Exit fullscreen mode

Here two resources are created IAM:role and Lambda:function. Basically a new role is created to be assumed by the lambda function we created for its proper execution.

Let us deploy it, by running cdk deploy CommonEventStack and confirming with y for the above IAM policy changes.


CommonEventStack: creating CloudFormation changeset...

 βœ…  CommonEventStack

✨  Deployment time: 46.9s

Stack ARN:
arn:aws:cloudformation:ap-south-1:********:stack/CommonEventStack/93688c10-a10a-11ec-b942-0ad3136ae540

✨  Total time: 60.19s

Enter fullscreen mode Exit fullscreen mode

Inspection in AWS console πŸ“Œ

Now we can navigate to the lambda in AWS console into your default region and you will be able to identify the lambda.

Deployed Lambda

Let us test this lambda now πŸ‚

For which we have to have some sample test event as follows.

Sample Test event

Let us create run the same test, we have created above.

Sample Test event Execution logs

You can also find this logged inside the cloud watch logs.

Cloud watch logs

And that is it, we have a new lambda function running which is ready to receive our messages. So what we have achieved in this article is only tech demonstration, which can be further vertically integrated based on the use cases and is not considered to be the best approach, rather it is only a know-how.

Before we complete this article let us understand one more cdk cli which we would find to be very much helpful in your development environment.

Hot swapping deployments 🎺

cdk deploy --hotswap

This command deliberately introduces drift in CloudFormation stacks in order to speed up deployments. For this reason, only use it for development purposes. Never use hotswap for your production deployments!

Let us make a simple change in our code for lambda in the entry

exports.receiver = async function(event:any) {
  console.log("request:", JSON.stringify(event, undefined, 2));
  return {
    statusCode: 200,
    headers: { "Content-Type": "text/plain" },
    body: `Hotswapped now! \nMessage Received: ${JSON.stringify(event)}\n`
  };
};
Enter fullscreen mode Exit fullscreen mode

Just be mindful of the fact this only publishes the assets already built for lambda, in certain cases you will have used typescript in lambda and forget to build it before hotswaping, in that case the distributable files configured will be published but the js files would never have been updated yet. I make sure to add a script in my package json to run it like a script in package.json.

"fast": "npm run build && cdk deploy CommonEventStack --hotswap"

The total time taken is reduced, but what is significant to notice here is the deployment time which is reduced to very small value. Earlier it is 45+s for full deployment, now here it is only 2+ seconds, would be useful in the development environment.

✨ hotswapping resources:
   ✨ Lambda Function 'CommonEventStack-EventEntryHandler0826D724-xaVWqcUsxERH'
✨ Lambda Function 'CommonEventStack-EventEntryHandler0826D724-xaVWqcUsxERH' hotswapped!

 βœ…  CommonEventStack

✨  Deployment time: 2.22s

Stack ARN:
arn:aws:cloudformation:ap-south-1:575066707855:stack/CommonEventStack/93688c10-a10a-11ec-b942-0ad3136ae540

✨  Total time: 15.81s

Enter fullscreen mode Exit fullscreen mode

Hotswapped Changes in lambda

Here I introduced some jargon drift, let us see what it means and how it can be helpful. To enable this you can select a stack or a resource under it and enable drift detection to capture it for tracking and audit.

Drift detection 🎒

Drift detection enables you to detect whether a stack's actual configuration differs, or has drifted, from its expected configuration. Use CloudFormation to detect drift on an entire stack, or on individual resources within the stack.

A resource is considered to have drifted if any of its actual property values differ from the expected property values. This even includes if the property or resource has been deleted. A stack is considered to have drifted if one or more of its resources have drifted.

Here instead of using native cloud formation deployment, a more simple swift deployment is carried out by hot-swapping deployment by making use of the drifting changes on top of the initial stack.

Sample Drift status

Resource drift status code and description πŸ—½

This is basically a comparison with the recent cloudformation deployment.

  • DELETED The resource differs from its expected template configuration because the resource has been deleted.
  • MODIFIED The resource differs from its expected template configuration.
  • NOT_CHECKED CloudFormation has not checked if the resource differs from its expected template configuration.
  • IN_SYNC The resource's current configuration matches its expected template configuration.

Before we wrap up let us see one more deploy cli command below.

CDK Watch πŸŽͺ

CDK watch helps to monitor the file changes and invoke cdk deploy when it is needed. It monitors the files specified in the include and the exclude list in the cdk.json file.


{
    "watch": {
    "include": [
      "**"
    ],
    "exclude": [
      "README.md",
      "cdk*.json",
      "**/*.d.ts",
      "lambda/*.ts",
      "tsconfig.json",
      "package*.json",
      "yarn.lock",
      "node_modules",
      "test"
    ]
  },
}


Enter fullscreen mode Exit fullscreen mode

In the above snippet, I have purposefully updated the **/*.js to lambda/*.ts. This change is done to make sure the ts file changes in our lambda source not detectable at the same time it will detect the .js file which be emitted by tsc.

So I will be launching couple of windows to run tsc -w and cdk watch CommonEventStack --hotswap. Working in parallel this will automatically deploy the expect lambda code changes, basically these are developer friendly customizations.

tsc -w this rewrites the js files.

[4:26:07 PM] File change detected. Starting incremental compilation...

[4:26:11 PM] Found 0 errors. Watching for file changes.
Enter fullscreen mode Exit fullscreen mode

cdk watch CommonEventStack --hotswap published my js files automatically and swiftly.

Detected change to 'lambda/event-entry.js' (type: change). Triggering 'cdk deploy'

✨  Synthesis time: 21.92s

✨ hotswapping resources:
   ✨ Lambda Function 'CommonEventStack-EventEntryHandler0826D724-xaVWqcUsxERH'
✨ Lambda Function 'CommonEventStack-EventEntryHandler0826D724-xaVWqcUsxERH' hotswapped!

 βœ…  CommonEventStack

✨  Deployment time: 2.17s

Stack ARN:
arn:aws:cloudformation:ap-south-1:575066707855:stack/CommonEventStack/93688c10-a10a-11ec-b942-0ad3136ae540
current credentials could not be used to assume 'arn:aws:iam::575066707855:role/cdk-hnb659fds-lookup-role-575066707855-ap-south-1', but are for the right account. Proceeding anyway.
(To get rid of this warning, please upgrade to bootstrap version >= 8)

✨  Total time: 24.09s

Enter fullscreen mode Exit fullscreen mode

We will add more connections to this lambda and make it more usable in the coming articles stay subscribed.

⏭ We have our next article in serverless, do check out

aws-cdk-101-api-gateway-construct-usage-throttle-quota-usage-plans-api-keys

Thanks for supporting! πŸ™

Would be really great if you like to β˜• Buy Me a Coffee, to help boost my efforts.

Buy Me a Coffee at ko-fi.com

Also follow my posts in the platform of your choice listed below.

πŸ” Original post at πŸ”— Dev Post

πŸ” Reposted at πŸ”— dev to @aravindvcyber

Top comments (0)