k2hr3-api
Version:
K2HR3 REST API is K2hdkc based Resource and Roles and policy Rules
313 lines (286 loc) • 10.8 kB
JavaScript
/*
* K2HR3 REST API
*
* Copyright 2018 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: Tue Oct 2 2018
* REVISION:
*
*/
'use strict';
var apiutil = require('./k2hr3apiutil');
var cryptutil = require('./k2hr3cryptutil');
var r3Conf = require('./k2hr3config').r3ApiConfig;
var r3keys = require('./k2hr3keys').getK2hr3Keys;
var apiConf = new r3Conf();
// Debug logging objects
var r3logger = require('./dbglogging');
//---------------------------------------------------------
// Empty script for error
//---------------------------------------------------------
var EmptyScriptContents = [
'#!/bin/sh',
'#',
'# K2HR3 Frontend Web Application',
'#',
'# Copyright(C) 2018 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: Tue Oct 2 2018',
'# REVISION:',
'#',
'',
'SCRIPTNAME="k2hr3-init"',
'LOGFILE="/var/log/${SCRIPTNAME}.log"',
'',
'echo "`date "+%Y-%m-%d %H:%M:%S,%3N"` - ${SCRIPTNAME}[ERROR]: Invalid userdata for creating k2hr3-init script was specified(detail error = {{= %K2HR3_ERROR_MSG% }})" | tee -a ${LOGFILE}',
'exit 1',
'',
'#',
'# VIM modelines',
'#',
'# vim:set ts=4 fenc=utf-8:',
'#'
].join('\n');
//---------------------------------------------------------
// load userdata templates from config directory
//---------------------------------------------------------
var LoadedUserdataTemplates = (function()
{
var templates = {
cloud_config: null,
init_script: null,
init_err_script: null,
kw_role_name: /{{= %K2HR3_ROLE_NAME% }}/g, // Role YRN full path
kw_role_tenant: /{{= %K2HR3_ROLE_TENANT% }}/g, // Tenant YRN full path
kw_role_token: /{{= %K2HR3_ROLE_TOKEN% }}/g, // Role Token
kw_api_uri: /{{= %K2HR3_API_HOST_URI% }}/g, // K2HR3 API server URI(ex. https://localhost:3000)
kw_err_msg: /{{= %K2HR3_ERROR_MSG% }}/g // Error message string when something error occured
};
var userdatacfgobj = apiConf.getUserdataConfig();
if(apiutil.isSafeEntity(userdatacfgobj)){
templates.baseuri = apiutil.getSafeString(userdatacfgobj.baseuri);
templates.algorithm = apiutil.getSafeString(userdatacfgobj.algorithm);
templates.passphrase = apiutil.getSafeString(userdatacfgobj.passphrase);
templates.cloud_config = apiutil.readFileContents(userdatacfgobj.cc_templ);
templates.init_script = apiutil.readFileContents(userdatacfgobj.script_templ);
templates.init_err_script = apiutil.readFileContents(userdatacfgobj.errscript_templ);
}else{
templates.baseuri = '';
templates.algorithm = '';
templates.passphrase = '';
templates.cloud_config = null;
templates.init_script = null;
templates.init_err_script = null;
}
templates.default_script = EmptyScriptContents;
return templates;
}());
//---------------------------------------------------------
// Userdata Processing Class
//---------------------------------------------------------
var UserdataProcess = (function()
{
//
// Constructor
//
var UserdataProcess = function()
{
this._userdataTemplates = LoadedUserdataTemplates;
};
var proto = UserdataProcess.prototype;
//
// Methods
//
proto.encryptRoleInfo = function(obj)
{
if(!apiutil.isSafeEntity(obj)){
r3logger.elog('role information object parameter is empty.');
return null;
}
return cryptutil.r3EncryptJSON(obj, this._userdataTemplates.passphrase, this._userdataTemplates.algorithm);
};
proto.decryptRoleInfo = function(str)
{
if(!apiutil.isSafeString(str)){
r3logger.elog('string parameter is empty.');
return null;
}
return cryptutil.r3DecryptJSON(str, this._userdataTemplates.passphrase, this._userdataTemplates.algorithm);
};
proto.getMultipartUserdata = function(roleobj, errorMsg)
{
var rolename = '';
var roletenant = '';
var roletoken = '';
if(!apiutil.isSafeString(errorMsg)){
errorMsg = null;
}
if(!apiutil.isSafeEntity(roleobj)){
r3logger.elog('role object(role name, role token) parameter is empty.');
if(!errorMsg){
errorMsg = 'k2hr3 role information is wrong';
}
}else if(!apiutil.isSafeString(roleobj.role)){
r3logger.elog('role name parameter is empty.');
if(!errorMsg){
errorMsg = 'k2hr3 role name is empty';
}
}else if(!apiutil.isSafeString(roleobj.token)){
r3logger.elog('role token parameter is empty.');
if(!errorMsg){
errorMsg = 'k2hr3 role token is empty';
}
}else{
rolename = roleobj.role;
roletoken = roleobj.token;
// Extract tenant yrn full path from role yrn full path
var keys = r3keys();
var roleptn = new RegExp('^' + keys.MATCH_ANY_TENANT_ROLE); // regex = /^yrn:yahoo:(.*)::(.*):role:(.*)/
var matches = rolename.match(roleptn);
if(!apiutil.isEmptyArray(matches) && 4 <= matches.length && apiutil.isSafeString(matches[2])){
roletenant = keys.NO_SERVICE_KEY + apiutil.getSafeString(matches[1]) + '::' + apiutil.getSafeString(matches[2]);
}
}
//-----------------
// expands templates
//-----------------
var config = this._userdataTemplates.cloud_config; // cloud-config does not have keywords, then no-replacing.
var script = null;
var errscript = null;
var defscript = this._userdataTemplates.default_script;
if(this._userdataTemplates.init_script){
script = this._userdataTemplates.init_script.replace(this._userdataTemplates.kw_role_name, rolename);
script = script.replace(this._userdataTemplates.kw_role_tenant, roletenant);
script = script.replace(this._userdataTemplates.kw_role_token, roletoken);
script = script.replace(this._userdataTemplates.kw_api_uri, this._userdataTemplates.baseuri);
if(errorMsg){
// [NOTE]
// Normally, you'll use a script for error, so this process will be wasted.
// However, there are cases where this keyword is specified in the template,
// so we will replace it.
//
script = script.replace(this._userdataTemplates.kw_err_msg, errorMsg);
}else{
script = script.replace(this._userdataTemplates.kw_err_msg, '');
}
}
if(this._userdataTemplates.init_err_script){
errscript = this._userdataTemplates.init_err_script.replace(this._userdataTemplates.kw_role_name, rolename);
errscript = errscript.replace(this._userdataTemplates.kw_role_token, roletoken);
errscript = script.replace(this._userdataTemplates.kw_role_tenant, roletenant);
errscript = errscript.replace(this._userdataTemplates.kw_api_uri, this._userdataTemplates.baseuri);
if(errorMsg){
errscript = errscript.replace(this._userdataTemplates.kw_err_msg, errorMsg);
}else{
errscript = errscript.replace(this._userdataTemplates.kw_err_msg, '');
}
}
if(!config && !script){
r3logger.wlog('k2hr3-init and error script template is not specified.');
if(!errorMsg){
errorMsg = 'no script is set';
}
}
if(errorMsg){
defscript = defscript.replace(this._userdataTemplates.kw_err_msg, errorMsg);
}
//-----------------
// make part type array
//-----------------
var parts = new Array(); // member object is {type: 'contents-type string', filename: 'filename', contents: '...'}
if(errorMsg){
if(!errscript){
parts.push({type: 'text/x-shellscript', filename: 'k2hr3-init-empty.sh', contents: defscript});
}else{
parts.push({type: 'text/x-shellscript', filename: 'k2hr3-init-error.sh', contents: errscript});
}
}else if(config && script){
parts.push({type: 'text/cloud-config', filename: 'k2hr3-cloud-config.txt', contents: config});
parts.push({type: 'text/x-shellscript', filename: 'k2hr3-init.sh', contents: script});
}else if(config && !script){
parts.push({type: 'text/cloud-config', filename: 'k2hr3-cloud-config.txt', contents: config});
}else if(!config && script){
parts.push({type: 'text/x-shellscript', filename: 'k2hr3-init.sh', contents: script});
}else{ // !config && !script
parts.push({type: 'text/x-shellscript', filename: 'k2hr3-init-empty.sh', contents: defscript});
}
//-----------------
// make multipart
//-----------------
var boundary = '================K2HR3INIT' + Date.now().toString() + '==';
var result = {
body: '',
type: null,
mimeverkey: 'MIME-Version',
mimeverval: '1.0',
partcntkey: 'Number-Attachments',
partcntval: parts.length
};
result.body = '';
result.type = 'multipart/mixed; boundary="' + boundary + '"';
// fill parts
for(var cnt = 0; cnt < parts.length; ++cnt){
// part header
result.body += '--' + boundary + '\r\n';
result.body += 'MIME-Version: 1.0\r\n';
result.body += 'Content-Type: ' + parts[cnt].type + '; charset="us-ascii"\r\n';
result.body += 'Content-Transfer-Encoding: 7bit\r\n';
result.body += 'Content-Disposition: attachment; filename="' + parts[cnt].filename + '"\r\n\r\n';
// part contents
result.body += parts[cnt].contents;
result.body += '\r\n';
}
// make footer
result.body += '--' + boundary + '--\r\n';
return result;
};
proto.getGzipMultipartUserdata = function(roleobj, errorMsg, callback)
{
var _callback = null;
if(apiutil.isSafeEntity(callback)){
_callback = callback;
}
// get multipart headers and body
var multipartobj= this.getMultipartUserdata(roleobj, errorMsg);
// make one string
var multipart = '';
multipart += 'Content-Type: ' + multipartobj.type + '\r\n';
multipart += multipartobj.mimeverkey + ': ' + multipartobj.mimeverval + '\r\n';
multipart += multipartobj.partcntkey + ': ' + multipartobj.partcntval + '\r\n\r\n';
multipart += multipartobj.body;
return cryptutil.r3Gzip(multipart, _callback);
};
return UserdataProcess;
})();
//---------------------------------------------------------
// Exports
//---------------------------------------------------------
exports.userdataProcess = UserdataProcess;
/*
* 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
*/