SAM Template - Always enable event trigger for lambda - amazon-web-services

I have a lambda function created using SAM template which has an event trigger scheduled every 5 mins.
When the lambda get created for first time the event is enabled. But, when someone disables the trigger manually, the rerunning the stack does not enable it again.
Native cloud formation has an attribute called State in AWS::Events::Rule. But this is not supported in SAM Function's Events property. It is to be noted that this Events property gets translated to AWS::Events::Rule by SAM engine.
I tried adding the same State attribute in SAM but that doen't work.
Now the question is really how do I make sure Event is always enabled when SAM is used.
This there a hack available.
Sample code:
MyUpdater:
Type: 'AWS::Serverless::Function'
Properties:
Handler: myupdater.lambda_handler
Runtime: python3.6
FunctionName: "myupdater"
CodeUri: ./code
Description: Sample updater lambda
MemorySize: 128
Timeout: 60
Role: !ImportValue myIamRole
KmsKeyArn: !ImportValue myKeyArn
Events:
Timer:
Type: Schedule
Properties:
Schedule: rate(5 minutes)
Thanks in advance

This is not possible today. We are considering this feature (CFN properties pass-through) for the future.

Related

Running existing AWS Lambdas locally

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.

Dynamically change event properties on aws cloudformation templates

We are building a serverless app using aws and we want to enable lambda warmers only on the production environment.
Our cloudformation parameters:
Parameters:
Environment:
Description: Environment name
Type: String
EnableWarmer:
Description: Flag to enable/disable warmup Events
Default: DISABLED
Type: String
Our lambdas yaml file looks like this:
MyLambda:
Type: AWS::Serverless::Function
Properties:
FunctionName: !Sub '${Environment}-my-lambda'
CodeUri: src
Handler: lambda.handler
Runtime: nodejs12.x
MemorySize: 128
Timeout: 100
Description: Creates a new something
Layers:
- !Ref InternalDependencyLayer
- !Ref ExternalDependencyLayer
Role: !Ref LambdaRoleArn
Events:
Api:
Type: Api
Properties:
Path: /url
Method: POST
RestApiId: !Ref ApiGateway
WarmingSchedule:
Type: Schedule
Properties:
Enabled: !Ref EnableWarmer
Schedule: rate(5 minutes)
Input: '{ "warmer":true, "concurrency": 2 }'
And then we deploy the dev environment with these params:
- Key: Environment
Value: dev
- Key: EnableWarmer
Value: DISABLED
Similarly for the production environment we deploy with these params:
- Key: Environment
Value: production
- Key: EnableWarmer
Value: ENABLED
According to aws documentation parameters can't be of type boolean which is the required type of the enabled attribute of the schedule event.
Fortunately amazon states:
Enabled Indicates whether the rule is enabled.
To disable the rule, set this property to False.
Type: Boolean
Required: No
AWS CloudFormation compatibility: This property is similar to the
State property of an AWS::Events::Rule resource. If this property is
set to True then AWS SAM passes ENABLED, otherwise it passes DISABLED
https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/sam-property-function-schedule.html
However when we deploy to the dev environment the warmers are enabled.
The problem with the Enabled property here seems to be that it does not support using CloudFormation's If function and a Condition to do something like that:
WarmingSchedule:
Enabled: !If [WarmerCondition, true, false]
(At least I couldn't figure it out, but maybe I just did something wrong) This is similar to what #raul-barreto suggests with !Equals. However, in my tests it always sets the rule's status to ENABLED.
It seems like there are two options left what you can do:
a) (Not recommended) Copy the CloudFormation code of your Lambda function and have a second one available in your CloudFormation resources. Now set a condition to both of them so you only create one of them, depending on your environment. Note: I don't say this is a good approach but it'd be possible. Problems are you have to maintain the definition of both Lambda functions and if you repeat this approach, you'll faster reach CloudFormations template size limits.
b) If you want to make sure you have a minimum number of instances available to your function (at least that's what I interpret from your question), consider using AWS Lambda's Provisioned Concurrency feature instead. You can define it like this in your AWS Lambda function using SAM:
MyLambda:
Type: AWS::Serverless::Function
Properties:
AutoPublishAlias: 'LATEST' #Setting AutoPublishAlias is important, otherwise you can not use provisioned concurrency
ProvisionedConcurrencyConfig:
ProvisionedConcurrentExecutions: 2
This snippet will provision concurrency for the function's alias 'LATEST' which points to the latest version of your function. Read more about AutoPublishAlias in SAM (Note: the link's content is written in the context of traffic shifting but it explains what the property does). It makes sure that you always have 2 instances of your Lambda functions available.
The accepted solution works, but as stated in comments, it is a bit difficult to control the enabling and disabling of the event. The following seems to work in a more robust way.
Events:
Scheduler:
Type: Schedule
Properties:
Schedule: !If [EnableWarmer, "rate(5 minutes)",
"cron(00 00 01 01 ? 1970)"]
According to the documentation, Enabled must a Boolean variable.
You can still have a String parameter and convert it to Boolean inside the CloudFormation.
WarmingSchedule:
Type: Schedule
Properties:
Enabled: !Equals [!Ref EnableWarmer, ENABLED]
Schedule: rate(5 minutes)
Input: '{ "warmer":true, "concurrency": 2 }'
This way you still can send ENABLED or DISABLED as a parameter but the input of WarmingSchedule.Enabled will be a Boolean.

