# ./config.yml
nodes:
zero:
neither: {}
one:
consul: {}
vault: {}
two:
consul: {}
vault: {}
three:
vault: {}
four:
consul: {}
#!/usr/local/bin bash
# config.sh
config="${CONFIG_FILE:-./config.yml}"
set -o nounset
property="$1"
filter="$2"
if [[ "$#" == 3 ]]; then
config="$1"
property="$2"
filter="$3"
fi
echo "filtering .$property of $config" >/dev/stderr
jq "{ data: ( ($filter) | @json) }" <(gcy get "$config" "$property")
# main.tf
data external nodes {
# project the config data using jq filters
program = ["./config.sh", "./config.yml", "nodes", <<-JQ
{
consul: ([ to_entries[] | select( .value | has("consul") ) | .key ]),
vault: ([ to_entries[] | select( .value | has("vault") ) | .key ]),
either: ([
to_entries[] | select( .value | (has("vault") or has("consul")) ) | .key
])
}
JQ
]
}
locals {
nodes = jsondecode(data.external.nodes.result.data)
}
// local.nodes.consul = ["one", "two", "four"]
// local.nodes.vault = ["one", "two", "three"]
// local.nodes.either = ["one, "two", "three", "four"]
This is a simplification of how I do ansible at home
# ./config.yml
dns:
zone: my.ansible-managed.tld
consul:
initial_token: "d34db33f"
vault:
port: 1337
nomad:
plugins: [raw_exec, docker, mock]
nodes:
zero:
dns:
enabled: true
platform: edegeos
reachability: gateway
one:
consul: {}
vault: {}
platform: linux
reachability: public
two:
consul: {}
vault: {}
platform: macos
reachability: public
three:
dns:
enabled: true
vault: {}
platform: linux
reachability: public
four:
dns:
enabled: true
consul: {}
platform: linux
reachability: public
. as $data |
def store_this_as: "bin/inventory.jq";
def nodes: $data | .nodes;
def nodes(query): nodes | query;
def global(query): $data | query;
def filter(query):
nodes(with_entries(select(.value | query)));
def filter(query; rdc):
filter(query) | rdc;
def names(query):
filter(query; keys);
def address_pairs(query):
filter(query; to_entries | map({ name: .key, address: .value.address }));
def address_pairs(query; srt):
filter(query; to_entries | sort_by(.value | srt) | map({ name: .key, address: .value.address }));
def addresses(query):
address_pairs(query) | map(.address);
def addresses(query; srt):
address_pairs(query; srt) | map(.address);
def node_tags($prop):
nodes |
to_entries |
reduce .[] as $n ({}; . * {
($n.value[$prop]): ((.[$n.value[$prop]] // []) + [$n.key])
}
) |
to_entries |
map({
($prop+"_"+(.key | gsub("\\W"; "_"))): { hosts: .value }
}) |
add;
{
_meta: {
hostvars: nodes(with_entries({
key: .key,
value: ({node: .value} + .value._ansible)
}))
},
all: {
hosts: nodes(keys),
vars: {
config: {
consul: global(.consul),
dns_servers: addresses(.dns.enabled; .dns.mode != "leader"),
dns: global(.dns),
nomad: global(.nomad),
vault: global(.vault),
}
}
},
consul_server: {
hosts: names(.consul)
},
nomad_server: {
hosts: names(.nomad)
},
vault_server: {
hosts: names(.vault)
},
ungrouped: {
children: []
}
}
* node_tags("reachability")
* node_tags("platform")
#!/usr/bin/env bash
# bin/inventory.ini
case $1 in
--list)
# continue
;;
--host)
echo "{}"
exit 0
;;
*)
>&2 echo "unknown args: $*"
exit 2
esac
CONFIG_FILE="${CONFIG_FILE:-../config.yml}"
SRC_DIR="${BASH_SOURCE%/*}"
jq -f "${SRC_DIR}/inventory.jq" <(gcy get "$CONFIG_FILE" ".")
# playbook.yml
- hosts: reachability_gateway
gather_facts: no
roles:
- gateway
- coredns
- wireguard
- hosts: platform_macos
roles:
- server-users
- hosts: consul_server
roles:
- consul-server
- hosts: vault_server
roles:
- vault-server
- hosts: nomad_server
roles:
- nomad-server
- hosts: all
tasks:
- name: Do stuff with config
debug:
msg: "your password is {{ config.consul.initial_token }}"