Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I list all my Amazon EC2 instances using Node.js in AWS Lambda?

I'm on AWS and using AWS SDK for JavaScript in Node.js. I'm trying to build an AWS Lambda function and inside I want to get a list of all my Amazon EC2 instances, but I just can't seem to get it working. Can anyone spot what I'm doing wrong?

Here is my Lambda function code:

var AWS = require('aws-sdk');
AWS.config.region = 'us-west-1';

exports.handler = function(event, context) {
    console.log("\n\nLoading handler\n\n");
    var ec2 = new AWS.EC2();
    ec2.describeInstances( function(err, data) {
        console.log("\nIn describe instances:\n");
      if (err) console.log(err, err.stack); // an error occurred
      else     console.log("\n\n" + data + "\n\n"); // successful response
    });
    context.done(null, 'Function Finished!');  
};

And this is my policy (I think it's correct?)

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": [
        "logs:*"
      ],
      "Resource": "arn:aws:logs:*:*:*"
    },
    {
    "Effect": "Allow",
    "Action": [
      "ec2:*"
    ],
    "Resource": "arn:aws:ec2:*"
  },
    {
      "Effect": "Allow",
      "Action": [
        "s3:GetObject",
        "s3:PutObject"
      ],
      "Resource": [
        "arn:aws:s3:::*"
      ]
    }
  ]
}

And if I do a console.log on 'ec2' I get:

{ config: 
   { credentials: 
      { expired: false,
        expireTime: null,
        accessKeyId: 'XXXXXXXXXXXXXXXXXX',
        sessionToken: 'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX',
        envPrefix: 'AWS' },
     credentialProvider: { providers: [Object] },
     region: 'us-west-1',
     logger: null,
     apiVersions: {},
     apiVersion: null,
     endpoint: 'ec2.us-west-1.amazonaws.com',
     httpOptions: { timeout: 120000 },
     maxRetries: undefined,
     maxRedirects: 10,
     paramValidation: true,
     sslEnabled: true,
     s3ForcePathStyle: false,
     s3BucketEndpoint: false,
     computeChecksums: true,
     convertResponseTypes: true,
     dynamoDbCrc32: true,
     systemClockOffset: 0,
     signatureVersion: 'v4' },
  isGlobalEndpoint: false,
  endpoint: 
   { protocol: 'https:',
     host: 'ec2.us-west-1.amazonaws.com',
     port: 443,
     hostname: 'ec2.us-west-1.amazonaws.com',
     pathname: '/',
     path: '/',
     href: 'https://ec2.us-west-1.amazonaws.com/' } }
like image 885
Jordie Avatar asked Dec 29 '14 13:12

Jordie


People also ask

How do I get a list of EC2 instances?

Go to VPC dashboard https://console.aws.amazon.com/vpc/home and click on Running instances -> See all regions . Example output: $ aws. print-all-instances Listing Instances in region: 'eu-north-1'.. "EC2: i-0548d1de00c39f923: terminated" "EC2: i-0fadd093234a1c21d: running" Listing Instances in region: 'ap-south-1'..

Can Lambda Access EC2 instance?

From AWS Lambda, SSH into your EC2 instances and run commands. AWS Lambda lets you run arbitrary code without worrying about provisioning servers. I recently worked on a project where a Lambda function SSHed into an EC2 instance and ran some commands. This is a very powerful way to control access to your EC2 instances.

Does AWS Lambda support node JS?

AWS Lambda now supports Node. js 16 as both a managed runtime and a container base image. Developers creating serverless applications in Lambda with Node. js 16 can take advantage of new features such as support for Apple silicon for local development, the timers promises API, and enhanced performance.


2 Answers

As of 2019 (October), the given answer didn't help, after digging I found now it is promise based

exports.handler = async function(event) {
  const promise = new Promise(function(resolve, reject) {
      //your logic, goes here at the end just call resolve 
      resolve("data you want to return"); // here lamda exits 
    })
  return promise;// lamda does not  exits here, it waits for to resolve
}
like image 133
Pranoy Sarkar Avatar answered Sep 29 '22 07:09

Pranoy Sarkar


The most likely cause is that you are explicitly terminating your Lambda function before it completes the call to EC2 DescribeInstances API.

The reason is that Lambda assumes your code has finished executing as soon as you call context.done(...). And this is happening before the console.log(... data ...) call.

This weird ordering happens because of how NodeJS works and how the AWS SDK for JavaScript works. In NodeJS you should never block the execution. A call to a webservice (such as EC2) would block the execution. Therefore the AWS SDK for JavaScript (as well as most NodeJS libraries) works by making an asynchronous call.

Most often, when you have an asynchronous call, you pass a callback function to that call. When the results are ready, NodeJS will execute the callback function.

In your code, that function(err, data) {...} is the callback function. This is not executed immediately, but will be scheduled for execution when NodeJS sees that the ec2.describeInstances call has received the its results.

As soon as you schedule the execution of your call back, you are calling context.done(...), which tells Lambda: I'm done, you can kill me. And it's happily obeying and interrupting your function, before the EC2 DescribeInstances call receives its data and passes it to your callback function.

How to solve the problem?

The answer should be clear by now: just move your context.done(...) call to inside your callback function, right after the if/else block containing the console.log(...data...) call:

ec2.describeInstances( function(err, data) {
  console.log("\nIn describe instances:\n");
  if (err) console.log(err, err.stack); // an error occurred
  else     console.log("\n\n" + data + "\n\n"); // successful response
  context.done(null, 'Function Finished!');  
});
like image 44
Bruno Reis Avatar answered Sep 29 '22 07:09

Bruno Reis