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


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

这是我的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!');  
};

这是我的政策(我认为这是正确的吗?)

{
  "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:::*"
      ]
    }
  ]
}

如果我在'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/' } }

1237
2017-12-29 13:42


起源



答案:


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

原因是Lambda假设您的代码在您调用后立即执行完毕 context.done(...)。这种情况正在发生 之前 该 console.log(... data ...) 呼叫。

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

大多数情况下,当你有一个 异步 打电话,你通过了 回电话 该电话的功能。结果准备好后,NodeJS将执行 回电话 功能。

在你的代码中,那 function(err, data) {...} 是个 回电话 功能。这不会立即执行,但会在NodeJS看到时执行 ec2.describeInstances 电话已收到其结果。

只要你 时间表 执行你的回电,你正在打电话 context.done(...),告诉Lambda: 我做完了,你可以杀了我。在EC2 DescribeInstances调用收到数据并将其传递给您之前,它很乐意遵守和中断您的功能 回电话 功能。

如何解决问题?

现在答案应该是明确的:只需移动你的 context.done(...) 打电话到你的内心 回电话 函数,紧跟在包含的if / else块之后 console.log(...data...) 呼叫:

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

13
2017-12-29 17:49



谢谢@Bruno。你如何建议在循环中完成相同的操作 - 比如创建10个SQS队列,插入20个消息[存在批处理api,除此之外],如果我将context.done()放在循环中,这并不意味着迭代会单次执行后停止(1然后部分执行) - Naveen Vijay


答案:


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

原因是Lambda假设您的代码在您调用后立即执行完毕 context.done(...)。这种情况正在发生 之前 该 console.log(... data ...) 呼叫。

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

大多数情况下,当你有一个 异步 打电话,你通过了 回电话 该电话的功能。结果准备好后,NodeJS将执行 回电话 功能。

在你的代码中,那 function(err, data) {...} 是个 回电话 功能。这不会立即执行,但会在NodeJS看到时执行 ec2.describeInstances 电话已收到其结果。

只要你 时间表 执行你的回电,你正在打电话 context.done(...),告诉Lambda: 我做完了,你可以杀了我。在EC2 DescribeInstances调用收到数据并将其传递给您之前,它很乐意遵守和中断您的功能 回电话 功能。

如何解决问题?

现在答案应该是明确的:只需移动你的 context.done(...) 打电话到你的内心 回电话 函数,紧跟在包含的if / else块之后 console.log(...data...) 呼叫:

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

13
2017-12-29 17:49



谢谢@Bruno。你如何建议在循环中完成相同的操作 - 比如创建10个SQS队列,插入20个消息[存在批处理api,除此之外],如果我将context.done()放在循环中,这并不意味着迭代会单次执行后停止(1然后部分执行) - Naveen Vijay