How to scan the dynamodb table form the AWS Lambda function - amazon-web-services

I am trying to scan the Dynamodb table form my following code, can anyone please guide me what is wrong here.
const AWS = require("aws-sdk");
const dynamodb = new AWS.DynamoDB({
region: "eu-west-1",
apiVersion: "2012-08-10"
});
exports.handler = async (event, callback) => {
const params = {
TableName: "job_Status"
};
dynamodb.scan(params, (err, data) => {
if (err) {
console.log(err);
callback(err);
} else {
console.log(data);
callback(null, data);
}
});
};
I have given full dynamodb access role to the function but still it gives me the null response. Any idea what can be wrong here?
Response:
I tried with dynaomClient which not working too.
const AWS = require("aws-sdk");
const db = new AWS.DynamoDB.DocumentClient({
region : 'eu-west-1'
});
exports.handler = async (event, callback) => {
const params = {
TableName: "job_Status"
};
db.scan(params, (err, data) => {
if (err) {
console.log(err);
callback(err);
} else {
console.log(data);
callback(null, data);
}
});
};

Your Lambda function is async but your code uses callbacks. By the time the callback is reached, your function has already been terminated because it ran asynchronously. I'd speculate that the null output you see is the return value from the Lambda function, not your console.log.
Replace your call to scan with the following:
try{
let results = await db.scan(params).promise()
console.log(results);
} catch(err){
console.log(err)
}
For more info, check out the AWS documentation about working with promises.

Related

Lambda not triggering codebuild to run?

I am trying to have lambda trigger a codebuild function when it hits the point within the lambda function, here is the current code im using for lamda:
console.log('Loading function');
const aws = require('aws-sdk');
const s3 = new aws.S3();
exports.handler = async (event, context) => {
const codebuild = new aws.CodeBuild();
let body = JSON.parse(event.body);
let key = body.model;
var getParams = {
Bucket: 'bucketname', // your bucket name,
Key: key + '/config/training_parameters.json' // path to the object you're looking for
}
if (key) {
const objects = await s3.listObjects({
Bucket: 'bucketname',
Prefix: key + "/data"
}).promise();
console.log(objects)
if (objects.Contents.length == 3) {
console.log("Pushing")
await s3.getObject(getParams, function(err, data) {
if (err)
console.log(err);
if (data) {
let objectData = JSON.parse(data.Body.toString('utf-8'));
const build = {
projectName: "projname",
environmentVariablesOverride: [
{
name: 'MODEL_NAME',
value: objectData.title,
type: 'PLAINTEXT',
},
]
};
console.log(objectData.title)
codebuild.startBuild(build,function(err, data){
if (err) {
console.log(err, err.stack);
}
else {
console.log(data);
}
});
console.log("Done with codebuild")
}
}).promise();
const message = {
'message': 'Execution started successfully!',
}
return {
'statusCode': 200,
'headers': {'Content-Type': 'application/json'},
'body': JSON.stringify(message)
};
}
}
};
Specifically this part should trigger it:
codebuild.startBuild(build,function(err, data){
if (err) {
console.log(err, err.stack);
}
else {
console.log(data);
}
});
But its not, it even outputs after the function? Im thinking its something to do with promises/await/async but cant find the right solution? Any help would be appreciated.
As you pointed out the problem is related to promises. Change your code like this:
const result = await codebuild.startBuild(build).promise();
And if you configured your lambda permissions for CodeBuild it should work.
You can change your s3.getObject the same way without the callback function:
const file = await s3.getObject(getParams).promise();
console.log(file.Body);

How to publish to AWS Shadow from lambda

This is the code Iam using,
var AWS = require('aws-sdk');
var iotdata = new AWS.IotData({
endpoint: '###########.iot.ap-south-1.amazonaws.com'
});
exports.handler = async (event) => {
var params = {
payload: Buffer.from('...') || 'STRING_VALUE'
encoded on your behalf */, /* required */
thingName: 'ESP32', /* required */
//shadowName: 'STRING_VALUE'
};
iotdata.updateThingShadow(params, function(err, data) {
if (err) console.log(err, err.stack); // an error occurred
else console.log(data); // successful response
});
};
I referred to this from the given link,
https://docs.aws.amazon.com/AWSJavaScriptSDK/latest/AWS/IotData.html#updateThingShadow-property
But I cant update my shadow.
I also dont understand in which format I should include the payload.
I am running this on AWS Lambda function in Nodejs 12.x environment. I also dont receive any errors in cloudwatch . Cloudwatch tells me execution result has succeeded? Can you help me?
I have already given permission for Lambda to updateShadow.
This the final correct code .....
var AWS = require('aws-sdk');
var iotdata = new AWS.IotData({
endpoint: '#######.iot.ap-south-1.amazonaws.com'
});
exports.handler = async (event) => {
var POST_DATA = JSON.stringify({"state":{"desired":{"state":10}}});
await new Promise((resolve, reject) => {
var params = {
payload:POST_DATA ,
thingName: 'ESP32', /* required */
//shadowName: 'STRING_VALUE'
};
iotdata.updateThingShadow(params, function(err, data) {
if (err) {
console.log(err, err.stack);
console.log("error................")// an error occurred
reject(err);
} else {
console.log(data); // successful response
resolve(data)
}
});
})
}
The issue here is that you are using the async Lambda handler. So while your updateThingShadow() call is in progress, the Lambda function completes and exits. You need to wait for that call to complete. There are two ways to do that -
Approach 1: (A simpler async-await syntax)
var AWS = require('aws-sdk');
var iotdata = new AWS.IotData({
endpoint: '###########.iot.ap-south-1.amazonaws.com'
});
exports.handler = async (event) => {
var params = {
// Define params
};
try {
const data = await iotdata.updateThingShadow(params).promise();
console.log(data);
} catch (err) {
console.log(err);
}
};
Approach 2: (If you prefer using the callback approach)
var AWS = require('aws-sdk');
var iotdata = new AWS.IotData({
endpoint: '###########.iot.ap-south-1.amazonaws.com'
});
exports.handler = async (event) => {
var params = {
// Define params
};
await new Promise((resolve, reject) => {
iotdata.updateThingShadow(params, function(err, data) {
if (err) {
console.log(err, err.stack); // an error occurred
reject(err); // End the promise with an error
} else {
console.log(data); // successful response
resolve(data); // End the promise with success
}
});
})
};

