#!/usr/bin/env bash # Заводит read-only роль grafana_ro в базе glitchtip — под датасорс Grafana. # Идемпотентен: повторный запуск только досогласует права. # # ПОЧЕМУ ОТДЕЛЬНАЯ РОЛЬ, А НЕ ВЛАДЕЛЕЦ БАЗЫ. Датасорс Grafana доступен всякому, # кто вошёл в интерфейс, и позволяет выполнять произвольный SQL в панелях. # Владельческая роль сделала бы витрину способом уронить трекер ошибок. Здесь # прав на запись нет вовсе, поэтому худшее, что можно сделать через панель, — # медленный SELECT. # # Запускать на инфраструктурном хосте. Вызывается из deploy-metrics.yml. set -euo pipefail CONT=gendesign-infra-postgres DB=glitchtip ROLE=grafana_ro : "${GLITCHTIP_RO_PASSWORD:?GLITCHTIP_RO_PASSWORD не задан — запусти scripts/setup-metrics-secrets.sh}" if ! docker inspect "$CONT" >/dev/null 2>&1; then echo " $CONT не найден — пропускаю создание роли." exit 0 fi # Ищем роль с правом заводить других. Имя суперпользователя в этом кластере # нигде не зафиксировано, а угадывать «postgres» неверно: в образе оно задаётся # переменной POSTGRES_USER и здесь ею не является. # # Поэтому НЕ угадываем, а спрашиваем сам контейнер: POSTGRES_USER — это та самая # переменная, которой роль и была создана при initdb, то есть источник истины. # Прежний список был перебором трёх имён (glitchtip/forgejo/postgres), и ни одно # из них не совпадало ни с одним реальным кластером проекта: # # gendesign-infra-postgres → infra # gendesign-postgres-1 → gendesign # tradein-postgres → tradein # # Из-за этого деплой стека падал на первом же прогоне (#3099, задача 23657): # ОШИБКА: не нашёл роль с правом CREATE ROLE в gendesign-infra-postgres # Замер 26.08 на живом контейнере: glitchtip/forgejo/postgres — отказ, # infra — проходит. Список имён оставлен ПОСЛЕ него запасным путём: он # пригодится кластеру, поднятому не из образа postgres, где POSTGRES_USER пуст. SUPER="" _pg_user="$(docker exec "$CONT" sh -c 'printf %s "${POSTGRES_USER:-}"' 2>/dev/null || true)" for candidate in $_pg_user glitchtip forgejo postgres; do [ -n "$candidate" ] || continue if docker exec "$CONT" psql -U "$candidate" -d postgres -tAc \ "SELECT 1 FROM pg_roles WHERE rolname = CURRENT_USER AND (rolsuper OR rolcreaterole)" 2>/dev/null \ | grep -q 1; then SUPER="$candidate" break fi done if [ -z "$SUPER" ]; then echo " ОШИБКА: не нашёл роль с правом CREATE ROLE в $CONT." >&2 echo " Проверь вручную: docker exec $CONT psql -U <роль> -c '\\du'" >&2 exit 1 fi echo " привилегированная роль: $SUPER" # Пароль передаётся через переменную окружения psql, а не в тексте запроса — # иначе он осел бы в pg_stat_statements и в логе запросов. docker exec -e RO_PASS="$GLITCHTIP_RO_PASSWORD" -i "$CONT" \ psql -U "$SUPER" -d "$DB" -v ON_ERROR_STOP=1 <<'SQL' \set ro_pass `echo "$RO_PASS"` DO $$ BEGIN IF NOT EXISTS (SELECT 1 FROM pg_roles WHERE rolname = 'grafana_ro') THEN CREATE ROLE grafana_ro LOGIN; RAISE NOTICE 'роль grafana_ro создана'; ELSE RAISE NOTICE 'роль grafana_ro уже есть'; END IF; END $$; ALTER ROLE grafana_ro WITH PASSWORD :'ro_pass'; -- Ограничение на число соединений: панель с автообновлением способна открыть -- их десятками, а это тот же кластер, где живёт Forgejo. ALTER ROLE grafana_ro CONNECTION LIMIT 8; GRANT CONNECT ON DATABASE glitchtip 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 IN SCHEMA public GRANT SELECT ON TABLES TO grafana_ro; SQL echo " grafana_ro: права выданы на $DB"