Skip to content

Commit

Permalink
docs: clarify resource and block types (#174)
Browse files Browse the repository at this point in the history
  • Loading branch information
hknutsen authored Jul 10, 2024
1 parent 8d0d41f commit 266dbcb
Showing 1 changed file with 90 additions and 89 deletions.
179 changes: 90 additions & 89 deletions docs/best-practices/resources.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,131 +31,132 @@
## Conditional resources

- Use the `count` meta-argument to conditionally create resources based on a static value, for example a local or variable of type `string` or `bool`.
**Conditional resources** refers to the creation of 0 or 1 resources based on a condition.

Using a variable of type `string` string is the more extensible approach, as you can add more allowed values down the road:
Use the `count` meta-argument to conditionally create resources based on a static value, for example a local or variable of type `string` or `bool`.

```terraform
variable "kind" {
description = "The kind of Web App to create. Allowed values are \"Linux\" and \"Windows\"."
type = string
default = "Linux"
Using a variable of type `string` string is the more extensible approach, as you can add more allowed values down the road:

validation {
condition = contains(["Linux", "Windows"], var.kind)
error_message = "Kind must be \"Linux\" or \"Windows\"."
}
}
```terraform
variable "kind" {
description = "The kind of Web App to create. Allowed values are \"Linux\" and \"Windows\"."
type = string
default = "Linux"
resource "azurerm_linux_web_app" "this" {
count = var.kind == "Linux" ? 1 : 0
}
validation {
condition = contains(["Linux", "Windows"], var.kind)
error_message = "Kind must be \"Linux\" or \"Windows\"."
}
}
resource "azurerm_windows_web_app" "this" {
count = var.kind == "Windows" ? 1 : 0
}
```
resource "azurerm_linux_web_app" "this" {
count = var.kind == "Linux" ? 1 : 0
}
resource "azurerm_windows_web_app" "this" {
count = var.kind == "Windows" ? 1 : 0
}
```

## Repeatable resources

- For repeatable resources, use a variable of type `map(object())` to dynamically create the resources, where setting the value to `{}` will not create any resources.
**Repeatable resources** refers to the creation of 0 or more resources based on a value.

```terraform
variable "firewall_rules" {
description = "A map of SQL firewall rules to create."
For repeatable resources, use a variable of type `map(object())` to dynamically create the resources, where setting the value to `{}` will not create any resources.

type = map(object({
name = string
start_ip_address = string
end_ip_address = string
}))
```terraform
variable "firewall_rules" {
description = "A map of SQL firewall rules to create."
default = {}
}
type = map(object({
name = string
start_ip_address = string
end_ip_address = string
}))
resource "azurerm_mssql_firewall_rule" "this" {
for_each = var.firewall_rules
default = {}
}
name = each.value.name
start_ip_address = each.value.start_ip_address
end_ip_address = each.value.end_ip_address
}
```
resource "azurerm_mssql_firewall_rule" "this" {
for_each = var.firewall_rules
name = each.value.name
start_ip_address = each.value.start_ip_address
end_ip_address = each.value.end_ip_address
}
```

## Repeatable nested blocks

- For repeatable nested blocks, use a variable of type `list(object())` to dynamically create the nested blocks, where setting the value to `[]` will not create any nested blocks:
**Repeatable nested blocks** refers to the creation of 0 or more [dynamic blocks](https://developer.hashicorp.com/terraform/language/expressions/dynamic-blocks) based on a value.

```terraform
variable "auth_settings_active_directory" {
description = "A list of authentication settings using the Active Directory provider to configure for this Linux web app."
For repeatable nested blocks, use a variable of type `list(object())` to dynamically create the nested blocks, where setting the value to `[]` will not create any nested blocks:

type = list(object({
client_id = string
client_secret_setting_name = string
}))
```terraform
variable "auth_settings_active_directory" {
description = "A list of authentication settings using the Active Directory provider to configure for this Linux web app."
default = []
}
type = list(object({
client_id = string
client_secret_setting_name = string
}))
default = []
}
resource "azurerm_linux_web_app" "this" {
# omitted
resource "azurerm_linux_web_app" "this" {
# omitted
auth_settings {
enabled = length(var.auth_settings_active_directory) == 0 ? false : true
auth_settings {
enabled = length(var.auth_settings_active_directory) == 0 ? false : true
dynamic "active_directory" {
for_each = var.auth_settings_active_directory
dynamic "active_directory" {
for_each = var.auth_settings_active_directory
content {
client_id = active_directory.value["client_id"]
client_secret_setting_name = active_directory.value["client_secret_setting_name"]
}
}
content {
client_id = active_directory.value["client_id"]
client_secret_setting_name = active_directory.value["client_secret_setting_name"]
}
}
```
}
}
```

## Non-repeatable nested blocks

- For non-repeatable nested blocks, use a variable of type `object()` to dynamically create the nested block, where setting the value to `null` will not create the nested block.
**Non-repeatable nested blocks** refers to the creation of 0 or 1 dynamic blocks based on a value.

**Note:** This is important because the nested block may not be supported in certain scenarios. For example, `blob_properties` for `azurerm_storage_account` is only supported if `account_kind` is set to `StorageV2` or `BlobStorage`.
For non-repeatable nested blocks, use a variable of type `object()` to dynamically create the nested block, where setting the value to `null` will not create the nested block:

```terraform
variable "account_kind" {
description = "The kind of storage account to create."
type = string
default = "StorageV2"
}
```terraform
variable "blob_properties" {
description = "The blob properties for this storage account."
variable "blob_properties" {
description = "The blob properties for this storage account."
type = object({
versioning_enabled = optional(bool, true)
change_feed_enabled = optional(bool, true)
})
type = object({
versioning_enabled = optional(bool, true)
change_feed_enabled = optional(bool, true)
})
default = {}
}
default = {}
}
resource "azurerm_storage_account" "this" {
# omitted
account_kind = var.account_kind
resource "azurerm_storage_account" "this" {
# omitted
dynamic "blob_properties" {
for_each = var.blob_properties != null ? [var.blob_properties] : []
dynamic "blob_properties" {
for_each = var.blob_properties != null ? [var.blob_properties] : []
content {
versioning_enabled = blob_properties.value["versioning_enabled"]
change_feed_enabled = blob_properties.value["change_feed_enabled"]
}
content {
versioning_enabled = blob_properties.value["versioning_enabled"]
change_feed_enabled = blob_properties.value["change_feed_enabled"]
}
}
```
}
```

Known exceptions to this rule would be:
!!! abstract "Rationale"
A nested block may not be supported in certain scenarios. For example, the `blob_properties` nested block for the `azurerm_storage_account` resource is only supported if the value of the `account_kind` argument is set to `StorageV2` or `BlobStorage`.

- Blocks that are defined as required by the provider (e.g. the `site_config` block for the `azurerm_linux_web_app` resource).
- Blocks that are optional but requires an argument to enable/disable its functionality (e.g. the `auth_settings` block for the `azurerm_linux_web_app` resource which requires an argument `enabled`).
!!! info "Exceptions"
- Blocks that are defined as required by the provider (e.g. the [`site_config` block](https://registry.terraform.io/providers/hashicorp/azurerm/3.0.2/docs/resources/linux_web_app#site_config) for the `azurerm_linux_web_app` resource).
- Blocks that are optional but requires an argument to enable/disable its functionality (e.g. the [`auth_settings` block](https://registry.terraform.io/providers/hashicorp/azurerm/3.0.2/docs/resources/linux_web_app#auth_settings) for the `azurerm_linux_web_app` resource which requires an argument `enabled`).

0 comments on commit 266dbcb

Please sign in to comment.