SSM Automation で AWS Lambda の関数を実行してみる。

記事タイトルとURLをコピーする

こんにちは。
技術課の山本です。

SSM Automation を試したことがなかったので、触ってみました。
SSM Automation を使い Lambda 関数を実行してみました。

はじめに、Amazon 提供の Runbook のご紹介

SSM Automation では 利用者がさまざまな Runbook を作成して実行します。
また、利用者が独自の Runbook を作らなくても大丈夫なように、Amazon がさまざまな Runbook を作成し提供しています。
CloudTrail を有効にする Runbook 、EC2 にボリュームを付与する Runbook などがあります。
Jira に issue を起票するものだったり、ServiceNow に incident を作成したりするものなど、外部サービスとの連携処理もできます。

独自の Runbook を作成し、 AWS Lambda の関数を実行してみる。

AWS Lambda の関数を実行する場合は、独自の Runbook を作成します。(2023年2月28日時点)

事前準備:Lambda 関数 (test) の作成

以下のようなコードの Lambda 関数 (test) を用意してみました。
5秒待って、statusCode 500 を返す関数です。Node.js 18 で書いています。
Lambda のタイムアウト値はデフォルトでは 3秒なので、 少し伸ばしています。

export const handler = async(event, callback) => {
    function sleep(waitSec) {
        return new Promise(function (resolve) {
            setTimeout(function() { resolve() }, waitSec);
        });
    } 
    await sleep(5000);
    const response = {
        statusCode: 500,
        body: JSON.stringify('Hello from Lambda!'),
        headers: {
            'Content-Type': 'application/json',
        }
    };
    return response;
};

Lambda のコード画面です。

タイムアウト設定画面です。5分3秒にしてるのは、深い意味はありません。
いろいろ試していて、たまたまこの設定になっています。

Lamba をテスト実行すると、Succeeded (成功)で、statusCode は 500 です。
Succeeded (成功)なのは コード内で throw せずに、return しているためです。

Lambda 関数 (test) を実行する SSM Automation の Runbook

Lambda 関数 (test) を実行する SSM Automation の Runbook を作成してみます。

作成画面 その2 です。

Editor には以下の yaml を記載します。

description: Invoke Lambda Functions
schemaVersion: '0.3'
#assumeRole: '{{ AutomationAssumeRole }}'
parameters:
  FunctionName:
    type: String
    description: Lambda Function Name
    default: 'test'
mainSteps:
  - name: lambda1
    action: 'aws:invokeLambdaFunction'
    inputs:
      InvocationType: RequestResponse
      FunctionName: '{{FunctionName}}'
  • 解説します。
    • parameters セクションには、 Automation 実行時に入力する引数を定義します。今回は Lambda 関数名を引数にします。
      • 文字列型 (String)
      • デフォルトの引数を test に設定
    • mainSteps セクションには、Lambda を実行する処理 (name: lambda1) を書いています。
      • aws:invokeLambdaFunction アクション(action)に、実行種別(InvocationType) と 関数名 (FunctionName) を入力 (inputs) しています。
      • aws:invokeLambdaFunction アクションの詳細は以下ドキュメントを見てください。

実行してみます。

実行画面 その2 です。

実行できました。
結果は Success になっています。

Step ID をクリックし、詳細を確認してみると以下のようになっています。
Payload 内の statusCode は 500、Lambda の StatusCode は 200 になっています。

Boto3 の Lambda に関するドキュメントを見ると、Lambda の StatusCode は Lambda を実行できない場合に、200 ではない値になるようです。
IAM 権限の不足で Lambda を実行できない場合や、クォータに抵触した、などです。
実行した Lambda のコード内で、200 じゃない statusCode を返して( return して )も、Automation はエラーになりません。

The status code in the API response doesn't reflect function errors. Error codes are reserved for errors that prevent your function from executing, such as permissions errors, quota errors, or issues with your function's code and configuration.
引用元: https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/lambda.html#Lambda.Client.invoke

Lambda 関数 (test) のコード内で、エラーがある場合に、捕捉して終了する。

Lambda の コード内にある return を throw に書き換えます。

export const handler = async(event) => {
    function sleep(waitSec) {
        return new Promise(function (resolve) {
            setTimeout(function() { resolve() }, waitSec);
        });
    } 
    await sleep(5000);
    const response = {
        statusCode: 500,
        body: JSON.stringify('Hello from Lambda!'),
        headers: {
            'Content-Type': 'application/json',
        }
    };
    throw new Error("error")
    //return response;
};

Lambda のコード画面です。

