Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge "Closes-Bug: #1446910 Enhancements & Performance Fix for Server…
…-Manager Monitoring"
- Loading branch information
Showing
16 changed files
with
782 additions
and
407 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,270 @@ | ||
/* | ||
* Copyright (c) 2014 Juniper Networks, Inc. All rights reserved. | ||
*/ | ||
|
||
var http = require('http'), | ||
config = process.mainModule.exports.config, | ||
logutils = require('../utils/log.utils'), | ||
messages = require('./messages'), | ||
appErrors = require('../errors/app.errors'), | ||
util = require('util'), | ||
commonUtils = require('../utils/common.utils'), | ||
restler = require('restler'), | ||
fs = require('fs'), | ||
global = require('./global'), | ||
httpsOp = require('./httpsoptions.api'), | ||
request = require('request'), | ||
discClient = require('./discoveryclient.api'); | ||
|
||
if (!module.parent) { | ||
logutils.logger.warn(util.format(messages.warn.invalid_mod_call, module.filename)); | ||
process.exit(1); | ||
} | ||
|
||
/** | ||
* Constructor to API server access. | ||
* @param {Object} Parameters required to define a new API server | ||
*/ | ||
function APIServer(params) { | ||
var self = this; | ||
self.hostname = params.server; | ||
self.port = params.port; | ||
self.api = new self.API(self, params.apiName); | ||
} | ||
|
||
/** | ||
* Authenticate and call the callback function on successful authentication. | ||
* @param {Function} Callback function | ||
*/ | ||
APIServer.prototype.authorize = function (callback) { | ||
var self = this; | ||
// TODO: Implement Authentication. | ||
self.cb(callback); | ||
}; | ||
|
||
/** | ||
* Constructor to API. | ||
* @param {Object} API server object | ||
* @param {String} Name of the API | ||
*/ | ||
APIServer.prototype.API = function (self, apiName) { | ||
self.name = apiName; | ||
return { | ||
hostname: self.hostname, | ||
port: self.port, | ||
name: apiName, | ||
get: function (url, callback, headers) { | ||
var s = this, | ||
obj = { | ||
url: s.hostname, path: url, method: 'GET', port: s.port, headers: headers | ||
}; | ||
self.makeCall(restler.get, obj, callback, false); | ||
}, | ||
post: function (url, data, callback, headers) { | ||
var s = this, | ||
obj = { | ||
url: s.hostname, path: url, method: 'POST', port: s.port, data: data, headers: headers | ||
}; | ||
self.makeCall(restler.post, obj, callback, false); | ||
}, | ||
put: function (url, data, callback, headers) { | ||
var s = this, | ||
obj = { | ||
url: s.hostname, path: url, method: 'PUT', port: s.port, data: data, headers: headers | ||
}; | ||
self.makeCall(restler.put, obj, callback, false); | ||
}, | ||
delete: function (url, callback, headers) { | ||
var s = this, | ||
obj = { | ||
url: s.hostname, path: url, method: 'DELETE', port: s.port, headers: headers | ||
}; | ||
self.makeCall(restler.del, obj, callback, false); | ||
} | ||
}; | ||
}; | ||
|
||
/** | ||
* Check if given callback is a function and call it. | ||
* @param {Function} Callback function | ||
*/ | ||
APIServer.prototype.cb = function (cb) { | ||
if (typeof cb == 'function') { | ||
cb(); | ||
} | ||
}; | ||
|
||
/** | ||
* Update the host/port from discovery server response | ||
* @param {params} {object} Parameters | ||
*/ | ||
APIServer.prototype.updateDiscoveryServiceParams = function (params) { | ||
var opS = require('./opServer.api'); | ||
var configS = require('./configServer.api'); | ||
var server = null; | ||
var self = this; | ||
var apiServerType = self.name; | ||
var discService = null; | ||
|
||
discService = discClient.getDiscServiceByApiServerType(apiServerType); | ||
if (discService) { | ||
/* We are sending only the first IP */ | ||
if (discService['ip-address'] != null) { | ||
params.url = discService['ip-address']; | ||
} | ||
if (discService['port'] != null) { | ||
params.port = discService['port']; | ||
} | ||
} | ||
return params; | ||
} | ||
|
||
/** | ||
* Make a https call to server. | ||
* @param {options} {object} Parameters | ||
* @param {callback} {function} Callback function once response comes | ||
* from Server | ||
*/ | ||
|
||
APIServer.prototype.makeHttpsRestCall = function (options, callback) { | ||
request(options, function (err, response, data) { | ||
callback(err, data, response); | ||
}); | ||
} | ||
|
||
/** Retry the REST API Call, once it fails | ||
* @param {err} {object} error object got from previous error response | ||
* @param {restApi} {function} restler API based on method | ||
* @param {params} {object} Parameters | ||
* @param {response} {object} Response Object | ||
* @param {callback} {function} Callback function once response comes | ||
* from Server | ||
* @param {isRetry} {bool} boolean flag if it is already a retry call | ||
*/ | ||
APIServer.prototype.retryMakeCall = function (err, restApi, params, response, callback, isRetry) { | ||
var self = this; | ||
/* Check if the error code is ECONNREFUSED or ETIMEOUT, if yes then | ||
* issue once again discovery subscribe request, the remote server | ||
* may be down, so discovery server should send the Up Servers now | ||
*/ | ||
if ((true == process.mainModule.exports['discServEnable']) && | ||
(('ECONNREFUSED' == err.code) || ('ETIMEOUT' == err.code))) { | ||
if (false == isRetry) { | ||
/* Only one time send a retry */ | ||
discClient.sendDiscSubMessageOnDemand(self.name); | ||
} | ||
var reqParams = null; | ||
reqParams = discClient.resetServicesByParams(params, self.name); | ||
if (null != reqParams) { | ||
return self.makeCall(restApi, reqParams, callback, true); | ||
} | ||
} | ||
error = new appErrors.RESTServerError(util.format(err)); | ||
error['custom'] = true; | ||
error['responseCode'] = ((null != response) && | ||
(null != response.statusCode)) ? | ||
response.statusCode : | ||
global.HTTP_STATUS_INTERNAL_ERROR; | ||
error['code'] = err.code; | ||
callback(error, '', response); | ||
} | ||
|
||
/** | ||
* Send the parsed response data to APP | ||
* @param {data} {object} response data either in xml/json format | ||
* @param {response} {object} response object | ||
* @param {callback} {function} Callback function to call once data parsing is done | ||
*/ | ||
APIServer.prototype.sendParsedDataToApp = function (data, response, callback) { | ||
|
||
try { | ||
var JSONData = JSON.parse(data); | ||
callback(null, JSONData, response); | ||
} catch (e) { | ||
callback(null, data, response); | ||
} | ||
} | ||
|
||
/** | ||
* Make a call to API server. | ||
* @param {restApi} {function} restler API based on method | ||
* @param {params} {object} Parameters | ||
* @param {callback} {function} Callback function once response comes | ||
from API Server | ||
*/ | ||
APIServer.prototype.makeCall = function (restApi, params, callback, isRetry) { | ||
var self = this; | ||
var reqUrl = null; | ||
var options = {}; | ||
var data = commonUtils.getApiPostData(params['path'], params['data']); | ||
var method = params['method']; | ||
options['headers'] = params['headers'] || {}; | ||
options['data'] = data || {}; | ||
options['method'] = method; | ||
options['headers']['Content-Length'] = (data) ? data.toString().length : 0; | ||
|
||
if ((method == 'POST') || (method == 'PUT')) { | ||
/* When we need to send the data along with options (POST/PUT) | ||
we need to specify the Content-Type as App/JSON with JSON.stringify | ||
of the data, otherwise, restler treats it as | ||
application/x-www-form-urlencoded as Content-Type and encodes | ||
the data accordingly | ||
*/ | ||
options['headers']['Content-Type'] = 'application/json'; | ||
} | ||
params = self.updateDiscoveryServiceParams(params); | ||
options['parser'] = restler.parsers.auto; | ||
options = httpsOp.updateHttpsSecureOptions(self.name, options); | ||
if ((null != options['headers']) && (null != options['headers']['protocol']) && (global.PROTOCOL_HTTPS == options['headers']['protocol'])) { | ||
delete options['headers']['protocol']; | ||
reqUrl = global.HTTPS_URL + params.url + ':' + params.port + params.path; | ||
options['uri'] = reqUrl; | ||
options['body'] = options['data']; | ||
if (('POST' != method) && ('PUT' != method)) { | ||
delete options['data']; | ||
delete options['body']; | ||
} | ||
self.makeHttpsRestCall(options, function (err, data, response) { | ||
if (null != err) { | ||
try { | ||
logutils.logger.error('URL [' + reqUrl + ']' + | ||
' returned error [' + | ||
JSON.stringify(err) + ']'); | ||
} catch (e) { | ||
logutils.logger.error('URL [' + reqUrl + ']' + | ||
' returned error [' + err + ']'); | ||
} | ||
self.retryMakeCall(err, restApi, params, response, callback, false); | ||
} else { | ||
self.sendParsedDataToApp(data, response, callback); | ||
} | ||
}); | ||
return; | ||
} | ||
reqUrl = global.HTTP_URL + params.url + ':' + params.port + params.path; | ||
restApi(reqUrl, options).on('complete', function (data, response) { | ||
if (data instanceof Error || | ||
parseInt(response.statusCode) >= 400) { | ||
try { | ||
logutils.logger.error('URL [' + reqUrl + ']' + | ||
' returned error [' + JSON.stringify(data) + ']'); | ||
} catch (e) { | ||
logutils.logger.error('URL [' + reqUrl + ']' + | ||
' returned error [' + data + ']'); | ||
} | ||
self.retryMakeCall(data, restApi, params, response, callback, false); | ||
} else { | ||
self.sendParsedDataToApp(data, response, callback); | ||
} | ||
}); | ||
} | ||
|
||
// Export this as a module. | ||
module.exports.getAPIServer = function (params) { | ||
return new APIServer(params); | ||
}; | ||
|
||
// Export this as a module. | ||
module.exports.getSOAPApiServer = function (params) { | ||
return new APIServer(params); | ||
}; |
Oops, something went wrong.