96 lines
2.5 KiB
Python
Executable File
96 lines
2.5 KiB
Python
Executable File
#!/usr/bin/env python3
|
|
|
|
from pathlib import Path
|
|
import sys
|
|
import yaml
|
|
from jinja2 import Environment, FileSystemLoader, StrictUndefined
|
|
|
|
BASE = Path("/opt/homelab")
|
|
SERVICES_DIR = BASE / "services"
|
|
TEMPLATES_DIR = BASE / "templates"
|
|
OUTPUT_DIR = BASE / "generated" / "caddy"
|
|
|
|
|
|
def load_yaml(path: Path) -> dict:
|
|
with path.open("r", encoding="utf-8") as f:
|
|
data = yaml.safe_load(f) or {}
|
|
return data
|
|
|
|
|
|
def validate_service(data: dict, source: Path) -> None:
|
|
required_common = ["name", "type", "domain"]
|
|
for key in required_common:
|
|
if key not in data:
|
|
raise ValueError(f"{source.name}: missing required key '{key}'")
|
|
|
|
svc_type = data["type"]
|
|
if svc_type not in {"static", "proxy"}:
|
|
raise ValueError(f"{source.name}: unsupported type '{svc_type}'")
|
|
|
|
if svc_type == "static" and "root" not in data:
|
|
raise ValueError(f"{source.name}: static service requires 'root'")
|
|
|
|
if svc_type == "proxy" and "backend" not in data:
|
|
raise ValueError(f"{source.name}: proxy service requires 'backend'")
|
|
|
|
|
|
def render_service(env: Environment, data: dict) -> str:
|
|
svc_type = data["type"]
|
|
|
|
defaults = {
|
|
"headers": False,
|
|
"auth": False,
|
|
"real_ip": False,
|
|
"health_uri": None,
|
|
"health_interval": None,
|
|
}
|
|
|
|
merged = {**defaults, **data}
|
|
|
|
if svc_type == "static":
|
|
template = env.get_template("static.caddy.j2")
|
|
return template.render(**merged).strip() + "\n"
|
|
|
|
reverse_proxy_block = any(
|
|
[
|
|
merged.get("real_ip"),
|
|
merged.get("health_uri"),
|
|
merged.get("health_interval"),
|
|
]
|
|
)
|
|
merged["reverse_proxy_block"] = reverse_proxy_block
|
|
|
|
template = env.get_template("proxy.caddy.j2")
|
|
return template.render(**merged).strip() + "\n"
|
|
|
|
|
|
def main() -> int:
|
|
OUTPUT_DIR.mkdir(parents=True, exist_ok=True)
|
|
|
|
env = Environment(
|
|
loader=FileSystemLoader(str(TEMPLATES_DIR)),
|
|
undefined=StrictUndefined,
|
|
trim_blocks=True,
|
|
lstrip_blocks=True,
|
|
)
|
|
|
|
rendered_files = []
|
|
|
|
for svc_file in sorted(SERVICES_DIR.glob("*.yml")):
|
|
data = load_yaml(svc_file)
|
|
validate_service(data, svc_file)
|
|
|
|
rendered = render_service(env, data)
|
|
output_file = OUTPUT_DIR / f"{data['name']}.caddy"
|
|
output_file.write_text(rendered, encoding="utf-8")
|
|
rendered_files.append(output_file.name)
|
|
|
|
print("Generated:")
|
|
for name in rendered_files:
|
|
print(f" - {name}")
|
|
|
|
return 0
|
|
|
|
|
|
if __name__ == "__main__":
|
|
sys.exit(main()) |