I have a long list of machines, all of which are a little different in functionality in a system. I'd like to organize these machines and add to a hosts inventory file automatically so I can run ansible and manage inventory. Are there good solutions out there for this?
I think ansible hosts should looks something like...
[webservers]
someip
someip
[integration]
someip
someip
etc..
After asking the question, I currently am researching output vars and using those to render a template from a file.
I figured it out.
data "template_file" "dev_hosts" {
template = "${file("${path.module}/templates/dev_hosts.cfg")}"
depends_on = [
"aws_instance.dev-api-gateway",
"aws_instance.dev-api-gateway-internal",
....
]
vars {
api_public = "${aws_instance.dev-api-gateway.private_ip}"
api_internal = "${aws_instance.dev-api-gateway-internal.private_ip}"
}
}
resource "null_resource" "dev-hosts" {
triggers {
template_rendered = "${data.template_file.dev_hosts.rendered}"
}
provisioner "local-exec" {
command = "echo '${data.template_file.dev_hosts.rendered}' > dev_hosts"
}
}
Then create a template in the file referenced earlier
Contents of example dev_hosts.cfg
[public]
${api_public}
[private]
${api_internal}
Our approach is slightly different. We define a Terraform Module (terraform-null-ansible
) which calls ansible anytime we want to run a playbook on a host by using a dynamic inventory.
https://github.com/cloudposse/terraform-null-ansible
This is a very terraform-centric approach but leads to very clean integration. Plus, by calculating the checksum of the playbook, we only call the ansible provisioner when the playbook has changed.
Usage is quite easy:
module "web_provisioner" {
source = "git::https://github.com/cloudposse/terraform-null-ansible.git?ref=tags/0.3.8"
arguments = ["--user=ubuntu"]
envs = ["host=${aws_instance.web.public_ip}"]
playbook = "../ansible/playbooks/test.yml"
dry_run = false
}
More docs are on the GitHub README.md
My approach: from template to inventory file, use template_file to render the content and use local_file to output a file.
template file:
## file inventory.tpl
[frontend]
${bastion_pub_ip}
[all:vars]
ansible_ssh_private_key_file = ${key_path}
ansible_ssh_user = ubuntu
render and output:
## file inventory.tf
data "template_file" "inventory" {
template = "${file("./test/inventory.tpl")}"
vars {
bastion_pub_ip = "${element(azurerm_public_ip.bastion.*.ip_address, count.index)}"
key_path = "~/.ssh/id_rsa"
}
}
resource "local_file" "save_inventory" {
content = "${data.template_file.inventory.rendered}"
filename = "./myhost"
}
It works for single server, if you have a list, I don't find a proper way to do it.