How to set default values for a object in terraform? - terraform

My terraform snippet:
variable "machine_details" {
type = object({
name = string
size = string
username = string
password = string
})
default = [
{
name = "example-vm"
size = "Standard_F2"
username = "adminuser"
password = "Notallowed1!"
}
]
}
I am getting error as below.
Error: Invalid default value for variable
│
│ on variables.tf line 38, in variable "machine_details":
│ 38: default = [
│ 39: {
│ 40: name = "example-vm"
│ 41: size = "Standard_F2"
│ 42: username = "adminuser"
│ 43: password = "Notallowed1!"
│ 44: }
│ 45: ]
This default value is not compatible with the variable's type constraint: object required.
I tried map(string) but didn't work too.
similary list(string) also.
I am trying the latest azurerm provider.
Also, in the gcp, we have option to provide count(for instances), so if I provide 2, two instances will be created.
How to do the same with azure and aws?
How to resolve this?

it is working this way.
variable "machine_details" {
type = object({
name = string
size = string
username = string
password = string
})
default = {
name = "example-vm"
size = "Standard_F2"
username = "adminuser"
password = "Notallowed1!"
}
}
And can refer like this : var.machine_details.name

As Marko E and luk2302 have mentioned , You have to declare and pass the variable as below :
variable "machine_details" {
type = list(object({
name = string
size = string
username = string
password = string
}))
default = [
{
name = "example-vm"
size = "Standard_F2"
username = "adminuser"
password = "Notallowed1!"
},
{
name = "example2-vm"
size = "Standard_F2"
username = "adminuser1"
password = "Notallowed2!"
}
]
}
So that if you want to use count then you can use something like below :
provider "azurerm" {
features{}
}
data "azurerm_resource_group" "example" {
name = "ansumantest"
}
resource "azurerm_virtual_network" "example" {
name = "example-network"
address_space = ["10.0.0.0/16"]
location = data.azurerm_resource_group.example.location
resource_group_name = data.azurerm_resource_group.example.name
}
resource "azurerm_subnet" "example" {
name = "internal"
resource_group_name = data.azurerm_resource_group.example.name
virtual_network_name = azurerm_virtual_network.example.name
address_prefixes = ["10.0.2.0/24"]
}
resource "azurerm_public_ip" "example" {
count = length(var.machine_details)
name = "aks-nfs-public-ip${count.index}"
location = data.azurerm_resource_group.example.location
resource_group_name = data.azurerm_resource_group.example.name
allocation_method = "Dynamic"
tags = {
environment = "Production"
}
}
resource "azurerm_network_interface" "example" {
count = length(var.machine_details)
name = "example-nic-${count.index}"
location = data.azurerm_resource_group.example.location
resource_group_name = data.azurerm_resource_group.example.name
ip_configuration {
name = "internal"
subnet_id = azurerm_subnet.example.id
public_ip_address_id = "${element(azurerm_public_ip.example.*.id, count.index)}"
private_ip_address_allocation = "Dynamic"
}
}
resource "azurerm_ssh_public_key" "example" {
name = "ansuman-sshkey"
resource_group_name = data.azurerm_resource_group.example.name
location = data.azurerm_resource_group.example.location
public_key = file("~/.ssh/id_rsa.pub")
}
resource "azurerm_linux_virtual_machine" "example" {
count = length(var.machine_details)
name = var.machine_details[count.index].name
resource_group_name = data.azurerm_resource_group.example.name
location = data.azurerm_resource_group.example.location
size = var.machine_details[count.index].size
admin_username = var.machine_details[count.index].username
admin_password = var.machine_details[count.index].password
disable_password_authentication = true
network_interface_ids = ["${element(azurerm_network_interface.example.*.id, count.index)}"]
admin_ssh_key {
username = var.machine_details[count.index].username
public_key = azurerm_ssh_public_key.example.public_key
}
os_disk {
caching = "ReadWrite"
storage_account_type = "Standard_LRS"
}
source_image_reference {
publisher = "Canonical"
offer = "UbuntuServer"
sku = "16.04-LTS"
version = "latest"
}
}
Output:

Related

Terraform Azure for each VM / NIC