AWS::Serverless::Function lambda version for Lambda#Edge event handler

I am trying to use the AWS SAM framework to create a lambda to be used as a CloudFront event handler. It seems like the AWS::Serverless::Function doesn't support the Version attribute. The error I am seeing:
com.amazonaws.services.cloudfront.model.InvalidLambdaFunctionAssociationException: The function ARN must reference a specific function version. (The ARN must end with the version number.)
I found this answer that led me to try it. The relevant parts of my CloudFormation YAML file:
Resources:
CloudFrontFunction:
Type: AWS::Serverless::Function
Properties:
CodeUri: cloudfront-handler/hello_world/
Handler: app.lambda_handler
Runtime: python3.7
Outputs:
CloudFrontFunctionArn:
Description: CloudFront Function ARN with Version
Value: !Join [':', [!GetAtt CloudFrontFunction.Arn, !GetAtt CloudFrontFunction.Version]]
When I sam deploy I get the following error.
Waiting for changeset to be created..
Error: Failed to create changeset for the stack: my-sam-app, ex: Waiter ChangeSetCreateComplete failed: Waiter encountered a terminal failure state Status: FAILED. Reason: Template error: resource CloudFrontFunction does not support attribute type Version in Fn::GetAtt
The properties available on AWS::Lambda::Function are documented here and it lists Version as one of the properties. So it seems AWS::Serverless::Function doesn't support getting the version. How can I get around this so I can deploy a CloudFront event handler implemented using the AWS SAM framework?
UPDATE
As per #mokugo-devops (thanks!), the fix for this was to add AutoPublishAlias: live like this:
Resources:
CloudFrontFunction:
Type: AWS::Serverless::Function
Properties:
CodeUri: cloudfront-handler/hello_world/
Handler: app.lambda_handler
Runtime: python3.7
AutoPublishAlias: live
Outputs:
CloudFrontFunctionVersion:
Description: CloudFront Function ARN with Version
Value: !Ref CloudFrontFunction.Version
By default the function will not automatically have a Version deployed. Instead you will need to specify the AutoPublishAlias attribute.
More information available here.
By doing this you will be unable to retrieve the version.
Instead you will need to create a resource of AWS::Lambda::Version and pass in the Arn from the CloudFrontFunction resource. Then you can get the Lambda version arn from this new resource and pass that to your CloudFrontFunctionArn output.

AWS SAM - Template does not have any APIs connected to Lambda functions

