sunday 5th apr (rip mark hollis) (#52)

* lots of work

* feat: move rg-stats in, ensure consistency in db queries

* the clocks dont work

* almost

* ok jesus been and gone now back to usual
This commit is contained in:
zk
2026-04-06 01:25:30 +01:00
committed by GitHub
parent 71e8aa2152
commit edda03e916
217 changed files with 11757 additions and 1496 deletions
-19
View File
@@ -73,24 +73,6 @@ function seedMinioCdn {
)
}
function selfSignHTTPS {
if [ -e typescript/server/cert/key.pem ] && [ -e typescript/server/cert/cert.pem ] && openssl x509 -checkend 0 -noout -in typescript/server/cert/cert.pem; then
echo "HTTPS Certificates for local-dev server already exists and has not expired."
return 0
fi
echo "Self-Signing HTTPS Certificates for local-dev server..."
# This is for dev servers only! You should use this to
# create a self-signed HTTPS certificate for local dev.
# That is it. This is not secure.
mkdir -p typescript/server/cert
openssl req -x509 -newkey rsa:4096 -keyout typescript/server/cert/key.pem -out typescript/server/cert/cert.pem -sha256 -days 365 -nodes -subj "/C=AU/ST=TachiExample/L=TachiExample/O=TachiExample/CN=127.0.0.1" &> /dev/null
echo "Created HTTPS Certificates!"
}
function bunInstall {
echo "Installing dependencies..."
@@ -125,7 +107,6 @@ function syncDatabaseWithSeeds {
setupShell
mvExampleFiles
seedMinioCdn
selfSignHTTPS
bunInstall
if [ -e _SETUP_OK ] && [ $FORCE -eq 0 ]; then
+1 -1
View File
@@ -60,7 +60,7 @@ function fish_greeting
echo $(rgb "This machine comes pre-installed with Tachi and helpful tools." ffffff 000000)
echo ""
echo "Type $(cmd "just start") to start up a frontend and backend."
echo " $(rgb "The server will start on http://127.0.0.1:3000." ffff00 000000)"
echo " $(rgb "The server will start on http://localhost:3000." ffff00 000000)"
echo " $(rgb "Use Ctrl+C to stop the server." ffff00 000000)"
echo ""
echo "Type $(cmd "seeds") to run seeds scripts."
+20
View File
@@ -0,0 +1,20 @@
// Scrape Tachi API Prometheus metrics and remote-write to local Prometheus.
prometheus.remote_write "default" {
endpoint {
url = "http://tachi-prometheus:9090/api/v1/write"
}
}
prometheus.scrape "tachi_api" {
targets = [
{
"__address__" = "tachi-dev:9779",
"job" = "tachi-api",
},
]
forward_to = [prometheus.remote_write.default.receiver]
scrape_interval = "15s"
metrics_path = "/metrics"
}
@@ -0,0 +1,897 @@
{
"annotations": {
"list": [
{
"builtIn": 1,
"datasource": "-- Grafana --",
"enable": true,
"hide": true,
"iconColor": "rgba(0, 211, 255, 1)",
"name": "Annotations & Alerts",
"type": "dashboard"
}
]
},
"description": "node.js prometheus client basic metrics",
"editable": true,
"gnetId": 11159,
"graphTooltip": 0,
"id": null,
"iteration": 1573392431370,
"links": [],
"panels": [
{
"aliasColors": {},
"bars": false,
"dashLength": 10,
"dashes": false,
"datasource": "Prometheus",
"fill": 1,
"gridPos": {
"h": 7,
"w": 10,
"x": 0,
"y": 0
},
"id": 6,
"legend": {
"alignAsTable": true,
"avg": true,
"current": true,
"max": true,
"min": true,
"show": true,
"total": false,
"values": true
},
"lines": true,
"linewidth": 1,
"links": [],
"nullPointMode": "null",
"paceLength": 10,
"percentage": false,
"pointradius": 2,
"points": false,
"renderer": "flot",
"seriesOverrides": [],
"stack": false,
"steppedLine": false,
"targets": [
{
"expr": "irate(process_cpu_user_seconds_total{instance=~\"$instance\"}[2m]) * 100",
"format": "time_series",
"intervalFactor": 1,
"legendFormat": "User CPU - {{instance}}",
"refId": "A"
},
{
"expr": "irate(process_cpu_system_seconds_total{instance=~\"$instance\"}[2m]) * 100",
"format": "time_series",
"intervalFactor": 1,
"legendFormat": "Sys CPU - {{instance}}",
"refId": "B"
}
],
"thresholds": [],
"timeFrom": null,
"timeRegions": [],
"timeShift": null,
"title": "Process CPU Usage",
"tooltip": {
"shared": true,
"sort": 0,
"value_type": "individual"
},
"type": "graph",
"xaxis": {
"buckets": null,
"mode": "time",
"name": null,
"show": true,
"values": []
},
"yaxes": [
{
"format": "percent",
"label": null,
"logBase": 1,
"max": null,
"min": null,
"show": true
},
{
"format": "short",
"label": null,
"logBase": 1,
"max": null,
"min": null,
"show": true
}
],
"yaxis": {
"align": false,
"alignLevel": null
}
},
{
"aliasColors": {},
"bars": false,
"dashLength": 10,
"dashes": false,
"datasource": "Prometheus",
"fill": 1,
"gridPos": {
"h": 7,
"w": 9,
"x": 10,
"y": 0
},
"id": 8,
"legend": {
"alignAsTable": true,
"avg": true,
"current": true,
"max": true,
"min": true,
"show": true,
"total": false,
"values": true
},
"lines": true,
"linewidth": 1,
"links": [],
"nullPointMode": "null",
"paceLength": 10,
"percentage": false,
"pointradius": 2,
"points": false,
"renderer": "flot",
"seriesOverrides": [],
"stack": false,
"steppedLine": false,
"targets": [
{
"expr": "nodejs_eventloop_lag_seconds{instance=~\"$instance\"}",
"format": "time_series",
"intervalFactor": 1,
"legendFormat": "{{instance}}",
"refId": "A"
}
],
"thresholds": [],
"timeFrom": null,
"timeRegions": [],
"timeShift": null,
"title": "Event Loop Lag",
"tooltip": {
"shared": true,
"sort": 0,
"value_type": "individual"
},
"type": "graph",
"xaxis": {
"buckets": null,
"mode": "time",
"name": null,
"show": true,
"values": []
},
"yaxes": [
{
"format": "s",
"label": null,
"logBase": 1,
"max": null,
"min": null,
"show": true
},
{
"format": "short",
"label": null,
"logBase": 1,
"max": null,
"min": null,
"show": true
}
],
"yaxis": {
"align": false,
"alignLevel": null
}
},
{
"cacheTimeout": null,
"colorBackground": false,
"colorValue": false,
"colors": [
"#299c46",
"rgba(237, 129, 40, 0.89)",
"#d44a3a"
],
"datasource": "Prometheus",
"format": "none",
"gauge": {
"maxValue": 100,
"minValue": 0,
"show": false,
"thresholdLabels": false,
"thresholdMarkers": true
},
"gridPos": {
"h": 3,
"w": 5,
"x": 19,
"y": 0
},
"id": 2,
"interval": "",
"links": [],
"mappingType": 1,
"mappingTypes": [
{
"name": "value to text",
"value": 1
},
{
"name": "range to text",
"value": 2
}
],
"maxDataPoints": 100,
"nullPointMode": "connected",
"nullText": null,
"postfix": "",
"postfixFontSize": "50%",
"prefix": "",
"prefixFontSize": "50%",
"rangeMaps": [
{
"from": "null",
"text": "N/A",
"to": "null"
}
],
"sparkline": {
"fillColor": "rgba(31, 118, 189, 0.18)",
"full": false,
"lineColor": "rgb(31, 120, 193)",
"show": false
},
"tableColumn": "__name__",
"targets": [
{
"expr": "sum(nodejs_version_info{instance=~\"$instance\"}) by (version)",
"format": "time_series",
"instant": false,
"interval": "",
"intervalFactor": 1,
"legendFormat": "{{version}}",
"refId": "A"
}
],
"thresholds": "",
"timeFrom": null,
"timeShift": null,
"title": "Node.js Version",
"type": "singlestat",
"valueFontSize": "80%",
"valueMaps": [
{
"op": "=",
"text": "N/A",
"value": "null"
}
],
"valueName": "name"
},
{
"cacheTimeout": null,
"colorBackground": false,
"colorValue": false,
"colors": [
"#299c46",
"rgba(237, 129, 40, 0.89)",
"#d44a3a"
],
"datasource": "Prometheus",
"format": "none",
"gauge": {
"maxValue": 100,
"minValue": 0,
"show": false,
"thresholdLabels": false,
"thresholdMarkers": true
},
"gridPos": {
"h": 4,
"w": 5,
"x": 19,
"y": 3
},
"id": 4,
"interval": null,
"links": [],
"mappingType": 1,
"mappingTypes": [
{
"name": "value to text",
"value": 1
},
{
"name": "range to text",
"value": 2
}
],
"maxDataPoints": 100,
"nullPointMode": "connected",
"nullText": null,
"postfix": "",
"postfixFontSize": "50%",
"prefix": "",
"prefixFontSize": "50%",
"rangeMaps": [
{
"from": "null",
"text": "N/A",
"to": "null"
}
],
"sparkline": {
"fillColor": "rgba(31, 118, 189, 0.18)",
"full": false,
"lineColor": "#F2495C",
"show": true
},
"tableColumn": "",
"targets": [
{
"expr": "sum(changes(process_start_time_seconds{instance=~\"$instance\"}[1m]))",
"format": "time_series",
"intervalFactor": 1,
"legendFormat": "{{instance}}",
"refId": "A"
}
],
"thresholds": "",
"timeFrom": null,
"timeShift": null,
"title": "Process Restart Times",
"type": "singlestat",
"valueFontSize": "80%",
"valueMaps": [
{
"op": "=",
"text": "N/A",
"value": "null"
}
],
"valueName": "current"
},
{
"aliasColors": {},
"bars": false,
"dashLength": 10,
"dashes": false,
"datasource": "Prometheus",
"fill": 1,
"gridPos": {
"h": 7,
"w": 16,
"x": 0,
"y": 7
},
"id": 7,
"legend": {
"alignAsTable": true,
"avg": true,
"current": true,
"max": true,
"min": true,
"rightSide": true,
"show": true,
"total": false,
"values": true
},
"lines": true,
"linewidth": 1,
"links": [],
"nullPointMode": "null",
"paceLength": 10,
"percentage": false,
"pointradius": 2,
"points": false,
"renderer": "flot",
"seriesOverrides": [],
"stack": false,
"steppedLine": false,
"targets": [
{
"expr": "process_resident_memory_bytes{instance=~\"$instance\"}",
"format": "time_series",
"intervalFactor": 1,
"legendFormat": "Process Memory - {{instance}}",
"refId": "A"
},
{
"expr": "nodejs_heap_size_total_bytes{instance=~\"$instance\"}",
"format": "time_series",
"intervalFactor": 1,
"legendFormat": "Heap Total - {{instance}}",
"refId": "B"
},
{
"expr": "nodejs_heap_size_used_bytes{instance=~\"$instance\"}",
"format": "time_series",
"intervalFactor": 1,
"legendFormat": "Heap Used - {{instance}}",
"refId": "C"
},
{
"expr": "nodejs_external_memory_bytes{instance=~\"$instance\"}",
"format": "time_series",
"intervalFactor": 1,
"legendFormat": "External Memory - {{instance}}",
"refId": "D"
}
],
"thresholds": [],
"timeFrom": null,
"timeRegions": [],
"timeShift": null,
"title": "Process Memory Usage",
"tooltip": {
"shared": true,
"sort": 0,
"value_type": "individual"
},
"type": "graph",
"xaxis": {
"buckets": null,
"mode": "time",
"name": null,
"show": true,
"values": []
},
"yaxes": [
{
"format": "bytes",
"label": null,
"logBase": 1,
"max": null,
"min": null,
"show": true
},
{
"format": "short",
"label": null,
"logBase": 1,
"max": null,
"min": null,
"show": true
}
],
"yaxis": {
"align": false,
"alignLevel": null
}
},
{
"aliasColors": {},
"bars": false,
"dashLength": 10,
"dashes": false,
"datasource": "Prometheus",
"fill": 1,
"gridPos": {
"h": 7,
"w": 8,
"x": 16,
"y": 7
},
"id": 9,
"legend": {
"alignAsTable": true,
"avg": true,
"current": true,
"max": true,
"min": true,
"show": true,
"total": false,
"values": true
},
"lines": true,
"linewidth": 1,
"links": [],
"nullPointMode": "null",
"paceLength": 10,
"percentage": false,
"pointradius": 2,
"points": false,
"renderer": "flot",
"seriesOverrides": [],
"stack": false,
"steppedLine": false,
"targets": [
{
"expr": "nodejs_active_handles_total{instance=~\"$instance\"}",
"format": "time_series",
"intervalFactor": 1,
"legendFormat": "Active Handler - {{instance}}",
"refId": "A"
},
{
"expr": "nodejs_active_requests_total{instance=~\"$instance\"}",
"format": "time_series",
"intervalFactor": 1,
"legendFormat": "Active Request - {{instance}}",
"refId": "B"
}
],
"thresholds": [],
"timeFrom": null,
"timeRegions": [],
"timeShift": null,
"title": "Active Handlers/Requests Total",
"tooltip": {
"shared": true,
"sort": 0,
"value_type": "individual"
},
"type": "graph",
"xaxis": {
"buckets": null,
"mode": "time",
"name": null,
"show": true,
"values": []
},
"yaxes": [
{
"format": "short",
"label": null,
"logBase": 1,
"max": null,
"min": null,
"show": true
},
{
"format": "short",
"label": null,
"logBase": 1,
"max": null,
"min": null,
"show": true
}
],
"yaxis": {
"align": false,
"alignLevel": null
}
},
{
"aliasColors": {},
"bars": false,
"dashLength": 10,
"dashes": false,
"datasource": "Prometheus",
"fill": 1,
"gridPos": {
"h": 8,
"w": 8,
"x": 0,
"y": 14
},
"id": 10,
"legend": {
"alignAsTable": true,
"avg": true,
"current": true,
"max": true,
"min": true,
"rightSide": false,
"show": true,
"total": false,
"values": true
},
"lines": true,
"linewidth": 1,
"links": [],
"nullPointMode": "null",
"paceLength": 10,
"percentage": false,
"pointradius": 2,
"points": false,
"renderer": "flot",
"seriesOverrides": [],
"stack": false,
"steppedLine": false,
"targets": [
{
"expr": "nodejs_heap_space_size_total_bytes{instance=~\"$instance\"}",
"format": "time_series",
"intervalFactor": 1,
"legendFormat": "Heap Total - {{instance}} - {{space}}",
"refId": "A"
}
],
"thresholds": [],
"timeFrom": null,
"timeRegions": [],
"timeShift": null,
"title": "Heap Total Detail",
"tooltip": {
"shared": true,
"sort": 0,
"value_type": "individual"
},
"type": "graph",
"xaxis": {
"buckets": null,
"mode": "time",
"name": null,
"show": true,
"values": []
},
"yaxes": [
{
"format": "bytes",
"label": null,
"logBase": 1,
"max": null,
"min": null,
"show": true
},
{
"format": "short",
"label": null,
"logBase": 1,
"max": null,
"min": null,
"show": true
}
],
"yaxis": {
"align": false,
"alignLevel": null
}
},
{
"aliasColors": {},
"bars": false,
"dashLength": 10,
"dashes": false,
"datasource": "Prometheus",
"fill": 1,
"gridPos": {
"h": 8,
"w": 8,
"x": 8,
"y": 14
},
"id": 11,
"legend": {
"alignAsTable": true,
"avg": true,
"current": true,
"max": true,
"min": true,
"rightSide": false,
"show": true,
"total": false,
"values": true
},
"lines": true,
"linewidth": 1,
"links": [],
"nullPointMode": "null",
"paceLength": 10,
"percentage": false,
"pointradius": 2,
"points": false,
"renderer": "flot",
"seriesOverrides": [],
"stack": false,
"steppedLine": false,
"targets": [
{
"expr": "nodejs_heap_space_size_used_bytes{instance=~\"$instance\"}",
"format": "time_series",
"intervalFactor": 1,
"legendFormat": "Heap Used - {{instance}} - {{space}}",
"refId": "A"
}
],
"thresholds": [],
"timeFrom": null,
"timeRegions": [],
"timeShift": null,
"title": "Heap Used Detail",
"tooltip": {
"shared": true,
"sort": 0,
"value_type": "individual"
},
"type": "graph",
"xaxis": {
"buckets": null,
"mode": "time",
"name": null,
"show": true,
"values": []
},
"yaxes": [
{
"format": "bytes",
"label": null,
"logBase": 1,
"max": null,
"min": null,
"show": true
},
{
"format": "short",
"label": null,
"logBase": 1,
"max": null,
"min": null,
"show": true
}
],
"yaxis": {
"align": false,
"alignLevel": null
}
},
{
"aliasColors": {},
"bars": false,
"dashLength": 10,
"dashes": false,
"datasource": "Prometheus",
"fill": 1,
"gridPos": {
"h": 8,
"w": 8,
"x": 16,
"y": 14
},
"id": 12,
"legend": {
"alignAsTable": true,
"avg": true,
"current": true,
"max": true,
"min": true,
"rightSide": false,
"show": true,
"total": false,
"values": true
},
"lines": true,
"linewidth": 1,
"links": [],
"nullPointMode": "null",
"paceLength": 10,
"percentage": false,
"pointradius": 2,
"points": false,
"renderer": "flot",
"seriesOverrides": [],
"stack": false,
"steppedLine": false,
"targets": [
{
"expr": "nodejs_heap_space_size_available_bytes{instance=~\"$instance\"}",
"format": "time_series",
"intervalFactor": 1,
"legendFormat": "Heap Used - {{instance}} - {{space}}",
"refId": "A"
}
],
"thresholds": [],
"timeFrom": null,
"timeRegions": [],
"timeShift": null,
"title": "Heap Available Detail",
"tooltip": {
"shared": true,
"sort": 0,
"value_type": "individual"
},
"type": "graph",
"xaxis": {
"buckets": null,
"mode": "time",
"name": null,
"show": true,
"values": []
},
"yaxes": [
{
"format": "bytes",
"label": null,
"logBase": 1,
"max": null,
"min": null,
"show": true
},
{
"format": "short",
"label": null,
"logBase": 1,
"max": null,
"min": null,
"show": true
}
],
"yaxis": {
"align": false,
"alignLevel": null
}
}
],
"schemaVersion": 18,
"style": "dark",
"tags": [
"nodejs"
],
"templating": {
"list": [
{
"allValue": null,
"current": {},
"datasource": "Prometheus",
"definition": "label_values(nodejs_version_info, instance)",
"hide": 0,
"includeAll": true,
"label": "instance",
"multi": true,
"name": "instance",
"options": [],
"query": "label_values(nodejs_version_info, instance)",
"refresh": 1,
"regex": "",
"skipUrlSync": false,
"sort": 1,
"tagValuesQuery": "",
"tags": [],
"tagsQuery": "",
"type": "query",
"useTags": false
}
]
},
"time": {
"from": "now-1h",
"to": "now"
},
"timepicker": {
"refresh_intervals": [
"5s",
"10s",
"30s",
"1m",
"5m",
"15m",
"30m",
"1h",
"2h",
"1d"
],
"time_options": [
"5m",
"15m",
"1h",
"6h",
"12h",
"24h",
"2d",
"7d",
"30d"
]
},
"timezone": "",
"title": "NodeJS Application Dashboard",
"uid": "PTSqcpJWk",
"version": 4
}
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,12 @@
apiVersion: 1
providers:
- name: default
orgId: 1
folder: ""
type: file
disableDeletion: false
updateIntervalSeconds: 30
options:
path: /var/lib/grafana/dashboards
foldersFromFilesStructure: false
@@ -0,0 +1,57 @@
apiVersion: 1
datasources:
- name: Prometheus
type: prometheus
access: proxy
url: http://tachi-prometheus:9090
isDefault: true
editable: false
- name: Postgres (tachi_dev)
type: postgres
access: proxy
url: tachi-postgres:5432
user: tachi
secureJsonData:
password: tachi
jsonData:
database: tachi_dev
sslmode: disable
maxOpenConns: 5
maxIdleConns: 2
connMaxLifetime: 14400
isDefault: false
editable: true
- name: Postgres (kamai)
type: postgres
access: proxy
url: tachi-postgres:5432
user: tachi
secureJsonData:
password: tachi
jsonData:
database: kamai
sslmode: disable
maxOpenConns: 5
maxIdleConns: 2
connMaxLifetime: 14400
isDefault: false
editable: true
- name: Postgres (boku)
type: postgres
access: proxy
url: tachi-postgres:5432
user: tachi
secureJsonData:
password: tachi
jsonData:
database: boku
sslmode: disable
maxOpenConns: 5
maxIdleConns: 2
connMaxLifetime: 14400
isDefault: false
editable: true
+5
View File
@@ -0,0 +1,5 @@
# Metrics are ingested via remote write from Grafana Alloy (see alloy-config.alloy).
global:
scrape_interval: 15s
scrape_configs: []
+157
View File
@@ -0,0 +1,157 @@
#!/usr/bin/env bash
set -euo pipefail
GRAFANA_URL="${GRAFANA_URL:-http://tachi-grafana:3000}"
GRAFANA_USER="${GRAFANA_USER:-admin}"
GRAFANA_PASS="${GRAFANA_PASS:-admin}"
PROM_URL="${PROM_URL:-http://tachi-prometheus:9090}"
ALLOY_URL="${ALLOY_URL:-http://tachi-alloy:12345}"
MAX_WAIT="${MAX_WAIT:-60}"
auth="${GRAFANA_USER}:${GRAFANA_PASS}"
wait_for_grafana() {
local elapsed=0
printf "Waiting for Grafana at %s " "$GRAFANA_URL"
while ! curl -sf -o /dev/null "${GRAFANA_URL}/api/health" 2>/dev/null; do
if (( elapsed >= MAX_WAIT )); then
printf "\nGrafana did not become ready within %ds\n" "$MAX_WAIT" >&2
exit 1
fi
sleep 2
elapsed=$((elapsed + 2))
printf "."
done
printf " ready (%ds)\n" "$elapsed"
}
upsert_datasource() {
local name="$1" type="$2" url="$3" is_default="$4"
local existing
existing=$(curl -sf -u "$auth" "${GRAFANA_URL}/api/datasources/name/${name}" 2>/dev/null || true)
local payload
payload=$(cat <<EOF
{
"name": "${name}",
"type": "${type}",
"access": "proxy",
"url": "${url}",
"isDefault": ${is_default},
"editable": true
}
EOF
)
if [ -n "$existing" ] && echo "$existing" | grep -q '"id"'; then
if echo "$existing" | grep -q '"readOnly":true'; then
printf " %-12s ok (provisioned, read-only)\n" "$name"
return 0
fi
local uid
uid=$(echo "$existing" | grep -o '"uid":"[^"]*"' | head -1 | cut -d'"' -f4)
local status
status=$(curl -s -o /dev/null -w "%{http_code}" -u "$auth" \
-X PUT "${GRAFANA_URL}/api/datasources/uid/${uid}" \
-H "Content-Type: application/json" \
-d "$payload")
if [ "$status" = "200" ]; then
printf " %-12s updated (uid=%s)\n" "$name" "$uid"
else
printf " %-12s update failed (HTTP %s)\n" "$name" "$status" >&2
return 1
fi
else
local resp
resp=$(curl -s -u "$auth" \
-X POST "${GRAFANA_URL}/api/datasources" \
-H "Content-Type: application/json" \
-d "$payload" 2>&1) || true
if echo "$resp" | grep -q '"datasource"'; then
local uid
uid=$(echo "$resp" | grep -o '"uid":"[^"]*"' | head -1 | cut -d'"' -f4)
printf " %-12s created (uid=%s)\n" "$name" "$uid"
elif echo "$resp" | grep -q "data source with the same name already exists"; then
printf " %-12s already exists (provisioned)\n" "$name"
else
printf " %-12s create failed: %s\n" "$name" "$resp" >&2
return 1
fi
fi
}
health_check() {
local name="$1"
local resp
resp=$(curl -sf -u "$auth" "${GRAFANA_URL}/api/datasources/name/${name}" 2>/dev/null || true)
if [ -z "$resp" ]; then
printf " %-12s not found\n" "$name" >&2
return 1
fi
local uid
uid=$(echo "$resp" | grep -o '"uid":"[^"]*"' | head -1 | cut -d'"' -f4)
local check
check=$(curl -sf -u "$auth" \
-X POST "${GRAFANA_URL}/api/datasources/uid/${uid}/health" \
-H "Content-Type: application/json" 2>&1) || true
if echo "$check" | grep -q '"status":"OK"'; then
printf " %-12s healthy\n" "$name"
elif echo "$check" | grep -q '"status":"ERROR"'; then
local msg
msg=$(echo "$check" | grep -o '"message":"[^"]*"' | head -1 | cut -d'"' -f4)
printf " %-12s unhealthy: %s\n" "$name" "$msg" >&2
return 1
else
printf " %-12s health unknown (endpoint may not be supported)\n" "$name"
fi
}
reload_provisioning() {
local kind="$1"
local status
status=$(curl -sf -o /dev/null -w "%{http_code}" -u "$auth" \
-X POST "${GRAFANA_URL}/api/admin/provisioning/${kind}/reload" 2>/dev/null) || true
if [ "$status" = "200" ]; then
printf " %-12s reloaded\n" "$kind"
else
printf " %-12s reload failed (HTTP %s)\n" "$kind" "$status" >&2
fi
}
wait_for_grafana
echo "Registering datasources:"
upsert_datasource "Prometheus" "prometheus" "$PROM_URL" "true"
echo "Reloading provisioning:"
reload_provisioning "datasources"
reload_provisioning "dashboards"
echo "Health checks:"
health_check "Prometheus"
health_check "Postgres"
echo "Reloading Alloy config:"
alloy_status=$(curl -s -o /dev/null -w "%{http_code}" -X POST "${ALLOY_URL}/-/reload" 2>/dev/null) || true
if [ "$alloy_status" = "200" ]; then
printf " %-12s reloaded\n" "Alloy"
else
printf " %-12s reload failed (HTTP %s)\n" "Alloy" "$alloy_status" >&2
fi
echo "Done."
+12
View File
@@ -4,3 +4,15 @@ GRANT ALL PRIVILEGES ON DATABASE tachi_dev TO tachi;
-- Match genesis: pg_stat_statements (requires shared_preload_libraries in docker-compose).
\connect tachi_dev
CREATE EXTENSION IF NOT EXISTS pg_stat_statements;
-- Read-only user for Grafana dashboards.
DO $$
BEGIN
IF NOT EXISTS (SELECT FROM pg_catalog.pg_roles WHERE rolname = 'grafana_ro') THEN
CREATE ROLE grafana_ro WITH LOGIN PASSWORD 'grafana_ro';
END IF;
END$$;
GRANT CONNECT ON DATABASE tachi_dev TO grafana_ro;
GRANT USAGE ON SCHEMA public TO grafana_ro;
GRANT SELECT ON ALL TABLES IN SCHEMA public TO grafana_ro;
ALTER DEFAULT PRIVILEGES FOR ROLE tachi IN SCHEMA public GRANT SELECT ON TABLES TO grafana_ro;