Search code examples
terraformopentofu

vm specs in .tfvars file not working as expected when executing plan


I am new to terraform so I have been looking for and trying to modify other's work. I am stuck as when I do the terraform plan, it's asking me to enter the

var.vm_disk_size.

  Disk size of the created virtual machine in GB

  Enter a value:

This has been declared in terraform.tfvars file as below:

vms = {
  vm1 = {
    name                = "vm1"
    vm_ip               = "192.168.1.33"
    vm_cpu              = "6"
    vm_memory           = "8192"
    vm_disk_size        = "75"
  }
  vm2 = {
    name                = "vm2"
    vm_ip               = "192.168.1.34"
    vm_cpu              = "4"
    vm_memory           = "7168"
    vm_disk_size        = "100"
  }
  vm3 = {
    name                = "vm3"
    vm_ip               = "192.168.1.62"
    vm_cpu              = "2"
    vm_memory           = "3072"
    vm_disk_size        = "50"
  }

Here is the resource section from main.tf

#Resource
resource "vsphere_virtual_machine" "vm" {
  for_each      = var.vms

  datastore_id      = data.vsphere_datastore.datastore.id
  resource_pool_id  = data.vsphere_compute_cluster.compute_cluster.resource_pool_id
  guest_id      = var.vm_guest_id

  network_interface {
    network_id      = data.vsphere_network.network.id
    adapter_type = data.vsphere_virtual_machine.template.network_interface_types[0]
  }

  name          = each.value.name
  
  num_cpus      = var.vm_vcpu
  memory        = var.vm_memory
  firmware      = var.vm_firmware 
  disk {
    label       = var.vm_disk_label
    size    = var.vm_disk_size
    thin_provisioned    = var.vm_disk_thin
  }

  clone {
    template_uuid       = data.vsphere_virtual_machine.template.id
    customize {
      linux_options {
        host_name   = each.value.name
        domain        = var.vm_domain
    }
    network_interface {
      ipv4_address  = each.value.vm_ip
      ipv4_netmask  = var.vm_ipv4_netmask
      dns_server_list   = var.vm_dns_servers
    }
    ipv4_gateway = var.vm_ipv4_gateway
   }
  }
 }

Here is the VM variables section from variables.tf

##################   VM Variables    ############################
variable "vm_template_name" {
  description = "redhat 9.3 template"
}

variable "vm_guest_id" {
  description = "VM guest ID"
}

variable "vm_vcpu" {
  description = "The number of virtual processors to assign to this virtual machine."
  #default = "1"
}

variable "vm_memory" {
  description = "The size of the virtual machine's memory in MB"
  #default = "1024"
}

variable "vm_ipv4_netmask" {
  description = "The IPv4 subnet mask"
}

variable "vm_ipv4_gateway" {
  description = "The IPv4 default gateway"
}

variable "vm_dns_servers" {
  description = "The list of DNS servers to configure on the virtual machine"
}

variable "vm_domain" {
  description = "Domain name of virtual machine"
}

variable "vms" {
  type = map(any)
  description = "List of virtual machines to be deployed"
}

variable "vm_disk_label" {
  description = "Disk label of the created virtual machine"
}

variable "vm_disk_size" {
  description = "Disk size of the created virtual machine in GB"
}

variable "vm_disk_thin" {
  description = "Disk type of the created virtual machine , thin or thick"

}

Thank you in advance and please let me know if additional info is needed.


Solution

  • Since you have defined a variable for each of the arguments, the value provided in the terraform.tfvars is not enough, and terraform is asking you to provide values for the defined variables since you haven't provided a default one. You should be able to get it working by using the vms variable (which is of type map) with the following code:

    resource "vsphere_virtual_machine" "vm" {
      for_each      = var.vms
    
      datastore_id      = data.vsphere_datastore.datastore.id
      resource_pool_id  = data.vsphere_compute_cluster.compute_cluster.resource_pool_id
      guest_id          = var.vm_guest_id
    
      network_interface {
        network_id      = data.vsphere_network.network.id
        adapter_type    = data.vsphere_virtual_machine.template.network_interface_types[0]
      }
    
      name          = each.value.name
      
      num_cpus      = each.value.vm_cpu
      memory        = each.value.vm_memory
      firmware      = var.vm_firmware 
      disk {
        label               = var.vm_disk_label
        size                = each.value.vm_disk_size
        thin_provisioned    = var.vm_disk_thin
      }
    
      clone {
        template_uuid = data.vsphere_virtual_machine.template.id
        customize {
          linux_options {
            host_name     = each.value.name
            domain        = var.vm_domain
        }
        network_interface {
          ipv4_address      = each.value.vm_ip
          ipv4_netmask      = var.vm_ipv4_netmask
          dns_server_list   = var.vm_dns_servers
        }
        ipv4_gateway = var.vm_ipv4_gateway
       }
      }
     }
    

    You can comment out variables "vm_vcpu", "vm_memory", and "vm_disk_size" by the looks of it and test.

    EDIT: As per Matt Schuchard's suggestion, the variable vms should probably be defined as a map of maps, i.e:

    variable "vms" {
      type = map(map(string))
      description = "Map of virtual machines to be deployed"
    }