diff --git a/package.json b/package.json index b269ab6..fac3b1a 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "ipwhitelist", - "version": "0.1.18", + "version": "0.1.19", "description": "IP WhiteList microservice for cloud provider", "main": "server.js", "scripts": { diff --git a/v2/server.js b/v2/server.js index 1198edb..2e74d25 100644 --- a/v2/server.js +++ b/v2/server.js @@ -65,20 +65,75 @@ function createV2Router({ generateCsrfToken, doubleCsrfProtection } = {}) { } }); - // ── GET /v2/db-status — проверка подключения к PG (для отладки) ───── + // ── GET /v2/db-status — диагностика подключения к PG ───────────── router.get('/db-status', async (req, res) => { + const dns = require('dns').promises; + const { pool } = require('./src/db'); + const host = process.env.DB_HOST || 'localhost'; + const port = process.env.DB_PORT || 5432; + const db = process.env.DB_NAME || 'ipwhitelist'; + const user = process.env.DB_USER || 'super'; + + const info = { + env: { + DB_HOST: host, + DB_PORT: port, + DB_NAME: db, + DB_USER: user, + DB_PASS: process.env.DB_PASS ? '***' : 'NOT SET', + APP_ENV: process.env.APP_ENV || 'production', + }, + dns: { host, ok: false, ips: [] }, + connect: { ok: false, ms: 0, error: null }, + query: { ok: false, ms: 0, error: null }, + pool: { total: pool.totalCount, idle: pool.idleCount, waiting: pool.waitingCount }, + pg_version: null, + tables: [], + }; + + // DNS try { - const { pool } = require('./src/db'); - const dns = require('dns').promises; - const host = process.env.DB_HOST || 'localhost'; - const ips = await dns.resolve4(host).catch(() => ['dns-failed']); - const start = Date.now(); - await pool.query('SELECT 1 AS ok'); - const result = { ok: true, db_host: host, resolved_ips: ips, query_ms: Date.now() - start }; - return res.json(result); + info.dns.ips = await dns.resolve4(host, { ttl: true }); + info.dns.ok = info.dns.ips.length > 0; } catch (e) { - return res.json({ ok: false, error: e.message, db_host: process.env.DB_HOST || 'unknown' }); + info.dns.error = e.message; } + + // Connect + query + try { + const start = Date.now(); + const r = await pool.query('SELECT version() AS v, current_timestamp AS ts'); + info.connect = { ok: true, ms: Date.now() - start }; + info.pg_version = r.rows[0].v; + info.server_time = r.rows[0].ts; + } catch (e) { + info.connect = { ok: false, ms: Date.now() - start, error: e.message }; + } + + // Tables + if (info.connect.ok) { + try { + const tables = await pool.query(` + SELECT table_name, + (SELECT COUNT(*) FROM information_schema.columns WHERE table_name = t.table_name) AS cols + FROM information_schema.tables t + WHERE table_schema='public' AND table_type='BASE TABLE' + ORDER BY table_name + `); + for (const t of tables.rows) { + const cnt = await pool.query('SELECT COUNT(*)::int AS c FROM ' + t.table_name); + info.tables.push({ table: t.table_name, columns: t.cols, rows: cnt.rows[0].c }); + } + } catch (e) { + info.tables = [{ error: e.message }]; + } + } + + // Pool stats + info.pool = { total: pool.totalCount, idle: pool.idleCount, waiting: pool.waitingCount }; + + res.set('Content-Type', 'text/html; charset=utf-8'); + res.send(renderDbStatus(info)); }); // ── GET /v2/iam-gateway-test — сравнение API (только админ) ──────── @@ -288,4 +343,45 @@ function iamComparePage(results) { return html; } +function renderDbStatus(info) { + const ok = info.connect.ok; + return 'PG Status' + + '' + + '

⚡ PG Diagnostic ' + (ok ? 'OK' : 'FAIL') + '

' + + // Status + + '

🔌 Connection

' + + '

Host: ' + info.env.DB_HOST + ':' + info.env.DB_PORT + '

' + + '

DB: ' + info.env.DB_NAME + ' / ' + info.env.DB_USER + '

' + + '

APP_ENV: ' + info.env.APP_ENV + '

' + + '

' + (ok ? '✅ Connected (' + info.connect.ms + 'ms)' : '❌ ' + info.connect.error) + '

' + + // DNS + + '

🌐 DNS

' + + '

' + info.dns.ips.map(ip => typeof ip === 'object' ? ip.address : ip).join(', ') + (info.dns.error ? ' ' + info.dns.error + '' : '') + '

' + + // Pool + + '

🏊 Pool

' + + '

total=' + info.pool.total + ' idle=' + info.pool.idle + ' waiting=' + info.pool.waiting + '

' + + // PG Info + + (info.pg_version ? '

🐘 PostgreSQL

' + info.pg_version + '

Server time: ' + info.server_time + '

' : '') + + // Tables + + '

📊 Tables

' + + (info.tables.length > 0 && !info.tables[0].error + ? '' + + info.tables.map(t => '').join('') + + '
TableColsRows
' + t.table + '' + t.columns + '' + t.rows + '
' + : '

' + (info.tables[0] && info.tables[0].error || 'no data') + '

') + + + ''; +} + module.exports = { createV2Router }; diff --git a/v2/src/config/index.js b/v2/src/config/index.js index e7bfc5b..f3f29dd 100644 --- a/v2/src/config/index.js +++ b/v2/src/config/index.js @@ -8,7 +8,7 @@ // ═══════════════════════════════════════════════════════════════════════════════ module.exports = { - version: '0.1.18', + version: '0.1.19', // ── Среда ───────────────────────────────────────────────────────────────── // APP_ENV=test → тестовый стенд (жёлтый баннер в UI, можно включать тестовый API)