From f196493402574b0a6d638d14aa2b367a80202264 Mon Sep 17 00:00:00 2001 From: Nick O'Leary Date: Fri, 23 Jun 2023 09:35:00 +0100 Subject: [PATCH] Evaluate global-config env on startup --- .../@node-red/runtime/lib/flows/Flow.js | 21 ++++++++--- .../@node-red/runtime/lib/flows/index.js | 20 ++--------- .../@node-red/runtime/lib/flows/util.js | 36 ------------------- .../@node-red/runtime/lib/nodes/index.js | 1 - .../@node-red/runtime/lib/flows/Flow_spec.js | 25 +++++++++++++ 5 files changed, 45 insertions(+), 58 deletions(-) diff --git a/packages/node_modules/@node-red/runtime/lib/flows/Flow.js b/packages/node_modules/@node-red/runtime/lib/flows/Flow.js index 2e03f5165..e7ca490d2 100644 --- a/packages/node_modules/@node-red/runtime/lib/flows/Flow.js +++ b/packages/node_modules/@node-red/runtime/lib/flows/Flow.js @@ -172,11 +172,24 @@ class Flow { this.statusNodes = []; this.completeNodeMap = {}; - if (this.env) { - this._env = await flowUtil.evaluateEnvProperties(this, this.env, credentials.get(this.id)) - // console.log('env', this.env) - // console.log('_env', this._env) + + if (this.isGlobalFlow) { + // This is the global flow. It needs to go find the `global-config` + // node and extract any env properties from it + const configNodes = Object.keys(this.flow.configs); + for (let i = 0; i < configNodes.length; i++) { + const node = this.flow.configs[configNodes[i]] + if (node.type === 'global-config' && node.env) { + const nodeEnv = await flowUtil.evaluateEnvProperties(this, node.env, credentials.get(node.id)) + this._env = { ...this._env, ...nodeEnv } + } + } } + + if (this.env) { + this._env = { ...this._env, ...await flowUtil.evaluateEnvProperties(this, this.env, credentials.get(this.id)) } + } + for (let i = 0; i < this.groupOrder.length; i++) { // Start the groups in the right order so they // can setup their env vars knowning their parent diff --git a/packages/node_modules/@node-red/runtime/lib/flows/index.js b/packages/node_modules/@node-red/runtime/lib/flows/index.js index c121e469c..16bd8a867 100644 --- a/packages/node_modules/@node-red/runtime/lib/flows/index.js +++ b/packages/node_modules/@node-red/runtime/lib/flows/index.js @@ -359,7 +359,7 @@ async function start(type,diff,muteLog,isDeploy) { if (activeFlowConfig.flows.hasOwnProperty(id)) { if (!activeFlowConfig.flows[id].disabled && !activeFlows[id]) { // This flow is not disabled, nor is it currently active, so create it - activeFlows[id] = Flow.create(flowAPI,activeFlowConfig,activeFlowConfig.flows[id]); + activeFlows[id] = Flow.create(activeFlows['global'],activeFlowConfig,activeFlowConfig.flows[id]); log.debug("red/nodes/flows.start : starting flow : "+id); } else { log.debug("red/nodes/flows.start : not starting disabled flow : "+id); @@ -379,7 +379,7 @@ async function start(type,diff,muteLog,isDeploy) { activeFlows[id].update(activeFlowConfig,activeFlowConfig.flows[id]); } else { // This flow didn't previously exist, so create it - activeFlows[id] = Flow.create(flowAPI,activeFlowConfig,activeFlowConfig.flows[id]); + activeFlows[id] = Flow.create(activeFlows['global'],activeFlowConfig,activeFlowConfig.flows[id]); log.debug("red/nodes/flows.start : starting flow : "+id); } } else { @@ -784,17 +784,6 @@ const flowAPI = { log: m => log.log(m) } - -function getGlobalConfig() { - let gconf = null; - eachNode((n) => { - if (n.type === "global-config") { - gconf = n; - } - }); - return gconf; -} - module.exports = { init: init, @@ -807,10 +796,7 @@ module.exports = { get:getNode, eachNode: eachNode, - - - getGlobalConfig: getGlobalConfig, - + /** * Gets the current flow configuration */ diff --git a/packages/node_modules/@node-red/runtime/lib/flows/util.js b/packages/node_modules/@node-red/runtime/lib/flows/util.js index 85c1381b3..ed9a3a1b9 100644 --- a/packages/node_modules/@node-red/runtime/lib/flows/util.js +++ b/packages/node_modules/@node-red/runtime/lib/flows/util.js @@ -318,37 +318,6 @@ function parseConfig(config) { return flow; } -function getGlobalEnv(name) { - const nodes = _runtime.nodes; - if (!nodes) { - return null; - } - const gconf = nodes.getGlobalConfig(); - const env = gconf ? gconf.env : null; - - if (env) { - const cred = (gconf ? credentials.get(gconf.id) : null) || { - map: {} - }; - const map = cred.map; - - for (let i = 0; i < env.length; i++) { - const item = env[i]; - if (item.name === name) { - if (item.type === "cred") { - return { - name: name, - value: map[name], - type: "cred" - }; - } - return item; - } - } - } - return null; -} - module.exports = { init: function(runtime) { _runtime = runtime; @@ -359,11 +328,6 @@ module.exports = { }, getEnvVar: function(k) { if (!envVarExcludes[k]) { - const item = getGlobalEnv(k); - if (item) { - const val = redUtil.evaluateNodeProperty(item.value, item.type, null, null, null); - return val; - } return process.env[k]; } return undefined; diff --git a/packages/node_modules/@node-red/runtime/lib/nodes/index.js b/packages/node_modules/@node-red/runtime/lib/nodes/index.js index fd01ebdb0..5b859a5f8 100644 --- a/packages/node_modules/@node-red/runtime/lib/nodes/index.js +++ b/packages/node_modules/@node-red/runtime/lib/nodes/index.js @@ -205,7 +205,6 @@ module.exports = { getNode: flows.get, eachNode: flows.eachNode, getContext: context.get, - getGlobalConfig: flows.getGlobalConfig, clearContext: context.clear, diff --git a/test/unit/@node-red/runtime/lib/flows/Flow_spec.js b/test/unit/@node-red/runtime/lib/flows/Flow_spec.js index 9f115c058..167691074 100644 --- a/test/unit/@node-red/runtime/lib/flows/Flow_spec.js +++ b/test/unit/@node-red/runtime/lib/flows/Flow_spec.js @@ -1369,6 +1369,31 @@ describe('Flow', function() { await flow.stop() }); + it("global flow can access global-config defined environment variables", async function () { + after(function() { + delete process.env.V0; + }) + const config = flowUtils.parseConfig([ + {id:"gc", type:"global-config", env:[ + {"name": "GC0", value: "3+4", type: "jsonata"} + ]}, + {id:"t1",type:"tab" }, + {id:"1",x:10,y:10,z:"t1",type:"test",foo:"${GC0}",wires:[]}, + ]); + // Two-arg call - makes this the global flow that handles global-config nodes + const globalFlow = Flow.create({getSetting:v=>process.env[v]},config); + await globalFlow.start(); + + // Pass the globalFlow in as the parent flow to allow global-config lookup + const flow = Flow.create(globalFlow,config,config.flows["t1"]); + await flow.start(); + + var activeNodes = flow.getActiveNodes(); + activeNodes["1"].foo.should.equal(7); + + await flow.stop() + await globalFlow.stop() + }); }); });