pomelo-admin1312
Version:
`pomelo-admin1312` is an admin console library for [pomelo](https://github.com/NetEase/pomelo). It provides the a series of utilities to monitor the `pomelo` server clusters.
727 lines (675 loc) • 17 kB
JavaScript
/*!
* Pomelo -- consoleModule watchServer
* Copyright(c) 2013 fantasyni <fantasyni@163.com>
* MIT Licensed
*/
var logger = require('pomelo-logger').getLogger('pomelo-admin', __filename);
var countDownLatch = require('../util/countDownLatch');
var monitor = require('pomelo-monitor');
var utils = require('../util/utils');
var util = require('util');
var fs = require('fs');
var vm = require('vm');
module.exports = function(opts) {
return new Module(opts);
};
module.exports.moduleId = 'watchServer';
var Module = function(opts) {
opts = opts || {};
this.app = opts.app;
};
Module.prototype.monitorHandler = function(agent, msg, cb) {
var comd = msg['comd'];
var context = msg['context'];
var param = msg['param'];
var app = this.app;
var handle = 'monitor';
switch (comd) {
case 'servers':
showServers(handle, agent, comd, context, cb);
break;
case 'connections':
showConnections(handle, agent, app, comd, context, cb);
break;
case 'logins':
showLogins(handle, agent, app, comd, context, cb);
break;
case 'modules':
showModules(handle, agent, comd, context, cb);
break;
case 'status':
showStatus(handle, agent, comd, context, cb);
break;
case 'config':
showConfig(handle, agent, app, comd, context, param, cb);
break;
case 'proxy':
showProxy(handle, agent, app, comd, context, param, cb);
break;
case 'handler':
showHandler(handle, agent, app, comd, context, param, cb);
break;
case 'components':
showComponents(handle, agent, app, comd, context, param, cb);
break;
case 'settings':
showSettings(handle, agent, app, comd, context, param, cb);
break;
case 'cpu':
dumpCPU(handle, agent, comd, context, param, cb);
break;
case 'memory':
dumpMemory(handle, agent, comd, context, param, cb);
break;
case 'get':
getApp(handle, agent, app, comd, context, param, cb);
break;
case 'set':
setApp(handle, agent, app, comd, context, param, cb);
break;
case 'enable':
enableApp(handle, agent, app, comd, context, param, cb);
break;
case 'disable':
disableApp(handle, agent, app, comd, context, param, cb);
break;
case 'run':
runScript(handle, agent, app, comd, context, param, cb);
break;
default:
showError(handle, agent, comd, context, cb);
}
};
Module.prototype.clientHandler = function(agent, msg, cb) {
var comd = msg['comd'];
var context = msg['context'];
var param = msg['param'];
var app = this.app; // master app
if (!comd || !context) {
cb('lack of comd or context param');
return;
}
var handle = 'client';
switch (comd) {
case 'servers':
showServers(handle, agent, comd, context, cb);
break;
case 'connections':
showConnections(handle, agent, app, comd, context, cb);
break;
case 'logins':
showLogins(handle, agent, app, comd, context, cb);
break;
case 'modules':
showModules(handle, agent, comd, context, cb);
break;
case 'status':
showStatus(handle, agent, comd, context, cb);
break;
case 'config':
showConfig(handle, agent, app, comd, context, param, cb);
break;
case 'proxy':
showProxy(handle, agent, app, comd, context, param, cb);
break;
case 'handler':
showHandler(handle, agent, app, comd, context, param, cb);
break;
case 'components':
showComponents(handle, agent, app, comd, context, param, cb);
break;
case 'settings':
showSettings(handle, agent, app, comd, context, param, cb);
break;
case 'cpu':
dumpCPU(handle, agent, comd, context, param, cb);
break;
case 'memory':
dumpMemory(handle, agent, comd, context, param, cb);
break;
case 'get':
getApp(handle, agent, app, comd, context, param, cb);
break;
case 'set':
setApp(handle, agent, app, comd, context, param, cb);
break;
case 'enable':
enableApp(handle, agent, app, comd, context, param, cb);
break;
case 'disable':
disableApp(handle, agent, app, comd, context, param, cb);
break;
case 'run':
runScript(handle, agent, app, comd, context, param, cb);
break;
default:
showError(handle, agent, comd, context, cb);
}
};
function showServers(handle, agent, comd, context, cb) {
if (handle === 'client') {
var sid, record;
var serverInfo = {};
var count = utils.size(agent.idMap);
var latch = countDownLatch.createCountDownLatch(count, function() {
cb(null, {
msg: serverInfo
});
});
for (sid in agent.idMap) {
record = agent.idMap[sid];
agent.request(record.id, module.exports.moduleId, {
comd: comd,
context: context
}, function(msg) {
serverInfo[msg.serverId] = msg.body;
latch.done();
});
}
} else if (handle === 'monitor') {
var serverId = agent.id;
var serverType = agent.type;
var info = agent.info;
var pid = process.pid;
var heapUsed = (process.memoryUsage().heapUsed / (1000 * 1000)).toFixed(2);
var uptime = (process.uptime() / 60).toFixed(2);
cb({
serverId: serverId,
body: {
serverId: serverId,
serverType: serverType,
host: info['host'],
port: info['port'],
pid: pid,
heapUsed: heapUsed,
uptime: uptime
}
});
}
}
function showConnections(handle, agent, app, comd, context, cb) {
if (handle === 'client') {
if (context === 'all') {
var sid, record;
var serverInfo = {};
var count = 0;
for (var key in agent.idMap) {
if (agent.idMap[key].info.frontend === 'true') {
count++;
}
}
var latch = countDownLatch.createCountDownLatch(count, function() {
cb(null, {
msg: serverInfo
});
});
for (sid in agent.idMap) {
record = agent.idMap[sid];
if (record.info.frontend === 'true') {
agent.request(record.id, module.exports.moduleId, {
comd: comd,
context: context
}, function(msg) {
serverInfo[msg.serverId] = msg.body;
latch.done();
});
}
}
} else {
var record = agent.idMap[context];
if (!record) {
cb("the server " + context + " not exist");
}
if (record.info.frontend === 'true') {
agent.request(record.id, module.exports.moduleId, {
comd: comd,
context: context
}, function(msg) {
var serverInfo = {};
serverInfo[msg.serverId] = msg.body;
cb(null, {
msg: serverInfo
});
});
} else {
cb('\nthis command should be applied to frontend server\n');
}
}
} else if (handle === 'monitor') {
var connection = app.components.__connection__;
if (!connection) {
cb({
serverId: agent.id,
body: 'error'
});
return;
}
cb({
serverId: agent.id,
body: connection.getStatisticsInfo()
});
}
}
function showLogins(handle, agent, app, comd, context, cb) {
showConnections(handle, agent, app, comd, context, cb);
}
function showModules(handle, agent, comd, context, cb) {
var modules = agent.consoleService.modules;
var result = [];
for (var module in modules) {
result.push(module);
}
cb(null, {
msg: result
});
}
function showStatus(handle, agent, comd, context, cb) {
if (handle === 'client') {
agent.request(context, module.exports.moduleId, {
comd: comd,
context: context
}, function(err, msg) {
cb(null, {
msg: msg
});
});
} else if (handle === 'monitor') {
var serverId = agent.id;
var pid = process.pid;
var params = {
serverId: serverId,
pid: pid
};
monitor.psmonitor.getPsInfo(params, function(err, data) {
cb(null, {
serverId: agent.id,
body: data
})
});
}
}
function showConfig(handle, agent, app, comd, context, param, cb) {
if (handle === 'client') {
if (param === 'master') {
cb(null, {
masterConfig: app.get('masterConfig') || 'no config to master in app.js',
masterInfo: app.get('master')
});
return;
}
agent.request(context, module.exports.moduleId, {
comd: comd,
param: param,
context: context
}, function(err, msg) {
cb(null, msg);
});
} else if (handle === 'monitor') {
var key = param + 'Config';
cb(null, clone(param, app.get(key)));
}
}
function showProxy(handle, agent, app, comd, context, param, cb) {
if (handle === 'client') {
if (context === 'all') {
cb('context error');
return;
}
agent.request(context, module.exports.moduleId, {
comd: comd,
param: param,
context: context
}, function(err, msg) {
cb(null, msg);
});
} else if (handle === 'monitor') {
proxyCb(app, context, cb);
}
}
function showHandler(handle, agent, app, comd, context, param, cb) {
if (handle === 'client') {
if (context === 'all') {
cb('context error');
return;
}
agent.request(context, module.exports.moduleId, {
comd: comd,
param: param,
context: context
}, function(err, msg) {
cb(null, msg);
});
} else if (handle === 'monitor') {
handlerCb(app, context, cb);
}
}
function showComponents(handle, agent, app, comd, context, param, cb) {
if (handle === 'client') {
if (context === 'all') {
cb('context error');
return;
}
agent.request(context, module.exports.moduleId, {
comd: comd,
param: param,
context: context
}, function(err, msg) {
cb(null, msg);
});
} else if (handle === 'monitor') {
var _components = app.components;
var res = {};
for (var key in _components) {
var name = getComponentName(key);
res[name] = clone(name, app.get(name + 'Config'))
}
cb(null, res);
}
}
function showSettings(handle, agent, app, comd, context, param, cb) {
if (handle === 'client') {
if (context === 'all') {
cb('context error');
return;
}
agent.request(context, module.exports.moduleId, {
comd: comd,
param: param,
context: context
}, function(err, msg) {
cb(null, msg);
});
} else if (handle === 'monitor') {
var _settings = app.settings;
var res = {};
for (var key in _settings) {
if (key.match(/^__\w+__$/) || key.match(/\w+Config$/)) {
continue;
}
if (!checkJSON(_settings[key])) {
res[key] = 'Object';
continue;
}
res[key] = _settings[key];
}
cb(null, res);
}
}
function dumpCPU(handle, agent, comd, context, param, cb) {
if (handle === 'client') {
if (context === 'all') {
cb('context error');
return;
}
agent.request(context, module.exports.moduleId, {
comd: comd,
param: param,
context: context
}, function(err, msg) {
cb(err, msg);
});
} else if (handle === 'monitor') {
var times = param['times'];
var filepath = param['filepath'];
var force = param['force'];
cb(null, 'cpu dump is unused in 1.0 of pomelo');
/**
if (!/\.cpuprofile$/.test(filepath)) {
filepath = filepath + '.cpuprofile';
}
if (!times || !/^[0-9]*[1-9][0-9]*$/.test(times)) {
cb('no times or times invalid error');
return;
}
checkFilePath(filepath, force, function(err) {
if (err) {
cb(err);
return;
}
//ndump.cpu(filepath, times);
cb(null, filepath + ' cpu dump ok');
});
*/
}
}
function dumpMemory(handle, agent, comd, context, param, cb) {
if (handle === 'client') {
if (context === 'all') {
cb('context error');
return;
}
agent.request(context, module.exports.moduleId, {
comd: comd,
param: param,
context: context
}, function(err, msg) {
cb(err, msg);
});
} else if (handle === 'monitor') {
var filepath = param['filepath'];
var force = param['force'];
if (!/\.heapsnapshot$/.test(filepath)) {
filepath = filepath + '.heapsnapshot';
}
checkFilePath(filepath, force, function(err) {
if (err) {
cb(err);
return;
}
var heapdump = null;
try {
heapdump = require('heapdump');
heapdump.writeSnapshot(filepath);
cb(null, filepath + ' memory dump ok')
} catch (e) {
cb('pomelo-admin require heapdump');
}
});
}
}
function getApp(handle, agent, app, comd, context, param, cb) {
if (handle === 'client') {
if (context === 'all') {
cb('context error');
return;
}
agent.request(context, module.exports.moduleId, {
comd: comd,
param: param,
context: context
}, function(err, msg) {
cb(null, msg);
});
} else if (handle === 'monitor') {
var res = app.get(param);
if (!checkJSON(res)) {
res = 'object';
}
cb(null, res || null);
}
}
function setApp(handle, agent, app, comd, context, param, cb) {
if (handle === 'client') {
if (context === 'all') {
cb('context error');
return;
}
agent.request(context, module.exports.moduleId, {
comd: comd,
param: param,
context: context
}, function(err, msg) {
cb(null, msg);
});
} else if (handle === 'monitor') {
var key = param['key'];
var value = param['value'];
app.set(key, value);
cb(null, 'set ' + key + ':' + value + ' ok');
}
}
function enableApp(handle, agent, app, comd, context, param, cb) {
if (handle === 'client') {
if (context === 'all') {
cb('context error');
return;
}
agent.request(context, module.exports.moduleId, {
comd: comd,
param: param,
context: context
}, function(err, msg) {
cb(null, msg);
});
} else if (handle === 'monitor') {
app.enable(param);
cb(null, 'enable ' + param + ' ok');
}
}
function disableApp(handle, agent, app, comd, context, param, cb) {
if (handle === 'client') {
if (context === 'all') {
cb('context error');
return;
}
agent.request(context, module.exports.moduleId, {
comd: comd,
param: param,
context: context
}, function(err, msg) {
cb(null, msg);
});
} else if (handle === 'monitor') {
app.disable(param);
cb(null, 'disable ' + param + ' ok');
}
}
function runScript(handle, agent, app, comd, context, param, cb) {
if (handle === 'client') {
if (context === 'all') {
cb('context error');
return;
}
agent.request(context, module.exports.moduleId, {
comd: comd,
param: param,
context: context
}, function(err, msg) {
cb(null, msg);
});
} else if (handle === 'monitor') {
var ctx = {
app: app,
result: null
};
try {
vm.runInNewContext('result = ' + param, ctx, 'myApp.vm');
cb(null, util.inspect(ctx.result));
} catch (e) {
cb(null, e.stack);
}
}
}
function showError(handle, agent, comd, context, cb) {
}
function clone(param, obj) {
var result = {};
var flag = 1;
for (var key in obj) {
if (typeof obj[key] === 'function' || typeof obj[key] === 'object') {
continue;
}
flag = 0;
result[key] = obj[key];
}
if (flag) {
// return 'no ' + param + 'Config info';
}
return result;
}
function checkFilePath(filepath, force, cb) {
if (!force && fs.existsSync(filepath)) {
cb('filepath file exist');
return;
}
fs.writeFile(filepath, 'test', function(err) {
if (err) {
cb('filepath invalid error');
return;
}
fs.unlinkSync(filepath);
cb(null);
})
}
function proxyCb(app, context, cb) {
var msg = {};
var __proxy__ = app.components.__proxy__;
if (__proxy__ && __proxy__.client && __proxy__.client.proxies.user) {
var proxies = __proxy__.client.proxies.user;
var server = app.getServerById(context);
if (!server) {
cb('no server with this id ' + context);
} else {
var type = server['serverType'];
var tmp = proxies[type];
msg[type] = {};
for (var _proxy in tmp) {
var r = tmp[_proxy];
msg[type][_proxy] = {};
for (var _rpc in r) {
if (typeof r[_rpc] === 'function') {
msg[type][_proxy][_rpc] = 'function';
}
}
}
cb(null, msg);
}
} else {
cb('no proxy loaded');
}
}
function handlerCb(app, context, cb) {
var msg = {};
var __server__ = app.components.__server__;
if (__server__ && __server__.server && __server__.server.handlerService.handlers) {
var handles = __server__.server.handlerService.handlers;
var server = app.getServerById(context);
if (!server) {
cb('no server with this id ' + context);
} else {
var type = server['serverType'];
var tmp = handles;
msg[type] = {};
for (var _p in tmp) {
var r = tmp[_p];
msg[type][_p] = {};
for (var _r in r) {
if (typeof r[_r] === 'function') {
msg[type][_p][_r] = 'function';
}
}
}
cb(null, msg);
}
} else {
cb('no handler loaded');
}
}
function getComponentName(c) {
var t = c.match(/^__(\w+)__$/);
if (t) {
t = t[1];
}
return t;
}
function checkJSON(obj) {
if (!obj) {
return true;
}
try {
JSON.stringify(obj);
} catch (e) {
return false;
}
return true;
}