refactor(routes): Phase 3.5 - standardize monitoring.js (only 3 deps!)

This commit is contained in:
Krystie
2026-03-28 19:30:03 -07:00
parent 970e862533
commit f095ef24aa
2 changed files with 43 additions and 31 deletions

View File

@@ -1,72 +1,81 @@
const express = require('express'); const express = require('express');
const { success } = require('../response-helpers');
module.exports = function(ctx) { /**
* Monitoring routes factory
* @param {Object} deps - Explicit dependencies
* @param {Object} deps.resourceMonitor - Resource monitoring manager
* @param {Object} deps.docker - Docker client wrapper
* @param {Function} deps.asyncHandler - Async route handler wrapper
* @returns {express.Router}
*/
module.exports = function({ resourceMonitor, docker, asyncHandler }) {
const router = express.Router(); const router = express.Router();
// ===== RESOURCE MONITORING ENDPOINTS ===== // ===== RESOURCE MONITORING ENDPOINTS =====
// Get all container stats (from resource monitor module) // Get all container stats (from resource monitor module)
router.get('/monitoring/stats', ctx.asyncHandler(async (req, res) => { router.get('/monitoring/stats', asyncHandler(async (req, res) => {
const stats = ctx.resourceMonitor.getAllStats(); const stats = resourceMonitor.getAllStats();
res.json({ success: true, stats }); success(res, { stats });
}, 'monitoring-stats')); }, 'monitoring-stats'));
// Get stats for specific container // Get stats for specific container
router.get('/monitoring/stats/:containerId', ctx.asyncHandler(async (req, res) => { router.get('/monitoring/stats/:containerId', asyncHandler(async (req, res) => {
const stats = ctx.resourceMonitor.getCurrentStats(req.params.containerId); const stats = resourceMonitor.getCurrentStats(req.params.containerId);
if (!stats) { if (!stats) {
const { NotFoundError } = require('../errors'); const { NotFoundError } = require('../errors');
throw new NotFoundError('Container'); throw new NotFoundError('Container');
} }
res.json({ success: true, stats }); success(res, { stats });
}, 'monitoring-stats-container')); }, 'monitoring-stats-container'));
// Get historical stats // Get historical stats
router.get('/monitoring/history/:containerId', ctx.asyncHandler(async (req, res) => { router.get('/monitoring/history/:containerId', asyncHandler(async (req, res) => {
const hours = parseInt(req.query.hours) || 24; const hours = parseInt(req.query.hours) || 24;
const history = ctx.resourceMonitor.getHistoricalStats(req.params.containerId, hours); const history = resourceMonitor.getHistoricalStats(req.params.containerId, hours);
res.json({ success: true, history, hours }); success(res, { history, hours });
}, 'monitoring-history')); }, 'monitoring-history'));
// Get aggregated stats // Get aggregated stats
router.get('/monitoring/aggregated/:containerId', ctx.asyncHandler(async (req, res) => { router.get('/monitoring/aggregated/:containerId', asyncHandler(async (req, res) => {
const hours = parseInt(req.query.hours) || 24; const hours = parseInt(req.query.hours) || 24;
const aggregated = ctx.resourceMonitor.getAggregatedStats(req.params.containerId, hours); const aggregated = resourceMonitor.getAggregatedStats(req.params.containerId, hours);
if (!aggregated) { if (!aggregated) {
const { NotFoundError } = require('../errors'); const { NotFoundError } = require('../errors');
throw new NotFoundError('Monitoring data'); throw new NotFoundError('Monitoring data');
} }
res.json({ success: true, aggregated, hours }); success(res, { aggregated, hours });
}, 'monitoring-aggregated')); }, 'monitoring-aggregated'));
// Configure alerts // Configure alerts
router.post('/monitoring/alerts/:containerId', ctx.asyncHandler(async (req, res) => { router.post('/monitoring/alerts/:containerId', asyncHandler(async (req, res) => {
ctx.resourceMonitor.setAlertConfig(req.params.containerId, req.body); resourceMonitor.setAlertConfig(req.params.containerId, req.body);
res.json({ success: true, message: 'Alert configuration saved' }); success(res, { message: 'Alert configuration saved' });
}, 'monitoring-alerts-set')); }, 'monitoring-alerts-set'));
// Get alert configuration // Get alert configuration
router.get('/monitoring/alerts/:containerId', ctx.asyncHandler(async (req, res) => { router.get('/monitoring/alerts/:containerId', asyncHandler(async (req, res) => {
const config = ctx.resourceMonitor.getAlertConfig(req.params.containerId); const config = resourceMonitor.getAlertConfig(req.params.containerId);
res.json({ success: true, config: config || {} }); success(res, { config: config || {} });
}, 'monitoring-alerts-get')); }, 'monitoring-alerts-get'));
// Delete alert configuration // Delete alert configuration
router.delete('/monitoring/alerts/:containerId', ctx.asyncHandler(async (req, res) => { router.delete('/monitoring/alerts/:containerId', asyncHandler(async (req, res) => {
ctx.resourceMonitor.removeAlertConfig(req.params.containerId); resourceMonitor.removeAlertConfig(req.params.containerId);
res.json({ success: true, message: 'Alert configuration removed' }); success(res, { message: 'Alert configuration removed' });
}, 'monitoring-alerts-delete')); }, 'monitoring-alerts-delete'));
// ===== CONTAINER STATS ENDPOINTS (legacy /stats/) ===== // ===== CONTAINER STATS ENDPOINTS (legacy /stats/) =====
// Get all container stats (live Docker stats) // Get all container stats (live Docker stats)
router.get('/stats/containers', ctx.asyncHandler(async (req, res) => { router.get('/stats/containers', asyncHandler(async (req, res) => {
const containers = await ctx.docker.client.listContainers({ all: false }); const containers = await docker.client.listContainers({ all: false });
const stats = []; const stats = [];
for (const containerInfo of containers) { for (const containerInfo of containers) {
try { try {
const container = ctx.docker.client.getContainer(containerInfo.Id); const container = docker.client.getContainer(containerInfo.Id);
const containerStats = await container.stats({ stream: false }); const containerStats = await container.stats({ stream: false });
// Calculate CPU percentage // Calculate CPU percentage
@@ -114,12 +123,12 @@ module.exports = function(ctx) {
} }
} }
res.json({ success: true, stats, timestamp: new Date().toISOString() }); success(res, { stats, timestamp: new Date().toISOString() });
}, 'stats-containers')); }, 'stats-containers'));
// Get single container stats // Get single container stats
router.get('/stats/container/:id', ctx.asyncHandler(async (req, res) => { router.get('/stats/container/:id', asyncHandler(async (req, res) => {
const container = ctx.docker.client.getContainer(req.params.id); const container = docker.client.getContainer(req.params.id);
const containerStats = await container.stats({ stream: false }); const containerStats = await container.stats({ stream: false });
const info = await container.inspect(); const info = await container.inspect();
@@ -143,8 +152,7 @@ module.exports = function(ctx) {
} }
} }
res.json({ success(res, {
success: true,
stats: { stats: {
name: info.Name.replace(/^\//, ''), name: info.Name.replace(/^\//, ''),
image: info.Config.Image, image: info.Config.Image,

View File

@@ -1225,7 +1225,11 @@ apiRouter.use(healthRoutes({
logError: ctx.logError, logError: ctx.logError,
healthChecker: ctx.healthChecker healthChecker: ctx.healthChecker
})); }));
apiRouter.use(monitoringRoutes(ctx)); apiRouter.use(monitoringRoutes({
resourceMonitor: ctx.resourceMonitor,
docker: ctx.docker,
asyncHandler: ctx.asyncHandler
}));
apiRouter.use(updatesRoutes(ctx)); apiRouter.use(updatesRoutes(ctx));
apiRouter.use('/tailscale', tailscaleRoutes(ctx)); apiRouter.use('/tailscale', tailscaleRoutes(ctx));
apiRouter.use(sitesRoutes(ctx)); apiRouter.use(sitesRoutes(ctx));