How to output multiple items of a list to file

Hi Terraform community.

I have been trying to output a list of IPs to a custom output file but without luck.

I’m currently using Terraform 0.14.2.

Here is the snippet of code:

data "azurerm_public_ip" "FEs-PIP" {
  count               = var.coaching-persons * 3
  name                = azurerm_public_ip.pip-coaching[count.index].name
  resource_group_name = azurerm_resource_group.rg-coaching.name
}

resource "azurerm_public_ip" "pip-coaching" {
  count                   = var.coaching-persons * 3
  name                    = "Pip-Coaching-${count.index}"
  location                = var.location
  resource_group_name     = azurerm_resource_group.rg-coaching.name
  allocation_method       = "Dynamic"
  idle_timeout_in_minutes = 30
}

resource "null_resource" "tfoutput" {
  provisioner "local-exec" {
    command = <<EOF
    Write-Output ${data.azurerm_public_ip.FEs-PIP.*.ip_address} | Out-File - "tf_output.txt"
    interpreter = ["PowerShell", "-Command"]
  }
}

Here is what I’ve tried:

Write-Output ${data.azurerm_public_ip.FEs-PIP.*.ip_address} | Out-File - "tf_output.txt"

Write-Output ${azurerm_public_ip.pip-coaching.ip_address} | Out-File - "tf_output.txt"

Write-Output ${element(data.azurerm_public_ip.FEs-PIP.*.ip_address, [count.index])} | Out-File -Append "tf_output.txt"

Example error in one of the cases:
Invalid template interpolation value: Cannot include the given value in a string template: string required

Weird thing is that the output below works, but all I need is it to be written to a file:
output “FEs-IPs” {
description = “IPs of all FEs provisoned.”
value = data.azurerm_public_ip.FEs-PIP.*.ip_address
}

Any help would be appreciated!

What’s the purpose of having that output?
Usually you would define output variables and post process those with running terraform output -json .....
Another option is to create a file with the file resource:

locals {
  allmyinfo = {
    resourceA = resource.nameA.output
    resourceB = resource.nameB.output
    moduleA = module.moduleA.output
  }
}
resource "local_file" "outputdata" {
  filename = "${path.module}/mydata.json"
  content  = jsonencode(local.allmyinfo)
}

Overall json format might also help for postprocessing the data.

Thank you for the reply!

My ultimate goal is to have a txt file with a few useful data on it that will be used for the person executing the terraform template.

A local_file resource wouldn’t help me because I needed a structured text file with more data, from more resources

if you put required variable outputs within a locals block, then you get access to any resource/module which might be needed.
I’ve updated the code above.

Do you have the closing EOF somewhere else or missed it copying it here?

Hi again and thank you for showing interest in helping me.

I’ve tried with the local variable approach and got same error.
Yes I got the EOF but didn’t put in the snippet

Another way I found that could be possible (maybe), was to use element, like this:

locals {
  AppServersPips = element(data.azurerm_public_ip.FEs-PIP.*.ip_address, count.index)
}

But that gives me a different error:

Error: Reference to "count" in non-counted context

  on coaching.tf line 36, in locals:
  36:   AppServersPips = concat(element(data.azurerm_public_ip.FEs-PIP.*.ip_address, count.index),"")

The "count" object can only be used in "module", "resource", and "data"
blocks, and only when the "count" argument is set.

I’m really getting confused on if whether I’m doing something wrong or if this isn’t possible at all with Terraform

Indeed you cannot use count.index without having an appropriate object.
I still don’t understand why terraform output -json might not support your use case and the local-exec provisioner is needed.
Do you have a repo to use for further testing?

Still looking for any suggestions.
Json Output is something I don’t need for my use case

JSON could be easily post processed into the format you’re looking for - anyway - maybe templatefile() gives you more options?

Nop, this is not what I need

The local_file resource type is the best way to create a file on local disk with Terraform.

Using a provisioner to do it would be much harder because rather than using a template to generate a file you’d instead be using a template to generate a script which in turn generates a file, which will be hard to write (as you’ve seen) and read.

@joaooamaral is right that it’s not really typical for a Terraform configuration to generate local files on disk – output values are the usual approach – but if you do need to do it then you can use local_file in conjunction with the Terraform template syntax:

resource "local_file" "outputdata" {
  filename = "${path.module}/tf_output.txt"
  content  = <<EOT
%{ for ip_addr in data.azurerm_public_ip.FEs-PIP.*.ip_address ~}
${ip_addr}
%{ endfor ~}
  EOT
}
1 Like