メンチカツには醤油でしょ!!

AWS/Java/Node.js/Spreadsheets/Docker/Jenkins/コミュニティ・勉強会レポを主とした技術系ブログ

AWS CLIを使ってLambdaのリリースを自動化しよう

CLIで下記を実行

aws s3 cp ./build/index.zip s3://YOUR-S3-BUCKET-HERE/index.zip

aws lambda update-function-code --function-name YOUR-LAMBDA-FUNCTION-NAME --s3-bucket YOUR-S3-BUCKET-HERE --s3-key index.zip --publish

Jenkinsの場合はそのマシンにAWS CLIを入れるのと、プロファイルの設定を忘れずに。
CLIの末尾に--profile your-profile-nameを付ければ良いですね。

参考

update-function-code — AWS CLI 1.14.44 Command Reference

--s3-keyってのがわかりにくいですが、パスを指します。

(※ 厳密にはS3にはパスの概念はないのでkeyとなっています)

 

AWS LambdaでCannot find module (Windowsからgulp-zipでupload)

そもそものよくある問題は次の参考サイトへ

qiita.com

lealog.hateblo.jp

Windowsでのgulp-zipが問題?

Windowsでgulp-zipをした際に、Cannot find moduleが出ます。
シンプルにモジュール1つで試してみましたが、ダメでした。

github.com

コンソールからテスト

{
  "errorMessage": "Cannot find module 'moment'",
  "errorType": "Error",
  "stackTrace": [
    "Function.Module._load (module.js:417:25)",
    "Module.require (module.js:497:17)",
    "require (internal/module.js:20:19)",
    "Object. (/var/task/index.js:2:16)",
    "Module._compile (module.js:570:32)",
    "Object.Module._extensions..js (module.js:579:10)",
    "Module.load (module.js:487:32)",
    "tryModuleLoad (module.js:446:12)",
    "Function.Module._load (module.js:438:3)"
  ]
}

テスト実行時のCloudWatchのログは

Unable to import module 'index': Error
at Function.Module._load (module.js:417:25)
at Module.require (module.js:497:17)
at require (internal/module.js:20:19)
at Object. (/var/task/index.js:2:16)
at Module._compile (module.js:570:32)
at Object.Module._extensions..js (module.js:579:10)
at Module.load (module.js:487:32)
at tryModuleLoad (module.js:446:12)
at Function.Module._load (module.js:438:3)

indexなのかrequireのmoduleなのか。

だいたいがhandler名の問題だが…

// hello.js
exports.world = (event, context, callback) => {
  //
}

だとhello.worldで呼ぶべき、ともありますが、今回そんな感じではなさそう。
上記にも引用した AWSのLambdaで、zipにしたコードを動かす時にハマったこと - console.lealog(); に従って、WindowsのGit Bashで chmod +x index.js してみたが、うまくいかない。

Macだとうまくいくんだけど…う〜ん。。

ん、もしや…!?

WindowsだとダメでMacだとうまくいく

Windowsでnpm run make

zipアップ⇒だめ。
S3アップ⇒だめ。

Macでnpm run make

zipアップ⇒とおる。

 

gulp-zip ぁゃしぃ。。。

 

stackoverflow.com

.pipe(zip('simple-lambda.zip', { compress: false })) を試す。
⇒変わらずエラー

7-Zip(圧縮・解凍ソフト 7-Zip)で圧縮
⇒成功

ますます gulp-zip ぁゃしぃ。。。

これで解決

stackoverflow.com

gulp
    .src(['src/**'], { nodir: true, dot: true })
    .pipe(zip('simple-lambda.zip'))
    .pipe(gulp.dest('build/'));

nodirとdotの指定が必要でした。

HTTP Request Headerが正しく(?)送信されなかった問題

先頭の方は当初の記事で、訂正は後半に書きました。

そもそもリクエストヘッダーは大文字小文字を気にしないと、RFC 2616に書いてありますので、ロジック側で両方取れるように工夫すべきでした。

正しく送信されないのは小文字になってしまうから (訂正前)

X-My-Apps-Tokenx-my-apps-tokenになり、
API Gatewayのカスタムオーソライザー設定でのチェックは通過するが、
Lambdaのカスタムオーソライザーで下記のようなコードでトークンを取得しようとした際にうまく取得できません。

const myAppsToken = event.headers['X-My-Apps-Token'];

なお、API Gatewayのカスタムオーソライザーの設定では、
Lambda イベントペイロードにリクエストを設定していました。

アプリ版のPostmanを使用すると…

環境にもよると思います。

Windows + Chrome Postman : NG
Mac + Chrome Postman : ?
Windows + Postman Apps : OK
Mac + Postman Apps : OK

Chrome AppsのPostmanは既に非推奨なので、アップデートしましょう。 

Postmanだけでなくクライアントの仕様に依存

WindowsのGit Bashcurlしても同じ問題が発生しました。
あとで確認したら、Macのターミナルでも小文字で送信されてきました。。

デバッグ大事

Lambdaの先頭でconsole.log(event);してCloudWatchを見ましょう。

■ ここからが訂正版です ■

そもそも今回の原因が、API GatewayのカスタムオーソライザーからLambdaを呼び出す流れだったのですが、Lambdaの中で、

const myAppsToken = event.headers['X-My-Apps-Token'];

と書いていて取れないのが原因でした。大文字小文字を気にしないので

const myAppsToken = event.headers['x-my-apps-token'];

でも取れるべきです。
ここの記述をどうするのかベストなのかは、色々ありそうですが、
設計で小文字に寄せておけば丸められても問題なさそうです。

そもそも、カスタムオーソライザーの設定で、Lambdaイベントペイロードを、
トークンではなくリクエスで設定していたため、このような実装をしなければなりませんでしたが、トークン以外に拾うものがないため設定を戻しました。

リクエストではなくトークで設定した場合のLambdaの実装は

const token = event.authorizationToken;

となります。

当初はRequest Bodyの内容まで取ってトークンとbodyの内容の整合まで検証することを期待していたのでこういう設定にしていましたが、結局Request Bodyは取れないことが判ったので、むしろLambdaイベントペイロードにリクエストを設定するケースって何だろう…とも思います。

参考

stackoverflow.com