AWS CLIがAWS::Include transformをS3へアップロードできるようになりました

はじめに

こんにちは、knakayamaです。

このポストでは、AWS CLIのバージョン1.16.36で導入された新機能をご紹介したいと思います。実際のところとても小さな機能追加です。ただし、私のように毎日の開発の中でAWS SAMを使っているなら、きっと少しだけ幸せにしてくれると思います。

Swagger in AWS SAM

もしAmazon API GatewayをプロビジョニングするためにAWS SAMでSwaggerを使っているなら、AWS::Serverless::Apiリソースを利用しているでしょう。このリソースの中でSwaggerファイルを指定する方法は2つあります。

  1. DefinitionUri プロパティを使ってS3バケット内のSwaggerファイルを指定する
  2. DefinitionBody プロパティを使ってAWS SAMテンプレート内にインラインSwaggerを記述する

私はよく2つ目の方法を選びます。なぜなら、もし DefinitionUri プロパティをSwaggerファイルと共に使った場合、AWS SAMはそのファイルを単なるSwaggerファイルとして扱ってしまうため、Intrinsic FunctionsPseudo ParametersがSwaggerの中で使えなくなってしまうからです。そういった仕様はSwaggerの中にないからですね。例えば、Swaggerの中の Fn::Sub 関数で AWS::AccountIdRef パラメータを参照できないため統合リクエストとして指定されたAWS LambdaのARNをハードコーディングする必要があります。この場合、もしAWSアカウントを複数の環境(本番、ステージング、その他)で分割していると、各環境毎にたくさんのSwaggerファイルが必要になるでしょう。面倒ですね。こういった理由から、1番目より2番目の方法が好ましいと思っています。

ただし、AWS SAMテンプレートにインラインSwaggerを直接記述した場合、その管理がとても難しくなるでしょう。なぜならSwaggerとAWS SAMテンプレートが混ざってしまうためです。これもまた面倒ですね。この問題を防ぐために、AWS::Include transformをうまいこと利用する開発者もいます。この解決方法はAWS SAMのsample projectでも紹介されているため、もしかすると聞いたことがあるかもしれません。

使い方はとても簡単です。以下のように DefinitionBody プロパティで Fn::Transform を指定する必要があるだけです。

  ApiGatewayApi:
    Type: AWS::Serverless::Api
    Properties:
      StageName: Sample
      DefinitionBody:
        Fn::Transform:
          Name: AWS::Include
          Parameters:
            Location: s3://<path-to-s3-bucket>/swagger.yml

もし上記ファイルからスタックを作成した場合、 Location プロパティで指定されたSwaggerファイルがテンプレート内に挿入されます。つまり、SwaggerファイルとAWS SAMテンプレートを分割できるということです。

で、何が問題なの?

サンプルコードの Location プロパティをもう一度見てください。値がS3のパスになっています。つまり、テンプレートからスタックを作る前にそのS3パスへSwaggerファイルをアップロードする必要があるということです。

一般的に、AWS SAMを使う場合は以下のステップに倣うと思います。

  • aws cloudformation package コマンドを使って、デプロイメントパッケージを作成し、それをS3バケットにアップロード、変換されたAWS SAMテンプレートを生成する
  • aws cloudformation deploy コマンドでスタックを作成/更新する

もしこのステップに従っている場合、自分でS3バケットにSwaggerファイルをアップロードする必要がありました。もちろんこれを実現するのは難しいことではありません。単に aws s3 cp コマンドを使えばいいだけです。ただ、私はAWS CLIが代わりにやって欲しいなと思っていました。デプロイパイプラインに余計なステップを可能なら加えたくありません。

しかし、最近このPRがマージされたため、AWS CLIバージョン1.16.36でこのアップロード機能が導入されました。めでたい。

やってみた

この章ではこの機能をデモしてみます。執筆時点の最新AWS CLIバージョン(1.16.37)でテストしています。

$ aws --version
aws-cli/1.16.37 Python/3.6.5 Darwin/17.7.0 botocore/1.12.27

最初に、 Location プロパティを以下のように変更しました。

  ApiGatewayApi:
    Type: AWS::Serverless::Api
    Properties:
      StageName: Sample
      DefinitionBody:
        Fn::Transform:
          Name: AWS::Include
          Parameters:
            Location: src/api/swagger.yml

Location プロパティにローカルディレクトリへのパスを指定しただけです。続いて、 aws cloudformation package コマンドを実行します。

$ aws cloudformation package \
  --template-file sam.yml \
  --s3-bucket <path-to-s3-bucket> \
  --output-template-file template.yml

Uploading to 256b8dbcba1d8ad7f1d4dadda741722d  2371 / 2371.0  (100.00%)
Successfully packaged artifacts and wrote output template to file template.yml.
Execute the following command to deploy the packaged template
aws cloudformation deploy --template-file /path/to/template.yml --stack-name <YOUR STACK NAME>

予想したとおりに動いているようです。S3バケットにアップロードされたオブジェクトを見てみましょう。

$ aws s3 cp s3://<path-to-s3-bucket>/256b8dbcba1d8ad7f1d4dadda741722d - | md5
256b8dbcba1d8ad7f1d4dadda741722d
$ md5 src/api/swagger.yml
MD5 (src/api/swagger.yml) = 256b8dbcba1d8ad7f1d4dadda741722d

両ファイルに違いはありません。次は変換されたAWS SAMテンプレートを見てみます。

  ApiGateway:
    Properties:
      DefinitionBody:
        Fn::Transform:
          Name: AWS::Include
          Parameters:
            Location: s3://<path-to-s3-bucket>/256b8dbcba1d8ad7f1d4dadda741722d
      StageName: Sample
    Type: AWS::Serverless::Api

値が変わってますね。値が最初のサンプルスニペットのようにS3へのパスになっています。したがって、以前と同じようにデプロイ可能です。

$ aws cloudformation deploy \
  --template-file template.yml \
  --stack-name <your-stack-name>

Waiting for changeset to be created..
Waiting for stack create/update to complete
Successfully created/updated stack - <your-stack-name>

まとめ

いかがだったでしょうか?

このポストでは、AWS CLIの小さなアップデートをご紹介しました。私は多くの状況で便利なのではないかと思っています。このポストがお役に立てれば幸いです。