Skip to content

Instantly share code, notes, and snippets.

@cosimo
Last active October 1, 2021 10:19
Show Gist options
  • Save cosimo/a4d87f262f4cbd550846ea429eb2e3c8 to your computer and use it in GitHub Desktop.
Save cosimo/a4d87f262f4cbd550846ea429eb2e3c8 to your computer and use it in GitHub Desktop.
Display ansible inventories with Python and the rich console library
"""
Display Ansible inventories as a tree of environments, groups and hosts as leaves.
A nice diversion/excuse to dive into the rich console library.
It will expand simple host ranges, allowing grep commands to find
group names for given hosts.
Usage:
./inv.py
./inv.py | grep -B10 some-hostname
Example:
...
└── experimental
├── 🌏 tomcat9
│ └── 📂 tomcat9_experimental
│ └── 💻 experimental-tomcat9-1.domain.com
├── 🌏 couchbase
│ ├── 📂 couchbase_experimental
│ │ ├── 💻 1.2.3.4
│ │ └── 💻 5.6.7.8
│ └── 📂 index_experimental
│ └── 📂 experimental_index_1
│ └── 💻 experimental-index-1.domain.com
├── 🌏 elasticsearch
│ └── 📂 es_experimental
│ ├── 💻 experimental-es-1.domain.com
│ └── 💻 experimental-es-2.domain.com
└── 🌏 services
└── 📂 services_experimental
├── 💻 e-services1.domain.com
└── 💻 e-services2.domain.com
"""
from pathlib import Path
import re
import yaml
from rich import print as rprint
from rich.tree import Tree
def read_inventory(filename) -> dict:
with open(filename, 'r') as inventory_file:
groups = yaml.load(inventory_file)
return groups
def build_inventory_tree(envs: dict) -> Tree:
tree = Tree("Ansible Inventories")
for env in envs.keys():
env_node = tree.add(f"[bold cyan] {env}")
for group in envs[env].keys():
group_node = env_node.add(f"[bold blue] 🌏 {group}")
walk_inventory(envs[env][group], group_node)
return tree
def walk_inventory(node, tree: Tree) -> None:
if type(node) != dict:
return
is_group = "children" in node
is_leaf = "hosts" in node
if is_group:
children = node["children"]
for c in children.keys():
subgroup = tree.add(f"📂 {c}")
walk_inventory(children[c], subgroup)
elif is_leaf:
hosts_spec = node["hosts"]
if type(hosts_spec) not in (list, iter):
hosts_spec = [hosts_spec]
expanded_hosts = expand_hosts_range(hosts_spec)
for host in expanded_hosts:
tree.add(f"[bold white] 💻 {host}")
def expand_hosts_range(hosts_spec):
expanded_hosts = []
range_re = re.compile(r'^([a-z0-9\._-]+)\[([0-9]+):([0-9]+)\]([a-z0-9\._-]+)$')
for host in hosts_spec:
if range_re.match(host):
groups = range_re.match(host)
prefix = groups[1]
suffix = groups[4]
m = int(groups[2])
n = int(groups[3])
for i in range(m, m + n):
expanded_hosts.append(prefix + str(i) + suffix)
else:
expanded_hosts.append(host)
return expanded_hosts
p = Path('./inventories')
envs = dict()
inventories = list(p.glob('./**/inventory.yml'))
for i in inventories:
env = i.parent.stem
groups = read_inventory(i)
envs[env] = groups
rprint(build_inventory_tree(envs))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment