New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Example: AWS SAM #716

Open
0xdevalias opened this Issue Sep 14, 2018 · 10 comments

Comments

Projects
None yet
6 participants
@0xdevalias
Copy link

0xdevalias commented Sep 14, 2018

I think it could be useful to have a basic canonical example of how to use SAM from CDK (See also: #703, awslabs/aws-sam-cli#663)

If it would be useful, I could probably knock together what I figured out here into a PR to examples? If so.. what would be the best naming/etc for it? Potentially could choose one of the simpler examples from the following and translate it to CDK:

I found the following, so should be doable:

But when I was exploring the docs, it didn't look like I could do much without dropping into the cloudformation namespace (which is probably fine, as this is 'lower level/direct mapping'):

So I decided to try and make a basic function example from that, just to see how it would work. It took me a little while to figure the intricacies of the types used and their interrelations:

import sam = require('@aws-cdk/aws-serverless');
const helloWorld = new sam.cloudformation.FunctionResource(this, "HelloWorld", {
            functionName: "HelloWorld",
            description: "Greeting the world",
            codeUri: "./target",
            handler: "hello-world",
            runtime: lambda.Runtime.Go1x.name,
            tracing: "active",
            events: {
                CatchAll: {
                    type: "Api",
                    properties: {
                        path: "/{proxy+}",
                        method: "ANY",
                        // restApiId: ""
                    }
                }
            }
        });

Which synthesises to:

Transform: 'AWS::Serverless-2016-10-31'
Resources:
    HelloWorld:
        Type: 'AWS::Serverless::Function'
        Properties:
            CodeUri: ./target
            Handler: hello-world
            Runtime: go1.x
            Description: 'Greeting the world'
            Events:
                CatchAll:
                    Properties:
                        Method: ANY
                        Path: '/{proxy+}'
                    Type: Api
            FunctionName: HelloWorld
            Tracing: active
    CDKMetadata:
        Type: 'AWS::CDK::Metadata'
        Properties:
            Modules: '@aws-cdk/assets=0.9.0,@aws-cdk/aws-cloudwatch=0.9.0,@aws-cdk/aws-codepipeline-api=0.9.0,@aws-cdk/aws-ec2=0.9.0,@aws-cdk/aws-elasticloadbalancing=0.9.0,@aws-cdk/aws-events=0.9.0,@aws-cdk/aws-iam=0.9.0,@aws-cdk/aws-kms=0.9.0,@aws-cdk/aws-lambda=0.9.0,@aws-cdk/aws-s3=0.9.0,@aws-cdk/aws-s3-notifications=0.9.0,@aws-cdk/aws-serverless=0.9.0,@aws-cdk/aws-sqs=0.9.0,@aws-cdk/cdk=0.9.0,@aws-cdk/cx-api=0.9.0,js-base64=2.4.5,poc-aws-cdk=0.1.0'

CDK References:

SAM References:

@eladb

This comment has been minimized.

Copy link
Contributor

eladb commented Sep 16, 2018

Eventually, you should be able to achieve the same results you currently achieve with the SAM resources by simply using the AWS Construct Library.

The CDK already has support for Lambda via the @aws-cdk/aws-lambda module, and we are working on an API Gateway module (see #665) which will allow you to implement the above example like this:

const handler = new lambda.Function(this, 'HelloWorldHandler', {
  description: 'Greeting the world',
  code: apigw.Lambda.directory('./target'),
  handler: 'hello-world',
  runtime: lambda.Runtime.Go1x,
  tracing: lambda.Tracing.Active
});

const api = new apigw.RestApi(this, 'HelloWorldApi');
api.root.onMethod('ANY', handler);

Furthermore, we are looking at ways to allow people to use SAM CLI with CDK Apps, in order to enable local debugging of SAM apps written using the CDK (whether or not they use the SAM resources).

@0xdevalias

This comment has been minimized.

Copy link

0xdevalias commented Sep 17, 2018

Eventually, you should be able to achieve the same results you currently achieve with the SAM resources by simply using the AWS Construct Library.

Expected that would be the case based on the wording of how it was described. Until then though, it will be nice to be able to leverage the existing abstractions SAM offers.

The CLI tie in will be nice.

@eladb

This comment has been minimized.

Copy link
Contributor

eladb commented Sep 17, 2018

it will be nice to be able to leverage the existing abstractions SAM offers.

Is the @aws-cdk/aws-sam library what you were looking for or did you look for some richer APIs on top of it?

@0xdevalias

This comment has been minimized.

Copy link

0xdevalias commented Sep 18, 2018

As per my example above (probably edited original issue as I worked it all out), it is, but this issue was more about making a canonical example of using it so that others don't have to dig through everything to figure it out.

@jmhummel

This comment has been minimized.

Copy link

jmhummel commented Sep 28, 2018

One issue I saw when I attempted to deploy my SAM resources via CDK:

        new FunctionResource(this, 'HelloWorld', {
            codeUri: './src',
            handler: 'handler.handler,
            description: 'Hello World',
            runtime: 'nodejs8.10',
            events: {
                Endpoint: {
                    properties: {
                        path: '/helloworld,
                        method: 'get',
                    },
                    type: 'Api',
                }
            }
        });

I ran cdk synth hello-world > template.yml in order to use SAM
The SAM CLI expects codeUri to be local path. However, this fails at cdk deploy:

Deployment of stack hello-world failed: Error: Failed to create ChangeSet CDK-5bb75637-dc16-4c02-bc7c-2b7bfb218223 on hello-world: FAILED, Transform AWS::Serverless-2016-10-31 failed with: Invalid Serverless Application Specification document. Number of errors found: 1. Resource with id [HelloWorldFBEC9B61] is invalid. 'CodeUri' is not a valid S3 Uri of the form "s3://bucket/key" with optional versionId query parameter.

If I use an asset to upload the code, and pass the s3 information:

codeUri: {
                bucket: codeAsset.s3BucketName,
                key: codeAsset.s3ObjectKey,
            },

It succeeds, but now I can't use template.yml to run sam local start-api as it can't find the handlers

@jmhummel

This comment has been minimized.

Copy link

jmhummel commented Sep 29, 2018

My current workaround:

        const createSamTemplate = this.getContext("sam");

        const codeAsset = new ZipDirectoryAsset(this, 'CodeAsset', {
            path: './src',
        });

        new FunctionResource(this, id, {
            codeUri: createSamTemplate ? './src' : {
                bucket: codeAsset.s3BucketName,
                key: codeAsset.s3ObjectKey,
            },

I run cdk synth hello-world -c sam=true > template.yml and pass in the context var to use local src and deploy with cdk deploy

@eladb

This comment has been minimized.

Copy link
Contributor

eladb commented Sep 29, 2018

Hey, thanks for this! We are looking at streamlining this experience. Stay tuned :-)

@aripalo

This comment has been minimized.

Copy link

aripalo commented Dec 20, 2018

What @eladb said:

Furthermore, we are looking at ways to allow people to use SAM CLI with CDK Apps, in order to enable local debugging of SAM apps written using the CDK (whether or not they use the SAM resources).

That would be super useful. I don't see much purpose on using SAM when using CDK, but currently the biggest pain point by doing so is not having support for SAM CLI (or not having other similar local development toolkit); So basically there isn't a sane local development setup.

Of course one can always build something custom around it, but reinventing the wheel isn't really what I want 😅 … and also as we are using a compiled language (Golang) to write our functions that also makes writing "local invoke wrappers" harder than with - say- NodeJS.

We're currently developing with AppSync, Golang Lambdas and CDK. I know, I know CDK docs say not to use it for production, but it's just exactly the tooling we've been looking for 🙂 and we do vendor in the synthetized CloudFormation templates to Github (just to be on the safe side).

@mipearson

This comment has been minimized.

Copy link

mipearson commented Jan 13, 2019

Chucking this here as it may be useful to others looking to combine these tools.

The following works just fine:

    const fn = new lambda.Function(this, "Func", {
      ..
    });

    new cdk.Output(this, "FunctionName", { value: fn.functionName });

Then on deploy:

Outputs:
Stack.FunctionName = Stack272B588B-NRQ0Y3ASCFAX

And in your terminal:

sam logs -tn Stack272B588B-NRQ0Y3ASCFAX
@eladb

This comment has been minimized.

Copy link
Contributor

eladb commented Jan 13, 2019

@mipearson thanks for this. Useful for us to learn about this use case. Copying @sam-goodwin

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment