Search code examples
azureterraformterraform-provider-azureazure-vm

Is version mandatory while creating an Azure VM using terraform?


So I have been working with terraform since last 3 weeks and have been trying to use it to create self hosted GitHub Actions runners in our Azure account.

We have a shared windows VM image in Azure Compute Gallery that I'm planning to use as base image for the GA runner. I have noticed that these shared windows VM images do not generally have any versions attached to them they just have a publisher, offer and SKU attached.

I also verified by creating a new image from a VM to check if somebody missed attaching the version to the VM, but no shared images do not really have a version attached.

Yeah they do have versions but it is not attached as it is for Microsoft Platform Images.

Example of a shared image:

enter image description here

Now I found that in terraform, runners can be created by using both: azurerm_windows_virtual_machine and azurerm_virtual_machine resources.

I used both of them to test the runner creation, below are the terraform code used:

data "azurerm_shared_image" "win19_gold_image" {
  provider            = azurerm.gi
  name                = "Windows-2019_base"
  gallery_name        = data.azurerm_shared_image_gallery.cap_win_gold_image_gallery.name
  resource_group_name = "gi-rg"
}

resource "azurerm_virtual_machine" "win_runners_gold_image_based" {
  provider              = azurerm.og
  name                  = "ga-win-gold-1"
  location              = "East US"
  count                 = "1" # if I need to increase the number of VMs.
  resource_group_name   = data.azurerm_resource_group.dts_rg.name
  network_interface_ids = [azurerm_network_interface.azure_win_runner_gold_nic[count.index].id,]
  vm_size               = "Standard_D4ads_v5"

  delete_os_disk_on_termination = true
  delete_data_disks_on_termination = true

  storage_image_reference {
    publisher = data.azurerm_shared_image.win19_gold_image.identifier[0].publisher
    offer     = data.azurerm_shared_image.win19_gold_image.identifier[0].offer
    sku       = data.azurerm_shared_image.win19_gold_image.identifier[0].sku
    # Here I get the error: Error: compute.VirtualMachinesClient#CreateOrUpdate: Failure sending request: StatusCode=400 -- Original Error: Code="InvalidParameter" Message="The value of parameter imageReference.version is invalid." Target="imageReference.version"
  }
  
  storage_os_disk {
    name              = "ga-win-gold-os-disk-1"
    caching           = "None"
    create_option     = "FromImage"
    managed_disk_type = "StandardSSD_LRS"
  }
  
  os_profile {
    computer_name  = "ga-win-gold-1"
    admin_username = "svc"
    admin_password = var.WINDOWS_ADMIN_PASS
  }
  
  os_profile_windows_config {
    enable_automatic_upgrades = true
    provision_vm_agent        = true
  }
  
  storage_data_disk {
    name              = "ga-win-gold-data-disk-1"
    caching           = "None"
    create_option     = "Empty"
    disk_size_gb      = var.disk_size_gb
    lun               = 0
    managed_disk_type = "StandardSSD_LRS"
  }
}

OR

data "azurerm_shared_image" "win19_gold_image" {
  provider            = azurerm.gi
  name                = "Windows-2019_base"
  gallery_name        = data.azurerm_shared_image_gallery.cap_win_gold_image_gallery.name
  resource_group_name = "gi-rg"
}

resource "azurerm_windows_virtual_machine" "azure_win_runner" {
  provider                          = azurerm.og
  name                              = "vm-github-actions-win-${count.index}"
  resource_group_name               = data.azurerm_resource_group.dts_rg.name
  location                          = "East US"
  size                              = var.windows-vm-size
  count                             = "${var.number_of_win_az_instances}"
  network_interface_ids             = [
    azurerm_network_interface.azure_win_runner_nic[count.index].id,
  ]
  computer_name                     = "vm-ga-win-${count.index}"
  admin_username                    = var.windows-admin-username
  admin_password                    = var.WINDOWS_ADMIN_PASS

  os_disk {
    name = "vm-github-actions-win-${count.index}-os-disk"
    caching              = "None"
    storage_account_type = "StandardSSD_LRS"
  }

  source_image_reference {
    publisher = data.azurerm_shared_image.win19_gold_image.identifier[0].publisher
    offer     = data.azurerm_shared_image.win19_gold_image.identifier[0].offer
    sku       = data.azurerm_shared_image.win19_gold_image.identifier[0].sku
    version   = data.azurerm_shared_image.win19_gold_image.identifier[0].version # says this object does not have a version attached to it.
    # or version = "latest" or any other correct version string will throw error at time of apply that such a version does not exist.
  }

  enable_automatic_updates = true
  provision_vm_agent       = true
}

