deploy: render launchctl templates safely
This commit is contained in:
87
deploy/local/launchctl/render.py
Normal file
87
deploy/local/launchctl/render.py
Normal file
@@ -0,0 +1,87 @@
|
||||
#!/usr/bin/env python3
|
||||
import html
|
||||
import os
|
||||
import re
|
||||
from pathlib import Path
|
||||
|
||||
|
||||
SERVICES = (
|
||||
"gb32960",
|
||||
"jt808",
|
||||
"yutong-mqtt",
|
||||
"vehicle-history",
|
||||
"vehicle-analytics",
|
||||
)
|
||||
|
||||
LOG_DIRS = (
|
||||
"lingniu-gb32960-live",
|
||||
"lingniu-jt808-live",
|
||||
"lingniu-yutong-mqtt-live",
|
||||
"lingniu-vehicle-history-live",
|
||||
"lingniu-vehicle-analytics-live",
|
||||
)
|
||||
|
||||
|
||||
def env(name: str, default: str = "") -> str:
|
||||
return os.environ.get(name, default)
|
||||
|
||||
|
||||
def xml_value(value: str) -> str:
|
||||
return html.escape(value, quote=False)
|
||||
|
||||
|
||||
def replacements() -> dict[str, str]:
|
||||
identity_jdbc = env("VEHICLE_IDENTITY_MYSQL_JDBC_URL", "jdbc:mysql://127.0.0.1:3306/vehicle_ingest")
|
||||
identity_username = env("VEHICLE_IDENTITY_MYSQL_USERNAME", "")
|
||||
identity_password = env("VEHICLE_IDENTITY_MYSQL_PASSWORD", "")
|
||||
return {
|
||||
"__PROJECT_ROOT__": env("PROJECT_ROOT", str(Path.cwd())),
|
||||
"__JAVA_BIN__": env("JAVA_BIN", "/usr/bin/java"),
|
||||
"__SHARED_ARCHIVE_PATH__": env("INGEST_ARCHIVE_PATH", str(Path.cwd() / "data/archive-live")),
|
||||
"__TDENGINE_JDBC_URL__": env("TDENGINE_JDBC_URL", "jdbc:TAOS-WS://127.0.0.1:6041/vehicle_ts"),
|
||||
"__TDENGINE_USERNAME__": env("TDENGINE_USERNAME", "root"),
|
||||
"__TDENGINE_PASSWORD__": env("TDENGINE_PASSWORD", ""),
|
||||
"__VEHICLE_IDENTITY_MYSQL_JDBC_URL__": identity_jdbc,
|
||||
"__VEHICLE_IDENTITY_MYSQL_USERNAME__": identity_username,
|
||||
"__VEHICLE_IDENTITY_MYSQL_PASSWORD__": identity_password,
|
||||
"__VEHICLE_IDENTITY_MYSQL_REFRESH_INTERVAL__": env("VEHICLE_IDENTITY_MYSQL_REFRESH_INTERVAL", "60s"),
|
||||
"__MYSQL_JDBC_URL__": env("MYSQL_JDBC_URL", identity_jdbc),
|
||||
"__MYSQL_USERNAME__": env("MYSQL_USERNAME", identity_username),
|
||||
"__MYSQL_PASSWORD__": env("MYSQL_PASSWORD", identity_password),
|
||||
"__YUTONG_MQTT_ENABLED__": env("YUTONG_MQTT_ENABLED", "false"),
|
||||
"__YUTONG_MQTT_URI__": env("YUTONG_MQTT_URI", ""),
|
||||
"__YUTONG_MQTT_TOPIC__": env("YUTONG_MQTT_TOPIC", "#"),
|
||||
"__YUTONG_MQTT_USERNAME__": env("YUTONG_MQTT_USERNAME", ""),
|
||||
"__YUTONG_MQTT_PASSWORD__": env("YUTONG_MQTT_PASSWORD", ""),
|
||||
}
|
||||
|
||||
|
||||
def render_template(template: str, values: dict[str, str]) -> str:
|
||||
rendered = template
|
||||
for placeholder, value in values.items():
|
||||
rendered = rendered.replace(placeholder, xml_value(value))
|
||||
unresolved = sorted(set(re.findall(r"__[A-Z0-9_]+__", rendered)))
|
||||
if unresolved:
|
||||
raise RuntimeError("unresolved launchctl placeholder(s): " + ", ".join(unresolved))
|
||||
return rendered
|
||||
|
||||
|
||||
def main() -> None:
|
||||
root = Path(env("PROJECT_ROOT", str(Path.cwd()))).resolve()
|
||||
template_dir = Path(__file__).resolve().parent
|
||||
launch_agents = Path.home() / "Library/LaunchAgents"
|
||||
launch_agents.mkdir(parents=True, exist_ok=True)
|
||||
(root / "data").mkdir(parents=True, exist_ok=True)
|
||||
for log_dir in LOG_DIRS:
|
||||
(Path("/tmp") / log_dir).mkdir(parents=True, exist_ok=True)
|
||||
|
||||
values = replacements()
|
||||
for service in SERVICES:
|
||||
template_path = template_dir / f"com.lingniu.{service}.plist.template"
|
||||
output_path = launch_agents / f"com.lingniu.{service}.plist"
|
||||
output_path.write_text(render_template(template_path.read_text(), values), encoding="utf-8")
|
||||
print(output_path)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Reference in New Issue
Block a user