I wrote a script to create Azure VM using terraform. Script is flexible to take the OS as input. Now there are some attributes in azurerm_virtual_machine resource block which are specific to OS.
How to use a condition like if windows use os_profile_windows_config{} or if OS is linux use os_profile_linux_config{}.
Normal conditional statements didn't work as this attributes are not taking any values directly by using = .
resource "azurerm_virtual_machine" "vmdeploy" {
count = "${var.count_of_VMs}"
name = "${var.vm_name}-${count.index}"
resource_group_name = "${azurerm_resource_group.deployrg.name}"
availability_set_id = "${azurerm_availability_set.avset.id}"
location = "${azurerm_resource_group.deployrg.location}"
network_interface_ids = ["${element(azurerm_network_interface.nic.*.id, count.index)}"]
vm_size = "Standard_DS1_v2"
storage_image_reference{
publisher = "${var.OS_Image_Publisher}"
offer = "${var.OS_Image_Offer}"
sku = "${var.OS_Image_Sku}"
version = "latest"
}
storage_os_disk{
name = "${var.vm_name}-${count.index}-osdisk"
caching = "ReadWrite"
managed_disk_type = "Standard_LRS"
create_option = "FromImage"
}
storage_data_disk {
name = "${element(azurerm_managed_disk.mdisk.*.name, count.index)}"
managed_disk_id = "${element(azurerm_managed_disk.mdisk.*.id, count.index)}"
create_option = "Attach"
lun = 1
disk_size_gb = "${element(azurerm_managed_disk.mdisk.*.disk_size_gb, count.index)}"
}
os_profile {
computer_name = "${var.vm_name}-${count.index}"
admin_username = "XXXXXXXXXXXX"
admin_password = "XXXXXXXXXXXX"
}
os_profile_windows_config {
}
}
I am trying to find a way to use condition here to use respective config attribute based on OS version which is provided as input.
This is not possible pre terraform-0.12. This is possible with dynamic blocks in version 0.12.
provider "azurerm" {
version = "~>2.19.0"
features {}
}
variable "image" {
type = map
default = {
publisher = "Canonical"
offer = "UbuntuServer"
sku = "16.04-LTS"
version = "latest"
}
}
locals {
_is_microsoft = substr(lookup(var.image, "publisher", "value_not_declared"), 0, 9) == "Microsoft" ? true : false
is_linux = ! local._is_microsoft ? { empty = true } : {}
is_windows = local._is_microsoft ? { empty = true } : {}
}
resource "azurerm_resource_group" "rg" {
name = "rg"
location = "east us"
}
resource "azurerm_virtual_network" "rg" {
name = "-network"
address_space = ["10.0.0.0/16"]
location = azurerm_resource_group.rg.location
resource_group_name = azurerm_resource_group.rg.name
}
resource "azurerm_subnet" "subnet" {
name = "subnet"
resource_group_name = azurerm_resource_group.rg.name
virtual_network_name = azurerm_virtual_network.rg.name
address_prefixes = ["10.10.10.0/24"]
}
resource "azurerm_network_interface" "rg" {
name = "nic"
location = azurerm_resource_group.rg.location
resource_group_name = azurerm_resource_group.rg.name
ip_configuration {
name = "ipconfig"
subnet_id = azurerm_subnet.subnet.id
private_ip_address_allocation = "Dynamic"
}
}
resource "azurerm_virtual_machine" "rg" {
name = "-vm"
location = azurerm_resource_group.rg.location
resource_group_name = azurerm_resource_group.rg.name
network_interface_ids = [azurerm_network_interface.rg.id]
vm_size = "Standard_D2_v3"
storage_image_reference {
publisher = lookup(var.image, "publisher")
offer = lookup(var.image, "offer")
sku = lookup(var.image, "sku")
version = lookup(var.image, "version")
}
storage_os_disk {
name = "disk1"
caching = "ReadWrite"
create_option = "FromImage"
managed_disk_type = "Standard_LRS"
}
os_profile {
computer_name = "computer"
admin_username = "localadmin"
admin_password = "donotuserthispassword123!"
}
dynamic "os_profile_linux_config" {
for_each = local.is_linux
content {
disable_password_authentication = false
}
}
dynamic "os_profile_windows_config" {
for_each = local.is_windows
content {
provision_vm_agent = true
}
}
}
Note the azurerm team decided this was not a
good
idea and split out the resources into two different types. Use
azurerm_linux_virtual_machine or azurerm_windows_virtual_machine.
Build a module with a single interface then use a count to pick which
resource to build either windows or linux.
Related
What are you looking to accomplish?
To scale up or down the quantity of 'Resource VMs' in direct relation with their necessary 'Resource OS_disk'. For example, if we require to provision '5, 10, or 20' VMs we will require also to match the same '5, 10, or 20' OS Disks.
Currently, I know how to use count.index (see bellow code snippet) for the resource VM, but I don't know how to implement it for the resource OS_Disk, meaning that if we require to provision '200 VMs' I can define those '200 VMs' by setting that amount via the parameter count from the resource VM code block (see bellow code snippet), but I can't for the '200' OS_disk (disclaimer, once again because I don't know how to)
Do you have a code example to share?
resource "azurerm_network_interface" "network_card_resource" {
count = 1
name = "network_card_${count.index}"
location = "removed"
resource_group_name = removed
ip_configuration {
name = "internal"
subnet_id = removed.outputs.removed.subnet.removed.main.subnets["removed-XX.XX.XX.XX_XX"].id
private_ip_address_allocation = "Dynamic"
}
}
resource "azurerm_windows_virtual_machine" "vm_resource" {
count = 10
name = "vm_name_${count.index}"
resource_group_name = removed
location = "removed"
size = "Standard_D4_v3"
admin_username = var.admin_username
admin_password = var.admin_password
network_interface_ids = [
element(azurerm_network_interface.network_card_resource.*.id, count.index)
]
os_disk {
count = 10
name = "disk_name_${count.index}"
caching = "ReadWrite"
storage_account_type = "Standard_LRS"
resource_group_name = removed
disk_size_gb = 180
}
The above code failed to build the 10 OS disks via the count.index,
Is there an approach to tackle this?
It is not possible to add 10 OS disk for a particular VM , you can have only 1 OS disk Per VM and other than that you can attach data disks (2 disks for 1 VM VCPU).
So , as a solution you can use for_each instead of count for better functionality of the code and then you can use the below script to create the VM's with additional data disks as per your requirement:
In the below code I am creating 3 VM's with 1 OS disk and 5 Data disk each:
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" "test_subnet" {
name = "VM-subnet"
resource_group_name = data.azurerm_resource_group.example.name
virtual_network_name = azurerm_virtual_network.example.name
address_prefixes = ["10.0.0.0/24"]
}
resource "azurerm_public_ip" "myterraformpublicip" {
for_each = toset(var.instances)
name = "myPublicIP-${each.key}"
location = data.azurerm_resource_group.example.location
resource_group_name = data.azurerm_resource_group.example.name
allocation_method = "Dynamic"
}
resource "azurerm_network_interface" "myterraformnic" {
for_each= toset(var.instances)
name = "myNIC-${each.key}"
location = data.azurerm_resource_group.example.location
resource_group_name = data.azurerm_resource_group.example.name
ip_configuration {
name = "myNicConfiguration"
subnet_id = azurerm_subnet.test_subnet.id
private_ip_address_allocation = "Dynamic"
public_ip_address_id = azurerm_public_ip.myterraformpublicip[each.key].id
}
}
variable "instances" {
default = ["vm-test-1", "vm-test-2", "vm-test-3"]
}
variable "nb_disks_per_instance" {
default = 5
}
locals {
vm_datadiskdisk_count_map = { for k in toset(var.instances) : k => var.nb_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
}
]
])
}
resource "azurerm_windows_virtual_machine" "example" {
for_each = toset(var.instances)
name = "example-machine${each.key}"
resource_group_name = data.azurerm_resource_group.example.name
location = data.azurerm_resource_group.example.location
size = "Standard_F2"
admin_username = "adminuser"
admin_password = "P#$$w0rd1234!"
network_interface_ids = [azurerm_network_interface.myterraformnic[format("%s", each.key)].id]
os_disk {
name = "${each.key}-OSDISK"
caching = "ReadWrite"
storage_account_type = "Standard_LRS"
disk_size_gb = 180
}
source_image_reference {
publisher = "MicrosoftWindowsServer"
offer = "WindowsServer"
sku = "2016-Datacenter"
version = "latest"
}
}
resource "azurerm_managed_disk" "example" {
for_each = toset([for j in local.datadisk_lun_map : j.datadisk_name])
name = each.key
location = data.azurerm_resource_group.example.location
resource_group_name = data.azurerm_resource_group.example.name
storage_account_type = "Standard_LRS"
create_option = "Empty"
disk_size_gb = 10
}
resource "azurerm_virtual_machine_data_disk_attachment" "example" {
for_each = toset([for j in local.datadisk_lun_map : j.datadisk_name])
managed_disk_id = azurerm_managed_disk.example[each.key].id
virtual_machine_id = azurerm_windows_virtual_machine.example[element(split("_", each.key), 1)].id
lun = lookup(local.luns, each.key)
caching = "ReadWrite"
}
Output:
Matching the OS Disk with count is not required by providing another count inside the OS_disk Block :
For example, I created 2 VMs using terraform then its by default that 2 OS disk will also be created like below :
resource "azurerm_linux_virtual_machine" "myterraformvm" {
count = 2
name = "testpoc0${count.index + 1}"
location = data.azurerm_resource_group.example.location
resource_group_name = data.azurerm_resource_group.example.name
#network_interface_ids = azurerm_network_interface.myterraformnic.*.id
network_interface_ids = [element(azurerm_network_interface.myterraformnic.*.id, count.index + 1)]
size = "Standard_DS1_v2"
os_disk {
## count == not required here again as this is a child block inside the main VM resource block , so as many VM's will be created OS disk will also be created that many
name = "OsDisk${count.index + 1}"
caching = "ReadWrite"
storage_account_type = "Premium_LRS"
}
source_image_reference {
publisher = "Canonical"
offer = "UbuntuServer"
sku = "18.04-LTS"
version = "latest"
}
computer_name = "testpoc0${count.index}"
admin_username = "azureuser"
disable_password_authentication = true
admin_ssh_key {
username = "azureuser"
public_key = file("~/.ssh/id_rsa.pub")
}
}
I’m trying to create a VM in Azure using below config.
resource “azurerm_virtual_machine” “VM38” {
name = “VM38”
resource_group_name = data.azurerm_resource_group.myRG.name
location = data.azurerm_resource_group.myRG.location
vm_size = “Standard_F16s_v2”
delete_os_disk_on_termination = true
delete_data_disks_on_termination = true
os_profile {
computer_name = “vm38”
admin_username = “adminuser”
admin_password = “Password1234!”
custom_data = base64encode(data.cloudinit_config.hybrid_vm38_cloudinit_cfg.rendered)
}
os_profile_linux_config {
disable_password_authentication = false
}
storage_image_reference {
id = data.azurerm_image.my_image.id
}
depends_on = [aws_instance.vm12]
storage_os_disk {
name = “VMDisk”
create_option = “FromImage”
caching = “ReadWrite”
#disk_size_gb = 16
#os_type = “Linux”
#managed_disk_type = “Standard_LRS”
vhd_uri = var.vmVHDURI
}
network_interface_ids = [azurerm_network_interface.mgmtNwIntf.id, azurerm_network_interface.transportNwIntf.id]
}
When I execute terraform apply I’m getting below error…
Error: compute.VirtualMachinesClient#CreateOrUpdate: Failure sending request: StatusCode=0 – Original Error: autorest/azure: Service returned an error. Status= Code=“PropertyChangeNotAllowed” Message=“Changing property ‘osDisk.name’ is not allowed.” Target=“osDisk.name”
with azurerm_virtual_machine.VM38,
on az_virtual_machine.tf line 1, in resource “azurerm_virtual_machine” “VM38”:
1: resource “azurerm_virtual_machine” “VM38” {
Please let me know how to resolve this issue.
Terraform and Azure provider version details are given below:
Terraform v1.0.8
on linux_amd64
provider registry.terraform.io/hashicorp/azurerm v2.79.1
Thanks & Regards,
-Ravi
**In terraform.tfvars**
resourceGroupName = "myResourceGroup"
deviceImageName = "myDeviceImageName"
**In cloudinit_config.tf**
data "cloudinit_config" "hybrid_vm38_cloudinit_cfg" {
gzip = false
base64_encode = false
depends_on = [aws_instance.hybrid_vm12]
part {
filename = "cloud-config"
content_type = "text/cloud-config"
content = file("cloudinit/vm38_cloud_config.yaml")
}
part {
filename = "config-C8K.txt"
content_type = "text/cloud-boothook"
content = file("cloudinit/vm38_cloud_boothook.cfg")
}
}
**In az_resource_group.tf**
data "azurerm_resource_group" "vm38RG" {
name = var.resourceGroupName
}
**In az_image.tf**
data "azurerm_image" "deviceImage" {
name = var.deviceImageName
resource_group_name = data.azurerm_resource_group.vm38RG.name
}
**In az_virtual_network.tf**
resource "azurerm_virtual_network" "vm38VirtualNw" {
name = "vm38VirtualNw"
address_space = ["30.0.0.0/16"]
location = "eastus"
resource_group_name = data.azurerm_resource_group.vm38RG.name
tags = {
environment = "My virtual network"
}
}
**In az_subnet.tf**
resource "azurerm_subnet" "vm38MgmtSubnet" {
name = "vm38MgmtSubnet"
resource_group_name = data.azurerm_resource_group.vm38RG.name
virtual_network_name = azurerm_virtual_network.vm38VirtualNw.name
address_prefixes = ["30.0.11.0/24"]
}
resource "azurerm_subnet" "vm38TransportSubnet" {
name = "vm38TransportSubnet"
resource_group_name = data.azurerm_resource_group.vm38RG.name
virtual_network_name = azurerm_virtual_network.vm38VirtualNw.name
address_prefixes = ["30.0.12.0/24"]
}
**In az_network_interface.tf**
resource "azurerm_network_interface" "vm38MgmtNwIntf" {
name = "vm38MgmtNwIntf"
location = data.azurerm_resource_group.vm38RG.location
resource_group_name = data.azurerm_resource_group.vm38RG.name
ip_configuration {
name = "vm38MgmtPvtIP"
subnet_id = azurerm_subnet.vm38MgmtSubnet.id
private_ip_address_allocation = "Dynamic"
public_ip_address_id = azurerm_public_ip.vm38MgmtPublicIP.id
}
}
resource "azurerm_network_interface" "vm38TransportNwIntf" {
name = "vm38TransportNwIntf"
location = data.azurerm_resource_group.vm38RG.location
resource_group_name = data.azurerm_resource_group.vm38RG.name
ip_configuration {
name = "vm38TransportPvtIP"
subnet_id = azurerm_subnet.vm38TransportSubnet.id
private_ip_address_allocation = "Dynamic"
public_ip_address_id = azurerm_public_ip.vm38TransportPublicIP.id
}
}
**In az_virtual_machine.tf**
resource "azurerm_virtual_machine" "VM38" {
name = "VM38"
resource_group_name = data.azurerm_resource_group.vm38RG.name
location = data.azurerm_resource_group.vm38RG.location
vm_size = "Standard_F16s_v2"
delete_os_disk_on_termination = true
#delete_data_disks_on_termination = true
os_profile {
computer_name = "vm38"
admin_username = "adminuser"
admin_password = "Password1234!"
custom_data = base64encode(data.cloudinit_config.hybrid_vm38_cloudinit_cfg.rendered)
}
os_profile_linux_config {
disable_password_authentication = false
}
storage_image_reference {
id = data.azurerm_image.deviceImage.id
}
depends_on = [aws_instance.hybrid_vm12]
storage_os_disk {
name = "osDisk"
create_option = "FromImage"
caching = "ReadWrite"
#disk_size_gb = 16
#os_type = "Linux"
managed_disk_type = "Standard_LRS"
}
/*
storage_data_disk {
name = "vm38SecondaryDisk"
caching = "ReadWrite"
create_option = "Empty"
disk_size_gb = 2048
lun = 0
managed_disk_type = "Premium_LRS"
}
*/
network_interface_ids = [
azurerm_network_interface.vm38MgmtNwIntf.id,
azurerm_network_interface.vm38TransportNwIntf.id
]
}
You can't change the os_disk name while creating the VM. It should be "osdisk" or something starting with that.
I tested using the below code:
provider "azurerm" {
features {}
}
resource "azurerm_resource_group" "example" {
name = "ansuman-resources"
location = "West US 2"
}
resource "azurerm_virtual_network" "example" {
name = "ansuman-network"
address_space = ["10.0.0.0/16"]
location = "${azurerm_resource_group.example.location}"
resource_group_name = "${azurerm_resource_group.example.name}"
}
resource "azurerm_subnet" "example" {
name = "internal"
resource_group_name = "${azurerm_resource_group.example.name}"
virtual_network_name = "${azurerm_virtual_network.example.name}"
address_prefixes = ["10.0.2.0/24"]
}
resource "azurerm_network_interface" "example" {
name = "ansuman-nic"
location = "${azurerm_resource_group.example.location}"
resource_group_name = "${azurerm_resource_group.example.name}"
ip_configuration {
name = "testconfiguration1"
subnet_id = "${azurerm_subnet.example.id}"
private_ip_address_allocation = "Dynamic"
}
}
# we assume that this Custom Image already exists
data "azurerm_image" "custom" {
name = "ansumantestvm-image-20211007225625"
resource_group_name = "resourcegroup"
}
resource "azurerm_virtual_machine" "example" {
name = "ansuman-vm"
location = "${azurerm_resource_group.example.location}"
resource_group_name = "${azurerm_resource_group.example.name}"
network_interface_ids = ["${azurerm_network_interface.example.id}"]
vm_size = "Standard_F2"
# This means the OS Disk will be deleted when Terraform destroys the Virtual Machine
# NOTE: This may not be optimal in all cases.
delete_os_disk_on_termination = true
storage_image_reference {
id = "${data.azurerm_image.custom.id}"
}
storage_os_disk {
name = "osdisk"
caching = "ReadWrite"
create_option = "FromImage"
managed_disk_type = "Standard_LRS"
}
os_profile {
computer_name = "hostname"
admin_username = "testadmin"
admin_password = "Password1234!"
}
os_profile_windows_config {
}
}
Output:
Note: Please make sure while creating the image from the original VM , first generalize it . If its not generalized then VM created from the custom image will get stuck in creating state and will not be able to boot up.
If you want to change the osdisk name to something of your choice then as a solution try creating the managed os disk first from the image using create option "copy" or "import" and then attach the disk while creating the VM as creating managed disk from custom image is also not supported ,it can be only done for platform image or marketplace image . You can refer this GitHub issue and this Github issue.
Reference terraform code for similar issue to give custom name to osdisk created from platform image/ market place image which Charles Xu has done in this SO thread.
I am trying to create multiple Azure VM using for_each via terrform , I am able to create 2 NIC card but while defining NIC id in zurerm_windows_virtual_machine block , both VM are picking same NIC card (last one , index 1) and result is only VM is getting created and other got failed .
what would be logic for (network_interface_ids = azurerm_network_interface.az_nic[*].id) put that 1st vm will pick 1st NIC and second do so .
#---------------creating Network Interface for Windows VM's---------------
resource "azurerm_network_interface" "az_nic" {
count = length(var.vm_names)
name = "${var.vm_names[count.index]}_nic"
location = var.location
resource_group_name = data.azurerm_resource_group.Resource_group.name
ip_configuration {
name = var.vm_names[count.index]
subnet_id = data.azurerm_subnet.subnet.id
private_ip_address_allocation = "Dynamic"
}
}
resource "azurerm_windows_virtual_machine" "myvm" {
for_each = toset(var.vm_names)
name = each.value
resource_group_name = data.azurerm_resource_group.Resource_group.name
location = var.location
size = "Standard_D2s_v3"
admin_username = "abc"
admin_password = "uejehrikch123"
network_interface_ids = azurerm_network_interface.az_nic[*].id
source_image_reference {
publisher = "MicrosoftWindowsServer"
offer = "WindowsServer"
sku = "2016-Datacenter"
version = "latest"
}
os_disk {
caching = "ReadWrite"
storage_account_type = "Standard_LRS"
}
You can add the count parameter in the resource "azurerm_windows_virtual_machine" instead of mixing the count and for_each.
Suppose you have
variable "vm_names" {
default = ["vm1", "vm2"]
}
then you can change the resource .tf file like this:
resource "azurerm_windows_virtual_machine" "myvm" {
count = length(var.vm_names)
name = element(var.vm_names,count.index)
resource_group_name = data.azurerm_resource_group.Resource_group.name
location = var.location
size = "Standard_D2s_v3"
admin_username = "abc"
admin_password = "uejehrikch123"
network_interface_ids = [element(azurerm_network_interface.az_nic.*.id, count.index)]
source_image_reference {
publisher = "MicrosoftWindowsServer"
offer = "WindowsServer"
sku = "2016-Datacenter"
version = "latest"
}
os_disk {
caching = "ReadWrite"
storage_account_type = "Standard_LRS"
}
Trying to create a VM in Terraform with and without an availability set. The idea is to use a template where if the availability set name is not provided, it defaults to empty, then the VM will not be added to the availability set. I did try using "count", as in 'count = var.avail_set != "" ? 1 : 0', but that did not work exactly as I wanted even though I had two sections that executed conditionally, I needed the name of the VM resource to be the same so I could add log analytics and backup later in the code. . Please see my code below:
name = "${var.resource_group_name}"
}
data azurerm_subnet sndata02 {
name = "${var.subnet_name}"
resource_group_name = "${var.core_resource_group_name}"
virtual_network_name = "${var.virtual_network_name}"
}
data azurerm_availability_set availsetdata02 {
name = "${var.availability_set_name}"
resource_group_name = "${var.resource_group_name}"
}
data azurerm_backup_policy_vm bkpoldata02 {
name = "${var.backup_policy_name}"
recovery_vault_name = "${var.recovery_services_vault_name}"
resource_group_name = "${var.core_resource_group_name}"
}
data azurerm_log_analytics_workspace law02 {
name = "${var.log_analytics_workspace_name}"
resource_group_name = "${var.core_resource_group_name}"
}
#===================================================================
# Create NIC
#===================================================================
resource "azurerm_network_interface" "vmnic02" {
name = "nic${var.virtual_machine_name}"
location = "${data.azurerm_resource_group.rgdata02.location}"
resource_group_name = "${var.resource_group_name}"
ip_configuration {
name = "ipcnfg${var.virtual_machine_name}"
subnet_id = "${data.azurerm_subnet.sndata02.id}"
private_ip_address_allocation = "Static"
private_ip_address = "${var.private_ip}"
}
}
#===================================================================
# Create VM with Availability Set
#===================================================================
resource "azurerm_virtual_machine" "vm02" {
count = var.avail_set != "" ? 1 : 0
depends_on = [azurerm_network_interface.vmnic02]
name = "${var.virtual_machine_name}"
location = "${data.azurerm_resource_group.rgdata02.location}"
resource_group_name = "${var.resource_group_name}"
network_interface_ids = [azurerm_network_interface.vmnic02.id]
vm_size = "${var.virtual_machine_size}"
availability_set_id = "${data.azurerm_availability_set.availsetdata02.id}"
tags = var.tags
# This means the OS Disk will be deleted when Terraform destroys the Virtual Machine
# NOTE: This may not be optimal in all cases.
delete_os_disk_on_termination = true
os_profile {
computer_name = "${var.virtual_machine_name}"
admin_username = "__VMUSER__"
admin_password = "__VMPWD__"
}
os_profile_linux_config {
disable_password_authentication = false
}
storage_image_reference {
id = "${var.image_id}"
}
storage_os_disk {
name = "${var.virtual_machine_name}osdisk"
caching = "ReadWrite"
create_option = "FromImage"
managed_disk_type = "Premium_LRS"
os_type = "Linux"
}
boot_diagnostics {
enabled = true
storage_uri = "${var.boot_diagnostics_uri}"
}
}
#===================================================================
# Create VM without Availability Set
#===================================================================
resource "azurerm_virtual_machine" "vm03" {
count = var.avail_set == "" ? 1 : 0
depends_on = [azurerm_network_interface.vmnic02]
name = "${var.virtual_machine_name}"
location = "${data.azurerm_resource_group.rgdata02.location}"
resource_group_name = "${var.resource_group_name}"
network_interface_ids = [azurerm_network_interface.vmnic02.id]
vm_size = "${var.virtual_machine_size}"
# availability_set_id = "${data.azurerm_availability_set.availsetdata02.id}"
tags = var.tags
# This means the OS Disk will be deleted when Terraform destroys the Virtual Machine
# NOTE: This may not be optimal in all cases.
delete_os_disk_on_termination = true
os_profile {
computer_name = "${var.virtual_machine_name}"
admin_username = "__VMUSER__"
admin_password = "__VMPWD__"
}
os_profile_linux_config {
disable_password_authentication = false
}
storage_image_reference {
id = "${var.image_id}"
}
storage_os_disk {
name = "${var.virtual_machine_name}osdisk"
caching = "ReadWrite"
create_option = "FromImage"
managed_disk_type = "Premium_LRS"
os_type = "Linux"
}
boot_diagnostics {
enabled = true
storage_uri = "${var.boot_diagnostics_uri}"
}
}
#===================================================================
# Set Monitoring and Log Analytics Workspace
#===================================================================
resource "azurerm_virtual_machine_extension" "oms_mma02" {
count = var.bootstrap ? 1 : 0
name = "${var.virtual_machine_name}-OMSExtension"
virtual_machine_id = "${azurerm_virtual_machine.vm02.id}"
publisher = "Microsoft.EnterpriseCloud.Monitoring"
type = "OmsAgentForLinux"
type_handler_version = "1.8"
auto_upgrade_minor_version = true
settings = <<SETTINGS
{
"workspaceId" : "${data.azurerm_log_analytics_workspace.law02.workspace_id}"
}
SETTINGS
protected_settings = <<PROTECTED_SETTINGS
{
"workspaceKey" : "${data.azurerm_log_analytics_workspace.law02.primary_shared_key}"
}
PROTECTED_SETTINGS
}
#===================================================================
# Associate VM to Backup Policy
#===================================================================
resource "azurerm_backup_protected_vm" "vm02" {
count = var.bootstrap ? 1 : 0
resource_group_name = "${var.core_resource_group_name}"
recovery_vault_name = "${var.recovery_services_vault_name}"
source_vm_id = "${azurerm_virtual_machine.vm02.id}"
backup_policy_id = "${data.azurerm_backup_policy_vm.bkpoldata02.id}"
}
The count property only controls the number of resources, for you, it means to create the VM or not, it won't change the configuration of the VM. It's not the right way for your situation.
As I think, you can use the condition expression for the VM property availability_set_id like this:
availability_set_id = var.avail_set != "" ? "${data.azurerm_availability_set.availsetdata02.id}" : ""
Error Message
I get the following error message when executing terraform apply:
Error: Error Creating/Updating Virtual Network "CTI-NETWORK" (Resource Group "CTI-RESOURCES"): network.VirtualNetworksClient#CreateOrUpdate: Failure sending request: StatusCode=400 -- Original Error: Code="InUseSubnetCannotBeDeleted" Message="Subnet CTI-PRD is in use by /subscriptions/d92e8f07-e127-4015-b67a-a547af76fdfc/resourceGroups/CTI-RESOURCES/providers/Microsoft.Network/networkInterfaces/CTI-NIC-PRD1/ipConfigurations/CTI-IP-PRD1 and cannot be deleted. In order to delete the subnet, delete all the resources within the subnet. See aka.ms/deletesubnet." Details=[]
I assume I've got a dependency mixed up but cant seem to figure it out.
Code Snippet
Content of main.tf
provider "azurerm" {
version = "=1.38.0"
subscription_id = "d92e8f07-e127-4015-b67a-a547af76fdfc"
}
resource "azurerm_resource_group" "resourcegroup" {
name = "${var.prefix}RESOURCES"
location = var.location
}
resource "azurerm_virtual_network" "network" {
name = "${var.prefix}NETWORK"
resource_group_name = azurerm_resource_group.resourcegroup.name
address_space = ["10.0.0.0/16"]
location = var.location
}
resource "azurerm_subnet" "prd-subnet" {
name = "${var.prefix}PRD"
resource_group_name = azurerm_resource_group.resourcegroup.name
virtual_network_name = azurerm_virtual_network.network.name
address_prefix = "10.0.0.0/24"
}
resource "azurerm_subnet" "tst-subnet" {
name = "${var.prefix}TST"
resource_group_name = azurerm_resource_group.resourcegroup.name
virtual_network_name = azurerm_virtual_network.network.name
address_prefix = "10.0.1.0/24"
}
resource "azurerm_public_ip" "ip-prd-1" {
name = "${var.prefix}PIP-PRD1"
resource_group_name = azurerm_resource_group.resourcegroup.name
location = var.location
allocation_method = "Dynamic"
domain_name_label = "vm-prd-1"
}
resource "azurerm_network_interface" "nic-prd-1" {
name = "${var.prefix}NIC-PRD1"
resource_group_name = azurerm_resource_group.resourcegroup.name
location = var.location
ip_configuration {
name = "${var.prefix}IP-PRD1"
subnet_id = azurerm_subnet.prd-subnet.id
private_ip_address_allocation = "Dynamic"
public_ip_address_id = azurerm_public_ip.ip-prd-1.id
}
}
resource "azurerm_virtual_machine" "vm-prd-1" {
name = "${var.prefix}VM-PRD-1"
location = var.location
resource_group_name = azurerm_resource_group.resourcegroup.name
network_interface_ids = [azurerm_network_interface.nic-prd-1.id]
vm_size = var.size
delete_os_disk_on_termination = true
delete_data_disks_on_termination = true
storage_image_reference {
publisher = "credativ"
offer = "Debian"
sku = "9-backports"
version = "latest"
}
storage_os_disk {
name = "lin-disk-1"
caching = "ReadWrite"
create_option = "FromImage"
managed_disk_type = "Standard_LRS"
}
os_profile {
computer_name = "${var.prefix}IP-PRD1"
admin_username = "ADM-ADV"
admin_password = "!!W0rksh0p"
}
os_profile_linux_config {
disable_password_authentication = false
}
tags = {
environment = "Production"
application = "CTI Core"
}
}
resource "azurerm_public_ip" "ip-prd-2" {
name = "${var.prefix}PIP-PRD-2"
resource_group_name = azurerm_resource_group.resourcegroup.name
location = var.location
allocation_method = "Dynamic"
domain_name_label = "vm-prd-2"
}
resource "azurerm_network_interface" "nic-prd-2" {
name = "${var.prefix}NIC-PRD-2"
resource_group_name = azurerm_resource_group.resourcegroup.name
location = var.location
ip_configuration {
name = "${var.prefix}IP-PRD-2"
subnet_id = azurerm_subnet.prd-subnet.id
private_ip_address_allocation = "Dynamic"
public_ip_address_id = azurerm_public_ip.ip-prd-2.id
}
}
resource "azurerm_virtual_machine" "vm-prd-chef" {
name = "${var.prefix}VM-PRD-CHEF"
location = var.location
resource_group_name = azurerm_resource_group.resourcegroup.name
network_interface_ids = [azurerm_network_interface.nic-prd-2.id]
vm_size = var.size
delete_os_disk_on_termination = true
delete_data_disks_on_termination = true
storage_image_reference {
publisher = "Canonical"
offer = "UbuntuServer"
sku = "18.04-LTS"
version = "latest"
}
storage_os_disk {
name = "lin-disk-2"
caching = "ReadWrite"
create_option = "FromImage"
managed_disk_type = "Standard_LRS"
}
os_profile {
computer_name = "${var.prefix}IP-PRD-CHEF"
admin_username = "XXX"
admin_password = "XXX"
}
os_profile_linux_config {
disable_password_authentication = false
}
tags = {
environment = "Production"
application = "CTI Service"
}
provisioner "remote-exec" {
inline = [
"touch /root/test.txt"
]
}
}
Content of variables.tf
variable "prefix" {
type = string
default = "CTI-"
description = "Prefix of the resources"
}
variable "location" {
type = string
default = "westeurope"
description = "Location of the resources"
}
variable "size" {
type = string
default = "Standard_A1_v2"
description = "Size of the virtual machines"
}
Thanks for you help!
With the message you provided, you want to create another VM in the existing subnet of the Vnet. So you need to use the data resource instead of the resource format. Change your Terraform code like this:
Change:
resource "azurerm_virtual_network" "network" {
name = "${var.prefix}NETWORK"
resource_group_name = azurerm_resource_group.resourcegroup.name
address_space = ["10.0.0.0/16"]
location = var.location
}
resource "azurerm_subnet" "prd-subnet" {
name = "${var.prefix}PRD"
resource_group_name = azurerm_resource_group.resourcegroup.name
virtual_network_name = azurerm_virtual_network.network.name
address_prefix = "10.0.0.0/24"
}
Into:
data "azurerm_virtual_network" "network" {
name = "${var.prefix}NETWORK"
resource_group_name = azurerm_resource_group.resourcegroup.name
}
data "azurerm_subnet" "prd-subnet" {
name = "${var.prefix}PRD"
virtual_network_name = data.azurerm_virtual_network.network.name
resource_group_name = azurerm_resource_group.resourcegroup.name
}
resource "azurerm_network_interface" "nic-prd-1" {
name = "${var.prefix}NIC-PRD1"
resource_group_name = azurerm_resource_group.resourcegroup.name
location = var.location
ip_configuration {
name = "${var.prefix}IP-PRD1"
subnet_id = data.azurerm_subnet.prd-subnet.id
private_ip_address_allocation = "Dynamic"
public_ip_address_id = azurerm_public_ip.ip-prd-1.id
}
}
The Terraform data will quote the existing resource and do not change them. If the other subnet tst-subnet is also existing, you can change it like above yourself.