From be25b5c41197f4dbddca1cb301dd185de9dd527a Mon Sep 17 00:00:00 2001 From: Marius Storhaug Date: Thu, 22 Feb 2024 16:25:56 +0100 Subject: [PATCH 01/13] Initial code --- docs/content/specs/terraform/_index.md | 26 +++++++++++++++++++ .../specification/int.spec.nest.nested.tf | 4 +++ .../specification/int.spec.nest.opt.more.tf | 4 +++ .../specification/int.spec.nest.opt.one.tf | 4 +++ .../specification/int.spec.nest.req.more.tf | 4 +++ .../specification/int.spec.nest.req.one.tf | 26 +++++++++++++++++++ 6 files changed, 68 insertions(+) create mode 100644 docs/static/includes/specification/int.spec.nest.nested.tf create mode 100644 docs/static/includes/specification/int.spec.nest.opt.more.tf create mode 100644 docs/static/includes/specification/int.spec.nest.opt.one.tf create mode 100644 docs/static/includes/specification/int.spec.nest.req.more.tf create mode 100644 docs/static/includes/specification/int.spec.nest.req.one.tf diff --git a/docs/content/specs/terraform/_index.md b/docs/content/specs/terraform/_index.md index e01da2b27..8a2f89ea7 100644 --- a/docs/content/specs/terraform/_index.md +++ b/docs/content/specs/terraform/_index.md @@ -270,6 +270,32 @@ resource "azurerm_subnet" "pair" { } ``` +##### Nested blocks + +Resources nested blocks are implemented differently depending on if they are optional or required and support one or more blocks. These **SHOULD** be implemented in the following ways: + +{{< /hint >}} + +{{< tabs "nested blocks" >}} + {{< tab "Required, one" >}} + {{< include file="/static/includes/spec/int.spec.nest.req.one.tf" language="terraform" options="linenos=false" >}} + {{< /tab >}} + {{< tab "Required, one or more" >}} + {{< include file="/static/includes/spec/int.spec.nest.req.more.tf" language="terraform" options="linenos=false" >}} + {{< /tab >}} + {{< tab "Optional, one" >}} + {{< include file="/static/includes/spec/int.spec.nest.opt.one.tf" language="terraform" options="linenos=false" >}} + {{< /tab >}} + {{< tab "Optional, one or more" >}} + {{< include file="/static/includes/spec/int.spec.nest.opt.more.tf" language="terraform" options="linenos=false" >}} + {{< /tab >}} + {{< tab "Nested dynamic blocks" >}} + {{< include file="/static/includes/spec/int.spec.nest.nested.tf" language="terraform" options="linenos=false" >}} + {{< /tab >}} +{{< /tabs >}} + +{{< hint type=note >}} +
--- diff --git a/docs/static/includes/specification/int.spec.nest.nested.tf b/docs/static/includes/specification/int.spec.nest.nested.tf new file mode 100644 index 000000000..b22fdba10 --- /dev/null +++ b/docs/static/includes/specification/int.spec.nest.nested.tf @@ -0,0 +1,4 @@ +# Variable declaration + + +# Resource implementation \ No newline at end of file diff --git a/docs/static/includes/specification/int.spec.nest.opt.more.tf b/docs/static/includes/specification/int.spec.nest.opt.more.tf new file mode 100644 index 000000000..b22fdba10 --- /dev/null +++ b/docs/static/includes/specification/int.spec.nest.opt.more.tf @@ -0,0 +1,4 @@ +# Variable declaration + + +# Resource implementation \ No newline at end of file diff --git a/docs/static/includes/specification/int.spec.nest.opt.one.tf b/docs/static/includes/specification/int.spec.nest.opt.one.tf new file mode 100644 index 000000000..b22fdba10 --- /dev/null +++ b/docs/static/includes/specification/int.spec.nest.opt.one.tf @@ -0,0 +1,4 @@ +# Variable declaration + + +# Resource implementation \ No newline at end of file diff --git a/docs/static/includes/specification/int.spec.nest.req.more.tf b/docs/static/includes/specification/int.spec.nest.req.more.tf new file mode 100644 index 000000000..b22fdba10 --- /dev/null +++ b/docs/static/includes/specification/int.spec.nest.req.more.tf @@ -0,0 +1,4 @@ +# Variable declaration + + +# Resource implementation \ No newline at end of file diff --git a/docs/static/includes/specification/int.spec.nest.req.one.tf b/docs/static/includes/specification/int.spec.nest.req.one.tf new file mode 100644 index 000000000..3dd66a515 --- /dev/null +++ b/docs/static/includes/specification/int.spec.nest.req.one.tf @@ -0,0 +1,26 @@ +# The nested block is required and supports only a single instance +# Use the nested block directly without a dynamic block and looping. + +# Variable declaration +Variable "my_nested_block" { + +} + +# Resource implementation +resource "my_resource" "this" { + +} + + + +# The nested block is required and supports one or more instances +# Use a dynamic block with a `for_each` meta argument. As it requires atleast one input, the definition can be `for_each = var.loop_me` + +# The nested block is optional and supports only a single instance +# Use a dynamic block with a `for_each` meta argument. +# As its input is optional, the definision **SHOULD** be `for_each = var.loop_me != null ? { this = var.loop_me } : {}` + +# The nested block is optional and supports one or more instance +# Use a dynamic block with a `for_each` meta argument. +# As its input is optional and supports multiple, the definition **SHOULD** be `for_each = var.loop_me != null ? var.loop_me : {}`. +# Where the input parameter is a `map()` type. \ No newline at end of file From d61c7dc877f3c873e32fb788cf7ae017cc9b38c3 Mon Sep 17 00:00:00 2001 From: Marius Storhaug Date: Thu, 22 Feb 2024 17:25:36 +0100 Subject: [PATCH 02/13] update - wip --- .vscode/settings.json | 6 ++- .../specification/int.spec.nest.nested.tf | 4 +- .../specification/int.spec.nest.opt.more.tf | 26 ++++++++++++- .../specification/int.spec.nest.opt.one.tf | 26 ++++++++++++- .../specification/int.spec.nest.req.more.tf | 25 ++++++++++++- .../specification/int.spec.nest.req.one.tf | 37 +++++++++---------- 6 files changed, 96 insertions(+), 28 deletions(-) diff --git a/.vscode/settings.json b/.vscode/settings.json index 847d87020..5917b58ad 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -24,5 +24,9 @@ "VMSS", "xbcp", "xgtf" - ] + ], + ["terraform"]: { + "editor.insertSpaces": true, + "editor.indentSize": 2 + } } diff --git a/docs/static/includes/specification/int.spec.nest.nested.tf b/docs/static/includes/specification/int.spec.nest.nested.tf index b22fdba10..92d00f099 100644 --- a/docs/static/includes/specification/int.spec.nest.nested.tf +++ b/docs/static/includes/specification/int.spec.nest.nested.tf @@ -1,4 +1,6 @@ +# Nested dynamic blocks and conditions. + # Variable declaration -# Resource implementation \ No newline at end of file +# Resource implementation diff --git a/docs/static/includes/specification/int.spec.nest.opt.more.tf b/docs/static/includes/specification/int.spec.nest.opt.more.tf index b22fdba10..2f586fd17 100644 --- a/docs/static/includes/specification/int.spec.nest.opt.more.tf +++ b/docs/static/includes/specification/int.spec.nest.opt.more.tf @@ -1,4 +1,26 @@ -# Variable declaration +# The nested block is optional and supports one or more instances +# Variable declaration +variable "optional_multi_block" { + type = map(object({ + name = string + color = string + length = optional(number) + })) + default = null + ... +} -# Resource implementation \ No newline at end of file +# Resource declaration +resource "my_resource" "this" { + ... + dynamic "optional_multi_block" { + for_each = var.optional_multi_block != null ? var.optional_multi_block : {} + content { + name = var.optional_multi_block.name + color = var.optional_multi_block.color + length = var.optional_multi_block.length + } + } + ... +} diff --git a/docs/static/includes/specification/int.spec.nest.opt.one.tf b/docs/static/includes/specification/int.spec.nest.opt.one.tf index b22fdba10..9a15a6b20 100644 --- a/docs/static/includes/specification/int.spec.nest.opt.one.tf +++ b/docs/static/includes/specification/int.spec.nest.opt.one.tf @@ -1,4 +1,26 @@ -# Variable declaration +# The nested block is optional and supports a single instance +# Variable declaration +variable "optional_single_block" { + type = object({ + name = string + color = string + length = optional(number) + }) + default = null + ... +} -# Resource implementation \ No newline at end of file +# Resource declaration +resource "my_resource" "this" { + ... + dynamic "optional_single_block" { + for_each = var.optional_single_block != null ? { this = var.optional_single_block } : {} + content { + name = var.optional_single_block.name + color = var.optional_single_block.color + length = var.optional_single_block.length + } + } + ... +} diff --git a/docs/static/includes/specification/int.spec.nest.req.more.tf b/docs/static/includes/specification/int.spec.nest.req.more.tf index b22fdba10..63755cd20 100644 --- a/docs/static/includes/specification/int.spec.nest.req.more.tf +++ b/docs/static/includes/specification/int.spec.nest.req.more.tf @@ -1,4 +1,25 @@ -# Variable declaration +# The nested block is required and supports one or more instances +# Variable declaration +variable "required_multi_blocks" { + type = map(object({ + name = string + color = string + length = optional(number) + })) + ... +} -# Resource implementation \ No newline at end of file +# Resource declaration +resource "my_resource" "this" { + ... + dynamic "required_multi_blocks" { + for_each = var.required_multi_blocks + content { + name = var.required_multi_blocks.name + color = var.required_multi_blocks.color + length = var.required_multi_blocks.length + } + } + ... +} diff --git a/docs/static/includes/specification/int.spec.nest.req.one.tf b/docs/static/includes/specification/int.spec.nest.req.one.tf index 3dd66a515..c84a91693 100644 --- a/docs/static/includes/specification/int.spec.nest.req.one.tf +++ b/docs/static/includes/specification/int.spec.nest.req.one.tf @@ -1,26 +1,23 @@ -# The nested block is required and supports only a single instance -# Use the nested block directly without a dynamic block and looping. +# The nested block is required and supports a single instance # Variable declaration -Variable "my_nested_block" { - +variable "required_single_block" { + type = object({ + name = string + color = string + length = optional(number) + pets = map(object(...)) + }) + ... } -# Resource implementation +# Resource declaration resource "my_resource" "this" { - + ... + required_single_block { + name = var.required_single_block.name + color = var.required_single_block.color + length = var.required_single_block.length + } + ... } - - - -# The nested block is required and supports one or more instances -# Use a dynamic block with a `for_each` meta argument. As it requires atleast one input, the definition can be `for_each = var.loop_me` - -# The nested block is optional and supports only a single instance -# Use a dynamic block with a `for_each` meta argument. -# As its input is optional, the definision **SHOULD** be `for_each = var.loop_me != null ? { this = var.loop_me } : {}` - -# The nested block is optional and supports one or more instance -# Use a dynamic block with a `for_each` meta argument. -# As its input is optional and supports multiple, the definition **SHOULD** be `for_each = var.loop_me != null ? var.loop_me : {}`. -# Where the input parameter is a `map()` type. \ No newline at end of file From 3f182b425db1d7460721874bdaf0a024346d0d7c Mon Sep 17 00:00:00 2001 From: Marius Storhaug Date: Thu, 22 Feb 2024 18:15:17 +0100 Subject: [PATCH 03/13] Updates --- .vscode/settings.json | 6 +-- .../specification/int.spec.nest.nested.tf | 42 ++++++++++++++++++- .../specification/int.spec.nest.opt.more.tf | 14 +++---- .../specification/int.spec.nest.opt.one.tf | 15 ++++--- .../specification/int.spec.nest.req.more.tf | 14 +++---- .../specification/int.spec.nest.req.one.tf | 15 +++---- 6 files changed, 67 insertions(+), 39 deletions(-) diff --git a/.vscode/settings.json b/.vscode/settings.json index 5917b58ad..d57fac86d 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -25,8 +25,6 @@ "xbcp", "xgtf" ], - ["terraform"]: { - "editor.insertSpaces": true, - "editor.indentSize": 2 - } + "editor.insertSpaces": true, + "editor.tabSize": 2 } diff --git a/docs/static/includes/specification/int.spec.nest.nested.tf b/docs/static/includes/specification/int.spec.nest.nested.tf index 92d00f099..4389740bc 100644 --- a/docs/static/includes/specification/int.spec.nest.nested.tf +++ b/docs/static/includes/specification/int.spec.nest.nested.tf @@ -1,6 +1,44 @@ -# Nested dynamic blocks and conditions. +# The resource has nested dynamic blocks # Variable declaration +variable "optional_multi_block" { + type = map(object({ + name = string + length = optional(number) + nested_block = optional(object(any)) + nested_multi_blocks = optional(map(object({ + name = string + length = optional(number) + }))) + })) + default = null +} +# Resource declaration +resource "my_resource" "this" { + dynamic "optional_multi_block" { + for_each = var.optional_multi_block != null ? var.optional_multi_block : {} + content { + name = var.optional_multi_block.name + length = var.optional_multi_block.length -# Resource implementation + dynamic "nested_block" { + for_each = try(optional_multi_block.value.nested_block, null) != null ? { this = var.optional_multi_block.value.nested_block } : {} + + content { + name = var.optional_multi_block.value.nested_block.name + length = var.optional_multi_block.value.nested_block.length + } + } + + dynamic "nested_multi_blocks" { + for_each = try(optional_multi_block.value.nested_multi_blocks, null) != null ? var.optional_multi_block.value.nested_multi_blocks : {} + + content { + name = nested_multi_blocks.value.name + length = nested_multi_blocks.value.length + } + } + } + } +} diff --git a/docs/static/includes/specification/int.spec.nest.opt.more.tf b/docs/static/includes/specification/int.spec.nest.opt.more.tf index 2f586fd17..d79f14b1b 100644 --- a/docs/static/includes/specification/int.spec.nest.opt.more.tf +++ b/docs/static/includes/specification/int.spec.nest.opt.more.tf @@ -1,26 +1,24 @@ -# The nested block is optional and supports one or more instances +# The resource supports one or more optional nested blocks # Variable declaration +# Default value is null, as it is optional and should not configure anything by default. +# Uses a map type to support multiple instances. variable "optional_multi_block" { type = map(object({ name = string - color = string length = optional(number) })) default = null - ... } # Resource declaration +# The dynamic block is used to support the optionality and looping. resource "my_resource" "this" { - ... dynamic "optional_multi_block" { for_each = var.optional_multi_block != null ? var.optional_multi_block : {} content { - name = var.optional_multi_block.name - color = var.optional_multi_block.color - length = var.optional_multi_block.length + name = optional_multi_block.value.name + length = optional_multi_block.value.length } } - ... } diff --git a/docs/static/includes/specification/int.spec.nest.opt.one.tf b/docs/static/includes/specification/int.spec.nest.opt.one.tf index 9a15a6b20..11334a24b 100644 --- a/docs/static/includes/specification/int.spec.nest.opt.one.tf +++ b/docs/static/includes/specification/int.spec.nest.opt.one.tf @@ -1,26 +1,25 @@ -# The nested block is optional and supports a single instance +# The resource supports a single optional nested block # Variable declaration +# Default value is null, as it is optional and should not configure anything by default. +# It uses an object type to support a single instance. variable "optional_single_block" { type = object({ name = string - color = string length = optional(number) }) default = null - ... } # Resource declaration +# The dynamic block provides the optionality. +# The `this` key is used to access the current instance and maps the content to the name of the block. resource "my_resource" "this" { - ... dynamic "optional_single_block" { for_each = var.optional_single_block != null ? { this = var.optional_single_block } : {} content { - name = var.optional_single_block.name - color = var.optional_single_block.color - length = var.optional_single_block.length + name = optional_single_block.value.name + length = optional_single_block.value.length } } - ... } diff --git a/docs/static/includes/specification/int.spec.nest.req.more.tf b/docs/static/includes/specification/int.spec.nest.req.more.tf index 63755cd20..4dbe1a2d6 100644 --- a/docs/static/includes/specification/int.spec.nest.req.more.tf +++ b/docs/static/includes/specification/int.spec.nest.req.more.tf @@ -1,25 +1,23 @@ -# The nested block is required and supports one or more instances +# The resource requires one or more nested blocks # Variable declaration +# No default value, as it is required in the module. +# Uses a map type to support multiple instances. variable "required_multi_blocks" { type = map(object({ name = string - color = string length = optional(number) })) - ... } # Resource declaration +# The dynamic block is used, as there are multiple instances. resource "my_resource" "this" { - ... dynamic "required_multi_blocks" { for_each = var.required_multi_blocks content { - name = var.required_multi_blocks.name - color = var.required_multi_blocks.color - length = var.required_multi_blocks.length + name = required_multi_blocks.value.name + length = required_multi_blocks.value.length } } - ... } diff --git a/docs/static/includes/specification/int.spec.nest.req.one.tf b/docs/static/includes/specification/int.spec.nest.req.one.tf index c84a91693..29115f1a6 100644 --- a/docs/static/includes/specification/int.spec.nest.req.one.tf +++ b/docs/static/includes/specification/int.spec.nest.req.one.tf @@ -1,23 +1,20 @@ -# The nested block is required and supports a single instance +# The resource requires a single nested block # Variable declaration +# No default value, as it is required in the module. +# Uses an object type to support a single instance. variable "required_single_block" { type = object({ name = string - color = string length = optional(number) - pets = map(object(...)) }) - ... } # Resource declaration +# The block is used directly, as only one instance is supported and required. resource "my_resource" "this" { - ... required_single_block { - name = var.required_single_block.name - color = var.required_single_block.color - length = var.required_single_block.length + name = var.required_single_block.name + length = var.required_single_block.length } - ... } From 4743902681a8bfc38ee4ef1b3b684fb502cbfcf8 Mon Sep 17 00:00:00 2001 From: Marius Storhaug Date: Thu, 22 Feb 2024 18:17:46 +0100 Subject: [PATCH 04/13] fix --- docs/static/includes/specification/int.spec.nest.nested.tf | 2 ++ docs/static/includes/specification/int.spec.nest.opt.more.tf | 1 + docs/static/includes/specification/int.spec.nest.opt.one.tf | 1 + docs/static/includes/specification/int.spec.nest.req.more.tf | 1 + docs/static/includes/specification/int.spec.nest.req.one.tf | 1 + 5 files changed, 6 insertions(+) diff --git a/docs/static/includes/specification/int.spec.nest.nested.tf b/docs/static/includes/specification/int.spec.nest.nested.tf index 4389740bc..161bca38f 100644 --- a/docs/static/includes/specification/int.spec.nest.nested.tf +++ b/docs/static/includes/specification/int.spec.nest.nested.tf @@ -16,8 +16,10 @@ variable "optional_multi_block" { # Resource declaration resource "my_resource" "this" { + dynamic "optional_multi_block" { for_each = var.optional_multi_block != null ? var.optional_multi_block : {} + content { name = var.optional_multi_block.name length = var.optional_multi_block.length diff --git a/docs/static/includes/specification/int.spec.nest.opt.more.tf b/docs/static/includes/specification/int.spec.nest.opt.more.tf index d79f14b1b..6ee0b7544 100644 --- a/docs/static/includes/specification/int.spec.nest.opt.more.tf +++ b/docs/static/includes/specification/int.spec.nest.opt.more.tf @@ -16,6 +16,7 @@ variable "optional_multi_block" { resource "my_resource" "this" { dynamic "optional_multi_block" { for_each = var.optional_multi_block != null ? var.optional_multi_block : {} + content { name = optional_multi_block.value.name length = optional_multi_block.value.length diff --git a/docs/static/includes/specification/int.spec.nest.opt.one.tf b/docs/static/includes/specification/int.spec.nest.opt.one.tf index 11334a24b..0ff32dfbc 100644 --- a/docs/static/includes/specification/int.spec.nest.opt.one.tf +++ b/docs/static/includes/specification/int.spec.nest.opt.one.tf @@ -17,6 +17,7 @@ variable "optional_single_block" { resource "my_resource" "this" { dynamic "optional_single_block" { for_each = var.optional_single_block != null ? { this = var.optional_single_block } : {} + content { name = optional_single_block.value.name length = optional_single_block.value.length diff --git a/docs/static/includes/specification/int.spec.nest.req.more.tf b/docs/static/includes/specification/int.spec.nest.req.more.tf index 4dbe1a2d6..259e5b9c8 100644 --- a/docs/static/includes/specification/int.spec.nest.req.more.tf +++ b/docs/static/includes/specification/int.spec.nest.req.more.tf @@ -15,6 +15,7 @@ variable "required_multi_blocks" { resource "my_resource" "this" { dynamic "required_multi_blocks" { for_each = var.required_multi_blocks + content { name = required_multi_blocks.value.name length = required_multi_blocks.value.length diff --git a/docs/static/includes/specification/int.spec.nest.req.one.tf b/docs/static/includes/specification/int.spec.nest.req.one.tf index 29115f1a6..df2307010 100644 --- a/docs/static/includes/specification/int.spec.nest.req.one.tf +++ b/docs/static/includes/specification/int.spec.nest.req.one.tf @@ -13,6 +13,7 @@ variable "required_single_block" { # Resource declaration # The block is used directly, as only one instance is supported and required. resource "my_resource" "this" { + required_single_block { name = var.required_single_block.name length = var.required_single_block.length From 893823f3b8e14957985958122558cec43125681e Mon Sep 17 00:00:00 2001 From: Marius Storhaug Date: Thu, 22 Feb 2024 21:56:26 +0100 Subject: [PATCH 05/13] Link dynamic block definition to nested dynamic block section --- docs/content/specs/terraform/_index.md | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/docs/content/specs/terraform/_index.md b/docs/content/specs/terraform/_index.md index 8a2f89ea7..3580f37f1 100644 --- a/docs/content/specs/terraform/_index.md +++ b/docs/content/specs/terraform/_index.md @@ -543,11 +543,7 @@ resource "azurerm_kubernetes_cluster" "main" { } ``` -Please refer to the coding style in the example. If you just want to declare some nested block under conditions, please use: - -```terraform -for_each = ? [] : [] -``` +Please refer to the coding style in the example. If you just want to declare some nested block under conditions, please see the section on [nested blocks](#nested-blocks).
From 8c6511eff1812e8a965610e1260610d5a6bd8b31 Mon Sep 17 00:00:00 2001 From: Marius Storhaug Date: Thu, 22 Feb 2024 22:02:23 +0100 Subject: [PATCH 06/13] Relocate new content to TFNFR12 --- docs/content/specs/terraform/_index.md | 59 ++++++++++++-------------- 1 file changed, 28 insertions(+), 31 deletions(-) diff --git a/docs/content/specs/terraform/_index.md b/docs/content/specs/terraform/_index.md index 3580f37f1..361402c22 100644 --- a/docs/content/specs/terraform/_index.md +++ b/docs/content/specs/terraform/_index.md @@ -270,32 +270,6 @@ resource "azurerm_subnet" "pair" { } ``` -##### Nested blocks - -Resources nested blocks are implemented differently depending on if they are optional or required and support one or more blocks. These **SHOULD** be implemented in the following ways: - -{{< /hint >}} - -{{< tabs "nested blocks" >}} - {{< tab "Required, one" >}} - {{< include file="/static/includes/spec/int.spec.nest.req.one.tf" language="terraform" options="linenos=false" >}} - {{< /tab >}} - {{< tab "Required, one or more" >}} - {{< include file="/static/includes/spec/int.spec.nest.req.more.tf" language="terraform" options="linenos=false" >}} - {{< /tab >}} - {{< tab "Optional, one" >}} - {{< include file="/static/includes/spec/int.spec.nest.opt.one.tf" language="terraform" options="linenos=false" >}} - {{< /tab >}} - {{< tab "Optional, one or more" >}} - {{< include file="/static/includes/spec/int.spec.nest.opt.more.tf" language="terraform" options="linenos=false" >}} - {{< /tab >}} - {{< tab "Nested dynamic blocks" >}} - {{< include file="/static/includes/spec/int.spec.nest.nested.tf" language="terraform" options="linenos=false" >}} - {{< /tab >}} -{{< /tabs >}} - -{{< hint type=note >}} -
--- @@ -526,24 +500,47 @@ Please use this technique under this use case only. #### ID: TFNFR12 - Category: Code Style - Optional nested object argument should use `dynamic` -An example from the community: +An example from the interfaces for managed_identity: ```terraform resource "azurerm_kubernetes_cluster" "main" { ... dynamic "identity" { - for_each = var.client_id == "" || var.client_secret == "" ? [1] : [] + for_each = local.managed_identities.user_assigned content { - type = var.identity_type - user_assigned_identity_id = var.user_assigned_identity_id + type = identity.value.type + identity_ids = identity.value.user_assigned_resource_ids } } ... } ``` -Please refer to the coding style in the example. If you just want to declare some nested block under conditions, please see the section on [nested blocks](#nested-blocks). +Resources nested blocks are implemented differently depending on if they are optional or required and support one or more blocks. These **SHOULD** be implemented in the following ways: + +{{< /hint >}} + +{{< tabs "nested blocks" >}} + {{< tab "Required, one" >}} + {{< include file="/static/includes/spec/int.spec.nest.req.one.tf" language="terraform" options="linenos=false" >}} + {{< /tab >}} + {{< tab "Required, one or more" >}} + {{< include file="/static/includes/spec/int.spec.nest.req.more.tf" language="terraform" options="linenos=false" >}} + {{< /tab >}} + {{< tab "Optional, one" >}} + {{< include file="/static/includes/spec/int.spec.nest.opt.one.tf" language="terraform" options="linenos=false" >}} + {{< /tab >}} + {{< tab "Optional, one or more" >}} + {{< include file="/static/includes/spec/int.spec.nest.opt.more.tf" language="terraform" options="linenos=false" >}} + {{< /tab >}} + {{< tab "Nested dynamic blocks" >}} + {{< include file="/static/includes/spec/int.spec.nest.nested.tf" language="terraform" options="linenos=false" >}} + {{< /tab >}} +{{< /tabs >}} + +{{< hint type=note >}} +
From 9660ec7da0b338ede527f46be01383c35a9e60b1 Mon Sep 17 00:00:00 2001 From: Marius Storhaug Date: Thu, 22 Feb 2024 22:21:35 +0100 Subject: [PATCH 07/13] linux_profile update --- docs/content/specs/terraform/_index.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/content/specs/terraform/_index.md b/docs/content/specs/terraform/_index.md index 361402c22..fc63156e0 100644 --- a/docs/content/specs/terraform/_index.md +++ b/docs/content/specs/terraform/_index.md @@ -345,13 +345,13 @@ Meta-arguments, arguments and nested blocked are separated by blank lines. ```terraform dynamic "linux_profile" { - for_each = var.admin_username == null ? [] : ["linux_profile"] + for_each = var.linux_profile != null ? { this = var.linux_profile } : {} content { - admin_username = var.admin_username + admin_username = linux_profile.value.admin_username ssh_key { - key_data = replace(coalesce(var.public_ssh_key, tls_private_key.ssh[0].public_key_openssh), "\n", "") + key_data = linux_profile.value.ssh_key } } } From ca13e2d770ca735209ffa8379dced0e64f2947fe Mon Sep 17 00:00:00 2001 From: Marius Storhaug Date: Thu, 22 Feb 2024 22:22:03 +0100 Subject: [PATCH 08/13] diag update --- docs/static/includes/interfaces/int.diag.schema.tf | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/docs/static/includes/interfaces/int.diag.schema.tf b/docs/static/includes/interfaces/int.diag.schema.tf index 9f034bb8f..3659cfe2a 100644 --- a/docs/static/includes/interfaces/int.diag.schema.tf +++ b/docs/static/includes/interfaces/int.diag.schema.tf @@ -11,8 +11,7 @@ variable "diagnostic_settings" { event_hub_name = optional(string, null) marketplace_partner_resource_id = optional(string, null) })) - default = {} - nullable = false + default = null validation { condition = alltrue([for _, v in var.diagnostic_settings : contains(["Dedicated", "AzureDiagnostics"], v.log_analytics_destination_type)]) @@ -45,7 +44,7 @@ DESCRIPTION # Sample resource resource "azurerm_monitor_diagnostic_setting" "this" { - for_each = var.diagnostic_settings + for_each = var.diagnostic_settings != null ? var.diagnostic_settings : {} name = each.value.name != null ? each.value.name : "diag-${var.name}" target_resource_id = azurerm_.this.id storage_account_id = each.value.storage_account_resource_id From ff4c7aa797400d46dccbf55577f8a59331eb0383 Mon Sep 17 00:00:00 2001 From: Marius Storhaug Date: Thu, 22 Feb 2024 22:24:32 +0100 Subject: [PATCH 09/13] rbac update --- docs/static/includes/interfaces/int.rbac.schema.tf | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/docs/static/includes/interfaces/int.rbac.schema.tf b/docs/static/includes/interfaces/int.rbac.schema.tf index 91b9e09fe..0fa2afe01 100644 --- a/docs/static/includes/interfaces/int.rbac.schema.tf +++ b/docs/static/includes/interfaces/int.rbac.schema.tf @@ -8,8 +8,7 @@ variable "role_assignments" { condition_version = optional(string, null) delegated_managed_identity_resource_id = optional(string, null) })) - default = {} - nullable = false + default = null description = < Date: Thu, 22 Feb 2024 22:25:01 +0100 Subject: [PATCH 10/13] tags update --- docs/static/includes/interfaces/int.tags.schema.tf | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/docs/static/includes/interfaces/int.tags.schema.tf b/docs/static/includes/interfaces/int.tags.schema.tf index 2d419a8f2..afbf59f96 100644 --- a/docs/static/includes/interfaces/int.tags.schema.tf +++ b/docs/static/includes/interfaces/int.tags.schema.tf @@ -1,7 +1,6 @@ # Having default empty map and `nullable = false` means that # any expressions within the module are simpler. variable "tags" { - type = map(string) - default = {} - nullable = false + type = map(string) + default = null } From c10dbcb9da0be1ee78060f04faad507ea7ab1dbb Mon Sep 17 00:00:00 2001 From: Marius Storhaug Date: Thu, 22 Feb 2024 22:26:58 +0100 Subject: [PATCH 11/13] revert VSCode settings --- .vscode/settings.json | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/.vscode/settings.json b/.vscode/settings.json index d57fac86d..847d87020 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -24,7 +24,5 @@ "VMSS", "xbcp", "xgtf" - ], - "editor.insertSpaces": true, - "editor.tabSize": 2 + ] } From be6efa82689444e775b02484d53bab35de6ab6eb Mon Sep 17 00:00:00 2001 From: Marius Storhaug Date: Thu, 22 Feb 2024 22:41:57 +0100 Subject: [PATCH 12/13] Tags can be null on resources --- docs/static/includes/interfaces/int.tags.schema.tf | 2 -- 1 file changed, 2 deletions(-) diff --git a/docs/static/includes/interfaces/int.tags.schema.tf b/docs/static/includes/interfaces/int.tags.schema.tf index afbf59f96..89db37de9 100644 --- a/docs/static/includes/interfaces/int.tags.schema.tf +++ b/docs/static/includes/interfaces/int.tags.schema.tf @@ -1,5 +1,3 @@ -# Having default empty map and `nullable = false` means that -# any expressions within the module are simpler. variable "tags" { type = map(string) default = null From 784f30c3dc3fccf9e79c4d7110a2152f70d9e89e Mon Sep 17 00:00:00 2001 From: Marius Storhaug Date: Thu, 22 Feb 2024 22:47:12 +0100 Subject: [PATCH 13/13] reset interface, not dynamic blocks... --- docs/static/includes/interfaces/int.diag.schema.tf | 5 +++-- docs/static/includes/interfaces/int.rbac.schema.tf | 5 +++-- docs/static/includes/interfaces/int.tags.schema.tf | 7 +++++-- 3 files changed, 11 insertions(+), 6 deletions(-) diff --git a/docs/static/includes/interfaces/int.diag.schema.tf b/docs/static/includes/interfaces/int.diag.schema.tf index 3659cfe2a..9f034bb8f 100644 --- a/docs/static/includes/interfaces/int.diag.schema.tf +++ b/docs/static/includes/interfaces/int.diag.schema.tf @@ -11,7 +11,8 @@ variable "diagnostic_settings" { event_hub_name = optional(string, null) marketplace_partner_resource_id = optional(string, null) })) - default = null + default = {} + nullable = false validation { condition = alltrue([for _, v in var.diagnostic_settings : contains(["Dedicated", "AzureDiagnostics"], v.log_analytics_destination_type)]) @@ -44,7 +45,7 @@ DESCRIPTION # Sample resource resource "azurerm_monitor_diagnostic_setting" "this" { - for_each = var.diagnostic_settings != null ? var.diagnostic_settings : {} + for_each = var.diagnostic_settings name = each.value.name != null ? each.value.name : "diag-${var.name}" target_resource_id = azurerm_.this.id storage_account_id = each.value.storage_account_resource_id diff --git a/docs/static/includes/interfaces/int.rbac.schema.tf b/docs/static/includes/interfaces/int.rbac.schema.tf index 0fa2afe01..91b9e09fe 100644 --- a/docs/static/includes/interfaces/int.rbac.schema.tf +++ b/docs/static/includes/interfaces/int.rbac.schema.tf @@ -8,7 +8,8 @@ variable "role_assignments" { condition_version = optional(string, null) delegated_managed_identity_resource_id = optional(string, null) })) - default = null + default = {} + nullable = false description = <