how to use json file consisting of host info as input to ansible inventory
Asked Answered
V

3

6

I am trying to use the following json file as input to ansible host inventory but I get error when I run the playbook. JSON File:

{
   "instances":{
       "host": 10.66.70.33
   }
}

Playbook:

hosts: "{{ instances.host }}"
remote_user: root #vars:

When I run the play book I get the following errors. I am not sure where I am doing wrong. I am new to Ansible. Please advice I guess i am doing some silly mistake.

[WARNING]: Could not match supplied host pattern, ignoring: all [WARNING]: provided hosts list is empty, only localhost is available ERROR! The field 'hosts' has an invalid value, which includes an undefined variable. The error was: 'instances' is undefined

I am running the playbook as follows:

ansible-playbook -i <path>/test.json <path>test_playbook.yml
Vacant answered 8/2, 2018 at 8:2 Comment(0)
E
8

Ansible's yaml plugin will actually parse a JSON file, and has done so for years.

It's barely documented but you can see in the parameters section of the yaml plugin docs, .json is listed as a valid extension.

The JSON format has the same semantics as the YAML format. Note: not the same format as the dynamic inventory!

So your JSON should look like,

{
   "instances": {
      "hosts": {
         "10.66.70.33": null
      }
   }
}

Note: it's "hosts" rather than "host" and each address is a dictionary/hash key with the values being host-specific vars.

Taking the first example from Working with Inventory docs,

all:
  hosts:
    mail.example.com:
  children:
    webservers:
      hosts:
        foo.example.com:
        bar.example.com:
    dbservers:
      hosts:
        one.example.com:
        two.example.com:
        three.example.com:

would look like,

{
  "all": {
    "hosts": {
      "mail.example.com": null
    },
    "children": {
      "webservers": {
        "hosts": {
          "foo.example.com": null,
          "bar.example.com": null
        }
      },
      "dbservers": {
        "hosts": {
          "one.example.com": null,
          "two.example.com": null,
          "three.example.com": null
        }
      }
    }
  }
}

Those nulls are odd-looking but in the YAML example you'll see the trailing colon which does indeed mean each of those hosts are effectively dictionary/hash keys.

For the curious, the JSON-then-YAML loading code is in parsing/utils/yaml.py and the actual parsing is in parsing/inventory/yaml.py.

Eloisaeloise answered 3/9, 2019 at 9:18 Comment(1)
Talk about non-obvious!! Thanks for exposing/documenting this functionalityLiselisetta
G
3

It seems pure JSON it's not supported as inventory file. In the inventory plugin list I don't see JSON:

  • advanced_host_list - Parses a ‘host list’ with ranges
  • auto - Loads and executes an inventory plugin specified in a YAML config
  • aws_ec2 - ec2 inventory source
  • constructed - Uses Jinja2 to construct vars and groups based on existing inventory.
  • host_list - Parses a ‘host list’ string
  • ini - Uses an Ansible INI file as inventory source.
  • k8s - Kubernetes (K8s) inventory source
  • openshift - OpenShift inventory source
  • openstack - OpenStack inventory source
  • script - Executes an inventory script that returns JSON
  • virtualbox - virtualbox inventory source
  • yaml - Uses a specifically YAML file as inventory source.

On the other hand you can wrap that JSON in a simple python script as follows:

  1. Make sure the script plugin is enabled in your ansible.cfg file:

    [inventory]
    enable_plugins = host_list, script, yaml, ini
    
  2. Create wrapper script (inventory file), only reads your JSON and prints it in the console (I'm assuming the JSON and the wrapper script are in the same path):

    #!/usr/bin/env python
    import os
    
    __location__ = os.path.realpath(
        os.path.join(os.getcwd(), os.path.dirname(__file__)))
    
    with open(os.path.join(__location__, "hosts.json")) as f:
        print f.read()
    
  3. Use the following in your JSON inventory (performance improvements):

    {
        "_meta": {
            "hostvars": { }
        },
    
        "instances": {
            "hosts": ["10.66.70.33"]
        }
    }
    
  4. When running the playbook just be aware the group you want to target should be "instances", for example this is my playbook:

    ---
    - hosts: instances
      tasks:
        - debug:
            msg: Hi there
    

Then just run the playbook as you did, specifying the python wrapper script, in my case this was:

ansible-playbook -i inventory/hostswrapper.py test-stkovfl.yml

Hope it helps!

Garfish answered 8/2, 2018 at 17:26 Comment(3)
As mentioned before JSON does actually parse as YAML, i.e. a YAML-parser can read both formats.Supercool
For anyone wondering about the obviousness of this, JSON is (a subset of) YAML. If you have valid JSON, it is also valid YAML.Feud
A simple shell script with cat hosts.json will suffice, no need to complicate this with PythonPhotocopier
C
2

late but i hope this could help you !

I took this info from here


Json inventory is almost exactly as Yaml inventory. You should keep in mind these json keys:

  • hosts: json array to define your hosts. Notice the plural
  • vars: json object to define vars with its values at group level
  • children: allows you to define an inner hostgroup
  • _meta: to define metadata like host specific variables

for example:

{
  "all": {                                               # group called `all`
    "hosts": ["webmin.mydomain.com"],                    # hosts that compose `all` group
    "vars": {                                            # vars for `all` hosts
      "vendor": "vultr"                                  # var definition called `vendor`
    },
    "children": {                                        # inner group definition 
      "ipc": {                                           # called `ipc` ...
        "hosts": ["ipc-appserver-01", "ipc-db-01"],      # hosts that compose `ipc` group
        "vars": {                                        # vars only for `ipc` hosts
          "os": "centos7.6"                              # var def for `ipc` group called `os`
        }
      }                                                  # you could define more inner host groups
    }
  },
  "_meta": {                                             # metadata
    "hostvars": {                                        
      "ipc-appserver-01": {                              # vars only for `ipc-appserver-01` host
        "role": "php"                                    # var called `role`
      }
    }
  }
}
Cilo answered 5/3, 2021 at 18:24 Comment(1)
You cannot pass this json to ansible-playbook -i it will not work. Have you actually tried it?Photocopier

© 2022 - 2024 — McMap. All rights reserved.