graphs: send service graphs

This commit is contained in:
Girish Ramakrishnan
2022-10-13 20:32:36 +02:00
parent 6d8c3febac
commit 4015afc69c
8 changed files with 67 additions and 54 deletions

View File

@@ -2,7 +2,7 @@
exports = module.exports = {
getSystem,
getApp
getContainerStats
};
const apps = require('./apps.js'),
@@ -10,6 +10,7 @@ const apps = require('./apps.js'),
BoxError = require('./boxerror.js'),
docker = require('./docker.js'),
safe = require('safetydance'),
services = require('./services.js'),
superagent = require('superagent');
// for testing locally: curl 'http://${graphite-ip}:8000/graphite-web/render?format=json&from=-1min&target=absolute(collectd.localhost.du-docker.capacity-usage)'
@@ -25,8 +26,8 @@ async function getGraphiteUrl() {
return `http://${ip}:8000/graphite-web/render`;
}
async function getApp(app, fromMinutes, noNullPoints) {
assert.strictEqual(typeof app, 'object');
async function getContainerStats(name, fromMinutes, noNullPoints) {
assert.strictEqual(typeof name, 'string');
assert.strictEqual(typeof fromMinutes, 'number');
assert.strictEqual(typeof noNullPoints, 'boolean');
@@ -34,13 +35,13 @@ async function getApp(app, fromMinutes, noNullPoints) {
const graphiteUrl = await getGraphiteUrl();
const targets = [
`summarize(collectd.localhost.docker-stats-${app.id}.gauge-cpu-perc, "${timeBucketSize}min", "avg")`,
`summarize(collectd.localhost.docker-stats-${app.id}.gauge-mem-used, "${timeBucketSize}min", "avg")`,
// `summarize(collectd.localhost.docker-stats-${app.id}.gauge-mem-max, "${timeBucketSize}min", "avg")`,
`summarize(collectd.localhost.docker-stats-${app.id}.counter-blockio-read, "${timeBucketSize}min", "sum")`,
`summarize(collectd.localhost.docker-stats-${app.id}.counter-blockio-write, "${timeBucketSize}min", "sum")`,
`summarize(collectd.localhost.docker-stats-${app.id}.counter-network-read, "${timeBucketSize}min", "sum")`,
`summarize(collectd.localhost.docker-stats-${app.id}.counter-network-write, "${timeBucketSize}min", "sum")`,
`summarize(collectd.localhost.docker-stats-${name}.gauge-cpu-perc, "${timeBucketSize}min", "avg")`,
`summarize(collectd.localhost.docker-stats-${name}.gauge-mem-used, "${timeBucketSize}min", "avg")`,
// `summarize(collectd.localhost.docker-stats-${name}.gauge-mem-max, "${timeBucketSize}min", "avg")`,
`summarize(collectd.localhost.docker-stats-${name}.counter-blockio-read, "${timeBucketSize}min", "sum")`,
`summarize(collectd.localhost.docker-stats-${name}.counter-blockio-write, "${timeBucketSize}min", "sum")`,
`summarize(collectd.localhost.docker-stats-${name}.counter-network-read, "${timeBucketSize}min", "sum")`,
`summarize(collectd.localhost.docker-stats-${name}.counter-network-write, "${timeBucketSize}min", "sum")`,
];
const results = [];
@@ -94,8 +95,13 @@ async function getSystem(fromMinutes, noNullPoints) {
const appResponses = {};
for (const app of await apps.list()) {
appResponses[app.id] = await getApp(app, fromMinutes, noNullPoints);
appResponses[app.id] = await getContainerStats(app.id, fromMinutes, noNullPoints);
}
return { cpu: memCpuResponse.body[0], memory: memCpuResponse.body[1], apps: appResponses };
const serviceResponses = {};
for (const serviceId of await services.listServices()) {
serviceResponses[serviceId] = await getContainerStats(serviceId, fromMinutes, noNullPoints);
}
return { cpu: memCpuResponse.body[0], memory: memCpuResponse.body[1], apps: appResponses, services: serviceResponses };
}

View File

@@ -58,6 +58,7 @@ exports = module.exports = {
updateBackup,
getLimits,
getGraphs,
load
};
@@ -68,6 +69,7 @@ const apps = require('../apps.js'),
BoxError = require('../boxerror.js'),
constants = require('../constants.js'),
debug = require('debug')('box:routes/apps'),
graphs = require('../graphs.js'),
HttpError = require('connect-lastmile').HttpError,
HttpSuccess = require('connect-lastmile').HttpSuccess,
safe = require('safetydance'),
@@ -959,3 +961,16 @@ async function getLimits(req, res, next) {
next(new HttpSuccess(200, { limits }));
}
async function getGraphs(req, res, next) {
assert.strictEqual(typeof req.app, 'object');
if (!req.query.fromMinutes || !parseInt(req.query.fromMinutes)) return next(new HttpError(400, 'fromMinutes must be a number'));
const fromMinutes = parseInt(req.query.fromMinutes);
const noNullPoints = !!req.query.noNullPoints;
const [error, result] = await safe(graphs.getContainerStats(req.app.id, fromMinutes, noNullPoints));
if (error) return next(new HttpError(500, error));
next(new HttpSuccess(200, result));
}

View File

@@ -25,7 +25,8 @@ exports = module.exports = {
getServerIpv6,
getLanguages,
syncExternalLdap,
syncDnsRecords
syncDnsRecords,
getSystemGraphs
};
const assert = require('assert'),
@@ -36,6 +37,7 @@ const assert = require('assert'),
debug = require('debug')('box:routes/cloudron'),
eventlog = require('../eventlog.js'),
externalLdap = require('../externalldap.js'),
graphs = require('../graphs.js'),
HttpError = require('connect-lastmile').HttpError,
HttpSuccess = require('connect-lastmile').HttpSuccess,
safe = require('safetydance'),
@@ -343,3 +345,14 @@ async function syncDnsRecords(req, res, next) {
next(new HttpSuccess(201, { taskId }));
}
async function getSystemGraphs(req, res, next) {
if (!req.query.fromMinutes || !parseInt(req.query.fromMinutes)) return next(new HttpError(400, 'fromMinutes must be a number'));
const fromMinutes = parseInt(req.query.fromMinutes);
const noNullPoints = !!req.query.noNullPoints;
const [error, result] = await safe(graphs.getSystem(fromMinutes, noNullPoints));
if (error) return next(new HttpError(500, error));
next(new HttpSuccess(200, result));
}

View File

@@ -1,36 +0,0 @@
'use strict';
exports = module.exports = {
getSystemGraphs,
getAppGraphs
};
const assert = require('assert'),
graphs = require('../graphs.js'),
HttpError = require('connect-lastmile').HttpError,
HttpSuccess = require('connect-lastmile').HttpSuccess,
safe = require('safetydance');
async function getSystemGraphs(req, res, next) {
if (!req.query.fromMinutes || !parseInt(req.query.fromMinutes)) return next(new HttpError(400, 'fromMinutes must be a number'));
const fromMinutes = parseInt(req.query.fromMinutes);
const noNullPoints = !!req.query.noNullPoints;
const [error, result] = await safe(graphs.getSystem(fromMinutes, noNullPoints));
if (error) return next(new HttpError(500, error));
next(new HttpSuccess(200, result));
}
async function getAppGraphs(req, res, next) {
assert.strictEqual(typeof req.app, 'object');
if (!req.query.fromMinutes || !parseInt(req.query.fromMinutes)) return next(new HttpError(400, 'fromMinutes must be a number'));
const fromMinutes = parseInt(req.query.fromMinutes);
const noNullPoints = !!req.query.noNullPoints;
const [error, result] = await safe(graphs.getApp(req.app, fromMinutes, noNullPoints));
if (error) return next(new HttpError(500, error));
next(new HttpSuccess(200, result));
}

View File

@@ -12,7 +12,6 @@ exports = module.exports = {
domains: require('./domains.js'),
eventlog: require('./eventlog.js'),
filemanager: require('./filemanager.js'),
graphs: require('./graphs.js'),
groups: require('./groups.js'),
mail: require('./mail.js'),
mailserver: require('./mailserver.js'),

View File

@@ -7,12 +7,14 @@ exports = module.exports = {
getLogs,
getLogStream,
restart,
rebuild
rebuild,
getGraphs
};
const assert = require('assert'),
AuditSource = require('../auditsource.js'),
BoxError = require('../boxerror.js'),
graphs = require('../graphs.js'),
HttpError = require('connect-lastmile').HttpError,
HttpSuccess = require('connect-lastmile').HttpSuccess,
safe = require('safetydance'),
@@ -131,3 +133,16 @@ async function rebuild(req, res, next) {
next(new HttpSuccess(202, {}));
}
async function getGraphs(req, res, next) {
assert.strictEqual(typeof req.params.service, 'string');
if (!req.query.fromMinutes || !parseInt(req.query.fromMinutes)) return next(new HttpError(400, 'fromMinutes must be a number'));
const fromMinutes = parseInt(req.query.fromMinutes);
const noNullPoints = !!req.query.noNullPoints;
const [error, result] = await safe(graphs.getContainerStats(req.params.service, fromMinutes, noNullPoints));
if (error) return next(new HttpError(500, error));
next(new HttpSuccess(200, result));
}

View File

@@ -116,7 +116,7 @@ function initializeExpressSync() {
router.post('/api/v1/cloudron/check_for_updates', json, token, authorizeAdmin, routes.cloudron.checkForUpdates);
router.get ('/api/v1/cloudron/reboot', token, authorizeAdmin, routes.cloudron.isRebootRequired);
router.post('/api/v1/cloudron/reboot', json, token, authorizeAdmin, routes.cloudron.reboot);
router.get ('/api/v1/cloudron/graphs', token, authorizeAdmin, routes.graphs.getSystemGraphs);
router.get ('/api/v1/cloudron/graphs', token, authorizeAdmin, routes.cloudron.getSystemGraphs);
router.get ('/api/v1/cloudron/disks', token, authorizeAdmin, routes.cloudron.getDisks);
router.get ('/api/v1/cloudron/disk_usage', token, authorizeAdmin, routes.cloudron.getDiskUsage);
router.post('/api/v1/cloudron/disk_usage', token, authorizeAdmin, routes.cloudron.updateDiskUsage);
@@ -250,7 +250,7 @@ function initializeExpressSync() {
router.get ('/api/v1/apps/:id/eventlog', token, routes.apps.load, authorizeOperator, routes.apps.listEventlog);
router.get ('/api/v1/apps/:id/limits', token, routes.apps.load, authorizeOperator, routes.apps.getLimits);
router.get ('/api/v1/apps/:id/task', token, routes.apps.load, authorizeOperator, routes.apps.getTask);
router.get ('/api/v1/apps/:id/graphs', token, routes.apps.load, authorizeOperator, routes.graphs.getAppGraphs);
router.get ('/api/v1/apps/:id/graphs', token, routes.apps.load, authorizeOperator, routes.apps.getGraphs);
router.post('/api/v1/apps/:id/clone', json, token, routes.apps.load, authorizeAdmin, routes.apps.clone);
router.get ('/api/v1/apps/:id/download', token, routes.apps.load, authorizeOperator, routes.apps.downloadFile);
router.post('/api/v1/apps/:id/upload', json, token, multipart, routes.apps.load, authorizeOperator, routes.apps.uploadFile);
@@ -356,6 +356,7 @@ function initializeExpressSync() {
router.get ('/api/v1/services', token, authorizeAdmin, routes.services.list);
router.get ('/api/v1/services/:service', token, authorizeAdmin, routes.services.get);
router.post('/api/v1/services/:service', json, token, authorizeAdmin, routes.services.configure);
router.get ('/api/v1/services/:service/graphs', token, authorizeAdmin, routes.services.getGraphs);
router.get ('/api/v1/services/:service/logs', token, authorizeAdmin, routes.services.getLogs);
router.get ('/api/v1/services/:service/logstream', token, authorizeAdmin, routes.services.getLogStream);
router.post('/api/v1/services/:service/restart', json, token, authorizeAdmin, routes.services.restart);

View File

@@ -310,7 +310,7 @@ async function containerStatus(containerName, tokenEnvName) {
}
async function listServices() {
let serviceIds = Object.keys(SERVICES);
const serviceIds = Object.keys(SERVICES);
const result = await apps.list();
for (let app of result) {