diff --git a/src/cli/microservice.js b/src/cli/microservice.js index 0b9895f8d..735af77d6 100644 --- a/src/cli/microservice.js +++ b/src/cli/microservice.js @@ -80,7 +80,8 @@ class Microservice extends BaseCLIHandler { }, { name: 'microservice-id', alias: 'i', type: String, description: 'Microservice ID', - group: [constants.CMD_UPDATE, constants.CMD_REMOVE, constants.CMD_INFO, constants.CMD_PORT_MAPPING] + group: [constants.CMD_UPDATE, constants.CMD_REMOVE, constants.CMD_INFO, constants.CMD_PORT_MAPPING_CREATE, + constants.CMD_PORT_MAPPING_REMOVE, constants.CMD_PORT_MAPPING_LIST] }, { name: 'name', alias: 'n', type: String, description: 'Microservice name', @@ -123,28 +124,20 @@ class Microservice extends BaseCLIHandler { group: [constants.CMD_ADD] }, { - name: 'routes', alias: 't', type: String, description: 'Microservice route(s) (receiving microservices)', multiple: true, - group: [constants.CMD_ADD] - }, - { - name: 'add', alias: 'a', type: String, description: 'Add new route(s)', - group: [constants.CMD_ROUTE] - }, - { - name: 'remove', alias: 'm', type: String, description: 'Delete existing route(s)', - group: [constants.CMD_ROUTE] + name: 'mapping', alias: 'P', type: String, description: 'Container port mapping', + group: [constants.CMD_PORT_MAPPING_CREATE] }, { - name: 'create', alias: 'b', type: String, description: 'Add new port mapping(s)', - group: [constants.CMD_PORT_MAPPING] + name: 'routes', alias: 't', type: String, description: 'Microservice route(s) (receiving microservices)', multiple: true, + group: [constants.CMD_ADD] }, { - name: 'delete', alias: 'B', type: String, description: 'Delete existing port mapping(s)', - group: [constants.CMD_PORT_MAPPING] + name: 'route', alias: 'T', type: String, description: 'Microservice route (receiving microservices)', + group: [constants.CMD_ROUTE_CREATE, constants.CMD_ROUTE_REMOVE] }, { - name: 'list', alias: 'G', type: Boolean, description: 'List port mappings', - group: [constants.CMD_PORT_MAPPING] + name: 'internal-port', alias: 'b', type: String, description: 'Internal port', + group: [constants.CMD_PORT_MAPPING_REMOVE] }, { name: 'rebuild', alias: 'w', type: Boolean, description: 'Rebuild microservice image on fog agent', @@ -165,8 +158,11 @@ class Microservice extends BaseCLIHandler { [constants.CMD_REMOVE]: 'Delete a microservice.', [constants.CMD_LIST]: 'List all microservices.', [constants.CMD_INFO]: 'Get microservice settings.', - [constants.CMD_ROUTE]: 'Add/Remove microservice route.', - [constants.CMD_PORT_MAPPING]: 'Create/Delete/List microservice port mapping.' + [constants.CMD_ROUTE_CREATE]: 'Create microservice route.', + [constants.CMD_ROUTE_REMOVE]: 'Remove microservice route.', + [constants.CMD_PORT_MAPPING_CREATE]: 'Create microservice port mapping.', + [constants.CMD_PORT_MAPPING_REMOVE]: 'Remove microservice port mapping.', + [constants.CMD_PORT_MAPPING_LIST]: 'List microservice port mapping.' } } @@ -175,25 +171,34 @@ class Microservice extends BaseCLIHandler { switch (microserviceCommand.command.command) { case constants.CMD_ADD: - await _executeCase(microserviceCommand, constants.CMD_ADD, _createMicroservice, false); + await _executeCase(microserviceCommand, constants.CMD_ADD, _createMicroservice); break; case constants.CMD_UPDATE: - await _executeCase(microserviceCommand, constants.CMD_UPDATE, _updateMicroservice, false); + await _executeCase(microserviceCommand, constants.CMD_UPDATE, _updateMicroservice); break; case constants.CMD_REMOVE: - await _executeCase(microserviceCommand, constants.CMD_REMOVE, _removeMicroservice, false); + await _executeCase(microserviceCommand, constants.CMD_REMOVE, _removeMicroservice); break; case constants.CMD_LIST: - await _executeCase(microserviceCommand, constants.CMD_LIST, _listMicroservices, false); + await _executeCase(microserviceCommand, constants.CMD_LIST, _listMicroservices); break; case constants.CMD_INFO: - await _executeCase(microserviceCommand, constants.CMD_INFO, _getMicroservice, false); + await _executeCase(microserviceCommand, constants.CMD_INFO, _getMicroservice); + break; + case constants.CMD_ROUTE_CREATE: + await _executeCase(microserviceCommand, constants.CMD_ROUTE_CREATE, _createRoute); + break; + case constants.CMD_ROUTE_REMOVE: + await _executeCase(microserviceCommand, constants.CMD_ROUTE_REMOVE, _removeRoute); break; - case constants.CMD_ROUTE: - await _executeCase(microserviceCommand, constants.CMD_ROUTE, _executeRouteCommand, false); + case constants.CMD_PORT_MAPPING_CREATE: + await _executeCase(microserviceCommand, constants.CMD_PORT_MAPPING_CREATE, _createPortMapping); break; - case constants.CMD_PORT_MAPPING: - await _executeCase(microserviceCommand, constants.CMD_PORT_MAPPING, _executePortMappingCommand, false); + case constants.CMD_PORT_MAPPING_REMOVE: + await _executeCase(microserviceCommand, constants.CMD_PORT_MAPPING_REMOVE, _removePortMapping); + break; + case constants.CMD_PORT_MAPPING_LIST: + await _executeCase(microserviceCommand, constants.CMD_PORT_MAPPING_LIST, _listPortMappings); break; case constants.CMD_HELP: default: @@ -229,24 +234,28 @@ class Microservice extends BaseCLIHandler { example: '$ iofog-controller microservice add [other required options] --volumes /host_src:/container_src /host_bin:/container_bin', }, { - desc: '3. Port mapping (internal:external:publicMode)', + desc: '3. Port mapping (80:8080:false - internal port : external port : public mode)', example: '$ iofog-controller microservice add [other required options] --ports 80:8080:false 443:5443:false', }, { - desc: '4. Add routes (sourceMicroserviceId:destMicroserviceId)', - example: '$ iofog-controller microservice route --add ABC:DEF', + desc: '4. Add routes (ABC:DEF - source microservice id : dest microservice id)', + example: '$ iofog-controller microservice add [other required options] --routes ABC:DEF RFG:HJK' + }, + { + desc: '4. Add route (ABC:DEF - source microservice id : dest microservice id)', + example: '$ iofog-controller microservice route-create --route ABC:DEF', }, { - desc: '5. Delete route (sourceMicroserviceId:destMicroserviceId)', - example: '$ iofog-controller microservice route --remove ABC:DEF', + desc: '5. Delete route (ABC:DEF - source microservice id : dest microservice id)', + example: '$ iofog-controller microservice route-remove --route ABC:DEF', }, { - desc: '6. Create port mapping (internal:external:publicMode)', - example: '$ iofog-controller microservice port-mapping --create 80:8080:false -i ABC' + desc: '6. Create port mapping (80:8080:false - internal port : external port : public mode, ABC - microservice)', + example: '$ iofog-controller microservice port-mapping-create --mapping 80:8080:false -i ABC' }, { - desc: '7. Delete port mapping (internal)', - example: '$ iofog-controller microservice port-mapping --delete 80 -i ABC' + desc: '7. Delete port mapping (80 - internal port, ABC - microservice id)', + example: '$ iofog-controller microservice port-mapping-remove --internal-port 80 -i ABC' } ], }, @@ -254,75 +263,67 @@ class Microservice extends BaseCLIHandler { } } -const _executeCase = async function (microserviceCommand, commandName, f, isUserRequired) { +const _executeCase = async function (microserviceCommand, commandName, f) { try { const item = microserviceCommand[commandName] || {}; - - if (isUserRequired) { - const decoratedFunction = AuthDecorator.prepareUserById(f); - await decoratedFunction(item); - } else { - await f(item); - } + await f(item); } catch (error) { logger.error(error.message); } }; -const _executeRouteCommand = async function (obj) { +const _createRoute = async function (obj) { logger.info(JSON.stringify(obj)); - if (obj.add) { - try { - const arr = obj.add.split(':'); - const sourceMicroserviceId = arr[0]; - const destMicroserviceId = arr[1]; - await MicroserviceService.createRouteWithTransaction(sourceMicroserviceId, destMicroserviceId, {}, true); - logger.info(`Microservice route with source microservice ${sourceMicroserviceId} and dest microservice + try { + const arr = obj.route.split(':'); + const sourceMicroserviceId = arr[0]; + const destMicroserviceId = arr[1]; + await MicroserviceService.createRouteWithTransaction(sourceMicroserviceId, destMicroserviceId, {}, true); + logger.info(`Microservice route with source microservice ${sourceMicroserviceId} and dest microservice ${destMicroserviceId} has been created successfully.`) - } catch (e) { - logger.error(ErrorMessages.CLI.INVALID_ROUTE); - } - } else if (obj.remove) { - try { - const arr = obj.add.split(':'); - const sourceMicroserviceId = arr[0]; - const destMicroserviceId = arr[1]; - await MicroserviceService.deleteRouteWithTransaction(sourceMicroserviceId, destMicroserviceId, {}, true); - logger.info(`Microservice route with source microservice ${obj.sourceMicroserviceId} and dest microservice + } catch (e) { + logger.error(ErrorMessages.CLI.INVALID_ROUTE); + } +}; + +const _removeRoute = async function (obj) { + logger.info(JSON.stringify(obj)); + try { + const arr = obj.route.split(':'); + const sourceMicroserviceId = arr[0]; + const destMicroserviceId = arr[1]; + await MicroserviceService.deleteRouteWithTransaction(sourceMicroserviceId, destMicroserviceId, {}, true); + logger.info(`Microservice route with source microservice ${obj.sourceMicroserviceId} and dest microservice ${obj.destMicroserviceId} has been removed successfully.`); - } catch (e) { - logger.error(ErrorMessages.CLI.INVALID_ROUTE); - } - } else if (obj.add && obj.remove) { - logger.info('Please specify either "add" or "remove" operation'); - } else { - logger.info('No operation specified'); + } catch (e) { + logger.error(ErrorMessages.CLI.INVALID_ROUTE); } }; -const _executePortMappingCommand = async function (obj) { +const _createPortMapping = async function (obj) { logger.info(JSON.stringify(obj)); + const mapping = parsePortMappingObject(obj.mapping, ErrorMessages.CLI.INVALID_PORT_MAPPING); + await MicroserviceService.createPortMappingWithTransaction(obj.microserviceId, mapping, {}, true); + logger.info('Port mapping has been create successfully'); +}; - if (obj.create) { - const mapping = parsePortMappingObject(obj.create, ErrorMessages.CLI.INVALID_PORT_MAPPING); - await MicroserviceService.createPortMappingWithTransaction(obj.microserviceId, mapping, {}, true); - logger.info('Port mapping has been create successfully'); - } else if (obj.delete) { - try { - const internalPort = parseInt(obj.delete); - await MicroserviceService.deletePortMappingWithTransaction(obj.microserviceId, internalPort, {}, true); - logger.info('Port mapping has been deleted successfully'); - } catch(e) { - logger.error(ErrorMessages.CLI.INVALID_INTERNAL_PORT); - } - } else if (obj.list) { - await MicroserviceService.getMicroservicePortMappingListWithTransaction(obj.microserviceId, {}, true); - logger.info('Port mappings have been retrieved successfully'); - } else { - logger.info('Incorrect command usage. Please specify only one command at once'); +const _removePortMapping = async function (obj) { + logger.info(JSON.stringify(obj)); + try { + const internalPort = parseInt(obj.internalPort); + await MicroserviceService.deletePortMappingWithTransaction(obj.microserviceId, internalPort, {}, true); + logger.info('Port mapping has been deleted successfully'); + } catch(e) { + logger.error(ErrorMessages.CLI.INVALID_INTERNAL_PORT); } }; +const _listPortMappings = async function (obj) { + const result = await MicroserviceService.getMicroservicePortMappingListWithTransaction(obj.microserviceId, {}, true); + logger.info(JSON.stringify(result)); + logger.info('Port mappings have been retrieved successfully'); +}; + const _removeMicroservice = async function (obj) { logger.info(JSON.stringify(obj)); await MicroserviceService.deleteMicroserviceWithTransaction(obj.microserviceId, obj.cleanUp, {}, true); @@ -331,7 +332,7 @@ const _removeMicroservice = async function (obj) { const _listMicroservices = async function () { const result = await MicroserviceService.listMicroservicesWithTransaction({}, {}, true); - logger.info(JSON.stringify(result, null, 2)); + logger.info(JSON.stringify(result)); logger.info('Microservices have been retrieved successfully.'); }; diff --git a/src/helpers/constants.js b/src/helpers/constants.js index 58964cbbe..3e7eee6d1 100644 --- a/src/helpers/constants.js +++ b/src/helpers/constants.js @@ -36,8 +36,11 @@ module.exports = { CMD_CATALOG: 'catalog', CMD_FLOW: 'flow', CMD_MICROSERVICE: 'microservice', - CMD_ROUTE: 'route', - CMD_PORT_MAPPING: 'port-mapping', + CMD_ROUTE_CREATE: 'route-create', + CMD_ROUTE_REMOVE: 'route-remove', + CMD_PORT_MAPPING_CREATE: 'port-mapping-create', + CMD_PORT_MAPPING_REMOVE: 'port-mapping-remove', + CMD_PORT_MAPPING_LIST: 'port-mapping-list', CMD_REGISTRY: 'registry', CMD_ACTIVATE: 'activate', CMD_SUSPEND: 'suspend', diff --git a/src/sequelize/managers/flow-manager.js b/src/sequelize/managers/flow-manager.js index d993044d3..798d9aa66 100644 --- a/src/sequelize/managers/flow-manager.js +++ b/src/sequelize/managers/flow-manager.js @@ -14,12 +14,30 @@ const BaseManager = require('./base-manager'); const models = require('./../models'); const Flow = models.Flow; +const Microservice = models.Microservice; +const sequelize = require('sequelize'); class FlowManager extends BaseManager { getEntity() { return Flow } + + async findFlowMicroservices(where, transaction) { + return Flow.findOne({ + include: [ + { + model: Microservice, + as: 'microservice', + required: false, + attributes: ['iofogUuid'] + } + ], + where: where, + attributes: ['id'] + }, {transaction: transaction}) + } } + const instance = new FlowManager(); module.exports = instance; \ No newline at end of file diff --git a/src/services/flow-service.js b/src/services/flow-service.js index aa70d1041..9bd5bca6e 100644 --- a/src/services/flow-service.js +++ b/src/services/flow-service.js @@ -17,13 +17,14 @@ const AppHelper = require('../helpers/app-helper'); const Errors = require('../helpers/errors'); const ErrorMessages = require('../helpers/error-messages'); const Validation = require('../schemas'); -const MicroserviceService = require('./microservices-service') +// const MicroserviceService = require('./microservices-service') const ChangeTrackingManager = require('../sequelize/managers/change-tracking-manager') const _createFlow = async function (flowData, user, isCLI, transaction) { await Validation.validate(flowData, Validation.schemas.flowCreate); await isFlowExist(flowData.name, transaction); + await _checkForDuplicateName(flowData.name, {}, transaction); const flowToCreate = { name: flowData.name, @@ -56,65 +57,59 @@ const _deleteFlow = async function (flowId, user, isCLI, transaction) { }; const _updateFlow = async function (flowData, flowId, user, isCLI, transaction) { - await Validation.validate(flowData, Validation.schemas.flowUpdate); + await Validation.validate(flowData, Validation.schemas.flowUpdate); - const oldFlow = await _getFlow(flowId, user, isCLI, transaction); + const oldFlow = await _getFlow(flowId, user, isCLI, transaction); + if (!oldFlow) { + throw new Errors.NotFoundError(ErrorMessages.INVALID_FLOW_ID) + } + if (flowData.name) { + await _checkForDuplicateName(flowData.name, flowId, transaction); + } - if (!oldFlow) { - throw new Errors.NotFoundError(ErrorMessages.INVALID_FLOW_ID) - } - if (flowData.name !== undefined) { - await isFlowExist(flowData.name, transaction); - } + const flow = { + name: flowData.name, + description: flowData.description, + isActivated: flowData.isActivated, + updatedBy: user.id + }; - const flow = { - name: flowData.name, - description: flowData.description, - isActivated: flowData.isActivated, - updatedBy: user.id - }; - - const updateFlowData = AppHelper.deleteUndefinedFields(flow); - - const where = isCLI ? - { - id: flowId - } - : - { - id: flowId, - userId: user.id + const updateFlowData = AppHelper.deleteUndefinedFields(flow); + + const where = isCLI + ? {id: flowId} + : {id: flowId, userId: user.id}; + + await FlowManager.update(where, updateFlowData, transaction); + + if (oldFlow.isActivated !== flowData.isActivated) { + const flowWithMicroservices = await FlowManager.findFlowMicroservices({id: flowId}, transaction); + const onlyUnique = (value, index, self) => self.indexOf(value) === index; + const iofogUuids = flowWithMicroservices.microservice + .map(obj => obj.iofogUuid) + .filter(onlyUnique) + .filter(val => val !== null); + for (let iofogUuid of iofogUuids) { + const updateChangeTrackingData = { + containerConfig: true, + containerList: true, + routing: true }; - - await FlowManager.update(where, updateFlowData, transaction); - - //TODO: simplify. use manager's join query - if (oldFlow.isActivated !== flowData.isActivated) { - const msList = await MicroserviceService.getListMicroservices({flowId: flowId}, user, isCLI, transaction) - for (const ms of msList) { - const updateChangeTrackingData = { - containerConfig: true, - containerList: true, - routing: true - } - await ChangeTrackingManager.update({iofogUuid: ms.iofogUuid}, updateChangeTrackingData, transaction); - } + await ChangeTrackingManager.update({iofogUuid: iofogUuid}, updateChangeTrackingData, transaction); } + } }; const _getFlow = async function (flowId, user, isCLI, transaction) { - const whereObj = { - id: flowId, - userId: user.id - }; - const where = AppHelper.deleteUndefinedFields(whereObj); + const where = isCLI + ? {id: flowId} + : {id: flowId, userId: user.id}; const flow = await FlowManager.findOne(where, transaction); if (!flow) { throw new Errors.NotFoundError(AppHelper.formatMessage(ErrorMessages.INVALID_FLOW_ID, flowId)) } - return flow }; @@ -130,13 +125,16 @@ const _getAllFlows = async function (isCLI, transaction) { return await FlowManager.findAll({}, transaction); }; -const isFlowExist = async function (flowName, transaction) { - const flow = await FlowManager.findOne({ - name: flowName - }, transaction); +const _checkForDuplicateName = async function (name, item, transaction) { + if (name) { + const where = item.id + ? {name: name, id: {[Op.ne]: item.id}} + : {name: name}; - if (flow) { - throw new Errors.ValidationError(AppHelper.formatMessage(ErrorMessages.DUPLICATE_NAME, flowName)); + const result = await FlowManager.findOne(where, transaction); + if (result) { + throw new Errors.DuplicatePropertyError(AppHelper.formatMessage(ErrorMessages.DUPLICATE_NAME, name)); + } } }; diff --git a/src/services/microservices-service.js b/src/services/microservices-service.js index 910a56555..de0ce38bc 100644 --- a/src/services/microservices-service.js +++ b/src/services/microservices-service.js @@ -19,17 +19,16 @@ const ConnectorManager = require('../sequelize/managers/connector-manager'); const ConnectorPortManager = require('../sequelize/managers/connector-port-manager'); const MicroservicePublicModeManager = require('../sequelize/managers/microservice-public-mode-manager'); const ChangeTrackingManager = require('../sequelize/managers/change-tracking-manager'); -const FlowService = require('../services/flow-service'); const IoFogService = require('../services/iofog-service'); const AppHelper = require('../helpers/app-helper'); const Errors = require('../helpers/errors'); const ErrorMessages = require('../helpers/error-messages'); const Validation = require('../schemas/index'); const ConnectorService = require('../services/connector-service'); +const FlowService = require('../services/flow-service'); const CatalogService = require('../services/catalog-service'); const RoutingManager = require('../sequelize/managers/routing-manager'); const Op = require('sequelize').Op; -const Sequelize = require('sequelize'); const _listMicroservices = async function (flowId, user, isCLI, transaction) { if (!isCLI) { @@ -103,7 +102,7 @@ const _createMicroserviceOnFog = async function (microserviceData, user, isCLI, const _createMicroservice = async function (microserviceData, user, isCLI, transaction) { - const microserviceToCreate = { + let newMicroservice = { uuid: AppHelper.generateRandomString(32), name: microserviceData.name, config: microserviceData.config, @@ -115,20 +114,20 @@ const _createMicroservice = async function (microserviceData, user, isCLI, trans updatedBy: user.id }; - const microserviceDataCreate = AppHelper.deleteUndefinedFields(microserviceToCreate); + newMicroservice = AppHelper.deleteUndefinedFields(newMicroservice); - await _checkForDuplicateName(microserviceDataCreate.name, {}, transaction); + await _checkForDuplicateName(newMicroservice.name, {}, transaction); //validate catalog item - await CatalogService.getCatalogItem(microserviceDataCreate.catalogItemId, user, isCLI, transaction); + await CatalogService.getCatalogItem(newMicroservice.catalogItemId, user, isCLI, transaction); //validate flow - await FlowService.getFlow(microserviceDataCreate.flowId, user, isCLI, transaction); + await FlowService.getFlow(newMicroservice.flowId, user, isCLI, transaction); //validate fog node - if (microserviceDataCreate.iofogUuid) { - await IoFogService.getFog({uuid: microserviceDataCreate.iofogUuid}, user, isCLI, transaction); + if (newMicroservice.iofogUuid) { + await IoFogService.getFog({uuid: newMicroservice.iofogUuid}, user, isCLI, transaction); } - return await MicroserviceManager.create(microserviceDataCreate, transaction); + return await MicroserviceManager.create(newMicroservice, transaction); }; const _createMicroservicePorts = async function (ports, microserviceUuid, transaction) {