lambdaからEC2ディレクトリに配置したCSVファイルにアクセスし、CSVファイル内の値を取得してlambdaに返す方法[ubuntu(Linux)]

0

やりたい事としてはタイトルの通りになります。

現状、やりたいことを実現するために以下の方法を実施していますが、テスト時にErrorとなってしまっています。 1.lambdaからEC2(ubuntu)ディレクトリに配置したシェルスクリプトファイルを実行 2.起動したシェルスクリプトファイルで同ディレクトリに配置されたCSVファイルを読み取り値を出力(echo)

以下のlambdaコードで1.を実装していますが、テスト時に下記エラーが発生しています。 改善方法があれば教えてください。 あるいは、他に取るべき手法があれば教えてください。 ※可能であればサンプルコードもあると非常にありがたいです。

<エラーメッセージ>

"errorType": "Runtime.ImportModuleError", "errorMessage": "Error: Cannot find module '@aws-sdk/client-ssm'\nRequire stack:\n- /var/task/index.js\n- /var/runtime/index.mjs", "trace": [ "Runtime.ImportModuleError: Error: Cannot find module '@aws-sdk/client-ssm'",

<コード>

const { SSMClient, ListCommandsCommand, SendCommandCommand } = require('@aws-sdk/client-ssm');

const startSsmRunCommandHandler = async (event) => {
    // SSMインスタンスを生成
    const client = new SSMClient({ region: '<リージョン名を指定>' });
    
    // RunCommandのコマンドインスタンスを生成
    const commandRunCommand = new SendCommandCommand({
        DocumentName: 'AWS-RunShellScript',
        InstanceIds: ['対象のインスタンスID'],
        Parameters: {
            commands: ["sh <起動するシェルスクリプトファイル名>"],
            workingDirectory: ['/home/ubuntu/<ディレクトリ名>']
        },
    });

    // 実行したRunCommandのIDを格納するための変数
    let runCommandId;
    // RunCommandを実行
    await client
        .send(commandRunCommand)
        .then((data) => {
            console.info(`SSM RunCommand Success: ${data}`);
            // RunCommandのIDを取得します。
            runCommandId = data.Command.CommandId;
        })
        .catch((error) => {
            console.error(`SSM RunCommand Failed: ${error.message}`);
            throw error;
        });

    // 実行したRunCommandのリスト取得のコマンドインスタンを生成
    const commandList = new ListCommandsCommand({
        CommandId: runCommandId
    });

    // ListCommandを実行する関数
    const runCommandStatusGetFunction = async () => {
        await client
            .send(commandList)
            .then((data) => {
                console.info(`RunCommand List: ${JSON.stringify(data)}`);
                const cmd = data.Commands[0];
                const status = cmd.Status;
                switch (status) {
                    case 'Pending':
                    case 'InProgress':
                    case 'Delayed':
                        // Pending, InProgress, Delayedの場合はエラーをスローして再実行する。
                        throw new Error('ListCommand Re-run.');
                    case 'Success':
                        console.info(`SSM RunCommand Finished.`);
                    default:
                        // 上記ステータス以外はlambdaを異常終了させる。
                        context.fail(new Error(`SSM RunCommand Failed.`));
                }
            });
    };

    // エラーが発生した場合再実行を行う関数
    const retry = (func, onError) => {
        const _retry = (e) => {
            return onError(e)
              .catch((e) => {
                throw e;
              })
              .then(func)
              .catch(_retry);
        };
        return func().catch(_retry);
    };

    // 実行結果が特定できるまで繰り返し処理する。
    await retry(runCommandStatusGetFunction, (e) => {
        console.error(e);
        return new Promise((resolve) => setTimeout(resolve, 2000));
    });
};

module.exports = {
    startSsmRunCommandHandler: startSsmRunCommandHandler
};
已提问 2 个月前176 查看次数
1 回答
0
已接受的回答

こんな感じでサンプルコード作ってみました。
おそらく新しいバージョンのNode.jsを使用していて「require」が使えないのではないかと思います。

SendCommandCommandとGetCommandInvocationCommandの使い方は以下のドキュメントに記載されています。
https://docs.aws.amazon.com/AWSJavaScriptSDK/v3/latest/client/ssm/command/SendCommandCommand/
https://docs.aws.amazon.com/AWSJavaScriptSDK/v3/latest/client/ssm/command/GetCommandInvocationCommand/

GetCommandInvocationCommandを実行するときに5秒間待機する処理にしましたが、この書き方ではなくレスポンスに含まれるStatusが「Success」以外の時にループさせるような処理でもよいと思います。
https://docs.aws.amazon.com/systems-manager/latest/userguide/monitor-commands.html

import { SSMClient, SendCommandCommand, GetCommandInvocationCommand } from "@aws-sdk/client-ssm";

export const handler = async (event) => {
  // TODO implement
  const client = new SSMClient({region: 'ap-northeast-1'});
  const input = {
      DocumentName: 'AWS-RunShellScript',
      InstanceIds: ['EC2 ID],
      Parameters: {
          commands: ["sh test.sh"],
          workingDirectory: ['/home/ec2-user/']
      }
  }
  const command = new SendCommandCommand(input);
  const response = await client.send(command);
  const commandId = response.Command.CommandId;
  const getCommandInput = {
    CommandId: commandId,
    InstanceId: 'EC2 ID'
  }
  await new Promise(resolve => setTimeout(resolve, 5000));  
  const getCommand = new GetCommandInvocationCommand(getCommandInput);
  const getResponse = await client.send(getCommand);

  console.log(getResponse.StandardOutputContent);
};

profile picture
专家
已回答 2 个月前
  • シェルスクリプトはこんな感じです。

    #!/bin/bash
    
    cat test.csv
    

    CSVのサンプルは以下になります。

    test,kobayashi,riku
    

    Lambdaを実行すると以下のようにCloudWatch Logsに記録されます。 a

  • Riku_Kobayashi様 早々にご回答いただきありがとうございます。

    丁寧なご回答およびサンプルコードのおかげもあり、無事やりたい事が実現できました。 時間待機ではなくステータスに応じて、ループし ・待機 ・GetCommandInvocationCommandを実行 ・異常終了 を使い分ける書き方も調査して試してみます。

    早々かつ的確なご回答ありがとうございました。 承認させていただきます。

您未登录。 登录 发布回答。

一个好的回答可以清楚地解答问题和提供建设性反馈,并能促进提问者的职业发展。

回答问题的准则

相关内容