I have a Terraform file called azure.tf which is supposed to deploy a Virtual machine to Azure and afterwards SSH to said machine to run an Ansible playbook. The problem is that everytime i run terraform apply, the old public IP-address of the previous vm gets used.
I’ve got a file called outputs.tf which outputs this IP-address
output "public_ip_address" {
value = data.azurerm_public_ip.my_terraform_public_ip.ip_address
}
This Outputs IP address but it seems to be the old IP-adress of the already destroyed resource
# Create public IPs
resource "azurerm_public_ip" "my_terraform_public_ip" {
name = "testpublicIP"
location = azurerm_resource_group.rg.location
resource_group_name = azurerm_resource_group.rg.name
allocation_method = "Dynamic"
}
data "azurerm_public_ip" "my_terraform_public_ip" {
name = azurerm_public_ip.my_terraform_public_ip.name
resource_group_name = azurerm_public_ip.my_terraform_public_ip.resource_group_name
}
# Create Network Security Group and rule
resource "azurerm_network_security_group" "my_terraform_nsg" {
name = "myNetworkSecurityGroup"
location = azurerm_resource_group.rg.location
resource_group_name = azurerm_resource_group.rg.name
security_rule {
name = "SSH"
priority = 1001
direction = "Inbound"
access = "Allow"
protocol = "Tcp"
source_port_range = "*"
destination_port_range = "22"
source_address_prefix = "*"
destination_address_prefix = "*"
}
}
# Create network interface
resource "azurerm_network_interface" "my_terraform_nic" {
name = "myNIC"
location = azurerm_resource_group.rg.location
resource_group_name = azurerm_resource_group.rg.name
ip_configuration {
name = "my_nic_configuration"
subnet_id = azurerm_subnet.my_terraform_subnet.id
private_ip_address_allocation = "Dynamic"
public_ip_address_id = azurerm_public_ip.my_terraform_public_ip.id
}
}
# Connect the security group to the network interface
resource "azurerm_network_interface_security_group_association" "example" {
network_interface_id = azurerm_network_interface.my_terraform_nic.id
network_security_group_id = azurerm_network_security_group.my_terraform_nsg.id
}
resource "azurerm_virtual_machine" "my_terraform_vm" {
name = "myVM" #abstract away
location = azurerm_resource_group.rg.location
resource_group_name = azurerm_resource_group.rg.name
network_interface_ids = [azurerm_network_interface.my_terraform_nic.id]
vm_size = "Standard_DS1_v2" #abstract away
delete_data_disks_on_termination = true
delete_os_disk_on_termination = true
storage_image_reference {
publisher = "canonical" #abstract away
offer = "0001-com-ubuntu-server-focal" #abstract away
sku = "20_04-lts" #abstract away
version = "latest" #abstract away
}
storage_os_disk {
name = "vm1-osdisk" #abstract away
caching = "ReadWrite" #abstract away
create_option = "FromImage" #abstract away
managed_disk_type = "Standard_LRS"#abstract away
}
os_profile {
computer_name = "hostname" #abstract away
admin_username = "testadmin" #abstract away
}
os_profile_linux_config {
disable_password_authentication = false
}
provisioner "remote-exec" {
inline = ["echo 'Wait until SSH is ready'"]
connection {
type = "ssh"
user = "ubuntu"
private_key = file(local.private_key_path_Azure)
host = data.azurerm_public_ip.my_terraform_public_ip.ip_address
}
}
provisioner "local-exec" {
command = "ansible-playbook -i ${data.azurerm_public_ip.my_terraform_public_ip.ip_address}, --private-key ${local.private_key_path_Azure} docker.yaml"
}
}
I’ve looked at the NIC, public IP, and vm in the portal and they all get assigned the new public IP-adress. So why does the remote-exec use the old one?
Any help would be greatly appreciated.
2
Answers
allocation_method = "Dynamic" should have been "static"
A Terraform configuration should typically not contain both a
resource
block and adata
block referring to the same object, because when you do that it can be hard to explain to Terraform the correct order of operations so that all of the resources end up having the correct data at the end of the run.Inside your
connection
block (and anywhere else you refer todata.azurerm_public_ip.my_terraform_public_ip
), you should refer directly toazurerm_public_ip.my_terraform_public_ip
(theresource
block) instead. For example:You can then remove the
data "azurerm_public_ip" "my_terraform_public_ip"
altogether, because it isn’t necessary here. Adata
block is for telling Terraform that your configuration depends on an object managed elsewhere, but this object is managed directly inside this configuration and so thisdata
block is misleading.