I'm trying to create multiplane vms using for each function in terraform.
Resource Group
resource "azurerm_resource_group" "rg" {
name = "${var.prefix}-rg"
location = "east us 2"
tags = var.tags
}
VNET
resource "azurerm_virtual_network" "vnet" {
name = "${var.prefix}-network-1"
address_space = ["10.0.0.0/16"]
location = azurerm_resource_group.rg.location
resource_group_name = azurerm_resource_group.rg.name
tags = var.tags
}
Subnet
resource "azurerm_subnet" "subnet" {
name = "${var.prefix}-network-subnet-1"
resource_group_name = azurerm_resource_group.rg.name
virtual_network_name = azurerm_virtual_network.vnet.name
address_prefixes = ["10.0.2.0/24"]
}
Variables for NICS
variable "nics" {
type = map
default = {
nic3 = {
name = "ubuntu-test-3"
}
nic4 = {
name = "ubuntu-test-4"
}
}
}
NICS
resource "azurerm_network_interface" "nics" {
for_each = var.nics
name = each.value.name
location = azurerm_resource_group.rg.location
resource_group_name = azurerm_resource_group.rg.name
ip_configuration {
name = "${each.value.name}-conf-1"
subnet_id = azurerm_subnet.subnet.id
private_ip_address_allocation = "Dynamic"
}
tags = var.tags
}
Variables for VMS
variable "vms" {
description = "Virtual Machines"
type = map
default = {
vm3 = {
name = "ubuntu-test-3"
size = "Standard_DS1_v2"
}
vm4 = {
name = "ubuntu-test-4"
size = "Standard_DS1_v2"
}
}
}
and the block for the VM ( not completed - i wrote only the section that i have issue with )
resource "azurerm_virtual_machine" "vms" {
for_each = var.vms
name = each.value.name
resource_group_name = azurerm_resource_group.rg.name
location = azurerm_resource_group.rg.location
vm_size = each.value.size
tags = var.tags
network_interface_ids = [
azurerm_network_interface.nics[each.value].id,
]
The issue is with this section
network_interface_ids = [
azurerm_network_interface.nics[each.value].id,
]
I'm getting ERROR
│ Error: Invalid index
│
│ on main.tf line 247, in resource "azurerm_virtual_machine" "vms":
│ 247: azurerm_network_interface.nics[each.value].id,
│ ├────────────────
│ │ azurerm_network_interface.nics is object with 2 attributes
│ │ each.value is object with 2 attributes
│
│ The given key does not identify an element in this collection value: string required.
Also tried with
network_interface_ids = [
azurerm_network_interface.nics[each.key].id,
]
and got ERROR
│ Error: Invalid index
│
│ on main.tf line 249, in resource "azurerm_virtual_machine" "vms":
│ 249: azurerm_network_interface.nics[each.key].id,
│ ├────────────────
│ │ azurerm_network_interface.nics is object with 2 attributes
│ │ each.key is "vm3"
│
│ The given key does not identify an element in this collection value.
╵
╷
│ Error: Invalid index
│
│ on main.tf line 249, in resource "azurerm_virtual_machine" "vms":
│ 249: azurerm_network_interface.nics[each.key].id,
│ ├────────────────
│ │ azurerm_network_interface.nics is object with 2 attributes
│ │ each.key is "vm4"
│
│ The given key does not identify an element in this collection value
What I'm doing wrong ?
Replicated the same scenario and able to create resources.
Made couple of changes for the existing code base provided
Added **nic = "nic" value at vms block
Updated network_interface_ids = [azurerm_network_interface.nics[each.value.nic].id,]
Here is the code snippet.
Step1:
Main tf code as below
provider "azurerm" {
features {}
}
variable "prefix" {
default = "rg_swarna"
}
resource "azurerm_resource_group" "rg" {
name = "${var.prefix}-rg"
location = "West US"
// tags = var.tags
}
resource "azurerm_virtual_network" "vnet" {
name = "${var.prefix}-network-1"
address_space = ["10.0.0.0/16"]
location = azurerm_resource_group.rg.location
resource_group_name = azurerm_resource_group.rg.name
// tags = var.tags
}
resource "azurerm_subnet" "subnet" {
name = "${var.prefix}-network-subnet-1"
resource_group_name = azurerm_resource_group.rg.name
virtual_network_name = azurerm_virtual_network.vnet.name
address_prefixes = ["10.0.2.0/24"]
}
resource "azurerm_network_interface" "nics" {
for_each = var.nics
name = each.value.name
location = azurerm_resource_group.rg.location
resource_group_name = azurerm_resource_group.rg.name
ip_configuration {
name = "${each.value.name}-conf-1"
subnet_id = azurerm_subnet.subnet.id
private_ip_address_allocation = "Dynamic"
}
//tags = var.tags
}
resource "azurerm_virtual_machine" "vms" {
for_each = var.vms
name = each.value.name
vm_size = "Standard_DS1_v2"
resource_group_name = azurerm_resource_group.rg.name
location = azurerm_resource_group.rg.location
network_interface_ids = [azurerm_network_interface.nics[each.value.nic].id,]
storage_os_disk {
name = "myosdisk${each.value.name}"
caching = "ReadWrite"
create_option = "FromImage"
managed_disk_type = "Standard_LRS"
}
storage_image_reference {
publisher = "Canonical"
offer = "UbuntuServer"
sku = "16.04-LTS"
version = "latest"
}
os_profile {
computer_name = "TestDemo"
admin_username = "azureuser"
admin_password = "*****#123"
}
os_profile_linux_config {
disable_password_authentication = false
}
}
Step2:
variable tf file
variable "allowed_subnet_ids" {
type = list(string)
description = "access"
}
variable "nics" {
type = map
default = {
nic3 = {
name = "ubun3"
}
nic4 = {
name = "ubun4"
}
}
}
variable "vms" {
description = "VM"
type = map
default = {
vm3 = {
name = "ubun3"
size = "Standard_DS1_v2"
nic = "nic3"
}
vm4 = {
name = "ubuntu4"
size = "Standard_DS1_v2"
nic = "nic4"
}
}
}
variable "allowed_ips" {
type = list(string)
description = "IP addresses"
}
variable "sku" {
type = string
description = "SKU"
}
variable "resource_group_name" {
type = string
description = "resource_group_name"
}
variable "location" {
type = string
description = "location"
}
Step3:
terraform plan
terraform apply -auto-approve
Here are the reference screenshots
Here is the output from above code
In order for this to work, you would need to modify the variable for VMs slightly:
variable "vms" {
description = "Virtual Machines"
type = map
default = {
vm3 = {
name = "ubuntu-test-3"
size = "Standard_DS1_v2"
nic = "nic3"
}
vm4 = {
name = "ubuntu-test-4"
size = "Standard_DS1_v2"
nic = "nic4"
}
}
}
Then, in the VM resource block:
resource "azurerm_virtual_machine" "vms" {
for_each = var.vms
name = each.value.name
resource_group_name = azurerm_resource_group.rg.name
location = azurerm_resource_group.rg.location
vm_size = each.value.size
tags = var.tags
network_interface_ids = [
azurerm_network_interface.nics[each.value.nic].id,
]
}
Alternatively, you could try with resource chaining with for_each [1], but then you would have to refactor the resource block a bit:
resource "azurerm_virtual_machine" "vms" {
for_each = azurerm_network_interface.nics
name = each.value.name
resource_group_name = azurerm_resource_group.rg.name
location = azurerm_resource_group.rg.location
vm_size = var.vm_size # or set it to be equal to "Standard_DS1_v2"
tags = var.tags
network_interface_ids = [
each.value.id,
]
}
Then, you would also have to define a new variable called vm_size:
variable "vm_size" {
type = string
description = "VM size."
default = "Standard_DS1_v2"
}
In the second case, you could remove the variable vms completely.
[1] https://developer.hashicorp.com/terraform/language/meta-arguments/for_each#chaining-for_each-between-resources

azure terraform: how to attach multiple data disks to multiple VMs

I'm following Neal Shah's instructions for deploying multiple VMs with multiple managed disks (https://www.nealshah.dev/posts/2020/05/terraform-for-azure-deploying-multiple-vms-with-multiple-managed-disks/#deploying-multiple-vms-with-multiple-datadisks)
everything works fine except for the azurerm_virtual_machine_data_disk_attachment resource which fails with the following error
│ Error: Invalid index
│
│ on main.tf line 103, in resource "azurerm_virtual_machine_data_disk_attachment" "managed_disk_attach":
│ 103: virtual_machine_id = azurerm_linux_virtual_machine.vms[element(split("_", each.key), 1)].id
│ ├────────────────
│ │ azurerm_linux_virtual_machine.vms is tuple with 3 elements
│ │ each.key is "datadisk_dca0-apache-cassandra-node0_disk00"
│
│ The given key does not identify an element in this collection value: a number is required.
my code is below:
locals {
vm_datadiskdisk_count_map = { for k in toset(var.nodes) : k => var.data_disk_count }
luns = { for k in local.datadisk_lun_map : k.datadisk_name => k.lun }
datadisk_lun_map = flatten([
for vm_name, count in local.vm_datadiskdisk_count_map : [
for i in range(count) : {
datadisk_name = format("datadisk_%s_disk%02d", vm_name, i)
lun = i
}
]
])
}
# create resource group
resource "azurerm_resource_group" "resource_group" {
name = format("%s-%s", var.dca, var.name)
location = var.location
}
# create availability set
resource "azurerm_availability_set" "vm_availability_set" {
name = format("%s-%s-availability-set", var.dca, var.name)
location = azurerm_resource_group.resource_group.location
resource_group_name = azurerm_resource_group.resource_group.name
}
# create Security Group to access linux
resource "azurerm_network_security_group" "linux_vm_nsg" {
name = format("%s-%s-linux-vm-nsg", var.dca, var.name)
location = azurerm_resource_group.resource_group.location
resource_group_name = azurerm_resource_group.resource_group.name
security_rule {
name = "AllowSSH"
description = "Allow SSH"
priority = 100
direction = "Inbound"
access = "Allow"
protocol = "Tcp"
source_port_range = "*"
destination_port_range = "22"
source_address_prefix = "*"
destination_address_prefix = "*"
}
}
# associate the linux NSG with the subnet
resource "azurerm_subnet_network_security_group_association" "linux_vm_nsg_association" {
subnet_id = "${data.azurerm_subnet.subnet.id}"
network_security_group_id = azurerm_network_security_group.linux_vm_nsg.id
}
# create NICs for apache cassandra hosts
resource "azurerm_network_interface" "vm_nics" {
depends_on = [azurerm_subnet_network_security_group_association.linux_vm_nsg_association]
count = length(var.nodes)
name = format("%s-%s-nic${count.index}", var.dca, var.name)
location = azurerm_resource_group.resource_group.location
resource_group_name = azurerm_resource_group.resource_group.name
ip_configuration {
name = format("%s-%s-apache-cassandra-ip", var.dca, var.name)
subnet_id = "${data.azurerm_subnet.subnet.id}"
private_ip_address_allocation = "Dynamic"
}
}
# create apache cassandra VMs
resource "azurerm_linux_virtual_machine" "vms" {
count = length(var.nodes)
name = element(var.nodes, count.index)
location = azurerm_resource_group.resource_group.location
resource_group_name = azurerm_resource_group.resource_group.name
network_interface_ids = [element(azurerm_network_interface.vm_nics.*.id, count.index)]
availability_set_id = azurerm_availability_set.vm_availability_set.id
size = var.vm_size
admin_username = var.admin_username
disable_password_authentication = true
admin_ssh_key {
username = var.admin_username
public_key = var.ssh_pub_key
}
source_image_id = var.source_image_id
os_disk {
caching = "ReadWrite"
storage_account_type = var.storage_account_type
disk_size_gb = var.os_disk_size_gb
}
}
# create data disk(s) for VMs
resource "azurerm_managed_disk" "managed_disk" {
for_each= toset([for j in local.datadisk_lun_map : j.datadisk_name])
name= each.key
location = azurerm_resource_group.resource_group.location
resource_group_name = azurerm_resource_group.resource_group.name
storage_account_type = var.storage_account_type
create_option = "Empty"
disk_size_gb = var.disk_size_gb
}
resource "azurerm_virtual_machine_data_disk_attachment" "managed_disk_attach" {
for_each = toset([for j in local.datadisk_lun_map : j.datadisk_name])
managed_disk_id = azurerm_managed_disk.managed_disk[each.key].id
virtual_machine_id = azurerm_linux_virtual_machine.vms[element(split("_", each.key), 1)].id
lun = lookup(local.luns, each.key)
caching = "ReadWrite"
}
anyone know how to accomplish this? thanks!
I've tried several different approaches to this but have been unsuccessful so far, I was expecting it to work as described in Neal's post
I was able to get this working. However, I have not tested adding/removing nodes/disks yet. But this working to create multiple VMs with multiple data disks attached to each VM.
I use a variable file that I source to substitute the variables in the *.tf files.
variables.tf
variable "azure_subscription_id" {
type = string
description = "Azure Subscription ID"
default = ""
}
variable "dca" {
type = string
description = "datacenter [dca0|dca2|dca4|dca6]."
default = ""
}
variable "location" {
type = string
description = "Location of the resource group."
default = ""
}
variable "resource_group" {
type = string
description = "resource group name."
default = ""
}
variable "subnet_name" {
type = string
description = "subnet name"
default = ""
}
variable "vnet_name" {
type = string
description = "vnet name"
default = ""
}
variable "vnet_rg" {
type = string
description = "vnet resource group"
default = ""
}
variable "vm_size" {
type = string
description = "vm size"
default = ""
}
variable "os_disk_size_gb" {
type = string
description = "vm os disk size gb"
default = ""
}
variable "data_disk_size_gb" {
type = string
description = "vm data disk size gb"
default = ""
}
variable "admin_username" {
type = string
description = "admin user name"
default = ""
}
variable "ssh_pub_key" {
type = string
description = "public key for admin user"
default = ""
}
variable "source_image_id" {
type = string
description = "image id"
default = ""
}
variable "os_disk_storage_account_type" {
type = string
description = ""
default = ""
}
variable "data_disk_storage_account_type" {
type = string
description = ""
default = ""
}
variable "vm_list" {
type = map(object({
hostname = string
}))
default = {
vm0 ={
hostname = "${dca}-${name}-node-0"
},
vm1 = {
hostname = "${dca}-${name}-node-1"
}
vm2 = {
hostname = "${dca}-${name}-node-2"
}
}
}
variable "disks_per_instance" {
type = string
description = ""
default = ""
}
terraform.tfvars
# subscription
azure_subscription_id = "${azure_subscription_id}"
# name and location
resource_group = "${dca}-${name}"
location = "${location}"
dca = "${dca}"
# Network
subnet_name = "${subnet_name}"
vnet_name = "${dca}vnet"
vnet_rg = "th-${dca}-vnet"
# VM
vm_size = "${vm_size}"
os_disk_size_gb = "${os_disk_size_gb}"
os_disk_storage_account_type = "${os_disk_storage_account_type}"
source_image_id = "${source_image_id}"
# User/key info
admin_username = "${admin_username}"
ssh_pub_key = ${ssh_pub_key}
# data disk info
data_disk_storage_account_type = "${data_disk_storage_account_type}"
data_disk_size_gb = "${data_disk_size_gb}"
disks_per_instance= "${disks_per_instance}"
main.tf
# set locals for multi data disks
locals {
vm_datadiskdisk_count_map = { for k, query in var.vm_list : k => var.disks_per_instance }
luns = { for k in local.datadisk_lun_map : k.datadisk_name => k.lun }
datadisk_lun_map = flatten([
for vm_name, count in local.vm_datadiskdisk_count_map : [
for i in range(count) : {
datadisk_name = format("datadisk_%s_disk%02d", vm_name, i)
lun = i
}
]
])
}
# create resource group
resource "azurerm_resource_group" "resource_group" {
name = format("%s", var.resource_group)
location = var.location
}
# create data disk(s)
resource "azurerm_managed_disk" "managed_disk" {
for_each = toset([for j in local.datadisk_lun_map : j.datadisk_name])
name = each.key
location = azurerm_resource_group.resource_group.location
resource_group_name = azurerm_resource_group.resource_group.name
storage_account_type = var.data_disk_storage_account_type
create_option = "Empty"
disk_size_gb = var.data_disk_size_gb
}
# create availability set
resource "azurerm_availability_set" "vm_availability_set" {
name = format("%s-availability-set", var.resource_group)
location = azurerm_resource_group.resource_group.location
resource_group_name = azurerm_resource_group.resource_group.name
}
# create Security Group to access linux
resource "azurerm_network_security_group" "linux_vm_nsg" {
name = format("%s-linux-vm-nsg", var.resource_group)
location = azurerm_resource_group.resource_group.location
resource_group_name = azurerm_resource_group.resource_group.name
security_rule {
name = "AllowSSH"
description = "Allow SSH"
priority = 100
direction = "Inbound"
access = "Allow"
protocol = "Tcp"
source_port_range = "*"
destination_port_range = "22"
source_address_prefix = "*"
destination_address_prefix = "*"
}
}
# associate the linux NSG with the subnet
resource "azurerm_subnet_network_security_group_association" "linux_vm_nsg_association" {
subnet_id = "${data.azurerm_subnet.subnet.id}"
network_security_group_id = azurerm_network_security_group.linux_vm_nsg.id
}
# create NICs for vms
resource "azurerm_network_interface" "nics" {
depends_on = [azurerm_subnet_network_security_group_association.linux_vm_nsg_association]
for_each = var.vm_list
name = "${each.value.hostname}-nic"
location = azurerm_resource_group.resource_group.location
resource_group_name = azurerm_resource_group.resource_group.name
ip_configuration {
name = format("%s-proxy-ip", var.resource_group)
subnet_id = "${data.azurerm_subnet.subnet.id}"
private_ip_address_allocation = "Dynamic"
}
}
# create VMs
resource "azurerm_linux_virtual_machine" "vms" {
for_each = var.vm_list
name = each.value.hostname
location = azurerm_resource_group.resource_group.location
resource_group_name = azurerm_resource_group.resource_group.name
network_interface_ids = [azurerm_network_interface.nics[each.key].id]
availability_set_id = azurerm_availability_set.vm_availability_set.id
size = var.vm_size
source_image_id = var.source_image_id
custom_data = filebase64("cloud-init.sh")
admin_username = var.admin_username
disable_password_authentication = true
admin_ssh_key {
username = var.admin_username
public_key = var.ssh_pub_key
}
os_disk {
caching = "ReadWrite"
storage_account_type = var.os_disk_storage_account_type
disk_size_gb = var.os_disk_size_gb
}
}
# attache data disks vms
resource "azurerm_virtual_machine_data_disk_attachment" "managed_disk_attach" {
for_each = toset([for j in local.datadisk_lun_map : j.datadisk_name])
managed_disk_id = azurerm_managed_disk.managed_disk[each.key].id
virtual_machine_id = azurerm_linux_virtual_machine.vms[element(split("_", each.key), 1)].id
lun = lookup(local.luns, each.key)
caching = "ReadWrite"
}

A managed resource "azurerm_network_interface" has not been declared in module

I'm running a "terraform plan" against my Linux VM and I'm receiving the following error:
│ Error: Reference to undeclared resource
│
│ on .terraform/modules/vm-ansiblecontroller/virtual-machine/linux/outputs.tf line 13, in output "nic_id":
│ 13: value = azurerm_network_interface.nic-linux.id
│
│ A managed resource "azurerm_network_interface" "nic-linux" has not been declared in module.vm-ansiblecontroller.
I haven't included any code from my RGs & vNets, as I'm hoping what I have included is enough to solve this.
Any assistance would be appreciated, I just can't figure it out
module "vm-ansiblecontroller" {
resource_group_name = module.rg-ansiblecontroller.resource_group_name
location = local.location
linux_machine_name = "linux-test1"
tags = var.tags
nic_id = module.vm-ansiblecontroller.nic_id
subnet_id = module.subnet-networkcore.subnet_id
virtual_machine_size = "Standard_D2"
admin_username = "jpadmin"
admin_ssh_public_key = file("~/.ssh/id_rsa.pub")
source_image_publisher = "Canonical"
source_image_offer = "UbuntuServer"
source_image_sku = "16.04-LTS"
source_image_version = "latest"
operating_system_disk_cache = "ReadWrite"
operating_system_disk_type = "Standard_LRS"
ip_configuration_name = "internal"
private_ip_address_allocation = "Dynamic"
public_ip_allocation_method = "Static"
public_ip_sku = "Standard"
}
modules/virtualmachine/main.tf
# Linux Virtual Machine
resource "azurerm_linux_virtual_machine" "vm-linux" {
name = var.linux_machine_name
location = var.location
resource_group_name = var.resource_group_name
tags = var.tags
size = var.virtual_machine_size
admin_username = var.admin_username
disable_password_authentication = true
# network_interface_ids = [azurerm_network_interface.nic-linux.id]
network_interface_ids = var.nic_id
admin_ssh_key {
username = var.admin_username
public_key = var.admin_ssh_public_key
}
source_image_reference {
publisher = var.source_image_publisher
offer = var.source_image_offer
sku = var.source_image_sku
version = var.source_image_version
}
os_disk {
caching = var.operating_system_disk_cache
storage_account_type = var.operating_system_disk_type
}
}
# Network Interfaces for Linux VM
resource "azurerm_network_interface" "nic-linux" {
name = var.linux_machine_name
location = var.location
resource_group_name = var.resource_group_name
tags = var.tags
ip_configuration {
name = var.ip_configuration_name
# subnet_id = azurerm_subnet.subnet.id
subnet_id = var.subnet_id
private_ip_address_allocation = var.private_ip_address_allocation
public_ip_address_id = azurerm_public_ip.pip-linux.id
}
}
resource "azurerm_public_ip" "pip-linux" {
name = var.linux_machine_name
location = var.location
resource_group_name = var.resource_group_name
tags = var.tags
allocation_method = var.public_ip_allocation_method
sku = var.public_ip_sku
}
modules/virtualmachine/variables.tf
# VM Name
variable "linux_machine_name" {
description = "Linux Virtual Machine Name - If left blank generated from metadata module"
type = string
default = ""
}
variable "resource_group_name" {
description = "Resource group name"
type = string
}
variable "location" {
description = "Azure region"
type = string
}
variable "tags" {
description = "tags to be applied to resources"
type = map(string)
}
# VM Size
variable "virtual_machine_size" {
description = "Instance size to be provisioned"
type = string
}
variable "admin_username" {
description = "names to be applied to resources"
type = string
}
variable "admin_ssh_public_key" {
description = "(Linux) Public SSH Key - Generated if left blank"
type = string
default = ""
sensitive = true
}
# Operating System
variable "source_image_publisher" {
description = "Operating System Publisher"
type = string
}
variable "source_image_offer" {
description = "Operating System Name"
type = string
}
variable "source_image_sku" {
description = "Operating System SKU"
type = string
}
variable "source_image_version" {
description = "Operating System Version"
type = string
default = "latest"
}
# Operating System Disk
variable "operating_system_disk_cache" {
description = "Type of caching to use on the OS disk - Options: None, ReadOnly or ReadWrite"
type = string
default = "ReadWrite"
}
variable "operating_system_disk_type" {
description = "Type of storage account to use with the OS disk - Options: Standard_LRS, StandardSSD_LRS or Premium_LRS"
type = string
default = "StandardSSD_LRS"
}
variable "ip_configuration_name" {
description = "ip configuration name"
type = string
default = ""
}
# Networking
variable "nic_id" {
type = list(string)
description = "ID of the nic"
}
variable "subnet_id" {
type = string
description = "ID of the subnet"
}
variable "private_ip_address_allocation" {
type = string
description = "Private ip allocation method"
}
variable "public_ip_allocation_method" {
type = string
description = "Public ip allocation method"
}
variable "public_ip_sku" {
description = "SKU to be used with this public IP - Basic or Standard"
type = string
default = "Standard"
}
modules/virtualmachine/outputs.tf
output "nic_id" {
description = "ids of the vm nics provisoned."
value = azurerm_network_interface.nic-linux.id
}
NEW ERROR:
Error: Invalid value for module argument
│
│ on compute_lin_vm.tf line 10, in module "vm-ansiblecontroller":
│ 10: nic_id = module.vm-ansiblecontroller.nic_id
│
│ The given value is not suitable for child module variable "nic_id" defined at
│ .terraform/modules/vm-ansiblecontroller/virtual-machine/linux/variables.tf:83,1-18: list of string required.
You placed your azurerm_network_interface inside azurerm_linux_virtual_machine. It should be:
resource "azurerm_linux_virtual_machine" "vm-linux" {
name = var.linux_machine_name
location = var.location
resource_group_name = var.resource_group_name
tags = var.tags
size = var.virtual_machine_size
admin_username = var.admin_username
disable_password_authentication = true
# network_interface_ids = [azurerm_network_interface.nic-linux.id]
network_interface_ids = var.nic_id
admin_ssh_key {
username = var.admin_username
public_key = var.admin_ssh_public_key
}
source_image_id = var.source_image_id
custom_data = var.custom_data
source_image_reference {
publisher = var.source_image_publisher
offer = var.source_image_offer
sku = var.source_image_sku
version = var.source_image_version
}
os_disk {
caching = var.operating_system_disk_cache
storage_account_type = var.operating_system_disk_type
}
}
# Network Interfaces for Linux VM
resource "azurerm_network_interface" "nic-linux" {
name = var.linux_machine_name
location = var.location
resource_group_name = var.resource_group_name
tags = var.tags
ip_configuration {
name = var.ip_configuration_name
subnet_id = azurerm_subnet.subnet.id
private_ip_address_allocation = var.private_ip_address_allocation
public_ip_address_id = azurerm_public_ip.pip-linux.id
}
}

how to deploy two vm to two different resource group

Does anyone could give a hint on how should i do. i want to deploy 4 Az linux VM but 2 in each different resource group.
eg: rg-one will have 2 linux and rg-two will the other two
the way i did it is too create two block with azure_linux_virtual_machine, it is working but i was wondering if it could not be simplify.
thank in advance for the head up
here a snipped what i have done.
# Fetch exisiting resource_group
data "azurerm_resource_group" "rg-dock001" {
name = var.resource_group01
}
# Fetch vm network
data "azurerm_virtual_network" "vm_network" {
name = var.vm_network
resource_group_name = var.rg_name_network
}
output "azurerm_virtual_network" {
value = data.azurerm_virtual_network.vm_network.id
}
# Fetch vm subnet
data "azurerm_subnet" "vm_subnet" {
name = var.vm_subnet
resource_group_name = var.rg_name_network
virtual_network_name = var.vm_network
}
output "subnet_id" {
value = data.azurerm_subnet.vm_subnet.id
}
resource "azurerm_network_interface" "ens124-01" {
name = var.vm_nic01[count.index]
count = length(var.vm_nic01)
location = var.rg_location
resource_group_name = var.resource_group01
ip_configuration {
name = "internal"
subnet_id = data.azurerm_subnet.vm_subnet.id
private_ip_address_allocation = "Static"
private_ip_address = "10.241.25.${count.index + 10}"
}
tags = var.vm_tags
}
output "private_ip01" {
value = length(azurerm_network_interface.ens124-01.*.private_ip_address)
}
# Fetch existing image
data "azurerm_image" "custom_docker_image" {
name_regex = var.packer_image
sort_descending = true
resource_group_name = var.resource_group_image
}
output "image_id" {
value = data.azurerm_image.custom_docker_image.id
}
# create and display an SSH key
resource "tls_private_key" "ssh" {
algorithm = "RSA"
rsa_bits = 4096
}
output "tls_private_key" {
value = tls_private_key.ssh.private_key_pem
sensitive = true
}
resource "azurerm_linux_virtual_machine" "main01" {
name = var.vm_name01[count.index]
count = length(var.vm_name01)
resource_group_name = var.resource_group01
location = var.rg_location
size = "standard_ds3_v2"
admin_username = var.username
admin_password = var.password
disable_password_authentication = true
network_interface_ids = ["${element(azurerm_network_interface.ens124-01.*.id, count.index)}"]
source_image_id = data.azurerm_image.custom_docker_image.id
computer_name = var.vm_name01[count.index]
admin_ssh_key {
username = var.ssh_username
public_key = tls_private_key.ssh.public_key_openssh
}
os_disk {
name = "disk-int-dock-0${count.index + 1}"
storage_account_type = "Standard_LRS"
caching = "ReadWrite"
}
tags = var.vm_tags
}
data "azurerm_resource_group" "rg-dock002" {
name = var.resource_group02
}
resource "azurerm_network_interface" "ens124-02" {
name = var.vm_nic02[count.index]
count = length(var.vm_nic02)
location = var.rg_location
resource_group_name = var.resource_group02
ip_configuration {
name = "internal"
subnet_id = data.azurerm_subnet.vm_subnet.id
private_ip_address_allocation = "Static"
private_ip_address = "10.241.25.${count.index + 20}"
}
tags = var.vm_tags
}
output "private_ip02" {
value = length(azurerm_network_interface.ens124-02.*.private_ip_address)
}
resource "azurerm_linux_virtual_machine" "main02" {
name = var.vm_name02[count.index]
count = length(var.vm_name02)
resource_group_name = var.resource_group02
location = var.rg_location
size = "standard_ds3_v2"
admin_username = var.username
admin_password = var.password
disable_password_authentication = true
network_interface_ids = ["${element(azurerm_network_interface.ens124-02.*.id, count.index)}"]
source_image_id = data.azurerm_image.custom_docker_image.id
computer_name = var.vm_name02[count.index]
admin_ssh_key {
username = var.ssh_username
public_key = tls_private_key.ssh.public_key_openssh
}
os_disk {
name = "disk-int-dock-0${count.index + 1}"
storage_account_type = "Standard_LRS"
caching = "ReadWrite"
}
tags = var.vm_tags
}````
As per your requirement you can use something like below :
provider "azurerm" {
features {}
}
variable "VM" {
default= {
vm1={
rg_name= "ajaytest",
vnet_name="ajay-vnet",
subnet_name="default",
nic_name = "ansumanVM-nic",
private_ip="10.0.0.10",
vm_name="ansumanVM"
},
vm2={
rg_name= "kartiktest",
vnet_name="kartik-vnet",
subnet_name="default",
nic_name="terraformVM-nic",
private_ip="10.0.0.20",
vm_name="terraformVM"
}
}
}
variable "username" {
default="ansuman"
}
variable "password" {
default="Password#1234!"
}
data "azurerm_shared_image_version" "example" {
name = "0.0.1"
image_name = "UbuntuwithNginxinstalled"
gallery_name = "ansumantestgallery"
resource_group_name = "ansumantest"
}
data "azurerm_resource_group" "rg-dock" {
for_each = var.VM
name = each.value["rg_name"]
}
# Fetch vm network
data "azurerm_virtual_network" "vm_network" {
for_each = var.VM
name = each.value["vnet_name"]
resource_group_name = each.value["rg_name"]
}
# Fetch vm subnet
data "azurerm_subnet" "vm_subnet" {
for_each = var.VM
name = each.value["subnet_name"]
resource_group_name = each.value["rg_name"]
virtual_network_name = each.value["vnet_name"]
}
resource "azurerm_network_interface" "ens124" {
for_each = var.VM
name = each.value["nic_name"]
location = data.azurerm_resource_group.rg-dock[each.key].location
resource_group_name = data.azurerm_resource_group.rg-dock[each.key].name
ip_configuration {
name = "internal"
subnet_id = data.azurerm_subnet.vm_subnet[each.key].id
private_ip_address_allocation = "Static"
private_ip_address = each.value["private_ip"]
}
}
# create and display an SSH key
resource "tls_private_key" "ssh" {
algorithm = "RSA"
rsa_bits = 4096
}
output "tls_private_key" {
value = tls_private_key.ssh.private_key_pem
sensitive = true
}
resource "azurerm_linux_virtual_machine" "main" {
for_each = var.VM
name = each.value["vm_name"]
resource_group_name = data.azurerm_resource_group.rg-dock[each.key].name
location = data.azurerm_resource_group.rg-dock[each.key].location
size = "standard_ds3_v2"
admin_username = var.username
admin_password = var.password
disable_password_authentication = true
network_interface_ids = [azurerm_network_interface.ens124[format("%s", each.key)].id]
source_image_id = data.azurerm_shared_image_version.example.id
computer_name = each.key
admin_ssh_key {
username = var.username
public_key = tls_private_key.ssh.public_key_openssh
}
os_disk {
name = "disk-int-dock-${each.key}"
storage_account_type = "Standard_LRS"
caching = "ReadWrite"
}
}
Note: The admin username and the ssh username must be the same due the below limitation :
And the location of the VM ,Vnet ,Image and other resources must be the same.
Output:

Incorrect terraform config post 0.12upgrade command

In its simplest form,
main.tf is as below:
data "azurerm_resource_group" "tf-rg-external" {
name = var.rg_name
}
# Reference existing Virtual Network
data "azurerm_virtual_network" "tf-vn" {
name = var.vnet_name
resource_group_name = data.azurerm_resource_group.tf-rg-external.name
}
# Reference existing subnet
data "azurerm_subnet" "tf-sn" {
name = var.subnet_name
virtual_network_name = data.azurerm_virtual_network.tf-vn.name
resource_group_name = data.azurerm_resource_group.tf-rg-external.name
}
resource "azurerm_network_security_group" "tf-nsg" {
name = var.app_nsg
location = data.azurerm_virtual_network.tf-vn.location
resource_group_name = data.azurerm_resource_group.tf-rg-external.name
}
resource "azurerm_network_security_rule" "tf-nsr-5986" {
name = "Open Port 5986"
priority = 101
direction = "Inbound"
access = "Allow"
protocol = "Tcp"
source_port_range = "*"
destination_port_range = "5986"
source_address_prefixes = var.allowed_source_ips
destination_address_prefix = "VirtualNetwork"
resource_group_name = data.azurerm_resource_group.tf-rg-external.name
network_security_group_name = azurerm_network_security_group.tf-nsg.name
}
resource "azurerm_network_security_rule" "tf-nsr-3389" {
name = "Open Port 3389"
priority = 102
direction = "Inbound"
access = "Allow"
protocol = "Tcp"
source_port_range = "*"
destination_port_range = "3389"
source_address_prefixes = var.allowed_source_ips
destination_address_prefix = "VirtualNetwork"
resource_group_name = data.azurerm_resource_group.tf-rg-external.name
network_security_group_name = azurerm_network_security_group.tf-nsg.name
}
# Assosciate NSG to subnet
resource "azurerm_subnet_network_security_group_association" "tf-snnsg" {
subnet_id = data.azurerm_subnet.tf-sn.id
network_security_group_id = azurerm_network_security_group.tf-nsg.id
}
# Network inteface for Interface
resource "azurerm_network_interface" "tf-ni" {
count = var.vm_count
name = "${var.base_hostname}${format("%02d", count.index + 1)}-nic01"
location = data.azurerm_virtual_network.tf-vn.location
resource_group_name = data.azurerm_resource_group.tf-rg-external.name
ip_configuration {
name = "${var.base_hostname}${format("%02d", count.index)}-iip01"
subnet_id = data.azurerm_subnet.tf-sn.id
private_ip_address_allocation = "dynamic"
public_ip_address_id = element(azurerm_public_ip.tf-pip.*.id, count.index)
}
}
resource "azurerm_public_ip" "tf-pip" {
count = var.vm_count
location = data.azurerm_virtual_network.tf-vn.location
name = "${var.base_hostname}${format("%02d", count.index + 1)}-pip01"
resource_group_name = data.azurerm_resource_group.tf-rg-external.name
allocation_method = "Dynamic"
}
# Storage Account
resource "azurerm_storage_account" "tf-sa" {
count = var.vm_count
name = "${lower(var.base_hostname)}${format("%02d", count.index + 1)}${var.sto_acc_suffix}01"
location = data.azurerm_virtual_network.tf-vn.location
resource_group_name = data.azurerm_resource_group.tf-rg-external.name
account_tier = var.sto_acc_tier_std
account_replication_type = var.sto_acc_rep_type_lrs
}
resource "azurerm_virtual_machine" "tf-vm" {
count = var.vm_count
name = "${var.base_hostname}${format("%02d", count.index + 1)}"
location = data.azurerm_virtual_network.tf-vn.location
resource_group_name = data.azurerm_resource_group.tf-rg-external.name
network_interface_ids = [element(azurerm_network_interface.tf-ni.*.id, count.index)]
vm_size = var.vm_size
delete_os_disk_on_termination = true
delete_data_disks_on_termination = true
storage_image_reference {
publisher = var.vm_publisher
offer = var.vm_offer
sku = var.vm_sku
version = var.vm_img_version
}
storage_os_disk {
name = "${var.base_hostname}${format("%02d", count.index + 1)}-wosdsk01"
caching = var.caching_option
create_option = var.create_option
managed_disk_type = var.managed_disk_std_lrs
}
os_profile {
computer_name = "${var.base_hostname}${format("%02d", count.index + 1)}"
admin_username = var.username
admin_password = var.password
}
os_profile_windows_config {
enable_automatic_upgrades = false
provision_vm_agent = "true"
}
}
variables.tf is below:
# Declare env variable
variable "rg_name" {
type = string
}
variable "vnet_name" {
type = string
}
variable "subnet_name" {
type = string
}
variable "app_nsg" {
type = string
}
variable "vm_count" {
type = number
}
variable "base_hostname" {
type = string
}
variable "sto_acc_suffix" {
type = string
}
variable "sto_acc_tier_std" {
type = string
default = "Standard"
}
variable "sto_acc_rep_type_lrs" {
type = string
default = "LRS"
}
variable "vm_size" {
type = string
}
variable "vm_publisher" {
type = string
}
variable "vm_offer" {
type = string
}
variable "vm_sku" {
type = string
}
variable "vm_img_version" {
type = string
}
variable "username" {
type = string
}
variable "password" {
type = string
}
variable "caching_option" {
type = string
default = "ReadWrite"
}
variable "create_option" {
type = string
default = "FromImage"
}
variable "managed_disk_std_lrs" {
type = string
default = "Standard_LRS"
}
variable "managed_disk_prem_lrs" {
type = string
default = "Premium_LRS"
}
variable "allowed_source_ips" {
description = "List of ips from which inbound connection to VMs is allowed"
type = list(string)
}
I run below command for upgrading terraform config to 0.12 and above
terraform 0.12upgrade
Error:
Error: Syntax error in configuration file
on main.tf line 22, in data "azurerm_resource_group" "tf-rg-external":
22: name = var.rg_name
Error while parsing: At 22:10: Unknown token: 22:10 IDENT var.rg_name
Error: Syntax error in configuration file
on variable.tf line 3, in variable "rg_name":
3: type = string
Error while parsing: At 3:10: Unknown token: 3:10 IDENT string
Any idea, what is the problem? this would work if I don't run terrafom 0.12upgrade command. It is intriguing me why it is not working. I did same upgrade command in another terraform config and I get similar error there.
One observation. This IDENT error comes for first variable in main.tf and variable.tf file. Unable to correlate this error.
You're already using 0.12 syntax, the 0.12upgrade command expects to find 0.11 syntax and will attempt to automatically update it.
e.g. name = var.rg_name - note the lack of ${}
See https://www.terraform.io/docs/commands/0.12upgrade.html
The terraform 0.12upgrade command applies several automatic upgrade rules to help prepare a module that was written for Terraform v0.11 to be used with Terraform v0.12.
(Emphasis mine)

Resources