From 0e205a2cecfd135da1ce22c1224491a9c09ec306 Mon Sep 17 00:00:00 2001 From: Kasra Bigdeli Date: Fri, 16 Nov 2018 22:23:50 -0800 Subject: [PATCH] routes for registry added --- app-backend/src/api/ApiStatusCodes.js | 6 +- app-backend/src/datastore/DataStoreImpl.js | 128 ++++++++++++++++-- app-backend/src/routes/RegistriesRouter.js | 146 +++++++++++++++++++++ app-backend/src/routes/SystemRouter.js | 3 + app-backend/src/user/CaptainManager.js | 79 +++++++++-- 5 files changed, 345 insertions(+), 17 deletions(-) create mode 100644 app-backend/src/routes/RegistriesRouter.js diff --git a/app-backend/src/api/ApiStatusCodes.js b/app-backend/src/api/ApiStatusCodes.js index a6942eb..2ac9b78 100644 --- a/app-backend/src/api/ApiStatusCodes.js +++ b/app-backend/src/api/ApiStatusCodes.js @@ -32,7 +32,11 @@ let apiStatusCode = { ILLEGAL_OPERATION: 1108, - BUILD_ERROR: 1109 + BUILD_ERROR: 1109, + + ILLEGAL_PARAMETER: 1110, + + NOT_FOUND: 1111, }; diff --git a/app-backend/src/datastore/DataStoreImpl.js b/app-backend/src/datastore/DataStoreImpl.js index cc2bc63..aeadd85 100644 --- a/app-backend/src/datastore/DataStoreImpl.js +++ b/app-backend/src/datastore/DataStoreImpl.js @@ -21,6 +21,8 @@ const HAS_REGISTRY_SSL = 'hasRegistrySsl'; const HAS_LOCAL_REGISTRY = 'hasLocalRegistry'; const APP_DEFINITIONS = 'appDefinitions'; const EMAIL_ADDRESS = 'emailAddress'; +const DOCKER_REGISTRIES = 'dockerRegistries'; +const DEFAULT_DOCKER_REGISTRY = 'defaultDockerReg'; const NET_DATA_INFO = 'netDataInfo'; const NGINX_BASE_CONFIG = 'NGINX_BASE_CONFIG'; const NGINX_CAPTAIN_CONFIG = 'NGINX_CAPTAIN_CONFIG'; @@ -259,8 +261,7 @@ class DataStore { for (let idx = 0; idx < app.customDomain.length; idx++) { if (app.customDomain[idx].publicDomain === customDomain) { removed = true; - } - else { + } else { newDomains.push(app.customDomain[idx]); } } @@ -497,8 +498,7 @@ class DataStore { } app.appPushWebhook.repoInfo = appPushWebhookRepoInfo; - } - else { + } else { app.appPushWebhook = {}; @@ -506,9 +506,9 @@ class DataStore { if (ports) { - function isPortValid(portNumber) { + let isPortValid = function (portNumber) { return portNumber > 0 && portNumber < 65535; - } + }; let tempPorts = []; for (let i = 0; i < ports.length; i++) { @@ -572,8 +572,7 @@ class DataStore { newVol.hostPath = obj.hostPath; newVol.type = 'bind'; - } - else { + } else { if (!isNameAllowed(obj.volumeName)) { throw new ApiStatusCodes.createError(ApiStatusCodes.STATUS_ERROR_GENERIC, "Invalid volume name: " + obj.volumeName); @@ -609,6 +608,119 @@ class DataStore { }); } + getDefaultPushRegistry() { + + const self = this; + + return Promise.resolve() + .then(function () { + + return self.data.get(DEFAULT_DOCKER_REGISTRY); + + }); + + } + + setDefaultPushRegistry(registryId) { + + const self = this; + + return Promise.resolve() + .then(function () { + + let found = false; + let registries = self.data.get(DOCKER_REGISTRIES) || []; + for (let i = 0; i < registries.length; i++) { + const registry = registries[i]; + if (registry.id === registryId) { + found = true; + } + } + + // registryId can be NULL/Empty, meaning that no registry will be the default push registry + if (!found && !!registryId) { + throw ApiStatusCodes.createError(ApiStatusCodes.NOT_FOUND, 'Registry not found'); + } + + self.data.set(DEFAULT_DOCKER_REGISTRY, registryId); + + }); + } + + deleteRegistry(registryId) { + + const self = this; + + return Promise.resolve() + .then(function () { + + let newReg = []; + let registries = self.data.get(DOCKER_REGISTRIES) || []; + for (let i = 0; i < registries.length; i++) { + const registry = registries[i]; + if (registry.id !== registryId) { + newReg.push(registry); + } + } + + if (newReg.length === registries.length) { + throw ApiStatusCodes.createError(ApiStatusCodes.NOT_FOUND, 'Registry not found'); + } + + self.data.set(DOCKER_REGISTRIES, newReg); + + }); + } + + getAllRegistries() { + + const self = this; + + return Promise.resolve() + .then(function () { + + return self.data.get(DOCKER_REGISTRIES); + + }); + } + + addRegistryToDb(registryUser, registryPassword, registryDomain, registryImagePrefix) { + + const self = this; + + return Promise.resolve() + .then(function () { + return new Promise(function (resolve, reject) { + + resolve(self.data.get(DOCKER_REGISTRIES) || []); + + }) + }) + .then(function (registries) { + + let id = uuid(); + let isAlreadyTaken = true; + + while (isAlreadyTaken) { + isAlreadyTaken = false; + for (let i = 0; i < registries.length; i++) { + if (registries[i].id === id) { + isAlreadyTaken = true; + break; + } + } + } + + registries.push({ + id, registryUser, registryPassword, registryDomain, registryImagePrefix + }); + + self.data.set(DOCKER_REGISTRIES, registries); + + }); + + } + setUserEmailAddress(emailAddress) { const self = this; diff --git a/app-backend/src/routes/RegistriesRouter.js b/app-backend/src/routes/RegistriesRouter.js new file mode 100644 index 0000000..be714ad --- /dev/null +++ b/app-backend/src/routes/RegistriesRouter.js @@ -0,0 +1,146 @@ +const express = require('express'); +const router = express.Router(); +const BaseApi = require('../api/BaseApi'); +const ApiStatusCodes = require('../api/ApiStatusCodes'); +const Logger = require('../utils/Logger'); +const CaptainManager = require('../user/CaptainManager'); +const Validator = require('validator'); +const CaptainConstants = require('../utils/CaptainConstants'); + +router.post('/insert/', function (req, res, next) { + + let registryUser = req.body.registryUser + ''; + let registryPassword = req.body.registryPassword + ''; + let registryDomain = req.body.registryDomain + ''; + let registryImagePrefix = req.body.registryImagePrefix + ''; + + const captainManager = CaptainManager.get(); + + return Promise.resolve() + .then(function () { + + return captainManager.addRegistry(registryUser, registryPassword, registryDomain, registryImagePrefix); + + }) + .then(function () { + + let msg = 'Registry is added.'; + Logger.d(msg); + res.send(new BaseApi(ApiStatusCodes.STATUS_OK, msg)); + + }) + .catch(function (error) { + + Logger.e(error); + + if (error && error.captainErrorType) { + res.send(new BaseApi(error.captainErrorType, error.apiMessage)); + return; + } + + res.sendStatus(500); + }); + +}); + +router.get('/all/', function (req, res, next) { + + const captainManager = CaptainManager.get(); + let registries = []; + + return Promise.resolve() + .then(function () { + + return captainManager.getAllRegistries(); + + }) + .then(function (registriesAll) { + + registries = registriesAll; + return captainManager.getDefaultPushRegistry(); + + }) + .then(function (defaultPush) { + + + let baseApi = new BaseApi(ApiStatusCodes.STATUS_OK, 'All registries retrieved'); + baseApi.registries = registries; + baseApi.defaultPushRegistryId = defaultPush; + res.send(baseApi); + + }) + .catch(function (error) { + + Logger.e(error); + + if (error && error.captainErrorType) { + res.send(new BaseApi(error.captainErrorType, error.apiMessage)); + return; + } + + res.sendStatus(500); + }); +}); + +router.post('/delete/', function (req, res, next) { + + let registryId = req.body.registryId + ''; + const captainManager = CaptainManager.get(); + + return Promise.resolve() + .then(function () { + + return captainManager.deleteRegistry(registryId); + + }) + .then(function () { + + let baseApi = new BaseApi(ApiStatusCodes.STATUS_OK, 'Registry deleted'); + res.send(baseApi); + + }) + .catch(function (error) { + + Logger.e(error); + + if (error && error.captainErrorType) { + res.send(new BaseApi(error.captainErrorType, error.apiMessage)); + return; + } + + res.sendStatus(500); + }); +}); + +router.post('/setpush/', function (req, res, next) { + + let registryId = req.body.registryId + ''; + const captainManager = CaptainManager.get(); + + return Promise.resolve() + .then(function () { + + return captainManager.setDefaultPushRegistry(registryId); + + }) + .then(function () { + + let baseApi = new BaseApi(ApiStatusCodes.STATUS_OK, 'Push Registry changed'); + res.send(baseApi); + + }) + .catch(function (error) { + + Logger.e(error); + + if (error && error.captainErrorType) { + res.send(new BaseApi(error.captainErrorType, error.apiMessage)); + return; + } + + res.sendStatus(500); + }); +}); + + +module.exports = router; diff --git a/app-backend/src/routes/SystemRouter.js b/app-backend/src/routes/SystemRouter.js index befa317..473c9e8 100644 --- a/app-backend/src/routes/SystemRouter.js +++ b/app-backend/src/routes/SystemRouter.js @@ -6,6 +6,9 @@ const Logger = require('../utils/Logger'); const CaptainManager = require('../user/CaptainManager'); const Validator = require('validator'); const CaptainConstants = require('../utils/CaptainConstants'); +const RegistriesRouter = require('./RegistriesRouter'); + +router.use('/registries/', RegistriesRouter); router.post('/changerootdomain/', function (req, res, next) { diff --git a/app-backend/src/user/CaptainManager.js b/app-backend/src/user/CaptainManager.js index 06cac7b..620726d 100644 --- a/app-backend/src/user/CaptainManager.js +++ b/app-backend/src/user/CaptainManager.js @@ -318,8 +318,7 @@ class CaptainManager { if (error || !body || (body !== self.getHealthCheckUuid())) { callback(false); - } - else { + } else { callback(true); } @@ -382,8 +381,7 @@ class CaptainManager { if (hasFailedCheck) { self.consecutiveHealthCheckFailCount = self.consecutiveHealthCheckFailCount + 1; - } - else { + } else { self.consecutiveHealthCheckFailCount = 0; } @@ -431,11 +429,9 @@ class CaptainManager { if (error) { reject(error); - } - else if (!body || !JSON.parse(body).results) { + } else if (!body || !JSON.parse(body).results) { reject(new Error('Received empty body or no result for version list on docker hub.')); - } - else { + } else { let results = JSON.parse(body).results; let tags = []; for (let idx = 0; idx < results.length; idx++) { @@ -700,6 +696,73 @@ class CaptainManager { return this.dockerRegistry; } + setDefaultPushRegistry(registryId) { + + const self = this; + return Promise.resolve() + .then(function () { + + return self.dataStore.setDefaultPushRegistry(registryId); + + }); + + } + + getDefaultPushRegistry() { + + const self = this; + return Promise.resolve() + .then(function () { + + return self.dataStore.getDefaultPushRegistry(); + + }); + + } + + deleteRegistry(registryId) { + const self = this; + return Promise.resolve() + .then(function () { + + return self.getDefaultPushRegistry(); + + }) + .then(function (registryIdDefaultPush) { + + if (registryId === registryIdDefaultPush) { + throw ApiStatusCodes.createError(ApiStatusCodes.ILLEGAL_PARAMETER, 'Cannot remove the default push'); + } + + return self.dataStore.deleteRegistry(registryId); + + }); + } + + getAllRegistries() { + const self = this; + return Promise.resolve() + .then(function () { + + return (self.dataStore.getAllRegistries() || []); + + }); + } + + addRegistry(registryUser, registryPassword, registryDomain, registryImagePrefix) { + const self = this; + return Promise.resolve() + .then(function () { + + if (!registryUser || !registryPassword || !registryDomain) { + throw ApiStatusCodes.createError(ApiStatusCodes.ILLEGAL_PARAMETER, 'User, password and domain are required.'); + } + + return self.dataStore.addRegistryToDb(registryUser, registryPassword, registryDomain, registryImagePrefix); + + }); + } + enableSsl(emailAddress) { const self = this; return Promise.resolve()