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/.gitignore b/.gitignore
index 31e1bf66..e6576745 100644
--- a/.gitignore
+++ b/.gitignore
@@ -15,3 +15,5 @@ package-lock.json
*.swp
*.swo
currentTagChangelog.md
+joblog-X
+test/fixtures/path-check*.txt
diff --git a/.travis.yml b/.travis.yml
index 1425f6b0..0c217f31 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -4,14 +4,16 @@ node_js:
- "4"
- "6"
- "8"
- - "0.12"
+git:
+ depth: 5
os:
- linux
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
-notifications:
- slack: pm2-nodejs:5Lolyw2LMnwy8fziqOGILQxG
+install:
+ - npm install
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/CHANGELOG.md b/CHANGELOG.md
index fbd96fd2..fcb607ed 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,312 @@
+## 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))
+ - 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
+ - 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) )
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
diff --git a/README.md b/README.md
index 6bee4318..f0a6a68b 100644
--- a/README.md
+++ b/README.md
@@ -17,7 +17,7 @@
-
+
@@ -234,14 +234,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
@@ -294,7 +294,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..002657e7 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';
@@ -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')
@@ -90,38 +90,50 @@ commander.version(pkg.version)
.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 [options] ')
+ console.log('');
+ 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('');
+ console.log('Access pm2 files in ~/.pm2');
+ }
+
+ function displayExamples() {
+ console.log('- Start and add a process to the pm2 process list:')
+ console.log('');
+ console.log(chalk.cyan(' $ pm2 start app.js --name app'));
+ console.log('');
+ console.log('- Show the process list:');
+ console.log('');
+ console.log(chalk.cyan(' $ pm2 ls'));
+ console.log('');
+ console.log('- Stop and delete a process from the pm2 process list:');
+ console.log('');
+ console.log(chalk.cyan(' $ pm2 delete app'));
+ console.log('');
+ console.log('- Stop, start and restart a process from the process list:');
+ console.log('');
+ 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('');
+ 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:')
+ console.log('');
+ console.log(chalk.cyan(' $ pm2 completion install'))
+ console.log('');
+ console.log('Check the full documentation on https://pm2.io/doc');
+ console.log('');
+ }
if (process.argv.indexOf('-s') > -1) {
for(var key in console){
@@ -155,7 +167,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){
@@ -253,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)')
@@ -280,6 +292,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) {
@@ -329,7 +344,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);
@@ -390,25 +405,24 @@ 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) {
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
//
commander.command('delete ')
+ .alias('del')
.description('stop and delete a process from pm2 process list')
.action(function(name) {
if (name == "-") {
@@ -464,11 +478,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;
@@ -553,41 +567,42 @@ 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')
+ .option('--ws', 'websocket mode')
+ .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();
});
@@ -612,6 +627,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
//
@@ -645,7 +669,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);
});
@@ -654,7 +678,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);
});
@@ -891,15 +915,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
//
@@ -914,18 +929,27 @@ 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')
+ .description('display pm2 usage examples')
+ .action(() => {
+ console.log(cst.PREFIX_MSG + chalk.grey('pm2 usage examples:\n'));
+ displayExamples();
+ 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 + 'Command not found\n');
+ displayUsage();
// Check if it does not forget to close fds from RPC
process.exit(cst.ERROR_EXIT);
});
@@ -935,7 +959,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);
}
diff --git a/constants.js b/constants.js
index c86f8772..127f5764 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
@@ -28,7 +27,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',
@@ -55,7 +54,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',
@@ -74,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;
})(),
@@ -91,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/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/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');
diff --git a/lib/API.js b/lib/API.js
index 59bc227f..fa147e6b 100644
--- a/lib/API.js
+++ b/lib/API.js
@@ -3,20 +3,21 @@
* Use of this source code is governed by a license that
* can be found in the LICENSE file.
*/
+'use strict';
-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');
var Common = require('./Common');
-var KMDaemon = require('./Interactor/InteractorDaemonizer');
+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');
@@ -41,89 +42,1605 @@ 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
*/
-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 = 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
+ */
+ 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
+ const 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;
+ });
+
+ this.gl_retry = 0;
}
/**
- * PM2 HOME resolution
+ * Connect to PM2
+ * Calling this command is now optional
+ *
+ * @param {Function} cb callback once pm2 is ready for commands
*/
- if (opts.pm2_home && opts.independent == true)
- throw new Error('You cannot set a pm2_home and independent instance in same time');
+ connect (noDaemon, cb) {
+ var that = this;
+ this.start_timer = new Date();
- 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')
+ 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;
- conf = util._extend(conf, path_structure(this.pm2_home));
+ }
+
+ 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);
+ });
+ });
}
- this._conf = conf;
+ /**
+ * 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;
- 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);
+ 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'));
+
+ 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);
+ });
+ });
}
- 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
- });
+ /**
+ * 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;
- this.gl_interact_infos = null;
- this.gl_is_km_linked = false;
+ if (!cb) cb = function() {};
- 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;
+ this.Client.close(function(err, data) {
+ debug('The session lasted %ds', (new Date() - that.start_timer) / 1000);
+ return cb(err, data);
+ });
+ };
+
+ /**
+ * Alias on disconnect
+ * @param cb
+ */
+ close (cb) {
+ this.disconnect(cb);
}
- // For testing purposes
- if (this.secret_key && process.env.NODE_ENV == 'local_test')
- that.gl_is_km_linked = true;
+ /**
+ * Launch modules
+ *
+ * @param {Function} cb callback once pm2 has launched modules
+ */
+ launchModules (cb) {
+ Modularizer.launchAll(this, cb);
+ }
- KMDaemon.getInteractInfo(this._conf, function(i_err, interact) {
- that.gl_interact_infos = interact;
- });
+ /**
+ * 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 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());
+ }
+
+ 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;
+ }
+
+ /**
+ * 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(null, list);
+ });
+ }
+
+ /**
+ * 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);
+ });
+ });
+ });
+ });
+ }
+
+ kill (cb) {
+ this.killDaemon(cb);
+ }
+
+ /////////////////////
+ // 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';
+
+ 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];
+
+ /**
+ * 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 = path.isAbsolute(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) {
+ if (!app.env) { app.env = {}; }
+ app.env.io = app.io;
+ // --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, 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;
+
+ if (list) {
+ return doList(null, list)
+ }
+
+ that.Client.executeRemote('getMonitorData', {}, doList);
+
+ function doList(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('%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),
+ that.gl_interact_infos.transporters);
+ }
+ 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);
+ });
+ }
};
@@ -135,1553 +1652,12 @@ 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);
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;
diff --git a/lib/API/Configuration.js b/lib/API/Configuration.js
index 01b4439a..321a295e 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');
@@ -7,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('@pm2/agent/src/InteractorClient');
module.exports = function(CLI) {
@@ -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/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/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/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/Extra.js b/lib/API/Extra.js
index 00f445dd..bca1da25 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) {
@@ -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`');
@@ -639,4 +639,27 @@ 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 && 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(`Unable to activate inspect mode on ${app_name} !!!`);
+ }
+
+ 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/API/Interaction.js b/lib/API/Interaction.js
index 1bde2cd7..621dbf27 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('@pm2/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);
@@ -74,20 +76,20 @@ 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') {
- 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);
@@ -104,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;
@@ -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);
@@ -129,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);
}
@@ -143,9 +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);
diff --git a/lib/API/Keymetrics/cli-api.js b/lib/API/Keymetrics/cli-api.js
deleted file mode 100644
index 3ad3ea03..00000000
--- a/lib/API/Keymetrics/cli-api.js
+++ /dev/null
@@ -1,248 +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('../../Interactor/InteractorDaemonizer');
-var KM = require('./kmapi.js');
-var Table = require('cli-table-redemption');
-var open = require('../../tools/open.js');
-var promptly = require('promptly');
-
-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.keymetrics.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 Keymetrics.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
- }, function(err, dt) {
- open('https://app.keymetrics.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) {
- console.log(chalk.bold('Log in to Keymetrics'));
- (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 to Keymetrics Bucket [%s]', target_bucket.name);
-
- KMDaemon.launchAndInteract(cst, {
- public_key : target_bucket.public_id,
- secret_key : target_bucket.secret_id
- }, 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() {
- console.log(chalk.bold('Now registering to Keymetrics'));
- 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 Keymetrics..'));
- 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 af5d91f8..00000000
--- a/lib/API/Keymetrics/kmapi.js
+++ /dev/null
@@ -1,162 +0,0 @@
-var querystring = require('querystring');
-var https = require('https');
-var fs = require('fs');
-var needle = require('needle');
-var url = require('url');
-var cst = require('../../../constants.js');
-
-var KM = function() {
- 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 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.BASE_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, {
- cookies : cookie
- }, function(err, resp, body) {
- if (err) return cb(err);
- if (body.indexOf('/api/oauth/login') > -1) return cb('Wrong credentials');
-
- var location = resp.headers.location;
- var redirect = that.BASE_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.BASE_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/Keymetrics/motd b/lib/API/Keymetrics/motd
deleted file mode 100644
index 26b30058..00000000
--- a/lib/API/Keymetrics/motd
+++ /dev/null
@@ -1,8 +0,0 @@
- __ __ __ _
- / //_/__ __ ______ ___ ___ / /______(_)_________
- / ,< / _ \/ / / / __ `__ \/ _ \/ __/ ___/ / ___/ ___/
- / /| / __/ /_/ / / / / / / __/ /_/ / / / /__(__ )
-/_/ |_\___/\__, /_/ /_/ /_/\___/\__/_/ /_/\___/____/
- /____/
-
- Harden your Node.js application, today
diff --git a/lib/API/Modules/Modularizer.js b/lib/API/Modules/Modularizer.js
index 7093324b..b8b88e1e 100644
--- a/lib/API/Modules/Modularizer.js
+++ b/lib/API/Modules/Modularizer.js
@@ -3,9 +3,9 @@
* 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');
var async = require('async');
var p = path;
var readline = require('readline');
@@ -17,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';
@@ -47,7 +46,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;
@@ -184,8 +183,8 @@ 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() {
- process.chdir(process.env.HOME);
+ 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 ], {
stdio : 'inherit',
@@ -404,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);
@@ -435,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, 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');
@@ -455,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);
}
}
@@ -520,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);
@@ -549,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/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;
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/PM2/motd b/lib/API/PM2/motd
new file mode 100644
index 00000000..9d44fc76
--- /dev/null
+++ b/lib/API/PM2/motd
@@ -0,0 +1,13 @@
+
+ 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/Serve.js b/lib/API/Serve.js
index d4707ade..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('pmx').probe();
+var probe = require('@pm2/io').probe();
/**
* list of supported content types.
diff --git a/lib/API/Startup.js b/lib/API/Startup.js
index 7810dc82..8916e037 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) {
/**
@@ -42,12 +41,13 @@ 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);
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;
}
}
@@ -148,9 +148,19 @@ 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;
};
- 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) {
@@ -222,21 +232,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':
@@ -283,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;
@@ -326,7 +335,7 @@ module.exports = function(CLI) {
async.forEachLimit(commands, 1, function(command, next) {
Common.printOut(cst.PREFIX_MSG + '[-] Executing: %s...', chalk.bold(command));
- shelljs.exec(command, function(code, stdout, stderr) {
+ require('shelljs').exec(command, function(code, stdout, stderr) {
if (code === 0) {
Common.printOut(cst.PREFIX_MSG + chalk.bold('[v] Command successfully executed.'));
return next();
@@ -380,13 +389,32 @@ module.exports = function(CLI) {
* @return
*/
function fin(err) {
+
+ // 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) {
+ 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.writeFileSync(cst.DUMP_BACKUP_FILE_PATH, fs.readFileSync(cst.DUMP_FILE_PATH));
}
} catch (e) {
console.error(e.stack || e);
@@ -399,8 +427,13 @@ module.exports = function(CLI) {
} catch (e) {
console.error(e.stack || e);
try {
- fs.unlinkSync(cst.DUMP_FILE_PATH);
+ // try to backup file
+ 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
+ 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);
@@ -424,6 +457,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/API/Version.js b/lib/API/Version.js
index 8f5bb93b..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;
@@ -21,11 +20,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];
@@ -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) {
@@ -82,19 +81,19 @@ 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];
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) {
@@ -138,20 +137,22 @@ 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)
return cb({msg : 'Versioning unknown'});
- vizion.prev({
+ require('vizion').prev({
folder: proc.pm2_env.versioning.repo_path
}, function(err, meta) {
if (err)
@@ -165,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);
});
@@ -194,16 +195,18 @@ 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) {
+ 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) {
@@ -211,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);
});
@@ -366,16 +369,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/API/schema.json b/lib/API/schema.json
index d650a73d..94ef70e0 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": ["interpreterArgs", "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,43 +185,51 @@
"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"
- },
- "disable_trace": {
- "type": [
- "boolean"
- ]
+ "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": [
@@ -208,14 +247,66 @@
]
},
"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"
+ },
+ "username" : {
+ "type": "string",
+ "docDescription": "Current user that started the process"
+ },
+ "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
+ },
+ "kill_retry_time": {
+ "type": "number",
+ "default" : 100
+ },
+ "write": {
+ "type": "boolean"
+ },
+ "io": {
+ "type": "object",
+ "docDescription": "Specify apm values and configuration"
}
}
diff --git a/lib/Client.js b/lib/Client.js
index 74103fd3..6edb18f7 100644
--- a/lib/Client.js
+++ b/lib/Client.js
@@ -6,15 +6,14 @@
var debug = require('debug')('pm2:client');
var Common = require('./Common.js');
-var KMDaemon = require('./Interactor/InteractorDaemonizer.js');
+var KMDaemon = require('@pm2/agent/src/InteractorClient');
var rpc = require('pm2-axon-rpc');
var async = require('async');
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() {}
@@ -79,7 +78,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;
});
@@ -129,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);
}
@@ -137,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);
}
@@ -153,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);
}
@@ -241,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, {
@@ -278,7 +278,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);
@@ -717,3 +718,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);
+ });
+};
diff --git a/lib/Common.js b/lib/Common.js
index 2dd053aa..35b13389 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('./Interactor/InteractorDaemonizer.js');
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');
@@ -247,20 +244,22 @@ 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;
};
/**
- * 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
@@ -288,7 +287,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);
@@ -366,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)'),
@@ -409,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;
@@ -585,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) {
@@ -597,25 +621,34 @@ 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);
+ if (app.exec_mode != 'cluster_mode' &&
+ !app.instances && typeof(app.merge_logs) == 'undefined')
+ app.merge_logs = true;
+
// Render an app name if not existing.
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);
@@ -689,18 +722,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/lib/Daemon.js b/lib/Daemon.js
index 22f5fc7d..95eee01b 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.js b/lib/God.js
index dc001997..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');
@@ -291,9 +290,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 ||
@@ -384,6 +380,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 65cb6415..808170b6 100644
--- a/lib/God/ActionMethods.js
+++ b/lib/God/ActionMethods.js
@@ -40,55 +40,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: Math.round(stat.cpu * 10) / 10
+ };
+
+ return pro;
+ });
+
+ cb(null, processes);
+ });
};
/**
@@ -126,6 +134,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`.
@@ -137,13 +146,25 @@ module.exports = function(God) {
}
function fin(err) {
+
+ // 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});
+ }
+
// 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.writeFileSync(cst.DUMP_BACKUP_FILE_PATH, fs.readFileSync(cst.DUMP_FILE_PATH));
}
} catch (e) {
console.error(e.stack || e);
@@ -155,8 +176,13 @@ module.exports = function(God) {
} catch (e) {
console.error(e.stack || e);
try {
- fs.unlinkSync(cst.DUMP_FILE_PATH);
+ // try to backup file
+ if(fs.existsSync(cst.DUMP_BACKUP_FILE_PATH)) {
+ fsExtra.copySync(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);
}
}
@@ -213,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) {
@@ -264,17 +295,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;
@@ -286,7 +319,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);
@@ -823,3 +855,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/lib/God/Methods.js b/lib/God/Methods.js
index e7b8e9fa..60fc31be 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);
@@ -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/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/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 a6de7c61..00000000
--- a/lib/Interactor/RemoteActions/Pm2Actions.js
+++ /dev/null
@@ -1,345 +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');
-var Password = require('../Password.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' : { password_required : true },
- 'uninstall' : { password_required : true },
- 'stop' : { password_required : true },
- 'delete' : { password_required : true },
- 'set' : {},
- 'multiset' : {},
- 'deepUpdate' : { password_required : true },
-
- 'pullAndRestart' : { password_optional : true },
- 'forward' : { password_optional : true },
- 'backward' : { password_optional : true },
-
- 'startLogging' : {},
- 'stopLogging' : {},
-
- 'resetTransactionCache': {},
- 'resetFileCache': {},
-
- // This is just for testing purproses
- 'ping' : { password_required : true }
-};
-
-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];
-
- /**
- * 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;
-
- /**
- * 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/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 6d1b0ceb..59c45d3f 100644
--- a/lib/ProcessContainerFork.js
+++ b/lib/ProcessContainerFork.js
@@ -1,18 +1,10 @@
-/**
+ /**
* 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({
- 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();
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..4dad2196
--- /dev/null
+++ b/lib/ProcessUtils.js
@@ -0,0 +1,43 @@
+'use strict'
+
+module.exports = {
+ injectModules: function() {
+ if (process.env.pmx !== 'false') {
+ const pmx = require('@pm2/io');
+
+ 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
+ };
+
+ const mergedConf = Object.assign(defaultConf, conf);
+
+ pmx.init(mergedConf);
+
+ 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);
+ });
+ }
+ }
+ }
+};
diff --git a/lib/Satan.js b/lib/Satan.js
index e6df06ba..a6c77c26 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,
@@ -329,7 +328,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('@pm2/agent/src/InteractorClient');
var node_args = [];
@@ -385,7 +384,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/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/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
});
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
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'
- }
}
}
};
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
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){
diff --git a/package.json b/package.json
index 0a27c968..526aa66b 100644
--- a/package.json
+++ b/package.json
@@ -1,9 +1,9 @@
{
"name": "pm2",
"preferGlobal": true,
- "version": "2.10.4",
+ "version": "3.0.0",
"engines": {
- "node": ">=0.12"
+ "node": ">=4.0.0"
},
"directories": {
"bin": "./bin",
@@ -12,25 +12,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": [
@@ -91,8 +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",
- "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",
@@ -159,38 +158,41 @@
"pm2-runtime": "./bin/pm2-runtime"
},
"dependencies": {
- "async": "^2.5",
+ "@pm2/agent": "^0.5.4",
+ "@pm2/io": "^2.0.2",
+ "@pm2/js-api": "^0.5.15",
+ "async": "^2.6.1",
"blessed": "^0.1.81",
- "chalk": "^1.1",
- "chokidar": "^2",
+ "chalk": "^2.4.1",
+ "chokidar": "^2.0.4",
"cli-table-redemption": "^1.0.0",
- "commander": "2.13.0",
+ "coffee-script": "^1.12.7",
+ "commander": "2.15.1",
"cron": "^1.3",
- "debug": "^3.0",
- "eventemitter2": "1.0.5",
+ "debug": "^3.1",
+ "eventemitter2": "5.0.1",
"fclone": "1.0.11",
"mkdirp": "0.5.1",
- "moment": "^2.19",
- "needle": "^2.1.0",
+ "moment": "^2.22.2",
+ "needle": "^2.2.1",
"nssocket": "0.6.0",
- "pidusage": "^1.2.0",
- "pm2-axon": "3.1.0",
+ "pidusage": "^2.0.6",
+ "pm2-axon": "3.3.0",
"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.7.8",
- "source-map-support": "^0.5",
+ "promptly": "3.0.3",
+ "semver": "^5.5",
+ "shelljs": "~0.8.2",
+ "source-map-support": "^0.5.6",
"sprintf-js": "1.1.1",
- "v8-compile-cache": "^1.1.0",
- "vizion": "^0.2",
+ "v8-compile-cache": "^2.0.0",
+ "vizion": "~0.2.0",
"yamljs": "^0.3.0"
},
"devDependencies": {
- "mocha": "^3.5",
- "should": "^11"
+ "mocha": "^5.2.0",
+ "should": "^13"
},
"optionalDependencies": {
"gkt": "https://tgz.pm2.io/gkt-1.0.0.tgz"
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'),
diff --git a/test/Dockerfile b/test/Dockerfile
index 4c5cd64f..70a27f30 100644
--- a/test/Dockerfile
+++ b/test/Dockerfile
@@ -1,9 +1,14 @@
-FROM node:9
+FROM node:alpine
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 python 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/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/file-descriptor.sh b/test/bash/file-descriptor.sh
deleted file mode 100644
index 1d3aa419..00000000
--- a/test/bash/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/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/interact.sh b/test/bash/interact.sh
deleted file mode 100644
index 1fc1049c..00000000
--- a/test/bash/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/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/docker_parallel_test.sh b/test/docker_parallel_test.sh
index 4b2b73a4..b46304bc 100644
--- a/test/docker_parallel_test.sh
+++ b/test/docker_parallel_test.sh
@@ -1,3 +1,10 @@
-# 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=2
+OPTS="--jobs $JOBS --joblog joblog-X docker run -v `pwd`:/var/pm2 pm2-test"
+
+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..1b73924a
--- /dev/null
+++ b/test/e2e.sh
@@ -0,0 +1,144 @@
+#!/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/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
+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"
+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/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/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/e2e/misc/inside-pm2.sh
+spec "Starting a process inside a PM2 process"
+bash ./test/e2e/misc/vizion.sh
+spec "vizion features (versioning control)"
+bash ./test/e2e/misc/misc.sh
+spec "MISC features"
+bash ./test/e2e/misc/versioning-cmd.sh
+spec "versioning system tests"
+bash ./test/e2e/misc/instance-number.sh
+spec "Negative instance number spawn one worker"
+bash ./test/e2e/misc/startup.sh
+spec "upstart startup test"
+bash ./test/e2e/misc/nvm-node-version.sh
+spec "NVM node version setting"
+bash ./test/e2e/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/bash/pm2-dev.sh b/test/e2e/binaries/pm2-dev.sh
similarity index 72%
rename from test/bash/pm2-dev.sh
rename to test/e2e/binaries/pm2-dev.sh
index 748dc7b7..6839550d 100644
--- a/test/bash/pm2-dev.sh
+++ b/test/e2e/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/e2e/binaries/pm2-runtime.sh
similarity index 80%
rename from test/bash/pm2-runtime.sh
rename to test/e2e/binaries/pm2-runtime.sh
index da29b919..8cfe8c38 100644
--- a/test/bash/pm2-runtime.sh
+++ b/test/e2e/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/app-configuration.sh b/test/e2e/cli/app-configuration.sh
similarity index 84%
rename from test/bash/app-configuration.sh
rename to test/e2e/cli/app-configuration.sh
index ab741c98..35c8a74f 100644
--- a/test/bash/app-configuration.sh
+++ b/test/e2e/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"
@@ -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 2
-
-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
diff --git a/test/bash/args.sh b/test/e2e/cli/args.sh
similarity index 97%
rename from test/bash/args.sh
rename to test/e2e/cli/args.sh
index 0bfce30a..01a0529c 100644
--- a/test/bash/args.sh
+++ b/test/e2e/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/e2e/cli/attach.sh
similarity index 91%
rename from test/bash/attach.sh
rename to test/e2e/cli/attach.sh
index fed9ac70..4a32e147 100644
--- a/test/bash/attach.sh
+++ b/test/e2e/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/e2e/cli/binary.sh
similarity index 96%
rename from test/bash/binary.sh
rename to test/e2e/cli/binary.sh
index 13054c4f..e970a8ec 100644
--- a/test/bash/binary.sh
+++ b/test/e2e/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/e2e/cli/cli-actions-1.sh
similarity index 99%
rename from test/bash/cli-actions-1.sh
rename to test/e2e/cli/cli-actions-1.sh
index 8d393f52..1cbe7697 100644
--- a/test/bash/cli-actions-1.sh
+++ b/test/e2e/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/e2e/cli/cli-actions-2.sh
similarity index 95%
rename from test/bash/cli-actions-2.sh
rename to test/e2e/cli/cli-actions-2.sh
index 02b50fc5..46ef2c49 100644
--- a/test/bash/cli-actions-2.sh
+++ b/test/e2e/cli/cli-actions-2.sh
@@ -1,11 +1,11 @@
#!/usr/bin/env bash
SRC=$(cd $(dirname "$0"); pwd)
-source "${SRC}/include.sh"
+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/bash/dump.sh b/test/e2e/cli/dump.sh
similarity index 94%
rename from test/bash/dump.sh
rename to test/e2e/cli/dump.sh
index 3f9a9973..62ed1a58 100644
--- a/test/bash/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
diff --git a/test/bash/env-refresh.sh b/test/e2e/cli/env-refresh.sh
similarity index 98%
rename from test/bash/env-refresh.sh
rename to test/e2e/cli/env-refresh.sh
index b49c6bf8..418c9e2f 100644
--- a/test/bash/env-refresh.sh
+++ b/test/e2e/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/e2e/cli/extra-lang.sh
similarity index 97%
rename from test/bash/extra-lang.sh
rename to test/e2e/cli/extra-lang.sh
index e3f22eb1..8761cd34 100644
--- a/test/bash/extra-lang.sh
+++ b/test/e2e/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/e2e/cli/fork.sh
similarity index 95%
rename from test/bash/fork.sh
rename to test/e2e/cli/fork.sh
index e6091ce4..f641d23e 100644
--- a/test/bash/fork.sh
+++ b/test/e2e/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/e2e/cli/harmony.sh
similarity index 96%
rename from test/bash/harmony.sh
rename to test/e2e/cli/harmony.sh
index 03094ea0..bba81985 100644
--- a/test/bash/harmony.sh
+++ b/test/e2e/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/e2e/cli/interpreter.sh
similarity index 60%
rename from test/bash/interpreter.sh
rename to test/e2e/cli/interpreter.sh
index 3257e85c..e7379c29 100644
--- a/test/bash/interpreter.sh
+++ b/test/e2e/cli/interpreter.sh
@@ -1,12 +1,13 @@
#!/usr/bin/env bash
SRC=$(cd $(dirname "$0"); pwd)
-source "${SRC}/include.sh"
+source "${SRC}/../include.sh"
cd $file_path/interpreter
rm -rf ../../../node_modules/coffee-script/
rm -rf ../../../node_modules/livescript/
+rm -rf ../../../node_modules/ts-node/
########### coffee
@@ -41,49 +42,45 @@ 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
-$pm2 delete all
-$pm2 start echo.ts
-sleep 1
-should 'process should be errored without typescript installed' "status: 'errored'" 1
-
########### Install
+
# $pm2 install typescript
-########### typescript fork test
+# ########### typescript fork test
# $pm2 delete all
# >typescript.log
@@ -95,7 +92,7 @@ should 'process should be errored without typescript installed' "status: 'errore
# grep "Hello Typescript!" typescript.log
# spec "Should work on Typescript files in fork mode"
-########### typescript cluster test
+# ########### typescript cluster test
# $pm2 delete all
# >typescript.log
diff --git a/test/bash/mjs.sh b/test/e2e/cli/mjs.sh
similarity index 95%
rename from test/bash/mjs.sh
rename to test/e2e/cli/mjs.sh
index 817ea2dd..662ef43c 100644
--- a/test/bash/mjs.sh
+++ b/test/e2e/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/e2e/cli/monit.sh
similarity index 95%
rename from test/bash/monit.sh
rename to test/e2e/cli/monit.sh
index 668a46cd..14cf954d 100644
--- a/test/bash/monit.sh
+++ b/test/e2e/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/e2e/cli/multiparam.sh
similarity index 94%
rename from test/bash/multiparam.sh
rename to test/e2e/cli/multiparam.sh
index c71212e5..c3207862 100644
--- a/test/bash/multiparam.sh
+++ b/test/e2e/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/e2e/cli/operate-regex.sh
similarity index 94%
rename from test/bash/operate-regex.sh
rename to test/e2e/cli/operate-regex.sh
index 86e59fa8..d2e0fd92 100644
--- a/test/bash/operate-regex.sh
+++ b/test/e2e/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/e2e/cli/piped-config.sh
similarity index 90%
rename from test/bash/piped-config.sh
rename to test/e2e/cli/piped-config.sh
index 416cec35..83fa2725 100644
--- a/test/bash/piped-config.sh
+++ b/test/e2e/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/reload.sh b/test/e2e/cli/reload.sh
similarity index 80%
rename from test/bash/reload.sh
rename to test/e2e/cli/reload.sh
index d659a1b6..a7248427 100644
--- a/test/bash/reload.sh
+++ b/test/e2e/cli/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
@@ -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/bash/reset.sh b/test/e2e/cli/reset.sh
similarity index 96%
rename from test/bash/reset.sh
rename to test/e2e/cli/reset.sh
index a8f425bf..1a192f47 100644
--- a/test/bash/reset.sh
+++ b/test/e2e/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/e2e/cli/resurrect.sh
similarity index 95%
rename from test/bash/resurrect.sh
rename to test/e2e/cli/resurrect.sh
index b37abf58..ff83b513 100644
--- a/test/bash/resurrect.sh
+++ b/test/e2e/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/e2e/cli/right-exit-code.sh
similarity index 93%
rename from test/bash/right-exit-code.sh
rename to test/e2e/cli/right-exit-code.sh
index 38ec3c13..3f5e99a1 100644
--- a/test/bash/right-exit-code.sh
+++ b/test/e2e/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/e2e/cli/serve.sh
similarity index 69%
rename from test/bash/serve.sh
rename to test/e2e/cli/serve.sh
index 8989efda..e4179af0 100644
--- a/test/bash/serve.sh
+++ b/test/e2e/cli/serve.sh
@@ -1,21 +1,22 @@
#!/usr/bin/env bash
SRC=$(cd $(dirname "$0"); pwd)
-source "${SRC}/include.sh"
+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"
@@ -67,4 +68,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/e2e/cli/smart-start.sh
similarity index 96%
rename from test/bash/smart-start.sh
rename to test/e2e/cli/smart-start.sh
index a09513f1..70880b6b 100644
--- a/test/bash/smart-start.sh
+++ b/test/e2e/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/e2e/cli/sort.sh
similarity index 97%
rename from test/bash/sort.sh
rename to test/e2e/cli/sort.sh
index 995a49cb..bac3f8ba 100644
--- a/test/bash/sort.sh
+++ b/test/e2e/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/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/bash/startOrX.sh b/test/e2e/cli/startOrX.sh
similarity index 93%
rename from test/bash/startOrX.sh
rename to test/e2e/cli/startOrX.sh
index dd714e3d..ef985cba 100644
--- a/test/bash/startOrX.sh
+++ b/test/e2e/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/e2e/cli/watch.sh
similarity index 98%
rename from test/bash/watch.sh
rename to test/e2e/cli/watch.sh
index a47ec8a2..4a42c229 100644
--- a/test/bash/watch.sh
+++ b/test/e2e/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/docker.sh b/test/e2e/docker.sh
similarity index 98%
rename from test/bash/docker.sh
rename to test/e2e/docker.sh
index dcbeed6d..09174b73 100644
--- a/test/bash/docker.sh
+++ b/test/e2e/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/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/bash/include.sh b/test/e2e/include.sh
similarity index 71%
rename from test/bash/include.sh
rename to test/e2e/include.sh
index 1abf9199..af6f9f79 100644
--- a/test/bash/include.sh
+++ b/test/e2e/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/e2e/internals/daemon-paths-override.sh
similarity index 63%
rename from test/bash/daemon-paths-override.sh
rename to test/e2e/internals/daemon-paths-override.sh
index 31b65b2d..43b6b164 100644
--- a/test/bash/daemon-paths-override.sh
+++ b/test/e2e/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/e2e/internals/increment-var.sh
similarity index 98%
rename from test/bash/increment-var.sh
rename to test/e2e/internals/increment-var.sh
index 7deb2377..ad4c3f3e 100644
--- a/test/bash/increment-var.sh
+++ b/test/e2e/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/e2e/internals/infinite-loop.sh
similarity index 96%
rename from test/bash/infinite-loop.sh
rename to test/e2e/internals/infinite-loop.sh
index 809c71ae..f0528251 100644
--- a/test/bash/infinite-loop.sh
+++ b/test/e2e/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/e2e/internals/listen-timeout.sh
similarity index 86%
rename from test/bash/listen-timeout.sh
rename to test/e2e/internals/listen-timeout.sh
index d9d9cc40..4d874e3d 100644
--- a/test/bash/listen-timeout.sh
+++ b/test/e2e/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/e2e/internals/options-via-env.sh
similarity index 93%
rename from test/bash/options-via-env.sh
rename to test/e2e/internals/options-via-env.sh
index c2049f50..bd644bf5 100644
--- a/test/bash/options-via-env.sh
+++ b/test/e2e/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/e2e/internals/promise.sh
similarity index 98%
rename from test/bash/promise.sh
rename to test/e2e/internals/promise.sh
index a4c1b6cb..fb36c2e1 100644
--- a/test/bash/promise.sh
+++ b/test/e2e/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/e2e/internals/signal.sh
similarity index 93%
rename from test/bash/signal.sh
rename to test/e2e/internals/signal.sh
index 3fb15af9..2182440b 100644
--- a/test/bash/signal.sh
+++ b/test/e2e/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/e2e/internals/source_map.sh
similarity index 97%
rename from test/bash/source_map.sh
rename to test/e2e/internals/source_map.sh
index 896f6b75..368deee4 100644
--- a/test/bash/source_map.sh
+++ b/test/e2e/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/e2e/internals/start-consistency.sh
similarity index 94%
rename from test/bash/start-consistency.sh
rename to test/e2e/internals/start-consistency.sh
index f7a9c682..ada5d84a 100644
--- a/test/bash/start-consistency.sh
+++ b/test/e2e/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/e2e/internals/wait-ready-event.sh
similarity index 88%
rename from test/bash/wait-ready-event.sh
rename to test/e2e/internals/wait-ready-event.sh
index c4a326c6..f6c19d1b 100644
--- a/test/bash/wait-ready-event.sh
+++ b/test/e2e/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/e2e/internals/wrapped-fork.sh
similarity index 94%
rename from test/bash/wrapped-fork.sh
rename to test/e2e/internals/wrapped-fork.sh
index 0731031c..475ea06f 100644
--- a/test/bash/wrapped-fork.sh
+++ b/test/e2e/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/log-custom.sh b/test/e2e/logs/log-custom.sh
similarity index 96%
rename from test/bash/log-custom.sh
rename to test/e2e/logs/log-custom.sh
index 8017f3c6..6a8ca50a 100644
--- a/test/bash/log-custom.sh
+++ b/test/e2e/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/e2e/logs/log-entire.sh
similarity index 99%
rename from test/bash/log-entire.sh
rename to test/e2e/logs/log-entire.sh
index 50150ac4..d09804bc 100644
--- a/test/bash/log-entire.sh
+++ b/test/e2e/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/e2e/logs/log-json.sh
similarity index 90%
rename from test/bash/log-json.sh
rename to test/e2e/logs/log-json.sh
index d602cc8f..14cf9af7 100644
--- a/test/bash/log-json.sh
+++ b/test/e2e/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/e2e/logs/log-null.sh
similarity index 98%
rename from test/bash/log-null.sh
rename to test/e2e/logs/log-null.sh
index ed8c6b2a..5007d248 100644
--- a/test/bash/log-null.sh
+++ b/test/e2e/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/e2e/logs/log-reload.sh
similarity index 96%
rename from test/bash/log-reload.sh
rename to test/e2e/logs/log-reload.sh
index 0227a6e8..ce64f5c6 100644
--- a/test/bash/log-reload.sh
+++ b/test/e2e/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/e2e/logs/log-timestamp.sh
similarity index 98%
rename from test/bash/log-timestamp.sh
rename to test/e2e/logs/log-timestamp.sh
index 1a4d065f..d5308cbd 100644
--- a/test/bash/log-timestamp.sh
+++ b/test/e2e/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/e2e/misc/cron-system.sh
similarity index 85%
rename from test/bash/cron-system.sh
rename to test/e2e/misc/cron-system.sh
index 96b05b89..d9dbbe0e 100644
--- a/test/bash/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
@@ -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/bash/inside-pm2.sh b/test/e2e/misc/inside-pm2.sh
similarity index 87%
rename from test/bash/inside-pm2.sh
rename to test/e2e/misc/inside-pm2.sh
index bfb8c45e..6646e8fb 100644
--- a/test/bash/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
@@ -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/bash/instance-number.sh b/test/e2e/misc/instance-number.sh
similarity index 76%
rename from test/bash/instance-number.sh
rename to test/e2e/misc/instance-number.sh
index 61b46e9b..fe2ba630 100644
--- a/test/bash/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/bash/misc.sh b/test/e2e/misc/misc.sh
similarity index 98%
rename from test/bash/misc.sh
rename to test/e2e/misc/misc.sh
index 42dbb45a..939e7ae4 100644
--- a/test/bash/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/bash/nvm-node-version.sh b/test/e2e/misc/nvm-node-version.sh
similarity index 97%
rename from test/bash/nvm-node-version.sh
rename to test/e2e/misc/nvm-node-version.sh
index cb39919e..d9436f41 100644
--- a/test/bash/nvm-node-version.sh
+++ b/test/e2e/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/startup.sh b/test/e2e/misc/startup.sh
similarity index 96%
rename from test/bash/startup.sh
rename to test/e2e/misc/startup.sh
index 84d43b5d..f34ea214 100644
--- a/test/bash/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/bash/versioning-cmd.sh b/test/e2e/misc/versioning-cmd.sh
similarity index 97%
rename from test/bash/versioning-cmd.sh
rename to test/e2e/misc/versioning-cmd.sh
index 487a227b..f1bdad07 100644
--- a/test/bash/versioning-cmd.sh
+++ b/test/e2e/misc/versioning-cmd.sh
@@ -1,10 +1,12 @@
#!/usr/bin/env bash
SRC=$(cd $(dirname "$0"); pwd)
-source "${SRC}/include.sh"
+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/bash/vizion.sh b/test/e2e/misc/vizion.sh
similarity index 94%
rename from test/bash/vizion.sh
rename to test/e2e/misc/vizion.sh
index d7e896d1..b65b1942 100644
--- a/test/bash/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/bash/get-set.sh b/test/e2e/modules/get-set.sh
similarity index 92%
rename from test/bash/get-set.sh
rename to test/e2e/modules/get-set.sh
index 76cfdc47..c1a64984 100644
--- a/test/bash/get-set.sh
+++ b/test/e2e/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/e2e/modules/module-safeguard.sh
similarity index 97%
rename from test/bash/module-safeguard.sh
rename to test/e2e/modules/module-safeguard.sh
index 4dcc8221..6b677879 100644
--- a/test/bash/module-safeguard.sh
+++ b/test/e2e/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/e2e/modules/module.sh
similarity index 70%
rename from test/bash/module.sh
rename to test/e2e/modules/module.sh
index 6a7a0a44..715abb2d 100644
--- a/test/bash/module.sh
+++ b/test/e2e/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"
@@ -16,24 +16,30 @@ $pm2 kill
#
#
+$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
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
diff --git a/test/bash/app-config-update.sh b/test/e2e/process-file/app-config-update.sh
similarity index 82%
rename from test/bash/app-config-update.sh
rename to test/e2e/process-file/app-config-update.sh
index 8ef0a532..1859007f 100644
--- a/test/bash/app-config-update.sh
+++ b/test/e2e/process-file/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
@@ -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/append-env-to-name.sh b/test/e2e/process-file/append-env-to-name.sh
similarity index 88%
rename from test/bash/append-env-to-name.sh
rename to test/e2e/process-file/append-env-to-name.sh
index cbecbd15..9acb8760 100644
--- a/test/bash/append-env-to-name.sh
+++ b/test/e2e/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/e2e/process-file/homogen-json-action.sh
similarity index 97%
rename from test/bash/homogen-json-action.sh
rename to test/e2e/process-file/homogen-json-action.sh
index 81c5b306..2111f839 100644
--- a/test/bash/homogen-json-action.sh
+++ b/test/e2e/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/e2e/process-file/js-configuration.sh
similarity index 58%
rename from test/bash/js-configuration.sh
rename to test/e2e/process-file/js-configuration.sh
index 6888ddd2..b5de850d 100644
--- a/test/bash/js-configuration.sh
+++ b/test/e2e/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/e2e/process-file/json-file.sh
similarity index 93%
rename from test/bash/json-file.sh
rename to test/e2e/process-file/json-file.sh
index 50c3ff35..c6c984f5 100644
--- a/test/bash/json-file.sh
+++ b/test/e2e/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"
@@ -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/json-reload.sh b/test/e2e/process-file/json-reload.sh
similarity index 98%
rename from test/bash/json-reload.sh
rename to test/e2e/process-file/json-reload.sh
index 64841bb9..2698fa87 100644
--- a/test/bash/json-reload.sh
+++ b/test/e2e/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/e2e/process-file/yaml-configuration.sh
similarity index 96%
rename from test/bash/yaml-configuration.sh
rename to test/e2e/process-file/yaml-configuration.sh
index 4286309c..51c4e71a 100644
--- a/test/bash/yaml-configuration.sh
+++ b/test/e2e/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/pull.sh b/test/e2e/pull.sh
similarity index 98%
rename from test/bash/pull.sh
rename to test/e2e/pull.sh
index 54e279f6..d12e68ea 100644
--- a/test/bash/pull.sh
+++ b/test/e2e/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/fixtures/child_no_http.js b/test/fixtures/child_no_http.js
index 83ec9517..f38d18c4 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..b68bdd9e 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..693d8b9a 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..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('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..a0df61bc 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/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/fixtures/homogen-json-action/http.js b/test/fixtures/homogen-json-action/http.js
index 61d823c7..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('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..1a3d9a69 100644
--- a/test/fixtures/interface/http_transaction.js
+++ b/test/fixtures/interface/http_transaction.js
@@ -1,6 +1,9 @@
-var axm = require('pmx');
-axm.http();
+var axm = require('@pm2/io');
+
+axm.init({
+ http: true
+})
var http = require('http');
diff --git a/test/fixtures/interface/human_event.js b/test/fixtures/interface/human_event.js
index 925a72a3..e1807256 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..23575d2b 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..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('pmx');
+var pmx = require('@pm2/io');
pmx.action('exception', function(reply) {
console.log('Im going to crash');
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
-
-
-
-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
-
-
-
-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:
-
- 
-
- 
-
-#### 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.
-
- 
-
- When stdout is not a TTY, `Date#toUTCString()` is used, making it more useful for logging the debug information as shown below:
-
- 
-
-## 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:
-
- 
-
-### 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\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\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"
-}
diff --git a/test/fixtures/module-fixture/scoped-action.js b/test/fixtures/module-fixture/scoped-action.js
index 49d844aa..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('pmx');
+var pmx = require('@pm2/io');
var conf = pmx.initModule({
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/fixtures/probes.js b/test/fixtures/probes.js
index bf2e07ca..28b34677 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-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);
+ }
+});
diff --git a/test/fixtures/start-consistency/child.js b/test/fixtures/start-consistency/child.js
index b22f8e48..c457878b 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
});
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..72e35829 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');
@@ -58,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) {
@@ -89,7 +87,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);
@@ -173,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 706d5a1e..4db6b9c3 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');
@@ -60,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) {
@@ -173,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();
- });
- });
-
});
});
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/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/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/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);
- });
- });
-});
diff --git a/test/parallel.js b/test/parallel.js
new file mode 100644
index 00000000..838520e2
--- /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 = 3
+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'))
+ })
+})
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/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/pm2_programmatic_tests.sh
deleted file mode 100644
index 695c622f..00000000
--- a/test/pm2_programmatic_tests.sh
+++ /dev/null
@@ -1,131 +0,0 @@
-#!/usr/bin/env bash
-
-alias mocha='../node_modules/mocha/bin/mocha'
-pm2="`type -P node` `pwd`/bin/pm2"
-
-# Abort script at first error
-set -e
-# Display all commands executed
-set -o verbose
-
-function fail {
- echo -e "######## \033[31m ✘ $1\033[0m"
- exit 1
-}
-
-function success {
- echo -e "\033[32m------------> ✔ $1\033[0m"
-}
-
-function spec {
- [ $? -eq 0 ] || fail "$1"
- $pm2 uninstall all
- $pm2 link delete
- $pm2 kill
- success "$1"
-}
-
-$pm2 uninstall all
-
-# if [ $TRAVIS ]
-# then
-# export DEBUG="pm2:*"
-# fi
-cd test/programmatic
-
-mocha --opts ./mocha.opts ./god.mocha.js
-spec "God test"
-
-mocha --opts ./mocha.opts ./programmatic.js
-spec "Programmatic test"
-
-mocha --opts ./mocha.opts ./containerizer.mocha.js
-spec "Dockerfile parser test"
-
-mocha --opts ./mocha.opts ./api.mocha.js
-spec "API tests"
-mocha --opts ./mocha.opts ./path_resolution.mocha.js
-spec "API tests"
-mocha --opts ./mocha.opts ./lazy_api.mocha.js
-spec "API tests"
-mocha --opts ./mocha.opts ./reload-locker.mocha.js
-spec "Reload locker tests"
-
-mocha --opts ./mocha.opts ./api.backward.compatibility.mocha.js
-spec "API Backward compatibility tests"
-mocha --opts ./mocha.opts ./custom_action.mocha.js
-spec "Custom Actions tests"
-
-mocha --opts ./mocha.opts ./logs.js
-spec "Logs test"
-mocha --opts ./mocha.opts ./watcher.js
-spec "Watcher"
-mocha --opts ./mocha.opts ./max_memory_limit.js
-spec "Max memory tests"
-# mocha --opts ./mocha.opts ./module_configuration.mocha.js
-# spec "Max memory tests"
-mocha --opts ./mocha.opts ./cluster.mocha.js
-spec "Cluster tests"
-mocha --opts ./mocha.opts ./graceful.mocha.js
-spec "Graceful tests"
-mocha --opts ./mocha.opts ./inside.mocha.js
-spec "Inside pm2 call tests"
-mocha --opts ./mocha.opts ./misc_commands.js
-spec "MISC tests"
-mocha --opts ./mocha.opts ./signals.js
-spec "SIGINT signal interception + delay customization"
-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 ./json_validation.mocha.js
-spec "JSON validation test"
-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"
-
-#
-# Interface testing
-#
-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"
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/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/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()
+ })
+ });
});
diff --git a/test/programmatic/id.mocha.js b/test/programmatic/id.mocha.js
new file mode 100644
index 00000000..1d879859
--- /dev/null
+++ b/test/programmatic/id.mocha.js
@@ -0,0 +1,82 @@
+
+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.delete('all', function() { done() });
+ });
+
+ after(function(done) {
+ PM2.delete('all', function() { 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();
+ });
+ });
+ });
+ });
+});
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();
+ });
+ });
+
});
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) {
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/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() {
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
diff --git a/test/unit.sh b/test/unit.sh
new file mode 100644
index 00000000..1fb7143d
--- /dev/null
+++ b/test/unit.sh
@@ -0,0 +1,105 @@
+#!/usr/bin/env bash
+
+alias mocha='../node_modules/mocha/bin/mocha'
+pm2="`type -P node` `pwd`/bin/pm2"
+
+# Abort script at first error
+set -e
+# Display all commands executed
+set -o verbose
+
+function fail {
+ echo -e "######## \033[31m ✘ $1\033[0m"
+ exit 1
+}
+
+function success {
+ echo -e "\033[32m------------> ✔ $1\033[0m"
+}
+
+function spec {
+ [ $? -eq 0 ] || fail "$1"
+ $pm2 uninstall all
+ $pm2 link delete
+ $pm2 kill
+ success "$1"
+}
+
+$pm2 uninstall all
+
+# if [ $TRAVIS ]
+# then
+# export DEBUG="pm2:*"
+# fi
+cd test/programmatic
+
+mocha --exit --opts ./mocha.opts ./god.mocha.js
+spec "God test"
+
+mocha --exit --opts ./mocha.opts ./programmatic.js
+spec "Programmatic test"
+
+mocha --exit --opts ./mocha.opts ./containerizer.mocha.js
+spec "Dockerfile parser test"
+
+mocha --exit --opts ./mocha.opts ./api.mocha.js
+spec "API tests"
+mocha --exit --opts ./mocha.opts ./path_resolution.mocha.js
+spec "API tests"
+mocha --exit --opts ./mocha.opts ./lazy_api.mocha.js
+spec "API tests"
+mocha --exit --opts ./mocha.opts ./reload-locker.mocha.js
+spec "Reload locker tests"
+
+mocha --exit --opts ./mocha.opts ./api.backward.compatibility.mocha.js
+spec "API Backward compatibility tests"
+mocha --exit --opts ./mocha.opts ./custom_action.mocha.js
+spec "Custom Actions tests"
+
+mocha --exit --opts ./mocha.opts ./logs.js
+spec "Logs test"
+mocha --exit --opts ./mocha.opts ./watcher.js
+spec "Watcher"
+mocha --exit --opts ./mocha.opts ./max_memory_limit.js
+spec "Max memory tests"
+# mocha --exit --opts ./mocha.opts ./module_configuration.mocha.js
+# spec "Max memory tests"
+mocha --exit --opts ./mocha.opts ./cluster.mocha.js
+spec "Cluster tests"
+mocha --exit --opts ./mocha.opts ./graceful.mocha.js
+spec "Graceful tests"
+mocha --exit --opts ./mocha.opts ./inside.mocha.js
+spec "Inside pm2 call tests"
+mocha --exit --opts ./mocha.opts ./misc_commands.js
+spec "MISC tests"
+mocha --exit --opts ./mocha.opts ./signals.js
+spec "SIGINT signal interception + delay customization"
+mocha --exit --opts ./mocha.opts ./send_data_process.mocha.js
+spec "Send data to a process"
+mocha --exit --opts ./mocha.opts ./modules.mocha.js
+spec "Module API testing"
+# mocha --exit --opts ./mocha.opts ./module_retrocompat.mocha.js
+# spec "Module retrocompatibility system"
+
+mocha --exit --opts ./mocha.opts ./json_validation.mocha.js
+spec "JSON validation test"
+mocha --exit --opts ./mocha.opts ./env_switching.js
+spec "JSON environment switching on JSON restart with --env"
+mocha --exit --opts ./mocha.opts ./configuration.mocha.js
+spec "Configuration system working"
+mocha --exit --opts ./mocha.opts ./id.mocha.js
+spec "Uniqueness id for each process"
+
+#
+# Interface testing
+#
+cd ../interface
+
+# echo $PM2_HOME
+
+mocha --exit --opts ./mocha.opts ./bus.spec.mocha.js
+spec "Protocol communication test"
+mocha --exit --opts ./mocha.opts ./bus.fork.spec.mocha.js
+spec "Protocol communication test"
+mocha --exit --opts ./mocha.opts ./utility.mocha.js
+spec "PM2 Utility"
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.
*/
diff --git a/yarn.lock b/yarn.lock
new file mode 100644
index 00000000..0d6ed766
--- /dev/null
+++ b/yarn.lock
@@ -0,0 +1,1894 @@
+# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
+# yarn lockfile v1
+
+
+"@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"
+ 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"
+
+ajv@^4.9.1:
+ version "4.11.8"
+ resolved "https://registry.yarnpkg.com/ajv/-/ajv-4.11.8.tgz#82ffb02b29e662ae53bdc20af15947706739c536"
+ dependencies:
+ co "^4.6.0"
+ json-stable-stringify "^1.0.1"
+
+amp-message@~0.1.1:
+ version "0.1.2"
+ resolved "https://registry.yarnpkg.com/amp-message/-/amp-message-0.1.2.tgz#a78f1c98995087ad36192a41298e4db49e3dfc45"
+ dependencies:
+ amp "0.3.1"
+
+amp@0.3.1, amp@~0.3.1:
+ version "0.3.1"
+ resolved "https://registry.yarnpkg.com/amp/-/amp-0.3.1.tgz#6adf8d58a74f361e82c1fa8d389c079e139fc47d"
+
+ansi-regex@^2.0.0:
+ version "2.1.1"
+ resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-2.1.1.tgz#c3b33ab5ee360d86e0e628f0468ae7ef27d654df"
+
+ansi-styles@^2.2.1:
+ version "2.2.1"
+ resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-2.2.1.tgz#b432dd3358b634cf75e1e4664368240533c1ddbe"
+
+ansi-styles@^3.2.1:
+ version "3.2.1"
+ resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d"
+ dependencies:
+ color-convert "^1.9.0"
+
+anymatch@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-2.0.0.tgz#bcb24b4f37934d9aa7ac17b4adaf89e7c76ef2eb"
+ dependencies:
+ micromatch "^3.1.4"
+ normalize-path "^2.1.1"
+
+aproba@^1.0.3:
+ version "1.2.0"
+ resolved "https://registry.yarnpkg.com/aproba/-/aproba-1.2.0.tgz#6802e6264efd18c790a1b0d517f0f2627bf2c94a"
+
+are-we-there-yet@~1.1.2:
+ version "1.1.4"
+ resolved "https://registry.yarnpkg.com/are-we-there-yet/-/are-we-there-yet-1.1.4.tgz#bb5dca382bb94f05e15194373d16fd3ba1ca110d"
+ dependencies:
+ delegates "^1.0.0"
+ readable-stream "^2.0.6"
+
+argparse@^1.0.7:
+ version "1.0.10"
+ resolved "https://registry.yarnpkg.com/argparse/-/argparse-1.0.10.tgz#bcd6791ea5ae09725e17e5ad988134cd40b3d911"
+ dependencies:
+ sprintf-js "~1.0.2"
+
+arr-diff@^4.0.0:
+ version "4.0.0"
+ resolved "https://registry.yarnpkg.com/arr-diff/-/arr-diff-4.0.0.tgz#d6461074febfec71e7e15235761a329a5dc7c520"
+
+arr-flatten@^1.1.0:
+ version "1.1.0"
+ resolved "https://registry.yarnpkg.com/arr-flatten/-/arr-flatten-1.1.0.tgz#36048bbff4e7b47e136644316c99669ea5ae91f1"
+
+arr-union@^3.1.0:
+ version "3.1.0"
+ resolved "https://registry.yarnpkg.com/arr-union/-/arr-union-3.1.0.tgz#e39b09aea9def866a8f206e288af63919bae39c4"
+
+array-unique@^0.3.2:
+ version "0.3.2"
+ resolved "https://registry.yarnpkg.com/array-unique/-/array-unique-0.3.2.tgz#a894b75d4bc4f6cd679ef3244a9fd8f46ae2d428"
+
+asn1@~0.2.3:
+ version "0.2.3"
+ resolved "https://registry.yarnpkg.com/asn1/-/asn1-0.2.3.tgz#dac8787713c9966849fc8180777ebe9c1ddf3b86"
+
+assert-plus@1.0.0, assert-plus@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/assert-plus/-/assert-plus-1.0.0.tgz#f12e0f3c5d77b0b1cdd9146942e4e96c1e4dd525"
+
+assert-plus@^0.2.0:
+ version "0.2.0"
+ resolved "https://registry.yarnpkg.com/assert-plus/-/assert-plus-0.2.0.tgz#d74e1b87e7affc0db8aadb7021f3fe48101ab234"
+
+assign-symbols@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/assign-symbols/-/assign-symbols-1.0.0.tgz#59667f41fadd4f20ccbc2bb96b8d4f7f78ec0367"
+
+async-each@^1.0.0:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/async-each/-/async-each-1.0.1.tgz#19d386a1d9edc6e7c1c85d388aedbcc56d33602d"
+
+async-limiter@~1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/async-limiter/-/async-limiter-1.0.0.tgz#78faed8c3d074ab81f22b4e985d79e8738f720f8"
+
+async-listener@^0.6.0:
+ version "0.6.9"
+ resolved "https://registry.yarnpkg.com/async-listener/-/async-listener-0.6.9.tgz#51bc95e41095417f33922fb4dee4f232b3226488"
+ dependencies:
+ semver "^5.3.0"
+ shimmer "^1.1.0"
+
+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"
+
+async@^2.5, async@^2.6.0:
+ version "2.6.0"
+ resolved "https://registry.yarnpkg.com/async/-/async-2.6.0.tgz#61a29abb6fcc026fea77e56d1c6ec53a795951f4"
+ dependencies:
+ lodash "^4.14.0"
+
+asynckit@^0.4.0:
+ version "0.4.0"
+ resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79"
+
+atob@^2.0.0:
+ version "2.0.3"
+ resolved "https://registry.yarnpkg.com/atob/-/atob-2.0.3.tgz#19c7a760473774468f20b2d2d03372ad7d4cbf5d"
+
+aws-sign2@~0.6.0:
+ version "0.6.0"
+ resolved "https://registry.yarnpkg.com/aws-sign2/-/aws-sign2-0.6.0.tgz#14342dd38dbcc94d0e5b87d763cd63612c0e794f"
+
+aws4@^1.2.1:
+ version "1.6.0"
+ resolved "https://registry.yarnpkg.com/aws4/-/aws4-1.6.0.tgz#83ef5ca860b2b32e4a0deedee8c771b9db57471e"
+
+balanced-match@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.0.tgz#89b4d199ab2bee49de164ea02b89ce462d71b767"
+
+base@^0.11.1:
+ version "0.11.2"
+ resolved "https://registry.yarnpkg.com/base/-/base-0.11.2.tgz#7bde5ced145b6d551a90db87f83c558b4eb48a8f"
+ dependencies:
+ cache-base "^1.0.1"
+ class-utils "^0.3.5"
+ component-emitter "^1.2.1"
+ define-property "^1.0.0"
+ isobject "^3.0.1"
+ mixin-deep "^1.2.0"
+ pascalcase "^0.1.1"
+
+bcrypt-pbkdf@^1.0.0:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.1.tgz#63bc5dcb61331b92bc05fd528953c33462a06f8d"
+ dependencies:
+ tweetnacl "^0.14.3"
+
+binary-extensions@^1.0.0:
+ version "1.11.0"
+ resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-1.11.0.tgz#46aa1751fb6a2f93ee5e689bb1087d4b14c6c205"
+
+blessed@^0.1.81:
+ version "0.1.81"
+ resolved "https://registry.yarnpkg.com/blessed/-/blessed-0.1.81.tgz#f962d687ec2c369570ae71af843256e6d0ca1129"
+
+block-stream@*:
+ version "0.0.9"
+ resolved "https://registry.yarnpkg.com/block-stream/-/block-stream-0.0.9.tgz#13ebfe778a03205cfe03751481ebb4b3300c126a"
+ dependencies:
+ inherits "~2.0.0"
+
+boom@2.x.x:
+ version "2.10.1"
+ resolved "https://registry.yarnpkg.com/boom/-/boom-2.10.1.tgz#39c8918ceff5799f83f9492a848f625add0c766f"
+ dependencies:
+ hoek "2.x.x"
+
+brace-expansion@^1.1.7:
+ version "1.1.11"
+ resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd"
+ dependencies:
+ balanced-match "^1.0.0"
+ concat-map "0.0.1"
+
+braces@^2.3.0, braces@^2.3.1:
+ version "2.3.1"
+ resolved "https://registry.yarnpkg.com/braces/-/braces-2.3.1.tgz#7086c913b4e5a08dbe37ac0ee6a2500c4ba691bb"
+ dependencies:
+ arr-flatten "^1.1.0"
+ array-unique "^0.3.2"
+ define-property "^1.0.0"
+ extend-shallow "^2.0.1"
+ fill-range "^4.0.0"
+ isobject "^3.0.1"
+ kind-of "^6.0.2"
+ repeat-element "^1.1.2"
+ snapdragon "^0.8.1"
+ snapdragon-node "^2.0.1"
+ split-string "^3.0.2"
+ to-regex "^3.0.1"
+
+browser-stdout@1.3.0:
+ version "1.3.0"
+ resolved "https://registry.yarnpkg.com/browser-stdout/-/browser-stdout-1.3.0.tgz#f351d32969d32fa5d7a5567154263d928ae3bd1f"
+
+cache-base@^1.0.1:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/cache-base/-/cache-base-1.0.1.tgz#0a7f46416831c8b662ee36fe4e7c59d76f666ab2"
+ dependencies:
+ collection-visit "^1.0.0"
+ component-emitter "^1.2.1"
+ get-value "^2.0.6"
+ has-value "^1.0.0"
+ isobject "^3.0.1"
+ set-value "^2.0.0"
+ to-object-path "^0.3.0"
+ union-value "^1.0.0"
+ unset-value "^1.0.0"
+
+caseless@~0.12.0:
+ version "0.12.0"
+ resolved "https://registry.yarnpkg.com/caseless/-/caseless-0.12.0.tgz#1b681c21ff84033c826543090689420d187151dc"
+
+chalk@^1.1.3:
+ version "1.1.3"
+ resolved "https://registry.yarnpkg.com/chalk/-/chalk-1.1.3.tgz#a8115c55e4a702fe4d150abd3872822a7e09fc98"
+ dependencies:
+ ansi-styles "^2.2.1"
+ escape-string-regexp "^1.0.2"
+ has-ansi "^2.0.0"
+ strip-ansi "^3.0.0"
+ supports-color "^2.0.0"
+
+chalk@^2.3.1:
+ version "2.3.2"
+ resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.3.2.tgz#250dc96b07491bfd601e648d66ddf5f60c7a5c65"
+ dependencies:
+ ansi-styles "^3.2.1"
+ escape-string-regexp "^1.0.5"
+ supports-color "^5.3.0"
+
+charm@~0.1.1:
+ version "0.1.2"
+ resolved "https://registry.yarnpkg.com/charm/-/charm-0.1.2.tgz#06c21eed1a1b06aeb67553cdc53e23274bac2296"
+
+chokidar@^2.0.2:
+ version "2.0.2"
+ resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-2.0.2.tgz#4dc65139eeb2714977735b6a35d06e97b494dfd7"
+ dependencies:
+ anymatch "^2.0.0"
+ async-each "^1.0.0"
+ braces "^2.3.0"
+ glob-parent "^3.1.0"
+ inherits "^2.0.1"
+ is-binary-path "^1.0.0"
+ is-glob "^4.0.0"
+ normalize-path "^2.1.1"
+ path-is-absolute "^1.0.0"
+ readdirp "^2.0.0"
+ upath "^1.0.0"
+ optionalDependencies:
+ fsevents "^1.0.0"
+
+class-utils@^0.3.5:
+ version "0.3.6"
+ resolved "https://registry.yarnpkg.com/class-utils/-/class-utils-0.3.6.tgz#f93369ae8b9a7ce02fd41faad0ca83033190c463"
+ dependencies:
+ arr-union "^3.1.0"
+ define-property "^0.2.5"
+ isobject "^3.0.0"
+ static-extend "^0.1.1"
+
+cli-table-redemption@^1.0.0:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/cli-table-redemption/-/cli-table-redemption-1.0.1.tgz#0359d8c34df74980029d76dff071a05a127c4fdd"
+ dependencies:
+ chalk "^1.1.3"
+
+co@^4.6.0:
+ version "4.6.0"
+ resolved "https://registry.yarnpkg.com/co/-/co-4.6.0.tgz#6ea6bdf3d853ae54ccb8e47bfa0bf3f9031fb184"
+
+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"
+
+collection-visit@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/collection-visit/-/collection-visit-1.0.0.tgz#4bc0373c164bc3291b4d368c829cf1a80a59dca0"
+ dependencies:
+ map-visit "^1.0.0"
+ object-visit "^1.0.0"
+
+color-convert@^1.9.0:
+ version "1.9.1"
+ resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.1.tgz#c1261107aeb2f294ebffec9ed9ecad529a6097ed"
+ dependencies:
+ color-name "^1.1.1"
+
+color-name@^1.1.1:
+ version "1.1.3"
+ resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25"
+
+combined-stream@^1.0.5, combined-stream@~1.0.5:
+ version "1.0.6"
+ resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.6.tgz#723e7df6e801ac5613113a7e445a9b69cb632818"
+ dependencies:
+ delayed-stream "~1.0.0"
+
+commander@2.14.1:
+ version "2.14.1"
+ resolved "https://registry.yarnpkg.com/commander/-/commander-2.14.1.tgz#2235123e37af8ca3c65df45b026dbd357b01b9aa"
+
+commander@2.9.0:
+ version "2.9.0"
+ resolved "https://registry.yarnpkg.com/commander/-/commander-2.9.0.tgz#9c99094176e12240cb22d6c5146098400fe0f7d4"
+ dependencies:
+ graceful-readlink ">= 1.0.0"
+
+component-emitter@^1.2.1:
+ version "1.2.1"
+ resolved "https://registry.yarnpkg.com/component-emitter/-/component-emitter-1.2.1.tgz#137918d6d78283f7df7a6b7c5a63e140e69425e6"
+
+concat-map@0.0.1:
+ version "0.0.1"
+ resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b"
+
+console-control-strings@^1.0.0, console-control-strings@~1.1.0:
+ version "1.1.0"
+ resolved "https://registry.yarnpkg.com/console-control-strings/-/console-control-strings-1.1.0.tgz#3d7cf4464db6446ea644bf4b39507f9851008e8e"
+
+continuation-local-storage@^3.1.4:
+ version "3.2.1"
+ resolved "https://registry.yarnpkg.com/continuation-local-storage/-/continuation-local-storage-3.2.1.tgz#11f613f74e914fe9b34c92ad2d28fe6ae1db7ffb"
+ dependencies:
+ async-listener "^0.6.0"
+ emitter-listener "^1.1.1"
+
+copy-descriptor@^0.1.0:
+ version "0.1.1"
+ resolved "https://registry.yarnpkg.com/copy-descriptor/-/copy-descriptor-0.1.1.tgz#676f6eb3c39997c2ee1ac3a924fd6124748f578d"
+
+core-util-is@1.0.2, core-util-is@~1.0.0:
+ version "1.0.2"
+ resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7"
+
+cron@^1.3:
+ version "1.3.0"
+ resolved "https://registry.yarnpkg.com/cron/-/cron-1.3.0.tgz#7e459968eaf94e1a445be796ce402166c234659d"
+ dependencies:
+ moment-timezone "^0.5.x"
+
+cryptiles@2.x.x:
+ version "2.0.5"
+ resolved "https://registry.yarnpkg.com/cryptiles/-/cryptiles-2.0.5.tgz#3bdfecdc608147c1c67202fa291e7dca59eaa3b8"
+ dependencies:
+ boom "2.x.x"
+
+dashdash@^1.12.0:
+ version "1.14.1"
+ resolved "https://registry.yarnpkg.com/dashdash/-/dashdash-1.14.1.tgz#853cfa0f7cbe2fed5de20326b8dd581035f6e2f0"
+ dependencies:
+ assert-plus "^1.0.0"
+
+debug@2.6.8:
+ version "2.6.8"
+ resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.8.tgz#e731531ca2ede27d188222427da17821d68ff4fc"
+ dependencies:
+ ms "2.0.0"
+
+debug@^2.1.2, debug@^2.2.0, debug@^2.3.3, debug@^2.6.3:
+ version "2.6.9"
+ resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f"
+ dependencies:
+ ms "2.0.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:
+ ms "2.0.0"
+
+debug@~2.2.0:
+ version "2.2.0"
+ resolved "https://registry.yarnpkg.com/debug/-/debug-2.2.0.tgz#f87057e995b1a1f6ae6a4960664137bc56f039da"
+ dependencies:
+ ms "0.7.1"
+
+decode-uri-component@^0.2.0:
+ version "0.2.0"
+ resolved "https://registry.yarnpkg.com/decode-uri-component/-/decode-uri-component-0.2.0.tgz#eb3913333458775cb84cd1a1fae062106bb87545"
+
+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"
+
+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"
+ dependencies:
+ is-descriptor "^0.1.0"
+
+define-property@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/define-property/-/define-property-1.0.0.tgz#769ebaaf3f4a63aad3af9e8d304c9bbe79bfb0e6"
+ dependencies:
+ is-descriptor "^1.0.0"
+
+define-property@^2.0.2:
+ version "2.0.2"
+ resolved "https://registry.yarnpkg.com/define-property/-/define-property-2.0.2.tgz#d459689e8d654ba77e02a817f8710d702cb16e9d"
+ dependencies:
+ is-descriptor "^1.0.2"
+ isobject "^3.0.1"
+
+delayed-stream@~1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619"
+
+delegates@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/delegates/-/delegates-1.0.0.tgz#84c6e159b81904fdca59a0ef44cd870d31250f9a"
+
+detect-libc@^1.0.2:
+ version "1.0.3"
+ resolved "https://registry.yarnpkg.com/detect-libc/-/detect-libc-1.0.3.tgz#fa137c4bd698edf55cd5cd02ac559f91a4c4ba9b"
+
+diff@3.2.0:
+ version "3.2.0"
+ resolved "https://registry.yarnpkg.com/diff/-/diff-3.2.0.tgz#c9ce393a4b7cbd0b058a725c93df299027868ff9"
+
+ecc-jsbn@~0.1.1:
+ version "0.1.1"
+ resolved "https://registry.yarnpkg.com/ecc-jsbn/-/ecc-jsbn-0.1.1.tgz#0fc73a9ed5f0d53c38193398523ef7e543777505"
+ dependencies:
+ jsbn "~0.1.0"
+
+emitter-listener@^1.1.1:
+ version "1.1.1"
+ resolved "https://registry.yarnpkg.com/emitter-listener/-/emitter-listener-1.1.1.tgz#e8bbbe8244bc8e0d0b4ef71cd14294c7f241c7ec"
+ dependencies:
+ shimmer "^1.2.0"
+
+escape-regexp@0.0.1:
+ version "0.0.1"
+ resolved "https://registry.yarnpkg.com/escape-regexp/-/escape-regexp-0.0.1.tgz#f44bda12d45bbdf9cb7f862ee7e4827b3dd32254"
+
+escape-string-regexp@1.0.5, escape-string-regexp@^1.0.2, escape-string-regexp@^1.0.5:
+ version "1.0.5"
+ resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4"
+
+eventemitter2@5.0.1, eventemitter2@^5.0.1:
+ version "5.0.1"
+ resolved "https://registry.yarnpkg.com/eventemitter2/-/eventemitter2-5.0.1.tgz#6197a095d5fb6b57e8942f6fd7eaad63a09c9452"
+
+eventemitter2@~0.4.14:
+ version "0.4.14"
+ resolved "https://registry.yarnpkg.com/eventemitter2/-/eventemitter2-0.4.14.tgz#8f61b75cde012b2e9eb284d4545583b5643b61ab"
+
+expand-brackets@^2.1.4:
+ version "2.1.4"
+ resolved "https://registry.yarnpkg.com/expand-brackets/-/expand-brackets-2.1.4.tgz#b77735e315ce30f6b6eff0f83b04151a22449622"
+ dependencies:
+ debug "^2.3.3"
+ define-property "^0.2.5"
+ extend-shallow "^2.0.1"
+ posix-character-classes "^0.1.0"
+ regex-not "^1.0.0"
+ snapdragon "^0.8.1"
+ to-regex "^3.0.1"
+
+extend-shallow@^2.0.1:
+ version "2.0.1"
+ resolved "https://registry.yarnpkg.com/extend-shallow/-/extend-shallow-2.0.1.tgz#51af7d614ad9a9f610ea1bafbb989d6b1c56890f"
+ dependencies:
+ is-extendable "^0.1.0"
+
+extend-shallow@^3.0.0, extend-shallow@^3.0.2:
+ version "3.0.2"
+ resolved "https://registry.yarnpkg.com/extend-shallow/-/extend-shallow-3.0.2.tgz#26a71aaf073b39fb2127172746131c2704028db8"
+ dependencies:
+ assign-symbols "^1.0.0"
+ is-extendable "^1.0.1"
+
+extend@^3.0.0, extend@~3.0.0:
+ version "3.0.1"
+ resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.1.tgz#a755ea7bc1adfcc5a31ce7e762dbaadc5e636444"
+
+extglob@^2.0.4:
+ version "2.0.4"
+ resolved "https://registry.yarnpkg.com/extglob/-/extglob-2.0.4.tgz#ad00fe4dc612a9232e8718711dc5cb5ab0285543"
+ dependencies:
+ array-unique "^0.3.2"
+ define-property "^1.0.0"
+ expand-brackets "^2.1.4"
+ extend-shallow "^2.0.1"
+ fragment-cache "^0.2.1"
+ regex-not "^1.0.0"
+ snapdragon "^0.8.1"
+ to-regex "^3.0.1"
+
+extsprintf@1.3.0:
+ version "1.3.0"
+ resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.3.0.tgz#96918440e3041a7a414f8c52e3c574eb3c3e1e05"
+
+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.0.11:
+ version "1.0.11"
+ resolved "https://registry.yarnpkg.com/fclone/-/fclone-1.0.11.tgz#10e85da38bfea7fc599341c296ee1d77266ee640"
+
+fill-range@^4.0.0:
+ version "4.0.0"
+ resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-4.0.0.tgz#d544811d428f98eb06a63dc402d2403c328c38f7"
+ dependencies:
+ extend-shallow "^2.0.1"
+ is-number "^3.0.0"
+ repeat-string "^1.6.1"
+ to-regex-range "^2.1.0"
+
+for-in@^1.0.2:
+ version "1.0.2"
+ resolved "https://registry.yarnpkg.com/for-in/-/for-in-1.0.2.tgz#81068d295a8142ec0ac726c6e2200c30fb6d5e80"
+
+forever-agent@~0.6.1:
+ version "0.6.1"
+ resolved "https://registry.yarnpkg.com/forever-agent/-/forever-agent-0.6.1.tgz#fbc71f0c41adeb37f96c577ad1ed42d8fdacca91"
+
+form-data@~2.1.1:
+ version "2.1.4"
+ resolved "https://registry.yarnpkg.com/form-data/-/form-data-2.1.4.tgz#33c183acf193276ecaa98143a69e94bfee1750d1"
+ dependencies:
+ asynckit "^0.4.0"
+ combined-stream "^1.0.5"
+ mime-types "^2.1.12"
+
+fragment-cache@^0.2.1:
+ version "0.2.1"
+ resolved "https://registry.yarnpkg.com/fragment-cache/-/fragment-cache-0.2.1.tgz#4290fad27f13e89be7f33799c6bc5a0abfff0d19"
+ dependencies:
+ map-cache "^0.2.2"
+
+fs-extra@^5.0.0:
+ version "5.0.0"
+ resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-5.0.0.tgz#414d0110cdd06705734d055652c5411260c31abd"
+ dependencies:
+ graceful-fs "^4.1.2"
+ jsonfile "^4.0.0"
+ universalify "^0.1.0"
+
+fs.realpath@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f"
+
+fsevents@^1.0.0:
+ version "1.1.3"
+ resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-1.1.3.tgz#11f82318f5fe7bb2cd22965a108e9306208216d8"
+ dependencies:
+ nan "^2.3.0"
+ node-pre-gyp "^0.6.39"
+
+fstream-ignore@^1.0.5:
+ version "1.0.5"
+ resolved "https://registry.yarnpkg.com/fstream-ignore/-/fstream-ignore-1.0.5.tgz#9c31dae34767018fe1d249b24dada67d092da105"
+ dependencies:
+ fstream "^1.0.0"
+ inherits "2"
+ minimatch "^3.0.0"
+
+fstream@^1.0.0, fstream@^1.0.10, fstream@^1.0.2:
+ version "1.0.11"
+ resolved "https://registry.yarnpkg.com/fstream/-/fstream-1.0.11.tgz#5c1fb1f117477114f0632a0eb4b71b3cb0fd3171"
+ dependencies:
+ graceful-fs "^4.1.2"
+ inherits "~2.0.0"
+ mkdirp ">=0.5 0"
+ rimraf "2"
+
+gauge@~2.7.3:
+ version "2.7.4"
+ resolved "https://registry.yarnpkg.com/gauge/-/gauge-2.7.4.tgz#2c03405c7538c39d7eb37b317022e325fb018bf7"
+ dependencies:
+ aproba "^1.0.3"
+ console-control-strings "^1.0.0"
+ has-unicode "^2.0.0"
+ object-assign "^4.1.0"
+ signal-exit "^3.0.0"
+ string-width "^1.0.1"
+ strip-ansi "^3.0.1"
+ wide-align "^1.1.0"
+
+get-value@^2.0.3, get-value@^2.0.6:
+ version "2.0.6"
+ resolved "https://registry.yarnpkg.com/get-value/-/get-value-2.0.6.tgz#dc15ca1c672387ca76bd37ac0a395ba2042a2c28"
+
+getpass@^0.1.1:
+ version "0.1.7"
+ resolved "https://registry.yarnpkg.com/getpass/-/getpass-0.1.7.tgz#5eff8e3e684d569ae4cb2b1282604e8ba62149fa"
+ dependencies:
+ assert-plus "^1.0.0"
+
+"gkt@https://tgz.pm2.io/gkt-1.0.0.tgz":
+ version "1.0.0"
+ resolved "https://tgz.pm2.io/gkt-1.0.0.tgz#405502b007f319c3f47175c4474527300f2ab5ad"
+
+glob-parent@^3.1.0:
+ version "3.1.0"
+ resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-3.1.0.tgz#9e6af6299d8d3bd2bd40430832bd113df906c5ae"
+ dependencies:
+ is-glob "^3.1.0"
+ path-dirname "^1.0.0"
+
+glob@7.1.1:
+ version "7.1.1"
+ resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.1.tgz#805211df04faaf1c63a3600306cdf5ade50b2ec8"
+ dependencies:
+ fs.realpath "^1.0.0"
+ inflight "^1.0.4"
+ inherits "2"
+ minimatch "^3.0.2"
+ once "^1.3.0"
+ path-is-absolute "^1.0.0"
+
+glob@^7.0.0, glob@^7.0.5:
+ version "7.1.2"
+ resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.2.tgz#c19c9df9a028702d678612384a6552404c636d15"
+ dependencies:
+ fs.realpath "^1.0.0"
+ inflight "^1.0.4"
+ inherits "2"
+ minimatch "^3.0.4"
+ once "^1.3.0"
+ path-is-absolute "^1.0.0"
+
+graceful-fs@^4.1.2, graceful-fs@^4.1.6:
+ version "4.1.11"
+ resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.1.11.tgz#0e8bdfe4d1ddb8854d64e04ea7c00e2a026e5658"
+
+"graceful-readlink@>= 1.0.0":
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/graceful-readlink/-/graceful-readlink-1.0.1.tgz#4cafad76bc62f02fa039b2f94e9a3dd3a391a725"
+
+growl@1.9.2:
+ version "1.9.2"
+ resolved "https://registry.yarnpkg.com/growl/-/growl-1.9.2.tgz#0ea7743715db8d8de2c5ede1775e1b45ac85c02f"
+
+handy-http@^1.0.2:
+ version "1.0.2"
+ resolved "https://registry.yarnpkg.com/handy-http/-/handy-http-1.0.2.tgz#24860dca376a69fbb7cd1a604a221e2a56639126"
+
+har-schema@^1.0.5:
+ version "1.0.5"
+ resolved "https://registry.yarnpkg.com/har-schema/-/har-schema-1.0.5.tgz#d263135f43307c02c602afc8fe95970c0151369e"
+
+har-validator@~4.2.1:
+ version "4.2.1"
+ resolved "https://registry.yarnpkg.com/har-validator/-/har-validator-4.2.1.tgz#33481d0f1bbff600dd203d75812a6a5fba002e2a"
+ dependencies:
+ ajv "^4.9.1"
+ har-schema "^1.0.5"
+
+has-ansi@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/has-ansi/-/has-ansi-2.0.0.tgz#34f5049ce1ecdf2b0649af3ef24e45ed35416d91"
+ dependencies:
+ ansi-regex "^2.0.0"
+
+has-flag@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-1.0.0.tgz#9d9e793165ce017a00f00418c43f942a7b1d11fa"
+
+has-flag@^3.0.0:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd"
+
+has-unicode@^2.0.0:
+ version "2.0.1"
+ resolved "https://registry.yarnpkg.com/has-unicode/-/has-unicode-2.0.1.tgz#e0e6fe6a28cf51138855e086d1691e771de2a8b9"
+
+has-value@^0.3.1:
+ version "0.3.1"
+ resolved "https://registry.yarnpkg.com/has-value/-/has-value-0.3.1.tgz#7b1f58bada62ca827ec0a2078025654845995e1f"
+ dependencies:
+ get-value "^2.0.3"
+ has-values "^0.1.4"
+ isobject "^2.0.0"
+
+has-value@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/has-value/-/has-value-1.0.0.tgz#18b281da585b1c5c51def24c930ed29a0be6b177"
+ dependencies:
+ get-value "^2.0.6"
+ has-values "^1.0.0"
+ isobject "^3.0.0"
+
+has-values@^0.1.4:
+ version "0.1.4"
+ resolved "https://registry.yarnpkg.com/has-values/-/has-values-0.1.4.tgz#6d61de95d91dfca9b9a02089ad384bff8f62b771"
+
+has-values@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/has-values/-/has-values-1.0.0.tgz#95b0b63fec2146619a6fe57fe75628d5a39efe4f"
+ dependencies:
+ is-number "^3.0.0"
+ kind-of "^4.0.0"
+
+hawk@3.1.3, hawk@~3.1.3:
+ version "3.1.3"
+ resolved "https://registry.yarnpkg.com/hawk/-/hawk-3.1.3.tgz#078444bd7c1640b0fe540d2c9b73d59678e8e1c4"
+ dependencies:
+ boom "2.x.x"
+ cryptiles "2.x.x"
+ hoek "2.x.x"
+ sntp "1.x.x"
+
+he@1.1.1:
+ version "1.1.1"
+ resolved "https://registry.yarnpkg.com/he/-/he-1.1.1.tgz#93410fd21b009735151f8868c2f271f3427e23fd"
+
+hoek@2.x.x:
+ version "2.16.3"
+ resolved "https://registry.yarnpkg.com/hoek/-/hoek-2.16.3.tgz#20bb7403d3cea398e91dc4710a8ff1b8274a25ed"
+
+http-signature@~1.1.0:
+ version "1.1.1"
+ resolved "https://registry.yarnpkg.com/http-signature/-/http-signature-1.1.1.tgz#df72e267066cd0ac67fb76adf8e134a8fbcf91bf"
+ dependencies:
+ assert-plus "^0.2.0"
+ jsprim "^1.2.2"
+ sshpk "^1.7.0"
+
+iconv-lite@^0.4.4:
+ version "0.4.19"
+ resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.19.tgz#f7468f60135f5e5dad3399c0a81be9a1603a082b"
+
+inflight@^1.0.4:
+ version "1.0.6"
+ resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9"
+ dependencies:
+ once "^1.3.0"
+ wrappy "1"
+
+inherits@2, inherits@^2.0.1, inherits@~2.0.0, inherits@~2.0.3:
+ version "2.0.3"
+ resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de"
+
+ini@~1.3.0:
+ version "1.3.5"
+ resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.5.tgz#eee25f56db1c9ec6085e0c22778083f596abf927"
+
+interpret@^1.0.0:
+ version "1.1.0"
+ resolved "https://registry.yarnpkg.com/interpret/-/interpret-1.1.0.tgz#7ed1b1410c6a0e0f78cf95d3b8440c63f78b8614"
+
+is-accessor-descriptor@^0.1.6:
+ version "0.1.6"
+ resolved "https://registry.yarnpkg.com/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz#a9e12cb3ae8d876727eeef3843f8a0897b5c98d6"
+ dependencies:
+ kind-of "^3.0.2"
+
+is-accessor-descriptor@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz#169c2f6d3df1f992618072365c9b0ea1f6878656"
+ dependencies:
+ kind-of "^6.0.0"
+
+is-binary-path@^1.0.0:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/is-binary-path/-/is-binary-path-1.0.1.tgz#75f16642b480f187a711c814161fd3a4a7655898"
+ dependencies:
+ binary-extensions "^1.0.0"
+
+is-buffer@^1.1.5:
+ version "1.1.6"
+ resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-1.1.6.tgz#efaa2ea9daa0d7ab2ea13a97b2b8ad51fefbe8be"
+
+is-data-descriptor@^0.1.4:
+ version "0.1.4"
+ resolved "https://registry.yarnpkg.com/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz#0b5ee648388e2c860282e793f1856fec3f301b56"
+ dependencies:
+ kind-of "^3.0.2"
+
+is-data-descriptor@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz#d84876321d0e7add03990406abbbbd36ba9268c7"
+ dependencies:
+ kind-of "^6.0.0"
+
+is-descriptor@^0.1.0:
+ version "0.1.6"
+ resolved "https://registry.yarnpkg.com/is-descriptor/-/is-descriptor-0.1.6.tgz#366d8240dde487ca51823b1ab9f07a10a78251ca"
+ dependencies:
+ is-accessor-descriptor "^0.1.6"
+ is-data-descriptor "^0.1.4"
+ kind-of "^5.0.0"
+
+is-descriptor@^1.0.0, is-descriptor@^1.0.2:
+ version "1.0.2"
+ resolved "https://registry.yarnpkg.com/is-descriptor/-/is-descriptor-1.0.2.tgz#3b159746a66604b04f8c81524ba365c5f14d86ec"
+ dependencies:
+ is-accessor-descriptor "^1.0.0"
+ is-data-descriptor "^1.0.0"
+ kind-of "^6.0.2"
+
+is-extendable@^0.1.0, is-extendable@^0.1.1:
+ version "0.1.1"
+ resolved "https://registry.yarnpkg.com/is-extendable/-/is-extendable-0.1.1.tgz#62b110e289a471418e3ec36a617d472e301dfc89"
+
+is-extendable@^1.0.1:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/is-extendable/-/is-extendable-1.0.1.tgz#a7470f9e426733d81bd81e1155264e3a3507cab4"
+ dependencies:
+ is-plain-object "^2.0.4"
+
+is-extglob@^2.1.0, is-extglob@^2.1.1:
+ version "2.1.1"
+ resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2"
+
+is-fullwidth-code-point@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz#ef9e31386f031a7f0d643af82fde50c457ef00cb"
+ dependencies:
+ number-is-nan "^1.0.0"
+
+is-glob@^3.1.0:
+ version "3.1.0"
+ resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-3.1.0.tgz#7ba5ae24217804ac70707b96922567486cc3e84a"
+ dependencies:
+ is-extglob "^2.1.0"
+
+is-glob@^4.0.0:
+ version "4.0.0"
+ resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.0.tgz#9521c76845cc2610a85203ddf080a958c2ffabc0"
+ dependencies:
+ is-extglob "^2.1.1"
+
+is-number@^3.0.0:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/is-number/-/is-number-3.0.0.tgz#24fd6201a4782cf50561c810276afc7d12d71195"
+ dependencies:
+ kind-of "^3.0.2"
+
+is-number@^4.0.0:
+ version "4.0.0"
+ resolved "https://registry.yarnpkg.com/is-number/-/is-number-4.0.0.tgz#0026e37f5454d73e356dfe6564699867c6a7f0ff"
+
+is-odd@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/is-odd/-/is-odd-2.0.0.tgz#7646624671fd7ea558ccd9a2795182f2958f1b24"
+ dependencies:
+ is-number "^4.0.0"
+
+is-plain-object@^2.0.1, is-plain-object@^2.0.3, is-plain-object@^2.0.4:
+ version "2.0.4"
+ resolved "https://registry.yarnpkg.com/is-plain-object/-/is-plain-object-2.0.4.tgz#2c163b3fafb1b606d9d17928f05c2a1c38e07677"
+ dependencies:
+ isobject "^3.0.1"
+
+is-typedarray@~1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/is-typedarray/-/is-typedarray-1.0.0.tgz#e479c80858df0c1b11ddda6940f96011fcda4a9a"
+
+is-windows@^1.0.2:
+ version "1.0.2"
+ resolved "https://registry.yarnpkg.com/is-windows/-/is-windows-1.0.2.tgz#d1850eb9791ecd18e6182ce12a30f396634bb19d"
+
+is@^3.2.0:
+ version "3.2.1"
+ resolved "https://registry.yarnpkg.com/is/-/is-3.2.1.tgz#d0ac2ad55eb7b0bec926a5266f6c662aaa83dca5"
+
+isarray@1.0.0, isarray@~1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11"
+
+isobject@^2.0.0:
+ version "2.1.0"
+ resolved "https://registry.yarnpkg.com/isobject/-/isobject-2.1.0.tgz#f065561096a3f1da2ef46272f815c840d87e0c89"
+ dependencies:
+ isarray "1.0.0"
+
+isobject@^3.0.0, isobject@^3.0.1:
+ version "3.0.1"
+ resolved "https://registry.yarnpkg.com/isobject/-/isobject-3.0.1.tgz#4e431e92b11a9731636aa1f9c8d1ccbcfdab78df"
+
+isstream@~0.1.2:
+ version "0.1.2"
+ resolved "https://registry.yarnpkg.com/isstream/-/isstream-0.1.2.tgz#47e63f7af55afa6f92e1500e690eb8b8529c099a"
+
+jsbn@~0.1.0:
+ version "0.1.1"
+ resolved "https://registry.yarnpkg.com/jsbn/-/jsbn-0.1.1.tgz#a5e654c2e5a2deb5f201d96cefbca80c0ef2f513"
+
+json-schema@0.2.3:
+ version "0.2.3"
+ resolved "https://registry.yarnpkg.com/json-schema/-/json-schema-0.2.3.tgz#b480c892e59a2f05954ce727bd3f2a4e882f9e13"
+
+json-stable-stringify@^1.0.1:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/json-stable-stringify/-/json-stable-stringify-1.0.1.tgz#9a759d39c5f2ff503fd5300646ed445f88c4f9af"
+ dependencies:
+ jsonify "~0.0.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"
+
+json3@3.3.2:
+ version "3.3.2"
+ resolved "https://registry.yarnpkg.com/json3/-/json3-3.3.2.tgz#3c0434743df93e2f5c42aee7b19bcb483575f4e1"
+
+jsonfile@^4.0.0:
+ version "4.0.0"
+ resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-4.0.0.tgz#8771aae0799b64076b76640fca058f9c10e33ecb"
+ optionalDependencies:
+ graceful-fs "^4.1.6"
+
+jsonify@~0.0.0:
+ version "0.0.0"
+ resolved "https://registry.yarnpkg.com/jsonify/-/jsonify-0.0.0.tgz#2c74b6ee41d93ca51b7b5aaee8f503631d252a73"
+
+jsprim@^1.2.2:
+ version "1.4.1"
+ resolved "https://registry.yarnpkg.com/jsprim/-/jsprim-1.4.1.tgz#313e66bc1e5cc06e438bc1b7499c2e5c56acb6a2"
+ dependencies:
+ assert-plus "1.0.0"
+ extsprintf "1.3.0"
+ json-schema "0.2.3"
+ verror "1.10.0"
+
+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"
+ 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.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"
+ resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-3.2.2.tgz#31ea21a734bab9bbb0f32466d893aea51e4a3c64"
+ dependencies:
+ is-buffer "^1.1.5"
+
+kind-of@^4.0.0:
+ version "4.0.0"
+ resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-4.0.0.tgz#20813df3d712928b207378691a45066fae72dd57"
+ dependencies:
+ is-buffer "^1.1.5"
+
+kind-of@^5.0.0:
+ version "5.1.0"
+ resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-5.1.0.tgz#729c91e2d857b7a419a1f9aa65685c4c33f5845d"
+
+kind-of@^6.0.0, kind-of@^6.0.2:
+ version "6.0.2"
+ resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-6.0.2.tgz#01146b36a6218e64e58f3a8d66de5d7fc6f6d051"
+
+lazy@~1.0.11:
+ version "1.0.11"
+ resolved "https://registry.yarnpkg.com/lazy/-/lazy-1.0.11.tgz#daa068206282542c088288e975c297c1ae77b690"
+
+lodash._baseassign@^3.0.0:
+ version "3.2.0"
+ resolved "https://registry.yarnpkg.com/lodash._baseassign/-/lodash._baseassign-3.2.0.tgz#8c38a099500f215ad09e59f1722fd0c52bfe0a4e"
+ dependencies:
+ lodash._basecopy "^3.0.0"
+ lodash.keys "^3.0.0"
+
+lodash._basecopy@^3.0.0:
+ version "3.0.1"
+ resolved "https://registry.yarnpkg.com/lodash._basecopy/-/lodash._basecopy-3.0.1.tgz#8da0e6a876cf344c0ad8a54882111dd3c5c7ca36"
+
+lodash._basecreate@^3.0.0:
+ version "3.0.3"
+ resolved "https://registry.yarnpkg.com/lodash._basecreate/-/lodash._basecreate-3.0.3.tgz#1bc661614daa7fc311b7d03bf16806a0213cf821"
+
+lodash._getnative@^3.0.0:
+ version "3.9.1"
+ resolved "https://registry.yarnpkg.com/lodash._getnative/-/lodash._getnative-3.9.1.tgz#570bc7dede46d61cdcde687d65d3eecbaa3aaff5"
+
+lodash._isiterateecall@^3.0.0:
+ version "3.0.9"
+ resolved "https://registry.yarnpkg.com/lodash._isiterateecall/-/lodash._isiterateecall-3.0.9.tgz#5203ad7ba425fae842460e696db9cf3e6aac057c"
+
+lodash.create@3.1.1:
+ version "3.1.1"
+ resolved "https://registry.yarnpkg.com/lodash.create/-/lodash.create-3.1.1.tgz#d7f2849f0dbda7e04682bb8cd72ab022461debe7"
+ dependencies:
+ lodash._baseassign "^3.0.0"
+ lodash._basecreate "^3.0.0"
+ lodash._isiterateecall "^3.0.0"
+
+lodash.findindex@^4.4.0:
+ version "4.6.0"
+ resolved "https://registry.yarnpkg.com/lodash.findindex/-/lodash.findindex-4.6.0.tgz#a3245dee61fb9b6e0624b535125624bb69c11106"
+
+lodash.isarguments@^3.0.0:
+ version "3.1.0"
+ resolved "https://registry.yarnpkg.com/lodash.isarguments/-/lodash.isarguments-3.1.0.tgz#2f573d85c6a24289ff00663b491c1d338ff3458a"
+
+lodash.isarray@^3.0.0:
+ version "3.0.4"
+ resolved "https://registry.yarnpkg.com/lodash.isarray/-/lodash.isarray-3.0.4.tgz#79e4eb88c36a8122af86f844aa9bcd851b5fbb55"
+
+lodash.isequal@^4.0.0:
+ version "4.5.0"
+ resolved "https://registry.yarnpkg.com/lodash.isequal/-/lodash.isequal-4.5.0.tgz#415c4478f2bcc30120c22ce10ed3226f7d3e18e0"
+
+lodash.keys@^3.0.0:
+ version "3.1.2"
+ resolved "https://registry.yarnpkg.com/lodash.keys/-/lodash.keys-3.1.2.tgz#4dbc0472b156be50a0b286855d1bd0b0c656098a"
+ dependencies:
+ lodash._getnative "^3.0.0"
+ lodash.isarguments "^3.0.0"
+ lodash.isarray "^3.0.0"
+
+lodash.merge@^4.6.0:
+ version "4.6.1"
+ resolved "https://registry.yarnpkg.com/lodash.merge/-/lodash.merge-4.6.1.tgz#adc25d9cb99b9391c59624f379fbba60d7111d54"
+
+lodash@^4.14.0:
+ version "4.17.5"
+ resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.5.tgz#99a92d65c0272debe8c96b6057bc8fbfa3bed511"
+
+map-cache@^0.2.2:
+ version "0.2.2"
+ resolved "https://registry.yarnpkg.com/map-cache/-/map-cache-0.2.2.tgz#c32abd0bd6525d9b051645bb4f26ac5dc98a0dbf"
+
+map-visit@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/map-visit/-/map-visit-1.0.0.tgz#ecdca8f13144e660f1b5bd41f12f3479d98dfb8f"
+ dependencies:
+ object-visit "^1.0.0"
+
+methods@^1.1.1:
+ version "1.1.2"
+ resolved "https://registry.yarnpkg.com/methods/-/methods-1.1.2.tgz#5529a4d67654134edcc5266656835b0f851afcee"
+
+micromatch@^3.1.4:
+ version "3.1.9"
+ resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-3.1.9.tgz#15dc93175ae39e52e93087847096effc73efcf89"
+ dependencies:
+ arr-diff "^4.0.0"
+ array-unique "^0.3.2"
+ braces "^2.3.1"
+ define-property "^2.0.2"
+ extend-shallow "^3.0.2"
+ extglob "^2.0.4"
+ fragment-cache "^0.2.1"
+ kind-of "^6.0.2"
+ nanomatch "^1.2.9"
+ object.pick "^1.3.0"
+ regex-not "^1.0.0"
+ snapdragon "^0.8.1"
+ to-regex "^3.0.1"
+
+mime-db@~1.33.0:
+ version "1.33.0"
+ resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.33.0.tgz#a3492050a5cb9b63450541e39d9788d2272783db"
+
+mime-types@^2.1.12, mime-types@~2.1.7:
+ version "2.1.18"
+ resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.18.tgz#6f323f60a83d11146f831ff11fd66e2fe5503bb8"
+ dependencies:
+ mime-db "~1.33.0"
+
+minimatch@^3.0.0, minimatch@^3.0.2, minimatch@^3.0.4:
+ version "3.0.4"
+ resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083"
+ dependencies:
+ brace-expansion "^1.1.7"
+
+minimist@0.0.8:
+ version "0.0.8"
+ resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.0.8.tgz#857fcabfc3397d2625b8228262e86aa7a011b05d"
+
+minimist@^1.2.0:
+ version "1.2.0"
+ resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.0.tgz#a35008b20f41383eec1fb914f4cd5df79a264284"
+
+mixin-deep@^1.2.0:
+ version "1.3.1"
+ resolved "https://registry.yarnpkg.com/mixin-deep/-/mixin-deep-1.3.1.tgz#a49e7268dce1a0d9698e45326c5626df3543d0fe"
+ dependencies:
+ for-in "^1.0.2"
+ is-extendable "^1.0.1"
+
+mkdirp@0.5.1, "mkdirp@>=0.5 0", mkdirp@^0.5.1:
+ version "0.5.1"
+ resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.1.tgz#30057438eac6cf7f8c4767f38648d6697d75c903"
+ dependencies:
+ minimist "0.0.8"
+
+mocha@^3.5:
+ version "3.5.3"
+ resolved "https://registry.yarnpkg.com/mocha/-/mocha-3.5.3.tgz#1e0480fe36d2da5858d1eb6acc38418b26eaa20d"
+ dependencies:
+ browser-stdout "1.3.0"
+ commander "2.9.0"
+ debug "2.6.8"
+ diff "3.2.0"
+ escape-string-regexp "1.0.5"
+ glob "7.1.1"
+ growl "1.9.2"
+ he "1.1.1"
+ json3 "3.3.2"
+ lodash.create "3.1.1"
+ mkdirp "0.5.1"
+ supports-color "3.1.2"
+
+moment-timezone@^0.5.x:
+ version "0.5.14"
+ resolved "https://registry.yarnpkg.com/moment-timezone/-/moment-timezone-0.5.14.tgz#4eb38ff9538b80108ba467a458f3ed4268ccfcb1"
+ dependencies:
+ moment ">= 2.9.0"
+
+"moment@>= 2.9.0", moment@^2.19, moment@^2.21.0:
+ version "2.21.0"
+ resolved "https://registry.yarnpkg.com/moment/-/moment-2.21.0.tgz#2a114b51d2a6ec9e6d83cf803f838a878d8a023a"
+
+ms@0.7.1:
+ version "0.7.1"
+ resolved "https://registry.yarnpkg.com/ms/-/ms-0.7.1.tgz#9cd13c03adbff25b65effde7ce864ee952017098"
+
+ms@2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8"
+
+mute-stream@~0.0.4:
+ version "0.0.7"
+ resolved "https://registry.yarnpkg.com/mute-stream/-/mute-stream-0.0.7.tgz#3075ce93bc21b8fab43e1bc4da7e8115ed1e7bab"
+
+nan@^2.3.0:
+ version "2.10.0"
+ resolved "https://registry.yarnpkg.com/nan/-/nan-2.10.0.tgz#96d0cd610ebd58d4b4de9cc0c6828cda99c7548f"
+
+nanomatch@^1.2.9:
+ version "1.2.9"
+ resolved "https://registry.yarnpkg.com/nanomatch/-/nanomatch-1.2.9.tgz#879f7150cb2dab7a471259066c104eee6e0fa7c2"
+ dependencies:
+ arr-diff "^4.0.0"
+ array-unique "^0.3.2"
+ define-property "^2.0.2"
+ extend-shallow "^3.0.2"
+ fragment-cache "^0.2.1"
+ is-odd "^2.0.0"
+ is-windows "^1.0.2"
+ kind-of "^6.0.2"
+ object.pick "^1.3.0"
+ regex-not "^1.0.0"
+ snapdragon "^0.8.1"
+ to-regex "^3.0.1"
+
+needle@^2.2.0:
+ version "2.2.0"
+ resolved "https://registry.yarnpkg.com/needle/-/needle-2.2.0.tgz#f14efc69cee1024b72c8b21c7bdf94a731dc12fa"
+ dependencies:
+ debug "^2.1.2"
+ iconv-lite "^0.4.4"
+ sax "^1.2.4"
+
+node-pre-gyp@^0.6.39:
+ version "0.6.39"
+ resolved "https://registry.yarnpkg.com/node-pre-gyp/-/node-pre-gyp-0.6.39.tgz#c00e96860b23c0e1420ac7befc5044e1d78d8649"
+ dependencies:
+ detect-libc "^1.0.2"
+ hawk "3.1.3"
+ mkdirp "^0.5.1"
+ nopt "^4.0.1"
+ npmlog "^4.0.2"
+ rc "^1.1.7"
+ request "2.81.0"
+ rimraf "^2.6.1"
+ semver "^5.3.0"
+ tar "^2.2.1"
+ tar-pack "^3.4.0"
+
+nopt@^4.0.1:
+ version "4.0.1"
+ resolved "https://registry.yarnpkg.com/nopt/-/nopt-4.0.1.tgz#d0d4685afd5415193c8c7505602d0d17cd64474d"
+ dependencies:
+ abbrev "1"
+ osenv "^0.1.4"
+
+normalize-path@^2.1.1:
+ version "2.1.1"
+ resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-2.1.1.tgz#1ab28b556e198363a8c1a6f7e6fa20137fe6aed9"
+ dependencies:
+ remove-trailing-separator "^1.0.1"
+
+npmlog@^4.0.2:
+ version "4.1.2"
+ resolved "https://registry.yarnpkg.com/npmlog/-/npmlog-4.1.2.tgz#08a7f2a8bf734604779a9efa4ad5cc717abb954b"
+ dependencies:
+ are-we-there-yet "~1.1.2"
+ console-control-strings "~1.1.0"
+ gauge "~2.7.3"
+ set-blocking "~2.0.0"
+
+nssocket@0.6.0, nssocket@^0.6.0:
+ version "0.6.0"
+ resolved "https://registry.yarnpkg.com/nssocket/-/nssocket-0.6.0.tgz#59f96f6ff321566f33c70f7dbeeecdfdc07154fa"
+ dependencies:
+ eventemitter2 "~0.4.14"
+ lazy "~1.0.11"
+
+number-is-nan@^1.0.0:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/number-is-nan/-/number-is-nan-1.0.1.tgz#097b602b53422a522c1afb8790318336941a011d"
+
+oauth-sign@~0.8.1:
+ version "0.8.2"
+ resolved "https://registry.yarnpkg.com/oauth-sign/-/oauth-sign-0.8.2.tgz#46a6ab7f0aead8deae9ec0565780b7d4efeb9d43"
+
+object-assign@^4.1.0:
+ version "4.1.1"
+ resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863"
+
+object-copy@^0.1.0:
+ version "0.1.0"
+ resolved "https://registry.yarnpkg.com/object-copy/-/object-copy-0.1.0.tgz#7e7d858b781bd7c991a41ba975ed3812754e998c"
+ dependencies:
+ copy-descriptor "^0.1.0"
+ define-property "^0.2.5"
+ kind-of "^3.0.3"
+
+object-visit@^1.0.0:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/object-visit/-/object-visit-1.0.1.tgz#f79c4493af0c5377b59fe39d395e41042dd045bb"
+ dependencies:
+ isobject "^3.0.0"
+
+object.pick@^1.3.0:
+ version "1.3.0"
+ resolved "https://registry.yarnpkg.com/object.pick/-/object.pick-1.3.0.tgz#87a10ac4c1694bd2e1cbf53591a66141fb5dd747"
+ dependencies:
+ isobject "^3.0.1"
+
+once@^1.3.0, once@^1.3.3:
+ version "1.4.0"
+ resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1"
+ dependencies:
+ wrappy "1"
+
+os-homedir@^1.0.0:
+ version "1.0.2"
+ resolved "https://registry.yarnpkg.com/os-homedir/-/os-homedir-1.0.2.tgz#ffbc4988336e0e833de0c168c7ef152121aa7fb3"
+
+os-tmpdir@^1.0.0:
+ version "1.0.2"
+ resolved "https://registry.yarnpkg.com/os-tmpdir/-/os-tmpdir-1.0.2.tgz#bbe67406c79aa85c5cfec766fe5734555dfa1274"
+
+osenv@^0.1.4:
+ version "0.1.5"
+ resolved "https://registry.yarnpkg.com/osenv/-/osenv-0.1.5.tgz#85cdfafaeb28e8677f416e287592b5f3f49ea410"
+ dependencies:
+ os-homedir "^1.0.0"
+ os-tmpdir "^1.0.0"
+
+pascalcase@^0.1.1:
+ version "0.1.1"
+ resolved "https://registry.yarnpkg.com/pascalcase/-/pascalcase-0.1.1.tgz#b363e55e8006ca6fe21784d2db22bd15d7917f14"
+
+path-dirname@^1.0.0:
+ version "1.0.2"
+ resolved "https://registry.yarnpkg.com/path-dirname/-/path-dirname-1.0.2.tgz#cc33d24d525e099a5388c0336c6e32b9160609e0"
+
+path-is-absolute@^1.0.0:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f"
+
+path-parse@^1.0.5:
+ version "1.0.5"
+ resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.5.tgz#3c1adf871ea9cd6c9431b6ea2bd74a0ff055c4c1"
+
+performance-now@^0.2.0:
+ version "0.2.0"
+ resolved "https://registry.yarnpkg.com/performance-now/-/performance-now-0.2.0.tgz#33ef30c5c77d4ea21c5a53869d91b56d8f2555e5"
+
+pidusage@^2.0.6:
+ version "2.0.6"
+ resolved "https://registry.yarnpkg.com/pidusage/-/pidusage-2.0.6.tgz#32bc37e57ca828f46b1c1e679a9cfc56ef945850"
+
+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"
+
+pm2-axon@3.0.2:
+ version "3.0.2"
+ resolved "https://registry.yarnpkg.com/pm2-axon/-/pm2-axon-3.0.2.tgz#53de1d34edbf266d58f6b1dea2d8244c71ad24b9"
+ dependencies:
+ amp "~0.3.1"
+ amp-message "~0.1.1"
+ debug "~2.2.0"
+ escape-regexp "0.0.1"
+
+pm2-axon@3.1.0:
+ version "3.1.0"
+ resolved "https://registry.yarnpkg.com/pm2-axon/-/pm2-axon-3.1.0.tgz#1b4527f3385e203adc1a5b0488bb52f0322731da"
+ dependencies:
+ amp "~0.3.1"
+ amp-message "~0.1.1"
+ debug "^3.0"
+ escape-regexp "0.0.1"
+
+pm2-deploy@^0.3.9:
+ version "0.3.9"
+ resolved "https://registry.yarnpkg.com/pm2-deploy/-/pm2-deploy-0.3.9.tgz#adeee775c56d52b8f251ba9b0abe0db50a01dfc7"
+ dependencies:
+ async "^1.5"
+ tv4 "^1.3"
+
+pm2-multimeter@^0.1.2:
+ version "0.1.2"
+ resolved "https://registry.yarnpkg.com/pm2-multimeter/-/pm2-multimeter-0.1.2.tgz#1a1e55153d41a05534cea23cfe860abaa0eb4ace"
+ dependencies:
+ charm "~0.1.1"
+
+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"
+
+process-nextick-args@~2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-2.0.0.tgz#a37d732f4271b4ab1ad070d35508e8290788ffaa"
+
+promptly@2.2.0:
+ version "2.2.0"
+ resolved "https://registry.yarnpkg.com/promptly/-/promptly-2.2.0.tgz#2a13fa063688a2a5983b161fff0108a07d26fc74"
+ dependencies:
+ read "^1.0.4"
+
+punycode@^1.4.1:
+ version "1.4.1"
+ resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.4.1.tgz#c0d5a63b2718800ad8e1eb0fa5269c84dd41845e"
+
+qs@~6.4.0:
+ version "6.4.0"
+ resolved "https://registry.yarnpkg.com/qs/-/qs-6.4.0.tgz#13e26d28ad6b0ffaa91312cd3bf708ed351e7233"
+
+rc@^1.1.7:
+ version "1.2.6"
+ resolved "https://registry.yarnpkg.com/rc/-/rc-1.2.6.tgz#eb18989c6d4f4f162c399f79ddd29f3835568092"
+ dependencies:
+ deep-extend "~0.4.0"
+ ini "~1.3.0"
+ minimist "^1.2.0"
+ strip-json-comments "~2.0.1"
+
+read@^1.0.4:
+ version "1.0.7"
+ resolved "https://registry.yarnpkg.com/read/-/read-1.0.7.tgz#b3da19bd052431a97671d44a42634adf710b40c4"
+ dependencies:
+ mute-stream "~0.0.4"
+
+readable-stream@^2.0.2, readable-stream@^2.0.6, readable-stream@^2.1.4:
+ version "2.3.5"
+ resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.5.tgz#b4f85003a938cbb6ecbce2a124fb1012bd1a838d"
+ dependencies:
+ core-util-is "~1.0.0"
+ inherits "~2.0.3"
+ isarray "~1.0.0"
+ process-nextick-args "~2.0.0"
+ safe-buffer "~5.1.1"
+ string_decoder "~1.0.3"
+ util-deprecate "~1.0.1"
+
+readdirp@^2.0.0:
+ version "2.1.0"
+ resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-2.1.0.tgz#4ed0ad060df3073300c48440373f72d1cc642d78"
+ dependencies:
+ graceful-fs "^4.1.2"
+ minimatch "^3.0.2"
+ readable-stream "^2.0.2"
+ set-immediate-shim "^1.0.1"
+
+rechoir@^0.6.2:
+ version "0.6.2"
+ resolved "https://registry.yarnpkg.com/rechoir/-/rechoir-0.6.2.tgz#85204b54dba82d5742e28c96756ef43af50e3384"
+ dependencies:
+ resolve "^1.1.6"
+
+regex-not@^1.0.0, regex-not@^1.0.2:
+ version "1.0.2"
+ resolved "https://registry.yarnpkg.com/regex-not/-/regex-not-1.0.2.tgz#1f4ece27e00b0b65e0247a6810e6a85d83a5752c"
+ dependencies:
+ extend-shallow "^3.0.2"
+ safe-regex "^1.1.0"
+
+remove-trailing-separator@^1.0.1:
+ version "1.1.0"
+ resolved "https://registry.yarnpkg.com/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz#c24bce2a283adad5bc3f58e0d48249b92379d8ef"
+
+repeat-element@^1.1.2:
+ version "1.1.2"
+ resolved "https://registry.yarnpkg.com/repeat-element/-/repeat-element-1.1.2.tgz#ef089a178d1483baae4d93eb98b4f9e4e11d990a"
+
+repeat-string@^1.6.1:
+ version "1.6.1"
+ resolved "https://registry.yarnpkg.com/repeat-string/-/repeat-string-1.6.1.tgz#8dcae470e1c88abc2d600fff4a776286da75e637"
+
+request@2.81.0:
+ version "2.81.0"
+ resolved "https://registry.yarnpkg.com/request/-/request-2.81.0.tgz#c6928946a0e06c5f8d6f8a9333469ffda46298a0"
+ dependencies:
+ aws-sign2 "~0.6.0"
+ aws4 "^1.2.1"
+ caseless "~0.12.0"
+ combined-stream "~1.0.5"
+ extend "~3.0.0"
+ forever-agent "~0.6.1"
+ form-data "~2.1.1"
+ har-validator "~4.2.1"
+ hawk "~3.1.3"
+ http-signature "~1.1.0"
+ is-typedarray "~1.0.0"
+ isstream "~0.1.2"
+ json-stringify-safe "~5.0.1"
+ mime-types "~2.1.7"
+ oauth-sign "~0.8.1"
+ performance-now "^0.2.0"
+ qs "~6.4.0"
+ safe-buffer "^5.0.1"
+ stringstream "~0.0.4"
+ tough-cookie "~2.3.0"
+ tunnel-agent "^0.6.0"
+ uuid "^3.0.0"
+
+resolve-url@^0.2.1:
+ version "0.2.1"
+ resolved "https://registry.yarnpkg.com/resolve-url/-/resolve-url-0.2.1.tgz#2c637fe77c893afd2a663fe21aa9080068e2052a"
+
+resolve@^1.1.6:
+ version "1.6.0"
+ resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.6.0.tgz#0fbd21278b27b4004481c395349e7aba60a9ff5c"
+ dependencies:
+ path-parse "^1.0.5"
+
+ret@~0.1.10:
+ version "0.1.15"
+ resolved "https://registry.yarnpkg.com/ret/-/ret-0.1.15.tgz#b8a4825d5bdb1fc3f6f53c2bc33f81388681c7bc"
+
+rimraf@2, rimraf@^2.5.1, rimraf@^2.6.1:
+ version "2.6.2"
+ resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.6.2.tgz#2ed8150d24a16ea8651e6d6ef0f47c4158ce7a36"
+ dependencies:
+ glob "^7.0.5"
+
+safe-buffer@^5.0.1, safe-buffer@~5.1.0, safe-buffer@~5.1.1:
+ version "5.1.1"
+ resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.1.tgz#893312af69b2123def71f57889001671eeb2c853"
+
+safe-regex@^1.1.0:
+ version "1.1.0"
+ resolved "https://registry.yarnpkg.com/safe-regex/-/safe-regex-1.1.0.tgz#40a3669f3b077d1e943d44629e157dd48023bf2e"
+ dependencies:
+ ret "~0.1.10"
+
+sax@^1.2.4:
+ version "1.2.4"
+ resolved "https://registry.yarnpkg.com/sax/-/sax-1.2.4.tgz#2816234e2378bddc4e5354fab5caa895df7100d9"
+
+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"
+
+set-blocking@~2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/set-blocking/-/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7"
+
+set-immediate-shim@^1.0.1:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/set-immediate-shim/-/set-immediate-shim-1.0.1.tgz#4b2b1b27eb808a9f8dcc481a58e5e56f599f3f61"
+
+set-value@^0.4.3:
+ version "0.4.3"
+ resolved "https://registry.yarnpkg.com/set-value/-/set-value-0.4.3.tgz#7db08f9d3d22dc7f78e53af3c3bf4666ecdfccf1"
+ dependencies:
+ extend-shallow "^2.0.1"
+ is-extendable "^0.1.1"
+ is-plain-object "^2.0.1"
+ to-object-path "^0.3.0"
+
+set-value@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/set-value/-/set-value-2.0.0.tgz#71ae4a88f0feefbbf52d1ea604f3fb315ebb6274"
+ dependencies:
+ extend-shallow "^2.0.1"
+ is-extendable "^0.1.1"
+ is-plain-object "^2.0.3"
+ split-string "^3.0.1"
+
+shelljs@0.8.1:
+ version "0.8.1"
+ resolved "https://registry.yarnpkg.com/shelljs/-/shelljs-0.8.1.tgz#729e038c413a2254c4078b95ed46e0397154a9f1"
+ dependencies:
+ glob "^7.0.0"
+ interpret "^1.0.0"
+ rechoir "^0.6.2"
+
+shimmer@^1.0.0, shimmer@^1.1.0, shimmer@^1.2.0:
+ version "1.2.0"
+ resolved "https://registry.yarnpkg.com/shimmer/-/shimmer-1.2.0.tgz#f966f7555789763e74d8841193685a5e78736665"
+
+should-equal@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/should-equal/-/should-equal-2.0.0.tgz#6072cf83047360867e68e98b09d71143d04ee0c3"
+ dependencies:
+ should-type "^1.4.0"
+
+should-format@^3.0.3:
+ version "3.0.3"
+ resolved "https://registry.yarnpkg.com/should-format/-/should-format-3.0.3.tgz#9bfc8f74fa39205c53d38c34d717303e277124f1"
+ dependencies:
+ should-type "^1.3.0"
+ should-type-adaptors "^1.0.1"
+
+should-type-adaptors@^1.0.1:
+ version "1.1.0"
+ resolved "https://registry.yarnpkg.com/should-type-adaptors/-/should-type-adaptors-1.1.0.tgz#401e7f33b5533033944d5cd8bf2b65027792e27a"
+ dependencies:
+ should-type "^1.3.0"
+ should-util "^1.0.0"
+
+should-type@^1.3.0, should-type@^1.4.0:
+ version "1.4.0"
+ resolved "https://registry.yarnpkg.com/should-type/-/should-type-1.4.0.tgz#0756d8ce846dfd09843a6947719dfa0d4cff5cf3"
+
+should-util@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/should-util/-/should-util-1.0.0.tgz#c98cda374aa6b190df8ba87c9889c2b4db620063"
+
+should@^13:
+ version "13.2.1"
+ resolved "https://registry.yarnpkg.com/should/-/should-13.2.1.tgz#84e6ebfbb145c79e0ae42307b25b3f62dcaf574e"
+ dependencies:
+ should-equal "^2.0.0"
+ should-format "^3.0.3"
+ should-type "^1.4.0"
+ should-type-adaptors "^1.0.1"
+ should-util "^1.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"
+
+snapdragon-node@^2.0.1:
+ version "2.1.1"
+ resolved "https://registry.yarnpkg.com/snapdragon-node/-/snapdragon-node-2.1.1.tgz#6c175f86ff14bdb0724563e8f3c1b021a286853b"
+ dependencies:
+ define-property "^1.0.0"
+ isobject "^3.0.0"
+ snapdragon-util "^3.0.1"
+
+snapdragon-util@^3.0.1:
+ version "3.0.1"
+ resolved "https://registry.yarnpkg.com/snapdragon-util/-/snapdragon-util-3.0.1.tgz#f956479486f2acd79700693f6f7b805e45ab56e2"
+ dependencies:
+ kind-of "^3.2.0"
+
+snapdragon@^0.8.1:
+ version "0.8.2"
+ resolved "https://registry.yarnpkg.com/snapdragon/-/snapdragon-0.8.2.tgz#64922e7c565b0e14204ba1aa7d6964278d25182d"
+ dependencies:
+ base "^0.11.1"
+ debug "^2.2.0"
+ define-property "^0.2.5"
+ extend-shallow "^2.0.1"
+ map-cache "^0.2.2"
+ source-map "^0.5.6"
+ source-map-resolve "^0.5.0"
+ use "^3.1.0"
+
+sntp@1.x.x:
+ version "1.0.9"
+ resolved "https://registry.yarnpkg.com/sntp/-/sntp-1.0.9.tgz#6541184cc90aeea6c6e7b35e2659082443c66198"
+ dependencies:
+ hoek "2.x.x"
+
+source-map-resolve@^0.5.0:
+ version "0.5.1"
+ resolved "https://registry.yarnpkg.com/source-map-resolve/-/source-map-resolve-0.5.1.tgz#7ad0f593f2281598e854df80f19aae4b92d7a11a"
+ dependencies:
+ atob "^2.0.0"
+ decode-uri-component "^0.2.0"
+ resolve-url "^0.2.1"
+ source-map-url "^0.4.0"
+ urix "^0.1.0"
+
+source-map-support@^0.5:
+ version "0.5.4"
+ resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.4.tgz#54456efa89caa9270af7cd624cc2f123e51fbae8"
+ dependencies:
+ source-map "^0.6.0"
+
+source-map-url@^0.4.0:
+ version "0.4.0"
+ resolved "https://registry.yarnpkg.com/source-map-url/-/source-map-url-0.4.0.tgz#3e935d7ddd73631b97659956d55128e87b5084a3"
+
+source-map@^0.5.6:
+ version "0.5.7"
+ resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.7.tgz#8a039d2d1021d22d1ea14c80d8ea468ba2ef3fcc"
+
+source-map@^0.6.0:
+ version "0.6.1"
+ resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263"
+
+split-string@^3.0.1, split-string@^3.0.2:
+ version "3.1.0"
+ resolved "https://registry.yarnpkg.com/split-string/-/split-string-3.1.0.tgz#7cb09dda3a86585705c64b39a6466038682e8fe2"
+ dependencies:
+ extend-shallow "^3.0.0"
+
+sprintf-js@1.1.1:
+ version "1.1.1"
+ resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.1.1.tgz#36be78320afe5801f6cea3ee78b6e5aab940ea0c"
+
+sprintf-js@~1.0.2:
+ version "1.0.3"
+ resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c"
+
+sshpk@^1.7.0:
+ version "1.14.1"
+ resolved "https://registry.yarnpkg.com/sshpk/-/sshpk-1.14.1.tgz#130f5975eddad963f1d56f92b9ac6c51fa9f83eb"
+ dependencies:
+ asn1 "~0.2.3"
+ assert-plus "^1.0.0"
+ dashdash "^1.12.0"
+ getpass "^0.1.1"
+ optionalDependencies:
+ bcrypt-pbkdf "^1.0.0"
+ ecc-jsbn "~0.1.1"
+ jsbn "~0.1.0"
+ tweetnacl "~0.14.0"
+
+static-extend@^0.1.1:
+ version "0.1.2"
+ resolved "https://registry.yarnpkg.com/static-extend/-/static-extend-0.1.2.tgz#60809c39cbff55337226fd5e0b520f341f1fb5c6"
+ dependencies:
+ define-property "^0.2.5"
+ object-copy "^0.1.0"
+
+string-width@^1.0.1, string-width@^1.0.2:
+ version "1.0.2"
+ resolved "https://registry.yarnpkg.com/string-width/-/string-width-1.0.2.tgz#118bdf5b8cdc51a2a7e70d211e07e2b0b9b107d3"
+ dependencies:
+ code-point-at "^1.0.0"
+ is-fullwidth-code-point "^1.0.0"
+ strip-ansi "^3.0.0"
+
+string_decoder@~1.0.3:
+ version "1.0.3"
+ resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.0.3.tgz#0fc67d7c141825de94282dd536bec6b9bce860ab"
+ dependencies:
+ safe-buffer "~5.1.0"
+
+stringstream@~0.0.4:
+ version "0.0.5"
+ resolved "https://registry.yarnpkg.com/stringstream/-/stringstream-0.0.5.tgz#4e484cd4de5a0bbbee18e46307710a8a81621878"
+
+strip-ansi@^3.0.0, strip-ansi@^3.0.1:
+ version "3.0.1"
+ resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-3.0.1.tgz#6a385fb8853d952d5ff05d0e8aaf94278dc63dcf"
+ dependencies:
+ ansi-regex "^2.0.0"
+
+strip-json-comments@~2.0.1:
+ version "2.0.1"
+ resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-2.0.1.tgz#3c531942e908c2697c0ec344858c286c7ca0a60a"
+
+supports-color@3.1.2:
+ version "3.1.2"
+ resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-3.1.2.tgz#72a262894d9d408b956ca05ff37b2ed8a6e2a2d5"
+ dependencies:
+ has-flag "^1.0.0"
+
+supports-color@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-2.0.0.tgz#535d045ce6b6363fa40117084629995e9df324c7"
+
+supports-color@^5.3.0:
+ version "5.3.0"
+ resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.3.0.tgz#5b24ac15db80fa927cf5227a4a33fd3c4c7676c0"
+ dependencies:
+ has-flag "^3.0.0"
+
+tar-pack@^3.4.0:
+ version "3.4.1"
+ resolved "https://registry.yarnpkg.com/tar-pack/-/tar-pack-3.4.1.tgz#e1dbc03a9b9d3ba07e896ad027317eb679a10a1f"
+ dependencies:
+ debug "^2.2.0"
+ fstream "^1.0.10"
+ fstream-ignore "^1.0.5"
+ once "^1.3.3"
+ readable-stream "^2.1.4"
+ rimraf "^2.5.1"
+ tar "^2.2.1"
+ uid-number "^0.0.6"
+
+tar@^2.2.1:
+ version "2.2.1"
+ resolved "https://registry.yarnpkg.com/tar/-/tar-2.2.1.tgz#8e4d2a256c0e2185c6b18ad694aec968b83cb1d1"
+ dependencies:
+ block-stream "*"
+ fstream "^1.0.2"
+ inherits "2"
+
+to-object-path@^0.3.0:
+ version "0.3.0"
+ resolved "https://registry.yarnpkg.com/to-object-path/-/to-object-path-0.3.0.tgz#297588b7b0e7e0ac08e04e672f85c1f4999e17af"
+ dependencies:
+ kind-of "^3.0.2"
+
+to-regex-range@^2.1.0:
+ version "2.1.1"
+ resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-2.1.1.tgz#7c80c17b9dfebe599e27367e0d4dd5590141db38"
+ dependencies:
+ is-number "^3.0.0"
+ repeat-string "^1.6.1"
+
+to-regex@^3.0.1:
+ version "3.0.2"
+ resolved "https://registry.yarnpkg.com/to-regex/-/to-regex-3.0.2.tgz#13cfdd9b336552f30b51f33a8ae1b42a7a7599ce"
+ dependencies:
+ define-property "^2.0.2"
+ extend-shallow "^3.0.2"
+ regex-not "^1.0.2"
+ safe-regex "^1.1.0"
+
+tough-cookie@~2.3.0:
+ version "2.3.4"
+ resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-2.3.4.tgz#ec60cee38ac675063ffc97a5c18970578ee83655"
+ 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"
+ dependencies:
+ safe-buffer "^5.0.1"
+
+tv4@^1.3:
+ version "1.3.0"
+ resolved "https://registry.yarnpkg.com/tv4/-/tv4-1.3.0.tgz#d020c846fadd50c855abb25ebaecc68fc10f7963"
+
+tweetnacl@^0.14.3, tweetnacl@~0.14.0:
+ version "0.14.5"
+ resolved "https://registry.yarnpkg.com/tweetnacl/-/tweetnacl-0.14.5.tgz#5ae68177f192d4456269d108afa93ff8743f4f64"
+
+uid-number@^0.0.6:
+ version "0.0.6"
+ resolved "https://registry.yarnpkg.com/uid-number/-/uid-number-0.0.6.tgz#0ea10e8035e8eb5b8e4449f06da1c730663baa81"
+
+union-value@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/union-value/-/union-value-1.0.0.tgz#5c71c34cb5bad5dcebe3ea0cd08207ba5aa1aea4"
+ dependencies:
+ arr-union "^3.1.0"
+ get-value "^2.0.6"
+ is-extendable "^0.1.1"
+ set-value "^0.4.3"
+
+universalify@^0.1.0:
+ version "0.1.1"
+ resolved "https://registry.yarnpkg.com/universalify/-/universalify-0.1.1.tgz#fa71badd4437af4c148841e3b3b165f9e9e590b7"
+
+unset-value@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/unset-value/-/unset-value-1.0.0.tgz#8376873f7d2335179ffb1e6fc3a8ed0dfc8ab559"
+ dependencies:
+ has-value "^0.3.1"
+ isobject "^3.0.0"
+
+upath@^1.0.0:
+ version "1.0.4"
+ resolved "https://registry.yarnpkg.com/upath/-/upath-1.0.4.tgz#ee2321ba0a786c50973db043a50b7bcba822361d"
+
+urix@^0.1.0:
+ version "0.1.0"
+ resolved "https://registry.yarnpkg.com/urix/-/urix-0.1.0.tgz#da937f7a62e21fec1fd18d49b35c2935067a6c72"
+
+use@^3.1.0:
+ version "3.1.0"
+ resolved "https://registry.yarnpkg.com/use/-/use-3.1.0.tgz#14716bf03fdfefd03040aef58d8b4b85f3a7c544"
+ dependencies:
+ kind-of "^6.0.2"
+
+util-deprecate@~1.0.1:
+ version "1.0.2"
+ resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf"
+
+uuid@^3.0.0, uuid@^3.0.1:
+ version "3.2.1"
+ resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.2.1.tgz#12c528bb9d58d0b9265d9a2f6f0fe8be17ff1f14"
+
+v8-compile-cache@^1.1.0:
+ version "1.1.2"
+ resolved "https://registry.yarnpkg.com/v8-compile-cache/-/v8-compile-cache-1.1.2.tgz#8d32e4f16974654657e676e0e467a348e89b0dc4"
+
+verror@1.10.0:
+ version "1.10.0"
+ resolved "https://registry.yarnpkg.com/verror/-/verror-1.10.0.tgz#3a105ca17053af55d6e270c1f8288682e18da400"
+ dependencies:
+ assert-plus "^1.0.0"
+ core-util-is "1.0.2"
+ extsprintf "^1.2.0"
+
+vizion@0.2.0:
+ version "0.2.0"
+ resolved "https://registry.yarnpkg.com/vizion/-/vizion-0.2.0.tgz#9cfb9e710e06e7b3d0e67474d38ab6b9f6a0c55b"
+ dependencies:
+ async "0.9.0"
+
+vxx@^1.2.2:
+ version "1.2.2"
+ resolved "https://registry.yarnpkg.com/vxx/-/vxx-1.2.2.tgz#741fb51c6f11d3383da6f9b92018a5d7ba807611"
+ dependencies:
+ continuation-local-storage "^3.1.4"
+ debug "^2.6.3"
+ extend "^3.0.0"
+ is "^3.2.0"
+ lodash.findindex "^4.4.0"
+ lodash.isequal "^4.0.0"
+ lodash.merge "^4.6.0"
+ methods "^1.1.1"
+ semver "^5.0.1"
+ shimmer "^1.0.0"
+ uuid "^3.0.1"
+
+wide-align@^1.1.0:
+ version "1.1.2"
+ resolved "https://registry.yarnpkg.com/wide-align/-/wide-align-1.1.2.tgz#571e0f1b0604636ebc0dfc21b0339bbe31341710"
+ dependencies:
+ string-width "^1.0.2"
+
+wrappy@1:
+ version "1.0.2"
+ resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f"
+
+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"
+
+yamljs@^0.3.0:
+ version "0.3.0"
+ resolved "https://registry.yarnpkg.com/yamljs/-/yamljs-0.3.0.tgz#dc060bf267447b39f7304e9b2bfbe8b5a7ddb03b"
+ dependencies:
+ argparse "^1.0.7"
+ glob "^7.0.5"