Dmitri
Dmitri

Reputation: 131

Terraform using dynamic variable values based on user input

terraform gurus,

Please advice how to use different pre-configured variables (preferably maps) based on user-provided variables.

For example, user executes terraform apply -var="dc=dc1" and terraform uses vsphere variables (server, credentials, vm names, etc) specified for dc1.

Currently I tried this code:

# Variable for dc provided by user
variable "vsphere" {
  type        = string
  description = "VSphere DC: dc1 or dc2"

  validation {
    condition     = var.dc == "dc1" || var.dc == "dc2"
    error_message = "The dc value must be dc1 or dc2"
  }
}

# Provide dc details based on user input
variable "vsphere_data" {
  type = map(string)

  default = {
    user       = "terraform"
    password   = ""
    server     = var.vsphere_dc == "dc1" ? "vcenter" : "vcenter2"
    host_ip    = var.vsphere_dc == "dc1" ? "192.168.1.1" : "192.168.2.1"
    datacenter = var.vsphere_dc == "dc1" ? "DC1" : "DC2"
    datastore  = var.vsphere_dc == "dc1" ? "dc1-ssd" : "dc2-ssd"
    dvs        = var.vsphere_dc == "dc1" ? "dc1-dvs" : "dc2-dvs"
  }
}

# Provider
provider "vsphere" {
  user                 = var.vsphere_data.user
  password             = var.vsphere_data.password
  vsphere_server       = var.vsphere_data.server
}

But when running terraform validate I experience this error:

│ Error: Variables not allowed
│
│   on main.tf line 22, in variable "vsphere_data":
│   22:     datacenter = var.vsphere_dc == "dc1" ? "DC1" : "DC2"
│
│ Variables may not be used here.

Please advice how to better implement such case and why do I experience this error? Is locals or removing ternary operation will be a solution to the scenario above?

Upvotes: 0

Views: 2147

Answers (1)

Ervin Szilagyi
Ervin Szilagyi

Reputation: 16775

Use locals instead of variables.

# Variable for dc provided by user
variable "vsphere" {
  type        = string
  description = "VSphere DC: dc1 or dc2"

  validation {
    condition     = var.vsphere == "dc1" || var.vsphere == "dc2"
    error_message = "The dc value must be dc1 or dc2."
  }
}

# Provide dc details based on user input
locals {
  vsphere_data = {
    user       = "terraform"
    password   = ""
    server     = var.vsphere == "dc1" ? "vcenter" : "vcenter2"
    host_ip    = var.vsphere == "dc1" ? "192.168.1.1" : "192.168.2.1"
    datacenter = var.vsphere == "dc1" ? "DC1" : "DC2"
    datastore  = var.vsphere == "dc1" ? "dc1-ssd" : "dc2-ssd"
    dvs        = var.vsphere == "dc1" ? "dc1-dvs" : "dc2-dvs"
  }
}

provider "vsphere" {
  user                 = local.vsphere_data.user
  password             = local.vsphere_data.password
  vsphere_server       = local.vsphere_data.server
}

You can run a plan for this code with:

terraform plan -var="vsphere=dc1"

There are a few additional problems with your initial code:

variable "vsphere" {
  type        = string
  description = "VSphere DC: dc1 or dc2"  

  validation {
    condition     = var.dc == "dc1" || var.dc == "dc2" # # THIS IS WRONG!!!
    error_message = "The dc value must be dc1 or dc2"
  }
}

For validation of a variable, you can not reference another variable. The validation should reference only itself. Correctly would be:

variable "vsphere" {
  type        = string
  description = "VSphere DC: dc1 or dc2"

  validation {
    condition     = var.vsphere == "dc1" || var.vsphere == "dc2"
    error_message = "The dc value must be dc1 or dc2."
  }
}

Please note, you don't need the var.dc variable.

Moreover, you don't have this variable var.vsphere_dc. I assume this is a typo or something, otherwise it makes no sense. The is the local value we compute.

Upvotes: 1

Related Questions