js/topology/deploy/topology_deploy_local_node.js
// NPM IMPORTS
import assert from 'assert'
import _ from 'lodash'
// COMMON IMPORTS
import T from '../../utils/types'
import TopologyDeployItem from './topology_deploy_item'
const context = 'common/topology/deploy/topology_deploy_local_node'
/**
* TopologyDeployLocalNode class.
*
* @author Luc BORIES
* @license Apache-2.0
*
* @example
* API:
* this.deployed_tenants[deployed_tenant_name] =
* name:deployed_tenant_name, // String
* tenant:defined_tenant, // TopologyDefineTenant instance
* services:
* svc_name:svc // TopologyDefinedService instance
* applications:
* app_name:
* name:app_name, // String
* tenant:defined_tenant, // TopologyDefineTenant instance
* appplication:defined_app, // TopologyDefinedApplication instance
* services:
* svc_name:svc // TopologyDefinedService instance
* assets:
* ... // See TopologyDefinedApplication instance assets
*
*/
export default class TopologyDeployLocalNode extends TopologyDeployItem
{
/**
* Create a TopologyDeployNode instance.
*
* @param {string} arg_name - instance name.
* @param {TopologyDefineItem} arg_definition_item - topology definition item.
* @param {object} arg_settings - instance settings map.
* @param {object} arg_deploy_factory - factory object { create(type, name, settings) { return TopologyDeployItem } }
* @param {string} arg_log_context - trace context string.
*
* @returns {nothing}
*/
constructor(arg_name, arg_definition_item, arg_settings, arg_deploy_factory, arg_log_context)
{
const log_context = arg_log_context ? arg_log_context : context
super(arg_name, arg_definition_item, arg_settings, 'TopologyDeployLocalNode', log_context)
assert( T.isObject(arg_definition_item) && arg_definition_item.is_topology_define_node, context + ':constructor:bad node topology definition object')
assert( T.isObject(arg_deploy_factory), context + ':constructor:bad factory object')
assert( T.isFunction(arg_deploy_factory.create), context + ':constructor:bad factory.create function')
this.is_topology_deploy_local_node = true
this.topology_type = 'local_nodes'
this.deployed_factory = arg_deploy_factory
this.deployed_tenants = {}
this.info('Local Node is created')
}
/**
* Get deployed tenants.
*
* @returns {array} - deployed tenants.
*/
get_deployed_tenants_names()
{
this.enter_group('get_deployed_tenants')
const tenants = Object.keys(this.deployed_tenants)
this.leave_group('get_deployed_tenants')
return tenants
}
/**
* Get deployed tenant informations.
*
* @param {string} arg_tenant_name - tenant name.
*
* @returns {object} - deployed tenant infos.
*/
get_deployed_tenant_topology(arg_tenant_name)
{
this.enter_group('get_deployed_tenant_topology')
// CHECK TENANT NAME
if (! this.deployed_tenants || ! (arg_tenant_name in this.deployed_tenants) )
{
this.leave_group('get_deployed_tenant_topology:tenant not found')
return undefined
}
const deployed_tenant_topology = this.deployed_tenants[arg_tenant_name]
if (! deployed_tenant_topology)
{
this.leave_group('get_deployed_tenant_topology:bad tenant topology')
return undefined
}
this.leave_group('get_deployed_tenant_topology')
return deployed_tenant_topology
}
/**
* Get deployed tenants informations.
*
* @param {boolean} arg_deep - get deep sub items information on true (default:true).
*
* @returns {object} - deployed tenant infos.
*/
get_deployed_tenants_infos(arg_deep=true)
{
this.enter_group('get_deployed_tenants_infos')
const deployed_tenants_infos = {}
_.forEach(this.deployed_tenants,
(deployed_tenant_topology, tenant_name)=>{
if (! deployed_tenant_topology)
{
this.leave_group('get_deployed_tenants_infos:bad tenant topology')
return undefined
}
const tenant = deployed_tenant_topology.tenant
if (! tenant)
{
this.leave_group('get_deployed_tenants_infos:bad tenant instance')
return undefined
}
deployed_tenants_infos[tenant_name] = tenant.get_topology_info(arg_deep)
}
)
this.leave_group('get_deployed_tenants_infos')
return deployed_tenants_infos
}
/**
* Get deployed tenant informations.
*
* @param {string} arg_tenant_name - tenant name.
* @param {boolean} arg_deep - get deep sub items information on true (default:true).
*
* @returns {object} - deployed tenant infos.
*/
get_deployed_tenant_infos(arg_tenant_name, arg_deep=true)
{
this.enter_group('get_deployed_tenant_infos')
const deployed_tenant_topology = this.get_deployed_tenant_topology(arg_tenant_name)
if (! deployed_tenant_topology)
{
this.leave_group('get_deployed_tenant_infos:bad tenant topology')
return undefined
}
const tenant = deployed_tenant_topology.tenant
if (! tenant)
{
this.leave_group('get_deployed_tenant_infos:bad tenant instance')
return undefined
}
this.leave_group('get_deployed_tenant_infos')
return tenant.get_topology_info(arg_deep)
}
/**
* Get deployed tenant applications names.
*
* @param {string} arg_tenant_name - tenant name.
*
* @returns {array} - deployed tenant applications names.
*/
get_deployed_tenant_applications_names(arg_tenant_name)
{
this.enter_group('get_deployed_tenant_applications_names')
const deployed_tenant_topology = this.get_deployed_tenant_topology(arg_tenant_name)
if (! deployed_tenant_topology)
{
this.leave_group('get_deployed_tenant_applications_names:bad tenant topology')
return undefined
}
const apps_names = Object.keys(deployed_tenant_topology.applications)
this.leave_group('get_deployed_tenant_applications_names')
return apps_names
}
/**
* Get deployed tenant applications infos.
*
* @param {string} arg_tenant_name - tenant name.
* @param {boolean} arg_deep - get deep sub items information on true (default:true).
*
* @returns {object} - deployed tenant applications infos.
*/
get_deployed_tenant_applications_infos(arg_tenant_name, arg_deep=true)
{
this.enter_group('get_deployed_tenant_applications_infos')
const deployed_tenant_topology = this.get_deployed_tenant_topology(arg_tenant_name)
if (! deployed_tenant_topology)
{
this.leave_group('get_deployed_tenant_applications_infos:bad tenant topology')
return undefined
}
const apps_infos = {}
_.forEach(deployed_tenant_topology.applications,
(app, app_name)=>{
apps_infos[app_name] = app.get_topology_info(arg_deep)
}
)
this.leave_group('get_deployed_tenant_applications_infos')
return apps_infos
}
/**
* Get deployed tenant services names.
*
* @param {string} arg_tenant_name - tenant name.
*
* @returns {array} - deployed tenant services names.
*/
get_deployed_tenant_services_names(arg_tenant_name)
{
this.enter_group('get_deployed_tenant_services_names')
const deployed_tenant_topology = this.get_deployed_tenant_topology(arg_tenant_name)
if (! deployed_tenant_topology)
{
this.leave_group('get_deployed_tenant_services_names:bad tenant topology')
return undefined
}
const services_names = Object.keys(deployed_tenant_topology.services)
this.leave_group('get_deployed_tenant_services_names')
return services_names
}
/**
* Get deployed tenant services infos.
*
* @param {string} arg_tenant_name - tenant name.
* @param {boolean} arg_deep - get deep sub items information on true (default:true).
*
* @returns {object} - deployed tenant services infos.
*/
get_deployed_tenant_services_infos(arg_tenant_name, arg_deep=true)
{
this.enter_group('get_deployed_tenant_services_infos')
const deployed_tenant_topology = this.get_deployed_tenant_topology(arg_tenant_name)
if (! deployed_tenant_topology)
{
this.leave_group('get_deployed_tenant_services_infos:bad tenant topology')
return undefined
}
const svcs_infos = {}
_.forEach(deployed_tenant_topology.services,
(svc, svc_name)=>{
svcs_infos[svc_name] = svc.get_topology_info(arg_deep)
svcs_infos[svc_name].operations = svc.get_a_provider().get_operations_names()
}
)
this.leave_group('get_deployed_tenant_services_infos')
return svcs_infos
}
/**
* Get deployed tenant services infos.
*
* @param {string} arg_tenant_name - tenant name.
* @param {string} arg_svc_name - service name.
* @param {boolean} arg_deep - get deep sub items information on true (default:true).
*
* @returns {object} - deployed tenant services infos.
*/
get_deployed_tenant_service_infos(arg_tenant_name, arg_svc_name, arg_deep=true)
{
this.enter_group('get_deployed_tenant_service_infos')
const deployed_tenant_topology = this.get_deployed_tenant_topology(arg_tenant_name)
if (! deployed_tenant_topology)
{
this.leave_group('get_deployed_tenant_service_infos:bad tenant topology')
return undefined
}
if (arg_svc_name in deployed_tenant_topology.services)
{
const svc = deployed_tenant_topology.services[arg_svc_name]
const svc_infos = svc.get_topology_info(arg_deep)
svc_infos.operations = svc.get_a_provider().get_operations_names()
this.leave_group('get_deployed_tenant_service_infos')
return svc_infos
}
this.leave_group('get_deployed_tenant_service_infos:service not found for [' + arg_svc_name + ']')
return undefined
}
/**
* Get deployed nodes names.
*
* @returns {array} - nodes names.
*/
get_deployed_nodes_names()
{
this.enter_group('get_deployed_nodes_names')
const defined_node = this.get_topology_definition_item()
const defined_world = defined_node.get_topology_owner()
const nodes = defined_world.nodes()
const nodes_names = nodes.get_all_names()
this.leave_group('get_deployed_nodes_names')
return nodes_names
}
/**
* Find a deployed service in tenants services.
*
* @param {string} arg_svc_name - service name.
*
* @returns {Service} - deployed service instance.
*/
find_deployed_service(arg_svc_name)
{
this.enter_group('find_deployed_service')
this.debug('find_deployed_service', 'service', arg_svc_name)
// LOOP ON TENANTS
const tenants_names = this.get_deployed_tenants_names()
for(const tenant_name of tenants_names)
{
const svc = this.get_deployed_service(tenant_name, arg_svc_name)
if (svc && svc.is_service)
{
this.debug('find_deployed_service', 'tenant', tenant_name)
this.leave_group('find_deployed_service:found')
return svc
}
}
this.leave_group('find_deployed_service:not found')
return undefined
}
/**
* Get or create a deployed service.
*
* @param {string} arg_tenant_name - tenant name.
* @param {string} arg_svc_name - service name.
*
* @returns {Service} - deployed service instance.
*/
get_deployed_service(arg_tenant_name, arg_svc_name)
{
this.enter_group('get_deployed_service')
this.debug('get_deployed_service', 'tenant', arg_tenant_name)
this.debug('get_deployed_service', 'service', arg_svc_name)
// GET TENANT
const defined_node = this.get_topology_definition_item()
const defined_world = defined_node.get_topology_owner()
const defined_tenant = defined_world.tenant(arg_tenant_name)
assert( T.isObject(defined_tenant) && defined_tenant.is_topology_define_tenant, context + ':get_deployed_service:bad tenant object for [' + arg_tenant_name + ']')
// GET TENANT DEPLOYMENT
if (! T.isObject(this.deployed_tenants[arg_tenant_name]) )
{
this.deployed_tenants[arg_tenant_name] = {
name:arg_tenant_name,
tenant:defined_tenant,
services:{},
applications:{}
}
}
const deployed_tenant = this.deployed_tenants[arg_tenant_name]
// SERVICE IS ALREADY DEPLOYED ON TENANT
if (arg_svc_name in deployed_tenant.services)
{
this.leave_group('get_deployed_service (already deployed)')
return deployed_tenant.services[arg_svc_name]
}
// GET SERVICE DEFINITION
const defined_service = defined_tenant.get_service(arg_svc_name)
this.debug('get_deployed_service:defined_service', defined_service)
if (! defined_service)
{
this.error(context + ':get_deployed_service:definition not found for service [' + arg_svc_name + '] for tenant [' + arg_tenant_name + ']')
this.leave_group('get_deployed_service (error)')
return undefined
}
this.debug('get_deployed_service:defined service found [' + arg_svc_name + ']')
// CREATE SERVICE
let service = undefined
const settings = defined_service.get_settings()
service = this.deployed_factory.create('service', arg_svc_name, settings)
if (! service)
{
this.error(context + ':get_deployed_service:creation failed for service [' + arg_svc_name + '] for tenant [' + arg_tenant_name + ']')
this.leave_group('get_deployed_service (error)')
return undefined
}
this.debug('get_deployed_service:service instance created [' + arg_svc_name + '] for tenant [' + arg_tenant_name + ']')
// ENABLE SERVICE
service.enable()
this.debug('get_deployed_service:service is enabled')
this.deployed_tenants[arg_tenant_name].services[arg_svc_name] = service
this.leave_group('get_deployed_service')
return service
}
/**
* Deploy defined topology on this local node.
*
* @returns {Promise} - Promise(boolean)
*/
deploy()
{
this.enter_group('deploy')
const defined_world = this.get_topology_definition_item().get_topology_owner()
// LOOP ON TENANTS TO DEPLOY
const deployed_tenants = this.get_settings().toJS()
_.forEach(deployed_tenants,
(deployed_apps, deployed_tenant_name)=>{
// SKIP SPECIAL CASES
if (deployed_tenant_name == 'runtime' || deployed_tenant_name == 'logger_manager')
{
return
}
this.info('deploy:loop on tenant:' + deployed_tenant_name)
// GET DEFINED TENANT
const defined_tenant = defined_world.tenant(deployed_tenant_name)
if (! defined_tenant)
{
this.leave_group('deploy (error):bad tenant for ' + deployed_tenant_name)
return Promise.reject('deploy:tenant ' + deployed_tenant_name + ' not found for world')
}
// INIT TENANT
this.deployed_tenants[deployed_tenant_name] = {
name:deployed_tenant_name,
tenant:defined_tenant,
services:{},
applications:{}
}
// LOOP ON APPLICATIONS TO DEPLOY
// const deployed_apps = deployed_tenants[deployed_tenant_name]
_.forEach(deployed_apps,
(deployed_app, deployed_app_name)=>{
this.info('deploy:loop on application:' + deployed_app_name)
// GET DEFINED APPLICATION
const defined_app = defined_tenant.application(deployed_app_name)
if (! defined_app)
{
this.leave_group('deploy (error):bad application for ' + deployed_app_name)
return Promise.reject('deploy:application ' + deployed_app_name + ' not found for tenant ' + deployed_tenant_name)
}
// INIT TENANT APPLICATION
const deployed_app_topology = {
name:deployed_app_name,
tenant:defined_tenant,
application:defined_app,
services:{},
assets:{}
}
// LOOP ON APPLICATION SERVICES TO DEPLOY
const deployed_app_services = deployed_app.services
_.forEach(deployed_app_services,
(deployed_app_svc, deployed_svc_name)=>{
this.info('deploy:loop on service:' + deployed_svc_name)
// const deployed_app_svc = deployed_app_services[deployed_svc_name]
const service = this.get_deployed_service(deployed_tenant_name, deployed_svc_name)
if (! service || ! service.is_service)
{
this.error('deploy:services:service not found [' + deployed_svc_name + '] for tenant [' + deployed_tenant_name + ']')
return
}
// LOOP ON DEPLOYED APPLICATION SERVICE SERVERS
service.activate(defined_app, deployed_app_svc)
service.enable()
deployed_app_topology.services[deployed_svc_name] = service
this.deployed_tenants[deployed_tenant_name].services[deployed_svc_name] = service
}
)
// LOOP ON APPLICATION ASSETS TO DEPLOY
let deployed_assets = {}
const deployed_app_assets = deployed_apps[deployed_app_name].assets
assert( T.isObject(deployed_app_assets), context + ':deploy:bad assets object')
if ( T.isObject(deployed_app_assets.regions) )
{
assert( T.isObject(deployed_app_assets.regions), context + ':deploy:bad assets.regions object')
_.forEach(deployed_app_assets.regions,
(deployed_region, deployed_region_name)=>{
this.info('deploy:loop on assets region:' + deployed_region_name)
// const deployed_region = deployed_app_assets.regions[deployed_region_name]
assert( T.isObject(deployed_region), context + ':deploy:bad assets.regions.* object for region ' + deployed_region_name)
const style_svc_array = T.isArray(deployed_region.style) ? deployed_region.style : []
const script_svc_array = T.isArray(deployed_region.script) ? deployed_region.script : []
const image_svc_array = T.isArray(deployed_region.image) ? deployed_region.image : []
const html_svc_array = T.isArray(deployed_region.html) ? deployed_region.html : []
deployed_assets[deployed_region_name] = {
style:style_svc_array,
script:script_svc_array,
image:image_svc_array,
html:html_svc_array
}
}
)
}
deployed_app_topology.assets = deployed_app_assets
this.deployed_tenants[deployed_tenant_name].applications[deployed_app_name] = deployed_app_topology
// REGISTER ASSETS ON DEPLOYED SERVICES
_.forEach(deployed_app_services,
(service_cfg, svc_name)=>{
const service = this.deployed_tenants[deployed_tenant_name].services[svc_name]
if (! service || ! service.is_service)
{
this.error('deploy:assets:service not found [' + svc_name + '] for tenant [' + deployed_tenant_name + ']')
return
}
service.topology_deploy_assets = deployed_assets
}
)
}
)
}
)
this.leave_group('deploy')
return Promise.resolve(true)
}
}