From 935afab9254c7f4dd19e0f830ced1940dd7dec8c Mon Sep 17 00:00:00 2001 From: vince Date: Wed, 21 Feb 2018 14:41:17 +0100 Subject: [PATCH 001/140] feature: add mjs support --- lib/Common.js | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/lib/Common.js b/lib/Common.js index 2dd053aa..a8eeec1f 100644 --- a/lib/Common.js +++ b/lib/Common.js @@ -247,15 +247,17 @@ Common.prepareAppConf = function(opts, app) { * @param {string} filename * @return {mixed} null if not conf file, json or yaml if conf */ -Common.isConfigFile = function(filename) { - if (typeof(filename) != 'string') +Common.isConfigFile = function (filename) { + if (typeof (filename) !== 'string') return null; - if (filename.indexOf('.json') != -1) + if (filename.indexOf('.json') !== -1) return 'json'; if (filename.indexOf('.yml') > -1 || filename.indexOf('.yaml') > -1) return 'yaml'; - if (filename.indexOf('.config.js') != -1) + if (filename.indexOf('.config.js') !== -1) return 'js'; + if (filename.indexOf('.config.mjs') !== -1) + return 'mjs'; return null; }; @@ -288,7 +290,7 @@ Common.parseConfig = function(confObj, filename) { filename.indexOf('.yaml') > -1) { return yamljs.parse(confObj.toString()); } - else if (filename.indexOf('.config.js') > -1) { + else if (filename.indexOf('.config.js') > -1 || filename.indexOf('.config.mjs') > -1) { var confPath = require.resolve(path.resolve(filename)); delete require.cache[confPath]; return require(confPath); From 0908e9afb29e76ccdef3cffdbd6e1575e31915d9 Mon Sep 17 00:00:00 2001 From: vince Date: Wed, 21 Feb 2018 16:38:00 +0100 Subject: [PATCH 002/140] feature: make "pull", "backward" and "forward" works with id and pid --- lib/API/Version.js | 36 ++++++++++++++++++++---------------- lib/Client.js | 22 ++++++++++++++++++++++ 2 files changed, 42 insertions(+), 16 deletions(-) diff --git a/lib/API/Version.js b/lib/API/Version.js index 8f5bb93b..9a20bb20 100644 --- a/lib/API/Version.js +++ b/lib/API/Version.js @@ -21,11 +21,11 @@ module.exports = function(CLI) { printOut(cst.PREFIX_MSG + 'Updating repository for process name %s', process_name); - that.Client.getProcessByName(process_name, function(err, processes) { + that.Client.getProcessByNameOrId(process_name, function (err, processes) { - if (processes.length === 0) { - printError('No processes with this name: %s', process_name); - return cb ? cb({msg:'Process not found: '+process_name}) : that.exitCli(cst.ERROR_EXIT); + if (err || processes.length === 0) { + printError('No processes with this name or id : %s', process_name); + return cb ? cb({msg: 'Process not found: ' + process_name}) : that.exitCli(cst.ERROR_EXIT); } var proc = processes[0]; @@ -82,11 +82,11 @@ module.exports = function(CLI) { printOut(cst.PREFIX_MSG + 'Updating repository for process name %s', process_name); - that.Client.getProcessByName(process_name, function(err, processes) { + that.Client.getProcessByNameOrId(process_name, function (err, processes) { - if (processes.length === 0) { - printError('No processes with this name: %s', process_name); - return cb ? cb({msg:'Process not found: ' + process_name}) : that.exitCli(cst.ERROR_EXIT); + if (err || processes.length === 0) { + printError('No processes with this name or id : %s', process_name); + return cb ? cb({msg: 'Process not found: ' + process_name}) : that.exitCli(cst.ERROR_EXIT); } var proc = processes[0]; @@ -138,14 +138,16 @@ module.exports = function(CLI) { var that = this; printOut(cst.PREFIX_MSG + 'Downgrading to previous commit repository for process name %s', process_name); - that.Client.getProcessByName(process_name, function(err, processes) { + that.Client.getProcessByNameOrId(process_name, function (err, processes) { - if (processes.length === 0) { - printError('No processes with this name: %s', process_name); - return cb ? cb({msg:'Process not found: '+process_name}) : that.exitCli(cst.ERROR_EXIT); + if (err || processes.length === 0) { + printError('No processes with this name or id : %s', process_name); + return cb ? cb({msg: 'Process not found: ' + process_name}) : that.exitCli(cst.ERROR_EXIT); } var proc = processes[0]; + // in case user searched by id/pid + process_name = proc.name; if (proc.pm2_env.versioning === undefined || proc.pm2_env.versioning === null) @@ -194,14 +196,16 @@ module.exports = function(CLI) { var that = this; printOut(cst.PREFIX_MSG + 'Updating to next commit repository for process name %s', process_name); - that.Client.getProcessByName(process_name, function(err, processes) { + that.Client.getProcessByNameOrId(process_name, function (err, processes) { - if (processes.length === 0) { - printError('No processes with this name: %s', process_name); - return cb ? cb({msg:'Process not found: '+process_name}) : that.exitCli(cst.ERROR_EXIT); + if (err || processes.length === 0) { + printError('No processes with this name or id: %s', process_name); + return cb ? cb({msg: 'Process not found: ' + process_name}) : that.exitCli(cst.ERROR_EXIT); } var proc = processes[0]; + // in case user searched by id/pid + process_name = proc.name; if (proc.pm2_env.versioning) { vizion.next({folder: proc.pm2_env.versioning.repo_path}, function(err, meta) { if (err !== null) diff --git a/lib/Client.js b/lib/Client.js index 74103fd3..0b785515 100644 --- a/lib/Client.js +++ b/lib/Client.js @@ -717,3 +717,25 @@ Client.prototype.getProcessByName = function(name, cb) { return cb(null, found_proc); }); }; + +Client.prototype.getProcessByNameOrId = function (nameOrId, cb) { + var foundProc = []; + + this.executeRemote('getMonitorData', {}, function (err, list) { + if (err) { + Common.printError('Error retrieving process list: ' + err); + return cb(err); + } + + list.forEach(function (proc) { + if (proc.pm2_env.name === nameOrId || + proc.pm2_env.pm_exec_path === path.resolve(nameOrId) || + proc.pid === parseInt(nameOrId) || + proc.pm2_env.pm_id === parseInt(nameOrId)) { + foundProc.push(proc); + } + }); + + return cb(null, foundProc); + }); +}; From 84796956347ca638750fe89cb5545e2a90a0f2c2 Mon Sep 17 00:00:00 2001 From: vince Date: Mon, 26 Feb 2018 14:11:14 +0100 Subject: [PATCH 003/140] chore: upgrade module version and engine version --- package.json | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/package.json b/package.json index 1855d6c3..bb5a31fe 100644 --- a/package.json +++ b/package.json @@ -3,7 +3,7 @@ "preferGlobal": true, "version": "2.10.1", "engines": { - "node": ">=0.12" + "node": ">=4.0.0" }, "directories": { "bin": "./bin", @@ -161,17 +161,19 @@ "dependencies": { "async": "^2.5", "blessed": "^0.1.81", - "chalk": "^1.1", - "chokidar": "^2", + "chalk": "^2.3.1", + "chokidar": "^2.0.2", "cli-table-redemption": "^1.0.0", - "commander": "2.13.0", + "coffee-script": "^1.12.7", + "commander": "2.14.1", "cron": "^1.3", "debug": "^3.0", - "eventemitter2": "1.0.5", + "eventemitter2": "5.0.1", "fclone": "1.0.11", + "livescript": "^1.5.0", "mkdirp": "0.5.1", "moment": "^2.19", - "needle": "^2.1.0", + "needle": "^2.2.0", "nssocket": "0.6.0", "pidusage": "^1.2.0", "pm2-axon": "3.1.0", @@ -179,9 +181,9 @@ "pm2-deploy": "^0.3.9", "pm2-multimeter": "^0.1.2", "pmx": "^1.6", - "promptly": "2.2.0", + "promptly": "3.0.3", "semver": "^5.3", - "shelljs": "0.7.8", + "shelljs": "0.8.1", "source-map-support": "^0.5", "sprintf-js": "1.1.1", "v8-compile-cache": "^1.1.0", @@ -190,7 +192,7 @@ }, "devDependencies": { "mocha": "^3.5", - "should": "^11" + "should": "^13" }, "optionalDependencies": { "gkt": "https://tgz.pm2.io/gkt-1.0.0.tgz" From 1e0017325fc8cf658263fb4e02c7bf8912f422b3 Mon Sep 17 00:00:00 2001 From: vince Date: Mon, 26 Feb 2018 14:45:34 +0100 Subject: [PATCH 004/140] fix: #3456 use homedir() instead of process.env.HOME, make module installation work on windows --- lib/API/Modules/Modularizer.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/API/Modules/Modularizer.js b/lib/API/Modules/Modularizer.js index 7093324b..e738255e 100644 --- a/lib/API/Modules/Modularizer.js +++ b/lib/API/Modules/Modularizer.js @@ -6,6 +6,7 @@ var shelljs = require('shelljs'); var path = require('path'); var fs = require('fs'); +var os = require('os'); var async = require('async'); var p = path; var readline = require('readline'); @@ -185,7 +186,7 @@ Modularizer.installModule = function(CLI, module_name, opts, cb) { var install_path = path.join(cst.DEFAULT_MODULE_PATH, canonic_module_name); mkdirp(install_path, function() { - process.chdir(process.env.HOME); + process.chdir(os.homedir()); var install_instance = spawn(cst.IS_WINDOWS ? 'npm.cmd' : 'npm', ['install', module_name, '--loglevel=error', '--prefix', install_path ], { stdio : 'inherit', From 417fc19b2055313831ec0a515eb8ccd061ef8426 Mon Sep 17 00:00:00 2001 From: Robin Monnier Date: Mon, 26 Feb 2018 15:15:23 +0100 Subject: [PATCH 005/140] documentation for ecosystem file --- lib/API/schema.json | 307 +++++++++++++++++++++++++++----------------- 1 file changed, 188 insertions(+), 119 deletions(-) diff --git a/lib/API/schema.json b/lib/API/schema.json index 97400a3b..3f1847ea 100644 --- a/lib/API/schema.json +++ b/lib/API/schema.json @@ -1,24 +1,89 @@ { "script": { "type": "string", + "default": "Required", "require": true, - "alias" : "exec" + "alias" : "exec", + "description": "Path of the script to launch" + }, + "name": { + "type": "string", + "default": "Script filename without extension (app for app.js)", + "description": "Process name in the process list" + }, + "cwd": { + "type": "string", + "default": "CWD of the current environment (ie from your shell)", + "description": "Current working directory to start the process with" }, "args": { "type": [ "array", "string" - ] + ], + "description": "Arguments to pass to the script" + }, + "interpreter": { + "type": "string", + "alias": "exec_interpreter", + "default": "node", + "description": "Interpreter absolute path" }, "node_args": { "type": [ "array", "string" ], - "alias": ["interpreterArgs", "interpreter_args"] + "alias": ["interpreter_args"], + "description": "Arguments to pass to the interpreter" }, - "name": { - "type": "string" + "output": { + "type": "string", + "alias": ["out", "out_file", "out_log"], + "default": "~/.pm2/logs/-out.log", + "description": "File path for stdout (each line is appended to this file)" + }, + "error": { + "type": "string", + "alias": ["error_file", "err", "err_file", "err_log"], + "default": "~/.pm2/logs/-error.err", + "description": "File path for stderr (each line is appended to this file)" + }, + "log": { + "type": [ + "boolean", + "string" + ], + "default": "/dev/null", + "alias": "log_file", + "description": "File path for combined stdout and stderr" + }, + "disable_logs": { + "type": "boolean", + "default": false, + "description": "Disable all logs storage" + }, + "log_type": { + "type": "string", + "description": "Define a specific log output type, possible values: json|" + }, + "log_date_format": { + "type": "string", + "description": "Format for log timestamps (eg YYYY-MM-DD HH:mm Z) in moment.js format" + }, + "env": { + "type": [ + "object", + "string" + ], + "description": "Specify environment variables to be injected in your app" + }, + "^env_\\S*$": { + "type": [ + "object", + "string" + ], + "description": "Specify environment variables to be injected when using --env " }, "max_memory_restart": { "type": [ @@ -27,124 +92,89 @@ ], "regex": "^\\d+(G|M|K)?$", "ext_type": "sbyte", - "desc": "it should be a NUMBER - byte, \"[NUMBER]G\"(Gigabyte), \"[NUMBER]M\"(Megabyte) or \"[NUMBER]K\"(Kilobyte)" - }, - "uid" : { - "type" : "string" - }, - "gid" : { - "type" : "string" - }, - "restart_delay": { - "type" : "number" - }, - "source_map_support" : { - "type": "boolean" - }, - "wait_ready" : { - "type": "boolean" - }, - "disable_source_map_support" : { - "type": "boolean" - }, - "instances": { - "type": "number" - }, - "kill_timeout": { - "type": "number" - }, - "listen_timeout": { - "type": "number" - }, - "port": { - "type": "number" - }, - "log_file": { - "type": [ - "boolean", - "string" - ], - "alias": "log" - }, - "error_file": { - "type": "string", - "alias": ["error", "err", "err_file", "err_log"] - }, - "log_type": { - "type": "string" - }, - "out_file": { - "type": "string", - "alias": ["output", "out", "out_log"] + "desc": "it should be a NUMBER - byte, \"[NUMBER]G\"(Gigabyte), \"[NUMBER]M\"(Megabyte) or \"[NUMBER]K\"(Kilobyte)", + "description": "Restart the app if an amount of memory,is exceeded. Uses human-friendly format: 'K' for kilobytes, 'M' for megabytes, 'G' for gigabytes', etc. Eg 150M" }, "pid_file": { "type": "string", - "alias": "pid" + "alias": "pid", + "default": "~/.pm2/pids/app_name-id.pid", + "description": "File path where the pid of the started process is written by pm2" + }, + "restart_delay": { + "type" : "number", + "default": 0, + "description": "Time in ms to wait before restarting a crashing app" + }, + "source_map_support": { + "type": "boolean", + "default": true, + "description": "Enable or disable the source map support" + }, + "disable_source_map_support": { + "type": "boolean", + "default": false, + "description": "Enable or disable the source map support" + }, + "wait_ready": { + "type": "boolean", + "default": false, + "description": "Make the process wait for process.send('ready')" + }, + "instances": { + "type": "number", + "default": 1, + "description": "Number of instances to be started in cluster mode" + }, + "kill_timeout": { + "type": "number", + "default": 1600, + "description": "Time in ms before sending the final SIGKILL signal after SIGINT" + }, + "listen_timeout": { + "type": "number", + "description": "Time in ms before forcing a reload if app is still not listening/has still note sent ready" }, "cron_restart": { "type": "string", - "alias": "cron" - }, - "cwd": { - "type": "string" + "alias": "cron", + "description": "A cron pattern to restart your app" }, "merge_logs": { "type": "boolean", - "alias" : "combine_logs" + "alias" : "combine_logs", + "default": false, + "description": "In cluster mode, merge each type of logs into a single file (instead of having one for each cluster)" }, - "vizion" : { + "vizion": { "type": "boolean", - "default" : true + "default" : true, + "description": "Enable or disable the versioning control metadatas (vizion library)" }, - "pmx" : { + "autorestart": { "type": "boolean", - "default" : true - }, - "automation" : { - "type": "boolean", - "default" : true - }, - "autorestart" : { - "type": "boolean", - "default" : true - }, - "treekill" : { - "type": "boolean", - "default" : true + "default" : true, + "description": "pm2 will not attempt to restart it following successful completion or process failure" }, "watch": { "type": [ "boolean", "array", "string" - ] + ], + "default": false, + "description": "Enable or disable the watch mode" }, "ignore_watch": { "type": [ "array", "string" - ] + ], + "description": "List of path to ignore (regex)" }, "watch_options": { - "type": "object" - }, - "env": { - "type": [ - "object", - "string" - ] - }, - "^env_\\S*$": { - "type": [ - "object", - "string" - ] - }, - "disable_logs" : { - "type": "boolean" - }, - "log_date_format": { - "type": "string" + "type": "object", + "description": "Object that will be used as an options with chokidar (refer to chokidar documentation)" }, "min_uptime": { "type": [ @@ -154,49 +184,88 @@ "regex": "^\\d+(h|m|s)?$", "desc": "it should be a NUMBER - milliseconds, \"[NUMBER]h\"(hours), \"[NUMBER]m\"(minutes) or \"[NUMBER]s\"(seconds)", "min": 100, - "ext_type": "stime" + "ext_type": "stime", + "default": 1000, + "description": "Minimum uptime of the app to be considered started (format is [0-9]+(h|m|s)?, for hours, minutes, seconds, default to ms)" }, "max_restarts": { "type": "number", - "min": 0 + "min": 0, + "default": 16, + "description": "Number of times a script is restarted when it exits in less than min_uptime" }, "exec_mode": { "type": "string", "regex": "^(cluster|fork)(_mode)?$", "alias": "executeCommand", - "desc": "it should be \"cluster\"(\"cluster_mode\") or \"fork\"(\"fork_mode\") only" - }, - "exec_interpreter": { - "type": "string", - "alias": "interpreter" - }, - "write": { - "type": "boolean" + "desc": "it should be \"cluster\"(\"cluster_mode\") or \"fork\"(\"fork_mode\") only", + "default": "fork", + "description": "Set the execution mode, possible values: fork|cluster" }, "force": { - "type": "boolean" + "type": "boolean", + "default": false, + "description": "pm2 will start a script even if it is already running (the script path is considered, not the name)" }, "append_env_to_name": { - "type": "boolean" + "type": "boolean", + "default": false, + "description": "Append the environment name to the app name" }, "post_update": { - "type": "array" - }, - "disable_trace": { - "type": [ - "boolean" - ] + "type": "array", + "description": "List of commands executed after a pull/upgrade operation performed from Keymetrics dashboard" }, "trace": { "type": [ "boolean" - ] + ], + "default": false, + "description": "Enable or disable the transaction tracing" + }, + "disable_trace": { + "type": [ + "boolean" + ], + "default": true, + "description": "Enable or disable the transaction tracing" }, "increment_var": { - "type": "string" + "type": "string", + "description": "Specify the name of an environnement variable to inject which increments for each cluster" }, "instance_var": { "type": "string", - "default" : "NODE_APP_INSTANCE" + "default" : "NODE_APP_INSTANCE", + "description": "Rename the NODE_APP_INSTANCE environment variable" + }, + "pmx": { + "type": "boolean", + "default" : true, + "description": "Enable or disable the pmx injection" + }, + "automation": { + "type": "boolean", + "default" : true, + "description": "See --no-automation flag" + }, + "treekill": { + "type": "boolean", + "default" : true, + "description": "See --no-treekill flag" + }, + "port": { + "type": "number", + "description": "Shortcut to inject a PORT environment variable" + }, + "uid": { + "type" : "string", + "default": "Current user uid", + "description": "Set user id" + }, + "gid": { + "type" : "string", + "default": "Current user gid", + "description": "Set group id" } -} +} \ No newline at end of file From 13d6565c72e3596d05f87bfc8be15d3ee45fb279 Mon Sep 17 00:00:00 2001 From: vince Date: Mon, 26 Feb 2018 15:54:14 +0100 Subject: [PATCH 006/140] chore: remove coffee and livescript dependencies --- package.json | 2 -- 1 file changed, 2 deletions(-) diff --git a/package.json b/package.json index bb5a31fe..14a819c3 100644 --- a/package.json +++ b/package.json @@ -164,13 +164,11 @@ "chalk": "^2.3.1", "chokidar": "^2.0.2", "cli-table-redemption": "^1.0.0", - "coffee-script": "^1.12.7", "commander": "2.14.1", "cron": "^1.3", "debug": "^3.0", "eventemitter2": "5.0.1", "fclone": "1.0.11", - "livescript": "^1.5.0", "mkdirp": "0.5.1", "moment": "^2.19", "needle": "^2.2.0", From 074a7a407a31b4d88442f5834d253d62f4e543b8 Mon Sep 17 00:00:00 2001 From: vince Date: Mon, 26 Feb 2018 16:02:10 +0100 Subject: [PATCH 007/140] chore: downgrade promptly --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 14a819c3..3bd207d6 100644 --- a/package.json +++ b/package.json @@ -179,7 +179,7 @@ "pm2-deploy": "^0.3.9", "pm2-multimeter": "^0.1.2", "pmx": "^1.6", - "promptly": "3.0.3", + "promptly": "2.2.0", "semver": "^5.3", "shelljs": "0.8.1", "source-map-support": "^0.5", From 1650ec7f91f6f5102f80b7c34210b899841a4402 Mon Sep 17 00:00:00 2001 From: Robin Monnier Date: Mon, 26 Feb 2018 16:22:58 +0100 Subject: [PATCH 008/140] documentation for ecosystem file --- lib/API/schema.json | 29 ++++++++++++++--------------- 1 file changed, 14 insertions(+), 15 deletions(-) diff --git a/lib/API/schema.json b/lib/API/schema.json index 3f1847ea..22fbacac 100644 --- a/lib/API/schema.json +++ b/lib/API/schema.json @@ -1,19 +1,18 @@ { "script": { "type": "string", - "default": "Required", "require": true, "alias" : "exec", - "description": "Path of the script to launch" + "description": "Path of the script to launch, required field" }, "name": { "type": "string", - "default": "Script filename without extension (app for app.js)", + "default": "Script filename without the extension (app for app.js)", "description": "Process name in the process list" }, "cwd": { "type": "string", - "default": "CWD of the current environment (ie from your shell)", + "default": "CWD of the current environment (from your shell)", "description": "Current working directory to start the process with" }, "args": { @@ -56,7 +55,7 @@ ], "default": "/dev/null", "alias": "log_file", - "description": "File path for combined stdout and stderr" + "description": "File path for combined stdout and stderr (each line is appended to this file)" }, "disable_logs": { "type": "boolean", @@ -76,7 +75,7 @@ "object", "string" ], - "description": "Specify environment variables to be injected in your app" + "description": "Specify environment variables to be injected" }, "^env_\\S*$": { "type": [ @@ -93,7 +92,7 @@ "regex": "^\\d+(G|M|K)?$", "ext_type": "sbyte", "desc": "it should be a NUMBER - byte, \"[NUMBER]G\"(Gigabyte), \"[NUMBER]M\"(Megabyte) or \"[NUMBER]K\"(Kilobyte)", - "description": "Restart the app if an amount of memory,is exceeded. Uses human-friendly format: 'K' for kilobytes, 'M' for megabytes, 'G' for gigabytes', etc. Eg 150M" + "description": "Restart the app if an amount of memory is exceeded (format: 'K|G|' for KB, 'M' for MB, 'G' for GB, default to byte)" }, "pid_file": { "type": "string", @@ -119,7 +118,7 @@ "wait_ready": { "type": "boolean", "default": false, - "description": "Make the process wait for process.send('ready')" + "description": "Make the process wait for a process.send('ready')" }, "instances": { "type": "number", @@ -149,12 +148,12 @@ "vizion": { "type": "boolean", "default" : true, - "description": "Enable or disable the versioning control metadatas (vizion library)" + "description": "Enable or disable the versioning metadatas (vizion library)" }, "autorestart": { "type": "boolean", "default" : true, - "description": "pm2 will not attempt to restart it following successful completion or process failure" + "description": "Enable or disable auto restart after process failure" }, "watch": { "type": [ @@ -170,7 +169,7 @@ "array", "string" ], - "description": "List of path to ignore (regex)" + "description": "List of paths to ignore (regex)" }, "watch_options": { "type": "object", @@ -205,7 +204,7 @@ "force": { "type": "boolean", "default": false, - "description": "pm2 will start a script even if it is already running (the script path is considered, not the name)" + "description": "Start a script even if it is already running (only the script path is considered)" }, "append_env_to_name": { "type": "boolean", @@ -242,17 +241,17 @@ "pmx": { "type": "boolean", "default" : true, - "description": "Enable or disable the pmx injection" + "description": "Enable or disable pmx wrapping" }, "automation": { "type": "boolean", "default" : true, - "description": "See --no-automation flag" + "description": "Enable or disable pmx wrapping" }, "treekill": { "type": "boolean", "default" : true, - "description": "See --no-treekill flag" + "description": "Only kill the main process, not detached children" }, "port": { "type": "number", From beb6e48787c39c66569141d0fd8d090736114d23 Mon Sep 17 00:00:00 2001 From: vince Date: Mon, 26 Feb 2018 16:23:34 +0100 Subject: [PATCH 009/140] chore: drop 0.12 test on travis --- .travis.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index d76fc89c..25b0a367 100644 --- a/.travis.yml +++ b/.travis.yml @@ -4,7 +4,6 @@ node_js: - "4" - "6" - "8" - - "0.12" os: - linux before_install: From d4b4375e16fe7ac463b252702da662d3a21bf8b4 Mon Sep 17 00:00:00 2001 From: Unitech Date: Mon, 26 Feb 2018 20:12:18 +0100 Subject: [PATCH 010/140] refactor: parallelize bash test --- .travis.yml | 4 +- package.json | 2 +- test/Dockerfile | 5 +- test/bash/{ => agent}/interact.sh | 0 test/bash/{ => binaries}/pm2-dev.sh | 16 ++++- test/bash/{ => binaries}/pm2-runtime.sh | 16 ++++- test/bash/cli-ux.sh | 24 ------- test/bash/{ => cli}/app-config-update.sh | 2 +- test/bash/{ => cli}/app-configuration.sh | 2 +- test/bash/{ => cli}/args.sh | 2 +- test/bash/{ => cli}/attach.sh | 2 +- test/bash/{ => cli}/binary.sh | 2 +- test/bash/{ => cli}/cli-actions-1.sh | 2 +- test/bash/{ => cli}/cli-actions-2.sh | 2 +- test/bash/{ => cli}/env-refresh.sh | 2 +- test/bash/{ => cli}/extra-lang.sh | 2 +- test/bash/{ => cli}/fork.sh | 2 +- test/bash/{ => cli}/harmony.sh | 2 +- test/bash/{ => cli}/interpreter.sh | 68 +++++++++---------- test/bash/{ => cli}/mjs.sh | 2 +- test/bash/{ => cli}/monit.sh | 2 +- test/bash/{ => cli}/multiparam.sh | 2 +- test/bash/{ => cli}/operate-regex.sh | 3 +- test/bash/{ => cli}/piped-config.sh | 2 +- test/bash/{ => cli}/reset.sh | 2 +- test/bash/{ => cli}/resurrect.sh | 2 +- test/bash/{ => cli}/right-exit-code.sh | 2 +- test/bash/{ => cli}/serve.sh | 4 +- test/bash/{ => cli}/smart-start.sh | 2 +- test/bash/{ => cli}/sort.sh | 2 +- test/bash/{ => cli}/startOrX.sh | 2 +- test/bash/{ => cli}/watch.sh | 2 +- test/bash/include.sh | 25 ++++++- .../{ => internals}/daemon-paths-override.sh | 6 +- test/bash/{ => internals}/increment-var.sh | 4 +- test/bash/{ => internals}/infinite-loop.sh | 2 +- test/bash/{ => internals}/listen-timeout.sh | 5 +- test/bash/{ => internals}/options-via-env.sh | 2 +- test/bash/{ => internals}/promise.sh | 2 +- test/bash/{ => internals}/signal.sh | 4 +- test/bash/{ => internals}/source_map.sh | 2 +- .../bash/{ => internals}/start-consistency.sh | 2 +- test/bash/{ => internals}/wait-ready-event.sh | 8 ++- test/bash/{ => internals}/wrapped-fork.sh | 2 +- test/bash/issues/2337.sh | 18 ----- test/bash/{ => logs}/log-custom.sh | 2 +- test/bash/{ => logs}/log-entire.sh | 4 +- test/bash/{ => logs}/log-json.sh | 12 ++-- test/bash/{ => logs}/log-null.sh | 4 +- test/bash/{ => logs}/log-reload.sh | 2 +- test/bash/{ => logs}/log-timestamp.sh | 2 +- test/bash/{ => misc}/cron-system.sh | 0 test/bash/{ => misc}/docker.sh | 2 +- test/bash/{ => misc}/dump.sh | 0 test/bash/{ => misc}/file-descriptor.sh | 2 +- test/bash/{ => misc}/inside-pm2.sh | 0 test/bash/{ => misc}/instance-number.sh | 0 test/bash/{ => misc}/misc.sh | 0 test/bash/{ => misc}/nvm-node-version.sh | 2 +- test/bash/{ => misc}/pull.sh | 0 test/bash/{ => misc}/startup.sh | 0 test/bash/{ => misc}/versioning-cmd.sh | 0 test/bash/{ => misc}/vizion.sh | 0 test/bash/{ => modules}/get-set.sh | 2 +- test/bash/{ => modules}/module-safeguard.sh | 2 +- test/bash/{ => modules}/module.sh | 2 +- .../{ => process-file}/append-env-to-name.sh | 4 +- .../{ => process-file}/homogen-json-action.sh | 2 +- .../{ => process-file}/js-configuration.sh | 4 +- test/bash/{ => process-file}/json-file.sh | 2 +- test/bash/{ => process-file}/json-reload.sh | 2 +- .../{ => process-file}/yaml-configuration.sh | 2 +- test/bash/{ => reload}/gracefulReload.sh | 2 +- test/bash/{ => reload}/gracefulReload2.sh | 2 +- test/bash/{ => reload}/gracefulReload3.sh | 2 +- test/bash/{ => reload}/reload.sh | 2 +- test/docker_parallel_test.sh | 23 ++++++- test/parallel_programmatic_tests.sh | 26 ------- test/programmatic/configuration.mocha.js | 7 +- test/programmatic/reload-locker.mocha.js | 4 ++ test/programmatic_commands.txt | 22 ------ 81 files changed, 197 insertions(+), 215 deletions(-) rename test/bash/{ => agent}/interact.sh (100%) rename test/bash/{ => binaries}/pm2-dev.sh (72%) rename test/bash/{ => binaries}/pm2-runtime.sh (80%) delete mode 100644 test/bash/cli-ux.sh rename test/bash/{ => cli}/app-config-update.sh (98%) rename test/bash/{ => cli}/app-configuration.sh (98%) rename test/bash/{ => cli}/args.sh (97%) rename test/bash/{ => cli}/attach.sh (91%) rename test/bash/{ => cli}/binary.sh (96%) rename test/bash/{ => cli}/cli-actions-1.sh (99%) rename test/bash/{ => cli}/cli-actions-2.sh (99%) rename test/bash/{ => cli}/env-refresh.sh (98%) rename test/bash/{ => cli}/extra-lang.sh (97%) rename test/bash/{ => cli}/fork.sh (95%) rename test/bash/{ => cli}/harmony.sh (96%) rename test/bash/{ => cli}/interpreter.sh (54%) rename test/bash/{ => cli}/mjs.sh (95%) rename test/bash/{ => cli}/monit.sh (95%) rename test/bash/{ => cli}/multiparam.sh (94%) rename test/bash/{ => cli}/operate-regex.sh (94%) rename test/bash/{ => cli}/piped-config.sh (90%) rename test/bash/{ => cli}/reset.sh (96%) rename test/bash/{ => cli}/resurrect.sh (95%) rename test/bash/{ => cli}/right-exit-code.sh (93%) rename test/bash/{ => cli}/serve.sh (97%) rename test/bash/{ => cli}/smart-start.sh (96%) rename test/bash/{ => cli}/sort.sh (97%) rename test/bash/{ => cli}/startOrX.sh (93%) rename test/bash/{ => cli}/watch.sh (98%) rename test/bash/{ => internals}/daemon-paths-override.sh (63%) rename test/bash/{ => internals}/increment-var.sh (98%) rename test/bash/{ => internals}/infinite-loop.sh (96%) rename test/bash/{ => internals}/listen-timeout.sh (86%) rename test/bash/{ => internals}/options-via-env.sh (93%) rename test/bash/{ => internals}/promise.sh (98%) rename test/bash/{ => internals}/signal.sh (93%) rename test/bash/{ => internals}/source_map.sh (97%) rename test/bash/{ => internals}/start-consistency.sh (94%) rename test/bash/{ => internals}/wait-ready-event.sh (88%) rename test/bash/{ => internals}/wrapped-fork.sh (94%) delete mode 100644 test/bash/issues/2337.sh rename test/bash/{ => logs}/log-custom.sh (96%) rename test/bash/{ => logs}/log-entire.sh (99%) rename test/bash/{ => logs}/log-json.sh (90%) rename test/bash/{ => logs}/log-null.sh (98%) rename test/bash/{ => logs}/log-reload.sh (96%) rename test/bash/{ => logs}/log-timestamp.sh (98%) rename test/bash/{ => misc}/cron-system.sh (100%) rename test/bash/{ => misc}/docker.sh (98%) rename test/bash/{ => misc}/dump.sh (100%) rename test/bash/{ => misc}/file-descriptor.sh (96%) rename test/bash/{ => misc}/inside-pm2.sh (100%) rename test/bash/{ => misc}/instance-number.sh (100%) rename test/bash/{ => misc}/misc.sh (100%) rename test/bash/{ => misc}/nvm-node-version.sh (97%) rename test/bash/{ => misc}/pull.sh (100%) rename test/bash/{ => misc}/startup.sh (100%) rename test/bash/{ => misc}/versioning-cmd.sh (100%) rename test/bash/{ => misc}/vizion.sh (100%) rename test/bash/{ => modules}/get-set.sh (92%) rename test/bash/{ => modules}/module-safeguard.sh (97%) rename test/bash/{ => modules}/module.sh (98%) rename test/bash/{ => process-file}/append-env-to-name.sh (88%) rename test/bash/{ => process-file}/homogen-json-action.sh (97%) rename test/bash/{ => process-file}/js-configuration.sh (58%) rename test/bash/{ => process-file}/json-file.sh (98%) rename test/bash/{ => process-file}/json-reload.sh (98%) rename test/bash/{ => process-file}/yaml-configuration.sh (96%) rename test/bash/{ => reload}/gracefulReload.sh (96%) rename test/bash/{ => reload}/gracefulReload2.sh (95%) rename test/bash/{ => reload}/gracefulReload3.sh (95%) rename test/bash/{ => reload}/reload.sh (98%) delete mode 100755 test/parallel_programmatic_tests.sh delete mode 100644 test/programmatic_commands.txt diff --git a/.travis.yml b/.travis.yml index 25b0a367..93a4007c 100644 --- a/.travis.yml +++ b/.travis.yml @@ -8,9 +8,7 @@ os: - linux before_install: - sudo apt-get -qq update - - sudo apt-get install python3 - sudo apt-get install php5-cli + - sudo apt-get install parallel services: - docker -notifications: - slack: pm2-nodejs:5Lolyw2LMnwy8fziqOGILQxG diff --git a/package.json b/package.json index 3bd207d6..b117d85e 100644 --- a/package.json +++ b/package.json @@ -91,7 +91,7 @@ "main": "index.js", "types": "types/index.d.ts", "scripts": { - "test": "NODE_ENV=test bash test/pm2_check_dependencies.sh && NODE_ENV=test bash test/pm2_programmatic_tests.sh && NODE_ENV=test bash test/pm2_behavior_tests.sh", + "test": "bash test/docker_parallel_test.sh", "bench-pmx": "pm2 delete all; pm2 install pm2-probe; node examples/pmx/app.js; pm2 ls" }, "keywords": [ diff --git a/test/Dockerfile b/test/Dockerfile index 4c5cd64f..4979fe06 100644 --- a/test/Dockerfile +++ b/test/Dockerfile @@ -1,9 +1,12 @@ -FROM node:9 +FROM node:alpine RUN mkdir -p /var/pm2 WORKDIR /var/pm2 +ENV NODE_ENV test +RUN apk update && apk add bash git curl python3 php5 && rm -rf /var/cache/apk/* +RUN ln -s /usr/bin/php5 /usr/bin/php RUN npm install -g mocha@3.5 CMD ["mocha", "./test/programmatic/api.mocha.js"] diff --git a/test/bash/interact.sh b/test/bash/agent/interact.sh similarity index 100% rename from test/bash/interact.sh rename to test/bash/agent/interact.sh diff --git a/test/bash/pm2-dev.sh b/test/bash/binaries/pm2-dev.sh similarity index 72% rename from test/bash/pm2-dev.sh rename to test/bash/binaries/pm2-dev.sh index 748dc7b7..6839550d 100644 --- a/test/bash/pm2-dev.sh +++ b/test/bash/binaries/pm2-dev.sh @@ -1,9 +1,21 @@ #!/usr/bin/env bash SRC=$(cd $(dirname "$0"); pwd) -source "${SRC}/include.sh" +source "${SRC}/../include.sh" -pm2dev="`type -P node` `pwd`/bin/pm2-dev" + +pm2_path=`pwd`/bin/pm2-dev + +if [ ! -f $pm2_path ]; +then + pm2_path=`pwd`/../bin/pm2-dev + if [ ! -f $pm2_path ]; + then + pm2_path=`pwd`/../../bin/pm2-dev + fi +fi + +pm2dev="`type -P node` $pm2_path" export PM2_HOME=$HOME'/.pm2-dev' diff --git a/test/bash/pm2-runtime.sh b/test/bash/binaries/pm2-runtime.sh similarity index 80% rename from test/bash/pm2-runtime.sh rename to test/bash/binaries/pm2-runtime.sh index da29b919..8cfe8c38 100644 --- a/test/bash/pm2-runtime.sh +++ b/test/bash/binaries/pm2-runtime.sh @@ -1,9 +1,21 @@ #!/usr/bin/env bash SRC=$(cd $(dirname "$0"); pwd) -source "${SRC}/include.sh" +source "${SRC}/../include.sh" -pm2_runtime="`type -P node` `pwd`/bin/pm2-runtime" + +pm2_path=`pwd`/bin/pm2-runtime + +if [ ! -f $pm2_path ]; +then + pm2_path=`pwd`/../bin/pm2-runtime + if [ ! -f $pm2_path ]; + then + pm2_path=`pwd`/../../bin/pm2-runtime + fi +fi + +pm2_runtime="`type -P node` $pm2_path" export PM2_RUNTIME_DEBUG='true' diff --git a/test/bash/cli-ux.sh b/test/bash/cli-ux.sh deleted file mode 100644 index 8f3ddc7e..00000000 --- a/test/bash/cli-ux.sh +++ /dev/null @@ -1,24 +0,0 @@ -#!/usr/bin/env bash - -SRC=$(cd $(dirname "$0"); pwd) -source "${SRC}/include.sh" - - -echo -e "\033[1mRunning tests:\033[0m" - -which wrk -spec "You should have wrk benchmark in your /usr/bin" - -killall node - -cd $file_path -$pm2 start cluster-pm2.json -$pm2 start cluster-pm2.json -f -$pm2 start cluster-pm2.json -f -$pm2 start cluster-pm2.json -f -spec "start cluster" - -wrk -c 500 -t 500 -d 8 http://localhost:8020 &> /dev/null & -$pm2 monit -$pm2 list -$pm2 stop diff --git a/test/bash/app-config-update.sh b/test/bash/cli/app-config-update.sh similarity index 98% rename from test/bash/app-config-update.sh rename to test/bash/cli/app-config-update.sh index 8ef0a532..e46313e5 100644 --- a/test/bash/app-config-update.sh +++ b/test/bash/cli/app-config-update.sh @@ -1,7 +1,7 @@ #!/usr/bin/env bash SRC=$(cd $(dirname "$0"); pwd) -source "${SRC}/include.sh" +source "${SRC}/../include.sh" export PM2_GRACEFUL_TIMEOUT=1000 export PM2_GRACEFUL_LISTEN_TIMEOUT=1000 diff --git a/test/bash/app-configuration.sh b/test/bash/cli/app-configuration.sh similarity index 98% rename from test/bash/app-configuration.sh rename to test/bash/cli/app-configuration.sh index ab741c98..cb17b214 100644 --- a/test/bash/app-configuration.sh +++ b/test/bash/cli/app-configuration.sh @@ -1,7 +1,7 @@ #!/usr/bin/env bash SRC=$(cd $(dirname "$0"); pwd) -source "${SRC}/include.sh" +source "${SRC}/../include.sh" echo -e "\033[1mRunning tests:\033[0m" diff --git a/test/bash/args.sh b/test/bash/cli/args.sh similarity index 97% rename from test/bash/args.sh rename to test/bash/cli/args.sh index 0bfce30a..01a0529c 100644 --- a/test/bash/args.sh +++ b/test/bash/cli/args.sh @@ -1,7 +1,7 @@ #!/usr/bin/env bash SRC=$(cd $(dirname "$0"); pwd) -source "${SRC}/include.sh" +source "${SRC}/../include.sh" cd $file_path/args diff --git a/test/bash/attach.sh b/test/bash/cli/attach.sh similarity index 91% rename from test/bash/attach.sh rename to test/bash/cli/attach.sh index fed9ac70..4a32e147 100644 --- a/test/bash/attach.sh +++ b/test/bash/cli/attach.sh @@ -1,7 +1,7 @@ #!/usr/bin/env bash SRC=$(cd $(dirname "$0"); pwd) -source "${SRC}/include.sh" +source "${SRC}/../include.sh" echo -e "\033[1mRunning tests:\033[0m" diff --git a/test/bash/binary.sh b/test/bash/cli/binary.sh similarity index 96% rename from test/bash/binary.sh rename to test/bash/cli/binary.sh index 13054c4f..e970a8ec 100644 --- a/test/bash/binary.sh +++ b/test/bash/cli/binary.sh @@ -1,7 +1,7 @@ #!/usr/bin/env bash SRC=$(cd $(dirname "$0"); pwd) -source "${SRC}/include.sh" +source "${SRC}/../include.sh" echo -e "\033[1mRunning tests:\033[0m" diff --git a/test/bash/cli-actions-1.sh b/test/bash/cli/cli-actions-1.sh similarity index 99% rename from test/bash/cli-actions-1.sh rename to test/bash/cli/cli-actions-1.sh index 8d393f52..1cbe7697 100644 --- a/test/bash/cli-actions-1.sh +++ b/test/bash/cli/cli-actions-1.sh @@ -1,7 +1,7 @@ #!/usr/bin/env bash SRC=$(cd $(dirname "$0"); pwd) -source "${SRC}/include.sh" +source "${SRC}/../include.sh" cd $file_path diff --git a/test/bash/cli-actions-2.sh b/test/bash/cli/cli-actions-2.sh similarity index 99% rename from test/bash/cli-actions-2.sh rename to test/bash/cli/cli-actions-2.sh index 02b50fc5..51abb450 100644 --- a/test/bash/cli-actions-2.sh +++ b/test/bash/cli/cli-actions-2.sh @@ -1,7 +1,7 @@ #!/usr/bin/env bash SRC=$(cd $(dirname "$0"); pwd) -source "${SRC}/include.sh" +source "${SRC}/../include.sh" cd $file_path diff --git a/test/bash/env-refresh.sh b/test/bash/cli/env-refresh.sh similarity index 98% rename from test/bash/env-refresh.sh rename to test/bash/cli/env-refresh.sh index b49c6bf8..418c9e2f 100644 --- a/test/bash/env-refresh.sh +++ b/test/bash/cli/env-refresh.sh @@ -1,7 +1,7 @@ #!/usr/bin/env bash SRC=$(cd $(dirname "$0"); pwd) -source "${SRC}/include.sh" +source "${SRC}/../include.sh" cd $file_path echo -e "\033[1mENV REFRESH\033[0m" diff --git a/test/bash/extra-lang.sh b/test/bash/cli/extra-lang.sh similarity index 97% rename from test/bash/extra-lang.sh rename to test/bash/cli/extra-lang.sh index e3f22eb1..8761cd34 100644 --- a/test/bash/extra-lang.sh +++ b/test/bash/cli/extra-lang.sh @@ -1,7 +1,7 @@ #!/usr/bin/env bash SRC=$(cd $(dirname "$0"); pwd) -source "${SRC}/include.sh" +source "${SRC}/../include.sh" cd $file_path/extra-lang diff --git a/test/bash/fork.sh b/test/bash/cli/fork.sh similarity index 95% rename from test/bash/fork.sh rename to test/bash/cli/fork.sh index e6091ce4..f641d23e 100644 --- a/test/bash/fork.sh +++ b/test/bash/cli/fork.sh @@ -1,7 +1,7 @@ #!/usr/bin/env bash SRC=$(cd $(dirname "$0"); pwd) -source "${SRC}/include.sh" +source "${SRC}/../include.sh" cd $file_path diff --git a/test/bash/harmony.sh b/test/bash/cli/harmony.sh similarity index 96% rename from test/bash/harmony.sh rename to test/bash/cli/harmony.sh index 03094ea0..bba81985 100644 --- a/test/bash/harmony.sh +++ b/test/bash/cli/harmony.sh @@ -1,7 +1,7 @@ #!/usr/bin/env bash SRC=$(cd $(dirname "$0"); pwd) -source "${SRC}/include.sh" +source "${SRC}/../include.sh" cd $file_path diff --git a/test/bash/interpreter.sh b/test/bash/cli/interpreter.sh similarity index 54% rename from test/bash/interpreter.sh rename to test/bash/cli/interpreter.sh index 3257e85c..ebd2aec3 100644 --- a/test/bash/interpreter.sh +++ b/test/bash/cli/interpreter.sh @@ -1,7 +1,7 @@ #!/usr/bin/env bash SRC=$(cd $(dirname "$0"); pwd) -source "${SRC}/include.sh" +source "${SRC}/../include.sh" cd $file_path/interpreter @@ -41,36 +41,36 @@ should 'process should be online' "status: 'online'" 1 ########## LIVESCRIPT -$pm2 delete all -$pm2 start echo.ls -sleep 1 -should 'process should be errored without livescript installed' "status: 'errored'" 1 +# $pm2 delete all +# $pm2 start echo.ls +# sleep 1 +# should 'process should be errored without livescript installed' "status: 'errored'" 1 -########### Install +# ########### Install -$pm2 install livescript +# $pm2 install livescript -########### livescript fork test -$pm2 delete all +# ########### livescript fork test +# $pm2 delete all ->livescript.log +# >livescript.log -$pm2 start echo.ls -o livescript.log --merge-logs +# $pm2 start echo.ls -o livescript.log --merge-logs -sleep 1.5 -grep "Hello Livescript!" livescript.log -spec "Should work on Livescript files in fork mode" +# sleep 1.5 +# grep "Hello Livescript!" livescript.log +# spec "Should work on Livescript files in fork mode" -########### livescript cluster test -$pm2 delete all +# ########### livescript cluster test +# $pm2 delete all ->livescript.log +# >livescript.log -$pm2 start echo.ls -i 1 -o livescript.log --merge-logs +# $pm2 start echo.ls -i 1 -o livescript.log --merge-logs -sleep 1.5 -grep "Hello Livescript!" livescript.log -spec "Should work on Livescript files in cluster mode" +# sleep 1.5 +# grep "Hello Livescript!" livescript.log +# spec "Should work on Livescript files in cluster mode" ########### TYPESCRIPT @@ -81,27 +81,27 @@ should 'process should be errored without typescript installed' "status: 'errore ########### Install -# $pm2 install typescript +$pm2 install typescript ########### typescript fork test -# $pm2 delete all +$pm2 delete all -# >typescript.log +>typescript.log -# $pm2 start echo.ts -o typescript.log --merge-logs +$pm2 start echo.ts -o typescript.log --merge-logs -# sleep 1.5 +sleep 1.5 -# grep "Hello Typescript!" typescript.log -# spec "Should work on Typescript files in fork mode" +grep "Hello Typescript!" typescript.log +spec "Should work on Typescript files in fork mode" ########### typescript cluster test -# $pm2 delete all +$pm2 delete all -# >typescript.log +>typescript.log -# $pm2 start echo.ts -i 1 -o typescript.log --merge-logs +$pm2 start echo.ts -i 1 -o typescript.log --merge-logs -# sleep 1.5 -# grep "Hello Typescript!" typescript.log -# spec "Should work on Typescript files in cluster mode" +sleep 1.5 +grep "Hello Typescript!" typescript.log +spec "Should work on Typescript files in cluster mode" diff --git a/test/bash/mjs.sh b/test/bash/cli/mjs.sh similarity index 95% rename from test/bash/mjs.sh rename to test/bash/cli/mjs.sh index 817ea2dd..662ef43c 100644 --- a/test/bash/mjs.sh +++ b/test/bash/cli/mjs.sh @@ -1,7 +1,7 @@ #!/usr/bin/env bash SRC=$(cd $(dirname "$0"); pwd) -source "${SRC}/include.sh" +source "${SRC}/../include.sh" cd $file_path/mjs diff --git a/test/bash/monit.sh b/test/bash/cli/monit.sh similarity index 95% rename from test/bash/monit.sh rename to test/bash/cli/monit.sh index 668a46cd..14cf954d 100644 --- a/test/bash/monit.sh +++ b/test/bash/cli/monit.sh @@ -1,7 +1,7 @@ #!/usr/bin/env bash SRC=$(cd $(dirname "$0"); pwd) -source "${SRC}/include.sh" +source "${SRC}/../include.sh" cd $file_path diff --git a/test/bash/multiparam.sh b/test/bash/cli/multiparam.sh similarity index 94% rename from test/bash/multiparam.sh rename to test/bash/cli/multiparam.sh index c71212e5..c3207862 100644 --- a/test/bash/multiparam.sh +++ b/test/bash/cli/multiparam.sh @@ -1,7 +1,7 @@ #!/usr/bin/env bash SRC=$(cd $(dirname "$0"); pwd) -source "${SRC}/include.sh" +source "${SRC}/../include.sh" cd $file_path diff --git a/test/bash/operate-regex.sh b/test/bash/cli/operate-regex.sh similarity index 94% rename from test/bash/operate-regex.sh rename to test/bash/cli/operate-regex.sh index 86e59fa8..d2e0fd92 100644 --- a/test/bash/operate-regex.sh +++ b/test/bash/cli/operate-regex.sh @@ -1,7 +1,7 @@ #!/usr/bin/env bash SRC=$(cd $(dirname "$0"); pwd) -source "${SRC}/include.sh" +source "${SRC}/../include.sh" cd $file_path @@ -24,4 +24,3 @@ should 'should have stopped 1 apps' 'online' 0 $pm2 restart /echo-[1,2]/ should 'should have restarted 2 apps' 'online' 2 - diff --git a/test/bash/piped-config.sh b/test/bash/cli/piped-config.sh similarity index 90% rename from test/bash/piped-config.sh rename to test/bash/cli/piped-config.sh index 416cec35..83fa2725 100644 --- a/test/bash/piped-config.sh +++ b/test/bash/cli/piped-config.sh @@ -2,7 +2,7 @@ #!/usr/bin/env bash SRC=$(cd $(dirname "$0"); pwd) -source "${SRC}/include.sh" +source "${SRC}/../include.sh" cd $file_path diff --git a/test/bash/reset.sh b/test/bash/cli/reset.sh similarity index 96% rename from test/bash/reset.sh rename to test/bash/cli/reset.sh index a8f425bf..1a192f47 100644 --- a/test/bash/reset.sh +++ b/test/bash/cli/reset.sh @@ -2,7 +2,7 @@ #!/usr/bin/env bash SRC=$(cd $(dirname "$0"); pwd) -source "${SRC}/include.sh" +source "${SRC}/../include.sh" cd $file_path diff --git a/test/bash/resurrect.sh b/test/bash/cli/resurrect.sh similarity index 95% rename from test/bash/resurrect.sh rename to test/bash/cli/resurrect.sh index b37abf58..ff83b513 100644 --- a/test/bash/resurrect.sh +++ b/test/bash/cli/resurrect.sh @@ -1,7 +1,7 @@ #!/usr/bin/env bash SRC=$(cd $(dirname "$0"); pwd) -source "${SRC}/include.sh" +source "${SRC}/../include.sh" cd $file_path $pm2 start echo.js -i 4 diff --git a/test/bash/right-exit-code.sh b/test/bash/cli/right-exit-code.sh similarity index 93% rename from test/bash/right-exit-code.sh rename to test/bash/cli/right-exit-code.sh index 38ec3c13..3f5e99a1 100644 --- a/test/bash/right-exit-code.sh +++ b/test/bash/cli/right-exit-code.sh @@ -1,7 +1,7 @@ #!/usr/bin/env bash SRC=$(cd $(dirname "$0"); pwd) -source "${SRC}/include.sh" +source "${SRC}/../include.sh" cd $file_path diff --git a/test/bash/serve.sh b/test/bash/cli/serve.sh similarity index 97% rename from test/bash/serve.sh rename to test/bash/cli/serve.sh index 8989efda..48289bbe 100644 --- a/test/bash/serve.sh +++ b/test/bash/cli/serve.sh @@ -1,7 +1,7 @@ #!/usr/bin/env bash SRC=$(cd $(dirname "$0"); pwd) -source "${SRC}/include.sh" +source "${SRC}/../include.sh" cd $file_path/serve @@ -67,4 +67,4 @@ $pm2 stop ecosystem.json curl http://localhost:8081/index.html > /tmp/tmp_out.txt OUT=`cat /tmp/tmp_out.txt | grep -o "good shit" | wc -l` [ $OUT -eq 0 ] || fail "should be offline" -success "should be offline" \ No newline at end of file +success "should be offline" diff --git a/test/bash/smart-start.sh b/test/bash/cli/smart-start.sh similarity index 96% rename from test/bash/smart-start.sh rename to test/bash/cli/smart-start.sh index a09513f1..70880b6b 100644 --- a/test/bash/smart-start.sh +++ b/test/bash/cli/smart-start.sh @@ -2,7 +2,7 @@ #!/usr/bin/env bash SRC=$(cd $(dirname "$0"); pwd) -source "${SRC}/include.sh" +source "${SRC}/../include.sh" cd $file_path diff --git a/test/bash/sort.sh b/test/bash/cli/sort.sh similarity index 97% rename from test/bash/sort.sh rename to test/bash/cli/sort.sh index 995a49cb..bac3f8ba 100644 --- a/test/bash/sort.sh +++ b/test/bash/cli/sort.sh @@ -1,7 +1,7 @@ #!/usr/bin/env bash SRC=$(cd $(dirname "$0"); pwd) -source "${SRC}/include.sh" +source "${SRC}/../include.sh" cd $file_path/sort diff --git a/test/bash/startOrX.sh b/test/bash/cli/startOrX.sh similarity index 93% rename from test/bash/startOrX.sh rename to test/bash/cli/startOrX.sh index dd714e3d..ef985cba 100644 --- a/test/bash/startOrX.sh +++ b/test/bash/cli/startOrX.sh @@ -1,7 +1,7 @@ #!/usr/bin/env bash SRC=$(cd $(dirname "$0"); pwd) -source "${SRC}/include.sh" +source "${SRC}/../include.sh" echo -e "\033[1mStartOrX.sh:\033[0m" diff --git a/test/bash/watch.sh b/test/bash/cli/watch.sh similarity index 98% rename from test/bash/watch.sh rename to test/bash/cli/watch.sh index a47ec8a2..4a42c229 100644 --- a/test/bash/watch.sh +++ b/test/bash/cli/watch.sh @@ -1,7 +1,7 @@ #!/usr/bin/env bash SRC=$(cd $(dirname "$0"); pwd) -source "${SRC}/include.sh" +source "${SRC}/../include.sh" cd $file_path/watch diff --git a/test/bash/include.sh b/test/bash/include.sh index 1abf9199..af6f9f79 100644 --- a/test/bash/include.sh +++ b/test/bash/include.sh @@ -7,11 +7,30 @@ node="`type -P node`" -pm2="`type -P node` `pwd`/bin/pm2" +pm2_path=`pwd`/bin/pm2 -file_path="test/fixtures" +if [ ! -f $pm2_path ]; +then + pm2_path=`pwd`/../bin/pm2 + if [ ! -f $pm2_path ]; + then + pm2_path=`pwd`/../../bin/pm2 + fi +fi -#set -o verbose +pm2="$node $pm2_path" + +SRC=$(cd $(dirname "$0"); pwd) +file_path="${SRC}/../fixtures" + +if [ ! -d $file_path ]; +then + file_path="${SRC}/../../fixtures" + if [ ! -d $file_path ]; + then + file_path="${SRC}/../../../fixtures" + fi +fi $pm2 kill $pm2 link delete diff --git a/test/bash/daemon-paths-override.sh b/test/bash/internals/daemon-paths-override.sh similarity index 63% rename from test/bash/daemon-paths-override.sh rename to test/bash/internals/daemon-paths-override.sh index 31b65b2d..43b6b164 100644 --- a/test/bash/daemon-paths-override.sh +++ b/test/bash/internals/daemon-paths-override.sh @@ -1,7 +1,7 @@ #!/usr/bin/env bash SRC=$(cd $(dirname "$0"); pwd) -source "${SRC}/include.sh" +source "${SRC}/../include.sh" $pm2 kill rm /tmp/.toto.pid @@ -10,6 +10,6 @@ rm /tmp/.toto.pid PM2_PID_FILE_PATH=/tmp/.toto.pid $pm2 ls sleep 2 -test -f /tmp/.toto.pid +test -f /tmp/.toto.pid -spec 'should have picked the pm2 pid path' \ No newline at end of file +spec 'should have picked the pm2 pid path' diff --git a/test/bash/increment-var.sh b/test/bash/internals/increment-var.sh similarity index 98% rename from test/bash/increment-var.sh rename to test/bash/internals/increment-var.sh index 7deb2377..ad4c3f3e 100644 --- a/test/bash/increment-var.sh +++ b/test/bash/internals/increment-var.sh @@ -2,7 +2,7 @@ #!/usr/bin/env bash SRC=$(cd $(dirname "$0"); pwd) -source "${SRC}/include.sh" +source "${SRC}/../include.sh" cd $file_path/increment-var/ @@ -120,4 +120,4 @@ should "start 2 processes" "online" 2 should "start one process with NODE_APP_INSTANCE at 0" "NODE_APP_INSTANCE: 0" 1 should "start one process with NODE_APP_INSTANCE at 1" "NODE_APP_INSTANCE: 1" 1 should "start one process with PORT at 3000" "PORT: 3000" 2 -should "start one process with PORT at 3001" "PORT: 3001" 2 \ No newline at end of file +should "start one process with PORT at 3001" "PORT: 3001" 2 diff --git a/test/bash/infinite-loop.sh b/test/bash/internals/infinite-loop.sh similarity index 96% rename from test/bash/infinite-loop.sh rename to test/bash/internals/infinite-loop.sh index 809c71ae..f0528251 100644 --- a/test/bash/infinite-loop.sh +++ b/test/bash/internals/infinite-loop.sh @@ -1,7 +1,7 @@ #!/usr/bin/env bash SRC=$(cd $(dirname "$0"); pwd) -source "${SRC}/include.sh" +source "${SRC}/../include.sh" cd $file_path diff --git a/test/bash/listen-timeout.sh b/test/bash/internals/listen-timeout.sh similarity index 86% rename from test/bash/listen-timeout.sh rename to test/bash/internals/listen-timeout.sh index d9d9cc40..4d874e3d 100644 --- a/test/bash/listen-timeout.sh +++ b/test/bash/internals/listen-timeout.sh @@ -3,13 +3,14 @@ #export PM2_GRACEFUL_LISTEN_TIMEOUT=1000 SRC=$(cd $(dirname "$0"); pwd) -source "${SRC}/include.sh" +source "${SRC}/../include.sh" cd $file_path/listen-timeout/ echo -e "\033[1mENV REFRESH\033[0m" $pm2 start wait-ready.js -i 1 --wait-ready --listen-timeout 5000 -timeout 2 $pm2 reload all +$pm2 reload all & +sleep 2 should 'should have started 1 clustered app' 'online' 1 should 'should restart processes with new name' 'restart_time: 1' 1 diff --git a/test/bash/options-via-env.sh b/test/bash/internals/options-via-env.sh similarity index 93% rename from test/bash/options-via-env.sh rename to test/bash/internals/options-via-env.sh index c2049f50..bd644bf5 100644 --- a/test/bash/options-via-env.sh +++ b/test/bash/internals/options-via-env.sh @@ -2,7 +2,7 @@ #!/usr/bin/env bash SRC=$(cd $(dirname "$0"); pwd) -source "${SRC}/include.sh" +source "${SRC}/../include.sh" cd $file_path diff --git a/test/bash/promise.sh b/test/bash/internals/promise.sh similarity index 98% rename from test/bash/promise.sh rename to test/bash/internals/promise.sh index a4c1b6cb..fb36c2e1 100644 --- a/test/bash/promise.sh +++ b/test/bash/internals/promise.sh @@ -1,7 +1,7 @@ #!/usr/bin/env bash SRC=$(cd $(dirname "$0"); pwd) -source "${SRC}/include.sh" +source "${SRC}/../include.sh" cd $file_path/promise/ diff --git a/test/bash/signal.sh b/test/bash/internals/signal.sh similarity index 93% rename from test/bash/signal.sh rename to test/bash/internals/signal.sh index 3fb15af9..2182440b 100644 --- a/test/bash/signal.sh +++ b/test/bash/internals/signal.sh @@ -1,7 +1,7 @@ #!/usr/bin/env bash SRC=$(cd $(dirname "$0"); pwd) -source "${SRC}/include.sh" +source "${SRC}/../include.sh" cd $file_path @@ -15,7 +15,7 @@ $pm2 start signal.js -i 2 OUT_LOG=`$pm2 prettylist | grep -m 1 -E "pm_out_log_path:" | sed "s/.*'\([^']*\)',/\1/"` cat /dev/null > $OUT_LOG -$pm2 sendSignal SIGUSR2 signal.js +$pm2 sendSignal SIGUSR2 signal sleep 1 OUT=`grep "SIGUSR2" "$OUT_LOG" | wc -l` diff --git a/test/bash/source_map.sh b/test/bash/internals/source_map.sh similarity index 97% rename from test/bash/source_map.sh rename to test/bash/internals/source_map.sh index 896f6b75..368deee4 100644 --- a/test/bash/source_map.sh +++ b/test/bash/internals/source_map.sh @@ -1,7 +1,7 @@ #!/usr/bin/env bash SRC=$(cd $(dirname "$0"); pwd) -source "${SRC}/include.sh" +source "${SRC}/../include.sh" cd $file_path diff --git a/test/bash/start-consistency.sh b/test/bash/internals/start-consistency.sh similarity index 94% rename from test/bash/start-consistency.sh rename to test/bash/internals/start-consistency.sh index f7a9c682..ada5d84a 100644 --- a/test/bash/start-consistency.sh +++ b/test/bash/internals/start-consistency.sh @@ -1,7 +1,7 @@ #!/usr/bin/env bash SRC=$(cd $(dirname "$0"); pwd) -source "${SRC}/include.sh" +source "${SRC}/../include.sh" cd $file_path diff --git a/test/bash/wait-ready-event.sh b/test/bash/internals/wait-ready-event.sh similarity index 88% rename from test/bash/wait-ready-event.sh rename to test/bash/internals/wait-ready-event.sh index c4a326c6..f6c19d1b 100644 --- a/test/bash/wait-ready-event.sh +++ b/test/bash/internals/wait-ready-event.sh @@ -1,7 +1,7 @@ #!/usr/bin/env bash SRC=$(cd $(dirname "$0"); pwd) -source "${SRC}/include.sh" +source "${SRC}/../include.sh" cd $file_path/wait_ready_event @@ -21,7 +21,8 @@ should 'should have started 1 forked app ' 'online' 1 $pm2 delete all ##### start without sending event and ask to wait (fork mode) -timeout 5 $pm2 start http-wait-start_nocb.js --wait-ready --listen-timeout=8000 +$pm2 start http-wait-start_nocb.js --wait-ready --listen-timeout=8000 & +sleep 5 should 'should be 1 forked launching state app waiting for ready event' 'launching' 1 $pm2 delete all @@ -41,6 +42,7 @@ should 'should have started 1 clustered app' 'online' 1 $pm2 delete all ##### start without sending event and ask to wait (cluster mode) -timeout 5 $pm2 start http-wait-start_nocb.js -i 1 --wait-ready --listen-timeout=8000 +$pm2 start http-wait-start_nocb.js -i 1 --wait-ready --listen-timeout=8000 & +sleep 5 should 'should be 1 clustered launching state app waiting for ready event' 'launching' 1 $pm2 delete all diff --git a/test/bash/wrapped-fork.sh b/test/bash/internals/wrapped-fork.sh similarity index 94% rename from test/bash/wrapped-fork.sh rename to test/bash/internals/wrapped-fork.sh index 0731031c..475ea06f 100644 --- a/test/bash/wrapped-fork.sh +++ b/test/bash/internals/wrapped-fork.sh @@ -1,7 +1,7 @@ #!/usr/bin/env bash SRC=$(cd $(dirname "$0"); pwd) -source "${SRC}/include.sh" +source "${SRC}/../include.sh" cd $file_path diff --git a/test/bash/issues/2337.sh b/test/bash/issues/2337.sh deleted file mode 100644 index 67159ad1..00000000 --- a/test/bash/issues/2337.sh +++ /dev/null @@ -1,18 +0,0 @@ -#!/usr/bin/env bash - -SRC=$(cd $(dirname "$0"); pwd) -source "${SRC}/../include.sh" -cd $file_path - -echo -e "\033[1mRunning tests for json files :\033[0m" - -$pm2 start echo.js --name zero -f -$pm2 start echo.js --name one -f -$pm2 start echo.js --name two -f -should 'should have 3 processes online' 'online' 3 -$pm2 stop 0 -$pm2 stop 2 -$pm2 start echo.js --name three -f -$pm2 ls -should 'should have 2 processes online' 'online' 2 -should 'should have 2 processes stopped' 'stopped' 2 diff --git a/test/bash/log-custom.sh b/test/bash/logs/log-custom.sh similarity index 96% rename from test/bash/log-custom.sh rename to test/bash/logs/log-custom.sh index 8017f3c6..6a8ca50a 100644 --- a/test/bash/log-custom.sh +++ b/test/bash/logs/log-custom.sh @@ -2,7 +2,7 @@ #!/usr/bin/env bash SRC=$(cd $(dirname "$0"); pwd) -source "${SRC}/include.sh" +source "${SRC}/../include.sh" cd $file_path diff --git a/test/bash/log-entire.sh b/test/bash/logs/log-entire.sh similarity index 99% rename from test/bash/log-entire.sh rename to test/bash/logs/log-entire.sh index 50150ac4..d09804bc 100644 --- a/test/bash/log-entire.sh +++ b/test/bash/logs/log-entire.sh @@ -2,7 +2,7 @@ #!/usr/bin/env bash SRC=$(cd $(dirname "$0"); pwd) -source "${SRC}/include.sh" +source "${SRC}/../include.sh" function head { echo -e "\x1B[1;35m$1\x1B[0m" @@ -17,7 +17,7 @@ function test_dir { echo "$result" } function test { - sleep 3 + sleep 5 out_file=$(test_dir "out") err_file=$(test_dir "err") diff --git a/test/bash/log-json.sh b/test/bash/logs/log-json.sh similarity index 90% rename from test/bash/log-json.sh rename to test/bash/logs/log-json.sh index d602cc8f..14cf9af7 100644 --- a/test/bash/log-json.sh +++ b/test/bash/logs/log-json.sh @@ -2,7 +2,7 @@ #!/usr/bin/env bash SRC=$(cd $(dirname "$0"); pwd) -source "${SRC}/include.sh" +source "${SRC}/../include.sh" cd $file_path/log-json/ @@ -11,7 +11,7 @@ rm output.log # fork mode json logs $pm2 start ecosystem.json --only one-echo -! test -f output.log +! test -f output.log sleep 2 @@ -24,7 +24,7 @@ rm output.log # cluster mode json logs $pm2 start ecosystem.json -i 2 --only one-echo-cluster -! test -f output.log +! test -f output.log sleep 2 @@ -39,7 +39,7 @@ CURRENT_YEAR=`date +"%Y"` $pm2 start ecosystem.json --only one-echo-date -! test -f output.log +! test -f output.log sleep 2 @@ -57,7 +57,7 @@ rm output.log $pm2 start ecosystem.json --only one-echo-cluster-date -! test -f output.log +! test -f output.log sleep 2 @@ -69,4 +69,4 @@ OUT=`cat output.log | grep -o "$CURRENT_YEAR" | wc -l` success "should contains custom timestamp in cluster mode" $pm2 delete all -rm output.log \ No newline at end of file +rm output.log diff --git a/test/bash/log-null.sh b/test/bash/logs/log-null.sh similarity index 98% rename from test/bash/log-null.sh rename to test/bash/logs/log-null.sh index ed8c6b2a..5007d248 100644 --- a/test/bash/log-null.sh +++ b/test/bash/logs/log-null.sh @@ -2,7 +2,7 @@ #!/usr/bin/env bash SRC=$(cd $(dirname "$0"); pwd) -source "${SRC}/include.sh" +source "${SRC}/../include.sh" cd $file_path @@ -166,4 +166,4 @@ spec "out log shouldnt exist with /dev/null in fork mode" ! test -f ~/.pm2/logs/echo-error.log spec "error log shouldnt exist with /dev/null in fork mode" -$pm2 delete all \ No newline at end of file +$pm2 delete all diff --git a/test/bash/log-reload.sh b/test/bash/logs/log-reload.sh similarity index 96% rename from test/bash/log-reload.sh rename to test/bash/logs/log-reload.sh index 0227a6e8..ce64f5c6 100644 --- a/test/bash/log-reload.sh +++ b/test/bash/logs/log-reload.sh @@ -1,7 +1,7 @@ #!/usr/bin/env bash SRC=$(cd $(dirname "$0"); pwd) -source "${SRC}/include.sh" +source "${SRC}/../include.sh" cd $file_path diff --git a/test/bash/log-timestamp.sh b/test/bash/logs/log-timestamp.sh similarity index 98% rename from test/bash/log-timestamp.sh rename to test/bash/logs/log-timestamp.sh index 1a4d065f..d5308cbd 100644 --- a/test/bash/log-timestamp.sh +++ b/test/bash/logs/log-timestamp.sh @@ -1,7 +1,7 @@ #!/usr/bin/env bash SRC=$(cd $(dirname "$0"); pwd) -source "${SRC}/include.sh" +source "${SRC}/../include.sh" function head { echo -e "\x1B[1;35m$1\x1B[0m" diff --git a/test/bash/cron-system.sh b/test/bash/misc/cron-system.sh similarity index 100% rename from test/bash/cron-system.sh rename to test/bash/misc/cron-system.sh diff --git a/test/bash/docker.sh b/test/bash/misc/docker.sh similarity index 98% rename from test/bash/docker.sh rename to test/bash/misc/docker.sh index dcbeed6d..09174b73 100644 --- a/test/bash/docker.sh +++ b/test/bash/misc/docker.sh @@ -1,7 +1,7 @@ #!/usr/bin/env bash SRC=$(cd $(dirname "$0"); pwd) -source "${SRC}/include.sh" +source "${SRC}/../include.sh" # Docker should function dshould { diff --git a/test/bash/dump.sh b/test/bash/misc/dump.sh similarity index 100% rename from test/bash/dump.sh rename to test/bash/misc/dump.sh diff --git a/test/bash/file-descriptor.sh b/test/bash/misc/file-descriptor.sh similarity index 96% rename from test/bash/file-descriptor.sh rename to test/bash/misc/file-descriptor.sh index 1d3aa419..b51a676c 100644 --- a/test/bash/file-descriptor.sh +++ b/test/bash/misc/file-descriptor.sh @@ -5,7 +5,7 @@ # SRC=$(cd $(dirname "$0"); pwd) -source "${SRC}/include.sh" +source "${SRC}/../include.sh" cd $file_path diff --git a/test/bash/inside-pm2.sh b/test/bash/misc/inside-pm2.sh similarity index 100% rename from test/bash/inside-pm2.sh rename to test/bash/misc/inside-pm2.sh diff --git a/test/bash/instance-number.sh b/test/bash/misc/instance-number.sh similarity index 100% rename from test/bash/instance-number.sh rename to test/bash/misc/instance-number.sh diff --git a/test/bash/misc.sh b/test/bash/misc/misc.sh similarity index 100% rename from test/bash/misc.sh rename to test/bash/misc/misc.sh diff --git a/test/bash/nvm-node-version.sh b/test/bash/misc/nvm-node-version.sh similarity index 97% rename from test/bash/nvm-node-version.sh rename to test/bash/misc/nvm-node-version.sh index cb39919e..d9436f41 100644 --- a/test/bash/nvm-node-version.sh +++ b/test/bash/misc/nvm-node-version.sh @@ -1,7 +1,7 @@ #!/usr/bin/env bash SRC=$(cd $(dirname "$0"); pwd) -source "${SRC}/include.sh" +source "${SRC}/../include.sh" echo -e "\033[1mRunning tests:\033[0m" diff --git a/test/bash/pull.sh b/test/bash/misc/pull.sh similarity index 100% rename from test/bash/pull.sh rename to test/bash/misc/pull.sh diff --git a/test/bash/startup.sh b/test/bash/misc/startup.sh similarity index 100% rename from test/bash/startup.sh rename to test/bash/misc/startup.sh diff --git a/test/bash/versioning-cmd.sh b/test/bash/misc/versioning-cmd.sh similarity index 100% rename from test/bash/versioning-cmd.sh rename to test/bash/misc/versioning-cmd.sh diff --git a/test/bash/vizion.sh b/test/bash/misc/vizion.sh similarity index 100% rename from test/bash/vizion.sh rename to test/bash/misc/vizion.sh diff --git a/test/bash/get-set.sh b/test/bash/modules/get-set.sh similarity index 92% rename from test/bash/get-set.sh rename to test/bash/modules/get-set.sh index 76cfdc47..c1a64984 100644 --- a/test/bash/get-set.sh +++ b/test/bash/modules/get-set.sh @@ -1,7 +1,7 @@ #!/usr/bin/env bash SRC=$(cd $(dirname "$0"); pwd) -source "${SRC}/include.sh" +source "${SRC}/../include.sh" cd $file_path diff --git a/test/bash/module-safeguard.sh b/test/bash/modules/module-safeguard.sh similarity index 97% rename from test/bash/module-safeguard.sh rename to test/bash/modules/module-safeguard.sh index 4dcc8221..6b677879 100644 --- a/test/bash/module-safeguard.sh +++ b/test/bash/modules/module-safeguard.sh @@ -1,7 +1,7 @@ #!/usr/bin/env bash SRC=$(cd $(dirname "$0"); pwd) -source "${SRC}/include.sh" +source "${SRC}/../include.sh" echo -e "\033[1mRunning tests:\033[0m" diff --git a/test/bash/module.sh b/test/bash/modules/module.sh similarity index 98% rename from test/bash/module.sh rename to test/bash/modules/module.sh index 6a7a0a44..d3a0e077 100644 --- a/test/bash/module.sh +++ b/test/bash/modules/module.sh @@ -1,7 +1,7 @@ #!/usr/bin/env bash SRC=$(cd $(dirname "$0"); pwd) -source "${SRC}/include.sh" +source "${SRC}/../include.sh" echo -e "\033[1mRunning tests:\033[0m" diff --git a/test/bash/append-env-to-name.sh b/test/bash/process-file/append-env-to-name.sh similarity index 88% rename from test/bash/append-env-to-name.sh rename to test/bash/process-file/append-env-to-name.sh index cbecbd15..9acb8760 100644 --- a/test/bash/append-env-to-name.sh +++ b/test/bash/process-file/append-env-to-name.sh @@ -1,7 +1,7 @@ #!/usr/bin/env bash SRC=$(cd $(dirname "$0"); pwd) -source "${SRC}/include.sh" +source "${SRC}/../include.sh" cd $file_path @@ -11,4 +11,4 @@ $pm2 start append-env-to-name.json --env dev should 'have started app with name web-dev' "name: 'web-dev'" 3 $pm2 start append-env-to-name.json --env prod -should 'have started same app with name : web-prod' "name: 'web-prod'" 3 \ No newline at end of file +should 'have started same app with name : web-prod' "name: 'web-prod'" 3 diff --git a/test/bash/homogen-json-action.sh b/test/bash/process-file/homogen-json-action.sh similarity index 97% rename from test/bash/homogen-json-action.sh rename to test/bash/process-file/homogen-json-action.sh index 81c5b306..2111f839 100644 --- a/test/bash/homogen-json-action.sh +++ b/test/bash/process-file/homogen-json-action.sh @@ -1,7 +1,7 @@ #!/usr/bin/env bash SRC=$(cd $(dirname "$0"); pwd) -source "${SRC}/include.sh" +source "${SRC}/../include.sh" echo -e "\033[1mRunning tests:\033[0m" diff --git a/test/bash/js-configuration.sh b/test/bash/process-file/js-configuration.sh similarity index 58% rename from test/bash/js-configuration.sh rename to test/bash/process-file/js-configuration.sh index 6888ddd2..b5de850d 100644 --- a/test/bash/js-configuration.sh +++ b/test/bash/process-file/js-configuration.sh @@ -1,8 +1,8 @@ #!/usr/bin/env bash SRC=$(cd $(dirname "$0"); pwd) -source "${SRC}/include.sh" +source "${SRC}/../include.sh" cd $file_path/js-configuration $pm2 start ecosystem.config.js -should 'should have started 1 processes' 'online' 1 \ No newline at end of file +should 'should have started 1 processes' 'online' 1 diff --git a/test/bash/json-file.sh b/test/bash/process-file/json-file.sh similarity index 98% rename from test/bash/json-file.sh rename to test/bash/process-file/json-file.sh index 50c3ff35..f5927627 100644 --- a/test/bash/json-file.sh +++ b/test/bash/process-file/json-file.sh @@ -1,7 +1,7 @@ #!/usr/bin/env bash SRC=$(cd $(dirname "$0"); pwd) -source "${SRC}/include.sh" +source "${SRC}/../include.sh" cd $file_path echo -e "\033[1mRunning tests for json files :\033[0m" diff --git a/test/bash/json-reload.sh b/test/bash/process-file/json-reload.sh similarity index 98% rename from test/bash/json-reload.sh rename to test/bash/process-file/json-reload.sh index 64841bb9..2698fa87 100644 --- a/test/bash/json-reload.sh +++ b/test/bash/process-file/json-reload.sh @@ -2,7 +2,7 @@ #!/usr/bin/env bash SRC=$(cd $(dirname "$0"); pwd) -source "${SRC}/include.sh" +source "${SRC}/../include.sh" cd $file_path diff --git a/test/bash/yaml-configuration.sh b/test/bash/process-file/yaml-configuration.sh similarity index 96% rename from test/bash/yaml-configuration.sh rename to test/bash/process-file/yaml-configuration.sh index 4286309c..51c4e71a 100644 --- a/test/bash/yaml-configuration.sh +++ b/test/bash/process-file/yaml-configuration.sh @@ -1,7 +1,7 @@ #!/usr/bin/env bash SRC=$(cd $(dirname "$0"); pwd) -source "${SRC}/include.sh" +source "${SRC}/../include.sh" cd $file_path/yaml-configuration $pm2 start non-existent.yaml diff --git a/test/bash/gracefulReload.sh b/test/bash/reload/gracefulReload.sh similarity index 96% rename from test/bash/gracefulReload.sh rename to test/bash/reload/gracefulReload.sh index e7ed9fce..625f1a19 100644 --- a/test/bash/gracefulReload.sh +++ b/test/bash/reload/gracefulReload.sh @@ -1,7 +1,7 @@ #!/usr/bin/env bash SRC=$(cd $(dirname "$0"); pwd) -source "${SRC}/include.sh" +source "${SRC}/../include.sh" cd $file_path diff --git a/test/bash/gracefulReload2.sh b/test/bash/reload/gracefulReload2.sh similarity index 95% rename from test/bash/gracefulReload2.sh rename to test/bash/reload/gracefulReload2.sh index b7c25fdd..15dbc924 100644 --- a/test/bash/gracefulReload2.sh +++ b/test/bash/reload/gracefulReload2.sh @@ -1,7 +1,7 @@ #!/usr/bin/env bash SRC=$(cd $(dirname "$0"); pwd) -source "${SRC}/include.sh" +source "${SRC}/../include.sh" cd $file_path diff --git a/test/bash/gracefulReload3.sh b/test/bash/reload/gracefulReload3.sh similarity index 95% rename from test/bash/gracefulReload3.sh rename to test/bash/reload/gracefulReload3.sh index 307d74f6..fc661a99 100644 --- a/test/bash/gracefulReload3.sh +++ b/test/bash/reload/gracefulReload3.sh @@ -1,7 +1,7 @@ #!/usr/bin/env bash SRC=$(cd $(dirname "$0"); pwd) -source "${SRC}/include.sh" +source "${SRC}/../include.sh" cd $file_path diff --git a/test/bash/reload.sh b/test/bash/reload/reload.sh similarity index 98% rename from test/bash/reload.sh rename to test/bash/reload/reload.sh index d659a1b6..3653c522 100644 --- a/test/bash/reload.sh +++ b/test/bash/reload/reload.sh @@ -1,7 +1,7 @@ #!/usr/bin/env bash SRC=$(cd $(dirname "$0"); pwd) -source "${SRC}/include.sh" +source "${SRC}/../include.sh" cd $file_path diff --git a/test/docker_parallel_test.sh b/test/docker_parallel_test.sh index 4b2b73a4..0f8fe6ac 100644 --- a/test/docker_parallel_test.sh +++ b/test/docker_parallel_test.sh @@ -1,3 +1,20 @@ -# docker build -t pm2-test -f test/Dockerfile . -docker run -v `pwd`:/var/pm2 pm2-test mocha ./test/programmatic/api.mocha.js -docker run -v `pwd`:/var/pm2 pm2-test mocha ./test/programmatic/client.mocha.js +set -e + +docker build -t pm2-test -f test/Dockerfile . + +JOBS=20 + +# cli ok +ls test/bash/cli/* | parallel --jobs $JOBS --no-notice --halt now,success=0 --joblog joblog-X docker run -v `pwd`:/var/pm2 pm2-test bash +# process-file ok +ls test/bash/process-file/* | parallel --jobs $JOBS --no-notice --halt now,success=0 --joblog joblog-X docker run -v `pwd`:/var/pm2 pm2-test bash +# logs ok +# misc +# reload ok +ls test/bash/reload/* | parallel --jobs $JOBS --no-notice --halt now,success=0 --joblog joblog-X docker run -v `pwd`:/var/pm2 pm2-test bash +# internals ok +ls test/bash/internal/* | parallel --jobs $JOBS --no-notice --halt now,success=0 --joblog joblog-X docker run -v `pwd`:/var/pm2 pm2-test bash +# modules ok +ls test/bash/modules/* | parallel --jobs $JOBS --no-notice --halt now,success=0 --joblog joblog-X docker run -v `pwd`:/var/pm2 pm2-test bash +# binaries ok +ls test/bash/binaries/* | parallel --jobs $JOBS --no-notice --halt now,success=0 --joblog joblog-X docker run -v `pwd`:/var/pm2 pm2-test bash diff --git a/test/parallel_programmatic_tests.sh b/test/parallel_programmatic_tests.sh deleted file mode 100755 index d4e40e9a..00000000 --- a/test/parallel_programmatic_tests.sh +++ /dev/null @@ -1,26 +0,0 @@ -#!/bin/bash - -export NODE_ENV='test' - -function fail { - echo -e "######## \033[31m ✘ $1\033[0m" -} - -function success { - echo -e "\033[32m------------> ✔ $1\033[0m" -} - -function spec { - [ $? -eq 0 ] || fail "$1" - success "$1" -} - -pkill -f PM2 - -cd test/ - -parallel --gnu --keep-order --joblog joblog --halt now,fail=1 -j+0 < programmatic_commands.txt -spec "Should text have passed" -cat joblog - -# possible to pass --tmux diff --git a/test/programmatic/configuration.mocha.js b/test/programmatic/configuration.mocha.js index 0a2bc86a..7ff040d7 100644 --- a/test/programmatic/configuration.mocha.js +++ b/test/programmatic/configuration.mocha.js @@ -1,9 +1,14 @@ -var should = require('should'); +var should = require('should'); +var PM2 = require('../..'); var Configuration = require('../../lib/Configuration.js'); describe('Configuration via SET / GET tests', function() { + before(function(done) { + PM2.list(done); + }); + it('should set a value', function(done) { Configuration.set('key1', 'val1', function(err, data) { should.not.exists(err); diff --git a/test/programmatic/reload-locker.mocha.js b/test/programmatic/reload-locker.mocha.js index c07fc0c3..0e07938c 100644 --- a/test/programmatic/reload-locker.mocha.js +++ b/test/programmatic/reload-locker.mocha.js @@ -17,6 +17,10 @@ describe('Reload locker system', function() { cwd : '../fixtures' }); + before(function(done) { + pm2.list(done); + }); + after(function(done) { pm2.kill(done) }); diff --git a/test/programmatic_commands.txt b/test/programmatic_commands.txt deleted file mode 100644 index f8e9053e..00000000 --- a/test/programmatic_commands.txt +++ /dev/null @@ -1,22 +0,0 @@ -mocha ./programmatic/god.mocha.js -mocha ./programmatic/programmatic.js -mocha ./programmatic/logs.js -mocha ./programmatic/watcher.js -mocha ./programmatic/max_memory_limit.js -mocha ./programmatic/cluster.mocha.js -mocha ./programmatic/misc_commands.js -mocha ./programmatic/signals.js -mocha ./programmatic/send_data_process.mocha.js -mocha ./programmatic/return.mocha.js -mocha ./programmatic/json_validation.mocha.js -mocha ./programmatic/env_switching.js -mocha ./programmatic/configuration.mocha.js -mocha ./interface/interactor.connect.mocha.js -mocha ./interface/interactor.daemonizer.mocha.js -mocha ./interface/remote.mocha.js -mocha ./interface/scoped_pm2_actions.mocha.js -mocha ./interface/password.mocha.js -mocha ./interface/custom-actions.mocha.js -mocha ./interface/bus.spec.mocha.js -mocha ./interface/bus.fork.spec.mocha.js -mocha ./interface/request.mocha.js From 282186f24b19b010999f7c7c49750935ef19c190 Mon Sep 17 00:00:00 2001 From: Unitech Date: Mon, 26 Feb 2018 20:19:22 +0100 Subject: [PATCH 011/140] refactor: change params --- .gitignore | 1 + .travis.yml | 1 - test/docker_parallel_test.sh | 4 ++-- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.gitignore b/.gitignore index 31e1bf66..786a0100 100644 --- a/.gitignore +++ b/.gitignore @@ -15,3 +15,4 @@ package-lock.json *.swp *.swo currentTagChangelog.md +joblog-X diff --git a/.travis.yml b/.travis.yml index 93a4007c..27286f64 100644 --- a/.travis.yml +++ b/.travis.yml @@ -8,7 +8,6 @@ os: - linux before_install: - sudo apt-get -qq update - - sudo apt-get install php5-cli - sudo apt-get install parallel services: - docker diff --git a/test/docker_parallel_test.sh b/test/docker_parallel_test.sh index 0f8fe6ac..e8b3b7c2 100644 --- a/test/docker_parallel_test.sh +++ b/test/docker_parallel_test.sh @@ -3,9 +3,9 @@ set -e docker build -t pm2-test -f test/Dockerfile . JOBS=20 - +OPTS="--jobs $JOBS --no-notice --joblog joblog-X docker run -v `pwd`:/var/pm2 pm2-test" # cli ok -ls test/bash/cli/* | parallel --jobs $JOBS --no-notice --halt now,success=0 --joblog joblog-X docker run -v `pwd`:/var/pm2 pm2-test bash +ls test/bash/cli/* | parallel $OPTS bash # process-file ok ls test/bash/process-file/* | parallel --jobs $JOBS --no-notice --halt now,success=0 --joblog joblog-X docker run -v `pwd`:/var/pm2 pm2-test bash # logs ok From 8a7db95aabc8437f292af0316cec81ab80ec41f5 Mon Sep 17 00:00:00 2001 From: Unitech Date: Mon, 26 Feb 2018 20:41:08 +0100 Subject: [PATCH 012/140] refactor: e2e rename --- test/docker_parallel_test.sh | 21 +++++++++++-------- test/{bash => e2e}/agent/interact.sh | 0 test/{bash => e2e}/binaries/pm2-dev.sh | 0 test/{bash => e2e}/binaries/pm2-runtime.sh | 0 test/{bash => e2e}/cli/app-config-update.sh | 0 test/{bash => e2e}/cli/app-configuration.sh | 0 test/{bash => e2e}/cli/args.sh | 0 test/{bash => e2e}/cli/attach.sh | 0 test/{bash => e2e}/cli/binary.sh | 0 test/{bash => e2e}/cli/cli-actions-1.sh | 0 test/{bash => e2e}/cli/cli-actions-2.sh | 0 test/{bash => e2e}/cli/env-refresh.sh | 0 test/{bash => e2e}/cli/extra-lang.sh | 0 test/{bash => e2e}/cli/fork.sh | 0 test/{bash => e2e}/cli/harmony.sh | 0 test/{bash => e2e}/cli/interpreter.sh | 0 test/{bash => e2e}/cli/mjs.sh | 0 test/{bash => e2e}/cli/monit.sh | 0 test/{bash => e2e}/cli/multiparam.sh | 0 test/{bash => e2e}/cli/operate-regex.sh | 0 test/{bash => e2e}/cli/piped-config.sh | 0 test/{bash => e2e}/cli/reset.sh | 0 test/{bash => e2e}/cli/resurrect.sh | 0 test/{bash => e2e}/cli/right-exit-code.sh | 0 test/{bash => e2e}/cli/serve.sh | 0 test/{bash => e2e}/cli/smart-start.sh | 0 test/{bash => e2e}/cli/sort.sh | 0 test/{bash => e2e}/cli/startOrX.sh | 0 test/{bash => e2e}/cli/watch.sh | 0 test/{bash => e2e}/include.sh | 0 .../internals/daemon-paths-override.sh | 0 test/{bash => e2e}/internals/increment-var.sh | 0 test/{bash => e2e}/internals/infinite-loop.sh | 0 .../{bash => e2e}/internals/listen-timeout.sh | 0 .../internals/options-via-env.sh | 0 test/{bash => e2e}/internals/promise.sh | 0 test/{bash => e2e}/internals/signal.sh | 0 test/{bash => e2e}/internals/source_map.sh | 0 .../internals/start-consistency.sh | 0 .../internals/wait-ready-event.sh | 0 test/{bash => e2e}/internals/wrapped-fork.sh | 0 test/{bash => e2e}/logs/log-custom.sh | 0 test/{bash => e2e}/logs/log-entire.sh | 0 test/{bash => e2e}/logs/log-json.sh | 0 test/{bash => e2e}/logs/log-null.sh | 0 test/{bash => e2e}/logs/log-reload.sh | 0 test/{bash => e2e}/logs/log-timestamp.sh | 0 test/{bash => e2e}/misc/cron-system.sh | 0 test/{bash => e2e}/misc/docker.sh | 0 test/{bash => e2e}/misc/dump.sh | 0 test/{bash => e2e}/misc/file-descriptor.sh | 0 test/{bash => e2e}/misc/inside-pm2.sh | 0 test/{bash => e2e}/misc/instance-number.sh | 0 test/{bash => e2e}/misc/misc.sh | 0 test/{bash => e2e}/misc/nvm-node-version.sh | 0 test/{bash => e2e}/misc/pull.sh | 0 test/{bash => e2e}/misc/startup.sh | 0 test/{bash => e2e}/misc/versioning-cmd.sh | 0 test/{bash => e2e}/misc/vizion.sh | 0 test/{bash => e2e}/modules/get-set.sh | 0 .../{bash => e2e}/modules/module-safeguard.sh | 0 test/{bash => e2e}/modules/module.sh | 0 .../process-file/append-env-to-name.sh | 0 .../process-file/homogen-json-action.sh | 0 .../process-file/js-configuration.sh | 0 test/{bash => e2e}/process-file/json-file.sh | 0 .../{bash => e2e}/process-file/json-reload.sh | 0 .../process-file/yaml-configuration.sh | 0 test/{bash => e2e}/reload/gracefulReload.sh | 0 test/{bash => e2e}/reload/gracefulReload2.sh | 0 test/{bash => e2e}/reload/gracefulReload3.sh | 0 test/{bash => e2e}/reload/reload.sh | 0 72 files changed, 12 insertions(+), 9 deletions(-) rename test/{bash => e2e}/agent/interact.sh (100%) rename test/{bash => e2e}/binaries/pm2-dev.sh (100%) rename test/{bash => e2e}/binaries/pm2-runtime.sh (100%) rename test/{bash => e2e}/cli/app-config-update.sh (100%) rename test/{bash => e2e}/cli/app-configuration.sh (100%) rename test/{bash => e2e}/cli/args.sh (100%) rename test/{bash => e2e}/cli/attach.sh (100%) rename test/{bash => e2e}/cli/binary.sh (100%) rename test/{bash => e2e}/cli/cli-actions-1.sh (100%) rename test/{bash => e2e}/cli/cli-actions-2.sh (100%) rename test/{bash => e2e}/cli/env-refresh.sh (100%) rename test/{bash => e2e}/cli/extra-lang.sh (100%) rename test/{bash => e2e}/cli/fork.sh (100%) rename test/{bash => e2e}/cli/harmony.sh (100%) rename test/{bash => e2e}/cli/interpreter.sh (100%) rename test/{bash => e2e}/cli/mjs.sh (100%) rename test/{bash => e2e}/cli/monit.sh (100%) rename test/{bash => e2e}/cli/multiparam.sh (100%) rename test/{bash => e2e}/cli/operate-regex.sh (100%) rename test/{bash => e2e}/cli/piped-config.sh (100%) rename test/{bash => e2e}/cli/reset.sh (100%) rename test/{bash => e2e}/cli/resurrect.sh (100%) rename test/{bash => e2e}/cli/right-exit-code.sh (100%) rename test/{bash => e2e}/cli/serve.sh (100%) rename test/{bash => e2e}/cli/smart-start.sh (100%) rename test/{bash => e2e}/cli/sort.sh (100%) rename test/{bash => e2e}/cli/startOrX.sh (100%) rename test/{bash => e2e}/cli/watch.sh (100%) rename test/{bash => e2e}/include.sh (100%) rename test/{bash => e2e}/internals/daemon-paths-override.sh (100%) rename test/{bash => e2e}/internals/increment-var.sh (100%) rename test/{bash => e2e}/internals/infinite-loop.sh (100%) rename test/{bash => e2e}/internals/listen-timeout.sh (100%) rename test/{bash => e2e}/internals/options-via-env.sh (100%) rename test/{bash => e2e}/internals/promise.sh (100%) rename test/{bash => e2e}/internals/signal.sh (100%) rename test/{bash => e2e}/internals/source_map.sh (100%) rename test/{bash => e2e}/internals/start-consistency.sh (100%) rename test/{bash => e2e}/internals/wait-ready-event.sh (100%) rename test/{bash => e2e}/internals/wrapped-fork.sh (100%) rename test/{bash => e2e}/logs/log-custom.sh (100%) rename test/{bash => e2e}/logs/log-entire.sh (100%) rename test/{bash => e2e}/logs/log-json.sh (100%) rename test/{bash => e2e}/logs/log-null.sh (100%) rename test/{bash => e2e}/logs/log-reload.sh (100%) rename test/{bash => e2e}/logs/log-timestamp.sh (100%) rename test/{bash => e2e}/misc/cron-system.sh (100%) rename test/{bash => e2e}/misc/docker.sh (100%) rename test/{bash => e2e}/misc/dump.sh (100%) rename test/{bash => e2e}/misc/file-descriptor.sh (100%) rename test/{bash => e2e}/misc/inside-pm2.sh (100%) rename test/{bash => e2e}/misc/instance-number.sh (100%) rename test/{bash => e2e}/misc/misc.sh (100%) rename test/{bash => e2e}/misc/nvm-node-version.sh (100%) rename test/{bash => e2e}/misc/pull.sh (100%) rename test/{bash => e2e}/misc/startup.sh (100%) rename test/{bash => e2e}/misc/versioning-cmd.sh (100%) rename test/{bash => e2e}/misc/vizion.sh (100%) rename test/{bash => e2e}/modules/get-set.sh (100%) rename test/{bash => e2e}/modules/module-safeguard.sh (100%) rename test/{bash => e2e}/modules/module.sh (100%) rename test/{bash => e2e}/process-file/append-env-to-name.sh (100%) rename test/{bash => e2e}/process-file/homogen-json-action.sh (100%) rename test/{bash => e2e}/process-file/js-configuration.sh (100%) rename test/{bash => e2e}/process-file/json-file.sh (100%) rename test/{bash => e2e}/process-file/json-reload.sh (100%) rename test/{bash => e2e}/process-file/yaml-configuration.sh (100%) rename test/{bash => e2e}/reload/gracefulReload.sh (100%) rename test/{bash => e2e}/reload/gracefulReload2.sh (100%) rename test/{bash => e2e}/reload/gracefulReload3.sh (100%) rename test/{bash => e2e}/reload/reload.sh (100%) diff --git a/test/docker_parallel_test.sh b/test/docker_parallel_test.sh index e8b3b7c2..1b9ffe35 100644 --- a/test/docker_parallel_test.sh +++ b/test/docker_parallel_test.sh @@ -3,18 +3,21 @@ set -e docker build -t pm2-test -f test/Dockerfile . JOBS=20 -OPTS="--jobs $JOBS --no-notice --joblog joblog-X docker run -v `pwd`:/var/pm2 pm2-test" -# cli ok -ls test/bash/cli/* | parallel $OPTS bash +OPTS="--jobs $JOBS --joblog joblog-X docker run -v `pwd`:/var/pm2 pm2-test" + # process-file ok -ls test/bash/process-file/* | parallel --jobs $JOBS --no-notice --halt now,success=0 --joblog joblog-X docker run -v `pwd`:/var/pm2 pm2-test bash +ls test/e2e/process-file/* | parallel $OPTS bash +# cli ok +ls test/e2e/cli/* | parallel $OPTS bash # logs ok -# misc +ls test/e2e/logs/* | parallel $OPTS bash # reload ok -ls test/bash/reload/* | parallel --jobs $JOBS --no-notice --halt now,success=0 --joblog joblog-X docker run -v `pwd`:/var/pm2 pm2-test bash +ls test/e2e/reload/* | parallel $OPTS bash # internals ok -ls test/bash/internal/* | parallel --jobs $JOBS --no-notice --halt now,success=0 --joblog joblog-X docker run -v `pwd`:/var/pm2 pm2-test bash +ls test/e2e/internal/* | parallel $OPTS bash # modules ok -ls test/bash/modules/* | parallel --jobs $JOBS --no-notice --halt now,success=0 --joblog joblog-X docker run -v `pwd`:/var/pm2 pm2-test bash +ls test/e2e/modules/* | parallel $OPTS bash # binaries ok -ls test/bash/binaries/* | parallel --jobs $JOBS --no-notice --halt now,success=0 --joblog joblog-X docker run -v `pwd`:/var/pm2 pm2-test bash +ls test/e2e/binaries/* | parallel $OPTS bash + +# misc diff --git a/test/bash/agent/interact.sh b/test/e2e/agent/interact.sh similarity index 100% rename from test/bash/agent/interact.sh rename to test/e2e/agent/interact.sh diff --git a/test/bash/binaries/pm2-dev.sh b/test/e2e/binaries/pm2-dev.sh similarity index 100% rename from test/bash/binaries/pm2-dev.sh rename to test/e2e/binaries/pm2-dev.sh diff --git a/test/bash/binaries/pm2-runtime.sh b/test/e2e/binaries/pm2-runtime.sh similarity index 100% rename from test/bash/binaries/pm2-runtime.sh rename to test/e2e/binaries/pm2-runtime.sh diff --git a/test/bash/cli/app-config-update.sh b/test/e2e/cli/app-config-update.sh similarity index 100% rename from test/bash/cli/app-config-update.sh rename to test/e2e/cli/app-config-update.sh diff --git a/test/bash/cli/app-configuration.sh b/test/e2e/cli/app-configuration.sh similarity index 100% rename from test/bash/cli/app-configuration.sh rename to test/e2e/cli/app-configuration.sh diff --git a/test/bash/cli/args.sh b/test/e2e/cli/args.sh similarity index 100% rename from test/bash/cli/args.sh rename to test/e2e/cli/args.sh diff --git a/test/bash/cli/attach.sh b/test/e2e/cli/attach.sh similarity index 100% rename from test/bash/cli/attach.sh rename to test/e2e/cli/attach.sh diff --git a/test/bash/cli/binary.sh b/test/e2e/cli/binary.sh similarity index 100% rename from test/bash/cli/binary.sh rename to test/e2e/cli/binary.sh diff --git a/test/bash/cli/cli-actions-1.sh b/test/e2e/cli/cli-actions-1.sh similarity index 100% rename from test/bash/cli/cli-actions-1.sh rename to test/e2e/cli/cli-actions-1.sh diff --git a/test/bash/cli/cli-actions-2.sh b/test/e2e/cli/cli-actions-2.sh similarity index 100% rename from test/bash/cli/cli-actions-2.sh rename to test/e2e/cli/cli-actions-2.sh diff --git a/test/bash/cli/env-refresh.sh b/test/e2e/cli/env-refresh.sh similarity index 100% rename from test/bash/cli/env-refresh.sh rename to test/e2e/cli/env-refresh.sh diff --git a/test/bash/cli/extra-lang.sh b/test/e2e/cli/extra-lang.sh similarity index 100% rename from test/bash/cli/extra-lang.sh rename to test/e2e/cli/extra-lang.sh diff --git a/test/bash/cli/fork.sh b/test/e2e/cli/fork.sh similarity index 100% rename from test/bash/cli/fork.sh rename to test/e2e/cli/fork.sh diff --git a/test/bash/cli/harmony.sh b/test/e2e/cli/harmony.sh similarity index 100% rename from test/bash/cli/harmony.sh rename to test/e2e/cli/harmony.sh diff --git a/test/bash/cli/interpreter.sh b/test/e2e/cli/interpreter.sh similarity index 100% rename from test/bash/cli/interpreter.sh rename to test/e2e/cli/interpreter.sh diff --git a/test/bash/cli/mjs.sh b/test/e2e/cli/mjs.sh similarity index 100% rename from test/bash/cli/mjs.sh rename to test/e2e/cli/mjs.sh diff --git a/test/bash/cli/monit.sh b/test/e2e/cli/monit.sh similarity index 100% rename from test/bash/cli/monit.sh rename to test/e2e/cli/monit.sh diff --git a/test/bash/cli/multiparam.sh b/test/e2e/cli/multiparam.sh similarity index 100% rename from test/bash/cli/multiparam.sh rename to test/e2e/cli/multiparam.sh diff --git a/test/bash/cli/operate-regex.sh b/test/e2e/cli/operate-regex.sh similarity index 100% rename from test/bash/cli/operate-regex.sh rename to test/e2e/cli/operate-regex.sh diff --git a/test/bash/cli/piped-config.sh b/test/e2e/cli/piped-config.sh similarity index 100% rename from test/bash/cli/piped-config.sh rename to test/e2e/cli/piped-config.sh diff --git a/test/bash/cli/reset.sh b/test/e2e/cli/reset.sh similarity index 100% rename from test/bash/cli/reset.sh rename to test/e2e/cli/reset.sh diff --git a/test/bash/cli/resurrect.sh b/test/e2e/cli/resurrect.sh similarity index 100% rename from test/bash/cli/resurrect.sh rename to test/e2e/cli/resurrect.sh diff --git a/test/bash/cli/right-exit-code.sh b/test/e2e/cli/right-exit-code.sh similarity index 100% rename from test/bash/cli/right-exit-code.sh rename to test/e2e/cli/right-exit-code.sh diff --git a/test/bash/cli/serve.sh b/test/e2e/cli/serve.sh similarity index 100% rename from test/bash/cli/serve.sh rename to test/e2e/cli/serve.sh diff --git a/test/bash/cli/smart-start.sh b/test/e2e/cli/smart-start.sh similarity index 100% rename from test/bash/cli/smart-start.sh rename to test/e2e/cli/smart-start.sh diff --git a/test/bash/cli/sort.sh b/test/e2e/cli/sort.sh similarity index 100% rename from test/bash/cli/sort.sh rename to test/e2e/cli/sort.sh diff --git a/test/bash/cli/startOrX.sh b/test/e2e/cli/startOrX.sh similarity index 100% rename from test/bash/cli/startOrX.sh rename to test/e2e/cli/startOrX.sh diff --git a/test/bash/cli/watch.sh b/test/e2e/cli/watch.sh similarity index 100% rename from test/bash/cli/watch.sh rename to test/e2e/cli/watch.sh diff --git a/test/bash/include.sh b/test/e2e/include.sh similarity index 100% rename from test/bash/include.sh rename to test/e2e/include.sh diff --git a/test/bash/internals/daemon-paths-override.sh b/test/e2e/internals/daemon-paths-override.sh similarity index 100% rename from test/bash/internals/daemon-paths-override.sh rename to test/e2e/internals/daemon-paths-override.sh diff --git a/test/bash/internals/increment-var.sh b/test/e2e/internals/increment-var.sh similarity index 100% rename from test/bash/internals/increment-var.sh rename to test/e2e/internals/increment-var.sh diff --git a/test/bash/internals/infinite-loop.sh b/test/e2e/internals/infinite-loop.sh similarity index 100% rename from test/bash/internals/infinite-loop.sh rename to test/e2e/internals/infinite-loop.sh diff --git a/test/bash/internals/listen-timeout.sh b/test/e2e/internals/listen-timeout.sh similarity index 100% rename from test/bash/internals/listen-timeout.sh rename to test/e2e/internals/listen-timeout.sh diff --git a/test/bash/internals/options-via-env.sh b/test/e2e/internals/options-via-env.sh similarity index 100% rename from test/bash/internals/options-via-env.sh rename to test/e2e/internals/options-via-env.sh diff --git a/test/bash/internals/promise.sh b/test/e2e/internals/promise.sh similarity index 100% rename from test/bash/internals/promise.sh rename to test/e2e/internals/promise.sh diff --git a/test/bash/internals/signal.sh b/test/e2e/internals/signal.sh similarity index 100% rename from test/bash/internals/signal.sh rename to test/e2e/internals/signal.sh diff --git a/test/bash/internals/source_map.sh b/test/e2e/internals/source_map.sh similarity index 100% rename from test/bash/internals/source_map.sh rename to test/e2e/internals/source_map.sh diff --git a/test/bash/internals/start-consistency.sh b/test/e2e/internals/start-consistency.sh similarity index 100% rename from test/bash/internals/start-consistency.sh rename to test/e2e/internals/start-consistency.sh diff --git a/test/bash/internals/wait-ready-event.sh b/test/e2e/internals/wait-ready-event.sh similarity index 100% rename from test/bash/internals/wait-ready-event.sh rename to test/e2e/internals/wait-ready-event.sh diff --git a/test/bash/internals/wrapped-fork.sh b/test/e2e/internals/wrapped-fork.sh similarity index 100% rename from test/bash/internals/wrapped-fork.sh rename to test/e2e/internals/wrapped-fork.sh diff --git a/test/bash/logs/log-custom.sh b/test/e2e/logs/log-custom.sh similarity index 100% rename from test/bash/logs/log-custom.sh rename to test/e2e/logs/log-custom.sh diff --git a/test/bash/logs/log-entire.sh b/test/e2e/logs/log-entire.sh similarity index 100% rename from test/bash/logs/log-entire.sh rename to test/e2e/logs/log-entire.sh diff --git a/test/bash/logs/log-json.sh b/test/e2e/logs/log-json.sh similarity index 100% rename from test/bash/logs/log-json.sh rename to test/e2e/logs/log-json.sh diff --git a/test/bash/logs/log-null.sh b/test/e2e/logs/log-null.sh similarity index 100% rename from test/bash/logs/log-null.sh rename to test/e2e/logs/log-null.sh diff --git a/test/bash/logs/log-reload.sh b/test/e2e/logs/log-reload.sh similarity index 100% rename from test/bash/logs/log-reload.sh rename to test/e2e/logs/log-reload.sh diff --git a/test/bash/logs/log-timestamp.sh b/test/e2e/logs/log-timestamp.sh similarity index 100% rename from test/bash/logs/log-timestamp.sh rename to test/e2e/logs/log-timestamp.sh diff --git a/test/bash/misc/cron-system.sh b/test/e2e/misc/cron-system.sh similarity index 100% rename from test/bash/misc/cron-system.sh rename to test/e2e/misc/cron-system.sh diff --git a/test/bash/misc/docker.sh b/test/e2e/misc/docker.sh similarity index 100% rename from test/bash/misc/docker.sh rename to test/e2e/misc/docker.sh diff --git a/test/bash/misc/dump.sh b/test/e2e/misc/dump.sh similarity index 100% rename from test/bash/misc/dump.sh rename to test/e2e/misc/dump.sh diff --git a/test/bash/misc/file-descriptor.sh b/test/e2e/misc/file-descriptor.sh similarity index 100% rename from test/bash/misc/file-descriptor.sh rename to test/e2e/misc/file-descriptor.sh diff --git a/test/bash/misc/inside-pm2.sh b/test/e2e/misc/inside-pm2.sh similarity index 100% rename from test/bash/misc/inside-pm2.sh rename to test/e2e/misc/inside-pm2.sh diff --git a/test/bash/misc/instance-number.sh b/test/e2e/misc/instance-number.sh similarity index 100% rename from test/bash/misc/instance-number.sh rename to test/e2e/misc/instance-number.sh diff --git a/test/bash/misc/misc.sh b/test/e2e/misc/misc.sh similarity index 100% rename from test/bash/misc/misc.sh rename to test/e2e/misc/misc.sh diff --git a/test/bash/misc/nvm-node-version.sh b/test/e2e/misc/nvm-node-version.sh similarity index 100% rename from test/bash/misc/nvm-node-version.sh rename to test/e2e/misc/nvm-node-version.sh diff --git a/test/bash/misc/pull.sh b/test/e2e/misc/pull.sh similarity index 100% rename from test/bash/misc/pull.sh rename to test/e2e/misc/pull.sh diff --git a/test/bash/misc/startup.sh b/test/e2e/misc/startup.sh similarity index 100% rename from test/bash/misc/startup.sh rename to test/e2e/misc/startup.sh diff --git a/test/bash/misc/versioning-cmd.sh b/test/e2e/misc/versioning-cmd.sh similarity index 100% rename from test/bash/misc/versioning-cmd.sh rename to test/e2e/misc/versioning-cmd.sh diff --git a/test/bash/misc/vizion.sh b/test/e2e/misc/vizion.sh similarity index 100% rename from test/bash/misc/vizion.sh rename to test/e2e/misc/vizion.sh diff --git a/test/bash/modules/get-set.sh b/test/e2e/modules/get-set.sh similarity index 100% rename from test/bash/modules/get-set.sh rename to test/e2e/modules/get-set.sh diff --git a/test/bash/modules/module-safeguard.sh b/test/e2e/modules/module-safeguard.sh similarity index 100% rename from test/bash/modules/module-safeguard.sh rename to test/e2e/modules/module-safeguard.sh diff --git a/test/bash/modules/module.sh b/test/e2e/modules/module.sh similarity index 100% rename from test/bash/modules/module.sh rename to test/e2e/modules/module.sh diff --git a/test/bash/process-file/append-env-to-name.sh b/test/e2e/process-file/append-env-to-name.sh similarity index 100% rename from test/bash/process-file/append-env-to-name.sh rename to test/e2e/process-file/append-env-to-name.sh diff --git a/test/bash/process-file/homogen-json-action.sh b/test/e2e/process-file/homogen-json-action.sh similarity index 100% rename from test/bash/process-file/homogen-json-action.sh rename to test/e2e/process-file/homogen-json-action.sh diff --git a/test/bash/process-file/js-configuration.sh b/test/e2e/process-file/js-configuration.sh similarity index 100% rename from test/bash/process-file/js-configuration.sh rename to test/e2e/process-file/js-configuration.sh diff --git a/test/bash/process-file/json-file.sh b/test/e2e/process-file/json-file.sh similarity index 100% rename from test/bash/process-file/json-file.sh rename to test/e2e/process-file/json-file.sh diff --git a/test/bash/process-file/json-reload.sh b/test/e2e/process-file/json-reload.sh similarity index 100% rename from test/bash/process-file/json-reload.sh rename to test/e2e/process-file/json-reload.sh diff --git a/test/bash/process-file/yaml-configuration.sh b/test/e2e/process-file/yaml-configuration.sh similarity index 100% rename from test/bash/process-file/yaml-configuration.sh rename to test/e2e/process-file/yaml-configuration.sh diff --git a/test/bash/reload/gracefulReload.sh b/test/e2e/reload/gracefulReload.sh similarity index 100% rename from test/bash/reload/gracefulReload.sh rename to test/e2e/reload/gracefulReload.sh diff --git a/test/bash/reload/gracefulReload2.sh b/test/e2e/reload/gracefulReload2.sh similarity index 100% rename from test/bash/reload/gracefulReload2.sh rename to test/e2e/reload/gracefulReload2.sh diff --git a/test/bash/reload/gracefulReload3.sh b/test/e2e/reload/gracefulReload3.sh similarity index 100% rename from test/bash/reload/gracefulReload3.sh rename to test/e2e/reload/gracefulReload3.sh diff --git a/test/bash/reload/reload.sh b/test/e2e/reload/reload.sh similarity index 100% rename from test/bash/reload/reload.sh rename to test/e2e/reload/reload.sh From 938027117cdb2f300ee772ab27f008cbe22a4b19 Mon Sep 17 00:00:00 2001 From: Unitech Date: Mon, 26 Feb 2018 20:46:11 +0100 Subject: [PATCH 013/140] refactor e2e one line parallel --- test/Dockerfile | 2 ++ test/docker_parallel_test.sh | 17 +---------------- 2 files changed, 3 insertions(+), 16 deletions(-) diff --git a/test/Dockerfile b/test/Dockerfile index 4979fe06..ee1a9ecb 100644 --- a/test/Dockerfile +++ b/test/Dockerfile @@ -5,6 +5,8 @@ RUN mkdir -p /var/pm2 WORKDIR /var/pm2 ENV NODE_ENV test +ENV PM2_DISCRETE_MODE true + RUN apk update && apk add bash git curl python3 php5 && rm -rf /var/cache/apk/* RUN ln -s /usr/bin/php5 /usr/bin/php RUN npm install -g mocha@3.5 diff --git a/test/docker_parallel_test.sh b/test/docker_parallel_test.sh index 1b9ffe35..da37de23 100644 --- a/test/docker_parallel_test.sh +++ b/test/docker_parallel_test.sh @@ -5,19 +5,4 @@ docker build -t pm2-test -f test/Dockerfile . JOBS=20 OPTS="--jobs $JOBS --joblog joblog-X docker run -v `pwd`:/var/pm2 pm2-test" -# process-file ok -ls test/e2e/process-file/* | parallel $OPTS bash -# cli ok -ls test/e2e/cli/* | parallel $OPTS bash -# logs ok -ls test/e2e/logs/* | parallel $OPTS bash -# reload ok -ls test/e2e/reload/* | parallel $OPTS bash -# internals ok -ls test/e2e/internal/* | parallel $OPTS bash -# modules ok -ls test/e2e/modules/* | parallel $OPTS bash -# binaries ok -ls test/e2e/binaries/* | parallel $OPTS bash - -# misc +ls test/e2e/binaries/* test/e2e/modules/* test/e2e/internal/* test/e2e/reload/* test/e2e/process-file/* test/e2e/cli/* test/e2e/logs/* | parallel $OPTS bash From c3ccc651d09ed7291090f516637b75bda99ff71c Mon Sep 17 00:00:00 2001 From: Unitech Date: Tue, 27 Feb 2018 01:10:51 +0100 Subject: [PATCH 014/140] refactor: name tests well --- test/docker_parallel_test.sh | 4 +- test/e2e.sh | 148 +++++++++++++++++++ test/e2e/{misc => cli}/dump.sh | 0 test/e2e/{reload => cli}/gracefulReload.sh | 0 test/e2e/{reload => cli}/gracefulReload2.sh | 0 test/e2e/{reload => cli}/gracefulReload3.sh | 0 test/e2e/{reload => cli}/reload.sh | 0 test/pm2_behavior_tests.sh | 150 -------------------- test/{pm2_programmatic_tests.sh => unit.sh} | 0 9 files changed, 151 insertions(+), 151 deletions(-) create mode 100644 test/e2e.sh rename test/e2e/{misc => cli}/dump.sh (100%) rename test/e2e/{reload => cli}/gracefulReload.sh (100%) rename test/e2e/{reload => cli}/gracefulReload2.sh (100%) rename test/e2e/{reload => cli}/gracefulReload3.sh (100%) rename test/e2e/{reload => cli}/reload.sh (100%) delete mode 100644 test/pm2_behavior_tests.sh rename test/{pm2_programmatic_tests.sh => unit.sh} (100%) diff --git a/test/docker_parallel_test.sh b/test/docker_parallel_test.sh index da37de23..e4cceb53 100644 --- a/test/docker_parallel_test.sh +++ b/test/docker_parallel_test.sh @@ -5,4 +5,6 @@ docker build -t pm2-test -f test/Dockerfile . JOBS=20 OPTS="--jobs $JOBS --joblog joblog-X docker run -v `pwd`:/var/pm2 pm2-test" -ls test/e2e/binaries/* test/e2e/modules/* test/e2e/internal/* test/e2e/reload/* test/e2e/process-file/* test/e2e/cli/* test/e2e/logs/* | parallel $OPTS bash +ls test/e2e/cli/* | parallel $OPTS bash + +#ls test/e2e/binaries/* test/e2e/modules/* test/e2e/internal/* test/e2e/process-file/* test/e2e/cli/* test/e2e/logs/* | parallel $OPTS bash diff --git a/test/e2e.sh b/test/e2e.sh new file mode 100644 index 00000000..07cfe4ac --- /dev/null +++ b/test/e2e.sh @@ -0,0 +1,148 @@ +#!/usr/bin/env bash + +SRC=$(cd $(dirname "$0"); pwd) +source "${SRC}/e2e/include.sh" + +# Abort script at first error +set -e +set -o verbose + +# MODULES +bash ./test/e2e/modules/get-set.sh +spec "Configuration system working" +bash ./test/e2e/modules/module.sh +spec "module system" +bash ./test/e2e/modules/module-safeguard.sh +spec "module safeguard system (--safe)" + +# CLI +bash ./test/e2e/cli/gracefulReload.sh +spec "gracefulReload system 1" +bash ./test/e2e/cli/gracefulReload2.sh +spec "gracefulReload system 2" +bash ./test/e2e/cli/gracefulReload3.sh +spec "gracefulReload system 3" +bash ./test/e2e/cli/reload.sh +spec "Reload" +bash ./test/e2e/cli/operate-regex.sh +spec "Operate process that match regex" +bash ./test/e2e/cli/interpreter.sh +spec "Javascript transpilers tests" +bash ./test/e2e/cli/app-configuration.sh +spec "App configuration" +bash ./test/e2e/cli/binary.sh +spec "binary test" +bash ./test/e2e/cli/startOrX.sh +spec "startOrX commands" +bash ./test/e2e/cli/reset.sh +spec "Reset meta" +bash ./test/e2e/cli/env-refresh.sh +spec "Environment refresh on restart" +bash ./test/e2e/cli/extra-lang.sh +spec "Various programming languages checks (Python, PHP)" +bash ./test/e2e/cli/multiparam.sh +spec "Multiparam process management" +bash ./test/e2e/cli/smart-start.sh +spec "smart start test" +bash ./test/e2e/cli/args.sh +spec "check arguments passing" +bash ./test/e2e/cli/attach.sh +spec "pm2 attach method" +bash ./test/e2e/cli/serve.sh +spec "pm2 serve CLI method" +bash ./test/e2e/cli/monit.sh +spec "km selective monitoring " +bash ./test/e2e/cli/cli-actions-1.sh +spec "CLI basic test" +bash ./test/e2e/cli/cli-actions-2.sh +spec "Second hard cli tests" +bash ./test/e2e/cli/dump.sh +spec "dump test" +bash ./test/e2e/cli/resurrect.sh +spec "resurrect test" +bash ./test/e2e/cli/mjs.sh +spec "Test import syntax" +bash ./test/e2e/cli/watch.sh +spec "watch system tests" +bash ./test/e2e/cli/right-exit-code.sh +spec "Verification exit code" +bash ./test/e2e/cli/harmony.sh +spec "Harmony test" +bash ./test/e2e/cli/fork.sh +spec "Fork system working" + +# PROCESS FILES +bash ./test/e2e/process-file/json-file.sh +spec "JSON file test" +bash ./test/e2e/process-file/yaml-configuration.sh +spec "YAML configuration support" +bash ./test/e2e/process-file/piped-config.sh +spec "Piped JSON file test" +bash ./test/e2e/process-file/json-reload.sh +spec "JSON reload test" +bash ./test/e2e/process-file/homogen-json-action.sh +spec "Homogen json actions" +bash ./test/e2e/process-file/app-config-update.sh +spec "CLI/JSON argument reload" +bash ./test/e2e/process-file/js-configuration.sh +spec "js configuration support" + +# BINARIES +bash ./test/e2e/binaries/pm2-dev.sh +spec "pm2-dev" +bash ./test/e2e/binaries/pm2-runtime.sh +spec "pm2-runtime" + +# INTERNALS +bash ./test/e2e/internals/wait-ready-event.sh +spec "Wait for application ready event" +bash ./test/e2e/internals/daemon-paths-override.sh +spec "Override daemon configuration paths" +bash ./test/e2e/internals/source_map.sh +spec "Source map resolution on exception" +bash ./test/e2e/internals/wrapped-fork.sh +spec "wrapped fork" +bash ./test/e2e/internals/infinite-loop.sh +spec "Infinite loop stop" +bash ./test/e2e/internals/internals/options-via-env.sh +spec "set option via environment" +bash ./test/e2e/internals/promise.sh +spec "Promise warning message tests" +bash ./test/e2e/internals/increment-var.sh +spec "Increment env variables" +bash ./test/e2e/internals/start-consistency.sh +spec "Consistency between a JSON an CLI start" + +# MISC +bash ./test/misc/inside-pm2.sh +spec "Starting a process inside a PM2 process" +bash ./test/misc/vizion.sh +spec "vizion features (versioning control)" +bash ./test/misc/misc.sh +spec "MISC features" +bash ./test/misc/versioning-cmd.sh +spec "versioning system tests" +bash ./test/misc/instance-number.sh +spec "Negative instance number spawn one worker" +bash ./test/misc/startup.sh +spec "upstart startup test" +bash ./test/misc/nvm-node-version.sh +spec "NVM node version setting" +bash ./test/misc/cron-system.sh +spec "Cron system tests" + +# LOGS +bash ./test/e2e/logs/log-timestamp.sh +spec "timestamp prefix of pm2.log" +bash ./test/e2e/logs/log-custom.sh +spec "Custom log timestamp" +bash ./test/e2e/logs/log-reload.sh +spec "Log reload" +bash ./test/e2e/logs/log-entire.sh +spec "merge stdout && stderr" +bash ./test/e2e/logs/log-null.sh +spec "Logging path set to null" +bash ./test/e2e/logs/log-json.sh +spec "Logging directly to file in json" + +$pm2 kill diff --git a/test/e2e/misc/dump.sh b/test/e2e/cli/dump.sh similarity index 100% rename from test/e2e/misc/dump.sh rename to test/e2e/cli/dump.sh diff --git a/test/e2e/reload/gracefulReload.sh b/test/e2e/cli/gracefulReload.sh similarity index 100% rename from test/e2e/reload/gracefulReload.sh rename to test/e2e/cli/gracefulReload.sh diff --git a/test/e2e/reload/gracefulReload2.sh b/test/e2e/cli/gracefulReload2.sh similarity index 100% rename from test/e2e/reload/gracefulReload2.sh rename to test/e2e/cli/gracefulReload2.sh diff --git a/test/e2e/reload/gracefulReload3.sh b/test/e2e/cli/gracefulReload3.sh similarity index 100% rename from test/e2e/reload/gracefulReload3.sh rename to test/e2e/cli/gracefulReload3.sh diff --git a/test/e2e/reload/reload.sh b/test/e2e/cli/reload.sh similarity index 100% rename from test/e2e/reload/reload.sh rename to test/e2e/cli/reload.sh diff --git a/test/pm2_behavior_tests.sh b/test/pm2_behavior_tests.sh deleted file mode 100644 index 6b1fa630..00000000 --- a/test/pm2_behavior_tests.sh +++ /dev/null @@ -1,150 +0,0 @@ -#!/usr/bin/env bash - -SRC=$(cd $(dirname "$0"); pwd) -source "${SRC}/bash/include.sh" - -# Abort script at first error -set -e -# Display all commands executed -set -o verbose - -# if [ $TRAVIS ] -# then -# export DEBUG="*" -# fi - -bash ./test/bash/cli-actions-1.sh -spec "CLI basic test" -bash ./test/bash/cli-actions-2.sh -spec "Second hard cli tests" - -# Power feature -bash ./test/bash/pm2-dev.sh -spec "pm2-dev" -bash ./test/bash/pm2-runtime.sh -spec "pm2-runtime" -bash ./test/bash/options-via-env.sh -spec "set option via environment" -bash ./test/bash/startup.sh -spec "upstart startup test" -bash ./test/bash/dump.sh -spec "dump test" -bash ./test/bash/resurrect.sh -spec "resurrect test" -# bash ./test/bash/docker.sh -# spec "Docker tests" -bash ./test/bash/nvm-node-version.sh -spec "NVM node version setting" -bash ./test/bash/mjs.sh -spec "Test import syntax" - -bash ./test/bash/cron-system.sh -spec "Cron system tests" -bash ./test/bash/promise.sh -spec "Promise warning message tests" - -# bash ./test/bash/log-timestamp.sh -# spec "timestamp prefix of pm2.log" -bash ./test/bash/watch.sh -spec "watch system tests" -bash ./test/bash/versioning-cmd.sh -spec "versioning system tests" -bash ./test/bash/args.sh -spec "check arguments passing" -bash ./test/bash/smart-start.sh -spec "smart start test" -bash ./test/bash/multiparam.sh -spec "Multiparam process management" -bash ./test/bash/json-file.sh -spec "JSON file test" -bash ./test/bash/yaml-configuration.sh -spec "YAML configuration support" -bash ./test/bash/piped-config.sh -spec "Piped JSON file test" -bash ./test/bash/extra-lang.sh -spec "Various programming languages checks (Python, PHP)" -bash ./test/bash/json-reload.sh -spec "JSON reload test" -bash ./test/bash/homogen-json-action.sh -spec "Homogen json actions" -bash ./test/bash/app-config-update.sh -spec "CLI/JSON argument reload" -bash ./test/bash/start-consistency.sh -spec "Consistency between a JSON an CLI start" -bash ./test/bash/harmony.sh -spec "Harmony test" -bash ./test/bash/log-custom.sh -spec "Custom log timestamp" -bash ./test/bash/reload.sh -spec "Reload" -bash ./test/bash/right-exit-code.sh -spec "Verification exit code" -bash ./test/bash/log-reload.sh -spec "Log reload" -bash ./test/bash/gracefulReload.sh -spec "gracefulReload system 1" -bash ./test/bash/gracefulReload2.sh -spec "gracefulReload system 2" -bash ./test/bash/gracefulReload3.sh -spec "gracefulReload system 3" -bash ./test/bash/misc.sh -spec "MISC features" -bash ./test/bash/fork.sh -spec "Fork system working" -bash ./test/bash/get-set.sh -spec "Configuration system working" -bash ./test/bash/infinite-loop.sh -spec "Infinite loop stop" -bash ./test/bash/env-refresh.sh -spec "Environment refresh on restart" -bash ./test/bash/reset.sh -spec "Reset meta" -bash ./test/bash/startOrX.sh -spec "startOrX commands" -bash ./test/bash/binary.sh -spec "binary test" -bash ./test/bash/log-entire.sh -spec "merge stdout && stderr" -bash ./test/bash/module.sh -spec "module system" -bash ./test/bash/module-safeguard.sh -spec "module safeguard system (--safe)" -bash ./test/bash/vizion.sh -spec "vizion features (versioning control)" -bash ./test/bash/wrapped-fork.sh -spec "wrapped fork" -bash ./test/bash/app-configuration.sh -spec "App configuration" -bash ./test/bash/interpreter.sh -spec "Javascript transpilers tests" -bash ./test/bash/source_map.sh -spec "Source map resolution on exception" -bash ./test/bash/inside-pm2.sh -spec "Starting a process inside a PM2 process" -bash ./test/bash/js-configuration.sh -spec "js configuration support" -bash ./test/bash/wait-ready-event.sh -spec "Wait for application ready event" -bash ./test/bash/serve.sh -spec "pm2 serve CLI method" -bash ./test/bash/monit.sh -spec "km selective monitoring " -bash ./test/bash/log-null.sh -spec "Logging path set to null" -bash ./test/bash/log-json.sh -spec "Logging directly to file in json" -bash ./test/bash/operate-regex.sh -spec "Operate process that match regex" -bash ./test/bash/daemon-paths-override.sh -spec "Override daemon configuration paths" -bash ./test/bash/increment-var.sh -spec "Increment env variables" -bash ./test/bash/instance-number.sh -spec "Negative instance number spawn one worker" -bash ./test/bash/attach.sh -spec "pm2 attach method" - -# Issues related -bash ./test/bash/issues/2337.sh - -$pm2 kill diff --git a/test/pm2_programmatic_tests.sh b/test/unit.sh similarity index 100% rename from test/pm2_programmatic_tests.sh rename to test/unit.sh From e3831f95c8d71f98e8840da37f7e883727eccd59 Mon Sep 17 00:00:00 2001 From: vince Date: Tue, 27 Feb 2018 10:52:12 +0100 Subject: [PATCH 015/140] refactor: transform API into class --- lib/API.js | 157 +++++++++++++++++++++++++++-------------------------- 1 file changed, 81 insertions(+), 76 deletions(-) diff --git a/lib/API.js b/lib/API.js index 59bc227f..8e7e0086 100644 --- a/lib/API.js +++ b/lib/API.js @@ -45,85 +45,88 @@ var IMMUTABLE_MSG = chalk.bold.blue('Use --update-env to update environment vari * @param {String} [opts.secret_key=null] keymetrics bucket secret key * @param {String} [opts.machine_name=null] keymetrics instance name */ -var API = module.exports = function(opts) { - if (!opts) opts = {}; - var that = this; +class API { - this.daemon_mode = typeof(opts.daemon_mode) == 'undefined' ? true : opts.daemon_mode; - this.pm2_home = conf.PM2_ROOT_PATH; - this.public_key = process.env.KEYMETRICS_SECRET || opts.public_key || null; - this.secret_key = process.env.KEYMETRICS_PUBLIC || opts.secret_key || null; - this.machine_name = process.env.INSTANCE_NAME || opts.machine_name || null + constructor (opts) { + if (!opts) opts = {}; + var that = this; - /** - * CWD resolution - */ - this.cwd = process.cwd(); - if (opts.cwd) { - this.cwd = path.resolve(opts.cwd); + this.daemon_mode = typeof(opts.daemon_mode) == 'undefined' ? true : opts.daemon_mode; + this.pm2_home = conf.PM2_ROOT_PATH; + this.public_key = process.env.KEYMETRICS_SECRET || opts.public_key || null; + this.secret_key = process.env.KEYMETRICS_PUBLIC || opts.secret_key || null; + this.machine_name = process.env.INSTANCE_NAME || opts.machine_name || null + + /** + * CWD resolution + */ + this.cwd = process.cwd(); + if (opts.cwd) { + this.cwd = path.resolve(opts.cwd); + } + + /** + * PM2 HOME resolution + */ + if (opts.pm2_home && opts.independent == true) + throw new Error('You cannot set a pm2_home and independent instance in same time'); + + if (opts.pm2_home) { + // Override default conf file + this.pm2_home = opts.pm2_home; + conf = util._extend(conf, path_structure(this.pm2_home)); + } + else if (opts.independent == true && conf.IS_WINDOWS === false) { + // Create an unique pm2 instance + var crypto = require('crypto'); + var random_file = crypto.randomBytes(8).toString('hex'); + this.pm2_home = path.join('/tmp', random_file); + + // If we dont explicitly tell to have a daemon + // It will go as in proc + if (typeof(opts.daemon_mode) == 'undefined') + this.daemon_mode = false; + conf = util._extend(conf, path_structure(this.pm2_home)); + } + + this._conf = conf; + + if (conf.IS_WINDOWS) { + // Weird fix, may need to be dropped + // @todo windows connoisseur double check + if (process.stdout._handle && process.stdout._handle.setBlocking) + process.stdout._handle.setBlocking(true); + } + + this.Client = new Client({ + pm2_home: that.pm2_home, + conf: this._conf, + secret_key: this.secret_key, + public_key: this.public_key, + daemon_mode: this.daemon_mode, + machine_name: this.machine_name + }); + + this.gl_interact_infos = null; + this.gl_is_km_linked = false; + + try { + var pid = fs.readFileSync(conf.INTERACTOR_PID_PATH); + pid = parseInt(pid.toString().trim()); + process.kill(pid, 0); + that.gl_is_km_linked = true; + } catch (e) { + that.gl_is_km_linked = false; + } + + // For testing purposes + if (this.secret_key && process.env.NODE_ENV == 'local_test') + that.gl_is_km_linked = true; + + KMDaemon.getInteractInfo(this._conf, function (i_err, interact) { + that.gl_interact_infos = interact; + }); } - - /** - * PM2 HOME resolution - */ - if (opts.pm2_home && opts.independent == true) - throw new Error('You cannot set a pm2_home and independent instance in same time'); - - if (opts.pm2_home) { - // Override default conf file - this.pm2_home = opts.pm2_home; - conf = util._extend(conf, path_structure(this.pm2_home)); - } - else if (opts.independent == true && conf.IS_WINDOWS === false) { - // Create an unique pm2 instance - var crypto = require('crypto'); - var random_file = crypto.randomBytes(8).toString('hex'); - this.pm2_home = path.join('/tmp', random_file); - - // If we dont explicitly tell to have a daemon - // It will go as in proc - if (typeof(opts.daemon_mode) == 'undefined') - this.daemon_mode = false; - conf = util._extend(conf, path_structure(this.pm2_home)); - } - - this._conf = conf; - - if (conf.IS_WINDOWS) { - // Weird fix, may need to be dropped - // @todo windows connoisseur double check - if (process.stdout._handle && process.stdout._handle.setBlocking) - process.stdout._handle.setBlocking(true); - } - - this.Client = new Client({ - pm2_home : that.pm2_home, - conf : this._conf, - secret_key : this.secret_key, - public_key : this.public_key, - daemon_mode : this.daemon_mode, - machine_name : this.machine_name - }); - - this.gl_interact_infos = null; - this.gl_is_km_linked = false; - - try { - var pid = fs.readFileSync(conf.INTERACTOR_PID_PATH); - pid = parseInt(pid.toString().trim()); - process.kill(pid, 0); - that.gl_is_km_linked = true; - } catch(e) { - that.gl_is_km_linked = false; - } - - // For testing purposes - if (this.secret_key && process.env.NODE_ENV == 'local_test') - that.gl_is_km_linked = true; - - KMDaemon.getInteractInfo(this._conf, function(i_err, interact) { - that.gl_interact_infos = interact; - }); }; @@ -1685,3 +1688,5 @@ API.prototype.deepUpdate = function(cb) { cb ? cb(null, {success:true}) : that.exitCli(conf.SUCCESS_EXIT); }); }; + +module.exports = API; From 9552bd61b72692beb620a91765ad440cdf6abefe Mon Sep 17 00:00:00 2001 From: vince Date: Tue, 27 Feb 2018 11:25:32 +0100 Subject: [PATCH 016/140] refactor: remove prototype from API and create method --- lib/API.js | 3090 ++++++++++++++++++++++++++-------------------------- 1 file changed, 1547 insertions(+), 1543 deletions(-) diff --git a/lib/API.js b/lib/API.js index 8e7e0086..c42cf837 100644 --- a/lib/API.js +++ b/lib/API.js @@ -126,9 +126,1556 @@ class API { KMDaemon.getInteractInfo(this._conf, function (i_err, interact) { that.gl_interact_infos = interact; }); + + this.gl_retry = 0; + } + + /** + * Connect to PM2 + * Calling this command is now optional + * + * @param {Function} cb callback once pm2 is ready for commands + */ + connect (noDaemon, cb) { + var that = this; + this.start_timer = new Date(); + + if (typeof(cb) == 'undefined') { + cb = noDaemon; + noDaemon = false; + } else if (noDaemon === true) { + // Backward compatibility with PM2 1.x + this.Client.daemon_mode = false; + this.daemon_mode = false; + } + + this.Client.start(function(err, meta) { + if (err) + return cb(err); + + if (meta.new_pm2_instance == false && that.daemon_mode === true) + return cb(err, meta); + + // If new pm2 instance has been popped + // Lauch all modules + Modularizer.launchAll(that, function(err_mod) { + return cb(err, meta); + }); + }); + } + + /** + * Usefull when custom PM2 created with independent flag set to true + * This will cleanup the newly created instance + * by removing folder, killing PM2 and so on + * + * @param {Function} cb callback once cleanup is successfull + */ + destroy (cb) { + var exec = require('shelljs').exec; + var that = this; + + debug('Killing and deleting current deamon'); + + this.killDaemon(function() { + var cmd = 'rm -rf ' + that.pm2_home; + var test_path = path.join(that.pm2_home, 'module_conf.json'); + var test_path_2 = path.join(that.pm2_home, 'pm2.pid'); + + if (that.pm2_home.indexOf('.pm2') > -1) + return cb(new Error('Destroy is not a allowed method on .pm2')); + + if (fs.accessSync) { + fs.access(test_path, fs.R_OK, function(err) { + if (err) return cb(err); + debug('Deleting temporary folder %s', that.pm2_home); + exec(cmd, cb); + }); + return false; + } + + // Support for Node 0.10 + fs.exists(test_path, function(exist) { + if (exist) { + debug('Deleting temporary folder %s', that.pm2_home); + exec(cmd, cb); + } + return cb(null); + }); + }); + } + + /** + * Disconnect from PM2 instance + * This will allow your software to exit by itself + * + * @param {Function} [cb] optional callback once connection closed + */ + disconnect (cb) { + var that = this; + + if (!cb) cb = function() {}; + + this.Client.close(function(err, data) { + debug('The session lasted %ds', (new Date() - that.start_timer) / 1000); + return cb(err, data); + }); + }; + + /** + * Launch modules + * + * @param {Function} cb callback once pm2 has launched modules + */ + launchModules (cb) { + Modularizer.launchAll(this, cb); + } + + /** + * Enable bus allowing to retrieve various process event + * like logs, restarts, reloads + * + * @param {Function} cb callback called with 1st param err and 2nb param the bus + */ + launchBus (cb) { + this.Client.launchBus(cb); + } + + /** + * Exit methods for API + * @param {Integer} code exit code for terminal + */ + exitCli (code) { + var that = this; + + // Do nothing if PM2 called programmatically (also in speedlist) + if (conf.PM2_PROGRAMMATIC && process.env.PM2_USAGE != 'CLI') return false; + + KMDaemon.disconnectRPC(function() { + that.Client.close(function() { + code = code || 0; + // Safe exits process after all streams are drained. + // file descriptor flag. + var fds = 0; + // exits process when stdout (1) and sdterr(2) are both drained. + function tryToExit() { + if ((fds & 1) && (fds & 2)) { + debug('This command took %ds to execute', (new Date() - that.start_timer) / 1000); + process.exit(code); + } + } + + [process.stdout, process.stderr].forEach(function(std) { + var fd = std.fd; + if (!std.bufferSize) { + // bufferSize equals 0 means current stream is drained. + fds = fds | fd; + } else { + // Appends nothing to the std queue, but will trigger `tryToExit` event on `drain`. + std.write && std.write('', function() { + fds = fds | fd; + tryToExit(); + }); + } + // Does not write anything more. + delete std.write; + }); + tryToExit(); + }); + }); + } + +//////////////////////////// +// Application management // +//////////////////////////// + + /** + * Start a file or json with configuration + * @param {Object||String} cmd script to start or json + * @param {Function} cb called when application has been started + */ + start (cmd, opts, cb) { + if (typeof(opts) == "function") { + cb = opts; + opts = {}; + } + if (!opts) + opts = {}; + + var that = this; + + if (util.isArray(opts.watch) && opts.watch.length === 0) + opts.watch = (opts.rawArgs ? !!~opts.rawArgs.indexOf('--watch') : !!~process.argv.indexOf('--watch')) || false; + + if (Common.isConfigFile(cmd) || (typeof(cmd) === 'object')) + that._startJson(cmd, opts, 'restartProcessId', cb); + else { + that._startScript(cmd, opts, cb); + } + } + + /** + * Reset process counters + * + * @method resetMetaProcess + */ + reset (process_name, cb) { + var that = this; + + function processIds(ids, cb) { + async.eachLimit(ids, conf.CONCURRENT_ACTIONS, function(id, next) { + that.Client.executeRemote('resetMetaProcessId', id, function(err, res) { + if (err) console.error(err); + Common.printOut(conf.PREFIX_MSG + 'Resetting meta for process id %d', id); + return next(); + }); + }, function(err) { + if (err) return cb(Common.retErr(err)); + return cb ? cb(null, {success:true}) : that.speedList(); + }); + } + + if (process_name == 'all') { + that.Client.getAllProcessId(function(err, ids) { + if (err) { + Common.printError(err); + return cb ? cb(Common.retErr(err)) : that.exitCli(conf.ERROR_EXIT); + } + return processIds(ids, cb); + }); + } + else if (isNaN(process_name)) { + that.Client.getProcessIdByName(process_name, function(err, ids) { + if (err) { + Common.printError(err); + return cb ? cb(Common.retErr(err)) : that.exitCli(conf.ERROR_EXIT); + } + if (ids.length === 0) { + Common.printError('Unknown process name'); + return cb ? cb(new Error('Unknown process name')) : that.exitCli(conf.ERROR_EXIT); + } + return processIds(ids, cb); + }); + } else { + processIds([process_name], cb); + } + } + + /** + * Update daemonized PM2 Daemon + * + * @param {Function} cb callback when pm2 has been upgraded + */ + update (cb) { + var that = this; + + Common.printOut('Be sure to have the latest version by doing `npm install pm2@latest -g` before doing this procedure.'); + + // Dump PM2 processes + that.Client.executeRemote('notifyKillPM2', {}, function() {}); + + that.getVersion(function(err, new_version) { + // If not linked to keymetrics, and update pm2 to latest, display motd.update + if (!that.gl_is_km_linked && !err && (pkg.version != new_version)) { + var dt = fs.readFileSync(path.join(__dirname, that._conf.KEYMETRICS_UPDATE)); + console.log(dt.toString()); + } + + that.dump(function(err) { + debug('Dumping successfull', err); + that.killDaemon(function() { + debug('------------------ Everything killed', arguments); + that.Client.launchDaemon({interactor:false}, function(err, child) { + that.Client.launchRPC(function() { + that.resurrect(function() { + Common.printOut(chalk.blue.bold('>>>>>>>>>> PM2 updated')); + Modularizer.launchAll(that, function() { + KMDaemon.launchAndInteract(that._conf, null, function(err, data, interactor_proc) { + // Interactor error can be skipped here + return cb ? cb(null, {success:true}) : that.speedList(); + }); + }); + }); + }); + }); + }); + }); + }); + + return false; + } + + /** + * Graceful Reload an application + * + * @param {String} process_name Application Name or All + * @param {Object} opts Options + * @param {Function} cb Callback + */ + gracefulReload (process_name, opts, cb) { + var that = this; + + if (typeof(opts) == "function") { + cb = opts; + opts = {}; + } + + //Common.printOut(conf.PREFIX_MSG_WARNING + chalk.bold.yellow('Warning gracefulReload will be soon deprecated')); + //Common.printOut(conf.PREFIX_MSG_WARNING + chalk.bold.yellow('Use http://pm2.keymetrics.io/docs/usage/signals-clean-restart/ instead')); + + if (Common.isConfigFile(process_name)) + that._startJson(process_name, commander, 'softReloadProcessId'); + else { + if (opts && !opts.updateEnv) + Common.printOut(IMMUTABLE_MSG); + that._operate('softReloadProcessId', process_name, opts, cb); + } + } + + /** + * Reload an application + * + * @param {String} process_name Application Name or All + * @param {Object} opts Options + * @param {Function} cb Callback + */ + reload (process_name, opts, cb) { + var that = this; + + if (typeof(opts) == "function") { + cb = opts; + opts = {}; + } + + var delay = Common.lockReload(); + + if (delay > 0 && opts.force != true) { + Common.printError(conf.PREFIX_MSG_ERR + 'Reload already in progress, please try again in ' + Math.floor((conf.RELOAD_LOCK_TIMEOUT - delay) / 1000) + ' seconds or use --force'); + return cb ? cb(new Error('Reload in progress')) : that.exitCli(conf.ERROR_EXIT); + } + + if (Common.isConfigFile(process_name)) + that._startJson(process_name, opts, 'reloadProcessId', function(err, apps) { + Common.unlockReload(); + if (err) + return cb ? cb(err) : that.exitCli(conf.ERROR_EXIT); + return cb ? cb(null, apps) : that.exitCli(conf.SUCCESS_EXIT);; + }); + else { + if (opts && !opts.updateEnv) + Common.printOut(IMMUTABLE_MSG); + + that._operate('reloadProcessId', process_name, opts, function(err, apps) { + Common.unlockReload(); + + if (err) + return cb ? cb(err) : that.exitCli(conf.ERROR_EXIT); + return cb ? cb(null, apps) : that.exitCli(conf.SUCCESS_EXIT);; + }); + } + } + + /** + * Restart process + * + * @param {String} cmd Application Name / Process id / JSON application file / 'all' + * @param {Object} opts Extra options to be updated + * @param {Function} cb Callback + */ + restart (cmd, opts, cb) { + if (typeof(opts) == "function") { + cb = opts; + opts = {}; + } + var that = this; + + if (typeof(cmd) === 'number') + cmd = cmd.toString(); + + if (cmd == "-") { + // Restart from PIPED JSON + process.stdin.resume(); + process.stdin.setEncoding('utf8'); + process.stdin.on('data', function (param) { + process.stdin.pause(); + that.actionFromJson('restartProcessId', param, opts, 'pipe', cb); + }); + } + else if (Common.isConfigFile(cmd) || typeof(cmd) === 'object') + that._startJson(cmd, opts, 'restartProcessId', cb); + else { + if (opts && !opts.updateEnv) + Common.printOut(IMMUTABLE_MSG); + that._operate('restartProcessId', cmd, opts, cb); + } + } + + /** + * Delete process + * + * @param {String} process_name Application Name / Process id / Application file / 'all' + * @param {Function} cb Callback + */ + delete (process_name, jsonVia, cb) { + var that = this; + + if (typeof(jsonVia) === "function") { + cb = jsonVia; + jsonVia = null; + } + if (typeof(process_name) === "number") { + process_name = process_name.toString(); + } + + if (jsonVia == 'pipe') + return that.actionFromJson('deleteProcessId', process_name, commander, 'pipe', cb); + if (Common.isConfigFile(process_name)) + return that.actionFromJson('deleteProcessId', process_name, commander, 'file', cb); + else + that._operate('deleteProcessId', process_name, cb); + } + + /** + * Stop process + * + * @param {String} process_name Application Name / Process id / Application file / 'all' + * @param {Function} cb Callback + */ + stop (process_name, cb) { + var that = this; + + if (typeof(process_name) === 'number') + process_name = process_name.toString(); + + if (process_name == "-") { + process.stdin.resume(); + process.stdin.setEncoding('utf8'); + process.stdin.on('data', function (param) { + process.stdin.pause(); + that.actionFromJson('stopProcessId', param, commander, 'pipe', cb); + }); + } + else if (Common.isConfigFile(process_name)) + that.actionFromJson('stopProcessId', process_name, commander, 'file', cb); + else + that._operate('stopProcessId', process_name, cb); + } + + /** + * Get list of all processes managed + * + * @param {Function} cb Callback + */ + list (opts, cb) { + var that = this; + + if (typeof(opts) == 'function') { + cb = opts; + opts = null; + } + + that.Client.executeRemote('getMonitorData', {}, function(err, list) { + if (err) { + Common.printError(err); + return cb ? cb(Common.retErr(err)) : that.exitCli(conf.ERROR_EXIT); + } + + if (opts && opts.rawArgs && opts.rawArgs.indexOf('--watch') > -1) { + var moment = require('moment'); + function show() { + process.stdout.write('\\033[2J'); + process.stdout.write('\\033[0f'); + console.log('Last refresh: ', moment().format('LTS')); + that.Client.executeRemote('getMonitorData', {}, function(err, list) { + UX.dispAsTable(list, null); + }); + } + + show(); + setInterval(show, 900); + return false; + } + + return cb ? cb(null, list) : that.speedList(); + }); + } + + /** + * Kill Daemon + * + * @param {Function} cb Callback + */ + killDaemon (cb) { + var that = this; + + var semver = require('semver'); + Common.printOut(conf.PREFIX_MSG + 'Stopping PM2...'); + + that.Client.executeRemote('notifyKillPM2', {}, function() {}); + + that.killAllModules(function() { + that._operate('deleteProcessId', 'all', function(err, list) { + Common.printOut(conf.PREFIX_MSG + 'All processes have been stopped and deleted'); + process.env.PM2_SILENT = 'false'; + + that.killInteract(function(err, data) { + that.Client.killDaemon(function(err, res) { + if (err) Common.printError(err); + Common.printOut(conf.PREFIX_MSG + 'PM2 stopped'); + return cb ? cb(err, res) : that.exitCli(conf.SUCCESS_EXIT); + }); + }); + }); + }); + } + + ///////////////////// + // Private methods // + ///////////////////// + + /** + * Method to START / RESTART a script + * + * @private + * @param {string} script script name (will be resolved according to location) + */ + _startScript (script, opts, cb) { + if (typeof opts == "function") { + cb = opts; + opts = {}; + } + var that = this; + + var app_conf = Config.transCMDToConf(opts); + var appConf = {}; + + if (!!opts.executeCommand) + app_conf.exec_mode = 'fork'; + else if (opts.instances !== undefined) + app_conf.exec_mode = 'cluster'; + else + app_conf.exec_mode = 'fork'; + + // Options set via environment variables + if (process.env.PM2_DEEP_MONITORING) + app_conf.deep_monitoring = true; + + if (typeof app_conf.name == 'function'){ + delete app_conf.name; + } + + delete app_conf.args; + + var argsIndex; + + if (opts.rawArgs && (argsIndex = opts.rawArgs.indexOf('--')) >= 0) { + app_conf.args = opts.rawArgs.slice(argsIndex + 1); + } + else if (opts.scriptArgs) { + app_conf.args = opts.scriptArgs; + } + + app_conf.script = script; + + if ((appConf = Common.verifyConfs(app_conf)) instanceof Error) + return cb ? cb(Common.retErr(appConf)) : that.exitCli(conf.ERROR_EXIT); + + app_conf = appConf[0]; + + app_conf.username = Common.getCurrentUsername(); + + /** + * If -w option, write configuration to configuration.json file + */ + if (appConf.write) { + var dst_path = path.join(process.env.PWD || process.cwd(), app_conf.name + '-pm2.json'); + Common.printOut(conf.PREFIX_MSG + 'Writing configuration to', chalk.blue(dst_path)); + // pretty JSON + try { + fs.writeFileSync(dst_path, JSON.stringify(app_conf, null, 2)); + } catch (e) { + console.error(e.stack || e); + } + } + + /** + * If start start/restart application + */ + function restartExistingProcessName(cb) { + if (!isNaN(script) || + (typeof script === 'string' && script.indexOf('/') != -1) || + (typeof script === 'string' && path.extname(script) !== '')) + return cb(null); + + if (script !== 'all') { + that.Client.getProcessIdByName(script, function(err, ids) { + if (err && cb) return cb(err); + if (ids.length > 0) { + that._operate('restartProcessId', script, opts, function(err, list) { + if (err) return cb(err); + Common.printOut(conf.PREFIX_MSG + 'Process successfully started'); + return cb(true, list); + }); + } + else return cb(null); + }); + } + else { + that._operate('restartProcessId', 'all', function(err, list) { + if (err) return cb(err); + Common.printOut(conf.PREFIX_MSG + 'Process successfully started'); + return cb(true, list); + }); + } + } + + function restartExistingProcessId(cb) { + if (isNaN(script)) return cb(null); + + that._operate('restartProcessId', script, opts, function(err, list) { + if (err) return cb(err); + Common.printOut(conf.PREFIX_MSG + 'Process successfully started'); + return cb(true, list); + }); + } + + /** + * Restart a process with the same full path + * Or start it + */ + function restartExistingProcessPath(cb) { + that.Client.executeRemote('getMonitorData', {}, function(err, procs) { + if (err) return cb ? cb(new Error(err)) : that.exitCli(conf.ERROR_EXIT); + + var full_path = path.resolve(that.cwd, script); + var managed_script = null; + + procs.forEach(function(proc) { + if (proc.pm2_env.pm_exec_path == full_path && + proc.pm2_env.name == app_conf.name) + managed_script = proc; + }); + + if (managed_script && + (managed_script.pm2_env.status == conf.STOPPED_STATUS || + managed_script.pm2_env.status == conf.STOPPING_STATUS || + managed_script.pm2_env.status == conf.ERRORED_STATUS)) { + // Restart process if stopped + var app_name = managed_script.pm2_env.name; + + that._operate('restartProcessId', app_name, opts, function(err, list) { + if (err) return cb ? cb(new Error(err)) : that.exitCli(conf.ERROR_EXIT); + Common.printOut(conf.PREFIX_MSG + 'Process successfully started'); + return cb(true, list); + }); + return false; + } + else if (managed_script && !opts.force) { + Common.printError(conf.PREFIX_MSG_ERR + 'Script already launched, add -f option to force re-execution'); + return cb(new Error('Script already launched')); + } + + var resolved_paths = null; + + try { + resolved_paths = Common.resolveAppAttributes({ + cwd : that.cwd, + pm2_home : that.pm2_home + }, app_conf); + } catch(e) { + Common.printError(e); + return cb(Common.retErr(e)); + } + + Common.printOut(conf.PREFIX_MSG + 'Starting %s in %s (%d instance' + (resolved_paths.instances > 1 ? 's' : '') + ')', + resolved_paths.pm_exec_path, resolved_paths.exec_mode, resolved_paths.instances); + + if (!resolved_paths.env) resolved_paths.env = {}; + + // Set PM2 HOME in case of child process using PM2 API + resolved_paths.env['PM2_HOME'] = that.pm2_home; + + var additional_env = Modularizer.getAdditionalConf(resolved_paths.name); + util._extend(resolved_paths.env, additional_env); + + // Is KM linked? + resolved_paths.km_link = that.gl_is_km_linked; + + that.Client.executeRemote('prepare', resolved_paths, function(err, data) { + if (err) { + Common.printError(conf.PREFIX_MSG_ERR + 'Error while launching application', err.stack || err); + return cb(Common.retErr(err)); + } + + Common.printOut(conf.PREFIX_MSG + 'Done.'); + return cb(true, data); + }); + return false; + }); + } + + async.series([ + restartExistingProcessName, + restartExistingProcessId, + restartExistingProcessPath + ], function(err, data) { + + if (err instanceof Error) + return cb ? cb(err) : that.exitCli(conf.ERROR_EXIT); + + var ret = {}; + data.forEach(function(_dt) { + if (_dt !== undefined) + ret = _dt; + }); + + return cb ? cb(null, ret) : that.speedList(); + }); + } + + /** + * Method to start/restart/reload processes from a JSON file + * It will start app not started + * Can receive only option to skip applications + * + * @private + */ + _startJson (file, opts, action, pipe, cb) { + var config = {}; + var appConf = {}; + var deployConf = {}; + var apps_info = []; + var that = this; + + if (typeof(cb) === 'undefined' && typeof(pipe) === 'function') { + cb = pipe; + } + + if (typeof(file) === 'object') { + config = file; + } else if (pipe === 'pipe') { + config = Common.parseConfig(file, 'pipe'); + } else { + var data = null; + + var isAbsolute = false + + //node 0.11 compatibility #2815 + if (typeof path.isAbsolute === 'function') { + isAbsolute = path.isAbsolute(file) + } else { + isAbsolute = require('./tools/IsAbsolute.js')(file) + } + + var file_path = isAbsolute ? file : path.join(that.cwd, file); + + debug('Resolved filepath %s', file_path); + + try { + data = fs.readFileSync(file_path); + } catch(e) { + Common.printError(conf.PREFIX_MSG_ERR + 'File ' + file +' not found'); + return cb ? cb(Common.retErr(e)) : that.exitCli(conf.ERROR_EXIT); + } + + try { + config = Common.parseConfig(data, file); + } catch(e) { + Common.printError(conf.PREFIX_MSG_ERR + 'File ' + file + ' malformated'); + console.error(e); + return cb ? cb(Common.retErr(e)) : that.exitCli(conf.ERROR_EXIT); + } + } + + if (config.deploy) + deployConf = config.deploy; + + if (config.apps) + appConf = config.apps; + else if (config.pm2) + appConf = config.pm2; + else + appConf = config; + + if (!Array.isArray(appConf)) + appConf = [appConf]; //convert to array + + if ((appConf = Common.verifyConfs(appConf)) instanceof Error) + return cb ? cb(appConf) : that.exitCli(conf.ERROR_EXIT); + + process.env.PM2_JSON_PROCESSING = true; + + // Get App list + var apps_name = []; + var proc_list = {}; + + // Here we pick only the field we want from the CLI when starting a JSON + appConf.forEach(function(app) { + // --only + if (opts.only && opts.only != app.name) + return false; + // --watch + if (!app.watch && opts.watch && opts.watch === true) + app.watch = true; + // --ignore-watch + if (!app.ignore_watch && opts.ignore_watch) + app.ignore_watch = opts.ignore_watch; + // --instances + if (opts.instances && typeof(opts.instances) === 'number') + app.instances = opts.instances; + // --uid + if (opts.uid) + app.uid = opts.uid; + // --gid + if (opts.gid) + app.gid = opts.gid; + // Specific + if (app.append_env_to_name && opts.env) + app.name += ('-' + opts.env); + app.username = Common.getCurrentUsername(); + apps_name.push(app.name); + }); + + that.Client.executeRemote('getMonitorData', {}, function(err, raw_proc_list) { + if (err) { + Common.printError(err); + return cb ? cb(Common.retErr(err)) : that.exitCli(conf.ERROR_EXIT); + } + + /** + * Uniquify in memory process list + */ + raw_proc_list.forEach(function(proc) { + proc_list[proc.name] = proc; + }); + + /** + * Auto detect application already started + * and act on them depending on action + */ + async.eachLimit(Object.keys(proc_list), conf.CONCURRENT_ACTIONS, function(proc_name, next) { + // Skip app name (--only option) + if (apps_name.indexOf(proc_name) == -1) + return next(); + + if (!(action == 'reloadProcessId' || + action == 'softReloadProcessId' || + action == 'restartProcessId')) + throw new Error('Wrong action called'); + + var apps = appConf.filter(function(app) { + return app.name == proc_name; + }); + + var envs = apps.map(function(app){ + // Binds env_diff to env and returns it. + return Common.mergeEnvironmentVariables(app, opts.env, deployConf); + }); + + // Assigns own enumerable properties of all + // Notice: if people use the same name in different apps, + // duplicated envs will be overrode by the last one + var env = envs.reduce(function(e1, e2){ + return util._extend(e1, e2); + }); + + // When we are processing JSON, allow to keep the new env by default + env.updateEnv = true; + + // Pass `env` option + that._operate(action, proc_name, env, function(err, ret) { + if (err) Common.printError(err); + + // For return + apps_info = apps_info.concat(ret); + + that.Client.notifyGod(action, proc_name); + // And Remove from array to spy + apps_name.splice(apps_name.indexOf(proc_name), 1); + return next(); + }); + + }, function(err) { + if (err) return cb ? cb(Common.retErr(err)) : that.exitCli(conf.ERROR_EXIT); + if (apps_name.length > 0 && action != 'start') + Common.printOut(conf.PREFIX_MSG_WARNING + 'Applications %s not running, starting...', apps_name.join(', ')); + // Start missing apps + return startApps(apps_name, function(err, apps) { + apps_info = apps_info.concat(apps); + return cb ? cb(err, apps_info) : that.speedList(err ? 1 : 0); + }); + }); + return false; + }); + + function startApps(app_name_to_start, cb) { + var apps_to_start = []; + var apps_started = []; + + appConf.forEach(function(app, i) { + if (app_name_to_start.indexOf(app.name) != -1) { + apps_to_start.push(appConf[i]); + } + }); + + async.eachLimit(apps_to_start, conf.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; + + var resolved_paths = null; + + // hardcode script name to use `serve` feature inside a process file + if (app.script === 'serve') { + app.script = path.resolve(__dirname, 'API', 'Serve.js') + } + + try { + resolved_paths = Common.resolveAppAttributes({ + cwd : that.cwd, + pm2_home : that.pm2_home + }, app); + } catch (e) { + return next(); + } + + if (!resolved_paths.env) resolved_paths.env = {}; + + // Set PM2 HOME in case of child process using PM2 API + resolved_paths.env['PM2_HOME'] = that.pm2_home; + + var additional_env = Modularizer.getAdditionalConf(resolved_paths.name); + util._extend(resolved_paths.env, additional_env); + + resolved_paths.env = Common.mergeEnvironmentVariables(resolved_paths, opts.env, deployConf); + + delete resolved_paths.env.current_conf; + + // Is KM linked? + resolved_paths.km_link = that.gl_is_km_linked; + + that.Client.executeRemote('prepare', resolved_paths, function(err, data) { + if (err) { + Common.printError(conf.PREFIX_MSG_ERR + 'Process failed to launch %s', err.message ? err.message : err); + return next(); + } + if (data.length === 0) { + Common.printError(conf.PREFIX_MSG_ERR + 'Process config loading failed', data); + return next(); + } + + Common.printOut(conf.PREFIX_MSG + 'App [%s] launched (%d instances)', data[0].pm2_env.name, data.length); + apps_started = apps_started.concat(data); + next(); + }); + + }, function(err) { + return cb ? cb(err || null, apps_started) : that.speedList(); + }); + return false; + } + } + + /** + * Apply a RPC method on the json file + * @private + * @method actionFromJson + * @param {string} action RPC Method + * @param {object} options + * @param {string|object} file file + * @param {string} jsonVia action type (=only 'pipe' ?) + * @param {Function} + */ + actionFromJson (action, file, opts, jsonVia, cb) { + var appConf = {}; + var ret_processes = []; + var that = this; + + //accept programmatic calls + if (typeof file == 'object') { + cb = typeof jsonVia == 'function' ? jsonVia : cb; + appConf = file; + } + else if (jsonVia == 'file') { + var data = null; + + try { + data = fs.readFileSync(file); + } catch(e) { + Common.printError(conf.PREFIX_MSG_ERR + 'File ' + file +' not found'); + return cb ? cb(Common.retErr(e)) : that.exitCli(conf.ERROR_EXIT); + } + + try { + appConf = Common.parseConfig(data, file); + } catch(e) { + Common.printError(conf.PREFIX_MSG_ERR + 'File ' + file + ' malformated'); + console.error(e); + return cb ? cb(Common.retErr(e)) : that.exitCli(conf.ERROR_EXIT); + } + } else if (jsonVia == 'pipe') { + appConf = Common.parseConfig(file, 'pipe'); + } else { + Common.printError('Bad call to actionFromJson, jsonVia should be one of file, pipe'); + return that.exitCli(conf.ERROR_EXIT); + } + + // Backward compatibility + if (appConf.apps) + appConf = appConf.apps; + + if (!Array.isArray(appConf)) + appConf = [appConf]; + + if ((appConf = Common.verifyConfs(appConf)) instanceof Error) + return cb ? cb(appConf) : that.exitCli(conf.ERROR_EXIT); + + async.eachLimit(appConf, conf.CONCURRENT_ACTIONS, function(proc, next1) { + var name = ''; + var new_env; + + if (!proc.name) + name = path.basename(proc.script); + else + name = proc.name; + + if (opts.only && opts.only != name) + return process.nextTick(next1); + + if (opts && opts.env) + new_env = Common.mergeEnvironmentVariables(proc, opts.env); + else + new_env = Common.mergeEnvironmentVariables(proc); + + that.Client.getProcessIdByName(name, function(err, ids) { + if (err) { + Common.printError(err); + return next1(); + } + if (!ids) return next1(); + + async.eachLimit(ids, conf.CONCURRENT_ACTIONS, function(id, next2) { + var opts = {}; + + //stopProcessId could accept options to? + if (action == 'restartProcessId') { + opts = {id : id, env : new_env}; + } else { + opts = id; + } + + that.Client.executeRemote(action, opts, function(err, res) { + ret_processes.push(res); + if (err) { + Common.printError(err); + return next2(); + } + + if (action == 'restartProcessId') { + that.Client.notifyGod('restart', id); + } else if (action == 'deleteProcessId') { + that.Client.notifyGod('delete', id); + } else if (action == 'stopProcessId') { + that.Client.notifyGod('stop', id); + } + + Common.printOut(conf.PREFIX_MSG + '[%s](%d) \u2713', name, id); + return next2(); + }); + }, function(err) { + return next1(null, ret_processes); + }); + }); + }, function(err) { + if (cb) return cb(null, ret_processes); + else return that.speedList(); + }); + } + + + /** + * Main function to operate with PM2 daemon + * + * @param {String} action_name Name of action (restartProcessId, deleteProcessId, stopProcessId) + * @param {String} process_name can be 'all', a id integer or process name + * @param {Object} envs object with CLI options / environment + */ + _operate (action_name, process_name, envs, cb) { + var that = this; + var update_env = false; + var ret = []; + + // Make sure all options exist + if (!envs) + envs = {}; + + if (typeof(envs) == 'function'){ + cb = envs; + envs = {}; + } + + // Set via env.update (JSON processing) + if (envs.updateEnv === true) + update_env = true; + + var concurrent_actions = envs.parallel || conf.CONCURRENT_ACTIONS; + + if (!process.env.PM2_JSON_PROCESSING || envs.commands) { + envs = that._handleAttributeUpdate(envs); + } + + /** + * Set current updated configuration if not passed + */ + if (!envs.current_conf) { + var _conf = fclone(envs); + envs = { + current_conf : _conf + } + + // Is KM linked? + envs.current_conf.km_link = that.gl_is_km_linked; + } + + /** + * Operate action on specific process id + */ + function processIds(ids, cb) { + Common.printOut(conf.PREFIX_MSG + 'Applying action %s on app [%s](ids: %s)', action_name, process_name, ids); + + if (action_name == 'deleteProcessId') + concurrent_actions = 10; + + async.eachLimit(ids, concurrent_actions, function(id, next) { + var opts; + + // These functions need extra param to be passed + if (action_name == 'restartProcessId' || + action_name == 'reloadProcessId' || + action_name == 'softReloadProcessId') { + var new_env = {}; + + if (update_env === true) { + if (conf.PM2_PROGRAMMATIC == true) + new_env = Common.safeExtend({}, process.env); + else + new_env = util._extend({}, process.env); + + Object.keys(envs).forEach(function(k) { + new_env[k] = envs[k]; + }); + } + else { + new_env = envs; + } + + opts = { + id : id, + env : new_env + }; + } + else { + opts = id; + } + + that.Client.executeRemote(action_name, opts, function(err, res) { + if (err) { + Common.printError(conf.PREFIX_MSG_ERR + 'Process %s not found', id); + return next('Process not found'); + } + + if (action_name == 'restartProcessId') { + that.Client.notifyGod('restart', id); + } else if (action_name == 'deleteProcessId') { + that.Client.notifyGod('delete', id); + } else if (action_name == 'stopProcessId') { + that.Client.notifyGod('stop', id); + } else if (action_name == 'reloadProcessId') { + that.Client.notifyGod('reload', id); + } else if (action_name == 'softReloadProcessId') { + that.Client.notifyGod('graceful reload', id); + } + + if (!Array.isArray(res)) + res = [res]; + + // Filter return + res.forEach(function(proc) { + Common.printOut(conf.PREFIX_MSG + '[%s](%d) \u2713', proc.pm2_env ? proc.pm2_env.name : process_name, id); + + if (!proc.pm2_env) return false; + + ret.push({ + name : proc.pm2_env.name, + pm_id : proc.pm2_env.pm_id, + status : proc.pm2_env.status, + restart_time : proc.pm2_env.restart_time, + pm2_env : { + name : proc.pm2_env.name, + pm_id : proc.pm2_env.pm_id, + status : proc.pm2_env.status, + restart_time : proc.pm2_env.restart_time, + env : proc.pm2_env.env + } + }); + }); + + return next(); + }); + }, function(err) { + if (err) return cb ? cb(Common.retErr(err)) : that.exitCli(conf.ERROR_EXIT); + return cb ? cb(null, ret) : that.speedList(); + }); + } + + if (process_name == 'all') { + that.Client.getAllProcessId(function(err, ids) { + if (err) { + Common.printError(err); + return cb ? cb(Common.retErr(err)) : that.exitCli(conf.ERROR_EXIT); + } + if (!ids || ids.length === 0) { + Common.printError(conf.PREFIX_MSG_WARNING + 'No process found'); + return cb ? cb(new Error('process name not found')) : that.exitCli(conf.ERROR_EXIT); + } + + return processIds(ids, cb); + }); + } + // operate using regex + else if (isNaN(process_name) && process_name[0] === '/' && process_name[process_name.length - 1] === '/') { + var regex = new RegExp(process_name.replace(/\//g, '')); + + that.Client.executeRemote('getMonitorData', {}, function(err, list) { + if (err) { + Common.printError('Error retrieving process list: ' + err); + return cb(err); + } + var found_proc = []; + list.forEach(function(proc) { + if (regex.test(proc.pm2_env.name)) { + found_proc.push(proc.pm_id); + } + }); + + if (found_proc.length === 0) { + Common.printError(conf.PREFIX_MSG_WARNING + 'No process found'); + return cb ? cb(new Error('process name not found')) : that.exitCli(conf.ERROR_EXIT); + } + + return processIds(found_proc, cb); + }); + } + else if (isNaN(process_name)) { + /** + * We can not stop or delete a module but we can restart it + * to refresh configuration variable + */ + var allow_module_restart = action_name == 'restartProcessId' ? true : false; + + that.Client.getProcessIdByName(process_name, allow_module_restart, function(err, ids) { + if (err) { + Common.printError(err); + return cb ? cb(Common.retErr(err)) : that.exitCli(conf.ERROR_EXIT); + } + if (!ids || ids.length === 0) { + Common.printError(conf.PREFIX_MSG_ERR + 'Process %s not found', process_name); + return cb ? cb(new Error('process name not found')) : that.exitCli(conf.ERROR_EXIT); + } + + /** + * Determine if the process to restart is a module + * if yes load configuration variables and merge with the current environment + */ + var additional_env = Modularizer.getAdditionalConf(process_name); + util._extend(envs, additional_env); + + return processIds(ids, cb); + }); + } else { + // Check if application name as number is an app name + that.Client.getProcessIdByName(process_name, function(err, ids) { + if (ids.length > 0) + return processIds(ids, cb); + // Else operate on pm id + return processIds([process_name], cb); + }); + } + } + + /** + * Converts CamelCase Commander.js arguments + * to Underscore + * (nodeArgs -> node_args) + */ + _handleAttributeUpdate (opts) { + var conf = Config.transCMDToConf(opts); + var that = this; + + if (typeof(conf.name) != 'string') + delete conf.name; + + var argsIndex = 0; + if (opts.rawArgs && (argsIndex = opts.rawArgs.indexOf('--')) >= 0) { + conf.args = opts.rawArgs.slice(argsIndex + 1); + } + + var appConf = Common.verifyConfs(conf)[0]; + + if (appConf instanceof Error) { + Common.printError('Error while transforming CamelCase args to underscore'); + return appConf; + } + + if (argsIndex == -1) + delete appConf.args; + if (appConf.name == 'undefined') + delete appConf.name; + + delete appConf.exec_mode; + + if (util.isArray(appConf.watch) && appConf.watch.length === 0) { + if (!~opts.rawArgs.indexOf('--watch')) + delete appConf.watch + } + + // Options set via environment variables + if (process.env.PM2_DEEP_MONITORING) + appConf.deep_monitoring = true; + + // Force deletion of defaults values set by commander + // to avoid overriding specified configuration by user + if (appConf.treekill === true) + delete appConf.treekill; + if (appConf.pmx === true) + delete appConf.pmx; + if (appConf.vizion === true) + delete appConf.vizion; + if (appConf.automation === true) + delete appConf.automation; + if (appConf.autorestart === true) + delete appConf.autorestart; + + return appConf; + } + + getProcessIdByName (name, cb) { + var that = this; + + this.Client.getProcessIdByName(name, function(err, id) { + if (err) { + Common.printError(err); + return cb ? cb(Common.retErr(err)) : that.exitCli(conf.ERROR_EXIT); + } + console.log(id); + return cb ? cb(null, id) : that.exitCli(conf.SUCCESS_EXIT); + }); + } + + /** + * Description + * @method jlist + * @param {} debug + * @return + */ + jlist (debug) { + var that = this; + + that.Client.executeRemote('getMonitorData', {}, function(err, list) { + if (err) { + Common.printError(err); + that.exitCli(conf.ERROR_EXIT); + } + + if (debug) { + process.stdout.write(util.inspect(list, false, null, false)); + } + else { + process.stdout.write(JSON.stringify(list)); + } + + that.exitCli(conf.SUCCESS_EXIT); + + }); + } + + /** + * Description + * @method speedList + * @return + */ + speedList (code) { + var that = this; + + // Do nothing if PM2 called programmatically and not called from CLI (also in exitCli) + if (conf.PM2_PROGRAMMATIC && process.env.PM2_USAGE != 'CLI') return false; + + that.Client.executeRemote('getMonitorData', {}, function(err, list) { + if (err) { + if (gl_retry == 0) { + gl_retry += 1; + return setTimeout(that.speedList.bind(that), 1400); + } + console.error('Error retrieving process list: %s.\nA process seems to be on infinite loop, retry in 5 seconds',err); + return that.exitCli(conf.ERROR_EXIT); + } + if (process.stdout.isTTY === false) { + UX.miniDisplay(list); + } + else if (commander.miniList && !commander.silent) + UX.miniDisplay(list); + else if (!commander.silent) { + if (that.gl_interact_infos) { + Common.printOut(chalk.green.bold('●') + ' Agent Online | Dashboard Access: ' + chalk.bold('https://app.keymetrics.io/#/r/%s') + ' | Server name: %s', that.gl_interact_infos.public_key, that.gl_interact_infos.machine_name); + } + UX.dispAsTable(list, commander); + Common.printOut(chalk.white.italic(' Use `pm2 show ` to get more details about an app')); + } + + if (that.Client.daemon_mode == false) { + Common.printOut('[--no-daemon] Continue to stream logs'); + Common.printOut('[--no-daemon] Exit on target PM2 exit pid=' + fs.readFileSync(conf.PM2_PID_FILE_PATH).toString()); + global._auto_exit = true; + return that.streamLogs('all', 0, false, 'HH:mm:ss', false); + } + else if (commander.attach === true) { + return that.streamLogs('all', 0, false, null, false); + } + else { + return that.exitCli(code ? code : conf.SUCCESS_EXIT); + } + }); + } + + /** + * Scale up/down a process + * @method scale + */ + scale (app_name, number, cb) { + var that = this; + + function addProcs(proc, value, cb) { + (function ex(proc, number) { + if (number-- === 0) return cb(); + Common.printOut(conf.PREFIX_MSG + 'Scaling up application'); + that.Client.executeRemote('duplicateProcessId', proc.pm2_env.pm_id, ex.bind(this, proc, number)); + })(proc, number); + } + + function rmProcs(procs, value, cb) { + var i = 0; + + (function ex(procs, number) { + if (number++ === 0) return cb(); + that._operate('deleteProcessId', procs[i++].pm2_env.pm_id, ex.bind(this, procs, number)); + })(procs, number); + } + + function end() { + return cb ? cb(null, {success:true}) : that.speedList(); + } + + this.Client.getProcessByName(app_name, function(err, procs) { + if (err) { + Common.printError(err); + return cb ? cb(Common.retErr(err)) : that.exitCli(conf.ERROR_EXIT); + } + + if (!procs || procs.length === 0) { + Common.printError(conf.PREFIX_MSG_ERR + 'Application %s not found', app_name); + return cb ? cb(new Error('App not found')) : that.exitCli(conf.ERROR_EXIT); + } + + var proc_number = procs.length; + + if (typeof(number) === 'string' && number.indexOf('+') >= 0) { + number = parseInt(number, 10); + return addProcs(procs[0], number, end); + } + else if (typeof(number) === 'string' && number.indexOf('-') >= 0) { + number = parseInt(number, 10); + return rmProcs(procs[0], number, end); + } + else { + number = parseInt(number, 10); + number = number - proc_number; + + if (number < 0) + return rmProcs(procs, number, end); + else if (number > 0) + return addProcs(procs[0], number, end); + else { + Common.printError(conf.PREFIX_MSG_ERR + 'Nothing to do'); + return cb ? cb(new Error('Same process number')) : that.exitCli(conf.ERROR_EXIT); + } + } + }); + } + + /** + * Description + * @method describeProcess + * @param {} pm2_id + * @return + */ + describe (pm2_id, cb) { + var that = this; + + var found_proc = []; + + that.Client.executeRemote('getMonitorData', {}, function(err, list) { + if (err) { + Common.printError('Error retrieving process list: ' + err); + that.exitCli(conf.ERROR_EXIT); + } + + list.forEach(function(proc) { + if ((!isNaN(pm2_id) && proc.pm_id == pm2_id) || + (typeof(pm2_id) === 'string' && proc.name == pm2_id)) { + found_proc.push(proc); + } + }); + + if (found_proc.length === 0) { + Common.printError(conf.PREFIX_MSG_WARNING + '%s doesn\'t exist', pm2_id); + return cb ? cb(null, []) : that.exitCli(conf.ERROR_EXIT); + } + + if (!cb) { + found_proc.forEach(function(proc) { + UX.describeTable(proc); + }); + } + + return cb ? cb(null, found_proc) : that.exitCli(conf.SUCCESS_EXIT); + }); + } + + /** + * API method to perform a deep update of PM2 + * @method deepUpdate + */ + deepUpdate (cb) { + var that = this; + + Common.printOut(conf.PREFIX_MSG + 'Updating PM2...'); + + var exec = require('shelljs').exec; + var child = exec("npm i -g pm2@latest; pm2 update", {async : true}); + + child.stdout.on('end', function() { + Common.printOut(conf.PREFIX_MSG + 'PM2 successfully updated'); + cb ? cb(null, {success:true}) : that.exitCli(conf.SUCCESS_EXIT); + }); } }; +API.prototype.close = API.prototype.disconnect; +API.prototype.kill = API.prototype.killDaemon; + ////////////////////////// // Load all API methods // @@ -145,1548 +1692,5 @@ require('./API/Startup.js')(API); require('./API/LogManagement.js')(API); require('./API/Containerizer.js')(API); -/** - * Connect to PM2 - * Calling this command is now optional - * - * @param {Function} cb callback once pm2 is ready for commands - */ -API.prototype.connect = function(noDaemon, cb) { - var that = this; - this.start_timer = new Date(); - - if (typeof(cb) == 'undefined') { - cb = noDaemon; - noDaemon = false; - } else if (noDaemon === true) { - // Backward compatibility with PM2 1.x - this.Client.daemon_mode = false; - this.daemon_mode = false; - } - - this.Client.start(function(err, meta) { - if (err) - return cb(err); - - if (meta.new_pm2_instance == false && that.daemon_mode === true) - return cb(err, meta); - - // If new pm2 instance has been popped - // Lauch all modules - Modularizer.launchAll(that, function(err_mod) { - return cb(err, meta); - }); - }); -} - -/** - * Usefull when custom PM2 created with independent flag set to true - * This will cleanup the newly created instance - * by removing folder, killing PM2 and so on - * - * @param {Function} cb callback once cleanup is successfull - */ -API.prototype.destroy = function(cb) { - var exec = require('shelljs').exec; - var that = this; - - debug('Killing and deleting current deamon'); - - this.killDaemon(function() { - var cmd = 'rm -rf ' + that.pm2_home; - var test_path = path.join(that.pm2_home, 'module_conf.json'); - var test_path_2 = path.join(that.pm2_home, 'pm2.pid'); - - if (that.pm2_home.indexOf('.pm2') > -1) - return cb(new Error('Destroy is not a allowed method on .pm2')); - - if (fs.accessSync) { - fs.access(test_path, fs.R_OK, function(err) { - if (err) return cb(err); - debug('Deleting temporary folder %s', that.pm2_home); - exec(cmd, cb); - }); - return false; - } - - // Support for Node 0.10 - fs.exists(test_path, function(exist) { - if (exist) { - debug('Deleting temporary folder %s', that.pm2_home); - exec(cmd, cb); - } - return cb(null); - }); - }); -}; - -/** - * Disconnect from PM2 instance - * This will allow your software to exit by itself - * - * @param {Function} [cb] optional callback once connection closed - */ -API.prototype.disconnect = API.prototype.close = function(cb) { - var that = this; - - if (!cb) cb = function() {}; - - this.Client.close(function(err, data) { - debug('The session lasted %ds', (new Date() - that.start_timer) / 1000); - return cb(err, data); - }); -}; - -/** - * Launch modules - * - * @param {Function} cb callback once pm2 has launched modules - */ -API.prototype.launchModules = function(cb) { - Modularizer.launchAll(this, cb); -}; - -/** - * Enable bus allowing to retrieve various process event - * like logs, restarts, reloads - * - * @param {Function} cb callback called with 1st param err and 2nb param the bus - */ -API.prototype.launchBus = function(cb) { - this.Client.launchBus(cb); -}; - -/** - * Exit methods for API - * @param {Integer} code exit code for terminal - */ -API.prototype.exitCli = function(code) { - var that = this; - - // Do nothing if PM2 called programmatically (also in speedlist) - if (conf.PM2_PROGRAMMATIC && process.env.PM2_USAGE != 'CLI') return false; - - KMDaemon.disconnectRPC(function() { - that.Client.close(function() { - code = code || 0; - // Safe exits process after all streams are drained. - // file descriptor flag. - var fds = 0; - // exits process when stdout (1) and sdterr(2) are both drained. - function tryToExit() { - if ((fds & 1) && (fds & 2)) { - debug('This command took %ds to execute', (new Date() - that.start_timer) / 1000); - process.exit(code); - } - } - - [process.stdout, process.stderr].forEach(function(std) { - var fd = std.fd; - if (!std.bufferSize) { - // bufferSize equals 0 means current stream is drained. - fds = fds | fd; - } else { - // Appends nothing to the std queue, but will trigger `tryToExit` event on `drain`. - std.write && std.write('', function() { - fds = fds | fd; - tryToExit(); - }); - } - // Does not write anything more. - delete std.write; - }); - tryToExit(); - }); - }); -}; - -//////////////////////////// -// Application management // -//////////////////////////// - -/** - * Start a file or json with configuration - * @param {Object||String} cmd script to start or json - * @param {Function} cb called when application has been started - */ -API.prototype.start = function(cmd, opts, cb) { - if (typeof(opts) == "function") { - cb = opts; - opts = {}; - } - if (!opts) - opts = {}; - - var that = this; - - if (util.isArray(opts.watch) && opts.watch.length === 0) - opts.watch = (opts.rawArgs ? !!~opts.rawArgs.indexOf('--watch') : !!~process.argv.indexOf('--watch')) || false; - - if (Common.isConfigFile(cmd) || (typeof(cmd) === 'object')) - that._startJson(cmd, opts, 'restartProcessId', cb); - else { - that._startScript(cmd, opts, cb); - } -}; - -/** - * Reset process counters - * - * @method resetMetaProcess - */ -API.prototype.reset = function(process_name, cb) { - var that = this; - - function processIds(ids, cb) { - async.eachLimit(ids, conf.CONCURRENT_ACTIONS, function(id, next) { - that.Client.executeRemote('resetMetaProcessId', id, function(err, res) { - if (err) console.error(err); - Common.printOut(conf.PREFIX_MSG + 'Resetting meta for process id %d', id); - return next(); - }); - }, function(err) { - if (err) return cb(Common.retErr(err)); - return cb ? cb(null, {success:true}) : that.speedList(); - }); - } - - if (process_name == 'all') { - that.Client.getAllProcessId(function(err, ids) { - if (err) { - Common.printError(err); - return cb ? cb(Common.retErr(err)) : that.exitCli(conf.ERROR_EXIT); - } - return processIds(ids, cb); - }); - } - else if (isNaN(process_name)) { - that.Client.getProcessIdByName(process_name, function(err, ids) { - if (err) { - Common.printError(err); - return cb ? cb(Common.retErr(err)) : that.exitCli(conf.ERROR_EXIT); - } - if (ids.length === 0) { - Common.printError('Unknown process name'); - return cb ? cb(new Error('Unknown process name')) : that.exitCli(conf.ERROR_EXIT); - } - return processIds(ids, cb); - }); - } else { - processIds([process_name], cb); - } -}; - -/** - * Update daemonized PM2 Daemon - * - * @param {Function} cb callback when pm2 has been upgraded - */ -API.prototype.update = function(cb) { - var that = this; - - Common.printOut('Be sure to have the latest version by doing `npm install pm2@latest -g` before doing this procedure.'); - - // Dump PM2 processes - that.Client.executeRemote('notifyKillPM2', {}, function() {}); - - that.getVersion(function(err, new_version) { - // If not linked to keymetrics, and update pm2 to latest, display motd.update - if (!that.gl_is_km_linked && !err && (pkg.version != new_version)) { - var dt = fs.readFileSync(path.join(__dirname, that._conf.KEYMETRICS_UPDATE)); - console.log(dt.toString()); - } - - that.dump(function(err) { - debug('Dumping successfull', err); - that.killDaemon(function() { - debug('------------------ Everything killed', arguments); - that.Client.launchDaemon({interactor:false}, function(err, child) { - that.Client.launchRPC(function() { - that.resurrect(function() { - Common.printOut(chalk.blue.bold('>>>>>>>>>> PM2 updated')); - Modularizer.launchAll(that, function() { - KMDaemon.launchAndInteract(that._conf, null, function(err, data, interactor_proc) { - // Interactor error can be skipped here - return cb ? cb(null, {success:true}) : that.speedList(); - }); - }); - }); - }); - }); - }); - }); - }); - - return false; -}; - -/** - * Graceful Reload an application - * - * @param {String} process_name Application Name or All - * @param {Object} opts Options - * @param {Function} cb Callback - */ -API.prototype.gracefulReload = function(process_name, opts, cb) { - var that = this; - - if (typeof(opts) == "function") { - cb = opts; - opts = {}; - } - - //Common.printOut(conf.PREFIX_MSG_WARNING + chalk.bold.yellow('Warning gracefulReload will be soon deprecated')); - //Common.printOut(conf.PREFIX_MSG_WARNING + chalk.bold.yellow('Use http://pm2.keymetrics.io/docs/usage/signals-clean-restart/ instead')); - - if (Common.isConfigFile(process_name)) - that._startJson(process_name, commander, 'softReloadProcessId'); - else { - if (opts && !opts.updateEnv) - Common.printOut(IMMUTABLE_MSG); - that._operate('softReloadProcessId', process_name, opts, cb); - } -}; - -/** - * Reload an application - * - * @param {String} process_name Application Name or All - * @param {Object} opts Options - * @param {Function} cb Callback - */ -API.prototype.reload = function(process_name, opts, cb) { - var that = this; - - if (typeof(opts) == "function") { - cb = opts; - opts = {}; - } - - var delay = Common.lockReload(); - - if (delay > 0 && opts.force != true) { - Common.printError(conf.PREFIX_MSG_ERR + 'Reload already in progress, please try again in ' + Math.floor((conf.RELOAD_LOCK_TIMEOUT - delay) / 1000) + ' seconds or use --force'); - return cb ? cb(new Error('Reload in progress')) : that.exitCli(conf.ERROR_EXIT); - } - - if (Common.isConfigFile(process_name)) - that._startJson(process_name, opts, 'reloadProcessId', function(err, apps) { - Common.unlockReload(); - if (err) - return cb ? cb(err) : that.exitCli(conf.ERROR_EXIT); - return cb ? cb(null, apps) : that.exitCli(conf.SUCCESS_EXIT);; - }); - else { - if (opts && !opts.updateEnv) - Common.printOut(IMMUTABLE_MSG); - - that._operate('reloadProcessId', process_name, opts, function(err, apps) { - Common.unlockReload(); - - if (err) - return cb ? cb(err) : that.exitCli(conf.ERROR_EXIT); - return cb ? cb(null, apps) : that.exitCli(conf.SUCCESS_EXIT);; - }); - } -}; - -/** - * Restart process - * - * @param {String} cmd Application Name / Process id / JSON application file / 'all' - * @param {Object} opts Extra options to be updated - * @param {Function} cb Callback - */ -API.prototype.restart = function(cmd, opts, cb) { - if (typeof(opts) == "function") { - cb = opts; - opts = {}; - } - var that = this; - - if (typeof(cmd) === 'number') - cmd = cmd.toString(); - - if (cmd == "-") { - // Restart from PIPED JSON - process.stdin.resume(); - process.stdin.setEncoding('utf8'); - process.stdin.on('data', function (param) { - process.stdin.pause(); - that.actionFromJson('restartProcessId', param, opts, 'pipe', cb); - }); - } - else if (Common.isConfigFile(cmd) || typeof(cmd) === 'object') - that._startJson(cmd, opts, 'restartProcessId', cb); - else { - if (opts && !opts.updateEnv) - Common.printOut(IMMUTABLE_MSG); - that._operate('restartProcessId', cmd, opts, cb); - } -}; - -/** - * Delete process - * - * @param {String} process_name Application Name / Process id / Application file / 'all' - * @param {Function} cb Callback - */ -API.prototype.delete = function(process_name, jsonVia, cb) { - var that = this; - - if (typeof(jsonVia) === "function") { - cb = jsonVia; - jsonVia = null; - } - if (typeof(process_name) === "number") { - process_name = process_name.toString(); - } - - if (jsonVia == 'pipe') - return that.actionFromJson('deleteProcessId', process_name, commander, 'pipe', cb); - if (Common.isConfigFile(process_name)) - return that.actionFromJson('deleteProcessId', process_name, commander, 'file', cb); - else - that._operate('deleteProcessId', process_name, cb); -}; - -/** - * Stop process - * - * @param {String} process_name Application Name / Process id / Application file / 'all' - * @param {Function} cb Callback - */ -API.prototype.stop = function(process_name, cb) { - var that = this; - - if (typeof(process_name) === 'number') - process_name = process_name.toString(); - - if (process_name == "-") { - process.stdin.resume(); - process.stdin.setEncoding('utf8'); - process.stdin.on('data', function (param) { - process.stdin.pause(); - that.actionFromJson('stopProcessId', param, commander, 'pipe', cb); - }); - } - else if (Common.isConfigFile(process_name)) - that.actionFromJson('stopProcessId', process_name, commander, 'file', cb); - else - that._operate('stopProcessId', process_name, cb); -}; - -/** - * Get list of all processes managed - * - * @param {Function} cb Callback - */ -API.prototype.list = function(opts, cb) { - var that = this; - - if (typeof(opts) == 'function') { - cb = opts; - opts = null; - } - - that.Client.executeRemote('getMonitorData', {}, function(err, list) { - if (err) { - Common.printError(err); - return cb ? cb(Common.retErr(err)) : that.exitCli(conf.ERROR_EXIT); - } - - if (opts && opts.rawArgs && opts.rawArgs.indexOf('--watch') > -1) { - var moment = require('moment'); - function show() { - process.stdout.write('\033[2J'); - process.stdout.write('\033[0f'); - console.log('Last refresh: ', moment().format('LTS')); - that.Client.executeRemote('getMonitorData', {}, function(err, list) { - UX.dispAsTable(list, null); - }); - } - - show(); - setInterval(show, 900); - return false; - } - - return cb ? cb(null, list) : that.speedList(); - }); -}; - -/** - * Kill Daemon - * - * @param {Function} cb Callback - */ -API.prototype.killDaemon = API.prototype.kill = function(cb) { - var that = this; - - var semver = require('semver'); - Common.printOut(conf.PREFIX_MSG + 'Stopping PM2...'); - - that.Client.executeRemote('notifyKillPM2', {}, function() {}); - - that.killAllModules(function() { - that._operate('deleteProcessId', 'all', function(err, list) { - Common.printOut(conf.PREFIX_MSG + 'All processes have been stopped and deleted'); - process.env.PM2_SILENT = 'false'; - - that.killInteract(function(err, data) { - that.Client.killDaemon(function(err, res) { - if (err) Common.printError(err); - Common.printOut(conf.PREFIX_MSG + 'PM2 stopped'); - return cb ? cb(err, res) : that.exitCli(conf.SUCCESS_EXIT); - }); - }); - }); - }); -}; - -///////////////////// -// Private methods // -///////////////////// - -/** - * Method to START / RESTART a script - * - * @private - * @param {string} script script name (will be resolved according to location) - */ -API.prototype._startScript = function(script, opts, cb) { - if (typeof opts == "function") { - cb = opts; - opts = {}; - } - var that = this; - - var app_conf = Config.transCMDToConf(opts); - var appConf = {}; - - if (!!opts.executeCommand) - app_conf.exec_mode = 'fork'; - else if (opts.instances !== undefined) - app_conf.exec_mode = 'cluster'; - else - app_conf.exec_mode = 'fork'; - - // Options set via environment variables - if (process.env.PM2_DEEP_MONITORING) - app_conf.deep_monitoring = true; - - if (typeof app_conf.name == 'function'){ - delete app_conf.name; - } - - delete app_conf.args; - - var argsIndex; - - if (opts.rawArgs && (argsIndex = opts.rawArgs.indexOf('--')) >= 0) { - app_conf.args = opts.rawArgs.slice(argsIndex + 1); - } - else if (opts.scriptArgs) { - app_conf.args = opts.scriptArgs; - } - - app_conf.script = script; - - if ((appConf = Common.verifyConfs(app_conf)) instanceof Error) - return cb ? cb(Common.retErr(appConf)) : that.exitCli(conf.ERROR_EXIT); - - app_conf = appConf[0]; - - app_conf.username = Common.getCurrentUsername(); - - /** - * If -w option, write configuration to configuration.json file - */ - if (appConf.write) { - var dst_path = path.join(process.env.PWD || process.cwd(), app_conf.name + '-pm2.json'); - Common.printOut(conf.PREFIX_MSG + 'Writing configuration to', chalk.blue(dst_path)); - // pretty JSON - try { - fs.writeFileSync(dst_path, JSON.stringify(app_conf, null, 2)); - } catch (e) { - console.error(e.stack || e); - } - } - - /** - * If start start/restart application - */ - function restartExistingProcessName(cb) { - if (!isNaN(script) || - (typeof script === 'string' && script.indexOf('/') != -1) || - (typeof script === 'string' && path.extname(script) !== '')) - return cb(null); - - if (script !== 'all') { - that.Client.getProcessIdByName(script, function(err, ids) { - if (err && cb) return cb(err); - if (ids.length > 0) { - that._operate('restartProcessId', script, opts, function(err, list) { - if (err) return cb(err); - Common.printOut(conf.PREFIX_MSG + 'Process successfully started'); - return cb(true, list); - }); - } - else return cb(null); - }); - } - else { - that._operate('restartProcessId', 'all', function(err, list) { - if (err) return cb(err); - Common.printOut(conf.PREFIX_MSG + 'Process successfully started'); - return cb(true, list); - }); - } - } - - function restartExistingProcessId(cb) { - if (isNaN(script)) return cb(null); - - that._operate('restartProcessId', script, opts, function(err, list) { - if (err) return cb(err); - Common.printOut(conf.PREFIX_MSG + 'Process successfully started'); - return cb(true, list); - }); - } - - /** - * Restart a process with the same full path - * Or start it - */ - function restartExistingProcessPath(cb) { - that.Client.executeRemote('getMonitorData', {}, function(err, procs) { - if (err) return cb ? cb(new Error(err)) : that.exitCli(conf.ERROR_EXIT); - - var full_path = path.resolve(that.cwd, script); - var managed_script = null; - - procs.forEach(function(proc) { - if (proc.pm2_env.pm_exec_path == full_path && - proc.pm2_env.name == app_conf.name) - managed_script = proc; - }); - - if (managed_script && - (managed_script.pm2_env.status == conf.STOPPED_STATUS || - managed_script.pm2_env.status == conf.STOPPING_STATUS || - managed_script.pm2_env.status == conf.ERRORED_STATUS)) { - // Restart process if stopped - var app_name = managed_script.pm2_env.name; - - that._operate('restartProcessId', app_name, opts, function(err, list) { - if (err) return cb ? cb(new Error(err)) : that.exitCli(conf.ERROR_EXIT); - Common.printOut(conf.PREFIX_MSG + 'Process successfully started'); - return cb(true, list); - }); - return false; - } - else if (managed_script && !opts.force) { - Common.printError(conf.PREFIX_MSG_ERR + 'Script already launched, add -f option to force re-execution'); - return cb(new Error('Script already launched')); - } - - var resolved_paths = null; - - try { - resolved_paths = Common.resolveAppAttributes({ - cwd : that.cwd, - pm2_home : that.pm2_home - }, app_conf); - } catch(e) { - Common.printError(e); - return cb(Common.retErr(e)); - } - - Common.printOut(conf.PREFIX_MSG + 'Starting %s in %s (%d instance' + (resolved_paths.instances > 1 ? 's' : '') + ')', - resolved_paths.pm_exec_path, resolved_paths.exec_mode, resolved_paths.instances); - - if (!resolved_paths.env) resolved_paths.env = {}; - - // Set PM2 HOME in case of child process using PM2 API - resolved_paths.env['PM2_HOME'] = that.pm2_home; - - var additional_env = Modularizer.getAdditionalConf(resolved_paths.name); - util._extend(resolved_paths.env, additional_env); - - // Is KM linked? - resolved_paths.km_link = that.gl_is_km_linked; - - that.Client.executeRemote('prepare', resolved_paths, function(err, data) { - if (err) { - Common.printError(conf.PREFIX_MSG_ERR + 'Error while launching application', err.stack || err); - return cb(Common.retErr(err)); - } - - Common.printOut(conf.PREFIX_MSG + 'Done.'); - return cb(true, data); - }); - return false; - }); - } - - async.series([ - restartExistingProcessName, - restartExistingProcessId, - restartExistingProcessPath - ], function(err, data) { - - if (err instanceof Error) - return cb ? cb(err) : that.exitCli(conf.ERROR_EXIT); - - var ret = {}; - data.forEach(function(_dt) { - if (_dt !== undefined) - ret = _dt; - }); - - return cb ? cb(null, ret) : that.speedList(); - }); -}; - -/** - * Method to start/restart/reload processes from a JSON file - * It will start app not started - * Can receive only option to skip applications - * - * @private - */ -API.prototype._startJson = function(file, opts, action, pipe, cb) { - var config = {}; - var appConf = {}; - var deployConf = {}; - var apps_info = []; - var that = this; - - if (typeof(cb) === 'undefined' && typeof(pipe) === 'function') { - cb = pipe; - } - - if (typeof(file) === 'object') { - config = file; - } else if (pipe === 'pipe') { - config = Common.parseConfig(file, 'pipe'); - } else { - var data = null; - - var isAbsolute = false - - //node 0.11 compatibility #2815 - if (typeof path.isAbsolute === 'function') { - isAbsolute = path.isAbsolute(file) - } else { - isAbsolute = require('./tools/IsAbsolute.js')(file) - } - - var file_path = isAbsolute ? file : path.join(that.cwd, file); - - debug('Resolved filepath %s', file_path); - - try { - data = fs.readFileSync(file_path); - } catch(e) { - Common.printError(conf.PREFIX_MSG_ERR + 'File ' + file +' not found'); - return cb ? cb(Common.retErr(e)) : that.exitCli(conf.ERROR_EXIT); - } - - try { - config = Common.parseConfig(data, file); - } catch(e) { - Common.printError(conf.PREFIX_MSG_ERR + 'File ' + file + ' malformated'); - console.error(e); - return cb ? cb(Common.retErr(e)) : that.exitCli(conf.ERROR_EXIT); - } - } - - if (config.deploy) - deployConf = config.deploy; - - if (config.apps) - appConf = config.apps; - else if (config.pm2) - appConf = config.pm2; - else - appConf = config; - - if (!Array.isArray(appConf)) - appConf = [appConf]; //convert to array - - if ((appConf = Common.verifyConfs(appConf)) instanceof Error) - return cb ? cb(appConf) : that.exitCli(conf.ERROR_EXIT); - - process.env.PM2_JSON_PROCESSING = true; - - // Get App list - var apps_name = []; - var proc_list = {}; - - // Here we pick only the field we want from the CLI when starting a JSON - appConf.forEach(function(app) { - // --only - if (opts.only && opts.only != app.name) - return false; - // --watch - if (!app.watch && opts.watch && opts.watch === true) - app.watch = true; - // --ignore-watch - if (!app.ignore_watch && opts.ignore_watch) - app.ignore_watch = opts.ignore_watch; - // --instances - if (opts.instances && typeof(opts.instances) === 'number') - app.instances = opts.instances; - // --uid - if (opts.uid) - app.uid = opts.uid; - // --gid - if (opts.gid) - app.gid = opts.gid; - // Specific - if (app.append_env_to_name && opts.env) - app.name += ('-' + opts.env); - app.username = Common.getCurrentUsername(); - apps_name.push(app.name); - }); - - that.Client.executeRemote('getMonitorData', {}, function(err, raw_proc_list) { - if (err) { - Common.printError(err); - return cb ? cb(Common.retErr(err)) : that.exitCli(conf.ERROR_EXIT); - } - - /** - * Uniquify in memory process list - */ - raw_proc_list.forEach(function(proc) { - proc_list[proc.name] = proc; - }); - - /** - * Auto detect application already started - * and act on them depending on action - */ - async.eachLimit(Object.keys(proc_list), conf.CONCURRENT_ACTIONS, function(proc_name, next) { - // Skip app name (--only option) - if (apps_name.indexOf(proc_name) == -1) - return next(); - - if (!(action == 'reloadProcessId' || - action == 'softReloadProcessId' || - action == 'restartProcessId')) - throw new Error('Wrong action called'); - - var apps = appConf.filter(function(app) { - return app.name == proc_name; - }); - - var envs = apps.map(function(app){ - // Binds env_diff to env and returns it. - return Common.mergeEnvironmentVariables(app, opts.env, deployConf); - }); - - // Assigns own enumerable properties of all - // Notice: if people use the same name in different apps, - // duplicated envs will be overrode by the last one - var env = envs.reduce(function(e1, e2){ - return util._extend(e1, e2); - }); - - // When we are processing JSON, allow to keep the new env by default - env.updateEnv = true; - - // Pass `env` option - that._operate(action, proc_name, env, function(err, ret) { - if (err) Common.printError(err); - - // For return - apps_info = apps_info.concat(ret); - - that.Client.notifyGod(action, proc_name); - // And Remove from array to spy - apps_name.splice(apps_name.indexOf(proc_name), 1); - return next(); - }); - - }, function(err) { - if (err) return cb ? cb(Common.retErr(err)) : that.exitCli(conf.ERROR_EXIT); - if (apps_name.length > 0 && action != 'start') - Common.printOut(conf.PREFIX_MSG_WARNING + 'Applications %s not running, starting...', apps_name.join(', ')); - // Start missing apps - return startApps(apps_name, function(err, apps) { - apps_info = apps_info.concat(apps); - return cb ? cb(err, apps_info) : that.speedList(err ? 1 : 0); - }); - }); - return false; - }); - - function startApps(app_name_to_start, cb) { - var apps_to_start = []; - var apps_started = []; - - appConf.forEach(function(app, i) { - if (app_name_to_start.indexOf(app.name) != -1) { - apps_to_start.push(appConf[i]); - } - }); - - async.eachLimit(apps_to_start, conf.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; - - var resolved_paths = null; - - // hardcode script name to use `serve` feature inside a process file - if (app.script === 'serve') { - app.script = path.resolve(__dirname, 'API', 'Serve.js') - } - - try { - resolved_paths = Common.resolveAppAttributes({ - cwd : that.cwd, - pm2_home : that.pm2_home - }, app); - } catch (e) { - return next(); - } - - if (!resolved_paths.env) resolved_paths.env = {}; - - // Set PM2 HOME in case of child process using PM2 API - resolved_paths.env['PM2_HOME'] = that.pm2_home; - - var additional_env = Modularizer.getAdditionalConf(resolved_paths.name); - util._extend(resolved_paths.env, additional_env); - - resolved_paths.env = Common.mergeEnvironmentVariables(resolved_paths, opts.env, deployConf); - - delete resolved_paths.env.current_conf; - - // Is KM linked? - resolved_paths.km_link = that.gl_is_km_linked; - - that.Client.executeRemote('prepare', resolved_paths, function(err, data) { - if (err) { - Common.printError(conf.PREFIX_MSG_ERR + 'Process failed to launch %s', err.message ? err.message : err); - return next(); - } - if (data.length === 0) { - Common.printError(conf.PREFIX_MSG_ERR + 'Process config loading failed', data); - return next(); - } - - Common.printOut(conf.PREFIX_MSG + 'App [%s] launched (%d instances)', data[0].pm2_env.name, data.length); - apps_started = apps_started.concat(data); - next(); - }); - - }, function(err) { - return cb ? cb(err || null, apps_started) : that.speedList(); - }); - return false; - } -}; - -/** - * Apply a RPC method on the json file - * @private - * @method actionFromJson - * @param {string} action RPC Method - * @param {object} options - * @param {string|object} file file - * @param {string} jsonVia action type (=only 'pipe' ?) - * @param {Function} - */ -API.prototype.actionFromJson = function(action, file, opts, jsonVia, cb) { - var appConf = {}; - var ret_processes = []; - var that = this; - - //accept programmatic calls - if (typeof file == 'object') { - cb = typeof jsonVia == 'function' ? jsonVia : cb; - appConf = file; - } - else if (jsonVia == 'file') { - var data = null; - - try { - data = fs.readFileSync(file); - } catch(e) { - Common.printError(conf.PREFIX_MSG_ERR + 'File ' + file +' not found'); - return cb ? cb(Common.retErr(e)) : that.exitCli(conf.ERROR_EXIT); - } - - try { - appConf = Common.parseConfig(data, file); - } catch(e) { - Common.printError(conf.PREFIX_MSG_ERR + 'File ' + file + ' malformated'); - console.error(e); - return cb ? cb(Common.retErr(e)) : that.exitCli(conf.ERROR_EXIT); - } - } else if (jsonVia == 'pipe') { - appConf = Common.parseConfig(file, 'pipe'); - } else { - Common.printError('Bad call to actionFromJson, jsonVia should be one of file, pipe'); - return that.exitCli(conf.ERROR_EXIT); - } - - // Backward compatibility - if (appConf.apps) - appConf = appConf.apps; - - if (!Array.isArray(appConf)) - appConf = [appConf]; - - if ((appConf = Common.verifyConfs(appConf)) instanceof Error) - return cb ? cb(appConf) : that.exitCli(conf.ERROR_EXIT); - - async.eachLimit(appConf, conf.CONCURRENT_ACTIONS, function(proc, next1) { - var name = ''; - var new_env; - - if (!proc.name) - name = path.basename(proc.script); - else - name = proc.name; - - if (opts.only && opts.only != name) - return process.nextTick(next1); - - if (opts && opts.env) - new_env = Common.mergeEnvironmentVariables(proc, opts.env); - else - new_env = Common.mergeEnvironmentVariables(proc); - - that.Client.getProcessIdByName(name, function(err, ids) { - if (err) { - Common.printError(err); - return next1(); - } - if (!ids) return next1(); - - async.eachLimit(ids, conf.CONCURRENT_ACTIONS, function(id, next2) { - var opts = {}; - - //stopProcessId could accept options to? - if (action == 'restartProcessId') { - opts = {id : id, env : new_env}; - } else { - opts = id; - } - - that.Client.executeRemote(action, opts, function(err, res) { - ret_processes.push(res); - if (err) { - Common.printError(err); - return next2(); - } - - if (action == 'restartProcessId') { - that.Client.notifyGod('restart', id); - } else if (action == 'deleteProcessId') { - that.Client.notifyGod('delete', id); - } else if (action == 'stopProcessId') { - that.Client.notifyGod('stop', id); - } - - Common.printOut(conf.PREFIX_MSG + '[%s](%d) \u2713', name, id); - return next2(); - }); - }, function(err) { - return next1(null, ret_processes); - }); - }); - }, function(err) { - if (cb) return cb(null, ret_processes); - else return that.speedList(); - }); -}; - - -/** - * Main function to operate with PM2 daemon - * - * @param {String} action_name Name of action (restartProcessId, deleteProcessId, stopProcessId) - * @param {String} process_name can be 'all', a id integer or process name - * @param {Object} envs object with CLI options / environment - */ -API.prototype._operate = function(action_name, process_name, envs, cb) { - var that = this; - var update_env = false; - var ret = []; - - // Make sure all options exist - if (!envs) - envs = {}; - - if (typeof(envs) == 'function'){ - cb = envs; - envs = {}; - } - - // Set via env.update (JSON processing) - if (envs.updateEnv === true) - update_env = true; - - var concurrent_actions = envs.parallel || conf.CONCURRENT_ACTIONS; - - if (!process.env.PM2_JSON_PROCESSING || envs.commands) { - envs = that._handleAttributeUpdate(envs); - } - - /** - * Set current updated configuration if not passed - */ - if (!envs.current_conf) { - var _conf = fclone(envs); - envs = { - current_conf : _conf - } - - // Is KM linked? - envs.current_conf.km_link = that.gl_is_km_linked; - } - - /** - * Operate action on specific process id - */ - function processIds(ids, cb) { - Common.printOut(conf.PREFIX_MSG + 'Applying action %s on app [%s](ids: %s)', action_name, process_name, ids); - - if (action_name == 'deleteProcessId') - concurrent_actions = 10; - - async.eachLimit(ids, concurrent_actions, function(id, next) { - var opts; - - // These functions need extra param to be passed - if (action_name == 'restartProcessId' || - action_name == 'reloadProcessId' || - action_name == 'softReloadProcessId') { - var new_env = {}; - - if (update_env === true) { - if (conf.PM2_PROGRAMMATIC == true) - new_env = Common.safeExtend({}, process.env); - else - new_env = util._extend({}, process.env); - - Object.keys(envs).forEach(function(k) { - new_env[k] = envs[k]; - }); - } - else { - new_env = envs; - } - - opts = { - id : id, - env : new_env - }; - } - else { - opts = id; - } - - that.Client.executeRemote(action_name, opts, function(err, res) { - if (err) { - Common.printError(conf.PREFIX_MSG_ERR + 'Process %s not found', id); - return next('Process not found'); - } - - if (action_name == 'restartProcessId') { - that.Client.notifyGod('restart', id); - } else if (action_name == 'deleteProcessId') { - that.Client.notifyGod('delete', id); - } else if (action_name == 'stopProcessId') { - that.Client.notifyGod('stop', id); - } else if (action_name == 'reloadProcessId') { - that.Client.notifyGod('reload', id); - } else if (action_name == 'softReloadProcessId') { - that.Client.notifyGod('graceful reload', id); - } - - if (!Array.isArray(res)) - res = [res]; - - // Filter return - res.forEach(function(proc) { - Common.printOut(conf.PREFIX_MSG + '[%s](%d) \u2713', proc.pm2_env ? proc.pm2_env.name : process_name, id); - - if (!proc.pm2_env) return false; - - ret.push({ - name : proc.pm2_env.name, - pm_id : proc.pm2_env.pm_id, - status : proc.pm2_env.status, - restart_time : proc.pm2_env.restart_time, - pm2_env : { - name : proc.pm2_env.name, - pm_id : proc.pm2_env.pm_id, - status : proc.pm2_env.status, - restart_time : proc.pm2_env.restart_time, - env : proc.pm2_env.env - } - }); - }); - - return next(); - }); - }, function(err) { - if (err) return cb ? cb(Common.retErr(err)) : that.exitCli(conf.ERROR_EXIT); - return cb ? cb(null, ret) : that.speedList(); - }); - } - - if (process_name == 'all') { - that.Client.getAllProcessId(function(err, ids) { - if (err) { - Common.printError(err); - return cb ? cb(Common.retErr(err)) : that.exitCli(conf.ERROR_EXIT); - } - if (!ids || ids.length === 0) { - Common.printError(conf.PREFIX_MSG_WARNING + 'No process found'); - return cb ? cb(new Error('process name not found')) : that.exitCli(conf.ERROR_EXIT); - } - - return processIds(ids, cb); - }); - } - // operate using regex - else if (isNaN(process_name) && process_name[0] === '/' && process_name[process_name.length - 1] === '/') { - var regex = new RegExp(process_name.replace(/\//g, '')); - - that.Client.executeRemote('getMonitorData', {}, function(err, list) { - if (err) { - Common.printError('Error retrieving process list: ' + err); - return cb(err); - } - var found_proc = []; - list.forEach(function(proc) { - if (regex.test(proc.pm2_env.name)) { - found_proc.push(proc.pm_id); - } - }); - - if (found_proc.length === 0) { - Common.printError(conf.PREFIX_MSG_WARNING + 'No process found'); - return cb ? cb(new Error('process name not found')) : that.exitCli(conf.ERROR_EXIT); - } - - return processIds(found_proc, cb); - }); - } - else if (isNaN(process_name)) { - /** - * We can not stop or delete a module but we can restart it - * to refresh configuration variable - */ - var allow_module_restart = action_name == 'restartProcessId' ? true : false; - - that.Client.getProcessIdByName(process_name, allow_module_restart, function(err, ids) { - if (err) { - Common.printError(err); - return cb ? cb(Common.retErr(err)) : that.exitCli(conf.ERROR_EXIT); - } - if (!ids || ids.length === 0) { - Common.printError(conf.PREFIX_MSG_ERR + 'Process %s not found', process_name); - return cb ? cb(new Error('process name not found')) : that.exitCli(conf.ERROR_EXIT); - } - - /** - * Determine if the process to restart is a module - * if yes load configuration variables and merge with the current environment - */ - var additional_env = Modularizer.getAdditionalConf(process_name); - util._extend(envs, additional_env); - - return processIds(ids, cb); - }); - } else { - // Check if application name as number is an app name - that.Client.getProcessIdByName(process_name, function(err, ids) { - if (ids.length > 0) - return processIds(ids, cb); - // Else operate on pm id - return processIds([process_name], cb); - }); - } -}; - -/** - * Converts CamelCase Commander.js arguments - * to Underscore - * (nodeArgs -> node_args) - */ -API.prototype._handleAttributeUpdate = function(opts) { - var conf = Config.transCMDToConf(opts); - var that = this; - - if (typeof(conf.name) != 'string') - delete conf.name; - - var argsIndex = 0; - if (opts.rawArgs && (argsIndex = opts.rawArgs.indexOf('--')) >= 0) { - conf.args = opts.rawArgs.slice(argsIndex + 1); - } - - var appConf = Common.verifyConfs(conf)[0]; - - if (appConf instanceof Error) { - Common.printError('Error while transforming CamelCase args to underscore'); - return appConf; - } - - if (argsIndex == -1) - delete appConf.args; - if (appConf.name == 'undefined') - delete appConf.name; - - delete appConf.exec_mode; - - if (util.isArray(appConf.watch) && appConf.watch.length === 0) { - if (!~opts.rawArgs.indexOf('--watch')) - delete appConf.watch - } - - // Options set via environment variables - if (process.env.PM2_DEEP_MONITORING) - appConf.deep_monitoring = true; - - // Force deletion of defaults values set by commander - // to avoid overriding specified configuration by user - if (appConf.treekill === true) - delete appConf.treekill; - if (appConf.pmx === true) - delete appConf.pmx; - if (appConf.vizion === true) - delete appConf.vizion; - if (appConf.automation === true) - delete appConf.automation; - if (appConf.autorestart === true) - delete appConf.autorestart; - - return appConf; -}; - -API.prototype.getProcessIdByName = function(name, cb) { - var that = this; - - this.Client.getProcessIdByName(name, function(err, id) { - if (err) { - Common.printError(err); - return cb ? cb(Common.retErr(err)) : that.exitCli(conf.ERROR_EXIT); - } - console.log(id); - return cb ? cb(null, id) : that.exitCli(conf.SUCCESS_EXIT); - }); -}; - -/** - * Description - * @method jlist - * @param {} debug - * @return - */ -API.prototype.jlist = function(debug) { - var that = this; - - that.Client.executeRemote('getMonitorData', {}, function(err, list) { - if (err) { - Common.printError(err); - that.exitCli(conf.ERROR_EXIT); - } - - if (debug) { - process.stdout.write(util.inspect(list, false, null, false)); - } - else { - process.stdout.write(JSON.stringify(list)); - } - - that.exitCli(conf.SUCCESS_EXIT); - - }); -}; - -var gl_retry = 0; - -/** - * Description - * @method speedList - * @return - */ -API.prototype.speedList = function(code) { - var that = this; - - // Do nothing if PM2 called programmatically and not called from CLI (also in exitCli) - if (conf.PM2_PROGRAMMATIC && process.env.PM2_USAGE != 'CLI') return false; - - that.Client.executeRemote('getMonitorData', {}, function(err, list) { - if (err) { - if (gl_retry == 0) { - gl_retry += 1; - return setTimeout(that.speedList.bind(that), 1400); - } - console.error('Error retrieving process list: %s.\nA process seems to be on infinite loop, retry in 5 seconds',err); - return that.exitCli(conf.ERROR_EXIT); - } - if (process.stdout.isTTY === false) { - UX.miniDisplay(list); - } - else if (commander.miniList && !commander.silent) - UX.miniDisplay(list); - else if (!commander.silent) { - if (that.gl_interact_infos) { - Common.printOut(chalk.green.bold('●') + ' Agent Online | Dashboard Access: ' + chalk.bold('https://app.keymetrics.io/#/r/%s') + ' | Server name: %s', that.gl_interact_infos.public_key, that.gl_interact_infos.machine_name); - } - UX.dispAsTable(list, commander); - Common.printOut(chalk.white.italic(' Use `pm2 show ` to get more details about an app')); - } - - if (that.Client.daemon_mode == false) { - Common.printOut('[--no-daemon] Continue to stream logs'); - Common.printOut('[--no-daemon] Exit on target PM2 exit pid=' + fs.readFileSync(conf.PM2_PID_FILE_PATH).toString()); - global._auto_exit = true; - return that.streamLogs('all', 0, false, 'HH:mm:ss', false); - } - else if (commander.attach === true) { - return that.streamLogs('all', 0, false, null, false); - } - else { - return that.exitCli(code ? code : conf.SUCCESS_EXIT); - } - }); -} - -/** - * Scale up/down a process - * @method scale - */ -API.prototype.scale = function(app_name, number, cb) { - var that = this; - - function addProcs(proc, value, cb) { - (function ex(proc, number) { - if (number-- === 0) return cb(); - Common.printOut(conf.PREFIX_MSG + 'Scaling up application'); - that.Client.executeRemote('duplicateProcessId', proc.pm2_env.pm_id, ex.bind(this, proc, number)); - })(proc, number); - } - - function rmProcs(procs, value, cb) { - var i = 0; - - (function ex(procs, number) { - if (number++ === 0) return cb(); - that._operate('deleteProcessId', procs[i++].pm2_env.pm_id, ex.bind(this, procs, number)); - })(procs, number); - } - - function end() { - return cb ? cb(null, {success:true}) : that.speedList(); - } - - this.Client.getProcessByName(app_name, function(err, procs) { - if (err) { - Common.printError(err); - return cb ? cb(Common.retErr(err)) : that.exitCli(conf.ERROR_EXIT); - } - - if (!procs || procs.length === 0) { - Common.printError(conf.PREFIX_MSG_ERR + 'Application %s not found', app_name); - return cb ? cb(new Error('App not found')) : that.exitCli(conf.ERROR_EXIT); - } - - var proc_number = procs.length; - - if (typeof(number) === 'string' && number.indexOf('+') >= 0) { - number = parseInt(number, 10); - return addProcs(procs[0], number, end); - } - else if (typeof(number) === 'string' && number.indexOf('-') >= 0) { - number = parseInt(number, 10); - return rmProcs(procs[0], number, end); - } - else { - number = parseInt(number, 10); - number = number - proc_number; - - if (number < 0) - return rmProcs(procs, number, end); - else if (number > 0) - return addProcs(procs[0], number, end); - else { - Common.printError(conf.PREFIX_MSG_ERR + 'Nothing to do'); - return cb ? cb(new Error('Same process number')) : that.exitCli(conf.ERROR_EXIT); - } - } - }); -}; - -/** - * Description - * @method describeProcess - * @param {} pm2_id - * @return - */ -API.prototype.describe = function(pm2_id, cb) { - var that = this; - - var found_proc = []; - - that.Client.executeRemote('getMonitorData', {}, function(err, list) { - if (err) { - Common.printError('Error retrieving process list: ' + err); - that.exitCli(conf.ERROR_EXIT); - } - - list.forEach(function(proc) { - if ((!isNaN(pm2_id) && proc.pm_id == pm2_id) || - (typeof(pm2_id) === 'string' && proc.name == pm2_id)) { - found_proc.push(proc); - } - }); - - if (found_proc.length === 0) { - Common.printError(conf.PREFIX_MSG_WARNING + '%s doesn\'t exist', pm2_id); - return cb ? cb(null, []) : that.exitCli(conf.ERROR_EXIT); - } - - if (!cb) { - found_proc.forEach(function(proc) { - UX.describeTable(proc); - }); - } - - return cb ? cb(null, found_proc) : that.exitCli(conf.SUCCESS_EXIT); - }); -}; - -/** - * API method to perform a deep update of PM2 - * @method deepUpdate - */ -API.prototype.deepUpdate = function(cb) { - var that = this; - - Common.printOut(conf.PREFIX_MSG + 'Updating PM2...'); - - var exec = require('shelljs').exec; - var child = exec("npm i -g pm2@latest; pm2 update", {async : true}); - - child.stdout.on('end', function() { - Common.printOut(conf.PREFIX_MSG + 'PM2 successfully updated'); - cb ? cb(null, {success:true}) : that.exitCli(conf.SUCCESS_EXIT); - }); -}; module.exports = API; From 0cab8880ffa362cf27ab7d7b6a64d6b478dce7cd Mon Sep 17 00:00:00 2001 From: vince Date: Tue, 27 Feb 2018 12:28:43 +0100 Subject: [PATCH 017/140] refactor: drop some 0.x patch --- lib/API.js | 30 +++++------------------------- 1 file changed, 5 insertions(+), 25 deletions(-) diff --git a/lib/API.js b/lib/API.js index c42cf837..7c7b997b 100644 --- a/lib/API.js +++ b/lib/API.js @@ -185,22 +185,10 @@ class API { if (that.pm2_home.indexOf('.pm2') > -1) return cb(new Error('Destroy is not a allowed method on .pm2')); - if (fs.accessSync) { - fs.access(test_path, fs.R_OK, function(err) { - if (err) return cb(err); - debug('Deleting temporary folder %s', that.pm2_home); - exec(cmd, cb); - }); - return false; - } - - // Support for Node 0.10 - fs.exists(test_path, function(exist) { - if (exist) { - debug('Deleting temporary folder %s', that.pm2_home); - exec(cmd, cb); - } - return cb(null); + fs.access(test_path, fs.R_OK, function(err) { + if (err) return cb(err); + debug('Deleting temporary folder %s', that.pm2_home); + exec(cmd, cb); }); }); } @@ -858,15 +846,7 @@ class API { } else { var data = null; - var isAbsolute = false - - //node 0.11 compatibility #2815 - if (typeof path.isAbsolute === 'function') { - isAbsolute = path.isAbsolute(file) - } else { - isAbsolute = require('./tools/IsAbsolute.js')(file) - } - + var isAbsolute = path.isAbsolute(file) var file_path = isAbsolute ? file : path.join(that.cwd, file); debug('Resolved filepath %s', file_path); From 6da48a4362c7edd6ac36b04f5a52abeab613b72c Mon Sep 17 00:00:00 2001 From: Unitech Date: Tue, 27 Feb 2018 15:44:03 +0100 Subject: [PATCH 018/140] e2e: fix dump --- test/e2e/cli/dump.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/e2e/cli/dump.sh b/test/e2e/cli/dump.sh index 3f9a9973..62ed1a58 100644 --- a/test/e2e/cli/dump.sh +++ b/test/e2e/cli/dump.sh @@ -1,7 +1,7 @@ #!/usr/bin/env bash SRC=$(cd $(dirname "$0"); pwd) -source "${SRC}/include.sh" +source "${SRC}/../include.sh" cd $file_path $pm2 start echo.js -i 4 From 047aa494d5c4dd4342915766b54d673db0d5cdf1 Mon Sep 17 00:00:00 2001 From: vince Date: Tue, 27 Feb 2018 15:47:37 +0100 Subject: [PATCH 019/140] refactor: change safety var to const --- lib/API.js | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/lib/API.js b/lib/API.js index 7c7b997b..60c69380 100644 --- a/lib/API.js +++ b/lib/API.js @@ -4,14 +4,14 @@ * can be found in the LICENSE file. */ -var commander = require('commander'); -var fs = require('fs'); -var path = require('path'); -var async = require('async'); -var debug = require('debug')('pm2:cli'); -var util = require('util'); -var chalk = require('chalk'); -var fclone = require('fclone'); +const commander = require('commander'); +const fs = require('fs'); +const path = require('path'); +const async = require('async'); +const debug = require('debug')('pm2:cli'); +const util = require('util'); +const chalk = require('chalk'); +const fclone = require('fclone'); var conf = require('../constants.js'); var Client = require('./Client'); @@ -49,7 +49,7 @@ class API { constructor (opts) { if (!opts) opts = {}; - var that = this; + const that = this; this.daemon_mode = typeof(opts.daemon_mode) == 'undefined' ? true : opts.daemon_mode; this.pm2_home = conf.PM2_ROOT_PATH; @@ -78,8 +78,8 @@ class API { } else if (opts.independent == true && conf.IS_WINDOWS === false) { // Create an unique pm2 instance - var crypto = require('crypto'); - var random_file = crypto.randomBytes(8).toString('hex'); + const crypto = require('crypto'); + const random_file = crypto.randomBytes(8).toString('hex'); this.pm2_home = path.join('/tmp', random_file); // If we dont explicitly tell to have a daemon @@ -111,7 +111,7 @@ class API { this.gl_is_km_linked = false; try { - var pid = fs.readFileSync(conf.INTERACTOR_PID_PATH); + const pid = fs.readFileSync(conf.INTERACTOR_PID_PATH); pid = parseInt(pid.toString().trim()); process.kill(pid, 0); that.gl_is_km_linked = true; From 6d8f0dfae8106deb2fee0a7ae15b6ca9802a066d Mon Sep 17 00:00:00 2001 From: vince Date: Tue, 27 Feb 2018 16:15:41 +0100 Subject: [PATCH 020/140] refactor: create alias method instead of modify prototype --- lib/API.js | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/lib/API.js b/lib/API.js index 60c69380..0c9519fd 100644 --- a/lib/API.js +++ b/lib/API.js @@ -210,6 +210,14 @@ class API { }); }; + /** + * Alias on disconnect + * @param cb + */ + close (cb) { + this.disconnect(cb); + } + /** * Launch modules * @@ -617,6 +625,10 @@ class API { }); } + kill (cb) { + this.killDaemon(cb); + } + ///////////////////// // Private methods // ///////////////////// @@ -1653,9 +1665,6 @@ class API { } }; -API.prototype.close = API.prototype.disconnect; -API.prototype.kill = API.prototype.killDaemon; - ////////////////////////// // Load all API methods // From d322dd00de0f527224c027b4fec5e86f12fd69ed Mon Sep 17 00:00:00 2001 From: vince Date: Tue, 27 Feb 2018 16:53:40 +0100 Subject: [PATCH 021/140] refactor: add node 4.x support --- lib/API.js | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/API.js b/lib/API.js index 0c9519fd..d950d1b0 100644 --- a/lib/API.js +++ b/lib/API.js @@ -3,6 +3,7 @@ * Use of this source code is governed by a license that * can be found in the LICENSE file. */ +'use strict'; const commander = require('commander'); const fs = require('fs'); From bb57c76d4191343925013d4353299092d80732c9 Mon Sep 17 00:00:00 2001 From: vince Date: Wed, 28 Feb 2018 18:39:40 +0100 Subject: [PATCH 022/140] refactor: drop gracefullreload --- README.md | 1 - bin/pm2 | 11 +------ examples/misc-examples/graceful-exit.js | 2 +- examples/sourcemap-auto-resolve/API.js | 27 ----------------- lib/API.js | 27 ----------------- lib/API/Version.js | 10 ------- lib/God/Reload.js | 2 +- lib/Interactor/RemoteActions/Pm2Actions.js | 1 - test/bash/app-config-update.sh | 11 +------ test/bash/gracefulReload.sh | 35 ---------------------- test/bash/gracefulReload2.sh | 28 ----------------- test/bash/gracefulReload3.sh | 22 -------------- test/bash/json-file.sh | 7 +---- test/bash/reload.sh | 2 -- test/fixtures/graceful-exit-no-listen.js | 2 +- test/fixtures/graceful-exit-send.js | 2 +- test/fixtures/graceful-exit.js | 2 +- test/interface/remote.mocha.js | 24 --------------- test/pm2_behavior_tests.sh | 6 ---- test/programmatic/signals.js | 15 ---------- 20 files changed, 8 insertions(+), 229 deletions(-) delete mode 100644 test/bash/gracefulReload.sh delete mode 100644 test/bash/gracefulReload2.sh delete mode 100644 test/bash/gracefulReload3.sh diff --git a/README.md b/README.md index 1ef3279a..21a9dc85 100644 --- a/README.md +++ b/README.md @@ -293,7 +293,6 @@ $ pm2 reset [app-name] # Reset all counters $ pm2 stop all # Stop all apps $ pm2 stop 0 # Stop process with id 0 $ pm2 restart all # Restart all apps -$ pm2 gracefulReload all # Gracefully reload all apps in cluster mode $ pm2 delete all # Kill and delete all apps $ pm2 delete 0 # Delete app with id 0 diff --git a/bin/pm2 b/bin/pm2 index 05072f4b..809177b0 100755 --- a/bin/pm2 +++ b/bin/pm2 @@ -155,7 +155,7 @@ function checkCompletion(){ return data.short; }), data); // array containing commands after which process name should be listed - var cmdProcess = ['stop', 'restart', 'scale', 'reload', 'gracefulReload', 'delete', 'reset', 'pull', 'forward', 'backward', 'logs', 'describe', 'desc', 'show']; + var cmdProcess = ['stop', 'restart', 'scale', 'reload', 'delete', 'reset', 'pull', 'forward', 'backward', 'logs', 'describe', 'desc', 'show']; if (cmdProcess.indexOf(data.prev) > -1) { pm2.list(function(err, list){ @@ -390,15 +390,6 @@ commander.command('reload ') pm2.reload(pm2_id, commander); }); -// -// Reload process(es) -// -commander.command('gracefulReload ') - .description('gracefully reload a process. Send a "shutdown" message to close all connections.') - .action(function(pm2_id) { - pm2.gracefulReload(pm2_id, commander); - }); - commander.command('id ') .description('get process id by name') .action(function(name) { diff --git a/examples/misc-examples/graceful-exit.js b/examples/misc-examples/graceful-exit.js index df593d44..a35fc3e8 100644 --- a/examples/misc-examples/graceful-exit.js +++ b/examples/misc-examples/graceful-exit.js @@ -2,7 +2,7 @@ /* * Example of graceful exit * - * $ pm2 gracefulReload all + * $ pm2 reload all */ process.on('message', function(msg) { diff --git a/examples/sourcemap-auto-resolve/API.js b/examples/sourcemap-auto-resolve/API.js index ed62bdec..54413879 100644 --- a/examples/sourcemap-auto-resolve/API.js +++ b/examples/sourcemap-auto-resolve/API.js @@ -399,33 +399,6 @@ API.prototype.update = function(cb) { return false; }; -/** - * Graceful Reload an application - * - * @param {String} process_name Application Name or All - * @param {Object} opts Options - * @param {Function} cb Callback - */ -API.prototype.gracefulReload = function(process_name, opts, cb) { - var that = this; - - if (typeof(opts) == "function") { - cb = opts; - opts = {}; - } - - //Common.printOut(conf.PREFIX_MSG_WARNING + chalk.bold.yellow('Warning gracefulReload will be soon deprecated')); - //Common.printOut(conf.PREFIX_MSG_WARNING + chalk.bold.yellow('Use http://pm2.keymetrics.io/docs/usage/signals-clean-restart/ instead')); - - if (Common.isConfigFile(process_name)) - that._startJson(process_name, commander, 'softReloadProcessId'); - else { - if (opts && !opts.updateEnv) - Common.printOut(IMMUTABLE_MSG); - that._operate('softReloadProcessId', process_name, opts, cb); - } -}; - /** * Reload an application * diff --git a/lib/API.js b/lib/API.js index d950d1b0..0296c2d3 100644 --- a/lib/API.js +++ b/lib/API.js @@ -402,33 +402,6 @@ class API { return false; } - /** - * Graceful Reload an application - * - * @param {String} process_name Application Name or All - * @param {Object} opts Options - * @param {Function} cb Callback - */ - gracefulReload (process_name, opts, cb) { - var that = this; - - if (typeof(opts) == "function") { - cb = opts; - opts = {}; - } - - //Common.printOut(conf.PREFIX_MSG_WARNING + chalk.bold.yellow('Warning gracefulReload will be soon deprecated')); - //Common.printOut(conf.PREFIX_MSG_WARNING + chalk.bold.yellow('Use http://pm2.keymetrics.io/docs/usage/signals-clean-restart/ instead')); - - if (Common.isConfigFile(process_name)) - that._startJson(process_name, commander, 'softReloadProcessId'); - else { - if (opts && !opts.updateEnv) - Common.printOut(IMMUTABLE_MSG); - that._operate('softReloadProcessId', process_name, opts, cb); - } - } - /** * Reload an application * diff --git a/lib/API/Version.js b/lib/API/Version.js index 8f5bb93b..a32de64f 100644 --- a/lib/API/Version.js +++ b/lib/API/Version.js @@ -366,16 +366,6 @@ module.exports = function(CLI) { this._pull({process_name: process_name, action: 'reload'}, cb); }; - /** - * CLI method for updating a repository - * @method pullAndGracefulReload - * @param {string} process_name name of processes to pull - * @return - */ - CLI.prototype.pullAndGracefulReload = function (process_name, cb) { - this._pull({process_name: process_name, action: 'gracefulReload'}, cb); - }; - /** * CLI method for updating a repository to a specific commit id * @method pullCommitId diff --git a/lib/God/Reload.js b/lib/God/Reload.js index d55cad1c..5472f3b4 100644 --- a/lib/God/Reload.js +++ b/lib/God/Reload.js @@ -174,7 +174,7 @@ function hardReload(God, id, wait_msg, cb) { module.exports = function(God) { /** - * GracefulReload + * Reload * @method softReloadProcessId * @param {} id * @param {} cb diff --git a/lib/Interactor/RemoteActions/Pm2Actions.js b/lib/Interactor/RemoteActions/Pm2Actions.js index a6de7c61..b5edd93b 100644 --- a/lib/Interactor/RemoteActions/Pm2Actions.js +++ b/lib/Interactor/RemoteActions/Pm2Actions.js @@ -21,7 +21,6 @@ var Password = require('../Password.js'); var PM2_REMOTE_METHOD_ALLOWED = { 'restart' : {}, 'reload' : {}, - 'gracefulReload' : {}, 'reset' : {}, 'scale' : {}, diff --git a/test/bash/app-config-update.sh b/test/bash/app-config-update.sh index 8ef0a532..1807110e 100644 --- a/test/bash/app-config-update.sh +++ b/test/bash/app-config-update.sh @@ -58,14 +58,10 @@ $pm2 reload app-config-update/echo.js --node-args="--harmony" $pm2 prettylist | grep "node_args: \[ '--harmony' \]" spec "Should application have one node argument" -$pm2 gracefulReload app-config-update/echo.js --node-args="--harmony" -$pm2 prettylist | grep "node_args: \[ '--harmony' \]" -spec "Should application have two node arguments" - $pm2 prettylist | grep "node_args" spec "Should have found parameter" # Now set node-args to null -$pm2 gracefulReload app-config-update/echo.js --node-args=null +$pm2 reload app-config-update/echo.js --node-args=null # Should not find node_args anymore $pm2 prettylist | grep "node_args" ispec "Should have deleted cli parameter when passing null" @@ -74,8 +70,3 @@ $pm2 reload echo --name="new-name" $pm2 reset all $pm2 restart new-name should 'should reload processes with new name' 'restart_time: 1' 1 - -$pm2 gracefulReload new-name --name="new-name-2" -$pm2 reset all -$pm2 restart new-name-2 -should 'should graceful reload processes with new name' 'restart_time: 1' 1 diff --git a/test/bash/gracefulReload.sh b/test/bash/gracefulReload.sh deleted file mode 100644 index e7ed9fce..00000000 --- a/test/bash/gracefulReload.sh +++ /dev/null @@ -1,35 +0,0 @@ -#!/usr/bin/env bash - -SRC=$(cd $(dirname "$0"); pwd) -source "${SRC}/include.sh" - -cd $file_path - -echo "################## GRACEFUL RELOAD ###################" - -############### - -echo "Launching" -$pm2 start graceful-exit.js -i 4 --name="graceful" -o "grace.log" -e "grace-err.log" -should 'should start processes' 'online' 4 - -OUT_LOG=`$pm2 prettylist | grep -m 1 -E "pm_out_log_path:" | sed "s/.*'\([^']*\)',/\1/"` -cat /dev/null > $OUT_LOG - -#### Graceful reload all - -$pm2 gracefulReload all - -OUT=`grep "Finished closing connections" "$OUT_LOG" | wc -l` -[ $OUT -eq 1 ] || fail "Process not restarted gracefuly" -success "Process restarted gracefuly" - - -cat /dev/null > $OUT_LOG - -#### Graceful reload name -$pm2 gracefulReload graceful - -OUT=`grep "Finished closing connections" "$OUT_LOG" | wc -l` -[ $OUT -eq 1 ] || fail "Process not restarted gracefuly" -success "Process restarted gracefuly" diff --git a/test/bash/gracefulReload2.sh b/test/bash/gracefulReload2.sh deleted file mode 100644 index b7c25fdd..00000000 --- a/test/bash/gracefulReload2.sh +++ /dev/null @@ -1,28 +0,0 @@ -#!/usr/bin/env bash - -SRC=$(cd $(dirname "$0"); pwd) -source "${SRC}/include.sh" - -cd $file_path - -echo "################## GRACEFUL RELOAD 2 ###################" - -echo "Launching" -$pm2 start graceful-exit-no-listen.js -i 2 --name="graceful2" -o "grace2.log" -e "grace-err2.log" -should 'should start processes' 'online' 2 - -OUT_LOG=`$pm2 prettylist | grep -m 1 -E "pm_out_log_path:" | sed "s/.*'\([^']*\)',/\1/"` -cat /dev/null > $OUT_LOG - -#### Graceful reload name -$pm2 gracefulReload graceful2 - -echo "PATH: $OUT_LOG" - -TEXT=$(cat $OUT_LOG) - -echo "TEXT: $TEXT" - -OUT=`grep "Finished closing connections" "$OUT_LOG" | wc -l` -[ $OUT -eq 1 ] || fail "Non-listening process not restarted gracefuly" -success "Non-listening process restarted gracefuly" diff --git a/test/bash/gracefulReload3.sh b/test/bash/gracefulReload3.sh deleted file mode 100644 index 307d74f6..00000000 --- a/test/bash/gracefulReload3.sh +++ /dev/null @@ -1,22 +0,0 @@ -#!/usr/bin/env bash - -SRC=$(cd $(dirname "$0"); pwd) -source "${SRC}/include.sh" - -cd $file_path - -echo "################## GRACEFUL RELOAD 3 ###################" - -echo "Launching" -$pm2 start graceful-exit-send.js -i 2 --name="graceful3" -o "grace3.log" -e "grace-err3.log" -should 'should start processes' 'online' 2 - -OUT_LOG=`$pm2 prettylist | grep -m 1 -E "pm_out_log_path:" | sed "s/.*'\([^']*\)',/\1/"` -cat /dev/null > $OUT_LOG - -#### Graceful reload name -$pm2 gracefulReload graceful3 - -OUT=`grep "Finished closing connections" "$OUT_LOG" | wc -l` -[ $OUT -eq 1 ] || fail "Process that sends 'online' not restarted gracefuly" -success "Process that sends 'online' restarted gracefuly" diff --git a/test/bash/json-file.sh b/test/bash/json-file.sh index 50c3ff35..08ce5543 100644 --- a/test/bash/json-file.sh +++ b/test/bash/json-file.sh @@ -36,18 +36,13 @@ sleep 1 should 'should reload processes' 'online' 6 should 'should all script been restarted one time' 'restart_time: 2' 6 -$pm2 gracefulReload all.json -sleep 1 -should 'should graceful reload processes' 'online' 6 -should 'should all script been restarted one time' 'restart_time: 3' 6 - ## ## Smart restart ## $pm2 start all.json sleep 1 should 'should smart restart processes' 'online' 6 -should 'should all script been restarted one time' 'restart_time: 4' 6 +should 'should all script been restarted one time' 'restart_time: 3' 6 $pm2 stop all.json sleep 1 diff --git a/test/bash/reload.sh b/test/bash/reload.sh index d659a1b6..88ad9416 100644 --- a/test/bash/reload.sh +++ b/test/bash/reload.sh @@ -50,8 +50,6 @@ $pm2 restart delayed_exit.js should 'should restart processes' 'restart_time: 1' 2 $pm2 reload delayed_exit.js should 'should restart processes' 'restart_time: 2' 2 -$pm2 gracefulReload delayed_exit.js -should 'should restart processes' 'restart_time: 3' 2 $pm2 kill $pm2 start child.js -i 4 diff --git a/test/fixtures/graceful-exit-no-listen.js b/test/fixtures/graceful-exit-no-listen.js index 37cfba2d..814d3845 100644 --- a/test/fixtures/graceful-exit-no-listen.js +++ b/test/fixtures/graceful-exit-no-listen.js @@ -2,7 +2,7 @@ /* * Example of graceful exit that does not listen * - * $ pm2 gracefulReload all + * $ pm2 reload all */ process.on('message', function(msg) { diff --git a/test/fixtures/graceful-exit-send.js b/test/fixtures/graceful-exit-send.js index 7142c3f5..94d461f0 100644 --- a/test/fixtures/graceful-exit-send.js +++ b/test/fixtures/graceful-exit-send.js @@ -2,7 +2,7 @@ /* * Example of graceful exit that does not listen but sends 'online' * - * $ pm2 gracefulReload all + * $ pm2 reload all */ process.on('message', function(msg) { diff --git a/test/fixtures/graceful-exit.js b/test/fixtures/graceful-exit.js index 43e8212a..5b1461a1 100644 --- a/test/fixtures/graceful-exit.js +++ b/test/fixtures/graceful-exit.js @@ -2,7 +2,7 @@ /* * Example of graceful exit * - * $ pm2 gracefulReload all + * $ pm2 reload all */ process.on('message', function(msg) { diff --git a/test/interface/remote.mocha.js b/test/interface/remote.mocha.js index d1ded5a1..87adbcd4 100644 --- a/test/interface/remote.mocha.js +++ b/test/interface/remote.mocha.js @@ -145,30 +145,6 @@ describe('REMOTE PM2 ACTIONS', function() { }); }); - it('should gracefulRELOAD', function(done) { - send_cmd.once('trigger:pm2:result', function(pck) { - /** - * Once remote command is finished... - */ - - should(pck.ret.err).be.null(); - - pm2.list(function(err, ret) { - ret.forEach(function(proc) { - proc.pm2_env.restart_time.should.eql(3); - }); - }); - - done(); - }); - - send_cmd.emit('cmd', { - _type : 'trigger:pm2:action', - method_name : 'gracefulReload', - parameters : {name : 'child' } - }); - }); - it('should RESET metadata', function(done) { send_cmd.once('trigger:pm2:result', function(pck) { /** diff --git a/test/pm2_behavior_tests.sh b/test/pm2_behavior_tests.sh index 6b1fa630..9d212a11 100644 --- a/test/pm2_behavior_tests.sh +++ b/test/pm2_behavior_tests.sh @@ -81,12 +81,6 @@ bash ./test/bash/right-exit-code.sh spec "Verification exit code" bash ./test/bash/log-reload.sh spec "Log reload" -bash ./test/bash/gracefulReload.sh -spec "gracefulReload system 1" -bash ./test/bash/gracefulReload2.sh -spec "gracefulReload system 2" -bash ./test/bash/gracefulReload3.sh -spec "gracefulReload system 3" bash ./test/bash/misc.sh spec "MISC features" bash ./test/bash/fork.sh diff --git a/test/programmatic/signals.js b/test/programmatic/signals.js index 6c9c93b3..fad65206 100644 --- a/test/programmatic/signals.js +++ b/test/programmatic/signals.js @@ -162,21 +162,6 @@ describe('Signal kill (+delayed)', function() { }); }); - - it('should graceful reload script', function(done) { - setTimeout(function() { - pm2.list(function(err, list) { - list[0].pm2_env.status.should.eql('online'); - list[0].pm2_env.restart_time.should.eql(2); - done(); - }); - }, 1500); - - pm2.gracefulReload('delayed-sigint', function(err, app) { - //done(err); - }); - - }); }); describe('with 4000ms via kill_timeout (json/cli option)', function() { From fadf82a95e0adaa097c82599ed5092c0f1cc81d1 Mon Sep 17 00:00:00 2001 From: Chang Wang Date: Thu, 1 Mar 2018 21:39:54 -0500 Subject: [PATCH 023/140] Update downloads badge to point to graph of downloads --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 1ef3279a..38652709 100644 --- a/README.md +++ b/README.md @@ -13,7 +13,7 @@ npm version - + NPM Downloads From f2523f6a6b9d8b61ba6ace7b89a0353bee76360b Mon Sep 17 00:00:00 2001 From: vince Date: Fri, 2 Mar 2018 10:22:23 +0100 Subject: [PATCH 024/140] fix: #3485 fix issue when there is empty dump file --- lib/API/Startup.js | 26 +++++++++++++++++++++----- lib/God/ActionMethods.js | 19 ++++++++++++++----- 2 files changed, 35 insertions(+), 10 deletions(-) diff --git a/lib/API/Startup.js b/lib/API/Startup.js index 5249acc5..5be3e3d6 100644 --- a/lib/API/Startup.js +++ b/lib/API/Startup.js @@ -371,13 +371,26 @@ module.exports = function(CLI) { * @return */ function fin(err) { + + // try to fix issues with empty dump file + // like #3485 + if (env_arr.length === 0) { + // if no process in list don't modify dump file + // process list should not be empty + if(cb) { + return cb(null, {success: true}); + } else { + Common.printOut(cst.PREFIX_MSG + 'Nothing to save !!!'); + Common.printOut(cst.PREFIX_MSG + 'In this case we keep old dump file. To clear dump file you can delete it manually !'); + that.exitCli(cst.SUCCESS_EXIT); + return; + } + } + // Back up dump file try { if (fs.existsSync(cst.DUMP_FILE_PATH)) { - if (fs.existsSync(cst.DUMP_BACKUP_FILE_PATH)) { - fs.unlinkSync(cst.DUMP_BACKUP_FILE_PATH); - } - fs.renameSync(cst.DUMP_FILE_PATH, cst.DUMP_BACKUP_FILE_PATH); + fs.copyFileSync(cst.DUMP_FILE_PATH, cst.DUMP_BACKUP_FILE_PATH); } } catch (e) { console.error(e.stack || e); @@ -390,8 +403,11 @@ module.exports = function(CLI) { } catch (e) { console.error(e.stack || e); try { - fs.unlinkSync(cst.DUMP_FILE_PATH); + // try to backup file + fs.copyFileSync(cst.DUMP_BACKUP_FILE_PATH, cst.DUMP_FILE_PATH); } catch (e) { + // don't keep broken file + fs.unlinkSync(cst.DUMP_FILE_PATH); console.error(e.stack || e); } Common.printOut(cst.PREFIX_MSG_ERR + 'Failed to save dump file in %s', cst.DUMP_FILE_PATH); diff --git a/lib/God/ActionMethods.js b/lib/God/ActionMethods.js index 65cb6415..6b577d69 100644 --- a/lib/God/ActionMethods.js +++ b/lib/God/ActionMethods.js @@ -137,13 +137,19 @@ module.exports = function(God) { } function fin(err) { + + // try to fix issues with empty dump file + // like #3485 + if (process_list.length === 0) { + // if no process in list don't modify dump file + // process list should not be empty + return cb(null, {success:true, process_list: process_list}); + } + // Back up dump file try { if (fs.existsSync(cst.DUMP_FILE_PATH)) { - if (fs.existsSync(cst.DUMP_BACKUP_FILE_PATH)) { - fs.unlinkSync(cst.DUMP_BACKUP_FILE_PATH); - } - fs.renameSync(cst.DUMP_FILE_PATH, cst.DUMP_BACKUP_FILE_PATH); + fs.copyFileSync(cst.DUMP_FILE_PATH, cst.DUMP_BACKUP_FILE_PATH); } } catch (e) { console.error(e.stack || e); @@ -155,8 +161,11 @@ module.exports = function(God) { } catch (e) { console.error(e.stack || e); try { - fs.unlinkSync(cst.DUMP_FILE_PATH); + // try to backup file + fs.copyFileSync(cst.DUMP_BACKUP_FILE_PATH, cst.DUMP_FILE_PATH); } catch (e) { + // don't keep broken file + fs.unlinkSync(cst.DUMP_FILE_PATH); console.error(e.stack || e); } } From ced2835d2100dc7f5162295f7b51335374855495 Mon Sep 17 00:00:00 2001 From: vince Date: Fri, 2 Mar 2018 12:18:54 +0100 Subject: [PATCH 025/140] feature: #3485 add cleardump command --- bin/pm2 | 9 +++++++++ lib/API/Startup.js | 19 ++++++++++++++++++- lib/God/ActionMethods.js | 4 +++- test/programmatic/programmatic.js | 7 ++++++- 4 files changed, 36 insertions(+), 3 deletions(-) diff --git a/bin/pm2 b/bin/pm2 index 05072f4b..3099bba4 100755 --- a/bin/pm2 +++ b/bin/pm2 @@ -612,6 +612,15 @@ commander.command('dump') pm2.dump(); })); +// +// Delete dump file +// +commander.command('cleardump') + .description('Create empty dump file') + .action(failOnUnknown(function() { + pm2.clearDump(); + })); + // // Save processes to file // diff --git a/lib/API/Startup.js b/lib/API/Startup.js index 5be3e3d6..3064e6a6 100644 --- a/lib/API/Startup.js +++ b/lib/API/Startup.js @@ -404,7 +404,9 @@ module.exports = function(CLI) { console.error(e.stack || e); try { // try to backup file - fs.copyFileSync(cst.DUMP_BACKUP_FILE_PATH, cst.DUMP_FILE_PATH); + if(fs.existsSync(cst.DUMP_BACKUP_FILE_PATH)) { + fs.copyFileSync(cst.DUMP_BACKUP_FILE_PATH, cst.DUMP_FILE_PATH); + } } catch (e) { // don't keep broken file fs.unlinkSync(cst.DUMP_FILE_PATH); @@ -431,6 +433,21 @@ module.exports = function(CLI) { }); }; + /** + * Remove DUMP_FILE_PATH file and DUMP_BACKUP_FILE_PATH file + * @method dump + * @param {} cb + * @return + */ + CLI.prototype.clearDump = function(cb) { + fs.writeFileSync(cst.DUMP_FILE_PATH, JSON.stringify([])); + + if(cb && typeof cb === 'function') return cb(); + + Common.printOut(cst.PREFIX_MSG + 'Successfully created %s', cst.DUMP_FILE_PATH); + return this.exitCli(cst.SUCCESS_EXIT); + }; + /** * Resurrect processes * @method resurrect diff --git a/lib/God/ActionMethods.js b/lib/God/ActionMethods.js index 6b577d69..37a6255c 100644 --- a/lib/God/ActionMethods.js +++ b/lib/God/ActionMethods.js @@ -162,7 +162,9 @@ module.exports = function(God) { console.error(e.stack || e); try { // try to backup file - fs.copyFileSync(cst.DUMP_BACKUP_FILE_PATH, cst.DUMP_FILE_PATH); + if(fs.existsSync(cst.DUMP_BACKUP_FILE_PATH)) { + fs.copyFileSync(cst.DUMP_BACKUP_FILE_PATH, cst.DUMP_FILE_PATH); + } } catch (e) { // don't keep broken file fs.unlinkSync(cst.DUMP_FILE_PATH); diff --git a/test/programmatic/programmatic.js b/test/programmatic/programmatic.js index e71f0aec..478e1361 100644 --- a/test/programmatic/programmatic.js +++ b/test/programmatic/programmatic.js @@ -18,7 +18,12 @@ describe('PM2 programmatic calls', function() { }); after(function(done) { - pm2.kill(done); + pm2.delete('all', function(err, ret) { + // clean dump file + pm2.clearDump(function(err) { + pm2.kill(done); + }); + }); }); before(function(done) { From 8951184688c720ded5b4b46bd5b393c3793f9b03 Mon Sep 17 00:00:00 2001 From: vince Date: Fri, 2 Mar 2018 15:25:15 +0100 Subject: [PATCH 026/140] fix: solve empty list when no process and try to update pm2 --- lib/API/Startup.js | 6 ++++++ lib/God/ActionMethods.js | 6 ++++++ 2 files changed, 12 insertions(+) diff --git a/lib/API/Startup.js b/lib/API/Startup.js index 3064e6a6..f77ca516 100644 --- a/lib/API/Startup.js +++ b/lib/API/Startup.js @@ -375,6 +375,12 @@ module.exports = function(CLI) { // try to fix issues with empty dump file // like #3485 if (env_arr.length === 0) { + + // fix : if no dump file, no process, only module and after pm2 update + if (!fs.existsSync(cst.DUMP_FILE_PATH)) { + that.clearDump(function(){}); + } + // if no process in list don't modify dump file // process list should not be empty if(cb) { diff --git a/lib/God/ActionMethods.js b/lib/God/ActionMethods.js index 37a6255c..1df6b159 100644 --- a/lib/God/ActionMethods.js +++ b/lib/God/ActionMethods.js @@ -141,6 +141,12 @@ module.exports = function(God) { // try to fix issues with empty dump file // like #3485 if (process_list.length === 0) { + + // fix : if no dump file, no process, only module and after pm2 update + if (!fs.existsSync(cst.DUMP_FILE_PATH)) { + that.clearDump(function(){}); + } + // if no process in list don't modify dump file // process list should not be empty return cb(null, {success:true, process_list: process_list}); From 39f242985b7d0886a1f99f3dbe7a9145d60e66fe Mon Sep 17 00:00:00 2001 From: vince Date: Fri, 2 Mar 2018 17:18:23 +0100 Subject: [PATCH 027/140] feature: add inspect feature, on runtime --- bin/pm2 | 7 +++++++ lib/API/Extra.js | 20 +++++++++++++++++++- lib/ProcessContainerFork.js | 20 ++++++++++++++++++-- 3 files changed, 44 insertions(+), 3 deletions(-) diff --git a/bin/pm2 b/bin/pm2 index 809177b0..eebc8da6 100755 --- a/bin/pm2 +++ b/bin/pm2 @@ -396,6 +396,13 @@ commander.command('id ') pm2.getProcessIdByName(name); }); +// Inspect a process +commander.command('inspect ') + .description('inspect a process') + .action(function(cmd) { + pm2.inspect(cmd, commander); + }); + // // Stop and delete a process by name from database // diff --git a/lib/API/Extra.js b/lib/API/Extra.js index 00f445dd..6f70d549 100644 --- a/lib/API/Extra.js +++ b/lib/API/Extra.js @@ -15,6 +15,7 @@ var fs = require('fs'); var fmt = require('../tools/fmt.js'); var moment = require('moment'); var pkg = require('../../package.json'); +const semver = require('semver'); module.exports = function(CLI) { @@ -38,7 +39,6 @@ module.exports = function(CLI) { */ CLI.prototype.report = function() { var that = this; - var semver = require('semver'); function reporting(cb) { @@ -639,4 +639,22 @@ module.exports = function(CLI) { launchMonitor(); }; + + CLI.prototype.inspect = function(app_name, cb) { + const that = this; + if(semver.satisfies(process.versions.node, '>= 8.0.0')) { + this.trigger(app_name, 'internal:inspect', function (err, res) { + if(res[0].data.return === '') { + Common.printOut(`Inspect disabled on ${app_name}`); + } else { + Common.printOut(`Inspect enabled on ${app_name} => go to chrome : chrome://inspect !!!`); + } + + that.exitCli(cst.SUCCESS_EXIT); + }); + } else { + Common.printOut('Inspect is available for node version >=8.x !'); + that.exitCli(cst.SUCCESS_EXIT); + } + }; }; diff --git a/lib/ProcessContainerFork.js b/lib/ProcessContainerFork.js index 6d1b0ceb..189851e9 100644 --- a/lib/ProcessContainerFork.js +++ b/lib/ProcessContainerFork.js @@ -1,17 +1,33 @@ -/** + /** * Copyright 2013 the PM2 project authors. All rights reserved. * Use of this source code is governed by a license that * can be found in the LICENSE file. */ // Inject custom modules if (process.env.pmx !== 'false') { - require('pmx').init({ + const pmx = require('pmx'); + pmx.init({ transactions: (process.env.km_link === 'true' && (process.env.trace === 'true' || process.env.deep_monitoring === 'true')) || false, http: process.env.km_link === 'true' || false, v8: process.env.v8 === 'true' || process.env.deep_monitoring === 'true' || false, event_loop_dump: process.env.event_loop_inspector === 'true' || process.env.deep_monitoring === 'true' || false, deep_metrics: process.env.deep_monitoring === 'true' || false }); + + if(require('semver').satisfies(process.versions.node, '>= 8.0.0')) { + var url = ''; + pmx.action('internal:inspect', function(reply) { + const inspector = require('inspector'); + if(url === '') { + inspector.open(); + url = inspector.url(); + } else { + inspector.close(); + url = ''; + } + reply(url); + }); + } } if (typeof(process.env.source_map_support) != "undefined" && From 33d1fb3762840795db5921683806d6b62ff6dc8a Mon Sep 17 00:00:00 2001 From: vince Date: Fri, 2 Mar 2018 17:43:47 +0100 Subject: [PATCH 028/140] feature: add inspect feature, on runtime for cluster app --- lib/API/Extra.js | 2 +- lib/ProcessContainer.js | 10 +--------- lib/ProcessContainerFork.js | 26 +------------------------- lib/ProcessUtils.js | 29 +++++++++++++++++++++++++++++ 4 files changed, 32 insertions(+), 35 deletions(-) create mode 100644 lib/ProcessUtils.js diff --git a/lib/API/Extra.js b/lib/API/Extra.js index 6f70d549..60ced15d 100644 --- a/lib/API/Extra.js +++ b/lib/API/Extra.js @@ -644,7 +644,7 @@ module.exports = function(CLI) { const that = this; if(semver.satisfies(process.versions.node, '>= 8.0.0')) { this.trigger(app_name, 'internal:inspect', function (err, res) { - if(res[0].data.return === '') { + if(res && res[0].data.return === '') { Common.printOut(`Inspect disabled on ${app_name}`); } else { Common.printOut(`Inspect enabled on ${app_name} => go to chrome : chrome://inspect !!!`); diff --git a/lib/ProcessContainer.js b/lib/ProcessContainer.js index db9540dd..0d739bac 100644 --- a/lib/ProcessContainer.js +++ b/lib/ProcessContainer.js @@ -30,15 +30,7 @@ delete process.env.pm2_env; (function ProcessContainer() { var fs = require('fs'); - if (process.env.pmx !== 'false') { - require('pmx').init({ - transactions: (process.env.km_link === 'true' && (process.env.trace === 'true' || process.env.deep_monitoring === 'true')) || false, - http: process.env.km_link === 'true' || false, - v8: process.env.v8 === 'true' || process.env.deep_monitoring === 'true' || false, - event_loop_dump: process.env.event_loop_inspector === 'true' || process.env.deep_monitoring === 'true' || false, - deep_metrics: process.env.deep_monitoring === 'true' || false - }); - } + require('./ProcessUtils').injectModules(); var stdFile = pm2_env.pm_log_path; var outFile = pm2_env.pm_out_log_path; diff --git a/lib/ProcessContainerFork.js b/lib/ProcessContainerFork.js index 189851e9..59c45d3f 100644 --- a/lib/ProcessContainerFork.js +++ b/lib/ProcessContainerFork.js @@ -4,31 +4,7 @@ * can be found in the LICENSE file. */ // Inject custom modules -if (process.env.pmx !== 'false') { - const pmx = require('pmx'); - pmx.init({ - transactions: (process.env.km_link === 'true' && (process.env.trace === 'true' || process.env.deep_monitoring === 'true')) || false, - http: process.env.km_link === 'true' || false, - v8: process.env.v8 === 'true' || process.env.deep_monitoring === 'true' || false, - event_loop_dump: process.env.event_loop_inspector === 'true' || process.env.deep_monitoring === 'true' || false, - deep_metrics: process.env.deep_monitoring === 'true' || false - }); - - if(require('semver').satisfies(process.versions.node, '>= 8.0.0')) { - var url = ''; - pmx.action('internal:inspect', function(reply) { - const inspector = require('inspector'); - if(url === '') { - inspector.open(); - url = inspector.url(); - } else { - inspector.close(); - url = ''; - } - reply(url); - }); - } -} +require('./ProcessUtils').injectModules(); if (typeof(process.env.source_map_support) != "undefined" && process.env.source_map_support !== "false") { diff --git a/lib/ProcessUtils.js b/lib/ProcessUtils.js new file mode 100644 index 00000000..3e90117e --- /dev/null +++ b/lib/ProcessUtils.js @@ -0,0 +1,29 @@ +module.exports = { + injectModules: function() { + if (process.env.pmx !== 'false') { + const pmx = require('pmx'); + pmx.init({ + transactions: (process.env.km_link === 'true' && (process.env.trace === 'true' || process.env.deep_monitoring === 'true')) || false, + http: process.env.km_link === 'true' || false, + v8: process.env.v8 === 'true' || process.env.deep_monitoring === 'true' || false, + event_loop_dump: process.env.event_loop_inspector === 'true' || process.env.deep_monitoring === 'true' || false, + deep_metrics: process.env.deep_monitoring === 'true' || false + }); + + if(require('semver').satisfies(process.versions.node, '>= 8.0.0')) { + var url = ''; + pmx.action('internal:inspect', function(reply) { + const inspector = require('inspector'); + if(url === '') { + inspector.open(); + url = inspector.url(); + } else { + inspector.close(); + url = ''; + } + reply(url); + }); + } + } + } +}; From dacc654207cbe494af0d12a3f9f27c3b16541802 Mon Sep 17 00:00:00 2001 From: vince Date: Mon, 5 Mar 2018 10:49:32 +0100 Subject: [PATCH 029/140] fix: improve error message if action has failed --- lib/API/Extra.js | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/lib/API/Extra.js b/lib/API/Extra.js index 60ced15d..c6c057ec 100644 --- a/lib/API/Extra.js +++ b/lib/API/Extra.js @@ -644,10 +644,15 @@ module.exports = function(CLI) { const that = this; if(semver.satisfies(process.versions.node, '>= 8.0.0')) { this.trigger(app_name, 'internal:inspect', function (err, res) { - if(res && res[0].data.return === '') { - Common.printOut(`Inspect disabled on ${app_name}`); + + if(res && res[0]) { + if (res[0].data.return === '') { + Common.printOut(`Inspect disabled on ${app_name}`); + } else { + Common.printOut(`Inspect enabled on ${app_name} => go to chrome : chrome://inspect !!!`); + } } else { - Common.printOut(`Inspect enabled on ${app_name} => go to chrome : chrome://inspect !!!`); + Common.printOut(`Impossible to enabled inspect mode on ${app_name} !!!`); } that.exitCli(cst.SUCCESS_EXIT); From 5f78ecbf90f9f46a7feb2a169968e86b0ecac91e Mon Sep 17 00:00:00 2001 From: vince Date: Mon, 5 Mar 2018 11:14:11 +0100 Subject: [PATCH 030/140] chore: wording on error message --- lib/API/Extra.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/API/Extra.js b/lib/API/Extra.js index c6c057ec..cf7a23fc 100644 --- a/lib/API/Extra.js +++ b/lib/API/Extra.js @@ -652,7 +652,7 @@ module.exports = function(CLI) { Common.printOut(`Inspect enabled on ${app_name} => go to chrome : chrome://inspect !!!`); } } else { - Common.printOut(`Impossible to enabled inspect mode on ${app_name} !!!`); + Common.printOut(`Unable to activate inspect mode on ${app_name} !!!`); } that.exitCli(cst.SUCCESS_EXIT); From 97fd1010d005e59f2411042fa95891f9717fa8b7 Mon Sep 17 00:00:00 2001 From: vince Date: Mon, 5 Mar 2018 13:38:29 +0100 Subject: [PATCH 031/140] chore: fix issue with snapshot command + remove command forceGc --- bin/pm2 | 9 --------- lib/Daemon.js | 3 +-- lib/God/Methods.js | 17 ----------------- lib/Satan.js | 1 - 4 files changed, 1 insertion(+), 29 deletions(-) diff --git a/bin/pm2 b/bin/pm2 index 809177b0..55aeda64 100755 --- a/bin/pm2 +++ b/bin/pm2 @@ -882,15 +882,6 @@ commander.command('backward ') pm2.backward(pm2_name); }); -// -// Force PM2 to trigger garbage collection -// -commander.command('gc') - .description('force PM2 to trigger garbage collection') - .action(function() { - pm2.forceGc(); - }); - // // Perform a deep update of PM2 // diff --git a/lib/Daemon.js b/lib/Daemon.js index 26c9c98e..c1d7019f 100644 --- a/lib/Daemon.js +++ b/lib/Daemon.js @@ -153,7 +153,7 @@ Daemon.prototype.innerStart = function(cb) { var profiler; try { - profiler = require('v8-profiler'); + profiler = require('v8-profiler-node8'); } catch(e) { profiler = null; } @@ -231,7 +231,6 @@ Daemon.prototype.innerStart = function(cb) { notifyByProcessId : God.notifyByProcessId, notifyKillPM2 : God.notifyKillPM2, - forceGc : God.forceGc, monitor : God.monitor, unmonitor : God.unmonitor, diff --git a/lib/God/Methods.js b/lib/God/Methods.js index e7b8e9fa..ea6753a2 100644 --- a/lib/God/Methods.js +++ b/lib/God/Methods.js @@ -247,21 +247,4 @@ module.exports = function(God) { pm2_env.unstable_restarts = 0; }; - /** - * Description - * @method forcegc - * @return - */ - God.forceGc = function(opts, cb) { - if (global.gc) { - global.gc(); - debug('Garbage collection triggered successfully'); - if (cb) cb(null, {success: true}); - } - else { - debug('Garbage collection failed'); - if (cb) cb(null, {success: false}); - } - }; - }; diff --git a/lib/Satan.js b/lib/Satan.js index e6df06ba..1fc6651e 100644 --- a/lib/Satan.js +++ b/lib/Satan.js @@ -215,7 +215,6 @@ Satan.remoteWrapper = function() { killMe : God.killMe, notifyKillPM2 : God.notifyKillPM2, - forceGc : God.forceGc, findByFullPath : God.findByFullPath, From aae1d55e410c4dcfbbca83eaabbdf1a65d55f3aa Mon Sep 17 00:00:00 2001 From: vince Date: Mon, 5 Mar 2018 16:02:50 +0100 Subject: [PATCH 032/140] chore: revert PR #3496 --- lib/API/schema.json | 306 +++++++++++++++++--------------------------- 1 file changed, 119 insertions(+), 187 deletions(-) diff --git a/lib/API/schema.json b/lib/API/schema.json index 75db9a98..4fb1e935 100644 --- a/lib/API/schema.json +++ b/lib/API/schema.json @@ -2,87 +2,23 @@ "script": { "type": "string", "require": true, - "alias" : "exec", - "description": "Path of the script to launch, required field" - }, - "name": { - "type": "string", - "default": "Script filename without the extension (app for app.js)", - "description": "Process name in the process list" - }, - "cwd": { - "type": "string", - "default": "CWD of the current environment (from your shell)", - "description": "Current working directory to start the process with" + "alias" : "exec" }, "args": { "type": [ "array", "string" - ], - "description": "Arguments to pass to the script" - }, - "interpreter": { - "type": "string", - "alias": "exec_interpreter", - "default": "node", - "description": "Interpreter absolute path" + ] }, "node_args": { "type": [ "array", "string" ], - "alias": ["interpreter_args"], - "description": "Arguments to pass to the interpreter" + "alias": ["interpreterArgs", "interpreter_args"] }, - "output": { - "type": "string", - "alias": ["out", "out_file", "out_log"], - "default": "~/.pm2/logs/-out.log", - "description": "File path for stdout (each line is appended to this file)" - }, - "error": { - "type": "string", - "alias": ["error_file", "err", "err_file", "err_log"], - "default": "~/.pm2/logs/-error.err", - "description": "File path for stderr (each line is appended to this file)" - }, - "log": { - "type": [ - "boolean", - "string" - ], - "default": "/dev/null", - "alias": "log_file", - "description": "File path for combined stdout and stderr (each line is appended to this file)" - }, - "disable_logs": { - "type": "boolean", - "default": false, - "description": "Disable all logs storage" - }, - "log_type": { - "type": "string", - "description": "Define a specific log output type, possible values: json|" - }, - "log_date_format": { - "type": "string", - "description": "Format for log timestamps (eg YYYY-MM-DD HH:mm Z) in moment.js format" - }, - "env": { - "type": [ - "object", - "string" - ], - "description": "Specify environment variables to be injected" - }, - "^env_\\S*$": { - "type": [ - "object", - "string" - ], - "description": "Specify environment variables to be injected when using --env " + "name": { + "type": "string" }, "max_memory_restart": { "type": [ @@ -91,89 +27,124 @@ ], "regex": "^\\d+(G|M|K)?$", "ext_type": "sbyte", - "desc": "it should be a NUMBER - byte, \"[NUMBER]G\"(Gigabyte), \"[NUMBER]M\"(Megabyte) or \"[NUMBER]K\"(Kilobyte)", - "description": "Restart the app if an amount of memory is exceeded (format: 'K|G|' for KB, 'M' for MB, 'G' for GB, default to byte)" + "desc": "it should be a NUMBER - byte, \"[NUMBER]G\"(Gigabyte), \"[NUMBER]M\"(Megabyte) or \"[NUMBER]K\"(Kilobyte)" + }, + "uid" : { + "type" : "string" + }, + "gid" : { + "type" : "string" + }, + "restart_delay": { + "type" : "number" + }, + "source_map_support" : { + "type": "boolean" + }, + "wait_ready" : { + "type": "boolean" + }, + "disable_source_map_support" : { + "type": "boolean" + }, + "instances": { + "type": "number" + }, + "kill_timeout": { + "type": "number" + }, + "listen_timeout": { + "type": "number" + }, + "port": { + "type": "number" + }, + "log_file": { + "type": [ + "boolean", + "string" + ], + "alias": "log" + }, + "error_file": { + "type": "string", + "alias": ["error", "err", "err_file", "err_log"] + }, + "log_type": { + "type": "string" + }, + "out_file": { + "type": "string", + "alias": ["output", "out", "out_log"] }, "pid_file": { "type": "string", - "alias": "pid", - "default": "~/.pm2/pids/app_name-id.pid", - "description": "File path where the pid of the started process is written by pm2" - }, - "restart_delay": { - "type" : "number", - "default": 0, - "description": "Time in ms to wait before restarting a crashing app" - }, - "source_map_support": { - "type": "boolean", - "default": true, - "description": "Enable or disable the source map support" - }, - "disable_source_map_support": { - "type": "boolean", - "default": false, - "description": "Enable or disable the source map support" - }, - "wait_ready": { - "type": "boolean", - "default": false, - "description": "Make the process wait for a process.send('ready')" - }, - "instances": { - "type": "number", - "default": 1, - "description": "Number of instances to be started in cluster mode" - }, - "kill_timeout": { - "type": "number", - "default": 1600, - "description": "Time in ms before sending the final SIGKILL signal after SIGINT" - }, - "listen_timeout": { - "type": "number", - "description": "Time in ms before forcing a reload if app is still not listening/has still note sent ready" + "alias": "pid" }, "cron_restart": { "type": "string", - "alias": "cron", - "description": "A cron pattern to restart your app" + "alias": "cron" + }, + "cwd": { + "type": "string" }, "merge_logs": { "type": "boolean", - "alias" : "combine_logs", - "default": false, - "description": "In cluster mode, merge each type of logs into a single file (instead of having one for each cluster)" + "alias" : "combine_logs" }, - "vizion": { + "vizion" : { "type": "boolean", - "default" : true, - "description": "Enable or disable the versioning metadatas (vizion library)" + "default" : true }, - "autorestart": { + "pmx" : { "type": "boolean", - "default" : true, - "description": "Enable or disable auto restart after process failure" + "default" : true + }, + "automation" : { + "type": "boolean", + "default" : true + }, + "autorestart" : { + "type": "boolean", + "default" : true + }, + "treekill" : { + "type": "boolean", + "default" : true }, "watch": { "type": [ "boolean", "array", "string" - ], - "default": false, - "description": "Enable or disable the watch mode" + ] }, "ignore_watch": { "type": [ "array", "string" - ], - "description": "List of paths to ignore (regex)" + ] }, "watch_options": { - "type": "object", - "description": "Object that will be used as an options with chokidar (refer to chokidar documentation)" + "type": "object" + }, + "env": { + "type": [ + "object", + "string" + ] + }, + "^env_\\S*$": { + "type": [ + "object", + "string" + ] + }, + "disable_logs" : { + "type": "boolean" + }, + "log_date_format": { + "type": "string" }, "min_uptime": { "type": [ @@ -183,51 +154,43 @@ "regex": "^\\d+(h|m|s)?$", "desc": "it should be a NUMBER - milliseconds, \"[NUMBER]h\"(hours), \"[NUMBER]m\"(minutes) or \"[NUMBER]s\"(seconds)", "min": 100, - "ext_type": "stime", - "default": 1000, - "description": "Minimum uptime of the app to be considered started (format is [0-9]+(h|m|s)?, for hours, minutes, seconds, default to ms)" + "ext_type": "stime" }, "max_restarts": { "type": "number", - "min": 0, - "default": 16, - "description": "Number of times a script is restarted when it exits in less than min_uptime" + "min": 0 }, "exec_mode": { "type": "string", "regex": "^(cluster|fork)(_mode)?$", "alias": "executeCommand", - "desc": "it should be \"cluster\"(\"cluster_mode\") or \"fork\"(\"fork_mode\") only", - "default": "fork", - "description": "Set the execution mode, possible values: fork|cluster" + "desc": "it should be \"cluster\"(\"cluster_mode\") or \"fork\"(\"fork_mode\") only" + }, + "exec_interpreter": { + "type": "string", + "alias": "interpreter" + }, + "write": { + "type": "boolean" }, "force": { - "type": "boolean", - "default": false, - "description": "Start a script even if it is already running (only the script path is considered)" + "type": "boolean" }, "append_env_to_name": { - "type": "boolean", - "default": false, - "description": "Append the environment name to the app name" + "type": "boolean" }, "post_update": { - "type": "array", - "description": "List of commands executed after a pull/upgrade operation performed from Keymetrics dashboard" - }, - "trace": { - "type": [ - "boolean" - ], - "default": false, - "description": "Enable or disable the transaction tracing" + "type": "array" }, "disable_trace": { "type": [ "boolean" - ], - "default": true, - "description": "Enable or disable the transaction tracing" + ] + }, + "trace": { + "type": [ + "boolean" + ] }, "v8": { "type": [ @@ -245,45 +208,14 @@ ] }, "increment_var": { - "type": "string", - "description": "Specify the name of an environnement variable to inject which increments for each cluster" + "type": "string" }, "instance_var": { "type": "string", - "default" : "NODE_APP_INSTANCE", - "description": "Rename the NODE_APP_INSTANCE environment variable" - }, - "pmx": { - "type": "boolean", - "default" : true, - "description": "Enable or disable pmx wrapping" - }, - "automation": { - "type": "boolean", - "default" : true, - "description": "Enable or disable pmx wrapping" - }, - "treekill": { - "type": "boolean", - "default" : true, - "description": "Only kill the main process, not detached children" - }, - "port": { - "type": "number", - "description": "Shortcut to inject a PORT environment variable" - }, - "uid": { - "type" : "string", - "default": "Current user uid", - "description": "Set user id" - }, - "gid": { - "type" : "string", - "default": "Current user gid", - "description": "Set group id" + "default" : "NODE_APP_INSTANCE" }, "windowsHide": { "type": "boolean", "default" : true } -} \ No newline at end of file +} From bc07f43b115066f6077606df8f59379777f2a917 Mon Sep 17 00:00:00 2001 From: vince Date: Mon, 5 Mar 2018 17:11:36 +0100 Subject: [PATCH 033/140] fix: use polyfill module for copySync with node 4.x --- lib/API/Startup.js | 5 +++-- lib/God/ActionMethods.js | 5 +++-- package.json | 1 + 3 files changed, 7 insertions(+), 4 deletions(-) diff --git a/lib/API/Startup.js b/lib/API/Startup.js index f77ca516..b96877fe 100644 --- a/lib/API/Startup.js +++ b/lib/API/Startup.js @@ -7,6 +7,7 @@ var debug = require('debug')('pm2:cli:startup'); var chalk = require('chalk'); var path = require('path'); var fs = require('fs'); +const fsExtra = require('fs-extra'); var async = require('async'); var exec = require('child_process').exec; var Common = require('../Common.js'); @@ -396,7 +397,7 @@ module.exports = function(CLI) { // Back up dump file try { if (fs.existsSync(cst.DUMP_FILE_PATH)) { - fs.copyFileSync(cst.DUMP_FILE_PATH, cst.DUMP_BACKUP_FILE_PATH); + fsExtra.copySync(cst.DUMP_FILE_PATH, cst.DUMP_BACKUP_FILE_PATH); } } catch (e) { console.error(e.stack || e); @@ -411,7 +412,7 @@ module.exports = function(CLI) { try { // try to backup file if(fs.existsSync(cst.DUMP_BACKUP_FILE_PATH)) { - fs.copyFileSync(cst.DUMP_BACKUP_FILE_PATH, cst.DUMP_FILE_PATH); + fsExtra.copySync(cst.DUMP_BACKUP_FILE_PATH, cst.DUMP_FILE_PATH); } } catch (e) { // don't keep broken file diff --git a/lib/God/ActionMethods.js b/lib/God/ActionMethods.js index 1df6b159..1556a165 100644 --- a/lib/God/ActionMethods.js +++ b/lib/God/ActionMethods.js @@ -12,6 +12,7 @@ */ var fs = require('fs'); +const fsExtra = require('fs-extra'); var path = require('path'); var async = require('async'); var os = require('os'); @@ -155,7 +156,7 @@ module.exports = function(God) { // Back up dump file try { if (fs.existsSync(cst.DUMP_FILE_PATH)) { - fs.copyFileSync(cst.DUMP_FILE_PATH, cst.DUMP_BACKUP_FILE_PATH); + fsExtra.copySync(cst.DUMP_FILE_PATH, cst.DUMP_BACKUP_FILE_PATH); } } catch (e) { console.error(e.stack || e); @@ -169,7 +170,7 @@ module.exports = function(God) { try { // try to backup file if(fs.existsSync(cst.DUMP_BACKUP_FILE_PATH)) { - fs.copyFileSync(cst.DUMP_BACKUP_FILE_PATH, cst.DUMP_FILE_PATH); + fsExtra.copySync(cst.DUMP_BACKUP_FILE_PATH, cst.DUMP_FILE_PATH); } } catch (e) { // don't keep broken file diff --git a/package.json b/package.json index 3bd207d6..4acaa133 100644 --- a/package.json +++ b/package.json @@ -169,6 +169,7 @@ "debug": "^3.0", "eventemitter2": "5.0.1", "fclone": "1.0.11", + "fs-extra": "^5.0.0", "mkdirp": "0.5.1", "moment": "^2.19", "needle": "^2.2.0", From c3ae6aa8b45a5e8bcf408c07473d19379a10c53e Mon Sep 17 00:00:00 2001 From: vince Date: Fri, 2 Mar 2018 17:18:23 +0100 Subject: [PATCH 034/140] feature: add inspect feature, on runtime --- bin/pm2 | 7 +++++++ lib/API/Extra.js | 20 +++++++++++++++++++- lib/ProcessContainerFork.js | 20 ++++++++++++++++++-- 3 files changed, 44 insertions(+), 3 deletions(-) diff --git a/bin/pm2 b/bin/pm2 index 9bcae4e6..840dc84c 100755 --- a/bin/pm2 +++ b/bin/pm2 @@ -396,6 +396,13 @@ commander.command('id ') pm2.getProcessIdByName(name); }); +// Inspect a process +commander.command('inspect ') + .description('inspect a process') + .action(function(cmd) { + pm2.inspect(cmd, commander); + }); + // // Stop and delete a process by name from database // diff --git a/lib/API/Extra.js b/lib/API/Extra.js index 00f445dd..6f70d549 100644 --- a/lib/API/Extra.js +++ b/lib/API/Extra.js @@ -15,6 +15,7 @@ var fs = require('fs'); var fmt = require('../tools/fmt.js'); var moment = require('moment'); var pkg = require('../../package.json'); +const semver = require('semver'); module.exports = function(CLI) { @@ -38,7 +39,6 @@ module.exports = function(CLI) { */ CLI.prototype.report = function() { var that = this; - var semver = require('semver'); function reporting(cb) { @@ -639,4 +639,22 @@ module.exports = function(CLI) { launchMonitor(); }; + + CLI.prototype.inspect = function(app_name, cb) { + const that = this; + if(semver.satisfies(process.versions.node, '>= 8.0.0')) { + this.trigger(app_name, 'internal:inspect', function (err, res) { + if(res[0].data.return === '') { + Common.printOut(`Inspect disabled on ${app_name}`); + } else { + Common.printOut(`Inspect enabled on ${app_name} => go to chrome : chrome://inspect !!!`); + } + + that.exitCli(cst.SUCCESS_EXIT); + }); + } else { + Common.printOut('Inspect is available for node version >=8.x !'); + that.exitCli(cst.SUCCESS_EXIT); + } + }; }; diff --git a/lib/ProcessContainerFork.js b/lib/ProcessContainerFork.js index 6d1b0ceb..189851e9 100644 --- a/lib/ProcessContainerFork.js +++ b/lib/ProcessContainerFork.js @@ -1,17 +1,33 @@ -/** + /** * Copyright 2013 the PM2 project authors. All rights reserved. * Use of this source code is governed by a license that * can be found in the LICENSE file. */ // Inject custom modules if (process.env.pmx !== 'false') { - require('pmx').init({ + const pmx = require('pmx'); + pmx.init({ transactions: (process.env.km_link === 'true' && (process.env.trace === 'true' || process.env.deep_monitoring === 'true')) || false, http: process.env.km_link === 'true' || false, v8: process.env.v8 === 'true' || process.env.deep_monitoring === 'true' || false, event_loop_dump: process.env.event_loop_inspector === 'true' || process.env.deep_monitoring === 'true' || false, deep_metrics: process.env.deep_monitoring === 'true' || false }); + + if(require('semver').satisfies(process.versions.node, '>= 8.0.0')) { + var url = ''; + pmx.action('internal:inspect', function(reply) { + const inspector = require('inspector'); + if(url === '') { + inspector.open(); + url = inspector.url(); + } else { + inspector.close(); + url = ''; + } + reply(url); + }); + } } if (typeof(process.env.source_map_support) != "undefined" && From e1f7224d9bc0c627a42f813d651a06c71d43c67c Mon Sep 17 00:00:00 2001 From: vince Date: Fri, 2 Mar 2018 17:43:47 +0100 Subject: [PATCH 035/140] feature: add inspect feature, on runtime for cluster app --- lib/API/Extra.js | 2 +- lib/ProcessContainer.js | 10 +--------- lib/ProcessContainerFork.js | 26 +------------------------- lib/ProcessUtils.js | 29 +++++++++++++++++++++++++++++ 4 files changed, 32 insertions(+), 35 deletions(-) create mode 100644 lib/ProcessUtils.js diff --git a/lib/API/Extra.js b/lib/API/Extra.js index 6f70d549..60ced15d 100644 --- a/lib/API/Extra.js +++ b/lib/API/Extra.js @@ -644,7 +644,7 @@ module.exports = function(CLI) { const that = this; if(semver.satisfies(process.versions.node, '>= 8.0.0')) { this.trigger(app_name, 'internal:inspect', function (err, res) { - if(res[0].data.return === '') { + if(res && res[0].data.return === '') { Common.printOut(`Inspect disabled on ${app_name}`); } else { Common.printOut(`Inspect enabled on ${app_name} => go to chrome : chrome://inspect !!!`); diff --git a/lib/ProcessContainer.js b/lib/ProcessContainer.js index db9540dd..0d739bac 100644 --- a/lib/ProcessContainer.js +++ b/lib/ProcessContainer.js @@ -30,15 +30,7 @@ delete process.env.pm2_env; (function ProcessContainer() { var fs = require('fs'); - if (process.env.pmx !== 'false') { - require('pmx').init({ - transactions: (process.env.km_link === 'true' && (process.env.trace === 'true' || process.env.deep_monitoring === 'true')) || false, - http: process.env.km_link === 'true' || false, - v8: process.env.v8 === 'true' || process.env.deep_monitoring === 'true' || false, - event_loop_dump: process.env.event_loop_inspector === 'true' || process.env.deep_monitoring === 'true' || false, - deep_metrics: process.env.deep_monitoring === 'true' || false - }); - } + require('./ProcessUtils').injectModules(); var stdFile = pm2_env.pm_log_path; var outFile = pm2_env.pm_out_log_path; diff --git a/lib/ProcessContainerFork.js b/lib/ProcessContainerFork.js index 189851e9..59c45d3f 100644 --- a/lib/ProcessContainerFork.js +++ b/lib/ProcessContainerFork.js @@ -4,31 +4,7 @@ * can be found in the LICENSE file. */ // Inject custom modules -if (process.env.pmx !== 'false') { - const pmx = require('pmx'); - pmx.init({ - transactions: (process.env.km_link === 'true' && (process.env.trace === 'true' || process.env.deep_monitoring === 'true')) || false, - http: process.env.km_link === 'true' || false, - v8: process.env.v8 === 'true' || process.env.deep_monitoring === 'true' || false, - event_loop_dump: process.env.event_loop_inspector === 'true' || process.env.deep_monitoring === 'true' || false, - deep_metrics: process.env.deep_monitoring === 'true' || false - }); - - if(require('semver').satisfies(process.versions.node, '>= 8.0.0')) { - var url = ''; - pmx.action('internal:inspect', function(reply) { - const inspector = require('inspector'); - if(url === '') { - inspector.open(); - url = inspector.url(); - } else { - inspector.close(); - url = ''; - } - reply(url); - }); - } -} +require('./ProcessUtils').injectModules(); if (typeof(process.env.source_map_support) != "undefined" && process.env.source_map_support !== "false") { diff --git a/lib/ProcessUtils.js b/lib/ProcessUtils.js new file mode 100644 index 00000000..3e90117e --- /dev/null +++ b/lib/ProcessUtils.js @@ -0,0 +1,29 @@ +module.exports = { + injectModules: function() { + if (process.env.pmx !== 'false') { + const pmx = require('pmx'); + pmx.init({ + transactions: (process.env.km_link === 'true' && (process.env.trace === 'true' || process.env.deep_monitoring === 'true')) || false, + http: process.env.km_link === 'true' || false, + v8: process.env.v8 === 'true' || process.env.deep_monitoring === 'true' || false, + event_loop_dump: process.env.event_loop_inspector === 'true' || process.env.deep_monitoring === 'true' || false, + deep_metrics: process.env.deep_monitoring === 'true' || false + }); + + if(require('semver').satisfies(process.versions.node, '>= 8.0.0')) { + var url = ''; + pmx.action('internal:inspect', function(reply) { + const inspector = require('inspector'); + if(url === '') { + inspector.open(); + url = inspector.url(); + } else { + inspector.close(); + url = ''; + } + reply(url); + }); + } + } + } +}; From d9f44f170f115c2d6dfb6a7fe71dc31bd7fb66fb Mon Sep 17 00:00:00 2001 From: vince Date: Mon, 5 Mar 2018 10:49:32 +0100 Subject: [PATCH 036/140] fix: improve error message if action has failed --- lib/API/Extra.js | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/lib/API/Extra.js b/lib/API/Extra.js index 60ced15d..c6c057ec 100644 --- a/lib/API/Extra.js +++ b/lib/API/Extra.js @@ -644,10 +644,15 @@ module.exports = function(CLI) { const that = this; if(semver.satisfies(process.versions.node, '>= 8.0.0')) { this.trigger(app_name, 'internal:inspect', function (err, res) { - if(res && res[0].data.return === '') { - Common.printOut(`Inspect disabled on ${app_name}`); + + if(res && res[0]) { + if (res[0].data.return === '') { + Common.printOut(`Inspect disabled on ${app_name}`); + } else { + Common.printOut(`Inspect enabled on ${app_name} => go to chrome : chrome://inspect !!!`); + } } else { - Common.printOut(`Inspect enabled on ${app_name} => go to chrome : chrome://inspect !!!`); + Common.printOut(`Impossible to enabled inspect mode on ${app_name} !!!`); } that.exitCli(cst.SUCCESS_EXIT); From c251c8c97e6f18aae584cac6b7f3c83cf4f2de9c Mon Sep 17 00:00:00 2001 From: vince Date: Mon, 5 Mar 2018 11:14:11 +0100 Subject: [PATCH 037/140] chore: wording on error message --- lib/API/Extra.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/API/Extra.js b/lib/API/Extra.js index c6c057ec..cf7a23fc 100644 --- a/lib/API/Extra.js +++ b/lib/API/Extra.js @@ -652,7 +652,7 @@ module.exports = function(CLI) { Common.printOut(`Inspect enabled on ${app_name} => go to chrome : chrome://inspect !!!`); } } else { - Common.printOut(`Impossible to enabled inspect mode on ${app_name} !!!`); + Common.printOut(`Unable to activate inspect mode on ${app_name} !!!`); } that.exitCli(cst.SUCCESS_EXIT); From 2c310084453dd7b1546957e59b1fc7ef964d425b Mon Sep 17 00:00:00 2001 From: Robin Monnier Date: Mon, 5 Mar 2018 22:13:39 +0100 Subject: [PATCH 038/140] feat(bin/pm2): improve usage --- bin/pm2 | 127 +++++++++++++++++++++++++++++--------------------------- 1 file changed, 66 insertions(+), 61 deletions(-) diff --git a/bin/pm2 b/bin/pm2 index 05072f4b..02fdce44 100755 --- a/bin/pm2 +++ b/bin/pm2 @@ -33,24 +33,29 @@ if (process.argv.indexOf('-v') > -1) { var pm2 = new PM2(); commander.version(pkg.version) - .option('-v --version', 'get version') + .option('-v --version', 'print pm2 version') .option('-s --silent', 'hide all messages', false) + .option('-n --name ', 'set a name for the process in the process list') .option('-m --mini-list', 'display a compacted list without formatting') + .option('--interpreter ', 'set a specific interpreter to use for executing app, default: node') + .option('--interpreter-args ', 'set arguments to pass to the interpreter (alias of --node-args)') + .option('--node-args ', 'space delimited arguments to pass to node') + .option('-o --output ', 'specify log file for stdout') + .option('-e --error ', 'specify log file for stderr') + .option('-l --log [path]', 'specify log file which gathers both stdout and stderr') + .option('--log-type ', 'specify log output style (raw by default, json optional)') + .option('--log-date-format ', 'add custom prefix timestamp to logs') + .option('--disable-logs', 'disable all logs storage') + .option('--env ', 'specify which set of environment variables from ecosystem file must be injected') + .option('-a --update-env', 'force an update of the environment with restart/reload (-a <=> apply)') .option('-f --force', 'force actions') - .option('--disable-logs', 'do not write logs') - .option('-n --name ', 'set a for script') .option('-i --instances ', 'launch [number] instances (for networked app)(load balanced)') .option('--parallel ', 'number of parallel actions (for restart/reload)') - .option('-l --log [path]', 'specify entire log file (error and out are both included)') - .option('-o --output ', 'specify out log file') - .option('-e --error ', 'specify error log file') .option('-p --pid ', 'specify pid file') .option('-k --kill-timeout ', 'delay before sending final SIGKILL signal to process') .option('--listen-timeout ', 'listen timeout on application reload') - .option('--max-memory-restart ', 'specify max memory amount used to autorestart (in octet or use syntax like 100M)') + .option('--max-memory-restart ', 'Restart the app if an amount of memory is exceeded (in bytes)') .option('--restart-delay ', 'specify a delay between restarts (in milliseconds)') - .option('--env ', 'specify environment to get specific env variables (for JSON declaration)') - .option('--log-type ', 'specify log output style (raw by default, json optional)') .option('-x --execute-command', 'execute a program using fork system') .option('--max-restarts [count]', 'only restart the script COUNT times') .option('-u --user ', 'define user when generating startup script') @@ -62,19 +67,14 @@ commander.version(pkg.version) .option('--service-name ', 'define service name when generating startup script') .option('-c --cron ', 'restart a running process based on a cron pattern') .option('-w --write', 'write configuration in local folder') - .option('--interpreter ', 'the interpreter pm2 should use for executing app (bash, python...)') - .option('--interpreter-args ', 'interpret options (alias of --node-args)') - .option('--log-date-format ', 'add custom prefix timestamp to logs') .option('--no-daemon', 'run pm2 daemon in the foreground if it doesn\'t exist already') - .option('-a --update-env', 'update environment on restart/reload (-a <=> apply)') .option('--source-map-support', 'force source map support') .option('--only ', 'with json declaration, allow to only act on one application') .option('--disable-source-map-support', 'force source map support') .option('--wait-ready', 'ask pm2 to wait for ready event from your app') .option('--merge-logs', 'merge logs from different instances but keep error and out separated') .option('--watch [paths]', 'watch application folder for changes', function(v, m) { m.push(v); return m;}, []) - .option('--ignore-watch ', 'folder/files to be ignored watching, should be a specific name or regex - e.g. --ignore-watch="test node_modules \"some scripts\""') - .option('--node-args ', 'space delimited arguments to pass to node in cluster mode - e.g. --node-args="--debug=7001 --trace-deprecation"') + .option('--ignore-watch ', 'List of paths to ignore (name or regex)') .option('--no-color', 'skip colors') .option('--no-vizion', 'start an app without vizion feature (versioning control)') .option('--no-autorestart', 'start an app without automatic restart') @@ -85,43 +85,46 @@ commander.version(pkg.version) .option('--disable-trace', 'disable transaction tracing with km') .option('--attach', 'attach logging after your start/restart/stop/reload') .option('--sort ', 'sort process according to field\'s name') - .option('--v8', 'enable v8 data collecting') - .option('--event-loop-inspector', 'enable event-loop-inspector dump in pmx') - .option('--deep-monitoring', 'enable all monitoring tools (equivalent to --v8 --event-loop-inspector --trace)') .usage('[cmd] app'); -commander.on('--help', function() { - console.log(' Basic Examples:'); - console.log(''); - console.log(' Start an app using all CPUs available + set a name :'); - console.log(' $ pm2 start app.js -i 0 --name "api"'); - console.log(''); - console.log(' Restart the previous app launched, by name :'); - console.log(' $ pm2 restart api'); - console.log(''); - console.log(' Stop the app :'); - console.log(' $ pm2 stop api'); - console.log(''); - console.log(' Restart the app that is stopped :'); - console.log(' $ pm2 restart api'); - console.log(''); - console.log(' Remove the app from the process list :'); - console.log(' $ pm2 delete api'); - console.log(''); - console.log(' Kill daemon pm2 :'); - console.log(' $ pm2 kill'); - console.log(''); - console.log(' Update pm2 :'); - console.log(' $ npm install pm2@latest -g ; pm2 update'); - console.log(''); - console.log(' More examples in https://github.com/Unitech/pm2#usagefeatures'); - console.log(''); - console.log(' Deployment help:'); - console.log(''); - console.log(' $ pm2 deploy help'); - console.log(''); - console.log(''); -}); + function displayUsage() { + console.log('Usage: pm2 ') + console.log(' pm2 [option(s)]'); + console.log(''); + console.log('pm2 -h, --help all commands and options available'); + console.log('pm2 quickStart display pm2 usage examples'); + console.log('pm2 -h help on '); + console.log(''); + console.log('Access pm2 files in ~/.pm2'); + } + + function displayQuickStart() { + console.log('Install pm2 auto completion:') + console.log('$> pm2 completion install') + console.log(''); + console.log('Start and add a process to the pm2 process list:') + console.log('$> pm2 start app.js --name app'); + console.log(''); + console.log('Stop and delete a process from the pm2 process list:'); + console.log('$> pm2 delete app'); + console.log(''); + console.log('Show the process list:'); + console.log('$> pm2 ls'); + console.log(''); + console.log('Stop, start and restart a process from the process list:'); + console.log('$> pm2 stop app'); + console.log('$> pm2 start app'); + console.log('$> pm2 restart app'); + console.log(''); + console.log('Clusterize an app to all CPU cores available:'); + console.log('$> pm2 start -i max'); + console.log(''); + console.log('Update pm2 :'); + console.log('$> npm install pm2 -g && pm2 update'); + console.log(''); + console.log('Check the full documentation on https://docs.pm2.io'); + console.log(''); + } if (process.argv.indexOf('-s') > -1) { for(var key in console){ @@ -312,12 +315,6 @@ commander.command('startOrReload ') pm2._startJson(file, commander, 'reloadProcessId'); }); -commander.command('pid [app_name]') - .description('return pid of [app_name] or all') - .action(function(app) { - pm2.getPID(app); - }); - commander.command('startOrGracefulReload ') .description('start or gracefully reload JSON file') .action(function(file) { @@ -464,11 +461,11 @@ commander.command('update') /** * Module specifics */ -commander.command('install [module|git:// url|json]') +commander.command('install ') .alias('module:install') .option('--v1', 'install module in v1 manner (do not use it)') .option('--safe [time]', 'keep module backup, if new module fail = restore with previous') - .description('install or update a module (or a set of modules) and run it forever') + .description('install or update a module and run it forever') .action(function(plugin_name, opts) { if (opts.v1) commander.v1 = true; @@ -919,13 +916,21 @@ commander.command('serve [path] [port]') pm2.serve(path, port, commander); }); +commander.command('quickStart') + .description('display pm2 usage examples') + .action(() => { + console.log(cst.PREFIX_MSG + '\nQuick Start:\n'); + displayQuickStart(); + process.exit(cst.SUCCESS_EXIT); + }) + // // Catch all // commander.command('*') .action(function() { - console.log(cst.PREFIX_MSG + '\nCommand not found'); - commander.outputHelp(); + console.log(cst.PREFIX_MSG + '\nCommand not found\n'); + displayUsage(); // Check if it does not forget to close fds from RPC process.exit(cst.ERROR_EXIT); }); @@ -935,7 +940,7 @@ commander.command('*') // if (process.argv.length == 2) { commander.parse(process.argv); - commander.outputHelp(); + displayUsage(); // Check if it does not forget to close fds from RPC process.exit(cst.ERROR_EXIT); } From 65f60659139f46874882ca5a0c377dc2ad20ad9a Mon Sep 17 00:00:00 2001 From: Alexandre Strzelewicz Date: Wed, 7 Mar 2018 13:42:19 +0100 Subject: [PATCH 039/140] doc: move up docker integration --- README.md | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/README.md b/README.md index b9de87c9..3b07141d 100644 --- a/README.md +++ b/README.md @@ -70,6 +70,21 @@ Your app is now daemonized, monitored and kept alive forever. [More about Process Management](http://pm2.keymetrics.io/docs/usage/process-management/) +### Container Support + +With the drop-in replacement command for `node`, called `pm2-runtime`, run your Node.js application in a proper production environment. +We also offer an [officialy supported Docker image](https://hub.docker.com/r/keymetrics/pm2/). + +Using it is seamless: + +``` +FROM keymetrics/pm2:latest-alpine +[...] +CMD [ "pm2-runtime", "npm", "--", "start" ] +``` + +[Read More about the dedicated integration](http://pm2.keymetrics.io/docs/usage/docker-pm2-nodejs/) + ### Managing a Process Once applications are started you can manage them easily: @@ -130,21 +145,6 @@ Seamlessly supported by all major Node.js frameworks and any Node.js application [More informations about how PM2 make clustering easy](https://keymetrics.io/2015/03/26/pm2-clustering-made-easy/) -### Container Support - -With the drop-in replacement command for `node`, called `pm2-runtime`, run your Node.js application in a proper production environment. -We also offer an [officialy supported Docker image](https://hub.docker.com/r/keymetrics/pm2/). - -Using it is seamless: - -``` -FROM keymetrics/pm2:latest-alpine -[...] -CMD [ "pm2-runtime", "npm", "--", "start" ] -``` - -[Read More about the dedicated integration](http://pm2.keymetrics.io/docs/usage/docker-pm2-nodejs/) - ### Terminal Based Monitoring ![Monit](https://github.com/Unitech/pm2/raw/master/pres/pm2-monit.png) From 41c6be78e13066fd7ce7ed81c653e9807f54fca6 Mon Sep 17 00:00:00 2001 From: Robin Monnier Date: Thu, 15 Mar 2018 14:55:12 +0100 Subject: [PATCH 040/140] improve pm2 examples --- bin/pm2 | 86 ++++++++++++++++++++++++++++++--------------------------- 1 file changed, 45 insertions(+), 41 deletions(-) diff --git a/bin/pm2 b/bin/pm2 index 02fdce44..0bb033bc 100755 --- a/bin/pm2 +++ b/bin/pm2 @@ -88,41 +88,45 @@ commander.version(pkg.version) .usage('[cmd] app'); function displayUsage() { - console.log('Usage: pm2 ') - console.log(' pm2 [option(s)]'); + console.log('usage: pm2 [options] ') console.log(''); console.log('pm2 -h, --help all commands and options available'); - console.log('pm2 quickStart display pm2 usage examples'); - console.log('pm2 -h help on '); + console.log('pm2 examples display pm2 usage examples'); + console.log('pm2 -h help on a specific command'); console.log(''); console.log('Access pm2 files in ~/.pm2'); } - function displayQuickStart() { - console.log('Install pm2 auto completion:') - console.log('$> pm2 completion install') + function displayExamples() { + console.log('- Start and add a process to the pm2 process list:') console.log(''); - console.log('Start and add a process to the pm2 process list:') - console.log('$> pm2 start app.js --name app'); + console.log(chalk.cyan(' $ pm2 start app.js --name app')); console.log(''); - console.log('Stop and delete a process from the pm2 process list:'); - console.log('$> pm2 delete app'); + console.log('- Show the process list:'); console.log(''); - console.log('Show the process list:'); - console.log('$> pm2 ls'); + console.log(chalk.cyan(' $ pm2 ls')); console.log(''); - console.log('Stop, start and restart a process from the process list:'); - console.log('$> pm2 stop app'); - console.log('$> pm2 start app'); - console.log('$> pm2 restart app'); + console.log('- Stop and delete a process from the pm2 process list:'); console.log(''); - console.log('Clusterize an app to all CPU cores available:'); - console.log('$> pm2 start -i max'); + console.log(chalk.cyan(' $ pm2 delete app')); console.log(''); - console.log('Update pm2 :'); - console.log('$> npm install pm2 -g && pm2 update'); + console.log('- Stop, start and restart a process from the process list:'); console.log(''); - console.log('Check the full documentation on https://docs.pm2.io'); + console.log(chalk.cyan(' $ pm2 stop app')); + console.log(chalk.cyan(' $ pm2 start app')); + console.log(chalk.cyan(' $ pm2 restart app')); + console.log(''); + console.log('- Clusterize an app to all CPU cores available:'); + console.log(chalk.cyan(' $ pm2 start -i max')); + console.log(''); + console.log('- Update pm2 :'); + console.log(chalk.cyan(' $ npm install pm2 -g && pm2 update')); + console.log(''); + console.log('- Install pm2 auto completion:') + console.log(''); + console.log(chalk.cyan(' $ pm2 completion install')) + console.log(''); + console.log('Check the full documentation on https://pm2.io/doc'); console.log(''); } @@ -256,7 +260,7 @@ function patchCommanderArg(cmd) { // // Start command // -commander.command('start ') +commander.command('start ') .option('--watch', 'Watch folder for changes') .option('--fresh', 'Rebuild Dockerfile') .option('--daemon', 'Run container in Daemon mode (debug purposes)') @@ -326,7 +330,7 @@ commander.command('startOrGracefulReload ') // commander.command('stop ') .option('--watch', 'Stop watching folder for changes') - .description('stop a process (to start it again, do pm2 restart )') + .description('stop a process') .action(function(param) { async.forEachLimit(param, 1, function(script, next) { pm2.stop(script, next); @@ -550,41 +554,41 @@ commander.command('report') commander.command('link [secret] [public] [name]') .alias('interact') .option('--info-node [url]', 'set url info node') - .description('linking action to keymetrics.io - command can be stop|info|delete|restart') + .description('link with the pm2 monitoring dashboard') .action(pm2._pre_interact.bind(pm2)); commander.command('unlink') - .description('linking action to keymetrics.io - command can be stop|info|delete|restart') + .description('unlink with the pm2 monitoring dashboard') .action(function() { pm2.unlink(); }); -commander.command('unmonitor [name]') - .description('unmonitor target process') - .action(function(name) { - pm2.monitorState('unmonitor', name); - }); - commander.command('monitor [name]') .description('monitor target process') .action(function(name) { pm2.monitorState('monitor', name); }); +commander.command('unmonitor [name]') + .description('unmonitor target process') + .action(function(name) { + pm2.monitorState('unmonitor', name); + }); + commander.command('open') - .description('open dashboard in browser') + .description('open the pm2 monitoring dashboard') .action(function(name) { pm2.openDashboard(); }); commander.command('register') - .description('create an account on keymetrics') + .description('register on pm2 monitoring') .action(function(name) { pm2.registerToKM(); }); commander.command('login') - .description('login to keymetrics and link current PM2') + .description('use login to link with the pm2 monitoring dashboard') .action(function(name) { pm2.loginToKM(); }); @@ -642,7 +646,7 @@ commander.command('resurrect') // Set pm2 to startup // commander.command('unstartup [platform]') - .description('disable and clear auto startup - [platform]=systemd,upstart,launchd,rcd') + .description('disable the pm2 startup hook') .action(function(platform) { pm2.uninstallStartup(platform, commander); }); @@ -651,7 +655,7 @@ commander.command('unstartup [platform]') // Set pm2 to startup // commander.command('startup [platform]') - .description('setup script for pm2 at boot - [platform]=systemd,upstart,launchd,rcd') + .description('enable the pm2 startup hook') .action(function(platform) { pm2.startup(platform, commander); }); @@ -916,11 +920,11 @@ commander.command('serve [path] [port]') pm2.serve(path, port, commander); }); -commander.command('quickStart') +commander.command('examples') .description('display pm2 usage examples') .action(() => { - console.log(cst.PREFIX_MSG + '\nQuick Start:\n'); - displayQuickStart(); + console.log(cst.PREFIX_MSG + chalk.grey('pm2 usage examples:\n')); + displayExamples(); process.exit(cst.SUCCESS_EXIT); }) @@ -929,7 +933,7 @@ commander.command('quickStart') // commander.command('*') .action(function() { - console.log(cst.PREFIX_MSG + '\nCommand not found\n'); + console.log(cst.PREFIX_MSG + 'Command not found\n'); displayUsage(); // Check if it does not forget to close fds from RPC process.exit(cst.ERROR_EXIT); From 42bcc02a512f2128e2e8f7743bf79c3f80284cac Mon Sep 17 00:00:00 2001 From: Robin Monnier Date: Thu, 15 Mar 2018 14:59:03 +0100 Subject: [PATCH 041/140] correct bad english --- bin/pm2 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/pm2 b/bin/pm2 index 0bb033bc..18a1f81e 100755 --- a/bin/pm2 +++ b/bin/pm2 @@ -90,7 +90,7 @@ commander.version(pkg.version) function displayUsage() { console.log('usage: pm2 [options] ') console.log(''); - console.log('pm2 -h, --help all commands and options available'); + console.log('pm2 -h, --help all available commands and options'); console.log('pm2 examples display pm2 usage examples'); console.log('pm2 -h help on a specific command'); console.log(''); From 3524617606ac2d262d9a278603f221b22e30bf48 Mon Sep 17 00:00:00 2001 From: Robin Monnier Date: Thu, 15 Mar 2018 15:48:26 +0100 Subject: [PATCH 042/140] add unwanted deletion --- bin/pm2 | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/bin/pm2 b/bin/pm2 index 18a1f81e..c15b9a56 100755 --- a/bin/pm2 +++ b/bin/pm2 @@ -85,6 +85,9 @@ commander.version(pkg.version) .option('--disable-trace', 'disable transaction tracing with km') .option('--attach', 'attach logging after your start/restart/stop/reload') .option('--sort ', 'sort process according to field\'s name') + .option('--v8', 'enable v8 data collecting') + .option('--event-loop-inspector', 'enable event-loop-inspector dump in pmx') + .option('--deep-monitoring', 'enable all monitoring tools (equivalent to --v8 --event-loop-inspector --trace)') .usage('[cmd] app'); function displayUsage() { @@ -319,6 +322,12 @@ commander.command('startOrReload ') pm2._startJson(file, commander, 'reloadProcessId'); }); +commander.command('pid [app_name]') + .description('return pid of [app_name] or all') + .action(function(app) { + pm2.getPID(app); + }); + commander.command('startOrGracefulReload ') .description('start or gracefully reload JSON file') .action(function(file) { From 37bc6296590f17bde59d68e8c5f132108b454d66 Mon Sep 17 00:00:00 2001 From: Eywek Date: Thu, 15 Mar 2018 15:48:59 +0100 Subject: [PATCH 043/140] meta: drop password --- lib/API/Configuration.js | 31 ---------------- lib/Interactor/RemoteActions/Pm2Actions.js | 41 +++++----------------- test/interface/password.mocha.js | 20 ----------- 3 files changed, 9 insertions(+), 83 deletions(-) delete mode 100644 test/interface/password.mocha.js diff --git a/lib/API/Configuration.js b/lib/API/Configuration.js index 01b4439a..17ce16c7 100644 --- a/lib/API/Configuration.js +++ b/lib/API/Configuration.js @@ -1,5 +1,4 @@ -var Password = require('../Interactor/Password.js'); var Common = require('../Common.js'); var cst = require('../../constants.js'); var UX = require('./CliUx'); @@ -63,36 +62,6 @@ module.exports = function(CLI) { return false; } - /** - * Specific when setting pm2 password - * Used for restricted remote actions - * Also alert Interactor that password has been set - */ - if (key.indexOf('pm2:passwd') > -1) { - value = Password.generate(value); - Configuration.set(key, value, function(err) { - if (err) - return cb ? cb(Common.retErr(err)) : that.exitCli(cst.ERROR_EXIT); - InteractorDaemonizer.launchRPC(that._conf, function(err) { - if (err) { - displayConf('pm2', function() { - return cb ? cb(null, {success:true}) : that.exitCli(cst.SUCCESS_EXIT) - }); - return false; - } - InteractorDaemonizer.rpc.passwordSet(function() { - InteractorDaemonizer.disconnectRPC(function() { - displayConf('pm2', function() { - return cb ? cb(null, {success:true}) : that.exitCli(cst.SUCCESS_EXIT); - }); - }); - }); - return false; - }); - }); - return false; - } - /** * Set value */ diff --git a/lib/Interactor/RemoteActions/Pm2Actions.js b/lib/Interactor/RemoteActions/Pm2Actions.js index a6de7c61..bcad7fe2 100644 --- a/lib/Interactor/RemoteActions/Pm2Actions.js +++ b/lib/Interactor/RemoteActions/Pm2Actions.js @@ -9,7 +9,6 @@ var Url = require('url'); var Cipher = require('../Cipher.js'); var PushInteractor = require('../PushInteractor'); var Conf = require('../../Configuration.js'); -var Password = require('../Password.js'); /** * Allowed remote PM2 methods @@ -25,17 +24,17 @@ var PM2_REMOTE_METHOD_ALLOWED = { 'reset' : {}, 'scale' : {}, - 'install' : { password_required : true }, - 'uninstall' : { password_required : true }, - 'stop' : { password_required : true }, - 'delete' : { password_required : true }, + 'install' : {}, + 'uninstall' : {}, + 'stop' : {}, + 'delete' : {}, 'set' : {}, 'multiset' : {}, - 'deepUpdate' : { password_required : true }, + 'deepUpdate' : {}, - 'pullAndRestart' : { password_optional : true }, - 'forward' : { password_optional : true }, - 'backward' : { password_optional : true }, + 'pullAndRestart' : {}, + 'forward' : {}, + 'backward' : {}, 'startLogging' : {}, 'stopLogging' : {}, @@ -44,7 +43,7 @@ var PM2_REMOTE_METHOD_ALLOWED = { 'resetFileCache': {}, // This is just for testing purproses - 'ping' : { password_required : true } + 'ping' : {} }; var Pm2Actions = module.exports = { @@ -272,28 +271,6 @@ var Pm2Actions = module.exports = { var action_conf = PM2_REMOTE_METHOD_ALLOWED[action_name]; - /** - * Password checking - */ - if (action_conf.password_required === true) { - if (!msg.password) { - console.error('Missing password in query'); - return cb('Missing password in query'); - } - - var passwd = Conf.getSync('pm2:passwd'); - - if (passwd === null) { - console.error('Password at PM2 level is missing'); - return cb('Password at PM2 level is missing please set password via pm2 set pm2:passwd '); - } - - if (Password.verify(msg.password, passwd) != true) { - console.error('Password does not match'); - return cb('Password does not match'); - } - } - if (action_conf.lock === false) opts.lock = false; diff --git a/test/interface/password.mocha.js b/test/interface/password.mocha.js deleted file mode 100644 index 68772fd5..00000000 --- a/test/interface/password.mocha.js +++ /dev/null @@ -1,20 +0,0 @@ - -var Password = require('../../lib/Interactor/Password.js'); -var should = require('should'); - -describe('Password test', function() { - var crypted = ''; - - it('should crypt a password', function() { - crypted = Password.generate('testpass'); - }); - - it('should fail with wrong password', function() { - Password.verify('testpasds', crypted).should.be.false; - }); - - it('should success with right password', function() { - Password.verify('testpass', crypted).should.be.true; - }); - -}); From 0914e2a7bcca68466ad64b52d94ef096cde4505f Mon Sep 17 00:00:00 2001 From: Robin Monnier Date: Thu, 15 Mar 2018 15:52:23 +0100 Subject: [PATCH 044/140] add spacing to examples --- bin/pm2 | 2 ++ 1 file changed, 2 insertions(+) diff --git a/bin/pm2 b/bin/pm2 index c15b9a56..1e19ead7 100755 --- a/bin/pm2 +++ b/bin/pm2 @@ -120,9 +120,11 @@ commander.version(pkg.version) console.log(chalk.cyan(' $ pm2 restart app')); console.log(''); console.log('- Clusterize an app to all CPU cores available:'); + console.log(''); console.log(chalk.cyan(' $ pm2 start -i max')); console.log(''); console.log('- Update pm2 :'); + console.log(''); console.log(chalk.cyan(' $ npm install pm2 -g && pm2 update')); console.log(''); console.log('- Install pm2 auto completion:') From 716b191ae8cadca611b729b53e219b988df32b0b Mon Sep 17 00:00:00 2001 From: Robin Monnier Date: Thu, 15 Mar 2018 17:37:01 +0100 Subject: [PATCH 045/140] add documentation to schema.json --- lib/API/schema.json | 326 ++++++++++++++++++++++++++++---------------- 1 file changed, 210 insertions(+), 116 deletions(-) diff --git a/lib/API/schema.json b/lib/API/schema.json index d650a73d..a7d7984e 100644 --- a/lib/API/schema.json +++ b/lib/API/schema.json @@ -2,23 +2,87 @@ "script": { "type": "string", "require": true, - "alias" : "exec" + "alias" : "exec", + "docDescription": "Path of the script to launch, required field" + }, + "name": { + "type": "string", + "docDefault": "Script filename without the extension (app for app.js)", + "docDescription": "Process name in the process list" + }, + "cwd": { + "type": "string", + "docDefault": "CWD of the current environment (from your shell)", + "docDescription": "Current working directory to start the process with" }, "args": { "type": [ "array", "string" - ] + ], + "docDescription": "Arguments to pass to the script" + }, + "exec_interpreter": { + "type": "string", + "alias": "interpreter", + "docDefault": "node", + "docDescription": "Interpreter absolute path" }, "node_args": { "type": [ "array", "string" ], - "alias": ["interpreterArgs", "interpreter_args"] + "alias": ["interpreter_args"], + "docDescription": "Arguments to pass to the interpreter" }, - "name": { - "type": "string" + "out_file": { + "type": "string", + "alias": ["out", "output", "out_log"], + "docDefault": "~/.pm2/logs/-out.log", + "docDescription": "File path for stdout (each line is appended to this file)" + }, + "error_file": { + "type": "string", + "alias": ["error", "err", "err_file", "err_log"], + "docDefault": "~/.pm2/logs/-error.err", + "docDescription": "File path for stderr (each line is appended to this file)" + }, + "log_file": { + "type": [ + "boolean", + "string" + ], + "alias": "log", + "docDefault": "/dev/null", + "docDescription": "File path for combined stdout and stderr (each line is appended to this file)" + }, + "disable_logs": { + "type": "boolean", + "docDefault": false, + "docDescription": "Disable all logs storage" + }, + "log_type": { + "type": "string", + "docDescription": "Define a specific log output type, possible value: json" + }, + "log_date_format": { + "type": "string", + "docDescription": "Format for log timestamps in moment.js format (eg YYYY-MM-DD HH:mm Z)" + }, + "env": { + "type": [ + "object", + "string" + ], + "docDescription": "Specify environment variables to be injected" + }, + "^env_\\S*$": { + "type": [ + "object", + "string" + ], + "docDescription": "Specify environment variables to be injected when using --env " }, "max_memory_restart": { "type": [ @@ -27,124 +91,91 @@ ], "regex": "^\\d+(G|M|K)?$", "ext_type": "sbyte", - "desc": "it should be a NUMBER - byte, \"[NUMBER]G\"(Gigabyte), \"[NUMBER]M\"(Megabyte) or \"[NUMBER]K\"(Kilobyte)" - }, - "uid" : { - "type" : "string" - }, - "gid" : { - "type" : "string" - }, - "restart_delay": { - "type" : "number" - }, - "source_map_support" : { - "type": "boolean" - }, - "wait_ready" : { - "type": "boolean" - }, - "disable_source_map_support" : { - "type": "boolean" - }, - "instances": { - "type": "number" - }, - "kill_timeout": { - "type": "number" - }, - "listen_timeout": { - "type": "number" - }, - "port": { - "type": "number" - }, - "log_file": { - "type": [ - "boolean", - "string" - ], - "alias": "log" - }, - "error_file": { - "type": "string", - "alias": ["error", "err", "err_file", "err_log"] - }, - "log_type": { - "type": "string" - }, - "out_file": { - "type": "string", - "alias": ["output", "out", "out_log"] + "desc": "it should be a NUMBER - byte, \"[NUMBER]G\"(Gigabyte), \"[NUMBER]M\"(Megabyte) or \"[NUMBER]K\"(Kilobyte)", + "docDescription": "Restart the app if an amount of memory is exceeded (format: /[0-9](K|M|G)?/ K for KB, 'M' for MB, 'G' for GB, default to B)" }, "pid_file": { "type": "string", - "alias": "pid" + "alias": "pid", + "docDefault": "~/.pm2/pids/app_name-id.pid", + "docDescription": "File path where the pid of the started process is written by pm2" + }, + "restart_delay": { + "type" : "number", + "docDefault": 0, + "docDescription": "Time in ms to wait before restarting a crashing app" + }, + "source_map_support": { + "type": "boolean", + "docDefault": true, + "docDescription": "Enable or disable the source map support" + }, + "disable_source_map_support": { + "type": "boolean", + "docDefault": false, + "docDescription": "Enable or disable the source map support" + }, + "wait_ready": { + "type": "boolean", + "docDefault": false, + "docDescription": "Make the process wait for a process.send('ready')" + }, + "instances": { + "type": "number", + "docDefault": 1, + "docDescription": "Number of instances to be started in cluster mode" + }, + "kill_timeout": { + "type": "number", + "docDefault": 1600, + "docDescription": "Time in ms before sending the final SIGKILL signal after SIGINT" + }, + "listen_timeout": { + "type": "number", + "docDescription": "Time in ms before forcing a reload if app is still not listening/has still note sent ready" }, "cron_restart": { "type": "string", - "alias": "cron" - }, - "cwd": { - "type": "string" + "alias": "cron", + "docDescription": "A cron pattern to restart your app" }, "merge_logs": { "type": "boolean", - "alias" : "combine_logs" + "alias" : "combine_logs", + "docDefault": false, + "docDescription": "In cluster mode, merge each type of logs into a single file (instead of having one for each cluster)" }, - "vizion" : { + "vizion": { "type": "boolean", - "default" : true + "default" : true, + "docDefault" : "True", + "docDescription": "Enable or disable the versioning metadatas (vizion library)" }, - "pmx" : { + "autorestart": { "type": "boolean", - "default" : true - }, - "automation" : { - "type": "boolean", - "default" : true - }, - "autorestart" : { - "type": "boolean", - "default" : true - }, - "treekill" : { - "type": "boolean", - "default" : true + "default": true, + "docDefault": "True", + "docDescription": "Enable or disable auto restart after process failure" }, "watch": { "type": [ "boolean", "array", "string" - ] + ], + "docDefault": false, + "docDescription": "Enable or disable the watch mode" }, "ignore_watch": { "type": [ "array", "string" - ] + ], + "docDescription": "List of paths to ignore (regex)" }, "watch_options": { - "type": "object" - }, - "env": { - "type": [ - "object", - "string" - ] - }, - "^env_\\S*$": { - "type": [ - "object", - "string" - ] - }, - "disable_logs" : { - "type": "boolean" - }, - "log_date_format": { - "type": "string" + "type": "object", + "docDescription": "Object that will be used as an options with chokidar (refer to chokidar documentation)" }, "min_uptime": { "type": [ @@ -154,40 +185,63 @@ "regex": "^\\d+(h|m|s)?$", "desc": "it should be a NUMBER - milliseconds, \"[NUMBER]h\"(hours), \"[NUMBER]m\"(minutes) or \"[NUMBER]s\"(seconds)", "min": 100, - "ext_type": "stime" + "ext_type": "stime", + "docDefault": 1000, + "docDescription": "Minimum uptime of the app to be considered started (format is /[0-9]+(h|m|s)?/, for hours, minutes, seconds, docDefault to ms)" }, "max_restarts": { "type": "number", - "min": 0 + "min": 0, + "docDefault": 16, + "docDescription": "Number of times a script is restarted when it exits in less than min_uptime" }, "exec_mode": { "type": "string", "regex": "^(cluster|fork)(_mode)?$", "alias": "executeCommand", - "desc": "it should be \"cluster\"(\"cluster_mode\") or \"fork\"(\"fork_mode\") only" - }, - "exec_interpreter": { - "type": "string", - "alias": "interpreter" - }, - "write": { - "type": "boolean" + "desc": "it should be \"cluster\"(\"cluster_mode\") or \"fork\"(\"fork_mode\") only", + "docDefault": "fork", + "docDescription": "Set the execution mode, possible values: fork|cluster" }, "force": { - "type": "boolean" + "type": "boolean", + "docDefault": false, + "docDescription": "Start a script even if it is already running (only the script path is considered)" }, "append_env_to_name": { - "type": "boolean" + "type": "boolean", + "docDefault": false, + "docDescription": "Append the environment name to the app name" }, "post_update": { - "type": "array" + "type": "array", + "docDescription": "List of commands executed after a pull/upgrade operation performed from Keymetrics dashboard" + }, + "trace": { + "type": [ + "boolean" + ], + "docDefault": false, + "docDescription": "Enable or disable the transaction tracing" }, "disable_trace": { + "type": [ + "boolean" + ], + "docDefault": true, + "docDescription": "Enable or disable the transaction tracing" + }, + "v8": { "type": [ "boolean" ] }, - "trace": { + "event_loop_inspector": { + "type": [ + "boolean" + ] + }, + "deep_monitoring": { "type": [ "boolean" ] @@ -208,14 +262,54 @@ ] }, "increment_var": { - "type": "string" + "type": "string", + "docDescription": "Specify the name of an environment variable to inject which increments for each cluster" }, "instance_var": { "type": "string", - "default" : "NODE_APP_INSTANCE" -}, + "default": "NODE_APP_INSTANCE", + "docDefault": "NODE_APP_INSTANCE", + "docDescription": "Rename the NODE_APP_INSTANCE environment variable" + }, + "pmx": { + "type": "boolean", + "default": true, + "docDefault": "True", + "docDescription": "Enable or disable pmx wrapping" + }, + "automation": { + "type": "boolean", + "default": true, + "docDefault": "True", + "docDescription": "Enable or disable pmx wrapping" + }, + "treekill": { + "type": "boolean", + "default": true, + "docDefault": "True", + "docDescription": "Only kill the main process, not detached children" + }, + "port": { + "type": "number", + "docDescription": "Shortcut to inject a PORT environment variable" + }, + "uid": { + "type" : "string", + "docDefault": "Current user uid", + "docDescription": "Set user id" + }, + "gid": { + "type" : "string", + "docDefault": "Current user gid", + "docDescription": "Set group id" + }, "windowsHide": { "type": "boolean", - "default" : true + "docDefault": "True", + "docDescription": "Enable or disable the Windows popup when starting an app", + "default": true + }, + "write": { + "type": "boolean" } -} +} \ No newline at end of file From b2cc003114b44f1a9a31876ee4a2f4cb91e210b3 Mon Sep 17 00:00:00 2001 From: KimSeongIl Date: Fri, 16 Mar 2018 10:07:48 +0900 Subject: [PATCH 046/140] feat: add kill_retry_time argument --- lib/API/schema.json | 4 ++++ lib/God/Methods.js | 4 ++-- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/lib/API/schema.json b/lib/API/schema.json index d650a73d..6be87b72 100644 --- a/lib/API/schema.json +++ b/lib/API/schema.json @@ -217,5 +217,9 @@ "windowsHide": { "type": "boolean", "default" : true + }, + "kill_retry_time": { + "type": "number", + "default" : 100 } } diff --git a/lib/God/Methods.js b/lib/God/Methods.js index e7b8e9fa..4904fbd3 100644 --- a/lib/God/Methods.js +++ b/lib/God/Methods.js @@ -167,9 +167,9 @@ module.exports = function(God) { clearInterval(timer); return cb(null, true); } - console.log('pid=%d msg=failed to kill - retrying in 100ms', pid); + console.log('pid=%d msg=failed to kill - retrying in %dms', pid, pm2_env.kill_retry_time); return false; - }, 100); + }, pm2_env.kill_retry_time); timeout = setTimeout(function() { clearInterval(timer); From 269d75e83ba9375897ecf6a7eb48d44ec5230ccc Mon Sep 17 00:00:00 2001 From: abluchet Date: Fri, 16 Mar 2018 12:08:36 +0100 Subject: [PATCH 047/140] Update pidusage --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 4acaa133..3702dbae 100644 --- a/package.json +++ b/package.json @@ -174,7 +174,7 @@ "moment": "^2.19", "needle": "^2.2.0", "nssocket": "0.6.0", - "pidusage": "^1.2.0", + "pidusage": "^2.0.0", "pm2-axon": "3.1.0", "pm2-axon-rpc": "0.5.0", "pm2-deploy": "^0.3.9", From 799c48e77378c35233b14fdea4d0888eb4033b0a Mon Sep 17 00:00:00 2001 From: Robin Monnier Date: Fri, 16 Mar 2018 16:29:13 +0100 Subject: [PATCH 048/140] start ecosystem file with pm2 start by default --- bin/pm2 | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/bin/pm2 b/bin/pm2 index 05072f4b..1f989a22 100755 --- a/bin/pm2 +++ b/bin/pm2 @@ -253,7 +253,7 @@ function patchCommanderArg(cmd) { // // Start command // -commander.command('start ') +commander.command('start [file|json|stdin|app_name|pm_id...]') .option('--watch', 'Watch folder for changes') .option('--fresh', 'Rebuild Dockerfile') .option('--daemon', 'Run container in Daemon mode (debug purposes)') @@ -280,6 +280,9 @@ commander.command('start ') else { // Commander.js patch cmd = patchCommanderArg(cmd); + if (cmd.length === 0) { + cmd = [cst.APP_CONF_DEFAULT_FILE]; + } async.forEachLimit(cmd, 1, function(script, next) { pm2.start(script, commander, next); }, function(err) { From b26efa0d4cd72cf04762df7b7d2eaddc4f4117d2 Mon Sep 17 00:00:00 2001 From: Robin Monnier Date: Fri, 16 Mar 2018 17:40:23 +0100 Subject: [PATCH 049/140] fix bug with interpreter args --- lib/API/schema.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/API/schema.json b/lib/API/schema.json index a7d7984e..79bef624 100644 --- a/lib/API/schema.json +++ b/lib/API/schema.json @@ -33,7 +33,7 @@ "array", "string" ], - "alias": ["interpreter_args"], + "alias": ["interpreterArgs", "interpreter_args"], "docDescription": "Arguments to pass to the interpreter" }, "out_file": { @@ -312,4 +312,4 @@ "write": { "type": "boolean" } -} \ No newline at end of file +} From 2506c75956a0fd7223330ad9493bc63b8adae6ed Mon Sep 17 00:00:00 2001 From: Eywek Date: Thu, 15 Mar 2018 16:41:28 +0100 Subject: [PATCH 050/140] improv: use keymetrics-agent --- lib/API.js | 2 +- lib/API/Configuration.js | 2 +- lib/API/Interaction.js | 12 +- lib/API/Keymetrics/cli-api.js | 9 +- lib/Client.js | 9 +- lib/Common.js | 2 +- lib/Interactor/Cipher.js | 50 -- lib/Interactor/Daemon.js | 443 ------------ lib/Interactor/Filter.js | 124 ---- lib/Interactor/HttpRequest.js | 86 --- lib/Interactor/InteractorDaemonizer.js | 535 -------------- lib/Interactor/Password.js | 71 -- lib/Interactor/PushInteractor.js | 380 ---------- lib/Interactor/RemoteActions/CustomActions.js | 92 --- lib/Interactor/RemoteActions/Pm2Actions.js | 322 --------- .../RemoteActions/ScopedExecution.js | 34 - lib/Interactor/ReverseInteractor.js | 128 ---- lib/Interactor/TransactionAggregator.js | 684 ------------------ lib/Interactor/Utility.js | 235 ------ lib/Interactor/WatchDog.js | 69 -- lib/Interactor/internal-ip.js | 40 - lib/Interactor/pm2-interface.js | 122 ---- lib/Satan.js | 4 +- package.json | 1 + test/interface/aggregator.mocha.js | 239 ------ test/interface/bus.fork.spec.mocha.js | 1 - test/interface/bus.spec.mocha.js | 1 - test/interface/cache.mocha.js | 86 --- test/interface/custom-actions.mocha.js | 169 ----- test/interface/exception.e2e.mocha.js | 88 --- test/interface/filter.mocha.js | 23 - test/interface/interactor.connect.mocha.js | 227 ------ test/interface/interactor.daemonizer.mocha.js | 164 ----- test/interface/misc/trace.json | 167 ----- test/interface/misc/trace_factory.js | 146 ---- test/interface/monitor.mocha.js | 90 --- test/interface/push_interactor.mocha.js | 78 -- test/interface/remote.mocha.js | 249 ------- test/interface/request.mocha.js | 91 --- test/interface/scoped_pm2_actions.mocha.js | 258 ------- test/interface/stacktrace.mocha.js | 157 ---- 41 files changed, 26 insertions(+), 5664 deletions(-) delete mode 100644 lib/Interactor/Cipher.js delete mode 100644 lib/Interactor/Daemon.js delete mode 100644 lib/Interactor/Filter.js delete mode 100644 lib/Interactor/HttpRequest.js delete mode 100644 lib/Interactor/InteractorDaemonizer.js delete mode 100644 lib/Interactor/Password.js delete mode 100644 lib/Interactor/PushInteractor.js delete mode 100644 lib/Interactor/RemoteActions/CustomActions.js delete mode 100644 lib/Interactor/RemoteActions/Pm2Actions.js delete mode 100644 lib/Interactor/RemoteActions/ScopedExecution.js delete mode 100644 lib/Interactor/ReverseInteractor.js delete mode 100644 lib/Interactor/TransactionAggregator.js delete mode 100644 lib/Interactor/Utility.js delete mode 100644 lib/Interactor/WatchDog.js delete mode 100644 lib/Interactor/internal-ip.js delete mode 100644 lib/Interactor/pm2-interface.js delete mode 100644 test/interface/aggregator.mocha.js delete mode 100644 test/interface/cache.mocha.js delete mode 100644 test/interface/custom-actions.mocha.js delete mode 100644 test/interface/exception.e2e.mocha.js delete mode 100644 test/interface/filter.mocha.js delete mode 100644 test/interface/interactor.connect.mocha.js delete mode 100644 test/interface/interactor.daemonizer.mocha.js delete mode 100644 test/interface/misc/trace.json delete mode 100644 test/interface/misc/trace_factory.js delete mode 100644 test/interface/monitor.mocha.js delete mode 100644 test/interface/push_interactor.mocha.js delete mode 100644 test/interface/remote.mocha.js delete mode 100644 test/interface/request.mocha.js delete mode 100644 test/interface/scoped_pm2_actions.mocha.js delete mode 100644 test/interface/stacktrace.mocha.js diff --git a/lib/API.js b/lib/API.js index 59bc227f..8fda0b4e 100644 --- a/lib/API.js +++ b/lib/API.js @@ -16,7 +16,7 @@ var fclone = require('fclone'); var conf = require('../constants.js'); var Client = require('./Client'); var Common = require('./Common'); -var KMDaemon = require('./Interactor/InteractorDaemonizer'); +var KMDaemon = require('keymetrics-agent/src/InteractorClient'); var Config = require('./tools/Config'); var Modularizer = require('./API/Modules/Modularizer.js'); var path_structure = require('../paths.js'); diff --git a/lib/API/Configuration.js b/lib/API/Configuration.js index 17ce16c7..cebc8529 100644 --- a/lib/API/Configuration.js +++ b/lib/API/Configuration.js @@ -6,7 +6,7 @@ var chalk = require('chalk'); var async = require('async'); var Configuration = require('../Configuration.js'); //@todo double check that imported methods works -var InteractorDaemonizer = require('../Interactor/InteractorDaemonizer'); +var InteractorDaemonizer = require('keymetrics-agent/src/InteractorClient'); module.exports = function(CLI) { diff --git a/lib/API/Interaction.js b/lib/API/Interaction.js index 1bde2cd7..8d9557d4 100644 --- a/lib/API/Interaction.js +++ b/lib/API/Interaction.js @@ -6,7 +6,8 @@ var chalk = require('chalk'); var async = require('async'); var path = require('path'); var fs = require('fs'); -var KMDaemon = require('../Interactor/InteractorDaemonizer'); +var KMDaemon = require('keymetrics-agent/src/InteractorClient'); +var pkg = require('../../package.json') module.exports = function(CLI) { @@ -45,7 +46,8 @@ module.exports = function(CLI) { KMDaemon.launchAndInteract(that._conf, { secret_key : secret_key || null, public_key : public_key || null, - machine_name : machine_name || null + machine_name : machine_name || null, + pm2_version: pkg.version }, function(err, dt) { if (err) { return cb ? cb(err) : that.exitCli(cst.ERROR_EXIT); @@ -118,7 +120,8 @@ module.exports = function(CLI) { public_key : null, secret_key : null, machine_name : null, - info_node : null + info_node : null, + pm2_version: pkg.version }, function(err, dt) { if (err) { Common.printError(err); @@ -143,7 +146,8 @@ module.exports = function(CLI) { public_key : public_key, secret_key : cmd, machine_name : machine, - info_node : info_node.infoNode || null + info_node : info_node.infoNode || null, + pm2_version: pkg.version } KMDaemon.launchAndInteract(that._conf, infos, function(err, dt) { diff --git a/lib/API/Keymetrics/cli-api.js b/lib/API/Keymetrics/cli-api.js index 3ad3ea03..18107f85 100644 --- a/lib/API/Keymetrics/cli-api.js +++ b/lib/API/Keymetrics/cli-api.js @@ -5,11 +5,12 @@ var chalk = require('chalk'); var async = require('async'); var path = require('path'); var fs = require('fs'); -var KMDaemon = require('../../Interactor/InteractorDaemonizer'); +var KMDaemon = require('keymetrics-agent/src/InteractorClient'); var KM = require('./kmapi.js'); var Table = require('cli-table-redemption'); var open = require('../../tools/open.js'); var promptly = require('promptly'); +var pkg = require('../../../package.json') module.exports = function(CLI) { @@ -127,7 +128,8 @@ module.exports = function(CLI) { function linkOpenExit(target_bucket) { KMDaemon.launchAndInteract(cst, { public_key : target_bucket.public_id, - secret_key : target_bucket.secret_id + secret_key : target_bucket.secret_id, + pm2_version: pkg.version }, function(err, dt) { open('https://app.keymetrics.io/#/r/' + target_bucket.public_id); setTimeout(function() { @@ -194,7 +196,8 @@ module.exports = function(CLI) { KMDaemon.launchAndInteract(cst, { public_key : target_bucket.public_id, - secret_key : target_bucket.secret_id + secret_key : target_bucket.secret_id, + pm2_version: pkg.version }, function(err, dt) { linkOpenExit(target_bucket); }); diff --git a/lib/Client.js b/lib/Client.js index 74103fd3..d3be47a6 100644 --- a/lib/Client.js +++ b/lib/Client.js @@ -6,7 +6,7 @@ var debug = require('debug')('pm2:client'); var Common = require('./Common.js'); -var KMDaemon = require('./Interactor/InteractorDaemonizer.js'); +var KMDaemon = require('keymetrics-agent/src/InteractorClient'); var rpc = require('pm2-axon-rpc'); var async = require('async'); var axon = require('pm2-axon'); @@ -15,6 +15,7 @@ var fs = require('fs'); var path = require('path'); var mkdirp = require('mkdirp'); var shelljs = require('shelljs'); +var pkg = require('../package.json') function noop() {} @@ -79,7 +80,8 @@ Client.prototype.start = function(cb) { KMDaemon.launchAndInteract(that.conf, { machine_name : that.machine_name, public_key : that.public_key, - secret_key : that.secret_key + secret_key : that.secret_key, + pm2_version : pkg.version }, function(err, data, interactor_proc) { that.interactor_process = interactor_proc; }); @@ -278,7 +280,8 @@ Client.prototype.launchDaemon = function(opts, cb) { KMDaemon.launchAndInteract(that.conf, { machine_name : that.machine_name, public_key : that.public_key, - secret_key : that.secret_key + secret_key : that.secret_key, + pm2_version : pkg.version }, function(err, data, interactor_proc) { that.interactor_process = interactor_proc; return cb(null, child); diff --git a/lib/Common.js b/lib/Common.js index 2dd053aa..b944b742 100644 --- a/lib/Common.js +++ b/lib/Common.js @@ -23,7 +23,7 @@ var isBinary = require('./tools/isbinaryfile.js'); var cst = require('../constants.js'); var extItps = require('./API/interpreter.json'); var Config = require('./tools/Config'); -var KMDaemon = require('./Interactor/InteractorDaemonizer.js'); +var KMDaemon = require('keymetrics-agent/src/InteractorClient'); var Common = module.exports; diff --git a/lib/Interactor/Cipher.js b/lib/Interactor/Cipher.js deleted file mode 100644 index 1204a3eb..00000000 --- a/lib/Interactor/Cipher.js +++ /dev/null @@ -1,50 +0,0 @@ -/** - * Copyright 2013 the PM2 project authors. All rights reserved. - * Use of this source code is governed by a license that - * can be found in the LICENSE file. - */ - -var crypto = require('crypto'); - -const CIPHER_ALGORITHM = 'aes256'; - -var Cipher = module.exports = {}; - -/** - * Description - * @method decipherMessage - * @param {} msg - * @return ret - */ -Cipher.decipherMessage = function(msg, key) { - var ret = {}; - - try { - var decipher = crypto.createDecipher(CIPHER_ALGORITHM, key); - var decipheredMessage = decipher.update(msg, 'hex', 'utf8'); - decipheredMessage += decipher.final('utf8'); - ret = JSON.parse(decipheredMessage); - } catch(e) { - return null; - } - - return ret; -} - -/** - * Description - * @method cipherMessage - * @param {} data - * @param {} key - * @return - */ -Cipher.cipherMessage = function(data, key) { - try { - var cipher = crypto.createCipher(CIPHER_ALGORITHM, key); - var cipheredData = cipher.update(data, 'utf8', 'hex'); - cipheredData += cipher.final('hex'); - return cipheredData; - } catch(e) { - return null; - } -} diff --git a/lib/Interactor/Daemon.js b/lib/Interactor/Daemon.js deleted file mode 100644 index 4bcf9c78..00000000 --- a/lib/Interactor/Daemon.js +++ /dev/null @@ -1,443 +0,0 @@ -/** - * Copyright 2013 the PM2 project authors. All rights reserved. - * Use of this source code is governed by a license that - * can be found in the LICENSE file. - */ - -var fs = require('fs'); -var ipm2 = require('./pm2-interface.js'); -var rpc = require('pm2-axon-rpc'); -var axon = require('pm2-axon'); -var debug = require('debug')('interface:driver'); // Interface -var chalk = require('chalk'); -var Url = require('url'); -var os = require('os'); -var domain = require('domain'); -var fmt = require('../tools/fmt.js'); -var pkg = require('../../package.json'); -var PM2 = require('../..'); - -var cst = require('../../constants.js'); -var Cipher = require('./Cipher.js'); -var ReverseInteractor = require('./ReverseInteractor.js'); -var PushInteractor = require('./PushInteractor.js'); -var Utility = require('../Utility.js'); -var WatchDog = require('./WatchDog.js'); -var Conf = require('../Configuration.js'); -var HttpRequest = require('./HttpRequest.js'); -var InternalIP = require('./internal-ip.js'); - -global._pm2_password_protected = false; - -// Flag for log streaming status -global._logs = false; - -var Daemon = module.exports = { - connectToPM2 : function() { - return ipm2(); - }, - exit : function() { - var self = this; - - this.opts.pm2_instance.disconnect(function() { - console.log('Connection to PM2 via CLI closed'); - }); - - process.nextTick(function() { - try { - fs.unlinkSync(cst.INTERACTOR_RPC_PORT); - fs.unlinkSync(cst.INTERACTOR_PID_PATH); - } catch(e) {} - - if (self.opts.ipm2) - self.opts.ipm2.disconnect(); - - console.log('Exiting Interactor'); - - if (!this._rpc || !this._rpc.sock) - return process.exit(cst.ERROR_EXIT); - - this._rpc.sock.close(function() { - console.log('RPC closed - Interactor killed'); - process.exit(cst.SUCCESS_EXIT); - }); - }); - }, - 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); - return Daemon.exit(); - }, - passwordSet : function(cb) { - global._pm2_password_protected = true; - return cb(null); - }, - getInfos : function(cb) { - if (self.opts && - self.opts.DAEMON_ACTIVE == true) - 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, - socket_path : cst.INTERACTOR_RPC_PORT, - pm2_home_monitored : cst.PM2_HOME - }); - else { - return cb(null); - } - } - }); - 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, - RECYCLE : this.opts.RECYCLE || false, - MEMORY : memory, - HOSTNAME : os.hostname(), - CPUS : cpu.length - }), this.opts.SECRET_KEY); - - return ciphered_data; - }, - pingKeepAlive : function() { - var self = this; - - (function checkInternet() { - require('dns').lookup('google.com',function(err) { - if (err && (err.code == 'ENOTFOUND' || err.code == 'EAI_AGAIN')) { - if (self.opts._connection_is_up == true) - console.error('[CRITICAL] Internet is unreachable (via DNS lookup strategy)'); - self.opts._connection_is_up = false; - } else { - if (self.opts._connection_is_up == false) { - console.log('[TENTATIVE] Reactivating connection'); - PushInteractor.connectRemote(); - ReverseInteractor.reconnect(); - } - self.opts._connection_is_up = true; - } - setTimeout(checkInternet, 15000); - }); - })(); - }, - changeUrls : function(push_url, reverse) { - if (push_url) - PushInteractor.connectRemote(push_url); - if (reverse) - ReverseInteractor.changeUrl(reverse); - }, - 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); - - /** protect against malformated data **/ - if (!km_data || - !km_data.endpoints || - !km_data.endpoints.push || - !km_data.endpoints.reverse) { - console.error('[CRITICAL] Malformated data received, skipping...'); - return false; - } - - /************************************** - * 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)) { - self.changeUrls(km_data.endpoints.push, km_data.endpoints.reverse); - Daemon.current_km_data = km_data; - } - else { - debug('[REFRESH META] No need to update URL (same)', km_data); - } - return false; - }); - - }; - - // Refresh metadata every minutes - setInterval(function() { - refreshMetadata(); - }, 60000); - }, - 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.RECYCLE = process.env.KM_RECYCLE ? JSON.parse(process.env.KM_RECYCLE) : false; - 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); - } - - var retries = 0; - - function doWelcomeQuery(cb) { - HttpRequest.post({ - url : self.opts.ROOT_URL, - data : { - public_id : self.opts.PUBLIC_KEY, - data : ciphered_data - } - }, function(err, km_data) { - self.current_km_data = km_data; - if (err) { - console.error('Got error while connecting: %s', err.message || err); - - if (retries < 30) { - retries++; - - setTimeout(function() { - doWelcomeQuery(cb); - }, 200 * retries); - return false; - } - return cb(err); - } - - if (self.opts.RECYCLE) { - if (!km_data.name) { - console.error('Error no previous machine name for recycle option returned!'); - } - self.opts.MACHINE_NAME = km_data.name; - }; - - // For Human feedback - if (process.send) { - try { - 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 - }); - } catch(e) { - // Just in case the CLI has been disconected - } - } - // Return get data - return cb(null, km_data); - }) - } - - doWelcomeQuery(function(err, meta) { - return cb(err, meta); - }); - }, - protectedStart : function() { - var self = this; - var d = domain.create(); - - d.once('error', function(err) { - fmt.sep(); - fmt.title('Agent global error caught'); - fmt.field('Time', new Date()); - console.error(err.message); - console.error(err.stack); - fmt.sep(); - - console.error('[Agent] Resurrecting'); - - var KMDaemon = require('../Interactor/InteractorDaemonizer'); - - KMDaemon.rescueStart(cst, function(err, dt) { - if (err) { - console.error('[Agent] Failed to rescue agent, error:'); - console.error(err.message || err); - process.exit(1); - } - console.log('[Agent] Rescued.'); - process.exit(0); - }); - }); - - d.run(function() { - self.start(); - }); - }, - start : function() { - var self = this; - - self.opts = self.validateData(); - self.opts.ipm2 = null; - self.opts.internal_ip = InternalIP(); - self.opts.pm2_instance = PM2; - self.opts._connection_is_up = true; - self.current_km_data = null; - - self.opts.pm2_instance.connect(function() { - console.log('Connected to PM2'); - }); - - self._rpc = self.activateRPC(); - - // Test mode #1 - 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; - } - - if (Conf.getSync('pm2:passwd')) - global._pm2_password_protected = true; - - // Test mode #2 - if (process.env.NODE_ENV == 'local_test') { - self.opts.DAEMON_ACTIVE = true; - - self.opts.ipm2 = self.connectToPM2(); - - PushInteractor.start({ - url : 'http://127.0.0.1:4321', - conf : self.opts - }); - - ReverseInteractor.start({ - url : 'http://127.0.0.1:4322', - conf : self.opts - }); - if (process.send) - process.send({ - success : true, - debug : true - }); - return false; - } - - Daemon.welcome(function(err, km_data) { - if (err) { - if (process.send) - process.send({ - error : true, - msg : err.stack || err - }); - console.log(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.DAEMON_ACTIVE = true; - - self.opts.ipm2 = self.connectToPM2(); - - WatchDog.start({ - conf : self.opts - }); - - 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(); - Daemon.pingKeepAlive(); - } - else { - console.log('Nothing to do, exiting'); - Daemon.exit(); - } - return false; - }); - } -}; - -/** - * MAIN - */ -if (require.main === module) { - console.log(chalk.cyan.bold('[Keymetrics.io]') + ' Launching agent'); - process.title = 'PM2: KM Agent (' + process.env.PM2_HOME + ')'; - - Utility.overrideConsole(); - Daemon.protectedStart(); -} diff --git a/lib/Interactor/Filter.js b/lib/Interactor/Filter.js deleted file mode 100644 index 52f44e6c..00000000 --- a/lib/Interactor/Filter.js +++ /dev/null @@ -1,124 +0,0 @@ -/** - * Copyright 2013 the PM2 project authors. All rights reserved. - * Use of this source code is governed by a license that - * can be found in the LICENSE file. - */ - -/** - * @file Filter process and system data to be sent to server - * @author Alexandre Strzelewicz - * @project Interface - */ - -var os = require('os'); - -var cpu_info = { - number : 0, - info : 'no-data' -}; - -try { - cpu_info = { - number : os.cpus().length, - info : os.cpus()[0].model - }; -} catch(e) { -} - -var SERVER_META = { - totalMem : os.totalmem(), - hostname : os.hostname(), - type : os.type(), - platform : os.platform(), - arch : os.arch() -}; - -var Filter = {}; - -Filter.getProcessID = function(machine_name, name, id) { - return machine_name + ':' + name + ':' + id; -}; - -Filter.machineSnapshot = function(processes, conf) { - if (!processes) return null; - - var filter_procs = []; - - processes.forEach(function(proc) { - if (proc.pm2_env.pm_id.toString().indexOf('_old_') == -1) - filter_procs.push({ - pid : proc.pid, - name : proc.pm2_env.name, - interpreter : proc.pm2_env.exec_interpreter, - restart_time : proc.pm2_env.restart_time, - created_at : proc.pm2_env.created_at, - exec_mode : proc.pm2_env.exec_mode, - watching : proc.pm2_env.watch, - pm_uptime : proc.pm2_env.pm_uptime, - status : proc.pm2_env.status, - pm_id : proc.pm2_env.pm_id, - - cpu : Math.floor(proc.monit.cpu) || 0, - memory : Math.floor(proc.monit.memory) || 0, - - versioning : proc.pm2_env.versioning || null, - - node_env : proc.pm2_env.NODE_ENV || null, - - axm_actions : proc.pm2_env.axm_actions || [], - axm_monitor : proc.pm2_env.axm_monitor || {}, - axm_options : proc.pm2_env.axm_options || {}, - axm_dynamic : proc.pm2_env.dynamic || {} - }); - }); - - var node_version = process.version || ''; - - if (node_version != '') { - if (node_version.indexOf('v1.') === 0 || node_version.indexOf('v2.') === 0 || node_version.indexOf('v3.') === 0) - node_version = 'iojs ' + node_version; - } - var username = process.env.SUDO_USER || process.env.C9_USER || process.env.LOGNAME || - process.env.USER || process.env.LNAME || process.env.USERNAME; - - return { - process : filter_procs, - server : { - loadavg : os.loadavg(), - total_mem : SERVER_META.totalMem, - free_mem : os.freemem(), - cpu : cpu_info, - hostname : SERVER_META.hostname, - uptime : os.uptime(), - type : SERVER_META.type, - platform : SERVER_META.platform, - arch : SERVER_META.arch, - user : username, - interaction : conf.REVERSE_INTERACT, - pm2_version : conf.PM2_VERSION, - node_version : node_version - } - }; -}; - -Filter.monitoring = function(processes, conf) { - if (!processes) return null; - - var filter_procs = {}; - - processes.forEach(function(proc) { - filter_procs[Filter.getProcessID(conf.MACHINE_NAME, proc.pm2_env.name,proc.pm2_env.pm_id)] = [ - Math.floor(proc.monit.cpu), - Math.floor(proc.monit.memory) - ]; - }); - - return { - loadavg : os.loadavg(), - total_mem : SERVER_META.totalMem, - free_mem : os.freemem(), - processes : filter_procs - }; -}; - -module.exports = Filter; diff --git a/lib/Interactor/HttpRequest.js b/lib/Interactor/HttpRequest.js deleted file mode 100644 index 1ade6cc9..00000000 --- a/lib/Interactor/HttpRequest.js +++ /dev/null @@ -1,86 +0,0 @@ -/** - * Copyright 2013 the PM2 project authors. All rights reserved. - * Use of this source code is governed by a license that - * can be found in the LICENSE file. - */ - -var http = require('http'); -var https = require('https'); -var url = require('url') -var debug = require('debug')('interface:http'); - -var HttpRequest = module.exports = {}; - -HttpRequest.post = function(opts, cb) { - if (!(opts.data && opts.url)) { - return cb({ - msg: 'missing parameters', - port: opts.port, - data: opts.data, - url: opts.url - }) - } - - if (!opts.port) { - var parsed = url.parse(opts.url) - if (parsed.hostname && parsed.port) { - opts.port = parseInt(parsed.port) - opts.url = parsed.hostname - } else { - opts.port = 443 - } - } - - var options = { - hostname: opts.url, - path: '/api/node/verifyPM2', - method: 'POST', - port: opts.port, - rejectUnauthorized: false, - headers: { - 'Content-Type': 'application/json', - 'Content-Length': Buffer.byteLength(JSON.stringify(opts.data)) - } - } - - var client = (opts.port === 443) ? https : http; - - var req = client.request(options, function(res){ - var dt = ''; - - res.on('data', function (chunk) { - dt += chunk; - }); - - res.on('end',function(){ - try { - cb(null, JSON.parse(dt)); - } catch(e) { - cb(e); - } - }); - - res.on('error', function(e){ - cb(e); - }); - }); - - req.on('socket', function (socket) { - /** - * Configure request timeout - */ - socket.setTimeout(7000); - socket.on('timeout', function() { - debug('Connection timeout when retrieveing PM2 metadata', options); - req.abort(); - }); - }); - - req.on('error', function(e) { - cb(e); - }); - - req.write(JSON.stringify(opts.data)); - - req.end(); -}; diff --git a/lib/Interactor/InteractorDaemonizer.js b/lib/Interactor/InteractorDaemonizer.js deleted file mode 100644 index 2d87715f..00000000 --- a/lib/Interactor/InteractorDaemonizer.js +++ /dev/null @@ -1,535 +0,0 @@ -/** - * Copyright 2013 the PM2 project authors. All rights reserved. - * Use of this source code is governed by a license that - * can be found in the LICENSE file. - */ - -'use strict'; - -var debug = require('debug')('pm2:interface:daemon'); -var fs = require('fs'); -var path = require('path'); -var util = require('util'); -var rpc = require('pm2-axon-rpc'); -var axon = require('pm2-axon'); -var chalk = require('chalk'); -var os = require('os'); -var cst = require('../../constants.js'); -var Common = require('../Common'); -var json5 = require('../tools/json5.js'); -var UX = require('../API/CliUx.js'); - -var InteractorDaemonizer = module.exports = {}; - -InteractorDaemonizer.rpc = {}; - -/** - * Description - * @method ping - * @param {} cb - * @return - */ -InteractorDaemonizer.ping = function(conf, cb) { - var req = axon.socket('req'); - var client = new rpc.Client(req); - - debug('[PING INTERACTOR] Trying to connect to Interactor daemon'); - - client.sock.once('reconnect attempt', function() { - client.sock.close(); - debug('Interactor Daemon not launched'); - return cb(false); - }); - - client.sock.once('connect', function() { - client.sock.once('close', function() { - return cb(true); - }); - client.sock.close(); - debug('Interactor Daemon alive'); - }); - - client.sock.once('error', function(e) { - if (e.code == 'EACCES') { - fs.stat(conf.INTERACTOR_RPC_PORT, function(e, stats) { - if (stats.uid === 0) { - console.error(conf.PREFIX_MSG_ERR + 'Permission denied, activate current user:'); - console.log(chalk.bold('$sudo chown ' + process.env.USER + ':' + process.env.USER + ' ' + conf.INTERACTOR_RPC_PORT)); - return process.exit(1); - } - }); - } - }); - - req.connect(conf.INTERACTOR_RPC_PORT); -}; - -InteractorDaemonizer.killInteractorDaemon = function(conf, cb) { - process.env.PM2_INTERACTOR_PROCESSING = true; - - debug('Killing interactor #1 ping'); - InteractorDaemonizer.ping(conf, function(online) { - debug('Interactor online', online); - - if (!online) { - if (!cb) Common.printError('Interactor not launched'); - - return cb(new Error('Interactor not launched')); - } - - InteractorDaemonizer.launchRPC(conf, function(err, data) { - if (err) { - setTimeout(function() { - InteractorDaemonizer.disconnectRPC(cb); - }, 100); - return false; - } - InteractorDaemonizer.rpc.kill(function(err) { - if (err) Common.printError(err); - setTimeout(function() { - InteractorDaemonizer.disconnectRPC(cb); - }, 100); - }); - return false; - }); - return false; - }); -}; - -/** - * Description - * @method launchRPC - * @param {} cb - * @return - */ -InteractorDaemonizer.launchRPC = function(conf, cb) { - var self = this; - var req = axon.socket('req'); - this.client = new rpc.Client(req); - - debug('Generating methods'); - - /** - * Description - * @method generateMethods - * @param {} cb - * @return - */ - var generateMethods = function(cb) { - self.client.methods(function(err, methods) { - Object.keys(methods).forEach(function(key) { - var method_signature = methods[key]; - debug('+-- Creating %s method', method_signature.name); - - (function(name) { - /** - * Description - * @method name - * @return - */ - self.rpc[name] = function() { - var args = Array.prototype.slice.call(arguments); - args.unshift(name); - self.client.call.apply(self.client, args); - }; - })(method_signature.name); - - }); - return cb(); - }); - }; - - this.client.sock.once('reconnect attempt', function(e) { - self.client.sock.removeAllListeners(); - return cb({success:false, msg:'reconnect attempt'}); - }); - - this.client.sock.once('error', function(e) { - console.error('Error in error catch all on Interactor'); - console.error(e.stack || e); - }); - - this.client.sock.once('connect', function() { - self.client.sock.removeAllListeners(); - generateMethods(function() { - debug('Methods generated'); - cb(null, {success:true}); - }); - }); - - this.client_sock = req.connect(conf.INTERACTOR_RPC_PORT); -}; - -/** - * Description - * @method launchOrAttach - * @param {} secret_key - * @param {} public_key - * @param {} machine_name - * @param {} cb - * @return - */ -function launchOrAttach(conf, infos, cb) { - InteractorDaemonizer.ping(conf, function(online) { - if (online) { - debug('Interactor online, restarting it...'); - InteractorDaemonizer.launchRPC(conf, function() { - InteractorDaemonizer.rpc.kill(function(err) { - daemonize(conf, infos, function(err, msg, proc) { - return cb(err, msg, proc); - }); - }); - }); - } - else { - debug('Interactor offline, launching it...'); - daemonize(conf, infos, function(err, msg, proc) { - return cb(err, msg, proc); - }); - } - return false; - }); -}; - -/** - * Description - * @method daemonize - * @param {} secret_key - * @param {} public_key - * @param {} machine_name - * @param {} cb - * @return - */ -var daemonize = function(conf, infos, cb) { - var InteractorJS = path.resolve(path.dirname(module.filename), 'Daemon.js'); - - var out = null; - var err = null; - - if (process.env.TRAVIS || process.env.NODE_ENV == 'local_test') { - // Redirect PM2 internal err and out - // to STDERR STDOUT when running with Travis - out = 1; - err = 2; - } - else { - out = fs.openSync(conf.INTERACTOR_LOG_FILE_PATH, 'a'); - err = fs.openSync(conf.INTERACTOR_LOG_FILE_PATH, 'a'); - } - - var child = require('child_process').spawn('node', [InteractorJS], { - silent : false, - detached : true, - cwd : process.cwd(), - env : util._extend({ - PM2_HOME : conf.PM2_HOME, - PM2_MACHINE_NAME : infos.machine_name, - PM2_SECRET_KEY : infos.secret_key, - PM2_PUBLIC_KEY : infos.public_key, - PM2_REVERSE_INTERACT : infos.reverse_interact, - KEYMETRICS_NODE : infos.info_node - }, process.env), - stdio : ['ipc', out, err] - }); - - console.log('[KM] Connecting'); - - fs.writeFileSync(conf.INTERACTOR_PID_PATH, child.pid); - - function onError(msg) { - debug('Error when launching Interactor, please check the agent logs'); - return cb(msg); - } - - child.once('error', onError); - - child.unref(); - - var t = setTimeout(function() { - Common.printOut(cst.PREFIX_MSG_WARNING + ' Not managed to connect to Keymetrics, retrying in background. (check %s)', cst.INTERACTOR_LOG_FILE_PATH); - child.removeAllListeners('message'); - child.removeAllListeners('error'); - child.disconnect(); - return cb(null, {}, child); - }, 7000); - - child.once('message', function(msg) { - clearTimeout(t); - debug('Interactor daemon launched', msg); - - if (msg.debug) { - return cb(null, msg, child); - } - - child.removeAllListeners('error'); - child.disconnect(); - - /***************** - * Error messages - */ - if (msg.error == true) { - console.log(chalk.red('[Keymetrics.io][ERROR]'), msg.msg); - console.log(chalk.cyan('[Keymetrics.io]') + ' Contact support contact@keymetrics.io and send us the error message'); - return cb(msg); - } - - if (msg.km_data.disabled == true) { - console.log(chalk.cyan('[Keymetrics.io]') + ' Server DISABLED BY ADMINISTRATION contact support contact@keymetrics.io with reference to your public and secret keys)'); - return cb(msg); - } - - if (msg.km_data.error == true) { - console.log(chalk.red('[Keymetrics.io][ERROR]') + ' ' + msg.km_data.msg + ' (Public: %s) (Secret: %s) (Machine name: %s)', msg.public_key, msg.secret_key, msg.machine_name); - return cb(msg); - } - - else if (msg.km_data.active == false && msg.km_data.pending == true) { - console.log(chalk.red('[Keymetrics.io]') + ' ' + chalk.bold.red('Agent PENDING') + ' - Web Access: https://app.keymetrics.io/'); - console.log(chalk.red('[Keymetrics.io]') + ' You must upgrade your bucket in order to monitor more servers.'); - - return cb(msg); - } - - if (msg.km_data.active == true) { - console.log(chalk.green.bold('[Monitoring Enabled]') + ' Dashboard access: https://app.keymetrics.io/#/r/%s', msg.public_key); - return cb(null, msg, child); - } - - return cb(null, msg, child); - }); - -}; - -InteractorDaemonizer.update = function(conf, cb) { - InteractorDaemonizer.ping(conf, function(online) { - if (!online) { - Common.printError('Interactor not launched'); - return cb(new Error('Interactor not launched')); - } - InteractorDaemonizer.launchRPC(conf, function() { - InteractorDaemonizer.rpc.kill(function(err) { - if (err) { - Common.printError(err); - return cb(new Error(err)); - } - Common.printOut('Interactor successfully killed'); - setTimeout(function() { - InteractorDaemonizer.launchAndInteract(conf, {}, function() { - return cb(null, {msg : 'Daemon launched'}); - }); - }, 500); - }); - }); - return false; - }); -}; - -/** - * Get/Update/Merge agent configuration - * @param {object} _infos - */ -InteractorDaemonizer.getOrSetConf = function(conf, infos, cb) { - var reverse_interact = true; - var version_management_active = true; - var version_management_password = null; - var secret_key; - var public_key; - var machine_name; - var info_node; - var new_connection = false; - - // 1# Load configuration file - try { - var interaction_conf = json5.parse(fs.readFileSync(conf.INTERACTION_CONF)); - - public_key = interaction_conf.public_key; - machine_name = interaction_conf.machine_name; - secret_key = interaction_conf.secret_key; - info_node = interaction_conf.info_node; - - reverse_interact = interaction_conf.reverse_interact || true; - - if (interaction_conf.version_management) { - version_management_password = interaction_conf.version_management.password || version_management_password; - version_management_active = interaction_conf.version_management.active || version_management_active; - } - } catch (e) { - debug('Interaction file does not exists'); - } - - // 2# Override with passed informations - if (infos) { - if (infos.secret_key) - secret_key = infos.secret_key; - - if (infos.public_key) - public_key = infos.public_key; - - if (infos.machine_name) - machine_name = infos.machine_name; - - if (infos.info_node) - info_node = infos.info_node; - - new_connection = true; - } - - // 3# Override with environment variables (highest-priority conf) - if (process.env.PM2_SECRET_KEY || process.env.KEYMETRICS_SECRET) - secret_key = process.env.PM2_SECRET_KEY || process.env.KEYMETRICS_SECRET; - - if (process.env.PM2_PUBLIC_KEY || process.env.KEYMETRICS_PUBLIC) - public_key = process.env.PM2_PUBLIC_KEY || process.env.KEYMETRICS_PUBLIC; - - if (new_connection && info_node == null) - info_node = process.env.KEYMETRICS_NODE || cst.KEYMETRICS_ROOT_URL; - - if (!info_node) - info_node = cst.KEYMETRICS_ROOT_URL; - - if (!secret_key) - return cb(new Error('secret key is not defined')); - - if (!public_key) - return cb(new Error('public key is not defined')); - - if (!machine_name) - machine_name = os.hostname() + '-' + require('crypto').randomBytes(4).toString('hex'); - - /** - * Write new data to configuration file - */ - try { - var new_interaction_conf = { - secret_key : secret_key, - public_key : public_key, - machine_name : machine_name, - reverse_interact : reverse_interact, - info_node : info_node, - version_management : { - active : version_management_active, - password : version_management_password - } - }; - fs.writeFileSync(conf.INTERACTION_CONF, json5.stringify(new_interaction_conf, null, 4)); - } catch(e) { - console.error('Error when writting configuration file %s', conf.INTERACTION_CONF); - return cb(e); - } - - // Don't block the event loop - process.nextTick(function() { - cb(null, new_interaction_conf); - }); -}; - -InteractorDaemonizer.disconnectRPC = function(cb) { - if (!InteractorDaemonizer.client_sock || - !InteractorDaemonizer.client_sock.close) - return cb(null, { - success : false, - msg : 'RPC connection to Interactor Daemon is not launched' - }); - - if (InteractorDaemonizer.client_sock.connected === false || - InteractorDaemonizer.client_sock.closing === true) { - return cb(null, { - success : false, - msg : 'RPC closed' - }); - } - - try { - var timer; - - debug('Closing RPC INTERACTOR'); - - InteractorDaemonizer.client_sock.once('close', function() { - debug('RPC INTERACTOR cleanly closed'); - clearTimeout(timer); - return cb ? cb(null, {success:true}) : false; - }); - - timer = setTimeout(function() { - if (InteractorDaemonizer.client_sock.destroy) - InteractorDaemonizer.client_sock.destroy(); - return cb ? cb(null, {success:true}) : false; - }, 200); - - InteractorDaemonizer.client_sock.close(); - } catch(e) { - debug('Error while closing RPC INTERACTOR', e.stack || e); - return cb ? cb(e.stack || e) : false; - } - return false; -}; - -InteractorDaemonizer.rescueStart = function(conf, cb) { - InteractorDaemonizer.getOrSetConf(conf, null, function(err, infos) { - if (err || !infos) { - return cb(err); - } - - console.log(chalk.cyan('[Keymetrics.io]') + ' Using (Public key: %s) (Private key: %s)', infos.public_key, infos.secret_key); - - daemonize(conf, infos, function(err, msg, proc) { - return cb(err, msg, proc); - }); - }); -}; - -InteractorDaemonizer.launchAndInteract = function(conf, opts, cb) { - // For Watchdog - if (process.env.PM2_AGENT_ONLINE) { - return process.nextTick(cb); - } - - process.env.PM2_INTERACTOR_PROCESSING = true; - - this.getOrSetConf(conf, opts, function(err, data) { - if (err || !data) { - return cb(err); - } - - //console.log(chalk.cyan('[Keymetrics.io]') + ' Using (Public key: %s) (Private key: %s)', data.public_key, data.secret_key); - - launchOrAttach(conf, data, function(err, msg, proc) { - if (err) - return cb(err); - return cb(null, msg, proc); - }); - return false; - }); -}; - -/** - * Description - * @method getInteractInfo - * @param {} cb - * @return - */ -InteractorDaemonizer.getInteractInfo = function(conf, cb) { - debug('Getting interaction info'); - if (process.env.PM2_NO_INTERACTION) return; - InteractorDaemonizer.ping(conf, function(online) { - if (!online) { - return cb(new Error('Interactor is offline')); - } - InteractorDaemonizer.launchRPC(conf, function() { - InteractorDaemonizer.rpc.getInfos(function(err, infos) { - if (err) - return cb(err); - - // Avoid general CLI to interfere with Keymetrics CLI commands - if (process.env.PM2_INTERACTOR_PROCESSING) - return cb(null, infos); - - InteractorDaemonizer.disconnectRPC(function() { - return cb(null, infos); - }); - return false; - }); - }); - return false; - }); -}; diff --git a/lib/Interactor/Password.js b/lib/Interactor/Password.js deleted file mode 100644 index 86b1fdd7..00000000 --- a/lib/Interactor/Password.js +++ /dev/null @@ -1,71 +0,0 @@ -/** - * Copyright 2013 the PM2 project authors. All rights reserved. - * Use of this source code is governed by a license that - * can be found in the LICENSE file. - */ -var crypto = require('crypto'); - -var saltChars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'; -var saltCharsCount = saltChars.length; - -function generateSalt(len) { - if (typeof len != 'number' || len <= 0 || len !== parseInt(len, 10)) throw new Error('Invalid salt length'); - if (crypto.randomBytes) { - return crypto.randomBytes(Math.ceil(len / 2)).toString('hex').substring(0, len); - } else { - for (var i = 0, salt = ''; i < len; i++) { - salt += saltChars.charAt(Math.floor(Math.random() * saltCharsCount)); - } - return salt; - } -} - -function generateHash(algorithm, salt, password, iterations) { - iterations = iterations || 1; - try { - var hash = password; - for(var i=0; i -1)) - return false; - - if (Object.keys(self.monitored_processes).length > 0 && - !self.monitored_processes[packet.process.pm_id]) - return false; - - // keep log in a buffer - if (event.match(/^log:/)) { - if (!LOGS_BUFFER[packet.process.name]) { - LOGS_BUFFER[packet.process.name] = []; - } - // push the log data - LOGS_BUFFER[packet.process.name].push(packet.data); - // delete the last one if too long - if (LOGS_BUFFER[packet.process.name].length >= cst.LOGS_BUFFER_SIZE) { - LOGS_BUFFER[packet.process.name].pop(); - } - - // don't send if not asked - if (!global._logs) return false; - } - - // attach additional info on exception - if (event === 'process:exception') { - packet.data.last_logs = LOGS_BUFFER[packet.process.name]; - packet.data = self.stackParser.attachContext(packet.data); - } - - /** - * This is a heapdump action - */ - if (event == 'axm:reply' && packet.data && packet.data.return && (packet.data.return.heapdump || packet.data.return.cpuprofile)) { - PushInteractor.sendFile(packet); - return false; - } - - if (event == 'human:event') { - packet.name = packet.data.__name + ''; - delete packet.data.__name; - } - - if (!packet.process) - return console.error('No process field [%s]', event); - - /** - * Process specific messages - * -- Reformat raw output of pm2-interface - */ - packet.process = { - pm_id : packet.process.pm_id, - name : packet.process.name, - rev : packet.process.rev || ((packet.process.versioning && packet.process.versioning.revision) ? packet.process.versioning.revision : null), - server: PushInteractor.conf.MACHINE_NAME - }; - - // agregate transaction data before sending them - if (event.indexOf('axm:trace') > -1) - return self.aggregator.aggregate(packet); - - if (event.match(/^log:/)) { - packet.log_type = event.split(':')[1]; - event = 'logs'; - } - return PushInteractor.bufferData(event, packet); - }); - }, - resetPacket : function() { - var self = this; - - this._packet = { - 'server_name' : self.conf.MACHINE_NAME, - 'status' : {}, - 'monitoring' : {} - }; - }, - bufferData : function(event, packet) { - var self = this; - var logs_limit_size = 1024 * 50; - - // if (Object.keys(self._packet).indexOf(event) == -1) { - // return console.error('SKIP unknown field name [%s]', event); - // } - debug('Buffering one more event %s', event); - - if (!(event in self._packet)) - self._packet[event] = []; - - if (packet.process && !packet.server) { - if (event === 'logs' - && (JSON.stringify(self._packet[event]).length > logs_limit_size - || self._packet[event].length > 100)) - return console.error('Logs packet larger than 50KB limit'); - - self._packet[event].push(packet); - } - else { - console.error('Got packet without any process'); - } - return false; - }, - preparePacket : function(cb) { - var self = this; - - this.ipm2.rpc.getMonitorData({}, function(err, processes) { - if (!processes) - return console.error('Cant access to getMonitorData RPC PM2 method'); - - processes = processes.filter(function (proc) { - return proc.pm2_env._km_monitored !== false; - }); - - var ret = null; - - if ((ret = Filter.monitoring(processes, PushInteractor.conf))) { - self._packet['monitoring'] = ret; - } - - if ((ret = Filter.machineSnapshot(processes, PushInteractor.conf))) { - self._packet['status'] = { - data : ret, - server_name : self.conf.MACHINE_NAME, - internal_ip : self.conf.internal_ip, - protected : global._pm2_password_protected, - rev_con : self.conf.rev_con - }; - } - - return cb ? cb(null, ret) : false; - }); - }, - /** - * Description - * @method send_data - * @return - */ - sendData : function() { - var self = this; - - if (self.socket.client && - self.socket.client.socks[0] && - self.socket.client.socks[0].bufferSize > 290000) { - self.resetPacket(); - self._reconnect_counter++; - console.log('Buffer size too high (%d), stopping buffering and sending', self.socket.client.socks[0].bufferSize); - - if (self._reconnect_counter > 20) { - console.log('[PUSH] Forcing reconnection'); - self._reconnect_counter = 0; - self.socket.reconnect(); - } - return false; - } - - this.preparePacket(function() { - var data = {}; - - if (process.env.NODE_ENV && - (process.env.NODE_ENV == 'test' || process.env.NODE_ENV == 'local_test')) { - data = { - public_key : PushInteractor.conf.PUBLIC_KEY, - sent_at : Utility.getDate(), - data : self._packet - }; - } - else { - var cipheredData = Cipher.cipherMessage(JSON.stringify(self._packet), - PushInteractor.conf.SECRET_KEY); - data = { - public_key : self.conf.PUBLIC_KEY, - sent_at : Utility.getDate(), - data : cipheredData - }; - } - - var str = JSON.stringify(data); - var t1 = new Date(); - - self.resetPacket(); - - if (!self.socket) return false; - - self.socket.client.sendv2(str, function() { - var duration_sec = (new Date() - t1) / 1000; - debugInfo('Time to flush data %ds (buffer size %d)', duration_sec); - - if (duration_sec > 1) - console.info('[WARN] Time to send data over TCP took %dseconds!', duration_sec); - - data = null; - str = null; - }); - }); - } -}; diff --git a/lib/Interactor/RemoteActions/CustomActions.js b/lib/Interactor/RemoteActions/CustomActions.js deleted file mode 100644 index 69749397..00000000 --- a/lib/Interactor/RemoteActions/CustomActions.js +++ /dev/null @@ -1,92 +0,0 @@ -/** - * Copyright 2013 the PM2 project authors. All rights reserved. - * Use of this source code is governed by a license that - * can be found in the LICENSE file. - */ - -var debug = require('debug')('interface:driver'); -var Cipher = require('../Cipher.js'); - -var CustomActions = module.exports = { - /** - * Method to trigger custom actions (axm actions) - */ - axmCustomActions : function() { - var self = this; - - this.socket.data('trigger:action', function(raw_msg) { - var msg = {}; - - if (process.env.NODE_ENV && (process.env.NODE_ENV == 'test' || - process.env.NODE_ENV == 'local_test')) - msg = raw_msg; - else - msg = Cipher.decipherMessage(raw_msg, self.conf.SECRET_KEY); - - if (!msg) return console.error('Error while receiving message! #axmCustomActions'); - - console.log('New remote action %s triggered for process %s', msg.action_name, msg.process_id); - self.pm2_instance.msgProcess({ - id : msg.process_id, - msg : msg.action_name, - opts: msg.opts || null - }, function(err, data) { - if (err) { - return self.socket.send('trigger:action:failure', { - success : false, - err : err.message, - id : msg.process_id, - action_name : msg.action_name - }); - } - console.log('[REVERSE INTERACTOR] Message received from AXM for proc_id : %s and action name %s', - msg.process_id, msg.action_name); - - return self.socket.send('trigger:action:success', { - success : true, - id : msg.process_id, - action_name : msg.action_name - }); - }); - }); - - this.socket.data('trigger:scoped_action', function(raw_msg) { - var msg = {}; - - if (process.env.NODE_ENV && (process.env.NODE_ENV == 'test' || - process.env.NODE_ENV == 'local_test')) - msg = raw_msg; - else - msg = Cipher.decipherMessage(raw_msg, self.conf.SECRET_KEY); - - if (!msg) return console.error('Error while receiving message! #axmCustomActions'); - - console.log('New SCOPED action %s triggered for process %s', msg.action_name, msg.process.pm_id); - - self.pm2_instance.msgProcess({ - id : msg.process.pm_id, - action_name : msg.action_name, - msg : msg.action_name, - opts : msg.options || {}, - uuid : msg.uuid - }, function(err, data) { - if (err) { - return self.socket.send('trigger:action:failure', { - success : false, - err : err.message, - id : msg.process.pm_id, - action_name : msg.action_name - }); - } - console.log('[REVERSE INTERACTOR] Message received from AXM for proc_id : %s and action name %s', - msg.process_id, msg.action_name); - - return self.socket.send('trigger:action:success', { - success : true, - id : msg.process.pm_id, - action_name : msg.action_name - }); - }); - }); - } -}; diff --git a/lib/Interactor/RemoteActions/Pm2Actions.js b/lib/Interactor/RemoteActions/Pm2Actions.js deleted file mode 100644 index bcad7fe2..00000000 --- a/lib/Interactor/RemoteActions/Pm2Actions.js +++ /dev/null @@ -1,322 +0,0 @@ -/** - * Copyright 2013 the PM2 project authors. All rights reserved. - * Use of this source code is governed by a license that - * can be found in the LICENSE file. - */ - -var debug = require('debug')('interface:driver'); -var Url = require('url'); -var Cipher = require('../Cipher.js'); -var PushInteractor = require('../PushInteractor'); -var Conf = require('../../Configuration.js'); - -/** - * Allowed remote PM2 methods - * with options - * - password_required : force to pass a password in parameter - * - password_optional : if a password is set, force it - * - lock : enable the locking system (block parallel commands) - */ -var PM2_REMOTE_METHOD_ALLOWED = { - 'restart' : {}, - 'reload' : {}, - 'gracefulReload' : {}, - 'reset' : {}, - 'scale' : {}, - - 'install' : {}, - 'uninstall' : {}, - 'stop' : {}, - 'delete' : {}, - 'set' : {}, - 'multiset' : {}, - 'deepUpdate' : {}, - - 'pullAndRestart' : {}, - 'forward' : {}, - 'backward' : {}, - - 'startLogging' : {}, - 'stopLogging' : {}, - - 'resetTransactionCache': {}, - 'resetFileCache': {}, - - // This is just for testing purproses - 'ping' : {} -}; - -var Pm2Actions = module.exports = { - /** - * Methods to trigger PM2 actions from remote - */ - pm2Actions : function() { - var self = this; - - function executionBox(msg, cb) { - /** - * Exemple - * msg = { - * method_name : 'restart', - * parameters : {} - * } - */ - console.log('PM2 action from remote triggered "pm2 %s %j"', - msg.method_name, - msg.parameters); - - var method_name = JSON.parse(JSON.stringify(msg.method_name)); - - var parameters = ''; - - try { - parameters = JSON.parse(JSON.stringify(msg.parameters)); - } - catch(e) { - console.error(e.stack || e); - parameters = msg.parameters; - } - - if (!method_name) { - console.error('no method name'); - return cb(new Error('no method name defined')); - } - - if (!PM2_REMOTE_METHOD_ALLOWED[method_name]) { - console.error('method %s not allowed', method_name); - return cb(new Error('method ' + method_name + ' not allowed')); - } - - if (method_name === 'startLogging') { - global._logs = true; - // Stop streaming logs automatically after timeout - setTimeout(function() { - global._logs = false; - }, 120000); - return cb(null, 'Log streaming enabled'); - } else if (method_name === 'stopLogging') { - global._logs = false; - return cb(null, 'Log streaming disabled'); - } else if (method_name === 'resetTransactionCache') { - PushInteractor.aggregator.clearData(); - return cb(null, 'Transaction cache has beem reset'); - } else if (method_name === 'resetFileCache') { - PushInteractor.cache.reset(); - return cb(null, 'File cache has beem reset'); - } - - self.pm2_instance.remote(method_name, parameters, cb); - return false; - } - - function sendBackResult(data) { - self.socket.send('trigger:pm2:result', data); - }; - - this.socket.data('trigger:pm2:action', function(raw_msg) { - var d = require('domain').create(); - - var msg = {}; - - /** - * Uncipher Data - */ - if (process.env.NODE_ENV && - (process.env.NODE_ENV == 'test' || - process.env.NODE_ENV == 'local_test')) - msg = raw_msg; - else - msg = Cipher.decipherMessage(raw_msg, self.conf.SECRET_KEY); - - d.on('error', function(e) { - console.error('Error caught in domain'); - console.error(e.stack || e); - - /** - * Send error back to - */ - sendBackResult({ - ret : { - err : e, - data : null - }, - meta : { - method_name : msg.method_name, - app_name : msg.parameters.name, - machine_name : self.conf.MACHINE_NAME, - public_key : self.conf.PUBLIC_KEY - } - }); - }); - - d.run(function() { - if (!msg) - throw new Error('Wrong SECRET KEY to uncipher package'); - - /** - * Execute command - */ - executionBox(msg, function(err, data) { - if (err) console.error(err.stack || JSON.stringify(err)); - - /** - * Send back the result - */ - sendBackResult({ - ret : { - err : err, - data : data || null - }, - meta : { - method_name : msg.method_name, - app_name : msg.parameters.name, - machine_name : self.conf.MACHINE_NAME, - public_key : self.conf.PUBLIC_KEY - } - }); - }); - }); - - }); - }, - - /**************************************************** - * - * - * Scoped PM2 Actions with streaming and multi args - * - * - ****************************************************/ - pm2ScopedActions : function() { - var self = this; - - this.socket.data('trigger:pm2:scoped:action', function(raw_msg) { - var msg = {}; - - if (process.env.NODE_ENV && (process.env.NODE_ENV == 'test' || - process.env.NODE_ENV == 'local_test')) - msg = raw_msg; - else { - /** - * Uncipher Data - */ - msg = Cipher.decipherMessage(raw_msg, self.conf.SECRET_KEY); - } - - if (!msg.uuid || - !msg.action_name) { - console.error('PM2 Scoped: Parameter missing!'); - return sendEvent('pm2:scoped:error', { - at : Date.now(), - out : 'Parameter missing', - msg : msg.uuid || null - }); - } - - sendEvent('pm2:scoped:stream', { - at : Date.now(), - out : 'Action ' + msg.action_name + ' received', - uuid : msg.uuid - }); - - executionBox(msg, function(err, data) { - if (err) { - console.error(err.stack || err); - return sendEvent('pm2:scoped:error', { - at : Date.now(), - out : err.stack || err, - uuid : msg.uuid - }); - } - return sendEvent('pm2:scoped:end', { - at : Date.now(), - out : data, - uuid : msg.uuid - }); - }); - }); - - /** - * Compact event in Push Interactor *pipe* - */ - function sendEvent(event, data) { - var packet = { - at : Date.now(), - data : { - data : data.out, - uuid : data.uuid - } - }; - - if (!PushInteractor._packet[event]) - PushInteractor._packet[event] = []; - - PushInteractor._packet[event].push(packet); - - if (process.env.NODE_ENV == 'local_test') - process.send({event : event, data : data}); - }; - - /** - * Processing - */ - function executionBox(msg, cb) { - var action_name = msg.action_name; - var opts = msg.options; - - if (!PM2_REMOTE_METHOD_ALLOWED[action_name]) { - console.error('method %s not allowed', action_name); - return cb(new Error('method ' + action_name + ' not allowed')); - } - - var action_conf = PM2_REMOTE_METHOD_ALLOWED[action_name]; - - if (action_conf.lock === false) - opts.lock = false; - - /** - * Fork the remote action in another process - * so we can catch the stdout/stderr and emit it - */ - var fork = require('child_process').fork; - - process.env.fork_params = JSON.stringify({ action : action_name, opts : opts}); - - console.log('Executing: pm2 %s %s', action_name, opts.args ? opts.args.join(' ') : ''); - - var app = fork(__dirname + '/ScopedExecution.js', [], { - silent : true - }); - - app.stdout.on('data', function(dt) { - console.log(dt.toString()); - sendEvent('pm2:scoped:stream', { - at : Date.now(), - out : dt.toString(), - uuid : msg.uuid - }); - }); - - app.once('error', function(dt) { - console.error('Error got?', dt); - sendEvent('pm2:scoped:error', { - at : Date.now(), - out : 'Shit happening ' + JSON.stringify(dt), - msg : msg.uuid - }); - }); - - app.on('message', function(dt) { - var ret = JSON.parse(dt); - if (ret.isFinished != true) return false; - - console.log('Action %s finished (err= %s)', - action_name, ret.err); - return cb(ret.err, ret.dt); - }); - - return false; - } - - } -}; diff --git a/lib/Interactor/RemoteActions/ScopedExecution.js b/lib/Interactor/RemoteActions/ScopedExecution.js deleted file mode 100644 index 08c962e3..00000000 --- a/lib/Interactor/RemoteActions/ScopedExecution.js +++ /dev/null @@ -1,34 +0,0 @@ -/** - * Copyright 2013 the PM2 project authors. All rights reserved. - * Use of this source code is governed by a license that - * can be found in the LICENSE file. - */ - -var pm2 = require('../../..'); -var domain = require('domain'); -var Utility = require('../../Utility.js'); - -var d = domain.create(); - -d.once('error', function(err) { - process.send(JSON.stringify({err: err.stack, isFinished : true})); -}); - -d.run(function() { - var params = JSON.parse(process.env.fork_params); - - console.log('Executing: pm2 %s %s', - params.action, - params.opts.args ? params.opts.args.join(' ') : ''); - - pm2.connect(function() { - pm2.remoteV2(params.action, params.opts, function(err, dt) { - process.send(JSON.stringify(Utility.clone({ - err: err, - dt: dt, - isFinished : true - }))); - pm2.disconnect(process.exit); - }); - }); -}); diff --git a/lib/Interactor/ReverseInteractor.js b/lib/Interactor/ReverseInteractor.js deleted file mode 100644 index 67673bba..00000000 --- a/lib/Interactor/ReverseInteractor.js +++ /dev/null @@ -1,128 +0,0 @@ -/** - * Copyright 2013 the PM2 project authors. All rights reserved. - * Use of this source code is governed by a license that - * can be found in the LICENSE file. - */ - -var debug = require('debug')('interface:driver'); -var nssocket = require('nssocket'); -var Url = require('url'); -var Cipher = require('./Cipher.js'); -var util = require('util'); - -var ReverseInteract = { - changeUrl : function(url) { - if (!this.connected) return; - console.log('[REV] Changing URL to %s', url); - - this.network = Url.parse(url); - this.socket.connect(parseInt(this.network.port), this.network.hostname); - this.socket.reconnect(); - }, - destroy : function() { - this.socket.destroy(); - }, - reconnect : function() { - console.log('[REV] Reconnecting to %s', this.network.hostname); - this.socket.reconnect(); - }, - start : function(opts) { - var self = this; - - if (!opts.url) - throw new Error('url not declared'); - if (!opts.conf) - throw new Error('Conf not passed to ReverseInteractor'); - - this.connected = false; - this.conf = opts.conf; - this.network = Url.parse(opts.url); - this.pm2_instance = opts.conf.pm2_instance; - - this.socket = new nssocket.NsSocket({ - type : 'tcp4', - reconnect : true, - retryInterval : 2000, - max : Infinity, - maxListeners : 50 - }); - - this.socket.on('error', function(e) { - self.connected = false; - console.error('[REV] %s', e.message || e); - }); - - this.socket.on('close', function(dt) { - self.connected = false; - }); - - this.socket.on('start', function() { - self.connected = true; - opts.conf.rev_con = true; - console.log('[REV] Connected to %s:%s', self.network.hostname, self.network.port); - }); - - console.log('[REV] Connecting to %s:%s', this.network.hostname, this.network.port); - - this.socket.connect(parseInt(this.network.port), this.network.hostname); - this.onMessage(); - }, - /** - * Listening to remote events from Keymetrics - */ - onMessage : function() { - if (!this.socket) return console.error('Reverse interaction not initialized'); - - /** - * Identify this agent to Keymetrics - * via PUBLIC/PRIVATE key exchange - */ - ReverseInteract.introduceToKeymetrics(); - - ReverseInteract.axmCustomActions(); - - /** - * From Pm2Actions.js - */ - ReverseInteract.pm2Actions(); - - ReverseInteract.pm2ScopedActions(); - - return false; - }, - /** - * First method called to identify this agent - */ - introduceToKeymetrics : function() { - var self = this; - - this.socket.data('ask', function(raw_msg) { - if (process.env.NODE_ENV && process.env.NODE_ENV == 'test') { - // Dont cipher data in test environment - self.socket.send('ask:rep', { - success : true, - machine_name : self.conf.MACHINE_NAME, - public_key : self.conf.PUBLIC_KEY - }); - } else { - var ciphered_data = Cipher.cipherMessage(JSON.stringify({ - machine_name : self.conf.MACHINE_NAME - }), self.conf.SECRET_KEY); - - if (!ciphered_data) - return console.error('Got wrong ciphering data %s %s', self.conf.MACHINE_NAME, self.conf.SECRET_KEY); - - self.socket.send('ask:rep', { - data : ciphered_data, - public_key : self.conf.PUBLIC_KEY - }); - } - return false; - }); - } -}; - -util._extend(ReverseInteract, require('./RemoteActions/Pm2Actions.js')); -util._extend(ReverseInteract, require('./RemoteActions/CustomActions.js')); - -module.exports = ReverseInteract; diff --git a/lib/Interactor/TransactionAggregator.js b/lib/Interactor/TransactionAggregator.js deleted file mode 100644 index d6a46283..00000000 --- a/lib/Interactor/TransactionAggregator.js +++ /dev/null @@ -1,684 +0,0 @@ -/** - * Copyright 2013 the PM2 project authors. All rights reserved. - * Use of this source code is governed by a license that - * can be found in the LICENSE file. - */ - -/** - * Dependencies - */ -var cst = require('../../constants.js'); -var log = require('debug')('pm2:aggregator'); -var async = require('async'); -var Utility = require('./Utility.js'); -var fclone = require('fclone'); -var fs = require('fs'); -var path = require('path'); -var Histogram = require('pmx/lib/utils/probes/Histogram.js'); - -var LABELS = { - "HTTP_RESPONSE_CODE_LABEL_KEY": 'http/status_code', - "HTTP_URL_LABEL_KEY": 'http/url', - "HTTP_METHOD_LABEL_KEY": 'http/method', - "HTTP_RESPONSE_SIZE_LABEL_KEY": 'http/response/size', - "STACK_TRACE_DETAILS_KEY": 'stacktrace', - "ERROR_DETAILS_NAME": 'error/name', - "ERROR_DETAILS_MESSAGE": 'error/message', - "HTTP_SOURCE_IP": 'http/source/ip', - "HTTP_PATH_LABEL_KEY": "http/path" -} -var SPANS_DB = ['redis', 'mysql', 'pg', 'mongo', 'outbound_http']; - -/** - * - * # Data structure sent to interactor - * - * { - * 'process_name': { - * process : {}, // PM2 process meta data - * data : { - * routes : [ // array of all routes ordered by count - * { - * path: '/', // path of the route - * meta: { - * count: 50, // count of this route - * max: 300, // max latency of this route - * min: 50, // min latency of this route - * mean: 120 // mean latency of this route - * } - * variances: [{ // array of variance order by count - * spans : [ - * ... // transactions - * ], - * count: 50, // count of this variance - * max: 300, // max latency of this variance - * min: 50, // min latency of this variance - * mean: 120 // mean latency of this variance - * }] - * } - * ], - * meta : { - * trace_count : 50, // trace number - * mean_latency : 40, // global app latency in ms - * http_meter : 30, // global app req per minutes - * db_meter : 20, // number of database transaction per min - * } - * } - * } - * } - */ - -var TransactionAggregator = module.exports = function (pushInteractor) { - if (!(this instanceof TransactionAggregator)) return new TransactionAggregator(pushInteractor); - - var self = this; - this.processes = {}; - this.stackParser = pushInteractor.stackParser; - - /** - * First method to call in real environment - * - Listen to restart event for initialization period - * - Clear aggregation on process stop - * - Launch worker to attach data to be pushed to KM - */ - this.init = function () { - // New Process Online, reset & wait a bit before processing - pushInteractor.ipm2.bus.on('process:event', function (data) { - if (data.event !== 'online' || !self.processes[data.process.name]) return false; - - var rev = (data.process.versioning && data.process.versioning.revision) - ? data.process.versioning.revision : null; - - self.resetAggregation(data.process.name, { - rev: rev, - server: pushInteractor.conf.MACHINE_NAME - }); - }); - - // Process getting offline, delete aggregation - pushInteractor.ipm2.bus.on('process:event', function (data) { - if (data.event !== 'stop' || !self.processes[data.process.name]) return false; - log('Deleting aggregation for %s', data.process.name); - delete self.processes[data.process.name]; - }); - - self.launchWorker(); - }; - - /** - * Reset aggregation for target app_name - */ - this.resetAggregation = function (app_name, meta) { - log('Reseting agg for app:%s meta:%j', app_name, meta); - - if (self.processes[app_name].initialization_timeout) { - log('Reseting initialization timeout app:%s', app_name); - clearTimeout(self.processes[app_name].initialization_timeout); - clearInterval(self.processes[app_name].notifier); - self.processes[app_name].notifier = null; - } - - self.processes[app_name] = initializeRouteMeta({ - name: app_name, - rev: meta.rev, - server: meta.server - }); - - var start = Date.now(); - self.processes[app_name].notifier = setInterval(function () { - var elapsed = Date.now() - start; - // failsafe - if (elapsed / 1000 > cst.AGGREGATION_DURATION) { - clearInterval(self.processes[app_name].notifier); - self.processes[app_name].notifier = null; - } - - var msg = { - data: { - learning_duration: cst.AGGREGATION_DURATION, - elapsed: elapsed - }, - process: self.processes[app_name].process - }; - pushInteractor && pushInteractor.bufferData('axm:transaction:learning', msg); - }, 5000); - - self.processes[app_name].initialization_timeout = setTimeout(function () { - log('Initialization timeout finished for app:%s', app_name); - clearInterval(self.processes[app_name].notifier); - self.processes[app_name].notifier = null; - self.processes[app_name].initialization_timeout = null; - }, cst.AGGREGATION_DURATION); - }; - - /** - * Clear aggregated data for all process - */ - this.clearData = function () { - var self = this; - Object.keys(this.processes).forEach(function (process) { - self.resetAggregation(process, self.processes[process].process); - }); - }; - - /** - * Generate new entry for application - * - * @param {Object} process process meta - */ - function initializeRouteMeta (process) { - if (process.pm_id) delete process.pm_id; - - return { - routes: {}, - meta: { - trace_count: 0, - http_meter: new Utility.EWMA(), - db_meter: new Utility.EWMA(), - histogram: new Histogram({ measurement: 'median' }), - db_histograms: {} - }, - process: process - }; - } - - this.getAggregation = function () { - return this.processes; - }; - - this.validateData = function (packet) { - if (!packet || !packet.data) { - log('Packet malformated', packet); - return false; - } - - if (!packet.process) { - log('Got packet without process: %j', packet); - return false; - } - - if (!packet.data.spans || !packet.data.spans[0]) { - log('Trace without spans: %s', Object.keys(packet.data)); - return false; - } - - if (!packet.data.spans[0].labels) { - log('Trace spans without labels: %s', Object.keys(packet.data.spans)); - return false; - } - - return true; - } - - /** - * Main method to aggregate and compute stats for traces - * - * @param {Object} packet - * @param {Object} packet.process process metadata - * @param {Object} packet.data trace - */ - this.aggregate = function(packet) { - if (self.validateData(packet) === false) return false; - - var new_trace = packet.data; - var app_name = packet.process.name; - - if (!self.processes[app_name]) { - self.processes[app_name] = initializeRouteMeta(packet.process); - } - - var process = self.processes[app_name]; - - // Get http path of current span - var path = new_trace.spans[0].labels[LABELS.HTTP_PATH_LABEL_KEY]; - - // Cleanup spans - self.censorSpans(new_trace.spans); - - // remove spans with startTime == endTime - new_trace.spans = new_trace.spans.filter(function (span) { - return span.endTime !== span.startTime; - }); - - // compute duration of child spans - new_trace.spans.forEach(function (span) { - span.mean = Math.round(new Date(span.endTime) - new Date(span.startTime)); - delete span.endTime; - }); - - // Update app meta (mean_latency, http_meter, db_meter, trace_count) - new_trace.spans.forEach(function (span) { - if (!span.name || !span.kind) return false; - - if (span.kind === 'RPC_SERVER') { - process.meta.histogram.update(span.mean); - return process.meta.http_meter.update(); - } - - // Override outbount http queries for processing - if (span.labels && span.labels['http/method'] && span.labels['http/status_code']) { - span.labels['service'] = span.name; - span.name = 'outbound_http'; - } - - for (var i = 0, len = SPANS_DB.length; i < len; i++) { - if (span.name.indexOf(SPANS_DB[i]) > -1) { - process.meta.db_meter.update(); - if (!process.meta.db_histograms[SPANS_DB[i]]) { - process.meta.db_histograms[SPANS_DB[i]] = new Histogram({ measurement: 'mean' }); - } - process.meta.db_histograms[SPANS_DB[i]].update(span.mean); - break; - } - } - }); - - process.meta.trace_count++; - - /** - * Handle traces aggregation - */ - if (path[0] === '/' && path !== '/') { - path = path.substr(1, path.length - 1); - } - - var matched = self.matchPath(path, process.routes); - - if (!matched) { - process.routes[path] = []; - self.mergeTrace(process.routes[path], new_trace, process); - } else { - self.mergeTrace(process.routes[matched], new_trace, process); - } - - return self.processes; - }; - - /** - * Merge new trace and compute mean, min, max, count - * - * @param {Object} aggregated previous aggregated route - * @param {Object} trace - */ - this.mergeTrace = function (aggregated, trace, process) { - var self = this; - - if (!aggregated || !trace) return; - - // if the trace doesn't any spans stop aggregation here - if (trace.spans.length === 0) return; - - // create data structure if needed - if (!aggregated.variances) aggregated.variances = []; - if (!aggregated.meta) { - aggregated.meta = { - histogram: new Histogram({ measurement: 'median' }), - meter: new Utility.EWMA() - }; - } - - aggregated.meta.histogram.update(trace.spans[0].mean); - aggregated.meta.meter.update(); - - var merge = function (variance) { - // no variance found so its a new one - if (variance == null) { - delete trace.projectId; - delete trace.traceId; - trace.histogram = new Histogram({ measurement: 'median' }); - trace.histogram.update(trace.spans[0].mean); - - trace.spans.forEach(function (span) { - span.histogram = new Histogram({ measurement: 'median' }); - span.histogram.update(span.mean); - delete span.mean; - }); - - // parse strackrace - self.parseStacktrace(trace.spans); - aggregated.variances.push(trace); - } else { - // check to see if request is anormally slow, if yes send it as inquisitor - if (trace.spans[0].mean > variance.histogram.percentiles([0.95])[0.95] && - typeof pushInteractor !== 'undefined' && !process.initialization_timeout) { - // serialize and add metadata - self.parseStacktrace(trace.spans) - var data = { - trace: fclone(trace.spans), - variance: fclone(variance.spans.map(function (span) { - return { - labels: span.labels, - kind: span.kind, - name: span.name, - startTime: span.startTime, - percentiles: { - p5: variance.histogram.percentiles([0.5])[0.5], - p95: variance.histogram.percentiles([0.95])[0.95] - } - } - })), - meta: { - value: trace.spans[0].mean, - percentiles: { - p5: variance.histogram.percentiles([0.5])[0.5], - p75: variance.histogram.percentiles([0.75])[0.75], - p95: variance.histogram.percentiles([0.95])[0.95], - p99: variance.histogram.percentiles([0.99])[0.99] - }, - min: variance.histogram.getMin(), - max: variance.histogram.getMax(), - count: variance.histogram.getCount() - }, - process: process.process - }; - pushInteractor.bufferData('axm:transaction:outlier', data); - } - - // variance found, merge spans - variance.histogram.update(trace.spans[0].mean); - - // update duration of spans to be mean - self.updateSpanDuration(variance.spans, trace.spans, variance.count); - - // delete stacktrace before merging - trace.spans.forEach(function (span) { - delete span.labels.stacktrace; - }); - } - }; - - // for every variance, check spans same variance - for (var i = 0; i < aggregated.variances.length; i++) { - if (self.compareList(aggregated.variances[i].spans, trace.spans)) { - return merge(aggregated.variances[i]); - } - } - // else its a new variance - return merge(null); - }; - - /** - * Parkour simultaneously both spans list to update value of the first one using value of the second one - * The first should be variance already aggregated for which we want to merge the second one - * The second one is a new trace, so we need to re-compute mean/min/max time for each spans - */ - this.updateSpanDuration = function (spans, newSpans) { - for (var i = 0, len = spans.length; i < len; i++) { - if (!newSpans[i]) continue; - spans[i].histogram.update(newSpans[i].mean); - } - }; - - /** - * Compare two spans list by going down on each span and comparing child and attribute - */ - this.compareList = function (one, two) { - if (one.length !== two.length) return false; - - for (var i = 0, len = one; i < len; i++) { - if (one[i].name !== two[i].name) return false; - if (one[i].kind !== two[i].kind) return false; - if (!one[i].labels && two[i].labels) return false; - if (one[i].labels && !two[i].labels) return false; - if (one[i].labels.length !== two[i].labels.length) return false; - } - return true; - }; - - /** - * Will return the route if we found an already matched route - */ - this.matchPath = function (path, routes) { - // empty route is / without the fist slash - if (!path || !routes) return false; - if (path === '/') return routes[path] ? path : null; - - // remove the last slash if exist - if (path[path.length - 1] === '/') { - path = path.substr(0, path.length - 1); - } - - // split to get array of segment - path = path.split('/'); - - // if the path has only one segment, we just need to compare the key - if (path.length === 1) return routes[path[0]] ? routes[path[0]] : null; - - // check in routes already stored for match - var keys = Object.keys(routes); - for (var i = 0, len = keys.length; i < len; i++) { - var route = keys[i]; - var segments = route.split('/'); - - if (segments.length !== path.length) continue; - - for (var j = path.length - 1; j >= 0; j--) { - // different segment, try to find if new route or not - if (path[j] !== segments[j]) { - // if the aggregator already have matched that segment with a wildcard and the next segment is the same - if (self.isIdentifier(path[j]) && segments[j] === '*' && path[j - 1] === segments[j - 1]) { - return segments.join('/'); - } // case a var in url match, so we continue because they must be other var in url - else if (path[j - 1] !== undefined && path[j - 1] === segments[j - 1] && self.isIdentifier(path[j]) && self.isIdentifier(segments[j])) { - segments[j] = '*'; - // update routes in cache - routes[segments.join('/')] = routes[route]; - delete routes[keys[i]]; - return segments.join('/'); - } else { - break; - } - } - - // if finish to iterate over segment of path, we must be on the same route - if (j === 0) return segments.join('/'); - } - } - }; - - this.launchWorker = function () { - setInterval(function () { - var normalized = self.prepareAggregationforShipping(); - Object.keys(normalized).forEach(function (key) { - pushInteractor.bufferData('axm:transaction', normalized[key]); - }); - }, cst.TRACE_FLUSH_INTERVAL); - }; - - /** - * Normalize aggregation - */ - this.prepareAggregationforShipping = function () { - var normalized = {}; - - // Iterate each applications - Object.keys(self.processes).forEach(function (app_name) { - var process = self.processes[app_name]; - var routes = process.routes; - - if (process.initialization_timeout) { - log('Waiting for app %s to be initialized', app_name); - return null; - } - - normalized[app_name] = { - data: { - routes: [], - meta: fclone({ - trace_count: process.meta.trace_count, - http_meter: Math.round(process.meta.http_meter.rate(1000) * 100) / 100, - db_meter: Math.round(process.meta.db_meter.rate(1000) * 100) / 100, - http_percentiles: { - median: process.meta.histogram.percentiles([0.5])[0.5], - p95: process.meta.histogram.percentiles([0.95])[0.95], - p99: process.meta.histogram.percentiles([0.99])[0.99] - }, - db_percentiles: {} - }) - }, - process: process.process - }; - - // compute percentiles for each db spans if they exist - SPANS_DB.forEach(function (name) { - var histogram = process.meta.db_histograms[name]; - if (!histogram) return; - normalized[app_name].data.meta.db_percentiles[name] = fclone(histogram.percentiles([0.5])[0.5]); - }); - - Object.keys(routes).forEach(function (path) { - var data = routes[path]; - - // hard check for invalid data - if (!data.variances || data.variances.length === 0) return; - - // get top 5 variances of the same route - var variances = data.variances.sort(function (a, b) { - return b.count - a.count; - }).slice(0, 5); - - // create a copy without reference to stored one - var routeCopy = { - path: path === '/' ? '/' : '/' + path, - meta: fclone({ - min: data.meta.histogram.getMin(), - max: data.meta.histogram.getMax(), - count: data.meta.histogram.getCount(), - meter: Math.round(data.meta.meter.rate(1000) * 100) / 100, - median: data.meta.histogram.percentiles([0.5])[0.5], - p95: data.meta.histogram.percentiles([0.95])[0.95] - }), - variances: [] - }; - - variances.forEach(function (variance) { - // hard check for invalid data - if (!variance.spans || variance.spans.length === 0) return; - - // deep copy of variances data - var tmp = fclone({ - spans: [], - count: variance.histogram.getCount(), - min: variance.histogram.getMin(), - max: variance.histogram.getMax(), - median: variance.histogram.percentiles([0.5])[0.5], - p95: variance.histogram.percentiles([0.95])[0.95] - }); - - // get data for each span - variance.spans.forEach(function (span) { - tmp.spans.push(fclone({ - name: span.name, - labels: span.labels, - kind: span.kind, - min: span.histogram.getMin(), - max: span.histogram.getMax(), - median: span.histogram.percentiles([0.5])[0.5] - })); - }); - // push serialized into normalized data - routeCopy.variances.push(tmp); - }); - // push the route into normalized data - normalized[app_name].data.routes.push(routeCopy); - }); - }); - - return normalized; - }; - - /** - * Check if the string can be a id of some sort - * - * @param {String} id - */ - this.isIdentifier = function (id) { - id = typeof (id) !== 'string' ? id + '' : id; - - // uuid v1/v4 with/without dash - if (id.match(/[0-9a-f]{8}-[0-9a-f]{4}-[14][0-9a-f]{3}-[0-9a-f]{4}-[0-9a-f]{12}|[0-9a-f]{12}[14][0-9a-f]{19}/i)) - return true; - // if number - else if (id.match(/\d+/)) - return true; - // if suit of nbr/letters - else if (id.match(/[0-9]+[a-z]+|[a-z]+[0-9]+/)) - return true; - // if match pattern with multiple char spaced by . - _ @ - else if (id.match(/((?:[0-9a-zA-Z]+[@\-_.][0-9a-zA-Z]+|[0-9a-zA-Z]+[@\-_.]|[@\-_.][0-9a-zA-Z]+)+)/)) - return true; - else - return false; - } - - var REGEX_JSON_CLEANUP = /":(?!\[|{)\\"[^"]*\\"|":(["'])(?:(?=(\\?))\2.)*?\1|":(?!\[|{)[^,}\]]*|":\[[^{]*]/g - /** - * Cleanup trace data - * - delete result(s) - * - replace labels value with a question mark - * - * @param {Object} spans list of span for a trace - */ - this.censorSpans = function(spans) { - if (!spans) - return log('spans is null'); - if (cst.DEBUG) return; - - spans.forEach(function(span) { - if (!span.labels) - return; - - delete span.labels.results; - delete span.labels.result; - delete span.spanId; - delete span.parentSpanId; - delete span.labels.values; - - Object.keys(span.labels).forEach(function(key) { - if (typeof(span.labels[key]) === 'string' && key !== 'stacktrace') - span.labels[key] = span.labels[key].replace(REGEX_JSON_CLEANUP, '\": \"?\"'); - }); - }); - } - - /** - * Parse stackrace of spans to extract and normalize data - * - * @param {Object} spans list of span for a trace - */ - this.parseStacktrace = function (spans) { - var self = this; - if (!spans) - return log('spans is null'); - - spans.forEach(function (span) { - // if empty make sure that it doesnt exist - if (!span || - !span.labels || - !span.labels.stacktrace || - typeof(span.labels.stacktrace) !== 'string') - return; - - // you never know what come through that door - try { - span.labels.stacktrace = JSON.parse(span.labels.stacktrace); - } catch (e) { - return ; - } - - if (!span.labels.stacktrace || !(span.labels.stacktrace.stack_frame instanceof Array) ) return ; - // parse the stacktrace - var result = self.stackParser.parse(span.labels.stacktrace.stack_frame); - if (result) { - span.labels['source/file'] = result.callsite || undefined; - span.labels['source/context'] = result.context || undefined; - } - }); - - spans.forEach(function (span) { - if (!span || !span.labels) - return; - delete span.labels.stacktrace; - }) - } -}; diff --git a/lib/Interactor/Utility.js b/lib/Interactor/Utility.js deleted file mode 100644 index 898e734f..00000000 --- a/lib/Interactor/Utility.js +++ /dev/null @@ -1,235 +0,0 @@ -var path = require('path'); -var isAbsolute = require('../tools/IsAbsolute.js'); - -// EWMA = ExponentiallyWeightedMovingAverage from -// https://github.com/felixge/node-measured/blob/master/lib/util/ExponentiallyMovingWeightedAverage.js -// used to compute the nbr of time per minute that a variance is hit by a new trace -function EWMA () { - this._timePeriod = 60000 - this._tickInterval = 5000 - this._alpha = 1 - Math.exp(-this._tickInterval / this._timePeriod) - this._count = 0 - this._rate = 0 - - var self = this - this._interval = setInterval(function () { - self.tick() - }, this._tickInterval) - this._interval.unref() -} - -EWMA.prototype.update = function (n) { - this._count += n || 1 -} - -EWMA.prototype.tick = function () { - var instantRate = this._count / this._tickInterval - this._count = 0 - - this._rate += (this._alpha * (instantRate - this._rate)) -} - -EWMA.prototype.rate = function (timeUnit) { - return (this._rate || 0) * timeUnit -} - -var moment = require('moment'); - -/** - * Simple cache implementation - * - * @param {Object} opts cache options - * @param {Integer} opts.ttl time to live of all the keys - * @param {Function} opts.miss function called when a key isn't found in the cache - */ -function Cache (opts) { - this._cache = {}; - this._miss = opts.miss; - this._ttl_time = opts.ttl; - this._ttl = {}; - - if (opts.ttl) { - setInterval(this._worker.bind(this), 1000); - } -} - -/** - * Task running to check TTL and potentially remove older key - */ -Cache.prototype._worker = function () { - var keys = Object.keys(this._ttl); - for (var i = 0; i < keys.length; i++) { - var key = keys[i]; - var value = this._ttl[key]; - if (moment().isAfter(value)) { - delete this._cache[key]; - delete this._ttl[key]; - } - } -}; - -/** - * Empty the cache - */ -Cache.prototype.reset = function () { - this._cache = null; - this._cache = {}; - this._ttl = null; - this._ttl = {}; -}; - -/** - * Get a value from the cache - * - * @param {String} key - */ -Cache.prototype.get = function (key) { - if (!key) return null; - var value = this._cache[key]; - if (value) return value; - - value = this._miss(key); - - if (value) { - this.set(key, value); - } - return value; -}; - -/** - * Set a value in the cache - * - * @param {String} key - * @param {Mixed} value - */ -Cache.prototype.set = function (key, value) { - if (!key || !value) return false; - this._cache[key] = value; - if (this._ttl_time) { - this._ttl[key] = moment().add(this._ttl_time, 'seconds'); - } - return true; -}; - -/** - * StackTraceParser is used to parse callsite from stacktrace - * and get from FS the context of the error (if available) - * - * @param {Cache} cache cache implementation used to query file from FS and get context - */ -function StackTraceParser (opts) { - this._cache = opts.cache; - this._context_size = opts.context; -} - -StackTraceParser.prototype.attachContext = function (error) { - var self = this; - if (!error) return error; - - // if pmx attached callsites we can parse them to retrieve the context - if (typeof (error.stackframes) === 'object') { - var result = self.parse(error.stackframes); - // no need to send it since there is already the stacktrace - delete error.stackframes; - delete error.__error_callsites; - - if (result) { - error.callsite = result.callsite; - error.context = result.context; - } - } - // if the stack is here we can parse it directly from the stack string - // only if the context has been retrieved from elsewhere - if (typeof error.stack === 'string' && !error.callsite) { - var siteRegex = /(\/[^\\\n]*)/g; - var tmp; - var stack = []; - - // find matching groups - while ((tmp = siteRegex.exec(error.stack))) { - stack.push(tmp[1]); - } - - // parse each callsite to match the format used by the stackParser - stack = stack.map(function (callsite) { - // remove the trailing ) if present - if (callsite[callsite.length - 1] === ')') { - callsite = callsite.substr(0, callsite.length - 1); - } - var location = callsite.split(':'); - - return location.length < 3 ? callsite : { - file_name: location[0], - line_number: parseInt(location[1]) - }; - }); - - var finalCallsite = self.parse(stack); - if (finalCallsite) { - error.callsite = finalCallsite.callsite; - error.context = finalCallsite.context; - } - } - return error; -}; - -/** - * Parse the stacktrace and return callsite + context if available - */ -StackTraceParser.prototype.parse = function (stack) { - var self = this; - if (!stack || stack.length === 0) return false; - - for (var i = 0, len = stack.length; i < len; i++) { - var callsite = stack[i]; - - // avoid null values - if (typeof callsite !== 'object') continue; - if (!callsite.file_name || !callsite.line_number) continue; - - var type = isAbsolute(callsite.file_name) || callsite.file_name[0] === '.' ? 'user' : 'core'; - - // only use the callsite if its inside user space - if (!callsite || type === 'core' || callsite.file_name.indexOf('node_modules') > -1 || - callsite.file_name.indexOf('vxx') > -1) { - continue; - } - - // get the whole context (all lines) and cache them if necessary - var context = self._cache.get(callsite.file_name); - var source = []; - if (context && context.length > 0) { - // get line before the call - var preLine = callsite.line_number - self._context_size - 1; - var pre = context.slice(preLine > 0 ? preLine : 0, callsite.line_number - 1); - if (pre && pre.length > 0) { - pre.forEach(function (line) { - source.push(line.replace(/\t/g, ' ')); - }); - } - // get the line where the call has been made - if (context[callsite.line_number - 1]) { - source.push(context[callsite.line_number - 1].replace(/\t/g, ' ').replace(' ', '>>')); - } - // and get the line after the call - var postLine = callsite.line_number + self._context_size; - var post = context.slice(callsite.line_number, postLine); - if (post && post.length > 0) { - post.forEach(function (line) { - source.push(line.replace(/\t/g, ' ')); - }); - } - } - return { - context: source.length > 0 ? source.join('\n') : 'cannot retrieve source context', - callsite: [ callsite.file_name, callsite.line_number ].join(':') - }; - } - return false; -}; - -module.exports = { - EWMA: EWMA, - Cache: Cache, - StackTraceParser: StackTraceParser -}; diff --git a/lib/Interactor/WatchDog.js b/lib/Interactor/WatchDog.js deleted file mode 100644 index 8ade9c81..00000000 --- a/lib/Interactor/WatchDog.js +++ /dev/null @@ -1,69 +0,0 @@ -/** - * Copyright 2013 the PM2 project authors. All rights reserved. - * Use of this source code is governed by a license that - * can be found in the LICENSE file. - */ - -var PM2 = require('../..'); -var debug = require('debug')('interface:watchdog'); -var shelljs = require('shelljs'); -var csts = require('../../constants'); -var path = require('path'); - -process.env.PM2_AGENT_ONLINE = true; - -var WatchDog = module.exports = { - start : function(p) { - var self = this; - this.ipm2 = p.conf.ipm2; - this.relaunching = false; - this.pm2_instance = p.conf.pm2_instance; - - /** - * Handle PM2 connection state changes - */ - this.ipm2.on('ready', function() { - console.log('[WATCHDOG] Connected to PM2'); - self.relaunching = false; - self.autoDump(); - }); - - console.log('[WATCHDOG] Launching'); - - this.ipm2.on('reconnecting', function() { - console.log('[WATCHDOG] PM2 is disconnected - Relaunching PM2'); - - if (self.relaunching === true) return console.log('[WATCHDOG] Already relaunching PM2'); - self.relaunching = true; - - if (self.dump_interval) - clearInterval(self.dump_interval); - - return WatchDog.resurrect(); - }); - }, - resurrect : function() { - var self = this; - - console.log('[WATCHDOG] Trying to launch PM2 #1'); - - shelljs.exec('node ' + path.resolve(__dirname, '../../bin/pm2') + ' resurrect', function() { - setTimeout(function() { - self.relaunching = false; - }, 2500); - }); - }, - autoDump : function() { - var self = this; - - this.dump_interval = setInterval(function() { - if (self.relaunching == true) return false; - - self.pm2_instance.dump(function(err) { - if (err) return console.error('[WATCHDOG] Error when dumping'); - debug('PM2 process list dumped'); - return false; - }); - }, 5 * 60 * 1000); - } -}; diff --git a/lib/Interactor/internal-ip.js b/lib/Interactor/internal-ip.js deleted file mode 100644 index b3f1b7c9..00000000 --- a/lib/Interactor/internal-ip.js +++ /dev/null @@ -1,40 +0,0 @@ -var os = require('os'); - -var type = { - v4: { - def: '127.0.0.1', - family: 'IPv4' - }, - v6: { - def: '::1', - family: 'IPv6' - } -}; - -function internalIp(version) { - var options = type[version]; - var ret = options.def; - var interfaces = os.networkInterfaces(); - - Object.keys(interfaces).forEach(function (el) { - interfaces[el].forEach(function (el2) { - if (!el2.internal && el2.family === options.family) { - ret = el2.address; - } - }); - }); - - return ret; -} - -function v4() { - return internalIp('v4'); -} - -function v6() { - return internalIp('v6'); -} - -module.exports = v4; -module.exports.v4 = v4; -module.exports.v6 = v6; diff --git a/lib/Interactor/pm2-interface.js b/lib/Interactor/pm2-interface.js deleted file mode 100644 index 17d40303..00000000 --- a/lib/Interactor/pm2-interface.js +++ /dev/null @@ -1,122 +0,0 @@ -/** - * Copyright 2013 the PM2 project authors. All rights reserved. - * Use of this source code is governed by a license that - * can be found in the LICENSE file. - */ - -/** - * Dependencies - */ - -var axon = require('pm2-axon'); -var cst = require('../../constants.js'); -var util = require('util'); -var rpc = require('pm2-axon-rpc'); -var log = require('debug')('pm2:interface'); -var EventEmitter = require('events').EventEmitter; - -/** - * Export with conf - */ -module.exports = function(opts){ - var sub_port = opts && opts.sub_port || cst.DAEMON_PUB_PORT; - var rpc_port = opts && opts.rpc_port || cst.DAEMON_RPC_PORT; - - return new IPM2(sub_port, rpc_port); -}; - -/** - * IPM2, Pm2 Interface - */ - -var IPM2 = function(sub_port, rpc_port) { - if (!(this instanceof IPM2)) return new IPM2(sub_port, rpc_port); - var self = this; - - EventEmitter.call(this); - - this.sub_port = sub_port; - this.rpc_port = rpc_port; - - - var sub = axon.socket('sub-emitter'); - var sub_sock = this.sub_sock = sub.connect(sub_port); - this.bus = sub; - - var req = axon.socket('req'); - var rpc_sock = this.rpc_sock = req.connect(rpc_port); - this.rpc_client = new rpc.Client(req); - - this.rpc = {}; - - rpc_sock.on('connect', function() { - log('rpc_sock:ready'); - self.emit('rpc_sock:ready'); - generateMethods(function() { - self.emit('ready'); - }); - }); - - rpc_sock.on('close', function() { - log('rpc_sock:closed'); - self.emit('close'); - }); - - rpc_sock.on('reconnect attempt', function() { - log('rpc_sock:reconnecting'); - self.emit('reconnecting'); - }); - - sub_sock.on('connect', function() { - log('sub_sock ready'); - self.emit('sub_sock:ready'); - }); - - sub_sock.on('close', function() { - log('sub_sock:closed'); - self.emit('closed'); - }); - - sub_sock.on('reconnect attempt', function() { - log('sub_sock:reconnecting'); - self.emit('reconnecting'); - }); - - /** - * Disconnect socket connections. This will allow Node to exit automatically. - * Further calls to PM2 from this object will throw an error. - */ - this.disconnect = function () { - self.sub_sock.close(); - self.rpc_sock.close(); - }; - - /** - * Generate method by requesting exposed methods by PM2 - * You can now control/interact with PM2 - */ - var generateMethods = function(cb) { - log('Requesting and generating RPC methods'); - self.rpc_client.methods(function(err, methods) { - Object.keys(methods).forEach(function(key) { - var method_signature, md; - method_signature = md = methods[key]; - - log('+-- Creating %s method', md.name); - - (function(name) { - self.rpc[name] = function() { - log(name); - var args = Array.prototype.slice.call(arguments); - args.unshift(name); - self.rpc_client.call.apply(self.rpc_client, args); - }; - })(md.name); - - }); - return cb(); - }); - }; -}; - -util.inherits(IPM2, EventEmitter); diff --git a/lib/Satan.js b/lib/Satan.js index e6df06ba..0c8e232e 100644 --- a/lib/Satan.js +++ b/lib/Satan.js @@ -329,7 +329,7 @@ Satan.launchDaemon = function launchDaemon(cb) { debug('Launching daemon'); var SatanJS = p.resolve(p.dirname(module.filename), 'Satan.js'); - var InteractorDaemonizer = require('./Interactor/InteractorDaemonizer.js'); + var InteractorDaemonizer = require('keymetrics-agent/src/InteractorClient'); var node_args = []; @@ -385,7 +385,7 @@ Satan.launchDaemon = function launchDaemon(cb) { debug('PM2 daemon launched with return message: ', msg); child.removeListener('error', onError); child.disconnect(); - InteractorDaemonizer.launchAndInteract({}, function(err, data) { + InteractorDaemonizer.launchAndInteract({}, {}, function(err, data) { if (data) debug('Interactor launched'); return cb ? cb(null, child) : false; diff --git a/package.json b/package.json index 1855d6c3..6ef05aa4 100644 --- a/package.json +++ b/package.json @@ -169,6 +169,7 @@ "debug": "^3.0", "eventemitter2": "1.0.5", "fclone": "1.0.11", + "keymetrics-agent": "0.2.0", "mkdirp": "0.5.1", "moment": "^2.19", "needle": "^2.1.0", diff --git a/test/interface/aggregator.mocha.js b/test/interface/aggregator.mocha.js deleted file mode 100644 index b90d0d79..00000000 --- a/test/interface/aggregator.mocha.js +++ /dev/null @@ -1,239 +0,0 @@ - -process.env.DEBUG='pm2:aggregator'; -var should = require('should'); -var Aggregator = require('../../lib/Interactor/TransactionAggregator.js'); -var Utility = require('../../lib/Interactor/Utility.js'); -var Plan = require('../helpers/plan.js'); -var TraceFactory = require('./misc/trace_factory.js'); -var TraceMock = require('./misc/trace.json'); -var path = require('path'); -var fs = require('fs'); - -describe('Transactions Aggregator', function() { - var aggregator; - var stackParser; - - it('should instanciate context cache', function() { - var cache = new Utility.Cache({ - miss: function (key) { - try { - var content = fs.readFileSync(path.resolve(key)); - return content.toString().split(/\r?\n/); - } catch (err) { - return undefined; - } - } - }) - - stackParser = new Utility.StackTraceParser({ cache: cache, context: 2}); - }); - - it('should instanciate aggregator', function() { - aggregator = new Aggregator({ stackParser: stackParser}); - }); - - describe('.censorSpans', function() { - var trace = TraceFactory.generateTrace('/yoloswag/swag', 2); - - it('should not fail', function() { - aggregator.censorSpans(null); - }); - - it('should censor span', function() { - should.exist(trace.spans[1].labels.results); - aggregator.censorSpans(trace.spans); - should.not.exist(trace.spans[1].labels.results); - trace.spans[1].labels.cmd.should.containEql('?'); - }); - }); - - describe('.isIdentifier', function() { - it('should be an identifier (api version)', function() { - aggregator.isIdentifier('v1').should.equal(true); - }); - - it('should be an identifier (number)', function() { - aggregator.isIdentifier('123').should.equal(true); - }); - - it('should be an identifier (random str)', function() { - aggregator.isIdentifier('65f4ez656').should.equal(true); - }); - - it('should be an identifier (uuid)', function() { - aggregator.isIdentifier('123e4567-e89b-12d3-a456-426655440000').should.equal(true); - aggregator.isIdentifier('123e4567e89b12d3a456426655440000').should.equal(true); - }); - - it('should be an identifier', function() { - aggregator.isIdentifier('toto-toto-tooa').should.equal(true); - aggregator.isIdentifier('toto@toto.fr').should.equal(true); - aggregator.isIdentifier('toto@toto.fr').should.equal(true); - aggregator.isIdentifier('fontawesome-webfont.eot').should.equal(true); - aggregator.isIdentifier('life_is_just_fantasy').should.equal(true); - aggregator.isIdentifier('OR-IS_THIS-REAL_LIFE').should.equal(true); - }); - - it('should be NOT an identifier', function() { - aggregator.isIdentifier('bucket').should.equal(false); - aggregator.isIdentifier('admin').should.equal(false); - aggregator.isIdentifier('auth').should.equal(false); - aggregator.isIdentifier('users').should.equal(false); - aggregator.isIdentifier('version').should.equal(false); - }); - }); - - describe('.matchPath - aggregate', function() { - var routes = { - 'bucket/6465577': { spans: true } - }; - - it('should not fail', function() { - aggregator.matchPath(); - aggregator.matchPath('/'); - aggregator.matchPath('/', {}); - aggregator.matchPath('/', { - '/' : {} - }); - }); - - it('should match first route', function() { - var match = aggregator.matchPath('bucket/67754', routes); - should.exist(match); - match.should.be.a.String(); - match.should.equal('bucket/*'); - should.exist(routes['bucket/*']) - }); - - it('should NOT match any route', function() { - should.not.exist(aggregator.matchPath('toto/67754', routes)); - }); - - it('should match aggregated route with *', function() { - var match = aggregator.matchPath('bucket/87998', routes); - should.exist(match); - match.should.be.a.String(); - match.should.equal('bucket/*'); - should.exist(routes['bucket/*']) - }); - }); - - describe('merging trace together', function() { - var trace = TraceFactory.generateTrace('yoloswag/swag', 2); - var ROUTES = { - 'yoloswag/swag': {} - }; - - it('should not fail', function() { - aggregator.mergeTrace() - aggregator.mergeTrace(null, trace) - aggregator.mergeTrace({}, trace) - aggregator.mergeTrace({}) - }); - - it('should add a trace', function() { - aggregator.mergeTrace(ROUTES['yoloswag/swag'], trace) - ROUTES['yoloswag/swag'].meta.histogram.getCount().should.be.equal(1); - ROUTES['yoloswag/swag'].variances.length.should.be.equal(1); - ROUTES['yoloswag/swag'].variances[0].spans.length.should.be.equal(3); - }); - - it('should merge with the first variance', function() { - aggregator.mergeTrace(ROUTES['yoloswag/swag'], trace); - ROUTES['yoloswag/swag'].variances.length.should.be.equal(1); - ROUTES['yoloswag/swag'].variances[0].histogram.getCount().should.be.equal(2); - }); - - it('should merge as a new variance with the same route', function () { - var trace2 = TraceFactory.generateTrace('yoloswag/swag', 3) - trace2.spans.forEach(function (span) { - span.min = span.max = span.mean = Math.round(new Date(span.endTime) - new Date(span.startTime)); - }) - aggregator.mergeTrace(ROUTES['yoloswag/swag'], trace2); - ROUTES['yoloswag/swag'].meta.histogram.getCount().should.be.equal(3); - ROUTES['yoloswag/swag'].variances.length.should.be.equal(2); - ROUTES['yoloswag/swag'].variances[0].histogram.getCount().should.be.equal(2); - ROUTES['yoloswag/swag'].variances[1].histogram.getCount().should.be.equal(1); - ROUTES['yoloswag/swag'].variances[1].spans.length.should.be.equal(4); - }); - }); - - describe('.aggregate', function() { - it('should not fail', function() { - var dt = aggregator.aggregate(null); - should(dt).be.false(); - }); - - it('should aggregate', function() { - // Simulate some data - var packet = TraceFactory.generatePacket('yoloswag/swag', 'appname'); - aggregator.aggregate(packet); - packet = TraceFactory.generatePacket('yoloswag/swag', 'appname'); - aggregator.aggregate(packet); - packet = TraceFactory.generatePacket('yoloswag/swag', 'appname'); - aggregator.aggregate(packet); - packet = TraceFactory.generatePacket('sisi/aight', 'appname'); - aggregator.aggregate(packet); - packet = TraceFactory.generatePacket('sisi/aight', 'APP2'); - aggregator.aggregate(packet); - - var agg = aggregator.getAggregation(); - - // should get 2 apps in agg - should.exist(agg['appname']); - should.exist(agg['APP2']); - - // should contain 2 routes for appname - Object.keys(agg['appname'].routes).length.should.eql(2); - should.exist(agg['appname'].process); - agg['appname'].meta.trace_count.should.eql(4); - should.exist(agg['appname'].meta.histogram.percentiles([0.5])[0.5]); - - // should pm_id not taken into account - should.not.exist(agg['appname'].process.pm_id); - }); - }); - - describe('.normalizeAggregation', function() { - it('should get normalized aggregattion', function(done) { - var ret = aggregator.prepareAggregationforShipping(); - should.exist(ret['appname'].process.server); - should.exist(ret['APP2'].process.server); - done(); - }); - }); - - describe('.resetAggregation and .clearData', function() { - it('should get transactions', function() { - var cache = aggregator.getAggregation(); - Object.keys(cache).length.should.eql(2); - }); - - it('should .resetAggregation for "appname" app', function() { - var cache = aggregator.getAggregation(); - - cache['appname'].meta.trace_count.should.eql(4); - Object.keys(cache['appname'].routes).length.should.eql(2); - - aggregator.resetAggregation('appname', {}) - cache = aggregator.getAggregation(); - Object.keys(cache).length.should.eql(2); - - cache['appname'].meta.trace_count.should.eql(0); - Object.keys(cache['appname'].routes).length.should.eql(0); - }); - - it('should .clearData', function() { - var cache = aggregator.getAggregation(); - cache['APP2'].meta.trace_count.should.eql(1); - Object.keys(cache['APP2'].routes).length.should.eql(1); - aggregator.clearData(); - - cache = aggregator.getAggregation(); - cache['APP2'].meta.trace_count.should.eql(0); - Object.keys(cache['APP2'].routes).length.should.eql(0); - }); - - }); - -}); diff --git a/test/interface/bus.fork.spec.mocha.js b/test/interface/bus.fork.spec.mocha.js index 3ed46921..88e52737 100644 --- a/test/interface/bus.fork.spec.mocha.js +++ b/test/interface/bus.fork.spec.mocha.js @@ -1,6 +1,5 @@ var should = require('should'); -var Ipm2 = require('../../lib/Interactor/pm2-interface'); var PM2 = require('../..'); var Plan = require('../helpers/plan.js'); diff --git a/test/interface/bus.spec.mocha.js b/test/interface/bus.spec.mocha.js index 706d5a1e..bbf593a9 100644 --- a/test/interface/bus.spec.mocha.js +++ b/test/interface/bus.spec.mocha.js @@ -1,6 +1,5 @@ var should = require('should'); -var Ipm2 = require('../../lib/Interactor/pm2-interface'); var PM2 = require('../..'); var Plan = require('../helpers/plan.js'); diff --git a/test/interface/cache.mocha.js b/test/interface/cache.mocha.js deleted file mode 100644 index ecd30771..00000000 --- a/test/interface/cache.mocha.js +++ /dev/null @@ -1,86 +0,0 @@ - -var should = require('should'); -var Utility = require('../../lib/Interactor/Utility.js'); -var path = require('path'); -var fs = require('fs'); - -describe('Cache Utility', function() { - var aggregator; - var stackParser; - var cache; - - it('should instanciate context cache', function() { - cache = new Utility.Cache({ - miss: function (key) { - try { - var content = fs.readFileSync(path.resolve(key)); - return content.toString().split(/\r?\n/); - } catch (err) { - return null; - } - } - }) - }); - - it('should get null without key', function() { - should(cache.get()).be.null(); - }); - - it('should get null with unknow value', function() { - should(cache.get('toto')).be.null(); - }); - - it('should get null', function() { - should(cache.get()).be.null(); - }); - - it('should set null', function() { - should(cache.set()).be.false(); - }); - - it('should not set key without value', function() { - should(cache.set('toto')).be.false(); - }); - - it('should set value', function() { - should(cache.set('toto', 'val')).be.true(); - }); - - it('should get value', function() { - should(cache.get('toto')).eql('val'); - }); - - it('should reset', function() { - cache.reset(); - }); - - it('should get null with unknow value', function() { - should(cache.get('toto')).be.null(); - }); - - it('should instanciate context cache with ttl', function() { - cache = new Utility.Cache({ - miss: function (key) { - try { - var content = fs.readFileSync(path.resolve(key)); - return content.toString().split(/\r?\n/); - } catch (err) { - return null; - } - }, - ttl: 1 - }); - }); - - it('should add a key', function () { - should(cache.set('toto', 'yeslife')).be.true(); - }); - - it('should wait one second to see the key disapear', function (done) { - setTimeout(function () { - should(cache.get('toto')).be.null(); - done(); - }, 3000); - }); - -}); diff --git a/test/interface/custom-actions.mocha.js b/test/interface/custom-actions.mocha.js deleted file mode 100644 index 5d6117ec..00000000 --- a/test/interface/custom-actions.mocha.js +++ /dev/null @@ -1,169 +0,0 @@ - - -var PM2 = require('../..'); -var should = require('should'); -var nssocket = require('nssocket'); -var events = require('events'); -var util = require('util'); - -var Cipher = require('../../lib/Interactor/Cipher.js'); -var cst = require('../../constants.js'); -var Plan = require('../helpers/plan.js'); -var Interactor = require('../../lib/Interactor/InteractorDaemonizer.js'); - -var server = new events.EventEmitter(); -var pm2_bus; - -process.env.NODE_ENV = 'local_test'; - -var meta_connect = { - secret_key : 'osef', - public_key : 'osef', - machine_name : 'osef' -}; - -/** - * Mock server receiving data - * @method forkInteractor - * @return CallExpression - */ -function createMockServer(cb) { - var server = nssocket.createServer(function(_socket) { - - console.log('Got new connection in Mock server'); - - server.on('cmd', function(data) { - console.log('Sending command %j', data); - _socket.send(data._type, data); - }); - - _socket.data('*', function(data) { - this.event.forEach(function(ev) { - server.emit(ev, data); - }); - }); - - }); - - server.on('error', function(e) { - throw new Error(e); - }); - - server.on('listening', function() { - cb(null, server); - }); - - server.listen(4322, '0.0.0.0'); -} - -function startSomeApps(pm2, cb) { - pm2.start({ - script : './events/custom_action.js', - name : 'custom-action' - }, cb); -} - -describe('Custom actions', function() { - var server; - var interactor; - var pm2 = new PM2.custom({ - independent : true, - cwd : __dirname + '/../fixtures', - secret_key : 'osef', - public_key : 'osef', - machine_name : 'osef', - daemon_mode: true - });; - - before(function(done) { - createMockServer(function(err, _server) { - server = _server; - pm2.connect(function(err) { - startSomeApps(pm2, function() { - pm2.launchBus(function(err, bus) { - pm2_bus = bus; - setTimeout(done, 500); - }); - }); - }); - }); - }); - - after(function(done) { - server.close(); - pm2.destroy(done); - }); - - it('should send ask, receive ask:rep and identify agent', function(done) { - server.once('ask:rep', function(pck) { - var data = Cipher.decipherMessage(pck.data, meta_connect.secret_key); - data.machine_name.should.eql(meta_connect.machine_name); - done(); - }); - - server.emit('cmd', { _type : 'ask' }); - }); - - /** - * PM2 agent is now identified - */ - - it('should trigger remote action successfully', function(done) { - var plan = new Plan(2, done); - - var success = function(pck) { - plan.ok(true); - server.removeListener('trigger:action:failure', failure); - }; - - var failure = function(pck) { - console.log(pck); - plan.ok(false); - }; - - server.once('trigger:action:success', success); - - server.once('trigger:action:failure', failure); - - pm2_bus.on('axm:reply', function(pck) { - pck.data.return.success.should.be.true; - pck.data.return.subobj.a.should.eql('b'); - plan.ok(true); - }); - - server.emit('cmd', { - _type : 'trigger:action', - process_id : 0, - action_name : 'refresh:db' - }); - }); - - it('should trigger failure action', function(done) { - var plan = new Plan(1, done); - - var success = function(pck) { - plan.ok(false); - }; - - var failure = function(pck) { - server.removeListener('trigger:action:success', success); - plan.ok(true); - }; - - server.once('trigger:action:success', success); - - server.once('trigger:action:failure', failure); - - pm2_bus.on('axm:reply', function(pck) { - plan.ok(false); - }); - - server.emit('cmd', { - _type : 'trigger:action', - process_id : 0, - action_name : 'unknown:action' - }); - }); - - -}); diff --git a/test/interface/exception.e2e.mocha.js b/test/interface/exception.e2e.mocha.js deleted file mode 100644 index 65ef7f78..00000000 --- a/test/interface/exception.e2e.mocha.js +++ /dev/null @@ -1,88 +0,0 @@ - -process.env.NODE_ENV = 'local_test'; -process.env.KM_URL_REFRESH_RATE = 1000; - -var axon = require('pm2-axon'); -var PM2 = require('../..'); -var should = require('should'); -var sub; - -function listen(cb) { - sub = axon.socket('sub'); - sub.bind(8080, cb); -} - -function listenRev(cb) { - var listener_server = require('nssocket').createServer(function(_socket) { - }); - - listener_server.listen(4322, '0.0.0.0', function() { - console.log('Reverse interact online'); - cb(); - }); -} - -describe('Programmatically test interactor', function() { - var pm2; - - before(function(done) { - listen(function() { - listenRev(function() { - - pm2 = new PM2.custom({ - public_key : 'xxx', - secret_key : 'yyy', - cwd : __dirname + '/../fixtures/interface' - }); - - pm2.connect(function() { - pm2.kill(function() { - done(); - }); - }); - }); - }); - }); - - after(function(done) { - pm2.kill(done); - }); - - describe('application testing', function() { - it('should start test application', function(done) { - sub.once('message', function(data) { - var packet = JSON.parse(data); - packet.data['process:event'].length.should.eql(2) - done(); - }); - - pm2.start({ - script : 'process_exception_with_logs.js', - name : 'API' - }, function(err, data) { - if (err) done(err); - //console.log(arguments); - }); - }); - - it('should get transaction trace via interactor output', function(done) { - (function callAgain() { - sub.once('message', function(data) { - var packet = JSON.parse(data); - - if (packet.data['process:exception']) { - packet.data['process:exception'][0].data.callsite.should.containEql('process_exception_with_logs.js:7'); - packet.data['process:exception'][0].data.context.should.containEql('console.log'); - should.exist(packet.data['process:exception'][0].data.last_logs); - //console.log - done(); - } - else callAgain(); - }); - })() - - pm2.trigger('API', 'exception'); - }); - - }); -}); diff --git a/test/interface/filter.mocha.js b/test/interface/filter.mocha.js deleted file mode 100644 index 9e48d7cf..00000000 --- a/test/interface/filter.mocha.js +++ /dev/null @@ -1,23 +0,0 @@ - -var Filter = require('../../lib/Interactor/Filter.js'); -var should = require('should'); -var os = require('os'); - -describe('Filter Utility', function() { - it('should .machineSnapshot works as expected', function() { - var filtered = Filter.machineSnapshot([], { - REVERSE_INTERACT : true, - PM2_VERSION : '2.2.0' - }); - filtered.server.should.have.properties(['loadavg', 'total_mem', 'free_mem']); - should(filtered.server.total_mem).eql(os.totalmem()); - should(filtered.server.arch).eql(os.arch()); - }); - - it('should .monitoring works as expected', function() { - var filtered = Filter.monitoring([], {}); - filtered.should.have.properties(['loadavg', 'total_mem', 'free_mem', 'processes']); - filtered.total_mem.should.eql(os.totalmem()); - }); - -}); diff --git a/test/interface/interactor.connect.mocha.js b/test/interface/interactor.connect.mocha.js deleted file mode 100644 index f9974038..00000000 --- a/test/interface/interactor.connect.mocha.js +++ /dev/null @@ -1,227 +0,0 @@ - -process.env.NODE_ENV = 'local_test'; -process.env.TRAVIS = true; -process.env.DEBUG='interface:*'; - -var PM2 = require('../..'); -var should = require('should'); -var nssocket = require('nssocket'); -var events = require('events'); -var util = require('util'); -var axon = require('pm2-axon'); -var sock = axon.socket('sub'); - -var pub_sock = sock.bind(8080); -var Cipher = require('../../lib/Interactor/Cipher.js'); -var cst = require('../../constants.js'); -var Plan = require('../helpers/plan.js'); -var Configuration = require('../../lib/Configuration.js'); -var Helpers = require('../helpers/apps.js'); - -var server = null; -var listener_server; - -var _socket_list = []; - -var meta_connect = { - secret_key : 'osef', - public_key : 'osef', - machine_name : 'osef' -}; - -/** - * Mock server receiving data - * @method forkInteractor - * @return CallExpression - */ -function createMockServer(cb) { - - pub_sock.server.on('connection', function(socket) { - _socket_list.push(socket); - console.log('Got new connection on mock server'); - }); - - server = new events.EventEmitter(); - - listener_server = nssocket.createServer(function(_socket) { - server.on('cmd', function(data) { - _socket.send(data._type, data); - }); - - _socket.data('*', function(data) { - this.event.forEach(function(ev) { - server.emit(ev, data); - }); - }); - - }); - - listener_server.on('error', function(e) { - throw new Error(e); - }); - - listener_server.on('listening', function() { - cb(null, server); - }); - - listener_server.listen(4322, '0.0.0.0'); -} - -describe('Interactor testing', function() { - var server; - var interactor; - var pm2_bus; - - var pm2 = new PM2.custom({ - independent : true, - cwd : __dirname + '/../fixtures', - secret_key : 'osef', - public_key : 'osef', - machine_name : 'osef', - daemon_mode: true - }); - - before(function(done) { - Configuration.unset('pm2:passwd', function(err, data) { - createMockServer(function(err, _server) { - server = _server; - - pm2.connect(function(err, data) { - Helpers.startSomeApps(pm2, function(err, dt) { - done(); - }); - }); - }); - }); - }); - - after(function(done) { - listener_server.close(); - pm2.destroy(done); - }); - - describe('Interactor methods', function() { - it('should display info', function(done) { - pm2.interactInfos(function(err, meta) { - meta.should.have.properties([ - 'machine_name', - 'public_key', - 'secret_key', - 'socket_path', - 'pm2_home_monitored' - ]) - - meta.pm2_home_monitored.should.eql(pm2.pm2_home); - done(); - }); - }); - }); - - describe('Input command / Output data checks', function() { - it('should send ask, receive ask:rep and identify agent', function(done) { - server.once('ask:rep', function(pck) { - var data = Cipher.decipherMessage(pck.data, meta_connect.secret_key); - data.machine_name.should.eql(meta_connect.machine_name); - done(); - }); - - server.emit('cmd', { _type : 'ask' }); - }); - - it('should get status via PushInteractor and PM2 should be statused as not protected', function(done) { - sock.once('message', function(data) { - var dt = JSON.parse(data); - - dt.public_key.should.eql('osef'); - - var status = dt.data.status.data; - var procs = status.process; - var server = status.server; - - procs.length.should.eql(1); - - var meta = dt.data.status; - should.exists(dt.sent_at); - meta.protected.should.be.false(); - meta.rev_con.should.be.true(); - meta.server_name.should.eql('osef'); - done(); - }); - - it('should get status via PushInteractor and PM2 should be statused as not protected', function(done) { - sock.once('message', function(data) { - var dt = JSON.parse(data); - - dt.public_key.should.eql('osef'); - - var status = dt.data.status.data; - var procs = status.process; - var server = status.server; - - procs.length.should.eql(1); - - var meta = dt.data.status; - - should.exists(dt.sent_at); - meta.protected.should.be.false(); - meta.rev_con.should.be.true(); - meta.server_name.should.eql('osef'); - - done(); - }); - }); - }); - - describe('General behaviors', function() { - it('should receive event application restart', function(done) { - - sock.once('message', function(data) { - var dt = JSON.parse(data); - var monitoring = dt.data.monitoring; - var process_event = dt.data['process:event']; - - //console.log(JSON.stringify(process_event, '', 2)); - done(); - }); - - pm2.restart('all', function() {}); - }); - }); - - describe('PM2 password checking', function() { - it('should set a password', function(done) { - pm2.set('pm2:passwd', 'testpass', function(err, data) { - should.not.exists(err); - setTimeout(done, 1000); - }); - }); - - it('should interactor be notified of password set', function(done) { - sock.once('message', function(data) { - var dt = JSON.parse(data); - // Has switched to true - dt.data.status.protected.should.be.true(); - done(); - }); - }); - }); - - }); - - describe('Offline', function() { - it('should handle offline gracefully', function(done) { - _socket_list.forEach(function(socket, i) { - _socket_list[i].destroy(); - }); - - sock.closeSockets(); - - pub_sock.server.close(function() { - console.log('Server closed'); - }); - setTimeout(done, 500); - }); - }); - - -}); diff --git a/test/interface/interactor.daemonizer.mocha.js b/test/interface/interactor.daemonizer.mocha.js deleted file mode 100644 index 35dba90c..00000000 --- a/test/interface/interactor.daemonizer.mocha.js +++ /dev/null @@ -1,164 +0,0 @@ - -var should = require('should'); -var fs = require('fs'); -var os = require('os'); -var default_conf = require('../../constants'); -var interactorDaemonizer = require('../../lib/Interactor/InteractorDaemonizer'); -var json5 = require('../../lib/tools/json5.js'); - -describe('Daemonizer interactor', function() { - before(function(done) { - delete process.env.PM2_SECRET_KEY; - delete process.env.PM2_PUBLIC_KEY; - delete process.env.KEYMETRICS_NODE; - - try { - fs.unlinkSync(default_conf.INTERACTION_CONF); - } catch(e) {} - done(); - }); - - describe('General tests', function() { - it('should try get set keys but get error because nothing exposed', function(done) { - interactorDaemonizer.getOrSetConf(default_conf, null, function(err, data) { - err.should.not.be.null(); - done(); - }); - }); - }); - - describe('Default behavior', function() { - after(function() { - fs.unlinkSync(default_conf.INTERACTION_CONF); - }); - - it('should set right node by default', function(done) { - interactorDaemonizer.getOrSetConf(default_conf, { - secret_key : 'xxx', - public_key : 'yyy', - machine_name : null, - info_node : null - }, function(err, data) { - should(err).be.null(); - data.info_node.should.eql(default_conf.KEYMETRICS_ROOT_URL); - - var interaction_conf = json5.parse(fs.readFileSync(default_conf.INTERACTION_CONF)); - interaction_conf.info_node.should.eql(default_conf.KEYMETRICS_ROOT_URL); - - return done(); - }); - }); - - it('should retrieve data from file without env variable', function(done) { - interactorDaemonizer.getOrSetConf(default_conf, null, function(err, data) { - should(err).be.null(); - data.secret_key.should.eql('xxx'); - data.public_key.should.eql('yyy'); - data.info_node.should.eql(default_conf.KEYMETRICS_ROOT_URL); - - var interaction_conf = json5.parse(fs.readFileSync(default_conf.INTERACTION_CONF)); - interaction_conf.info_node.should.eql(default_conf.KEYMETRICS_ROOT_URL); - - return done(); - }); - }); - - it('should set new keys and write in configuration file', function(done) { - interactorDaemonizer.getOrSetConf(default_conf, { - secret_key : 'XXXS2', - public_key : 'XXXP2', - info_node : 'test2.url' - }, function(err, data) { - should(err).be.null(); - data.secret_key.should.eql('XXXS2'); - data.public_key.should.eql('XXXP2'); - data.info_node.should.eql('test2.url'); - - var interaction_conf = json5.parse(fs.readFileSync(default_conf.INTERACTION_CONF)); - interaction_conf.secret_key.should.eql('XXXS2'); - interaction_conf.public_key.should.eql('XXXP2'); - interaction_conf.info_node.should.eql('test2.url'); - - should.exist(interaction_conf.version_management.active); - should(interaction_conf.version_management.password).be.null(); - - interaction_conf.machine_name.should.startWith(os.hostname()); - return done(); - }); - }); - - it('should retrieve data from file without env variable', function(done) { - interactorDaemonizer.getOrSetConf(default_conf, null, function(err, data) { - should(err).be.null(); - data.secret_key.should.eql('XXXS2'); - data.public_key.should.eql('XXXP2'); - data.info_node.should.eql('test2.url'); - return done(); - }); - }); - - it('should retrieve the same data with null fields', function(done) { - interactorDaemonizer.getOrSetConf(default_conf, { - secret_key : null, - public_key : null, - machine_name : null, - info_node : null - }, function(err, data) { - should(err).be.null(); - data.secret_key.should.eql('XXXS2'); - data.public_key.should.eql('XXXP2'); - data.info_node.should.eql('test2.url'); - return done(); - }); - }); - - }); - - describe('Environment variable override', function() { - before(function() { - process.env.PM2_SECRET_KEY = 'XXXS'; - process.env.PM2_PUBLIC_KEY = 'XXXP'; - process.env.KEYMETRICS_NODE = 'test.url'; - }); - - after(function() { - delete process.env.PM2_SECRET_KEY; - delete process.env.PM2_PUBLIC_KEY; - delete process.env.KEYMETRICS_NODE; - }); - - it('should work with env variables and create file', function(done) { - - interactorDaemonizer.getOrSetConf(default_conf, { - secret_key : null, - public_key : null, - machine_name : null, - info_node : null - }, function(err, data) { - should(err).be.null(); - data.secret_key.should.eql('XXXS'); - data.public_key.should.eql('XXXP'); - data.info_node.should.eql('test.url'); - - should.exist(data.version_management.active); - should(data.version_management.password).be.null(); - try { - fs.statSync(default_conf.INTERACTION_CONF); - } catch(e) { - return done(e); - } - return done(); - }); - }); - - it('should retrieve data from file without env variable', function(done) { - interactorDaemonizer.getOrSetConf(default_conf, null, function(err, data) { - should(err).be.null(); - data.secret_key.should.eql('XXXS'); - data.public_key.should.eql('XXXP'); - data.info_node.should.eql('test.url'); - return done(); - }); - }); - }); -}); diff --git a/test/interface/misc/trace.json b/test/interface/misc/trace.json deleted file mode 100644 index 962497e6..00000000 --- a/test/interface/misc/trace.json +++ /dev/null @@ -1,167 +0,0 @@ -[{ - "projectId": 0, - "traceId": "43fd648369374111b4ee56565c7cecb2", - "spans": [ - { - "name": "/api/bucket", - "parentSpanId": "0", - "spanId": 36, - "kind": "RPC_SERVER", - "labels": { - "http/method": "OPTIONS", - "http/url": "http://cl1.km.io/api/bucket", - "http/source/ip": "::ffff:127.0.0.1", - "http/status_code": "204" - }, - "startTime": "2016-11-13T16:55:51.677Z", - "endTime": "2016-11-13T16:55:51.680Z" - }, - { - "name": "redis-set", - "parentSpanId": 36, - "spanId": 37, - "kind": "RPC_CLIENT", - "labels": { - "command": "set", - "arguments": "[\"sess:rYrMvzCAwhlXrIOp8swjKxvIYh1UN5EF\",\"{\\\"cookie\\\":{\\\"originalMaxAge\\\":null,\\\"expires\\\":null,\\\"secure\\\":false,\\\"httpOnly\\\":true,\\\"domain\\\":\\\".km.io\\\",\\\"path\\\":\\\"/\\\"},\\\"passport\\\":{}}\",\"EX\",120]", - "result": "OK" - }, - "startTime": "2016-11-13T16:55:51.678Z", - "endTime": "2016-11-13T16:55:51.678Z" - } - ] -},{ - "projectId": 0, - "traceId": "43887a4ff20c44b990c8ec6540440690", - "spans": [ - { - "name": "/api/bucket", - "parentSpanId": "0", - "spanId": 38, - "kind": "RPC_SERVER", - "labels": { - "http/method": "GET", - "http/url": "http://cl1.km.io/api/bucket", - "http/source/ip": "::ffff:127.0.0.1", - "express/request.route.path": "/", - "http/status_code": "304" - }, - "startTime": "2016-11-13T16:55:51.779Z", - "endTime": "2016-11-13T16:55:51.829Z" - }, - { - "name": "redis-get", - "parentSpanId": 38, - "spanId": 39, - "kind": "RPC_CLIENT", - "labels": { - "command": "get", - "arguments": "[\"sess:As-xHUEPTRSvi9lrK8j3gWO_mxnl7Llk\"]", - "result": "{\"cookie\":{\"originalMaxAge\":null,\"expires\":null,\"secure\":false,\"httpOnly\":true,\"domain\":\".km.io\",\"path\":\"/\"},\"passport\":{}}" - }, - "startTime": "2016-11-13T16:55:51.781Z", - "endTime": "2016-11-13T16:55:51.782Z" - }, - { - "name": "mongo-cursor", - "parentSpanId": 38, - "spanId": 40, - "kind": "RPC_CLIENT", - "labels": { - "db": "devdb6.tokens", - "cmd": "{\"find\":\"devdb6.tokens\",\"limit\":-1,\"skip\":0,\"query\":{\"type\":\"access_token\",\"token\":\"u009vf00u9cdyf8yyzzhpkxrrhq07euhfd3p106mfgbbqq3icfd9katq7oz2oe6bwqxhuzhl9uzkquq8mgnz0k80oryr7i4ym2litx317uakb8dcm9y5irqi7l2f5e81\"},\"slaveOk\":false,\"batchSize\":1}", - "results": "{_id:{_bsontype:ObjectID,id:X(ÂÓð†\f#\u0002í\\},token:u009vf00u9cdyf8yyzzhpkxrrhq07euhfd3p106mfgbbqq3icfd9katq7oz2oe6bwqxhuz..." - }, - "startTime": "2016-11-13T16:55:51.783Z", - "endTime": "2016-11-13T16:55:51.786Z" - }, - { - "name": "mongo-cursor", - "parentSpanId": 38, - "spanId": 41, - "kind": "RPC_CLIENT", - "labels": { - "db": "devdb6.users", - "cmd": "{\"find\":\"devdb6.users\",\"limit\":0,\"skip\":0,\"query\":{\"_id\":{\"$in\":[\"57f26987af49d57472b3d104\"]}},\"slaveOk\":false}", - "results": "{_id:{_bsontype:ObjectID,id:Wòi‡¯IÕtr³Ñ\u0004},short_id:k3l0x,auth_token:iuub9912b8ruh6h7dgoi,username:alexandre,email:alex..." - }, - "startTime": "2016-11-13T16:55:51.787Z", - "endTime": "2016-11-13T16:55:51.789Z" - }, - { - "name": "mongo-cursor", - "parentSpanId": 38, - "spanId": 42, - "kind": "RPC_CLIENT", - "labels": { - "db": "devdb6.clients", - "cmd": "{\"find\":\"devdb6.clients\",\"limit\":0,\"skip\":0,\"query\":{\"_id\":{\"$in\":[\"57fe6588ffc3dd335c78b7e0\"]}},\"slaveOk\":false}", - "results": "{_id:{_bsontype:ObjectID,id:WþeÿÃÝ3\\x·à},name:Keymetrics Dashboard,clientID:5413907556,clientSecret:2393878333,autho..." - }, - "startTime": "2016-11-13T16:55:51.788Z", - "endTime": "2016-11-13T16:55:51.794Z" - }, - { - "name": "mongo-cursor", - "parentSpanId": 38, - "spanId": 43, - "kind": "RPC_CLIENT", - "labels": { - "db": "devdb6.users", - "cmd": "{\"find\":\"devdb6.users\",\"limit\":0,\"skip\":0,\"query\":{\"_id\":{\"$in\":[\"57f26987af49d57472b3d104\"]}},\"slaveOk\":false}" - }, - "startTime": "2016-11-13T16:55:51.789Z", - "endTime": "2016-11-13T16:55:51.790Z" - }, - { - "name": "mongo-cursor", - "parentSpanId": 38, - "spanId": 44, - "kind": "RPC_CLIENT", - "labels": { - "db": "devdb6.buckets", - "cmd": "{\"find\":\"devdb6.buckets\",\"limit\":0,\"skip\":0,\"query\":{\"_id\":{\"$in\":[\"57f269abaf49d57472b3d109\",\"581e81e03f91d96e46eb0f65\",\"581e831316d4875e482dd174\",\"581e836716d4875e482dd175\",\"581e83f316d4875e482dd176\",\"581e840c4a4ade7c49389b1e\",\"581e843e8c08e8b9494604a3\",\"581e84a20f148e364b5331f3\",\"581e859e0b5bce564d4b246e\",\"581e86a7eb307d47504fe25f\",\"581e86f9eb307d47504fe260\"]}},\"slaveOk\":false}", - "results": "{_id:{_bsontype:ObjectID,id:Wòi«¯IÕtr³Ñ\t},secret_id:mcp6snmnon1asmt,public_id:mxfiwlvzracelhl,node_cache:{_id:{_bsonty..." - }, - "startTime": "2016-11-13T16:55:51.792Z", - "endTime": "2016-11-13T16:55:51.794Z" - }, - { - "name": "mongo-cursor", - "parentSpanId": 38, - "spanId": 45, - "kind": "RPC_CLIENT", - "labels": { - "db": "devdb6.buckets", - "cmd": "{\"find\":\"devdb6.buckets\",\"limit\":0,\"skip\":0,\"query\":{\"_id\":{\"$in\":[\"57f269abaf49d57472b3d109\",\"581e81e03f91d96e46eb0f65\",\"581e831316d4875e482dd174\",\"581e836716d4875e482dd175\",\"581e83f316d4875e482dd176\",\"581e840c4a4ade7c49389b1e\",\"581e843e8c08e8b9494604a3\",\"581e84a20f148e364b5331f3\",\"581e859e0b5bce564d4b246e\",\"581e86a7eb307d47504fe25f\",\"581e86f9eb307d47504fe260\"]}},\"slaveOk\":false}" - }, - "startTime": "2016-11-13T16:55:51.794Z", - "endTime": "2016-11-13T16:55:51.794Z" - }, - { - "name": "mongo-cursor", - "parentSpanId": 38, - "spanId": 46, - "kind": "RPC_CLIENT", - "labels": { - "db": "devdb6.clients", - "cmd": "{\"find\":\"devdb6.clients\",\"limit\":0,\"skip\":0,\"query\":{\"_id\":{\"$in\":[\"57fe6588ffc3dd335c78b7e0\"]}},\"slaveOk\":false}" - }, - "startTime": "2016-11-13T16:55:51.794Z", - "endTime": "2016-11-13T16:55:51.795Z" - }, - { - "name": "redis-expire", - "parentSpanId": 38, - "spanId": 47, - "kind": "RPC_CLIENT", - "labels": { - "command": "expire", - "arguments": "[\"sess:As-xHUEPTRSvi9lrK8j3gWO_mxnl7Llk\",120]", - "result": "1" - }, - "startTime": "2016-11-13T16:55:51.827Z", - "endTime": "2016-11-13T16:55:51.829Z" - } - ] -}] diff --git a/test/interface/misc/trace_factory.js b/test/interface/misc/trace_factory.js deleted file mode 100644 index b2ee85b5..00000000 --- a/test/interface/misc/trace_factory.js +++ /dev/null @@ -1,146 +0,0 @@ - -var crypto = require('crypto'); -var moment = require('moment'); -var path = require('path'); -var WEBSITE_ROOT = 'http://toto.com'; -var spanId = 0; - -var random_routes = [ - '/api/bucket', - '/api/bucket/users', - '/api/bucket/chameau', - '/backo/testo' -]; - -function getRandomInt(min, max) { - min = Math.ceil(min); - return Math.floor(Math.random() * (Math.floor(max) - min)) + min; -} - -/** - * Generate Trace - * @param {String} route_path route name, default to random route name - * @param {Integer} db_query_nb number of spans, default to random number (0-10) - */ -function generateTrace(route_path, db_query_nb) { - if (!db_query_nb) - db_query_nb = getRandomInt(2, 5); - if (!route_path) - route_path = random_routes[getRandomInt(0, random_routes.length - 1)]; - var parentSpanId = ++spanId; - - var timeframe = []; - - var trace = { - projectId : 0, - traceId : crypto.randomBytes(32).toString('hex'), - spans : [{ - "name": route_path, - "parentSpanId": "0", - "spanId": parentSpanId, - "kind": "RPC_SERVER", - "labels": { - "http/method": "GET", - "http/path": route_path, - "http/url": WEBSITE_ROOT + route_path, - "http/source/ip": "::ffff:127.0.0.1", - "http/status_code": "204" - }, - "startTime": moment().subtract(db_query_nb + 1, 'seconds').toISOString(), - "endTime": moment().toISOString() - }] - }; - - for (var i = 0; i < db_query_nb; i++) { - trace.spans[i + 1] = { - "name": "mongo-cursor", - "parentSpanId": parentSpanId, - "spanId": ++spanId, - "kind": "RPC_CLIENT", - "labels": { - "db": "devdb6.tokens", - "cmd": "{\"find\":\"devdb6.tokens\",\"limit\":-1,\"skip\":0,\"query\":{\"type\":\"access_token\",\"token\":\"u00i7l2f5e81\"},\"slaveOk\":false,\"batchSize\":1}", - "results": "{_id:{_bsontype:ObjectID,id:X(Â\\},token:u009vf00..." - }, - "startTime": moment().subtract(db_query_nb - i + 1, 'seconds').toISOString(), - "endTime": moment().subtract(db_query_nb - i, 'seconds').toISOString() - }; - } - - return trace; -} - -exports.generateTrace = generateTrace; - -// Generate the same kind of data sent by pm2 -exports.generatePacket = function(route, app_name) { - return { - data : generateTrace(route), - process : { - name : app_name, - pm_id : 4, - server : 'test', - rev : 'xxx' - } - }; -}; - -exports.staticTrace = { - "spans": [ - { - "name":"/auth/signin", - "parentSpanId":"0", - "spanId":9, - "kind":"RPC_SERVER", - "labels":{ - "http/method":"POST", - "http/path":"/auth/signin", - "express/request.route.path":"/signin", - "http/status_code":"200" - }, - "startTime":"2016-11-11T14:03:18.449Z", - "endTime":"2016-11-11T14:03:18.792Z" - }, - { - "name":"mysql-query", - "parentSpanId": 9, - "spanId": 10, - "kind":"RPC_CLIENT", - "labels": { - "sql":"SELECT * FROM users WHERE mail = ?", - "values":"XXXXX", - "result":"XXXX" - }, - "startTime":"2016-11-11T14:03:18.558Z", - "endTime":"2016-11-11T14:03:18.568Z" - } - ] -}; - -exports.stacktrace = { - stack_frame: [ - { - file_name: 'events.js', - line_number: 10, - column_number: 10, - method_name: '' - }, - { - file_name: 'node_modules/express.js', - line_number: 10, - column_number: 10, - method_name: '' - }, - { - file_name: path.resolve(__dirname, 'trace_factory.js'), - line_number: 10, - column_number: 10, - method_name: '' - } - ] -} - - -if (require.main === module) { - console.log(generateTrace()); -} diff --git a/test/interface/monitor.mocha.js b/test/interface/monitor.mocha.js deleted file mode 100644 index 9baedf9c..00000000 --- a/test/interface/monitor.mocha.js +++ /dev/null @@ -1,90 +0,0 @@ -/* eslint-env mocha */ - -process.env.NODE_ENV='test'; - -'use strict'; - -var pm2 = require('../../index.js'); -var async = require('async'); -var assert = require('assert'); -var path = require('path'); -var PushInteractor = require('../../lib/Interactor/PushInteractor.js'); - -describe('unmonitor process', function () { - before(function (done) { - pm2.connect(function (err) { - if (err) return done(err); - pm2.delete('all', function () { - return done(); - }); - }); - }); - - after(function (done) { - pm2.delete('all', function (_) { - return done(); - }); - }); - - it('should start some processes', function (done) { - async.times(3, function (n, next) { - pm2.start({ - script: path.resolve(__dirname, '../fixtures/empty.js'), - name: 'test-' + n - }, next); - }, done); - }); - - it('should have 3 processes started', function (done) { - pm2.list(function (err, processes) { - assert(err === null); - assert(processes.length === 3); - return done(err); - }); - }); - - it('should start the push interactor', function (done) { - PushInteractor.start({ - url: 'toto', - conf: { - ipm2: require('../../lib/Interactor/pm2-interface.js')() - } - }); - return setTimeout(done, 100); - }); - - it('should return three processes with interactor', function (done) { - PushInteractor.preparePacket(function (err, data) { - if (err) return done(err); - - assert(data.process.length === 3); - return done(); - }); - }); - - it('should run the unmonitor command', function (done) { - pm2.monitorState('unmonitor', '0', done); - }); - - it('should return two processes with interactor', function (done) { - PushInteractor.preparePacket(function (err, data) { - if (err) return done(err); - - assert(data.process.length === 2); - return done(); - }); - }); - - it('should run the unmonitor command', function (done) { - pm2.monitorState('monitor', '0', done); - }); - - it('should return three processes with interactor', function (done) { - PushInteractor.preparePacket(function (err, data) { - if (err) return done(err); - - assert(data.process.length === 3); - return done(); - }); - }); -}); diff --git a/test/interface/push_interactor.mocha.js b/test/interface/push_interactor.mocha.js deleted file mode 100644 index 032b3a97..00000000 --- a/test/interface/push_interactor.mocha.js +++ /dev/null @@ -1,78 +0,0 @@ - -process.env.DEBUG='interface:push-interactor'; -process.env.NODE_ENV = 'local_test'; -process.env.PM2_PUBLIC_KEY = 'xxxx'; -process.env.PM2_SECRET_KEY = 'yyyy'; -process.env.PM2_REVERSE_INTERACT = true; -process.env.PM2_MACHINE_NAME = 'xmachine'; -process.env.KM_URL_REFRESH_RATE = 1000; - -var InterfaceD = require('../../lib/Interactor/Daemon.js'); -var Helpers = require('../helpers/apps.js'); -var axon = require('pm2-axon'); - -var pm2; - -var sock; - -function listen(cb) { - sock = axon.socket('sub'); - sock.bind(8080, cb); -} - -function listenRev(cb) { - var listener_server = require('nssocket').createServer(function(_socket) { - }); - - listener_server.listen(4322, '0.0.0.0', cb); -} - -describe('Programmatically test interactor', function() { - before(function(done) { - Helpers.forkPM2(function(err, _pm2) { - listen(function() { - listenRev(function() { - pm2 = _pm2; - done(); - }); - }); - }); - }); - - after(function(done) { - pm2.on('exit', done); - pm2.kill(); - }); - - it('should start Daemon', function(done) { - InterfaceD.start(); - setTimeout(done, 2000); - }); - - it('should receive a message', function(done) { - sock.once('message', function(data) { - data = JSON.parse(data); - done(); - }); - }); - - it('should still receive messages', function(done) { - sock.once('message', function(data) { - done(); - }); - }); - - it('should simulate server restart', function(done) { - sock.close(done); - }); - - it('should recreate connection', function(done) { - listen(done); - }); - - it('should still receive messages', function(done) { - sock.once('message', function(data) { - done(); - }); - }); -}); diff --git a/test/interface/remote.mocha.js b/test/interface/remote.mocha.js deleted file mode 100644 index d1ded5a1..00000000 --- a/test/interface/remote.mocha.js +++ /dev/null @@ -1,249 +0,0 @@ - -process.env.NODE_ENV = 'local_test'; - -var PM2 = require('../..'); -var should = require('should'); -var nssocket = require('nssocket'); -var events = require('events'); -var util = require('util'); -var Cipher = require('../../lib/Interactor/Cipher.js'); -var cst = require('../../constants.js'); - -var send_cmd = new events.EventEmitter(); -var meta_connect = { - secret_key : 'test-secret-key', - public_key : 'test-public-key', - machine_name : 'test-machine-name' -}; - -function createMockServer(cb) { - var server = nssocket.createServer(function(_socket) { - - console.log('Got new connection in Mock server'); - - send_cmd.on('cmd', function(data) { - if (process.env.DEBUG) - console.log('Sending command %j', data); - _socket.send(data._type, data); - }); - - _socket.data('*', function(data) { - this.event.forEach(function(ev) { - send_cmd.emit(ev, data); - }); - }); - - }); - - server.on('error', function(e) { - throw new Error(e); - }); - - server.on('listening', function() { - cb(null, server); - }); - - server.listen(4322, '0.0.0.0'); -} - -function startSomeApps(pm2, cb) { - pm2.start('./child.js', {instances : 4, name : 'child'}, cb); -} - -describe('REMOTE PM2 ACTIONS', function() { - var server; - var interactor; - var pm2 = new PM2.custom({ - independent : true, - cwd : __dirname + '/../fixtures', - secret_key : 'test-secret-key', - public_key : 'test-public-key', - machine_name : 'test-machine-name', - daemon_mode: true - });; - - after(function(done) { - server.close(); - pm2.destroy(done); - }); - - before(function(done) { - createMockServer(function(err, _server) { - console.log('Mock server created'); - server = _server; - pm2.connect(function(err, _pm2) { - startSomeApps(pm2, function() { - done(); - }); - }); - }); - }); - - it('should send ask, receive ask:rep and identify agent', function(done) { - send_cmd.once('ask:rep', function(pck) { - var data = Cipher.decipherMessage(pck.data, meta_connect.secret_key); - data.machine_name.should.eql(meta_connect.machine_name); - done(); - }); - - send_cmd.emit('cmd', { _type : 'ask' }); - }); - - /** - * PM2 agent is now identified - */ - it('should act on PM2', function(done) { - send_cmd.once('trigger:pm2:result', function(pck) { - if (pck.ret.data.length > 0) - done(); - else - done(new Error('wrong data rcvied')); - }); - - send_cmd.emit('cmd', { - _type : 'trigger:pm2:action', - method_name : 'restart', - parameters : {name : 'child' } - }); - }); - - it('should act on PM2 but handle failure', function(done) { - send_cmd.once('trigger:pm2:result', function(pck) { - // Error is present telling process does not exists - pck.ret.err.should.not.be.null(); - done(); - }); - - send_cmd.emit('cmd', { - _type : 'trigger:pm2:action', - method_name : 'restart', - parameters : {name : 'UNKNOWN APP' } - }); - }); - - it('should RELOAD', function(done) { - send_cmd.once('trigger:pm2:result', function(pck) { - /** - * Once remote command is finished... - */ - - should(pck.ret.err).be.null(); - - pm2.list(function(err, ret) { - ret.forEach(function(proc) { - proc.pm2_env.restart_time.should.eql(2); - }); - }); - - done(); - }); - - send_cmd.emit('cmd', { - _type : 'trigger:pm2:action', - method_name : 'reload', - parameters : {name : 'child' } - }); - }); - - it('should gracefulRELOAD', function(done) { - send_cmd.once('trigger:pm2:result', function(pck) { - /** - * Once remote command is finished... - */ - - should(pck.ret.err).be.null(); - - pm2.list(function(err, ret) { - ret.forEach(function(proc) { - proc.pm2_env.restart_time.should.eql(3); - }); - }); - - done(); - }); - - send_cmd.emit('cmd', { - _type : 'trigger:pm2:action', - method_name : 'gracefulReload', - parameters : {name : 'child' } - }); - }); - - it('should RESET metadata', function(done) { - send_cmd.once('trigger:pm2:result', function(pck) { - /** - * Once remote command is finished... - */ - should(pck.ret.err).be.null(); - - pm2.list(function(err, ret) { - ret.forEach(function(proc) { - proc.pm2_env.restart_time.should.eql(0); - }); - }); - - done(); - }); - - send_cmd.emit('cmd', { - _type : 'trigger:pm2:action', - method_name : 'reset', - parameters : {name : 'child' } - }); - }); - - it('should delete all processes', function(done) { - pm2.delete('all', {}, function() { - startSomeApps(pm2, function() { - pm2.list(function(err, ret) { - ret.forEach(function(proc) { - proc.pm2_env.restart_time.should.eql(0); - }); - done(); - }); - }); - }); - }); - - it('should test .remote', function(done) { - pm2.remote('restart', { - name : 'child' - }, function(err, procs) { - - pm2.list(function(err, ret) { - ret.forEach(function(proc) { - proc.pm2_env.restart_time.should.eql(1); - }); - done(); - }); - }); - }); - - it('should test .remote and handle failure', function(done) { - pm2.remote('restart', { - name : 'UNKNOWN_NAME' - }, function(err, procs) { - pm2.list(function(err, ret) { - ret.forEach(function(proc) { - proc.pm2_env.restart_time.should.eql(1); - }); - done(); - }); - }); - }); - - it('should test .remote #2', function(done) { - pm2.remote('reload', { - name : 'child' - }, function(err, procs) { - - pm2.list(function(err, ret) { - ret.forEach(function(proc) { - proc.pm2_env.restart_time.should.eql(2); - }); - done(); - }); - }); - }); - -}); diff --git a/test/interface/request.mocha.js b/test/interface/request.mocha.js deleted file mode 100644 index eaeb9d0e..00000000 --- a/test/interface/request.mocha.js +++ /dev/null @@ -1,91 +0,0 @@ - -process.env.DEBUG="interface:*"; - -var should = require('should'); -var assert = require('assert'); -var HttpRequest = require('../../lib/Interactor/HttpRequest.js'); - -var PORT = 8080; - -function mockIrritableServer(cb) { - var http = require('http'); - var url = require('url'); - - function handleRequest(req, res) { - var uri = url.parse(req.url).pathname; - - if (uri == '/api/node/verifyPM2') { - // res.writeHead(505, {"Content-Type": "text/json"}); - // return res.end(new Buffer(50).fill('h')); - // } - // console.log(uri); - return false; - } - if (uri == '/api/misc/pm2_version') { - res.writeHead(505); - return res.end(); - } - } - - //Create a server - var server = http.createServer(handleRequest); - - //Lets start our server - server.listen(PORT, function(err){ - if (err) console.error(err); - cb(null, server); - }); -} - -describe('Http requests', function() { - var _server = null; - - before(function(done) { - mockIrritableServer(function(err, server) { - _server = server; - done(); - }); - }); - - after(function(done) { - _server.close(done); - }); - - describe('POST', function() { - it('should post to 404 URL', function(done) { - HttpRequest.post({ - port : 9999, - url : 'http://keymetrics.io/NOTHING', - data : { no : 'thing' } - }, function(err, data) { - assert(err); - assert(err.code == 'ENOTFOUND'); - assert(data == null); - done(); - }) - }); - - it('should timeout after 7secs', function(done) { - HttpRequest.post({ - port : PORT, - url : '127.0.0.1', - data : { no : 'thing' } - }, function(err, data) { - assert(err); - assert(err.code == 'ECONNRESET'); - assert(data == null); - done(); - }); - }); - - }); - - // @todo: more behavioral tests (reverse interactor failcheck) - - // @todo: do more tests when doing changeUrls - it.skip('should change urls (forcing reconnection)', function(done) { - InterfaceD.changeUrls('app.km.io', 'app.km.io:4322'); - setTimeout(done, 2000); - }); - -}); diff --git a/test/interface/scoped_pm2_actions.mocha.js b/test/interface/scoped_pm2_actions.mocha.js deleted file mode 100644 index ecf837cc..00000000 --- a/test/interface/scoped_pm2_actions.mocha.js +++ /dev/null @@ -1,258 +0,0 @@ - -var PM2 = require('../..'); -var should = require('should'); -var nssocket = require('nssocket'); -var events = require('events'); -var util = require('util'); -var Cipher = require('../../lib/Interactor/Cipher.js'); -var cst = require('../../constants.js'); -var Plan = require('../helpers/plan.js'); -var Configuration = require('../../lib/Configuration.js'); -var Helpers = require('../helpers/apps.js'); -var Interactor = require('../../lib/Interactor/InteractorDaemonizer.js'); -var gl_interactor_process; - -var send_cmd = new events.EventEmitter(); - -process.env.NODE_ENV = 'local_test'; - -var meta_connect = { - secret_key : 'test-secret-key', - public_key : 'test-public-key', - machine_name : 'test-machine-name' -}; - -/** - * Description - * @method forkInteractor - * @return CallExpression - */ -function forkInteractor(cb) { - Interactor.launchAndInteract(meta_connect, function(err, data, interactor_process) { - gl_interactor_process = interactor_process; - cb(); - }); -} - -/** - * Mock server receiving data - * @method forkInteractor - * @return CallExpression - */ -function createMockServer(cb) { - var server = nssocket.createServer(function(_socket) { - - send_cmd.on('cmd', function(data) { - if (process.env.DEBUG) - console.log('Sending command %j', data); - _socket.send(data._type, data); - }); - - _socket.data('*', function(data) { - this.event.forEach(function(ev) { - send_cmd.emit(ev, data); - }); - }); - - }); - - server.on('error', function(e) { - throw new Error(e); - }); - - server.on('listening', function() { - cb(null, server); - }); - - server.listen(4322, '0.0.0.0'); -} - -function startSomeApps(cb) { - pm2.start('./child.js', {instances : 1, name : 'child'}, cb); -} - -var pm2 = new PM2.custom({ - independent : true, - cwd : __dirname + '/../fixtures', - secret_key : 'test-secret-key', - public_key : 'test-public-key', - machine_name : 'test-machine-name', - daemon_mode: true -}); - -describe('SCOPED PM2 ACTIONS', function() { - var server; - var interactor; - - after(function(done) { - server.close(); - pm2.destroy(done); - }); - - before(function(done) { - createMockServer(function(err, _server) { - server = _server; - pm2.connect(function() { - startSomeApps(function(err) { - gl_interactor_process = pm2.Client.interactor_process; - // @todo: would be nice to know when an app is ready - // @priotity: minor - setTimeout(done, 1500); - }); - }); - }); - }); - - it('should send ask, receive ask:rep and identify agent', function(done) { - send_cmd.once('ask:rep', function(pck) { - var data = Cipher.decipherMessage(pck.data, meta_connect.secret_key); - data.machine_name.should.eql(meta_connect.machine_name); - done(); - }); - - send_cmd.emit('cmd', { _type : 'ask' }); - }); - - /** - * PM2 agent is now identified - */ - describe('Test non auth remote commands', function() { - before(function(done) { - Configuration.unset('pm2:passwd', function(err, data) { - should.not.exists(err); - done(); - }); - }); - - it('should restart command via scoped pm2 action (no pass needed)', function(done) { - var good = false; - var plan = new Plan(2, function() { - gl_interactor_process.removeListener('message', actionCheck); - good = true; - done(); - }); - - function actionCheck(pck) { - if (good) return false; - if (pck.event == 'pm2:scoped:stream' && pck.data.out === 'Action restart received') - return plan.ok(true); - if (pck.event == 'pm2:scoped:end') - return plan.ok(true); - if (pck.event == 'pm2:scoped:error') - return plan.ok(false, pck); - return false; - } - - gl_interactor_process.on('message', actionCheck); - - send_cmd.emit('cmd', { - _type : 'trigger:pm2:scoped:action', - action_name : 'restart', - uuid : '1234', - options : { args : ['child'] } - }); - - }); - - }); - - describe('Password verification', function() { - - before(function(done) { - Configuration.unset('pm2:passwd', function(err, data) { - should.not.exists(err); - done(); - }); - }); - - it('should error when call an action that is password protected', function(done) { - function actionCheck(pck) { - if (pck.event == 'pm2:scoped:error' && pck.data.out.indexOf('Missing password') > -1) { - gl_interactor_process.removeListener('message', actionCheck); - done(); - } - }; - - gl_interactor_process.on('message', actionCheck); - - send_cmd.emit('cmd', { - _type : 'trigger:pm2:scoped:action', - action_name : 'install', - uuid : '5678', - options : { args : ['child'] } - }); - }); - - it('should fail when password passed but no pm2 password configured', function(done) { - function actionCheck(pck) { - if (pck.event == 'pm2:scoped:error' && pck.data.out.indexOf('Password at PM2') > -1) { - gl_interactor_process.removeListener('message', actionCheck); - done(); - } - }; - - gl_interactor_process.on('message', actionCheck); - - send_cmd.emit('cmd', { - _type : 'trigger:pm2:scoped:action', - action_name : 'install', - uuid : '5678', - password : 'random-pass', - options : { args : ['pm2-module'] } - }); - }); - - it('should set a password', function(done) { - pm2.set('pm2:passwd', 'testpass', function(err, data) { - should.not.exists(err); - done(); - }); - }); - - it('should fail when wrong password', function(done) { - function actionCheck(pck) { - if (pck.event == 'pm2:scoped:error' && pck.data.out.indexOf('Password does not match') > -1) { - gl_interactor_process.removeListener('message', actionCheck); - setTimeout(done, 100); - } - }; - - gl_interactor_process.on('message', actionCheck); - - send_cmd.emit('cmd', { - _type : 'trigger:pm2:scoped:action', - action_name : 'install', - uuid : '5678', - password : 'random-pass', - options : { args : ['pm2-module'] } - }); - }); - - it('should work when good password passed', function(done) { - function actionCheck(pck) { - if (pck.event === 'pm2:scoped:end') { - gl_interactor_process.removeListener('message', actionCheck); - done(); - } - if (pck.event === 'pm2:scoped:error') { - gl_interactor_process.removeListener('message', actionCheck); - done('{ERROR} Wrong password!' + JSON.stringify(pck)); - } - }; - - gl_interactor_process.on('message', actionCheck); - - send_cmd.emit('cmd', { - _type : 'trigger:pm2:scoped:action', - action_name : 'ping', - uuid : '5678', - password : 'testpass', - options : {} - }); - }); - - - }); - - -}); diff --git a/test/interface/stacktrace.mocha.js b/test/interface/stacktrace.mocha.js deleted file mode 100644 index 630f844b..00000000 --- a/test/interface/stacktrace.mocha.js +++ /dev/null @@ -1,157 +0,0 @@ - -var should = require('should'); -var Aggregator = require('../../lib/Interactor/TransactionAggregator.js'); -var Utility = require('../../lib/Interactor/Utility.js'); -var TraceFactory = require('./misc/trace_factory.js'); -var path = require('path'); -var fs = require('fs'); -var assert = require('assert'); - -describe('StackTrace Utility', function() { - var aggregator; - var stackParser; - - it('should instanciate context cache', function() { - var cache = new Utility.Cache({ - miss: function (key) { - try { - var content = fs.readFileSync(path.resolve(key)); - return content.toString().split(/\r?\n/); - } catch (err) { - return undefined; - } - } - }) - - stackParser = new Utility.StackTraceParser({ cache: cache, context: 2}); - }); - - it('should instanciate aggregator', function() { - aggregator = new Aggregator({ stackParser: stackParser}); - }); - - describe('.parse', function() { - it('should parse stacktrace and get context', function(done) { - var obj = [{ - labels: { - stacktrace: JSON.stringify(TraceFactory.stacktrace) - } - }]; - - aggregator.parseStacktrace(obj); - obj[0].labels['source/file'].indexOf('test/interface/misc/trace_factory.js:10').should.be.above(0); - should(obj[0].labels['source/context']).eql("var random_routes = [\n '/api/bucket',\n>>'/api/bucket/users',\n '/api/bucket/chameau',\n '/backo/testo'"); - done(); - }); - - it('should handle malformated stacktraces', function() { - aggregator.parseStacktrace([{ - labels: { - stacktrace: JSON.stringify({ - stack_frame: [{ - line_number: 10, - column_number: 10, - method_name: '' - }, { - file_name: 'node_modules/express.js', - column_number: 10, - method_name: '' - }, { - file_name: path.resolve(__dirname, 'trace_factory.js'), - line_number: 10, - column_number: 10, - method_name: '' - }] - }) - } - }]); - }); - - it('should handle malformated stacktrace v1', function() { - aggregator.parseStacktrace([{ - labels: { - stacktrace: JSON.stringify({ - stack_frame: [{ - file_name: 'events.js' - },{ - file_name: 'node_modules/express.js' - },{ - file_name: path.resolve(__dirname, 'trace_factory.js') - }] - }) - } - }]); - }); - - it('should handle malformated stacktrace v2', function() { - aggregator.parseStacktrace([{ - labels: { - stacktrace: JSON.stringify({ - stack_frame: [{ - file_name: 'events.js', - column_number: 10, - method_name: '' - },{ - file_name: 'node_modules/express.js', - column_number: 10, - method_name: '' - },{ - file_name: path.resolve(__dirname, 'trace_factory.js'), - line_number: 10, - column_number: 10, - method_name: '' - }] - }) - } - }]); - }); - - it('should handle malformated stacktrace v3', function() { - aggregator.parseStacktrace([{ - labels: {} - }]); - }); - - it('should handle malformated stacktrace v4', function() { - aggregator.parseStacktrace([{ - }]); - }); - - it('should handle malformated stacktrace v5', function() { - aggregator.parseStacktrace([]); - }); - - it('should handle malformated stacktrace v5', function() { - aggregator.parseStacktrace(); - }); - - }); - - describe('.attachContext', function () { - it('should extract context from stackframes', function () { - var error = stackParser.attachContext({ - stackframes: [ - { - file_name: '/toto/tmp/lol', - line_number: 10 - } - ] - }); - assert(error !== undefined); - assert(error.stackframes === undefined); - assert(error.callsite !== undefined); - assert(error.callsite.indexOf('/toto/tmp/lol') >= 0); - }); - - it('should extract context from the stack string', function () { - var error = new Error(); - // stack is lazy so we need to load it - error.stack = error.stack; - error = stackParser.attachContext(error); - assert(error !== undefined); - assert(error.stackframes === undefined); - assert(error.callsite.indexOf(__filename) >= 0); - assert(error.context.indexOf('var error = new Error()') >= 0); - }); - }); -}); From d9df60eb97ab4afbf9f4e35d3ea64d6364615a6b Mon Sep 17 00:00:00 2001 From: Robin Monnier Date: Fri, 16 Mar 2018 18:44:00 +0100 Subject: [PATCH 051/140] change all ecosystem.json to ecosystem.config.js --- ADVANCED_README.md | 2 +- constants.js | 2 +- lib/API/Modules/Modularizer.js | 2 +- lib/Common.js | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/ADVANCED_README.md b/ADVANCED_README.md index 8c6931d9..1de13ee0 100644 --- a/ADVANCED_README.md +++ b/ADVANCED_README.md @@ -32,7 +32,7 @@ - [Without Keymetrics](#without-keymetrics) - [With Keymetrics](#with-keymetrics) -### Deployment - ecosystem.json +### Deployment - ecosystem.config.js - [Getting started with deployment](#deployment) - [Deployment options](#deployment-help) diff --git a/constants.js b/constants.js index c86f8772..3c21e4c0 100644 --- a/constants.js +++ b/constants.js @@ -28,7 +28,7 @@ var csts = { TEMPLATE_FOLDER : p.join(__dirname, 'lib/templates'), - APP_CONF_DEFAULT_FILE : 'ecosystem.json', + APP_CONF_DEFAULT_FILE : 'ecosystem.config.js', APP_CONF_TPL : 'ecosystem.tpl', APP_CONF_TPL_SIMPLE : 'ecosystem-simple.tpl', SAMPLE_CONF_FILE : 'sample-conf.js', diff --git a/lib/API/Modules/Modularizer.js b/lib/API/Modules/Modularizer.js index 7093324b..f2189fba 100644 --- a/lib/API/Modules/Modularizer.js +++ b/lib/API/Modules/Modularizer.js @@ -47,7 +47,7 @@ var KNOWN_MODULES = { * - Generate sample module via pm2 module:generate */ Modularizer.install = function (CLI, moduleName, opts, cb) { - // if user want to install module from ecosystem.json file + // if user want to install module from ecosystem.config.js file // it can also be a custom json file's name if (!moduleName || moduleName.length === 0 || moduleName.indexOf('.json') > 0) { var file = moduleName || cst.APP_CONF_DEFAULT_FILE; diff --git a/lib/Common.js b/lib/Common.js index 2dd053aa..c4226f3e 100644 --- a/lib/Common.js +++ b/lib/Common.js @@ -260,7 +260,7 @@ Common.isConfigFile = function(filename) { }; /** - * Parses a config file like ecosystem.json. Supported formats: JS, JSON, JSON5, YAML. + * Parses a config file like ecosystem.config.js. Supported formats: JS, JSON, JSON5, YAML. * @param {string} confString contents of the config file * @param {string} filename path to the config file * @return {Object} config object From c424cc497f714458b9e49e85ec9e2d0a4bb0c50a Mon Sep 17 00:00:00 2001 From: Robin Monnier Date: Mon, 19 Mar 2018 13:34:02 +0100 Subject: [PATCH 052/140] set first argument of pm2 start an option rather than a required argument --- bin/pm2 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/pm2 b/bin/pm2 index 011265fc..19dbbcaf 100755 --- a/bin/pm2 +++ b/bin/pm2 @@ -265,7 +265,7 @@ function patchCommanderArg(cmd) { // // Start command // -commander.command('start ') +commander.command('start [name|file|ecosystem|id...]') .option('--watch', 'Watch folder for changes') .option('--fresh', 'Rebuild Dockerfile') .option('--daemon', 'Run container in Daemon mode (debug purposes)') From 8e96ab360e04e056a0f75844d4c4d44ebf1261fb Mon Sep 17 00:00:00 2001 From: abluchet Date: Mon, 19 Mar 2018 14:01:20 +0100 Subject: [PATCH 053/140] Improve monitoring performances --- lib/God.js | 3 - lib/God/ActionMethods.js | 119 +++++++++++++++++++++------------ package.json | 2 +- test/programmatic/god.mocha.js | 48 +++++++++++++ 4 files changed, 124 insertions(+), 48 deletions(-) diff --git a/lib/God.js b/lib/God.js index dc001997..3e4c1d54 100644 --- a/lib/God.js +++ b/lib/God.js @@ -291,9 +291,6 @@ God.handleExit = function handleExit(clu, exit_code, kill_signal) { return false; } - if (proc.process.pid) - pidusage.unmonitor(proc.process.pid); - var stopping = (proc.pm2_env.status == cst.STOPPING_STATUS || proc.pm2_env.status == cst.STOPPED_STATUS || proc.pm2_env.status == cst.ERRORED_STATUS) || (proc.pm2_env.autorestart === false || diff --git a/lib/God/ActionMethods.js b/lib/God/ActionMethods.js index 1556a165..092b7df3 100644 --- a/lib/God/ActionMethods.js +++ b/lib/God/ActionMethods.js @@ -41,55 +41,63 @@ module.exports = function(God) { */ God.getMonitorData = function getMonitorData(env, cb) { var processes = God.getFormatedProcesses(); + var pids = processes.filter(filterBadProcess) + .map(function(pro, i) { + var pid = getProcessId(pro) + return pid; + }) - async.eachSeries(processes, function computeMonitor(pro, next) { - if (pro.pm2_env.status == cst.ONLINE_STATUS) { - var pid = pro.pid; - - if (pro.pm2_env.axm_options && pro.pm2_env.axm_options.pid) { - if (isNaN(pro.pm2_env.axm_options.pid)) { - pro['monit'] = { - memory : 0, - cpu : 0 - }; - return process.nextTick(next); - } - pid = pro.pm2_env.axm_options.pid; - } - - pidusage.stat(pid, function retPidUsage(err, res) { - if (err) { - // Do not log, some time modules does not retrieve PID - // console.error('Error caught while calling pidusage'); - // console.error(err); - pro['monit'] = { - memory : 0, - cpu : 0 - }; - return next(); - } - - pro['monit'] = { - memory : Math.floor(res.memory), - cpu : Math.floor(res.cpu) - }; - res = null; - pid = null; - return next(); - }); - } - else { + // No pids, return empty statistics + if (pids.length === 0) { + return cb(null, processes.map(function(pro) { pro['monit'] = { memory : 0, cpu : 0 }; - return next(); - } - }, function retMonitor(err, res) { - if (err) return cb(God.logAndGenerateError(err), null); - return cb(null, processes); - }); + return pro + })) + } + + pidusage(pids, function retPidUsage(err, statistics) { + // Just log, we'll set empty statistics + if (err) { + console.error('Error caught while calling pidusage'); + console.error(err); + } + + processes = processes.map(function(pro) { + if (filterBadProcess(pro) === false) { + pro['monit'] = { + memory : 0, + cpu : 0 + }; + + return pro; + } + + var pid = getProcessId(pro); + var stat = statistics[pid]; + + if (!stat) { + pro['monit'] = { + memory : 0, + cpu : 0 + }; + + return pro; + } + + pro['monit'] = { + memory: stat.memory, + cpu: stat.cpu + }; + + return pro; + }); + + cb(null, processes); + }); }; /** @@ -304,7 +312,6 @@ module.exports = function(God) { God.killProcess(proc.process.pid, proc.pm2_env, function(err) { proc.pm2_env.status = cst.STOPPED_STATUS; - pidusage.unmonitor(proc.process.pid); God.notify('exit', proc); @@ -841,3 +848,27 @@ module.exports = function(God) { }); }; }; + +function filterBadProcess(pro) { + if (pro.pm2_env.status !== cst.ONLINE_STATUS) { + return false; + } + + if (pro.pm2_env.axm_options && pro.pm2_env.axm_options.pid) { + if (isNaN(pro.pm2_env.axm_options.pid)) { + return false; + } + } + + return true; +} + +function getProcessId(pro) { + var pid = pro.pid + + if (pro.pm2_env.axm_options && pro.pm2_env.axm_options.pid) { + pid = pro.pm2_env.axm_options.pid; + } + + return pid +} diff --git a/package.json b/package.json index 3702dbae..8e9a9608 100644 --- a/package.json +++ b/package.json @@ -174,7 +174,7 @@ "moment": "^2.19", "needle": "^2.2.0", "nssocket": "0.6.0", - "pidusage": "^2.0.0", + "pidusage": "^2.0.5", "pm2-axon": "3.1.0", "pm2-axon-rpc": "0.5.0", "pm2-deploy": "^0.3.9", diff --git a/test/programmatic/god.mocha.js b/test/programmatic/god.mocha.js index 887a15f3..5c22cd53 100644 --- a/test/programmatic/god.mocha.js +++ b/test/programmatic/god.mocha.js @@ -256,4 +256,52 @@ describe('God', function() { }); }); + it('should get monitor data', function(done) { + var f = require('child_process').fork('../fixtures/echo.js') + + var processes = [ + // stopped status + { + pm2_env: {status: cst.STOPPED_STATUS} + }, + // axm pid + { + pm2_env: { + status: cst.ONLINE_STATUS, axm_options: {pid: process.pid} + } + }, + // axm pid is NaN + { + pm2_env: { + status: cst.ONLINE_STATUS, axm_options: {pid: 'notanumber'} + } + }, + { + pm2_env: { + status: cst.ONLINE_STATUS + }, + pid: f.pid + } + ] + + // mock + var g = { + getFormatedProcesses: function() { + return processes + } + } + + require('../../lib/God/ActionMethods.js')(g) + + g.getMonitorData({}, function(err, procs) { + should(err).be.null(); + procs.length.should.be.equal(processes.length); + procs[0].monit.should.be.deepEqual({memory: 0, cpu: 0}); + procs[1].monit.memory.should.be.greaterThan(0); + procs[2].monit.should.be.deepEqual({memory: 0, cpu: 0}); + procs[3].monit.memory.should.be.greaterThan(0); + f.kill() + done() + }) + }); }); From e0be81c86c7defb5e7a271edd5cc37f960c6aa69 Mon Sep 17 00:00:00 2001 From: Eywek Date: Mon, 19 Mar 2018 14:09:48 +0100 Subject: [PATCH 054/140] fix: remove useless tests from .sh --- test/pm2_programmatic_tests.sh | 26 -------------------------- 1 file changed, 26 deletions(-) diff --git a/test/pm2_programmatic_tests.sh b/test/pm2_programmatic_tests.sh index 695c622f..97f203f3 100644 --- a/test/pm2_programmatic_tests.sh +++ b/test/pm2_programmatic_tests.sh @@ -95,37 +95,11 @@ cd ../interface echo $PM2_HOME -mocha --opts ./mocha.opts ./exception.e2e.mocha.js -spec "E2E exception system checking" -mocha --opts ./mocha.opts ./interactor.connect.mocha.js -spec "Interactor test #1 with password setting" -mocha --opts ./mocha.opts ./interactor.daemonizer.mocha.js -spec "Remote interactor keys save verification" -mocha --opts ./mocha.opts ./scoped_pm2_actions.mocha.js -spec "Scoped PM2 Remote interactions test" -mocha --opts ./mocha.opts ./remote.mocha.js -spec "Remote interactions test" -mocha --opts ./mocha.opts ./password.mocha.js -spec "Password library checking" -mocha --opts ./mocha.opts ./custom-actions.mocha.js -spec "Custom actions test" mocha --opts ./mocha.opts ./bus.spec.mocha.js spec "Protocol communication test" mocha --opts ./mocha.opts ./bus.fork.spec.mocha.js spec "Protocol communication test" -mocha --opts ./mocha.opts ./request.mocha.js -spec "Protocol communication test" -mocha --opts ./mocha.opts ./aggregator.mocha.js -spec "Transaction trace aggregator test" -mocha --opts ./mocha.opts ./stacktrace.mocha.js -spec "Stacktrace Utility" -mocha --opts ./mocha.opts ./cache.mocha.js -spec "Cache Utility" -mocha --opts ./mocha.opts ./filter.mocha.js -spec "Filter Utility" mocha --opts ./mocha.opts ./utility.mocha.js spec "PM2 Utility" mocha --opts ./mocha.opts ./pm2.link.check.mocha.js spec "Transaction option enablement" -mocha --opts ./mocha.opts ./monitor.mocha.js -spec "Monitor / Unmonitor commands" From fc5adf36d5a77ac6cb1a8b84719afb1336563f83 Mon Sep 17 00:00:00 2001 From: Eywek Date: Mon, 19 Mar 2018 15:54:13 +0100 Subject: [PATCH 055/140] remove useless test --- test/interface/pm2.link.check.mocha.js | 86 -------------------------- test/pm2_programmatic_tests.sh | 2 - 2 files changed, 88 deletions(-) delete mode 100644 test/interface/pm2.link.check.mocha.js diff --git a/test/interface/pm2.link.check.mocha.js b/test/interface/pm2.link.check.mocha.js deleted file mode 100644 index 6bc24e6b..00000000 --- a/test/interface/pm2.link.check.mocha.js +++ /dev/null @@ -1,86 +0,0 @@ -process.env.NODE_ENV = 'local_test'; -process.env.TRAVIS = true; - -var PM2 = require('../..'); -var should = require('should'); - -describe('PM2 link variable checks', function() { - var server; - this.timeout(5000); - - describe('km_link false', function() { - var pm2 = new PM2.custom({ - cwd : __dirname + '/../fixtures' - }); - - before(function(done) { - pm2.connect(function(err, data) { - done(); - }); - }); - - after(function(done) { - pm2.kill(done); - }); - - it('should start an app and app km_link to false', function(done) { - pm2.start({ - trace : true, - script : 'http.js' - }, function(err) { - done(); - }) - }); - - it('should have km_link to false', function(done) { - // Wait for process initialization - setTimeout(function() { - pm2.list(function(err, dt) { - dt[0].pm2_env.km_link.should.be.false(); - dt[0].pm2_env.axm_options.transactions.should.be.false(); - done(); - }); - }, 500); - }); - }); - - describe('km_link true', function() { - var pm2; - - before(function(done) { - pm2 = new PM2.custom({ - cwd : __dirname + '/../fixtures', - secret_key : 'osef', - public_key : 'osef', - machine_name : 'osef', - daemon_mode: true - }); - - pm2.connect(done); - }); - - after(function(done) { - pm2.kill(done); - }); - - it('should start an app and app km_link to false', function(done) { - pm2.start({ - script : 'http.js', - trace : true - }, done) - }); - - it('should have km_link to false', function(done) { - // Wait for process initialization - setTimeout(function() { - pm2.list(function(err, dt) { - dt[0].pm2_env.km_link.should.be.true(); - //dt[0].pm2_env.axm_options.transactions.should.be.true(); - dt[0].pm2_env.axm_options.tracing_enabled.should.be.true(); - done(); - }); - }, 1000); - }); - }); - -}); diff --git a/test/pm2_programmatic_tests.sh b/test/pm2_programmatic_tests.sh index 97f203f3..c99dac23 100644 --- a/test/pm2_programmatic_tests.sh +++ b/test/pm2_programmatic_tests.sh @@ -101,5 +101,3 @@ mocha --opts ./mocha.opts ./bus.fork.spec.mocha.js spec "Protocol communication test" mocha --opts ./mocha.opts ./utility.mocha.js spec "PM2 Utility" -mocha --opts ./mocha.opts ./pm2.link.check.mocha.js -spec "Transaction option enablement" From 3aeeba02f628bf4f19e8d5b93657fd94a6ef0ec7 Mon Sep 17 00:00:00 2001 From: vince Date: Mon, 19 Mar 2018 15:55:57 +0100 Subject: [PATCH 056/140] fix: remove unused variable when trying to use tracing --- lib/ProcessUtils.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/lib/ProcessUtils.js b/lib/ProcessUtils.js index 3e90117e..4162fe3f 100644 --- a/lib/ProcessUtils.js +++ b/lib/ProcessUtils.js @@ -1,9 +1,12 @@ module.exports = { injectModules: function() { + console.log(process.env.pmx) if (process.env.pmx !== 'false') { const pmx = require('pmx'); + console.log('-------------------------------------------------') + console.log(process.env.km_link,process.env.trace, process.env.deep_monitoring) pmx.init({ - transactions: (process.env.km_link === 'true' && (process.env.trace === 'true' || process.env.deep_monitoring === 'true')) || false, + transactions: (process.env.trace === 'true' || process.env.deep_monitoring === 'true') || false, http: process.env.km_link === 'true' || false, v8: process.env.v8 === 'true' || process.env.deep_monitoring === 'true' || false, event_loop_dump: process.env.event_loop_inspector === 'true' || process.env.deep_monitoring === 'true' || false, From 33db5084814ae7940c90b7f933f9514d28008b78 Mon Sep 17 00:00:00 2001 From: vince Date: Mon, 19 Mar 2018 16:24:48 +0100 Subject: [PATCH 057/140] chore: remove unused console.log --- lib/ProcessUtils.js | 3 --- test/interface/bus.fork.spec.mocha.js | 1 - 2 files changed, 4 deletions(-) diff --git a/lib/ProcessUtils.js b/lib/ProcessUtils.js index 4162fe3f..5d32750b 100644 --- a/lib/ProcessUtils.js +++ b/lib/ProcessUtils.js @@ -1,10 +1,7 @@ module.exports = { injectModules: function() { - console.log(process.env.pmx) if (process.env.pmx !== 'false') { const pmx = require('pmx'); - console.log('-------------------------------------------------') - console.log(process.env.km_link,process.env.trace, process.env.deep_monitoring) pmx.init({ transactions: (process.env.trace === 'true' || process.env.deep_monitoring === 'true') || false, http: process.env.km_link === 'true' || false, diff --git a/test/interface/bus.fork.spec.mocha.js b/test/interface/bus.fork.spec.mocha.js index 3ed46921..31e98f7a 100644 --- a/test/interface/bus.fork.spec.mocha.js +++ b/test/interface/bus.fork.spec.mocha.js @@ -89,7 +89,6 @@ describe('PM2 BUS / RPC', function() { var plan = new Plan(2, done); pm2_bus.on('*', function(event, data) { - console.log(event); if (event == 'process:event') { event.should.eql('process:event'); data.should.have.properties(PROCESS_EVENT); From 23fd8ecfea9b2bf61359f62a8e6e1a582c3b0d6e Mon Sep 17 00:00:00 2001 From: vince Date: Mon, 19 Mar 2018 16:40:16 +0100 Subject: [PATCH 058/140] test: fix test with km_link --- test/interface/pm2.link.check.mocha.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/interface/pm2.link.check.mocha.js b/test/interface/pm2.link.check.mocha.js index 6bc24e6b..8bec6029 100644 --- a/test/interface/pm2.link.check.mocha.js +++ b/test/interface/pm2.link.check.mocha.js @@ -37,7 +37,7 @@ describe('PM2 link variable checks', function() { setTimeout(function() { pm2.list(function(err, dt) { dt[0].pm2_env.km_link.should.be.false(); - dt[0].pm2_env.axm_options.transactions.should.be.false(); + dt[0].pm2_env.axm_options.transactions.should.be.true(); done(); }); }, 500); From 2b9ffd4eb493f1ff32c979e3811f4f1fedfae97d Mon Sep 17 00:00:00 2001 From: Unitech Date: Tue, 20 Mar 2018 10:54:11 +0100 Subject: [PATCH 059/140] refactor: e2e test rewrite --- .gitignore | 1 + package.json | 3 +- test/docker_parallel_test.sh | 2 +- test/e2e.sh | 22 +++++++------- test/e2e/cli/interpreter.sh | 6 +--- test/e2e/cli/reload.sh | 29 ++++++++++--------- test/e2e/misc/cron-system.sh | 2 +- test/e2e/misc/inside-pm2.sh | 2 +- test/e2e/misc/instance-number.sh | 4 +-- test/e2e/misc/misc.sh | 2 +- test/e2e/misc/pull.sh | 2 +- test/e2e/misc/startup.sh | 2 +- test/e2e/misc/versioning-cmd.sh | 2 +- test/e2e/misc/vizion.sh | 2 +- .../app-config-update.sh | 0 15 files changed, 39 insertions(+), 42 deletions(-) rename test/e2e/{cli => process-file}/app-config-update.sh (100%) diff --git a/.gitignore b/.gitignore index 786a0100..e6576745 100644 --- a/.gitignore +++ b/.gitignore @@ -16,3 +16,4 @@ package-lock.json *.swo currentTagChangelog.md joblog-X +test/fixtures/path-check*.txt diff --git a/package.json b/package.json index b117d85e..9593d4b2 100644 --- a/package.json +++ b/package.json @@ -91,8 +91,7 @@ "main": "index.js", "types": "types/index.d.ts", "scripts": { - "test": "bash test/docker_parallel_test.sh", - "bench-pmx": "pm2 delete all; pm2 install pm2-probe; node examples/pmx/app.js; pm2 ls" + "test": "bash test/e2e.sh; bash test/unit.sh" }, "keywords": [ "cli", diff --git a/test/docker_parallel_test.sh b/test/docker_parallel_test.sh index e4cceb53..b46304bc 100644 --- a/test/docker_parallel_test.sh +++ b/test/docker_parallel_test.sh @@ -2,7 +2,7 @@ set -e docker build -t pm2-test -f test/Dockerfile . -JOBS=20 +JOBS=2 OPTS="--jobs $JOBS --joblog joblog-X docker run -v `pwd`:/var/pm2 pm2-test" ls test/e2e/cli/* | parallel $OPTS bash diff --git a/test/e2e.sh b/test/e2e.sh index 07cfe4ac..52817fa8 100644 --- a/test/e2e.sh +++ b/test/e2e.sh @@ -70,14 +70,14 @@ bash ./test/e2e/cli/harmony.sh spec "Harmony test" bash ./test/e2e/cli/fork.sh spec "Fork system working" +bash ./test/e2e/cli/piped-config.sh +spec "Piped JSON file test" # PROCESS FILES bash ./test/e2e/process-file/json-file.sh spec "JSON file test" bash ./test/e2e/process-file/yaml-configuration.sh spec "YAML configuration support" -bash ./test/e2e/process-file/piped-config.sh -spec "Piped JSON file test" bash ./test/e2e/process-file/json-reload.sh spec "JSON reload test" bash ./test/e2e/process-file/homogen-json-action.sh @@ -104,7 +104,7 @@ bash ./test/e2e/internals/wrapped-fork.sh spec "wrapped fork" bash ./test/e2e/internals/infinite-loop.sh spec "Infinite loop stop" -bash ./test/e2e/internals/internals/options-via-env.sh +bash ./test/e2e/internals/options-via-env.sh spec "set option via environment" bash ./test/e2e/internals/promise.sh spec "Promise warning message tests" @@ -114,21 +114,21 @@ bash ./test/e2e/internals/start-consistency.sh spec "Consistency between a JSON an CLI start" # MISC -bash ./test/misc/inside-pm2.sh +bash ./test/e2e/misc/inside-pm2.sh spec "Starting a process inside a PM2 process" -bash ./test/misc/vizion.sh +bash ./test/e2e/misc/vizion.sh spec "vizion features (versioning control)" -bash ./test/misc/misc.sh +bash ./test/e2e/misc/misc.sh spec "MISC features" -bash ./test/misc/versioning-cmd.sh +bash ./test/e2e/misc/versioning-cmd.sh spec "versioning system tests" -bash ./test/misc/instance-number.sh +bash ./test/e2e/misc/instance-number.sh spec "Negative instance number spawn one worker" -bash ./test/misc/startup.sh +bash ./test/e2e/misc/startup.sh spec "upstart startup test" -bash ./test/misc/nvm-node-version.sh +bash ./test/e2e/misc/nvm-node-version.sh spec "NVM node version setting" -bash ./test/misc/cron-system.sh +bash ./test/e2e/misc/cron-system.sh spec "Cron system tests" # LOGS diff --git a/test/e2e/cli/interpreter.sh b/test/e2e/cli/interpreter.sh index ebd2aec3..7962a580 100644 --- a/test/e2e/cli/interpreter.sh +++ b/test/e2e/cli/interpreter.sh @@ -7,6 +7,7 @@ cd $file_path/interpreter rm -rf ../../../node_modules/coffee-script/ rm -rf ../../../node_modules/livescript/ +rm -rf ../../../node_modules/ts-node/ ########### coffee @@ -74,11 +75,6 @@ should 'process should be online' "status: 'online'" 1 ########### TYPESCRIPT -$pm2 delete all -$pm2 start echo.ts -sleep 1 -should 'process should be errored without typescript installed' "status: 'errored'" 1 - ########### Install $pm2 install typescript diff --git a/test/e2e/cli/reload.sh b/test/e2e/cli/reload.sh index 3653c522..a7248427 100644 --- a/test/e2e/cli/reload.sh +++ b/test/e2e/cli/reload.sh @@ -39,22 +39,23 @@ sleep 3 should 'should restart processes' 'restart_time: 1' 1 $pm2 kill -$pm2 start delayed_exit.js -i 2 -should 'should start processes' 'online' 2 -$pm2 stop delayed_exit.js -sleep 3 -should 'should stop processes' 'stopped' 2 -$pm2 restart delayed_exit.js -should 'should restart processes' 'restart_time: 0' 2 -$pm2 restart delayed_exit.js -should 'should restart processes' 'restart_time: 1' 2 -$pm2 reload delayed_exit.js -should 'should restart processes' 'restart_time: 2' 2 -$pm2 gracefulReload delayed_exit.js -should 'should restart processes' 'restart_time: 3' 2 -$pm2 kill +# $pm2 start delayed_exit.js -i 2 +# should 'should start processes' 'online' 2 +# $pm2 stop delayed_exit.js +# sleep 3 +# should 'should stop processes' 'stopped' 2 +# $pm2 restart delayed_exit.js +# should 'should restart processes' 'restart_time: 0' 2 +# $pm2 restart delayed_exit.js +# should 'should restart processes' 'restart_time: 1' 2 +# $pm2 reload delayed_exit.js +# should 'should restart processes' 'restart_time: 2' 2 +# $pm2 gracefulReload delayed_exit.js +# should 'should restart processes' 'restart_time: 3' 2 +# $pm2 kill $pm2 start child.js -i 4 +sleep 0.5 should 'should start processes' 'online' 4 $pm2 restart all should 'should restarted be one for all' 'restart_time' 4 diff --git a/test/e2e/misc/cron-system.sh b/test/e2e/misc/cron-system.sh index 96b05b89..f97376c1 100644 --- a/test/e2e/misc/cron-system.sh +++ b/test/e2e/misc/cron-system.sh @@ -1,7 +1,7 @@ #!/usr/bin/env bash SRC=$(cd $(dirname "$0"); pwd) -source "${SRC}/include.sh" +source "${SRC}/../include.sh" cd $file_path diff --git a/test/e2e/misc/inside-pm2.sh b/test/e2e/misc/inside-pm2.sh index bfb8c45e..377241d6 100644 --- a/test/e2e/misc/inside-pm2.sh +++ b/test/e2e/misc/inside-pm2.sh @@ -1,7 +1,7 @@ #!/usr/bin/env bash SRC=$(cd $(dirname "$0"); pwd) -source "${SRC}/include.sh" +source "${SRC}/../include.sh" cd $file_path diff --git a/test/e2e/misc/instance-number.sh b/test/e2e/misc/instance-number.sh index 61b46e9b..fe2ba630 100644 --- a/test/e2e/misc/instance-number.sh +++ b/test/e2e/misc/instance-number.sh @@ -1,10 +1,10 @@ #!/usr/bin/env bash SRC=$(cd $(dirname "$0"); pwd) -source "${SRC}/include.sh" +source "${SRC}/../include.sh" cd $file_path $pm2 start server.js -i -100 should 'should have started 1 processes' 'online' 1 -$pm2 delete all \ No newline at end of file +$pm2 delete all diff --git a/test/e2e/misc/misc.sh b/test/e2e/misc/misc.sh index 42dbb45a..939e7ae4 100644 --- a/test/e2e/misc/misc.sh +++ b/test/e2e/misc/misc.sh @@ -1,7 +1,7 @@ #!/usr/bin/env bash SRC=$(cd $(dirname "$0"); pwd) -source "${SRC}/include.sh" +source "${SRC}/../include.sh" cd $file_path diff --git a/test/e2e/misc/pull.sh b/test/e2e/misc/pull.sh index 54e279f6..d12e68ea 100644 --- a/test/e2e/misc/pull.sh +++ b/test/e2e/misc/pull.sh @@ -1,7 +1,7 @@ #!/usr/bin/env bash SRC=$(cd $(dirname "$0"); pwd) -source "${SRC}/include.sh" +source "${SRC}/../include.sh" echo -e "\033[1mRunning tests:\033[0m" diff --git a/test/e2e/misc/startup.sh b/test/e2e/misc/startup.sh index 84d43b5d..f34ea214 100644 --- a/test/e2e/misc/startup.sh +++ b/test/e2e/misc/startup.sh @@ -7,7 +7,7 @@ then fi SRC=$(cd $(dirname "$0"); pwd) -source "${SRC}/include.sh" +source "${SRC}/../include.sh" cd $file_path $pm2 startup upstart -u $USER --hp $HOME --service-name abcdef diff --git a/test/e2e/misc/versioning-cmd.sh b/test/e2e/misc/versioning-cmd.sh index 487a227b..6f4199b8 100644 --- a/test/e2e/misc/versioning-cmd.sh +++ b/test/e2e/misc/versioning-cmd.sh @@ -1,7 +1,7 @@ #!/usr/bin/env bash SRC=$(cd $(dirname "$0"); pwd) -source "${SRC}/include.sh" +source "${SRC}/../include.sh" cd $file_path diff --git a/test/e2e/misc/vizion.sh b/test/e2e/misc/vizion.sh index d7e896d1..b65b1942 100644 --- a/test/e2e/misc/vizion.sh +++ b/test/e2e/misc/vizion.sh @@ -1,7 +1,7 @@ #!/usr/bin/env bash SRC=$(cd $(dirname "$0"); pwd) -source "${SRC}/include.sh" +source "${SRC}/../include.sh" cd $file_path diff --git a/test/e2e/cli/app-config-update.sh b/test/e2e/process-file/app-config-update.sh similarity index 100% rename from test/e2e/cli/app-config-update.sh rename to test/e2e/process-file/app-config-update.sh From 88fbb84597cee7029ce33f5b7e20e45f5a815b4b Mon Sep 17 00:00:00 2001 From: Unitech Date: Tue, 20 Mar 2018 11:14:00 +0100 Subject: [PATCH 060/140] fix: add missing libraries in travis --- .travis.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.travis.yml b/.travis.yml index 27286f64..320d304d 100644 --- a/.travis.yml +++ b/.travis.yml @@ -9,5 +9,7 @@ os: before_install: - sudo apt-get -qq update - sudo apt-get install parallel + - sudo apt-get install python3 + - sudo apt-get install php5-cli services: - docker From 234c63143e723a508796bc1d323c7241979bf4c2 Mon Sep 17 00:00:00 2001 From: Unitech Date: Tue, 20 Mar 2018 11:31:25 +0100 Subject: [PATCH 061/140] fix: remove unused tests --- test/e2e.sh | 6 ------ 1 file changed, 6 deletions(-) diff --git a/test/e2e.sh b/test/e2e.sh index 52817fa8..9f0d8619 100644 --- a/test/e2e.sh +++ b/test/e2e.sh @@ -16,12 +16,6 @@ bash ./test/e2e/modules/module-safeguard.sh spec "module safeguard system (--safe)" # CLI -bash ./test/e2e/cli/gracefulReload.sh -spec "gracefulReload system 1" -bash ./test/e2e/cli/gracefulReload2.sh -spec "gracefulReload system 2" -bash ./test/e2e/cli/gracefulReload3.sh -spec "gracefulReload system 3" bash ./test/e2e/cli/reload.sh spec "Reload" bash ./test/e2e/cli/operate-regex.sh From 7e7b4878194418363d6d80611bbde6817656a15a Mon Sep 17 00:00:00 2001 From: vmarchaud Date: Tue, 20 Mar 2018 12:12:41 +0100 Subject: [PATCH 062/140] deps: upgrade keymetrics-agent to latest --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index b0c34bea..f2261177 100644 --- a/package.json +++ b/package.json @@ -170,7 +170,7 @@ "eventemitter2": "5.0.1", "fclone": "1.0.11", "fs-extra": "^5.0.0", - "keymetrics-agent": "0.2.0", + "keymetrics-agent": "^0.3.0", "mkdirp": "0.5.1", "moment": "^2.19", "needle": "^2.2.0", From 36c4d6bca7445b46afc1236dc8ab4b8bf921148b Mon Sep 17 00:00:00 2001 From: Unitech Date: Tue, 20 Mar 2018 14:13:58 +0100 Subject: [PATCH 063/140] fix: skip interactor tests --- test/unit.sh | 72 ++++++++++++++++++++++++++-------------------------- 1 file changed, 36 insertions(+), 36 deletions(-) diff --git a/test/unit.sh b/test/unit.sh index 695c622f..79919de7 100644 --- a/test/unit.sh +++ b/test/unit.sh @@ -91,41 +91,41 @@ spec "Configuration system working" # # Interface testing # -cd ../interface +# cd ../interface -echo $PM2_HOME +# echo $PM2_HOME -mocha --opts ./mocha.opts ./exception.e2e.mocha.js -spec "E2E exception system checking" -mocha --opts ./mocha.opts ./interactor.connect.mocha.js -spec "Interactor test #1 with password setting" -mocha --opts ./mocha.opts ./interactor.daemonizer.mocha.js -spec "Remote interactor keys save verification" -mocha --opts ./mocha.opts ./scoped_pm2_actions.mocha.js -spec "Scoped PM2 Remote interactions test" -mocha --opts ./mocha.opts ./remote.mocha.js -spec "Remote interactions test" -mocha --opts ./mocha.opts ./password.mocha.js -spec "Password library checking" -mocha --opts ./mocha.opts ./custom-actions.mocha.js -spec "Custom actions test" -mocha --opts ./mocha.opts ./bus.spec.mocha.js -spec "Protocol communication test" -mocha --opts ./mocha.opts ./bus.fork.spec.mocha.js -spec "Protocol communication test" -mocha --opts ./mocha.opts ./request.mocha.js -spec "Protocol communication test" -mocha --opts ./mocha.opts ./aggregator.mocha.js -spec "Transaction trace aggregator test" -mocha --opts ./mocha.opts ./stacktrace.mocha.js -spec "Stacktrace Utility" -mocha --opts ./mocha.opts ./cache.mocha.js -spec "Cache Utility" -mocha --opts ./mocha.opts ./filter.mocha.js -spec "Filter Utility" -mocha --opts ./mocha.opts ./utility.mocha.js -spec "PM2 Utility" -mocha --opts ./mocha.opts ./pm2.link.check.mocha.js -spec "Transaction option enablement" -mocha --opts ./mocha.opts ./monitor.mocha.js -spec "Monitor / Unmonitor commands" +# mocha --opts ./mocha.opts ./exception.e2e.mocha.js +# spec "E2E exception system checking" +# mocha --opts ./mocha.opts ./interactor.connect.mocha.js +# spec "Interactor test #1 with password setting" +# mocha --opts ./mocha.opts ./interactor.daemonizer.mocha.js +# spec "Remote interactor keys save verification" +# mocha --opts ./mocha.opts ./scoped_pm2_actions.mocha.js +# spec "Scoped PM2 Remote interactions test" +# mocha --opts ./mocha.opts ./remote.mocha.js +# spec "Remote interactions test" +# mocha --opts ./mocha.opts ./password.mocha.js +# spec "Password library checking" +# mocha --opts ./mocha.opts ./custom-actions.mocha.js +# spec "Custom actions test" +# mocha --opts ./mocha.opts ./bus.spec.mocha.js +# spec "Protocol communication test" +# mocha --opts ./mocha.opts ./bus.fork.spec.mocha.js +# spec "Protocol communication test" +# mocha --opts ./mocha.opts ./request.mocha.js +# spec "Protocol communication test" +# mocha --opts ./mocha.opts ./aggregator.mocha.js +# spec "Transaction trace aggregator test" +# mocha --opts ./mocha.opts ./stacktrace.mocha.js +# spec "Stacktrace Utility" +# mocha --opts ./mocha.opts ./cache.mocha.js +# spec "Cache Utility" +# mocha --opts ./mocha.opts ./filter.mocha.js +# spec "Filter Utility" +# mocha --opts ./mocha.opts ./utility.mocha.js +# spec "PM2 Utility" +# mocha --opts ./mocha.opts ./pm2.link.check.mocha.js +# spec "Transaction option enablement" +# mocha --opts ./mocha.opts ./monitor.mocha.js +# spec "Monitor / Unmonitor commands" From 08612de5b7893a004ae33ed77fcb2ee3ff7b2251 Mon Sep 17 00:00:00 2001 From: Unitech Date: Fri, 23 Mar 2018 10:36:44 +0100 Subject: [PATCH 064/140] refactor: parallel test v1 --- package.json | 4 +- test/Dockerfile | 2 +- test/e2e/agent/interact.sh | 32 ------- test/e2e/cli/app-configuration.sh | 2 +- test/e2e/cli/cli-actions-2.sh | 24 ++--- test/e2e/{misc => }/docker.sh | 0 test/e2e/{cli => }/env-refresh.sh | 0 test/e2e/file-descriptor.sh | 61 +++++++++++++ test/e2e/misc/file-descriptor.sh | 53 ----------- test/e2e/misc/versioning-cmd.sh | 2 + test/e2e/{misc => }/nvm-node-version.sh | 0 test/e2e/{misc => }/pull.sh | 0 test/e2e/{misc => }/startup.sh | 0 test/parallel.js | 111 ++++++++++++++++++++++++ 14 files changed, 191 insertions(+), 100 deletions(-) delete mode 100644 test/e2e/agent/interact.sh rename test/e2e/{misc => }/docker.sh (100%) rename test/e2e/{cli => }/env-refresh.sh (100%) create mode 100644 test/e2e/file-descriptor.sh delete mode 100644 test/e2e/misc/file-descriptor.sh rename test/e2e/{misc => }/nvm-node-version.sh (100%) rename test/e2e/{misc => }/pull.sh (100%) rename test/e2e/{misc => }/startup.sh (100%) create mode 100644 test/parallel.js diff --git a/package.json b/package.json index 1e01c50f..d0608929 100644 --- a/package.json +++ b/package.json @@ -91,7 +91,7 @@ "main": "index.js", "types": "types/index.d.ts", "scripts": { - "test": "bash test/e2e.sh; bash test/unit.sh" + "test": "node test/parallel.js" }, "keywords": [ "cli", @@ -173,7 +173,7 @@ "moment": "^2.19", "needle": "^2.2.0", "nssocket": "0.6.0", - "pidusage": "^2.0.5", + "pidusage": "^2.0.6", "pm2-axon": "3.1.0", "pm2-axon-rpc": "0.5.0", "pm2-deploy": "^0.3.9", diff --git a/test/Dockerfile b/test/Dockerfile index ee1a9ecb..70a27f30 100644 --- a/test/Dockerfile +++ b/test/Dockerfile @@ -7,7 +7,7 @@ WORKDIR /var/pm2 ENV NODE_ENV test ENV PM2_DISCRETE_MODE true -RUN apk update && apk add bash git curl python3 php5 && rm -rf /var/cache/apk/* +RUN apk update && apk add bash git curl python python3 php5 && rm -rf /var/cache/apk/* RUN ln -s /usr/bin/php5 /usr/bin/php RUN npm install -g mocha@3.5 diff --git a/test/e2e/agent/interact.sh b/test/e2e/agent/interact.sh deleted file mode 100644 index 1fc1049c..00000000 --- a/test/e2e/agent/interact.sh +++ /dev/null @@ -1,32 +0,0 @@ -#!/usr/bin/env bash - -SRC=$(cd $(dirname "$0"); pwd) -source "${SRC}/include.sh" -cd $file_path - -echo -e "\033[1mRunning Interaction tests:\033[0m" - -$pm2 interact stop - -$pm2 interact - -$pm2 interact XXX2 XXX3 homeloc - -$pm2 updatePM2 - -$pm2 interact stop - -$pm2 interact - -$pm2 interact info - -$pm2 interact info | grep "XXX2" -spec "Should have XXX2 has public key" - -$pm2 interact info | grep "XXX3" -spec "Should have XXX3 has public key" - -$pm2 list - -$pm2 interact stop -$pm2 kill diff --git a/test/e2e/cli/app-configuration.sh b/test/e2e/cli/app-configuration.sh index cb17b214..f8683744 100644 --- a/test/e2e/cli/app-configuration.sh +++ b/test/e2e/cli/app-configuration.sh @@ -69,7 +69,7 @@ exists 'probe Event Loop Latency default value' "alert: {}" # Override value for test-probe $pm2 set probe-test.probes.test-probe.value 30 -sleep 2 +sleep 1 exists 'probe Event Loop Latency alerted' "value: 30" diff --git a/test/e2e/cli/cli-actions-2.sh b/test/e2e/cli/cli-actions-2.sh index 51abb450..46ef2c49 100644 --- a/test/e2e/cli/cli-actions-2.sh +++ b/test/e2e/cli/cli-actions-2.sh @@ -5,7 +5,7 @@ source "${SRC}/../include.sh" cd $file_path -############# TEST +############# Start / Stop / Restart echo -e "\033[1mRunning tests:\033[0m" @@ -17,7 +17,8 @@ spec "Should stop an app by script.js" $pm2 restart echo.js spec "Should restart an app by script.js (TRANSITIONAL STATE)" -############### +############### Start edge case + $pm2 delete all echo "Start application with filename starting with a numeric" @@ -28,28 +29,29 @@ should 'should app be stopped' 'stopped' 1 $pm2 restart 001-test should 'should app be online once restart called' 'online' 1 -$pm2 delete all ############## PID + +$pm2 delete all $pm2 start 001-test.js --name "test" should 'should app be online' 'online' 1 $pm2 pid > /tmp/pid-tmp $pm2 pid test -$pm2 delete all ############### +$pm2 delete all echo "Start application with filename starting with a numeric" $pm2 start throw-string.js -l err-string.log --merge-logs --no-automation >err-string.log -sleep 2 +sleep 1 grep 'throw-string.js' err-string.log spec "Should have written raw stack when throwing a string" -$pm2 delete all - #### +$pm2 delete all + $pm2 start echo.js --name gege should 'should app be online' 'online' 1 $pm2 stop gege @@ -78,7 +80,7 @@ $pm2 start echo.js ispec "Should not re start app" ########### DELETED STUFF BY ID -$pm2 kill +$pm2 delete all $pm2 start echo.js $pm2 delete 0 @@ -100,7 +102,7 @@ $pm2 list should 'should has been deleted process by script' "name: 'echo'" 0 ######## Actions on app name as number (#1937) -$pm2 kill +$pm2 delete all $pm2 start echo.js --name "455" should 'should restart processes' 'restart_time: 0' 1 $pm2 restart 455 @@ -113,9 +115,9 @@ $pm2 delete 455 should 'should has been deleted process by id' "name: '455'" 0 ########### OPTIONS OUTPUT FILES -$pm2 kill +$pm2 delete all -$pm2 start echo.js -o outech.log -e errech.log --name gmail -i 10 +$pm2 start echo.js -o outech.log -e errech.log --name gmail -i 1 sleep 1 cat outech-0.log > /dev/null spec "file outech-0.log exist" diff --git a/test/e2e/misc/docker.sh b/test/e2e/docker.sh similarity index 100% rename from test/e2e/misc/docker.sh rename to test/e2e/docker.sh diff --git a/test/e2e/cli/env-refresh.sh b/test/e2e/env-refresh.sh similarity index 100% rename from test/e2e/cli/env-refresh.sh rename to test/e2e/env-refresh.sh diff --git a/test/e2e/file-descriptor.sh b/test/e2e/file-descriptor.sh new file mode 100644 index 00000000..05df60ac --- /dev/null +++ b/test/e2e/file-descriptor.sh @@ -0,0 +1,61 @@ +#!/usr/bin/env bash + +# +# LSOF check +# + +SRC=$(cd $(dirname "$0"); pwd) +source "${SRC}/../include.sh" + +cd $file_path + +echo "################## RELOAD ###################" + +# lsof -c PM2 > /tmp/no_pm2_out.dat + +# $pm2 list + +# sleep 1 +# lsof -c PM2 > /tmp/empty_pm2_out.dat + +# $pm2 start echo.js -i 3 +# $pm2 start killtoofast.js -i 3 +# $pm2 delete all + +# sleep 3 +# lsof -c PM2 > /tmp/empty_pm2_out2.dat + +# OUT1=`cat /tmp/empty_pm2_out.dat | wc -l` +# OUT2=`cat /tmp/empty_pm2_out2.dat | wc -l` + +# if [ $OUT1 -eq $OUT2 ]; then +# success "All file descriptors have been closed" +# else +# fail "Some file descriptors are still open" +# fi + +# $pm2 start killtoofast.js -i 6 +# $pm2 kill + +# rm /tmp/no_pm2_out.dat +# rm /tmp/no_pm2_out2.dat +# rm /tmp/empty_pm2_out.dat +# rm /tmp/empty_pm2_out2.dat + +# sleep 6 +> /tmp/no_pm_pm2_out.dat +> /tmp/no_pm_pm2_out2.dat + +lsof -c PM2 > /tmp/no_pm2_out2.dat +diff /tmp/no_pm2_out.dat /tmp/no_pm2_out2.dat + +if [ $? == "0" ]; then + success "All file descriptors have been closed" +else + fail "Some file descriptors are still open" +fi + +rm /tmp/no_pm2_out.dat +rm /tmp/no_pm2_out2.dat +rm /tmp/empty_pm2_out.dat +rm /tmp/empty_pm2_out2.dat diff --git a/test/e2e/misc/file-descriptor.sh b/test/e2e/misc/file-descriptor.sh deleted file mode 100644 index b51a676c..00000000 --- a/test/e2e/misc/file-descriptor.sh +++ /dev/null @@ -1,53 +0,0 @@ -#!/usr/bin/env bash - -# -# LSOF check -# - -SRC=$(cd $(dirname "$0"); pwd) -source "${SRC}/../include.sh" - -cd $file_path - -echo "################## RELOAD ###################" - -lsof -c PM2 > /tmp/no_pm2_out.dat - -$pm2 list - -sleep 3 -lsof -c PM2 > /tmp/empty_pm2_out.dat - -$pm2 start echo.js -i 3 -$pm2 start killtoofast.js -i 3 -$pm2 delete all - -sleep 3 -lsof -c PM2 > /tmp/empty_pm2_out2.dat - -OUT1=`cat /tmp/empty_pm2_out.dat | wc -l` -OUT2=`cat /tmp/empty_pm2_out2.dat | wc -l` - -if [ $OUT1 -eq $OUT2 ]; then - success "All file descriptors have been closed" -else - fail "Some file descriptors are still open" -fi - -$pm2 start killtoofast.js -i 6 -$pm2 kill - -sleep 3 -lsof -c PM2 > /tmp/no_pm2_out2.dat -diff /tmp/no_pm2_out.dat /tmp/no_pm2_out2.dat - -if [ $? == "0" ]; then - success "All file descriptors have been closed" -else - fail "Some file descriptors are still open" -fi - -rm /tmp/no_pm2_out.dat -rm /tmp/no_pm2_out2.dat -rm /tmp/empty_pm2_out.dat -rm /tmp/empty_pm2_out2.dat diff --git a/test/e2e/misc/versioning-cmd.sh b/test/e2e/misc/versioning-cmd.sh index 6f4199b8..f1bdad07 100644 --- a/test/e2e/misc/versioning-cmd.sh +++ b/test/e2e/misc/versioning-cmd.sh @@ -5,6 +5,8 @@ source "${SRC}/../include.sh" cd $file_path +rm -rf app-playground + git clone https://github.com/keymetrics/app-playground.git cd app-playground diff --git a/test/e2e/misc/nvm-node-version.sh b/test/e2e/nvm-node-version.sh similarity index 100% rename from test/e2e/misc/nvm-node-version.sh rename to test/e2e/nvm-node-version.sh diff --git a/test/e2e/misc/pull.sh b/test/e2e/pull.sh similarity index 100% rename from test/e2e/misc/pull.sh rename to test/e2e/pull.sh diff --git a/test/e2e/misc/startup.sh b/test/e2e/startup.sh similarity index 100% rename from test/e2e/misc/startup.sh rename to test/e2e/startup.sh diff --git a/test/parallel.js b/test/parallel.js new file mode 100644 index 00000000..7d8a32b8 --- /dev/null +++ b/test/parallel.js @@ -0,0 +1,111 @@ + +const async = require('async') +const fs = require('fs') +const exec = require('child_process').exec +const path = require('path') +const chalk = require('chalk') +const Table = require('cli-table-redemption'); + +const testFolder = './test/e2e/' + +const CONCURRENT_TEST = 6 +const DOCKER_IMAGE_NAME = 'pm2-test' + +var timings = {}; + +function run(cmd, cb) { + exec(cmd, function(err, stdout, stderr) { + if (err) { + console.log(`Retrying ${cmd}`) + return exec(cmd, function(err, stdout, stderr) { + if (err) return cb(stdout.split('\n')); + return cb(null); + }) + } + return cb(null) + }) +} + +function buildContainer(cb) { + exec(`docker build -t ${DOCKER_IMAGE_NAME} -f test/Dockerfile .`, cb) +} + +function listAllTest(cb) { + var test_suite = [] + + fs.readdir(testFolder, (err, folders) => { + async.forEachLimit(folders, 4, (folder, next) => { + var fold = path.join(testFolder, folder) + fs.readdir(fold, (err, files) => { + if (err) return next() + files.forEach((file) => { + test_suite.push(path.join(fold, file)) + }) + next() + }) + }, function() { + launchTestSuite(test_suite, cb) + }) + }) +} + +function launchTestSuite(files, cb) { + async.forEachLimit(files, CONCURRENT_TEST, function(file, next) { + var cmd = `docker run -v ${path.resolve(__dirname, '..')}:/var/pm2 ${DOCKER_IMAGE_NAME} bash ${file}` + + console.log(chalk.bold(`Running test ${file}`)) + timings[file] = new Date().getTime() + + run(cmd, function(err) { + if (err) { + // Display Error + console.error(chalk.bold.red(`${'='.repeat(25)} Test File ${file} has failed ${'='.repeat(25)}`)) + console.error(chalk.bold('Output (stderr):')) + err.forEach(function(line) { + console.error(line) + }) + console.error(chalk.bold.red(`${'='.repeat(80)}`)) + return next(err) + } + + timings[file] = new Date().getTime() - timings[file] + + console.log(chalk.bold.green(`✓ Test ${file} success`)) + return next(); + }) + }, (err) => { + if (err) { + console.log('Test Suite has failed') + cb(err) + } + console.log('Test Suite passed succesfully') + cb() + }) +} + +buildContainer(function(err) { + if (err) { + console.error(err) + process.exit(1) + } + console.log(`Container ${DOCKER_IMAGE_NAME} has been built`) + + return listAllTest(function(err) { + + var table = new Table({ + head: ['Test', 'Duration'], + style : {'padding-left' : 1, head : ['cyan', 'bold'], compact : true} + }); + + Object.keys(timings).forEach(function(test) { + table.push(test, timings[test]) + }) + + console.log(table.toString()); + + if (err) { + return console.error(chalk.bold.red('Test suite failed')) + } + console.log(chalk.bold.blue('Test suite succeeded')) + }) +}) From b075e6d09b09ff371adf045dc5079bb8ef82f1cf Mon Sep 17 00:00:00 2001 From: Unitech Date: Fri, 23 Mar 2018 11:54:44 +0100 Subject: [PATCH 065/140] fix: test/display summary --- test/e2e/cli/interpreter.sh | 31 ++++++++++++++++--------------- test/parallel.js | 4 ++-- 2 files changed, 18 insertions(+), 17 deletions(-) diff --git a/test/e2e/cli/interpreter.sh b/test/e2e/cli/interpreter.sh index 7962a580..e7379c29 100644 --- a/test/e2e/cli/interpreter.sh +++ b/test/e2e/cli/interpreter.sh @@ -77,27 +77,28 @@ should 'process should be online' "status: 'online'" 1 ########### Install -$pm2 install typescript -########### typescript fork test -$pm2 delete all +# $pm2 install typescript ->typescript.log +# ########### typescript fork test +# $pm2 delete all -$pm2 start echo.ts -o typescript.log --merge-logs +# >typescript.log -sleep 1.5 +# $pm2 start echo.ts -o typescript.log --merge-logs -grep "Hello Typescript!" typescript.log -spec "Should work on Typescript files in fork mode" +# sleep 1.5 -########### typescript cluster test -$pm2 delete all +# grep "Hello Typescript!" typescript.log +# spec "Should work on Typescript files in fork mode" ->typescript.log +# ########### typescript cluster test +# $pm2 delete all -$pm2 start echo.ts -i 1 -o typescript.log --merge-logs +# >typescript.log -sleep 1.5 -grep "Hello Typescript!" typescript.log -spec "Should work on Typescript files in cluster mode" +# $pm2 start echo.ts -i 1 -o typescript.log --merge-logs + +# sleep 1.5 +# grep "Hello Typescript!" typescript.log +# spec "Should work on Typescript files in cluster mode" diff --git a/test/parallel.js b/test/parallel.js index 7d8a32b8..6290859d 100644 --- a/test/parallel.js +++ b/test/parallel.js @@ -95,10 +95,10 @@ buildContainer(function(err) { var table = new Table({ head: ['Test', 'Duration'], style : {'padding-left' : 1, head : ['cyan', 'bold'], compact : true} - }); + }) Object.keys(timings).forEach(function(test) { - table.push(test, timings[test]) + table.push([test, timings[test]]) }) console.log(table.toString()); From 952b7631d19e1074ea73cc7a67bbaefe20950603 Mon Sep 17 00:00:00 2001 From: Unitech Date: Fri, 23 Mar 2018 20:21:27 +0100 Subject: [PATCH 066/140] test: move test --- test/e2e/{internals => }/infinite-loop.sh | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename test/e2e/{internals => }/infinite-loop.sh (100%) diff --git a/test/e2e/internals/infinite-loop.sh b/test/e2e/infinite-loop.sh similarity index 100% rename from test/e2e/internals/infinite-loop.sh rename to test/e2e/infinite-loop.sh From 9c9733246dbe6afff1b488bc3ba3b6fea3877ea5 Mon Sep 17 00:00:00 2001 From: Unitech Date: Fri, 23 Mar 2018 21:09:35 +0100 Subject: [PATCH 067/140] test: move test --- test/e2e/{internals => }/source_map.sh | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename test/e2e/{internals => }/source_map.sh (100%) diff --git a/test/e2e/internals/source_map.sh b/test/e2e/source_map.sh similarity index 100% rename from test/e2e/internals/source_map.sh rename to test/e2e/source_map.sh From 472aba3499ff2d9d0eb834e819410026b1a44503 Mon Sep 17 00:00:00 2001 From: Unitech Date: Sat, 24 Mar 2018 10:49:23 +0100 Subject: [PATCH 068/140] test: 3 concurrent jobs --- test/parallel.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/parallel.js b/test/parallel.js index 6290859d..838520e2 100644 --- a/test/parallel.js +++ b/test/parallel.js @@ -8,7 +8,7 @@ const Table = require('cli-table-redemption'); const testFolder = './test/e2e/' -const CONCURRENT_TEST = 6 +const CONCURRENT_TEST = 3 const DOCKER_IMAGE_NAME = 'pm2-test' var timings = {}; From 91d14f0434b96b9994fa58a3f577824053ede3b8 Mon Sep 17 00:00:00 2001 From: Unitech Date: Sat, 24 Mar 2018 17:39:25 +0100 Subject: [PATCH 069/140] revert: stick with normal test wo parallelization --- package.json | 3 ++- test/e2e/{ => cli}/env-refresh.sh | 0 test/e2e/{ => internals}/infinite-loop.sh | 0 test/e2e/{ => internals}/source_map.sh | 0 test/e2e/{ => misc}/nvm-node-version.sh | 0 test/e2e/{ => misc}/startup.sh | 0 6 files changed, 2 insertions(+), 1 deletion(-) rename test/e2e/{ => cli}/env-refresh.sh (100%) rename test/e2e/{ => internals}/infinite-loop.sh (100%) rename test/e2e/{ => internals}/source_map.sh (100%) rename test/e2e/{ => misc}/nvm-node-version.sh (100%) rename test/e2e/{ => misc}/startup.sh (100%) diff --git a/package.json b/package.json index d0608929..a92c27bd 100644 --- a/package.json +++ b/package.json @@ -91,7 +91,7 @@ "main": "index.js", "types": "types/index.d.ts", "scripts": { - "test": "node test/parallel.js" + "test": "bash test/e2e.sh && bash test/unit.sh" }, "keywords": [ "cli", @@ -163,6 +163,7 @@ "chalk": "^2.3.1", "chokidar": "^2.0.2", "cli-table-redemption": "^1.0.0", + "coffee-script": "^1.12.7", "commander": "2.14.1", "cron": "^1.3", "debug": "^3.0", diff --git a/test/e2e/env-refresh.sh b/test/e2e/cli/env-refresh.sh similarity index 100% rename from test/e2e/env-refresh.sh rename to test/e2e/cli/env-refresh.sh diff --git a/test/e2e/infinite-loop.sh b/test/e2e/internals/infinite-loop.sh similarity index 100% rename from test/e2e/infinite-loop.sh rename to test/e2e/internals/infinite-loop.sh diff --git a/test/e2e/source_map.sh b/test/e2e/internals/source_map.sh similarity index 100% rename from test/e2e/source_map.sh rename to test/e2e/internals/source_map.sh diff --git a/test/e2e/nvm-node-version.sh b/test/e2e/misc/nvm-node-version.sh similarity index 100% rename from test/e2e/nvm-node-version.sh rename to test/e2e/misc/nvm-node-version.sh diff --git a/test/e2e/startup.sh b/test/e2e/misc/startup.sh similarity index 100% rename from test/e2e/startup.sh rename to test/e2e/misc/startup.sh From e6febcd70dd0f1e68b74df8563d3046ee3b32b89 Mon Sep 17 00:00:00 2001 From: Unitech Date: Sat, 24 Mar 2018 22:19:50 +0100 Subject: [PATCH 070/140] fix: re-enable agent tests --- test/unit.sh | 70 ++++++++++++++++++++++++++-------------------------- 1 file changed, 35 insertions(+), 35 deletions(-) diff --git a/test/unit.sh b/test/unit.sh index 79919de7..03b18425 100644 --- a/test/unit.sh +++ b/test/unit.sh @@ -91,41 +91,41 @@ spec "Configuration system working" # # Interface testing # -# cd ../interface +cd ../interface # echo $PM2_HOME -# mocha --opts ./mocha.opts ./exception.e2e.mocha.js -# spec "E2E exception system checking" -# mocha --opts ./mocha.opts ./interactor.connect.mocha.js -# spec "Interactor test #1 with password setting" -# mocha --opts ./mocha.opts ./interactor.daemonizer.mocha.js -# spec "Remote interactor keys save verification" -# mocha --opts ./mocha.opts ./scoped_pm2_actions.mocha.js -# spec "Scoped PM2 Remote interactions test" -# mocha --opts ./mocha.opts ./remote.mocha.js -# spec "Remote interactions test" -# mocha --opts ./mocha.opts ./password.mocha.js -# spec "Password library checking" -# mocha --opts ./mocha.opts ./custom-actions.mocha.js -# spec "Custom actions test" -# mocha --opts ./mocha.opts ./bus.spec.mocha.js -# spec "Protocol communication test" -# mocha --opts ./mocha.opts ./bus.fork.spec.mocha.js -# spec "Protocol communication test" -# mocha --opts ./mocha.opts ./request.mocha.js -# spec "Protocol communication test" -# mocha --opts ./mocha.opts ./aggregator.mocha.js -# spec "Transaction trace aggregator test" -# mocha --opts ./mocha.opts ./stacktrace.mocha.js -# spec "Stacktrace Utility" -# mocha --opts ./mocha.opts ./cache.mocha.js -# spec "Cache Utility" -# mocha --opts ./mocha.opts ./filter.mocha.js -# spec "Filter Utility" -# mocha --opts ./mocha.opts ./utility.mocha.js -# spec "PM2 Utility" -# mocha --opts ./mocha.opts ./pm2.link.check.mocha.js -# spec "Transaction option enablement" -# mocha --opts ./mocha.opts ./monitor.mocha.js -# spec "Monitor / Unmonitor commands" +mocha --opts ./mocha.opts ./exception.e2e.mocha.js +spec "E2E exception system checking" +mocha --opts ./mocha.opts ./interactor.connect.mocha.js +spec "Interactor test #1 with password setting" +mocha --opts ./mocha.opts ./interactor.daemonizer.mocha.js +spec "Remote interactor keys save verification" +mocha --opts ./mocha.opts ./scoped_pm2_actions.mocha.js +spec "Scoped PM2 Remote interactions test" +mocha --opts ./mocha.opts ./remote.mocha.js +spec "Remote interactions test" +mocha --opts ./mocha.opts ./password.mocha.js +spec "Password library checking" +mocha --opts ./mocha.opts ./custom-actions.mocha.js +spec "Custom actions test" +mocha --opts ./mocha.opts ./bus.spec.mocha.js +spec "Protocol communication test" +mocha --opts ./mocha.opts ./bus.fork.spec.mocha.js +spec "Protocol communication test" +mocha --opts ./mocha.opts ./request.mocha.js +spec "Protocol communication test" +mocha --opts ./mocha.opts ./aggregator.mocha.js +spec "Transaction trace aggregator test" +mocha --opts ./mocha.opts ./stacktrace.mocha.js +spec "Stacktrace Utility" +mocha --opts ./mocha.opts ./cache.mocha.js +spec "Cache Utility" +mocha --opts ./mocha.opts ./filter.mocha.js +spec "Filter Utility" +mocha --opts ./mocha.opts ./utility.mocha.js +spec "PM2 Utility" +mocha --opts ./mocha.opts ./pm2.link.check.mocha.js +spec "Transaction option enablement" +mocha --opts ./mocha.opts ./monitor.mocha.js +spec "Monitor / Unmonitor commands" From 299a52a253d70edcde23cbd7e0c201d492984df4 Mon Sep 17 00:00:00 2001 From: Unitech Date: Mon, 26 Mar 2018 14:15:00 +0200 Subject: [PATCH 071/140] refactor: remove test deported to keymetrics-agent --- test/interface/aggregator.mocha.js | 239 ------------------- test/interface/cache.mocha.js | 86 ------- test/interface/custom-actions.mocha.js | 169 -------------- test/interface/exception.e2e.mocha.js | 88 ------- test/interface/filter.mocha.js | 23 -- test/interface/interactor.connect.mocha.js | 227 ------------------ test/interface/monitor.mocha.js | 90 ------- test/interface/password.mocha.js | 20 -- test/interface/remote.mocha.js | 225 ------------------ test/interface/request.mocha.js | 91 -------- test/interface/scoped_pm2_actions.mocha.js | 258 --------------------- test/interface/stacktrace.mocha.js | 157 ------------- test/unit.sh | 24 -- 13 files changed, 1697 deletions(-) delete mode 100644 test/interface/aggregator.mocha.js delete mode 100644 test/interface/cache.mocha.js delete mode 100644 test/interface/custom-actions.mocha.js delete mode 100644 test/interface/exception.e2e.mocha.js delete mode 100644 test/interface/filter.mocha.js delete mode 100644 test/interface/interactor.connect.mocha.js delete mode 100644 test/interface/monitor.mocha.js delete mode 100644 test/interface/password.mocha.js delete mode 100644 test/interface/remote.mocha.js delete mode 100644 test/interface/request.mocha.js delete mode 100644 test/interface/scoped_pm2_actions.mocha.js delete mode 100644 test/interface/stacktrace.mocha.js diff --git a/test/interface/aggregator.mocha.js b/test/interface/aggregator.mocha.js deleted file mode 100644 index b90d0d79..00000000 --- a/test/interface/aggregator.mocha.js +++ /dev/null @@ -1,239 +0,0 @@ - -process.env.DEBUG='pm2:aggregator'; -var should = require('should'); -var Aggregator = require('../../lib/Interactor/TransactionAggregator.js'); -var Utility = require('../../lib/Interactor/Utility.js'); -var Plan = require('../helpers/plan.js'); -var TraceFactory = require('./misc/trace_factory.js'); -var TraceMock = require('./misc/trace.json'); -var path = require('path'); -var fs = require('fs'); - -describe('Transactions Aggregator', function() { - var aggregator; - var stackParser; - - it('should instanciate context cache', function() { - var cache = new Utility.Cache({ - miss: function (key) { - try { - var content = fs.readFileSync(path.resolve(key)); - return content.toString().split(/\r?\n/); - } catch (err) { - return undefined; - } - } - }) - - stackParser = new Utility.StackTraceParser({ cache: cache, context: 2}); - }); - - it('should instanciate aggregator', function() { - aggregator = new Aggregator({ stackParser: stackParser}); - }); - - describe('.censorSpans', function() { - var trace = TraceFactory.generateTrace('/yoloswag/swag', 2); - - it('should not fail', function() { - aggregator.censorSpans(null); - }); - - it('should censor span', function() { - should.exist(trace.spans[1].labels.results); - aggregator.censorSpans(trace.spans); - should.not.exist(trace.spans[1].labels.results); - trace.spans[1].labels.cmd.should.containEql('?'); - }); - }); - - describe('.isIdentifier', function() { - it('should be an identifier (api version)', function() { - aggregator.isIdentifier('v1').should.equal(true); - }); - - it('should be an identifier (number)', function() { - aggregator.isIdentifier('123').should.equal(true); - }); - - it('should be an identifier (random str)', function() { - aggregator.isIdentifier('65f4ez656').should.equal(true); - }); - - it('should be an identifier (uuid)', function() { - aggregator.isIdentifier('123e4567-e89b-12d3-a456-426655440000').should.equal(true); - aggregator.isIdentifier('123e4567e89b12d3a456426655440000').should.equal(true); - }); - - it('should be an identifier', function() { - aggregator.isIdentifier('toto-toto-tooa').should.equal(true); - aggregator.isIdentifier('toto@toto.fr').should.equal(true); - aggregator.isIdentifier('toto@toto.fr').should.equal(true); - aggregator.isIdentifier('fontawesome-webfont.eot').should.equal(true); - aggregator.isIdentifier('life_is_just_fantasy').should.equal(true); - aggregator.isIdentifier('OR-IS_THIS-REAL_LIFE').should.equal(true); - }); - - it('should be NOT an identifier', function() { - aggregator.isIdentifier('bucket').should.equal(false); - aggregator.isIdentifier('admin').should.equal(false); - aggregator.isIdentifier('auth').should.equal(false); - aggregator.isIdentifier('users').should.equal(false); - aggregator.isIdentifier('version').should.equal(false); - }); - }); - - describe('.matchPath - aggregate', function() { - var routes = { - 'bucket/6465577': { spans: true } - }; - - it('should not fail', function() { - aggregator.matchPath(); - aggregator.matchPath('/'); - aggregator.matchPath('/', {}); - aggregator.matchPath('/', { - '/' : {} - }); - }); - - it('should match first route', function() { - var match = aggregator.matchPath('bucket/67754', routes); - should.exist(match); - match.should.be.a.String(); - match.should.equal('bucket/*'); - should.exist(routes['bucket/*']) - }); - - it('should NOT match any route', function() { - should.not.exist(aggregator.matchPath('toto/67754', routes)); - }); - - it('should match aggregated route with *', function() { - var match = aggregator.matchPath('bucket/87998', routes); - should.exist(match); - match.should.be.a.String(); - match.should.equal('bucket/*'); - should.exist(routes['bucket/*']) - }); - }); - - describe('merging trace together', function() { - var trace = TraceFactory.generateTrace('yoloswag/swag', 2); - var ROUTES = { - 'yoloswag/swag': {} - }; - - it('should not fail', function() { - aggregator.mergeTrace() - aggregator.mergeTrace(null, trace) - aggregator.mergeTrace({}, trace) - aggregator.mergeTrace({}) - }); - - it('should add a trace', function() { - aggregator.mergeTrace(ROUTES['yoloswag/swag'], trace) - ROUTES['yoloswag/swag'].meta.histogram.getCount().should.be.equal(1); - ROUTES['yoloswag/swag'].variances.length.should.be.equal(1); - ROUTES['yoloswag/swag'].variances[0].spans.length.should.be.equal(3); - }); - - it('should merge with the first variance', function() { - aggregator.mergeTrace(ROUTES['yoloswag/swag'], trace); - ROUTES['yoloswag/swag'].variances.length.should.be.equal(1); - ROUTES['yoloswag/swag'].variances[0].histogram.getCount().should.be.equal(2); - }); - - it('should merge as a new variance with the same route', function () { - var trace2 = TraceFactory.generateTrace('yoloswag/swag', 3) - trace2.spans.forEach(function (span) { - span.min = span.max = span.mean = Math.round(new Date(span.endTime) - new Date(span.startTime)); - }) - aggregator.mergeTrace(ROUTES['yoloswag/swag'], trace2); - ROUTES['yoloswag/swag'].meta.histogram.getCount().should.be.equal(3); - ROUTES['yoloswag/swag'].variances.length.should.be.equal(2); - ROUTES['yoloswag/swag'].variances[0].histogram.getCount().should.be.equal(2); - ROUTES['yoloswag/swag'].variances[1].histogram.getCount().should.be.equal(1); - ROUTES['yoloswag/swag'].variances[1].spans.length.should.be.equal(4); - }); - }); - - describe('.aggregate', function() { - it('should not fail', function() { - var dt = aggregator.aggregate(null); - should(dt).be.false(); - }); - - it('should aggregate', function() { - // Simulate some data - var packet = TraceFactory.generatePacket('yoloswag/swag', 'appname'); - aggregator.aggregate(packet); - packet = TraceFactory.generatePacket('yoloswag/swag', 'appname'); - aggregator.aggregate(packet); - packet = TraceFactory.generatePacket('yoloswag/swag', 'appname'); - aggregator.aggregate(packet); - packet = TraceFactory.generatePacket('sisi/aight', 'appname'); - aggregator.aggregate(packet); - packet = TraceFactory.generatePacket('sisi/aight', 'APP2'); - aggregator.aggregate(packet); - - var agg = aggregator.getAggregation(); - - // should get 2 apps in agg - should.exist(agg['appname']); - should.exist(agg['APP2']); - - // should contain 2 routes for appname - Object.keys(agg['appname'].routes).length.should.eql(2); - should.exist(agg['appname'].process); - agg['appname'].meta.trace_count.should.eql(4); - should.exist(agg['appname'].meta.histogram.percentiles([0.5])[0.5]); - - // should pm_id not taken into account - should.not.exist(agg['appname'].process.pm_id); - }); - }); - - describe('.normalizeAggregation', function() { - it('should get normalized aggregattion', function(done) { - var ret = aggregator.prepareAggregationforShipping(); - should.exist(ret['appname'].process.server); - should.exist(ret['APP2'].process.server); - done(); - }); - }); - - describe('.resetAggregation and .clearData', function() { - it('should get transactions', function() { - var cache = aggregator.getAggregation(); - Object.keys(cache).length.should.eql(2); - }); - - it('should .resetAggregation for "appname" app', function() { - var cache = aggregator.getAggregation(); - - cache['appname'].meta.trace_count.should.eql(4); - Object.keys(cache['appname'].routes).length.should.eql(2); - - aggregator.resetAggregation('appname', {}) - cache = aggregator.getAggregation(); - Object.keys(cache).length.should.eql(2); - - cache['appname'].meta.trace_count.should.eql(0); - Object.keys(cache['appname'].routes).length.should.eql(0); - }); - - it('should .clearData', function() { - var cache = aggregator.getAggregation(); - cache['APP2'].meta.trace_count.should.eql(1); - Object.keys(cache['APP2'].routes).length.should.eql(1); - aggregator.clearData(); - - cache = aggregator.getAggregation(); - cache['APP2'].meta.trace_count.should.eql(0); - Object.keys(cache['APP2'].routes).length.should.eql(0); - }); - - }); - -}); diff --git a/test/interface/cache.mocha.js b/test/interface/cache.mocha.js deleted file mode 100644 index ecd30771..00000000 --- a/test/interface/cache.mocha.js +++ /dev/null @@ -1,86 +0,0 @@ - -var should = require('should'); -var Utility = require('../../lib/Interactor/Utility.js'); -var path = require('path'); -var fs = require('fs'); - -describe('Cache Utility', function() { - var aggregator; - var stackParser; - var cache; - - it('should instanciate context cache', function() { - cache = new Utility.Cache({ - miss: function (key) { - try { - var content = fs.readFileSync(path.resolve(key)); - return content.toString().split(/\r?\n/); - } catch (err) { - return null; - } - } - }) - }); - - it('should get null without key', function() { - should(cache.get()).be.null(); - }); - - it('should get null with unknow value', function() { - should(cache.get('toto')).be.null(); - }); - - it('should get null', function() { - should(cache.get()).be.null(); - }); - - it('should set null', function() { - should(cache.set()).be.false(); - }); - - it('should not set key without value', function() { - should(cache.set('toto')).be.false(); - }); - - it('should set value', function() { - should(cache.set('toto', 'val')).be.true(); - }); - - it('should get value', function() { - should(cache.get('toto')).eql('val'); - }); - - it('should reset', function() { - cache.reset(); - }); - - it('should get null with unknow value', function() { - should(cache.get('toto')).be.null(); - }); - - it('should instanciate context cache with ttl', function() { - cache = new Utility.Cache({ - miss: function (key) { - try { - var content = fs.readFileSync(path.resolve(key)); - return content.toString().split(/\r?\n/); - } catch (err) { - return null; - } - }, - ttl: 1 - }); - }); - - it('should add a key', function () { - should(cache.set('toto', 'yeslife')).be.true(); - }); - - it('should wait one second to see the key disapear', function (done) { - setTimeout(function () { - should(cache.get('toto')).be.null(); - done(); - }, 3000); - }); - -}); diff --git a/test/interface/custom-actions.mocha.js b/test/interface/custom-actions.mocha.js deleted file mode 100644 index 5d6117ec..00000000 --- a/test/interface/custom-actions.mocha.js +++ /dev/null @@ -1,169 +0,0 @@ - - -var PM2 = require('../..'); -var should = require('should'); -var nssocket = require('nssocket'); -var events = require('events'); -var util = require('util'); - -var Cipher = require('../../lib/Interactor/Cipher.js'); -var cst = require('../../constants.js'); -var Plan = require('../helpers/plan.js'); -var Interactor = require('../../lib/Interactor/InteractorDaemonizer.js'); - -var server = new events.EventEmitter(); -var pm2_bus; - -process.env.NODE_ENV = 'local_test'; - -var meta_connect = { - secret_key : 'osef', - public_key : 'osef', - machine_name : 'osef' -}; - -/** - * Mock server receiving data - * @method forkInteractor - * @return CallExpression - */ -function createMockServer(cb) { - var server = nssocket.createServer(function(_socket) { - - console.log('Got new connection in Mock server'); - - server.on('cmd', function(data) { - console.log('Sending command %j', data); - _socket.send(data._type, data); - }); - - _socket.data('*', function(data) { - this.event.forEach(function(ev) { - server.emit(ev, data); - }); - }); - - }); - - server.on('error', function(e) { - throw new Error(e); - }); - - server.on('listening', function() { - cb(null, server); - }); - - server.listen(4322, '0.0.0.0'); -} - -function startSomeApps(pm2, cb) { - pm2.start({ - script : './events/custom_action.js', - name : 'custom-action' - }, cb); -} - -describe('Custom actions', function() { - var server; - var interactor; - var pm2 = new PM2.custom({ - independent : true, - cwd : __dirname + '/../fixtures', - secret_key : 'osef', - public_key : 'osef', - machine_name : 'osef', - daemon_mode: true - });; - - before(function(done) { - createMockServer(function(err, _server) { - server = _server; - pm2.connect(function(err) { - startSomeApps(pm2, function() { - pm2.launchBus(function(err, bus) { - pm2_bus = bus; - setTimeout(done, 500); - }); - }); - }); - }); - }); - - after(function(done) { - server.close(); - pm2.destroy(done); - }); - - it('should send ask, receive ask:rep and identify agent', function(done) { - server.once('ask:rep', function(pck) { - var data = Cipher.decipherMessage(pck.data, meta_connect.secret_key); - data.machine_name.should.eql(meta_connect.machine_name); - done(); - }); - - server.emit('cmd', { _type : 'ask' }); - }); - - /** - * PM2 agent is now identified - */ - - it('should trigger remote action successfully', function(done) { - var plan = new Plan(2, done); - - var success = function(pck) { - plan.ok(true); - server.removeListener('trigger:action:failure', failure); - }; - - var failure = function(pck) { - console.log(pck); - plan.ok(false); - }; - - server.once('trigger:action:success', success); - - server.once('trigger:action:failure', failure); - - pm2_bus.on('axm:reply', function(pck) { - pck.data.return.success.should.be.true; - pck.data.return.subobj.a.should.eql('b'); - plan.ok(true); - }); - - server.emit('cmd', { - _type : 'trigger:action', - process_id : 0, - action_name : 'refresh:db' - }); - }); - - it('should trigger failure action', function(done) { - var plan = new Plan(1, done); - - var success = function(pck) { - plan.ok(false); - }; - - var failure = function(pck) { - server.removeListener('trigger:action:success', success); - plan.ok(true); - }; - - server.once('trigger:action:success', success); - - server.once('trigger:action:failure', failure); - - pm2_bus.on('axm:reply', function(pck) { - plan.ok(false); - }); - - server.emit('cmd', { - _type : 'trigger:action', - process_id : 0, - action_name : 'unknown:action' - }); - }); - - -}); diff --git a/test/interface/exception.e2e.mocha.js b/test/interface/exception.e2e.mocha.js deleted file mode 100644 index 65ef7f78..00000000 --- a/test/interface/exception.e2e.mocha.js +++ /dev/null @@ -1,88 +0,0 @@ - -process.env.NODE_ENV = 'local_test'; -process.env.KM_URL_REFRESH_RATE = 1000; - -var axon = require('pm2-axon'); -var PM2 = require('../..'); -var should = require('should'); -var sub; - -function listen(cb) { - sub = axon.socket('sub'); - sub.bind(8080, cb); -} - -function listenRev(cb) { - var listener_server = require('nssocket').createServer(function(_socket) { - }); - - listener_server.listen(4322, '0.0.0.0', function() { - console.log('Reverse interact online'); - cb(); - }); -} - -describe('Programmatically test interactor', function() { - var pm2; - - before(function(done) { - listen(function() { - listenRev(function() { - - pm2 = new PM2.custom({ - public_key : 'xxx', - secret_key : 'yyy', - cwd : __dirname + '/../fixtures/interface' - }); - - pm2.connect(function() { - pm2.kill(function() { - done(); - }); - }); - }); - }); - }); - - after(function(done) { - pm2.kill(done); - }); - - describe('application testing', function() { - it('should start test application', function(done) { - sub.once('message', function(data) { - var packet = JSON.parse(data); - packet.data['process:event'].length.should.eql(2) - done(); - }); - - pm2.start({ - script : 'process_exception_with_logs.js', - name : 'API' - }, function(err, data) { - if (err) done(err); - //console.log(arguments); - }); - }); - - it('should get transaction trace via interactor output', function(done) { - (function callAgain() { - sub.once('message', function(data) { - var packet = JSON.parse(data); - - if (packet.data['process:exception']) { - packet.data['process:exception'][0].data.callsite.should.containEql('process_exception_with_logs.js:7'); - packet.data['process:exception'][0].data.context.should.containEql('console.log'); - should.exist(packet.data['process:exception'][0].data.last_logs); - //console.log - done(); - } - else callAgain(); - }); - })() - - pm2.trigger('API', 'exception'); - }); - - }); -}); diff --git a/test/interface/filter.mocha.js b/test/interface/filter.mocha.js deleted file mode 100644 index 9e48d7cf..00000000 --- a/test/interface/filter.mocha.js +++ /dev/null @@ -1,23 +0,0 @@ - -var Filter = require('../../lib/Interactor/Filter.js'); -var should = require('should'); -var os = require('os'); - -describe('Filter Utility', function() { - it('should .machineSnapshot works as expected', function() { - var filtered = Filter.machineSnapshot([], { - REVERSE_INTERACT : true, - PM2_VERSION : '2.2.0' - }); - filtered.server.should.have.properties(['loadavg', 'total_mem', 'free_mem']); - should(filtered.server.total_mem).eql(os.totalmem()); - should(filtered.server.arch).eql(os.arch()); - }); - - it('should .monitoring works as expected', function() { - var filtered = Filter.monitoring([], {}); - filtered.should.have.properties(['loadavg', 'total_mem', 'free_mem', 'processes']); - filtered.total_mem.should.eql(os.totalmem()); - }); - -}); diff --git a/test/interface/interactor.connect.mocha.js b/test/interface/interactor.connect.mocha.js deleted file mode 100644 index f9974038..00000000 --- a/test/interface/interactor.connect.mocha.js +++ /dev/null @@ -1,227 +0,0 @@ - -process.env.NODE_ENV = 'local_test'; -process.env.TRAVIS = true; -process.env.DEBUG='interface:*'; - -var PM2 = require('../..'); -var should = require('should'); -var nssocket = require('nssocket'); -var events = require('events'); -var util = require('util'); -var axon = require('pm2-axon'); -var sock = axon.socket('sub'); - -var pub_sock = sock.bind(8080); -var Cipher = require('../../lib/Interactor/Cipher.js'); -var cst = require('../../constants.js'); -var Plan = require('../helpers/plan.js'); -var Configuration = require('../../lib/Configuration.js'); -var Helpers = require('../helpers/apps.js'); - -var server = null; -var listener_server; - -var _socket_list = []; - -var meta_connect = { - secret_key : 'osef', - public_key : 'osef', - machine_name : 'osef' -}; - -/** - * Mock server receiving data - * @method forkInteractor - * @return CallExpression - */ -function createMockServer(cb) { - - pub_sock.server.on('connection', function(socket) { - _socket_list.push(socket); - console.log('Got new connection on mock server'); - }); - - server = new events.EventEmitter(); - - listener_server = nssocket.createServer(function(_socket) { - server.on('cmd', function(data) { - _socket.send(data._type, data); - }); - - _socket.data('*', function(data) { - this.event.forEach(function(ev) { - server.emit(ev, data); - }); - }); - - }); - - listener_server.on('error', function(e) { - throw new Error(e); - }); - - listener_server.on('listening', function() { - cb(null, server); - }); - - listener_server.listen(4322, '0.0.0.0'); -} - -describe('Interactor testing', function() { - var server; - var interactor; - var pm2_bus; - - var pm2 = new PM2.custom({ - independent : true, - cwd : __dirname + '/../fixtures', - secret_key : 'osef', - public_key : 'osef', - machine_name : 'osef', - daemon_mode: true - }); - - before(function(done) { - Configuration.unset('pm2:passwd', function(err, data) { - createMockServer(function(err, _server) { - server = _server; - - pm2.connect(function(err, data) { - Helpers.startSomeApps(pm2, function(err, dt) { - done(); - }); - }); - }); - }); - }); - - after(function(done) { - listener_server.close(); - pm2.destroy(done); - }); - - describe('Interactor methods', function() { - it('should display info', function(done) { - pm2.interactInfos(function(err, meta) { - meta.should.have.properties([ - 'machine_name', - 'public_key', - 'secret_key', - 'socket_path', - 'pm2_home_monitored' - ]) - - meta.pm2_home_monitored.should.eql(pm2.pm2_home); - done(); - }); - }); - }); - - describe('Input command / Output data checks', function() { - it('should send ask, receive ask:rep and identify agent', function(done) { - server.once('ask:rep', function(pck) { - var data = Cipher.decipherMessage(pck.data, meta_connect.secret_key); - data.machine_name.should.eql(meta_connect.machine_name); - done(); - }); - - server.emit('cmd', { _type : 'ask' }); - }); - - it('should get status via PushInteractor and PM2 should be statused as not protected', function(done) { - sock.once('message', function(data) { - var dt = JSON.parse(data); - - dt.public_key.should.eql('osef'); - - var status = dt.data.status.data; - var procs = status.process; - var server = status.server; - - procs.length.should.eql(1); - - var meta = dt.data.status; - should.exists(dt.sent_at); - meta.protected.should.be.false(); - meta.rev_con.should.be.true(); - meta.server_name.should.eql('osef'); - done(); - }); - - it('should get status via PushInteractor and PM2 should be statused as not protected', function(done) { - sock.once('message', function(data) { - var dt = JSON.parse(data); - - dt.public_key.should.eql('osef'); - - var status = dt.data.status.data; - var procs = status.process; - var server = status.server; - - procs.length.should.eql(1); - - var meta = dt.data.status; - - should.exists(dt.sent_at); - meta.protected.should.be.false(); - meta.rev_con.should.be.true(); - meta.server_name.should.eql('osef'); - - done(); - }); - }); - }); - - describe('General behaviors', function() { - it('should receive event application restart', function(done) { - - sock.once('message', function(data) { - var dt = JSON.parse(data); - var monitoring = dt.data.monitoring; - var process_event = dt.data['process:event']; - - //console.log(JSON.stringify(process_event, '', 2)); - done(); - }); - - pm2.restart('all', function() {}); - }); - }); - - describe('PM2 password checking', function() { - it('should set a password', function(done) { - pm2.set('pm2:passwd', 'testpass', function(err, data) { - should.not.exists(err); - setTimeout(done, 1000); - }); - }); - - it('should interactor be notified of password set', function(done) { - sock.once('message', function(data) { - var dt = JSON.parse(data); - // Has switched to true - dt.data.status.protected.should.be.true(); - done(); - }); - }); - }); - - }); - - describe('Offline', function() { - it('should handle offline gracefully', function(done) { - _socket_list.forEach(function(socket, i) { - _socket_list[i].destroy(); - }); - - sock.closeSockets(); - - pub_sock.server.close(function() { - console.log('Server closed'); - }); - setTimeout(done, 500); - }); - }); - - -}); diff --git a/test/interface/monitor.mocha.js b/test/interface/monitor.mocha.js deleted file mode 100644 index 9baedf9c..00000000 --- a/test/interface/monitor.mocha.js +++ /dev/null @@ -1,90 +0,0 @@ -/* eslint-env mocha */ - -process.env.NODE_ENV='test'; - -'use strict'; - -var pm2 = require('../../index.js'); -var async = require('async'); -var assert = require('assert'); -var path = require('path'); -var PushInteractor = require('../../lib/Interactor/PushInteractor.js'); - -describe('unmonitor process', function () { - before(function (done) { - pm2.connect(function (err) { - if (err) return done(err); - pm2.delete('all', function () { - return done(); - }); - }); - }); - - after(function (done) { - pm2.delete('all', function (_) { - return done(); - }); - }); - - it('should start some processes', function (done) { - async.times(3, function (n, next) { - pm2.start({ - script: path.resolve(__dirname, '../fixtures/empty.js'), - name: 'test-' + n - }, next); - }, done); - }); - - it('should have 3 processes started', function (done) { - pm2.list(function (err, processes) { - assert(err === null); - assert(processes.length === 3); - return done(err); - }); - }); - - it('should start the push interactor', function (done) { - PushInteractor.start({ - url: 'toto', - conf: { - ipm2: require('../../lib/Interactor/pm2-interface.js')() - } - }); - return setTimeout(done, 100); - }); - - it('should return three processes with interactor', function (done) { - PushInteractor.preparePacket(function (err, data) { - if (err) return done(err); - - assert(data.process.length === 3); - return done(); - }); - }); - - it('should run the unmonitor command', function (done) { - pm2.monitorState('unmonitor', '0', done); - }); - - it('should return two processes with interactor', function (done) { - PushInteractor.preparePacket(function (err, data) { - if (err) return done(err); - - assert(data.process.length === 2); - return done(); - }); - }); - - it('should run the unmonitor command', function (done) { - pm2.monitorState('monitor', '0', done); - }); - - it('should return three processes with interactor', function (done) { - PushInteractor.preparePacket(function (err, data) { - if (err) return done(err); - - assert(data.process.length === 3); - return done(); - }); - }); -}); diff --git a/test/interface/password.mocha.js b/test/interface/password.mocha.js deleted file mode 100644 index 68772fd5..00000000 --- a/test/interface/password.mocha.js +++ /dev/null @@ -1,20 +0,0 @@ - -var Password = require('../../lib/Interactor/Password.js'); -var should = require('should'); - -describe('Password test', function() { - var crypted = ''; - - it('should crypt a password', function() { - crypted = Password.generate('testpass'); - }); - - it('should fail with wrong password', function() { - Password.verify('testpasds', crypted).should.be.false; - }); - - it('should success with right password', function() { - Password.verify('testpass', crypted).should.be.true; - }); - -}); diff --git a/test/interface/remote.mocha.js b/test/interface/remote.mocha.js deleted file mode 100644 index 87adbcd4..00000000 --- a/test/interface/remote.mocha.js +++ /dev/null @@ -1,225 +0,0 @@ - -process.env.NODE_ENV = 'local_test'; - -var PM2 = require('../..'); -var should = require('should'); -var nssocket = require('nssocket'); -var events = require('events'); -var util = require('util'); -var Cipher = require('../../lib/Interactor/Cipher.js'); -var cst = require('../../constants.js'); - -var send_cmd = new events.EventEmitter(); -var meta_connect = { - secret_key : 'test-secret-key', - public_key : 'test-public-key', - machine_name : 'test-machine-name' -}; - -function createMockServer(cb) { - var server = nssocket.createServer(function(_socket) { - - console.log('Got new connection in Mock server'); - - send_cmd.on('cmd', function(data) { - if (process.env.DEBUG) - console.log('Sending command %j', data); - _socket.send(data._type, data); - }); - - _socket.data('*', function(data) { - this.event.forEach(function(ev) { - send_cmd.emit(ev, data); - }); - }); - - }); - - server.on('error', function(e) { - throw new Error(e); - }); - - server.on('listening', function() { - cb(null, server); - }); - - server.listen(4322, '0.0.0.0'); -} - -function startSomeApps(pm2, cb) { - pm2.start('./child.js', {instances : 4, name : 'child'}, cb); -} - -describe('REMOTE PM2 ACTIONS', function() { - var server; - var interactor; - var pm2 = new PM2.custom({ - independent : true, - cwd : __dirname + '/../fixtures', - secret_key : 'test-secret-key', - public_key : 'test-public-key', - machine_name : 'test-machine-name', - daemon_mode: true - });; - - after(function(done) { - server.close(); - pm2.destroy(done); - }); - - before(function(done) { - createMockServer(function(err, _server) { - console.log('Mock server created'); - server = _server; - pm2.connect(function(err, _pm2) { - startSomeApps(pm2, function() { - done(); - }); - }); - }); - }); - - it('should send ask, receive ask:rep and identify agent', function(done) { - send_cmd.once('ask:rep', function(pck) { - var data = Cipher.decipherMessage(pck.data, meta_connect.secret_key); - data.machine_name.should.eql(meta_connect.machine_name); - done(); - }); - - send_cmd.emit('cmd', { _type : 'ask' }); - }); - - /** - * PM2 agent is now identified - */ - it('should act on PM2', function(done) { - send_cmd.once('trigger:pm2:result', function(pck) { - if (pck.ret.data.length > 0) - done(); - else - done(new Error('wrong data rcvied')); - }); - - send_cmd.emit('cmd', { - _type : 'trigger:pm2:action', - method_name : 'restart', - parameters : {name : 'child' } - }); - }); - - it('should act on PM2 but handle failure', function(done) { - send_cmd.once('trigger:pm2:result', function(pck) { - // Error is present telling process does not exists - pck.ret.err.should.not.be.null(); - done(); - }); - - send_cmd.emit('cmd', { - _type : 'trigger:pm2:action', - method_name : 'restart', - parameters : {name : 'UNKNOWN APP' } - }); - }); - - it('should RELOAD', function(done) { - send_cmd.once('trigger:pm2:result', function(pck) { - /** - * Once remote command is finished... - */ - - should(pck.ret.err).be.null(); - - pm2.list(function(err, ret) { - ret.forEach(function(proc) { - proc.pm2_env.restart_time.should.eql(2); - }); - }); - - done(); - }); - - send_cmd.emit('cmd', { - _type : 'trigger:pm2:action', - method_name : 'reload', - parameters : {name : 'child' } - }); - }); - - it('should RESET metadata', function(done) { - send_cmd.once('trigger:pm2:result', function(pck) { - /** - * Once remote command is finished... - */ - should(pck.ret.err).be.null(); - - pm2.list(function(err, ret) { - ret.forEach(function(proc) { - proc.pm2_env.restart_time.should.eql(0); - }); - }); - - done(); - }); - - send_cmd.emit('cmd', { - _type : 'trigger:pm2:action', - method_name : 'reset', - parameters : {name : 'child' } - }); - }); - - it('should delete all processes', function(done) { - pm2.delete('all', {}, function() { - startSomeApps(pm2, function() { - pm2.list(function(err, ret) { - ret.forEach(function(proc) { - proc.pm2_env.restart_time.should.eql(0); - }); - done(); - }); - }); - }); - }); - - it('should test .remote', function(done) { - pm2.remote('restart', { - name : 'child' - }, function(err, procs) { - - pm2.list(function(err, ret) { - ret.forEach(function(proc) { - proc.pm2_env.restart_time.should.eql(1); - }); - done(); - }); - }); - }); - - it('should test .remote and handle failure', function(done) { - pm2.remote('restart', { - name : 'UNKNOWN_NAME' - }, function(err, procs) { - pm2.list(function(err, ret) { - ret.forEach(function(proc) { - proc.pm2_env.restart_time.should.eql(1); - }); - done(); - }); - }); - }); - - it('should test .remote #2', function(done) { - pm2.remote('reload', { - name : 'child' - }, function(err, procs) { - - pm2.list(function(err, ret) { - ret.forEach(function(proc) { - proc.pm2_env.restart_time.should.eql(2); - }); - done(); - }); - }); - }); - -}); diff --git a/test/interface/request.mocha.js b/test/interface/request.mocha.js deleted file mode 100644 index eaeb9d0e..00000000 --- a/test/interface/request.mocha.js +++ /dev/null @@ -1,91 +0,0 @@ - -process.env.DEBUG="interface:*"; - -var should = require('should'); -var assert = require('assert'); -var HttpRequest = require('../../lib/Interactor/HttpRequest.js'); - -var PORT = 8080; - -function mockIrritableServer(cb) { - var http = require('http'); - var url = require('url'); - - function handleRequest(req, res) { - var uri = url.parse(req.url).pathname; - - if (uri == '/api/node/verifyPM2') { - // res.writeHead(505, {"Content-Type": "text/json"}); - // return res.end(new Buffer(50).fill('h')); - // } - // console.log(uri); - return false; - } - if (uri == '/api/misc/pm2_version') { - res.writeHead(505); - return res.end(); - } - } - - //Create a server - var server = http.createServer(handleRequest); - - //Lets start our server - server.listen(PORT, function(err){ - if (err) console.error(err); - cb(null, server); - }); -} - -describe('Http requests', function() { - var _server = null; - - before(function(done) { - mockIrritableServer(function(err, server) { - _server = server; - done(); - }); - }); - - after(function(done) { - _server.close(done); - }); - - describe('POST', function() { - it('should post to 404 URL', function(done) { - HttpRequest.post({ - port : 9999, - url : 'http://keymetrics.io/NOTHING', - data : { no : 'thing' } - }, function(err, data) { - assert(err); - assert(err.code == 'ENOTFOUND'); - assert(data == null); - done(); - }) - }); - - it('should timeout after 7secs', function(done) { - HttpRequest.post({ - port : PORT, - url : '127.0.0.1', - data : { no : 'thing' } - }, function(err, data) { - assert(err); - assert(err.code == 'ECONNRESET'); - assert(data == null); - done(); - }); - }); - - }); - - // @todo: more behavioral tests (reverse interactor failcheck) - - // @todo: do more tests when doing changeUrls - it.skip('should change urls (forcing reconnection)', function(done) { - InterfaceD.changeUrls('app.km.io', 'app.km.io:4322'); - setTimeout(done, 2000); - }); - -}); diff --git a/test/interface/scoped_pm2_actions.mocha.js b/test/interface/scoped_pm2_actions.mocha.js deleted file mode 100644 index ecf837cc..00000000 --- a/test/interface/scoped_pm2_actions.mocha.js +++ /dev/null @@ -1,258 +0,0 @@ - -var PM2 = require('../..'); -var should = require('should'); -var nssocket = require('nssocket'); -var events = require('events'); -var util = require('util'); -var Cipher = require('../../lib/Interactor/Cipher.js'); -var cst = require('../../constants.js'); -var Plan = require('../helpers/plan.js'); -var Configuration = require('../../lib/Configuration.js'); -var Helpers = require('../helpers/apps.js'); -var Interactor = require('../../lib/Interactor/InteractorDaemonizer.js'); -var gl_interactor_process; - -var send_cmd = new events.EventEmitter(); - -process.env.NODE_ENV = 'local_test'; - -var meta_connect = { - secret_key : 'test-secret-key', - public_key : 'test-public-key', - machine_name : 'test-machine-name' -}; - -/** - * Description - * @method forkInteractor - * @return CallExpression - */ -function forkInteractor(cb) { - Interactor.launchAndInteract(meta_connect, function(err, data, interactor_process) { - gl_interactor_process = interactor_process; - cb(); - }); -} - -/** - * Mock server receiving data - * @method forkInteractor - * @return CallExpression - */ -function createMockServer(cb) { - var server = nssocket.createServer(function(_socket) { - - send_cmd.on('cmd', function(data) { - if (process.env.DEBUG) - console.log('Sending command %j', data); - _socket.send(data._type, data); - }); - - _socket.data('*', function(data) { - this.event.forEach(function(ev) { - send_cmd.emit(ev, data); - }); - }); - - }); - - server.on('error', function(e) { - throw new Error(e); - }); - - server.on('listening', function() { - cb(null, server); - }); - - server.listen(4322, '0.0.0.0'); -} - -function startSomeApps(cb) { - pm2.start('./child.js', {instances : 1, name : 'child'}, cb); -} - -var pm2 = new PM2.custom({ - independent : true, - cwd : __dirname + '/../fixtures', - secret_key : 'test-secret-key', - public_key : 'test-public-key', - machine_name : 'test-machine-name', - daemon_mode: true -}); - -describe('SCOPED PM2 ACTIONS', function() { - var server; - var interactor; - - after(function(done) { - server.close(); - pm2.destroy(done); - }); - - before(function(done) { - createMockServer(function(err, _server) { - server = _server; - pm2.connect(function() { - startSomeApps(function(err) { - gl_interactor_process = pm2.Client.interactor_process; - // @todo: would be nice to know when an app is ready - // @priotity: minor - setTimeout(done, 1500); - }); - }); - }); - }); - - it('should send ask, receive ask:rep and identify agent', function(done) { - send_cmd.once('ask:rep', function(pck) { - var data = Cipher.decipherMessage(pck.data, meta_connect.secret_key); - data.machine_name.should.eql(meta_connect.machine_name); - done(); - }); - - send_cmd.emit('cmd', { _type : 'ask' }); - }); - - /** - * PM2 agent is now identified - */ - describe('Test non auth remote commands', function() { - before(function(done) { - Configuration.unset('pm2:passwd', function(err, data) { - should.not.exists(err); - done(); - }); - }); - - it('should restart command via scoped pm2 action (no pass needed)', function(done) { - var good = false; - var plan = new Plan(2, function() { - gl_interactor_process.removeListener('message', actionCheck); - good = true; - done(); - }); - - function actionCheck(pck) { - if (good) return false; - if (pck.event == 'pm2:scoped:stream' && pck.data.out === 'Action restart received') - return plan.ok(true); - if (pck.event == 'pm2:scoped:end') - return plan.ok(true); - if (pck.event == 'pm2:scoped:error') - return plan.ok(false, pck); - return false; - } - - gl_interactor_process.on('message', actionCheck); - - send_cmd.emit('cmd', { - _type : 'trigger:pm2:scoped:action', - action_name : 'restart', - uuid : '1234', - options : { args : ['child'] } - }); - - }); - - }); - - describe('Password verification', function() { - - before(function(done) { - Configuration.unset('pm2:passwd', function(err, data) { - should.not.exists(err); - done(); - }); - }); - - it('should error when call an action that is password protected', function(done) { - function actionCheck(pck) { - if (pck.event == 'pm2:scoped:error' && pck.data.out.indexOf('Missing password') > -1) { - gl_interactor_process.removeListener('message', actionCheck); - done(); - } - }; - - gl_interactor_process.on('message', actionCheck); - - send_cmd.emit('cmd', { - _type : 'trigger:pm2:scoped:action', - action_name : 'install', - uuid : '5678', - options : { args : ['child'] } - }); - }); - - it('should fail when password passed but no pm2 password configured', function(done) { - function actionCheck(pck) { - if (pck.event == 'pm2:scoped:error' && pck.data.out.indexOf('Password at PM2') > -1) { - gl_interactor_process.removeListener('message', actionCheck); - done(); - } - }; - - gl_interactor_process.on('message', actionCheck); - - send_cmd.emit('cmd', { - _type : 'trigger:pm2:scoped:action', - action_name : 'install', - uuid : '5678', - password : 'random-pass', - options : { args : ['pm2-module'] } - }); - }); - - it('should set a password', function(done) { - pm2.set('pm2:passwd', 'testpass', function(err, data) { - should.not.exists(err); - done(); - }); - }); - - it('should fail when wrong password', function(done) { - function actionCheck(pck) { - if (pck.event == 'pm2:scoped:error' && pck.data.out.indexOf('Password does not match') > -1) { - gl_interactor_process.removeListener('message', actionCheck); - setTimeout(done, 100); - } - }; - - gl_interactor_process.on('message', actionCheck); - - send_cmd.emit('cmd', { - _type : 'trigger:pm2:scoped:action', - action_name : 'install', - uuid : '5678', - password : 'random-pass', - options : { args : ['pm2-module'] } - }); - }); - - it('should work when good password passed', function(done) { - function actionCheck(pck) { - if (pck.event === 'pm2:scoped:end') { - gl_interactor_process.removeListener('message', actionCheck); - done(); - } - if (pck.event === 'pm2:scoped:error') { - gl_interactor_process.removeListener('message', actionCheck); - done('{ERROR} Wrong password!' + JSON.stringify(pck)); - } - }; - - gl_interactor_process.on('message', actionCheck); - - send_cmd.emit('cmd', { - _type : 'trigger:pm2:scoped:action', - action_name : 'ping', - uuid : '5678', - password : 'testpass', - options : {} - }); - }); - - - }); - - -}); diff --git a/test/interface/stacktrace.mocha.js b/test/interface/stacktrace.mocha.js deleted file mode 100644 index 630f844b..00000000 --- a/test/interface/stacktrace.mocha.js +++ /dev/null @@ -1,157 +0,0 @@ - -var should = require('should'); -var Aggregator = require('../../lib/Interactor/TransactionAggregator.js'); -var Utility = require('../../lib/Interactor/Utility.js'); -var TraceFactory = require('./misc/trace_factory.js'); -var path = require('path'); -var fs = require('fs'); -var assert = require('assert'); - -describe('StackTrace Utility', function() { - var aggregator; - var stackParser; - - it('should instanciate context cache', function() { - var cache = new Utility.Cache({ - miss: function (key) { - try { - var content = fs.readFileSync(path.resolve(key)); - return content.toString().split(/\r?\n/); - } catch (err) { - return undefined; - } - } - }) - - stackParser = new Utility.StackTraceParser({ cache: cache, context: 2}); - }); - - it('should instanciate aggregator', function() { - aggregator = new Aggregator({ stackParser: stackParser}); - }); - - describe('.parse', function() { - it('should parse stacktrace and get context', function(done) { - var obj = [{ - labels: { - stacktrace: JSON.stringify(TraceFactory.stacktrace) - } - }]; - - aggregator.parseStacktrace(obj); - obj[0].labels['source/file'].indexOf('test/interface/misc/trace_factory.js:10').should.be.above(0); - should(obj[0].labels['source/context']).eql("var random_routes = [\n '/api/bucket',\n>>'/api/bucket/users',\n '/api/bucket/chameau',\n '/backo/testo'"); - done(); - }); - - it('should handle malformated stacktraces', function() { - aggregator.parseStacktrace([{ - labels: { - stacktrace: JSON.stringify({ - stack_frame: [{ - line_number: 10, - column_number: 10, - method_name: '' - }, { - file_name: 'node_modules/express.js', - column_number: 10, - method_name: '' - }, { - file_name: path.resolve(__dirname, 'trace_factory.js'), - line_number: 10, - column_number: 10, - method_name: '' - }] - }) - } - }]); - }); - - it('should handle malformated stacktrace v1', function() { - aggregator.parseStacktrace([{ - labels: { - stacktrace: JSON.stringify({ - stack_frame: [{ - file_name: 'events.js' - },{ - file_name: 'node_modules/express.js' - },{ - file_name: path.resolve(__dirname, 'trace_factory.js') - }] - }) - } - }]); - }); - - it('should handle malformated stacktrace v2', function() { - aggregator.parseStacktrace([{ - labels: { - stacktrace: JSON.stringify({ - stack_frame: [{ - file_name: 'events.js', - column_number: 10, - method_name: '' - },{ - file_name: 'node_modules/express.js', - column_number: 10, - method_name: '' - },{ - file_name: path.resolve(__dirname, 'trace_factory.js'), - line_number: 10, - column_number: 10, - method_name: '' - }] - }) - } - }]); - }); - - it('should handle malformated stacktrace v3', function() { - aggregator.parseStacktrace([{ - labels: {} - }]); - }); - - it('should handle malformated stacktrace v4', function() { - aggregator.parseStacktrace([{ - }]); - }); - - it('should handle malformated stacktrace v5', function() { - aggregator.parseStacktrace([]); - }); - - it('should handle malformated stacktrace v5', function() { - aggregator.parseStacktrace(); - }); - - }); - - describe('.attachContext', function () { - it('should extract context from stackframes', function () { - var error = stackParser.attachContext({ - stackframes: [ - { - file_name: '/toto/tmp/lol', - line_number: 10 - } - ] - }); - assert(error !== undefined); - assert(error.stackframes === undefined); - assert(error.callsite !== undefined); - assert(error.callsite.indexOf('/toto/tmp/lol') >= 0); - }); - - it('should extract context from the stack string', function () { - var error = new Error(); - // stack is lazy so we need to load it - error.stack = error.stack; - error = stackParser.attachContext(error); - assert(error !== undefined); - assert(error.stackframes === undefined); - assert(error.callsite.indexOf(__filename) >= 0); - assert(error.context.indexOf('var error = new Error()') >= 0); - }); - }); -}); diff --git a/test/unit.sh b/test/unit.sh index 03b18425..b28eb6d3 100644 --- a/test/unit.sh +++ b/test/unit.sh @@ -95,37 +95,13 @@ cd ../interface # echo $PM2_HOME -mocha --opts ./mocha.opts ./exception.e2e.mocha.js -spec "E2E exception system checking" -mocha --opts ./mocha.opts ./interactor.connect.mocha.js -spec "Interactor test #1 with password setting" mocha --opts ./mocha.opts ./interactor.daemonizer.mocha.js spec "Remote interactor keys save verification" -mocha --opts ./mocha.opts ./scoped_pm2_actions.mocha.js -spec "Scoped PM2 Remote interactions test" -mocha --opts ./mocha.opts ./remote.mocha.js -spec "Remote interactions test" -mocha --opts ./mocha.opts ./password.mocha.js -spec "Password library checking" -mocha --opts ./mocha.opts ./custom-actions.mocha.js -spec "Custom actions test" mocha --opts ./mocha.opts ./bus.spec.mocha.js spec "Protocol communication test" mocha --opts ./mocha.opts ./bus.fork.spec.mocha.js spec "Protocol communication test" -mocha --opts ./mocha.opts ./request.mocha.js -spec "Protocol communication test" -mocha --opts ./mocha.opts ./aggregator.mocha.js -spec "Transaction trace aggregator test" -mocha --opts ./mocha.opts ./stacktrace.mocha.js -spec "Stacktrace Utility" -mocha --opts ./mocha.opts ./cache.mocha.js -spec "Cache Utility" -mocha --opts ./mocha.opts ./filter.mocha.js -spec "Filter Utility" mocha --opts ./mocha.opts ./utility.mocha.js spec "PM2 Utility" mocha --opts ./mocha.opts ./pm2.link.check.mocha.js spec "Transaction option enablement" -mocha --opts ./mocha.opts ./monitor.mocha.js -spec "Monitor / Unmonitor commands" From 4bc2eb4c9a8179b9ae38438e98ce7650a91b64db Mon Sep 17 00:00:00 2001 From: Unitech Date: Mon, 26 Mar 2018 14:25:55 +0200 Subject: [PATCH 072/140] chore: upgrade PM2 to 3.0 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index a92c27bd..b6a239a6 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "pm2", "preferGlobal": true, - "version": "2.10.1", + "version": "3.0.0", "engines": { "node": ">=4.0.0" }, From 830fc15fad1aee95e65b2681482b03369f1f97d7 Mon Sep 17 00:00:00 2001 From: Unitech Date: Tue, 27 Mar 2018 11:10:03 +0200 Subject: [PATCH 073/140] chore: remove unused dependency --- package.json | 1 - 1 file changed, 1 deletion(-) diff --git a/package.json b/package.json index 4f56e89b..125e94a1 100644 --- a/package.json +++ b/package.json @@ -163,7 +163,6 @@ "chalk": "^2.3.1", "chokidar": "^2.0.2", "cli-table-redemption": "^1.0.0", - "coffee-script": "^1.12.7", "commander": "2.14.1", "cron": "^1.3", "debug": "^3.0", From 03e6b59f71c2e07d5b8d758400e5abf752ea3f90 Mon Sep 17 00:00:00 2001 From: vmarchaud Date: Tue, 27 Mar 2018 14:33:40 +0200 Subject: [PATCH 074/140] deps: update keymetrics-agent to latest --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 125e94a1..2f94e034 100644 --- a/package.json +++ b/package.json @@ -169,7 +169,7 @@ "eventemitter2": "5.0.1", "fclone": "1.0.11", "fs-extra": "^5.0.0", - "keymetrics-agent": "^0.3.0", + "keymetrics-agent": "^0.3.2", "mkdirp": "0.5.1", "moment": "^2.19", "needle": "^2.2.0", From 5290218626af815f6cae8173bc78d21881a4dda8 Mon Sep 17 00:00:00 2001 From: vmarchaud Date: Thu, 29 Mar 2018 11:01:17 +0200 Subject: [PATCH 075/140] chore: use npm install for CI as yarn has issue with npm --- .travis.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.travis.yml b/.travis.yml index 320d304d..3d36d45e 100644 --- a/.travis.yml +++ b/.travis.yml @@ -13,3 +13,5 @@ before_install: - sudo apt-get install php5-cli services: - docker +install: + - npm install From c4c811e76e823291d5a75628df032702364c957e Mon Sep 17 00:00:00 2001 From: ngtmuzi Date: Mon, 2 Apr 2018 16:41:43 +0800 Subject: [PATCH 076/140] fix the bug: process with "restart-delay" can't restart when manually stop --- lib/God/ActionMethods.js | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/lib/God/ActionMethods.js b/lib/God/ActionMethods.js index 092b7df3..d4dba58e 100644 --- a/lib/God/ActionMethods.js +++ b/lib/God/ActionMethods.js @@ -290,17 +290,19 @@ module.exports = function(God) { if (!(id in God.clusters_db)) return cb(God.logAndGenerateError(id + ' : id unknown'), {}); - //clear time-out restart task - clearTimeout(God.clusters_db[id].pm2_env.restart_task); - - if (God.clusters_db[id].pm2_env.status == cst.STOPPED_STATUS) - return cb(null, God.getFormatedProcess(id)); - // state == 'none' means that the process is not online yet - if (God.clusters_db[id].state && God.clusters_db[id].state === 'none') - return setTimeout(function() { God.stopProcessId(id, cb); }, 250); - var proc = God.clusters_db[id]; + //clear time-out restart task + clearTimeout(proc.pm2_env.restart_task); + + if (proc.pm2_env.status == cst.STOPPED_STATUS) { + proc.process.pid = 0; + return cb(null, God.getFormatedProcess(id)); + } + // state == 'none' means that the process is not online yet + if (proc.state && proc.state === 'none') + return setTimeout(function() { God.stopProcessId(id, cb); }, 250); + console.log('Stopping app:%s id:%s', proc.pm2_env.name, proc.pm2_env.pm_id); proc.pm2_env.status = cst.STOPPING_STATUS; From 85a5ee0f1fd16da9635fb4b16ddcd8d53aca8224 Mon Sep 17 00:00:00 2001 From: vmarchaud Date: Wed, 11 Apr 2018 15:03:33 +0200 Subject: [PATCH 077/140] chore: add unique id for each process --- lib/God.js | 3 ++ lib/God/ActionMethods.js | 5 ++ lib/Utility.js | 12 +++++ test/programmatic/id.mocha.js | 94 +++++++++++++++++++++++++++++++++++ 4 files changed, 114 insertions(+) create mode 100644 test/programmatic/id.mocha.js diff --git a/lib/God.js b/lib/God.js index 3e4c1d54..2067ec31 100644 --- a/lib/God.js +++ b/lib/God.js @@ -381,6 +381,9 @@ God.handleExit = function handleExit(clu, exit_code, kill_signal) { * Init new process */ God.prepare = function prepare (env, cb) { + // generate a new unique id for each processes + env.env.unique_id = Utility.generateUUID() + // if the app is standalone, no multiple instance if (typeof env.instances === 'undefined') { env.vizion_running = false; diff --git a/lib/God/ActionMethods.js b/lib/God/ActionMethods.js index d4dba58e..1b105bfe 100644 --- a/lib/God/ActionMethods.js +++ b/lib/God/ActionMethods.js @@ -239,8 +239,13 @@ module.exports = function(God) { var proc = Utility.clone(God.clusters_db[id].pm2_env); + delete proc.created_at; delete proc.pm_id; + delete proc.unique_id; + + // generate a new unique id for new process + proc.unique_id = Utility.generateUUID() God.injectVariables(proc, function inject (_err, proc) { return God.executeApp(Utility.clone(proc), function (err, clu) { diff --git a/lib/Utility.js b/lib/Utility.js index 71f65b03..f172dc81 100644 --- a/lib/Utility.js +++ b/lib/Utility.js @@ -247,6 +247,18 @@ var Utility = module.exports = { checkPathIsNull: function(path) { return path === 'NULL' || path === '/dev/null'; + }, + + generateUUID: function () { + var s = []; + var hexDigits = "0123456789abcdef"; + for (var i = 0; i < 36; i++) { + s[i] = hexDigits.substr(Math.floor(Math.random() * 0x10), 1); + } + s[14] = "4"; + s[19] = hexDigits.substr((s[19] & 0x3) | 0x8, 1); + s[8] = s[13] = s[18] = s[23] = "-"; + return s.join(""); } }; diff --git a/test/programmatic/id.mocha.js b/test/programmatic/id.mocha.js new file mode 100644 index 00000000..40a89308 --- /dev/null +++ b/test/programmatic/id.mocha.js @@ -0,0 +1,94 @@ + +process.chdir(__dirname); + +var PM2 = require('../..'); +var should = require('should'); +var assert = require('assert') + +describe('Unique ID verification', function() { + describe('when starting', function() { + var _id = null + + before(function(done) { + PM2.kill(done); + }); + + before(function(done) { + PM2.delete('all', function() { done() }); + }); + + it('should connect to PM2', function(done) { + PM2.connect(done); + }); + + it('should start a script', function(done) { + PM2.start('../fixtures/child.js', function(err) { + should(err).be.null(); + PM2.list(function(err, list) { + should(err).be.null(); + assert(list.length > 0) + assert(typeof list[0].pm2_env.unique_id === 'string') + _id = list[0].pm2_env.unique_id + done(); + }); + }); + }); + + it('should stop app by id', function(done) { + PM2.stop(0, done); + }); + + it('should restart and not changed unique id', function(done) { + PM2.restart(0, (err) => { + should(err).be.null(); + PM2.list(function(err, list) { + should(err).be.null(); + assert(list.length > 0) + assert(typeof list[0].pm2_env.unique_id === 'string') + assert( list[0].pm2_env.unique_id === _id) + done(); + }); + }); + }); + + + it('should generate another unique id for new process', function(done) { + PM2.start('./../fixtures/child.js', { name: 'toto' }, function(err) { + assert(!err); + PM2.list(function(err, list) { + should(err).be.null(); + assert(list.length === 2) + assert(typeof list[0].pm2_env.unique_id === 'string') + assert(typeof list[1].pm2_env.unique_id === 'string') + assert(list[0].pm2_env.unique_id !== typeof list[1].pm2_env.unique_id) + done(); + }); + }); + }); + + it('should duplicate a process and have a new id', function(done) { + PM2.scale('child', 2, function(err) { + assert(!err); + PM2.list(function(err, list) { + should(err).be.null(); + should(list.length).eql(3); + assert(typeof list[0].pm2_env.unique_id === 'string') + assert(typeof list[1].pm2_env.unique_id === 'string') + assert(typeof list[2].pm2_env.unique_id === 'string') + assert(list[0].pm2_env.unique_id !== typeof list[1].pm2_env.unique_id) + assert(list[1].pm2_env.unique_id !== typeof list[2].pm2_env.unique_id) + assert(list[0].pm2_env.unique_id !== typeof list[2].pm2_env.unique_id) + done(); + }); + }); + }); + + after(function(done) { + PM2.delete('all', done); + }); + + after(function(done) { + PM2.kill(done); + }); + }); +}); From 746f6013f328daf215d910bbed09f62ebd5bb1d3 Mon Sep 17 00:00:00 2001 From: vmarchaud Date: Wed, 11 Apr 2018 15:17:22 +0200 Subject: [PATCH 078/140] tests: add new test for CI --- test/unit.sh | 2 ++ 1 file changed, 2 insertions(+) diff --git a/test/unit.sh b/test/unit.sh index 425f3d96..c7ead325 100644 --- a/test/unit.sh +++ b/test/unit.sh @@ -87,6 +87,8 @@ mocha --opts ./mocha.opts ./env_switching.js spec "JSON environment switching on JSON restart with --env" mocha --opts ./mocha.opts ./configuration.mocha.js spec "Configuration system working" +mocha --opts ./mocha.opts ./id.mocha.js +spec "Uniqueness id for each process" # # Interface testing From 3ec178e577e79730aae02c913301cd905ea8ce52 Mon Sep 17 00:00:00 2001 From: Unitech Date: Thu, 26 Apr 2018 23:17:04 +0200 Subject: [PATCH 079/140] fix: version --- package.json | 1 - 1 file changed, 1 deletion(-) diff --git a/package.json b/package.json index cc083ed1..fc8de45d 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,6 @@ "name": "pm2", "preferGlobal": true, "version": "3.0.0", - "version": "2.10.2", "engines": { "node": ">=4.0.0" }, From 3274132b866ba5c93d5786e755acbada922f5f1e Mon Sep 17 00:00:00 2001 From: Unitech Date: Fri, 27 Apr 2018 09:50:42 +0200 Subject: [PATCH 080/140] fix: do not run two pm2 para cmds --- test/programmatic/id.mocha.js | 4 ---- 1 file changed, 4 deletions(-) diff --git a/test/programmatic/id.mocha.js b/test/programmatic/id.mocha.js index 40a89308..f792e7ef 100644 --- a/test/programmatic/id.mocha.js +++ b/test/programmatic/id.mocha.js @@ -13,10 +13,6 @@ describe('Unique ID verification', function() { PM2.kill(done); }); - before(function(done) { - PM2.delete('all', function() { done() }); - }); - it('should connect to PM2', function(done) { PM2.connect(done); }); From e0840c7aaae1594ca607db5121de4fda66d3ee69 Mon Sep 17 00:00:00 2001 From: vmarchaud Date: Fri, 27 Apr 2018 16:27:10 +0200 Subject: [PATCH 081/140] deps: bump keymetrics-agent to 0.3.5 --- package.json | 2 +- yarn.lock | 72 ++++++++++++++-------------------------------------- 2 files changed, 20 insertions(+), 54 deletions(-) diff --git a/package.json b/package.json index fc8de45d..b9667650 100644 --- a/package.json +++ b/package.json @@ -169,7 +169,7 @@ "eventemitter2": "5.0.1", "fclone": "1.0.11", "fs-extra": "^5.0.0", - "keymetrics-agent": "^0.3.2", + "keymetrics-agent": "^0.3.5", "mkdirp": "0.5.1", "moment": "^2.19", "needle": "^2.2.0", diff --git a/yarn.lock b/yarn.lock index bb7e72c2..bd57721f 100644 --- a/yarn.lock +++ b/yarn.lock @@ -61,10 +61,6 @@ argparse@^1.0.7: dependencies: sprintf-js "~1.0.2" -argv@0.0.2: - version "0.0.2" - resolved "https://registry.yarnpkg.com/argv/-/argv-0.0.2.tgz#ecbd16f8949b157183711b1bda334f37840185ab" - arr-diff@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/arr-diff/-/arr-diff-4.0.0.tgz#d6461074febfec71e7e15235761a329a5dc7c520" @@ -236,7 +232,7 @@ chalk@^1.1.3: strip-ansi "^3.0.0" supports-color "^2.0.0" -chalk@^2.3.1, chalk@^2.3.2: +chalk@^2.3.1: version "2.3.2" resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.3.2.tgz#250dc96b07491bfd601e648d66ddf5f60c7a5c65" dependencies: @@ -289,18 +285,6 @@ code-point-at@^1.0.0: version "1.1.0" resolved "https://registry.yarnpkg.com/code-point-at/-/code-point-at-1.1.0.tgz#0d070b4d043a5bea33a2f1a40e2edb3d9a4ccf77" -codecov@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/codecov/-/codecov-3.0.0.tgz#c273b8c4f12945723e8dc9d25803d89343e5f28e" - dependencies: - argv "0.0.2" - request "2.81.0" - urlgrey "0.4.4" - -coffee-script@^1.12.7: - version "1.12.7" - resolved "https://registry.yarnpkg.com/coffee-script/-/coffee-script-1.12.7.tgz#c05dae0cb79591d05b3070a8433a98c9a89ccc53" - collection-visit@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/collection-visit/-/collection-visit-1.0.0.tgz#4bc0373c164bc3291b4d368c829cf1a80a59dca0" @@ -379,12 +363,6 @@ dashdash@^1.12.0: dependencies: assert-plus "^1.0.0" -debug@*, debug@^3, debug@^3.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/debug/-/debug-3.1.0.tgz#5bb5a0672628b64149566ba16819e61518c67261" - dependencies: - ms "2.0.0" - debug@2.6.8: version "2.6.8" resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.8.tgz#e731531ca2ede27d188222427da17821d68ff4fc" @@ -397,6 +375,12 @@ debug@^2.1.2, debug@^2.2.0, debug@^2.3.3, debug@^2.6.3: dependencies: ms "2.0.0" +debug@^3, debug@^3.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/debug/-/debug-3.1.0.tgz#5bb5a0672628b64149566ba16819e61518c67261" + dependencies: + ms "2.0.0" + debug@~2.2.0: version "2.2.0" resolved "https://registry.yarnpkg.com/debug/-/debug-2.2.0.tgz#f87057e995b1a1f6ae6a4960664137bc56f039da" @@ -530,14 +514,10 @@ extsprintf@^1.2.0: version "1.4.0" resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.4.0.tgz#e2689f8f356fad62cca65a3a91c5df5f9551692f" -fclone@1.0.11, fclone@^1, fclone@^1.0.11: +fclone@1.0.11, fclone@^1.0.11: version "1.0.11" resolved "https://registry.yarnpkg.com/fclone/-/fclone-1.0.11.tgz#10e85da38bfea7fc599341c296ee1d77266ee640" -fclone@1.0.8: - version "1.0.8" - resolved "https://registry.yarnpkg.com/fclone/-/fclone-1.0.8.tgz#a0d4a73d983249978c0e0671a161520b996467eb" - fill-range@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-4.0.0.tgz#d544811d428f98eb06a63dc402d2403c328c38f7" @@ -956,21 +936,19 @@ jsprim@^1.2.2: json-schema "0.2.3" verror "1.10.0" -keymetrics-agent@^0.3.0: - version "0.3.0" - resolved "https://registry.yarnpkg.com/keymetrics-agent/-/keymetrics-agent-0.3.0.tgz#324ebb9c9dbd3b40770284d55c73bf24674993d0" +keymetrics-agent@^0.3.5: + version "0.3.5" + resolved "https://registry.yarnpkg.com/keymetrics-agent/-/keymetrics-agent-0.3.5.tgz#183ad8313a620e10eed6c98ce18e6af0e386efeb" dependencies: async "^2.6.0" - chalk "^2.3.2" - codecov "^3.0.0" eventemitter2 "^5.0.1" fclone "^1.0.11" handy-http "^1.0.2" moment "^2.21.0" nssocket "^0.6.0" pm2-axon "3.0.2" - pm2-axon-rpc "0.4.5" - ws "^5.0.0" + pm2-axon-rpc "^0.5.0" + ws "^5.1.0" kind-of@^3.0.2, kind-of@^3.0.3, kind-of@^3.2.0: version "3.2.2" @@ -1318,19 +1296,11 @@ pidusage@^2.0.6: version "2.0.6" resolved "https://registry.yarnpkg.com/pidusage/-/pidusage-2.0.6.tgz#32bc37e57ca828f46b1c1e679a9cfc56ef945850" -pm2-axon-rpc@0.4.5: - version "0.4.5" - resolved "https://registry.yarnpkg.com/pm2-axon-rpc/-/pm2-axon-rpc-0.4.5.tgz#fb62e9a53f3e2b7bed1afe16e3b0d1b06fe8ba69" - dependencies: - debug "*" - fclone "1.0.8" - -pm2-axon-rpc@0.5.0: - version "0.5.0" - resolved "https://registry.yarnpkg.com/pm2-axon-rpc/-/pm2-axon-rpc-0.5.0.tgz#ad08d6a27f580d5c7be4d7bf9dddff398f868994" +pm2-axon-rpc@^0.5.0, pm2-axon-rpc@^0.5.1: + version "0.5.1" + resolved "https://registry.yarnpkg.com/pm2-axon-rpc/-/pm2-axon-rpc-0.5.1.tgz#ad3c43c43811c71f13e5eee2821194d03ceb03fe" dependencies: debug "^3.0" - fclone "^1" pm2-axon@3.0.2: version "3.0.2" @@ -1836,10 +1806,6 @@ urix@^0.1.0: version "0.1.0" resolved "https://registry.yarnpkg.com/urix/-/urix-0.1.0.tgz#da937f7a62e21fec1fd18d49b35c2935067a6c72" -urlgrey@0.4.4: - version "0.4.4" - resolved "https://registry.yarnpkg.com/urlgrey/-/urlgrey-0.4.4.tgz#892fe95960805e85519f1cd4389f2cb4cbb7652f" - use@^3.1.0: version "3.1.0" resolved "https://registry.yarnpkg.com/use/-/use-3.1.0.tgz#14716bf03fdfefd03040aef58d8b4b85f3a7c544" @@ -1898,9 +1864,9 @@ wrappy@1: version "1.0.2" resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" -ws@^5.0.0: - version "5.1.0" - resolved "https://registry.yarnpkg.com/ws/-/ws-5.1.0.tgz#ad7f95a65c625d47c24f2b8e5928018cf965e2a6" +ws@^5.1.0: + version "5.1.1" + resolved "https://registry.yarnpkg.com/ws/-/ws-5.1.1.tgz#1d43704689711ac1942fd2f283e38f825c4b8b95" dependencies: async-limiter "~1.0.0" From 928f41c7ada559bc18816744e3e125c94824ece5 Mon Sep 17 00:00:00 2001 From: vmarchaud Date: Mon, 30 Apr 2018 15:38:19 +0200 Subject: [PATCH 082/140] deps: use @keymetrics/pmx insteadof pmx --- lib/ProcessUtils.js | 2 +- package.json | 2 +- yarn.lock | 38 +++++++++++++++++++++++++++++++++----- 3 files changed, 35 insertions(+), 7 deletions(-) diff --git a/lib/ProcessUtils.js b/lib/ProcessUtils.js index 5d32750b..75218823 100644 --- a/lib/ProcessUtils.js +++ b/lib/ProcessUtils.js @@ -1,7 +1,7 @@ module.exports = { injectModules: function() { if (process.env.pmx !== 'false') { - const pmx = require('pmx'); + const pmx = require('@keymetrics/pmx'); pmx.init({ transactions: (process.env.trace === 'true' || process.env.deep_monitoring === 'true') || false, http: process.env.km_link === 'true' || false, diff --git a/package.json b/package.json index b9667650..8a804521 100644 --- a/package.json +++ b/package.json @@ -158,6 +158,7 @@ "pm2-runtime": "./bin/pm2-runtime" }, "dependencies": { + "@keymetrics/pmx": "^2.0.0-alpha9", "async": "^2.5", "blessed": "^0.1.81", "chalk": "^2.3.1", @@ -179,7 +180,6 @@ "pm2-axon-rpc": "^0.5.1", "pm2-deploy": "^0.3.9", "pm2-multimeter": "^0.1.2", - "pmx": "^1.6", "promptly": "2.2.0", "semver": "^5.3", "shelljs": "0.8.1", diff --git a/yarn.lock b/yarn.lock index bd57721f..998250f9 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2,6 +2,20 @@ # yarn lockfile v1 +"@keymetrics/pmx@^2.0.0-alpha9": + version "2.0.0-alpha9" + resolved "https://registry.yarnpkg.com/@keymetrics/pmx/-/pmx-2.0.0-alpha9.tgz#1d29eaae08a6cdfc4ea4c2ac0501c50370f0c12b" + dependencies: + async "^2.6.0" + debug "^3.1.0" + deep-metrics "0.0.2" + deepmerge "^2.1.0" + json-stringify-safe "^5.0.1" + semver "^5.5.0" + signal-exit "^3.0.2" + tslib "^1.6.0" + vxx "^1.2.2" + abbrev@1: version "1.1.1" resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-1.1.1.tgz#f8f2c887ad10bf67f634f005b6987fed3179aac8" @@ -375,7 +389,7 @@ debug@^2.1.2, debug@^2.2.0, debug@^2.3.3, debug@^2.6.3: dependencies: ms "2.0.0" -debug@^3, debug@^3.0: +debug@^3, debug@^3.0, debug@^3.1.0: version "3.1.0" resolved "https://registry.yarnpkg.com/debug/-/debug-3.1.0.tgz#5bb5a0672628b64149566ba16819e61518c67261" dependencies: @@ -395,12 +409,22 @@ deep-extend@~0.4.0: version "0.4.2" resolved "https://registry.yarnpkg.com/deep-extend/-/deep-extend-0.4.2.tgz#48b699c27e334bf89f10892be432f6e4c7d34a7f" +deep-metrics@0.0.2: + version "0.0.2" + resolved "https://registry.yarnpkg.com/deep-metrics/-/deep-metrics-0.0.2.tgz#180900dea82a2c4b976be2b7684914748f5a0931" + dependencies: + semver "^5.3.0" + deep-metrics@^0.0.1: version "0.0.1" resolved "https://registry.yarnpkg.com/deep-metrics/-/deep-metrics-0.0.1.tgz#8ac3333195cc5eca059b224eb1ca61fc4cda50fd" dependencies: semver "^5.3.0" +deepmerge@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/deepmerge/-/deepmerge-2.1.0.tgz#511a54fff405fc346f0240bb270a3e9533a31102" + define-property@^0.2.5: version "0.2.5" resolved "https://registry.yarnpkg.com/define-property/-/define-property-0.2.5.tgz#c35b1ef918ec3c990f9a5bc57be04aacec5c8116" @@ -909,7 +933,7 @@ json-stable-stringify@^1.0.1: dependencies: jsonify "~0.0.0" -json-stringify-safe@^5.0, json-stringify-safe@~5.0.1: +json-stringify-safe@^5.0, json-stringify-safe@^5.0.1, json-stringify-safe@~5.0.1: version "5.0.1" resolved "https://registry.yarnpkg.com/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz#1296a2d58fd45f19a0f6ce01d65701e2c735b6eb" @@ -1487,7 +1511,7 @@ sax@^1.2.4: version "1.2.4" resolved "https://registry.yarnpkg.com/sax/-/sax-1.2.4.tgz#2816234e2378bddc4e5354fab5caa895df7100d9" -semver@5.*, semver@^5.0.1, semver@^5.3, semver@^5.3.0: +semver@5.*, semver@^5.0.1, semver@^5.3, semver@^5.3.0, semver@^5.5.0: version "5.5.0" resolved "https://registry.yarnpkg.com/semver/-/semver-5.5.0.tgz#dc4bbc7a6ca9d916dee5d43516f0092b58f7b8ab" @@ -1567,7 +1591,7 @@ should@^13: should-type-adaptors "^1.0.1" should-util "^1.0.0" -signal-exit@^3.0.0: +signal-exit@^3.0.0, signal-exit@^3.0.2: version "3.0.2" resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.2.tgz#b5fdc08f1287ea1178628e415e25132b73646c6d" @@ -1760,6 +1784,10 @@ tough-cookie@~2.3.0: dependencies: punycode "^1.4.1" +tslib@^1.6.0: + version "1.9.0" + resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.9.0.tgz#e37a86fda8cbbaf23a057f473c9f4dc64e5fc2e8" + tunnel-agent@^0.6.0: version "0.6.0" resolved "https://registry.yarnpkg.com/tunnel-agent/-/tunnel-agent-0.6.0.tgz#27a5dea06b36b04a0a9966774b290868f0fc40fd" @@ -1838,7 +1866,7 @@ vizion@^0.2: dependencies: async "1.5" -vxx@^1.2.0: +vxx@^1.2.0, vxx@^1.2.2: version "1.2.2" resolved "https://registry.yarnpkg.com/vxx/-/vxx-1.2.2.tgz#741fb51c6f11d3383da6f9b92018a5d7ba807611" dependencies: From c2614130d228eb742030ad2fad5bb9fdd822bcc5 Mon Sep 17 00:00:00 2001 From: vmarchaud Date: Mon, 30 Apr 2018 17:02:26 +0200 Subject: [PATCH 083/140] deps: update keymetrics-agent & vizion --- package.json | 6 +++--- yarn.lock | 50 +++++++++++++++++++------------------------------- 2 files changed, 22 insertions(+), 34 deletions(-) diff --git a/package.json b/package.json index 8a804521..3a89a91f 100644 --- a/package.json +++ b/package.json @@ -158,7 +158,7 @@ "pm2-runtime": "./bin/pm2-runtime" }, "dependencies": { - "@keymetrics/pmx": "^2.0.0-alpha9", + "@keymetrics/pmx": "^2.0.0-alpha11", "async": "^2.5", "blessed": "^0.1.81", "chalk": "^2.3.1", @@ -170,7 +170,7 @@ "eventemitter2": "5.0.1", "fclone": "1.0.11", "fs-extra": "^5.0.0", - "keymetrics-agent": "^0.3.5", + "keymetrics-agent": "^0.4.0", "mkdirp": "0.5.1", "moment": "^2.19", "needle": "^2.2.0", @@ -186,7 +186,7 @@ "source-map-support": "^0.5", "sprintf-js": "1.1.1", "v8-compile-cache": "^1.1.0", - "vizion": "^0.2", + "vizion": "0.2.0", "yamljs": "^0.3.0" }, "devDependencies": { diff --git a/yarn.lock b/yarn.lock index 998250f9..0d6ed766 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2,9 +2,9 @@ # yarn lockfile v1 -"@keymetrics/pmx@^2.0.0-alpha9": - version "2.0.0-alpha9" - resolved "https://registry.yarnpkg.com/@keymetrics/pmx/-/pmx-2.0.0-alpha9.tgz#1d29eaae08a6cdfc4ea4c2ac0501c50370f0c12b" +"@keymetrics/pmx@^2.0.0-alpha11": + version "2.0.0-alpha11" + resolved "https://registry.yarnpkg.com/@keymetrics/pmx/-/pmx-2.0.0-alpha11.tgz#6429672ee942dc30c200acaac1e305ec30a9cb32" dependencies: async "^2.6.0" debug "^3.1.0" @@ -122,7 +122,11 @@ async-listener@^0.6.0: semver "^5.3.0" shimmer "^1.1.0" -async@1.5, async@^1.5: +async@0.9.0: + version "0.9.0" + resolved "https://registry.yarnpkg.com/async/-/async-0.9.0.tgz#ac3613b1da9bed1b47510bb4651b8931e47146c7" + +async@^1.5: version "1.5.2" resolved "https://registry.yarnpkg.com/async/-/async-1.5.2.tgz#ec6a61ae56480c0c3cb241c95618e20892f9672a" @@ -389,7 +393,7 @@ debug@^2.1.2, debug@^2.2.0, debug@^2.3.3, debug@^2.6.3: dependencies: ms "2.0.0" -debug@^3, debug@^3.0, debug@^3.1.0: +debug@^3.0, debug@^3.1.0: version "3.1.0" resolved "https://registry.yarnpkg.com/debug/-/debug-3.1.0.tgz#5bb5a0672628b64149566ba16819e61518c67261" dependencies: @@ -415,12 +419,6 @@ deep-metrics@0.0.2: dependencies: semver "^5.3.0" -deep-metrics@^0.0.1: - version "0.0.1" - resolved "https://registry.yarnpkg.com/deep-metrics/-/deep-metrics-0.0.1.tgz#8ac3333195cc5eca059b224eb1ca61fc4cda50fd" - dependencies: - semver "^5.3.0" - deepmerge@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/deepmerge/-/deepmerge-2.1.0.tgz#511a54fff405fc346f0240bb270a3e9533a31102" @@ -933,7 +931,7 @@ json-stable-stringify@^1.0.1: dependencies: jsonify "~0.0.0" -json-stringify-safe@^5.0, json-stringify-safe@^5.0.1, json-stringify-safe@~5.0.1: +json-stringify-safe@^5.0.1, json-stringify-safe@~5.0.1: version "5.0.1" resolved "https://registry.yarnpkg.com/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz#1296a2d58fd45f19a0f6ce01d65701e2c735b6eb" @@ -960,9 +958,9 @@ jsprim@^1.2.2: json-schema "0.2.3" verror "1.10.0" -keymetrics-agent@^0.3.5: - version "0.3.5" - resolved "https://registry.yarnpkg.com/keymetrics-agent/-/keymetrics-agent-0.3.5.tgz#183ad8313a620e10eed6c98ce18e6af0e386efeb" +keymetrics-agent@^0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/keymetrics-agent/-/keymetrics-agent-0.4.0.tgz#9c23bb33427faaea6ed4dfdbd8316de4f3a229c9" dependencies: async "^2.6.0" eventemitter2 "^5.0.1" @@ -1357,16 +1355,6 @@ pm2-multimeter@^0.1.2: dependencies: charm "~0.1.1" -pmx@^1.6: - version "1.6.4" - resolved "https://registry.yarnpkg.com/pmx/-/pmx-1.6.4.tgz#45a0ebbf3c302e51b7514815f09817db79afd593" - dependencies: - debug "^3" - deep-metrics "^0.0.1" - json-stringify-safe "^5.0" - semver "5.*" - vxx "^1.2.0" - posix-character-classes@^0.1.0: version "0.1.1" resolved "https://registry.yarnpkg.com/posix-character-classes/-/posix-character-classes-0.1.1.tgz#01eac0fe3b5af71a2a6c02feabb8c1fef7e00eab" @@ -1511,7 +1499,7 @@ sax@^1.2.4: version "1.2.4" resolved "https://registry.yarnpkg.com/sax/-/sax-1.2.4.tgz#2816234e2378bddc4e5354fab5caa895df7100d9" -semver@5.*, semver@^5.0.1, semver@^5.3, semver@^5.3.0, semver@^5.5.0: +semver@^5.0.1, semver@^5.3, semver@^5.3.0, semver@^5.5.0: version "5.5.0" resolved "https://registry.yarnpkg.com/semver/-/semver-5.5.0.tgz#dc4bbc7a6ca9d916dee5d43516f0092b58f7b8ab" @@ -1860,13 +1848,13 @@ verror@1.10.0: core-util-is "1.0.2" extsprintf "^1.2.0" -vizion@^0.2: - version "0.2.13" - resolved "https://registry.yarnpkg.com/vizion/-/vizion-0.2.13.tgz#1314cdee2b34116f9f5b1248536f95dbfcd6ef5f" +vizion@0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/vizion/-/vizion-0.2.0.tgz#9cfb9e710e06e7b3d0e67474d38ab6b9f6a0c55b" dependencies: - async "1.5" + async "0.9.0" -vxx@^1.2.0, vxx@^1.2.2: +vxx@^1.2.2: version "1.2.2" resolved "https://registry.yarnpkg.com/vxx/-/vxx-1.2.2.tgz#741fb51c6f11d3383da6f9b92018a5d7ba807611" dependencies: From d0a2a30e4110496b178199fb33e026d6402dd00d Mon Sep 17 00:00:00 2001 From: Unitech Date: Thu, 10 May 2018 20:09:13 +0200 Subject: [PATCH 084/140] refactor: centralize SECRET/PUBLIC/MACHINE_NAME + change some wordings --- constants.js | 7 ++++++- lib/API.js | 14 +++++++------- lib/API/Interaction.js | 12 ++++++------ lib/binaries/Runtime.js | 12 ++++++------ lib/binaries/Runtime4Docker.js | 12 ++++++------ 5 files changed, 31 insertions(+), 26 deletions(-) diff --git a/constants.js b/constants.js index 3c21e4c0..48d7a9a0 100644 --- a/constants.js +++ b/constants.js @@ -55,7 +55,12 @@ var csts = { LOW_MEMORY_ENVIRONMENT : process.env.PM2_OPTIMIZE_MEMORY || false, - KEYMETRICS_ROOT_URL : process.env.KEYMETRICS_NODE || 'root.keymetrics.io', + MACHINE_NAME : process.env.INSTANCE_NAME || process.env.MACHINE_NAME, + SECRET_KEY : process.env.KEYMETRICS_SECRET || process.env.PM2_SECRET_KEY || process.env.SECRET_KEY, + PUBLIC_KEY : process.env.KEYMETRICS_PUBLIC || process.env.PM2_PUBLIC_KEY || process.env.PUBLIC_KEY, + KEYMETRICS_ROOT_URL : process.env.KEYMETRICS_NODE || process.env.ROOT_URL || process.env.INFO_NODE || 'root.keymetrics.io', + + KEYMETRICS_BANNER : '../lib/motd', KEYMETRICS_UPDATE : '../lib/motd.update', DEFAULT_MODULE_JSON : 'package.json', diff --git a/lib/API.js b/lib/API.js index c1a23f36..aaea293f 100644 --- a/lib/API.js +++ b/lib/API.js @@ -42,9 +42,9 @@ var IMMUTABLE_MSG = chalk.bold.blue('Use --update-env to update environment vari * @param {String} [opts.pm2_home=[]] pm2 directory for log, pids, socket files * @param {Boolean} [opts.independent=false] unique PM2 instance (random pm2_home) * @param {Boolean} [opts.daemon_mode=true] should be called in the same process or not - * @param {String} [opts.public_key=null] keymetrics bucket public key - * @param {String} [opts.secret_key=null] keymetrics bucket secret key - * @param {String} [opts.machine_name=null] keymetrics instance name + * @param {String} [opts.public_key=null] pm2 plus bucket public key + * @param {String} [opts.secret_key=null] pm2 plus bucket secret key + * @param {String} [opts.machine_name=null] pm2 plus instance name */ class API { @@ -54,9 +54,9 @@ class API { this.daemon_mode = typeof(opts.daemon_mode) == 'undefined' ? true : opts.daemon_mode; this.pm2_home = conf.PM2_ROOT_PATH; - this.public_key = process.env.KEYMETRICS_SECRET || opts.public_key || null; - this.secret_key = process.env.KEYMETRICS_PUBLIC || opts.secret_key || null; - this.machine_name = process.env.INSTANCE_NAME || opts.machine_name || null + this.public_key = conf.PUBLIC_KEY || opts.public_key || null; + this.secret_key = conf.SECRET_KEY || opts.secret_key || null; + this.machine_name = conf.MACHINE_NAME || opts.machine_name || null /** * CWD resolution @@ -372,7 +372,7 @@ class API { that.Client.executeRemote('notifyKillPM2', {}, function() {}); that.getVersion(function(err, new_version) { - // If not linked to keymetrics, and update pm2 to latest, display motd.update + // If not linked to PM2 plus, and update PM2 to latest, display motd.update if (!that.gl_is_km_linked && !err && (pkg.version != new_version)) { var dt = fs.readFileSync(path.join(__dirname, that._conf.KEYMETRICS_UPDATE)); console.log(dt.toString()); diff --git a/lib/API/Interaction.js b/lib/API/Interaction.js index 8d9557d4..3181127a 100644 --- a/lib/API/Interaction.js +++ b/lib/API/Interaction.js @@ -80,16 +80,16 @@ module.exports = function(CLI) { var that = this; if (cmd == 'stop' || cmd == 'kill') { - console.log(chalk.cyan('[Keymetrics.io]') + ' Stopping agent...'); + console.log(chalk.cyan('[PM2 agent]') + ' Stopping agent...'); that.killInteract(function() { - console.log(chalk.cyan('[Keymetrics.io]') + ' Stopped'); + console.log(chalk.cyan('[PM2 agent]') + ' Stopped'); return process.exit(cst.SUCCESS_EXIT); }); return false; } if (cmd == 'info') { - console.log(chalk.cyan('[Keymetrics.io]') + ' Getting agent information...'); + console.log(chalk.cyan('[PM2 agent]') + ' Getting agent information...'); that.interactInfos(function(err, infos) { if (err) { console.error(err.message); @@ -106,10 +106,10 @@ module.exports = function(CLI) { try { fs.unlinkSync(cst.INTERACTION_CONF); } catch(e) { - console.log(chalk.cyan('[Keymetrics.io]') + ' No interaction config file found'); + console.log(chalk.cyan('[PM2 agent]') + ' No interaction config file found'); return process.exit(cst.SUCCESS_EXIT); } - console.log(chalk.cyan('[Keymetrics.io]') + ' Agent interaction ended'); + console.log(chalk.cyan('[PM2 agent]') + ' Agent interaction ended'); return process.exit(cst.SUCCESS_EXIT); }); return false; @@ -132,7 +132,7 @@ module.exports = function(CLI) { } if (cmd && !public_key) { - console.error(chalk.cyan('[Keymetrics.io]') + ' Command [%s] unknown or missing public key', cmd); + console.error(chalk.cyan('[PM2 agent]') + ' Command [%s] unknown or missing public key', cmd); return process.exit(cst.ERROR_EXIT); } diff --git a/lib/binaries/Runtime.js b/lib/binaries/Runtime.js index 99c6cb19..0ad94aee 100644 --- a/lib/binaries/Runtime.js +++ b/lib/binaries/Runtime.js @@ -20,9 +20,9 @@ commander.version(pkg.version) .option('--auto-manage', 'keep application online after command exit') .option('--fast-boot', 'boot app faster by keeping pm2 runtime online in background (effective at second exit/start)') .option('--web [port]', 'launch process web api on [port] default to 9615') - .option('--secret [key]', 'keymetrics secret key') - .option('--public [key]', 'keymetrics public key') - .option('--machine-name [name]', 'keymetrics machine name') + .option('--secret [key]', 'PM2 plus secret key') + .option('--public [key]', 'PM2 plus public key') + .option('--machine-name [name]', 'PM2 plus machine name') .option('--env [name]', 'select env_[name] env variables in process config file') .option('--watch', 'Watch and Restart') .option('-i --instances ', 'launch [number] instances with load-balancer') @@ -32,9 +32,9 @@ commander.command('*') .action(function(cmd){ pm2 = new PM2.custom({ pm2_home : path.join(process.env.HOME, '.pm3'), - secret_key : process.env.KEYMETRICS_SECRET || commander.secret, - public_key : process.env.KEYMETRICS_PUBLIC || commander.public, - machine_name : process.env.INSTANCE_NAME || commander.machineName + secret_key : cst.SECRET_KEY || commander.secret, + public_key : cst.PUBLIC_KEY || commander.public, + machine_name : cst.MACHINE_NAME || commander.machineName }); pm2.connect(function() { diff --git a/lib/binaries/Runtime4Docker.js b/lib/binaries/Runtime4Docker.js index ee956bfe..837daa4b 100644 --- a/lib/binaries/Runtime4Docker.js +++ b/lib/binaries/Runtime4Docker.js @@ -17,15 +17,15 @@ process.env.PM2_DISCRETE_MODE = true; commander.version(pkg.version) .description('pm2-runtime is a drop-in replacement Node.js binary for containers') .option('-i --instances ', 'launch [number] of processes automatically load-balanced. Increase overall performances and performance stability.') - .option('--secret [key]', '[MONITORING] keymetrics secret key') + .option('--secret [key]', '[MONITORING] PM2 plus secret key') .option('--no-autorestart', 'start an app without automatic restart') .option('--node-args ', 'space delimited arguments to pass to node in cluster mode - e.g. --node-args="--debug=7001 --trace-deprecation"') .option('-n --name ', 'set a for script') .option('--max-memory-restart ', 'specify max memory amount used to autorestart (in octet or use syntax like 100M)') .option('-c --cron ', 'restart a running process based on a cron pattern') .option('--interpreter ', 'the interpreter pm2 should use for executing app (bash, python...)') - .option('--public [key]', '[MONITORING] keymetrics public key') - .option('--machine-name [name]', '[MONITORING] keymetrics machine name') + .option('--public [key]', '[MONITORING] PM2 plus public key') + .option('--machine-name [name]', '[MONITORING] PM2 plus machine name') .option('--trace', 'enable transaction tracing with km') .option('--v8', 'enable v8 data collecting') .option('--format', 'output logs formated like key=val') @@ -65,9 +65,9 @@ var Runtime = { instanciate : function(cmd) { this.pm2 = new PM2.custom({ pm2_home : process.env.PM2_HOME || path.join(process.env.HOME, '.pm2'), - secret_key : process.env.KEYMETRICS_SECRET || commander.secret, - public_key : process.env.KEYMETRICS_PUBLIC || commander.public, - machine_name : process.env.INSTANCE_NAME || commander.machineName, + secret_key : cst.SECRET_KEY || commander.secret, + public_key : cst.PUBLIC_KEY || commander.public, + machine_name : cst.MACHINE_NAME || commander.machineName, daemon_mode : process.env.PM2_RUNTIME_DEBUG || false }); From c43414a63438d724b8099eb531ec72bab23b8ca2 Mon Sep 17 00:00:00 2001 From: Unitech Date: Thu, 10 May 2018 21:02:28 +0200 Subject: [PATCH 085/140] chore: remove test for pmx alert system --- test/e2e/cli/app-configuration.sh | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/test/e2e/cli/app-configuration.sh b/test/e2e/cli/app-configuration.sh index f8683744..35c8a74f 100644 --- a/test/e2e/cli/app-configuration.sh +++ b/test/e2e/cli/app-configuration.sh @@ -59,7 +59,6 @@ exists 'probe test-probe exist' "test-probe" exists 'probe Event Loop Latency exist' "Loop delay" exists 'probe Event Loop Latency default value' "agg_type: 'avg'" -exists 'probe Event Loop Latency default value' "alert: {}" # Set new value for alert probe # $pm2 set probe-test.probes.Event\ Loop\ Latency.value 25 @@ -68,12 +67,5 @@ exists 'probe Event Loop Latency default value' "alert: {}" # exists 'probe Event Loop Latency alerted' "alert: { cmp: '>', value: 25, mode: 'threshold'" # Override value for test-probe -$pm2 set probe-test.probes.test-probe.value 30 -sleep 1 - -exists 'probe Event Loop Latency alerted' "value: 30" - -$pm2 restart all -sleep 1 - -exists 'probe Event Loop Latency alerted' "value: 30" +# $pm2 set probe-test.probes.test-probe.value 30 +# sleep 1 From 56f05a900b03fb0c8dd635aede666c7d2f213271 Mon Sep 17 00:00:00 2001 From: Unitech Date: Fri, 11 May 2018 00:12:01 +0200 Subject: [PATCH 086/140] fix: bug because of const --- lib/API.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/API.js b/lib/API.js index aaea293f..3c84365c 100644 --- a/lib/API.js +++ b/lib/API.js @@ -50,7 +50,7 @@ class API { constructor (opts) { if (!opts) opts = {}; - const that = this; + var that = this; this.daemon_mode = typeof(opts.daemon_mode) == 'undefined' ? true : opts.daemon_mode; this.pm2_home = conf.PM2_ROOT_PATH; @@ -80,7 +80,7 @@ class API { else if (opts.independent == true && conf.IS_WINDOWS === false) { // Create an unique pm2 instance const crypto = require('crypto'); - const random_file = crypto.randomBytes(8).toString('hex'); + var random_file = crypto.randomBytes(8).toString('hex'); this.pm2_home = path.join('/tmp', random_file); // If we dont explicitly tell to have a daemon @@ -112,7 +112,7 @@ class API { this.gl_is_km_linked = false; try { - const pid = fs.readFileSync(conf.INTERACTOR_PID_PATH); + var pid = fs.readFileSync(conf.INTERACTOR_PID_PATH); pid = parseInt(pid.toString().trim()); process.kill(pid, 0); that.gl_is_km_linked = true; From 13723bd938d0e6fb1cbf35f15eabe91c52d87b58 Mon Sep 17 00:00:00 2001 From: Unitech Date: Fri, 11 May 2018 00:12:38 +0200 Subject: [PATCH 087/140] chore: disable legacy test --- test/unit.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/unit.sh b/test/unit.sh index c7ead325..7dd0f930 100644 --- a/test/unit.sh +++ b/test/unit.sh @@ -78,8 +78,8 @@ mocha --opts ./mocha.opts ./send_data_process.mocha.js spec "Send data to a process" mocha --opts ./mocha.opts ./modules.mocha.js spec "Module API testing" -mocha --opts ./mocha.opts ./module_retrocompat.mocha.js -spec "Module retrocompatibility system" +# mocha --opts ./mocha.opts ./module_retrocompat.mocha.js +# spec "Module retrocompatibility system" mocha --opts ./mocha.opts ./json_validation.mocha.js spec "JSON validation test" From eeeb2988f8886e405aea107db3b888fc1fc929f8 Mon Sep 17 00:00:00 2001 From: Unitech Date: Fri, 11 May 2018 00:15:17 +0200 Subject: [PATCH 088/140] chore: updgrade pmx-2 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 3a89a91f..e286793a 100644 --- a/package.json +++ b/package.json @@ -158,7 +158,7 @@ "pm2-runtime": "./bin/pm2-runtime" }, "dependencies": { - "@keymetrics/pmx": "^2.0.0-alpha11", + "@keymetrics/pmx": "latest", "async": "^2.5", "blessed": "^0.1.81", "chalk": "^2.3.1", From adcbebc3f6419cd97c5ea99f3c3a6789585bda66 Mon Sep 17 00:00:00 2001 From: Unitech Date: Fri, 11 May 2018 00:50:49 +0200 Subject: [PATCH 089/140] chore: pmx -> pm2.io --- lib/API/Serve.js | 2 +- lib/ProcessUtils.js | 2 +- package.json | 2 +- test/fixtures/child_no_http.js | 2 +- test/fixtures/custom_actions/index.js | 2 +- test/fixtures/events/custom_action.js | 2 +- test/fixtures/events/custom_action_with_params.js | 2 +- test/fixtures/events/own_event.js | 2 +- test/fixtures/homogen-json-action/http.js | 2 +- test/fixtures/interface/http_transaction.js | 2 +- test/fixtures/interface/human_event.js | 2 +- test/fixtures/interface/process_exception.js | 2 +- test/fixtures/interface/process_exception_with_logs.js | 2 +- test/fixtures/module-fixture/scoped-action.js | 2 +- test/fixtures/probes.js | 2 +- test/fixtures/start-consistency/child.js | 2 +- 16 files changed, 16 insertions(+), 16 deletions(-) diff --git a/lib/API/Serve.js b/lib/API/Serve.js index d4707ade..7fed27be 100644 --- a/lib/API/Serve.js +++ b/lib/API/Serve.js @@ -8,7 +8,7 @@ var http = require('http'); var url = require('url'); var path = require('path'); var debug = require('debug')('pm2:serve'); -var probe = require('pmx').probe(); +var probe = require('pm2.io').probe(); /** * list of supported content types. diff --git a/lib/ProcessUtils.js b/lib/ProcessUtils.js index 75218823..72815dbf 100644 --- a/lib/ProcessUtils.js +++ b/lib/ProcessUtils.js @@ -1,7 +1,7 @@ module.exports = { injectModules: function() { if (process.env.pmx !== 'false') { - const pmx = require('@keymetrics/pmx'); + const pmx = require('pm2.io'); pmx.init({ transactions: (process.env.trace === 'true' || process.env.deep_monitoring === 'true') || false, http: process.env.km_link === 'true' || false, diff --git a/package.json b/package.json index e286793a..40992a87 100644 --- a/package.json +++ b/package.json @@ -158,7 +158,7 @@ "pm2-runtime": "./bin/pm2-runtime" }, "dependencies": { - "@keymetrics/pmx": "latest", + "pm2.io": "latest", "async": "^2.5", "blessed": "^0.1.81", "chalk": "^2.3.1", diff --git a/test/fixtures/child_no_http.js b/test/fixtures/child_no_http.js index 83ec9517..4e544844 100644 --- a/test/fixtures/child_no_http.js +++ b/test/fixtures/child_no_http.js @@ -1,4 +1,4 @@ -var pmx = require('pmx').init({ +var pmx = require('pm2.io').init({ http: false }); diff --git a/test/fixtures/custom_actions/index.js b/test/fixtures/custom_actions/index.js index 1efbe259..c6f593d7 100644 --- a/test/fixtures/custom_actions/index.js +++ b/test/fixtures/custom_actions/index.js @@ -1,5 +1,5 @@ -var pmx = require('pmx'); +var pmx = require('pm2.io'); pmx.action('ping', function(reply) { return reply({ 'pong' : 'hehe' }) diff --git a/test/fixtures/events/custom_action.js b/test/fixtures/events/custom_action.js index 443b26bf..edbd929b 100755 --- a/test/fixtures/events/custom_action.js +++ b/test/fixtures/events/custom_action.js @@ -1,5 +1,5 @@ -var axm = require('pmx'); +var axm = require('pm2.io'); axm.action('refresh:db', function(reply) { console.log('Refreshing'); diff --git a/test/fixtures/events/custom_action_with_params.js b/test/fixtures/events/custom_action_with_params.js index 8d0b6630..93784ed3 100755 --- a/test/fixtures/events/custom_action_with_params.js +++ b/test/fixtures/events/custom_action_with_params.js @@ -1,5 +1,5 @@ -var axm = require('pmx'); +var axm = require('pm2.io'); axm.action('refresh:db', { comment : 'Refresh the database' }, function(reply) { console.log('Refreshing'); diff --git a/test/fixtures/events/own_event.js b/test/fixtures/events/own_event.js index c4959741..b72fdfec 100644 --- a/test/fixtures/events/own_event.js +++ b/test/fixtures/events/own_event.js @@ -1,5 +1,5 @@ -var axm = require('pmx'); +var axm = require('pm2.io'); setInterval(function() { axm.emit('user:register', { diff --git a/test/fixtures/homogen-json-action/http.js b/test/fixtures/homogen-json-action/http.js index 61d823c7..546a6a2c 100644 --- a/test/fixtures/homogen-json-action/http.js +++ b/test/fixtures/homogen-json-action/http.js @@ -1,4 +1,4 @@ -var pmx = require('pmx').init({ +var pmx = require('pm2.io').init({ http : true }); diff --git a/test/fixtures/interface/http_transaction.js b/test/fixtures/interface/http_transaction.js index 17a91be5..e72eee6c 100644 --- a/test/fixtures/interface/http_transaction.js +++ b/test/fixtures/interface/http_transaction.js @@ -1,5 +1,5 @@ -var axm = require('pmx'); +var axm = require('pm2.io'); axm.http(); var http = require('http'); diff --git a/test/fixtures/interface/human_event.js b/test/fixtures/interface/human_event.js index 925a72a3..856b9c00 100644 --- a/test/fixtures/interface/human_event.js +++ b/test/fixtures/interface/human_event.js @@ -1,5 +1,5 @@ -var axm = require('pmx'); +var axm = require('pm2.io'); setInterval(function() { axm.emit('content:page:created', { diff --git a/test/fixtures/interface/process_exception.js b/test/fixtures/interface/process_exception.js index d4b0c937..f0ff97f0 100644 --- a/test/fixtures/interface/process_exception.js +++ b/test/fixtures/interface/process_exception.js @@ -1,5 +1,5 @@ -var axm = require('pmx'); +var axm = require('pm2.io'); axm.catchAll(); diff --git a/test/fixtures/interface/process_exception_with_logs.js b/test/fixtures/interface/process_exception_with_logs.js index 1200055b..67c9a621 100644 --- a/test/fixtures/interface/process_exception_with_logs.js +++ b/test/fixtures/interface/process_exception_with_logs.js @@ -1,5 +1,5 @@ -var pmx = require('pmx'); +var pmx = require('pm2.io'); pmx.action('exception', function(reply) { console.log('Im going to crash'); diff --git a/test/fixtures/module-fixture/scoped-action.js b/test/fixtures/module-fixture/scoped-action.js index 49d844aa..66010123 100644 --- a/test/fixtures/module-fixture/scoped-action.js +++ b/test/fixtures/module-fixture/scoped-action.js @@ -1,5 +1,5 @@ -var pmx = require('pmx'); +var pmx = require('pm2.io'); var conf = pmx.initModule({ diff --git a/test/fixtures/probes.js b/test/fixtures/probes.js index bf2e07ca..cc517c65 100644 --- a/test/fixtures/probes.js +++ b/test/fixtures/probes.js @@ -1,6 +1,6 @@ -var pmx = require('pmx'); +var pmx = require('pm2.io'); var conf = pmx.init(); var http = require('http'); diff --git a/test/fixtures/start-consistency/child.js b/test/fixtures/start-consistency/child.js index b22f8e48..969d49f9 100644 --- a/test/fixtures/start-consistency/child.js +++ b/test/fixtures/start-consistency/child.js @@ -1,5 +1,5 @@ -require('pmx').init({ +require('pm2.io').init({ http : true }); From 157b106df78af1d28d37bbea069b926de4dceca5 Mon Sep 17 00:00:00 2001 From: Unitech Date: Fri, 11 May 2018 01:33:25 +0200 Subject: [PATCH 090/140] fix: verify default conf variable via package.json on public module --- test/e2e/modules/module.sh | 33 ++++++++++++++++++--------------- 1 file changed, 18 insertions(+), 15 deletions(-) diff --git a/test/e2e/modules/module.sh b/test/e2e/modules/module.sh index d3a0e077..fb1e1c53 100644 --- a/test/e2e/modules/module.sh +++ b/test/e2e/modules/module.sh @@ -16,6 +16,8 @@ $pm2 kill # # +$pm2 unset pm2-probe + $pm2 set 'pm2-probe:config1xxx' true $pm2 install pm2-probe @@ -29,11 +31,15 @@ should 'should app be online' 'online' 1 ls ~/.pm2/modules/pm2-probe spec "Module should be installed" + +# Default configuration variable in package.json (under "config" attribute) +should 'should have default config variable via package.json' "var2: false" 4 + # # Should configuration variable be present two times # one time in the raw env, and a second time prefixed with the module name # -exists '1# should have config variable' "config1xxx: 'true'" 4 +exists '1# should have config variable' "config1xxx: 'true'" 6 # # Change variable value @@ -98,21 +104,18 @@ $pm2 install . sleep 0.5 spec 'Should have installed module' -# Default configuration variable in package.json (under "config" attribute) -# Only 2 occurences because this is the first start -should 'should have config variable' "var2: false" 2 -# Override environment variable -$pm2 set example-module:var2 true -sleep 0.5 -should 'should module been restarted after setting variable' 'restart_time: 1' 1 +# # Override environment variable +# $pm2 set example-module:var2 true +# sleep 0.5 +# should 'should module been restarted after setting variable' 'restart_time: 1' 1 -# 4 occurences because of a restart -should 'should have config variable modified' "var2: 'true'" 4 +# # 4 occurences because of a restart +# should 'should have config variable modified' "var2: 'true'" 4 -$pm2 set example-module:newvar true -sleep 0.5 -should 'should module been restarted after setting variable' 'restart_time: 2' 1 +# $pm2 set example-module:newvar true +# sleep 0.5 +# should 'should module been restarted after setting variable' 'restart_time: 2' 1 -# 4 occurences because of a restart -should 'should have config variable modified' "newvar: 'true'" 4 +# # 4 occurences because of a restart +# should 'should have config variable modified' "newvar: 'true'" 4 From 36834c2c00d496e04c38abaca30202eb650015c4 Mon Sep 17 00:00:00 2001 From: Unitech Date: Fri, 11 May 2018 01:33:53 +0200 Subject: [PATCH 091/140] chore: delete old stagnating pmx inside test --- .../node_modules/pmx/.npmignore | 7 - .../node_modules/pmx/.travis.yml | 10 - .../node_modules/pmx/CHANGELOG.md | 18 -- .../module-fixture/node_modules/pmx/README.md | 303 ------------------ .../node_modules/pmx/examples/package.json | 21 -- .../pmx/examples/scoped-action.js | 70 ---- .../module-fixture/node_modules/pmx/index.js | 2 - .../node_modules/pmx/lib/Probe.js | 180 ----------- .../node_modules/pmx/lib/actions.js | 147 --------- .../node_modules/pmx/lib/common.js | 6 - .../node_modules/pmx/lib/events.js | 26 -- .../node_modules/pmx/lib/index.js | 66 ---- .../node_modules/pmx/lib/monitor.js | 49 --- .../node_modules/pmx/lib/network.js | 116 ------- .../node_modules/pmx/lib/notify.js | 117 ------- .../node_modules/pmx/lib/pm2_module.js | 110 ------- .../node_modules/pmx/lib/probes/pacemaker.js | 19 -- .../node_modules/pmx/lib/probes/profiling.js | 121 ------- .../node_modules/pmx/lib/transaction.js | 84 ----- .../node_modules/pmx/lib/utils/BinaryHeap.js | 135 -------- .../node_modules/pmx/lib/utils/EDS.js | 101 ------ .../node_modules/pmx/lib/utils/EWMA.js | 31 -- .../node_modules/pmx/lib/utils/fixedQueue.js | 115 ------- .../pmx/lib/utils/probes/Counter.js | 26 -- .../pmx/lib/utils/probes/Histogram.js | 185 ----------- .../pmx/lib/utils/probes/Meter.js | 36 --- .../node_modules/pmx/lib/utils/proxy.js | 34 -- .../node_modules/pmx/lib/utils/transport.js | 34 -- .../node_modules/pmx/lib/utils/units.js | 9 - .../pmx/lib/wrapper/simple_http.js | 98 ------ .../pmx/node_modules/debug/.jshintrc | 3 - .../pmx/node_modules/debug/.npmignore | 6 - .../pmx/node_modules/debug/History.md | 195 ----------- .../pmx/node_modules/debug/Makefile | 36 --- .../pmx/node_modules/debug/Readme.md | 188 ----------- .../pmx/node_modules/debug/bower.json | 28 -- .../pmx/node_modules/debug/browser.js | 168 ---------- .../pmx/node_modules/debug/component.json | 19 -- .../pmx/node_modules/debug/debug.js | 197 ------------ .../pmx/node_modules/debug/node.js | 209 ------------ .../debug/node_modules/ms/.npmignore | 5 - .../debug/node_modules/ms/History.md | 66 ---- .../debug/node_modules/ms/LICENSE | 20 -- .../debug/node_modules/ms/README.md | 35 -- .../debug/node_modules/ms/index.js | 125 -------- .../debug/node_modules/ms/package.json | 48 --- .../pmx/node_modules/debug/package.json | 73 ----- .../json-stringify-safe/.npmignore | 1 - .../json-stringify-safe/CHANGELOG.md | 14 - .../node_modules/json-stringify-safe/LICENSE | 15 - .../node_modules/json-stringify-safe/Makefile | 35 -- .../json-stringify-safe/README.md | 52 --- .../json-stringify-safe/package.json | 68 ---- .../json-stringify-safe/stringify.js | 27 -- .../json-stringify-safe/test/mocha.opts | 2 - .../test/stringify_test.js | 246 -------------- .../node_modules/pmx/package.json | 38 --- .../node_modules/pmx/test/action.mocha.js | 164 ---------- .../node_modules/pmx/test/auto.mocha.js | 101 ------ .../node_modules/pmx/test/event.mocha.js | 38 --- .../node_modules/pmx/test/event.mock.js | 13 - .../node_modules/pmx/test/express/app.js | 23 -- .../pmx/test/express/package.json | 14 - .../pmx/test/fixtures/histogram.fixture.js | 45 --- .../test/fixtures/module/module.fixture.js | 4 - .../pmx/test/fixtures/module/package.json | 14 - .../pmx/test/fixtures/monitor.mock.js | 20 -- .../pmx/test/fixtures/monitor2.mock.js | 26 -- .../pmx/test/fixtures/notify.mock.js | 6 - .../test/fixtures/notify_catch_all.mock.js | 9 - .../pmx/test/fixtures/probe.fixture.js | 118 ------- .../test/fixtures/scoped-action.fixture.js | 15 - .../pmx/test/fixtures/scoped-action.mocha.js | 1 - .../pmx/test/fixtures/transpose.fixture.js | 36 --- .../node_modules/pmx/test/helpers/plan.js | 23 -- .../node_modules/pmx/test/mocha.opts | 4 - .../node_modules/pmx/test/module.mocha.js | 119 ------- .../node_modules/pmx/test/monitor.mocha.js | 65 ---- .../node_modules/pmx/test/notify.mocha.js | 90 ------ .../node_modules/pmx/test/pmx.mocha.js | 18 -- .../node_modules/pmx/test/probe.mocha.js | 83 ----- .../node_modules/pmx/test/proc-option.mock.js | 8 - .../node_modules/pmx/test/proc.mock.js | 7 - .../node_modules/pmx/test/profiling.mocha.js | 47 --- .../node_modules/pmx/test/transaction.pmx.js | 0 .../pmx/test/transaction/app.mock.auto.js | 37 --- .../pmx/test/transaction/package.json | 14 - 87 files changed, 5357 deletions(-) delete mode 100644 test/fixtures/module-fixture/node_modules/pmx/.npmignore delete mode 100644 test/fixtures/module-fixture/node_modules/pmx/.travis.yml delete mode 100644 test/fixtures/module-fixture/node_modules/pmx/CHANGELOG.md delete mode 100644 test/fixtures/module-fixture/node_modules/pmx/README.md delete mode 100644 test/fixtures/module-fixture/node_modules/pmx/examples/package.json delete mode 100644 test/fixtures/module-fixture/node_modules/pmx/examples/scoped-action.js delete mode 100644 test/fixtures/module-fixture/node_modules/pmx/index.js delete mode 100644 test/fixtures/module-fixture/node_modules/pmx/lib/Probe.js delete mode 100644 test/fixtures/module-fixture/node_modules/pmx/lib/actions.js delete mode 100644 test/fixtures/module-fixture/node_modules/pmx/lib/common.js delete mode 100644 test/fixtures/module-fixture/node_modules/pmx/lib/events.js delete mode 100644 test/fixtures/module-fixture/node_modules/pmx/lib/index.js delete mode 100644 test/fixtures/module-fixture/node_modules/pmx/lib/monitor.js delete mode 100644 test/fixtures/module-fixture/node_modules/pmx/lib/network.js delete mode 100644 test/fixtures/module-fixture/node_modules/pmx/lib/notify.js delete mode 100644 test/fixtures/module-fixture/node_modules/pmx/lib/pm2_module.js delete mode 100644 test/fixtures/module-fixture/node_modules/pmx/lib/probes/pacemaker.js delete mode 100644 test/fixtures/module-fixture/node_modules/pmx/lib/probes/profiling.js delete mode 100644 test/fixtures/module-fixture/node_modules/pmx/lib/transaction.js delete mode 100644 test/fixtures/module-fixture/node_modules/pmx/lib/utils/BinaryHeap.js delete mode 100644 test/fixtures/module-fixture/node_modules/pmx/lib/utils/EDS.js delete mode 100644 test/fixtures/module-fixture/node_modules/pmx/lib/utils/EWMA.js delete mode 100644 test/fixtures/module-fixture/node_modules/pmx/lib/utils/fixedQueue.js delete mode 100644 test/fixtures/module-fixture/node_modules/pmx/lib/utils/probes/Counter.js delete mode 100644 test/fixtures/module-fixture/node_modules/pmx/lib/utils/probes/Histogram.js delete mode 100644 test/fixtures/module-fixture/node_modules/pmx/lib/utils/probes/Meter.js delete mode 100644 test/fixtures/module-fixture/node_modules/pmx/lib/utils/proxy.js delete mode 100644 test/fixtures/module-fixture/node_modules/pmx/lib/utils/transport.js delete mode 100644 test/fixtures/module-fixture/node_modules/pmx/lib/utils/units.js delete mode 100644 test/fixtures/module-fixture/node_modules/pmx/lib/wrapper/simple_http.js delete mode 100644 test/fixtures/module-fixture/node_modules/pmx/node_modules/debug/.jshintrc delete mode 100644 test/fixtures/module-fixture/node_modules/pmx/node_modules/debug/.npmignore delete mode 100644 test/fixtures/module-fixture/node_modules/pmx/node_modules/debug/History.md delete mode 100644 test/fixtures/module-fixture/node_modules/pmx/node_modules/debug/Makefile delete mode 100644 test/fixtures/module-fixture/node_modules/pmx/node_modules/debug/Readme.md delete mode 100644 test/fixtures/module-fixture/node_modules/pmx/node_modules/debug/bower.json delete mode 100644 test/fixtures/module-fixture/node_modules/pmx/node_modules/debug/browser.js delete mode 100644 test/fixtures/module-fixture/node_modules/pmx/node_modules/debug/component.json delete mode 100644 test/fixtures/module-fixture/node_modules/pmx/node_modules/debug/debug.js delete mode 100644 test/fixtures/module-fixture/node_modules/pmx/node_modules/debug/node.js delete mode 100644 test/fixtures/module-fixture/node_modules/pmx/node_modules/debug/node_modules/ms/.npmignore delete mode 100644 test/fixtures/module-fixture/node_modules/pmx/node_modules/debug/node_modules/ms/History.md delete mode 100644 test/fixtures/module-fixture/node_modules/pmx/node_modules/debug/node_modules/ms/LICENSE delete mode 100644 test/fixtures/module-fixture/node_modules/pmx/node_modules/debug/node_modules/ms/README.md delete mode 100644 test/fixtures/module-fixture/node_modules/pmx/node_modules/debug/node_modules/ms/index.js delete mode 100644 test/fixtures/module-fixture/node_modules/pmx/node_modules/debug/node_modules/ms/package.json delete mode 100644 test/fixtures/module-fixture/node_modules/pmx/node_modules/debug/package.json delete mode 100644 test/fixtures/module-fixture/node_modules/pmx/node_modules/json-stringify-safe/.npmignore delete mode 100644 test/fixtures/module-fixture/node_modules/pmx/node_modules/json-stringify-safe/CHANGELOG.md delete mode 100644 test/fixtures/module-fixture/node_modules/pmx/node_modules/json-stringify-safe/LICENSE delete mode 100644 test/fixtures/module-fixture/node_modules/pmx/node_modules/json-stringify-safe/Makefile delete mode 100644 test/fixtures/module-fixture/node_modules/pmx/node_modules/json-stringify-safe/README.md delete mode 100644 test/fixtures/module-fixture/node_modules/pmx/node_modules/json-stringify-safe/package.json delete mode 100644 test/fixtures/module-fixture/node_modules/pmx/node_modules/json-stringify-safe/stringify.js delete mode 100644 test/fixtures/module-fixture/node_modules/pmx/node_modules/json-stringify-safe/test/mocha.opts delete mode 100644 test/fixtures/module-fixture/node_modules/pmx/node_modules/json-stringify-safe/test/stringify_test.js delete mode 100644 test/fixtures/module-fixture/node_modules/pmx/package.json delete mode 100644 test/fixtures/module-fixture/node_modules/pmx/test/action.mocha.js delete mode 100644 test/fixtures/module-fixture/node_modules/pmx/test/auto.mocha.js delete mode 100644 test/fixtures/module-fixture/node_modules/pmx/test/event.mocha.js delete mode 100644 test/fixtures/module-fixture/node_modules/pmx/test/event.mock.js delete mode 100644 test/fixtures/module-fixture/node_modules/pmx/test/express/app.js delete mode 100644 test/fixtures/module-fixture/node_modules/pmx/test/express/package.json delete mode 100644 test/fixtures/module-fixture/node_modules/pmx/test/fixtures/histogram.fixture.js delete mode 100644 test/fixtures/module-fixture/node_modules/pmx/test/fixtures/module/module.fixture.js delete mode 100644 test/fixtures/module-fixture/node_modules/pmx/test/fixtures/module/package.json delete mode 100644 test/fixtures/module-fixture/node_modules/pmx/test/fixtures/monitor.mock.js delete mode 100644 test/fixtures/module-fixture/node_modules/pmx/test/fixtures/monitor2.mock.js delete mode 100644 test/fixtures/module-fixture/node_modules/pmx/test/fixtures/notify.mock.js delete mode 100644 test/fixtures/module-fixture/node_modules/pmx/test/fixtures/notify_catch_all.mock.js delete mode 100644 test/fixtures/module-fixture/node_modules/pmx/test/fixtures/probe.fixture.js delete mode 100644 test/fixtures/module-fixture/node_modules/pmx/test/fixtures/scoped-action.fixture.js delete mode 100644 test/fixtures/module-fixture/node_modules/pmx/test/fixtures/scoped-action.mocha.js delete mode 100644 test/fixtures/module-fixture/node_modules/pmx/test/fixtures/transpose.fixture.js delete mode 100644 test/fixtures/module-fixture/node_modules/pmx/test/helpers/plan.js delete mode 100644 test/fixtures/module-fixture/node_modules/pmx/test/mocha.opts delete mode 100644 test/fixtures/module-fixture/node_modules/pmx/test/module.mocha.js delete mode 100644 test/fixtures/module-fixture/node_modules/pmx/test/monitor.mocha.js delete mode 100644 test/fixtures/module-fixture/node_modules/pmx/test/notify.mocha.js delete mode 100644 test/fixtures/module-fixture/node_modules/pmx/test/pmx.mocha.js delete mode 100644 test/fixtures/module-fixture/node_modules/pmx/test/probe.mocha.js delete mode 100644 test/fixtures/module-fixture/node_modules/pmx/test/proc-option.mock.js delete mode 100644 test/fixtures/module-fixture/node_modules/pmx/test/proc.mock.js delete mode 100644 test/fixtures/module-fixture/node_modules/pmx/test/profiling.mocha.js delete mode 100644 test/fixtures/module-fixture/node_modules/pmx/test/transaction.pmx.js delete mode 100644 test/fixtures/module-fixture/node_modules/pmx/test/transaction/app.mock.auto.js delete mode 100644 test/fixtures/module-fixture/node_modules/pmx/test/transaction/package.json diff --git a/test/fixtures/module-fixture/node_modules/pmx/.npmignore b/test/fixtures/module-fixture/node_modules/pmx/.npmignore deleted file mode 100644 index 3fcc6400..00000000 --- a/test/fixtures/module-fixture/node_modules/pmx/.npmignore +++ /dev/null @@ -1,7 +0,0 @@ -node_modules -*.log -*.log -test/child -*.iml -.idea/** -sample/pmx-server-stats diff --git a/test/fixtures/module-fixture/node_modules/pmx/.travis.yml b/test/fixtures/module-fixture/node_modules/pmx/.travis.yml deleted file mode 100644 index 7e7d37b1..00000000 --- a/test/fixtures/module-fixture/node_modules/pmx/.travis.yml +++ /dev/null @@ -1,10 +0,0 @@ -language: node_js -branches: - only: - - master - - development -node_js: - - "iojs" - - "0.12" - - "0.11" - - "0.10" diff --git a/test/fixtures/module-fixture/node_modules/pmx/CHANGELOG.md b/test/fixtures/module-fixture/node_modules/pmx/CHANGELOG.md deleted file mode 100644 index e89f1868..00000000 --- a/test/fixtures/module-fixture/node_modules/pmx/CHANGELOG.md +++ /dev/null @@ -1,18 +0,0 @@ - -# 0.2.27 - -- Remove debug message -- Rename module -- Auto instanciation - -# 0.2.25 - -- Add ip address on each transaction - -# 0.2.24 - -- Add unit option for Histogram and Meter - -# 0.2.23 - -- Include Counter, Meter, Metric and Histogram diff --git a/test/fixtures/module-fixture/node_modules/pmx/README.md b/test/fixtures/module-fixture/node_modules/pmx/README.md deleted file mode 100644 index 1e4a60b0..00000000 --- a/test/fixtures/module-fixture/node_modules/pmx/README.md +++ /dev/null @@ -1,303 +0,0 @@ - -# Driver for Keymetrics - -![Keymetrics](https://keymetrics.io/assets/images/application-demo.png) - -PMX is a module that allows you to create advanced interactions with Keymetrics. - -With it you can: -- Trigger remote actions / functions -- Analyze custom metrics / variables (with utilities like Histogram/Counter/Metric/Meters) -- Report errors (uncaught exceptions and custom errors) -- Emit events -- Analyze HTTP latency - -# Installation - -![Build Status](https://api.travis-ci.org/keymetrics/pmx.png?branch=master) - -Install PMX and add it to your package.json via: - -```bash -$ npm install pmx --save -``` - -Then init the module to monitor HTTP, Errors and diverse metrics. -```javascript -var pmx = require('pmx').init(); // By default everything is enabled and ignore_routes is empty -``` -Or choose what to monitor. -```javascript -var pmx = require('pmx').init({ - http : true, // HTTP routes logging (default: true) - ignore_routes : [/socket\.io/, /notFound/], // Ignore http routes with this pattern (Default: []) - errors : true, // Exceptions loggin (default: true) - custom_probes : true, // Custom probes (default: true) - network : true, // Traffic usage monitoring (default: false) - ports : true // Shows which ports your app is listening on (default: false) -}); -``` - -# Custom monitoring - -## Emit Events - -Emit events and get historical and statistics: - -```javascript -var pmx = require('pmx'); - -pmx.emit('user:register', { - user : 'Alex registered', - email : 'thorustor@gmail.com' -}); -``` - -## Custom Action - -Trigger function from Keymetrics - -### Long running - -```javascript -var pmx = require('pmx'); - -pmx.action('db:clean', { comment : 'Description for this action' }, function(reply) { - clean.db(function() { - /** - * reply() must be called at the end of the action - */ - reply({success : true}); - }); -}); -``` - -## Errors - -Catch uncaught exceptions: -```javascript -var pmx = require('pmx').init(); -``` - -Attach more data from errors that happens in Express: -```javascript -var pmx = require('pmx'); - -app.get('/' ...); -app.post(...); - -app.use(pmx.expressErrorHandler()); -``` - -Trigger custom errors: -```javascript -var pmx = require('pmx'); - -pmx.notify({ success : false }); - -pmx.notify('This is an error'); - -pmx.notify(new Error('This is an error')); -``` - -## TCP network usage monitoring - -If you enable the flag `network: true` when you init pmx it will show network usage datas (download and upload) in realtime. - -If you enable the flag `ports: true` when you init pmx it will show which ports your app is listenting on. - - -## HTTP latency analysis - -Monitor routes, latency and codes. REST compliant. - -```javascript -pmx.http(); // You must do this BEFORE any require('http') -``` -Ignore some routes by passing a list of regular expressions. -```javascript -pmx.http({ - http : true, // (Default: true) - ignore_routes : [/socket\.io/, /notFound/] // Ignore http routes with this pattern (Default: []) -}); -``` -This can also be done via pmx.init() -```javascript -pmx.init({ - http : true, // (Default: true) - ignore_routes : [/socket\.io/, /notFound/] // Ignore http routes with this pattern (Default: []) -}); -``` - -**This module is enabled by default if you called pmx with the init() function.** - -## Measure - -Measure critical segments of you code thanks to 4 kind of probes: - -- Simple metrics: Values that can be read instantly - - Monitor variable value -- Counter: Things that increment or decrement - - Downloads being processed, user connected -- Meter: Things that are measured as events / interval - - Request per minute for a http server -- Histogram: Keeps a resevoir of statistically relevant values biased towards the last 5 minutes to explore their distribution - - Monitor the mean of execution of a query into database - -#### Common options - -- `name` : The probe name as is will be displayed on the **Keymetrics** dashboard -- `agg_type` : This param is optional, it can be `sum`, `max`, `min`, `avg` (default) or `none`. It will impact the way the probe data are aggregated within the **Keymetrics** backend. Use `none` if this is irrelevant (eg: constant or string value). - - -### Metric - -Values that can be read instantly. - -```javascript -var probe = pmx.probe(); - -var metric = probe.metric({ - name : 'Realtime user', - agg_type: 'max', - value : function() { - return Object.keys(users).length; - } -}); -``` - -### Counter - -Things that increment or decrement. - -```javascript -var probe = pmx.probe(); - -var counter = probe.counter({ - name : 'Downloads', - agg_type: 'sum' -}); - -http.createServer(function(req, res) { - counter.inc(); - req.on('end', function() { - counter.dec(); - }); -}); -``` - -### Meter - -Things that are measured as events / interval. - -```javascript -var probe = pmx.probe(); - -var meter = probe.meter({ - name : 'req/sec', - samples : 1, - timeframe : 60 -}); - -http.createServer(function(req, res) { - meter.mark(); - res.end({success:true}); -}); -``` -#### Options - -**samples** option is the rate unit. Defaults to **1** sec. - -**timeframe** option is the timeframe over which events will be analyzed. Defaults to **60** sec. - -### Histogram - -Keeps a resevoir of statistically relevant values biased towards the last 5 minutes to explore their distribution. - -```javascript -var probe = pmx.probe(); - -var histogram = probe.histogram({ - name : 'latency', - measurement : 'mean' -}); - -var latency = 0; - -setInterval(function() { - latency = Math.round(Math.random() * 100); - histogram.update(latency); -}, 100); -``` - -#### Options - -**measurement** option can be: - -- min: The lowest observed value. -- max: The highest observed value. -- sum: The sum of all observed values. -- variance: The variance of all observed values. -- mean: The average of all observed values. -- stddev: The stddev of all observed values. -- count: The number of observed values. -- median: 50% of all values in the resevoir are at or below this value. -- p75: See median, 75% percentile. -- p95: See median, 95% percentile. -- p99: See median, 99% percentile. -- p999: See median, 99.9% percentile. - -## Expose data (JSON object) - -```javascript -pmx.transpose('variable name', function() { return my_data }); - -// or - -pmx.tranpose({ - name : 'variable name', - value : function() { return my_data; } -}); -``` - -## Modules - -### Simple app - -``` -process.env.MODULE_DEBUG = true; - -var pmx = require('pmx'); - -var conf = pmx.initModule(); -``` - -# Beta - -### Long running with data emitter (scoped action) - -A scoped action is an action that can emit logs related to this action. - -```javascript -var pmx = require('pmx'); - -pmx.scopedAction('scoped:action', function(options, res) { - var i = setInterval(function() { - // Emit progress data - if (error) - res.error('oops'); - else - res.send('this is a chunk of data'); - }, 1000); - - setTimeout(function() { - clearInterval(i); - return res.end(); - }, 8000); -}); -``` - - -# License - -MIT diff --git a/test/fixtures/module-fixture/node_modules/pmx/examples/package.json b/test/fixtures/module-fixture/node_modules/pmx/examples/package.json deleted file mode 100644 index acac5aa1..00000000 --- a/test/fixtures/module-fixture/node_modules/pmx/examples/package.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "name": "example-module", - "version": "0.3.21", - "description": "Keymetrics++ and PM2 adapter", - "main": "scoped-action.js", - "dependencies": { - }, - "scripts": { - "test": "DEBUG='axm:*' mocha test/*.mocha.js" - }, - "repository": { - "type": "git", - "url": "https://github.com/keymetrics/pmx.git" - }, - "config" : { - "aconfig-var" : true, - "var2" : false - }, - "author": "Keymetrics I/O", - "license": "MIT" -} diff --git a/test/fixtures/module-fixture/node_modules/pmx/examples/scoped-action.js b/test/fixtures/module-fixture/node_modules/pmx/examples/scoped-action.js deleted file mode 100644 index c6280c1b..00000000 --- a/test/fixtures/module-fixture/node_modules/pmx/examples/scoped-action.js +++ /dev/null @@ -1,70 +0,0 @@ - -var pmx = require('..'); - - -var conf = pmx.initModule({ - - widget : { - type : 'generic', - logo : 'https://app.keymetrics.io/img/logo/keymetrics-300.png', - - // 0 = main element - // 1 = secondary - // 2 = main border - // 3 = secondary border - theme : ['#141A1F', '#222222', '#3ff', '#3ff'], - - el : { - probes : true, - actions : true - }, - - block : { - actions : true, - issues : true, - meta : true - } - - // Status - // Green / Yellow / Red - } -}); - - -pmx.scopedAction('testo', function(data, emitter) { - var i = setInterval(function() { - emitter.send('datard'); - }, 100); - - setTimeout(function() { - - emitter.end('end'); - clearInterval(i); - }, 3000); -}); - -var spawn = require('child_process').spawn; - -pmx.scopedAction('long running lsof', function(data, res) { - var child = spawn('lsof', []); - - child.stdout.on('data', function(chunk) { - chunk.toString().split('\n').forEach(function(line) { - res.send(line); - }); - }); - - child.stdout.on('end', function(chunk) { - res.end('end'); - }); - -}); - - -pmx.action('simple action', function(reply) { - return reply({success:true}); -}); - -pmx.action('simple with arg', function(opts,reply) { - return reply(opts); -}); diff --git a/test/fixtures/module-fixture/node_modules/pmx/index.js b/test/fixtures/module-fixture/node_modules/pmx/index.js deleted file mode 100644 index 055544a9..00000000 --- a/test/fixtures/module-fixture/node_modules/pmx/index.js +++ /dev/null @@ -1,2 +0,0 @@ - -module.exports = exports = require("./lib"); diff --git a/test/fixtures/module-fixture/node_modules/pmx/lib/Probe.js b/test/fixtures/module-fixture/node_modules/pmx/lib/Probe.js deleted file mode 100644 index d5f73c4f..00000000 --- a/test/fixtures/module-fixture/node_modules/pmx/lib/Probe.js +++ /dev/null @@ -1,180 +0,0 @@ - -var Counter = require('./utils/probes/Counter.js'); -var Histogram = require('./utils/probes/Histogram.js'); -var Meter = require('./utils/probes/Meter.js'); - -var Transport = require('./utils/transport.js'); - -var debug = require('debug')('axm:probe'); -var Probe = {}; - -Probe._started = false; -Probe._var = {}; - -Probe.AVAILABLE_AGG_TYPES = ['avg', 'min', 'max', 'sum', 'none']; -Probe.AVAILABLE_MEASUREMENTS = [ - 'min', - 'max', - 'sum', - 'count', - 'variance', - 'mean', - 'stddev', - 'median', - 'p75', - 'p95', - 'p99', - 'p999' -]; -Probe.default_aggregation = 'avg'; - -function cookData(data) { - var cooked_data = {}; - - Object.keys(data).forEach(function(probe_name) { - var value = data[probe_name].value; - - if (typeof(value) == 'function') - value = value(); - else - value = value; - - cooked_data[probe_name] = { - value: value - }; - - if (data[probe_name].agg_type && - data[probe_name].agg_type != 'none') - cooked_data[probe_name].agg_type = data[probe_name].agg_type; - - }); - return cooked_data; -}; - -Probe.probe = function() { - - if (Probe._started == false) { - Probe._started = true; - - setInterval(function() { - Transport.send({ - type : 'axm:monitor', - data : cookData(Probe._var) - }); - }, 990); - } - - return { - /** - * This reflect data to keymetrics - * pmx.transpose('prop name', fn) - * - * or - * - * pmx.transpose({ - * name : 'variable name', - * data : function() { return value } - * }); - */ - transpose : function(variable_name, reporter) { - if (typeof variable_name === 'object') { - reporter = variable_name.data; - variable_name = variable_name.name; - } - - if (typeof reporter !== 'function') { - return console.error('[PMX] reporter is not a function'); - } - - Probe._var[variable_name] = { - value: reporter - }; - }, - metric : function(opts) { - var agg_type = opts.agg_type || Probe.default_aggregation; - - if (!opts.name) - return console.error('[Probe][Metric] Name not defined'); - if (typeof(opts.value) === 'undefined') - return console.error('[Probe][Metric] Value not defined'); - if (Probe.AVAILABLE_AGG_TYPES.indexOf(agg_type) == -1) - return console.error("[Probe][Metric] Unknown agg_type: %s", agg_type); - - if (opts.value) - Probe._var[opts.name] = { - value: opts.value, - agg_type: agg_type - }; - - return { - val : function() { - var value = Probe._var[opts.name].value; - - if (typeof(value) == 'function') - value = value(); - - return value; - }, - set : function(dt) { Probe._var[opts.name].value = dt } - } - }, - histogram : function(opts) { - if (!opts.name) - return console.error('[Probe][Histogram] Name not defined'); - opts.measurement = opts.measurement || 'mean'; - opts.unit = opts.unit || ''; - var agg_type = opts.agg_type || Probe.default_aggregation; - - if (Probe.AVAILABLE_MEASUREMENTS.indexOf(opts.measurement) == -1) - return console.error('[Probe][Histogram] Measure type %s does not exists', opts.measurement); - if (Probe.AVAILABLE_AGG_TYPES.indexOf(agg_type) == -1) - return console.error("[Probe][Metric] Unknown agg_type: %s", agg_type); - - var histogram = new Histogram(opts); - - Probe._var[opts.name] = { - value: function() { return (Math.round(histogram.val() * 100) / 100) + '' + opts.unit }, - agg_type: agg_type - }; - - return histogram; - }, - meter : function(opts) { - var agg_type = opts.agg_type || Probe.default_aggregation; - - if (!opts.name) - return console.error('[Probe][Meter] Name not defined'); - if (Probe.AVAILABLE_AGG_TYPES.indexOf(agg_type) == -1) - return console.error("[Probe][Metric] Unknown agg_type: %s", agg_type); - - opts.unit = opts.unit || ''; - - var meter = new Meter(opts); - - Probe._var[opts.name] = { - value: function() { return meter.val() + '' + opts.unit }, - agg_type: agg_type - }; - - return meter; - }, - counter : function(opts) { - var agg_type = opts.agg_type || Probe.default_aggregation; - - if (!opts.name) - return console.error('[Probe][Counter] Name not defined'); - if (Probe.AVAILABLE_AGG_TYPES.indexOf(agg_type) == -1) - return console.error("[Probe][Metric] Unknown agg_type: %s", agg_type); - - var counter = new Counter(); - - Probe._var[opts.name] = { - value: function() { return counter.val() }, - agg_type: agg_type - }; - return counter; - }, - } -}; - -module.exports = Probe; diff --git a/test/fixtures/module-fixture/node_modules/pmx/lib/actions.js b/test/fixtures/module-fixture/node_modules/pmx/lib/actions.js deleted file mode 100644 index dd807d58..00000000 --- a/test/fixtures/module-fixture/node_modules/pmx/lib/actions.js +++ /dev/null @@ -1,147 +0,0 @@ -var domain = require('domain'); -var debug = require('debug')('axm:events'); -var Common = require('./common.js'); -var Transport = require('./utils/transport.js'); - -var Actions = {}; - -Actions.action = function(action_name, opts, fn) { - if (!fn) { - fn = opts; - opts = null; - } - - if (!action_name) - return console.error('[PMX] action.action_name is missing'); - if (!fn) - return console.error('[PMX] emit.data is mission'); - - if (!process.send) { - debug('Process not running within PM2'); - return false; - } - - // Notify the action - Transport.send({ - type : 'axm:action', - data : { - action_name : action_name, - opts : opts, - arity : fn.length - } - }); - - function reply(data) { - Transport.send({ - type : 'axm:reply', - data : { - return : data, - action_name : action_name - } - }); - } - - process.on('message', function(data) { - if (!data) return false; - - // In case 2 arguments has been set but no options has been transmitted - if (fn.length === 2 && typeof(data) === 'string' && data === action_name) - return fn({}, reply); - - // In case 1 arguments has been set but options has been transmitted - if (fn.length === 1 && typeof(data) === 'object' && data.msg === action_name) - return fn(reply); - - /** - * Classical call - */ - if (typeof(data) === 'string' && data === action_name) - return fn(reply); - - /** - * If data is an object == v2 protocol - * Pass the opts as first argument - */ - if (typeof(data) === 'object' && data.msg === action_name) - return fn(data.opts, reply); - }); -}; - -Actions.scopedAction = function(action_name, fn) { - - if (!action_name) - return console.error('[PMX] action.action_name is missing'); - if (!fn) - return console.error('[PMX] callback is missing'); - - if (!process.send) { - debug('Process not running within PM2'); - return false; - } - - // Notify the action - Transport.send({ - type : 'axm:action', - data : { - action_name : action_name, - action_type : 'scoped' - } - }); - - process.on('message', function(data) { - if (!data - || data.uuid === undefined - || data.action_name === undefined) - return false; - - if (data.action_name === action_name) { - var res = { - send : function(dt) { - Transport.send({ - type : 'axm:scoped_action:stream', - data : { - data : dt, - uuid : data.uuid, - action_name : action_name - } - }); - }, - error : function(dt) { - Transport.send({ - type : 'axm:scoped_action:error', - data : { - data : dt, - uuid : data.uuid, - action_name : action_name - } - }); - }, - end : function(dt) { - Transport.send({ - type : 'axm:scoped_action:end', - data : { - data : dt, - uuid : data.uuid, - action_name : action_name - } - }); - } - }; - - var d = domain.create(); - - d.on('error', function(err) { - res.error({error : err}); - setTimeout(function() { - process.exit(1); - }, 300); - }); - - d.run(function() { - fn(data.opts || null, res); - }); - } - }); -}; - -module.exports = Actions; diff --git a/test/fixtures/module-fixture/node_modules/pmx/lib/common.js b/test/fixtures/module-fixture/node_modules/pmx/lib/common.js deleted file mode 100644 index c1bce910..00000000 --- a/test/fixtures/module-fixture/node_modules/pmx/lib/common.js +++ /dev/null @@ -1,6 +0,0 @@ - -var Common = module.exports = {}; - -Common.getDate = function getDate() { - return Math.round(Date.now() / 1000); -}; diff --git a/test/fixtures/module-fixture/node_modules/pmx/lib/events.js b/test/fixtures/module-fixture/node_modules/pmx/lib/events.js deleted file mode 100644 index f09496bc..00000000 --- a/test/fixtures/module-fixture/node_modules/pmx/lib/events.js +++ /dev/null @@ -1,26 +0,0 @@ - -var debug = require('debug')('axm:events'); -var Transport = require('./utils/transport.js'); -var Common = require('./common.js'); -var stringify = require('json-stringify-safe'); - -var Events = {}; - -Events.emit = function(name, data) { - if (!name) - return console.error('[AXM] emit.name is missing'); - if (!data) - return console.error('[AXM] emit.data is missing'); - - var inflight_obj = JSON.parse(stringify(data)); - - inflight_obj.__name = name; - - Transport.send({ - type : 'human:event', - data : inflight_obj - }, true); - return false; -}; - -module.exports = Events; diff --git a/test/fixtures/module-fixture/node_modules/pmx/lib/index.js b/test/fixtures/module-fixture/node_modules/pmx/lib/index.js deleted file mode 100644 index 55803e4a..00000000 --- a/test/fixtures/module-fixture/node_modules/pmx/lib/index.js +++ /dev/null @@ -1,66 +0,0 @@ - -var Events = require('./events.js'); -var Actions = require('./actions.js'); -var Notify = require('./notify.js'); -var Transaction = require('./transaction.js'); -var Network = require('./network.js'); -var Monitor = require('./monitor.js'); -var Profiling = require('./probes/profiling.js'); -var Probe = require('./Probe.js'); - -var Pm2Module = require('./pm2_module.js'); - -var util = require('util'); - -var Export = {}; - -/** - * Flatten API - */ -util._extend(Export, Events); -util._extend(Export, Actions); -util._extend(Export, Notify); -util._extend(Export, Monitor); -util._extend(Export, Pm2Module); -util._extend(Export, Probe); -util._extend(Export, Transaction); -util._extend(Export, Network); -util._extend(Export, Profiling); - -Export.init = function(opts) { - if (!opts) opts = {}; - - opts = util._extend({ - http : true, - http_latency : 200, - http_code : 500, - ignore_routes : [], - profiling : true, - errors : true, - custom_probes : true, - network : false, - ports : false - }, opts); - - if (opts.ports) - Export.catchPorts(); - if (opts.network) - Export.catchTraffic(); - Export.http(opts); - Export.catchAll(opts); - - if (opts.profiling) - Profiling.v8Profiling(Export); - - if (opts.custom_probes) { - // Event loop monitoring - require('./probes/pacemaker.js')(Export); - } - return this; -}; - -/** - * Export - */ - -module.exports = Export; diff --git a/test/fixtures/module-fixture/node_modules/pmx/lib/monitor.js b/test/fixtures/module-fixture/node_modules/pmx/lib/monitor.js deleted file mode 100644 index 7c519506..00000000 --- a/test/fixtures/module-fixture/node_modules/pmx/lib/monitor.js +++ /dev/null @@ -1,49 +0,0 @@ - -var Transport = require('./utils/transport.js'); -var debug = require('debug')('axm:monitor'); - -var Monitor = {}; - -function cookData(data) { - var cooked_data = {}; - - Object.keys(data).forEach(function(probe_name) { - if (typeof(data[probe_name]) == 'function') - cooked_data[probe_name] = data[probe_name](); - else - cooked_data[probe_name] = data[probe_name]; - }); - return cooked_data; -}; - -function enableProbes(custom_namespace) { - if (!custom_namespace) - custom_namespace = 'axm'; - - if (!global[custom_namespace]) - global[custom_namespace] = {}; - - if (this.interval) - return global[custom_namespace]; - - this.interval = setInterval(function() { - Transport.send({ - type : 'axm:monitor', - data : cookData(global[custom_namespace]) - }); - }, 990); - - return global[custom_namespace]; -}; - -function stopProbing() { - clearInterval(this.interval); -} - -Monitor.enableProbes = enableProbes; -Monitor.enableProbe = enableProbes; - -Monitor.stopProbe = stopProbing; -Monitor.stopProbes = stopProbing; - -module.exports = Monitor; diff --git a/test/fixtures/module-fixture/node_modules/pmx/lib/network.js b/test/fixtures/module-fixture/node_modules/pmx/lib/network.js deleted file mode 100644 index c83e513e..00000000 --- a/test/fixtures/module-fixture/node_modules/pmx/lib/network.js +++ /dev/null @@ -1,116 +0,0 @@ -var net_module = require('net'); -var Probe = require('./Probe.js'); - -var Network = module.exports = {}; - -Network.catchPorts = function() { - var ports_list = []; - var opened_ports = 'N/A'; - - Probe.probe().metric({ - name : 'Open ports', - value : function() { return opened_ports; } - }); - - var original_listen = net_module.Server.prototype.listen; - - net_module.Server.prototype.listen = function() { - var port = parseInt(arguments[0]); - - if (!isNaN(port) && ports_list.indexOf(port) === -1) { - ports_list.push(port); - opened_ports = ports_list.sort().join(); - } - - this.once('close', function() { - if (ports_list.indexOf(port) > -1) { - ports_list.splice(ports_list.indexOf(port), 1); - opened_ports = ports_list.sort().join(); - } - }); - - return original_listen.apply(this, arguments); - }; -}; - -Network.catchTraffic = function() { - var download = 0; - var upload = 0; - var up = '0 B/sec'; - var down = '0 B/sec'; - - var filter = function(bytes) { - var to_fixed = 0; - - if (bytes === 0) - ; - else if (bytes < 1024) - to_fixed = 6; - else if (bytes < (1024 * 1024)) - to_fixed = 3; - else - to_fixed = 2; - - bytes = (bytes / (1024 * 1024)).toFixed(to_fixed); - - var cut_zeros = 0; - - for (var i = (bytes.length - 1); i > 0; --i) { - if (bytes[i] === '.') { - ++cut_zeros; - break; - } - if (bytes[i] !== '0') - break; - ++cut_zeros; - } - - if (cut_zeros > 0) - bytes = bytes.slice(0, -(cut_zeros)); - - return (bytes + ' MB/s'); - }; - - setInterval(function() { - up = filter(upload); - down = filter(download); - upload = 0; - download = 0; - }, 999); - - Probe.probe().metric({ - name : 'Network Download', - agg_type : 'sum', - value : function() { return down; } - }); - - Probe.probe().metric({ - name : 'Network Upload', - agg_type : 'sum', - value : function() { return up; } - }); - - var original_write = net_module.Socket.prototype.write; - - net_module.Socket.prototype.write = function(data) { - if (data.length) - upload += data.length; - return original_write.apply(this, arguments); - }; - - var original_read = net_module.Socket.prototype.read; - - net_module.Socket.prototype.read = function() { - - if (!this.monitored) { - this.monitored = true; - - this.on('data', function(data) { - if (data.length) - download += data.length; - }); - } - - return original_read.apply(this, arguments); - }; -}; diff --git a/test/fixtures/module-fixture/node_modules/pmx/lib/notify.js b/test/fixtures/module-fixture/node_modules/pmx/lib/notify.js deleted file mode 100644 index 49bd5a78..00000000 --- a/test/fixtures/module-fixture/node_modules/pmx/lib/notify.js +++ /dev/null @@ -1,117 +0,0 @@ - -var debug = require('debug')('axm:notify'); -var util = require('util'); -var Common = require('./common.js'); - -var Options = require('./pm2_module.js'); - -var Transport = require('./utils/transport.js'); - -var Notify = {}; - - -var jsonize = function(err, filter, space) { - if (typeof(err) != 'object') - return err; - - var plainObject = {}; - - Object.getOwnPropertyNames(err).forEach(function(key) { - plainObject[key] = err[key]; - }); - return plainObject; -}; - -Notify.catchAll = function(opts) { - - if (opts === undefined) - opts = { errors : true }; - - Options.configureModule({ - error : opts.errors - }); - - if (process.env.exec_mode == 'cluster_mode') - return false; - - var catchException = function(err) { - //debug(err.stack || err); - Transport.send({ - type : 'process:exception', - data : jsonize(err) - }, true); - console.error(err.stack || err); - process.exit(255); - }; - - if (opts.errors === true - && util.inspect(process.listeners('uncaughtException')).length === 2) { - process.once('uncaughtException', catchException); - } - else if (opts.errors === false - && util.inspect(process.listeners('uncaughtException')).length !== 2) { - process.removeAllListeners('uncaughtException'); - } -}; - -Notify._interpretError = function(err) { - var s_err = {}; - - if (typeof(err) === 'string') { - // Simple string processing - s_err = new Error(err); - } - else if (!(err instanceof Error) && typeof(err) === 'object') { - // JSON processing - s_err = new Error(JSON.stringify(err)); - s_err.data = err; - } - else if (err instanceof Error) { - // Error object type processing - s_err = err; - } - - return jsonize(s_err); -}; - -Notify.notify = function(err) { - var ret_err = this._interpretError(err); - - // full_err - //debug(ret_err); - - Transport.send({ - type : 'process:exception', - data : ret_err - }, true); - - return ret_err; -}; - -Notify.expressErrorHandler = function() { - var self = this; - - Options.configureModule({ - error : true - }); - - return function errorHandler(err, req, res, next) { - if (res.statusCode < 400) res.statusCode = 500; - - //debug(err.stack || err); - - err.url = req.url; - err.component = req.url; - err.action = req.method; - err.params = req.body; - err.session = req.session; - - Transport.send({ - type : 'process:exception', - data : jsonize(err) - }, true); - return next(err); - }; -}; - -module.exports = Notify; diff --git a/test/fixtures/module-fixture/node_modules/pmx/lib/pm2_module.js b/test/fixtures/module-fixture/node_modules/pmx/lib/pm2_module.js deleted file mode 100644 index 7b3b8aae..00000000 --- a/test/fixtures/module-fixture/node_modules/pmx/lib/pm2_module.js +++ /dev/null @@ -1,110 +0,0 @@ - -var debug = require('debug')('axm:events'); -var Transport = require('./utils/transport.js'); -var path = require('path'); -var fs = require('fs'); -var util = require('util'); - -var Options = {}; - -Options.configureModule = function(opts) { - if (!this.running) { - this.running = true; - /* Avoid automatic exit of the script */ - - setInterval(function() {}, 1000); - } - - Transport.send({ - type : 'axm:option:configuration', - data : opts - }, false); -}; - -/** - * Load config and merge with data from package.json - */ -Options.loadConfig = Options.initModule = function(conf) { - var package_filepath = path.resolve(path.dirname(require.main.filename), 'package.json'); - - if (!conf) - conf = {}; - - if (!conf.module_conf) - conf.module_conf = {}; - - conf = util._extend(conf, { - errors : false, - latency : false, - versioning : false, - show_module_meta : false - }); - - /** - * Merge package.json metadata - */ - try { - var package_json = require(package_filepath); - - conf.module_version = package_json.version; - conf.module_name = package_json.name; - conf.description = package_json.description; - - if (package_json.config) { - conf = util._extend(conf, package_json.config); - conf.module_conf = package_json.config; - } - } catch(e) { - throw new Error('[PMX] package.json problem (not found or mal formated', e); - } - - /** - * If custom variables has been set, merge with returned configuration - */ - try { - if (process.env[package_json.name]) { - conf = util._extend(conf, JSON.parse(process.env[package_json.name])); - conf.module_conf = util._extend(conf.module_conf, JSON.parse(process.env[package_json.name])); - } - } catch(e) { - console.error(e); - console.error('Ezssadrror while parsing configuration in environment (%s)', package_json.name); - } - - Options.configureModule(conf); - - return conf; -}; - -Options.getPID = function(file) { - if (typeof(file) === 'number') - return file; - return parseInt(fs.readFileSync(file).toString()); -}; - -Options.resolvePidPaths = function(filepaths) { - if (typeof(filepaths) === 'number') - return filepaths; - - function detect(filepaths) { - var content = ''; - - filepaths.some(function(filepath) { - try { - content = fs.readFileSync(filepath); - } catch(e) { - return false; - } - return true; - }); - - return content.toString().trim(); - } - - var ret = parseInt(detect(filepaths)); - - return isNaN(ret) ? null : ret; -}; - - -module.exports = Options; diff --git a/test/fixtures/module-fixture/node_modules/pmx/lib/probes/pacemaker.js b/test/fixtures/module-fixture/node_modules/pmx/lib/probes/pacemaker.js deleted file mode 100644 index f16ceda6..00000000 --- a/test/fixtures/module-fixture/node_modules/pmx/lib/probes/pacemaker.js +++ /dev/null @@ -1,19 +0,0 @@ - -module.exports = function(pmx) { - var TIME_INTERVAL = 1000; - - var oldTime = process.hrtime(); - - var histogram = pmx.probe().histogram({ - name : 'Loop delay', - measurement : 'mean', - unit : 'ms' - }); - - setInterval(function() { - var newTime = process.hrtime(); - var delay = (newTime[0] - oldTime[0]) * 1e3 + (newTime[1] - oldTime[1]) / 1e6 - TIME_INTERVAL; - oldTime = newTime; - histogram.update(delay); - }, TIME_INTERVAL); -}; diff --git a/test/fixtures/module-fixture/node_modules/pmx/lib/probes/profiling.js b/test/fixtures/module-fixture/node_modules/pmx/lib/probes/profiling.js deleted file mode 100644 index 806aad00..00000000 --- a/test/fixtures/module-fixture/node_modules/pmx/lib/probes/profiling.js +++ /dev/null @@ -1,121 +0,0 @@ - -var debug = require('debug')('axm:profiling'); -var os = require('os'); -var path = require('path'); -var fs = require('fs'); - -var Options = require('../pm2_module.js'); - -var Profiling = module.exports = {}; - -Profiling.exposeProfiling = function(pmx, profiler_path) { - try { - var profiler = require(profiler_path); - } catch(e) { - debug('v8-profiler module not installed', e); - return false; - } - - debug('v8-profiler sucessfully enabled'); - - /** - * Tell Keymetrics that profiling is possible - * (flag available in axm_options object) - */ - Options.configureModule({ - heapdump : true - }); - - /** - * Heap snapshot - */ - pmx.action('km:heapdump', function(reply) { - var dump_file = path.join(os.tmpDir(), Date.now() + '.heapsnapshot'); - - var snapshot = profiler.takeSnapshot('km-heap-snapshot'); - var buffer = ''; - - snapshot.serialize( - function iterator(data, length) { - buffer += data; - }, function complete() { - fs.writeFile(dump_file, buffer, function (err) { - debug('Heap dump file flushed (e=', err); - - if (err) { - return reply({ - success : false, - err : err - }); - } - return reply({ - success : true, - heapdump : true, - dump_file : dump_file - }); - }); - } - ); - }); - - /** - * CPU profiling snapshot - */ - var ns_cpu_profiling = 'km-cpu-profiling'; - var cpu_dump_file = path.join(os.tmpDir(), Date.now() + '.cpuprofile'); - - pmx.action('km:cpu:profiling:start', function(reply) { - profiler.startProfiling(ns_cpu_profiling); - return reply({ success : true }); - }); - - pmx.action('km:cpu:profiling:stop', function(reply) { - var cpu = profiler.stopProfiling(ns_cpu_profiling); - - fs.writeFile(cpu_dump_file, JSON.stringify(cpu), function(err) { - if (err) { - return reply({ - success : false, - err : err - }); - } - return reply({ - success : true, - cpuprofile : true, - dump_file : cpu_dump_file - }); - }); - }); - -}; - -/** - * Discover v8-profiler - */ -Profiling.detectV8Profiler = function(cb) { - var require_paths = require.main.paths; - - (function look_for_profiler(require_paths) { - if (!require_paths[0]) - return cb(new Error('Module not found')); - - var profiler_path = path.join(require_paths[0], 'v8-profiler'); - - fs.exists(profiler_path, function(exist) { - if (exist) - return cb(null, profiler_path); - - require_paths.shift(); - return look_for_profiler(require_paths); - }); - return false; - })(require_paths); -}; - -Profiling.v8Profiling = function(pmx) { - Profiling.detectV8Profiler(function(err, profiler_path) { - if (err) - return false; - return Profiling.exposeProfiling(pmx, profiler_path); - }); -}; diff --git a/test/fixtures/module-fixture/node_modules/pmx/lib/transaction.js b/test/fixtures/module-fixture/node_modules/pmx/lib/transaction.js deleted file mode 100644 index d076f154..00000000 --- a/test/fixtures/module-fixture/node_modules/pmx/lib/transaction.js +++ /dev/null @@ -1,84 +0,0 @@ - -var util = require('util'); -var Proxy = require('./utils/proxy.js'); -var SimpleHttpWrap = require('./wrapper/simple_http.js'); -var Options = require('./pm2_module.js'); - -var debug = require('debug')('axm:patch'); - -var Transaction = module.exports = {}; - -Transaction.http = function(opts) { - var Module = require('module'); - - debug('Wrapping HTTP routes'); - - if (Array.isArray(opts)) { - var routes = JSON.parse(JSON.stringify(opts)); - opts = { - http : true, - http_latency : 200, - http_code : 500, - ignore_routes : routes - }; - } - opts = util._extend({ - http : true, - http_latency : 200, - http_code : 500, - ignore_routes : [], - }, opts); - - Proxy.wrap(Module, '_load', function(load) { - if (load.__axm_original) { - debug('HTTP routes have already been wrapped before'); - - Options.configureModule({ - latency : opts.http - }); - - if (opts.http === false) { - return function(file) { return load.__axm_original.apply(this, arguments) }; - } else { - return function(file) { - if (file === 'http' || file === 'https') - return SimpleHttpWrap(opts, load.__axm_original.apply(this, arguments)); - else - return load.__axm_original.apply(this, arguments); - }; - } - } - - return function(file) { - if (opts.http && - (file === 'http' || file === 'https')) { - debug('http module being required'); - Options.configureModule({ - latency : true - }); - return SimpleHttpWrap(opts, load.apply(this, arguments)); - } - else - return load.apply(this, arguments); - }; - }); -}; - -// Transaction.patch = function() { -// var Module = require('module'); - -// debug('Patching'); - -// Proxy.wrap(Module, '_load', function(load) { -// return function(file) { -// if (file == 'redis') { -// return RedisWrap(load.apply(this, arguments)); -// } -// else if (file == 'http') { -// return HttpWrap(load.apply(this, arguments)); -// } -// else -// return load.apply(this, arguments); -// }; -// }); -// }; diff --git a/test/fixtures/module-fixture/node_modules/pmx/lib/utils/BinaryHeap.js b/test/fixtures/module-fixture/node_modules/pmx/lib/utils/BinaryHeap.js deleted file mode 100644 index 384464b6..00000000 --- a/test/fixtures/module-fixture/node_modules/pmx/lib/utils/BinaryHeap.js +++ /dev/null @@ -1,135 +0,0 @@ - -// Hacked https://github.com/felixge/node-measured - -// Based on http://en.wikipedia.org/wiki/Binary_Heap -// as well as http://eloquentjavascript.net/appendix2.html -module.exports = BinaryHeap; -function BinaryHeap(options) { - options = options || {}; - - this._elements = options.elements || []; - this._score = options.score || this._score; -} - -BinaryHeap.prototype.add = function(/* elements */) { - for (var i = 0; i < arguments.length; i++) { - var element = arguments[i]; - - this._elements.push(element); - this._bubble(this._elements.length - 1); - } -}; - -BinaryHeap.prototype.first = function() { - return this._elements[0]; -}; - -BinaryHeap.prototype.removeFirst = function() { - var root = this._elements[0]; - var last = this._elements.pop(); - - if (this._elements.length > 0) { - this._elements[0] = last; - this._sink(0); - } - - return root; -}; - -BinaryHeap.prototype.clone = function() { - return new BinaryHeap({ - elements: this.toArray(), - score: this._score, - }); -}; - -BinaryHeap.prototype.toSortedArray = function() { - var array = []; - var clone = this.clone(); - - while (true) { - var element = clone.removeFirst(); - if (element === undefined) break; - - array.push(element); - } - - return array; -}; - -BinaryHeap.prototype.toArray = function() { - return [].concat(this._elements); -}; - -BinaryHeap.prototype.size = function() { - return this._elements.length; -}; - -BinaryHeap.prototype._bubble = function(bubbleIndex) { - var bubbleElement = this._elements[bubbleIndex]; - var bubbleScore = this._score(bubbleElement); - - while (bubbleIndex > 0) { - var parentIndex = this._parentIndex(bubbleIndex); - var parentElement = this._elements[parentIndex]; - var parentScore = this._score(parentElement); - - if (bubbleScore <= parentScore) break; - - this._elements[parentIndex] = bubbleElement; - this._elements[bubbleIndex] = parentElement; - bubbleIndex = parentIndex; - } -}; - -BinaryHeap.prototype._sink = function(sinkIndex) { - var sinkElement = this._elements[sinkIndex]; - var sinkScore = this._score(sinkElement); - var length = this._elements.length; - - while (true) { - var swapIndex = null; - var swapScore = null; - var swapElement = null; - var childIndexes = this._childIndexes(sinkIndex); - - for (var i = 0; i < childIndexes.length; i++) { - var childIndex = childIndexes[i]; - - if (childIndex >= length) break; - - var childElement = this._elements[childIndex]; - var childScore = this._score(childElement); - - if (childScore > sinkScore) { - if (swapScore === null || swapScore < childScore) { - swapIndex = childIndex; - swapScore = childScore; - swapElement = childElement; - } - } - } - - if (swapIndex === null) break; - - this._elements[swapIndex] = sinkElement; - this._elements[sinkIndex] = swapElement; - sinkIndex = swapIndex; - } -}; - -BinaryHeap.prototype._parentIndex = function(index) { - return Math.floor((index - 1) / 2); -}; - -BinaryHeap.prototype._childIndexes = function(index) { - return [ - 2 * index + 1, - 2 * index + 2, - ]; - return ; -}; - -BinaryHeap.prototype._score = function(element) { - return element.valueOf(); -}; diff --git a/test/fixtures/module-fixture/node_modules/pmx/lib/utils/EDS.js b/test/fixtures/module-fixture/node_modules/pmx/lib/utils/EDS.js deleted file mode 100644 index 4389e27c..00000000 --- a/test/fixtures/module-fixture/node_modules/pmx/lib/utils/EDS.js +++ /dev/null @@ -1,101 +0,0 @@ - -// Hacked https://github.com/felixge/node-measured - -var BinaryHeap = require('./BinaryHeap'); -var units = require('./units'); - -module.exports = ExponentiallyDecayingSample; -function ExponentiallyDecayingSample(options) { - options = options || {}; - - this._elements = new BinaryHeap({ - score: function(element) { - return -element.priority; - } - }); - - this._rescaleInterval = options.rescaleInterval || ExponentiallyDecayingSample.RESCALE_INTERVAL; - this._alpha = options.alpha || ExponentiallyDecayingSample.ALPHA; - this._size = options.size || ExponentiallyDecayingSample.SIZE; - this._random = options.random || this._random; - this._landmark = null; - this._nextRescale = null; -} - -ExponentiallyDecayingSample.RESCALE_INTERVAL = 1 * units.HOURS; -ExponentiallyDecayingSample.ALPHA = 0.015; -ExponentiallyDecayingSample.SIZE = 1028; - -ExponentiallyDecayingSample.prototype.update = function(value, timestamp) { - var now = Date.now(); - if (!this._landmark) { - this._landmark = now; - this._nextRescale = this._landmark + this._rescaleInterval; - } - - timestamp = timestamp || now; - - var newSize = this._elements.size() + 1; - - var element = { - priority: this._priority(timestamp - this._landmark), - value: value - }; - - if (newSize <= this._size) { - this._elements.add(element); - } else if (element.priority > this._elements.first().priority) { - this._elements.removeFirst(); - this._elements.add(element); - } - - if (now >= this._nextRescale) this._rescale(now); -}; - -ExponentiallyDecayingSample.prototype.toSortedArray = function() { - return this._elements - .toSortedArray() - .map(function(element) { - return element.value; - }); -}; - - -ExponentiallyDecayingSample.prototype.toArray = function() { - return this._elements - .toArray() - .map(function(element) { - return element.value; - }); -}; - -ExponentiallyDecayingSample.prototype._weight = function(age) { - // We divide by 1000 to not run into huge numbers before reaching a - // rescale event. - return Math.exp(this._alpha * (age / 1000)); -}; - -ExponentiallyDecayingSample.prototype._priority = function(age) { - return this._weight(age) / this._random(); -}; - -ExponentiallyDecayingSample.prototype._random = function() { - return Math.random(); -}; - -ExponentiallyDecayingSample.prototype._rescale = function(now) { - now = now || Date.now(); - - var self = this; - var oldLandmark = this._landmark; - this._landmark = now || Date.now(); - this._nextRescale = now + this._rescaleInterval; - - var factor = self._priority(-(self._landmark - oldLandmark)); - - this._elements - .toArray() - .forEach(function(element) { - element.priority *= factor; - }); -}; diff --git a/test/fixtures/module-fixture/node_modules/pmx/lib/utils/EWMA.js b/test/fixtures/module-fixture/node_modules/pmx/lib/utils/EWMA.js deleted file mode 100644 index dec164e9..00000000 --- a/test/fixtures/module-fixture/node_modules/pmx/lib/utils/EWMA.js +++ /dev/null @@ -1,31 +0,0 @@ - -// Hacked https://github.com/felixge/node-measured - -var units = require('./units'); - -module.exports = ExponentiallyWeightedMovingAverage; - -function ExponentiallyWeightedMovingAverage(timePeriod, tickInterval) { - this._timePeriod = timePeriod || 1 * units.MINUTE; - this._tickInterval = tickInterval || ExponentiallyWeightedMovingAverage.TICK_INTERVAL; - this._alpha = 1 - Math.exp(-this._tickInterval / this._timePeriod); - this._count = 0; - this._rate = 0; -}; - -ExponentiallyWeightedMovingAverage.TICK_INTERVAL = 5 * units.SECONDS; - -ExponentiallyWeightedMovingAverage.prototype.update = function(n) { - this._count += n; -}; - -ExponentiallyWeightedMovingAverage.prototype.tick = function() { - var instantRate = this._count / this._tickInterval; - this._count = 0; - - this._rate += (this._alpha * (instantRate - this._rate)); -}; - -ExponentiallyWeightedMovingAverage.prototype.rate = function(timeUnit) { - return (this._rate || 0) * timeUnit; -}; diff --git a/test/fixtures/module-fixture/node_modules/pmx/lib/utils/fixedQueue.js b/test/fixtures/module-fixture/node_modules/pmx/lib/utils/fixedQueue.js deleted file mode 100644 index 86059a5f..00000000 --- a/test/fixtures/module-fixture/node_modules/pmx/lib/utils/fixedQueue.js +++ /dev/null @@ -1,115 +0,0 @@ -function FixedQueue( size, initialValues ){ - - // If there are no initial arguments, default it to - // an empty value so we can call the constructor in - // a uniform way. - initialValues = (initialValues || []); - - // Create the fixed queue array value. - var queue = Array.apply( null, initialValues ); - - // Store the fixed size in the queue. - queue.fixedSize = size; - - // Add the class methods to the queue. Some of these have - // to override the native Array methods in order to make - // sure the queue lenght is maintained. - queue.push = FixedQueue.push; - queue.splice = FixedQueue.splice; - queue.unshift = FixedQueue.unshift; - - // Trim any initial excess from the queue. - FixedQueue.trimTail.call( queue ); - - // Return the new queue. - return( queue ); - -} - - -// I trim the queue down to the appropriate size, removing -// items from the beginning of the internal array. -FixedQueue.trimHead = function(){ - - // Check to see if any trimming needs to be performed. - if (this.length <= this.fixedSize){ - - // No trimming, return out. - return; - - } - - // Trim whatever is beyond the fixed size. - Array.prototype.splice.call( - this, - 0, - (this.length - this.fixedSize) - ); - -}; - - -// I trim the queue down to the appropriate size, removing -// items from the end of the internal array. -FixedQueue.trimTail = function(){ - - // Check to see if any trimming needs to be performed. - if (this.length <= this.fixedSize){ - - // No trimming, return out. - return; - - } - - // Trim whatever is beyond the fixed size. - Array.prototype.splice.call( - this, - this.fixedSize, - (this.length - this.fixedSize) - ); - -}; - - -// I synthesize wrapper methods that call the native Array -// methods followed by a trimming method. -FixedQueue.wrapMethod = function( methodName, trimMethod ){ - - // Create a wrapper that calls the given method. - var wrapper = function(){ - - // Get the native Array method. - var method = Array.prototype[ methodName ]; - - // Call the native method first. - var result = method.apply( this, arguments ); - - // Trim the queue now that it's been augmented. - trimMethod.call( this ); - - // Return the original value. - return( result ); - - }; - - // Return the wrapper method. - return( wrapper ); - -}; - - -// Wrap the native methods. -FixedQueue.push = FixedQueue.wrapMethod( - "push", - FixedQueue.trimHead -); - -FixedQueue.splice = FixedQueue.wrapMethod( - "splice", - FixedQueue.trimTail -); - -FixedQueue.unshift = FixedQueue.wrapMethod( - "unshift", - FixedQueue.trimTail -); diff --git a/test/fixtures/module-fixture/node_modules/pmx/lib/utils/probes/Counter.js b/test/fixtures/module-fixture/node_modules/pmx/lib/utils/probes/Counter.js deleted file mode 100644 index b7e9e7b3..00000000 --- a/test/fixtures/module-fixture/node_modules/pmx/lib/utils/probes/Counter.js +++ /dev/null @@ -1,26 +0,0 @@ - -// Hacked from https://github.com/felixge/node-measured - -module.exports = Counter; - -function Counter(opts) { - opts = opts || {}; - - this._count = opts.count || 0; -} - -Counter.prototype.val = function() { - return this._count; -}; - -Counter.prototype.inc = function(n) { - this._count += (n || 1); -}; - -Counter.prototype.dec = function(n) { - this._count -= (n || 1); -}; - -Counter.prototype.reset = function(count) { - this._count = count || 0; -}; diff --git a/test/fixtures/module-fixture/node_modules/pmx/lib/utils/probes/Histogram.js b/test/fixtures/module-fixture/node_modules/pmx/lib/utils/probes/Histogram.js deleted file mode 100644 index affba16a..00000000 --- a/test/fixtures/module-fixture/node_modules/pmx/lib/utils/probes/Histogram.js +++ /dev/null @@ -1,185 +0,0 @@ - -// Hacked from https://github.com/felixge/node-measured - -var EDS = require('../EDS.js'); - -function Histogram(opts) { - var self = this; - - opts = opts || {}; - - this._measurement = opts.measurement; - this._call_fn = null; - - var methods = { - min : this.getMin, - max : this.getMax, - sum : this.getSum, - count : this.getCount, - variance : this._calculateVariance, - mean : this._calculateMean, - stddev : this._calculateStddev - }; - - if (methods[this._measurement]) - this._call_fn = methods[this._measurement]; - else { - this._call_fn = function() { - var percentiles = this.percentiles([0.5, 0.75, 0.95, 0.99, 0.999]); - - var medians = { - median : percentiles[0.5], - p75 : percentiles[0.75], - p95 : percentiles[0.95], - p99 : percentiles[0.99], - p999 : percentiles[0.999] - }; - - return medians[this._measurement]; - } - } - this._sample = new EDS(); - this._min = null; - this._max = null; - this._count = 0; - this._sum = 0; - - // These are for the Welford algorithm for calculating running variance - // without floating-point doom. - this._varianceM = 0; - this._varianceS = 0; -} - -Histogram.prototype.update = function(value) { - this._count++; - this._sum += value; - - this._sample.update(value); - this._updateMin(value); - this._updateMax(value); - this._updateVariance(value); -}; - -Histogram.prototype.percentiles = function(percentiles) { - var values = this._sample - .toArray() - .sort(function(a, b) { - return (a === b) - ? 0 - : a - b; - }); - - var results = {}; - - for (var i = 0; i < percentiles.length; i++) { - var percentile = percentiles[i]; - if (!values.length) { - results[percentile] = null; - continue; - } - - var pos = percentile * (values.length + 1); - - if (pos < 1) { - results[percentile] = values[0]; - } else if (pos >= values.length) { - results[percentile] = values[values.length - 1]; - } else { - var lower = values[Math.floor(pos) - 1]; - var upper = values[Math.ceil(pos) - 1]; - - results[percentile] = lower + (pos - Math.floor(pos)) * (upper - lower); - } - } - - return results; -}; - -Histogram.prototype.reset = function() { - this.constructor.call(this); -}; - -Histogram.prototype.val = function() { - if (typeof(this._call_fn) === 'function') - return this._call_fn(); - else - return this._call_fn; -}; - -Histogram.prototype.getMin = function() { - return this._min; -}; - -Histogram.prototype.getMax = function() { - return this._max; -}; - -Histogram.prototype.getSum = function() { - return this._sum; -}; - -Histogram.prototype.getCount = function() { - return this._count; -}; - - -Histogram.prototype.fullResults = function() { - var percentiles = this.percentiles([0.5, 0.75, 0.95, 0.99, 0.999]); - - return { - min : this._min, - max : this._max, - sum : this._sum, - variance : this._calculateVariance(), - mean : this._calculateMean(), - stddev : this._calculateStddev(), - count : this._count, - median : percentiles[0.5], - p75 : percentiles[0.75], - p95 : percentiles[0.95], - p99 : percentiles[0.99], - p999 : percentiles[0.999] - }; -}; - -Histogram.prototype._updateMin = function(value) { - if (this._min === null || value < this._min) { - this._min = value; - //console.log(value); - } -}; - -Histogram.prototype._updateMax = function(value) { - if (this._max === null || value > this._max) { - this._max = value; - } -}; - -Histogram.prototype._updateVariance = function(value) { - if (this._count === 1) return this._varianceM = value; - - var oldM = this._varianceM; - - this._varianceM += ((value - oldM) / this._count); - this._varianceS += ((value - oldM) * (value - this._varianceM)); -}; - -Histogram.prototype._calculateMean = function() { - return (this._count === 0) - ? 0 - : this._sum / this._count; -}; - -Histogram.prototype._calculateVariance = function() { - return (this._count <= 1) - ? null - : this._varianceS / (this._count - 1); -}; - -Histogram.prototype._calculateStddev = function() { - return (this._count < 1) - ? null - : Math.sqrt(this._calculateVariance()); -}; - -module.exports = Histogram; diff --git a/test/fixtures/module-fixture/node_modules/pmx/lib/utils/probes/Meter.js b/test/fixtures/module-fixture/node_modules/pmx/lib/utils/probes/Meter.js deleted file mode 100644 index f436af40..00000000 --- a/test/fixtures/module-fixture/node_modules/pmx/lib/utils/probes/Meter.js +++ /dev/null @@ -1,36 +0,0 @@ - -// Hacked from https://github.com/felixge/node-measured - -var units = require('../units'); -var EWMA = require('../EWMA'); - -function Meter(opts) { - var self = this; - - this._tickInterval = 5 * units.SECONDS; - this._samples = opts.samples || 1; - this._timeframe = opts.timeframe || 60; - - this._rate = new EWMA(this._timeframe * units.SECONDS, this._tickInterval); - - if (opts.debug && opts.debug == true) - return false; - - this._interval = setInterval(function() { - self._rate.tick(); - }, this._tickInterval); -} - -Meter.RATE_UNIT = units.SECONDS; - -Meter.prototype.mark = function(n) { - n = n || 1; - - this._rate.update(n); -}; - -Meter.prototype.val = function() { - return Math.round(this._rate.rate(this._samples * Meter.RATE_UNIT) * 100 ) / 100; -}; - -module.exports = Meter; diff --git a/test/fixtures/module-fixture/node_modules/pmx/lib/utils/proxy.js b/test/fixtures/module-fixture/node_modules/pmx/lib/utils/proxy.js deleted file mode 100644 index 830a30fe..00000000 --- a/test/fixtures/module-fixture/node_modules/pmx/lib/utils/proxy.js +++ /dev/null @@ -1,34 +0,0 @@ - -var debug = require('debug')('axm:proxy'); - -// var cls = require('continuation-local-storage'); -// var ns = cls.createNamespace('namespace'); - -var Proxy = module.exports = { - wrap : function(object, methods, hook) { - var self = this; - - if (!Array.isArray(methods)) methods = [methods]; - - for (var i = 0; i < methods.length; ++i) { - debug('Wrapping method:', methods[i]); - var original = object[methods[i]]; - if (!original) return debug('Method %s unknown', methods[i]); - if (original.__axm_original) { - debug('Already wrapped', methods[i]); - if (methods[i] != '_load') - return; - } - var hooked = hook(original); - - if (original.__axm_original) { - hooked.__axm_original = original.__axm_original; - } - else { - hooked.__axm_original = original; - } - object[methods[i]] = hooked; - //debug('Method proxified'); - } - } -}; diff --git a/test/fixtures/module-fixture/node_modules/pmx/lib/utils/transport.js b/test/fixtures/module-fixture/node_modules/pmx/lib/utils/transport.js deleted file mode 100644 index b7485e4b..00000000 --- a/test/fixtures/module-fixture/node_modules/pmx/lib/utils/transport.js +++ /dev/null @@ -1,34 +0,0 @@ - -var debug = require('debug')('axm:transport'); -var stringify = require('json-stringify-safe'); - -var Transport = module.exports = {}; - -function ipcSend(args, print) { - /** - * For debug purpose - */ - if (process.env.MODULE_DEBUG) - console.log(args); - - if (!process.send) { - var output = args.data; - delete output.__name; - return false; - } - - - try { - process.send(JSON.parse(stringify(args))); - } catch(e) { - console.error('Process disconnected from parent !'); - console.error(e.stack || e); - process.exit(1); - } -}; - -Transport.send = function(args, print) { - if (!print) print = false; - - ipcSend(args, print); -}; diff --git a/test/fixtures/module-fixture/node_modules/pmx/lib/utils/units.js b/test/fixtures/module-fixture/node_modules/pmx/lib/utils/units.js deleted file mode 100644 index b1e16a24..00000000 --- a/test/fixtures/module-fixture/node_modules/pmx/lib/utils/units.js +++ /dev/null @@ -1,9 +0,0 @@ -// Time units, as found in Java: -// see: http://download.oracle.com/javase/6/docs/api/java/util/concurrent/TimeUnit.html -exports.NANOSECONDS = 1 / (1000 * 1000); -exports.MICROSECONDS = 1 / 1000; -exports.MILLISECONDS = 1; -exports.SECONDS = 1000 * exports.MILLISECONDS; -exports.MINUTES = 60 * exports.SECONDS; -exports.HOURS = 60 * exports.MINUTES; -exports.DAYS = 24 * exports.HOURS; diff --git a/test/fixtures/module-fixture/node_modules/pmx/lib/wrapper/simple_http.js b/test/fixtures/module-fixture/node_modules/pmx/lib/wrapper/simple_http.js deleted file mode 100644 index ca6d65a9..00000000 --- a/test/fixtures/module-fixture/node_modules/pmx/lib/wrapper/simple_http.js +++ /dev/null @@ -1,98 +0,0 @@ - -var Proxy = require('../utils/proxy.js'); -var Transport = require('../utils/transport.js'); -var Probe = require('../Probe.js'); - -var gl_meter, gl_latency; - -var HttpWrap = module.exports = function(opts, http) { - - gl_meter = Probe.probe().meter({ - name : 'HTTP', - seconds : 60, - unit : 'req/s' - }); - - gl_latency = Probe.probe().histogram({ - measurement : 'mean', - name : 'pmx:http:latency', - unit : 'ms' - }); - - var ignoreRoutes = function(url) { - for (var i = 0; i < opts.ignore_routes.length; ++i) { - if (url.match(opts.ignore_routes[i]) != null) { - return true; - } - } - return false; - }; - - Proxy.wrap(http.Server.prototype, ['on', 'addListener'], function(addListener) { - return function(event, listener) { - var self = this; - - var overloaded_function = function(request, response) { - gl_meter.mark(); - - var http_start = { - url : request.url, - method : request.method, - start : Date.now(), - ip : request.headers['x-forwarded-for'] || - (request.connection ? request.connection.remoteAddress : false) || - (request.socket ? request.socket.remoteAddress : false) || - ((request.connection && request.connection.socket) ? request.connection.socket.remoteAddress : false) || '' - }; - - response.once('finish', function() { - - if (!ignoreRoutes(http_start.url)) - gl_latency.update(Date.now() - http_start.start); - - if (((Date.now() - http_start.start) >= opts.http_latency - || response.statusCode >= opts.http_code) - && !ignoreRoutes(http_start.url)) { - - Transport.send({ - type : 'http:transaction', - data : { - url : http_start.url, - method : http_start.method, - time : Date.now() - http_start.start, - code : response.statusCode, - ip : http_start.ip, - size : response.getHeader('Content-Length') || null - } - }); - } - - http_start = null; - }); - }; - - if (!(event === 'request' && typeof listener === 'function')) - return addListener.apply(self, arguments); - - if (self.__overloaded !== true) { - - self.on('removeListener', function onRemoveListener() { - setTimeout(function() { - if (self.listeners('request').length === 1) { - self.removeListener('request', overloaded_function); - self.removeListener('removeListener', onRemoveListener); - self.__overloaded = false; - } - }, 200); - }); - - addListener.call(self, event, overloaded_function); - - self.__overloaded = true; - } - - return addListener.apply(self, arguments); - }; - }); - return http; -}; diff --git a/test/fixtures/module-fixture/node_modules/pmx/node_modules/debug/.jshintrc b/test/fixtures/module-fixture/node_modules/pmx/node_modules/debug/.jshintrc deleted file mode 100644 index 299877f2..00000000 --- a/test/fixtures/module-fixture/node_modules/pmx/node_modules/debug/.jshintrc +++ /dev/null @@ -1,3 +0,0 @@ -{ - "laxbreak": true -} diff --git a/test/fixtures/module-fixture/node_modules/pmx/node_modules/debug/.npmignore b/test/fixtures/module-fixture/node_modules/pmx/node_modules/debug/.npmignore deleted file mode 100644 index 7e6163db..00000000 --- a/test/fixtures/module-fixture/node_modules/pmx/node_modules/debug/.npmignore +++ /dev/null @@ -1,6 +0,0 @@ -support -test -examples -example -*.sock -dist diff --git a/test/fixtures/module-fixture/node_modules/pmx/node_modules/debug/History.md b/test/fixtures/module-fixture/node_modules/pmx/node_modules/debug/History.md deleted file mode 100644 index 854c9711..00000000 --- a/test/fixtures/module-fixture/node_modules/pmx/node_modules/debug/History.md +++ /dev/null @@ -1,195 +0,0 @@ - -2.2.0 / 2015-05-09 -================== - - * package: update "ms" to v0.7.1 (#202, @dougwilson) - * README: add logging to file example (#193, @DanielOchoa) - * README: fixed a typo (#191, @amir-s) - * browser: expose `storage` (#190, @stephenmathieson) - * Makefile: add a `distclean` target (#189, @stephenmathieson) - -2.1.3 / 2015-03-13 -================== - - * Updated stdout/stderr example (#186) - * Updated example/stdout.js to match debug current behaviour - * Renamed example/stderr.js to stdout.js - * Update Readme.md (#184) - * replace high intensity foreground color for bold (#182, #183) - -2.1.2 / 2015-03-01 -================== - - * dist: recompile - * update "ms" to v0.7.0 - * package: update "browserify" to v9.0.3 - * component: fix "ms.js" repo location - * changed bower package name - * updated documentation about using debug in a browser - * fix: security error on safari (#167, #168, @yields) - -2.1.1 / 2014-12-29 -================== - - * browser: use `typeof` to check for `console` existence - * browser: check for `console.log` truthiness (fix IE 8/9) - * browser: add support for Chrome apps - * Readme: added Windows usage remarks - * Add `bower.json` to properly support bower install - -2.1.0 / 2014-10-15 -================== - - * node: implement `DEBUG_FD` env variable support - * package: update "browserify" to v6.1.0 - * package: add "license" field to package.json (#135, @panuhorsmalahti) - -2.0.0 / 2014-09-01 -================== - - * package: update "browserify" to v5.11.0 - * node: use stderr rather than stdout for logging (#29, @stephenmathieson) - -1.0.4 / 2014-07-15 -================== - - * dist: recompile - * example: remove `console.info()` log usage - * example: add "Content-Type" UTF-8 header to browser example - * browser: place %c marker after the space character - * browser: reset the "content" color via `color: inherit` - * browser: add colors support for Firefox >= v31 - * debug: prefer an instance `log()` function over the global one (#119) - * Readme: update documentation about styled console logs for FF v31 (#116, @wryk) - -1.0.3 / 2014-07-09 -================== - - * Add support for multiple wildcards in namespaces (#122, @seegno) - * browser: fix lint - -1.0.2 / 2014-06-10 -================== - - * browser: update color palette (#113, @gscottolson) - * common: make console logging function configurable (#108, @timoxley) - * node: fix %o colors on old node <= 0.8.x - * Makefile: find node path using shell/which (#109, @timoxley) - -1.0.1 / 2014-06-06 -================== - - * browser: use `removeItem()` to clear localStorage - * browser, node: don't set DEBUG if namespaces is undefined (#107, @leedm777) - * package: add "contributors" section - * node: fix comment typo - * README: list authors - -1.0.0 / 2014-06-04 -================== - - * make ms diff be global, not be scope - * debug: ignore empty strings in enable() - * node: make DEBUG_COLORS able to disable coloring - * *: export the `colors` array - * npmignore: don't publish the `dist` dir - * Makefile: refactor to use browserify - * package: add "browserify" as a dev dependency - * Readme: add Web Inspector Colors section - * node: reset terminal color for the debug content - * node: map "%o" to `util.inspect()` - * browser: map "%j" to `JSON.stringify()` - * debug: add custom "formatters" - * debug: use "ms" module for humanizing the diff - * Readme: add "bash" syntax highlighting - * browser: add Firebug color support - * browser: add colors for WebKit browsers - * node: apply log to `console` - * rewrite: abstract common logic for Node & browsers - * add .jshintrc file - -0.8.1 / 2014-04-14 -================== - - * package: re-add the "component" section - -0.8.0 / 2014-03-30 -================== - - * add `enable()` method for nodejs. Closes #27 - * change from stderr to stdout - * remove unnecessary index.js file - -0.7.4 / 2013-11-13 -================== - - * remove "browserify" key from package.json (fixes something in browserify) - -0.7.3 / 2013-10-30 -================== - - * fix: catch localStorage security error when cookies are blocked (Chrome) - * add debug(err) support. Closes #46 - * add .browser prop to package.json. Closes #42 - -0.7.2 / 2013-02-06 -================== - - * fix package.json - * fix: Mobile Safari (private mode) is broken with debug - * fix: Use unicode to send escape character to shell instead of octal to work with strict mode javascript - -0.7.1 / 2013-02-05 -================== - - * add repository URL to package.json - * add DEBUG_COLORED to force colored output - * add browserify support - * fix component. Closes #24 - -0.7.0 / 2012-05-04 -================== - - * Added .component to package.json - * Added debug.component.js build - -0.6.0 / 2012-03-16 -================== - - * Added support for "-" prefix in DEBUG [Vinay Pulim] - * Added `.enabled` flag to the node version [TooTallNate] - -0.5.0 / 2012-02-02 -================== - - * Added: humanize diffs. Closes #8 - * Added `debug.disable()` to the CS variant - * Removed padding. Closes #10 - * Fixed: persist client-side variant again. Closes #9 - -0.4.0 / 2012-02-01 -================== - - * Added browser variant support for older browsers [TooTallNate] - * Added `debug.enable('project:*')` to browser variant [TooTallNate] - * Added padding to diff (moved it to the right) - -0.3.0 / 2012-01-26 -================== - - * Added millisecond diff when isatty, otherwise UTC string - -0.2.0 / 2012-01-22 -================== - - * Added wildcard support - -0.1.0 / 2011-12-02 -================== - - * Added: remove colors unless stderr isatty [TooTallNate] - -0.0.1 / 2010-01-03 -================== - - * Initial release diff --git a/test/fixtures/module-fixture/node_modules/pmx/node_modules/debug/Makefile b/test/fixtures/module-fixture/node_modules/pmx/node_modules/debug/Makefile deleted file mode 100644 index 5cf4a596..00000000 --- a/test/fixtures/module-fixture/node_modules/pmx/node_modules/debug/Makefile +++ /dev/null @@ -1,36 +0,0 @@ - -# get Makefile directory name: http://stackoverflow.com/a/5982798/376773 -THIS_MAKEFILE_PATH:=$(word $(words $(MAKEFILE_LIST)),$(MAKEFILE_LIST)) -THIS_DIR:=$(shell cd $(dir $(THIS_MAKEFILE_PATH));pwd) - -# BIN directory -BIN := $(THIS_DIR)/node_modules/.bin - -# applications -NODE ?= $(shell which node) -NPM ?= $(NODE) $(shell which npm) -BROWSERIFY ?= $(NODE) $(BIN)/browserify - -all: dist/debug.js - -install: node_modules - -clean: - @rm -rf dist - -dist: - @mkdir -p $@ - -dist/debug.js: node_modules browser.js debug.js dist - @$(BROWSERIFY) \ - --standalone debug \ - . > $@ - -distclean: clean - @rm -rf node_modules - -node_modules: package.json - @NODE_ENV= $(NPM) install - @touch node_modules - -.PHONY: all install clean distclean diff --git a/test/fixtures/module-fixture/node_modules/pmx/node_modules/debug/Readme.md b/test/fixtures/module-fixture/node_modules/pmx/node_modules/debug/Readme.md deleted file mode 100644 index b4f45e3c..00000000 --- a/test/fixtures/module-fixture/node_modules/pmx/node_modules/debug/Readme.md +++ /dev/null @@ -1,188 +0,0 @@ -# debug - - tiny node.js debugging utility modelled after node core's debugging technique. - -## Installation - -```bash -$ npm install debug -``` - -## Usage - - With `debug` you simply invoke the exported function to generate your debug function, passing it a name which will determine if a noop function is returned, or a decorated `console.error`, so all of the `console` format string goodies you're used to work fine. A unique color is selected per-function for visibility. - -Example _app.js_: - -```js -var debug = require('debug')('http') - , http = require('http') - , name = 'My App'; - -// fake app - -debug('booting %s', name); - -http.createServer(function(req, res){ - debug(req.method + ' ' + req.url); - res.end('hello\n'); -}).listen(3000, function(){ - debug('listening'); -}); - -// fake worker of some kind - -require('./worker'); -``` - -Example _worker.js_: - -```js -var debug = require('debug')('worker'); - -setInterval(function(){ - debug('doing some work'); -}, 1000); -``` - - The __DEBUG__ environment variable is then used to enable these based on space or comma-delimited names. Here are some examples: - - ![debug http and worker](http://f.cl.ly/items/18471z1H402O24072r1J/Screenshot.png) - - ![debug worker](http://f.cl.ly/items/1X413v1a3M0d3C2c1E0i/Screenshot.png) - -#### Windows note - - On Windows the environment variable is set using the `set` command. - - ```cmd - set DEBUG=*,-not_this - ``` - -Then, run the program to be debugged as usual. - -## Millisecond diff - - When actively developing an application it can be useful to see when the time spent between one `debug()` call and the next. Suppose for example you invoke `debug()` before requesting a resource, and after as well, the "+NNNms" will show you how much time was spent between calls. - - ![](http://f.cl.ly/items/2i3h1d3t121M2Z1A3Q0N/Screenshot.png) - - When stdout is not a TTY, `Date#toUTCString()` is used, making it more useful for logging the debug information as shown below: - - ![](http://f.cl.ly/items/112H3i0e0o0P0a2Q2r11/Screenshot.png) - -## Conventions - - If you're using this in one or more of your libraries, you _should_ use the name of your library so that developers may toggle debugging as desired without guessing names. If you have more than one debuggers you _should_ prefix them with your library name and use ":" to separate features. For example "bodyParser" from Connect would then be "connect:bodyParser". - -## Wildcards - - The `*` character may be used as a wildcard. Suppose for example your library has debuggers named "connect:bodyParser", "connect:compress", "connect:session", instead of listing all three with `DEBUG=connect:bodyParser,connect:compress,connect:session`, you may simply do `DEBUG=connect:*`, or to run everything using this module simply use `DEBUG=*`. - - You can also exclude specific debuggers by prefixing them with a "-" character. For example, `DEBUG=*,-connect:*` would include all debuggers except those starting with "connect:". - -## Browser support - - Debug works in the browser as well, currently persisted by `localStorage`. Consider the situation shown below where you have `worker:a` and `worker:b`, and wish to debug both. Somewhere in the code on your page, include: - -```js -window.myDebug = require("debug"); -``` - - ("debug" is a global object in the browser so we give this object a different name.) When your page is open in the browser, type the following in the console: - -```js -myDebug.enable("worker:*") -``` - - Refresh the page. Debug output will continue to be sent to the console until it is disabled by typing `myDebug.disable()` in the console. - -```js -a = debug('worker:a'); -b = debug('worker:b'); - -setInterval(function(){ - a('doing some work'); -}, 1000); - -setInterval(function(){ - b('doing some work'); -}, 1200); -``` - -#### Web Inspector Colors - - Colors are also enabled on "Web Inspectors" that understand the `%c` formatting - option. These are WebKit web inspectors, Firefox ([since version - 31](https://hacks.mozilla.org/2014/05/editable-box-model-multiple-selection-sublime-text-keys-much-more-firefox-developer-tools-episode-31/)) - and the Firebug plugin for Firefox (any version). - - Colored output looks something like: - - ![](https://cloud.githubusercontent.com/assets/71256/3139768/b98c5fd8-e8ef-11e3-862a-f7253b6f47c6.png) - -### stderr vs stdout - -You can set an alternative logging method per-namespace by overriding the `log` method on a per-namespace or globally: - -Example _stdout.js_: - -```js -var debug = require('debug'); -var error = debug('app:error'); - -// by default stderr is used -error('goes to stderr!'); - -var log = debug('app:log'); -// set this namespace to log via console.log -log.log = console.log.bind(console); // don't forget to bind to console! -log('goes to stdout'); -error('still goes to stderr!'); - -// set all output to go via console.info -// overrides all per-namespace log settings -debug.log = console.info.bind(console); -error('now goes to stdout via console.info'); -log('still goes to stdout, but via console.info now'); -``` - -### Save debug output to a file - -You can save all debug statements to a file by piping them. - -Example: - -```bash -$ DEBUG_FD=3 node your-app.js 3> whatever.log -``` - -## Authors - - - TJ Holowaychuk - - Nathan Rajlich - -## License - -(The MIT License) - -Copyright (c) 2014 TJ Holowaychuk <tj@vision-media.ca> - -Permission is hereby granted, free of charge, to any person obtaining -a copy of this software and associated documentation files (the -'Software'), to deal in the Software without restriction, including -without limitation the rights to use, copy, modify, merge, publish, -distribute, sublicense, and/or sell copies of the Software, and to -permit persons to whom the Software is furnished to do so, subject to -the following conditions: - -The above copyright notice and this permission notice shall be -included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. -IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY -CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, -TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE -SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/test/fixtures/module-fixture/node_modules/pmx/node_modules/debug/bower.json b/test/fixtures/module-fixture/node_modules/pmx/node_modules/debug/bower.json deleted file mode 100644 index 6af573ff..00000000 --- a/test/fixtures/module-fixture/node_modules/pmx/node_modules/debug/bower.json +++ /dev/null @@ -1,28 +0,0 @@ -{ - "name": "visionmedia-debug", - "main": "dist/debug.js", - "version": "2.2.0", - "homepage": "https://github.com/visionmedia/debug", - "authors": [ - "TJ Holowaychuk " - ], - "description": "visionmedia-debug", - "moduleType": [ - "amd", - "es6", - "globals", - "node" - ], - "keywords": [ - "visionmedia", - "debug" - ], - "license": "MIT", - "ignore": [ - "**/.*", - "node_modules", - "bower_components", - "test", - "tests" - ] -} diff --git a/test/fixtures/module-fixture/node_modules/pmx/node_modules/debug/browser.js b/test/fixtures/module-fixture/node_modules/pmx/node_modules/debug/browser.js deleted file mode 100644 index 7c764522..00000000 --- a/test/fixtures/module-fixture/node_modules/pmx/node_modules/debug/browser.js +++ /dev/null @@ -1,168 +0,0 @@ - -/** - * This is the web browser implementation of `debug()`. - * - * Expose `debug()` as the module. - */ - -exports = module.exports = require('./debug'); -exports.log = log; -exports.formatArgs = formatArgs; -exports.save = save; -exports.load = load; -exports.useColors = useColors; -exports.storage = 'undefined' != typeof chrome - && 'undefined' != typeof chrome.storage - ? chrome.storage.local - : localstorage(); - -/** - * Colors. - */ - -exports.colors = [ - 'lightseagreen', - 'forestgreen', - 'goldenrod', - 'dodgerblue', - 'darkorchid', - 'crimson' -]; - -/** - * Currently only WebKit-based Web Inspectors, Firefox >= v31, - * and the Firebug extension (any Firefox version) are known - * to support "%c" CSS customizations. - * - * TODO: add a `localStorage` variable to explicitly enable/disable colors - */ - -function useColors() { - // is webkit? http://stackoverflow.com/a/16459606/376773 - return ('WebkitAppearance' in document.documentElement.style) || - // is firebug? http://stackoverflow.com/a/398120/376773 - (window.console && (console.firebug || (console.exception && console.table))) || - // is firefox >= v31? - // https://developer.mozilla.org/en-US/docs/Tools/Web_Console#Styling_messages - (navigator.userAgent.toLowerCase().match(/firefox\/(\d+)/) && parseInt(RegExp.$1, 10) >= 31); -} - -/** - * Map %j to `JSON.stringify()`, since no Web Inspectors do that by default. - */ - -exports.formatters.j = function(v) { - return JSON.stringify(v); -}; - - -/** - * Colorize log arguments if enabled. - * - * @api public - */ - -function formatArgs() { - var args = arguments; - var useColors = this.useColors; - - args[0] = (useColors ? '%c' : '') - + this.namespace - + (useColors ? ' %c' : ' ') - + args[0] - + (useColors ? '%c ' : ' ') - + '+' + exports.humanize(this.diff); - - if (!useColors) return args; - - var c = 'color: ' + this.color; - args = [args[0], c, 'color: inherit'].concat(Array.prototype.slice.call(args, 1)); - - // the final "%c" is somewhat tricky, because there could be other - // arguments passed either before or after the %c, so we need to - // figure out the correct index to insert the CSS into - var index = 0; - var lastC = 0; - args[0].replace(/%[a-z%]/g, function(match) { - if ('%%' === match) return; - index++; - if ('%c' === match) { - // we only are interested in the *last* %c - // (the user may have provided their own) - lastC = index; - } - }); - - args.splice(lastC, 0, c); - return args; -} - -/** - * Invokes `console.log()` when available. - * No-op when `console.log` is not a "function". - * - * @api public - */ - -function log() { - // this hackery is required for IE8/9, where - // the `console.log` function doesn't have 'apply' - return 'object' === typeof console - && console.log - && Function.prototype.apply.call(console.log, console, arguments); -} - -/** - * Save `namespaces`. - * - * @param {String} namespaces - * @api private - */ - -function save(namespaces) { - try { - if (null == namespaces) { - exports.storage.removeItem('debug'); - } else { - exports.storage.debug = namespaces; - } - } catch(e) {} -} - -/** - * Load `namespaces`. - * - * @return {String} returns the previously persisted debug modes - * @api private - */ - -function load() { - var r; - try { - r = exports.storage.debug; - } catch(e) {} - return r; -} - -/** - * Enable namespaces listed in `localStorage.debug` initially. - */ - -exports.enable(load()); - -/** - * Localstorage attempts to return the localstorage. - * - * This is necessary because safari throws - * when a user disables cookies/localstorage - * and you attempt to access it. - * - * @return {LocalStorage} - * @api private - */ - -function localstorage(){ - try { - return window.localStorage; - } catch (e) {} -} diff --git a/test/fixtures/module-fixture/node_modules/pmx/node_modules/debug/component.json b/test/fixtures/module-fixture/node_modules/pmx/node_modules/debug/component.json deleted file mode 100644 index ca106372..00000000 --- a/test/fixtures/module-fixture/node_modules/pmx/node_modules/debug/component.json +++ /dev/null @@ -1,19 +0,0 @@ -{ - "name": "debug", - "repo": "visionmedia/debug", - "description": "small debugging utility", - "version": "2.2.0", - "keywords": [ - "debug", - "log", - "debugger" - ], - "main": "browser.js", - "scripts": [ - "browser.js", - "debug.js" - ], - "dependencies": { - "rauchg/ms.js": "0.7.1" - } -} diff --git a/test/fixtures/module-fixture/node_modules/pmx/node_modules/debug/debug.js b/test/fixtures/module-fixture/node_modules/pmx/node_modules/debug/debug.js deleted file mode 100644 index 7571a860..00000000 --- a/test/fixtures/module-fixture/node_modules/pmx/node_modules/debug/debug.js +++ /dev/null @@ -1,197 +0,0 @@ - -/** - * This is the common logic for both the Node.js and web browser - * implementations of `debug()`. - * - * Expose `debug()` as the module. - */ - -exports = module.exports = debug; -exports.coerce = coerce; -exports.disable = disable; -exports.enable = enable; -exports.enabled = enabled; -exports.humanize = require('ms'); - -/** - * The currently active debug mode names, and names to skip. - */ - -exports.names = []; -exports.skips = []; - -/** - * Map of special "%n" handling functions, for the debug "format" argument. - * - * Valid key names are a single, lowercased letter, i.e. "n". - */ - -exports.formatters = {}; - -/** - * Previously assigned color. - */ - -var prevColor = 0; - -/** - * Previous log timestamp. - */ - -var prevTime; - -/** - * Select a color. - * - * @return {Number} - * @api private - */ - -function selectColor() { - return exports.colors[prevColor++ % exports.colors.length]; -} - -/** - * Create a debugger with the given `namespace`. - * - * @param {String} namespace - * @return {Function} - * @api public - */ - -function debug(namespace) { - - // define the `disabled` version - function disabled() { - } - disabled.enabled = false; - - // define the `enabled` version - function enabled() { - - var self = enabled; - - // set `diff` timestamp - var curr = +new Date(); - var ms = curr - (prevTime || curr); - self.diff = ms; - self.prev = prevTime; - self.curr = curr; - prevTime = curr; - - // add the `color` if not set - if (null == self.useColors) self.useColors = exports.useColors(); - if (null == self.color && self.useColors) self.color = selectColor(); - - var args = Array.prototype.slice.call(arguments); - - args[0] = exports.coerce(args[0]); - - if ('string' !== typeof args[0]) { - // anything else let's inspect with %o - args = ['%o'].concat(args); - } - - // apply any `formatters` transformations - var index = 0; - args[0] = args[0].replace(/%([a-z%])/g, function(match, format) { - // if we encounter an escaped % then don't increase the array index - if (match === '%%') return match; - index++; - var formatter = exports.formatters[format]; - if ('function' === typeof formatter) { - var val = args[index]; - match = formatter.call(self, val); - - // now we need to remove `args[index]` since it's inlined in the `format` - args.splice(index, 1); - index--; - } - return match; - }); - - if ('function' === typeof exports.formatArgs) { - args = exports.formatArgs.apply(self, args); - } - var logFn = enabled.log || exports.log || console.log.bind(console); - logFn.apply(self, args); - } - enabled.enabled = true; - - var fn = exports.enabled(namespace) ? enabled : disabled; - - fn.namespace = namespace; - - return fn; -} - -/** - * Enables a debug mode by namespaces. This can include modes - * separated by a colon and wildcards. - * - * @param {String} namespaces - * @api public - */ - -function enable(namespaces) { - exports.save(namespaces); - - var split = (namespaces || '').split(/[\s,]+/); - var len = split.length; - - for (var i = 0; i < len; i++) { - if (!split[i]) continue; // ignore empty strings - namespaces = split[i].replace(/\*/g, '.*?'); - if (namespaces[0] === '-') { - exports.skips.push(new RegExp('^' + namespaces.substr(1) + '$')); - } else { - exports.names.push(new RegExp('^' + namespaces + '$')); - } - } -} - -/** - * Disable debug output. - * - * @api public - */ - -function disable() { - exports.enable(''); -} - -/** - * Returns true if the given mode name is enabled, false otherwise. - * - * @param {String} name - * @return {Boolean} - * @api public - */ - -function enabled(name) { - var i, len; - for (i = 0, len = exports.skips.length; i < len; i++) { - if (exports.skips[i].test(name)) { - return false; - } - } - for (i = 0, len = exports.names.length; i < len; i++) { - if (exports.names[i].test(name)) { - return true; - } - } - return false; -} - -/** - * Coerce `val`. - * - * @param {Mixed} val - * @return {Mixed} - * @api private - */ - -function coerce(val) { - if (val instanceof Error) return val.stack || val.message; - return val; -} diff --git a/test/fixtures/module-fixture/node_modules/pmx/node_modules/debug/node.js b/test/fixtures/module-fixture/node_modules/pmx/node_modules/debug/node.js deleted file mode 100644 index 1d392a81..00000000 --- a/test/fixtures/module-fixture/node_modules/pmx/node_modules/debug/node.js +++ /dev/null @@ -1,209 +0,0 @@ - -/** - * Module dependencies. - */ - -var tty = require('tty'); -var util = require('util'); - -/** - * This is the Node.js implementation of `debug()`. - * - * Expose `debug()` as the module. - */ - -exports = module.exports = require('./debug'); -exports.log = log; -exports.formatArgs = formatArgs; -exports.save = save; -exports.load = load; -exports.useColors = useColors; - -/** - * Colors. - */ - -exports.colors = [6, 2, 3, 4, 5, 1]; - -/** - * The file descriptor to write the `debug()` calls to. - * Set the `DEBUG_FD` env variable to override with another value. i.e.: - * - * $ DEBUG_FD=3 node script.js 3>debug.log - */ - -var fd = parseInt(process.env.DEBUG_FD, 10) || 2; -var stream = 1 === fd ? process.stdout : - 2 === fd ? process.stderr : - createWritableStdioStream(fd); - -/** - * Is stdout a TTY? Colored output is enabled when `true`. - */ - -function useColors() { - var debugColors = (process.env.DEBUG_COLORS || '').trim().toLowerCase(); - if (0 === debugColors.length) { - return tty.isatty(fd); - } else { - return '0' !== debugColors - && 'no' !== debugColors - && 'false' !== debugColors - && 'disabled' !== debugColors; - } -} - -/** - * Map %o to `util.inspect()`, since Node doesn't do that out of the box. - */ - -var inspect = (4 === util.inspect.length ? - // node <= 0.8.x - function (v, colors) { - return util.inspect(v, void 0, void 0, colors); - } : - // node > 0.8.x - function (v, colors) { - return util.inspect(v, { colors: colors }); - } -); - -exports.formatters.o = function(v) { - return inspect(v, this.useColors) - .replace(/\s*\n\s*/g, ' '); -}; - -/** - * Adds ANSI color escape codes if enabled. - * - * @api public - */ - -function formatArgs() { - var args = arguments; - var useColors = this.useColors; - var name = this.namespace; - - if (useColors) { - var c = this.color; - - args[0] = ' \u001b[3' + c + ';1m' + name + ' ' - + '\u001b[0m' - + args[0] + '\u001b[3' + c + 'm' - + ' +' + exports.humanize(this.diff) + '\u001b[0m'; - } else { - args[0] = new Date().toUTCString() - + ' ' + name + ' ' + args[0]; - } - return args; -} - -/** - * Invokes `console.error()` with the specified arguments. - */ - -function log() { - return stream.write(util.format.apply(this, arguments) + '\n'); -} - -/** - * Save `namespaces`. - * - * @param {String} namespaces - * @api private - */ - -function save(namespaces) { - if (null == namespaces) { - // If you set a process.env field to null or undefined, it gets cast to the - // string 'null' or 'undefined'. Just delete instead. - delete process.env.DEBUG; - } else { - process.env.DEBUG = namespaces; - } -} - -/** - * Load `namespaces`. - * - * @return {String} returns the previously persisted debug modes - * @api private - */ - -function load() { - return process.env.DEBUG; -} - -/** - * Copied from `node/src/node.js`. - * - * XXX: It's lame that node doesn't expose this API out-of-the-box. It also - * relies on the undocumented `tty_wrap.guessHandleType()` which is also lame. - */ - -function createWritableStdioStream (fd) { - var stream; - var tty_wrap = process.binding('tty_wrap'); - - // Note stream._type is used for test-module-load-list.js - - switch (tty_wrap.guessHandleType(fd)) { - case 'TTY': - stream = new tty.WriteStream(fd); - stream._type = 'tty'; - - // Hack to have stream not keep the event loop alive. - // See https://github.com/joyent/node/issues/1726 - if (stream._handle && stream._handle.unref) { - stream._handle.unref(); - } - break; - - case 'FILE': - var fs = require('fs'); - stream = new fs.SyncWriteStream(fd, { autoClose: false }); - stream._type = 'fs'; - break; - - case 'PIPE': - case 'TCP': - var net = require('net'); - stream = new net.Socket({ - fd: fd, - readable: false, - writable: true - }); - - // FIXME Should probably have an option in net.Socket to create a - // stream from an existing fd which is writable only. But for now - // we'll just add this hack and set the `readable` member to false. - // Test: ./node test/fixtures/echo.js < /etc/passwd - stream.readable = false; - stream.read = null; - stream._type = 'pipe'; - - // FIXME Hack to have stream not keep the event loop alive. - // See https://github.com/joyent/node/issues/1726 - if (stream._handle && stream._handle.unref) { - stream._handle.unref(); - } - break; - - default: - // Probably an error on in uv_guess_handle() - throw new Error('Implement me. Unknown stream file type!'); - } - - // For supporting legacy API we put the FD here. - stream.fd = fd; - - stream._isStdio = true; - - return stream; -} - -/** - * Enable namespaces listed in `process.env.DEBUG` initially. - */ - -exports.enable(load()); diff --git a/test/fixtures/module-fixture/node_modules/pmx/node_modules/debug/node_modules/ms/.npmignore b/test/fixtures/module-fixture/node_modules/pmx/node_modules/debug/node_modules/ms/.npmignore deleted file mode 100644 index d1aa0ce4..00000000 --- a/test/fixtures/module-fixture/node_modules/pmx/node_modules/debug/node_modules/ms/.npmignore +++ /dev/null @@ -1,5 +0,0 @@ -node_modules -test -History.md -Makefile -component.json diff --git a/test/fixtures/module-fixture/node_modules/pmx/node_modules/debug/node_modules/ms/History.md b/test/fixtures/module-fixture/node_modules/pmx/node_modules/debug/node_modules/ms/History.md deleted file mode 100644 index 32fdfc17..00000000 --- a/test/fixtures/module-fixture/node_modules/pmx/node_modules/debug/node_modules/ms/History.md +++ /dev/null @@ -1,66 +0,0 @@ - -0.7.1 / 2015-04-20 -================== - - * prevent extraordinary long inputs (@evilpacket) - * Fixed broken readme link - -0.7.0 / 2014-11-24 -================== - - * add time abbreviations, updated tests and readme for the new units - * fix example in the readme. - * add LICENSE file - -0.6.2 / 2013-12-05 -================== - - * Adding repository section to package.json to suppress warning from NPM. - -0.6.1 / 2013-05-10 -================== - - * fix singularization [visionmedia] - -0.6.0 / 2013-03-15 -================== - - * fix minutes - -0.5.1 / 2013-02-24 -================== - - * add component namespace - -0.5.0 / 2012-11-09 -================== - - * add short formatting as default and .long option - * add .license property to component.json - * add version to component.json - -0.4.0 / 2012-10-22 -================== - - * add rounding to fix crazy decimals - -0.3.0 / 2012-09-07 -================== - - * fix `ms()` [visionmedia] - -0.2.0 / 2012-09-03 -================== - - * add component.json [visionmedia] - * add days support [visionmedia] - * add hours support [visionmedia] - * add minutes support [visionmedia] - * add seconds support [visionmedia] - * add ms string support [visionmedia] - * refactor tests to facilitate ms(number) [visionmedia] - -0.1.0 / 2012-03-07 -================== - - * Initial release diff --git a/test/fixtures/module-fixture/node_modules/pmx/node_modules/debug/node_modules/ms/LICENSE b/test/fixtures/module-fixture/node_modules/pmx/node_modules/debug/node_modules/ms/LICENSE deleted file mode 100644 index 6c07561b..00000000 --- a/test/fixtures/module-fixture/node_modules/pmx/node_modules/debug/node_modules/ms/LICENSE +++ /dev/null @@ -1,20 +0,0 @@ -(The MIT License) - -Copyright (c) 2014 Guillermo Rauch - -Permission is hereby granted, free of charge, to any person obtaining a copy of -this software and associated documentation files (the "Software"), to deal in -the Software without restriction, including without limitation the rights to -use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of -the Software, and to permit persons to whom the Software is furnished to do so, -subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS -FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR -COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER -IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN -CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/test/fixtures/module-fixture/node_modules/pmx/node_modules/debug/node_modules/ms/README.md b/test/fixtures/module-fixture/node_modules/pmx/node_modules/debug/node_modules/ms/README.md deleted file mode 100644 index 9b4fd035..00000000 --- a/test/fixtures/module-fixture/node_modules/pmx/node_modules/debug/node_modules/ms/README.md +++ /dev/null @@ -1,35 +0,0 @@ -# ms.js: miliseconds conversion utility - -```js -ms('2 days') // 172800000 -ms('1d') // 86400000 -ms('10h') // 36000000 -ms('2.5 hrs') // 9000000 -ms('2h') // 7200000 -ms('1m') // 60000 -ms('5s') // 5000 -ms('100') // 100 -``` - -```js -ms(60000) // "1m" -ms(2 * 60000) // "2m" -ms(ms('10 hours')) // "10h" -``` - -```js -ms(60000, { long: true }) // "1 minute" -ms(2 * 60000, { long: true }) // "2 minutes" -ms(ms('10 hours'), { long: true }) // "10 hours" -``` - -- Node/Browser compatible. Published as [`ms`](https://www.npmjs.org/package/ms) in [NPM](http://nodejs.org/download). -- If a number is supplied to `ms`, a string with a unit is returned. -- If a string that contains the number is supplied, it returns it as -a number (e.g: it returns `100` for `'100'`). -- If you pass a string with a number and a valid unit, the number of -equivalent ms is returned. - -## License - -MIT diff --git a/test/fixtures/module-fixture/node_modules/pmx/node_modules/debug/node_modules/ms/index.js b/test/fixtures/module-fixture/node_modules/pmx/node_modules/debug/node_modules/ms/index.js deleted file mode 100644 index 4f927716..00000000 --- a/test/fixtures/module-fixture/node_modules/pmx/node_modules/debug/node_modules/ms/index.js +++ /dev/null @@ -1,125 +0,0 @@ -/** - * Helpers. - */ - -var s = 1000; -var m = s * 60; -var h = m * 60; -var d = h * 24; -var y = d * 365.25; - -/** - * Parse or format the given `val`. - * - * Options: - * - * - `long` verbose formatting [false] - * - * @param {String|Number} val - * @param {Object} options - * @return {String|Number} - * @api public - */ - -module.exports = function(val, options){ - options = options || {}; - if ('string' == typeof val) return parse(val); - return options.long - ? long(val) - : short(val); -}; - -/** - * Parse the given `str` and return milliseconds. - * - * @param {String} str - * @return {Number} - * @api private - */ - -function parse(str) { - str = '' + str; - if (str.length > 10000) return; - var match = /^((?:\d+)?\.?\d+) *(milliseconds?|msecs?|ms|seconds?|secs?|s|minutes?|mins?|m|hours?|hrs?|h|days?|d|years?|yrs?|y)?$/i.exec(str); - if (!match) return; - var n = parseFloat(match[1]); - var type = (match[2] || 'ms').toLowerCase(); - switch (type) { - case 'years': - case 'year': - case 'yrs': - case 'yr': - case 'y': - return n * y; - case 'days': - case 'day': - case 'd': - return n * d; - case 'hours': - case 'hour': - case 'hrs': - case 'hr': - case 'h': - return n * h; - case 'minutes': - case 'minute': - case 'mins': - case 'min': - case 'm': - return n * m; - case 'seconds': - case 'second': - case 'secs': - case 'sec': - case 's': - return n * s; - case 'milliseconds': - case 'millisecond': - case 'msecs': - case 'msec': - case 'ms': - return n; - } -} - -/** - * Short format for `ms`. - * - * @param {Number} ms - * @return {String} - * @api private - */ - -function short(ms) { - if (ms >= d) return Math.round(ms / d) + 'd'; - if (ms >= h) return Math.round(ms / h) + 'h'; - if (ms >= m) return Math.round(ms / m) + 'm'; - if (ms >= s) return Math.round(ms / s) + 's'; - return ms + 'ms'; -} - -/** - * Long format for `ms`. - * - * @param {Number} ms - * @return {String} - * @api private - */ - -function long(ms) { - return plural(ms, d, 'day') - || plural(ms, h, 'hour') - || plural(ms, m, 'minute') - || plural(ms, s, 'second') - || ms + ' ms'; -} - -/** - * Pluralization helper. - */ - -function plural(ms, n, name) { - if (ms < n) return; - if (ms < n * 1.5) return Math.floor(ms / n) + ' ' + name; - return Math.ceil(ms / n) + ' ' + name + 's'; -} diff --git a/test/fixtures/module-fixture/node_modules/pmx/node_modules/debug/node_modules/ms/package.json b/test/fixtures/module-fixture/node_modules/pmx/node_modules/debug/node_modules/ms/package.json deleted file mode 100644 index 253335e6..00000000 --- a/test/fixtures/module-fixture/node_modules/pmx/node_modules/debug/node_modules/ms/package.json +++ /dev/null @@ -1,48 +0,0 @@ -{ - "name": "ms", - "version": "0.7.1", - "description": "Tiny ms conversion utility", - "repository": { - "type": "git", - "url": "git://github.com/guille/ms.js.git" - }, - "main": "./index", - "devDependencies": { - "mocha": "*", - "expect.js": "*", - "serve": "*" - }, - "component": { - "scripts": { - "ms/index.js": "index.js" - } - }, - "gitHead": "713dcf26d9e6fd9dbc95affe7eff9783b7f1b909", - "bugs": { - "url": "https://github.com/guille/ms.js/issues" - }, - "homepage": "https://github.com/guille/ms.js", - "_id": "ms@0.7.1", - "scripts": {}, - "_shasum": "9cd13c03adbff25b65effde7ce864ee952017098", - "_from": "ms@0.7.1", - "_npmVersion": "2.7.5", - "_nodeVersion": "0.12.2", - "_npmUser": { - "name": "rauchg", - "email": "rauchg@gmail.com" - }, - "maintainers": [ - { - "name": "rauchg", - "email": "rauchg@gmail.com" - } - ], - "dist": { - "shasum": "9cd13c03adbff25b65effde7ce864ee952017098", - "tarball": "http://registry.npmjs.org/ms/-/ms-0.7.1.tgz" - }, - "directories": {}, - "_resolved": "https://registry.npmjs.org/ms/-/ms-0.7.1.tgz", - "readme": "ERROR: No README data found!" -} diff --git a/test/fixtures/module-fixture/node_modules/pmx/node_modules/debug/package.json b/test/fixtures/module-fixture/node_modules/pmx/node_modules/debug/package.json deleted file mode 100644 index 7e6d9fc5..00000000 --- a/test/fixtures/module-fixture/node_modules/pmx/node_modules/debug/package.json +++ /dev/null @@ -1,73 +0,0 @@ -{ - "name": "debug", - "version": "2.2.0", - "repository": { - "type": "git", - "url": "git://github.com/visionmedia/debug.git" - }, - "description": "small debugging utility", - "keywords": [ - "debug", - "log", - "debugger" - ], - "author": { - "name": "TJ Holowaychuk", - "email": "tj@vision-media.ca" - }, - "contributors": [ - { - "name": "Nathan Rajlich", - "email": "nathan@tootallnate.net", - "url": "http://n8.io" - } - ], - "license": "MIT", - "dependencies": { - "ms": "0.7.1" - }, - "devDependencies": { - "browserify": "9.0.3", - "mocha": "*" - }, - "main": "./node.js", - "browser": "./browser.js", - "component": { - "scripts": { - "debug/index.js": "browser.js", - "debug/debug.js": "debug.js" - } - }, - "gitHead": "b38458422b5aa8aa6d286b10dfe427e8a67e2b35", - "bugs": { - "url": "https://github.com/visionmedia/debug/issues" - }, - "homepage": "https://github.com/visionmedia/debug", - "_id": "debug@2.2.0", - "scripts": {}, - "_shasum": "f87057e995b1a1f6ae6a4960664137bc56f039da", - "_from": "debug@*", - "_npmVersion": "2.7.4", - "_nodeVersion": "0.12.2", - "_npmUser": { - "name": "tootallnate", - "email": "nathan@tootallnate.net" - }, - "maintainers": [ - { - "name": "tjholowaychuk", - "email": "tj@vision-media.ca" - }, - { - "name": "tootallnate", - "email": "nathan@tootallnate.net" - } - ], - "dist": { - "shasum": "f87057e995b1a1f6ae6a4960664137bc56f039da", - "tarball": "http://registry.npmjs.org/debug/-/debug-2.2.0.tgz" - }, - "directories": {}, - "_resolved": "https://registry.npmjs.org/debug/-/debug-2.2.0.tgz", - "readme": "ERROR: No README data found!" -} diff --git a/test/fixtures/module-fixture/node_modules/pmx/node_modules/json-stringify-safe/.npmignore b/test/fixtures/module-fixture/node_modules/pmx/node_modules/json-stringify-safe/.npmignore deleted file mode 100644 index 17d6b367..00000000 --- a/test/fixtures/module-fixture/node_modules/pmx/node_modules/json-stringify-safe/.npmignore +++ /dev/null @@ -1 +0,0 @@ -/*.tgz diff --git a/test/fixtures/module-fixture/node_modules/pmx/node_modules/json-stringify-safe/CHANGELOG.md b/test/fixtures/module-fixture/node_modules/pmx/node_modules/json-stringify-safe/CHANGELOG.md deleted file mode 100644 index 42bcb60a..00000000 --- a/test/fixtures/module-fixture/node_modules/pmx/node_modules/json-stringify-safe/CHANGELOG.md +++ /dev/null @@ -1,14 +0,0 @@ -## Unreleased -- Fixes stringify to only take ancestors into account when checking - circularity. - It previously assumed every visited object was circular which led to [false - positives][issue9]. - Uses the tiny serializer I wrote for [Must.js][must] a year and a half ago. -- Fixes calling the `replacer` function in the proper context (`thisArg`). -- Fixes calling the `cycleReplacer` function in the proper context (`thisArg`). -- Speeds serializing by a factor of - Big-O(h-my-god-it-linearly-searched-every-object) it had ever seen. Searching - only the ancestors for a circular references speeds up things considerably. - -[must]: https://github.com/moll/js-must -[issue9]: https://github.com/isaacs/json-stringify-safe/issues/9 diff --git a/test/fixtures/module-fixture/node_modules/pmx/node_modules/json-stringify-safe/LICENSE b/test/fixtures/module-fixture/node_modules/pmx/node_modules/json-stringify-safe/LICENSE deleted file mode 100644 index 19129e31..00000000 --- a/test/fixtures/module-fixture/node_modules/pmx/node_modules/json-stringify-safe/LICENSE +++ /dev/null @@ -1,15 +0,0 @@ -The ISC License - -Copyright (c) Isaac Z. Schlueter and Contributors - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR -IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. diff --git a/test/fixtures/module-fixture/node_modules/pmx/node_modules/json-stringify-safe/Makefile b/test/fixtures/module-fixture/node_modules/pmx/node_modules/json-stringify-safe/Makefile deleted file mode 100644 index 36088c72..00000000 --- a/test/fixtures/module-fixture/node_modules/pmx/node_modules/json-stringify-safe/Makefile +++ /dev/null @@ -1,35 +0,0 @@ -NODE_OPTS = -TEST_OPTS = - -love: - @echo "Feel like makin' love." - -test: - @node $(NODE_OPTS) ./node_modules/.bin/_mocha -R dot $(TEST_OPTS) - -spec: - @node $(NODE_OPTS) ./node_modules/.bin/_mocha -R spec $(TEST_OPTS) - -autotest: - @node $(NODE_OPTS) ./node_modules/.bin/_mocha -R dot --watch $(TEST_OPTS) - -autospec: - @node $(NODE_OPTS) ./node_modules/.bin/_mocha -R spec --watch $(TEST_OPTS) - -pack: - @file=$$(npm pack); echo "$$file"; tar tf "$$file" - -publish: - npm publish - -tag: - git tag "v$$(node -e 'console.log(require("./package").version)')" - -clean: - rm -f *.tgz - npm prune --production - -.PHONY: love -.PHONY: test spec autotest autospec -.PHONY: pack publish tag -.PHONY: clean diff --git a/test/fixtures/module-fixture/node_modules/pmx/node_modules/json-stringify-safe/README.md b/test/fixtures/module-fixture/node_modules/pmx/node_modules/json-stringify-safe/README.md deleted file mode 100644 index a11f302a..00000000 --- a/test/fixtures/module-fixture/node_modules/pmx/node_modules/json-stringify-safe/README.md +++ /dev/null @@ -1,52 +0,0 @@ -# json-stringify-safe - -Like JSON.stringify, but doesn't throw on circular references. - -## Usage - -Takes the same arguments as `JSON.stringify`. - -```javascript -var stringify = require('json-stringify-safe'); -var circularObj = {}; -circularObj.circularRef = circularObj; -circularObj.list = [ circularObj, circularObj ]; -console.log(stringify(circularObj, null, 2)); -``` - -Output: - -```json -{ - "circularRef": "[Circular]", - "list": [ - "[Circular]", - "[Circular]" - ] -} -``` - -## Details - -``` -stringify(obj, serializer, indent, decycler) -``` - -The first three arguments are the same as to JSON.stringify. The last -is an argument that's only used when the object has been seen already. - -The default `decycler` function returns the string `'[Circular]'`. -If, for example, you pass in `function(k,v){}` (return nothing) then it -will prune cycles. If you pass in `function(k,v){ return {foo: 'bar'}}`, -then cyclical objects will always be represented as `{"foo":"bar"}` in -the result. - -``` -stringify.getSerialize(serializer, decycler) -``` - -Returns a serializer that can be used elsewhere. This is the actual -function that's passed to JSON.stringify. - -**Note** that the function returned from `getSerialize` is stateful for now, so -do **not** use it more than once. diff --git a/test/fixtures/module-fixture/node_modules/pmx/node_modules/json-stringify-safe/package.json b/test/fixtures/module-fixture/node_modules/pmx/node_modules/json-stringify-safe/package.json deleted file mode 100644 index 7a97649f..00000000 --- a/test/fixtures/module-fixture/node_modules/pmx/node_modules/json-stringify-safe/package.json +++ /dev/null @@ -1,68 +0,0 @@ -{ - "name": "json-stringify-safe", - "version": "5.0.1", - "description": "Like JSON.stringify, but doesn't blow up on circular refs.", - "keywords": [ - "json", - "stringify", - "circular", - "safe" - ], - "homepage": "https://github.com/isaacs/json-stringify-safe", - "bugs": { - "url": "https://github.com/isaacs/json-stringify-safe/issues" - }, - "author": { - "name": "Isaac Z. Schlueter", - "email": "i@izs.me", - "url": "http://blog.izs.me" - }, - "contributors": [ - { - "name": "Andri Möll", - "email": "andri@dot.ee", - "url": "http://themoll.com" - } - ], - "license": "ISC", - "repository": { - "type": "git", - "url": "git://github.com/isaacs/json-stringify-safe.git" - }, - "main": "stringify.js", - "scripts": { - "test": "node test.js" - }, - "devDependencies": { - "mocha": ">= 2.1.0 < 3", - "must": ">= 0.12 < 0.13", - "sinon": ">= 1.12.2 < 2" - }, - "gitHead": "3890dceab3ad14f8701e38ca74f38276abc76de5", - "_id": "json-stringify-safe@5.0.1", - "_shasum": "1296a2d58fd45f19a0f6ce01d65701e2c735b6eb", - "_from": "json-stringify-safe@*", - "_npmVersion": "2.10.0", - "_nodeVersion": "2.0.1", - "_npmUser": { - "name": "isaacs", - "email": "isaacs@npmjs.com" - }, - "dist": { - "shasum": "1296a2d58fd45f19a0f6ce01d65701e2c735b6eb", - "tarball": "http://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz" - }, - "maintainers": [ - { - "name": "isaacs", - "email": "i@izs.me" - }, - { - "name": "moll", - "email": "andri@dot.ee" - } - ], - "directories": {}, - "_resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", - "readme": "ERROR: No README data found!" -} diff --git a/test/fixtures/module-fixture/node_modules/pmx/node_modules/json-stringify-safe/stringify.js b/test/fixtures/module-fixture/node_modules/pmx/node_modules/json-stringify-safe/stringify.js deleted file mode 100644 index 124a4521..00000000 --- a/test/fixtures/module-fixture/node_modules/pmx/node_modules/json-stringify-safe/stringify.js +++ /dev/null @@ -1,27 +0,0 @@ -exports = module.exports = stringify -exports.getSerialize = serializer - -function stringify(obj, replacer, spaces, cycleReplacer) { - return JSON.stringify(obj, serializer(replacer, cycleReplacer), spaces) -} - -function serializer(replacer, cycleReplacer) { - var stack = [], keys = [] - - if (cycleReplacer == null) cycleReplacer = function(key, value) { - if (stack[0] === value) return "[Circular ~]" - return "[Circular ~." + keys.slice(0, stack.indexOf(value)).join(".") + "]" - } - - return function(key, value) { - if (stack.length > 0) { - var thisPos = stack.indexOf(this) - ~thisPos ? stack.splice(thisPos + 1) : stack.push(this) - ~thisPos ? keys.splice(thisPos, Infinity, key) : keys.push(key) - if (~stack.indexOf(value)) value = cycleReplacer.call(this, key, value) - } - else stack.push(value) - - return replacer == null ? value : replacer.call(this, key, value) - } -} diff --git a/test/fixtures/module-fixture/node_modules/pmx/node_modules/json-stringify-safe/test/mocha.opts b/test/fixtures/module-fixture/node_modules/pmx/node_modules/json-stringify-safe/test/mocha.opts deleted file mode 100644 index 2544e586..00000000 --- a/test/fixtures/module-fixture/node_modules/pmx/node_modules/json-stringify-safe/test/mocha.opts +++ /dev/null @@ -1,2 +0,0 @@ ---recursive ---require must diff --git a/test/fixtures/module-fixture/node_modules/pmx/node_modules/json-stringify-safe/test/stringify_test.js b/test/fixtures/module-fixture/node_modules/pmx/node_modules/json-stringify-safe/test/stringify_test.js deleted file mode 100644 index 5b325831..00000000 --- a/test/fixtures/module-fixture/node_modules/pmx/node_modules/json-stringify-safe/test/stringify_test.js +++ /dev/null @@ -1,246 +0,0 @@ -var Sinon = require("sinon") -var stringify = require("..") -function jsonify(obj) { return JSON.stringify(obj, null, 2) } - -describe("Stringify", function() { - it("must stringify circular objects", function() { - var obj = {name: "Alice"} - obj.self = obj - var json = stringify(obj, null, 2) - json.must.eql(jsonify({name: "Alice", self: "[Circular ~]"})) - }) - - it("must stringify circular objects with intermediaries", function() { - var obj = {name: "Alice"} - obj.identity = {self: obj} - var json = stringify(obj, null, 2) - json.must.eql(jsonify({name: "Alice", identity: {self: "[Circular ~]"}})) - }) - - it("must stringify circular objects deeper", function() { - var obj = {name: "Alice", child: {name: "Bob"}} - obj.child.self = obj.child - - stringify(obj, null, 2).must.eql(jsonify({ - name: "Alice", - child: {name: "Bob", self: "[Circular ~.child]"} - })) - }) - - it("must stringify circular objects deeper with intermediaries", function() { - var obj = {name: "Alice", child: {name: "Bob"}} - obj.child.identity = {self: obj.child} - - stringify(obj, null, 2).must.eql(jsonify({ - name: "Alice", - child: {name: "Bob", identity: {self: "[Circular ~.child]"}} - })) - }) - - it("must stringify circular objects in an array", function() { - var obj = {name: "Alice"} - obj.self = [obj, obj] - - stringify(obj, null, 2).must.eql(jsonify({ - name: "Alice", self: ["[Circular ~]", "[Circular ~]"] - })) - }) - - it("must stringify circular objects deeper in an array", function() { - var obj = {name: "Alice", children: [{name: "Bob"}, {name: "Eve"}]} - obj.children[0].self = obj.children[0] - obj.children[1].self = obj.children[1] - - stringify(obj, null, 2).must.eql(jsonify({ - name: "Alice", - children: [ - {name: "Bob", self: "[Circular ~.children.0]"}, - {name: "Eve", self: "[Circular ~.children.1]"} - ] - })) - }) - - it("must stringify circular arrays", function() { - var obj = [] - obj.push(obj) - obj.push(obj) - var json = stringify(obj, null, 2) - json.must.eql(jsonify(["[Circular ~]", "[Circular ~]"])) - }) - - it("must stringify circular arrays with intermediaries", function() { - var obj = [] - obj.push({name: "Alice", self: obj}) - obj.push({name: "Bob", self: obj}) - - stringify(obj, null, 2).must.eql(jsonify([ - {name: "Alice", self: "[Circular ~]"}, - {name: "Bob", self: "[Circular ~]"} - ])) - }) - - it("must stringify repeated objects in objects", function() { - var obj = {} - var alice = {name: "Alice"} - obj.alice1 = alice - obj.alice2 = alice - - stringify(obj, null, 2).must.eql(jsonify({ - alice1: {name: "Alice"}, - alice2: {name: "Alice"} - })) - }) - - it("must stringify repeated objects in arrays", function() { - var alice = {name: "Alice"} - var obj = [alice, alice] - var json = stringify(obj, null, 2) - json.must.eql(jsonify([{name: "Alice"}, {name: "Alice"}])) - }) - - it("must call given decycler and use its output", function() { - var obj = {} - obj.a = obj - obj.b = obj - - var decycle = Sinon.spy(function() { return decycle.callCount }) - var json = stringify(obj, null, 2, decycle) - json.must.eql(jsonify({a: 1, b: 2}, null, 2)) - - decycle.callCount.must.equal(2) - decycle.thisValues[0].must.equal(obj) - decycle.args[0][0].must.equal("a") - decycle.args[0][1].must.equal(obj) - decycle.thisValues[1].must.equal(obj) - decycle.args[1][0].must.equal("b") - decycle.args[1][1].must.equal(obj) - }) - - it("must call replacer and use its output", function() { - var obj = {name: "Alice", child: {name: "Bob"}} - - var replacer = Sinon.spy(bangString) - var json = stringify(obj, replacer, 2) - json.must.eql(jsonify({name: "Alice!", child: {name: "Bob!"}})) - - replacer.callCount.must.equal(4) - replacer.args[0][0].must.equal("") - replacer.args[0][1].must.equal(obj) - replacer.thisValues[1].must.equal(obj) - replacer.args[1][0].must.equal("name") - replacer.args[1][1].must.equal("Alice") - replacer.thisValues[2].must.equal(obj) - replacer.args[2][0].must.equal("child") - replacer.args[2][1].must.equal(obj.child) - replacer.thisValues[3].must.equal(obj.child) - replacer.args[3][0].must.equal("name") - replacer.args[3][1].must.equal("Bob") - }) - - it("must call replacer after describing circular references", function() { - var obj = {name: "Alice"} - obj.self = obj - - var replacer = Sinon.spy(bangString) - var json = stringify(obj, replacer, 2) - json.must.eql(jsonify({name: "Alice!", self: "[Circular ~]!"})) - - replacer.callCount.must.equal(3) - replacer.args[0][0].must.equal("") - replacer.args[0][1].must.equal(obj) - replacer.thisValues[1].must.equal(obj) - replacer.args[1][0].must.equal("name") - replacer.args[1][1].must.equal("Alice") - replacer.thisValues[2].must.equal(obj) - replacer.args[2][0].must.equal("self") - replacer.args[2][1].must.equal("[Circular ~]") - }) - - it("must call given decycler and use its output for nested objects", - function() { - var obj = {} - obj.a = obj - obj.b = {self: obj} - - var decycle = Sinon.spy(function() { return decycle.callCount }) - var json = stringify(obj, null, 2, decycle) - json.must.eql(jsonify({a: 1, b: {self: 2}})) - - decycle.callCount.must.equal(2) - decycle.args[0][0].must.equal("a") - decycle.args[0][1].must.equal(obj) - decycle.args[1][0].must.equal("self") - decycle.args[1][1].must.equal(obj) - }) - - it("must use decycler's output when it returned null", function() { - var obj = {a: "b"} - obj.self = obj - obj.selves = [obj, obj] - - function decycle() { return null } - stringify(obj, null, 2, decycle).must.eql(jsonify({ - a: "b", - self: null, - selves: [null, null] - })) - }) - - it("must use decycler's output when it returned undefined", function() { - var obj = {a: "b"} - obj.self = obj - obj.selves = [obj, obj] - - function decycle() {} - stringify(obj, null, 2, decycle).must.eql(jsonify({ - a: "b", - selves: [null, null] - })) - }) - - it("must throw given a decycler that returns a cycle", function() { - var obj = {} - obj.self = obj - var err - function identity(key, value) { return value } - try { stringify(obj, null, 2, identity) } catch (ex) { err = ex } - err.must.be.an.instanceof(TypeError) - }) - - describe(".getSerialize", function() { - it("must stringify circular objects", function() { - var obj = {a: "b"} - obj.circularRef = obj - obj.list = [obj, obj] - - var json = JSON.stringify(obj, stringify.getSerialize(), 2) - json.must.eql(jsonify({ - "a": "b", - "circularRef": "[Circular ~]", - "list": ["[Circular ~]", "[Circular ~]"] - })) - }) - - // This is the behavior as of Mar 3, 2015. - // The serializer function keeps state inside the returned function and - // so far I'm not sure how to not do that. JSON.stringify's replacer is not - // called _after_ serialization. - xit("must return a function that could be called twice", function() { - var obj = {name: "Alice"} - obj.self = obj - - var json - var serializer = stringify.getSerialize() - - json = JSON.stringify(obj, serializer, 2) - json.must.eql(jsonify({name: "Alice", self: "[Circular ~]"})) - - json = JSON.stringify(obj, serializer, 2) - json.must.eql(jsonify({name: "Alice", self: "[Circular ~]"})) - }) - }) -}) - -function bangString(key, value) { - return typeof value == "string" ? value + "!" : value -} diff --git a/test/fixtures/module-fixture/node_modules/pmx/package.json b/test/fixtures/module-fixture/node_modules/pmx/package.json deleted file mode 100644 index dc51be59..00000000 --- a/test/fixtures/module-fixture/node_modules/pmx/package.json +++ /dev/null @@ -1,38 +0,0 @@ -{ - "name": "pmx", - "version": "0.3.23", - "description": "Keymetrics++ and PM2 adapter", - "main": "index.js", - "dependencies": { - "debug": "*", - "json-stringify-safe": "*" - }, - "devDependencies": { - "express": "*", - "request": "*", - "should": "*", - "mocha": "*", - "shelljs": "*" - }, - "scripts": { - "test": "DEBUG='axm:*' mocha test/*.mocha.js" - }, - "repository": { - "type": "git", - "url": "git+https://github.com/keymetrics/pmx.git" - }, - "author": { - "name": "Keymetrics I/O" - }, - "license": "MIT", - "readme": "\n# Driver for Keymetrics\n\n![Keymetrics](https://keymetrics.io/assets/images/application-demo.png)\n\nPMX is a module that allows you to create advanced interactions with Keymetrics.\n\nWith it you can:\n- Trigger remote actions / functions\n- Analyze custom metrics / variables (with utilities like Histogram/Counter/Metric/Meters)\n- Report errors (uncaught exceptions and custom errors)\n- Emit events\n- Analyze HTTP latency\n\n# Installation\n\n![Build Status](https://api.travis-ci.org/keymetrics/pmx.png?branch=master)\n\nInstall PMX and add it to your package.json via:\n\n```bash\n$ npm install pmx --save\n```\n\nThen init the module to monitor HTTP, Errors and diverse metrics.\n```javascript\nvar pmx = require('pmx').init(); // By default everything is enabled and ignore_routes is empty\n```\nOr choose what to monitor.\n```javascript\nvar pmx = require('pmx').init({\n http : true, // HTTP routes logging (default: true)\n ignore_routes : [/socket\\.io/, /notFound/], // Ignore http routes with this pattern (Default: [])\n errors : true, // Exceptions loggin (default: true)\n custom_probes : true, // Custom probes (default: true)\n network : true, // Traffic usage monitoring (default: false)\n ports : true // Shows which ports your app is listening on (default: false)\n});\n```\n\n# Custom monitoring\n\n## Emit Events\n\nEmit events and get historical and statistics:\n\n```javascript\nvar pmx = require('pmx');\n\npmx.emit('user:register', {\n user : 'Alex registered',\n email : 'thorustor@gmail.com'\n});\n```\n\n## Custom Action\n\nTrigger function from Keymetrics\n\n### Long running\n\n```javascript\nvar pmx = require('pmx');\n\npmx.action('db:clean', { comment : 'Description for this action' }, function(reply) {\n clean.db(function() {\n /**\n * reply() must be called at the end of the action\n */\n reply({success : true});\n });\n});\n```\n\n## Errors\n\nCatch uncaught exceptions:\n```javascript\nvar pmx = require('pmx').init();\n```\n\nAttach more data from errors that happens in Express:\n```javascript\nvar pmx = require('pmx');\n\napp.get('/' ...);\napp.post(...);\n\napp.use(pmx.expressErrorHandler());\n```\n\nTrigger custom errors:\n```javascript\nvar pmx = require('pmx');\n\npmx.notify({ success : false });\n\npmx.notify('This is an error');\n\npmx.notify(new Error('This is an error'));\n```\n\n## TCP network usage monitoring\n\nIf you enable the flag `network: true` when you init pmx it will show network usage datas (download and upload) in realtime.\n\nIf you enable the flag `ports: true` when you init pmx it will show which ports your app is listenting on.\n\n\n## HTTP latency analysis\n\nMonitor routes, latency and codes. REST compliant.\n\n```javascript\npmx.http(); // You must do this BEFORE any require('http')\n```\nIgnore some routes by passing a list of regular expressions.\n```javascript\npmx.http({\n http : true, // (Default: true)\n ignore_routes : [/socket\\.io/, /notFound/] // Ignore http routes with this pattern (Default: [])\n});\n```\nThis can also be done via pmx.init()\n```javascript\npmx.init({\n http : true, // (Default: true)\n ignore_routes : [/socket\\.io/, /notFound/] // Ignore http routes with this pattern (Default: [])\n});\n```\n\n**This module is enabled by default if you called pmx with the init() function.**\n\n## Measure\n\nMeasure critical segments of you code thanks to 4 kind of probes:\n\n- Simple metrics: Values that can be read instantly\n - Monitor variable value\n- Counter: Things that increment or decrement\n - Downloads being processed, user connected\n- Meter: Things that are measured as events / interval\n - Request per minute for a http server\n- Histogram: Keeps a resevoir of statistically relevant values biased towards the last 5 minutes to explore their distribution\n - Monitor the mean of execution of a query into database\n\n#### Common options\n\n- `name` : The probe name as is will be displayed on the **Keymetrics** dashboard\n- `agg_type` : This param is optional, it can be `sum`, `max`, `min`, `avg` (default) or `none`. It will impact the way the probe data are aggregated within the **Keymetrics** backend. Use `none` if this is irrelevant (eg: constant or string value).\n\n\n### Metric\n\nValues that can be read instantly.\n\n```javascript\nvar probe = pmx.probe();\n\nvar metric = probe.metric({\n name : 'Realtime user',\n agg_type: 'max',\n value : function() {\n return Object.keys(users).length;\n }\n});\n```\n\n### Counter\n\nThings that increment or decrement.\n\n```javascript\nvar probe = pmx.probe();\n\nvar counter = probe.counter({\n name : 'Downloads',\n agg_type: 'sum'\n});\n\nhttp.createServer(function(req, res) {\n counter.inc();\n req.on('end', function() {\n counter.dec();\n });\n});\n```\n\n### Meter\n\nThings that are measured as events / interval.\n\n```javascript\nvar probe = pmx.probe();\n\nvar meter = probe.meter({\n name : 'req/sec',\n samples : 1,\n timeframe : 60\n});\n\nhttp.createServer(function(req, res) {\n meter.mark();\n res.end({success:true});\n});\n```\n#### Options\n\n**samples** option is the rate unit. Defaults to **1** sec.\n\n**timeframe** option is the timeframe over which events will be analyzed. Defaults to **60** sec.\n\n### Histogram\n\nKeeps a resevoir of statistically relevant values biased towards the last 5 minutes to explore their distribution.\n\n```javascript\nvar probe = pmx.probe();\n\nvar histogram = probe.histogram({\n name : 'latency',\n measurement : 'mean'\n});\n\nvar latency = 0;\n\nsetInterval(function() {\n latency = Math.round(Math.random() * 100);\n histogram.update(latency);\n}, 100);\n```\n\n#### Options\n\n**measurement** option can be:\n\n- min: The lowest observed value.\n- max: The highest observed value.\n- sum: The sum of all observed values.\n- variance: The variance of all observed values.\n- mean: The average of all observed values.\n- stddev: The stddev of all observed values.\n- count: The number of observed values.\n- median: 50% of all values in the resevoir are at or below this value.\n- p75: See median, 75% percentile.\n- p95: See median, 95% percentile.\n- p99: See median, 99% percentile.\n- p999: See median, 99.9% percentile.\n\n## Expose data (JSON object)\n\n```javascript\npmx.transpose('variable name', function() { return my_data });\n\n// or\n\npmx.tranpose({\n name : 'variable name',\n value : function() { return my_data; }\n});\n```\n\n## Modules\n\n### Simple app\n\n```\nprocess.env.MODULE_DEBUG = true;\n\nvar pmx = require('pmx');\n\nvar conf = pmx.initModule();\n```\n\n# Beta\n\n### Long running with data emitter (scoped action)\n\nA scoped action is an action that can emit logs related to this action.\n\n```javascript\nvar pmx = require('pmx');\n\npmx.scopedAction('scoped:action', function(options, res) {\n var i = setInterval(function() {\n // Emit progress data\n if (error)\n res.error('oops');\n else\n res.send('this is a chunk of data');\n }, 1000);\n\n setTimeout(function() {\n clearInterval(i);\n return res.end();\n }, 8000);\n});\n```\n\n\n# License\n\nMIT\n", - "readmeFilename": "README.md", - "gitHead": "8f487ccb89d25d5bc1d23a0fc75a50ae7d9aab5a", - "bugs": { - "url": "https://github.com/keymetrics/pmx/issues" - }, - "homepage": "https://github.com/keymetrics/pmx#readme", - "_id": "pmx@0.3.23", - "_shasum": "fbb9c118f63109aedeb4309903898c70f978396b", - "_from": "pmx@*" -} diff --git a/test/fixtures/module-fixture/node_modules/pmx/test/action.mocha.js b/test/fixtures/module-fixture/node_modules/pmx/test/action.mocha.js deleted file mode 100644 index 3a195adb..00000000 --- a/test/fixtures/module-fixture/node_modules/pmx/test/action.mocha.js +++ /dev/null @@ -1,164 +0,0 @@ - - -var pmx = require('..'); - -function forkApp(script) { - var app = require('child_process').fork(__dirname + (script || '/proc.mock.js'), []); - return app; -} - -function forkAppWithOptions() { - var app = require('child_process').fork(__dirname + '/proc-option.mock.js', []); - return app; -} - -describe('Action module', function() { - - describe('Action without option', function() { - var app; - var action_name; - - after(function() { - process.kill(app.pid); - }); - - it('should notify PM2 of a new action available', function(done) { - app = forkApp(); - - app.once('message', function(dt) { - dt.type.should.eql('axm:action'); - dt.data.action_name.should.eql('test:nab'); - dt.data.opts.comment.should.eql('This is a test'); - dt.data.opts.display.should.eql(true); - - action_name = dt.data.action_name; - - done(); - }); - }); - - it('should trigger the action', function(done) { - app.once('message', function(dt) { - dt.type.should.eql('axm:reply'); - dt.data.return.res.should.eql('hello moto'); - done(); - }); - - app.send(action_name); - }); - - it('should trigger the action via Object arity 1 (FALLBACK)', function(done) { - app.once('message', function(dt) { - dt.type.should.eql('axm:reply'); - dt.data.return.res.should.eql('hello moto'); - done(); - }); - - app.send({msg : action_name, opts : { sisi : 'true' }}); - }); - - it('should not trigger the action if wrong action name', function(done) { - app.once('message', function(dt) { - throw new Error('Should not be called'); - }); - - app.send({ - action_name : 'im unknown' - }); - - setTimeout(done, 200); - }); - }); - - describe('Action with extra options (parameters)', function() { - var app; - var action_name; - - after(function() { - process.kill(app.pid); - }); - - it('should notify PM2 of a new action available', function(done) { - app = forkAppWithOptions(); - - app.once('message', function(dt) { - dt.type.should.eql('axm:action'); - dt.data.action_name.should.eql('test:with:options'); - action_name = dt.data.action_name; - done(); - }); - }); - - it('should trigger the action without failing (2 args without option)', function(done) { - app.once('message', function(dt) { - dt.type.should.eql('axm:reply'); - dt.data.return.res.should.eql('hello moto'); - done(); - }); - - app.send(action_name); - }); - - it('should trigger the action', function(done) { - app.once('message', function(dt) { - dt.type.should.eql('axm:reply'); - dt.data.return.res.should.eql('hello moto'); - dt.data.return.options.f1.should.eql('ab'); - done(); - }); - - app.send({ msg : action_name, opts : { f1 : 'ab', f2 : 'cd'}}); - }); - - it('should not trigger the action if wrong action name', function(done) { - app.once('message', function(dt) { - throw new Error('Should not be called'); - }); - - app.send('im unknown'); - - setTimeout(done, 200); - }); - - }); - - describe('Scoped Action (option, emitter, callback)', function() { - var app; - var action_name; - - after(function() { - process.kill(app.pid); - }); - - it('should notify PM2 of a new action available', function(done) { - app = forkApp('/fixtures/scoped-action.fixture.js'); - - app.once('message', function(dt) { - dt.type.should.eql('axm:action'); - dt.data.action_name.should.eql('scoped:action'); - dt.data.action_type.should.eql('scoped'); - action_name = dt.data.action_name; - done(); - }); - }); - - it('should stream data', function(done) { - app.once('message', function(dt) { - dt.type.should.eql('axm:scoped_action:stream'); - dt.data.data.should.eql('data random'); - done(); - }); - - app.send({ action_name : action_name, uuid : 'Random nb'}); - }); - - it('should trigger the action', function(done) { - app.on('message', function(dt) { - if (dt.type == 'axm:scoped_action:end') - done(); - }); - }); - - }); - -}); diff --git a/test/fixtures/module-fixture/node_modules/pmx/test/auto.mocha.js b/test/fixtures/module-fixture/node_modules/pmx/test/auto.mocha.js deleted file mode 100644 index 7e4239ec..00000000 --- a/test/fixtures/module-fixture/node_modules/pmx/test/auto.mocha.js +++ /dev/null @@ -1,101 +0,0 @@ - - -var axm = require('..'); -var request = require('request'); -var should = require('should'); - -var Plan = require('./helpers/plan'); - -function fork() { - return require('child_process').fork(__dirname + '/transaction/app.mock.auto.js', []); -} - -describe('Automatic transaction', function() { - it('should have right properties', function(done) { - axm.should.have.property('http'); - done(); - }); - - var app; - - - after(function() { - process.kill(app.pid); - }); - - it('should receive configuration flag', function(done) { - app = fork(); - - app.once('message', function(data) { - data.type.should.eql('axm:option:configuration'); - done(); - }); - - }); - - it('should not log fast http request', function(done) { - var rcpt = function(data) { - if (data.type == 'axm:option:configuration') - return false; - if (data.type == 'axm:monitor') - return false; - - return data.type.should.not.eql('http:transaction'); - }; - - app.on('message', rcpt); - - setTimeout(function() { - app.removeListener('message', rcpt); - return done(); - }, 500); - - setTimeout(function() { - request('http://127.0.0.1:9007/', function(req, res) {}); - }, 100); - }); - - it('should not log ignored http request', function(done) { - var timer = setTimeout(function() { - app.removeListener('message', rcpt); - return done(); - }, 1000); - - var rcpt = function(data) { - if (data.type == 'axm:option:configuration') - return false; - if (data.type == 'axm:monitor') - return false; - - return data.type.should.not.eql('http:transaction'); - }; - - app.on('message', rcpt); - - setTimeout(function() { - request('http://127.0.0.1:9007/socket.io/slow', function(req, res) {}); - }, 100); - }); - - it('should log slow http request', function(done) { - var plan = new Plan(3, done); - - app.on('message', function(data) { - if (data.type == 'axm:monitor') { - plan.ok(true); - if (Object.keys(data.data) < 3) - plan.ok(false); - } - - if (data.type == 'http:transaction') { - data.data.should.have.properties('ip', 'time', 'url', 'method'); - plan.ok(true); - } - }); - - setTimeout(function() { - request('http://127.0.0.1:9007/slow', function(req, res) {}); - }, 100); - }); - -}); diff --git a/test/fixtures/module-fixture/node_modules/pmx/test/event.mocha.js b/test/fixtures/module-fixture/node_modules/pmx/test/event.mocha.js deleted file mode 100644 index 901597df..00000000 --- a/test/fixtures/module-fixture/node_modules/pmx/test/event.mocha.js +++ /dev/null @@ -1,38 +0,0 @@ - -var axm = require('..'); - -function fork() { - return require('child_process').fork(__dirname + '/event.mock.js', []); -} - -describe('Event', function() { - it('should have right property', function(done) { - axm.should.have.property('emit'); - done(); - }); - - describe('Event scenario', function() { - var app; - - before(function() { - app = fork(); - }); - - after(function() { - process.kill(app.pid); - }); - - it('should send right event data when called', function(done) { - app.once('message', function(data) { - data.type.should.eql('human:event'); - data.data.user.should.eql('toto'); - data.data.__name.should.eql('test'); - data.data.subobj.subobj.a.should.eql('b'); - done(); - }); - }); - }); - - - -}); diff --git a/test/fixtures/module-fixture/node_modules/pmx/test/event.mock.js b/test/fixtures/module-fixture/node_modules/pmx/test/event.mock.js deleted file mode 100644 index faacdcf5..00000000 --- a/test/fixtures/module-fixture/node_modules/pmx/test/event.mock.js +++ /dev/null @@ -1,13 +0,0 @@ - -var axm = require('..'); - -setInterval(function() { - axm.emit('test', { - user : 'toto', - subobj : { - subobj : { - a : 'b' - } - } - }); -}, 100); diff --git a/test/fixtures/module-fixture/node_modules/pmx/test/express/app.js b/test/fixtures/module-fixture/node_modules/pmx/test/express/app.js deleted file mode 100644 index 39da2a22..00000000 --- a/test/fixtures/module-fixture/node_modules/pmx/test/express/app.js +++ /dev/null @@ -1,23 +0,0 @@ - -var axm = require('../..'); -var express = require('express'); -var app = express(); - -var err = new Error('jajajja'); - -err.url = 'http://thd.com/'; - -axm.notify(err); - -app.get('/', function(req, res){ - res.send('Hello World'); -}); - -app.get('/error', function(req, res, next){ - next(new Error('toto')); -}); - -app.use(axm.expressErrorHandler()); - - -app.listen(3001); diff --git a/test/fixtures/module-fixture/node_modules/pmx/test/express/package.json b/test/fixtures/module-fixture/node_modules/pmx/test/express/package.json deleted file mode 100644 index a8c001f1..00000000 --- a/test/fixtures/module-fixture/node_modules/pmx/test/express/package.json +++ /dev/null @@ -1,14 +0,0 @@ -{ - "name": "express", - "version": "0.0.0", - "description": "", - "main": "index.js", - "scripts": { - "test": "echo \"Error: no test specified\" && exit 1" - }, - "dependencies" : { - "express" : "*" - }, - "author": "", - "license": "ISC" -} diff --git a/test/fixtures/module-fixture/node_modules/pmx/test/fixtures/histogram.fixture.js b/test/fixtures/module-fixture/node_modules/pmx/test/fixtures/histogram.fixture.js deleted file mode 100644 index f8a2776a..00000000 --- a/test/fixtures/module-fixture/node_modules/pmx/test/fixtures/histogram.fixture.js +++ /dev/null @@ -1,45 +0,0 @@ - - -var axm = require('../..'); - -var probe = axm.probe(); - -var histogram = probe.histogram({ - name : 'test', - measurement : 'p95', - agg_type: 'sum' -}); - -var a = 0; - -setInterval(function() { - a = Math.round(Math.random() * 100); - histogram.update(a); -}, 100); - -var h2 = probe.histogram({ - name : 'mean', - measurement : 'mean', - unit : 'ms' -}); - -var b = 0; - -setInterval(function() { - b = Math.round(Math.random() * 100); - h2.update(b); -}, 100); - - -var h3 = probe.histogram({ - name : 'min', - measurement : 'min', - agg_type: 'min' -}); - -var c = 0; - -setInterval(function() { - c = Math.round(Math.random() * 100); - h3.update(c); -}, 100); diff --git a/test/fixtures/module-fixture/node_modules/pmx/test/fixtures/module/module.fixture.js b/test/fixtures/module-fixture/node_modules/pmx/test/fixtures/module/module.fixture.js deleted file mode 100644 index b19db785..00000000 --- a/test/fixtures/module-fixture/node_modules/pmx/test/fixtures/module/module.fixture.js +++ /dev/null @@ -1,4 +0,0 @@ - -var pmx = require('../../..'); - -var conf = pmx.initModule(); diff --git a/test/fixtures/module-fixture/node_modules/pmx/test/fixtures/module/package.json b/test/fixtures/module-fixture/node_modules/pmx/test/fixtures/module/package.json deleted file mode 100644 index 8d00b455..00000000 --- a/test/fixtures/module-fixture/node_modules/pmx/test/fixtures/module/package.json +++ /dev/null @@ -1,14 +0,0 @@ -{ - "name": "module", - "version": "1.0.0", - "description": "comment", - "main": "module.fixture.js", - "scripts": { - "test": "echo \"Error: no test specified\" && exit 1" - }, - "config" : { - "initial" : "init-val" - }, - "author": "strzel", - "license": "ISC" -} diff --git a/test/fixtures/module-fixture/node_modules/pmx/test/fixtures/monitor.mock.js b/test/fixtures/module-fixture/node_modules/pmx/test/fixtures/monitor.mock.js deleted file mode 100644 index ba175350..00000000 --- a/test/fixtures/module-fixture/node_modules/pmx/test/fixtures/monitor.mock.js +++ /dev/null @@ -1,20 +0,0 @@ - -var axm = require('../..'); - -var obj = axm.enableProbes(); - -var i = 2; - -obj.it_works = true; -obj.value = 20; -obj.i = i; - -setTimeout(function() { - i = 4; - obj.it_works = false; - obj.value = 99; - - setTimeout(function() { - axm.stopProbes(); - }, 1100); -}, 1100); diff --git a/test/fixtures/module-fixture/node_modules/pmx/test/fixtures/monitor2.mock.js b/test/fixtures/module-fixture/node_modules/pmx/test/fixtures/monitor2.mock.js deleted file mode 100644 index b9216580..00000000 --- a/test/fixtures/module-fixture/node_modules/pmx/test/fixtures/monitor2.mock.js +++ /dev/null @@ -1,26 +0,0 @@ - - -var axm = require('../..'); - -var obj = axm.enableProbes(); - -var a = { - 'aaa' : { 'ok' : true }, - 'bbb' : { 'ok' : false } -}; - -// Does not refresh because it copies the val -obj.count = Object.keys(a).length; - -obj.countFn = function() { - return Object.keys(a).length; -}; - -setTimeout(function () { - a.ccc = 'test'; - a.ddd = 'test'; - - setTimeout(function () { - axm.stopProbes(); - }, 1100); -}, 1100); diff --git a/test/fixtures/module-fixture/node_modules/pmx/test/fixtures/notify.mock.js b/test/fixtures/module-fixture/node_modules/pmx/test/fixtures/notify.mock.js deleted file mode 100644 index 87d40422..00000000 --- a/test/fixtures/module-fixture/node_modules/pmx/test/fixtures/notify.mock.js +++ /dev/null @@ -1,6 +0,0 @@ - -var axm = require('../..'); - -setTimeout(function() { - axm.notify('hey'); -}, 100); diff --git a/test/fixtures/module-fixture/node_modules/pmx/test/fixtures/notify_catch_all.mock.js b/test/fixtures/module-fixture/node_modules/pmx/test/fixtures/notify_catch_all.mock.js deleted file mode 100644 index a05c44df..00000000 --- a/test/fixtures/module-fixture/node_modules/pmx/test/fixtures/notify_catch_all.mock.js +++ /dev/null @@ -1,9 +0,0 @@ - - -var axm = require('../..'); - -axm.catchAll(); - -setTimeout(function() { - throw new Error('global error'); -}, 200); diff --git a/test/fixtures/module-fixture/node_modules/pmx/test/fixtures/probe.fixture.js b/test/fixtures/module-fixture/node_modules/pmx/test/fixtures/probe.fixture.js deleted file mode 100644 index 89e30c27..00000000 --- a/test/fixtures/module-fixture/node_modules/pmx/test/fixtures/probe.fixture.js +++ /dev/null @@ -1,118 +0,0 @@ - -var axm = require('../..'); - -var probe = axm.probe(); - -var users = { - 'alex' : 'ok', - 'musta' : 'fa' -}; - -/** - * Monitor synchronous return of functions - */ -var rt_users = probe.metric({ - name : 'Realtime user', - agg_type: 'max', - value : function() { - return Object.keys(users).length; - } -}); - -/** - * Monitor value - */ - -var config_example = { - val : 'hey', - test : { - a : 'good', - sign : 'healthy' - } -} - -var cheerio = probe.metric({ - name : 'Cheerio', - value : function() { - return config_example; - } -}); - -/** - * Monitor value - */ - - -// probe.transpose('docker_config', config_example); - -probe.transpose({ - name : 'style_2_docker_config', - data : function doSomething() { - return config_example; - } -}); - -probe.transpose('style_1_docker_config', function doSomething() { - return config_example; -}); - - -/** - * Meter for HTTP - */ -var meter = probe.meter({ - name : 'req/min', - agg_type: 'min', - seconds : 60 -}); - -var http = require('http'); - -http.createServer(function(req, res) { - meter.mark(); - res.end('Thanks'); -}).listen(3400); - -/** - * Meter example - */ - -var meter2 = probe.meter({ - name : 'random', - unit : 'rd', - agg_type: 'sum', - seconds : 1 -}); - -setInterval(function() { - meter2.mark(Math.random() * 100); -}, 10); - - -setTimeout(function() { - counter.inc(); - config_example = { yes : true }; -}, 1100); - -/** - * Counter - */ - -var counter = probe.counter({ - name : 'Downloads', - agg_type: 'max' -}); - -counter.inc(); -counter.dec(); -counter.inc(); -counter.inc(); - -// console.log(cheerio.val()); -// setInterval(function() { -// console.log(counter.val()); -// console.log(meter.val()); -// console.log(meter2.val()); -// console.log(rt_users.val()); -// console.log(cheerio.val()); -// }, 1500); diff --git a/test/fixtures/module-fixture/node_modules/pmx/test/fixtures/scoped-action.fixture.js b/test/fixtures/module-fixture/node_modules/pmx/test/fixtures/scoped-action.fixture.js deleted file mode 100644 index ca3497f1..00000000 --- a/test/fixtures/module-fixture/node_modules/pmx/test/fixtures/scoped-action.fixture.js +++ /dev/null @@ -1,15 +0,0 @@ - - -var pmx = require('../..'); - -pmx.scopedAction('scoped:action', function(opts, res) { - var i = setInterval(function() { - // Emit progress data - res.send('data random'); - }, 100); - - setTimeout(function() { - clearInterval(i); - res.end('end data'); - }, 800); -}); diff --git a/test/fixtures/module-fixture/node_modules/pmx/test/fixtures/scoped-action.mocha.js b/test/fixtures/module-fixture/node_modules/pmx/test/fixtures/scoped-action.mocha.js deleted file mode 100644 index 8b137891..00000000 --- a/test/fixtures/module-fixture/node_modules/pmx/test/fixtures/scoped-action.mocha.js +++ /dev/null @@ -1 +0,0 @@ - diff --git a/test/fixtures/module-fixture/node_modules/pmx/test/fixtures/transpose.fixture.js b/test/fixtures/module-fixture/node_modules/pmx/test/fixtures/transpose.fixture.js deleted file mode 100644 index 8d7f926c..00000000 --- a/test/fixtures/module-fixture/node_modules/pmx/test/fixtures/transpose.fixture.js +++ /dev/null @@ -1,36 +0,0 @@ - -var axm = require('../..'); - -var probe = axm.probe(); - - -var config_example = { - val : 'hey', - test : { - a : 'good', - sign : 'healthy' - } -} - -/** - * Monitor value - */ - -// This is ompossible to do :( (refresh value by pointer): -// -// probe.transpose('docker_config', config_example); - -probe.transpose({ - name : 'style_2_docker_config', - data : function doSomething() { - return config_example; - } -}); - -probe.transpose('style_1_docker_config', function doSomething() { - return config_example; -}); - -setTimeout(function() { - config_example.val = 'new value'; -}, 1100); diff --git a/test/fixtures/module-fixture/node_modules/pmx/test/helpers/plan.js b/test/fixtures/module-fixture/node_modules/pmx/test/helpers/plan.js deleted file mode 100644 index 2523adcc..00000000 --- a/test/fixtures/module-fixture/node_modules/pmx/test/helpers/plan.js +++ /dev/null @@ -1,23 +0,0 @@ - -var assert = require('assert'); - -function Plan(count, done) { - this.done = done; - this.count = count; -} - -Plan.prototype.ok = function(expression) { - assert(expression); - - if (this.count === 0) { - assert(false, 'Too many assertions called'); - } else { - this.count--; - } - - if (this.count === 0) { - this.done(); - } -}; - -module.exports = Plan; diff --git a/test/fixtures/module-fixture/node_modules/pmx/test/mocha.opts b/test/fixtures/module-fixture/node_modules/pmx/test/mocha.opts deleted file mode 100644 index d3cb22ae..00000000 --- a/test/fixtures/module-fixture/node_modules/pmx/test/mocha.opts +++ /dev/null @@ -1,4 +0,0 @@ ---require should ---reporter spec ---timeout 30000000 ---slow 300 diff --git a/test/fixtures/module-fixture/node_modules/pmx/test/module.mocha.js b/test/fixtures/module-fixture/node_modules/pmx/test/module.mocha.js deleted file mode 100644 index 9f2982a4..00000000 --- a/test/fixtures/module-fixture/node_modules/pmx/test/module.mocha.js +++ /dev/null @@ -1,119 +0,0 @@ - -var pmx = require('..'); -var should = require('should'); - -function forkWithoutEnv() { - var app = require('child_process').fork(__dirname + '/fixtures/module/module.fixture.js', [], { - env : { - } - }); - return app; -} - -function forkWithSpecificVar() { - var app = require('child_process').fork(__dirname + '/fixtures/module/module.fixture.js', [], { - env : { - 'module' : '{ "option1" : "value1", "option2" : "value2", "initial" : "over" }' - } - }); - return app; -} - -describe('PMX module', function() { - var app; - var action_name; - - it('should emit a new action', function(done) { - // 1 - It should emit an action - app = forkWithoutEnv(); - - app.once('message', function(dt) { - - /** - * Right event sent - */ - dt.type.should.eql('axm:option:configuration'); - - /** - * Options set - */ - dt.data.show_module_meta.should.exists; - dt.data.description.should.eql('comment'); - dt.data.module_version.should.eql('1.0.0'); - dt.data.module_name.should.eql('module'); - - /** - * Configuration succesfully passed - */ - dt.data.initial.should.eql('init-val'); - - /** - * Should configuration variable be mirrored into module_conf - * attribute (for keymetrics purposes) - */ - dt.data.module_conf.initial.should.eql('init-val'); - done(); - }); - }); - - it('should emit a new action', function(done) { - // 1 - It should emit an action - app = forkWithSpecificVar(); - - app.once('message', function(dt) { - - /** - * Right event sent - */ - dt.type.should.eql('axm:option:configuration'); - - /** - * Options set - */ - dt.data.show_module_meta.should.exists; - dt.data.description.should.eql('comment'); - dt.data.module_version.should.eql('1.0.0'); - dt.data.module_name.should.eql('module'); - - /** - * Configuration succesfully passed - */ - dt.data.option1.should.eql('value1'); - dt.data.option2.should.eql('value2'); - dt.data.initial.should.eql('over'); - - /** - * Should configuration variable be mirrored into module_conf - * attribute (for keymetrics purposes) - */ - dt.data.module_conf.option1.should.eql('value1'); - dt.data.module_conf.option2.should.eql('value2'); - dt.data.module_conf.initial.should.eql('over'); - done(); - }); - }); - - it('should find existing file', function(done) { - var content = pmx.resolvePidPaths([ - 'asdasdsad', - 'asdasd', - 'lolilol', - __dirname + '/fixtures/file.pid' - ]); - - content.should.eql(1456); - done(); - }); - - it('should return null', function(done) { - var content = pmx.resolvePidPaths([ - 'asdasdsad', - 'asdasd', - 'lolilol' - ]); - - should(content).be.null; - done(); - }); - -}); diff --git a/test/fixtures/module-fixture/node_modules/pmx/test/monitor.mocha.js b/test/fixtures/module-fixture/node_modules/pmx/test/monitor.mocha.js deleted file mode 100644 index 859506d2..00000000 --- a/test/fixtures/module-fixture/node_modules/pmx/test/monitor.mocha.js +++ /dev/null @@ -1,65 +0,0 @@ - -var axm = require('..'); - -function fork() { - return require('child_process').fork(__dirname + '/fixtures/monitor.mock.js', []); -} - -function forkMonitor2() { - return require('child_process').fork(__dirname + '/fixtures/monitor2.mock.js', []); -} - -describe('Monitor', function() { - - it('should have properties', function(done) { - axm.should.have.property('enableProbes'); - done(); - }); - - - it('should send event when called', function(done) { - var app = fork(); - - app.once('message', function(pck) { - pck.type.should.eql('axm:monitor'); - - pck.data.it_works.should.eql(true); - pck.data.value.should.eql(20); - - app.once('message', function(pck) { - pck.type.should.eql('axm:monitor'); - - pck.data.it_works.should.eql(false); - pck.data.value.should.eql(99); - pck.data.i.should.eql(2); - - app.kill(); - - done(); - }); - }); - }); - - it('should send right value with monitor2', function(done) { - var app = forkMonitor2(); - - app.once('message', function(pck) { - pck.type.should.eql('axm:monitor'); - - pck.data.count.should.eql(2); - pck.data.countFn.should.eql(2); - - app.once('message', function(pck) { - pck.type.should.eql('axm:monitor'); - - pck.data.count.should.eql(2); - pck.data.countFn.should.eql(4); - - app.kill(); - - done(); - }); - }); - }); - -}); diff --git a/test/fixtures/module-fixture/node_modules/pmx/test/notify.mocha.js b/test/fixtures/module-fixture/node_modules/pmx/test/notify.mocha.js deleted file mode 100644 index c38e8cff..00000000 --- a/test/fixtures/module-fixture/node_modules/pmx/test/notify.mocha.js +++ /dev/null @@ -1,90 +0,0 @@ - - -var axm = require('..'); -var should = require('should'); - -function forkCatch() { - var app = require('child_process').fork(__dirname + '/fixtures/notify_catch_all.mock.js', []); - return app; -} - -function forkNotify() { - var app = require('child_process').fork(__dirname + '/fixtures/notify.mock.js', []); - return app; -} - -describe('Notify exceptions', function() { - it('should have the right properties', function(done) { - axm.should.have.property('catchAll'); - axm.should.have.property('notify'); - axm.should.have.property('expressErrorHandler'); - done(); - }); - - it('should process simple string error', function(done) { - var ret = axm._interpretError('this is a message'); - should.exist(ret.stack); - should.exist(ret.message); - ret.message.should.eql('this is a message'); - done(); - }); - - it('should process JSON object', function(done) { - var ret = axm._interpretError({ - line : 'ok', - env : 'sisi' - }); - - should.exist(ret.stack); - should.exist(ret.message); - - ret.data.line.should.eql('ok'); - ret.data.env.should.eql('sisi'); - done(); - }); - - it('should process simple string', function(done) { - var ret = axm._interpretError('Error'); - - should.exist(ret.stack); - should.exist(ret.message); - - done(); - }); - - it('should process error', function(done) { - var ret = axm._interpretError(new Error('error')); - - should.exist(ret.stack); - should.exist(ret.message); - - done(); - }); - - - it('should catchAll exception in fork mode', function(done) { - var app = forkCatch(); - - app.once('message', function(data) { - data.type.should.eql('axm:option:configuration'); - app.once('message', function(data) { - data.type.should.eql('process:exception'); - data.data.message.should.eql('global error'); - process.kill(app.pid); - done(); - }); - }); - }); - - it('should notify process about error', function(done) { - var app = forkNotify(); - - app.once('message', function(data) { - data.type.should.eql('process:exception'); - data.data.message.should.eql('hey'); - process.kill(app.pid); - done(); - }); - }); - -}); diff --git a/test/fixtures/module-fixture/node_modules/pmx/test/pmx.mocha.js b/test/fixtures/module-fixture/node_modules/pmx/test/pmx.mocha.js deleted file mode 100644 index 3f75ba81..00000000 --- a/test/fixtures/module-fixture/node_modules/pmx/test/pmx.mocha.js +++ /dev/null @@ -1,18 +0,0 @@ - -var pmx = require('..'); - -describe('PMX driver', function() { - it('should have the right properties', function(done) { - pmx.should.have.property('emit'); - pmx.should.have.property('action'); - done(); - }); - - describe('Event module', function() { - it('should not hang if process not forked', function(done) { - pmx.emit('testo', { data : 'ok' }); - done(); - }); - - }); -}); diff --git a/test/fixtures/module-fixture/node_modules/pmx/test/probe.mocha.js b/test/fixtures/module-fixture/node_modules/pmx/test/probe.mocha.js deleted file mode 100644 index 1b705454..00000000 --- a/test/fixtures/module-fixture/node_modules/pmx/test/probe.mocha.js +++ /dev/null @@ -1,83 +0,0 @@ - -var axm = require('..'); - -function fork(script) { - var app = require('child_process').fork(__dirname + (script || '/fixtures/probe.fixture.js'), []); - return app; -} - -function forkHistogram() { - var app = require('child_process').fork(__dirname + '/fixtures/histogram.fixture.js', []); - return app; - -} -describe('Probe', function() { - it('should have the right properties', function(done) { - axm.should.have.property('probe'); - - var probe = axm.probe(); - - probe.should.have.property('meter'); - probe.should.have.property('metric'); - probe.should.have.property('histogram'); - probe.should.have.property('counter'); - done(); - }); - - it('should fork app and receive data from probes', function(done) { - var app = fork(); - - app.on('message', function(pck) { - // Will iterate two times, metric change the value to false - pck.type.should.eql('axm:monitor'); - - pck.data.should.have.properties('req/min', - 'Realtime user', - 'random', - 'Cheerio'); - - if (pck.data.random.value && pck.data.random.agg_type == 'sum' && - pck.data.Cheerio.value.yes == true && pck.data.Cheerio.agg_type == 'avg' && - pck.data.Downloads.value > 1 && pck.data.Downloads.agg_type == 'max') { - app.kill(); - done(); - } - }); - }); - - it('should receive transposed data', function(done) { - var app = fork('/fixtures/transpose.fixture.js'); - var pass = 0; - - app.on('message', function(pck) { - // Will iterate two times, metric change the value to false - pck.type.should.eql('axm:monitor'); - - pck.data.should.have.properties('style_2_docker_config', - 'style_1_docker_config'); - - if (pck.data.style_1_docker_config.value.val == 'new value' && - pck.data.style_2_docker_config.value.val == 'new value') { - app.kill(); - done(); - } - }); - }); - - it('should fork app and receive data', function(done) { - var app = forkHistogram(); - - app.on('message', function(pck) { - pck.type.should.eql('axm:monitor'); - - if (pck.data.mean && pck.data.mean.agg_type == 'avg' && - pck.data.min && pck.data.min.agg_type == 'min' && - pck.data.test && pck.data.test.agg_type == 'sum') { - app.kill(); - done(); - } - }); - }); - - -}) diff --git a/test/fixtures/module-fixture/node_modules/pmx/test/proc-option.mock.js b/test/fixtures/module-fixture/node_modules/pmx/test/proc-option.mock.js deleted file mode 100644 index bcdd7794..00000000 --- a/test/fixtures/module-fixture/node_modules/pmx/test/proc-option.mock.js +++ /dev/null @@ -1,8 +0,0 @@ - - -var axm = require('..'); - -axm.action('test:with:options', function(options, reply) { - console.log('CHILD: Action test called from external process'); - reply({ res : 'hello moto', options : options}); -}); diff --git a/test/fixtures/module-fixture/node_modules/pmx/test/proc.mock.js b/test/fixtures/module-fixture/node_modules/pmx/test/proc.mock.js deleted file mode 100644 index 3bb99a4d..00000000 --- a/test/fixtures/module-fixture/node_modules/pmx/test/proc.mock.js +++ /dev/null @@ -1,7 +0,0 @@ - -var axm = require('..'); - -axm.action('test:nab', {comment : 'This is a test', display : true}, function(reply) { - console.log('CHILD: Action test called from external process'); - reply({ res : 'hello moto'}); -}); diff --git a/test/fixtures/module-fixture/node_modules/pmx/test/profiling.mocha.js b/test/fixtures/module-fixture/node_modules/pmx/test/profiling.mocha.js deleted file mode 100644 index 05da3f5b..00000000 --- a/test/fixtures/module-fixture/node_modules/pmx/test/profiling.mocha.js +++ /dev/null @@ -1,47 +0,0 @@ - -var pmx = require('..'); -var Profiling = require('../lib/probes/profiling.js'); -var should = require('should'); -var shelljs = require('shelljs'); - -describe('Profiling', function() { - it('should have right properties', function(done) { - pmx.should.have.property('v8Profiling'); - Profiling.should.have.property('detectV8Profiler'); - Profiling.should.have.property('exposeProfiling'); - Profiling.should.have.property('v8Profiling'); - done(); - }); - - it('should return error as v8-profiler not present', function(done) { - Profiling.detectV8Profiler(function(err, data) { - err.should.not.be.null; - should(data).be.undefined; - done(); - }); - }); - - describe.skip('V8-profiler', function() { - before(function(done) { - shelljs.exec('npm install v8-profiler', function() { - setTimeout(done, 10000); - }); - }); - - after(function(done) { - shelljs.exec('npm uninstall v8-profiler', function() { - done(); - }); - }); - - it('should detect v8 profiler', function(done) { - Profiling.detectV8Profiler(function(err, data) { - console.log(arguments); - err.should.not.be.null; - should(data).be.undefined; - done(); - }); - }); - }); - -}); diff --git a/test/fixtures/module-fixture/node_modules/pmx/test/transaction.pmx.js b/test/fixtures/module-fixture/node_modules/pmx/test/transaction.pmx.js deleted file mode 100644 index e69de29b..00000000 diff --git a/test/fixtures/module-fixture/node_modules/pmx/test/transaction/app.mock.auto.js b/test/fixtures/module-fixture/node_modules/pmx/test/transaction/app.mock.auto.js deleted file mode 100644 index 50cd2bd3..00000000 --- a/test/fixtures/module-fixture/node_modules/pmx/test/transaction/app.mock.auto.js +++ /dev/null @@ -1,37 +0,0 @@ - -require('../..').init({ - ignore_routes : [/\/socket\.io.*/] -}); - -var express = require('express'); -var app = express(); - -app.get('/', function(req, res) { - res.send(202, {success:true}); -}); - -app.get('/nothing', function(req, res) { - res.send('yes'); -}); - - -app.get('/slow', function(req, res) { - setTimeout(function() { - res.send('yes'); - }, 700); -}); - -app.get('/socket.io/slow', function(req, res) { - setTimeout(function() { - res.send('yes'); - }, 700); -}); - -app.get('/nothing2', function(req, res) { - setTimeout(function() { - res.send('yes'); - }, 1000); -}); - - -app.listen(9007); diff --git a/test/fixtures/module-fixture/node_modules/pmx/test/transaction/package.json b/test/fixtures/module-fixture/node_modules/pmx/test/transaction/package.json deleted file mode 100644 index bdc7199e..00000000 --- a/test/fixtures/module-fixture/node_modules/pmx/test/transaction/package.json +++ /dev/null @@ -1,14 +0,0 @@ -{ - "name": "transaction", - "version": "0.0.0", - "description": "", - "main": "index.js", - "scripts": { - "test": "echo \"Error: no test specified\" && exit 1" - }, - "devDependencies" : { - "express" : "*" - }, - "author": "", - "license": "ISC" -} From b85ca3caa3c68e18f7ce6954cc85e90a9d33efef Mon Sep 17 00:00:00 2001 From: Unitech Date: Fri, 11 May 2018 18:36:55 +0200 Subject: [PATCH 092/140] test: refactor before/after --- test/programmatic/custom_action.mocha.js | 12 ++++-------- test/programmatic/id.mocha.js | 14 +++----------- 2 files changed, 7 insertions(+), 19 deletions(-) diff --git a/test/programmatic/custom_action.mocha.js b/test/programmatic/custom_action.mocha.js index 9de735f8..6df8aaf3 100644 --- a/test/programmatic/custom_action.mocha.js +++ b/test/programmatic/custom_action.mocha.js @@ -5,16 +5,12 @@ var pm2 = require('../..'); var should = require('should'); describe('Custom actions via CLI/API', function() { - after(function(done) { - pm2.kill(done); + before(function(done) { + pm2.delete('all', function() { done() }); }); - before(function(done) { - pm2.connect(function() { - pm2.kill(function() { - pm2.connect(done); - }) - }); + after(function(done) { + pm2.delete('all', function() { done() }); }); it('should start custom action script', function(done) { diff --git a/test/programmatic/id.mocha.js b/test/programmatic/id.mocha.js index f792e7ef..1d879859 100644 --- a/test/programmatic/id.mocha.js +++ b/test/programmatic/id.mocha.js @@ -10,11 +10,11 @@ describe('Unique ID verification', function() { var _id = null before(function(done) { - PM2.kill(done); + PM2.delete('all', function() { done() }); }); - it('should connect to PM2', function(done) { - PM2.connect(done); + after(function(done) { + PM2.delete('all', function() { done() }); }); it('should start a script', function(done) { @@ -78,13 +78,5 @@ describe('Unique ID verification', function() { }); }); }); - - after(function(done) { - PM2.delete('all', done); - }); - - after(function(done) { - PM2.kill(done); - }); }); }); From 7a275e279ea01b1239e9dd8b9cf8e088e407b96d Mon Sep 17 00:00:00 2001 From: Unitech Date: Fri, 11 May 2018 18:51:23 +0200 Subject: [PATCH 093/140] test: adapt test to new api --- test/fixtures/interface/http_transaction.js | 5 ++++- test/interface/bus.fork.spec.mocha.js | 3 +-- test/interface/bus.spec.mocha.js | 3 +-- 3 files changed, 6 insertions(+), 5 deletions(-) diff --git a/test/fixtures/interface/http_transaction.js b/test/fixtures/interface/http_transaction.js index e72eee6c..9c88d11e 100644 --- a/test/fixtures/interface/http_transaction.js +++ b/test/fixtures/interface/http_transaction.js @@ -1,6 +1,9 @@ var axm = require('pm2.io'); -axm.http(); + +axm.init({ + http: true +}) var http = require('http'); diff --git a/test/interface/bus.fork.spec.mocha.js b/test/interface/bus.fork.spec.mocha.js index 281cd32b..5ad9f662 100644 --- a/test/interface/bus.fork.spec.mocha.js +++ b/test/interface/bus.fork.spec.mocha.js @@ -57,13 +57,12 @@ process.on('uncaughtException', function(e) { describe('PM2 BUS / RPC', function() { var pm2 = new PM2.custom({ - independent : true, cwd : __dirname + '/../fixtures/interface' }); var pm2_bus; after(function(done) { - pm2.destroy(done); + pm2.delete('all', () => done()); }); before(function(done) { diff --git a/test/interface/bus.spec.mocha.js b/test/interface/bus.spec.mocha.js index bbf593a9..3fcf29e2 100644 --- a/test/interface/bus.spec.mocha.js +++ b/test/interface/bus.spec.mocha.js @@ -59,13 +59,12 @@ process.on('uncaughtException', function(e) { describe('PM2 BUS / RPC', function() { var pm2 = new PM2.custom({ - independent : true, cwd : __dirname + '/../fixtures/interface' }); var pm2_bus; after(function(done) { - pm2.destroy(done); + pm2.delete('all', () => done()); }); before(function(done) { From dad38ed1bae849147f66e44186cd71c4b9cb022d Mon Sep 17 00:00:00 2001 From: Daniel Ruf Date: Sat, 12 May 2018 17:29:27 +0200 Subject: [PATCH 094/140] chore: clone last 5 commits --- .travis.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.travis.yml b/.travis.yml index a99f15a0..0c217f31 100644 --- a/.travis.yml +++ b/.travis.yml @@ -4,6 +4,8 @@ node_js: - "4" - "6" - "8" +git: + depth: 5 os: - linux before_install: From 81627e94c72efa1f4d726e20bbf67f0bbd5c116f Mon Sep 17 00:00:00 2001 From: Daniel Ruf Date: Sat, 12 May 2018 17:30:13 +0200 Subject: [PATCH 095/140] chore: cache node_modules --- .travis.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.travis.yml b/.travis.yml index a99f15a0..13e0e2be 100644 --- a/.travis.yml +++ b/.travis.yml @@ -4,6 +4,9 @@ node_js: - "4" - "6" - "8" +cache: + directories: + - node_modules os: - linux before_install: From d77bfbc3c8929851ee19ea604b2a6481d03771e3 Mon Sep 17 00:00:00 2001 From: vince Date: Thu, 17 May 2018 14:20:59 +0200 Subject: [PATCH 096/140] chore: add changelog generation into contributing.md --- CONTRIBUTING.md | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 83fa8bea..21dda9d7 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -100,3 +100,25 @@ This test files are located in test/bash/* - `$HOME/.pm2/pm2.pid` PM2 pid - `$HOME/.pm2/rpc.sock` Socket file for remote commands - `$HOME/.pm2/pub.sock` Socket file for publishable events + +## Generate changelog + +### requirements + +``` +npm install git-changelog -g +``` + +### usage + +Edit .changelogrc +Change "version_name" to the next version to release (example 1.1.2). +Change "tag" to the latest existing tag (example 1.1.1). + +Run the following command into pm2 directory +``` +git-changelog +``` + +It will generate currentTagChangelog.md file. +Just copy/paste the result into changelog.md From e8cd7131a6b9c9d497a2079bcbfc03770a753a06 Mon Sep 17 00:00:00 2001 From: Unitech Date: Thu, 17 May 2018 14:43:30 +0200 Subject: [PATCH 097/140] chore: right names as pm2 maintainers --- package.json | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/package.json b/package.json index 40992a87..0b5b50cc 100644 --- a/package.json +++ b/package.json @@ -1,3 +1,4 @@ + { "name": "pm2", "preferGlobal": true, @@ -12,25 +13,25 @@ }, "author": { "name": "Strzelewicz Alexandre", - "email": "alexandre@keymetrics.io", - "url": "https://keymetrics.io" + "email": "alexandre@pm2.io", + "url": "https://pm2.io" }, "maintainers": [ { - "name": "tknew", - "email": "strzelewicz.alexandre@gmail.com" + "name": "Alexandre Strzelewicz", + "email": "alexandre@pm2.io" }, { - "name": "soyuka", - "email": "soyuka@gmail.com" + "name": "Antoine Bluchet", + "email": "antoine@pm2.io" }, { - "name": "wallet77", - "email": "wallet77@gmail.com" + "name": "Vincent Vallet", + "email": "vincent@pm2.io" }, { - "name": "vmarchaud", - "email": "contact@vmarchaud.fr" + "name": "Valentin Marchaud", + "email": "valentin@pm2.io" } ], "contributors": [ From ae098962df35eee7f482dc0a514fd29a02a5f4ad Mon Sep 17 00:00:00 2001 From: Unitech Date: Thu, 17 May 2018 14:45:21 +0200 Subject: [PATCH 098/140] chore: pm2.io -> @pm2/io --- lib/API/Serve.js | 2 +- lib/ProcessUtils.js | 2 +- package.json | 2 +- test/fixtures/child_no_http.js | 2 +- test/fixtures/custom_actions/index.js | 2 +- test/fixtures/events/custom_action.js | 2 +- test/fixtures/events/custom_action_with_params.js | 2 +- test/fixtures/events/own_event.js | 2 +- test/fixtures/homogen-json-action/http.js | 2 +- test/fixtures/interface/http_transaction.js | 2 +- test/fixtures/interface/human_event.js | 2 +- test/fixtures/interface/process_exception.js | 2 +- test/fixtures/interface/process_exception_with_logs.js | 2 +- test/fixtures/module-fixture/scoped-action.js | 2 +- test/fixtures/probes.js | 2 +- test/fixtures/start-consistency/child.js | 2 +- 16 files changed, 16 insertions(+), 16 deletions(-) diff --git a/lib/API/Serve.js b/lib/API/Serve.js index 7fed27be..5027b25f 100644 --- a/lib/API/Serve.js +++ b/lib/API/Serve.js @@ -8,7 +8,7 @@ var http = require('http'); var url = require('url'); var path = require('path'); var debug = require('debug')('pm2:serve'); -var probe = require('pm2.io').probe(); +var probe = require('@pm2/io').probe(); /** * list of supported content types. diff --git a/lib/ProcessUtils.js b/lib/ProcessUtils.js index 72815dbf..0cc84f3b 100644 --- a/lib/ProcessUtils.js +++ b/lib/ProcessUtils.js @@ -1,7 +1,7 @@ module.exports = { injectModules: function() { if (process.env.pmx !== 'false') { - const pmx = require('pm2.io'); + const pmx = require('@pm2/io'); pmx.init({ transactions: (process.env.trace === 'true' || process.env.deep_monitoring === 'true') || false, http: process.env.km_link === 'true' || false, diff --git a/package.json b/package.json index 0b5b50cc..d268c609 100644 --- a/package.json +++ b/package.json @@ -159,7 +159,7 @@ "pm2-runtime": "./bin/pm2-runtime" }, "dependencies": { - "pm2.io": "latest", + "@pm2/io": "latest", "async": "^2.5", "blessed": "^0.1.81", "chalk": "^2.3.1", diff --git a/test/fixtures/child_no_http.js b/test/fixtures/child_no_http.js index 4e544844..f38d18c4 100644 --- a/test/fixtures/child_no_http.js +++ b/test/fixtures/child_no_http.js @@ -1,4 +1,4 @@ -var pmx = require('pm2.io').init({ +var pmx = require('@pm2/io').init({ http: false }); diff --git a/test/fixtures/custom_actions/index.js b/test/fixtures/custom_actions/index.js index c6f593d7..b68bdd9e 100644 --- a/test/fixtures/custom_actions/index.js +++ b/test/fixtures/custom_actions/index.js @@ -1,5 +1,5 @@ -var pmx = require('pm2.io'); +var pmx = require('@pm2/io'); pmx.action('ping', function(reply) { return reply({ 'pong' : 'hehe' }) diff --git a/test/fixtures/events/custom_action.js b/test/fixtures/events/custom_action.js index edbd929b..693d8b9a 100755 --- a/test/fixtures/events/custom_action.js +++ b/test/fixtures/events/custom_action.js @@ -1,5 +1,5 @@ -var axm = require('pm2.io'); +var axm = require('@pm2/io'); axm.action('refresh:db', function(reply) { console.log('Refreshing'); diff --git a/test/fixtures/events/custom_action_with_params.js b/test/fixtures/events/custom_action_with_params.js index 93784ed3..023c75e7 100755 --- a/test/fixtures/events/custom_action_with_params.js +++ b/test/fixtures/events/custom_action_with_params.js @@ -1,5 +1,5 @@ -var axm = require('pm2.io'); +var axm = require('@pm2/io'); axm.action('refresh:db', { comment : 'Refresh the database' }, function(reply) { console.log('Refreshing'); diff --git a/test/fixtures/events/own_event.js b/test/fixtures/events/own_event.js index b72fdfec..a0df61bc 100644 --- a/test/fixtures/events/own_event.js +++ b/test/fixtures/events/own_event.js @@ -1,5 +1,5 @@ -var axm = require('pm2.io'); +var axm = require('@pm2/io'); setInterval(function() { axm.emit('user:register', { diff --git a/test/fixtures/homogen-json-action/http.js b/test/fixtures/homogen-json-action/http.js index 546a6a2c..221eafbe 100644 --- a/test/fixtures/homogen-json-action/http.js +++ b/test/fixtures/homogen-json-action/http.js @@ -1,4 +1,4 @@ -var pmx = require('pm2.io').init({ +var pmx = require('@pm2/io').init({ http : true }); diff --git a/test/fixtures/interface/http_transaction.js b/test/fixtures/interface/http_transaction.js index 9c88d11e..1a3d9a69 100644 --- a/test/fixtures/interface/http_transaction.js +++ b/test/fixtures/interface/http_transaction.js @@ -1,5 +1,5 @@ -var axm = require('pm2.io'); +var axm = require('@pm2/io'); axm.init({ http: true diff --git a/test/fixtures/interface/human_event.js b/test/fixtures/interface/human_event.js index 856b9c00..e1807256 100644 --- a/test/fixtures/interface/human_event.js +++ b/test/fixtures/interface/human_event.js @@ -1,5 +1,5 @@ -var axm = require('pm2.io'); +var axm = require('@pm2/io'); setInterval(function() { axm.emit('content:page:created', { diff --git a/test/fixtures/interface/process_exception.js b/test/fixtures/interface/process_exception.js index f0ff97f0..23575d2b 100644 --- a/test/fixtures/interface/process_exception.js +++ b/test/fixtures/interface/process_exception.js @@ -1,5 +1,5 @@ -var axm = require('pm2.io'); +var axm = require('@pm2/io'); axm.catchAll(); diff --git a/test/fixtures/interface/process_exception_with_logs.js b/test/fixtures/interface/process_exception_with_logs.js index 67c9a621..da8e43e7 100644 --- a/test/fixtures/interface/process_exception_with_logs.js +++ b/test/fixtures/interface/process_exception_with_logs.js @@ -1,5 +1,5 @@ -var pmx = require('pm2.io'); +var pmx = require('@pm2/io'); pmx.action('exception', function(reply) { console.log('Im going to crash'); diff --git a/test/fixtures/module-fixture/scoped-action.js b/test/fixtures/module-fixture/scoped-action.js index 66010123..bf988d6d 100644 --- a/test/fixtures/module-fixture/scoped-action.js +++ b/test/fixtures/module-fixture/scoped-action.js @@ -1,5 +1,5 @@ -var pmx = require('pm2.io'); +var pmx = require('@pm2/io'); var conf = pmx.initModule({ diff --git a/test/fixtures/probes.js b/test/fixtures/probes.js index cc517c65..28b34677 100644 --- a/test/fixtures/probes.js +++ b/test/fixtures/probes.js @@ -1,6 +1,6 @@ -var pmx = require('pm2.io'); +var pmx = require('@pm2/io'); var conf = pmx.init(); var http = require('http'); diff --git a/test/fixtures/start-consistency/child.js b/test/fixtures/start-consistency/child.js index 969d49f9..c457878b 100644 --- a/test/fixtures/start-consistency/child.js +++ b/test/fixtures/start-consistency/child.js @@ -1,5 +1,5 @@ -require('pm2.io').init({ +require('@pm2/io').init({ http : true }); From 294038d76272a915e3addc67d3694717a9f7d704 Mon Sep 17 00:00:00 2001 From: Unitech Date: Thu, 17 May 2018 15:06:54 +0200 Subject: [PATCH 099/140] fix: that this - uncache node_modules --- .travis.yml | 3 --- lib/God/ActionMethods.js | 1 + package.json | 1 - 3 files changed, 1 insertion(+), 4 deletions(-) diff --git a/.travis.yml b/.travis.yml index cf0c7cc6..0c217f31 100644 --- a/.travis.yml +++ b/.travis.yml @@ -4,9 +4,6 @@ node_js: - "4" - "6" - "8" -cache: - directories: - - node_modules git: depth: 5 os: diff --git a/lib/God/ActionMethods.js b/lib/God/ActionMethods.js index 1b105bfe..834b68f3 100644 --- a/lib/God/ActionMethods.js +++ b/lib/God/ActionMethods.js @@ -135,6 +135,7 @@ module.exports = function(God) { God.dumpProcessList = function(cb) { var process_list = []; var apps = Utility.clone(God.getFormatedProcesses()); + var that = this; // Don't override the actual dump file if process list is empty // unless user explicitely did `pm2 dump`. diff --git a/package.json b/package.json index d268c609..54ab207a 100644 --- a/package.json +++ b/package.json @@ -1,4 +1,3 @@ - { "name": "pm2", "preferGlobal": true, From 53ca18c12868ab177b60a4edff2ccaa8127e301f Mon Sep 17 00:00:00 2001 From: Unitech Date: Thu, 17 May 2018 15:42:43 +0200 Subject: [PATCH 100/140] chore: upgrade all modules + keymetrics-agent -> pm2/agent + increase version enabling v8-compile-cache --- bin/pm2 | 2 +- lib/API.js | 2 +- lib/API/Configuration.js | 2 +- lib/API/Interaction.js | 2 +- lib/API/Keymetrics/cli-api.js | 2 +- lib/Client.js | 2 +- lib/Common.js | 2 +- lib/Satan.js | 2 +- package.json | 22 +++++++++++----------- test/e2e/modules/module.sh | 4 ++-- 10 files changed, 21 insertions(+), 21 deletions(-) diff --git a/bin/pm2 b/bin/pm2 index 19dbbcaf..3ee1ac76 100755 --- a/bin/pm2 +++ b/bin/pm2 @@ -3,7 +3,7 @@ var semver = require('semver'); -if (semver.satisfies(process.versions.node, '>= 5.7.0')) +if (semver.satisfies(process.versions.node, '>= 6.0.0')) require('v8-compile-cache'); process.env.PM2_USAGE = 'CLI'; diff --git a/lib/API.js b/lib/API.js index 3c84365c..d99b8d31 100644 --- a/lib/API.js +++ b/lib/API.js @@ -17,7 +17,7 @@ const fclone = require('fclone'); var conf = require('../constants.js'); var Client = require('./Client'); var Common = require('./Common'); -var KMDaemon = require('keymetrics-agent/src/InteractorClient'); +var KMDaemon = require('@pm2/agent/src/InteractorClient'); var Config = require('./tools/Config'); var Modularizer = require('./API/Modules/Modularizer.js'); var path_structure = require('../paths.js'); diff --git a/lib/API/Configuration.js b/lib/API/Configuration.js index cebc8529..321a295e 100644 --- a/lib/API/Configuration.js +++ b/lib/API/Configuration.js @@ -6,7 +6,7 @@ var chalk = require('chalk'); var async = require('async'); var Configuration = require('../Configuration.js'); //@todo double check that imported methods works -var InteractorDaemonizer = require('keymetrics-agent/src/InteractorClient'); +var InteractorDaemonizer = require('@pm2/agent/src/InteractorClient'); module.exports = function(CLI) { diff --git a/lib/API/Interaction.js b/lib/API/Interaction.js index 3181127a..8feaa69d 100644 --- a/lib/API/Interaction.js +++ b/lib/API/Interaction.js @@ -6,7 +6,7 @@ var chalk = require('chalk'); var async = require('async'); var path = require('path'); var fs = require('fs'); -var KMDaemon = require('keymetrics-agent/src/InteractorClient'); +var KMDaemon = require('@pm2/agent/src/InteractorClient'); var pkg = require('../../package.json') module.exports = function(CLI) { diff --git a/lib/API/Keymetrics/cli-api.js b/lib/API/Keymetrics/cli-api.js index 18107f85..30852143 100644 --- a/lib/API/Keymetrics/cli-api.js +++ b/lib/API/Keymetrics/cli-api.js @@ -5,7 +5,7 @@ var chalk = require('chalk'); var async = require('async'); var path = require('path'); var fs = require('fs'); -var KMDaemon = require('keymetrics-agent/src/InteractorClient'); +var KMDaemon = require('@pm2/agent/src/InteractorClient'); var KM = require('./kmapi.js'); var Table = require('cli-table-redemption'); var open = require('../../tools/open.js'); diff --git a/lib/Client.js b/lib/Client.js index 1ddc0d22..cf5eb222 100644 --- a/lib/Client.js +++ b/lib/Client.js @@ -6,7 +6,7 @@ var debug = require('debug')('pm2:client'); var Common = require('./Common.js'); -var KMDaemon = require('keymetrics-agent/src/InteractorClient'); +var KMDaemon = require('@pm2/agent/src/InteractorClient'); var rpc = require('pm2-axon-rpc'); var async = require('async'); var axon = require('pm2-axon'); diff --git a/lib/Common.js b/lib/Common.js index 5762f5c2..bae55373 100644 --- a/lib/Common.js +++ b/lib/Common.js @@ -23,7 +23,7 @@ var isBinary = require('./tools/isbinaryfile.js'); var cst = require('../constants.js'); var extItps = require('./API/interpreter.json'); var Config = require('./tools/Config'); -var KMDaemon = require('keymetrics-agent/src/InteractorClient'); +var KMDaemon = require('@pm2/agent/src/InteractorClient'); var Common = module.exports; diff --git a/lib/Satan.js b/lib/Satan.js index 968a4bbb..a6c77c26 100644 --- a/lib/Satan.js +++ b/lib/Satan.js @@ -328,7 +328,7 @@ Satan.launchDaemon = function launchDaemon(cb) { debug('Launching daemon'); var SatanJS = p.resolve(p.dirname(module.filename), 'Satan.js'); - var InteractorDaemonizer = require('keymetrics-agent/src/InteractorClient'); + var InteractorDaemonizer = require('@pm2/agent/src/InteractorClient'); var node_args = []; diff --git a/package.json b/package.json index 54ab207a..6cb2bf9e 100644 --- a/package.json +++ b/package.json @@ -159,20 +159,20 @@ }, "dependencies": { "@pm2/io": "latest", - "async": "^2.5", + "@pm2/agent": "^0.4.0", + "async": "^2.6", "blessed": "^0.1.81", - "chalk": "^2.3.1", - "chokidar": "^2.0.2", + "chalk": "^2.4.1", + "chokidar": "^2.0.3", "cli-table-redemption": "^1.0.0", - "commander": "2.14.1", + "commander": "2.15.1", "cron": "^1.3", - "debug": "^3.0", + "debug": "^3.1", "eventemitter2": "5.0.1", "fclone": "1.0.11", "fs-extra": "^5.0.0", - "keymetrics-agent": "^0.4.0", "mkdirp": "0.5.1", - "moment": "^2.19", + "moment": "^2.22", "needle": "^2.2.0", "nssocket": "0.6.0", "pidusage": "^2.0.6", @@ -181,12 +181,12 @@ "pm2-deploy": "^0.3.9", "pm2-multimeter": "^0.1.2", "promptly": "2.2.0", - "semver": "^5.3", - "shelljs": "0.8.1", + "semver": "^5.5", + "shelljs": "~0.8.2", "source-map-support": "^0.5", "sprintf-js": "1.1.1", - "v8-compile-cache": "^1.1.0", - "vizion": "0.2.0", + "v8-compile-cache": "^2.0.0", + "vizion": "~0.2.0", "yamljs": "^0.3.0" }, "devDependencies": { diff --git a/test/e2e/modules/module.sh b/test/e2e/modules/module.sh index fb1e1c53..715abb2d 100644 --- a/test/e2e/modules/module.sh +++ b/test/e2e/modules/module.sh @@ -20,11 +20,11 @@ $pm2 unset pm2-probe $pm2 set 'pm2-probe:config1xxx' true -$pm2 install pm2-probe +$pm2 install pm2-probe@latest spec "Should install a module" should 'should app be online' 'online' 1 -$pm2 install pm2-probe +$pm2 install pm2-probe@latest spec "Should update a module" should 'should app be online' 'online' 1 From 4576b4c97bc685c9d774018d6b29c918abd7cb8d Mon Sep 17 00:00:00 2001 From: Unitech Date: Thu, 17 May 2018 19:47:49 +0200 Subject: [PATCH 101/140] refactor: replace fs-extra with node calls --- lib/API/Startup.js | 7 +++---- lib/God/ActionMethods.js | 3 +-- package.json | 1 - 3 files changed, 4 insertions(+), 7 deletions(-) diff --git a/lib/API/Startup.js b/lib/API/Startup.js index b96877fe..356197f6 100644 --- a/lib/API/Startup.js +++ b/lib/API/Startup.js @@ -7,7 +7,6 @@ var debug = require('debug')('pm2:cli:startup'); var chalk = require('chalk'); var path = require('path'); var fs = require('fs'); -const fsExtra = require('fs-extra'); var async = require('async'); var exec = require('child_process').exec; var Common = require('../Common.js'); @@ -397,7 +396,7 @@ module.exports = function(CLI) { // Back up dump file try { if (fs.existsSync(cst.DUMP_FILE_PATH)) { - fsExtra.copySync(cst.DUMP_FILE_PATH, cst.DUMP_BACKUP_FILE_PATH); + fs.writeFileSync(cst.DUMP_BACKUP_FILE_PATH, fs.readFileSync(cst.DUMP_FILE_PATH)); } } catch (e) { console.error(e.stack || e); @@ -411,8 +410,8 @@ module.exports = function(CLI) { console.error(e.stack || e); try { // try to backup file - if(fs.existsSync(cst.DUMP_BACKUP_FILE_PATH)) { - fsExtra.copySync(cst.DUMP_BACKUP_FILE_PATH, cst.DUMP_FILE_PATH); + if (fs.existsSync(cst.DUMP_BACKUP_FILE_PATH)) { + fs.writeFileSync(cst.DUMP_FILE_PATH, fs.readFileSync(cst.DUMP_BACKUP_FILE_PATH)); } } catch (e) { // don't keep broken file diff --git a/lib/God/ActionMethods.js b/lib/God/ActionMethods.js index 834b68f3..83665571 100644 --- a/lib/God/ActionMethods.js +++ b/lib/God/ActionMethods.js @@ -12,7 +12,6 @@ */ var fs = require('fs'); -const fsExtra = require('fs-extra'); var path = require('path'); var async = require('async'); var os = require('os'); @@ -165,7 +164,7 @@ module.exports = function(God) { // Back up dump file try { if (fs.existsSync(cst.DUMP_FILE_PATH)) { - fsExtra.copySync(cst.DUMP_FILE_PATH, cst.DUMP_BACKUP_FILE_PATH); + fs.writeFileSync(cst.DUMP_BACKUP_FILE_PATH, fs.readFileSync(cst.DUMP_FILE_PATH)); } } catch (e) { console.error(e.stack || e); diff --git a/package.json b/package.json index 6cb2bf9e..7e325cc8 100644 --- a/package.json +++ b/package.json @@ -170,7 +170,6 @@ "debug": "^3.1", "eventemitter2": "5.0.1", "fclone": "1.0.11", - "fs-extra": "^5.0.0", "mkdirp": "0.5.1", "moment": "^2.22", "needle": "^2.2.0", From ee5e6a06cbf93f2d1fa7fa022d6bdcad55a39695 Mon Sep 17 00:00:00 2001 From: Unitech Date: Thu, 17 May 2018 23:34:48 +0200 Subject: [PATCH 102/140] refactor: faster cli with less require --- constants.js | 6 +----- lib/API/Containerizer.js | 3 +-- lib/API/Deploy.js | 4 +--- lib/API/Keymetrics/cli-api.js | 4 +++- lib/API/Keymetrics/kmapi.js | 5 +++-- lib/API/Modules/Modularizer.js | 24 +++++++++++------------- lib/API/Modules/Modularizerv1.js | 1 - lib/API/Modules/Modules.js | 1 - lib/API/Startup.js | 7 +++---- lib/API/Version.js | 15 +++++++-------- lib/Client.js | 10 ++++------ lib/Common.js | 11 ++++------- package.json | 2 +- 13 files changed, 39 insertions(+), 54 deletions(-) diff --git a/constants.js b/constants.js index 48d7a9a0..3bbcb07c 100644 --- a/constants.js +++ b/constants.js @@ -8,7 +8,6 @@ var debug = require('debug')('pm2:conf'); var p = require('path'); var util = require('util'); var chalk = require('chalk'); -var semver = require('semver'); /** * Get PM2 path structure @@ -79,10 +78,7 @@ var csts = { // Concurrent actions when doing start/restart/reload CONCURRENT_ACTIONS : (function() { - var default_concurrent_actions = 1; - if (semver.satisfies(process.versions.node, '>= 4.0.0')) - default_concurrent_actions = 2; - var concurrent_actions = parseInt(process.env.PM2_CONCURRENT_ACTIONS) || default_concurrent_actions; + var concurrent_actions = parseInt(process.env.PM2_CONCURRENT_ACTIONS) || 2; debug('Using %d parallelism (CONCURRENT_ACTIONS)', concurrent_actions); return concurrent_actions; })(), diff --git a/lib/API/Containerizer.js b/lib/API/Containerizer.js index 28f4d572..686edfd1 100644 --- a/lib/API/Containerizer.js +++ b/lib/API/Containerizer.js @@ -4,7 +4,6 @@ var exec = require('child_process').exec; var chalk = require('chalk'); var util = require('util'); var fmt = require('../tools/fmt.js'); -var vizion = require('vizion'); var fs = require('fs'); var path = require('path'); var cst = require('../../constants.js'); @@ -148,7 +147,7 @@ function handleExit(CLI, opts, mode) { if (err) { console.error(err); } - vizion.analyze({folder : process.cwd()}, function recur_path(err, meta){ + require('vizion').analyze({folder : process.cwd()}, function recur_path(err, meta){ if (!err && meta.revision) { var commit_id = util.format('#%s(%s) %s', meta.branch, diff --git a/lib/API/Deploy.js b/lib/API/Deploy.js index 9a19b516..7cc7845a 100644 --- a/lib/API/Deploy.js +++ b/lib/API/Deploy.js @@ -5,8 +5,6 @@ */ var fs = require('fs'); -var Deploy = require('pm2-deploy'); - var cst = require('../../constants.js'); var Utility = require('../Utility.js'); var Common = require('../Common.js'); @@ -104,7 +102,7 @@ module.exports = function(CLI) { json_conf.deploy[env]['post-deploy'] = 'pm2 startOrRestart ' + file + ' --env ' + env; } - Deploy.deployForEnv(json_conf.deploy, env, args, function(err, data) { + require('pm2-deploy').deployForEnv(json_conf.deploy, env, args, function(err, data) { if (err) { Common.printError('Deploy failed'); return cb ? cb(err) : that.exitCli(cst.ERROR_EXIT); diff --git a/lib/API/Keymetrics/cli-api.js b/lib/API/Keymetrics/cli-api.js index 30852143..596c0f96 100644 --- a/lib/API/Keymetrics/cli-api.js +++ b/lib/API/Keymetrics/cli-api.js @@ -6,7 +6,6 @@ var async = require('async'); var path = require('path'); var fs = require('fs'); var KMDaemon = require('@pm2/agent/src/InteractorClient'); -var KM = require('./kmapi.js'); var Table = require('cli-table-redemption'); var open = require('../../tools/open.js'); var promptly = require('promptly'); @@ -144,6 +143,7 @@ module.exports = function(CLI) { * Open Browser */ function loginPrompt(cb) { + var KM = require('./kmapi.js'); console.log(chalk.bold('Log in to Keymetrics')); (function retry() { promptly.prompt('Username or Email: ', function(err, username) { @@ -217,6 +217,8 @@ module.exports = function(CLI) { * Open Browser for access to monitoring dashboard */ function registerPrompt() { + var KM = require('./kmapi.js'); + console.log(chalk.bold('Now registering to Keymetrics')); promptly.prompt('Username: ', { validator : validateUsername, diff --git a/lib/API/Keymetrics/kmapi.js b/lib/API/Keymetrics/kmapi.js index af5d91f8..6cd75dcf 100644 --- a/lib/API/Keymetrics/kmapi.js +++ b/lib/API/Keymetrics/kmapi.js @@ -1,5 +1,4 @@ -var querystring = require('querystring'); -var https = require('https'); + var fs = require('fs'); var needle = require('needle'); var url = require('url'); @@ -19,6 +18,8 @@ var KM = function() { * @return promise */ KM.prototype.loginAndGetAccessToken = function (user_info, cb) { + var querystring = require('querystring'); + var that = this; var URL_AUTH = '/api/oauth/authorize?response_type=token&scope=all&client_id=' + that.CLIENT_ID + '&redirect_uri=' + that.CB_URI; diff --git a/lib/API/Modules/Modularizer.js b/lib/API/Modules/Modularizer.js index ea1efd32..900afc1e 100644 --- a/lib/API/Modules/Modularizer.js +++ b/lib/API/Modules/Modularizer.js @@ -3,7 +3,6 @@ * Use of this source code is governed by a license that * can be found in the LICENSE file. */ -var shelljs = require('shelljs'); var path = require('path'); var fs = require('fs'); var os = require('os'); @@ -18,7 +17,6 @@ var Common = require('../../Common'); var Utility = require('../../Utility.js'); var ModularizerV1 = require('./Modularizerv1.js'); var Modularizer = module.exports = {}; -var mkdirp = require('mkdirp'); var MODULE_CONF_PREFIX = 'module-db-v2'; @@ -185,7 +183,7 @@ Modularizer.installModule = function(CLI, module_name, opts, cb) { var canonic_module_name = Utility.getCanonicModuleName(module_name); var install_path = path.join(cst.DEFAULT_MODULE_PATH, canonic_module_name); - mkdirp(install_path, function() { + require('mkdirp')(install_path, function() { process.chdir(os.homedir()); var install_instance = spawn(cst.IS_WINDOWS ? 'npm.cmd' : 'npm', ['install', module_name, '--loglevel=error', '--prefix', install_path ], { @@ -405,14 +403,14 @@ function uninstallModule(CLI, opts, cb) { if (module_name != '.') { console.log(proc_path); - shelljs.rm('-r', proc_path); + require('shelljs').rm('-r', proc_path); } return cb(err); } if (module_name != '.') { - shelljs.rm('-r', proc_path); + require('shelljs').rm('-r', proc_path); } return cb(null, data); @@ -436,9 +434,9 @@ var Rollback = { CLI.deleteModule(canonic_module_name, function() { // Delete failing module - shelljs.rm('-r', module_path); + require('shelljs').rm('-r', module_path); // Restore working version - shelljs.cp('-r', backup_path, module_path); + require('shelljs').cp('-r', backup_path, module_path); var proc_path = path.join(module_path, 'node_modules', canonic_module_name); var package_json_path = path.join(proc_path, 'package.json'); @@ -456,7 +454,7 @@ var Rollback = { var tmpdir = require('os').tmpdir(); var canonic_module_name = Utility.getCanonicModuleName(module_name); var module_path = path.join(cst.DEFAULT_MODULE_PATH, canonic_module_name); - shelljs.cp('-r', module_path, tmpdir); + require('shelljs').cp('-r', module_path, tmpdir); } } @@ -521,13 +519,13 @@ Modularizer.publish = function(cb) { package_json.name, package_json.version); - shelljs.exec('npm publish', function(code) { + require('shelljs').exec('npm publish', function(code) { Common.printOut(cst.PREFIX_MSG_MOD + 'Module - %s@%s successfully published', package_json.name, package_json.version); Common.printOut(cst.PREFIX_MSG_MOD + 'Pushing module on Git'); - shelljs.exec('git add . ; git commit -m "' + package_json.version + '"; git push origin master', function(code) { + require('shelljs').exec('git add . ; git commit -m "' + package_json.version + '"; git push origin master', function(code) { Common.printOut(cst.PREFIX_MSG_MOD + 'Installable with pm2 install %s', package_json.name); return cb(null, package_json); @@ -550,11 +548,11 @@ Modularizer.generateSample = function(app_name, cb) { var cmd3 = 'cd ' + module_name + ' ; npm install'; Common.printOut(cst.PREFIX_MSG_MOD + 'Getting sample app'); - shelljs.exec(cmd1, function(err) { + require('shelljs').exec(cmd1, function(err) { if (err) Common.printError(cst.PREFIX_MSG_MOD_ERR + err.message); - shelljs.exec(cmd2, function(err) { + require('shelljs').exec(cmd2, function(err) { console.log(''); - shelljs.exec(cmd3, function(err) { + require('shelljs').exec(cmd3, function(err) { console.log(''); Common.printOut(cst.PREFIX_MSG_MOD + 'Module sample created in folder: ', path.join(process.cwd(), module_name)); console.log(''); diff --git a/lib/API/Modules/Modularizerv1.js b/lib/API/Modules/Modularizerv1.js index 00d48991..ad63a560 100644 --- a/lib/API/Modules/Modularizerv1.js +++ b/lib/API/Modules/Modularizerv1.js @@ -3,7 +3,6 @@ * Use of this source code is governed by a license that * can be found in the LICENSE file. */ -var shelljs = require('shelljs'); var path = require('path'); var fs = require('fs'); var async = require('async'); diff --git a/lib/API/Modules/Modules.js b/lib/API/Modules/Modules.js index 77412b01..3d9f6f2a 100644 --- a/lib/API/Modules/Modules.js +++ b/lib/API/Modules/Modules.js @@ -11,7 +11,6 @@ var UX = require('../CliUx'); var chalk = require('chalk'); var async = require('async'); -var shelljs = require('shelljs'); var path = require('path'); var fs = require('fs'); var p = path; diff --git a/lib/API/Startup.js b/lib/API/Startup.js index 356197f6..e27469c1 100644 --- a/lib/API/Startup.js +++ b/lib/API/Startup.js @@ -12,7 +12,6 @@ var exec = require('child_process').exec; var Common = require('../Common.js'); var cst = require('../../constants.js'); var spawn = require('child_process').spawn; -var shelljs = require('shelljs'); module.exports = function(CLI) { /** @@ -47,7 +46,7 @@ module.exports = function(CLI) { var init_systems = Object.keys(hash_map); for (var i = 0; i < init_systems.length; i++) { - if (shelljs.which(init_systems[i]) != null) { + if (require('shelljs').which(init_systems[i]) != null) { break; } } @@ -150,7 +149,7 @@ module.exports = function(CLI) { ]; }; - shelljs.exec(commands.join('&& '), function(code, stdout, stderr) { + require('shelljs').exec(commands.join('&& '), function(code, stdout, stderr) { Common.printOut(stdout); Common.printOut(stderr); if (code == 0) { @@ -317,7 +316,7 @@ module.exports = function(CLI) { async.forEachLimit(commands, 1, function(command, next) { Common.printOut(chalk.bold('>>> Executing %s'), command); - shelljs.exec(command, function(code, stdout, stderr) { + require('shelljs').exec(command, function(code, stdout, stderr) { if (code === 0) { Common.printOut(chalk.bold('[DONE] ')); return next(); diff --git a/lib/API/Version.js b/lib/API/Version.js index 84495317..aefe9352 100644 --- a/lib/API/Version.js +++ b/lib/API/Version.js @@ -3,7 +3,6 @@ var cst = require('../../constants.js'); var Common = require('../Common.js'); var fs = require('fs'); var async = require('async'); -var vizion = require('vizion'); var child = require('child_process'); var printError = Common.printError; @@ -33,7 +32,7 @@ module.exports = function(CLI) { printOut(cst.PREFIX_MSG + 'No versioning system found for process %s', process_name); return cb ? cb({success:false, msg: 'No versioning system found for process'}) : that.exitCli(cst.SUCCESS_EXIT); } - vizion.update({ + require('vizion').update({ folder: proc.pm2_env.versioning.repo_path }, function(err, meta) { if (err !== null) { @@ -91,10 +90,10 @@ module.exports = function(CLI) { var proc = processes[0]; if (proc.pm2_env.versioning) { - vizion.isUpToDate({folder: proc.pm2_env.versioning.repo_path}, function(err, meta) { + require('vizion').isUpToDate({folder: proc.pm2_env.versioning.repo_path}, function(err, meta) { if (err !== null) return cb ? cb({msg:err}) : that.exitCli(cst.ERROR_EXIT); - vizion.revertTo( + require('vizion').revertTo( {revision: commit_id, folder: proc.pm2_env.versioning.repo_path}, function(err2, meta2) { @@ -153,7 +152,7 @@ module.exports = function(CLI) { proc.pm2_env.versioning === null) return cb({msg : 'Versioning unknown'}); - vizion.prev({ + require('vizion').prev({ folder: proc.pm2_env.versioning.repo_path }, function(err, meta) { if (err) @@ -167,7 +166,7 @@ module.exports = function(CLI) { getPostUpdateCmds(proc.pm2_env.versioning.repo_path, process_name, function (command_list) { execCommands(proc.pm2_env.versioning.repo_path, command_list, function(err, res) { if (err !== null) { - vizion.next({folder: proc.pm2_env.versioning.repo_path}, function(err2, meta2) { + require('vizion').next({folder: proc.pm2_env.versioning.repo_path}, function(err2, meta2) { printError(err); return cb ? cb({msg: meta.output + err}) : that.exitCli(cst.ERROR_EXIT); }); @@ -207,7 +206,7 @@ module.exports = function(CLI) { // in case user searched by id/pid process_name = proc.name; if (proc.pm2_env.versioning) { - vizion.next({folder: proc.pm2_env.versioning.repo_path}, function(err, meta) { + require('vizion').next({folder: proc.pm2_env.versioning.repo_path}, function(err, meta) { if (err !== null) return cb ? cb({msg:err}) : that.exitCli(cst.ERROR_EXIT); if (meta.success === true) { @@ -215,7 +214,7 @@ module.exports = function(CLI) { execCommands(proc.pm2_env.versioning.repo_path, command_list, function(err, res) { if (err !== null) { - vizion.prev({folder: proc.pm2_env.versioning.repo_path}, function(err2, meta2) { + require('vizion').prev({folder: proc.pm2_env.versioning.repo_path}, function(err2, meta2) { printError(err); return cb ? cb({msg:meta.output + err}) : that.exitCli(cst.ERROR_EXIT); }); diff --git a/lib/Client.js b/lib/Client.js index cf5eb222..6edb18f7 100644 --- a/lib/Client.js +++ b/lib/Client.js @@ -13,8 +13,6 @@ var axon = require('pm2-axon'); var util = require('util'); var fs = require('fs'); var path = require('path'); -var mkdirp = require('mkdirp'); -var shelljs = require('shelljs'); var pkg = require('../package.json') function noop() {} @@ -131,7 +129,7 @@ Client.prototype.start = function(cb) { Client.prototype.initFileStructure = function (opts) { if (!fs.existsSync(opts.DEFAULT_LOG_PATH)) { try { - mkdirp.sync(opts.DEFAULT_LOG_PATH); + require('mkdirp').sync(opts.DEFAULT_LOG_PATH); } catch (e) { console.error(e.stack || e); } @@ -139,7 +137,7 @@ Client.prototype.initFileStructure = function (opts) { if (!fs.existsSync(opts.DEFAULT_PID_PATH)) { try { - mkdirp.sync(opts.DEFAULT_PID_PATH); + require('mkdirp').sync(opts.DEFAULT_PID_PATH); } catch (e) { console.error(e.stack || e); } @@ -155,7 +153,7 @@ Client.prototype.initFileStructure = function (opts) { if (!fs.existsSync(opts.DEFAULT_MODULE_PATH)) { try { - mkdirp.sync(opts.DEFAULT_MODULE_PATH); + require('mkdirp').sync(opts.DEFAULT_MODULE_PATH); } catch (e) { console.error(e.stack || e); } @@ -243,7 +241,7 @@ Client.prototype.launchDaemon = function(opts, cb) { var interpreter = 'node'; - if (shelljs.which('node') == null) + if (require('shelljs').which('node') == null) interpreter = process.execPath; var child = require('child_process').spawn(interpreter, node_args, { diff --git a/lib/Common.js b/lib/Common.js index bae55373..662df66b 100644 --- a/lib/Common.js +++ b/lib/Common.js @@ -12,9 +12,7 @@ var fs = require('fs'); var path = require('path'); var os = require('os'); var util = require('util'); -var mkdirp = require('mkdirp'); var async = require('async'); -var shelljs = require('shelljs'); var chalk = require('chalk'); var fclone = require('fclone'); var semver = require('semver'); @@ -23,7 +21,6 @@ var isBinary = require('./tools/isbinaryfile.js'); var cst = require('../constants.js'); var extItps = require('./API/interpreter.json'); var Config = require('./tools/Config'); -var KMDaemon = require('@pm2/agent/src/InteractorClient'); var Common = module.exports; @@ -151,7 +148,7 @@ Common.prepareAppConf = function(opts, app) { if (!fs.existsSync(app.pm_exec_path)) { var ckd; // Try resolve command available in $PATH - if ((ckd = shelljs.which(app.script))) { + if ((ckd = require('shelljs').which(app.script))) { if (typeof(ckd) !== 'string') ckd = ckd.toString(); app.pm_exec_path = ckd; @@ -226,7 +223,7 @@ Common.prepareAppConf = function(opts, app) { if (!fs.existsSync(dir)) { Common.printError(cst.PREFIX_MSG_WARNING + 'Folder does not exists: ' + dir); Common.printOut(cst.PREFIX_MSG + 'Creating folder: ' + dir); - mkdirp(dir, function(err) { + require('mkdirp')(dir, function(err) { if (!err) return; Common.printError(cst.PREFIX_MSG_ERR + 'Could not create folder: ' + path.dirname(af)); throw new Error('Could not create folder'); @@ -368,7 +365,7 @@ var resolveNodeInterpreter = function(app) { var nvm_cmd = '. ' + nvm_bin + ' ; nvm install ' + node_version; Common.printOut(cst.PREFIX_MSG + 'Executing: %s', nvm_cmd); - shelljs.exec(nvm_cmd); + require('shelljs').exec(nvm_cmd); } Common.printOut(cst.PREFIX_MSG + chalk.green.bold('Setting Node to v%s (path=%s)'), @@ -411,7 +408,7 @@ Common.sink.resolveInterpreter = function(app) { app.exec_interpreter = path.resolve(__dirname, '../node_modules/.bin/coffee'); } - if (app.exec_interpreter != 'none' && shelljs.which(app.exec_interpreter) == null) { + if (app.exec_interpreter != 'none' && require('shelljs').which(app.exec_interpreter) == null) { Common.printError(cst.PREFIX_MSG_ERR + 'Interpreter ' + app.exec_interpreter + ' does not seem to be available'); } return app; diff --git a/package.json b/package.json index 7e325cc8..9d6a6970 100644 --- a/package.json +++ b/package.json @@ -158,8 +158,8 @@ "pm2-runtime": "./bin/pm2-runtime" }, "dependencies": { - "@pm2/io": "latest", "@pm2/agent": "^0.4.0", + "@pm2/io": "latest", "async": "^2.6", "blessed": "^0.1.81", "chalk": "^2.4.1", From f8c8bd90729251a24a4fcffd6d7d72e30034d7ca Mon Sep 17 00:00:00 2001 From: Unitech Date: Fri, 18 May 2018 12:48:15 +0200 Subject: [PATCH 103/140] doc: reword --- README.md | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index 3b07141d..6555ac7b 100644 --- a/README.md +++ b/README.md @@ -27,13 +27,8 @@
-PM2 is a General Purpose Process Manager and a Production Runtime for Node.js apps with a built-in Load Balancer. - -Key features: -- Simple and efficient process management (start/stop/restart/delete/show/monit) -- Keep your application ALWAYS ONLINE with auto restarts and init system script generation -- Clusterize Node.js Applications without code change to increase performance and reliability -- Hot Reload Node.js Applications without extra configuration +PM2 is a Production Runtime and Process Manager for Node.js applications with a built-in Load Balancer. +It allows you to keep applications alive forever, to reload them without downtime and facilitate common Devops tasks. Starting an application in production mode is as easy as: From 109b331ddf37e061d1890ef952f4cd167ce53f64 Mon Sep 17 00:00:00 2001 From: Unitech Date: Fri, 18 May 2018 20:17:59 +0200 Subject: [PATCH 104/140] refactor: keymetrics examples --- .../actions-fibonacci.js | 2 +- .../custom_action.js | 2 +- .../custom_action_with_params.js | 2 +- .../test-all-keymetrics-features/event.js | 2 +- .../test-all-keymetrics-features/http_app.js | 4 +-- .../http_transaction.js | 4 +-- .../test-all-keymetrics-features/pm2_probe.js | 7 ++--- .../test-all-keymetrics-features/probes.js | 4 +-- .../process-transpose.js | 28 +++++++++---------- .../scoped-actions.js | 6 ++-- .../test-all-keymetrics-features/throw.js | 4 +-- 11 files changed, 31 insertions(+), 34 deletions(-) diff --git a/examples/test-all-keymetrics-features/actions-fibonacci.js b/examples/test-all-keymetrics-features/actions-fibonacci.js index 3b230314..608753f6 100644 --- a/examples/test-all-keymetrics-features/actions-fibonacci.js +++ b/examples/test-all-keymetrics-features/actions-fibonacci.js @@ -47,7 +47,7 @@ function fib(n) { } -var axm = require('pmx'); +var axm = require('@pm2/io'); axm.action('load:start', function(reply) { fib(50000); diff --git a/examples/test-all-keymetrics-features/custom_action.js b/examples/test-all-keymetrics-features/custom_action.js index 5a01fc63..d11d8257 100644 --- a/examples/test-all-keymetrics-features/custom_action.js +++ b/examples/test-all-keymetrics-features/custom_action.js @@ -1,5 +1,5 @@ -var axm = require('pmx'); +var axm = require('@pm2/io'); axm.action('getEnv', function(reply) { reply(process.env); diff --git a/examples/test-all-keymetrics-features/custom_action_with_params.js b/examples/test-all-keymetrics-features/custom_action_with_params.js index 8d0b6630..023c75e7 100644 --- a/examples/test-all-keymetrics-features/custom_action_with_params.js +++ b/examples/test-all-keymetrics-features/custom_action_with_params.js @@ -1,5 +1,5 @@ -var axm = require('pmx'); +var axm = require('@pm2/io'); axm.action('refresh:db', { comment : 'Refresh the database' }, function(reply) { console.log('Refreshing'); diff --git a/examples/test-all-keymetrics-features/event.js b/examples/test-all-keymetrics-features/event.js index dca10d4f..3c092ac1 100644 --- a/examples/test-all-keymetrics-features/event.js +++ b/examples/test-all-keymetrics-features/event.js @@ -1,5 +1,5 @@ -var axm = require('pmx'); +var axm = require('@pm2/io'); setInterval(function() { diff --git a/examples/test-all-keymetrics-features/http_app.js b/examples/test-all-keymetrics-features/http_app.js index 38653c02..2e24737a 100644 --- a/examples/test-all-keymetrics-features/http_app.js +++ b/examples/test-all-keymetrics-features/http_app.js @@ -1,7 +1,7 @@ -var pmx = require('pmx').init({ http : true }); -var probe = pmx.probe(); +var io = require('@pm2/io').init({ http : true }); +var probe = io.probe(); var http = require('http'); diff --git a/examples/test-all-keymetrics-features/http_transaction.js b/examples/test-all-keymetrics-features/http_transaction.js index 87e12253..1334ea85 100644 --- a/examples/test-all-keymetrics-features/http_transaction.js +++ b/examples/test-all-keymetrics-features/http_transaction.js @@ -1,6 +1,6 @@ -var axm = require('pmx'); +var axm = require('@pm2/io'); var probe = axm.probe(); @@ -17,7 +17,7 @@ http.createServer(function(req, res) { setTimeout(function() { res.end('transaction'); }, 1000); -}).listen(9010); +}).listen(10010); setInterval(function() { request(['/user', '/bla', '/user/lol/delete', '/POST/POST'][Math.floor((Math.random() * 4))]); diff --git a/examples/test-all-keymetrics-features/pm2_probe.js b/examples/test-all-keymetrics-features/pm2_probe.js index bedab4c9..a8741ae3 100644 --- a/examples/test-all-keymetrics-features/pm2_probe.js +++ b/examples/test-all-keymetrics-features/pm2_probe.js @@ -1,16 +1,15 @@ -var pmx = require('pmx'); +var io = require('@pm2/io'); var pm2 = require('../..'); var fs = require('fs'); var path = require('path'); -var conf = pmx.initModule({ +var conf = io.initModule({ comment : 'This module monitors PM2', errors : true, latency : false, versioning : false, show_module_meta : false, module_type : 'database', - pid : pmx.getPID(path.join(process.env.HOME, '.pm2', 'pm2.pid')), widget : { theme : ['#111111', '#1B2228', '#807C7C', '#807C7C'], @@ -18,7 +17,7 @@ var conf = pmx.initModule({ } }); -var probe = pmx.probe(); +var probe = io.probe(); var pm2_procs = 0; diff --git a/examples/test-all-keymetrics-features/probes.js b/examples/test-all-keymetrics-features/probes.js index 51dc1f56..8cefdac2 100644 --- a/examples/test-all-keymetrics-features/probes.js +++ b/examples/test-all-keymetrics-features/probes.js @@ -1,6 +1,6 @@ -var axm = require('pmx'); +var axm = require('@pm2/io'); var probe = axm.probe(); @@ -84,7 +84,7 @@ setInterval(function() { }, 1500); -axm.catchAll(); +//axm.catchAll(); axm.action('throw error', function(reply) { setTimeout(function() { diff --git a/examples/test-all-keymetrics-features/process-transpose.js b/examples/test-all-keymetrics-features/process-transpose.js index a0f078da..d02ed7e8 100644 --- a/examples/test-all-keymetrics-features/process-transpose.js +++ b/examples/test-all-keymetrics-features/process-transpose.js @@ -1,21 +1,21 @@ -var Probe = require('pmx').probe(); +var Probe = require('@pm2/io').probe(); var counter = 0; -var metric = Probe.transpose({ - name : 'data-flow', - data : function() { - return { - a : { - b : { - data : 'textflow', - array : [ 'yes', 'it', 'is' ] - } - } - } - } -}); +// var metric = Probe.transpose({ +// name : 'data-flow', +// data : function() { +// return { +// a : { +// b : { +// data : 'textflow', +// array : [ 'yes', 'it', 'is' ] +// } +// } +// } +// } +// }); setInterval(function() { }, 100); diff --git a/examples/test-all-keymetrics-features/scoped-actions.js b/examples/test-all-keymetrics-features/scoped-actions.js index 5a096dd4..427dcc8c 100644 --- a/examples/test-all-keymetrics-features/scoped-actions.js +++ b/examples/test-all-keymetrics-features/scoped-actions.js @@ -1,7 +1,7 @@ -var pmx = require('pmx'); +var io = require('@pm2/io'); -pmx.scopedAction('simple test', function(data, emitter) { +io.scopedAction('simple test', function(data, emitter) { var i = setInterval(function() { emitter.send('output-stream'); }, 100); @@ -13,7 +13,7 @@ pmx.scopedAction('simple test', function(data, emitter) { }, 3000); }); -pmx.scopedAction('throwing error', function(data, emitter) { +io.scopedAction('throwing error', function(data, emitter) { var i = setInterval(function() { emitter.send('output-stream'); }, 100); diff --git a/examples/test-all-keymetrics-features/throw.js b/examples/test-all-keymetrics-features/throw.js index 7351209c..1c9dfd1f 100644 --- a/examples/test-all-keymetrics-features/throw.js +++ b/examples/test-all-keymetrics-features/throw.js @@ -1,7 +1,5 @@ -var axm = require('pmx'); - -axm.catchAll(); +var axm = require('@pm2/io'); setTimeout(function() { console.log('log message from echo auto kill'); From f111596b801867501e1562742cac85a895dc75c4 Mon Sep 17 00:00:00 2001 From: Alexandre Strzelewicz Date: Mon, 21 May 2018 15:59:09 +0200 Subject: [PATCH 105/140] feature: add --ws option to pm2 link --- bin/pm2 | 1 + lib/API/Interaction.js | 17 +++++++++++++++-- 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/bin/pm2 b/bin/pm2 index 3ee1ac76..a77b7ea0 100755 --- a/bin/pm2 +++ b/bin/pm2 @@ -566,6 +566,7 @@ commander.command('report') commander.command('link [secret] [public] [name]') .alias('interact') .option('--info-node [url]', 'set url info node') + .option('--ws', 'websocket mode') .description('link with the pm2 monitoring dashboard') .action(pm2._pre_interact.bind(pm2)); diff --git a/lib/API/Interaction.js b/lib/API/Interaction.js index 8feaa69d..621dbf27 100644 --- a/lib/API/Interaction.js +++ b/lib/API/Interaction.js @@ -76,7 +76,7 @@ module.exports = function(CLI) { // // Interact // - CLI.prototype._pre_interact = function(cmd, public_key, machine, info_node) { + CLI.prototype._pre_interact = function(cmd, public_key, machine, opts) { var that = this; if (cmd == 'stop' || cmd == 'kill') { @@ -146,10 +146,23 @@ module.exports = function(CLI) { public_key : public_key, secret_key : cmd, machine_name : machine, - info_node : info_node.infoNode || null, + info_node : opts.infoNode || null, pm2_version: pkg.version } + if (opts.ws === true && infos) { + infos.agent_transport_axon = false + infos.agent_transport_websocket = true + process.env.AGENT_TRANSPORT_AXON = false + process.env.AGENT_TRANSPORT_WEBSOCKET = true + } + else if (infos) { + infos.agent_transport_axon = true + infos.agent_transport_websocket = false + process.env.AGENT_TRANSPORT_AXON = true + process.env.AGENT_TRANSPORT_WEBSOCKET = false + } + KMDaemon.launchAndInteract(that._conf, infos, function(err, dt) { if (err) return that.exitCli(cst.ERROR_EXIT); From 809ff15c32517bc4b2247e47ff6d8ca537602f8e Mon Sep 17 00:00:00 2001 From: Alexandre Strzelewicz Date: Mon, 21 May 2018 16:04:45 +0200 Subject: [PATCH 106/140] meta: use pm2-io-agent repo for @pm2/agent --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 9d6a6970..edd40a27 100644 --- a/package.json +++ b/package.json @@ -158,7 +158,7 @@ "pm2-runtime": "./bin/pm2-runtime" }, "dependencies": { - "@pm2/agent": "^0.4.0", + "@pm2/agent": "keymetrics/pm2-io-agent", "@pm2/io": "latest", "async": "^2.6", "blessed": "^0.1.81", From 7aba519b050b044e2b4b3b0e4bf79be1931216be Mon Sep 17 00:00:00 2001 From: Alexandre Strzelewicz Date: Sat, 26 May 2018 17:41:51 +0200 Subject: [PATCH 107/140] pm2-io-agent development --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index edd40a27..74a200f1 100644 --- a/package.json +++ b/package.json @@ -158,7 +158,7 @@ "pm2-runtime": "./bin/pm2-runtime" }, "dependencies": { - "@pm2/agent": "keymetrics/pm2-io-agent", + "@pm2/agent": "keymetrics/pm2-io-agent#development", "@pm2/io": "latest", "async": "^2.6", "blessed": "^0.1.81", From c4804cba5fec3f1a44ac9ceb5150db0010c3ec13 Mon Sep 17 00:00:00 2001 From: Alexandre Strzelewicz Date: Sat, 26 May 2018 18:31:10 +0200 Subject: [PATCH 108/140] chrore: latest @pm2/agent version --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 74a200f1..de0d4d7d 100644 --- a/package.json +++ b/package.json @@ -158,7 +158,7 @@ "pm2-runtime": "./bin/pm2-runtime" }, "dependencies": { - "@pm2/agent": "keymetrics/pm2-io-agent#development", + "@pm2/agent": "latest", "@pm2/io": "latest", "async": "^2.6", "blessed": "^0.1.81", From 2c8170c25e231eb8827bb0944b76c2f4b041d84e Mon Sep 17 00:00:00 2001 From: Alexandre Strzelewicz Date: Sat, 26 May 2018 19:09:21 +0200 Subject: [PATCH 109/140] chore: keymetrics -> pm2 --- lib/API.js | 5 ++++- lib/API/Dashboard.js | 2 +- lib/API/Keymetrics/cli-api.js | 14 +++++++------- lib/API/Keymetrics/motd | 19 ++++++++++++------- lib/API/Monit.js | 4 ++-- 5 files changed, 26 insertions(+), 18 deletions(-) diff --git a/lib/API.js b/lib/API.js index d99b8d31..514c24eb 100644 --- a/lib/API.js +++ b/lib/API.js @@ -1495,7 +1495,10 @@ class API { UX.miniDisplay(list); else if (!commander.silent) { if (that.gl_interact_infos) { - Common.printOut(chalk.green.bold('●') + ' Agent Online | Dashboard Access: ' + chalk.bold('https://app.keymetrics.io/#/r/%s') + ' | Server name: %s', that.gl_interact_infos.public_key, that.gl_interact_infos.machine_name); + Common.printOut('%s Agent Online | Access: %s | Server: %s', + chalk.green.bold('⇆'), + chalk.bold('https://app.pm2.io/#/r/' + that.gl_interact_infos.public_key), + chalk.bold(that.gl_interact_infos.machine_name)); } UX.dispAsTable(list, commander); Common.printOut(chalk.white.italic(' Use `pm2 show ` to get more details about an app')); diff --git a/lib/API/Dashboard.js b/lib/API/Dashboard.js index 6e12f6c8..85c37a7f 100644 --- a/lib/API/Dashboard.js +++ b/lib/API/Dashboard.js @@ -162,7 +162,7 @@ Dashboard.init = function() { }); this.box4 = blessed.text({ - content: ' left/right: switch boards | up/down/mouse: scroll | Ctrl-C: exit{|} {cyan-fg}{bold}To go further check out https://keymetrics.io/{/} ', + content: ' left/right: switch boards | up/down/mouse: scroll | Ctrl-C: exit{|} {cyan-fg}{bold}To go further check out https://pm2.io/{/} ', left: '0%', top: '95%', width: '100%', diff --git a/lib/API/Keymetrics/cli-api.js b/lib/API/Keymetrics/cli-api.js index 596c0f96..e6561e7d 100644 --- a/lib/API/Keymetrics/cli-api.js +++ b/lib/API/Keymetrics/cli-api.js @@ -22,7 +22,7 @@ module.exports = function(CLI) { return that.exitCli(cst.ERROR_EXIT); } Common.printOut(chalk.bold('Opening Dashboard in Browser...')); - open('https://app.keymetrics.io/#/r/' + data.public_key); + open('https://app.pm2.io/#/r/' + data.public_key); setTimeout(function() { that.exitCli(); }, 200); @@ -37,7 +37,7 @@ module.exports = function(CLI) { CLI.prototype.registerToKM = function() { printMotd(); - promptly.confirm(chalk.bold('Do you have a Keymetrics.io account? (y/n)'), function (err, answer) { + promptly.confirm(chalk.bold('Do you have a pm2.io account? (y/n)'), function (err, answer) { if (answer == true) { return loginPrompt(); } @@ -130,7 +130,7 @@ module.exports = function(CLI) { secret_key : target_bucket.secret_id, pm2_version: pkg.version }, function(err, dt) { - open('https://app.keymetrics.io/#/r/' + target_bucket.public_id); + open('https://app.pm2.io/#/r/' + target_bucket.public_id); setTimeout(function() { process.exit(cst.SUCCESS_EXIT); }, 100); @@ -144,7 +144,7 @@ module.exports = function(CLI) { */ function loginPrompt(cb) { var KM = require('./kmapi.js'); - console.log(chalk.bold('Log in to Keymetrics')); + console.log(chalk.bold('Log in to pm2.io')); (function retry() { promptly.prompt('Username or Email: ', function(err, username) { promptly.password('Password: ', { replace : '*' }, function(err, password) { @@ -192,7 +192,7 @@ module.exports = function(CLI) { } else { var target_bucket = buckets[0]; - console.log('Connecting local PM2 to Keymetrics Bucket [%s]', target_bucket.name); + console.log('Connecting local PM2 Runtime to pm2.io, bucket name= [%s]', target_bucket.name); KMDaemon.launchAndInteract(cst, { public_key : target_bucket.public_id, @@ -219,7 +219,7 @@ module.exports = function(CLI) { function registerPrompt() { var KM = require('./kmapi.js'); - console.log(chalk.bold('Now registering to Keymetrics')); + console.log(chalk.bold('Now registering to pm2.io')); promptly.prompt('Username: ', { validator : validateUsername, retry : true @@ -229,7 +229,7 @@ module.exports = function(CLI) { retry : true }, function(err, email) { promptly.password('Password: ', { replace : '*' }, function(err, password) { - process.stdout.write(chalk.bold('Creating account on Keymetrics..')); + process.stdout.write(chalk.bold('Creating account on pm2.io ...')); var inter = setInterval(function() { process.stdout.write('.'); }, 300); diff --git a/lib/API/Keymetrics/motd b/lib/API/Keymetrics/motd index 26b30058..9d44fc76 100644 --- a/lib/API/Keymetrics/motd +++ b/lib/API/Keymetrics/motd @@ -1,8 +1,13 @@ - __ __ __ _ - / //_/__ __ ______ ___ ___ / /______(_)_________ - / ,< / _ \/ / / / __ `__ \/ _ \/ __/ ___/ / ___/ ___/ - / /| / __/ /_/ / / / / / / __/ /_/ / / / /__(__ ) -/_/ |_\___/\__, /_/ /_/ /_/\___/\__/_/ /_/\___/____/ - /____/ - Harden your Node.js application, today + 88888888ba 88b d88 ad888888b, 88 ,ad8888ba, + 88 "8b 888b d888 d8" "88 88 d8"' `"8b + 88 ,8P 88`8b d8'88 a8P 88 d8' `8b + 88aaaaaa8P' 88 `8b d8' 88 ,d8P" 88 88 88 + 88""""""' 88 `8b d8' 88 a8P" 88 88 88 + 88 88 `8b d8' 88 a8P' 88 Y8, ,8P + 88 88 `888' 88 d8" 888 88 Y8a. .a8P + 88 88 `8' 88 88888888888 888 88 `"Y8888Y"' + + https://pm2.io/ + + Add Control and Monitoring to Your Node.js Apps diff --git a/lib/API/Monit.js b/lib/API/Monit.js index 08d9a63a..9d86c27c 100644 --- a/lib/API/Monit.js +++ b/lib/API/Monit.js @@ -45,7 +45,7 @@ Monit.reset = function(msg) { this.multi.charm.reset(); - this.multi.write('\x1B[32m⌬ PM2 \x1B[39mmonitoring\x1B[96m (To go further check out https://app.keymetrics.io) \x1B[39m\n\n'); + this.multi.write('\x1B[32m⌬ PM2 \x1B[39mmonitoring\x1B[96m (To go further check out https://app.pm2.io) \x1B[39m\n\n'); if(msg) { this.multi.write(msg); @@ -244,4 +244,4 @@ Monit.updateBars = function(proc) { return this; } -module.exports = Monit; \ No newline at end of file +module.exports = Monit; From ff1a7f315bfee38eb9fd9cdd63efcc0d971585f8 Mon Sep 17 00:00:00 2001 From: Alexandre Strzelewicz Date: Sat, 26 May 2018 19:14:37 +0200 Subject: [PATCH 110/140] fix: startup script issue 18.04 #3645 --- lib/API/Startup.js | 14 +------------- 1 file changed, 1 insertion(+), 13 deletions(-) diff --git a/lib/API/Startup.js b/lib/API/Startup.js index 08d487c3..d35cd05c 100644 --- a/lib/API/Startup.js +++ b/lib/API/Startup.js @@ -221,21 +221,9 @@ module.exports = function(CLI) { else template = getTemplate('systemd'); destination = '/etc/systemd/system/' + service_name + '.service'; - commands = [ 'systemctl enable ' + service_name - ] - - try { - fs.readFileSync(cst.PM2_PID_FILE_PATH).toString() - } catch(e) { - commands = [ - 'systemctl enable ' + service_name, - 'systemctl start ' + service_name, - 'systemctl daemon-reload', - 'systemctl status ' + service_name - ] - } + ]; break; case 'ubuntu14': case 'ubuntu12': From af60e99466b2dc2cec40328a4e790211159bb71c Mon Sep 17 00:00:00 2001 From: Alexandre Strzelewicz Date: Sun, 27 May 2018 16:07:54 +0200 Subject: [PATCH 111/140] feature: allow to start raw command via `pm2 start "my command with params"` + alias script in ecosystem file with cmd & command --- lib/API.js | 15 +---- lib/Common.js | 66 +++++++++++++-------- test/e2e.sh | 2 + test/e2e/cli/start-app.sh | 38 ++++++++++++ test/fixtures/start-app/ecosystem.config.js | 10 ++++ test/fixtures/start-app/http.js | 21 +++++++ 6 files changed, 116 insertions(+), 36 deletions(-) create mode 100644 test/e2e/cli/start-app.sh create mode 100644 test/fixtures/start-app/ecosystem.config.js create mode 100644 test/fixtures/start-app/http.js diff --git a/lib/API.js b/lib/API.js index 514c24eb..ff89d5e1 100644 --- a/lib/API.js +++ b/lib/API.js @@ -630,24 +630,17 @@ class API { else app_conf.exec_mode = 'fork'; - // Options set via environment variables - if (process.env.PM2_DEEP_MONITORING) - app_conf.deep_monitoring = true; - - if (typeof app_conf.name == 'function'){ + if (typeof app_conf.name == 'function') delete app_conf.name; - } delete app_conf.args; var argsIndex; - if (opts.rawArgs && (argsIndex = opts.rawArgs.indexOf('--')) >= 0) { + if (opts.rawArgs && (argsIndex = opts.rawArgs.indexOf('--')) >= 0) app_conf.args = opts.rawArgs.slice(argsIndex + 1); - } - else if (opts.scriptArgs) { + else if (opts.scriptArgs) app_conf.args = opts.scriptArgs; - } app_conf.script = script; @@ -656,8 +649,6 @@ class API { app_conf = appConf[0]; - app_conf.username = Common.getCurrentUsername(); - /** * If -w option, write configuration to configuration.json file */ diff --git a/lib/Common.js b/lib/Common.js index 662df66b..d0523cf1 100644 --- a/lib/Common.js +++ b/lib/Common.js @@ -584,9 +584,34 @@ Common.verifyConfs = function(appConfs){ for (var i = 0; i < appConfs.length; i++) { var app = appConfs[i]; - if (app.disable_trace) { - app.trace = false - delete app.disable_trace; + // JSON conf: alias cmd to script + if (app.cmd && !app.script) { + app.script = app.cmd + delete app.cmd + } + // JSON conf: alias command to script + if (app.command && !app.script) { + app.script = app.command + delete app.command + } + + app.username = Common.getCurrentUsername(); + + // If command is like pm2 start "python xx.py --ok" + // Then automatically start the script with bash -c and set a name eq to command + if (app.script && app.script.indexOf(' ') > -1) { + var _script = app.script; + if (require('shelljs').which('bash')) + app.script = 'bash'; + else if (require('shelljs').which('sh')) + app.script = 'sh'; + else + throw new Error('bash and sh not available in $PATH') + + app.args = ['-c', _script]; + if (!app.name) { + app.name = _script + } } if ((app.uid || app.gid) && app.force !== true) { @@ -596,14 +621,20 @@ Common.verifyConfs = function(appConfs){ } } - // If no uid set and command runned as sudo, use the parent shell USER - // to set it to his uid and not root - // if (!app.uid && process.env.SUDO_USER) { - // app.uid = process.env.SUDO_USER; - // } + // Specific options of PM2.io + if (process.env.PM2_DEEP_MONITORING) + app.deep_monitoring = true; - // Warn deprecates. - checkDeprecates(app); + if (app.disable_trace) { + app.trace = false + delete app.disable_trace; + } + + if (app.instances == 'max') + app.instances = 0; + // Sanity check, default to number of cores if value can't be parsed + if (typeof(app.instances) === 'string') + app.instances = parseInt(app.instances) || 0; // Check Exec mode checkExecMode(app); @@ -612,9 +643,8 @@ Common.verifyConfs = function(appConfs){ prepareAppName(app); var ret = Config.validateJSON(app); - //debug('After processing', ret); - // Show errors if existing. + // Show errors if existing. if (ret.errors && ret.errors.length > 0){ ret.errors.forEach(function(err){ warn(err); @@ -688,18 +718,6 @@ function checkExecMode(conf) { } } -/** - * Check deprecates and show warnings. - * @param {Object} conf - */ -function checkDeprecates(conf){ - if (conf.instances == 'max') - conf.instances = 0; - // Sanity check, default to number of cores if value can't be parsed - if (typeof(conf.instances) === 'string') - conf.instances = parseInt(conf.instances) || 0; -} - /** * Render an app name if not existing. * @param {Object} conf diff --git a/test/e2e.sh b/test/e2e.sh index 9f0d8619..1b73924a 100644 --- a/test/e2e.sh +++ b/test/e2e.sh @@ -18,6 +18,8 @@ spec "module safeguard system (--safe)" # CLI bash ./test/e2e/cli/reload.sh spec "Reload" +bash ./test/e2e/cli/start-app.sh +spec "Command line passing" bash ./test/e2e/cli/operate-regex.sh spec "Operate process that match regex" bash ./test/e2e/cli/interpreter.sh diff --git a/test/e2e/cli/start-app.sh b/test/e2e/cli/start-app.sh new file mode 100644 index 00000000..70fa7442 --- /dev/null +++ b/test/e2e/cli/start-app.sh @@ -0,0 +1,38 @@ +#!/usr/bin/env bash + +SRC=$(cd $(dirname "$0"); pwd) +source "${SRC}/../include.sh" + +echo -e "\033[1mRunning tests:\033[0m" + +cd $file_path/start-app + +# +# Direct command +# +$pm2 delete all + +$pm2 start "node -e 'setTimeout(function() { }, 100000); console.log(process.env.TEST)'" -l test.log --merge-logs +should 'should have started command' 'online' 1 +should 'should have not been restarted' 'restart_time: 0' 1 + +cat test.log | grep "undefined" +spec "should have printed undefined env var" + +TEST='ok' $pm2 restart 0 --update-env +cat test.log | grep "ok" + +should 'should have started command' 'online' 1 +should 'should have not been restarted' 'restart_time: 1' 1 +spec "should have printed undefined env var" + +# +# Direct command via Conf file +# +$pm2 delete all + +$pm2 start ecosystem.config.js +should 'should have started command' 'online' 1 +should 'should have not been restarted' 'restart_time: 0' 1 +cat test-conf.log | grep "test_val" +spec "should have printed the test_val" diff --git a/test/fixtures/start-app/ecosystem.config.js b/test/fixtures/start-app/ecosystem.config.js new file mode 100644 index 00000000..2fc0a706 --- /dev/null +++ b/test/fixtures/start-app/ecosystem.config.js @@ -0,0 +1,10 @@ +module.exports = { + apps : [{ + cmd: "node -e 'setTimeout(function() { }, 100000); console.log(process.env.TEST)'", + log: 'test-conf.log', + merge_logs: true, + env: { + TEST: 'test_val' + } + }] +}; diff --git a/test/fixtures/start-app/http.js b/test/fixtures/start-app/http.js new file mode 100644 index 00000000..0dc42cb1 --- /dev/null +++ b/test/fixtures/start-app/http.js @@ -0,0 +1,21 @@ + +var http = require('http'); + +var app = http.createServer(function(req, res) { + res.writeHead(200); + res.end('hey'); +}) + +var listener = app.listen(0, function() { + console.log('Listening on port ' + listener.address().port); +}); + +process.on('message', function(msg) { + if (msg == 'shutdown') { + console.log('Closing all connections...'); + setTimeout(function() { + console.log('Finished closing connections'); + process.exit(0); + }, 100); + } +}); From ae02adf63f70ceb3bf101be968996ca68d9ce277 Mon Sep 17 00:00:00 2001 From: Alexandre Strzelewicz Date: Sun, 27 May 2018 16:35:54 +0200 Subject: [PATCH 112/140] BREAKING: merge_logs is now activated by default if not in cluster mode. Logs will not be suffixed by the pm_id if only one app is started --- lib/Common.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/lib/Common.js b/lib/Common.js index d0523cf1..4981afd9 100644 --- a/lib/Common.js +++ b/lib/Common.js @@ -639,6 +639,9 @@ Common.verifyConfs = function(appConfs){ // Check Exec mode checkExecMode(app); + if (app.exec_mode != 'cluster_mode' && !app.instances) + app.merge_logs = true; + // Render an app name if not existing. prepareAppName(app); From aa183ba19d88777d82619aa40499c2661d67879e Mon Sep 17 00:00:00 2001 From: Alexandre Strzelewicz Date: Sun, 27 May 2018 16:36:05 +0200 Subject: [PATCH 113/140] chore: change motd wording --- lib/motd | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/lib/motd b/lib/motd index e2001d75..37e0505b 100644 --- a/lib/motd +++ b/lib/motd @@ -12,12 +12,11 @@ __/\\\\\\\\\\\\\____/\\\\____________/\\\\____/\\\\\\\\\_____ _\///______________\///______________\///__\///////////////__ - Community Edition + Runtime Edition - Production Process Manager for Node.js applications + PM2 is a Production Process Manager for Node.js applications with a built-in Load Balancer. - Start and Daemonize any application: $ pm2 start app.js From bb094b445ea01e9db8ff29fa3f5259167db23805 Mon Sep 17 00:00:00 2001 From: Alexandre Strzelewicz Date: Sun, 27 May 2018 16:59:36 +0200 Subject: [PATCH 114/140] feature: alias pm2 delete to pm2 del --- bin/pm2 | 1 + 1 file changed, 1 insertion(+) diff --git a/bin/pm2 b/bin/pm2 index a77b7ea0..62dcbf8a 100755 --- a/bin/pm2 +++ b/bin/pm2 @@ -422,6 +422,7 @@ commander.command('inspect ') // Stop and delete a process by name from database // commander.command('delete ') + .alias('del') .description('stop and delete a process from pm2 process list') .action(function(name) { if (name == "-") { From f0249684bcbfdb75749a516f447c8e8d32020709 Mon Sep 17 00:00:00 2001 From: Alexandre Strzelewicz Date: Sun, 27 May 2018 19:33:53 +0200 Subject: [PATCH 115/140] fix: #3688 test adaptation + pm2 serve --port option --- bin/pm2 | 5 ++-- lib/Common.js | 3 +- test/e2e/cli/serve.sh | 29 ++++++++++--------- test/e2e/misc/cron-system.sh | 10 +++---- test/e2e/misc/inside-pm2.sh | 6 ++-- .../path-resolution/ecosystem3.config.js | 15 ++++++++++ test/programmatic/logs.js | 3 +- test/programmatic/path_resolution.mocha.js | 21 +++++++++++--- 8 files changed, 62 insertions(+), 30 deletions(-) create mode 100644 test/fixtures/path-resolution/ecosystem3.config.js diff --git a/bin/pm2 b/bin/pm2 index 62dcbf8a..002657e7 100755 --- a/bin/pm2 +++ b/bin/pm2 @@ -929,9 +929,10 @@ commander.command('deepUpdate') // commander.command('serve [path] [port]') .alias('expose') + .option('--port [port]', 'specify port to listen to') .description('serve a directory over http via port') - .action(function (path, port) { - pm2.serve(path, port, commander); + .action(function (path, port, cmd) { + pm2.serve(path, port || cmd.port, commander); }); commander.command('examples') diff --git a/lib/Common.js b/lib/Common.js index 4981afd9..35b13389 100644 --- a/lib/Common.js +++ b/lib/Common.js @@ -639,7 +639,8 @@ Common.verifyConfs = function(appConfs){ // Check Exec mode checkExecMode(app); - if (app.exec_mode != 'cluster_mode' && !app.instances) + if (app.exec_mode != 'cluster_mode' && + !app.instances && typeof(app.merge_logs) == 'undefined') app.merge_logs = true; // Render an app name if not existing. diff --git a/test/e2e/cli/serve.sh b/test/e2e/cli/serve.sh index 48289bbe..e4179af0 100644 --- a/test/e2e/cli/serve.sh +++ b/test/e2e/cli/serve.sh @@ -4,18 +4,19 @@ SRC=$(cd $(dirname "$0"); pwd) source "${SRC}/../include.sh" cd $file_path/serve - +PORT=8081 +PORT_2=8082 echo "################## PM2 SERVE ###################" -$pm2 serve +$pm2 serve --port $PORT should 'should have started serving dir' 'online' 1 -curl http://localhost:8080/ > /tmp/tmp_out.txt +curl http://localhost:$PORT/ > /tmp/tmp_out.txt OUT=`cat /tmp/tmp_out.txt | grep -o "good shit" | wc -l` [ $OUT -eq 1 ] || fail "should have served index file under /" success "should have served index file under /" -curl http://localhost:8080/index.html > /tmp/tmp_out.txt +curl http://localhost:$PORT/index.html > /tmp/tmp_out.txt OUT=`cat /tmp/tmp_out.txt | grep -o "good shit" | wc -l` [ $OUT -eq 1 ] || fail "should have served index file under /index.html" success "should have served index file under /index.html" @@ -23,31 +24,31 @@ success "should have served index file under /index.html" echo "Shutting down the server" $pm2 delete all -curl http://localhost:8080/index.html > /tmp/tmp_out.txt +curl http://localhost:$PORT/index.html > /tmp/tmp_out.txt OUT=`cat /tmp/tmp_out.txt | grep -o "good shit" | wc -l` [ $OUT -eq 0 ] || fail "should be offline" success "should be offline" -$pm2 serve . 8000 +$pm2 serve . $PORT_2 should 'should have started serving dir' 'online' 1 -curl http://localhost:8000/index.html > /tmp/tmp_out.txt +curl http://localhost:$PORT_2/index.html > /tmp/tmp_out.txt OUT=`cat /tmp/tmp_out.txt | grep -o "good shit" | wc -l` -[ $OUT -eq 1 ] || fail "should be listening on port 8000" -success "should be listening on port 8000" +[ $OUT -eq 1 ] || fail "should be listening on port $PORT_2" +success "should be listening on port $PORT_2" $pm2 delete all -$pm2 serve . 8000 --name frontend +$pm2 serve . $PORT_2 --name frontend should 'should have started serving dir' 'online' 1 should 'should have custom name' 'frontend' 7 -curl http://localhost:8000/index.html > /tmp/tmp_out.txt +curl http://localhost:$PORT_2/index.html > /tmp/tmp_out.txt OUT=`cat /tmp/tmp_out.txt | grep -o "good shit" | wc -l` -[ $OUT -eq 1 ] || fail "should be listening on port 8000" -success "should be listening on port 8000" +[ $OUT -eq 1 ] || fail "should be listening on port $PORT_2" +success "should be listening on port $PORT_2" -curl http://localhost:8000/yolo.html > /tmp/tmp_out.txt +curl http://localhost:$PORT_2/yolo.html > /tmp/tmp_out.txt OUT=`cat /tmp/tmp_out.txt | grep -o "your file doesnt exist" | wc -l` [ $OUT -eq 1 ] || fail "should have served custom 404 file" success "should have served custom 404 file" diff --git a/test/e2e/misc/cron-system.sh b/test/e2e/misc/cron-system.sh index f97376c1..d9dbbe0e 100644 --- a/test/e2e/misc/cron-system.sh +++ b/test/e2e/misc/cron-system.sh @@ -16,12 +16,12 @@ spec "Should cron restart echo.js" $pm2 delete all -> mock-0.log +> mock.log $pm2 start cron/mock-cron.js -o mock.log sleep 3 should 'should app been restarted when cron in fork mode' 'restart_time: 0' 0 -cat mock-0.log | grep "SIGINT" +cat mock.log | grep "SIGINT" spec "1# Should cron exit call SIGINT handler" $pm2 delete all @@ -29,7 +29,7 @@ $pm2 delete all $pm2 start cron/mock-cron.js -o mock.log -i 1 sleep 3 should 'should app been restarted when cron in cluster mode' 'restart_time: 0' 0 -cat mock-0.log | grep "SIGINT" +cat mock.log | grep "SIGINT" spec "2# Should cron exit call SIGINT handler" $pm2 delete all @@ -38,7 +38,7 @@ $pm2 delete all $pm2 start cron/mock-cron-no-exit.js -o mock.log sleep 3 should 'should app been restarted' 'restart_time: 0' 0 -cat mock-0.log | grep "SIGINT" +cat mock.log | grep "SIGINT" spec "3# Should cron exit call SIGINT handler" @@ -52,7 +52,7 @@ spec "Should cron restart delayed sigint" sleep 100 -cat cron-0.log | grep "SIGINT cb called" +cat cron.log | grep "SIGINT cb called" spec "Should cron exit call SIGINT handler" should 'should app been restarted' 'restart_time: 1' 1 diff --git a/test/e2e/misc/inside-pm2.sh b/test/e2e/misc/inside-pm2.sh index 377241d6..6646e8fb 100644 --- a/test/e2e/misc/inside-pm2.sh +++ b/test/e2e/misc/inside-pm2.sh @@ -12,7 +12,7 @@ echo -e "\033[1mRunning tests:\033[0m" #################################################################### TEST_VARIABLE='hello1' $pm2 start startProcessInsidePm2.json ->inside-out-1.log +>inside-out.log sleep 1 @@ -25,12 +25,12 @@ $pm2 list should 'child process should be started' 'pm_id: 1' 2 should 'restarted status should be zero' "restart_time: 0" 2 -grep "hello1" inside-out-1.log &> /dev/null +grep "hello1" inside-out.log &> /dev/null spec "Child should have hello1 variable" TEST_VARIABLE='hello2' $pm2 restart "insideProcess" --update-env sleep 1 -grep "hello2" inside-out-1.log &> /dev/null +grep "hello2" inside-out.log &> /dev/null spec "Child should have hello2 variable after restart" # Call bash script that restarts app diff --git a/test/fixtures/path-resolution/ecosystem3.config.js b/test/fixtures/path-resolution/ecosystem3.config.js new file mode 100644 index 00000000..d201bfdd --- /dev/null +++ b/test/fixtures/path-resolution/ecosystem3.config.js @@ -0,0 +1,15 @@ +module.exports = { + /** + * Application configuration section + * http://pm2.keymetrics.io/docs/usage/application-declaration/ + */ + apps : [ + { + name : "test-cluster", + script : "./echo.js", + out_file : 'echo-out.log', + error_file : 'echo-err.log', + instances: 4 + } + ] +} diff --git a/test/programmatic/logs.js b/test/programmatic/logs.js index 6cf72e6b..8f73f908 100644 --- a/test/programmatic/logs.js +++ b/test/programmatic/logs.js @@ -33,7 +33,8 @@ describe('Programmatic log feature test', function() { pm2.start({ script: './echo.js', error_file : 'error-echo.log', - out_file : 'out-echo.log' + out_file : 'out-echo.log', + merge_logs: false }, function(err, procs) { should(err).be.null(); diff --git a/test/programmatic/path_resolution.mocha.js b/test/programmatic/path_resolution.mocha.js index 2c6f40b1..a29ed0d1 100644 --- a/test/programmatic/path_resolution.mocha.js +++ b/test/programmatic/path_resolution.mocha.js @@ -6,6 +6,7 @@ var PM2 = require('../..'); var should = require('should'); describe('Path resolution in configuration file', function() { + this.timeout(4000) before(function(done) { PM2.delete('all', function() { done() } ); }); @@ -16,8 +17,8 @@ describe('Path resolution in configuration file', function() { it('should resolve paths (home)', function(done) { PM2.start('./path-resolution/ecosystem.config.js', function(err, proc) { - should(proc[0].pm2_env.pm_err_log_path).eql(path.join(process.env.HOME, 'echo-err-0.log')); - should(proc[0].pm2_env.pm_out_log_path).eql(path.join(process.env.HOME, 'echo-out-0.log')); + should(proc[0].pm2_env.pm_err_log_path).eql(path.join(process.env.HOME, 'echo-err.log')); + should(proc[0].pm2_env.pm_out_log_path).eql(path.join(process.env.HOME, 'echo-out.log')); should(proc[0].pm2_env.pm_pid_path).eql(path.join(process.env.HOME, 'echo-pid.log')); done(); }); @@ -25,10 +26,22 @@ describe('Path resolution in configuration file', function() { it('should resolve paths (local)', function(done) { PM2.start('./path-resolution/ecosystem2.config.js', function(err, proc) { - should(proc[0].pm2_env.pm_err_log_path).eql(path.join(process.cwd(), 'echo-err-0.log')); - should(proc[0].pm2_env.pm_out_log_path).eql(path.join(process.cwd(), 'echo-out-0.log')); + should(proc[0].pm2_env.pm_err_log_path).eql(path.join(process.cwd(), 'echo-err.log')); + should(proc[0].pm2_env.pm_out_log_path).eql(path.join(process.cwd(), 'echo-out.log')); should(proc[0].pm2_env.pm_pid_path).eql(path.join(process.cwd(), 'echo-pid.log')); done(); }); }); + + it('should auto prefix log path on cluster mode', function(done) { + PM2.start('./path-resolution/ecosystem3.config.js', function(err, proc) { + should(proc[0].pm2_env.pm_err_log_path).eql(path.join(process.cwd(), 'echo-err-0.log')); + should(proc[0].pm2_env.pm_out_log_path).eql(path.join(process.cwd(), 'echo-out-0.log')); + + should(proc[1].pm2_env.pm_err_log_path).eql(path.join(process.cwd(), 'echo-err-1.log')); + should(proc[1].pm2_env.pm_out_log_path).eql(path.join(process.cwd(), 'echo-out-1.log')); + done(); + }); + }); + }); From 99cd385038971d4fa2129abfda3d52f1a7041abc Mon Sep 17 00:00:00 2001 From: Alexandre Strzelewicz Date: Tue, 29 May 2018 21:36:34 +0200 Subject: [PATCH 116/140] pm2 login/register: fix legacy login --- lib/API/Keymetrics/kmapi.js | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/lib/API/Keymetrics/kmapi.js b/lib/API/Keymetrics/kmapi.js index 6cd75dcf..f38431e9 100644 --- a/lib/API/Keymetrics/kmapi.js +++ b/lib/API/Keymetrics/kmapi.js @@ -5,6 +5,7 @@ var url = require('url'); var cst = require('../../../constants.js'); var KM = function() { + this.AUTH_URI = 'https://id.keymetrics.io'; this.BASE_URI = 'https://app.keymetrics.io'; this.CLIENT_ID = '938758711'; this.CB_URI = 'https://app.keymetrics.io'; @@ -24,19 +25,19 @@ KM.prototype.loginAndGetAccessToken = function (user_info, cb) { var URL_AUTH = '/api/oauth/authorize?response_type=token&scope=all&client_id=' + that.CLIENT_ID + '&redirect_uri=' + that.CB_URI; - needle.get(that.BASE_URI + URL_AUTH, function(err, res) { + needle.get(that.AUTH_URI + URL_AUTH, function(err, res) { if (err) return cb(err); var cookie = res.cookies; - needle.post(that.BASE_URI + '/api/oauth/login', user_info, { + needle.post(that.AUTH_URI + '/api/oauth/login', user_info, { cookies : cookie }, function(err, resp, body) { if (err) return cb(err); - if (body.indexOf('/api/oauth/login') > -1) return cb('Wrong credentials'); + if (resp.statusCode != 200) return cb('Wrong credentials'); - var location = resp.headers.location; - var redirect = that.BASE_URI + location; + var location = resp.headers['x-redirect']; + var redirect = that.AUTH_URI + location; needle.get(redirect, { cookies : cookie @@ -44,7 +45,7 @@ KM.prototype.loginAndGetAccessToken = function (user_info, cb) { if (err) return cb(err); var refresh_token = querystring.parse(url.parse(res.headers.location).query).access_token; - needle.post(that.BASE_URI + '/api/oauth/token', { + needle.post(that.AUTH_URI + '/api/oauth/token', { client_id : that.CLIENT_ID, grant_type : 'refresh_token', refresh_token : refresh_token, From db09275f8e353e257c89e12fed754236b15cee74 Mon Sep 17 00:00:00 2001 From: Alexandre Strzelewicz Date: Wed, 30 May 2018 14:46:06 +0200 Subject: [PATCH 117/140] fix: deprecated warning on isbinaryfile --- lib/tools/isbinaryfile.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/tools/isbinaryfile.js b/lib/tools/isbinaryfile.js index 65f37fdf..7b0135d0 100644 --- a/lib/tools/isbinaryfile.js +++ b/lib/tools/isbinaryfile.js @@ -18,7 +18,7 @@ module.exports = function(bytes, size) { } var descriptor = fs.openSync(file, 'r'); try { - bytes = new Buffer(max_bytes); + bytes = Buffer.alloc(max_bytes); size = fs.readSync(descriptor, bytes, 0, bytes.length, 0); } finally { fs.closeSync(descriptor); @@ -32,7 +32,7 @@ module.exports = function(bytes, size) { fs.open(file, 'r', function(err, descriptor){ if (err) return callback(err); - var bytes = new Buffer(max_bytes); + var bytes = Buffer.alloc(max_bytes); // Read the file with no encoding for raw buffer access. fs.read(descriptor, bytes, 0, bytes.length, 0, function(err, size, bytes){ fs.close(descriptor, function(err2){ From cb6521ac32f4737c42fc97fef972960bfe16c829 Mon Sep 17 00:00:00 2001 From: Alexandre Strzelewicz Date: Wed, 30 May 2018 14:48:21 +0200 Subject: [PATCH 118/140] refactor: use @pm2/js-api for login/register on pm2.io via CLI --- lib/API.js | 2 +- lib/API/Keymetrics/cli-api.js | 253 --------------------------- lib/API/Keymetrics/kmapi.js | 164 ------------------ lib/API/PM2/CliAuth.js | 285 +++++++++++++++++++++++++++++++ lib/API/PM2/PM2IO.js | 245 ++++++++++++++++++++++++++ lib/API/PM2/WebAuth.js | 192 +++++++++++++++++++++ lib/API/{Keymetrics => PM2}/motd | 0 package.json | 1 + paths.js | 2 +- 9 files changed, 725 insertions(+), 419 deletions(-) delete mode 100644 lib/API/Keymetrics/cli-api.js delete mode 100644 lib/API/Keymetrics/kmapi.js create mode 100644 lib/API/PM2/CliAuth.js create mode 100644 lib/API/PM2/PM2IO.js create mode 100644 lib/API/PM2/WebAuth.js rename lib/API/{Keymetrics => PM2}/motd (100%) diff --git a/lib/API.js b/lib/API.js index ff89d5e1..8424ef79 100644 --- a/lib/API.js +++ b/lib/API.js @@ -1642,7 +1642,7 @@ require('./API/Extra.js')(API); require('./API/Interaction.js')(API); require('./API/Deploy.js')(API); require('./API/Modules/Modules.js')(API); -require('./API/Keymetrics/cli-api.js')(API); +require('./API/PM2/PM2IO.js')(API); require('./API/Configuration.js')(API); require('./API/Version.js')(API); require('./API/Startup.js')(API); diff --git a/lib/API/Keymetrics/cli-api.js b/lib/API/Keymetrics/cli-api.js deleted file mode 100644 index e6561e7d..00000000 --- a/lib/API/Keymetrics/cli-api.js +++ /dev/null @@ -1,253 +0,0 @@ -var cst = require('../../../constants.js'); -var Common = require('../../Common.js'); -var UX = require('../CliUx'); -var chalk = require('chalk'); -var async = require('async'); -var path = require('path'); -var fs = require('fs'); -var KMDaemon = require('@pm2/agent/src/InteractorClient'); -var Table = require('cli-table-redemption'); -var open = require('../../tools/open.js'); -var promptly = require('promptly'); -var pkg = require('../../../package.json') - -module.exports = function(CLI) { - - CLI.prototype.openDashboard = function() { - var that = this; - - KMDaemon.getInteractInfo(this._conf, function(err, data) { - if (err) { - Common.printError(chalk.bold.white('Agent if offline, type `$ pm2 register` to log in')); - return that.exitCli(cst.ERROR_EXIT); - } - Common.printOut(chalk.bold('Opening Dashboard in Browser...')); - open('https://app.pm2.io/#/r/' + data.public_key); - setTimeout(function() { - that.exitCli(); - }, 200); - }); - }; - - CLI.prototype.loginToKM = function() { - printMotd(); - return loginPrompt(); - }; - - CLI.prototype.registerToKM = function() { - printMotd(); - - promptly.confirm(chalk.bold('Do you have a pm2.io account? (y/n)'), function (err, answer) { - if (answer == true) { - return loginPrompt(); - } - registerPrompt(); - }); - }; - - /** - * Monitor Selectively Processes (auto filter in interaction) - * @param String state 'monitor' or 'unmonitor' - * @param String target - * @param Function cb callback - */ - CLI.prototype.monitorState = function(state, target, cb) { - var that = this; - - if (process.env.NODE_ENV !== 'test') { - try { - fs.statSync(this._conf.INTERACTION_CONF); - } catch(e) { - printMotd(); - return registerPrompt(); - } - } - - if (!target) { - Common.printError(cst.PREFIX_MSG_ERR + 'Please specify an '); - return cb ? cb(new Error('argument missing')) : that.exitCli(cst.ERROR_EXIT); - } - - function monitor (pm_id, cb) { - // State can be monitor or unmonitor - that.Client.executeRemote(state, pm_id, cb); - } - if (target === 'all') { - that.Client.getAllProcessId(function (err, procs) { - if (err) { - Common.printError(err); - return cb ? cb(Common.retErr(err)) : that.exitCli(cst.ERROR_EXIT); - } - async.forEachLimit(procs, 1, monitor, function (err, res) { - return typeof cb === 'function' ? cb(err, res) : that.speedList(); - }); - }); - } else if (!Number.isInteger(parseInt(target))) { - this.Client.getProcessIdByName(target, true, function (err, procs) { - if (err) { - Common.printError(err); - return cb ? cb(Common.retErr(err)) : that.exitCli(cst.ERROR_EXIT); - } - async.forEachLimit(procs, 1, monitor, function (err, res) { - return typeof cb === 'function' ? cb(err, res) : that.speedList(); - }); - }); - } else { - monitor(parseInt(target), function (err, res) { - return typeof cb === 'function' ? cb(err, res) : that.speedList(); - }); - } - }; - - - /** - * Private Functions - */ - - function printMotd() { - var dt = fs.readFileSync(path.join(__dirname, 'motd')); - console.log(dt.toString()); - } - - function validateEmail(email) { - var re = /^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/; - if (re.test(email) == false) - throw new Error('Not an email'); - return email; - } - - function validateUsername(value) { - if (value.length < 6) { - throw new Error('Min length of 6'); - } - return value; - }; - - - function linkOpenExit(target_bucket) { - KMDaemon.launchAndInteract(cst, { - public_key : target_bucket.public_id, - secret_key : target_bucket.secret_id, - pm2_version: pkg.version - }, function(err, dt) { - open('https://app.pm2.io/#/r/' + target_bucket.public_id); - setTimeout(function() { - process.exit(cst.SUCCESS_EXIT); - }, 100); - }); - } - - /** - * Login on Keymetrics - * Link to the only bucket or list bucket for selection - * Open Browser - */ - function loginPrompt(cb) { - var KM = require('./kmapi.js'); - console.log(chalk.bold('Log in to pm2.io')); - (function retry() { - promptly.prompt('Username or Email: ', function(err, username) { - promptly.password('Password: ', { replace : '*' }, function(err, password) { - KM.loginAndGetAccessToken({ username : username, password: password }, function(err) { - if (err) { - console.error(chalk.red.bold(err) + '\n'); - return retry(); - } - KM.getBuckets(function(err, buckets) { - if (err) { - console.error(chalk.red.bold(err) + '\n'); - return retry(); - } - - if (buckets.length > 1) { - console.log(chalk.bold('Bucket list')); - - var table = new Table({ - style : {'padding-left' : 1, head : ['cyan', 'bold'], compact : true}, - head : ['Bucket name', 'Plan type'] - }); - - buckets.forEach(function(bucket) { - table.push([bucket.name, bucket.credits.offer_type]); - }); - - console.log(table.toString()); - - (function retryInsertion() { - promptly.prompt('Type the bucket you want to link to: ', function(err, bucket_name) { - var target_bucket = null; - - buckets.some(function(bucket) { - if (bucket.name == bucket_name) { - target_bucket = bucket; - return true; - } - }); - - if (target_bucket == null) - return retryInsertion(); - linkOpenExit(target_bucket); - }); - })(); - } - else { - var target_bucket = buckets[0]; - console.log('Connecting local PM2 Runtime to pm2.io, bucket name= [%s]', target_bucket.name); - - KMDaemon.launchAndInteract(cst, { - public_key : target_bucket.public_id, - secret_key : target_bucket.secret_id, - pm2_version: pkg.version - }, function(err, dt) { - linkOpenExit(target_bucket); - }); - } - }); - }); - - }); - }) - })() - } - - /** - * Register on Keymetrics - * Create Bucket - * Auto Link local PM2 to new Bucket - * Open Browser for access to monitoring dashboard - */ - function registerPrompt() { - var KM = require('./kmapi.js'); - - console.log(chalk.bold('Now registering to pm2.io')); - promptly.prompt('Username: ', { - validator : validateUsername, - retry : true - }, function(err, username) { - promptly.prompt('Email: ', { - validator : validateEmail, - retry : true - }, function(err, email) { - promptly.password('Password: ', { replace : '*' }, function(err, password) { - process.stdout.write(chalk.bold('Creating account on pm2.io ...')); - var inter = setInterval(function() { - process.stdout.write('.'); - }, 300); - KM.fullCreationFlow({ - email : email, - password : password, - username : username - }, function(err, target_bucket) { - clearInterval(inter); - if (err) { - console.error('\n' + chalk.red.bold(err) + '\n'); - return registerPrompt(); - } - linkOpenExit(target_bucket); - }); - }); - }); - }) - } - -}; diff --git a/lib/API/Keymetrics/kmapi.js b/lib/API/Keymetrics/kmapi.js deleted file mode 100644 index f38431e9..00000000 --- a/lib/API/Keymetrics/kmapi.js +++ /dev/null @@ -1,164 +0,0 @@ - -var fs = require('fs'); -var needle = require('needle'); -var url = require('url'); -var cst = require('../../../constants.js'); - -var KM = function() { - this.AUTH_URI = 'https://id.keymetrics.io'; - this.BASE_URI = 'https://app.keymetrics.io'; - this.CLIENT_ID = '938758711'; - this.CB_URI = 'https://app.keymetrics.io'; - this.ACCESS_TOKEN_FILE = cst.KM_ACCESS_TOKEN; - this.access_token = null; -} - -/** - * @param user_info.username - * @param user_info.password - * @return promise - */ -KM.prototype.loginAndGetAccessToken = function (user_info, cb) { - var querystring = require('querystring'); - - var that = this; - var URL_AUTH = '/api/oauth/authorize?response_type=token&scope=all&client_id=' + - that.CLIENT_ID + '&redirect_uri=' + that.CB_URI; - - needle.get(that.AUTH_URI + URL_AUTH, function(err, res) { - if (err) return cb(err); - - var cookie = res.cookies; - - needle.post(that.AUTH_URI + '/api/oauth/login', user_info, { - cookies : cookie - }, function(err, resp, body) { - if (err) return cb(err); - if (resp.statusCode != 200) return cb('Wrong credentials'); - - var location = resp.headers['x-redirect']; - var redirect = that.AUTH_URI + location; - - needle.get(redirect, { - cookies : cookie - }, function(err, res) { - if (err) return cb(err); - var refresh_token = querystring.parse(url.parse(res.headers.location).query).access_token; - - needle.post(that.AUTH_URI + '/api/oauth/token', { - client_id : that.CLIENT_ID, - grant_type : 'refresh_token', - refresh_token : refresh_token, - scope : 'all' - }, function(err, res, body) { - if (err) return cb(err); - that.access_token = body.access_token; - return cb(null, body.access_token); - }) - }); - }); - }); -} - -KM.prototype.getLocalAccessToken = function(cb) { - var that = this; - - fs.readFile(that.ACCESS_TOKEN_FILE, function(e, content) { - if (e) return cb(e); - cb(null, content.toString()); - }); -}; - -KM.prototype.saveLocalAccessToken = function(access_token, cb) { - var that = this; - fs.writeFile(that.ACCESS_TOKEN_FILE, access_token, function(e, content) { - if (e) return cb(e); - cb(); - }); -}; - -KM.prototype.getBuckets = function(cb) { - var that = this; - - needle.get(that.BASE_URI + '/api/bucket', { - headers : { - 'Authorization' : 'Bearer ' + that.access_token - }, - json : true - }, function(err, res, body) { - if (err) return cb(err); - return cb(null, body); - }); -} - -/** - * @param user_info.username - * @param user_info.password - * @param user_info.email - * @return promise - */ -KM.prototype.register = function(user_info, cb) { - var that = this; - - needle.post(that.BASE_URI + '/api/oauth/register', user_info, { - json: true, - headers: { - 'X-Register-Provider': 'pm2-register' - } - }, function (err, res, body) { - if (err) return cb(err); - if (body.email && body.email.message) return cb(body.email.message); - if (body.username && body.username.message) return cb(body.username.message); - - cb(null, { - token : body.access_token.token - }) - }); -}; - -KM.prototype.defaultNode = function(cb) { - var that = this; - - needle.get(that.BASE_URI + '/api/node/default', function(err, res, body) { - if (err) return cb(err); - cb(null, url.parse(body.endpoints.web).protocol + '//' + url.parse(body.endpoints.web).hostname); - }); -} - - -KM.prototype.createBucket = function(default_node, bucket_name, cb) { - var that = this; - - needle.post(default_node + '/api/bucket/create_classic', { - name : bucket_name - }, { - json : true, - headers : { - 'Authorization' : 'Bearer ' + that.access_token - } - }, function(err, res, body) { - if (err) return cb(err); - cb(null, body); - }); -} - -KM.prototype.fullCreationFlow = function(user_info, cb) { - var that = this; - - this.register(user_info, function(err, dt) { - if (err) return cb(err); - that.access_token = dt.token; - that.defaultNode(function(err, default_node) { - if (err) return cb(err); - that.createBucket(default_node, 'Node Monitoring', function(err, packet) { - if (err) return cb(err); - return cb(null, { - secret_id : packet.bucket.secret_id, - public_id : packet.bucket.public_id - }); - }); - }) - }); -} - -module.exports = new KM; diff --git a/lib/API/PM2/CliAuth.js b/lib/API/PM2/CliAuth.js new file mode 100644 index 00000000..17e74d8b --- /dev/null +++ b/lib/API/PM2/CliAuth.js @@ -0,0 +1,285 @@ + + +'use strict' + +const AuthStrategy = require('@pm2/js-api/src/auth_strategies/strategy') + +const http = require('http') +const fs = require('fs') +const url = require('url') +const exec = require('child_process').exec +const async = require('async') +const path = require('path') +const os = require('os') +const needle = require('needle'); +const chalk = require('chalk') +const cst = require('../../../constants.js'); + +module.exports = class CustomStrategy extends AuthStrategy { + // the client will try to call this but we handle this part ourselves + retrieveTokens (km, cb) { + this.authenticated = false + this.callback = cb + this.km = km + this.BASE_URI = 'https://app.keymetrics.io'; + } + + // so the cli know if we need to tell user to login/register + isAuthenticated () { + return new Promise((resolve, reject) => { + if (this.authenticated) return resolve(true) + + let tokensPath = cst.PM2_IO_ACCESS_TOKEN + fs.readFile(tokensPath, (err, tokens) => { + if (err && err.code === 'ENOENT') return resolve(false) + if (err) return reject(err) + + // verify that the token is valid + try { + tokens = JSON.parse(tokens || '{}') + } catch (err) { + fs.unlinkSync(tokensPath) + return resolve(false) + } + + // if the refresh tokens is here, the user could be automatically authenticated + return resolve(typeof tokens.refresh_token === 'string') + }) + }) + } + + verifyToken (refresh) { + return this.km.auth.retrieveToken({ + client_id: this.client_id, + refresh_token: refresh + }) + } + + // called when we are sure the user asked to be logged in + _retrieveTokens (optionalCallback) { + const km = this.km + const cb = this.callback + + async.tryEach([ + // try to find the token via the environement + (next) => { + if (!process.env.KM_TOKEN) { + return next(new Error('No token in env')) + } + this.verifyToken(process.env.KM_TOKEN) + .then((res) => { + return next(null, res.data) + }).catch(next) + }, + // try to find it in the file system + (next) => { + return next(new Error('nope')) + + fs.readFile(cst.PM2_IO_ACCESS_TOKEN, (err, tokens) => { + if (err) return next(err) + + // verify that the token is valid + tokens = JSON.parse(tokens || '{}') + if (new Date(tokens.expire_at) > new Date(new Date().toISOString())) { + return next(null, tokens) + } + + this.verifyToken(tokens.refresh_token) + .then((res) => { + return next(null, res.data) + }).catch(next) + }) + }, + // otherwise make the whole flow + (next) => { + return this.loginViaCLI((data) => { + // verify that the token is valid + this.verifyToken(data.refresh_token) + .then((res) => { + return next(null, res.data) + }).catch(next) + }) + } + ], (err, result) => { + // if present run the optional callback + if (typeof optionalCallback === 'function') { + optionalCallback(err, result) + } + + if (result.refresh_token) { + this.authenticated = true + let file = cst.PM2_IO_ACCESS_TOKEN + fs.writeFile(file, JSON.stringify(result), () => { + return cb(err, result) + }) + } else { + return cb(err, result) + } + }) + } + + loginViaCLI (cb) { + var promptly = require('promptly'); + + let retry = () => { + promptly.prompt('Username or Email: ', (err, username) => { + if (err) return retry(); + + promptly.password('Password: ', { replace : '*' }, (err, password) => { + if (err) return retry(); + + this._loginUser({ + username: username, + password: password + }, (err, data) => { + if (err) return retry() + cb(data) + }) + }) + }) + } + + retry() + } + + _loginUser (user_info, cb) { + const querystring = require('querystring'); + const AUTH_URI = 'https://id.keymetrics.io' + const URL_AUTH = '/api/oauth/authorize?response_type=token&scope=all&client_id=' + + this.client_id + '&redirect_uri=https://app.keymetrics.io'; + + console.log(chalk.bold('[-] Logging to pm2.io')) + + needle.get(AUTH_URI + URL_AUTH, (err, res) => { + if (err) return cb(err); + + var cookie = res.cookies; + + needle.post(AUTH_URI + '/api/oauth/login', user_info, { + cookies : cookie + }, (err, resp, body) => { + if (err) return cb(err); + if (resp.statusCode != 200) return cb('Wrong credentials'); + + var location = resp.headers['x-redirect']; + var redirect = AUTH_URI + location; + + needle.get(redirect, { + cookies : cookie + }, (err, res) => { + if (err) return cb(err); + var refresh_token = querystring.parse(url.parse(res.headers.location).query).access_token; + needle.post(AUTH_URI + '/api/oauth/token', { + client_id : this.client_id, + grant_type : 'refresh_token', + refresh_token : refresh_token, + scope : 'all' + }, (err, res, body) => { + if (err) return cb(err); + console.log(chalk.bold.green('[+] Logged in!')) + return cb(null, body); + }) + }); + }); + }); + } + + registerViaCLI (cb) { + var promptly = require('promptly'); + console.log(chalk.bold('[-] Registering to pm2.io')); + + var retry = () => { + promptly.prompt('Username: ', { + validator : this._validateUsername, + retry : true + }, (err, username) => { + promptly.prompt('Email: ', { + validator : this._validateEmail, + retry : true + },(err, email) => { + promptly.password('Password: ', { replace : '*' }, (err, password) => { + process.stdout.write('Creating account on pm2.io...'); + + var inter = setInterval(function() { + process.stdout.write('.'); + }, 200); + + this._registerUser({ + email : email, + password : password, + username : username + }, (err, data) => { + clearInterval(inter) + if (err) { + console.error() + console.error(chalk.bold.red(err)); + return retry() + } + console.log(chalk.green.bold('\n[+] Account created!')) + + this._loginUser({ + username: username, + password: password + }, (err, data) => { + this.callback(err, data) + return cb(err, data) + }) + }) + }); + }); + }) + } + retry(); + } + + /** + * Register function + * @param user_info.username + * @param user_info.password + * @param user_info.email + */ + _registerUser (user_info, cb) { + needle.post(this.BASE_URI + '/api/oauth/register', user_info, { + json: true, + headers: { + 'X-Register-Provider': 'pm2-register' + } + }, function (err, res, body) { + if (err) return cb(err); + if (body.email && body.email.message) return cb(body.email.message); + if (body.username && body.username.message) return cb(body.username.message); + if (!body.access_token) return cb(body.msg) + + cb(null, { + token : body.refresh_token.token + }) + }); + } + + _validateEmail (email) { + var re = /^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/; + if (re.test(email) == false) + throw new Error('Not an email'); + return email; + } + + _validateUsername (value) { + if (value.length < 6) { + throw new Error('Min length of 6'); + } + return value; + }; + + deleteTokens (km) { + return new Promise((resolve, reject) => { + // revoke the refreshToken + km.auth.revoke() + .then(res => { + // remove the token from the filesystem + let file = cst.PM2_IO_ACCESS_TOKEN + fs.unlinkSync(file) + return resolve(res) + }).catch(reject) + }) + } +} diff --git a/lib/API/PM2/PM2IO.js b/lib/API/PM2/PM2IO.js new file mode 100644 index 00000000..09048071 --- /dev/null +++ b/lib/API/PM2/PM2IO.js @@ -0,0 +1,245 @@ +'use strict' + +var cst = require('../../../constants.js'); +var Common = require('../../Common.js'); +var KMDaemon = require('@pm2/agent/src/InteractorClient'); + +const chalk = require('chalk'); +const async = require('async'); +const path = require('path'); +const fs = require('fs'); +const Table = require('cli-table-redemption'); +const open = require('../../tools/open.js'); +const pkg = require('../../../package.json') +const IOAPI = require('@pm2/js-api') + + +// const CustomStrategy = require('./custom_auth') +// const strategy = new CustomStrategy({ +// client_id: '7412235273' +// }) + +const CLIAuth = require('./CliAuth') + +const CLIAuthStrategy = new CLIAuth({ + client_id: '938758711' +}) + +const io = new IOAPI().use(CLIAuthStrategy) + +module.exports = function(CLI) { + + CLI.prototype.openDashboard = function() { + KMDaemon.getInteractInfo(this._conf, (err, data) => { + if (err) { + Common.printError(chalk.bold.white('Agent if offline, type `$ pm2 register` to log in')); + return this.exitCli(cst.ERROR_EXIT); + } + Common.printOut(chalk.bold('Opening Dashboard in Browser...')); + open('https://app.pm2.io/#/r/' + data.public_key); + setTimeout(_ => { + this.exitCli(); + }, 200); + }); + }; + + CLI.prototype.loginToKM = function() { + var promptly = require('promptly') + printMotd(); + + return CLIAuthStrategy._retrieveTokens((err, tokens) => { + if (err) { + console.error(`Oups, a error happened : ${err}`) + process.exit(1) + } + + // query both the user and all bucket + Promise.all([ io.user.retrieve(), io.bucket.retrieveAll() ]) + .then(results => { + let user = results[0].data + let buckets = results[1].data + + if (buckets.length > 1) { + var table = new Table({ + style : {'padding-left' : 1, head : ['cyan', 'bold'], compact : true}, + head : ['Bucket name', 'Plan type'] + }); + + buckets.forEach(function(bucket) { + table.push([bucket.name, bucket.credits.offer_type]); + }); + + console.log(table.toString()); + + (function retryInsertion() { + promptly.prompt('Type the bucket you want to link to: ', function(err, bucket_name) { + var target_bucket = null; + + buckets.some(function(bucket) { + if (bucket.name == bucket_name) { + target_bucket = bucket; + return true; + } + }); + + if (target_bucket == null) + return retryInsertion(); + linkOpenExit(target_bucket); + }); + })(); + } + else { + var target_bucket = buckets[0]; + linkOpenExit(target_bucket) + } + }).catch(err => { + console.error(chalk.bold.red(`Oups, a error happened : ${err}`)) + return process.exit(1) + }) + }) + }; + + CLI.prototype.registerToKM = function() { + var promptly = require('promptly'); + + promptly.confirm(chalk.bold('Do you have a pm2.io account? (y/n)'), (err, answer) => { + if (answer == true) { + return this.loginToKM(); + } + CLIAuthStrategy.registerViaCLI((err, data) => { + console.log('[-] Creating Bucket...') + + io.bucket.create({ + name: 'Node.JS Monitoring' + }).then(res => { + const bucket = res.data.bucket + console.log(chalk.bold.green('[+] Bucket created!')) + linkOpenExit(bucket) + }) + }) + }); + } + + CLI.prototype.logoutToKM = function () { + CLIAuthStrategy._retrieveTokens(_ => { + io.auth.logout() + .then(res => { + console.log(`- Logout successful`) + return process.exit(0) + }).catch(err => { + console.error(`Oups, a error happened : ${err.message}`) + return process.exit(1) + }) + }) + } + + CLI.prototype.connectToPM2IO = function() { + io.bucket.create({ + name: 'Node.JS Monitoring' + }).then(res => { + const bucket = res.data.bucket + console.log(`Succesfully created a bucket !`) + console.log(`To start using it, you should push data with : + pm2 link ${bucket.secret_id} ${bucket.public_id} + `) + console.log(`You can also access our dedicated UI by going here : + https://app.pm2.io/#/r/${bucket.public_id} + `) + + KMDaemon.launchAndInteract(cst, { + public_key : bucket.public_id, + secret_key : bucket.secret_id + }, function(err, dt) { + open(`https://app.pm2.io/#/r/${bucket.public_id}`); + setTimeout(_ => { + return process.exit(0) + }, 200) + }); + + }) + } + + /** + * Monitor Selectively Processes (auto filter in interaction) + * @param String state 'monitor' or 'unmonitor' + * @param String target + * @param Function cb callback + */ + CLI.prototype.monitorState = function(state, target, cb) { + var that = this; + + if (process.env.NODE_ENV !== 'test') { + try { + fs.statSync(this._conf.INTERACTION_CONF); + } catch(e) { + printMotd(); + return this.registerToKM(); + } + } + + if (!target) { + Common.printError(cst.PREFIX_MSG_ERR + 'Please specify an '); + return cb ? cb(new Error('argument missing')) : that.exitCli(cst.ERROR_EXIT); + } + + function monitor (pm_id, cb) { + // State can be monitor or unmonitor + that.Client.executeRemote(state, pm_id, cb); + } + if (target === 'all') { + that.Client.getAllProcessId(function (err, procs) { + if (err) { + Common.printError(err); + return cb ? cb(Common.retErr(err)) : that.exitCli(cst.ERROR_EXIT); + } + async.forEachLimit(procs, 1, monitor, function (err, res) { + return typeof cb === 'function' ? cb(err, res) : that.speedList(); + }); + }); + } else if (!Number.isInteger(parseInt(target))) { + this.Client.getProcessIdByName(target, true, function (err, procs) { + if (err) { + Common.printError(err); + return cb ? cb(Common.retErr(err)) : that.exitCli(cst.ERROR_EXIT); + } + async.forEachLimit(procs, 1, monitor, function (err, res) { + return typeof cb === 'function' ? cb(err, res) : that.speedList(); + }); + }); + } else { + monitor(parseInt(target), function (err, res) { + return typeof cb === 'function' ? cb(err, res) : that.speedList(); + }); + } + }; + + + function linkOpenExit(target_bucket) { + console.log('[-] Linking local PM2 to newly created bucket...') + KMDaemon.launchAndInteract(cst, { + public_key : target_bucket.public_id, + secret_key : target_bucket.secret_id, + pm2_version: pkg.version + }, function(err, dt) { + console.log(chalk.bold.green('[+] Local PM2 Connected!')) + + console.log('[-] Opening Monitoring Interface in Browser...') + + setTimeout(function() { + open('https://app.pm2.io/#/r/' + target_bucket.public_id); + console.log(chalk.bold.green('[+] Opened! Exiting now.')) + setTimeout(function() { + process.exit(cst.SUCCESS_EXIT); + }, 100); + }, 1000) + }); + } + + /** + * Private Functions + */ + function printMotd() { + var dt = fs.readFileSync(path.join(__dirname, 'motd')); + console.log(dt.toString()); + } +}; diff --git a/lib/API/PM2/WebAuth.js b/lib/API/PM2/WebAuth.js new file mode 100644 index 00000000..49a52631 --- /dev/null +++ b/lib/API/PM2/WebAuth.js @@ -0,0 +1,192 @@ + +'use strict' + +const cst = require('../../../constants.js'); + +const AuthStrategy = require('@pm2/js-api/src/auth_strategies/strategy') +const http = require('http') +const fs = require('fs') +const url = require('url') +const exec = require('child_process').exec +const async = require('async') +const path = require('path') +const os = require('os') +const needle = require('needle'); + +module.exports = class CustomStrategy extends AuthStrategy { + // the client will try to call this but we handle this part ourselves + retrieveTokens (km, cb) { + this.authenticated = false + this.callback = cb + this.km = km + } + + // so the cli know if we need to tell user to login/register + isAuthenticated () { + return new Promise((resolve, reject) => { + if (this.authenticated) return resolve(true) + + let tokensPath = cst.PM2_IO_ACCESS_TOKEN + fs.readFile(tokensPath, (err, tokens) => { + if (err && err.code === 'ENOENT') return resolve(false) + if (err) return reject(err) + + // verify that the token is valid + try { + tokens = JSON.parse(tokens || '{}') + } catch (err) { + fs.unlinkSync(tokensPath) + return resolve(false) + } + + // if the refresh tokens is here, the user could be automatically authenticated + return resolve(typeof tokens.refresh_token === 'string') + }) + }) + } + + // called when we are sure the user asked to be logged in + _retrieveTokens (optionalCallback) { + const km = this.km + const cb = this.callback + + let verifyToken = (refresh) => { + return km.auth.retrieveToken({ + client_id: this.client_id, + refresh_token: refresh + }) + } + async.tryEach([ + // try to find the token via the environement + (next) => { + if (!process.env.KM_TOKEN) { + return next(new Error('No token in env')) + } + verifyToken(process.env.KM_TOKEN) + .then((res) => { + return next(null, res.data) + }).catch(next) + }, + // try to find it in the file system + (next) => { + return next(new Error('nope')) + + fs.readFile(cst.PM2_IO_ACCESS_TOKEN, (err, tokens) => { + if (err) return next(err) + + // verify that the token is valid + tokens = JSON.parse(tokens || '{}') + if (new Date(tokens.expire_at) > new Date(new Date().toISOString())) { + return next(null, tokens) + } + + verifyToken(tokens.refresh_token) + .then((res) => { + return next(null, res.data) + }).catch(next) + }) + }, + // otherwise make the whole flow + (next) => { + return this.loginViaWeb((data) => { + // verify that the token is valid + verifyToken(data.access_token) + .then((res) => { + return next(null, res.data) + }).catch(next) + }) + } + ], (err, result) => { + // if present run the optional callback + if (typeof optionalCallback === 'function') { + optionalCallback(err, result) + } + + if (result.refresh_token) { + this.authenticated = true + let file = cst.PM2_IO_ACCESS_TOKEN + fs.writeFile(file, JSON.stringify(result), () => { + return cb(err, result) + }) + } else { + return cb(err, result) + } + }) + } + + loginViaWeb (cb) { + let shutdown = false + let server = http.createServer((req, res) => { + // only handle one request + if (shutdown === true) return res.end() + shutdown = true + + let query = url.parse(req.url, true).query + + res.write(` + + + + +

+ You can go back to your terminal now :) +

+ `) + res.end() + server.close() + return cb(query) + }) + server.listen(43532, () => { + this.open(`${this.oauth_endpoint}${this.oauth_query}`) + }) + } + + deleteTokens (km) { + return new Promise((resolve, reject) => { + // revoke the refreshToken + km.auth.revoke() + .then(res => { + // remove the token from the filesystem + let file = cst.PM2_IO_ACCESS_TOKEN + fs.unlinkSync(file) + return resolve(res) + }).catch(reject) + }) + } + + open (target, appName, callback) { + let opener + const escape = function (s) { + return s.replace(/"/g, '\\"') + } + + if (typeof (appName) === 'function') { + callback = appName + appName = null + } + + switch (process.platform) { + case 'darwin': { + opener = appName ? `open -a "${escape(appName)}"` : `open` + break + } + case 'win32': { + opener = appName ? `start "" ${escape(appName)}"` : `start ""` + break + } + default: { + opener = appName ? escape(appName) : `xdg-open` + break + } + } + + if (process.env.SUDO_USER) { + opener = 'sudo -u ' + process.env.SUDO_USER + ' ' + opener + } + return exec(`${opener} "${escape(target)}"`, callback) + } +} diff --git a/lib/API/Keymetrics/motd b/lib/API/PM2/motd similarity index 100% rename from lib/API/Keymetrics/motd rename to lib/API/PM2/motd diff --git a/package.json b/package.json index f504ef95..243a8988 100644 --- a/package.json +++ b/package.json @@ -160,6 +160,7 @@ "dependencies": { "@pm2/agent": "latest", "@pm2/io": "latest", + "@pm2/js-api": "latest", "async": "^2.6", "blessed": "^0.1.81", "chalk": "^2.4.1", diff --git a/paths.js b/paths.js index c8bccb3e..8830a7e0 100644 --- a/paths.js +++ b/paths.js @@ -45,7 +45,7 @@ module.exports = function(PM2_HOME) { DEFAULT_PID_PATH : p.resolve(PM2_HOME, 'pids'), DEFAULT_LOG_PATH : p.resolve(PM2_HOME, 'logs'), DEFAULT_MODULE_PATH : p.resolve(PM2_HOME, 'modules'), - KM_ACCESS_TOKEN : p.resolve(PM2_HOME, 'km-access-token'), + PM2_IO_ACCESS_TOKEN : p.resolve(PM2_HOME, 'pm2-io-token'), DUMP_FILE_PATH : p.resolve(PM2_HOME, 'dump.pm2'), DUMP_BACKUP_FILE_PATH : p.resolve(PM2_HOME, 'dump.pm2.bak'), From ef965de1f4a932eec428c3b6f82ae3ddf717261e Mon Sep 17 00:00:00 2001 From: Alexandre Strzelewicz Date: Sun, 3 Jun 2018 20:53:09 +0200 Subject: [PATCH 119/140] #3651 fix username undefined --- lib/API/schema.json | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/lib/API/schema.json b/lib/API/schema.json index ce823c2b..063ffcdd 100644 --- a/lib/API/schema.json +++ b/lib/API/schema.json @@ -272,21 +272,25 @@ "type": "boolean", "default": true, "docDefault": "True", - "docDescription": "Only kill the main process, not detached children" + "docDescription": "Only kill the main process, not detached children" }, "port": { "type": "number", "docDescription": "Shortcut to inject a PORT environment variable" }, + "username" : { + "type": "string", + "docDescription": "Current user that started the process" + }, "uid": { "type" : "string", "docDefault": "Current user uid", - "docDescription": "Set user id" + "docDescription": "Set user id" }, "gid": { "type" : "string", "docDefault": "Current user gid", - "docDescription": "Set group id" + "docDescription": "Set group id" }, "windowsHide": { "type": "boolean", From 052d6c55df0e941e1dd11430bbcbcaa34061a06e Mon Sep 17 00:00:00 2001 From: vince Date: Thu, 7 Jun 2018 15:59:46 +0200 Subject: [PATCH 120/140] fix: #3695 change version check method in order to make it work with alpha/beta versions --- lib/API/Extra.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/API/Extra.js b/lib/API/Extra.js index cf7a23fc..bca1da25 100644 --- a/lib/API/Extra.js +++ b/lib/API/Extra.js @@ -108,7 +108,7 @@ module.exports = function(CLI) { } that.Client.executeRemote('getVersion', {}, function(err, data) { - if (semver.satisfies(data, '>= 2.6.0')) + if (semver.satisfies(semver.coerce(data), '>=2.6.0')) reporting(); else { Common.printError(cst.PREFIX_MSG_ERR + 'You need to update your Daemon, please type `$ pm2 update`'); From 992a045227aed559e708ac4e6bb3f54beabe48e0 Mon Sep 17 00:00:00 2001 From: Unitech Date: Wed, 13 Jun 2018 00:14:19 +0200 Subject: [PATCH 121/140] chore: shorten ecosystem file --- lib/templates/ecosystem.tpl | 45 +++++++------------------------------ 1 file changed, 8 insertions(+), 37 deletions(-) diff --git a/lib/templates/ecosystem.tpl b/lib/templates/ecosystem.tpl index a5455ea4..9ad0995a 100644 --- a/lib/templates/ecosystem.tpl +++ b/lib/templates/ecosystem.tpl @@ -1,33 +1,15 @@ module.exports = { - /** - * Application configuration section - * http://pm2.keymetrics.io/docs/usage/application-declaration/ - */ - apps : [ - - // First application - { - name : 'API', - script : 'app.js', - env: { - COMMON_VARIABLE: 'true' - }, - env_production : { - NODE_ENV: 'production' - } + apps : [{ + name : 'API', + script : 'app.js', + env: { + NODE_ENV: 'development' }, - - // Second application - { - name : 'WEB', - script : 'web.js' + env_production : { + NODE_ENV: 'production' } - ], + }], - /** - * Deployment section - * http://pm2.keymetrics.io/docs/usage/deployment/ - */ deploy : { production : { user : 'node', @@ -36,17 +18,6 @@ module.exports = { repo : 'git@github.com:repo.git', path : '/var/www/production', 'post-deploy' : 'npm install && pm2 reload ecosystem.config.js --env production' - }, - dev : { - user : 'node', - host : '212.83.163.1', - ref : 'origin/master', - repo : 'git@github.com:repo.git', - path : '/var/www/development', - 'post-deploy' : 'npm install && pm2 reload ecosystem.config.js --env dev', - env : { - NODE_ENV: 'dev' - } } } }; From c8616276e4e08b4d90a742e219372e775bb81098 Mon Sep 17 00:00:00 2001 From: vince Date: Fri, 15 Jun 2018 10:50:59 +0200 Subject: [PATCH 122/140] fix: #3605 fix parameters definition, don't use camelcase for properties --- types/index.d.ts | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/types/index.d.ts b/types/index.d.ts index 42ff4293..49c058d2 100644 --- a/types/index.d.ts +++ b/types/index.d.ts @@ -311,7 +311,7 @@ export interface StartOptions { * Eg “–harmony” or [”–harmony”,”–debug”]. Only applies if interpreter is something other * than “none” (its “node” by default). */ - interpreterArgs?: string | string[]; + interpreter_args?: string | string[]; /** * The working directory to start the process with. */ @@ -328,7 +328,7 @@ export interface StartOptions { /** * The display format for log timestamps (eg “YYYY-MM-DD HH:mm Z”). The format is a moment display format. */ - logDateFormat?: string; + log_date_format?: string; /** * Default: “~/.pm2/logs/~/.pm2/pids/app_name-id.pid”) * The path to a file to write the pid of the started process. The file will be overwritten. @@ -339,26 +339,26 @@ export interface StartOptions { /** * The minimum uptime of the script before it’s considered successfully started. */ - minUptime?: number; + min_uptime?: number; /** * The maximum number of times in a row a script will be restarted if it exits in less than min_uptime. */ - maxRestarts?: number; + max_restarts?: number; /** * If sets and script’s memory usage goes about the configured number, pm2 restarts the script. * Uses human-friendly suffixes: ‘K’ for kilobytes, ‘M’ for megabytes, ‘G’ for gigabytes’, etc. Eg “150M”. */ - maxMemoryRestart?: number; + max_memory_restart?: number; /** * (Default: 1600) * The number of milliseconds to wait after a stop or restart command issues a SIGINT signal to kill the * script forceably with a SIGKILL signal. */ - killTimeout?: number; + kill_timeout?: number; /** * (Default: 0) Number of millseconds to wait before restarting a script that has exited. */ - restartDelay?: number; + restart_delay?: number; /** * (Default: “node”) The interpreter for your script (eg “python”, “ruby”, “bash”, etc). * The value “none” will execute the ‘script’ as a binary executable. @@ -368,7 +368,7 @@ export interface StartOptions { * (Default: ‘fork’) If sets to ‘cluster’, will enable clustering * (running multiple instances of the script). */ - execMode?: string; + exec_mode?: string; /** * (Default: 1) How many instances of script to create. Only relevant in exec_mode ‘cluster’. */ @@ -379,7 +379,7 @@ export interface StartOptions { * ‘test.js’ started via pm2, normally you would have 4 stdout log files and 4 stderr log files, * but with this option set to true you would only have one stdout file and one stderr file. */ - mergeLogs?: boolean; + merge_logs?: boolean; /** * If set to true, the application will be restarted on change of the script file. */ @@ -391,10 +391,10 @@ export interface StartOptions { */ force?: boolean; cron?: any; - executeCommand?: any; + execute_command?: any; write?: any; - sourceMapSupport?: any; - disableSourceMapSupport?: any; + source_map_support?: any; + disable_source_map_support?: any; /** * The environment variables to pass on to the process. */ From e3a6aea748b9dc8de33fc3416734c700980b8af7 Mon Sep 17 00:00:00 2001 From: vince Date: Fri, 15 Jun 2018 16:59:27 +0200 Subject: [PATCH 123/140] feature: #3692 allow pm2 to send to pm2-io-apm configuration --- lib/API.js | 3 +++ lib/API/schema.json | 4 ++++ lib/ProcessUtils.js | 16 ++++++++++++++-- 3 files changed, 21 insertions(+), 2 deletions(-) diff --git a/lib/API.js b/lib/API.js index 8424ef79..f53c3412 100644 --- a/lib/API.js +++ b/lib/API.js @@ -868,6 +868,8 @@ class API { // Here we pick only the field we want from the CLI when starting a JSON appConf.forEach(function(app) { + if (!app.env) { app.env = {}; } + app.env.io = app.io; // --only if (opts.only && opts.only != app.name) return false; @@ -911,6 +913,7 @@ class API { * and act on them depending on action */ async.eachLimit(Object.keys(proc_list), conf.CONCURRENT_ACTIONS, function(proc_name, next) { + // Skip app name (--only option) if (apps_name.indexOf(proc_name) == -1) return next(); diff --git a/lib/API/schema.json b/lib/API/schema.json index 063ffcdd..94ef70e0 100644 --- a/lib/API/schema.json +++ b/lib/API/schema.json @@ -304,5 +304,9 @@ }, "write": { "type": "boolean" + }, + "io": { + "type": "object", + "docDescription": "Specify apm values and configuration" } } diff --git a/lib/ProcessUtils.js b/lib/ProcessUtils.js index 0cc84f3b..95edd4b0 100644 --- a/lib/ProcessUtils.js +++ b/lib/ProcessUtils.js @@ -2,13 +2,25 @@ module.exports = { injectModules: function() { if (process.env.pmx !== 'false') { const pmx = require('@pm2/io'); - pmx.init({ + + let conf = {}; + + if (process.env.io) { + const io = JSON.parse(process.env.io); + conf = io.conf ? io.conf : conf; + } + + let defaultConf = { transactions: (process.env.trace === 'true' || process.env.deep_monitoring === 'true') || false, http: process.env.km_link === 'true' || false, v8: process.env.v8 === 'true' || process.env.deep_monitoring === 'true' || false, event_loop_dump: process.env.event_loop_inspector === 'true' || process.env.deep_monitoring === 'true' || false, deep_metrics: process.env.deep_monitoring === 'true' || false - }); + }; + + Object.assign(conf, defaultConf); + + pmx.init(conf); if(require('semver').satisfies(process.versions.node, '>= 8.0.0')) { var url = ''; From ba2ee3b1ea9aa5fa665e706b3d49a205eac44d53 Mon Sep 17 00:00:00 2001 From: vince Date: Fri, 15 Jun 2018 17:44:47 +0200 Subject: [PATCH 124/140] fix: add use strict for node 4 compatibility --- lib/ProcessUtils.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/ProcessUtils.js b/lib/ProcessUtils.js index 95edd4b0..1f0b7703 100644 --- a/lib/ProcessUtils.js +++ b/lib/ProcessUtils.js @@ -1,3 +1,5 @@ +'use strict' + module.exports = { injectModules: function() { if (process.env.pmx !== 'false') { From fdeb0c327afd91b113b214c4c4de187848f9f1cb Mon Sep 17 00:00:00 2001 From: Aaron Miller Date: Sat, 16 Jun 2018 16:43:04 -0700 Subject: [PATCH 125/140] feat: add support for openbsd rc.d init scripts --- README.md | 4 +-- lib/API/Startup.js | 24 ++++++++++++- lib/templates/init-scripts/rcd-openbsd.tpl | 41 ++++++++++++++++++++++ 3 files changed, 66 insertions(+), 3 deletions(-) create mode 100644 lib/templates/init-scripts/rcd-openbsd.tpl diff --git a/README.md b/README.md index 445b4e9c..b1374b7f 100644 --- a/README.md +++ b/README.md @@ -228,14 +228,14 @@ $ pm2 reloadLogs # Reload all logs PM2 can generates and configure a startup script to keep PM2 and your processes alive at every server restart. -Supports init systems like: **systemd** (Ubuntu 16, CentOS, Arch), **upstart** (Ubuntu 14/12), **launchd** (MacOSx, Darwin), **rc.d** (FreeBSD). +Supports init systems like: **systemd** (Ubuntu 16, CentOS, Arch), **upstart** (Ubuntu 14/12), **launchd** (MacOSx, Darwin), **rc.d** (FreeBSD, OpenBSD). ```bash # Auto detect init system + generate and setup PM2 boot at server startup $ pm2 startup # Manually specify the startup system -# Can be: systemd, upstart, launchd, rcd +# Can be: systemd, upstart, launchd, rcd, rcd-openbsd $ pm2 startup [platform] # Disable and remove PM2 boot at server startup diff --git a/lib/API/Startup.js b/lib/API/Startup.js index d35cd05c..8916e037 100644 --- a/lib/API/Startup.js +++ b/lib/API/Startup.js @@ -41,7 +41,8 @@ module.exports = function(CLI) { 'chkconfig' : 'systemv', 'rc-update' : 'openrc', 'launchctl' : 'launchd', - 'sysrc' : 'rcd' + 'sysrc' : 'rcd', + 'rcctl' : 'rcd-openbsd', }; var init_systems = Object.keys(hash_map); @@ -147,6 +148,16 @@ module.exports = function(CLI) { 'sysrc -x ' + service_name + '_enable', 'rm /usr/local/etc/rc.d/' + service_name ]; + break; + case 'rcd-openbsd': + service_name = (opts.serviceName || 'pm2_' + user); + var destination = path.join('/etc/rc.d', service_name); + commands = [ + 'rcctl stop ' + service_name, + 'rcctl disable ' + service_name, + 'rm ' + destination + ]; + break; }; require('shelljs').exec(commands.join('&& '), function(code, stdout, stderr) { @@ -270,6 +281,17 @@ module.exports = function(CLI) { 'sysrc ' + service_name + '_enable=YES' ]; break; + case 'openbsd': + case 'rcd-openbsd': + template = getTemplate('rcd-openbsd'); + service_name = (opts.serviceName || 'pm2_' + user); + destination = path.join('/etc/rc.d/', service_name); + commands = [ + 'chmod 755 ' + destination, + 'rcctl enable ' + service_name, + 'rcctl start ' + service_name + ]; + break; case 'openrc': template = getTemplate('openrc'); service_name = openrc_service_name; diff --git a/lib/templates/init-scripts/rcd-openbsd.tpl b/lib/templates/init-scripts/rcd-openbsd.tpl new file mode 100644 index 00000000..590a995e --- /dev/null +++ b/lib/templates/init-scripts/rcd-openbsd.tpl @@ -0,0 +1,41 @@ +#!/bin/sh +# +# from /usr/ports/infrastructure/templates/rc.template + +daemon="/usr/local/bin/pm2" +#daemon_flags= +#daemon_rtable=0 +#daemon_timeout="30" +daemon_user="%USER%" + +. /etc/rc.d/rc.subr + +pexp="node: PM2.*God Daemon.*" +#rc_bg= # (undefined) +#rc_reload= # (undefined) +#rc_usercheck=YES + +#rc_pre() { +#} + +rc_start() { + ${rcexec} "${daemon} ${daemon_flags} resurrect" +} + +#rc_check() { +# pgrep -T "${daemon_rtable}" -q -xf "${pexp}" +#} + +rc_reload() { + ${rcexec} "${daemon} reload all" + #pkill -HUP -T "${daemon_rtable}" -xf "${pexp}" +} + +#rc_stop() { +# pkill -T "${daemon_rtable}" -xf "${pexp}" +#} + +#rc_post() { +#} + +rc_cmd $1 From 37dc7de11e930aa4fce6a485e892f11ee714acd6 Mon Sep 17 00:00:00 2001 From: vince Date: Mon, 18 Jun 2018 10:58:33 +0200 Subject: [PATCH 126/140] fix: return the configuration and allow custom conf to override default values --- lib/ProcessUtils.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/ProcessUtils.js b/lib/ProcessUtils.js index 1f0b7703..4dad2196 100644 --- a/lib/ProcessUtils.js +++ b/lib/ProcessUtils.js @@ -20,9 +20,9 @@ module.exports = { deep_metrics: process.env.deep_monitoring === 'true' || false }; - Object.assign(conf, defaultConf); + const mergedConf = Object.assign(defaultConf, conf); - pmx.init(conf); + pmx.init(mergedConf); if(require('semver').satisfies(process.versions.node, '>= 8.0.0')) { var url = ''; From 623eb78e662515c27d8bab72595ad1f79d34591d Mon Sep 17 00:00:00 2001 From: abluchet Date: Tue, 19 Jun 2018 11:57:43 +0200 Subject: [PATCH 127/140] Fix pm2 list cpu display --- lib/API.js | 14 ++++++++++---- lib/API/CliUx.js | 2 +- 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/lib/API.js b/lib/API.js index f53c3412..0eebf103 100644 --- a/lib/API.js +++ b/lib/API.js @@ -566,7 +566,7 @@ class API { return false; } - return cb ? cb(null, list) : that.speedList(); + return cb ? cb(null, list) : that.speedList(null, list); }); } @@ -1467,13 +1467,19 @@ class API { * @method speedList * @return */ - speedList (code) { + speedList (code, list) { var that = this; // Do nothing if PM2 called programmatically and not called from CLI (also in exitCli) if (conf.PM2_PROGRAMMATIC && process.env.PM2_USAGE != 'CLI') return false; - that.Client.executeRemote('getMonitorData', {}, function(err, list) { + if (list) { + return doList(null, list) + } + + that.Client.executeRemote('getMonitorData', {}, doList); + + function doList(err, list) { if (err) { if (gl_retry == 0) { gl_retry += 1; @@ -1510,7 +1516,7 @@ class API { else { return that.exitCli(code ? code : conf.SUCCESS_EXIT); } - }); + } } /** diff --git a/lib/API/CliUx.js b/lib/API/CliUx.js index a25f72e0..3e99ee55 100644 --- a/lib/API/CliUx.js +++ b/lib/API/CliUx.js @@ -327,7 +327,7 @@ UX.dispAsTable = function(list, commander) { obj[key].push((l.pm2_env.pm_uptime && status == 'online') ? timeSince(l.pm2_env.pm_uptime) : 0); // CPU - obj[key].push(l.monit ? l.monit.cpu + '%' : 'N/A'); + obj[key].push(l.monit ? l.monit.cpu.toFixed(2) + '%' : 'N/A'); // Memory obj[key].push(l.monit ? UX.bytesToSize(l.monit.memory, 1) : 'N/A'); From d39a4247fda2ecc7b92aa6cd5f26a09f4cc36afd Mon Sep 17 00:00:00 2001 From: abluchet Date: Tue, 19 Jun 2018 17:08:47 +0200 Subject: [PATCH 128/140] Fix cpu value for modules --- lib/API/CliUx.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/API/CliUx.js b/lib/API/CliUx.js index 3e99ee55..a5f809d3 100644 --- a/lib/API/CliUx.js +++ b/lib/API/CliUx.js @@ -293,7 +293,7 @@ UX.dispAsTable = function(list, commander) { obj[key].push(l.pm2_env.restart_time ? l.pm2_env.restart_time : 0); // CPU + Memory - obj[key].push(l.monit ? (l.monit.cpu + '%') : 'N/A', l.monit ? UX.bytesToSize(l.monit.memory, 3) : 'N/A' ); + obj[key].push(l.monit ? (l.monit.cpu.toFixed(2) + '%') : 'N/A', l.monit ? UX.bytesToSize(l.monit.memory, 3) : 'N/A' ); // User if (!stacked) From 09aacdc13e642fd7fb712c3c4338c1eb39f49990 Mon Sep 17 00:00:00 2001 From: vince Date: Wed, 20 Jun 2018 11:04:26 +0200 Subject: [PATCH 129/140] chore: upgrade module and version --- package.json | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/package.json b/package.json index 243a8988..3d21d7ef 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "pm2", "preferGlobal": true, - "version": "3.0.0-alpha1", + "version": "3.0.0", "engines": { "node": ">=4.0.0" }, @@ -158,9 +158,9 @@ "pm2-runtime": "./bin/pm2-runtime" }, "dependencies": { - "@pm2/agent": "latest", - "@pm2/io": "latest", - "@pm2/js-api": "latest", + "@pm2/agent": "^0.5.1", + "@pm2/io": "^2.0.0", + "@pm2/js-api": "^0.5.15", "async": "^2.6", "blessed": "^0.1.81", "chalk": "^2.4.1", From 829fcb335ff973669bdc27d91d4dcebca3176f14 Mon Sep 17 00:00:00 2001 From: vince Date: Wed, 20 Jun 2018 11:09:01 +0200 Subject: [PATCH 130/140] chore: update version to 3.0.0 --- .changelogrc | 6 +- CHANGELOG.md | 307 +++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 310 insertions(+), 3 deletions(-) diff --git a/.changelogrc b/.changelogrc index 14a1a689..83c18d09 100644 --- a/.changelogrc +++ b/.changelogrc @@ -2,10 +2,10 @@ "app_name": "", "logo": "", "intro": "", - "branch" : "master", + "branch" : "development", "repo_url": "https://github.com/Unitech/pm2", - "version_name" : "2.10.4", - "tag": "2.10.3", + "version_name" : "3.0.0", + "tag": "2.10.4", "file": "currentTagChangelog.md", "template": "changelogTemplate.md", "sections": [ diff --git a/CHANGELOG.md b/CHANGELOG.md index fbd96fd2..1a3a79db 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,310 @@ +## 3.0.0 ( Wed Jun 20 2018 11:06:21 GMT+0200 (CEST) ) + + +## Breaking changes + - merge_logs is now activated by default if not in cluster mode. Logs will not be suffixed by the pm_id if only one app is started + ([ae02adf6](https://github.com/Unitech/pm2/commit/ae02adf63f70ceb3bf101be968996ca68d9ce277)) + + + + +## Bug Fixes + - return the configuration and allow custom conf to override default values + ([37dc7de1](https://github.com/Unitech/pm2/commit/37dc7de11e930aa4fce6a485e892f11ee714acd6)) + - add use strict for node 4 compatibility + ([ba2ee3b1](https://github.com/Unitech/pm2/commit/ba2ee3b1ea9aa5fa665e706b3d49a205eac44d53)) + - #3605 fix parameters definition, don't use camelcase for properties + ([c8616276](https://github.com/Unitech/pm2/commit/c8616276e4e08b4d90a742e219372e775bb81098)) + - #3695 change version check method in order to make it work with alpha/beta versions + ([052d6c55](https://github.com/Unitech/pm2/commit/052d6c55df0e941e1dd11430bbcbcaa34061a06e)) + - deprecated warning on isbinaryfile + ([db09275f](https://github.com/Unitech/pm2/commit/db09275f8e353e257c89e12fed754236b15cee74)) + - #3688 test adaptation + pm2 serve --port option + ([f0249684](https://github.com/Unitech/pm2/commit/f0249684bcbfdb75749a516f447c8e8d32020709)) + - startup script issue 18.04 #3645 + ([ff1a7f31](https://github.com/Unitech/pm2/commit/ff1a7f315bfee38eb9fd9cdd63efcc0d971585f8)) + - that this - uncache node_modules + ([294038d7](https://github.com/Unitech/pm2/commit/294038d76272a915e3addc67d3694717a9f7d704)) + - verify default conf variable via package.json on public module + ([157b106d](https://github.com/Unitech/pm2/commit/157b106df78af1d28d37bbea069b926de4dceca5)) + - bug because of const + ([56f05a90](https://github.com/Unitech/pm2/commit/56f05a900b03fb0c8dd635aede666c7d2f213271)) + - do not run two pm2 para cmds + ([3274132b](https://github.com/Unitech/pm2/commit/3274132b866ba5c93d5786e755acbada922f5f1e)) + - version + ([3ec178e5](https://github.com/Unitech/pm2/commit/3ec178e577e79730aae02c913301cd905ea8ce52)) + - re-enable agent tests + ([e6febcd7](https://github.com/Unitech/pm2/commit/e6febcd70dd0f1e68b74df8563d3046ee3b32b89)) + - test/display summary + ([b075e6d0](https://github.com/Unitech/pm2/commit/b075e6d09b09ff371adf045dc5079bb8ef82f1cf)) + - skip interactor tests + ([36c4d6bc](https://github.com/Unitech/pm2/commit/36c4d6bca7445b46afc1236dc8ab4b8bf921148b)) + - remove unused tests + ([234c6314](https://github.com/Unitech/pm2/commit/234c63143e723a508796bc1d323c7241979bf4c2)) + - add missing libraries in travis + ([88fbb845](https://github.com/Unitech/pm2/commit/88fbb84597cee7029ce33f5b7e20e45f5a815b4b)) + - remove unused variable when trying to use tracing + ([3aeeba02](https://github.com/Unitech/pm2/commit/3aeeba02f628bf4f19e8d5b93657fd94a6ef0ec7)) + - remove useless tests from .sh + ([e0be81c8](https://github.com/Unitech/pm2/commit/e0be81c86c7defb5e7a271edd5cc37f960c6aa69)) + - conflict + ([e13f39c9](https://github.com/Unitech/pm2/commit/e13f39c90b6a5e803c59c5424332520564703f5c)) + - fix bug with interpreter args + ([b26efa0d](https://github.com/Unitech/pm2/commit/b26efa0d4cd72cf04762df7b7d2eaddc4f4117d2)) + - improve error message if action has failed + ([d9f44f17](https://github.com/Unitech/pm2/commit/d9f44f170f115c2d6dfb6a7fe71dc31bd7fb66fb)) + - use polyfill module for copySync with node 4.x + ([bc07f43b](https://github.com/Unitech/pm2/commit/bc07f43b115066f6077606df8f59379777f2a917)) + - improve error message if action has failed + ([dacc6542](https://github.com/Unitech/pm2/commit/dacc654207cbe494af0d12a3f9f27c3b16541802)) + - solve empty list when no process and try to update pm2 + ([89511846](https://github.com/Unitech/pm2/commit/8951184688c720ded5b4b46bd5b393c3793f9b03)) + - #3485 fix issue when there is empty dump file + ([f2523f6a](https://github.com/Unitech/pm2/commit/f2523f6a6b9d8b61ba6ace7b89a0353bee76360b)) + - #3456 use homedir() instead of process.env.HOME, make module installation work on windows + ([1e001732](https://github.com/Unitech/pm2/commit/1e0017325fc8cf658263fb4e02c7bf8912f422b3)) + + + + +## Features + - add support for openbsd rc.d init scripts + ([fdeb0c32](https://github.com/Unitech/pm2/commit/fdeb0c327afd91b113b214c4c4de187848f9f1cb)) + - add kill_retry_time argument + ([b2cc0031](https://github.com/Unitech/pm2/commit/b2cc003114b44f1a9a31876ee4a2f4cb91e210b3)) + + - **bin/pm2** + - improve usage + ([2c310084](https://github.com/Unitech/pm2/commit/2c310084453dd7b1546957e59b1fc7ef964d425b)) + + + + +## Refactor + - use @pm2/js-api for login/register on pm2.io via CLI + ([cb6521ac](https://github.com/Unitech/pm2/commit/cb6521ac32f4737c42fc97fef972960bfe16c829)) + - keymetrics examples + ([109b331d](https://github.com/Unitech/pm2/commit/109b331ddf37e061d1890ef952f4cd167ce53f64)) + - faster cli with less require + ([ee5e6a06](https://github.com/Unitech/pm2/commit/ee5e6a06cbf93f2d1fa7fa022d6bdcad55a39695)) + - replace fs-extra with node calls + ([4576b4c9](https://github.com/Unitech/pm2/commit/4576b4c97bc685c9d774018d6b29c918abd7cb8d)) + - centralize SECRET/PUBLIC/MACHINE_NAME + change some wordings + ([d0a2a30e](https://github.com/Unitech/pm2/commit/d0a2a30e4110496b178199fb33e026d6402dd00d)) + - remove test deported to keymetrics-agent + ([299a52a2](https://github.com/Unitech/pm2/commit/299a52a253d70edcde23cbd7e0c201d492984df4)) + - parallel test v1 + ([08612de5](https://github.com/Unitech/pm2/commit/08612de5b7893a004ae33ed77fcb2ee3ff7b2251)) + - e2e test rewrite + ([2b9ffd4e](https://github.com/Unitech/pm2/commit/2b9ffd4eb493f1ff32c979e3811f4f1fedfae97d)) + - drop gracefullreload + ([bb57c76d](https://github.com/Unitech/pm2/commit/bb57c76d4191343925013d4353299092d80732c9)) + - add node 4.x support + ([d322dd00](https://github.com/Unitech/pm2/commit/d322dd00de0f527224c027b4fec5e86f12fd69ed)) + - create alias method instead of modify prototype + ([6d8f0dfa](https://github.com/Unitech/pm2/commit/6d8f0dfae8106deb2fee0a7ae15b6ca9802a066d)) + - change safety var to const + ([047aa494](https://github.com/Unitech/pm2/commit/047aa494d5c4dd4342915766b54d673db0d5cdf1)) + - drop some 0.x patch + ([0cab8880](https://github.com/Unitech/pm2/commit/0cab8880ffa362cf27ab7d7b6a64d6b478dce7cd)) + - remove prototype from API and create method + ([9552bd61](https://github.com/Unitech/pm2/commit/9552bd61b72692beb620a91765ad440cdf6abefe)) + - transform API into class + ([e3831f95](https://github.com/Unitech/pm2/commit/e3831f95c8d71f98e8840da37f7e883727eccd59)) + - name tests well + ([c3ccc651](https://github.com/Unitech/pm2/commit/c3ccc651d09ed7291090f516637b75bda99ff71c)) + - refactor e2e one line parallel + ([93802711](https://github.com/Unitech/pm2/commit/938027117cdb2f300ee772ab27f008cbe22a4b19)) + - e2e rename + ([8a7db95a](https://github.com/Unitech/pm2/commit/8a7db95aabc8437f292af0316cec81ab80ec41f5)) + - change params + ([282186f2](https://github.com/Unitech/pm2/commit/282186f24b19b010999f7c7c49750935ef19c190)) + - parallelize bash test + ([d4b4375e](https://github.com/Unitech/pm2/commit/d4b4375e16fe7ac463b252702da662d3a21bf8b4)) + + + + +## Test + - adapt test to new api + ([7a275e27](https://github.com/Unitech/pm2/commit/7a275e279ea01b1239e9dd8b9cf8e088e407b96d)) + - refactor before/after + ([b85ca3ca](https://github.com/Unitech/pm2/commit/b85ca3caa3c68e18f7ce6954cc85e90a9d33efef)) + - 3 concurrent jobs + ([472aba34](https://github.com/Unitech/pm2/commit/472aba3499ff2d9d0eb834e819410026b1a44503)) + - move test + ([9c973324](https://github.com/Unitech/pm2/commit/9c9733246dbe6afff1b488bc3ba3b6fea3877ea5)) + - move test + ([952b7631](https://github.com/Unitech/pm2/commit/952b7631d19e1074ea73cc7a67bbaefe20950603)) + - fix test with km_link + ([23fd8ecf](https://github.com/Unitech/pm2/commit/23fd8ecfea9b2bf61359f62a8e6e1a582c3b0d6e)) + + + + +## Chore + - shorten ecosystem file + ([992a0452](https://github.com/Unitech/pm2/commit/992a045227aed559e708ac4e6bb3f54beabe48e0)) + - change motd wording + ([aa183ba1](https://github.com/Unitech/pm2/commit/aa183ba19d88777d82619aa40499c2661d67879e)) + - merge master in development + ([0e4453d9](https://github.com/Unitech/pm2/commit/0e4453d9cc789aa08ee778ff400572337e90d2e3)) + - keymetrics -> pm2 + ([2c8170c2](https://github.com/Unitech/pm2/commit/2c8170c25e231eb8827bb0944b76c2f4b041d84e)) + - upgrade all modules + keymetrics-agent -> pm2/agent + increase version enabling v8-compile-cache + ([53ca18c1](https://github.com/Unitech/pm2/commit/53ca18c12868ab177b60a4edff2ccaa8127e301f)) + - pm2.io -> @pm2/io + ([ae098962](https://github.com/Unitech/pm2/commit/ae098962df35eee7f482dc0a514fd29a02a5f4ad)) + - right names as pm2 maintainers + ([e8cd7131](https://github.com/Unitech/pm2/commit/e8cd7131a6b9c9d497a2079bcbfc03770a753a06)) + - add changelog generation into contributing.md + ([d77bfbc3](https://github.com/Unitech/pm2/commit/d77bfbc3c8929851ee19ea604b2a6481d03771e3)) + - cache node_modules + ([81627e94](https://github.com/Unitech/pm2/commit/81627e94c72efa1f4d726e20bbf67f0bbd5c116f)) + - clone last 5 commits + ([dad38ed1](https://github.com/Unitech/pm2/commit/dad38ed1bae849147f66e44186cd71c4b9cb022d)) + - delete old stagnating pmx inside test + ([36834c2c](https://github.com/Unitech/pm2/commit/36834c2c00d496e04c38abaca30202eb650015c4)) + - pmx -> pm2.io + ([adcbebc3](https://github.com/Unitech/pm2/commit/adcbebc3f6419cd97c5ea99f3c3a6789585bda66)) + - updgrade pmx-2 + ([eeeb2988](https://github.com/Unitech/pm2/commit/eeeb2988f8886e405aea107db3b888fc1fc929f8)) + - disable legacy test + ([13723bd9](https://github.com/Unitech/pm2/commit/13723bd938d0e6fb1cbf35f15eabe91c52d87b58)) + - remove test for pmx alert system + ([c43414a6](https://github.com/Unitech/pm2/commit/c43414a63438d724b8099eb531ec72bab23b8ca2)) + - sync from master + ([3424ee27](https://github.com/Unitech/pm2/commit/3424ee27870feaf62fdf4509cce9015f8b1a8a2e)) + - add unique id for each process + ([85a5ee0f](https://github.com/Unitech/pm2/commit/85a5ee0f1fd16da9635fb4b16ddcd8d53aca8224)) + - use npm install for CI as yarn has issue with npm + ([52902186](https://github.com/Unitech/pm2/commit/5290218626af815f6cae8173bc78d21881a4dda8)) + - remove unused dependency + ([830fc15f](https://github.com/Unitech/pm2/commit/830fc15fad1aee95e65b2681482b03369f1f97d7)) + - upgrade PM2 to 3.0 + ([4bc2eb4c](https://github.com/Unitech/pm2/commit/4bc2eb4c9a8179b9ae38438e98ce7650a91b64db)) + - remove unused console.log + ([33db5084](https://github.com/Unitech/pm2/commit/33db5084814ae7940c90b7f933f9514d28008b78)) + - wording on error message + ([c251c8c9](https://github.com/Unitech/pm2/commit/c251c8c97e6f18aae584cac6b7f3c83cf4f2de9c)) + - revert PR #3496 + ([aae1d55e](https://github.com/Unitech/pm2/commit/aae1d55e410c4dcfbbca83eaabbdf1a65d55f3aa)) + - fix issue with snapshot command + remove command forceGc + ([97fd1010](https://github.com/Unitech/pm2/commit/97fd1010d005e59f2411042fa95891f9717fa8b7)) + - wording on error message + ([5f78ecbf](https://github.com/Unitech/pm2/commit/5f78ecbf90f9f46a7feb2a169968e86b0ecac91e)) + - drop 0.12 test on travis + ([beb6e487](https://github.com/Unitech/pm2/commit/beb6e48787c39c66569141d0fd8d090736114d23)) + - downgrade promptly + ([074a7a40](https://github.com/Unitech/pm2/commit/074a7a407a31b4d88442f5834d253d62f4e543b8)) + - remove coffee and livescript dependencies + ([13d6565c](https://github.com/Unitech/pm2/commit/13d6565c72e3596d05f87bfc8be15d3ee45fb279)) + - upgrade module version and engine version + ([84796956](https://github.com/Unitech/pm2/commit/84796956347ca638750fe89cb5545e2a90a0f2c2)) + + + + +## Branchs merged + - Merge branch 'development' into chore/dev-cache-node-modules + ([146c4e11](https://github.com/Unitech/pm2/commit/146c4e113c88e8ade17c7558c8e14cf523a3b2d6)) + - Merge branch 'development' of https://github.com/Unitech/pm2 into new-agent + ([3514e7fa](https://github.com/Unitech/pm2/commit/3514e7fac624bb83b4cc22651ebc05385f9c284d)) + - Merge branch 'development' into master + ([f5668331](https://github.com/Unitech/pm2/commit/f5668331dbe7346304258317a3b84450f421ed03)) + - Merge branch 'development' into new-usage-cli + ([4ae27694](https://github.com/Unitech/pm2/commit/4ae27694e34c4bc6ed389566d71fc5ec48b69652)) + - Merge branch 'Eywek-improv/agent' into new-agent + ([3e259dd1](https://github.com/Unitech/pm2/commit/3e259dd1d6bb96ea41897c49f3a84557c00c7dad)) + - Merge branch 'ecosystem-documentation' of github.com:rmonnier/pm2 into ecosystem-documentation + ([98348955](https://github.com/Unitech/pm2/commit/98348955a6eb3a9cd524b991bd1dd6ed03d2c857)) + - Merge branch 'development' into ecosystem-documentation + ([40157784](https://github.com/Unitech/pm2/commit/40157784a63bcb0e744d4ed56f6c687e28379fdd)) + - Merge branch 'inspect_mode' of github.com:Unitech/pm2 into inspect_mode + ([7e1494c7](https://github.com/Unitech/pm2/commit/7e1494c7f7971aaf1f4d00d2ee691c3c41775001)) + - Merge branch 'development' of github.com:Unitech/pm2 into development + ([48f81a8b](https://github.com/Unitech/pm2/commit/48f81a8b2f6f0db39edd86083fb369b74845c387)) + - Merge branch 'development' into master + ([47e54109](https://github.com/Unitech/pm2/commit/47e5410987ab3d824a34c062d70c24ab686e57db)) + - Merge branch 'development' into module_install_windows + ([7b82fb91](https://github.com/Unitech/pm2/commit/7b82fb916ed453c1c263bae43c962f6a5294d810)) + - Merge branch 'development' into module_install_windows + ([80b0495f](https://github.com/Unitech/pm2/commit/80b0495f63d1224b850af4b14cdeb055e3fef50b)) + + + + +## Pull requests merged + - Merge pull request #3726 from soyuka/fix-list + ([0255c5a6](https://github.com/Unitech/pm2/commit/0255c5a6ab1b8a8f609d2183d998695b8c42838d)) + - Merge pull request #3725 from soyuka/fix-list + ([a39eb4f8](https://github.com/Unitech/pm2/commit/a39eb4f806e87565f53758a19f0ee289b6489b67)) + - Merge pull request #3718 from AaronM04/openbsd-init-script + ([85458261](https://github.com/Unitech/pm2/commit/85458261d2673c609cb252d64ad4dfbaa466d848)) + - Merge pull request #3721 from Unitech/io_conf + ([70ec1f81](https://github.com/Unitech/pm2/commit/70ec1f81eae089f75e82723fde7b0b3926d0a9bc)) + - Merge pull request #3716 from Unitech/io_conf + ([0bc000b9](https://github.com/Unitech/pm2/commit/0bc000b9aae7dd37b456bc2d4fbc9eb4a9f047ef)) + - Merge pull request #3714 from Unitech/definition + ([d8cff0de](https://github.com/Unitech/pm2/commit/d8cff0dec5160a620d1512ff56726c073368d1a4)) + - Merge pull request #3700 from Unitech/report_error + ([4b2cad40](https://github.com/Unitech/pm2/commit/4b2cad407b76994e978074a2a3825fe70656304d)) + - Merge pull request #3670 from Unitech/changelog + ([4bcbcce1](https://github.com/Unitech/pm2/commit/4bcbcce16ced596f6ca2bab2b77d608a174a7c1a)) + - Merge pull request #3662 from DanielRuf/chore/dev-cache-node-modules + ([540590ee](https://github.com/Unitech/pm2/commit/540590ee056b44eed3b688a7b0b16ca78ec82cd9)) + - Merge pull request #3663 from DanielRuf/chore/dev-clone-last-5-commits + ([bdf95fc9](https://github.com/Unitech/pm2/commit/bdf95fc997f9ab2995b23668f25f11b6e98b5c47)) + - Merge pull request #3584 from ngtmuzi/development + ([33984b64](https://github.com/Unitech/pm2/commit/33984b64a2969ca4a3a5913f0f7da0242b6c5ec1)) + - Merge pull request #3500 from Unitech/test-parallel + ([da56c7af](https://github.com/Unitech/pm2/commit/da56c7aff18d3a38b3ad068b22cd75b290bac9d0)) + - Merge pull request #3539 from KimSeongIl/master + ([1325704d](https://github.com/Unitech/pm2/commit/1325704d95d324e56b0ebc86aed8137e0d0aa450)) + - Merge pull request #3556 from N-Nagorny/logs-smart-app-name-cutting + ([bfddf4fd](https://github.com/Unitech/pm2/commit/bfddf4fdef5ec293119d850cc2532ac5d6490ae3)) + - Merge pull request #3553 from Unitech/fix_tracing_not_working + ([9d51fe08](https://github.com/Unitech/pm2/commit/9d51fe0819182339f3a6a4aee7ea603ea3f4dd76)) + - Merge pull request #3549 from Eywek/new-agent + ([2f04027b](https://github.com/Unitech/pm2/commit/2f04027b536094d192b399677b3a113102f06b8e)) + - Merge pull request #3548 from rmonnier/start-ecosystem-default + ([55412f26](https://github.com/Unitech/pm2/commit/55412f263250395de0085144932cfe06b8c7180d)) + - Merge pull request #3546 from soyuka/improve-monitor-perf + ([e4e29233](https://github.com/Unitech/pm2/commit/e4e29233f99db36462a6e8f48eb8ebd3d2fd9fa5)) + - Merge pull request #3534 from rmonnier/new-usage-cli + ([5dfba8a4](https://github.com/Unitech/pm2/commit/5dfba8a4491f0bb83f2879915f0c4b164be2552c)) + - Merge pull request #3542 from rmonnier/default-start-ecosystem + ([c65595f4](https://github.com/Unitech/pm2/commit/c65595f4a70659e1e0d753e6c28a1fcedf45a91a)) + - Merge pull request #3545 from rmonnier/default-ecosystem + ([b3718656](https://github.com/Unitech/pm2/commit/b3718656f630aa54880343d9742534a2a508daec)) + - Merge pull request #3543 from rmonnier/ecosystem-documentation + ([a60580a1](https://github.com/Unitech/pm2/commit/a60580a12b4a0066c8df6620317fbc8bf599b0b6)) + - Merge pull request #3541 from soyuka/development + ([67e7a015](https://github.com/Unitech/pm2/commit/67e7a015cabaa7b08206a3b1bf9c0399af88f76b)) + - Merge pull request #3511 from Unitech/inspect_mode + ([75fb87f8](https://github.com/Unitech/pm2/commit/75fb87f8a1c46a6db8e974b421e857175e69b535)) + - Merge pull request #3517 from Unitech/polyfill_fs_copy_node4 + ([524f5494](https://github.com/Unitech/pm2/commit/524f54948de5080632d43bb512038d7bd7271619)) + - Merge pull request #3516 from Unitech/drop_unused_feature + ([9436f11a](https://github.com/Unitech/pm2/commit/9436f11aeecfc07e77aa9d6b108df4478b43402e)) + - Merge pull request #3510 from Unitech/dump_refacto + ([674e4469](https://github.com/Unitech/pm2/commit/674e4469554e6a765bb3d57a3c083e6ab53b20cc)) + - Merge pull request #3501 from Unitech/refactor_api + ([9f2c4ca4](https://github.com/Unitech/pm2/commit/9f2c4ca4c9eadf6c7730e3889c72e908cd2d8f5d)) + - Merge pull request #3496 from rmonnier/master + ([829cc303](https://github.com/Unitech/pm2/commit/829cc3032b2d61e20f7a2e7d1d819c0ddc0845e8)) + - Merge pull request #3484 from Unitech/pull_by_name + ([24d29404](https://github.com/Unitech/pm2/commit/24d294049008a0d01b2bc407b9b2b880d5843fbd)) + - Merge pull request #3482 from Unitech/mjs_support + ([ebe7b048](https://github.com/Unitech/pm2/commit/ebe7b0487218557858aaa98527360eca1776b140)) + - Merge pull request #3495 from Unitech/module_install_windows + ([e9c625d3](https://github.com/Unitech/pm2/commit/e9c625d3088c71eef4237ecd866b806957c61815)) + - Merge pull request #3507 from cheapsteak/patch-1 + ([a49287d6](https://github.com/Unitech/pm2/commit/a49287d6a1d22b39270e2d05dee2a17c0ed55797)) + + + + ## 2.10.4 ( Thu May 17 2018 14:32:40 GMT+0200 (CEST) ) From 439c37304024f756fce1d904fdc702c4ea31ca1a Mon Sep 17 00:00:00 2001 From: vince Date: Wed, 20 Jun 2018 15:12:48 +0200 Subject: [PATCH 131/140] chore: update readme with breaking changes --- CHANGELOG.md | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1a3a79db..fcb607ed 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,8 +4,10 @@ ## Breaking changes - merge_logs is now activated by default if not in cluster mode. Logs will not be suffixed by the pm_id if only one app is started ([ae02adf6](https://github.com/Unitech/pm2/commit/ae02adf63f70ceb3bf101be968996ca68d9ce277)) - - + - Drop support for node 0.12 + - Drop gracefulReload command + - Remove Interactor from PM2 source code + - Replace pmx with [pm2-io-apm](https://github.com/keymetrics/pm2-io-apm) ## Bug Fixes From a3c2900f3efecdc27f91b8b5e2a6328444656bee Mon Sep 17 00:00:00 2001 From: vince Date: Thu, 21 Jun 2018 10:44:35 +0200 Subject: [PATCH 132/140] refactor: change default log date format --- constants.js | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/constants.js b/constants.js index 3bbcb07c..127f5764 100644 --- a/constants.js +++ b/constants.js @@ -92,7 +92,7 @@ var csts = { WORKER_INTERVAL : process.env.PM2_WORKER_INTERVAL || 30000, KILL_TIMEOUT : process.env.PM2_KILL_TIMEOUT || 1600, PM2_PROGRAMMATIC : typeof(process.env.pm_id) !== 'undefined' || process.env.PM2_PROGRAMMATIC, - PM2_LOG_DATE_FORMAT : process.env.PM2_LOG_DATE_FORMAT !== undefined ? process.env.PM2_LOG_DATE_FORMAT : 'YYYY-MM-DD HH:mm:ss' + PM2_LOG_DATE_FORMAT : process.env.PM2_LOG_DATE_FORMAT !== undefined ? process.env.PM2_LOG_DATE_FORMAT : 'YYYY-MM-DD[T]HH:mm:ss.SSS[Z]' }; diff --git a/package.json b/package.json index 3d21d7ef..5d9499ff 100644 --- a/package.json +++ b/package.json @@ -158,7 +158,7 @@ "pm2-runtime": "./bin/pm2-runtime" }, "dependencies": { - "@pm2/agent": "^0.5.1", + "@pm2/agent": "^0.5.2", "@pm2/io": "^2.0.0", "@pm2/js-api": "^0.5.15", "async": "^2.6", From dfd3d621b890c6296f2cf85348848aee8f2dd2c2 Mon Sep 17 00:00:00 2001 From: Unitech Date: Thu, 21 Jun 2018 12:27:34 +0200 Subject: [PATCH 133/140] fix: format cpu usage at root --- lib/API/CliUx.js | 4 ++-- lib/God.js | 1 - lib/God/ActionMethods.js | 2 +- 3 files changed, 3 insertions(+), 4 deletions(-) diff --git a/lib/API/CliUx.js b/lib/API/CliUx.js index a5f809d3..a25f72e0 100644 --- a/lib/API/CliUx.js +++ b/lib/API/CliUx.js @@ -293,7 +293,7 @@ UX.dispAsTable = function(list, commander) { obj[key].push(l.pm2_env.restart_time ? l.pm2_env.restart_time : 0); // CPU + Memory - obj[key].push(l.monit ? (l.monit.cpu.toFixed(2) + '%') : 'N/A', l.monit ? UX.bytesToSize(l.monit.memory, 3) : 'N/A' ); + obj[key].push(l.monit ? (l.monit.cpu + '%') : 'N/A', l.monit ? UX.bytesToSize(l.monit.memory, 3) : 'N/A' ); // User if (!stacked) @@ -327,7 +327,7 @@ UX.dispAsTable = function(list, commander) { obj[key].push((l.pm2_env.pm_uptime && status == 'online') ? timeSince(l.pm2_env.pm_uptime) : 0); // CPU - obj[key].push(l.monit ? l.monit.cpu.toFixed(2) + '%' : 'N/A'); + obj[key].push(l.monit ? l.monit.cpu + '%' : 'N/A'); // Memory obj[key].push(l.monit ? UX.bytesToSize(l.monit.memory, 1) : 'N/A'); diff --git a/lib/God.js b/lib/God.js index 2067ec31..b6a64404 100644 --- a/lib/God.js +++ b/lib/God.js @@ -20,7 +20,6 @@ var numCPUs = require('os').cpus() ? require('os').cpus().length : 1; var path = require('path'); var EventEmitter2 = require('eventemitter2').EventEmitter2; var fs = require('fs'); -var pidusage = require('pidusage'); var vizion = require('vizion'); var debug = require('debug')('pm2:god'); var Utility = require('./Utility'); diff --git a/lib/God/ActionMethods.js b/lib/God/ActionMethods.js index 83665571..808170b6 100644 --- a/lib/God/ActionMethods.js +++ b/lib/God/ActionMethods.js @@ -89,7 +89,7 @@ module.exports = function(God) { pro['monit'] = { memory: stat.memory, - cpu: stat.cpu + cpu: Math.round(stat.cpu * 10) / 10 }; return pro; From 66d5e061f001076edbf847a0e187d7a9f44ffdcf Mon Sep 17 00:00:00 2001 From: Unitech Date: Mon, 25 Jun 2018 10:39:16 +0200 Subject: [PATCH 134/140] chore: display active transport --- lib/API.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/lib/API.js b/lib/API.js index 0eebf103..fa147e6b 100644 --- a/lib/API.js +++ b/lib/API.js @@ -1495,10 +1495,11 @@ class API { UX.miniDisplay(list); else if (!commander.silent) { if (that.gl_interact_infos) { - Common.printOut('%s Agent Online | Access: %s | Server: %s', + Common.printOut('%s Agent Online | Access: %s | Server: %s | Transport %s', chalk.green.bold('⇆'), chalk.bold('https://app.pm2.io/#/r/' + that.gl_interact_infos.public_key), - chalk.bold(that.gl_interact_infos.machine_name)); + chalk.bold(that.gl_interact_infos.machine_name), + that.gl_interact_infos.transporters); } UX.dispAsTable(list, commander); Common.printOut(chalk.white.italic(' Use `pm2 show ` to get more details about an app')); From 94599373940ddbabe580726b9aee652810a1e273 Mon Sep 17 00:00:00 2001 From: vince Date: Mon, 25 Jun 2018 11:22:48 +0200 Subject: [PATCH 135/140] chore: upgrades node modules --- package.json | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/package.json b/package.json index 5d9499ff..658097c7 100644 --- a/package.json +++ b/package.json @@ -158,32 +158,33 @@ "pm2-runtime": "./bin/pm2-runtime" }, "dependencies": { - "@pm2/agent": "^0.5.2", + "@pm2/agent": "^0.5.4", "@pm2/io": "^2.0.0", "@pm2/js-api": "^0.5.15", - "async": "^2.6", + "async": "^2.6.1", "blessed": "^0.1.81", "chalk": "^2.4.1", - "chokidar": "^2.0.3", + "chokidar": "^2.0.4", "cli-table-redemption": "^1.0.0", + "coffee-script": "^1.12.7", "commander": "2.15.1", "cron": "^1.3", "debug": "^3.1", "eventemitter2": "5.0.1", "fclone": "1.0.11", "mkdirp": "0.5.1", - "moment": "^2.22", - "needle": "^2.2.0", + "moment": "^2.22.2", + "needle": "^2.2.1", "nssocket": "0.6.0", "pidusage": "^2.0.6", - "pm2-axon": "3.1.0", + "pm2-axon": "3.3.0", "pm2-axon-rpc": "^0.5.1", "pm2-deploy": "^0.3.9", "pm2-multimeter": "^0.1.2", - "promptly": "2.2.0", + "promptly": "3.0.3", "semver": "^5.5", "shelljs": "~0.8.2", - "source-map-support": "^0.5", + "source-map-support": "^0.5.6", "sprintf-js": "1.1.1", "v8-compile-cache": "^2.0.0", "vizion": "~0.2.0", From 6e3b45f6371a3ac7d01ab0bb892b17a1a80ead1c Mon Sep 17 00:00:00 2001 From: vince Date: Mon, 25 Jun 2018 16:08:26 +0200 Subject: [PATCH 136/140] chore: upgrade mocha to version 5 --- package.json | 2 +- test/unit.sh | 56 ++++++++++++++++++++++++++-------------------------- 2 files changed, 29 insertions(+), 29 deletions(-) diff --git a/package.json b/package.json index 658097c7..8a1ec696 100644 --- a/package.json +++ b/package.json @@ -191,7 +191,7 @@ "yamljs": "^0.3.0" }, "devDependencies": { - "mocha": "^3.5", + "mocha": "^5.2.0", "should": "^13" }, "optionalDependencies": { diff --git a/test/unit.sh b/test/unit.sh index 7dd0f930..1fb7143d 100644 --- a/test/unit.sh +++ b/test/unit.sh @@ -33,61 +33,61 @@ $pm2 uninstall all # fi cd test/programmatic -mocha --opts ./mocha.opts ./god.mocha.js +mocha --exit --opts ./mocha.opts ./god.mocha.js spec "God test" -mocha --opts ./mocha.opts ./programmatic.js +mocha --exit --opts ./mocha.opts ./programmatic.js spec "Programmatic test" -mocha --opts ./mocha.opts ./containerizer.mocha.js +mocha --exit --opts ./mocha.opts ./containerizer.mocha.js spec "Dockerfile parser test" -mocha --opts ./mocha.opts ./api.mocha.js +mocha --exit --opts ./mocha.opts ./api.mocha.js spec "API tests" -mocha --opts ./mocha.opts ./path_resolution.mocha.js +mocha --exit --opts ./mocha.opts ./path_resolution.mocha.js spec "API tests" -mocha --opts ./mocha.opts ./lazy_api.mocha.js +mocha --exit --opts ./mocha.opts ./lazy_api.mocha.js spec "API tests" -mocha --opts ./mocha.opts ./reload-locker.mocha.js +mocha --exit --opts ./mocha.opts ./reload-locker.mocha.js spec "Reload locker tests" -mocha --opts ./mocha.opts ./api.backward.compatibility.mocha.js +mocha --exit --opts ./mocha.opts ./api.backward.compatibility.mocha.js spec "API Backward compatibility tests" -mocha --opts ./mocha.opts ./custom_action.mocha.js +mocha --exit --opts ./mocha.opts ./custom_action.mocha.js spec "Custom Actions tests" -mocha --opts ./mocha.opts ./logs.js +mocha --exit --opts ./mocha.opts ./logs.js spec "Logs test" -mocha --opts ./mocha.opts ./watcher.js +mocha --exit --opts ./mocha.opts ./watcher.js spec "Watcher" -mocha --opts ./mocha.opts ./max_memory_limit.js +mocha --exit --opts ./mocha.opts ./max_memory_limit.js spec "Max memory tests" -# mocha --opts ./mocha.opts ./module_configuration.mocha.js +# mocha --exit --opts ./mocha.opts ./module_configuration.mocha.js # spec "Max memory tests" -mocha --opts ./mocha.opts ./cluster.mocha.js +mocha --exit --opts ./mocha.opts ./cluster.mocha.js spec "Cluster tests" -mocha --opts ./mocha.opts ./graceful.mocha.js +mocha --exit --opts ./mocha.opts ./graceful.mocha.js spec "Graceful tests" -mocha --opts ./mocha.opts ./inside.mocha.js +mocha --exit --opts ./mocha.opts ./inside.mocha.js spec "Inside pm2 call tests" -mocha --opts ./mocha.opts ./misc_commands.js +mocha --exit --opts ./mocha.opts ./misc_commands.js spec "MISC tests" -mocha --opts ./mocha.opts ./signals.js +mocha --exit --opts ./mocha.opts ./signals.js spec "SIGINT signal interception + delay customization" -mocha --opts ./mocha.opts ./send_data_process.mocha.js +mocha --exit --opts ./mocha.opts ./send_data_process.mocha.js spec "Send data to a process" -mocha --opts ./mocha.opts ./modules.mocha.js +mocha --exit --opts ./mocha.opts ./modules.mocha.js spec "Module API testing" -# mocha --opts ./mocha.opts ./module_retrocompat.mocha.js +# mocha --exit --opts ./mocha.opts ./module_retrocompat.mocha.js # spec "Module retrocompatibility system" -mocha --opts ./mocha.opts ./json_validation.mocha.js +mocha --exit --opts ./mocha.opts ./json_validation.mocha.js spec "JSON validation test" -mocha --opts ./mocha.opts ./env_switching.js +mocha --exit --opts ./mocha.opts ./env_switching.js spec "JSON environment switching on JSON restart with --env" -mocha --opts ./mocha.opts ./configuration.mocha.js +mocha --exit --opts ./mocha.opts ./configuration.mocha.js spec "Configuration system working" -mocha --opts ./mocha.opts ./id.mocha.js +mocha --exit --opts ./mocha.opts ./id.mocha.js spec "Uniqueness id for each process" # @@ -97,9 +97,9 @@ cd ../interface # echo $PM2_HOME -mocha --opts ./mocha.opts ./bus.spec.mocha.js +mocha --exit --opts ./mocha.opts ./bus.spec.mocha.js spec "Protocol communication test" -mocha --opts ./mocha.opts ./bus.fork.spec.mocha.js +mocha --exit --opts ./mocha.opts ./bus.fork.spec.mocha.js spec "Protocol communication test" -mocha --opts ./mocha.opts ./utility.mocha.js +mocha --exit --opts ./mocha.opts ./utility.mocha.js spec "PM2 Utility" From 792cef8ec80d8e050333fbeb289a20ea001c1b5c Mon Sep 17 00:00:00 2001 From: Florian Hermouet-Joscht Date: Mon, 25 Jun 2018 16:09:24 +0200 Subject: [PATCH 137/140] Fix #3669 Fix revert path of modules --- lib/API/Modules/Modularizer.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/API/Modules/Modularizer.js b/lib/API/Modules/Modularizer.js index 900afc1e..b8b88e1e 100644 --- a/lib/API/Modules/Modularizer.js +++ b/lib/API/Modules/Modularizer.js @@ -436,7 +436,7 @@ var Rollback = { // Delete failing module require('shelljs').rm('-r', module_path); // Restore working version - require('shelljs').cp('-r', backup_path, module_path); + require('shelljs').cp('-r', backup_path, cst.DEFAULT_MODULE_PATH); var proc_path = path.join(module_path, 'node_modules', canonic_module_name); var package_json_path = path.join(proc_path, 'package.json'); From 6392a3869e85ab20f82ee8f3834ec49a0dd4e811 Mon Sep 17 00:00:00 2001 From: vince Date: Tue, 26 Jun 2018 10:28:00 +0200 Subject: [PATCH 138/140] chore: upgrade pm2-io-apm to 2.0.1 to fix https patching --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 8a1ec696..f724fa86 100644 --- a/package.json +++ b/package.json @@ -159,7 +159,7 @@ }, "dependencies": { "@pm2/agent": "^0.5.4", - "@pm2/io": "^2.0.0", + "@pm2/io": "^2.0.1", "@pm2/js-api": "^0.5.15", "async": "^2.6.1", "blessed": "^0.1.81", From 2e91827ea2bc309545726cb4bd195a5eb29b55a9 Mon Sep 17 00:00:00 2001 From: vince Date: Wed, 27 Jun 2018 12:11:44 +0200 Subject: [PATCH 139/140] chore: upgrade pm2-io-apm to 2.0.2 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index f724fa86..526aa66b 100644 --- a/package.json +++ b/package.json @@ -159,7 +159,7 @@ }, "dependencies": { "@pm2/agent": "^0.5.4", - "@pm2/io": "^2.0.1", + "@pm2/io": "^2.0.2", "@pm2/js-api": "^0.5.15", "async": "^2.6.1", "blessed": "^0.1.81", From 9cb24dd35d558146f720e6236043e0dd7422ce5d Mon Sep 17 00:00:00 2001 From: vince Date: Wed, 27 Jun 2018 16:00:11 +0200 Subject: [PATCH 140/140] test: remove tests on http:transaction from apm, it was removed in apm 2.0.2 --- test/interface/bus.fork.spec.mocha.js | 16 ---------------- test/interface/bus.spec.mocha.js | 14 -------------- 2 files changed, 30 deletions(-) diff --git a/test/interface/bus.fork.spec.mocha.js b/test/interface/bus.fork.spec.mocha.js index 5ad9f662..72e35829 100644 --- a/test/interface/bus.fork.spec.mocha.js +++ b/test/interface/bus.fork.spec.mocha.js @@ -170,22 +170,6 @@ describe('PM2 BUS / RPC', function() { should(err).be.null(); }); }); - - it('should (transaction:http)', function(done) { - - pm2_bus.on('*', function(event, data) { - if (event == 'http:transaction') { - data.should.have.properties(TRANSACTION_HTTP_EVENT); - data.process.should.have.properties(PROCESS_ARCH); - done(); - } - }); - - pm2.start('./http_transaction.js', {}, function(err, data) { - should(err).be.null(); - }); - }); - }); }); diff --git a/test/interface/bus.spec.mocha.js b/test/interface/bus.spec.mocha.js index 3fcf29e2..4db6b9c3 100644 --- a/test/interface/bus.spec.mocha.js +++ b/test/interface/bus.spec.mocha.js @@ -171,20 +171,6 @@ describe('PM2 BUS / RPC', function() { }); }); - it('should (transaction:http)', function(done) { - pm2_bus.on('*', function(event, data) { - if (event == 'http:transaction') { - data.should.have.properties(TRANSACTION_HTTP_EVENT); - data.process.should.have.properties(PROCESS_ARCH); - done(); - } - }); - - pm2.start('./http_transaction.js', {instances : 1}, function(err, data) { - should(err).be.null(); - }); - }); - }); });