How to add an event type as Cloudfront for SAM template for a Lambda function
I have a SAM template where there will be a lambda function and Api gateway as a trigger , Now instead of Api gateway as a Trigger , I need to add an existing CLoudfront Distribution. But I am not finding any such option to do that.
cloudfrontlambda:
Type: AWS::Serverless::Function
Properties:
FunctionName: cloudfrontlambda
Handler: index.handler
Runtime: nodejs8.10
CodeUri: ./Lambda/cloudfrontlambda/
Description: Function is used for validating the id token
MemorySize: 128
Timeout: 30
Role: 'arn:aws:iam::1234567:role/DR_lambda_web_execution'
Events:
--------- ## how to add an Existing cloudfront distribution here
At present there is no event source type for CloudFront distributions within the SAM model [1]. Assuming you are attempting to create an edge lambda function, you will need to attach the function either manually or via the cloudformation template that you used to create the distribution - as it needs to be declared directly against the cloud front distribution. I’ve edited it down for brevity, but for example -
cloudfrontlambda:
Type: AWS::Serverless::Function
Properties:
FunctionName: cloudfrontlambda
Handler: index.handler
Runtime: nodejs8.10
CodeUri: ./Lambda/cloudfrontlambda/
Description: Function is used for validating the id token
MemorySize: 128
Timeout: 30
Role: 'arn:aws:iam::1234567:role/DR_lambda_web_exec’
cloudfrontdistribution:
Type: AWS::CloudFront::Distribution
Properties:
DistributionConfig:
CacheBehaviors:
- LambdaFunctionAssociations:
- EventType: string-value
LambdaFunctionARN: !Sub ‘${cloudfrontlambda.Arn}:${cloudfrontlambda.Version}’
E.g.
Note that your lambda function must be deployed in us-east-1 to work in this way. I can confirm that you can deploy a cloud front distribution via a cloudformation template in another region and still reference lambda functions that are deployed to us-east-1.
Also, you must specify the version of the lambda function within the ARN. The AWS::Lambda::Function cloudformation type does not provide this on its own (requiring an additional AWS::Lambda::Version resource), so this may complicate your CloudFront distribution template if it is not already contained with a SAM template.
[1] https://github.com/awslabs/serverless-application-model/blob/master/versions/2016-10-31.md#event-source-object
Short answer, SNS. Long answer, you can't except for SNS.
You can't add an existing CloudFront resource, because that breaks the mold of CF. This took me a while to wrap my head around too, but essentially a CloudFront template can only create/modify resources within itself. It cannot modify resources outside of its stack. Here are a few links supporting this:
https://github.com/awslabs/serverless-application-model/issues/241
https://github.com/awslabs/serverless-application-model/blob/master/versions/2016-10-31.md#s3 (specifically says existing S3 buckets cannot be an event source)
This last link shows that recently they supported importing resources from other stacks, but the resource must first be deleted from its previous stack before it can be used. I'm not sure about your architecture, but I know for mine that would break things very quickly. https://github.com/awslabs/serverless-application-model/issues/249
The work around is to add Custom Resources (lambdas) to alleviate this impediment. In the last link I sent there is an example of an SNS workaround since this limitation does not apply to SNS.
Related
I am using SAM to develop a lambda that is triggered by SNS.
When I am using SAM, it seems I get API GATEWAY associated to the Lambda when I deploy.
It is nice in dev, but not in prod.
How would I develop a Lambda without deploying it attached to an API GATEWAY?
"I was not aware of Lambda runtime API"
Using the Lambda runtime API and the AWS SDKs, as a developer, you can build more flexible Lambda functions with the exact functionality that you want.
For example, you can build Lambda functions that can invoke multiple AWS Services to perform a given use case. For example, from a Lambda function, I want to detect PPE information in images within an Amazon S3 bucket, store the results in an Amazon DynamoDB table, and use the SES service to email the results.
Here are a few end to end tutorials.
For example - here are two JavaScript examples:
Creating and using Lambda functions
Creating scheduled events to execute AWS Lambda functions
Here are some Java runtime examples:
Creating an AWS Lambda function that detects images with Personal Protective Equipment
Creating an Amazon Web Services Lambda function that tags digital assets located in Amazon S3 buckets
Creating an ETL workflow by using AWS Step Functions and the AWS SDK for Java
UPDATE
Once you test your code in an IDE, deploy it and test it from the Lambda console. Once it is successfully invoked, you will see a message like this:
Another option I found, this time within SAM is define the function with a different Event source.
The Lambda will be exposed if it's event source is defined as Api
You can define it as many other things (S3,Sns,Sqs etc)
Here is an example of a function triggered by and http event via api gateway, and the other one, by Sns. The config for SNS is not complete, Check this link for full details https://github.com/awslabs/serverless-application-model/blob/master/versions/2016-10-31.md
in template.yaml Notice the Events section of each Lambda definition.
Resources:
HelloWorldFunction:
Type: AWS::Serverless::Function # More info about Function Resource: https://github.com/awslabs/serverless-application-model/blob/master/versions/2016-10-31.md#awsserverlessfunction
Properties:
CodeUri: hello-world/
Handler: app.lambdaHandler
Runtime: nodejs14.x
Events:
HelloWorld:
Type: Api # More info about API Event Source: https://github.com/awslabs/serverless-application-model/blob/master/versions/2016-10-31.md#api
Properties:
Path: /hello
Method: get
BooBooFunction:
Type: AWS::Serverless::Function # More info about Function Resource: https://github.com/awslabs/serverless-application-model/blob/master/versions/2016-10-31.md#awsserverlessfunction
Properties:
CodeUri: booboo/
Handler: app.lambdaHandler
Runtime: nodejs14.x
Events:
BooBoo:
Type: Sns # More info about API Event Source: https://github.com/awslabs/serverless-application-model/blob/master/versions/2016-10-31.md#api
I've created AWS Lambda in C# using Visual Studio that returns some JSON from the API endpoint. Now I want to run that lambda locally. All the examples use AWS SAM, but they create a new function using the SAM template.
When I run the command sam local start-lambda I get an error saying that the template isn't found. So what is certain is that I need template.yaml, but I'm not sure is there a way to generate this template for existing Lambda?
Any help is appreciated!
Check out the Template Anatomy resource on the AWS documentation.
You might find this example helpful (it's greatly simplified). I use NodeJS for development, but the differences between programming languages when you're creating a SAM Template are trivial. The example is an outline for a simple Lambda function someFunction being invoked by an API Gateway (HTTP) event.
AWSTemplateFormatVersion: '2010-09-09'
Transform: 'AWS::Serverless-2016-10-31'
Description: My Serverless Application
Parameters:
# Manually define this in AWS IAM for just the services needed.
lambdaExecutionRole:
Description: 'Required. The role used for lambda execution.'
Type: 'String'
Default: 'arn:aws:iam::nnnnnnnnnnnn:role/LambdaExecutionRole'
Globals:
Function:
Runtime: nodejs10.x
# Environment:
# Variables:
# NODE_ENV: test
# DEBUG: myapp:foo
Resources:
performSomeFunction:
Type: 'AWS::Serverless::Function'
Properties:
FunctionName: performSomeFunction
Handler: lambda.someFunction
CodeUri: ./
Description: description of the function being performed
MemorySize: 256
Timeout: 60
Role:
Ref: lambdaExecutionRole
Events:
# API Gateway proxy endpoint.
ProxyApiRoot:
Type: Api
Properties:
Path: '/'
Method: ANY
ProxyApiGreedy:
Type: Api
Properties:
Path: '/{proxy+}'
Method: ANY
As you're getting started with AWS Lambda, one of the big concepts to keep in mind is how your function will be triggered. Functions are triggered by different kinds of events, and there can be many many different types of events. I tend to use API Gateway, Simple Queue Service and CloudWatch Events to trigger mine, but it entirely depends on your use case.
It turned out that you can export Lambda function, and get the generated .yaml template, which was exactly what I needed.
I'm trying to deploy AWS Lambda function by using SAM.
What I want to do is to update exsiting lambda function by deploying local source code.
In order to do that, I specified the existing lambda function name as 'FunctionName' in template.yaml like below.
However, 'FunctionName' does only support for creating new function, not updating to existing function.
https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-lambda-function.html#cfn-lambda-function-functionname
Are there any ways to specify Function Name in SAM in order to update lambda function?
[template.yaml]
AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::Serverless-2016-10-31
Resources:
HelloWorld:
Type: 'AWS::Serverless::Function'
Properties:
FunctionName: 'hello_world'
Description: ''
Handler: index.handler
MemorySize: 256
Role: 'arn:aws:iam::368834739507:role/lambda_basic_execution'
Runtime: nodejs6.10
Timeout: 120
Using SAM (and/or CloudFormation), you cannot update existing resources.
SAM (and CloudFormation) create and manage their own resources. All resources specified in the template are going to be created when the stack is created. They cannot be "taken over".
Instead, you should allow SAM (or CloudFormation) to create the Lambda function for you, then update users to reference the new function. After that, you can update your code using SAM.
We use Cloud Formation for define a bunch of Lambda functions:
AWSTemplateFormatVersion: '2010-09-09'
Transform:
- 'AWS::Serverless-2016-10-31'
Resources:
MyLambda:
Type: 'AWS::Serverless::Function'
Properties:
Handler: com.handler::MyLambda
Runtime: java8
CodeUri: .
Description: Some desc
MemorySize: 512
Timeout: 15
Role: !Ref LambdaRole
FunctionName: MyLambda
Events:
MyLambdaEvt:
Type: Api
Properties:
RestApiId: !Ref MyApiDef
Path: /lambda/my
Method: get
MyApiDef:
Type: AWS::Serverless::Api
Properties:
DefinitionUri: s3://a-bucket/api-gateway.yml
StageName: prod
Outputs:
ApiUrl:
Description: URL of your API endpoint
Value: !Join
- ''
- - https://
- !Ref MyApiDef
- '.execute-api.'
- !Ref 'AWS::Region'
- '.amazonaws.com/prod'
A CodePipeline generate a changeset and execute it.
In this way all the Lambda function are correctly updated but the API Gateway endpoint are not update correctly and we need to import and deploy the YML in s3://a-bucket/api-gateway.yml manually.
Why the API doesn't update (an educated guess)
In order for a change to be added to a a change set, CloudFormation has to detect a change. If the only thing that changes (for MyApiDef) between deployments is the contents of the .yaml file out on S3, CloudFormation isn't going to detect a change that it needs to add to the change set.
If this API definition lived in the CF template, rather than a file on S3, CF would (obviously) detect every change and update the API for you.
Since the definition lives in S3, and the file name hasn't changed, no change is detected, so nothing gets updated.
Possible work arounds
You have to convince CloudFormation that something has changed with your API definition. These two things worked for me:
Updating the MyApiDef key itself each run works. (MyApiDefv2,
MyApiDefv3, etc)
Updating the DefinitionUri works. (i.e. version the
filename in S3).
Neither of these is great, but appending a version to the filename in S3 seems more reasonable than the other option.
There are probably other ways to convince CloudFormation a change has taken place. Notably, I could not get Variables to work for this purpose.
I am trying to create a lambda function from a CloudFormation template based on this example:
http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/quickref-lambda.html
As can be seen from this link:
http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-lambda-function.html
there is no way to add a trigger for the lambda function (like a S3 upload trigger).
Is there a workaround to specify the trigger while writing the template?
You can use cloudwatch rule to trigger your lambda function :
AWSTemplateFormatVersion: '2010-09-09'
Resources:
MyCloudWatchRule:
Type: "AWS::Events::Rule"
Properties:
Description: "Rule to trigger lambda"
Name: "MyCloudWatchRule"
EventPattern: <Provide Valid JSON Event pattern>
State: "ENABLED"
Targets:
- Arn: "arn:aws:lambda:us-west-2:12345678:function:MyLambdaFunction"
Id: "1234567-acvd-awse-kllpk-123456789"
Ref :
https://docs.aws.amazon.com/AmazonCloudWatch/latest/events/CloudWatchEventsandEventPatterns.html
https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-events-rule.html#aws-resource-events-rule-syntax
https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-events-rule-target.html
It's been a while so I imagine you've solved the problem, but I'll put in my 2 cents to help others.
It's best to use SAM (Serverless Application Model) for this kind of things. So use AWS::Serverless::Function instead of AWS::Lambda::Function
https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/sam-resource-function.html
In there, you can specify an EventSource which accepts the following possible values:
S3
SNS
Kinesis
DynamoDB
SQS
Api
Schedule
CloudWatchEvent
CloudWatchLogs
IoTRule
AlexaSkill
Cognito
HttpApi
SAM does the rest of the work. Follow this guide for the rest of the details:
https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/serverless-deploying.html
Nowadays, this issue is fixed by Amazon:
https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-events-rule.html#aws-resource-events-rule--examples
Just create Lambda permissions like in the example.
Lambda function can be triggered by several AWS resources such as S3, SNS, SQS, API, etc. Checkout for the full list at AWS docs
I suggest you use Altostra Designer, which let you create and configure Lambda Function super quick and also choose what will trigger it.
You need to add a NotificationConfiguration to the S3 bucket definition. However, this will lead to a circular dependency where the S3 bucket refers to the Lambda function and the Lambda function refers to the S3 bucket.
To avoid this circular dependency, create all resources (including the S3 bucket and the Lambda function) without specifying the notification configuration. Then, after you have created your stack, update the template with a notification configuration and then update the stack.
Here is a SAM based YAML example for CloudWatch log group trigger
lambdaFunction:
Type: AWS::Serverless::Function
Properties:
CodeUri:
Bucket: someBucket
Key: someKey
Description: someDescription
Handler: function.lambda_handler
MemorySize:
Ref: MemorySize
Runtime: python3.7
Role: !GetAtt 'iamRole.Arn'
Timeout:
Ref: Timeout
Events:
NRSubscription0:
Type: CloudWatchLogs
Properties:
LogGroupName: 'someLogGroupName'
FilterPattern: "" #Match everything
For S3 example event see https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/sam-property-function-s3.html