I am using terraform to create resources then using templatefile approach to create ansible inventory in yaml language. I am creating multiple Virtual Machines in terraform and configure them using ansible in single pipeline.
Issue I am having is yaml file uses - for lists which is giving error in ansible playbook
Outputs.tf
resource "local_file" "AnsibleInventory" {
content = templatefile("inventory.tmpl",
{
ansible_port = "5986"
ansible_connection = "winrm"
ansible_winrm_server_cert_validation = "ignore"
ansible_winrm_transport = "ntlm"
vm-ip = data.azurerm_public_ip.main.*.ip_address,
username = "testadmin",
ansible_password = "abc"
}
)
filename = "inventory.json"
}
inventory.tmpl
${jsonencode({
"all": {
"hosts": {
"server": [
for ip in vm-ip : {
"ansible_host": "${ip}",
"ansible_port": 5986,
"ansible_user": "testadmin",
"ansible_winrm_transport": "ntlm",
"ansible_connection": "winrm",
"ansible_winrm_server_cert_validation": "ignore",
"ansible_password": "abc"
}
]
}
}
})}
inventory.json
{"all":{"hosts":{"server":{"ansible_connection":"winrm","ansible_host":"343434","ansible_password":"abc","ansible_port":5986,"ansible_user":"testadmin","ansible_winrm_server_cert_validation":"ignore","ansible_winrm_transport":"ntlm"}}}}
inventory.yaml
all:
hosts:
server:
- ansible_connection: winrm
ansible_host: 40.88.14.205
ansible_password: abc
ansible_port: 5986
ansible_user: testadmin
ansible_winrm_server_cert_validation: ignore
ansible_winrm_transport: ntlm
Is my approach right then how to remove "-" from code or am I doing something wrong.
Edited:
I am converting json file to yaml file using bash in pipeline.
python -c 'import sys, yaml, json; yaml.safe_dump(json.load(sys.stdin), sys.stdout, default_flow_style=False)' < inventory.json > inventory.yaml
If you have equal count of hosts in each group, you can use pattern + serial. Ansible forms host list by pattern moving through groups sequentially. So if you have equal count of hosts, then batches formed by serial will be equal to groups.
Ansible works against multiple systems in your infrastructure at the same time. It does this by selecting portions of systems listed in Ansible's inventory, which defaults to being saved in the location /etc/ansible/hosts . You can specify a different inventory file using the -i <path> option on the command line.
As pointed out by @ydaetskcoR's comment, your inventory is wrong because you need the list of hosts to be an immediate child of the hosts
attribute.
Note that the list you end up with is produced by the use of the brackets []
, producing tuples, around for
in your Terraform template as opposed to the use of the bracket {}
, producing objects.
The type of brackets around the
for
expression decide what type of result it produces. The above example uses[
and]
, which produces a tuple. If{
and}
are used instead, the result is an object, and two result expressions must be provided separated by the=>
symbol.
https://www.terraform.io/docs/configuration/expressions.html#for-expressions
If your structure, should look like all > server1, server2, server3
Then your inventory should be
all:
hosts:
server1:
ansible_host: 10.0.0.2
ansible_port: 5986
server2:
ansible_host: 10.0.0.3
ansible_port: 5986
server3:
ansible_host: 10.0.0.4
ansible_port: 5986
This is an approach for a Terraform template producing this:
${yamlencode({
"all": {
"hosts": {
for i, ip in vm-ip:
"server${i+1}" => {
"ansible_host": "${ip}",
"ansible_port": 5986
}
}
}
})}
Which gives this valid inventory.yaml:
"all":
"hosts":
"server1":
"ansible_host": "10.0.0.2"
"ansible_port": 5986
"server2":
"ansible_host": "10.0.0.3"
"ansible_port": 5986
"server3":
"ansible_host": "10.0.0.4"
"ansible_port": 5986
On the other hand, if you want a structure like all > server > server1, server2, server3
Then you should make server
a child of all
and use the children
entry in your inventory:
all:
children:
server:
hosts:
server1:
ansible_host: 10.0.0.2
ansible_port: 5986
server2:
ansible_host: 10.0.0.3
ansible_port: 5986
server3:
ansible_host: 10.0.0.4
ansible_port: 5986
For this one, the corresponding Terraform template would be
${yamlencode({
"all": {
"children": {
"server": {
"hosts": {
for i, ip in vm-ip:
"server${i+1}" => {
"ansible_host": "${ip}",
"ansible_port": 5986
}
}
}
}
}
})}
Which produce this inventory.yaml:
"all":
"children":
"server":
"hosts":
"server1":
"ansible_host": "10.0.0.2"
"ansible_port": 5986
"server2":
"ansible_host": "10.0.0.3"
"ansible_port": 5986
"server3":
"ansible_host": "10.0.0.4"
"ansible_port": 5986
Note: for all the examples above, I am using the terraform file test.tf below:
resource "local_file" "AnsibleInventory" {
content = templatefile("inventory.tpl", {
vm-ip = ["10.0.0.2","10.0.0.3","10.0.0.4"],
})
filename = "inventory.yaml"
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With