7

We have a set of servers shared between different instances of an application and would like the list of them to be a separate file, with other -- instance-specific inventories -- including it.

(I know, this can be done with dynamic inventories, but those are code and we'd like our server-listings to remain data, so to speak.)

With INI-inventories this is impossible, but with YAML-ones it is tantalizingly close. For example, this answer shows, how this can be done by adding a handler for !include to Python's YAML-parser. One could then write:

all:
  group1:
    host1:
    host2:
  sharedservers: !include shared-servers.yaml

How can one add this functionality to one's own Ansible repository -- preferably, without implementing a whole new inventory-plugin (although inhering from Ansible's existing one would be Ok)?

Mikhail T.
  • 3,043
  • 3
  • 29
  • 46

2 Answers2

10

To start with, your example inventory in your question does not respect the schema for yaml ansible inventory and will be declined parsing.

Now to answer your question, you can simply use several inventories at once. Here is a simple example:

I created 3 yaml inventory files:

  • inventories/hosts.yml
    ---
    group1:
      hosts:
        host1:
        host2:
    
  • inventories/otherhosts.yml
    ---
    group2:
      hosts:
        hostA:
        hostB:
    
  • and finally inventories/shared.yml
    ---
    sharedservers:
      hosts:
        host3:
        host4:
    

From there, it is fairly easy to address all needed hosts. The example below use ansible-inventory for a better output, but the -i option and target selection is the same whith ansible and ansible-playbook

  • Address all hosts in all inventory files inside inventory directory:
    $ ansible-inventory -i inventories/ all --graph
    @all:
      |--@group1:
      |  |--host1
      |  |--host2
      |--@group2:
      |  |--hostA
      |  |--hostB
      |--@sharedservers:
      |  |--host3
      |  |--host4
      |--@ungrouped:
    
    This is equivalent to calling each yaml files in a seperate -i option in this case
    ansible-inventory -i inventories/hosts.yml \
      -i inventories/otherhosts.yml -i inventories/shared.yml \
      all --graph
    
  • Address only specific inventories
    $ ansible-inventory -i inventories/hosts.yml \
      -i inventories/shared.yml all --graph
    @all:
      |--@group1:
      |  |--host1
      |  |--host2
      |--@sharedservers:
      |  |--host3
      |  |--host4
      |--@ungrouped:
    
    $ ansible-inventory -i inventories/otherhosts.yml \
      -i inventories/shared.yml all --graph
    @all:
      |--@group2:
      |  |--hostA
      |  |--hostB
      |--@sharedservers:
      |  |--host3
      |  |--host4
      |--@ungrouped:
    
Zeitounator
  • 38,476
  • 7
  • 53
  • 66
  • This sounds like a good approach. Is it possible to have a group in an inventory file which uses `children` to combine other groups which are located in other inventory files? – MaKaNu Aug 23 '23 at 13:42
  • @MaKaNu [This can be tested in less time it takes to ask](https://gist.github.com/zeitounator/da8bb12b76401a5e2094cff4c979d5ee) – Zeitounator Aug 23 '23 at 14:02
  • Yes you are right, but now everybody knows that it is possible, thanks to your gist. – MaKaNu Aug 24 '23 at 12:01
5

You could take advantage of what is already there in Ansible:

  1. Using inventory directories, you can specify a folder where all your inventory files are located and they will be included one by one in alphabetical ordering.

  2. You can use multiple inventory sources using either:

    • multiple -i options in the command line
    • the ANSIBLE_INVENTORY environment variable and supply a comma separated list of inventory paths (either directories or files)
    • the inventory option in ansible.cfg to do the same as above.

See the docs.

I doubt that with the above you will not be able to cover your needs. It is better to modify your wrapper scripts and your project's file structure a bit than hack your way into pyyaml and ansible. /intro_inventory.html?highlight=inventory directory#using-multiple-inventory-sources) for more information.

  • Option 1 is interesting, but then the same file still cannot be _shared_ with another inventory (directory), save for a symlink. For the rest -- we have many inventories -- one for each application instance -- and everyone is accustomed, to the one instance -> one file paradigm. The work-arounds you're proposeing will take a while to get used to, unfortunately. Why wouldn't Ansible just implement the feature multiple people want?.. Sigh... – Mikhail T. Nov 03 '19 at 21:34
  • You can "share" an inventory by specifying both the main inventory and the shared inventory in `ANSIBLE_INVENTORY`. – Nikolaos Kakouros Nov 03 '19 at 22:42
  • Messes up the command-line :( The concept of include is so simple and known for decades (`#include <...>`)... – Mikhail T. Nov 03 '19 at 22:53
  • You can create your own inventory script/plugin that will do exactly what you need. https://docs.ansible.com/ansible/latest/plugins/inventory.html, https://docs.ansible.com/ansible/latest/dev_guide/developing_inventory.html#developing-inventory – Zeitounator Nov 10 '19 at 18:18
  • 1
    As best I can tell, ansible does not support any kind of real inclusion/inheritance with inventory files. It's unfortunate b/c it's pretty necessary for basic organization. E.g. two child inventory files (feature and production), with a parent inventory file with common stuff. My team is looking into symlinks as well, but it's not as clean as if true inclusion was just supported. – Josh Nov 28 '22 at 20:53