Dynamic Inventory Error

Hi All,

I have been using Ansible for a few months now and have started to create some custom python scripts to enable me to implement tasks I haven’t otherwise been able to do within standard playbooks.

My inventory file is starting to grow and since all of the information in it is currently available from a DB, I started to look at dynamic inventory.

I wanted to start by understanding the JSON required to build an inventory, so came up with the following code in an effort to understand it. I realise that this is not a complete solution, it is purely for me to understand the required format of the data.

`
inv = {
“company”: {
“hosts”: [
“server”,
“sensor”
]
},
“_meta”: {
“hostvars”: {
“server”: {
“ansible_ssh_host” : “7.7.7.7”,
“ansible_ssh_port” : “44”
},
“sensor”: {
“ansible_ssh_host” : “7.7.7.7”,
“ansible_ssh_port” : “33”
}
}
}
}
inv = json.dumps(inv)

inventory = ansible.inventory.Inventory(inv)
`

If I print inv, it comes out like so…

{“company”: {“hosts”: [“server”, “sensor”]}, “_meta”: {“hostvars”: {“sensor”: {“ansible_ssh_host”: “7.7.7.7”, “ansible_ssh_port”: “44”}, “server”: {“ansible_ssh_host”: “7.7.7.7”, “ansible_ssh_port”: “33”}}}}

When I execute this code however, I get the following error.

Traceback (most recent call last):
File “test_inventory.py”, line 33, in
inventory = ansible.inventory.Inventory(inv)
File “/usr/local/lib/python2.7/dist-packages/ansible/inventory/init.py”, line 93, in init
all.add_host(Host(tokens[0], tokens[1]))
File “/usr/local/lib/python2.7/dist-packages/ansible/inventory/host.py”, line 32, in init
self.set_variable(‘ansible_ssh_port’, int(port))
ValueError: invalid literal for int() with base 10: ‘“22”}’

I’ve tried removing the string quotes from the port number, but the problem persists. If I remove the ansible_ssh_port lines, I get no errors.

Can anyone offer any advice? I’m current running Ansible version 1.9.4 which I understand is the latest.

Thanks!

You cannot provide dynamic inventory JSON output, that would normally come from a script, directly to the Inventory class. The first argument for Inventory is the host_list, which can be 1 of 3 things:

  1. Path to ini formatted inventory file
  2. Path to executable dynamic inventory script
  3. Comma separated hosts list that looks like “foo,bar,baz” or at minimum “foo,” with a trailing comma

Because your JSON has a comma in it, it get’s split, and then we try to loop through and split things out. At this point Ansible believes it finds a host called “ansible_ssh_host” with a port of “22” (including the quotes).

I have done what you are trying to do before, which required subclassing Inventory and overriding parse_inventory and subclassing InventoryScript and overriding __init__ and get_host_variables in order to allow my new classes to just accept a JSON string like you are trying to do.

In the end, it is just easier, using a callable script, and passing that to Inventory. So, basically move the inv assignment and do print json.dumps(inv) in a single script, and provide the path to that script to ansible.inventory.Inventory.

Just to add, if I change the line to:
“ansible_ssh_port” : 22

I get:
ValueError: invalid literal for int() with base 10: ‘22}’

I edited “/usr/local/lib/python2.7/dist-packages/ansible/inventory/host.py” and before line 32 added:
print ‘>>’ + port + ‘<<’

Which outputs:

22}<<

Clearly, the information isn’t being parsed correctly. Is it my code, or a bug?

If your just trying to get the syntax of the json right, there are easier ways to test. heres the above as an inventory script.

`
#!/usr/bin/env python
import json

inv = {
“company”: {
“hosts”: [
“server”,
“sensor”
]
},
“_meta”: {
“hostvars”: {
“server”: {
“ansible_ssh_host” : “7.7.7.7”,
“ansible_ssh_port” : 44
},
“sensor”: {
“ansible_ssh_host” : “7.7.7.7”,
“ansible_ssh_port” : “33”
}
}
}
}

print(json.dumps(inv))

`

heres the output of some test commands with (with ansible 2.0rc8, but it should work the same with 1.9x)

`
$ ansible -i leon.py all --list-hosts
hosts (2):
server
sensor
$ ansible -i leon.py sensor -m debug -a var=vars
sensor | SUCCESS => {
“vars”: {
“ansible_ssh_host”: “7.7.7.7”,
“ansible_ssh_port”: “33”,
“group_names”: [
“company”
],
“inventory_hostname”: “sensor”,
“inventory_hostname_short”: “sensor”
}
}

`