Terraform - Azure - Create VM in availability set conditionally - azure

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}" : ""

Related

Need help to create Terraform code where user has an option to create Azure VM from Marketplace image or specify a custom VHD from Storage Account

We have a very specific requirement where some of the Vendors provides their images from Azure Marketplace and some just provide the .vhd
I need to build a terraform code where user should have an option to either create a VM based out of Azure Marketplace image, or he should be able provide source_uri of the VHD to create a VM.
For now I have the codes ready to create a VM from .vdh file,
resource "azurerm_virtual_machine" "this" {
name = var.name
location = var.location
resource_group_name = var.resource_group_name
vm_size = var.size
network_interface_ids = [azurerm_network_interface.this.id]
delete_os_disk_on_termination = true
delete_data_disks_on_termination = true
tags = var.tags
availability_set_id = var.availability_set_id == "" ? null : var.availability_set_id
resource "azurerm_managed_disk" "os" {
name = var.os_disk_name
location = "${var.location}"
resource_group_name = var.resource_group_name
os_type = "Linux"
storage_account_type = "Standard_LRS"
create_option = "Import"
storage_account_id = var.storage_account_id
source_uri = var.source_uri
disk_size_gb = var.disk_size_gb
}
# attach the managed disk, created from the imported vhd.
storage_os_disk {
name = join("", [var.name, "-", var.os_disk_name])
os_type = "Linux"
managed_disk_id = azurerm_managed_disk.os.id
managed_disk_type = "Standard_LRS"
caching = "ReadWrite"
create_option = "Attach"
}
os_profile_linux_config {
disable_password_authentication = false
}
}
The default option should be spin up a VM from Azure Marketplace. Can this be archived via variables
You can check the list of VM's image based on publishers available in the Azure Marketplace.
az vm image list --output table --all --publisher center-for-internet-security-inc.
I am taking the below image from Azure MarketPlace as a reference:
You can find your images based on offer, SKU, Publisher on your requirement. Refer to this MS Document for more info.
You can use this terraform code to create Azure VM from Marketplace image:
main.tf
provider "azurerm" {
features{}
}
data "azurerm_resource_group" "main" {
name = "${var.resource_group_name}"
}
resource "azurerm_virtual_network" "main" {
name = "${var.prefix}-network"
address_space = ["10.0.0.0/16"]
location = data.azurerm_resource_group.main.location
resource_group_name = data.azurerm_resource_group.main.name
}
resource "azurerm_subnet" "internal" {
name = "internal"
resource_group_name = data.azurerm_resource_group.main.name
virtual_network_name = azurerm_virtual_network.main.name
address_prefixes = ["10.0.2.0/24"]
}
resource "azurerm_network_interface" "main" {
name = "${var.prefix}-nic"
location = data.azurerm_resource_group.main.location
resource_group_name = data.azurerm_resource_group.main.name
ip_configuration {
name = "testconfiguration1"
subnet_id = azurerm_subnet.internal.id
private_ip_address_allocation = "Dynamic"
}
}
resource "azurerm_virtual_machine" "main" {
name = "${var.prefix}-vm"
location = data.azurerm_resource_group.main.location
resource_group_name = data.azurerm_resource_group.main.name
network_interface_ids = [azurerm_network_interface.main.id]
admin_username = "adminuser"
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.version1}"
}
plan {
publisher = "${var.publisher}"
product = "${var.offer}"
name = "cis-ubuntu2004-l1""
}
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
}
tags = {
environment = "staging"
}
}
variable.tf
variable "resource_group_name" {
default = "v-XXXXX-XXXXX"
}
variable "prefix" {
default = "tfvmex"
}
variable "publisher" {
default="center-for-internet-security-inc"
}
variable "offer" {
default = "cis-ubuntu-linux-2004-l1"
}
variable "sku" {
default = "cis-ubuntu2004-l1povw"
}
variable "version1" {
default="1.1.9"
}
Due to somepolicy appiled in my subscription so i am not able to test it but yes you can test in your enviorment.
You can refer this document for the same requirement.

Getting error PropertyChangeNotAllowed while creating VM in Azure

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.

How to skip storage data disk creation when value is 0 during VMSS creation through Terraform

