I’m having trouble wrapping my head around how to accomplish something with an inventory. I have multiple datacetners that internally have similar structures that I want to represent.
What I’d like to be able to do is be able to address “all items in DC1” with a typical --limit dc1 (this does not work as written). What I end up with when trying to do that limit is still all hosts. What I believe is happening is that because the group names match, and dev exists in both groups, it loads both dev groups, and then the dc2 dev group vars are loaded second, and override the DC1 vars.
Is there a way to structure this to achieve what I’m looking for?
---
all:
vars:
service1_user: "{{ lookup('env', 'SERVICE1_USER') }}"
service1_password: "{{ lookup('env','SERVICE1_PASSWORD') }}"
service2_password: "{{ lookup('env','SERVICE2_PASSWORD') }}"
service3_user: "{{ lookup('env', 'SERVICE3_USER') }}"
service3_pass: "{{ lookup('env', 'SERVICE3_PASS') }}"
dc1:
vars:
var0: dc1 value
children:
dev:
vars:
var1: DC1 dev value
var2: DC1 dev value
var3: DC1 dev value
hosts:
dc1devhost1
dc1devhost2
dc1devhost3
dc1devhost4
uat:
vars:
var1: DC1 uat value
var2: DC1 uat value
var3: DC1 uat value
hosts:
dc1uathost1
dc1uathost2
dc1uathost3
dc1uathost4
prod:
vars:
var1: DC1 prod value
var2: DC1 prod value
var3: DC1 prod value
hosts:
dc1prodhost1
dc1prodhost2
dc1prodhost3
dc1prodhost4
dc2:
vars:
var0: dc2 value
children:
dev:
vars:
var1: dc2 dev value
var2: dc2 dev value
var3: dc2 dev value
hosts:
dc2devhost1
dc2devhost2
dc2devhost3
dc2devhost4
uat:
vars:
var1: dc2 uat value
var2: dc2 uat value
var3: dc2 uat value
hosts:
dc2uathost1
dc2uathost2
dc2uathost3
dc2uathost4
prod:
vars:
var1: dc2 prod value
var2: dc2 prod value
var3: dc2 prod value
hosts:
dc2prodhost1
dc2prodhost2
dc2prodhost3
dc2prodhost4
There’s your problem right there! There aren’t multiple dev groups. Groups don’t nest. It’s easy to imagine that they do, especially when you define them in a complex data structure — a dev under dc1 and a dev under dc2 — but that isn’t what’s happening.
What is happening is, you’re saying “Put these hosts associated with dc1 in the dev group, and put these other hosts associated with dc2also in the one-and-only dev group.”
In other words, the “group namespace” is flat, not a hierarchy, regardless of how you define them.
That may seem like overkill, but it gives you the flexibility to construct group names programmatically without having to worry about undefined group names.
A fair question. It may be overdoing it a bit. However, In our experience, we do a lot of slicing and dicing with generated group names, and we’ve found them to be handy.
For example, if you need to do something across the uat groups in all data centers, you can say "dcall_uat" instead of "dc1_uat,dc2_uat".
In practice, we have a prefix for each of our inventories, so if this were in mw inventory, we’d have these groups:
And of course these would have the obvious children relationships.
We used to start with only the group names we’d actually need, then back-fill the intermediate groups as needed for convenience. But we found that remembering which groups we he had and had not back-filled was more of a pain than just fully articulating the entire hierarchy from the outset. We probably define some group names that we never use, but we know we could use them because we’re pretty consistent in setting this up this way. We’ve done it across ~45 projects (where a “project” maps to the 2nd level in our mw_* inventory), so we know how our group names are defined regardless of which project we’re currently working on. (It one project, it goes to 5 levels!)
vars would only be allowed on groups and hosts at top level under groups and hosts keys
hosts and children keys under groups would be simple lists, which can ‘create’ the hosts, but not allow chaining definitions
I would change the children keyword to include
I believe that would clarify how the inventory works as the current model, while very convenient, that allows you to add to host/group definitions anywhere they appear, leads to much confusion about a hierarchy that does not really exist in the inventory. I hope the above helps give you a clearer picture on how to organize.
Thanks. That more or less matches what I did as a “temporary” fix while researching if there was a solution that more accurately aligned with what I wanted.
If I were to break dc1/dc2 into distinct files (inventory/dc1.yml, inventory/dc2.yml) and then did --limit dc1 would that behave the way I expect, or would it still parse both anyway?
parsing depends on what you pass to ansible as an inventory source:
-i inventory/dc1.yml will ONLY get that file -i inventory/ will merge all inventory source files in that directory into a single inventory -i inventory/dc1.yml -i inventory/dc2.yml will merge both files as a single inventory also
limit runs AFTER creating a unified inventory, it only acts on play/target selection, not definitions
@bcoca & @utoddl, thanks for taking the time to help clear that up. This is more or less the outcome I expected, but I was hoping I was missing something.
I highly encourage you to use the ansible-inventory command to see what you’ve got with various inventory specifications. For example, I’m doing this to check my copy of your inventory:
Yeah, that’s what I did to confirm what was happening with the groups merging. I didn’t think to do it before hand because I thought I knew what I was doing (I clearly did not). It very quickly showed me what was happening.