I am trying to create a number of VMs in Azure using the for_each loop. Let's say VMs 1-100. However, there will be requests to delete i.e. VM number 50.
I have 2 problems with this:
terraform_azure> terraform state list
module.edit_vms.azurerm_linux_virtual_machine.test_seat["test-vm-1"]
terraform state rm module.edit_vms.azurerm_linux_virtual_machine.test_seat["test-vm-1"]
zsh: no matches found: module.edit_vms.azurerm_linux_virtual_machine.test_seat[test-vm-1]
When I try to delete the VM 50 from Terraform state I get the error above. I don't understand why am I seeing no matches found when the resource was listed under terraform state list command
Is there a way to delete the VM number 50 and set the VM count from 1 -> 101 and to prevent terraform from re-creating VM number 50? If deleting the VM from state file is not a good practice it would be even better if I could specify in the code that I want it destroyed and not recreated on future apply.
This is my variables.tf
variable "edit_seat_spec" {
description = "VM details"
type = list
default = [{
resource_group_name = "my_rg"
server_name = "test-vm"
server_size = "Standard_B2s"
location = "East US"
vnet = "test_vnet"
subnet_name = "default"
username = "username"
password = "password"
vm_count = "4"
}]
}
And main.tf
locals{
edit_seat = [
for edit in var.edit_seat_spec : [
for i in range(1, edit.vm_count) : {
name = "${edit.server_name}-${i}"
resource_group = edit.resource_group_name
vnet = edit.vnet
nic = "${edit.server_name}-${i}-nic"
location = edit.location
subnet_name = edit.subnet_name
size = edit.server_size
admin_username = edit.username
admin_password = edit.password
}
]
]
}
locals {
edit_vm = flatten(local.edit_seat)
}
resource "azurerm_linux_virtual_machine" "vm" {
for_each = {for edit in local.edit_vm: edit.name => edit}
name = each.value.name
resource_group_name = each.value.resource_group
location = each.value.location
size = each.value.size
admin_username = each.value.admin_username
admin_password = each.value.admin_password
disable_password_authentication = false
network_interface_ids = [azurerm_network_interface.edit_seat_nic[each.key].id]
os_disk {
caching = "ReadWrite"
storage_account_type = "Standard_LRS"
}
source_image_reference {
publisher = "Canonical"
offer = "UbuntuServer"
sku = "16.04-LTS"
version = "latest"
}
}
CodePudding user response:
You can filter elements in a for
, with the help of if
statement.
Also mind that, range
won't include the upper limit:
The interpretation of
limit
depends on the direction ofstep
: for a positive step, the sequence is complete when the next number is greater than or equal tolimit
.
So, if you want a range from 1 to 100, you will need a range(1, var.variable_that_contains_100 1)
.
And so, if you want to skip one element in the stepping from 1 to 100, you'll need your upper limit to be at 102.
Here is an example, requesting 5 elements, skipping 3, for brevity:
variable "vm_count" {
default = 5
}
output "test" {
value = [for i in range(1, var.vm_count 2) : {
name = "some-server-${i}"
} if i != 3]
}
This yields:
Changes to Outputs:
test = [
{
name = "some-server-1"
},
{
name = "some-server-2"
},
{
name = "some-server-4"
},
{
name = "some-server-5"
},
{
name = "some-server-6"
},
]
And if you want to exclude a list, as the title of the question state it, you could use contains
instead in the condition, then increase the upper limit based on the length
of the exclusion list plus one.
variable "vm_count" {
default = 5
}
variable "exclusion" {
default = [2,4,5]
}
output "test" {
value = [for i in range(1, var.vm_count length(var.exclusion) 1) : {
name = "some-server-${i}"
} if !contains(var.exclusion, i)]
}
This gives:
Changes to Outputs:
test = [
{
name = "some-server-1"
},
{
name = "some-server-3"
},
{
name = "some-server-6"
},
{
name = "some-server-7"
},
{
name = "some-server-8"
},
]
Of course, here, you start to have edge cases, where you will possibly have to much VMs if the exclusion list contains numbers that are outside of the range, but that all depends on the complexity of your use case.