sqlite --> postgres

This commit is contained in:
2025-12-28 14:35:41 +09:00
parent 6196c03e46
commit 9de6af2789
3 changed files with 79 additions and 158 deletions

View File

@@ -1,4 +1,4 @@
import { getDb } from '../../../utils/db'
import { execute } from '../../../utils/db'
import { refreshServerTimer } from '../../../utils/server-scheduler'
export default defineEventHandler(async (event) => {
@@ -14,14 +14,13 @@ export default defineEventHandler(async (event) => {
// 스케줄러에서 제거
refreshServerTimer(Number(targetId))
const db = getDb()
const result = db.prepare(`
DELETE FROM server_targets WHERE target_id = ?
`).run(targetId)
const changes = await execute(
'DELETE FROM server_targets WHERE target_id = $1',
[targetId]
)
return {
success: true,
changes: result.changes
changes
}
})

View File

@@ -1,10 +1,10 @@
import { getDb } from '../../../utils/db'
import { execute } from '../../../utils/db'
import { refreshServerTimer } from '../../../utils/server-scheduler'
export default defineEventHandler(async (event) => {
const targetId = getRouterParam(event, 'id')
const body = await readBody(event)
const { server_name, server_ip, glances_url, is_active, collect_interval } = body
const { name, host, port, username, auth_type, is_active } = body
if (!targetId) {
throw createError({
@@ -13,24 +13,23 @@ export default defineEventHandler(async (event) => {
})
}
const db = getDb()
const result = db.prepare(`
const changes = await execute(`
UPDATE server_targets
SET server_name = ?,
server_ip = ?,
glances_url = ?,
is_active = ?,
collect_interval = ?,
updated_at = datetime('now', 'localtime')
WHERE target_id = ?
`).run(server_name, server_ip, glances_url, is_active ? 1 : 0, collect_interval || 60, targetId)
SET name = $1,
host = $2,
port = $3,
username = $4,
auth_type = $5,
is_active = $6,
updated_at = NOW()
WHERE target_id = $7
`, [name, host, port || 22, username, auth_type || 'password', is_active ? 1 : 0, targetId])
// 스케줄러에 반영
refreshServerTimer(Number(targetId))
return {
success: true,
changes: result.changes
changes
}
})

View File

@@ -1,4 +1,4 @@
import { getDb } from '../utils/db'
import { query, queryOne } from '../utils/db'
interface Client {
ws: any
@@ -9,11 +9,9 @@ interface Client {
const clients = new Map<any, Client>()
function getNetworkStatus() {
const db = getDb()
async function getNetworkStatus() {
// pubnet 상태
const pubnetStatus = db.prepare(`
const pubnetStatus = await queryOne(`
SELECT
ps.*,
pt.name as last_target_name,
@@ -21,9 +19,9 @@ function getNetworkStatus() {
FROM pubnet_status ps
LEFT JOIN pubnet_targets pt ON ps.last_target_id = pt.id
WHERE ps.id = 1
`).get()
`)
const pubnetLogs = db.prepare(`
const pubnetLogs = await query(`
SELECT
pl.*,
pt.name as target_name,
@@ -32,10 +30,10 @@ function getNetworkStatus() {
JOIN pubnet_targets pt ON pl.target_id = pt.id
ORDER BY pl.checked_at DESC
LIMIT 5
`).all()
`)
// privnet 상태
const privnetStatus = db.prepare(`
const privnetStatus = await queryOne(`
SELECT
ps.*,
pt.name as last_target_name,
@@ -43,9 +41,9 @@ function getNetworkStatus() {
FROM privnet_status ps
LEFT JOIN privnet_targets pt ON ps.last_target_id = pt.id
WHERE ps.id = 1
`).get()
`)
const privnetLogs = db.prepare(`
const privnetLogs = await query(`
SELECT
pl.*,
pt.name as target_name,
@@ -54,7 +52,7 @@ function getNetworkStatus() {
JOIN privnet_targets pt ON pl.target_id = pt.id
ORDER BY pl.checked_at DESC
LIMIT 5
`).all()
`)
return {
pubnet: {
@@ -69,35 +67,31 @@ function getNetworkStatus() {
}
}
function getHistoricalData(datetime: string) {
const db = getDb()
// 특정 시간 이전의 로그 조회
const pubnetLogs = db.prepare(`
async function getHistoricalData(datetime: string) {
const pubnetLogs = await query(`
SELECT
pl.*,
pt.name as target_name,
pt.url as target_url
FROM pubnet_logs pl
JOIN pubnet_targets pt ON pl.target_id = pt.id
WHERE pl.checked_at <= @datetime
WHERE pl.checked_at <= $1
ORDER BY pl.checked_at DESC
LIMIT 5
`).all({ datetime })
`, [datetime])
const privnetLogs = db.prepare(`
const privnetLogs = await query(`
SELECT
pl.*,
pt.name as target_name,
pt.url as target_url
FROM privnet_logs pl
JOIN privnet_targets pt ON pl.target_id = pt.id
WHERE pl.checked_at <= @datetime
WHERE pl.checked_at <= $1
ORDER BY pl.checked_at DESC
LIMIT 5
`).all({ datetime })
`, [datetime])
// 해당 시점의 최신 상태 (로그 기준)
const pubnetLatest = pubnetLogs[0] || null
const privnetLatest = privnetLogs[0] || null
@@ -123,9 +117,13 @@ function getHistoricalData(datetime: string) {
}
// 임계값 조회
function getThresholds() {
const db = getDb()
const rows = db.prepare(`SELECT category, metric, warning, critical, danger FROM thresholds`).all() as any[]
async function getThresholds() {
let rows: any[] = []
try {
rows = await query(`SELECT category, metric, warning, critical, danger FROM thresholds`)
} catch (e) {
// 테이블 없으면 빈 배열
}
const result: Record<string, Record<string, { warning: number; critical: number; danger: number }>> = {}
for (const row of rows) {
@@ -158,46 +156,38 @@ function getHighestLevel(levels: string[]): string {
}
// 서버 대시보드 데이터
function getServerDashboard() {
const db = getDb()
const thresholds = getThresholds()
async function getServerDashboard() {
const thresholds = await getThresholds()
const now = new Date()
const offlineThreshold = 5 * 60 * 1000 // 5분
// 서버 목록
const servers = db.prepare(`SELECT target_id, server_name, is_active FROM server_targets WHERE is_active = 1 ORDER BY server_name`).all() as any[]
const servers = await query(`
SELECT target_id, name as server_name, is_active
FROM server_targets
WHERE is_active = 1
ORDER BY name
`)
const serverStatuses: any[] = []
const summaryServers = { total: servers.length, normal: 0, warning: 0, critical: 0, danger: 0, offline: 0 }
const summaryContainers = { total: 0, normal: 0, warning: 0, critical: 0, danger: 0, stopped: 0 }
for (const server of servers) {
// 최신 스냅샷
const snapshot = db.prepare(`
SELECT cpu_percent, memory_percent, collected_at
FROM server_snapshots
WHERE target_id = ?
ORDER BY collected_at DESC
// 최신 로그
const snapshot = await queryOne(`
SELECT cpu_usage as cpu_percent, memory_usage as memory_percent, disk_usage as disk_percent, checked_at as collected_at
FROM server_logs
WHERE target_id = $1 AND is_success = 1
ORDER BY checked_at DESC
LIMIT 1
`).get(server.target_id) as any
// 디스크 정보 조회 (루트 마운트 또는 최대 사용률)
const disk = db.prepare(`
SELECT disk_percent
FROM server_disks
WHERE target_id = ?
ORDER BY
CASE WHEN mount_point = '/' THEN 0 ELSE 1 END,
disk_percent DESC
LIMIT 1
`).get(server.target_id) as any
`, [server.target_id])
// 오프라인 체크
let isOffline = true
let lastCollected = null
if (snapshot && snapshot.collected_at) {
lastCollected = snapshot.collected_at
const collectedTime = new Date(snapshot.collected_at.replace(' ', 'T') + '+09:00').getTime()
const collectedTime = new Date(snapshot.collected_at).getTime()
isOffline = (now.getTime() - collectedTime) > offlineThreshold
}
@@ -206,65 +196,13 @@ function getServerDashboard() {
let cpuLevel = 'normal', memLevel = 'normal', diskLevel = 'normal'
if (!isOffline && snapshot) {
cpuLevel = getLevel(snapshot.cpu_percent, thresholds.server?.cpu || { warning: 70, critical: 85, danger: 95 })
memLevel = getLevel(snapshot.memory_percent, thresholds.server?.memory || { warning: 80, critical: 90, danger: 95 })
diskLevel = getLevel(disk?.disk_percent ?? null, thresholds.server?.disk || { warning: 80, critical: 90, danger: 95 })
cpuLevel = getLevel(Number(snapshot.cpu_percent), thresholds.server?.cpu || { warning: 70, critical: 85, danger: 95 })
memLevel = getLevel(Number(snapshot.memory_percent), thresholds.server?.memory || { warning: 80, critical: 90, danger: 95 })
diskLevel = getLevel(Number(snapshot.disk_percent), thresholds.server?.disk || { warning: 80, critical: 90, danger: 95 })
serverLevel = getHighestLevel([cpuLevel, memLevel, diskLevel])
}
// 컨테이너 조회 (최신 데이터, 중복 제거)
const containers = db.prepare(`
SELECT container_name, container_status, cpu_percent, memory_usage, memory_limit, uptime, network_rx, network_tx
FROM server_containers
WHERE target_id = ? AND collected_at = (
SELECT MAX(collected_at) FROM server_containers WHERE target_id = ?
)
GROUP BY container_name
ORDER BY container_name
`).all(server.target_id, server.target_id) as any[]
const containerStatuses: any[] = []
const containerSummary = { total: containers.length, normal: 0, warning: 0, critical: 0, danger: 0, stopped: 0 }
for (const c of containers) {
let containerLevel = 'normal'
if (c.container_status !== 'running') {
containerLevel = 'stopped'
containerSummary.stopped++
} else {
const cCpuLevel = getLevel(c.cpu_percent, thresholds.container?.cpu || { warning: 80, critical: 90, danger: 95 })
const cMemPercent = c.memory_limit ? (c.memory_usage / c.memory_limit * 100) : null
const cMemLevel = getLevel(cMemPercent, thresholds.container?.memory || { warning: 80, critical: 90, danger: 95 })
containerLevel = getHighestLevel([cCpuLevel, cMemLevel])
if (containerLevel === 'normal') containerSummary.normal++
else if (containerLevel === 'warning') containerSummary.warning++
else if (containerLevel === 'critical') containerSummary.critical++
else if (containerLevel === 'danger') containerSummary.danger++
}
containerStatuses.push({
name: c.container_name,
status: c.container_status,
level: containerLevel,
cpu_percent: c.cpu_percent,
memory_usage: c.memory_usage,
memory_limit: c.memory_limit,
uptime: c.uptime,
network_rx: c.network_rx,
network_tx: c.network_tx
})
}
// 요약 집계
summaryContainers.total += containerSummary.total
summaryContainers.normal += containerSummary.normal
summaryContainers.warning += containerSummary.warning
summaryContainers.critical += containerSummary.critical
summaryContainers.danger += containerSummary.danger
summaryContainers.stopped += containerSummary.stopped
if (serverLevel === 'offline') summaryServers.offline++
else if (serverLevel === 'danger') summaryServers.danger++
else if (serverLevel === 'critical') summaryServers.critical++
@@ -279,23 +217,17 @@ function getServerDashboard() {
cpu_level: cpuLevel,
memory_percent: snapshot?.memory_percent ?? null,
memory_level: memLevel,
disk_percent: disk?.disk_percent ?? null,
disk_percent: snapshot?.disk_percent ?? null,
disk_level: diskLevel,
last_collected: lastCollected,
containers: containerStatuses,
container_summary: containerSummary
last_collected: lastCollected
})
}
// 서버 정렬: 컨테이너 많은 순 → 이름 순
serverStatuses.sort((a, b) => {
const containerDiff = (b.container_summary?.total || 0) - (a.container_summary?.total || 0)
if (containerDiff !== 0) return containerDiff
return a.server_name.localeCompare(b.server_name)
})
// 서버 정렬: 이름 순
serverStatuses.sort((a, b) => a.server_name.localeCompare(b.server_name))
return {
summary: { servers: summaryServers, containers: summaryContainers },
summary: { servers: summaryServers },
servers: serverStatuses,
timestamp: new Date().toISOString()
}
@@ -307,24 +239,23 @@ function startAutoRefresh(client: Client) {
}
if (client.autoRefresh) {
client.timer = setInterval(() => {
const data = getNetworkStatus()
client.timer = setInterval(async () => {
const data = await getNetworkStatus()
client.ws.send(JSON.stringify({ type: 'status', data }))
// 서버 대시보드 데이터도 전송
const serverData = getServerDashboard()
const serverData = await getServerDashboard()
client.ws.send(JSON.stringify({ type: 'server', data: serverData }))
}, client.interval)
}
}
export default defineWebSocketHandler({
open(peer) {
async open(peer) {
console.log('[WebSocket] Client connected')
const client: Client = {
ws: peer,
interval: 60 * 1000, // 기본 1분
interval: 60 * 1000,
timer: null,
autoRefresh: true
}
@@ -332,18 +263,16 @@ export default defineWebSocketHandler({
clients.set(peer, client)
// 초기 데이터 전송
const data = getNetworkStatus()
const data = await getNetworkStatus()
peer.send(JSON.stringify({ type: 'status', data }))
// 서버 대시보드 데이터 전송
const serverData = getServerDashboard()
const serverData = await getServerDashboard()
peer.send(JSON.stringify({ type: 'server', data: serverData }))
// 자동 갱신 시작
startAutoRefresh(client)
},
message(peer, message) {
async message(peer, message) {
const client = clients.get(peer)
if (!client) return
@@ -352,14 +281,12 @@ export default defineWebSocketHandler({
switch (msg.type) {
case 'set_interval':
// 간격 변경 (분 단위로 받음)
client.interval = msg.interval * 60 * 1000
console.log(`[WebSocket] Interval changed to ${msg.interval} min`)
startAutoRefresh(client)
break
case 'set_auto_refresh':
// 자동 갱신 ON/OFF
client.autoRefresh = msg.enabled
console.log(`[WebSocket] Auto refresh: ${msg.enabled}`)
if (msg.enabled) {
@@ -371,23 +298,19 @@ export default defineWebSocketHandler({
break
case 'fetch_at':
// 특정 시간 데이터 조회
const historicalData = getHistoricalData(msg.datetime)
const historicalData = await getHistoricalData(msg.datetime)
peer.send(JSON.stringify({ type: 'historical', data: historicalData }))
break
case 'refresh':
// 즉시 갱신 요청
const currentData = getNetworkStatus()
const currentData = await getNetworkStatus()
peer.send(JSON.stringify({ type: 'status', data: currentData }))
// 서버 데이터도 전송
const currentServerData = getServerDashboard()
const currentServerData = await getServerDashboard()
peer.send(JSON.stringify({ type: 'server', data: currentServerData }))
break
case 'refresh_server':
// 서버 대시보드만 즉시 갱신
const serverDashData = getServerDashboard()
const serverDashData = await getServerDashboard()
peer.send(JSON.stringify({ type: 'server', data: serverDashData }))
break
}