Variable to map other Variables (Interpolation?) - Azure

Terraform v0.14.7
provider registry.terraform.io/hashicorp/azurerm v2.48.0

Hi All,

New user here, any help would be appreciated.
I have different flavours of operating systems that I would like to provision in Azure.

  1. I would like to update the variable.tf with “windowsimage” or linuximage"
  2. variable “windowsimage” will have its own set of map.
  3. createvm.tf identifies that it is a “windowsimage” and will use the mappings from the variable "windowsimage"
variable.tf

variable "azure_vm" {
  default = {
        vmos = "windowsimage"
  }
}

variable "windowsimage" {
  default = {
    publisher = "MicrosoftWindowsServer"
    offer     = "WindowsServer"
    sku       = "2016-Datacenter"
  }
}

I do not want to hardcode var.windowsimage as I would like the script to be portable for linuximages etc.
Something like this but I’m not unsure of the expression

join("", “var.”, [var.azure_vm[“vmos”], “[“publisher”]”])

createvm.tf

  source_image_reference {
    publisher  = var.windowsimage["publisher"]
    offer      = var.windowsimage["offer"]
    sku        = var.windowsimage["sku"]
    version    = "latest"
  }

Hi,

I do not understand your question but I am happy to help.

What I understand is that your are trying to create a Terraform stack (script) that can create Azure VM with both Linux and Windows operating systems. Never done that myself with Azure but with AWS. In my understanding you can do that easily by calling Terraform with the right set of parameters as input. The example in the documentation (https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/virtual_machine) has nothing OS specific as far as I understand it.

Is it maybe a deployement problem? What if you had something like that in your stack:

variable "publisher" {
  type = string
}

variable "offer" {
  type = string
}

variable "sku" {
  type = string
}

variable "version" {
  type = string
}

resource "azurerm_virtual_machine" "main" {
  name                  = "my-vm"
  location              = azurerm_resource_group.main.location
  resource_group_name   = azurerm_resource_group.main.name
  network_interface_ids = [azurerm_network_interface.main.id]
  vm_size               = "Standard_DS1_v2"

  # Uncomment this line to delete the OS disk automatically when deleting the VM
  # delete_os_disk_on_termination = true

  # Uncomment this line to delete the data disks automatically when deleting the VM
  # delete_data_disks_on_termination = true

  storage_image_reference {
    publisher = var.publisher
    offer     = var.offer
    sku       = var.sku
    version   = var.version
  }
  storage_os_disk {
    name              = "myosdisk1"
    caching           = "ReadWrite"
    create_option     = "FromImage"
    managed_disk_type = "Standard_LRS"
  }
  os_profile {
    computer_name  = "hostname"
    admin_username = "testadmin"
    admin_password = "Password1234!"
  }
  os_profile_linux_config {
    disable_password_authentication = false
  }
}

Then when you want to create a VM with Ubuntu 16.04-LTS you invoke Terraform that way:

terraform -var 'publisher=Canonical' -var 'offer=UbuntuServer' -var 'sku=16.04-LTS' -var 'version=latest'

And for a Windows Server 2016 Datacenter edition:

terraform -var 'publisher=MicrosoftWindowsServer' -var 'offer=WindowsServer' -var 'sku=2016-Datacenter' -var 'version=latest'

Does that help?

There are other examples of Terraform + Azure usage here to help: Define Input Variables | Terraform - HashiCorp Learn

Cheers,

1 Like

Hi - Apologies if my question was confusing.

I want to be able to change variable vmos between “windowsimage” and “linuximage”.
This will then query the variable “windowsimage” and variable “linuximage”

variable "azure_vm" {
  default = {
        vmos = "windowsimage"
  }
}

variable "windowsimage" {
  default = {
    publisher = "MicrosoftWindowsServer"
    offer     = "WindowsServer"
    sku       = "2016-Datacenter"
    version   = "latest"
  }
}

variable "linuximage" {
  default = {
    publisher = "Canonical"
    offer     = "UbuntuServer"
    sku       = "16.04-LTS"
    version   = "latest"
  }
}

So from my createvm.tf, instead of putting in a hard variable of var.windowsimage, I want to be able to query var.azurevm[vmos] which is windowsimage then append it so my publisher = var.windowsimage[“publisher”] or publisher = var.linuximage[“publisher”] depending on what is entered for vmos

source_image_reference {
    publisher = join("", ["var.", var.azure_environment["vm1os"],"[publisher]"])
    offer     = var.windowsimage["offer"]
    sku       = var.windowsimage["sku"]
    version   = var.windowsimage["version"]

}

No worries, I think you might find a solution by using nested maps or lookup function.

variable "azure_vm" {
  default = {
    vmos = "windowsimage"
  }
}

variable "windowsimage" {
  default = {
    publisher = "MicrosoftWindowsServer"
    offer     = "WindowsServer"
    sku       = "2016-Datacenter"
    version   = "latest"
  }
}

variable "linuximage" {
  default = {
    publisher = "Canonical"
    offer     = "UbuntuServer"
    sku       = "16.04-LTS"
    version   = "latest"
  }
}

locals {
  vmos = var.vmos == "windowsimage" ? var.windowsimage : var.linuximage
}

In your VM resource:

source_image_reference {
    publisher = local.vmos["publisher"]
    offer     = local.vmos["offer"]
    sku       = local.vmos["sku"]
    version   = local.vmos["version"]
}

I find this more evolutive with nested maps if you need to work with more than 2 vmos 2 values:

variable "azure_vm" {
  default = {
    vmos = "windows"
  }
}

variable "images" {
  default = {
    windows = {
      publisher = "MicrosoftWindowsServer"
      offer     = "WindowsServer"
      sku       = "2016-Datacenter"
      version   = "latest"
    }
    linux = {
      publisher = "Canonical"
      offer     = "UbuntuServer"
      sku       = "16.04-LTS"
      version   = "latest"
    }
  }
}

In your VM resource:

source_image_reference {
    publisher = var.images["vmos"]["publisher"]
    offer     = var.images["vmos"]["offer"]
    sku       = var.images["vmos"]["sku"]
    version   = var.images["vmos"]["version"]
}
2 Likes

Thanks Ohmar, I got it working with

  source_image_reference {
    publisher = var.images[var.azure_vm["vmos"]]["publisher"]
    offer     = var.images[var.azure_vm["vmos"]]["offer"]
    sku       = var.images[var.azure_vm["vmos"]]["sku"]
    version   = var.images[var.azure_vm["vmos"]]["version"]
  }
2 Likes