From b21addc3f3919b59d08c20443f7df94d5aadc8ea Mon Sep 17 00:00:00 2001 From: Steve-Mcl Date: Mon, 16 Dec 2024 12:19:32 +0000 Subject: [PATCH 1/5] Add disableAutoSafeMode feature to Launcher class --- lib/launcher.js | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/lib/launcher.js b/lib/launcher.js index c6c465b..3447697 100644 --- a/lib/launcher.js +++ b/lib/launcher.js @@ -6,6 +6,7 @@ const LogBuffer = require('./logBuffer') const { getSettingsFile } = require('./runtimeSettings') const SampleBuffer = require('./resources/sampleBuffer') const resourceSample = require('./resources/sample') +const { hasProperty } = require('../../device-agent/lib/utils') /** The point at which we check to see if we are in a boot loop */ const MAX_RESTART_COUNT = 5 @@ -86,6 +87,8 @@ class Launcher { this.sampleBuffer = new SampleBuffer(this.options.sampleBufferMax || 2520) this.cpuAuditLogged = 0 this.memoryAuditLogged = 0 + + this.disableAutoSafeMode = false } /** @type {Number} */ @@ -101,7 +104,7 @@ class Launcher { const settingsURL = `${this.options.forgeURL}/api/v1/projects/${this.options.project}/settings` let newSettings try { - newSettings = await got(settingsURL, { + newSettings = await got.get(settingsURL, { headers: { authorization: `Bearer ${this.options.token}` } @@ -149,7 +152,12 @@ class Launcher { nodesDir.push(require.main.path) this.settings.nodesDir = nodesDir - + if (hasProperty(this.settings, 'disableAutoSafeMode') && typeof this.settings.disableAutoSafeMode === 'boolean') { + this.disableAutoSafeMode = this.settings.disableAutoSafeMode + } + if (this.disableAutoSafeMode === true) { + this.logBuffer.add({ level: 'system', msg: 'Auto Safe Mode is disabled.' }) + } const settingsFileContent = getSettingsFile(this.settings) const settingsPath = path.join(this.settings.rootDir, this.settings.userDir, 'settings.js') this.targetState = this.settings.state || States.RUNNING @@ -271,7 +279,7 @@ class Launcher { Object.assign(data, body) } } - return got.post(this.options.forgeURL + '/logging/' + this.options.project + '/audit', { + return got.default.get.post(this.options.forgeURL + '/logging/' + this.options.project + '/audit', { json: data, headers: { authorization: 'Bearer ' + this.options.token @@ -430,7 +438,7 @@ class Launcher { opts.throwHttpErrors = false } // Use a HEAD request to minimise data transfer - const res = await got.head(pollUrl, opts) + const res = await got.default.get.head(pollUrl, opts) statusCode = res.statusCode || 500 } catch (error) { if (this.state === States.STARTING) { @@ -464,8 +472,8 @@ class Launcher { this.logBuffer.add({ level: 'system', msg: `Node-RED unexpectedly stopped after: ${Math.round(duration / 1000)}s` }) - // if start count == MAX_RESTART_COUNT, then check for boot loop - if (this.startTimes.length === MAX_RESTART_COUNT) { + // if auto-safe-mode is not disabled && start count == MAX_RESTART_COUNT, then check for boot loop + if (this.disableAutoSafeMode !== true && this.startTimes.length === MAX_RESTART_COUNT) { // calculate the average runtime const avg = this.runDurations.reduce((a, b) => a + b, 0) / this.runDurations.length From ca2b68bc8f1c0d103d30b0a2cc38440274491e0c Mon Sep 17 00:00:00 2001 From: Steve-Mcl Date: Mon, 16 Dec 2024 12:22:24 +0000 Subject: [PATCH 2/5] Add unit tests for disableAutoSafeMode feature in Launcher class --- test/unit/lib/launcher_spec.js | 35 ++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/test/unit/lib/launcher_spec.js b/test/unit/lib/launcher_spec.js index 5d53455..0fdc2af 100644 --- a/test/unit/lib/launcher_spec.js +++ b/test/unit/lib/launcher_spec.js @@ -1,5 +1,7 @@ const should = require('should') // eslint-disable-line const sinon = require('sinon') +const got = require('got') +const fs = require('fs') const launcher = require('../../../lib/launcher.js') describe('Launcher', function () { @@ -7,6 +9,9 @@ describe('Launcher', function () { const l = new launcher.Launcher({}) should.exist(l) }) + this.afterEach(function () { + sinon.restore() + }) describe('health check', function () { it('has a default value', async function () { const l = new launcher.Launcher({}) @@ -34,4 +39,34 @@ describe('Launcher', function () { l.should.have.property('healthCheckInterval', 7499) }) }) + + describe('disable auto safe mode', function () { + it('has a default value', async function () { + const l = new launcher.Launcher({}) + l.should.have.property('disableAutoSafeMode', false) + }) + it('can be set by user', async function () { + const l = new launcher.Launcher({}) + sinon.stub(fs, 'writeFileSync').callsFake(() => {}) + sinon.stub(l, 'updatePackage').callsFake(() => {}) + sinon.stub(got, 'get').callsFake(() => { + return { + json () { + return { + forgeURL: 'http://localhost:1880', + rootDir: '/path/to/node-red', + userDir: '/path/to/.node-red', + settings: { + palette: {} + }, + disableAutoSafeMode: true + } + } + } + }) + + await l.loadSettings() + l.should.have.property('disableAutoSafeMode', true) + }) + }) }) From e1b320c08883a2885a7cbb41b0a6e7a6fa1f0c62 Mon Sep 17 00:00:00 2001 From: Steve-Mcl Date: Mon, 16 Dec 2024 12:23:23 +0000 Subject: [PATCH 3/5] fix tests not doing what they really should be doing --- test/unit/lib/launcher_spec.js | 41 +++++++++++++++++++++++++++------- 1 file changed, 33 insertions(+), 8 deletions(-) diff --git a/test/unit/lib/launcher_spec.js b/test/unit/lib/launcher_spec.js index 0fdc2af..a5d165d 100644 --- a/test/unit/lib/launcher_spec.js +++ b/test/unit/lib/launcher_spec.js @@ -19,19 +19,44 @@ describe('Launcher', function () { }) it('can be set by user', async function () { const l = new launcher.Launcher({}) - sinon.stub(l, 'loadSettings').callsFake(() => { - l.settings = { - healthCheckInterval: 1234 + l.should.have.property('healthCheckInterval', 7499) // initial/default value is 7499 + sinon.stub(fs, 'writeFileSync').callsFake(() => {}) + sinon.stub(l, 'updatePackage').callsFake(() => {}) + sinon.stub(got, 'get').callsFake(() => { + return { + json () { + return { + forgeURL: 'http://localhost:1880', + rootDir: '/path/to/node-red', + userDir: '/path/to/.node-red', + settings: { + palette: {} + }, + healthCheckInterval: 1234 + } + } } }) await l.loadSettings() - l.should.have.property('healthCheckInterval', 1234) + l.should.have.property('healthCheckInterval', 1234) // when loaded from API, it should now be updated }) it('cannot be less than 1 second', async function () { const l = new launcher.Launcher({}) - sinon.stub(l, 'loadSettings').callsFake(() => { - l.settings = { - healthCheckInterval: 999 + sinon.stub(fs, 'writeFileSync').callsFake(() => {}) + sinon.stub(l, 'updatePackage').callsFake(() => {}) + sinon.stub(got, 'get').callsFake(() => { + return { + json () { + return { + forgeURL: 'http://localhost:1880', + rootDir: '/path/to/node-red', + userDir: '/path/to/.node-red', + settings: { + palette: {} + }, + healthCheckInterval: 999 + } + } } }) await l.loadSettings() @@ -41,7 +66,7 @@ describe('Launcher', function () { }) describe('disable auto safe mode', function () { - it('has a default value', async function () { + it('is disabled by default', async function () { const l = new launcher.Launcher({}) l.should.have.property('disableAutoSafeMode', false) }) From 8c5c5f693dfb641cf3752f9e9e87375f579eb5fa Mon Sep 17 00:00:00 2001 From: Steve-Mcl Date: Mon, 16 Dec 2024 12:41:46 +0000 Subject: [PATCH 4/5] fix incorrect import --- lib/launcher.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/launcher.js b/lib/launcher.js index 3447697..dcc5e90 100644 --- a/lib/launcher.js +++ b/lib/launcher.js @@ -6,7 +6,7 @@ const LogBuffer = require('./logBuffer') const { getSettingsFile } = require('./runtimeSettings') const SampleBuffer = require('./resources/sampleBuffer') const resourceSample = require('./resources/sample') -const { hasProperty } = require('../../device-agent/lib/utils') +const hasProperty = (object, property) => !!(object && Object.prototype.hasOwnProperty.call(object, property)) /** The point at which we check to see if we are in a boot loop */ const MAX_RESTART_COUNT = 5 From 36d460977032b213d99ef335a3aa3b0a09ddcbe1 Mon Sep 17 00:00:00 2001 From: Steve-Mcl Date: Mon, 16 Dec 2024 14:26:49 +0000 Subject: [PATCH 5/5] fix typo --- lib/launcher.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/launcher.js b/lib/launcher.js index dcc5e90..2c0e5ec 100644 --- a/lib/launcher.js +++ b/lib/launcher.js @@ -279,7 +279,7 @@ class Launcher { Object.assign(data, body) } } - return got.default.get.post(this.options.forgeURL + '/logging/' + this.options.project + '/audit', { + return got.post(this.options.forgeURL + '/logging/' + this.options.project + '/audit', { json: data, headers: { authorization: 'Bearer ' + this.options.token @@ -438,7 +438,7 @@ class Launcher { opts.throwHttpErrors = false } // Use a HEAD request to minimise data transfer - const res = await got.default.get.head(pollUrl, opts) + const res = await got.head(pollUrl, opts) statusCode = res.statusCode || 500 } catch (error) { if (this.state === States.STARTING) {