SysDeck/klanker-gate/deploy/observability/grafana-observer.sh

65 lines
2.4 KiB
Bash
Executable File

#!/bin/sh
# Create-or-update the `frosty-observer` Grafana account with the Editor role.
#
# Why an account and not a role: Grafana OSS cannot define custom RBAC roles -
# /api/access-control/roles is Enterprise-licensed and 404s here - so a
# pre-provisioned principal with a scoped basic role is the OSS equivalent.
# Anonymous access stays read-only Viewer; this account is what trace drill-down
# through Explore uses.
#
# Idempotent: safe to re-run, and re-running fixes a drifted role or password.
set -eu
API="${GF_URL:-http://grafana:3000}"
AUTH="${GF_ADMIN_USER}:${GF_ADMIN_PASSWORD}"
LOGIN="${GF_OBSERVER_USER}"
PASSWORD="${GF_OBSERVER_PASSWORD}"
ROLE="${GF_OBSERVER_ROLE:-Editor}"
api() {
# $1 method, $2 path, $3 optional JSON body. Prints body, then HTTP code on
# the last line so the caller can branch on it.
if [ $# -ge 3 ]; then
curl -sS -u "$AUTH" -X "$1" -H 'Content-Type: application/json' \
-d "$3" -w '\n%{http_code}' "$API$2"
else
curl -sS -u "$AUTH" -X "$1" -w '\n%{http_code}' "$API$2"
fi
}
code_of() { printf '%s' "$1" | tail -n 1; }
body_of() { printf '%s' "$1" | sed '$d'; }
# Grafana can accept connections a moment before its API is serving.
i=0
until [ "$(code_of "$(api GET /api/health)")" = "200" ]; do
i=$((i + 1))
[ "$i" -lt 60 ] || { echo "grafana API never became ready" >&2; exit 1; }
sleep 2
done
lookup=$(api GET "/api/users/lookup?loginOrEmail=$LOGIN")
if [ "$(code_of "$lookup")" = "200" ]; then
id=$(body_of "$lookup" | sed -n 's/.*"id":\([0-9]*\).*/\1/p')
echo "grafana: '$LOGIN' exists (id=$id)"
# Re-assert the password so a redeploy with new credentials converges.
api PUT "/api/admin/users/$id/password" "{\"password\":\"$PASSWORD\"}" >/dev/null
else
created=$(api POST /api/admin/users \
"{\"name\":\"Frosty Observer\",\"login\":\"$LOGIN\",\"password\":\"$PASSWORD\"}")
if [ "$(code_of "$created")" != "200" ]; then
echo "grafana: failed to create '$LOGIN': $(body_of "$created")" >&2
exit 1
fi
id=$(body_of "$created" | sed -n 's/.*"id":\([0-9]*\).*/\1/p')
echo "grafana: created '$LOGIN' (id=$id)"
fi
# Org role is what actually gates Explore, so assert it every run.
role=$(api PATCH "/api/org/users/$id" "{\"role\":\"$ROLE\"}")
if [ "$(code_of "$role")" != "200" ]; then
echo "grafana: failed to set role $ROLE on '$LOGIN': $(body_of "$role")" >&2
exit 1
fi
echo "grafana: '$LOGIN' has org role $ROLE - sign in to use Explore -> Tempo"