pm2/lib/Interactor/Daemon.js

271 lines
7.2 KiB
JavaScript

var fs = require('fs');
var ipm2 = require('pm2-interface');
var rpc = require('pm2-axon-rpc');
var axon = require('pm2-axon');
var debug = require('debug')('interface:driver'); // Interface
var chalk = require('chalk');
var pkg = require('../../package.json');
var cst = require('../../constants.js');
var Cipher = require('./Cipher.js');
var Filter = require('./Filter.js');
var ReverseInteractor = require('./ReverseInteractor.js');
var PushInteractor = require('./PushInteractor.js');
var WatchDog = require('./WatchDog.js');
var Url = require('url');
var os = require('os');
var HttpRequest = require('./HttpRequest.js');
var Daemon = {
connectToPM2 : function() {
return ipm2({bind_host: 'localhost'});
},
exit : function() {
setTimeout(function() {
if (!this._rpc || !this._rpc.sock)
return process.exit(cst.ERROR_EXIT);
this._rpc.sock.close(function() {
process.exit(cst.SUCCESS_EXIT);
});
}, 100);
},
activateRPC : function() {
console.log('Launching Interactor exposure');
var self = this;
var rep = axon.socket('rep');
var daemon_server = new rpc.Server(rep);
var sock = rep.bind(cst.INTERACTOR_RPC_PORT);
daemon_server.expose({
kill : function(cb) {
console.log('Killing interactor');
cb(null);
Daemon.exit();
},
getInfos : function(cb) {
return cb(null, {
machine_name : self.opts.MACHINE_NAME,
public_key : self.opts.PUBLIC_KEY,
secret_key : self.opts.SECRET_KEY,
remote_host : cst.REMOTE_HOST,
remote_port : cst.REMOTE_PORT,
reverse_interaction : self.opts.REVERSE_INTERACT
});
}
});
return daemon_server;
},
formatMetada : function() {
var cpu, memory;
var self = this;
try {
cpu = os.cpus();
memory = Math.floor(os.totalmem() / 1024 / 1024);
} catch(e) {
cpu = 0;
memory = 0;
};
var ciphered_data = Cipher.cipherMessage(JSON.stringify({
MACHINE_NAME : this.opts.MACHINE_NAME,
PUBLIC_KEY : this.opts.PUBLIC_KEY,
PM2_VERSION : this.opts.PM2_VERSION,
MEMORY : memory,
HOSTNAME : os.hostname(),
CPUS : cpu.length
}), this.opts.SECRET_KEY);
return ciphered_data;
},
refreshWorker : function() {
var self = this;
function refreshMetadata() {
var ciphered_data = Daemon.formatMetada();
HttpRequest.post({
url : self.opts.ROOT_URL,
port : self.opts.ROOT_PORT,
data : {
public_id : self.opts.PUBLIC_KEY,
data : ciphered_data
}
}, function(err, km_data) {
if (err) return console.error(err);
if (km_data.disabled == true) {
console.error(chalk.cyan('[Keymetrics.io]') + ' Server DISABLED BY ADMINISTRATION contact support contact@keymetrics.io with reference to your public and secret keys)');
return Daemon.exit();
}
/**************************************
* Urls has changed = update workers *
**************************************/
if ((Daemon.current_km_data.endpoints.push != km_data.endpoints.push) ||
(Daemon.current_km_data.endpoints.reverse != km_data.endpoints.reverse)) {
console.log('[Interactor] Urls changed');
PushInteractor.changeUrl(km_data.endpoints.push);
ReverseInteractor.changeUrl(km_data.endpoints.reverse);
Daemon.current_km_data = km_data;
}
return false;
});
};
// Refresh metadata every 10 minutes
setInterval(function() {
refreshMetadata();
}, 60000 * 10);
},
validateData : function() {
var opts = {};
opts.MACHINE_NAME = process.env.PM2_MACHINE_NAME;
opts.PUBLIC_KEY = process.env.PM2_PUBLIC_KEY;
opts.SECRET_KEY = process.env.PM2_SECRET_KEY;
opts.REVERSE_INTERACT = JSON.parse(process.env.PM2_REVERSE_INTERACT);
opts.PM2_VERSION = pkg.version;
if (!opts.MACHINE_NAME) {
console.error('You must provide a PM2_MACHINE_NAME environment variable');
process.exit(cst.ERROR_EXIT);
}
else if (!opts.PUBLIC_KEY) {
console.error('You must provide a PM2_PUBLIC_KEY environment variable');
process.exit(cst.ERROR_EXIT);
}
else if (!opts.SECRET_KEY) {
console.error('You must provide a PM2_SECRET_KEY environment variable');
process.exit(cst.ERROR_EXIT);
}
return opts;
},
welcome : function(cb) {
var self = this;
var ciphered_data = Daemon.formatMetada();
if (!ciphered_data) {
process.send({
msg : 'Error while ciphering data',
error : true
});
return process.exit(1);
}
HttpRequest.post({
url : self.opts.ROOT_URL,
port : self.opts.ROOT_PORT,
data : {
public_id : this.opts.PUBLIC_KEY,
data : ciphered_data
}
}, function(err, km_data) {
self.current_km_data = km_data;
if (err) {
return cb(err);
}
// For Human feedback
if (process.send)
process.send({
error : false,
km_data : km_data,
online : true,
pid : process.pid,
machine_name : self.opts.MACHINE_NAME,
public_key : self.opts.PUBLIC_KEY,
secret_key : self.opts.SECRET_KEY,
reverse_interaction : self.opts.REVERSE_INTERACT
});
// Return get data
return cb(null, km_data);
});
},
start : function() {
var self = this;
self.opts = self.validateData();
self.opts.ipm2 = null;
self.current_km_data = null;
self._rpc = self.activateRPC();
// WatchDog.start({
// conf : self.opts
// });
if (cst.DEBUG) {
self.opts.ROOT_URL = '127.0.0.1';
if (process.env.NODE_ENV == 'test')
self.opts.ROOT_PORT = 3400;
else
self.opts.ROOT_PORT = 3000;
}
else {
self.opts.ROOT_URL = cst.KEYMETRICS_ROOT_URL;
self.opts.ROOT_PORT = 443;
}
Daemon.welcome(function(err, km_data) {
if (err) {
process.send({
error : true,
msg : err.stack || err
});
return Daemon.exit();
}
if (km_data.disabled == true) {
console.error('Interactor disabled');
return Daemon.exit();
}
if (km_data.pending == true) {
console.error('Interactor pending');
return Daemon.exit();
}
if (km_data.active == true) {
self.opts.ipm2 = self.connectToPM2();
PushInteractor.start({
url : km_data.endpoints.push,
conf : self.opts
});
if (self.opts.REVERSE_INTERACT == true) {
ReverseInteractor.start({
url : km_data.endpoints.reverse,
conf : self.opts
});
}
Daemon.refreshWorker();
}
});
}
};
/**
* MAIN
*/
if (require.main === module) {
console.log(chalk.cyan.bold('[Keymetrics.io]') + ' Launching agent');
process.title = 'PM2: Keymetrics.io Agent';
Daemon.start();
}