0

Background

I have domain managed via Terraform and it outputs server IP address. Then I have a script which outputs YAML inventory (outputs follows later).

Problem

When I run ansible-inventory --inventory inventory.sh --graph it always end up with

@all:
  |--@stage:
  |--@ungrouped:
  |  |--18.66.1.28

Were I would expect the machine to be in group stage.

I found out there is different behaviour for static inventory and for inventory as a script output.

Static file

If You save this as a static file and use it as an inventory, it will work.

all:
  hosts:
    18.66.1.28
  children:
    stage:
      hosts:
        18.66.1.28:

Output:

  @all:
  |--@stage:
  |  |--18.66.1.28
  |--@ungrouped:

Script

but if You specify shell script like follows, it won't work

#!/bin/bash

echo "all:
  hosts:
    18.66.1.28
  children:
    stage:
      hosts:
        18.66.1.28:"

Output:

 [WARNING]:  * Failed to parse /tmp/inventory.sh with script plugin: You defined a group 'all' with bad data for the host list:  {u'hosts':
u'18.66.1.28', u'children': {u'stage': {u'hosts': {u'18.66.1.28': None}}}}

 [WARNING]:  * Failed to parse /tmp/inventory.sh with ini plugin: /tmp/inventory.sh:3: Error parsing host definition 'echo "all:': No closing
quotation

 [WARNING]: Unable to parse /tmp/inventory.sh as an inventory source

 [WARNING]: No inventory was parsed, only implicit localhost is available

YAML outputs

Variant 1

all:
  hosts:
    - 18.66.1.28
  children:
    stage:
      hosts:
        - 18.66.1.28:

Variant 2

all:
  hosts:
    - 18.66.1.28
  children:
    stage:
      hosts:
        18.66.1.28:

Variant 3

all:
  hosts:
    - 18.66.1.28
  children:
    stage:
      hosts:
        - 18.66.1.28
Mailo Světel
  • 213
  • 3
  • 10

2 Answers2

2

Short answer

Don't look at https://docs.ansible.com/ansible/2.6/user_guide/intro_inventory.html but at https://docs.ansible.com/ansible/2.6/dev_guide/developing_inventory.html.

Long answer

Ansible is using at least three formats for inventories. YAML, INI and JSON. INI format is completely separate format with its own structure. YAML and JSON per-se allows to create pretty much same data structures. When I look at https://docs.ansible.com/ansible/2.6/user_guide/intro_inventory.html full of YAML examples, using JSON I would just change the notation to produce same data structure as with YAML. The thing is, script plugin is using different different data structure, but it allows you to use both YAML and JSON format.

Examples

Static inventory

Input:

$ cat /tmp/inventory-static 
all:
  hosts:
    18.66.1.28
  children:
    stage:
      hosts:
        18.66.1.28:

Output

$ ansible-inventory --inventory /tmp/inventory-static --graph 
@all:
  |--@stage:
  |  |--18.66.1.28
  |--@ungrouped:

This is correct format and behaviour according to https://docs.ansible.com/ansible/2.6/user_guide/intro_inventory.html .

Script

Input:

$ cat /tmp/inventory.sh 
#!/bin/bash

echo "all:
  hosts:
    18.66.1.28
  children:
    stage:
      hosts:
        18.66.1.28:"

Output:

 $ ansible-inventory --inventory /tmp/inventory.sh --graph    
 [WARNING]:  * Failed to parse /tmp/inventory.sh with script plugin: You defined a group 'all' with bad data for the host list:  {u'hosts':
u'18.66.1.28', u'children': {u'stage': {u'hosts': {u'18.66.1.28': None}}}}

 [WARNING]:  * Failed to parse /tmp/inventory.sh with ini plugin: /tmp/inventory.sh:3: Error parsing host definition 'echo "all:': No closing
quotation

 [WARNING]: Unable to parse /tmp/inventory.sh as an inventory source

 [WARNING]: No inventory was parsed, only implicit localhost is available

This is not what I would expect. Problem is the script plugin expects different data structure. Let’s try this with data structure from https://docs.ansible.com/ansible/2.6/dev_guide/developing_inventory.html.

Input:

$ cat /tmp/inventory.sh                                  
#!/bin/bash
echo "stage:
  hosts:
    - 18.66.1.28”

Output

$ ansible-inventory --inventory /tmp/inventory.sh --graph
@all:
  |--@stage:
  |  |--18.66.1.28
  |--@ungrouped:

Yes this is the result I expected. The machine is in the right group and the ingesting plugin is not complaining about anything. Of course according to the “Dynamic Inventory Sources”, the script should do a bit more than just echo the inventory and it should probably output JSON, this is just demonstration of how to structure the output of a scripted inventory.

This took me quite a lot of time to figure out, so I hope by writing this I'll save it to somebody else.

Mailo Světel
  • 213
  • 3
  • 10
0

There should be no dashes before a hostname (your variant 1).

all:
  hosts:
    18.66.1.28
  children:
    stage:
      hosts:
        18.66.1.28:

$ ansible-inventory --inventory inventory --graph

@all:
  |--@stage:
  |  |--18.66.1.28
  |--@ungrouped:

With the dashes you should see lot of warnings.

all:
  hosts:
    - 18.66.1.28
  children:
    stage:
      hosts:
        - 18.66.1.28:

$ ansible-inventory --inventory inventory --graph

 [WARNING]:  * Failed to parse inventory with yaml plugin:
 Invalid "hosts" entry for "all" group, requires a dictionary, found "<class 
 'ansible.parsing.yaml.objects.AnsibleSequence'>" instead.

 [WARNING]:  * Failed to parse inventory with ini plugin:
 inventory:3: Expected key=value host variable assignment, 
 got: 18.66.1.28

 [WARNING]: Unable to parse inventory as an inventory source

 [WARNING]: No inventory was parsed, only implicit localhost is available

...

Quoting from man ansible-inventory

-i, --inventory, --inventory-file
    specify inventory host path or comma separated host list.
    --inventory-file is deprecated

If the script creates a file first all is right.

$ ./inventory.sh > /tmp/my_inventory.yml && ansible-inventory --inventory /tmp/my_inventory.yml --graph

@all:
  |--@stage:
  |  |--18.66.1.28
  |--@ungrouped:
Vladimir Botka
  • 3,791
  • 6
  • 17
  • Ty, I'll give it a try in the evening – Mailo Světel Aug 20 '18 at 10:16
  • Ok, I tried. If I remove the dash in hosts section I get a lot of warnings and only group "@ungrouped" in group @all as a result. Could it be some broken parsing library? But I found one thing. What you sent works if it is static file. Unfortunately if it's output of a script, it doesn't work for some reason – Mailo Světel Aug 21 '18 at 21:29
  • Examples in updated question – Mailo Světel Aug 21 '18 at 21:46
  • --inventory should be **inventory host path or comma separated host list**. Script does not work. – Vladimir Botka Aug 21 '18 at 22:49
  • It does. Ansible tries to ingest the inventory with more plugins. One of them is script. That's what I am using. I'll write answer here in the evening. I had a chat on Freenode with one guy last night and things make a bit more sense now ;) – Mailo Světel Aug 22 '18 at 09:01