summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPaul Buetow <paul@buetow.org>2026-04-14 22:42:12 +0300
committerPaul Buetow <paul@buetow.org>2026-04-14 22:42:12 +0300
commita911c4e690608a9a8430e928fe1853f4a217fbda (patch)
tree598d2775b7ed1c757b96f3dbd10ad0c6caad2f21
parent2a81b54c59ff937f66d42bf7aa625c5e30d62321 (diff)
frontends: daily goprecords uptimed upload for fishfinger and blowfish.
Add POSIX sh script template deployed to /usr/local/bin/goprecords-upload.sh, invoked from /etc/daily.local. Rex task goprecords_upload installs curl, renders per-host script from geheim secrets/etc/goprecords/<host>.token, and hooks commons. Document token layout and kubectl key creation in README. Made-with: Cursor
-rw-r--r--frontends/README.md20
-rw-r--r--frontends/Rexfile46
-rw-r--r--frontends/scripts/goprecords-upload.sh.tpl51
3 files changed, 117 insertions, 0 deletions
diff --git a/frontends/README.md b/frontends/README.md
index e2d59d9..2df2113 100644
--- a/frontends/README.md
+++ b/frontends/README.md
@@ -1,3 +1,23 @@
# Frontends
Rexify my internet facing frontend servers!
+
+## goprecords upload (fishfinger, blowfish)
+
+Uptimed stats are pushed once per day from **`/etc/daily.local`** via **`/usr/local/bin/goprecords-upload.sh`** (POSIX **`sh`**, deploy **`rex goprecords_upload`** or **`rex commons`**).
+
+Bearer tokens live in **geheim** as plain text (one line, no newline):
+
+- **`secrets/etc/goprecords/fishfinger.token`**
+- **`secrets/etc/goprecords/blowfish.token`**
+
+Issue or rotate keys on the goprecords daemon (Kubernetes example):
+
+```bash
+kubectl exec -n services deployment/goprecords -- \
+ goprecords --create-client-key fishfinger -stats-dir=/data/stats
+kubectl exec -n services deployment/goprecords -- \
+ goprecords --create-client-key blowfish -stats-dir=/data/stats
+```
+
+Then update the matching **`secrets/etc/goprecords/<host>.token`** file and re-run **`rex goprecords_upload`** (or **`commons`**) so the script on each host is regenerated.
diff --git a/frontends/Rexfile b/frontends/Rexfile
index f44a33c..09aa426 100644
--- a/frontends/Rexfile
+++ b/frontends/Rexfile
@@ -169,6 +169,51 @@ task 'uptimed',
service 'uptimed', ensure => 'started';
};
+desc 'Upload uptimed stats to goprecords.f3s (daily.local; tokens in geheim secrets/etc/goprecords/)';
+task 'goprecords_upload',
+ group => 'frontends',
+ sub {
+ pkg 'curl', ensure => present;
+
+ my $srv = connection->server;
+ my ($short) = $srv =~ /^([^.]+)\./;
+ unless ($short) {
+ Rex::Logger::info( "goprecords_upload: cannot parse short hostname from $srv", 'error' );
+ return;
+ }
+
+ my $token_path = "etc/goprecords/${short}.token";
+ my $full = "./secrets/$token_path";
+ unless ( -f $full ) {
+ Rex::Logger::info( "goprecords_upload: skip (missing $full; add via geheim)", 'warn' );
+ return;
+ }
+ my $token = $secrets->($token_path);
+ chomp $token;
+ unless ($token) {
+ Rex::Logger::info( "goprecords_upload: empty secrets/$token_path", 'error' );
+ return;
+ }
+
+ file '/usr/local/bin/goprecords-upload.sh',
+ content => template(
+ './scripts/goprecords-upload.sh.tpl',
+ goprecords_host => $short,
+ goprecords_token => $token,
+ ),
+ owner => 'root',
+ group => 'wheel',
+ mode => '500';
+
+ file '/etc/daily.local',
+ ensure => 'present',
+ owner => 'root',
+ group => 'wheel',
+ mode => '644';
+
+ append_if_no_such_line '/etc/daily.local', '/usr/local/bin/goprecords-upload.sh';
+ };
+
desc 'Setup rsync';
task 'rsync',
group => 'frontends',
@@ -769,6 +814,7 @@ task 'commons',
run_task 'nsd';
run_task 'nsd_failover';
run_task 'uptimed';
+ run_task 'goprecords_upload';
run_task 'httpd';
run_task 'gemtexter';
run_task 'taskwarrior';
diff --git a/frontends/scripts/goprecords-upload.sh.tpl b/frontends/scripts/goprecords-upload.sh.tpl
new file mode 100644
index 0000000..4770f1e
--- /dev/null
+++ b/frontends/scripts/goprecords-upload.sh.tpl
@@ -0,0 +1,51 @@
+#!/bin/sh
+set -e
+HOST="<%= $goprecords_host %>"
+BASE_URL="https://goprecords.f3s.buetow.org"
+TOKEN="<%= $goprecords_token %>"
+PATH="/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:${PATH}"
+
+upload() {
+ kind=$1
+ file=$2
+ if [ ! -f "$file" ]; then
+ echo "goprecords-upload: skip $kind (no $file)" >&2
+ return 0
+ fi
+ curl -fsS -X PUT --data-binary "@${file}" \
+ -H "Authorization: Bearer ${TOKEN}" \
+ "${BASE_URL}/upload/${HOST}/${kind}"
+}
+
+records_path=/var/db/uptimed/records
+if [ -f /var/spool/uptimed/records ]; then
+ records_path=/var/spool/uptimed/records
+fi
+
+tmp=$(mktemp)
+trap 'rm -f "$tmp"' 0 INT TERM HUP
+
+upload records "$records_path"
+
+if command -v uprecords >/dev/null 2>&1; then
+ uprecords -a -m 100 >"$tmp"
+ upload txt "$tmp"
+ uprecords -a | grep '^->' >"$tmp" || true
+ if [ -s "$tmp" ]; then
+ upload cur.txt "$tmp"
+ fi
+fi
+
+if [ -r /etc/os-release ]; then
+ upload os.txt /etc/os-release
+else
+ uname -a >"$tmp"
+ upload os.txt "$tmp"
+fi
+
+if [ -r /var/run/dmesg.boot ]; then
+ upload cpuinfo.txt /var/run/dmesg.boot
+else
+ sysctl hw.model hw.ncpu hw.machine >"$tmp" 2>/dev/null || uname -a >"$tmp"
+ upload cpuinfo.txt "$tmp"
+fi