How to get CloudWatch Event name in Lambda function? - amazon-web-services

I have a CloudWatch scheduled event invoking a Lambda function.
The event is currently passing a JSON with some parameters. One of which contains the event name, handwritten, which isn't very elegant and can lead to typos.
I cannot choose to pass the Matched event, as I am also passing some other parameters as JSON.
So I would somehow need to pass the event as a parameter in that JSON object, but I couldn't find any docs about that.
How can I get the invoking event name inside the Lambda function?

You can use input transformer which can be used to add your own stuff plus something from the meta data available. In your case
Input path will be
{"ruleName":"$.resources[0]"}
While the Input template will be
{"yourKey": "yourValue", "ruleName": <ruleName>}
The screenshot is here
And this is how it will be available in your lambda function
{
yourKey: 'yourValue',
ruleName: 'arn:aws:events:someregion:someaccountId:rule/testevent'
}
Hope this helps.

Related

Why is the JSON output of my task being escaped by AWS Step Functions?

I have a Lambda function that runs in a step function.
The Lambda function returns a JSON string as output.
When I debug the function locally, I see that the JSON is valid but when I run the step function and get to the next step after my function, I can see that all my " have turned to \" and there is a " at the beginning and end of my JSON.
So a JSON object that looks like the following when I debug my function:
{"test":60,"test2":"30000","test3":"result1"}
Ends up looking like the following as the input of the step after my lambda:
"{\"test\":60,\"test2\":\"30000\",\"test3\":\"result1\"}"
Why does my valid JSON object end up being escaped?
How can I prevent this from happening?
The Lambda function returns a JSON string as output.
That is exactly why your JSON is being escaped - you're returning your object as a JSON string e.g. using JSON.stringify not as a JSON object.
The easiest way to fix this would be to just return the object & not convert the output to a JSON string. That way, it won't be escaped & will be returned, as you expect, as an object.
However, if it must stay as a JSON string for whatever reason, you can use the States.StringToJson(...) intrinsic function to unescape the escaped JSON string using the ResultSelector property of your task.
So for example, if your output is:
{
"Payload": "{\"test\":60,\"test2\":\"30000\",\"test3\":\"result1\"}",
...
}
To be able to unescape the output before passing it to the next task, set the ResultSelector of your task to:
"ResultSelector": {
"Payload.$":"States.StringToJson($.Payload)"
}
Or if using the Workflow Studio, click on the task, check the Output > Transform result with ResultSelector - optional checkbox and fill in the text box with the above ResultSelector object:
Either way, the final result of your task definition should look like this:
{
...
"States": {
"Lambda Invoke": {
"Type": "Task",
...
"ResultSelector": {
"Payload.$":"States.StringToJson($.Payload)"
}
}
}
}
The output will then be as you expect:
{
"Payload": {
"test": 60,
"test2": "30000",
"test3": "result1"
}
}
While the answer from #Ermiya Eskandary is entirely correct, you also have a few more options that you can use to your advantage with or without using ResultSelector (if its a stringified json, then you pretty much have to use ResultSelector however as that answer mentioned) property. ResultPath and OutputPath.
If you do not need the incoming event for anything else after this Lambda, then have your lambda return an Json like object (ie: if in python, return a dict)
In your State Machine Definition, then include two properties in your Lambda Task
OutputPath:"$.SomeKey",
ResultPath:"$.SomeKey"
the SomeKey has to be the same for both.
What these two lines together in the task properties is say (ResultPath) "Put the output of this lambda in the event under the key 'SomeKey'" and then (OutputPath) "only send this key on to the next Task"
If you still need the data from the Input, you can use ResultPath: alone, which will put the output of the Lambda under the key assigned and append it to the InputEvent as well.
See This documentation for more info
Newbie to step functions here. I noticed there are two different ways to call a lambda from step functions:
The AWS-SDK way using Resource: arn:aws:states:::aws-sdk:lambda:invoke
The "optimised" way using Resource: arn:aws:states:::lambda:invoke
I found that the optimized way does a much better job with the JSON coming back from the python Lambda whereas the AWS SDK way was an escaped mess.

