From 3388f699a002c332af6b7a176f63b93ea7a539b1 Mon Sep 17 00:00:00 2001 From: Steve-Mcl Date: Thu, 24 Mar 2022 16:00:45 +0000 Subject: [PATCH] Add diagnostics endpoint fixes #3430 --- .../editor-api/lib/admin/diagnostics.js | 27 ++++ .../@node-red/editor-api/lib/admin/index.js | 5 + .../@node-red/runtime/lib/api/diagnostics.js | 116 ++++++++++++++++++ .../@node-red/runtime/lib/api/index.js | 2 + .../@node-red/runtime/lib/index.js | 7 +- packages/node_modules/node-red/lib/red.js | 9 +- 6 files changed, 164 insertions(+), 2 deletions(-) create mode 100644 packages/node_modules/@node-red/editor-api/lib/admin/diagnostics.js create mode 100644 packages/node_modules/@node-red/runtime/lib/api/diagnostics.js diff --git a/packages/node_modules/@node-red/editor-api/lib/admin/diagnostics.js b/packages/node_modules/@node-red/editor-api/lib/admin/diagnostics.js new file mode 100644 index 000000000..dd37e0fe4 --- /dev/null +++ b/packages/node_modules/@node-red/editor-api/lib/admin/diagnostics.js @@ -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); + }); + } +} diff --git a/packages/node_modules/@node-red/editor-api/lib/admin/index.js b/packages/node_modules/@node-red/editor-api/lib/admin/index.js index be9bb5317..a6e42fdfc 100644 --- a/packages/node_modules/@node-red/editor-api/lib/admin/index.js +++ b/packages/node_modules/@node-red/editor-api/lib/admin/index.js @@ -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; } } diff --git a/packages/node_modules/@node-red/runtime/lib/api/diagnostics.js b/packages/node_modules/@node-red/runtime/lib/api/diagnostics.js new file mode 100644 index 000000000..8440bd85e --- /dev/null +++ b/packages/node_modules/@node-red/runtime/lib/api/diagnostics.js @@ -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); + } + }) + }, +} diff --git a/packages/node_modules/@node-red/runtime/lib/api/index.js b/packages/node_modules/@node-red/runtime/lib/api/index.js index 46d15d1e7..d2fa3c6fd 100644 --- a/packages/node_modules/@node-red/runtime/lib/api/index.js +++ b/packages/node_modules/@node-red/runtime/lib/api/index.js @@ -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(); diff --git a/packages/node_modules/@node-red/runtime/lib/index.js b/packages/node_modules/@node-red/runtime/lib/index.js index b78d7d372..535b5f5e4 100644 --- a/packages/node_modules/@node-red/runtime/lib/index.js +++ b/packages/node_modules/@node-red/runtime/lib/index.js @@ -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, diff --git a/packages/node_modules/node-red/lib/red.js b/packages/node_modules/node-red/lib/red.js index 2c6f00a6e..4dc5f1281 100644 --- a/packages/node_modules/node-red/lib/red.js +++ b/packages/node_modules/node-red/lib/red.js @@ -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 } };