Adding CloudWatchEvents to AWS lambda function - amazon-web-services

I have 2 AWS lambda functions belonging to the same account producer and consumer function. I want the producer to schedule the consumer to run at a specified time. When I check under CloudWatch Events the events are being created but the consumer is not being triggered. I am using this link
Producer Code
var AWS = require('aws-sdk');
var cwevents = new AWS.CloudWatchEvents({apiVersion: '2015-10-07'});
var params_for_rule = {
Name: 'DEMO_EVENT',
ScheduleExpression: 'cron(0/3 * * * ? *)',
State: 'ENABLED'
};
var params_for_target = {
Rule: 'DEMO_EVENT',
Targets: [
{
Arn: 'consumer',
Id: 'default',
}
]
};
exports.handler = async (event, context, callback) => {
const response = {
statusCode: 200,
body: JSON.stringify('Hello from Lambda!'),
};
cwevents.putRule(params_for_rule, function(err, data){
if(err){
console.log("Not Working");
}
else{
console.log("Working");
cwevents.putTargets(params_for_target, function(err, data){
if(err){
console.log("Not Working");
}
else{
console.log("Working");
}
});
}
});
};

You are calling callback before the function putTargets will return.
Your callback code should be done after putTargets returns with success.
cwevents.putRule(params_for_rule, function(err, data){
if(err){
console.log("Not Working");
}
else{
console.log("Working");
cwevents.putTargets(params_for_target, function(err, data){
if(err){
console.log("Not Working");
callback(err, null);
}
else{
console.log("Working");
callback(null, response);
}
});
}
});

For the cloud Watch event to be added we need to add certain permissions using the addPermission method. Here is the
document.
Here is the sample code.
cwevents.putRule(params_for_rule, function(err, data){
if(err){
console.log("Not Working",data);
}
else{
console.log("Working",data);
lambda.addPermission(lambdaPermission, function(err, data){
if(err){
console.log(err);
}
else{
console.log(data);
cwevents.putTargets(params_for_target, function(err, data){
if(err){
console.log("Not Working",data);
}
else{
console.log("Working",data);
}
});
}
});
}
});

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
}
});
})
};

Recall dynamodb table with Alexa

Im trying to create a skill that will scan or query my dynamodb table which includes a date column, filmanme, and time.
Here is the code i have so far.
console.log('Loading function');
var AWSregion = 'us-east-1'; // us-east-1
var AWS = require('aws-sdk');
var dclient = new AWS.DynamoDB.DocumentClient();
var getItems = (event, context, callback)=>{
dclient.get(event.params,(error,data)=>{
if(error){
callback(null,"error occurerd");
}
else{
callback(null,data);
}
});
};
exports.handler = getItems;
exports.handler = (event, context, callback) => {
try {
var request = event.request;
if (request.type === "LaunchRequest") {
context.succeed(buildResponse({
speechText: "Welcome to H.S.S.M.I skill, what would you like to find",
repromptText: "I repeat, Welcome to my skill, what would you like to find",
endSession: false
}));
}
else if (request.type === "IntentRequest") {
let options = {};
if (request.intent.name === "cinema") {
if (request.intent.slots.cimema !== undefined)
var sign = request.intent.slots.cinema.value;
//Check sign is valid
if (sign === undefined || sign === null) {
options.speechText = " sorry, i didn't understant your question. can you say that again?";
options.endSession = false;
context.succeed(buildResponse(options));
return;
}
if (request.intent.slots.zodiac !== undefined && !ValidateZodiacSign(sign)) {
options.speechText = ` The Zoadiac sign ${sign} is not a valid one. Please tell a valid zodiac sign .`;
options.endSession = false;
context.succeed(buildResponse(options));
return;
}
cinema(sign, function (cinema, error) {
if (error) {
context.fail(error);
options.speechText = "There has been a problem with the request.";
options.endSession = true;
context.succeed(buildResponse(options));
} else {
options.speechText = todaysFortune;
options.speechText += " . Have a nice day ahead . ";
options.sign = sign;
options.cardText = todaysFortune;
options.endSession = true;
context.succeed(buildResponse(options));
}
});
} else if (request.intent.name === "AMAZON.StopIntent" || request.intent.name === "AMAZON.CancelIntent") {
options.speechText = "ok, good bye.";
options.endSession = true;
context.succeed(buildResponse(options));
}
else if (request.intent.name === "AMAZON.HelpIntent") {
options.speechText = "My skill will read your table depending on what is asked. For example, you can ask what about a specific date. Please refer to skill description for all possible utterences.";
options.repromptText = "What is the data sign you want to know about today? If you want to exit from my skill please say stop or cancel."
options.endSession = false;
context.succeed(buildResponse(options));
}
else {
context.fail("Unknown Intent")
}
}
else if (request.type === "SessionEndedRequest") {
options.endSession = true;
context.succeed();
}
else {
context.fail("Unknown Intent type");
}
} catch (e) {
}
};
function buildResponse(options) {
var response = {
version: "1.0",
response: {
outputSpeech: {
"type": "SSML",
"ssml": `<speak><prosody rate="slow">${options.speechText}</prosody></speak>`
},
shouldEndSession: options.endSession
}
};
if (options.repromptText) {
response.response.reprompt = {
outputSpeech: {
"type": "SSML",
"ssml": `<speak><prosody rate="slow">${options.repromptText}</prosody></speak>`
}
};
}
return response;
}
function readDynamoItem(params, callback) {
var AWS = require('aws-sdk');
AWS.config.update({region: AWSregion});
var dynamodb = new AWS.DynamoDB();
console.log('reading item from DynamoDB table');
dynamodb.scan(params, function(err, data) {
if (err) console.log(err, err.stack); // an error occurred
else{
console.log(data); // successful response
callback(JSON.stringify(data));
}
});
var docClient = new AWS.DynamoDB.DocumentClient();
//Get item by key
docClient.get(params, (err, data) => {
if (err) {
console.error("Unable to read item. Error JSON:", JSON.stringify(err, null, 2));
} else {
console.log("GetItem succeeded:", JSON.stringify(data, null, 2));
callback(data.Item.message); // this particular row has an attribute called message
}
});
}
///////////////////////////////////////////////////////////////////////////////
and here is my DBHandlder
const AWS = require('aws-sdk');
AWS.config.update({
region: "'us-east-1'"
});
var docClient = new AWS.DynamoDB.DocumentClient();
var table = "Cinema";
var getItems = (Id,callback) => {
var params = {
TableName: "cinema",
Key: {
"Id": Id
}
};
docClient.get(params, function (err, data) {
callback(err, data);
});
};
module.exports = {
getItems
};
i'm very new to this and i cant find muchsupport online for the skill i want to produce or anything similar.
I created a lambda function which works and will find the corresponding movie when i configure the test function to find a specified date, however this does not work with alexa
any input is helpful.

