144 lines
9.3 KiB
Markdown
144 lines
9.3 KiB
Markdown
# История getpgdata — 2026-08-18
|
||
|
||
## Суть проекта
|
||
|
||
`getpgdata` — отдельное приложение для доступа к PostgreSQL (managed k8s, internal-only).
|
||
Разворачивается на платформе Nubes как **NodeJS managed service** (`nodejsk8s`).
|
||
|
||
Репозиторий: `https://gitea.services.ngcloud.ru/Nail/getpgdata.git` (ветка `master`).
|
||
Локальный путь: `/home/naeel/ipwhitelist-app/getpgdata`.
|
||
|
||
## 1. Создание (Flask-версия, ошибочная)
|
||
|
||
Первоначально приложение было собрано как **Flask (Python)** по howto `~/nubes/howto-flask-nubes.md`
|
||
(структура `site/app.py` + `requirements.txt`). Запушено коммитом `5c5e11c`.
|
||
|
||
**Функции Flask-версии:** главная со списком таблиц, просмотр таблицы, SQL-консоль (read-only), `/healthz`.
|
||
|
||
## 2. Ошибка пользователя и замена на Node.js
|
||
|
||
Пользователь указал, что перепутал стек — нужно **Node.js**, а не Flask.
|
||
|
||
**Решение:** Flask-файлы (`site/`, `requirements.txt`) удалены, создана Node.js структура
|
||
по образцу рабочего `ipwhitelist-app`:
|
||
|
||
```
|
||
getpgdata/
|
||
├── package.json # version 1.0.x; main server.js; start: node server.js
|
||
├── server.js # точка входа: Express + pg Pool
|
||
├── public/style.css
|
||
└── views/
|
||
├── index.ejs # главная: подключение + список таблиц
|
||
├── table.ejs # просмотр таблицы с пагинацией
|
||
├── query.ejs # SQL-консоль (read-only, только SELECT)
|
||
└── error.ejs
|
||
```
|
||
|
||
Коммит замены: `b061dcd`.
|
||
|
||
**Проверено:** `node -c server.js`, `npm install` (90 пакетов), реальный запуск сервера:
|
||
- `GET /` → 200 (рендер страницы)
|
||
- `GET /healthz` при недоступной БД → 503 (degraded, приложение не падает)
|
||
- `GET /table` без имени → 302 redirect
|
||
- `POST /query` не-SELECT → блокируется (read-only)
|
||
- статика `/public/style.css` → 200
|
||
|
||
## 3. Настройки подключения к БД
|
||
|
||
- Хост: `postgresqlk8s-master.60bdf3e3-5087-41ff-b760-fe6ea544a80e.svc.cluster.local`
|
||
- Порт: `5432`
|
||
- БД: `ipwhitelist` (коммит `102689d` — дефолт изменён с `postgres` на `ipwhitelist`)
|
||
- Пользователи: `super` (полный доступ) и `contracts` — оба с паролями из jsonEnv
|
||
- `DB_SSLMODE`: `disable`
|
||
|
||
Пароли в коде НЕ хранятся (читаются через `process.env.DB_PASS`). Готовые jsonEnv-блоки
|
||
на обоих пользователей добавлены в `README.md` (коммит `a890bb9`).
|
||
|
||
## 4. Проблема деплоя: под `nodejsk8s` не стартует
|
||
|
||
**Симптом (Nubes UI):**
|
||
> Приложение не запустилось. Производится полный откат установки.
|
||
> Error: jlib.k8s [correctReplicaActive] | ERROR | Под(ы) не работают: 'nodejsk8s' (Deployment).
|
||
|
||
**Диагноз (сравнение с работающим `whitelist`):**
|
||
|
||
| Параметр | `whitelist` (работает) | `getpgdata` (падал) |
|
||
|---|---|---|
|
||
| Точка входа | `server.js`, `main` в package.json | `server.js` ✓ |
|
||
| `npm start` | `node server.js` | `node server.js` ✓ |
|
||
| **Дефолтный порт** | **3000** | **5000** ✗ |
|
||
| Liveness | `/healthz` | `/healthz` ✓ |
|
||
| Старт без доступной БД | стартует | стартует ✓ |
|
||
|
||
**Гипотеза:** дефолтный порт `5000` (перенесён из Flask-версии) не совпадает с портом `3000`,
|
||
который ожидает платформа Nubes для NodeJS managed service. Health-проба не находила сервис →
|
||
под не Ready → «не работает nodejsk8s» → откат.
|
||
|
||
**Исправление:** дефолтный `PORT` в `server.js` изменён с `5000` на `3000`;
|
||
в `README.md` jsonEnv-блоки обновлены (`PORT: 3000`); `package.json` version → `1.0.1`.
|
||
|
||
**Проверено:** сервер запущен без env `PORT` → слушает `0.0.0.0:3000`, `/` → 200, `/healthz` → 503 (degraded).
|
||
|
||
**⚠️ НЕ проверено:** доступ к кластеру Nubes с этой машины отсутствует (`iot-naeel` и
|
||
`naeel-test-3` требуют OIDC-аутентификацию, managed-сервисы в них не видны). Поэтому
|
||
точную причину «почему под упал» по логам пода подтвердить нельзя — требуется лог пода
|
||
из Nubes UI. Если деплой после фикса порта снова не поднимется — смотреть логи пода
|
||
(`nodejsk8s` Deployment) в UI, а не только полагаться на гипотезу о порте.
|
||
|
||
## 5. Прочее
|
||
|
||
- `package-lock.json` закоммичен (зависимости: express, ejs, pg).
|
||
- `node_modules/` в `.gitignore`.
|
||
- Версия в `package.json` повышается при каждой правке кода (правило проекта).
|
||
|
||
## 6. Минимальный вывод на экран (фикс падения пода)
|
||
|
||
Несмотря на фикс порта (п.4), деплой снова упал — под `nodejsk8s` не поднялся.
|
||
|
||
**Требование пользователя:** «сделай код минимальным. Сам код не удаляй — сделай вывод
|
||
на экран какой-то информации и всё».
|
||
|
||
**Решение (коммит c8a776e, версия 1.0.2):**
|
||
- Роут `GET /` переписан так, чтобы **не зависеть от EJS-шаблонов**: отдаёт простой HTML
|
||
напрямую (`res.send`), выводя:
|
||
- версию Node, `APP_ENV`, PID
|
||
- конфиг БД (host, port, database, user)
|
||
- статус подключения к БД (или текст ошибки)
|
||
- список таблиц (или сообщение об ошибке)
|
||
- Каждая попытка работы с БД обёрнута в try/catch, поэтому страница **всегда** отдаёт 200
|
||
с информацией, даже если БД недоступна.
|
||
- Весь остальной код (роуты `/table`, `/query`, `/healthz`, `dbConfig`, `pool`) **не удалён** —
|
||
только главная страница упрощена.
|
||
|
||
**Проверено:** синтаксис OK; запуск без env `PORT` → слушает `0.0.0.0:3000`;
|
||
`GET /` → 200 (HTML с конфигом и статусом БД), `GET /healthz` при недоступной БД → 503 degraded.
|
||
|
||
**⚠️ Точная причина падения пода по-прежнему не подтверждена** (нет доступа к логам Nubes).
|
||
Если под не поднимется и после этого — смотреть логи `nodejsk8s` Deployment в Nubes UI:
|
||
replica не активна (CrashLoopBackOff, invalidImage, порт/health, зависший старт).
|
||
|
||
## 7. JSON API POST /api/sql (перенос данных в новую ПГ)
|
||
|
||
**Контекст:** нужно перенести белые списки (IP, кто создал, когда) из прежней БД в **новую**
|
||
PostgreSQL (тот же realm k8s). Доступ к новой БД — через Keycloak, автоматизировать нельзя.
|
||
Решение: код в репе `getpgdata` + передеплой с кредами новой ПГ.
|
||
|
||
**Что добавлено (версия 1.0.3):**
|
||
- Эндпоинт **`POST /api/sql`** — JSON API для произвольных SQL-команд.
|
||
Body: `{ "sql": "...", "params": [...] }` (params → `$1..$n`).
|
||
- `SELECT`/`WITH` → `{ ok:true, fields, rows, rowCount }` (всегда доступен)
|
||
- `INSERT`/`UPDATE`/`DELETE`/DDL → `{ ok:true, rowCount }` **только при `WRITE_SQL=1`**
|
||
- иначе → HTTP 403 «Write-SQL отключён»
|
||
- **Защита:** выполняется только первый statement (split по `;`) — блокирует мульти-команды
|
||
вроде `SELECT 1; DROP TABLE ...`.
|
||
- Флаг в env: `WRITE_SQL=1` включает запись.
|
||
|
||
**Логика переноса:**
|
||
1. Приложение подключено к прежней БД — читать данные через `/api/sql` (SELECT).
|
||
2. Сменить креды в jsonEnv на новую ПГ (+ `WRITE_SQL=1`).
|
||
3. Передеплой — теперь `/api/sql` выполняет запросы уже в новой БД; выполнить INSERT данных.
|
||
|
||
**Проверено:** `node -c server.js` OK; локально: пустой SQL → 400; SELECT → идёт в БД;
|
||
`INSERT` без `WRITE_SQL` → 403 (до попытки подключения); `WRITE_SQL=1` + мульти-statement →
|
||
берётся только первый; процесс проверки остановлен.
|