Lamba をテスト実行すると、Failed (失敗)になりました。

SSM Automation の Runbook を実行してみると、同様に Failed (失敗)になりました。
FunctionError に Unhandled と入っています。

SSM Automation の仕様として、Failed (失敗)になると、次のステップには行かずに止まります。成功の場合は継続して次のステップに進みます。
試しに、同じ Lambda を 2回実行する Runbook を作成し、実行してみます。

description: Invoke Lambda Functions
schemaVersion: '0.3'
parameters:
  FunctionName:
    type: String
    description: Lambda Function Name
    default: test
mainSteps:
  - name: lambda1
    action: 'aws:invokeLambdaFunction'
    inputs:
      InvocationType: RequestResponse
      FunctionName: '{{FunctionName}}'
  - name: lambda2
    action: 'aws:invokeLambdaFunction'
    inputs:
      InvocationType: RequestResponse
      FunctionName: '{{FunctionName}}'

作成した Runbook です。

実行結果です。
Failed (失敗)になると、次のステップには行かずに止まります。

Lambda 関数 (test) のコード内で、エラーがある場合に、処理を継続する。

Lambda 関数 (test) のコード内で、エラーがある場合に、処理を継続させてみます。
以下のような処理を作ります。

  1. Lambda 関数 (test) を実行 (name: lambda1)
  2. 失敗した場合 (onFailure) には、Lambda 関数 (test2) を実行 (name: lambda2)

以下の yaml になります。

description: Invoke Lambda Functions
schemaVersion: '0.3'
parameters:
  FunctionName1:
    type: String
    description: Lambda Function Name 1
    default: test
  FunctionName2:
    type: String
    description: Lambda Function Name 2
    default: test2
mainSteps:
  - name: lambda1
    action: 'aws:invokeLambdaFunction'
    inputs:
      InvocationType: RequestResponse
      FunctionName: '{{FunctionName1}}'
    onFailure: 'step:lambda2'
  - name: lambda2
    action: 'aws:invokeLambdaFunction'
    inputs:
      InvocationType: RequestResponse
      FunctionName: '{{FunctionName2}}'

上の yaml は、onFailure: 'Continue' (処理継続)としても、同じ結果になります。

作成した Runbook です。

実行結果です。
後続の lambda2 を実行できています。全体のステータスは Failed になっています。

Lambda 関数 (test) のコード内で、エラーがある場合に、処理を分岐する。

aws:branch アクションを使って、前のステップの結果に応じた処理をすることもできます。

  1. Lambda 関数 (test) を実行 (name: lambda1)
  2. 分岐処理 (name: ResultCheck1) 。
    • lambda1 の結果 (Output) にエラー ( FunctionError ) がない ( null である ) 場合に、3秒待機する処理 ( name: Sleep ) に飛ぶ。
      • そのほかの場合には、Lambda 関数 (test) を実行 (name: lambda2) する。lambda2 が正常終了すると、3秒待機する処理 ( Sleep ) をする 。
  3. Sleep のステップ には isEnd: true があるため、後続にステップがあっても無視する。
description: Invoke Lambda Functions
schemaVersion: '0.3'
parameters:
  FunctionName:
    type: String
    description: Lambda Function Name
    default: test
mainSteps:
  - name: lambda1
    action: 'aws:invokeLambdaFunction'
    inputs:
      InvocationType: RequestResponse
      FunctionName: '{{FunctionName}}'
  - name: ResultCheck1
    action: 'aws:branch'
    inputs:
      Choices:
        - NextStep: Sleep
          Variable: '{{lambda1.FunctionError}}'
          StringEquals: 'null'
      Default: lambda2
  - name: lambda2
    action: 'aws:invokeLambdaFunction'
    inputs:
      InvocationType: RequestResponse
      FunctionName: '{{FunctionName}}'
  - name: Sleep
    action: 'aws:sleep'
    inputs:
      Duration: PT3S
    isEnd: true

まとめ

SSM Automation の Runbook で Lambda を実行してみました。
使用を把握できさえすれば、エラー時の処理継続や処理分岐もできます。
Step Functions のように、グラフィカルなユーザーインターフェイスではないため、小規模な単位の処理に向いていそうです。

リンク集

SSM Automation の概要に関しては、以下のドキュメントを参照しています。
AWS Systems Manager Automation

aws:invokeLambdaFunction

ランブックでの条件文の使用

余談

夏山が恋しいです。

山本 哲也 (記事一覧)

カスタマーサクセス部のエンジニア(一応)

好きなサービス:ECS、ALB

趣味:トレラン、登山(たまに)