feat: 초기 프로젝트 설정 및 룰.md 파일 추가
This commit is contained in:
4
api.hyungi.net/node_modules/pm2/.gitattributes
generated
vendored
Normal file
4
api.hyungi.net/node_modules/pm2/.gitattributes
generated
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
* text=auto
|
||||
*.sh eol=lf
|
||||
bin/** eol=lf
|
||||
test/fixtures/** eol=lf
|
||||
14
api.hyungi.net/node_modules/pm2/.mocharc.js
generated
vendored
Normal file
14
api.hyungi.net/node_modules/pm2/.mocharc.js
generated
vendored
Normal file
@@ -0,0 +1,14 @@
|
||||
|
||||
module.exports = {
|
||||
'allow-uncaught' : false,
|
||||
'async-only': false,
|
||||
bail: true,
|
||||
color: true,
|
||||
delay: false,
|
||||
diff: true,
|
||||
exit: true,
|
||||
timeout: 10000,
|
||||
'trace-warnings': true,
|
||||
ui: 'bdd',
|
||||
retries: 2
|
||||
}
|
||||
2355
api.hyungi.net/node_modules/pm2/CHANGELOG.md
generated
vendored
Normal file
2355
api.hyungi.net/node_modules/pm2/CHANGELOG.md
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
124
api.hyungi.net/node_modules/pm2/CONTRIBUTING.md
generated
vendored
Normal file
124
api.hyungi.net/node_modules/pm2/CONTRIBUTING.md
generated
vendored
Normal file
@@ -0,0 +1,124 @@
|
||||
# Contributing
|
||||
|
||||
## Cloning PM2 development
|
||||
|
||||
```bash
|
||||
$ git clone https://github.com/Unitech/pm2.git
|
||||
$ cd pm2
|
||||
$ git checkout development
|
||||
$ npm install
|
||||
```
|
||||
|
||||
I recommend having a pm2 alias pointing to the development version to make it easier to use pm2 development:
|
||||
|
||||
```
|
||||
$ cd pm2/
|
||||
$ echo "alias pm2='`pwd`/bin/pm2'" >> ~/.bashrc
|
||||
```
|
||||
|
||||
You are now able to use pm2 in dev mode:
|
||||
|
||||
```
|
||||
$ pm2 update
|
||||
$ pm2 ls
|
||||
```
|
||||
|
||||
## Project structure
|
||||
|
||||
```
|
||||
.
|
||||
├── bin // pm2, pmd, pm2-dev, pm2-docker are there
|
||||
├── examples // examples files
|
||||
├── lib // source files
|
||||
├── pres // presentation files
|
||||
├── test // test files
|
||||
└── types // TypeScript definition files
|
||||
```
|
||||
|
||||
## Modifying the Daemon
|
||||
|
||||
When you modify the Daemon (lib/Daemon.js, lib/God.js, lib/God/*, lib/Watcher.js), you must restart the pm2 Daemon by doing:
|
||||
|
||||
```
|
||||
$ pm2 update
|
||||
```
|
||||
|
||||
## Commit rules
|
||||
|
||||
### Commit message
|
||||
|
||||
A good commit message should describe what changed and why.
|
||||
|
||||
It should :
|
||||
* contain a short description of the change (preferably 50 characters or less)
|
||||
* be entirely in lowercase with the exception of proper nouns, acronyms, and the words that refer to code, like function/variable names
|
||||
* be prefixed with one of the following word
|
||||
* fix : bug fix
|
||||
* hotfix : urgent bug fix
|
||||
* feat : new or updated feature
|
||||
* docs : documentation updates
|
||||
* BREAKING : if commit is a breaking change
|
||||
* refactor : code refactoring (no functional change)
|
||||
* perf : performance improvement
|
||||
* style : UX and display updates
|
||||
* test : tests and CI updates
|
||||
* chore : updates on build, tools, configuration ...
|
||||
* Merge branch : when merging branch
|
||||
* Merge pull request : when merging PR
|
||||
|
||||
## Tests
|
||||
|
||||
There are two tests type. Programmatic and Behavioral.
|
||||
The main test command is `npm test`
|
||||
|
||||
### Programmatic
|
||||
|
||||
Programmatic tests are runned by doing
|
||||
|
||||
```
|
||||
$ bash test/pm2_programmatic_tests.sh
|
||||
```
|
||||
|
||||
This test files are located in test/programmatic/*
|
||||
|
||||
### Behavioral
|
||||
|
||||
Behavioral tests are runned by doing:
|
||||
|
||||
```
|
||||
$ bash test/e2e.sh
|
||||
```
|
||||
|
||||
This test files are located in test/e2e/*
|
||||
|
||||
## File of interest
|
||||
|
||||
- `$HOME/.pm2` contain all PM2 related files
|
||||
- `$HOME/.pm2/logs` contain all applications logs
|
||||
- `$HOME/.pm2/pids` contain all applications pids
|
||||
- `$HOME/.pm2/pm2.log` PM2 logs
|
||||
- `$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
|
||||
665
api.hyungi.net/node_modules/pm2/GNU-AGPL-3.0.txt
generated
vendored
Normal file
665
api.hyungi.net/node_modules/pm2/GNU-AGPL-3.0.txt
generated
vendored
Normal file
@@ -0,0 +1,665 @@
|
||||
|
||||
GNU AFFERO GENERAL PUBLIC LICENSE
|
||||
Version 3, 19 November 2007
|
||||
|
||||
Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
Preamble
|
||||
|
||||
The GNU Affero General Public License is a free, copyleft license for
|
||||
software and other kinds of works, specifically designed to ensure
|
||||
cooperation with the community in the case of network server software.
|
||||
|
||||
The licenses for most software and other practical works are designed
|
||||
to take away your freedom to share and change the works. By contrast,
|
||||
our General Public Licenses are intended to guarantee your freedom to
|
||||
share and change all versions of a program--to make sure it remains free
|
||||
software for all its users.
|
||||
|
||||
When we speak of free software, we are referring to freedom, not
|
||||
price. Our General Public Licenses are designed to make sure that you
|
||||
have the freedom to distribute copies of free software (and charge for
|
||||
them if you wish), that you receive source code or can get it if you
|
||||
want it, that you can change the software or use pieces of it in new
|
||||
free programs, and that you know you can do these things.
|
||||
|
||||
Developers that use our General Public Licenses protect your rights
|
||||
with two steps: (1) assert copyright on the software, and (2) offer
|
||||
you this License which gives you legal permission to copy, distribute
|
||||
and/or modify the software.
|
||||
|
||||
A secondary benefit of defending all users' freedom is that
|
||||
improvements made in alternate versions of the program, if they
|
||||
receive widespread use, become available for other developers to
|
||||
incorporate. Many developers of free software are heartened and
|
||||
encouraged by the resulting cooperation. However, in the case of
|
||||
software used on network servers, this result may fail to come about.
|
||||
The GNU General Public License permits making a modified version and
|
||||
letting the public access it on a server without ever releasing its
|
||||
source code to the public.
|
||||
|
||||
The GNU Affero General Public License is designed specifically to
|
||||
ensure that, in such cases, the modified source code becomes available
|
||||
to the community. It requires the operator of a network server to
|
||||
provide the source code of the modified version running there to the
|
||||
users of that server. Therefore, public use of a modified version, on
|
||||
a publicly accessible server, gives the public access to the source
|
||||
code of the modified version.
|
||||
|
||||
An older license, called the Affero General Public License and
|
||||
published by Affero, was designed to accomplish similar goals. This is
|
||||
a different license, not a version of the Affero GPL, but Affero has
|
||||
released a new version of the Affero GPL which permits relicensing under
|
||||
this license.
|
||||
|
||||
The precise terms and conditions for copying, distribution and
|
||||
modification follow.
|
||||
|
||||
TERMS AND CONDITIONS
|
||||
|
||||
0. Definitions.
|
||||
|
||||
"This License" refers to version 3 of the GNU Affero General Public License.
|
||||
|
||||
"Copyright" also means copyright-like laws that apply to other kinds of
|
||||
works, such as semiconductor masks.
|
||||
|
||||
"The Program" refers to any copyrightable work licensed under this
|
||||
License. Each licensee is addressed as "you". "Licensees" and
|
||||
"recipients" may be individuals or organizations.
|
||||
|
||||
To "modify" a work means to copy from or adapt all or part of the work
|
||||
in a fashion requiring copyright permission, other than the making of an
|
||||
exact copy. The resulting work is called a "modified version" of the
|
||||
earlier work or a work "based on" the earlier work.
|
||||
|
||||
A "covered work" means either the unmodified Program or a work based
|
||||
on the Program.
|
||||
|
||||
To "propagate" a work means to do anything with it that, without
|
||||
permission, would make you directly or secondarily liable for
|
||||
infringement under applicable copyright law, except executing it on a
|
||||
computer or modifying a private copy. Propagation includes copying,
|
||||
distribution (with or without modification), making available to the
|
||||
public, and in some countries other activities as well.
|
||||
|
||||
To "convey" a work means any kind of propagation that enables other
|
||||
parties to make or receive copies. Mere interaction with a user through
|
||||
a computer network, with no transfer of a copy, is not conveying.
|
||||
|
||||
An interactive user interface displays "Appropriate Legal Notices"
|
||||
to the extent that it includes a convenient and prominently visible
|
||||
feature that (1) displays an appropriate copyright notice, and (2)
|
||||
tells the user that there is no warranty for the work (except to the
|
||||
extent that warranties are provided), that licensees may convey the
|
||||
work under this License, and how to view a copy of this License. If
|
||||
the interface presents a list of user commands or options, such as a
|
||||
menu, a prominent item in the list meets this criterion.
|
||||
|
||||
1. Source Code.
|
||||
|
||||
The "source code" for a work means the preferred form of the work
|
||||
for making modifications to it. "Object code" means any non-source
|
||||
form of a work.
|
||||
|
||||
A "Standard Interface" means an interface that either is an official
|
||||
standard defined by a recognized standards body, or, in the case of
|
||||
interfaces specified for a particular programming language, one that
|
||||
is widely used among developers working in that language.
|
||||
|
||||
The "System Libraries" of an executable work include anything, other
|
||||
than the work as a whole, that (a) is included in the normal form of
|
||||
packaging a Major Component, but which is not part of that Major
|
||||
Component, and (b) serves only to enable use of the work with that
|
||||
Major Component, or to implement a Standard Interface for which an
|
||||
implementation is available to the public in source code form. A
|
||||
"Major Component", in this context, means a major essential component
|
||||
(kernel, window system, and so on) of the specific operating system
|
||||
(if any) on which the executable work runs, or a compiler used to
|
||||
produce the work, or an object code interpreter used to run it.
|
||||
|
||||
The "Corresponding Source" for a work in object code form means all
|
||||
the source code needed to generate, install, and (for an executable
|
||||
work) run the object code and to modify the work, including scripts to
|
||||
control those activities. However, it does not include the work's
|
||||
System Libraries, or general-purpose tools or generally available free
|
||||
programs which are used unmodified in performing those activities but
|
||||
which are not part of the work. For example, Corresponding Source
|
||||
includes interface definition files associated with source files for
|
||||
the work, and the source code for shared libraries and dynamically
|
||||
linked subprograms that the work is specifically designed to require,
|
||||
such as by intimate data communication or control flow between those
|
||||
subprograms and other parts of the work.
|
||||
|
||||
The Corresponding Source need not include anything that users
|
||||
can regenerate automatically from other parts of the Corresponding
|
||||
Source.
|
||||
|
||||
The Corresponding Source for a work in source code form is that
|
||||
same work.
|
||||
|
||||
2. Basic Permissions.
|
||||
|
||||
All rights granted under this License are granted for the term of
|
||||
copyright on the Program, and are irrevocable provided the stated
|
||||
conditions are met. This License explicitly affirms your unlimited
|
||||
permission to run the unmodified Program. The output from running a
|
||||
covered work is covered by this License only if the output, given its
|
||||
content, constitutes a covered work. This License acknowledges your
|
||||
rights of fair use or other equivalent, as provided by copyright law.
|
||||
|
||||
You may make, run and propagate covered works that you do not
|
||||
convey, without conditions so long as your license otherwise remains
|
||||
in force. You may convey covered works to others for the sole purpose
|
||||
of having them make modifications exclusively for you, or provide you
|
||||
with facilities for running those works, provided that you comply with
|
||||
the terms of this License in conveying all material for which you do
|
||||
not control copyright. Those thus making or running the covered works
|
||||
for you must do so exclusively on your behalf, under your direction
|
||||
and control, on terms that prohibit them from making any copies of
|
||||
your copyrighted material outside their relationship with you.
|
||||
|
||||
Conveying under any other circumstances is permitted solely under
|
||||
the conditions stated below. Sublicensing is not allowed; section 10
|
||||
makes it unnecessary.
|
||||
|
||||
3. Protecting Users' Legal Rights From Anti-Circumvention Law.
|
||||
|
||||
No covered work shall be deemed part of an effective technological
|
||||
measure under any applicable law fulfilling obligations under article
|
||||
11 of the WIPO copyright treaty adopted on 20 December 1996, or
|
||||
similar laws prohibiting or restricting circumvention of such
|
||||
measures.
|
||||
|
||||
When you convey a covered work, you waive any legal power to forbid
|
||||
circumvention of technological measures to the extent such circumvention
|
||||
is effected by exercising rights under this License with respect to
|
||||
the covered work, and you disclaim any intention to limit operation or
|
||||
modification of the work as a means of enforcing, against the work's
|
||||
users, your or third parties' legal rights to forbid circumvention of
|
||||
technological measures.
|
||||
|
||||
4. Conveying Verbatim Copies.
|
||||
|
||||
You may convey verbatim copies of the Program's source code as you
|
||||
receive it, in any medium, provided that you conspicuously and
|
||||
appropriately publish on each copy an appropriate copyright notice;
|
||||
keep intact all notices stating that this License and any
|
||||
non-permissive terms added in accord with section 7 apply to the code;
|
||||
keep intact all notices of the absence of any warranty; and give all
|
||||
recipients a copy of this License along with the Program.
|
||||
|
||||
You may charge any price or no price for each copy that you convey,
|
||||
and you may offer support or warranty protection for a fee.
|
||||
|
||||
5. Conveying Modified Source Versions.
|
||||
|
||||
You may convey a work based on the Program, or the modifications to
|
||||
produce it from the Program, in the form of source code under the
|
||||
terms of section 4, provided that you also meet all of these conditions:
|
||||
|
||||
a) The work must carry prominent notices stating that you modified
|
||||
it, and giving a relevant date.
|
||||
|
||||
b) The work must carry prominent notices stating that it is
|
||||
released under this License and any conditions added under section
|
||||
7. This requirement modifies the requirement in section 4 to
|
||||
"keep intact all notices".
|
||||
|
||||
c) You must license the entire work, as a whole, under this
|
||||
License to anyone who comes into possession of a copy. This
|
||||
License will therefore apply, along with any applicable section 7
|
||||
additional terms, to the whole of the work, and all its parts,
|
||||
regardless of how they are packaged. This License gives no
|
||||
permission to license the work in any other way, but it does not
|
||||
invalidate such permission if you have separately received it.
|
||||
|
||||
d) If the work has interactive user interfaces, each must display
|
||||
Appropriate Legal Notices; however, if the Program has interactive
|
||||
interfaces that do not display Appropriate Legal Notices, your
|
||||
work need not make them do so.
|
||||
|
||||
A compilation of a covered work with other separate and independent
|
||||
works, which are not by their nature extensions of the covered work,
|
||||
and which are not combined with it such as to form a larger program,
|
||||
in or on a volume of a storage or distribution medium, is called an
|
||||
"aggregate" if the compilation and its resulting copyright are not
|
||||
used to limit the access or legal rights of the compilation's users
|
||||
beyond what the individual works permit. Inclusion of a covered work
|
||||
in an aggregate does not cause this License to apply to the other
|
||||
parts of the aggregate.
|
||||
|
||||
6. Conveying Non-Source Forms.
|
||||
|
||||
You may convey a covered work in object code form under the terms
|
||||
of sections 4 and 5, provided that you also convey the
|
||||
machine-readable Corresponding Source under the terms of this License,
|
||||
in one of these ways:
|
||||
|
||||
a) Convey the object code in, or embodied in, a physical product
|
||||
(including a physical distribution medium), accompanied by the
|
||||
Corresponding Source fixed on a durable physical medium
|
||||
customarily used for software interchange.
|
||||
|
||||
b) Convey the object code in, or embodied in, a physical product
|
||||
(including a physical distribution medium), accompanied by a
|
||||
written offer, valid for at least three years and valid for as
|
||||
long as you offer spare parts or customer support for that product
|
||||
model, to give anyone who possesses the object code either (1) a
|
||||
copy of the Corresponding Source for all the software in the
|
||||
product that is covered by this License, on a durable physical
|
||||
medium customarily used for software interchange, for a price no
|
||||
more than your reasonable cost of physically performing this
|
||||
conveying of source, or (2) access to copy the
|
||||
Corresponding Source from a network server at no charge.
|
||||
|
||||
c) Convey individual copies of the object code with a copy of the
|
||||
written offer to provide the Corresponding Source. This
|
||||
alternative is allowed only occasionally and noncommercially, and
|
||||
only if you received the object code with such an offer, in accord
|
||||
with subsection 6b.
|
||||
|
||||
d) Convey the object code by offering access from a designated
|
||||
place (gratis or for a charge), and offer equivalent access to the
|
||||
Corresponding Source in the same way through the same place at no
|
||||
further charge. You need not require recipients to copy the
|
||||
Corresponding Source along with the object code. If the place to
|
||||
copy the object code is a network server, the Corresponding Source
|
||||
may be on a different server (operated by you or a third party)
|
||||
that supports equivalent copying facilities, provided you maintain
|
||||
clear directions next to the object code saying where to find the
|
||||
Corresponding Source. Regardless of what server hosts the
|
||||
Corresponding Source, you remain obligated to ensure that it is
|
||||
available for as long as needed to satisfy these requirements.
|
||||
|
||||
e) Convey the object code using peer-to-peer transmission, provided
|
||||
you inform other peers where the object code and Corresponding
|
||||
Source of the work are being offered to the general public at no
|
||||
charge under subsection 6d.
|
||||
|
||||
A separable portion of the object code, whose source code is excluded
|
||||
from the Corresponding Source as a System Library, need not be
|
||||
included in conveying the object code work.
|
||||
|
||||
A "User Product" is either (1) a "consumer product", which means any
|
||||
tangible personal property which is normally used for personal, family,
|
||||
or household purposes, or (2) anything designed or sold for incorporation
|
||||
into a dwelling. In determining whether a product is a consumer product,
|
||||
doubtful cases shall be resolved in favor of coverage. For a particular
|
||||
product received by a particular user, "normally used" refers to a
|
||||
typical or common use of that class of product, regardless of the status
|
||||
of the particular user or of the way in which the particular user
|
||||
actually uses, or expects or is expected to use, the product. A product
|
||||
is a consumer product regardless of whether the product has substantial
|
||||
commercial, industrial or non-consumer uses, unless such uses represent
|
||||
the only significant mode of use of the product.
|
||||
|
||||
"Installation Information" for a User Product means any methods,
|
||||
procedures, authorization keys, or other information required to install
|
||||
and execute modified versions of a covered work in that User Product from
|
||||
a modified version of its Corresponding Source. The information must
|
||||
suffice to ensure that the continued functioning of the modified object
|
||||
code is in no case prevented or interfered with solely because
|
||||
modification has been made.
|
||||
|
||||
If you convey an object code work under this section in, or with, or
|
||||
specifically for use in, a User Product, and the conveying occurs as
|
||||
part of a transaction in which the right of possession and use of the
|
||||
User Product is transferred to the recipient in perpetuity or for a
|
||||
fixed term (regardless of how the transaction is characterized), the
|
||||
Corresponding Source conveyed under this section must be accompanied
|
||||
by the Installation Information. But this requirement does not apply
|
||||
if neither you nor any third party retains the ability to install
|
||||
modified object code on the User Product (for example, the work has
|
||||
been installed in ROM).
|
||||
|
||||
The requirement to provide Installation Information does not include a
|
||||
requirement to continue to provide support service, warranty, or updates
|
||||
for a work that has been modified or installed by the recipient, or for
|
||||
the User Product in which it has been modified or installed. Access to a
|
||||
network may be denied when the modification itself materially and
|
||||
adversely affects the operation of the network or violates the rules and
|
||||
protocols for communication across the network.
|
||||
|
||||
Corresponding Source conveyed, and Installation Information provided,
|
||||
in accord with this section must be in a format that is publicly
|
||||
documented (and with an implementation available to the public in
|
||||
source code form), and must require no special password or key for
|
||||
unpacking, reading or copying.
|
||||
|
||||
7. Additional Terms.
|
||||
|
||||
"Additional permissions" are terms that supplement the terms of this
|
||||
License by making exceptions from one or more of its conditions.
|
||||
Additional permissions that are applicable to the entire Program shall
|
||||
be treated as though they were included in this License, to the extent
|
||||
that they are valid under applicable law. If additional permissions
|
||||
apply only to part of the Program, that part may be used separately
|
||||
under those permissions, but the entire Program remains governed by
|
||||
this License without regard to the additional permissions.
|
||||
|
||||
When you convey a copy of a covered work, you may at your option
|
||||
remove any additional permissions from that copy, or from any part of
|
||||
it. (Additional permissions may be written to require their own
|
||||
removal in certain cases when you modify the work.) You may place
|
||||
additional permissions on material, added by you to a covered work,
|
||||
for which you have or can give appropriate copyright permission.
|
||||
|
||||
Notwithstanding any other provision of this License, for material you
|
||||
add to a covered work, you may (if authorized by the copyright holders of
|
||||
that material) supplement the terms of this License with terms:
|
||||
|
||||
a) Disclaiming warranty or limiting liability differently from the
|
||||
terms of sections 15 and 16 of this License; or
|
||||
|
||||
b) Requiring preservation of specified reasonable legal notices or
|
||||
author attributions in that material or in the Appropriate Legal
|
||||
Notices displayed by works containing it; or
|
||||
|
||||
c) Prohibiting misrepresentation of the origin of that material, or
|
||||
requiring that modified versions of such material be marked in
|
||||
reasonable ways as different from the original version; or
|
||||
|
||||
d) Limiting the use for publicity purposes of names of licensors or
|
||||
authors of the material; or
|
||||
|
||||
e) Declining to grant rights under trademark law for use of some
|
||||
trade names, trademarks, or service marks; or
|
||||
|
||||
f) Requiring indemnification of licensors and authors of that
|
||||
material by anyone who conveys the material (or modified versions of
|
||||
it) with contractual assumptions of liability to the recipient, for
|
||||
any liability that these contractual assumptions directly impose on
|
||||
those licensors and authors.
|
||||
|
||||
All other non-permissive additional terms are considered "further
|
||||
restrictions" within the meaning of section 10. If the Program as you
|
||||
received it, or any part of it, contains a notice stating that it is
|
||||
governed by this License along with a term that is a further
|
||||
restriction, you may remove that term. If a license document contains
|
||||
a further restriction but permits relicensing or conveying under this
|
||||
License, you may add to a covered work material governed by the terms
|
||||
of that license document, provided that the further restriction does
|
||||
not survive such relicensing or conveying.
|
||||
|
||||
If you add terms to a covered work in accord with this section, you
|
||||
must place, in the relevant source files, a statement of the
|
||||
additional terms that apply to those files, or a notice indicating
|
||||
where to find the applicable terms.
|
||||
|
||||
Additional terms, permissive or non-permissive, may be stated in the
|
||||
form of a separately written license, or stated as exceptions;
|
||||
the above requirements apply either way.
|
||||
|
||||
8. Termination.
|
||||
|
||||
You may not propagate or modify a covered work except as expressly
|
||||
provided under this License. Any attempt otherwise to propagate or
|
||||
modify it is void, and will automatically terminate your rights under
|
||||
this License (including any patent licenses granted under the third
|
||||
paragraph of section 11).
|
||||
|
||||
However, if you cease all violation of this License, then your
|
||||
license from a particular copyright holder is reinstated (a)
|
||||
provisionally, unless and until the copyright holder explicitly and
|
||||
finally terminates your license, and (b) permanently, if the copyright
|
||||
holder fails to notify you of the violation by some reasonable means
|
||||
prior to 60 days after the cessation.
|
||||
|
||||
Moreover, your license from a particular copyright holder is
|
||||
reinstated permanently if the copyright holder notifies you of the
|
||||
violation by some reasonable means, this is the first time you have
|
||||
received notice of violation of this License (for any work) from that
|
||||
copyright holder, and you cure the violation prior to 30 days after
|
||||
your receipt of the notice.
|
||||
|
||||
Termination of your rights under this section does not terminate the
|
||||
licenses of parties who have received copies or rights from you under
|
||||
this License. If your rights have been terminated and not permanently
|
||||
reinstated, you do not qualify to receive new licenses for the same
|
||||
material under section 10.
|
||||
|
||||
9. Acceptance Not Required for Having Copies.
|
||||
|
||||
You are not required to accept this License in order to receive or
|
||||
run a copy of the Program. Ancillary propagation of a covered work
|
||||
occurring solely as a consequence of using peer-to-peer transmission
|
||||
to receive a copy likewise does not require acceptance. However,
|
||||
nothing other than this License grants you permission to propagate or
|
||||
modify any covered work. These actions infringe copyright if you do
|
||||
not accept this License. Therefore, by modifying or propagating a
|
||||
covered work, you indicate your acceptance of this License to do so.
|
||||
|
||||
10. Automatic Licensing of Downstream Recipients.
|
||||
|
||||
Each time you convey a covered work, the recipient automatically
|
||||
receives a license from the original licensors, to run, modify and
|
||||
propagate that work, subject to this License. You are not responsible
|
||||
for enforcing compliance by third parties with this License.
|
||||
|
||||
An "entity transaction" is a transaction transferring control of an
|
||||
organization, or substantially all assets of one, or subdividing an
|
||||
organization, or merging organizations. If propagation of a covered
|
||||
work results from an entity transaction, each party to that
|
||||
transaction who receives a copy of the work also receives whatever
|
||||
licenses to the work the party's predecessor in interest had or could
|
||||
give under the previous paragraph, plus a right to possession of the
|
||||
Corresponding Source of the work from the predecessor in interest, if
|
||||
the predecessor has it or can get it with reasonable efforts.
|
||||
|
||||
You may not impose any further restrictions on the exercise of the
|
||||
rights granted or affirmed under this License. For example, you may
|
||||
not impose a license fee, royalty, or other charge for exercise of
|
||||
rights granted under this License, and you may not initiate litigation
|
||||
(including a cross-claim or counterclaim in a lawsuit) alleging that
|
||||
any patent claim is infringed by making, using, selling, offering for
|
||||
sale, or importing the Program or any portion of it.
|
||||
|
||||
11. Patents.
|
||||
|
||||
A "contributor" is a copyright holder who authorizes use under this
|
||||
License of the Program or a work on which the Program is based. The
|
||||
work thus licensed is called the contributor's "contributor version".
|
||||
|
||||
A contributor's "essential patent claims" are all patent claims
|
||||
owned or controlled by the contributor, whether already acquired or
|
||||
hereafter acquired, that would be infringed by some manner, permitted
|
||||
by this License, of making, using, or selling its contributor version,
|
||||
but do not include claims that would be infringed only as a
|
||||
consequence of further modification of the contributor version. For
|
||||
purposes of this definition, "control" includes the right to grant
|
||||
patent sublicenses in a manner consistent with the requirements of
|
||||
this License.
|
||||
|
||||
Each contributor grants you a non-exclusive, worldwide, royalty-free
|
||||
patent license under the contributor's essential patent claims, to
|
||||
make, use, sell, offer for sale, import and otherwise run, modify and
|
||||
propagate the contents of its contributor version.
|
||||
|
||||
In the following three paragraphs, a "patent license" is any express
|
||||
agreement or commitment, however denominated, not to enforce a patent
|
||||
(such as an express permission to practice a patent or covenant not to
|
||||
sue for patent infringement). To "grant" such a patent license to a
|
||||
party means to make such an agreement or commitment not to enforce a
|
||||
patent against the party.
|
||||
|
||||
If you convey a covered work, knowingly relying on a patent license,
|
||||
and the Corresponding Source of the work is not available for anyone
|
||||
to copy, free of charge and under the terms of this License, through a
|
||||
publicly available network server or other readily accessible means,
|
||||
then you must either (1) cause the Corresponding Source to be so
|
||||
available, or (2) arrange to deprive yourself of the benefit of the
|
||||
patent license for this particular work, or (3) arrange, in a manner
|
||||
consistent with the requirements of this License, to extend the patent
|
||||
license to downstream recipients. "Knowingly relying" means you have
|
||||
actual knowledge that, but for the patent license, your conveying the
|
||||
covered work in a country, or your recipient's use of the covered work
|
||||
in a country, would infringe one or more identifiable patents in that
|
||||
country that you have reason to believe are valid.
|
||||
|
||||
If, pursuant to or in connection with a single transaction or
|
||||
arrangement, you convey, or propagate by procuring conveyance of, a
|
||||
covered work, and grant a patent license to some of the parties
|
||||
receiving the covered work authorizing them to use, propagate, modify
|
||||
or convey a specific copy of the covered work, then the patent license
|
||||
you grant is automatically extended to all recipients of the covered
|
||||
work and works based on it.
|
||||
|
||||
A patent license is "discriminatory" if it does not include within
|
||||
the scope of its coverage, prohibits the exercise of, or is
|
||||
conditioned on the non-exercise of one or more of the rights that are
|
||||
specifically granted under this License. You may not convey a covered
|
||||
work if you are a party to an arrangement with a third party that is
|
||||
in the business of distributing software, under which you make payment
|
||||
to the third party based on the extent of your activity of conveying
|
||||
the work, and under which the third party grants, to any of the
|
||||
parties who would receive the covered work from you, a discriminatory
|
||||
patent license (a) in connection with copies of the covered work
|
||||
conveyed by you (or copies made from those copies), or (b) primarily
|
||||
for and in connection with specific products or compilations that
|
||||
contain the covered work, unless you entered into that arrangement,
|
||||
or that patent license was granted, prior to 28 March 2007.
|
||||
|
||||
Nothing in this License shall be construed as excluding or limiting
|
||||
any implied license or other defenses to infringement that may
|
||||
otherwise be available to you under applicable patent law.
|
||||
|
||||
12. No Surrender of Others' Freedom.
|
||||
|
||||
If conditions are imposed on you (whether by court order, agreement or
|
||||
otherwise) that contradict the conditions of this License, they do not
|
||||
excuse you from the conditions of this License. If you cannot convey a
|
||||
covered work so as to satisfy simultaneously your obligations under this
|
||||
License and any other pertinent obligations, then as a consequence you may
|
||||
not convey it at all. For example, if you agree to terms that obligate you
|
||||
to collect a royalty for further conveying from those to whom you convey
|
||||
the Program, the only way you could satisfy both those terms and this
|
||||
License would be to refrain entirely from conveying the Program.
|
||||
|
||||
13. Remote Network Interaction; Use with the GNU General Public License.
|
||||
|
||||
Notwithstanding any other provision of this License, if you modify the
|
||||
Program, your modified version must prominently offer all users
|
||||
interacting with it remotely through a computer network (if your version
|
||||
supports such interaction) an opportunity to receive the Corresponding
|
||||
Source of your version by providing access to the Corresponding Source
|
||||
from a network server at no charge, through some standard or customary
|
||||
means of facilitating copying of software. This Corresponding Source
|
||||
shall include the Corresponding Source for any work covered by version 3
|
||||
of the GNU General Public License that is incorporated pursuant to the
|
||||
following paragraph.
|
||||
|
||||
Notwithstanding any other provision of this License, you have
|
||||
permission to link or combine any covered work with a work licensed
|
||||
under version 3 of the GNU General Public License into a single
|
||||
combined work, and to convey the resulting work. The terms of this
|
||||
License will continue to apply to the part which is the covered work,
|
||||
but the work with which it is combined will remain governed by version
|
||||
3 of the GNU General Public License.
|
||||
|
||||
14. Revised Versions of this License.
|
||||
|
||||
The Free Software Foundation may publish revised and/or new versions of
|
||||
the GNU Affero General Public License from time to time. Such new versions
|
||||
will be similar in spirit to the present version, but may differ in detail to
|
||||
address new problems or concerns.
|
||||
|
||||
Each version is given a distinguishing version number. If the
|
||||
Program specifies that a certain numbered version of the GNU Affero General
|
||||
Public License "or any later version" applies to it, you have the
|
||||
option of following the terms and conditions either of that numbered
|
||||
version or of any later version published by the Free Software
|
||||
Foundation. If the Program does not specify a version number of the
|
||||
GNU Affero General Public License, you may choose any version ever published
|
||||
by the Free Software Foundation.
|
||||
|
||||
If the Program specifies that a proxy can decide which future
|
||||
versions of the GNU Affero General Public License can be used, that proxy's
|
||||
public statement of acceptance of a version permanently authorizes you
|
||||
to choose that version for the Program.
|
||||
|
||||
Later license versions may give you additional or different
|
||||
permissions. However, no additional obligations are imposed on any
|
||||
author or copyright holder as a result of your choosing to follow a
|
||||
later version.
|
||||
|
||||
15. Disclaimer of Warranty.
|
||||
|
||||
THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
|
||||
APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
|
||||
HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
|
||||
OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
|
||||
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
|
||||
IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
|
||||
ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
|
||||
|
||||
16. Limitation of Liability.
|
||||
|
||||
IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
||||
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
|
||||
THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
|
||||
GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
|
||||
USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
|
||||
DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
|
||||
PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
|
||||
EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
|
||||
SUCH DAMAGES.
|
||||
|
||||
17. Interpretation of Sections 15 and 16.
|
||||
|
||||
If the disclaimer of warranty and limitation of liability provided
|
||||
above cannot be given local legal effect according to their terms,
|
||||
reviewing courts shall apply local law that most closely approximates
|
||||
an absolute waiver of all civil liability in connection with the
|
||||
Program, unless a warranty or assumption of liability accompanies a
|
||||
copy of the Program in return for a fee.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
How to Apply These Terms to Your New Programs
|
||||
|
||||
If you develop a new program, and you want it to be of the greatest
|
||||
possible use to the public, the best way to achieve this is to make it
|
||||
free software which everyone can redistribute and change under these terms.
|
||||
|
||||
To do so, attach the following notices to the program. It is safest
|
||||
to attach them to the start of each source file to most effectively
|
||||
state the exclusion of warranty; and each file should have at least
|
||||
the "copyright" line and a pointer to where the full notice is found.
|
||||
|
||||
PM2 Process manager for Node.JS
|
||||
Copyright (C) 2013-2016 Strzelewicz Alexandre
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Also add information on how to contact you by electronic and paper mail.
|
||||
|
||||
If your software can interact with users remotely through a computer
|
||||
network, you should also make sure that it provides a way for users to
|
||||
get its source. For example, if your program is a web application, its
|
||||
interface could display a "Source" link that leads users to an archive
|
||||
of the code. There are many ways you could offer source, and different
|
||||
solutions will be better for different programs; see section 13 for the
|
||||
specific requirements.
|
||||
|
||||
You should also get your employer (if you work as a programmer) or school,
|
||||
if any, to sign a "copyright disclaimer" for the program, if necessary.
|
||||
For more information on this, and how to apply and follow the GNU AGPL, see
|
||||
<http://www.gnu.org/licenses/>.
|
||||
|
||||
|
||||
--- ALEXANDRE STRZELEWICZ
|
||||
1
api.hyungi.net/node_modules/pm2/LICENSE
generated
vendored
Normal file
1
api.hyungi.net/node_modules/pm2/LICENSE
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
GNU-AGPL-3.0.txt
|
||||
252
api.hyungi.net/node_modules/pm2/README.md
generated
vendored
Normal file
252
api.hyungi.net/node_modules/pm2/README.md
generated
vendored
Normal file
@@ -0,0 +1,252 @@
|
||||
<div align="center">
|
||||
<br/>
|
||||
<picture>
|
||||
<source
|
||||
srcset="https://raw.githubusercontent.com/Unitech/pm2/master/pres/pm2-v4.png"
|
||||
width=710px
|
||||
media="(prefers-color-scheme: light)"
|
||||
/>
|
||||
<source
|
||||
srcset="https://raw.githubusercontent.com/Unitech/pm2/development/pres/pm2-v4-dark-mode.png"
|
||||
width=710px
|
||||
media="(prefers-color-scheme: dark), (prefers-color-scheme: no-preference)"
|
||||
/>
|
||||
<img src="https://raw.githubusercontent.com/Unitech/pm2/master/pres/pm2-v4.png" />
|
||||
</picture>
|
||||
|
||||
<br/>
|
||||
<br/>
|
||||
<b>P</b>(rocess) <b>M</b>(anager) <b>2</b><br/>
|
||||
<i>Runtime Edition</i>
|
||||
<br/><br/>
|
||||
|
||||
|
||||
<a title="PM2 Downloads" href="https://npm-stat.com/charts.html?package=pm2&from=2018-01-01&to=2023-08-01">
|
||||
<img src="https://img.shields.io/npm/dm/pm2" alt="Downloads per Month"/>
|
||||
</a>
|
||||
|
||||
<a title="PM2 Downloads" href="https://npm-stat.com/charts.html?package=pm2&from=2018-01-01&to=2023-08-01">
|
||||
<img src="https://img.shields.io/npm/dy/pm2" alt="Downloads per Year"/>
|
||||
</a>
|
||||
|
||||
<a href="https://badge.fury.io/js/pm2" title="NPM Version Badge">
|
||||
<img src="https://badge.fury.io/js/pm2.svg" alt="npm version">
|
||||
</a>
|
||||
|
||||
<br/>
|
||||
<br/>
|
||||
<br/>
|
||||
</div>
|
||||
|
||||
|
||||
PM2 is a production process manager for Node.js applications with a built-in load balancer. It allows you to keep applications alive forever, to reload them without downtime and to facilitate common system admin tasks.
|
||||
|
||||
Starting an application in production mode is as easy as:
|
||||
|
||||
```bash
|
||||
$ pm2 start app.js
|
||||
```
|
||||
|
||||
PM2 is constantly assailed by [more than 1800 tests](https://github.com/Unitech/pm2/actions/workflows/node.js.yml).
|
||||
|
||||
Official website: [https://pm2.keymetrics.io/](https://pm2.keymetrics.io/)
|
||||
|
||||
Works on Linux (stable) & macOS (stable) & Windows (stable). All Node.js versions are supported starting Node.js 12.X.
|
||||
|
||||
|
||||
### Installing PM2
|
||||
|
||||
With NPM:
|
||||
|
||||
```bash
|
||||
$ npm install pm2 -g
|
||||
```
|
||||
|
||||
You can install Node.js easily with [NVM](https://github.com/nvm-sh/nvm#installing-and-updating) or [FNM](https://github.com/Schniz/fnm).
|
||||
|
||||
### Start an application
|
||||
|
||||
You can start any application (Node.js, Python, Ruby, binaries in $PATH...) like that:
|
||||
|
||||
```bash
|
||||
$ pm2 start app.js
|
||||
```
|
||||
|
||||
Your app is now daemonized, monitored and kept alive forever.
|
||||
|
||||
### Managing Applications
|
||||
|
||||
Once applications are started you can manage them easily:
|
||||
|
||||

|
||||
|
||||
To list all running applications:
|
||||
|
||||
```bash
|
||||
$ pm2 list
|
||||
```
|
||||
|
||||
Managing apps is straightforward:
|
||||
|
||||
```bash
|
||||
$ pm2 stop <app_name|namespace|id|'all'|json_conf>
|
||||
$ pm2 restart <app_name|namespace|id|'all'|json_conf>
|
||||
$ pm2 delete <app_name|namespace|id|'all'|json_conf>
|
||||
```
|
||||
|
||||
To have more details on a specific application:
|
||||
|
||||
```bash
|
||||
$ pm2 describe <id|app_name>
|
||||
```
|
||||
|
||||
To monitor logs, custom metrics, application information:
|
||||
|
||||
```bash
|
||||
$ pm2 monit
|
||||
```
|
||||
|
||||
[More about Process Management](https://pm2.keymetrics.io/docs/usage/process-management/)
|
||||
|
||||
### Cluster Mode: Node.js Load Balancing & Zero Downtime Reload
|
||||
|
||||
The Cluster mode is a special mode when starting a Node.js application, it starts multiple processes and load-balance HTTP/TCP/UDP queries between them. This increase overall performance (by a factor of x10 on 16 cores machines) and reliability (faster socket re-balancing in case of unhandled errors).
|
||||
|
||||

|
||||
|
||||
Starting a Node.js application in cluster mode that will leverage all CPUs available:
|
||||
|
||||
```bash
|
||||
$ pm2 start api.js -i <processes>
|
||||
```
|
||||
|
||||
`<processes>` can be `'max'`, `-1` (all cpu minus 1) or a specified number of instances to start.
|
||||
|
||||
**Zero Downtime Reload**
|
||||
|
||||
Hot Reload allows to update an application without any downtime:
|
||||
|
||||
```bash
|
||||
$ pm2 reload all
|
||||
```
|
||||
|
||||
[More informations about how PM2 make clustering easy](https://pm2.keymetrics.io/docs/usage/cluster-mode/)
|
||||
|
||||
### Container Support
|
||||
|
||||
With the drop-in replacement command for `node`, called `pm2-runtime`, run your Node.js application in a hardened production environment.
|
||||
Using it is seamless:
|
||||
|
||||
```
|
||||
RUN npm install pm2 -g
|
||||
CMD [ "pm2-runtime", "npm", "--", "start" ]
|
||||
```
|
||||
|
||||
[Read More about the dedicated integration](https://pm2.keymetrics.io/docs/usage/docker-pm2-nodejs/)
|
||||
|
||||
### Host monitoring speedbar
|
||||
|
||||
PM2 allows to monitor your host/server vitals with a monitoring speedbar.
|
||||
|
||||
To enable host monitoring:
|
||||
|
||||
```bash
|
||||
$ pm2 set pm2:sysmonit true
|
||||
$ pm2 update
|
||||
```
|
||||
|
||||

|
||||
|
||||
### Terminal Based Monitoring
|
||||
|
||||

|
||||
|
||||
Monitor all processes launched straight from the command line:
|
||||
|
||||
```bash
|
||||
$ pm2 monit
|
||||
```
|
||||
|
||||
### Log Management
|
||||
|
||||
To consult logs just type the command:
|
||||
|
||||
```bash
|
||||
$ pm2 logs
|
||||
```
|
||||
|
||||
Standard, Raw, JSON and formated output are available.
|
||||
|
||||
Examples:
|
||||
|
||||
```bash
|
||||
$ pm2 logs APP-NAME # Display APP-NAME logs
|
||||
$ pm2 logs --json # JSON output
|
||||
$ pm2 logs --format # Formated output
|
||||
|
||||
$ pm2 flush # Flush all logs
|
||||
$ pm2 reloadLogs # Reload all logs
|
||||
```
|
||||
|
||||
To enable log rotation install the following module
|
||||
|
||||
```bash
|
||||
$ pm2 install pm2-logrotate
|
||||
```
|
||||
|
||||
[More about log management](https://pm2.keymetrics.io/docs/usage/log-management/)
|
||||
|
||||
### Startup Scripts Generation
|
||||
|
||||
PM2 can generate and configure a Startup Script to keep PM2 and your processes alive at every server restart.
|
||||
|
||||
Init Systems Supported: **systemd**, **upstart**, **launchd**, **rc.d**
|
||||
|
||||
```bash
|
||||
# Generate Startup Script
|
||||
$ pm2 startup
|
||||
|
||||
# Freeze your process list across server restart
|
||||
$ pm2 save
|
||||
|
||||
# Remove Startup Script
|
||||
$ pm2 unstartup
|
||||
```
|
||||
|
||||
[More about Startup Scripts Generation](https://pm2.keymetrics.io/docs/usage/startup/)
|
||||
|
||||
### Updating PM2
|
||||
|
||||
```bash
|
||||
# Install latest PM2 version
|
||||
$ npm install pm2@latest -g
|
||||
# Save process list, exit old PM2 & restore all processes
|
||||
$ pm2 update
|
||||
```
|
||||
|
||||
*PM2 updates are seamless*
|
||||
|
||||
## PM2+ Monitoring
|
||||
|
||||
If you manage your apps with PM2, PM2+ makes it easy to monitor and manage apps across servers.
|
||||
|
||||

|
||||
|
||||
Feel free to try it:
|
||||
|
||||
[Discover the monitoring dashboard for PM2](https://app.pm2.io/)
|
||||
|
||||
Thanks in advance and we hope that you like PM2!
|
||||
|
||||
## CHANGELOG
|
||||
|
||||
[CHANGELOG](https://github.com/Unitech/PM2/blob/master/CHANGELOG.md)
|
||||
|
||||
## Contributors
|
||||
|
||||
[Contributors](http://pm2.keymetrics.io/hall-of-fame/)
|
||||
|
||||
## License
|
||||
|
||||
PM2 is made available under the terms of the GNU Affero General Public License 3.0 (AGPL 3.0).
|
||||
For other licenses [contact us](mailto:contact@keymetrics.io).
|
||||
3
api.hyungi.net/node_modules/pm2/bin/pm2
generated
vendored
Normal file
3
api.hyungi.net/node_modules/pm2/bin/pm2
generated
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
#!/usr/bin/env node
|
||||
|
||||
require('../lib/binaries/CLI.js');
|
||||
3
api.hyungi.net/node_modules/pm2/bin/pm2-dev
generated
vendored
Normal file
3
api.hyungi.net/node_modules/pm2/bin/pm2-dev
generated
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
#!/usr/bin/env node
|
||||
|
||||
require('../lib/binaries/DevCLI.js');
|
||||
3
api.hyungi.net/node_modules/pm2/bin/pm2-docker
generated
vendored
Normal file
3
api.hyungi.net/node_modules/pm2/bin/pm2-docker
generated
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
#!/usr/bin/env node
|
||||
|
||||
require('../lib/binaries/Runtime4Docker.js');
|
||||
3
api.hyungi.net/node_modules/pm2/bin/pm2-runtime
generated
vendored
Normal file
3
api.hyungi.net/node_modules/pm2/bin/pm2-runtime
generated
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
#!/usr/bin/env node
|
||||
|
||||
require('../lib/binaries/Runtime4Docker.js');
|
||||
112
api.hyungi.net/node_modules/pm2/constants.js
generated
vendored
Normal file
112
api.hyungi.net/node_modules/pm2/constants.js
generated
vendored
Normal file
@@ -0,0 +1,112 @@
|
||||
/**
|
||||
* Copyright 2013-2022 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')('pm2:conf');
|
||||
var p = require('path');
|
||||
var util = require('util');
|
||||
var chalk = require('chalk');
|
||||
|
||||
/**
|
||||
* Get PM2 path structure
|
||||
*/
|
||||
var path_structure = require('./paths.js')(process.env.OVER_HOME);
|
||||
|
||||
/**
|
||||
* Constants variables used by PM2
|
||||
*/
|
||||
var csts = {
|
||||
PREFIX_MSG : chalk.green('[PM2] '),
|
||||
PREFIX_MSG_INFO : chalk.cyan('[PM2][INFO] '),
|
||||
PREFIX_MSG_ERR : chalk.red('[PM2][ERROR] '),
|
||||
PREFIX_MSG_MOD : chalk.bold.green('[PM2][Module] '),
|
||||
PREFIX_MSG_MOD_ERR : chalk.red('[PM2][Module][ERROR] '),
|
||||
PREFIX_MSG_WARNING : chalk.yellow('[PM2][WARN] '),
|
||||
PREFIX_MSG_SUCCESS : chalk.cyan('[PM2] '),
|
||||
|
||||
PM2_IO_MSG : chalk.cyan('[PM2 I/O]'),
|
||||
PM2_IO_MSG_ERR : chalk.red('[PM2 I/O]'),
|
||||
|
||||
TEMPLATE_FOLDER : p.join(__dirname, 'lib/templates'),
|
||||
|
||||
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',
|
||||
LOGROTATE_SCRIPT : 'logrotate.d/pm2',
|
||||
|
||||
DOCKERFILE_NODEJS : 'Dockerfiles/Dockerfile-nodejs.tpl',
|
||||
DOCKERFILE_JAVA : 'Dockerfiles/Dockerfile-java.tpl',
|
||||
DOCKERFILE_RUBY : 'Dockerfiles/Dockerfile-ruby.tpl',
|
||||
|
||||
SUCCESS_EXIT : 0,
|
||||
ERROR_EXIT : 1,
|
||||
CODE_UNCAUGHTEXCEPTION : 1,
|
||||
|
||||
IS_WINDOWS : (process.platform === 'win32' || process.platform === 'win64' || /^(msys|cygwin)$/.test(process.env.OSTYPE)),
|
||||
ONLINE_STATUS : 'online',
|
||||
STOPPED_STATUS : 'stopped',
|
||||
STOPPING_STATUS : 'stopping',
|
||||
WAITING_RESTART : 'waiting restart',
|
||||
LAUNCHING_STATUS : 'launching',
|
||||
ERRORED_STATUS : 'errored',
|
||||
ONE_LAUNCH_STATUS : 'one-launch-status',
|
||||
|
||||
CLUSTER_MODE_ID : 'cluster_mode',
|
||||
FORK_MODE_ID : 'fork_mode',
|
||||
|
||||
LOW_MEMORY_ENVIRONMENT : process.env.PM2_OPTIMIZE_MEMORY || false,
|
||||
|
||||
MACHINE_NAME : process.env.INSTANCE_NAME || process.env.MACHINE_NAME || process.env.PM2_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.PM2_APM_ADDRESS || process.env.ROOT_URL || process.env.INFO_NODE || 'root.keymetrics.io',
|
||||
|
||||
|
||||
PM2_BANNER : '../lib/motd',
|
||||
PM2_UPDATE : '../lib/API/pm2-plus/pres/motd.update',
|
||||
DEFAULT_MODULE_JSON : 'package.json',
|
||||
|
||||
MODULE_BASEFOLDER: 'module',
|
||||
MODULE_CONF_PREFIX: 'module-db-v2',
|
||||
MODULE_CONF_PREFIX_TAR: 'tar-modules',
|
||||
|
||||
EXP_BACKOFF_RESET_TIMER : parseInt(process.env.EXP_BACKOFF_RESET_TIMER) || 30000,
|
||||
REMOTE_PORT_TCP : isNaN(parseInt(process.env.KEYMETRICS_PUSH_PORT)) ? 80 : parseInt(process.env.KEYMETRICS_PUSH_PORT),
|
||||
REMOTE_PORT : 41624,
|
||||
REMOTE_HOST : 's1.keymetrics.io',
|
||||
SEND_INTERVAL : 1000,
|
||||
RELOAD_LOCK_TIMEOUT : parseInt(process.env.PM2_RELOAD_LOCK_TIMEOUT) || 30000,
|
||||
GRACEFUL_TIMEOUT : parseInt(process.env.PM2_GRACEFUL_TIMEOUT) || 8000,
|
||||
GRACEFUL_LISTEN_TIMEOUT : parseInt(process.env.PM2_GRACEFUL_LISTEN_TIMEOUT) || 3000,
|
||||
LOGS_BUFFER_SIZE : 8,
|
||||
CONTEXT_ON_ERROR : 2,
|
||||
AGGREGATION_DURATION : process.env.PM2_DEBUG || process.env.NODE_ENV === 'local_test' || process.env.NODE_ENV === 'development' ? 3000 : 5 * 60000,
|
||||
TRACE_FLUSH_INTERVAL : process.env.PM2_DEBUG || process.env.NODE_ENV === 'local_test' ? 1000 : 60000,
|
||||
|
||||
// Concurrent actions when doing start/restart/reload
|
||||
CONCURRENT_ACTIONS : (function() {
|
||||
var concurrent_actions = parseInt(process.env.PM2_CONCURRENT_ACTIONS) || 2;
|
||||
debug('Using %d parallelism (CONCURRENT_ACTIONS)', concurrent_actions);
|
||||
return concurrent_actions;
|
||||
})(),
|
||||
|
||||
DEBUG : process.env.PM2_DEBUG || false,
|
||||
WEB_IPADDR : process.env.PM2_API_IPADDR || '0.0.0.0',
|
||||
WEB_PORT : parseInt(process.env.PM2_API_PORT) || 9615,
|
||||
WEB_STRIP_ENV_VARS : process.env.PM2_WEB_STRIP_ENV_VARS || false,
|
||||
MODIFY_REQUIRE : process.env.PM2_MODIFY_REQUIRE || false,
|
||||
|
||||
WORKER_INTERVAL : process.env.PM2_WORKER_INTERVAL || 30000,
|
||||
KILL_TIMEOUT : process.env.PM2_KILL_TIMEOUT || 1600,
|
||||
KILL_SIGNAL : process.env.PM2_KILL_SIGNAL || 'SIGINT',
|
||||
KILL_USE_MESSAGE : process.env.PM2_KILL_USE_MESSAGE || false,
|
||||
|
||||
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-DDTHH:mm:ss'
|
||||
|
||||
};
|
||||
|
||||
module.exports = Object.assign(csts, path_structure);
|
||||
8
api.hyungi.net/node_modules/pm2/e2e_time
generated
vendored
Normal file
8
api.hyungi.net/node_modules/pm2/e2e_time
generated
vendored
Normal file
@@ -0,0 +1,8 @@
|
||||
[V] ./test/e2e/cli/reload.sh succeeded and took 64 seconds
|
||||
[V] ./test/e2e/cli/start-app.sh succeeded and took 10 seconds
|
||||
[V] ./test/e2e/cli/operate-regex.sh succeeded and took 5 seconds
|
||||
[V] ./test/e2e/cli/app-configuration.sh succeeded and took 9 seconds
|
||||
[V] ./test/e2e/cli/binary.sh succeeded and took 4 seconds
|
||||
[V] ./test/e2e/cli/startOrX.sh succeeded and took 3 seconds
|
||||
[V] ./test/e2e/cli/reset.sh succeeded and took 14 seconds
|
||||
[V] ./test/e2e/cli/env-refresh.sh succeeded and took 11 seconds
|
||||
12
api.hyungi.net/node_modules/pm2/index.js
generated
vendored
Normal file
12
api.hyungi.net/node_modules/pm2/index.js
generated
vendored
Normal file
@@ -0,0 +1,12 @@
|
||||
/**
|
||||
* Copyright 2013-2022 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.
|
||||
*/
|
||||
|
||||
process.env.PM2_PROGRAMMATIC = 'true';
|
||||
|
||||
var API = require('./lib/API.js');
|
||||
|
||||
module.exports = new API;
|
||||
module.exports.custom = API;
|
||||
1929
api.hyungi.net/node_modules/pm2/lib/API.js
generated
vendored
Normal file
1929
api.hyungi.net/node_modules/pm2/lib/API.js
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
212
api.hyungi.net/node_modules/pm2/lib/API/Configuration.js
generated
vendored
Normal file
212
api.hyungi.net/node_modules/pm2/lib/API/Configuration.js
generated
vendored
Normal file
@@ -0,0 +1,212 @@
|
||||
|
||||
var Common = require('../Common.js');
|
||||
var cst = require('../../constants.js');
|
||||
var UX = require('./UX');
|
||||
var chalk = require('chalk');
|
||||
var Configuration = require('../Configuration.js');
|
||||
|
||||
module.exports = function(CLI) {
|
||||
|
||||
CLI.prototype.get = function(key, cb) {
|
||||
var that = this;
|
||||
|
||||
if (!key || key == 'all') {
|
||||
displayConf(function(err, data) {
|
||||
if (err)
|
||||
return cb ? cb(Common.retErr(err)) : that.exitCli(cst.ERROR_EXIT);
|
||||
return cb ? cb(null, {success:true}) : that.exitCli(cst.SUCCESS_EXIT);
|
||||
});
|
||||
return false;
|
||||
}
|
||||
Configuration.get(key, function(err, data) {
|
||||
if (err) {
|
||||
return cb ? cb(Common.retErr(err)) : that.exitCli(cst.ERROR_EXIT);
|
||||
}
|
||||
// pm2 conf module-name
|
||||
if (key.indexOf(':') === -1 && key.indexOf('.') === -1) {
|
||||
displayConf(key, function() {
|
||||
console.log('Modules configuration. Copy/Paste line to edit values.')
|
||||
return cb ? cb(null, {success:true}) : that.exitCli(cst.SUCCESS_EXIT)
|
||||
});
|
||||
return false;
|
||||
}
|
||||
// pm2 conf module-name:key
|
||||
var module_name, key_name;
|
||||
|
||||
if (key.indexOf(':') > -1) {
|
||||
module_name = key.split(':')[0];
|
||||
key_name = key.split(':')[1];
|
||||
} else if (key.indexOf('.') > -1) {
|
||||
module_name = key.split('.')[0];
|
||||
key_name = key.split('.')[1];
|
||||
}
|
||||
|
||||
Common.printOut('Value for module ' + chalk.blue(module_name), 'key ' + chalk.blue(key_name) + ': ' + chalk.bold.green(data));
|
||||
|
||||
|
||||
return cb ? cb(null, {success:true}) : that.exitCli(cst.SUCCESS_EXIT);
|
||||
});
|
||||
};
|
||||
|
||||
CLI.prototype.set = function(key, value, cb) {
|
||||
var that = this;
|
||||
|
||||
if (!key) {
|
||||
interactiveConfigEdit(function(err) {
|
||||
if (err)
|
||||
return cb ? cb(Common.retErr(err)) : that.exitCli(cst.ERROR_EXIT);
|
||||
return cb ? cb(null, {success:true}) : that.exitCli(cst.SUCCESS_EXIT);
|
||||
});
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set value
|
||||
*/
|
||||
Configuration.set(key, value, function(err) {
|
||||
if (err)
|
||||
return cb ? cb(Common.retErr(err)) : that.exitCli(cst.ERROR_EXIT);
|
||||
|
||||
var values = [];
|
||||
|
||||
if (key.indexOf('.') > -1)
|
||||
values = key.split('.');
|
||||
|
||||
if (key.indexOf(':') > -1)
|
||||
values = key.split(':');
|
||||
|
||||
if (values && values.length > 1) {
|
||||
// The first element is the app name (module_conf.json)
|
||||
var app_name = values[0];
|
||||
|
||||
process.env.PM2_PROGRAMMATIC = 'true';
|
||||
that.restart(app_name, {
|
||||
updateEnv : true
|
||||
}, function(err, data) {
|
||||
process.env.PM2_PROGRAMMATIC = 'false';
|
||||
if (!err)
|
||||
Common.printOut(cst.PREFIX_MSG + 'Module %s restarted', app_name);
|
||||
Common.log('Setting changed')
|
||||
displayConf(app_name, function() {
|
||||
return cb ? cb(null, {success:true}) : that.exitCli(cst.SUCCESS_EXIT);
|
||||
});
|
||||
});
|
||||
return false;
|
||||
}
|
||||
displayConf(null, function() {
|
||||
return cb ? cb(null, {success:true}) : that.exitCli(cst.SUCCESS_EXIT);
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
CLI.prototype.multiset = function(serial, cb) {
|
||||
var that = this;
|
||||
|
||||
Configuration.multiset(serial, function(err, data) {
|
||||
if (err)
|
||||
return cb ? cb({success:false, err:err}) : that.exitCli(cst.ERROR_EXIT);
|
||||
|
||||
var values = [];
|
||||
var key = serial.match(/(?:[^ "]+|"[^"]*")+/g)[0];
|
||||
|
||||
if (key.indexOf('.') > -1)
|
||||
values = key.split('.');
|
||||
|
||||
if (key.indexOf(':') > -1)
|
||||
values = key.split(':');
|
||||
|
||||
if (values && values.length > 1) {
|
||||
// The first element is the app name (module_conf.json)
|
||||
var app_name = values[0];
|
||||
|
||||
process.env.PM2_PROGRAMMATIC = 'true';
|
||||
that.restart(app_name, {
|
||||
updateEnv : true
|
||||
}, function(err, data) {
|
||||
process.env.PM2_PROGRAMMATIC = 'false';
|
||||
if (!err)
|
||||
Common.printOut(cst.PREFIX_MSG + 'Module %s restarted', app_name);
|
||||
displayConf(app_name, function() {
|
||||
return cb ? cb(null, {success:true}) : that.exitCli(cst.SUCCESS_EXIT)
|
||||
});
|
||||
});
|
||||
return false;
|
||||
}
|
||||
displayConf(app_name, function() {
|
||||
return cb ? cb(null, {success:true}) : that.exitCli(cst.SUCCESS_EXIT)
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
CLI.prototype.unset = function(key, cb) {
|
||||
var that = this;
|
||||
|
||||
Configuration.unset(key, function(err) {
|
||||
if (err) {
|
||||
return cb ? cb(Common.retErr(err)) : that.exitCli(cst.ERROR_EXIT);
|
||||
}
|
||||
|
||||
displayConf(function() { cb ? cb(null, {success:true}) : that.exitCli(cst.SUCCESS_EXIT) });
|
||||
});
|
||||
};
|
||||
|
||||
CLI.prototype.conf = function(key, value, cb) {
|
||||
var that = this;
|
||||
|
||||
if (typeof(value) === 'function') {
|
||||
cb = value;
|
||||
value = null;
|
||||
}
|
||||
|
||||
// If key + value = set
|
||||
if (key && value) {
|
||||
that.set(key, value, function(err) {
|
||||
if (err)
|
||||
return cb ? cb(Common.retErr(err)) : that.exitCli(cst.ERROR_EXIT);
|
||||
return cb ? cb(null, {success:true}) : that.exitCli(cst.SUCCESS_EXIT);
|
||||
});
|
||||
}
|
||||
// If only key = get
|
||||
else if (key) {
|
||||
that.get(key, function(err, data) {
|
||||
if (err)
|
||||
return cb ? cb(Common.retErr(err)) : that.exitCli(cst.ERROR_EXIT);
|
||||
return cb ? cb(null, {success:true}) : that.exitCli(cst.SUCCESS_EXIT);
|
||||
});
|
||||
}
|
||||
else {
|
||||
interactiveConfigEdit(function(err) {
|
||||
if (err)
|
||||
return cb ? cb(Common.retErr(err)) : that.exitCli(cst.ERROR_EXIT);
|
||||
return cb ? cb(null, {success:true}) : that.exitCli(cst.SUCCESS_EXIT);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
function interactiveConfigEdit(cb) {
|
||||
UX.helpers.openEditor(cst.PM2_MODULE_CONF_FILE, function(err, data) {
|
||||
Common.printOut(chalk.bold('Module configuration (%s) edited.'), cst.PM2_MODULE_CONF_FILE);
|
||||
Common.printOut(chalk.bold('To take changes into account, please restart module related.'), cst.PM2_MODULE_CONF_FILE);
|
||||
if (err)
|
||||
return cb(Common.retErr(err));
|
||||
return cb(null, {success:true});
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Configuration
|
||||
*/
|
||||
function displayConf(target_app, cb) {
|
||||
if (typeof(target_app) == 'function') {
|
||||
cb = target_app;
|
||||
target_app = null;
|
||||
}
|
||||
|
||||
Configuration.getAll(function(err, data) {
|
||||
UX.helpers.dispKeys(data, target_app);
|
||||
return cb();
|
||||
});
|
||||
}
|
||||
335
api.hyungi.net/node_modules/pm2/lib/API/Containerizer.js
generated
vendored
Normal file
335
api.hyungi.net/node_modules/pm2/lib/API/Containerizer.js
generated
vendored
Normal file
@@ -0,0 +1,335 @@
|
||||
|
||||
var spawn = require('child_process').spawn;
|
||||
var exec = require('child_process').exec;
|
||||
var chalk = require('chalk');
|
||||
var util = require('util');
|
||||
var fmt = require('../tools/fmt.js');
|
||||
var fs = require('fs');
|
||||
var path = require('path');
|
||||
var cst = require('../../constants.js');
|
||||
var Promise = require('../tools/promise.min.js');
|
||||
|
||||
function pspawn(cmd) {
|
||||
return new Promise(function(resolve, reject) {
|
||||
var p_cmd = cmd.split(' ');
|
||||
|
||||
var install_instance = spawn(p_cmd[0], p_cmd.splice(1, cmd.length), {
|
||||
stdio : 'inherit',
|
||||
env : process.env,
|
||||
shell : true
|
||||
});
|
||||
|
||||
install_instance.on('close', function(code) {
|
||||
if (code != 0) {
|
||||
console.log(chalk.bold.red('Command failed'));
|
||||
return reject(new Error('Bad cmd return'));
|
||||
}
|
||||
return resolve();
|
||||
});
|
||||
|
||||
install_instance.on('error', function (err) {
|
||||
return reject(err);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function checkDockerSetup() {
|
||||
return new Promise(function(resolve, reject) {
|
||||
exec("docker version -f '{{.Client.Version}}'", function(err, stdout, stderr) {
|
||||
if (err) {
|
||||
console.error(chalk.red.bold('[Docker access] Error while trying to use docker command'));
|
||||
if (err.message && err.message.indexOf('Cannot connect to the Docker') > -1) {
|
||||
console.log();
|
||||
console.log(chalk.blue.bold('[Solution] Setup Docker to be able to be used without sudo rights:'));
|
||||
console.log(chalk.bold('$ sudo groupadd docker'));
|
||||
console.log(chalk.bold('$ sudo usermod -aG docker $USER'));
|
||||
console.log(chalk.bold('Then LOGOUT and LOGIN your Linux session'));
|
||||
console.log('Read more: http://bit.ly/29JGdCE');
|
||||
}
|
||||
return reject(err);
|
||||
}
|
||||
return resolve();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Switch Dockerfile mode
|
||||
* check test/programmatic/containerizer.mocha.js
|
||||
*/
|
||||
function parseAndSwitch(file_content, main_file, opts) {
|
||||
var lines = file_content.split('\n');
|
||||
var mode = opts.mode;
|
||||
|
||||
lines[0] = 'FROM keymetrics/pm2:' + opts.node_version;
|
||||
|
||||
for (var i = 0; i < lines.length; i++) {
|
||||
var line = lines[i];
|
||||
|
||||
if (['## DISTRIBUTION MODE', '## DEVELOPMENT MODE'].indexOf(line) > -1 ||
|
||||
i == lines.length - 1) {
|
||||
lines.splice(i, lines.length);
|
||||
lines[i] = '## ' + mode.toUpperCase() + ' MODE';
|
||||
lines[i + 1] = 'ENV NODE_ENV=' + (mode == 'distribution' ? 'production' : mode);
|
||||
|
||||
if (mode == 'distribution') {
|
||||
lines[i + 2] = 'COPY . /var/app';
|
||||
lines[i + 3] = 'CMD ["pm2-docker", "' + main_file + '", "--env", "production"]';
|
||||
}
|
||||
if (mode == 'development') {
|
||||
lines[i + 2] = 'CMD ["pm2-dev", "' + main_file + '", "--env", "development"]';
|
||||
}
|
||||
break;
|
||||
}
|
||||
};
|
||||
lines = lines.join('\n');
|
||||
return lines;
|
||||
};
|
||||
|
||||
/**
|
||||
* Replace ENV, COPY and CMD depending on the mode
|
||||
* @param {String} docker_filepath Dockerfile absolute path
|
||||
* @param {String} main_file Main file to start in container
|
||||
* @param {String} mode Mode to switch the Dockerfile
|
||||
*/
|
||||
function switchDockerFile(docker_filepath, main_file, opts) {
|
||||
return new Promise(function(resolve, reject) {
|
||||
var data = fs.readFileSync(docker_filepath, 'utf8').toString();
|
||||
|
||||
if (['distribution', 'development'].indexOf(opts.mode) == -1)
|
||||
return reject(new Error('Unknown mode'));
|
||||
|
||||
var lines = parseAndSwitch(data, main_file, opts)
|
||||
fs.writeFile(docker_filepath, lines, function(err) {
|
||||
if (err) return reject(err);
|
||||
resolve({
|
||||
Dockerfile_path : docker_filepath,
|
||||
Dockerfile : lines,
|
||||
CMD : ''
|
||||
});
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate sample Dockerfile (lib/templates/Dockerfiles)
|
||||
* @param {String} docker_filepath Dockerfile absolute path
|
||||
* @param {String} main_file Main file to start in container
|
||||
* @param {String} mode Mode to switch the Dockerfile
|
||||
*/
|
||||
function generateDockerfile(docker_filepath, main_file, opts) {
|
||||
return new Promise(function(resolve, reject) {
|
||||
var tpl_file = path.join(cst.TEMPLATE_FOLDER, cst.DOCKERFILE_NODEJS);
|
||||
var template = fs.readFileSync(tpl_file, {encoding: 'utf8'});
|
||||
var CMD;
|
||||
|
||||
template = parseAndSwitch(template, main_file, opts);
|
||||
|
||||
fs.writeFile(docker_filepath, template, function(err) {
|
||||
if (err) return reject(err);
|
||||
resolve({
|
||||
Dockerfile_path : docker_filepath,
|
||||
Dockerfile : template,
|
||||
CMD : CMD
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function handleExit(CLI, opts, mode) {
|
||||
process.on('SIGINT', function() {
|
||||
CLI.disconnect();
|
||||
|
||||
if (mode != 'distribution')
|
||||
return false;
|
||||
|
||||
exec('docker ps -lq', function(err, stdout, stderr) {
|
||||
if (err) {
|
||||
console.error(err);
|
||||
}
|
||||
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,
|
||||
meta.revision.slice(0, 5),
|
||||
meta.comment);
|
||||
|
||||
console.log(chalk.bold.magenta('$ docker commit -m "%s" %s %s'),
|
||||
commit_id,
|
||||
stdout.replace('\n', ''),
|
||||
opts.imageName);
|
||||
}
|
||||
else
|
||||
console.log(chalk.bold.magenta('$ docker commit %s %s'), stdout.replace('\n', ''), opts.imageName);
|
||||
|
||||
console.log(chalk.bold.magenta('$ docker push %s'), opts.imageName);
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
module.exports = function(CLI) {
|
||||
CLI.prototype.generateDockerfile = function(script, opts) {
|
||||
var docker_filepath = path.join(process.cwd(), 'Dockerfile');
|
||||
var that = this;
|
||||
|
||||
fs.stat(docker_filepath, function(err, stat) {
|
||||
if (err || opts.force == true) {
|
||||
generateDockerfile(docker_filepath, script, {
|
||||
mode : 'development'
|
||||
})
|
||||
.then(function() {
|
||||
console.log(chalk.bold('New Dockerfile generated in current folder'));
|
||||
console.log(chalk.bold('You can now run\n$ pm2 docker:dev <file|config>'));
|
||||
return that.exitCli(cst.SUCCESS_EXIT);
|
||||
});
|
||||
return false;
|
||||
}
|
||||
console.log(chalk.red.bold('Dockerfile already exists in this folder, use --force if you want to replace it'));
|
||||
that.exitCli(cst.ERROR_EXIT);
|
||||
});
|
||||
};
|
||||
|
||||
CLI.prototype.dockerMode = function(script, opts, mode) {
|
||||
var promptly = require('promptly');
|
||||
var self = this;
|
||||
handleExit(self, opts, mode);
|
||||
|
||||
if (mode == 'distribution' && !opts.imageName) {
|
||||
console.error(chalk.bold.red('--image-name [name] option is missing'));
|
||||
return self.exitCli(cst.ERROR_EXIT);
|
||||
}
|
||||
|
||||
var template;
|
||||
var app_path, main_script;
|
||||
var image_name;
|
||||
var node_version = opts.nodeVersion ? opts.nodeVersion.split('.')[0] : 'latest';
|
||||
|
||||
image_name = opts.imageName || require('crypto').randomBytes(6).toString('hex');
|
||||
|
||||
if (script.indexOf('/') > -1) {
|
||||
app_path = path.join(process.cwd(), path.dirname(script));
|
||||
main_script = path.basename(script);
|
||||
}
|
||||
else {
|
||||
app_path = process.cwd();
|
||||
main_script = script;
|
||||
}
|
||||
|
||||
checkDockerSetup()
|
||||
.then(function() {
|
||||
/////////////////////////
|
||||
// Generate Dockerfile //
|
||||
/////////////////////////
|
||||
return new Promise(function(resolve, reject) {
|
||||
var docker_filepath = path.join(process.cwd(), 'Dockerfile');
|
||||
|
||||
fs.stat(docker_filepath, function(err, stat) {
|
||||
if (err) {
|
||||
// Dockerfile does not exist, generate one
|
||||
// console.log(chalk.blue.bold('Generating new Dockerfile'));
|
||||
if (opts.force == true) {
|
||||
return resolve(generateDockerfile(docker_filepath, main_script, {
|
||||
node_version : node_version,
|
||||
mode : mode
|
||||
}));
|
||||
}
|
||||
if (opts.dockerdaemon)
|
||||
return resolve(generateDockerfile(docker_filepath, main_script, {
|
||||
node_version : node_version,
|
||||
mode : mode
|
||||
}));
|
||||
promptly.prompt('No Dockerfile in current directory, ok to generate a new one? (y/n)', function(err, value) {
|
||||
if (value == 'y')
|
||||
return resolve(generateDockerfile(docker_filepath, main_script, {
|
||||
node_version : node_version,
|
||||
mode : mode
|
||||
}));
|
||||
else
|
||||
return self.exitCli(cst.SUCCESS_EXIT);
|
||||
});
|
||||
return false;
|
||||
}
|
||||
return resolve(switchDockerFile(docker_filepath, main_script, {
|
||||
node_version : node_version,
|
||||
mode : mode
|
||||
}));
|
||||
});
|
||||
});
|
||||
})
|
||||
.then(function(_template) {
|
||||
template = _template;
|
||||
return Promise.resolve();
|
||||
})
|
||||
.then(function() {
|
||||
//////////////////
|
||||
// Docker build //
|
||||
//////////////////
|
||||
|
||||
var docker_build = util.format('docker build -t %s -f %s',
|
||||
image_name,
|
||||
template.Dockerfile_path);
|
||||
|
||||
if (opts.fresh == true)
|
||||
docker_build += ' --no-cache';
|
||||
docker_build += ' .';
|
||||
|
||||
console.log();
|
||||
fmt.sep();
|
||||
fmt.title('Building Boot System');
|
||||
fmt.field('Type', chalk.cyan.bold('Docker'));
|
||||
fmt.field('Mode', mode);
|
||||
fmt.field('Image name', image_name);
|
||||
fmt.field('Docker build command', docker_build);
|
||||
fmt.field('Dockerfile path', template.Dockerfile_path);
|
||||
fmt.sep();
|
||||
|
||||
return pspawn(docker_build);
|
||||
})
|
||||
.then(function() {
|
||||
////////////////
|
||||
// Docker run //
|
||||
////////////////
|
||||
|
||||
var docker_run = 'docker run --net host';
|
||||
|
||||
if (opts.dockerdaemon == true)
|
||||
docker_run += ' -d';
|
||||
if (mode != 'distribution')
|
||||
docker_run += util.format(' -v %s:/var/app -v /var/app/node_modules', app_path);
|
||||
docker_run += ' ' + image_name;
|
||||
var dockerfile_parsed = template.Dockerfile.split('\n');
|
||||
var base_image = dockerfile_parsed[0];
|
||||
var run_cmd = dockerfile_parsed[dockerfile_parsed.length - 1];
|
||||
|
||||
console.log();
|
||||
fmt.sep();
|
||||
fmt.title('Booting');
|
||||
fmt.field('Type', chalk.cyan.bold('Docker'));
|
||||
fmt.field('Mode', mode);
|
||||
fmt.field('Base Image', base_image);
|
||||
fmt.field('Image Name', image_name);
|
||||
fmt.field('Docker Command', docker_run);
|
||||
fmt.field('RUN Command', run_cmd);
|
||||
fmt.field('CWD', app_path);
|
||||
fmt.sep();
|
||||
return pspawn(docker_run);
|
||||
})
|
||||
.then(function() {
|
||||
console.log(chalk.blue.bold('>>> Leaving Docker instance uuid=%s'), image_name);
|
||||
self.disconnect();
|
||||
return Promise.resolve();
|
||||
})
|
||||
.catch(function(err) {
|
||||
console.log();
|
||||
console.log(chalk.grey('Raw error=', err.message));
|
||||
self.disconnect();
|
||||
});
|
||||
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
module.exports.generateDockerfile = generateDockerfile;
|
||||
module.exports.parseAndSwitch = parseAndSwitch;
|
||||
module.exports.switchDockerFile = switchDockerFile;
|
||||
459
api.hyungi.net/node_modules/pm2/lib/API/Dashboard.js
generated
vendored
Normal file
459
api.hyungi.net/node_modules/pm2/lib/API/Dashboard.js
generated
vendored
Normal file
@@ -0,0 +1,459 @@
|
||||
/**
|
||||
* Copyright 2013-2022 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 os = require('os');
|
||||
var p = require('path');
|
||||
var blessed = require('blessed');
|
||||
var debug = require('debug')('pm2:monit');
|
||||
var printf = require('sprintf-js').sprintf;
|
||||
|
||||
// Total memory
|
||||
const totalMem = os.totalmem();
|
||||
|
||||
var Dashboard = {};
|
||||
|
||||
var DEFAULT_PADDING = {
|
||||
top : 0,
|
||||
left : 1,
|
||||
right : 1
|
||||
};
|
||||
|
||||
var WIDTH_LEFT_PANEL = 30;
|
||||
|
||||
/**
|
||||
* Synchronous Dashboard init method
|
||||
* @method init
|
||||
* @return this
|
||||
*/
|
||||
Dashboard.init = function() {
|
||||
// Init Screen
|
||||
this.screen = blessed.screen({
|
||||
smartCSR: true,
|
||||
fullUnicode: true
|
||||
});
|
||||
this.screen.title = 'PM2 Dashboard';
|
||||
|
||||
this.logLines = {}
|
||||
|
||||
this.list = blessed.list({
|
||||
top: '0',
|
||||
left: '0',
|
||||
width: WIDTH_LEFT_PANEL + '%',
|
||||
height: '70%',
|
||||
padding: 0,
|
||||
scrollbar: {
|
||||
ch: ' ',
|
||||
inverse: false
|
||||
},
|
||||
border: {
|
||||
type: 'line'
|
||||
},
|
||||
keys: true,
|
||||
autoCommandKeys: true,
|
||||
tags: true,
|
||||
style: {
|
||||
selected: {
|
||||
bg: 'blue',
|
||||
fg: 'white'
|
||||
},
|
||||
scrollbar: {
|
||||
bg: 'blue',
|
||||
fg: 'black'
|
||||
},
|
||||
fg: 'white',
|
||||
border: {
|
||||
fg: 'blue'
|
||||
},
|
||||
header: {
|
||||
fg: 'blue'
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
this.list.on('select item', (item, i) => {
|
||||
this.logBox.clearItems()
|
||||
})
|
||||
|
||||
this.logBox = blessed.list({
|
||||
label: ' Logs ',
|
||||
top: '0',
|
||||
left: WIDTH_LEFT_PANEL + '%',
|
||||
width: 100 - WIDTH_LEFT_PANEL + '%',
|
||||
height: '70%',
|
||||
padding: DEFAULT_PADDING,
|
||||
scrollable: true,
|
||||
scrollbar: {
|
||||
ch: ' ',
|
||||
inverse: false
|
||||
},
|
||||
keys: true,
|
||||
autoCommandKeys: true,
|
||||
tags: true,
|
||||
border: {
|
||||
type: 'line'
|
||||
},
|
||||
style: {
|
||||
fg: 'white',
|
||||
border: {
|
||||
fg: 'white'
|
||||
},
|
||||
scrollbar: {
|
||||
bg: 'blue',
|
||||
fg: 'black'
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
this.metadataBox = blessed.box({
|
||||
label: ' Metadata ',
|
||||
top: '70%',
|
||||
left: WIDTH_LEFT_PANEL + '%',
|
||||
width: 100 - WIDTH_LEFT_PANEL + '%',
|
||||
height: '26%',
|
||||
padding: DEFAULT_PADDING,
|
||||
scrollable: true,
|
||||
scrollbar: {
|
||||
ch: ' ',
|
||||
inverse: false
|
||||
},
|
||||
keys: true,
|
||||
autoCommandKeys: true,
|
||||
tags: true,
|
||||
border: {
|
||||
type: 'line'
|
||||
},
|
||||
style: {
|
||||
fg: 'white',
|
||||
border: {
|
||||
fg: 'white'
|
||||
},
|
||||
scrollbar: {
|
||||
bg: 'blue',
|
||||
fg: 'black'
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
this.metricsBox = blessed.list({
|
||||
label: ' Custom Metrics ',
|
||||
top: '70%',
|
||||
left: '0%',
|
||||
width: WIDTH_LEFT_PANEL + '%',
|
||||
height: '26%',
|
||||
padding: DEFAULT_PADDING,
|
||||
scrollbar: {
|
||||
ch: ' ',
|
||||
inverse: false
|
||||
},
|
||||
keys: true,
|
||||
autoCommandKeys: true,
|
||||
tags: true,
|
||||
border: {
|
||||
type: 'line'
|
||||
},
|
||||
style: {
|
||||
fg: 'white',
|
||||
border: {
|
||||
fg: 'white'
|
||||
},
|
||||
scrollbar: {
|
||||
bg: 'blue',
|
||||
fg: 'black'
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
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://pm2.io/{/} ',
|
||||
left: '0%',
|
||||
top: '95%',
|
||||
width: '100%',
|
||||
height: '6%',
|
||||
valign: 'middle',
|
||||
tags: true,
|
||||
style: {
|
||||
fg: 'white'
|
||||
}
|
||||
});
|
||||
|
||||
this.list.focus();
|
||||
|
||||
this.screen.append(this.list);
|
||||
this.screen.append(this.logBox);
|
||||
this.screen.append(this.metadataBox);
|
||||
this.screen.append(this.metricsBox);
|
||||
this.screen.append(this.box4);
|
||||
|
||||
this.list.setLabel(' Process List ');
|
||||
|
||||
this.screen.render();
|
||||
|
||||
var that = this;
|
||||
|
||||
var i = 0;
|
||||
var boards = ['list', 'logBox', 'metricsBox', 'metadataBox'];
|
||||
this.screen.key(['left', 'right'], function(ch, key) {
|
||||
(key.name === 'left') ? i-- : i++;
|
||||
if (i == 4)
|
||||
i = 0;
|
||||
if (i == -1)
|
||||
i = 3;
|
||||
that[boards[i]].focus();
|
||||
that[boards[i]].style.border.fg = 'blue';
|
||||
if (key.name === 'left') {
|
||||
if (i == 3)
|
||||
that[boards[0]].style.border.fg = 'white';
|
||||
else
|
||||
that[boards[i + 1]].style.border.fg = 'white';
|
||||
}
|
||||
else {
|
||||
if (i == 0)
|
||||
that[boards[3]].style.border.fg = 'white';
|
||||
else
|
||||
that[boards[i - 1]].style.border.fg = 'white';
|
||||
}
|
||||
});
|
||||
|
||||
this.screen.key(['escape', 'q', 'C-c'], function(ch, key) {
|
||||
this.screen.destroy();
|
||||
process.exit(0);
|
||||
});
|
||||
|
||||
// async refresh of the ui
|
||||
setInterval(function () {
|
||||
that.screen.render();
|
||||
}, 300);
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Refresh dashboard
|
||||
* @method refresh
|
||||
* @param {} processes
|
||||
* @return this
|
||||
*/
|
||||
Dashboard.refresh = function(processes) {
|
||||
debug('Monit refresh');
|
||||
|
||||
if(!processes) {
|
||||
this.list.setItem(0, 'No process available');
|
||||
return;
|
||||
}
|
||||
|
||||
if (processes.length != this.list.items.length) {
|
||||
this.list.clearItems();
|
||||
}
|
||||
|
||||
// Total of processes memory
|
||||
var mem = 0;
|
||||
processes.forEach(function(proc) {
|
||||
mem += proc.monit.memory;
|
||||
})
|
||||
|
||||
// Sort process list
|
||||
processes.sort(function(a, b) {
|
||||
if (a.pm2_env.name < b.pm2_env.name)
|
||||
return -1;
|
||||
if (a.pm2_env.name > b.pm2_env.name)
|
||||
return 1;
|
||||
return 0;
|
||||
});
|
||||
|
||||
// Loop to get process infos
|
||||
for (var i = 0; i < processes.length; i++) {
|
||||
// Percent of memory use by one process in all pm2 processes
|
||||
var memPercent = (processes[i].monit.memory / mem) * 100;
|
||||
|
||||
// Status of process
|
||||
var status = processes[i].pm2_env.status == 'online' ? '{green-fg}' : '{red-fg}';
|
||||
status = status + '{bold}' + processes[i].pm2_env.status + '{/}';
|
||||
|
||||
var name = processes[i].pm2_env.name || p.basename(processes[i].pm2_env.pm_exec_path);
|
||||
|
||||
// Line of list
|
||||
var item = printf('[%2s] %s {|} Mem: {bold}{%s-fg}%3d{/} MB CPU: {bold}{%s-fg}%2d{/} %s %s',
|
||||
processes[i].pm2_env.pm_id,
|
||||
name,
|
||||
gradient(memPercent, [255, 0, 0], [0, 255, 0]),
|
||||
(processes[i].monit.memory / 1048576).toFixed(2),
|
||||
gradient(processes[i].monit.cpu, [255, 0, 0], [0, 255, 0]),
|
||||
processes[i].monit.cpu,
|
||||
"%",
|
||||
status);
|
||||
|
||||
// Check if item exist
|
||||
if (this.list.getItem(i)) {
|
||||
this.list.setItem(i, item);
|
||||
}
|
||||
else {
|
||||
this.list.pushItem(item);
|
||||
}
|
||||
|
||||
var proc = processes[this.list.selected];
|
||||
// render the logBox
|
||||
let process_id = proc.pm_id
|
||||
let logs = this.logLines[process_id];
|
||||
if(typeof(logs) !== "undefined"){
|
||||
this.logBox.setItems(logs)
|
||||
if (!this.logBox.focused) {
|
||||
this.logBox.setScrollPerc(100);
|
||||
}
|
||||
}else{
|
||||
this.logBox.clearItems();
|
||||
}
|
||||
this.logBox.setLabel(` ${proc.pm2_env.name} Logs `)
|
||||
|
||||
this.metadataBox.setLine(0, 'App Name ' + '{bold}' + proc.pm2_env.name + '{/}');
|
||||
this.metadataBox.setLine(1, 'Namespace ' + '{bold}' + proc.pm2_env.namespace + '{/}');
|
||||
this.metadataBox.setLine(2, 'Version ' + '{bold}' + proc.pm2_env.version + '{/}');
|
||||
this.metadataBox.setLine(3, 'Restarts ' + proc.pm2_env.restart_time);
|
||||
this.metadataBox.setLine(4, 'Uptime ' + ((proc.pm2_env.pm_uptime && proc.pm2_env.status == 'online') ? timeSince(proc.pm2_env.pm_uptime) : 0));
|
||||
this.metadataBox.setLine(5, 'Script path ' + proc.pm2_env.pm_exec_path);
|
||||
this.metadataBox.setLine(6, 'Script args ' + (proc.pm2_env.args ? (typeof proc.pm2_env.args == 'string' ? JSON.parse(proc.pm2_env.args.replace(/'/g, '"')):proc.pm2_env.args).join(' ') : 'N/A'));
|
||||
this.metadataBox.setLine(7, 'Interpreter ' + proc.pm2_env.exec_interpreter);
|
||||
this.metadataBox.setLine(8, 'Interpreter args ' + (proc.pm2_env.node_args.length != 0 ? proc.pm2_env.node_args : 'N/A'));
|
||||
this.metadataBox.setLine(9, 'Exec mode ' + (proc.pm2_env.exec_mode == 'fork_mode' ? '{bold}fork{/}' : '{blue-fg}{bold}cluster{/}'));
|
||||
this.metadataBox.setLine(10, 'Node.js version ' + proc.pm2_env.node_version);
|
||||
this.metadataBox.setLine(11, 'watch & reload ' + (proc.pm2_env.watch ? '{green-fg}{bold}✔{/}' : '{red-fg}{bold}✘{/}'));
|
||||
this.metadataBox.setLine(12, 'Unstable restarts ' + proc.pm2_env.unstable_restarts);
|
||||
|
||||
this.metadataBox.setLine(13, 'Comment ' + ((proc.pm2_env.versioning) ? proc.pm2_env.versioning.comment : 'N/A'));
|
||||
this.metadataBox.setLine(14, 'Revision ' + ((proc.pm2_env.versioning) ? proc.pm2_env.versioning.revision : 'N/A'));
|
||||
this.metadataBox.setLine(15, 'Branch ' + ((proc.pm2_env.versioning) ? proc.pm2_env.versioning.branch : 'N/A'));
|
||||
this.metadataBox.setLine(16, 'Remote url ' + ((proc.pm2_env.versioning) ? proc.pm2_env.versioning.url : 'N/A'));
|
||||
this.metadataBox.deleteLine(17)
|
||||
this.metadataBox.setLine(17, 'Last update ' + ((proc.pm2_env.versioning) ? proc.pm2_env.versioning.update_time : 'N/A'));
|
||||
|
||||
if (Object.keys(proc.pm2_env.axm_monitor).length != this.metricsBox.items.length) {
|
||||
this.metricsBox.clearItems();
|
||||
}
|
||||
var j = 0;
|
||||
for (var key in proc.pm2_env.axm_monitor) {
|
||||
var metric_name = proc.pm2_env.axm_monitor[key].hasOwnProperty('value') ? proc.pm2_env.axm_monitor[key].value : proc.pm2_env.axm_monitor[key]
|
||||
var metric_unit = proc.pm2_env.axm_monitor[key].hasOwnProperty('unit') ? proc.pm2_env.axm_monitor[key].unit : null
|
||||
var probe = `{bold}${key}{/} {|} ${metric_name}${metric_unit == null ? '' : ' ' + metric_unit}`
|
||||
|
||||
if (this.metricsBox.getItem(j)) {
|
||||
this.metricsBox.setItem(j, probe);
|
||||
}
|
||||
else {
|
||||
this.metricsBox.pushItem(probe);
|
||||
}
|
||||
j++;
|
||||
}
|
||||
|
||||
this.screen.render();
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Put Log
|
||||
* @method log
|
||||
* @param {} data
|
||||
* @return this
|
||||
*/
|
||||
Dashboard.log = function(type, data) {
|
||||
var that = this;
|
||||
|
||||
if(typeof(this.logLines[data.process.pm_id]) == "undefined"){
|
||||
this.logLines[data.process.pm_id]=[];
|
||||
}
|
||||
// Logs colors
|
||||
switch (type) {
|
||||
case 'PM2':
|
||||
var color = '{blue-fg}';
|
||||
break;
|
||||
case 'out':
|
||||
var color = '{green-fg}';
|
||||
break;
|
||||
case 'err':
|
||||
var color = '{red-fg}';
|
||||
break;
|
||||
default:
|
||||
var color = '{white-fg}';
|
||||
}
|
||||
|
||||
var logs = data.data.split('\n')
|
||||
|
||||
logs.forEach((log) => {
|
||||
if (log.length > 0) {
|
||||
this.logLines[data.process.pm_id].push(color + data.process.name + '{/} > ' + log)
|
||||
|
||||
|
||||
//removing logs if longer than limit
|
||||
let count = 0;
|
||||
let max_count = 0;
|
||||
let leading_process_id = -1;
|
||||
|
||||
for(var process_id in this.logLines){
|
||||
count += this.logLines[process_id].length;
|
||||
if( this.logLines[process_id].length > max_count){
|
||||
leading_process_id = process_id;
|
||||
max_count = this.logLines[process_id].length;
|
||||
}
|
||||
}
|
||||
|
||||
if (count > 200) {
|
||||
this.logLines[leading_process_id].shift()
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
module.exports = Dashboard;
|
||||
|
||||
function timeSince(date) {
|
||||
|
||||
var seconds = Math.floor((new Date() - date) / 1000);
|
||||
|
||||
var interval = Math.floor(seconds / 31536000);
|
||||
|
||||
if (interval > 1) {
|
||||
return interval + 'Y';
|
||||
}
|
||||
interval = Math.floor(seconds / 2592000);
|
||||
if (interval > 1) {
|
||||
return interval + 'M';
|
||||
}
|
||||
interval = Math.floor(seconds / 86400);
|
||||
if (interval > 1) {
|
||||
return interval + 'D';
|
||||
}
|
||||
interval = Math.floor(seconds / 3600);
|
||||
if (interval > 1) {
|
||||
return interval + 'h';
|
||||
}
|
||||
interval = Math.floor(seconds / 60);
|
||||
if (interval > 1) {
|
||||
return interval + 'm';
|
||||
}
|
||||
return Math.floor(seconds) + 's';
|
||||
}
|
||||
|
||||
/* Args :
|
||||
* p : Percent 0 - 100
|
||||
* rgb_ : Array of rgb [255, 255, 255]
|
||||
* Return :
|
||||
* Hexa #FFFFFF
|
||||
*/
|
||||
function gradient(p, rgb_beginning, rgb_end) {
|
||||
|
||||
var w = (p / 100) * 2 - 1;
|
||||
|
||||
var w1 = (w + 1) / 2.0;
|
||||
var w2 = 1 - w1;
|
||||
|
||||
var rgb = [parseInt(rgb_beginning[0] * w1 + rgb_end[0] * w2),
|
||||
parseInt(rgb_beginning[1] * w1 + rgb_end[1] * w2),
|
||||
parseInt(rgb_beginning[2] * w1 + rgb_end[2] * w2)];
|
||||
|
||||
return "#" + ((1 << 24) + (rgb[0] << 16) + (rgb[1] << 8) + rgb[2]).toString(16).slice(1);
|
||||
}
|
||||
117
api.hyungi.net/node_modules/pm2/lib/API/Deploy.js
generated
vendored
Normal file
117
api.hyungi.net/node_modules/pm2/lib/API/Deploy.js
generated
vendored
Normal file
@@ -0,0 +1,117 @@
|
||||
/**
|
||||
* Copyright 2013-2022 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 cst = require('../../constants.js');
|
||||
var Utility = require('../Utility.js');
|
||||
var Common = require('../Common.js');
|
||||
|
||||
function deployHelper() {
|
||||
console.log('');
|
||||
console.log('-----> Helper: Deployment with PM2');
|
||||
console.log('');
|
||||
console.log(' Generate a sample ecosystem.config.js with the command');
|
||||
console.log(' $ pm2 ecosystem');
|
||||
console.log(' Then edit the file depending on your needs');
|
||||
console.log('');
|
||||
console.log(' Commands:');
|
||||
console.log(' setup run remote setup commands');
|
||||
console.log(' update update deploy to the latest release');
|
||||
console.log(' revert [n] revert to [n]th last deployment or 1');
|
||||
console.log(' curr[ent] output current release commit');
|
||||
console.log(' prev[ious] output previous release commit');
|
||||
console.log(' exec|run <cmd> execute the given <cmd>');
|
||||
console.log(' list list previous deploy commits');
|
||||
console.log(' [ref] deploy to [ref], the "ref" setting, or latest tag');
|
||||
console.log('');
|
||||
console.log('');
|
||||
console.log(' Basic Examples:');
|
||||
console.log('');
|
||||
console.log(' First initialize remote production host:');
|
||||
console.log(' $ pm2 deploy ecosystem.config.js production setup');
|
||||
console.log('');
|
||||
console.log(' Then deploy new code:');
|
||||
console.log(' $ pm2 deploy ecosystem.config.js production');
|
||||
console.log('');
|
||||
console.log(' If I want to revert to the previous commit:');
|
||||
console.log(' $ pm2 deploy ecosystem.config.js production revert 1');
|
||||
console.log('');
|
||||
console.log(' Execute a command on remote server:');
|
||||
console.log(' $ pm2 deploy ecosystem.config.js production exec "pm2 restart all"');
|
||||
console.log('');
|
||||
console.log(' PM2 will look by default to the ecosystem.config.js file so you dont need to give the file name:');
|
||||
console.log(' $ pm2 deploy production');
|
||||
console.log(' Else you have to tell PM2 the name of your ecosystem file');
|
||||
console.log('');
|
||||
console.log(' More examples in https://github.com/Unitech/pm2');
|
||||
console.log('');
|
||||
};
|
||||
|
||||
module.exports = function(CLI) {
|
||||
CLI.prototype.deploy = function(file, commands, cb) {
|
||||
var that = this;
|
||||
|
||||
if (file == 'help') {
|
||||
deployHelper();
|
||||
return cb ? cb() : that.exitCli(cst.SUCCESS_EXIT);
|
||||
}
|
||||
|
||||
var args = commands.rawArgs;
|
||||
var env;
|
||||
|
||||
args.splice(0, args.indexOf('deploy') + 1);
|
||||
|
||||
// Find ecosystem file by default
|
||||
if (!Common.isConfigFile(file)) {
|
||||
env = args[0];
|
||||
var defaultConfigNames = [ ...Common.getConfigFileCandidates('ecosystem'), 'ecosystem.json5', 'package.json'];
|
||||
|
||||
file = Utility.whichFileExists(defaultConfigNames);
|
||||
|
||||
if (!file) {
|
||||
Common.printError('Not any default deployment file exists.'+
|
||||
' Allowed default config file names are: ' + defaultConfigNames.join(', '));
|
||||
return cb ? cb('Not any default ecosystem file present') : that.exitCli(cst.ERROR_EXIT);
|
||||
}
|
||||
}
|
||||
else
|
||||
env = args[1];
|
||||
|
||||
var json_conf = null;
|
||||
|
||||
try {
|
||||
json_conf = Common.parseConfig(fs.readFileSync(file), file);
|
||||
} catch (e) {
|
||||
Common.printError(e);
|
||||
return cb ? cb(e) : that.exitCli(cst.ERROR_EXIT);
|
||||
}
|
||||
|
||||
if (!env) {
|
||||
deployHelper();
|
||||
return cb ? cb() : that.exitCli(cst.SUCCESS_EXIT);
|
||||
}
|
||||
|
||||
if (!json_conf.deploy || !json_conf.deploy[env]) {
|
||||
Common.printError('%s environment is not defined in %s file', env, file);
|
||||
return cb ? cb('%s environment is not defined in %s file') : that.exitCli(cst.ERROR_EXIT);
|
||||
}
|
||||
|
||||
if (!json_conf.deploy[env]['post-deploy']) {
|
||||
json_conf.deploy[env]['post-deploy'] = 'pm2 startOrRestart ' + file + ' --env ' + env;
|
||||
}
|
||||
|
||||
require('pm2-deploy').deployForEnv(json_conf.deploy, env, args, function(err, data) {
|
||||
if (err) {
|
||||
Common.printError('Deploy failed');
|
||||
Common.printError(err.message || err);
|
||||
return cb ? cb(err) : that.exitCli(cst.ERROR_EXIT);
|
||||
}
|
||||
Common.printOut('--> Success');
|
||||
return cb ? cb(null, data) : that.exitCli(cst.SUCCESS_EXIT);
|
||||
});
|
||||
};
|
||||
|
||||
};
|
||||
775
api.hyungi.net/node_modules/pm2/lib/API/Extra.js
generated
vendored
Normal file
775
api.hyungi.net/node_modules/pm2/lib/API/Extra.js
generated
vendored
Normal file
@@ -0,0 +1,775 @@
|
||||
|
||||
/***************************
|
||||
*
|
||||
* Extra methods
|
||||
*
|
||||
**************************/
|
||||
|
||||
var cst = require('../../constants.js');
|
||||
var Common = require('../Common.js');
|
||||
var UX = require('./UX');
|
||||
var chalk = require('chalk');
|
||||
var path = require('path');
|
||||
var fs = require('fs');
|
||||
var fmt = require('../tools/fmt.js');
|
||||
var dayjs = require('dayjs');
|
||||
var pkg = require('../../package.json');
|
||||
const copyDirSync = require('../tools/copydirSync.js')
|
||||
|
||||
module.exports = function(CLI) {
|
||||
/**
|
||||
* Get version of the daemonized PM2
|
||||
* @method getVersion
|
||||
* @callback cb
|
||||
*/
|
||||
CLI.prototype.getVersion = function(cb) {
|
||||
var that = this;
|
||||
|
||||
that.Client.executeRemote('getVersion', {}, function(err) {
|
||||
return cb ? cb.apply(null, arguments) : that.exitCli(cst.SUCCESS_EXIT);
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Install pm2-sysmonit
|
||||
*/
|
||||
CLI.prototype.launchSysMonitoring = function(cb) {
|
||||
if ((this.pm2_configuration && this.pm2_configuration.sysmonit != 'true') ||
|
||||
process.env.TRAVIS ||
|
||||
global.it === 'function' ||
|
||||
cst.IS_WINDOWS === true)
|
||||
return cb ? cb(null) : null
|
||||
|
||||
var filepath
|
||||
|
||||
try {
|
||||
filepath = path.dirname(require.resolve('pm2-sysmonit'))
|
||||
} catch(e) {
|
||||
return cb ? cb(null) : null
|
||||
}
|
||||
|
||||
this.start({
|
||||
script: filepath
|
||||
}, {
|
||||
started_as_module : true
|
||||
}, (err, res) => {
|
||||
if (err) {
|
||||
Common.printError(cst.PREFIX_MSG_ERR + 'Error while trying to serve : ' + err.message || err);
|
||||
return cb ? cb(err) : this.speedList(cst.ERROR_EXIT);
|
||||
}
|
||||
return cb ? cb(null) : this.speedList();
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Show application environment
|
||||
* @method env
|
||||
* @callback cb
|
||||
*/
|
||||
CLI.prototype.env = function(app_id, cb) {
|
||||
var procs = []
|
||||
var printed = 0
|
||||
|
||||
this.Client.executeRemote('getMonitorData', {}, (err, list) => {
|
||||
list.forEach(l => {
|
||||
if (app_id == l.pm_id) {
|
||||
printed++
|
||||
var env = Common.safeExtend({}, l.pm2_env)
|
||||
Object.keys(env).forEach(key => {
|
||||
console.log(`${key}: ${chalk.green(env[key])}`)
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
if (printed == 0) {
|
||||
Common.err(`Modules with id ${app_id} not found`)
|
||||
return cb ? cb.apply(null, arguments) : this.exitCli(cst.ERROR_EXIT);
|
||||
}
|
||||
return cb ? cb.apply(null, arguments) : this.exitCli(cst.SUCCESS_EXIT);
|
||||
})
|
||||
};
|
||||
|
||||
/**
|
||||
* Get version of the daemonized PM2
|
||||
* @method getVersion
|
||||
* @callback cb
|
||||
*/
|
||||
CLI.prototype.report = function() {
|
||||
var that = this;
|
||||
|
||||
var Log = require('./Log');
|
||||
|
||||
that.Client.executeRemote('getReport', {}, function(err, report) {
|
||||
|
||||
console.log()
|
||||
console.log()
|
||||
console.log()
|
||||
console.log('```')
|
||||
fmt.title('PM2 report')
|
||||
fmt.field('Date', new Date());
|
||||
fmt.sep();
|
||||
|
||||
if (report && !err) {
|
||||
fmt.title(chalk.bold.blue('Daemon'));
|
||||
fmt.field('pm2d version', report.pm2_version);
|
||||
fmt.field('node version', report.node_version);
|
||||
fmt.field('node path', report.node_path);
|
||||
fmt.field('argv', report.argv);
|
||||
fmt.field('argv0', report.argv0);
|
||||
fmt.field('user', report.user);
|
||||
fmt.field('uid', report.uid);
|
||||
fmt.field('gid', report.gid);
|
||||
fmt.field('uptime', dayjs(new Date()).diff(report.started_at, 'minute') + 'min');
|
||||
}
|
||||
|
||||
fmt.sep();
|
||||
fmt.title(chalk.bold.blue('CLI'));
|
||||
fmt.field('local pm2', pkg.version);
|
||||
fmt.field('node version', process.versions.node);
|
||||
fmt.field('node path', process.env['_'] || 'not found');
|
||||
fmt.field('argv', process.argv);
|
||||
fmt.field('argv0', process.argv0);
|
||||
fmt.field('user', process.env.USER || process.env.LNAME || process.env.USERNAME);
|
||||
if (cst.IS_WINDOWS === false && process.geteuid)
|
||||
fmt.field('uid', process.geteuid());
|
||||
if (cst.IS_WINDOWS === false && process.getegid)
|
||||
fmt.field('gid', process.getegid());
|
||||
|
||||
var os = require('os');
|
||||
|
||||
fmt.sep();
|
||||
fmt.title(chalk.bold.blue('System info'));
|
||||
fmt.field('arch', os.arch());
|
||||
fmt.field('platform', os.platform());
|
||||
fmt.field('type', os.type());
|
||||
fmt.field('cpus', os.cpus()[0].model);
|
||||
fmt.field('cpus nb', Object.keys(os.cpus()).length);
|
||||
fmt.field('freemem', os.freemem());
|
||||
fmt.field('totalmem', os.totalmem());
|
||||
fmt.field('home', os.homedir());
|
||||
|
||||
that.Client.executeRemote('getMonitorData', {}, function(err, list) {
|
||||
|
||||
fmt.sep();
|
||||
fmt.title(chalk.bold.blue('PM2 list'));
|
||||
UX.list(list, that.gl_interact_infos);
|
||||
|
||||
fmt.sep();
|
||||
fmt.title(chalk.bold.blue('Daemon logs'));
|
||||
Log.tail([{
|
||||
path : cst.PM2_LOG_FILE_PATH,
|
||||
app_name : 'PM2',
|
||||
type : 'PM2'
|
||||
}], 20, false, function() {
|
||||
console.log('```')
|
||||
console.log()
|
||||
console.log()
|
||||
|
||||
console.log(chalk.bold.green('Please copy/paste the above report in your issue on https://github.com/Unitech/pm2/issues'));
|
||||
|
||||
console.log()
|
||||
console.log()
|
||||
that.exitCli(cst.SUCCESS_EXIT);
|
||||
});
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
CLI.prototype.getPID = function(app_name, cb) {
|
||||
var that = this;
|
||||
|
||||
if (typeof(app_name) === 'function') {
|
||||
cb = app_name;
|
||||
app_name = null;
|
||||
}
|
||||
|
||||
this.Client.executeRemote('getMonitorData', {}, function(err, list) {
|
||||
if (err) {
|
||||
Common.printError(cst.PREFIX_MSG_ERR + err);
|
||||
return cb ? cb(Common.retErr(err)) : that.exitCli(cst.ERROR_EXIT);
|
||||
}
|
||||
|
||||
var pids = [];
|
||||
|
||||
list.forEach(function(app) {
|
||||
if (!app_name || app_name == app.name)
|
||||
pids.push(app.pid);
|
||||
})
|
||||
|
||||
if (!cb) {
|
||||
Common.printOut(pids.join("\n"))
|
||||
return that.exitCli(cst.SUCCESS_EXIT);
|
||||
}
|
||||
return cb(null, pids);
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* Create PM2 memory snapshot
|
||||
* @method getVersion
|
||||
* @callback cb
|
||||
*/
|
||||
CLI.prototype.profile = function(type, time, cb) {
|
||||
var that = this;
|
||||
var dayjs = require('dayjs');
|
||||
var cmd
|
||||
|
||||
if (type == 'cpu') {
|
||||
cmd = {
|
||||
ext: '.cpuprofile',
|
||||
action: 'profileCPU'
|
||||
}
|
||||
}
|
||||
if (type == 'mem') {
|
||||
cmd = {
|
||||
ext: '.heapprofile',
|
||||
action: 'profileMEM'
|
||||
}
|
||||
}
|
||||
|
||||
var file = path.join(process.cwd(), dayjs().format('dd-HH:mm:ss') + cmd.ext);
|
||||
time = time || 10000
|
||||
|
||||
console.log(`Starting ${cmd.action} profiling for ${time}ms...`)
|
||||
that.Client.executeRemote(cmd.action, {
|
||||
pwd : file,
|
||||
timeout: time
|
||||
}, function(err) {
|
||||
if (err) {
|
||||
console.error(err);
|
||||
return that.exitCli(1);
|
||||
}
|
||||
console.log(`Profile done in ${file}`)
|
||||
return cb ? cb.apply(null, arguments) : that.exitCli(cst.SUCCESS_EXIT);
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
function basicMDHighlight(lines) {
|
||||
console.log('\n\n+-------------------------------------+')
|
||||
console.log(chalk.bold('README.md content:'))
|
||||
lines = lines.split('\n')
|
||||
var isInner = false
|
||||
lines.forEach(l => {
|
||||
if (l.startsWith('#'))
|
||||
console.log(chalk.bold.green(l))
|
||||
else if (isInner || l.startsWith('```')) {
|
||||
if (isInner && l.startsWith('```'))
|
||||
isInner = false
|
||||
else if (isInner == false)
|
||||
isInner = true
|
||||
console.log(chalk.grey(l))
|
||||
}
|
||||
else if (l.startsWith('`'))
|
||||
console.log(chalk.grey(l))
|
||||
else
|
||||
console.log(l)
|
||||
})
|
||||
console.log('+-------------------------------------+')
|
||||
}
|
||||
/**
|
||||
* pm2 create command
|
||||
* create boilerplate of application for fast try
|
||||
* @method boilerplate
|
||||
*/
|
||||
CLI.prototype.boilerplate = function(cb) {
|
||||
var i = 0
|
||||
var projects = []
|
||||
var enquirer = require('enquirer')
|
||||
const forEach = require('async/forEach')
|
||||
|
||||
fs.readdir(path.join(__dirname, '../templates/sample-apps'), (err, items) => {
|
||||
forEach(items, (app, next) => {
|
||||
var fp = path.join(__dirname, '../templates/sample-apps', app)
|
||||
fs.readFile(path.join(fp, 'package.json'), (err, dt) => {
|
||||
var meta = JSON.parse(dt)
|
||||
meta.fullpath = fp
|
||||
meta.folder_name = app
|
||||
projects.push(meta)
|
||||
next()
|
||||
})
|
||||
}, () => {
|
||||
const prompt = new enquirer.Select({
|
||||
name: 'boilerplate',
|
||||
message: 'Select a boilerplate',
|
||||
choices: projects.map((p, i) => {
|
||||
return {
|
||||
message: `${chalk.bold.blue(p.name)} ${p.description}`,
|
||||
value: `${i}`
|
||||
}
|
||||
})
|
||||
});
|
||||
|
||||
prompt.run()
|
||||
.then(answer => {
|
||||
var p = projects[parseInt(answer)]
|
||||
basicMDHighlight(fs.readFileSync(path.join(p.fullpath, 'README.md')).toString())
|
||||
console.log(chalk.bold(`>> Project copied inside folder ./${p.folder_name}/\n`))
|
||||
copyDirSync(p.fullpath, path.join(process.cwd(), p.folder_name));
|
||||
this.start(path.join(p.fullpath, 'ecosystem.config.js'), {
|
||||
cwd: p.fullpath
|
||||
}, () => {
|
||||
return cb ? cb.apply(null, arguments) : this.speedList(cst.SUCCESS_EXIT);
|
||||
})
|
||||
})
|
||||
.catch(e => {
|
||||
return cb ? cb.apply(null, arguments) : this.speedList(cst.SUCCESS_EXIT);
|
||||
});
|
||||
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* Description
|
||||
* @method sendLineToStdin
|
||||
*/
|
||||
CLI.prototype.sendLineToStdin = function(pm_id, line, separator, cb) {
|
||||
var that = this;
|
||||
|
||||
if (!cb && typeof(separator) == 'function') {
|
||||
cb = separator;
|
||||
separator = null;
|
||||
}
|
||||
|
||||
var packet = {
|
||||
pm_id : pm_id,
|
||||
line : line + (separator || '\n')
|
||||
};
|
||||
|
||||
that.Client.executeRemote('sendLineToStdin', packet, function(err, res) {
|
||||
if (err) {
|
||||
Common.printError(cst.PREFIX_MSG_ERR + err);
|
||||
return cb ? cb(Common.retErr(err)) : that.exitCli(cst.ERROR_EXIT);
|
||||
}
|
||||
return cb ? cb(null, res) : that.speedList();
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Description
|
||||
* @method attachToProcess
|
||||
*/
|
||||
CLI.prototype.attach = function(pm_id, separator, cb) {
|
||||
var that = this;
|
||||
var readline = require('readline');
|
||||
|
||||
if (isNaN(pm_id)) {
|
||||
Common.printError('pm_id must be a process number (not a process name)');
|
||||
return cb ? cb(Common.retErr('pm_id must be number')) : that.exitCli(cst.ERROR_EXIT);
|
||||
}
|
||||
|
||||
if (typeof(separator) == 'function') {
|
||||
cb = separator;
|
||||
separator = null;
|
||||
}
|
||||
|
||||
var rl = readline.createInterface({
|
||||
input: process.stdin,
|
||||
output: process.stdout
|
||||
});
|
||||
|
||||
rl.on('close', function() {
|
||||
return cb ? cb() : that.exitCli(cst.SUCCESS_EXIT);
|
||||
});
|
||||
|
||||
that.Client.launchBus(function(err, bus, socket) {
|
||||
if (err) {
|
||||
Common.printError(err);
|
||||
return cb ? cb(Common.retErr(err)) : that.exitCli(cst.ERROR_EXIT);
|
||||
}
|
||||
|
||||
bus.on('log:*', function(type, packet) {
|
||||
if (packet.process.pm_id !== parseInt(pm_id))
|
||||
return;
|
||||
process.stdout.write(packet.data);
|
||||
});
|
||||
});
|
||||
|
||||
rl.on('line', function(line) {
|
||||
that.sendLineToStdin(pm_id, line, separator, function() {});
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Description
|
||||
* @method sendDataToProcessId
|
||||
*/
|
||||
CLI.prototype.sendDataToProcessId = function(proc_id, packet, cb) {
|
||||
var that = this;
|
||||
|
||||
if (typeof proc_id === 'object' && typeof packet === 'function') {
|
||||
// the proc_id is packet.
|
||||
cb = packet;
|
||||
packet = proc_id;
|
||||
} else {
|
||||
packet.id = proc_id;
|
||||
}
|
||||
|
||||
that.Client.executeRemote('sendDataToProcessId', packet, function(err, res) {
|
||||
if (err) {
|
||||
Common.printError(err);
|
||||
return cb ? cb(Common.retErr(err)) : that.exitCli(cst.ERROR_EXIT);
|
||||
}
|
||||
Common.printOut('successfully sent data to process');
|
||||
return cb ? cb(null, res) : that.speedList();
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Used for custom actions, allows to trigger function inside an app
|
||||
* To expose a function you need to use keymetrics/pmx
|
||||
*
|
||||
* @method msgProcess
|
||||
* @param {Object} opts
|
||||
* @param {String} id process id
|
||||
* @param {String} action_name function name to trigger
|
||||
* @param {Object} [opts.opts] object passed as first arg of the function
|
||||
* @param {String} [uuid] optional unique identifier when logs are emitted
|
||||
*
|
||||
*/
|
||||
CLI.prototype.msgProcess = function(opts, cb) {
|
||||
var that = this;
|
||||
|
||||
that.Client.executeRemote('msgProcess', opts, cb);
|
||||
};
|
||||
|
||||
/**
|
||||
* Trigger a PMX custom action in target application
|
||||
* Custom actions allows to interact with an application
|
||||
*
|
||||
* @method trigger
|
||||
* @param {String|Number} pm_id process id or application name
|
||||
* @param {String} action_name name of the custom action to trigger
|
||||
* @param {Mixed} params parameter to pass to target action
|
||||
* @param {Function} cb callback
|
||||
*/
|
||||
CLI.prototype.trigger = function(pm_id, action_name, params, cb) {
|
||||
if (typeof(params) === 'function') {
|
||||
cb = params;
|
||||
params = null;
|
||||
}
|
||||
var cmd = {
|
||||
msg : action_name
|
||||
};
|
||||
var counter = 0;
|
||||
var process_wait_count = 0;
|
||||
var that = this;
|
||||
var results = [];
|
||||
|
||||
if (params)
|
||||
cmd.opts = params;
|
||||
if (isNaN(pm_id))
|
||||
cmd.name = pm_id;
|
||||
else
|
||||
cmd.id = pm_id;
|
||||
|
||||
this.launchBus(function(err, bus) {
|
||||
bus.on('axm:reply', function(ret) {
|
||||
if (ret.process.name == pm_id || ret.process.pm_id == pm_id || ret.process.namespace == pm_id || pm_id == 'all') {
|
||||
results.push(ret);
|
||||
Common.printOut('[%s:%s:%s]=%j', ret.process.name, ret.process.pm_id, ret.process.namespace, ret.data.return);
|
||||
if (++counter == process_wait_count)
|
||||
return cb ? cb(null, results) : that.exitCli(cst.SUCCESS_EXIT);
|
||||
}
|
||||
});
|
||||
|
||||
that.msgProcess(cmd, function(err, data) {
|
||||
if (err) {
|
||||
Common.printError(err);
|
||||
return cb ? cb(Common.retErr(err)) : that.exitCli(cst.ERROR_EXIT);
|
||||
}
|
||||
|
||||
if (data.process_count == 0) {
|
||||
Common.printError('Not any process has received a command (offline or unexistent)');
|
||||
return cb ? cb(Common.retErr('Unknown process')) : that.exitCli(cst.ERROR_EXIT);
|
||||
}
|
||||
|
||||
process_wait_count = data.process_count;
|
||||
Common.printOut(chalk.bold('%s processes have received command %s'),
|
||||
data.process_count, action_name);
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Description
|
||||
* @method sendSignalToProcessName
|
||||
* @param {} signal
|
||||
* @param {} process_name
|
||||
* @return
|
||||
*/
|
||||
CLI.prototype.sendSignalToProcessName = function(signal, process_name, cb) {
|
||||
var that = this;
|
||||
|
||||
that.Client.executeRemote('sendSignalToProcessName', {
|
||||
signal : signal,
|
||||
process_name : process_name
|
||||
}, function(err, list) {
|
||||
if (err) {
|
||||
Common.printError(err);
|
||||
return cb ? cb(Common.retErr(err)) : that.exitCli(cst.ERROR_EXIT);
|
||||
}
|
||||
Common.printOut('successfully sent signal %s to process name %s', signal, process_name);
|
||||
return cb ? cb(null, list) : that.speedList();
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Description
|
||||
* @method sendSignalToProcessId
|
||||
* @param {} signal
|
||||
* @param {} process_id
|
||||
* @return
|
||||
*/
|
||||
CLI.prototype.sendSignalToProcessId = function(signal, process_id, cb) {
|
||||
var that = this;
|
||||
|
||||
that.Client.executeRemote('sendSignalToProcessId', {
|
||||
signal : signal,
|
||||
process_id : process_id
|
||||
}, function(err, list) {
|
||||
if (err) {
|
||||
Common.printError(err);
|
||||
return cb ? cb(Common.retErr(err)) : that.exitCli(cst.ERROR_EXIT);
|
||||
}
|
||||
Common.printOut('successfully sent signal %s to process id %s', signal, process_id);
|
||||
return cb ? cb(null, list) : that.speedList();
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* API method to launch a process that will serve directory over http
|
||||
*/
|
||||
CLI.prototype.autoinstall = function (cb) {
|
||||
var filepath = path.resolve(path.dirname(module.filename), '../Sysinfo/ServiceDetection/ServiceDetection.js');
|
||||
|
||||
this.start(filepath, (err, res) => {
|
||||
if (err) {
|
||||
Common.printError(cst.PREFIX_MSG_ERR + 'Error while trying to serve : ' + err.message || err);
|
||||
return cb ? cb(err) : this.speedList(cst.ERROR_EXIT);
|
||||
}
|
||||
return cb ? cb(null) : this.speedList();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* API method to launch a process that will serve directory over http
|
||||
*
|
||||
* @param {Object} opts options
|
||||
* @param {String} opts.path path to be served
|
||||
* @param {Number} opts.port port on which http will bind
|
||||
* @param {Boolean} opts.spa single page app served
|
||||
* @param {String} opts.basicAuthUsername basic auth username
|
||||
* @param {String} opts.basicAuthPassword basic auth password
|
||||
* @param {Object} commander commander object
|
||||
* @param {Function} cb optional callback
|
||||
*/
|
||||
CLI.prototype.serve = function (target_path, port, opts, commander, cb) {
|
||||
var that = this;
|
||||
var servePort = process.env.PM2_SERVE_PORT || port || 8080;
|
||||
var servePath = path.resolve(process.env.PM2_SERVE_PATH || target_path || '.');
|
||||
|
||||
var filepath = path.resolve(path.dirname(module.filename), './Serve.js');
|
||||
|
||||
if (typeof commander.name === 'string')
|
||||
opts.name = commander.name
|
||||
else
|
||||
opts.name = 'static-page-server-' + servePort
|
||||
if (!opts.env)
|
||||
opts.env = {};
|
||||
opts.env.PM2_SERVE_PORT = servePort;
|
||||
opts.env.PM2_SERVE_PATH = servePath;
|
||||
opts.env.PM2_SERVE_SPA = opts.spa;
|
||||
if (opts.basicAuthUsername && opts.basicAuthPassword) {
|
||||
opts.env.PM2_SERVE_BASIC_AUTH = 'true';
|
||||
opts.env.PM2_SERVE_BASIC_AUTH_USERNAME = opts.basicAuthUsername;
|
||||
opts.env.PM2_SERVE_BASIC_AUTH_PASSWORD = opts.basicAuthPassword;
|
||||
}
|
||||
if (opts.monitor) {
|
||||
opts.env.PM2_SERVE_MONITOR = opts.monitor
|
||||
}
|
||||
opts.cwd = servePath;
|
||||
|
||||
this.start(filepath, opts, function (err, res) {
|
||||
if (err) {
|
||||
Common.printError(cst.PREFIX_MSG_ERR + 'Error while trying to serve : ' + err.message || err);
|
||||
return cb ? cb(err) : that.speedList(cst.ERROR_EXIT);
|
||||
}
|
||||
Common.printOut(cst.PREFIX_MSG + 'Serving ' + servePath + ' on port ' + servePort);
|
||||
return cb ? cb(null, res) : that.speedList();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Ping daemon - if PM2 daemon not launched, it will launch it
|
||||
* @method ping
|
||||
*/
|
||||
CLI.prototype.ping = function(cb) {
|
||||
var that = this;
|
||||
|
||||
that.Client.executeRemote('ping', {}, function(err, res) {
|
||||
if (err) {
|
||||
Common.printError(err);
|
||||
return cb ? cb(new Error(err)) : that.exitCli(cst.ERROR_EXIT);
|
||||
}
|
||||
Common.printOut(res);
|
||||
return cb ? cb(null, res) : that.exitCli(cst.SUCCESS_EXIT);
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Execute remote command
|
||||
*/
|
||||
CLI.prototype.remote = function(command, opts, cb) {
|
||||
var that = this;
|
||||
|
||||
that[command](opts.name, function(err_cmd, ret) {
|
||||
if (err_cmd)
|
||||
console.error(err_cmd);
|
||||
console.log('Command %s finished', command);
|
||||
return cb(err_cmd, ret);
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* This remote method allows to pass multiple arguments
|
||||
* to PM2
|
||||
* It is used for the new scoped PM2 action system
|
||||
*/
|
||||
CLI.prototype.remoteV2 = function(command, opts, cb) {
|
||||
var that = this;
|
||||
|
||||
if (that[command].length == 1)
|
||||
return that[command](cb);
|
||||
|
||||
opts.args.push(cb);
|
||||
return that[command].apply(this, opts.args);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Description
|
||||
* @method generateSample
|
||||
* @param {} name
|
||||
* @return
|
||||
*/
|
||||
CLI.prototype.generateSample = function(mode) {
|
||||
var that = this;
|
||||
var templatePath;
|
||||
|
||||
if (mode == 'simple')
|
||||
templatePath = path.join(cst.TEMPLATE_FOLDER, cst.APP_CONF_TPL_SIMPLE);
|
||||
else
|
||||
templatePath = path.join(cst.TEMPLATE_FOLDER, cst.APP_CONF_TPL);
|
||||
|
||||
var sample = fs.readFileSync(templatePath);
|
||||
var dt = sample.toString();
|
||||
var f_name = 'ecosystem.config.js';
|
||||
var pwd = process.env.PWD || process.cwd();
|
||||
|
||||
try {
|
||||
fs.writeFileSync(path.join(pwd, f_name), dt);
|
||||
} catch (e) {
|
||||
console.error(e.stack || e);
|
||||
return that.exitCli(cst.ERROR_EXIT);
|
||||
}
|
||||
Common.printOut('File %s generated', path.join(pwd, f_name));
|
||||
that.exitCli(cst.SUCCESS_EXIT);
|
||||
};
|
||||
|
||||
/**
|
||||
* Description
|
||||
* @method dashboard
|
||||
* @return
|
||||
*/
|
||||
CLI.prototype.dashboard = function(cb) {
|
||||
var that = this;
|
||||
|
||||
var Dashboard = require('./Dashboard');
|
||||
|
||||
if (cb)
|
||||
return cb(new Error('Dashboard cant be called programmatically'));
|
||||
|
||||
Dashboard.init();
|
||||
|
||||
this.Client.launchBus(function (err, bus) {
|
||||
if (err) {
|
||||
console.error('Error launchBus: ' + err);
|
||||
that.exitCli(cst.ERROR_EXIT);
|
||||
}
|
||||
bus.on('log:*', function(type, data) {
|
||||
Dashboard.log(type, data)
|
||||
})
|
||||
});
|
||||
|
||||
process.on('SIGINT', function() {
|
||||
this.Client.disconnectBus(function() {
|
||||
process.exit(cst.SUCCESS_EXIT);
|
||||
});
|
||||
});
|
||||
|
||||
function refreshDashboard() {
|
||||
that.Client.executeRemote('getMonitorData', {}, function(err, list) {
|
||||
if (err) {
|
||||
console.error('Error retrieving process list: ' + err);
|
||||
that.exitCli(cst.ERROR_EXIT);
|
||||
}
|
||||
|
||||
Dashboard.refresh(list);
|
||||
|
||||
setTimeout(function() {
|
||||
refreshDashboard();
|
||||
}, 800);
|
||||
});
|
||||
}
|
||||
|
||||
refreshDashboard();
|
||||
};
|
||||
|
||||
CLI.prototype.monit = function(cb) {
|
||||
var that = this;
|
||||
|
||||
var Monit = require('./Monit.js');
|
||||
|
||||
if (cb) return cb(new Error('Monit cant be called programmatically'));
|
||||
|
||||
Monit.init();
|
||||
|
||||
function launchMonitor() {
|
||||
that.Client.executeRemote('getMonitorData', {}, function(err, list) {
|
||||
if (err) {
|
||||
console.error('Error retrieving process list: ' + err);
|
||||
that.exitCli(conf.ERROR_EXIT);
|
||||
}
|
||||
|
||||
Monit.refresh(list);
|
||||
|
||||
setTimeout(function() {
|
||||
launchMonitor();
|
||||
}, 400);
|
||||
});
|
||||
}
|
||||
|
||||
launchMonitor();
|
||||
};
|
||||
|
||||
CLI.prototype.inspect = function(app_name, cb) {
|
||||
const that = this;
|
||||
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);
|
||||
});
|
||||
};
|
||||
};
|
||||
30
api.hyungi.net/node_modules/pm2/lib/API/ExtraMgmt/Docker.js
generated
vendored
Normal file
30
api.hyungi.net/node_modules/pm2/lib/API/ExtraMgmt/Docker.js
generated
vendored
Normal file
@@ -0,0 +1,30 @@
|
||||
|
||||
const util = require('util')
|
||||
const spawn = require('child_process').spawn
|
||||
const DockerMgmt = {}
|
||||
|
||||
module.exports = DockerMgmt
|
||||
|
||||
function execDocker(cmd, cb) {
|
||||
var i = spawn('docker', cmd, {
|
||||
stdio : 'inherit',
|
||||
env: process.env,
|
||||
shell : true
|
||||
})
|
||||
|
||||
i.on('close', cb)
|
||||
}
|
||||
|
||||
DockerMgmt.processCommand = function(PM2, start_id, select_id, action, cb) {
|
||||
PM2.Client.executeRemote('getSystemData', {}, (err, sys_infos) => {
|
||||
if (sys_infos.containers && sys_infos.containers.length == 0)
|
||||
return cb(new Error(`Process ${select_id} not found`))
|
||||
var container = sys_infos.containers[select_id - start_id - 1]
|
||||
if (action == 'stopProcessId')
|
||||
execDocker(['stop', container.id], cb)
|
||||
if (action == 'deleteProcessId')
|
||||
execDocker(['rm', container.id], cb)
|
||||
if (action == 'restartProcessId')
|
||||
execDocker(['restart', container.id], cb)
|
||||
})
|
||||
}
|
||||
315
api.hyungi.net/node_modules/pm2/lib/API/Log.js
generated
vendored
Normal file
315
api.hyungi.net/node_modules/pm2/lib/API/Log.js
generated
vendored
Normal file
@@ -0,0 +1,315 @@
|
||||
/**
|
||||
* Copyright 2013-2022 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'),
|
||||
util = require('util'),
|
||||
chalk = require('chalk'),
|
||||
forEachLimit = require('async/forEachLimit'),
|
||||
dayjs = require('dayjs');
|
||||
|
||||
var Log = module.exports = {};
|
||||
|
||||
var DEFAULT_PADDING = ' ';
|
||||
|
||||
/**
|
||||
* Tail logs from file stream.
|
||||
* @param {Object} apps_list
|
||||
* @param {Number} lines
|
||||
* @param {Boolean} raw
|
||||
* @param {Function} callback
|
||||
* @return
|
||||
*/
|
||||
|
||||
Log.tail = function(apps_list, lines, raw, callback) {
|
||||
var that = this;
|
||||
|
||||
if (lines === 0 || apps_list.length === 0)
|
||||
return callback && callback();
|
||||
|
||||
var count = 0;
|
||||
|
||||
var getLastLines = function (filename, lines, callback) {
|
||||
var chunk = '';
|
||||
var size = Math.max(0, fs.statSync(filename).size - (lines * 200));
|
||||
|
||||
var fd = fs.createReadStream(filename, {start : size});
|
||||
fd.on('data', function(data) { chunk += data.toString(); });
|
||||
fd.on('end', function() {
|
||||
chunk = chunk.split('\n').slice(-(lines+1));
|
||||
chunk.pop();
|
||||
callback(chunk);
|
||||
});
|
||||
};
|
||||
|
||||
apps_list.sort(function(a, b) {
|
||||
return (fs.existsSync(a.path) ? fs.statSync(a.path).mtime.valueOf() : 0) -
|
||||
(fs.existsSync(b.path) ? fs.statSync(b.path).mtime.valueOf() : 0);
|
||||
});
|
||||
|
||||
forEachLimit(apps_list, 1, function(app, next) {
|
||||
if (!fs.existsSync(app.path || ''))
|
||||
return next();
|
||||
|
||||
getLastLines(app.path, lines, function(output) {
|
||||
console.log(chalk.grey('%s last %d lines:'), app.path, lines);
|
||||
output.forEach(function(out) {
|
||||
if (raw)
|
||||
return app.type === 'err' ? console.error(out) : console.log(out);
|
||||
if (app.type === 'out')
|
||||
process.stdout.write(chalk.green(pad(DEFAULT_PADDING, app.app_name) + ' | '));
|
||||
else if (app.type === 'err')
|
||||
process.stdout.write(chalk.red(pad(DEFAULT_PADDING, app.app_name) + ' | '));
|
||||
else
|
||||
process.stdout.write(chalk.blue(pad(DEFAULT_PADDING, 'PM2') + ' | '));
|
||||
console.log(out);
|
||||
});
|
||||
if (output.length)
|
||||
process.stdout.write('\n');
|
||||
next();
|
||||
});
|
||||
}, function() {
|
||||
callback && callback();
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Stream logs in realtime from the bus eventemitter.
|
||||
* @param {String} id
|
||||
* @param {Boolean} raw
|
||||
* @return
|
||||
*/
|
||||
|
||||
Log.stream = function(Client, id, raw, timestamp, exclusive, highlight) {
|
||||
var that = this;
|
||||
|
||||
Client.launchBus(function(err, bus, socket) {
|
||||
|
||||
socket.on('reconnect attempt', function() {
|
||||
if (global._auto_exit === true) {
|
||||
if (timestamp)
|
||||
process.stdout.write(chalk['dim'](chalk.grey(dayjs().format(timestamp) + ' ')));
|
||||
process.stdout.write(chalk.blue(pad(DEFAULT_PADDING, 'PM2') + ' | ') + '[[[ Target PM2 killed. ]]]');
|
||||
process.exit(0);
|
||||
}
|
||||
});
|
||||
|
||||
var min_padding = 3
|
||||
|
||||
bus.on('log:*', function(type, packet) {
|
||||
var isMatchingProcess = id === 'all'
|
||||
|| packet.process.name == id
|
||||
|| packet.process.pm_id == id
|
||||
|| packet.process.namespace == id;
|
||||
|
||||
if (!isMatchingProcess)
|
||||
return;
|
||||
|
||||
if ((type === 'out' && exclusive === 'err')
|
||||
|| (type === 'err' && exclusive === 'out')
|
||||
|| (type === 'PM2' && exclusive !== false))
|
||||
return;
|
||||
|
||||
var lines;
|
||||
|
||||
if (typeof(packet.data) === 'string')
|
||||
lines = (packet.data || '').split('\n');
|
||||
else
|
||||
return;
|
||||
|
||||
lines.forEach(function(line) {
|
||||
if (!line || line.length === 0) return;
|
||||
|
||||
if (raw)
|
||||
return type === 'err' ? process.stderr.write(util.format(line) + '\n') : process.stdout.write(util.format(line) + '\n');
|
||||
|
||||
if (timestamp)
|
||||
process.stdout.write(chalk['dim'](chalk.grey(dayjs().format(timestamp) + ' ')));
|
||||
|
||||
var name = packet.process.pm_id + '|' + packet.process.name;
|
||||
|
||||
if (name.length > min_padding)
|
||||
min_padding = name.length + 1
|
||||
|
||||
if (type === 'out')
|
||||
process.stdout.write(chalk.green(pad(' '.repeat(min_padding), name) + ' | '));
|
||||
else if (type === 'err')
|
||||
process.stdout.write(chalk.red(pad(' '.repeat(min_padding), name) + ' | '));
|
||||
else if (!raw && (id === 'all' || id === 'PM2'))
|
||||
process.stdout.write(chalk.blue(pad(' '.repeat(min_padding), 'PM2') + ' | '));
|
||||
if (highlight)
|
||||
process.stdout.write(util.format(line).replace(highlight, chalk.bgBlackBright(highlight)) + '\n');
|
||||
else
|
||||
process.stdout.write(util.format(line)+ '\n');
|
||||
});
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
Log.devStream = function(Client, id, raw, timestamp, exclusive) {
|
||||
var that = this;
|
||||
|
||||
Client.launchBus(function(err, bus) {
|
||||
|
||||
setTimeout(function() {
|
||||
bus.on('process:event', function(packet) {
|
||||
if (packet.event == 'online')
|
||||
console.log(chalk.green('[rundev] App %s restarted'), packet.process.name);
|
||||
});
|
||||
}, 1000);
|
||||
|
||||
var min_padding = 3
|
||||
|
||||
bus.on('log:*', function(type, packet) {
|
||||
if (id !== 'all'
|
||||
&& packet.process.name != id
|
||||
&& packet.process.pm_id != id)
|
||||
return;
|
||||
|
||||
if ((type === 'out' && exclusive === 'err')
|
||||
|| (type === 'err' && exclusive === 'out')
|
||||
|| (type === 'PM2' && exclusive !== false))
|
||||
return;
|
||||
|
||||
if (type === 'PM2')
|
||||
return;
|
||||
|
||||
var name = packet.process.pm_id + '|' + packet.process.name;
|
||||
|
||||
var lines;
|
||||
|
||||
if (typeof(packet.data) === 'string')
|
||||
lines = (packet.data || '').split('\n');
|
||||
else
|
||||
return;
|
||||
|
||||
lines.forEach(function(line) {
|
||||
if (!line || line.length === 0) return;
|
||||
|
||||
if (raw)
|
||||
return process.stdout.write(util.format(line) + '\n');
|
||||
|
||||
if (timestamp)
|
||||
process.stdout.write(chalk['dim'](chalk.grey(dayjs().format(timestamp) + ' ')));
|
||||
|
||||
var name = packet.process.name + '-' + packet.process.pm_id;
|
||||
|
||||
if (name.length > min_padding)
|
||||
min_padding = name.length + 1
|
||||
|
||||
if (type === 'out')
|
||||
process.stdout.write(chalk.green(pad(' '.repeat(min_padding), name) + ' | '));
|
||||
else if (type === 'err')
|
||||
process.stdout.write(chalk.red(pad(' '.repeat(min_padding), name) + ' | '));
|
||||
else if (!raw && (id === 'all' || id === 'PM2'))
|
||||
process.stdout.write(chalk.blue(pad(' '.repeat(min_padding), 'PM2') + ' | '));
|
||||
process.stdout.write(util.format(line) + '\n');
|
||||
});
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
Log.jsonStream = function(Client, id) {
|
||||
var that = this;
|
||||
|
||||
Client.launchBus(function(err, bus) {
|
||||
if (err) console.error(err);
|
||||
|
||||
bus.on('process:event', function(packet) {
|
||||
process.stdout.write(JSON.stringify({
|
||||
timestamp : dayjs(packet.at),
|
||||
type : 'process_event',
|
||||
status : packet.event,
|
||||
app_name : packet.process.name
|
||||
}));
|
||||
process.stdout.write('\n');
|
||||
});
|
||||
|
||||
bus.on('log:*', function(type, packet) {
|
||||
if (id !== 'all'
|
||||
&& packet.process.name != id
|
||||
&& packet.process.pm_id != id)
|
||||
return;
|
||||
|
||||
if (type === 'PM2')
|
||||
return;
|
||||
|
||||
if (typeof(packet.data) == 'string')
|
||||
packet.data = packet.data.replace(/(\r\n|\n|\r)/gm,'');
|
||||
|
||||
process.stdout.write(JSON.stringify({
|
||||
message : packet.data,
|
||||
timestamp : dayjs(packet.at),
|
||||
type : type,
|
||||
process_id : packet.process.pm_id,
|
||||
app_name : packet.process.name
|
||||
}));
|
||||
process.stdout.write('\n');
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
Log.formatStream = function(Client, id, raw, timestamp, exclusive, highlight) {
|
||||
var that = this;
|
||||
|
||||
Client.launchBus(function(err, bus) {
|
||||
|
||||
bus.on('log:*', function(type, packet) {
|
||||
if (id !== 'all'
|
||||
&& packet.process.name != id
|
||||
&& packet.process.pm_id != id)
|
||||
return;
|
||||
|
||||
if ((type === 'out' && exclusive === 'err')
|
||||
|| (type === 'err' && exclusive === 'out')
|
||||
|| (type === 'PM2' && exclusive !== false))
|
||||
return;
|
||||
|
||||
if (type === 'PM2' && raw)
|
||||
return;
|
||||
|
||||
var name = packet.process.name + '-' + packet.process.pm_id;
|
||||
|
||||
var lines;
|
||||
|
||||
if (typeof(packet.data) === 'string')
|
||||
lines = (packet.data || '').split('\n');
|
||||
else
|
||||
return;
|
||||
|
||||
lines.forEach(function(line) {
|
||||
if (!line || line.length === 0) return;
|
||||
|
||||
if (!raw) {
|
||||
if (timestamp)
|
||||
process.stdout.write('timestamp=' + dayjs().format(timestamp) + ' ');
|
||||
if (packet.process.name === 'PM2')
|
||||
process.stdout.write('app=pm2 ');
|
||||
if (packet.process.name !== 'PM2')
|
||||
process.stdout.write('app=' + packet.process.name + ' id=' + packet.process.pm_id + ' ');
|
||||
if (type === 'out')
|
||||
process.stdout.write('type=out ');
|
||||
else if (type === 'err')
|
||||
process.stdout.write('type=error ');
|
||||
}
|
||||
|
||||
process.stdout.write('message=');
|
||||
if (highlight)
|
||||
process.stdout.write(util.format(line).replace(highlight, chalk.bgBlackBright(highlight)) + '\n');
|
||||
else
|
||||
process.stdout.write(util.format(line) + '\n');
|
||||
});
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
function pad(pad, str, padLeft) {
|
||||
if (typeof str === 'undefined')
|
||||
return pad;
|
||||
if (padLeft) {
|
||||
return (pad + str).slice(-pad.length);
|
||||
} else {
|
||||
return (str + pad).substring(0, pad.length);
|
||||
}
|
||||
}
|
||||
371
api.hyungi.net/node_modules/pm2/lib/API/LogManagement.js
generated
vendored
Normal file
371
api.hyungi.net/node_modules/pm2/lib/API/LogManagement.js
generated
vendored
Normal file
@@ -0,0 +1,371 @@
|
||||
var chalk = require('chalk');
|
||||
var util = require('util');
|
||||
var fs = require('fs');
|
||||
var exec = require('child_process').exec;
|
||||
var path = require('path');
|
||||
|
||||
var Log = require('./Log');
|
||||
var cst = require('../../constants.js');
|
||||
var Common = require('../Common.js');
|
||||
|
||||
module.exports = function(CLI) {
|
||||
|
||||
/**
|
||||
* Description
|
||||
* @method flush
|
||||
* @return
|
||||
*/
|
||||
CLI.prototype.flush = function(api, cb) {
|
||||
var that = this;
|
||||
|
||||
if (!api) {
|
||||
Common.printOut(cst.PREFIX_MSG + 'Flushing ' + cst.PM2_LOG_FILE_PATH);
|
||||
fs.closeSync(fs.openSync(cst.PM2_LOG_FILE_PATH, 'w'));
|
||||
}
|
||||
|
||||
that.Client.executeRemote('getMonitorData', {}, function(err, list) {
|
||||
if (err) {
|
||||
Common.printError(err);
|
||||
return cb ? cb(Common.retErr(err)) : that.exitCli(cst.ERROR_EXIT);
|
||||
}
|
||||
list.forEach(function(l) {
|
||||
if (typeof api == 'undefined') {
|
||||
Common.printOut(cst.PREFIX_MSG + 'Flushing:');
|
||||
Common.printOut(cst.PREFIX_MSG + l.pm2_env.pm_out_log_path);
|
||||
Common.printOut(cst.PREFIX_MSG + l.pm2_env.pm_err_log_path);
|
||||
|
||||
if (l.pm2_env.pm_log_path) {
|
||||
Common.printOut(cst.PREFIX_MSG + l.pm2_env.pm_log_path);
|
||||
fs.closeSync(fs.openSync(l.pm2_env.pm_log_path, 'w'));
|
||||
}
|
||||
fs.closeSync(fs.openSync(l.pm2_env.pm_out_log_path, 'w'));
|
||||
fs.closeSync(fs.openSync(l.pm2_env.pm_err_log_path, 'w'));
|
||||
}
|
||||
else if (l.pm2_env.pm_id == api || l.pm2_env.name === api) {
|
||||
Common.printOut(cst.PREFIX_MSG + 'Flushing:');
|
||||
|
||||
if (l.pm2_env.pm_log_path && fs.existsSync(l.pm2_env.pm_log_path)) {
|
||||
Common.printOut(cst.PREFIX_MSG + l.pm2_env.pm_log_path);
|
||||
fs.closeSync(fs.openSync(l.pm2_env.pm_log_path, 'w'));
|
||||
}
|
||||
|
||||
if (l.pm2_env.pm_out_log_path && fs.existsSync(l.pm2_env.pm_out_log_path)) {
|
||||
Common.printOut(cst.PREFIX_MSG + l.pm2_env.pm_out_log_path);
|
||||
fs.closeSync(fs.openSync(l.pm2_env.pm_out_log_path, 'w'));
|
||||
}
|
||||
|
||||
if (l.pm2_env.pm_err_log_path && fs.existsSync(l.pm2_env.pm_err_log_path)) {
|
||||
Common.printOut(cst.PREFIX_MSG + l.pm2_env.pm_err_log_path);
|
||||
fs.closeSync(fs.openSync(l.pm2_env.pm_err_log_path, 'w'));
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
Common.printOut(cst.PREFIX_MSG + 'Logs flushed');
|
||||
return cb ? cb(null, list) : that.exitCli(cst.SUCCESS_EXIT);
|
||||
});
|
||||
};
|
||||
|
||||
CLI.prototype.logrotate = function(opts, cb) {
|
||||
var that = this;
|
||||
|
||||
if (process.getuid() != 0) {
|
||||
return exec('whoami', function(err, stdout, stderr) {
|
||||
Common.printError(cst.PREFIX_MSG + 'You have to run this command as root. Execute the following command:');
|
||||
Common.printError(cst.PREFIX_MSG + chalk.grey(' sudo env PATH=$PATH:' + path.dirname(process.execPath) + ' pm2 logrotate -u ' + stdout.trim()));
|
||||
|
||||
cb ? cb(Common.retErr('You have to run this with elevated rights')) : that.exitCli(cst.ERROR_EXIT);
|
||||
});
|
||||
}
|
||||
|
||||
if (!fs.existsSync('/etc/logrotate.d')) {
|
||||
Common.printError(cst.PREFIX_MSG + '/etc/logrotate.d does not exist we can not copy the default configuration.');
|
||||
return cb ? cb(Common.retErr('/etc/logrotate.d does not exist')) : that.exitCli(cst.ERROR_EXIT);
|
||||
}
|
||||
|
||||
var templatePath = path.join(cst.TEMPLATE_FOLDER, cst.LOGROTATE_SCRIPT);
|
||||
Common.printOut(cst.PREFIX_MSG + 'Getting logrorate template ' + templatePath);
|
||||
var script = fs.readFileSync(templatePath, {encoding: 'utf8'});
|
||||
|
||||
var user = opts.user || 'root';
|
||||
|
||||
script = script.replace(/%HOME_PATH%/g, cst.PM2_ROOT_PATH)
|
||||
.replace(/%USER%/g, user);
|
||||
|
||||
try {
|
||||
fs.writeFileSync('/etc/logrotate.d/pm2-'+user, script);
|
||||
} catch (e) {
|
||||
console.error(e.stack || e);
|
||||
}
|
||||
|
||||
Common.printOut(cst.PREFIX_MSG + 'Logrotate configuration added to /etc/logrotate.d/pm2');
|
||||
return cb ? cb(null, {success:true}) : that.exitCli(cst.SUCCESS_EXIT);
|
||||
};
|
||||
|
||||
/**
|
||||
* Description
|
||||
* @method reloadLogs
|
||||
* @return
|
||||
*/
|
||||
CLI.prototype.reloadLogs = function(cb) {
|
||||
var that = this;
|
||||
|
||||
Common.printOut('Reloading all logs...');
|
||||
that.Client.executeRemote('reloadLogs', {}, function(err, logs) {
|
||||
if (err) {
|
||||
Common.printError(err);
|
||||
return cb ? cb(Common.retErr(err)) : that.exitCli(cst.ERROR_EXIT);
|
||||
}
|
||||
Common.printOut('All logs reloaded');
|
||||
return cb ? cb(null, logs) : that.exitCli(cst.SUCCESS_EXIT);
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Description
|
||||
* @method streamLogs
|
||||
* @param {String} id
|
||||
* @param {Number} lines
|
||||
* @param {Boolean} raw
|
||||
* @return
|
||||
*/
|
||||
CLI.prototype.streamLogs = function(id, lines, raw, timestamp, exclusive, highlight) {
|
||||
var that = this;
|
||||
var files_list = [];
|
||||
|
||||
// If no argument is given, we stream logs for all running apps
|
||||
id = id || 'all';
|
||||
lines = lines !== undefined ? lines : 20;
|
||||
lines = lines < 0 ? -(lines) : lines;
|
||||
|
||||
// Avoid duplicates and check if path is different from '/dev/null'
|
||||
var pushIfUnique = function(entry) {
|
||||
var exists = false;
|
||||
|
||||
if (entry.path.toLowerCase
|
||||
&& entry.path.toLowerCase() !== '/dev/null') {
|
||||
|
||||
files_list.some(function(file) {
|
||||
if (file.path === entry.path)
|
||||
exists = true;
|
||||
return exists;
|
||||
});
|
||||
|
||||
if (exists)
|
||||
return;
|
||||
|
||||
files_list.push(entry);
|
||||
}
|
||||
}
|
||||
|
||||
// Get the list of all running apps
|
||||
that.Client.executeRemote('getMonitorData', {}, function(err, list) {
|
||||
var regexList = [];
|
||||
var namespaceList = [];
|
||||
|
||||
if (err) {
|
||||
Common.printError(err);
|
||||
that.exitCli(cst.ERROR_EXIT);
|
||||
}
|
||||
|
||||
if (lines === 0)
|
||||
return Log.stream(that.Client, id, raw, timestamp, exclusive, highlight);
|
||||
|
||||
Common.printOut(chalk.bold.grey(util.format.call(this, '[TAILING] Tailing last %d lines for [%s] process%s (change the value with --lines option)', lines, id, id === 'all' ? 'es' : '')));
|
||||
|
||||
// Populate the array `files_list` with the paths of all files we need to tail
|
||||
list.forEach(function(proc) {
|
||||
if (proc.pm2_env && (id === 'all' ||
|
||||
proc.pm2_env.name == id ||
|
||||
proc.pm2_env.pm_id == id)) {
|
||||
if (proc.pm2_env.pm_out_log_path && exclusive !== 'err')
|
||||
pushIfUnique({
|
||||
path : proc.pm2_env.pm_out_log_path,
|
||||
app_name :proc.pm2_env.pm_id + '|' + proc.pm2_env.name,
|
||||
type : 'out'});
|
||||
if (proc.pm2_env.pm_err_log_path && exclusive !== 'out')
|
||||
pushIfUnique({
|
||||
path : proc.pm2_env.pm_err_log_path,
|
||||
app_name : proc.pm2_env.pm_id + '|' + proc.pm2_env.name,
|
||||
type : 'err'
|
||||
});
|
||||
} else if(proc.pm2_env && proc.pm2_env.namespace == id) {
|
||||
if(namespaceList.indexOf(proc.pm2_env.name) === -1) {
|
||||
namespaceList.push(proc.pm2_env.name)
|
||||
}
|
||||
if (proc.pm2_env.pm_out_log_path && exclusive !== 'err')
|
||||
pushIfUnique({
|
||||
path : proc.pm2_env.pm_out_log_path,
|
||||
app_name :proc.pm2_env.pm_id + '|' + proc.pm2_env.name,
|
||||
type : 'out'});
|
||||
if (proc.pm2_env.pm_err_log_path && exclusive !== 'out')
|
||||
pushIfUnique({
|
||||
path : proc.pm2_env.pm_err_log_path,
|
||||
app_name : proc.pm2_env.pm_id + '|' + proc.pm2_env.name,
|
||||
type : 'err'
|
||||
});
|
||||
}
|
||||
// Populate the array `files_list` with the paths of all files we need to tail, when log in put is a regex
|
||||
else if(proc.pm2_env && (isNaN(id) && id[0] === '/' && id[id.length - 1] === '/')) {
|
||||
var regex = new RegExp(id.replace(/\//g, ''));
|
||||
if(regex.test(proc.pm2_env.name)) {
|
||||
if(regexList.indexOf(proc.pm2_env.name) === -1) {
|
||||
regexList.push(proc.pm2_env.name);
|
||||
}
|
||||
if (proc.pm2_env.pm_out_log_path && exclusive !== 'err')
|
||||
pushIfUnique({
|
||||
path : proc.pm2_env.pm_out_log_path,
|
||||
app_name : proc.pm2_env.pm_id + '|' + proc.pm2_env.name,
|
||||
type : 'out'});
|
||||
if (proc.pm2_env.pm_err_log_path && exclusive !== 'out')
|
||||
pushIfUnique({
|
||||
path : proc.pm2_env.pm_err_log_path,
|
||||
app_name : proc.pm2_env.pm_id + '|' + proc.pm2_env.name,
|
||||
type : 'err'
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
//for fixing issue https://github.com/Unitech/pm2/issues/3506
|
||||
/* if (files_list && files_list.length == 0) {
|
||||
Common.printError(cst.PREFIX_MSG_ERR + 'No file to stream for app [%s], exiting.', id);
|
||||
return process.exit(cst.ERROR_EXIT);
|
||||
}*/
|
||||
|
||||
if (!raw && (id === 'all' || id === 'PM2') && exclusive === false) {
|
||||
Log.tail([{
|
||||
path : cst.PM2_LOG_FILE_PATH,
|
||||
app_name : 'PM2',
|
||||
type : 'PM2'
|
||||
}], lines, raw, function() {
|
||||
Log.tail(files_list, lines, raw, function() {
|
||||
Log.stream(that.Client, id, raw, timestamp, exclusive, highlight);
|
||||
});
|
||||
});
|
||||
}
|
||||
else {
|
||||
Log.tail(files_list, lines, raw, function() {
|
||||
if(regexList.length > 0) {
|
||||
regexList.forEach(function(id) {
|
||||
Log.stream(that.Client, id, raw, timestamp, exclusive, highlight);
|
||||
})
|
||||
}
|
||||
else if(namespaceList.length > 0) {
|
||||
namespaceList.forEach(function(id) {
|
||||
Log.stream(that.Client, id, raw, timestamp, exclusive, highlight);
|
||||
})
|
||||
}
|
||||
else {
|
||||
Log.stream(that.Client, id, raw, timestamp, exclusive, highlight);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Description
|
||||
* @method printLogs
|
||||
* @param {String} id
|
||||
* @param {Number} lines
|
||||
* @param {Boolean} raw
|
||||
* @return
|
||||
*/
|
||||
CLI.prototype.printLogs = function(id, lines, raw, timestamp, exclusive) {
|
||||
var that = this;
|
||||
var files_list = [];
|
||||
|
||||
// If no argument is given, we stream logs for all running apps
|
||||
id = id || 'all';
|
||||
lines = lines !== undefined ? lines : 20;
|
||||
lines = lines < 0 ? -(lines) : lines;
|
||||
|
||||
// Avoid duplicates and check if path is different from '/dev/null'
|
||||
var pushIfUnique = function(entry) {
|
||||
var exists = false;
|
||||
|
||||
if (entry.path.toLowerCase
|
||||
&& entry.path.toLowerCase() !== '/dev/null') {
|
||||
|
||||
files_list.some(function(file) {
|
||||
if (file.path === entry.path)
|
||||
exists = true;
|
||||
return exists;
|
||||
});
|
||||
|
||||
if (exists)
|
||||
return;
|
||||
|
||||
files_list.push(entry);
|
||||
}
|
||||
}
|
||||
|
||||
// Get the list of all running apps
|
||||
that.Client.executeRemote('getMonitorData', {}, function(err, list) {
|
||||
if (err) {
|
||||
Common.printError(err);
|
||||
that.exitCli(cst.ERROR_EXIT);
|
||||
}
|
||||
|
||||
if (lines <= 0) {
|
||||
return that.exitCli(cst.SUCCESS_EXIT)
|
||||
}
|
||||
|
||||
Common.printOut(chalk.bold.grey(util.format.call(this, '[TAILING] Tailing last %d lines for [%s] process%s (change the value with --lines option)', lines, id, id === 'all' ? 'es' : '')));
|
||||
|
||||
// Populate the array `files_list` with the paths of all files we need to tail
|
||||
list.forEach(function(proc) {
|
||||
if (proc.pm2_env && (id === 'all' ||
|
||||
proc.pm2_env.name == id ||
|
||||
proc.pm2_env.pm_id == id)) {
|
||||
if (proc.pm2_env.pm_out_log_path && exclusive !== 'err')
|
||||
pushIfUnique({
|
||||
path : proc.pm2_env.pm_out_log_path,
|
||||
app_name :proc.pm2_env.pm_id + '|' + proc.pm2_env.name,
|
||||
type : 'out'});
|
||||
if (proc.pm2_env.pm_err_log_path && exclusive !== 'out')
|
||||
pushIfUnique({
|
||||
path : proc.pm2_env.pm_err_log_path,
|
||||
app_name : proc.pm2_env.pm_id + '|' + proc.pm2_env.name,
|
||||
type : 'err'
|
||||
});
|
||||
}
|
||||
// Populate the array `files_list` with the paths of all files we need to tail, when log in put is a regex
|
||||
else if(proc.pm2_env && (isNaN(id) && id[0] === '/' && id[id.length - 1] === '/')) {
|
||||
var regex = new RegExp(id.replace(/\//g, ''));
|
||||
if(regex.test(proc.pm2_env.name)) {
|
||||
if (proc.pm2_env.pm_out_log_path && exclusive !== 'err')
|
||||
pushIfUnique({
|
||||
path : proc.pm2_env.pm_out_log_path,
|
||||
app_name : proc.pm2_env.pm_id + '|' + proc.pm2_env.name,
|
||||
type : 'out'});
|
||||
if (proc.pm2_env.pm_err_log_path && exclusive !== 'out')
|
||||
pushIfUnique({
|
||||
path : proc.pm2_env.pm_err_log_path,
|
||||
app_name : proc.pm2_env.pm_id + '|' + proc.pm2_env.name,
|
||||
type : 'err'
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
if (!raw && (id === 'all' || id === 'PM2') && exclusive === false) {
|
||||
Log.tail([{
|
||||
path : cst.PM2_LOG_FILE_PATH,
|
||||
app_name : 'PM2',
|
||||
type : 'PM2'
|
||||
}], lines, raw, function() {
|
||||
Log.tail(files_list, lines, raw, function() {
|
||||
that.exitCli(cst.SUCCESS_EXIT);
|
||||
});
|
||||
});
|
||||
}
|
||||
else {
|
||||
Log.tail(files_list, lines, raw, function() {
|
||||
that.exitCli(cst.SUCCESS_EXIT);
|
||||
});
|
||||
}
|
||||
});
|
||||
};
|
||||
};
|
||||
122
api.hyungi.net/node_modules/pm2/lib/API/Modules/LOCAL.js
generated
vendored
Normal file
122
api.hyungi.net/node_modules/pm2/lib/API/Modules/LOCAL.js
generated
vendored
Normal file
@@ -0,0 +1,122 @@
|
||||
|
||||
var path = require('path');
|
||||
var fs = require('fs');
|
||||
var os = require('os');
|
||||
var spawn = require('child_process').spawn;
|
||||
var chalk = require('chalk');
|
||||
var parallel = require('async/parallel');
|
||||
|
||||
var Configuration = require('../../Configuration.js');
|
||||
var cst = require('../../../constants.js');
|
||||
var Common = require('../../Common');
|
||||
var Utility = require('../../Utility.js');
|
||||
var readline = require('readline')
|
||||
|
||||
var INTERNAL_MODULES = {
|
||||
'deep-monitoring': {
|
||||
dependencies: [{name: 'v8-profiler-node8'}, {name: 'gc-stats'}, {name: 'event-loop-inspector'}]
|
||||
},
|
||||
'gc-stats': {name: 'gc-stats'},
|
||||
'event-loop-inspector': {name: 'event-loop-inspector'},
|
||||
'v8-profiler': {name: 'v8-profiler-node8'},
|
||||
'profiler': {name: 'v8-profiler-node8'},
|
||||
'typescript': {dependencies: [{name: 'typescript'}, {name: 'ts-node@latest'}]},
|
||||
'livescript': {name: 'livescript'},
|
||||
'coffee-script': {name: 'coffee-script', message: 'Coffeescript v1 support'},
|
||||
'coffeescript': {name: 'coffeescript', message: 'Coffeescript v2 support'}
|
||||
};
|
||||
|
||||
module.exports = {
|
||||
install,
|
||||
INTERNAL_MODULES,
|
||||
installMultipleModules
|
||||
}
|
||||
|
||||
|
||||
function install(module, cb, verbose) {
|
||||
if (!module || !module.name || module.name.length === 0) {
|
||||
return cb(new Error('No module name !'));
|
||||
}
|
||||
|
||||
if (typeof verbose === 'undefined') {
|
||||
verbose = true;
|
||||
}
|
||||
|
||||
installLangModule(module.name, function (err) {
|
||||
var display = module.message || module.name;
|
||||
if (err) {
|
||||
if (verbose) { Common.printError(cst.PREFIX_MSG_MOD_ERR + chalk.bold.green(display + ' installation has FAILED (checkout previous logs)')); }
|
||||
return cb(err);
|
||||
}
|
||||
|
||||
if (verbose) { Common.printOut(cst.PREFIX_MSG + chalk.bold.green(display + ' ENABLED')); }
|
||||
return cb();
|
||||
});
|
||||
}
|
||||
|
||||
function installMultipleModules(modules, cb, post_install) {
|
||||
var functionList = [];
|
||||
for (var i = 0; i < modules.length; i++) {
|
||||
functionList.push((function (index) {
|
||||
return function (callback) {
|
||||
var module = modules[index];
|
||||
if (typeof modules[index] === 'string') {
|
||||
module = {name: modules[index]};
|
||||
}
|
||||
install(module, function ($post_install, err, $index, $modules) {
|
||||
try {
|
||||
var install_instance = spawn(post_install[modules[index]], {
|
||||
stdio : 'inherit',
|
||||
windowsHide: true,
|
||||
env: process.env,
|
||||
shell : true,
|
||||
cwd : process.cwd()
|
||||
});
|
||||
Common.printOut(cst.PREFIX_MSG_MOD + 'Running configuraton script.');
|
||||
}
|
||||
catch(e)
|
||||
{
|
||||
Common.printOut(cst.PREFIX_MSG_MOD + 'No configuraton script found.');
|
||||
}
|
||||
callback(null, { module: module, err: err });
|
||||
}, false);
|
||||
};
|
||||
})(i));
|
||||
}
|
||||
|
||||
parallel(functionList, function (err, results) {
|
||||
for (var i = 0; i < results.length; i++) {
|
||||
var display = results[i].module.message || results[i].module.name;
|
||||
if (results[i].err) {
|
||||
err = results[i].err;
|
||||
Common.printError(cst.PREFIX_MSG_MOD_ERR + chalk.bold.green(display + ' installation has FAILED (checkout previous logs)'));
|
||||
} else {
|
||||
Common.printOut(cst.PREFIX_MSG + chalk.bold.green(display + ' ENABLED'));
|
||||
}
|
||||
}
|
||||
|
||||
if(cb) cb(err);
|
||||
});
|
||||
};
|
||||
|
||||
function installLangModule(module_name, cb) {
|
||||
var node_module_path = path.resolve(path.join(__dirname, '../../../'));
|
||||
Common.printOut(cst.PREFIX_MSG_MOD + 'Calling ' + chalk.bold.red('[NPM]') + ' to install ' + module_name + ' ...');
|
||||
|
||||
var install_instance = spawn(cst.IS_WINDOWS ? 'npm.cmd' : 'npm', ['install', module_name, '--loglevel=error'], {
|
||||
stdio : 'inherit',
|
||||
env: process.env,
|
||||
shell : true,
|
||||
cwd : node_module_path
|
||||
});
|
||||
|
||||
install_instance.on('close', function(code) {
|
||||
if (code > 0)
|
||||
return cb(new Error('Module install failed'));
|
||||
return cb(null);
|
||||
});
|
||||
|
||||
install_instance.on('error', function (err) {
|
||||
console.error(err.stack || err);
|
||||
});
|
||||
};
|
||||
148
api.hyungi.net/node_modules/pm2/lib/API/Modules/Modularizer.js
generated
vendored
Normal file
148
api.hyungi.net/node_modules/pm2/lib/API/Modules/Modularizer.js
generated
vendored
Normal file
@@ -0,0 +1,148 @@
|
||||
/**
|
||||
* Copyright 2013-2022 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 path = require('path');
|
||||
var eachLimit = require('async/eachLimit');
|
||||
var forEachLimit = require('async/forEachLimit');
|
||||
|
||||
var Configuration = require('../../Configuration.js');
|
||||
var cst = require('../../../constants.js');
|
||||
var Common = require('../../Common');
|
||||
var NPM = require('./NPM.js')
|
||||
var TAR = require('./TAR.js')
|
||||
var LOCAL = require('./LOCAL.js')
|
||||
|
||||
var Modularizer = module.exports = {};
|
||||
|
||||
/**
|
||||
* PM2 Module System.
|
||||
*/
|
||||
Modularizer.install = function (CLI, module_name, opts, cb) {
|
||||
module_name = module_name.replace(/[;`|]/g, "");
|
||||
if (typeof(opts) == 'function') {
|
||||
cb = opts;
|
||||
opts = {};
|
||||
}
|
||||
|
||||
if (LOCAL.INTERNAL_MODULES.hasOwnProperty(module_name)) {
|
||||
Common.logMod(`Adding dependency ${module_name} to PM2 Runtime`);
|
||||
var currentModule = LOCAL.INTERNAL_MODULES[module_name];
|
||||
if (currentModule && currentModule.hasOwnProperty('dependencies')) {
|
||||
LOCAL.installMultipleModules(currentModule.dependencies, cb);
|
||||
} else {
|
||||
LOCAL.install(currentModule, cb);
|
||||
}
|
||||
}
|
||||
else if (module_name == '.') {
|
||||
Common.logMod(`Installing local NPM module`);
|
||||
return NPM.localStart(CLI, opts, cb)
|
||||
}
|
||||
else if (opts.tarball || /\.tar\.gz$/i.test(module_name)) {
|
||||
Common.logMod(`Installing TAR module`);
|
||||
TAR.install(CLI, module_name, opts, cb)
|
||||
}
|
||||
else {
|
||||
Common.logMod(`Installing NPM ${module_name} module`);
|
||||
NPM.install(CLI, module_name, opts, cb)
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Launch All Modules
|
||||
* Used PM2 at startup
|
||||
*/
|
||||
Modularizer.launchModules = function(CLI, cb) {
|
||||
var modules = Modularizer.listModules();
|
||||
|
||||
if (!modules) return cb();
|
||||
|
||||
// 1#
|
||||
function launchNPMModules(cb) {
|
||||
if (!modules.npm_modules) return launchTARModules(cb)
|
||||
|
||||
eachLimit(Object.keys(modules.npm_modules), 1, function(module_name, next) {
|
||||
NPM.start(CLI, modules, module_name, next)
|
||||
}, function() {
|
||||
launchTARModules(cb)
|
||||
});
|
||||
}
|
||||
|
||||
// 2#
|
||||
function launchTARModules(cb) {
|
||||
if (!modules.tar_modules) return cb()
|
||||
|
||||
eachLimit(Object.keys(modules.tar_modules), 1, function(module_name, next) {
|
||||
TAR.start(CLI, module_name, next)
|
||||
}, function() {
|
||||
return cb ? cb(null) : false;
|
||||
});
|
||||
}
|
||||
|
||||
launchNPMModules(cb)
|
||||
}
|
||||
|
||||
Modularizer.package = function(CLI, module_path, cb) {
|
||||
var fullpath = process.cwd()
|
||||
if (module_path)
|
||||
fullpath = require('path').resolve(module_path)
|
||||
TAR.package(fullpath, process.cwd(), cb)
|
||||
}
|
||||
|
||||
/**
|
||||
* Uninstall module
|
||||
*/
|
||||
Modularizer.uninstall = function(CLI, module_name, cb) {
|
||||
Common.printOut(cst.PREFIX_MSG_MOD + 'Uninstalling module ' + module_name);
|
||||
var modules_list = Modularizer.listModules();
|
||||
|
||||
if (module_name == 'all') {
|
||||
if (!modules_list) return cb();
|
||||
|
||||
return forEachLimit(Object.keys(modules_list.npm_modules), 1, function(module_name, next) {
|
||||
NPM.uninstall(CLI, module_name, next)
|
||||
}, () => {
|
||||
forEachLimit(Object.keys(modules_list.tar_modules), 1, function(module_name, next) {
|
||||
TAR.uninstall(CLI, module_name, next)
|
||||
}, cb)
|
||||
});
|
||||
}
|
||||
|
||||
if (modules_list.npm_modules[module_name]) {
|
||||
NPM.uninstall(CLI, module_name, cb)
|
||||
} else if (modules_list.tar_modules[module_name]) {
|
||||
TAR.uninstall(CLI, module_name, cb)
|
||||
}
|
||||
else {
|
||||
Common.errMod('Unknown module')
|
||||
CLI.exitCli(1)
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* List modules based on modules present in ~/.pm2/modules/ folder
|
||||
*/
|
||||
Modularizer.listModules = function() {
|
||||
return {
|
||||
npm_modules: Configuration.getSync(cst.MODULE_CONF_PREFIX) || {},
|
||||
tar_modules: Configuration.getSync(cst.MODULE_CONF_PREFIX_TAR) || {}
|
||||
}
|
||||
};
|
||||
|
||||
Modularizer.getAdditionalConf = function(app_name) {
|
||||
return NPM.getModuleConf(app_name)
|
||||
};
|
||||
|
||||
Modularizer.publish = function(PM2, folder, opts, cb) {
|
||||
if (opts.npm == true) {
|
||||
NPM.publish(opts, cb)
|
||||
}
|
||||
else {
|
||||
TAR.publish(PM2, folder, cb)
|
||||
}
|
||||
};
|
||||
|
||||
Modularizer.generateSample = function(app_name, cb) {
|
||||
NPM.generateSample(app_name, cb)
|
||||
};
|
||||
437
api.hyungi.net/node_modules/pm2/lib/API/Modules/NPM.js
generated
vendored
Normal file
437
api.hyungi.net/node_modules/pm2/lib/API/Modules/NPM.js
generated
vendored
Normal file
@@ -0,0 +1,437 @@
|
||||
const path = require('path');
|
||||
const fs = require('fs');
|
||||
const os = require('os');
|
||||
const spawn = require('child_process').spawn;
|
||||
const chalk = require('chalk');
|
||||
|
||||
const readline = require('readline')
|
||||
const which = require('../../tools/which.js')
|
||||
const sexec = require('../../tools/sexec.js')
|
||||
const copydirSync = require('../../tools/copydirSync.js')
|
||||
const deleteFolderRecursive = require('../../tools/deleteFolderRecursive.js')
|
||||
|
||||
var Configuration = require('../../Configuration.js');
|
||||
var cst = require('../../../constants.js');
|
||||
var Common = require('../../Common');
|
||||
var Utility = require('../../Utility.js');
|
||||
|
||||
module.exports = {
|
||||
install,
|
||||
uninstall,
|
||||
start,
|
||||
publish,
|
||||
generateSample,
|
||||
localStart,
|
||||
getModuleConf
|
||||
}
|
||||
|
||||
/**
|
||||
* PM2 Module System.
|
||||
* Features:
|
||||
* - Installed modules are listed separately from user applications
|
||||
* - Always ON, a module is always up along PM2, to stop it, you need to uninstall it
|
||||
* - Install a runnable module from NPM/Github/HTTP (require a package.json only)
|
||||
* - Some modules add internal PM2 depencencies (like typescript, profiling...)
|
||||
* - Internally it uses NPM install (https://docs.npmjs.com/cli/install)
|
||||
* - Auto discover script to launch (first it checks the apps field, then bin and finally main attr)
|
||||
* - Generate sample module via pm2 module:generate <module_name>
|
||||
*/
|
||||
|
||||
function localStart(PM2, opts, cb) {
|
||||
var proc_path = '',
|
||||
cmd = '',
|
||||
conf = {};
|
||||
|
||||
Common.printOut(cst.PREFIX_MSG_MOD + 'Installing local module in DEVELOPMENT MODE with WATCH auto restart');
|
||||
proc_path = process.cwd();
|
||||
|
||||
cmd = path.join(proc_path, cst.DEFAULT_MODULE_JSON);
|
||||
|
||||
Common.extend(opts, {
|
||||
cmd : cmd,
|
||||
development_mode : true,
|
||||
proc_path : proc_path
|
||||
});
|
||||
|
||||
return StartModule(PM2, opts, function(err, dt) {
|
||||
if (err) return cb(err);
|
||||
Common.printOut(cst.PREFIX_MSG_MOD + 'Module successfully installed and launched');
|
||||
return cb(null, dt);
|
||||
});
|
||||
}
|
||||
|
||||
function generateSample(app_name, cb) {
|
||||
var rl = readline.createInterface({
|
||||
input: process.stdin,
|
||||
output: process.stdout
|
||||
});
|
||||
|
||||
function samplize(module_name) {
|
||||
var cmd1 = 'git clone https://github.com/pm2-hive/sample-module.git ' + module_name + '; cd ' + module_name + '; rm -rf .git';
|
||||
var cmd2 = 'cd ' + module_name + ' ; sed -i "s:sample-module:'+ module_name +':g" package.json';
|
||||
var cmd3 = 'cd ' + module_name + ' ; npm install';
|
||||
|
||||
Common.printOut(cst.PREFIX_MSG_MOD + 'Getting sample app');
|
||||
|
||||
sexec(cmd1, function(err) {
|
||||
if (err) Common.printError(cst.PREFIX_MSG_MOD_ERR + err.message);
|
||||
sexec(cmd2, function(err) {
|
||||
console.log('');
|
||||
sexec(cmd3, function(err) {
|
||||
console.log('');
|
||||
Common.printOut(cst.PREFIX_MSG_MOD + 'Module sample created in folder: ', path.join(process.cwd(), module_name));
|
||||
console.log('');
|
||||
Common.printOut('Start module in development mode:');
|
||||
Common.printOut('$ cd ' + module_name + '/');
|
||||
Common.printOut('$ pm2 install . ');
|
||||
console.log('');
|
||||
|
||||
Common.printOut('Module Log: ');
|
||||
Common.printOut('$ pm2 logs ' + module_name);
|
||||
console.log('');
|
||||
Common.printOut('Uninstall module: ');
|
||||
Common.printOut('$ pm2 uninstall ' + module_name);
|
||||
console.log('');
|
||||
Common.printOut('Force restart: ');
|
||||
Common.printOut('$ pm2 restart ' + module_name);
|
||||
return cb ? cb() : false;
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
if (app_name) return samplize(app_name);
|
||||
|
||||
rl.question(cst.PREFIX_MSG_MOD + "Module name: ", function(module_name) {
|
||||
samplize(module_name);
|
||||
});
|
||||
}
|
||||
|
||||
function publish(opts, cb) {
|
||||
var rl = readline.createInterface({
|
||||
input: process.stdin,
|
||||
output: process.stdout
|
||||
});
|
||||
|
||||
var semver = require('semver');
|
||||
|
||||
var package_file = path.join(process.cwd(), 'package.json');
|
||||
|
||||
var package_json = require(package_file);
|
||||
|
||||
package_json.version = semver.inc(package_json.version, 'minor');
|
||||
Common.printOut(cst.PREFIX_MSG_MOD + 'Incrementing module to: %s@%s',
|
||||
package_json.name,
|
||||
package_json.version);
|
||||
|
||||
|
||||
rl.question("Write & Publish? [Y/N]", function(answer) {
|
||||
if (answer != "Y")
|
||||
return cb();
|
||||
|
||||
|
||||
fs.writeFile(package_file, JSON.stringify(package_json, null, 2), function(err, data) {
|
||||
if (err) return cb(err);
|
||||
|
||||
Common.printOut(cst.PREFIX_MSG_MOD + 'Publishing module - %s@%s',
|
||||
package_json.name,
|
||||
package_json.version);
|
||||
|
||||
sexec('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');
|
||||
sexec('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);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
function moduleExistInLocalDB(CLI, module_name, cb) {
|
||||
var modules = Configuration.getSync(cst.MODULE_CONF_PREFIX);
|
||||
if (!modules) return cb(false);
|
||||
var module_name_only = Utility.getCanonicModuleName(module_name)
|
||||
modules = Object.keys(modules);
|
||||
return cb(modules.indexOf(module_name_only) > -1 ? true : false);
|
||||
};
|
||||
|
||||
function install(CLI, module_name, opts, cb) {
|
||||
moduleExistInLocalDB(CLI, module_name, function (exists) {
|
||||
if (exists) {
|
||||
Common.logMod('Module already installed. Updating.');
|
||||
|
||||
Rollback.backup(module_name);
|
||||
|
||||
return uninstall(CLI, module_name, function () {
|
||||
return continueInstall(CLI, module_name, opts, cb);
|
||||
});
|
||||
}
|
||||
return continueInstall(CLI, module_name, opts, cb);
|
||||
})
|
||||
}
|
||||
|
||||
// Builtin Node Switch
|
||||
function getNPMCommandLine(module_name, install_path) {
|
||||
if (which('npm')) {
|
||||
return spawn.bind(this, cst.IS_WINDOWS ? 'npm.cmd' : 'npm', ['install', module_name, '--loglevel=error', '--prefix', `"${install_path}"` ], {
|
||||
stdio : 'inherit',
|
||||
env: process.env,
|
||||
windowsHide: true,
|
||||
shell : true
|
||||
})
|
||||
}
|
||||
else {
|
||||
return spawn.bind(this, cst.BUILTIN_NODE_PATH, [cst.BUILTIN_NPM_PATH, 'install', module_name, '--loglevel=error', '--prefix', `"${install_path}"`], {
|
||||
stdio : 'inherit',
|
||||
env: process.env,
|
||||
windowsHide: true,
|
||||
shell : true
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
function continueInstall(CLI, module_name, opts, cb) {
|
||||
Common.printOut(cst.PREFIX_MSG_MOD + 'Calling ' + chalk.bold.red('[NPM]') + ' to install ' + module_name + ' ...');
|
||||
|
||||
var canonic_module_name = Utility.getCanonicModuleName(module_name);
|
||||
var install_path = path.join(cst.DEFAULT_MODULE_PATH, canonic_module_name);
|
||||
|
||||
require('mkdirp')(install_path)
|
||||
.then(function() {
|
||||
process.chdir(os.homedir());
|
||||
|
||||
var install_instance = getNPMCommandLine(module_name, install_path)();
|
||||
|
||||
install_instance.on('close', finalizeInstall);
|
||||
|
||||
install_instance.on('error', function (err) {
|
||||
console.error(err.stack || err);
|
||||
});
|
||||
});
|
||||
|
||||
function finalizeInstall(code) {
|
||||
if (code != 0) {
|
||||
// If install has failed, revert to previous module version
|
||||
return Rollback.revert(CLI, module_name, function() {
|
||||
return cb(new Error('Installation failed via NPM, module has been restored to prev version'));
|
||||
});
|
||||
}
|
||||
|
||||
Common.printOut(cst.PREFIX_MSG_MOD + 'Module downloaded');
|
||||
|
||||
var proc_path = path.join(install_path, 'node_modules', canonic_module_name);
|
||||
var package_json_path = path.join(proc_path, 'package.json');
|
||||
|
||||
// Append default configuration to module configuration
|
||||
try {
|
||||
var conf = JSON.parse(fs.readFileSync(package_json_path).toString()).config;
|
||||
|
||||
if (conf) {
|
||||
Object.keys(conf).forEach(function(key) {
|
||||
Configuration.setSyncIfNotExist(canonic_module_name + ':' + key, conf[key]);
|
||||
});
|
||||
}
|
||||
} catch(e) {
|
||||
Common.printError(e);
|
||||
}
|
||||
|
||||
opts = Common.extend(opts, {
|
||||
cmd : package_json_path,
|
||||
development_mode : false,
|
||||
proc_path : proc_path
|
||||
});
|
||||
|
||||
Configuration.set(cst.MODULE_CONF_PREFIX + ':' + canonic_module_name, {
|
||||
uid : opts.uid,
|
||||
gid : opts.gid
|
||||
}, function(err, data) {
|
||||
if (err) return cb(err);
|
||||
|
||||
StartModule(CLI, opts, function(err, dt) {
|
||||
if (err) return cb(err);
|
||||
|
||||
if (process.env.PM2_PROGRAMMATIC === 'true')
|
||||
return cb(null, dt);
|
||||
|
||||
CLI.conf(canonic_module_name, function() {
|
||||
Common.printOut(cst.PREFIX_MSG_MOD + 'Module successfully installed and launched');
|
||||
Common.printOut(cst.PREFIX_MSG_MOD + 'Checkout module options: `$ pm2 conf`');
|
||||
return cb(null, dt);
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function start(PM2, modules, module_name, cb) {
|
||||
Common.printOut(cst.PREFIX_MSG_MOD + 'Starting NPM module ' + module_name);
|
||||
|
||||
var install_path = path.join(cst.DEFAULT_MODULE_PATH, module_name);
|
||||
var proc_path = path.join(install_path, 'node_modules', module_name);
|
||||
var package_json_path = path.join(proc_path, 'package.json');
|
||||
|
||||
var opts = {};
|
||||
|
||||
// Merge with embedded configuration inside module_conf (uid, gid)
|
||||
Common.extend(opts, modules[module_name]);
|
||||
|
||||
// Merge meta data to start module properly
|
||||
Common.extend(opts, {
|
||||
// package.json path
|
||||
cmd : package_json_path,
|
||||
// starting mode
|
||||
development_mode : false,
|
||||
// process cwd
|
||||
proc_path : proc_path
|
||||
});
|
||||
|
||||
StartModule(PM2, opts, function(err, dt) {
|
||||
if (err) console.error(err);
|
||||
return cb();
|
||||
})
|
||||
}
|
||||
|
||||
function uninstall(CLI, module_name, cb) {
|
||||
var module_name_only = Utility.getCanonicModuleName(module_name)
|
||||
var proc_path = path.join(cst.DEFAULT_MODULE_PATH, module_name_only);
|
||||
Configuration.unsetSync(cst.MODULE_CONF_PREFIX + ':' + module_name_only);
|
||||
|
||||
CLI.deleteModule(module_name_only, function(err, data) {
|
||||
console.log('Deleting', proc_path)
|
||||
if (module_name != '.' && proc_path.includes('modules') === true) {
|
||||
deleteFolderRecursive(proc_path)
|
||||
}
|
||||
|
||||
if (err) {
|
||||
Common.printError(err);
|
||||
return cb(err);
|
||||
}
|
||||
|
||||
return cb(null, data);
|
||||
});
|
||||
}
|
||||
|
||||
function getModuleConf(app_name) {
|
||||
if (!app_name) throw new Error('No app_name defined');
|
||||
|
||||
var module_conf = Configuration.getAllSync();
|
||||
|
||||
var additional_env = {};
|
||||
|
||||
if (!module_conf[app_name]) {
|
||||
additional_env = {};
|
||||
additional_env[app_name] = {};
|
||||
}
|
||||
else {
|
||||
additional_env = Common.clone(module_conf[app_name]);
|
||||
additional_env[app_name] = JSON.stringify(module_conf[app_name]);
|
||||
}
|
||||
return additional_env;
|
||||
}
|
||||
|
||||
function StartModule(CLI, opts, cb) {
|
||||
if (!opts.cmd && !opts.package) throw new Error('module package.json not defined');
|
||||
if (!opts.development_mode) opts.development_mode = false;
|
||||
|
||||
var package_json = require(opts.cmd || opts.package);
|
||||
|
||||
/**
|
||||
* Script file detection
|
||||
* 1- *apps* field (default pm2 json configuration)
|
||||
* 2- *bin* field
|
||||
* 3- *main* field
|
||||
*/
|
||||
if (!package_json.apps && !package_json.pm2) {
|
||||
package_json.apps = {};
|
||||
|
||||
if (package_json.bin) {
|
||||
var bin = Object.keys(package_json.bin)[0];
|
||||
package_json.apps.script = package_json.bin[bin];
|
||||
}
|
||||
else if (package_json.main) {
|
||||
package_json.apps.script = package_json.main;
|
||||
}
|
||||
}
|
||||
|
||||
Common.extend(opts, {
|
||||
cwd : opts.proc_path,
|
||||
watch : opts.development_mode,
|
||||
force_name : package_json.name,
|
||||
started_as_module : true
|
||||
});
|
||||
|
||||
// Start the module
|
||||
CLI.start(package_json, opts, function(err, data) {
|
||||
if (err) return cb(err);
|
||||
|
||||
if (opts.safe) {
|
||||
Common.printOut(cst.PREFIX_MSG_MOD + 'Monitoring module behavior for potential issue (5secs...)');
|
||||
|
||||
var time = typeof(opts.safe) == 'boolean' ? 3000 : parseInt(opts.safe);
|
||||
return setTimeout(function() {
|
||||
CLI.describe(package_json.name, function(err, apps) {
|
||||
if (err || apps[0].pm2_env.restart_time > 2) {
|
||||
return Rollback.revert(CLI, package_json.name, function() {
|
||||
return cb(new Error('New Module is instable, restored to previous version'));
|
||||
});
|
||||
}
|
||||
return cb(null, data);
|
||||
});
|
||||
}, time);
|
||||
}
|
||||
|
||||
return cb(null, data);
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
|
||||
var Rollback = {
|
||||
revert : function(CLI, module_name, cb) {
|
||||
var canonic_module_name = Utility.getCanonicModuleName(module_name);
|
||||
var backup_path = path.join(require('os').tmpdir(), canonic_module_name);
|
||||
var module_path = path.join(cst.DEFAULT_MODULE_PATH, canonic_module_name);
|
||||
|
||||
try {
|
||||
fs.statSync(backup_path)
|
||||
} catch(e) {
|
||||
return cb(new Error('no backup found'));
|
||||
}
|
||||
|
||||
Common.printOut(cst.PREFIX_MSG_MOD + chalk.bold.red('[[[[[ Module installation failure! ]]]]]'));
|
||||
Common.printOut(cst.PREFIX_MSG_MOD + chalk.bold.red('[RESTORING TO PREVIOUS VERSION]'));
|
||||
|
||||
CLI.deleteModule(canonic_module_name, function() {
|
||||
// Delete failing module
|
||||
|
||||
if (module_name.includes('modules') === true)
|
||||
deleteFolderRecursive(module_path)
|
||||
// Restore working version
|
||||
copydirSync(backup_path, path.join(cst.DEFAULT_MODULE_PATH, canonic_module_name));
|
||||
|
||||
var proc_path = path.join(module_path, 'node_modules', canonic_module_name);
|
||||
var package_json_path = path.join(proc_path, 'package.json');
|
||||
|
||||
// Start module
|
||||
StartModule(CLI, {
|
||||
cmd : package_json_path,
|
||||
development_mode : false,
|
||||
proc_path : proc_path
|
||||
}, cb);
|
||||
});
|
||||
},
|
||||
backup : function(module_name) {
|
||||
// Backup current module
|
||||
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);
|
||||
copydirSync(module_path, path.join(tmpdir, canonic_module_name));
|
||||
}
|
||||
}
|
||||
362
api.hyungi.net/node_modules/pm2/lib/API/Modules/TAR.js
generated
vendored
Normal file
362
api.hyungi.net/node_modules/pm2/lib/API/Modules/TAR.js
generated
vendored
Normal file
@@ -0,0 +1,362 @@
|
||||
|
||||
var Configuration = require('../../Configuration.js');
|
||||
var cst = require('../../../constants.js');
|
||||
var Common = require('../../Common');
|
||||
var forEachLimit = require('async/forEachLimit');
|
||||
const sexec = require('../../tools/sexec.js');
|
||||
const deleteFolderRecursive = require('../../tools/deleteFolderRecursive.js');
|
||||
|
||||
var path = require('path');
|
||||
var fs = require('fs');
|
||||
var os = require('os');
|
||||
var spawn = require('child_process').spawn;
|
||||
var exec = require('child_process').exec;
|
||||
var execSync = require('child_process').execSync;
|
||||
|
||||
module.exports = {
|
||||
install,
|
||||
uninstall,
|
||||
start,
|
||||
publish,
|
||||
packager
|
||||
}
|
||||
|
||||
/**
|
||||
* Module management to manage tarball packages
|
||||
*
|
||||
* pm2 install http.tar.gz
|
||||
* pm2 uninstall http
|
||||
*
|
||||
* - the first and only folder in the tarball must be called module (tar zcvf http module/)
|
||||
* - a package.json must be present with attribute "name", "version" and "pm2" to declare apps to run
|
||||
*/
|
||||
|
||||
function install(PM2, module_filepath, opts, cb) {
|
||||
// Remote file retrieval
|
||||
if (module_filepath.includes('http') === true) {
|
||||
var target_file = module_filepath.split('/').pop()
|
||||
var target_filepath = path.join(os.tmpdir(), target_file)
|
||||
|
||||
opts.install_url = module_filepath
|
||||
|
||||
return retrieveRemote(module_filepath, target_filepath, (err) => {
|
||||
if (err) {
|
||||
Common.errMod(err)
|
||||
process.exit(1)
|
||||
}
|
||||
installLocal(PM2, target_filepath, opts, cb)
|
||||
})
|
||||
}
|
||||
|
||||
// Local install
|
||||
installLocal(PM2, module_filepath, opts, cb)
|
||||
}
|
||||
|
||||
function retrieveRemote(url, dest, cb) {
|
||||
Common.logMod(`Retrieving remote package ${url}...`)
|
||||
|
||||
var wget = spawn('wget', [url, '-O', dest, '-q'], {
|
||||
stdio : 'inherit',
|
||||
env: process.env,
|
||||
windowsHide: true,
|
||||
shell : true
|
||||
})
|
||||
|
||||
wget.on('error', (err) => {
|
||||
console.error(err.stack || err)
|
||||
})
|
||||
|
||||
wget.on('close', (code) => {
|
||||
if (code !== 0)
|
||||
return cb(new Error('Could not download'))
|
||||
return cb(null)
|
||||
})
|
||||
}
|
||||
|
||||
function installLocal(PM2, module_filepath, opts, cb) {
|
||||
Common.logMod(`Installing package ${module_filepath}`)
|
||||
|
||||
// Get module name by unpacking the module/package.json only and read the name attribute
|
||||
getModuleName(module_filepath, function(err, module_name) {
|
||||
if (err) return cb(err)
|
||||
|
||||
Common.logMod(`Module name is ${module_name}`)
|
||||
|
||||
Common.logMod(`Depackaging module...`)
|
||||
|
||||
var install_path = path.join(cst.DEFAULT_MODULE_PATH, module_name);
|
||||
|
||||
require('mkdirp').sync(install_path)
|
||||
|
||||
var install_instance = spawn('tar', ['zxf', module_filepath, '-C', install_path, '--strip-components 1'], {
|
||||
stdio : 'inherit',
|
||||
env: process.env,
|
||||
shell : true
|
||||
})
|
||||
|
||||
install_instance.on('close', function(code) {
|
||||
Common.logMod(`Module depackaged in ${install_path}`)
|
||||
if (code == 0)
|
||||
return runInstall(PM2, install_path, module_name, opts, cb)
|
||||
return PM2.exitCli(1)
|
||||
});
|
||||
|
||||
install_instance.on('error', function (err) {
|
||||
console.error(err.stack || err);
|
||||
});
|
||||
})
|
||||
}
|
||||
|
||||
function deleteModulePath(module_name) {
|
||||
var sanitized = module_name.replace(/\./g, '')
|
||||
deleteFolderRecursive(path.join(cst.DEFAULT_MODULE_PATH, module_name));
|
||||
}
|
||||
|
||||
function runInstall(PM2, target_path, module_name, opts, cb) {
|
||||
var config_file = path.join(target_path, 'package.json')
|
||||
var conf
|
||||
|
||||
try {
|
||||
conf = require(config_file)
|
||||
module_name = conf.name
|
||||
} catch(e) {
|
||||
Common.errMod(new Error('Cannot find package.json file with name attribute at least'));
|
||||
}
|
||||
|
||||
// Force with the name in the package.json
|
||||
opts.started_as_module = true
|
||||
opts.cwd = target_path
|
||||
|
||||
if (needPrefix(conf))
|
||||
opts.name_prefix = module_name
|
||||
|
||||
if (opts.install) {
|
||||
Common.logMod(`Running YARN install...`)
|
||||
|
||||
sexec(`cd ${target_path} ; yarn install`, {silent: false}, function(code) {
|
||||
// Start apps under "apps" or "pm2" attribute
|
||||
Common.logMod(`Starting ${target_path}`)
|
||||
PM2.start(conf, opts, function(err, data) {
|
||||
if (err) return cb(err)
|
||||
|
||||
Configuration.setSync(`${cst.MODULE_CONF_PREFIX_TAR}:${module_name}`, {
|
||||
source: 'tarball',
|
||||
install_url: opts.install_url,
|
||||
installed_at: Date.now()
|
||||
})
|
||||
|
||||
Common.logMod(`Module INSTALLED and STARTED`)
|
||||
return cb(null, 'Module installed & Started')
|
||||
})
|
||||
})
|
||||
}
|
||||
else {
|
||||
PM2.start(conf, opts, function(err, data) {
|
||||
if (err) return cb(err)
|
||||
|
||||
Configuration.setSync(`${cst.MODULE_CONF_PREFIX_TAR}:${module_name}`, {
|
||||
source: 'tarball',
|
||||
install_url: opts.install_url,
|
||||
installed_at: Date.now()
|
||||
})
|
||||
|
||||
Common.logMod(`Module INSTALLED and STARTED`)
|
||||
return cb(null, 'Module installed & Started')
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
function start(PM2, module_name, cb) {
|
||||
var module_path = path.join(cst.DEFAULT_MODULE_PATH, module_name);
|
||||
Common.printOut(cst.PREFIX_MSG_MOD + 'Starting TAR module ' + module_name);
|
||||
var package_json_path = path.join(module_path, 'package.json');
|
||||
var module_conf = Configuration.getSync(`${cst.MODULE_CONF_PREFIX_TAR}:${module_name}`)
|
||||
|
||||
try {
|
||||
var conf = require(package_json_path)
|
||||
} catch(e) {
|
||||
Common.printError(`Could not find package.json as ${package_json_path}`)
|
||||
return cb()
|
||||
}
|
||||
|
||||
var opts = {};
|
||||
|
||||
opts.started_as_module = true
|
||||
opts.cwd = module_path
|
||||
|
||||
if (module_conf.install_url)
|
||||
opts.install_url = module_conf.install_url
|
||||
|
||||
if (needPrefix(conf))
|
||||
opts.name_prefix = module_name
|
||||
|
||||
PM2.start(conf, opts, function(err, data) {
|
||||
if (err) {
|
||||
Common.printError(`Could not start ${module_name} ${module_path}`)
|
||||
return cb()
|
||||
}
|
||||
|
||||
Common.printOut(`${cst.PREFIX_MSG_MOD} Module ${module_name} STARTED`)
|
||||
return cb();
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve from module package.json the name of each application
|
||||
* delete process and delete folder
|
||||
*/
|
||||
function uninstall(PM2, module_name, cb) {
|
||||
var module_path = path.join(cst.DEFAULT_MODULE_PATH, module_name);
|
||||
|
||||
Common.logMod(`Removing ${module_name} from auto startup`)
|
||||
|
||||
try {
|
||||
var pkg = require(path.join(module_path, 'package.json'))
|
||||
} catch(e) {
|
||||
Common.errMod('Could not retrieve module package.json');
|
||||
return cb(e)
|
||||
}
|
||||
|
||||
var apps = pkg.apps || pkg.pm2
|
||||
apps = [].concat(apps);
|
||||
|
||||
/**
|
||||
* Some time a module can have multiple processes
|
||||
*/
|
||||
forEachLimit(apps, 1, (app, next) => {
|
||||
var app_name
|
||||
|
||||
if (!app.name) {
|
||||
Common.renderApplicationName(app)
|
||||
}
|
||||
|
||||
if (apps.length > 1)
|
||||
app_name = `${module_name}:${app.name}`
|
||||
else if (apps.length == 1 && pkg.name != apps[0].name)
|
||||
app_name = `${module_name}:${app.name}`
|
||||
else
|
||||
app_name = app.name
|
||||
|
||||
PM2._operate('deleteProcessId', app_name, () => {
|
||||
deleteModulePath(module_name)
|
||||
next()
|
||||
})
|
||||
}, () => {
|
||||
Configuration.unsetSync(`${cst.MODULE_CONF_PREFIX_TAR}:${module_name}`)
|
||||
cb(null)
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Uncompress only module/package.json and retrieve the "name" attribute in the package.json
|
||||
*/
|
||||
function getModuleName(module_filepath, cb) {
|
||||
var tmp_folder = path.join(os.tmpdir(), cst.MODULE_BASEFOLDER)
|
||||
|
||||
var install_instance = spawn('tar', ['zxf', module_filepath, '-C', os.tmpdir(), `${cst.MODULE_BASEFOLDER}/package.json`], {
|
||||
stdio : 'inherit',
|
||||
env: process.env,
|
||||
shell : true
|
||||
})
|
||||
|
||||
install_instance.on('close', function(code) {
|
||||
try {
|
||||
var pkg = JSON.parse(fs.readFileSync(path.join(tmp_folder, `package.json`)))
|
||||
return cb(null, pkg.name)
|
||||
} catch(e) {
|
||||
return cb(e)
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function packager(module_path, target_path, cb) {
|
||||
var base_folder = path.dirname(module_path)
|
||||
var module_folder_name = path.basename(module_path)
|
||||
var pkg = require(path.join(module_path, 'package.json'))
|
||||
var pkg_name = `${module_folder_name}-v${pkg.version.replace(/\./g, '-')}.tar.gz`
|
||||
var target_fullpath = path.join(target_path, pkg_name)
|
||||
|
||||
var cmd = `tar zcf ${target_fullpath} -C ${base_folder} --transform 's,${module_folder_name},module,' ${module_folder_name}`
|
||||
|
||||
Common.logMod(`Gziping ${module_path} to ${target_fullpath}`)
|
||||
|
||||
var tar = exec(cmd, (err, sto, ste) => {
|
||||
if (err) {
|
||||
console.log(sto.toString().trim())
|
||||
console.log(ste.toString().trim())
|
||||
}
|
||||
})
|
||||
|
||||
tar.on('close', function (code) {
|
||||
cb(code == 0 ? null : code, {
|
||||
package_name: pkg_name,
|
||||
path: target_fullpath
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
function publish(PM2, folder, cb) {
|
||||
var target_folder = folder ? path.resolve(folder) : process.cwd()
|
||||
|
||||
try {
|
||||
var pkg = JSON.parse(fs.readFileSync(path.join(target_folder, 'package.json')).toString())
|
||||
} catch(e) {
|
||||
Common.errMod(`${process.cwd()} module does not contain any package.json`)
|
||||
process.exit(1)
|
||||
}
|
||||
|
||||
if (!pkg.name) throw new Error('Attribute name should be present')
|
||||
if (!pkg.version) throw new Error('Attribute version should be present')
|
||||
if (!pkg.pm2 && !pkg.apps) throw new Error('Attribute apps should be present')
|
||||
|
||||
var current_path = target_folder
|
||||
var module_name = path.basename(current_path)
|
||||
var target_path = os.tmpdir()
|
||||
|
||||
Common.logMod(`Starting publishing procedure for ${module_name}@${pkg.version}`)
|
||||
|
||||
packager(current_path, target_path, (err, res) => {
|
||||
if (err) {
|
||||
Common.errMod('Can\'t package, exiting')
|
||||
process.exit(1)
|
||||
}
|
||||
|
||||
Common.logMod(`Package [${pkg.name}] created in path ${res.path}`)
|
||||
|
||||
var data = {
|
||||
module_data: {
|
||||
file: res.path,
|
||||
content_type: 'content/gzip'
|
||||
},
|
||||
id: pkg.name,
|
||||
name: pkg.name,
|
||||
version: pkg.version
|
||||
};
|
||||
|
||||
var uri = `${PM2.pm2_configuration.registry}/api/v1/modules`
|
||||
Common.logMod(`Sending Package to remote ${pkg.name} ${uri}`)
|
||||
|
||||
require('needle')
|
||||
.post(uri, data, { multipart: true }, function(err, res, body) {
|
||||
if (err) {
|
||||
Common.errMod(err)
|
||||
process.exit(1)
|
||||
}
|
||||
if (res.statusCode !== 200) {
|
||||
Common.errMod(`${pkg.name}-${pkg.version}: ${res.body.msg}`)
|
||||
process.exit(1)
|
||||
}
|
||||
Common.logMod(`Module ${module_name} published under version ${pkg.version}`)
|
||||
process.exit(0)
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
function needPrefix(conf) {
|
||||
if ((conf.apps && conf.apps.length > 1) ||
|
||||
(conf.pm2 && conf.pm2.length > 1) ||
|
||||
(conf.apps.length == 1 && conf.name != conf.apps[0].name))
|
||||
return true
|
||||
return false
|
||||
}
|
||||
46
api.hyungi.net/node_modules/pm2/lib/API/Modules/flagExt.js
generated
vendored
Normal file
46
api.hyungi.net/node_modules/pm2/lib/API/Modules/flagExt.js
generated
vendored
Normal file
@@ -0,0 +1,46 @@
|
||||
var fs = require('fs');
|
||||
var conf = require('../../../constants.js');
|
||||
|
||||
function find_extensions(folder, ext, ret)
|
||||
{
|
||||
try {
|
||||
fs.accessSync(folder, fs.constants.R_OK);
|
||||
} catch (err) {
|
||||
return;
|
||||
}
|
||||
if(fs.statSync(folder).isDirectory() && folder.indexOf('node_modules') == -1 && (fs.statSync(folder)["mode"] & 4))
|
||||
{
|
||||
fs.readdirSync(folder).forEach(file => {
|
||||
var tmp;
|
||||
if(Number.parseInt(folder.lastIndexOf('/') + 1) === folder.length)
|
||||
tmp = folder + file;
|
||||
else
|
||||
tmp = folder + '/' + file;
|
||||
if(fs.statSync(tmp).isDirectory())
|
||||
find_extensions(tmp, ext, ret);
|
||||
else
|
||||
{
|
||||
var p = true;
|
||||
for(var i = 0; i < ext.length;i++)
|
||||
if(ext[i].test(file))
|
||||
p = false;
|
||||
if(p)
|
||||
ret.push(folder + '/' + file);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
module.exports.make_available_extension = function make_available_extension(opts, ret)
|
||||
{
|
||||
if(typeof opts == 'object' && typeof ret == 'object')
|
||||
{
|
||||
var mas = opts.ext.split(',');
|
||||
for(var i = 0;i < mas.length;i++)
|
||||
mas[i] = '.' + mas[i];
|
||||
var res = [];
|
||||
for(var i = 0;i < mas.length;i++)
|
||||
res[i] = new RegExp(mas[i] + '$');
|
||||
find_extensions(process.cwd(), res, ret);
|
||||
}
|
||||
}
|
||||
120
api.hyungi.net/node_modules/pm2/lib/API/Modules/index.js
generated
vendored
Normal file
120
api.hyungi.net/node_modules/pm2/lib/API/Modules/index.js
generated
vendored
Normal file
@@ -0,0 +1,120 @@
|
||||
|
||||
/***************************
|
||||
*
|
||||
* Module methods
|
||||
*
|
||||
**************************/
|
||||
|
||||
var cst = require('../../../constants.js');
|
||||
var Common = require('../../Common.js');
|
||||
var chalk = require('chalk');
|
||||
var forEachLimit = require('async/forEachLimit');
|
||||
|
||||
var Modularizer = require('./Modularizer.js');
|
||||
|
||||
module.exports = function(CLI) {
|
||||
/**
|
||||
* Install / Update a module
|
||||
*/
|
||||
CLI.prototype.install = function(module_name, opts, cb) {
|
||||
var that = this;
|
||||
|
||||
if (typeof(opts) == 'function') {
|
||||
cb = opts;
|
||||
opts = {};
|
||||
}
|
||||
|
||||
Modularizer.install(this, module_name, opts, function(err, data) {
|
||||
if (err) {
|
||||
Common.printError(cst.PREFIX_MSG_ERR + (err.message || err));
|
||||
return cb ? cb(Common.retErr(err)) : that.speedList(cst.ERROR_EXIT);
|
||||
}
|
||||
return cb ? cb(null, data) : that.speedList(cst.SUCCESS_EXIT);
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Uninstall a module
|
||||
*/
|
||||
CLI.prototype.uninstall = function(module_name, cb) {
|
||||
var that = this;
|
||||
|
||||
Modularizer.uninstall(this, module_name, function(err, data) {
|
||||
if (err)
|
||||
return cb ? cb(Common.retErr(err)) : that.speedList(cst.ERROR_EXIT);
|
||||
return cb ? cb(null, data) : that.speedList(cst.SUCCESS_EXIT);
|
||||
});
|
||||
};
|
||||
|
||||
CLI.prototype.launchAll = function(CLI, cb) {
|
||||
Modularizer.launchModules(CLI, cb);
|
||||
};
|
||||
|
||||
CLI.prototype.package = function(module_path, cb) {
|
||||
Modularizer.package(this, module_path, (err, res) => {
|
||||
if (err) {
|
||||
Common.errMod(err)
|
||||
return cb ? cb(err) : this.exitCli(1)
|
||||
}
|
||||
Common.logMod(`Module packaged in ${res.path}`)
|
||||
return cb ? cb(err) : this.exitCli(0)
|
||||
})
|
||||
};
|
||||
|
||||
/**
|
||||
* Publish module on NPM + Git push
|
||||
*/
|
||||
CLI.prototype.publish = function(folder, opts, cb) {
|
||||
var that = this;
|
||||
|
||||
Modularizer.publish(this, folder, opts, function(err, data) {
|
||||
if (err)
|
||||
return cb ? cb(Common.retErr(err)) : that.speedList(cst.ERROR_EXIT);
|
||||
return cb ? cb(null, data) : that.speedList(cst.SUCCESS_EXIT);
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Publish module on NPM + Git push
|
||||
*/
|
||||
CLI.prototype.generateModuleSample = function(app_name, cb) {
|
||||
var that = this;
|
||||
|
||||
Modularizer.generateSample(app_name, function(err, data) {
|
||||
if (err)
|
||||
return cb ? cb(Common.retErr(err)) : that.exitCli(cst.ERROR_EXIT);
|
||||
return cb ? cb(null, data) : that.exitCli(cst.SUCCESS_EXIT);
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Special delete method
|
||||
*/
|
||||
CLI.prototype.deleteModule = function(module_name, cb) {
|
||||
var that = this;
|
||||
|
||||
var found_proc = [];
|
||||
|
||||
this.Client.getAllProcess(function(err, procs) {
|
||||
if (err) {
|
||||
Common.printError('Error retrieving process list: ' + err);
|
||||
return cb(Common.retErr(err));
|
||||
}
|
||||
|
||||
procs.forEach(function(proc) {
|
||||
if (proc.pm2_env.name == module_name && proc.pm2_env.pmx_module) {
|
||||
found_proc.push(proc.pm_id);
|
||||
}
|
||||
});
|
||||
|
||||
if (found_proc.length == 0)
|
||||
return cb();
|
||||
|
||||
that._operate('deleteProcessId', found_proc[0], function(err) {
|
||||
if (err) return cb(Common.retErr(err));
|
||||
Common.printOut('In memory process deleted');
|
||||
return cb();
|
||||
});
|
||||
});
|
||||
};
|
||||
};
|
||||
247
api.hyungi.net/node_modules/pm2/lib/API/Monit.js
generated
vendored
Normal file
247
api.hyungi.net/node_modules/pm2/lib/API/Monit.js
generated
vendored
Normal file
@@ -0,0 +1,247 @@
|
||||
/**
|
||||
* Copyright 2013-2022 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.
|
||||
*/
|
||||
// pm2-htop
|
||||
// Library who interacts with PM2 to display processes resources in htop way
|
||||
// by Strzelewicz Alexandre
|
||||
|
||||
var multimeter = require('pm2-multimeter');
|
||||
var os = require('os');
|
||||
var p = require('path');
|
||||
var chalk = require('chalk');
|
||||
|
||||
var UX = require('./UX');
|
||||
|
||||
var debug = require('debug')('pm2:monit');
|
||||
|
||||
// Cst for light programs
|
||||
const RATIO_T1 = Math.floor(os.totalmem() / 500);
|
||||
// Cst for medium programs
|
||||
const RATIO_T2 = Math.floor(os.totalmem() / 50);
|
||||
// Cst for heavy programs
|
||||
const RATIO_T3 = Math.floor(os.totalmem() / 5);
|
||||
// Cst for heavy programs
|
||||
const RATIO_T4 = Math.floor(os.totalmem());
|
||||
|
||||
var Monit = {};
|
||||
|
||||
//helper to get bars.length (num bars printed)
|
||||
Object.size = function(obj) {
|
||||
var size = 0, key;
|
||||
for (key in obj) {
|
||||
if (obj.hasOwnProperty(key)) size++;
|
||||
}
|
||||
return size;
|
||||
};
|
||||
|
||||
/**
|
||||
* Reset the monitor through charm, basically \033c
|
||||
* @param String msg optional message to show
|
||||
* @return Monit
|
||||
*/
|
||||
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.pm2.io) \x1B[39m\n\n');
|
||||
|
||||
if(msg) {
|
||||
this.multi.write(msg);
|
||||
}
|
||||
|
||||
this.bars = {};
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Synchronous Monitor init method
|
||||
* @method init
|
||||
* @return Monit
|
||||
*/
|
||||
Monit.init = function() {
|
||||
|
||||
this.multi = multimeter(process);
|
||||
|
||||
this.multi.on('^C', this.stop);
|
||||
|
||||
this.reset();
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Stops monitor
|
||||
* @method stop
|
||||
*/
|
||||
Monit.stop = function() {
|
||||
this.multi.charm.destroy();
|
||||
process.exit(0);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Refresh monitor
|
||||
* @method refresh
|
||||
* @param {} processes
|
||||
* @return this
|
||||
*/
|
||||
Monit.refresh = function(processes) {
|
||||
debug('Monit refresh');
|
||||
|
||||
if(!processes) {
|
||||
processes = [];
|
||||
}
|
||||
|
||||
var num = processes.length;
|
||||
this.num_bars = Object.size(this.bars);
|
||||
|
||||
if(num !== this.num_bars) {
|
||||
debug('Monit addProcesses - actual: %s, new: %s', this.num_bars, num);
|
||||
return this.addProcesses(processes);
|
||||
} else {
|
||||
|
||||
if(num === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
debug('Monit refresh');
|
||||
var proc;
|
||||
|
||||
for(var i = 0; i < num; i++) {
|
||||
proc = processes[i];
|
||||
|
||||
//this is to avoid a print issue when the process is restarted for example
|
||||
//we might also check for the pid but restarted|restarting will be rendered bad
|
||||
if(this.bars[proc.pm_id] && proc.pm2_env.status !== this.bars[proc.pm_id].status) {
|
||||
debug('bars for %s does not exist', proc.pm_id);
|
||||
this.addProcesses(processes);
|
||||
break;
|
||||
}
|
||||
|
||||
this.updateBars(proc);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
Monit.addProcess = function(proc, i) {
|
||||
if(proc.pm_id in this.bars) {
|
||||
return ;
|
||||
}
|
||||
|
||||
if (proc.monit.error)
|
||||
throw new Error(JSON.stringify(proc.monit.error));
|
||||
|
||||
var process_name = proc.pm2_env.name || p.basename(proc.pm2_env.pm_exec_path);
|
||||
var status = proc.pm2_env.status == 'online' ? chalk.green.bold('●') : chalk.red.bold('●');
|
||||
|
||||
this.multi.write(' ' + status + ' ' + chalk.green.bold(process_name));
|
||||
this.multi.write('\n');
|
||||
this.multi.write('[' + proc.pm2_env.pm_id + '] [' + proc.pm2_env.exec_mode + ']\n');
|
||||
|
||||
var bar_cpu = this.multi(40, (i * 2) + 3 + i, {
|
||||
width: 30,
|
||||
solid: {
|
||||
text: '|',
|
||||
foreground: 'white',
|
||||
background: 'blue'
|
||||
},
|
||||
empty: {
|
||||
text: ' '
|
||||
}
|
||||
});
|
||||
|
||||
var bar_memory = this.multi(40, (i * 2) + 4 + i, {
|
||||
width: 30,
|
||||
solid: {
|
||||
text: '|',
|
||||
foreground: 'white',
|
||||
background: 'red'
|
||||
},
|
||||
empty: {
|
||||
text: ' '
|
||||
}
|
||||
});
|
||||
|
||||
this.bars[proc.pm_id] = {
|
||||
memory: bar_memory,
|
||||
cpu: bar_cpu,
|
||||
status: proc.pm2_env.status
|
||||
};
|
||||
|
||||
this.updateBars(proc);
|
||||
|
||||
this.multi.write('\n');
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
Monit.addProcesses = function(processes) {
|
||||
|
||||
if(!processes) {
|
||||
processes = [];
|
||||
}
|
||||
|
||||
this.reset();
|
||||
|
||||
var num = processes.length;
|
||||
|
||||
if(num > 0) {
|
||||
for(var i = 0; i < num; i++) {
|
||||
this.addProcess(processes[i], i);
|
||||
}
|
||||
} else {
|
||||
this.reset('No processes to monit');
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Draw memory bars
|
||||
/**
|
||||
* Description
|
||||
* @method drawRatio
|
||||
* @param {} bar_memory
|
||||
* @param {} memory
|
||||
* @return
|
||||
*/
|
||||
Monit.drawRatio = function(bar_memory, memory) {
|
||||
var scale = 0;
|
||||
|
||||
if (memory < RATIO_T1) scale = RATIO_T1;
|
||||
else if (memory < RATIO_T2) scale = RATIO_T2;
|
||||
else if (memory < RATIO_T3) scale = RATIO_T3;
|
||||
else scale = RATIO_T4;
|
||||
|
||||
bar_memory.ratio(memory,
|
||||
scale,
|
||||
UX.helpers.bytesToSize(memory, 3));
|
||||
};
|
||||
|
||||
/**
|
||||
* Updates bars informations
|
||||
* @param {} proc proc object
|
||||
* @return this
|
||||
*/
|
||||
Monit.updateBars = function(proc) {
|
||||
if (this.bars[proc.pm_id]) {
|
||||
if (proc.pm2_env.status !== 'online' || proc.pm2_env.status !== this.bars[proc.pm_id].status) {
|
||||
this.bars[proc.pm_id].cpu.percent(0, chalk.red(proc.pm2_env.status));
|
||||
this.drawRatio(this.bars[proc.pm_id].memory, 0, chalk.red(proc.pm2_env.status));
|
||||
} else if (!proc.monit) {
|
||||
this.bars[proc.pm_id].cpu.percent(0, chalk.red('No data'));
|
||||
this.drawRatio(this.bars[proc.pm_id].memory, 0, chalk.red('No data'));
|
||||
} else {
|
||||
this.bars[proc.pm_id].cpu.percent(proc.monit.cpu);
|
||||
this.drawRatio(this.bars[proc.pm_id].memory, proc.monit.memory);
|
||||
}
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
module.exports = Monit;
|
||||
342
api.hyungi.net/node_modules/pm2/lib/API/Serve.js
generated
vendored
Normal file
342
api.hyungi.net/node_modules/pm2/lib/API/Serve.js
generated
vendored
Normal file
@@ -0,0 +1,342 @@
|
||||
/**
|
||||
* Copyright 2013-2022 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 fs = require('fs');
|
||||
var http = require('http');
|
||||
var url = require('url');
|
||||
var path = require('path');
|
||||
var debug = require('debug')('pm2:serve');
|
||||
|
||||
var probe = require('@pm2/io');
|
||||
var errorMeter = probe.meter({
|
||||
name : '404/sec',
|
||||
samples : 1,
|
||||
timeframe : 60
|
||||
})
|
||||
/**
|
||||
* list of supported content types.
|
||||
*/
|
||||
var contentTypes = {
|
||||
'3gp': 'video/3gpp',
|
||||
'a': 'application/octet-stream',
|
||||
'ai': 'application/postscript',
|
||||
'aif': 'audio/x-aiff',
|
||||
'aiff': 'audio/x-aiff',
|
||||
'asc': 'application/pgp-signature',
|
||||
'asf': 'video/x-ms-asf',
|
||||
'asm': 'text/x-asm',
|
||||
'asx': 'video/x-ms-asf',
|
||||
'atom': 'application/atom+xml',
|
||||
'au': 'audio/basic',
|
||||
'avi': 'video/x-msvideo',
|
||||
'bat': 'application/x-msdownload',
|
||||
'bin': 'application/octet-stream',
|
||||
'bmp': 'image/bmp',
|
||||
'bz2': 'application/x-bzip2',
|
||||
'c': 'text/x-c',
|
||||
'cab': 'application/vnd.ms-cab-compressed',
|
||||
'cc': 'text/x-c',
|
||||
'chm': 'application/vnd.ms-htmlhelp',
|
||||
'class': 'application/octet-stream',
|
||||
'com': 'application/x-msdownload',
|
||||
'conf': 'text/plain',
|
||||
'cpp': 'text/x-c',
|
||||
'crt': 'application/x-x509-ca-cert',
|
||||
'css': 'text/css',
|
||||
'csv': 'text/csv',
|
||||
'cxx': 'text/x-c',
|
||||
'deb': 'application/x-debian-package',
|
||||
'der': 'application/x-x509-ca-cert',
|
||||
'diff': 'text/x-diff',
|
||||
'djv': 'image/vnd.djvu',
|
||||
'djvu': 'image/vnd.djvu',
|
||||
'dll': 'application/x-msdownload',
|
||||
'dmg': 'application/octet-stream',
|
||||
'doc': 'application/msword',
|
||||
'dot': 'application/msword',
|
||||
'dtd': 'application/xml-dtd',
|
||||
'dvi': 'application/x-dvi',
|
||||
'ear': 'application/java-archive',
|
||||
'eml': 'message/rfc822',
|
||||
'eps': 'application/postscript',
|
||||
'exe': 'application/x-msdownload',
|
||||
'f': 'text/x-fortran',
|
||||
'f77': 'text/x-fortran',
|
||||
'f90': 'text/x-fortran',
|
||||
'flv': 'video/x-flv',
|
||||
'for': 'text/x-fortran',
|
||||
'gem': 'application/octet-stream',
|
||||
'gemspec': 'text/x-script.ruby',
|
||||
'gif': 'image/gif',
|
||||
'gz': 'application/x-gzip',
|
||||
'h': 'text/x-c',
|
||||
'hh': 'text/x-c',
|
||||
'htm': 'text/html',
|
||||
'html': 'text/html',
|
||||
'ico': 'image/vnd.microsoft.icon',
|
||||
'ics': 'text/calendar',
|
||||
'ifb': 'text/calendar',
|
||||
'iso': 'application/octet-stream',
|
||||
'jar': 'application/java-archive',
|
||||
'java': 'text/x-java-source',
|
||||
'jnlp': 'application/x-java-jnlp-file',
|
||||
'jpeg': 'image/jpeg',
|
||||
'jpg': 'image/jpeg',
|
||||
'js': 'application/javascript',
|
||||
'json': 'application/json',
|
||||
'log': 'text/plain',
|
||||
'm3u': 'audio/x-mpegurl',
|
||||
'm4v': 'video/mp4',
|
||||
'man': 'text/troff',
|
||||
'mathml': 'application/mathml+xml',
|
||||
'mbox': 'application/mbox',
|
||||
'mdoc': 'text/troff',
|
||||
'me': 'text/troff',
|
||||
'mid': 'audio/midi',
|
||||
'midi': 'audio/midi',
|
||||
'mime': 'message/rfc822',
|
||||
'mml': 'application/mathml+xml',
|
||||
'mng': 'video/x-mng',
|
||||
'mov': 'video/quicktime',
|
||||
'mp3': 'audio/mpeg',
|
||||
'mp4': 'video/mp4',
|
||||
'mp4v': 'video/mp4',
|
||||
'mpeg': 'video/mpeg',
|
||||
'mpg': 'video/mpeg',
|
||||
'ms': 'text/troff',
|
||||
'msi': 'application/x-msdownload',
|
||||
'odp': 'application/vnd.oasis.opendocument.presentation',
|
||||
'ods': 'application/vnd.oasis.opendocument.spreadsheet',
|
||||
'odt': 'application/vnd.oasis.opendocument.text',
|
||||
'ogg': 'application/ogg',
|
||||
'p': 'text/x-pascal',
|
||||
'pas': 'text/x-pascal',
|
||||
'pbm': 'image/x-portable-bitmap',
|
||||
'pdf': 'application/pdf',
|
||||
'pem': 'application/x-x509-ca-cert',
|
||||
'pgm': 'image/x-portable-graymap',
|
||||
'pgp': 'application/pgp-encrypted',
|
||||
'pkg': 'application/octet-stream',
|
||||
'pl': 'text/x-script.perl',
|
||||
'pm': 'text/x-script.perl-module',
|
||||
'png': 'image/png',
|
||||
'pnm': 'image/x-portable-anymap',
|
||||
'ppm': 'image/x-portable-pixmap',
|
||||
'pps': 'application/vnd.ms-powerpoint',
|
||||
'ppt': 'application/vnd.ms-powerpoint',
|
||||
'ps': 'application/postscript',
|
||||
'psd': 'image/vnd.adobe.photoshop',
|
||||
'py': 'text/x-script.python',
|
||||
'qt': 'video/quicktime',
|
||||
'ra': 'audio/x-pn-realaudio',
|
||||
'rake': 'text/x-script.ruby',
|
||||
'ram': 'audio/x-pn-realaudio',
|
||||
'rar': 'application/x-rar-compressed',
|
||||
'rb': 'text/x-script.ruby',
|
||||
'rdf': 'application/rdf+xml',
|
||||
'roff': 'text/troff',
|
||||
'rpm': 'application/x-redhat-package-manager',
|
||||
'rss': 'application/rss+xml',
|
||||
'rtf': 'application/rtf',
|
||||
'ru': 'text/x-script.ruby',
|
||||
's': 'text/x-asm',
|
||||
'sgm': 'text/sgml',
|
||||
'sgml': 'text/sgml',
|
||||
'sh': 'application/x-sh',
|
||||
'sig': 'application/pgp-signature',
|
||||
'snd': 'audio/basic',
|
||||
'so': 'application/octet-stream',
|
||||
'svg': 'image/svg+xml',
|
||||
'svgz': 'image/svg+xml',
|
||||
'swf': 'application/x-shockwave-flash',
|
||||
't': 'text/troff',
|
||||
'tar': 'application/x-tar',
|
||||
'tbz': 'application/x-bzip-compressed-tar',
|
||||
'tcl': 'application/x-tcl',
|
||||
'tex': 'application/x-tex',
|
||||
'texi': 'application/x-texinfo',
|
||||
'texinfo': 'application/x-texinfo',
|
||||
'text': 'text/plain',
|
||||
'tif': 'image/tiff',
|
||||
'tiff': 'image/tiff',
|
||||
'torrent': 'application/x-bittorrent',
|
||||
'tr': 'text/troff',
|
||||
'txt': 'text/plain',
|
||||
'vcf': 'text/x-vcard',
|
||||
'vcs': 'text/x-vcalendar',
|
||||
'vrml': 'model/vrml',
|
||||
'war': 'application/java-archive',
|
||||
'wav': 'audio/x-wav',
|
||||
'wma': 'audio/x-ms-wma',
|
||||
'wmv': 'video/x-ms-wmv',
|
||||
'wmx': 'video/x-ms-wmx',
|
||||
'wrl': 'model/vrml',
|
||||
'wsdl': 'application/wsdl+xml',
|
||||
'xbm': 'image/x-xbitmap',
|
||||
'xhtml': 'application/xhtml+xml',
|
||||
'xls': 'application/vnd.ms-excel',
|
||||
'xml': 'application/xml',
|
||||
'xpm': 'image/x-xpixmap',
|
||||
'xsl': 'application/xml',
|
||||
'xslt': 'application/xslt+xml',
|
||||
'yaml': 'text/yaml',
|
||||
'yml': 'text/yaml',
|
||||
'zip': 'application/zip',
|
||||
'woff': 'application/font-woff',
|
||||
'woff2': 'application/font-woff',
|
||||
'otf': 'application/font-sfnt',
|
||||
'otc': 'application/font-sfnt',
|
||||
'ttf': 'application/font-sfnt'
|
||||
};
|
||||
|
||||
var options = {
|
||||
port: process.env.PM2_SERVE_PORT || process.argv[3] || 8080,
|
||||
host: process.env.PM2_SERVE_HOST || process.argv[4] || '0.0.0.0',
|
||||
path: path.resolve(process.env.PM2_SERVE_PATH || process.argv[2] || '.'),
|
||||
spa: process.env.PM2_SERVE_SPA === 'true',
|
||||
homepage: process.env.PM2_SERVE_HOMEPAGE || '/index.html',
|
||||
basic_auth: process.env.PM2_SERVE_BASIC_AUTH === 'true' ? {
|
||||
username: process.env.PM2_SERVE_BASIC_AUTH_USERNAME,
|
||||
password: process.env.PM2_SERVE_BASIC_AUTH_PASSWORD
|
||||
} : null,
|
||||
monitor: process.env.PM2_SERVE_MONITOR
|
||||
};
|
||||
|
||||
if (typeof options.port === 'string') {
|
||||
options.port = parseInt(options.port) || 8080
|
||||
}
|
||||
|
||||
if (typeof options.monitor === 'string' && options.monitor !== '') {
|
||||
try {
|
||||
let fileContent = fs.readFileSync(path.join(process.env.PM2_HOME, 'agent.json5')).toString()
|
||||
// Handle old configuration with json5
|
||||
fileContent = fileContent.replace(/\s(\w+):/g, '"$1":')
|
||||
// parse
|
||||
let conf = JSON.parse(fileContent)
|
||||
options.monitorBucket = conf.public_key
|
||||
} catch (e) {
|
||||
console.log('Interaction file does not exist')
|
||||
}
|
||||
}
|
||||
|
||||
// start an HTTP server
|
||||
http.createServer(function (request, response) {
|
||||
if (options.basic_auth) {
|
||||
if (!request.headers.authorization || request.headers.authorization.indexOf('Basic ') === -1) {
|
||||
return sendBasicAuthResponse(response)
|
||||
}
|
||||
|
||||
var user = parseBasicAuth(request.headers.authorization)
|
||||
if (user.username !== options.basic_auth.username || user.password !== options.basic_auth.password) {
|
||||
return sendBasicAuthResponse(response)
|
||||
}
|
||||
}
|
||||
|
||||
serveFile(request.url, request, response);
|
||||
|
||||
}).listen(options.port, options.host, function (err) {
|
||||
if (err) {
|
||||
console.error(err);
|
||||
process.exit(1);
|
||||
}
|
||||
console.log('Exposing %s directory on %s:%d', options.path, options.host, options.port);
|
||||
});
|
||||
|
||||
function serveFile(uri, request, response) {
|
||||
var file = decodeURIComponent(url.parse(uri || request.url).pathname);
|
||||
|
||||
if (file === '/' || file === '') {
|
||||
file = options.homepage;
|
||||
request.wantHomepage = true;
|
||||
}
|
||||
var filePath = path.resolve(options.path + file);
|
||||
|
||||
// since we call filesystem directly so we need to verify that the
|
||||
// url doesn't go outside the serve path
|
||||
if (filePath.indexOf(options.path) !== 0) {
|
||||
response.writeHead(403, { 'Content-Type': 'text/html' });
|
||||
return response.end('403 Forbidden');
|
||||
}
|
||||
|
||||
var contentType = contentTypes[filePath.split('.').pop().toLowerCase()] || 'text/plain';
|
||||
|
||||
fs.readFile(filePath, function (error, content) {
|
||||
if (error) {
|
||||
if ((!options.spa || file === options.homepage)) {
|
||||
console.error('[%s] Error while serving %s with content-type %s : %s',
|
||||
new Date(), filePath, contentType, error.message || error);
|
||||
}
|
||||
errorMeter.mark();
|
||||
if (error.code === 'ENOENT') {
|
||||
if (options.spa && !request.wantHomepage) {
|
||||
request.wantHomepage = true;
|
||||
return serveFile(`/${path.basename(file)}`, request, response);
|
||||
} else if (options.spa && file !== options.homepage) {
|
||||
return serveFile(options.homepage, request, response);
|
||||
}
|
||||
fs.readFile(options.path + '/404.html', function (err, content) {
|
||||
content = err ? '404 Not Found' : content;
|
||||
response.writeHead(404, { 'Content-Type': 'text/html' });
|
||||
return response.end(content, 'utf-8');
|
||||
});
|
||||
return;
|
||||
}
|
||||
response.writeHead(500);
|
||||
return response.end('Sorry, check with the site admin for error: ' + error.code + ' ..\n');
|
||||
}
|
||||
|
||||
// Add CORS headers to allow browsers to fetch data directly
|
||||
response.writeHead(200, {
|
||||
'Content-Type': contentType,
|
||||
'Access-Control-Allow-Origin': '*',
|
||||
'Access-Control-Allow-Methods': 'GET'
|
||||
});
|
||||
if (options.monitorBucket && contentType === 'text/html') {
|
||||
content = content.toString().replace('</body>', `
|
||||
<script>
|
||||
;(function (b,e,n,o,i,t) {
|
||||
b[o]=b[o]||function(f){(b[o].c=b[o].c||[]).push(f)};
|
||||
t=e.createElement(i);e=e.getElementsByTagName(i)[0];
|
||||
t.async=1;t.src=n;e.parentNode.insertBefore(t,e);
|
||||
}(window,document,'https://apm.pm2.io/pm2-io-apm-browser.v1.js','pm2Ready','script'))
|
||||
|
||||
pm2Ready(function(apm) {
|
||||
apm.setBucket('${options.monitorBucket}')
|
||||
apm.setApplication('${options.monitor}')
|
||||
apm.reportTimings()
|
||||
apm.reportIssues()
|
||||
})
|
||||
</script>
|
||||
</body>
|
||||
`);
|
||||
}
|
||||
response.end(content, 'utf-8');
|
||||
debug('[%s] Serving %s with content-type %s', Date.now(), filePath, contentType);
|
||||
});
|
||||
}
|
||||
|
||||
function parseBasicAuth(auth) {
|
||||
// auth is like `Basic Y2hhcmxlczoxMjM0NQ==`
|
||||
var tmp = auth.split(' ');
|
||||
|
||||
var buf = Buffer.from(tmp[1], 'base64');
|
||||
var plain = buf.toString();
|
||||
|
||||
var creds = plain.split(':');
|
||||
return {
|
||||
username: creds[0],
|
||||
password: creds[1]
|
||||
}
|
||||
}
|
||||
|
||||
function sendBasicAuthResponse(response) {
|
||||
response.writeHead(401, {
|
||||
'Content-Type': 'text/html',
|
||||
'WWW-Authenticate': 'Basic realm="Authentication service"'
|
||||
});
|
||||
return response.end('401 Unauthorized');
|
||||
}
|
||||
616
api.hyungi.net/node_modules/pm2/lib/API/Startup.js
generated
vendored
Normal file
616
api.hyungi.net/node_modules/pm2/lib/API/Startup.js
generated
vendored
Normal file
@@ -0,0 +1,616 @@
|
||||
/**
|
||||
* Copyright 2013-2022 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 chalk = require('chalk');
|
||||
var path = require('path');
|
||||
var fs = require('fs');
|
||||
var forEachLimit = require('async/forEachLimit');
|
||||
var eachLimit = require('async/eachLimit');
|
||||
var Common = require('../Common.js');
|
||||
var cst = require('../../constants.js');
|
||||
var util = require('util');
|
||||
var tmpPath = require('os').tmpdir;
|
||||
var which = require('../tools/which.js');
|
||||
var sexec = require('../tools/sexec')
|
||||
module.exports = function(CLI) {
|
||||
/**
|
||||
* If command is launched without root right
|
||||
* Display helper
|
||||
*/
|
||||
function isNotRoot(startup_mode, platform, opts, cb) {
|
||||
Common.printOut(`${cst.PREFIX_MSG}To ${startup_mode} the Startup Script, copy/paste the following command:`);
|
||||
if (opts.user) {
|
||||
console.log('sudo env PATH=$PATH:' + path.dirname(process.execPath) + ' pm2 ' + opts.args[1].name() + ' ' + platform + ' -u ' + opts.user + ' --hp ' + process.env.HOME);
|
||||
return cb(new Error('You have to run this with elevated rights'));
|
||||
}
|
||||
return sexec('whoami', {silent: true}, function(err, stdout, stderr) {
|
||||
console.log('sudo env PATH=$PATH:' + path.dirname(process.execPath) + ' ' + require.main.filename + ' ' + opts.args[1].name() + ' ' + platform + ' -u ' + stdout.trim() + ' --hp ' + process.env.HOME);
|
||||
return cb(new Error('You have to run this with elevated rights'));
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Detect running init system
|
||||
*/
|
||||
function detectInitSystem() {
|
||||
var hash_map = {
|
||||
'systemctl' : 'systemd',
|
||||
'update-rc.d': 'upstart',
|
||||
'chkconfig' : 'systemv',
|
||||
'rc-update' : 'openrc',
|
||||
'launchctl' : 'launchd',
|
||||
'sysrc' : 'rcd',
|
||||
'rcctl' : 'rcd-openbsd',
|
||||
'svcadm' : 'smf'
|
||||
};
|
||||
var init_systems = Object.keys(hash_map);
|
||||
|
||||
for (var i = 0; i < init_systems.length; i++) {
|
||||
if (which(init_systems[i]) != null) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (i >= init_systems.length) {
|
||||
Common.printError(cst.PREFIX_MSG_ERR + 'Init system not found');
|
||||
return null;
|
||||
}
|
||||
Common.printOut(cst.PREFIX_MSG + 'Init System found: ' + chalk.bold(hash_map[init_systems[i]]));
|
||||
return hash_map[init_systems[i]];
|
||||
}
|
||||
|
||||
CLI.prototype.uninstallStartup = function(platform, opts, cb) {
|
||||
var commands;
|
||||
var that = this;
|
||||
var actual_platform = detectInitSystem();
|
||||
var user = opts.user || process.env.USER || process.env.LOGNAME; // Use LOGNAME on Solaris-like systems
|
||||
var service_name = (opts.serviceName || 'pm2-' + user);
|
||||
var openrc_service_name = 'pm2';
|
||||
var launchd_service_name = (opts.serviceName || 'pm2.' + user);
|
||||
|
||||
if (!platform)
|
||||
platform = actual_platform;
|
||||
else if (actual_platform && actual_platform !== platform) {
|
||||
Common.printOut('-----------------------------------------------------------')
|
||||
Common.printOut(' PM2 detected ' + actual_platform + ' but you precised ' + platform)
|
||||
Common.printOut(' Please verify that your choice is indeed your init system')
|
||||
Common.printOut(' If you arent sure, just run : pm2 startup')
|
||||
Common.printOut('-----------------------------------------------------------')
|
||||
}
|
||||
if (platform === null)
|
||||
throw new Error('Init system not found')
|
||||
|
||||
if (!cb) {
|
||||
cb = function(err, data) {
|
||||
if (err)
|
||||
return that.exitCli(cst.ERROR_EXIT);
|
||||
return that.exitCli(cst.SUCCESS_EXIT);
|
||||
}
|
||||
}
|
||||
|
||||
if (process.getuid() != 0) {
|
||||
return isNotRoot('unsetup', platform, opts, cb);
|
||||
}
|
||||
|
||||
if (fs.existsSync('/etc/init.d/pm2-init.sh')) {
|
||||
platform = 'oldsystem';
|
||||
}
|
||||
|
||||
switch(platform) {
|
||||
case 'systemd':
|
||||
commands = [
|
||||
'systemctl stop ' + service_name,
|
||||
'systemctl disable ' + service_name,
|
||||
'rm /etc/systemd/system/' + service_name + '.service'
|
||||
];
|
||||
break;
|
||||
case 'systemv':
|
||||
commands = [
|
||||
'chkconfig ' + service_name + ' off',
|
||||
'rm /etc/init.d/' + service_name
|
||||
];
|
||||
break;
|
||||
case 'oldsystem':
|
||||
Common.printOut(cst.PREFIX_MSG + 'Disabling and deleting old startup system');
|
||||
commands = [
|
||||
'update-rc.d pm2-init.sh disable',
|
||||
'update-rc.d -f pm2-init.sh remove',
|
||||
'rm /etc/init.d/pm2-init.sh'
|
||||
];
|
||||
break;
|
||||
case 'openrc':
|
||||
service_name = openrc_service_name;
|
||||
commands = [
|
||||
'/etc/init.d/' + service_name + ' stop',
|
||||
'rc-update delete ' + service_name + ' default',
|
||||
'rm /etc/init.d/' + service_name
|
||||
];
|
||||
break;
|
||||
case 'upstart':
|
||||
commands = [
|
||||
'update-rc.d ' + service_name + ' disable',
|
||||
'update-rc.d -f ' + service_name + ' remove',
|
||||
'rm /etc/init.d/' + service_name
|
||||
];
|
||||
break;
|
||||
case 'launchd':
|
||||
var destination = path.join(process.env.HOME, 'Library/LaunchAgents/' + launchd_service_name + '.plist');
|
||||
commands = [
|
||||
'launchctl remove ' + launchd_service_name + ' || true',
|
||||
'rm ' + destination
|
||||
];
|
||||
break;
|
||||
case 'rcd':
|
||||
service_name = (opts.serviceName || 'pm2_' + user);
|
||||
commands = [
|
||||
'/usr/local/etc/rc.d/' + service_name + ' stop',
|
||||
'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;
|
||||
case 'smf':
|
||||
service_name = (opts.serviceName || 'pm2_' + user);
|
||||
commands = [
|
||||
'svcadm disable ' + service_name,
|
||||
'svccfg delete -f ' + service_name
|
||||
]
|
||||
};
|
||||
|
||||
sexec(commands.join('&& '), function(code, stdout, stderr) {
|
||||
Common.printOut(stdout);
|
||||
Common.printOut(stderr);
|
||||
if (code == 0) {
|
||||
Common.printOut(cst.PREFIX_MSG + chalk.bold('Init file disabled.'));
|
||||
} else {
|
||||
Common.printOut(cst.ERROR_MSG + chalk.bold('Return code : ' + code));
|
||||
}
|
||||
|
||||
cb(null, {
|
||||
commands : commands,
|
||||
platform : platform
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Startup script generation
|
||||
* @method startup
|
||||
* @param {string} platform type (centos|redhat|amazon|gentoo|systemd|smf)
|
||||
*/
|
||||
CLI.prototype.startup = function(platform, opts, cb) {
|
||||
var that = this;
|
||||
var actual_platform = detectInitSystem();
|
||||
var user = (opts.user || process.env.USER || process.env.LOGNAME); // Use LOGNAME on Solaris-like systems
|
||||
var service_name = (opts.serviceName || 'pm2-' + user);
|
||||
var openrc_service_name = 'pm2';
|
||||
var launchd_service_name = (opts.serviceName || 'pm2.' + user);
|
||||
|
||||
if (!platform)
|
||||
platform = actual_platform;
|
||||
else if (actual_platform && actual_platform !== platform) {
|
||||
Common.printOut('-----------------------------------------------------------')
|
||||
Common.printOut(' PM2 detected ' + actual_platform + ' but you precised ' + platform)
|
||||
Common.printOut(' Please verify that your choice is indeed your init system')
|
||||
Common.printOut(' If you arent sure, just run : pm2 startup')
|
||||
Common.printOut('-----------------------------------------------------------')
|
||||
}
|
||||
if (platform == null)
|
||||
throw new Error('Init system not found');
|
||||
|
||||
if (!cb) {
|
||||
cb = function(err, data) {
|
||||
if (err)
|
||||
return that.exitCli(cst.ERROR_EXIT);
|
||||
return that.exitCli(cst.SUCCESS_EXIT);
|
||||
}
|
||||
}
|
||||
|
||||
if (process.getuid() != 0) {
|
||||
return isNotRoot('setup', platform, opts, cb);
|
||||
}
|
||||
|
||||
var destination;
|
||||
var commands;
|
||||
var template;
|
||||
|
||||
function getTemplate(type) {
|
||||
return fs.readFileSync(path.join(__dirname, '..', 'templates/init-scripts', type + '.tpl'), {encoding: 'utf8'});
|
||||
}
|
||||
|
||||
switch(platform) {
|
||||
case 'ubuntu':
|
||||
case 'centos':
|
||||
case 'arch':
|
||||
case 'oracle':
|
||||
case 'systemd':
|
||||
if (opts.waitIp)
|
||||
template = getTemplate('systemd-online');
|
||||
else
|
||||
template = getTemplate('systemd');
|
||||
destination = '/etc/systemd/system/' + service_name + '.service';
|
||||
commands = [
|
||||
'systemctl enable ' + service_name
|
||||
];
|
||||
break;
|
||||
case 'ubuntu14':
|
||||
case 'ubuntu12':
|
||||
case 'upstart':
|
||||
template = getTemplate('upstart');
|
||||
destination = '/etc/init.d/' + service_name;
|
||||
commands = [
|
||||
'chmod +x ' + destination,
|
||||
'mkdir -p /var/lock/subsys',
|
||||
'touch /var/lock/subsys/' + service_name,
|
||||
'update-rc.d ' + service_name + ' defaults'
|
||||
];
|
||||
break;
|
||||
case 'systemv':
|
||||
case 'amazon':
|
||||
case 'centos6':
|
||||
template = getTemplate('upstart');
|
||||
destination = '/etc/init.d/' + service_name;
|
||||
commands = [
|
||||
'chmod +x ' + destination,
|
||||
'mkdir -p /var/lock/subsys',
|
||||
'touch /var/lock/subsys/' + service_name,
|
||||
'chkconfig --add ' + service_name,
|
||||
'chkconfig ' + service_name + ' on',
|
||||
'initctl list'
|
||||
];
|
||||
break;
|
||||
case 'macos':
|
||||
case 'darwin':
|
||||
case 'launchd':
|
||||
template = getTemplate('launchd');
|
||||
destination = path.join(process.env.HOME, 'Library/LaunchAgents/' + launchd_service_name + '.plist');
|
||||
commands = [
|
||||
'mkdir -p ' + path.join(process.env.HOME, 'Library/LaunchAgents'),
|
||||
'launchctl load -w ' + destination
|
||||
]
|
||||
break;
|
||||
case 'freebsd':
|
||||
case 'rcd':
|
||||
template = getTemplate('rcd');
|
||||
service_name = (opts.serviceName || 'pm2_' + user);
|
||||
destination = '/usr/local/etc/rc.d/' + service_name;
|
||||
commands = [
|
||||
'chmod 755 ' + destination,
|
||||
'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;
|
||||
destination = '/etc/init.d/' + service_name;
|
||||
commands = [
|
||||
'chmod +x ' + destination,
|
||||
'rc-update add ' + service_name + ' default'
|
||||
];
|
||||
break;
|
||||
case 'smf':
|
||||
case 'sunos':
|
||||
case 'solaris':
|
||||
template = getTemplate('smf');
|
||||
service_name = (opts.serviceName || 'pm2_' + user);
|
||||
destination = path.join(tmpPath(), service_name + '.xml');
|
||||
commands = [
|
||||
'svccfg import ' + destination,
|
||||
'svcadm enable ' + service_name
|
||||
];
|
||||
break;
|
||||
default:
|
||||
throw new Error('Unknown platform / init system name');
|
||||
}
|
||||
|
||||
/**
|
||||
* 4# Replace template variable value
|
||||
*/
|
||||
var envPath
|
||||
|
||||
if (cst.HAS_NODE_EMBEDDED == true)
|
||||
envPath = util.format('%s:%s', process.env.PATH || '', path.dirname(process.execPath))
|
||||
else if (new RegExp(path.dirname(process.execPath)).test(process.env.PATH))
|
||||
envPath = process.env.PATH
|
||||
else
|
||||
envPath = util.format('%s:%s', process.env.PATH || '', path.dirname(process.execPath))
|
||||
|
||||
template = template.replace(/%PM2_PATH%/g, process.mainModule.filename)
|
||||
.replace(/%NODE_PATH%/g, envPath)
|
||||
.replace(/%USER%/g, user)
|
||||
.replace(/%HOME_PATH%/g, opts.hp ? path.resolve(opts.hp, '.pm2') : cst.PM2_ROOT_PATH)
|
||||
.replace(/%SERVICE_NAME%/g, service_name);
|
||||
|
||||
Common.printOut(chalk.bold('Platform'), platform);
|
||||
Common.printOut(chalk.bold('Template'));
|
||||
Common.printOut(template);
|
||||
Common.printOut(chalk.bold('Target path'));
|
||||
Common.printOut(destination);
|
||||
Common.printOut(chalk.bold('Command list'));
|
||||
Common.printOut(commands);
|
||||
|
||||
Common.printOut(cst.PREFIX_MSG + 'Writing init configuration in ' + destination);
|
||||
try {
|
||||
fs.writeFileSync(destination, template);
|
||||
} catch (e) {
|
||||
console.error(cst.PREFIX_MSG_ERR + 'Failure when trying to write startup script');
|
||||
console.error(e.message || e);
|
||||
return cb(e);
|
||||
}
|
||||
|
||||
Common.printOut(cst.PREFIX_MSG + 'Making script booting at startup...');
|
||||
|
||||
forEachLimit(commands, 1, function(command, next) {
|
||||
Common.printOut(cst.PREFIX_MSG + '[-] Executing: %s...', chalk.bold(command));
|
||||
|
||||
sexec(command, function(code, stdout, stderr) {
|
||||
if (code === 0) {
|
||||
Common.printOut(cst.PREFIX_MSG + chalk.bold('[v] Command successfully executed.'));
|
||||
return next();
|
||||
} else {
|
||||
Common.printOut(chalk.red('[ERROR] Exit code : ' + code))
|
||||
return next(new Error(command + ' failed, see error above.'));
|
||||
}
|
||||
})
|
||||
|
||||
}, function(err) {
|
||||
if (err) {
|
||||
console.error(cst.PREFIX_MSG_ERR + (err.message || err));
|
||||
return cb(err);
|
||||
}
|
||||
Common.printOut(chalk.bold.blue('+---------------------------------------+'));
|
||||
Common.printOut(chalk.bold.blue((cst.PREFIX_MSG + 'Freeze a process list on reboot via:' )));
|
||||
Common.printOut(chalk.bold('$ pm2 save'));
|
||||
Common.printOut('');
|
||||
Common.printOut(chalk.bold.blue(cst.PREFIX_MSG + 'Remove init script via:'));
|
||||
Common.printOut(chalk.bold('$ pm2 unstartup ' + platform));
|
||||
|
||||
return cb(null, {
|
||||
destination : destination,
|
||||
template : template
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* DISABLED FEATURE
|
||||
* KEEPING METHOD FOR BACKWARD COMPAT
|
||||
*/
|
||||
CLI.prototype.autodump = function(cb) {
|
||||
return cb()
|
||||
}
|
||||
|
||||
/**
|
||||
* Dump current processes managed by pm2 into DUMP_FILE_PATH file
|
||||
* @method dump
|
||||
* @param {} cb
|
||||
* @return
|
||||
*/
|
||||
CLI.prototype.dump = function(force, cb) {
|
||||
var env_arr = [];
|
||||
var that = this;
|
||||
|
||||
if (typeof(force) === 'function') {
|
||||
cb = force
|
||||
force = false
|
||||
}
|
||||
|
||||
if (!cb)
|
||||
Common.printOut(cst.PREFIX_MSG + 'Saving current process list...');
|
||||
|
||||
that.Client.executeRemote('getMonitorData', {}, function(err, list) {
|
||||
if (err) {
|
||||
Common.printError('Error retrieving process list: ' + err);
|
||||
return cb ? cb(Common.retErr(err)) : that.exitCli(cst.ERROR_EXIT);
|
||||
}
|
||||
|
||||
/**
|
||||
* Description
|
||||
* @method fin
|
||||
* @param {} err
|
||||
* @return
|
||||
*/
|
||||
function fin(err) {
|
||||
|
||||
// try to fix issues with empty dump file
|
||||
// like #3485
|
||||
if (!force && env_arr.length === 0 && !process.env.FORCE) {
|
||||
|
||||
// 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(new Error('Process list empty, cannot save empty list'));
|
||||
} else {
|
||||
Common.printOut(cst.PREFIX_MSG_WARNING + 'PM2 is not managing any process, skipping save...');
|
||||
Common.printOut(cst.PREFIX_MSG_WARNING + 'To force saving use: pm2 save --force');
|
||||
that.exitCli(cst.SUCCESS_EXIT);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Back up dump file
|
||||
try {
|
||||
if (fs.existsSync(cst.DUMP_FILE_PATH)) {
|
||||
fs.writeFileSync(cst.DUMP_BACKUP_FILE_PATH, fs.readFileSync(cst.DUMP_FILE_PATH));
|
||||
}
|
||||
} catch (e) {
|
||||
console.error(e.stack || e);
|
||||
Common.printOut(cst.PREFIX_MSG_ERR + 'Failed to back up dump file in %s', cst.DUMP_BACKUP_FILE_PATH);
|
||||
}
|
||||
|
||||
// Overwrite dump file, delete if broken and exit
|
||||
try {
|
||||
fs.writeFileSync(cst.DUMP_FILE_PATH, JSON.stringify(env_arr, '', 2));
|
||||
} catch (e) {
|
||||
console.error(e.stack || e);
|
||||
try {
|
||||
// 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);
|
||||
return that.exitCli(cst.ERROR_EXIT);
|
||||
}
|
||||
if (cb) return cb(null, {success:true});
|
||||
|
||||
Common.printOut(cst.PREFIX_MSG + 'Successfully saved in %s', cst.DUMP_FILE_PATH);
|
||||
return that.exitCli(cst.SUCCESS_EXIT);
|
||||
}
|
||||
|
||||
(function ex(apps) {
|
||||
if (!apps[0]) return fin(null);
|
||||
delete apps[0].pm2_env.instances;
|
||||
delete apps[0].pm2_env.pm_id;
|
||||
delete apps[0].pm2_env.prev_restart_delay;
|
||||
if (!apps[0].pm2_env.pmx_module)
|
||||
env_arr.push(apps[0].pm2_env);
|
||||
apps.shift();
|
||||
return ex(apps);
|
||||
})(list);
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* 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
|
||||
* @param {} cb
|
||||
* @return
|
||||
*/
|
||||
CLI.prototype.resurrect = function(cb) {
|
||||
var apps = {};
|
||||
var that = this;
|
||||
|
||||
var processes;
|
||||
|
||||
function readDumpFile(dumpFilePath) {
|
||||
Common.printOut(cst.PREFIX_MSG + 'Restoring processes located in %s', dumpFilePath);
|
||||
try {
|
||||
var apps = fs.readFileSync(dumpFilePath);
|
||||
} catch (e) {
|
||||
Common.printError(cst.PREFIX_MSG_ERR + 'Failed to read dump file in %s', dumpFilePath);
|
||||
throw e;
|
||||
}
|
||||
|
||||
return apps;
|
||||
}
|
||||
|
||||
function parseDumpFile(dumpFilePath, apps) {
|
||||
try {
|
||||
var processes = Common.parseConfig(apps, 'none');
|
||||
} catch (e) {
|
||||
Common.printError(cst.PREFIX_MSG_ERR + 'Failed to parse dump file in %s', dumpFilePath);
|
||||
try {
|
||||
fs.unlinkSync(dumpFilePath);
|
||||
} catch (e) {
|
||||
console.error(e.stack || e);
|
||||
}
|
||||
throw e;
|
||||
}
|
||||
|
||||
return processes;
|
||||
}
|
||||
|
||||
// Read dump file, fall back to backup, delete if broken
|
||||
try {
|
||||
apps = readDumpFile(cst.DUMP_FILE_PATH);
|
||||
processes = parseDumpFile(cst.DUMP_FILE_PATH, apps);
|
||||
} catch(e) {
|
||||
try {
|
||||
apps = readDumpFile(cst.DUMP_BACKUP_FILE_PATH);
|
||||
processes = parseDumpFile(cst.DUMP_BACKUP_FILE_PATH, apps);
|
||||
} catch(e) {
|
||||
Common.printError(cst.PREFIX_MSG_ERR + 'No processes saved; DUMP file doesn\'t exist');
|
||||
// if (cb) return cb(Common.retErr(e));
|
||||
// else return that.exitCli(cst.ERROR_EXIT);
|
||||
return that.speedList();
|
||||
}
|
||||
}
|
||||
|
||||
that.Client.executeRemote('getMonitorData', {}, function(err, list) {
|
||||
if (err) {
|
||||
Common.printError(err);
|
||||
return that.exitCli(1);
|
||||
}
|
||||
|
||||
var current = [];
|
||||
var target = [];
|
||||
|
||||
list.forEach(function(app) {
|
||||
if (!current[app.name])
|
||||
current[app.name] = 0;
|
||||
current[app.name]++;
|
||||
});
|
||||
|
||||
processes.forEach(function(app) {
|
||||
if (!target[app.name])
|
||||
target[app.name] = 0;
|
||||
target[app.name]++;
|
||||
});
|
||||
|
||||
var tostart = Object.keys(target).filter(function(i) {
|
||||
return Object.keys(current).indexOf(i) < 0;
|
||||
})
|
||||
|
||||
eachLimit(processes, cst.CONCURRENT_ACTIONS, function(app, next) {
|
||||
if (tostart.indexOf(app.name) == -1)
|
||||
return next();
|
||||
that.Client.executeRemote('prepare', app, function(err, dt) {
|
||||
if (err)
|
||||
Common.printError(err);
|
||||
else
|
||||
Common.printOut(cst.PREFIX_MSG + 'Process %s restored', app.pm_exec_path);
|
||||
next();
|
||||
});
|
||||
}, function(err) {
|
||||
return cb ? cb(null, apps) : that.speedList();
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
}
|
||||
213
api.hyungi.net/node_modules/pm2/lib/API/UX/helpers.js
generated
vendored
Normal file
213
api.hyungi.net/node_modules/pm2/lib/API/UX/helpers.js
generated
vendored
Normal file
@@ -0,0 +1,213 @@
|
||||
const chalk = require('chalk')
|
||||
const Helpers = {}
|
||||
|
||||
/**
|
||||
* Converts Byte to Human readable size
|
||||
* @method bytesToSize
|
||||
* @param {} bytes
|
||||
* @param {} precision
|
||||
* @return
|
||||
*/
|
||||
Helpers.bytesToSize = function(bytes, precision) {
|
||||
var kilobyte = 1024
|
||||
var megabyte = kilobyte * 1024
|
||||
var gigabyte = megabyte * 1024
|
||||
var terabyte = gigabyte * 1024
|
||||
|
||||
if ((bytes >= 0) && (bytes < kilobyte)) {
|
||||
return bytes + 'b '
|
||||
} else if ((bytes >= kilobyte) && (bytes < megabyte)) {
|
||||
return (bytes / kilobyte).toFixed(precision) + 'kb '
|
||||
} else if ((bytes >= megabyte) && (bytes < gigabyte)) {
|
||||
return (bytes / megabyte).toFixed(precision) + 'mb '
|
||||
} else if ((bytes >= gigabyte) && (bytes < terabyte)) {
|
||||
return (bytes / gigabyte).toFixed(precision) + 'gb '
|
||||
} else if (bytes >= terabyte) {
|
||||
return (bytes / terabyte).toFixed(precision) + 'tb '
|
||||
} else {
|
||||
return bytes + 'b '
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Color Process state
|
||||
* @method colorStatus
|
||||
* @param {} status
|
||||
* @return
|
||||
*/
|
||||
Helpers.colorStatus = function(status) {
|
||||
switch (status) {
|
||||
|
||||
case 'online':
|
||||
return chalk.green.bold('online')
|
||||
break
|
||||
case 'running':
|
||||
return chalk.green.bold('online')
|
||||
break
|
||||
case 'restarting':
|
||||
return chalk.yellow.bold('restart')
|
||||
break
|
||||
case 'created':
|
||||
return chalk.yellow.bold('created')
|
||||
break
|
||||
case 'launching':
|
||||
return chalk.blue.bold('launching')
|
||||
break
|
||||
default:
|
||||
return chalk.red.bold(status)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Safe Push
|
||||
*/
|
||||
Helpers.safe_push = function() {
|
||||
var argv = arguments
|
||||
var table = argv[0]
|
||||
|
||||
for (var i = 1; i < argv.length; ++i) {
|
||||
var elem = argv[i]
|
||||
if (elem[Object.keys(elem)[0]] === undefined
|
||||
|| elem[Object.keys(elem)[0]] === null) {
|
||||
elem[Object.keys(elem)[0]] = 'N/A'
|
||||
}
|
||||
else if (Array.isArray(elem[Object.keys(elem)[0]])) {
|
||||
elem[Object.keys(elem)[0]].forEach(function(curr, j) {
|
||||
if (curr === undefined || curr === null)
|
||||
elem[Object.keys(elem)[0]][j] = 'N/A'
|
||||
})
|
||||
}
|
||||
table.push(elem)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Description
|
||||
* @method timeSince
|
||||
* @param {} date
|
||||
* @return BinaryExpression
|
||||
*/
|
||||
Helpers.timeSince = function(date) {
|
||||
var seconds = Math.floor((new Date() - date) / 1000)
|
||||
|
||||
var interval = Math.floor(seconds / 31536000)
|
||||
|
||||
if (interval > 1) {
|
||||
return interval + 'Y'
|
||||
}
|
||||
interval = Math.floor(seconds / 2592000)
|
||||
if (interval > 1) {
|
||||
return interval + 'M'
|
||||
}
|
||||
interval = Math.floor(seconds / 86400)
|
||||
if (interval > 1) {
|
||||
return interval + 'D'
|
||||
}
|
||||
interval = Math.floor(seconds / 3600)
|
||||
if (interval > 1) {
|
||||
return interval + 'h'
|
||||
}
|
||||
interval = Math.floor(seconds / 60)
|
||||
if (interval > 1) {
|
||||
return interval + 'm'
|
||||
}
|
||||
return Math.floor(seconds) + 's'
|
||||
}
|
||||
|
||||
/**
|
||||
* Colorize Metrics
|
||||
*
|
||||
* @param {Number} value current value
|
||||
* @param {Number} warn value threshold
|
||||
* @param {Number} alert value threshold
|
||||
* @param {String} prefix value prefix
|
||||
* @return {String} value
|
||||
*/
|
||||
Helpers.colorizedMetric = function(value, warn, alert, prefix) {
|
||||
var inverted = false
|
||||
if (alert < warn)
|
||||
inverted = true
|
||||
|
||||
if (!prefix) prefix = ''
|
||||
if (isNaN(value) === true)
|
||||
return 'N/A'
|
||||
if (value == 0)
|
||||
return 0 + prefix
|
||||
if (inverted == true) {
|
||||
if (value > warn)
|
||||
return chalk.green(value + prefix)
|
||||
if (value <= warn && value >= alert)
|
||||
return chalk.bold.yellow(value + prefix)
|
||||
return chalk.bold.red(value + prefix)
|
||||
}
|
||||
if (value < warn)
|
||||
return chalk.green(value + prefix)
|
||||
if (value >= warn && value <= alert)
|
||||
return chalk.bold.yellow(value + prefix)
|
||||
return chalk.bold.red(value + prefix)
|
||||
}
|
||||
|
||||
/**
|
||||
* Get nested property
|
||||
*
|
||||
* @param {String} propertyName
|
||||
* @param {Object} obj
|
||||
* @returns {String} property value
|
||||
*/
|
||||
Helpers.getNestedProperty = function(propertyName, obj) {
|
||||
var parts = propertyName.split('.'),
|
||||
length = parts.length,
|
||||
property = obj || {}
|
||||
|
||||
for (var i = 0; i < length; i++ ) {
|
||||
property = property[parts[i]]
|
||||
}
|
||||
|
||||
return property
|
||||
}
|
||||
|
||||
Helpers.openEditor = function (file, opts, cb) {
|
||||
var spawn = require('child_process').spawn
|
||||
|
||||
if (typeof opts === 'function') {
|
||||
cb = opts
|
||||
opts = {}
|
||||
}
|
||||
|
||||
if (!opts) opts = {}
|
||||
|
||||
var ed = /^win/.test(process.platform) ? 'notepad' : 'vim'
|
||||
var editor = opts.editor || process.env.VISUAL || process.env.EDITOR || ed
|
||||
var args = editor.split(/\s+/)
|
||||
var bin = args.shift()
|
||||
|
||||
var ps = spawn(bin, args.concat([ file ]), {
|
||||
windowsHide: true,
|
||||
stdio: 'inherit'
|
||||
})
|
||||
|
||||
ps.on('exit', function (code, sig) {
|
||||
if (typeof cb === 'function') cb(code, sig)
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
Helpers.dispKeys = function(kv, target_module) {
|
||||
Object.keys(kv).forEach(function(key) {
|
||||
|
||||
if (target_module != null && target_module != key)
|
||||
return false
|
||||
|
||||
if (typeof(kv[key]) == 'object') {
|
||||
var obj = {}
|
||||
|
||||
console.log(chalk.bold('Module: ') + chalk.bold.blue(key))
|
||||
Object.keys(kv[key]).forEach(function(sub_key) {
|
||||
console.log(`$ pm2 set ${key}:${sub_key} ${kv[key][sub_key]}`)
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
module.exports = Helpers
|
||||
9
api.hyungi.net/node_modules/pm2/lib/API/UX/index.js
generated
vendored
Normal file
9
api.hyungi.net/node_modules/pm2/lib/API/UX/index.js
generated
vendored
Normal file
@@ -0,0 +1,9 @@
|
||||
|
||||
const UX = {
|
||||
helpers: require('./helpers.js'),
|
||||
describe: require('./pm2-describe.js'),
|
||||
list: require('./pm2-ls.js'),
|
||||
list_min: require('./pm2-ls-minimal.js')
|
||||
}
|
||||
|
||||
module.exports = UX
|
||||
193
api.hyungi.net/node_modules/pm2/lib/API/UX/pm2-describe.js
generated
vendored
Normal file
193
api.hyungi.net/node_modules/pm2/lib/API/UX/pm2-describe.js
generated
vendored
Normal file
@@ -0,0 +1,193 @@
|
||||
const Table = require('cli-tableau')
|
||||
const chalk = require('chalk')
|
||||
const UxHelpers = require('./helpers.js')
|
||||
const Common = require('../../Common.js')
|
||||
|
||||
var postModuleInfos = function(module_name, human_info) {
|
||||
var table = new Table({
|
||||
style : {'padding-left' : 1, head : ['cyan', 'bold'], compact : true}
|
||||
})
|
||||
|
||||
var disp = {}
|
||||
|
||||
human_info.unshift(['Module name', module_name])
|
||||
human_info.forEach(function(info) {
|
||||
var obj = {}
|
||||
obj[chalk.bold.cyan(info[0])] = info[1]
|
||||
table.push(obj)
|
||||
})
|
||||
|
||||
console.log()
|
||||
console.log(chalk.bold.inverse(' Module %s infos '), module_name)
|
||||
console.log(table.toString())
|
||||
}
|
||||
|
||||
/**
|
||||
* Description
|
||||
* @method describeTable
|
||||
* @param {Object} proc process list
|
||||
*/
|
||||
module.exports = function(proc) {
|
||||
var table = new Table({
|
||||
style : {'padding-left' : 1, head : ['cyan', 'bold'], compact : true}
|
||||
})
|
||||
|
||||
var pm2_env = proc.pm2_env
|
||||
|
||||
var created_at = 'N/A'
|
||||
|
||||
if (pm2_env.axm_options && pm2_env.axm_options.human_info) {
|
||||
postModuleInfos(pm2_env.name, pm2_env.axm_options.human_info)
|
||||
}
|
||||
|
||||
try {
|
||||
if (pm2_env.created_at != null)
|
||||
created_at = new Date(pm2_env.created_at).toISOString()
|
||||
} catch (e) {
|
||||
}
|
||||
|
||||
console.log(chalk.bold.inverse(' Describing process with id %d - name %s '), pm2_env.pm_id, pm2_env.name)
|
||||
UxHelpers.safe_push(table,
|
||||
{ 'status' : UxHelpers.colorStatus(pm2_env.status) },
|
||||
{ 'name': pm2_env.name },
|
||||
{ 'namespace': pm2_env.namespace },
|
||||
{ 'version': pm2_env.version },
|
||||
{ 'restarts' : pm2_env.restart_time },
|
||||
{ 'uptime' : (pm2_env.pm_uptime && pm2_env.status == 'online') ? UxHelpers.timeSince(pm2_env.pm_uptime) : 0 },
|
||||
{ 'script path' : pm2_env.pm_exec_path },
|
||||
{ 'script args' : pm2_env.args ? (typeof pm2_env.args == 'string' ? JSON.parse(pm2_env.args.replace(/'/g, '"')):pm2_env.args).join(' ') : null },
|
||||
{ 'error log path' : pm2_env.pm_err_log_path },
|
||||
{ 'out log path' : pm2_env.pm_out_log_path },
|
||||
{ 'pid path' : pm2_env.pm_pid_path },
|
||||
|
||||
{ 'interpreter' : pm2_env.exec_interpreter },
|
||||
{ 'interpreter args' : pm2_env.node_args.length != 0 ? pm2_env.node_args : null },
|
||||
|
||||
{ 'script id' : pm2_env.pm_id },
|
||||
{ 'exec cwd' : pm2_env.pm_cwd },
|
||||
|
||||
{ 'exec mode' : pm2_env.exec_mode },
|
||||
{ 'node.js version' : pm2_env.node_version },
|
||||
{ 'node env': pm2_env.env.NODE_ENV },
|
||||
{ 'watch & reload' : pm2_env.watch ? chalk.green.bold('✔') : '✘' },
|
||||
{ 'unstable restarts' : pm2_env.unstable_restarts },
|
||||
{ 'created at' : created_at }
|
||||
)
|
||||
|
||||
if ('pm_log_path' in pm2_env){
|
||||
table.splice(6, 0, {'entire log path': pm2_env.pm_log_path})
|
||||
}
|
||||
|
||||
if ('cron_restart' in pm2_env){
|
||||
table.splice(5, 0, {'cron restart': pm2_env.cron_restart})
|
||||
}
|
||||
|
||||
console.log(table.toString())
|
||||
|
||||
/**
|
||||
* Module conf display
|
||||
*/
|
||||
if (pm2_env.axm_options &&
|
||||
pm2_env.axm_options.module_conf &&
|
||||
Object.keys(pm2_env.axm_options.module_conf).length > 0) {
|
||||
var table_conf = new Table({
|
||||
style : {'padding-left' : 1, head : ['cyan', 'bold'], compact : true}
|
||||
})
|
||||
console.log('Process configuration')
|
||||
|
||||
Object.keys(pm2_env.axm_options.module_conf).forEach(function(key) {
|
||||
var tmp = {}
|
||||
tmp[key] = pm2_env.axm_options.module_conf[key]
|
||||
UxHelpers.safe_push(table_conf, tmp)
|
||||
})
|
||||
|
||||
console.log(table_conf.toString())
|
||||
}
|
||||
|
||||
/**
|
||||
* Versioning metadata
|
||||
*/
|
||||
if (pm2_env.versioning) {
|
||||
|
||||
var table2 = new Table({
|
||||
style : {'padding-left' : 1, head : ['cyan', 'bold'], compact : true}
|
||||
})
|
||||
|
||||
console.log(chalk.inverse.bold(' Revision control metadata '))
|
||||
UxHelpers.safe_push(table2,
|
||||
{ 'revision control' : pm2_env.versioning.type },
|
||||
{ 'remote url' : pm2_env.versioning.url },
|
||||
{ 'repository root' : pm2_env.versioning.repo_path },
|
||||
{ 'last update' : pm2_env.versioning.update_time },
|
||||
{ 'revision' : pm2_env.versioning.revision },
|
||||
{ 'comment' : pm2_env.versioning.comment ? pm2_env.versioning.comment.trim().slice(0, 60) : '' },
|
||||
{ 'branch' : pm2_env.versioning.branch }
|
||||
)
|
||||
console.log(table2.toString())
|
||||
}
|
||||
|
||||
if (pm2_env.axm_actions && Object.keys(pm2_env.axm_actions).length > 0) {
|
||||
var table_actions = new Table({
|
||||
style : {'padding-left' : 1, head : ['cyan', 'bold'], compact : true}
|
||||
})
|
||||
|
||||
console.log(chalk.inverse.bold(' Actions available '))
|
||||
pm2_env.axm_actions.forEach(function(action_set) {
|
||||
UxHelpers.safe_push(table_actions, [action_set.action_name])
|
||||
})
|
||||
|
||||
console.log(table_actions.toString())
|
||||
Common.printOut(chalk.white.italic(' Trigger via: pm2 trigger %s <action_name>\n'), pm2_env.name)
|
||||
}
|
||||
|
||||
if (pm2_env.axm_monitor && Object.keys(pm2_env.axm_monitor).length > 0) {
|
||||
var table_probes = new Table({
|
||||
style : {'padding-left' : 1, head : ['cyan', 'bold'], compact : true}
|
||||
})
|
||||
|
||||
console.log(chalk.inverse.bold(' Code metrics value '))
|
||||
Object.keys(pm2_env.axm_monitor).forEach(function(key) {
|
||||
var obj = {}
|
||||
var metric_name = pm2_env.axm_monitor[key].hasOwnProperty("value") ? pm2_env.axm_monitor[key].value : pm2_env.axm_monitor[key]
|
||||
var metric_unit = pm2_env.axm_monitor[key].hasOwnProperty("unit") ? pm2_env.axm_monitor[key].unit : ''
|
||||
var value = `${metric_name} ${metric_unit}`
|
||||
obj[key] = value
|
||||
UxHelpers.safe_push(table_probes, obj)
|
||||
})
|
||||
|
||||
console.log(table_probes.toString())
|
||||
}
|
||||
|
||||
var table_env = new Table({
|
||||
style : {'padding-left' : 1, head : ['cyan', 'bold'], compact : true}
|
||||
})
|
||||
|
||||
console.log(chalk.inverse.bold(' Divergent env variables from local env '))
|
||||
|
||||
var _env = Common.safeExtend({}, pm2_env)
|
||||
var diff_env = {}
|
||||
|
||||
Object.keys(process.env).forEach(k => {
|
||||
if (!_env[k] || _env[k] != process.env[k]) {
|
||||
diff_env[k] = process.env[k]
|
||||
}
|
||||
})
|
||||
|
||||
Object.keys(diff_env).forEach(function(key) {
|
||||
var obj = {}
|
||||
if (_env[key]) {
|
||||
// 1. fix env value is not a String and slice is undeinfed
|
||||
// 2. fix process.stdout.columns is undefined and causes empty string output
|
||||
// 3. columns defaults to 300 - same as specified in pm2-ls
|
||||
obj[key] = String(_env[key]).slice(0, (process.stdout.columns || 300) - 60)
|
||||
UxHelpers.safe_push(table_env, obj)
|
||||
}
|
||||
})
|
||||
|
||||
console.log(table_env.toString())
|
||||
console.log()
|
||||
Common.printOut(chalk.white.italic(' Add your own code metrics: http://bit.ly/code-metrics'))
|
||||
Common.printOut(chalk.white.italic(' Use `pm2 logs %s [--lines 1000]` to display logs'), pm2_env.name)
|
||||
Common.printOut(chalk.white.italic(' Use `pm2 env %s` to display environment variables'), pm2_env.pm_id)
|
||||
Common.printOut(chalk.white.italic(' Use `pm2 monit` to monitor CPU and Memory usage'), pm2_env.name)
|
||||
}
|
||||
31
api.hyungi.net/node_modules/pm2/lib/API/UX/pm2-ls-minimal.js
generated
vendored
Normal file
31
api.hyungi.net/node_modules/pm2/lib/API/UX/pm2-ls-minimal.js
generated
vendored
Normal file
@@ -0,0 +1,31 @@
|
||||
|
||||
const UxHelpers = require('./helpers.js')
|
||||
const p = require('path')
|
||||
|
||||
/**
|
||||
* Minimal display via pm2 ls -m
|
||||
* @method miniDisplay
|
||||
* @param {Object} list process list
|
||||
*/
|
||||
module.exports = function(list) {
|
||||
list.forEach(function(l) {
|
||||
|
||||
var mode = l.pm2_env.exec_mode.split('_mode')[0]
|
||||
var status = l.pm2_env.status
|
||||
var key = l.pm2_env.name || p.basename(l.pm2_env.pm_exec_path.script)
|
||||
|
||||
console.log('+--- %s', key)
|
||||
console.log('namespace : %s', l.pm2_env.namespace)
|
||||
console.log('version : %s', l.pm2_env.version)
|
||||
console.log('pid : %s', l.pid)
|
||||
console.log('pm2 id : %s', l.pm2_env.pm_id)
|
||||
console.log('status : %s', status)
|
||||
console.log('mode : %s', mode)
|
||||
console.log('restarted : %d', l.pm2_env.restart_time ? l.pm2_env.restart_time : 0)
|
||||
console.log('uptime : %s', (l.pm2_env.pm_uptime && status == 'online') ? UxHelpers.timeSince(l.pm2_env.pm_uptime) : 0)
|
||||
console.log('memory usage : %s', l.monit ? UxHelpers.bytesToSize(l.monit.memory, 1) : '')
|
||||
console.log('error log : %s', l.pm2_env.pm_err_log_path)
|
||||
console.log('watching : %s', l.pm2_env.watch ? 'yes' : 'no')
|
||||
console.log('PID file : %s\n', l.pm2_env.pm_pid_path)
|
||||
})
|
||||
}
|
||||
482
api.hyungi.net/node_modules/pm2/lib/API/UX/pm2-ls.js
generated
vendored
Normal file
482
api.hyungi.net/node_modules/pm2/lib/API/UX/pm2-ls.js
generated
vendored
Normal file
@@ -0,0 +1,482 @@
|
||||
|
||||
const cst = require('../../../constants')
|
||||
const Common = require('../../Common')
|
||||
const Configuration = require('../../Configuration')
|
||||
const UxHelpers = require('./helpers.js')
|
||||
const chalk = require('chalk')
|
||||
const Table = require('cli-tableau')
|
||||
const Passwd = require('../../tools/passwd.js')
|
||||
|
||||
const List = {}
|
||||
|
||||
const CONDENSED_MODE = (process.stdout.columns || 300) < 134
|
||||
|
||||
/**
|
||||
* Check if dump file contains same apps that the one managed by PM2
|
||||
*/
|
||||
function checkIfProcessAreDumped(list) {
|
||||
try {
|
||||
var dump_raw = require('fs').readFileSync(cst.DUMP_FILE_PATH)
|
||||
var dump = JSON.parse(dump_raw)
|
||||
var apps_dumped = dump.map(proc => proc.name)
|
||||
var apps_running = list
|
||||
.filter(proc => proc.pm2_env.pmx_module != true)
|
||||
.map(proc => proc.name)
|
||||
var diff = apps_dumped.filter(a => !apps_running.includes(a))
|
||||
if (diff.length > 0) {
|
||||
Common.warn(`Current process list is not synchronized with saved list. App ${chalk.bold(diff.join(' '))} differs. Type 'pm2 save' to synchronize.`)
|
||||
}
|
||||
else if (apps_dumped.length != apps_running.length) {
|
||||
Common.warn(`Current process list is not synchronized with saved list. Type 'pm2 save' to synchronize.`)
|
||||
}
|
||||
} catch(e) {
|
||||
}
|
||||
}
|
||||
|
||||
var proc_id = 0
|
||||
|
||||
/**
|
||||
* List Applications and Modules managed by PM2
|
||||
*/
|
||||
function listModulesAndAppsManaged(list, commander) {
|
||||
var name_col_size = 11
|
||||
|
||||
if (list && list.length > 0)
|
||||
name_col_size = (list.reduce((p, c) => (p.name.length > c.name.length) ? p : c)).name.length + 5
|
||||
|
||||
var id_width = Math.max(
|
||||
2 + (Math.max(...list.map((l) => String(l.pm2_env.pm_id || 0).length)) || 0),
|
||||
4
|
||||
);
|
||||
|
||||
var app_head = {
|
||||
id: id_width,
|
||||
name: name_col_size,
|
||||
namespace: 13,
|
||||
version: 9,
|
||||
mode: 9,
|
||||
pid: 10,
|
||||
uptime: 8,
|
||||
'↺': 6,
|
||||
status: 11,
|
||||
cpu: 10,
|
||||
mem: 10,
|
||||
user: 10,
|
||||
watching: 10
|
||||
}
|
||||
|
||||
var mod_head = {
|
||||
id: id_width,
|
||||
module: 30,
|
||||
version: 15,
|
||||
pid: 10,
|
||||
status: 10,
|
||||
'↺': 6,
|
||||
cpu: 10,
|
||||
mem: 10,
|
||||
user: 10
|
||||
}
|
||||
|
||||
if (CONDENSED_MODE) {
|
||||
app_head = {
|
||||
id: id_width,
|
||||
name: 20,
|
||||
mode: 10,
|
||||
'↺': 6,
|
||||
status: 11,
|
||||
cpu: 10,
|
||||
memory: 10
|
||||
}
|
||||
|
||||
mod_head = {
|
||||
id: id_width,
|
||||
name: 20,
|
||||
status: 10,
|
||||
cpu: 10,
|
||||
mem: 10
|
||||
}
|
||||
}
|
||||
|
||||
var app_table = new Table({
|
||||
head : Object.keys(app_head),
|
||||
colWidths: Object.keys(app_head).map(k => app_head[k]),
|
||||
colAligns : ['left'],
|
||||
style : {'padding-left' : 1, head : ['cyan', 'bold'], compact : true}
|
||||
})
|
||||
|
||||
var module_table = new Table({
|
||||
head : Object.keys(mod_head),
|
||||
colWidths: Object.keys(mod_head).map(k => mod_head[k]),
|
||||
colAligns : ['left'],
|
||||
style : {'padding-left' : 1, head : ['cyan', 'bold'], compact : true}
|
||||
})
|
||||
|
||||
var sortField = 'name', sortOrder = 'asc', sort,
|
||||
fields = {
|
||||
name: 'pm2_env.name',
|
||||
namespace: 'pm2_env.namespace',
|
||||
pid: 'pid',
|
||||
id: 'pm_id',
|
||||
cpu: 'monit.cpu',
|
||||
memory: 'monit.memory',
|
||||
uptime: 'pm2_env.pm_uptime',
|
||||
status: 'pm2_env.status'
|
||||
}
|
||||
|
||||
if (commander && commander.sort) {
|
||||
sort = commander.sort.split(':');
|
||||
|
||||
if(fields[sort[0].toLowerCase()]) {
|
||||
sortField = sort[0].toLowerCase();
|
||||
sortOrder = sort.length === 2 ? sort[1] : 'asc';
|
||||
}
|
||||
}
|
||||
|
||||
list.sort(function(a, b) {
|
||||
var fieldA = UxHelpers.getNestedProperty(fields[sortField], a)
|
||||
var fieldB = UxHelpers.getNestedProperty(fields[sortField], b)
|
||||
|
||||
if (sortOrder === 'desc') {
|
||||
if (fieldA > fieldB)
|
||||
return -1
|
||||
if (fieldA < fieldB)
|
||||
return 1
|
||||
} else {
|
||||
if (fieldA < fieldB)
|
||||
return -1
|
||||
if (fieldA > fieldB)
|
||||
return 1
|
||||
}
|
||||
return 0
|
||||
})
|
||||
|
||||
list.forEach(function(l) {
|
||||
var obj = {}
|
||||
|
||||
if (l.pm2_env.pm_id > proc_id) {
|
||||
proc_id = l.pm2_env.pm_id
|
||||
}
|
||||
|
||||
var mode = l.pm2_env.exec_mode
|
||||
var status = l.pm2_env.status
|
||||
var key = l.pm2_env.pm_id
|
||||
key = chalk.bold.cyan(key)
|
||||
|
||||
if (l.pm2_env.axm_options) {
|
||||
var is_tracing_enabled = false
|
||||
|
||||
if (l.pm2_env.axm_options.tracing &&
|
||||
typeof(l.pm2_env.axm_options.tracing) == 'boolean' &&
|
||||
l.pm2_env.axm_options.tracing == true)
|
||||
is_tracing_enabled = true
|
||||
|
||||
if (l.pm2_env.axm_options.tracing &&
|
||||
l.pm2_env.axm_options.tracing.enabled &&
|
||||
typeof(l.pm2_env.axm_options.tracing.enabled) == 'boolean' &&
|
||||
l.pm2_env.axm_options.tracing.enabled == true)
|
||||
is_tracing_enabled = true
|
||||
|
||||
if (is_tracing_enabled == true)
|
||||
l.pm2_env.name = chalk.green('☵') + ' ' + l.pm2_env.name
|
||||
|
||||
if (l.pm2_env._km_monitored)
|
||||
l.pm2_env.name = chalk.bold.green('◉') + ' ' + l.pm2_env.name
|
||||
}
|
||||
|
||||
if (l.pm2_env.pmx_module == true) {
|
||||
if (l.pm2_env.name == 'pm2-sysmonit') return
|
||||
// pm2 ls for Modules
|
||||
obj[key] = []
|
||||
|
||||
obj[key].push(l.name)
|
||||
|
||||
// Module version + PID
|
||||
if (!CONDENSED_MODE) {
|
||||
var pid = l.pm2_env.axm_options.pid ? l.pm2_env.axm_options.pid : l.pid
|
||||
obj[key].push(l.pm2_env.version || 'N/A', pid)
|
||||
}
|
||||
|
||||
// Status
|
||||
obj[key].push(UxHelpers.colorStatus(status))
|
||||
|
||||
// Restart
|
||||
if (!CONDENSED_MODE)
|
||||
obj[key].push(l.pm2_env.restart_time ? l.pm2_env.restart_time : 0)
|
||||
|
||||
// CPU + Memory
|
||||
obj[key].push(l.monit ? (l.monit.cpu + '%') : 'N/A', l.monit ? UxHelpers.bytesToSize(l.monit.memory, 1) : 'N/A' )
|
||||
|
||||
// User
|
||||
if (!CONDENSED_MODE) {
|
||||
|
||||
if (l.pm2_env.uid && typeof(l.pm2_env.uid) == 'number') {
|
||||
// Resolve user id to username
|
||||
let users = Passwd.getUsers()
|
||||
Object.keys(users).forEach(function(username) {
|
||||
var user = users[username]
|
||||
if (user.userId == l.pm2_env.uid) {
|
||||
l.pm2_env.uid = user.username
|
||||
}
|
||||
})
|
||||
}
|
||||
obj[key].push(chalk.bold(l.pm2_env.uid || l.pm2_env.username))
|
||||
}
|
||||
|
||||
UxHelpers.safe_push(module_table, obj)
|
||||
}
|
||||
else {
|
||||
// pm2 ls for Applications
|
||||
obj[key] = []
|
||||
|
||||
// PM2 ID
|
||||
obj[key].push(l.pm2_env.name)
|
||||
|
||||
// Namespace
|
||||
if (!CONDENSED_MODE)
|
||||
obj[key].push(l.pm2_env.namespace)
|
||||
|
||||
// Version
|
||||
if (!CONDENSED_MODE)
|
||||
obj[key].push(l.pm2_env.version)
|
||||
|
||||
// Exec mode
|
||||
obj[key].push(mode == 'fork_mode' ? chalk.inverse.bold('fork') : chalk.blue.bold('cluster'))
|
||||
|
||||
// PID
|
||||
if (!CONDENSED_MODE)
|
||||
obj[key].push(l.pid)
|
||||
|
||||
// Uptime
|
||||
if (!CONDENSED_MODE)
|
||||
obj[key].push((l.pm2_env.pm_uptime && status == 'online') ? UxHelpers.timeSince(l.pm2_env.pm_uptime) : 0)
|
||||
|
||||
// Restart
|
||||
obj[key].push(l.pm2_env.restart_time ? l.pm2_env.restart_time : 0)
|
||||
|
||||
// Status
|
||||
obj[key].push(UxHelpers.colorStatus(status))
|
||||
|
||||
|
||||
// CPU
|
||||
obj[key].push(l.monit ? l.monit.cpu + '%' : 'N/A')
|
||||
|
||||
// Memory
|
||||
obj[key].push(l.monit ? UxHelpers.bytesToSize(l.monit.memory, 1) : 'N/A')
|
||||
|
||||
// User
|
||||
if (!CONDENSED_MODE) {
|
||||
if (l.pm2_env.uid && typeof(l.pm2_env.uid) == 'number') {
|
||||
// Resolve user id to username
|
||||
let users = Passwd.getUsers()
|
||||
Object.keys(users).forEach(function(username) {
|
||||
var user = users[username]
|
||||
if (user.userId == l.pm2_env.uid) {
|
||||
l.pm2_env.uid = user.username
|
||||
}
|
||||
})
|
||||
}
|
||||
obj[key].push(chalk.bold(l.pm2_env.uid || l.pm2_env.username))
|
||||
}
|
||||
|
||||
// Watch status
|
||||
if (!CONDENSED_MODE)
|
||||
obj[key].push(l.pm2_env.watch ? chalk.green.bold('enabled') : chalk.grey('disabled'))
|
||||
|
||||
UxHelpers.safe_push(app_table, obj)
|
||||
}
|
||||
|
||||
})
|
||||
|
||||
// Print Applications Managed
|
||||
console.log(app_table.toString())
|
||||
|
||||
// Print Modules Managed
|
||||
if (module_table.length > 0) {
|
||||
console.log(chalk.bold(`Module${module_table.length > 1 ? 's' : ''}`))
|
||||
console.log(module_table.toString())
|
||||
}
|
||||
|
||||
proc_id++
|
||||
}
|
||||
|
||||
// Container display
|
||||
function containersListing(sys_infos) {
|
||||
var stacked_docker = (process.stdout.columns || 100) < 140
|
||||
|
||||
var docker_head = {
|
||||
id: 4,
|
||||
image: 50,
|
||||
status: 10,
|
||||
'↺': 6,
|
||||
cpu: 10,
|
||||
mem: 10,
|
||||
'net I/O ⇵': 11,
|
||||
'fs I/O ⇵': 11
|
||||
}
|
||||
|
||||
if (stacked_docker) {
|
||||
docker_head = {
|
||||
id: 4,
|
||||
image: 25,
|
||||
status: 10,
|
||||
cpu: 10,
|
||||
mem: 10
|
||||
}
|
||||
}
|
||||
|
||||
var docker_table = new Table({
|
||||
colWidths: Object.keys(docker_head).map(k => docker_head[k]),
|
||||
head : Object.keys(docker_head),
|
||||
colAligns : ['left'],
|
||||
style : {'padding-left' : 1, head : ['cyan', 'bold'], compact : true}
|
||||
})
|
||||
|
||||
sys_infos.containers.forEach((c) => {
|
||||
var cpu = c.stats.cpu_percent
|
||||
var mem = c.stats.mem_percent == 0 ? '0' : c.stats.mem_percent
|
||||
var id = chalk.bold.cyan(proc_id++)
|
||||
var state = UxHelpers.colorStatus(c.state)
|
||||
|
||||
if (stacked_docker)
|
||||
docker_table.push([id, c.image, state, `${cpu}%`, `${mem}mb`])
|
||||
else {
|
||||
docker_table.push([
|
||||
id,
|
||||
c.image,
|
||||
state,
|
||||
c.restartCount,
|
||||
`${cpu == 0 ? '0' : cpu}%`,
|
||||
`${mem}mb`,
|
||||
`${c.stats.netIO.rx}/${isNaN(c.stats.netIO.tx) == true ? '0.0' : c.stats.netIO.tx}`,
|
||||
`${c.stats.blockIO.r}/${c.stats.blockIO.w}`
|
||||
])
|
||||
}
|
||||
})
|
||||
|
||||
console.log(chalk.bold(`Container${sys_infos.containers.length > 1 ? 's' : ''}`))
|
||||
console.log(docker_table.toString())
|
||||
}
|
||||
|
||||
/**
|
||||
* High resource processes
|
||||
*/
|
||||
function listHighResourcesProcesses(sys_infos) {
|
||||
const CPU_MIN_SHOW = 60
|
||||
const MEM_MIN_SHOW = 30
|
||||
|
||||
var sys_proc_head = ['id', 'cmd', 'pid', 'cpu', 'mem', 'uid']
|
||||
|
||||
var sys_proc_table = new Table({
|
||||
colWidths: [4, CONDENSED_MODE ? 29 : 77, 10, 10, 10, 8],
|
||||
head : sys_proc_head,
|
||||
colAligns : ['left'],
|
||||
style : {'padding-left' : 1, head : ['cyan', 'bold'], compact : true}
|
||||
})
|
||||
|
||||
sys_infos.processes.cpu_sorted = sys_infos.processes.cpu_sorted.filter((proc) => {
|
||||
return proc.cpu > CPU_MIN_SHOW && proc.cmd.includes('node') === false &&
|
||||
proc.cmd.includes('God Daemon') === false
|
||||
})
|
||||
|
||||
sys_infos.processes.cpu_sorted.forEach(proc => {
|
||||
var cpu = `${UxHelpers.colorizedMetric(proc.cpu, 40, 70, '%')}`
|
||||
var mem = `${UxHelpers.colorizedMetric(proc.memory, 40, 70, '%')}`
|
||||
var cmd = proc.cmd
|
||||
sys_proc_table.push([chalk.bold.cyan(proc_id++), cmd, proc.pid, cpu, mem, proc.uid])
|
||||
})
|
||||
|
||||
sys_infos.processes.mem_sorted = sys_infos.processes.mem_sorted.filter((proc) => {
|
||||
return proc.memory > MEM_MIN_SHOW && proc.cmd.includes('node') == false
|
||||
})
|
||||
|
||||
sys_infos.processes.mem_sorted.forEach((proc) => {
|
||||
var cpu = `${UxHelpers.colorizedMetric(proc.cpu, 40, 70, '%')}`
|
||||
var mem = `${UxHelpers.colorizedMetric(proc.memory, 40, 70, '%')}`
|
||||
var cmd = proc.cmd
|
||||
// if (proc.cmd.length > 50)
|
||||
// cmd = '…' + proc.cmd.slice(proc.cmd.length - 48, proc.cmd.length)
|
||||
sys_proc_table.push([chalk.bold.cyan(proc_id++), cmd, proc.pid, cpu, mem, proc.uid])
|
||||
})
|
||||
|
||||
if (sys_infos.processes.cpu_sorted.length >= 1 || sys_infos.processes.mem_sorted.length >= 1) {
|
||||
console.log(chalk.bold('Intensive Processes'))
|
||||
console.log(sys_proc_table.toString())
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sys info line
|
||||
*/
|
||||
function miniMonitBar(sys_infos) {
|
||||
let sys_metrics = sys_infos.pm2_env.axm_monitor
|
||||
|
||||
let cpu = sys_metrics['CPU Usage']
|
||||
|
||||
if (typeof(cpu) == 'undefined') return
|
||||
|
||||
var sys_summary_line = `${chalk.bold.cyan('host metrics')} `
|
||||
sys_summary_line += `| ${chalk.bold('cpu')}: ${UxHelpers.colorizedMetric(cpu.value, 40, 70, '%')}`
|
||||
|
||||
let temp = sys_metrics['CPU Temperature'].value
|
||||
if (temp && temp != '-1') {
|
||||
sys_summary_line += ` ${UxHelpers.colorizedMetric(temp, 50, 70, 'º')}`
|
||||
}
|
||||
|
||||
let mem_total = sys_metrics['RAM Total'].value
|
||||
let mem_available = sys_metrics['RAM Available'].value
|
||||
|
||||
if (mem_total) {
|
||||
var perc_mem_usage = (((mem_available) / mem_total) * 100).toFixed(1)
|
||||
sys_summary_line += ` | ${chalk.bold('mem free')}: ${UxHelpers.colorizedMetric(perc_mem_usage, 30, 10, '%')} `
|
||||
}
|
||||
|
||||
let interfaces = Object.keys(sys_metrics).filter(m => m.includes('net') && m != 'net:default').map(i => i.split(':')[2]).filter((iface, i, self) => self.indexOf(iface) === i)
|
||||
|
||||
interfaces.forEach(iface => {
|
||||
if (!sys_metrics[`net:rx_5:${iface}`]) return
|
||||
sys_summary_line += `| ${chalk.bold(iface)}: `
|
||||
sys_summary_line += `⇓ ${UxHelpers.colorizedMetric(sys_metrics[`net:rx_5:${iface}`].value, 10, 20, 'mb/s')} `
|
||||
sys_summary_line += `⇑ ${UxHelpers.colorizedMetric(sys_metrics[`net:tx_5:${iface}`].value, 10, 20, 'mb/s')} `
|
||||
})
|
||||
|
||||
if (CONDENSED_MODE == false) {
|
||||
let read = sys_metrics['Disk Reads'].value
|
||||
let write = sys_metrics['Disk Writes'].value
|
||||
|
||||
sys_summary_line += `| ${chalk.bold('disk')}: ⇓ ${UxHelpers.colorizedMetric(read, 10, 20, 'mb/s')}`
|
||||
sys_summary_line += ` ⇑ ${UxHelpers.colorizedMetric(write, 10, 20, 'mb/s')} `
|
||||
|
||||
let disks = Object.keys(sys_metrics).filter(m => m.includes('fs:')).map(i => i.split(':')[2]).filter((iface, i, self) => self.indexOf(iface) === i)
|
||||
var disk_nb = 0
|
||||
|
||||
disks.forEach(fs => {
|
||||
let use = sys_metrics[`fs:use:${fs}`].value
|
||||
if (use > 60)
|
||||
sys_summary_line += `${chalk.grey(fs)} ${UxHelpers.colorizedMetric(use, 80, 90, '%')} `
|
||||
})
|
||||
}
|
||||
|
||||
sys_summary_line += '|'
|
||||
console.log(sys_summary_line)
|
||||
}
|
||||
|
||||
/**
|
||||
* pm2 ls
|
||||
* @method dispAsTable
|
||||
* @param {Object} list
|
||||
* @param {Object} system informations (via pm2 sysmonit/pm2 sysinfos)
|
||||
*/
|
||||
module.exports = function(list, commander) {
|
||||
var pm2_conf = Configuration.getSync('pm2')
|
||||
|
||||
if (!list)
|
||||
return console.log('list empty')
|
||||
|
||||
listModulesAndAppsManaged(list, commander)
|
||||
|
||||
let sysmonit = list.filter(proc => proc.name == 'pm2-sysmonit')
|
||||
if (sysmonit && sysmonit[0])
|
||||
miniMonitBar(sysmonit[0])
|
||||
|
||||
checkIfProcessAreDumped(list)
|
||||
}
|
||||
382
api.hyungi.net/node_modules/pm2/lib/API/Version.js
generated
vendored
Normal file
382
api.hyungi.net/node_modules/pm2/lib/API/Version.js
generated
vendored
Normal file
@@ -0,0 +1,382 @@
|
||||
|
||||
var cst = require('../../constants.js');
|
||||
var Common = require('../Common.js');
|
||||
var fs = require('fs');
|
||||
var eachSeries = require('async/eachSeries');
|
||||
var child = require('child_process');
|
||||
|
||||
var printError = Common.printError;
|
||||
var printOut = Common.printOut;
|
||||
|
||||
module.exports = function(CLI) {
|
||||
|
||||
var EXEC_TIMEOUT = 60000; // Default: 1 min
|
||||
|
||||
CLI.prototype._pull = function(opts, cb) {
|
||||
var that = this;
|
||||
|
||||
var process_name = opts.process_name;
|
||||
var reload_type = opts.action;
|
||||
|
||||
printOut(cst.PREFIX_MSG + 'Updating repository for process name %s', process_name);
|
||||
|
||||
that.Client.getProcessByNameOrId(process_name, function (err, processes) {
|
||||
|
||||
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) {
|
||||
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);
|
||||
}
|
||||
require('vizion').update({
|
||||
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) {
|
||||
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) {
|
||||
printError(err);
|
||||
return cb ? cb({msg: meta.output + err}) : that.exitCli(cst.ERROR_EXIT);
|
||||
}
|
||||
else {
|
||||
printOut(cst.PREFIX_MSG + 'Process successfully updated %s', process_name);
|
||||
printOut(cst.PREFIX_MSG + 'Current commit %s', meta.current_revision);
|
||||
return that[reload_type](process_name, function(err, procs) {
|
||||
if (err && cb) return cb(err);
|
||||
if (err) console.error(err);
|
||||
return cb ? cb(null, meta.output + res) : that.exitCli(cst.SUCCESS_EXIT);
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
else {
|
||||
printOut(cst.PREFIX_MSG + 'Already up-to-date or an error occured for app: %s', process_name);
|
||||
return cb ? cb({success:false, msg : 'Already up to date'}) : that.exitCli(cst.SUCCESS_EXIT);
|
||||
}
|
||||
return false;
|
||||
});
|
||||
return false;
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* CLI method for updating a repository to a specific commit id
|
||||
* @method pullCommitId
|
||||
* @param {string} process_name
|
||||
* @param {string} commit_id
|
||||
* @return
|
||||
*/
|
||||
CLI.prototype.pullCommitId = function(process_name, commit_id, cb) {
|
||||
var reload_type = 'reload';
|
||||
var that = this;
|
||||
|
||||
printOut(cst.PREFIX_MSG + 'Updating repository for process name %s', process_name);
|
||||
|
||||
that.Client.getProcessByNameOrId(process_name, function (err, processes) {
|
||||
|
||||
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) {
|
||||
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);
|
||||
require('vizion').revertTo(
|
||||
{revision: commit_id,
|
||||
folder: proc.pm2_env.versioning.repo_path},
|
||||
function(err2, meta2) {
|
||||
if (!err2 && meta2.success) {
|
||||
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)
|
||||
{
|
||||
printError(err);
|
||||
return cb ? cb({msg:err}) : that.exitCli(cst.ERROR_EXIT);
|
||||
}
|
||||
else {
|
||||
printOut(cst.PREFIX_MSG + 'Process successfully updated %s', process_name);
|
||||
printOut(cst.PREFIX_MSG + 'Current commit %s', commit_id);
|
||||
return that[reload_type](process_name, cb);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
else {
|
||||
printOut(cst.PREFIX_MSG + 'Already up-to-date or an error occured: %s', process_name);
|
||||
return cb ? cb(null, {success:meta.success}) : that.exitCli(cst.SUCCESS_EXIT);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
else {
|
||||
printOut(cst.PREFIX_MSG + 'No versioning system found for process %s', process_name);
|
||||
return cb ? cb(null, {success:false}) : that.exitCli(cst.SUCCESS_EXIT);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* CLI method for downgrading a repository to the previous commit (older)
|
||||
* @method backward
|
||||
* @param {string} process_name
|
||||
* @return
|
||||
*/
|
||||
CLI.prototype.backward = function(process_name, cb) {
|
||||
var that = this;
|
||||
printOut(cst.PREFIX_MSG + 'Downgrading to previous commit repository for process name %s', process_name);
|
||||
|
||||
that.Client.getProcessByNameOrId(process_name, function (err, processes) {
|
||||
|
||||
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'});
|
||||
|
||||
require('vizion').prev({
|
||||
folder: proc.pm2_env.versioning.repo_path
|
||||
}, function(err, meta) {
|
||||
if (err)
|
||||
return cb ? cb({msg:err, data : meta}) : that.exitCli(cst.ERROR_EXIT);
|
||||
|
||||
if (meta.success !== true) {
|
||||
printOut(cst.PREFIX_MSG + 'No versioning system found for process %s', process_name);
|
||||
return cb ? cb({msg:err, data : meta}) : that.exitCli(cst.ERROR_EXIT);
|
||||
}
|
||||
|
||||
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) {
|
||||
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);
|
||||
});
|
||||
return false;
|
||||
}
|
||||
|
||||
printOut(cst.PREFIX_MSG + 'Process successfully updated %s', process_name);
|
||||
printOut(cst.PREFIX_MSG + 'Current commit %s', meta.current_revision);
|
||||
that.reload(process_name, function(err, procs) {
|
||||
if (err) return cb(err);
|
||||
return cb ? cb(null, meta.output + res) : that.exitCli(cst.SUCCESS_EXIT);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* CLI method for updating a repository to the next commit (more recent)
|
||||
* @method forward
|
||||
* @param {string} process_name
|
||||
* @return
|
||||
*/
|
||||
CLI.prototype.forward = function(process_name, cb) {
|
||||
var that = this;
|
||||
printOut(cst.PREFIX_MSG + 'Updating to next commit repository for process name %s', process_name);
|
||||
|
||||
that.Client.getProcessByNameOrId(process_name, function (err, processes) {
|
||||
|
||||
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) {
|
||||
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) {
|
||||
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)
|
||||
{
|
||||
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);
|
||||
});
|
||||
}
|
||||
else {
|
||||
printOut(cst.PREFIX_MSG + 'Process successfully updated %s', process_name);
|
||||
printOut(cst.PREFIX_MSG + 'Current commit %s', meta.current_revision);
|
||||
that.reload(process_name, function(err, procs) {
|
||||
if (err) return cb(err);
|
||||
return cb ? cb(null, meta.output + res) : that.exitCli(cst.SUCCESS_EXIT);
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
else {
|
||||
printOut(cst.PREFIX_MSG + 'Already up-to-date or an error occured: %s', process_name);
|
||||
return cb ? cb(null, {success:meta.success}) : that.exitCli(cst.SUCCESS_EXIT);
|
||||
}
|
||||
});
|
||||
}
|
||||
else {
|
||||
printOut(cst.PREFIX_MSG + 'No versioning system found for process %s', process_name);
|
||||
return cb ? cb({success:false, msg: 'No versioning system found'}) : that.exitCli(cst.SUCCESS_EXIT);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
var exec = function (cmd, callback) {
|
||||
var output = '';
|
||||
|
||||
var c = child.exec(cmd, {
|
||||
env: process.env,
|
||||
maxBuffer: 3*1024*1024,
|
||||
timeout: EXEC_TIMEOUT
|
||||
}, function(err) {
|
||||
if (callback)
|
||||
callback(err ? err.code : 0, output);
|
||||
});
|
||||
|
||||
c.stdout.on('data', function(data) {
|
||||
output += data;
|
||||
});
|
||||
|
||||
c.stderr.on('data', function(data) {
|
||||
output += data;
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
*
|
||||
* @method execCommands
|
||||
* @param {string} repo_path
|
||||
* @param {object} command_list
|
||||
* @return
|
||||
*/
|
||||
var execCommands = function(repo_path, command_list, cb) {
|
||||
var stdout = '';
|
||||
|
||||
eachSeries(command_list, function(command, callback) {
|
||||
stdout += '\n' + command;
|
||||
exec('cd '+repo_path+';'+command,
|
||||
function(code, output) {
|
||||
stdout += '\n' + output;
|
||||
if (code === 0)
|
||||
callback();
|
||||
else
|
||||
callback('`'+command+'` failed');
|
||||
});
|
||||
}, function(err) {
|
||||
if (err)
|
||||
return cb(stdout + '\n' + err);
|
||||
return cb(null, stdout);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Description Search process.json for post-update commands
|
||||
* @method getPostUpdateCmds
|
||||
* @param {string} repo_path
|
||||
* @param {string} proc_name
|
||||
* @return
|
||||
*/
|
||||
var getPostUpdateCmds = function(repo_path, proc_name, cb) {
|
||||
if (typeof repo_path !== 'string')
|
||||
return cb([]);
|
||||
if (repo_path[repo_path.length - 1] !== '/')
|
||||
repo_path += '/';
|
||||
|
||||
var searchForCommands = function(file, callback) {
|
||||
fs.exists(repo_path+file, function(exists) {
|
||||
if (exists) {
|
||||
try {
|
||||
var conf_string = fs.readFileSync(repo_path + file);
|
||||
var data = Common.parseConfig(conf_string, repo_path + file);
|
||||
} catch (e) {
|
||||
console.error(e.message || e);
|
||||
}
|
||||
|
||||
if (data && data.apps) {
|
||||
eachSeries(data.apps, function(item, callb) {
|
||||
if (item.name && item.name === proc_name) {
|
||||
if (item.post_update && typeof(item.post_update) === 'object') {
|
||||
if (item.exec_timeout)
|
||||
EXEC_TIMEOUT = parseInt(item.exec_timeout);
|
||||
return callb(item.post_update);
|
||||
}
|
||||
else {
|
||||
return callb();
|
||||
}
|
||||
}
|
||||
else
|
||||
return callb();
|
||||
}, function(final) {
|
||||
return callback(final);
|
||||
});
|
||||
}
|
||||
else {
|
||||
return callback();
|
||||
}
|
||||
}
|
||||
else {
|
||||
return callback();
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
eachSeries(['ecosystem.json', 'process.json', 'package.json'], searchForCommands,
|
||||
function(final) {
|
||||
return cb(final ? final : []);
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* CLI method for updating a repository
|
||||
* @method pullAndRestart
|
||||
* @param {string} process_name name of processes to pull
|
||||
* @return
|
||||
*/
|
||||
CLI.prototype.pullAndRestart = function (process_name, cb) {
|
||||
this._pull({process_name: process_name, action: 'reload'}, cb);
|
||||
};
|
||||
|
||||
/**
|
||||
* CLI method for updating a repository
|
||||
* @method pullAndReload
|
||||
* @param {string} process_name name of processes to pull
|
||||
* @return
|
||||
*/
|
||||
CLI.prototype.pullAndReload = function (process_name, cb) {
|
||||
this._pull({process_name: process_name, action: 'reload'}, cb);
|
||||
};
|
||||
|
||||
/**
|
||||
* CLI method for updating a repository to a specific commit id
|
||||
* @method pullCommitId
|
||||
* @param {object} opts
|
||||
* @return
|
||||
*/
|
||||
CLI.prototype._pullCommitId = function (opts, cb) {
|
||||
this.pullCommitId(opts.pm2_name, opts.commit_id, cb);
|
||||
};
|
||||
|
||||
}
|
||||
12
api.hyungi.net/node_modules/pm2/lib/API/interpreter.json
generated
vendored
Normal file
12
api.hyungi.net/node_modules/pm2/lib/API/interpreter.json
generated
vendored
Normal file
@@ -0,0 +1,12 @@
|
||||
{
|
||||
".sh" : "bash",
|
||||
".py" : "python",
|
||||
".rb" : "ruby",
|
||||
".php" : "php",
|
||||
".pl" : "perl",
|
||||
".js" : "node",
|
||||
".coffee" : "coffee",
|
||||
".ls" : "lsc",
|
||||
".ts" : "bun",
|
||||
".tsx" : "bun"
|
||||
}
|
||||
372
api.hyungi.net/node_modules/pm2/lib/API/pm2-plus/PM2IO.js
generated
vendored
Normal file
372
api.hyungi.net/node_modules/pm2/lib/API/pm2-plus/PM2IO.js
generated
vendored
Normal file
@@ -0,0 +1,372 @@
|
||||
'use strict'
|
||||
|
||||
var cst = require('../../../constants.js');
|
||||
const chalk = require('chalk');
|
||||
const path = require('path');
|
||||
const fs = require('fs');
|
||||
const Table = require('cli-tableau');
|
||||
const pkg = require('../../../package.json')
|
||||
const IOAPI = require('@pm2/js-api')
|
||||
const promptly = require('promptly')
|
||||
var CLIStrategy = require('./auth-strategies/CliAuth')
|
||||
var WebStrategy = require('./auth-strategies/WebAuth')
|
||||
const exec = require('child_process').exec
|
||||
|
||||
const OAUTH_CLIENT_ID_WEB = '138558311'
|
||||
const OAUTH_CLIENT_ID_CLI = '0943857435'
|
||||
|
||||
module.exports = class PM2ioHandler {
|
||||
|
||||
static usePM2Client (instance) {
|
||||
this.pm2 = instance
|
||||
}
|
||||
|
||||
static strategy () {
|
||||
switch (process.platform) {
|
||||
case 'darwin': {
|
||||
return new WebStrategy({
|
||||
client_id: OAUTH_CLIENT_ID_WEB
|
||||
})
|
||||
}
|
||||
case 'win32': {
|
||||
return new WebStrategy({
|
||||
client_id: OAUTH_CLIENT_ID_WEB
|
||||
})
|
||||
}
|
||||
case 'linux': {
|
||||
const isDesktop = process.env.XDG_CURRENT_DESKTOP || process.env.XDG_SESSION_DESKTOP || process.env.DISPLAY
|
||||
const isSSH = process.env.SSH_TTY || process.env.SSH_CONNECTION
|
||||
if (isDesktop && !isSSH) {
|
||||
return new WebStrategy({
|
||||
client_id: OAUTH_CLIENT_ID_WEB
|
||||
})
|
||||
} else {
|
||||
return new CLIStrategy({
|
||||
client_id: OAUTH_CLIENT_ID_CLI
|
||||
})
|
||||
}
|
||||
}
|
||||
default: {
|
||||
return new CLIStrategy({
|
||||
client_id: OAUTH_CLIENT_ID_CLI
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static init () {
|
||||
this._strategy = this.strategy()
|
||||
/**
|
||||
* If you are using a local backend you should give those options :
|
||||
* {
|
||||
* services: {
|
||||
* API: 'http://localhost:3000',
|
||||
* OAUTH: 'http://localhost:3100'
|
||||
* }
|
||||
* }
|
||||
*/
|
||||
this.io = new IOAPI().use(this._strategy)
|
||||
}
|
||||
|
||||
static launch (command, opts) {
|
||||
// first init the strategy and the io client
|
||||
this.init()
|
||||
|
||||
switch (command) {
|
||||
case 'connect' :
|
||||
case 'login' :
|
||||
case 'register' :
|
||||
case undefined :
|
||||
case 'authenticate' : {
|
||||
this.authenticate()
|
||||
break
|
||||
}
|
||||
case 'validate' : {
|
||||
this.validateAccount(opts)
|
||||
break
|
||||
}
|
||||
case 'help' :
|
||||
case 'welcome': {
|
||||
var dt = fs.readFileSync(path.join(__dirname, './pres/welcome'));
|
||||
console.log(dt.toString());
|
||||
return process.exit(0)
|
||||
}
|
||||
case 'logout': {
|
||||
this._strategy.isAuthenticated().then(isConnected => {
|
||||
// try to kill the agent anyway
|
||||
this.pm2.killAgent(err => {})
|
||||
|
||||
if (isConnected === false) {
|
||||
console.log(`${cst.PM2_IO_MSG} Already disconnected`)
|
||||
return process.exit(0)
|
||||
}
|
||||
|
||||
this._strategy._retrieveTokens((err, tokens) => {
|
||||
if (err) {
|
||||
console.log(`${cst.PM2_IO_MSG} Successfully disconnected`)
|
||||
return process.exit(0)
|
||||
}
|
||||
this._strategy.deleteTokens(this.io).then(_ => {
|
||||
console.log(`${cst.PM2_IO_MSG} Successfully disconnected`)
|
||||
return process.exit(0)
|
||||
}).catch(err => {
|
||||
console.log(`${cst.PM2_IO_MSG_ERR} Unexpected error: ${err.message}`)
|
||||
return process.exit(1)
|
||||
})
|
||||
})
|
||||
}).catch(err => {
|
||||
console.error(`${cst.PM2_IO_MSG_ERR} Failed to logout: ${err.message}`)
|
||||
console.error(`${cst.PM2_IO_MSG_ERR} You can also contact us to get help: contact@pm2.io`)
|
||||
})
|
||||
break
|
||||
}
|
||||
case 'create': {
|
||||
this._strategy.isAuthenticated().then(res => {
|
||||
// if the user isn't authenticated, we make them do the whole flow
|
||||
if (res !== true) {
|
||||
this.authenticate()
|
||||
} else {
|
||||
this.createBucket(this.createBucketHandler.bind(this))
|
||||
}
|
||||
}).catch(err => {
|
||||
console.error(`${cst.PM2_IO_MSG_ERR} Failed to create to the bucket: ${err.message}`)
|
||||
console.error(`${cst.PM2_IO_MSG_ERR} You can also contact us to get help: contact@pm2.io`)
|
||||
})
|
||||
break
|
||||
}
|
||||
case 'web': {
|
||||
this._strategy.isAuthenticated().then(res => {
|
||||
// if the user isn't authenticated, we make them do the whole flow
|
||||
if (res === false) {
|
||||
console.error(`${cst.PM2_IO_MSG_ERR} You need to be authenticated to do that, please use: pm2 plus login`)
|
||||
return process.exit(1)
|
||||
}
|
||||
this._strategy._retrieveTokens(() => {
|
||||
return this.openUI()
|
||||
})
|
||||
}).catch(err => {
|
||||
console.error(`${cst.PM2_IO_MSG_ERR} Failed to open the UI: ${err.message}`)
|
||||
console.error(`${cst.PM2_IO_MSG_ERR} You can also contact us to get help: contact@pm2.io`)
|
||||
})
|
||||
break
|
||||
}
|
||||
default : {
|
||||
console.log(`${cst.PM2_IO_MSG_ERR} Invalid command ${command}, available : login,register,validate,connect or web`)
|
||||
process.exit(1)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static openUI () {
|
||||
this.io.bucket.retrieveAll().then(res => {
|
||||
const buckets = res.data
|
||||
|
||||
if (buckets.length === 0) {
|
||||
return this.createBucket((err, bucket) => {
|
||||
if (err) {
|
||||
console.error(`${cst.PM2_IO_MSG_ERR} Failed to connect to the bucket: ${err.message}`)
|
||||
if (bucket) {
|
||||
console.error(`${cst.PM2_IO_MSG_ERR} You can retry using: pm2 plus link ${bucket.secret_id} ${bucket.public_id}`)
|
||||
}
|
||||
console.error(`${cst.PM2_IO_MSG_ERR} You can also contact us to get help: contact@pm2.io`)
|
||||
return process.exit(0)
|
||||
}
|
||||
const targetURL = `https://app.pm2.io/#/bucket/${bucket._id}`
|
||||
console.log(`${cst.PM2_IO_MSG} Please follow the popup or go to this URL :`, '\n', ' ', targetURL)
|
||||
this.open(targetURL)
|
||||
return process.exit(0)
|
||||
})
|
||||
}
|
||||
|
||||
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())
|
||||
console.log(`${cst.PM2_IO_MSG} If you don't want to open the UI to a bucket, type 'none'`)
|
||||
|
||||
const choices = buckets.map(bucket => bucket.name)
|
||||
choices.push('none')
|
||||
|
||||
promptly.choose(`${cst.PM2_IO_MSG} Type the name of the bucket you want to connect to :`, choices, (err, value) => {
|
||||
if (value === 'none') process.exit(0)
|
||||
|
||||
const bucket = buckets.find(bucket => bucket.name === value)
|
||||
if (bucket === undefined) return process.exit(0)
|
||||
|
||||
const targetURL = `https://app.pm2.io/#/bucket/${bucket._id}`
|
||||
console.log(`${cst.PM2_IO_MSG} Please follow the popup or go to this URL :`, '\n', ' ', targetURL)
|
||||
this.open(targetURL)
|
||||
return process.exit(0)
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
static validateAccount (token) {
|
||||
this.io.auth.validEmail(token)
|
||||
.then(res => {
|
||||
console.log(`${cst.PM2_IO_MSG} Email succesfully validated.`)
|
||||
console.log(`${cst.PM2_IO_MSG} You can now proceed and use: pm2 plus connect`)
|
||||
return process.exit(0)
|
||||
}).catch(err => {
|
||||
if (err.status === 401) {
|
||||
console.error(`${cst.PM2_IO_MSG_ERR} Invalid token`)
|
||||
return process.exit(1)
|
||||
} else if (err.status === 301) {
|
||||
console.log(`${cst.PM2_IO_MSG} Email succesfully validated.`)
|
||||
console.log(`${cst.PM2_IO_MSG} You can now proceed and use: pm2 plus connect`)
|
||||
return process.exit(0)
|
||||
}
|
||||
const msg = err.data ? err.data.error_description || err.data.msg : err.message
|
||||
console.error(`${cst.PM2_IO_MSG_ERR} Failed to validate your email: ${msg}`)
|
||||
console.error(`${cst.PM2_IO_MSG_ERR} You can also contact us to get help: contact@pm2.io`)
|
||||
return process.exit(1)
|
||||
})
|
||||
}
|
||||
|
||||
static createBucketHandler (err, bucket) {
|
||||
if (err) {
|
||||
console.trace(`${cst.PM2_IO_MSG_ERR} Failed to connect to the bucket: ${err.message}`)
|
||||
if (bucket) {
|
||||
console.error(`${cst.PM2_IO_MSG_ERR} You can retry using: pm2 plus link ${bucket.secret_id} ${bucket.public_id}`)
|
||||
}
|
||||
console.error(`${cst.PM2_IO_MSG_ERR} You can also contact us to get help: contact@pm2.io`)
|
||||
return process.exit(0)
|
||||
}
|
||||
if (bucket === undefined) {
|
||||
return process.exit(0)
|
||||
}
|
||||
console.log(`${cst.PM2_IO_MSG} Successfully connected to bucket ${bucket.name}`)
|
||||
var targetURL = `https://app.pm2.io/#/bucket/${bucket._id}`
|
||||
console.log(`${cst.PM2_IO_MSG} You can use the web interface over there: ${targetURL}`)
|
||||
this.open(targetURL)
|
||||
return process.exit(0)
|
||||
}
|
||||
|
||||
static createBucket (cb) {
|
||||
console.log(`${cst.PM2_IO_MSG} By default we allow you to trial PM2 Plus for 14 days without any credit card.`)
|
||||
|
||||
this.io.bucket.create({
|
||||
name: 'PM2 Plus Monitoring'
|
||||
}).then(res => {
|
||||
const bucket = res.data.bucket
|
||||
|
||||
console.log(`${cst.PM2_IO_MSG} Successfully created the bucket`)
|
||||
this.pm2.link({
|
||||
public_key: bucket.public_id,
|
||||
secret_key: bucket.secret_id,
|
||||
pm2_version: pkg.version
|
||||
}, (err) => {
|
||||
if (err) {
|
||||
return cb(new Error('Failed to connect your local PM2 to your bucket'), bucket)
|
||||
} else {
|
||||
return cb(null, bucket)
|
||||
}
|
||||
})
|
||||
}).catch(err => {
|
||||
return cb(new Error(`Failed to create a bucket: ${err.message}`))
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* Connect the local agent to a specific bucket
|
||||
* @param {Function} cb
|
||||
*/
|
||||
static connectToBucket (cb) {
|
||||
this.io.bucket.retrieveAll().then(res => {
|
||||
const buckets = res.data
|
||||
|
||||
if (buckets.length === 0) {
|
||||
return this.createBucket(cb)
|
||||
}
|
||||
|
||||
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.payment.offer_type])
|
||||
})
|
||||
console.log(table.toString())
|
||||
console.log(`${cst.PM2_IO_MSG} If you don't want to connect to a bucket, type 'none'`)
|
||||
|
||||
const choices = buckets.map(bucket => bucket.name)
|
||||
choices.push('none')
|
||||
|
||||
promptly.choose(`${cst.PM2_IO_MSG} Type the name of the bucket you want to connect to :`, choices, (err, value) => {
|
||||
if (value === 'none') return cb()
|
||||
|
||||
const bucket = buckets.find(bucket => bucket.name === value)
|
||||
if (bucket === undefined) return cb()
|
||||
this.pm2.link({
|
||||
public_key: bucket.public_id,
|
||||
secret_key: bucket.secret_id,
|
||||
pm2_version: pkg.version
|
||||
}, (err) => {
|
||||
return err ? cb(err) : cb(null, bucket)
|
||||
})
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* Authenticate the user with either of the strategy
|
||||
* @param {Function} cb
|
||||
*/
|
||||
static authenticate () {
|
||||
this._strategy._retrieveTokens((err, tokens) => {
|
||||
if (err) {
|
||||
const msg = err.data ? err.data.error_description || err.data.msg : err.message
|
||||
console.log(`${cst.PM2_IO_MSG_ERR} Unexpected error : ${msg}`)
|
||||
return process.exit(1)
|
||||
}
|
||||
console.log(`${cst.PM2_IO_MSG} Successfully authenticated`)
|
||||
this.io.user.retrieve().then(res => {
|
||||
const user = res.data
|
||||
|
||||
this.io.user.retrieve().then(res => {
|
||||
const tmpUser = res.data
|
||||
console.log(`${cst.PM2_IO_MSG} Successfully validated`)
|
||||
this.connectToBucket(this.createBucketHandler.bind(this))
|
||||
})
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
static 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)
|
||||
}
|
||||
}
|
||||
288
api.hyungi.net/node_modules/pm2/lib/API/pm2-plus/auth-strategies/CliAuth.js
generated
vendored
Normal file
288
api.hyungi.net/node_modules/pm2/lib/API/pm2-plus/auth-strategies/CliAuth.js
generated
vendored
Normal file
@@ -0,0 +1,288 @@
|
||||
'use strict'
|
||||
|
||||
const AuthStrategy = require('@pm2/js-api/src/auth_strategies/strategy')
|
||||
const querystring = require('querystring');
|
||||
|
||||
const http = require('http')
|
||||
const fs = require('fs')
|
||||
const url = require('url')
|
||||
const exec = require('child_process').exec
|
||||
const tryEach = require('async/tryEach')
|
||||
const path = require('path')
|
||||
const os = require('os')
|
||||
const needle = require('needle')
|
||||
const chalk = require('chalk')
|
||||
const cst = require('../../../../constants.js')
|
||||
const promptly = require('promptly')
|
||||
|
||||
module.exports = class CliStrategy 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://id.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
|
||||
|
||||
tryEach([
|
||||
// try to find the token via the environment
|
||||
(next) => {
|
||||
if (!process.env.PM2_IO_TOKEN) {
|
||||
return next(new Error('No token in env'))
|
||||
}
|
||||
this.verifyToken(process.env.PM2_IO_TOKEN)
|
||||
.then((res) => {
|
||||
return next(null, res.data)
|
||||
}).catch(next)
|
||||
},
|
||||
// try to find it in the file system
|
||||
(next) => {
|
||||
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.authenticate((err, data) => {
|
||||
if (err instanceof Error) return next(err)
|
||||
// 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)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
authenticate (cb) {
|
||||
console.log(`${cst.PM2_IO_MSG} Using non-browser authentication.`)
|
||||
promptly.confirm(`${cst.PM2_IO_MSG} Do you have a pm2.io account? (y/n)`, (err, answer) => {
|
||||
// Either login or register
|
||||
return answer === true ? this.login(cb) : this.register(cb)
|
||||
})
|
||||
}
|
||||
|
||||
login (cb) {
|
||||
let retry = () => {
|
||||
promptly.prompt(`${cst.PM2_IO_MSG} Your username or email: `, (err, username) => {
|
||||
if (err) return retry();
|
||||
|
||||
promptly.password(`${cst.PM2_IO_MSG} Your password: `, { replace : '*' }, (err, password) => {
|
||||
if (err) return retry();
|
||||
|
||||
console.log(`${cst.PM2_IO_MSG} Authenticating ...`)
|
||||
this._loginUser({
|
||||
username: username,
|
||||
password: password
|
||||
}, (err, data) => {
|
||||
if (err) {
|
||||
console.error(`${cst.PM2_IO_MSG_ERR} Failed to authenticate: ${err.message}`)
|
||||
return retry()
|
||||
}
|
||||
return cb(null, data)
|
||||
})
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
retry()
|
||||
}
|
||||
|
||||
register (cb) {
|
||||
console.log(`${cst.PM2_IO_MSG} No problem ! We just need few informations to create your account`)
|
||||
|
||||
var retry = () => {
|
||||
promptly.prompt(`${cst.PM2_IO_MSG} Please choose an username :`, {
|
||||
validator : this._validateUsername,
|
||||
retry : true
|
||||
}, (err, username) => {
|
||||
promptly.prompt(`${cst.PM2_IO_MSG} Please choose an email :`, {
|
||||
validator : this._validateEmail,
|
||||
retry : true
|
||||
},(err, email) => {
|
||||
promptly.password(`${cst.PM2_IO_MSG} Please choose a password :`, { replace : '*' }, (err, password) => {
|
||||
promptly.confirm(`${cst.PM2_IO_MSG} Do you accept the terms and privacy policy (https://pm2.io/legals/terms_conditions.pdf) ? (y/n)`, (err, answer) => {
|
||||
if (err) {
|
||||
console.error(chalk.bold.red(err));
|
||||
return retry()
|
||||
} else if (answer === false) {
|
||||
console.error(`${cst.PM2_IO_MSG_ERR} You must accept the terms and privacy policy to contiue.`)
|
||||
return retry()
|
||||
}
|
||||
|
||||
this._registerUser({
|
||||
email : email,
|
||||
password : password,
|
||||
username : username
|
||||
}, (err, data) => {
|
||||
console.log('\n')
|
||||
if (err) {
|
||||
console.error(`${cst.PM2_IO_MSG_ERR} Unexpect error: ${err.message}`)
|
||||
console.error(`${cst.PM2_IO_MSG_ERR} You can also contact us to get help: contact@pm2.io`)
|
||||
return process.exit(1)
|
||||
}
|
||||
return cb(undefined, data)
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
}
|
||||
retry()
|
||||
}
|
||||
|
||||
/**
|
||||
* Register function
|
||||
* @param opts.username
|
||||
* @param opts.password
|
||||
* @param opts.email
|
||||
*/
|
||||
_registerUser (opts, cb) {
|
||||
const data = Object.assign(opts, {
|
||||
password_confirmation: opts.password,
|
||||
accept_terms: true
|
||||
})
|
||||
needle.post(this.BASE_URI + '/api/oauth/register', data, {
|
||||
json: true,
|
||||
headers: {
|
||||
'X-Register-Provider': 'pm2-register',
|
||||
'x-client-id': this.client_id
|
||||
}
|
||||
}, function (err, res, body) {
|
||||
if (err) return cb(err)
|
||||
if (body.email && body.email.message) return cb(new Error(body.email.message))
|
||||
if (body.username && body.username.message) return cb(new Error(body.username.message))
|
||||
if (!body.access_token) return cb(new Error(body.msg))
|
||||
|
||||
return cb(null, {
|
||||
refresh_token : body.refresh_token.token,
|
||||
access_token : body.access_token.token
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
_loginUser (user_info, cb) {
|
||||
const URL_AUTH = '/api/oauth/authorize?response_type=token&scope=all&client_id=' +
|
||||
this.client_id + '&redirect_uri=http://localhost:43532';
|
||||
|
||||
needle.get(this.BASE_URI + URL_AUTH, (err, res) => {
|
||||
if (err) return cb(err);
|
||||
|
||||
var cookie = res.cookies;
|
||||
|
||||
needle.post(this.BASE_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']
|
||||
|
||||
needle.get(this.BASE_URI + location, {
|
||||
cookies : cookie
|
||||
}, (err, res) => {
|
||||
if (err) return cb(err);
|
||||
var refresh_token = querystring.parse(url.parse(res.headers.location).query).access_token;
|
||||
needle.post(this.BASE_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)
|
||||
return cb(null, body)
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
_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)
|
||||
})
|
||||
}
|
||||
}
|
||||
187
api.hyungi.net/node_modules/pm2/lib/API/pm2-plus/auth-strategies/WebAuth.js
generated
vendored
Normal file
187
api.hyungi.net/node_modules/pm2/lib/API/pm2-plus/auth-strategies/WebAuth.js
generated
vendored
Normal file
@@ -0,0 +1,187 @@
|
||||
|
||||
'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 tryEach = require('async/tryEach');
|
||||
|
||||
module.exports = class WebStrategy 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
|
||||
})
|
||||
}
|
||||
tryEach([
|
||||
// try to find the token via the environment
|
||||
(next) => {
|
||||
if (!process.env.PM2_IO_TOKEN) {
|
||||
return next(new Error('No token in env'))
|
||||
}
|
||||
verifyToken(process.env.PM2_IO_TOKEN)
|
||||
.then((res) => {
|
||||
return next(null, res.data)
|
||||
}).catch(next)
|
||||
},
|
||||
// try to find it in the file system
|
||||
(next) => {
|
||||
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(err => next(err))
|
||||
})
|
||||
}
|
||||
], (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) {
|
||||
const redirectURL = `${this.oauth_endpoint}${this.oauth_query}`
|
||||
|
||||
console.log(`${cst.PM2_IO_MSG} Please follow the popup or go to this URL :`, '\n', ' ', redirectURL)
|
||||
|
||||
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(`
|
||||
<head>
|
||||
<script>
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
<h2 style="text-align: center">
|
||||
You can go back to your terminal now :)
|
||||
</h2>
|
||||
</body>`)
|
||||
res.end()
|
||||
server.close()
|
||||
return cb(query)
|
||||
})
|
||||
server.listen(43532, () => {
|
||||
this.open(redirectURL)
|
||||
})
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
}
|
||||
97
api.hyungi.net/node_modules/pm2/lib/API/pm2-plus/helpers.js
generated
vendored
Normal file
97
api.hyungi.net/node_modules/pm2/lib/API/pm2-plus/helpers.js
generated
vendored
Normal file
@@ -0,0 +1,97 @@
|
||||
|
||||
var cst = require('../../../constants.js');
|
||||
var Common = require('../../Common.js');
|
||||
|
||||
const chalk = require('chalk');
|
||||
const forEach = require('async/forEach');
|
||||
const open = require('../../tools/open.js');
|
||||
const Modules = require('../Modules');
|
||||
|
||||
function processesAreAlreadyMonitored(CLI, cb) {
|
||||
CLI.Client.executeRemote('getMonitorData', {}, function(err, list) {
|
||||
if (err) return cb(false);
|
||||
var l = list.filter(l => l.pm2_env.km_link == true)
|
||||
var l2 = list.filter(l => l.name == 'pm2-server-monit')
|
||||
|
||||
return cb(l.length > 0 && l2.length > 0 ? true : false)
|
||||
})
|
||||
}
|
||||
|
||||
module.exports = function(CLI) {
|
||||
CLI.prototype.openDashboard = function() {
|
||||
if (!this.gl_interact_infos) {
|
||||
Common.printError(chalk.bold.white('Agent if offline, type `$ pm2 plus` to log in'));
|
||||
return this.exitCli(cst.ERROR_EXIT);
|
||||
}
|
||||
|
||||
var uri = `https://app.pm2.io/#/r/${this.gl_interact_infos.public_key}`
|
||||
console.log(cst.PM2_IO_MSG + ` Opening ${uri}`)
|
||||
open(uri);
|
||||
setTimeout(_ => {
|
||||
this.exitCli();
|
||||
}, 200);
|
||||
};
|
||||
|
||||
CLI.prototype.clearSetup = function (opts, cb) {
|
||||
const modules = ['event-loop-inspector']
|
||||
this.gl_is_km_linked = false
|
||||
|
||||
forEach(modules, (_module, next) => {
|
||||
Modules.uninstall(this, _module, () => {
|
||||
next()
|
||||
});
|
||||
}, (err) => {
|
||||
this.reload('all', () => {
|
||||
return cb()
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* Install required package and enable flags for current running processes
|
||||
*/
|
||||
CLI.prototype.minimumSetup = function (opts, cb) {
|
||||
var self = this;
|
||||
this.gl_is_km_linked = true
|
||||
|
||||
function install(cb) {
|
||||
var modules = []
|
||||
|
||||
if (opts.type === 'enterprise' || opts.type === 'plus') {
|
||||
modules = ['pm2-logrotate', 'pm2-server-monit']
|
||||
if (opts.type === 'enterprise') {
|
||||
modules.push('deep-metrics')
|
||||
}
|
||||
}
|
||||
|
||||
forEach(modules, (_module, next) => {
|
||||
Modules.install(self, _module, {}, () => {
|
||||
next()
|
||||
});
|
||||
}, (err) => {
|
||||
self.reload('all', () => {
|
||||
return cb()
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
processesAreAlreadyMonitored(self, (already_monitored) => {
|
||||
if (already_monitored) {
|
||||
console.log(cst.PM2_IO_MSG + ` PM2 ${opts.type || ''} bundle already installed`);
|
||||
return cb()
|
||||
}
|
||||
|
||||
if (opts.installAll)
|
||||
return install(cb)
|
||||
|
||||
// promptly.confirm(chalk.bold('Install all pm2 plus dependencies ? (y/n)'), (err, answer) => {
|
||||
// if (!err && answer === true)
|
||||
return install(cb)
|
||||
// self.reload('all', () => {
|
||||
// return cb()
|
||||
// })
|
||||
// });
|
||||
})
|
||||
}
|
||||
|
||||
}
|
||||
126
api.hyungi.net/node_modules/pm2/lib/API/pm2-plus/link.js
generated
vendored
Normal file
126
api.hyungi.net/node_modules/pm2/lib/API/pm2-plus/link.js
generated
vendored
Normal file
@@ -0,0 +1,126 @@
|
||||
|
||||
var cst = require('../../../constants.js');
|
||||
var Common = require('../../Common.js');
|
||||
var chalk = require('chalk');
|
||||
var fs = require('fs');
|
||||
var KMDaemon = require('@pm2/agent/src/InteractorClient');
|
||||
var pkg = require('../../../package.json')
|
||||
|
||||
module.exports = function(CLI) {
|
||||
|
||||
CLI.prototype.linkManagement = function(cmd, public_key, machine, opts, cb) {
|
||||
var that = this;
|
||||
|
||||
// pm2 link stop || kill
|
||||
if (cmd == 'stop' || cmd == 'kill') {
|
||||
that.gl_is_km_linked = false
|
||||
console.log(cst.PM2_IO_MSG + ' Stopping agent...');
|
||||
|
||||
return that.killAgent(function(err) {
|
||||
if (err) {
|
||||
Common.printError(err);
|
||||
return process.exit(cst.ERROR_EXIT);
|
||||
}
|
||||
console.log(cst.PM2_IO_MSG + ' Stopped');
|
||||
|
||||
that.reload('all', () => {
|
||||
return process.exit(cst.SUCCESS_EXIT);
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
// pm2 link info
|
||||
if (cmd == 'info') {
|
||||
console.log(cst.PM2_IO_MSG + ' Getting agent information...');
|
||||
that.agentInfos(function(err, infos) {
|
||||
if (err) {
|
||||
console.error(cst.PM2_IO_MSG_ERR + ' ' + err.message);
|
||||
return that.exitCli(cst.ERROR_EXIT);
|
||||
}
|
||||
console.log(infos);
|
||||
return that.exitCli(cst.SUCCESS_EXIT);
|
||||
});
|
||||
return false;
|
||||
}
|
||||
|
||||
// pm2 link delete
|
||||
if (cmd == 'delete') {
|
||||
that.gl_is_km_linked = false
|
||||
console.log(cst.PM2_IO_MSG + ' Permanently disable agent...');
|
||||
that.killAgent(function(err) {
|
||||
try {
|
||||
fs.unlinkSync(cst.INTERACTION_CONF);
|
||||
} catch(e) {
|
||||
console.log(cst.PM2_IO_MSG + ' No interaction config file found');
|
||||
return process.exit(cst.SUCCESS_EXIT);
|
||||
}
|
||||
console.log(cst.PM2_IO_MSG + ' Agent interaction ended');
|
||||
if (!cb)
|
||||
return process.exit(cst.SUCCESS_EXIT);
|
||||
return cb()
|
||||
});
|
||||
return false;
|
||||
}
|
||||
|
||||
if (cmd && !public_key) {
|
||||
console.error(cst.PM2_IO_MSG + ' Command [%s] unknown or missing public key', cmd);
|
||||
return process.exit(cst.ERROR_EXIT);
|
||||
}
|
||||
|
||||
// pm2 link xxx yyy
|
||||
var infos;
|
||||
|
||||
if (!cmd) {
|
||||
infos = null;
|
||||
}
|
||||
else
|
||||
infos = {
|
||||
public_key : public_key,
|
||||
secret_key : cmd,
|
||||
machine_name : machine,
|
||||
info_node : opts.infoNode || null,
|
||||
pm2_version: pkg.version
|
||||
}
|
||||
|
||||
that.link(infos, cb)
|
||||
};
|
||||
|
||||
CLI.prototype.link = function(infos, cb) {
|
||||
var that = this;
|
||||
|
||||
process.env.WS_JSON_PATCH = true
|
||||
|
||||
KMDaemon.launchAndInteract(cst, infos, function(err, dt) {
|
||||
if (err) {
|
||||
Common.printError(cst.PM2_IO_MSG + ' Run `$ pm2 plus` to connect')
|
||||
return that.exitCli(cst.ERROR_EXIT);
|
||||
}
|
||||
console.log(chalk.bold.green('[+] PM2+ activated!'))
|
||||
if (!cb) {
|
||||
return that.exitCli(cst.SUCCESS_EXIT);
|
||||
}
|
||||
return cb(null, dt)
|
||||
});
|
||||
};
|
||||
|
||||
CLI.prototype.agentInfos = function(cb) {
|
||||
KMDaemon.getInteractInfo(this._conf, function(err, data) {
|
||||
if (err)
|
||||
return cb(Common.retErr(err));
|
||||
return cb(null, data);
|
||||
});
|
||||
};
|
||||
|
||||
CLI.prototype.killAgent = function(cb) {
|
||||
var that = this;
|
||||
KMDaemon.killInteractorDaemon(that._conf, function(err) {
|
||||
if (err)
|
||||
return cb ? cb(Common.retErr(err)) : that.exitCli(cst.SUCCESS_EXIT);
|
||||
return cb ? cb(null) : that.exitCli(cst.SUCCESS_EXIT);
|
||||
});
|
||||
};
|
||||
|
||||
CLI.prototype.unlink = function(cb) {
|
||||
this.linkManagement('delete', cb);
|
||||
};
|
||||
};
|
||||
16
api.hyungi.net/node_modules/pm2/lib/API/pm2-plus/pres/motd
generated
vendored
Normal file
16
api.hyungi.net/node_modules/pm2/lib/API/pm2-plus/pres/motd
generated
vendored
Normal file
@@ -0,0 +1,16 @@
|
||||
|
||||
██████╗ ███╗ ███╗██████╗ ██╗ ██╗ ██████╗
|
||||
██╔══██╗████╗ ████║╚════██╗ ██║ ██╔╝██╔═══██╗
|
||||
██████╔╝██╔████╔██║ █████╔╝ ██║ ██╔╝ ██║ ██║
|
||||
██╔═══╝ ██║╚██╔╝██║██╔═══╝ ██║ ██╔╝ ██║ ██║
|
||||
██║ ██║ ╚═╝ ██║███████╗ ██║██╔╝ ╚██████╔╝
|
||||
╚═╝ ╚═╝ ╚═╝╚══════╝ ╚═╝╚═╝ ╚═════╝
|
||||
|
||||
https://pm2.io/
|
||||
|
||||
Harden your Node.js Production Environment
|
||||
|
||||
- Real-time Monitoring Web Interface
|
||||
- Pro Active Alerting System
|
||||
- Production Profiling for Memory and CPU
|
||||
- PM2 Runtime High Availability Fallback
|
||||
26
api.hyungi.net/node_modules/pm2/lib/API/pm2-plus/pres/motd.update
generated
vendored
Normal file
26
api.hyungi.net/node_modules/pm2/lib/API/pm2-plus/pres/motd.update
generated
vendored
Normal file
@@ -0,0 +1,26 @@
|
||||
|
||||
-------------
|
||||
|
||||
|
||||
██████╗ ███╗ ███╗██████╗ ██╗ ██╗ ██████╗
|
||||
██╔══██╗████╗ ████║╚════██╗ ██║ ██╔╝██╔═══██╗
|
||||
██████╔╝██╔████╔██║ █████╔╝ ██║ ██╔╝ ██║ ██║
|
||||
██╔═══╝ ██║╚██╔╝██║██╔═══╝ ██║ ██╔╝ ██║ ██║
|
||||
██║ ██║ ╚═╝ ██║███████╗ ██║██╔╝ ╚██████╔╝
|
||||
╚═╝ ╚═╝ ╚═╝╚══════╝ ╚═╝╚═╝ ╚═════╝
|
||||
|
||||
https://pm2.io/
|
||||
|
||||
Harden your Node.js Production Environment
|
||||
|
||||
- Real-time Monitoring Web Interface
|
||||
- Pro Active Alerting System
|
||||
- Production Profiling for Memory and CPU
|
||||
- PM2 Runtime High Availability Fallback
|
||||
|
||||
|
||||
Start using it by typing:
|
||||
|
||||
$ pm2 plus
|
||||
|
||||
-------------
|
||||
28
api.hyungi.net/node_modules/pm2/lib/API/pm2-plus/pres/welcome
generated
vendored
Normal file
28
api.hyungi.net/node_modules/pm2/lib/API/pm2-plus/pres/welcome
generated
vendored
Normal file
@@ -0,0 +1,28 @@
|
||||
|
||||
-------------
|
||||
|
||||
PM2 Plus Edition
|
||||
|
||||
|
||||
PM2 Plus is a monitoring dashboard
|
||||
specialized for Node.js Apps.
|
||||
|
||||
Create an account:
|
||||
$ pm2 plus register
|
||||
|
||||
Connect your local PM2 to the PM2 Plus servers:
|
||||
$ pm2 plus connect
|
||||
|
||||
See our UI with your own realtime dashboard:
|
||||
$ pm2 plus web
|
||||
|
||||
More details available there:
|
||||
http://pm2.io/plus
|
||||
|
||||
-------------
|
||||
|
||||
Having complex or specific needs?
|
||||
You can also checkout our enterprise offer at:
|
||||
http://pm2.io/enterprise
|
||||
|
||||
-------------
|
||||
52
api.hyungi.net/node_modules/pm2/lib/API/pm2-plus/process-selector.js
generated
vendored
Normal file
52
api.hyungi.net/node_modules/pm2/lib/API/pm2-plus/process-selector.js
generated
vendored
Normal file
@@ -0,0 +1,52 @@
|
||||
const fs = require('fs');
|
||||
const forEachLimit = require('async/forEachLimit');
|
||||
|
||||
var cst = require('../../../constants.js');
|
||||
var Common = require('../../Common.js');
|
||||
|
||||
module.exports = function(CLI) {
|
||||
/**
|
||||
* Monitor Selectively Processes (auto filter in interaction)
|
||||
* @param String state 'monitor' or 'unmonitor'
|
||||
* @param String target <pm_id|name|all>
|
||||
* @param Function cb callback
|
||||
*/
|
||||
CLI.prototype.monitorState = function(state, target, cb) {
|
||||
var that = this;
|
||||
|
||||
if (!target) {
|
||||
Common.printError(cst.PREFIX_MSG_ERR + 'Please specify an <app_name|pm_id>');
|
||||
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);
|
||||
}
|
||||
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);
|
||||
}
|
||||
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();
|
||||
});
|
||||
}
|
||||
};
|
||||
}
|
||||
375
api.hyungi.net/node_modules/pm2/lib/API/schema.json
generated
vendored
Normal file
375
api.hyungi.net/node_modules/pm2/lib/API/schema.json
generated
vendored
Normal file
@@ -0,0 +1,375 @@
|
||||
{
|
||||
"script": {
|
||||
"type": "string",
|
||||
"require": true,
|
||||
"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"
|
||||
},
|
||||
"name_prefix": {
|
||||
"type": "string"
|
||||
},
|
||||
"filter_env": {
|
||||
"type": [
|
||||
"boolean",
|
||||
"array",
|
||||
"string"
|
||||
],
|
||||
"docDefault": false,
|
||||
"docDescription": "Enable filtering global environments"
|
||||
},
|
||||
"namespace": {
|
||||
"type": "string",
|
||||
"docDefault": "default",
|
||||
"docDescription": "Process namespace"
|
||||
},
|
||||
"install_url": {
|
||||
"type": "string"
|
||||
},
|
||||
"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"],
|
||||
"docDescription": "Arguments to pass to the interpreter"
|
||||
},
|
||||
"out_file": {
|
||||
"type": "string",
|
||||
"alias": ["out", "output", "out_log"],
|
||||
"docDefault": "~/.pm2/logs/<app_name>-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/<app_name>-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 day.js format (eg YYYY-MM-DD HH:mm Z)"
|
||||
},
|
||||
"time": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"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 <env_name>"
|
||||
},
|
||||
"max_memory_restart": {
|
||||
"type": [
|
||||
"string",
|
||||
"number"
|
||||
],
|
||||
"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)",
|
||||
"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",
|
||||
"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"
|
||||
},
|
||||
"exp_backoff_restart_delay": {
|
||||
"type": "number",
|
||||
"docDefault": 0,
|
||||
"docDescription": "Restart 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"
|
||||
},
|
||||
"shutdown_with_message": {
|
||||
"type": "boolean",
|
||||
"docDefault": false,
|
||||
"docDescription": "Shutdown an application with process.send('shutdown') instead of process.kill(pid, 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",
|
||||
"number"
|
||||
],
|
||||
"alias": "cron",
|
||||
"docDescription": "A cron pattern to restart your app"
|
||||
},
|
||||
"merge_logs": {
|
||||
"type": "boolean",
|
||||
"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": {
|
||||
"type": "boolean",
|
||||
"default" : true,
|
||||
"docDefault" : "True",
|
||||
"docDescription": "Enable or disable the versioning metadatas (vizion library)"
|
||||
},
|
||||
"autostart": {
|
||||
"type": "boolean",
|
||||
"default": true,
|
||||
"docDefault": "True",
|
||||
"docDescription": "Enable or disable auto start when adding process"
|
||||
},
|
||||
"autorestart": {
|
||||
"type": "boolean",
|
||||
"default": true,
|
||||
"docDefault": "True",
|
||||
"docDescription": "Enable or disable auto restart after process failure"
|
||||
},
|
||||
"stop_exit_codes": {
|
||||
"type": [
|
||||
"array",
|
||||
"number"
|
||||
],
|
||||
"docDescription": "List of exit codes that should allow the process to stop (skip autorestart)."
|
||||
},
|
||||
"watch_delay": {
|
||||
"type": "number",
|
||||
"docDefault": "True",
|
||||
"docDescription": "Restart delay on file change detected"
|
||||
},
|
||||
"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",
|
||||
"docDescription": "Object that will be used as an options with chokidar (refer to chokidar documentation)"
|
||||
},
|
||||
"min_uptime": {
|
||||
"type": [
|
||||
"number",
|
||||
"string"
|
||||
],
|
||||
"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",
|
||||
"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,
|
||||
"docDefault": 16,
|
||||
"docDescription": "Number of times a script is restarted when it exits in less than min_uptime"
|
||||
},
|
||||
"execute_command": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"exec_mode": {
|
||||
"type": "string",
|
||||
"regex": "^(cluster|fork)(_mode)?$",
|
||||
"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",
|
||||
"docDefault": false,
|
||||
"docDescription": "Start a script even if it is already running (only the script path is considered)"
|
||||
},
|
||||
"append_env_to_name": {
|
||||
"type": "boolean",
|
||||
"docDefault": false,
|
||||
"docDescription": "Append the environment name to the app name"
|
||||
},
|
||||
"post_update": {
|
||||
"type": "array",
|
||||
"docDescription": "List of commands executed after a pull/upgrade operation performed from Keymetrics dashboard"
|
||||
},
|
||||
"trace": {
|
||||
"type": [
|
||||
"boolean"
|
||||
],
|
||||
"docDefault": false,
|
||||
"docDescription": "Enable or disable the transaction tracing"
|
||||
},
|
||||
"disable_trace": {
|
||||
"type": [
|
||||
"boolean"
|
||||
],
|
||||
"docDefault": true,
|
||||
"docDescription": "Enable or disable the transaction tracing"
|
||||
},
|
||||
"v8": {
|
||||
"type": [
|
||||
"boolean"
|
||||
]
|
||||
},
|
||||
"event_loop_inspector": {
|
||||
"type": [
|
||||
"boolean"
|
||||
]
|
||||
},
|
||||
"deep_monitoring": {
|
||||
"type": [
|
||||
"boolean"
|
||||
]
|
||||
},
|
||||
"increment_var": {
|
||||
"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",
|
||||
"docDefault": "NODE_APP_INSTANCE",
|
||||
"docDescription": "Rename the NODE_APP_INSTANCE environment variable"
|
||||
},
|
||||
"pmx": {
|
||||
"type": ["boolean", "string"],
|
||||
"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" : [
|
||||
"number",
|
||||
"string"
|
||||
],
|
||||
"alias": "user",
|
||||
"docDefault": "Current user uid",
|
||||
"docDescription": "Set user id"
|
||||
},
|
||||
"gid": {
|
||||
"type" : [
|
||||
"number",
|
||||
"string"
|
||||
],
|
||||
"docDefault": "Current user gid",
|
||||
"docDescription": "Set group id"
|
||||
},
|
||||
"windowsHide": {
|
||||
"type": "boolean",
|
||||
"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"
|
||||
}
|
||||
}
|
||||
779
api.hyungi.net/node_modules/pm2/lib/Client.js
generated
vendored
Normal file
779
api.hyungi.net/node_modules/pm2/lib/Client.js
generated
vendored
Normal file
@@ -0,0 +1,779 @@
|
||||
/**
|
||||
* Copyright 2013-2022 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')('pm2:client');
|
||||
var Common = require('./Common.js');
|
||||
var KMDaemon = require('@pm2/agent/src/InteractorClient');
|
||||
var rpc = require('pm2-axon-rpc');
|
||||
var forEach = require('async/forEach');
|
||||
var axon = require('pm2-axon');
|
||||
var util = require('util');
|
||||
var fs = require('fs');
|
||||
var path = require('path');
|
||||
var pkg = require('../package.json');
|
||||
var which = require('./tools/which.js');
|
||||
|
||||
function noop() {}
|
||||
|
||||
var Client = module.exports = function(opts) {
|
||||
if (!opts) opts = {};
|
||||
|
||||
if (!opts.conf)
|
||||
this.conf = require('../constants.js');
|
||||
else {
|
||||
this.conf = opts.conf;
|
||||
}
|
||||
|
||||
this.daemon_mode = typeof(opts.daemon_mode) === 'undefined' ? true : opts.daemon_mode;
|
||||
this.pm2_home = this.conf.PM2_ROOT_PATH;
|
||||
this.secret_key = opts.secret_key;
|
||||
this.public_key = opts.public_key;
|
||||
this.machine_name = opts.machine_name;
|
||||
|
||||
// Create all folders and files needed
|
||||
// Client depends to that to interact with PM2 properly
|
||||
this.initFileStructure(this.conf);
|
||||
|
||||
debug('Using RPC file %s', this.conf.DAEMON_RPC_PORT);
|
||||
debug('Using PUB file %s', this.conf.DAEMON_PUB_PORT);
|
||||
this.rpc_socket_file = this.conf.DAEMON_RPC_PORT;
|
||||
this.pub_socket_file = this.conf.DAEMON_PUB_PORT;
|
||||
};
|
||||
|
||||
// @breaking change (noDaemonMode has been drop)
|
||||
// @todo ret err
|
||||
Client.prototype.start = function(cb) {
|
||||
var that = this;
|
||||
|
||||
this.pingDaemon(function(daemonAlive) {
|
||||
if (daemonAlive === true)
|
||||
return that.launchRPC(function(err, meta) {
|
||||
return cb(null, {
|
||||
daemon_mode : that.conf.daemon_mode,
|
||||
new_pm2_instance : false,
|
||||
rpc_socket_file : that.rpc_socket_file,
|
||||
pub_socket_file : that.pub_socket_file,
|
||||
pm2_home : that.pm2_home
|
||||
});
|
||||
});
|
||||
|
||||
/**
|
||||
* No Daemon mode
|
||||
*/
|
||||
if (that.daemon_mode === false) {
|
||||
var Daemon = require('./Daemon.js');
|
||||
|
||||
var daemon = new Daemon({
|
||||
pub_socket_file : that.conf.DAEMON_PUB_PORT,
|
||||
rpc_socket_file : that.conf.DAEMON_RPC_PORT,
|
||||
pid_file : that.conf.PM2_PID_FILE_PATH,
|
||||
ignore_signals : true
|
||||
});
|
||||
|
||||
console.log('Launching in no daemon mode');
|
||||
|
||||
daemon.innerStart(function() {
|
||||
KMDaemon.launchAndInteract(that.conf, {
|
||||
machine_name : that.machine_name,
|
||||
public_key : that.public_key,
|
||||
secret_key : that.secret_key,
|
||||
pm2_version : pkg.version
|
||||
}, function(err, data, interactor_proc) {
|
||||
that.interactor_process = interactor_proc;
|
||||
});
|
||||
|
||||
that.launchRPC(function(err, meta) {
|
||||
return cb(null, {
|
||||
daemon_mode : that.conf.daemon_mode,
|
||||
new_pm2_instance : true,
|
||||
rpc_socket_file : that.rpc_socket_file,
|
||||
pub_socket_file : that.pub_socket_file,
|
||||
pm2_home : that.pm2_home
|
||||
});
|
||||
});
|
||||
});
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Daemon mode
|
||||
*/
|
||||
that.launchDaemon(function(err, child) {
|
||||
if (err) {
|
||||
Common.printError(err);
|
||||
return cb ? cb(err) : process.exit(that.conf.ERROR_EXIT);
|
||||
}
|
||||
|
||||
if (!process.env.PM2_DISCRETE_MODE)
|
||||
Common.printOut(that.conf.PREFIX_MSG + 'PM2 Successfully daemonized');
|
||||
|
||||
that.launchRPC(function(err, meta) {
|
||||
return cb(null, {
|
||||
daemon_mode : that.conf.daemon_mode,
|
||||
new_pm2_instance : true,
|
||||
rpc_socket_file : that.rpc_socket_file,
|
||||
pub_socket_file : that.pub_socket_file,
|
||||
pm2_home : that.pm2_home
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
// Init file structure of pm2_home
|
||||
// This includes
|
||||
// - pm2 pid and log path
|
||||
// - rpc and pub socket for command execution
|
||||
Client.prototype.initFileStructure = function (opts) {
|
||||
if (!fs.existsSync(opts.DEFAULT_LOG_PATH)) {
|
||||
try {
|
||||
require('mkdirp').sync(opts.DEFAULT_LOG_PATH);
|
||||
} catch (e) {
|
||||
console.error(e.stack || e);
|
||||
}
|
||||
}
|
||||
|
||||
if (!fs.existsSync(opts.DEFAULT_PID_PATH)) {
|
||||
try {
|
||||
require('mkdirp').sync(opts.DEFAULT_PID_PATH);
|
||||
} catch (e) {
|
||||
console.error(e.stack || e);
|
||||
}
|
||||
}
|
||||
|
||||
if (!fs.existsSync(opts.PM2_MODULE_CONF_FILE)) {
|
||||
try {
|
||||
fs.writeFileSync(opts.PM2_MODULE_CONF_FILE, "{}");
|
||||
} catch (e) {
|
||||
console.error(e.stack || e);
|
||||
}
|
||||
}
|
||||
|
||||
if (!fs.existsSync(opts.DEFAULT_MODULE_PATH)) {
|
||||
try {
|
||||
require('mkdirp').sync(opts.DEFAULT_MODULE_PATH);
|
||||
} catch (e) {
|
||||
console.error(e.stack || e);
|
||||
}
|
||||
}
|
||||
|
||||
if (process.env.PM2_DISCRETE_MODE) {
|
||||
try {
|
||||
fs.writeFileSync(path.join(opts.PM2_HOME, 'touch'), Date.now().toString());
|
||||
} catch(e) {
|
||||
debug(e.stack || e);
|
||||
}
|
||||
}
|
||||
|
||||
if (!process.env.PM2_PROGRAMMATIC && !fs.existsSync(path.join(opts.PM2_HOME, 'touch'))) {
|
||||
|
||||
var vCheck = require('./VersionCheck.js')
|
||||
|
||||
vCheck({
|
||||
state: 'install',
|
||||
version: pkg.version
|
||||
})
|
||||
|
||||
var dt = fs.readFileSync(path.join(__dirname, opts.PM2_BANNER));
|
||||
console.log(dt.toString());
|
||||
try {
|
||||
fs.writeFileSync(path.join(opts.PM2_HOME, 'touch'), Date.now().toString());
|
||||
} catch(e) {
|
||||
debug(e.stack || e);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
Client.prototype.close = function(cb) {
|
||||
var that = this;
|
||||
|
||||
forEach([
|
||||
that.disconnectRPC.bind(that),
|
||||
that.disconnectBus.bind(that)
|
||||
], function(fn, next) {
|
||||
fn(next)
|
||||
}, cb);
|
||||
};
|
||||
|
||||
/**
|
||||
* Launch the Daemon by forking this same file
|
||||
* The method Client.remoteWrapper will be called
|
||||
*
|
||||
* @method launchDaemon
|
||||
* @param {Object} opts
|
||||
* @param {Object} [opts.interactor=true] allow to disable interaction on launch
|
||||
*/
|
||||
Client.prototype.launchDaemon = function(opts, cb) {
|
||||
if (typeof(opts) == 'function') {
|
||||
cb = opts;
|
||||
opts = {
|
||||
interactor : true
|
||||
};
|
||||
}
|
||||
|
||||
var that = this
|
||||
var ClientJS = path.resolve(path.dirname(module.filename), 'Daemon.js');
|
||||
var node_args = [];
|
||||
var out, err;
|
||||
|
||||
// if (process.env.TRAVIS) {
|
||||
// // Redirect PM2 internal err and out to STDERR STDOUT when running with Travis
|
||||
// out = 1;
|
||||
// err = 2;
|
||||
// }
|
||||
// else {
|
||||
out = fs.openSync(that.conf.PM2_LOG_FILE_PATH, 'a'),
|
||||
err = fs.openSync(that.conf.PM2_LOG_FILE_PATH, 'a');
|
||||
//}
|
||||
|
||||
if (this.conf.LOW_MEMORY_ENVIRONMENT) {
|
||||
var os = require('os');
|
||||
node_args.push('--gc-global'); // Does full GC (smaller memory footprint)
|
||||
node_args.push('--max-old-space-size=' + Math.floor(os.totalmem() / 1024 / 1024));
|
||||
}
|
||||
|
||||
// Node.js tuning for better performance
|
||||
//node_args.push('--expose-gc'); // Allows manual GC in the code
|
||||
|
||||
/**
|
||||
* Add node [arguments] depending on PM2_NODE_OPTIONS env variable
|
||||
*/
|
||||
if (process.env.PM2_NODE_OPTIONS)
|
||||
node_args = node_args.concat(process.env.PM2_NODE_OPTIONS.split(' '));
|
||||
node_args.push(ClientJS);
|
||||
|
||||
if (!process.env.PM2_DISCRETE_MODE)
|
||||
Common.printOut(that.conf.PREFIX_MSG + 'Spawning PM2 daemon with pm2_home=' + this.pm2_home);
|
||||
|
||||
var interpreter = 'node';
|
||||
|
||||
if (which('node') == null)
|
||||
interpreter = process.execPath;
|
||||
|
||||
var child = require('child_process').spawn(interpreter, node_args, {
|
||||
detached : true,
|
||||
cwd : that.conf.cwd || process.cwd(),
|
||||
windowsHide: true,
|
||||
env : Object.assign({
|
||||
'SILENT' : that.conf.DEBUG ? !that.conf.DEBUG : true,
|
||||
'PM2_HOME' : that.pm2_home
|
||||
}, process.env),
|
||||
stdio : ['ipc', out, err]
|
||||
});
|
||||
|
||||
function onError(e) {
|
||||
console.error(e.message || e);
|
||||
return cb ? cb(e.message || e) : false;
|
||||
}
|
||||
|
||||
child.once('error', onError);
|
||||
|
||||
child.unref();
|
||||
|
||||
child.once('message', function(msg) {
|
||||
debug('PM2 daemon launched with return message: ', msg);
|
||||
child.removeListener('error', onError);
|
||||
child.disconnect();
|
||||
|
||||
if (opts && opts.interactor == false)
|
||||
return cb(null, child);
|
||||
|
||||
if (process.env.PM2_NO_INTERACTION == 'true')
|
||||
return cb(null, child);
|
||||
|
||||
/**
|
||||
* Here the Keymetrics agent is launched automaticcaly if
|
||||
* it has been already configured before (via pm2 link)
|
||||
*/
|
||||
KMDaemon.launchAndInteract(that.conf, {
|
||||
machine_name : that.machine_name,
|
||||
public_key : that.public_key,
|
||||
secret_key : that.secret_key,
|
||||
pm2_version : pkg.version
|
||||
}, function(err, data, interactor_proc) {
|
||||
that.interactor_process = interactor_proc;
|
||||
return cb(null, child);
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Ping the daemon to know if it alive or not
|
||||
* @api public
|
||||
* @method pingDaemon
|
||||
* @param {} cb
|
||||
* @return
|
||||
*/
|
||||
Client.prototype.pingDaemon = function pingDaemon(cb) {
|
||||
var req = axon.socket('req');
|
||||
var client = new rpc.Client(req);
|
||||
var that = this;
|
||||
|
||||
debug('[PING PM2] Trying to connect to server');
|
||||
|
||||
client.sock.once('reconnect attempt', function() {
|
||||
client.sock.close();
|
||||
debug('Daemon not launched');
|
||||
process.nextTick(function() {
|
||||
return cb(false);
|
||||
});
|
||||
});
|
||||
|
||||
client.sock.once('error', function(e) {
|
||||
if (e.code === 'EACCES') {
|
||||
fs.stat(that.conf.DAEMON_RPC_PORT, function(e, stats) {
|
||||
if (stats.uid === 0) {
|
||||
console.error(that.conf.PREFIX_MSG_ERR + 'Permission denied, to give access to current user:');
|
||||
console.log('$ sudo chown ' + process.env.USER + ':' + process.env.USER + ' ' + that.conf.DAEMON_RPC_PORT + ' ' + that.conf.DAEMON_PUB_PORT);
|
||||
}
|
||||
else
|
||||
console.error(that.conf.PREFIX_MSG_ERR + 'Permission denied, check permissions on ' + that.conf.DAEMON_RPC_PORT);
|
||||
|
||||
process.exit(1);
|
||||
});
|
||||
}
|
||||
else
|
||||
console.error(e.message || e);
|
||||
});
|
||||
|
||||
client.sock.once('connect', function() {
|
||||
client.sock.once('close', function() {
|
||||
return cb(true);
|
||||
});
|
||||
client.sock.close();
|
||||
debug('Daemon alive');
|
||||
});
|
||||
|
||||
req.connect(this.rpc_socket_file);
|
||||
};
|
||||
|
||||
/**
|
||||
* Methods to interact with the Daemon via RPC
|
||||
* This method wait to be connected to the Daemon
|
||||
* Once he's connected it trigger the command parsing (on ./bin/pm2 file, at the end)
|
||||
* @method launchRPC
|
||||
* @params {function} [cb]
|
||||
* @return
|
||||
*/
|
||||
Client.prototype.launchRPC = function launchRPC(cb) {
|
||||
var self = this;
|
||||
debug('Launching RPC client on socket file %s', this.rpc_socket_file);
|
||||
var req = axon.socket('req');
|
||||
this.client = new rpc.Client(req);
|
||||
|
||||
var connectHandler = function() {
|
||||
self.client.sock.removeListener('error', errorHandler);
|
||||
debug('RPC Connected to Daemon');
|
||||
if (cb) {
|
||||
setTimeout(function() {
|
||||
cb(null);
|
||||
}, 4);
|
||||
}
|
||||
};
|
||||
|
||||
var errorHandler = function(e) {
|
||||
self.client.sock.removeListener('connect', connectHandler);
|
||||
if (cb) {
|
||||
return cb(e);
|
||||
}
|
||||
};
|
||||
|
||||
this.client.sock.once('connect', connectHandler);
|
||||
this.client.sock.once('error', errorHandler);
|
||||
this.client_sock = req.connect(this.rpc_socket_file);
|
||||
};
|
||||
|
||||
/**
|
||||
* Methods to close the RPC connection
|
||||
* @callback cb
|
||||
*/
|
||||
Client.prototype.disconnectRPC = function disconnectRPC(cb) {
|
||||
var that = this;
|
||||
if (!cb) cb = noop;
|
||||
|
||||
if (!this.client_sock || !this.client_sock.close) {
|
||||
this.client = null;
|
||||
return process.nextTick(function() {
|
||||
cb(new Error('SUB connection to PM2 is not launched'));
|
||||
});
|
||||
}
|
||||
|
||||
if (this.client_sock.connected === false ||
|
||||
this.client_sock.closing === true) {
|
||||
this.client = null;
|
||||
return process.nextTick(function() {
|
||||
cb(new Error('RPC already being closed'));
|
||||
});
|
||||
}
|
||||
|
||||
try {
|
||||
var timer;
|
||||
|
||||
that.client_sock.once('close', function() {
|
||||
clearTimeout(timer);
|
||||
that.client = null;
|
||||
debug('PM2 RPC cleanly closed');
|
||||
return cb(null, { msg : 'RPC Successfully closed' });
|
||||
});
|
||||
|
||||
timer = setTimeout(function() {
|
||||
if (that.client_sock.destroy)
|
||||
that.client_sock.destroy();
|
||||
that.client = null;
|
||||
return cb(null, { msg : 'RPC Successfully closed via timeout' });
|
||||
}, 200);
|
||||
|
||||
that.client_sock.close();
|
||||
} catch(e) {
|
||||
debug('Error while disconnecting RPC PM2', e.stack || e);
|
||||
return cb(e);
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
Client.prototype.launchBus = function launchEventSystem(cb) {
|
||||
var self = this;
|
||||
this.sub = axon.socket('sub-emitter');
|
||||
this.sub_sock = this.sub.connect(this.pub_socket_file);
|
||||
|
||||
this.sub_sock.once('connect', function() {
|
||||
return cb(null, self.sub, self.sub_sock);
|
||||
});
|
||||
};
|
||||
|
||||
Client.prototype.disconnectBus = function disconnectBus(cb) {
|
||||
if (!cb) cb = noop;
|
||||
|
||||
var that = this;
|
||||
|
||||
if (!this.sub_sock || !this.sub_sock.close) {
|
||||
that.sub = null;
|
||||
return process.nextTick(function() {
|
||||
cb(null, { msg : 'bus was not connected'});
|
||||
});
|
||||
}
|
||||
|
||||
if (this.sub_sock.connected === false ||
|
||||
this.sub_sock.closing === true) {
|
||||
that.sub = null;
|
||||
return process.nextTick(function() {
|
||||
cb(new Error('SUB connection is already being closed'));
|
||||
});
|
||||
}
|
||||
|
||||
try {
|
||||
var timer;
|
||||
|
||||
that.sub_sock.once('close', function() {
|
||||
that.sub = null;
|
||||
clearTimeout(timer);
|
||||
debug('PM2 PUB cleanly closed');
|
||||
return cb();
|
||||
});
|
||||
|
||||
timer = setTimeout(function() {
|
||||
if (Client.sub_sock.destroy)
|
||||
that.sub_sock.destroy();
|
||||
return cb();
|
||||
}, 200);
|
||||
|
||||
this.sub_sock.close();
|
||||
} catch(e) {
|
||||
return cb(e);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Description
|
||||
* @method gestExposedMethods
|
||||
* @param {} cb
|
||||
* @return
|
||||
*/
|
||||
Client.prototype.getExposedMethods = function getExposedMethods(cb) {
|
||||
this.client.methods(cb);
|
||||
};
|
||||
|
||||
/**
|
||||
* Description
|
||||
* @method executeRemote
|
||||
* @param {} method
|
||||
* @param {} env
|
||||
* @param {} fn
|
||||
* @return
|
||||
*/
|
||||
Client.prototype.executeRemote = function executeRemote(method, app_conf, fn) {
|
||||
var self = this;
|
||||
|
||||
// stop watch on stop | env is the process id
|
||||
if (method.indexOf('stop') !== -1) {
|
||||
this.stopWatch(method, app_conf);
|
||||
}
|
||||
// stop watching when process is deleted
|
||||
else if (method.indexOf('delete') !== -1) {
|
||||
this.stopWatch(method, app_conf);
|
||||
}
|
||||
// stop everything on kill
|
||||
else if (method.indexOf('kill') !== -1) {
|
||||
this.stopWatch('deleteAll', app_conf);
|
||||
}
|
||||
else if (method.indexOf('restartProcessId') !== -1 && process.argv.indexOf('--watch') > -1) {
|
||||
delete app_conf.env.current_conf.watch;
|
||||
this.toggleWatch(method, app_conf);
|
||||
}
|
||||
|
||||
if (!this.client || !this.client.call) {
|
||||
this.start(function(error) {
|
||||
if (error) {
|
||||
if (fn)
|
||||
return fn(error);
|
||||
console.error(error);
|
||||
return process.exit(0);
|
||||
}
|
||||
if (self.client) {
|
||||
return self.client.call(method, app_conf, fn);
|
||||
}
|
||||
});
|
||||
return false;
|
||||
}
|
||||
|
||||
debug('Calling daemon method pm2:%s on rpc socket:%s', method, this.rpc_socket_file);
|
||||
return this.client.call(method, app_conf, fn);
|
||||
};
|
||||
|
||||
Client.prototype.notifyGod = function(action_name, id, cb) {
|
||||
this.executeRemote('notifyByProcessId', {
|
||||
id : id,
|
||||
action_name : action_name,
|
||||
manually : true
|
||||
}, function() {
|
||||
debug('God notified');
|
||||
return cb ? cb() : false;
|
||||
});
|
||||
};
|
||||
|
||||
Client.prototype.killDaemon = function killDaemon(fn) {
|
||||
var timeout;
|
||||
var that = this;
|
||||
|
||||
function quit() {
|
||||
that.close(function() {
|
||||
return fn ? fn(null, {success:true}) : false;
|
||||
});
|
||||
}
|
||||
|
||||
// under unix, we listen for signal (that is send by daemon to notify us that its shuting down)
|
||||
if (process.platform !== 'win32' && process.platform !== 'win64') {
|
||||
process.once('SIGQUIT', function() {
|
||||
debug('Received SIGQUIT from pm2 daemon');
|
||||
clearTimeout(timeout);
|
||||
quit();
|
||||
});
|
||||
}
|
||||
else {
|
||||
// if under windows, try to ping the daemon to see if it still here
|
||||
setTimeout(function() {
|
||||
that.pingDaemon(function(alive) {
|
||||
if (!alive) {
|
||||
clearTimeout(timeout);
|
||||
return quit();
|
||||
}
|
||||
});
|
||||
}, 250)
|
||||
}
|
||||
|
||||
timeout = setTimeout(function() {
|
||||
quit();
|
||||
}, 3000);
|
||||
|
||||
// Kill daemon
|
||||
this.executeRemote('killMe', {pid : process.pid});
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Description
|
||||
* @method toggleWatch
|
||||
* @param {String} pm2 method name
|
||||
* @param {Object} application environment, should include id
|
||||
* @param {Function} callback
|
||||
*/
|
||||
Client.prototype.toggleWatch = function toggleWatch(method, env, fn) {
|
||||
debug('Calling toggleWatch');
|
||||
this.client.call('toggleWatch', method, env, function() {
|
||||
return fn ? fn() : false;
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Description
|
||||
* @method startWatch
|
||||
* @param {String} pm2 method name
|
||||
* @param {Object} application environment, should include id
|
||||
* @param {Function} callback
|
||||
*/
|
||||
Client.prototype.startWatch = function restartWatch(method, env, fn) {
|
||||
debug('Calling startWatch');
|
||||
this.client.call('startWatch', method, env, function() {
|
||||
return fn ? fn() : false;
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Description
|
||||
* @method stopWatch
|
||||
* @param {String} pm2 method name
|
||||
* @param {Object} application environment, should include id
|
||||
* @param {Function} callback
|
||||
*/
|
||||
Client.prototype.stopWatch = function stopWatch(method, env, fn) {
|
||||
debug('Calling stopWatch');
|
||||
this.client.call('stopWatch', method, env, function() {
|
||||
return fn ? fn() : false;
|
||||
});
|
||||
};
|
||||
|
||||
Client.prototype.getAllProcess = function(cb) {
|
||||
var found_proc = [];
|
||||
|
||||
this.executeRemote('getMonitorData', {}, function(err, procs) {
|
||||
if (err) {
|
||||
Common.printError('Error retrieving process list: ' + err);
|
||||
return cb(err);
|
||||
}
|
||||
|
||||
return cb(null, procs);
|
||||
});
|
||||
};
|
||||
|
||||
Client.prototype.getAllProcessId = function(cb) {
|
||||
var found_proc = [];
|
||||
|
||||
this.executeRemote('getMonitorData', {}, function(err, procs) {
|
||||
if (err) {
|
||||
Common.printError('Error retrieving process list: ' + err);
|
||||
return cb(err);
|
||||
}
|
||||
|
||||
return cb(null, procs.map(proc => proc.pm_id));
|
||||
});
|
||||
};
|
||||
|
||||
Client.prototype.getAllProcessIdWithoutModules = function(cb) {
|
||||
var found_proc = [];
|
||||
|
||||
this.executeRemote('getMonitorData', {}, function(err, procs) {
|
||||
if (err) {
|
||||
Common.printError('Error retrieving process list: ' + err);
|
||||
return cb(err);
|
||||
}
|
||||
|
||||
var proc_ids = procs
|
||||
.filter(proc => !proc.pm2_env.pmx_module)
|
||||
.map(proc => proc.pm_id)
|
||||
|
||||
return cb(null, proc_ids);
|
||||
});
|
||||
};
|
||||
|
||||
Client.prototype.getProcessIdByName = function(name, force_all, cb) {
|
||||
var found_proc = [];
|
||||
var full_details = {};
|
||||
|
||||
if (typeof(cb) === 'undefined') {
|
||||
cb = force_all;
|
||||
force_all = false;
|
||||
}
|
||||
|
||||
if (typeof(name) == 'number')
|
||||
name = name.toString();
|
||||
|
||||
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 == name || proc.pm2_env.pm_exec_path == path.resolve(name)) {
|
||||
found_proc.push(proc.pm_id);
|
||||
full_details[proc.pm_id] = proc;
|
||||
}
|
||||
});
|
||||
|
||||
return cb(null, found_proc, full_details);
|
||||
});
|
||||
};
|
||||
|
||||
Client.prototype.getProcessIdsByNamespace = function(namespace, force_all, cb) {
|
||||
var found_proc = [];
|
||||
var full_details = {};
|
||||
|
||||
if (typeof(cb) === 'undefined') {
|
||||
cb = force_all;
|
||||
force_all = false;
|
||||
}
|
||||
|
||||
if (typeof(namespace) == 'number')
|
||||
namespace = namespace.toString();
|
||||
|
||||
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.namespace == namespace) {
|
||||
found_proc.push(proc.pm_id);
|
||||
full_details[proc.pm_id] = proc;
|
||||
}
|
||||
});
|
||||
|
||||
return cb(null, found_proc, full_details);
|
||||
});
|
||||
};
|
||||
|
||||
Client.prototype.getProcessByName = function(name, cb) {
|
||||
var found_proc = [];
|
||||
|
||||
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 == name ||
|
||||
proc.pm2_env.pm_exec_path == path.resolve(name)) {
|
||||
found_proc.push(proc);
|
||||
}
|
||||
});
|
||||
|
||||
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);
|
||||
});
|
||||
};
|
||||
904
api.hyungi.net/node_modules/pm2/lib/Common.js
generated
vendored
Normal file
904
api.hyungi.net/node_modules/pm2/lib/Common.js
generated
vendored
Normal file
@@ -0,0 +1,904 @@
|
||||
/**
|
||||
* Copyright 2013-2022 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Common Utilities ONLY USED IN ->CLI<-
|
||||
*/
|
||||
|
||||
var fs = require('fs');
|
||||
var path = require('path');
|
||||
var os = require('os');
|
||||
var util = require('util');
|
||||
var chalk = require('chalk');
|
||||
var fclone = require('fclone');
|
||||
var semver = require('semver');
|
||||
var dayjs = require('dayjs');
|
||||
var execSync = require('child_process').execSync;
|
||||
var isBinary = require('./tools/isbinaryfile.js');
|
||||
var cst = require('../constants.js');
|
||||
var extItps = require('./API/interpreter.json');
|
||||
var Config = require('./tools/Config');
|
||||
var pkg = require('../package.json');
|
||||
var which = require('./tools/which.js');
|
||||
var Common = module.exports;
|
||||
|
||||
function homedir() {
|
||||
var env = process.env;
|
||||
var home = env.HOME;
|
||||
var user = env.LOGNAME || env.USER || env.LNAME || env.USERNAME;
|
||||
|
||||
if (process.platform === 'win32') {
|
||||
return env.USERPROFILE || env.HOMEDRIVE + env.HOMEPATH || home || null;
|
||||
}
|
||||
|
||||
if (process.platform === 'darwin') {
|
||||
return home || (user ? '/Users/' + user : null);
|
||||
}
|
||||
|
||||
if (process.platform === 'linux') {
|
||||
return home || (process.getuid() === 0 ? '/root' : (user ? '/home/' + user : null));
|
||||
}
|
||||
|
||||
return home || null;
|
||||
}
|
||||
|
||||
function resolveHome(filepath) {
|
||||
if (filepath[0] === '~') {
|
||||
return path.join(homedir(), filepath.slice(1));
|
||||
}
|
||||
return filepath;
|
||||
}
|
||||
|
||||
Common.determineSilentCLI = function() {
|
||||
// pm2 should ignore -s --silent -v if they are after '--'
|
||||
var variadicArgsDashesPos = process.argv.indexOf('--');
|
||||
var s1opt = process.argv.indexOf('--silent')
|
||||
var s2opt = process.argv.indexOf('-s')
|
||||
|
||||
if (process.env.PM2_SILENT || (variadicArgsDashesPos > -1 &&
|
||||
(s1opt != -1 && s1opt < variadicArgsDashesPos) &&
|
||||
(s2opt != -1 != s2opt < variadicArgsDashesPos)) ||
|
||||
(variadicArgsDashesPos == -1 && (s1opt > -1 || s2opt > -1))) {
|
||||
for (var key in console){
|
||||
var code = key.charCodeAt(0);
|
||||
if (code >= 97 && code <= 122){
|
||||
console[key] = function(){};
|
||||
}
|
||||
}
|
||||
process.env.PM2_DISCRETE_MODE = true;
|
||||
}
|
||||
}
|
||||
|
||||
Common.printVersion = function() {
|
||||
var variadicArgsDashesPos = process.argv.indexOf('--');
|
||||
|
||||
if (process.argv.indexOf('-v') > -1 && process.argv.indexOf('-v') < variadicArgsDashesPos) {
|
||||
console.log(pkg.version);
|
||||
process.exit(0);
|
||||
}
|
||||
}
|
||||
|
||||
Common.lockReload = function() {
|
||||
try {
|
||||
var t1 = fs.readFileSync(cst.PM2_RELOAD_LOCKFILE).toString();
|
||||
|
||||
// Check if content and if time < 30 return locked
|
||||
// Else if content detected (lock file staled), allow and rewritte
|
||||
if (t1 && t1 != '') {
|
||||
var diff = dayjs().diff(parseInt(t1));
|
||||
if (diff < cst.RELOAD_LOCK_TIMEOUT)
|
||||
return diff;
|
||||
}
|
||||
} catch(e) {}
|
||||
|
||||
try {
|
||||
// Write latest timestamp
|
||||
fs.writeFileSync(cst.PM2_RELOAD_LOCKFILE, dayjs().valueOf().toString());
|
||||
return 0;
|
||||
} catch(e) {
|
||||
console.error(e.message || e);
|
||||
}
|
||||
};
|
||||
|
||||
Common.unlockReload = function() {
|
||||
try {
|
||||
fs.writeFileSync(cst.PM2_RELOAD_LOCKFILE, '');
|
||||
} catch(e) {
|
||||
console.error(e.message || e);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Resolve app paths and replace missing values with defaults.
|
||||
* @method prepareAppConf
|
||||
* @param app {Object}
|
||||
* @param {} cwd
|
||||
* @param {} outputter
|
||||
* @return app
|
||||
*/
|
||||
Common.prepareAppConf = function(opts, app) {
|
||||
/**
|
||||
* Minimum validation
|
||||
*/
|
||||
if (!app.script)
|
||||
return new Error('No script path - aborting');
|
||||
|
||||
var cwd = null;
|
||||
|
||||
if (app.cwd) {
|
||||
cwd = path.resolve(app.cwd);
|
||||
process.env.PWD = app.cwd;
|
||||
}
|
||||
|
||||
if (!app.node_args) {
|
||||
app.node_args = [];
|
||||
}
|
||||
|
||||
if (app.port && app.env) {
|
||||
app.env.PORT = app.port;
|
||||
}
|
||||
|
||||
// CWD option resolving
|
||||
cwd && (cwd[0] != '/') && (cwd = path.resolve(process.cwd(), cwd));
|
||||
cwd = cwd || opts.cwd;
|
||||
|
||||
// Full path script resolution
|
||||
app.pm_exec_path = path.resolve(cwd, app.script);
|
||||
|
||||
// If script does not exist after resolution
|
||||
if (!fs.existsSync(app.pm_exec_path)) {
|
||||
var ckd;
|
||||
// Try resolve command available in $PATH
|
||||
if ((ckd = which(app.script))) {
|
||||
if (typeof(ckd) !== 'string')
|
||||
ckd = ckd.toString();
|
||||
app.pm_exec_path = ckd;
|
||||
}
|
||||
else
|
||||
// Throw critical error
|
||||
return new Error(`Script not found: ${app.pm_exec_path}`);
|
||||
}
|
||||
|
||||
/**
|
||||
* Auto detect .map file and enable source map support automatically
|
||||
*/
|
||||
if (app.disable_source_map_support != true) {
|
||||
try {
|
||||
fs.accessSync(app.pm_exec_path + '.map', fs.R_OK);
|
||||
app.source_map_support = true;
|
||||
} catch(e) {}
|
||||
delete app.disable_source_map_support;
|
||||
}
|
||||
|
||||
delete app.script;
|
||||
|
||||
// Set current env by first adding the process environment and then extending/replacing it
|
||||
// with env specified on command-line or JSON file.
|
||||
|
||||
var env = {};
|
||||
|
||||
/**
|
||||
* Do not copy internal pm2 environment variables if acting on process
|
||||
* is made from a programmatic script started by PM2 or if a pm_id is present in env
|
||||
*/
|
||||
if (cst.PM2_PROGRAMMATIC || process.env.pm_id)
|
||||
Common.safeExtend(env, process.env);
|
||||
else
|
||||
env = process.env;
|
||||
|
||||
function filterEnv (envObj) {
|
||||
if (app.filter_env == true)
|
||||
return {}
|
||||
|
||||
if (typeof app.filter_env === 'string') {
|
||||
delete envObj[app.filter_env]
|
||||
return envObj
|
||||
}
|
||||
|
||||
var new_env = {};
|
||||
var allowedKeys = app.filter_env.reduce((acc, current) =>
|
||||
acc.filter( item => !item.includes(current)), Object.keys(envObj))
|
||||
allowedKeys.forEach( key => new_env[key] = envObj[key]);
|
||||
return new_env
|
||||
}
|
||||
|
||||
app.env = [
|
||||
{}, (app.filter_env && app.filter_env.length > 0) ? filterEnv(process.env) : env, app.env || {}
|
||||
].reduce(function(e1, e2){
|
||||
return Object.assign(e1, e2);
|
||||
});
|
||||
|
||||
app.pm_cwd = cwd;
|
||||
// Interpreter
|
||||
try {
|
||||
Common.sink.resolveInterpreter(app);
|
||||
} catch(e) {
|
||||
return e
|
||||
}
|
||||
|
||||
// Exec mode and cluster stuff
|
||||
Common.sink.determineExecMode(app);
|
||||
|
||||
/**
|
||||
* Scary
|
||||
*/
|
||||
var formated_app_name = app.name.replace(/[^a-zA-Z0-9\\.\\-]/g, '-');
|
||||
|
||||
['log', 'out', 'error', 'pid'].forEach(function(f){
|
||||
var af = app[f + '_file'], ps, ext = (f == 'pid' ? 'pid':'log'), isStd = !~['log', 'pid'].indexOf(f);
|
||||
if (af) af = resolveHome(af);
|
||||
|
||||
if ((f == 'log' && typeof af == 'boolean' && af) || (f != 'log' && !af)) {
|
||||
ps = [cst['DEFAULT_' + ext.toUpperCase() + '_PATH'], formated_app_name + (isStd ? '-' + f : '') + '.' + ext];
|
||||
} else if ((f != 'log' || (f == 'log' && af)) && af !== 'NULL' && af !== '/dev/null') {
|
||||
ps = [cwd, af];
|
||||
|
||||
var dir = path.dirname(path.resolve(cwd, af));
|
||||
if (!fs.existsSync(dir)) {
|
||||
Common.printError(cst.PREFIX_MSG_WARNING + 'Folder does not exist: ' + dir);
|
||||
Common.printOut(cst.PREFIX_MSG + 'Creating folder: ' + dir);
|
||||
try {
|
||||
require('mkdirp').sync(dir);
|
||||
} catch (err) {
|
||||
Common.printError(cst.PREFIX_MSG_ERR + 'Could not create folder: ' + path.dirname(af));
|
||||
throw new Error('Could not create folder');
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
// PM2 paths
|
||||
if (af !== 'NULL' && af !== '/dev/null') {
|
||||
ps && (app['pm_' + (isStd ? f.substr(0, 3) + '_' : '') + ext + '_path'] = path.resolve.apply(null, ps));
|
||||
} else if (path.sep === '\\') {
|
||||
app['pm_' + (isStd ? f.substr(0, 3) + '_' : '') + ext + '_path'] = '\\\\.\\NUL';
|
||||
} else {
|
||||
app['pm_' + (isStd ? f.substr(0, 3) + '_' : '') + ext + '_path'] = '/dev/null';
|
||||
}
|
||||
delete app[f + '_file'];
|
||||
});
|
||||
|
||||
return app;
|
||||
};
|
||||
|
||||
/**
|
||||
* Definition of known config file extensions with their type
|
||||
*/
|
||||
Common.knonwConfigFileExtensions = {
|
||||
'.json': 'json',
|
||||
'.yml': 'yaml',
|
||||
'.yaml': 'yaml',
|
||||
'.config.js': 'js',
|
||||
'.config.cjs': 'js',
|
||||
'.config.mjs': 'mjs'
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if filename is a configuration file
|
||||
* @param {string} filename
|
||||
* @return {mixed} null if not conf file, json or yaml if conf
|
||||
*/
|
||||
Common.isConfigFile = function (filename) {
|
||||
if (typeof (filename) !== 'string')
|
||||
return null;
|
||||
|
||||
for (let extension in Common.knonwConfigFileExtensions) {
|
||||
if (filename.indexOf(extension) !== -1) {
|
||||
return Common.knonwConfigFileExtensions[extension];
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
};
|
||||
|
||||
Common.getConfigFileCandidates = function (name) {
|
||||
return Object.keys(Common.knonwConfigFileExtensions).map((extension) => name + extension);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
Common.parseConfig = function(confObj, filename) {
|
||||
var yamljs = require('js-yaml');
|
||||
var vm = require('vm');
|
||||
|
||||
var isConfigFile = Common.isConfigFile(filename);
|
||||
|
||||
if (!filename ||
|
||||
filename == 'pipe' ||
|
||||
filename == 'none' ||
|
||||
isConfigFile == 'json') {
|
||||
var code = '(' + confObj + ')';
|
||||
var sandbox = {};
|
||||
|
||||
return vm.runInThisContext(code, sandbox, {
|
||||
filename: path.resolve(filename),
|
||||
displayErrors: false,
|
||||
timeout: 1000
|
||||
});
|
||||
}
|
||||
else if (isConfigFile == 'yaml') {
|
||||
return yamljs.load(confObj.toString());
|
||||
}
|
||||
else if (isConfigFile == 'js' || isConfigFile == 'mjs') {
|
||||
var confPath = require.resolve(path.resolve(filename));
|
||||
delete require.cache[confPath];
|
||||
return require(confPath);
|
||||
}
|
||||
};
|
||||
|
||||
Common.retErr = function(e) {
|
||||
if (!e)
|
||||
return new Error('Unidentified error');
|
||||
if (e instanceof Error)
|
||||
return e;
|
||||
return new Error(e);
|
||||
}
|
||||
|
||||
Common.sink = {};
|
||||
|
||||
Common.sink.determineCron = function(app) {
|
||||
if (app.cron_restart == 0 || app.cron_restart == '0') {
|
||||
Common.printOut(cst.PREFIX_MSG + 'disabling cron restart');
|
||||
return
|
||||
}
|
||||
|
||||
if (app.cron_restart) {
|
||||
const Croner = require('croner');
|
||||
|
||||
try {
|
||||
Common.printOut(cst.PREFIX_MSG + 'cron restart at ' + app.cron_restart);
|
||||
Croner(app.cron_restart);
|
||||
} catch(ex) {
|
||||
return new Error(`Cron pattern error: ${ex.message}`);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Handle alias (fork <=> fork_mode, cluster <=> cluster_mode)
|
||||
*/
|
||||
Common.sink.determineExecMode = function(app) {
|
||||
if (app.exec_mode)
|
||||
app.exec_mode = app.exec_mode.replace(/^(fork|cluster)$/, '$1_mode');
|
||||
|
||||
/**
|
||||
* Here we put the default exec mode
|
||||
*/
|
||||
if (!app.exec_mode &&
|
||||
(app.instances >= 1 || app.instances === 0 || app.instances === -1) &&
|
||||
app.exec_interpreter.indexOf('node') > -1) {
|
||||
app.exec_mode = 'cluster_mode';
|
||||
} else if (!app.exec_mode) {
|
||||
app.exec_mode = 'fork_mode';
|
||||
}
|
||||
if (typeof app.instances == 'undefined')
|
||||
app.instances = 1;
|
||||
};
|
||||
|
||||
var resolveNodeInterpreter = function(app) {
|
||||
if (app.exec_mode && app.exec_mode.indexOf('cluster') > -1) {
|
||||
Common.printError(cst.PREFIX_MSG_WARNING + chalk.bold.yellow('Choosing the Node.js version in cluster mode is not supported'));
|
||||
return false;
|
||||
}
|
||||
|
||||
var nvm_path = cst.IS_WINDOWS ? process.env.NVM_HOME : process.env.NVM_DIR;
|
||||
if (!nvm_path) {
|
||||
Common.printError(cst.PREFIX_MSG_ERR + chalk.red('NVM is not available in PATH'));
|
||||
Common.printError(cst.PREFIX_MSG_ERR + chalk.red('Fallback to node in PATH'));
|
||||
var msg = cst.IS_WINDOWS
|
||||
? 'https://github.com/coreybutler/nvm-windows/releases/'
|
||||
: '$ curl https://raw.githubusercontent.com/creationix/nvm/master/install.sh | bash';
|
||||
Common.printOut(cst.PREFIX_MSG_ERR + chalk.bold('Install NVM:\n' + msg));
|
||||
}
|
||||
else {
|
||||
var node_version = app.exec_interpreter.split('@')[1];
|
||||
var path_to_node = cst.IS_WINDOWS
|
||||
? '/v' + node_version + '/node.exe'
|
||||
: semver.satisfies(node_version, '>= 0.12.0')
|
||||
? '/versions/node/v' + node_version + '/bin/node'
|
||||
: '/v' + node_version + '/bin/node';
|
||||
var nvm_node_path = path.join(nvm_path, path_to_node);
|
||||
try {
|
||||
fs.accessSync(nvm_node_path);
|
||||
} catch(e) {
|
||||
Common.printOut(cst.PREFIX_MSG + 'Installing Node v%s', node_version);
|
||||
var nvm_bin = path.join(nvm_path, 'nvm.' + (cst.IS_WINDOWS ? 'exe' : 'sh'));
|
||||
var nvm_cmd = cst.IS_WINDOWS
|
||||
? nvm_bin + ' install ' + node_version
|
||||
: '. ' + nvm_bin + ' ; nvm install ' + node_version;
|
||||
|
||||
Common.printOut(cst.PREFIX_MSG + 'Executing: %s', nvm_cmd);
|
||||
|
||||
execSync(nvm_cmd, {
|
||||
cwd: path.resolve(process.cwd()),
|
||||
env: process.env,
|
||||
maxBuffer: 20 * 1024 * 1024
|
||||
});
|
||||
|
||||
// in order to support both arch, nvm for Windows renames 'node.exe' to:
|
||||
// 'node32.exe' for x32 arch
|
||||
// 'node64.exe' for x64 arch
|
||||
if (cst.IS_WINDOWS)
|
||||
nvm_node_path = nvm_node_path.replace(/node/, 'node' + process.arch.slice(1))
|
||||
}
|
||||
|
||||
Common.printOut(cst.PREFIX_MSG + chalk.green.bold('Setting Node to v%s (path=%s)'),
|
||||
node_version,
|
||||
nvm_node_path);
|
||||
|
||||
app.exec_interpreter = nvm_node_path;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Resolve interpreter
|
||||
*/
|
||||
Common.sink.resolveInterpreter = function(app) {
|
||||
var noInterpreter = !app.exec_interpreter;
|
||||
var extName = path.extname(app.pm_exec_path);
|
||||
var betterInterpreter = extItps[extName];
|
||||
|
||||
// No interpreter defined and correspondance in schema hashmap
|
||||
if (noInterpreter && betterInterpreter) {
|
||||
app.exec_interpreter = betterInterpreter;
|
||||
|
||||
if (betterInterpreter == "python") {
|
||||
if (which('python') == null) {
|
||||
if (which('python3') == null)
|
||||
Common.printError(cst.PREFIX_MSG_WARNING + chalk.bold.yellow('python and python3 binaries not available in PATH'));
|
||||
else
|
||||
app.exec_interpreter = 'python3';
|
||||
}
|
||||
}
|
||||
}
|
||||
// Else if no Interpreter detect if process is binary
|
||||
else if (noInterpreter)
|
||||
app.exec_interpreter = isBinary(app.pm_exec_path) ? 'none' : 'node';
|
||||
else if (app.exec_interpreter.indexOf('node@') > -1)
|
||||
resolveNodeInterpreter(app);
|
||||
|
||||
if (app.exec_interpreter.indexOf('python') > -1)
|
||||
app.env.PYTHONUNBUFFERED = '1'
|
||||
|
||||
if (app.exec_interpreter == 'lsc') {
|
||||
app.exec_interpreter = path.resolve(__dirname, '../node_modules/.bin/lsc');
|
||||
}
|
||||
|
||||
if (app.exec_interpreter == 'coffee') {
|
||||
app.exec_interpreter = path.resolve(__dirname, '../node_modules/.bin/coffee');
|
||||
}
|
||||
|
||||
if (app.exec_interpreter != 'none' && which(app.exec_interpreter) == null) {
|
||||
// If node is not present
|
||||
if (app.exec_interpreter == 'node') {
|
||||
Common.warn(`Using builtin node.js version on version ${process.version}`)
|
||||
app.exec_interpreter = cst.BUILTIN_NODE_PATH
|
||||
}
|
||||
else
|
||||
throw new Error(`Interpreter ${app.exec_interpreter} is NOT AVAILABLE in PATH. (type 'which ${app.exec_interpreter}' to double check.)`)
|
||||
}
|
||||
|
||||
return app;
|
||||
};
|
||||
|
||||
Common.deepCopy = Common.serialize = Common.clone = function(obj) {
|
||||
if (obj === null || obj === undefined) return {};
|
||||
return fclone(obj);
|
||||
};
|
||||
|
||||
Common.errMod = function(msg) {
|
||||
if (process.env.PM2_SILENT || process.env.PM2_PROGRAMMATIC === 'true') return false;
|
||||
if (msg instanceof Error)
|
||||
return console.error(msg.message);
|
||||
return console.error(`${cst.PREFIX_MSG_MOD_ERR}${msg}`);
|
||||
}
|
||||
|
||||
Common.err = function(msg) {
|
||||
if (process.env.PM2_SILENT || process.env.PM2_PROGRAMMATIC === 'true') return false;
|
||||
if (msg instanceof Error)
|
||||
return console.error(`${cst.PREFIX_MSG_ERR}${msg.message}`);
|
||||
return console.error(`${cst.PREFIX_MSG_ERR}${msg}`);
|
||||
}
|
||||
|
||||
Common.printError = function(msg) {
|
||||
if (process.env.PM2_SILENT || process.env.PM2_PROGRAMMATIC === 'true') return false;
|
||||
if (msg instanceof Error)
|
||||
return console.error(msg.message);
|
||||
return console.error.apply(console, arguments);
|
||||
};
|
||||
|
||||
Common.log = function(msg) {
|
||||
if (process.env.PM2_SILENT || process.env.PM2_PROGRAMMATIC === 'true') return false;
|
||||
return console.log(`${cst.PREFIX_MSG}${msg}`);
|
||||
}
|
||||
|
||||
Common.info = function(msg) {
|
||||
if (process.env.PM2_SILENT || process.env.PM2_PROGRAMMATIC === 'true') return false;
|
||||
return console.log(`${cst.PREFIX_MSG_INFO}${msg}`);
|
||||
}
|
||||
|
||||
Common.warn = function(msg) {
|
||||
if (process.env.PM2_SILENT || process.env.PM2_PROGRAMMATIC === 'true') return false;
|
||||
return console.log(`${cst.PREFIX_MSG_WARNING}${msg}`);
|
||||
}
|
||||
|
||||
Common.logMod = function(msg) {
|
||||
if (process.env.PM2_SILENT || process.env.PM2_PROGRAMMATIC === 'true') return false;
|
||||
return console.log(`${cst.PREFIX_MSG_MOD}${msg}`);
|
||||
}
|
||||
|
||||
Common.printOut = function() {
|
||||
if (process.env.PM2_SILENT === 'true' || process.env.PM2_PROGRAMMATIC === 'true') return false;
|
||||
return console.log.apply(console, arguments);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Raw extend
|
||||
*/
|
||||
Common.extend = function(destination, source) {
|
||||
if (typeof destination !== 'object') {
|
||||
destination = {};
|
||||
}
|
||||
if (!source || typeof source !== 'object') {
|
||||
return destination;
|
||||
}
|
||||
|
||||
Object.keys(source).forEach(function(new_key) {
|
||||
if (source[new_key] != '[object Object]')
|
||||
destination[new_key] = source[new_key];
|
||||
});
|
||||
|
||||
return destination;
|
||||
};
|
||||
|
||||
/**
|
||||
* This is useful when starting script programmatically
|
||||
*/
|
||||
Common.safeExtend = function(origin, add){
|
||||
if (!add || typeof add != 'object') return origin;
|
||||
|
||||
//Ignore PM2's set environment variables from the nested env
|
||||
var keysToIgnore = ['name', 'exec_mode', 'env', 'args', 'pm_cwd', 'exec_interpreter', 'pm_exec_path', 'node_args', 'pm_out_log_path', 'pm_err_log_path', 'pm_pid_path', 'pm_id', 'status', 'pm_uptime', 'created_at', 'windowsHide', 'username', 'merge_logs', 'kill_retry_time', 'prev_restart_delay', 'instance_var', 'unstable_restarts', 'restart_time', 'axm_actions', 'pmx_module', 'command', 'watch', 'filter_env', 'versioning', 'vizion_runing', 'MODULE_DEBUG', 'pmx', 'axm_options', 'created_at', 'watch', 'vizion', 'axm_dynamic', 'axm_monitor', 'instances', 'automation', 'autostart', 'autorestart', 'stop_exit_codes', 'unstable_restart', 'treekill', 'exit_code', 'vizion'];
|
||||
|
||||
var keys = Object.keys(add);
|
||||
var i = keys.length;
|
||||
while (i--) {
|
||||
//Only copy stuff into the env that we don't have already.
|
||||
if(keysToIgnore.indexOf(keys[i]) == -1 && add[keys[i]] != '[object Object]')
|
||||
origin[keys[i]] = add[keys[i]];
|
||||
}
|
||||
return origin;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Extend the app.env object of with the properties taken from the
|
||||
* app.env_[envName] and deploy configuration.
|
||||
* Also update current json attributes
|
||||
*
|
||||
* Used only for Configuration file processing
|
||||
*
|
||||
* @param {Object} app The app object.
|
||||
* @param {string} envName The given environment name.
|
||||
* @param {Object} deployConf Deployment configuration object (from JSON file or whatever).
|
||||
* @returns {Object} The app.env variables object.
|
||||
*/
|
||||
Common.mergeEnvironmentVariables = function(app_env, env_name, deploy_conf) {
|
||||
var app = fclone(app_env);
|
||||
|
||||
var new_conf = {
|
||||
env : {}
|
||||
}
|
||||
|
||||
// Stringify possible object
|
||||
for (var key in app.env) {
|
||||
if (typeof app.env[key] == 'object') {
|
||||
app.env[key] = JSON.stringify(app.env[key]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Extra configuration update
|
||||
*/
|
||||
Object.assign(new_conf, app);
|
||||
|
||||
if (env_name) {
|
||||
// First merge variables from deploy.production.env object as least priority.
|
||||
if (deploy_conf && deploy_conf[env_name] && deploy_conf[env_name]['env']) {
|
||||
Object.assign(new_conf.env, deploy_conf[env_name]['env']);
|
||||
}
|
||||
|
||||
Object.assign(new_conf.env, app.env);
|
||||
|
||||
// Then, last and highest priority, merge the app.env_production object.
|
||||
if ('env_' + env_name in app) {
|
||||
Object.assign(new_conf.env, app['env_' + env_name]);
|
||||
}
|
||||
else {
|
||||
Common.printOut(cst.PREFIX_MSG_WARNING + chalk.bold('Environment [%s] is not defined in process file'), env_name);
|
||||
}
|
||||
}
|
||||
|
||||
delete new_conf.exec_mode
|
||||
|
||||
var res = {
|
||||
current_conf: {}
|
||||
}
|
||||
|
||||
Object.assign(res, new_conf.env);
|
||||
Object.assign(res.current_conf, new_conf);
|
||||
|
||||
// #2541 force resolution of node interpreter
|
||||
if (app.exec_interpreter &&
|
||||
app.exec_interpreter.indexOf('@') > -1) {
|
||||
resolveNodeInterpreter(app);
|
||||
res.current_conf.exec_interpreter = app.exec_interpreter
|
||||
}
|
||||
|
||||
return res
|
||||
}
|
||||
|
||||
/**
|
||||
* This function will resolve paths, option and environment
|
||||
* CALLED before 'prepare' God call (=> PROCESS INITIALIZATION)
|
||||
* @method resolveAppAttributes
|
||||
* @param {Object} opts
|
||||
* @param {Object} opts.cwd
|
||||
* @param {Object} opts.pm2_home
|
||||
* @param {Object} appConf application configuration
|
||||
* @return app
|
||||
*/
|
||||
Common.resolveAppAttributes = function(opts, conf) {
|
||||
var conf_copy = fclone(conf);
|
||||
|
||||
var app = Common.prepareAppConf(opts, conf_copy);
|
||||
if (app instanceof Error) {
|
||||
throw new Error(app.message);
|
||||
}
|
||||
return app;
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify configurations
|
||||
* Called on EVERY Operation (start/restart/reload/stop...)
|
||||
* @param {Array} appConfs
|
||||
* @returns {Array}
|
||||
*/
|
||||
Common.verifyConfs = function(appConfs) {
|
||||
if (!appConfs || appConfs.length == 0) {
|
||||
return [];
|
||||
}
|
||||
|
||||
// Make sure it is an Array.
|
||||
appConfs = [].concat(appConfs);
|
||||
|
||||
var verifiedConf = [];
|
||||
|
||||
for (var i = 0; i < appConfs.length; i++) {
|
||||
var app = appConfs[i];
|
||||
|
||||
if (app.exec_mode)
|
||||
app.exec_mode = app.exec_mode.replace(/^(fork|cluster)$/, '$1_mode');
|
||||
|
||||
// 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
|
||||
}
|
||||
|
||||
if (!app.env) {
|
||||
app.env = {}
|
||||
}
|
||||
|
||||
// Render an app name if not existing.
|
||||
Common.renderApplicationName(app);
|
||||
|
||||
if (app.execute_command == true) {
|
||||
app.exec_mode = 'fork'
|
||||
delete app.execute_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 && cst.IS_WINDOWS === false) {
|
||||
var _script = app.script;
|
||||
|
||||
if (which('bash')) {
|
||||
app.script = 'bash';
|
||||
app.args = ['-c', _script];
|
||||
if (!app.name) {
|
||||
app.name = _script
|
||||
}
|
||||
}
|
||||
else if (which('sh')) {
|
||||
app.script = 'sh';
|
||||
app.args = ['-c', _script];
|
||||
if (!app.name) {
|
||||
app.name = _script
|
||||
}
|
||||
}
|
||||
else {
|
||||
warn('bash or sh not available in $PATH, keeping script as is')
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add log_date_format by default
|
||||
*/
|
||||
if (app.time || process.env.ASZ_MODE) {
|
||||
app.log_date_format = 'YYYY-MM-DDTHH:mm:ss'
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks + Resolve UID/GID
|
||||
* comes from pm2 --uid <> --gid <> or --user
|
||||
*/
|
||||
if (app.uid || app.gid || app.user) {
|
||||
// 1/ Check if windows
|
||||
if (cst.IS_WINDOWS === true) {
|
||||
Common.printError(cst.PREFIX_MSG_ERR + '--uid and --git does not works on windows');
|
||||
return new Error('--uid and --git does not works on windows');
|
||||
}
|
||||
|
||||
// 2/ Verify that user is root (todo: verify if other has right)
|
||||
if (process.env.NODE_ENV != 'test' && process.getuid && process.getuid() !== 0) {
|
||||
Common.printError(cst.PREFIX_MSG_ERR + 'To use --uid and --gid please run pm2 as root');
|
||||
return new Error('To use UID and GID please run PM2 as root');
|
||||
}
|
||||
|
||||
// 3/ Resolve user info via /etc/password
|
||||
var passwd = require('./tools/passwd.js')
|
||||
var users
|
||||
try {
|
||||
users = passwd.getUsers()
|
||||
} catch(e) {
|
||||
Common.printError(e);
|
||||
return new Error(e);
|
||||
}
|
||||
|
||||
var user_info = users[app.uid || app.user]
|
||||
if (!user_info) {
|
||||
Common.printError(`${cst.PREFIX_MSG_ERR} User ${app.uid || app.user} cannot be found`);
|
||||
return new Error(`${cst.PREFIX_MSG_ERR} User ${app.uid || app.user} cannot be found`);
|
||||
}
|
||||
|
||||
app.env.HOME = user_info.homedir
|
||||
app.uid = parseInt(user_info.userId)
|
||||
|
||||
// 4/ Resolve group id if gid is specified
|
||||
if (app.gid) {
|
||||
var groups
|
||||
try {
|
||||
groups = passwd.getGroups()
|
||||
} catch(e) {
|
||||
Common.printError(e);
|
||||
return new Error(e);
|
||||
}
|
||||
var group_info = groups[app.gid]
|
||||
if (!group_info) {
|
||||
Common.printError(`${cst.PREFIX_MSG_ERR} Group ${app.gid} cannot be found`);
|
||||
return new Error(`${cst.PREFIX_MSG_ERR} Group ${app.gid} cannot be found`);
|
||||
}
|
||||
app.gid = parseInt(group_info.id)
|
||||
} else {
|
||||
app.gid = parseInt(user_info.groupId)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Specific options of PM2.io
|
||||
*/
|
||||
if (process.env.PM2_DEEP_MONITORING) {
|
||||
app.deep_monitoring = true;
|
||||
}
|
||||
|
||||
if (app.automation == false) {
|
||||
app.pmx = false;
|
||||
}
|
||||
|
||||
if (app.disable_trace) {
|
||||
app.trace = false
|
||||
delete app.disable_trace;
|
||||
}
|
||||
|
||||
/**
|
||||
* Instances params
|
||||
*/
|
||||
if (app.instances == 'max') {
|
||||
app.instances = 0;
|
||||
}
|
||||
|
||||
if (typeof(app.instances) === 'string') {
|
||||
app.instances = parseInt(app.instances) || 0;
|
||||
}
|
||||
|
||||
if (app.exec_mode != 'cluster_mode' &&
|
||||
!app.instances &&
|
||||
typeof(app.merge_logs) == 'undefined') {
|
||||
app.merge_logs = true;
|
||||
}
|
||||
|
||||
var ret;
|
||||
|
||||
if (app.cron_restart) {
|
||||
if ((ret = Common.sink.determineCron(app)) instanceof Error)
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Now validation configuration
|
||||
*/
|
||||
var ret = Config.validateJSON(app);
|
||||
if (ret.errors && ret.errors.length > 0){
|
||||
ret.errors.forEach(function(err) { warn(err) });
|
||||
return new Error(ret.errors);
|
||||
}
|
||||
|
||||
verifiedConf.push(ret.config);
|
||||
}
|
||||
|
||||
return verifiedConf;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get current username
|
||||
* Called on EVERY starting app
|
||||
*
|
||||
* @returns {String}
|
||||
*/
|
||||
Common.getCurrentUsername = function(){
|
||||
var current_user = '';
|
||||
|
||||
if (os.userInfo) {
|
||||
try {
|
||||
current_user = os.userInfo().username;
|
||||
} catch (err) {
|
||||
// For the case of unhandled error for uv_os_get_passwd
|
||||
// https://github.com/Unitech/pm2/issues/3184
|
||||
}
|
||||
}
|
||||
|
||||
if(current_user === '') {
|
||||
current_user = process.env.USER || process.env.LNAME || process.env.USERNAME || process.env.SUDO_USER || process.env.C9_USER || process.env.LOGNAME;
|
||||
}
|
||||
|
||||
return current_user;
|
||||
}
|
||||
|
||||
/**
|
||||
* Render an app name if not existing.
|
||||
* @param {Object} conf
|
||||
*/
|
||||
Common.renderApplicationName = function(conf){
|
||||
if (!conf.name && conf.script){
|
||||
conf.name = conf.script !== undefined ? path.basename(conf.script) : 'undefined';
|
||||
var lastDot = conf.name.lastIndexOf('.');
|
||||
if (lastDot > 0){
|
||||
conf.name = conf.name.slice(0, lastDot);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Show warnings
|
||||
* @param {String} warning
|
||||
*/
|
||||
function warn(warning){
|
||||
Common.printOut(cst.PREFIX_MSG_WARNING + warning);
|
||||
}
|
||||
304
api.hyungi.net/node_modules/pm2/lib/Configuration.js
generated
vendored
Normal file
304
api.hyungi.net/node_modules/pm2/lib/Configuration.js
generated
vendored
Normal file
@@ -0,0 +1,304 @@
|
||||
/**
|
||||
* Copyright 2013-2022 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 Configuration = module.exports = {};
|
||||
|
||||
var fs = require('fs');
|
||||
|
||||
var Common = require('./Common');
|
||||
var eachSeries = require('async/eachSeries');
|
||||
var cst = require('../constants.js');
|
||||
|
||||
function splitKey(key) {
|
||||
var values = [key];
|
||||
|
||||
if (key.indexOf('.') > -1)
|
||||
values = key.match(/(?:[^."]+|"[^"]*")+/g).map(function(dt) { return dt.replace(/"/g, '') });
|
||||
else if (key.indexOf(':') > -1)
|
||||
values = key.match(/(?:[^:"]+|"[^"]*")+/g).map(function(dt) { return dt.replace(/"/g, '') });
|
||||
|
||||
return values;
|
||||
}
|
||||
|
||||
function serializeConfiguration(json_conf) {
|
||||
return JSON.stringify(json_conf, null, 4)
|
||||
}
|
||||
|
||||
Configuration.set = function(key, value, cb) {
|
||||
fs.readFile(cst.PM2_MODULE_CONF_FILE, function(err, data) {
|
||||
if (err) return cb(err);
|
||||
|
||||
var json_conf = JSON.parse(data);
|
||||
|
||||
var values = splitKey(key);
|
||||
|
||||
if (values.length > 0) {
|
||||
var levels = values;
|
||||
|
||||
var tmp = json_conf;
|
||||
|
||||
levels.forEach(function(key, index) {
|
||||
if (index == levels.length -1)
|
||||
tmp[key] = value;
|
||||
else if (!tmp[key]) {
|
||||
tmp[key] = {};
|
||||
tmp = tmp[key];
|
||||
}
|
||||
else {
|
||||
if (typeof(tmp[key]) != 'object')
|
||||
tmp[key] = {};
|
||||
tmp = tmp[key];
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
else {
|
||||
if (json_conf[key] && typeof(json_conf[key]) === 'string')
|
||||
Common.printOut(cst.PREFIX_MSG + 'Replacing current value key %s by %s', key, value);
|
||||
|
||||
json_conf[key] = value;
|
||||
}
|
||||
|
||||
fs.writeFile(cst.PM2_MODULE_CONF_FILE, serializeConfiguration(json_conf), function(err, data) {
|
||||
if (err) return cb(err);
|
||||
|
||||
return cb(null, json_conf);
|
||||
});
|
||||
return false;
|
||||
});
|
||||
};
|
||||
|
||||
Configuration.unset = function(key, cb) {
|
||||
fs.readFile(cst.PM2_MODULE_CONF_FILE, function(err, data) {
|
||||
if (err) return cb(err);
|
||||
|
||||
var json_conf = JSON.parse(data);
|
||||
|
||||
var values = splitKey(key);
|
||||
|
||||
if (values.length > 0) {
|
||||
var levels = values;
|
||||
|
||||
var tmp = json_conf;
|
||||
|
||||
levels.forEach(function(key, index) {
|
||||
if (index == levels.length -1)
|
||||
delete tmp[key];
|
||||
else if (!tmp[key]) {
|
||||
tmp[key] = {};
|
||||
tmp = tmp[key];
|
||||
}
|
||||
else {
|
||||
if (typeof(tmp[key]) != 'object')
|
||||
tmp[key] = {};
|
||||
tmp = tmp[key];
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
else
|
||||
delete json_conf[key];
|
||||
|
||||
if (err) return cb(err);
|
||||
|
||||
if (key === 'all')
|
||||
json_conf = {};
|
||||
|
||||
fs.writeFile(cst.PM2_MODULE_CONF_FILE, serializeConfiguration(json_conf), function(err, data) {
|
||||
if (err) return cb(err);
|
||||
|
||||
return cb(null, json_conf);
|
||||
});
|
||||
return false;
|
||||
});
|
||||
}
|
||||
|
||||
Configuration.setSyncIfNotExist = function(key, value) {
|
||||
try {
|
||||
var conf = JSON.parse(fs.readFileSync(cst.PM2_MODULE_CONF_FILE));
|
||||
} catch(e) {
|
||||
return null;
|
||||
}
|
||||
|
||||
var values = splitKey(key);
|
||||
var exists = false;
|
||||
|
||||
if (values.length > 1 && conf && conf[values[0]]) {
|
||||
exists = Object.keys(conf[values[0]]).some(function(key) {
|
||||
if (key == values[1])
|
||||
return true;
|
||||
return false;
|
||||
});
|
||||
}
|
||||
|
||||
if (exists === false)
|
||||
return Configuration.setSync(key, value);
|
||||
|
||||
return null;
|
||||
};
|
||||
|
||||
Configuration.setSync = function(key, value) {
|
||||
try {
|
||||
var data = fs.readFileSync(cst.PM2_MODULE_CONF_FILE);
|
||||
} catch(e) {
|
||||
return null;
|
||||
}
|
||||
|
||||
var json_conf = JSON.parse(data);
|
||||
|
||||
var values = splitKey(key);
|
||||
|
||||
if (values.length > 0) {
|
||||
var levels = values;
|
||||
|
||||
var tmp = json_conf;
|
||||
|
||||
levels.forEach(function(key, index) {
|
||||
if (index == levels.length -1)
|
||||
tmp[key] = value;
|
||||
else if (!tmp[key]) {
|
||||
tmp[key] = {};
|
||||
tmp = tmp[key];
|
||||
}
|
||||
else {
|
||||
if (typeof(tmp[key]) != 'object')
|
||||
tmp[key] = {};
|
||||
tmp = tmp[key];
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
else {
|
||||
if (json_conf[key] && typeof(json_conf[key]) === 'string')
|
||||
Common.printOut(cst.PREFIX_MSG + 'Replacing current value key %s by %s', key, value);
|
||||
|
||||
json_conf[key] = value;
|
||||
}
|
||||
|
||||
if (key === 'all')
|
||||
json_conf = {};
|
||||
|
||||
try {
|
||||
fs.writeFileSync(cst.PM2_MODULE_CONF_FILE, serializeConfiguration(json_conf));
|
||||
return json_conf;
|
||||
} catch(e) {
|
||||
console.error(e.message);
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
Configuration.unsetSync = function(key) {
|
||||
try {
|
||||
var data = fs.readFileSync(cst.PM2_MODULE_CONF_FILE);
|
||||
} catch(e) {
|
||||
return null;
|
||||
}
|
||||
|
||||
var json_conf = JSON.parse(data);
|
||||
|
||||
var values = splitKey(key);
|
||||
|
||||
if (values.length > 0) {
|
||||
var levels = values;
|
||||
|
||||
var tmp = json_conf;
|
||||
|
||||
levels.forEach(function(key, index) {
|
||||
if (index == levels.length -1)
|
||||
delete tmp[key];
|
||||
else if (!tmp[key]) {
|
||||
tmp[key] = {};
|
||||
tmp = tmp[key];
|
||||
}
|
||||
else {
|
||||
if (typeof(tmp[key]) != 'object')
|
||||
tmp[key] = {};
|
||||
tmp = tmp[key];
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
else
|
||||
delete json_conf[key];
|
||||
|
||||
if (key === 'all')
|
||||
json_conf = {};
|
||||
|
||||
try {
|
||||
fs.writeFileSync(cst.PM2_MODULE_CONF_FILE, serializeConfiguration(json_conf));
|
||||
} catch(e) {
|
||||
console.error(e.message);
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
Configuration.multiset = function(serial, cb) {
|
||||
var arrays = [];
|
||||
serial = serial.match(/(?:[^ "]+|"[^"]*")+/g);
|
||||
|
||||
while (serial.length > 0)
|
||||
arrays.push(serial.splice(0, 2));
|
||||
|
||||
eachSeries(arrays, function(el, next) {
|
||||
Configuration.set(el[0], el[1], next);
|
||||
}, cb);
|
||||
};
|
||||
|
||||
Configuration.get = function(key, cb) {
|
||||
Configuration.getAll(function(err, data) {
|
||||
var climb = splitKey(key);
|
||||
|
||||
climb.some(function(val) {
|
||||
if (!data[val]) {
|
||||
data = null;
|
||||
return true;
|
||||
}
|
||||
data = data[val];
|
||||
return false;
|
||||
});
|
||||
|
||||
if (!data) return cb({err : 'Unknown key'}, null);
|
||||
return cb(null, data);
|
||||
});
|
||||
};
|
||||
|
||||
Configuration.getSync = function(key) {
|
||||
try {
|
||||
var data = Configuration.getAllSync();
|
||||
} catch(e) {
|
||||
return null;
|
||||
}
|
||||
|
||||
var climb = splitKey(key);
|
||||
|
||||
climb.some(function(val) {
|
||||
if (!data[val]) {
|
||||
data = null;
|
||||
return true;
|
||||
}
|
||||
data = data[val];
|
||||
return false;
|
||||
});
|
||||
|
||||
if (!data) return null;
|
||||
return data;
|
||||
};
|
||||
|
||||
Configuration.getAll = function(cb) {
|
||||
fs.readFile(cst.PM2_MODULE_CONF_FILE, function(err, data) {
|
||||
if (err) return cb(err);
|
||||
return cb(null, JSON.parse(data));
|
||||
});
|
||||
};
|
||||
|
||||
Configuration.getAllSync = function() {
|
||||
try {
|
||||
return JSON.parse(fs.readFileSync(cst.PM2_MODULE_CONF_FILE));
|
||||
} catch(e) {
|
||||
console.error(e.stack || e);
|
||||
return {};
|
||||
}
|
||||
};
|
||||
455
api.hyungi.net/node_modules/pm2/lib/Daemon.js
generated
vendored
Normal file
455
api.hyungi.net/node_modules/pm2/lib/Daemon.js
generated
vendored
Normal file
@@ -0,0 +1,455 @@
|
||||
/**
|
||||
* Copyright 2013-2022 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')('pm2:daemon');
|
||||
var pkg = require('../package.json');
|
||||
var cst = require('../constants.js');
|
||||
var rpc = require('pm2-axon-rpc');
|
||||
var axon = require('pm2-axon');
|
||||
var domain = require('domain');
|
||||
var Utility = require('./Utility.js');
|
||||
var util = require('util');
|
||||
var fs = require('fs');
|
||||
var God = require('./God');
|
||||
var eachLimit = require('async/eachLimit');
|
||||
var fmt = require('./tools/fmt.js');
|
||||
var semver = require('semver');
|
||||
|
||||
var Daemon = module.exports = function(opts) {
|
||||
if (!opts) opts = {};
|
||||
|
||||
this.ignore_signals = opts.ignore_signals || false;
|
||||
this.rpc_socket_ready = false;
|
||||
this.pub_socket_ready = false;
|
||||
|
||||
this.pub_socket_file = opts.pub_socket_file || cst.DAEMON_PUB_PORT;
|
||||
this.rpc_socket_file = opts.rpc_socket_file || cst.DAEMON_RPC_PORT;
|
||||
|
||||
this.pid_path = opts.pid_file || cst.PM2_PID_FILE_PATH;
|
||||
};
|
||||
|
||||
Daemon.prototype.start = function() {
|
||||
var that = this;
|
||||
var d = domain.create();
|
||||
|
||||
d.once('error', function(err) {
|
||||
fmt.sep();
|
||||
fmt.title('PM2 global error caught');
|
||||
fmt.field('Time', new Date());
|
||||
console.error(err.message);
|
||||
console.error(err.stack);
|
||||
fmt.sep();
|
||||
|
||||
console.error('[PM2] Resurrecting PM2');
|
||||
|
||||
var path = cst.IS_WINDOWS ? __dirname + '/../bin/pm2' : process.env['_'];
|
||||
var fork_new_pm2 = require('child_process').spawn('node', [path, 'update'], {
|
||||
detached: true,
|
||||
windowsHide: true,
|
||||
stdio: 'inherit'
|
||||
});
|
||||
|
||||
fork_new_pm2.on('close', function() {
|
||||
console.log('PM2 successfully forked');
|
||||
process.exit(0);
|
||||
})
|
||||
|
||||
});
|
||||
|
||||
d.run(function() {
|
||||
that.innerStart();
|
||||
});
|
||||
}
|
||||
|
||||
Daemon.prototype.innerStart = function(cb) {
|
||||
var that = this;
|
||||
|
||||
if (!cb) cb = function() {
|
||||
fmt.sep();
|
||||
fmt.title('New PM2 Daemon started');
|
||||
fmt.field('Time', new Date());
|
||||
fmt.field('PM2 version', pkg.version);
|
||||
fmt.field('Node.js version', process.versions.node);
|
||||
fmt.field('Current arch', process.arch);
|
||||
fmt.field('PM2 home', cst.PM2_HOME);
|
||||
fmt.field('PM2 PID file', that.pid_path);
|
||||
fmt.field('RPC socket file', that.rpc_socket_file);
|
||||
fmt.field('BUS socket file', that.pub_socket_file);
|
||||
fmt.field('Application log path', cst.DEFAULT_LOG_PATH);
|
||||
fmt.field('Worker Interval', cst.WORKER_INTERVAL);
|
||||
fmt.field('Process dump file', cst.DUMP_FILE_PATH);
|
||||
fmt.field('Concurrent actions', cst.CONCURRENT_ACTIONS);
|
||||
fmt.field('SIGTERM timeout', cst.KILL_TIMEOUT);
|
||||
fmt.sep();
|
||||
};
|
||||
|
||||
// Write Daemon PID into file
|
||||
try {
|
||||
fs.writeFileSync(that.pid_path, process.pid.toString());
|
||||
} catch (e) {
|
||||
console.error(e.stack || e);
|
||||
}
|
||||
|
||||
if (this.ignore_signals != true)
|
||||
this.handleSignals();
|
||||
|
||||
/**
|
||||
* Pub system for real time notifications
|
||||
*/
|
||||
this.pub = axon.socket('pub-emitter');
|
||||
|
||||
this.pub_socket = this.pub.bind(this.pub_socket_file);
|
||||
|
||||
this.pub_socket.once('bind', function() {
|
||||
fs.chmod(that.pub_socket_file, '775', function(e) {
|
||||
if (e) console.error(e);
|
||||
|
||||
try {
|
||||
if (process.env.PM2_SOCKET_USER && process.env.PM2_SOCKET_GROUP)
|
||||
fs.chown(that.pub_socket_file,
|
||||
parseInt(process.env.PM2_SOCKET_USER),
|
||||
parseInt(process.env.PM2_SOCKET_GROUP), function(e) {
|
||||
if (e) console.error(e);
|
||||
});
|
||||
} catch(e) {
|
||||
console.error(e);
|
||||
}
|
||||
});
|
||||
|
||||
that.pub_socket_ready = true;
|
||||
that.sendReady(cb);
|
||||
});
|
||||
|
||||
/**
|
||||
* Rep/Req - RPC system to interact with God
|
||||
*/
|
||||
this.rep = axon.socket('rep');
|
||||
|
||||
var server = new rpc.Server(this.rep);
|
||||
|
||||
this.rpc_socket = this.rep.bind(this.rpc_socket_file);
|
||||
|
||||
this.rpc_socket.once('bind', function() {
|
||||
fs.chmod(that.rpc_socket_file, '775', function(e) {
|
||||
if (e) console.error(e);
|
||||
|
||||
try {
|
||||
if (process.env.PM2_SOCKET_USER && process.env.PM2_SOCKET_GROUP)
|
||||
fs.chown(that.rpc_socket_file,
|
||||
parseInt(process.env.PM2_SOCKET_USER),
|
||||
parseInt(process.env.PM2_SOCKET_GROUP), function(e) {
|
||||
if (e) console.error(e);
|
||||
});
|
||||
} catch(e) {
|
||||
console.error(e);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
that.rpc_socket_ready = true;
|
||||
that.sendReady(cb);
|
||||
});
|
||||
|
||||
|
||||
/**
|
||||
* Memory Snapshot
|
||||
*/
|
||||
function profile(type, msg, cb) {
|
||||
if (semver.satisfies(process.version, '< 8'))
|
||||
return cb(null, { error: 'Node.js is not on right version' })
|
||||
|
||||
var cmd
|
||||
|
||||
if (type === 'cpu') {
|
||||
cmd = {
|
||||
enable: 'Profiler.enable',
|
||||
start: 'Profiler.start',
|
||||
stop: 'Profiler.stop',
|
||||
disable: 'Profiler.disable'
|
||||
}
|
||||
}
|
||||
if (type == 'mem') {
|
||||
cmd = {
|
||||
enable: 'HeapProfiler.enable',
|
||||
start: 'HeapProfiler.startSampling',
|
||||
stop: 'HeapProfiler.stopSampling',
|
||||
disable: 'HeapProfiler.disable'
|
||||
}
|
||||
}
|
||||
|
||||
const inspector = require('inspector')
|
||||
var session = new inspector.Session()
|
||||
|
||||
session.connect()
|
||||
|
||||
var timeout = msg.timeout || 5000
|
||||
|
||||
session.post(cmd.enable, (err, data) => {
|
||||
if (err) return cb(null, { error: err.message || err })
|
||||
|
||||
console.log(`Starting ${cmd.start}`)
|
||||
session.post(cmd.start, (err, data) => {
|
||||
if (err) return cb(null, { error: err.message || err })
|
||||
|
||||
setTimeout(() => {
|
||||
session.post(cmd.stop, (err, data) => {
|
||||
if (err) return cb(null, { error: err.message || err })
|
||||
const profile = data.profile
|
||||
|
||||
console.log(`Stopping ${cmd.stop}`)
|
||||
session.post(cmd.disable)
|
||||
|
||||
fs.writeFile(msg.pwd, JSON.stringify(profile), (err) => {
|
||||
if (err) return cb(null, { error: err.message || err })
|
||||
return cb(null, { file : msg.pwd })
|
||||
})
|
||||
})
|
||||
}, timeout)
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
server.expose({
|
||||
killMe : that.close.bind(this),
|
||||
profileCPU : profile.bind(this, 'cpu'),
|
||||
profileMEM : profile.bind(this, 'mem'),
|
||||
prepare : God.prepare,
|
||||
getMonitorData : God.getMonitorData,
|
||||
|
||||
startProcessId : God.startProcessId,
|
||||
stopProcessId : God.stopProcessId,
|
||||
restartProcessId : God.restartProcessId,
|
||||
deleteProcessId : God.deleteProcessId,
|
||||
|
||||
sendLineToStdin : God.sendLineToStdin,
|
||||
softReloadProcessId : God.softReloadProcessId,
|
||||
reloadProcessId : God.reloadProcessId,
|
||||
duplicateProcessId : God.duplicateProcessId,
|
||||
resetMetaProcessId : God.resetMetaProcessId,
|
||||
stopWatch : God.stopWatch,
|
||||
startWatch : God.startWatch,
|
||||
toggleWatch : God.toggleWatch,
|
||||
notifyByProcessId : God.notifyByProcessId,
|
||||
|
||||
notifyKillPM2 : God.notifyKillPM2,
|
||||
monitor : God.monitor,
|
||||
unmonitor : God.unmonitor,
|
||||
|
||||
msgProcess : God.msgProcess,
|
||||
sendDataToProcessId : God.sendDataToProcessId,
|
||||
sendSignalToProcessId : God.sendSignalToProcessId,
|
||||
sendSignalToProcessName : God.sendSignalToProcessName,
|
||||
|
||||
ping : God.ping,
|
||||
getVersion : God.getVersion,
|
||||
getReport : God.getReport,
|
||||
reloadLogs : God.reloadLogs
|
||||
});
|
||||
|
||||
this.startLogic();
|
||||
}
|
||||
|
||||
Daemon.prototype.close = function(opts, cb) {
|
||||
var that = this;
|
||||
|
||||
God.bus.emit('pm2:kill', {
|
||||
status : 'killed',
|
||||
msg : 'pm2 has been killed via CLI'
|
||||
});
|
||||
|
||||
if (God.system_infos_proc !== null)
|
||||
God.system_infos_proc.kill()
|
||||
|
||||
/**
|
||||
* Cleanly kill pm2
|
||||
*/
|
||||
that.rpc_socket.close(function() {
|
||||
that.pub_socket.close(function() {
|
||||
|
||||
// notify cli that the daemon is shuting down (only under unix since windows doesnt handle signals)
|
||||
if (cst.IS_WINDOWS === false) {
|
||||
try {
|
||||
process.kill(parseInt(opts.pid), 'SIGQUIT');
|
||||
} catch(e) {
|
||||
console.error('Could not send SIGQUIT to CLI');
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
fs.unlinkSync(that.pid_path);
|
||||
} catch(e) {}
|
||||
|
||||
console.log('PM2 successfully stopped');
|
||||
setTimeout(function() {
|
||||
process.exit(cst.SUCCESS_EXIT);
|
||||
}, 2);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
Daemon.prototype.handleSignals = function() {
|
||||
var that = this;
|
||||
|
||||
process.on('SIGTERM', that.gracefullExit.bind(this));
|
||||
process.on('SIGINT', that.gracefullExit.bind(this));
|
||||
process.on('SIGHUP', function() {});
|
||||
process.on('SIGQUIT', that.gracefullExit.bind(this));
|
||||
process.on('SIGUSR2', function() {
|
||||
God.reloadLogs({}, function() {});
|
||||
});
|
||||
}
|
||||
|
||||
Daemon.prototype.sendReady = function(cb) {
|
||||
// Send ready message to Client
|
||||
if (this.rpc_socket_ready == true && this.pub_socket_ready == true) {
|
||||
cb(null, {
|
||||
pid : process.pid,
|
||||
pm2_version : pkg.version
|
||||
});
|
||||
if (typeof(process.send) != 'function')
|
||||
return false;
|
||||
|
||||
process.send({
|
||||
online : true,
|
||||
success : true,
|
||||
pid : process.pid,
|
||||
pm2_version : pkg.version
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
Daemon.prototype.gracefullExit = function() {
|
||||
var that = this;
|
||||
|
||||
// never execute multiple gracefullExit simultaneously
|
||||
// this can lead to loss of some apps in dump file
|
||||
if (this.isExiting) return
|
||||
|
||||
this.isExiting = true
|
||||
|
||||
God.bus.emit('pm2:kill', {
|
||||
status : 'killed',
|
||||
msg : 'pm2 has been killed by SIGNAL'
|
||||
});
|
||||
|
||||
console.log('pm2 has been killed by signal, dumping process list before exit...');
|
||||
|
||||
if (God.system_infos_proc !== null)
|
||||
God.system_infos_proc.kill()
|
||||
|
||||
God.dumpProcessList(function() {
|
||||
|
||||
var processes = God.getFormatedProcesses();
|
||||
|
||||
eachLimit(processes, 1, function(proc, next) {
|
||||
console.log('Deleting process %s', proc.pm2_env.pm_id);
|
||||
God.deleteProcessId(proc.pm2_env.pm_id, function() {
|
||||
return next();
|
||||
});
|
||||
}, function(err) {
|
||||
try {
|
||||
fs.unlinkSync(that.pid_path);
|
||||
} catch(e) {}
|
||||
setTimeout(function() {
|
||||
that.isExiting = false
|
||||
console.log('Exited peacefully');
|
||||
process.exit(cst.SUCCESS_EXIT);
|
||||
}, 2);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
Daemon.prototype.startLogic = function() {
|
||||
var that = this;
|
||||
|
||||
/**
|
||||
* Action treatment specifics
|
||||
* Attach actions to pm2_env.axm_actions variables (name + options)
|
||||
*/
|
||||
God.bus.on('axm:action', function axmActions(msg) {
|
||||
var pm2_env = msg.process;
|
||||
var exists = false;
|
||||
var axm_action = msg.data;
|
||||
|
||||
if (!pm2_env || !God.clusters_db[pm2_env.pm_id])
|
||||
return console.error('AXM ACTION Unknown id %s', pm2_env.pm_id);
|
||||
|
||||
if (!God.clusters_db[pm2_env.pm_id].pm2_env.axm_actions)
|
||||
God.clusters_db[pm2_env.pm_id].pm2_env.axm_actions = [];
|
||||
|
||||
God.clusters_db[pm2_env.pm_id].pm2_env.axm_actions.forEach(function(actions) {
|
||||
if (actions.action_name == axm_action.action_name)
|
||||
exists = true;
|
||||
});
|
||||
|
||||
if (exists === false) {
|
||||
debug('Adding action', axm_action);
|
||||
God.clusters_db[pm2_env.pm_id].pm2_env.axm_actions.push(axm_action);
|
||||
}
|
||||
msg = null;
|
||||
});
|
||||
|
||||
/**
|
||||
* Configure module
|
||||
*/
|
||||
God.bus.on('axm:option:configuration', function axmMonitor(msg) {
|
||||
if (!msg.process)
|
||||
return console.error('[axm:option:configuration] no process defined');
|
||||
|
||||
if (!God.clusters_db[msg.process.pm_id])
|
||||
return console.error('[axm:option:configuration] Unknown id %s', msg.process.pm_id);
|
||||
|
||||
try {
|
||||
// Application Name nverride
|
||||
if (msg.data.name)
|
||||
God.clusters_db[msg.process.pm_id].pm2_env.name = msg.data.name;
|
||||
|
||||
Object.keys(msg.data).forEach(function(conf_key) {
|
||||
God.clusters_db[msg.process.pm_id].pm2_env.axm_options[conf_key] = Utility.clone(msg.data[conf_key]);
|
||||
});
|
||||
} catch(e) {
|
||||
console.error(e.stack || e);
|
||||
}
|
||||
msg = null;
|
||||
});
|
||||
|
||||
/**
|
||||
* Process monitoring data (probes)
|
||||
*/
|
||||
God.bus.on('axm:monitor', function axmMonitor(msg) {
|
||||
if (!msg.process)
|
||||
return console.error('[axm:monitor] no process defined');
|
||||
|
||||
if (!msg.process || !God.clusters_db[msg.process.pm_id])
|
||||
return console.error('AXM MONITOR Unknown id %s', msg.process.pm_id);
|
||||
|
||||
Object.assign(God.clusters_db[msg.process.pm_id].pm2_env.axm_monitor, Utility.clone(msg.data));
|
||||
msg = null;
|
||||
});
|
||||
|
||||
/**
|
||||
* Broadcast messages
|
||||
*/
|
||||
God.bus.onAny(function(event, data_v) {
|
||||
if (['axm:action',
|
||||
'axm:monitor',
|
||||
'axm:option:setPID',
|
||||
'axm:option:configuration'].indexOf(event) > -1) {
|
||||
data_v = null;
|
||||
return false;
|
||||
}
|
||||
that.pub.emit(event, Utility.clone(data_v));
|
||||
data_v = null;
|
||||
});
|
||||
};
|
||||
|
||||
if (require.main === module) {
|
||||
process.title = process.env.PM2_DAEMON_TITLE || 'PM2 v' + pkg.version + ': God Daemon (' + process.env.PM2_HOME + ')';
|
||||
|
||||
var daemon = new Daemon();
|
||||
|
||||
daemon.start();
|
||||
}
|
||||
37
api.hyungi.net/node_modules/pm2/lib/Event.js
generated
vendored
Normal file
37
api.hyungi.net/node_modules/pm2/lib/Event.js
generated
vendored
Normal file
@@ -0,0 +1,37 @@
|
||||
/**
|
||||
* Copyright 2013-2022 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 Utility = require('./Utility.js');
|
||||
|
||||
module.exports = function(God) {
|
||||
|
||||
God.notify = function(action_name, data, manually) {
|
||||
God.bus.emit('process:event', {
|
||||
event : action_name,
|
||||
manually : typeof(manually) == 'undefined' ? false : true,
|
||||
process : Utility.formatCLU(data),
|
||||
at : Utility.getDate()
|
||||
});
|
||||
};
|
||||
|
||||
God.notifyByProcessId = function(opts, cb) {
|
||||
if (typeof(opts.id) === 'undefined') { return cb(new Error('process id missing')); }
|
||||
var proc = God.clusters_db[opts.id];
|
||||
if (!proc) { return cb(new Error('process id doesnt exists')); }
|
||||
|
||||
God.bus.emit('process:event', {
|
||||
event : opts.action_name,
|
||||
manually : typeof(opts.manually) == 'undefined' ? false : true,
|
||||
process : Utility.formatCLU(proc),
|
||||
at : Utility.getDate()
|
||||
});
|
||||
|
||||
process.nextTick(function() {
|
||||
return cb ? cb(null) : false;
|
||||
});
|
||||
return false;
|
||||
};
|
||||
};
|
||||
588
api.hyungi.net/node_modules/pm2/lib/God.js
generated
vendored
Normal file
588
api.hyungi.net/node_modules/pm2/lib/God.js
generated
vendored
Normal file
@@ -0,0 +1,588 @@
|
||||
/**
|
||||
* Copyright 2013-2022 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.
|
||||
*/
|
||||
|
||||
/******************************
|
||||
* ______ _______ ______
|
||||
* | __ \ | |__ |
|
||||
* | __/ | __|
|
||||
* |___| |__|_|__|______|
|
||||
*
|
||||
* Main Daemon side file
|
||||
*
|
||||
******************************/
|
||||
|
||||
var cluster = require('cluster');
|
||||
var numCPUs = require('os').cpus() ? require('os').cpus().length : 1;
|
||||
var path = require('path');
|
||||
var EventEmitter2 = require('eventemitter2').EventEmitter2;
|
||||
var fs = require('fs');
|
||||
var vizion = require('vizion');
|
||||
var debug = require('debug')('pm2:god');
|
||||
var Utility = require('./Utility');
|
||||
var cst = require('../constants.js');
|
||||
var timesLimit = require('async/timesLimit');
|
||||
var Configuration = require('./Configuration.js');
|
||||
|
||||
/**
|
||||
* Override cluster module configuration
|
||||
*/
|
||||
cluster.setupMaster({
|
||||
windowsHide: true,
|
||||
exec : path.resolve(path.dirname(module.filename), 'ProcessContainer.js')
|
||||
});
|
||||
|
||||
/**
|
||||
* Expose God
|
||||
*/
|
||||
var God = module.exports = {
|
||||
next_id : 0,
|
||||
clusters_db : {},
|
||||
configuration: {},
|
||||
started_at : Date.now(),
|
||||
system_infos_proc: null,
|
||||
system_infos: null,
|
||||
bus : new EventEmitter2({
|
||||
wildcard: true,
|
||||
delimiter: ':',
|
||||
maxListeners: 1000
|
||||
})
|
||||
};
|
||||
|
||||
Utility.overrideConsole(God.bus);
|
||||
|
||||
/**
|
||||
* Populate God namespace
|
||||
*/
|
||||
require('./Event.js')(God);
|
||||
require('./God/Methods.js')(God);
|
||||
require('./God/ForkMode.js')(God);
|
||||
require('./God/ClusterMode.js')(God);
|
||||
require('./God/Reload')(God);
|
||||
require('./God/ActionMethods')(God);
|
||||
require('./Watcher')(God);
|
||||
|
||||
God.init = function() {
|
||||
require('./Worker.js')(this)
|
||||
God.system_infos_proc = null
|
||||
|
||||
this.configuration = Configuration.getSync('pm2')
|
||||
|
||||
setTimeout(function() {
|
||||
God.Worker.start()
|
||||
}, 500)
|
||||
}
|
||||
|
||||
God.writeExitSeparator = function(pm2_env, code, signal) {
|
||||
try {
|
||||
var exit_sep = `[PM2][${new Date().toISOString()}] app exited`
|
||||
if (code)
|
||||
exit_sep += `itself with exit code: ${code}`
|
||||
if (signal)
|
||||
exit_sep += `by an external signal: ${signal}`
|
||||
exit_sep += '\n'
|
||||
|
||||
if (pm2_env.pm_out_log_path)
|
||||
fs.writeFileSync(pm2_env.pm_out_log_path, exit_sep)
|
||||
if (pm2_env.pm_err_log_path)
|
||||
fs.writeFileSync(pm2_env.pm_err_log_path, exit_sep)
|
||||
if (pm2_env.pm_log_path)
|
||||
fs.writeFileSync(pm2_env.pm_log_path, exit_sep)
|
||||
} catch(e) {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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;
|
||||
if (env.env && env.env.vizion_running) env.env.vizion_running = false;
|
||||
|
||||
if (env.status == cst.STOPPED_STATUS) {
|
||||
env.pm_id = God.getNewId()
|
||||
var clu = {
|
||||
pm2_env : env,
|
||||
process: {
|
||||
}
|
||||
}
|
||||
God.clusters_db[env.pm_id] = clu
|
||||
God.registerCron(env)
|
||||
return cb(null, [ God.clusters_db[env.pm_id] ])
|
||||
}
|
||||
|
||||
return God.executeApp(env, function (err, clu) {
|
||||
if (err) return cb(err);
|
||||
God.notify('start', clu, true);
|
||||
return cb(null, [ Utility.clone(clu) ]);
|
||||
});
|
||||
}
|
||||
|
||||
// find how many replicate the user want
|
||||
env.instances = parseInt(env.instances);
|
||||
if (env.instances === 0) {
|
||||
env.instances = numCPUs;
|
||||
} else if (env.instances < 0) {
|
||||
env.instances += numCPUs;
|
||||
}
|
||||
if (env.instances <= 0) {
|
||||
env.instances = 1;
|
||||
}
|
||||
|
||||
timesLimit(env.instances, 1, function (n, next) {
|
||||
env.vizion_running = false;
|
||||
if (env.env && env.env.vizion_running) {
|
||||
env.env.vizion_running = false;
|
||||
}
|
||||
|
||||
God.injectVariables(env, function inject (err, _env) {
|
||||
if (err) return next(err);
|
||||
return God.executeApp(Utility.clone(_env), function (err, clu) {
|
||||
if (err) return next(err);
|
||||
God.notify('start', clu, true);
|
||||
// here call next wihtout an array because
|
||||
// async.times aggregate the result into an array
|
||||
return next(null, Utility.clone(clu));
|
||||
});
|
||||
});
|
||||
}, cb);
|
||||
};
|
||||
|
||||
/**
|
||||
* Launch the specified script (present in env)
|
||||
* @api private
|
||||
* @method executeApp
|
||||
* @param {Mixed} env
|
||||
* @param {Function} cb
|
||||
* @return Literal
|
||||
*/
|
||||
God.executeApp = function executeApp(env, cb) {
|
||||
var env_copy = Utility.clone(env);
|
||||
|
||||
Utility.extend(env_copy, env_copy.env);
|
||||
|
||||
env_copy['status'] = env.autostart ? cst.LAUNCHING_STATUS : cst.STOPPED_STATUS;
|
||||
env_copy['pm_uptime'] = Date.now();
|
||||
env_copy['axm_actions'] = [];
|
||||
env_copy['axm_monitor'] = {};
|
||||
env_copy['axm_options'] = {};
|
||||
env_copy['axm_dynamic'] = {};
|
||||
env_copy['vizion_running'] =
|
||||
env_copy['vizion_running'] !== undefined ? env_copy['vizion_running'] : false;
|
||||
|
||||
if (!env_copy.created_at)
|
||||
env_copy['created_at'] = Date.now();
|
||||
|
||||
/**
|
||||
* Enter here when it's the first time that the process is created
|
||||
* 1 - Assign a new id
|
||||
* 2 - Reset restart time and unstable_restarts
|
||||
* 3 - Assign a log file name depending on the id
|
||||
* 4 - If watch option is set, look for changes
|
||||
*/
|
||||
if (env_copy['pm_id'] === undefined) {
|
||||
env_copy['pm_id'] = God.getNewId();
|
||||
env_copy['restart_time'] = 0;
|
||||
env_copy['unstable_restarts'] = 0;
|
||||
|
||||
// add -pm_id to pid file
|
||||
env_copy.pm_pid_path = env_copy.pm_pid_path.replace(/-[0-9]+\.pid$|\.pid$/g, '-' + env_copy['pm_id'] + '.pid');
|
||||
|
||||
// If merge option, dont separate the logs
|
||||
if (!env_copy['merge_logs']) {
|
||||
['', '_out', '_err'].forEach(function(k){
|
||||
var key = 'pm' + k + '_log_path';
|
||||
env_copy[key] && (env_copy[key] = env_copy[key].replace(/-[0-9]+\.log$|\.log$/g, '-' + env_copy['pm_id'] + '.log'));
|
||||
});
|
||||
}
|
||||
|
||||
// Initiate watch file
|
||||
if (env_copy['watch']) {
|
||||
God.watch.enable(env_copy);
|
||||
}
|
||||
}
|
||||
|
||||
God.registerCron(env_copy)
|
||||
|
||||
if (env_copy['autostart'] === false) {
|
||||
var clu = {pm2_env: env_copy, process: {pid: 0}};
|
||||
God.clusters_db[env_copy.pm_id] = clu;
|
||||
return cb(null, clu);
|
||||
}
|
||||
|
||||
/** Callback when application is launched */
|
||||
var readyCb = function ready(proc) {
|
||||
// If vizion enabled run versioning retrieval system
|
||||
if (proc.pm2_env.vizion !== false && proc.pm2_env.vizion !== "false")
|
||||
God.finalizeProcedure(proc);
|
||||
else
|
||||
God.notify('online', proc);
|
||||
|
||||
if (proc.pm2_env.status !== cst.ERRORED_STATUS)
|
||||
proc.pm2_env.status = cst.ONLINE_STATUS
|
||||
|
||||
console.log(`App [${proc.pm2_env.name}:${proc.pm2_env.pm_id}] online`);
|
||||
if (cb) cb(null, proc);
|
||||
}
|
||||
|
||||
if (env_copy.exec_mode === 'cluster_mode') {
|
||||
/**
|
||||
* Cluster mode logic (for NodeJS apps)
|
||||
*/
|
||||
God.nodeApp(env_copy, function nodeApp(err, clu) {
|
||||
if (cb && err) return cb(err);
|
||||
if (err) return false;
|
||||
|
||||
var old_env = God.clusters_db[clu.pm2_env.pm_id];
|
||||
|
||||
if (old_env) {
|
||||
old_env = null;
|
||||
God.clusters_db[clu.pm2_env.pm_id] = null;
|
||||
}
|
||||
|
||||
God.clusters_db[clu.pm2_env.pm_id] = clu;
|
||||
|
||||
clu.once('error', function(err) {
|
||||
console.error(err.stack || err);
|
||||
try {
|
||||
clu.destroy && clu.destroy();
|
||||
}
|
||||
catch (e) {
|
||||
console.error(e.stack || e);
|
||||
God.handleExit(clu, cst.ERROR_EXIT);
|
||||
}
|
||||
});
|
||||
|
||||
clu.once('disconnect', function() {
|
||||
console.log('App name:%s id:%s disconnected', clu.pm2_env.name, clu.pm2_env.pm_id);
|
||||
});
|
||||
|
||||
clu.once('exit', function cluExit(code, signal) {
|
||||
//God.writeExitSeparator(clu.pm2_env, code, signal)
|
||||
God.handleExit(clu, code || 0, signal || 'SIGINT');
|
||||
});
|
||||
|
||||
return clu.once('online', function () {
|
||||
if (!clu.pm2_env.wait_ready)
|
||||
return readyCb(clu);
|
||||
|
||||
// Timeout if the ready message has not been sent before listen_timeout
|
||||
var ready_timeout = setTimeout(function() {
|
||||
God.bus.removeListener('process:msg', listener)
|
||||
return readyCb(clu)
|
||||
}, clu.pm2_env.listen_timeout || cst.GRACEFUL_LISTEN_TIMEOUT);
|
||||
|
||||
var listener = function (packet) {
|
||||
if (packet.raw === 'ready' &&
|
||||
packet.process.name === clu.pm2_env.name &&
|
||||
packet.process.pm_id === clu.pm2_env.pm_id) {
|
||||
clearTimeout(ready_timeout);
|
||||
God.bus.removeListener('process:msg', listener)
|
||||
return readyCb(clu)
|
||||
}
|
||||
}
|
||||
|
||||
God.bus.on('process:msg', listener);
|
||||
});
|
||||
});
|
||||
}
|
||||
else {
|
||||
/**
|
||||
* Fork mode logic
|
||||
*/
|
||||
God.forkMode(env_copy, function forkMode(err, clu) {
|
||||
if (cb && err) return cb(err);
|
||||
if (err) return false;
|
||||
|
||||
var old_env = God.clusters_db[clu.pm2_env.pm_id];
|
||||
if (old_env) old_env = null;
|
||||
|
||||
God.clusters_db[env_copy.pm_id] = clu;
|
||||
|
||||
clu.once('error', function cluError(err) {
|
||||
console.error(err.stack || err);
|
||||
try {
|
||||
clu.kill && clu.kill();
|
||||
}
|
||||
catch (e) {
|
||||
console.error(e.stack || e);
|
||||
God.handleExit(clu, cst.ERROR_EXIT);
|
||||
}
|
||||
});
|
||||
|
||||
clu.once('exit', function cluClose(code, signal) {
|
||||
//God.writeExitSeparator(clu.pm2_env, code, signal)
|
||||
|
||||
if (clu.connected === true)
|
||||
clu.disconnect && clu.disconnect();
|
||||
clu._reloadLogs = null;
|
||||
return God.handleExit(clu, code || 0, signal);
|
||||
});
|
||||
|
||||
if (!clu.pm2_env.wait_ready)
|
||||
return readyCb(clu);
|
||||
|
||||
// Timeout if the ready message has not been sent before listen_timeout
|
||||
var ready_timeout = setTimeout(function() {
|
||||
God.bus.removeListener('process:msg', listener)
|
||||
return readyCb(clu)
|
||||
}, clu.pm2_env.listen_timeout || cst.GRACEFUL_LISTEN_TIMEOUT);
|
||||
|
||||
var listener = function (packet) {
|
||||
if (packet.raw === 'ready' &&
|
||||
packet.process.name === clu.pm2_env.name &&
|
||||
packet.process.pm_id === clu.pm2_env.pm_id) {
|
||||
clearTimeout(ready_timeout);
|
||||
God.bus.removeListener('process:msg', listener)
|
||||
return readyCb(clu)
|
||||
}
|
||||
}
|
||||
God.bus.on('process:msg', listener);
|
||||
});
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
/**
|
||||
* Handle logic when a process exit (Node or Fork)
|
||||
* @method handleExit
|
||||
* @param {} clu
|
||||
* @param {} exit_code
|
||||
* @return
|
||||
*/
|
||||
God.handleExit = function handleExit(clu, exit_code, kill_signal) {
|
||||
console.log(`App [${clu.pm2_env.name}:${clu.pm2_env.pm_id}] exited with code [${exit_code}] via signal [${kill_signal || 'SIGINT'}]`)
|
||||
|
||||
var proc = this.clusters_db[clu.pm2_env.pm_id];
|
||||
|
||||
if (!proc) {
|
||||
console.error('Process undefined ? with process id ', clu.pm2_env.pm_id);
|
||||
return false;
|
||||
}
|
||||
|
||||
var stopExitCodes = proc.pm2_env.stop_exit_codes !== undefined && proc.pm2_env.stop_exit_codes !== null ? proc.pm2_env.stop_exit_codes : [];
|
||||
if (!Array.isArray(stopExitCodes)) {
|
||||
stopExitCodes = [stopExitCodes];
|
||||
}
|
||||
|
||||
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 || proc.pm2_env.autorestart === "false")
|
||||
|| (stopExitCodes.map((strOrNum) => typeof strOrNum === 'string' ? parseInt(strOrNum, 10) : strOrNum)
|
||||
.includes(exit_code));
|
||||
|
||||
var overlimit = false;
|
||||
|
||||
if (stopping) proc.process.pid = 0;
|
||||
|
||||
// Reset probes and actions
|
||||
if (proc.pm2_env.axm_actions) proc.pm2_env.axm_actions = [];
|
||||
if (proc.pm2_env.axm_monitor) proc.pm2_env.axm_monitor = {};
|
||||
|
||||
if (proc.pm2_env.status != cst.ERRORED_STATUS &&
|
||||
proc.pm2_env.status != cst.STOPPING_STATUS)
|
||||
proc.pm2_env.status = cst.STOPPED_STATUS;
|
||||
|
||||
if (proc.pm2_env.pm_id.toString().indexOf('_old_') !== 0) {
|
||||
try {
|
||||
fs.unlinkSync(proc.pm2_env.pm_pid_path);
|
||||
} catch (e) {
|
||||
debug('Error when unlinking pid file', e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Avoid infinite reloop if an error is present
|
||||
*/
|
||||
// If the process has been created less than 15seconds ago
|
||||
|
||||
// And if the process has an uptime less than a second
|
||||
var min_uptime = typeof(proc.pm2_env.min_uptime) !== 'undefined' ? proc.pm2_env.min_uptime : 1000;
|
||||
var max_restarts = typeof(proc.pm2_env.max_restarts) !== 'undefined' ? proc.pm2_env.max_restarts : 16;
|
||||
|
||||
if ((Date.now() - proc.pm2_env.created_at) < (min_uptime * max_restarts)) {
|
||||
if ((Date.now() - proc.pm2_env.pm_uptime) < min_uptime) {
|
||||
// Increment unstable restart
|
||||
proc.pm2_env.unstable_restarts += 1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (proc.pm2_env.unstable_restarts >= max_restarts) {
|
||||
// Too many unstable restart in less than 15 seconds
|
||||
// Set the process as 'ERRORED'
|
||||
// And stop restarting it
|
||||
proc.pm2_env.status = cst.ERRORED_STATUS;
|
||||
proc.process.pid = 0;
|
||||
|
||||
console.log('Script %s had too many unstable restarts (%d). Stopped. %j',
|
||||
proc.pm2_env.pm_exec_path,
|
||||
proc.pm2_env.unstable_restarts,
|
||||
proc.pm2_env.status);
|
||||
|
||||
God.notify('restart overlimit', proc);
|
||||
|
||||
proc.pm2_env.unstable_restarts = 0;
|
||||
proc.pm2_env.created_at = null;
|
||||
overlimit = true;
|
||||
}
|
||||
|
||||
if (typeof(exit_code) !== 'undefined') proc.pm2_env.exit_code = exit_code;
|
||||
|
||||
God.notify('exit', proc);
|
||||
|
||||
if (God.pm2_being_killed) {
|
||||
//console.log('[HandleExit] PM2 is being killed, stopping restart procedure...');
|
||||
return false;
|
||||
}
|
||||
|
||||
var restart_delay = 0;
|
||||
|
||||
if (proc.pm2_env.restart_delay !== undefined &&
|
||||
!isNaN(parseInt(proc.pm2_env.restart_delay))) {
|
||||
proc.pm2_env.status = cst.WAITING_RESTART;
|
||||
restart_delay = parseInt(proc.pm2_env.restart_delay);
|
||||
}
|
||||
|
||||
if (proc.pm2_env.exp_backoff_restart_delay !== undefined &&
|
||||
!isNaN(parseInt(proc.pm2_env.exp_backoff_restart_delay))) {
|
||||
proc.pm2_env.status = cst.WAITING_RESTART;
|
||||
if (!proc.pm2_env.prev_restart_delay) {
|
||||
proc.pm2_env.prev_restart_delay = proc.pm2_env.exp_backoff_restart_delay
|
||||
restart_delay = proc.pm2_env.exp_backoff_restart_delay
|
||||
}
|
||||
else {
|
||||
proc.pm2_env.prev_restart_delay = Math.floor(Math.min(15000, proc.pm2_env.prev_restart_delay * 1.5))
|
||||
restart_delay = proc.pm2_env.prev_restart_delay
|
||||
}
|
||||
console.log(`App [${clu.pm2_env.name}:${clu.pm2_env.pm_id}] will restart in ${restart_delay}ms`)
|
||||
}
|
||||
|
||||
if (!stopping && !overlimit) {
|
||||
//make this property unenumerable
|
||||
Object.defineProperty(proc.pm2_env, 'restart_task', {configurable: true, writable: true});
|
||||
proc.pm2_env.restart_task = setTimeout(function() {
|
||||
proc.pm2_env.restart_time += 1;
|
||||
God.executeApp(proc.pm2_env);
|
||||
}, restart_delay);
|
||||
}
|
||||
|
||||
return false;
|
||||
};
|
||||
|
||||
/**
|
||||
* @method finalizeProcedure
|
||||
* @param proc {Object}
|
||||
* @return
|
||||
*/
|
||||
God.finalizeProcedure = function finalizeProcedure(proc) {
|
||||
var last_path = '';
|
||||
var current_path = proc.pm2_env.cwd || path.dirname(proc.pm2_env.pm_exec_path);
|
||||
var proc_id = proc.pm2_env.pm_id;
|
||||
|
||||
proc.pm2_env.version = Utility.findPackageVersion(proc.pm2_env.pm_exec_path || proc.pm2_env.cwd);
|
||||
|
||||
if (proc.pm2_env.vizion_running === true) {
|
||||
debug('Vizion is already running for proc id: %d, skipping this round', proc_id);
|
||||
return God.notify('online', proc);
|
||||
}
|
||||
proc.pm2_env.vizion_running = true;
|
||||
|
||||
vizion.analyze({folder : current_path}, function recur_path(err, meta){
|
||||
var proc = God.clusters_db[proc_id];
|
||||
|
||||
if (err)
|
||||
debug(err.stack || err);
|
||||
|
||||
if (!proc ||
|
||||
!proc.pm2_env ||
|
||||
proc.pm2_env.status == cst.STOPPED_STATUS ||
|
||||
proc.pm2_env.status == cst.STOPPING_STATUS ||
|
||||
proc.pm2_env.status == cst.ERRORED_STATUS) {
|
||||
return console.error('Cancelling versioning data parsing');
|
||||
}
|
||||
|
||||
proc.pm2_env.vizion_running = false;
|
||||
|
||||
if (!err) {
|
||||
proc.pm2_env.versioning = meta;
|
||||
proc.pm2_env.versioning.repo_path = current_path;
|
||||
God.notify('online', proc);
|
||||
}
|
||||
else if (err && current_path === last_path) {
|
||||
proc.pm2_env.versioning = null;
|
||||
God.notify('online', proc);
|
||||
}
|
||||
else {
|
||||
last_path = current_path;
|
||||
current_path = path.dirname(current_path);
|
||||
proc.pm2_env.vizion_running = true;
|
||||
vizion.analyze({folder : current_path}, recur_path);
|
||||
}
|
||||
return false;
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Inject variables into processes
|
||||
* @param {Object} env environnement to be passed to the process
|
||||
* @param {Function} cb invoked with <err, env>
|
||||
*/
|
||||
God.injectVariables = function injectVariables (env, cb) {
|
||||
// allow to override the key of NODE_APP_INSTANCE if wanted
|
||||
var instanceKey = process.env.PM2_PROCESS_INSTANCE_VAR || env.instance_var;
|
||||
|
||||
// we need to find the last NODE_APP_INSTANCE used
|
||||
var instances = Object.keys(God.clusters_db)
|
||||
.map(function (procId) {
|
||||
return God.clusters_db[procId];
|
||||
}).filter(function (proc) {
|
||||
return proc.pm2_env.name === env.name &&
|
||||
typeof proc.pm2_env[instanceKey] !== 'undefined';
|
||||
}).map(function (proc) {
|
||||
return proc.pm2_env[instanceKey];
|
||||
}).sort(function (a, b) {
|
||||
return b - a;
|
||||
});
|
||||
// default to last one + 1
|
||||
var instanceNumber = typeof instances[0] === 'undefined' ? 0 : instances[0] + 1;
|
||||
// but try to find a one available
|
||||
for (var i = 0; i < instances.length; i++) {
|
||||
if (instances.indexOf(i) === -1) {
|
||||
instanceNumber = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
env[instanceKey] = instanceNumber;
|
||||
|
||||
// if using increment_var, we need to increment it
|
||||
if (env.increment_var) {
|
||||
var lastIncrement = Object.keys(God.clusters_db)
|
||||
.map(function (procId) {
|
||||
return God.clusters_db[procId];
|
||||
}).filter(function (proc) {
|
||||
return proc.pm2_env.name === env.name &&
|
||||
typeof proc.pm2_env[env.increment_var] !== 'undefined';
|
||||
}).map(function (proc) {
|
||||
return Number(proc.pm2_env[env.increment_var]);
|
||||
}).sort(function (a, b) {
|
||||
return b - a;
|
||||
})[0];
|
||||
// inject a incremental variable
|
||||
var defaut = Number(env.env[env.increment_var]) || 0;
|
||||
env[env.increment_var] = typeof lastIncrement === 'undefined' ? defaut : lastIncrement + 1;
|
||||
env.env[env.increment_var] = env[env.increment_var];
|
||||
}
|
||||
|
||||
return cb(null, env);
|
||||
};
|
||||
|
||||
God.init()
|
||||
909
api.hyungi.net/node_modules/pm2/lib/God/ActionMethods.js
generated
vendored
Normal file
909
api.hyungi.net/node_modules/pm2/lib/God/ActionMethods.js
generated
vendored
Normal file
@@ -0,0 +1,909 @@
|
||||
/**
|
||||
* Copyright 2013-2022 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';
|
||||
|
||||
/**
|
||||
* @file ActionMethod like restart, stop, monitor... are here
|
||||
* @author Alexandre Strzelewicz <as@unitech.io>
|
||||
* @project PM2
|
||||
*/
|
||||
|
||||
var fs = require('fs');
|
||||
var path = require('path');
|
||||
var eachLimit = require('async/eachLimit');
|
||||
var os = require('os');
|
||||
var p = path;
|
||||
var cst = require('../../constants.js');
|
||||
var pkg = require('../../package.json');
|
||||
var pidusage = require('pidusage');
|
||||
var util = require('util');
|
||||
var debug = require('debug')('pm2:ActionMethod');
|
||||
var Utility = require('../Utility');
|
||||
|
||||
/**
|
||||
* Description
|
||||
* @method exports
|
||||
* @param {} God
|
||||
* @return
|
||||
*/
|
||||
module.exports = function(God) {
|
||||
/**
|
||||
* Description
|
||||
* @method getMonitorData
|
||||
* @param {} env
|
||||
* @param {} cb
|
||||
* @return
|
||||
*/
|
||||
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;
|
||||
})
|
||||
|
||||
// No pids, return empty statistics
|
||||
if (pids.length === 0) {
|
||||
return cb(null, processes.map(function(pro) {
|
||||
pro['monit'] = {
|
||||
memory : 0,
|
||||
cpu : 0
|
||||
};
|
||||
|
||||
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);
|
||||
|
||||
return cb(null, processes.map(function(pro) {
|
||||
pro['monit'] = {
|
||||
memory : 0,
|
||||
cpu : 0
|
||||
};
|
||||
return pro
|
||||
}))
|
||||
}
|
||||
|
||||
if (!statistics) {
|
||||
console.error('Statistics is not defined!')
|
||||
|
||||
return cb(null, processes.map(function(pro) {
|
||||
pro['monit'] = {
|
||||
memory : 0,
|
||||
cpu : 0
|
||||
};
|
||||
return pro
|
||||
}))
|
||||
}
|
||||
|
||||
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);
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Description
|
||||
* @method dumpProcessList
|
||||
* @param {} cb
|
||||
* @return
|
||||
*/
|
||||
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`.
|
||||
// This often happens when PM2 crashed, we don't want to override
|
||||
// the dump file with an empty list of process.
|
||||
if (!apps[0]) {
|
||||
debug('[PM2] Did not override dump file because list of processes is empty');
|
||||
return cb(null, {success:true, process_list: process_list});
|
||||
}
|
||||
|
||||
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) && typeof that.clearDump === 'function') {
|
||||
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)) {
|
||||
fs.writeFileSync(cst.DUMP_BACKUP_FILE_PATH, fs.readFileSync(cst.DUMP_FILE_PATH));
|
||||
}
|
||||
} catch (e) {
|
||||
console.error(e.stack || e);
|
||||
}
|
||||
|
||||
// Overwrite dump file, delete if broken
|
||||
try {
|
||||
fs.writeFileSync(cst.DUMP_FILE_PATH, JSON.stringify(process_list));
|
||||
} catch (e) {
|
||||
console.error(e.stack || e);
|
||||
try {
|
||||
// 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);
|
||||
}
|
||||
}
|
||||
|
||||
return cb(null, {success:true, process_list: process_list});
|
||||
}
|
||||
|
||||
function saveProc(apps) {
|
||||
if (!apps[0])
|
||||
return fin(null);
|
||||
delete apps[0].pm2_env.instances;
|
||||
delete apps[0].pm2_env.pm_id;
|
||||
// Do not dump modules
|
||||
if (!apps[0].pm2_env.pmx_module)
|
||||
process_list.push(apps[0].pm2_env);
|
||||
apps.shift();
|
||||
return saveProc(apps);
|
||||
}
|
||||
saveProc(apps);
|
||||
};
|
||||
|
||||
/**
|
||||
* Description
|
||||
* @method ping
|
||||
* @param {} env
|
||||
* @param {} cb
|
||||
* @return CallExpression
|
||||
*/
|
||||
God.ping = function(env, cb) {
|
||||
return cb(null, {msg : 'pong'});
|
||||
};
|
||||
|
||||
/**
|
||||
* Description
|
||||
* @method notifyKillPM2
|
||||
*/
|
||||
God.notifyKillPM2 = function() {
|
||||
God.pm2_being_killed = true;
|
||||
};
|
||||
|
||||
/**
|
||||
* Duplicate a process
|
||||
* @method duplicateProcessId
|
||||
* @param {} id
|
||||
* @param {} cb
|
||||
* @return CallExpression
|
||||
*/
|
||||
God.duplicateProcessId = function(id, cb) {
|
||||
if (!(id in God.clusters_db))
|
||||
return cb(God.logAndGenerateError(id + ' id unknown'), {});
|
||||
|
||||
if (!God.clusters_db[id] || !God.clusters_db[id].pm2_env)
|
||||
return cb(God.logAndGenerateError('Error when getting proc || proc.pm2_env'), {});
|
||||
|
||||
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) {
|
||||
if (err) return cb(err);
|
||||
God.notify('start', clu, true);
|
||||
return cb(err, Utility.clone(clu));
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Start a stopped process by ID
|
||||
* @method startProcessId
|
||||
* @param {} id
|
||||
* @param {} cb
|
||||
* @return CallExpression
|
||||
*/
|
||||
God.startProcessId = function(id, cb) {
|
||||
if (!(id in God.clusters_db))
|
||||
return cb(God.logAndGenerateError(id + ' id unknown'), {});
|
||||
|
||||
var proc = God.clusters_db[id];
|
||||
if (proc.pm2_env.status == cst.ONLINE_STATUS)
|
||||
return cb(God.logAndGenerateError('process already online'), {});
|
||||
if (proc.pm2_env.status == cst.LAUNCHING_STATUS)
|
||||
return cb(God.logAndGenerateError('process already started'), {});
|
||||
if (proc.process && proc.process.pid)
|
||||
return cb(God.logAndGenerateError('Process with pid ' + proc.process.pid + ' already exists'), {});
|
||||
|
||||
return God.executeApp(God.clusters_db[id].pm2_env, function(err, proc) {
|
||||
return cb(err, Utility.clone(proc));
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Stop a process and set it on state 'stopped'
|
||||
* @method stopProcessId
|
||||
* @param {} id
|
||||
* @param {} cb
|
||||
* @return Literal
|
||||
*/
|
||||
God.stopProcessId = function(id, cb) {
|
||||
if (typeof id == 'object' && 'id' in id)
|
||||
id = id.id;
|
||||
|
||||
if (!(id in God.clusters_db))
|
||||
return cb(God.logAndGenerateError(id + ' : id unknown'), {});
|
||||
|
||||
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;
|
||||
|
||||
if (!proc.process.pid) {
|
||||
console.error('app=%s id=%d does not have a pid', proc.pm2_env.name, proc.pm2_env.pm_id);
|
||||
proc.pm2_env.status = cst.STOPPED_STATUS;
|
||||
return cb(null, { error : true, message : 'could not kill process w/o pid'});
|
||||
}
|
||||
|
||||
God.killProcess(proc.process.pid, proc.pm2_env, function(err) {
|
||||
proc.pm2_env.status = cst.STOPPED_STATUS;
|
||||
|
||||
God.notify('exit', proc);
|
||||
|
||||
if (err && err.type && err.type === 'timeout') {
|
||||
console.error('app=%s id=%d pid=%s could not be stopped',
|
||||
proc.pm2_env.name,
|
||||
proc.pm2_env.pm_id,
|
||||
proc.process.pid);
|
||||
proc.pm2_env.status = cst.ERRORED_STATUS;
|
||||
return cb(null, God.getFormatedProcess(id));
|
||||
}
|
||||
|
||||
if (proc.pm2_env.pm_id.toString().indexOf('_old_') !== 0) {
|
||||
try {
|
||||
fs.unlinkSync(proc.pm2_env.pm_pid_path);
|
||||
} catch (e) {}
|
||||
}
|
||||
|
||||
if (proc.pm2_env.axm_actions) proc.pm2_env.axm_actions = [];
|
||||
if (proc.pm2_env.axm_monitor) proc.pm2_env.axm_monitor = {};
|
||||
|
||||
proc.process.pid = 0;
|
||||
return cb(null, God.getFormatedProcess(id));
|
||||
});
|
||||
};
|
||||
|
||||
God.resetMetaProcessId = function(id, cb) {
|
||||
if (!(id in God.clusters_db))
|
||||
return cb(God.logAndGenerateError(id + ' id unknown'), {});
|
||||
|
||||
if (!God.clusters_db[id] || !God.clusters_db[id].pm2_env)
|
||||
return cb(God.logAndGenerateError('Error when getting proc || proc.pm2_env'), {});
|
||||
|
||||
God.clusters_db[id].pm2_env.created_at = Utility.getDate();
|
||||
God.clusters_db[id].pm2_env.unstable_restarts = 0;
|
||||
God.clusters_db[id].pm2_env.restart_time = 0;
|
||||
|
||||
return cb(null, God.getFormatedProcesses());
|
||||
};
|
||||
|
||||
/**
|
||||
* Delete a process by id
|
||||
* It will stop it and remove it from the database
|
||||
* @method deleteProcessId
|
||||
* @param {} id
|
||||
* @param {} cb
|
||||
* @return Literal
|
||||
*/
|
||||
God.deleteProcessId = function(id, cb) {
|
||||
God.deleteCron(id);
|
||||
|
||||
God.stopProcessId(id, function(err, proc) {
|
||||
if (err) return cb(God.logAndGenerateError(err), {});
|
||||
// ! transform to slow object
|
||||
delete God.clusters_db[id];
|
||||
|
||||
if (Object.keys(God.clusters_db).length == 0)
|
||||
God.next_id = 0;
|
||||
return cb(null, proc);
|
||||
});
|
||||
return false;
|
||||
};
|
||||
|
||||
/**
|
||||
* Restart a process ID
|
||||
* If the process is online it will not put it on state stopped
|
||||
* but directly kill it and let God restart it
|
||||
* @method restartProcessId
|
||||
* @param {} id
|
||||
* @param {} cb
|
||||
* @return Literal
|
||||
*/
|
||||
God.restartProcessId = function(opts, cb) {
|
||||
var id = opts.id;
|
||||
var env = opts.env || {};
|
||||
|
||||
if (typeof(id) === 'undefined')
|
||||
return cb(God.logAndGenerateError('opts.id not passed to restartProcessId', opts));
|
||||
if (!(id in God.clusters_db))
|
||||
return cb(God.logAndGenerateError('God db process id unknown'), {});
|
||||
|
||||
var proc = God.clusters_db[id];
|
||||
|
||||
God.resetState(proc.pm2_env);
|
||||
God.deleteCron(id);
|
||||
|
||||
/**
|
||||
* Merge new application configuration on restart
|
||||
* Same system in reloadProcessId and softReloadProcessId
|
||||
*/
|
||||
Utility.extend(proc.pm2_env.env, env);
|
||||
Utility.extendExtraConfig(proc, opts);
|
||||
|
||||
if (God.pm2_being_killed) {
|
||||
return cb(God.logAndGenerateError('[RestartProcessId] PM2 is being killed, stopping restart procedure...'));
|
||||
}
|
||||
if (proc.pm2_env.status === cst.ONLINE_STATUS || proc.pm2_env.status === cst.LAUNCHING_STATUS) {
|
||||
God.stopProcessId(id, function(err) {
|
||||
if (God.pm2_being_killed)
|
||||
return cb(God.logAndGenerateError('[RestartProcessId] PM2 is being killed, stopping restart procedure...'));
|
||||
proc.pm2_env.restart_time += 1;
|
||||
return God.startProcessId(id, cb);
|
||||
});
|
||||
|
||||
return false;
|
||||
}
|
||||
else {
|
||||
debug('[restart] process not online, starting it');
|
||||
return God.startProcessId(id, cb);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Restart all process by name
|
||||
* @method restartProcessName
|
||||
* @param {} name
|
||||
* @param {} cb
|
||||
* @return Literal
|
||||
*/
|
||||
God.restartProcessName = function(name, cb) {
|
||||
var processes = God.findByName(name);
|
||||
|
||||
if (processes && processes.length === 0)
|
||||
return cb(God.logAndGenerateError('Unknown process'), {});
|
||||
|
||||
eachLimit(processes, cst.CONCURRENT_ACTIONS, function(proc, next) {
|
||||
if (God.pm2_being_killed)
|
||||
return next('[Watch] PM2 is being killed, stopping restart procedure...');
|
||||
if (proc.pm2_env.status === cst.ONLINE_STATUS)
|
||||
return God.restartProcessId({id:proc.pm2_env.pm_id}, next);
|
||||
else if (proc.pm2_env.status !== cst.STOPPING_STATUS
|
||||
&& proc.pm2_env.status !== cst.LAUNCHING_STATUS)
|
||||
return God.startProcessId(proc.pm2_env.pm_id, next);
|
||||
else
|
||||
return next(util.format('[Watch] Process name %s is being stopped so I won\'t restart it', name));
|
||||
}, function(err) {
|
||||
if (err) return cb(God.logAndGenerateError(err));
|
||||
return cb(null, God.getFormatedProcesses());
|
||||
});
|
||||
|
||||
return false;
|
||||
};
|
||||
|
||||
/**
|
||||
* Send system signal to process id
|
||||
* @method sendSignalToProcessId
|
||||
* @param {} opts
|
||||
* @param {} cb
|
||||
* @return CallExpression
|
||||
*/
|
||||
God.sendSignalToProcessId = function(opts, cb) {
|
||||
var id = opts.process_id;
|
||||
var signal = opts.signal;
|
||||
|
||||
if (!(id in God.clusters_db))
|
||||
return cb(God.logAndGenerateError(id + ' id unknown'), {});
|
||||
|
||||
var proc = God.clusters_db[id];
|
||||
|
||||
//God.notify('send signal ' + signal, proc, true);
|
||||
|
||||
try {
|
||||
process.kill(God.clusters_db[id].process.pid, signal);
|
||||
} catch(e) {
|
||||
return cb(God.logAndGenerateError('Error when sending signal (signal unknown)'), {});
|
||||
}
|
||||
return cb(null, God.getFormatedProcesses());
|
||||
};
|
||||
|
||||
/**
|
||||
* Send system signal to all processes by name
|
||||
* @method sendSignalToProcessName
|
||||
* @param {} opts
|
||||
* @param {} cb
|
||||
* @return
|
||||
*/
|
||||
God.sendSignalToProcessName = function(opts, cb) {
|
||||
var processes = God.findByName(opts.process_name);
|
||||
var signal = opts.signal;
|
||||
|
||||
if (processes && processes.length === 0)
|
||||
return cb(God.logAndGenerateError('Unknown process name'), {});
|
||||
|
||||
eachLimit(processes, cst.CONCURRENT_ACTIONS, function(proc, next) {
|
||||
if (proc.pm2_env.status == cst.ONLINE_STATUS || proc.pm2_env.status == cst.LAUNCHING_STATUS) {
|
||||
try {
|
||||
process.kill(proc.process.pid, signal);
|
||||
} catch(e) {
|
||||
return next(e);
|
||||
}
|
||||
}
|
||||
return setTimeout(next, 200);
|
||||
}, function(err) {
|
||||
if (err) return cb(God.logAndGenerateError(err), {});
|
||||
return cb(null, God.getFormatedProcesses());
|
||||
});
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
* Stop watching daemon
|
||||
* @method stopWatch
|
||||
* @param {} method
|
||||
* @param {} value
|
||||
* @param {} fn
|
||||
* @return
|
||||
*/
|
||||
God.stopWatch = function(method, value, fn) {
|
||||
var env = null;
|
||||
|
||||
if (method == 'stopAll' || method == 'deleteAll') {
|
||||
var processes = God.getFormatedProcesses();
|
||||
|
||||
processes.forEach(function(proc) {
|
||||
God.clusters_db[proc.pm_id].pm2_env.watch = false;
|
||||
God.watch.disable(proc.pm2_env);
|
||||
});
|
||||
|
||||
} else {
|
||||
|
||||
if (method.indexOf('ProcessId') !== -1) {
|
||||
env = God.clusters_db[value];
|
||||
} else if (method.indexOf('ProcessName') !== -1) {
|
||||
env = God.clusters_db[God.findByName(value)];
|
||||
}
|
||||
|
||||
if (env) {
|
||||
God.watch.disable(env.pm2_env);
|
||||
env.pm2_env.watch = false;
|
||||
}
|
||||
}
|
||||
return fn(null, {success:true});
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Toggle watching daemon
|
||||
* @method toggleWatch
|
||||
* @param {String} method
|
||||
* @param {Object} application environment, should include id
|
||||
* @param {Function} callback
|
||||
*/
|
||||
God.toggleWatch = function(method, value, fn) {
|
||||
var env = null;
|
||||
|
||||
if (method == 'restartProcessId') {
|
||||
env = God.clusters_db[value.id];
|
||||
} else if(method == 'restartProcessName') {
|
||||
env = God.clusters_db[God.findByName(value)];
|
||||
}
|
||||
|
||||
if (env) {
|
||||
env.pm2_env.watch = !env.pm2_env.watch;
|
||||
if (env.pm2_env.watch)
|
||||
God.watch.enable(env.pm2_env);
|
||||
else
|
||||
God.watch.disable(env.pm2_env);
|
||||
}
|
||||
|
||||
return fn(null, {success:true});
|
||||
};
|
||||
|
||||
/**
|
||||
* Start Watch
|
||||
* @method startWatch
|
||||
* @param {String} method
|
||||
* @param {Object} application environment, should include id
|
||||
* @param {Function} callback
|
||||
*/
|
||||
God.startWatch = function(method, value, fn) {
|
||||
var env = null;
|
||||
|
||||
if (method == 'restartProcessId') {
|
||||
env = God.clusters_db[value.id];
|
||||
} else if(method == 'restartProcessName') {
|
||||
env = God.clusters_db[God.findByName(value)];
|
||||
}
|
||||
|
||||
if (env) {
|
||||
if (env.pm2_env.watch)
|
||||
return fn(null, {success:true, notrestarted:true});
|
||||
|
||||
God.watch.enable(env.pm2_env);
|
||||
//env.pm2_env.env.watch = true;
|
||||
env.pm2_env.watch = true;
|
||||
}
|
||||
|
||||
return fn(null, {success:true});
|
||||
};
|
||||
|
||||
/**
|
||||
* Description
|
||||
* @method reloadLogs
|
||||
* @param {} opts
|
||||
* @param {} cb
|
||||
* @return CallExpression
|
||||
*/
|
||||
God.reloadLogs = function(opts, cb) {
|
||||
console.log('Reloading logs...');
|
||||
var processIds = Object.keys(God.clusters_db);
|
||||
|
||||
processIds.forEach(function (id) {
|
||||
var cluster = God.clusters_db[id];
|
||||
|
||||
console.log('Reloading logs for process id %d', id);
|
||||
|
||||
if (cluster && cluster.pm2_env) {
|
||||
// Cluster mode
|
||||
if (cluster.send && cluster.pm2_env.exec_mode == 'cluster_mode') {
|
||||
try {
|
||||
cluster.send({
|
||||
type:'log:reload'
|
||||
});
|
||||
} catch(e) {
|
||||
console.error(e.message || e);
|
||||
}
|
||||
}
|
||||
// Fork mode
|
||||
else if (cluster._reloadLogs) {
|
||||
cluster._reloadLogs(function(err) {
|
||||
if (err) God.logAndGenerateError(err);
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
return cb(null, {});
|
||||
};
|
||||
|
||||
/**
|
||||
* Send Line To Stdin
|
||||
* @method sendLineToStdin
|
||||
* @param Object packet
|
||||
* @param String pm_id Process ID
|
||||
* @param String line Line to send to process stdin
|
||||
*/
|
||||
God.sendLineToStdin = function(packet, cb) {
|
||||
if (typeof(packet.pm_id) == 'undefined' || !packet.line)
|
||||
return cb(God.logAndGenerateError('pm_id or line field missing'), {});
|
||||
|
||||
var pm_id = packet.pm_id;
|
||||
var line = packet.line;
|
||||
|
||||
var proc = God.clusters_db[pm_id];
|
||||
|
||||
if (!proc)
|
||||
return cb(God.logAndGenerateError('Process with ID <' + pm_id + '> unknown.'), {});
|
||||
|
||||
if (proc.pm2_env.exec_mode == 'cluster_mode')
|
||||
return cb(God.logAndGenerateError('Cannot send line to processes in cluster mode'), {});
|
||||
|
||||
if (proc.pm2_env.status != cst.ONLINE_STATUS && proc.pm2_env.status != cst.LAUNCHING_STATUS)
|
||||
return cb(God.logAndGenerateError('Process with ID <' + pm_id + '> offline.'), {});
|
||||
|
||||
try {
|
||||
proc.stdin.write(line, function() {
|
||||
return cb(null, {
|
||||
pm_id : pm_id,
|
||||
line : line
|
||||
});
|
||||
});
|
||||
} catch(e) {
|
||||
return cb(God.logAndGenerateError(e), {});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {object} packet
|
||||
* @param {function} cb
|
||||
*/
|
||||
God.sendDataToProcessId = function(packet, cb) {
|
||||
if (typeof(packet.id) == 'undefined' ||
|
||||
typeof(packet.data) == 'undefined' ||
|
||||
!packet.topic)
|
||||
return cb(God.logAndGenerateError('ID, DATA or TOPIC field is missing'), {});
|
||||
|
||||
var pm_id = packet.id;
|
||||
var data = packet.data;
|
||||
|
||||
var proc = God.clusters_db[pm_id];
|
||||
|
||||
if (!proc)
|
||||
return cb(God.logAndGenerateError('Process with ID <' + pm_id + '> unknown.'), {});
|
||||
|
||||
if (proc.pm2_env.status != cst.ONLINE_STATUS && proc.pm2_env.status != cst.LAUNCHING_STATUS)
|
||||
return cb(God.logAndGenerateError('Process with ID <' + pm_id + '> offline.'), {});
|
||||
|
||||
try {
|
||||
proc.send(packet);
|
||||
}
|
||||
catch(e) {
|
||||
return cb(God.logAndGenerateError(e), {});
|
||||
}
|
||||
|
||||
return cb(null, {
|
||||
success: true,
|
||||
data : packet
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Send Message to Process by id or name
|
||||
* @method msgProcess
|
||||
* @param {} cmd
|
||||
* @param {} cb
|
||||
* @return Literal
|
||||
*/
|
||||
God.msgProcess = function(cmd, cb) {
|
||||
if ('id' in cmd) {
|
||||
var id = cmd.id;
|
||||
if (!(id in God.clusters_db))
|
||||
return cb(God.logAndGenerateError(id + ' id unknown'), {});
|
||||
var proc = God.clusters_db[id];
|
||||
|
||||
var action_exist = false;
|
||||
|
||||
proc.pm2_env.axm_actions.forEach(function(action) {
|
||||
if (action.action_name == cmd.msg) {
|
||||
action_exist = true;
|
||||
// Reset output buffer
|
||||
action.output = [];
|
||||
}
|
||||
});
|
||||
if (action_exist == false) {
|
||||
return cb(God.logAndGenerateError('Action doesn\'t exist ' + cmd.msg + ' for ' + proc.pm2_env.name), {});
|
||||
}
|
||||
|
||||
if (proc.pm2_env.status == cst.ONLINE_STATUS || proc.pm2_env.status == cst.LAUNCHING_STATUS) {
|
||||
/*
|
||||
* Send message
|
||||
*/
|
||||
if (cmd.opts == null && !cmd.uuid)
|
||||
proc.send(cmd.msg);
|
||||
else
|
||||
proc.send(cmd);
|
||||
|
||||
return cb(null, { process_count : 1, success : true });
|
||||
}
|
||||
else
|
||||
return cb(God.logAndGenerateError(id + ' : id offline'), {});
|
||||
}
|
||||
|
||||
else if ('name' in cmd) {
|
||||
/*
|
||||
* As names are not unique in case of cluster, this
|
||||
* will send msg to all process matching 'name'
|
||||
*/
|
||||
var name = cmd.name;
|
||||
var arr = Object.keys(God.clusters_db);
|
||||
var sent = 0;
|
||||
|
||||
(function ex(arr) {
|
||||
if (arr[0] == null || !arr) {
|
||||
return cb(null, {
|
||||
process_count : sent,
|
||||
success : true
|
||||
});
|
||||
}
|
||||
|
||||
var id = arr[0];
|
||||
|
||||
if (!God.clusters_db[id] || !God.clusters_db[id].pm2_env) {
|
||||
arr.shift();
|
||||
return ex(arr);
|
||||
}
|
||||
|
||||
var proc_env = God.clusters_db[id].pm2_env;
|
||||
|
||||
const isActionAvailable = proc_env.axm_actions.find(action => action.action_name === cmd.msg) !== undefined
|
||||
|
||||
// if action doesn't exist for this app
|
||||
// try with the next one
|
||||
if (isActionAvailable === false) {
|
||||
arr.shift();
|
||||
return ex(arr);
|
||||
}
|
||||
|
||||
|
||||
if ((p.basename(proc_env.pm_exec_path) == name ||
|
||||
proc_env.name == name ||
|
||||
proc_env.namespace == name ||
|
||||
name == 'all') &&
|
||||
(proc_env.status == cst.ONLINE_STATUS ||
|
||||
proc_env.status == cst.LAUNCHING_STATUS)) {
|
||||
|
||||
proc_env.axm_actions.forEach(function(action) {
|
||||
if (action.action_name == cmd.msg) {
|
||||
action_exist = true;
|
||||
}
|
||||
});
|
||||
|
||||
if (action_exist == false || proc_env.axm_actions.length == 0) {
|
||||
arr.shift();
|
||||
return ex(arr);
|
||||
}
|
||||
|
||||
if (cmd.opts == null)
|
||||
God.clusters_db[id].send(cmd.msg);
|
||||
else
|
||||
God.clusters_db[id].send(cmd);
|
||||
|
||||
sent++;
|
||||
arr.shift();
|
||||
return ex(arr);
|
||||
}
|
||||
else {
|
||||
arr.shift();
|
||||
return ex(arr);
|
||||
}
|
||||
return false;
|
||||
})(arr);
|
||||
}
|
||||
|
||||
else return cb(God.logAndGenerateError('method requires name or id field'), {});
|
||||
return false;
|
||||
};
|
||||
|
||||
/**
|
||||
* Description
|
||||
* @method getVersion
|
||||
* @param {} env
|
||||
* @param {} cb
|
||||
* @return CallExpression
|
||||
*/
|
||||
God.getVersion = function(env, cb) {
|
||||
process.nextTick(function() {
|
||||
return cb(null, pkg.version);
|
||||
});
|
||||
};
|
||||
|
||||
God.monitor = function Monitor(pm_id, cb) {
|
||||
if (!God.clusters_db[pm_id] || !God.clusters_db[pm_id].pm2_env)
|
||||
return cb(new Error('Unknown pm_id'));
|
||||
|
||||
God.clusters_db[pm_id].pm2_env._km_monitored = true;
|
||||
return cb(null, { success : true, pm_id : pm_id });
|
||||
}
|
||||
|
||||
God.unmonitor = function Monitor(pm_id, cb) {
|
||||
if (!God.clusters_db[pm_id] || !God.clusters_db[pm_id].pm2_env)
|
||||
return cb(new Error('Unknown pm_id'));
|
||||
|
||||
God.clusters_db[pm_id].pm2_env._km_monitored = false;
|
||||
return cb(null, { success : true, pm_id : pm_id });
|
||||
}
|
||||
|
||||
God.getReport = function(arg, cb) {
|
||||
var report = {
|
||||
pm2_version : pkg.version,
|
||||
node_version : 'N/A',
|
||||
node_path : process.env['_'] || 'not found',
|
||||
argv0 : process.argv0,
|
||||
argv : process.argv,
|
||||
user : process.env.USER,
|
||||
uid : (cst.IS_WINDOWS === false && process.geteuid) ? process.geteuid() : 'N/A',
|
||||
gid : (cst.IS_WINDOWS === false && process.getegid) ? process.getegid() : 'N/A',
|
||||
env : process.env,
|
||||
managed_apps : Object.keys(God.clusters_db).length,
|
||||
started_at : God.started_at
|
||||
};
|
||||
|
||||
if (process.versions && process.versions.node) {
|
||||
report.node_version = process.versions.node;
|
||||
}
|
||||
|
||||
process.nextTick(function() {
|
||||
return cb(null, report);
|
||||
});
|
||||
};
|
||||
};
|
||||
|
||||
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
|
||||
}
|
||||
97
api.hyungi.net/node_modules/pm2/lib/God/ClusterMode.js
generated
vendored
Normal file
97
api.hyungi.net/node_modules/pm2/lib/God/ClusterMode.js
generated
vendored
Normal file
@@ -0,0 +1,97 @@
|
||||
/**
|
||||
* Copyright 2013-2022 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';
|
||||
|
||||
/**
|
||||
* @file Cluster execution functions related
|
||||
* @author Alexandre Strzelewicz <as@unitech.io>
|
||||
* @project PM2
|
||||
*/
|
||||
var cluster = require('cluster');
|
||||
var Utility = require('../Utility.js');
|
||||
var pkg = require('../../package.json');
|
||||
|
||||
/**
|
||||
* Description
|
||||
* @method exports
|
||||
* @param {} God
|
||||
* @return
|
||||
*/
|
||||
module.exports = function ClusterMode(God) {
|
||||
|
||||
/**
|
||||
* For Node apps - Cluster mode
|
||||
* It will wrap the code and enable load-balancing mode
|
||||
* @method nodeApp
|
||||
* @param {} env_copy
|
||||
* @param {} cb
|
||||
* @return Literal
|
||||
*/
|
||||
God.nodeApp = function nodeApp(env_copy, cb){
|
||||
var clu = null;
|
||||
|
||||
console.log(`App [${env_copy.name}:${env_copy.pm_id}] starting in -cluster mode-`)
|
||||
if (env_copy.node_args && Array.isArray(env_copy.node_args)) {
|
||||
cluster.settings.execArgv = env_copy.node_args;
|
||||
}
|
||||
|
||||
env_copy._pm2_version = pkg.version;
|
||||
|
||||
try {
|
||||
// node.js cluster clients can not receive deep-level objects or arrays in the forked process, e.g.:
|
||||
// { "args": ["foo", "bar"], "env": { "foo1": "bar1" }} will be parsed to
|
||||
// { "args": "foo, bar", "env": "[object Object]"}
|
||||
// So we passing a stringified JSON here.
|
||||
clu = cluster.fork({pm2_env: JSON.stringify(env_copy), windowsHide: true});
|
||||
} catch(e) {
|
||||
God.logAndGenerateError(e);
|
||||
return cb(e);
|
||||
}
|
||||
|
||||
clu.pm2_env = env_copy;
|
||||
|
||||
/**
|
||||
* Broadcast message to God
|
||||
*/
|
||||
clu.on('message', function cluMessage(msg) {
|
||||
/*********************************
|
||||
* If you edit this function
|
||||
* Do the same in ForkMode.js !
|
||||
*********************************/
|
||||
if (msg.data && msg.type) {
|
||||
return God.bus.emit(msg.type ? msg.type : 'process:msg', {
|
||||
at : Utility.getDate(),
|
||||
data : msg.data,
|
||||
process : {
|
||||
pm_id : clu.pm2_env.pm_id,
|
||||
name : clu.pm2_env.name,
|
||||
rev : (clu.pm2_env.versioning && clu.pm2_env.versioning.revision) ? clu.pm2_env.versioning.revision : null,
|
||||
namespace : clu.pm2_env.namespace
|
||||
}
|
||||
});
|
||||
}
|
||||
else {
|
||||
|
||||
if (typeof msg == 'object' && 'node_version' in msg) {
|
||||
clu.pm2_env.node_version = msg.node_version;
|
||||
return false;
|
||||
}
|
||||
|
||||
return God.bus.emit('process:msg', {
|
||||
at : Utility.getDate(),
|
||||
raw : msg,
|
||||
process : {
|
||||
pm_id : clu.pm2_env.pm_id,
|
||||
name : clu.pm2_env.name,
|
||||
namespace : clu.pm2_env.namespace
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
return cb(null, clu);
|
||||
};
|
||||
};
|
||||
293
api.hyungi.net/node_modules/pm2/lib/God/ForkMode.js
generated
vendored
Normal file
293
api.hyungi.net/node_modules/pm2/lib/God/ForkMode.js
generated
vendored
Normal file
@@ -0,0 +1,293 @@
|
||||
/**
|
||||
* Copyright 2013-2022 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';
|
||||
|
||||
/**
|
||||
* @file Fork execution related functions
|
||||
* @author Alexandre Strzelewicz <as@unitech.io>
|
||||
* @project PM2
|
||||
*/
|
||||
var log = require('debug')('pm2:fork_mode');
|
||||
var fs = require('fs');
|
||||
var Utility = require('../Utility.js');
|
||||
var path = require('path');
|
||||
var dayjs = require('dayjs');
|
||||
var semver = require('semver')
|
||||
|
||||
/**
|
||||
* Description
|
||||
* @method exports
|
||||
* @param {} God
|
||||
* @return
|
||||
*/
|
||||
module.exports = function ForkMode(God) {
|
||||
/**
|
||||
* For all apps - FORK MODE
|
||||
* fork the app
|
||||
* @method forkMode
|
||||
* @param {} pm2_env
|
||||
* @param {} cb
|
||||
* @return
|
||||
*/
|
||||
God.forkMode = function forkMode(pm2_env, cb) {
|
||||
var command = '';
|
||||
var args = [];
|
||||
|
||||
console.log(`App [${pm2_env.name}:${pm2_env.pm_id}] starting in -fork mode-`)
|
||||
var spawn = require('child_process').spawn;
|
||||
|
||||
var interpreter = pm2_env.exec_interpreter || 'node';
|
||||
var pidFile = pm2_env.pm_pid_path;
|
||||
|
||||
if (interpreter !== 'none') {
|
||||
command = interpreter;
|
||||
|
||||
if (pm2_env.node_args && Array.isArray(pm2_env.node_args)) {
|
||||
args = args.concat(pm2_env.node_args);
|
||||
}
|
||||
|
||||
// Deprecated - to remove at some point
|
||||
if (process.env.PM2_NODE_OPTIONS) {
|
||||
args = args.concat(process.env.PM2_NODE_OPTIONS.split(' '));
|
||||
}
|
||||
|
||||
if (interpreter === 'node' || RegExp('node$').test(interpreter)) {
|
||||
args.push(path.resolve(path.dirname(module.filename), '..', 'ProcessContainerFork.js'));
|
||||
}
|
||||
else
|
||||
args.push(pm2_env.pm_exec_path);
|
||||
}
|
||||
else {
|
||||
command = pm2_env.pm_exec_path;
|
||||
args = [ ];
|
||||
}
|
||||
|
||||
if (pm2_env.args) {
|
||||
args = args.concat(pm2_env.args);
|
||||
}
|
||||
|
||||
// piping stream o file
|
||||
var stds = {
|
||||
out: pm2_env.pm_out_log_path,
|
||||
err: pm2_env.pm_err_log_path
|
||||
};
|
||||
|
||||
// entire log std if necessary.
|
||||
if ('pm_log_path' in pm2_env){
|
||||
stds.std = pm2_env.pm_log_path;
|
||||
}
|
||||
|
||||
log("stds: %j", stds);
|
||||
|
||||
Utility.startLogging(stds, function(err, result) {
|
||||
if (err) {
|
||||
God.logAndGenerateError(err);
|
||||
return cb(err);
|
||||
};
|
||||
|
||||
try {
|
||||
var options = {
|
||||
env : pm2_env,
|
||||
detached : true,
|
||||
cwd : pm2_env.pm_cwd || process.cwd(),
|
||||
stdio : ['pipe', 'pipe', 'pipe', 'ipc'] //Same as fork() in node core
|
||||
}
|
||||
|
||||
if (typeof(pm2_env.windowsHide) === "boolean") {
|
||||
options.windowsHide = pm2_env.windowsHide;
|
||||
} else {
|
||||
options.windowsHide = true;
|
||||
}
|
||||
|
||||
if (pm2_env.uid) {
|
||||
options.uid = pm2_env.uid
|
||||
}
|
||||
|
||||
if (pm2_env.gid) {
|
||||
options.gid = pm2_env.gid
|
||||
}
|
||||
|
||||
var cspr = spawn(command, args, options);
|
||||
} catch(e) {
|
||||
God.logAndGenerateError(e);
|
||||
return cb(e);
|
||||
}
|
||||
|
||||
if (!cspr || !cspr.stderr || !cspr.stdout) {
|
||||
var fatalError = new Error('Process could not be forked properly, check your system health')
|
||||
God.logAndGenerateError(fatalError);
|
||||
return cb(fatalError);
|
||||
}
|
||||
|
||||
cspr.process = {};
|
||||
cspr.process.pid = cspr.pid;
|
||||
cspr.pm2_env = pm2_env;
|
||||
|
||||
function transformLogToJson(pm2_env, type, data) {
|
||||
return JSON.stringify({
|
||||
message : data.toString(),
|
||||
timestamp : pm2_env.log_date_format ? dayjs().format(pm2_env.log_date_format) : new Date().toISOString(),
|
||||
type : type,
|
||||
process_id : cspr.pm2_env.pm_id,
|
||||
app_name : cspr.pm2_env.name
|
||||
}) + '\n'
|
||||
}
|
||||
|
||||
function prefixLogWithDate(pm2_env, data) {
|
||||
var log_data = []
|
||||
log_data = data.toString().split('\n')
|
||||
if (log_data.length > 1)
|
||||
log_data.pop()
|
||||
log_data = log_data.map(line => `${dayjs().format(pm2_env.log_date_format)}: ${line}\n`)
|
||||
log_data = log_data.join('')
|
||||
return log_data
|
||||
}
|
||||
|
||||
cspr.stderr.on('data', function forkErrData(data) {
|
||||
var log_data = null;
|
||||
|
||||
// via --out /dev/null --err /dev/null
|
||||
if (pm2_env.disable_logs === true) return false;
|
||||
|
||||
if (pm2_env.log_type && pm2_env.log_type === 'json')
|
||||
log_data = transformLogToJson(pm2_env, 'err', data)
|
||||
else if (pm2_env.log_date_format)
|
||||
log_data = prefixLogWithDate(pm2_env, data)
|
||||
else
|
||||
log_data = data.toString();
|
||||
|
||||
God.bus.emit('log:err', {
|
||||
process : {
|
||||
pm_id : cspr.pm2_env.pm_id,
|
||||
name : cspr.pm2_env.name,
|
||||
rev : (cspr.pm2_env.versioning && cspr.pm2_env.versioning.revision) ? cspr.pm2_env.versioning.revision : null,
|
||||
namespace : cspr.pm2_env.namespace
|
||||
},
|
||||
at : Utility.getDate(),
|
||||
data : log_data
|
||||
});
|
||||
|
||||
if (Utility.checkPathIsNull(pm2_env.pm_err_log_path) &&
|
||||
(!pm2_env.pm_log_path || Utility.checkPathIsNull(pm2_env.pm_log_path))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
stds.std && stds.std.write && stds.std.write(log_data);
|
||||
stds.err && stds.err.write && stds.err.write(log_data);
|
||||
});
|
||||
|
||||
cspr.stdout.on('data', function forkOutData(data) {
|
||||
var log_data = null;
|
||||
|
||||
if (pm2_env.disable_logs === true)
|
||||
return false;
|
||||
|
||||
if (pm2_env.log_type && pm2_env.log_type === 'json')
|
||||
log_data = transformLogToJson(pm2_env, 'out', data)
|
||||
else if (pm2_env.log_date_format)
|
||||
log_data = prefixLogWithDate(pm2_env, data)
|
||||
else
|
||||
log_data = data.toString()
|
||||
|
||||
God.bus.emit('log:out', {
|
||||
process : {
|
||||
pm_id : cspr.pm2_env.pm_id,
|
||||
name : cspr.pm2_env.name,
|
||||
rev : (cspr.pm2_env.versioning && cspr.pm2_env.versioning.revision) ? cspr.pm2_env.versioning.revision : null,
|
||||
namespace : cspr.pm2_env.namespace
|
||||
},
|
||||
at : Utility.getDate(),
|
||||
data : log_data
|
||||
});
|
||||
|
||||
if (Utility.checkPathIsNull(pm2_env.pm_out_log_path) &&
|
||||
(!pm2_env.pm_log_path || Utility.checkPathIsNull(pm2_env.pm_log_path)))
|
||||
return false;
|
||||
|
||||
stds.std && stds.std.write && stds.std.write(log_data);
|
||||
stds.out && stds.out.write && stds.out.write(log_data);
|
||||
});
|
||||
|
||||
/**
|
||||
* Broadcast message to God
|
||||
*/
|
||||
cspr.on('message', function forkMessage(msg) {
|
||||
/*********************************
|
||||
* If you edit this function
|
||||
* Do the same in ClusterMode.js !
|
||||
*********************************/
|
||||
if (msg.data && msg.type) {
|
||||
process.nextTick(function() {
|
||||
return God.bus.emit(msg.type ? msg.type : 'process:msg', {
|
||||
at : Utility.getDate(),
|
||||
data : msg.data,
|
||||
process : {
|
||||
pm_id : cspr.pm2_env.pm_id,
|
||||
name : cspr.pm2_env.name,
|
||||
versioning : cspr.pm2_env.versioning,
|
||||
namespace : cspr.pm2_env.namespace
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
else {
|
||||
|
||||
if (typeof msg == 'object' && 'node_version' in msg) {
|
||||
cspr.pm2_env.node_version = msg.node_version;
|
||||
return false;
|
||||
}
|
||||
|
||||
return God.bus.emit('process:msg', {
|
||||
at : Utility.getDate(),
|
||||
raw : msg,
|
||||
process : {
|
||||
pm_id : cspr.pm2_env.pm_id,
|
||||
name : cspr.pm2_env.name,
|
||||
namespace : cspr.pm2_env.namespace
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
try {
|
||||
var pid = cspr.pid
|
||||
if (typeof(pid) !== 'undefined')
|
||||
fs.writeFileSync(pidFile, pid.toString());
|
||||
} catch (e) {
|
||||
console.error(e.stack || e);
|
||||
}
|
||||
|
||||
cspr.once('exit', function forkClose(status) {
|
||||
try {
|
||||
for(var k in stds){
|
||||
if (stds[k] && stds[k].destroy) stds[k].destroy();
|
||||
else if (stds[k] && stds[k].end) stds[k].end();
|
||||
else if (stds[k] && stds[k].close) stds[k].close();
|
||||
stds[k] = stds[k]._file;
|
||||
}
|
||||
} catch(e) { God.logAndGenerateError(e);}
|
||||
});
|
||||
|
||||
cspr._reloadLogs = function(cb) {
|
||||
try {
|
||||
for (var k in stds){
|
||||
if (stds[k] && stds[k].destroy) stds[k].destroy();
|
||||
else if (stds[k] && stds[k].end) stds[k].end();
|
||||
else if (stds[k] && stds[k].close) stds[k].close();
|
||||
stds[k] = stds[k]._file;
|
||||
}
|
||||
} catch(e) { God.logAndGenerateError(e);}
|
||||
//cspr.removeAllListeners();
|
||||
Utility.startLogging(stds, cb);
|
||||
};
|
||||
|
||||
cspr.unref();
|
||||
|
||||
return cb(null, cspr);
|
||||
});
|
||||
|
||||
};
|
||||
};
|
||||
265
api.hyungi.net/node_modules/pm2/lib/God/Methods.js
generated
vendored
Normal file
265
api.hyungi.net/node_modules/pm2/lib/God/Methods.js
generated
vendored
Normal file
@@ -0,0 +1,265 @@
|
||||
/**
|
||||
* Copyright 2013-2022 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';
|
||||
|
||||
/**
|
||||
* @file Utilities for PM2
|
||||
* @author Alexandre Strzelewicz <as@unitech.io>
|
||||
* @project PM2
|
||||
*/
|
||||
var p = require('path');
|
||||
var treekill = require('../TreeKill');
|
||||
var cst = require('../../constants.js');
|
||||
|
||||
/**
|
||||
* Description
|
||||
* @method exports
|
||||
* @param {} God
|
||||
* @return
|
||||
*/
|
||||
module.exports = function(God) {
|
||||
|
||||
/**
|
||||
* Description
|
||||
* @method logAndGenerateError
|
||||
* @param {} err
|
||||
* @return NewExpression
|
||||
*/
|
||||
God.logAndGenerateError = function(err) {
|
||||
// Is an Error object
|
||||
if (err instanceof Error) {
|
||||
console.trace(err);
|
||||
return err;
|
||||
}
|
||||
// Is a JSON or simple string
|
||||
console.error(err);
|
||||
return new Error(err);
|
||||
};
|
||||
|
||||
/**
|
||||
* Utility functions
|
||||
* @method getProcesses
|
||||
* @return MemberExpression
|
||||
*/
|
||||
God.getProcesses = function() {
|
||||
return God.clusters_db;
|
||||
};
|
||||
|
||||
God.getFormatedProcess = function getFormatedProcesses(id) {
|
||||
if (God.clusters_db[id])
|
||||
return {
|
||||
pid : God.clusters_db[id].process.pid,
|
||||
name : God.clusters_db[id].pm2_env.name,
|
||||
pm2_env : God.clusters_db[id].pm2_env,
|
||||
pm_id : God.clusters_db[id].pm2_env.pm_id
|
||||
};
|
||||
return {};
|
||||
};
|
||||
|
||||
/**
|
||||
* Get formated processes
|
||||
* @method getFormatedProcesses
|
||||
* @return {Array} formated processes
|
||||
*/
|
||||
God.getFormatedProcesses = function getFormatedProcesses() {
|
||||
var keys = Object.keys(God.clusters_db);
|
||||
var arr = new Array();
|
||||
var kl = keys.length;
|
||||
|
||||
for (var i = 0; i < kl; i++) {
|
||||
var key = keys[i];
|
||||
|
||||
if (!God.clusters_db[key]) continue;
|
||||
// Avoid _old type pm_ids
|
||||
if (isNaN(God.clusters_db[key].pm2_env.pm_id)) continue;
|
||||
|
||||
arr.push({
|
||||
pid : God.clusters_db[key].process.pid,
|
||||
name : God.clusters_db[key].pm2_env.name,
|
||||
pm2_env : God.clusters_db[key].pm2_env,
|
||||
pm_id : God.clusters_db[key].pm2_env.pm_id
|
||||
})
|
||||
}
|
||||
return arr;
|
||||
};
|
||||
|
||||
/**
|
||||
* Description
|
||||
* @method findProcessById
|
||||
* @param {} id
|
||||
* @return ConditionalExpression
|
||||
*/
|
||||
God.findProcessById = function findProcessById(id) {
|
||||
return God.clusters_db[id] ? God.clusters_db[id] : null;
|
||||
};
|
||||
|
||||
/**
|
||||
* Description
|
||||
* @method findByName
|
||||
* @param {} name
|
||||
* @return arr
|
||||
*/
|
||||
God.findByName = function(name) {
|
||||
var db = God.clusters_db;
|
||||
var arr = [];
|
||||
|
||||
if (name == 'all') {
|
||||
for (var key in db) {
|
||||
// Avoid _old_proc process style
|
||||
if (typeof(God.clusters_db[key].pm2_env.pm_id) === 'number')
|
||||
arr.push(db[key]);
|
||||
}
|
||||
return arr;
|
||||
}
|
||||
|
||||
for (var key in db) {
|
||||
if (God.clusters_db[key].pm2_env.name == name ||
|
||||
God.clusters_db[key].pm2_env.pm_exec_path == p.resolve(name)) {
|
||||
arr.push(db[key]);
|
||||
}
|
||||
}
|
||||
return arr;
|
||||
};
|
||||
|
||||
/**
|
||||
* Check if a process is alive in system processes
|
||||
* Return TRUE if process online
|
||||
* @method checkProcess
|
||||
* @param {} pid
|
||||
* @return
|
||||
*/
|
||||
God.checkProcess = function(pid) {
|
||||
if (!pid) return false;
|
||||
|
||||
try {
|
||||
// Sending 0 signal do not kill the process
|
||||
process.kill(pid, 0);
|
||||
return true;
|
||||
}
|
||||
catch (err) {
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Description
|
||||
* @method processIsDead
|
||||
* @param {} pid
|
||||
* @param {} cb
|
||||
* @return Literal
|
||||
*/
|
||||
God.processIsDead = function(pid, pm2_env, cb, sigkill) {
|
||||
if (!pid) return cb({type : 'param:missing', msg : 'no pid passed'});
|
||||
|
||||
var timeout = null;
|
||||
var kill_timeout = (pm2_env && pm2_env.kill_timeout) ? pm2_env.kill_timeout : cst.KILL_TIMEOUT;
|
||||
var mode = pm2_env.exec_mode;
|
||||
|
||||
var timer = setInterval(function() {
|
||||
if (God.checkProcess(pid) === false) {
|
||||
console.log('pid=%d msg=process killed', pid);
|
||||
clearTimeout(timeout);
|
||||
clearInterval(timer);
|
||||
return cb(null, true);
|
||||
}
|
||||
console.log('pid=%d msg=failed to kill - retrying in %dms', pid, pm2_env.kill_retry_time);
|
||||
return false;
|
||||
}, pm2_env.kill_retry_time);
|
||||
|
||||
timeout = setTimeout(function() {
|
||||
clearInterval(timer);
|
||||
if (sigkill) {
|
||||
console.log('Process with pid %d could not be killed', pid);
|
||||
return cb({type : 'timeout', msg : 'timeout'});
|
||||
}
|
||||
else {
|
||||
console.log('Process with pid %d still alive after %sms, sending it SIGKILL now...', pid, kill_timeout);
|
||||
|
||||
if (pm2_env.treekill !== true) {
|
||||
try {
|
||||
process.kill(parseInt(pid), 'SIGKILL');
|
||||
} catch(e) {
|
||||
console.error('[SimpleKill][SIGKILL] %s pid can not be killed', pid, e.stack, e.message);
|
||||
}
|
||||
return God.processIsDead(pid, pm2_env, cb, true);
|
||||
}
|
||||
else {
|
||||
treekill(parseInt(pid), 'SIGKILL', function(err) {
|
||||
return God.processIsDead(pid, pm2_env, cb, true);
|
||||
});
|
||||
}
|
||||
}
|
||||
}, kill_timeout);
|
||||
return false;
|
||||
};
|
||||
|
||||
/**
|
||||
* Description
|
||||
* @method killProcess
|
||||
* @param int pid
|
||||
* @param Object pm2_env
|
||||
* @param function cb
|
||||
* @return CallExpression
|
||||
*/
|
||||
God.killProcess = function(pid, pm2_env, cb) {
|
||||
if (!pid) return cb({msg : 'no pid passed or null'});
|
||||
|
||||
if (typeof(pm2_env.pm_id) === 'number' &&
|
||||
(cst.KILL_USE_MESSAGE || pm2_env.shutdown_with_message == true)) {
|
||||
var proc = God.clusters_db[pm2_env.pm_id];
|
||||
|
||||
if (proc && proc.send) {
|
||||
try {
|
||||
proc.send('shutdown');
|
||||
} catch (e) {
|
||||
console.error(`[AppKill] Cannot send "shutdown" message to ${pid}`)
|
||||
console.error(e.stack, e.message)
|
||||
}
|
||||
return God.processIsDead(pid, pm2_env, cb);
|
||||
}
|
||||
else {
|
||||
console.log(`[AppKill] ${pid} pid cannot be notified with send()`)
|
||||
}
|
||||
}
|
||||
|
||||
if (pm2_env.treekill !== true) {
|
||||
try {
|
||||
process.kill(parseInt(pid), cst.KILL_SIGNAL);
|
||||
} catch(e) {
|
||||
console.error('[SimpleKill] %s pid can not be killed', pid, e.stack, e.message);
|
||||
}
|
||||
return God.processIsDead(pid, pm2_env, cb);
|
||||
}
|
||||
else {
|
||||
treekill(parseInt(pid), cst.KILL_SIGNAL, function(err) {
|
||||
return God.processIsDead(pid, pm2_env, cb);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Description
|
||||
* @method getNewId
|
||||
* @return UpdateExpression
|
||||
*/
|
||||
God.getNewId = function() {
|
||||
return God.next_id++;
|
||||
};
|
||||
|
||||
/**
|
||||
* When a process is restarted or reloaded reset fields
|
||||
* to monitor unstable starts
|
||||
* @method resetState
|
||||
* @param {} pm2_env
|
||||
* @return
|
||||
*/
|
||||
God.resetState = function(pm2_env) {
|
||||
pm2_env.created_at = Date.now();
|
||||
pm2_env.unstable_restarts = 0;
|
||||
pm2_env.prev_restart_delay = 0;
|
||||
};
|
||||
|
||||
};
|
||||
240
api.hyungi.net/node_modules/pm2/lib/God/Reload.js
generated
vendored
Normal file
240
api.hyungi.net/node_modules/pm2/lib/God/Reload.js
generated
vendored
Normal file
@@ -0,0 +1,240 @@
|
||||
/**
|
||||
* Copyright 2013-2022 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';
|
||||
|
||||
/**
|
||||
* @file Reload functions related
|
||||
* @author Alexandre Strzelewicz <as@unitech.io>
|
||||
* @project PM2
|
||||
*/
|
||||
|
||||
var cst = require('../../constants.js');
|
||||
var Utility = require('../Utility.js');
|
||||
|
||||
/**
|
||||
* softReload will wait permission from process to exit
|
||||
* @method softReload
|
||||
* @param {} God
|
||||
* @param {} id
|
||||
* @param {} cb
|
||||
* @return Literal
|
||||
*/
|
||||
function softReload(God, id, cb) {
|
||||
var t_key = '_old_' + id;
|
||||
|
||||
// Move old worker to tmp id
|
||||
God.clusters_db[t_key] = God.clusters_db[id];
|
||||
|
||||
delete God.clusters_db[id];
|
||||
|
||||
var old_worker = God.clusters_db[t_key];
|
||||
|
||||
// Deep copy
|
||||
var new_env = Utility.clone(old_worker.pm2_env);
|
||||
|
||||
// Reset created_at and unstable_restarts
|
||||
God.resetState(new_env);
|
||||
|
||||
new_env.restart_time += 1;
|
||||
|
||||
old_worker.pm2_env.pm_id = t_key;
|
||||
old_worker.pm_id = t_key;
|
||||
|
||||
God.executeApp(new_env, function(err, new_worker) {
|
||||
if (err) return cb(err);
|
||||
|
||||
var timer = null;
|
||||
|
||||
var onListen = function () {
|
||||
clearTimeout(timer);
|
||||
softCleanDeleteProcess();
|
||||
console.log('-softReload- New worker listening');
|
||||
};
|
||||
|
||||
// Bind to know when the new process is up
|
||||
new_worker.once('listening', onListen);
|
||||
|
||||
timer = setTimeout(function() {
|
||||
new_worker.removeListener('listening', onListen);
|
||||
softCleanDeleteProcess();
|
||||
}, new_env.listen_timeout || cst.GRACEFUL_LISTEN_TIMEOUT);
|
||||
|
||||
// Remove old worker properly
|
||||
var softCleanDeleteProcess = function () {
|
||||
var cleanUp = function () {
|
||||
clearTimeout(timer);
|
||||
console.log('-softReload- Old worker disconnected');
|
||||
return God.deleteProcessId(t_key, cb);
|
||||
};
|
||||
|
||||
old_worker.once('disconnect', cleanUp);
|
||||
|
||||
try {
|
||||
if (old_worker.state != 'dead' && old_worker.state != 'disconnected')
|
||||
old_worker.send && old_worker.send('shutdown');
|
||||
else {
|
||||
clearTimeout(timer);
|
||||
console.error('Worker %d is already disconnected', old_worker.pm2_env.pm_id);
|
||||
return God.deleteProcessId(t_key, cb);
|
||||
}
|
||||
} catch(e) {
|
||||
clearTimeout(timer);
|
||||
console.error('Worker %d is already disconnected', old_worker.pm2_env.pm_id);
|
||||
return God.deleteProcessId(t_key, cb);
|
||||
}
|
||||
|
||||
timer = setTimeout(function () {
|
||||
old_worker.removeListener('disconnect', cleanUp);
|
||||
return God.deleteProcessId(t_key, cb);
|
||||
}, cst.GRACEFUL_TIMEOUT);
|
||||
return false;
|
||||
};
|
||||
return false;
|
||||
});
|
||||
return false;
|
||||
};
|
||||
|
||||
/**
|
||||
* hardReload will reload without waiting permission from process
|
||||
* @method hardReload
|
||||
* @param {} God
|
||||
* @param {} id
|
||||
* @param {} cb
|
||||
* @return Literal
|
||||
*/
|
||||
function hardReload(God, id, wait_msg, cb) {
|
||||
var t_key = '_old_' + id;
|
||||
|
||||
// Move old worker to tmp id
|
||||
God.clusters_db[t_key] = God.clusters_db[id];
|
||||
delete God.clusters_db[id];
|
||||
|
||||
var old_worker = God.clusters_db[t_key];
|
||||
// Deep copy
|
||||
var new_env = Utility.clone(old_worker.pm2_env);
|
||||
new_env.restart_time += 1;
|
||||
|
||||
// Reset created_at and unstable_restarts
|
||||
God.resetState(new_env);
|
||||
|
||||
old_worker.pm2_env.pm_id = t_key;
|
||||
old_worker.pm_id = t_key;
|
||||
var timer = null;
|
||||
var readySignalSent = false;
|
||||
|
||||
var onListen = function () {
|
||||
clearTimeout(timer);
|
||||
readySignalSent = true;
|
||||
console.log('-reload- New worker listening');
|
||||
return God.deleteProcessId(t_key, cb);
|
||||
};
|
||||
|
||||
var listener = function (packet) {
|
||||
if (packet.raw === 'ready' &&
|
||||
packet.process.name === old_worker.pm2_env.name &&
|
||||
packet.process.pm_id === id) {
|
||||
God.bus.removeListener('process:msg', listener);
|
||||
return onListen();
|
||||
}
|
||||
};
|
||||
|
||||
if (wait_msg !== 'listening') {
|
||||
God.bus.on('process:msg', listener);
|
||||
}
|
||||
|
||||
God.executeApp(new_env, function(err, new_worker) {
|
||||
if (err) return cb(err);
|
||||
|
||||
// Bind to know when the new process is up
|
||||
if (wait_msg === 'listening') {
|
||||
new_worker.once('listening', onListen);
|
||||
}
|
||||
|
||||
timer = setTimeout(function() {
|
||||
if (readySignalSent) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (wait_msg === 'listening')
|
||||
new_worker.removeListener(wait_msg, onListen);
|
||||
else
|
||||
God.bus.removeListener('process:msg', listener);
|
||||
|
||||
return God.deleteProcessId(t_key, cb);
|
||||
}, new_env.listen_timeout || cst.GRACEFUL_LISTEN_TIMEOUT);
|
||||
|
||||
return false;
|
||||
});
|
||||
return false;
|
||||
};
|
||||
|
||||
/**
|
||||
* Description
|
||||
* @method exports
|
||||
* @param {} God
|
||||
* @return
|
||||
*/
|
||||
module.exports = function(God) {
|
||||
|
||||
/**
|
||||
* Reload
|
||||
* @method softReloadProcessId
|
||||
* @param {} id
|
||||
* @param {} cb
|
||||
* @return CallExpression
|
||||
*/
|
||||
God.softReloadProcessId = function(opts, cb) {
|
||||
var id = opts.id;
|
||||
var env = opts.env || {};
|
||||
|
||||
if (!(id in God.clusters_db))
|
||||
return cb(new Error(`pm_id ${id} not available in ${id}`));
|
||||
|
||||
if (God.clusters_db[id].pm2_env.status == cst.ONLINE_STATUS &&
|
||||
God.clusters_db[id].pm2_env.exec_mode == 'cluster_mode' &&
|
||||
!God.clusters_db[id].pm2_env.wait_ready) {
|
||||
|
||||
Utility.extend(God.clusters_db[id].pm2_env.env, opts.env);
|
||||
Utility.extendExtraConfig(God.clusters_db[id], opts);
|
||||
|
||||
return softReload(God, id, cb);
|
||||
}
|
||||
else {
|
||||
console.log('Process %s in a stopped status, starting it', id);
|
||||
return God.restartProcessId(opts, cb);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Reload
|
||||
* @method reloadProcessId
|
||||
* @param {} id
|
||||
* @param {} cb
|
||||
* @return CallExpression
|
||||
*/
|
||||
God.reloadProcessId = function(opts, cb) {
|
||||
var id = opts.id;
|
||||
var env = opts.env || {};
|
||||
|
||||
if (!(id in God.clusters_db))
|
||||
return cb(new Error('PM2 ID unknown'));
|
||||
|
||||
if (God.clusters_db[id].pm2_env.status == cst.ONLINE_STATUS &&
|
||||
God.clusters_db[id].pm2_env.exec_mode == 'cluster_mode') {
|
||||
|
||||
Utility.extend(God.clusters_db[id].pm2_env.env, opts.env);
|
||||
Utility.extendExtraConfig(God.clusters_db[id], opts);
|
||||
|
||||
var wait_msg = God.clusters_db[id].pm2_env.wait_ready ? 'ready' : 'listening';
|
||||
return hardReload(God, id, wait_msg, cb);
|
||||
}
|
||||
else {
|
||||
console.log('Process %s in a stopped status, starting it', id);
|
||||
return God.restartProcessId(opts, cb);
|
||||
}
|
||||
};
|
||||
|
||||
};
|
||||
76
api.hyungi.net/node_modules/pm2/lib/HttpInterface.js
generated
vendored
Normal file
76
api.hyungi.net/node_modules/pm2/lib/HttpInterface.js
generated
vendored
Normal file
@@ -0,0 +1,76 @@
|
||||
/**
|
||||
* Copyright 2013-2022 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 os = require('os');
|
||||
var pm2 = require('../index.js');
|
||||
var urlT = require('url');
|
||||
var cst = require('../constants.js');
|
||||
|
||||
// Default, attach to default local PM2
|
||||
|
||||
pm2.connect(function() {
|
||||
startWebServer(pm2);
|
||||
});
|
||||
|
||||
function startWebServer(pm2) {
|
||||
http.createServer(function (req, res) {
|
||||
// Add CORS headers to allow browsers to fetch data directly
|
||||
res.setHeader('Access-Control-Allow-Origin', '*');
|
||||
res.setHeader('Access-Control-Allow-Headers', 'Cache-Control, Pragma, Origin, Authorization, Content-Type, X-Requested-With');
|
||||
res.setHeader('Access-Control-Allow-Methods', 'GET');
|
||||
|
||||
// We always send json
|
||||
res.setHeader('Content-Type','application/json');
|
||||
|
||||
var path = urlT.parse(req.url).pathname;
|
||||
|
||||
if (path == '/') {
|
||||
// Main monit route
|
||||
pm2.list(function(err, list) {
|
||||
if (err) {
|
||||
return res.send(err);
|
||||
}
|
||||
var data = {
|
||||
system_info: { hostname: os.hostname(),
|
||||
uptime: os.uptime()
|
||||
},
|
||||
monit: { loadavg: os.loadavg(),
|
||||
total_mem: os.totalmem(),
|
||||
free_mem: os.freemem(),
|
||||
cpu: os.cpus(),
|
||||
interfaces: os.networkInterfaces()
|
||||
},
|
||||
processes: list
|
||||
};
|
||||
|
||||
if (cst.WEB_STRIP_ENV_VARS === true) {
|
||||
for (var i = data.processes.length - 1; i >= 0; i--) {
|
||||
var proc = data.processes[i];
|
||||
|
||||
// Strip important environment variables
|
||||
if (typeof proc.pm2_env === 'undefined' && typeof proc.pm2_env.env === 'undefined') return;
|
||||
|
||||
delete proc.pm2_env.env;
|
||||
}
|
||||
}
|
||||
|
||||
res.statusCode = 200;
|
||||
res.write(JSON.stringify(data));
|
||||
return res.end();
|
||||
|
||||
})
|
||||
}
|
||||
else {
|
||||
// 404
|
||||
res.statusCode = 404;
|
||||
res.write(JSON.stringify({err : '404'}));
|
||||
return res.end();
|
||||
}
|
||||
}).listen(process.env.PM2_WEB_PORT || cst.WEB_PORT, cst.WEB_IPADDR, function() {
|
||||
console.log('Web interface listening on %s:%s', cst.WEB_IPADDR, cst.WEB_PORT);
|
||||
});
|
||||
|
||||
}
|
||||
315
api.hyungi.net/node_modules/pm2/lib/ProcessContainer.js
generated
vendored
Normal file
315
api.hyungi.net/node_modules/pm2/lib/ProcessContainer.js
generated
vendored
Normal file
@@ -0,0 +1,315 @@
|
||||
/**
|
||||
* Copyright 2013-2022 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.
|
||||
*
|
||||
* This file wrap target application
|
||||
* - redirect stdin, stderr to bus + log files
|
||||
* - rename process
|
||||
* - pid
|
||||
*/
|
||||
|
||||
var p = require('path');
|
||||
var cst = require('../constants');
|
||||
var Utility = require('./Utility.js');
|
||||
var ProcessUtils = require('./ProcessUtils');
|
||||
var Url = require('url');
|
||||
|
||||
// Load all env-vars from master.
|
||||
var pm2_env = JSON.parse(process.env.pm2_env);
|
||||
for(var k in pm2_env) {
|
||||
process.env[k] = pm2_env[k];
|
||||
}
|
||||
|
||||
// Rename process
|
||||
process.title = process.env.PROCESS_TITLE || 'node ' + pm2_env.pm_exec_path;
|
||||
|
||||
delete process.env.pm2_env;
|
||||
|
||||
/**
|
||||
* Main entrance to wrap the desired code
|
||||
*/
|
||||
(function ProcessContainer() {
|
||||
var fs = require('fs');
|
||||
|
||||
ProcessUtils.injectModules()
|
||||
|
||||
var stdFile = pm2_env.pm_log_path;
|
||||
var outFile = pm2_env.pm_out_log_path;
|
||||
var errFile = pm2_env.pm_err_log_path;
|
||||
var pidFile = pm2_env.pm_pid_path;
|
||||
var script = pm2_env.pm_exec_path;
|
||||
|
||||
var original_send = process.send;
|
||||
|
||||
if (typeof(process.env.source_map_support) != 'undefined' &&
|
||||
process.env.source_map_support !== 'false') {
|
||||
require('source-map-support').install();
|
||||
}
|
||||
|
||||
process.send = function() {
|
||||
if (process.connected)
|
||||
original_send.apply(this, arguments);
|
||||
};
|
||||
|
||||
//send node version
|
||||
if (process.versions && process.versions.node) {
|
||||
process.send({
|
||||
'node_version': process.versions.node
|
||||
});
|
||||
}
|
||||
|
||||
if (cst.MODIFY_REQUIRE)
|
||||
require.main.filename = pm2_env.pm_exec_path;
|
||||
|
||||
// Resets global paths for require()
|
||||
require('module')._initPaths();
|
||||
|
||||
try {
|
||||
var pid = process.pid
|
||||
if (typeof(pid) !== 'undefined')
|
||||
fs.writeFileSync(pidFile, process.pid.toString());
|
||||
} catch (e) {
|
||||
console.error(e.stack || e);
|
||||
}
|
||||
|
||||
// Add args to process if args specified on start
|
||||
if (process.env.args != null)
|
||||
process.argv = process.argv.concat(pm2_env.args);
|
||||
|
||||
// stdio, including: out, err and entire (both out and err if necessary).
|
||||
var stds = {
|
||||
out: outFile,
|
||||
err: errFile
|
||||
};
|
||||
stdFile && (stds.std = stdFile);
|
||||
|
||||
// uid/gid management
|
||||
if (pm2_env.uid || pm2_env.gid) {
|
||||
try {
|
||||
if (process.env.gid)
|
||||
process.setgid(pm2_env.gid);
|
||||
if (pm2_env.uid)
|
||||
process.setuid(pm2_env.uid);
|
||||
} catch(e) {
|
||||
setTimeout(function() {
|
||||
console.error('%s on call %s', e.message, e.syscall);
|
||||
console.error('%s is not accessible', pm2_env.uid);
|
||||
return process.exit(1);
|
||||
}, 100);
|
||||
}
|
||||
}
|
||||
|
||||
exec(script, stds);
|
||||
})();
|
||||
|
||||
/**
|
||||
* Description
|
||||
* @method exec
|
||||
* @param {} script
|
||||
* @param {} stds
|
||||
* @return
|
||||
*/
|
||||
function exec(script, stds) {
|
||||
if (p.extname(script) == '.coffee') {
|
||||
try {
|
||||
require('coffee-script/register');
|
||||
} catch (e) {
|
||||
console.error('Failed to load CoffeeScript interpreter:', e.message || e);
|
||||
}
|
||||
}
|
||||
|
||||
if (p.extname(script) == '.ls') {
|
||||
try {
|
||||
require('livescript');
|
||||
} catch (e) {
|
||||
console.error('Failed to load LiveScript interpreter:', e.message || e);
|
||||
}
|
||||
}
|
||||
|
||||
if (p.extname(script) == '.ts' || p.extname(script) == '.tsx') {
|
||||
try {
|
||||
require('ts-node/register');
|
||||
} catch (e) {
|
||||
console.error('Failed to load Typescript interpreter:', e.message || e);
|
||||
}
|
||||
}
|
||||
|
||||
process.on('message', function (msg) {
|
||||
if (msg.type === 'log:reload') {
|
||||
for (var k in stds){
|
||||
if (typeof stds[k] == 'object' && !isNaN(stds[k].fd)){
|
||||
if (stds[k].destroy) stds[k].destroy();
|
||||
else if (stds[k].end) stds[k].end();
|
||||
else if (stds[k].close) stds[k].close();
|
||||
stds[k] = stds[k]._file;
|
||||
}
|
||||
}
|
||||
Utility.startLogging(stds, function (err) {
|
||||
if (err)
|
||||
return console.error('Failed to reload logs:', err.stack);
|
||||
console.log('Reloading log...');
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
var dayjs = null;
|
||||
|
||||
if (pm2_env.log_date_format)
|
||||
dayjs = require('dayjs');
|
||||
|
||||
Utility.startLogging(stds, function (err) {
|
||||
if (err) {
|
||||
process.send({
|
||||
type : 'process:exception',
|
||||
data : {
|
||||
message: err.message,
|
||||
syscall: 'ProcessContainer.startLogging'
|
||||
}
|
||||
});
|
||||
throw err;
|
||||
return;
|
||||
}
|
||||
|
||||
process.stderr.write = (function(write) {
|
||||
return function(string, encoding, cb) {
|
||||
var log_data = null;
|
||||
|
||||
// Disable logs if specified
|
||||
if (pm2_env.disable_logs === true) {
|
||||
return cb ? cb() : false;
|
||||
}
|
||||
|
||||
if (pm2_env.log_type && pm2_env.log_type === 'json') {
|
||||
log_data = JSON.stringify({
|
||||
message : string.toString(),
|
||||
timestamp : pm2_env.log_date_format && dayjs ?
|
||||
dayjs().format(pm2_env.log_date_format) : new Date().toISOString(),
|
||||
type : 'err',
|
||||
process_id : pm2_env.pm_id,
|
||||
app_name : pm2_env.name
|
||||
}) + '\n';
|
||||
}
|
||||
else if (pm2_env.log_date_format && dayjs)
|
||||
log_data = `${dayjs().format(pm2_env.log_date_format)}: ${string.toString()}`;
|
||||
else
|
||||
log_data = string.toString();
|
||||
|
||||
process.send({
|
||||
type : 'log:err',
|
||||
topic : 'log:err',
|
||||
data : log_data
|
||||
});
|
||||
|
||||
if (Utility.checkPathIsNull(pm2_env.pm_err_log_path) &&
|
||||
(!pm2_env.pm_log_path || Utility.checkPathIsNull(pm2_env.pm_log_path)))
|
||||
return cb ? cb() : false;
|
||||
|
||||
stds.std && stds.std.write && stds.std.write(log_data, encoding);
|
||||
stds.err && stds.err.write && stds.err.write(log_data, encoding, cb);
|
||||
};
|
||||
})(process.stderr.write);
|
||||
|
||||
process.stdout.write = (function(write) {
|
||||
return function(string, encoding, cb) {
|
||||
var log_data = null;
|
||||
|
||||
// Disable logs if specified
|
||||
if (pm2_env.disable_logs === true) {
|
||||
return cb ? cb() : false;
|
||||
}
|
||||
|
||||
if (pm2_env.log_type && pm2_env.log_type === 'json') {
|
||||
log_data = JSON.stringify({
|
||||
message : string.toString(),
|
||||
timestamp : pm2_env.log_date_format && dayjs ?
|
||||
dayjs().format(pm2_env.log_date_format) : new Date().toISOString(),
|
||||
type : 'out',
|
||||
process_id : pm2_env.pm_id,
|
||||
app_name : pm2_env.name
|
||||
}) + '\n';
|
||||
}
|
||||
else if (pm2_env.log_date_format && dayjs)
|
||||
log_data = `${dayjs().format(pm2_env.log_date_format)}: ${string.toString()}`;
|
||||
else
|
||||
log_data = string.toString();
|
||||
|
||||
process.send({
|
||||
type : 'log:out',
|
||||
data : log_data
|
||||
});
|
||||
|
||||
if (Utility.checkPathIsNull(pm2_env.pm_out_log_path) &&
|
||||
(!pm2_env.pm_log_path || Utility.checkPathIsNull(pm2_env.pm_log_path)))
|
||||
return cb ? cb() : null;
|
||||
|
||||
stds.std && stds.std.write && stds.std.write(log_data, encoding);
|
||||
stds.out && stds.out.write && stds.out.write(log_data, encoding, cb);
|
||||
};
|
||||
})(process.stdout.write);
|
||||
|
||||
function getUncaughtExceptionListener(listener) {
|
||||
return function uncaughtListener(err) {
|
||||
var error = err && err.stack ? err.stack : err;
|
||||
|
||||
if (listener === 'unhandledRejection') {
|
||||
error = 'You have triggered an unhandledRejection, you may have forgotten to catch a Promise rejection:\n' + error;
|
||||
}
|
||||
|
||||
logError(['std', 'err'], error);
|
||||
|
||||
// Notify master that an uncaughtException has been catched
|
||||
try {
|
||||
if (err) {
|
||||
var errObj = {};
|
||||
|
||||
Object.getOwnPropertyNames(err).forEach(function(key) {
|
||||
errObj[key] = err[key];
|
||||
});
|
||||
}
|
||||
|
||||
process.send({
|
||||
type : 'log:err',
|
||||
topic : 'log:err',
|
||||
data : '\n' + error + '\n'
|
||||
});
|
||||
process.send({
|
||||
type : 'process:exception',
|
||||
data : errObj !== undefined ? errObj : {message: 'No error but ' + listener + ' was caught!'}
|
||||
});
|
||||
} catch(e) {
|
||||
logError(['std', 'err'], 'Channel is already closed can\'t broadcast error:\n' + e.stack);
|
||||
}
|
||||
|
||||
if (!process.listeners(listener).filter(function (listener) {
|
||||
return listener !== uncaughtListener;
|
||||
}).length) {
|
||||
if (listener == 'uncaughtException') {
|
||||
process.emit('disconnect');
|
||||
process.exit(cst.CODE_UNCAUGHTEXCEPTION);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
process.on('uncaughtException', getUncaughtExceptionListener('uncaughtException'));
|
||||
process.on('unhandledRejection', getUncaughtExceptionListener('unhandledRejection'));
|
||||
|
||||
// Change dir to fix process.cwd
|
||||
process.chdir(pm2_env.pm_cwd || process.env.PWD || p.dirname(script));
|
||||
|
||||
if (ProcessUtils.isESModule(script) === true)
|
||||
import(Url.pathToFileURL(process.env.pm_exec_path));
|
||||
else
|
||||
require('module')._load(script, null, true);
|
||||
|
||||
function logError(types, error){
|
||||
try {
|
||||
types.forEach(function(type){
|
||||
stds[type] && typeof stds[type].write == 'function' && stds[type].write(error + '\n');
|
||||
});
|
||||
} catch(e) { }
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
42
api.hyungi.net/node_modules/pm2/lib/ProcessContainerFork.js
generated
vendored
Normal file
42
api.hyungi.net/node_modules/pm2/lib/ProcessContainerFork.js
generated
vendored
Normal file
@@ -0,0 +1,42 @@
|
||||
/**
|
||||
* Copyright 2013-2022 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 url = require('url');
|
||||
// Inject custom modules
|
||||
var ProcessUtils = require('./ProcessUtils')
|
||||
ProcessUtils.injectModules()
|
||||
|
||||
if (typeof(process.env.source_map_support) != "undefined" &&
|
||||
process.env.source_map_support !== "false") {
|
||||
require('source-map-support').install();
|
||||
}
|
||||
|
||||
// Rename the process
|
||||
process.title = process.env.PROCESS_TITLE || 'node ' + process.env.pm_exec_path;
|
||||
|
||||
if (process.connected &&
|
||||
process.send &&
|
||||
process.versions &&
|
||||
process.versions.node)
|
||||
process.send({
|
||||
'node_version': process.versions.node
|
||||
});
|
||||
|
||||
// Require the real application
|
||||
if (process.env.pm_exec_path) {
|
||||
if (ProcessUtils.isESModule(process.env.pm_exec_path) === true) {
|
||||
import(url.pathToFileURL(process.env.pm_exec_path));
|
||||
}
|
||||
else
|
||||
require('module')._load(process.env.pm_exec_path, null, true);
|
||||
}
|
||||
else
|
||||
throw new Error('Could not _load() the script');
|
||||
|
||||
// Change some values to make node think that the user's application
|
||||
// was started directly such as `node app.js`
|
||||
process.mainModule = process.mainModule || {};
|
||||
process.mainModule.loaded = false;
|
||||
require.main = process.mainModule;
|
||||
55
api.hyungi.net/node_modules/pm2/lib/ProcessUtils.js
generated
vendored
Normal file
55
api.hyungi.net/node_modules/pm2/lib/ProcessUtils.js
generated
vendored
Normal file
@@ -0,0 +1,55 @@
|
||||
'use strict'
|
||||
|
||||
module.exports = {
|
||||
injectModules: function() {
|
||||
if (process.env.pmx !== 'false') {
|
||||
const pmx = require('@pm2/io')
|
||||
|
||||
let conf = {}
|
||||
const hasSpecificConfig = typeof process.env.io === 'string' || process.env.trace === 'true'
|
||||
// pmx is already init, no need to do it twice
|
||||
if (hasSpecificConfig === false) return
|
||||
|
||||
if (process.env.io) {
|
||||
const io = JSON.parse(process.env.io)
|
||||
conf = io.conf ? io.conf : conf
|
||||
}
|
||||
pmx.init(Object.assign({
|
||||
tracing: process.env.trace === 'true' || false
|
||||
}, conf))
|
||||
}
|
||||
},
|
||||
isESModule(exec_path) {
|
||||
var fs = require('fs')
|
||||
var path = require('path')
|
||||
var semver = require('semver')
|
||||
var data
|
||||
|
||||
var findPackageJson = function(directory) {
|
||||
var file = path.join(directory, 'package.json')
|
||||
if (fs.existsSync(file) && fs.statSync(file).isFile()) {
|
||||
return file;
|
||||
}
|
||||
var parent = path.resolve(directory, '..')
|
||||
if (parent === directory) {
|
||||
return null;
|
||||
}
|
||||
return findPackageJson(parent)
|
||||
}
|
||||
|
||||
if (semver.satisfies(process.version, '< 13.3.0'))
|
||||
return false
|
||||
|
||||
if (path.extname(exec_path) === '.mjs')
|
||||
return true
|
||||
|
||||
try {
|
||||
data = JSON.parse(fs.readFileSync(findPackageJson(path.dirname(exec_path))))
|
||||
if (data.type === 'module')
|
||||
return true
|
||||
else
|
||||
return false
|
||||
} catch(e) {
|
||||
}
|
||||
}
|
||||
}
|
||||
117
api.hyungi.net/node_modules/pm2/lib/TreeKill.js
generated
vendored
Normal file
117
api.hyungi.net/node_modules/pm2/lib/TreeKill.js
generated
vendored
Normal file
@@ -0,0 +1,117 @@
|
||||
'use strict';
|
||||
|
||||
// From https://raw.githubusercontent.com/pkrumins/node-tree-kill/master/index.js
|
||||
|
||||
var childProcess = require('child_process');
|
||||
var spawn = childProcess.spawn;
|
||||
var exec = childProcess.exec;
|
||||
|
||||
module.exports = function (pid, signal, callback) {
|
||||
var tree = {};
|
||||
var pidsToProcess = {};
|
||||
tree[pid] = [];
|
||||
pidsToProcess[pid] = 1;
|
||||
|
||||
switch (process.platform) {
|
||||
case 'win32':
|
||||
exec('taskkill /pid ' + pid + ' /T /F', { windowsHide: true }, callback);
|
||||
break;
|
||||
case 'darwin':
|
||||
buildProcessTree(pid, tree, pidsToProcess, function (parentPid) {
|
||||
return spawn('pgrep', ['-P', parentPid]);
|
||||
}, function () {
|
||||
killAll(tree, signal, callback);
|
||||
});
|
||||
break;
|
||||
// case 'sunos':
|
||||
// buildProcessTreeSunOS(pid, tree, pidsToProcess, function () {
|
||||
// killAll(tree, signal, callback);
|
||||
// });
|
||||
// break;
|
||||
default: // Linux
|
||||
buildProcessTree(pid, tree, pidsToProcess, function (parentPid) {
|
||||
return spawn('ps', ['-o', 'pid', '--no-headers', '--ppid', parentPid]);
|
||||
}, function () {
|
||||
killAll(tree, signal, callback);
|
||||
});
|
||||
break;
|
||||
}
|
||||
};
|
||||
|
||||
function killAll (tree, signal, callback) {
|
||||
var killed = {};
|
||||
try {
|
||||
Object.keys(tree).forEach(function (pid) {
|
||||
tree[pid].forEach(function (pidpid) {
|
||||
if (!killed[pidpid]) {
|
||||
killPid(pidpid, signal);
|
||||
killed[pidpid] = 1;
|
||||
}
|
||||
});
|
||||
if (!killed[pid]) {
|
||||
killPid(pid, signal);
|
||||
killed[pid] = 1;
|
||||
}
|
||||
});
|
||||
} catch (err) {
|
||||
if (callback) {
|
||||
return callback(err);
|
||||
} else {
|
||||
console.error(err);
|
||||
}
|
||||
}
|
||||
if (callback) {
|
||||
return callback();
|
||||
}
|
||||
}
|
||||
|
||||
function killPid(pid, signal) {
|
||||
try {
|
||||
process.kill(parseInt(pid, 10), signal);
|
||||
}
|
||||
catch (err) {
|
||||
if (err.code !== 'ESRCH')
|
||||
console.error(err);
|
||||
}
|
||||
}
|
||||
|
||||
function buildProcessTree (parentPid, tree, pidsToProcess, spawnChildProcessesList, cb) {
|
||||
var ps = spawnChildProcessesList(parentPid);
|
||||
var allData = '';
|
||||
|
||||
ps.on('error', function(err) {
|
||||
console.error(err);
|
||||
});
|
||||
|
||||
if (ps.stdout) {
|
||||
ps.stdout.on('data', function (data) {
|
||||
data = data.toString('ascii');
|
||||
allData += data;
|
||||
});
|
||||
}
|
||||
|
||||
var onClose = function (code) {
|
||||
delete pidsToProcess[parentPid];
|
||||
|
||||
if (code !== 0) {
|
||||
// no more parent processes
|
||||
if (Object.keys(pidsToProcess).length == 0) {
|
||||
cb();
|
||||
}
|
||||
return;
|
||||
}
|
||||
var pids = allData.match(/\d+/g) || [];
|
||||
if (pids.length === 0)
|
||||
return cb();
|
||||
|
||||
pids.forEach(function (pid) {
|
||||
pid = parseInt(pid, 10);
|
||||
tree[parentPid].push(pid);
|
||||
tree[pid] = [];
|
||||
pidsToProcess[pid] = 1;
|
||||
buildProcessTree(pid, tree, pidsToProcess, spawnChildProcessesList, cb);
|
||||
});
|
||||
};
|
||||
|
||||
ps.on('close', onClose);
|
||||
}
|
||||
278
api.hyungi.net/node_modules/pm2/lib/Utility.js
generated
vendored
Normal file
278
api.hyungi.net/node_modules/pm2/lib/Utility.js
generated
vendored
Normal file
@@ -0,0 +1,278 @@
|
||||
/**
|
||||
* Copyright 2013-2022 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Common Utilities ONLY USED IN ->DAEMON<-
|
||||
*/
|
||||
|
||||
var fclone = require('fclone');
|
||||
var fs = require('fs');
|
||||
var cst = require('../constants.js');
|
||||
var waterfall = require('async/waterfall');
|
||||
var util = require('util');
|
||||
var url = require('url');
|
||||
var dayjs = require('dayjs');
|
||||
var findPackageJson = require('./tools/find-package-json')
|
||||
|
||||
var Utility = module.exports = {
|
||||
findPackageVersion : function(fullpath) {
|
||||
var version
|
||||
|
||||
try {
|
||||
version = findPackageJson(fullpath).next().value.version
|
||||
} catch(e) {
|
||||
version = 'N/A'
|
||||
}
|
||||
return version
|
||||
},
|
||||
getDate : function() {
|
||||
return Date.now();
|
||||
},
|
||||
extendExtraConfig : function(proc, opts) {
|
||||
if (opts.env && opts.env.current_conf) {
|
||||
if (opts.env.current_conf.env &&
|
||||
typeof(opts.env.current_conf.env) === 'object' &&
|
||||
Object.keys(opts.env.current_conf.env).length === 0)
|
||||
delete opts.env.current_conf.env
|
||||
|
||||
Utility.extendMix(proc.pm2_env, opts.env.current_conf);
|
||||
delete opts.env.current_conf;
|
||||
}
|
||||
},
|
||||
formatCLU : function(process) {
|
||||
if (!process.pm2_env) {
|
||||
return process;
|
||||
}
|
||||
|
||||
var obj = Utility.clone(process.pm2_env);
|
||||
delete obj.env;
|
||||
|
||||
return obj;
|
||||
},
|
||||
extend : function(destination, source){
|
||||
if (!source || typeof source != 'object') return destination;
|
||||
|
||||
Object.keys(source).forEach(function(new_key) {
|
||||
if (source[new_key] != '[object Object]')
|
||||
destination[new_key] = source[new_key];
|
||||
});
|
||||
|
||||
return destination;
|
||||
},
|
||||
// Same as extend but drop value with 'null'
|
||||
extendMix : function(destination, source){
|
||||
if (!source || typeof source != 'object') return destination;
|
||||
|
||||
Object.keys(source).forEach(function(new_key) {
|
||||
if (source[new_key] == 'null')
|
||||
delete destination[new_key];
|
||||
else
|
||||
destination[new_key] = source[new_key]
|
||||
});
|
||||
|
||||
return destination;
|
||||
},
|
||||
|
||||
whichFileExists : function(file_arr) {
|
||||
var f = null;
|
||||
|
||||
file_arr.some(function(file) {
|
||||
try {
|
||||
fs.statSync(file);
|
||||
} catch(e) {
|
||||
return false;
|
||||
}
|
||||
f = file;
|
||||
return true;
|
||||
});
|
||||
return f;
|
||||
},
|
||||
clone : function(obj) {
|
||||
if (obj === null || obj === undefined) return {};
|
||||
return fclone(obj);
|
||||
},
|
||||
overrideConsole : function(bus) {
|
||||
if (cst.PM2_LOG_DATE_FORMAT && typeof cst.PM2_LOG_DATE_FORMAT == 'string') {
|
||||
// Generate timestamp prefix
|
||||
function timestamp(){
|
||||
return `${dayjs(Date.now()).format(cst.PM2_LOG_DATE_FORMAT)}:`;
|
||||
}
|
||||
|
||||
var hacks = ['info', 'log', 'error', 'warn'], consoled = {};
|
||||
|
||||
// store console functions.
|
||||
hacks.forEach(function(method){
|
||||
consoled[method] = console[method];
|
||||
});
|
||||
|
||||
hacks.forEach(function(k){
|
||||
console[k] = function(){
|
||||
if (bus) {
|
||||
bus.emit('log:PM2', {
|
||||
process : {
|
||||
pm_id : 'PM2',
|
||||
name : 'PM2',
|
||||
rev : null
|
||||
},
|
||||
at : Utility.getDate(),
|
||||
data : util.format.apply(this, arguments) + '\n'
|
||||
});
|
||||
}
|
||||
// do not destroy variable insertion
|
||||
arguments[0] && (arguments[0] = timestamp() + ' PM2 ' + k + ': ' + arguments[0]);
|
||||
consoled[k].apply(console, arguments);
|
||||
};
|
||||
});
|
||||
}
|
||||
},
|
||||
startLogging : function(stds, callback) {
|
||||
/**
|
||||
* Start log outgoing messages
|
||||
* @method startLogging
|
||||
* @param {} callback
|
||||
* @return
|
||||
*/
|
||||
// Make sure directories of `logs` and `pids` exist.
|
||||
// try {
|
||||
// ['logs', 'pids'].forEach(function(n){
|
||||
// console.log(n);
|
||||
// (function(_path){
|
||||
// !fs.existsSync(_path) && fs.mkdirSync(_path, '0755');
|
||||
// })(path.resolve(cst.PM2_ROOT_PATH, n));
|
||||
// });
|
||||
// } catch(err) {
|
||||
// return callback(new Error('can not create directories (logs/pids):' + err.message));
|
||||
// }
|
||||
|
||||
// waterfall.
|
||||
var flows = [];
|
||||
// types of stdio, should be sorted as `std(entire log)`, `out`, `err`.
|
||||
var types = Object.keys(stds).sort(function(x, y){
|
||||
return -x.charCodeAt(0) + y.charCodeAt(0);
|
||||
});
|
||||
|
||||
// Create write streams.
|
||||
(function createWS(io){
|
||||
if(io.length != 1){
|
||||
return false;
|
||||
}
|
||||
io = io[0];
|
||||
|
||||
// If `std` is a Stream type, try next `std`.
|
||||
// compatible with `pm2 reloadLogs`
|
||||
if(typeof stds[io] == 'object' && !isNaN(stds[io].fd)){
|
||||
return createWS(types.splice(0, 1));
|
||||
}
|
||||
|
||||
flows.push(function(next){
|
||||
var file = stds[io];
|
||||
|
||||
// if file contains ERR or /dev/null, dont try to create stream since he dont want logs
|
||||
if (!file || file.indexOf('NULL') > -1 || file.indexOf('/dev/null') > -1)
|
||||
return next();
|
||||
|
||||
stds[io] = fs.createWriteStream(file, {flags: 'a'})
|
||||
.once('error', next)
|
||||
.on('open', function(){
|
||||
stds[io].removeListener('error', next);
|
||||
|
||||
stds[io].on('error', function(err) {
|
||||
console.error(err);
|
||||
});
|
||||
|
||||
next();
|
||||
});
|
||||
stds[io]._file = file;
|
||||
});
|
||||
return createWS(types.splice(0, 1));
|
||||
})(types.splice(0, 1));
|
||||
|
||||
waterfall(flows, callback);
|
||||
},
|
||||
|
||||
/**
|
||||
* Function parse the module name and returns it as canonic:
|
||||
* - Makes the name based on installation filename.
|
||||
* - Removes the Github author, module version and git branch from original name.
|
||||
*
|
||||
* @param {string} module_name
|
||||
* @returns {string} Canonic module name (without trimed parts).
|
||||
* @example Always returns 'pm2-slack' for inputs 'ma-zal/pm2-slack', 'ma-zal/pm2-slack#own-branch',
|
||||
* 'pm2-slack-1.0.0.tgz' or 'pm2-slack@1.0.0'.
|
||||
*/
|
||||
getCanonicModuleName: function(module_name) {
|
||||
if (typeof module_name !== 'string') return null;
|
||||
var canonic_module_name = module_name;
|
||||
|
||||
// Returns the module name from a .tgz package name (or the original name if it is not a valid pkg).
|
||||
// Input: The package name (e.g. "foo.tgz", "foo-1.0.0.tgz", "folder/foo.tgz")
|
||||
// Output: The module name
|
||||
if (canonic_module_name.match(/\.tgz($|\?)/)) {
|
||||
if (canonic_module_name.match(/^(.+\/)?([^\/]+)\.tgz($|\?)/)) {
|
||||
canonic_module_name = canonic_module_name.match(/^(.+\/)?([^\/]+)\.tgz($|\?)/)[2];
|
||||
if (canonic_module_name.match(/^(.+)-[0-9]+\.[0-9]+\.[0-9]+(-[a-zA-Z0-9_]+\.[0-9]+)?$/)) {
|
||||
canonic_module_name = canonic_module_name.match(/^(.+)-[0-9]+\.[0-9]+\.[0-9]+(-[a-zA-Z0-9_]+\.[0-9]+)?$/)[1];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//pm2 install git+https://github.com/user/module
|
||||
if(canonic_module_name.indexOf('git+') !== -1) {
|
||||
canonic_module_name = canonic_module_name.split('/').pop();
|
||||
}
|
||||
|
||||
//pm2 install https://github.com/user/module
|
||||
if(canonic_module_name.indexOf('http') !== -1) {
|
||||
var uri = url.parse(canonic_module_name);
|
||||
canonic_module_name = uri.pathname.split('/').pop();
|
||||
}
|
||||
|
||||
//pm2 install file:///home/user/module
|
||||
else if(canonic_module_name.indexOf('file://') === 0) {
|
||||
canonic_module_name = canonic_module_name.replace(/\/$/, '').split('/').pop();
|
||||
}
|
||||
|
||||
//pm2 install username/module
|
||||
else if(canonic_module_name.indexOf('/') !== -1) {
|
||||
if (canonic_module_name.charAt(0) !== "@"){
|
||||
canonic_module_name = canonic_module_name.split('/')[1];
|
||||
}
|
||||
}
|
||||
|
||||
//pm2 install @somescope/module@2.1.0-beta
|
||||
if(canonic_module_name.lastIndexOf('@') > 0) {
|
||||
canonic_module_name = canonic_module_name.substr(0,canonic_module_name.lastIndexOf("@"));
|
||||
}
|
||||
|
||||
//pm2 install module#some-branch
|
||||
if(canonic_module_name.indexOf('#') !== -1) {
|
||||
canonic_module_name = canonic_module_name.split('#')[0];
|
||||
}
|
||||
|
||||
if (canonic_module_name.indexOf('.git') !== -1) {
|
||||
canonic_module_name = canonic_module_name.replace('.git', '');
|
||||
}
|
||||
|
||||
return canonic_module_name;
|
||||
},
|
||||
|
||||
checkPathIsNull: function(path) {
|
||||
return path === 'NULL' || path === '/dev/null' || path === '\\\\.\\NUL';
|
||||
},
|
||||
|
||||
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("");
|
||||
}
|
||||
|
||||
};
|
||||
46
api.hyungi.net/node_modules/pm2/lib/VersionCheck.js
generated
vendored
Normal file
46
api.hyungi.net/node_modules/pm2/lib/VersionCheck.js
generated
vendored
Normal file
@@ -0,0 +1,46 @@
|
||||
|
||||
var vCheck = require('@pm2/pm2-version-check')
|
||||
var semver = require('semver')
|
||||
var fs = require('fs')
|
||||
var os = require('os')
|
||||
|
||||
function hasDockerEnv() {
|
||||
try {
|
||||
fs.statSync('/.dockerenv');
|
||||
return true;
|
||||
} catch (_) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
function hasDockerCGroup() {
|
||||
try {
|
||||
return fs.readFileSync('/proc/self/cgroup', 'utf8').includes('docker');
|
||||
} catch (_) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = function (opts) {
|
||||
var params = {
|
||||
state: opts.state,
|
||||
version: opts.version
|
||||
}
|
||||
|
||||
try {
|
||||
params.os = os.type()
|
||||
params.uptime = Math.floor(process.uptime())
|
||||
params.nodev = process.versions.node
|
||||
params.docker = hasDockerEnv() || hasDockerCGroup()
|
||||
} catch(e) {
|
||||
}
|
||||
|
||||
vCheck.runCheck(params, (err, pkg) => {
|
||||
if (err) return false
|
||||
if (!pkg.current_version) return false
|
||||
if (opts.version && semver.lt(opts.version, pkg.current_version)) {
|
||||
console.log('[PM2] This PM2 is not UP TO DATE')
|
||||
console.log('[PM2] Upgrade to version %s', pkg.current_version)
|
||||
}
|
||||
})
|
||||
}
|
||||
117
api.hyungi.net/node_modules/pm2/lib/Watcher.js
generated
vendored
Normal file
117
api.hyungi.net/node_modules/pm2/lib/Watcher.js
generated
vendored
Normal file
@@ -0,0 +1,117 @@
|
||||
/**
|
||||
* Copyright 2013-2022 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 chokidar = require('chokidar');
|
||||
var util = require('util');
|
||||
var log = require('debug')('pm2:watch');
|
||||
|
||||
module.exports = function ClusterMode(God) {
|
||||
/**
|
||||
* Watch folder for changes and restart
|
||||
* @method watch
|
||||
* @param {Object} pm2_env pm2 app environnement
|
||||
* @return MemberExpression
|
||||
*/
|
||||
God.watch = {};
|
||||
|
||||
God.watch._watchers = {};
|
||||
|
||||
God.watch.enable = function(pm2_env) {
|
||||
if (God.watch._watchers[pm2_env.pm_id]) {
|
||||
God.watch._watchers[pm2_env.pm_id].close();
|
||||
God.watch._watchers[pm2_env.pm_id] = null;
|
||||
delete God.watch._watchers[pm2_env.pm_id];
|
||||
}
|
||||
|
||||
log('Initial watch ', pm2_env.watch)
|
||||
|
||||
var watch = pm2_env.watch
|
||||
|
||||
if(typeof watch == 'boolean' || Array.isArray(watch) && watch.length === 0)
|
||||
watch = pm2_env.pm_cwd;
|
||||
|
||||
log('Watching %s', watch);
|
||||
|
||||
var watch_options = {
|
||||
ignored : pm2_env.ignore_watch || /[\/\\]\.|node_modules/,
|
||||
persistent : true,
|
||||
ignoreInitial : true,
|
||||
cwd: pm2_env.pm_cwd
|
||||
};
|
||||
|
||||
if (pm2_env.watch_options) {
|
||||
watch_options = Object.assign(watch_options, pm2_env.watch_options);
|
||||
}
|
||||
|
||||
log('Watch opts', watch_options);
|
||||
|
||||
var watcher = chokidar.watch(watch, watch_options);
|
||||
|
||||
console.log('[Watch] Start watching', pm2_env.name);
|
||||
|
||||
watcher.on('all', function(event, path) {
|
||||
var self = this;
|
||||
|
||||
if (self.restarting === true) {
|
||||
log('Already restarting, skipping');
|
||||
return false;
|
||||
}
|
||||
|
||||
self.restarting = true;
|
||||
|
||||
console.log('Change detected on path %s for app %s - restarting', path, pm2_env.name);
|
||||
|
||||
setTimeout(function() {
|
||||
God.restartProcessName(pm2_env.name, function(err, list) {
|
||||
self.restarting = false;
|
||||
|
||||
if (err) {
|
||||
log('Error while restarting', err);
|
||||
return false;
|
||||
}
|
||||
|
||||
return log('Process restarted');
|
||||
});
|
||||
}, (pm2_env.watch_delay || 0));
|
||||
|
||||
return false;
|
||||
});
|
||||
|
||||
watcher.on('error', function(e) {
|
||||
console.error(e.stack || e);
|
||||
});
|
||||
|
||||
God.watch._watchers[pm2_env.pm_id] = watcher;
|
||||
|
||||
//return God.watch._watchers[pm2_env.name];
|
||||
},
|
||||
/**
|
||||
* Description
|
||||
* @method close
|
||||
* @param {} id
|
||||
* @return
|
||||
*/
|
||||
God.watch.disableAll = function() {
|
||||
var watchers = God.watch._watchers;
|
||||
|
||||
console.log('[Watch] PM2 is being killed. Watch is disabled to avoid conflicts');
|
||||
for (var i in watchers) {
|
||||
watchers[i].close && watchers[i].close();
|
||||
watchers.splice(i, 1);
|
||||
}
|
||||
},
|
||||
|
||||
God.watch.disable = function(pm2_env) {
|
||||
var watcher = God.watch._watchers[pm2_env.pm_id]
|
||||
if (watcher) {
|
||||
console.log('[Watch] Stop watching', pm2_env.name);
|
||||
watcher.close();
|
||||
delete God.watch._watchers[pm2_env.pm_id];
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
};
|
||||
213
api.hyungi.net/node_modules/pm2/lib/Worker.js
generated
vendored
Normal file
213
api.hyungi.net/node_modules/pm2/lib/Worker.js
generated
vendored
Normal file
@@ -0,0 +1,213 @@
|
||||
/**
|
||||
* Copyright 2013-2022 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.
|
||||
*/
|
||||
const vizion = require('vizion');
|
||||
const eachLimit = require('async/eachLimit');
|
||||
const debug = require('debug')('pm2:worker');
|
||||
const domain = require('domain');
|
||||
const Cron = require('croner');
|
||||
const pkg = require('../package.json');
|
||||
|
||||
var cst = require('../constants.js');
|
||||
var vCheck = require('./VersionCheck.js')
|
||||
|
||||
module.exports = function(God) {
|
||||
var timer = null;
|
||||
|
||||
God.CronJobs = new Map();
|
||||
God.Worker = {};
|
||||
God.Worker.is_running = false;
|
||||
|
||||
God.getCronID = function(pm_id) {
|
||||
return `cron-${pm_id}`
|
||||
}
|
||||
|
||||
God.registerCron = function(pm2_env) {
|
||||
if (!pm2_env ||
|
||||
pm2_env.pm_id === undefined ||
|
||||
!pm2_env.cron_restart ||
|
||||
pm2_env.cron_restart == '0' ||
|
||||
God.CronJobs.has(God.getCronID(pm2_env.pm_id)))
|
||||
return;
|
||||
|
||||
var pm_id = pm2_env.pm_id
|
||||
console.log('[PM2][WORKER] Registering a cron job on:', pm_id);
|
||||
|
||||
var job = Cron(pm2_env.cron_restart, function() {
|
||||
God.restartProcessId({id: pm_id}, function(err, data) {
|
||||
if (err)
|
||||
console.error(err.stack || err);
|
||||
return;
|
||||
});
|
||||
});
|
||||
|
||||
God.CronJobs.set(God.getCronID(pm_id), job);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Deletes the cron job on deletion of process
|
||||
*/
|
||||
God.deleteCron = function(id) {
|
||||
if (typeof(id) !== 'undefined' && God.CronJobs.has(God.getCronID(id)) === false)
|
||||
return;
|
||||
console.log('[PM2] Deregistering a cron job on:', id);
|
||||
var job = God.CronJobs.get(God.getCronID(id));
|
||||
|
||||
if (job)
|
||||
job.stop();
|
||||
|
||||
God.CronJobs.delete(God.getCronID(id));
|
||||
};
|
||||
|
||||
var _getProcessById = function(pm_id) {
|
||||
var proc = God.clusters_db[pm_id];
|
||||
return proc ? proc : null;
|
||||
};
|
||||
|
||||
|
||||
var maxMemoryRestart = function(proc_key, cb) {
|
||||
var proc = _getProcessById(proc_key.pm2_env.pm_id);
|
||||
|
||||
if (!(proc &&
|
||||
proc.pm2_env &&
|
||||
proc_key.monit))
|
||||
return cb();
|
||||
|
||||
if (proc_key.monit.memory !== undefined &&
|
||||
proc.pm2_env.max_memory_restart !== undefined &&
|
||||
proc.pm2_env.max_memory_restart < proc_key.monit.memory &&
|
||||
proc.pm2_env.axm_options &&
|
||||
proc.pm2_env.axm_options.pid === undefined) {
|
||||
console.log('[PM2][WORKER] Process %s restarted because it exceeds --max-memory-restart value (current_memory=%s max_memory_limit=%s [octets])', proc.pm2_env.pm_id, proc_key.monit.memory, proc.pm2_env.max_memory_restart);
|
||||
God.reloadProcessId({
|
||||
id : proc.pm2_env.pm_id
|
||||
}, function(err, data) {
|
||||
if (err)
|
||||
console.error(err.stack || err);
|
||||
return cb();
|
||||
});
|
||||
}
|
||||
else {
|
||||
return cb();
|
||||
}
|
||||
};
|
||||
|
||||
// Deprecated
|
||||
var versioningRefresh = function(proc_key, cb) {
|
||||
var proc = _getProcessById(proc_key.pm2_env.pm_id);
|
||||
if (!(proc &&
|
||||
proc.pm2_env &&
|
||||
(proc.pm2_env.vizion !== false && proc.pm2_env.vizion != "false") &&
|
||||
proc.pm2_env.versioning &&
|
||||
proc.pm2_env.versioning.repo_path)) {
|
||||
return cb();
|
||||
}
|
||||
|
||||
if (proc.pm2_env.vizion_running === true)
|
||||
{
|
||||
debug('Vizion is already running for proc id: %d, skipping this round', proc.pm2_env.pm_id);
|
||||
return cb();
|
||||
}
|
||||
|
||||
proc.pm2_env.vizion_running = true;
|
||||
var repo_path = proc.pm2_env.versioning.repo_path;
|
||||
|
||||
vizion.analyze({
|
||||
folder: proc.pm2_env.versioning.repo_path
|
||||
},
|
||||
function(err, meta) {
|
||||
if (err != null)
|
||||
return cb();
|
||||
|
||||
proc = _getProcessById(proc_key.pm2_env.pm_id);
|
||||
|
||||
if (!(proc &&
|
||||
proc.pm2_env &&
|
||||
proc.pm2_env.versioning &&
|
||||
proc.pm2_env.versioning.repo_path)) {
|
||||
console.error('Proc not defined anymore or versioning unknown');
|
||||
return cb();
|
||||
}
|
||||
|
||||
proc.pm2_env.vizion_running = false;
|
||||
meta.repo_path = repo_path;
|
||||
proc.pm2_env.versioning = meta;
|
||||
debug('[PM2][WORKER] %s parsed for versioning', proc.pm2_env.name);
|
||||
return cb();
|
||||
});
|
||||
};
|
||||
|
||||
var tasks = function() {
|
||||
if (God.Worker.is_running === true) {
|
||||
debug('[PM2][WORKER] Worker is already running, skipping this round');
|
||||
return false;
|
||||
}
|
||||
God.Worker.is_running = true;
|
||||
|
||||
God.getMonitorData(null, function(err, data) {
|
||||
if (err || !data || typeof(data) !== 'object') {
|
||||
God.Worker.is_running = false;
|
||||
return console.error(err);
|
||||
}
|
||||
|
||||
eachLimit(data, 1, function(proc, next) {
|
||||
if (!proc || !proc.pm2_env || proc.pm2_env.pm_id === undefined)
|
||||
return next();
|
||||
|
||||
debug('[PM2][WORKER] Processing proc id:', proc.pm2_env.pm_id);
|
||||
|
||||
// Reset restart delay if application has an uptime of more > 30secs
|
||||
if (proc.pm2_env.exp_backoff_restart_delay !== undefined &&
|
||||
proc.pm2_env.prev_restart_delay && proc.pm2_env.prev_restart_delay > 0) {
|
||||
var app_uptime = Date.now() - proc.pm2_env.pm_uptime
|
||||
if (app_uptime > cst.EXP_BACKOFF_RESET_TIMER) {
|
||||
var ref_proc = _getProcessById(proc.pm2_env.pm_id);
|
||||
ref_proc.pm2_env.prev_restart_delay = 0
|
||||
console.log(`[PM2][WORKER] Reset the restart delay, as app ${proc.name} has been up for more than ${cst.EXP_BACKOFF_RESET_TIMER}ms`)
|
||||
}
|
||||
}
|
||||
|
||||
// Check if application has reached memory threshold
|
||||
maxMemoryRestart(proc, function() {
|
||||
return next();
|
||||
});
|
||||
}, function(err) {
|
||||
God.Worker.is_running = false;
|
||||
debug('[PM2][WORKER] My job here is done, next job in %d seconds', parseInt(cst.WORKER_INTERVAL / 1000));
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
var wrappedTasks = function() {
|
||||
var d = domain.create();
|
||||
|
||||
d.once('error', function(err) {
|
||||
console.error('[PM2][WORKER] Error caught by domain:\n' + (err.stack || err));
|
||||
God.Worker.is_running = false;
|
||||
});
|
||||
|
||||
d.run(function() {
|
||||
tasks();
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
God.Worker.start = function() {
|
||||
timer = setInterval(wrappedTasks, cst.WORKER_INTERVAL);
|
||||
|
||||
setInterval(() => {
|
||||
vCheck({
|
||||
state: 'check',
|
||||
version: pkg.version
|
||||
})
|
||||
}, 1000 * 60 * 60 * 24)
|
||||
};
|
||||
|
||||
God.Worker.stop = function() {
|
||||
if (timer !== null)
|
||||
clearInterval(timer);
|
||||
};
|
||||
};
|
||||
1033
api.hyungi.net/node_modules/pm2/lib/binaries/CLI.js
generated
vendored
Normal file
1033
api.hyungi.net/node_modules/pm2/lib/binaries/CLI.js
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
183
api.hyungi.net/node_modules/pm2/lib/binaries/DevCLI.js
generated
vendored
Normal file
183
api.hyungi.net/node_modules/pm2/lib/binaries/DevCLI.js
generated
vendored
Normal file
@@ -0,0 +1,183 @@
|
||||
|
||||
'use strict';
|
||||
|
||||
process.env.PM2_NO_INTERACTION = 'true';
|
||||
// Do not print banner
|
||||
process.env.PM2_DISCRETE_MODE = true;
|
||||
|
||||
var commander = require('commander');
|
||||
|
||||
var PM2 = require('../..');
|
||||
var Log = require('../API/Log');
|
||||
var cst = require('../../constants.js');
|
||||
var pkg = require('../../package.json');
|
||||
var chalk = require('chalk');
|
||||
var path = require('path');
|
||||
var fmt = require('../tools/fmt.js');
|
||||
var exec = require('child_process').exec;
|
||||
var os = require('os');
|
||||
|
||||
commander.version(pkg.version)
|
||||
.description('pm2-dev monitor for any file changes and automatically restart it')
|
||||
.option('--raw', 'raw log output')
|
||||
.option('--timestamp', 'print timestamp')
|
||||
.option('--node-args <node_args>', 'space delimited arguments to pass to node in cluster mode - e.g. --node-args="--debug=7001 --trace-deprecation"')
|
||||
.option('--ignore [files]', 'files to ignore while watching')
|
||||
.option('--post-exec [cmd]', 'execute extra command after change detected')
|
||||
.option('--silent-exec', 'do not output result of post command', false)
|
||||
.option('--test-mode', 'debug mode for test suit')
|
||||
.option('--interpreter <interpreter>', 'the interpreter pm2 should use for executing app (bash, python...)')
|
||||
.option('--env [name]', 'select env_[name] env variables in process config file')
|
||||
.option('--auto-exit', 'exit if all processes are errored/stopped or 0 apps launched')
|
||||
.usage('pm2-dev app.js');
|
||||
|
||||
var pm2 = new PM2.custom({
|
||||
pm2_home : path.join(os.homedir ? os.homedir() : (process.env.HOME || process.env.HOMEPATH || process.env.USERPROFILE), '.pm2-dev')
|
||||
});
|
||||
|
||||
pm2.connect(function() {
|
||||
commander.parse(process.argv);
|
||||
});
|
||||
|
||||
function postExecCmd(command, cb) {
|
||||
var exec_cmd = exec(command);
|
||||
|
||||
if (commander.silentExec !== true) {
|
||||
exec_cmd.stdout.on('data', function(data) {
|
||||
process.stdout.write(data);
|
||||
});
|
||||
|
||||
exec_cmd.stderr.on('data', function(data) {
|
||||
process.stderr.write(data);
|
||||
});
|
||||
}
|
||||
|
||||
exec_cmd.on('close', function done() {
|
||||
if (cb) cb(null);
|
||||
});
|
||||
|
||||
exec_cmd.on('error', function (err) {
|
||||
console.error(err.stack || err);
|
||||
});
|
||||
};
|
||||
|
||||
function run(cmd, opts) {
|
||||
var timestamp = opts.timestamp;
|
||||
|
||||
opts.watch = true;
|
||||
opts.autostart = true;
|
||||
opts.autorestart = true;
|
||||
opts.restart_delay = 1000
|
||||
if (opts.autoExit)
|
||||
autoExit();
|
||||
|
||||
if (opts.ignore) {
|
||||
opts.ignore_watch = opts.ignore.split(',')
|
||||
opts.ignore_watch.push('node_modules');
|
||||
}
|
||||
|
||||
if (timestamp === true)
|
||||
timestamp = 'YYYY-MM-DD-HH:mm:ss';
|
||||
|
||||
pm2.start(cmd, opts, function(err, procs) {
|
||||
|
||||
if (err) {
|
||||
console.error(err);
|
||||
pm2.destroy(function() {
|
||||
process.exit(0);
|
||||
});
|
||||
return false;
|
||||
}
|
||||
|
||||
if (opts.testMode) {
|
||||
return pm2.disconnect(function() {
|
||||
});
|
||||
}
|
||||
|
||||
fmt.sep();
|
||||
fmt.title('PM2 development mode');
|
||||
fmt.field('Apps started', procs.map(function(p) { return p.pm2_env.name } ));
|
||||
fmt.field('Processes started', chalk.bold(procs.length));
|
||||
fmt.field('Watch and Restart', chalk.green('Enabled'));
|
||||
fmt.field('Ignored folder', opts.ignore_watch || 'node_modules');
|
||||
if (opts.postExec)
|
||||
fmt.field('Post restart cmd', opts.postExec);
|
||||
fmt.sep();
|
||||
|
||||
setTimeout(function() {
|
||||
pm2.Client.launchBus(function(err, bus) {
|
||||
bus.on('process:event', function(packet) {
|
||||
if (packet.event == 'online') {
|
||||
if (opts.postExec)
|
||||
postExecCmd(opts.postExec);
|
||||
}
|
||||
});
|
||||
});
|
||||
}, 1000);
|
||||
|
||||
Log.devStream(pm2.Client, 'all', opts.raw, timestamp, false);
|
||||
|
||||
process.on('SIGINT', function() {
|
||||
console.log('>>>>> [PM2 DEV] Stopping current development session');
|
||||
pm2.delete('all', function() {
|
||||
pm2.destroy(function() {
|
||||
process.exit(0);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
commander.command('*')
|
||||
.action(function(cmd, opts){
|
||||
run(cmd, commander);
|
||||
});
|
||||
|
||||
commander.command('start <file|json_file>')
|
||||
.description('start target config file/script in development mode')
|
||||
.action(function(cmd, opts) {
|
||||
run(cmd, commander);
|
||||
});
|
||||
|
||||
function exitPM2() {
|
||||
if (pm2 && pm2.connected == true) {
|
||||
console.log(chalk.green.bold('>>> Exiting PM2'));
|
||||
pm2.kill(function() {
|
||||
process.exit(0);
|
||||
});
|
||||
}
|
||||
else
|
||||
process.exit(0);
|
||||
}
|
||||
|
||||
function autoExit(final) {
|
||||
setTimeout(function() {
|
||||
pm2.list(function(err, apps) {
|
||||
if (err) console.error(err.stack || err);
|
||||
|
||||
var online_count = 0;
|
||||
|
||||
apps.forEach(function(app) {
|
||||
if (app.pm2_env.status == cst.ONLINE_STATUS ||
|
||||
app.pm2_env.status == cst.LAUNCHING_STATUS)
|
||||
online_count++;
|
||||
});
|
||||
|
||||
if (online_count == 0) {
|
||||
console.log('0 application online, exiting');
|
||||
if (final == true)
|
||||
process.exit(1);
|
||||
else
|
||||
autoExit(true);
|
||||
return false;
|
||||
}
|
||||
autoExit(false);
|
||||
});
|
||||
}, 3000);
|
||||
}
|
||||
|
||||
if (process.argv.length == 2) {
|
||||
commander.outputHelp();
|
||||
exitPM2();
|
||||
}
|
||||
101
api.hyungi.net/node_modules/pm2/lib/binaries/Runtime.js
generated
vendored
Normal file
101
api.hyungi.net/node_modules/pm2/lib/binaries/Runtime.js
generated
vendored
Normal file
@@ -0,0 +1,101 @@
|
||||
|
||||
'use strict';
|
||||
|
||||
var commander = require('commander');
|
||||
|
||||
var PM2 = require('../..');
|
||||
var Log = require('../../lib/API/Log');
|
||||
var cst = require('../../constants.js');
|
||||
var pkg = require('../../package.json');
|
||||
var path = require('path');
|
||||
|
||||
var pm2;
|
||||
|
||||
// Do not print banner
|
||||
process.env.PM2_DISCRETE_MODE = true;
|
||||
|
||||
commander.version(pkg.version)
|
||||
.description('pm2-runtime is an automatic pmx injection that runs in simulated no-daemon environment')
|
||||
.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]', '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 <number>', 'launch [number] instances with load-balancer')
|
||||
.usage('pm2-runtime app.js');
|
||||
|
||||
commander.command('*')
|
||||
.action(function(cmd){
|
||||
pm2 = new PM2.custom({
|
||||
pm2_home : path.join(process.env.HOME, '.pm3'),
|
||||
secret_key : cst.SECRET_KEY || commander.secret,
|
||||
public_key : cst.PUBLIC_KEY || commander.public,
|
||||
machine_name : cst.MACHINE_NAME || commander.machineName
|
||||
});
|
||||
|
||||
pm2.connect(function() {
|
||||
if (commander.web) {
|
||||
var port = commander.web === true ? cst.WEB_PORT : commander.web;
|
||||
pm2.web(port);
|
||||
}
|
||||
|
||||
pm2.start(cmd, commander, function(err, obj) {
|
||||
if (process.env.PM2_RUNTIME_DEBUG) {
|
||||
return pm2.disconnect(function() {});
|
||||
}
|
||||
|
||||
if (err) {
|
||||
console.error(err);
|
||||
return process.exit(1);
|
||||
}
|
||||
|
||||
var pm_id = obj[0].pm2_env.pm_id;
|
||||
|
||||
if (commander.instances == undefined) {
|
||||
return pm2.attach(pm_id, function() {
|
||||
exitPM2();
|
||||
});
|
||||
}
|
||||
|
||||
if (commander.json === true)
|
||||
Log.jsonStream(pm2.Client, pm_id);
|
||||
else if (commander.format === true)
|
||||
Log.formatStream(pm2.Client, pm_id, false, 'YYYY-MM-DD-HH:mm:ssZZ');
|
||||
else
|
||||
Log.stream(pm2.Client, 'all', true);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
if (process.argv.length == 2) {
|
||||
commander.outputHelp();
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
process.on('SIGINT', function() {
|
||||
exitPM2();
|
||||
});
|
||||
|
||||
process.on('SIGTERM', function() {
|
||||
exitPM2();
|
||||
});
|
||||
|
||||
commander.parse(process.argv);
|
||||
|
||||
function exitPM2() {
|
||||
console.log('Exited at %s', new Date());
|
||||
if (commander.autoManage)
|
||||
return process.exit(0);
|
||||
|
||||
if (commander.fastBoot) {
|
||||
return pm2.delete('all', function() {
|
||||
process.exit(0);
|
||||
});
|
||||
}
|
||||
pm2.kill(function() {
|
||||
process.exit(0);
|
||||
});
|
||||
}
|
||||
192
api.hyungi.net/node_modules/pm2/lib/binaries/Runtime4Docker.js
generated
vendored
Normal file
192
api.hyungi.net/node_modules/pm2/lib/binaries/Runtime4Docker.js
generated
vendored
Normal file
@@ -0,0 +1,192 @@
|
||||
'use strict';
|
||||
|
||||
/**
|
||||
* Specialized PM2 CLI for Containers
|
||||
*/
|
||||
var commander = require('commander');
|
||||
var PM2 = require('../..');
|
||||
var Log = require('../../lib/API/Log');
|
||||
var cst = require('../../constants.js');
|
||||
var pkg = require('../../package.json');
|
||||
var path = require('path');
|
||||
var DEFAULT_FAIL_COUNT = 3;
|
||||
|
||||
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 <number>', 'launch [number] of processes automatically load-balanced. Increase overall performances and performance stability.')
|
||||
.option('--secret [key]', '[MONITORING] PM2 plus secret key')
|
||||
.option('--no-autostart', 'add an app without automatic start')
|
||||
.option('--no-autorestart', 'start an app without automatic restart')
|
||||
.option('--stop-exit-codes <exit_codes...>', 'specify a list of exit codes that should skip automatic restart')
|
||||
.option('--node-args <node_args>', 'space delimited arguments to pass to node in cluster mode - e.g. --node-args="--debug=7001 --trace-deprecation"')
|
||||
.option('-n --name <name>', 'set a <name> for script')
|
||||
.option('--max-memory-restart <memory>', 'specify max memory amount used to autorestart (in octet or use syntax like 100M)')
|
||||
.option('-c --cron <cron_pattern>', 'restart a running process based on a cron pattern')
|
||||
.option('--interpreter <interpreter>', 'the interpreter pm2 should use for executing app (bash, python...)')
|
||||
.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')
|
||||
.option('--raw', 'raw output (default mode)')
|
||||
.option('--formatted', 'formatted log output |id|app|log')
|
||||
.option('--json', 'output logs in json format')
|
||||
.option('--delay <seconds>', 'delay start of configuration file by <seconds>', 0)
|
||||
.option('--web [port]', 'launch process web api on [port] (default to 9615)')
|
||||
.option('--only <application-name>', 'only act on one application of configuration')
|
||||
.option('--no-auto-exit', 'do not exit if all processes are errored/stopped or 0 apps launched')
|
||||
.option('--env [name]', 'inject env_[name] env variables in process config file')
|
||||
.option('--watch', 'watch and restart application on file change')
|
||||
.option('--error <path>', 'error log file destination (default disabled)', '/dev/null')
|
||||
.option('--output <path>', 'output log file destination (default disabled)', '/dev/null')
|
||||
.option('--deep-monitoring', 'enable all monitoring tools (equivalent to --v8 --event-loop-inspector --trace)')
|
||||
.allowUnknownOption()
|
||||
.usage('app.js');
|
||||
|
||||
commander.command('*')
|
||||
.action(function(cmd){
|
||||
Runtime.instanciate(cmd);
|
||||
});
|
||||
|
||||
commander.command('start <app.js|json_file>')
|
||||
.description('start an application or json ecosystem file')
|
||||
.action(function(cmd) {
|
||||
Runtime.instanciate(cmd);
|
||||
});
|
||||
|
||||
if (process.argv.length == 2) {
|
||||
commander.outputHelp();
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
var Runtime = {
|
||||
pm2 : null,
|
||||
instanciate : function(cmd) {
|
||||
this.pm2 = new PM2.custom({
|
||||
pm2_home : process.env.PM2_HOME || path.join(process.env.HOME, '.pm2'),
|
||||
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
|
||||
});
|
||||
|
||||
this.pm2.connect(function(err, pm2_meta) {
|
||||
process.on('SIGINT', function() {
|
||||
Runtime.exit();
|
||||
});
|
||||
|
||||
process.on('SIGTERM', function() {
|
||||
Runtime.exit();
|
||||
});
|
||||
|
||||
Runtime.startLogStreaming();
|
||||
Runtime.startApp(cmd, function(err) {
|
||||
if (err) {
|
||||
console.error(err.message || err);
|
||||
return Runtime.exit();
|
||||
}
|
||||
});
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* Log Streaming Management
|
||||
*/
|
||||
startLogStreaming : function() {
|
||||
if (commander.json === true)
|
||||
Log.jsonStream(this.pm2.Client, 'all');
|
||||
else if (commander.format === true)
|
||||
Log.formatStream(this.pm2.Client, 'all', false, 'YYYY-MM-DD-HH:mm:ssZZ');
|
||||
else
|
||||
Log.stream(this.pm2.Client, 'all', !commander.formatted, commander.timestamp, true);
|
||||
},
|
||||
|
||||
/**
|
||||
* Application Startup
|
||||
*/
|
||||
startApp : function(cmd, cb) {
|
||||
function exec() {
|
||||
this.pm2.start(cmd, commander, function(err, obj) {
|
||||
if (err)
|
||||
return cb(err);
|
||||
if (obj && obj.length == 0)
|
||||
return cb(new Error(`0 application started (no apps to run on ${cmd})`))
|
||||
|
||||
if (commander.web) {
|
||||
var port = commander.web === true ? cst.WEB_PORT : commander.web;
|
||||
Runtime.pm2.web(port);
|
||||
}
|
||||
|
||||
if (commander.autoExit) {
|
||||
setTimeout(function() {
|
||||
Runtime.autoExitWorker();
|
||||
}, 4000);
|
||||
}
|
||||
|
||||
// For Testing purpose (allow to auto exit CLI)
|
||||
if (process.env.PM2_RUNTIME_DEBUG)
|
||||
Runtime.pm2.disconnect(function() {});
|
||||
|
||||
return cb(null, obj);
|
||||
});
|
||||
}
|
||||
// via --delay <seconds> option
|
||||
setTimeout(exec.bind(this), commander.delay * 1000);
|
||||
},
|
||||
|
||||
/**
|
||||
* Exit runtime mgmt
|
||||
*/
|
||||
exit : function(code) {
|
||||
if (!this.pm2) return process.exit(1);
|
||||
|
||||
this.pm2.kill(function() {
|
||||
process.exit(code || 0);
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* Exit current PM2 instance if 0 app is online
|
||||
* function activated via --auto-exit
|
||||
*/
|
||||
autoExitWorker : function(fail_count) {
|
||||
var interval = 2000;
|
||||
|
||||
if (typeof(fail_count) =='undefined')
|
||||
fail_count = DEFAULT_FAIL_COUNT;
|
||||
|
||||
var timer = setTimeout(function () {
|
||||
Runtime.pm2.list(function (err, apps) {
|
||||
if (err) {
|
||||
console.error('Could not run pm2 list');
|
||||
return Runtime.autoExitWorker();
|
||||
}
|
||||
|
||||
var appOnline = 0;
|
||||
|
||||
apps.forEach(function (app) {
|
||||
if (!app.pm2_env.pmx_module &&
|
||||
(app.pm2_env.status === cst.ONLINE_STATUS ||
|
||||
app.pm2_env.status === cst.LAUNCHING_STATUS)) {
|
||||
appOnline++;
|
||||
}
|
||||
});
|
||||
|
||||
if (appOnline === 0) {
|
||||
console.log('0 application online, retry =', fail_count);
|
||||
if (fail_count <= 0)
|
||||
return Runtime.exit(2);
|
||||
return Runtime.autoExitWorker(--fail_count);
|
||||
}
|
||||
|
||||
Runtime.autoExitWorker();
|
||||
});
|
||||
}, interval);
|
||||
|
||||
timer.unref();
|
||||
}
|
||||
}
|
||||
|
||||
commander.parse(process.argv);
|
||||
229
api.hyungi.net/node_modules/pm2/lib/completion.js
generated
vendored
Normal file
229
api.hyungi.net/node_modules/pm2/lib/completion.js
generated
vendored
Normal file
@@ -0,0 +1,229 @@
|
||||
/**
|
||||
* Copyright 2013-2022 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'),
|
||||
pth = require('path');
|
||||
|
||||
// hacked from node-tabtab 0.0.4 https://github.com/mklabs/node-tabtab.git
|
||||
// Itself based on npm completion by @isaac
|
||||
|
||||
exports.complete = function complete(name, completer, cb) {
|
||||
|
||||
// cb not there, assume callback is completer and
|
||||
// the completer is the executable itself
|
||||
if(!cb) {
|
||||
cb = completer;
|
||||
completer = name;
|
||||
}
|
||||
|
||||
var env = parseEnv();
|
||||
|
||||
// if not a complete command, return here.
|
||||
if(!env.complete) return cb();
|
||||
|
||||
// if install cmd, add complete script to either ~/.bashrc or ~/.zshrc
|
||||
if(env.install) return install(name, completer, function(err, state) {
|
||||
console.log(state || err.message);
|
||||
if(err) return cb(err);
|
||||
cb(null, null, state);
|
||||
});
|
||||
|
||||
// if install cmd, add complete script to either ~/.bashrc or ~/.zshrc
|
||||
if(env.uninstall) return uninstall(name, completer, function(err, state) {
|
||||
console.log(state || err.message);
|
||||
if(err) return cb(err);
|
||||
cb(null, null, state);
|
||||
});
|
||||
|
||||
// if the COMP_* are not in the env, then dump the install script.
|
||||
if(!env.words || !env.point || !env.line) return script(name, completer, function(err, content) {
|
||||
if(err) return cb(err);
|
||||
process.stdout.write(content, function (n) { cb(null, null, content); });
|
||||
process.stdout.on("error", function (er) {
|
||||
// Darwin is a real dick sometimes.
|
||||
//
|
||||
// This is necessary because the "source" or "." program in
|
||||
// bash on OS X closes its file argument before reading
|
||||
// from it, meaning that you get exactly 1 write, which will
|
||||
// work most of the time, and will always raise an EPIPE.
|
||||
//
|
||||
// Really, one should not be tossing away EPIPE errors, or any
|
||||
// errors, so casually. But, without this, `. <(npm completion)`
|
||||
// can never ever work on OS X.
|
||||
// -- isaacs
|
||||
// https://github.com/isaacs/npm/blob/master/lib/completion.js#L162
|
||||
if (er.errno === "EPIPE") er = null
|
||||
cb(er, null, content);
|
||||
});
|
||||
cb(null, null, content);
|
||||
});
|
||||
|
||||
var partial = env.line.substr(0, env.point),
|
||||
last = env.line.split(' ').slice(-1).join(''),
|
||||
lastPartial = partial.split(' ').slice(-1).join(''),
|
||||
prev = env.line.split(' ').slice(0, -1).slice(-1)[0];
|
||||
|
||||
cb(null, {
|
||||
line: env.line,
|
||||
words: env.words,
|
||||
point: env.point,
|
||||
partial: partial,
|
||||
last: last,
|
||||
prev: prev,
|
||||
lastPartial: lastPartial
|
||||
});
|
||||
};
|
||||
|
||||
// simple helper function to know if the script is run
|
||||
// in the context of a completion command. Also mapping the
|
||||
// special `<pkgname> completion` cmd.
|
||||
exports.isComplete = function isComplete() {
|
||||
var env = parseEnv();
|
||||
return env.complete || (env.words && env.point && env.line);
|
||||
};
|
||||
|
||||
exports.parseOut = function parseOut(str) {
|
||||
var shorts = str.match(/\s-\w+/g);
|
||||
var longs = str.match(/\s--\w+/g);
|
||||
|
||||
return {
|
||||
shorts: shorts.map(trim).map(cleanPrefix),
|
||||
longs: longs.map(trim).map(cleanPrefix)
|
||||
};
|
||||
};
|
||||
|
||||
// specific to cake case
|
||||
exports.parseTasks = function(str, prefix, reg) {
|
||||
var tasks = str.match(reg || new RegExp('^' + prefix + '\\s[^#]+', 'gm')) || [];
|
||||
return tasks.map(trim).map(function(s) {
|
||||
return s.replace(prefix + ' ', '');
|
||||
});
|
||||
};
|
||||
|
||||
exports.log = function log(arr, o, prefix) {
|
||||
prefix = prefix || '';
|
||||
arr = Array.isArray(arr) ? arr : [arr];
|
||||
arr.filter(abbrev(o)).forEach(function(v) {
|
||||
console.log(prefix + v);
|
||||
});
|
||||
}
|
||||
|
||||
function trim (s) {
|
||||
return s.trim();
|
||||
}
|
||||
|
||||
function cleanPrefix(s) {
|
||||
return s.replace(/-/g, '');
|
||||
}
|
||||
|
||||
function abbrev(o) { return function(it) {
|
||||
return new RegExp('^' + o.last.replace(/^--?/g, '')).test(it);
|
||||
}}
|
||||
|
||||
// output the completion.sh script to the console for install instructions.
|
||||
// This is actually a 'template' where the package name is used to setup
|
||||
// the completion on the right command, and properly name the bash/zsh functions.
|
||||
function script(name, completer, cb) {
|
||||
var p = pth.join(__dirname, 'completion.sh');
|
||||
|
||||
fs.readFile(p, 'utf8', function (er, d) {
|
||||
if (er) return cb(er);
|
||||
cb(null, d);
|
||||
});
|
||||
}
|
||||
|
||||
function install(name, completer, cb) {
|
||||
var markerIn = '###-begin-' + name + '-completion-###',
|
||||
markerOut = '###-end-' + name + '-completion-###';
|
||||
|
||||
var rc, scriptOutput;
|
||||
|
||||
readRc(completer, function(err, file) {
|
||||
if(err) return cb(err);
|
||||
|
||||
var part = file.split(markerIn)[1];
|
||||
if(part) {
|
||||
return cb(null, ' ✗ ' + completer + ' tab-completion has been already installed. Do nothing.');
|
||||
}
|
||||
|
||||
rc = file;
|
||||
next();
|
||||
});
|
||||
|
||||
script(name, completer, function(err, file) {
|
||||
scriptOutput = file;
|
||||
next();
|
||||
});
|
||||
|
||||
function next() {
|
||||
if(!rc || !scriptOutput) return;
|
||||
|
||||
writeRc(rc + scriptOutput, function(err) {
|
||||
if(err) return cb(err);
|
||||
return cb(null, ' ✓ ' + completer + ' tab-completion installed.');
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function uninstall(name, completer, cb) {
|
||||
var markerIn = '\n\n###-begin-' + name + '-completion-###',
|
||||
markerOut = '###-end-' + name + '-completion-###\n';
|
||||
|
||||
readRc(completer, function(err, file) {
|
||||
if(err) return cb(err);
|
||||
|
||||
var part = file.split(markerIn)[1];
|
||||
if(!part) {
|
||||
return cb(null, ' ✗ ' + completer + ' tab-completion has been already uninstalled. Do nothing.');
|
||||
}
|
||||
|
||||
part = markerIn + part.split(markerOut)[0] + markerOut;
|
||||
writeRc(file.replace(part, ''), function(err) {
|
||||
if(err) return cb(err);
|
||||
return cb(null, ' ✓ ' + completer + ' tab-completion uninstalled.');
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function readRc(completer, cb) {
|
||||
var file = '.' + process.env.SHELL.match(/\/bin\/(\w+)/)[1] + 'rc',
|
||||
filepath = pth.join(process.env.HOME, file);
|
||||
fs.lstat(filepath, function (err, stats) {
|
||||
if(err) return cb(new Error("No " + file + " file. You'll have to run instead: " + completer + " completion >> ~/" + file));
|
||||
fs.readFile(filepath, 'utf8', cb);
|
||||
});
|
||||
}
|
||||
|
||||
function writeRc(content, cb) {
|
||||
var file = '.' + process.env.SHELL.match(/\/bin\/(\w+)/)[1] + 'rc',
|
||||
filepath = pth.join(process.env.HOME, file);
|
||||
fs.lstat(filepath, function (err, stats) {
|
||||
if(err) return cb(new Error("No " + file + " file. You'll have to run instead: " + completer + " completion >> ~/" + file));
|
||||
fs.writeFile(filepath, content, cb);
|
||||
});
|
||||
}
|
||||
|
||||
function installed (marker, completer, cb) {
|
||||
readRc(completer, function(err, file) {
|
||||
if(err) return cb(err);
|
||||
var installed = file.match(marker);
|
||||
return cb(!!installed);
|
||||
});
|
||||
}
|
||||
|
||||
function parseEnv() {
|
||||
var args = process.argv.slice(2),
|
||||
complete = args[0] === 'completion';
|
||||
|
||||
return {
|
||||
args: args,
|
||||
complete: complete,
|
||||
install: complete && args[1] === 'install',
|
||||
uninstall: complete && args[1] === 'uninstall',
|
||||
words: +process.env.COMP_CWORD,
|
||||
point: +process.env.COMP_POINT,
|
||||
line: process.env.COMP_LINE
|
||||
}
|
||||
};
|
||||
40
api.hyungi.net/node_modules/pm2/lib/completion.sh
generated
vendored
Normal file
40
api.hyungi.net/node_modules/pm2/lib/completion.sh
generated
vendored
Normal file
@@ -0,0 +1,40 @@
|
||||
###-begin-pm2-completion-###
|
||||
### credits to npm for the completion file model
|
||||
#
|
||||
# Installation: pm2 completion >> ~/.bashrc (or ~/.zshrc)
|
||||
#
|
||||
|
||||
COMP_WORDBREAKS=${COMP_WORDBREAKS/=/}
|
||||
COMP_WORDBREAKS=${COMP_WORDBREAKS/@/}
|
||||
export COMP_WORDBREAKS
|
||||
|
||||
if type complete &>/dev/null; then
|
||||
_pm2_completion () {
|
||||
local si="$IFS"
|
||||
IFS=$'\n' COMPREPLY=($(COMP_CWORD="$COMP_CWORD" \
|
||||
COMP_LINE="$COMP_LINE" \
|
||||
COMP_POINT="$COMP_POINT" \
|
||||
pm2 completion -- "${COMP_WORDS[@]}" \
|
||||
2>/dev/null)) || return $?
|
||||
IFS="$si"
|
||||
}
|
||||
complete -o default -F _pm2_completion pm2
|
||||
elif type compctl &>/dev/null; then
|
||||
_pm2_completion () {
|
||||
local cword line point words si
|
||||
read -Ac words
|
||||
read -cn cword
|
||||
let cword-=1
|
||||
read -l line
|
||||
read -ln point
|
||||
si="$IFS"
|
||||
IFS=$'\n' reply=($(COMP_CWORD="$cword" \
|
||||
COMP_LINE="$line" \
|
||||
COMP_POINT="$point" \
|
||||
pm2 completion -- "${words[@]}" \
|
||||
2>/dev/null)) || return $?
|
||||
IFS="$si"
|
||||
}
|
||||
compctl -K _pm2_completion + -f + pm2
|
||||
fi
|
||||
###-end-pm2-completion-###
|
||||
36
api.hyungi.net/node_modules/pm2/lib/motd
generated
vendored
Normal file
36
api.hyungi.net/node_modules/pm2/lib/motd
generated
vendored
Normal file
@@ -0,0 +1,36 @@
|
||||
|
||||
-------------
|
||||
|
||||
__/\\\\\\\\\\\\\____/\\\\____________/\\\\____/\\\\\\\\\_____
|
||||
_\/\\\/////////\\\_\/\\\\\\________/\\\\\\__/\\\///////\\\___
|
||||
_\/\\\_______\/\\\_\/\\\//\\\____/\\\//\\\_\///______\//\\\__
|
||||
_\/\\\\\\\\\\\\\/__\/\\\\///\\\/\\\/_\/\\\___________/\\\/___
|
||||
_\/\\\/////////____\/\\\__\///\\\/___\/\\\________/\\\//_____
|
||||
_\/\\\_____________\/\\\____\///_____\/\\\_____/\\\//________
|
||||
_\/\\\_____________\/\\\_____________\/\\\___/\\\/___________
|
||||
_\/\\\_____________\/\\\_____________\/\\\__/\\\\\\\\\\\\\\\_
|
||||
_\///______________\///______________\///__\///////////////__
|
||||
|
||||
|
||||
Runtime Edition
|
||||
|
||||
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
|
||||
|
||||
Load Balance 4 instances of api.js:
|
||||
$ pm2 start api.js -i 4
|
||||
|
||||
Monitor in production:
|
||||
$ pm2 monitor
|
||||
|
||||
Make pm2 auto-boot at server restart:
|
||||
$ pm2 startup
|
||||
|
||||
To go further checkout:
|
||||
http://pm2.io/
|
||||
|
||||
|
||||
-------------
|
||||
7
api.hyungi.net/node_modules/pm2/lib/templates/Dockerfiles/Dockerfile-java.tpl
generated
vendored
Normal file
7
api.hyungi.net/node_modules/pm2/lib/templates/Dockerfiles/Dockerfile-java.tpl
generated
vendored
Normal file
@@ -0,0 +1,7 @@
|
||||
FROM anapsix/alpine-java:latest
|
||||
|
||||
RUN apk update && apk add git && rm -rf /var/cache/apk/*
|
||||
RUN npm install pm2@next -g
|
||||
RUN mkdir -p /var/app
|
||||
|
||||
WORKDIR /var/app
|
||||
8
api.hyungi.net/node_modules/pm2/lib/templates/Dockerfiles/Dockerfile-nodejs.tpl
generated
vendored
Normal file
8
api.hyungi.net/node_modules/pm2/lib/templates/Dockerfiles/Dockerfile-nodejs.tpl
generated
vendored
Normal file
@@ -0,0 +1,8 @@
|
||||
FROM keymetrics/pm2:latest
|
||||
|
||||
RUN mkdir -p /var/app
|
||||
|
||||
WORKDIR /var/app
|
||||
|
||||
COPY ./package.json /var/app
|
||||
RUN npm install
|
||||
7
api.hyungi.net/node_modules/pm2/lib/templates/Dockerfiles/Dockerfile-ruby.tpl
generated
vendored
Normal file
7
api.hyungi.net/node_modules/pm2/lib/templates/Dockerfiles/Dockerfile-ruby.tpl
generated
vendored
Normal file
@@ -0,0 +1,7 @@
|
||||
FROM anapsix/alpine-ruby:latest
|
||||
|
||||
RUN apk update && apk add git && rm -rf /var/cache/apk/*
|
||||
RUN npm install pm2@next -g
|
||||
RUN mkdir -p /var/app
|
||||
|
||||
WORKDIR /var/app
|
||||
24
api.hyungi.net/node_modules/pm2/lib/templates/ecosystem-es.tpl
generated
vendored
Normal file
24
api.hyungi.net/node_modules/pm2/lib/templates/ecosystem-es.tpl
generated
vendored
Normal file
@@ -0,0 +1,24 @@
|
||||
const config = {
|
||||
apps : [{
|
||||
script: 'index.js',
|
||||
watch: '.'
|
||||
}, {
|
||||
script: './service-worker/',
|
||||
watch: ['./service-worker']
|
||||
}],
|
||||
|
||||
deploy : {
|
||||
production : {
|
||||
user : 'SSH_USERNAME',
|
||||
host : 'SSH_HOSTMACHINE',
|
||||
ref : 'origin/master',
|
||||
repo : 'GIT_REPOSITORY',
|
||||
path : 'DESTINATION_PATH',
|
||||
'pre-deploy-local': '',
|
||||
'post-deploy' : 'npm install && pm2 reload ecosystem.config.js --env production',
|
||||
'pre-setup': ''
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
export default config;
|
||||
8
api.hyungi.net/node_modules/pm2/lib/templates/ecosystem-simple-es.tpl
generated
vendored
Normal file
8
api.hyungi.net/node_modules/pm2/lib/templates/ecosystem-simple-es.tpl
generated
vendored
Normal file
@@ -0,0 +1,8 @@
|
||||
const config = {
|
||||
apps : [{
|
||||
name : "app1",
|
||||
script : "./app.js"
|
||||
}]
|
||||
}
|
||||
|
||||
export default config;
|
||||
6
api.hyungi.net/node_modules/pm2/lib/templates/ecosystem-simple.tpl
generated
vendored
Normal file
6
api.hyungi.net/node_modules/pm2/lib/templates/ecosystem-simple.tpl
generated
vendored
Normal file
@@ -0,0 +1,6 @@
|
||||
module.exports = {
|
||||
apps : [{
|
||||
name : "app1",
|
||||
script : "./app.js"
|
||||
}]
|
||||
}
|
||||
22
api.hyungi.net/node_modules/pm2/lib/templates/ecosystem.tpl
generated
vendored
Normal file
22
api.hyungi.net/node_modules/pm2/lib/templates/ecosystem.tpl
generated
vendored
Normal file
@@ -0,0 +1,22 @@
|
||||
module.exports = {
|
||||
apps : [{
|
||||
script: 'index.js',
|
||||
watch: '.'
|
||||
}, {
|
||||
script: './service-worker/',
|
||||
watch: ['./service-worker']
|
||||
}],
|
||||
|
||||
deploy : {
|
||||
production : {
|
||||
user : 'SSH_USERNAME',
|
||||
host : 'SSH_HOSTMACHINE',
|
||||
ref : 'origin/master',
|
||||
repo : 'GIT_REPOSITORY',
|
||||
path : 'DESTINATION_PATH',
|
||||
'pre-deploy-local': '',
|
||||
'post-deploy' : 'npm install && pm2 reload ecosystem.config.js --env production',
|
||||
'pre-setup': ''
|
||||
}
|
||||
}
|
||||
};
|
||||
35
api.hyungi.net/node_modules/pm2/lib/templates/init-scripts/launchd.tpl
generated
vendored
Normal file
35
api.hyungi.net/node_modules/pm2/lib/templates/init-scripts/launchd.tpl
generated
vendored
Normal file
@@ -0,0 +1,35 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>Label</key>
|
||||
<string>com.PM2</string>
|
||||
<key>UserName</key>
|
||||
<string>%USER%</string>
|
||||
<key>KeepAlive</key>
|
||||
<true/>
|
||||
<key>ProgramArguments</key>
|
||||
<array>
|
||||
<string>/bin/sh</string>
|
||||
<string>-c</string>
|
||||
<string>%PM2_PATH% resurrect</string>
|
||||
</array>
|
||||
<key>RunAtLoad</key>
|
||||
<true/>
|
||||
<key>OnDemand</key>
|
||||
<false/>
|
||||
<key>LaunchOnlyOnce</key>
|
||||
<true/>
|
||||
<key>EnvironmentVariables</key>
|
||||
<dict>
|
||||
<key>PATH</key>
|
||||
<string>%NODE_PATH%</string>
|
||||
<key>PM2_HOME</key>
|
||||
<string>%HOME_PATH%</string>
|
||||
</dict>
|
||||
<key>StandardErrorPath</key>
|
||||
<string>/tmp/com.PM2.err</string>
|
||||
<key>StandardOutPath</key>
|
||||
<string>/tmp/com.PM2.out</string>
|
||||
</dict>
|
||||
</plist>
|
||||
52
api.hyungi.net/node_modules/pm2/lib/templates/init-scripts/openrc.tpl
generated
vendored
Normal file
52
api.hyungi.net/node_modules/pm2/lib/templates/init-scripts/openrc.tpl
generated
vendored
Normal file
@@ -0,0 +1,52 @@
|
||||
#!/sbin/openrc-run
|
||||
# Copyright 2013-2022 the PM2 project authors. All rights reserved.
|
||||
# Init script automatically generated by pm2 startup
|
||||
|
||||
description="Production process manager for Node.js apps with a built-in load balancer."
|
||||
|
||||
extra_started_commands="reload"
|
||||
|
||||
PM2="%PM2_PATH%"
|
||||
user=${PM2_USER:-%USER%}
|
||||
export PM2_HOME=$(eval echo ~${user})"/.pm2/"
|
||||
# Options for start-stop-daemon (default start function)
|
||||
command=${PM2}
|
||||
command_user=${user}
|
||||
command_args="resurrect"
|
||||
pidfile=${PM2_HOME}/pm2.pid
|
||||
|
||||
run_pm2_as_user() {
|
||||
einfo "${PM2} $@"
|
||||
eval su -l ${user} -c \'${PM2} $@\'
|
||||
}
|
||||
|
||||
depend() {
|
||||
need net
|
||||
need localmount
|
||||
after bootmisc
|
||||
}
|
||||
|
||||
start_post() {
|
||||
if [ "${user}" == "root" ]; then
|
||||
ewarn "PM2: Better run this daemon as a non root user. To set this user create"
|
||||
ewarn "PM2: /etc/conf.d/pm2 file and define 'PM2_USER=user' there."
|
||||
ewarn "PM2: Note user MUST have home directory for PM2 logs/state/etc..."
|
||||
fi
|
||||
einfo "PM2: Process Manager started. To start services run:"
|
||||
einfo "PM2: # su -l ${user} -c '$PM2 start /path/to/app'"
|
||||
}
|
||||
|
||||
stop() {
|
||||
ebegin "Stopping PM2 process manager..."
|
||||
run_pm2_as_user dump
|
||||
run_pm2_as_user kill
|
||||
eend $?
|
||||
}
|
||||
|
||||
reload() {
|
||||
ebegin "Reloading pm2"
|
||||
run_pm2_as_user reload all
|
||||
eend $?
|
||||
}
|
||||
|
||||
# vim: ts=4
|
||||
86
api.hyungi.net/node_modules/pm2/lib/templates/init-scripts/pm2-init-amazon.sh
generated
vendored
Normal file
86
api.hyungi.net/node_modules/pm2/lib/templates/init-scripts/pm2-init-amazon.sh
generated
vendored
Normal file
@@ -0,0 +1,86 @@
|
||||
#!/bin/bash
|
||||
#
|
||||
# pm2 Process manager for NodeJS
|
||||
#
|
||||
# chkconfig: 345 80 20
|
||||
#
|
||||
# description: PM2 next gen process manager for Node.js
|
||||
# processname: pm2
|
||||
#
|
||||
### BEGIN INIT INFO
|
||||
# Provides: pm2
|
||||
# Required-Start: $local_fs $remote_fs
|
||||
# Required-Stop: $local_fs $remote_fs
|
||||
# Should-Start: $network
|
||||
# Should-Stop: $network
|
||||
# Default-Start: 2 3 4 5
|
||||
# Default-Stop: 0 1 6
|
||||
# Short-Description: PM2 init script
|
||||
# Description: PM2 is the next gen process manager for Node.js
|
||||
### END INIT INFO
|
||||
|
||||
NAME=pm2
|
||||
PM2=%PM2_PATH%
|
||||
USER=%USER%
|
||||
|
||||
export PATH=%NODE_PATH%:$PATH
|
||||
export PM2_HOME="%HOME_PATH%"
|
||||
|
||||
lockfile="/var/lock/subsys/pm2-init.sh"
|
||||
|
||||
super() {
|
||||
su - $USER -c "PATH=$PATH; PM2_HOME=$PM2_HOME $*"
|
||||
}
|
||||
|
||||
start() {
|
||||
echo "Starting $NAME"
|
||||
super $PM2 resurrect
|
||||
retval=$?
|
||||
[ $retval -eq 0 ] && touch $lockfile
|
||||
}
|
||||
|
||||
stop() {
|
||||
echo "Stopping $NAME"
|
||||
super $PM2 kill
|
||||
rm -f $lockfile
|
||||
}
|
||||
|
||||
restart() {
|
||||
echo "Restarting $NAME"
|
||||
stop
|
||||
start
|
||||
}
|
||||
|
||||
reload() {
|
||||
echo "Reloading $NAME"
|
||||
super $PM2 reload all
|
||||
}
|
||||
|
||||
status() {
|
||||
echo "Status for $NAME:"
|
||||
super $PM2 list
|
||||
RETVAL=$?
|
||||
}
|
||||
|
||||
case "$1" in
|
||||
start)
|
||||
start
|
||||
;;
|
||||
stop)
|
||||
stop
|
||||
;;
|
||||
status)
|
||||
status
|
||||
;;
|
||||
restart)
|
||||
restart
|
||||
;;
|
||||
reload)
|
||||
reload
|
||||
;;
|
||||
*)
|
||||
echo "Usage: {start|stop|status|restart|reload}"
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
exit $RETVAL
|
||||
41
api.hyungi.net/node_modules/pm2/lib/templates/init-scripts/rcd-openbsd.tpl
generated
vendored
Normal file
41
api.hyungi.net/node_modules/pm2/lib/templates/init-scripts/rcd-openbsd.tpl
generated
vendored
Normal file
@@ -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
|
||||
44
api.hyungi.net/node_modules/pm2/lib/templates/init-scripts/rcd.tpl
generated
vendored
Normal file
44
api.hyungi.net/node_modules/pm2/lib/templates/init-scripts/rcd.tpl
generated
vendored
Normal file
@@ -0,0 +1,44 @@
|
||||
#!/bin/sh
|
||||
|
||||
# PROVIDE: pm2
|
||||
# REQUIRE: LOGIN
|
||||
# KEYWORD: shutdown
|
||||
|
||||
. /etc/rc.subr
|
||||
|
||||
name="%SERVICE_NAME%"
|
||||
rcvar="%SERVICE_NAME%_enable"
|
||||
|
||||
start_cmd="pm2_start"
|
||||
stop_cmd="pm2_stop"
|
||||
reload_cmd="pm2_reload"
|
||||
status_cmd="pm2_status"
|
||||
extra_commands="reload status"
|
||||
|
||||
pm2()
|
||||
{
|
||||
env PATH="$PATH:%NODE_PATH%" PM2_HOME="%HOME_PATH%" su -m "%USER%" -c "%PM2_PATH% $*"
|
||||
}
|
||||
|
||||
pm2_start()
|
||||
{
|
||||
pm2 resurrect
|
||||
}
|
||||
|
||||
pm2_stop()
|
||||
{
|
||||
pm2 kill
|
||||
}
|
||||
|
||||
pm2_reload()
|
||||
{
|
||||
pm2 reload all
|
||||
}
|
||||
|
||||
pm2_status()
|
||||
{
|
||||
pm2 list
|
||||
}
|
||||
|
||||
load_rc_config $name
|
||||
run_rc_command "$1"
|
||||
43
api.hyungi.net/node_modules/pm2/lib/templates/init-scripts/smf.tpl
generated
vendored
Normal file
43
api.hyungi.net/node_modules/pm2/lib/templates/init-scripts/smf.tpl
generated
vendored
Normal file
@@ -0,0 +1,43 @@
|
||||
<?xml version="1.0"?>
|
||||
<!DOCTYPE service_bundle SYSTEM "/usr/share/lib/xml/dtd/service_bundle.dtd.1">
|
||||
<service_bundle type="manifest" name="%SERVICE_NAME%">
|
||||
<service name="application/%SERVICE_NAME%" type="service" version="1">
|
||||
<create_default_instance enabled="false"/>
|
||||
<single_instance/>
|
||||
|
||||
<dependency name="network" grouping="require_all" restart_on="error" type="service">
|
||||
<service_fmri value="svc:/milestone/network:default"/>
|
||||
</dependency>
|
||||
|
||||
<dependency name="filesystem" grouping="require_all" restart_on="error" type="service">
|
||||
<service_fmri value="svc:/system/filesystem/local"/>
|
||||
</dependency>
|
||||
|
||||
<method_context>
|
||||
<method_environment>
|
||||
<envvar name='PATH' value="%NODE_PATH%:/usr/local/sbin:/usr/local/bin:/opt/local/sbin:/opt/local/bin:/usr/sbin:/usr/bin:/sbin"/>
|
||||
<envvar name='PM2_HOME' value="%HOME_PATH%"/>
|
||||
</method_environment>
|
||||
</method_context>
|
||||
|
||||
<exec_method type="method" name="start" exec="%PM2_PATH% resurrect" timeout_seconds="60"/>
|
||||
<exec_method type="method" name="refresh" exec="%PM2_PATH% reload all" timeout_seconds="60"/>
|
||||
<exec_method type="method" name="stop" exec="%PM2_PATH% kill" timeout_seconds="60"/>
|
||||
|
||||
<property_group name="startd" type="framework">
|
||||
<propval name="duration" type="astring" value="contract"/>
|
||||
<propval name="ignore_error" type="astring" value="core,signal"/>
|
||||
</property_group>
|
||||
|
||||
<property_group name="application" type="application"></property_group>
|
||||
<stability value="Evolving"/>
|
||||
|
||||
<template>
|
||||
<common_name>
|
||||
<loctext xml:lang="C">
|
||||
PM2 process manager
|
||||
</loctext>
|
||||
</common_name>
|
||||
</template>
|
||||
</service>
|
||||
</service_bundle>
|
||||
22
api.hyungi.net/node_modules/pm2/lib/templates/init-scripts/systemd-online.tpl
generated
vendored
Normal file
22
api.hyungi.net/node_modules/pm2/lib/templates/init-scripts/systemd-online.tpl
generated
vendored
Normal file
@@ -0,0 +1,22 @@
|
||||
[Unit]
|
||||
Description=PM2 process manager
|
||||
Documentation=https://pm2.keymetrics.io/
|
||||
After=network-online.target
|
||||
Restart=on-failure
|
||||
|
||||
[Service]
|
||||
Type=forking
|
||||
User=%USER%
|
||||
LimitNOFILE=infinity
|
||||
LimitNPROC=infinity
|
||||
LimitCORE=infinity
|
||||
Environment=PATH=%NODE_PATH%:/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin
|
||||
Environment=PM2_HOME=%HOME_PATH%
|
||||
PIDFile=%HOME_PATH%/pm2.pid
|
||||
|
||||
ExecStart=%PM2_PATH% resurrect
|
||||
ExecReload=%PM2_PATH% reload all
|
||||
ExecStop=%PM2_PATH% kill
|
||||
|
||||
[Install]
|
||||
WantedBy=network-online.target
|
||||
22
api.hyungi.net/node_modules/pm2/lib/templates/init-scripts/systemd.tpl
generated
vendored
Normal file
22
api.hyungi.net/node_modules/pm2/lib/templates/init-scripts/systemd.tpl
generated
vendored
Normal file
@@ -0,0 +1,22 @@
|
||||
[Unit]
|
||||
Description=PM2 process manager
|
||||
Documentation=https://pm2.keymetrics.io/
|
||||
After=network.target
|
||||
|
||||
[Service]
|
||||
Type=forking
|
||||
User=%USER%
|
||||
LimitNOFILE=infinity
|
||||
LimitNPROC=infinity
|
||||
LimitCORE=infinity
|
||||
Environment=PATH=%NODE_PATH%:/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin
|
||||
Environment=PM2_HOME=%HOME_PATH%
|
||||
PIDFile=%HOME_PATH%/pm2.pid
|
||||
Restart=on-failure
|
||||
|
||||
ExecStart=%PM2_PATH% resurrect
|
||||
ExecReload=%PM2_PATH% reload all
|
||||
ExecStop=%PM2_PATH% kill
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
103
api.hyungi.net/node_modules/pm2/lib/templates/init-scripts/upstart.tpl
generated
vendored
Normal file
103
api.hyungi.net/node_modules/pm2/lib/templates/init-scripts/upstart.tpl
generated
vendored
Normal file
@@ -0,0 +1,103 @@
|
||||
#!/bin/bash
|
||||
### BEGIN INIT INFO
|
||||
# Provides: pm2
|
||||
# Required-Start: $local_fs $remote_fs $network
|
||||
# Required-Stop: $local_fs $remote_fs $network
|
||||
# Default-Start: 2 3 4 5
|
||||
# Default-Stop: 0 1 6
|
||||
# Short-Description: PM2 Init script
|
||||
# Description: PM2 process manager
|
||||
### END INIT INFO
|
||||
|
||||
NAME=pm2
|
||||
PM2=%PM2_PATH%
|
||||
USER=%USER%
|
||||
DEFAULT=/etc/default/$NAME
|
||||
|
||||
export PATH=%NODE_PATH%:$PATH
|
||||
export PM2_HOME="%HOME_PATH%"
|
||||
|
||||
# The following variables can be overwritten in $DEFAULT
|
||||
|
||||
# maximum number of open files
|
||||
MAX_OPEN_FILES=
|
||||
|
||||
# overwrite settings from default file
|
||||
if [ -f "$DEFAULT" ]; then
|
||||
. "$DEFAULT"
|
||||
fi
|
||||
|
||||
# set maximum open files if set
|
||||
if [ -n "$MAX_OPEN_FILES" ]; then
|
||||
ulimit -n $MAX_OPEN_FILES
|
||||
fi
|
||||
|
||||
get_user_shell() {
|
||||
local shell
|
||||
shell=$(getent passwd "${1:-$(whoami)}" | cut -d: -f7 | sed -e 's/[[:space:]]*$//')
|
||||
|
||||
if [[ $shell == *"/sbin/nologin" ]] || [[ $shell == "/bin/false" ]] || [[ -z "$shell" ]];
|
||||
then
|
||||
shell="/bin/bash"
|
||||
fi
|
||||
|
||||
echo "$shell"
|
||||
}
|
||||
|
||||
super() {
|
||||
local shell
|
||||
shell=$(get_user_shell $USER)
|
||||
su - "$USER" -s "$shell" -c "PATH=$PATH; PM2_HOME=$PM2_HOME $*"
|
||||
}
|
||||
|
||||
start() {
|
||||
echo "Starting $NAME"
|
||||
super $PM2 resurrect
|
||||
}
|
||||
|
||||
stop() {
|
||||
super $PM2 kill
|
||||
}
|
||||
|
||||
restart() {
|
||||
echo "Restarting $NAME"
|
||||
stop
|
||||
start
|
||||
}
|
||||
|
||||
reload() {
|
||||
echo "Reloading $NAME"
|
||||
super $PM2 reload all
|
||||
}
|
||||
|
||||
status() {
|
||||
echo "Status for $NAME:"
|
||||
super $PM2 list
|
||||
RETVAL=$?
|
||||
}
|
||||
|
||||
case "$1" in
|
||||
start)
|
||||
start
|
||||
;;
|
||||
stop)
|
||||
stop
|
||||
;;
|
||||
status)
|
||||
status
|
||||
;;
|
||||
restart)
|
||||
restart
|
||||
;;
|
||||
reload)
|
||||
reload
|
||||
;;
|
||||
force-reload)
|
||||
reload
|
||||
;;
|
||||
*)
|
||||
echo "Usage: {start|stop|status|restart|reload|force-reload}"
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
exit $RETVAL
|
||||
10
api.hyungi.net/node_modules/pm2/lib/templates/logrotate.d/pm2
generated
vendored
Normal file
10
api.hyungi.net/node_modules/pm2/lib/templates/logrotate.d/pm2
generated
vendored
Normal file
@@ -0,0 +1,10 @@
|
||||
%HOME_PATH%/pm2.log %HOME_PATH%/logs/*.log {
|
||||
rotate 12
|
||||
weekly
|
||||
missingok
|
||||
notifempty
|
||||
compress
|
||||
delaycompress
|
||||
copytruncate
|
||||
create 0640 %USER% %USER%
|
||||
}
|
||||
14
api.hyungi.net/node_modules/pm2/lib/templates/sample-apps/http-server/README.md
generated
vendored
Normal file
14
api.hyungi.net/node_modules/pm2/lib/templates/sample-apps/http-server/README.md
generated
vendored
Normal file
@@ -0,0 +1,14 @@
|
||||
|
||||
# Basic HTTP Server and Cluster mode
|
||||
|
||||
In this boilerplate it will start an http server in cluster mode.
|
||||
|
||||
You can check the content of the ecosystem.config.js on how to start mutliple instances of the same HTTP application in order to get the most from your working system.
|
||||
|
||||
## Via CLI
|
||||
|
||||
Via CLI you can start any HTTP/TCP application in cluster mode with:
|
||||
|
||||
```bash
|
||||
$ pm2 start api.js -i max
|
||||
```
|
||||
9
api.hyungi.net/node_modules/pm2/lib/templates/sample-apps/http-server/api.js
generated
vendored
Normal file
9
api.hyungi.net/node_modules/pm2/lib/templates/sample-apps/http-server/api.js
generated
vendored
Normal file
@@ -0,0 +1,9 @@
|
||||
|
||||
var http = require('http');
|
||||
|
||||
var server = http.createServer(function(req, res) {
|
||||
res.writeHead(200);
|
||||
res.end('hey');
|
||||
}).listen(process.env.PORT || 8000, function() {
|
||||
console.log('App listening on port %d', server.address().port);
|
||||
});
|
||||
14
api.hyungi.net/node_modules/pm2/lib/templates/sample-apps/http-server/ecosystem.config.js
generated
vendored
Normal file
14
api.hyungi.net/node_modules/pm2/lib/templates/sample-apps/http-server/ecosystem.config.js
generated
vendored
Normal file
@@ -0,0 +1,14 @@
|
||||
module.exports = {
|
||||
apps : [{
|
||||
name: 'API',
|
||||
script: 'api.js',
|
||||
instances: 4,
|
||||
max_memory_restart: '1G',
|
||||
env: {
|
||||
NODE_ENV: 'development'
|
||||
},
|
||||
env_production: {
|
||||
NODE_ENV: 'production'
|
||||
}
|
||||
}]
|
||||
};
|
||||
11
api.hyungi.net/node_modules/pm2/lib/templates/sample-apps/http-server/package.json
generated
vendored
Normal file
11
api.hyungi.net/node_modules/pm2/lib/templates/sample-apps/http-server/package.json
generated
vendored
Normal file
@@ -0,0 +1,11 @@
|
||||
{
|
||||
"name": "simple-http-server",
|
||||
"version": "1.0.0",
|
||||
"description": "Simple HTTP server that can be used in cluster mode",
|
||||
"main": "index.js",
|
||||
"scripts": {
|
||||
"test": "echo \"Error: no test specified\" && exit 1"
|
||||
},
|
||||
"author": "",
|
||||
"license": "ISC"
|
||||
}
|
||||
45
api.hyungi.net/node_modules/pm2/lib/templates/sample-apps/pm2-plus-metrics-actions/README.md
generated
vendored
Normal file
45
api.hyungi.net/node_modules/pm2/lib/templates/sample-apps/pm2-plus-metrics-actions/README.md
generated
vendored
Normal file
@@ -0,0 +1,45 @@
|
||||
|
||||
# pm2 custom metrics boilerplate
|
||||
|
||||
In this boilerplate you will discover a working example of custom metrics feature.
|
||||
|
||||
Metrics covered are:
|
||||
- io.metric
|
||||
- io.counter
|
||||
- io.meter
|
||||
- io.histogram
|
||||
|
||||
## What is Custom Metrics?
|
||||
|
||||
Custom metrics is a powerfull way to get more visibility from a running application. It will allow you to monitor in realtime the current value of variables, know the number of actions being processed, measure latency and much more.
|
||||
|
||||
Once you have plugged in some custom metrics you will be able to monitor their value in realtime with
|
||||
|
||||
`pm2 monit`
|
||||
|
||||
Or
|
||||
|
||||
`pm2 describe`
|
||||
|
||||
Or on the PM2+ Web interface
|
||||
|
||||
`pm2 open`
|
||||
|
||||
## Example
|
||||
|
||||
```javascript
|
||||
const io = require('@pm2/io')
|
||||
|
||||
const currentReq = io.counter({
|
||||
name: 'CM: Current Processing',
|
||||
type: 'counter'
|
||||
})
|
||||
|
||||
setInterval(() => {
|
||||
currentReq.inc()
|
||||
}, 1000)
|
||||
```
|
||||
|
||||
## Documentation
|
||||
|
||||
https://doc.pm2.io/en/plus/guide/custom-metrics/
|
||||
66
api.hyungi.net/node_modules/pm2/lib/templates/sample-apps/pm2-plus-metrics-actions/custom-metrics.js
generated
vendored
Normal file
66
api.hyungi.net/node_modules/pm2/lib/templates/sample-apps/pm2-plus-metrics-actions/custom-metrics.js
generated
vendored
Normal file
@@ -0,0 +1,66 @@
|
||||
|
||||
const io = require('@pm2/io')
|
||||
|
||||
// Straight Metric
|
||||
var user_count = 10
|
||||
|
||||
const users = io.metric({
|
||||
name: 'CM: Realtime user',
|
||||
value: () => {
|
||||
return user_count
|
||||
}
|
||||
})
|
||||
|
||||
// or users.set(user_count)
|
||||
|
||||
// Counter (.inc() .dec())
|
||||
const currentReq = io.counter({
|
||||
name: 'CM: Current Processing',
|
||||
type: 'counter'
|
||||
})
|
||||
|
||||
setInterval(() => {
|
||||
currentReq.inc()
|
||||
}, 1000)
|
||||
|
||||
// Meter
|
||||
const reqsec = io.meter({
|
||||
name: 'CM: req/sec'
|
||||
})
|
||||
|
||||
setInterval(() => {
|
||||
reqsec.mark()
|
||||
}, 100)
|
||||
|
||||
|
||||
// Histogram
|
||||
const latency = io.histogram({
|
||||
name: 'CM: latency'
|
||||
});
|
||||
|
||||
var latencyValue = 0;
|
||||
|
||||
setInterval(() => {
|
||||
latencyValue = Math.round(Math.random() * 100);
|
||||
latency.update(latencyValue);
|
||||
}, 100)
|
||||
|
||||
|
||||
////////////////////
|
||||
// Custom Actions //
|
||||
////////////////////
|
||||
|
||||
io.action('add user', (done) => {
|
||||
user_count++
|
||||
done({success:true})
|
||||
})
|
||||
|
||||
io.action('remove user', (done) => {
|
||||
user_count++
|
||||
done({success:true})
|
||||
})
|
||||
|
||||
io.action('with params', (arg, done) => {
|
||||
console.log(arg)
|
||||
done({success:arg})
|
||||
})
|
||||
12
api.hyungi.net/node_modules/pm2/lib/templates/sample-apps/pm2-plus-metrics-actions/ecosystem.config.js
generated
vendored
Normal file
12
api.hyungi.net/node_modules/pm2/lib/templates/sample-apps/pm2-plus-metrics-actions/ecosystem.config.js
generated
vendored
Normal file
@@ -0,0 +1,12 @@
|
||||
module.exports = {
|
||||
apps : [{
|
||||
name: 'Custom Metrics',
|
||||
script: 'custom-metrics.js',
|
||||
env: {
|
||||
NODE_ENV: 'development'
|
||||
},
|
||||
env_production: {
|
||||
NODE_ENV: 'production'
|
||||
}
|
||||
}]
|
||||
};
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user