From 312ee18e8a2103ab690057aa5ffc2b5a62db3f4b Mon Sep 17 00:00:00 2001 From: lgrd Date: Wed, 15 Mar 2023 16:01:11 +0100 Subject: [PATCH] [feat] create admin without services (#51) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * [feat] init admin without services * [fix] update changelog * [doc] précision dans la doc dev --- changelog.md | 4 +- documentation/developers/concepts.md | 1 + package.json | 4 +- src/js/administrator/administrator.js | 332 ++++++++++++++------------ src/js/road2.js | 6 +- 5 files changed, 183 insertions(+), 164 deletions(-) diff --git a/changelog.md b/changelog.md index 96ce9eb..2bbe528 100644 --- a/changelog.md +++ b/changelog.md @@ -4,6 +4,8 @@ ADDED: - Ajout de la route GET /admin/1.0.0/services dans l'API d'administration + - Ajout de la route GET /admin/1.0.0/services/{servcie} dans l'API d'administration + - Il est maintenant possible démarrer un administrateur sans services pré-configurés CHANGED: - La documentation de l'API d'administration a été grandement enrichie. @@ -11,7 +13,7 @@ CHANGED: - Les dossiers de sources et de resources des services peuvent maintenant être vide à l'initialisation. DELETED: - - option onStart inside admin configuration is deleted + - L'option onStart de la configuration admin est supprimée ## 2.0.0 diff --git a/documentation/developers/concepts.md b/documentation/developers/concepts.md index b25296f..582edc3 100644 --- a/documentation/developers/concepts.md +++ b/documentation/developers/concepts.md @@ -129,6 +129,7 @@ Le premier point d'entrée possible est le fichier `src/js/road2.js`. Ce fichier Cet administrateur permet plusieurs choses : - On peut le lancer uniquement pour vérifier la bonne configuration de l'administrateur et des services associés. Dans ce cas là, le processus s'éteint après la vérification et renvoie un code d'erreur permettant de déterminer s'il y a eu un problème et son type. - On peut le lancer en mode serveur pour administrer un ou plusieurs services via une API HTTP(S). Dans ce cas là, l'administrateur va lancer tous les services déjà configurés. Il sera aussi possible d'en créer d'autres plus tard. +- On peut créer un administrateur sans configuerer un service. Il sera possible de les configurer plus tard. Un administrateur a été créé pour réaliser des tâches qui auraient gêné la bonne exécution du service. diff --git a/package.json b/package.json index d612e10..677658b 100644 --- a/package.json +++ b/package.json @@ -1,12 +1,12 @@ { "name": "road2", - "version": "2.0.0", + "version": "2.1.0-DEVELOP", "description": "Calcul d'itinéraire", "author": "RDEV - IGN", "main": "src/js/road2.js", "scripts": { - "start": "node ./src/js/road2.js", + "start": "env NODE_ENV=prod node ./src/js/road2.js", "configCheck": "node ./src/js/road2.js --configCheck", "utest": "mocha --recursive './test/unit/mocha/**/*.js'", "itest": "mocha --recursive './test/integration/mocha/**/*.js'", diff --git a/src/js/administrator/administrator.js b/src/js/administrator/administrator.js index 7f41136..396127a 100644 --- a/src/js/administrator/administrator.js +++ b/src/js/administrator/administrator.js @@ -100,134 +100,134 @@ module.exports = class Administrator { LOGGER.debug("configuration.administration.services est bien un tableau"); if (configuration.administration.services.length === 0) { - LOGGER.error("Mauvaise configuration: 'administration.services' est un tableau vide."); - return false; + LOGGER.warn("'administration.services' est un tableau vide."); } else { LOGGER.debug("configuration.administration.services est bien un tableau qui contient des éléments"); - } - } - } + // On ne veut pas que les Id soient réutilisés + let checkedServiceId = new Array(); + let checkedServiceConf = new Array(); + let checkedServiceConfLocation = new Array(); - // On ne veut pas que les Id soient réutilisés - let checkedServiceId = new Array(); - let checkedServiceConf = new Array(); - let checkedServiceConfLocation = new Array(); + for (let i = 0; i < configuration.administration.services.length; i++) { - for (let i = 0; i < configuration.administration.services.length; i++) { + let curServiceConf = configuration.administration.services[i]; - let curServiceConf = configuration.administration.services[i]; + let configurationLocation = ""; + let configurationContent = {}; - let configurationLocation = ""; - let configurationContent = {}; - - if (!curServiceConf.id) { - LOGGER.error("Mauvaise configuration: 'id' absent."); - return false; - } else { - - if (typeof(curServiceConf.id) !== "string") { - LOGGER.error("Mauvaise configuration: 'id' n'est pas une string."); - return false; - } - if (curServiceConf.id === "") { - LOGGER.error("Mauvaise configuration: 'id' est une string vide."); - return false; - } + if (!curServiceConf.id) { + LOGGER.error("Mauvaise configuration: 'id' absent."); + return false; + } else { - LOGGER.debug("Id présent : " + curServiceConf.id); + if (typeof(curServiceConf.id) !== "string") { + LOGGER.error("Mauvaise configuration: 'id' n'est pas une string."); + return false; + } + if (curServiceConf.id === "") { + LOGGER.error("Mauvaise configuration: 'id' est une string vide."); + return false; + } - // On vérifie que l'id n'est pas déjà pris - if (checkedServiceId.length === 0) { - // On continue la suite de la vérification - } else { + LOGGER.debug("Id présent : " + curServiceConf.id); - for (let j = 0; j < checkedServiceId.length; j++) { - if (curServiceConf.id === checkedServiceId[j]) { - LOGGER.error("Id de service déjà pris : " + curServiceConf.id); - return false; - } - } + // On vérifie que l'id n'est pas déjà pris + if (checkedServiceId.length === 0) { + // On continue la suite de la vérification + } else { - } + for (let j = 0; j < checkedServiceId.length; j++) { + if (curServiceConf.id === checkedServiceId[j]) { + LOGGER.error("Id de service déjà pris : " + curServiceConf.id); + return false; + } + } - } + } - if (!curServiceConf.configuration) { - LOGGER.error("Mauvaise configuration: 'configuration' absent."); - return false; - } else { - - LOGGER.debug("configuration présent"); - - try { - configurationLocation = path.resolve(path.dirname(this._configurationPath), curServiceConf.configuration); - LOGGER.debug("Chemin absolu du fichier de configuration du service : " + configurationLocation); - } catch (error) { - LOGGER.error("Can't get absolute path of service configuration: " + curServiceConf.configuration); - LOGGER.error(error); - return false; - } + } - // On vérifie que ce chemin n'est pas déjà utilisé - if (checkedServiceConfLocation.length !== 0) { - for (let cs = 0; cs < checkedServiceConfLocation.length; cs++) { - if (configurationLocation === checkedServiceConfLocation[cs]) { - LOGGER.error("La configuration indiquée est déjà vérifiée. Elle ne peut être utilisée pour un autre service géré par cet administrateur."); + if (!curServiceConf.configuration) { + LOGGER.error("Mauvaise configuration: 'configuration' absent."); return false; + } else { + + LOGGER.debug("configuration présent"); + + try { + configurationLocation = path.resolve(path.dirname(this._configurationPath), curServiceConf.configuration); + LOGGER.debug("Chemin absolu du fichier de configuration du service : " + configurationLocation); + } catch (error) { + LOGGER.error("Can't get absolute path of service configuration: " + curServiceConf.configuration); + LOGGER.error(error); + return false; + } + + // On vérifie que ce chemin n'est pas déjà utilisé + if (checkedServiceConfLocation.length !== 0) { + for (let cs = 0; cs < checkedServiceConfLocation.length; cs++) { + if (configurationLocation === checkedServiceConfLocation[cs]) { + LOGGER.error("La configuration indiquée est déjà vérifiée. Elle ne peut être utilisée pour un autre service géré par cet administrateur."); + return false; + } + } + } + + try { + // Il s'agit juste de savoir si le fichier est lisible par Road2, il sera exploité plus tard + configurationContent = JSON.parse(fs.readFileSync(configurationLocation)); + LOGGER.debug("Le contenu du fichier est accessible par Road2"); + } catch (error) { + LOGGER.error("Mauvaise configuration: impossible de lire ou de parser le fichier de configuration du service: " + configurationLocation); + LOGGER.error(error); + return false; + } + + // On vérifie que ce contenu n'est pas déjà utilisé + if (checkedServiceConf.length !== 0) { + for (let cs = 0; cs < checkedServiceConf.length; cs++) { + try { + assert.deepStrictEqual(configurationContent, checkedServiceConf[cs]); + LOGGER.error("Le contenu de configuration indiqué est déjà vérifié pour un autre service. Il ne peut être utilisée pour plus d'un service géré par cet administrateur."); + return false; + } catch (err) { + LOGGER.debug("Les deux configuration de service ne sont pas identiques."); + } + } + } + + + } - } - } - - try { - // Il s'agit juste de savoir si le fichier est lisible par Road2, il sera exploité plus tard - configurationContent = JSON.parse(fs.readFileSync(configurationLocation)); - LOGGER.debug("Le contenu du fichier est accessible par Road2"); - } catch (error) { - LOGGER.error("Mauvaise configuration: impossible de lire ou de parser le fichier de configuration du service: " + configurationLocation); - LOGGER.error(error); - return false; - } - - // On vérifie que ce contenu n'est pas déjà utilisé - if (checkedServiceConf.length !== 0) { - for (let cs = 0; cs < checkedServiceConf.length; cs++) { - try { - assert.deepStrictEqual(configurationContent, checkedServiceConf[cs]); - LOGGER.error("Le contenu de configuration indiqué est déjà vérifié pour un autre service. Il ne peut être utilisée pour plus d'un service géré par cet administrateur."); + + if (!curServiceConf.creationType) { + LOGGER.error("Mauvaise configuration: 'creationType' absent."); return false; - } catch (err) { - LOGGER.debug("Les deux configuration de service ne sont pas identiques."); + } else { + + LOGGER.debug("configuration.creationType présent"); + + if (!["sameProcess","newProcess","findByURI"].includes(curServiceConf.creationType)) { + LOGGER.error("Mauvaise configuration: 'creationType' doit être parmi 'sameProcess', 'newProcess', 'findByURI'."); + return false; + } else { + LOGGER.debug("configuration.creationType bien configuré"); + } + } + + LOGGER.debug("Vérification du service en cours terminée"); + checkedServiceId.push(curServiceConf.id); + checkedServiceConf.push(configurationContent); + checkedServiceConfLocation.push(configurationLocation); + + } - } - - - } - - if (!curServiceConf.creationType) { - LOGGER.error("Mauvaise configuration: 'creationType' absent."); - return false; - } else { - - LOGGER.debug("configuration.creationType présent"); - - if (!["sameProcess","newProcess","findByURI"].includes(curServiceConf.creationType)) { - LOGGER.error("Mauvaise configuration: 'creationType' doit être parmi 'sameProcess', 'newProcess', 'findByURI'."); - return false; - } else { - LOGGER.debug("configuration.creationType bien configuré"); } - - } - - LOGGER.debug("Vérification du service en cours terminée"); - checkedServiceId.push(curServiceConf.id); - checkedServiceConf.push(configurationContent); - checkedServiceConfLocation.push(configurationLocation); - + } } LOGGER.debug("Vérification des services terminée"); @@ -380,6 +380,11 @@ module.exports = class Administrator { LOGGER.info("Vérification de la configuration des services..."); + if (this._configuration.administration.services.length === 0) { + LOGGER.warn("Aucun service à vérifier"); + return true; + } + for (let i = 0; i < this._configuration.administration.services.length; i++) { let curIASConf = this._configuration.administration.services[i]; @@ -414,7 +419,12 @@ module.exports = class Administrator { async createServices() { - LOGGER.info("Vérification et création des services"); + LOGGER.info("Vérification et création des services..."); + + if (this._configuration.administration.services.length === 0) { + LOGGER.warn("Aucun service à créer"); + return true; + } // Pour chaque service, on vérifie sa configuration puis on le démarre @@ -480,64 +490,70 @@ module.exports = class Administrator { // Dans ce cas là, il faudra que l'administrator ait un attribut d'état et que celui-ci soit lu dans cette fonction healthResponse.adminState = "green"; - // Pour chaque service, on demande au serviceManager l'état du service - for (let i = 0; i < this._configuration.administration.services.length; i++) { + if (this._configuration.administration.services.length === 0) { + LOGGER.info("Aucun service, donc pas de status à récupérer"); + } else { - let curServiceId = this._configuration.administration.services[i].id; - LOGGER.debug("Demande de l'état du service : " + curServiceId); + // Pour chaque service, on demande au serviceManager l'état du service + for (let i = 0; i < this._configuration.administration.services.length; i++) { - // Le passage potentiel par IPC fait perdre les méthodes donc dans la suite, on est obligé de prendre les attributs avec _ - let curHealthResponse = await this._serviceManager.computeRequest(curServiceId, healthRequest); + let curServiceId = this._configuration.administration.services[i].id; + LOGGER.debug("Demande de l'état du service : " + curServiceId); - if (curHealthResponse._type !== "healthResponse") { - // Ce n'est pas normal, on renvoit une erreur pour ce service - // et on met le flag rouge - LOGGER.error("Le service " + curServiceId + " n'a pas donné de réponse du bon type"); - gotRed = true; - healthResponse.serviceStates.push({"serviceId":curServiceId,"state":"unknown"}); - continue; - } + // Le passage potentiel par IPC fait perdre les méthodes donc dans la suite, on est obligé de prendre les attributs avec _ + let curHealthResponse = await this._serviceManager.computeRequest(curServiceId, healthRequest); - if (!curHealthResponse._serviceStates[0]) { - // Ce n'est pas normal, on renvoit une erreur pour ce service - // et on met le flag rouge - LOGGER.error("Le service " + curServiceId + " n'a pas donné de réponse"); - gotRed = true; - healthResponse.serviceStates.push({"serviceId":curServiceId,"state":"unknown"}); - continue; - } + if (curHealthResponse._type !== "healthResponse") { + // Ce n'est pas normal, on renvoit une erreur pour ce service + // et on met le flag rouge + LOGGER.error("Le service " + curServiceId + " n'a pas donné de réponse du bon type"); + gotRed = true; + healthResponse.serviceStates.push({"serviceId":curServiceId,"state":"unknown"}); + continue; + } - if (!curHealthResponse._serviceStates[0].state) { - // Ce n'est pas normal, on renvoit une erreur pour ce service - // et on met le flag rouge - LOGGER.error("Le service " + curServiceId + " n'a pas donné d'état"); - gotRed = true; - healthResponse.serviceStates.push({"serviceId":curServiceId,"state":"unknown"}); - continue; - } + if (!curHealthResponse._serviceStates[0]) { + // Ce n'est pas normal, on renvoit une erreur pour ce service + // et on met le flag rouge + LOGGER.error("Le service " + curServiceId + " n'a pas donné de réponse"); + gotRed = true; + healthResponse.serviceStates.push({"serviceId":curServiceId,"state":"unknown"}); + continue; + } - // Pour la suite, on note la présence d'orange et de rouge dans les services - if (curHealthResponse._serviceStates[0].state === "orange") { - LOGGER.debug("Le service " + curServiceId + " est orange"); - gotOrange = true; - } else if (curHealthResponse._serviceStates[0].state === "red") { - LOGGER.debug("Le service " + curServiceId + " est red"); - gotRed = true; - } else if (curHealthResponse._serviceStates[0].state === "green") { - // Tout va bien, rien à faire - LOGGER.debug("Le service " + curServiceId + " est green"); - } else { - // Cela ne devrait pas arriver, on renvoit une erreur pour ce service - // et on met le flag rouge - LOGGER.error("Le service " + curServiceId + " est dans un état inconnu"); - gotRed = true; - healthResponse.serviceStates.push({"serviceId":curServiceId,"state":"unknown"}); - continue; - } + if (!curHealthResponse._serviceStates[0].state) { + // Ce n'est pas normal, on renvoit une erreur pour ce service + // et on met le flag rouge + LOGGER.error("Le service " + curServiceId + " n'a pas donné d'état"); + gotRed = true; + healthResponse.serviceStates.push({"serviceId":curServiceId,"state":"unknown"}); + continue; + } + + // Pour la suite, on note la présence d'orange et de rouge dans les services + if (curHealthResponse._serviceStates[0].state === "orange") { + LOGGER.debug("Le service " + curServiceId + " est orange"); + gotOrange = true; + } else if (curHealthResponse._serviceStates[0].state === "red") { + LOGGER.debug("Le service " + curServiceId + " est red"); + gotRed = true; + } else if (curHealthResponse._serviceStates[0].state === "green") { + // Tout va bien, rien à faire + LOGGER.debug("Le service " + curServiceId + " est green"); + } else { + // Cela ne devrait pas arriver, on renvoit une erreur pour ce service + // et on met le flag rouge + LOGGER.error("Le service " + curServiceId + " est dans un état inconnu"); + gotRed = true; + healthResponse.serviceStates.push({"serviceId":curServiceId,"state":"unknown"}); + continue; + } - // On stocke le retour de ce service - curHealthResponse._serviceStates[0].id = curServiceId; - healthResponse.serviceStates.push(curHealthResponse._serviceStates[0]); + // On stocke le retour de ce service + curHealthResponse._serviceStates[0].id = curServiceId; + healthResponse.serviceStates.push(curHealthResponse._serviceStates[0]); + + } } diff --git a/src/js/road2.js b/src/js/road2.js index 6cdf6ed..b6342d6 100644 --- a/src/js/road2.js +++ b/src/js/road2.js @@ -68,7 +68,7 @@ async function start() { LOGGER.error("Problèmes lors du démarrage des services. Reconfigurez les et relancez leur démarrage."); // On n'éteint pas le serveur d'administration car les services pourront être reconfiguré et démarrés par l'API } else { - LOGGER.info("Les services ont été démarré"); + LOGGER.info("S'il y en a, les services ont été démarré"); } } @@ -102,7 +102,7 @@ async function start() { pm.shutdown(1); } else { - LOGGER.info("La configuration des services est validée"); + LOGGER.info("S'il y en a, la configuration des services est validée"); } } @@ -204,7 +204,7 @@ function checkAndInitLogger(userLogConfiguration) { } //Instanciation du logger - LOGGER = log4js.getLogger('SERVER'); + LOGGER = log4js.getLogger('ROAD2'); LOGGER.info("Logger charge.");