Serverless Frameworkでresourcesの分岐

やったこと

Serverless Frameworkで条件ごとにbuildするリソースの分岐をしようと、
いくつか試したので記録として残しておきます

先にまとめ

  • resource:に入れ子構造で- $file{xxxx}を設定できない
  • $file{(./xxxx.yml), ''}で書けば、そのファイルが存在する場合はリソースが作られるし、ファイルが存在しない場合はリソースが作られないかつ、エラーも発生しない

改修前の状態

serverless.ymlからresourceへのpathを書いたファイルを読み込む

custom:
  ...
resources: ${file(./resources_shared.yml)}
...
- $file{(./SampleLambda/lambda.yml)}
- $file{(./SampleEventRule/rule.yml)}

これで現状問題なく動いていました

今回やりたかったこと

特定のServerlessのserviceでのみあるリソースのbuildが必要になりました
なのでserverless.ymlから複数のresourceへのpathを書いたファイルを読み込んで、環境ごとにbuildするリソースを分けることができるかな…と調査を開始したのがきっかけです

例としてここではserviceNameの値を使ってにリソースを分けるつもりで記載しておきます
「serviceNameがappleの場合のみ特定のリソースをbuildしたい」想定です

  custom:
    serviceName: ${env:SERVICE_NAME, "apple"} #apple or orange
    ..
  resources:
    - ${file(./resources_shared.yml)}
    - ${file(./resources_${self:custom.serviceName}.yml)}
  ...
# apple, orange共通で必要なリソース
- $file{(./SampleLambda/lambda.yml)}
- $file{(./SampleEventRule/rule.yml)}
# appleのみで必要なリソース
- $file{(./Resource/IAM.yml)}
- $file{(./Resource/S3.yml)}
# orangeの場合は追加でbuildしたいリソースは無い

結果

上記のようにファイル名のsufixを動的に変えて試すも、そもそもresources:を配列にする場合は、
参照先のファイルで- $file{xxxx}を記述することができなかった
つまり- $file{xxxx}を入れ子にできない

対処

1. serverless.ymlのresources:には配列ではなく単一のymlを参照させる

  custom:
    serviceName: ${env:SERVICE_NAME, "apple"} #apple or orange
    ..
  resources: ${file(./resources.yml)}

2. appleのみで必要なリソースファイルを/Resource/apple/配下に配置する

3. resources.yml内で下記のように書く

# apple, orange共通で必要なリソース
- $file{(./SampleLambda/lambda.yml)}
- $file{(./SampleEventRule/rule.yml)}
# appleのみで必要なリソース
- $file{(./Resource/${self:custom.serviceName}/IAM.yml), ''}
- $file{(./Resource/${self:custom.serviceName}/S3.yml), ''}
ポイントは$file{(./xxxx.yml), ”}

この記法であればファイルが存在しない場合は、''が読み込まれ、
その結果何もリソースが作られない & エラーも発生しない

まとめ

分岐をするためのプラグインServerless Plugin IfElse もありますが、
後々repository内に分岐箇所が増殖していくことを避けたかったので、記法とフォルダ構成に頼りました
とはいえ力技でねじ伏せた感は残りますが…