Lambda関数URL(Function URLs)をCloud Automatorの後処理に設定してEC2停止後にインスタンスを終了する

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

こんにちは。Cloud Automatorの開発・運用をしている尾崎です。

先日発表されたLambda Function URLsは個人的に待望の機能でした。従来LambdaをHTTP(s)で呼び出す際に必要だったAPI Gatewayを不要にできる点にメリットを感じています。

今回はこのLambda Function URLsをCloud AutomatorのWebhook後処理に設定して、Cloud Automatorのジョブで「EC2: インスタンスを停止」した後にLambdaからEC2インスタンスの終了をしてみようと思います。
なお、記事の内容は2022/04/20現在のもので、設定値や設定方法に関しては変わる可能性があります。また、Lambdaに登録するコードに関しても動作保証はしませんので、あらかじめご了承ください。

Cloud AutomatorのWebhook後処理について

Cloud AutomatorのWebhook後処理についてのドキュメントは「Webhook後処理」にまとまっています。
記事中にある「POSTリクエストの内容」を参考にして、Lambda関数では以下のような流れで処理を行います。

  1. 設定しているジョブのWebhook後処理のリクエストかどうかを検証。
  2. Cloud Automatorのログに紐づくリソース操作結果取得APIを利用して、停止したEC2インスタンスIDを取得。
  3. AWSのterminate-instancesを利用して、EC2インスタンスを終了。

次のセクションで実際のコード例を記載します。

Lambda Functionのコード例

const https = require("https");
const util = require("util");

const AWS = require("aws-sdk");

// HTTPSリクエストを行う関数
async function request(url, options, data) {
  return new Promise((resolve, reject) => {
    const req = https.request(url, options, (res) => {
      let body = "";
      res.on("data", (chunk) => (body += chunk.toString()));
      res.on("error", reject);
      res.on("end", () => {
        if (res.statusCode >= 200 && res.statusCode <= 299) {
          resolve({
            statusCode: res.statusCode,
            headers: res.headers,
            body: body,
          });
        } else {
          reject(
            "Request failed. status: " + res.statusCode + ", body: " + body,
          );
        }
      });
    });
    req.on("error", reject);
    if (data != null) {
      req.write(data, "binary");
    }
    req.end();
  });
}

// Lambdaのハンドラー
exports.handler = async (event) => {
  // see: https://support.serverworks.co.jp/hc/ja/articles/115002386953-Webhook後処理
  const webhookPayload = JSON.parse(event.body);
  const result = webhookPayload[0];

  // 1. 設定しているジョブのWebhook後処理のリクエストかどうかを検証する
  // ここではジョブID: 10000を対象としています
  if (result.trigger_job_id !== 10000) {
    return {
      statusCode: 404, // Not Found
      body: JSON.stringify({
        result: false,
      }),
    };
  }

  // 2. 停止したEC2インスタンスIDを取得する
  // see: https://api.cloudautomator.com/#ジョブログ-get-2
  const resourceOperationResultsURL = `https://manager.cloudautomator.com/api/v1/logs/${result.trigger_job_log_id}/resource_operation_results`;
  const resultsResp = await request(resourceOperationResultsURL, {
    method: "GET",
    headers: {
      // 「APIキー」はCloud Automatorのアカウント設定画面から確認できます
      Authorization: "Bearer 「APIキー」",
    },
  });
  const instanceIds = JSON.parse(resultsResp.body)
    .data.map((result) => result.attributes.affected_resource_id)
    .filter((rs) => rs != null);

  // 停止インスタンスが0台の場合はterminateInstancesを実行しない
  if (instanceIds.length === 0) {
    return {
      statusCode: 200, // default value
      body: JSON.stringify({
        result: true,
      }),
    };
  }

  // 3. EC2インスタンスを終了する
  // see: https://docs.aws.amazon.com/AWSJavaScriptSDK/latest/AWS/EC2.html#terminateInstances-property
  // ここではap-northeast-1を指定
  const ec2 = new AWS.EC2({
    apiVersion: "2016-11-15",
    region: "ap-northeast-1",
  });
  await util.promisify(ec2.terminateInstances).bind(ec2)({
    InstanceIds: instanceIds,
  });
  return {
    statusCode: 200, // default value
    body: JSON.stringify({
      result: true,
    }),
  };
};

Lambda関数をCloud Automatorの後処理に設定する

Lambda Functionで関数 URLを設定する方法は公式ドキュメントを参照ください。
その際、認証タイプを NONE で設定する必要があります。
また、上記サンプルコードは実行時間がデフォルトの3秒を超える場合があるので、余裕を持ってLambda関数のタイムアウトを10秒程度に設定しました。

その後、生成された関数URLをCloud Automatorの後処理に登録します。

後処理登録後、今回の例ではジョブが成功した場合にのみインスタンスの終了をするので、ジョブの設定画面で成功時の後処理にLambda関数を実行するように設定します。

動作確認

動作確認はジョブを実行するだけです。タイマートリガーやスケジュールトリガーは実行予定時間を待たずに「今すぐ実行」できますし、手動トリガーを利用することで簡単に動作確認ができます。

まとめ

  • Lambda関数URLの機能によってCloud Automatorの後処理から直接Lambda関数を実行できるようになりました
  • Cloud Automatorのジョブ処理結果に応じて任意の処理をLambdaで行う際のサンプルコードを紹介しました
  • Lambda関数URLをCloud Automatorの後処理に設定する方法を紹介しました

Lambda Functionのコードを書く必要がありますが、Cloud Automatorで提供されていないアクションや少し挙動をカスタマイズしたい場合には便利です。

なお、今回紹介した設定には以下のような注意点があります。

  • Webhook後処理のステータスコードは200以外を返すとCloud Automator上では後処理が「失敗」扱いとなります。
  • Webhook後処理で実行するLambda処理でエラーが発生しても、Cloud Automatorの失敗時の後処理は実行されません。
  • 成功時の後処理に、メール通知など別の後処理も登録されている場合は、Lambdaの実行を待たずに後処理実行されます。

最後になりますが、Cloud Automatorでは開発ロードマップを公開しているのでぜひご覧ください!

https://cloudautomator.com/roadmap/

また、機能リクエストや要望はアイデア投稿ページから随時投稿を受け付けています。 いただいた投稿は全て開発チームで確認して、今後の開発計画策定に活用させていただいているので、ご要望お待ちしております!