skip to Main Content

I am trying to pass write the public IP address of a VM out to a text file via using locals and local-exec, see below code.

The issue is that the locals variable does not seem to work:

 my_ip=data.azurerm_public_ip.vm-publicip.ip_address

I tried passing the "data.azurerm_public_ip.vm-publicip.ip_address" inside local-exec at the environments too, but that also does not work.

Full code:

resource "azurerm_public_ip" "public"{
  name = "vm_public_ip"
  resource_group_name = azurerm_resource_group.main.name
  location = azurerm_resource_group.main.location
  allocation_method = "Dynamic"

}

data "azurerm_public_ip" "vm-publicip"{
  name = azurerm_public_ip.public.name
  resource_group_name = azurerm_resource_group.main.name
}
locals {
  my_ip=data.azurerm_public_ip.vm-publicip.ip_address
  my_vm="[azure_vm]"
} 

resource "terraform_data" "ansible" {
  provisioner "local-exec" {
    environment = {
      VM=local.my_vm
      IP=data.azurerm_public_ip.vm-publicip.ip_address
    }
    command = "echo %VM% %IP%  > ansible_inventory"
  }
}

When I tried to run it, %VM% worked correctly, but the %IP% not.

2

Answers


  1. Passing value to an environment variable in local-exec using terraform

    It seems like you’re trying to use the local-exec provisioner to write the public IP address of a VM to a text file. However, there are a couple of issues in your code that need to be addressed.

    Firstly, in your locals block, you’re assigning values directly without using the local-exec provisioner. local-exec is used to execute commands locally on the machine running Terraform, not within the Terraform configuration itself.

    Secondly, As Rui Jarimba suggested in your terraform_data resource, you’re trying to reference data.azurerm_public_ip.vm-publicip.ip_address directly, but you should be referring to it via the local variable you defined.

    I made necessary changes in the code as per the requirement

    My demo configuration:

    provider "azurerm" {
      features {}
    }
    
    resource "azurerm_resource_group" "main" {
      name     = "testrg-vk"
      location = "East US2"
    }
    
    resource "azurerm_public_ip" "public" {
      name                = "vm_public_ip"
      resource_group_name = azurerm_resource_group.main.name
      location            = azurerm_resource_group.main.location
      allocation_method   = "Dynamic"
    }
    
    data "azurerm_public_ip" "vm_publicip" {
      name                = azurerm_public_ip.public.name
      resource_group_name = azurerm_resource_group.main.name
    }
    
    locals {
      my_ip = data.azurerm_public_ip.vm_publicip.ip_address
      my_vm = "[azure_vm]"
    }
    
    resource "null_resource" "ansible_inventory" {
      provisioner "local-exec" {
        interpreter = ["pwsh", "-Command"]
        command     = "echo '${local.my_vm} ${local.my_ip}' > ansible_inventory"
      }
    }
    

    Deployment successfully:

    enter image description here

    now run the command type ansible_inventory

    enter image description here

    Login or Signup to reply.
  2. The Terraform documentation notes that provisioners are a last resort and that you should seek other alternatives before using them. This comment is therefore about a different way to solve this problem not using local-exec at all, because it isn’t necessary to use an external program written in another language just to create a file containing some data produced by Terraform.

    The Terraform provider hashicorp/local includes the resource type local_file which manages a file on local disk in a similar way to how azurerm_public_ip manages a remote object in the Azure API. You can use that resource type to instruct Terraform to create or update a file based on other data available in the Terraform configuration.

    For example:

    terraform {
      required_providers {
        azurerm = {
          source = "hashicorp/azurerm"
        }
        local = {
          source = "hashicorp/local"
        }
      }
    }
    
    resource "azurerm_public_ip" "public" {
      name                = "vm_public_ip"
      resource_group_name = azurerm_resource_group.main.name
      location            = azurerm_resource_group.main.location
      allocation_method   = "Dynamic"
    }
    
    data "azurerm_public_ip" "vm-publicip" {
      name                = azurerm_public_ip.public.name
      resource_group_name = azurerm_resource_group.main.name
    }
    
    locals {
      my_ip = data.azurerm_public_ip.vm-publicip.ip_address
      my_vm = "[azure_vm]"
    }
    
    resource "local_file" "ansible_inventory" {
      file    = "${path.module}/ansible_inventory"
      content = "${local.my_vm} ${data.azurerm_public_ip.vm-publicip.ip_address}"
    }
    

    When the local_file.ansible_inventory resource is created, it will create the ansible_inventory file and write the content value into it. If you subsequently change the value of local.my_vm or data.azurerm_public_ip.vm-publicip.ip_address, the provider will propose to rewrite the file with the new information.


    The local_file documentation has the following warning, but a similar situation would’ve been true for the local-exec approach too, so I assume it’s not a concern for your situation:

    When working with local files, Terraform will detect the resource as having been deleted each time a configuration is applied on a new machine where the file is not present and will generate a diff to re-create it. This may cause "noise" in diffs in environments where configurations are routinely applied by many different users or within automation systems.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search