I've tried and successfully created VMSS with os_disk and data_disk together. but i've requirement like when value of "data_disk==0" then i need to skip the creation of Data_disk. I've tried with value 0 but its clearly asking me to set value between(1-32767) . Here is my successful code
provider "azurerm" {
features{}
}
resource "azurerm_resource_group" "vmss" {
name = var.resourcegroup
location = var.location
}
resource "azurerm_windows_virtual_machine_scale_set" "vmss" {
name = var.vmss_name
resource_group_name = azurerm_resource_group.vmss.name
location = azurerm_resource_group.vmss.location
sku = var.vm_sku
instances = var.instancescount
computer_name_prefix = var.computer_name_prefix
admin_password = var.vmpassword
admin_username = var.vmusername
provision_vm_agent = true
overprovision = false
source_image_reference {
publisher = var.publisher
offer = var.offer
sku = var.os_sku
version = var.image_version
}
os_disk {
storage_account_type = var.os_disk_type
caching = "ReadWrite"
disk_size_gb = var.os_disk_size
}
data_disk{
lun = 1
storage_account_type = var.data_disk_type
caching = "ReadWrite"
disk_size_gb = var.data_disk_size
}
winrm_listener {
protocol = "Http"
}
additional_unattend_content{
content = "<AutoLogon><Password><Value>${var.vmpassword}</Value></Password><Enabled>true</Enabled><LogonCount>1</LogonCount><Username>${var.vmusername}</Username></AutoLogon>"
setting = "AutoLogon"
}
# Unattend config is to enable basic auth in WinRM, required for the provisioner stage.
additional_unattend_content {
setting = "FirstLogonCommands"
content = file("./files/FirstLogonCommands.xml")
}
network_interface {
name = "${var.computer_name_prefix}-profile"
primary = true
ip_configuration {
name = "${var.computer_name_prefix}-IPConfig"
primary = true
subnet_id = var.subnet
}
}
}
Can anyone help me to skip the data_disk creation when the value is 0.
Thanks in Advance.
Thanks,
Siva
In this case, you could use Conditional Expressions of the format condition ? true_val : false_val
declare a variable like this,
variable "select_data_disk" {
description = "conditionally creating vmss with data disk"
default = true // when the var is true, data disk is selected; when the var is false, data disk is not selected.
}
Then create the two resource "azurerm_windows_virtual_machine_scale_set" "example1" and resource "azurerm_windows_virtual_machine_scale_set" "example2". One VMSS resource includes the data disk block, another does not include the data disk block. Use count = var.select_data_disk ? 0 : 1 in each resource.
Example
variable "select_data_disk" {
description = "conditionally creating vmss with data disk"
default = true // when the var is true, data disk is selected; when the var is false, data disk is not selected.
}
...
resource "azurerm_windows_virtual_machine_scale_set" "example" {
count = var.select_data_disk ? 1 : 0
name = "myvmss"
resource_group_name = azurerm_resource_group.example.name
location = azurerm_resource_group.example.location
sku = "Standard_F2"
instances = 1
admin_password = "P#55w0rd1234!"
admin_username = "adminuser"
source_image_reference {
publisher = "MicrosoftWindowsServer"
offer = "WindowsServer"
sku = "2016-Datacenter-Server-Core"
version = "latest"
}
os_disk {
storage_account_type = "Standard_LRS"
caching = "ReadWrite"
}
data_disk{
lun = 1
storage_account_type = "Standard_LRS" //Standard_LRS, StandardSSD_LRS, Premium_LRS and UltraSSD_LRS.
caching = "ReadWrite"
disk_size_gb = 1
}
network_interface {
name = "example"
primary = true
ip_configuration {
name = "internal"
primary = true
subnet_id = azurerm_subnet.internal.id
}
}
}
resource "azurerm_windows_virtual_machine_scale_set" "example1" {
count = var.select_data_disk ? 0 : 1
name = "myvmss"
resource_group_name = azurerm_resource_group.example.name
location = azurerm_resource_group.example.location
sku = "Standard_F2"
instances = 1
admin_password = "P#55w0rd1234!"
admin_username = "adminuser"
source_image_reference {
publisher = "MicrosoftWindowsServer"
offer = "WindowsServer"
sku = "2016-Datacenter-Server-Core"
version = "latest"
}
os_disk {
storage_account_type = "Standard_LRS"
caching = "ReadWrite"
}
network_interface {
name = "example"
primary = true
ip_configuration {
name = "internal"
primary = true
subnet_id = azurerm_subnet.internal.id
}
}
}

How to use Conditional Attributes in Terraform

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.

The azurerm_virtual_machine is not displaying in the Terraform plan

