Azure Verified Modules
Glossary GitHub GitHub Issues Toggle Dark/Light/Auto mode Toggle Dark/Light/Auto mode Toggle Dark/Light/Auto mode Back to homepage

SNFR7 - Idempotency Tests

ID: SNFR7 - Category: Testing - Idempotency Tests

Modules MUST implement idempotency end-to-end (deployment) testing. E.g. deploying the module twice over the top of itself.

Modules SHOULD pass the idempotency test, as we are aware that there are some exceptions where they may fail as a false-positive or legitimate cases where a resource cannot be idempotent.

Read full article gdoc_arrow_right_alt

SNFR8 - Module Owner(s) GitHub

ID: SNFR8 - Category: Contribution/Support - Module Owner(s) GitHub

A module MUST have an owner that is defined and managed by a GitHub Team in the Azure GitHub organization.

Today this is only Microsoft FTEs, but everyone is welcome to contribute. The module just MUST be owned by a Microsoft FTE (today) so we can enforce and provide the long-term support required by this initiative.

Read full article gdoc_arrow_right_alt

SNFR9 - AVM & PG Teams GitHub Repo Permissions

ID: SNFR9 - Category: Contribution/Support - AVM & PG Teams GitHub Repo Permissions

A module owner MUST make the following GitHub teams in the Azure GitHub organization admins on the GitHub repo of the module in question:

Read full article gdoc_arrow_right_alt

TFFR1 - Cross-Referencing Modules

ID: TFFR1 - Category: Composition - Cross-Referencing Modules

Module owners MAY cross-references other modules to build either Resource or Pattern modules. However, they MUST be referenced only by a HashiCorp Terraform registry reference to a pinned version e.g.,

module "other-module" {
  source  = "Azure/xxx/azurerm"
  version = "1.2.3"
}

They MUST NOT use git reference to a module.

Read full article gdoc_arrow_right_alt

TFNFR1 - Descriptions

ID: TFNFR1 - Category: Documentation - Descriptions

Where descriptions for variables and outputs spans multiple lines. The description MAY provide variable input examples for each variable using the HEREDOC format and embedded markdown.

Example:

variable "my_complex_input" {
  type = map(object({
    param1 = string
    param2 = optional(number, null)
  }))
  description = <<DESCRIPTION
A complex input variable that is a map of objects.
Each object has two attributes:

- `param1`: A required string parameter.
- `param2`: (Optional) An optional number parameter.

Example Input:

```terraform
my_complex_input = {
  "object1" = {
    param1 = "value1"
    param2 = 2
  }
  "object2" = {
    param1 = "value2"
  }
}
```
DESCRIPTION
}

TFNFR12 - Dynamic for Optional Nested Objects

ID: TFNFR12 - Category: Code Style - Dynamic for Optional Nested Objects

An example from the community:

resource "azurerm_kubernetes_cluster" "main" {
  ...
  dynamic "identity" {
    for_each = var.client_id == "" || var.client_secret == "" ? [1] : []

    content {
      type                      = var.identity_type
      user_assigned_identity_id = var.user_assigned_identity_id
    }
  }
  ...
}

Please refer to the coding style in the example. Nested blocks under conditions, MUST be declared as:

Read full article gdoc_arrow_right_alt

TFNFR14 - Not allowed variables

ID: TFNFR14 - Category: Inputs - Not allowed variables

Since Terraform 0.13, count, for_each and depends_on are introduced for modules, module development is significantly simplified. Module’s owners MUST NOT add variables like enabled or module_depends_on to control the entire module’s operation. Boolean feature toggles are acceptable however.

Read full article gdoc_arrow_right_alt

TFNFR18 - Variables with Types

ID: TFNFR18 - Category: Code Style - Variables with Types

type MUST be defined for every variable. type SHOULD be as precise as possible, any MAY only be defined with adequate reasons.

  • Use bool instead of string or number for true/false
  • Use string for text
  • Use concrete object instead of map(any)

TFNFR2 - Module Documentation Generation

ID: TFNFR2 - Category: Documentation - Module Documentation Generation

Terraform modules documentation MUST be automatically generated via Terraform Docs .

A file called .terraform-docs.yml MUST be present in the root of the module and have the following content:

---
### To generate the output file to partially incorporate in the README.md,
### Execute this command in the Terraform module's code folder:
# terraform-docs -c .terraform-docs.yml .

formatter: "markdown document" # this is required

version: "0.16.0"

header-from: "_header.md"
footer-from: "_footer.md"

recursive:
  enabled: false
  path: modules

sections:
  hide: []
  show: []

content: |-
  {{ .Header }}

  <!-- markdownlint-disable MD033 -->
  {{ .Requirements }}

  {{ .Providers }}

  {{ .Resources }}

  <!-- markdownlint-disable MD013 -->
  {{ .Inputs }}

  {{ .Outputs }}

  {{ .Modules }}

  {{ .Footer }}  

output:
  file: README.md
  mode: replace
  template: |-
    <!-- BEGIN_TF_DOCS -->
    {{ .Content }}
    <!-- END_TF_DOCS -->    
output-values:
  enabled: false
  from: ""

sort:
  enabled: true
  by: required

settings:
  anchor: true
  color: true
  default: true
  description: false
  escape: true
  hide-empty: false
  html: true
  indent: 2
  lockfile: true
  read-comments: true
  required: true
  sensitive: true
  type: true