如何在AWS Lambda中使用Node.js列出我的所有Amazon EC2实例?

时间:2021-10-16 07:34:44

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?

我在AWS上并在Node.js中使用AWS SDK for JavaScript。我正在尝试构建一个AWS Lambda函数,我希望获得所有Amazon EC2实例的列表,但我似乎无法让它工作。谁能发现我做错了什么?

Here is my Lambda function code:

这是我的Lambda函数代码:

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:

如果我在'ec2'上做一个console.log,我得到:

{ 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/' } }

1 个解决方案

#1


13  

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

最可能的原因是您在完成对EC2 DescribeInstances API的调用之前明确终止了Lambda函数。

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.

原因是Lambda假设您的代码在调用context.done(...)后立即执行。这是在console.log(... data ...)调用之前发生的。

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.

这种奇怪的排序是因为NodeJS的工作原理以及AWS SDK for JavaScript的工作原理。在NodeJS中,您永远不应该阻止执行。对Web服务(例如EC2)的调用将阻止执行。因此,AWS SDK for JavaScript(以及大多数NodeJS库)通过进行异步调用来工作。

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.

大多数情况下,当您进行异步调用时,会将回调函数传递给该调用。结果准备就绪后,NodeJS将执行回调函数。

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.

在您的代码中,该函数(错误,数据){...}是回调函数。这不会立即执行,但会在NodeJS看到ec2.describeInstances调用已收到其结果时安排执行。

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.

一旦你安排回调的执行,你就调用了context.done(...),告诉Lambda:我已经完成了,你可以杀了我。在EC2 DescribeInstances调用收到数据并将其传递给回调函数之前,它很乐意遵守和中断您的功能。

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:

现在答案应该是清楚的:只需将您的context.done(...)调用移到回调函数内部,就在包含console.log(... data ...)调用的if / else块之后:

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

#1


13  

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

最可能的原因是您在完成对EC2 DescribeInstances API的调用之前明确终止了Lambda函数。

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.

原因是Lambda假设您的代码在调用context.done(...)后立即执行。这是在console.log(... data ...)调用之前发生的。

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.

这种奇怪的排序是因为NodeJS的工作原理以及AWS SDK for JavaScript的工作原理。在NodeJS中,您永远不应该阻止执行。对Web服务(例如EC2)的调用将阻止执行。因此,AWS SDK for JavaScript(以及大多数NodeJS库)通过进行异步调用来工作。

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.

大多数情况下,当您进行异步调用时,会将回调函数传递给该调用。结果准备就绪后,NodeJS将执行回调函数。

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.

在您的代码中,该函数(错误,数据){...}是回调函数。这不会立即执行,但会在NodeJS看到ec2.describeInstances调用已收到其结果时安排执行。

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.

一旦你安排回调的执行,你就调用了context.done(...),告诉Lambda:我已经完成了,你可以杀了我。在EC2 DescribeInstances调用收到数据并将其传递给回调函数之前,它很乐意遵守和中断您的功能。

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:

现在答案应该是清楚的:只需将您的context.done(...)调用移到回调函数内部,就在包含console.log(... data ...)调用的if / else块之后:

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