diff options
author | binary <me@rgoncalves.se> | 2021-02-08 14:30:33 +0100 |
---|---|---|
committer | binary <me@rgoncalves.se> | 2021-02-08 14:30:33 +0100 |
commit | ba54cc5fc68926597b308d585d812160d8f5938f (patch) | |
tree | 6cbd42a7d4f11339f576504a83434cad0c3212c3 | |
parent | 027606884d613f0daf0bd0e876bfba22a4954fa3 (diff) | |
download | infrastructure-ba54cc5fc68926597b308d585d812160d8f5938f.tar.gz |
Implement dynamic inventory based on files only
-rwxr-xr-x | dynamic.py | 194 | ||||
-rw-r--r-- | group_vars/bsd.yml | 4 | ||||
-rw-r--r-- | group_vars/linux.yml | 5 | ||||
-rw-r--r-- | host_vars/dc0.yml | 3 | ||||
-rw-r--r-- | host_vars/emb0.yml | 3 | ||||
-rw-r--r-- | host_vars/guest0.yml | 1 | ||||
-rw-r--r-- | host_vars/guest1.yml | 1 | ||||
-rw-r--r-- | host_vars/guest2.yml | 1 | ||||
-rw-r--r-- | host_vars/st0cld0.yml | 3 | ||||
-rw-r--r-- | host_vars/st0dev0.yml | 2 | ||||
-rw-r--r-- | host_vars/st0gme0.yml | 2 | ||||
-rw-r--r-- | host_vars/st0gme1.yml | 2 | ||||
-rw-r--r-- | host_vars/st0sbx0.yml | 2 | ||||
-rw-r--r-- | host_vars/st0sbx1.yml | 2 | ||||
-rw-r--r-- | host_vars/stack0.yml | 10 | ||||
-rw-r--r-- | host_vars/ws-bentonite.yml | 1 | ||||
-rw-r--r-- | host_vars/ws-think01.yml | 1 | ||||
-rw-r--r-- | host_vars/ws-xps01.yml | 1 |
18 files changed, 223 insertions, 15 deletions
diff --git a/dynamic.py b/dynamic.py new file mode 100755 index 0000000..78ebdb2 --- /dev/null +++ b/dynamic.py @@ -0,0 +1,194 @@ +#!/usr/bin/env python3 +# +# This is a dynamic inventory script for Ansible at +# rgoncalves.se infrastructure. +# +# Only groups_vars/ and host_vars/ directory are used for setting up devices +# and nodes. +# > Files, files, files, ... only files, everything files! +# +# The main goal here is to allow flexible code reviews and edits, POSIX +# compliant actions over files, and using "less is more" moto. Moreover, each +# host/group/node is individually track on version control. + +import os +import yaml +import logging +import json + +from typing import Final +from optparse import OptionParser + + +HOST_DIR: Final = "./host_vars" +GROUP_DIR: Final = "./group_vars" + + +class AnsibleInput: + """ + AnsibleInput class mixin. + Meta methods and inits for reading and processing yaml files. + """ + + data = None + name = None + + def __init__(self, filepath): + with open(filepath) as file: + self.data = yaml.load(file, Loader=yaml.FullLoader) + self.name = os.path.splitext(os.path.basename(filepath))[0] + + +def pprint(data): + """ + Json pretty print for ansible hosts/groups or whatever output we get. + """ + + try: + print(json.dumps(data, indent=4, sort_keys=True)) + except TypeError: + print(data) + + +def create_nodes(directory): + """ + Build-up and ansible node (Host or Group), + then return the full type list. + """ + + nodes = {} + for file in os.scandir(directory): + node = AnsibleInput(file.path) + nodes[node.name] = node + return nodes + + +def get_hostvars(host): + """ + Retrieve and build dynamic variables for a specific host. + """ + + data = host.data + if "ansible_host" not in host.data: + data["ansible_host"] = host.name + return data + + +def get_subgroups(groups, og): + """ + Get and return all children of a specific group, in a given subset. + """ + + # specific return for group "all" + if og.name in "all": + groups = list(groups.keys()) + groups.remove("all") + return groups + + # usual behavior + valid_groups = [] + if "_groups" not in og.data: + logging.warning(f"group { og.name } does not have any _groups var!") + else: + for group in og.data["_groups"]: + if group in groups: + valid_groups.append(group) + return valid_groups + + +def get_meta(hosts): + """ + For performance reasons, return all the hosts in a meta dict. + """ + + _meta = {} + _meta["hostvars"] = {} + for hostname, host in hosts.items(): + _meta["hostvars"][hostname] = get_hostvars(host) + # _meta["hostvars"][hostname] = host.data + return "{}" + return _meta + + +def get_list(hosts, groups): + """ + Return list of groups with all hosts. + """ + + _list = {} + _list["_meta"] = get_meta(hosts) + # init group array + for groupname, group in groups.items(): + _list[groupname] = {} + _list[groupname]["hosts"] = [] + _list[groupname]["vars"] = {} + _list[groupname]["children"] = get_subgroups(groups, group) + # append each hosts to their corresponding groups + for hostname, host in hosts.items(): + _list["all"]["hosts"].append(hostname) + if "_groups" not in host.data: + logging.info(f"no _groups data found for host { hostname }") + continue + # retrieve _groups variables and force conversion to list + cleangr = host.data["_groups"] + cleangr = [cleangr] if isinstance(cleangr, str) else cleangr + for group in cleangr: + # skip group assignement on non-existence! + logging.info(f"searching for group : { group }") + if group not in groups: + logging.error(f"group { group } does not exist!") + continue + _list[group]["hosts"].append(hostname) + return _list + + +def main(): + """ + Main entry. + """ + + # logging config + logging.basicConfig(level=logging.INFO) + logging.disable() + + # parse cli arguments + parser = OptionParser() + parser.add_option("--host", + dest="host", + default="_empty", + help="show specific host") + parser.add_option("--list", + action="store_true", + help="list all groups") + parser.add_option("--debug", + action="store_true", + help="show logging informations") + (options, args) = parser.parse_args() + + # enable debug if required + if options.debug: + logging.disable(0) + + # retrieve hosts and groups + hosts = create_nodes(HOST_DIR) + groups = create_nodes(GROUP_DIR) + + # return specific hostname + if options.host != "_empty": + if options.host in hosts: + pprint(get_hostvars(hosts[options.host])) + else: + pprint("{}") + exit(0) + + # return all groups + if options.list: + pprint(get_list(hosts, groups)) + exit(0) + + # return all hosts + exit(0) + + +if __name__ == "__main__": + main() diff --git a/group_vars/bsd.yml b/group_vars/bsd.yml index d2027af..95f6a17 100644 --- a/group_vars/bsd.yml +++ b/group_vars/bsd.yml @@ -4,6 +4,10 @@ --- +_groups: + - openbsd + - freebsd + ansible_become_method: "doas" group_root: "wheel" diff --git a/group_vars/linux.yml b/group_vars/linux.yml index c11daa7..81ffaf1 100644 --- a/group_vars/linux.yml +++ b/group_vars/linux.yml @@ -4,6 +4,11 @@ --- +_groups: + - alpine + - archlinux + - debian + ansible_become_method: "sudo" group_root: "root" diff --git a/host_vars/dc0.yml b/host_vars/dc0.yml index 3ef714b..c2b9df6 100644 --- a/host_vars/dc0.yml +++ b/host_vars/dc0.yml @@ -1,4 +1,5 @@ -ansible_host: dc0 +_groups: openbsd + virtual: true ip: diff --git a/host_vars/emb0.yml b/host_vars/emb0.yml index 1895e48..ddb8695 100644 --- a/host_vars/emb0.yml +++ b/host_vars/emb0.yml @@ -1,4 +1,5 @@ -ansible_host: emb0 +_groups: debian + virtual: false ip: diff --git a/host_vars/guest0.yml b/host_vars/guest0.yml index 76f7242..60300c2 100644 --- a/host_vars/guest0.yml +++ b/host_vars/guest0.yml @@ -1,4 +1,3 @@ -ansible_host: guest0 ip: in: 10.10.0.100 out: 192.168.5.100 diff --git a/host_vars/guest1.yml b/host_vars/guest1.yml index 48702bd..8df6714 100644 --- a/host_vars/guest1.yml +++ b/host_vars/guest1.yml @@ -1,4 +1,3 @@ -ansible_host: guest1 ip: in: 10.10.0.101 out: 192.168.5.101 diff --git a/host_vars/guest2.yml b/host_vars/guest2.yml index ee49906..0c10ace 100644 --- a/host_vars/guest2.yml +++ b/host_vars/guest2.yml @@ -1,4 +1,3 @@ -ansible_host: guest2 ip: in: 10.10.0.102 out: 192.168.5.102 diff --git a/host_vars/st0cld0.yml b/host_vars/st0cld0.yml index 40abf08..45b4f8e 100644 --- a/host_vars/st0cld0.yml +++ b/host_vars/st0cld0.yml @@ -1,4 +1,5 @@ -ansible_host: st0cld0 +_groups: openbsd + ip: in: 10.10.0.61 out: 192.168.5.61 diff --git a/host_vars/st0dev0.yml b/host_vars/st0dev0.yml index 2487ab6..88ddd14 100644 --- a/host_vars/st0dev0.yml +++ b/host_vars/st0dev0.yml @@ -1,4 +1,4 @@ -ansible_host: st0dev0 +_groups: openbsd ip: in: 10.10.0.60 out: 192.168.5.60 diff --git a/host_vars/st0gme0.yml b/host_vars/st0gme0.yml index 6db5411..1bdd70d 100644 --- a/host_vars/st0gme0.yml +++ b/host_vars/st0gme0.yml @@ -1,4 +1,4 @@ -ansible_host: st0gme0 +_groups: openbsd ip: in: 10.10.0.62 out: 192.168.5.62 diff --git a/host_vars/st0gme1.yml b/host_vars/st0gme1.yml index 8875f68..ad68490 100644 --- a/host_vars/st0gme1.yml +++ b/host_vars/st0gme1.yml @@ -1,4 +1,4 @@ -ansible_host: st0gme1 +_groups: alpine ip: in: 10.10.0.63 out: 192.168.5.63 diff --git a/host_vars/st0sbx0.yml b/host_vars/st0sbx0.yml index 09f9c46..e67d1cc 100644 --- a/host_vars/st0sbx0.yml +++ b/host_vars/st0sbx0.yml @@ -1,4 +1,4 @@ -ansible_host: st0sbx0 +_groups: openbsd ip: in: 10.10.0.64 out: 192.168.5.64 diff --git a/host_vars/st0sbx1.yml b/host_vars/st0sbx1.yml index 6f71178..c4f692f 100644 --- a/host_vars/st0sbx1.yml +++ b/host_vars/st0sbx1.yml @@ -1,4 +1,4 @@ -ansible_host: st0sbx1 +_groups: alpine ip: in: 10.10.0.65 out: 192.168.5.65 diff --git a/host_vars/stack0.yml b/host_vars/stack0.yml index 46afa0d..3c89dd1 100644 --- a/host_vars/stack0.yml +++ b/host_vars/stack0.yml @@ -1,4 +1,5 @@ -ansible_host: stack0 +_groups: freebsd + ip: in: 10.10.0.40 out: 192.168.5.40 @@ -20,6 +21,13 @@ vms: disks: - { id: 0, size: "32G" } + - name: st0dev1 + image: openbsd + memory: 1G + cpu: 1 + disks: + - { id: 0, size: "8G" } + - name: st0cld0 image: openbsd memory: 4G diff --git a/host_vars/ws-bentonite.yml b/host_vars/ws-bentonite.yml index d911ba1..755df94 100644 --- a/host_vars/ws-bentonite.yml +++ b/host_vars/ws-bentonite.yml @@ -1,4 +1,3 @@ -ansible_host: ws-bentonite ip: in: 10.10.0.81 out: 192.168.5.81 diff --git a/host_vars/ws-think01.yml b/host_vars/ws-think01.yml index 8fab600..724cfb3 100644 --- a/host_vars/ws-think01.yml +++ b/host_vars/ws-think01.yml @@ -1,4 +1,3 @@ -ansible_host: ws-think01 ip: in: 10.10.0.82 out: 192.168.5.82 diff --git a/host_vars/ws-xps01.yml b/host_vars/ws-xps01.yml index ee09d6b..448ae10 100644 --- a/host_vars/ws-xps01.yml +++ b/host_vars/ws-xps01.yml @@ -1,4 +1,3 @@ -ansible_host: ws-xps01 ip: in: 10.10.0.80 out: 192.168.5.80 |