k2hr3-api
Version:
K2HR3 REST API is K2hdkc based Resource and Roles and policy Rules
488 lines (440 loc) • 13.6 kB
JavaScript
/*
* K2HR3 REST API
*
* 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: Wed Jun 8 2017
* REVISION:
*
*/
;
var http = require('http');
var https = require('https');
var cacerts = require('../lib/cacerts');
var apiutil = require('../lib/k2hr3apiutil');
var cliutil = require('../lib/k2hr3cliutil');
// Debug logging objects
var r3logger = require('../lib/dbglogging');
//
// Hostname and port from env
//
var hostname = apiutil.getSafeString(process.env.APIHOST);
var hostport = apiutil.getSafeString(process.env.APIPORT);
var is_https = apiutil.compareCaseString('yes', process.env.HTTPS_ENV);
//
// Request API for test
//
function postV1Resource(method, token, querypath, name, datatype, data, reskeys, alias, port, cuk, roleyrn)
{
var strbody = '';
var headers = {
'Content-Type': 'application/json',
};
if(apiutil.isSafeString(token)){
headers['X-Auth-Token'] = token;
}
var options = {
'host': hostname,
'port': hostport,
'path': '/v1/resource' + apiutil.getSafeString(querypath),
'method': method
};
if(!apiutil.compareCaseString('string', datatype) && !apiutil.compareCaseString('object', datatype)){
datatype = 'string'; // default data type is string
}
if(apiutil.compareCaseString('post', method)){
// case for POST
if(apiutil.compareCaseString('object', datatype)){
// If datatype is object, data is needed to decode JSON to object here.
data = apiutil.parseJSON(data);
}
var body = {
'resource': {
'type': datatype,
'data': data, // if datatype is string, this includes control codes
'keys': reskeys
}
};
if(apiutil.isSafeString(name)){
body.resource.name = name;
}
if(apiutil.isSafeEntity(alias)){
body.resource.alias = alias;
}
if(apiutil.isSafeEntity(port) && !isNaN(port)){
body.resource.port = String(port);
}
if(apiutil.isSafeEntity(cuk)){
body.resource.cuk = cuk;
}
if(apiutil.isSafeString(roleyrn)){
body.resource.role = roleyrn;
}
strbody = JSON.stringify(body);
headers['Content-Length'] = strbody.length;
options.headers = headers;
}else if(apiutil.compareCaseString('put', method)){
// case for PUT
var urlarg = '';
var already_set = false;
if(apiutil.isSafeString(name)){
urlarg += already_set ? '&name=' : '?name=';
urlarg += name;
already_set = true;
}
if('' === datatype || apiutil.isSafeString(datatype)){
urlarg += already_set ? '&type=' : '?type=';
urlarg += datatype;
already_set = true;
}
if('' === data || apiutil.isSafeString(data)){
urlarg += already_set ? '&data=' : '?data=';
if(apiutil.compareCaseString('string', datatype)){
urlarg += JSON.stringify(data); // if data is string, data includes control codes, so it is converted to JSON.
}else{
urlarg += data; // if data is json, data is already json formatted.
}
already_set = true;
}
if(apiutil.isSafeEntity(reskeys)){
urlarg += already_set ? '&keys=' : '?keys=';
urlarg += JSON.stringify(reskeys); // keys is converted to JSON
already_set = true;
}
if(apiutil.isSafeEntity(alias)){
urlarg += already_set ? '&alias=' : '?alias=';
urlarg += JSON.stringify(alias); // alias is converted to JSON
already_set = true;
}
if(apiutil.isSafeEntity(port) && !isNaN(port)){
urlarg += already_set ? '&port=' : '?port=';
urlarg += String(port); // port is converted to String
already_set = true;
}
if(apiutil.isSafeEntity(cuk)){
urlarg += already_set ? '&cuk=' : '?cuk=';
urlarg += JSON.stringify(cuk); // cuk is converted to JSON
already_set = true;
}
if(apiutil.isSafeString(roleyrn)){
urlarg += already_set ? '&role=' : '?role=';
urlarg += roleyrn;
already_set = true;
}
headers['Content-Length'] = 0;
options.headers = headers;
options.path += encodeURI(urlarg);
}else{
console.log('method must be POST or PUT : ' + method);
process.exit(0);
}
r3logger.dlog('request options = ' + JSON.stringify(options));
r3logger.dlog('request headers = ' + JSON.stringify(headers));
r3logger.dlog('request body = ' + strbody);
var httpobj;
if(is_https){
if(null !== cacerts.ca){
options.ca = cacerts.ca;
}
options.rejectUnauthorized = false; // always insecure for this manual test
options.agent = new https.Agent(options);
httpobj = https;
}else{
options.agent = new http.Agent(options);
httpobj = http;
}
var req = httpobj.request(options, function(res)
{
var response = '';
console.log('RESPONSE CODE = ' + res.statusCode);
r3logger.dlog('response status = ' + res.statusCode);
r3logger.dlog('response header = ' + JSON.stringify(res.headers));
res.setEncoding('utf8');
res.on('data', function (chunk)
{
r3logger.dlog('response chunk = ' + chunk);
response += chunk;
});
res.on('end', function(result) // eslint-disable-line no-unused-vars
{
r3logger.mlog(r3logger.dump(response)); // response is object(or not)
console.log('RESPONSE BODY = ' + JSON.stringify(response));
process.exit(0);
});
});
req.on('error', function(e)
{
r3logger.elog('problem with request: ' + e.message);
});
// write data to request body
if('' !== strbody){
req.write(strbody);
}
req.end();
}
//
// Utility for inputting token for three pattern
//
// callback(error, token type, token string)
//
function rawInputToken(callback)
{
var _callback = callback;
cliutil.getConsoleInput('Token type(USER/ROLE/NULL(empty)) : ', true, false, function(isbreak, token_type)
{
if(isbreak){
_callback('break for inputting token type');
return;
}
var _token_type = null;
var _prefix = '';
if(!apiutil.isSafeString(token_type) || apiutil.compareCaseString('NULL', token_type)){
// no token
_callback(null, null, null);
return;
}else if(apiutil.compareCaseString('USER', token_type)){
// user token
_token_type = 'USER';
_prefix = 'U=';
}else if(apiutil.compareCaseString('ROLE', token_type)){
// role token
_token_type = 'ROLE';
_prefix = 'R=';
}else{
_callback('token type must be USER or ROLE or NULL(empty)');
return;
}
cliutil.getConsoleInput(_token_type + ' Token string : ', true, false, function(isbreak, token)
{
if(isbreak){
_callback('break for inputting token');
return;
}
if(!apiutil.isSafeString(_token_type) || apiutil.compareCaseString('NULL', _token_type)){
_callback('token must be string');
return;
}
var _token = _prefix + token;
_callback(null, _token_type, _token);
});
});
}
//
// Utility for input keys
//
function rawGetInputKeys(str)
{
var result;
if('' === apiutil.getSafeString(str)){
// empty value
result = '';
}else if(apiutil.compareCaseString('null', apiutil.getSafeString(str))){
// null value
result = null;
}else{
// try parse str as JSON string
try{
// parse JSON
result = JSON.parse(str);
}catch(err){ // eslint-disable-line no-unused-vars
// key=val,key=val...
result = {};
// parse ','
var rkeyarr = str.split(',');
for(var cnt = 0; cnt < rkeyarr.length; ++cnt){
var rkeyval = rkeyarr[cnt].trim();
var rkeyvalarr = rkeyval.split('=');
var rkey = null;
var rval = null;
for(var cnt2 = 0; cnt2 < rkeyvalarr.length; ++cnt2){
if(null === rkey){
rkey = rkeyvalarr[cnt2].trim();
}else if(null === rval){
rval = rkeyvalarr[cnt2].trim();
}else{
// many separator(=) in value
console.log('input resource sub key(' + rkey + ') has many separator(=) in value(' + rkeyarr[cnt] + '), but continue...');
rval += '=' + rkeyvalarr[cnt2]; // not trim
}
}
if(apiutil.isSafeString(rkey)){
result[rkey] = rval;
}else{
// input error
console.log('input key value something wrong : ' + str);
return undefined;
}
}
}
}
return result;
}
//
// Run
//
cliutil.getConsoleInput('Method(POST/PUT) : ', true, false, function(isbreak, method)
{
if(isbreak){
process.exit(0);
}
var _method;
if(apiutil.compareCaseString('post', method)){
_method = 'POST';
}else if(apiutil.compareCaseString('put', method)){
_method = 'PUT';
}else{
console.log('method must be POST or PUT : ' + method);
process.exit(0);
}
rawInputToken(function(error, token_type, token)
{
if(null !== error){
console.log(error);
process.exit(0);
}
var _token_type = token_type;
var _token = token;
cliutil.getConsoleInput('Resource name(path) : ', true, false, function(isbreak, name)
{
if(isbreak){
process.exit(0);
}
var _name = name;
cliutil.getConsoleInput(' data type(string(str) or object(obj)) : ', true, false, function(isbreak, datatype)
{
if(isbreak){
process.exit(0);
}
var _datatype = null;
var is_string = false;
if(apiutil.compareCaseString('string', datatype) || apiutil.compareCaseString('str', datatype)){
_datatype = 'string';
is_string = true;
}else if(apiutil.compareCaseString('object', datatype) || apiutil.compareCaseString('obj', datatype) || apiutil.compareCaseString('json', datatype)){
_datatype = 'object';
is_string = false;
}else{
console.log('data type must be STRING or OBJECT : ' + datatype);
process.exit(0);
}
cliutil.inputObjectData(is_string, function(isbreak, data)
{
if(isbreak){
process.exit(0);
}
// [NOTE]
// if data type is string, data has CR code = '\n'
//
var _data = data;
process.stdout.write(' key-value(following for example) \n');
process.stdout.write(' ex.1) empty -> (empty) \n');
process.stdout.write(' ex.2) null -> null \n');
process.stdout.write(' ex.3) key=val -> key01=val01,key02=val02,.. \n');
process.stdout.write(' ex.4) JSON -> <JSON string for object> \n');
cliutil.getConsoleInput(' input key value (one of example format) : ', true, false, function(isbreak, reskeys)
{
if(isbreak){
process.exit(0);
}
var _reskeys;
var _querypath;
if(undefined === (_reskeys = rawGetInputKeys(reskeys))){
process.exit(0);
}
if(null === _token_type){
// no token
_querypath = '/' + _name;
cliutil.getConsoleInput(' port number(0=any(empty default)) : ', true, false, function(isbreak, port)
{
if(isbreak){
process.exit(0);
}
var _port;
if(null === port || !apiutil.isSafeString(port)){
_port = 0;
}else if(!isNaN(port)){
_port = parseInt(port);
}else{
process.exit(0);
}
cliutil.getConsoleInput(' cuk(allow empty) : ', true, false, function(isbreak, cuk)
{
if(isbreak){
process.exit(0);
}
var _cuk;
if(apiutil.isSafeString(cuk) && apiutil.isSafeString(cuk.trim())){
_cuk = cuk.trim();
}
cliutil.getConsoleInput(' Role full yrn path for resource : ', true, false, function(isbreak, roleyrn)
{
if(isbreak){
process.exit(0);
}
if(!apiutil.isSafeString(roleyrn)){
process.exit(0);
}
var _roleyrn = roleyrn;
// run
postV1Resource(_method, _token, _querypath, null, _datatype, _data, _reskeys, null, _port, _cuk, _roleyrn);
});
});
});
}else if('USER' === _token_type){
// user token
_querypath = null;
cliutil.getConsoleInput(' alias(specify null/(empty)/yrn multiple with \',\'): ', true, false, function(isbreak, alias)
{
if(isbreak){
process.exit(0);
}
var _alias;
if('' === apiutil.getSafeString(alias)){
_alias = '';
}else if(apiutil.compareCaseString('null', apiutil.getSafeString(alias))){
_alias = null;
}else{
// parse ','
_alias = new Array(0);
var strarray= alias.split(',');
for(var cnt = 0; cnt < strarray.length; ++cnt){
var strtmp = strarray[cnt].trim();
_alias.push(strtmp);
}
}
// run
postV1Resource(_method, _token, _querypath, _name, _datatype, _data, _reskeys, _alias);
});
}else if('ROLE' === _token_type){
// role token
_querypath = '/' + _name;
// run
postV1Resource(_method, _token, _querypath, null, _datatype, _data, _reskeys, null);
}else{
// why?
process.exit(0);
}
});
});
});
});
});
});
/*
* 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
*/