I am using an existing template from github and have modified it a little bit. When I terraform.exe plan it says it will deploy 4 resources (NIC, NSG, VM-SA, and Resource Group).
I am trying to deploy a VM and have it joined to an existing VNet.
I have removed the NIC to see if it would add the windows VM for deployment and it does not
main.tf
# Configure the Microsoft Azure Provider
provider "azurerm" {
subscription_id = "************************************"
tenant_id = "************************************"
client_id = "************************************"
client_secret = "************************************"
}
module "os" {
source = "./os"
vm_os_simple = "${var.vm_os_simple}"
}
resource "azurerm_resource_group" "vm" {
name = "${var.resource_group_name}"
location = "${var.location}"
tags = "${var.tags}"
}
resource "random_id" "vm-sa" {
keepers = {
vm_hostname = "${var.vm_hostname}"
}
byte_length = 6
}
resource "azurerm_network_security_group" "nsg" {
name = "${var.network_security_group}"
location = "${var.location}"
resource_group_name = "${var.resource_group_name}"
}
resource "azurerm_storage_account" "vm-sa" {
count = "${var.boot_diagnostics == "true" ? 1 : 0}"
name = "bootdiag${lower(random_id.vm-sa.hex)}"
resource_group_name = "${azurerm_resource_group.vm.name}"
location = "${var.location}"
account_tier = "${element(split("_", var.boot_diagnostics_sa_type),0)}"
account_replication_type = "${element(split("_", var.boot_diagnostics_sa_type),1)}"
tags = "${var.tags}"
}
resource "azurerm_virtual_machine" "vm-windows" {
count = "${((var.is_windows_image == "true" || contains(list("${var.vm_os_simple}","${var.vm_os_offer}"), "Windows")) && var.data_disk == "false") ? var.nb_instances : 0}"
name = "${var.vm_hostname}${count.index}"
location = "${var.location}"
resource_group_name = "${azurerm_resource_group.vm.name}"
vm_size = "${var.vm_size}"
network_interface_ids = ["${element(azurerm_network_interface.vm.*.id, count.index)}"]
delete_os_disk_on_termination = "${var.delete_os_disk_on_termination}"
storage_image_reference {
id = "${var.vm_os_id}"
publisher = "${var.vm_os_id == "" ? coalesce(var.vm_os_publisher, module.os.calculated_value_os_publisher) : ""}"
offer = "${var.vm_os_id == "" ? coalesce(var.vm_os_offer, module.os.calculated_value_os_offer) : ""}"
sku = "${var.vm_os_id == "" ? coalesce(var.vm_os_sku, module.os.calculated_value_os_sku) : ""}"
version = "${var.vm_os_id == "" ? var.vm_os_version : ""}"
}
storage_os_disk {
name = "osdisk-${var.vm_hostname}-${count.index}"
create_option = "FromImage"
caching = "ReadWrite"
managed_disk_type = "${var.storage_account_type}"
}
os_profile {
computer_name = "${var.vm_hostname}${count.index}"
admin_username = "${var.admin_username}"
admin_password = "${var.admin_password}"
}
tags = "${var.tags}"
os_profile_windows_config {
provision_vm_agent = true
}
boot_diagnostics {
enabled = "${var.boot_diagnostics}"
storage_uri = "${var.boot_diagnostics == "true" ? join(",", azurerm_storage_account.vm-sa.*.primary_blob_endpoint) : "" }"
}
}
#refer to a subnet
data "azurerm_subnet" "test" {
name = "SubnetName"
virtual_network_name = "VNetName"
resource_group_name = "VNetresourceGroupName"
}
resource "azurerm_network_interface" "vm" {
count = "${var.nb_instances}"
name = "nic-${var.vm_hostname}-${count.index}"
location = "${azurerm_resource_group.vm.location}"
resource_group_name = "${azurerm_resource_group.vm.name}"
network_security_group_id = "${azurerm_network_security_group.nsg.id}"
ip_configuration {
name = "ipconfig${count.index}"
subnet_id = "${data.azurerm_subnet.test.id}"
private_ip_address_allocation = "Dynamic"
}
tags = "${var.tags}"
}
Expected results should be Deploy a VM, Storage Account, Network Security Group and Nic that is joined to an existing VNet
To create an Azure VM through Terraform, you can see the whole steps in Create a complete Linux virtual machine infrastructure in Azure with Terraform, it's a Linux VM, but you can change the image into windows and the os_profile_linux_config into os_profile_windows_config.
In an existing Vnet, you can use the Terraform data to quote the Vnet as you provide:
data "azurerm_subnet" "existing" {
name = "SubnetName"
virtual_network_name = "VNetName"
resource_group_name = "VNetresourceGroupName"
}
resource "azurerm_network_interface" "myterraformnic" {
name = "myNIC"
location = "eastus"
resource_group_name = "${azurerm_resource_group.myterraformgroup.name}"
network_security_group_id = "${azurerm_network_security_group.myterraformnsg.id}"
ip_configuration {
name = "myNicConfiguration"
subnet_id = "${data.azurerm_subnet.existing.id}"
private_ip_address_allocation = "Dynamic"
public_ip_address_id = "${azurerm_public_ip.myterraformpublicip.id}"
}
tags {
environment = "Terraform Demo"
}
}
The whole Terraform code here and you can change the information about the VM as you want.
# Configure the Microsoft Azure Provider
provider "azurerm" {
subscription_id = "xxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
client_id = "xxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
client_secret = "xxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
tenant_id = "xxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
}
# Create a resource group if it doesn’t exist
resource "azurerm_resource_group" "myterraformgroup" {
name = "myResourceGroup"
location = "eastus"
tags {
environment = "Terraform Demo"
}
}
# the existing subnet of the virtual network
data "azurerm_subnet" "existing" {
name = "SubnetName"
virtual_network_name = "VNetName"
resource_group_name = "VNetresourceGroupName"
}
# Create public IPs
resource "azurerm_public_ip" "myterraformpublicip" {
name = "myPublicIP"
location = "eastus"
resource_group_name = "${azurerm_resource_group.myterraformgroup.name}"
allocation_method = "Dynamic"
tags {
environment = "Terraform Demo"
}
}
# Create Network Security Group and rule
resource "azurerm_network_security_group" "myterraformnsg" {
name = "myNetworkSecurityGroup"
location = "eastus"
resource_group_name = "${azurerm_resource_group.myterraformgroup.name}"
security_rule {
name = "RDP"
priority = 1001
direction = "Inbound"
access = "Allow"
protocol = "Tcp"
source_port_range = "*"
destination_port_range = "3306"
source_address_prefix = "*"
destination_address_prefix = "*"
}
tags {
environment = "Terraform Demo"
}
}
# Create network interface
resource "azurerm_network_interface" "myterraformnic" {
name = "myNIC"
location = "eastus"
resource_group_name = "${azurerm_resource_group.myterraformgroup.name}"
network_security_group_id = "${azurerm_network_security_group.myterraformnsg.id}"
ip_configuration {
name = "myNicConfiguration"
subnet_id = "${data.azurerm_subnet.existing.id}"
private_ip_address_allocation = "Dynamic"
public_ip_address_id = "${azurerm_public_ip.myterraformpublicip.id}"
}
tags {
environment = "Terraform Demo"
}
}
# Generate random text for a unique storage account name
resource "random_id" "randomId" {
keepers = {
# Generate a new ID only when a new resource group is defined
resource_group = "${azurerm_resource_group.myterraformgroup.name}"
}
byte_length = 8
}
# Create storage account for boot diagnostics
resource "azurerm_storage_account" "mystorageaccount" {
name = "diag${random_id.randomId.hex}"
resource_group_name = "${azurerm_resource_group.myterraformgroup.name}"
location = "eastus"
account_tier = "Standard"
account_replication_type = "LRS"
tags {
environment = "Terraform Demo"
}
}
# Create virtual machine
resource "azurerm_virtual_machine" "myterraformvm" {
name = "myVM"
location = "eastus"
resource_group_name = "${azurerm_resource_group.myterraformgroup.name}"
network_interface_ids = ["${azurerm_network_interface.myterraformnic.id}"]
vm_size = "Standard_DS1_v2"
storage_os_disk {
name = "myOsDisk"
caching = "ReadWrite"
create_option = "FromImage"
managed_disk_type = "Premium_LRS"
}
storage_image_reference {
publisher = "MicrosoftWindowsServer"
offer = "WindowsServer"
sku = "2016-Datacenter-Server-Core-smalldisk"
version = "latest"
}
os_profile {
computer_name = "myvm"
admin_username = "azureuser"
admin_password = "Passwd#!1234"
}
os_profile_windows_config {
provision_vm_agent = true
}
boot_diagnostics {
enabled = "true"
storage_uri = "${azurerm_storage_account.mystorageaccount.primary_blob_endpoint}"
}
tags {
environment = "Terraform Demo"
}
}
For more details, see Azure Virtual Machine in Terraform.

Resources