Menu

Virtual Geek

Tales from real IT system administrators world and non-production environment

Terraform variable multiple validation advanced blocks example

In my previous article on configuring a Terraform module for an Azure Function App with a private endpoint and a storage account, I shown a section within the application_stack block where I needed to implement function apps stacks. Here in this article I focusing on advanced variable validation for application stack block. These stacks include .NET, Java, Python, and Node.js, each with specific version requirements. For example, the Linux Function App service plan supports Python versions from 3.7 to 3.11. Similarly, there are defined version ranges for Java, .NET, and other stacks.

To address these requirements, I created multiple validation blocks to ensure that the versions specified for each stack are within the allowed ranges.

Additionally, for custom runtimes, which require a boolean value to indicate whether they are enabled, I included separate validation blocks with appropriate error messages to ensure correct boolean values (true or false).

A more complex validation scenario involved ensuring that only one stack in the application_stack object had a non-null numerical version at any given time, while all others should be null or false. For instance, if Python is set to version 3.11, all other stacks must be null or false. Furthermore, since Python is not supported on Windows Function Apps, I added validation to handle this restriction as well.

Related article: Terraform module Azure function app with private endpoint and storage account

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
variable "os" {
  default = "Linux"
}

variable "application_stack" {
  type = object({
    dotnet_version              = optional(string)
    use_dotnet_isolated_runtime = optional(bool)
    java_version                = optional(string)
    node_version                = optional(string)
    python_version              = optional(string)
    powershell_core_version     = optional(string)
    use_custom_runtime          = optional(bool)
  })
  default = {
    dotnet_version              = null
    use_dotnet_isolated_runtime = false #null
    java_version                = null
    node_version                = 12
    python_version              = null
    powershell_core_version     = null
    use_custom_runtime          = false
  }

  # Validation for .NET version
  validation {
    condition = (
      var.application_stack.dotnet_version == null || (
        (var.os == "Linux" && (var.application_stack.dotnet_version == null || can(regex("^(3\\.1|6\\.0|7\\.0|8\\.0)$", var.application_stack.dotnet_version))))
        ) || (
        (var.os == "Windows" && (var.application_stack.dotnet_version == null || can(regex("^(3\\.0|4\\.0|6\\.0|7\\.0|8\\.0)$", var.application_stack.dotnet_version))))
      )
    )
    error_message = "If specified, .NET version must be one of 3.1, 6.0, 7.0, or 8.0 for Linux. Windows versions are possible values include v3.0, v4.0 v6.0, v7.0 and v8.0. Defaults to v4.0"
  }

  validation {
    condition     = can(var.application_stack.use_dotnet_isolated_runtime) && (var.os == "Linux" || var.os == "Windows")
    error_message = "Should the DotNet process use an isolated runtime, The 'use_dotnet_isolated_runtime' must be a boolean value, accepted true or false. Defaults to false"
  }

  validation {
    condition = (
      var.application_stack.java_version == null || (
        var.os == "Linux" && can(regex("^(8|11|17)$", var.application_stack.java_version))
        ) || (
        var.os == "Windows" && can(regex("^(1\\.8|11|17)$", var.application_stack.java_version))
      )
    )
    error_message = "The version of Java to use. Linux supported versions include 8, 11 & 17. For Windows supported versions include 1.8, 11 & 17 (In-Preview)."
  }

  validation {
    condition = (
      var.application_stack.node_version == null || (
        lower(var.os) == "linux" && can(regex("^(12|14|16|18|20)$", var.application_stack.node_version))
        ) || (
        lower(var.os) == "windows" && can(regex("^(~12|~14|~16|~18|~20)$", var.application_stack.node_version))
      )
    )
    error_message = "The version of Node to run. Possible values include 12, 14, 16, 18, and 20 for Linux. Possible values include ~12, ~14, ~16, ~18, and ~20 for Windows."
  }


  validation {
    condition = var.application_stack.python_version == null || (
      lower(var.os) == "Linux" && can(regex("^(3\\.12|3\\.11|3\\.10|3\\.9|3\\.8|3\\.7)$", var.application_stack.python_version))
    )
    error_message = var.os == "Windows" ? "Windows is not supported" : "The version of Python to run. Possible values for Linux are 3.12, 3.11, 3.10, 3.9, 3.8 and 3.7."
  }

  # validation {
  #   condition = var.application_stack.python_version == null || (
  #     lower(var.os) == "linux" && can(regex("^(3\\.12|3\\.11|3\\.10|3\\.9|3\\.8|3\\.7)$", var.application_stack.python_version))
  #   )
  #   error_message = lower(var.os) == "windows" ? "Python versions are only supported on Linux. Please set the OS to Linux or remove the Python version." : "The Python version is invalid. Supported versions for Linux are 3.12, 3.11, 3.10, 3.9, 3.8, and 3.7."
  # }


  validation {
    condition = var.application_stack.powershell_core_version == null || (
      lower(var.os) == "linux" && can(regex("^(7|7\\.2|7\\.4)$", var.application_stack.powershell_core_version))
      ) || (
      lower(var.os) == "windows" && can(regex("^(7|7\\.2|7\\.4)$", var.application_stack.powershell_core_version))
    )
    error_message = "he version of PowerShell Core to run. Windows and Linux Possible values are 7, 7.2, and 7.4"
  }

  validation {
    condition     = can(var.application_stack.use_custom_runtime) && (var.os == "Linux" || var.os == "Windows")
    error_message = "Should the Linux Function App use a custom runtime?, The 'use_custom_runtime ' must be a boolean value, accepted true or false. Defaults to false"
  }

  validation {
    condition = (
      (
        (
          length([for known_stack01 in [
            var.application_stack.dotnet_version,
            var.application_stack.java_version,
            var.application_stack.node_version,
            var.application_stack.python_version,
            var.application_stack.powershell_core_version
          ] : known_stack01 if known_stack01 != null]) == 1  #<= 1
          ) && (
          length([for unknown_stack01 in [
            var.application_stack.use_dotnet_isolated_runtime,
            var.application_stack.use_custom_runtime
          ] : unknown_stack01 if unknown_stack01 == true]) == 0
        )
        ) || (
        (
          length([for known_stack01 in [
            var.application_stack.dotnet_version,
            var.application_stack.java_version,
            var.application_stack.node_version,
            var.application_stack.python_version,
            var.application_stack.powershell_core_version
          ] : known_stack01 if known_stack01 != null]) == 0
          ) && (
          length([for unknown_stack01 in [
            var.application_stack.use_dotnet_isolated_runtime,
            var.application_stack.use_custom_runtime
          ] : unknown_stack01 if unknown_stack01 == true]) == 1 #<= 1
        )
      )

    )
    error_message = "Only one runtime version or isolated runtime option can be set at a time."
  }
}

