First real commit
This commit is contained in:
96
scripts/generate_caddy.py
Normal file → Executable file
96
scripts/generate_caddy.py
Normal file → Executable file
@@ -0,0 +1,96 @@
|
||||
#!/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())
|
||||
Reference in New Issue
Block a user