UNPKG

k2hr3-api

Version:

K2HR3 REST API is K2hdkc based Resource and Roles and policy Rules

1,096 lines (1,016 loc) 36.9 kB
/* * K2HR3 REST API * * Copyright 2023 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: Mon Sep 3 2023 * REVISION: * */ 'use strict'; var express = require('express'); var router = express.Router(); var r3token = require('../lib/k2hr3tokens'); var apiutil = require('../lib/k2hr3apiutil'); var resutil = require('../lib/k2hr3resutil'); var k2hr3 = require('../lib/k2hr3dkc'); var r3keys = require('../lib/k2hr3keys').getK2hr3Keys; // Debug logging objects var r3logger = require('../lib/dbglogging'); //========================================================= // CAUTION //--------------------------------------------------------- // This note is common to the TENANT API. // // TENANT API requires User Unscoped Token or User Scoped // Token. // Note that even if a User Scoped Token is specified, that // scoped Tenant will be ignored. // To specify the tenant of each API, use URI path or parameter // instead of Token. // Specify the tenant only by the tenant name, not by the YRN // full path. // //--------------------------------------------------------- //========================================================= // Common Utility function //========================================================= // // Utility for parsing common input parameters // // This function parse token(user or role or not have this) from HTTP request(req), // and tenant name, etc. // // return { // result: true/false // message: null or error message // status_code: status code(default 200) // parameters: { // token_type: null or 'user' or 'role' // token_str: token string(if user token or role token) // token_info: null or object(returned from checkToken) // user_name: null or user name(if user token) // tenant_name: null or tenant name in request uri path // keys: k2hr3keys object // } // } // function rawParseBaseParamInRequest(req) { var result = { result: true, message: null, status_code: 200 }; var parameters = { token_type: null, token_str: null, token_info: null, token_tenant: null, user_name: null, tenant_name: null, keys: r3keys() // temporary }; // // check token for API mode // if(r3token.hasAuthTokenHeader(req)){ var token_result = r3token.checkToken(req, false, true); // (un)scoped, user if(!token_result.result){ result.result = token_result.result; result.message = token_result.message; result.status_code = token_result.status; r3logger.elog(result.message); return result; } parameters.token_str = token_result.token; parameters.token_type = token_result.token_type; parameters.token_info = token_result.token_info; parameters.user_name = apiutil.getSafeString(parameters.token_info.user); } // // get tenant name from uri // var requestptn = new RegExp('^/v1/tenant/(.*)'); // regex = /^\/v1\/tenant\/(.*)/ var reqmatchs = decodeURI(req.baseUrl).match(requestptn); if(apiutil.isEmptyArray(reqmatchs) || reqmatchs.length < 2 || '' === apiutil.getSafeString(reqmatchs[1])){ parameters.tenant_name = null; }else{ // check tenant name if(0 !== reqmatchs[1].indexOf(parameters.keys.VALUE_PREFIX_LOCAL_TENANT)){ // Not have prefix("local@") parameters.tenant_name = parameters.keys.VALUE_PREFIX_LOCAL_TENANT + reqmatchs[1]; parameters.tenant_name = parameters.tenant_name.toLowerCase(); }else{ parameters.tenant_name = reqmatchs[1].toLowerCase(); } } // keys parameters.keys = r3keys(parameters.user_name, parameters.tenant_name); // no error result.parameters = parameters; return result; } // // Utility for Create/Update tenant for POST/PUT // // is_create : true/false // user_name : add main user name for tenant // tenant_name : tenant name // tenant_id : tenant id // tenant_desc : tenant description // tenant_display : tenant display name // tenant_users : other tenant user names // // result { // result: true/false // message: error message // rescode: 200/201/4xx/5xx // } // function rawCreateUpdateTenant(is_create, user_name, tenant_name, tenant_id, tenant_desc, tenant_display, tenant_users) { var result = {result: true, message: null, rescode: 200}; var resobj; if(is_create){ // // Create tenant // resobj = k2hr3.findTenant(tenant_name); if(apiutil.isSafeEntity(resobj) && apiutil.isSafeEntity(resobj.result) && true === resobj.result){ result.result = false; result.message = 'failed to create tenant by already tenant(' + tenant_name + ') existed'; result.rescode = 400; r3logger.elog(result.message); return result; } result.rescode = 201; // 201: Created }else{ // // Update tenant // resobj = k2hr3.findTenant(tenant_name, user_name, tenant_id); if(!apiutil.isSafeEntity(resobj) || !apiutil.isSafeEntity(resobj.result) || false === resobj.result){ result.result = false; if(apiutil.isSafeEntity(resobj) && apiutil.isSafeString(resobj.message)){ result.message = 'failed to update tenant by ' + resobj.message; }else{ result.message = 'failed to update tenant by unknown reason'; } result.rescode = 400; r3logger.elog(result.message); return result; } result.rescode = 200; // 200: OK } // // Create/Update tenant // resobj = k2hr3.initTenant(tenant_name, tenant_id, tenant_desc, tenant_display, user_name, tenant_users); if(!apiutil.isSafeEntity(resobj) || !apiutil.isSafeEntity(resobj.result) || false === resobj.result){ result.result = false; if(apiutil.isSafeEntity(resobj) && apiutil.isSafeString(resobj.message)){ result.message = 'failed to create tenant by ' + resobj.message; }else{ result.message = 'failed to create tenant by unknown reason'; } result.rescode = 400; r3logger.elog(result.message); return result; } return result; } //========================================================= // Router POST //========================================================= // // Mountpath : '/v1/tenant' // //--------------------------------------------------------- // [POST] No tenant path //--------------------------------------------------------- // POST '/v1/tenant' : create tenant version 1 // HEADER : X-Auth-Token = <User token> // body : { // "tenant": { // "name": <tenant> => key is "yrn:yahoo:::<tenant>" // thix value type must be string. // "desc": <description> => value for "yrn:yahoo:::<tenant>:desc" // thix value type must be string. // "display": <display name> => key is "yrn:yahoo:::<tenant>:display" // thix value type must be string. // "users": <user> or [user, ...] => key is "yrn:yahoo::::user:<user>" // specify adding user array which is yrn path as "yrn:yahoo::::user:<user>" or "user name" // } // } // // response status code : 201 or 4xx/5xx // response body : { // result: true/false // message: messages // } // // Create a tenant as <K2HR3 cluster LOCAL> tenant. // // [NOTE] // If the <K2HR3 cluster LOCAL> tenant already exists, this repsponses an error. // // Tenant names must start with "local@"(if not set it, this prefix adds automatically). // Specify the user by YRN full path or user name. // If the user indicated by <User Token> does not exist, it will be added. // New tenant id is set automatically. // //--------------------------------------------------------- // [POST] With tenant path //--------------------------------------------------------- // POST '/v1/tenant/tenant' : update tenant version 1 // HEADER : X-Auth-Token = <User token> // body : { // "tenant": { // "id": <id> => key is "yrn:yahoo:::<tenant>:id" // this value type must be string. // "desc": <description> => value for "yrn:yahoo:::<tenant>:desc" // thix value type must be string. // "display": <display name> => key is "yrn:yahoo:::<tenant>:display" // thix value type must be string. // "users": <user> or [user, ...] => key is "yrn:yahoo::::user:<user>" // specify adding user array which is yrn path as "yrn:yahoo::::user:<user>" or "user name" // } // } // // response status code : 200 or 4xx/5xx // response body : { // result: true/false // message: messages // } // // Update existed tenant as <K2HR3 cluster LOCAL> tenant. // // [NOTE] // If the <K2HR3 cluster LOCAL> tenant does not exist, this repsponses an error. // Tenant names must start with "local@"(if not set it, this prefix adds automatically for search). // The <User Token> user must be included in the tenant's user list. // // Specify the user by YRN full path or user name. // If the user indicated by <User Token> does not exist, it will be added. // router.post('/', function(req, res, next) // eslint-disable-line no-unused-vars { r3logger.dlog('CALL:', req.method, req.url); res.type('application/json; charset=utf-8'); var result = {result: true, message: null}; if( !apiutil.isSafeEntity(req) || !apiutil.isSafeEntity(req.baseUrl) || !apiutil.isSafeEntity(req.body) || !apiutil.isSafeEntity(req.body.tenant) ) { result.result = false; result.message = 'POST body does not have tenant data'; r3logger.elog(result.message); resutil.errResponse(req, res, 400, result); // 400: Bad Request return; } //------------------------------ // check common parameters(token, tenant etc) //------------------------------ var resobj = rawParseBaseParamInRequest(req); if(!resobj.result){ result.result = resobj.result; result.message = resobj.message; r3logger.elog(resobj.message); resutil.errResponse(req, res, resobj.status_code, result); return; } var comparam = resobj.parameters; //------------------------------ // check token type //------------------------------ if('user' !== comparam.token_type){ result.result = false; result.message = 'POST request tenant must specify <User Token>'; r3logger.elog(result.message); resutil.errResponse(req, res, 400, result); // 400: Bad Request return; } //------------------------------ // check arguments //------------------------------ var is_create = true; var tenant_name = null; var tenant_id = null; var tenant_desc = null; var tenant_display = null; var tenant_users = null; if(!apiutil.isSafeString(comparam.tenant_name)){ // // Create mode // is_create = true; tenant_name = apiutil.getSafeString(req.body.tenant.name).toLowerCase(); tenant_id = apiutil.getStrUuid4(); // Create new id here. if(!apiutil.isSafeString(tenant_name)){ result.result = false; result.message = 'POST request tenant body does not have tenant.name string object.'; r3logger.elog(result.message); resutil.errResponse(req, res, 400, result); // 400: Bad Request return; } if(0 !== tenant_name.indexOf(comparam.keys.VALUE_PREFIX_LOCAL_TENANT)){ // Not have prefix("local@") tenant_name = comparam.keys.VALUE_PREFIX_LOCAL_TENANT + tenant_name; } }else{ // // Update mode // is_create = false; tenant_name = comparam.tenant_name; tenant_id = apiutil.getSafeString(req.body.tenant.id); if(!apiutil.isSafeString(tenant_id)){ result.result = false; result.message = 'POST request tenant(' + tenant_name + ') body does not have tenant.id string object.'; r3logger.elog(result.message); resutil.errResponse(req, res, 400, result); // 400: Bad Request return; } } if(apiutil.isSafeString(req.body.tenant.desc)){ tenant_desc = apiutil.getSafeString(req.body.tenant.desc); }else{ tenant_desc = 'K2HR3 Cluster Local tenant'; } if(apiutil.isSafeString(req.body.tenant.display)){ tenant_display = apiutil.getSafeString(req.body.tenant.display); }else{ tenant_display = tenant_name; } // // Check users // if(apiutil.getSafeString(req.body.tenant.users)){ tenant_users = [req.body.tenant.users.trim()]; }else{ tenant_users = apiutil.getSafeArray(req.body.tenant.users); } if(is_create){ // add own user apiutil.tryAddStringToArray(tenant_users, comparam.user_name); }else{ if(apiutil.isEmptyArray(tenant_users)){ result.result = false; result.message = 'POST request tenant(' + tenant_name + ') does not have any user list.'; r3logger.elog(result.message); resutil.errResponse(req, res, 400, result); // 400: Bad Request return; } var findobj = k2hr3.findTenant(tenant_name, comparam.user_name, tenant_id); if( !apiutil.isSafeEntity(findobj) || !apiutil.isSafeEntity(findobj.result) || false === findobj.result || !apiutil.isSafeEntity(findobj.tenant) || !apiutil.isSafeEntity(findobj.tenant.name) || !apiutil.getSafeArray(findobj.tenant.users) || !apiutil.findStringInArray(findobj.tenant.users, comparam.user_name) ) { result.result = false; result.message = 'POST request tenant(' + tenant_name + ') does not allow user(' + comparam.user_name + ').'; r3logger.elog(result.message); resutil.errResponse(req, res, 400, result); // 400: Bad Request return; } } if(apiutil.isArray(tenant_users)){ tenant_users.sort(); } //------------------------------ // Processing //------------------------------ resobj = rawCreateUpdateTenant(is_create, comparam.user_name, tenant_name, tenant_id, tenant_desc, tenant_display, tenant_users); if(!apiutil.isSafeEntity(resobj) || !apiutil.isSafeEntity(resobj.result) || !apiutil.isSafeEntity(resobj.rescode) || false === resobj.result){ result.result = false; if(apiutil.isSafeEntity(resobj) && apiutil.isSafeString(resobj.message)){ result.message = 'POST request failed to update tenant by ' + resobj.message; }else{ result.message = 'POST request failed to update tenant by unknown reason'; } if(apiutil.isSafeEntity(resobj) && apiutil.isSafeEntity(resobj.rescode)){ resutil.errResponse(req, res, resobj.rescode, result); }else{ resutil.errResponse(req, res, 500, result); // 500: Internal error } r3logger.elog(result.message); return; } r3logger.dlog('succeed : create/update tenant(' + tenant_name + ') by user(' + comparam.user_name + ')'); res.status(resobj.rescode); // 200 or 201 res.send(JSON.stringify(result)); }); //========================================================= // Router PUT //========================================================= // // Mountpath : '/v1/tenant' // //--------------------------------------------------------- // [PUT] No tenant path //--------------------------------------------------------- // PUT '/v1/tenant' : create tenant version 1 // HEADER : X-Auth-Token = <User token> // url argument : // "name": <tenant> => key is "yrn:yahoo:::<tenant>" // <tenant> must include the prefix "R3CLUSTERLOCAL-". // "desc": <description> => value for "yrn:yahoo:::<tenant>:desc" // thix value type must be string. // "display": <display name> => key is "yrn:yahoo:::<tenant>:display" // thix value type must be string. // "users": <user> or [user, ...] => key is "yrn:yahoo::::user:<user>" // specify adding user array which is yrn path as "yrn:yahoo::::user:<user>" or "user name" // // response status code : 201 or 4xx/5xx // response body : { // result: true/false // message: messages // } // // Create a tenant as <K2HR3 cluster LOCAL> tenant. // // [NOTE] // If the <K2HR3 cluster LOCAL> tenant already exists, this repsponses an error. // // Tenant names must start with "R3CLUSTERLOCAL-". // Specify the user by YRN full path or user name. // If the user indicated by <User Token> does not exist, it will be added. // New tenant id("R3CLUSTERLOCAL-xxxxxx") is set automatically. // //--------------------------------------------------------- // [PUT] With tenant path //--------------------------------------------------------- // PUT '/v1/tenant/tenant' : update tenant version 1 // HEADER : X-Auth-Token = <User token> // url argument : // "id": <id> => key is "yrn:yahoo:::<tenant>:id" // this value type must be string. // "desc": <description> => value for "yrn:yahoo:::<tenant>:desc" // thix value type must be string. // "display": <display name> => key is "yrn:yahoo:::<tenant>:display" // thix value type must be string. // "users": <user> or [user, ...] => key is "yrn:yahoo::::user:<user>" // specify adding user array which is yrn path as "yrn:yahoo::::user:<user>" or "user name" // // response status code : 200 or 4xx/5xx // response body : { // result: true/false // message: messages // } // // Update existed tenant as <K2HR3 cluster LOCAL> tenant. // // [NOTE] // If the <K2HR3 cluster LOCAL> tenant does not exist, this repsponses an error. // The <User Token> user must be included in the tenant's user list. // // Specify the user by YRN full path or user name. // If the user indicated by <User Token> does not exist, it will be added. // router.put('/', function(req, res, next) // eslint-disable-line no-unused-vars { r3logger.dlog('CALL:', req.method, req.url); res.type('application/json; charset=utf-8'); var result = {result: true, message: null}; if( !apiutil.isSafeEntity(req) || !apiutil.isSafeEntity(req.baseUrl) || !apiutil.isSafeEntity(req.query) ) { result.result = false; result.message = 'PUT request is something wrong'; r3logger.elog(result.message); resutil.errResponse(req, res, 400, result); // 400: Bad Request return; } //------------------------------ // check common parameters(token, tenant etc) //------------------------------ var resobj = rawParseBaseParamInRequest(req); if(!resobj.result){ result.result = resobj.result; result.message = resobj.message; r3logger.elog(resobj.message); resutil.errResponse(req, res, resobj.status_code, result); return; } var comparam = resobj.parameters; //------------------------------ // check token type //------------------------------ if('user' !== comparam.token_type){ result.result = false; result.message = 'PUT request tenant must specify <User Token>'; r3logger.elog(result.message); resutil.errResponse(req, res, 400, result); // 400: Bad Request return; } //------------------------------ // check arguments //------------------------------ var is_create = true; var tenant_name = null; var tenant_id = null; var tenant_desc = null; var tenant_display = null; var tenant_users = null; if(!apiutil.isSafeString(comparam.tenant_name)){ // // Create mode // is_create = true; tenant_name = apiutil.getSafeString(req.query.name).toLowerCase(); tenant_id = apiutil.getStrUuid4(); // Create new id here. if(!apiutil.isSafeString(tenant_name)){ result.result = false; result.message = 'PUT request tenant body does not have tenant.name string object.'; r3logger.elog(result.message); resutil.errResponse(req, res, 400, result); // 400: Bad Request return; } if(0 !== tenant_name.indexOf(comparam.keys.VALUE_PREFIX_LOCAL_TENANT)){ // Not have prefix("local@") tenant_name = comparam.keys.VALUE_PREFIX_LOCAL_TENANT + tenant_name; } }else{ // // Update mode // is_create = false; tenant_name = comparam.tenant_name; tenant_id = apiutil.getSafeString(req.query.id); if(!apiutil.isSafeString(tenant_id)){ result.result = false; result.message = 'PUT request tenant(' + tenant_name + ') body does not have tenant.id string object.'; r3logger.elog(result.message); resutil.errResponse(req, res, 400, result); // 400: Bad Request return; } } if(apiutil.isSafeString(req.query.desc)){ tenant_desc = apiutil.getSafeString(req.query.desc); }else{ tenant_desc = 'K2HR3 Cluster Local tenant'; } if(apiutil.isSafeString(req.query.display)){ tenant_display = apiutil.getSafeString(req.query.display); }else{ tenant_display = tenant_name; } // // Check users // if(apiutil.checkSimpleJSON(req.query.users)){ tenant_users = apiutil.parseJSON(req.query.users); if(!apiutil.isArray(tenant_users) && apiutil.isSafeString(tenant_users)){ tenant_users = [tenant_users]; }else{ tenant_users = apiutil.getSafeArray(tenant_users); } }else if(!apiutil.isArray(req.query.users) && apiutil.isSafeString(req.query.users)){ tenant_users = [req.query.users]; }else{ tenant_users = apiutil.getSafeArray(req.query.users); } if(is_create){ // add own user apiutil.tryAddStringToArray(tenant_users, comparam.user_name); }else{ // check user in current tenant users if(apiutil.isEmptyArray(tenant_users)){ result.result = false; result.message = 'PUT request tenant(' + tenant_name + ') does not have any user list.'; r3logger.elog(result.message); resutil.errResponse(req, res, 400, result); // 400: Bad Request return; } var findobj = k2hr3.findTenant(tenant_name, comparam.user_name, tenant_id); if( !apiutil.isSafeEntity(findobj) || !apiutil.isSafeEntity(findobj.result) || false === findobj.result || !apiutil.isSafeEntity(findobj.tenant) || !apiutil.isSafeEntity(findobj.tenant.name) || !apiutil.getSafeArray(findobj.tenant.users) || !apiutil.findStringInArray(findobj.tenant.users, comparam.user_name) ) { result.result = false; result.message = 'PUT request tenant(' + tenant_name + ') does not allow user(' + comparam.user_name + ').'; r3logger.elog(result.message); resutil.errResponse(req, res, 400, result); // 400: Bad Request return; } } if(apiutil.isArray(tenant_users)){ tenant_users.sort(); } //------------------------------ // Processing //------------------------------ resobj = rawCreateUpdateTenant(is_create, comparam.user_name, tenant_name, tenant_id, tenant_desc, tenant_display, tenant_users); if(!apiutil.isSafeEntity(resobj) || !apiutil.isSafeEntity(resobj.result) || !apiutil.isSafeEntity(resobj.rescode) || false === resobj.result){ result.result = false; if(apiutil.isSafeEntity(resobj) && apiutil.isSafeString(resobj.message)){ result.message = 'PUT request failed to update tenant by ' + resobj.message; }else{ result.message = 'PUT request failed to update tenant by unknown reason'; } if(apiutil.isSafeEntity(resobj) && apiutil.isSafeEntity(resobj.rescode)){ resutil.errResponse(req, res, resobj.rescode, result); }else{ resutil.errResponse(req, res, 500, result); // 500: Internal error } r3logger.elog(result.message); return; } r3logger.dlog('succeed : create/update tenant(' + tenant_name + ') by user(' + comparam.user_name + ')'); res.status(resobj.rescode); // 200 or 201 res.send(JSON.stringify(result)); }); //========================================================= // Router GET //========================================================= // // Mountpath : '/v1/tenant{/tenant}' // //--------------------------------------------------------- // [GET] No tenant path //--------------------------------------------------------- // GET '/v1/tenant' : get tenant list version 1 // HEADER : X-Auth-Token = <User token> // URL arguments : expand = "true"(default) or "false" // response status code : 200 or 4xx/5xx // response : nothing // response body : { // result: true/false, // message: null or error message string // tenants: [ // { // name: "string", // id: "string", // desc: "string", // display: "string", // user: array[users...] // }, // ... // ] // } // or // { // result: true/false, // message: null or error message string // tenants: [ // "tenant", // ... // ] // } // // This mount point retrieves a list of tenants and information about each. // //--------------------------------------------------------- // [GET] With tenant path //--------------------------------------------------------- // GET '/v1/tenant/<tenant>' : get tenant information on version 1 // HEADER : X-Auth-Token = <User token> // URL arguments : nothing // response status code : 200 or 4xx/5xx // response : nothing // response body : { // result: true/false, // message: null or error message string // tenant: { // name: "string", // id: "string", // desc: "string", // display: "string", // user: array[users...] // } // } // router.get('/', function(req, res, next) { r3logger.dlog('CALL:', req.method, req.url); if('GET' !== req.method){ // HEAD request comes here, so it should be routed to head function. next(); return; } res.type('application/json; charset=utf-8'); var result = {result: true, message: null}; if( !apiutil.isSafeEntity(req) || !apiutil.isSafeEntity(req.baseUrl) ) { result.result = false; result.message = 'GET request is something wrong'; r3logger.elog(result.message); resutil.errResponse(req, res, 400, result); // 400: Bad Request return; } //------------------------------ // check common parameters(token, tenant etc) //------------------------------ var resobj = rawParseBaseParamInRequest(req); if(!resobj.result){ result.result = resobj.result; result.message = resobj.message; r3logger.elog(resobj.message); resutil.errResponse(req, res, resobj.status_code, result); return; } var comparam = resobj.parameters; //------------------------------ // check token type //------------------------------ if('user' !== comparam.token_type){ result.result = false; result.message = 'GET request tenant must specify <User Token>'; r3logger.elog(result.message); resutil.errResponse(req, res, 400, result); // 400: Bad Request return; } //------------------------------ // Processing //------------------------------ if(!apiutil.isSafeString(comparam.tenant_name)){ // // List mode // var keys = r3keys(comparam.user_name); // // Check expand type // var is_expand = true; if(apiutil.isSafeEntity(req.query) && apiutil.isSafeString(req.query.expand)){ if(apiutil.compareCaseString(keys.VALUE_TRUE, req.query.expand)){ is_expand = true; }else if(apiutil.compareCaseString(keys.VALUE_FALSE, req.query.expand)){ is_expand = false; }else{ result.result = false; result.message = 'GET expand url argument parameter(' + JSON.stringify(req.query.expand) + ') is wrong, it must be ' + keys.VALUE_TRUE + ' or ' + keys.VALUE_FALSE + '.'; r3logger.elog(result.message); resutil.errResponse(req, res, 400, result); // 400: Bad Request return; } } // // Get list // resobj = k2hr3.listLocalTenant(comparam.user_name, is_expand); if(!apiutil.isSafeEntity(resobj) || !apiutil.isSafeEntity(resobj.result) || !apiutil.isArray(resobj.tenants) || false === resobj.result){ result.result = false; if(apiutil.isSafeEntity(resobj) && apiutil.isSafeString(resobj.message)){ result.message = 'GET request failed to update tenant by ' + resobj.message; }else{ result.message = 'GET request failed to update tenant by unknown reason'; } r3logger.elog(result.message); resutil.errResponse(req, res, 400, result); // 400: Bad Request return; } result.tenants = resobj.tenants; }else{ // // One tenant // resobj = k2hr3.findTenant(comparam.tenant_name); if(!apiutil.isSafeEntity(resobj) || !apiutil.isSafeEntity(resobj.result) || !apiutil.isSafeEntity(resobj.tenant) || false === resobj.result){ result.result = false; if(apiutil.isSafeEntity(resobj) && apiutil.isSafeString(resobj.message)){ result.message = 'GET request failed to update tenant by ' + resobj.message; }else{ result.message = 'GET request failed to update tenant by unknown reason'; } r3logger.elog(result.message); resutil.errResponse(req, res, 400, result); // 400: Bad Request return; } result.tenant = resobj.tenant; } r3logger.dlog('succeed : get tenant(s) by user(' + comparam.user_name + ')'); res.status(200); // 200: OK res.send(JSON.stringify(result)); }); //========================================================= // Router HEAD //========================================================= // // Mountpath : '/v1/tenant/tenant' // // HEAD '/v1/tenant/<tenant>' : head tenant on version 1 // HEADER : X-Auth-Token = <User token> // response status code : 204 or 4xx/5xx // response body : nothing // // This mount point is an API for checking the existence of a tenant. // If the tenant is given, this returns a 204 if that tenant exists and is allowed to be seen. // If no tenant is given, returns 204 if at least one target tenant exists. // router.head('/', function(req, res, next) { r3logger.dlog('CALL:', req.method, req.url); if('HEAD' !== req.method){ // If other method request comes here, so it should be routed another function. next(); return; } res.type('application/json; charset=utf-8'); if( !apiutil.isSafeEntity(req) || !apiutil.isSafeEntity(req.baseUrl) ) { r3logger.elog('HEAD request is something wrong'); resutil.errResponse(req, res, 400); // 400: Bad Request return; } //------------------------------ // check common parameters(token, tenant etc) //------------------------------ var resobj = rawParseBaseParamInRequest(req); if(!resobj.result){ r3logger.elog(resobj.message); resutil.errResponse(req, res, resobj.status_code); return; } var comparam = resobj.parameters; //------------------------------ // check token type //------------------------------ if('user' !== comparam.token_type){ r3logger.elog('HEAD request tenant must specify <User Token>'); resutil.errResponse(req, res, 400); // 400: Bad Request return; } //------------------------------ // Check uri paths(tenant name) //------------------------------ if(!apiutil.isSafeString(comparam.tenant_name)){ r3logger.elog('HEAD request tenant must specify <tenant> path'); resutil.errResponse(req, res, 400); // 400: Bad Request return; } //------------------------------ // Processing //------------------------------ resobj = k2hr3.findTenant(comparam.tenant_name); if(!apiutil.isSafeEntity(resobj) || !apiutil.isSafeEntity(resobj.result) || !apiutil.isSafeEntity(resobj.tenant) || false === resobj.result){ if(apiutil.isSafeEntity(resobj) && apiutil.isSafeString(resobj.message)){ r3logger.elog('HEAD request failed to update tenant by ' + resobj.message); }else{ r3logger.elog('HEAD request failed to update tenant by unknown reason'); } resutil.errResponse(req, res, 400); // 400: Bad Request return; } r3logger.dlog('HEAD request succeed - check tenant(' + comparam.tenant_name + ') exists'); res.status(204); // 204: No Content res.send(); }); //========================================================= // Router DELETE //========================================================= // // Mountpath : '/v1/tenant' // //--------------------------------------------------------- // [DELETE] No tenant path //--------------------------------------------------------- // DELETE '/v1/tenant' : delete tenant version 1 // HEADER : X-Auth-Token = <User token> // url argument : "tenant" = <tenant name> // url argument : "id" = <id> => key is "yrn:yahoo:::<tenant>:id" // response status code : 204 or 4xx/5xx // response body : nothing // // This mount point deletes the specified <K2HR3 cluster LOCAL> tenant. // //--------------------------------------------------------- // [DELETE] With tenant path //--------------------------------------------------------- // DELETE '/v1/tenant/tenant' : delete tenant version 1 // HEADER : X-Auth-Token = <User token> // url argument : "id" = <id> => key is "yrn:yahoo:::<tenant>:id" // response status code : 204 or 4xx/5xx // response body : nothing // // This mount point deletes the specified <K2HR3 cluster LOCAL> tenant. // // [NOTE] // Only users registered in the tenant to be deleted can delete this tenant. // router.delete('/', function(req, res, next) // eslint-disable-line no-unused-vars { r3logger.dlog('CALL:', req.method, req.url); res.type('application/json; charset=utf-8'); if( !apiutil.isSafeEntity(req) || !apiutil.isSafeEntity(req.baseUrl) ) { r3logger.elog('DELETE request or url or query is wrong'); resutil.errResponse(req, res, 400); // 400: Bad Request return; } //------------------------------ // check common parameters(token, tenant etc) //------------------------------ var resobj = rawParseBaseParamInRequest(req); if(!resobj.result){ r3logger.elog(resobj.message); resutil.errResponse(req, res, resobj.status_code); return; } var comparam = resobj.parameters; //------------------------------ // check token type //------------------------------ if('user' !== comparam.token_type){ r3logger.elog('DELETE request tenant must specify <User Token>'); resutil.errResponse(req, res, 400); // 400: Bad Request return; } //------------------------------ // Check uri paths //------------------------------ var tenant_name; var tenant_id; if(!apiutil.isSafeString(comparam.tenant_name)){ //------------------------------ // Check argments(tenant) //------------------------------ tenant_name = apiutil.getSafeString(req.query.tenant); if(!apiutil.isSafeString(tenant_name)){ r3logger.elog('DELETE request tenant must specify in argument'); resutil.errResponse(req, res, 400); // 400: Bad Request return; } //------------------------------ // Check argments(id) //------------------------------ tenant_id = apiutil.getSafeString(req.query.id); if(!apiutil.isSafeString(tenant_id)){ r3logger.elog('DELETE request id must specify in argument'); resutil.errResponse(req, res, 400); // 400: Bad Request return; } //------------------------------ // Processing //------------------------------ resobj = k2hr3.removeLocalTenant(tenant_name, comparam.user_name, tenant_id); if(!apiutil.isSafeEntity(resobj) || !apiutil.isSafeEntity(resobj.result) || false === resobj.result){ if(apiutil.isSafeEntity(resobj) && apiutil.isSafeString(resobj.message)){ r3logger.elog('DELETE request failed to remove user from tenant by ' + resobj.message); }else{ r3logger.elog('DELETE request failed to remove user from tenant by unknown reason'); } resutil.errResponse(req, res, 400); // 400: Bad Request return; } r3logger.dlog('DELETE request succeed - remove tenant'); }else{ //------------------------------ // Check argments(id) //------------------------------ tenant_id = apiutil.getSafeString(req.query.id); if(!apiutil.isSafeString(tenant_id)){ r3logger.elog('DELETE request id must specify in argument'); resutil.errResponse(req, res, 400); // 400: Bad Request return; } //------------------------------ // Processing //------------------------------ resobj = k2hr3.removeUserFromLocalTenant(comparam.tenant_name, comparam.user_name, tenant_id); if(!apiutil.isSafeEntity(resobj) || !apiutil.isSafeEntity(resobj.result) || false === resobj.result){ if(apiutil.isSafeEntity(resobj) && apiutil.isSafeString(resobj.message)){ r3logger.elog('DELETE request failed to remove user from tenant by ' + resobj.message); }else{ r3logger.elog('DELETE request failed to remove user from tenant by unknown reason'); } resutil.errResponse(req, res, 400); // 400: Bad Request return; } r3logger.dlog('DELETE request succeed - remove user from tenant'); } res.status(204); // 204: No Content res.send(); }); module.exports = router; /* * 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 */