Transfer data from SQS to Dynamodb

Is there a way to transfer the messages I get from SQS and send them over to Dynamodb? I've tried making a Lambda function using CloudWatch to trigger it every minute. I'm open to using any other services in AWS to complete this task. I'm sure there's a simple explanation to this that I'm just overlooking.
*Edit my code does not work, I'm looking for either a fix to my code or another solution to accomplish this.
**Edit got it working.
'use strict';
const AWS = require('aws-sdk');
const SQS = new AWS.SQS({ apiVersion: '2012-11-05' });
const Lambda = new AWS.Lambda({ apiVersion: '2015-03-31' });
const QUEUE_URL = 'SQS_URL';
const PROCESS_MESSAGE = 'process-message';
const DYNAMO_TABLE = 'TABLE_NAME';
function poll(functionName, callback) {
const params = {
QueueUrl: QUEUE_URL,
MaxNumberOfMessages: 10,
VisibilityTimeout: 10
};
// batch request messages
SQS.receiveMessage(params, function(err, data) {
if (err) {
return callback(err);
}
// parse each message
data.Messages.forEach(parseSQSMessage);
})
.promise()
.then(function(){
return Lambda.invokeAsync({})
.promise()
.then(function(data){
console.log('Recursion');
})
}
)
.then(function(){context.succeed()}).catch(function(err){context.fail(err, err.stack)});
}
// send each event in message to dynamoDB.
// remove message from queue
function parseSQSMessage(msg, index, array) {
// delete SQS message
var params = {
QueueUrl: QUEUE_URL,
ReceiptHandle: msg.ReceiptHandle
};
SQS.deleteMessage(params, function(err, data) {
if (err) console.log(err, err.stack); // an error occurred
else console.log(data); // successful response
});
}
// store atomic event JSON directly to dynamoDB
function storeEvent(event) {
var params = {
TableName : DYNAMO_TABLE,
Item: event
};
var docClient = new AWS.DynamoDB.DocumentClient();
docClient.put(params, function(err, data) {
if (err) console.log(err);
else console.log(data);
});
}
exports.handler = (event, context, callback) => {
try {
// invoked by schedule
poll(context.functionName, callback);
} catch (err) {
callback(err);
}
};
var aws = require( "aws-sdk" );
// get configuration defaults from config file.
var tableName = 'Table_Name';
var queueUrl = 'SQS_URL';
var dbClient = new aws.DynamoDB.DocumentClient();
var sqsClient = new aws.SQS();
// get config values from dynamodb - if the config values are found, then override existing values
// this will occur on every execution of the lambda which will allow real time configuration changes.
var updateConfig = function updateConfigValues(invokedFunction, cb) {
var params = {
TableName: "Table_NAME",
Key: {
"KEY": "KEY"
}
};
dbClient.get(params, function(err, data) {
if(err) {
console.log("ERR_DYNAMODB_GET", err, params);
}
else if(!data || !data.Item) {
console.log("INFO_DYNAMODB_NOCONFIG", params);
}
else {
queueUrl = data.Item.config.queueUrl;
tableName = data.Item.config.tableName;
}
return cb(err);
});
};
// save the email to dynamodb using conditional write to ignore addresses already in the db
var saveEmail = function saveEmail(messageBody, cb) {
var params = {
TableName:tableName,
Item:messageBody,
ConditionExpression : "attribute_not_exists(clickId)",
};
dbClient.put(params, function(err, data) {
cb(err, data);
});
};
var deleteMessage = function deleteMessage(receiptHandle, cb) {
var params = {
QueueUrl: queueUrl,
ReceiptHandle: receiptHandle
};
sqsClient.deleteMessage(params, function(err, data) {
cb(err, data);
});
}
exports.handler = function(event, context) {
updateConfig(context.invokedFunctionArn, function(err) {
if(err) {
context.done(err);
return;
}
console.log("INFO_LAMBDA_EVENT", event);
console.log("INFO_LAMBDA_CONTEXT", context);
sqsClient.receiveMessage({MaxNumberOfMessages:10 , QueueUrl: queueUrl}, function(err, data) {
if(err) {
console.log("ERR_SQS_RECEIVEMESSAGE", err);
context.done(null);
}
else {
if (data && data.Messages) {
console.log("INFO_SQS_RESULT", " message received");
var message = JSON.parse(data.Messages[0].Body);
var messageBody = message.Message;
messageBody = JSON.parse(messageBody);
// loops though the messages and replaces any empty strings with "N/A"
messageBody.forEach((item) => {
var item = item;
var custom = item.customVariables;
for (i = 0; i < custom.length; i++) {
if(custom[i] === ''){
custom[i] = 'N/A';
}
item.customVariables = custom;
}
for(variable in item) {
if(item[variable] === ""){
item[variable] = "N/A";
console.log(item);
}
}
var messageBody = item;
});
var messageBody = messageBody[0];
// Logs out the new messageBody
console.log("FIXED - ", messageBody);
// Checks for errors and delets from que after sent
saveEmail(messageBody, function(err, data) {
if (err && err.code && err.code === "ConditionalCheckFailedException") {
console.error("INFO_DYNAMODB_SAVE", messageBody + " already subscribed");
deleteMessage(message.MessageId, function(err) {
if(!err) {
console.error("INFO_SQS_MESSAGE_DELETE", "receipt handle: " + message.MessageId, "successful");
} else {
console.error("ERR_SQS_MESSAGE_DELETE", "receipt handle: " + message.MessageId, err);
}
context.done(err);
});
}
else if (err) {
console.error("ERR_DYNAMODB_SAVE", "receipt handle: " + message.MessageId, err);
context.done(err);
}
else {
console.log("INFO_DYNAMODB_SAVE", "email_saved", "receipt handle: " + message.MessageId, messageBody.Message);
deleteMessage(message.MessageId, function(err) {
if(!err) {
console.error("INFO_SQS_MESSAGE_DELETE", "receipt handle: " + message.MessageId, "successful");
} else {
console.error("ERR_SQS_MESSAGE_DELETE", "receipt handle: " + message.MessageId, err);
}
context.done(err);
});
}
});
} else {
console.log("INFO_SQS_RESULT", "0 messages received");
context.done(null);
}
}
});
});
}

Node js: How to set aws cloudwatch alarm state

Tried with below lambda function which will change the state of alarm "OnSNSFailureArm".
exports.handler = (event, context, callback) => {
var params = {
AlarmName: 'OnSNSFailureArm',
StateReason: 'Change Dynamically',
StateValue: "INSUFFICIENT_DATA"
};
cloudwatch.setAlarmState(params, function(err, data) {
if (err){
console.log(err, err.stack);
context.done();
}
else{
console.log(data);
context.done();
}
});
};