Add diagnostics endpoint

fixes #3430
This commit is contained in:
Steve-Mcl 2022-03-24 16:00:45 +00:00
parent cb88409102
commit 3388f699a0
6 changed files with 164 additions and 2 deletions

View File

@ -0,0 +1,27 @@
var apiUtils = require("@node-red/editor-api/lib/util");
/** @type {runtime.RuntimeModule} */var runtimeAPI;
module.exports = {
init: function(/** @type {runtime.RuntimeModule} */_runtimeAPI) {
runtimeAPI = _runtimeAPI;
},
getBasicReport: function(req, res) {
var opts = {
user: req.user,
scope: "basic"
}
runtimeAPI.diagnostics.get(opts).then(function(result) {
res.json(result);
});
},
getAdminReport: function(req, res) {
var opts = {
user: req.user,
scope: "admin"
}
runtimeAPI.diagnostics.get(opts).then(function(result) {
res.json(result);
});
}
}

View File

@ -23,6 +23,7 @@ var context = require("./context");
var auth = require("../auth");
var info = require("./settings");
var plugins = require("./plugins");
var diagnostics = require("./diagnostics");
var apiUtil = require("../util");
@ -34,6 +35,7 @@ module.exports = {
context.init(runtimeAPI);
info.init(settings,runtimeAPI);
plugins.init(runtimeAPI);
diagnostics.init(runtimeAPI);
var needsPermission = auth.needsPermission;
@ -95,6 +97,9 @@ module.exports = {
adminApp.get("/plugins", needsPermission("plugins.read"), plugins.getAll, apiUtil.errorHandler);
adminApp.get("/plugins/messages", needsPermission("plugins.read"), plugins.getCatalogs, apiUtil.errorHandler);
adminApp.get("/diagnostics/basic", needsPermission("settings.read"), diagnostics.getBasicReport, apiUtil.errorHandler);
adminApp.get("/diagnostics/admin", needsPermission("flows.write"), diagnostics.getAdminReport, apiUtil.errorHandler);
return adminApp;
}
}

View File

@ -0,0 +1,116 @@
/**
* @mixin @node-red/diagnostics
* @namespace RED.runtime.diagnostics
*/
var runtime;
var util = require("@node-red/util").util;
function buildDiagnosticReport(scope, callback) {
var basic = {
"report": "diagnostics",
"scope": scope,
"runtime": {
version: runtime.settings.version,
isStarted: runtime.isStarted()
},
settings: {
available: runtime.settings.available(),
apiMaxLength: runtime.settings.apiMaxLength || "NO SETTING",
coreNodesDir: runtime.settings.coreNodesDir,
contextStorage: listContextModules(),
debugMaxLength: runtime.settings.debugMaxLength,
editorTheme: runtime.settings.editorTheme,
flowFile: runtime.settings.flowFile,
disableEditor:runtime.settings.disableEditor,
debugMaxLength:runtime.settings.debugMaxLength,
httpAdminRoot: runtime.settings.httpAdminRoot,
httpAdminCors: runtime.settings.httpAdminCors ? "HAS SETTING": "NOT SET",
httpNodeAuth: runtime.settings.httpNodeAuth ? "HAS SETTING": "NOT SET",
httpNodeRoot: runtime.settings.httpNodeRoot,
httpNodeCors: runtime.settings.httpNodeCors ? "HAS SETTING": "NOT SET",
httpStatic: runtime.settings.httpStatic,
httpStaticCors: runtime.settings.httpStaticCors,
mqttReconnectTime: runtime.settings.mqttReconnectTime,
uiHost: runtime.settings.uiHost ? "HAS SETTING": "NOT SET",
uiPort: runtime.settings.uiPort ? "HAS SETTING": "NOT SET",
userDir: runtime.settings.userDir ? "HAS SETTING": "NOT SET",
version: runtime.settings.version
}
}
var admin = {};
if(scope == "admin") {
admin = {
httpAdminCors: runtime.settings.httpAdminCors ? runtime.settings.httpAdminCors : "NOT SET",
httpNodeCors: runtime.settings.httpNodeCors ? runtime.settings.httpNodeCors : "NOT SET",
uiHost: runtime.settings.uiHost ? runtime.settings.uiHost : "NOT SET",
uiPort: runtime.settings.uiPort ? runtime.settings.uiPort : "NOT SET",
userDir: runtime.settings.userDir ? runtime.settings.userDir : "NOT SET",
}
}
var report = Object.assign({}, admin, basic);
callback(report);
function listContextModules() {
var keys = Object.keys(runtime.settings.contextStorage);
var result = {};
keys.forEach(e => {
result[e] = {
module: runtime.settings.contextStorage[e].module
}
})
return result;
}
}
var api = module.exports = {
init: function (_runtime) {
runtime = _runtime;
},
/**
* Gets the node-red diagnostics report
* @param {{scope: string}} - settings
* @return {Promise} - the diagnostics information
* @memberof @node-red/diagnostics
*/
get: async function (opts) {
return new Promise(function (resolve, reject) {
opts = opts || {}
var scope = opts.scope;
try {
if (scope === 'admin') {
//admin level info
runtime.log.audit({ event: "diagnostics.get", scope: "admin" }, opts.req);
buildDiagnosticReport(scope, (report) => resolve(report));
} else if (scope === 'detail') {
//detail!
runtime.log.audit({ event: "diagnostics.get", scope: "detail" }, opts.req);
buildDiagnosticReport(scope, (report) => resolve(report));
} else if (scope === 'basic') {
//basic!
runtime.log.audit({ event: "diagnostics.get", scope: "basic" }, opts.req);
buildDiagnosticReport(scope, (report) => resolve(report));
} else {
runtime.log.audit({ event: "diagnostics.get", scope: scope }, opts.req);
resolve({});
}
} catch (error) {
runtime.log.audit({ event: "diagnostics.get", scope: scope }, opts.req);
reject(error);
}
})
},
}

View File

@ -29,6 +29,7 @@ var api = module.exports = {
api.projects.init(runtime);
api.context.init(runtime);
api.plugins.init(runtime);
api.diagnostics.init(runtime);
},
comms: require("./comms"),
@ -39,6 +40,7 @@ var api = module.exports = {
projects: require("./projects"),
context: require("./context"),
plugins: require("./plugins"),
diagnostics: require("./diagnostics"),
isStarted: async function(opts) {
return runtime.isStarted();

View File

@ -395,7 +395,12 @@ module.exports = {
* @memberof @node-red/runtime
*/
version: externalAPI.version,
/**
* @memberof @node-red/diagnostics
*/
diagnostics:externalAPI.diagnostics,
storage: storage,
events: events,
hooks: hooks,

View File

@ -229,5 +229,12 @@ module.exports = {
* @see @node-red/editor-api_auth
* @memberof node-red
*/
auth: api.auth
auth: api.auth,
/**
* The editor authentication api.
* @see @node-red/editor-api_auth
* @memberof node-red
*/
get diagnostics() { debugger; return api.diagnostics }
};