145 lines
4.7 KiB
JavaScript
145 lines
4.7 KiB
JavaScript
/**
|
|
* Система оповещений: агрегирует проблемы из availability и resources/stats.
|
|
* Критерии проблем: сервер недоступен, MikroTik недоступен, высокое CPU/RAM/HDD.
|
|
*/
|
|
|
|
const { sendError } = require('../middleware/errorHandler');
|
|
const { readServersFromS3 } = require('./serversRoutes');
|
|
const { checkOneServerFast } = require('./miscRoutes');
|
|
const { getResourceStatsData } = require('./resourceStatsRoutes');
|
|
|
|
/** Пороги для ресурсов (проценты). */
|
|
const THRESHOLD_CPU = 85;
|
|
const THRESHOLD_RAM = 85;
|
|
const THRESHOLD_HDD = 90;
|
|
|
|
/**
|
|
* GET /api/alerts
|
|
* Возвращает список активных оповещений.
|
|
*/
|
|
async function getAlerts(req, res) {
|
|
try {
|
|
const servers = await readServersFromS3();
|
|
const alerts = [];
|
|
const now = new Date().toISOString();
|
|
|
|
// 1) Доступность серверов (TCP 80/443)
|
|
const availabilityChecks = await Promise.allSettled(
|
|
servers.map((s) => checkOneServerFast(s))
|
|
);
|
|
servers.forEach((server, i) => {
|
|
const online = availabilityChecks[i].status === 'fulfilled' && availabilityChecks[i].value;
|
|
if (!online) {
|
|
const name = server.name || server.dns || server.ip || server.id || `Сервер #${i + 1}`;
|
|
alerts.push({
|
|
id: `server-offline-${server.id || server.dns || server.ip || i}`,
|
|
type: 'server_offline',
|
|
severity: 'critical',
|
|
title: 'Сервер недоступен',
|
|
description: `${name} не отвечает на TCP (80/443).`,
|
|
entity: name,
|
|
entityId: server.id || server.dns || server.ip,
|
|
link: '/servers',
|
|
at: now,
|
|
});
|
|
}
|
|
});
|
|
|
|
// 2) Ресурсы роутеров (MikroTik): ошибка доступа, высокое CPU/RAM/HDD
|
|
let resourceData;
|
|
try {
|
|
resourceData = await getResourceStatsData();
|
|
} catch (err) {
|
|
console.warn('alerts: getResourceStatsData failed', err?.message);
|
|
resourceData = { routers: [] };
|
|
}
|
|
|
|
const routers = resourceData.routers || [];
|
|
routers.forEach((router) => {
|
|
const { serverId, name, error, resource } = router;
|
|
const entityName = name || serverId;
|
|
|
|
if (error) {
|
|
alerts.push({
|
|
id: `mikrotik-error-${serverId}`,
|
|
type: 'mikrotik_unreachable',
|
|
severity: 'critical',
|
|
title: 'MikroTik недоступен',
|
|
description: `${entityName}: ${error}`,
|
|
entity: entityName,
|
|
entityId: serverId,
|
|
link: '/resource-stats',
|
|
at: now,
|
|
});
|
|
return;
|
|
}
|
|
|
|
if (!resource) return;
|
|
|
|
if (resource.cpuLoad != null && resource.cpuLoad >= THRESHOLD_CPU) {
|
|
alerts.push({
|
|
id: `cpu-high-${serverId}`,
|
|
type: 'high_cpu',
|
|
severity: 'warning',
|
|
title: 'Высокое использование CPU',
|
|
description: `${entityName}: ${resource.cpuLoad}% (порог ${THRESHOLD_CPU}%).`,
|
|
entity: entityName,
|
|
entityId: serverId,
|
|
value: resource.cpuLoad,
|
|
threshold: THRESHOLD_CPU,
|
|
link: '/resource-stats',
|
|
at: now,
|
|
});
|
|
}
|
|
if (resource.memoryUsagePercent != null && resource.memoryUsagePercent >= THRESHOLD_RAM) {
|
|
alerts.push({
|
|
id: `ram-high-${serverId}`,
|
|
type: 'high_ram',
|
|
severity: 'warning',
|
|
title: 'Высокое использование RAM',
|
|
description: `${entityName}: ${resource.memoryUsagePercent}% (порог ${THRESHOLD_RAM}%).`,
|
|
entity: entityName,
|
|
entityId: serverId,
|
|
value: resource.memoryUsagePercent,
|
|
threshold: THRESHOLD_RAM,
|
|
link: '/resource-stats',
|
|
at: now,
|
|
});
|
|
}
|
|
if (resource.hddUsagePercent != null && resource.hddUsagePercent >= THRESHOLD_HDD) {
|
|
alerts.push({
|
|
id: `hdd-high-${serverId}`,
|
|
type: 'high_hdd',
|
|
severity: 'warning',
|
|
title: 'Высокое использование диска',
|
|
description: `${entityName}: ${resource.hddUsagePercent}% (порог ${THRESHOLD_HDD}%).`,
|
|
entity: entityName,
|
|
entityId: serverId,
|
|
value: resource.hddUsagePercent,
|
|
threshold: THRESHOLD_HDD,
|
|
link: '/resource-stats',
|
|
at: now,
|
|
});
|
|
}
|
|
});
|
|
|
|
return res.json({
|
|
alerts,
|
|
total: alerts.length,
|
|
at: now,
|
|
});
|
|
} catch (error) {
|
|
console.error('getAlerts:', error);
|
|
return sendError(
|
|
res,
|
|
500,
|
|
error.message || 'Ошибка загрузки оповещений',
|
|
'E_ALERTS'
|
|
);
|
|
}
|
|
}
|
|
|
|
module.exports = {
|
|
getAlerts,
|
|
};
|