Trouble making a Query of DynamoDB with Lambda (Node.js)

I want to make a query to return all entries with a certain userID, in this case Will666. I have a primaryKey and a sortKey.
const AWS = require('aws-sdk');
const dynamodb = new AWS.DynamoDB({region: 'eu-west-2', apiVersion: '2012-08-10'});
exports.handler = (event, context, callback) => {
const params = {
TableName: "signalepisodes",
KeyConditionExpression: "userID = :a",
ExpressionAttributeValues: {
":a": "Will666"
}
};
dynamodb.query(params, function(err, data){
if (err) {
console.log(err);
callback(err);
} else {
console.log(data);
const items = data.Items.map(
(dataField) => {
return { userID: dataField.userID.S, uploadDate: dataField.uploadDate.N, epTitle: dataField.epTitle.S };
}
);
callback(null, items);
}
});
};
i get this error message when i test it. I guess my syntax is wrong but i can't work it out.
"errorType": "MultipleValidationErrors",
my dynamoDB table looks like this:
The DynamoDB SDK has two types of client:
low-level client: new AWS.DynamoDB(...)
high-level client: new AWS.DynamoDB.DocumentClient(...)
You are currently using #1, but you are supplying attributes to your query as if you were using the document client #2.
So, either switch to the DocumentClient, and continue to use:
{":a": "Will666"}
Or stick with the low-level client and change your attributes to indicate value types, for example:
{":a": {"S": "Will666"}}
I'd recommend the DocumentClient because it significantly simplifies the marshalling and unmarshalling of data.
I would also recommend updating your code from the old callback style asynchronous code to the newer Promise-based options. For example, something like this:
exports.handler = async (event, context) => {
const params = {
TableName: "signalepisodes",
KeyConditionExpression: "userID = :a",
ExpressionAttributeValues: { ":a": "Will666" }
};
const items = await dynamodb.query(params).promise();
for (const item of items) {
console.log('Item:', item);
}
return items;
}

How to access the aws parameter store from a lambda using node.js and aws-sdk

