k2hr3-app
Version:
K2HR3 Web Application is K2hdkc based Resource and Roles and policy Rules
528 lines (475 loc) • 15.3 kB
JavaScript
/*
*
* K2HR3 Web Application
*
* Copyright 2017 Yahoo Japan Corporation.
*
* K2HR3 is K2hdkc based Resource and Roles and policy Rules, gathers
* common management information for the cloud.
* K2HR3 can dynamically manage information as "who", "what", "operate".
* These are stored as roles, resources, policies in K2hdkc, and the
* client system can dynamically read and modify these information.
*
* For the full copyright and license information, please view
* the license file that was distributed with this source code.
*
* AUTHOR: Takeshi Nakatani
* CREATE: Thu Sep 7 2017
* REVISION:
*
*/
'use strict';
var path = require('path');
var rotatefs = require('rotating-file-stream'); // [NOTICE] rotating-file-stream is using fsevents optionally.
var r3util = require('./libr3util');
//---------------------------------------------------------
// load configuration for API
//---------------------------------------------------------
var loadedConfig = (function()
{
var config = require('config');
var data = {
scheme: 'http', // This nodejs server scheme
port: 80, // This nodejs server port
multiproc: true, // Run multi processes mode
runuser: '', // User for process owner
privatekey: '', // Private key path for https
cert: '', // Certification file path for https
ca: '', // CA path for https
logdir: null, // Path for logging directory
fixedlogdir: null, // Fixed log directory
accesslogname: 'access.log', // Access log name
accesslogform: 'combined', // Access log format by morgan
consolelogname: null, // Console(Error) log name
logrotateopt: { // rotating-file-stream option object
compress: 'gzip', // gzip : compression method of rotated files.
interval: '6h', // 6 hour : the time interval to rotate the file.
initialRotation: true, // true : initial rotation based on not-rotated file timestamp.
path: null // null : the base path for files.(* this value is replace by 'logdir')
/*
* [NOTE] following option is not specified now.
*
rotationTime: true, // true : makes rotated file name with time of rotation.
highWaterMark: null, // null : proxied to new stream.
history: null, // null : the history filename.
immutable: null, // null : never mutates file names.
maxFiles: null, // null : the maximum number of rotated files to keep.
maxSize: null, // null : the maximum size of rotated files to keep.
mode: null, // null : proxied to fs.createWriteStream
rotate: null, // null : enables the classical UNIX logrotate behaviour.
size: null // null : the file size to rotate the file.
*/
},
apihost: 'localhost', // API host
apischeme: 'http', // API scheme
apiport: 3001, // API port
userdata: '', // User Data Script for OpenStack
secretyaml: '', // Secret Yaml for kubernetes
sidecaryaml: '', // Sidecar Yaml for kubernetes
crcobj: {}, // Custom Registration Codes(CRC) object
appmenu: null, // The menu array for application
validator: 'userValidateCredential', // Validator object module
validobj: null, // Generated(required) validator object module
rejectUnauthorized: true, // reject mode
uselocaltenant: true, // Use Local Tenant
lang: 'en', // Language for javascript application
extrouter: { // Configuration of Router module to be expanded
/*
* [NOTE] Define the following objects as an array.
* Define one object for one extended Router.
*
routername: {
name: 'file path', // Specify JS file name(except js extension) for defining Router. The "/router" directory is current.
path: 'route top path', // Specify the router entry path(ex. "/myenter").
config: {} // Specify the configuration required for the extended router. (Value, array, object)
},
...
*/
}
};
if(r3util.isSafeEntity(config)){
var tmp;
// scheme & port
if(r3util.isSafeString(config.scheme)){
data.scheme = r3util.getSafeString(config.scheme);
if('https' === data.scheme.toLowerCase()){
data.port = 443;
}
}
if(r3util.isSafeEntity(config.port)){
tmp = normalizePort(config.port);
if(false !== tmp){
data.port = tmp;
}
}else if(r3util.isSafeEntity(process.env.PORT)){ // Get port from environment
tmp = normalizePort(process.env.PORT);
if(false !== tmp){
data.port = tmp;
}
}
// private key & cert & ca
if(r3util.isSafeString(config.privatekey) || null === config.privatekey){
data.privatekey = r3util.getSafeString(config.privatekey);
}
if(r3util.isSafeString(config.cert) || null === config.cert){
data.cert = r3util.getSafeString(config.cert);
}
if(r3util.isSafeString(config.ca) || null === config.ca){
data.ca = r3util.getSafeString(config.ca);
}
// multi processes
if(r3util.isSafeBoolean(config.multiproc)){
data.multiproc = config.multiproc;
}
// run user
if(r3util.isSafeString(config.runuser) || null === config.runuser){
data.runuser = r3util.getSafeString(config.runuser);
}
// log directory
if(r3util.isSafeString(config.logdir) || null === config.logdir){
data.logdir = r3util.getSafeString(config.logdir);
}
// access log file name
if(r3util.isSafeString(config.accesslogname) || null === config.accesslogname){
data.accesslogname = r3util.getSafeString(config.accesslogname);
}
// access log format
if(r3util.isSafeString(config.accesslogform)){
data.accesslogform = r3util.getSafeString(config.accesslogform);
}
// console(error) log file name
if(r3util.isSafeString(config.consolelogname) || null === config.consolelogname){
data.consolelogname = r3util.getSafeString(config.consolelogname);
}
// log rotation option
if(r3util.isSafeEntity(config.logrotateopt) && 'object' == typeof config.logrotateopt && !r3util.isArray(config.logrotateopt)){
Object.keys(config.logrotateopt).forEach(function(key){
if(r3util.isSafeEntity(config.logrotateopt[key])){
data.logrotateopt[key] = config.logrotateopt[key];
}else{
// [NOTE] Not allow keyname
}
});
}
// api host & scheme & port
if(r3util.isSafeString(config.apihost)){
data.apihost = r3util.getSafeString(config.apihost);
}
if(r3util.isSafeString(config.apischeme)){
data.apischeme = r3util.getSafeString(config.apischeme);
if('https' === data.apischeme.toLowerCase()){
data.apiport= 443;
}
}
if(r3util.isSafeEntity(config.apiport) && !isNaN(config.apiport)){
data.apiport = config.apiport;
}
// User Date Script
if(r3util.isSafeString(config.userdata)){
data.userdata = r3util.getSafeString(config.userdata);
}
// Secret Yaml
if(r3util.isSafeString(config.secretyaml)){
data.secretyaml = r3util.getSafeString(config.secretyaml);
}
// Sidecar Yaml
if(r3util.isSafeString(config.sidecaryaml)){
data.sidecaryaml = r3util.getSafeString(config.sidecaryaml);
}
// Custom Configuration Codes(CRC) object
if(r3util.isSafeEntity(config.crcobj) && 'object' == typeof config.crcobj && !r3util.isArray(config.crcobj)){
Object.keys(config.crcobj).forEach(function(key){
if(r3util.isSafeEntity(config.crcobj[key]) && 'object' == typeof config.crcobj[key]){
data.crcobj[key] = config.crcobj[key];
}else{
// [NOTE] Something wrong object, skip it.
}
});
}
// App menu
if(r3util.isArray(config.appmenu)){
data.appmenu = config.appmenu;
}
// Validator & validobj
if(r3util.isSafeString(config.validator)){
data.validator = r3util.getSafeString(config.validator);
}
data.validobj = require('./' + data.validator);
// Reject mode at unauth
if((r3util.isSafeBoolean(config.rejectunauth) && !config.rejectunauth) || (process.env.NODE_ENV !== 'production')){
data.rejectUnauthorized = false;
}
// Use Local Tenant
if(r3util.isSafeBoolean(config.uselocaltenant)){
data.uselocaltenant = config.uselocaltenant;
}
// Lang
if(r3util.isSafeString(config.lang)){
data.lang = r3util.getSafeString(config.lang).toLowerCase();
}
// Extension Router
if(r3util.isSafeEntity(config.extrouter)){
// copy objects
try{
var tmpstr = JSON.stringify(config.extrouter);
data.extrouter = JSON.parse(tmpstr);
}catch(err){ // eslint-disable-line no-unused-vars
console.error('something wrong extrouter value in configration. then skip this value to load.');
}
}
}
return data;
}());
//
// Normalize a port into a number, string, or false.
//
function normalizePort(val)
{
var port = parseInt(val, 10);
if(isNaN(port)){
// named pipe
if(!r3util.isSafeString(val)){
return false;
}
return val;
}
if(0 <= port){
// port number
return port;
}
return false;
}
//---------------------------------------------------------
// Configuration Class
//---------------------------------------------------------
var R3AppConfig = (function()
{
//
// Constructor
//
var R3AppConfig = function()
{
this.loadedConfig = loadedConfig;
this.consolelog = null;
};
var proto = R3AppConfig.prototype;
//
// Methods
//
proto.getScheme = function()
{
return this.loadedConfig.scheme;
};
proto.getPort = function()
{
return this.loadedConfig.port;
};
proto.isMultiProc = function()
{
return this.loadedConfig.multiproc;
};
proto.getRunUser = function()
{
return this.loadedConfig.runuser;
};
proto.getPrivateKey = function()
{
return this.loadedConfig.privatekey;
};
proto.getCert = function()
{
return this.loadedConfig.cert;
};
proto.getCA = function()
{
return this.loadedConfig.ca;
};
proto.updateLogDir = function(basepath)
{
var dirpath = null;
if(null !== this.loadedConfig.logdir){
if(0 === this.loadedConfig.logdir.indexOf('/')){
dirpath = path.join(this.loadedConfig.logdir); // logdir is full path
}else{
if(r3util.isSafeString(basepath)){
if(0 === basepath.indexOf('/')){
dirpath = path.join(basepath, this.loadedConfig.logdir);
}else{
dirpath = path.join(__dirname, '../..', basepath, this.loadedConfig.logdir);// from top directory
}
}else{
dirpath = path.join(__dirname, '../..', this.loadedConfig.logdir); // from top directory
}
}
}else{
// logdir is null, it means not putting log to file.
}
// update log directory
this.loadedConfig.fixedlogdir = dirpath;
if(r3util.isSafeString(dirpath)){
// check log directory and make it if not exists
if(null !== dirpath && !r3util.checkMakeDir(dirpath)){
console.warn('Log directory(' + dirpath + ') is not existed, and could not create it.');
dirpath = null; // continue with no log directory
}else{
// set dir path to log rotation option
this.loadedConfig.logrotateopt['path'] = dirpath;
}
}
return dirpath;
};
proto.getAccessLogName = function()
{
return this.loadedConfig.accesslogname;
};
proto.getAccessLogFormat = function()
{
return this.loadedConfig.accesslogform;
};
proto.getConsoleLogName = function()
{
return this.loadedConfig.consolelogname;
};
proto.getLogRotateOption = function()
{
return this.loadedConfig.logrotateopt;
};
proto.getRotateLogStream = function(basedir, filename)
{
var logstream = null;
var logdir = this.updateLogDir(basedir);
if(null == logdir){
return logstream;
}
if(!r3util.isSafeString(filename)){
return logstream;
}
try{
logstream = rotatefs.createStream(filename, this.loadedConfig.logrotateopt);
}catch(error){
console.warn('Could not create log rotate option by : ' + JSON.stringify(error.message));
logstream = null;
}
return logstream;
};
proto.getMorganLoggerOption = function(basedir)
{
var loggeropt = null;
var logstream = this.getRotateLogStream(basedir, this.loadedConfig.accesslogname);
if(null !== logstream){
loggeropt = {
stream: logstream
};
}
return loggeropt;
};
proto.setConsoleLogging = function(basedir)
{
var logstream = this.getRotateLogStream(basedir, this.loadedConfig.consolelogname);
if(null !== logstream){
this.consolelog = new console.Console(logstream, logstream);
global.console.error= this.consolelog.error;
global.console.warn = this.consolelog.warn;
global.console.log = this.consolelog.log;
global.console.debug= this.consolelog.debug;
global.console.info = this.consolelog.info;
}
return true;
};
proto.getApiHost = function()
{
return this.loadedConfig.apihost;
};
proto.getApiScheme = function()
{
return this.loadedConfig.apischeme;
};
proto.getApiPort = function()
{
return this.loadedConfig.apiport;
};
proto.getUserData = function()
{
return this.loadedConfig.userdata;
};
proto.getSecretYaml = function()
{
return this.loadedConfig.secretyaml;
};
proto.getSidecarYaml = function()
{
// make k2hr3-k8s-init.sh parameters which is built from configuration.
//
var params = '-host ' + this.loadedConfig.apihost + ' -port ' + this.loadedConfig.apiport + ' -schema ' + this.loadedConfig.apischeme;
// repace '{{= %K2HR3_REST_API_HOST% }}' in sidecaryaml
//
// replace keyword in template
var replace = this.loadedConfig.sidecaryaml.replace(/{{= %K2HR3_REST_API_HOST% }}/g, params);
return replace;
};
proto.getCRCObject = function()
{
return this.loadedConfig.crcobj;
};
proto.getAppMenu = function()
{
return this.loadedConfig.appmenu;
};
proto.getUserValidator = function()
{
return this.loadedConfig.validator;
};
proto.getUserValidatorObj = function()
{
return this.loadedConfig.validobj;
};
proto.getRejectUnauthorized = function()
{
return this.loadedConfig.rejectUnauthorized;
};
proto.useLocalTenant = function()
{
return this.loadedConfig.uselocaltenant;
};
proto.getLang = function()
{
return this.loadedConfig.lang;
};
proto.getExtRouter = function(routername)
{
if(r3util.isSafeEntity(routername)){
if(!r3util.isSafeString(routername)){
console.error('routername(' + JSON.stringify(routername) + ') parameter is not empty but not string.');
return null;
}
if(!r3util.isSafeEntity(this.loadedConfig.extrouter)){
console.warn('extrouter configuration does not have router routername(' + JSON.stringify(routername) + ').');
return null;
}
if(!r3util.isSafeEntity(this.loadedConfig.extrouter[routername])){
console.warn('extrouter configuration does not have router routername(' + JSON.stringify(routername) + ').');
return null;
}
return this.loadedConfig.extrouter[routername];
}else{
// return all extrouter object
return this.loadedConfig.extrouter;
}
};
return R3AppConfig;
})();
//---------------------------------------------------------
// Exports
//---------------------------------------------------------
exports.r3AppConfig = R3AppConfig;
// SignIn types
exports.r3SigninUnscopedToken = 'unsopedtoken';
exports.r3SigninCredential = 'credential';
/*
* Local variables:
* tab-width: 4
* c-basic-offset: 4
* End:
* vim600: noexpandtab sw=4 ts=4 fdm=marker
* vim<600: noexpandtab sw=4 ts=4
*/