From 7477a8d2e28412db4dfce4d8527f5a653775a595 Mon Sep 17 00:00:00 2001 From: martinboulais <31805063+martinboulais@users.noreply.github.com> Date: Mon, 4 Nov 2024 15:25:10 +0100 Subject: [PATCH 1/4] [O2B-1393] Use certificate when handling lost runs and envs --- lib/application.js | 66 +++++++++++-------- lib/config/services.js | 15 +++-- .../monalisa/MonAlisaClient.js | 43 ++---------- .../handleLostRunsAndEnvironments.js | 15 +++-- 4 files changed, 63 insertions(+), 76 deletions(-) diff --git a/lib/application.js b/lib/application.js index d3e1d5d5ff..03f30077d1 100644 --- a/lib/application.js +++ b/lib/application.js @@ -15,12 +15,11 @@ const { webUiServer } = require('./server'); const { gRPCServer } = require('./server/index.js'); const { GRPCConfig, ServicesConfig } = require('./config'); -const { monalisa: monalisaConfig, ccdb: ccdbConfig } = ServicesConfig; +const { gridUserCertificate, monalisa: monalisaConfig, ccdb: ccdbConfig } = ServicesConfig; const { handleLostRunsAndEnvironments } = require('./server/services/housekeeping/handleLostRunsAndEnvironments.js'); const { isInTestMode } = require('./utilities/env-utils.js'); const { ScheduledProcessesManager } = require('./server/services/ScheduledProcessesManager.js'); const { MonAlisaSynchronizer } = require('./server/externalServicesSynchronization/monalisa/MonAlisaSynchronizer'); -const { createMonAlisaClient } = require('./server/externalServicesSynchronization/monalisa/MonAlisaClient'); const { LogManager } = require('@aliceo2/web-ui'); const { Kafka, logLevel } = require('kafkajs'); const { KafkaConfig } = require('./config/index.js'); @@ -28,6 +27,9 @@ const { AliEcsSynchronizer } = require('./server/kafka/AliEcsSynchronizer.js'); const { environmentService } = require('./server/services/environment/EnvironmentService.js'); const { runService } = require('./server/services/run/RunService.js'); const { CcdbSynchronizer } = require('./server/externalServicesSynchronization/ccdb/CcdbSynchronizer.js'); +const { promises: fs } = require('fs'); +const { MonAlisaClient } = require('./server/externalServicesSynchronization/monalisa/MonAlisaClient.js'); +const https = require('https'); /** * Bookkeeping Application @@ -79,15 +81,34 @@ class BookkeepingApplication { await this.aliEcsSynchronizer.start(); } - if (monalisaConfig.enableSynchronization) { - const monAlisaSynchronizer = await this.createMonAlisaSynchronizer(); - this.scheduledProcessesManager.schedule( - () => monAlisaSynchronizer.synchronize(), - { - wait: 10 * 1000, - every: monalisaConfig.synchronizationPeriod, - }, - ); + if (monalisaConfig.enableSynchronization || ServicesConfig.enableHousekeeping) { + const pfxCertificateBytes = await fs.readFile(gridUserCertificate.path); + const certificatePassphrase = gridUserCertificate.passphrase; + + const httpAgent = pfxCertificateBytes && certificatePassphrase + ? new https.Agent({ pfx: pfxCertificateBytes, passphrase: certificatePassphrase }) + : undefined; + + if (monalisaConfig.enableSynchronization) { + const monAlisaSynchronizer = await this.createMonAlisaSynchronizer(httpAgent); + this.scheduledProcessesManager.schedule( + () => monAlisaSynchronizer.synchronize(), + { + wait: 10 * 1000, + every: monalisaConfig.synchronizationPeriod, + }, + ); + } + + if (ServicesConfig.enableHousekeeping) { + this.scheduledProcessesManager.schedule( + () => this.housekeeping(httpAgent), + { + wait: 30 * 1000, + every: 30 * 1000, + }, + ); + } } if (ccdbConfig.enableSynchronization) { @@ -107,16 +128,6 @@ class BookkeepingApplication { }, ); } - - if (ServicesConfig.enableHousekeeping) { - this.scheduledProcessesManager.schedule( - () => this.housekeeping(), - { - wait: 30 * 1000, - every: 30 * 1000, - }, - ); - } } catch (error) { this._logger.errorMessage(`Error while starting: ${error}`); return this.stop(); @@ -128,27 +139,28 @@ class BookkeepingApplication { /** * Instantiate MonAlisa synchronizer with global configuration * + * @param {Agent} agent the HTTP agent to be used by synchronizer * @return {Promise} resolves with MonAlisaSynchronizer instance */ - async createMonAlisaSynchronizer() { - return new MonAlisaSynchronizer(await createMonAlisaClient({ + async createMonAlisaSynchronizer(agent) { + return new MonAlisaSynchronizer(new MonAlisaClient({ dataPassesUrl: monalisaConfig.dataPassesUrl, dataPassDetailsUrl: monalisaConfig.dataPassDetailsUrl, simulationPassesUrl: monalisaConfig.simulationPassesUrl, yearLowerLimit: monalisaConfig.dataPassesYearLowerLimit, - userCertificatePath: monalisaConfig.userCertificate.path, - certificatePassphrase: monalisaConfig.userCertificate.passphrase, + agent, })); } /** * Housekeeping method, it wraps @see handleLostRunsAndEnvironments and logs its results * + * @param {Agent} httpAgent agent to be used by the HTTP client * @return {Promise} promise */ - async housekeeping() { + async housekeeping(httpAgent) { try { - const { transitionedEnvironments, endedRuns } = await handleLostRunsAndEnvironments(); + const { transitionedEnvironments, endedRuns } = await handleLostRunsAndEnvironments(httpAgent); const subMessages = []; if (transitionedEnvironments.length > 0) { subMessages.push(`environments (${transitionedEnvironments.join(', ')})`); diff --git a/lib/config/services.js b/lib/config/services.js index 571f37b574..1bdbe63e2d 100644 --- a/lib/config/services.js +++ b/lib/config/services.js @@ -12,8 +12,10 @@ */ const { - MONALISA_CERTIFICATE_PATH, - MONALISA_CERTIFICATE_PASSPHRASE, + GRID_USER_CERTIFICATE_PATH, + GRID_USER_CERTIFICATE_PASSPHRASE, + MONALISA_CERTIFICATE_PATH, // DEPRECATED + MONALISA_CERTIFICATE_PASSPHRASE, // DEPRECATED DATA_PASSES_YEAR_LOWER_LIMIT, MONALISA_DATA_PASSES_URL, MONALISA_DATA_PASS_DETAILS_URL, @@ -27,6 +29,10 @@ const { exports.services = { enableHousekeeping: process.env?.ENABLE_HOUSEKEEPING ?? false, + gridUserCertificate: { + path: GRID_USER_CERTIFICATE_PATH ?? MONALISA_CERTIFICATE_PATH, + passphrase: GRID_USER_CERTIFICATE_PASSPHRASE ?? MONALISA_CERTIFICATE_PASSPHRASE, + }, aliEcsGui: { url: process.env?.ALI_ECS_GUI_URL || null, token: process.env?.ALI_ECS_GUI_TOKEN || null, @@ -45,12 +51,7 @@ exports.services = { aliFlpIndex: { url: process.env?.ALI_FLP_INDEX_URL || null, }, - monalisa: { - userCertificate: { - path: MONALISA_CERTIFICATE_PATH, - passphrase: MONALISA_CERTIFICATE_PASSPHRASE, - }, dataPassesYearLowerLimit: Number(DATA_PASSES_YEAR_LOWER_LIMIT) || 2022, dataPassesUrl: MONALISA_DATA_PASSES_URL, diff --git a/lib/server/externalServicesSynchronization/monalisa/MonAlisaClient.js b/lib/server/externalServicesSynchronization/monalisa/MonAlisaClient.js index 77e8e93d90..54319a4b41 100644 --- a/lib/server/externalServicesSynchronization/monalisa/MonAlisaClient.js +++ b/lib/server/externalServicesSynchronization/monalisa/MonAlisaClient.js @@ -62,20 +62,17 @@ class MonAlisaClient { * @param {object} configuration configuration of MonAlisa client * @param {URL|string} [configuration.dataPassesUrl] url to fetch data passes * @param {URL|string} [configuration.dataPassDetailsUrl] url to fetch data pass version details - * @param {string|string[]|Buffer|Buffer[]|Object[]} [configuration.pfxCertificateBytes] PFX or PKCS12 encoded private key - * and certificate chain @see tls.createSecureContext([options]) - * @param {string} [configuration.certificatePassphrase] passphrase to the certificate + * @param {URL|string} [configuration.simulationPassesUrl] url to fetch simulation passes * @param {number} [configuration.yearLowerLimit] indicates how old data are accepted, * year of lhc period that given data pass belongs must be greater or equal - * @param {URL|string} [configuration.simulationPassesUrl] url to fetch simulation passes + * @param {Agent} agent HTTPs agent to use when sending requests */ constructor({ dataPassesUrl, dataPassDetailsUrl, - pfxCertificateBytes, - certificatePassphrase, - yearLowerLimit, simulationPassesUrl, + yearLowerLimit, + agent, } = {}) { this.dataPassesUrl = dataPassesUrl ? new URL(dataPassesUrl) : null; this.dataPassDetailsUrl = dataPassDetailsUrl ? new URL(dataPassDetailsUrl) : null; @@ -88,8 +85,7 @@ class MonAlisaClient { Accept: 'application/json;charset=utf-8', Connection: 'keep-alive', }, - agent: pfxCertificateBytes && certificatePassphrase - ? new https.Agent({ pfx: pfxCertificateBytes, passphrase: certificatePassphrase }) : undefined, + agent, }; } @@ -106,7 +102,7 @@ class MonAlisaClient { /** * Fetch data passes versions from MonAlisa - * @return {string} payload raw data acquired from MonAlisa: csv with data passes properties + * @return {Promise} payload raw data acquired from MonAlisa: csv with data passes properties * @private */ async _fetchDataPassesVersions() { @@ -283,30 +279,3 @@ class MonAlisaClient { } exports.MonAlisaClient = MonAlisaClient; - -/** - * Create a new instance of MonAlisaClient - * - * @param {object} configuration configuration of MonAlisa client - * @param {URL|string} [configuration.dataPassesUrl] url to fetch data passes - * @param {URL|string} [configuration.dataPassDetailsUrl] url to fetch data pass version details - * @param {number} [configuration.yearLowerLimit] indicates how old data are accepted, - * @param {string} [configuration.userCertificatePath] path to PKCS12 certificate - * @param {string} [configuration.certificatePassphrase] passphrase to the certificate - * @return {Promise} resolved with instance configured with environment variables - */ -exports.createMonAlisaClient = async ({ - dataPassesUrl, - dataPassDetailsUrl, - simulationPassesUrl, - yearLowerLimit, - userCertificatePath, - certificatePassphrase, -}) => new MonAlisaClient({ - dataPassesUrl, - dataPassDetailsUrl, - simulationPassesUrl, - yearLowerLimit, - pfxCertificateBytes: await fs.readFile(userCertificatePath), - certificatePassphrase, -}); diff --git a/lib/server/services/housekeeping/handleLostRunsAndEnvironments.js b/lib/server/services/housekeeping/handleLostRunsAndEnvironments.js index 31724c30b3..6b27794aa5 100644 --- a/lib/server/services/housekeeping/handleLostRunsAndEnvironments.js +++ b/lib/server/services/housekeeping/handleLostRunsAndEnvironments.js @@ -12,16 +12,21 @@ const MILLISECONDS_IN_ONE_DAY = 24 * 60 * 60 * 1000; * mark them as gone to error. For all runs that do not have timeO2Stop or timeTrgStop, check through AliECS GUI if they are still running, and * if not, mark them as stopped NOW * + * @param {Agent} [httpAgent] agent to be used when sending HTTP requests * @return {Promise<{transitionedEnvironments: number[], endedRuns: []}>} resolve with the list of environment ids and run numbers that were lost * @deprecated */ -exports.handleLostRunsAndEnvironments = async () => { +exports.handleLostRunsAndEnvironments = async (httpAgent) => { // TODO remove with node 18 const { default: fetch } = await import('node-fetch'); - const existingEnvironmentsResponse = await fetch(buildUrl( - `${ServicesConfig.aliEcsGui.url}/api/core/environments`, - { token: ServicesConfig.aliEcsGui.token }, - )); + + const existingEnvironmentsResponse = await fetch( + buildUrl( + `${ServicesConfig.aliEcsGui.url}/api/core/environments`, + { token: ServicesConfig.aliEcsGui.token }, + ), + { agent: httpAgent }, + ); if (existingEnvironmentsResponse.ok) { const { environments } = await existingEnvironmentsResponse.json(); From fc9d1ef3e528f8a36d9c17a63eeea7d536f72b06 Mon Sep 17 00:00:00 2001 From: martinboulais <31805063+martinboulais@users.noreply.github.com> Date: Mon, 4 Nov 2024 15:41:27 +0100 Subject: [PATCH 2/4] Fix linter --- .../externalServicesSynchronization/monalisa/MonAlisaClient.js | 2 -- 1 file changed, 2 deletions(-) diff --git a/lib/server/externalServicesSynchronization/monalisa/MonAlisaClient.js b/lib/server/externalServicesSynchronization/monalisa/MonAlisaClient.js index 54319a4b41..f637d195d4 100644 --- a/lib/server/externalServicesSynchronization/monalisa/MonAlisaClient.js +++ b/lib/server/externalServicesSynchronization/monalisa/MonAlisaClient.js @@ -13,9 +13,7 @@ * or submit itself to any jurisdiction. */ -const https = require('https'); const { extractLhcPeriod } = require('../../utilities/extractLhcPeriod'); -const fs = require('fs').promises; const VALID_DATA_PASS_NAME_REGEX = /^LHC\d\d[a-zA-Z]+_([a-z]pass|skimming|skimmed)[^\s]*$/; From ee1d50a35c839d616d7e9fb0caf9829bddc979fe Mon Sep 17 00:00:00 2001 From: martinboulais <31805063+martinboulais@users.noreply.github.com> Date: Fri, 8 Nov 2024 14:36:26 +0100 Subject: [PATCH 3/4] Minor refactoring --- lib/application.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/application.js b/lib/application.js index cfd6b35876..ba2779e533 100644 --- a/lib/application.js +++ b/lib/application.js @@ -15,7 +15,7 @@ const { webUiServer } = require('./server'); const { gRPCServer } = require('./server/index.js'); const { GRPCConfig, ServicesConfig } = require('./config'); -const { gridUserCertificate, monalisa: monalisaConfig, ccdb: ccdbConfig } = ServicesConfig; +const { gridUserCertificate, monalisa: monalisaConfig, ccdb: ccdbConfig, enableHousekeeping } = ServicesConfig; const { handleLostRunsAndEnvironments } = require('./server/services/housekeeping/handleLostRunsAndEnvironments.js'); const { isInTestMode } = require('./utilities/env-utils.js'); const { ScheduledProcessesManager } = require('./server/services/ScheduledProcessesManager.js'); @@ -81,7 +81,7 @@ class BookkeepingApplication { await this.aliEcsSynchronizer.start(); } - if (monalisaConfig.enableSynchronization || ServicesConfig.enableHousekeeping) { + if (monalisaConfig.enableSynchronization || enableHousekeeping) { const pfxCertificateBytes = await fs.readFile(gridUserCertificate.path); const certificatePassphrase = gridUserCertificate.passphrase; @@ -100,7 +100,7 @@ class BookkeepingApplication { ); } - if (ServicesConfig.enableHousekeeping) { + if (enableHousekeeping) { this.scheduledProcessesManager.schedule( () => this.housekeeping(httpAgent), { From 6c85733df83a0389d9d5a26a903a42538f9b5a57 Mon Sep 17 00:00:00 2001 From: martinboulais <31805063+martinboulais@users.noreply.github.com> Date: Thu, 12 Dec 2024 11:54:23 +0100 Subject: [PATCH 4/4] Remove grid mention --- lib/application.js | 6 +++--- lib/config/services.js | 10 +++++----- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/lib/application.js b/lib/application.js index ba2779e533..dd4280d3de 100644 --- a/lib/application.js +++ b/lib/application.js @@ -15,7 +15,7 @@ const { webUiServer } = require('./server'); const { gRPCServer } = require('./server/index.js'); const { GRPCConfig, ServicesConfig } = require('./config'); -const { gridUserCertificate, monalisa: monalisaConfig, ccdb: ccdbConfig, enableHousekeeping } = ServicesConfig; +const { userCertificate, monalisa: monalisaConfig, ccdb: ccdbConfig, enableHousekeeping } = ServicesConfig; const { handleLostRunsAndEnvironments } = require('./server/services/housekeeping/handleLostRunsAndEnvironments.js'); const { isInTestMode } = require('./utilities/env-utils.js'); const { ScheduledProcessesManager } = require('./server/services/ScheduledProcessesManager.js'); @@ -82,8 +82,8 @@ class BookkeepingApplication { } if (monalisaConfig.enableSynchronization || enableHousekeeping) { - const pfxCertificateBytes = await fs.readFile(gridUserCertificate.path); - const certificatePassphrase = gridUserCertificate.passphrase; + const pfxCertificateBytes = await fs.readFile(userCertificate.path); + const certificatePassphrase = userCertificate.passphrase; const httpAgent = pfxCertificateBytes && certificatePassphrase ? new https.Agent({ pfx: pfxCertificateBytes, passphrase: certificatePassphrase }) diff --git a/lib/config/services.js b/lib/config/services.js index 0dd6368130..1d1b8b7602 100644 --- a/lib/config/services.js +++ b/lib/config/services.js @@ -12,8 +12,8 @@ */ const { - GRID_USER_CERTIFICATE_PATH, - GRID_USER_CERTIFICATE_PASSPHRASE, + USER_CERTIFICATE_PATH, + USER_CERTIFICATE_PASSPHRASE, MONALISA_CERTIFICATE_PATH, // DEPRECATED MONALISA_CERTIFICATE_PASSPHRASE, // DEPRECATED DATA_PASSES_YEAR_LOWER_LIMIT, @@ -29,9 +29,9 @@ const { exports.services = { enableHousekeeping: process.env?.ENABLE_HOUSEKEEPING?.toLowerCase() === 'true', - gridUserCertificate: { - path: GRID_USER_CERTIFICATE_PATH ?? MONALISA_CERTIFICATE_PATH, - passphrase: GRID_USER_CERTIFICATE_PASSPHRASE ?? MONALISA_CERTIFICATE_PASSPHRASE, + userCertificate: { + path: USER_CERTIFICATE_PATH ?? MONALISA_CERTIFICATE_PATH, + passphrase: USER_CERTIFICATE_PASSPHRASE ?? MONALISA_CERTIFICATE_PASSPHRASE, }, aliEcsGui: { url: process.env?.ALI_ECS_GUI_URL || null,