So I'm trying to convert an existing spring boot application to an AWS lambda and using SAM.
I'm trying to use aws-sam-cli to try my lambda locally, however with my SAM setup I am getting: Template does not have any APIs connected to Lambda functions
When I do: sam local start-api
My template.yml:
AWSTemplateFormatVersion : '2010-09-09'
Transform: AWS::Serverless-2016-10-31
Description: foo
Resources:
MailFunction:
Type: AWS::Serverless::Function
Properties:
Handler: bar.LambdaHandler::handleRequest
Runtime: java8
CodeUri: target/foo-bar-1.0.jar
Timeout: 300
MemorySize: 1024
Events:
Timer:
Type: Schedule
Properties:
Schedule: rate(1 day)
Any idea what I'm doing wrong? It looks correct as far as I can tell from https://blog.couchbase.com/aws-serverless-lambda-scheduled-events-tweets-couchbase/ + https://docs.aws.amazon.com/lambda/latest/dg/tutorial-scheduled-events-schedule-expressions.html
You didn't add any API Gateway event to your function. And start-api spawn a local API Gateway.
You need to add at least one Api event to your Events section.
Events:
[...]
Api:
Type: Api
Properties:
Path: /myresource
Method: get
If you just have a Schedule event, try to use generate-event to create such an event.
sam local generate-event schedule ...
and invoke function e.g. sam local invoke function-name -e event_file.json (see)
For Googlers:
Check whether you have an Event with Type: Api
ALSO check whether you have run sam build (very important)
Use the --debug flag so you will know what is going on
As of 2020/7/13, Type: HttpApi does not work with sam local start-api. See issue.
This error message also displays if you are trying to test a websocket API locally. Unfortunately, local testing of websockets is not currently supported - see https://github.com/awslabs/aws-sam-cli/issues/896.
I ran into this error too even when I did have an Api event defined in my SAM template. The problem was that I had a previous template in my .aws-sam/build/ directory which didn't have the Api event defined (from a previous run of sam build). Cleaning out the build directory fixed it.
I am getting this error, but I have function that is working with the HttpApi, it appears that current version of sam does not support HttpApi.
CLI Version
SAM CLI, version 0.52.0
Example Function
FeedsFunction:
Type: AWS::Serverless::Function
Properties:
CodeUri:
Description: "Function that handles feeds"
Events:
Handler:
Type: HttpApi
Properties:
ApiId: !Ref FeedsApi
Path: /
Method: get
Handler: api
MemorySize: 1024
Runtime: go1.x
Timeout: 5
Tracing: Active
There is currently an open issue on GitHub for adding support: https://github.com/awslabs/aws-sam-cli/issues/1641
I got this error when I had a whitespace error in my AWS::Serverless::Function definition, specifically Environment needed to be a child of Properties but was on the same level. Correcting the whitespace made this error disappear. Nodejs 10.15.

How To Rollback AWS CodeStar Lambda Functions Deployed Via CloudFormation?

I'm creating a Nodejs microservice for AWS Lambda. I scaffolded by project using AWS Codestar, and that set me up with a CI/CD pipeline that automatically deploys the lambda function. Nice.
The issue is that every time it deploys the lambda function it must delete and recreate the function, thus deleting any versions or aliases I made.
This means I really can't roll back to other releases. I basically have use git to actually revert the project, push to git, wait for the super-slow AWS Code Pipeline to flow through successfully, and then have it remake the function. To me that sounds like a pretty bad DR strategy, and I would think the right way to rollback should be simple and fast.
Unfortunately, it looks like the CloudFormation section of AWS doesn't offer any help here. When you drill into your stack on the first CloudFormation page it only shows you information about the latest formation that occurred. Dear engineers of AWS CloudFormation: if there was a page for each stack that showed a history of CloudFormation for this stack and an option to rollback to it, that would be really awesome. For now, though, there's not. There's just information about the latest formation that's been clouded. One initially promising option was "Rollback Triggers", but this is actually just something totally different that lets you send a SNS notification if your build doesn't pass.
When I try to change the CodePipeline stage for deploy from CREATE_CHANGE_SET to CREATE_UPDATE I then get this error when it tries to execute:
Action execution failed UpdateStack cannot be used with templates
containing Transforms. (Service: AmazonCloudFormation; Status Code:
400; Error Code: ValidationError; Request ID:
bea5f687-470b-11e8-a616-c791ebf3e8e1)
My template.yml looks like this by the way:
AWSTemplateFormatVersion: 2010-09-09
Transform:
- AWS::Serverless-2016-10-31
- AWS::CodeStar
Parameters:
ProjectId:
Type: String
Description: AWS CodeStar projectID used to associate new resources to team members
Resources:
HelloWorld:
Type: AWS::Serverless::Function
Properties:
Handler: index.handler
Runtime: nodejs8.10
Environment:
Variables:
NODE_ENV: staging
Role:
Fn::ImportValue:
!Join ['-', [!Ref 'ProjectId', !Ref 'AWS::Region', 'LambdaTrustRole']]
Events:
GetEvent:
Type: Api
Properties:
Path: /
Method: get
PostEvent:
Type: Api
Properties:
Path: /
Method: post
The only options in the CodePipeline "Deploy" action are these:
It would be really great if someone could help me to see how in AWS you can make Lambda functions with CodePipeline in a way that they are easy and fast to rollback. Thanks!