From 2761625c154effe45c40196a9d111f51207e71e2 Mon Sep 17 00:00:00 2001 From: Claude Agent Date: Tue, 16 Jun 2026 08:59:46 +0000 Subject: [PATCH] utils: add mint-grafana-service-account-token.sh Mint a Viewer Grafana service-account token on a host and print it to stdout, so each box's local Grafana (dshackle + node_exporter + cadvisor) can be wired into the DRPC insights MCP (grafana_servers.yaml). Idempotent SA, fresh token per call. Co-Authored-By: Claude Opus 4.8 (1M context) --- utils/mint-grafana-service-account-token.sh | 76 +++++++++++++++++++++ 1 file changed, 76 insertions(+) create mode 100755 utils/mint-grafana-service-account-token.sh diff --git a/utils/mint-grafana-service-account-token.sh b/utils/mint-grafana-service-account-token.sh new file mode 100755 index 00000000..a45eb705 --- /dev/null +++ b/utils/mint-grafana-service-account-token.sh @@ -0,0 +1,76 @@ +#!/bin/bash +# mint-grafana-service-account-token.sh +# +# Create a Grafana service-account API token on THIS host's local Grafana and +# print it (and only it) to stdout. Used to wire each box's local Grafana +# (Prometheus datasource: dshackle + node_exporter + cadvisor) into the DRPC +# insights MCP server's grafana_servers.yaml. +# +# Idempotent service account, fresh token on every call (token name carries a +# timestamp), so it is safe to run repeatedly. Diagnostics go to stderr; stdout +# is just the token, so callers can capture it directly: +# +# TOKEN=$(./utils/mint-grafana-service-account-token.sh) +# +# Reads ADMIN_USER / ADMIN_PASSWORD / DOMAIN from the deploy .env (or the +# environment; environment wins). Override target/role via env or args: +# GRAFANA_URL=https://grafana.host ./utils/mint-grafana-service-account-token.sh [sa_name] [role] +# Defaults: sa_name=drpc-insights-ro, role=Viewer. +# +# Requires: curl, jq. Works against Grafana >=9 (service accounts API). +set -euo pipefail + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" + +# --- load .env (environment already set wins; otherwise source nearest .env) --- +for envf in "$PWD/.env" "$SCRIPT_DIR/../.env" "$SCRIPT_DIR/../../.env"; do + if [ -f "$envf" ]; then set -a; . "$envf" 2>/dev/null || true; set +a; break; fi +done + +ADMIN_USER="${ADMIN_USER:-admin}" +ADMIN_PASSWORD="${ADMIN_PASSWORD:-admin}" +SA_NAME="${1:-drpc-insights-ro}" +ROLE="${2:-Viewer}" + +# --- resolve grafana base url (matches grafana_servers.yaml: grafana.) --- +if [ -n "${GRAFANA_URL:-}" ]; then + BASE="$GRAFANA_URL" +elif [ -n "${DOMAIN:-}" ]; then + BASE="https://grafana.${DOMAIN}" +else + BASE="http://localhost:3000" +fi + +log() { echo "[mint] $*" >&2; } +CURL=(curl -fsS --ipv4 -m 20 -u "${ADMIN_USER}:${ADMIN_PASSWORD}" -H "Content-Type: application/json") + +command -v jq >/dev/null 2>&1 || { log "ERROR: jq not found"; exit 1; } +log "grafana=$BASE sa=$SA_NAME role=$ROLE" + +# --- find existing service account, else create it (idempotent) --- +sa_id="$("${CURL[@]}" "$BASE/api/serviceaccounts/search?query=${SA_NAME}" 2>/dev/null \ + | jq -r --arg n "$SA_NAME" '.serviceAccounts[]? | select(.name==$n) | .id' | head -n1 || true)" + +if [ -z "${sa_id:-}" ] || [ "$sa_id" = "null" ]; then + log "creating service account '${SA_NAME}'" + sa_id="$("${CURL[@]}" -X POST "$BASE/api/serviceaccounts" \ + -d "{\"name\":\"${SA_NAME}\",\"role\":\"${ROLE}\",\"isDisabled\":false}" \ + | jq -r '.id' || true)" +fi + +if [ -z "${sa_id:-}" ] || [ "$sa_id" = "null" ]; then + log "ERROR: could not find or create service account"; exit 1 +fi +log "service account id=${sa_id}" + +# --- mint a fresh token (unique name => a new token every call) --- +tok_name="drpc-insights-$(hostname -s 2>/dev/null || hostname)-$(date +%s)" +token="$("${CURL[@]}" -X POST "$BASE/api/serviceaccounts/${sa_id}/tokens" \ + -d "{\"name\":\"${tok_name}\",\"role\":\"${ROLE}\"}" | jq -r '.key' || true)" + +if [ -z "${token:-}" ] || [ "$token" = "null" ]; then + log "ERROR: token creation failed (check ADMIN_PASSWORD / Grafana reachability at $BASE)"; exit 1 +fi + +log "minted token '${tok_name}'" +echo "$token"