-
Notifications
You must be signed in to change notification settings - Fork 94
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Suggestion on nested block definitions #682
Changes from all commits
be25b5c
d61c7dc
3f182b4
4743902
893823f
8c6511e
9660ec7
ca13e2d
ff4c7aa
5401f84
c10dbcb
be6efa8
784f30c
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,46 @@ | ||
# 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({ | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. By providing a default empty map can we lose the try() below? |
||
name = string | ||
length = optional(number) | ||
}))) | ||
})) | ||
default = null | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. For collection values we recommend default is empty map/list/set and set nullable to false There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Hey @matt-FFFFFF, thank you for the feedback. Why is this the recommendation? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Hi @MariusStorhaug, We prefer this because then the author does not need to check for a null value before using the variable in an expression. It is either empty, or it is not. The only time we recommend otherwise is if there is a semantic difference between null and an empty collection. In most resource modules that are authoritative about the resources they deploy, nullable = false is the correct approach. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I was instead thinking of optimizing for the 'pattern creator' or a direct consumer of the resource module. To me it makes more sense having checks in the code and have a clear interface where we support both
This would help when defining variables in patterns that would map to the modules that a pattern would consume and you want full flexibility to the consumed resource module. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. As I said before this very much depends on whether there is a semantic meaning to In the case of a map being used in a for_each expression, there is not. Therefore it makes sense to simplify the authoring experience and set nullable to false. In the case where we are defining an absolute list of something, and the difference between I still believe that for 80% of the cases that |
||
} | ||
|
||
# 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 | ||
|
||
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 | ||
} | ||
} | ||
} | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
# 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 | ||
length = optional(number) | ||
})) | ||
default = null | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Again please set empty map and nullable false |
||
} | ||
|
||
# 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 : {} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This can be simplified if the default is empty map |
||
|
||
content { | ||
name = optional_multi_block.value.name | ||
length = optional_multi_block.value.length | ||
} | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
# 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 | ||
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 = optional_single_block.value.name | ||
length = optional_single_block.value.length | ||
} | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
# 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 | ||
length = optional(number) | ||
})) | ||
} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Please add nullable = false |
||
|
||
# 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 = required_multi_blocks.value.name | ||
length = required_multi_blocks.value.length | ||
} | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
# 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 | ||
length = optional(number) | ||
}) | ||
} | ||
|
||
# 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 | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
By providing a default empty map can we lose the try below?