本文へスキップ

dynamicブロック

リソースのようなトップレベルのブロック構造内では、通常、式は`name = expression`形式を使用して引数に値を代入する場合にのみ使用できます。これにより多くの用途がカバーされますが、一部のリソースタイプでは、通常は包含オブジェクトに関連付けられている(または埋め込まれている)個別のオブジェクトを表す、繰り返し可能なネストされたブロックが引数に含まれています。

コードブロック
resource "aws_elastic_beanstalk_environment" "tfenvtest" {
name = "tf-test-name" # can use expressions here

setting {
# but the "setting" block is always a literal block
}
}

resourcedataproviderprovisionerブロック内でサポートされている特別なdynamicブロックタイプを使用して、settingのような繰り返し可能なネストされたブロックを動的に構築できます。

コードブロック
resource "aws_elastic_beanstalk_environment" "tfenvtest" {
name = "tf-test-name"
application = "${aws_elastic_beanstalk_application.tftest.name}"
solution_stack_name = "64bit Amazon Linux 2018.03 v2.11.4 running Go 1.12.6"

dynamic "setting" {
for_each = var.settings
content {
namespace = setting.value["namespace"]
name = setting.value["name"]
value = setting.value["value"]
}
}
}

dynamicブロックは、forと非常によく似ていますが、複雑な型付けされた値ではなく、ネストされたブロックを生成します。指定された複雑な値を反復処理し、その複雑な値の各要素に対してネストされたブロックを生成します。

  • 動的ブロックのラベル(上記の例では"setting")は、生成するネストされたブロックの種類を指定します。
  • for_each引数は、反復処理する複雑な値を提供します。
  • iterator引数(オプション)は、複雑な値の現在の要素を表す一時変数の名前を設定します。省略した場合、変数の名前はdynamicブロックのラベル(上記の例では"setting")にデフォルト設定されます。
  • labels引数(オプション)は、生成された各ブロックに使用するブロックラベルを順に指定する文字列のリストです。この値には、一時的な反復子変数を使用できます。
  • ネストされたcontentブロックは、生成された各ブロックの本体を定義します。このブロック内では、一時的な反復子変数を使用できます。

for_each引数は任意のコレクションまたは構造化された値を受け入れるため、for式またはスプラット式を使用して既存のコレクションを変換できます。

反復子オブジェクト(上記の例ではsetting)には2つの属性があります。

  • keyは、現在の要素のマップキーまたはリスト要素のインデックスです。for_each式がセット値を生成する場合、keyvalueと同一であり、使用しないでください。
  • valueは、現在の要素の値です。

dynamicブロックは、構成されているリソースタイプ、データソース、プロバイダ、またはプロビジョナに属する引数のみを生成できます。OpenTofuは式を評価する前にこれらの処理を行う必要があるため、lifecycleprovisionerブロックなどのメタ引数ブロックを生成することはできません。

for_each値は、目的のネストされたブロックごとに1つの要素を持つコレクションである必要があります。ネストされたデータ構造または複数のデータ構造からの要素の組み合わせに基づいてリソースインスタンスを宣言する必要がある場合は、OpenTofuの式と関数を使用して適切な値を導き出すことができます。このような状況の一般的な例については、flatten関数とsetproduct関数をご覧ください。

複数レベルのネストされたブロック構造

一部のプロバイダは、互いにネストされた複数のレベルのブロックを含むリソースタイプを定義しています。必要に応じて、他のdynamicブロックのcontent部分にdynamicブロックをネストすることで、これらのネストされた構造を動的に生成できます。

たとえば、モジュールは次のようないくつかの複雑なデータ構造を受け入れる場合があります。

コードブロック
variable "load_balancer_origin_groups" {
type = map(object({
origins = set(object({
hostname = string
}))
}))
}

各オリジングループのブロック、およびグループ内の各オリジンにネストされたブロックを期待するリソースタイプを定義する場合、次のネストされたdynamicブロックを使用してOpenTofuに動的に生成させることができます。

コードブロック
  dynamic "origin_group" {
for_each = var.load_balancer_origin_groups
content {
name = origin_group.key

dynamic "origin" {
for_each = origin_group.value.origins
content {
hostname = origin.value.hostname
}
}
}
}

ネストされたdynamicブロックを使用する場合は、各ブロックのイテレータ記号に特に注意することが重要です。上記の例では、origin_group.valueは外部ブロックの現在の要素を参照し、origin.valueは内部ブロックの現在の要素を参照します。

特定のリソースタイプが、親のいずれかと同じタイプ名を有するネストされたブロックを定義している場合、各dynamicブロックのiterator引数を使用して、区別しやすい異なるイテレータ記号を選択できます。

dynamicブロックのベストプラクティス

dynamicブロックの使いすぎは、設定の可読性と保守性を低下させる可能性があるため、再利用可能なモジュールのためにクリーンなユーザーインターフェースを構築するために詳細を隠す必要がある場合にのみ使用することをお勧めします。可能な限り、常にネストされたブロックを文字どおりに記述してください。

resourceブロックのほとんどまたはすべて引数とネストされたブロックを入力変数の直接対応する属性を使用して定義している場合、モジュールが役に立つ抽象化を作成していないことを示唆している可能性があります。呼び出し元モジュールがリソース自体を定義して、その情報を入力モジュールに渡す方が良い場合があります。この設計上のトレードオフの詳細については、モジュールを作成するタイミングモジュールの構成を参照してください。