简体   繁体   中英

Create Ansible inventory using Terraform

I am trying to create Ansible inventory file using local_file function in Terraform (I am open for suggestions to do it in a different way)

module "vm" config:

resource "azurerm_linux_virtual_machine" "vm" {
  for_each                        = { for edit in local.vm : edit.name => edit }
  name                            = each.value.name
  resource_group_name             = var.vm_rg
  location                        = var.vm_location
  size                            = each.value.size
  admin_username                  = var.vm_username
  admin_password                  = var.vm_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"
  }

output "vm_ips" {
  value = toset([
    for vm_ips in azurerm_linux_virtual_machine.vm : vm_ips.private_ip_address
  ])
}

When I run terraform plan with the above configuration I get:

Changes to Outputs:
  + test = [
      + "10.1.0.4",
    ]

Now, in my main TF I have the configuration for local_file as follows:

resource "local_file" "ansible_inventory" {
  filename = "./ansible_inventory/ansible_inventory.ini"
  content = <<EOF
  [vm]
  ${module.vm.vm_ips}
EOF
}

This returns the error below:

Error: Invalid template interpolation value
on main.tf line 92, in resource "local_file" "ansible_inventory":
90:   content = <<EOF
91:   [vm]
92:   ${module.vm.vm_ips}
93: EOF
module.vm.vm_ips is set of string with 1 element
Cannot include the given value in a string template: string required.

Any suggestion how to inject the list of IPs from the output into the local file while also being able to format the rest of the text in the file?

If you want the Ansible inventory to be statically sourced from a file in INI format, then you basically need to render a template in Terraform to produce the desired output.

module/templates/inventory.tmpl :

[vm]
%{ for ip in ips ~}
${ip}
%{ endfor ~}

alternative suggestion from @mdaniel:

[vm]
${join("\n", ips)}

module/config.tf :

resource "local_file" "ansible_inventory" {
  content = templatefile("${path.module}/templates/inventory.tmpl",
    { ips = module.vm.vm_ips }
  )

  filename        = "${path.module}/ansible_inventory/ansible_inventory.ini"
  file_permission = "0644"
}

A couple of additional notes though:

You can modify your output to be the entire map of objects of exported attributes like:

output "vms" {
  value = azurerm_linux_virtual_machine.vm
}

and then you can access more information about the instances to populate in your inventory. Your templatefile argument would still be the module output, but the for expression(s) in the template would look considerably different depending upon what you want to add.

You can also utilize the YAML or JSON inventory formats for Ansible static inventory. With those, you can then leverage the yamldecode or jsondecode Terraform functions to make the HCL2 data structure transformation much easier. The template file would become a good bit cleaner in that situation for more complex inventories.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM