I have a AWS Lambda function that checks if a site is online
var http = require('https');
var url = 'https://www.google.com';
exports.handler = function(event, context) {
http.get(url, function(res) {
console.log("Got response: " + res.statusCode);
context.succeed();
}).on('error', function(e) {
console.log("Got error: " + e.message);
context.done(null, 'FAILURE');
});
}
I would like to reboot an EC2 instance if the website is offline.
This is the Lambda function to reboot EC2:
var AWS = require('aws-sdk');
exports.handler = function(event, context) {
var ec2 = new AWS.EC2({region: 'us-east-1'});
ec2.rebootInstances({InstanceIds : ['i-xxxxxxxxxxxxxxx'] },function (err, data) {
if (err) console.log(err, err.stack);
else console.log(data);
context.done(err,data);
});
};
Both functions work.
Now I am trying to call the ec2 reboot function when the https request fails.
I have an extremely limited experience with node.js and aws so I tried many different ways but no result.
Can someone point me in the right direction?
you can invoke a lambda using the invoke function.
function checkWebsite(url, callback) {
https
.get(url, function(res) {
console.log(url, res.statusCode);
return callback(res.statusCode === 200);
})
.on("error", function(e) {
return callback(false);
});
}
var http = require('https');
exports.handler = function(event, context, callback) {
var url = 'https://www.google.com';
checkWebsite(url, (check) => {
if (!check) {
const lambda = new AWS.Lambda();
const params = {
FunctionName: "my-function",
Payload: '{"instanceId":"instance-1233x5"}'
};
lambda.invoke(params, function(err, data) {
if (err) console.log(err, err.stack); // an error occurred
else console.log(data); // successful response
// handle error/ success
// if you return the error, the lambda will be retried, hence returning a successful response
callback(null, 'successfully rebooted the instance')
});
} else {
callback(null, 'successfully completed')
}
})
}
Reference: Nodejs function to check if a website working
Related
I'm trying to list all of my cognito users in my lambda function, however i get nothing in the return as if the callback not getting executed. What am I doing wrong?
The output of the code below just gives me a hello in the console.
var AWS = require("aws-sdk");
const cognitoidentityserviceprovider = new AWS.CognitoIdentityServiceProvider();
export async function main() {
console.log("hello")
var params = {
UserPoolId: "myuserpoolid",
AttributesToGet: ["username"]
};
cognitoidentityserviceprovider.listUsers(params, (err, data) => {
if (err) {
console.log(err, err.stack);
return err;
} else {
console.log(data);
return data;
}
});
}
First of all, the structure of the code is wrong. The header of Lambda function should have a certain structure, either using async function or non-async function. Since you are using non-async code in your example I will show you how to do the later.
var AWS = require("aws-sdk");
const cognitoidentityserviceprovider = new AWS.CognitoIdentityServiceProvider();
exports.handler = function(event, context, callback) {
console.log("hello")
var params = {
UserPoolId: "myuserpoolid",
AttributesToGet: ["username"]
};
cognitoidentityserviceprovider.listUsers(params, (err, data) => {
if (err) {
console.log(err, err.stack);
callback(err) // here is the error return
} else {
console.log(data);
callback(null, data) // here is the success return
}
});
}
In this case, Lambda will finish only when callback is called (or when it times out).
Similarly, you can use async function but you will need to restructure your code accordingly. Here is an example taken from official docs. Note how the promise wrapper is used.
const https = require('https')
let url = "https://docs.aws.amazon.com/lambda/latest/dg/welcome.html"
exports.handler = async function(event) {
const promise = new Promise(function(resolve, reject) {
https.get(url, (res) => {
resolve(res.statusCode)
}).on('error', (e) => {
reject(Error(e))
})
})
return promise
}
For AttributesToGet, don't use username because it is one of the fields that always gets returned. The following are members of the Attributes array, and can be used in the AttributesToGet field:
sub, email_verified, phone_number_verified, phone_number, email.
e.g.
AttributesToGet: ["email","email_verified"]
I am new to NodeJS and i am trying to post a message to AWS SNS from lambda. I took the code from AWS code samples and it is working fine in lambda.
But when i wrapped the same code in a function aand invoked from the main handler it is not working..
I tried returning and resolving the promise but nothing works.
// Load the AWS SDK for Node.js
var AWS = require('aws-sdk');
// Set region
exports.handler = async (event, context) => {
saveToSNS();
};
function saveToSNS() {
console.log("sdsdsd");
var AWS = require('aws-sdk');
var params = {
Message: 'MESSAGE_TEXT', /* required */
TopicArn: '<MY TOPIC>'
};
// Create promise and SNS service object
var publishTextPromise = new AWS.SNS({apiVersion: '2010-03-31'}).publish(params).promise();
// Handle promise's fulfilled/rejected states
return publishTextPromise.then(
function(data) {
console.log("sdsdsd");
console.log("Message ${params.Message} send sent to the topic ${params.TopicArn}");
console.log("MessageID is " + data.MessageId);
}).catch(
function(err) {
console.error(err, err.stack);
});
}
You need to place all code inside the handler as well. You can try like this:
exports.handler = async (event, context) => {
// Load the AWS SDK for Node.js
var AWS = require('aws-sdk');
// Set region
AWS.config.update({region: 'REGION'});
saveToSNS();
function saveToSNS() {
// Create publish parameters
var params = {
Message: 'MESSAGE_TEXT', /* required */
TopicArn: 'TOPIC_ARN'
};
// Create promise and SNS service object
var publishTextPromise = new AWS.SNS({apiVersion: '2010-03-31'}).publish(params).promise();
publishTextPromise.then(function(data) {
console.log("Message ${params.Message} send sent to the topic ${params.TopicArn}");
console.log("MessageID is " + data.MessageId);
}).catch(function(err) {
console.error(err, err.stack);
});
}
};
You can either use async/await like this:
// Load the AWS SDK for Node.js
var AWS = require('aws-sdk');
// Set region
exports.handler = async (event, context) => {
await saveToSNS();
};
async function saveToSNS() {
console.log("sdsdsd");
var AWS = require('aws-sdk');
var params = {
Message: 'MESSAGE_TEXT', /* required */
TopicArn: '<MY TOPIC>'
};
// Create promise and SNS service object
var publishTextPromise = new AWS.SNS({apiVersion: '2010-03-31'}).publish(params).promise();
// Handle promise's fulfilled/rejected states
return publishTextPromise.then(
function(data) {
console.log("sdsdsd");
console.log("Message ${params.Message} send sent to the topic ${params.TopicArn}");
console.log("MessageID is " + data.MessageId);
}).catch(
function(err) {
console.error(err, err.stack);
});
}
or add the return statement before calling saveToSNS() function, like this:
exports.handler = async (event, context) => {
return saveToSNS();
};
I've got a problem I cannot solve myself. My lambda function works as expected when invoked locally, but it does not send the text message when called from AWS Lambda. It doesn't log any error either.
Here's my code, I've only starred the private stuff out:
import request from 'request';
import AWS from "aws-sdk";
const options = {***};
const sentAlert = async msg => {
const sns = new AWS.SNS();
await sns.publish({
Message: msg,
PhoneNumber: '***',
MessageAttributes: {
'AWS.SNS.SMS.SenderID': {
'DataType': 'String',
'StringValue': '***'
}
}
}, function (err, data) {
if (err) {
console.log(err.stack);
return;
}
});
console.log('sms sent');
};
export const getAlert = async (event, context, callback) => {
request(options, (err, res, body) => {
if (err) { return console.log('error: ', err); }
if (body.length === 0 ) { return }
console.log(`***`);
const optionsId = {*** };
request(optionsId, (err, res, body) => {
const msg = body.current.indexes[0].description;
console.log('msg: ', msg);
sentAlert(msg);
});
});
};
I test it locally using serverless invoke local --function getSmogAlert and it works just as expected, I get the sms from AWS, but when I call it with serverless invoke --function getSmogAlert - it returns null and doesn't send any text message.
I've had similar problems with Nexmo and thought that maybe AWS.SNS will help me, but nope.
Any help, please?
As I wrote in my comment, I think you confuse the promises and callbacks in the execution. Try this changes:
const options = {***};
const sentAlert = (msg, callback) => {
const sns = new AWS.SNS();
await sns.publish({
TopicArn: ***
Message: msg,
PhoneNumber: '***',
MessageAttributes: {
'AWS.SNS.SMS.SenderID': {
'DataType': 'String',
'StringValue': '***'
}
}
}, function (err, data) {
if (err) {
console.log(err.stack);
callback(err);
}
});
console.log('sms sent');
callback(null)
};
export const getAlert = (event, context, callback) => {
request(options, (err, res, body) => {
if (err) {
console.log('error: ', err);
callback(err);
}
if (body.length === 0 ) {
console.log('Got no body!')
callback(null)
}
console.log(`***`);
const optionsId = {*** };
request(optionsId, (err, res, body) => {
if (err) {
console.log(err.stack);
callback(err);
}
const msg = body.current.indexes[0].description;
console.log('msg: ', msg);
sentAlert(msg, callback);
});
});
};
But in general, I would prefer to use async/await mechanism supported by AWS Lambda nodejs8.10 image. That would make your code simple and easier to reason about.
I have the following two JS file. My problem is when i call the Calls.js which calls the Archive.js for archiving logs into DynamoDB the request times out.
I have tried out, many things, read about many things, tried in local/AWS environment without luck. What am i missing?
Link1, Link2, Link3, Link4, Link5,
Archive.js
module.exports.archive = archive;
...
function archive(input, callback){
AWS.config.update({
region: "eu-west-1",
endpoint: "http://localhost:8000"
});
var documentClient = new AWS.DynamoDB.DocumentClient({
httpOptions: {
agent: new https.Agent({
rejectUnauthorized: true,
secureProtocol: "TLSv1_method",
ciphers: "ALL"
})
}
});
...
var paramsPUT = {
TableName: "Logging",
Item: {
HashKey: dbID,
archiveEntry: archiveEntry
}
};
...
documentClient.put(paramsPUT, function(err, data) {
if (err) console.log(err);
if (data) console.log(data);
...
callback(data);
});
}
Calls.js
exports.handler(event, context, callback) => {
const archive = require("./..path..").archive;
...
context.callbackWaitsForEmptyEventLoop = false;
...
archive(input, callback);
...
}
I can not reproduce a timeout condition with your code. Your code is talking to an AWS endpoint at http://localhost:8000, so I assume you have DynamoDB local up and running, don't you ? Failling to have local DynamoDB running would cause the timeout.
That being said, I would strongly suggest to refactor your code to use Promise and the new async/await provided by NodeJS 8 instead of passing the Lambda callback around.
Here is the modified code.
const AWS = require("aws-sdk");
async function archive(input) {
return new Promise( (resolve, reject) => {
AWS.config.update({
region: "eu-west-1",
endpoint: 'http://localhost:8000'
});
//use client specific AWS configuration instead of the global one
const documentClient = new AWS.DynamoDB.DocumentClient();
var paramsPUT = {
TableName: "Logging",
Item: {
HashKey: "123",
archiveEntry: input
}
};
documentClient.put(paramsPUT, function (err, data) {
if (err) {
console.log("ERROR " + err);
reject(err);
}
console.log("Returned from DDB " + JSON.stringify(data, null,2));
resolve(data);
});
});
}
exports.handler = async (event, context, callback) => {
const result = await archive("abc");
callback(result);
}
// stuffs to test locally
callback = function (data) {
console.log("callback called with " + JSON.stringify(data,null,2));
}
event = context = {}
exports.handler(event, context, callback);
I have 2 Lambda functions that I would like to call directly not through API Gateway. Lambda function A is Calling Lambda B along with queryStringParameters. For some reasons I'm getting this error
{ UnexpectedParameter: Unexpected key 'queryStringParameters' found in params
This is my Lambda A function
var aws = require('aws-sdk');
var lambda = new aws.Lambda({
region: 'eu-central-1'
});
exports.handler = (event, context, callback) => {
var params = {
FunctionName: "function-getStats",
InvocationType: "RequestResponse",
LogType: "Tail",
"queryStringParameters" : { "fn" : "latest_no" }
};
lambda.invoke(params, function(err, data) {
if (err) console.log(err, err.stack); // an error occurred
else console.log(data); // successful response
});
};
Which is calling Lambda B as below
var AWS = require('aws-sdk');
AWS.config.update({region: 'eu-central-1'});
var ddb = new AWS.DynamoDB.DocumentClient({apiVersion: '2012-08-10'});
exports.handler = (event, context, callback) => {
var fn = event["queryStringParameters"]['fn'];
...
..
//If successful return the following response
console.log("Success", items);
callback(null, {
'statusCode': '200',
'body': JSON.stringify(items),
'headers': {
"Access-Control-Allow-Origin": "*"
},
'isBase64Encoded': false
});
Can someone please advise how to fix this?
In case anyone got the same issue. here's the approach I did
var aws = require('aws-sdk');
var lambda = new aws.Lambda({
region: 'eu-central-1'
});
exports.handler = (event, context, callback) => {
event.queryStringParameters= {"fn" : "latest_no" };
var params = {
FunctionName: "function-getStats",
InvocationType: "RequestResponse",
LogType: "Tail",
Payload: JSON.stringify(event, null, 2),
};
lambda.invoke(params, function(err, data) {
if (err) console.log(err, err.stack); // an error occurred
else console.log(data); // successful response
});
};