0

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?

1
  • 1
    I would use locals because variables inside variables are not allowed. Commented May 30, 2022 at 19:44

1 Answer 1

1

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.

Sign up to request clarification or add additional context in comments.

1 Comment

Thanks, Ervin, your solution worked like a charm. PS Yep, it was a typo from my code.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.