Serverless AWS Lambda Edge: MalformedHandlerName - node.js

I'm following the below example to setup a Lambda Edge function:
https://www.serverless.com/blog/lambda-at-edge-support-added
The code: ./handler.js
// SAME CODE STRUCTURE AS ORIGINAL, JUST ADDING A HEADER TO TEST
'use strict';
exports.handler = (event, context, callback) => {
const response = event.Records[0].cf.response;
const headers = response.headers;
headers['test-lambda-edge'] = [{ key: 'test-lambda-edge', value: 'working' }]
callback(null, response);
};
The Config: ./serverless.yml
# SAME CONFIG AS ORIGINAL, JUST CHANGING eventType and origin
service: mylambda
provider:
name: aws
runtime: nodejs12.x
lambdaHashingVersion: 20201221
functions:
cfLambda:
handler: functions/handler.cloudfront
events:
- cloudFront:
eventType: origin-response
origin: https://example.org
The function deploys properly:
$ sls deploy
Serverless: Packaging service...
Serverless: Excluding development dependencies...
Serverless: Uploading CloudFormation file to S3...
Serverless: Uploading artifacts...
Serverless: Uploading mylambda.zip file to S3 (554 B)...
Serverless: Validating template...
Serverless: Updating Stack...
Serverless: Checking Stack update progress...
................
Serverless: Stack update finished...
Service Information
service: mylambda
stage: dev
region: us-east-1
stack: mylambda-dev
resources: 8
api keys:
None
endpoints:
CloudFront - ---------------.cloudfront.net
functions:
cfLambda: mylambda-dev-cfLambda
layers:
None
I am using the Amazon CloudFront Modify Response Headers test template for testing.
Attempt 1) with the same handlers naming as article
I get the below error, which I can understand as the article seems wrong, the cloudfront function isn't defined:
"errorMessage": "functions/handler.cloudfront is undefined or not
exported"
Attempt 2) Trying to fix serverless.yml
I replaced handler: functions/handler.cloudfront with handler: functions/handler to match the code and I get the below error:
{"errorType":"Runtime.MalformedHandlerName","errorMessage":"Bad
handler","stack":["Runtime.MalformedHandlerName: Bad handler"," at
_splitHandlerString
If I look at the official doc, the handler naming is the same (ie exports.handler = ):
https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/lambda-edge-how-it-works-tutorial.html
'use strict';
exports.handler = (event, context, callback) => {
Q: How should I name my handler in the code/config?

If the catalog structure that you're using looks like this:
├── handler.js
└── serverless.yml
and the name of the exported handler is handler and lives in handler.js file then the correct config will look like this:
service: mylambda
provider:
name: aws
runtime: nodejs12.x
lambdaHashingVersion: 20201221
functions:
cfLambda:
handler: handler.handler
events:
- cloudFront:
eventType: origin-response
origin: https://example.org
First part is the path to the module and after . you reference specific function exported in that module. For handler: functions/handler.cloudfront to work, you'd have to export cloudfront function in ./functions/handler.js file.

Related

Errno 20 Not a directory: '/tmp/tmp6db1q_sn/pyproject.toml/egg-info'

I'm wrapping my colleague's code in an AWS SAM. I made a lambda to just call existing code with a run method which I did like this.
import json
from sentance_analyser_v2.main import run
def lambda_handler(event, context):
if (event['path'] == '/analyse'):
return RunAnalyser(event, context)
else:
return {
"statusCode": 200,
"body": json.dumps({
"message": "Hello"
}),
}
def RunAnalyser(event, context):
source = event['queryStringParameters']['source']
output = run(source)
return {
"statusCode": 200,
"body": json.dumps({
"output": json.dumps(output)
})
}
After running into numerous package problems I realized I forget to use the sam build --use-container command and I was hoping after a build it would solve some of my package errors but I ran into this error code -
Error: PythonPipBuilder:ResolveDependencies - [Errno 20] Not a directory: '/tmp/tmp6db1q_sn/pyproject.toml/egg-info'
After trying to understand what the freak that even is I started pulling my hairs out because there is nothing on this...
Here is the basic template that I currently use just so I can test that my wrapping worked. I'm still very new to AWS & SAM so I don't want to overcomplicate things just yet with the template.
AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::Serverless-2016-10-31
Description: >
sam-app
Sample SAM Template for sam-app
Globals:
Function:
Timeout: 30
Tracing: Active
Api:
TracingEnabled: True
Resources:
MainLambda:
Type: AWS::Serverless::Function
Properties:
CodeUri: main_lambda/
Handler: app.lambda_handler
Runtime: python3.9
Architectures:
- x86_64
Events:
Analyser:
Type: Api
Properties:
Path: /analyse
Method: get
Outputs:
HelloEfsApi:
Description: "API Gateway endpoint URL for Prod stage for Hello EFS function"
Value: !Sub "https://${ServerlessRestApi}.execute-api.${AWS::Region}.amazonaws.com/Prod/hello/"

How can I get service-name and function-name from serverless.yml in my Lambda NodeJS?

service: serverless-demo-app
provider:
name: aws
runtime: nodejs10.x
functions:
sample1:
handler: sample1/handler
events:
- http:
path: sample1
method: get
sample2:
handler: sample2/handler
events:
- http:
path: sample2
method: get
When I am invoking sample2 from sample1, I need it's full name, like: serverless-demo-app-dev-sample2
So, how can I get service name, function name and environment name inside function1?
Try:
${self:service}
..to obtain the service name.
AWS_LAMBDA_FUNCTION_NAME, will show your functions.

Endpoint is not created after serverless deployment

I am trying to deploy a lambda function using serverless framework, the deployment is successful but i am not able to see the api gateway for the lambda function , and no endpoint is created after deployment , i am posting the code below
serverless.yml
# Welcome to Serverless!
#
# This file is the main config file for your service.
# It's very minimal at this point and uses default values.
# You can always add more config options for more control.
# We've included some commented out config examples here.
# Just uncomment any of them to get that config option.
#
# For full config options, check the docs:
# docs.serverless.com
#
# Happy Coding!
service: learning-serverless-post-apigetway
# app and org for use with dashboard.serverless.com
#app: your-app-name
#org: your-org-name
# You can pin your service to only deploy with a specific Serverless version
# Check out our docs for more details
# frameworkVersion: "=X.X.X"
provider:
name: aws
runtime: nodejs12.x
# you can overwrite defaults here
# stage: dev
# region: us-east-1
# you can add statements to the Lambda function's IAM Role here
# iamRoleStatements:
# - Effect: "Allow"
# Action:
# - "s3:ListBucket"
# Resource: { "Fn::Join" : ["", ["arn:aws:s3:::", { "Ref" : "ServerlessDeploymentBucket" } ] ] }
# - Effect: "Allow"
# Action:
# - "s3:PutObject"
# Resource:
# Fn::Join:
# - ""
# - - "arn:aws:s3:::"
# - "Ref" : "ServerlessDeploymentBucket"
# - "/*"
# you can define service wide environment variables here
# environment:
# variable1: value1
# you can add packaging information here
#package:
# include:
# - include-me.js
# - include-me-dir/**
# exclude:
# - exclude-me.js
# - exclude-me-dir/**
functions:
hello:
handler: handler.hello
# The following are a few example events you can configure
# NOTE: Please make sure to change your handler code to work with those events
# Check the event documentation for details
# events:
# - http:
# path: users/create
# method: get
# - websocket: $connect
# - s3: ${env:BUCKET}
# - schedule: rate(10 minutes)
# - sns: greeter-topic
# - stream: arn:aws:dynamodb:region:XXXXXX:table/foo/stream/1970-01-01T00:00:00.000
# - alexaSkill: amzn1.ask.skill.xx-xx-xx-xx
# - alexaSmartHome: amzn1.ask.skill.xx-xx-xx-xx
# - iot:
# sql: "SELECT * FROM 'some_topic'"
# - cloudwatchEvent:
# event:
# source:
# - "aws.ec2"
# detail-type:
# - "EC2 Instance State-change Notification"
# detail:
# state:
# - pending
# - cloudwatchLog: '/aws/lambda/hello'
# - cognitoUserPool:
# pool: MyUserPool
# trigger: PreSignUp
# - alb:
# listenerArn: arn:aws:elasticloadbalancing:us-east-1:XXXXXX:listener/app/my-load-balancer/50dc6c495c0c9188/
# priority: 1
# conditions:
# host: example.com
# path: /hello
# Define function environment variables here
# environment:
# variable2: value2
# you can add CloudFormation resource templates here
#resources:
# Resources:
# NewResource:
# Type: AWS::S3::Bucket
# Properties:
# BucketName: my-new-bucket
# Outputs:
# NewOutput:
# Description: "Description for the output"
# Value: "Some output value"
handler.js
'use strict';
module.exports.hello = async event => {
if(event.httpMethod ==='POST'){
const response ={
statusCode: 200,
body: JSON.stringify({
body: event.body
})
};
}else{
const response = {
statusCode: 200,
body: JSON.stringify({
message:'Something else was called'
})
}
}
};
Output log:
Serverless: Packaging service...
Serverless: Excluding development dependencies...
Serverless: Creating Stack...
Serverless: Checking Stack create progress...
........
Serverless: Stack create finished...
Serverless: Uploading CloudFormation file to S3...
Serverless: Uploading artifacts...
Serverless: Uploading service learning-serverless-post-apigetway.zip file to S3 (607 B)...
Serverless: Validating template...
Serverless: Updating Stack...
Serverless: Checking Stack update progress...
...............
Serverless: Stack update finished...
Service Information
service: learning-serverless-post-apigetway
stage: dev
region: us-east-1
stack: learning-serverless-post-apigetway-dev
resources: 6
api keys:
None
endpoints: // There is no endpoint URL
None
functions:
hello: learning-serverless-post-apigetway-dev-hello
layers:
None
Serverless: Run the "serverless" command to setup monitoring, troubleshooting and testing.
I can not see the API in the API gateway also, please help i am new to the serverless
With your functions definition in the serverless.yml you need to tell it explicitly that there needs to be an http event trigger added to it. Serverless lets you set a large number of possible event triggers within the AWS eco system so you need to explicitly define which you want for a particular Lambda function. And the change is as simple as a few more lines than you already have:
functions:
hello:
handler: handler.hello
events:
- http:
method: get
path: /myendpointpath
If you want to see all possible event triggers this page should help:
https://serverless.com/framework/docs/providers/aws/guide/events/#aws---events

Environment Variables with Serverless and AWS Lambda

I am learning serverless framework and I'm making a simple login system.
Here is my serverless.yml file
service: lms-auth
provider:
name: aws
runtime: nodejs8.10
stage: dev
region: ap-south-1
environment:
MONGODB_URI: $(file(../env.yml):MONOGDB_URI)
JWT_SECRET: $(file(../env.yml):JWT_SECRET)
functions:
register:
handler: handler.register
events:
- http:
path: auth/register/
method: post
cors: true
login:
handler: handler.login
events:
- http:
path: auth/login/
method: post
cors: true
plugins:
- serverless-offline
As you can see, I have two environment variables and both of them are referencing to a different file in the same root folder.
Here is that env.yml file
MONOGDB_URI: <MY_MONGO_DB_URI>
JWT_SECRET: LmS_JWt_secREt_auth_PasSWoRds
When I do sls deploy, I see that both the variables are logging as null. The environment variables aren't sent to lambda.
How can I fix this?
Also, currently I'm using this method and adding the env.yml to .gitignore and saving the values. Is there any other efficient way of hiding sensitive data?
I would do something like this to help you out with the syntax
service: lms-auth
custom: ${file(env.yml)}
provider:
name: aws
runtime: nodejs8.10
stage: dev
region: ap-south-1
environment:
MONGODB_URI: ${self:custom.mongodb_uri}
JWT_SECRET: ${self:custom.jwt_secret}
functions:
register:
handler: handler.register
events:
- http:
path: auth/register/
method: post
cors: true
login:
handler: handler.login
events:
- http:
path: auth/login/
method: post
cors: true
plugins:
- serverless-offline
Then in your env.yml you can do
mongodb_uri: MY_MONGO_DB_URI
jwt_secret: LmS_JWt_secREt_auth_PasSWoRds
Enviroment variables
1. Add useDotenv:true to your .yml file 2.Add your variables like this -> ${env:VARIABLE_NAME}3.Create a file called .env.dev and write the variables (You can add .env.prod but you have to change the stage inside your .yml file ) Example :
service: lms-auth
useDotenv: true
provider:
name: aws
runtime: nodejs12.x
stage: dev
region: us-east-1
environment:
MONGODB_URI: ${env:MONOGDB_URI}
JWT_SECRET: ${env:JWT_SECRET}
functions:
register:
handler: handler.register
events:
- http:
path: auth/register/
method: post
cors: true
login:
handler: handler.login
events:
- http:
path: auth/login/
method: post
cors: true
plugins:
- serverless-offline
.env.dev
MONOGDB_URI = The URI Value
JWT_SECRET = The JWT Scret Value
I ended up solving it. I had set up my Dynamo DB in AWS us-west region. reinitialized in US-East-2, and reset the region under 'provider' within the .yml file.

LambdaFunction - Value of property Variables must be an object with String (or simple type) properties

I am using serverless to deploy my Lambda based application. It was deploying just fine, and then it stopped for some reason. I paired down the entire package to the serverless.yml below and one function in the handler - but I keep getting this error:
Serverless Error ---------------------------------------
An error occurred: TestLambdaFunction - Value of property Variables must be an object with String (or simple type) properties.
Stack Trace --------------------------------------------
Here is the serverless.yml
# serverless.yml
service: some-api
provider:
name: aws
runtime: nodejs6.10
stage: prod
region: us-east-1
iamRoleStatements:
$ref: ./user-policy.json
environment:
config:
region: us-east-1
plugins:
- serverless-local-dev-server
- serverless-dynamodb-local
- serverless-step-functions
package:
exclude:
- .gitignore
- package.json
- README.md
- .git
- ./**.test.js
functions:
test:
handler: handler.test
events:
- http: GET test
resources:
Outputs:
NewOutput:
Description: Description for the output
Value: Some output value
Test Lambda Function in Package
#handler.test
module.exports.test = (event, context, callback) => {
callback(null, {
statusCode: 200,
body: JSON.stringify({
message: 'sadfasd',
input: event
})
})
}
Turns out, this issue does not have any relationship to the Lambda function. Here is the issue that caused the error.
This does NOT work:
environment:
config:
region: us-east-1
This DOES work:
environment:
region: us-east-1
Simply put, I don't think you can have more than one level in your yaml environment variables.
Even if you try sls print as a sanity check, this issue will not pop up. Only in sls deploy.
You have been warned, and hopefully saved!
Other thing that might cause this kind of error is using invalid yaml syntax.
It's easy to get confused about this.
Valid syntax for environment variables
environment:
key: value
Invalid syntax for environment variables
environment:
- key: value
Notice little dash in the code below?
In yaml syntax - means array and therefore, code below is interpreted as array, not object.
So that's why error tells "Value of property Variables must be an object with String (or simple type) properties."
This can be easily fixed by removing - in front of all keys.

Resources