Add visualization script

This commit is contained in:
Tobias Reisinger 2024-10-14 17:49:44 +02:00
parent 13b69d5d4b
commit dc398ddb6e
Signed by: serguzim
GPG key ID: 13AD60C237A28DFE
4 changed files with 137 additions and 0 deletions

2
.gitignore vendored
View file

@ -10,3 +10,5 @@ secrets.auto.tfvars
inventory/group_vars/all/serguzim.net.yml inventory/group_vars/all/serguzim.net.yml
inventory/group_vars/all/opentofu.yml inventory/group_vars/all/opentofu.yml
inventory/group_vars/all/all_services.yml inventory/group_vars/all/all_services.yml
infrastructure.svg

View file

@ -52,3 +52,10 @@ all:
$(MAKE) dns $(MAKE) dns
@printf "\n=====\n\n" @printf "\n=====\n\n"
ansible-playbook ./playbooks/serguzim.net.yml -t $(TAGS) ansible-playbook ./playbooks/serguzim.net.yml -t $(TAGS)
visualize:
tofu output --json \
| jq 'with_entries(.value |= .value)' \
| ./visualize.py \
| d2 - infrastructure.svg

View file

@ -3,6 +3,7 @@ mkShell {
nativeBuildInputs = [ nativeBuildInputs = [
ansible ansible
ansible-lint ansible-lint
d2
dnscontrol dnscontrol
opentofu opentofu
]; ];

127
visualize.py Executable file
View file

@ -0,0 +1,127 @@
#!/usr/bin/env python
import json
import sys
icon_overrides = {
"acme_dns": "lets-encrypt",
"extra_services": None,
"faas": None,
"forgejo_runner": "forgejo",
"healthcheck": "healthchecks",
"mailcowdockerized": "mailcow",
"reitanlage_oranienburg": "grav",
"tandoor": "tandoor-recipes",
"teamspeak_fallback": None,
"tinytinyrss": "tiny-tiny-rss",
"wiki_js": "wiki-js",
"woodpecker": None,
}
template_host = """
'serguzim.net'.{host}: {{
label: {host}
}}
"""
template_service = """
{key}: {{
label: {label}
label.near: top-left
icon: https://cdn.jsdelivr.net/gh/selfhst/icons/webp/{icon}.webp
icon.near: top-right
}}
"""
default_d2 = """
vars: {
d2-config: {
layout-engine: elk
# Terminal theme code
theme-id: 101
}
}
external: {
scaleway: {
s3
}
restic: {
icon: https://cdn.jsdelivr.net/gh/selfhst/icons/webp/restic.webp
}
}
"""
def service_key(svc, data):
return f"'serguzim.net'.{data['host']}.{svc}"
def service_key_find(svc_name, services):
for svc, data in services.items():
if svc == svc_name:
return service_key(svc, data)
return None
def parse_hosts(hosts):
result = []
for host in hosts.keys():
result.append(template_host.format(host=host))
return result
def parse_services(services):
result = []
postgresql_key = service_key_find("postgresql", services)
authentik_key = service_key_find("authentik", services)
result.append(f"{postgresql_key}.grid-columns: 3")
result.append(f"{postgresql_key}.grid-gap: 0")
result.append(f"{authentik_key}.grid-columns: 3")
result.append(f"{authentik_key}.grid-gap: 0")
for svc, data in services.items():
svc_key = service_key(svc, data)
domains = []
if data.get("dns"):
domains = []
for dns in data["dns"]:
domain = ""
if dns.get("target") != "@":
domain += f"{dns["target"]}."
domain += dns['domain']
domains.append(f"- {domain}")
result.append(template_service.format(
key=svc_key,
label="\\n".join([svc] + domains),
icon=icon_overrides.get(svc, svc) or "docker",
))
for backup in data.get("backup") or []:
result.append(f'({svc_key} -> external.restic.{data['host']}).style.stroke: "#0f0"')
if data.get("database"):
result.append(f"({svc_key} -> {postgresql_key}).style.stroke: '#00f'")
result.append(f"{postgresql_key}.{svc}")
if data.get("auth"):
result.append(f"({svc_key} -> {authentik_key}).style.stroke: '#FD4B2D'")
result.append(f"{authentik_key}.{svc}")
if data.get("s3"):
result.append(f"({svc_key} -> external.scaleway.s3).style.stroke: '#bbb'")
result.append(f"external.scaleway.s3.{svc}")
return result
if __name__ == '__main__':
hosts = []
services = []
data = json.loads(sys.stdin.read())
hosts = parse_hosts(data["hosts"])
services = parse_services(data["services"])
print("\n".join(
[default_d2]
+ hosts
+ services))