Download this example code Terraform Variable multiple advanced validation block.tf here or it is also available on github.com.

To test In my first validation and apply in terraform is everything OK and all values are provided correctly I see no error. But as I change variable values for python (providing incorrect value) and assigning addition value in node_version. It shows the error message as expected.

Microsoft Azure Terraform variable advanced block configuration terraform apply auto approve application stack advanced variable multiple validation blocks error message blocks function app private endpoint.png

Useful Articles
Terraform Azure function app with private endpoint and storage account
Hashicorp Terraform map and object inside module and variable example
Terraform one module deploy null or multiple resources based on input
Terraform A reference to a resource type must be followed by at least one attribute access, specifying the resource name
Terraform fore_each for loop filter with if condition example
Terraform remote-exec provisioner with ssh connection in null_resource
Terraform count vs for_each for examples with map of objects
Terraform one module deploy null or multiple resources based on input (nested for loop) Example of Terraform functions flatten() and coalesce()
Terraform Azure Create Private Endpoint to existing Storage Account with Custom Private DNS zone record link
Creating a Private Endpoint for Azure Storage Account with required sub services using Terraform Example Terraform functions of lookup() and lower()
Using element function with count meta argument example Terraform Azure subnets Example Terraform functions of element()count() and sum()
Terraform create Azure Virtual Network subnets from map of object and show name in the header Header name change in the output
Creating a Private Endpoint for Azure Storage Account with Terraform example 2 Example of for_each with toset() function
Creating a Private Endpoint for Azure Storage Account with Terraform example 3

Go Back

Comment

Blog Search

Page Views

12086146

Follow me on Blogarama