简体   繁体   中英

Creating ansible inventory for multiple target hosts

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

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"
}

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