If I'm using azurerm_virtual_machine then if I ignore the version in storage_image_reference I receive the error:

Error: compute.VirtualMachinesClient#CreateOrUpdate: Failure sending request: StatusCode=400 -- Original Error: Code="InvalidParameter" Message="The value of parameter imageReference.version is invalid." Target="imageReference.version"

And if I add the version then I receive the error

Error: Unsupported attribute. 
This object does not have an attribute named "version".

When using azurerm_windows_virtual_machine if I remove the version argument terraform complains that version is required and when provided a sting such as 1.0.0 or latest, while applying(terraform apply) it would complain that such a version does not exist.

And if I pull the version from data.azurerm_shared_image.cap_win19_gold_image it would complain that this object does not have a version.

I am confused as to how to use shared images for VM creation using terraform if version is mandatory yet if version is not available for azure shared images. Please advise on what am I missing?

Any help would be appreciated.

Thanks, Sekhar


Solution

  • Hi All who come across this question,

    I found the solution to my issue. All I had to do was define a azurerm_shared_image_version data and then use source_image_id in azurerm_windows_virtual_machine in place of source_image_reference{} block.

    Below is what I did:

    data "azurerm_shared_image_gallery" "win_gold_image_gallery" {
      provider            = azurerm.gi
      name                = "golden_image_gallery"
      resource_group_name = "gi-rg"
    }
    
    data "azurerm_shared_image" "win19_gold_image" {
      provider            = azurerm.gi
      name                = "Windows-2019_base"
      gallery_name        = data.azurerm_shared_image_gallery.win_gold_image_gallery.name
      resource_group_name = data.azurerm_shared_image_gallery.win_gold_image_gallery.resource_group_name
    }
    
    data "azurerm_shared_image_version" "win19_gold_image_version" {
      provider            = azurerm.gi
      name                = "latest" # "recent" is also a tag to use the most recent image version
      image_name          = data.azurerm_shared_image.win19_gold_image.name
      gallery_name        = data.azurerm_shared_image.win19_gold_image.gallery_name
      resource_group_name = data.azurerm_shared_image.win19_gold_image.resource_group_name
    }
    
    resource "azurerm_windows_virtual_machine" "azure_win_gi_runner" {
      provider                          = azurerm.dep
      name                              = "vm-github-actions-win-gi-${count.index}"
      resource_group_name               = data.azurerm_resource_group.dts_rg.name
      location                          = "East US"
      size                              = var.windows-vm-size
      count                             = "${var.number_of_win_gi_az_instances}"
      network_interface_ids             = [
        azurerm_network_interface.azure_win_gi_runner_nic[count.index].id,
      ]
      computer_name                     = "ga-win-gi-${count.index}"
      admin_username                    = var.windows-admin-username
      admin_password                    = var.WINDOWS_ADMIN_PASS
    
      os_disk {
        name = "vm-github-actions-win-gi-${count.index}-os-disk"
        caching              = "None"
        storage_account_type = "StandardSSD_LRS"
      }
    
      source_image_id = data.azurerm_shared_image_version.win19_gold_image_version.id 
    # This is the thing I was missing.
    
      enable_automatic_updates = true
      provision_vm_agent       = true
    
      tags = {
        whichVM = var.gh_windows_runner
        environment = var.environment 
      }
    }