【小ネタ】 Fn::If(!If)の使いどころ

2023.07.07

アノテーション構築チームのいたくらです。
AWS CloudFormation を触り始めて、条件関数 Fn::If にお世話になることが増えました。
そんな中、これ便利かも?と思った Fn::If の使いどころについて、備忘を兼ねてまとめてみました。

Fn::If を使用するときの前提

条件関数 If の構文(YAML形式、短縮形)はこちらです。
以降、コード上は短縮形を使用します。

# 短縮形の構文
!If [condition_name, value_if_true, value_if_false]

参考:条件関数 If - AWS CloudFormation

ここで、公式ドキュメントに記載があるように、condition_name は Conditions セクションで定義した条件です。
つまり、以下のようにあらかじめ Conditions セクションで条件を定義しておく必要があります。

Parameters:
  Env:
    Type: "String"
    Default: "Prod"

Conditions:
  FlagProd:
    !Equals
      - !Ref Env
      - "Prod"

しれっと Conditions セクションで条件関数 Equals や組み込み関数 Ref が出てきていますが詳細はこちらを参照ください。
参考:条件関数 Equals - AWS CloudFormation
参考:Ref - AWS CloudFormation

上記の Condition セクションで定義している条件は、
パラメータ Env に格納された値が「Prod」の場合、FlagProd は「true」と評価される
というものです。
この記事では、
パラメータ Env はデフォルトの Prod が格納されている
(= FlagProd は true 評価)
という想定で話を進めていきます。

1.Resources の Properties で AWS::NoValue と組み合わせて Fn::If を使う

Resources の Properties とは、下記ハイライト部分を指しています。

Resources:
  DBInstance:
    Type: AWS::RDS::DBInstance
    Properties:
      MonitoringInterval: 60

(本来は色々な必須プロパティがありますが、説明に必要な部分だけピックアップしています)

上記は、
DB インスタンスに対して拡張モニタリングを有効化(0 以外の 1, 5, 10, 15, 30, 60 を指定すれば有効化)かつ、拡張モニタリングのメトリクス収集間隔を 60 秒に設定
と指定しています。

ここで、先ほど定義した条件 FlagProd を使用すると以下の条件分岐が指定できます。

Resources:
  DBInstance:
    Type: AWS::RDS::DBInstance
    Properties:
      MonitoringInterval: !If [FlagProd, 60, !Ref "AWS::NoValue"]

上記は、
FlagProd が true の場合は MonitoringInterval に 60 を設定、
false の場合は MonitoringInterval を削除する(=設定しないので拡張モニタリングは無効)
と指定しています。

AWS::NoValue は このように 条件関数 If の戻り値として指定すると、対応するリソースプロパティを削除します。
参考:擬似パラメータ参照 - AWS CloudFormation
とても便利ですね。
(ちなみに今回示した例であれば、!Ref AWS::NoValue ではなく 0 を指定しても無効にできます)

2.親スタックから子スタックに渡す Properties の Parameters で Fn::If を使う

親スタックから子スタックにパラメータを渡すときは以下のようにパラメータを渡します。
(こちらも説明に必要な部分だけピックアップしています。)

親スタックのテンプレート

  CloudWatchDB:
    Type: "AWS::CloudFormation::Stack"
    Properties:
      Parameters:
        DBInstanceId: "xxxx"
      TemplateURL: "https://zzzz/cloudwatch.yml"

上記テンプレートは、
子スタックのテンプレート(cloudwatch.yml)に対して、パラメータ(String型)DBInstanceId = xxxx を引き渡す
という内容です。

ここで自分は、
ある条件下では、子スタックでパラメータ DBInstanceId を使用しないので、先ほどの AWS::NoValue を使ってある条件下では DBInstanceId を削除する条件分岐が指定できればいいのにな~
と思い、AWS::NoValue を使用して条件分岐を作り、CloudFormation で作成を試みましたがエラーが出て失敗しました。
エラー内容はパラメータは値が必須ですというものでした。
ということで、以下のように修正しました。

親スタックのテンプレート

  CloudWatchDB:
    Type: "AWS::CloudFormation::Stack"
    Properties:
      Parameters:
        DBInstanceId: !If [FlagProd, "xxxx", ""]
      TemplateURL: "https://zzzz/cloudwatch.yml"

上記テンプレートは、
FlagProd が true の場合、DBInstanceId = xxxx を引き渡す、
false の場合、DBInstanceId = 空白文字 を引き渡す
という内容です。
パラメータ自体は削除はできませんが、意味のない文字を引き渡せるので良しとしました。

3.Resources の Properties(配列型)で Fn::If を使う

ニッチかもしれませんが、偶然遭遇したのでメモしておきます。
(こちらも説明に必要な部分だけピックアップしています。)

  BackupSelectionRds:
    Type: "AWS::Backup::BackupSelection"
    Properties: 
      BackupPlanId: xxxx
      BackupSelection: 
        SelectionName: yyyy
        IamRoleArn: zzzz
        Resources:
          - "arn:aws:rds:*:*:db:*"

上記テンプレートは、
BackupSelection で、ARN プレフィックスで対象として "arn:aws:rds:*:*:db:*" を割り当てる
という内容です。

ここで自分は、
ある条件下では Resources で "arn:aws:rds:*:*:db:*" を割り当てたいけど、それ以外では別の ARN プレフィックスを割り当てたいな~
と思いました。
この Resources は御覧の通り配列型でして、「配列型に Fn::If ってどう組み込むの・・・?」となりました。
配列だから [ ] で囲ってみるか~とやってみたら、うまくいきました。

  BackupSelectionRds:
    Type: "AWS::Backup::BackupSelection"
    Properties: 
      BackupPlanId: xxxx
      BackupSelection: 
        SelectionName: yyyy
        IamRoleArn: zzzz
        Resources:
          !If
            - FlagProd
            - ["arn:aws:rds:*:*:cluster:*"]
            - ["arn:aws:rds:*:*:db:*"]

上記テンプレートは、
FlagProd が true の場合、Resources に "arn:aws:rds:*:*:cluster:*" を格納する、
false の場合、"arn:aws:rds:*:*:db:*" を格納する
という内容です。

ちなみに複数の値を引き渡したい場合は、以下で渡せることが確認できました。

!If
  - FlagProd
  - ["xxxx", "yyyy"]
  - ["zzzz"]

さらにちなみに、値を何も渡したくない場合は、以下で実現できることが確認できました。

!If
  - FlagProd
  - ["xxxx"]
  - []

あとがき

Fn::If が好きになりました。
Fn::If で困っている方の助けになれたら幸いです。
新たな使いどころを見つけたらまた記事にしようと思います。

アノテーション株式会社について

アノテーション株式会社は、クラスメソッド社のグループ企業として「オペレーション・エクセレンス」を担える企業を目指してチャレンジを続けています。
「らしく働く、らしく生きる」のスローガンを掲げ、様々な背景をもつ多様なメンバーが自由度の高い働き方を通してお客様へサービスを提供し続けてきました。
現在当社では一緒に会社を盛り上げていただけるメンバーを募集中です。少しでもご興味あれば、アノテーション株式会社WEBサイトをご覧ください。