Lambda Function URLs に爆速で対応した Serverless Framework のコード差分を眺めてみる
目的は Serverless Framework の内部実装を読んで理解を深めること。
もうちょっと言うと自分が身近に利用している OSS に commit できるようになりたいので、まずはコードリーディングから始めたい、漠然と眺めるにはコードベースが大きすぎるため目的がハッキリしているかつ自分にも理解できるトピック・規模の Pull Request を読み、変更箇所の感覚を持つ
元ネタとなる Pull Request はこちら。
serverless/serverless - pull/10936
CloudFormation の仕様はこちら。
コードベースは v3.12.0 を使用。
sls のディレクトリ構造はこんな感じ
$ tree -d -L 3 -I docs -I scripts -I test
.
├── bin
├── commands
└── lib
├── aws
├── classes
│ └── config-schema-handler
├── cli
│ ├── commands-schema
│ │ └── common-options
│ ├── interactive-setup
│ └── render-help
├── commands
├── configuration
│ └── variables
│ └── sources
├── plugins
│ ├── aws
│ │ ├── common
│ │ ├── custom-resources
│ │ ├── deploy
│ │ ├── info
│ │ ├── invoke-local
│ │ ├── lib
│ │ ├── package
│ │ ├── remove
│ │ └── utils
│ ├── create
│ ├── package
│ │ └── lib
│ └── plugin
│ └── lib
├── templates
│ └── recommended-list
└── utils
├── fs
├── npm-package
└── telemetry
files を見ていくと、差分が出ているコード(テスト除く)は案外少ない
- lib/plugins/aws/info/display.js
- lib/plugins/aws/pacakge/compile/functions.js
- lib/plugins/aws/info/get-stack-info.js
- lib/plugins/aws/lib/naming.js
- lib/plugins/aws/provider.js
- lib/utils/telemetry/generate-payload.js
lib/utils/telemetry/*
はおそらく Serverless Framework がサービス提供してる "Monitoring" 関係の機能。
↑ここで外部のエンドポイントにリクエストを投げており、投げる先の URL である telemetryUrl
は @serverless/utils で sls がマネージしているっぽいものが定義されている
ということなので、 sls がホストしているテレメトリ系の機能にデータを送信できるという感じ。
(私自身は普段 serverless のツールしか使わないので、あんまり関係がない...。実際に改修する立場になれば考慮する必要がありそうな場所だが、今回読みたい場所からすると本質的な場所じゃないのでスルーしていく)
lib/plugins/aws/*
を見ていく
...が、その前に大枠を把握したいので sls の構文と cfn の対応を見ておく
serverless.yml の $.functions.*
の下がこんな感じ
url:
authorizer: 'aws_iam' # Authorizer used for calls to Lambda URL
cors: # CORS configuration for Lambda URL, can also be defined as `true` with default CORS configuration
allowedOrigins:
- *
allowedHeaders:
- Authorization
allowedMethods:
- GET
allowCredentials: true
exposedResponseHeaders:
- SomeHeader
maxAge: 3600
対して CloudFormation の AWS::Lambda::Url
は
Type: AWS::Lambda::Url
Properties:
AuthType: String
Cors:
Cors
Qualifier: String
TargetFunctionArn: String
Qualifier
以外のプロパティは素直にマップしている感じがある。必要な仕事は package (あるいは deploy) 時に行われる CFn 生成時のデータ変換の仕事だけ考えればよい、と理解して良さそう
plugin/aws/provider.js
基本的には AWS Provider に関する実装
例えば yaml の $.provider
以下の仕様を規定したり、AWS Provider としての機能(AWS Provider 適用下での $.functions
以下で使える構文とか?他は思いつかない)を宣言したり、といったことをしているように見える
PR では url
に対応するスキーマを追加している。
initiallize() hook の中で ConfigSchemaHandler とかいうよくわからんやつに対して AWS Provider が持つべきスキーマを宣言している感じ。
ConfigSchemaHandler.defineProvider() に渡している第二引数 (option) の中身は、 $.definitions 以外は yaml の中で使えるデータ構造を規定しているように見える。
今回追加されているのは $.function.url なので、yaml の functions の下で使えるプロパティをここで定義した、という見方で良さそう。このメソッドを持つクラスも "ConfigSchemaHandler" なので、 yaml のスキーマを定義するクラスと見ていいのではないか。
まとめると、
AWS Provider を使う上で、yaml 上で使える構文を拡張したかったら lib/plugins/aws/provider.js の configSchemaHandler.defineProvider() の中身を拡張仕様に準拠するように書き換えることが必要。
lib/plugins/aws/package/compile/function.js
この中で lib/plugins/aws/lib/naming.js の差分も使っているので一緒に取り上げる。
naming の差分を見ると getLambdaFunctionUrlLogicalId
という機能が追加されており、これは CFn の AWS::Lambda::Url
の CFn 上の論理リソースID に変換する役目のように見受けられる。横の関数を見ていても基本は AWS Provider において、 sls が用意する CFn 論理リソースID の導出のためのモジュールであることがわかる。ここで言えることは、
lib/plugins/aws/lib/naming.js は CFn 定義に変換する際の論理リソースID となる名前を自動計算するモジュールである ということ。なので、sls の方でよしなに CFn リソース定義を吐き出してくれる機能を作ろうと思ったらここを見ればよい。
functions.js を見ていく
ここでは Compile の仕事をしているらしい(パッケージ階層的にも)。class AwsCompileFunctions のメソッドに compileFunctionUrl を追加しているほか、compileFunction にこのメソッドの呼び出しを追加している。
yaml 的には functions の下で書かれた定義であり、これを CFn 対応の構造に展開する作業が compile である。よって、functions における本質的な仕事+差分はこうなる。
- yaml 定義に書かれた function の定義から CFn 準拠のデータ構造を生成すること
- Lambda Function の compile 処理を URL に対応させること