diff --git a/lib/addNewMask.js b/lib/addNewMask.js index 7d77ead..3232cbb 100644 --- a/lib/addNewMask.js +++ b/lib/addNewMask.js @@ -1,11 +1,11 @@ /* eslint-disable promise/catch-or-return */ // ↓ Should be imported first -const { terminate } = require('@codefresh-io/cf-telemetry/init'); +require('@codefresh-io/cf-telemetry/init'); // ↓ Keep one blank line below to prevent automatic import reordering const { Logger } = require('@codefresh-io/cf-telemetry/logs'); -const { getServerAddress, registerExitHandlers } = require('./helpers'); +const { getServerAddress, registerExitHandlers, shutdownGracefully } = require('./helpers'); const logger = new Logger('codefresh:containerLogger:addNewMask'); @@ -45,14 +45,14 @@ async function updateMasks(secret) { if (response.statusCode === 201) { logger.log(`successfully updated masks with secret: ${secret.key}`); exitWithError = false; - terminate().finally(() => process.exit(exitCodes.success)); + await shutdownGracefully(exitCodes.success); } else { logger.error(`could not create mask for secret: ${secret.key}. Server responded with: ${response.statusCode}\n\n${response.body}`); - terminate().finally(() => process.exit(exitCodes.error)); + await shutdownGracefully(exitCodes.error); } } catch (error) { logger.error(`could not create mask for secret: ${secret.key}. Error: ${error}`); - terminate().finally(() => process.exit(exitCodes.error)); + await shutdownGracefully(exitCodes.error); } } @@ -62,11 +62,12 @@ if (require.main === module) { // first argument is the secret key second argument is the secret value if (process.argv.length < 4) { logger.log('not enough arguments, need secret key and secret value'); - terminate().finally(() => process.exit(exitCodes.missingArguments)); + shutdownGracefully(exitCodes.missingArguments); + } else { + const key = process.argv[2]; + const value = process.argv[3]; + updateMasks({ key, value }); } - const key = process.argv[2]; - const value = process.argv[3]; - updateMasks({ key, value }); } else { module.exports = { updateMasks, exitHandler }; } diff --git a/lib/helpers.js b/lib/helpers.js index 77ffb3c..756279c 100644 --- a/lib/helpers.js +++ b/lib/helpers.js @@ -60,21 +60,33 @@ const getServerAddress = async () => { } }; +const shutdownGracefully = async (code) => { + try { + await terminate(); + } catch (error) { + // supress any error during terminating telemetry + logger.error(`Error occurred while terminating telemetry.`, error); + } + + process.exit(code); +}; + /** * As `@codefresh-io/cf-telemetry/init` changes the original node.js behavior of how SIGTERM and SIGINT * signals are handled, we revert this change back to the original node.js behavior. */ const registerExitHandlers = () => { - process.on('SIGTERM', () => { - terminate().finally(() => process.exit(143)); // default exit code for SIGTERM + process.on('SIGTERM', async () => { + await shutdownGracefully(143); // default exit code for SIGTERM }); - process.on('SIGINT', () => { - terminate().finally(() => process.exit(130)); // default exit code for SIGINT + process.on('SIGINT', async () => { + await shutdownGracefully(130); // default exit code for SIGINT }); }; module.exports = { + shutdownGracefully, watchForBuildFinishedSignal, saveServerAddress, getServerAddress, diff --git a/lib/index.js b/lib/index.js index 2850183..cd52b1e 100644 --- a/lib/index.js +++ b/lib/index.js @@ -32,8 +32,9 @@ const logger = new Logger({ showProgress: process.env.SHOW_PROGRESS === 'true', }); -logger.validate(); -logger.start(); +// eslint-disable-next-line promise/catch-or-return +logger.validate() + .then(() => logger.start()); process.on('beforeExit', (code) => { logs.log(`beforeExit: ${code}`); diff --git a/lib/isReady.js b/lib/isReady.js index d55906f..d5295e7 100644 --- a/lib/isReady.js +++ b/lib/isReady.js @@ -1,14 +1,14 @@ /* eslint-disable promise/catch-or-return */ // ↓ Should be imported first -const { terminate } = require('@codefresh-io/cf-telemetry/init'); +require('@codefresh-io/cf-telemetry/init'); // ↓ Keep one blank line below to prevent automatic import reordering const { readFileSync } = require('fs'); const _ = require('lodash'); const { Logger } = require('@codefresh-io/cf-telemetry/logs'); const { ContainerHandlingStatus } = require('./enums'); -const { registerExitHandlers } = require('./helpers'); +const { registerExitHandlers, shutdownGracefully } = require('./helpers'); registerExitHandlers(); @@ -33,15 +33,21 @@ function isContainerLoggerReady(state) { return isReady; } -(() => { +const isReady = async () => { const containerId = process.argv[2]; const state = JSON.parse(readFileSync('./lib/state.json').toString('utf-8')); - let isReady = false; + let ready = false; if (containerId) { - isReady = isContainerReady(state, containerId); + ready = isContainerReady(state, containerId); } else { - isReady = isContainerLoggerReady(state); + ready = isContainerLoggerReady(state); } - terminate().finally(() => process.exit(isReady ? 0 : 1)); -})(); + await shutdownGracefully(ready ? 0 : 1); +}; + +if (require.main === module) { + isReady(); +} else { + module.exports = { isReady }; +} diff --git a/lib/logger.js b/lib/logger.js index 0b45144..159d609 100644 --- a/lib/logger.js +++ b/lib/logger.js @@ -1,7 +1,7 @@ /* eslint-disable promise/catch-or-return */ // ↓ Should be imported first -const { terminate } = require('@codefresh-io/cf-telemetry/init'); +require('@codefresh-io/cf-telemetry/init'); // ↓ Keep one blank line below to prevent automatic import reordering const fs = require('fs'); @@ -19,6 +19,7 @@ const ContainerLogger = require('./ContainerLogger'); // eslint-disable-next-line import/no-unresolved,import/extensions const { HttpServer } = require('./http-server'); +const { shutdownGracefully } = require('./helpers'); const logger = new Logs('codefresh:containerLogger'); @@ -70,12 +71,12 @@ class Logger { * validates the passed params of the constructor * @returns {*} */ - validate() { + async validate() { if (!this.taskLoggerConfig) { - return this._error(new CFError('taskLogger configuration is missing')); + return await this._error(new CFError('taskLogger configuration is missing')); } if (!this.loggerId) { - return this._error(new CFError('logger id is missing')); + return await this._error(new CFError('logger id is missing')); } return undefined; } @@ -126,12 +127,11 @@ class Logger { this._listenForExistingContainers(); } }) - .catch((err) => { - this._error(new CFError({ + .catch(async (err) => { + await this._error(new CFError({ cause: err, message: `Failed to create taskLogger` })); - }); await this._listenForEngineRequests(); @@ -155,9 +155,9 @@ class Logger { * will print the error and exit the process * @param err */ - _error(err) { + async _error(err) { logger.error(err.toString()); - terminate().finally(() => process.exit(1)); + await shutdownGracefully(1); } /** diff --git a/service.yaml b/service.yaml index 653dc2e..c546f1e 100644 --- a/service.yaml +++ b/service.yaml @@ -1 +1 @@ -version: 1.13.0 +version: 1.13.1 diff --git a/test/addNewMask.unit.spec.js b/test/addNewMask.unit.spec.js index 007797b..5729842 100644 --- a/test/addNewMask.unit.spec.js +++ b/test/addNewMask.unit.spec.js @@ -1,6 +1,7 @@ const chai = require('chai'); const sinon = require('sinon'); const sinonChai = require('sinon-chai'); +const {shutdownGracefully} = require("../lib/helpers"); const proxyquire = require('proxyquire').noCallThru(); const expect = chai.expect; @@ -57,12 +58,10 @@ describe('addNewMask', () => { stubGot.post.resolves({ statusCode: 201 }); const { updateMasks, exitHandler } = proxyquire('../lib/addNewMask', { - '@codefresh-io/cf-telemetry/init': { - terminate: () => ({ - finally: callback => callback(), - }) + './helpers': { + getServerAddress: stubGetServerAddress, + shutdownGracefully, }, - './helpers': { getServerAddress: stubGetServerAddress }, }); process.listeners('exit').forEach((listener) => { if (listener === exitHandler) { @@ -82,16 +81,12 @@ describe('addNewMask', () => { it('should fail if the server address is not available', async () => { stubGetServerAddress.rejects('could not get server address'); const { updateMasks, exitHandler } = proxyquire('../lib/addNewMask', { - '@codefresh-io/cf-telemetry/init': { - terminate: () => ({ - finally: callback => callback(), - }) - }, '@codefresh-io/cf-telemetry/logs': { Logger: function() { return stubLogger }, }, './helpers': { getServerAddress: stubGetServerAddress, + shutdownGracefully, }, }); process.listeners('exit').forEach((listener) => { @@ -107,16 +102,12 @@ describe('addNewMask', () => { it('should fail if the server address is not valid URL', async () => { stubGetServerAddress.resolves('foo'); const { updateMasks, exitHandler } = proxyquire('../lib/addNewMask', { - '@codefresh-io/cf-telemetry/init': { - terminate: () => ({ - finally: callback => callback(), - }) - }, '@codefresh-io/cf-telemetry/logs': { Logger: function() { return stubLogger }, }, './helpers': { getServerAddress: stubGetServerAddress, + shutdownGracefully, }, }); process.listeners('exit').forEach((listener) => { @@ -137,15 +128,13 @@ describe('addNewMask', () => { body: 'Internal Server Error', }); const { updateMasks, exitHandler } = proxyquire('../lib/addNewMask', { - '@codefresh-io/cf-telemetry/init': { - terminate: () => ({ - finally: callback => callback(), - }) - }, '@codefresh-io/cf-telemetry/logs': { Logger: function() { return stubLogger }, }, - './helpers': { getServerAddress: stubGetServerAddress }, + './helpers': { + getServerAddress: stubGetServerAddress, + shutdownGracefully, + }, }); process.listeners('exit').forEach((listener) => { if (listener === exitHandler) { @@ -202,7 +191,10 @@ describe('addNewMask', () => { stubGetServerAddress.resolves(serverAddress); stubGot.post.resolves({ statusCode: 201 }); const { updateMasks, exitHandler } = proxyquire('../lib/addNewMask', { - './helpers': { getServerAddress: stubGetServerAddress }, + './helpers': { + getServerAddress: stubGetServerAddress, + shutdownGracefully, + }, }); process.listeners('exit').forEach((listener) => { if (listener === exitHandler) { diff --git a/test/isReady.unit.spec.js b/test/isReady.unit.spec.js index ea91979..6984335 100644 --- a/test/isReady.unit.spec.js +++ b/test/isReady.unit.spec.js @@ -18,96 +18,85 @@ describe('isReady script', () => { process.argv = orgArgs; }); describe('Container Logger Checks', () => { - it('Should check exit with 0 code if container logger is ready', () => { + it('Should check exit with 0 code if container logger is ready', async () => { const state = JSON.stringify({ status: 'ready', containers: {} }) process.argv = []; - proxyquire('../lib/isReady.js', { - '@codefresh-io/cf-telemetry/init': { - terminate: () => ({ - finally: callback => callback(), - }) - }, + const { isReady } = proxyquire('../lib/isReady.js', { 'fs': { readFileSync: () => Buffer.from(state), }, }); + await isReady(); expect(process.exit).to.have.been.calledOnceWith(0); }); - it('Should check exit with 1 code if container logger is not ready', () => { - const state = JSON.stringify({ status: 'notReady', containers: {} }) + it('Should check exit with 1 code if container logger is not ready', async () => { + const state = JSON.stringify({status: 'notReady', containers: {}}) process.argv = []; - proxyquire('../lib/isReady.js', { - '@codefresh-io/cf-telemetry/init': { - terminate: () => ({ - finally: callback => callback(), - }) - }, + const {isReady} = proxyquire('../lib/isReady.js', { 'fs': { readFileSync: () => Buffer.from(state), }, }); + await isReady(); expect(process.exit).to.have.been.calledOnceWith(1); }); }); describe('Container Checks', () => { - it('Should check exit with 0 code if container is ready', () => { - const state = JSON.stringify({ status: 'ready', containers: { 'container-id': { status: ContainerHandlingStatus.LISTENING } } }) + it('Should check exit with 0 code if container is ready', async () => { + const state = JSON.stringify({ + status: 'ready', + containers: {'container-id': {status: ContainerHandlingStatus.LISTENING}} + }) process.argv = ['foo', 'bar', 'container-id']; - proxyquire('../lib/isReady.js', { - '@codefresh-io/cf-telemetry/init': { - terminate: () => ({ - finally: callback => callback(), - }) - }, + const {isReady} = proxyquire('../lib/isReady.js', { 'fs': { readFileSync: () => Buffer.from(state), }, }); + await isReady(); expect(process.exit).to.have.been.calledOnceWith(0); }); - it('Should check exit with 0 code if container is waiting for start status', () => { - const state = JSON.stringify({ status: 'ready', containers: { 'container-id': { status: ContainerHandlingStatus.WAITING_FOR_START } } }) + it('Should check exit with 0 code if container is waiting for start status', async () => { + const state = JSON.stringify({ + status: 'ready', + containers: {'container-id': {status: ContainerHandlingStatus.WAITING_FOR_START}} + }) process.argv = ['foo', 'bar', 'container-id']; - proxyquire('../lib/isReady.js', { - '@codefresh-io/cf-telemetry/init': { - terminate: () => ({ - finally: callback => callback(), - }) - }, + const {isReady} = proxyquire('../lib/isReady.js', { 'fs': { readFileSync: () => Buffer.from(state), }, }); + await isReady(); expect(process.exit).to.have.been.calledOnceWith(0); }); - it('Should check exit with 0 code if container is finished status', () => { - const state = JSON.stringify({ status: 'ready', containers: { 'container-id': { status: ContainerHandlingStatus.FINISHED } } }) + it('Should check exit with 0 code if container is finished status', async () => { + const state = JSON.stringify({ + status: 'ready', + containers: {'container-id': {status: ContainerHandlingStatus.FINISHED}} + }) process.argv = ['foo', 'bar', 'container-id']; - proxyquire('../lib/isReady.js', { - '@codefresh-io/cf-telemetry/init': { - terminate: () => ({ - finally: callback => callback(), - }) - }, + const {isReady} = proxyquire('../lib/isReady.js', { 'fs': { readFileSync: () => Buffer.from(state), }, }); + await isReady(); expect(process.exit).to.have.been.calledOnceWith(0); }); - it('Should check exit with 1 code if container is not ready', () => { - const state = JSON.stringify({ status: 'ready', containers: { 'container-id': { status: ContainerHandlingStatus.INITIALIZING } } }) + it('Should check exit with 1 code if container is not ready', async () => { + const state = JSON.stringify({ + status: 'ready', + containers: {'container-id': {status: ContainerHandlingStatus.INITIALIZING}} + }) process.argv = ['foo', 'bar', 'container-id']; - proxyquire('../lib/isReady.js', { - '@codefresh-io/cf-telemetry/init': { - terminate: () => ({ - finally: callback => callback(), - }) - }, + const {isReady} = proxyquire('../lib/isReady.js', { + 'fs': { readFileSync: () => Buffer.from(state), }, }); + await isReady(); expect(process.exit).to.have.been.calledOnceWith(1); }); }); diff --git a/test/logger.unit.spec.js b/test/logger.unit.spec.js index cdf3183..2564e52 100644 --- a/test/logger.unit.spec.js +++ b/test/logger.unit.spec.js @@ -7,6 +7,7 @@ const sinonChai = require('sinon-chai'); const { EventEmitter } = require('events'); const { ContainerStatus } = require('../lib/enums'); const { LoggerStrategy } = require('../lib/enums'); +const {shutdownGracefully} = require("../lib/helpers"); const expect = chai.expect; chai.use(sinonChai); @@ -277,7 +278,6 @@ describe('Logger tests', () => { }); describe('negative', () => { - it('should call process exit in case creation of task logger failed', (done) => { let exited = false; const processExitSpy = sinon.spy((exitCode) => { @@ -300,6 +300,7 @@ describe('Logger tests', () => { 'fastify': stubFastify, './helpers': { saveServerAddress: stubSaveServerAddress, + shutdownGracefully, }, }); @@ -502,6 +503,7 @@ describe('Logger tests', () => { 'fastify': stubFastify, './helpers': { saveServerAddress: stubSaveServerAddress, + shutdownGracefully, }, }); @@ -528,6 +530,7 @@ describe('Logger tests', () => { 'fastify': stubFastify, './helpers': { saveServerAddress: stubSaveServerAddress, + shutdownGracefully, }, }); @@ -554,6 +557,7 @@ describe('Logger tests', () => { 'fastify': stubFastify, './helpers': { saveServerAddress: stubSaveServerAddress, + shutdownGracefully, }, }); @@ -580,6 +584,7 @@ describe('Logger tests', () => { 'fastify': stubFastify, './helpers': { saveServerAddress: stubSaveServerAddress, + shutdownGracefully, }, });