#!/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"