UNPKG

loganalysis

Version:

Collects stdout and stderr messages from Node.js applications and sends them to the IBM SmartCloud Analytics - Log Analysis service.

436 lines (409 loc) 15.2 kB
/* * © Copyright IBM Corp. 2014 * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ var fs = require('fs'); var assert = require('assert'); var url = require('url'); var querystring = require('querystring'); var logger = require('./logger').newLogger('restClient'); const USER_AGENT = 'Rest Client'; const REAUTH_BEFORE = 2; //minutes (must be less than the value of cacheCushionMax, which defaults to 3 mins) function RestClient(options) { logger.debug('Entering RestClient constructor'); var urlOptions = url.parse(options.url); this.requestPath = urlOptions.path == '/' ? '' : urlOptions.path; this.hostname = urlOptions.hostname; this.httpProtocol = urlOptions.protocol == 'http:'; this.port = urlOptions.port; this.client = this.httpProtocol ? require('http') : require('https'); this.username = options.username; this.password = options.password; this.app_guid = options.app_guid; this.isCloud = options.isCloud; this.CSRFToken = null; this.LTPAToken = null; this.reinitInProgress = false; this.login_data = querystring.stringify({ 'action' : 'Go', 'j_password' : this.password, 'j_username' : this.username }); this.login_opts = { host : this.hostname, path : '/Unity/j_security_check', method : 'POST', headers : { 'Content-Type' : 'application/x-www-form-urlencoded', 'Content-Length' : this.login_data.length, 'accept' : '*/*', Host: this.hostname } }; if(!this.isCloud) { this.ca = fs.readFileSync('client.crt'); this.agent = new this.client.Agent({ host: 'localhost', port: 1337, ca: this.ca, rejectUnauthorized: false }); this.agent.maxSockets = 10; this.login_opts.port = this.port; this.login_opts.agent = this.agent; this.login_opts.ca = [ this.ca ]; this.login_opts.headers.Host = this.hostname + ':' + this.port; } logger.debug('Exiting RestClient constructor'); } RestClient.prototype.reinit = function() { this.reinitInProgress = true; logger.debug('Entering RestClient.prototype.reinit'); this.doLogout(); var _this = this; setTimeout(function(){ _this.doLogin(); }, 5000); logger.debug('Exiting RestClient.prototype.reinit'); } RestClient.prototype.isHTTPProtocol = function () { return this.httpProtocol; }; RestClient.prototype.getServerName = function () { return this.hostname; }; RestClient.prototype.deleteOnce = function (path, callback, options, eventsCallbacks) { logger.debug('Entering RestClient.prototype.deleteOnce'); var deleteOptions = this.createRequestOptions(path, 'DELETE', options); var req = this.client.request(deleteOptions, callback); if (eventsCallbacks) { for (var event in eventsCallbacks) { if (eventsCallbacks.hasOwnProperty(event)) { req.on(event, eventsCallbacks[event]); } } } else { req.on('error', onRequestError); } req.end(); logger.debug('Exiting RestClient.prototype.deleteOnce'); }; RestClient.prototype.getOnce = function (path, callback, options, eventsCallbacks) { logger.debug('Entering RestClient.prototype.getOnce'); var getOptions = this.createRequestOptions(path, 'GET', options); var req = this.client.request(getOptions, callback); if (eventsCallbacks) { for (var event in eventsCallbacks) { if (eventsCallbacks.hasOwnProperty(event)) { req.on(event, eventsCallbacks[event]); } } } else { req.on('error', onRequestError); } req.end(); logger.debug('Exiting RestClient.prototype.getOnce'); }; RestClient.prototype.get = function (path, callback, options, eventsCallbacks) { logger.debug('Entering RestClient.prototype.get'); var getOptions = this.createRequestOptions(path, 'GET', options); var req = this.client.request(getOptions, callback); if (eventsCallbacks) { for (var event in eventsCallbacks) { req.on(event, eventsCallbacks[event]); } } else { req.on('error', onRequestError); } logger.debug('Entering RestClient.prototype.get'); return req; }; RestClient.prototype.postOnce = function (path, body, callback, options, eventsCallbacks) { logger.debug('Entering RestClient.prototype.postOnce'); var postOptions = this.createRequestOptions(path, 'POST', options); var req = this.client.request(postOptions, callback); req.setHeader('Accept', 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8'); req.setHeader('Content-Language', 'en-US'); req.setHeader('Content-Length', Buffer.byteLength(body)); req.write(body); if (eventsCallbacks) { for (var event in eventsCallbacks) { req.on(event, eventsCallbacks[event]); } } else { req.on('error', onRequestError); } req.end(); logger.debug('Exiting RestClient.prototype.postOnce'); }; RestClient.prototype.post = function (path, callback, options, eventsCallbacks) { logger.debug('Entering RestClient.prototype.post'); var postOptions = this.createRequestOptions(path, 'POST', options); var req = this.client.request(postOptions, callback); if (eventsCallbacks) { for (var event in eventsCallbacks) { req.on(event, eventsCallbacks[event]); } } else { req.on('error', onRequestError); } logger.debug('Exiting RestClient.prototype.post'); return req; }; RestClient.prototype.putOnce = function (path, body, callback, options, eventsCallbacks) { logger.debug('Entering RestClient.prototype.putOnce'); var putOptions = this.createRequestOptions(path, 'PUT', options); var req = this.client.request(putOptions, callback); req.setHeader('content-length', Buffer.byteLength(body)); if (eventsCallbacks) { for (var event in eventsCallbacks) { req.on(event, eventsCallbacks[event]); } } else { req.on('error', onRequestError); } req.write(body); req.end(); logger.debug('Exiting RestClient.prototype.putOnce'); }; RestClient.prototype.put = function (path, body, callback, options, eventsCallbacks) { logger.debug('Entering RestClient.prototype.put'); var putOptions = this.createRequestOptions(path, 'PUT', options); var req = this.client.request(putOptions, callback); req.setHeader('Content-Length', Buffer.byteLength(body)); if (eventsCallbacks) { for (var event in eventsCallbacks) { req.on(event, eventsCallbacks[event]); } } else { req.on('error', onRequestError); } req.write(body); logger.debug('Exiting RestClient.prototype.put'); return req; }; RestClient.prototype.createRequestOptions = function (path, method, options) { logger.debug('Entering RestClient.prototype.createRequestOptions'); var ltpa = this.LTPAToken; var csrf = this.CSRFToken; if (ltpa == null || csrf == null) { logger.error('LTPA or CSRF token is null'); } var cookie = ltpa && csrf ? ltpa + csrf + ';' : ''; if(csrf && (method == 'PUT' || method == 'POST')){ path = path + (path.indexOf('?') > 0 ? '&' : '?') + csrf; } var reqOpts = { hostname: this.hostname, port: this.port, path: this.requestPath + path, method: method, headers: { 'User-Agent': USER_AGENT, 'Cookie': [cookie] } }; if(!this.isCloud) { reqOpts.agent = this.agent; } if (method == 'POST' || method == 'PUT') { reqOpts.headers['Content-Type'] = 'application/json'; } if (options) { for (var key in options) { if (key == 'headers') { var headers = options.headers; for (var headerName in headers) { reqOpts.headers[headerName] = headers[headerName]; } } else { reqOpts[key] = options[key]; } } } logger.debug('Exiting RestClient.prototype.createRequestOptions'); return reqOpts; }; function onRequestError(e) { logger.error('Fail to execute request, the error message is ' + (e && e.message ? e.message : '')); } RestClient.prototype.doLogout = function () { logger.debug('Entering RestClient.prototype.doLogout'); logger.debug('Trying to log out from SCALA'); var getReq = this.get('/Unity/jsp/logoff.jsp?' + this.CSRFToken, function(res) { var getResponseData = ''; res.on('data', function (data) { getResponseData += data; }); res.on('end', function () { logger.debug('Response data for logout ' + getResponseData); }); res.on('error', function (e) { logger.error('Failed to log off due to ' + (e && e.message ? e.message : '')); }); if (res.statusCode == 302) { logger.debug('Cookies in logout response header: ' + res.headers['set-cookie']); this.LTPAToken = null; this.CSRFToken = null; logger.info('Logged out of scala'); } }); getReq.on('error', function (e) { logger.error('Failed to logout due to ' + (e && e.message ? e.message : '')); }); getReq.end(); logger.debug('Exiting RestClient.prototype.doLogout'); } RestClient.prototype.reauthenticate = function () { logger.debug('Entering RestClient.prototype.reauthenticate'); var _this = this; try{ logger.debug('Trying to re-authenticate with SCALA, as the LTPA token is about to expire'); var reauthReq = _this.get('/Unity/LTPAToken/reauthenticate?j_username=' + _this.username + '&j_password=' + _this.password, function(res){ var reauthResData = ''; res.on('data', function (d) { reauthResData += d; }); res.on('end', function () { logger.debug('Response for LTPA reauthentication ' + reauthResData); if (reauthResData.trim() != '') { var reauthRes = JSON.parse(reauthResData); if (reauthRes && reauthRes.reauthenticate === true) { var ltpa = res.headers['set-cookie'][0].split(';')[0].trim() + ';'; if (ltpa === _this.LTPAToken) { logger.error('New LTPA token is same as earlier one!'); } logger.debug('Re-authentication successful!'); _this.LTPAToken = ltpa; _this.scheduleReauth(); } else { logger.error('Could not re-authenticate into SCALA'); } } else { logger.error('Could not re-authenticate into SCALA, received empty response!'); } }); res.on('error', function(e) { logger.error('Could not log reauthenticate, due to: ' + e); }); }); reauthReq.end(); } catch (e) { logger.error('Clould not re-authenticate, due to ' + e); } logger.debug('Exiting RestClient.prototype.reauthenticate'); } RestClient.prototype.scheduleReauth = function () { logger.debug('Entering RestClient.prototype.scheduleReauth'); var _this = this; try{ var expReq = this.get('/Unity/LTPAToken/expiration', function(res){ var expResData = ''; res.on('data', function (data) { expResData += data; }); expReq.on('error', function(e) { logger.error(e); logger.error('Could not get LTPA exipry period'); }); res.on('end', function () { assert.strictEqual(200, res.statusCode); logger.debug('Response for querying LTPA expiration ' + expResData); if (expResData.trim() != '') { var ltpaExpInfo = JSON.parse(expResData); var timeout = ltpaExpInfo.ltpaexpiration - ltpaExpInfo.currentservertime - REAUTH_BEFORE * 60000; logger.debug('Scheduling reauthentication after ' + timeout/1000 + ' seconds'); setTimeout(function() { _this.reauthenticate(); }, timeout); } else { logger.error('Could not get LTPA exipry period, received empty response!'); } }); res.on('error', function(e) { logger.error('Could not schedule reauthentication, due to: ' + e); }); }); expReq.end(); } catch (e) { logger.error('Clould not schedule reauthentication, due to: ' + e); } logger.debug('Exiting RestClient.prototype.scheduleReauth'); } RestClient.prototype.doLogin = function () { logger.debug('Entering RestClient.prototype.doLogin'); logger.debug('Trying to log into SCALA'); var _this = this; try { var post_req = this.client.request(this.login_opts, function(res) { res.setEncoding('utf8'); res.on('error', function (e) { logger.error('Failed to log in to scala server due to ' + (e && e.message ? e.message : '')); }); res.on('data', function (data) {}); res.on('end', function () { var ltpaCookie = res.headers['set-cookie']; if (ltpaCookie != null) { assert.strictEqual(302, res.statusCode); _this.LTPAToken = ltpaCookie[0].split(';')[0].trim() + ';'; logger.debug(_this.LTPAToken); var hheaders = { Cookie : [_this.LTPAToken], Accept : '*/*', Host: _this.hostname }; var hoptions = { method : 'GET', host : _this.hostname, path : '/Unity/', headers : hheaders }; if(!_this.isCloud) { hheaders.Host = _this.hostname + ':' + _this.port; hoptions.port = _this.port; hoptions.agent = _this.agent; hoptions.ca = [ _this.ca ]; } var hreq = _this.client.request(hoptions, function(hres) { hres.on('error', function (e) { logger.error('Failed to log in to scala server due to ' + (e && e.message ? e.message : '')); }); hres.on('data', function (data) {}); hres.on('end', function () { var csrfCookie = hres.headers['set-cookie']; if (csrfCookie != null) { assert.strictEqual(200, hres.statusCode); _this.CSRFToken = csrfCookie[0].split(';')[0].trim(); _this.reinitInProgress = false; logger.debug('Successfully logged into SCALA: ' + _this.hostname +'; fetched CSRF & LTPA tokens!'); _this.scheduleReauth(); } else { logger.error('Could not log into SCALA, could not get CSRF token'); } }); }); hreq.on('error', function(e) { logger.error('Could not log into SCALA, due to: ' + e); }); hreq.end(); } else { logger.error('Could not log into SCALA, could not get LTPA token'); } }); }); post_req.on('error', function(e) { logger.error('Could not log into SCALA, due to: ' + e); }); post_req.write(this.login_data); post_req.end(); } catch (e) { logger.error(e); } logger.debug('Exiting RestClient.prototype.doLogin'); } exports.createRestClient = function (options) { var client = new RestClient(options); client.doLogin(); return client; };