CloudFormationテンプレート書いてますか?
今回は、使いどころが狭いもののテンプレートの保守性向上に効果バツグンのFn::ToJsonString
関数を紹介します。
CloudFormationの関数
CloudFormationには、テンプレートに柔軟性を持たせるためのいろいろな組み込み関数が用意されています。特に使いどころが多い以下の関数については、使ったことがあるという方も多いと思います。
ところで、Fn::ToJsonString
ってご存知でしょうか?
本稿執筆(2022年10月)時点では日本語ドキュメントには掲載されておらず、英語版に切り替えると存在が確認できます。
Fn::ToJsonString
とは
Fn::ToJsonString
とは、端的に言うと「JSONオブジェクトを文字列化してくれる組み込み関数」です。
公式ドキュメントはこちら。標準的な関数とは位置づけが異なり、拡張機能を有効にすることで使えるようになります。
ドキュメントの記述を引用すると、こういった使い方に対して、
1 2 3 4 5 6 7 8 9 10 11 12 | { //... "Transform": "AWS::LanguageExtensions" //... "Fn::ToJsonString": { "key1": "value1", "key2": { "Ref": "ParameterName" } } //... } |
関数の処理結果として下記の出力を返してくれます。
1 | "{\"key1\":\"value1\"},{\"key2\":\"resolvedValue\"}" |
どこで使うの?
自分は、CloudFormationのテンプレートを書くときは基本的にJSONで記述します。もちろん、Lambda関数コードなど埋め込みが難しいケースがありますので、あくまで「基本的には」です。
ただ、指定する値の型がJSON書式であるにもかかわらず、パラメータとしては文字列で与えるというところが存在します。テンプレートをJSONで記述していると、こういったパラメータについてはJSON形式で値を作った後に文字列に変換する必要が出てきます。つまりダブルクォートのエスケープ処理が発生します。短い文字列ならまだしも、埋め込みたいJSON書式の文字列が長くなってくると手間ですし、修正する気も起きなくなりますね。そんな時にFn::ToJsonString
を使うと記述がすっきりします。
こんなところで使うと便利です。
(他にも使いどころあるよ、という情報をお持ちの方、ぜひご連絡ください!)
AWS::CloudWatch::Dashboard
リソースのDashboardBody
プロパティ
どうやって使うの?
残念ながら、そのままでは使えません。
先述の関数のドキュメントの冒頭に以下のようなことが書いてあります。
Important:
You must use the AWS::LanguageExtensions transform to use the Fn::ToJsonString intrinsic function.
注意書き通り、まずはTransform
セクションで拡張機能を使用することを宣言しましょう。
すでにTransformセクションがある場合はString型からArray型に直したうえで列記する書式になります。
(JSON派なのでサンプルは原則JSONで貫きます)
1 | "Transform": "AWS::LanguageExtensions" |
そのうえで、ToJsonString
の効果を適用したい場所で利用します。
今回はAWS公式ドキュメントにあるサンプルテンプレートを、Fn::ToJsonString
を使用した形式に変換してみました。
こちらがToJsonString
を使って記述したテンプレートです。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 | { "AWSTemplateFormatVersion": "2010-09-09", "Transform": "AWS::LanguageExtensions", "Resources": { "Dashboard": { "Type": "AWS::CloudWatch::Dashboard", "Properties": { "DashboardName": "Sample", "DashboardBody": { "Fn::ToJsonString": { "widgets": [ { "type": "metric", "x": 0, "y": 0, "width": 12, "height": 6, "properties": { "metrics": [ [ "AWS/EC2", "CPUUtilization" ] ], "period": 300, "stat": "Average", "region": "ap-northeast-1", "title": "EC2 Instance CPU" } }, { "type": "text", "x": 0, "y": 7, "width": 3, "height": 3, "properties": { "markdown": "Hello world" } } ] } } } } } } |
比較用に、ToJsonString
を使わずに書いたものも掲載しておきます。つまりサンプルそのまんまですね。
1 2 3 4 5 6 7 8 9 10 11 12 | { "AWSTemplateFormatVersion": "2010-09-09", "Resources": { "Dashboard": { "Type": "AWS::CloudWatch::Dashboard", "Properties": { "DashboardName": "Sample", "DashboardBody": "{\"widgets\":[{\"type\":\"metric\",\"x\":0,\"y\":0,\"width\":12,\"height\":6,\"properties\":{\"metrics\":[[\"AWS/EC2\",\"CPUUtilization\"]],\"period\":300,\"stat\":\"Average\",\"region\":\"ap-northeast-1\",\"title\":\"EC2 Instance CPU\"}},{\"type\":\"text\",\"x\":0,\"y\":7,\"width\":3,\"height\":3,\"properties\":{\"markdown\":\"Hello world\"}}]}" } } } } |
分かりやすさで言えば圧倒的に前者ではないでしょうか。分かりやすいということは保守性の向上にもつながりますので、AWSが提唱する「小さい更新を高頻度で」のスタイルにもマッチします。
代償
もちろん、注意しなければならないこともついて回ります。公式ドキュメントにも記載があります。
更新時に「以前のテンプレートを使用」が使えない
CloudFormation側から見た場合、パラメータと条件以外の要素でリソースが変化するため、コンソールにおける「以前のテンプレートを使用」やCLI等における--use-previous-template
オプションは使えません。毎回新しいテンプレートを送り込む形でスタックを更新する必要があります。
YAMLでは短縮型記法が使えない
YAMLでは!Ref
などの短縮型記法が使えますが、AWS::LangusageExtentions
の追加によって初めて使えるようになる今回のような関数は、YAMLでの短縮型記法は使えません。ちゃんとFn::ToJsonString
と書きましょう。
複数の変換機能を利用する場合の記載順序に注意
AWS::Serverless
など別の変換機能と併用する場合、AWS::LanguageExtensions
はTransform
セクション内で先に現れるように記述しましょう。
使えるのはResources
セクションのみ
Conditions
やOutputs
など他の場所では使えません。あきらめてください。
まとめ
今回は、普通にテンプレートを書いていても欲しくなりそうな機能であるFn::ToJsonString
関数の使い方を紹介しました。みなさんも便利な関数を使ってテンプレートをより柔軟に使えるように改善していきましょう。ではまた!
投稿者プロフィール
- 根っこはインフラ屋な古いおじさん。
最新の投稿
- AWS2024年11月1日【小ネタ】cfnresponseが見つからない?
- CloudFormation2024年10月23日スポットインスタンスな起動テンプレートのインスタンスサイズを可変にしたい
- AWS2023年11月14日DLQを積み重ねる
- SQS2023年10月2日1分より短いサイクルで定期的にLambdaを実行する