From 1c6064a4b240b4198afa277308328a184a7e5bbb Mon Sep 17 00:00:00 2001 From: Alexey Khristov Date: Tue, 30 Dec 2014 17:09:51 +0200 Subject: [PATCH 1/9] add --config option and read default pm2-gui.json file --- README.md | 19 +++++++++++++++--- bin/pm2-gui | 54 +++++++++++++++++++++++++++++++++++++++++++++++++++- package.json | 2 +- 3 files changed, 70 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 546bfb3..2d8c885 100644 --- a/README.md +++ b/README.md @@ -76,15 +76,17 @@ $ npm install -g pm2-gui -h, --help output usage information --no-debug hide stdout/stderr information + --config path to custom .json config. Default value pm2-gui.json ``` ## Configs ```javascript { - "refresh": 3000 - "manipulation": true - "pm2": "~/.pm2" + "refresh": 3000, + "manipulation": true, + "pm2": "~/.pm2", + "port": 8088 } ``` @@ -92,6 +94,17 @@ $ npm install -g pm2-gui - **manupulation** A value indicates whether the client has permission to restart/stop processes, `true` by default. - **pm2** Root directory of Unitech/PM2, `~/.pm2` by default. - **password** The encrypted authentication code, if this config is set, users need to be authorized before accessing the index page. +- **port** Web GUI port, can be set only from config file + +### Config file +Config file can be set with option --config + +Example +```bash +$ pm2-gui start --config pm2-gui.json +``` + +If config name pm2-gui.json - option can be omitted ### Set Config Usage diff --git a/bin/pm2-gui b/bin/pm2-gui index 2b93160..efae12c 100755 --- a/bin/pm2-gui +++ b/bin/pm2-gui @@ -2,6 +2,7 @@ var commander = require('commander'), path = p = require('path'), + fs = require('fs'), chalk = require('chalk'), _ = require('lodash'), pkg = require('../package.json'), @@ -25,17 +26,68 @@ commander.on('-c', function(){ console.log(arguments); }) +var defaultConfigFileName = 'pm2-gui.json'; +var acceptKeys = ['pm2', 'refresh', 'manipulation', 'password']; // Web interface commander.command('start [port]') + .option('--config ', 'pass json config file with options') .option('--no-debug', 'hide stdout/stderr information') .description('Launch the web server, port default by 8088') .action(function(port, cmd){ + + function setupOptions(jsonConfig) { + var mon = Monitor(); + var passwordKeyName = acceptKeys[acceptKeys.length - 1]; + acceptKeys.forEach(function(keyName) { + var value = jsonConfig[keyName]; + if (!value) { + return; + } + if (keyName === passwordKeyName) { + var md5 = crypto.createHash('md5'); + md5.update(value); + value = md5.digest('hex'); + } + mon.config(keyName, value); + }); + } + + var configData; + if (cmd.config){ //if config file passed + + try { + configData = fs.readFileSync(cmd.config); + } catch (e) { + if (e.code === 'ENOENT') { + console.log('Config file %s not found', cmd.config); + process.exit(1); + } else { + console.log('Error read config file %s, error: %j', cmd.config, err); + process.exit(2); + } + } + } else { + try { + configData = fs.readFileSync(defaultConfigFileName); + } catch (e) {} + } + + try { + var jsonConfig = JSON.parse(configData); + setupOptions(jsonConfig); + } catch (e) { + console.log('Cant convert file %s to JSON', cmd.config); + process.exit(3); + } + + if (!port && jsonConfig.port) { // setup port from config file + port = jsonConfig.port; + } interface(port, cmd.debug); }); // Configuration -var acceptKeys = ['pm2', 'refresh', 'manipulation', 'password']; function showConfigs(cmd, mon){ if (!mon) { mon = Monitor(); diff --git a/package.json b/package.json index 432c5b8..48015e7 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "pm2-gui", - "version": "0.0.7", + "version": "0.0.8", "description": "An elegant web interface for Unitech/PM2.", "scripts": { }, From 48a00d543753b990c3128ab687744751aad01d77 Mon Sep 17 00:00:00 2001 From: Tjatse Date: Wed, 31 Dec 2014 18:11:51 +0800 Subject: [PATCH 2/9] remove test ignoring --- .gitignore | 1 - .npmignore | 1 - 2 files changed, 2 deletions(-) diff --git a/.gitignore b/.gitignore index 5743ba4..b512c09 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1 @@ -test node_modules \ No newline at end of file diff --git a/.npmignore b/.npmignore index a596fdc..a267a83 100644 --- a/.npmignore +++ b/.npmignore @@ -1,4 +1,3 @@ node_modules .gitignore -test screenshots \ No newline at end of file From c907d8a2200a92443051c1cfc1eed714b58fa7a3 Mon Sep 17 00:00:00 2001 From: Tjatse Date: Wed, 31 Dec 2014 18:11:59 +0800 Subject: [PATCH 3/9] --config option --- bin/pm2-gui | 154 +++++++++++++++++++++++++--------------------------- 1 file changed, 73 insertions(+), 81 deletions(-) diff --git a/bin/pm2-gui b/bin/pm2-gui index efae12c..d1913ee 100755 --- a/bin/pm2-gui +++ b/bin/pm2-gui @@ -22,83 +22,39 @@ commander.on('--help', function(){ chalk.grey(' $ pm2-gui start 8090\n') ); }); -commander.on('-c', function(){ - console.log(arguments); -}) -var defaultConfigFileName = 'pm2-gui.json'; -var acceptKeys = ['pm2', 'refresh', 'manipulation', 'password']; - -// Web interface +/** + * Run web interface. + */ commander.command('start [port]') - .option('--config ', 'pass json config file with options') - .option('--no-debug', 'hide stdout/stderr information') + .option('--config [file]', 'pass JSON config file with options') + .option('--no-debug', 'hide stdout / stderr information') .description('Launch the web server, port default by 8088') .action(function(port, cmd){ - - function setupOptions(jsonConfig) { - var mon = Monitor(); - var passwordKeyName = acceptKeys[acceptKeys.length - 1]; - acceptKeys.forEach(function(keyName) { - var value = jsonConfig[keyName]; - if (!value) { - return; - } - if (keyName === passwordKeyName) { - var md5 = crypto.createHash('md5'); - md5.update(value); - value = md5.digest('hex'); - } - mon.config(keyName, value); - }); - } - - var configData; - if (cmd.config){ //if config file passed - - try { - configData = fs.readFileSync(cmd.config); - } catch (e) { - if (e.code === 'ENOENT') { - console.log('Config file %s not found', cmd.config); - process.exit(1); - } else { - console.log('Error read config file %s, error: %j', cmd.config, err); - process.exit(2); - } + if (cmd.config) { + var jsonFile; + if (typeof cmd.config != 'string') { + jsonFile = 'pm2-gui.json'; + } else { + jsonFile = cmd.config; } - } else { + if (!fs.existsSync(jsonFile)) { + console.log(chalk.red('✘ JSON configured file does not exist!\n')); + process.exit(); + } + try { - configData = fs.readFileSync(defaultConfigFileName); - } catch (e) {} + var config = JSON.parse(fs.readFileSync(jsonFile, {encoding: 'utf-8'})); + setConfig(config); + } catch (err) { + console.log(chalk.red('✘ JSON configured file is invalid!\n')); + process.exit(); + } } - - try { - var jsonConfig = JSON.parse(configData); - setupOptions(jsonConfig); - } catch (e) { - console.log('Cant convert file %s to JSON', cmd.config); - process.exit(3); - } - - if (!port && jsonConfig.port) { // setup port from config file - port = jsonConfig.port; - } - interface(port, cmd.debug); + port && setConfig('port', port); + interface(cmd.debug); }); -// Configuration -function showConfigs(cmd, mon){ - if (!mon) { - mon = Monitor(); - } - var storage = mon._config.store, prints = ''; - for (var k in storage) { - prints += Array(15 - k.length).join(' ') + chalk.bold(k + ': ') + ' ' + chalk.blue(storage[k] + '\n'); - } - console.log(prints); -} - commander.command('config') .description('show all configs') .action(showConfigs); @@ -106,19 +62,8 @@ commander.command('config') commander.command('set ') .description('set config by key-value pairs') .action(function(key, value, cmd){ - if (!~acceptKeys.indexOf(key)) { - return console.log('key could only be one of below:', acceptKeys.map(function(m){ - return '\n' + chalk.magenta(m) - }).join('')); - } - var mon = Monitor(); - if (key == acceptKeys[acceptKeys.length - 1]) { - var md5 = crypto.createHash('md5'); - md5.update(value); - value = md5.digest('hex'); - } - mon.config(key, value); - showConfigs(cmd, mon); + var mon = setConfig(key, value); + mon && showConfigs(cmd, mon); }); commander.command('rm ') @@ -134,4 +79,51 @@ commander.parse(process.argv); if (process.argv.length == 2) { commander.outputHelp(); process.exit(0); +} + +/** + * Set configuration. + * @param key + * @param value + * @returns {*} + */ +function setConfig(key, value){ + var mon = Monitor(), + acceptKeys = Object.keys(mon.options).filter(function(key){ + return !~['socketio', 'pm2Conf', 'debug'].indexOf(key); + }); + + (function config(pairs){ + if (pairs.length == 0) { + return; + } + var pair = pairs.shift(); + if (!~acceptKeys.indexOf(pair[0])) { + return config(pairs); + } + if (pair[0] == 'password') { + var md5 = crypto.createHash('md5'); + md5.update(pair[1]); + pair[1] = md5.digest('hex'); + } + mon.config(pair[0], pair[1]); + config(pairs); + })(typeof key == 'object' ? _.pairs(key) : [[key, value]]); + + return mon; +} +/** + * Show all configurations. + * @param cmd + * @param mon + */ +function showConfigs(cmd, mon){ + if (!mon) { + mon = Monitor(); + } + var storage = mon._config.store, prints = ''; + for (var k in storage) { + prints += Array(15 - k.length).join(' ') + chalk.bold(k + ': ') + ' ' + chalk.blue(storage[k] + '\n'); + } + console.log(prints); } \ No newline at end of file From 2979b04d11db3c57c129d42f5dec80dc2511a6a4 Mon Sep 17 00:00:00 2001 From: Tjatse Date: Wed, 31 Dec 2014 18:12:09 +0800 Subject: [PATCH 4/9] fix: configuration --- lib/mon.js | 62 ++++++++++++++++++++++++++++++------------------------ 1 file changed, 34 insertions(+), 28 deletions(-) diff --git a/lib/mon.js b/lib/mon.js index 17c728c..9c57d1b 100644 --- a/lib/mon.js +++ b/lib/mon.js @@ -8,7 +8,8 @@ var fs = require('fs'), ansiHTML = require('ansi-html'), pm = require('./pm'), totalmem = require('os').totalmem(), - pidusage = require('pidusage'); + pidusage = require('pidusage'), + defConf = require('../pm2-gui.conf'); module.exports = Monitor; @@ -33,30 +34,34 @@ function Monitor(options){ this._init(options); }; +Monitor.prototype._resolveHome = function(pm2Home){ + if (pm2Home.indexOf('~/') == 0) { + // Get root directory of PM2. + pm2Home = process.env.PM2_HOME || p.resolve(process.env.HOME || process.env.HOMEPATH, pm2Home.substr(2)); + + // Make sure exist. + if (!pm2Home || !fs.existsSync(pm2Home)) { + throw new Error('PM2 root can not be located, try to set env by `export PM2_HOME=[ROOT]`.'); + } + } + return pm2Home; +} /** * Initialize options and configurations. * @private */ Monitor.prototype._init = function(options){ options = options || {}; + // bind default options. - _.defaults(options, { - refresh : 5000, - manipulation: true - }); + options = _.defaults(defConf, options); - // Get root directory of PM2. - var pm2Root = process.env.PM2_HOME || p.resolve(process.env.HOME || process.env.HOMEPATH, '.pm2'); - - // Make sure exist. - if (!pm2Root || !fs.existsSync(pm2Root)) { - throw new Error('PM2 root can not be located, try to set env by `export PM2_HOME=[ROOT]`.'); - } + options.pm2 = this._resolveHome(options.pm2); // Load PM2 config. - var pm2ConfPath = path.join(pm2Root, 'conf.js'); + var pm2ConfPath = path.join(options.pm2, 'conf.js'); try { - options.pm2Conf = require(pm2ConfPath)(pm2Root); + options.pm2Conf = require(pm2ConfPath)(options.pm2); if (!options.pm2Conf) { throw new Error(404); } @@ -64,8 +69,6 @@ Monitor.prototype._init = function(options){ throw new Error('Can not load PM2 config, the file "' + pm2ConfPath + '" does not exist.'); } - options.pm2Root = pm2Root; - // Bind socket.io server to context. if (options.sockio) { this._sockio = options.sockio; @@ -77,12 +80,18 @@ Monitor.prototype._init = function(options){ Object.freeze(this.options); // Initialize configurations. - this._config = new nconf.File({file: path.resolve(this.options.pm2Root, 'pm2-gui.json')}); + this._config = new nconf.File({file: path.resolve(this.options.pm2, 'pm2-gui.json')}); // Set configurations. - this.config('pm2', this._config.get('pm2') || this.options.pm2Root); - this.config('refresh', this._config.get('refresh') || this.options.refresh); - this.config('manipulation', this._config.get('manipulation') || this.options.manipulation || true); + this.config('pm2', this._resolveHome(this.config('pm2')) || this.options.pm2); + this.config('refresh', this.config('refresh') || this.options.refresh); + this.config('port', this.config('port') || this.options.port || 8088); + + var mani = false; + if (typeof (mani = this.config('manipulation')) == 'undefined' && typeof (mani = this.options.manipulation) == 'undefined') { + mani = true; + } + this.config('manipulation', mani); // Logger. this._log = Debug({ @@ -115,12 +124,8 @@ Monitor.prototype.config = function(key, value){ // Clear config. this._config.clear(key); // Reset to default if necessary. - if (key == 'refresh') { - value = 5000; - } else if (key == 'manipulation') { - value = true; - } - value && this._config.set(key, value); + var value = defConf[key]; + (typeof value != 'undefined') && this._config.set(key, value); return this._config.saveSync(); } @@ -132,6 +137,7 @@ Monitor.prototype.config = function(key, value){ value = (value == 'true'); } } + this._config.set(key, value); // Save it. this._config.saveSync(); @@ -350,8 +356,8 @@ Monitor.prototype._connectProcSock = function(socket){ stat.memory = stat.memory * 100 / totalmem; // Emit memory/CPU usage to clients. broadcast.call(ctx, { - pid : pid, - time: Date.now(), + pid : pid, + time : Date.now(), usage: stat }); }); From 4d795b1bc3a82a108bc52e7a205be08dcd7f7fbc Mon Sep 17 00:00:00 2001 From: Tjatse Date: Wed, 31 Dec 2014 18:12:34 +0800 Subject: [PATCH 5/9] test script --- package.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/package.json b/package.json index 48015e7..6613c60 100644 --- a/package.json +++ b/package.json @@ -1,8 +1,9 @@ { "name": "pm2-gui", - "version": "0.0.8", + "version": "0.0.7", "description": "An elegant web interface for Unitech/PM2.", "scripts": { + "test": "NODE_ENV=test bash test/index.sh" }, "bin": { "pm2-gui": "bin/pm2-gui" From 891c0345f6e09fc1e3aab9c7069704a72dc4f054 Mon Sep 17 00:00:00 2001 From: Tjatse Date: Wed, 31 Dec 2014 18:12:43 +0800 Subject: [PATCH 6/9] default config --- pm2-gui.conf | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 pm2-gui.conf diff --git a/pm2-gui.conf b/pm2-gui.conf new file mode 100644 index 0000000..d458811 --- /dev/null +++ b/pm2-gui.conf @@ -0,0 +1,6 @@ +module.exports = { + "pm2": "~/.pm2", + "refresh": 5000, + "manipulation": true, + "port": 8088 +}; \ No newline at end of file From f1c5a67b239d260d7f1852585f22b93176999b5f Mon Sep 17 00:00:00 2001 From: Tjatse Date: Wed, 31 Dec 2014 18:12:56 +0800 Subject: [PATCH 7/9] test cases --- test/bash/config.sh | 43 +++++++++++++ test/bash/include.sh | 42 +++++++++++++ test/bash/interface.sh | 114 ++++++++++++++++++++++++++++++++++ test/fixtures/colorful.js | 14 +++++ test/fixtures/exit.js | 1 + test/fixtures/fib-slow.js | 13 ++++ test/fixtures/invalid.conf | 5 ++ test/fixtures/pm2-gui-cp.conf | 6 ++ test/fixtures/pm2-gui.json | 6 ++ test/fixtures/rand.js | 3 + test/fixtures/throw.js | 4 ++ test/fixtures/tick.js | 4 ++ test/fixtures/tock.js | 6 ++ test/index.sh | 16 +++++ 14 files changed, 277 insertions(+) create mode 100644 test/bash/config.sh create mode 100644 test/bash/include.sh create mode 100644 test/bash/interface.sh create mode 100644 test/fixtures/colorful.js create mode 100644 test/fixtures/exit.js create mode 100644 test/fixtures/fib-slow.js create mode 100644 test/fixtures/invalid.conf create mode 100644 test/fixtures/pm2-gui-cp.conf create mode 100644 test/fixtures/pm2-gui.json create mode 100644 test/fixtures/rand.js create mode 100644 test/fixtures/throw.js create mode 100644 test/fixtures/tick.js create mode 100644 test/fixtures/tock.js create mode 100644 test/index.sh diff --git a/test/bash/config.sh b/test/bash/config.sh new file mode 100644 index 0000000..e9e2aef --- /dev/null +++ b/test/bash/config.sh @@ -0,0 +1,43 @@ +#!/usr/bin/env bash + +SRC=$(cd $(dirname "$0"); pwd) +source "${SRC}/include.sh" + +cd $fixtures + +head "set config (Number)(refresh)" +$pg set refresh 4000 > /dev/null +val=`$pg config | grep "refresh:" | egrep -oh "\d+"` + +[ $val -eq 4000 ] || fail "expect the value to be 4000, but current is $val" +success "the value should be 4000" + +head "set config (Number)(port)" +$pg set port 9000 > /dev/null +val=`$pg config | grep "port:" | egrep -oh "\d+"` + +[ $val -eq 9000 ] || fail "expect the value to be 9000, but current is $val" +success "the value should be 9000" + +head "set config (Boolean)" +$pg set manipulation false > /dev/null +val=`$pg config | grep "manipulation:" | egrep -oh "(true|false)"` + +[ $val = false ] || fail "expect the value to be false, but current is $val" +success "the value should be false" + +head "set config (String)" +tmpPM2="/tmp/.pm2" + +if [ ! -d "$tmpPM2" ]; then + mkdir "$tmpPM2" +fi + +$pg set pm2 "$tmpPM2" > /dev/null +val=`$pg config | grep "pm2:" | egrep -oh "$tmpPM2$" | wc -c` + +[ $val -gt 0 ] || fail "expect the value to be /tmp/.pm2" +success "the value should be /tmp/.pm2" + +$pg set pm2 "~/.pm2" > /dev/null +$pg set port 8088 > /dev/null diff --git a/test/bash/include.sh b/test/bash/include.sh new file mode 100644 index 0000000..4969547 --- /dev/null +++ b/test/bash/include.sh @@ -0,0 +1,42 @@ +#!/usr/bin/env bash + +node="`type -P node`" +nodeVersion="`$node -v`" + +pg="`type -P node` `pwd`/bin/pm2-gui" + +fixtures="test/fixtures" + +function success { + echo -e "\033[32m ✔ $1\033[0m" +} + +function fail { + echo -e "######## \033[31m ✘ $1\033[0m" + exit 1 +} + +function spec { + RET=$? + sleep 0.3 + [ $RET -eq 0 ] || fail "$1" + success "$1" +} + +function ispec { + RET=$? + sleep 0.3 + [ $RET -ne 0 ] || fail "$1" + success "$1" +} + +function should { + sleep 0.5 + OUT=`$pm2 prettylist | grep -o "$2" | wc -l` + [ $OUT -eq $3 ] || fail "$1" + success "$1" +} + +function head { + echo -e "\x1B[1;35m$1\x1B[0m" +} diff --git a/test/bash/interface.sh b/test/bash/interface.sh new file mode 100644 index 0000000..055a7b5 --- /dev/null +++ b/test/bash/interface.sh @@ -0,0 +1,114 @@ +#!/usr/bin/env bash + +SRC=$(cd $(dirname "$0"); pwd) +source "${SRC}/include.sh" + +cd $fixtures + +$pg set port 8088 > /dev/null + +head "run web server (default port)" +nohup $pg start > /dev/null 2>&1 & +pid=$! +sleep 1 +ret=`nc 127.0.0.1 8088 < /dev/null; echo $?` +[ $ret -eq 0 ] || fail "expect 127.0.0.1:8088 can be connected" +success "127.0.0.1:8088 should be connected" + +kill "$pid" +sleep 1 + +ret=`nc 127.0.0.1 8088 < /dev/null; echo $?` +[ $ret -eq 1 ] || fail "expect 127.0.0.1:8088 can not be connected" +success "127.0.0.1:8088 should be disconnected" + +head "run web server (customized port: 9000)" +nohup $pg start 9000 > /dev/null 2>&1 & +pid=$! +sleep 1 +ret=`nc 127.0.0.1 9000 < /dev/null; echo $?` +[ $ret -eq 0 ] || fail "expect 127.0.0.1:9000 can be connected" +success "127.0.0.1:9000 should be connected" + +kill "$pid" +sleep 1 + +ret=`nc 127.0.0.1 9000 < /dev/null; echo $?` +[ $ret -eq 1 ] || fail "expect 127.0.0.1:9000 can not be connected" +success "127.0.0.1:9000 should be disconnected" + +head "run web server (--config verify)" +ret=`$pg start --config not_exist.json | grep "does not exist" | wc -c` +[ $ret -gt 0 ] || fail "expect throw out error message" +success "JSON file does not exist" + +ret=`$pg start --config invalid.conf | grep "invalid" | wc -c` +[ $ret -gt 0 ] || fail "expect throw out error message" +success "JSON file invalid" + +head "run web server (--config specific file)" +nohup $pg start --config pm2-gui-cp.conf > /dev/null 2>&1 & +pid=$! +sleep 1 +ret=`nc 127.0.0.1 27130 < /dev/null; echo $?` +[ $ret -eq 0 ] || fail "expect 127.0.0.1:27130 can be connected" +success "127.0.0.1:27130 should be connected" + +kill "$pid" +sleep 1 + +ret=`nc 127.0.0.1 27130 < /dev/null; echo $?` +[ $ret -eq 1 ] || fail "expect 127.0.0.1:27130 can not be connected" +success "127.0.0.1:27130 should be disconnected" + +val=`$pg config | grep "refresh:" | egrep -oh "\d+"` +[ $val -eq 3000 ] || fail "expect the value of refresh to be 3000, but current is $val" +success "the value of refresh should be 3000" +val=`$pg config | grep "manipulation:" | egrep -oh "(true|false)"` +[ $val = false ] || fail "expect the value of manipulation to be false, but current is $val" +success "the value of manipulation should be false" +val=`$pg config | grep "pm2:" | egrep -oh "/tmp/\.pm2$" | wc -c` +[ $val -gt 0 ] || fail "expect the value of pm2 to be /tmp/.pm2" +success "the value of pm2 should be /tmp/.pm2" + +head "run web server (--config default file)" +nohup $pg start --config > /dev/null 2>&1 & +pid=$! +sleep 1 +ret=`nc 127.0.0.1 8088 < /dev/null; echo $?` +[ $ret -eq 0 ] || fail "expect 127.0.0.1:8088 can be connected" +success "127.0.0.1:8088 should be connected" + +kill "$pid" +sleep 1 + +ret=`nc 127.0.0.1 8088 < /dev/null; echo $?` +[ $ret -eq 1 ] || fail "expect 127.0.0.1:8088 can not be connected" +success "127.0.0.1:8088 should be disconnected" + +val=`$pg config | grep "refresh:" | egrep -oh "\d+"` +[ $val -eq 5000 ] || fail "expect the value of refresh to be 5000, but current is $val" +success "the value of refresh should be 3000" +val=`$pg config | grep "manipulation:" | egrep -oh "(true|false)"` +[ $val = true ] || fail "expect the value of manipulation to be true, but current is $val" +success "the value of manipulation should be true" +root="~/.pm2" +if [ -z "$PM2_HOME" ] +then + root="$PM2_HOME" +else + if [ -z "$HOME" ] + then + root="$HOME/.pm2" + else + if [ -z "$HOMEPATH" ] + then + root="$HOMEPATH/.pm2" + fi + fi +fi +val=`$pg config | grep "pm2:" | egrep -oh "$root$" | wc -c` +[ $val -gt 0 ] || fail "expect the value of pm2 to be $root" +success "the value of pm2 should be $root" + +$pg set port 8088 > /dev/null \ No newline at end of file diff --git a/test/fixtures/colorful.js b/test/fixtures/colorful.js new file mode 100644 index 0000000..5aaa8d6 --- /dev/null +++ b/test/fixtures/colorful.js @@ -0,0 +1,14 @@ +var chalk = require('chalk'); + +console.log('This is', chalk.bold.red('red')); +console.log('This is', chalk.dim.green('green')); +console.log('This is', chalk.bold.green('green')); +console.log('This is', chalk.bold.italic.yellow('yellow')); +console.log('This is', chalk.bold.strikethrough.blue('blue')); +console.log('This is', chalk.bold.underline.magenta('magenta')); +console.log('This is', chalk.bold.cyan('cyan')); +console.log('This is', chalk.bold.grey('grey')); + +setTimeout(function(){ + +}, 3000000); \ No newline at end of file diff --git a/test/fixtures/exit.js b/test/fixtures/exit.js new file mode 100644 index 0000000..3e3afd3 --- /dev/null +++ b/test/fixtures/exit.js @@ -0,0 +1 @@ +console.log('ok at', Date.now()); \ No newline at end of file diff --git a/test/fixtures/fib-slow.js b/test/fixtures/fib-slow.js new file mode 100644 index 0000000..1b86182 --- /dev/null +++ b/test/fixtures/fib-slow.js @@ -0,0 +1,13 @@ +function fib(n){ + if (n == 1) return 1; + if (n == 0) return 0; + if (n > 1) return fib(n - 2) + fib(n - 1) +} + +function fi(){ + console.log('fibonacci...'); + var f = fib((parseInt(Math.random() * 10000) + 30) % 42); + console.log('is:', f); + setTimeout(fi, 1000); +} +fi(); diff --git a/test/fixtures/invalid.conf b/test/fixtures/invalid.conf new file mode 100644 index 0000000..77d5015 --- /dev/null +++ b/test/fixtures/invalid.conf @@ -0,0 +1,5 @@ +{ + "pm2": "/tmp/.pm2", + "refresh": 3000, + "manipulation": +} \ No newline at end of file diff --git a/test/fixtures/pm2-gui-cp.conf b/test/fixtures/pm2-gui-cp.conf new file mode 100644 index 0000000..fef69bb --- /dev/null +++ b/test/fixtures/pm2-gui-cp.conf @@ -0,0 +1,6 @@ +{ + "pm2": "/tmp/.pm2", + "refresh": 3000, + "manipulation": false, + "port": 27130 +} \ No newline at end of file diff --git a/test/fixtures/pm2-gui.json b/test/fixtures/pm2-gui.json new file mode 100644 index 0000000..84e35f3 --- /dev/null +++ b/test/fixtures/pm2-gui.json @@ -0,0 +1,6 @@ +{ + "pm2": "~/.pm2", + "refresh": 5000, + "manipulation": true, + "port": 8088 +} \ No newline at end of file diff --git a/test/fixtures/rand.js b/test/fixtures/rand.js new file mode 100644 index 0000000..fe9081b --- /dev/null +++ b/test/fixtures/rand.js @@ -0,0 +1,3 @@ +setInterval(function(){ + console.log(Math.random()); +}, 3000); \ No newline at end of file diff --git a/test/fixtures/throw.js b/test/fixtures/throw.js new file mode 100644 index 0000000..4149452 --- /dev/null +++ b/test/fixtures/throw.js @@ -0,0 +1,4 @@ +console.log('App started.'); +setTimeout(function(){ + throw new Error('uncaughtException has been thrown.'); +}, 15000); \ No newline at end of file diff --git a/test/fixtures/tick.js b/test/fixtures/tick.js new file mode 100644 index 0000000..9c3f4a8 --- /dev/null +++ b/test/fixtures/tick.js @@ -0,0 +1,4 @@ +var chalk = require('chalk'); +setInterval(function(){ + console.log(chalk.bold.green('Tick'), Date.now()); +}, 1000); \ No newline at end of file diff --git a/test/fixtures/tock.js b/test/fixtures/tock.js new file mode 100644 index 0000000..025b26f --- /dev/null +++ b/test/fixtures/tock.js @@ -0,0 +1,6 @@ +var chalk = require('chalk'); + +console.log(chalk.magenta('Tock every 5 seconds.')); +setInterval(function(){ + console.log(chalk.bold.red.underline('Tock'), Date.now()); +}, 5000); \ No newline at end of file diff --git a/test/index.sh b/test/index.sh new file mode 100644 index 0000000..52e9da5 --- /dev/null +++ b/test/index.sh @@ -0,0 +1,16 @@ +#!/usr/bin/env bash + +SRC=$(cd $(dirname "$0"); pwd) +source "${SRC}/bash/include.sh" + +set -e + +echo -e "\x1B[1m############ TEST SUITE ############\x1B[0m" +echo -e "\x1B[1mpm2-gui Command = $pg\x1B[0m" +echo -e "\x1B[1mNode version = $nodeVersion\x1B[0m" +$node -e "var os = require('os'); console.log('\x1B[1march : %s\nplatform : %s\nrelease : %s\ntype : %s\nmem : %d\x1B[0m', os.arch(), os.platform(), os.release(), os.type(), os.totalmem())" +echo -e "\x1B[1m############# FINISHED #############\x1B[0m" +echo -e "" + +bash ./test/bash/config.sh +bash ./test/bash/interface.sh From 8e57e5667e9450e360102263e9bcbbe3a16f6cf3 Mon Sep 17 00:00:00 2001 From: Tjatse Date: Wed, 31 Dec 2014 18:13:18 +0800 Subject: [PATCH 8/9] read port from config now --- web/index.js | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/web/index.js b/web/index.js index 670ee7b..b5ff82c 100644 --- a/web/index.js +++ b/web/index.js @@ -8,7 +8,7 @@ var express = require('express'), module.exports = runServer; -function runServer(port, debug){ +function runServer(debug){ var app = express(); // all environments @@ -26,19 +26,16 @@ function runServer(port, debug){ // router require('../lib/util/router')(app, log); - if (!port || isNaN(port)) { - port = 8088; - } - var server = require('http').Server(app); var io = require('socket.io')(server); - server.listen(port); - log.i('http', 'Web server of', chalk.bold.underline('Unitech/PM2'), 'is listening on port', chalk.bold(port)); var mon = Monitor({ sockio: io, debug : !!debug }); + var port = mon.config('port'); + server.listen(port); + log.i('http', 'Web server of', chalk.bold.underline('Unitech/PM2'), 'is listening on port', chalk.bold(port)); mon.run(); } \ No newline at end of file From 45d6317e2591d190ab838633d18ec9fa35fab859 Mon Sep 17 00:00:00 2001 From: Tjatse Date: Wed, 31 Dec 2014 18:21:26 +0800 Subject: [PATCH 9/9] config docs --- README.md | 31 ++++++++++++------------------- 1 file changed, 12 insertions(+), 19 deletions(-) diff --git a/README.md b/README.md index 2d8c885..ae88d82 100644 --- a/README.md +++ b/README.md @@ -1,9 +1,9 @@ -pm2-gui [![NPM version](https://badge.fury.io/js/pm2-gui.svg)](http://badge.fury.io/js/pm2-gui) +pm2-gui [![NPM version](https://badge.fury.io/js/pm2-gui.svg)](http://badge.fury.io/js/pm2-gui) [![Build Status](https://travis-ci.org/Tjatse/pm2-gui.svg?branch=master)](https://travis-ci.org/Tjatse/pm2-gui) ======= An elegant web interface for Unitech/PM2. -> Compatible with PM2 v0.12.2. +> Compatible with PM2 v0.12.3. # Guide - [Features](#feats) @@ -14,7 +14,6 @@ An elegant web interface for Unitech/PM2. - [Configs](#cli_confs) - [Authorization](#auth) - [UI/UX](#ui) -- [TODO](#todo) # Feature @@ -74,7 +73,8 @@ $ npm install -g pm2-gui Options: - -h, --help output usage information + -h, --help output usage information + --config [file] pass JSON config file with options --no-debug hide stdout/stderr information --config path to custom .json config. Default value pm2-gui.json ``` @@ -91,20 +91,22 @@ $ npm install -g pm2-gui ``` - **refresh** The heartbeat duration of monitor (backend), `5000` by default. -- **manupulation** A value indicates whether the client has permission to restart/stop processes, `true` by default. +- **manipulation** A value indicates whether the client has permission to restart/stop processes, `true` by default. - **pm2** Root directory of Unitech/PM2, `~/.pm2` by default. -- **password** The encrypted authentication code, if this config is set, users need to be authorized before accessing the index page. +- **password** The encrypted authentication code, if this config is set, users need to be authorized before accessing the index page, `password` could only be set by `pm2-gui set password [password]`. - **port** Web GUI port, can be set only from config file ### Config file -Config file can be set with option --config +You can quit set configurations by `pm2-gui start --config [file]`, the `[file]` must be an valid JSON, and can including all the above keys. Example ```bash -$ pm2-gui start --config pm2-gui.json -``` +# Load the JSON configured file which is named as `pm2-gui.json` in current directory. +$ pm2-gui start --config -If config name pm2-gui.json - option can be omitted +# Load the specific JSON configured file in current directory. +$ pm2-gui start --config conf.json +``` ### Set Config Usage @@ -181,15 +183,6 @@ Tail Logs ![image](screenshots/tail-logs.jpg) - -# TODO -- [x] Authentication -- [ ] Multiple operations. -- [ ] Configured JSON files. -- [ ] Memory and CPU usage gauge of each process. -- [ ] Test on Internet Explorer (need environment && PRs). -- [ ] Need feedback/test. - ## License Licensed under the Apache License, Version 2.0 (the "License");