The create_profile_job() method is not accepting the new parameters

I am trying to use a Lambda function (written in python) to create a series of profile jobs in DataBrew. AWS recently added a new parameter to this function ("Configuration) which I have added in my code. However, when I call the function, I get the following error message: "Unknown parameter in input: "Configuration", must be one of: DatasetName, EncryptionKeyArn, EncryptionMode, Name, LogSubscription, MaxCapacity, MaxRetries, OutputLocation, RoleArn, Tags, Timeout, JobSample." This does not match the parameter list in the boto3 documentation, which was recently updated to align with the new features added to DataBrew on 07/23/21. Has anyone else had this issue? If so, is there a timeline for this bug to be fixed?
It turns out that the version of boto3 that is available in Lambda by default is not the most updated version. Hence, in order to use all the parameters for this method, you have to add the latest version of boto3 (and all dependencies) as a Lambda layer.

Scala: Get URL Parameters

I'm writing my first Scala lambda, and I have run into a bit of an issue, which i think should be straightforward, but I'm having trouble finding the answer.
So I have the following code that will allow me to accept json and use it in the lambda.
--eventTest.scala
val stream : InputStream = getClass.getResourceAsStream("/test_data/body.json")
--request handler
def handleRequest(input: InputStream): Unit = {
val name = scalaMapper.readValue(input, classOf[NameInfo])
val result = s"Hello there, ${name.firstName} ${name.lastName}."
println(result)
}
This works just fine, but I'm having problems figuring out how to be able to get URL parameters. Does it automatically use the same input Stream? There is seems to be very little documentation on this in Scala.
Thanks
A Lambda function's event is a JSON object. The Lambda runtime will introspect the handler function and attempt to extract or convert that object based on the function signature. I believe the easiest representation is a java.util.Map[String,String] (iirc, Lambda doesn't have a Scala runtime, so you'll have to use Java classes and convert them).
An example event from the API Gateway proxy integration: https://github.com/awsdocs/aws-lambda-developer-guide/blob/master/sample-apps/nodejs-apig/event.json
For more information about the Java runtime: https://docs.aws.amazon.com/lambda/latest/dg/java-handler.html

AWS nodejs handler module with dots yields "Bad handler" error

I'm trying to put my event handler function in a file called app.lambda.js because the app.js should contain only generic stuff not related to AWS Lambda.
But specifying "app.lambda.handler" as a handler yields Bad handler app.lambda.handler.
Is it simply impossible to use dots in the file name of the handler module?
Yes, You should give app.handler. Only one dot will allow you in handler name.
Try by giving your filename.handler. It will work for you.

CloudFormation - reference resource as default value for Parameter

I have a parameter "SecretKey" and I want to provide a default value to it (http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/parameters-section-structure.html) and the default value would be a generated random string. I already have a lambda function to do the generation of the key and a custom resource (call it RandomSecretKey) to get the value. Ultimately, I want to be able to do this in the parameters section:
"SecretKey": {
...
"Default": { "Fn::GetAtt": ["RandomSecretKey", "Value"] }
}
And this parameter would be referenced somewhere.
But this doesn't work because CloudFormation expects a static String based on the error message. Is there a way to do this?
No. It's not possible to have a dynamic default value for CloudFormation. The reason being that the template has not executed at all at the time that parameters are being collected.
If you want this to be a parameter, your generated value will have to be generated outside of the template and passed into the template as a parameter. You could do this from a bootstrapping creation script.
Alternatively, you should be able to use a Custom Resource in your template to generate your random secret key. It should be able to persist through stack updates.
References:
Custom Resources Docs - http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/template-custom-resources.html
Custom Resources Example - https://blogs.aws.amazon.com/application-management/post/Tx2FNAPE4YGYSRV/Customers-CloudFormation-and-Custom-Resources