diff --git a/stacks/owntracks/dawarich-hook.lua b/stacks/owntracks/dawarich-hook.lua new file mode 100644 index 00000000..0edff91e --- /dev/null +++ b/stacks/owntracks/dawarich-hook.lua @@ -0,0 +1,73 @@ +-- ot-recorder Lua hook: forward every location publish to Dawarich. +-- Loaded by ot-recorder via `--lua-script`. The hook() function is invoked +-- synchronously per publish; we fork curl with `&` to keep it fire-and-forget. +-- Dawarich's points table has UNIQUE (lonlat, timestamp, user_id) — duplicates +-- are safely dropped. The .rec file is always written regardless of hook result, +-- so a Dawarich 5xx loses nothing long-term (re-playable via backfill Job). + +local function escape_shell_single(s) + return "'" .. tostring(s):gsub("'", "'\\''") .. "'" +end + +local function json_escape_string(s) + return (s:gsub("\\", "\\\\") + :gsub('"', '\\"') + :gsub("\n", "\\n") + :gsub("\r", "\\r") + :gsub("\t", "\\t")) +end + +-- Minimal JSON serializer — scalars, arrays, maps. Owntracks payloads are +-- all primitive/flat; no bignum or cyclic-ref concerns. +local function to_json(v) + local t = type(v) + if t == "nil" then return "null" end + if t == "number" then return tostring(v) end + if t == "boolean" then return tostring(v) end + if t == "string" then return '"' .. json_escape_string(v) .. '"' end + if t == "table" then + if #v > 0 or next(v) == nil then + local parts = {} + for i, x in ipairs(v) do parts[i] = to_json(x) end + return "[" .. table.concat(parts, ",") .. "]" + end + local parts = {} + for k, x in pairs(v) do + parts[#parts + 1] = '"' .. json_escape_string(tostring(k)) .. '":' .. to_json(x) + end + return "{" .. table.concat(parts, ",") .. "}" + end + return "null" +end + +function otr_init() + otr.log("dawarich-bridge: init") + if not os.getenv("DAWARICH_API_KEY") then + otr.log("dawarich-bridge: WARN DAWARICH_API_KEY unset — hook will skip") + end +end + +function otr_exit() + otr.log("dawarich-bridge: exit") +end + +function otr_hook(topic, _type, data) + if _type ~= "location" then return end + local api_key = os.getenv("DAWARICH_API_KEY") + if not api_key or api_key == "" then + otr.log("dawarich-bridge: DAWARICH_API_KEY missing — dropping point") + return + end + local url = "https://dawarich.viktorbarzin.me/api/v1/owntracks/points?api_key=" .. api_key + local payload = to_json(data) + local cmd = table.concat({ + "curl -sS -o /dev/null --max-time 5 -X POST", + "-H 'Content-Type: application/json'", + "-d", escape_shell_single(payload), + escape_shell_single(url), + "&", + }, " ") + local ok = os.execute(cmd) + otr.log(string.format("dawarich-bridge: tst=%s lat=%s lon=%s ok=%s", + tostring(data.tst), tostring(data.lat), tostring(data.lon), tostring(ok))) +end diff --git a/stacks/owntracks/main.tf b/stacks/owntracks/main.tf index 40106565..0e21420d 100644 --- a/stacks/owntracks/main.tf +++ b/stacks/owntracks/main.tf @@ -86,6 +86,16 @@ resource "kubernetes_secret" "basic_auth" { } } +resource "kubernetes_config_map" "dawarich_hook" { + metadata { + name = "dawarich-hook" + namespace = kubernetes_namespace.owntracks.metadata[0].name + } + data = { + "dawarich-hook.lua" = file("${path.module}/dawarich-hook.lua") + } +} + resource "kubernetes_persistent_volume_claim" "data_proxmox" { wait_until_bound = false metadata { @@ -149,10 +159,23 @@ resource "kubernetes_deployment" "owntracks" { name = "http" container_port = 8083 } + # ot-recorder 1.0.1 has no OTR_HTTPHOOK; forwarding to Dawarich is + # done via a Lua hook script loaded with --lua-script. The script + # reads DAWARICH_API_KEY from env and fires curl fire-and-forget. + args = ["--lua-script", "/hook/dawarich-hook.lua", "owntracks/#"] env { name = "OTR_PORT" value = "0" } + env { + name = "DAWARICH_API_KEY" + value_from { + secret_key_ref { + name = "owntracks-secrets" + key = "dawarich_api_key" + } + } + } volume_mount { name = "data" @@ -162,6 +185,11 @@ resource "kubernetes_deployment" "owntracks" { name = "data" mount_path = "/config" } + volume_mount { + name = "hook" + mount_path = "/hook" + read_only = true + } resources { requests = { cpu = "10m" @@ -178,6 +206,12 @@ resource "kubernetes_deployment" "owntracks" { claim_name = "owntracks-data-encrypted" } } + volume { + name = "hook" + config_map { + name = kubernetes_config_map.dawarich_hook.metadata[0].name + } + } } } }