Skip to content

Commit

Permalink
POC module system
Browse files Browse the repository at this point in the history
  • Loading branch information
Unitech committed Feb 8, 2015
1 parent 74ed479 commit 3d4d46f
Show file tree
Hide file tree
Showing 14 changed files with 509 additions and 64 deletions.
12 changes: 12 additions & 0 deletions bin/pm2
Original file line number Diff line number Diff line change
Expand Up @@ -288,6 +288,18 @@ commander.command('update')
CLI.updatePM2()
});

commander.command('install')
.description('install a plugin / app and run it forever')
.action(function(plugin_name) {
CLI.install(plugin_name);
});

commander.command('uninstall')
.description('uninstall a plugin / app')
.action(function(plugin_name) {
CLI.uninstall(plugin_name);
});

//
// Interact
//
Expand Down
12 changes: 8 additions & 4 deletions constants.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
var p = require('path');
var fs = require('fs');
var util = require('util');
var chalk = require('chalk')
var chalk = require('chalk');
var debug = require('debug')('pm2:constants');

/**
Expand All @@ -17,7 +17,7 @@ else if (process.env.HOME || process.env.HOMEPATH)
else
PM2_ROOT_PATH = p.resolve('/etc', '.pm2');

debug("PM2_ROOT_PATH: " + PM2_ROOT_PATH)
debug("PM2_ROOT_PATH: " + PM2_ROOT_PATH);

/**
* Constants variables used by PM2
Expand All @@ -28,8 +28,10 @@ var csts = {
CODE_UNCAUGHTEXCEPTION : 100,
CONCURRENT_ACTIONS : 1,
PREFIX_MSG : chalk.green('[PM2] '),
PREFIX_MSG_ERR : chalk.red('[PM2] [ERROR] '),
PREFIX_MSG_WARNING : chalk.yellow('[PM2] [WARN] '),
PREFIX_MSG_ERR : chalk.red('[PM2][ERROR] '),
PREFIX_MSG_MOD : chalk.green('[PM2][Module] '),
PREFIX_MSG_MOD_ERR : chalk.red('[PM2][Module][ERROR] '),
PREFIX_MSG_WARNING : chalk.yellow('[PM2][WARN] '),
PREFIX_MSG_SUCCESS : chalk.cyan('[PM2] '),

SAMPLE_FILE_PATH : '../lib/samples/sample.json5',
Expand Down Expand Up @@ -57,6 +59,8 @@ var csts = {

KEYMETRICS_ROOT_URL : 'root.keymetrics.io',

DEFAULT_MODULE_JSON : 'package.json',

REMOTE_PORT_TCP : 80,
REMOTE_PORT : 41624,
REMOTE_REVERSE_PORT : 43554,
Expand Down
79 changes: 79 additions & 0 deletions doc/MODULE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@

# Modules system

A module can be a probe using pmx, an application or any process.
Once a module is installed, it will always stay online.

## Basics

```bash
$ pm2 install module-probe
$ pm2 uninstall module-probe
```

## Writing a module

A module is a classic NPM module that contains at least these files:
- **package.json** with all dependencies needed to run this module and the app to be run
- **conf.js** containing user and internals configuration variables
- **index.js** a script that init the module and do whatever you need

Publishing a module consist of doing:

```bash
$ npm publish
```

## Pre flight checks

- in the package.json this must be present in order to launch the app:

```json
[...]
"apps" : [{
"script" : "probe.js"
}]
[...]
```

- the conf.js MUST be present, it's a requirement

```javascript
var pmx = require('pmx');
var fs = require('fs');
var path = require('path');

module.exports = {
internals : {
comment : 'This module monitors PM2',
errors : false,
latency : false,
versioning : false,
show_module_meta : true,
pid : pmx.getPID(path.join(process.env.HOME, '.pm2', 'pm2.pid'))
},

my_conf_var1 : 1000,
my_conf_var2 : true
};
```

**internals.pid** allows you to monitor a specific PID instead of the PID of the current process.

**internals.errors|latency|versioning|show_module_meta** allows you to show or hide panel in the keymetrics dashboard.

**internals.name|comment** allows you to display some metadata in keymetrics

## Internals

### Start

1- When a plugin is installed, it does an npm install and move it to .pm2/node_modules/module-name
1- Then the package.json is started with watch option, forced name (= name folder) and started as module

-> pm2_env.pmx_module flag is set to true. Allows to differenciate it from other classic processes

### loadConfig()

1- send conf.internals to PM2 with msg type axm:option:configuration
1- Attach this data to pm2_env.axm_options
31 changes: 19 additions & 12 deletions examples/axm/pm2_probe.js
Original file line number Diff line number Diff line change
@@ -1,24 +1,31 @@
var axm = require('pmx');
var pmx = require('pmx');
var fs = require('fs');
var path = require('path');

fs.readFile(path.join(process.env.HOME, '.pm2', 'pm2.pid'), function(err, data) {

var pid = data.toString();
// conf.js
var conf = {

axm.configureModule({
name : 'PM2',
version : '0.12.1',
pid : pid,
keymetrics : {
errors : false,
latency : false,
versioning : false,
show_module_meta : true,
author : 'Alexandre Strzelewicz',
comment : 'This module monitors PM2'
});
module_type : 'database'
},

});
pid : pmx.getPID(path.join(process.env.HOME, '.pm2', 'pm2.pid')),
pool_time : 1000,
active_pro : true

};

// + merge package.json data

var conf = pmx.initModule();

setInterval(function() {
}, 1000);
// Do something at configurable interval
}, conf.pool_time);

var Probe = pmx.probe();
96 changes: 87 additions & 9 deletions lib/CLI.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@

var CLI = module.exports = {};

var commander = require('commander');
var fs = require('fs');
var path = require('path');
Expand All @@ -15,15 +18,14 @@ var Common = require('./Common');
var cst = require('../constants.js');
var extItps = require('./interpreter.json');
var InteractorDaemonizer = require('./Interactor/InteractorDaemonizer');
var Modularizer = require('./Modularizer.js');
var p = path;

var json5 = require('./tools/json5.js');
var Config = require('./tools/Config');

var Deploy = require('pm2-deploy');

var CLI = module.exports = {};

var exitCli = Common.exitCli;
var printError = Common.printError;
var printOut = Common.printOut;
Expand Down Expand Up @@ -302,10 +304,18 @@ CLI.actionFromJson = function(action, file, jsonVia, cb) {
CLI.startJson = function(cmd, opts, jsonVia, cb) {
var appConf, deployConf = null;

if (typeof(cb) === 'undefined' && typeof(jsonVia) === 'function')
cb = jsonVia;

if (jsonVia == 'pipe')
appConf = json5.parse(cmd);
else {
var data = fs.readFileSync(cmd);
try {
var data = fs.readFileSync(cmd);
} catch(e) {
printError(cst.PREFIX_MSG_ERR + 'JSON ' + cmd +' not found');
return cb ? cb(e) : exitCli(cst.ERROR_EXIT);
}
appConf = json5.parse(data);
// v2 JSON declaration
if (appConf.deploy) deployConf = appConf.deploy;
Expand All @@ -315,9 +325,16 @@ CLI.startJson = function(cmd, opts, jsonVia, cb) {
if (!Array.isArray(appConf)) appConf = [appConf]; //convert to array

if ((appConf = verifyConfs(appConf)) == null)
return exitCli(cst.ERROR_EXIT);
return cb ? cb({success:false}) : exitCli(cst.ERROR_EXIT);

async.eachLimit(appConf, cst.CONCURRENT_ACTIONS, function(app, next) {
if (opts.cwd)
app.cwd = opts.cwd;
if (opts.force_name)
app.name = opts.force_name;
if (opts.started_as_module)
app.pmx_module = true;

mergeEnvironmentVariables(app, opts.env, deployConf);
var app_paths = null;
try {
Expand Down Expand Up @@ -540,7 +557,7 @@ CLI.updatePM2 = function(cb) {
debug('------------------ Everything killed', arguments);
Satan.launchDaemon(function(err, child) {
Satan.launchRPC(function() {

require('./Modularizer.js').launchAll();
CLI.resurrect(function() {
printOut(chalk.blue.bold('>>>>>>>>>> PM2 updated'));
return cb ? cb(null, {success:true}) : speedList();
Expand Down Expand Up @@ -583,7 +600,8 @@ CLI.dump = function(cb) {
if (!apps[0]) return fin(null);
delete apps[0].pm2_env.instances;
delete apps[0].pm2_env.pm_id;
env_arr.push(apps[0].pm2_env);
if (!apps[0].pm2_env.pmx_module)
env_arr.push(apps[0].pm2_env);
apps.shift();
return ex(apps);
})(list);
Expand Down Expand Up @@ -896,6 +914,9 @@ CLI._operate = function(action_name, process_name, envs, cb) {
envs = {};
}

/**
* Operate action on specific process id
*/
function processIds(ids, cb) {
async.eachLimit(ids, cst.CONCURRENT_ACTIONS, function(id, next) {
var opts = id;
Expand Down Expand Up @@ -925,6 +946,8 @@ CLI._operate = function(action_name, process_name, envs, cb) {
});
};



if (process_name == 'all') {
Common.getAllProcessId(function(err, ids) {
if (err) {
Expand Down Expand Up @@ -1315,6 +1338,61 @@ CLI.killDaemon = function(cb) {
});
};



/**
* Launch interactor
* @method interact
* @param {string} secret_key
* @param {string} public_key
* @param {string} machine_name
*/
CLI.install = function(module_name, cb) {
Modularizer.install(module_name, function(err, data) {
if (err)
return cb ? cb(err) : speedList(cst.ERROR_EXIT);
return cb ? cb(null, data) : speedList(cst.SUCCESS_EXIT);
});
};

/**
* Launch interactor
* @method interact
* @param {string} secret_key
* @param {string} public_key
* @param {string} machine_name
*/
CLI.uninstall = function(module_name, cb) {
Modularizer.uninstall(module_name, function(err, data) {
if (err)
return cb ? cb(err) : speedList(cst.ERROR_EXIT);
return cb ? cb(null, data) : speedList(cst.SUCCESS_EXIT);
});
};

CLI.deleteModule = function(module_name, cb) {
var found_proc = [];

Common.getAllProcess(function(err, procs) {
if (err) {
Common.printError('Error retrieving process list: ' + err);
return cb(err);
}

procs.forEach(function(proc) {
if (proc.pm2_env.name == module_name && proc.pm2_env.pmx_module) {
found_proc.push(proc.pm_id);
}
});

CLI._operate('deleteProcessId', found_proc[0], function(err) {
if (err) return cb(err);
Common.printOut('In memory process deleted');
return cb();
});
})
}

/**
* Launch interactor
* @method interact
Expand Down Expand Up @@ -1454,7 +1532,7 @@ var gl_retry = 0;
* @method speedList
* @return
*/
function speedList() {
function speedList(code) {
var self = this;

getInteractInfo(function(i_err, interact_infos) {
Expand All @@ -1475,7 +1553,7 @@ function speedList() {
printOut(chalk.green.bold('●') + ' Agent online - public key: %s - machine name: %s - Web access: %s', interact_infos.public_key, interact_infos.machine_name, 'http://app.keymetrics.io/');
}
UX.dispAsTable(list, interact_infos);
printOut(' Use `pm2 info <id|name>` to get more details about an app');
printOut(chalk.white.italic(' Use `pm2 show <id|name>` to get more details about an app'));
}

if (Satan._noDaemonMode) {
Expand All @@ -1484,7 +1562,7 @@ function speedList() {
return Log.stream(cst.PM2_LOG_FILE_PATH);
}
else {
return exitCli(cst.SUCCESS_EXIT);
return exitCli(code ? code : cst.SUCCESS_EXIT);
}
});
});
Expand Down
Loading

0 comments on commit 3d4d46f

Please sign in to comment.