I've created a lambda and cloud formation template which grants a lambda access to the parameter store and secrets manager. When I test the lambda I have the following functions outside of the export.handler function:
function getParameterFromStore(param){
let promise = new Promise(function(resolve, reject){
console.log('++ ' + param.Path);
servmgr.getParametersByPath(param, function(err, data){
if(err){
reject(console.log('Error getting parameter: ' + err, err.stack));
} else {
resolve(data);
}
});
});
let parameterResult = promise.then(function(result){
console.log('---- result: '+ JSON.stringify(result));
return result;
});
return parameterResult;
};
servmgr is instantiated as var servmgr = new AWS.SSM();
When I call this function from the export.handler function I do so as:
myFirstParam = { Path : '/myPath/Service/servicesEndpoint'};
let endpointResult = getParameterFromStore(myFirstParam);
In the lambda I have the function retrieve the parameter defined outside of the export.handler function bt wrapped in a promise.
When I run/test this lambda the object returned is always undefined... I get Parameters[] back but no values.
2019-02-20T21:42:41.340Z 2684fe88-d552-4560-a477-6761f2de6717 ++ /myPath/Service/serviceEndpoint
2019-02-20T21:42:41.452Z 2684fe88-d552-4560-a477-6761f2de6717 ---- result: {"Parameters":[]}
How do you get parameter values returned back to a lambda at run time?
update
based upon the suggestion/answer from Thales I've simplified the lambda to just this:
const getParameterFromStoreAsync = (param) => {
return new Promise((resolve, reject) => {
servmgr.getParametersByPath(param, (err, data) => {
if(err){
reject(console.log('Error getting parameter: ' + err, err.stack));
}
return resolve(data);
});
});
};
exports.handler = async(event, ctx, callback) => {
console.log('INFO[lambda]: Event: [' + JSON.stringify(event, null, 2) + ']');
console.log('this is the event' + JSON.stringify(event));
sfdcEndPointParam = { Path : '/PartnerBanking/Service/SfdcEndpoint'};
let myendpoint = await getParameterFromStoreAsync(sfdcEndPointParam);
console.log('### endpoint path: ' + JSON.stringify(myendpoint));
done = ()=>{}
callback(null, done());
};
I am still seeing an empty array being returned in my tests:
### endpoint path: {"Parameters":[]}
I've also moved the function into the callback as
exports.handler = (event,ctx, callback){
done = async()=>{
console.log('this is the event' + JSON.stringify(event));
sfdcEndPointParam = { Path : '/PartnerBanking/Service/SfdcEndpoint'};
let myendpoint = await getParameterFromStoreAsync(sfdcEndPointParam);
console.log('### endpoint path: ' + JSON.stringify(myendpoint));}
}
callback(null, done());
Same result ... empty array. Any additional things to try?
This is because your getParameterFromStore returns before your then() code is executed, thus parameterResult is undefined. If you don't want to change your code too much, I would return the Promise you create, like this:
function getParameterFromStore(param){
return new Promise(function(resolve, reject){
console.log('++ ' + param.Path);
servmgr.getParametersByPath(param, function(err, data){
if(err){
reject(console.log('Error getting parameter: ' + err, err.stack));
} else {
resolve(data);
}
});
});
};
And finally, on your function's client, you can get the result like this:
const myFirstParam = { Path : '/myPath/Service/servicesEndpoint'}
getParameterFromStore(myFirstParam).then(console.log)
When coding in NodeJS, however, I highly recommend you use async/await instead, so you'll be able to escape the Promise Hell (chaninig Promise after Promise in order to achieve something "synchronously")
When using async/await, you can design your code as though it was synchronous. Here's a refactored version of your example, using async/await as well as arrow functions:
const getParameterFromStore = param => {
return new Promise((resolve, reject) => {
console.log('++ ' + param.Path);
servmgr.getParametersByPath(param, (err, data) => {
if (err) {
console.log('Error getting parameter: ' + err, err.stack)
return reject(err);
}
return resolve(data);
});
})
}
exports.handler = async (event) => {
const endpointResult = await getParameterFromStore(event.someAttributeFromTheEventThatYouWantToUse)
console.log(endpointResult)
};
EDIT: After the OP fixed the first issue, I created a working example on my own. It turned out that the way the OP was invoking the API was incorrect.
Here's the full working example:
'use strict';
const AWS = require('aws-sdk')
AWS.config.update({
region: 'us-east-1'
})
const parameterStore = new AWS.SSM()
const getParam = param => {
return new Promise((res, rej) => {
parameterStore.getParameter({
Name: param
}, (err, data) => {
if (err) {
return rej(err)
}
return res(data)
})
})
}
module.exports.get = async (event, context) => {
const param = await getParam('MyTestParameter')
console.log(param);
return {
statusCode: 200,
body: JSON.stringify(param)
};
};
Mind the Name attribute which must be provided as part of the API call to the ServiceManager.getAttribute method.
This attribute is stated in the official docs
I have run this myself and here's the output in CloudWatch Logs:
As you can see, the value was returned successfully.
Hope this helps!
If your lambda is deployed on VPC, make sure that Security Group is attached to it and outbound traffic is allowed. It will be able to access parameter store automatically.
https://aws.amazon.com/premiumsupport/knowledge-center/lambda-vpc-parameter-store/
A simpler solution would be:
const getParameterFromStore = (params) => servmgr.getParametersByPath(params).promise();
const myFirstParam = { Path : '/myPath/Service'};
getParameterFromStore(myFirstParam).then(console.log);
As you can see, the SDK itself provides utility functinality that you can use depending on your needs to use in an async or syncronious fashion.
Hope it helps.

Calling AWSCognito signup from lambda function

I am trying to create a lambda function to create a user whenever there is an update in one of the tables of dynamo db.
I have created a dynamodb table with a trigger. I get "adminCreateUser not a function" error when i run the below code in lambda.
lambda function:
exports.handler = function(event, context) {
// TODO implement
cognitoidentityserviceprovider.adminCreateUser(params, function(err, data) {
if (err) console.log(err, err.stack); // an error occurred
else console.log(data); // successful response
});
context.done(null, 'Hello from Lambda');
};
It should be just the code below. Maybe make sure adminCreateUser is in your main AWS SDK, it was only introduced pretty recently.
const AWS = require('aws-sdk');
exports.handler = (event, context, callback) => {
AWS.config.apiVersions = {
cognitoidentityserviceprovider: '2016-04-18'
};
AWS.config.update({accessKeyId: 'akid', secretAccessKey: 'secret'});
var cognito = new AWS.CognitoIdentityServiceProvider({
region: 'us-east-1'
});
params = {};
cognito.adminCreateUser(params, function(err, data) {
if (err) console.log(err, err.stack); // an error occurred
else
console.log(data); // successful response
});
context.done(null, 'Hello from Lambda');
};