I want to combine Ansible with Terraform so that Terraform creates the machines and Ansible will provision them. Using terraform-provisioner-ansible it's possible to bring them seamlessly together. But I saw a lack of change detection, which doesn't happen when Ansible runs standalone.
TL;DR: How can I apply changes made in Ansible to the Terraform Ansible plugin? Or at least execute the ansible plugin on every update so that Ansible can handle this itself?
Example use case
Consider this playbook which installs some packages
- name: Ansible install package test
hosts: all
tasks:
- name: Install cli tools
become: yes
apt:
name: "{{ tools }}"
update_cache: yes
vars:
tools:
- nnn
- htop
which is integrated into Terraform using the plugin
resource "libvirt_domain" "ubuntu18" {
# ...
connection {
type = "ssh"
host = "192.168.2.2"
user = "ubuntu"
private_key = "${file("~/.ssh/id_rsa")}"
}
provisioner "ansible" {
plays {
enabled = true
become_method = "sudo"
playbook = {
file_path = "ansible-test.yml"
}
}
}
}
will fork fine on the first run. But later I notice some package was missing
- name: Ansible install package test
hosts: all
tasks:
- name: Install cli tools
become: yes
apt:
name: "{{ tools }}"
update_cache: yes
vars:
tools:
- nnn
- htop
- vim # This is a new package
When running terraform plan
I'll get No changes. Infrastructure is up-to-date.
My new package vim
will never got installed! So Ansible didn't run because if Ansible runs, it would install the new package.
The problem seems to be the provisioner itself:
Creation-time provisioners are only run during creation, not during updating or any other lifecycle. They are meant as a means to perform bootstrapping of a system.
But what is the correct way of applying updates? I tried a null_ressource
with depends_on
link to my vm ressource, but Terraform doesn't detect changes on the Ansible part, too. Seems to be a lack of change detection from the Terraform plugin.
In the doc I only found destroy time provisioners. But none for updates. I could destroy and re-create the machine. This would slow down things a lot. I like the Ansible aproach of checking what is presend and only apply changes which aren't already present, this seems a good way of provisioning.
Isn't it possible to do something similar with Terraform?
With my current experience (more Ansible than Terraform), I don't see any other way as dropping the nice plugin and execute Ansible on my own. But this would also drop the nice integration. So I need to generate inventory files on my own or even by hand (which misses the automation approach in my point of view).
source_code_hash may be an option but is inflexible: When having multiple plays/roles, I need to do this by hand for every single file which keeps error-prone easily.