├── .editorconfig ├── .gitignore ├── .travis.yml ├── AUTHORS.rst ├── CONTRIBUTING.rst ├── HISTORY.rst ├── LICENSE ├── MANIFEST.in ├── Makefile ├── README.rst ├── Vagrantfile ├── check_pa ├── __init__.py ├── check_paloalto.py ├── modules │ ├── __init__.py │ ├── certificate.py │ ├── diskspace.py │ ├── environmental.py │ ├── load.py │ ├── sessioninfo.py │ ├── thermal.py │ ├── throughput.py │ └── useragent.py ├── utils.py └── xml_reader.py ├── docs ├── Makefile ├── authors.rst ├── check_pa.modules.rst ├── check_pa.rst ├── conf.py ├── configuration.rst ├── contributing.rst ├── history.rst ├── index.rst ├── installation.rst ├── make.bat ├── modules.rst ├── readme.rst └── usage.rst ├── requirements.txt ├── setup.cfg ├── setup.py ├── tests ├── conftest.py ├── test_alarm.py ├── test_certificate.py ├── test_check_paloalto.py ├── test_diskspace.py ├── test_load.py ├── test_sessioninfo.py ├── test_thermal.py ├── test_throughput.py ├── test_useragent.py ├── test_xml_reader.py ├── utils.py └── xml │ ├── certificates.xml │ ├── diskspace.xml │ ├── environmentals_alarms.xml │ ├── environmentals_ok.xml │ ├── error.xml │ ├── load.xml │ ├── mock_result.xml │ ├── not_authorized.xml │ ├── thermal.xml │ ├── throughput1.xml │ ├── throughput2.xml │ ├── throughput3.xml │ ├── useragent_changed_format.xml │ ├── useragent_last_heared.xml │ ├── useragent_no_connection.xml │ └── useragent_ok.xml └── tox.ini /.editorconfig: -------------------------------------------------------------------------------- 1 | # http://editorconfig.org 2 | 3 | root = true 4 | 5 | [*] 6 | indent_style = space 7 | indent_size = 4 8 | trim_trailing_whitespace = true 9 | insert_final_newline = true 10 | charset = utf-8 11 | end_of_line = lf 12 | 13 | [*.bat] 14 | indent_style = tab 15 | end_of_line = crlf 16 | 17 | [LICENSE] 18 | insert_final_newline = false 19 | 20 | [Makefile] 21 | indent_style = tab 22 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.py[cod] 2 | 3 | # C extensions 4 | *.so 5 | 6 | # Packages 7 | *.egg 8 | *.egg-info 9 | dist 10 | build 11 | eggs 12 | parts 13 | bin 14 | var 15 | sdist 16 | develop-eggs 17 | .installed.cfg 18 | lib 19 | lib64 20 | 21 | # Installer logs 22 | pip-log.txt 23 | 24 | # Unit test / coverage reports 25 | .coverage 26 | .tox 27 | nosetests.xml 28 | htmlcov 29 | 30 | # Translations 31 | *.mo 32 | 33 | # Mr Developer 34 | .mr.developer.cfg 35 | .project 36 | .pydevproject 37 | 38 | # Complexity 39 | output/*.html 40 | output/*/index.html 41 | 42 | # Sphinx 43 | docs/_build 44 | 45 | ### JetBrains template 46 | # Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio 47 | 48 | *.iml 49 | 50 | ## Directory-based project format: 51 | .idea/ 52 | # if you remove the above rule, at least ignore the following: 53 | 54 | # User-specific stuff: 55 | # .idea/workspace.xml 56 | # .idea/tasks.xml 57 | # .idea/dictionaries 58 | 59 | # Sensitive or high-churn files: 60 | # .idea/dataSources.ids 61 | # .idea/dataSources.xml 62 | # .idea/sqlDataSources.xml 63 | # .idea/dynamic.xml 64 | # .idea/uiDesigner.xml 65 | 66 | # Gradle: 67 | # .idea/gradle.xml 68 | # .idea/libraries 69 | 70 | # Mongo Explorer plugin: 71 | # .idea/mongoSettings.xml 72 | 73 | ## File-based project format: 74 | *.ipr 75 | *.iws 76 | 77 | ## Plugin-specific files: 78 | 79 | # IntelliJ 80 | /out/ 81 | 82 | # mpeltonen/sbt-idea plugin 83 | .idea_modules/ 84 | 85 | # JIRA plugin 86 | atlassian-ide-plugin.xml 87 | 88 | # Crashlytics plugin (for Android Studio and IntelliJ) 89 | com_crashlytics_export_strings.xml 90 | crashlytics.properties 91 | crashlytics-build.properties 92 | ### Vagrant template 93 | .vagrant/ 94 | ### JetBrains template 95 | # Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and Webstorm 96 | # Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 97 | 98 | # User-specific stuff: 99 | .idea/workspace.xml 100 | .idea/tasks.xml 101 | 102 | # Sensitive or high-churn files: 103 | .idea/dataSources/ 104 | .idea/dataSources.ids 105 | .idea/dataSources.xml 106 | .idea/dataSources.local.xml 107 | .idea/sqlDataSources.xml 108 | .idea/dynamic.xml 109 | .idea/uiDesigner.xml 110 | 111 | # Gradle: 112 | .idea/gradle.xml 113 | .idea/libraries 114 | 115 | # Mongo Explorer plugin: 116 | .idea/mongoSettings.xml 117 | 118 | ## File-based project format: 119 | 120 | ## Plugin-specific files: 121 | 122 | # IntelliJ 123 | 124 | # mpeltonen/sbt-idea plugin 125 | 126 | # JIRA plugin 127 | 128 | # Crashlytics plugin (for Android Studio and IntelliJ) 129 | fabric.properties 130 | 131 | *.log 132 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: python 2 | python: 3.5 3 | 4 | env: 5 | - TOXENV=py35 6 | - TOXENV=py34 7 | - TOXENV=py33 8 | - TOXENV=py27 9 | - TOXENV=pypy 10 | 11 | install: pip install -U tox 12 | 13 | script: tox -e ${TOXENV} 14 | 15 | after_success: 16 | - coveralls 17 | -------------------------------------------------------------------------------- /AUTHORS.rst: -------------------------------------------------------------------------------- 1 | ======= 2 | Credits 3 | ======= 4 | 5 | Development Lead 6 | ---------------- 7 | 8 | * Ralph Offinger 9 | 10 | Contributors 11 | ------------ 12 | 13 | * Thomas Fischer 14 | -------------------------------------------------------------------------------- /CONTRIBUTING.rst: -------------------------------------------------------------------------------- 1 | ============ 2 | Contributing 3 | ============ 4 | 5 | Contributions are welcome, and they are greatly appreciated! Every 6 | little bit helps, and credit will always be given. 7 | 8 | You can contribute in many ways: 9 | 10 | Types of Contributions 11 | ---------------------- 12 | 13 | Report Bugs 14 | ~~~~~~~~~~~ 15 | 16 | Report bugs at https://github.com/ralph-hm/nagios_check_paloalto/issues. 17 | 18 | If you are reporting a bug, please include: 19 | 20 | * Your operating system name and version. 21 | * Any details about your local setup that might be helpful in troubleshooting. 22 | * Detailed steps to reproduce the bug. 23 | 24 | Fix Bugs 25 | ~~~~~~~~ 26 | 27 | Look through the GitHub issues for bugs. Anything tagged with "bug" 28 | is open to whoever wants to implement it. 29 | 30 | Implement Features 31 | ~~~~~~~~~~~~~~~~~~ 32 | 33 | Look through the GitHub issues for features. Anything tagged with "feature" 34 | is open to whoever wants to implement it. 35 | 36 | Write Documentation 37 | ~~~~~~~~~~~~~~~~~~~ 38 | 39 | nagios_check_paloalto could always use more documentation, whether as part of the 40 | official nagios_check_paloalto docs, in docstrings, or even on the web in blog posts, 41 | articles, and such. 42 | 43 | Submit Feedback 44 | ~~~~~~~~~~~~~~~ 45 | 46 | The best way to send feedback is to file an issue at https://github.com/ralph-hm/nagios_check_paloalto/issues. 47 | 48 | If you are proposing a feature: 49 | 50 | * Explain in detail how it would work. 51 | * Keep the scope as narrow as possible, to make it easier to implement. 52 | * Remember that this is a volunteer-driven project, and that contributions 53 | are welcome :) 54 | 55 | Get Started! 56 | ------------ 57 | 58 | Ready to contribute? Here's how to set up `nagios_check_paloalto` for local development. 59 | 60 | 1. Fork the `nagios_check_paloalto` repo on GitHub. 61 | 2. Clone your fork locally:: 62 | 63 | $ git clone git@github.com:your_name_here/nagios_check_paloalto.git 64 | 65 | 3. Install your local copy into a virtualenv. Assuming you have virtualenvwrapper installed, this is how you set up your fork for local development:: 66 | 67 | $ mkvirtualenv nagios_check_paloalto 68 | $ cd nagios_check_paloalto/ 69 | $ python setup.py develop 70 | 71 | 4. Create a branch for local development:: 72 | 73 | $ git checkout -b name-of-your-bugfix-or-feature 74 | 75 | Now you can make your changes locally. 76 | 77 | 5. When you're done making changes, check that your changes pass flake8 and the tests, including testing other Python versions with tox:: 78 | 79 | $ make test-all 80 | 81 | To get flake8 and tox, just pip install them into your virtualenv. 82 | 83 | 6. Commit your changes and push your branch to GitHub:: 84 | 85 | $ git add . 86 | $ git commit -m "Your detailed description of your changes." 87 | $ git push origin name-of-your-bugfix-or-feature 88 | 89 | 7. Submit a pull request through the GitHub website. 90 | 91 | Virtual development environment 92 | ------------------------------- 93 | 94 | You can use Vagrant to start a virtual development environment, where all the necessary dependencies are already installed. 95 | 96 | Please have a look at the Vagrantfile. 97 | 98 | Pull Request Guidelines 99 | ----------------------- 100 | 101 | Before you submit a pull request, check that it meets these guidelines: 102 | 103 | 1. The pull request should include tests. 104 | 2. If the pull request adds functionality, the docs should be updated. Put 105 | your new functionality into a function with a docstring, and add the 106 | feature to the list in README.rst. 107 | 3. The pull request should work for Python 2.6, 2.7, 3.3, and 3.4, and for PyPy. Check 108 | https://travis-ci.org/ralph-hm/nagios_check_paloalto/pull_requests 109 | and make sure that the tests pass for all supported Python versions. 110 | -------------------------------------------------------------------------------- /HISTORY.rst: -------------------------------------------------------------------------------- 1 | .. :changelog: 2 | 3 | History 4 | ------- 5 | 0.3.2 (2017-16-05) 6 | ------------------ 7 | * Fixed issue #8: Measuring throughput on multiple identically configured PA's fails 8 | 9 | 0.3.1 (2017-10-03) 10 | ------------------ 11 | 12 | * Improvement: It is no longer necessary to reset the internal cookie when upgrading PA. 13 | * Renamed performance data label for throughput command. 14 | * Removed the the unit of measurement (UOM) for throughput command 15 | 16 | 0.3 (2017-27-02) 17 | ---------------- 18 | 19 | * Support for Python 3.5 added 20 | * Minor code improvements 21 | * Changed the the unit of measurement (UOM) according to official Nagios-Documentation (thanks to Ios77) 22 | 23 | 0.1.6 (2016-06-05) 24 | ------------------ 25 | 26 | * Added script version switch 27 | * Improved error handling 28 | * Updated documentation 29 | * Upgraded dependencies 30 | 31 | 0.1.5 (2016-29-04) 32 | ------------------ 33 | 34 | * Fixed a argparse bug 35 | 36 | 37 | 0.1.4 (2016-29-04) 38 | ------------------ 39 | 40 | * Added functionality to monitor state of the user-agents 41 | * Added script timeout switch 42 | * Improved error handling 43 | * Improved functionality of sessinfo command 44 | 45 | 46 | 0.1.3 (2015-14-09) 47 | ------------------ 48 | 49 | * Disabled warnings for insecure requests to support older installations: 50 | https://urllib3.readthedocs.org/en/latest/security.html 51 | 52 | 53 | 0.1.2 (2015-14-09) 54 | ------------------ 55 | 56 | * Fixed a bug for parsing args in python3. 57 | * Enabled warnings for insecure requests: 58 | https://urllib3.readthedocs.org/en/latest/security.html 59 | * Changed format for setup.cfg. 60 | * Updated docs. 61 | 62 | 63 | 0.1.1 (2015-10-09) 64 | ------------------ 65 | 66 | * Support Python 2.7, 3.3, 3.4. 67 | * Support PyPi. 68 | * Included tests. 69 | * Improved performance. 70 | * Improved output and debugging. 71 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright [yyyy] [name of copyright owner] 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /MANIFEST.in: -------------------------------------------------------------------------------- 1 | include AUTHORS.rst 2 | include CONTRIBUTING.rst 3 | include HISTORY.rst 4 | include LICENSE 5 | include README.rst 6 | 7 | recursive-include tests * 8 | recursive-exclude * __pycache__ 9 | recursive-exclude * *.py[co] 10 | 11 | recursive-include docs *.rst conf.py Makefile make.bat 12 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | .PHONY: clean-pyc clean-build docs clean 2 | define BROWSER_PYSCRIPT 3 | import os, webbrowser, sys 4 | try: 5 | from urllib import pathname2url 6 | except: 7 | from urllib.request import pathname2url 8 | 9 | webbrowser.open("file://" + pathname2url(os.path.abspath(sys.argv[1]))) 10 | endef 11 | export BROWSER_PYSCRIPT 12 | BROWSER := python -c "$$BROWSER_PYSCRIPT" 13 | 14 | help: 15 | @echo "clean - remove all build, test, coverage and Python artifacts" 16 | @echo "clean-build - remove build artifacts" 17 | @echo "clean-pyc - remove Python file artifacts" 18 | @echo "clean-test - remove test and coverage artifacts" 19 | @echo "lint - check style with flake8" 20 | @echo "test - run tests quickly with the default Python" 21 | @echo "test-all - run tests on every Python version with tox" 22 | @echo "coverage - check code coverage quickly with the default Python" 23 | @echo "docs - generate Sphinx HTML documentation, including API docs" 24 | @echo "release - package and upload a release" 25 | @echo "dist - package" 26 | @echo "install - install the package to the active Python's site-packages" 27 | 28 | clean: clean-build clean-pyc clean-test ## remove all build, test, coverage and Python artifacts 29 | 30 | clean-build: ## remove build artifacts 31 | rm -fr build/ 32 | rm -fr dist/ 33 | rm -fr .eggs/ 34 | find . -name '*.egg-info' -exec rm -fr {} + 35 | find . -name '*.egg' -exec rm -f {} + 36 | 37 | clean-pyc: ## remove Python file artifacts 38 | find . -name '*.pyc' -exec rm -f {} + 39 | find . -name '*.pyo' -exec rm -f {} + 40 | find . -name '__pycache__' -exec rm -fr {} + 41 | 42 | clean-test: ## remove test and coverage artifacts 43 | rm -fr .tox/ 44 | rm -f .coverage 45 | rm -fr .cache 46 | rm -fr htmlcov/ 47 | 48 | lint: 49 | flake8 check_pa tests 50 | 51 | test: 52 | py.test 53 | 54 | test-all: 55 | tox 56 | 57 | coverage: 58 | py.test --cov=check_pa tests/ 59 | 60 | docs: 61 | rm -f docs/check_pa.rst 62 | rm -f docs/modules.rst 63 | sphinx-apidoc -o docs/ check_pa 64 | $(MAKE) -C docs clean 65 | $(MAKE) -C docs html 66 | $(BROWSER) docs/_build/html/index.html 67 | 68 | release: clean 69 | python setup.py sdist upload 70 | python setup.py bdist_wheel upload 71 | 72 | dist: clean 73 | python setup.py sdist 74 | python setup.py bdist_wheel 75 | ls -l dist 76 | 77 | install: clean 78 | pip install -r requirements.txt 79 | -------------------------------------------------------------------------------- /README.rst: -------------------------------------------------------------------------------- 1 | ============================================= 2 | nagios_check_paloalto: a Nagios/Icinga Plugin 3 | ============================================= 4 | nagios_check_paloalto is a **Nagios/Icinga plugin** for Palo Alto Next Generation Firewalls. 5 | It is written in Python and based on the PA REST API. 6 | 7 | Tested on: 8 | 9 | - PA-500 v6.0.1 - v6.0.9 10 | - PA-3050 v6.0.9 - 7.1.9 11 | 12 | .. image:: https://travis-ci.org/ralph-hm/nagios_check_paloalto.svg?branch=master 13 | :target: https://travis-ci.org/ralph-hm/nagios_check_paloalto?branch=master 14 | 15 | .. image:: https://coveralls.io/repos/github/ralph-hm/nagios_check_paloalto/badge.svg?branch=master 16 | :target: https://coveralls.io/github/ralph-hm/nagios_check_paloalto?branch=master 17 | 18 | .. image:: https://badge.fury.io/py/check_paloalto.svg 19 | :target: https://badge.fury.io/py/check_paloalto 20 | 21 | Documentation 22 | ------------- 23 | http://nagios-check-paloalto.readthedocs.org/en/latest/ 24 | 25 | Quickstart 26 | ---------- 27 | Please make sure you have python-dev and libxslt1-dev installed on your machine. 28 | 29 | To install nagios_check_paloalto:: 30 | 31 | $ pip install check_paloalto --upgrade 32 | 33 | or use:: 34 | 35 | $ pip3 install check_paloalto --upgrade 36 | 37 | The plugin requires a token to get information from the PA-REST-API. Please see the following link for more information: 38 | http://nagios-check-paloalto.readthedocs.org/en/latest/configuration.html#token 39 | 40 | Usage 41 | ----- 42 | Command-line usage:: 43 | 44 | usage: check_paloalto [-h] -H HOST -T TOKEN [-v] [-t TIMEOUT] [--reset] 45 | [--version] 46 | {diskspace,certificates,load,useragent,environmental,sessinfo,thermal,throughput} 47 | ... 48 | 49 | positional arguments: 50 | {diskspace,certificates,load,useragent,environmental,sessinfo,thermal,throughput} 51 | diskspace check used diskspace. 52 | certificates check the certificate store for expiring certificates: 53 | Outputs is a warning, if a certificate is in range. 54 | load check the CPU load. 55 | useragent check for running useragents. 56 | environmental check if an alarm is found. 57 | sessinfo check important session parameters. 58 | thermal check the temperature. 59 | throughput check the throughput. 60 | 61 | optional arguments: 62 | -h, --help show this help message and exit 63 | 64 | Connection: 65 | -H HOST, --host HOST PaloAlto Server Hostname 66 | -T TOKEN, --token TOKEN 67 | Generated Token for REST-API access 68 | 69 | Debug: 70 | -v, --verbose increase output verbosity (use up to 3 times) 71 | -t TIMEOUT, --timeout TIMEOUT 72 | abort check execution after so many seconds (use 0 for 73 | no timeout) 74 | --reset Deletes the cookie file for the throughput check. 75 | 76 | Info: 77 | --version show program's version number and exit 78 | 79 | -------------------------------------------------------------------------------- /Vagrantfile: -------------------------------------------------------------------------------- 1 | Vagrant.configure(2) do |config| 2 | config.vm.box = "ubuntu/xenial64" 3 | 4 | config.vm.provider "virtualbox" do |vb| 5 | vb.memory = "1024" 6 | end 7 | 8 | config.vm.provision "shell", inline: <<-SHELL 9 | sudo apt-get install python-software-properties -y 10 | sudo add-apt-repository ppa:fkrull/deadsnakes -y 11 | sudo apt-get update 12 | sudo apt-get install -y build-essential libxslt1-dev libxml2-dev python-dev python3-dev libz-dev python3.3 python3.4 python3.3-dev python3.4-dev python-sphinx 13 | wget https://bootstrap.pypa.io/get-pip.py 14 | python get-pip.py 15 | SHELL 16 | end 17 | -------------------------------------------------------------------------------- /check_pa/__init__.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | __author__ = 'Ralph Offinger' 4 | __email__ = 'ralph.offinger@gmail.com' 5 | __version__ = '0.3.2' 6 | -------------------------------------------------------------------------------- /check_pa/check_paloalto.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | import argparse 3 | import sys 4 | import nagiosplugin 5 | 6 | sys.path.append('modules') 7 | 8 | from check_pa.modules import certificate, throughput, diskspace, useragent, environmental, sessioninfo, thermal, load 9 | 10 | 11 | @nagiosplugin.guarded 12 | def main(): # pragma: no cover 13 | args = parse_args(sys.argv[1:]) 14 | if args.reset: 15 | throughput.reset() 16 | else: 17 | check = args.func.create_check(args) 18 | check.main(verbose=args.verbose, timeout=args.timeout) 19 | 20 | 21 | def parse_args(args): 22 | parser = argparse.ArgumentParser(description=__doc__) 23 | 24 | connection = parser.add_argument_group('Connection') 25 | connection.add_argument('-H', '--host', 26 | help='PaloAlto Server Hostname', 27 | required=True) 28 | connection.add_argument('-T', '--token', 29 | help='Generated Token for REST-API access', 30 | required=True) 31 | 32 | debug = parser.add_argument_group('Debug') 33 | debug.add_argument('-v', '--verbose', action='count', default=0, 34 | help='increase output verbosity (use up to 3 times)') 35 | debug.add_argument('-t', '--timeout', default=10, 36 | help='abort check execution after so many seconds (use 0 for no timeout)') 37 | debug.add_argument('--reset', action='store_true', help='Deletes the cookie file for the throughput check.') 38 | 39 | info = parser.add_argument_group('Info') 40 | info.add_argument('--version', action='version', 41 | version='%(prog)s 0.3.2') 42 | 43 | subparsers = parser.add_subparsers(dest='command') 44 | subparsers.required = True 45 | 46 | # Sub-Parser for command 'diskspace'. 47 | parser_diskspace = subparsers.add_parser('diskspace', 48 | help='check used diskspace.', 49 | ) 50 | parser_diskspace.add_argument('-w', '--warn', 51 | metavar='WARN', type=int, default=85, 52 | help='Warning if diskspace is greater. ' 53 | '(default: %(default)s)') 54 | parser_diskspace.add_argument('-c', '--crit', 55 | metavar='CRIT', type=int, default=95, 56 | help='Critical if disksace is greater. ' 57 | '(default: %(default)s)') 58 | 59 | parser_diskspace.set_defaults(func=diskspace) 60 | 61 | # Sub-Parser for command 'certificates'. 62 | parser_certificates = subparsers.add_parser( 63 | 'certificates', 64 | help='check the certificate store for ' 65 | 'expiring certificates: Outputs is a warning, ' 66 | 'if a certificate is in range.') 67 | parser_certificates.add_argument( 68 | '-ex', '--exclude', default='', help='exclude certificates from ' 69 | 'check by name.') 70 | parser_certificates.add_argument( 71 | '-r', '--range', 72 | metavar='RANGE', 73 | default='0:20', 74 | help=''' 75 | Warning if days until certificate expiration is in range: 76 | Represents a threshold range. 77 | The general format is "[@][start:][end] 78 | (default: %(default)s) 79 | ''') 80 | parser_certificates.set_defaults(func=certificate) 81 | 82 | # Sub-Parser for command 'load'. 83 | parser_load = subparsers.add_parser( 84 | 'load', 85 | help='check the CPU load.') 86 | parser_load.add_argument( 87 | '-w', '--warn', 88 | metavar='WARN', type=int, default=85, 89 | help='Warning if CPU load is greater. (default: %(default)s)') 90 | parser_load.add_argument( 91 | '-c', '--crit', 92 | metavar='CRIT', type=int, default=95, 93 | help='Critical if CPU load is greater. (default: %(default)s)') 94 | parser_load.set_defaults(func=load) 95 | 96 | # Sub-Parser for command 'useragent'. 97 | parser_useragent = subparsers.add_parser( 98 | 'useragent', 99 | help='check for running useragents.') 100 | parser_useragent.add_argument( 101 | '-w', '--warn', 102 | metavar='WARN', type=int, default=60, 103 | help='Warning if agent is not responding for a given amount of seconds. (default: %(default)s)') 104 | parser_useragent.add_argument( 105 | '-c', '--crit', 106 | metavar='CRIT', type=int, default=240, 107 | help='Critical if agent is not responding for a given amount of seconds. (default: %(default)s)') 108 | parser_useragent.set_defaults(func=useragent) 109 | 110 | # Sub-Parser for command 'environmental'. 111 | parser_environmental = subparsers.add_parser( 112 | 'environmental', 113 | help='check if an alarm is found.') 114 | parser_environmental.set_defaults(func=environmental) 115 | 116 | # Sub-Parser for command 'sessinfo'. 117 | parser_sessinfo = subparsers.add_parser( 118 | 'sessinfo', 119 | help='check important session parameters.') 120 | parser_sessinfo.add_argument( 121 | '-w', '--warn', 122 | metavar='WARN', type=int, default=20000, 123 | help='Warning if number of sessions is greater. (default: %(default)s)') 124 | parser_sessinfo.add_argument( 125 | '-c', '--crit', 126 | metavar='CRIT', type=int, default=50000, 127 | help='Critical if number of sessions is greater. (default: %(default)s)') 128 | parser_sessinfo.set_defaults(func=sessioninfo) 129 | 130 | # Sub-Parser for command 'thermal'. 131 | parser_thermal = subparsers.add_parser( 132 | 'thermal', 133 | help='check the temperature.') 134 | parser_thermal.add_argument( 135 | '-w', '--warn', 136 | metavar='WARN', type=int, default=40, 137 | help='Warning if temperature is greater. (default: %(default)s)') 138 | parser_thermal.add_argument( 139 | '-c', '--crit', 140 | metavar='CRIT', type=int, default=45, 141 | help='Critical if temperature is greater. (default: %(default)s)') 142 | parser_thermal.set_defaults(func=thermal) 143 | 144 | # Sub-Parser for command 'throughput'. 145 | parser_throughput = subparsers.add_parser( 146 | 'throughput', 147 | help='check the throughput.') 148 | 149 | parser_throughput.add_argument( 150 | '-i', '--interface', 151 | help='PA interface name, seperate by comma.', 152 | nargs='?', 153 | required=True, 154 | ) 155 | parser_throughput.set_defaults(func=throughput) 156 | 157 | return parser.parse_args(args) 158 | 159 | 160 | if __name__ == '__main__': # pragma: no cover 161 | main() 162 | -------------------------------------------------------------------------------- /check_pa/modules/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ralph089/nagios_check_paloalto/6c439d87a5706c6ab97df39258699835040973e0/check_pa/modules/__init__.py -------------------------------------------------------------------------------- /check_pa/modules/certificate.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | import logging 4 | 5 | import nagiosplugin as np 6 | from datetime import datetime 7 | 8 | from check_pa.xml_reader import XMLReader, Finder 9 | 10 | _log = logging.getLogger('nagiosplugin') 11 | 12 | 13 | def get_now(): 14 | """ 15 | Extract method for mocking datetime.now. 16 | 17 | :return: datetime.today() object 18 | """ 19 | return datetime.today() # pragma: no cover 20 | 21 | 22 | def create_check(args): 23 | """ 24 | Creates and configures a check for the certificate command. 25 | 26 | :return: the throughput check. 27 | """ 28 | return np.Check( 29 | Certificate(args.host, args.token, args.exclude), 30 | CertificateContext('certificates', args.range), 31 | CertificateSummary(args.range)) 32 | 33 | 34 | class Certificate(np.Resource): 35 | """ 36 | Will fetch the certificates from the REST API and returns a warning if 37 | the remaining days of the certificate is between the value of warning 38 | (e. g. 20) and critical (e. g. 0). 39 | 40 | If a certificate has been revoked or excluded, no warning will appear. 41 | """ 42 | 43 | def __init__(self, host, token, exclude): 44 | self.host = host 45 | self.token = token 46 | self.cmd = '' \ 47 | 'shared/certificate' \ 48 | '' 49 | self.xml_obj = XMLReader(self.host, self.token, self.cmd) 50 | self.exclude = str(exclude).split(",") 51 | 52 | def probe(self): 53 | """ 54 | Querys the REST-API and create certificate metrics. 55 | 56 | :return: a certificate metric. 57 | """ 58 | _log.info('Reading XML from: %s', self.xml_obj.build_request_url()) 59 | soup = self.xml_obj.read() 60 | 61 | certificates = soup.find_all('entry') 62 | 63 | for certificate in certificates: 64 | not_valid_after = Finder.find_item(certificate, 65 | 'not-valid-after').replace( 66 | "GMT", "").strip() 67 | date_object = datetime.strptime(not_valid_after, '%b %d %H:%M:%S %Y') 68 | difference = date_object - get_now() 69 | _log.debug('Certificate %s difference: %s days' % ( 70 | certificate.get('name'), difference.days)) 71 | try: 72 | status = Finder.find_item(certificate, 'status') 73 | except np.CheckError: 74 | status = "" 75 | if certificate.get('name') not in self.exclude: 76 | if status != "revoked": 77 | yield np.Metric(certificate.get('name'), difference.days, 78 | context='certificates') 79 | 80 | 81 | class CertificateContext(np.Context): 82 | def __init__(self, name, r, 83 | fmt_metric='{name} expires in {valueunit}', 84 | result_cls=np.Result): 85 | super(CertificateContext, self).__init__(name, fmt_metric, result_cls) 86 | self.r = np.Range(r) 87 | 88 | def evaluate(self, metric, resource): 89 | """Output depending on given start and end range. 90 | 91 | Returns a warning, if a certificate is between given start and end 92 | range. 93 | Returns ok, if a certificate is out of range. 94 | 95 | :param metric: 96 | :param resource: 97 | :return: 98 | """ 99 | if self.r.match(metric.value): 100 | return self.result_cls(np.Warn, None, metric) 101 | else: 102 | return self.result_cls(np.Ok, None, metric) 103 | 104 | 105 | class CertificateSummary(np.Summary): 106 | def __init__(self, r): 107 | self.r = np.Range(r) 108 | 109 | def ok(self, results): 110 | l = [] 111 | for result in results: 112 | l.append(result.metric.value) 113 | output = 'The next certificate will expire in %s days.' % min(l) 114 | return str(output) 115 | 116 | def problem(self, results): 117 | l = [] 118 | for result in results: 119 | if self.r.match(result.metric.value): 120 | l.append(str(result) + ' days') 121 | output = ", ".join(l) 122 | return str(output) 123 | -------------------------------------------------------------------------------- /check_pa/modules/diskspace.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | import logging 4 | import re 5 | 6 | import nagiosplugin as np 7 | 8 | from check_pa.xml_reader import XMLReader 9 | 10 | _log = logging.getLogger('nagiosplugin') 11 | 12 | 13 | def create_check(args): 14 | """ 15 | Creates and configures a check for the diskspace command. 16 | 17 | :return: the diskspace check. 18 | """ 19 | return np.Check( 20 | DiskSpace(args.host, args.token), 21 | np.ScalarContext('diskspace', args.warn, args.crit), 22 | DiskSpaceSummary()) 23 | 24 | 25 | class DiskSpace(np.Resource): 26 | """Reads the used disk space of the Palo Alto Firewall System.""" 27 | 28 | def __init__(self, host, token): 29 | self.host = host 30 | self.token = token 31 | self.cmd = '<%2Fdisk-space><%2Fsystem' \ 32 | '><%2Fshow>' 33 | self.xml_obj = XMLReader(self.host, self.token, self.cmd) 34 | 35 | def probe(self): 36 | """ 37 | Querys the REST-API and create disk space metrics. 38 | 39 | :return: a disk space metric. 40 | """ 41 | _log.info('Reading XML from: %s', self.xml_obj.build_request_url()) 42 | soup = self.xml_obj.read() 43 | available_hdds = re.findall('(sda\d.*?)(?=/)', soup.result.string) 44 | for hdd in available_hdds: 45 | sda = re.findall('(sda\d)', hdd)[0] 46 | percent = int(re.findall('([0-9]+%)', hdd)[0].replace("%", "")) 47 | yield np.Metric(sda, percent, '%', context='diskspace') 48 | 49 | 50 | class DiskSpaceSummary(np.Summary): 51 | """Create status line from results.""" 52 | 53 | def ok(self, results): 54 | l = [] 55 | for sda in results.results: 56 | s = '%s: %s%%' % (sda.metric.name, sda.metric.value) 57 | l.append(s) 58 | _log.debug('HDD count: %d' % len(l)) 59 | output = ", ".join(l) 60 | return str(output) 61 | 62 | def problem(self, results): 63 | return '%s' % (str(results.first_significant)) 64 | -------------------------------------------------------------------------------- /check_pa/modules/environmental.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | import logging 4 | 5 | import nagiosplugin as np 6 | 7 | from check_pa.xml_reader import XMLReader 8 | 9 | _log = logging.getLogger('nagiosplugin') 10 | 11 | 12 | def create_check(args): 13 | """ 14 | Creates and configures a check for the environmental command. 15 | 16 | :return: the environmental check. 17 | """ 18 | return np.Check( 19 | Environmental(args.host, args.token), 20 | EnvironmentalContext('alarm'), 21 | EnvironmentalSummary()) 22 | 23 | 24 | class Environmental(np.Resource): 25 | """Reads the used disk space of the Palo Alto Firewall System.""" 26 | 27 | def __init__(self, host, token): 28 | self.host = host 29 | self.token = token 30 | self.cmd = '' \ 31 | '' 32 | self.xml_obj = XMLReader(self.host, self.token, self.cmd) 33 | 34 | def probe(self): 35 | """ 36 | Querys the REST-API and create disk space metrics. 37 | 38 | :return: a disk space metric. 39 | """ 40 | _log.info('Reading XML from: %s', self.xml_obj.build_request_url()) 41 | soup = self.xml_obj.read() 42 | entrys = soup.find_all('entry') 43 | for entry in entrys: 44 | if entry.alarm.text == 'True': 45 | _log.debug('Alarm found: %s' % entry.description) 46 | yield np.Metric(entry.description.text, True, context='alarm') 47 | yield np.Metric(entry.description.text, False, context='alarm') 48 | 49 | 50 | class EnvironmentalContext(np.Context): 51 | def __init__(self, name, fmt_metric='{name} is {valueunit}', 52 | result_cls=np.Result): 53 | super(EnvironmentalContext, self).__init__(name, fmt_metric, 54 | result_cls) 55 | 56 | def evaluate(self, metric, resource): 57 | if not metric.value: 58 | return self.result_cls(np.Ok, None, metric) 59 | else: 60 | return self.result_cls(np.Critical, None, metric) 61 | 62 | 63 | class EnvironmentalSummary(np.Summary): 64 | def ok(self, results): 65 | return 'No alarms found.' 66 | 67 | def problem(self, results): 68 | s = 'Alarm(s) found: ' 69 | l = [] 70 | for alarm in results.results: 71 | if alarm.metric.value: 72 | l.append(alarm.metric.name) 73 | s += ', '.join(l) 74 | return s 75 | -------------------------------------------------------------------------------- /check_pa/modules/load.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | import logging 4 | 5 | import nagiosplugin as np 6 | 7 | from check_pa.xml_reader import XMLReader, Finder 8 | 9 | _log = logging.getLogger('nagiosplugin') 10 | 11 | 12 | def create_check(args): 13 | """ 14 | Creates and configures a check for the load command. 15 | 16 | :return: the load check. 17 | """ 18 | return np.Check( 19 | Load(args.host, args.token), 20 | np.ScalarContext('load', args.warn, args.crit), 21 | LoadSummary()) 22 | 23 | 24 | class Load(np.Resource): 25 | def __init__(self, host, token): 26 | self.host = host 27 | self.token = token 28 | self.cmd = '1<%2Flast' \ 29 | '>' \ 30 | '<%2Fminute><%2Fresource-monitor><%2Frunning><%2Fshow>' 31 | self.xml_obj = XMLReader(self.host, self.token, self.cmd) 32 | 33 | def probe(self): 34 | """ 35 | Querys the REST-API and create load metrics. 36 | 37 | :return: a load metric. 38 | """ 39 | _log.info('Reading XML from: %s', self.xml_obj.build_request_url()) 40 | soup = self.xml_obj.read() 41 | cpuavg = soup.find('cpu-load-average') 42 | 43 | for entry in cpuavg.find_all('entry'): 44 | coreid = int(Finder.find_item(entry, 'coreid')) 45 | cpu_load = float(Finder.find_item(entry, 'value')) 46 | yield np.Metric('CPU%d' % coreid, cpu_load, '%', min=0, max=100, 47 | context='load') 48 | 49 | 50 | class LoadSummary(np.Summary): 51 | def ok(self, results): 52 | l = [] 53 | for cpu in results.results: 54 | s = '%s: %s%%' % (cpu.metric.name, cpu.metric.value) 55 | _log.debug('Add result %r', s) 56 | l.append(s) 57 | _log.debug('CPU count: %d' % len(l)) 58 | output = ", ".join(l) 59 | return str(output) 60 | -------------------------------------------------------------------------------- /check_pa/modules/sessioninfo.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | import logging 4 | 5 | import nagiosplugin as np 6 | 7 | from check_pa.xml_reader import XMLReader, Finder 8 | 9 | _log = logging.getLogger('nagiosplugin') 10 | 11 | 12 | def create_check(args): 13 | """ 14 | Creates and configures a check for the sessioninfo command. 15 | 16 | :return: the sessioninfo check. 17 | """ 18 | return np.Check( 19 | SessInfo(args.host, args.token), 20 | np.ScalarContext('session', args.warn, args.crit), 21 | np.ScalarContext('throughput'), 22 | SessSummary()) 23 | 24 | 25 | class SessInfo(np.Resource): 26 | def __init__(self, host, token): 27 | self.host = host 28 | self.token = token 29 | self.cmd = '' 30 | self.xml_obj = XMLReader(self.host, self.token, self.cmd) 31 | 32 | def probe(self): 33 | """ 34 | Querys the REST-API and create session info metrics. 35 | 36 | :return: a sessioninfo metric. 37 | """ 38 | _log.info('Reading XML from: %s', self.xml_obj.build_request_url()) 39 | soup = self.xml_obj.read() 40 | result = soup.result 41 | maxsess = int(Finder.find_item(result, 'num-max')) 42 | actsess = int(Finder.find_item(result, 'num-active')) 43 | throughput = int(Finder.find_item(result, 'kbps')) 44 | 45 | return [np.Metric('session', actsess, min=0, max=maxsess, context='session'), 46 | np.Metric('throughput_kbps', throughput, min=0, context='throughput')] 47 | 48 | 49 | class SessSummary(np.Summary): 50 | def ok(self, results): 51 | return 'Active sessions: ' + str( 52 | results['session'].metric) + ' / Throughput (kbps): ' + str( 53 | results['throughput_kbps'].metric) 54 | -------------------------------------------------------------------------------- /check_pa/modules/thermal.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | import logging 4 | 5 | import nagiosplugin as np 6 | 7 | from check_pa.xml_reader import XMLReader 8 | 9 | _log = logging.getLogger('nagiosplugin') 10 | 11 | 12 | def create_check(args): 13 | """ 14 | Creates and configures a check for the thermal command. 15 | 16 | :return: the thermal check. 17 | """ 18 | return np.Check( 19 | Thermal(args.host, args.token), 20 | np.ScalarContext('temperature', args.warn, args.crit), 21 | ThermalSummary()) 22 | 23 | 24 | class Thermal(np.Resource): 25 | def __init__(self, host, token): 26 | self.host = host 27 | self.token = token 28 | self.cmd = '' \ 29 | '' 30 | self.xml_obj = XMLReader(self.host, self.token, self.cmd) 31 | 32 | def probe(self): 33 | """ 34 | Querys the REST-API and create thermal metrics. 35 | 36 | :return: a disk space metric. 37 | """ 38 | _log.info('Reading XML from: %s', self.xml_obj.build_request_url()) 39 | soup = self.xml_obj.read() 40 | entrys = soup.find_all('entry') 41 | for entry in entrys: 42 | temp = entry.DegreesC.text 43 | _log.debug('Temperature: %s', temp) 44 | maxt = entry.max.text 45 | _log.debug('Max Temperature: %s', maxt) 46 | mint = entry.min.text 47 | _log.debug('Min Temperature: %s', mint) 48 | desc = entry.description.text 49 | _log.debug('Description: %s', desc) 50 | yield np.Metric(desc, float(temp), 51 | min=float(mint), 52 | max=float(maxt), 53 | context='temperature') 54 | 55 | 56 | class ThermalSummary(np.Summary): 57 | def ok(self, results): 58 | l = [] 59 | s = '' 60 | for temp in results.results: 61 | l.append('%s is %d degrees Celsius' % ( 62 | temp.metric.name, temp.metric.value)) 63 | s += ', '.join(l) 64 | return s 65 | 66 | def problem(self, results): 67 | """ 68 | Prints a more informative output 69 | 70 | :param results: Results container 71 | :return: status line 72 | """ 73 | return 'Too high temperature: %s degrees Celsius' % ( 74 | str(results.first_significant)) 75 | -------------------------------------------------------------------------------- /check_pa/modules/throughput.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | import logging 4 | import os 5 | import tempfile 6 | import time 7 | 8 | import nagiosplugin as np 9 | 10 | from check_pa.utils import * 11 | from check_pa.xml_reader import XMLReader, Finder 12 | 13 | _log = logging.getLogger('nagiosplugin') 14 | 15 | 16 | def get_statefile_path(): 17 | return os.path.join(tempfile.gettempdir(), 'throughput') 18 | 19 | 20 | def get_time(): 21 | """ 22 | Extract method for mocking time. 23 | 24 | :return: time.time() object 25 | """ 26 | return time.time() # pragma: no cover 27 | 28 | 29 | def create_check(args): 30 | """ 31 | Creates and configures a check for the throughput command. 32 | 33 | :return: the throughput check. 34 | """ 35 | interfaces = str(args.interface).split(",") 36 | check = np.Check() 37 | for interface in interfaces: 38 | check.add(Throughput(args.host, args.token, interface)) 39 | for interface in interfaces: 40 | check.add(np.ScalarContext('in_bps_' + interface)) 41 | for interface in interfaces: 42 | check.add(np.ScalarContext('out_bps_' + interface)) 43 | check.add(NetworkSummary()) 44 | return check 45 | 46 | 47 | def reset(): # pragma: no cover 48 | """ 49 | Removes the throughput file. 50 | """ 51 | if os.path.exists(get_statefile_path()): 52 | os.remove(os.path.join(tempfile.gettempdir(), 'throughput')) 53 | 54 | 55 | class Throughput(np.Resource): 56 | """ 57 | A throughput resource. 58 | """ 59 | 60 | def __init__(self, host, token, interface_name): 61 | self.host = host 62 | self.token = token 63 | self.interface_name = interface_name 64 | self.cmd = '' + str(self.interface_name) + '' 65 | self.xml_obj = XMLReader(self.host, self.token, self.cmd) 66 | 67 | def probe(self): 68 | """ 69 | Querys the REST-API and create throughput metrics. 70 | 71 | :return: a throughput metric. 72 | """ 73 | 74 | _log.info('Reading XML from: %s', self.xml_obj.build_request_url()) 75 | 76 | api_outbytes, api_inbytes = 0, 0 77 | 78 | current_time = get_time() 79 | soup = self.xml_obj.read() 80 | ifnet = soup.find('ifnet') 81 | 82 | for item in ifnet.find_all('entry'): 83 | api_inbytes = Finder.find_item(item, 'ibytes') 84 | api_outbytes = Finder.find_item(item, 'obytes') 85 | 86 | _log.debug('Path to statefile: %r' % get_statefile_path()) 87 | with np.Cookie(get_statefile_path()) as cookie: 88 | 89 | old_inbytes = cookie.get(self.host + self.interface_name + 'i', api_inbytes) 90 | old_outbytes = cookie.get(self.host + self.interface_name + 'o', api_outbytes) 91 | old_time = cookie.get(self.host + self.interface_name + 't', current_time) 92 | 93 | if not api_inbytes or not api_outbytes or float(api_inbytes) < 0 or float(api_outbytes) < 0: 94 | raise np.CheckError('Couldn\'t get a valid value!') 95 | 96 | cookie[self.host + self.interface_name + 'i'] = api_inbytes 97 | cookie[self.host + self.interface_name + 'o'] = api_outbytes 98 | cookie[self.host + self.interface_name + 't'] = current_time 99 | 100 | if float(api_inbytes) < float(old_inbytes) or float(api_outbytes) < float(old_outbytes): 101 | raise np.CheckError('Couldn\'t get a valid value: Found throughput less then old!') 102 | 103 | diff_time = int(current_time) - int(old_time) 104 | if diff_time > 0: 105 | in_bits_per_second = round( 106 | ((float(api_inbytes) - float(old_inbytes)) / diff_time) * 8, 2) 107 | out_bits_per_second = round( 108 | ((float(api_outbytes) - float(old_outbytes)) / diff_time) * 8, 109 | 2) 110 | else: 111 | raise np.CheckError( 112 | 'Difference between old timestamp and new timestamp is less ' 113 | 'or equal 0: If it is the first time you run the script, ' 114 | 'please execute it again!') 115 | 116 | return [ 117 | np.Metric('in_bps_' + str(self.interface_name), in_bits_per_second, 118 | min=0), 119 | np.Metric('out_bps_' + str(self.interface_name), out_bits_per_second, 120 | min=0)] 121 | 122 | 123 | class NetworkSummary(np.Summary): 124 | """ 125 | Creates a throughput summary. 126 | """ 127 | 128 | def __init__(self): 129 | pass 130 | 131 | def ok(self, results): 132 | bit_in, bit_out = 0, 0 133 | for result in results: 134 | if not str(result).find("in_bps"): 135 | bit_in += result.metric.value 136 | else: 137 | bit_out += result.metric.value 138 | return 'Input is %s Mb/s - Output is %s Mb/s' % ( 139 | str(Utils.to_mega(bit_in)), str(Utils.to_mega(bit_out))) 140 | -------------------------------------------------------------------------------- /check_pa/modules/useragent.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | import logging 4 | 5 | import nagiosplugin as np 6 | from nagiosplugin import CheckError 7 | 8 | from check_pa.xml_reader import XMLReader 9 | 10 | _log = logging.getLogger('nagiosplugin') 11 | 12 | 13 | def create_check(args): 14 | """ 15 | Creates and configures a check for the useragent command. 16 | 17 | :return: the useragent check. 18 | """ 19 | return np.Check( 20 | UserAgent(args.host, args.token), 21 | np.ScalarContext('agent_last_heared', args.warn, args.crit), 22 | UserAgentContext('agent_connected'), 23 | UserAgentSummary()) 24 | 25 | 26 | class UserAgent(np.Resource): 27 | def __init__(self, host, token): 28 | self.host = host 29 | self.token = token 30 | self.cmd = 'all' \ 31 | '' 32 | self.xml_obj = XMLReader(self.host, self.token, self.cmd) 33 | 34 | def probe(self): 35 | """ 36 | Querys the REST-API and create user agent metrics. 37 | 38 | :return: a user agent metric. 39 | """ 40 | _log.info('Reading XML from: %s', self.xml_obj.build_request_url()) 41 | soup = self.xml_obj.read() 42 | s = soup.result.string.strip() 43 | useragents = s.split('\n\n') 44 | 45 | for useragent in useragents: 46 | agent_details = useragent.split('\n') 47 | if (len(agent_details) != 31) or not (agent_details[0].startswith('Agent')): 48 | raise CheckError('Unexpected query result!') 49 | 50 | name = agent_details[0] 51 | status = agent_details[1].split(':')[1].strip() 52 | last_heared = int(agent_details[20].split(':')[1].strip()) 53 | 54 | _log.info('Checking %s ', name) 55 | _log.info('Found status %s', status) 56 | _log.info('Last heared: %i seconds ago', last_heared) 57 | 58 | yield np.Metric(name, status, context='agent_connected') 59 | yield np.Metric(name, last_heared, context='agent_last_heared') 60 | 61 | 62 | class UserAgentContext(np.Context): 63 | def __init__(self, name, fmt_metric='{name} is {valueunit}', 64 | result_cls=np.Result): 65 | super(UserAgentContext, self).__init__(name, fmt_metric, 66 | result_cls) 67 | 68 | def evaluate(self, metric, resource): 69 | if metric.value == 'conn': 70 | return self.result_cls(np.Ok, None, metric) 71 | else: 72 | return self.result_cls(np.Critical, None, metric) 73 | 74 | 75 | class UserAgentSummary(np.Summary): 76 | def ok(self, results): 77 | return 'All agents are connected and responding.' 78 | 79 | def problem(self, results): 80 | s = '' 81 | l = [] 82 | for result in results.results: 83 | if result.state == np.Warn or result.state == np.Critical: 84 | if result.metric.context == 'agent_last_heared': 85 | l.append("%s last heared: %i seconds ago" % (result.metric.name, result.metric.value)) 86 | if result.metric.context == 'agent_connected': 87 | l.append("%s connection status is %s" % (result.metric.name, result.metric.value)) 88 | s += ', '.join(l) 89 | return s 90 | -------------------------------------------------------------------------------- /check_pa/utils.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | 4 | class Utils: 5 | """ 6 | Utility class for common, often re-used functions. 7 | """ 8 | 9 | @staticmethod 10 | def to_mega(size): 11 | mega = 1000 * 1000 12 | new_size = round(size / mega, 2) 13 | return new_size 14 | -------------------------------------------------------------------------------- /check_pa/xml_reader.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | import requests 4 | from bs4 import BeautifulSoup 5 | from nagiosplugin import CheckError 6 | 7 | 8 | class XMLReader: 9 | """Extracts XML Data from Palo Alto REST API.""" 10 | 11 | def __init__(self, host, token, cmd): 12 | """Init XML Reader with required information. 13 | 14 | :param host: PaloAlto Firewall 15 | :param token: Generated token to access REST API. 16 | :param cmd: Command for the desired XML output. 17 | 18 | :return: the XMLReader object. 19 | """ 20 | self.host = host 21 | self.token = token 22 | self.cmd = cmd 23 | 24 | def read(self): 25 | """Performs a request with a given command to the XML API and reads 26 | the output. 27 | 28 | :return: The XML output parsed by soup. 29 | """ 30 | requests.packages.urllib3.disable_warnings() 31 | resp = requests.get(self.build_request_url(), verify=False) 32 | if resp.status_code != 200: 33 | raise CheckError('Expected status code: 200 (OK), returned' 34 | ' status code was: %d' % resp.status_code) 35 | soup = BeautifulSoup(resp.content, "lxml-xml") 36 | result = soup.response['status'] 37 | if result != 'success': 38 | raise CheckError('Request didn\'t succeed, result was %s' 39 | % result) 40 | return soup 41 | 42 | def build_request_url(self): 43 | """Creates the URL for a specific XML request. 44 | 45 | :return: URL. 46 | """ 47 | request_url = 'https://%s/api/?key=%s&type=op&cmd=%s' % ( 48 | self.host, self.token, self.cmd) 49 | return request_url 50 | 51 | 52 | class Finder: 53 | @staticmethod 54 | def find_item(item, s): 55 | """ 56 | Tries to find an item in a XML-structure. 57 | 58 | :param item: a tag object 59 | :param s: the search string 60 | :return: text of the first child-element found 61 | """ 62 | try: 63 | return item.find(s).text 64 | except AttributeError: 65 | raise CheckError('Couldn\'t find any matching item %s' % s) 66 | -------------------------------------------------------------------------------- /docs/Makefile: -------------------------------------------------------------------------------- 1 | # Makefile for Sphinx documentation 2 | # 3 | 4 | # You can set these variables from the command line. 5 | SPHINXOPTS = 6 | SPHINXBUILD = sphinx-build 7 | PAPER = 8 | BUILDDIR = _build 9 | 10 | # User-friendly check for sphinx-build 11 | ifeq ($(shell which $(SPHINXBUILD) >/dev/null 2>&1; echo $$?), 1) 12 | $(error The '$(SPHINXBUILD)' command was not found. Make sure you have Sphinx installed, then set the SPHINXBUILD environment variable to point to the full path of the '$(SPHINXBUILD)' executable. Alternatively you can add the directory with the executable to your PATH. If you don't have Sphinx installed, grab it from http://sphinx-doc.org/) 13 | endif 14 | 15 | # Internal variables. 16 | PAPEROPT_a4 = -D latex_paper_size=a4 17 | PAPEROPT_letter = -D latex_paper_size=letter 18 | ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . 19 | # the i18n builder cannot share the environment and doctrees with the others 20 | I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . 21 | 22 | .PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest gettext 23 | 24 | help: 25 | @echo "Please use \`make ' where is one of" 26 | @echo " html to make standalone HTML files" 27 | @echo " dirhtml to make HTML files named index.html in directories" 28 | @echo " singlehtml to make a single large HTML file" 29 | @echo " pickle to make pickle files" 30 | @echo " json to make JSON files" 31 | @echo " htmlhelp to make HTML files and a HTML help project" 32 | @echo " qthelp to make HTML files and a qthelp project" 33 | @echo " devhelp to make HTML files and a Devhelp project" 34 | @echo " epub to make an epub" 35 | @echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter" 36 | @echo " latexpdf to make LaTeX files and run them through pdflatex" 37 | @echo " latexpdfja to make LaTeX files and run them through platex/dvipdfmx" 38 | @echo " text to make text files" 39 | @echo " man to make manual pages" 40 | @echo " texinfo to make Texinfo files" 41 | @echo " info to make Texinfo files and run them through makeinfo" 42 | @echo " gettext to make PO message catalogs" 43 | @echo " changes to make an overview of all changed/added/deprecated items" 44 | @echo " xml to make Docutils-native XML files" 45 | @echo " pseudoxml to make pseudoxml-XML files for display purposes" 46 | @echo " linkcheck to check all external links for integrity" 47 | @echo " doctest to run all doctests embedded in the documentation (if enabled)" 48 | 49 | clean: 50 | rm -rf $(BUILDDIR)/* 51 | 52 | html: 53 | $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html 54 | @echo 55 | @echo "Build finished. The HTML pages are in $(BUILDDIR)/html." 56 | 57 | dirhtml: 58 | $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml 59 | @echo 60 | @echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml." 61 | 62 | singlehtml: 63 | $(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml 64 | @echo 65 | @echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml." 66 | 67 | pickle: 68 | $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle 69 | @echo 70 | @echo "Build finished; now you can process the pickle files." 71 | 72 | json: 73 | $(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json 74 | @echo 75 | @echo "Build finished; now you can process the JSON files." 76 | 77 | htmlhelp: 78 | $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp 79 | @echo 80 | @echo "Build finished; now you can run HTML Help Workshop with the" \ 81 | ".hhp project file in $(BUILDDIR)/htmlhelp." 82 | 83 | qthelp: 84 | $(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp 85 | @echo 86 | @echo "Build finished; now you can run "qcollectiongenerator" with the" \ 87 | ".qhcp project file in $(BUILDDIR)/qthelp, like this:" 88 | @echo "# qcollectiongenerator $(BUILDDIR)/qthelp/check_paloalto.qhcp" 89 | @echo "To view the help file:" 90 | @echo "# assistant -collectionFile $(BUILDDIR)/qthelp/check_paloalto.qhc" 91 | 92 | devhelp: 93 | $(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp 94 | @echo 95 | @echo "Build finished." 96 | @echo "To view the help file:" 97 | @echo "# mkdir -p $$HOME/.local/share/devhelp/check_paloalto" 98 | @echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/check_paloalto" 99 | @echo "# devhelp" 100 | 101 | epub: 102 | $(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub 103 | @echo 104 | @echo "Build finished. The epub file is in $(BUILDDIR)/epub." 105 | 106 | latex: 107 | $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex 108 | @echo 109 | @echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex." 110 | @echo "Run \`make' in that directory to run these through (pdf)latex" \ 111 | "(use \`make latexpdf' here to do that automatically)." 112 | 113 | latexpdf: 114 | $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex 115 | @echo "Running LaTeX files through pdflatex..." 116 | $(MAKE) -C $(BUILDDIR)/latex all-pdf 117 | @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." 118 | 119 | latexpdfja: 120 | $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex 121 | @echo "Running LaTeX files through platex and dvipdfmx..." 122 | $(MAKE) -C $(BUILDDIR)/latex all-pdf-ja 123 | @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." 124 | 125 | text: 126 | $(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text 127 | @echo 128 | @echo "Build finished. The text files are in $(BUILDDIR)/text." 129 | 130 | man: 131 | $(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man 132 | @echo 133 | @echo "Build finished. The manual pages are in $(BUILDDIR)/man." 134 | 135 | texinfo: 136 | $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo 137 | @echo 138 | @echo "Build finished. The Texinfo files are in $(BUILDDIR)/texinfo." 139 | @echo "Run \`make' in that directory to run these through makeinfo" \ 140 | "(use \`make info' here to do that automatically)." 141 | 142 | info: 143 | $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo 144 | @echo "Running Texinfo files through makeinfo..." 145 | make -C $(BUILDDIR)/texinfo info 146 | @echo "makeinfo finished; the Info files are in $(BUILDDIR)/texinfo." 147 | 148 | gettext: 149 | $(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale 150 | @echo 151 | @echo "Build finished. The message catalogs are in $(BUILDDIR)/locale." 152 | 153 | changes: 154 | $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes 155 | @echo 156 | @echo "The overview file is in $(BUILDDIR)/changes." 157 | 158 | linkcheck: 159 | $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck 160 | @echo 161 | @echo "Link check complete; look for any errors in the above output " \ 162 | "or in $(BUILDDIR)/linkcheck/output.txt." 163 | 164 | doctest: 165 | $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest 166 | @echo "Testing of doctests in the sources finished, look at the " \ 167 | "results in $(BUILDDIR)/doctest/output.txt." 168 | 169 | xml: 170 | $(SPHINXBUILD) -b xml $(ALLSPHINXOPTS) $(BUILDDIR)/xml 171 | @echo 172 | @echo "Build finished. The XML files are in $(BUILDDIR)/xml." 173 | 174 | pseudoxml: 175 | $(SPHINXBUILD) -b pseudoxml $(ALLSPHINXOPTS) $(BUILDDIR)/pseudoxml 176 | @echo 177 | @echo "Build finished. The pseudo-XML files are in $(BUILDDIR)/pseudoxml." 178 | -------------------------------------------------------------------------------- /docs/authors.rst: -------------------------------------------------------------------------------- 1 | .. include:: ../AUTHORS.rst 2 | -------------------------------------------------------------------------------- /docs/check_pa.modules.rst: -------------------------------------------------------------------------------- 1 | check_pa.modules package 2 | ======================== 3 | 4 | Submodules 5 | ---------- 6 | 7 | check_pa.modules.certificate module 8 | ----------------------------------- 9 | 10 | .. automodule:: check_pa.modules.certificate 11 | :members: 12 | :undoc-members: 13 | :show-inheritance: 14 | 15 | check_pa.modules.diskspace module 16 | --------------------------------- 17 | 18 | .. automodule:: check_pa.modules.diskspace 19 | :members: 20 | :undoc-members: 21 | :show-inheritance: 22 | 23 | check_pa.modules.environmental module 24 | ------------------------------------- 25 | 26 | .. automodule:: check_pa.modules.environmental 27 | :members: 28 | :undoc-members: 29 | :show-inheritance: 30 | 31 | check_pa.modules.load module 32 | ---------------------------- 33 | 34 | .. automodule:: check_pa.modules.load 35 | :members: 36 | :undoc-members: 37 | :show-inheritance: 38 | 39 | check_pa.modules.sessioninfo module 40 | ----------------------------------- 41 | 42 | .. automodule:: check_pa.modules.sessioninfo 43 | :members: 44 | :undoc-members: 45 | :show-inheritance: 46 | 47 | check_pa.modules.thermal module 48 | ------------------------------- 49 | 50 | .. automodule:: check_pa.modules.thermal 51 | :members: 52 | :undoc-members: 53 | :show-inheritance: 54 | 55 | check_pa.modules.throughput module 56 | ---------------------------------- 57 | 58 | .. automodule:: check_pa.modules.throughput 59 | :members: 60 | :undoc-members: 61 | :show-inheritance: 62 | 63 | check_pa.modules.useragent module 64 | --------------------------------- 65 | 66 | .. automodule:: check_pa.modules.useragent 67 | :members: 68 | :undoc-members: 69 | :show-inheritance: 70 | 71 | 72 | Module contents 73 | --------------- 74 | 75 | .. automodule:: check_pa.modules 76 | :members: 77 | :undoc-members: 78 | :show-inheritance: 79 | -------------------------------------------------------------------------------- /docs/check_pa.rst: -------------------------------------------------------------------------------- 1 | check_pa package 2 | ================ 3 | 4 | Subpackages 5 | ----------- 6 | 7 | .. toctree:: 8 | 9 | check_pa.modules 10 | 11 | Submodules 12 | ---------- 13 | 14 | check_pa.check_paloalto module 15 | ------------------------------ 16 | 17 | .. automodule:: check_pa.check_paloalto 18 | :members: 19 | :undoc-members: 20 | :show-inheritance: 21 | 22 | check_pa.utils module 23 | --------------------- 24 | 25 | .. automodule:: check_pa.utils 26 | :members: 27 | :undoc-members: 28 | :show-inheritance: 29 | 30 | check_pa.xml_reader module 31 | -------------------------- 32 | 33 | .. automodule:: check_pa.xml_reader 34 | :members: 35 | :undoc-members: 36 | :show-inheritance: 37 | 38 | 39 | Module contents 40 | --------------- 41 | 42 | .. automodule:: check_pa 43 | :members: 44 | :undoc-members: 45 | :show-inheritance: 46 | -------------------------------------------------------------------------------- /docs/conf.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | # 4 | # check_paloalto documentation build configuration file, created by 5 | # sphinx-quickstart on Tue Jul 9 22:26:36 2013. 6 | # 7 | # This file is execfile()d with the current directory set to its 8 | # containing dir. 9 | # 10 | # Note that not all possible configuration values are present in this 11 | # autogenerated file. 12 | # 13 | # All configuration values have a default; values that are commented out 14 | # serve to show the default. 15 | 16 | import sys 17 | import os 18 | 19 | # If extensions (or modules to document with autodoc) are in another 20 | # directory, add these directories to sys.path here. If the directory is 21 | # relative to the documentation root, use os.path.abspath to make it 22 | # absolute, like shown here. 23 | # sys.path.insert(0, os.path.abspath('.')) 24 | 25 | # Get the project root dir, which is the parent dir of this 26 | cwd = os.getcwd() 27 | project_root = os.path.dirname(cwd) 28 | 29 | # Insert the project root dir as the first element in the PYTHONPATH. 30 | # This lets us ensure that the source package is imported, and that its 31 | # version is used. 32 | sys.path.insert(0, project_root) 33 | 34 | import check_pa 35 | 36 | # -- General configuration --------------------------------------------- 37 | 38 | # If your documentation needs a minimal Sphinx version, state it here. 39 | # needs_sphinx = '1.0' 40 | 41 | # Add any Sphinx extension module names here, as strings. They can be 42 | # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom ones. 43 | extensions = ['sphinx.ext.autodoc', 'sphinx.ext.viewcode'] 44 | 45 | # Add any paths that contain templates here, relative to this directory. 46 | templates_path = ['_templates'] 47 | 48 | # The suffix of source filenames. 49 | source_suffix = '.rst' 50 | 51 | # The encoding of source files. 52 | # source_encoding = 'utf-8-sig' 53 | 54 | # The master toctree document. 55 | master_doc = 'index' 56 | 57 | # General information about the project. 58 | project = u'nagios_check_paloalto' 59 | copyright = u'2015, Ralph Offinger' 60 | 61 | # The version info for the project you're documenting, acts as replacement 62 | # for |version| and |release|, also used in various other places throughout 63 | # the built documents. 64 | # 65 | # The short X.Y version. 66 | version = check_pa.__version__ 67 | # The full version, including alpha/beta/rc tags. 68 | release = check_pa.__version__ 69 | 70 | # The language for content autogenerated by Sphinx. Refer to documentation 71 | # for a list of supported languages. 72 | # language = None 73 | 74 | # There are two options for replacing |today|: either, you set today to 75 | # some non-false value, then it is used: 76 | # today = '' 77 | # Else, today_fmt is used as the format for a strftime call. 78 | # today_fmt = '%B %d, %Y' 79 | 80 | # List of patterns, relative to source directory, that match files and 81 | # directories to ignore when looking for source files. 82 | exclude_patterns = ['_build'] 83 | 84 | # The reST default role (used for this markup: `text`) to use for all 85 | # documents. 86 | # default_role = None 87 | 88 | # If true, '()' will be appended to :func: etc. cross-reference text. 89 | # add_function_parentheses = True 90 | 91 | # If true, the current module name will be prepended to all description 92 | # unit titles (such as .. function::). 93 | # add_module_names = True 94 | 95 | # If true, sectionauthor and moduleauthor directives will be shown in the 96 | # output. They are ignored by default. 97 | # show_authors = False 98 | 99 | # The name of the Pygments (syntax highlighting) style to use. 100 | pygments_style = 'sphinx' 101 | 102 | # A list of ignored prefixes for module index sorting. 103 | # modindex_common_prefix = [] 104 | 105 | # If true, keep warnings as "system message" paragraphs in the built 106 | # documents. 107 | # keep_warnings = False 108 | 109 | 110 | # -- Options for HTML output ------------------------------------------- 111 | 112 | # The theme to use for HTML and HTML Help pages. See the documentation for 113 | # a list of builtin themes. 114 | html_theme = 'default' 115 | 116 | # Theme options are theme-specific and customize the look and feel of a 117 | # theme further. For a list of options available for each theme, see the 118 | # documentation. 119 | # html_theme_options = {} 120 | 121 | # Add any paths that contain custom themes here, relative to this directory. 122 | # html_theme_path = [] 123 | 124 | # The name for this set of Sphinx documents. If None, it defaults to 125 | # " v documentation". 126 | # html_title = None 127 | 128 | # A shorter title for the navigation bar. Default is the same as 129 | # html_title. 130 | # html_short_title = None 131 | 132 | # The name of an image file (relative to this directory) to place at the 133 | # top of the sidebar. 134 | # html_logo = None 135 | 136 | # The name of an image file (within the static path) to use as favicon 137 | # of the docs. This file should be a Windows icon file (.ico) being 138 | # 16x16 or 32x32 pixels large. 139 | # html_favicon = None 140 | 141 | # Add any paths that contain custom static files (such as style sheets) 142 | # here, relative to this directory. They are copied after the builtin 143 | # static files, so a file named "default.css" will overwrite the builtin 144 | # "default.css". 145 | html_static_path = ['_static'] 146 | 147 | # If not '', a 'Last updated on:' timestamp is inserted at every page 148 | # bottom, using the given strftime format. 149 | # html_last_updated_fmt = '%b %d, %Y' 150 | 151 | # If true, SmartyPants will be used to convert quotes and dashes to 152 | # typographically correct entities. 153 | # html_use_smartypants = True 154 | 155 | # Custom sidebar templates, maps document names to template names. 156 | # html_sidebars = {} 157 | 158 | # Additional templates that should be rendered to pages, maps page names 159 | # to template names. 160 | # html_additional_pages = {} 161 | 162 | # If false, no module index is generated. 163 | # html_domain_indices = True 164 | 165 | # If false, no index is generated. 166 | # html_use_index = True 167 | 168 | # If true, the index is split into individual pages for each letter. 169 | # html_split_index = False 170 | 171 | # If true, links to the reST sources are added to the pages. 172 | # html_show_sourcelink = True 173 | 174 | # If true, "Created using Sphinx" is shown in the HTML footer. 175 | # Default is True. 176 | # html_show_sphinx = True 177 | 178 | # If true, "(C) Copyright ..." is shown in the HTML footer. 179 | # Default is True. 180 | # html_show_copyright = True 181 | 182 | # If true, an OpenSearch description file will be output, and all pages 183 | # will contain a tag referring to it. The value of this option 184 | # must be the base URL from which the finished HTML is served. 185 | # html_use_opensearch = '' 186 | 187 | # This is the file name suffix for HTML files (e.g. ".xhtml"). 188 | # html_file_suffix = None 189 | 190 | # Output file base name for HTML help builder. 191 | htmlhelp_basename = 'check_paloaltodoc' 192 | 193 | 194 | # -- Options for LaTeX output ------------------------------------------ 195 | 196 | latex_elements = { 197 | # The paper size ('letterpaper' or 'a4paper'). 198 | # 'papersize': 'letterpaper', 199 | 200 | # The font size ('10pt', '11pt' or '12pt'). 201 | # 'pointsize': '10pt', 202 | 203 | # Additional stuff for the LaTeX preamble. 204 | # 'preamble': '', 205 | } 206 | 207 | # Grouping the document tree into LaTeX files. List of tuples 208 | # (source start file, target name, title, author, documentclass 209 | # [howto/manual]). 210 | latex_documents = [ 211 | ('index', 'check_paloalto.tex', 212 | u'nagios_check_paloalto Documentation', 213 | u'Ralph Offinger', 'manual'), 214 | ] 215 | 216 | # The name of an image file (relative to this directory) to place at 217 | # the top of the title page. 218 | # latex_logo = None 219 | 220 | # For "manual" documents, if this is true, then toplevel headings 221 | # are parts, not chapters. 222 | # latex_use_parts = False 223 | 224 | # If true, show page references after internal links. 225 | # latex_show_pagerefs = False 226 | 227 | # If true, show URL addresses after external links. 228 | # latex_show_urls = False 229 | 230 | # Documents to append as an appendix to all manuals. 231 | # latex_appendices = [] 232 | 233 | # If false, no module index is generated. 234 | # latex_domain_indices = True 235 | 236 | 237 | # -- Options for manual page output ------------------------------------ 238 | 239 | # One entry per manual page. List of tuples 240 | # (source start file, name, description, authors, manual section). 241 | man_pages = [ 242 | ('index', 'check_paloalto', 243 | u'nagios_check_paloalto Documentation', 244 | [u'Ralph Offinger'], 1) 245 | ] 246 | 247 | # If true, show URL addresses after external links. 248 | # man_show_urls = False 249 | 250 | 251 | # -- Options for Texinfo output ---------------------------------------- 252 | 253 | # Grouping the document tree into Texinfo files. List of tuples 254 | # (source start file, target name, title, author, 255 | # dir menu entry, description, category) 256 | texinfo_documents = [ 257 | ('index', 'check_paloalto', 258 | u'nagios_check_paloalto Documentation', 259 | u'Ralph Offinger', 260 | 'check_paloalto', 261 | 'Checks PaloAlto Firewall Systems', 262 | 'Miscellaneous'), 263 | ] 264 | 265 | # Documents to append as an appendix to all manuals. 266 | # texinfo_appendices = [] 267 | 268 | # If false, no module index is generated. 269 | # texinfo_domain_indices = True 270 | 271 | # How to display URL addresses: 'footnote', 'no', or 'inline'. 272 | # texinfo_show_urls = 'footnote' 273 | 274 | # If true, do not generate a @detailmenu in the "Top" node's menu. 275 | # texinfo_no_detailmenu = False 276 | -------------------------------------------------------------------------------- /docs/configuration.rst: -------------------------------------------------------------------------------- 1 | ============= 2 | Configuration 3 | ============= 4 | ***** 5 | Token 6 | ***** 7 | The REST API requires a token to get information. This token must be generated once:: 8 | 9 | 1. Create a "monitoring role" in the PA. 10 | 2. Disable everything in the WEB UI tab within that role 11 | 3. Enable "Operational requests" in the XML API tab and disable everything else 12 | 4. Ensure that the tab "Command line" is "None" 13 | 5. Create a new Admin user who uses that custom role and for best practices choose at least 20 length password without special characters other than '_-' 14 | 6. Generating the token is easy. To do that login to your PA with the monitoring user 15 | 16 | and open: 17 | https://x.x.x.x/api/?type=keygen&user=YOUR-USERNAME&password=YOUR-PASSWORD 18 | (replace YOUR-USERNAME with the username created in step 5. and YOUR-PASSWORD accordingly) 19 | 20 | ****** 21 | Nagios 22 | ****** 23 | .. code-block:: console 24 | 25 | define command { 26 | command_name check_paloalto 27 | command_line /usr/local/bin/check_paloalto 28 | } -------------------------------------------------------------------------------- /docs/contributing.rst: -------------------------------------------------------------------------------- 1 | .. include:: ../CONTRIBUTING.rst 2 | -------------------------------------------------------------------------------- /docs/history.rst: -------------------------------------------------------------------------------- 1 | .. include:: ../HISTORY.rst 2 | -------------------------------------------------------------------------------- /docs/index.rst: -------------------------------------------------------------------------------- 1 | Welcome to nagios_check_paloalto's documentation! 2 | ====================================== 3 | 4 | Contents: 5 | 6 | .. toctree:: 7 | :maxdepth: 2 8 | 9 | readme 10 | installation 11 | configuration 12 | usage 13 | contributing 14 | authors 15 | history 16 | 17 | Indices and tables 18 | ================== 19 | 20 | * :ref:`genindex` 21 | * :ref:`modindex` 22 | * :ref:`search` 23 | 24 | -------------------------------------------------------------------------------- /docs/installation.rst: -------------------------------------------------------------------------------- 1 | ============ 2 | Installation 3 | ============ 4 | 5 | Simply install check_paloalto:: 6 | 7 | $ pip install check_paloalto 8 | 9 | or use:: 10 | 11 | $ pip3 install check_paloalto 12 | -------------------------------------------------------------------------------- /docs/make.bat: -------------------------------------------------------------------------------- 1 | @ECHO OFF 2 | 3 | REM Command file for Sphinx documentation 4 | 5 | if "%SPHINXBUILD%" == "" ( 6 | set SPHINXBUILD=sphinx-build 7 | ) 8 | set BUILDDIR=_build 9 | set ALLSPHINXOPTS=-d %BUILDDIR%/doctrees %SPHINXOPTS% . 10 | set I18NSPHINXOPTS=%SPHINXOPTS% . 11 | if NOT "%PAPER%" == "" ( 12 | set ALLSPHINXOPTS=-D latex_paper_size=%PAPER% %ALLSPHINXOPTS% 13 | set I18NSPHINXOPTS=-D latex_paper_size=%PAPER% %I18NSPHINXOPTS% 14 | ) 15 | 16 | if "%1" == "" goto help 17 | 18 | if "%1" == "help" ( 19 | :help 20 | echo.Please use `make ^` where ^ is one of 21 | echo. html to make standalone HTML files 22 | echo. dirhtml to make HTML files named index.html in directories 23 | echo. singlehtml to make a single large HTML file 24 | echo. pickle to make pickle files 25 | echo. json to make JSON files 26 | echo. htmlhelp to make HTML files and a HTML help project 27 | echo. qthelp to make HTML files and a qthelp project 28 | echo. devhelp to make HTML files and a Devhelp project 29 | echo. epub to make an epub 30 | echo. latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter 31 | echo. text to make text files 32 | echo. man to make manual pages 33 | echo. texinfo to make Texinfo files 34 | echo. gettext to make PO message catalogs 35 | echo. changes to make an overview over all changed/added/deprecated items 36 | echo. xml to make Docutils-native XML files 37 | echo. pseudoxml to make pseudoxml-XML files for display purposes 38 | echo. linkcheck to check all external links for integrity 39 | echo. doctest to run all doctests embedded in the documentation if enabled 40 | goto end 41 | ) 42 | 43 | if "%1" == "clean" ( 44 | for /d %%i in (%BUILDDIR%\*) do rmdir /q /s %%i 45 | del /q /s %BUILDDIR%\* 46 | goto end 47 | ) 48 | 49 | 50 | %SPHINXBUILD% 2> nul 51 | if errorlevel 9009 ( 52 | echo. 53 | echo.The 'sphinx-build' command was not found. Make sure you have Sphinx 54 | echo.installed, then set the SPHINXBUILD environment variable to point 55 | echo.to the full path of the 'sphinx-build' executable. Alternatively you 56 | echo.may add the Sphinx directory to PATH. 57 | echo. 58 | echo.If you don't have Sphinx installed, grab it from 59 | echo.http://sphinx-doc.org/ 60 | exit /b 1 61 | ) 62 | 63 | if "%1" == "html" ( 64 | %SPHINXBUILD% -b html %ALLSPHINXOPTS% %BUILDDIR%/html 65 | if errorlevel 1 exit /b 1 66 | echo. 67 | echo.Build finished. The HTML pages are in %BUILDDIR%/html. 68 | goto end 69 | ) 70 | 71 | if "%1" == "dirhtml" ( 72 | %SPHINXBUILD% -b dirhtml %ALLSPHINXOPTS% %BUILDDIR%/dirhtml 73 | if errorlevel 1 exit /b 1 74 | echo. 75 | echo.Build finished. The HTML pages are in %BUILDDIR%/dirhtml. 76 | goto end 77 | ) 78 | 79 | if "%1" == "singlehtml" ( 80 | %SPHINXBUILD% -b singlehtml %ALLSPHINXOPTS% %BUILDDIR%/singlehtml 81 | if errorlevel 1 exit /b 1 82 | echo. 83 | echo.Build finished. The HTML pages are in %BUILDDIR%/singlehtml. 84 | goto end 85 | ) 86 | 87 | if "%1" == "pickle" ( 88 | %SPHINXBUILD% -b pickle %ALLSPHINXOPTS% %BUILDDIR%/pickle 89 | if errorlevel 1 exit /b 1 90 | echo. 91 | echo.Build finished; now you can process the pickle files. 92 | goto end 93 | ) 94 | 95 | if "%1" == "json" ( 96 | %SPHINXBUILD% -b json %ALLSPHINXOPTS% %BUILDDIR%/json 97 | if errorlevel 1 exit /b 1 98 | echo. 99 | echo.Build finished; now you can process the JSON files. 100 | goto end 101 | ) 102 | 103 | if "%1" == "htmlhelp" ( 104 | %SPHINXBUILD% -b htmlhelp %ALLSPHINXOPTS% %BUILDDIR%/htmlhelp 105 | if errorlevel 1 exit /b 1 106 | echo. 107 | echo.Build finished; now you can run HTML Help Workshop with the ^ 108 | .hhp project file in %BUILDDIR%/htmlhelp. 109 | goto end 110 | ) 111 | 112 | if "%1" == "qthelp" ( 113 | %SPHINXBUILD% -b qthelp %ALLSPHINXOPTS% %BUILDDIR%/qthelp 114 | if errorlevel 1 exit /b 1 115 | echo. 116 | echo.Build finished; now you can run "qcollectiongenerator" with the ^ 117 | .qhcp project file in %BUILDDIR%/qthelp, like this: 118 | echo.^> qcollectiongenerator %BUILDDIR%\qthelp\check_paloalto.qhcp 119 | echo.To view the help file: 120 | echo.^> assistant -collectionFile %BUILDDIR%\qthelp\check_paloalto.ghc 121 | goto end 122 | ) 123 | 124 | if "%1" == "devhelp" ( 125 | %SPHINXBUILD% -b devhelp %ALLSPHINXOPTS% %BUILDDIR%/devhelp 126 | if errorlevel 1 exit /b 1 127 | echo. 128 | echo.Build finished. 129 | goto end 130 | ) 131 | 132 | if "%1" == "epub" ( 133 | %SPHINXBUILD% -b epub %ALLSPHINXOPTS% %BUILDDIR%/epub 134 | if errorlevel 1 exit /b 1 135 | echo. 136 | echo.Build finished. The epub file is in %BUILDDIR%/epub. 137 | goto end 138 | ) 139 | 140 | if "%1" == "latex" ( 141 | %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex 142 | if errorlevel 1 exit /b 1 143 | echo. 144 | echo.Build finished; the LaTeX files are in %BUILDDIR%/latex. 145 | goto end 146 | ) 147 | 148 | if "%1" == "latexpdf" ( 149 | %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex 150 | cd %BUILDDIR%/latex 151 | make all-pdf 152 | cd %BUILDDIR%/.. 153 | echo. 154 | echo.Build finished; the PDF files are in %BUILDDIR%/latex. 155 | goto end 156 | ) 157 | 158 | if "%1" == "latexpdfja" ( 159 | %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex 160 | cd %BUILDDIR%/latex 161 | make all-pdf-ja 162 | cd %BUILDDIR%/.. 163 | echo. 164 | echo.Build finished; the PDF files are in %BUILDDIR%/latex. 165 | goto end 166 | ) 167 | 168 | if "%1" == "text" ( 169 | %SPHINXBUILD% -b text %ALLSPHINXOPTS% %BUILDDIR%/text 170 | if errorlevel 1 exit /b 1 171 | echo. 172 | echo.Build finished. The text files are in %BUILDDIR%/text. 173 | goto end 174 | ) 175 | 176 | if "%1" == "man" ( 177 | %SPHINXBUILD% -b man %ALLSPHINXOPTS% %BUILDDIR%/man 178 | if errorlevel 1 exit /b 1 179 | echo. 180 | echo.Build finished. The manual pages are in %BUILDDIR%/man. 181 | goto end 182 | ) 183 | 184 | if "%1" == "texinfo" ( 185 | %SPHINXBUILD% -b texinfo %ALLSPHINXOPTS% %BUILDDIR%/texinfo 186 | if errorlevel 1 exit /b 1 187 | echo. 188 | echo.Build finished. The Texinfo files are in %BUILDDIR%/texinfo. 189 | goto end 190 | ) 191 | 192 | if "%1" == "gettext" ( 193 | %SPHINXBUILD% -b gettext %I18NSPHINXOPTS% %BUILDDIR%/locale 194 | if errorlevel 1 exit /b 1 195 | echo. 196 | echo.Build finished. The message catalogs are in %BUILDDIR%/locale. 197 | goto end 198 | ) 199 | 200 | if "%1" == "changes" ( 201 | %SPHINXBUILD% -b changes %ALLSPHINXOPTS% %BUILDDIR%/changes 202 | if errorlevel 1 exit /b 1 203 | echo. 204 | echo.The overview file is in %BUILDDIR%/changes. 205 | goto end 206 | ) 207 | 208 | if "%1" == "linkcheck" ( 209 | %SPHINXBUILD% -b linkcheck %ALLSPHINXOPTS% %BUILDDIR%/linkcheck 210 | if errorlevel 1 exit /b 1 211 | echo. 212 | echo.Link check complete; look for any errors in the above output ^ 213 | or in %BUILDDIR%/linkcheck/output.txt. 214 | goto end 215 | ) 216 | 217 | if "%1" == "doctest" ( 218 | %SPHINXBUILD% -b doctest %ALLSPHINXOPTS% %BUILDDIR%/doctest 219 | if errorlevel 1 exit /b 1 220 | echo. 221 | echo.Testing of doctests in the sources finished, look at the ^ 222 | results in %BUILDDIR%/doctest/output.txt. 223 | goto end 224 | ) 225 | 226 | if "%1" == "xml" ( 227 | %SPHINXBUILD% -b xml %ALLSPHINXOPTS% %BUILDDIR%/xml 228 | if errorlevel 1 exit /b 1 229 | echo. 230 | echo.Build finished. The XML files are in %BUILDDIR%/xml. 231 | goto end 232 | ) 233 | 234 | if "%1" == "pseudoxml" ( 235 | %SPHINXBUILD% -b pseudoxml %ALLSPHINXOPTS% %BUILDDIR%/pseudoxml 236 | if errorlevel 1 exit /b 1 237 | echo. 238 | echo.Build finished. The pseudo-XML files are in %BUILDDIR%/pseudoxml. 239 | goto end 240 | ) 241 | 242 | :end 243 | -------------------------------------------------------------------------------- /docs/modules.rst: -------------------------------------------------------------------------------- 1 | check_pa 2 | ======== 3 | 4 | .. toctree:: 5 | :maxdepth: 4 6 | 7 | check_pa 8 | -------------------------------------------------------------------------------- /docs/readme.rst: -------------------------------------------------------------------------------- 1 | .. include:: ../README.rst 2 | -------------------------------------------------------------------------------- /docs/usage.rst: -------------------------------------------------------------------------------- 1 | ===== 2 | Usage 3 | ===== 4 | 5 | Command-line usage:: 6 | 7 | usage: check_paloalto [-h] -H HOST -T TOKEN [-v] [-t TIMEOUT] [--reset] 8 | [--version] 9 | {diskspace,certificates,load,useragent,environmental,sessinfo,thermal,throughput} 10 | ... 11 | 12 | positional arguments: 13 | {diskspace,certificates,load,useragent,environmental,sessinfo,thermal,throughput} 14 | diskspace check used diskspace. 15 | certificates check the certificate store for expiring certificates: 16 | Outputs is a warning, if a certificate is in range. 17 | load check the CPU load. 18 | useragent check for running useragents. 19 | environmental check if an alarm is found. 20 | sessinfo check important session parameters. 21 | thermal check the temperature. 22 | throughput check the throughput. 23 | 24 | optional arguments: 25 | -h, --help show this help message and exit 26 | 27 | Connection: 28 | -H HOST, --host HOST PaloAlto Server Hostname 29 | -T TOKEN, --token TOKEN 30 | Generated Token for REST-API access 31 | 32 | Debug: 33 | -v, --verbose increase output verbosity (use up to 3 times) 34 | -t TIMEOUT, --timeout TIMEOUT 35 | abort check execution after so many seconds (use 0 for 36 | no timeout) 37 | --reset Deletes the cookie file for the throughput check. 38 | 39 | Info: 40 | --version show program's version number and exit 41 | 42 | 43 | To check your Palo Alto Firewall, there are several commands available. 44 | 45 | diskspace 46 | --------- 47 | usage:: 48 | 49 | usage: check_paloalto diskspace [-h] [-w WARN] [-c CRIT] 50 | 51 | optional arguments: 52 | -h, --help show this help message and exit 53 | -w WARN, --warn WARN Warning if diskspace is greater. (default: 85) 54 | -c CRIT, --crit CRIT Critical if disksace is greater. (default: 95) 55 | 56 | example:: 57 | 58 | $ check_paloalto -H HOST -T TOKEN diskspace 59 | $ DISKSPACE OK - sda2: 70%, sda5: 51%, sda6: 58%, sda8: 78% | sda2=70%;85;95 sda5=51%;85;95 sda6=58%;85;95 sda8=78%;85;95 60 | 61 | certificates 62 | ------------ 63 | usage:: 64 | 65 | usage: check_paloalto certificates [-h] [-ex EXCLUDE] [-r RANGE] 66 | 67 | optional arguments: 68 | -h, --help show this help message and exit 69 | -ex EXCLUDE, --exclude EXCLUDE 70 | Exclude certificates from check by name. 71 | -r RANGE, --range RANGE 72 | Warning if days until certificate expiration is in 73 | range: Represents a threshold range. The general 74 | format is "[@][start:][end] (default: 0:20) 75 | 76 | example:: 77 | 78 | $ check_paloalto -H HOST -T TOKEN certificates 79 | $ CERTIFICATE WARNING - Certificate1 expires in 8 days 80 | 81 | load 82 | ---- 83 | usage:: 84 | 85 | usage: check_paloalto load [-h] [-w WARN] [-c CRIT] 86 | 87 | optional arguments: 88 | -h, --help show this help message and exit 89 | -w WARN, --warn WARN Warning if CPU load is greater. (default: 85) 90 | -c CRIT, --crit CRIT Critical if CPU load is greater. (default: 95) 91 | 92 | example:: 93 | 94 | $ check_paloalto -H HOST -T TOKEN load 95 | $ LOAD OK - CPU0: 0.0%, CPU1: 1.0%, CPU2: 4.0%, CPU3: 5.0%, CPU4: 6.0%, CPU5: 5.0% | CPU0=0.0%;85;95;0;100 CPU1=1.0%;85;95;0;100 CPU2=4.0%;85;95;0;100 CPU3=5.0%;85;95;0;100 CPU4=6.0%;85;95;0;100 CPU5=5.0%;85;95;0;100 96 | 97 | environmental 98 | ------------- 99 | usage:: 100 | 101 | usage: check_paloalto environmental [-h] 102 | 103 | optional arguments: 104 | -h, --help show this help message and exit 105 | 106 | example:: 107 | 108 | $ check_paloalto -H HOST -T TOKEN environmental 109 | $ ENVIRONMENTAL OK - No alarms found. 110 | 111 | 112 | sessinfo 113 | -------- 114 | usage:: 115 | 116 | usage: check_paloalto sessinfo [-h] 117 | 118 | optional arguments: 119 | -h, --help show this help message and exit 120 | 121 | example:: 122 | 123 | $ check_paloalto -H HOST -T TOKEN sessinfo 124 | $ SESSINFO OK - Active sessions: 6582 / Throughput (kbps): 24304 | session=6582;20000;50000;0;262142 throughput_kbps=24304;;;0 125 | 126 | 127 | thermal 128 | ------- 129 | usage:: 130 | 131 | usage: check_paloalto thermal [-h] [-w WARN] [-c CRIT] 132 | 133 | optional arguments: 134 | -h, --help show this help message and exit 135 | -w WARN, --warn WARN Warning if temperature is greater. (default: 40) 136 | -c CRIT, --crit CRIT Critical if temperature is greater. (default: 45) 137 | 138 | example:: 139 | 140 | $ check_paloalto -H HOST -T TOKEN thermal 141 | $ THERMAL OK - Temperature @ Ocelot is 29 degrees Celsius, Temperature @ Switch is 33 degrees Celsius, Temperature @ Cavium is 36 degrees Celsius, Temperature @ Intel PHY is 24 degrees Celsius | 'Temperature @ Cavium'=36.5;40;45;5.0;60.0 'Temperature @ Intel PHY'=24.2;40;45;5.0;60.0 'Temperature @ Ocelot'=29.9;40;45;5.0;60.0 'Temperature @ Switch'=33.8;40;45;5.0;60.0 142 | 143 | throughput 144 | ---------- 145 | usage:: 146 | 147 | usage: check_paloalto throughput [-h] -i [INTERFACE] 148 | 149 | optional arguments: 150 | -h, --help show this help message and exit 151 | -i [INTERFACE], --interface [INTERFACE] 152 | PA interface name, seperate by comma. 153 | 154 | example:: 155 | 156 | $ check_paloalto -H HOST -T TOKEN throughput -i ethernet1/1 157 | $ THROUGHPUT OK - Input is 5.74 Mb/s - Output is 11.81 Mb/s | 'in_bps_ethernet1/1'=5743432.0;;;0 'out_bps_ethernet1/1'=11807524.0;;;0 158 | 159 | $ check_paloalto -H HOST -T TOKEN throughput -i ethernet1/1,ethernet1/2 160 | $ THROUGHPUT OK - Input is 44.12 Mb/s - Output is 24.59 Mb/s | 'in_bps_ethernet1/1'=5895616.0;;;0 'in_bps_ethernet1/2'=38225768.0;;;0 'out_bps_ethernet1/1'=15926620.0;;;0 'out_bps_ethernet1/2'=8661100.0;;;0 161 | 162 | To get all available names of your interfaces, please have a look at 163 | https://www.paloaltonetworks.com/documentation/61/pan-os/pan-os/getting-started/configure-interfaces-and-zones.html 164 | 165 | useragents 166 | ---------- 167 | usage:: 168 | 169 | usage: check_paloalto useragent [-h] [-w WARN] [-c CRIT] 170 | 171 | optional arguments: 172 | -h, --help show this help message and exit 173 | -w WARN, --warn WARN Warning if agent is not responding for a given amount 174 | of seconds. (default: 60) 175 | -c CRIT, --crit CRIT Critical if agent is not responding for a given amount 176 | of seconds. (default: 240) 177 | 178 | 179 | example:: 180 | 181 | $ check_paloalto -H HOST -T TOKEN useragent 182 | $ USERAGENT OK - All agents are connected and responding. | 'Agent: Agent1 - HOST1(vsys: vsys1) Host: 192.168.1.1(192.168.1.1):5007'=1;60;240 183 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | mock==2.0.0 2 | pytest==2.9.1 3 | tox==2.3.1 4 | python-coveralls==2.7.0 5 | pytest-cov==2.2.1 6 | nagiosplugin==1.2.4 7 | beautifulsoup4==4.4.1 8 | lxml==3.6.0 9 | requests==2.10.0 10 | responses==0.5.1 11 | wheel==0.29.0 12 | -------------------------------------------------------------------------------- /setup.cfg: -------------------------------------------------------------------------------- 1 | [bdist_wheel] 2 | universal=1 3 | 4 | [flake8] 5 | exclude = docs 6 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | 4 | 5 | from setuptools import setup 6 | 7 | with open('README.rst') as readme_file: 8 | readme = readme_file.read() 9 | 10 | with open('HISTORY.rst') as history_file: 11 | history = history_file.read().replace('.. :changelog:', '') 12 | 13 | requirements = [ 14 | 'nagiosplugin', 15 | 'beautifulsoup4', 16 | 'lxml', 17 | 'requests' 18 | ] 19 | 20 | test_requirements = [ 21 | 'responses', 22 | 'flake8' 23 | ] 24 | 25 | setup(name='check_paloalto', 26 | version='0.3.2', 27 | description="check_paloalto is a Nagios/Icinga plugin for Palo Alto Next Generation Firewalls. It is written in " 28 | "Python and based on the PA REST API.", 29 | long_description=readme + '\n\n' + history, 30 | author="Ralph Offinger", 31 | author_email='ralph.offinger@gmail.com', 32 | url='https://github.com/ralph-hm/nagios_check_paloalto', 33 | install_requires=requirements, 34 | packages=['check_pa', 'check_pa.modules'], 35 | entry_points={ 36 | 'console_scripts': [ 37 | 'check_paloalto = check_pa.check_paloalto:main' 38 | ] 39 | }, 40 | license="CC BY-ND 4.0", 41 | classifiers=[ 42 | 'Development Status :: 4 - Beta', 43 | 'Intended Audience :: Developers', 44 | 'Intended Audience :: System Administrators', 45 | 'Topic :: System :: Monitoring', 46 | 'License :: OSI Approved :: Common Public License', 47 | 'Programming Language :: Python :: 2', 48 | 'Programming Language :: Python :: 2.7', 49 | 'Programming Language :: Python :: 3', 50 | 'Programming Language :: Python :: 3.3', 51 | 'Programming Language :: Python :: 3.4', 52 | 'Programming Language :: Python :: 3.5', 53 | ], 54 | keywords='paloalto icinga nagios check', 55 | zip_safe=False, 56 | test_suite='tests', 57 | tests_require=test_requirements, 58 | ) 59 | -------------------------------------------------------------------------------- /tests/conftest.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | 4 | import os 5 | 6 | import pytest 7 | 8 | import check_pa.modules.throughput 9 | 10 | 11 | @pytest.yield_fixture(scope="function") 12 | def statefile(delete = True): 13 | statefile_path = check_pa.modules.throughput.get_statefile_path() 14 | yield statefile_path 15 | try: 16 | os.remove(statefile_path) 17 | except OSError: 18 | pass 19 | 20 | 21 | -------------------------------------------------------------------------------- /tests/test_alarm.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | 4 | """ 5 | test_check_paloalto 6 | ---------------------------------- 7 | 8 | Tests for `check_paloalto` modules. 9 | """ 10 | 11 | import pytest 12 | import responses 13 | from nagiosplugin.state import ServiceState 14 | 15 | import utils 16 | from check_pa.modules import environmental 17 | 18 | 19 | class TestAlarm(object): 20 | @classmethod 21 | def setup_class(cls): 22 | """setup host and token for test of Palo Alto Firewall""" 23 | cls.host = 'localhost' 24 | cls.token = 'test' 25 | 26 | @responses.activate 27 | def test_alarm(self): 28 | f = 'environmentals_ok.xml' 29 | check = environmental.create_check(self) 30 | obj = check.resources[0] 31 | 32 | with responses.RequestsMock() as rsps: 33 | rsps.add(responses.GET, 34 | obj.xml_obj.build_request_url(), 35 | body=utils.read_xml(f), 36 | status=200, 37 | content_type='document', 38 | match_querystring=True) 39 | with pytest.raises(SystemExit): 40 | check.main(verbose=3) 41 | 42 | assert check.exitcode == 0 43 | assert check.state == ServiceState(code=0, text='ok') 44 | assert check.summary_str == 'No alarms found.' 45 | 46 | @responses.activate 47 | def test_alarm_critical(self): 48 | f = 'environmentals_alarms.xml' 49 | check = environmental.create_check(self) 50 | obj = check.resources[0] 51 | 52 | with responses.RequestsMock() as rsps: 53 | rsps.add(responses.GET, 54 | obj.xml_obj.build_request_url(), 55 | body=utils.read_xml(f), 56 | status=200, 57 | content_type='document', 58 | match_querystring=True) 59 | 60 | with pytest.raises(SystemExit): 61 | check.main(verbose=3) 62 | 63 | assert check.exitcode == 2 64 | assert check.state == ServiceState(code=2, text='critical') 65 | assert check.summary_str == 'Alarm(s) found: Temperature @ Test1, ' \ 66 | 'Temperature @ Test2' 67 | -------------------------------------------------------------------------------- /tests/test_certificate.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | 4 | """ 5 | test_check_paloalto 6 | ---------------------------------- 7 | 8 | Tests for `check_paloalto` modules. 9 | """ 10 | 11 | import mock 12 | import pytest 13 | import responses 14 | from nagiosplugin.state import ServiceState 15 | 16 | import check_pa.modules.certificate 17 | import utils 18 | 19 | 20 | class TestCertificates(object): 21 | @classmethod 22 | def setup_class(cls): 23 | """setup host and token for test of Palo Alto Firewall""" 24 | cls.host = 'localhost' 25 | cls.token = 'test' 26 | cls.exclude = '' 27 | cls.range = '0:20' 28 | 29 | @responses.activate 30 | def test_certificate_warning(self): 31 | check = check_pa.modules.certificate.create_check(self) 32 | obj = check.resources[0] 33 | 34 | from datetime import datetime 35 | now = datetime(2011, 10, 1) 36 | with mock.patch('check_pa.modules.certificate.get_now', 37 | return_value=now): 38 | with responses.RequestsMock() as rsps: 39 | rsps.add(responses.GET, 40 | obj.xml_obj.build_request_url(), 41 | body=utils.read_xml('certificates.xml'), 42 | status=200, 43 | content_type='document', 44 | match_querystring=True) 45 | 46 | with pytest.raises(SystemExit): 47 | check.main(verbose=3) 48 | 49 | assert check.exitcode == 1 50 | assert check.state == ServiceState(code=1, text='warning') 51 | assert check.summary_str == 'test-certificate1 expires in 1 days, ' \ 52 | 'test-certificate2 expires in 2 days' 53 | 54 | @responses.activate 55 | def test_certificate_ok(self): 56 | check = check_pa.modules.certificate.create_check(self) 57 | obj = check.resources[0] 58 | 59 | from datetime import datetime 60 | now = datetime(2011, 9, 1) 61 | with mock.patch('check_pa.modules.certificate.get_now', 62 | return_value=now): 63 | with responses.RequestsMock() as rsps: 64 | rsps.add(responses.GET, 65 | obj.xml_obj.build_request_url(), 66 | body=utils.read_xml('certificates.xml'), 67 | status=200, 68 | content_type='document', 69 | match_querystring=True) 70 | 71 | with pytest.raises(SystemExit): 72 | check.main(verbose=3) 73 | 74 | assert check.exitcode == 0 75 | assert check.state == ServiceState(code=0, text='ok') 76 | assert check.summary_str == 'The next certificate will expire ' \ 77 | 'in 31 days.' 78 | -------------------------------------------------------------------------------- /tests/test_check_paloalto.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | 4 | """ 5 | test_check_paloalto 6 | ---------------------------------- 7 | 8 | Tests for `check_paloalto` modules. 9 | """ 10 | 11 | import responses 12 | 13 | import utils 14 | from check_pa.check_paloalto import parse_args 15 | from check_pa.modules import diskspace, certificate, load, environmental, sessioninfo, thermal, throughput 16 | 17 | 18 | class TestCheckPaloAlto(object): 19 | @classmethod 20 | def setup_class(cls): 21 | """setup host and token for test of Palo Alto Firewall""" 22 | cls.host = 'localhost' 23 | cls.token = '123456ABC' 24 | cls.warn = 80 25 | cls.crit = 90 26 | cls.verbose = 1 27 | cls.exclude = '' 28 | cls.range = '0:20' 29 | cls.interface = 'test' 30 | cls.reset = False 31 | 32 | def test_arg_diskspace(self): 33 | args = parse_args(['-H', self.host, '-T', self.token, 'diskspace']) 34 | assert args.host == self.host 35 | assert args.token == self.token 36 | 37 | def test_arg_useragent(self): 38 | args = parse_args(['-H', self.host, '-T', self.token, 'useragent']) 39 | assert args.host == self.host 40 | assert args.token == self.token 41 | 42 | def test_arg_certificates(self): 43 | args = parse_args( 44 | ['-H', self.host, '-T', self.token, 'certificates', '-ex', 45 | self.exclude, '-r', self.range]) 46 | assert args.host == self.host 47 | assert args.token == self.token 48 | 49 | def test_arg_throughput(self): 50 | args = parse_args( 51 | ['-H', self.host, '-T', self.token, 'throughput', '-i', 52 | self.interface]) 53 | assert args.host == self.host 54 | assert args.token == self.token 55 | 56 | def test_certificates(self): 57 | f = 'certificates.xml' 58 | check = certificate.create_check(self) 59 | with responses.RequestsMock() as rsps: 60 | rsps.add(responses.GET, 61 | check.resources[0].xml_obj.build_request_url(), 62 | body=utils.read_xml(f), 63 | status=200, 64 | content_type='document', 65 | match_querystring=True) 66 | check.__call__() 67 | assert check.name == 'Certificate' 68 | 69 | def test_diskspace(self): 70 | f = 'diskspace.xml' 71 | check = diskspace.create_check(self) 72 | with responses.RequestsMock() as rsps: 73 | rsps.add(responses.GET, 74 | check.resources[0].xml_obj.build_request_url(), 75 | body=utils.read_xml(f), 76 | status=200, 77 | content_type='document', 78 | match_querystring=True) 79 | check.__call__() 80 | assert check.name == 'DiskSpace' 81 | 82 | def test_load(self): 83 | f = 'load.xml' 84 | check = load.create_check(self) 85 | with responses.RequestsMock() as rsps: 86 | rsps.add(responses.GET, 87 | check.resources[0].xml_obj.build_request_url(), 88 | body=utils.read_xml(f), 89 | status=200, 90 | content_type='document', 91 | match_querystring=True) 92 | check.__call__() 93 | assert check.name == 'Load' 94 | 95 | def test_sessinfo(self): 96 | f = 'mock_result.xml' 97 | check = sessioninfo.create_check(self) 98 | with responses.RequestsMock() as rsps: 99 | rsps.add(responses.GET, 100 | check.resources[0].xml_obj.build_request_url(), 101 | body=utils.read_xml(f), 102 | status=200, 103 | content_type='document', 104 | match_querystring=True) 105 | check.__call__() 106 | assert check.name == 'SessInfo' 107 | 108 | def test_environmental(self): 109 | f = 'environmentals_ok.xml' 110 | check = environmental.create_check(self) 111 | with responses.RequestsMock() as rsps: 112 | rsps.add(responses.GET, 113 | check.resources[0].xml_obj.build_request_url(), 114 | body=utils.read_xml(f), 115 | status=200, 116 | content_type='document', 117 | match_querystring=True) 118 | check.__call__() 119 | assert check.name == 'Environmental' 120 | 121 | def test_thermal(self): 122 | f = 'mock_result.xml' 123 | check = thermal.create_check(self) 124 | with responses.RequestsMock() as rsps: 125 | rsps.add(responses.GET, 126 | check.resources[0].xml_obj.build_request_url(), 127 | body=utils.read_xml(f), 128 | status=200, 129 | content_type='document', 130 | match_querystring=True) 131 | check.__call__() 132 | assert check.name == 'Thermal' 133 | 134 | def test_throughput(self): 135 | f = 'throughput1.xml' 136 | check = throughput.create_check(self) 137 | with responses.RequestsMock() as rsps: 138 | rsps.add(responses.GET, 139 | check.resources[0].xml_obj.build_request_url(), 140 | body=utils.read_xml(f), 141 | status=200, 142 | content_type='document', 143 | match_querystring=True) 144 | check.__call__() 145 | assert check.name == 'Throughput' 146 | -------------------------------------------------------------------------------- /tests/test_diskspace.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | 4 | """ 5 | test_check_paloalto 6 | ---------------------------------- 7 | 8 | Tests for `check_paloalto` modules. 9 | """ 10 | 11 | import pytest 12 | import responses 13 | from nagiosplugin.state import ServiceState 14 | 15 | import check_pa.modules.diskspace 16 | import utils 17 | 18 | 19 | class TestDiskspace(object): 20 | @classmethod 21 | def setup_class(cls): 22 | """setup host and token for test of Palo Alto Firewall""" 23 | cls.host = 'localhost' 24 | cls.token = 'test' 25 | 26 | @responses.activate 27 | def test_diskspace(self): 28 | self.warn = 80 29 | self.crit = 90 30 | 31 | f = 'diskspace.xml' 32 | check = check_pa.modules.diskspace.create_check(self) 33 | obj = check.resources[0] 34 | 35 | with responses.RequestsMock() as rsps: 36 | rsps.add(responses.GET, 37 | obj.xml_obj.build_request_url(), 38 | body=utils.read_xml(f), 39 | status=200, 40 | content_type='document', 41 | match_querystring=True) 42 | with pytest.raises(SystemExit): 43 | check.main(verbose=3) 44 | 45 | assert check.exitcode == 0 46 | assert check.state == ServiceState(code=0, text='ok') 47 | assert check.summary_str == 'sda2: 57%, ' \ 48 | 'sda5: 43%, ' \ 49 | 'sda6: 30%, ' \ 50 | 'sda8: 47%' 51 | 52 | @responses.activate 53 | def test_diskspace_warning(self): 54 | self.warn = 50 55 | self.crit = 90 56 | 57 | f = 'diskspace.xml' 58 | check = check_pa.modules.diskspace.create_check(self) 59 | obj = check.resources[0] 60 | 61 | with responses.RequestsMock() as rsps: 62 | rsps.add(responses.GET, 63 | obj.xml_obj.build_request_url(), 64 | body=utils.read_xml(f), 65 | status=200, 66 | content_type='document', 67 | match_querystring=True) 68 | with pytest.raises(SystemExit): 69 | check.main(verbose=3) 70 | 71 | assert check.exitcode == 1 72 | assert check.state == ServiceState(code=1, text='warning') 73 | assert check.summary_str == 'sda2 is 57% (outside range 0:50)' 74 | -------------------------------------------------------------------------------- /tests/test_load.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | 4 | """ 5 | test_check_paloalto 6 | ---------------------------------- 7 | 8 | Tests for `check_paloalto` modules. 9 | """ 10 | 11 | import pytest 12 | import responses 13 | from nagiosplugin.state import ServiceState 14 | 15 | import check_pa.modules.load 16 | import utils 17 | 18 | 19 | class TestLoad(object): 20 | @classmethod 21 | def setup_class(cls): 22 | """setup host and token for test of Palo Alto Firewall""" 23 | cls.host = 'localhost' 24 | cls.token = 'test' 25 | 26 | @responses.activate 27 | def test_load_ok(self): 28 | self.warn = 80 29 | self.crit = 90 30 | 31 | f = 'load.xml' 32 | check = check_pa.modules.load.create_check(self) 33 | obj = check.resources[0] 34 | 35 | with responses.RequestsMock() as rsps: 36 | rsps.add(responses.GET, 37 | obj.xml_obj.build_request_url(), 38 | body=utils.read_xml(f), 39 | status=200, 40 | content_type='document', 41 | match_querystring=True) 42 | 43 | with pytest.raises(SystemExit): 44 | check.main(verbose=3) 45 | 46 | assert check.exitcode == 0 47 | assert check.state == ServiceState(code=0, text='ok') 48 | assert check.summary_str == 'CPU0: 0.0%, CPU1: 2.0%, CPU2: 4.0%, ' \ 49 | 'CPU3: 4.0%, CPU4: 5.0%, CPU5: 6.0%' 50 | 51 | @responses.activate 52 | def test_load_critical(self): 53 | self.warn = 90 54 | self.crit = 5 55 | 56 | f = 'load.xml' 57 | check = check_pa.modules.load.create_check(self) 58 | obj = check.resources[0] 59 | 60 | with responses.RequestsMock() as rsps: 61 | rsps.add(responses.GET, 62 | obj.xml_obj.build_request_url(), 63 | body=utils.read_xml(f), 64 | status=200, 65 | content_type='document', 66 | match_querystring=True) 67 | 68 | with pytest.raises(SystemExit): 69 | check.main(verbose=3) 70 | 71 | assert check.exitcode == 2 72 | assert check.state == ServiceState(code=2, text='critical') 73 | assert check.summary_str == 'CPU5 is 6% (outside range 0:5)' 74 | -------------------------------------------------------------------------------- /tests/test_sessioninfo.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | 4 | """ 5 | test_check_paloalto 6 | ---------------------------------- 7 | 8 | Tests for `check_paloalto` modules. 9 | """ 10 | 11 | import mock 12 | import pytest 13 | import responses 14 | from nagiosplugin.state import ServiceState 15 | 16 | import check_pa.modules.sessioninfo 17 | import utils 18 | 19 | 20 | class TestSessionInfo(object): 21 | @classmethod 22 | def setup_class(cls): 23 | """setup host and token for test of Palo Alto Firewall""" 24 | cls.host = 'localhost' 25 | cls.token = 'test' 26 | 27 | @responses.activate 28 | def test_sessinfo(self): 29 | f = 'mock_result.xml' 30 | self.warn = 20000 31 | self.crit = 50000 32 | 33 | check = check_pa.modules.sessioninfo.create_check(self) 34 | obj = check.resources[0] 35 | 36 | with responses.RequestsMock() as rsps: 37 | rsps.add(responses.GET, 38 | obj.xml_obj.build_request_url(), 39 | body=utils.read_xml(f), 40 | status=200, 41 | content_type='document', 42 | match_querystring=True) 43 | 44 | nummax = 262142 45 | numactive = 4480 46 | kbps = 24266 47 | 48 | with mock.patch('check_pa.xml_reader.Finder.find_item', 49 | side_effect=[nummax, numactive, kbps]): 50 | with pytest.raises(SystemExit): 51 | check.main(verbose=3) 52 | 53 | assert check.exitcode == 0 54 | assert check.state == ServiceState(code=0, text='ok') 55 | assert check.summary_str == 'Active sessions: 4480 ' \ 56 | '/ Throughput (kbps): 24266' 57 | 58 | @responses.activate 59 | def test_sessinfo_warning(self): 60 | f = 'mock_result.xml' 61 | self.warn = 4000 62 | self.crit = 50000 63 | 64 | check = check_pa.modules.sessioninfo.create_check(self) 65 | obj = check.resources[0] 66 | 67 | with responses.RequestsMock() as rsps: 68 | rsps.add(responses.GET, 69 | obj.xml_obj.build_request_url(), 70 | body=utils.read_xml(f), 71 | status=200, 72 | content_type='document', 73 | match_querystring=True) 74 | 75 | nummax = 262142 76 | numactive = 4480 77 | kbps = 24266 78 | 79 | with mock.patch('check_pa.xml_reader.Finder.find_item', 80 | side_effect=[nummax, numactive, kbps]): 81 | with pytest.raises(SystemExit): 82 | check.main(verbose=3) 83 | 84 | assert check.exitcode == 1 85 | assert check.state == ServiceState(code=1, text='warning') 86 | assert check.summary_str == 'session is 4480 (outside range 0:4000)' 87 | 88 | @responses.activate 89 | def test_sessinfo_warning2(self): 90 | f = 'mock_result.xml' 91 | self.warn = 4000 92 | self.crit = 5000 93 | 94 | check = check_pa.modules.sessioninfo.create_check(self) 95 | obj = check.resources[0] 96 | 97 | with responses.RequestsMock() as rsps: 98 | rsps.add(responses.GET, 99 | obj.xml_obj.build_request_url(), 100 | body=utils.read_xml(f), 101 | status=200, 102 | content_type='document', 103 | match_querystring=True) 104 | 105 | nummax = 262142 106 | numactive = 5002 107 | kbps = 24266 108 | 109 | with mock.patch('check_pa.xml_reader.Finder.find_item', 110 | side_effect=[nummax, numactive, kbps]): 111 | with pytest.raises(SystemExit): 112 | check.main(verbose=3) 113 | 114 | assert check.exitcode == 2 115 | assert check.state == ServiceState(code=2, text='critical') 116 | assert check.summary_str == 'session is 5002 (outside range 0:5000)' 117 | -------------------------------------------------------------------------------- /tests/test_thermal.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | 4 | """ 5 | test_check_paloalto 6 | ---------------------------------- 7 | 8 | Tests for `check_paloalto` modules. 9 | """ 10 | 11 | import pytest 12 | import responses 13 | from nagiosplugin.state import ServiceState 14 | 15 | import check_pa.modules.thermal 16 | import utils 17 | 18 | 19 | class TestThermal(object): 20 | @classmethod 21 | def setup_class(cls): 22 | """setup host and token for test of Palo Alto Firewall""" 23 | cls.host = 'localhost' 24 | cls.token = 'test' 25 | 26 | @responses.activate 27 | def test_thermal(self): 28 | self.warn = 80 29 | self.crit = 90 30 | 31 | f = 'thermal.xml' 32 | check = check_pa.modules.thermal.create_check(self) 33 | obj = check.resources[0] 34 | 35 | with responses.RequestsMock() as rsps: 36 | rsps.add(responses.GET, 37 | obj.xml_obj.build_request_url(), 38 | body=utils.read_xml(f), 39 | status=200, 40 | content_type='document', 41 | match_querystring=True) 42 | with pytest.raises(SystemExit): 43 | check.main(verbose=3) 44 | 45 | assert check.exitcode == 0 46 | assert check.state == ServiceState(code=0, text='ok') 47 | assert check.summary_str == 'Temperature @ Test1 is 30 degrees' \ 48 | ' Celsius, Temperature @ Test2 is 34' \ 49 | ' degrees Celsius, Temperature @' \ 50 | ' Test3 is 37 degrees Celsius,' \ 51 | ' Temperature @ Test4' \ 52 | ' is 25 degrees Celsius' 53 | 54 | @responses.activate 55 | def test_thermal_critical(self): 56 | self.warn = 20 57 | self.crit = 30 58 | 59 | f = 'thermal.xml' 60 | check = check_pa.modules.thermal.create_check(self) 61 | obj = check.resources[0] 62 | 63 | with responses.RequestsMock() as rsps: 64 | rsps.add(responses.GET, 65 | obj.xml_obj.build_request_url(), 66 | body=utils.read_xml(f), 67 | status=200, 68 | content_type='document', 69 | match_querystring=True) 70 | with pytest.raises(SystemExit): 71 | check.main(verbose=3) 72 | 73 | assert check.exitcode == 2 74 | assert check.state == ServiceState(code=2, text='critical') 75 | assert check.summary_str == 'Too high temperature: Temperature @ ' \ 76 | 'Test1 is 30.6 (outside range 0:30) ' \ 77 | 'degrees Celsius' 78 | -------------------------------------------------------------------------------- /tests/test_throughput.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | 4 | """ 5 | test_check_paloalto 6 | ---------------------------------- 7 | 8 | Tests for `check_paloalto` modules. 9 | """ 10 | 11 | import mock 12 | import pytest 13 | import responses 14 | from nagiosplugin.state import ServiceState 15 | 16 | import check_pa.modules.throughput 17 | import utils 18 | 19 | 20 | class TestThroughput(object): 21 | @classmethod 22 | def setup_class(cls): 23 | """setup host and token for test of Palo Alto Firewall""" 24 | cls.host = 'localhost' 25 | cls.token = 'test' 26 | 27 | @responses.activate 28 | def test_with_three_interfaces(self, statefile): 29 | self.interface = 'ethernet1/1, ethernet1/2, ethernet1/3' 30 | interfaces = [] 31 | for interface in self.interface.split(','): 32 | interfaces.append(interface) 33 | 34 | file1 = 'throughput1.xml' 35 | file2 = 'throughput2.xml' 36 | file3 = 'throughput3.xml' 37 | 38 | check = check_pa.modules.throughput.create_check(self) 39 | objects = [] 40 | for resource in check.resources: 41 | objects.append(resource) 42 | 43 | with responses.RequestsMock() as rsps: 44 | 45 | rsps.add(responses.GET, 46 | objects[0].xml_obj.build_request_url(), 47 | body=utils.read_xml(file1), 48 | status=200, 49 | content_type='document', 50 | match_querystring=True) 51 | rsps.add(responses.GET, 52 | objects[1].xml_obj.build_request_url(), 53 | body=utils.read_xml(file2), 54 | status=200, 55 | content_type='document', 56 | match_querystring=True) 57 | rsps.add(responses.GET, 58 | objects[2].xml_obj.build_request_url(), 59 | body=utils.read_xml(file3), 60 | status=200, 61 | content_type='document', 62 | match_querystring=True) 63 | 64 | from nagiosplugin import Cookie 65 | 66 | # Resetting cookies 67 | with Cookie(statefile) as cookie: 68 | cookie[self.host + interfaces[0] + 'i'] = 0 69 | cookie[self.host + interfaces[0] + 'o'] = 0 70 | cookie[self.host + interfaces[0] + 't'] = 1441324800 71 | cookie[self.host + interfaces[1] + 'i'] = 0 72 | cookie[self.host + interfaces[1] + 'o'] = 0 73 | cookie[self.host + interfaces[1] + 't'] = 1441324800 74 | cookie[self.host + interfaces[2] + 'i'] = 0 75 | cookie[self.host + interfaces[2] + 'o'] = 0 76 | cookie[self.host + interfaces[2] + 't'] = 1441324800 77 | 78 | # Check will be executed exactly one second later 79 | now = 1441324801 80 | xml_ibytes = 1000000 81 | xml_obytes = 1000000 82 | 83 | with mock.patch('check_pa.modules.throughput.get_time', 84 | return_value=now): 85 | with mock.patch('check_pa.xml_reader.Finder.find_item', 86 | side_effect=[xml_ibytes, xml_obytes, 87 | xml_ibytes, xml_ibytes, 88 | xml_ibytes, xml_ibytes]): 89 | with pytest.raises(SystemExit): 90 | check.main(verbose=3) 91 | 92 | assert check.exitcode == 0 93 | assert check.state == ServiceState(code=0, text='ok') 94 | 95 | # 3000000 Byte = 3 MByte = 24 Mbit in 1 second = 24.0 Mb/s 96 | assert check.summary_str == 'Input is 24.0 Mb/s - Output is 24.0 ' \ 97 | 'Mb/s' 98 | 99 | @responses.activate 100 | def test_with_one_interface(self, statefile): 101 | file1 = 'throughput1.xml' 102 | 103 | self.interface = 'ethernet1/1' 104 | interfaces = [] 105 | for interface in self.interface.split(','): 106 | interfaces.append(interface) 107 | 108 | check = check_pa.modules.throughput.create_check(self) 109 | objects = [] 110 | for res in check.resources: 111 | objects.append(res) 112 | 113 | with responses.RequestsMock() as rsps: 114 | 115 | rsps.add(responses.GET, 116 | objects[0].xml_obj.build_request_url(), 117 | body=utils.read_xml(file1), 118 | status=200, 119 | content_type='document', 120 | match_querystring=True) 121 | 122 | from nagiosplugin import Cookie 123 | 124 | with Cookie(statefile) as cookie: 125 | cookie[self.host + interfaces[0] + 'i'] = 0 126 | cookie[self.host + interfaces[0] + 'o'] = 0 127 | cookie[self.host + interfaces[0] + 't'] = 1441324800 128 | 129 | # Check will be executed exactly ten seconds later 130 | now = 1441324810 131 | 132 | xml_ibytes = 1000000 # 1000000 Byte = 1 MByte 133 | xml_obytes = 1000000 # 1000000 Byte = 1 MByte 134 | with mock.patch('check_pa.modules.throughput.get_time', 135 | return_value=now): 136 | with mock.patch('check_pa.xml_reader.Finder.find_item', 137 | side_effect=[xml_ibytes, xml_obytes]): 138 | with pytest.raises(SystemExit): 139 | check.main(verbose=3) 140 | 141 | assert check.exitcode == 0 142 | assert check.state == ServiceState(code=0, text='ok') 143 | assert check.summary_str == 'Input is 0.8 Mb/s - Output is 0.8 ' \ 144 | 'Mb/s' 145 | 146 | def check_pa(self, time, ibytes, obytes, filename): 147 | objects = [] 148 | file1 = filename 149 | 150 | check = check_pa.modules.throughput.create_check(self) 151 | 152 | for res in check.resources: 153 | objects.append(res) 154 | 155 | with responses.RequestsMock() as rsps: 156 | rsps.add(responses.GET, 157 | objects[0].xml_obj.build_request_url(), 158 | body=utils.read_xml(file1), 159 | status=200, 160 | content_type='document', 161 | match_querystring=True) 162 | 163 | with mock.patch('check_pa.modules.throughput.get_time', 164 | return_value=time): 165 | with mock.patch('check_pa.xml_reader.Finder.find_item', 166 | side_effect=[ibytes, obytes]): 167 | with pytest.raises(SystemExit): 168 | check.main(verbose=3) 169 | 170 | return check 171 | 172 | @responses.activate 173 | def test_with_different_ips(self, statefile): 174 | 175 | pa_1 = self.__class__() 176 | pa_1.host = "192.168.0.1" 177 | pa_1.interface = "ethernet1/1" 178 | 179 | pa_2 = self.__class__() 180 | pa_2.host = "192.168.0.2" 181 | pa_2.interface = "ethernet1/1" 182 | 183 | from nagiosplugin import Cookie 184 | 185 | with Cookie(statefile) as cookie: 186 | cookie[pa_1.host + pa_1.interface + 'i'] = 0 187 | cookie[pa_1.host + pa_1.interface + 'o'] = 0 188 | cookie[pa_1.host + pa_1.interface + 't'] = 1441324800 189 | 190 | check = pa_1.check_pa(1441324800, 10, 10, "throughput1.xml") 191 | 192 | assert check.exitcode == 3 193 | assert check.state == ServiceState(code=3, text='unknown') 194 | assert check.summary_str == 'Difference between old timestamp and new timestamp is less or equal 0: If it is the first time you run the script, please execute it again!' 195 | 196 | check = pa_2.check_pa(1441324810, 110, 110, "throughput1.xml") 197 | 198 | assert check.exitcode == 3 199 | assert check.state == ServiceState(code=3, text='unknown') 200 | assert check.summary_str == 'Difference between old timestamp and new timestamp is less or equal 0: If it is the first time you run the script, please execute it again!' 201 | 202 | check = pa_1.check_pa(1441324801, 1000000, 1000000, "throughput1.xml") 203 | assert check.exitcode == 0 204 | assert check.state == ServiceState(code=0, text='ok') 205 | # 1000000 Byte = 1 MByte = 8 Mbit in 1 second = 8.0 Mb/s 206 | assert check.summary_str == 'Input is 8.0 Mb/s - Output is 8.0 ' \ 207 | 'Mb/s' 208 | 209 | check = pa_2.check_pa(1441324811, 1000000, 1000000, "throughput1.xml") 210 | assert check.exitcode == 0 211 | assert check.state == ServiceState(code=0, text='ok') 212 | # 1000000 Byte = 1 MByte = 8 Mbit in 1 second = 8.0 Mb/s 213 | assert check.summary_str == 'Input is 8.0 Mb/s - Output is 8.0 ' \ 214 | 'Mb/s' 215 | 216 | @responses.activate 217 | def test_new_input_less_than_old(self, statefile): 218 | file1 = 'throughput1.xml' 219 | 220 | self.interface = 'ethernet1/1' 221 | interfaces = [] 222 | for interface in self.interface.split(','): 223 | interfaces.append(interface) 224 | 225 | check = check_pa.modules.throughput.create_check(self) 226 | objects = [] 227 | for res in check.resources: 228 | objects.append(res) 229 | 230 | with responses.RequestsMock() as rsps: 231 | 232 | rsps.add(responses.GET, 233 | objects[0].xml_obj.build_request_url(), 234 | body=utils.read_xml(file1), 235 | status=200, 236 | content_type='document', 237 | match_querystring=True) 238 | 239 | from nagiosplugin import Cookie 240 | 241 | with Cookie(statefile) as cookie: 242 | cookie[self.host + interfaces[0] + 'i'] = 10 243 | cookie[self.host + interfaces[0] + 'o'] = 10 244 | cookie[self.host + interfaces[0] + 't'] = 1441324800 245 | 246 | # Check will be executed exactly ten seconds later 247 | now = 1441324810 248 | 249 | xml_ibytes = 9 250 | xml_obytes = 11 251 | with mock.patch('check_pa.modules.throughput.get_time', 252 | return_value=now): 253 | with mock.patch('check_pa.xml_reader.Finder.find_item', 254 | side_effect=[xml_ibytes, xml_obytes]): 255 | with pytest.raises(SystemExit): 256 | check.main(verbose=3) 257 | 258 | assert check.exitcode == 3 259 | assert check.state == ServiceState(code=3, text='unknown') 260 | assert check.summary_str == 'Couldn\'t get a valid value: Found throughput less then old!' 261 | 262 | @responses.activate 263 | def test_new_output_less_than_old(self, statefile): 264 | file1 = 'throughput1.xml' 265 | 266 | self.interface = 'ethernet1/1' 267 | interfaces = [] 268 | for interface in self.interface.split(','): 269 | interfaces.append(interface) 270 | 271 | check = check_pa.modules.throughput.create_check(self) 272 | objects = [] 273 | for res in check.resources: 274 | objects.append(res) 275 | 276 | with responses.RequestsMock() as rsps: 277 | 278 | rsps.add(responses.GET, 279 | objects[0].xml_obj.build_request_url(), 280 | body=utils.read_xml(file1), 281 | status=200, 282 | content_type='document', 283 | match_querystring=True) 284 | 285 | from nagiosplugin import Cookie 286 | 287 | with Cookie(statefile) as cookie: 288 | cookie[self.host + interfaces[0] + 'i'] = 10 289 | cookie[self.host + interfaces[0] + 'o'] = 10 290 | cookie[self.host + interfaces[0] + 't'] = 1441324800 291 | 292 | # Check will be executed exactly ten seconds later 293 | now = 1441324810 294 | xml_ibytes = 11 295 | xml_obytes = 9 296 | 297 | with mock.patch('check_pa.modules.throughput.get_time', 298 | return_value=now): 299 | with mock.patch('check_pa.xml_reader.Finder.find_item', 300 | side_effect=[xml_ibytes, xml_obytes]): 301 | with pytest.raises(SystemExit): 302 | check.main(verbose=3) 303 | 304 | with Cookie(statefile) as cookie: 305 | input = cookie.get(self.host + interfaces[0] + 'i') 306 | output = cookie.get(self.host + interfaces[0] + 'o') 307 | time = cookie.get(self.host + interfaces[0] + 't') 308 | 309 | assert input == xml_ibytes 310 | assert output == xml_obytes 311 | assert time == now 312 | 313 | assert check.exitcode == 3 314 | assert check.state == ServiceState(code=3, text='unknown') 315 | assert check.summary_str == 'Couldn\'t get a valid value: Found throughput less then old!' 316 | 317 | @responses.activate 318 | def test_same_time(self, statefile): 319 | file1 = 'throughput1.xml' 320 | 321 | self.interface = 'ethernet1/1' 322 | interfaces = [] 323 | for interface in self.interface.split(','): 324 | interfaces.append(interface) 325 | 326 | check = check_pa.modules.throughput.create_check(self) 327 | objects = [] 328 | for resource in check.resources: 329 | objects.append(resource) 330 | 331 | with responses.RequestsMock() as rsps: 332 | rsps.add(responses.GET, 333 | objects[0].xml_obj.build_request_url(), 334 | body=utils.read_xml(file1), 335 | status=200, 336 | content_type='document', 337 | match_querystring=True) 338 | 339 | from nagiosplugin import Cookie 340 | 341 | with Cookie(statefile) as cookie: 342 | cookie[self.host + interfaces[0] + 'i'] = 10 343 | cookie[self.host + interfaces[0] + 'o'] = 10 344 | cookie[self.host + interfaces[0] + 't'] = 1441324800 345 | 346 | # Check will be executed exactly at the same time 347 | now = 1441324800 348 | 349 | xml_ibytes = 11 350 | xml_obytes = 10 351 | 352 | with mock.patch('check_pa.modules.throughput.get_time', 353 | return_value=now): 354 | with mock.patch('check_pa.xml_reader.Finder.find_item', 355 | side_effect=[xml_ibytes, xml_obytes]): 356 | with pytest.raises(SystemExit): 357 | check.main(verbose=3) 358 | 359 | assert check.exitcode == 3 360 | assert check.state == ServiceState(code=3, text='unknown') 361 | assert check.summary_str == 'Difference between old timestamp ' \ 362 | 'and new timestamp is less or equal 0: ' \ 363 | 'If it is the first time you run the ' \ 364 | 'script, please execute it again!' 365 | 366 | @responses.activate 367 | def test_api_failed(self, statefile): 368 | file1 = 'throughput1.xml' 369 | 370 | self.interface = 'ethernet1/1' 371 | interfaces = [] 372 | for interface in self.interface.split(','): 373 | interfaces.append(interface) 374 | 375 | check = check_pa.modules.throughput.create_check(self) 376 | objects = [] 377 | for res in check.resources: 378 | objects.append(res) 379 | 380 | with responses.RequestsMock() as rsps: 381 | 382 | rsps.add(responses.GET, 383 | objects[0].xml_obj.build_request_url(), 384 | body=utils.read_xml(file1), 385 | status=200, 386 | content_type='document', 387 | match_querystring=True) 388 | 389 | from nagiosplugin import Cookie 390 | 391 | with Cookie(statefile) as cookie: 392 | cookie[self.host + interfaces[0] + 'i'] = 10 393 | cookie[self.host + interfaces[0] + 'o'] = 10 394 | cookie[self.host + interfaces[0] + 't'] = 1441324800 395 | 396 | # Check will be executed exactly ten seconds later 397 | now = 1441324810 398 | 399 | xml_ibytes = "" 400 | xml_obytes = "" 401 | 402 | with mock.patch('check_pa.modules.throughput.get_time', 403 | return_value=now): 404 | with mock.patch('check_pa.xml_reader.Finder.find_item', 405 | side_effect=[xml_ibytes, xml_obytes]): 406 | with pytest.raises(SystemExit): 407 | check.main(verbose=3) 408 | 409 | assert check.exitcode == 3 410 | assert check.state == ServiceState(code=3, text='unknown') 411 | assert check.summary_str == 'Couldn\'t get a valid value!' 412 | -------------------------------------------------------------------------------- /tests/test_useragent.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | 4 | """ 5 | test_check_paloalto 6 | ---------------------------------- 7 | 8 | Tests for `check_paloalto` modules. 9 | """ 10 | 11 | import pytest 12 | import responses 13 | from nagiosplugin.state import ServiceState 14 | 15 | import check_pa.modules.useragent 16 | import utils 17 | 18 | 19 | class TestUserAgent(object): 20 | @classmethod 21 | def setup_class(cls): 22 | """setup host and token for test of Palo Alto Firewall""" 23 | cls.host = 'localhost' 24 | cls.token = 'test' 25 | 26 | @responses.activate 27 | def test_useragent(self): 28 | self.warn = 60 29 | self.crit = 240 30 | 31 | f = 'useragent_ok.xml' 32 | check = check_pa.modules.useragent.create_check(self) 33 | obj = check.resources[0] 34 | 35 | with responses.RequestsMock() as rsps: 36 | rsps.add(responses.GET, 37 | obj.xml_obj.build_request_url(), 38 | body=utils.read_xml(f), 39 | status=200, 40 | content_type='document', 41 | match_querystring=True) 42 | with pytest.raises(SystemExit): 43 | check.main(verbose=3) 44 | 45 | assert check.exitcode == 0 46 | assert check.state == ServiceState(code=0, text='ok') 47 | assert check.summary_str == 'All agents are connected and responding.' 48 | 49 | @responses.activate 50 | def test_useragent_warning(self): 51 | self.warn = 60 52 | self.crit = 240 53 | 54 | f = 'useragent_last_heared.xml' 55 | check = check_pa.modules.useragent.create_check(self) 56 | obj = check.resources[0] 57 | 58 | with responses.RequestsMock() as rsps: 59 | rsps.add(responses.GET, 60 | obj.xml_obj.build_request_url(), 61 | body=utils.read_xml(f), 62 | status=200, 63 | content_type='document', 64 | match_querystring=True) 65 | with pytest.raises(SystemExit): 66 | check.main(verbose=3) 67 | 68 | assert check.exitcode == 1 69 | assert check.state == ServiceState(code=1, text='warning') 70 | assert check.summary_str == 'Agent: Agent1 - Name1(vsys: vsys1) Host: 10.10.10.10(10.10.10.10):5007 ' \ 71 | 'last heared: 61 seconds ago' 72 | 73 | @responses.activate 74 | def test_useragent_critical_noconn(self): 75 | self.warn = 60 76 | self.crit = 240 77 | 78 | f = 'useragent_no_connection.xml' 79 | check = check_pa.modules.useragent.create_check(self) 80 | obj = check.resources[0] 81 | 82 | with responses.RequestsMock() as rsps: 83 | rsps.add(responses.GET, 84 | obj.xml_obj.build_request_url(), 85 | body=utils.read_xml(f), 86 | status=200, 87 | content_type='document', 88 | match_querystring=True) 89 | with pytest.raises(SystemExit): 90 | check.main(verbose=3) 91 | 92 | assert check.exitcode == 2 93 | assert check.state == ServiceState(code=2, text='critical') 94 | assert check.summary_str == 'Agent: Agent2 - Name2(vsys: vsys1) Host: 192.168.0.1(192.168.0.1):5007 ' \ 95 | 'connection status is error, ' \ 96 | 'Agent: Agent3 - Name3(vsys: vsys1) Host:11.11.11.11(11.11.11.11):5007 ' \ 97 | 'connection status is non-conn' 98 | 99 | @responses.activate 100 | def test_useragent_critical_last_heared(self): 101 | self.warn = 2 102 | self.crit = 30 103 | 104 | f = 'useragent_last_heared.xml' 105 | check = check_pa.modules.useragent.create_check(self) 106 | obj = check.resources[0] 107 | 108 | with responses.RequestsMock() as rsps: 109 | rsps.add(responses.GET, 110 | obj.xml_obj.build_request_url(), 111 | body=utils.read_xml(f), 112 | status=200, 113 | content_type='document', 114 | match_querystring=True) 115 | with pytest.raises(SystemExit): 116 | check.main(verbose=3) 117 | 118 | assert check.exitcode == 2 119 | assert check.state == ServiceState(code=2, text='critical') 120 | assert check.summary_str == 'Agent: Agent1 - Name1(vsys: vsys1) Host: 10.10.10.10(10.10.10.10):5007 last heared: 61 seconds ago' 121 | 122 | @responses.activate 123 | def test_useragent_changed_format(self): 124 | self.warn = 2 125 | self.crit = 30 126 | 127 | f = 'useragent_changed_format.xml' 128 | check = check_pa.modules.useragent.create_check(self) 129 | obj = check.resources[0] 130 | 131 | with responses.RequestsMock() as rsps: 132 | rsps.add(responses.GET, 133 | obj.xml_obj.build_request_url(), 134 | body=utils.read_xml(f), 135 | status=200, 136 | content_type='document', 137 | match_querystring=True) 138 | with pytest.raises(SystemExit): 139 | check.main(verbose=3) 140 | 141 | assert check.exitcode == 3 142 | assert check.state == ServiceState(code=3, text='unknown') 143 | -------------------------------------------------------------------------------- /tests/test_xml_reader.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | 4 | """ 5 | test_check_paloalto 6 | ---------------------------------- 7 | 8 | Tests for `check_paloalto` modules. 9 | """ 10 | 11 | import pytest 12 | import responses 13 | from nagiosplugin import CheckError 14 | 15 | import utils 16 | from check_pa.xml_reader import XMLReader, Finder 17 | 18 | 19 | class TestCheckPaloAltoXML(object): 20 | @responses.activate 21 | def test_xml_read_response(self): 22 | f = 'diskspace.xml' 23 | xml_reader = XMLReader('test.de', 'test', 'test') 24 | 25 | with responses.RequestsMock() as rsps: 26 | rsps.add(responses.GET, xml_reader.build_request_url(), 27 | body=utils.read_xml(f), status=200, 28 | content_type='document', 29 | match_querystring=True) 30 | xml_response = xml_reader.read() 31 | text = xml_response.response['status'] 32 | assert text == "success" 33 | 34 | @responses.activate 35 | def test_xml_exception_404(self): 36 | f = 'diskspace.xml' 37 | xml_reader = XMLReader('test.de', 'test', 'test') 38 | 39 | with responses.RequestsMock() as rsps: 40 | rsps.add(responses.GET, xml_reader.build_request_url(), 41 | body=utils.read_xml(f), status=404, 42 | content_type='document', 43 | match_querystring=True) 44 | with pytest.raises(CheckError): 45 | xml_reader.read() 46 | 47 | @responses.activate 48 | def test_not_authorized(self): 49 | f = 'not_authorized.xml' 50 | xml_reader = XMLReader('test.de', 'test', 'test') 51 | 52 | with responses.RequestsMock() as rsps: 53 | rsps.add(responses.GET, xml_reader.build_request_url(), 54 | body=utils.read_xml(f), status=200, 55 | content_type='document', 56 | match_querystring=True) 57 | with pytest.raises(CheckError): 58 | xml_reader.read() 59 | 60 | @responses.activate 61 | def test_finder(self): 62 | f = 'load.xml' 63 | xml_reader = XMLReader('test.de', 'test', 'test') 64 | 65 | with responses.RequestsMock() as rsps: 66 | rsps.add(responses.GET, xml_reader.build_request_url(), 67 | body=utils.read_xml(f), status=200, 68 | content_type='document', 69 | match_querystring=True) 70 | xml_response = xml_reader.read() 71 | found = Finder.find_item(xml_response, 'coreid') 72 | assert '0' == found 73 | 74 | @responses.activate 75 | def test_finder2(self): 76 | f = 'load.xml' 77 | xml_reader = XMLReader('test.de', 'test', 'test') 78 | 79 | with responses.RequestsMock() as rsps: 80 | rsps.add(responses.GET, xml_reader.build_request_url(), 81 | body=utils.read_xml(f), status=200, 82 | content_type='document', 83 | match_querystring=True) 84 | xml_response = xml_reader.read() 85 | with pytest.raises(CheckError): 86 | Finder.find_item(xml_response, 'test') 87 | -------------------------------------------------------------------------------- /tests/utils.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | 4 | import os 5 | 6 | 7 | def read_xml(xml_file): 8 | project_root = os.path.abspath(os.path.dirname(__file__)) 9 | xml_path = os.path.join(project_root, 'xml', xml_file) 10 | with open(xml_path, "r") as f: 11 | return f.read() 12 | -------------------------------------------------------------------------------- /tests/xml/certificates.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 1234 7 | 1234 8 | Oct 01 07:00:00 2011 GMT 9 | 10 | C=AT/ST=Steiermark/L=Graz/O=TrustMe Ltd/OU=Certificate 11 | Authority/CN=CA/Email=ca@trustme.dom 12 | 13 | Oct 02 07:00:00 2011 GMT 14 | test-certificate1 15 | 1443861936 16 | yes 17 | 18 | /C=AT/ST=Steiermark/L=Graz/O=TrustMe Ltd/OU=Certificate 19 | Authority/CN=CA/Email=ca@trustme.dom 20 | 21 | 22 | -----BEGIN CERTIFICATE----- 23 | ... 24 | -----END CERTIFICATE----- 25 | 26 | 27 | ... 28 | 29 | 30 | 31 | 1234 32 | 1234 33 | Oct 01 07:00:00 2011 GMT 34 | 35 | C=AT/ST=Steiermark/L=Graz/O=TrustMe Ltd/OU=Certificate 36 | Authority/CN=CA/Email=ca@trustme.dom 37 | 38 | Oct 03 07:00:00 2011 GMT 39 | test-certificate2 40 | 1443861936 41 | yes 42 | 43 | /C=AT/ST=Steiermark/L=Graz/O=TrustMe Ltd/OU=Certificate 44 | Authority/CN=CA/Email=ca@trustme.dom 45 | 46 | 47 | -----BEGIN CERTIFICATE----- 48 | ... 49 | -----END CERTIFICATE----- 50 | 51 | 52 | ... 53 | 54 | 55 | 56 | 57 | -------------------------------------------------------------------------------- /tests/xml/diskspace.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | Filesystem Size Used Avail Use% Mounted on 4 | /dev/sda2 3.8G 2.1G 1.6G 57% / 5 | /dev/sda5 7.6G 3.1G 4.2G 43% /opt/pancfg 6 | /dev/sda6 3.8G 1.1G 2.6G 30% /opt/panrepo 7 | tmpfs 1.9G 67M 1.8G 4% /dev/shm 8 | /dev/sda8 90G 40G 46G 47% /opt/panlogs 9 | 10 | -------------------------------------------------------------------------------- /tests/xml/environmentals_alarms.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 60.0 8 | True 9 | 5.0 10 | Temperature @ Test1 11 | 25.0 12 | 13 | 14 | 60.0 15 | True 16 | 5.0 17 | Temperature @ Test2 18 | 25.0 19 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /tests/xml/environmentals_ok.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 60.0 8 | False 9 | 5.0 10 | Temperature @ Test1 11 | 30.5 12 | 13 | 14 | 60.0 15 | False 16 | 5.0 17 | Temperature @ Test2 18 | 34.5 19 | 20 | 21 | 60.0 22 | False 23 | 5.0 24 | Temperature @ Test3 25 | 37.0 26 | 27 | 28 | 29 | 30 | -------------------------------------------------------------------------------- /tests/xml/error.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /tests/xml/load.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 0 11 | 0 12 | 13 | 14 | 1 15 | 2 16 | 17 | 18 | 2 19 | 4 20 | 21 | 22 | 3 23 | 4 24 | 25 | 26 | 4 27 | 5 28 | 29 | 30 | 5 31 | 6 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | -------------------------------------------------------------------------------- /tests/xml/mock_result.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /tests/xml/not_authorized.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /tests/xml/thermal.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 60.0 8 | False 9 | 5.0 10 | Temperature @ Test1 11 | 30.6 12 | 13 | 14 | 60.0 15 | False 16 | 5.0 17 | Temperature @ Test2 18 | 34.4 19 | 20 | 21 | 60.0 22 | False 23 | 5.0 24 | Temperature @ Test3 25 | 37.0 26 | 27 | 28 | 60.0 29 | False 30 | 5.0 31 | Temperature @ Test4 32 | 25.0 33 | 34 | 35 | 36 | 37 | -------------------------------------------------------------------------------- /tests/xml/throughput1.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /tests/xml/throughput2.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /tests/xml/throughput3.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /tests/xml/useragent_changed_format.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 8 | 9 | -------------------------------------------------------------------------------- /tests/xml/useragent_last_heared.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 103 | 104 | -------------------------------------------------------------------------------- /tests/xml/useragent_no_connection.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 103 | 104 | -------------------------------------------------------------------------------- /tests/xml/useragent_ok.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 103 | 104 | -------------------------------------------------------------------------------- /tox.ini: -------------------------------------------------------------------------------- 1 | [tox] 2 | envlist = py27, py33, py34, py35 3 | toxworkdir={homedir} 4 | 5 | [testenv] 6 | setenv = 7 | PYTHONPATH = {toxinidir}:{toxinidir}/check_pa 8 | deps = 9 | -r{toxinidir}/requirements.txt 10 | commands = 11 | pip install -U pip 12 | py.test --basetemp={envtmpdir} 13 | 14 | [testenv:style] 15 | deps = 16 | -r{toxinidir}/requirements.txt 17 | flake8 18 | commands = 19 | python setup.py flake8 20 | 21 | [testenv:docs] 22 | changedir=docs/ 23 | deps = 24 | -r{toxinidir}/requirements.txt 25 | sphinx 26 | commands = 27 | sphinx-build -b linkcheck ./ _build/ 28 | sphinx-build -b html ./ _build/ 29 | --------------------------------------------------------------------------------