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

Posted

技术标签:

【中文标题】如何在 AWS Lambda 中使用 Node.js 列出我的所有 Amazon EC2 实例?【英文标题】:How can I list all my Amazon EC2 instances using Node.js in AWS Lambda? 【发布时间】:2015-02-25 17:00:53 【问题描述】:

我在 AWS 上并使用 AWS SDK for javascript in Node.js。我正在尝试构建一个 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/'  

【问题讨论】:

【参考方案1】:

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

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

由于 NodeJS 的工作方式以及适用于 JavaScript 的 AWS 开发工具包的工作方式,会发生这种奇怪的排序。在 NodeJS 中,你永远不应该 block 执行。对 Web 服务(例如 EC2)的调用会阻止执行。因此,适用于 JavaScript 的 AWS 开发工具包(以及大多数 NodeJS 库)通过 异步 调用来工作。

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

在您的代码中,function(err, data) ...回调 函数。这不会立即执行,而是会在 NodeJS 看到 ec2.describeInstances 调用已收到其结果时安排执行。

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

如何解决问题?

现在答案应该很清楚了:只需将您的 context.done(...) 调用移到您的 callback 函数内部,就在包含 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!');  
);

【讨论】:

谢谢@Bruno。您如何建议在循环中完成相同的任务 - 比如创建 10 个 SQS 队列,插入 20 条消息 [ 批处理 api 存在,除此之外],如果我将 context.done() 放入循环中,这是否意味着迭代会单次执行后停止(1,然后是部分执行)【参考方案2】:

截至 2019 年(10 月),给定的答案没有帮助,经过挖掘,我现在发现它是基于承诺的

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

【讨论】:

以上是关于如何在 AWS Lambda 中使用 Node.js 列出我的所有 Amazon EC2 实例?的主要内容,如果未能解决你的问题,请参考以下文章