Skip to content

Commit c6d0773

Browse files
committed
WIP
1 parent f767ebf commit c6d0773

File tree

2 files changed

+142
-2
lines changed

2 files changed

+142
-2
lines changed

inventory/README.md

Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,19 @@
1+
2+
# About our inventory
3+
4+
- Differences from usual Ansible projects
5+
- How bbb-configs uses Ansible
6+
- How hosts are constructed
7+
- base_inventory
8+
- keyed groups
9+
- merge_vars
10+
- Working with the inventory
11+
12+
13+
14+
15+
---
16+
117
### .. magic inside
218

319
this inventory consists of three inventories.
@@ -15,3 +31,72 @@ this is a configuration for the "constructed" inventory plugin. it dynamically c
1531

1632
# keyed_groups_stage_2.config
1733
this is yet another configuration for the "constructed" inventory plugin. in contrast to the first stage its purpose is to dynamically construct even more group memberships based on inherited vars from the previous stage.
34+
35+
---
36+
37+
Ansible inventory script for bbb-configs location files
38+
39+
By default, Ansible isn't well suited for how we organize hosts and locations.
40+
We want one complete file for every location, which consists of one or more
41+
hosts with various roles as well as shared and individual config data.
42+
Ansible on the other hand starts at the "host vars" and then
43+
uses the "keyed groups" plugin to merge multiple stages of "group vars".
44+
For our case, this results in an amount of files that can feel overwhelming.
45+
46+
This inventory script allows for complete single location files while
47+
at the same time being compatible with Ansible's host vars and group vars.
48+
Note that certain shared and common config data is still loaded using
49+
keyed groups and group vars where it makes sense (e.g. role and model).
50+
51+
Ansible expects this script to respond to `--host <hostname>` and `--list`.
52+
For more information on inventory scripts, see:
53+
https://docs.ansible.com/ansible/latest/collections/ansible/builtin/script_inventory.html
54+
55+
With `--host <hostname>`, if no matching host is found in `locations/*.yml`,
56+
we then look in Ansible's default `host_vars/` directory.
57+
58+
With `--list`, we scan both locations/ and host_vars/.
59+
60+
Data for hosts in host_vars/ is constructed by Ansible:
61+
1. Combine the data from all files in host_vars/<hostname>/
62+
2. Add keyed_groups as specified in inventory/
63+
3. Merge the data from all related groups in group_vars/<hostname>/
64+
65+
Data for a specific host in locations/ is constructed as follows:
66+
1. Copy the location data into a new object, ignore the `.hosts` array
67+
2. Merge the array entry from `.hosts` with a matching `.hostname` value,
68+
with shallow merge only at the moment
69+
3. Add keyed_groups as specified in inventory/
70+
4. Merge the data from all related groups in group_vars/<hostname>/
71+
72+
For example:
73+
74+
```yml
75+
location: pktpls
76+
hosts:
77+
- hostname: pktpls-core
78+
role: corerouter
79+
string: host-var-has-precedence
80+
object: { two: 456 }
81+
array: [ bar ]
82+
string: will-be-overridden
83+
object: { one: 123 }
84+
array: [ foo ]
85+
```
86+
87+
results in:
88+
89+
```json
90+
{
91+
"location": "pktpls",
92+
"hostname": "pktpls-core",
93+
"role": "corerouter",
94+
"string": "host-var-has-precedence",
95+
"object": {
96+
"two": 456
97+
},
98+
"array": [
99+
"bar"
100+
]
101+
}
102+
```

inventory/base_inventory

Lines changed: 57 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,67 @@
11
#!/usr/bin/env bash
22

3+
#
4+
# This inventory script translates our data model to Ansible's data model.
5+
# We have one file per network location, and one or more hosts per location.
6+
# Ansible has groups and hosts, with one file per host, which wasn't practical.
7+
#
8+
# This script's output is a JSON object containing an array of all host names,
9+
# and an array with the initial hostvars for each host. See
10+
# https://docs.ansible.com/ansible/latest/dev_guide/developing_inventory.html
11+
# for more general information on inventory construction.
12+
#
13+
# The queries and conversions are done with the help of the `jq` and `yq` tools.
14+
#
15+
# We first grab the JSON representation of every location YAML definition,
16+
# then read `.hosts[].hostname` for each location to create the list of all hosts.
17+
# Previously we also scanned the `host_vars/` directory for backward compatibility.
18+
#
19+
# Usually Ansible then calls this script with `--host <name>` for every host.
20+
# That would obviously get very slow with hundreds of hosts,
21+
# which is why Ansible lets us construct all hostvars objects in advance.
22+
#
23+
# To construct the hostvars object for a host,
24+
# we take as a base the full location object (without `.hosts`),
25+
# then merge the object from `.hosts[]` with a matching `hostname` value.
26+
# This way, host values overwrite location values.
27+
# (We actually merge host<-location<-host to preserve JSON ordering.)
28+
#
29+
# In total there are five stages to construct inventory and hostvars:
30+
#
31+
# 1. This inventory script
32+
#
33+
# 2. `host_vars/`
34+
# Old hosts in `host_vars/` don't need the conversion in this script,
35+
# they're still loaded by Ansible automatically.
36+
#
37+
# 3. Keyed groups
38+
# The next two stages after inventory construction handle keyed groups,
39+
# which load additional group data based on certain property values.
40+
# This is handled outside of this script by an Ansible plugin.
41+
# There are two stages so that new data from stage 1 can set properties
42+
# that result in more new data in stage 2 (e.g. `model` and OpenWrt version).
43+
# The first stage handles `location` (old), `target`, `model`, and `role`,
44+
# while the second handles `target` and `openwrt_version`.
45+
#
46+
# 4. Merge vars
47+
# The last stage is the `merge_vars` task.
48+
# All hostvars construction so far was only able to overwrite properties.
49+
# In some cases we need to merge with the existing property.
50+
# For specific properties, a "merge var" can be set:
51+
# `packages: ["some-pkg"]` and `xxx__packages__to_merge: ["another-pkg"]`
52+
# where `xxx` is an arbitrary name to allow for multiple merge vars.
53+
# Before any templates or tasks make use of hostvars,
54+
# these merge vars are merged together into one.
55+
# Applies to `ssh_keys`, `packages`, `sysctl`, `rclocal`,
56+
# `disabled_services`, `wireless_profiles`, `channel_assignments_*`
57+
#
58+
359
set -e
460
# set -x
561

662
case "$1" in
763
--host)
8-
# No op - won't be called by Ansible anymore because --list contains all data.
9-
# See https://docs.ansible.com/ansible/latest/dev_guide/developing_inventory.html#tuning-the-external-inventory-script
64+
# No op
1065
echo "{}"
1166
exit 0
1267
;;

0 commit comments

Comments
 (0)