@node-red/runtime 2.2.2 → 3.0.0-beta.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/api/diagnostics.js +202 -0
- package/lib/api/index.js +2 -0
- package/lib/api/settings.js +7 -0
- package/lib/flows/Flow.js +1 -1
- package/lib/index.js +12 -3
- package/lib/nodes/credentials.js +9 -1
- package/locales/en-US/runtime.json +6 -11
- package/locales/ja/runtime.json +3 -1
- package/package.json +5 -5
|
@@ -0,0 +1,202 @@
|
|
|
1
|
+
|
|
2
|
+
const os = require('os');
|
|
3
|
+
const fs = require('fs');
|
|
4
|
+
|
|
5
|
+
let runtime;
|
|
6
|
+
let isContainerCached;
|
|
7
|
+
let isWSLCached;
|
|
8
|
+
|
|
9
|
+
const isInWsl = () => {
|
|
10
|
+
if (isWSLCached === undefined) {
|
|
11
|
+
isWSLCached = getIsInWSL();
|
|
12
|
+
}
|
|
13
|
+
return isWSLCached;
|
|
14
|
+
function getIsInWSL() {
|
|
15
|
+
if (process.platform !== 'linux') {
|
|
16
|
+
return false;
|
|
17
|
+
}
|
|
18
|
+
try {
|
|
19
|
+
if (os.release().toLowerCase().includes('microsoft')) {
|
|
20
|
+
if (isInContainer()) {
|
|
21
|
+
return false;
|
|
22
|
+
}
|
|
23
|
+
return true;
|
|
24
|
+
}
|
|
25
|
+
return fs.readFileSync('/proc/version', 'utf8').toLowerCase().includes('microsoft') ? !isInContainer() : false;
|
|
26
|
+
} catch (_) {
|
|
27
|
+
return false;
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
const isInContainer = () => {
|
|
33
|
+
if (isContainerCached === undefined) {
|
|
34
|
+
isContainerCached = hasDockerEnv() || hasDockerCGroup();
|
|
35
|
+
}
|
|
36
|
+
return isContainerCached;
|
|
37
|
+
function hasDockerEnv() {
|
|
38
|
+
try {
|
|
39
|
+
fs.statSync('/.dockerenv');
|
|
40
|
+
return true;
|
|
41
|
+
} catch {
|
|
42
|
+
return false;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
function hasDockerCGroup() {
|
|
46
|
+
try {
|
|
47
|
+
const s = fs.readFileSync('/proc/self/cgroup', 'utf8');
|
|
48
|
+
if (s.includes('docker')) {
|
|
49
|
+
return "docker"
|
|
50
|
+
} else if (s.includes('kubepod')) {
|
|
51
|
+
return "kubepod"
|
|
52
|
+
} else if (s.includes('lxc')) {
|
|
53
|
+
return "lxc"
|
|
54
|
+
}
|
|
55
|
+
} catch {
|
|
56
|
+
return false;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
function buildDiagnosticReport(scope, callback) {
|
|
62
|
+
const modules = {};
|
|
63
|
+
const nl = runtime.nodes.getNodeList();
|
|
64
|
+
for (let i = 0; i < nl.length; i++) {
|
|
65
|
+
if (modules[nl[i].module]) {
|
|
66
|
+
continue;
|
|
67
|
+
}
|
|
68
|
+
modules[nl[i].module] = nl[i].version
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
const now = new Date();
|
|
72
|
+
const {locale, timeZone} = Intl.DateTimeFormat().resolvedOptions();
|
|
73
|
+
const report = {
|
|
74
|
+
report: "diagnostics",
|
|
75
|
+
scope: scope,
|
|
76
|
+
time: {
|
|
77
|
+
utc: now.toUTCString(),
|
|
78
|
+
local: now.toLocaleString(),
|
|
79
|
+
},
|
|
80
|
+
intl: {
|
|
81
|
+
locale, timeZone
|
|
82
|
+
},
|
|
83
|
+
nodejs: {
|
|
84
|
+
version: process.version,
|
|
85
|
+
arch: process.arch,
|
|
86
|
+
platform: process.platform,
|
|
87
|
+
memoryUsage: process.memoryUsage(),
|
|
88
|
+
},
|
|
89
|
+
os: {
|
|
90
|
+
containerised: isInContainer(),
|
|
91
|
+
wsl: isInWsl(),
|
|
92
|
+
totalmem: os.totalmem(),
|
|
93
|
+
freemem: os.freemem(),
|
|
94
|
+
arch: os.arch(),
|
|
95
|
+
loadavg: os.loadavg(),
|
|
96
|
+
platform: os.platform(),
|
|
97
|
+
release: os.release(),
|
|
98
|
+
type: os.type(),
|
|
99
|
+
uptime: os.uptime(),
|
|
100
|
+
version: os.version(),
|
|
101
|
+
},
|
|
102
|
+
runtime: {
|
|
103
|
+
isStarted: runtime.isStarted(),
|
|
104
|
+
modules: modules,
|
|
105
|
+
version: runtime.settings.version,
|
|
106
|
+
settings: {
|
|
107
|
+
available: runtime.settings.available(),
|
|
108
|
+
apiMaxLength: runtime.settings.apiMaxLength || "UNSET",
|
|
109
|
+
//coreNodesDir: runtime.settings.coreNodesDir,
|
|
110
|
+
disableEditor: runtime.settings.disableEditor,
|
|
111
|
+
contextStorage: listContextModules(),
|
|
112
|
+
debugMaxLength: runtime.settings.debugMaxLength || "UNSET",
|
|
113
|
+
editorTheme: runtime.settings.editorTheme || "UNSET",
|
|
114
|
+
flowFile: runtime.settings.flowFile || "UNSET",
|
|
115
|
+
mqttReconnectTime: runtime.settings.mqttReconnectTime || "UNSET",
|
|
116
|
+
serialReconnectTime: runtime.settings.serialReconnectTime || "UNSET",
|
|
117
|
+
|
|
118
|
+
adminAuth: runtime.settings.adminAuth ? "SET" : "UNSET",
|
|
119
|
+
|
|
120
|
+
httpAdminRoot: runtime.settings.httpAdminRoot || "UNSET",
|
|
121
|
+
httpAdminCors: runtime.settings.httpAdminCors ? "SET" : "UNSET",
|
|
122
|
+
httpNodeAuth: runtime.settings.httpNodeAuth ? "SET" : "UNSET",
|
|
123
|
+
|
|
124
|
+
httpNodeRoot: runtime.settings.httpNodeRoot || "UNSET",
|
|
125
|
+
httpNodeCors: runtime.settings.httpNodeCors ? "SET" : "UNSET",
|
|
126
|
+
|
|
127
|
+
httpStatic: runtime.settings.httpStatic ? "SET" : "UNSET",
|
|
128
|
+
httpStaticRoot: runtime.settings.httpStaticRoot || "UNSET",
|
|
129
|
+
httpStaticCors: runtime.settings.httpStaticCors ? "SET" : "UNSET",
|
|
130
|
+
|
|
131
|
+
uiHost: runtime.settings.uiHost ? "SET" : "UNSET",
|
|
132
|
+
uiPort: runtime.settings.uiPort ? "SET" : "UNSET",
|
|
133
|
+
userDir: runtime.settings.userDir ? "SET" : "UNSET",
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
// if (scope == "admin") {
|
|
139
|
+
// const moreSettings = {
|
|
140
|
+
// adminAuth_type: (runtime.settings.adminAuth && runtime.settings.adminAuth.type) ? runtime.settings.adminAuth.type : "UNSET",
|
|
141
|
+
// httpAdminCors: runtime.settings.httpAdminCors ? runtime.settings.httpAdminCors : "UNSET",
|
|
142
|
+
// httpNodeCors: runtime.settings.httpNodeCors ? runtime.settings.httpNodeCors : "UNSET",
|
|
143
|
+
// httpStaticCors: runtime.settings.httpStaticCors ? "SET" : "UNSET",
|
|
144
|
+
// settingsFile: runtime.settings.settingsFile ? runtime.settings.settingsFile : "UNSET",
|
|
145
|
+
// uiHost: runtime.settings.uiHost ? runtime.settings.uiHost : "UNSET",
|
|
146
|
+
// uiPort: runtime.settings.uiPort ? runtime.settings.uiPort : "UNSET",
|
|
147
|
+
// userDir: runtime.settings.userDir ? runtime.settings.userDir : "UNSET",
|
|
148
|
+
// }
|
|
149
|
+
// const moreNodejs = {
|
|
150
|
+
// execPath: process.execPath,
|
|
151
|
+
// pid: process.pid,
|
|
152
|
+
// }
|
|
153
|
+
// const moreOs = {
|
|
154
|
+
// cpus: os.cpus(),
|
|
155
|
+
// homedir: os.homedir(),
|
|
156
|
+
// hostname: os.hostname(),
|
|
157
|
+
// networkInterfaces: os.networkInterfaces(),
|
|
158
|
+
// }
|
|
159
|
+
// report.runtime.settings = Object.assign({}, report.runtime.settings, moreSettings);
|
|
160
|
+
// report.nodejs = Object.assign({}, report.nodejs, moreNodejs);
|
|
161
|
+
// report.os = Object.assign({}, report.os, moreOs);
|
|
162
|
+
// }
|
|
163
|
+
|
|
164
|
+
callback(report);
|
|
165
|
+
|
|
166
|
+
/** gets a sanitised list containing only the module name */
|
|
167
|
+
function listContextModules() {
|
|
168
|
+
const keys = Object.keys(runtime.settings.contextStorage || {});
|
|
169
|
+
const result = {};
|
|
170
|
+
keys.forEach(e => {
|
|
171
|
+
result[e] = {
|
|
172
|
+
module: String(runtime.settings.contextStorage[e].module)
|
|
173
|
+
}
|
|
174
|
+
})
|
|
175
|
+
return result;
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
|
|
180
|
+
module.exports = {
|
|
181
|
+
init: function (_runtime) {
|
|
182
|
+
runtime = _runtime;
|
|
183
|
+
},
|
|
184
|
+
/**
|
|
185
|
+
* Gets the node-red diagnostics report
|
|
186
|
+
* @param {{scope: string}} opts - settings
|
|
187
|
+
* @return {Promise} the diagnostics information
|
|
188
|
+
* @memberof @node-red/diagnostics
|
|
189
|
+
*/
|
|
190
|
+
get: async function (opts) {
|
|
191
|
+
return new Promise(function (resolve, reject) {
|
|
192
|
+
opts = opts || {}
|
|
193
|
+
try {
|
|
194
|
+
runtime.log.audit({ event: "diagnostics.get", scope: opts.scope }, opts.req);
|
|
195
|
+
buildDiagnosticReport(opts.scope, (report) => resolve(report));
|
|
196
|
+
} catch (error) {
|
|
197
|
+
error.status = 500;
|
|
198
|
+
reject(error);
|
|
199
|
+
}
|
|
200
|
+
})
|
|
201
|
+
},
|
|
202
|
+
}
|
package/lib/api/index.js
CHANGED
|
@@ -29,6 +29,7 @@ var api = module.exports = {
|
|
|
29
29
|
api.projects.init(runtime);
|
|
30
30
|
api.context.init(runtime);
|
|
31
31
|
api.plugins.init(runtime);
|
|
32
|
+
api.diagnostics.init(runtime);
|
|
32
33
|
},
|
|
33
34
|
|
|
34
35
|
comms: require("./comms"),
|
|
@@ -39,6 +40,7 @@ var api = module.exports = {
|
|
|
39
40
|
projects: require("./projects"),
|
|
40
41
|
context: require("./context"),
|
|
41
42
|
plugins: require("./plugins"),
|
|
43
|
+
diagnostics: require("./diagnostics"),
|
|
42
44
|
|
|
43
45
|
isStarted: async function(opts) {
|
|
44
46
|
return runtime.isStarted();
|
package/lib/api/settings.js
CHANGED
|
@@ -142,6 +142,13 @@ var api = module.exports = {
|
|
|
142
142
|
}
|
|
143
143
|
|
|
144
144
|
safeSettings.flowEncryptionType = runtime.nodes.getCredentialKeyType();
|
|
145
|
+
|
|
146
|
+
safeSettings.diagnostics = {
|
|
147
|
+
//unless diagnostics.ui and diagnostics.enabled are explicitly false, they will default to true.
|
|
148
|
+
enabled: (runtime.settings.diagnostics && runtime.settings.diagnostics.enabled === false) ? false : true,
|
|
149
|
+
ui: (runtime.settings.diagnostics && runtime.settings.diagnostics.ui === false) ? false : true
|
|
150
|
+
}
|
|
151
|
+
|
|
145
152
|
runtime.settings.exportNodeSettings(safeSettings);
|
|
146
153
|
runtime.plugins.exportPluginSettings(safeSettings);
|
|
147
154
|
}
|
package/lib/flows/Flow.js
CHANGED
|
@@ -582,7 +582,7 @@ class Flow {
|
|
|
582
582
|
reportingNode = node;
|
|
583
583
|
}
|
|
584
584
|
if (!muteStatusEvent) {
|
|
585
|
-
if (statusMessage.hasOwnProperty("text") && typeof
|
|
585
|
+
if (statusMessage.hasOwnProperty("text") && typeof statusMessage.text !== "string") {
|
|
586
586
|
try {
|
|
587
587
|
statusMessage.text = statusMessage.text.toString();
|
|
588
588
|
}
|
package/lib/index.js
CHANGED
|
@@ -207,8 +207,12 @@ function start() {
|
|
|
207
207
|
if (settings.readOnly){
|
|
208
208
|
log.info(log._("settings.readonly-mode"))
|
|
209
209
|
}
|
|
210
|
-
if (settings.httpStatic) {
|
|
211
|
-
|
|
210
|
+
if (settings.httpStatic && settings.httpStatic.length) {
|
|
211
|
+
for (let si = 0; si < settings.httpStatic.length; si++) {
|
|
212
|
+
let p = path.resolve(settings.httpStatic[si].path);
|
|
213
|
+
let r = settings.httpStatic[si].root || "/";
|
|
214
|
+
log.info(log._("runtime.paths.httpStatic",{path:`${p} > ${r}`}));
|
|
215
|
+
}
|
|
212
216
|
}
|
|
213
217
|
return redNodes.loadContextsPlugin().then(function () {
|
|
214
218
|
redNodes.loadFlows().then(redNodes.startFlows).catch(function(err) {});
|
|
@@ -395,7 +399,12 @@ module.exports = {
|
|
|
395
399
|
* @memberof @node-red/runtime
|
|
396
400
|
*/
|
|
397
401
|
version: externalAPI.version,
|
|
398
|
-
|
|
402
|
+
|
|
403
|
+
/**
|
|
404
|
+
* @memberof @node-red/diagnostics
|
|
405
|
+
*/
|
|
406
|
+
diagnostics:externalAPI.diagnostics,
|
|
407
|
+
|
|
399
408
|
storage: storage,
|
|
400
409
|
events: events,
|
|
401
410
|
hooks: hooks,
|
package/lib/nodes/credentials.js
CHANGED
|
@@ -239,7 +239,15 @@ var api = module.exports = {
|
|
|
239
239
|
throw error;
|
|
240
240
|
}
|
|
241
241
|
} else {
|
|
242
|
-
|
|
242
|
+
if (encryptionEnabled) {
|
|
243
|
+
// Our config expects the credentials to be encrypted but the encrypted object is not found
|
|
244
|
+
log.warn(log._("nodes.credentials.encryptedNotFound"))
|
|
245
|
+
credentialCache = credentials;
|
|
246
|
+
} else {
|
|
247
|
+
// credentialSecret is set to False
|
|
248
|
+
log.warn(log._("nodes.credentials.unencrypted"))
|
|
249
|
+
credentialCache = credentials;
|
|
250
|
+
}
|
|
243
251
|
}
|
|
244
252
|
if (clearInvalidFlag) {
|
|
245
253
|
// TODO: this delves too deep into Project structure
|
|
@@ -8,7 +8,6 @@
|
|
|
8
8
|
"httpStatic": "HTTP Static : __path__"
|
|
9
9
|
}
|
|
10
10
|
},
|
|
11
|
-
|
|
12
11
|
"server": {
|
|
13
12
|
"loading": "Loading palette nodes",
|
|
14
13
|
"palette-editor": {
|
|
@@ -61,7 +60,6 @@
|
|
|
61
60
|
"function-required": "httpsRefreshInterval requires https property to be a function"
|
|
62
61
|
}
|
|
63
62
|
},
|
|
64
|
-
|
|
65
63
|
"api": {
|
|
66
64
|
"flows": {
|
|
67
65
|
"error-save": "Error saving flows: __message__",
|
|
@@ -79,18 +77,16 @@
|
|
|
79
77
|
"error-enable": "Failed to enable node:"
|
|
80
78
|
}
|
|
81
79
|
},
|
|
82
|
-
|
|
83
80
|
"comms": {
|
|
84
81
|
"error": "Communication channel error: __message__",
|
|
85
82
|
"error-server": "Communication server error: __message__",
|
|
86
83
|
"error-send": "Communication send error: __message__"
|
|
87
84
|
},
|
|
88
|
-
|
|
89
85
|
"settings": {
|
|
90
86
|
"user-not-available": "Cannot save user settings: __message__",
|
|
91
87
|
"not-available": "Settings not available",
|
|
92
88
|
"property-read-only": "Property '__prop__' is read-only",
|
|
93
|
-
"readonly-mode"
|
|
89
|
+
"readonly-mode": "Runtime in read-only mode. Changes will not be saved."
|
|
94
90
|
},
|
|
95
91
|
"library": {
|
|
96
92
|
"unknownLibrary": "Unknown library: __library__",
|
|
@@ -101,10 +97,12 @@
|
|
|
101
97
|
},
|
|
102
98
|
"nodes": {
|
|
103
99
|
"credentials": {
|
|
104
|
-
"error":"Error loading credentials: __message__",
|
|
105
|
-
"error-saving":"Error saving credentials: __message__",
|
|
100
|
+
"error": "Error loading credentials: __message__",
|
|
101
|
+
"error-saving": "Error saving credentials: __message__",
|
|
106
102
|
"not-registered": "Credential type '__type__' is not registered",
|
|
107
|
-
"system-key-warning": "\n\n---------------------------------------------------------------------\nYour flow credentials file is encrypted using a system-generated key.\n\nIf the system-generated key is lost for any reason, your credentials\nfile will not be recoverable, you will have to delete it and re-enter\nyour credentials.\n\nYou should set your own key using the 'credentialSecret' option in\nyour settings file. Node-RED will then re-encrypt your credentials\nfile using your chosen key the next time you deploy a change.\n---------------------------------------------------------------------\n"
|
|
103
|
+
"system-key-warning": "\n\n---------------------------------------------------------------------\nYour flow credentials file is encrypted using a system-generated key.\n\nIf the system-generated key is lost for any reason, your credentials\nfile will not be recoverable, you will have to delete it and re-enter\nyour credentials.\n\nYou should set your own key using the 'credentialSecret' option in\nyour settings file. Node-RED will then re-encrypt your credentials\nfile using your chosen key the next time you deploy a change.\n---------------------------------------------------------------------\n",
|
|
104
|
+
"unencrypted": "Using unencrypted credentials",
|
|
105
|
+
"encryptedNotFound": "Encrypted credentials not found"
|
|
108
106
|
},
|
|
109
107
|
"flows": {
|
|
110
108
|
"safe-mode": "Flows stopped in safe mode. Deploy to start.",
|
|
@@ -148,7 +146,6 @@
|
|
|
148
146
|
}
|
|
149
147
|
}
|
|
150
148
|
},
|
|
151
|
-
|
|
152
149
|
"storage": {
|
|
153
150
|
"index": {
|
|
154
151
|
"forbidden-flow-name": "forbidden flow name"
|
|
@@ -178,7 +175,6 @@
|
|
|
178
175
|
}
|
|
179
176
|
}
|
|
180
177
|
},
|
|
181
|
-
|
|
182
178
|
"context": {
|
|
183
179
|
"log-store-init": "Context store : '__name__' [__info__]",
|
|
184
180
|
"error-loading-module": "Error loading context store: __message__",
|
|
@@ -193,5 +189,4 @@
|
|
|
193
189
|
"error-write": "Error writing context: __message__"
|
|
194
190
|
}
|
|
195
191
|
}
|
|
196
|
-
|
|
197
192
|
}
|
package/locales/ja/runtime.json
CHANGED
|
@@ -100,7 +100,9 @@
|
|
|
100
100
|
"error": "クレデンシャルの読み込みエラー: __message__",
|
|
101
101
|
"error-saving": "クレデンシャルの保存エラー: __message__",
|
|
102
102
|
"not-registered": "クレデンシャル '__type__' は登録されていません",
|
|
103
|
-
"system-key-warning": "\n\n---------------------------------------------------------------------\nフローのクレデンシャルファイルはシステム生成キーで暗号化されています。\n\nシステム生成キーを何らかの理由で失った場合、クレデンシャルファイルを\n復元することはできません。その場合、ファイルを削除してクレデンシャルを\n再入力しなければなりません。\n\n設定ファイル内で 'credentialSecret' オプションを使って独自キーを設定\nします。変更を次にデプロイする際、Node-REDは選択したキーを用いてクレ\nデンシャルを再暗号化します。 \n\n---------------------------------------------------------------------\n"
|
|
103
|
+
"system-key-warning": "\n\n---------------------------------------------------------------------\nフローのクレデンシャルファイルはシステム生成キーで暗号化されています。\n\nシステム生成キーを何らかの理由で失った場合、クレデンシャルファイルを\n復元することはできません。その場合、ファイルを削除してクレデンシャルを\n再入力しなければなりません。\n\n設定ファイル内で 'credentialSecret' オプションを使って独自キーを設定\nします。変更を次にデプロイする際、Node-REDは選択したキーを用いてクレ\nデンシャルを再暗号化します。 \n\n---------------------------------------------------------------------\n",
|
|
104
|
+
"unencrypted": "暗号化されていないクレデンシャルを使用",
|
|
105
|
+
"encryptedNotFound": "暗号化されたクレデンシャルが存在しません"
|
|
104
106
|
},
|
|
105
107
|
"flows": {
|
|
106
108
|
"safe-mode": "セーフモードでフローを停止しました。開始するためにはデプロイしてください",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@node-red/runtime",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "3.0.0-beta.3",
|
|
4
4
|
"license": "Apache-2.0",
|
|
5
5
|
"main": "./lib/index.js",
|
|
6
6
|
"repository": {
|
|
@@ -16,12 +16,12 @@
|
|
|
16
16
|
}
|
|
17
17
|
],
|
|
18
18
|
"dependencies": {
|
|
19
|
-
"@node-red/registry": "
|
|
20
|
-
"@node-red/util": "
|
|
19
|
+
"@node-red/registry": "3.0.0-beta.3",
|
|
20
|
+
"@node-red/util": "3.0.0-beta.3",
|
|
21
21
|
"async-mutex": "0.3.2",
|
|
22
22
|
"clone": "2.1.2",
|
|
23
|
-
"express": "4.
|
|
24
|
-
"fs-extra": "10.
|
|
23
|
+
"express": "4.18.1",
|
|
24
|
+
"fs-extra": "10.1.0",
|
|
25
25
|
"json-stringify-safe": "5.0.1"
|
|
26
26
|
}
|
|
27
27
|
}
|