web-dev-qa-db-ja.com

AWS LambdaでNode.jsを使用してすべてのAmazonEC2インスタンスを一覧表示するにはどうすればよいですか?

私は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/' } }
13
Jordie

最も可能性の高い原因は、EC2 DescribeInstancesAPIの呼び出しが完了する前にLambda関数を明示的に終了していることです。

その理由は、Lambdaは、context.done(...)を呼び出すとすぐにコードの実行が終了したと想定するためです。そして、これはconsole.log(... data ...)呼び出しの前に発生しています。

この奇妙な順序は、NodeJSの動作とAWS SDK forJavaScriptの動作が原因で発生します。 NodeJSでは、実行をブロックしないでください。 Webサービス(EC2など)を呼び出すと、実行がブロックされます。したがって、AWS SDK for JavaScript(およびほとんどのNodeJSライブラリ)は、asynchronous呼び出しを行うことで機能します。

ほとんどの場合、非同期呼び出しがある場合、コールバックを渡します。その呼び出しへの関数。結果の準備ができると、NodeJSはcallback関数を実行します。

あなたのコードでは、そのfunction(err, data) {...}callback関数です。これはすぐには実行されませんが、NodeJSが_ec2.describeInstances_呼び出しがその結果を受信したことを確認すると、実行がスケジュールされます。

コールバックの実行をscheduleするとすぐに、context.done(...)を呼び出します。これにより、Lambdaに次のように通知されます:私は終わりました、あなたは私を殺すことができます。また、EC2 DescribeInstances呼び出しがデータを受信し、それをcallback関数に渡す前に、関数を順守して中断します。

問題を解決する方法は?

答えは今では明確になっているはずです。if/ elseブロックの直後にあるcallback関数内にcontext.done(...)呼び出しを移動するだけです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
Bruno Reis

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
}
0
Pranoy Sarkar