Compare commits
18 commits
Author | SHA1 | Date | |
---|---|---|---|
fc37d736f5 | |||
598eeab975 | |||
5bdf0dd8d2 | |||
c1b254ea02 | |||
c1c132199d | |||
407d99c45d | |||
195b0c5b90 | |||
af6b9daf16 | |||
97d6a3669e | |||
a49297eda7 | |||
f5bf5494c6 | |||
e396d5a4a4 | |||
45f23e6450 | |||
c2336a1cd2 | |||
9be96f3705 | |||
684be87f62 | |||
95aad74ded | |||
5a124aacec |
208
.gitignore
vendored
208
.gitignore
vendored
|
@ -1,3 +1,207 @@
|
||||||
*.pyc
|
# ---> Python
|
||||||
.*.swp
|
# Byte-compiled / optimized / DLL files
|
||||||
|
__pycache__/
|
||||||
|
*.py[cod]
|
||||||
|
*$py.class
|
||||||
|
|
||||||
|
# C extensions
|
||||||
|
*.so
|
||||||
|
|
||||||
|
# Distribution / packaging
|
||||||
|
.Python
|
||||||
|
build/
|
||||||
|
develop-eggs/
|
||||||
|
dist/
|
||||||
|
downloads/
|
||||||
|
eggs/
|
||||||
|
.eggs/
|
||||||
|
lib/
|
||||||
|
lib64/
|
||||||
|
parts/
|
||||||
|
sdist/
|
||||||
|
var/
|
||||||
|
wheels/
|
||||||
|
share/python-wheels/
|
||||||
|
*.egg-info/
|
||||||
|
.installed.cfg
|
||||||
|
*.egg
|
||||||
|
MANIFEST
|
||||||
|
|
||||||
|
# PyInstaller
|
||||||
|
# Usually these files are written by a python script from a template
|
||||||
|
# before PyInstaller builds the exe, so as to inject date/other infos into it.
|
||||||
|
*.manifest
|
||||||
|
*.spec
|
||||||
|
|
||||||
|
# Installer logs
|
||||||
|
pip-log.txt
|
||||||
|
pip-delete-this-directory.txt
|
||||||
|
|
||||||
|
# Unit test / coverage reports
|
||||||
|
htmlcov/
|
||||||
|
.tox/
|
||||||
|
.nox/
|
||||||
|
.coverage
|
||||||
|
.coverage.*
|
||||||
|
.cache
|
||||||
|
nosetests.xml
|
||||||
|
coverage.xml
|
||||||
|
*.cover
|
||||||
|
*.py,cover
|
||||||
|
.hypothesis/
|
||||||
|
.pytest_cache/
|
||||||
|
cover/
|
||||||
|
|
||||||
|
# Translations
|
||||||
|
*.mo
|
||||||
|
*.pot
|
||||||
|
|
||||||
|
# Django stuff:
|
||||||
|
*.log
|
||||||
|
local_settings.py
|
||||||
|
db.sqlite3
|
||||||
|
db.sqlite3-journal
|
||||||
|
|
||||||
|
# Flask stuff:
|
||||||
|
instance/
|
||||||
|
.webassets-cache
|
||||||
|
|
||||||
|
# Scrapy stuff:
|
||||||
|
.scrapy
|
||||||
|
|
||||||
|
# Sphinx documentation
|
||||||
|
docs/_build/
|
||||||
|
|
||||||
|
# PyBuilder
|
||||||
|
.pybuilder/
|
||||||
|
target/
|
||||||
|
|
||||||
|
# Jupyter Notebook
|
||||||
|
.ipynb_checkpoints
|
||||||
|
|
||||||
|
# IPython
|
||||||
|
profile_default/
|
||||||
|
ipython_config.py
|
||||||
|
|
||||||
|
# pyenv
|
||||||
|
# For a library or package, you might want to ignore these files since the code is
|
||||||
|
# intended to run in multiple environments; otherwise, check them in:
|
||||||
|
# .python-version
|
||||||
|
|
||||||
|
# pipenv
|
||||||
|
# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
|
||||||
|
# However, in case of collaboration, if having platform-specific dependencies or dependencies
|
||||||
|
# having no cross-platform support, pipenv may install dependencies that don't work, or not
|
||||||
|
# install all needed dependencies.
|
||||||
|
#Pipfile.lock
|
||||||
|
|
||||||
|
# PEP 582; used by e.g. github.com/David-OConnor/pyflow
|
||||||
|
__pypackages__/
|
||||||
|
|
||||||
|
# Celery stuff
|
||||||
|
celerybeat-schedule
|
||||||
|
celerybeat.pid
|
||||||
|
|
||||||
|
# SageMath parsed files
|
||||||
|
*.sage.py
|
||||||
|
|
||||||
|
# Environments
|
||||||
|
.env
|
||||||
|
.venv
|
||||||
|
env/
|
||||||
|
venv/
|
||||||
|
ENV/
|
||||||
|
env.bak/
|
||||||
|
venv.bak/
|
||||||
|
|
||||||
|
# Spyder project settings
|
||||||
|
.spyderproject
|
||||||
|
.spyproject
|
||||||
|
|
||||||
|
# Rope project settings
|
||||||
|
.ropeproject
|
||||||
|
|
||||||
|
# mkdocs documentation
|
||||||
|
/site
|
||||||
|
|
||||||
|
# mypy
|
||||||
|
.mypy_cache/
|
||||||
|
.dmypy.json
|
||||||
|
dmypy.json
|
||||||
|
|
||||||
|
# Pyre type checker
|
||||||
|
.pyre/
|
||||||
|
|
||||||
|
# pytype static type analyzer
|
||||||
|
.pytype/
|
||||||
|
|
||||||
|
# Cython debug symbols
|
||||||
|
cython_debug/
|
||||||
|
|
||||||
|
# ---> Vim
|
||||||
|
# Swap
|
||||||
|
[._]*.s[a-v][a-z]
|
||||||
|
!*.svg # comment out if you don't need vector files
|
||||||
|
[._]*.sw[a-p]
|
||||||
|
[._]s[a-rt-v][a-z]
|
||||||
|
[._]ss[a-gi-z]
|
||||||
|
[._]sw[a-p]
|
||||||
|
|
||||||
|
# Session
|
||||||
|
Session.vim
|
||||||
|
Sessionx.vim
|
||||||
|
|
||||||
|
# Temporary
|
||||||
|
.netrwhist
|
||||||
|
*~
|
||||||
|
# Auto-generated tag files
|
||||||
|
tags
|
||||||
|
# Persistent undo
|
||||||
|
[._]*.un~
|
||||||
|
|
||||||
|
# ---> Perl
|
||||||
|
!Build/
|
||||||
|
.last_cover_stats
|
||||||
|
/META.yml
|
||||||
|
/META.json
|
||||||
|
/MYMETA.*
|
||||||
|
*.o
|
||||||
|
*.pm.tdy
|
||||||
|
*.bs
|
||||||
|
|
||||||
|
# Devel::Cover
|
||||||
|
cover_db/
|
||||||
|
|
||||||
|
# Devel::NYTProf
|
||||||
|
nytprof.out
|
||||||
|
|
||||||
|
# Dizt::Zilla
|
||||||
|
/.build/
|
||||||
|
|
||||||
|
# Module::Build
|
||||||
|
_build/
|
||||||
|
Build
|
||||||
|
Build.bat
|
||||||
|
|
||||||
|
# Module::Install
|
||||||
|
inc/
|
||||||
|
|
||||||
|
# ExtUtils::MakeMaker
|
||||||
|
/blib/
|
||||||
|
/_eumm/
|
||||||
|
/*.gz
|
||||||
|
/Makefile
|
||||||
|
/Makefile.old
|
||||||
|
/MANIFEST.bak
|
||||||
|
/pm_to_blib
|
||||||
|
/*.zip
|
||||||
|
|
||||||
|
# ---> Perl6
|
||||||
|
# Gitignore for Perl 6 (http://www.perl6.org)
|
||||||
|
# As part of https://github.com/github/gitignore
|
||||||
|
|
||||||
|
# precompiled files
|
||||||
|
.precomp
|
||||||
|
lib/.precomp
|
||||||
|
|
||||||
|
|
||||||
|
|
319
LICENSE
Normal file
319
LICENSE
Normal file
|
@ -0,0 +1,319 @@
|
||||||
|
GNU GENERAL PUBLIC LICENSE
|
||||||
|
|
||||||
|
Version 2, June 1991
|
||||||
|
|
||||||
|
Copyright (C) 1989, 1991 Free Software Foundation, Inc.
|
||||||
|
|
||||||
|
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
||||||
|
|
||||||
|
Everyone is permitted to copy and distribute verbatim copies of this license
|
||||||
|
document, but changing it is not allowed.
|
||||||
|
|
||||||
|
Preamble
|
||||||
|
|
||||||
|
The licenses for most software are designed to take away your freedom to share
|
||||||
|
and change it. By contrast, the GNU General Public License is intended to
|
||||||
|
guarantee your freedom to share and change free software--to make sure the
|
||||||
|
software is free for all its users. This General Public License applies to
|
||||||
|
most of the Free Software Foundation's software and to any other program whose
|
||||||
|
authors commit to using it. (Some other Free Software Foundation software
|
||||||
|
is covered by the GNU Lesser General Public License instead.) You can apply
|
||||||
|
it to your programs, too.
|
||||||
|
|
||||||
|
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 this service 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.
|
||||||
|
|
||||||
|
To protect your rights, we need to make restrictions that forbid anyone to
|
||||||
|
deny you these rights or to ask you to surrender the rights. These restrictions
|
||||||
|
translate to certain responsibilities for you if you distribute copies of
|
||||||
|
the software, or if you modify it.
|
||||||
|
|
||||||
|
For example, if you distribute copies of such a program, whether gratis or
|
||||||
|
for a fee, you must give the recipients all the rights that you have. You
|
||||||
|
must make sure that they, too, receive or can get the source code. And you
|
||||||
|
must show them these terms so they know their rights.
|
||||||
|
|
||||||
|
We protect your rights with two steps: (1) copyright the software, and (2)
|
||||||
|
offer you this license which gives you legal permission to copy, distribute
|
||||||
|
and/or modify the software.
|
||||||
|
|
||||||
|
Also, for each author's protection and ours, we want to make certain that
|
||||||
|
everyone understands that there is no warranty for this free software. If
|
||||||
|
the software is modified by someone else and passed on, we want its recipients
|
||||||
|
to know that what they have is not the original, so that any problems introduced
|
||||||
|
by others will not reflect on the original authors' reputations.
|
||||||
|
|
||||||
|
Finally, any free program is threatened constantly by software patents. We
|
||||||
|
wish to avoid the danger that redistributors of a free program will individually
|
||||||
|
obtain patent licenses, in effect making the program proprietary. To prevent
|
||||||
|
this, we have made it clear that any patent must be licensed for everyone's
|
||||||
|
free use or not licensed at all.
|
||||||
|
|
||||||
|
The precise terms and conditions for copying, distribution and modification
|
||||||
|
follow.
|
||||||
|
|
||||||
|
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
||||||
|
|
||||||
|
0. This License applies to any program or other work which contains a notice
|
||||||
|
placed by the copyright holder saying it may be distributed under the terms
|
||||||
|
of this General Public License. The "Program", below, refers to any such program
|
||||||
|
or work, and a "work based on the Program" means either the Program or any
|
||||||
|
derivative work under copyright law: that is to say, a work containing the
|
||||||
|
Program or a portion of it, either verbatim or with modifications and/or translated
|
||||||
|
into another language. (Hereinafter, translation is included without limitation
|
||||||
|
in the term "modification".) Each licensee is addressed as "you".
|
||||||
|
|
||||||
|
Activities other than copying, distribution and modification are not covered
|
||||||
|
by this License; they are outside its scope. The act of running the Program
|
||||||
|
is not restricted, and the output from the Program is covered only if its
|
||||||
|
contents constitute a work based on the Program (independent of having been
|
||||||
|
made by running the Program). Whether that is true depends on what the Program
|
||||||
|
does.
|
||||||
|
|
||||||
|
1. You may copy and distribute 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 and disclaimer of warranty;
|
||||||
|
keep intact all the notices that refer to this License and to the absence
|
||||||
|
of any warranty; and give any other recipients of the Program a copy of this
|
||||||
|
License along with the Program.
|
||||||
|
|
||||||
|
You may charge a fee for the physical act of transferring a copy, and you
|
||||||
|
may at your option offer warranty protection in exchange for a fee.
|
||||||
|
|
||||||
|
2. You may modify your copy or copies of the Program or any portion of it,
|
||||||
|
thus forming a work based on the Program, and copy and distribute such modifications
|
||||||
|
or work under the terms of Section 1 above, provided that you also meet all
|
||||||
|
of these conditions:
|
||||||
|
|
||||||
|
a) You must cause the modified files to carry prominent notices stating that
|
||||||
|
you changed the files and the date of any change.
|
||||||
|
|
||||||
|
b) You must cause any work that you distribute or publish, that in whole or
|
||||||
|
in part contains or is derived from the Program or any part thereof, to be
|
||||||
|
licensed as a whole at no charge to all third parties under the terms of this
|
||||||
|
License.
|
||||||
|
|
||||||
|
c) If the modified program normally reads commands interactively when run,
|
||||||
|
you must cause it, when started running for such interactive use in the most
|
||||||
|
ordinary way, to print or display an announcement including an appropriate
|
||||||
|
copyright notice and a notice that there is no warranty (or else, saying that
|
||||||
|
you provide a warranty) and that users may redistribute the program under
|
||||||
|
these conditions, and telling the user how to view a copy of this License.
|
||||||
|
(Exception: if the Program itself is interactive but does not normally print
|
||||||
|
such an announcement, your work based on the Program is not required to print
|
||||||
|
an announcement.)
|
||||||
|
|
||||||
|
These requirements apply to the modified work as a whole. If identifiable
|
||||||
|
sections of that work are not derived from the Program, and can be reasonably
|
||||||
|
considered independent and separate works in themselves, then this License,
|
||||||
|
and its terms, do not apply to those sections when you distribute them as
|
||||||
|
separate works. But when you distribute the same sections as part of a whole
|
||||||
|
which is a work based on the Program, the distribution of the whole must be
|
||||||
|
on the terms of this License, whose permissions for other licensees extend
|
||||||
|
to the entire whole, and thus to each and every part regardless of who wrote
|
||||||
|
it.
|
||||||
|
|
||||||
|
Thus, it is not the intent of this section to claim rights or contest your
|
||||||
|
rights to work written entirely by you; rather, the intent is to exercise
|
||||||
|
the right to control the distribution of derivative or collective works based
|
||||||
|
on the Program.
|
||||||
|
|
||||||
|
In addition, mere aggregation of another work not based on the Program with
|
||||||
|
the Program (or with a work based on the Program) on a volume of a storage
|
||||||
|
or distribution medium does not bring the other work under the scope of this
|
||||||
|
License.
|
||||||
|
|
||||||
|
3. You may copy and distribute the Program (or a work based on it, under Section
|
||||||
|
2) in object code or executable form under the terms of Sections 1 and 2 above
|
||||||
|
provided that you also do one of the following:
|
||||||
|
|
||||||
|
a) Accompany it with the complete corresponding machine-readable source code,
|
||||||
|
which must be distributed under the terms of Sections 1 and 2 above on a medium
|
||||||
|
customarily used for software interchange; or,
|
||||||
|
|
||||||
|
b) Accompany it with a written offer, valid for at least three years, to give
|
||||||
|
any third party, for a charge no more than your cost of physically performing
|
||||||
|
source distribution, a complete machine-readable copy of the corresponding
|
||||||
|
source code, to be distributed under the terms of Sections 1 and 2 above on
|
||||||
|
a medium customarily used for software interchange; or,
|
||||||
|
|
||||||
|
c) Accompany it with the information you received as to the offer to distribute
|
||||||
|
corresponding source code. (This alternative is allowed only for noncommercial
|
||||||
|
distribution and only if you received the program in object code or executable
|
||||||
|
form with such an offer, in accord with Subsection b above.)
|
||||||
|
|
||||||
|
The source code for a work means the preferred form of the work for making
|
||||||
|
modifications to it. For an executable work, complete source code means all
|
||||||
|
the source code for all modules it contains, plus any associated interface
|
||||||
|
definition files, plus the scripts used to control compilation and installation
|
||||||
|
of the executable. However, as a special exception, the source code distributed
|
||||||
|
need not include anything that is normally distributed (in either source or
|
||||||
|
binary form) with the major components (compiler, kernel, and so on) of the
|
||||||
|
operating system on which the executable runs, unless that component itself
|
||||||
|
accompanies the executable.
|
||||||
|
|
||||||
|
If distribution of executable or object code is made by offering access to
|
||||||
|
copy from a designated place, then offering equivalent access to copy the
|
||||||
|
source code from the same place counts as distribution of the source code,
|
||||||
|
even though third parties are not compelled to copy the source along with
|
||||||
|
the object code.
|
||||||
|
|
||||||
|
4. You may not copy, modify, sublicense, or distribute the Program except
|
||||||
|
as expressly provided under this License. Any attempt otherwise to copy, modify,
|
||||||
|
sublicense or distribute the Program is void, and will automatically terminate
|
||||||
|
your rights under this License. However, parties who have received copies,
|
||||||
|
or rights, from you under this License will not have their licenses terminated
|
||||||
|
so long as such parties remain in full compliance.
|
||||||
|
|
||||||
|
5. You are not required to accept this License, since you have not signed
|
||||||
|
it. However, nothing else grants you permission to modify or distribute the
|
||||||
|
Program or its derivative works. These actions are prohibited by law if you
|
||||||
|
do not accept this License. Therefore, by modifying or distributing the Program
|
||||||
|
(or any work based on the Program), you indicate your acceptance of this License
|
||||||
|
to do so, and all its terms and conditions for copying, distributing or modifying
|
||||||
|
the Program or works based on it.
|
||||||
|
|
||||||
|
6. Each time you redistribute the Program (or any work based on the Program),
|
||||||
|
the recipient automatically receives a license from the original licensor
|
||||||
|
to copy, distribute or modify the Program subject to these terms and conditions.
|
||||||
|
You may not impose any further restrictions on the recipients' exercise of
|
||||||
|
the rights granted herein. You are not responsible for enforcing compliance
|
||||||
|
by third parties to this License.
|
||||||
|
|
||||||
|
7. If, as a consequence of a court judgment or allegation of patent infringement
|
||||||
|
or for any other reason (not limited to patent issues), 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 distribute so as to satisfy simultaneously your
|
||||||
|
obligations under this License and any other pertinent obligations, then as
|
||||||
|
a consequence you may not distribute the Program at all. For example, if a
|
||||||
|
patent license would not permit royalty-free redistribution of the Program
|
||||||
|
by all those who receive copies directly or indirectly through you, then the
|
||||||
|
only way you could satisfy both it and this License would be to refrain entirely
|
||||||
|
from distribution of the Program.
|
||||||
|
|
||||||
|
If any portion of this section is held invalid or unenforceable under any
|
||||||
|
particular circumstance, the balance of the section is intended to apply and
|
||||||
|
the section as a whole is intended to apply in other circumstances.
|
||||||
|
|
||||||
|
It is not the purpose of this section to induce you to infringe any patents
|
||||||
|
or other property right claims or to contest validity of any such claims;
|
||||||
|
this section has the sole purpose of protecting the integrity of the free
|
||||||
|
software distribution system, which is implemented by public license practices.
|
||||||
|
Many people have made generous contributions to the wide range of software
|
||||||
|
distributed through that system in reliance on consistent application of that
|
||||||
|
system; it is up to the author/donor to decide if he or she is willing to
|
||||||
|
distribute software through any other system and a licensee cannot impose
|
||||||
|
that choice.
|
||||||
|
|
||||||
|
This section is intended to make thoroughly clear what is believed to be a
|
||||||
|
consequence of the rest of this License.
|
||||||
|
|
||||||
|
8. If the distribution and/or use of the Program is restricted in certain
|
||||||
|
countries either by patents or by copyrighted interfaces, the original copyright
|
||||||
|
holder who places the Program under this License may add an explicit geographical
|
||||||
|
distribution limitation excluding those countries, so that distribution is
|
||||||
|
permitted only in or among countries not thus excluded. In such case, this
|
||||||
|
License incorporates the limitation as if written in the body of this License.
|
||||||
|
|
||||||
|
9. The Free Software Foundation may publish revised and/or new versions of
|
||||||
|
the 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
|
||||||
|
a version number of this License which applies to it and "any later version",
|
||||||
|
you have the option of following the terms and conditions either of that version
|
||||||
|
or of any later version published by the Free Software Foundation. If the
|
||||||
|
Program does not specify a version number of this License, you may choose
|
||||||
|
any version ever published by the Free Software Foundation.
|
||||||
|
|
||||||
|
10. If you wish to incorporate parts of the Program into other free programs
|
||||||
|
whose distribution conditions are different, write to the author to ask for
|
||||||
|
permission. For software which is copyrighted by the Free Software Foundation,
|
||||||
|
write to the Free Software Foundation; we sometimes make exceptions for this.
|
||||||
|
Our decision will be guided by the two goals of preserving the free status
|
||||||
|
of all derivatives of our free software and of promoting the sharing and reuse
|
||||||
|
of software generally.
|
||||||
|
|
||||||
|
NO WARRANTY
|
||||||
|
|
||||||
|
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, 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.
|
||||||
|
|
||||||
|
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
||||||
|
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE
|
||||||
|
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.
|
||||||
|
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 convey the exclusion
|
||||||
|
of warranty; and each file should have at least the "copyright" line and a
|
||||||
|
pointer to where the full notice is found.
|
||||||
|
|
||||||
|
<one line to give the program's name and an idea of what it does.>
|
||||||
|
|
||||||
|
Copyright (C) <yyyy> <name of author>
|
||||||
|
|
||||||
|
This program is free software; you can redistribute it and/or modify it under
|
||||||
|
the terms of the GNU General Public License as published by the Free Software
|
||||||
|
Foundation; either version 2 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 General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License along with
|
||||||
|
this program; if not, write to the Free Software Foundation, Inc., 51 Franklin
|
||||||
|
Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
|
||||||
|
Also add information on how to contact you by electronic and paper mail.
|
||||||
|
|
||||||
|
If the program is interactive, make it output a short notice like this when
|
||||||
|
it starts in an interactive mode:
|
||||||
|
|
||||||
|
Gnomovision version 69, Copyright (C) year name of author Gnomovision comes
|
||||||
|
with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software,
|
||||||
|
and you are welcome to redistribute it under certain conditions; type `show
|
||||||
|
c' for details.
|
||||||
|
|
||||||
|
The hypothetical commands `show w' and `show c' should show the appropriate
|
||||||
|
parts of the General Public License. Of course, the commands you use may be
|
||||||
|
called something other than `show w' and `show c'; they could even be mouse-clicks
|
||||||
|
or menu items--whatever suits your program.
|
||||||
|
|
||||||
|
You should also get your employer (if you work as a programmer) or your school,
|
||||||
|
if any, to sign a "copyright disclaimer" for the program, if necessary. Here
|
||||||
|
is a sample; alter the names:
|
||||||
|
|
||||||
|
Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision'
|
||||||
|
(which makes passes at compilers) written by James Hacker.
|
||||||
|
|
||||||
|
<signature of Ty Coon>, 1 April 1989 Ty Coon, President of Vice This General
|
||||||
|
Public License does not permit incorporating your program into proprietary
|
||||||
|
programs. If your program is a subroutine library, you may consider it more
|
||||||
|
useful to permit linking proprietary applications with the library. If this
|
||||||
|
is what you want to do, use the GNU Lesser General Public License instead
|
||||||
|
of this License.
|
6
MyMonPlugin/__init__.py
Normal file
6
MyMonPlugin/__init__.py
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
__version__ = '0.0.161124'
|
||||||
|
__all__ = ['MonitoringPlugin', 'SNMPMonitoringPlugin']
|
||||||
|
|
||||||
|
from .monitoringplugin import MonitoringPlugin
|
||||||
|
from .snmpmonitoringplugin import SNMPMonitoringPlugin
|
||||||
|
|
|
@ -1,11 +1,11 @@
|
||||||
#!/usr/bin/env python
|
#!/usr/bin/env python3
|
||||||
# -*- encoding: utf-8 -*-
|
# -*- encoding: utf-8 -*-
|
||||||
|
|
||||||
#####################################################################
|
#####################################################################
|
||||||
# (c) 2010-2011 by Sven Velt and team(ix) GmbH, Nuernberg, Germany #
|
# (c) 2010-2011 by Sven Velt and team(ix) GmbH, Nuernberg, Germany #
|
||||||
# sv@teamix.net #
|
# sv@teamix.net #
|
||||||
# (c) 2016 by Sven Velt, Germany #
|
# (c) 2016- by Sven Velt, Germany #
|
||||||
# sven-mymonplugins@velt.biz #
|
# sven-mymonplugins@velt.biz #
|
||||||
# #
|
# #
|
||||||
# This file is part of "velt.biz - My Monitoring Plugins" #
|
# This file is part of "velt.biz - My Monitoring Plugins" #
|
||||||
# a fork of "team(ix) Monitoring Plugins" in 2015 #
|
# a fork of "team(ix) Monitoring Plugins" in 2015 #
|
||||||
|
@ -25,15 +25,11 @@
|
||||||
# along with this file. If not, see <http://www.gnu.org/licenses/>. #
|
# along with this file. If not, see <http://www.gnu.org/licenses/>. #
|
||||||
#####################################################################
|
#####################################################################
|
||||||
|
|
||||||
__version__ = '0.0.161124'
|
import datetime
|
||||||
__all__ = ['MonitoringPlugin', 'SNMPMonitoringPlugin']
|
import optparse
|
||||||
|
import os
|
||||||
import datetime, optparse, os, re, sys
|
import re
|
||||||
|
import sys
|
||||||
try:
|
|
||||||
import netsnmp
|
|
||||||
except ImportError:
|
|
||||||
pass
|
|
||||||
|
|
||||||
class MonitoringPlugin(object):
|
class MonitoringPlugin(object):
|
||||||
|
|
||||||
|
@ -78,12 +74,47 @@ class MonitoringPlugin(object):
|
||||||
if self._cmdlineoptions_parsed:
|
if self._cmdlineoptions_parsed:
|
||||||
return
|
return
|
||||||
# self.__optparser.add_option('-V', '--version', action='version', help='show version number and exit')
|
# self.__optparser.add_option('-V', '--version', action='version', help='show version number and exit')
|
||||||
self.__optparser.add_option('-v', '--verbose', dest='verbose', help='Verbosity, more for more ;-)', action='count')
|
self.__optparser.add_option('-v', '--verbose', dest='verbose', help='Verbosity, more for more ;-)', default=0, action='count')
|
||||||
|
|
||||||
(self.options, self.args) = self.__optparser.parse_args()
|
(self.options, self.args) = self.__optparser.parse_args()
|
||||||
self._cmdlineoptions_parsed = True
|
self._cmdlineoptions_parsed = True
|
||||||
|
|
||||||
|
|
||||||
|
def args2checks(self):
|
||||||
|
checks = []
|
||||||
|
try:
|
||||||
|
separator = self.options.separator
|
||||||
|
except AttributeError:
|
||||||
|
separator = ','
|
||||||
|
|
||||||
|
try:
|
||||||
|
subseparator = self.options.subseparator
|
||||||
|
except AttributeError:
|
||||||
|
subseparator = '+'
|
||||||
|
|
||||||
|
for quad in self.args:
|
||||||
|
quad = quad.split(separator)
|
||||||
|
quad = (quad + ['', '', ''])[:4] # Fix length to 4, fill with ''
|
||||||
|
|
||||||
|
# Convert list of checks to list
|
||||||
|
if subseparator in quad[0]:
|
||||||
|
quad[0] = quad[0].split(subseparator)
|
||||||
|
else:
|
||||||
|
quad[0] = [quad[0],]
|
||||||
|
|
||||||
|
# Convert list of targets to list
|
||||||
|
if subseparator in quad[1]:
|
||||||
|
quad[1] = quad[1].split(subseparator)
|
||||||
|
else:
|
||||||
|
quad[1] = [quad[1],]
|
||||||
|
|
||||||
|
for target in quad[1]:
|
||||||
|
for check in quad[0]:
|
||||||
|
checks.append(tuple([check, target, quad[2], quad[3]]))
|
||||||
|
|
||||||
|
return(checks)
|
||||||
|
|
||||||
|
|
||||||
def range_to_limits(self, range):
|
def range_to_limits(self, range):
|
||||||
# Check if we must negate result
|
# Check if we must negate result
|
||||||
if len(range) > 0 and range[0] == '@':
|
if len(range) > 0 and range[0] == '@':
|
||||||
|
@ -302,7 +333,7 @@ class MonitoringPlugin(object):
|
||||||
|
|
||||||
|
|
||||||
def seconds_to_timedelta(self, seconds):
|
def seconds_to_timedelta(self, seconds):
|
||||||
return datetime.timedelta(seconds=long(seconds))
|
return datetime.timedelta(seconds=int(seconds))
|
||||||
|
|
||||||
|
|
||||||
def human_to_number(self, value, total=None, unit=['',]):
|
def human_to_number(self, value, total=None, unit=['',]):
|
||||||
|
@ -365,8 +396,8 @@ class MonitoringPlugin(object):
|
||||||
bol = 'V' + str(level) + ':' + ' ' * level
|
bol = 'V' + str(level) + ':' + ' ' * level
|
||||||
if prefix:
|
if prefix:
|
||||||
bol += '%s' % prefix
|
bol += '%s' % prefix
|
||||||
if type(output) in [str, unicode, ]:
|
if type(output) in [str, ]:
|
||||||
print(bol + output)
|
print(bol + output.lstrip().rstrip().replace('\n', '\n' + bol))
|
||||||
elif type(output) in [list, ]:
|
elif type(output) in [list, ]:
|
||||||
print('\n'.join( ['%s%s' % (bol, l) for l in output] ) )
|
print('\n'.join( ['%s%s' % (bol, l) for l in output] ) )
|
||||||
else:
|
else:
|
||||||
|
@ -423,273 +454,13 @@ class MonitoringPlugin(object):
|
||||||
|
|
||||||
# Exit program or return output line(s)
|
# Exit program or return output line(s)
|
||||||
if exit:
|
if exit:
|
||||||
print out
|
print(out)
|
||||||
sys.exit(returncode)
|
sys.exit(returncode)
|
||||||
else:
|
else:
|
||||||
return (returncode, out)
|
return (returncode, out)
|
||||||
|
|
||||||
##############################################################################
|
##############################################################################
|
||||||
|
|
||||||
class SNMPMonitoringPlugin(MonitoringPlugin):
|
|
||||||
|
|
||||||
def __init__(self, *args, **kwargs):
|
|
||||||
# Same as "MonitoringPlugin.__init__(*args, **kwargs)" but a little bit more flexible
|
|
||||||
#super(MonitoringPlugin, self).__init__(*args, **kwargs)
|
|
||||||
MonitoringPlugin.__init__(self, *args, **kwargs)
|
|
||||||
|
|
||||||
self.add_cmdlineoption('-H', '', 'host', 'Host to check', default='127.0.0.1')
|
|
||||||
self.add_cmdlineoption('-P', '', 'snmpversion', 'SNMP protocol version', metavar='1', default='1')
|
|
||||||
self.add_cmdlineoption('-C', '', 'snmpauth', 'SNMP v1/v2c community OR SNMP v3 quadruple', metavar='public', default='public')
|
|
||||||
self.add_cmdlineoption('', '--snmpcmdlinepath', 'snmpcmdlinepath', 'Path to "snmpget" and "snmpwalk"', metavar='/usr/bin/', default='/usr/bin')
|
|
||||||
# FIXME
|
|
||||||
self.add_cmdlineoption('', '--nonetsnmp', 'nonetsnmp', 'Do not use NET-SNMP python bindings', action='store_true')
|
|
||||||
# self.__optparser.add_option('', '--nonetsnmp', dest='nonetsnmp', help='Do not use NET-SNMP python bindings', action='store_true')
|
|
||||||
|
|
||||||
self.__SNMP_Cache = {}
|
|
||||||
|
|
||||||
self.__use_netsnmp = False
|
|
||||||
self.__prepared_snmp = False
|
|
||||||
|
|
||||||
|
|
||||||
def prepare_snmp(self):
|
|
||||||
if not self._cmdlineoptions_parsed:
|
|
||||||
self.parse_cmdlineoptions()
|
|
||||||
|
|
||||||
if not self.options.nonetsnmp:
|
|
||||||
try:
|
|
||||||
import netsnmp
|
|
||||||
self.__use_netsnmp = True
|
|
||||||
except ImportError:
|
|
||||||
pass
|
|
||||||
|
|
||||||
if self.__use_netsnmp:
|
|
||||||
self.verbose(1, 'Using NET-SNMP Python bindings')
|
|
||||||
|
|
||||||
self.SNMPGET_wrapper = self.__SNMPGET_netsnmp
|
|
||||||
self.SNMPWALK_wrapper = self.__SNMPWALK_netsnmp
|
|
||||||
|
|
||||||
if self.options.snmpversion == '2c':
|
|
||||||
self.options.snmpversion = '2'
|
|
||||||
|
|
||||||
else:
|
|
||||||
self.verbose(1, 'Using NET-SNMP command line tools')
|
|
||||||
|
|
||||||
self.SNMPGET_wrapper = self.__SNMPGET_cmdline
|
|
||||||
self.SNMPWALK_wrapper = self.__SNMPWALK_cmdline
|
|
||||||
|
|
||||||
# Building command lines
|
|
||||||
self.__CMDLINE_get = os.path.join(self.options.snmpcmdlinepath, 'snmpget') + ' -OqevtU '
|
|
||||||
self.__CMDLINE_walk = os.path.join(self.options.snmpcmdlinepath, 'snmpwalk') + ' -OqevtU '
|
|
||||||
|
|
||||||
if self.options.snmpversion in [1, 2, '1', '2', '2c']:
|
|
||||||
if self.options.snmpversion in [2, '2']:
|
|
||||||
self.options.snmpversion = '2c'
|
|
||||||
self.__CMDLINE_get += ' -v' + str(self.options.snmpversion) + ' -c' + self.options.snmpauth + ' '
|
|
||||||
self.__CMDLINE_walk += ' -v' + str(self.options.snmpversion) + ' -c' + self.options.snmpauth + ' '
|
|
||||||
elif options.snmpversion == [3, '3']:
|
|
||||||
# FIXME: Better error handling
|
|
||||||
try:
|
|
||||||
snmpauth = self.options.snmpauth.split(':')
|
|
||||||
self.__CMDLINE_get += ' -v3 -l' + snmpauth[0] + ' -u' + snmpauth[1] + ' -a' + snmpauth[2] + ' -A' + snmpauth[3] + ' '
|
|
||||||
self.__CMDLINE_walk += ' -v3 -l' + snmpauth[0] + ' -u' + snmpauth[1] + ' -a' + snmpauth[2] + ' -A' + snmpauth[3] + ' '
|
|
||||||
except:
|
|
||||||
self.back2nagios(3, 'Could not build SNMPv3 command line, need "SecLevel:SecName:AuthProtocol:AuthKey"')
|
|
||||||
else:
|
|
||||||
self.back2nagios(3, 'Unknown SNMP version "' + str(self.options.snmpversion) + '"')
|
|
||||||
|
|
||||||
self.__CMDLINE_get += ' ' + self.options.host + ' %s 2>/dev/null'
|
|
||||||
self.__CMDLINE_walk += ' ' + self.options.host + ' %s 2>/dev/null'
|
|
||||||
|
|
||||||
self.verbose(3, 'Using commandline: ' + self.__CMDLINE_get)
|
|
||||||
self.verbose(3, 'Using commandline: ' + self.__CMDLINE_walk)
|
|
||||||
|
|
||||||
# Test if snmp(get|walk) are executable
|
|
||||||
for fpath in [self.__CMDLINE_get, self.__CMDLINE_walk,]:
|
|
||||||
fpath = fpath.split(' ',1)[0]
|
|
||||||
if not( os.path.exists(fpath) and os.path.isfile(fpath) and os.access(fpath, os.X_OK) ):
|
|
||||||
self.back2nagios(3, 'Could not execute "%s"' % fpath)
|
|
||||||
|
|
||||||
self.__prepared_snmp = True
|
|
||||||
|
|
||||||
|
|
||||||
def find_index_for_value(self, list_indexes, list_values, wanted):
|
|
||||||
self.verbose(2, 'Look for "' + str(wanted) + '"')
|
|
||||||
|
|
||||||
index = None
|
|
||||||
|
|
||||||
if len(list_indexes) != len(list_values):
|
|
||||||
self.verbose(1, 'Length of index and value lists do not match!')
|
|
||||||
return None
|
|
||||||
|
|
||||||
try:
|
|
||||||
index = list_values.index(wanted)
|
|
||||||
index = list_indexes[index]
|
|
||||||
except ValueError:
|
|
||||||
pass
|
|
||||||
|
|
||||||
if index:
|
|
||||||
self.verbose(2, 'Found "' + str(wanted) +'" with index "' + str(index) + '"')
|
|
||||||
else:
|
|
||||||
self.verbose(2, 'Nothing found!')
|
|
||||||
|
|
||||||
return index
|
|
||||||
|
|
||||||
|
|
||||||
def find_in_table(self, oid_index, oid_values, wanted):
|
|
||||||
self.verbose(2, 'Look for "' + str(wanted) + '" in "' + str(oid_values) +'"')
|
|
||||||
|
|
||||||
index = None
|
|
||||||
indexes = list(self.SNMPWALK(oid_index))
|
|
||||||
values = list(self.SNMPWALK(oid_values))
|
|
||||||
|
|
||||||
if len(indexes) != len(values):
|
|
||||||
self.back2nagios(3, 'Different data from 2 SNMP Walks!')
|
|
||||||
|
|
||||||
return self.find_index_for_value(indexes, values, wanted)
|
|
||||||
|
|
||||||
|
|
||||||
def SNMPGET(self, baseoid, idx=None, exitonerror=True):
|
|
||||||
if type(baseoid) in (list, tuple):
|
|
||||||
if idx not in ['', None]:
|
|
||||||
idx = '.' + str(idx)
|
|
||||||
else:
|
|
||||||
idx = ''
|
|
||||||
|
|
||||||
if self.options.snmpversion in [1, '1']:
|
|
||||||
value_low = long(self.SNMPGET_wrapper(baseoid[1] + idx, exitonerror=exitonerror))
|
|
||||||
if value_low < 0L:
|
|
||||||
value_low += 2 ** 32
|
|
||||||
|
|
||||||
value_hi = long(self.SNMPGET_wrapper(baseoid[2] + idx, exitonerror=exitonerror))
|
|
||||||
if value_hi < 0L:
|
|
||||||
value_hi += 2 ** 32
|
|
||||||
|
|
||||||
return value_hi * 2L ** 32L + value_low
|
|
||||||
|
|
||||||
elif self.options.snmpversion in [2, 3, '2', '2c', '3']:
|
|
||||||
return long(self.SNMPGET_wrapper(baseoid[0] + idx, exitonerror=exitonerror))
|
|
||||||
|
|
||||||
elif type(baseoid) in (str, ) and idx != None:
|
|
||||||
return self.SNMPGET_wrapper(baseoid + '.' + str(idx), exitonerror=exitonerror)
|
|
||||||
else:
|
|
||||||
return self.SNMPGET_wrapper(baseoid, exitonerror=exitonerror)
|
|
||||||
|
|
||||||
|
|
||||||
def SNMPWALK(self, baseoid, exitonerror=True):
|
|
||||||
return self.SNMPWALK_wrapper(baseoid, exitonerror=exitonerror)
|
|
||||||
|
|
||||||
|
|
||||||
def __SNMPGET_netsnmp(self, oid, exitonerror=True):
|
|
||||||
if not self.__prepared_snmp:
|
|
||||||
self.prepare_snmp()
|
|
||||||
|
|
||||||
if oid in self.__SNMP_Cache:
|
|
||||||
self.verbose(2, "%40s -> (CACHED) %s" % (oid, self.__SNMP_Cache[oid]))
|
|
||||||
return self.__SNMP_Cache[oid]
|
|
||||||
|
|
||||||
result = netsnmp.snmpget(oid, Version=int(self.options.snmpversion), DestHost=self.options.host, Community=self.options.snmpauth)[0]
|
|
||||||
|
|
||||||
if not result:
|
|
||||||
if exitonerror:
|
|
||||||
self.back2nagios(3, 'Timeout or no answer from "%s" looking for "%s"' % (self.options.host, oid))
|
|
||||||
else:
|
|
||||||
return None
|
|
||||||
|
|
||||||
self.__SNMP_Cache[oid] = result
|
|
||||||
|
|
||||||
self.verbose(2, "%40s -> %s" % (oid, result))
|
|
||||||
return result
|
|
||||||
|
|
||||||
|
|
||||||
def __SNMPWALK_netsnmp(self, oid, exitonerror=True):
|
|
||||||
if not self.__prepared_snmp:
|
|
||||||
self.prepare_snmp()
|
|
||||||
|
|
||||||
if oid in self.__SNMP_Cache:
|
|
||||||
self.verbose(2, "%40s -> (CACHED) %s" % (oid, self.__SNMP_Cache[oid]))
|
|
||||||
return self.__SNMP_Cache[oid]
|
|
||||||
|
|
||||||
result = netsnmp.snmpwalk(oid, Version=int(self.options.snmpversion), DestHost=self.options.host, Community=self.options.snmpauth)
|
|
||||||
|
|
||||||
if not result:
|
|
||||||
if exitonerror:
|
|
||||||
self.back2nagios(3, 'Timeout or no answer from "%s" looking for "%s"' % (self.options.host, oid))
|
|
||||||
else:
|
|
||||||
return None
|
|
||||||
|
|
||||||
self.__SNMP_Cache[oid] = result
|
|
||||||
|
|
||||||
self.verbose(2, "%40s -> %s" % (oid, result))
|
|
||||||
return result
|
|
||||||
|
|
||||||
|
|
||||||
def __SNMPGET_cmdline(self, oid, exitonerror=True):
|
|
||||||
if not self.__prepared_snmp:
|
|
||||||
self.prepare_snmp()
|
|
||||||
|
|
||||||
cmdline = self.__CMDLINE_get % oid
|
|
||||||
self.verbose(2, cmdline)
|
|
||||||
|
|
||||||
if oid in self.__SNMP_Cache:
|
|
||||||
self.verbose(2, "(CACHED) %s" % (self.__SNMP_Cache[oid]))
|
|
||||||
return self.__SNMP_Cache[oid]
|
|
||||||
|
|
||||||
cmd = os.popen(cmdline)
|
|
||||||
out = cmd.readline().rstrip().replace('"','')
|
|
||||||
retcode = cmd.close()
|
|
||||||
|
|
||||||
if retcode:
|
|
||||||
if not exitonerror:
|
|
||||||
return None
|
|
||||||
if retcode == 256:
|
|
||||||
self.back2nagios(3, 'Timeout - no SNMP answer from "' + self.options.host + '"')
|
|
||||||
elif retcode ==512:
|
|
||||||
self.back2nagios(3, 'OID "' + oid + '" not found')
|
|
||||||
else:
|
|
||||||
self.back2nagios(3, 'Unknown error code "' + str(retcode) + '" from command line utils')
|
|
||||||
|
|
||||||
self.__SNMP_Cache[oid] = out
|
|
||||||
|
|
||||||
self.verbose(1, out)
|
|
||||||
return out
|
|
||||||
|
|
||||||
|
|
||||||
def __SNMPWALK_cmdline(self, oid, exitonerror=True):
|
|
||||||
if not self.__prepared_snmp:
|
|
||||||
self.prepare_snmp()
|
|
||||||
|
|
||||||
cmdline = self.__CMDLINE_walk % oid
|
|
||||||
self.verbose(2, cmdline)
|
|
||||||
|
|
||||||
if oid in self.__SNMP_Cache:
|
|
||||||
self.verbose(2, "(CACHED) %s" % (self.__SNMP_Cache[oid]))
|
|
||||||
return self.__SNMP_Cache[oid]
|
|
||||||
|
|
||||||
cmd = os.popen(cmdline)
|
|
||||||
out = cmd.readlines()
|
|
||||||
retcode = cmd.close()
|
|
||||||
|
|
||||||
if retcode:
|
|
||||||
if not exitonerror:
|
|
||||||
return None
|
|
||||||
if retcode == 256:
|
|
||||||
self.back2nagios(3, 'Timeout - no SNMP answer from "' + self.options.host + '"')
|
|
||||||
elif retcode ==512:
|
|
||||||
self.back2nagios(3, 'OID "' + oid + '" not found')
|
|
||||||
else:
|
|
||||||
self.back2nagios(3, 'Unknown error code "' + str(retcode) + '" from command line utils')
|
|
||||||
|
|
||||||
for line in range(0,len(out)):
|
|
||||||
out[line] = out[line].rstrip().replace('"','')
|
|
||||||
|
|
||||||
self.__SNMP_Cache[oid] = out
|
|
||||||
|
|
||||||
self.verbose(1, str(out))
|
|
||||||
return out
|
|
||||||
|
|
||||||
|
|
||||||
##############################################################################
|
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
myplugin = MonitoringPlugin(pluginname='check_testplugin', tagforstatusline='TEST')
|
myplugin = MonitoringPlugin(pluginname='check_testplugin', tagforstatusline='TEST')
|
||||||
|
|
||||||
|
@ -703,14 +474,14 @@ def main():
|
||||||
pprint(myplugin.back2nagios(3, 'Nr. 13: Exit Code UNKNOWN', exit=False) )
|
pprint(myplugin.back2nagios(3, 'Nr. 13: Exit Code UNKNOWN', exit=False) )
|
||||||
|
|
||||||
ret = myplugin.back2nagios(0, 'Nr. 20: Plugin with string-based multiline output', 'Line 2\nLine 3\nLine4', exit=False)
|
ret = myplugin.back2nagios(0, 'Nr. 20: Plugin with string-based multiline output', 'Line 2\nLine 3\nLine4', exit=False)
|
||||||
print ret[1]
|
print(ret[1])
|
||||||
print 'Returncode: ' + str(ret[0])
|
print('Returncode: ' + str(ret[0]))
|
||||||
ret = myplugin.back2nagios(0, 'Nr. 21: Plugin with list-based multiline output', ['Line 2', 'Line 3', 'Line4'], exit=False)
|
ret = myplugin.back2nagios(0, 'Nr. 21: Plugin with list-based multiline output', ['Line 2', 'Line 3', 'Line4'], exit=False)
|
||||||
print ret[1]
|
print(ret[1])
|
||||||
print 'Returncode: ' + str(ret[0])
|
print('Returncode: ' + str(ret[0]))
|
||||||
ret = myplugin.back2nagios(0, 'Nr. 22: Plugin with tuple-based multiline output', ('Line 2', 'Line 3', 'Line4'), exit=False)
|
ret = myplugin.back2nagios(0, 'Nr. 22: Plugin with tuple-based multiline output', ('Line 2', 'Line 3', 'Line4'), exit=False)
|
||||||
print ret[1]
|
print(ret[1])
|
||||||
print 'Returncode: ' + str(ret[0])
|
print('Returncode: ' + str(ret[0]))
|
||||||
|
|
||||||
myplugin.add_performancedata('Val1', 42, '')
|
myplugin.add_performancedata('Val1', 42, '')
|
||||||
myplugin.add_performancedata('Val2', 23, 'c', warn=10, crit=20, min=0, max=100)
|
myplugin.add_performancedata('Val2', 23, 'c', warn=10, crit=20, min=0, max=100)
|
||||||
|
@ -723,4 +494,4 @@ def main():
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
main()
|
main()
|
||||||
|
|
||||||
#vim: ts=4 sw=4
|
#vim: ts=4 sw=4 sts=4
|
289
MyMonPlugin/snmpmonitoringplugin.py
Normal file
289
MyMonPlugin/snmpmonitoringplugin.py
Normal file
|
@ -0,0 +1,289 @@
|
||||||
|
#!/usr/bin/env python3
|
||||||
|
# -*- encoding: utf-8 -*-
|
||||||
|
|
||||||
|
#####################################################################
|
||||||
|
# (c) 2010-2011 by Sven Velt and team(ix) GmbH, Nuernberg, Germany #
|
||||||
|
# sv@teamix.net #
|
||||||
|
# (c) 2016- by Sven Velt, Germany #
|
||||||
|
# sven-mymonplugins@velt.biz #
|
||||||
|
# #
|
||||||
|
# This file is part of "velt.biz - My Monitoring Plugins" #
|
||||||
|
# a fork of "team(ix) Monitoring Plugins" in 2015 #
|
||||||
|
# URL: https://gogs.velt.biz/velt.biz/MyMonPlugins/ #
|
||||||
|
# #
|
||||||
|
# This file is free software: you can redistribute it and/or modify #
|
||||||
|
# it under the terms of the GNU General Public License as published #
|
||||||
|
# by the Free Software Foundation, either version 2 of the License, #
|
||||||
|
# or (at your option) any later version. #
|
||||||
|
# #
|
||||||
|
# This file 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 General Public License for more details. #
|
||||||
|
# #
|
||||||
|
# You should have received a copy of the GNU General Public License #
|
||||||
|
# along with this file. If not, see <http://www.gnu.org/licenses/>. #
|
||||||
|
#####################################################################
|
||||||
|
|
||||||
|
from .monitoringplugin import MonitoringPlugin
|
||||||
|
|
||||||
|
import os
|
||||||
|
|
||||||
|
class SNMPMonitoringPlugin(MonitoringPlugin):
|
||||||
|
|
||||||
|
def __init__(self, *args, **kwargs):
|
||||||
|
# Same as "MonitoringPlugin.__init__(*args, **kwargs)" but a little bit more flexible
|
||||||
|
#super(MonitoringPlugin, self).__init__(*args, **kwargs)
|
||||||
|
MonitoringPlugin.__init__(self, *args, **kwargs)
|
||||||
|
|
||||||
|
self.add_cmdlineoption('-H', '', 'host', 'Host to check', default='127.0.0.1')
|
||||||
|
self.add_cmdlineoption('-P', '', 'snmpversion', 'SNMP protocol version', metavar='1', default='1')
|
||||||
|
self.add_cmdlineoption('-C', '', 'snmpauth', 'SNMP v1/v2c community OR SNMP v3 quadruple', metavar='public', default='public')
|
||||||
|
self.add_cmdlineoption('', '--snmpcmdlinepath', 'snmpcmdlinepath', 'Path to "snmpget" and "snmpwalk"', metavar='/usr/bin/', default='/usr/bin')
|
||||||
|
# FIXME
|
||||||
|
self.add_cmdlineoption('', '--nonetsnmp', 'nonetsnmp', 'Do not use NET-SNMP python bindings', action='store_true')
|
||||||
|
# self.__optparser.add_option('', '--nonetsnmp', dest='nonetsnmp', help='Do not use NET-SNMP python bindings', action='store_true')
|
||||||
|
|
||||||
|
self.__SNMP_Cache = {}
|
||||||
|
|
||||||
|
self.__use_netsnmp = False
|
||||||
|
self.__prepared_snmp = False
|
||||||
|
|
||||||
|
|
||||||
|
def prepare_snmp(self):
|
||||||
|
if not self._cmdlineoptions_parsed:
|
||||||
|
self.parse_cmdlineoptions()
|
||||||
|
|
||||||
|
if not self.options.nonetsnmp:
|
||||||
|
try:
|
||||||
|
import netsnmp
|
||||||
|
self.__use_netsnmp = True
|
||||||
|
except ImportError:
|
||||||
|
pass
|
||||||
|
|
||||||
|
if self.__use_netsnmp:
|
||||||
|
self.verbose(1, 'Using NET-SNMP Python bindings')
|
||||||
|
|
||||||
|
self.SNMPGET_wrapper = self.__SNMPGET_netsnmp
|
||||||
|
self.SNMPWALK_wrapper = self.__SNMPWALK_netsnmp
|
||||||
|
|
||||||
|
if self.options.snmpversion == '2c':
|
||||||
|
self.options.snmpversion = '2'
|
||||||
|
|
||||||
|
else:
|
||||||
|
self.verbose(1, 'Using NET-SNMP command line tools')
|
||||||
|
|
||||||
|
self.SNMPGET_wrapper = self.__SNMPGET_cmdline
|
||||||
|
self.SNMPWALK_wrapper = self.__SNMPWALK_cmdline
|
||||||
|
|
||||||
|
# Building command lines
|
||||||
|
self.__CMDLINE_get = os.path.join(self.options.snmpcmdlinepath, 'snmpget') + ' -OqevtU '
|
||||||
|
self.__CMDLINE_walk = os.path.join(self.options.snmpcmdlinepath, 'snmpwalk') + ' -OqevtU '
|
||||||
|
|
||||||
|
if self.options.snmpversion in [1, 2, '1', '2', '2c']:
|
||||||
|
if self.options.snmpversion in [2, '2']:
|
||||||
|
self.options.snmpversion = '2c'
|
||||||
|
self.__CMDLINE_get += ' -v' + str(self.options.snmpversion) + ' -c' + self.options.snmpauth + ' '
|
||||||
|
self.__CMDLINE_walk += ' -v' + str(self.options.snmpversion) + ' -c' + self.options.snmpauth + ' '
|
||||||
|
elif options.snmpversion == [3, '3']:
|
||||||
|
# FIXME: Better error handling
|
||||||
|
try:
|
||||||
|
snmpauth = self.options.snmpauth.split(':')
|
||||||
|
self.__CMDLINE_get += ' -v3 -l' + snmpauth[0] + ' -u' + snmpauth[1] + ' -a' + snmpauth[2] + ' -A' + snmpauth[3] + ' '
|
||||||
|
self.__CMDLINE_walk += ' -v3 -l' + snmpauth[0] + ' -u' + snmpauth[1] + ' -a' + snmpauth[2] + ' -A' + snmpauth[3] + ' '
|
||||||
|
except:
|
||||||
|
self.back2nagios(3, 'Could not build SNMPv3 command line, need "SecLevel:SecName:AuthProtocol:AuthKey"')
|
||||||
|
else:
|
||||||
|
self.back2nagios(3, 'Unknown SNMP version "' + str(self.options.snmpversion) + '"')
|
||||||
|
|
||||||
|
self.__CMDLINE_get += ' ' + self.options.host + ' %s 2>/dev/null'
|
||||||
|
self.__CMDLINE_walk += ' ' + self.options.host + ' %s 2>/dev/null'
|
||||||
|
|
||||||
|
self.verbose(3, 'Using commandline: ' + self.__CMDLINE_get)
|
||||||
|
self.verbose(3, 'Using commandline: ' + self.__CMDLINE_walk)
|
||||||
|
|
||||||
|
# Test if snmp(get|walk) are executable
|
||||||
|
for fpath in [self.__CMDLINE_get, self.__CMDLINE_walk,]:
|
||||||
|
fpath = fpath.split(' ',1)[0]
|
||||||
|
if not( os.path.exists(fpath) and os.path.isfile(fpath) and os.access(fpath, os.X_OK) ):
|
||||||
|
self.back2nagios(3, 'Could not execute "%s"' % fpath)
|
||||||
|
|
||||||
|
self.__prepared_snmp = True
|
||||||
|
|
||||||
|
|
||||||
|
def find_index_for_value(self, list_indexes, list_values, wanted):
|
||||||
|
self.verbose(2, 'Look for "' + str(wanted) + '"')
|
||||||
|
|
||||||
|
index = None
|
||||||
|
|
||||||
|
if len(list_indexes) != len(list_values):
|
||||||
|
self.verbose(1, 'Length of index and value lists do not match!')
|
||||||
|
return None
|
||||||
|
|
||||||
|
try:
|
||||||
|
index = list_values.index(wanted)
|
||||||
|
index = list_indexes[index]
|
||||||
|
except ValueError:
|
||||||
|
pass
|
||||||
|
|
||||||
|
if index:
|
||||||
|
self.verbose(2, 'Found "' + str(wanted) +'" with index "' + str(index) + '"')
|
||||||
|
else:
|
||||||
|
self.verbose(2, 'Nothing found!')
|
||||||
|
|
||||||
|
return index
|
||||||
|
|
||||||
|
|
||||||
|
def find_in_table(self, oid_index, oid_values, wanted):
|
||||||
|
self.verbose(2, 'Look for "' + str(wanted) + '" in "' + str(oid_values) +'"')
|
||||||
|
|
||||||
|
index = None
|
||||||
|
indexes = list(self.SNMPWALK(oid_index))
|
||||||
|
values = list(self.SNMPWALK(oid_values))
|
||||||
|
|
||||||
|
if len(indexes) != len(values):
|
||||||
|
self.back2nagios(3, 'Different data from 2 SNMP Walks!')
|
||||||
|
|
||||||
|
return self.find_index_for_value(indexes, values, wanted)
|
||||||
|
|
||||||
|
|
||||||
|
def SNMPGET(self, baseoid, idx=None, exitonerror=True):
|
||||||
|
if type(baseoid) in (list, tuple):
|
||||||
|
if idx not in ['', None]:
|
||||||
|
idx = '.' + str(idx)
|
||||||
|
else:
|
||||||
|
idx = ''
|
||||||
|
|
||||||
|
if self.options.snmpversion in [1, '1']:
|
||||||
|
value_low = int(self.SNMPGET_wrapper(baseoid[1] + idx, exitonerror=exitonerror))
|
||||||
|
if value_low < 0:
|
||||||
|
value_low += 2 ** 32
|
||||||
|
|
||||||
|
value_hi = int(self.SNMPGET_wrapper(baseoid[2] + idx, exitonerror=exitonerror))
|
||||||
|
if value_hi < 0:
|
||||||
|
value_hi += 2 ** 32
|
||||||
|
|
||||||
|
return value_hi * 2 ** 32 + value_low
|
||||||
|
|
||||||
|
elif self.options.snmpversion in [2, 3, '2', '2c', '3']:
|
||||||
|
return int(self.SNMPGET_wrapper(baseoid[0] + idx, exitonerror=exitonerror))
|
||||||
|
|
||||||
|
elif type(baseoid) in (str, ) and idx != None:
|
||||||
|
return self.SNMPGET_wrapper(baseoid + '.' + str(idx), exitonerror=exitonerror)
|
||||||
|
else:
|
||||||
|
return self.SNMPGET_wrapper(baseoid, exitonerror=exitonerror)
|
||||||
|
|
||||||
|
|
||||||
|
def SNMPWALK(self, baseoid, exitonerror=True):
|
||||||
|
return self.SNMPWALK_wrapper(baseoid, exitonerror=exitonerror)
|
||||||
|
|
||||||
|
|
||||||
|
def __SNMPGET_netsnmp(self, oid, exitonerror=True):
|
||||||
|
if not self.__prepared_snmp:
|
||||||
|
self.prepare_snmp()
|
||||||
|
|
||||||
|
if oid in self.__SNMP_Cache:
|
||||||
|
self.verbose(2, "%40s -> (CACHED) %s" % (oid, self.__SNMP_Cache[oid]))
|
||||||
|
return self.__SNMP_Cache[oid]
|
||||||
|
|
||||||
|
result = netsnmp.snmpget(oid, Version=int(self.options.snmpversion), DestHost=self.options.host, Community=self.options.snmpauth)[0]
|
||||||
|
|
||||||
|
if not result:
|
||||||
|
if exitonerror:
|
||||||
|
self.back2nagios(3, 'Timeout or no answer from "%s" looking for "%s"' % (self.options.host, oid))
|
||||||
|
else:
|
||||||
|
return None
|
||||||
|
|
||||||
|
self.__SNMP_Cache[oid] = result
|
||||||
|
|
||||||
|
self.verbose(2, "%40s -> %s" % (oid, result))
|
||||||
|
return result
|
||||||
|
|
||||||
|
|
||||||
|
def __SNMPWALK_netsnmp(self, oid, exitonerror=True):
|
||||||
|
if not self.__prepared_snmp:
|
||||||
|
self.prepare_snmp()
|
||||||
|
|
||||||
|
if oid in self.__SNMP_Cache:
|
||||||
|
self.verbose(2, "%40s -> (CACHED) %s" % (oid, self.__SNMP_Cache[oid]))
|
||||||
|
return self.__SNMP_Cache[oid]
|
||||||
|
|
||||||
|
result = netsnmp.snmpwalk(oid, Version=int(self.options.snmpversion), DestHost=self.options.host, Community=self.options.snmpauth)
|
||||||
|
|
||||||
|
if not result:
|
||||||
|
if exitonerror:
|
||||||
|
self.back2nagios(3, 'Timeout or no answer from "%s" looking for "%s"' % (self.options.host, oid))
|
||||||
|
else:
|
||||||
|
return None
|
||||||
|
|
||||||
|
self.__SNMP_Cache[oid] = result
|
||||||
|
|
||||||
|
self.verbose(2, "%40s -> %s" % (oid, result))
|
||||||
|
return result
|
||||||
|
|
||||||
|
|
||||||
|
def __SNMPGET_cmdline(self, oid, exitonerror=True):
|
||||||
|
if not self.__prepared_snmp:
|
||||||
|
self.prepare_snmp()
|
||||||
|
|
||||||
|
cmdline = self.__CMDLINE_get % oid
|
||||||
|
self.verbose(2, cmdline)
|
||||||
|
|
||||||
|
if oid in self.__SNMP_Cache:
|
||||||
|
self.verbose(2, "(CACHED) %s" % (self.__SNMP_Cache[oid]))
|
||||||
|
return self.__SNMP_Cache[oid]
|
||||||
|
|
||||||
|
cmd = os.popen(cmdline)
|
||||||
|
out = cmd.readline().rstrip().replace('"','')
|
||||||
|
retcode = cmd.close()
|
||||||
|
|
||||||
|
if retcode:
|
||||||
|
if not exitonerror:
|
||||||
|
return None
|
||||||
|
if retcode == 256:
|
||||||
|
self.back2nagios(3, 'Timeout - no SNMP answer from "' + self.options.host + '"')
|
||||||
|
elif retcode ==512:
|
||||||
|
self.back2nagios(3, 'OID "' + oid + '" not found')
|
||||||
|
else:
|
||||||
|
self.back2nagios(3, 'Unknown error code "' + str(retcode) + '" from command line utils')
|
||||||
|
|
||||||
|
self.__SNMP_Cache[oid] = out
|
||||||
|
|
||||||
|
self.verbose(1, out)
|
||||||
|
return out
|
||||||
|
|
||||||
|
|
||||||
|
def __SNMPWALK_cmdline(self, oid, exitonerror=True):
|
||||||
|
if not self.__prepared_snmp:
|
||||||
|
self.prepare_snmp()
|
||||||
|
|
||||||
|
cmdline = self.__CMDLINE_walk % oid
|
||||||
|
self.verbose(2, cmdline)
|
||||||
|
|
||||||
|
if oid in self.__SNMP_Cache:
|
||||||
|
self.verbose(2, "(CACHED) %s" % (self.__SNMP_Cache[oid]))
|
||||||
|
return self.__SNMP_Cache[oid]
|
||||||
|
|
||||||
|
cmd = os.popen(cmdline)
|
||||||
|
out = cmd.readlines()
|
||||||
|
retcode = cmd.close()
|
||||||
|
|
||||||
|
if retcode:
|
||||||
|
if not exitonerror:
|
||||||
|
return None
|
||||||
|
if retcode == 256:
|
||||||
|
self.back2nagios(3, 'Timeout - no SNMP answer from "' + self.options.host + '"')
|
||||||
|
elif retcode ==512:
|
||||||
|
self.back2nagios(3, 'OID "' + oid + '" not found')
|
||||||
|
else:
|
||||||
|
self.back2nagios(3, 'Unknown error code "' + str(retcode) + '" from command line utils')
|
||||||
|
|
||||||
|
for line in range(0,len(out)):
|
||||||
|
out[line] = out[line].rstrip().replace('"','')
|
||||||
|
|
||||||
|
self.__SNMP_Cache[oid] = out
|
||||||
|
|
||||||
|
self.verbose(1, str(out))
|
||||||
|
return out
|
||||||
|
|
||||||
|
|
28
README.md
28
README.md
|
@ -1,30 +1,16 @@
|
||||||
MyMonPlugins
|
# MyMonPlugins
|
||||||
|
|
||||||
This is the old master branch! New development takes place in the "main" branch!
|
Python modules to simplify complex Naemon/Icinga/Nagios plugin development
|
||||||
|
|
||||||
Default branch will change in the near future.
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
(c) 2010-2011 by Sven Velt and team(ix) GmbH, Nuernberg, Germany
|
(c) 2010-2011 by Sven Velt and team(ix) GmbH, Nuernberg, Germany
|
||||||
sv@teamix.net
|
sv@teamix.net
|
||||||
(c) 2016 by Sven Velt, Germany
|
(c) 2016-2020 by Sven Velt, Germany
|
||||||
sven-mymonplugins@velt.biz
|
sven-mymonplugins@velt.biz
|
||||||
|
|
||||||
This file is part of "velt.biz - My Monitoring Plugins"
|
"velt.biz - My Monitoring Plugins" is a fork of "team(ix) Monitoring Plugins" in
|
||||||
a fork of "team(ix) Monitoring Plugins" in 2015
|
2015
|
||||||
URL: https://gogs.velt.biz/velt.biz/MyMonPlugins/
|
|
||||||
|
|
||||||
This file is free software: you can redistribute it and/or modify
|
URL: https://git.velt.biz/Monitoring/MyMonPlugins/
|
||||||
it under the terms of the GNU General Public License as published
|
|
||||||
by the Free Software Foundation, either version 2 of the License,
|
|
||||||
or (at your option) any later version.
|
|
||||||
|
|
||||||
This file 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 General Public License for more details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU General Public License
|
|
||||||
along with this file. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
|
|
254
check_apaches.py
254
check_apaches.py
|
@ -1,11 +1,11 @@
|
||||||
#!/usr/bin/env python
|
#!/usr/bin/env python3
|
||||||
# -*- encoding: utf-8 -*-
|
# -*- encoding: utf-8 -*-
|
||||||
|
|
||||||
#####################################################################
|
#####################################################################
|
||||||
# (c) 2007-2011 by Sven Velt and team(ix) GmbH, Nuernberg, Germany #
|
# (c) 2007-2011 by Sven Velt and team(ix) GmbH, Nuernberg, Germany #
|
||||||
# sv@teamix.net #
|
# sv@teamix.net #
|
||||||
# (c) 2016 by Sven Velt, Germany #
|
# (c) 2016- by Sven Velt, Germany #
|
||||||
# sven-mymonplugins@velt.biz #
|
# sven-mymonplugins@velt.biz #
|
||||||
# #
|
# #
|
||||||
# This file is part of "velt.biz - My Monitoring Plugins" #
|
# This file is part of "velt.biz - My Monitoring Plugins" #
|
||||||
# a fork of "team(ix) Monitoring Plugins" in 2015 #
|
# a fork of "team(ix) Monitoring Plugins" in 2015 #
|
||||||
|
@ -28,102 +28,196 @@
|
||||||
import os
|
import os
|
||||||
import re
|
import re
|
||||||
import sys
|
import sys
|
||||||
import urllib2
|
import urllib.request, urllib.error, urllib.parse
|
||||||
|
|
||||||
try:
|
try:
|
||||||
from monitoringplugin import MonitoringPlugin
|
from MyMonPlugin import MonitoringPlugin
|
||||||
except ImportError:
|
except ImportError:
|
||||||
print '=========================='
|
print('==========================')
|
||||||
print 'AIKS! Python import error!'
|
print('AIKS! Python import error!')
|
||||||
print '==========================\n'
|
print('==========================\n')
|
||||||
print 'Could not find "monitoringplugin.py"!\n'
|
print('Could not find class "MonitoringPlugin"!\n')
|
||||||
print 'Did you download "%s"' % os.path.basename(sys.argv[0])
|
print('Did you download "%s"' % os.path.basename(sys.argv[0]))
|
||||||
print 'without "monitoringplugin.py"?\n'
|
print('without "MyMonPlugin/"?\n')
|
||||||
print 'Please go back to'
|
print('Please go back to')
|
||||||
print 'https://gogs.velt.biz/velt.biz/MyMonPlugins and download it,'
|
print('https://gogs.velt.biz/velt.biz/MyMonPlugins and:')
|
||||||
print 'or even better:'
|
print('- get a full archive at http://gogs.velt.biz/velt.biz/MyMonPlugins/releases')
|
||||||
print 'get a full archive at http://gogs.velt.biz/velt.biz/MyMonPlugins/releases'
|
print('- or a master snapshot at http://gogs.velt.biz/velt.biz/MyMonPlugins/archive/master.tar.gz\n')
|
||||||
print 'or a master snapshot at http://gogs.velt.biz/velt.biz/MyMonPlugins/archive/master.tar.gz\n'
|
|
||||||
sys.exit(127)
|
sys.exit(127)
|
||||||
|
|
||||||
|
############################################################
|
||||||
|
|
||||||
plugin = MonitoringPlugin(pluginname='check_apaches', tagforstatusline='APACHE', description='Check Apache workers', version='0.1')
|
class CheckApaches(MonitoringPlugin):
|
||||||
|
|
||||||
plugin.add_cmdlineoption('-H', '', 'host', 'Hostname/IP to check', default='localhost')
|
apache_busy = None
|
||||||
plugin.add_cmdlineoption('-p', '', 'port', 'port to connect', default=None)
|
apache_idle = None
|
||||||
plugin.add_cmdlineoption('-P', '', 'proto', 'protocol to use', default='http')
|
apache_scoreboard = None
|
||||||
plugin.add_cmdlineoption('-u', '', 'url', 'path to "server-status"', default='/server-status')
|
apache_states = None
|
||||||
plugin.add_cmdlineoption('-a', '', 'httpauth', 'HTTP Username and Password, separated by ":"')
|
data = None
|
||||||
plugin.add_cmdlineoption('-w', '', 'warn', 'warning thresold', default='20')
|
url = None
|
||||||
plugin.add_cmdlineoption('-c', '', 'crit', 'warning thresold', default='50')
|
|
||||||
plugin.add_cmdlineoption('', '--statistics', 'statistics', 'Output worker statistics', action='store_true')
|
|
||||||
|
|
||||||
plugin.parse_cmdlineoptions()
|
def analyze(self):
|
||||||
|
try:
|
||||||
|
self.apache_idle = int(re.search('Idle(?:Workers|Servers): (\d+)\n', self.data).group(1))
|
||||||
|
self.apache_busy = int(re.search('Busy(?:Workers|Servers): (\d+)\n', self.data).group(1))
|
||||||
|
except:
|
||||||
|
self.back2nagios(2, 'Could not analyze data!')
|
||||||
|
|
||||||
if plugin.options.proto not in ['http', 'https']:
|
self.apache_scoreboard = re.search('Scoreboard: (.*)\n', self.data)
|
||||||
plugin.back2nagios(3, 'Unknown protocol "' + plugin.options.proto + '"')
|
if self.apache_scoreboard:
|
||||||
|
self.apache_states = {'_':0, 'S':0, 'R':0, 'W':0, 'K':0, 'D':0, 'C':0, 'L':0, 'G':0, 'I':0, '.':0,}
|
||||||
|
for worker in self.apache_scoreboard.group(1):
|
||||||
|
self.apache_states[worker] += 1
|
||||||
|
pass
|
||||||
|
|
||||||
if not plugin.options.port:
|
|
||||||
if plugin.options.proto == 'https':
|
|
||||||
plugin.options.port = '443'
|
|
||||||
else:
|
|
||||||
plugin.options.port = '80'
|
|
||||||
|
|
||||||
url = plugin.options.proto + '://' + plugin.options.host + ':' + plugin.options.port + '/' + plugin.options.url + '?auto'
|
def check_slots(self, target='open', warn='', crit=''):
|
||||||
plugin.verbose(1, 'Status URL: ' + url)
|
pd = {'label':'slots_open', 'unit':'', 'warn':warn, 'crit': crit, 'min':0}
|
||||||
|
|
||||||
if plugin.options.httpauth:
|
if target == 'open':
|
||||||
httpauth = plugin.options.httpauth.split(':')
|
returncode = self.value_wc_to_returncode(self.apache_states['.'], warn, crit)
|
||||||
if len(httpauth) != 2:
|
output = '%d open slots' % self.apache_states['.']
|
||||||
plugin.back2nagios(3, 'Wrong format of authentication data! Need "USERNAME:PASSWORD", got "' + plugin.options.httpauth + '"')
|
pd['value'] = self.apache_states['.']
|
||||||
passman = urllib2.HTTPPasswordMgrWithDefaultRealm()
|
pd['label'] = 'slots_open'
|
||||||
passman.add_password(None, url, httpauth[0], httpauth[1])
|
|
||||||
authhandler = urllib2.HTTPBasicAuthHandler(passman)
|
|
||||||
opener = urllib2.build_opener(authhandler)
|
|
||||||
urllib2.install_opener(opener)
|
|
||||||
|
|
||||||
try:
|
return self.remember_check('slots', returncode, output, perfdata=[pd], target=target)
|
||||||
data = urllib2.urlopen(url).read()
|
|
||||||
except urllib2.HTTPError, e:
|
|
||||||
plugin.back2nagios(2, 'Could not read data! ' + str(e))
|
|
||||||
except urllib2.URLError, e:
|
|
||||||
plugin.back2nagios(2, 'Could not connect to server!')
|
|
||||||
|
|
||||||
plugin.verbose(2, 'Got data:\n' + data)
|
|
||||||
|
|
||||||
try:
|
def check_worker(self, target='busy', warn='', crit=''):
|
||||||
idle = int(re.search('Idle(?:Workers|Servers): (\d+)\n', data).group(1))
|
pd = {'label':'worker_busy', 'unit':'', 'warn':warn, 'crit': crit, 'min':0}
|
||||||
busy = int(re.search('Busy(?:Workers|Servers): (\d+)\n', data).group(1))
|
|
||||||
except:
|
|
||||||
plugin.back2nagios(2, 'Could not analyze data!')
|
|
||||||
|
|
||||||
states = None
|
if target == 'busy':
|
||||||
if plugin.options.statistics:
|
returncode = self.value_wc_to_returncode(self.apache_busy, warn, crit)
|
||||||
scoreboard = re.search('Scoreboard: (.*)\n', data)
|
output = '%d busy workers' % self.apache_busy
|
||||||
if scoreboard:
|
pd['value'] = self.apache_busy
|
||||||
states = {'_':0, 'S':0, 'R':0, 'W':0, 'K':0, 'D':0, 'C':0, 'L':0, 'G':0, 'I':0, '.':0,}
|
pd = [pd]
|
||||||
for worker in scoreboard.group(1):
|
elif target == 'idle':
|
||||||
states[worker] += 1
|
returncode = self.value_wc_to_returncode(self.apache_idle, warn, crit)
|
||||||
plugin.add_multilineoutput(str(states['_']) + ' waiting for connection')
|
output = '%d idle workers' % self.apache_idle
|
||||||
plugin.add_multilineoutput(str(states['S']) + ' starting up')
|
pd['value'] = self.apache_idle
|
||||||
plugin.add_multilineoutput(str(states['R']) + ' reading request')
|
pd['label'] = 'worker_idle'
|
||||||
plugin.add_multilineoutput(str(states['W']) + ' writing/sending reply')
|
pd = [pd]
|
||||||
plugin.add_multilineoutput(str(states['K']) + ' keepalive')
|
else:
|
||||||
plugin.add_multilineoutput(str(states['D']) + ' looking up in DNS')
|
returncode = 3
|
||||||
plugin.add_multilineoutput(str(states['C']) + ' closing connection')
|
output = 'Target "%s" unknown' % target
|
||||||
plugin.add_multilineoutput(str(states['L']) + ' logging')
|
pd = None
|
||||||
plugin.add_multilineoutput(str(states['G']) + ' gracefully finishing')
|
|
||||||
plugin.add_multilineoutput(str(states['I']) + ' idle cleanup of worker')
|
|
||||||
plugin.add_multilineoutput(str(states['.']) + ' open slots(up to ServerLimit)')
|
|
||||||
|
|
||||||
returncode = plugin.value_wc_to_returncode(busy, plugin.options.warn, plugin.options.crit)
|
|
||||||
|
|
||||||
plugin.add_output(str(busy) + ' busy workers, ' + str(idle) + ' idle')
|
return self.remember_check('worker', returncode, output, perfdata=pd, target=target)
|
||||||
|
|
||||||
plugin.add_returncode(returncode)
|
|
||||||
|
|
||||||
plugin.format_add_performancedata('busy', busy, '', warn=plugin.options.warn, crit=plugin.options.crit, min=0.0)
|
def get_server_status(self):
|
||||||
plugin.format_add_performancedata('idle', idle, '')
|
if self.options.httpauth:
|
||||||
|
httpauth = self.options.httpauth.split(':')
|
||||||
|
if len(httpauth) != 2:
|
||||||
|
self.back2nagios(3, 'Wrong format of authentication data! Need "USERNAME:PASSWORD", got "' + self.options.httpauth + '"')
|
||||||
|
passman = urllib.request.HTTPPasswordMgrWithDefaultRealm()
|
||||||
|
passman.add_password(None, url, httpauth[0], httpauth[1])
|
||||||
|
authhandler = urllib.request.HTTPBasicAuthHandler(passman)
|
||||||
|
opener = urllib.request.build_opener(authhandler)
|
||||||
|
urllib.request.install_opener(opener)
|
||||||
|
|
||||||
plugin.exit()
|
try:
|
||||||
|
self.data = urllib.request.urlopen(self.url).read().decode()
|
||||||
|
except urllib.error.HTTPError as e:
|
||||||
|
self.back2nagios(2, 'Could not read data! ' + str(e))
|
||||||
|
except urllib.error.URLError as e:
|
||||||
|
self.back2nagios(2, 'Could not connect to server!')
|
||||||
|
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
def set_status_url(self):
|
||||||
|
if self.options.url:
|
||||||
|
self.url = self.options.url
|
||||||
|
else:
|
||||||
|
if self.options.proto not in ['http', 'https']:
|
||||||
|
self.back2nagios(3, 'Unknown protocol "' + self.options.proto + '"')
|
||||||
|
|
||||||
|
if not self.options.port:
|
||||||
|
if self.options.proto == 'https':
|
||||||
|
self.options.port = '443'
|
||||||
|
else:
|
||||||
|
self.options.port = '80'
|
||||||
|
|
||||||
|
self.url = self.options.proto + '://' + self.options.host + ':' + self.options.port + '/' + self.options.uri + '?auto'
|
||||||
|
|
||||||
|
pass
|
||||||
|
|
||||||
|
############################################################
|
||||||
|
|
||||||
|
def main():
|
||||||
|
plugin = CheckApaches(
|
||||||
|
pluginname='check_apaches',
|
||||||
|
tagforstatusline='APACHE',
|
||||||
|
description='Check Apache workers',
|
||||||
|
version='0.1',
|
||||||
|
)
|
||||||
|
|
||||||
|
plugin.add_cmdlineoption('-H', '', 'host', 'Hostname/IP to check', default='localhost')
|
||||||
|
plugin.add_cmdlineoption('-p', '', 'port', 'port to connect', default=None)
|
||||||
|
plugin.add_cmdlineoption('-P', '', 'proto', 'protocol to use', default='http')
|
||||||
|
plugin.add_cmdlineoption('-u', '', 'uri', 'path to "server-status"', default='/server-status')
|
||||||
|
plugin.add_cmdlineoption('-U', '', 'url', 'complete URL to "server-status", overrides other options', default=None)
|
||||||
|
plugin.add_cmdlineoption('-a', '', 'httpauth', 'HTTP Username and Password, separated by ":"')
|
||||||
|
plugin.add_cmdlineoption('-w', '', 'warn', 'OBSOLETE: warning thresold', default='')
|
||||||
|
plugin.add_cmdlineoption('-c', '', 'crit', 'OBSOLETE: warning thresold', default='')
|
||||||
|
plugin.add_cmdlineoption('', '--statistics', 'statistics', 'Output worker statistics', action='store_true')
|
||||||
|
|
||||||
|
plugin.parse_cmdlineoptions()
|
||||||
|
|
||||||
|
|
||||||
|
plugin.set_status_url()
|
||||||
|
plugin.verbose(1, 'Status URL: ' + plugin.url)
|
||||||
|
|
||||||
|
plugin.get_server_status()
|
||||||
|
plugin.verbose(2, 'Got data:')
|
||||||
|
plugin.verbose(2, plugin.data)
|
||||||
|
|
||||||
|
plugin.analyze()
|
||||||
|
|
||||||
|
checks = plugin.args2checks()
|
||||||
|
|
||||||
|
# backward compatibility
|
||||||
|
if len(checks) == 0:
|
||||||
|
checks = [
|
||||||
|
('worker','busy','20','50'),
|
||||||
|
('worker','idle','20:','5:'),
|
||||||
|
]
|
||||||
|
|
||||||
|
for quad in checks:
|
||||||
|
(check, target, warn, crit) = tuple(quad)
|
||||||
|
|
||||||
|
if check == 'slots':
|
||||||
|
result = plugin.check_slots(target, warn, crit)
|
||||||
|
elif check == 'worker':
|
||||||
|
result = plugin.check_worker(target, warn, crit)
|
||||||
|
else:
|
||||||
|
result = plugin.remember_check(check, plugin.RETURNCODE['UNKNOWN'], 'Unknown check "' + check + '"!')
|
||||||
|
|
||||||
|
plugin.verbose(5, result)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
if plugin.options.statistics:
|
||||||
|
plugin.add_multilineoutput(str(plugin.apache_states['_']) + ' waiting for connection')
|
||||||
|
plugin.add_multilineoutput(str(plugin.apache_states['S']) + ' starting up')
|
||||||
|
plugin.add_multilineoutput(str(plugin.apache_states['R']) + ' reading request')
|
||||||
|
plugin.add_multilineoutput(str(plugin.apache_states['W']) + ' writing/sending reply')
|
||||||
|
plugin.add_multilineoutput(str(plugin.apache_states['K']) + ' keepalive')
|
||||||
|
plugin.add_multilineoutput(str(plugin.apache_states['D']) + ' looking up in DNS')
|
||||||
|
plugin.add_multilineoutput(str(plugin.apache_states['C']) + ' closing connection')
|
||||||
|
plugin.add_multilineoutput(str(plugin.apache_states['L']) + ' logging')
|
||||||
|
plugin.add_multilineoutput(str(plugin.apache_states['G']) + ' gracefully finishing')
|
||||||
|
plugin.add_multilineoutput(str(plugin.apache_states['I']) + ' idle cleanup of worker')
|
||||||
|
plugin.add_multilineoutput(str(plugin.apache_states['.']) + ' open slots(up to ServerLimit)')
|
||||||
|
|
||||||
|
plugin.brain2output()
|
||||||
|
plugin.exit()
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
main()
|
||||||
|
|
||||||
|
#vim: ts=4 sts=4 sw=4
|
||||||
|
|
||||||
|
|
177
check_apk.py
Executable file
177
check_apk.py
Executable file
|
@ -0,0 +1,177 @@
|
||||||
|
#!/usr/bin/env python3
|
||||||
|
# -*- encoding: utf-8 -*-
|
||||||
|
|
||||||
|
#####################################################################
|
||||||
|
# (c) 2016- by Sven Velt, Germany #
|
||||||
|
# sven-mymonplugins@velt.biz #
|
||||||
|
# #
|
||||||
|
# This file is part of "velt.biz - My Monitoring Plugins" #
|
||||||
|
# a fork of "team(ix) Monitoring Plugins" in 2015 #
|
||||||
|
# URL: https://gogs.velt.biz/velt.biz/MyMonPlugins/ #
|
||||||
|
# #
|
||||||
|
# This file is free software: you can redistribute it and/or modify #
|
||||||
|
# it under the terms of the GNU General Public License as published #
|
||||||
|
# by the Free Software Foundation, either version 2 of the License, #
|
||||||
|
# or (at your option) any later version. #
|
||||||
|
# #
|
||||||
|
# This file 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 General Public License for more details. #
|
||||||
|
# #
|
||||||
|
# You should have received a copy of the GNU General Public License #
|
||||||
|
# along with this file. If not, see <http://www.gnu.org/licenses/>. #
|
||||||
|
#####################################################################
|
||||||
|
|
||||||
|
import os
|
||||||
|
import subprocess
|
||||||
|
import sys
|
||||||
|
import time
|
||||||
|
|
||||||
|
try:
|
||||||
|
from MyMonPlugin import MonitoringPlugin
|
||||||
|
except ImportError:
|
||||||
|
print('==========================')
|
||||||
|
print('AIKS! Python import error!')
|
||||||
|
print('==========================\n')
|
||||||
|
print('Could not find class "MonitoringPlugin"!\n')
|
||||||
|
print('Did you download "%s"' % os.path.basename(sys.argv[0]))
|
||||||
|
print('without "MyMonPlugin/"?\n')
|
||||||
|
print('Please go back to')
|
||||||
|
print('https://gogs.velt.biz/velt.biz/MyMonPlugins and:')
|
||||||
|
print('- get a full archive at http://gogs.velt.biz/velt.biz/MyMonPlugins/releases')
|
||||||
|
print('- or a master snapshot at http://gogs.velt.biz/velt.biz/MyMonPlugins/archive/master.tar.gz\n')
|
||||||
|
sys.exit(127)
|
||||||
|
|
||||||
|
|
||||||
|
plugin = MonitoringPlugin(
|
||||||
|
pluginname='check_apk',
|
||||||
|
tagforstatusline='APK',
|
||||||
|
description='Check APK package manager for updates',
|
||||||
|
version='0.1',
|
||||||
|
)
|
||||||
|
|
||||||
|
plugin.add_cmdlineoption('-P', '--path-apk', 'apk', 'full path to apk', default='/sbin/apk')
|
||||||
|
plugin.add_cmdlineoption('-S', '--sync-repo-index', 'sync_repo_index', 'sync repository index files at startup', default=False, action='store_true')
|
||||||
|
plugin.add_cmdlineoption('', '--ignore-sync-failure', 'fail_on_sync_failure', 'ignore repo index sync failures', default=True, action='store_false')
|
||||||
|
plugin.add_cmdlineoption('', '--sudo', 'sudo', 'call "apk" with sudo', default=False, action='store_true')
|
||||||
|
|
||||||
|
plugin.add_cmdlineoption('', '--mymonplugins-testmode', 'mymonplugins_testmode', None, default=False, action='store_true')
|
||||||
|
|
||||||
|
plugin.parse_cmdlineoptions()
|
||||||
|
|
||||||
|
##############################################################################
|
||||||
|
##### Testmode
|
||||||
|
|
||||||
|
if plugin.options.mymonplugins_testmode:
|
||||||
|
mymonplugins_testmode = {}
|
||||||
|
|
||||||
|
mymonplugins_testmode['apk update'] = '''fetch http://dl-cdn.alpinelinux.org/alpine/latest-stable/main/x86_64/APKINDEX.tar.gz
|
||||||
|
fetch http://dl-cdn.alpinelinux.org/alpine/latest-stable/community/x86_64/APKINDEX.tar.gz
|
||||||
|
v3.17.3-13-g98fa1f428e9 [http://dl-cdn.alpinelinux.org/alpine/latest-stable/main]
|
||||||
|
v3.17.3-12-g492f704d069 [http://dl-cdn.alpinelinux.org/alpine/latest-stable/community]
|
||||||
|
OK: 17824 distinct packages available
|
||||||
|
'''.split('\n')
|
||||||
|
|
||||||
|
mymonplugins_testmode['apk -s upgrade'] = '''(1/6) Upgrading alpine-release (3.17.2-r0 -> 3.17.3-r0)
|
||||||
|
(2/6) Upgrading libcrypto3 (3.0.8-r1 -> 3.0.8-r3)
|
||||||
|
(3/6) Upgrading libssl3 (3.0.8-r1 -> 3.0.8-r3)
|
||||||
|
(4/6) Upgrading alpine-base (3.17.2-r0 -> 3.17.3-r0)
|
||||||
|
(5/6) Upgrading mkinitfs (3.7.0-r0 -> 3.7.0-r1)
|
||||||
|
(6/6) Upgrading openssl (3.0.8-r1 -> 3.0.8-r3)
|
||||||
|
OK: 258 MiB in 220 packages
|
||||||
|
'''.split('\n')
|
||||||
|
|
||||||
|
##############################################################################
|
||||||
|
|
||||||
|
def run_command(cmdline, needs_sudo=False):
|
||||||
|
tstart = time.time()
|
||||||
|
if needs_sudo and plugin.options.sudo:
|
||||||
|
new = ['sudo', '-n', '--']
|
||||||
|
new.extend(cmdline)
|
||||||
|
cmdline = new
|
||||||
|
plugin.verbose(1, 'Running command line: %s' % subprocess.list2cmdline(cmdline))
|
||||||
|
try:
|
||||||
|
cmd = subprocess.Popen(
|
||||||
|
cmdline,
|
||||||
|
stdout = subprocess.PIPE,
|
||||||
|
stderr = subprocess.PIPE
|
||||||
|
)
|
||||||
|
except OSError:
|
||||||
|
plugin.back2nagios(plugin.RETURNCODE['UNKNOWN'], 'Could not execute command line: %s' % subprocess.list2cmdline(cmdline))
|
||||||
|
|
||||||
|
(sout,serr) = cmd.communicate()
|
||||||
|
plugin.verbose(2, 'Runtime %.3fs' % (time.time() - tstart, ) )
|
||||||
|
|
||||||
|
sout = sout.rstrip().decode('utf-8').split('\n')
|
||||||
|
if sout == ['']:
|
||||||
|
sout = []
|
||||||
|
serr = serr.rstrip().decode('utf-8').split('\n')
|
||||||
|
if serr == ['']:
|
||||||
|
serr = []
|
||||||
|
|
||||||
|
return( (sout, serr, cmd.returncode,) )
|
||||||
|
|
||||||
|
##############################################################################
|
||||||
|
|
||||||
|
if plugin.options.sync_repo_index:
|
||||||
|
plugin.verbose(1, '-S/--sync_repo_index given')
|
||||||
|
cmdline = [plugin.options.apk, 'update', '--no-progress',]
|
||||||
|
(sout, serr, rc) = run_command(cmdline, needs_sudo=True)
|
||||||
|
sout and plugin.verbose(3, sout, prefix='stdout: ')
|
||||||
|
serr and plugin.verbose(3, serr, prefix='stderr: ')
|
||||||
|
plugin.verbose(2, 'Return code: %d' % rc)
|
||||||
|
if plugin.options.fail_on_sync_failure and (rc != 0 or 'ERROR:' in ' '.join(serr)):
|
||||||
|
if 'Permission denied' in ' '.join(serr):
|
||||||
|
plugin.back2nagios(plugin.RETURNCODE['CRITICAL'], 'Syncing of repository index files failed, permission denied. Do you need "--sudo"?', multiline=serr)
|
||||||
|
plugin.back2nagios(plugin.RETURNCODE['CRITICAL'], 'Syncing of repository index files failed', multiline=serr)
|
||||||
|
|
||||||
|
##############################################################################
|
||||||
|
|
||||||
|
cmdline = [plugin.options.apk, 'upgrade', '--simulate', '--no-progress',]
|
||||||
|
(sout, serr, rc) = run_command(cmdline)
|
||||||
|
sout and plugin.verbose(3, sout, prefix='stdout: ')
|
||||||
|
serr and plugin.verbose(3, serr, prefix='stderr: ')
|
||||||
|
plugin.verbose(2, 'Return code: %d' % rc)
|
||||||
|
|
||||||
|
if plugin.options.sudo and 'sudo: ' in ' '.join(serr):
|
||||||
|
# Running with sudo
|
||||||
|
if rc == 1:
|
||||||
|
# sudo RC 1: a password is required
|
||||||
|
plugin.back2nagios(plugin.RETURNCODE['CRITICAL'], ' '.join(serr))
|
||||||
|
if rc == 8:
|
||||||
|
# RC 8: Transaction aborted due to unresolved shlibs.
|
||||||
|
plugin.back2nagios(plugin.RETURNCODE['WARNING'], serr[-1], serr[:-1])
|
||||||
|
elif rc not in [0, 6]:
|
||||||
|
# RC 0: Packages to update
|
||||||
|
# RC 6: Package(s) already installed
|
||||||
|
plugin.back2nagios(plugin.RETURNCODE['WARNING'], 'Unknown returncode "%s", please contact the author of plugin or open an issue!' % rc)
|
||||||
|
|
||||||
|
action = {'Upgrading':[], 'Installing':[], 'Purging':[], }
|
||||||
|
action_verb = {'Upgrading':'upgrade', 'Installing':'install', 'Purging':'purge', }
|
||||||
|
|
||||||
|
for line in sout[0:-1]:
|
||||||
|
cols = line.split(' ')
|
||||||
|
# Append package name to action type list
|
||||||
|
action[cols[1]].append(cols[2])
|
||||||
|
|
||||||
|
if len(sout) == 1:
|
||||||
|
plugin.remember_check('Updates', plugin.RETURNCODE['OK'], 'Everything uptodate')
|
||||||
|
else:
|
||||||
|
out = []
|
||||||
|
multiline = []
|
||||||
|
for act in list(action.keys()):
|
||||||
|
pkgs = action.pop(act)
|
||||||
|
pkgs.sort()
|
||||||
|
l = len(pkgs)
|
||||||
|
out.append('%s package%s to %s' % (l, l != 1 and 's' or '', action_verb[act]) )
|
||||||
|
l and multiline.append('%s(%s): %s' % (act, l, ', '.join(pkgs)) )
|
||||||
|
|
||||||
|
out = ', '.join(out)
|
||||||
|
|
||||||
|
plugin.remember_check('Updates', plugin.RETURNCODE['CRITICAL'], out, multilineoutput=multiline)
|
||||||
|
|
||||||
|
# Exit
|
||||||
|
plugin.brain2output()
|
||||||
|
plugin.exit()
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
#!/usr/bin/env python2
|
#!/usr/bin/env python3
|
||||||
# -*- encoding: utf-8 -*-
|
# -*- encoding: utf-8 -*-
|
||||||
|
|
||||||
#####################################################################
|
#####################################################################
|
||||||
# (c) 2016 by Sven Velt, Germany #
|
# (c) 2016- by Sven Velt, Germany #
|
||||||
# sven-mymonplugins@velt.biz #
|
# sven-mymonplugins@velt.biz #
|
||||||
# #
|
# #
|
||||||
# This file is part of "velt.biz - My Monitoring Plugins" #
|
# This file is part of "velt.biz - My Monitoring Plugins" #
|
||||||
|
@ -30,19 +30,18 @@ import sys
|
||||||
import time
|
import time
|
||||||
|
|
||||||
try:
|
try:
|
||||||
from monitoringplugin import MonitoringPlugin
|
from MyMonPlugin import MonitoringPlugin
|
||||||
except ImportError:
|
except ImportError:
|
||||||
print '=========================='
|
print('==========================')
|
||||||
print 'AIKS! Python import error!'
|
print('AIKS! Python import error!')
|
||||||
print '==========================\n'
|
print('==========================\n')
|
||||||
print 'Could not find "monitoringplugin.py"!\n'
|
print('Could not find class "MonitoringPlugin"!\n')
|
||||||
print 'Did you download "%s"' % os.path.basename(sys.argv[0])
|
print('Did you download "%s"' % os.path.basename(sys.argv[0]))
|
||||||
print 'without "monitoringplugin.py"?\n'
|
print('without "MyMonPlugin/"?\n')
|
||||||
print 'Please go back to'
|
print('Please go back to')
|
||||||
print 'https://gogs.velt.biz/velt.biz/MyMonPlugins and download it,'
|
print('https://gogs.velt.biz/velt.biz/MyMonPlugins and:')
|
||||||
print 'or even better:'
|
print('- get a full archive at http://gogs.velt.biz/velt.biz/MyMonPlugins/releases')
|
||||||
print 'get a full archive at http://gogs.velt.biz/velt.biz/MyMonPlugins/releases'
|
print('- or a master snapshot at http://gogs.velt.biz/velt.biz/MyMonPlugins/archive/master.tar.gz\n')
|
||||||
print 'or a master snapshot at http://gogs.velt.biz/velt.biz/MyMonPlugins/archive/master.tar.gz\n'
|
|
||||||
sys.exit(127)
|
sys.exit(127)
|
||||||
|
|
||||||
|
|
||||||
|
@ -54,7 +53,7 @@ plugin = MonitoringPlugin(
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
plugin.add_cmdlineoption('-P', '--check-printers', 'check_printers', 'check printer queue', default=False, action='store_true' )
|
plugin.add_cmdlineoption('-P', '--check-printers', 'check_printers', 'check printer', default=False, action='store_true' )
|
||||||
plugin.add_cmdlineoption('-J', '--check-jobs', 'check_jobs', 'check job queue', default=False, action='store_true')
|
plugin.add_cmdlineoption('-J', '--check-jobs', 'check_jobs', 'check job queue', default=False, action='store_true')
|
||||||
plugin.add_cmdlineoption('-w', '', 'warn', 'warning thresold for old jobs (seconds)', default='3600')
|
plugin.add_cmdlineoption('-w', '', 'warn', 'warning thresold for old jobs (seconds)', default='3600')
|
||||||
plugin.add_cmdlineoption('-c', '', 'crit', 'warning thresold for old jobs (seconds)', default='86400')
|
plugin.add_cmdlineoption('-c', '', 'crit', 'warning thresold for old jobs (seconds)', default='86400')
|
||||||
|
@ -110,7 +109,7 @@ def check_printer_queue(output_printer_queue):
|
||||||
def check_job_queue(output_job_queue):
|
def check_job_queue(output_job_queue):
|
||||||
plugin.verbose(1, 'Checking job queue')
|
plugin.verbose(1, 'Checking job queue')
|
||||||
m = re.compile('(\w{3} \d\d \w{3} \d{4} \d\d:\d\d:\d\d (AM|PM) \w{3,5})')
|
m = re.compile('(\w{3} \d\d \w{3} \d{4} \d\d:\d\d:\d\d (AM|PM) \w{3,5})')
|
||||||
nowsecs = long( time.time() )
|
nowsecs = int( time.time() )
|
||||||
|
|
||||||
jobs_warn = []
|
jobs_warn = []
|
||||||
jobs_crit = []
|
jobs_crit = []
|
||||||
|
@ -122,7 +121,7 @@ def check_job_queue(output_job_queue):
|
||||||
continue
|
continue
|
||||||
tstamp = time.strptime(f.group(1), '%a %d %b %Y %I:%M:%S %p %Z')
|
tstamp = time.strptime(f.group(1), '%a %d %b %Y %I:%M:%S %p %Z')
|
||||||
|
|
||||||
tsecs = long( time.mktime(tstamp) )
|
tsecs = int( time.mktime(tstamp) )
|
||||||
age = nowsecs - tsecs
|
age = nowsecs - tsecs
|
||||||
rc = plugin.value_wc_to_returncode(age, plugin.options.warn, plugin.options.crit)
|
rc = plugin.value_wc_to_returncode(age, plugin.options.warn, plugin.options.crit)
|
||||||
if rc == 1:
|
if rc == 1:
|
||||||
|
@ -156,7 +155,7 @@ def call_cmd(cmdline):
|
||||||
cmd = subprocess.Popen(cmdline, stdout=subprocess.PIPE, env=myenv)
|
cmd = subprocess.Popen(cmdline, stdout=subprocess.PIPE, env=myenv)
|
||||||
(sout, serr) = cmd.communicate()
|
(sout, serr) = cmd.communicate()
|
||||||
if sout:
|
if sout:
|
||||||
sout = sout.lstrip().rstrip().split('\n')
|
sout = sout.lstrip().rstrip().decode('utf-8').split('\n')
|
||||||
else:
|
else:
|
||||||
sout = []
|
sout = []
|
||||||
except OSError:
|
except OSError:
|
||||||
|
@ -170,7 +169,7 @@ allchecks = not( plugin.options.check_printers or plugin.options.check_jobs )
|
||||||
if allchecks or plugin.options.check_printers:
|
if allchecks or plugin.options.check_printers:
|
||||||
(sout, serr, retcode) = call_cmd(['lpstat', '-a'])
|
(sout, serr, retcode) = call_cmd(['lpstat', '-a'])
|
||||||
check_printer_queue(sout)
|
check_printer_queue(sout)
|
||||||
if allchecks or plugin.options.check_jobs:
|
if allchecks or plugin.options.check_jobs:
|
||||||
(sout, serr, retcode) = call_cmd(['lpstat', '-o'])
|
(sout, serr, retcode) = call_cmd(['lpstat', '-o'])
|
||||||
check_job_queue(sout)
|
check_job_queue(sout)
|
||||||
|
|
||||||
|
|
|
@ -1,11 +1,11 @@
|
||||||
#!/usr/bin/env python
|
#!/usr/bin/env python3
|
||||||
# -*- encoding: utf-8 -*-
|
# -*- encoding: utf-8 -*-
|
||||||
|
|
||||||
#####################################################################
|
#####################################################################
|
||||||
# (c) 2006-2011 by Sven Velt and team(ix) GmbH, Nuernberg, Germany #
|
# (c) 2006-2011 by Sven Velt and team(ix) GmbH, Nuernberg, Germany #
|
||||||
# sv@teamix.net #
|
# sv@teamix.net #
|
||||||
# (c) 2016 by Sven Velt, Germany #
|
# (c) 2016- by Sven Velt, Germany #
|
||||||
# sven-mymonplugins@velt.biz #
|
# sven-mymonplugins@velt.biz #
|
||||||
# #
|
# #
|
||||||
# This file is part of "velt.biz - My Monitoring Plugins" #
|
# This file is part of "velt.biz - My Monitoring Plugins" #
|
||||||
# a fork of "team(ix) Monitoring Plugins" in 2015 #
|
# a fork of "team(ix) Monitoring Plugins" in 2015 #
|
||||||
|
@ -31,25 +31,24 @@ import struct
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
try:
|
try:
|
||||||
from monitoringplugin import SNMPMonitoringPlugin
|
from MyMonPlugin import MonitoringPlugin
|
||||||
except ImportError:
|
except ImportError:
|
||||||
print '=========================='
|
print('==========================')
|
||||||
print 'AIKS! Python import error!'
|
print('AIKS! Python import error!')
|
||||||
print '==========================\n'
|
print('==========================\n')
|
||||||
print 'Could not find "monitoringplugin.py"!\n'
|
print('Could not find class "MonitoringPlugin"!\n')
|
||||||
print 'Did you download "%s"' % os.path.basename(sys.argv[0])
|
print('Did you download "%s"' % os.path.basename(sys.argv[0]))
|
||||||
print 'without "monitoringplugin.py"?\n'
|
print('without "MyMonPlugin/"?\n')
|
||||||
print 'Please go back to'
|
print('Please go back to')
|
||||||
print 'https://gogs.velt.biz/velt.biz/MyMonPlugins and download it,'
|
print('https://gogs.velt.biz/velt.biz/MyMonPlugins and:')
|
||||||
print 'or even better:'
|
print('- get a full archive at http://gogs.velt.biz/velt.biz/MyMonPlugins/releases')
|
||||||
print 'get a full archive at http://gogs.velt.biz/velt.biz/MyMonPlugins/releases'
|
print('- or a master snapshot at http://gogs.velt.biz/velt.biz/MyMonPlugins/archive/master.tar.gz\n')
|
||||||
print 'or a master snapshot at http://gogs.velt.biz/velt.biz/MyMonPlugins/archive/master.tar.gz\n'
|
|
||||||
sys.exit(127)
|
sys.exit(127)
|
||||||
|
|
||||||
|
|
||||||
def get_ipv4_address(iface):
|
def get_ipv4_address(iface):
|
||||||
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
|
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
|
||||||
return socket.inet_ntoa(fcntl.ioctl(sock.fileno(), 0x8915, struct.pack('256s', iface[:15]))[20:24])
|
return socket.inet_ntoa(fcntl.ioctl(sock.fileno(), 0x8915, struct.pack('256s', bytes(iface[:15], 'utf-8')))[20:24])
|
||||||
|
|
||||||
|
|
||||||
plugin = MonitoringPlugin(pluginname='check_iface-dns', tagforstatusline='IFACE-DNS', description='Check interface address vs. DNS', version='0.1')
|
plugin = MonitoringPlugin(pluginname='check_iface-dns', tagforstatusline='IFACE-DNS', description='Check interface address vs. DNS', version='0.1')
|
||||||
|
@ -74,7 +73,8 @@ plugin.parse_cmdlineoptions()
|
||||||
# Get IP from interface
|
# Get IP from interface
|
||||||
try:
|
try:
|
||||||
ip_iface = get_ipv4_address(plugin.options.iface)
|
ip_iface = get_ipv4_address(plugin.options.iface)
|
||||||
except IOError, (errno, strerror):
|
except IOError as xxx_todo_changeme:
|
||||||
|
(errno, strerror) = xxx_todo_changeme.args
|
||||||
if errno == 19:
|
if errno == 19:
|
||||||
plugin.back2nagios(2, 'Interface "%s" does not exist!' % plugin.options.iface)
|
plugin.back2nagios(2, 'Interface "%s" does not exist!' % plugin.options.iface)
|
||||||
elif errno == 99:
|
elif errno == 99:
|
||||||
|
@ -120,7 +120,7 @@ else:
|
||||||
else:
|
else:
|
||||||
plugin.add_multilineoutput('OK - "%s" resolves to "%s"' % (dns, ip_dns))
|
plugin.add_multilineoutput('OK - "%s" resolves to "%s"' % (dns, ip_dns))
|
||||||
|
|
||||||
|
|
||||||
if len(failed_dns) == 0:
|
if len(failed_dns) == 0:
|
||||||
plugin.add_returncode(0)
|
plugin.add_returncode(0)
|
||||||
plugin.add_output('All DNS objects have a correct IP')
|
plugin.add_output('All DNS objects have a correct IP')
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
#!/usr/bin/env python
|
#!/usr/bin/env python3
|
||||||
# -*- encoding: utf-8 -*-
|
# -*- encoding: utf-8 -*-
|
||||||
|
|
||||||
#####################################################################
|
#####################################################################
|
||||||
# (c) 2016 by Sven Velt, Germany #
|
# (c) 2016- by Sven Velt, Germany #
|
||||||
# sven-mymonplugins@velt.biz #
|
# sven-mymonplugins@velt.biz #
|
||||||
# #
|
# #
|
||||||
# This file is part of "velt.biz - My Monitoring Plugins" #
|
# This file is part of "velt.biz - My Monitoring Plugins" #
|
||||||
|
@ -29,19 +29,18 @@ import socket
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
try:
|
try:
|
||||||
from monitoringplugin import MonitoringPlugin
|
from MyMonPlugin import MonitoringPlugin
|
||||||
except ImportError:
|
except ImportError:
|
||||||
print '=========================='
|
print('==========================')
|
||||||
print 'AIKS! Python import error!'
|
print('AIKS! Python import error!')
|
||||||
print '==========================\n'
|
print('==========================\n')
|
||||||
print 'Could not find "monitoringplugin.py"!\n'
|
print('Could not find class "MonitoringPlugin"!\n')
|
||||||
print 'Did you download "%s"' % os.path.basename(sys.argv[0])
|
print('Did you download "%s"' % os.path.basename(sys.argv[0]))
|
||||||
print 'without "monitoringplugin.py"?\n'
|
print('without "MyMonPlugin/"?\n')
|
||||||
print 'Please go back to'
|
print('Please go back to')
|
||||||
print 'https://gogs.velt.biz/velt.biz/MyMonPlugins and download it,'
|
print('https://gogs.velt.biz/velt.biz/MyMonPlugins and:')
|
||||||
print 'or even better:'
|
print('- get a full archive at http://gogs.velt.biz/velt.biz/MyMonPlugins/releases')
|
||||||
print 'get a full archive at http://gogs.velt.biz/velt.biz/MyMonPlugins/releases'
|
print('- or a master snapshot at http://gogs.velt.biz/velt.biz/MyMonPlugins/archive/master.tar.gz\n')
|
||||||
print 'or a master snapshot at http://gogs.velt.biz/velt.biz/MyMonPlugins/archive/master.tar.gz\n'
|
|
||||||
sys.exit(127)
|
sys.exit(127)
|
||||||
|
|
||||||
|
|
||||||
|
@ -83,7 +82,7 @@ if not os.access(plugin.options.socket, os.W_OK):
|
||||||
plugin.back2nagios(3, 'Could not read from socket "%s"' % plugin.options.socket)
|
plugin.back2nagios(3, 'Could not read from socket "%s"' % plugin.options.socket)
|
||||||
# FIXME: End
|
# FIXME: End
|
||||||
|
|
||||||
cmd_svc='''GET services
|
cmd_svc=b'''GET services
|
||||||
OutputFormat: csv
|
OutputFormat: csv
|
||||||
Stats: min latency
|
Stats: min latency
|
||||||
Stats: max latency
|
Stats: max latency
|
||||||
|
@ -93,7 +92,7 @@ Stats: max execution_time
|
||||||
Stats: avg execution_time
|
Stats: avg execution_time
|
||||||
'''
|
'''
|
||||||
|
|
||||||
cmd_hst='''GET hosts
|
cmd_hst=b'''GET hosts
|
||||||
OutputFormat: csv
|
OutputFormat: csv
|
||||||
Stats: min latency
|
Stats: min latency
|
||||||
Stats: max latency
|
Stats: max latency
|
||||||
|
@ -116,7 +115,7 @@ try:
|
||||||
s.settimeout(10)
|
s.settimeout(10)
|
||||||
data = s.recv(32768)
|
data = s.recv(32768)
|
||||||
if data:
|
if data:
|
||||||
answer += data
|
answer += data.decode('utf-8')
|
||||||
else:
|
else:
|
||||||
break
|
break
|
||||||
except socket.timeout:
|
except socket.timeout:
|
||||||
|
@ -142,7 +141,7 @@ try:
|
||||||
s.settimeout(10)
|
s.settimeout(10)
|
||||||
data = s.recv(32768)
|
data = s.recv(32768)
|
||||||
if data:
|
if data:
|
||||||
answer += data
|
answer += data.decode('utf-8')
|
||||||
else:
|
else:
|
||||||
break
|
break
|
||||||
except socket.timeout:
|
except socket.timeout:
|
||||||
|
|
|
@ -1,11 +1,11 @@
|
||||||
#!/usr/bin/env python
|
#!/usr/bin/env python3
|
||||||
# -*- encoding: utf-8 -*-
|
# -*- encoding: utf-8 -*-
|
||||||
|
|
||||||
#####################################################################
|
#####################################################################
|
||||||
# (c) 2010-2011 by Sven Velt and team(ix) GmbH, Nuernberg, Germany #
|
# (c) 2010-2011 by Sven Velt and team(ix) GmbH, Nuernberg, Germany #
|
||||||
# sv@teamix.net #
|
# sv@teamix.net #
|
||||||
# (c) 2016 by Sven Velt, Germany #
|
# (c) 2016- by Sven Velt, Germany #
|
||||||
# sven-mymonplugins@velt.biz #
|
# sven-mymonplugins@velt.biz #
|
||||||
# #
|
# #
|
||||||
# This file is part of "velt.biz - My Monitoring Plugins" #
|
# This file is part of "velt.biz - My Monitoring Plugins" #
|
||||||
# a fork of "team(ix) Monitoring Plugins" in 2015 #
|
# a fork of "team(ix) Monitoring Plugins" in 2015 #
|
||||||
|
@ -30,19 +30,18 @@ import re
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
try:
|
try:
|
||||||
from monitoringplugin import MonitoringPlugin
|
from MyMonPlugin import MonitoringPlugin
|
||||||
except ImportError:
|
except ImportError:
|
||||||
print '=========================='
|
print('==========================')
|
||||||
print 'AIKS! Python import error!'
|
print('AIKS! Python import error!')
|
||||||
print '==========================\n'
|
print('==========================\n')
|
||||||
print 'Could not find "monitoringplugin.py"!\n'
|
print('Could not find class "MonitoringPlugin"!\n')
|
||||||
print 'Did you download "%s"' % os.path.basename(sys.argv[0])
|
print('Did you download "%s"' % os.path.basename(sys.argv[0]))
|
||||||
print 'without "monitoringplugin.py"?\n'
|
print('without "MyMonPlugin/"?\n')
|
||||||
print 'Please go back to'
|
print('Please go back to')
|
||||||
print 'https://gogs.velt.biz/velt.biz/MyMonPlugins and download it,'
|
print('https://gogs.velt.biz/velt.biz/MyMonPlugins and:')
|
||||||
print 'or even better:'
|
print('- get a full archive at http://gogs.velt.biz/velt.biz/MyMonPlugins/releases')
|
||||||
print 'get a full archive at http://gogs.velt.biz/velt.biz/MyMonPlugins/releases'
|
print('- or a master snapshot at http://gogs.velt.biz/velt.biz/MyMonPlugins/archive/master.tar.gz\n')
|
||||||
print 'or a master snapshot at http://gogs.velt.biz/velt.biz/MyMonPlugins/archive/master.tar.gz\n'
|
|
||||||
sys.exit(127)
|
sys.exit(127)
|
||||||
|
|
||||||
|
|
||||||
|
@ -103,16 +102,13 @@ for version in versions:
|
||||||
matcher = v4match
|
matcher = v4match
|
||||||
|
|
||||||
for proto in protos:
|
for proto in protos:
|
||||||
filename = '/proc/net/%s%s' % (proto, version)
|
with open('/proc/net/%s%s' % (proto, version)) as fh:
|
||||||
f = file(filename)
|
for line in fh:
|
||||||
lines = f.readlines()
|
m = matcher.match(line)
|
||||||
|
if m:
|
||||||
for line in lines:
|
port = int(m.group(2), 16)
|
||||||
m = matcher.match(line)
|
if port == plugin.options.port and m.group(3) not in ['00000000','00000000000000000000000000000000']:
|
||||||
if m:
|
count += 1
|
||||||
port = int(m.group(2), 16)
|
|
||||||
if port == plugin.options.port and m.group(3) not in ['00000000','00000000000000000000000000000000']:
|
|
||||||
count += 1
|
|
||||||
|
|
||||||
|
|
||||||
returncode = plugin.value_wc_to_returncode(count, plugin.options.warn, plugin.options.crit)
|
returncode = plugin.value_wc_to_returncode(count, plugin.options.warn, plugin.options.crit)
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
#!/usr/bin/env python2
|
#!/usr/bin/env python3
|
||||||
# -*- encoding: utf-8 -*-
|
# -*- encoding: utf-8 -*-
|
||||||
|
|
||||||
#####################################################################
|
#####################################################################
|
||||||
# (c) 2016-2017 by Sven Velt, Germany #
|
# (c) 2016- by Sven Velt, Germany #
|
||||||
# sven-mymonplugins@velt.biz #
|
# sven-mymonplugins@velt.biz #
|
||||||
# #
|
# #
|
||||||
# This file is part of "velt.biz - My Monitoring Plugins" #
|
# This file is part of "velt.biz - My Monitoring Plugins" #
|
||||||
# a fork of "team(ix) Monitoring Plugins" in 2015 #
|
# a fork of "team(ix) Monitoring Plugins" in 2015 #
|
||||||
|
@ -23,24 +23,24 @@
|
||||||
# along with this file. If not, see <http://www.gnu.org/licenses/>. #
|
# along with this file. If not, see <http://www.gnu.org/licenses/>. #
|
||||||
#####################################################################
|
#####################################################################
|
||||||
|
|
||||||
|
import os
|
||||||
import subprocess
|
import subprocess
|
||||||
import sys
|
import sys
|
||||||
import time
|
import time
|
||||||
|
|
||||||
try:
|
try:
|
||||||
from monitoringplugin import MonitoringPlugin
|
from MyMonPlugin import MonitoringPlugin
|
||||||
except ImportError:
|
except ImportError:
|
||||||
print '=========================='
|
print('==========================')
|
||||||
print 'AIKS! Python import error!'
|
print('AIKS! Python import error!')
|
||||||
print '==========================\n'
|
print('==========================\n')
|
||||||
print 'Could not find "monitoringplugin.py"!\n'
|
print('Could not find class "MonitoringPlugin"!\n')
|
||||||
print 'Did you download "%s"' % os.path.basename(sys.argv[0])
|
print('Did you download "%s"' % os.path.basename(sys.argv[0]))
|
||||||
print 'without "monitoringplugin.py"?\n'
|
print('without "MyMonPlugin/"?\n')
|
||||||
print 'Please go back to'
|
print('Please go back to')
|
||||||
print 'https://gogs.velt.biz/velt.biz/MyMonPlugins and download it,'
|
print('https://gogs.velt.biz/velt.biz/MyMonPlugins and:')
|
||||||
print 'or even better:'
|
print('- get a full archive at http://gogs.velt.biz/velt.biz/MyMonPlugins/releases')
|
||||||
print 'get a full archive at http://gogs.velt.biz/velt.biz/MyMonPlugins/releases'
|
print('- or a master snapshot at http://gogs.velt.biz/velt.biz/MyMonPlugins/archive/master.tar.gz\n')
|
||||||
print 'or a master snapshot at http://gogs.velt.biz/velt.biz/MyMonPlugins/archive/master.tar.gz\n'
|
|
||||||
sys.exit(127)
|
sys.exit(127)
|
||||||
|
|
||||||
|
|
||||||
|
@ -98,10 +98,10 @@ def run_command(cmdline, needs_sudo=False):
|
||||||
(sout,serr) = cmd.communicate()
|
(sout,serr) = cmd.communicate()
|
||||||
plugin.verbose(2, 'Runtime %.3fs' % (time.time() - tstart, ) )
|
plugin.verbose(2, 'Runtime %.3fs' % (time.time() - tstart, ) )
|
||||||
|
|
||||||
sout = sout.rstrip().split('\n')
|
sout = sout.rstrip().decode('utf-8').split('\n')
|
||||||
if sout == ['']:
|
if sout == ['']:
|
||||||
sout = []
|
sout = []
|
||||||
serr = serr.rstrip().split('\n')
|
serr = serr.rstrip().decode('utf-8').split('\n')
|
||||||
if serr == ['']:
|
if serr == ['']:
|
||||||
serr = []
|
serr = []
|
||||||
|
|
||||||
|
@ -145,7 +145,7 @@ elif rc not in [0, 6]:
|
||||||
action = {'remove':[], 'update':[], 'install':[], 'configure':[]}
|
action = {'remove':[], 'update':[], 'install':[], 'configure':[]}
|
||||||
arch = {}
|
arch = {}
|
||||||
repo = {}
|
repo = {}
|
||||||
downby = 0L
|
downby = 0
|
||||||
|
|
||||||
for line in sout:
|
for line in sout:
|
||||||
cols = line.split(' ')
|
cols = line.split(' ')
|
||||||
|
@ -169,9 +169,9 @@ for line in sout:
|
||||||
|
|
||||||
# Count bytes to download
|
# Count bytes to download
|
||||||
if len(cols) == 5:
|
if len(cols) == 5:
|
||||||
downby += long(cols[4])
|
downby += int(cols[4])
|
||||||
else:
|
else:
|
||||||
downby += long(cols[5])
|
downby += int(cols[5])
|
||||||
|
|
||||||
if len(sout) == 0:
|
if len(sout) == 0:
|
||||||
plugin.remember_check('Updates', plugin.RETURNCODE['OK'], 'Everything uptodate')
|
plugin.remember_check('Updates', plugin.RETURNCODE['OK'], 'Everything uptodate')
|
||||||
|
@ -184,7 +184,7 @@ else:
|
||||||
l = len(pkgs)
|
l = len(pkgs)
|
||||||
out.append('%s package%s to %s' % (l, l != 1 and 's' or '', act) )
|
out.append('%s package%s to %s' % (l, l != 1 and 's' or '', act) )
|
||||||
l and multiline.append('%s(%s): %s' % (act, l, ', '.join(pkgs)) )
|
l and multiline.append('%s(%s): %s' % (act, l, ', '.join(pkgs)) )
|
||||||
for act in action.keys():
|
for act in list(action.keys()):
|
||||||
pkgs = action.pop(act)
|
pkgs = action.pop(act)
|
||||||
pkgs.sort()
|
pkgs.sort()
|
||||||
l = len(pkgs)
|
l = len(pkgs)
|
||||||
|
@ -196,9 +196,9 @@ else:
|
||||||
out += ' - %s to download' % plugin.value_to_human_binary(downby, 'B')
|
out += ' - %s to download' % plugin.value_to_human_binary(downby, 'B')
|
||||||
|
|
||||||
stats = 'Statistics: '
|
stats = 'Statistics: '
|
||||||
for (k, v) in arch.iteritems():
|
for (k, v) in arch.items():
|
||||||
stats += '%sx %s, ' % (v, k)
|
stats += '%sx %s, ' % (v, k)
|
||||||
for (k, v) in repo.iteritems():
|
for (k, v) in repo.items():
|
||||||
stats += '%s from %s, ' % (v, k)
|
stats += '%s from %s, ' % (v, k)
|
||||||
multiline.append(stats[:-2])
|
multiline.append(stats[:-2])
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue