Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to share group_vars between different inventories in Ansible?

Tags:

ansible

The Ansible best practices documentation recommends to separate inventories:

inventories/
   production/
      hosts.ini           # inventory file for production servers
      group_vars/
         group1           # here we assign variables to particular groups
         group2           # ""
      host_vars/
         hostname1        # if systems need specific variables, put them here
         hostname2        # ""

   staging/
      hosts.ini           # inventory file for staging environment
      group_vars/
         group1           # here we assign variables to particular groups
         group2           # ""
      host_vars/
         stagehost1       # if systems need specific variables, put them here
         stagehost2       # ""

My staging and production environments are structured in the same way. I have in both environments the same groups. And it turns out that I have also the same group_vars for the same groups. This means redundancy I would like to wipe out.

Is there a way to share some group_vars between different inventories?

As a work-around I started to put shared group_vars into the roles.

my_var:
  my_group:
    - { var1: 1, var2: 2 }

This makes it possible to iterate over some vars by intersecting the groups of a host with the defined var:

with_items: "{{group_names | intersect(my_var.keys())}}"

But this is a bit complicate to understand and I think roles should not know anything about groups.

I would like to separate most of the inventories but share some of the group_vars in an easy to understand way. Is it possible to merge global group_vars with inventory specific group_vars?

like image 376
ceving Avatar asked Nov 15 '16 09:11

ceving


People also ask

Can Ansible have multiple inventory files?

If the location given to -i in Ansible is a directory (or as so configured in ansible. cfg ), Ansible can use multiple inventory sources at the same time. When doing so, it is possible to mix both dynamic and statically managed inventory sources in the same ansible run.

How can you specify a different inventory file when you run an Ansible command on the command line?

You can specify a different inventory file using the -i <path> option on the command line. Not only is this inventory configurable, but you can also use multiple inventory files at the same time (explained below) and also pull inventory from dynamic or cloud sources, as described in Dynamic Inventory.

What is inventory Host_vars and Group_vars in Ansible?

The host_vars is a similar folder to group_vars in the repository structure. It contains data models that apply to individual hosts/devices in the hosts. ini file. Hence, there is a YAML file created per device containing specific information about that device.


3 Answers

I scrapped the idea of following Ansible's recommendation. Now one year later, I am convinced that Ansible's recommendation is not useful for my requirements. Instead I think it is important to share as much as possible among different stages.

Now I put all inventories in the same directory:

production.ini
reference.ini

And I take care that each inventory defines a group including all hosts with the name of the stage.

The file production.ini has the group production:

[production:children]
all_production_hosts

And the file reference.ini has the group reference:

[reference:children]
all_reference_hosts

I have just one group_vars directory in which I define a file for every staging group:

group_vars/production.yml
group_vars/reference.yml

And each file defines a stage variable. The file production.yml defines this:

---
stage: production

And the file reference.yml defines that:

---
stage: reference

This makes it possible to share everything else between production and reference. But the hosts are completely different. By using the right inventory the playbook runs either on production or on reference hosts:

ansible-playbook -i production.ini site.yml
ansible-playbook -i reference.ini site.yml

If it is necessary for the site.yml or the roles to behave slightly different in the production and reference environment, they can use conditions using the stage variable. But I try to avoid even that. Because it is better to move all differences into equivalent definitions in the staging files production.yml and reference.yml.

For example, if the group_vars/all.yml defines some users:

users:
  - alice
  - bob
  - mallory

And I want to create the users in both environments, but I want to exclude mallory from the production environment, I can define a new group called effective_users. In the reference.yml it is identical to the users list:

effective_users: >-
  {{ users }}

But in the production.yml I can exclude mallory:

effective_users: >-
  {{ users | difference(['mallory']) }}

The playbook or the roles do not need to distinguish between the two stages, they can simply use the group effective_users. The group contains automatically the right list of users simply by selecting the inventory.

like image 93
ceving Avatar answered Oct 07 '22 02:10

ceving


The simple option here (and what we do) is simply symlink generic group vars files around.

For instance we might have a generic role for something like NGINX and then a few concrete use cases for that role. In this case we create a group vars file that uses the NGINX role for each concrete use case and then simply symlink those group vars files into the appropriate folders.

Our project folder structure then might look something like this (drastically simplified):

.
├── inventories
│   ├── bar-dev
│   │   ├── group_vars
│   │   │   ├── bar.yml -> ../../shared/bar.yml
│   │   │   └── dev.yml -> ../../shared/dev.yml
│   │   └── inventory
│   ├── bar-prod
│   │   ├── group_vars
│   │   │   ├── bar.yml -> ../../shared/bar.yml
│   │   │   └── prod.yml -> ../../shared/prod.yml
│   │   └── inventory
│   ├── bar-test
│   │   ├── group_vars
│   │   │   ├── bar.yml -> ../../shared/bar.yml
│   │   │   └── test.yml -> ../../shared/test.yml
│   │   └── inventory
│   ├── foo-dev
│   │   ├── group_vars
│   │   │   ├── dev.yml -> ../../shared/dev.yml
│   │   │   └── foo.yml -> ../../shared/foo.yml
│   │   └── inventory
│   ├── foo-prod
│   │   ├── group_vars
│   │   │   ├── foo.yml -> ../../shared/foo.yml
│   │   │   └── prod.yml -> ../../shared/prod.yml
│   │   └── inventory
│   ├── foo-test
│   │   ├── group_vars
│   │   │   ├── foo.yml -> ../../shared/foo.yml
│   │   │   └── test.yml -> ../../shared/test.yml
│   │   └── inventory
│   └── shared
│       ├── bar.yml
│       ├── dev.yml
│       ├── foo.yml
│       ├── prod.yml
│       └── test.yml
└── roles
    └── nginx
        ├── defaults
        │   └── main.yml
        ├── meta
        │   └── main.yml
        ├── tasks
        │   └── main.yml
        └── templates
            └── main.yml

Now our inventory files can have the hosts use these shared group vars simply by putting the hosts in the correct groups.

like image 7
ydaetskcoR Avatar answered Oct 07 '22 02:10

ydaetskcoR


You can place group_vars in playbook directory as well. More info.

Ansible will pick them up for all inventories.

like image 5
Konstantin Suvorov Avatar answered Oct 07 '22 03:10

Konstantin Suvorov