././@PaxHeader0000000000000000000000000000003300000000000011451 xustar000000000000000027 mtime=1740146654.540185 oslo_reports-3.5.1/0000775000175000017500000000000000000000000014275 5ustar00zuulzuul00000000000000././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1740146607.0 oslo_reports-3.5.1/.coveragerc0000664000175000017500000000016300000000000016416 0ustar00zuulzuul00000000000000[run] branch = True source = oslo_reports omit = oslo_reports/tests/* [report] ignore_errors = True precision = 2 ././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1740146607.0 oslo_reports-3.5.1/.mailmap0000664000175000017500000000013100000000000015711 0ustar00zuulzuul00000000000000# Format is: # # ././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1740146607.0 oslo_reports-3.5.1/.pre-commit-config.yaml0000664000175000017500000000213700000000000020561 0ustar00zuulzuul00000000000000repos: - repo: https://github.com/pre-commit/pre-commit-hooks rev: v5.0.0 hooks: - id: trailing-whitespace # Replaces or checks mixed line ending - id: mixed-line-ending args: ['--fix', 'lf'] exclude: '.*\.(svg)$' # Forbid files which have a UTF-8 byte-order marker - id: check-byte-order-marker # Checks that non-binary executables have a proper shebang - id: check-executables-have-shebangs # Check for files that contain merge conflict strings. - id: check-merge-conflict # Check for debugger imports and py37+ breakpoint() # calls in python source - id: debug-statements - id: check-yaml files: .*\.(yaml|yml)$ - repo: https://opendev.org/openstack/hacking rev: 7.0.0 hooks: - id: hacking additional_dependencies: [] - repo: https://github.com/PyCQA/bandit rev: 1.7.10 hooks: - id: bandit args: ['-x', 'tests', '-s', 'B314,B405'] - repo: https://github.com/asottile/pyupgrade rev: v3.18.0 hooks: - id: pyupgrade args: [--py3-only] ././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1740146607.0 oslo_reports-3.5.1/.stestr.conf0000664000175000017500000000006500000000000016547 0ustar00zuulzuul00000000000000[DEFAULT] test_path=./oslo_reports/tests top_path=./ ././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1740146607.0 oslo_reports-3.5.1/.zuul.yaml0000664000175000017500000000033300000000000016235 0ustar00zuulzuul00000000000000- project: templates: - check-requirements - lib-forward-testing-python3 - openstack-python3-jobs - periodic-stable-jobs - publish-openstack-docs-pti - release-notes-jobs-python3 ././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1740146654.0 oslo_reports-3.5.1/AUTHORS0000664000175000017500000000502500000000000015347 0ustar00zuulzuul00000000000000Adam Harwell Alessandro Pilotti Alex Gaynor Andreas Jaeger Andreas Jaeger Ben Nemec Brant Knudson Chang Bo Guo ChangBo Guo(gcb) Chris Lamb Christian Berendt Corey Bryant D G Lee Daisuke Fujita Daniel Bengtsson Davanum Srinivas Davanum Srinivas Dirk Mueller Doug Hellmann Eric Brown Flavio Percoco Frederic Lepied Ghanshyam Ghanshyam Mann Hervé Beraud Ildiko Ivan Kolodyazhny Jason Kölker Jay Pipes Joe Gordon Joel Capitao Johannes Kulik Joshua Harlow Julien Danjou Kashyap Chamarthy Kenneth Giusti Moisés Guimarães de Medeiros Nikola Dipanov OpenStack Release Bot Romain Soufflet Ronald Bradford Sean McGinnis Solly Ross Stephen Finucane Takashi Kajinami Takashi Kajinami Trevor Vardeman Vasyl Saienko Victor Sergeyev Vu Cong Tuan Zang MingJie ZhiQiang Fan ZhijunWei ZhongShengping Zhongyue Luo caoyuan gecong1973 gujin jacky06 loooosy melissaml niuke pengyuesheng tanlin wangqi wangzihao wu.shiming yangyawei zhangchunlong1@huawei.com zhoulinhui ././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1740146607.0 oslo_reports-3.5.1/CONTRIBUTING.rst0000664000175000017500000000153000000000000016735 0ustar00zuulzuul00000000000000If you would like to contribute to the development of oslo's libraries, first you must take a look to this page: https://specs.openstack.org/openstack/oslo-specs/specs/policy/contributing.html If you would like to contribute to the development of OpenStack, you must follow the steps in this page: https://docs.openstack.org/infra/manual/developers.html If you already have a good understanding of how the system works and your OpenStack accounts are set up, you can skip to the development workflow section of this documentation to learn how changes to OpenStack should be submitted for review via the Gerrit tool: https://docs.openstack.org/infra/manual/developers.html#development-workflow Pull requests submitted through GitHub will be ignored. Bugs should be filed on Launchpad, not GitHub: https://bugs.launchpad.net/oslo.reports ././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1740146654.0 oslo_reports-3.5.1/ChangeLog0000664000175000017500000002566100000000000016061 0ustar00zuulzuul00000000000000CHANGES ======= 3.5.1 ----- * Skip installation to speed up pep8 * reno: Update master for unmaintained/2023.1 3.5.0 ----- * Add note about requirements lower bounds * Remove Python 3.8 support * Run pyupgrade to clean up Python 2 syntaxes * Declare Python 3.12 support * Update master for stable/2024.2 * Handle shell\_completion option in test suite 3.4.0 ----- * Remove old excludes * Update master for stable/2024.1 * reno: Update master for unmaintained/victoria 3.3.0 ----- * Remove logic for python 2 support * Update coverage commands * pre-commit: Integrate bandit * pre-commit: Bump versions * Make greenlet optional * Add missing direct imports * Bump hacking * Update python classifier in setup.cfg 3.2.0 ----- * Update master for stable/2023.2 * GMR: Allow disabling signal handler 3.1.0 ----- * Imported Translations from Zanata * Bump bandit * Revert "Moves supported python runtimes from version 3.8 to 3.10" * Moves supported python runtimes from version 3.8 to 3.10 * Update master for stable/2023.1 3.0.0 ----- * remove unicode prefix from code * remove unicode literal from code * Imported Translations from Zanata * Fix formatting of release list * Drop python3.6/3.7 support in testing runtime 2.4.0 ----- * Update CI to use unversioned jobs template * Support integer keys of dicts in text serialization * Changed minversion in tox to 3.18.0 2.3.0 ----- * Switch testing to Xena testing runtime * setup.cfg: Replace dashes with underscores * Move flake8 as a pre-commit local target * Remove lower-constraints remnants * Dropping lower constraints testing * Replace concatenation with f-strings * Use TOX\_CONSTRAINTS\_FILE * Use py3 as the default runtime for tox * Fix hacking min version to 3.0.1 * Remove all six usage * Adding pre-commit * Add Python3 wallaby unit tests * Update master for stable/victoria 2.2.0 ----- * [goal] Migrate testing to ubuntu focal * Bump bandit version * Fix pygments style 2.1.0 ----- * Stop to use the \_\_future\_\_ module * Switch to newer openstackdocstheme and reno versions * Remove the unused coding style modules * Remove translation sections from setup.cfg * Align contributing doc with oslo's policy * Bump default tox env from py37 to py38 * Add py38 package metadata * Add release notes links to doc index * Add Python3 victoria unit tests * Update master for stable/ussuri 2.0.1 ----- * Update hacking for Python3 * Use unittest.mock instead of third party mock 2.0.0 ----- * remove outdated header * [ussuri][goal] Drop python 2.7 support and testing * tox: Trivial cleanup * trivial: Remove cruft from sphinx config file * tox: Add missing deps for 'releasenotes' job 1.31.1 ------ * Switch from 'collections' -> 'collections.abc' * Exclude tests from apidoc * tox: Keeping going with docs * Switch to Ussuri jobs * Update the constraints url 1.31.0 ------ * Update master for stable/train 1.30.0 ------ * Add Python 3 Train unit tests * Move doc related modules to doc/requirements.txt * Sync Sphinx requirement * Replace git.openstack.org URLs with opendev.org URLs * OpenDev Migration Patch * Update master for stable/stein 1.29.2 ------ * add python 3.7 unit test job * Update hacking version * Use template for lower-constraints * Update mailinglist from dev to discuss * Clean up .gitignore references to personal tools 1.29.1 ------ * Imported Translations from Zanata * add lib-forward-testing-python3 test job * add python 3.6 unit test job * import zuul job settings from project-config * Update unit test to reflect latest oslo.config * Update reno for stable/rocky * Switch to stestr * Add release notes link to README * fix tox python3 overrides * Remove the remaining of the removed option * Replace deprecated "auth\_uri" by "www\_authenticate\_uri" * Remove stale pip-missing-reqs and pypy tox tests * Trivial: Update pypi url to new url 1.28.0 ------ * set default python to python3 * fix lower constraints and uncap eventlet * Document workaround for AccessDenied error * add lower-constraints job * Updated from global requirements * Update links in README 1.27.0 ------ * Imported Translations from Zanata * Imported Translations from Zanata * Update reno for stable/queens * Updated from global requirements * Updated from global requirements * Updated from global requirements * Updated from global requirements 1.26.0 ------ * Updated from global requirements * Add bandit to pep8 job 1.25.0 ------ * Remove -U from pip install * Avoid tox\_install.sh for constraints support * Updated from global requirements * Remove setting of version/release from releasenotes * Updated from global requirements * Updated from global requirements 1.24.0 ------ * Imported Translations from Zanata * Remove psutil 1.x compat wrapping * Updated from global requirements 1.23.0 ------ * Updated from global requirements * Update the documentation link * Remove SIGUSR1 handler, which was deprecated after Ocata * Updated from global requirements * Update reno for stable/pike * Updated from global requirements 1.22.0 ------ * Updated from global requirements * update the doc URL according to document migration 1.21.1 ------ * switch from oslosphinx to openstackdocstheme * rearrange content to fit the new standard layout 1.21.0 ------ * Updated from global requirements * Updated from global requirements * Remove pbr warnerrors in favor of sphinx check * Updated from global requirements 1.20.0 ------ * Updated from global requirements * Updated from global requirements * Updated from global requirements * Updated from global requirements * Updated from global requirements * Updated from global requirements 1.19.0 ------ * Remove log translations * Updated from global requirements 1.18.0 ------ * Updated from global requirements * Updated from global requirements * Updated from global requirements * Updated from global requirements * Updated from global requirements * Update reno for stable/ocata * Remove references to Python 3.4 1.17.0 ------ * Updated from global requirements * Updated from global requirements * Add Constraints support * Bump hacking dep * Show team and repo badges on README 1.16.0 ------ * Fix a typo * Updated from global requirements * Add reno for release notes management * Updated from global requirements * Updated from global requirements * Changed the home-page link 1.15.0 ------ * Updated from global requirements 1.14.0 ------ * Updated from global requirements 1.13.0 ------ * Updated from global requirements * Add Python 3.5 classifier and venv 1.12.0 ------ * Updated from global requirements * Updated from global requirements * Updated from global requirements 1.11.0 ------ * Use file modification events instead of signal handler * Imported Translations from Zanata 1.10.0 ------ * Updated from global requirements 1.9.0 ----- * Trivial: ignore openstack/common in flake8 exclude list 1.8.0 ----- * Remove direct dependency on babel * Updated from global requirements * Updated from global requirements * Updated from global requirements 1.6.0 ----- * Updated from global requirements * Updated from global requirements 1.5.0 ----- * Updated from global requirements 1.4.0 ----- * Update translation setup * Updated from global requirements * Updated from global requirements * Updated from global requirements * Updated from global requirements * Updated from global requirements 1.3.0 ----- * Updated from global requirements 1.2.0 ----- * Print the traceback if there was an exception in run() * Rename signal handler argument to 'frame' * Updated from global requirements * Updated from global requirements * Trival: Remove 'MANIFEST.in' 1.1.0 ----- * Drop python 2.6 support 1.0.0 ----- * Updated from global requirements * Remove Python 2.6 classifier * Updated from global requirements * Remove python 2.6 and cleanup tox.ini 0.8.0 ----- * Fix Transition to SIGUSR2 in oslo.reports breaks upgrade * Updated from global requirements * Updated from global requirements 0.7.0 ----- * Updated from global requirements * Fix a typo in process.py 0.6.0 ----- * remove extraneous coverage omit instruction * No need for Oslo Incubator Sync * Fix coverage configuration and execution * How to use oslo.reports documentation * add auto-generated api documentation * clean up release notes in toctree * add auto-generated docs for config options * Add shields.io version/downloads links/badges into README.rst * Updated from global requirements * guru\_meditation\_report: Use SIGUSR2 instead of SIGUSR1 0.5.0 ----- * Updated from global requirements * Updated from global requirements * Add a configuration for the directory to generate gmr * Fill README from information in the wiki * Updated from global requirements * Setup translations * Updated from global requirements 0.4.0 ----- * Updated from global requirements 0.3.0 ----- * Updated from global requirements * Fix mock of open() for mock 1.1.0 * Fix GMR break with new psutil versions 0.2.0 ----- * Add oslo.utils dependency * Add tox target to find missing requirements 0.1.0 ----- * Updated from global requirements * Guru Meditation Reports broken without version\_string * Fix intermittent test failures because of sort order * Graduation Prep: Use six.text\_type instead of str * Graduation Prep: Initial Import Fixup * exported from oslo-incubator by graduate.sh * Remove timeutils.strtime() usage * Switch from oslo.config to oslo\_config * Use oslo\_utils instead of deprecated oslo.utils * Report: Add basic processes section * Change oslo.config to oslo\_config * switch to oslo\_serialization * Reports: Use sig handler traceback for curr thread * Report: Propagate view\_type through collections * Report: Support Sequences and Mappings as Data * Use same mask pattern for reports as mask\_password * Mask secrets when output conf * Delete graduated serialization files * Remove our custom test base class * Switch oslo-incubator to use oslo.utils and remove old modules * Fix tests.unit.reports.\* with python3.4 * Fix tests.unit.reports.test\_base\_report with python3.4 * Set pbr 'warnerrors' option for doc build * fixed typos found by RETF rules * Report: Fix JinjaView deepcopy * Fixed several typos * Fix tests.unit.reports.test\_guru\_meditation\_report under Python3 * Use from/import style in module report * Fix tests.unit.reports.test\_views failures under Python3 * Add option for GM report to dump to a file * Removed unneeded #noqa tag * Fixes Guru Meditation portability issue * Fix typo in inline documentation for report module * Use six.StringIO/BytesIO instead of StringIO.StringIO * Rename Openstack to OpenStack * Avoid failure of test\_basic\_report on 32 bit OS * Fix filter() usage due to python 3 compability * Unify different names between Python2/3 with six.moves * Remove vim header * Use six.string\_type instead of basestring * Fix typos in oslo * Adjust import order according to PEP8 imports rule * Replace assertEquals with assertEqual * Introduces The Guru Meditation Report * Introduces Openstack-Specific Report Utilities * Introduces Report Views * Introduces Basic Report and Model * initial commit * Initial skeleton project ././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1740146607.0 oslo_reports-3.5.1/HACKING.rst0000664000175000017500000000022200000000000016067 0ustar00zuulzuul00000000000000oslo.reports Style Commandments =============================== Read the OpenStack Style Commandments https://docs.openstack.org/hacking/latest/ ././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1740146607.0 oslo_reports-3.5.1/LICENSE0000664000175000017500000002363700000000000015315 0ustar00zuulzuul00000000000000 Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. ././@PaxHeader0000000000000000000000000000003300000000000011451 xustar000000000000000027 mtime=1740146654.540185 oslo_reports-3.5.1/PKG-INFO0000644000175000017500000000775200000000000015403 0ustar00zuulzuul00000000000000Metadata-Version: 2.1 Name: oslo.reports Version: 3.5.1 Summary: oslo.reports library Home-page: https://docs.openstack.org/oslo.reports/latest Author: OpenStack Author-email: openstack-discuss@lists.openstack.org Classifier: Environment :: OpenStack Classifier: Intended Audience :: Information Technology Classifier: Intended Audience :: System Administrators Classifier: License :: OSI Approved :: Apache Software License Classifier: Operating System :: POSIX :: Linux Classifier: Programming Language :: Python Classifier: Programming Language :: Python :: 3 Classifier: Programming Language :: Python :: 3.9 Classifier: Programming Language :: Python :: 3.10 Classifier: Programming Language :: Python :: 3.11 Classifier: Programming Language :: Python :: 3.12 Classifier: Programming Language :: Python :: 3 :: Only Classifier: Programming Language :: Python :: Implementation :: CPython Requires-Python: >=3.9 License-File: LICENSE Requires-Dist: pbr>=2.0.0 Requires-Dist: Jinja2>=2.10 Requires-Dist: oslo.serialization>=2.18.0 Requires-Dist: psutil>=3.2.2 Requires-Dist: oslo.i18n>=3.15.3 Requires-Dist: oslo.utils>=3.33.0 Requires-Dist: oslo.config>=5.1.0 Provides-Extra: greenlet Requires-Dist: greenlet>=0.4.15; extra == "greenlet" Provides-Extra: test Requires-Dist: oslotest>=3.2.0; extra == "test" Requires-Dist: stestr>=2.0.0; extra == "test" Requires-Dist: greenlet>=0.4.15; extra == "test" Requires-Dist: coverage>=4.0; extra == "test" ======================== Team and repository tags ======================== .. image:: https://governance.openstack.org/tc/badges/oslo.reports.svg :target: https://governance.openstack.org/tc/reference/tags/index.html .. Change things from this point on =================================== oslo.reports =================================== .. image:: https://img.shields.io/pypi/v/oslo.reports.svg :target: https://pypi.org/project/oslo.reports/ :alt: Latest Version .. image:: https://img.shields.io/pypi/dm/oslo.reports.svg :target: https://pypi.org/project/oslo.reports/ :alt: Downloads When things go wrong in (production) deployments of OpenStack collecting debug data is a key first step in the process of triaging & ultimately resolving the problem. Projects like Nova has extensively used logging capabilities which produce a vast amount of data. This does not, however, enable an admin to obtain an accurate view on the current live state of the system. For example, what threads are running, what config parameters are in effect, and more. The project oslo.reports hosts a general purpose error report generation framework, known as the "guru meditation report" (cf http://en.wikipedia.org/wiki/Guru_Meditation) to address the issues described above. Models: These classes define structured data for a variety of interesting pieces of state. For example, stack traces, threads, config parameters, package version info, etc. They are capable of being serialized to XML / JSON or a plain text representation Generators: These classes are used to populate the model classes with the current runtime state of the system Views: views serialize models into say JSON, text or xml. There is also a predefined view that utilizes Jinja templating system. There will be a number of standard models / generators available for all OpenStack services StackTraceModel: a base class for any model which includes a stack trace ThreadModel: a class for information about a thread ExceptionModel: a class for information about a caught exception ConfigModel: a class for information about configuration file settings PackageModel: a class for information about vendor/product/version/package information Each OpenStack project will have the ability to register further generator classes to provide custom project specific data. * Free software: Apache license * Documentation: https://docs.openstack.org/oslo.reports/latest * Source: https://opendev.org/openstack/oslo.reports * Bugs: https://bugs.launchpad.net/oslo.reports * Release notes: https://docs.openstack.org/releasenotes/oslo.reports/ ././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1740146607.0 oslo_reports-3.5.1/README.rst0000664000175000017500000000507300000000000015771 0ustar00zuulzuul00000000000000======================== Team and repository tags ======================== .. image:: https://governance.openstack.org/tc/badges/oslo.reports.svg :target: https://governance.openstack.org/tc/reference/tags/index.html .. Change things from this point on =================================== oslo.reports =================================== .. image:: https://img.shields.io/pypi/v/oslo.reports.svg :target: https://pypi.org/project/oslo.reports/ :alt: Latest Version .. image:: https://img.shields.io/pypi/dm/oslo.reports.svg :target: https://pypi.org/project/oslo.reports/ :alt: Downloads When things go wrong in (production) deployments of OpenStack collecting debug data is a key first step in the process of triaging & ultimately resolving the problem. Projects like Nova has extensively used logging capabilities which produce a vast amount of data. This does not, however, enable an admin to obtain an accurate view on the current live state of the system. For example, what threads are running, what config parameters are in effect, and more. The project oslo.reports hosts a general purpose error report generation framework, known as the "guru meditation report" (cf http://en.wikipedia.org/wiki/Guru_Meditation) to address the issues described above. Models: These classes define structured data for a variety of interesting pieces of state. For example, stack traces, threads, config parameters, package version info, etc. They are capable of being serialized to XML / JSON or a plain text representation Generators: These classes are used to populate the model classes with the current runtime state of the system Views: views serialize models into say JSON, text or xml. There is also a predefined view that utilizes Jinja templating system. There will be a number of standard models / generators available for all OpenStack services StackTraceModel: a base class for any model which includes a stack trace ThreadModel: a class for information about a thread ExceptionModel: a class for information about a caught exception ConfigModel: a class for information about configuration file settings PackageModel: a class for information about vendor/product/version/package information Each OpenStack project will have the ability to register further generator classes to provide custom project specific data. * Free software: Apache license * Documentation: https://docs.openstack.org/oslo.reports/latest * Source: https://opendev.org/openstack/oslo.reports * Bugs: https://bugs.launchpad.net/oslo.reports * Release notes: https://docs.openstack.org/releasenotes/oslo.reports/ ././@PaxHeader0000000000000000000000000000003400000000000011452 xustar000000000000000028 mtime=1740146654.5201795 oslo_reports-3.5.1/doc/0000775000175000017500000000000000000000000015042 5ustar00zuulzuul00000000000000././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1740146607.0 oslo_reports-3.5.1/doc/requirements.txt0000664000175000017500000000016700000000000020332 0ustar00zuulzuul00000000000000openstackdocstheme>=2.2.0 # Apache-2.0 sphinx>=2.0.0 # BSD reno>=3.1.0 # Apache-2.0 sphinxcontrib-apidoc>=0.2.0 # BSD ././@PaxHeader0000000000000000000000000000003400000000000011452 xustar000000000000000028 mtime=1740146654.5201795 oslo_reports-3.5.1/doc/source/0000775000175000017500000000000000000000000016342 5ustar00zuulzuul00000000000000././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1740146607.0 oslo_reports-3.5.1/doc/source/conf.py0000664000175000017500000000365000000000000017645 0ustar00zuulzuul00000000000000# Copyright (C) 2020 Red Hat, Inc. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or # implied. # See the License for the specific language governing permissions and # limitations under the License. # -- General configuration ---------------------------------------------------- # Add any Sphinx extension module names here, as strings. They can be # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom ones. extensions = [ 'sphinx.ext.autodoc', 'sphinxcontrib.apidoc', 'openstackdocstheme', 'oslo_config.sphinxext', ] # openstackdocstheme options openstackdocs_repo_name = 'openstack/oslo.reports' openstackdocs_bug_project = 'oslo.reports' openstackdocs_bug_tag = '' # The master toctree document. master_doc = 'index' # General information about the project. copyright = '2014, OpenStack Foundation' # If true, '()' will be appended to :func: etc. cross-reference text. add_function_parentheses = True # If true, the current module name will be prepended to all description # unit titles (such as .. function::). add_module_names = True # The name of the Pygments (syntax highlighting) style to use. pygments_style = 'native' # A list of ignored prefixes for module index sorting. modindex_common_prefix = ['oslo_reports.'] # -- Options for HTML output ------------------------------------------------- html_theme = 'openstackdocs' # -- sphinxcontrib.apidoc configuration -------------------------------------- apidoc_module_dir = '../../oslo_reports' apidoc_output_dir = 'reference/api' apidoc_excluded_paths = [ 'tests', ] ././@PaxHeader0000000000000000000000000000003400000000000011452 xustar000000000000000028 mtime=1740146654.5201795 oslo_reports-3.5.1/doc/source/contributor/0000775000175000017500000000000000000000000020714 5ustar00zuulzuul00000000000000././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1740146607.0 oslo_reports-3.5.1/doc/source/contributor/index.rst0000664000175000017500000000012400000000000022552 0ustar00zuulzuul00000000000000============== Contributing ============== .. include:: ../../../CONTRIBUTING.rst ././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1740146607.0 oslo_reports-3.5.1/doc/source/index.rst0000664000175000017500000000063300000000000020205 0ustar00zuulzuul00000000000000============== oslo.reports ============== oslo.reports library Contents ======== .. toctree:: :maxdepth: 2 install/index contributor/index user/index reference/index Release Notes ============= Read also the `oslo.reports Release Notes `_. Indices and tables ================== * :ref:`genindex` * :ref:`modindex` * :ref:`search` ././@PaxHeader0000000000000000000000000000003400000000000011452 xustar000000000000000028 mtime=1740146654.5201795 oslo_reports-3.5.1/doc/source/install/0000775000175000017500000000000000000000000020010 5ustar00zuulzuul00000000000000././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1740146607.0 oslo_reports-3.5.1/doc/source/install/index.rst0000664000175000017500000000013600000000000021651 0ustar00zuulzuul00000000000000============ Installation ============ At the command line:: $ pip install oslo.reports ././@PaxHeader0000000000000000000000000000003400000000000011452 xustar000000000000000028 mtime=1740146654.5201795 oslo_reports-3.5.1/doc/source/reference/0000775000175000017500000000000000000000000020300 5ustar00zuulzuul00000000000000././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1740146607.0 oslo_reports-3.5.1/doc/source/reference/index.rst0000664000175000017500000000021000000000000022132 0ustar00zuulzuul00000000000000.. _using: ========= Reference ========= .. toctree:: :maxdepth: 2 opts API === .. toctree:: :maxdepth: 1 api/modules ././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1740146607.0 oslo_reports-3.5.1/doc/source/reference/opts.rst0000664000175000017500000000042100000000000022014 0ustar00zuulzuul00000000000000.. _option-definitions: ===================== Configuration Options ===================== oslo.reports uses oslo.config to define and manage configuration options to allow the deployer to control where the GMR reports should be generated. .. show-options:: oslo.reports ././@PaxHeader0000000000000000000000000000003400000000000011452 xustar000000000000000028 mtime=1740146654.5241807 oslo_reports-3.5.1/doc/source/user/0000775000175000017500000000000000000000000017320 5ustar00zuulzuul00000000000000././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1740146607.0 oslo_reports-3.5.1/doc/source/user/history.rst0000664000175000017500000000004000000000000021545 0ustar00zuulzuul00000000000000.. include:: ../../../ChangeLog ././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1740146607.0 oslo_reports-3.5.1/doc/source/user/index.rst0000664000175000017500000000015700000000000021164 0ustar00zuulzuul00000000000000=================== Using oslo.reports =================== .. toctree:: :maxdepth: 2 usage history ././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1740146607.0 oslo_reports-3.5.1/doc/source/user/report.txt0000664000175000017500000005303100000000000021376 0ustar00zuulzuul00000000000000======================================================================== ==== Guru Meditation ==== ======================================================================== |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||| ======================================================================== ==== Package ==== ======================================================================== product = OpenStack Nova vendor = OpenStack Foundation version = 13.0.0 ======================================================================== ==== Threads ==== ======================================================================== ------ Thread #140417215547200 ------ /usr/local/lib/python2.7/dist-packages/eventlet/hubs/hub.py:346 in run `self.wait(sleep_time)` /usr/local/lib/python2.7/dist-packages/eventlet/hubs/poll.py:82 in wait `sleep(seconds)` ======================================================================== ==== Green Threads ==== ======================================================================== ------ Green Thread ------ /usr/local/bin/nova-api:10 in `sys.exit(main())` /opt/stack/nova/nova/cmd/api.py:57 in main `launcher.wait()` /usr/local/lib/python2.7/dist-packages/oslo_service/service.py:511 in wait `self._respawn_children()` /usr/local/lib/python2.7/dist-packages/oslo_service/service.py:495 in _respawn_children `eventlet.greenthread.sleep(self.wait_interval)` /usr/local/lib/python2.7/dist-packages/eventlet/greenthread.py:34 in sleep `hub.switch()` /usr/local/lib/python2.7/dist-packages/eventlet/hubs/hub.py:294 in switch `return self.greenlet.switch()` ------ Green Thread ------ No Traceback! ======================================================================== ==== Processes ==== ======================================================================== Process 14756 (under 1) [ run by: stack (1001), state: running ] Process 14770 (under 14756) [ run by: stack (1001), state: sleeping ] Process 14771 (under 14756) [ run by: stack (1001), state: sleeping ] Process 14776 (under 14756) [ run by: stack (1001), state: sleeping ] Process 14777 (under 14756) [ run by: stack (1001), state: sleeping ] Process 14784 (under 14756) [ run by: stack (1001), state: sleeping ] Process 14785 (under 14756) [ run by: stack (1001), state: sleeping ] ======================================================================== ==== Configuration ==== ======================================================================== api_database: connection = *** connection_debug = 0 connection_trace = False idle_timeout = 3600 max_overflow = None max_pool_size = None max_retries = 10 mysql_sql_mode = TRADITIONAL pool_timeout = None retry_interval = 10 slave_connection = *** sqlite_synchronous = True cells: bandwidth_update_interval = 600 call_timeout = 60 capabilities = hypervisor=xenserver;kvm os=linux;windows cell_type = compute enable = False instance_update_sync_database_limit = 100 manager = nova.cells.manager.CellsManager mute_child_interval = 300 name = nova reserve_percent = 10.0 topic = cells cinder: cafile = None catalog_info = volumev2:cinderv2:publicURL certfile = None cross_az_attach = True endpoint_template = None http_retries = 3 insecure = False keyfile = None os_region_name = RegionOne timeout = None conductor: manager = nova.conductor.manager.ConductorManager topic = conductor use_local = False workers = 2 database: backend = sqlalchemy connection = *** connection_debug = 0 connection_trace = False db_inc_retry_interval = True db_max_retries = 20 db_max_retry_interval = 10 db_retry_interval = 1 idle_timeout = 3600 max_overflow = None max_pool_size = None max_retries = 10 min_pool_size = 1 mysql_sql_mode = TRADITIONAL pool_timeout = None retry_interval = 10 slave_connection = *** sqlite_db = nova.sqlite sqlite_synchronous = True use_db_reconnect = False use_tpool = False default: allow_instance_snapshots = True allow_resize_to_same_host = True allow_same_net_traffic = True api_paste_config = /etc/nova/api-paste.ini api_rate_limit = False auth_strategy = keystone auto_assign_floating_ip = False bandwidth_poll_interval = 600 bindir = /usr/local/bin block_device_allocate_retries = 60 block_device_allocate_retries_interval = 3 boot_script_template = /opt/stack/nova/nova/cloudpipe/bootscript.template ca_file = cacert.pem ca_path = /opt/stack/data/nova/CA cert_manager = nova.cert.manager.CertManager cert_topic = cert client_socket_timeout = 900 cnt_vpn_clients = 0 compute_available_monitors = None compute_driver = libvirt.LibvirtDriver compute_manager = nova.compute.manager.ComputeManager compute_monitors = compute_resources = vcpu compute_stats_class = nova.compute.stats.Stats compute_topic = compute config-dir = None config-file = /etc/nova/nova.conf config_drive_format = iso9660 config_drive_skip_versions = 1.0 2007-01-19 2007-03-01 2007-08-29 2007-10-10 2007-12-15 2008-02-01 2008-09-01 console_host = dims-ubuntu console_manager = nova.console.manager.ConsoleProxyManager console_topic = console consoleauth_manager = nova.consoleauth.manager.ConsoleAuthManager consoleauth_topic = consoleauth control_exchange = nova cpu_allocation_ratio = 0.0 create_unique_mac_address_attempts = 5 crl_file = crl.pem db_driver = nova.db debug = True default_access_ip_network_name = None default_availability_zone = nova default_ephemeral_format = ext4 default_flavor = m1.small default_floating_pool = public default_log_levels = amqp=WARN amqplib=WARN boto=WARN glanceclient=WARN iso8601=WARN keystonemiddleware=WARN oslo_messaging=INFO qpid=WARN requests.packages.urllib3.connectionpool=WARN routes.middleware=WARN sqlalchemy=WARN stevedore=WARN suds=INFO urllib3.connectionpool=WARN websocket=WARN default_notification_level = INFO default_publisher_id = None default_schedule_zone = None defer_iptables_apply = False dhcp_domain = novalocal dhcp_lease_time = 86400 dhcpbridge = /usr/local/bin/nova-dhcpbridge dhcpbridge_flagfile = /etc/nova/nova.conf dmz_cidr = dmz_mask = 255.255.255.0 dmz_net = 10.0.0.0 dns_server = dns_update_periodic_interval = -1 dnsmasq_config_file = ebtables_exec_attempts = 3 ebtables_retry_interval = 1.0 ec2_dmz_host = 10.0.0.9 ec2_host = 10.0.0.9 ec2_listen = 0.0.0.0 ec2_listen_port = 8773 ec2_path = / ec2_port = 8773 ec2_private_dns_show_ip = False ec2_scheme = http ec2_strict_validation = True ec2_timestamp_expiry = 300 ec2_workers = 2 enable_instance_password = True enable_network_quota = False enable_new_services = True enabled_apis = ec2 metadata osapi_compute enabled_ssl_apis = fake_call = False fake_network = False fatal_deprecations = False fatal_exception_format_errors = False firewall_driver = nova.virt.firewall.NoopFirewallDriver fixed_ip_disassociate_timeout = 600 fixed_range_v6 = fd00::/48 flat_injected = False flat_interface = None flat_network_bridge = None flat_network_dns = 8.8.4.4 floating_ip_dns_manager = nova.network.noop_dns_driver.NoopDNSDriver force_config_drive = True force_dhcp_release = True force_raw_images = True force_snat_range = forward_bridge_interface = all fping_path = /usr/sbin/fping gateway = None gateway_v6 = None heal_instance_info_cache_interval = 60 host = dims-ubuntu image_cache_manager_interval = 2400 image_cache_subdirectory_name = _base image_decryption_dir = /tmp injected_network_template = /opt/stack/nova/nova/virt/interfaces.template instance_build_timeout = 0 instance_delete_interval = 300 instance_dns_domain = instance_dns_manager = nova.network.noop_dns_driver.NoopDNSDriver instance_format = [instance: %(uuid)s] instance_name_template = instance-%08x instance_usage_audit = False instance_usage_audit_period = month instance_uuid_format = [instance: %(uuid)s] instances_path = /opt/stack/data/nova/instances internal_service_availability_zone = internal iptables_bottom_regex = iptables_drop_action = DROP iptables_top_regex = ipv6_backend = rfc2462 key_file = private/cakey.pem keys_path = /opt/stack/data/nova/keys keystone_ec2_insecure = False keystone_ec2_url = http://10.0.0.9:5000/v2.0/ec2tokens l3_lib = nova.network.l3.LinuxNetL3 linuxnet_interface_driver = linuxnet_ovs_integration_bridge = br-int live_migration_retry_count = 30 lockout_attempts = 5 lockout_minutes = 15 lockout_window = 15 log-config-append = None log-date-format = %Y-%m-%d %H:%M:%S log-dir = None log-file = None log-format = None log_options = True logging_context_format_string = %(asctime)s.%(msecs)03d %(color)s%(levelname)s %(name)s [%(request_id)s %(user_name)s %(project_name)s%(color)s] %(instance)s%(color)s%(message)s logging_debug_format_suffix = from (pid=%(process)d) %(funcName)s %(pathname)s:%(lineno)d logging_default_format_string = %(asctime)s.%(msecs)03d %(color)s%(levelname)s %(name)s [-%(color)s] %(instance)s%(color)s%(message)s logging_exception_prefix = %(color)s%(asctime)s.%(msecs)03d TRACE %(name)s %(instance)s max_age = 0 max_concurrent_builds = 10 max_concurrent_live_migrations = 1 max_header_line = 16384 max_local_block_devices = 3 maximum_instance_delete_attempts = 5 memcached_servers = None metadata_cache_expiration = 15 metadata_host = 10.0.0.9 metadata_listen = 0.0.0.0 metadata_listen_port = 8775 metadata_manager = nova.api.manager.MetadataManager metadata_port = 8775 metadata_workers = 2 migrate_max_retries = -1 mkisofs_cmd = genisoimage monkey_patch = False monkey_patch_modules = nova.api.ec2.cloud:nova.notifications.notify_decorator nova.compute.api:nova.notifications.notify_decorator multi_host = False my_block_storage_ip = 10.0.0.9 my_ip = 10.0.0.9 network_allocate_retries = 0 network_api_class = nova.network.neutronv2.api.API network_device_mtu = None network_driver = nova.network.linux_net network_manager = nova.network.manager.VlanManager network_size = 256 network_topic = network networks_path = /opt/stack/data/nova/networks neutron_default_tenant_id = default non_inheritable_image_properties = bittorrent cache_in_nova notification_driver = notification_topics = notifications notify_api_faults = False notify_on_state_change = None null_kernel = nokernel num_networks = 1 osapi_compute_ext_list = osapi_compute_extension = nova.api.openstack.compute.legacy_v2.contrib.standard_extensions osapi_compute_link_prefix = None osapi_compute_listen = 0.0.0.0 osapi_compute_listen_port = 8774 osapi_compute_unique_server_name_scope = osapi_compute_workers = 2 osapi_glance_link_prefix = None osapi_hide_server_address_states = building osapi_max_limit = 1000 ovs_vsctl_timeout = 120 password_length = 12 pci_alias = pci_passthrough_whitelist = periodic_enable = True periodic_fuzzy_delay = 60 policy_default_rule = default policy_dirs = policy.d policy_file = policy.json preallocate_images = none project_cert_subject = /C=US/ST=California/O=OpenStack/OU=NovaDev/CN=project-ca-%.16s-%s public_interface = eth0 publish_errors = False pybasedir = /opt/stack/nova quota_cores = 20 quota_driver = nova.quota.DbQuotaDriver quota_fixed_ips = -1 quota_floating_ips = 10 quota_injected_file_content_bytes = 10240 quota_injected_file_path_length = 255 quota_injected_files = 5 quota_instances = 10 quota_key_pairs = 100 quota_metadata_items = 128 quota_networks = 3 quota_ram = 51200 quota_security_group_rules = 20 quota_security_groups = 10 quota_server_group_members = 10 quota_server_groups = 10 ram_allocation_ratio = 0.0 reboot_timeout = 0 reclaim_instance_interval = 0 region_list = remove_unused_base_images = True remove_unused_original_minimum_age_seconds = 86400 report_interval = 10 rescue_timeout = 0 reservation_expire = 86400 reserved_host_disk_mb = 0 reserved_host_memory_mb = 512 resize_confirm_window = 0 resize_fs_using_block_device = False resume_guests_state_on_host_boot = False rootwrap_config = /etc/nova/rootwrap.conf routing_source_ip = 10.0.0.9 rpc_backend = rabbit rpc_response_timeout = 60 run_external_periodic_tasks = True running_deleted_instance_action = reap running_deleted_instance_poll_interval = 1800 running_deleted_instance_timeout = 0 s3_access_key = notchecked s3_affix_tenant = False s3_host = 10.0.0.9 s3_port = 3333 s3_secret_key = notchecked s3_use_ssl = False scheduler_available_filters = nova.scheduler.filters.all_filters scheduler_default_filters = AvailabilityZoneFilter ComputeCapabilitiesFilter ComputeFilter DiskFilter ImagePropertiesFilter RamFilter RetryFilter ServerGroupAffinityFilter ServerGroupAntiAffinityFilter scheduler_instance_sync_interval = 120 scheduler_manager = nova.scheduler.manager.SchedulerManager scheduler_max_attempts = 3 scheduler_topic = scheduler scheduler_tracks_instance_changes = True scheduler_weight_classes = nova.scheduler.weights.all_weighers secure_proxy_ssl_header = None security_group_api = neutron send_arp_for_ha = False send_arp_for_ha_count = 3 service_down_time = 60 servicegroup_driver = db share_dhcp_address = False shelved_offload_time = 0 shelved_poll_interval = 3600 shutdown_timeout = 60 snapshot_name_template = snapshot-%s ssl_ca_file = None ssl_cert_file = None ssl_key_file = None state_path = /opt/stack/data/nova sync_power_state_interval = 600 syslog-log-facility = LOG_USER tcp_keepidle = 600 teardown_unused_network_gateway = False tempdir = None transport_url = None until_refresh = 0 update_dns_entries = False update_resources_interval = 0 use-syslog = False use-syslog-rfc-format = True use_cow_images = True use_forwarded_for = False use_ipv6 = False use_network_dns_servers = False use_neutron_default_nets = False use_project_ca = False use_rootwrap_daemon = False use_single_default_gateway = False use_stderr = True user_cert_subject = /C=US/ST=California/O=OpenStack/OU=NovaDev/CN=%.16s-%.16s-%s vcpu_pin_set = None vendordata_driver = nova.api.metadata.vendordata_json.JsonFileVendorData verbose = True vif_plugging_is_fatal = True vif_plugging_timeout = 300 virt_mkfs = vlan_interface = None vlan_start = 100 volume_api_class = nova.volume.cinder.API volume_usage_poll_interval = 0 vpn_flavor = m1.tiny vpn_image_id = 0 vpn_ip = 10.0.0.9 vpn_key_suffix = -vpn vpn_start = 1000 wsgi_default_pool_size = 1000 wsgi_keep_alive = True wsgi_log_format = %(client_ip)s "%(request_line)s" status: %(status_code)s len: %(body_length)s time: %(wall_seconds).7f ephemeral_storage_encryption: cipher = aes-xts-plain64 enabled = False key_size = 512 glance: allowed_direct_url_schemes = api_insecure = False api_servers = http://10.0.0.9:9292 host = 10.0.0.9 num_retries = 0 port = 9292 protocol = http guestfs: debug = False image_file_url: filesystems = ironic: admin_auth_token = *** admin_password = *** admin_tenant_name = None admin_url = None admin_username = None api_endpoint = None api_max_retries = 60 api_retry_interval = 2 api_version = 1 client_log_level = None keymgr: api_class = nova.keymgr.conf_key_mgr.ConfKeyManager keystone_authtoken: admin_password = *** admin_tenant_name = admin admin_token = *** admin_user = None auth-url = http://10.0.0.9:35357 auth_admin_prefix = auth_host = 127.0.0.1 auth_plugin = password auth_port = 35357 auth_protocol = https auth_section = None www_authenticate_uri = http://10.0.0.9:5000 auth_version = None cache = None cafile = /opt/stack/data/ca-bundle.pem certfile = None check_revocations_for_cached = False delay_auth_decision = False domain-id = None domain-name = None enforce_token_bind = permissive hash_algorithms = md5 http_connect_timeout = None http_request_max_retries = 3 identity_uri = None include_service_catalog = True insecure = False keyfile = None memcache_pool_conn_get_timeout = 10 memcache_pool_dead_retry = 300 memcache_pool_maxsize = 10 memcache_pool_socket_timeout = 3 memcache_pool_unused_timeout = 60 memcache_secret_key = *** memcache_security_strategy = None memcache_use_advanced_pool = False memcached_servers = None password = password project-domain-id = default project-domain-name = None project-id = None project-name = service region_name = None revocation_cache_time = 10 signing_dir = /var/cache/nova tenant-id = None tenant-name = None token_cache_time = 300 trust-id = None user-domain-id = default user-domain-name = None user-id = None user-name = nova libvirt: block_migration_flag = VIR_MIGRATE_UNDEFINE_SOURCE, VIR_MIGRATE_PEER2PEER, VIR_MIGRATE_LIVE, VIR_MIGRATE_TUNNELLED, VIR_MIGRATE_NON_SHARED_INC checksum_base_images = False checksum_interval_seconds = 3600 connection_uri = cpu_mode = none cpu_model = None disk_cachemodes = disk_prefix = None gid_maps = hw_disk_discard = None hw_machine_type = None image_info_filename_pattern = /opt/stack/data/nova/instances/_base/%(image)s.info images_rbd_ceph_conf = images_rbd_pool = rbd images_type = default images_volume_group = None inject_key = False inject_partition = -2 inject_password = False iscsi_iface = None iscsi_use_multipath = False live_migration_bandwidth = 0 live_migration_completion_timeout = 800 live_migration_downtime = 500 live_migration_downtime_delay = 75 live_migration_downtime_steps = 10 live_migration_flag = VIR_MIGRATE_UNDEFINE_SOURCE, VIR_MIGRATE_PEER2PEER, VIR_MIGRATE_LIVE, VIR_MIGRATE_TUNNELLED live_migration_progress_timeout = 150 live_migration_uri = qemu+ssh://stack@%s/system mem_stats_period_seconds = 10 num_iscsi_scan_tries = 5 qemu_allowed_storage_drivers = rbd_secret_uuid = None rbd_user = None remote_filesystem_transport = ssh remove_unused_kernels = True remove_unused_resized_minimum_age_seconds = 3600 rescue_image_id = None rescue_kernel_id = None rescue_ramdisk_id = None rng_dev_path = None snapshot_compression = False snapshot_image_format = None snapshots_directory = /opt/stack/data/nova/instances/snapshots sparse_logical_volumes = False sysinfo_serial = auto uid_maps = use_usb_tablet = False use_virtio_for_bridges = True virt_type = kvm volume_clear = zero volume_clear_size = 0 wait_soft_reboot_seconds = 120 xen_hvmloader_path = /usr/lib/xen/boot/hvmloader mks: enabled = False mksproxy_base_url = http://127.0.0.1:6090/ neutron: admin_auth_url = http://10.0.0.9:35357/v2.0 admin_password = *** admin_tenant_id = None admin_tenant_name = service admin_user_id = None admin_username = neutron auth_plugin = None auth_section = None auth_strategy = keystone cafile = None certfile = None extension_sync_interval = 600 insecure = False keyfile = None metadata_proxy_shared_secret = *** ovs_bridge = br-int region_name = RegionOne service_metadata_proxy = True timeout = None url = http://10.0.0.9:9696 osapi_v21: enabled = True extensions_blacklist = extensions_whitelist = oslo_concurrency: disable_process_locking = False lock_path = /opt/stack/data/nova oslo_messaging_rabbit: amqp_auto_delete = False amqp_durable_queues = False fake_rabbit = False heartbeat_rate = 2 heartbeat_timeout_threshold = 60 kombu_reconnect_delay = 1.0 kombu_reconnect_timeout = 60 kombu_ssl_ca_certs = kombu_ssl_certfile = kombu_ssl_keyfile = kombu_ssl_version = rabbit_ha_queues = False rabbit_host = localhost rabbit_hosts = 10.0.0.9 rabbit_login_method = AMQPLAIN rabbit_max_retries = 0 rabbit_password = *** rabbit_port = 5672 rabbit_retry_backoff = 2 rabbit_retry_interval = 1 rabbit_use_ssl = False rabbit_userid = stackrabbit rabbit_virtual_host = / rpc_conn_pool_size = 30 send_single_reply = False oslo_middleware: max_request_body_size = 114688 oslo_versionedobjects: fatal_exception_format_errors = False rdp: enabled = False html5_proxy_base_url = http://127.0.0.1:6083/ remote_debug: host = None port = None serial_console: base_url = ws://127.0.0.1:6083/ enabled = False listen = 127.0.0.1 port_range = 10000:20000 proxyclient_address = 127.0.0.1 spice: agent_enabled = True enabled = False html5proxy_base_url = http://10.0.0.9:6082/spice_auto.html keymap = en-us server_listen = 127.0.0.1 server_proxyclient_address = 127.0.0.1 ssl: ca_file = None cert_file = None key_file = None upgrade_levels: baseapi = None cells = None cert = None compute = None conductor = None console = None consoleauth = None network = None scheduler = None vnc: enabled = False keymap = en-us novncproxy_base_url = http://10.0.0.9:6080/vnc_auto.html vncserver_listen = 127.0.0.1 vncserver_proxyclient_address = 127.0.0.1 xvpvncproxy_base_url = http://10.0.0.9:6081/console workarounds: destroy_after_evacuate = True disable_libvirt_livesnapshot = True disable_rootwrap = False handle_virt_lifecycle_events = True ././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1740146607.0 oslo_reports-3.5.1/doc/source/user/usage.rst0000664000175000017500000000266500000000000021167 0ustar00zuulzuul00000000000000======= Usage ======= Every long running service process should have a call to install a signal handler which will trigger the guru meditation framework upon receipt of SIGUSR1/SIGUSR2. This will result in the process dumping a complete report of its current state to stderr. For RPC listeners, it may also be desirable to install some kind of hook in the RPC request dispatcher that will save a guru meditation report whenever the processing of a request results in an uncaught exception. It could save these reports to a well known directory (/var/log/openstack///) for later analysis by the sysadmin or automated bug analysis tools. To use oslo.reports in a project, you need to add the following call to :py:func:`~oslo_reports.TextGuruMeditation.setup_autorun` somewhere really early in the startup sequence of the process:: from oslo_reports import guru_meditation_report as gmr gmr.TextGuruMeditation.setup_autorun(version='13.0.0') Note that the version parameter is the version of the component itself. To trigger the report to be generated:: kill -SIGUSR2 .. note:: On SELinux platforms the report process may fail with an AccessDenied exception. If this happens, temporarily disable SELinux enforcement by running ``sudo setenforce 0``, trigger the report, then turn SELinux back on by running ``sudo setenforce 1``. Here is a sample report: .. include:: report.txt :literal: ././@PaxHeader0000000000000000000000000000003400000000000011452 xustar000000000000000028 mtime=1740146654.5361838 oslo_reports-3.5.1/oslo.reports.egg-info/0000775000175000017500000000000000000000000020440 5ustar00zuulzuul00000000000000././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1740146654.0 oslo_reports-3.5.1/oslo.reports.egg-info/PKG-INFO0000644000175000017500000000775200000000000021546 0ustar00zuulzuul00000000000000Metadata-Version: 2.1 Name: oslo.reports Version: 3.5.1 Summary: oslo.reports library Home-page: https://docs.openstack.org/oslo.reports/latest Author: OpenStack Author-email: openstack-discuss@lists.openstack.org Classifier: Environment :: OpenStack Classifier: Intended Audience :: Information Technology Classifier: Intended Audience :: System Administrators Classifier: License :: OSI Approved :: Apache Software License Classifier: Operating System :: POSIX :: Linux Classifier: Programming Language :: Python Classifier: Programming Language :: Python :: 3 Classifier: Programming Language :: Python :: 3.9 Classifier: Programming Language :: Python :: 3.10 Classifier: Programming Language :: Python :: 3.11 Classifier: Programming Language :: Python :: 3.12 Classifier: Programming Language :: Python :: 3 :: Only Classifier: Programming Language :: Python :: Implementation :: CPython Requires-Python: >=3.9 License-File: LICENSE Requires-Dist: pbr>=2.0.0 Requires-Dist: Jinja2>=2.10 Requires-Dist: oslo.serialization>=2.18.0 Requires-Dist: psutil>=3.2.2 Requires-Dist: oslo.i18n>=3.15.3 Requires-Dist: oslo.utils>=3.33.0 Requires-Dist: oslo.config>=5.1.0 Provides-Extra: greenlet Requires-Dist: greenlet>=0.4.15; extra == "greenlet" Provides-Extra: test Requires-Dist: oslotest>=3.2.0; extra == "test" Requires-Dist: stestr>=2.0.0; extra == "test" Requires-Dist: greenlet>=0.4.15; extra == "test" Requires-Dist: coverage>=4.0; extra == "test" ======================== Team and repository tags ======================== .. image:: https://governance.openstack.org/tc/badges/oslo.reports.svg :target: https://governance.openstack.org/tc/reference/tags/index.html .. Change things from this point on =================================== oslo.reports =================================== .. image:: https://img.shields.io/pypi/v/oslo.reports.svg :target: https://pypi.org/project/oslo.reports/ :alt: Latest Version .. image:: https://img.shields.io/pypi/dm/oslo.reports.svg :target: https://pypi.org/project/oslo.reports/ :alt: Downloads When things go wrong in (production) deployments of OpenStack collecting debug data is a key first step in the process of triaging & ultimately resolving the problem. Projects like Nova has extensively used logging capabilities which produce a vast amount of data. This does not, however, enable an admin to obtain an accurate view on the current live state of the system. For example, what threads are running, what config parameters are in effect, and more. The project oslo.reports hosts a general purpose error report generation framework, known as the "guru meditation report" (cf http://en.wikipedia.org/wiki/Guru_Meditation) to address the issues described above. Models: These classes define structured data for a variety of interesting pieces of state. For example, stack traces, threads, config parameters, package version info, etc. They are capable of being serialized to XML / JSON or a plain text representation Generators: These classes are used to populate the model classes with the current runtime state of the system Views: views serialize models into say JSON, text or xml. There is also a predefined view that utilizes Jinja templating system. There will be a number of standard models / generators available for all OpenStack services StackTraceModel: a base class for any model which includes a stack trace ThreadModel: a class for information about a thread ExceptionModel: a class for information about a caught exception ConfigModel: a class for information about configuration file settings PackageModel: a class for information about vendor/product/version/package information Each OpenStack project will have the ability to register further generator classes to provide custom project specific data. * Free software: Apache license * Documentation: https://docs.openstack.org/oslo.reports/latest * Source: https://opendev.org/openstack/oslo.reports * Bugs: https://bugs.launchpad.net/oslo.reports * Release notes: https://docs.openstack.org/releasenotes/oslo.reports/ ././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1740146654.0 oslo_reports-3.5.1/oslo.reports.egg-info/SOURCES.txt0000664000175000017500000000526100000000000022330 0ustar00zuulzuul00000000000000.coveragerc .mailmap .pre-commit-config.yaml .stestr.conf .zuul.yaml AUTHORS CONTRIBUTING.rst ChangeLog HACKING.rst LICENSE README.rst requirements.txt setup.cfg setup.py test-requirements.txt tox.ini doc/requirements.txt doc/source/conf.py doc/source/index.rst doc/source/contributor/index.rst doc/source/install/index.rst doc/source/reference/index.rst doc/source/reference/opts.rst doc/source/user/history.rst doc/source/user/index.rst doc/source/user/report.txt doc/source/user/usage.rst oslo.reports.egg-info/PKG-INFO oslo.reports.egg-info/SOURCES.txt oslo.reports.egg-info/dependency_links.txt oslo.reports.egg-info/entry_points.txt oslo.reports.egg-info/not-zip-safe oslo.reports.egg-info/pbr.json oslo.reports.egg-info/requires.txt oslo.reports.egg-info/top_level.txt oslo_reports/__init__.py oslo_reports/_i18n.py oslo_reports/_utils.py oslo_reports/guru_meditation_report.py oslo_reports/opts.py oslo_reports/report.py oslo_reports/generators/__init__.py oslo_reports/generators/conf.py oslo_reports/generators/process.py oslo_reports/generators/threading.py oslo_reports/generators/version.py oslo_reports/locale/en_GB/LC_MESSAGES/oslo_reports.po oslo_reports/models/__init__.py oslo_reports/models/base.py oslo_reports/models/conf.py oslo_reports/models/process.py oslo_reports/models/threading.py oslo_reports/models/version.py oslo_reports/models/with_default_views.py oslo_reports/tests/__init__.py oslo_reports/tests/test_base_report.py oslo_reports/tests/test_guru_meditation_report.py oslo_reports/tests/test_openstack_generators.py oslo_reports/tests/test_views.py oslo_reports/views/__init__.py oslo_reports/views/jinja_view.py oslo_reports/views/json/__init__.py oslo_reports/views/json/generic.py oslo_reports/views/text/__init__.py oslo_reports/views/text/generic.py oslo_reports/views/text/header.py oslo_reports/views/text/process.py oslo_reports/views/text/threading.py oslo_reports/views/xml/__init__.py oslo_reports/views/xml/generic.py releasenotes/notes/add-reno-996dd44974d53238.yaml releasenotes/notes/drop-python27-support-26fad37c3f7a3d28.yaml releasenotes/notes/remove-py38-9a3e6702c3d23445.yaml releasenotes/source/2023.1.rst releasenotes/source/2023.2.rst releasenotes/source/2024.1.rst releasenotes/source/2024.2.rst releasenotes/source/conf.py releasenotes/source/index.rst releasenotes/source/ocata.rst releasenotes/source/pike.rst releasenotes/source/queens.rst releasenotes/source/rocky.rst releasenotes/source/stein.rst releasenotes/source/train.rst releasenotes/source/unreleased.rst releasenotes/source/ussuri.rst releasenotes/source/victoria.rst releasenotes/source/_static/.placeholder releasenotes/source/_templates/.placeholder releasenotes/source/locale/en_GB/LC_MESSAGES/releasenotes.po././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1740146654.0 oslo_reports-3.5.1/oslo.reports.egg-info/dependency_links.txt0000664000175000017500000000000100000000000024506 0ustar00zuulzuul00000000000000 ././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1740146654.0 oslo_reports-3.5.1/oslo.reports.egg-info/entry_points.txt0000664000175000017500000000007600000000000023741 0ustar00zuulzuul00000000000000[oslo.config.opts] oslo.reports = oslo_reports.opts:list_opts ././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1740146654.0 oslo_reports-3.5.1/oslo.reports.egg-info/not-zip-safe0000664000175000017500000000000100000000000022666 0ustar00zuulzuul00000000000000 ././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1740146654.0 oslo_reports-3.5.1/oslo.reports.egg-info/pbr.json0000664000175000017500000000005600000000000022117 0ustar00zuulzuul00000000000000{"git_version": "2f5eb7c", "is_release": true}././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1740146654.0 oslo_reports-3.5.1/oslo.reports.egg-info/requires.txt0000664000175000017500000000033300000000000023037 0ustar00zuulzuul00000000000000pbr>=2.0.0 Jinja2>=2.10 oslo.serialization>=2.18.0 psutil>=3.2.2 oslo.i18n>=3.15.3 oslo.utils>=3.33.0 oslo.config>=5.1.0 [greenlet] greenlet>=0.4.15 [test] oslotest>=3.2.0 stestr>=2.0.0 greenlet>=0.4.15 coverage>=4.0 ././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1740146654.0 oslo_reports-3.5.1/oslo.reports.egg-info/top_level.txt0000664000175000017500000000001500000000000023166 0ustar00zuulzuul00000000000000oslo_reports ././@PaxHeader0000000000000000000000000000003400000000000011452 xustar000000000000000028 mtime=1740146654.5241807 oslo_reports-3.5.1/oslo_reports/0000775000175000017500000000000000000000000017027 5ustar00zuulzuul00000000000000././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1740146607.0 oslo_reports-3.5.1/oslo_reports/__init__.py0000664000175000017500000000205100000000000021136 0ustar00zuulzuul00000000000000# Copyright 2013 Red Hat, Inc. # # Licensed under the Apache License, Version 2.0 (the "License"); you may # not use this file except in compliance with the License. You may obtain # a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the # License for the specific language governing permissions and limitations # under the License. """Provides a way to generate serializable reports This package/module provides mechanisms for defining reports which may then be serialized into various data types. Each report ( :class:`oslo_reports.report.BasicReport` ) is composed of one or more report sections ( :class:`oslo_reports.report.BasicSection` ), which contain generators which generate data models ( :class:`oslo_reports.models.base.ReportModels` ), which are then serialized by views. """ ././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1740146607.0 oslo_reports-3.5.1/oslo_reports/_i18n.py0000664000175000017500000000147400000000000020325 0ustar00zuulzuul00000000000000# Licensed under the Apache License, Version 2.0 (the "License"); you may # not use this file except in compliance with the License. You may obtain # a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the # License for the specific language governing permissions and limitations # under the License. """oslo.i18n integration module. See https://docs.openstack.org/oslo.i18n/latest/user/index.html . """ import oslo_i18n _translators = oslo_i18n.TranslatorFactory(domain='oslo_reports') # The primary translation function using the well-known name "_" _ = _translators.primary ././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1740146607.0 oslo_reports-3.5.1/oslo_reports/_utils.py0000664000175000017500000000145700000000000020707 0ustar00zuulzuul00000000000000# Copyright 2013 Red Hat, Inc. # # Licensed under the Apache License, Version 2.0 (the "License"); you may # not use this file except in compliance with the License. You may obtain # a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the # License for the specific language governing permissions and limitations # under the License. """Various utilities for report generation This module includes various utilities used in generating reports. """ class StringWithAttrs(str): """A String that can have arbitrary attributes""" pass ././@PaxHeader0000000000000000000000000000003400000000000011452 xustar000000000000000028 mtime=1740146654.5281816 oslo_reports-3.5.1/oslo_reports/generators/0000775000175000017500000000000000000000000021200 5ustar00zuulzuul00000000000000././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1740146607.0 oslo_reports-3.5.1/oslo_reports/generators/__init__.py0000664000175000017500000000151000000000000023306 0ustar00zuulzuul00000000000000# Copyright 2013 Red Hat, Inc. # # Licensed under the Apache License, Version 2.0 (the "License"); you may # not use this file except in compliance with the License. You may obtain # a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the # License for the specific language governing permissions and limitations # under the License. """Provides Data Model Generators This module defines classes for generating data models ( :class:`oslo_reports.models.base.ReportModel` ). A generator is any object which is callable with no parameters and returns a data model. """ ././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1740146607.0 oslo_reports-3.5.1/oslo_reports/generators/conf.py0000664000175000017500000000253600000000000022505 0ustar00zuulzuul00000000000000# Copyright 2013 Red Hat, Inc. # # Licensed under the Apache License, Version 2.0 (the "License"); you may # not use this file except in compliance with the License. You may obtain # a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the # License for the specific language governing permissions and limitations # under the License. """Provides OpenStack config generators This module defines a class for configuration generators for generating the model in :mod:`oslo_reports.models.conf`. """ from oslo_config import cfg from oslo_reports.models import conf as cm class ConfigReportGenerator: """A Configuration Data Generator This generator returns :class:`oslo_reports.models.conf.ConfigModel`, by default using the configuration options stored in :attr:`oslo_config.cfg.CONF`, which is where OpenStack stores everything. :param cnf: the configuration option object :type cnf: :class:`oslo_config.cfg.ConfigOpts` """ def __init__(self, cnf=cfg.CONF): self.conf_obj = cnf def __call__(self): return cm.ConfigModel(self.conf_obj) ././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1740146607.0 oslo_reports-3.5.1/oslo_reports/generators/process.py0000664000175000017500000000223700000000000023234 0ustar00zuulzuul00000000000000# Copyright 2014 Red Hat, Inc. # # Licensed under the Apache License, Version 2.0 (the "License"); you may # not use this file except in compliance with the License. You may obtain # a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the # License for the specific language governing permissions and limitations # under the License. """Provides process-data generators This modules defines a class for generating process data by way of the psutil package. """ import os import psutil from oslo_reports.models import process as pm class ProcessReportGenerator: """A Process Data Generator This generator returns a :class:`oslo_reports.models.process.ProcessModel` based on the current process (which will also include all subprocesses, recursively) using the :class:`psutil.Process` class`. """ def __call__(self): return pm.ProcessModel(psutil.Process(os.getpid())) ././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1740146607.0 oslo_reports-3.5.1/oslo_reports/generators/threading.py0000664000175000017500000000660300000000000023524 0ustar00zuulzuul00000000000000# Copyright 2013 Red Hat, Inc. # # Licensed under the Apache License, Version 2.0 (the "License"); you may # not use this file except in compliance with the License. You may obtain # a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the # License for the specific language governing permissions and limitations # under the License. """Provides thread-related generators This module defines classes for threading-related generators for generating the models in :mod:`oslo_reports.models.threading`. """ import gc import sys import threading from oslo_reports.models import threading as tm from oslo_reports.models import with_default_views as mwdv from oslo_reports.views.text import generic as text_views def _find_objects(t): """Find Objects in the GC State This horribly hackish method locates objects of a given class in the current python instance's garbage collection state. In case you couldn't tell, this is horribly hackish, but is necessary for locating all green threads, since they don't keep track of themselves like normal threads do in python. :param class t: the class of object to locate :rtype: list :returns: a list of objects of the given type """ return [o for o in gc.get_objects() if isinstance(o, t)] class ThreadReportGenerator: """A Thread Data Generator This generator returns a collection of :class:`oslo_reports.models.threading.ThreadModel` objects by introspecting the current python state using :func:`sys._current_frames()` . Its constructor may optionally be passed a frame object. This frame object will be interpreted as the actual stack trace for the current thread, and, come generation time, will be used to replace the stack trace of the thread in which this code is running. """ def __init__(self, curr_thread_traceback=None): self.traceback = curr_thread_traceback def __call__(self): threadModels = { thread_id: tm.ThreadModel(thread_id, stack) for thread_id, stack in sys._current_frames().items() } if self.traceback is not None: curr_thread_id = threading.current_thread().ident threadModels[curr_thread_id] = tm.ThreadModel(curr_thread_id, self.traceback) return mwdv.ModelWithDefaultViews(threadModels, text_view=text_views.MultiView()) class GreenThreadReportGenerator: """A Green Thread Data Generator This generator returns a collection of :class:`oslo_reports.models.threading.GreenThreadModel` objects by introspecting the current python garbage collection state, and sifting through for :class:`greenlet.greenlet` objects. .. seealso:: Function :func:`_find_objects` """ def __call__(self): import greenlet threadModels = [ tm.GreenThreadModel(gr.gr_frame) for gr in _find_objects(greenlet.greenlet) ] return mwdv.ModelWithDefaultViews(threadModels, text_view=text_views.MultiView()) ././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1740146607.0 oslo_reports-3.5.1/oslo_reports/generators/version.py0000664000175000017500000000407500000000000023245 0ustar00zuulzuul00000000000000# Copyright 2013 Red Hat, Inc. # # Licensed under the Apache License, Version 2.0 (the "License"); you may # not use this file except in compliance with the License. You may obtain # a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the # License for the specific language governing permissions and limitations # under the License. """Provides OpenStack version generators This module defines a class for OpenStack version and package information generators for generating the model in :mod:`oslo_reports.models.version`. """ from oslo_reports.models import version as vm class PackageReportGenerator: """A Package Information Data Generator This generator returns :class:`oslo_reports.models.version.PackageModel`, extracting data from the given version object, which should follow the general format defined in Nova's version information (i.e. it should contain the methods vendor_string, product_string, and version_string_with_package). :param version_object: the version information object """ def __init__(self, version_obj): self.version_obj = version_obj def __call__(self): if hasattr(self.version_obj, "vendor_string"): vendor_string = self.version_obj.vendor_string() else: vendor_string = None if hasattr(self.version_obj, "product_string"): product_string = self.version_obj.product_string() else: product_string = None if hasattr(self.version_obj, "version_string_with_package"): version_string_with_package = self.version_obj.\ version_string_with_package() else: version_string_with_package = None return vm.PackageModel(vendor_string, product_string, version_string_with_package) ././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1740146607.0 oslo_reports-3.5.1/oslo_reports/guru_meditation_report.py0000664000175000017500000002337200000000000024202 0ustar00zuulzuul00000000000000# Copyright 2013 Red Hat, Inc. # # Licensed under the Apache License, Version 2.0 (the "License"); you may # not use this file except in compliance with the License. You may obtain # a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the # License for the specific language governing permissions and limitations # under the License. """Provides Guru Meditation Report This module defines the actual OpenStack Guru Meditation Report class. This can be used in the OpenStack command definition files. For example, in a nova command module (under nova/cmd): .. code-block:: python :emphasize-lines: 8,9,10 from oslo_config import cfg from oslo_log import log as oslo_logging from oslo_reports import opts as gmr_opts from oslo_reports import guru_meditation_report as gmr CONF = cfg.CONF # maybe import some options here... def main(): oslo_logging.register_options(CONF) gmr_opts.set_defaults(CONF) CONF(sys.argv[1:], default_config_files=['myapp.conf']) oslo_logging.setup(CONF, 'myapp') gmr.TextGuruMeditation.register_section('Some Special Section', special_section_generator) gmr.TextGuruMeditation.setup_autorun(version_object, conf=CONF) server = service.Service.create(binary='some-service', topic=CONF.some_service_topic) service.serve(server) service.wait() Then, you can do .. code-block:: bash $ kill -USR2 $SERVICE_PID and get a Guru Meditation Report in the file or terminal where stderr is logged for that given service. """ import inspect import logging import os import signal import stat import sys import threading import time import traceback from oslo_utils import timeutils from oslo_reports.generators import conf as cgen from oslo_reports.generators import process as prgen from oslo_reports.generators import threading as tgen from oslo_reports.generators import version as pgen from oslo_reports import report try: import greenlet except ImportError: greenlet = None LOG = logging.getLogger(__name__) class GuruMeditation: """A Guru Meditation Report Mixin/Base Class This class is a base class for Guru Meditation Reports. It provides facilities for registering sections and setting up functionality to auto-run the report on a certain signal or use file modification events. This class should always be used in conjunction with a Report class via multiple inheritance. It should always come first in the class list to ensure the MRO is correct. """ timestamp_fmt = "%Y%m%d%H%M%S" def __init__(self, version_obj, sig_handler_tb=None, *args, **kwargs): self.version_obj = version_obj self.traceback = sig_handler_tb super().__init__(*args, **kwargs) self.start_section_index = len(self.sections) @classmethod def register_section(cls, section_title, generator): """Register a New Section This method registers a persistent section for the current class. :param str section_title: the title of the section :param generator: the generator for the section """ try: cls.persistent_sections.append([section_title, generator]) except AttributeError: cls.persistent_sections = [[section_title, generator]] @classmethod def setup_autorun(cls, version, service_name=None, log_dir=None, signum=None, conf=None, setup_signal=True): """Set Up Auto-Run This method sets up the Guru Meditation Report to automatically get dumped to stderr or a file in a given dir when the given signal is received. It can also use file modification events instead of signals. :param version: the version object for the current product :param service_name: this program name used to construct logfile name :param logdir: path to a log directory where to create a file :param signum: the signal to associate with running the report :param conf: Configuration object, managed by the caller. :param setup_signal: Set up a signal handler """ if log_dir is None and conf is not None: log_dir = conf.oslo_reports.log_dir if signum: if setup_signal: cls._setup_signal(signum, version, service_name, log_dir) return if conf and conf.oslo_reports.file_event_handler: cls._setup_file_watcher( conf.oslo_reports.file_event_handler, conf.oslo_reports.file_event_handler_interval, version, service_name, log_dir) else: if setup_signal and hasattr(signal, 'SIGUSR2'): cls._setup_signal(signal.SIGUSR2, version, service_name, log_dir) @classmethod def _setup_file_watcher(cls, filepath, interval, version, service_name, log_dir): st = os.stat(filepath) if not bool(st.st_mode & stat.S_IRGRP): LOG.error("Guru Meditation Report does not have read " "permissions to '%s' file.", filepath) def _handler(): mtime = time.time() while True: try: stat = os.stat(filepath) if stat.st_mtime > mtime: cls.handle_signal(version, service_name, log_dir, None) mtime = stat.st_mtime except OSError: msg = ("Guru Meditation Report cannot read " + "'{}' file".format(filepath)) raise OSError(msg) finally: time.sleep(interval) th = threading.Thread(target=_handler) th.daemon = True th.start() @classmethod def _setup_signal(cls, signum, version, service_name, log_dir): signal.signal(signum, lambda sn, f: cls.handle_signal( version, service_name, log_dir, f)) @classmethod def handle_signal(cls, version, service_name, log_dir, frame): """The Signal Handler This method (indirectly) handles receiving a registered signal and dumping the Guru Meditation Report to stderr or a file in a given dir. If service name and log dir are not None, the report will be dumped to a file named $service_name_gurumeditation_$current_time in the log_dir directory. This method is designed to be curried into a proper signal handler by currying out the version parameter. :param version: the version object for the current product :param service_name: this program name used to construct logfile name :param logdir: path to a log directory where to create a file :param frame: the frame object provided to the signal handler """ try: res = cls(version, frame).run() except Exception: traceback.print_exc(file=sys.stderr) print("Unable to run Guru Meditation Report!", file=sys.stderr) else: if log_dir: service_name = service_name or os.path.basename( inspect.stack()[-1][1]) filename = "{}_gurumeditation_{}".format( service_name, timeutils.utcnow().strftime( cls.timestamp_fmt)) filepath = os.path.join(log_dir, filename) try: with open(filepath, "w") as dumpfile: dumpfile.write(res) except Exception: print("Unable to dump Guru Meditation Report to file %s" % (filepath,), file=sys.stderr) else: print(res, file=sys.stderr) def _readd_sections(self): del self.sections[self.start_section_index:] self.add_section('Package', pgen.PackageReportGenerator(self.version_obj)) self.add_section('Threads', tgen.ThreadReportGenerator(self.traceback)) if greenlet: self.add_section('Green Threads', tgen.GreenThreadReportGenerator()) self.add_section('Processes', prgen.ProcessReportGenerator()) self.add_section('Configuration', cgen.ConfigReportGenerator()) try: for section_title, generator in self.persistent_sections: self.add_section(section_title, generator) except AttributeError: pass def run(self): self._readd_sections() return super().run() # GuruMeditation must come first to get the correct MRO class TextGuruMeditation(GuruMeditation, report.TextReport): """A Text Guru Meditation Report This report is the basic human-readable Guru Meditation Report It contains the following sections by default (in addition to any registered persistent sections): - Package Information - Threads List - Green Threads List - Process List - Configuration Options :param version_obj: the version object for the current product :param traceback: an (optional) frame object providing the actual traceback for the current thread """ def __init__(self, version_obj, traceback=None): super().__init__(version_obj, traceback, 'Guru Meditation') ././@PaxHeader0000000000000000000000000000003400000000000011452 xustar000000000000000028 mtime=1740146654.5121772 oslo_reports-3.5.1/oslo_reports/locale/0000775000175000017500000000000000000000000020266 5ustar00zuulzuul00000000000000././@PaxHeader0000000000000000000000000000003400000000000011452 xustar000000000000000028 mtime=1740146654.5121772 oslo_reports-3.5.1/oslo_reports/locale/en_GB/0000775000175000017500000000000000000000000021240 5ustar00zuulzuul00000000000000././@PaxHeader0000000000000000000000000000003400000000000011452 xustar000000000000000028 mtime=1740146654.5281816 oslo_reports-3.5.1/oslo_reports/locale/en_GB/LC_MESSAGES/0000775000175000017500000000000000000000000023025 5ustar00zuulzuul00000000000000././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1740146607.0 oslo_reports-3.5.1/oslo_reports/locale/en_GB/LC_MESSAGES/oslo_reports.po0000664000175000017500000000262000000000000026117 0ustar00zuulzuul00000000000000# Andi Chandler , 2016. #zanata # Andi Chandler , 2017. #zanata msgid "" msgstr "" "Project-Id-Version: oslo.reports VERSION\n" "Report-Msgid-Bugs-To: https://bugs.launchpad.net/openstack-i18n/\n" "POT-Creation-Date: 2018-01-29 04:42+0000\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "PO-Revision-Date: 2017-10-07 10:54+0000\n" "Last-Translator: Andi Chandler \n" "Language-Team: English (United Kingdom)\n" "Language: en_GB\n" "X-Generator: Zanata 4.3.3\n" "Plural-Forms: nplurals=2; plural=(n != 1)\n" msgid "How many seconds to wait between polls when file_event_handler is set" msgstr "How many seconds to wait between polls when file_event_handler is set" msgid "Path to a log directory where to create a file" msgstr "Path to a log directory where to create a file" msgid "" "The path to a file to watch for changes to trigger the reports, instead of " "signals. Setting this option disables the signal trigger for the reports. If " "application is running as a WSGI application it is recommended to use this " "instead of signals." msgstr "" "The path to a file to watch for changes to trigger the reports, instead of " "signals. Setting this option disables the signal trigger for the reports. If " "application is running as a WSGI application it is recommended to use this " "instead of signals." ././@PaxHeader0000000000000000000000000000003400000000000011452 xustar000000000000000028 mtime=1740146654.5281816 oslo_reports-3.5.1/oslo_reports/models/0000775000175000017500000000000000000000000020312 5ustar00zuulzuul00000000000000././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1740146607.0 oslo_reports-3.5.1/oslo_reports/models/__init__.py0000664000175000017500000000136400000000000022427 0ustar00zuulzuul00000000000000# Copyright 2013 Red Hat, Inc. # # Licensed under the Apache License, Version 2.0 (the "License"); you may # not use this file except in compliance with the License. You may obtain # a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the # License for the specific language governing permissions and limitations # under the License. """Provides data models This module provides both the base data model, as well as several predefined specific data models to be used in reports. """ ././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1740146607.0 oslo_reports-3.5.1/oslo_reports/models/base.py0000664000175000017500000001306400000000000021602 0ustar00zuulzuul00000000000000# Copyright 2013 Red Hat, Inc. # # Licensed under the Apache License, Version 2.0 (the "License"); you may # not use this file except in compliance with the License. You may obtain # a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the # License for the specific language governing permissions and limitations # under the License. """Provides the base report model This module defines a class representing the basic report data model from which all data models should inherit (or at least implement similar functionality). Data models store unserialized data generated by generators during the report serialization process. """ from collections import abc import copy class ReportModel(abc.MutableMapping): """A Report Data Model A report data model contains data generated by some generator method or class. Data may be read or written using dictionary-style access, and may be read (but not written) using object-member-style access. Additionally, a data model may have an associated view. This view is used to serialize the model when str() is called on the model. An appropriate object for a view is callable with a single parameter: the model to be serialized. If present, the object passed in as data will be transformed into a standard python dict. For mappings, this is fairly straightforward. For sequences, the indices become keys and the items become values. :param data: a sequence or mapping of data to associate with the model :param attached_view: a view object to attach to this model """ def __init__(self, data=None, attached_view=None): self.attached_view = attached_view if data is not None: if isinstance(data, abc.Mapping): self.data = dict(data) elif isinstance(data, abc.Sequence): # convert a list [a, b, c] to a dict {0: a, 1: b, 2: c} self.data = dict(enumerate(data)) else: raise TypeError('Data for the model must be a sequence ' 'or mapping.') else: self.data = {} def __str__(self): self_cpy = copy.deepcopy(self) for key in self_cpy: if getattr(self_cpy[key], 'attached_view', None) is not None: self_cpy[key] = str(self_cpy[key]) if self.attached_view is not None: return self.attached_view(self_cpy) else: raise Exception("Cannot stringify model: no attached view") def __repr__(self): if self.attached_view is not None: return ("").format(cl=type(self), dt=self.data, vw=type(self.attached_view)) else: return ("").format(cl=type(self), dt=self.data) def __getitem__(self, attrname): return self.data[attrname] def __setitem__(self, attrname, attrval): self.data[attrname] = attrval def __delitem__(self, attrname): del self.data[attrname] def __contains__(self, key): return self.data.__contains__(key) def __getattr__(self, attrname): # Needed for deepcopy in Python3. That will avoid an infinite loop # in __getattr__ . if 'data' not in self.__dict__: self.data = {} try: return self.data[attrname] except KeyError: # we don't have that key in data, and the # model class doesn't have that attribute raise AttributeError( "'{cl}' object has no attribute '{an}'".format( cl=type(self).__name__, an=attrname ) ) def __len__(self): return len(self.data) def __iter__(self): return self.data.__iter__() def set_current_view_type(self, tp, visited=None): """Set the current view type This method attempts to set the current view type for this model and all submodels by calling itself recursively on all values, traversing intervening sequences and mappings when possible, and ignoring all other objects. :param tp: the type of the view ('text', 'json', 'xml', etc) :param visited: a set of object ids for which the corresponding objects have already had their view type set """ if visited is None: visited = set() def traverse_obj(obj): oid = id(obj) # don't die on recursive structures, # and don't treat strings like sequences if oid in visited or isinstance(obj, str): return visited.add(oid) if hasattr(obj, 'set_current_view_type'): obj.set_current_view_type(tp, visited=visited) if isinstance(obj, abc.Sequence): for item in obj: traverse_obj(item) elif isinstance(obj, abc.Mapping): for val in obj.values(): traverse_obj(val) traverse_obj(self) ././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1740146607.0 oslo_reports-3.5.1/oslo_reports/models/conf.py0000664000175000017500000000441400000000000021614 0ustar00zuulzuul00000000000000# Copyright 2013 Red Hat, Inc. # # Licensed under the Apache License, Version 2.0 (the "License"); you may # not use this file except in compliance with the License. You may obtain # a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the # License for the specific language governing permissions and limitations # under the License. """Provides OpenStack Configuration Model This module defines a class representing the data model for :mod:`oslo_config` configuration options """ from oslo_reports.models import with_default_views as mwdv from oslo_reports.views.text import generic as generic_text_views class ConfigModel(mwdv.ModelWithDefaultViews): """A Configuration Options Model This model holds data about a set of configuration options from :mod:`oslo_config`. It supports both the default group of options and named option groups. :param conf_obj: a configuration object :type conf_obj: :class:`oslo_config.cfg.ConfigOpts` """ def __init__(self, conf_obj): kv_view = generic_text_views.KeyValueView(dict_sep=": ", before_dict='') super().__init__(text_view=kv_view) def opt_title(optname, co): return co._opts[optname]['opt'].name def opt_value(opt_obj, value): if opt_obj['opt'].secret: return '***' else: return value self['default'] = { opt_title(optname, conf_obj): opt_value(conf_obj._opts[optname], conf_obj[optname]) for optname in conf_obj._opts } groups = {} for groupname in conf_obj._groups: group_obj = conf_obj._groups[groupname] curr_group_opts = { opt_title(optname, group_obj): opt_value(group_obj._opts[optname], conf_obj[groupname][optname]) for optname in group_obj._opts} groups[group_obj.name] = curr_group_opts self.update(groups) ././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1740146607.0 oslo_reports-3.5.1/oslo_reports/models/process.py0000664000175000017500000000425600000000000022351 0ustar00zuulzuul00000000000000# Copyright 2014 Red Hat, Inc. # # Licensed under the Apache License, Version 2.0 (the "License"); you may # not use this file except in compliance with the License. You may obtain # a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the # License for the specific language governing permissions and limitations # under the License. """Provides a process model This module defines a class representing a process, potentially with subprocesses. """ import oslo_reports.models.with_default_views as mwdv import oslo_reports.views.text.process as text_views class ProcessModel(mwdv.ModelWithDefaultViews): """A Process Model This model holds data about a process, including references to any subprocesses :param process: a :class:`psutil.Process` object """ def __init__(self, process): super().__init__( text_view=text_views.ProcessView()) self['pid'] = process.pid self['parent_pid'] = process.ppid() if hasattr(process, 'uids'): self['uids'] = { 'real': process.uids().real, 'effective': process.uids().effective, 'saved': process.uids().saved } else: self['uids'] = {'real': None, 'effective': None, 'saved': None} if hasattr(process, 'gids'): self['gids'] = { 'real': process.gids().real, 'effective': process.gids().effective, 'saved': process.gids().saved } else: self['gids'] = {'real': None, 'effective': None, 'saved': None} self['username'] = process.username() self['command'] = process.cmdline() self['state'] = process.status() children = process.children() self['children'] = [ProcessModel(pr) for pr in children] ././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1740146607.0 oslo_reports-3.5.1/oslo_reports/models/threading.py0000664000175000017500000000624600000000000022641 0ustar00zuulzuul00000000000000# Copyright 2013 Red Hat, Inc. # # Licensed under the Apache License, Version 2.0 (the "License"); you may # not use this file except in compliance with the License. You may obtain # a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the # License for the specific language governing permissions and limitations # under the License. """Provides threading and stack-trace models This module defines classes representing thread, green thread, and stack trace data models """ import traceback from oslo_reports.models import with_default_views as mwdv from oslo_reports.views.text import threading as text_views class StackTraceModel(mwdv.ModelWithDefaultViews): """A Stack Trace Model This model holds data from a python stack trace, commonly extracted from running thread information :param stack_state: the python stack_state object """ def __init__(self, stack_state): super().__init__( text_view=text_views.StackTraceView()) if (stack_state is not None): self['lines'] = [ {'filename': fn, 'line': ln, 'name': nm, 'code': cd} for fn, ln, nm, cd in traceback.extract_stack(stack_state) ] # FIXME(flepied): under Python3 f_exc_type doesn't exist # anymore so we lose information about exceptions if getattr(stack_state, 'f_exc_type', None) is not None: self['root_exception'] = { 'type': stack_state.f_exc_type, 'value': stack_state.f_exc_value} else: self['root_exception'] = None else: self['lines'] = [] self['root_exception'] = None class ThreadModel(mwdv.ModelWithDefaultViews): """A Thread Model This model holds data for information about an individual thread. It holds both a thread id, as well as a stack trace for the thread .. seealso:: Class :class:`StackTraceModel` :param int thread_id: the id of the thread :param stack: the python stack state for the current thread """ # threadId, stack in sys._current_frams().items() def __init__(self, thread_id, stack): super().__init__(text_view=text_views.ThreadView()) self['thread_id'] = thread_id self['stack_trace'] = StackTraceModel(stack) class GreenThreadModel(mwdv.ModelWithDefaultViews): """A Green Thread Model This model holds data for information about an individual thread. Unlike the thread model, it holds just a stack trace, since green threads do not have thread ids. .. seealso:: Class :class:`StackTraceModel` :param stack: the python stack state for the green thread """ # gr in greenpool.coroutines_running --> gr.gr_frame def __init__(self, stack): super().__init__( {'stack_trace': StackTraceModel(stack)}, text_view=text_views.GreenThreadView()) ././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1740146607.0 oslo_reports-3.5.1/oslo_reports/models/version.py0000664000175000017500000000267500000000000022363 0ustar00zuulzuul00000000000000# Copyright 2013 Red Hat, Inc. # # Licensed under the Apache License, Version 2.0 (the "License"); you may # not use this file except in compliance with the License. You may obtain # a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the # License for the specific language governing permissions and limitations # under the License. """Provides OpenStack Version Info Model This module defines a class representing the data model for OpenStack package and version information """ from oslo_reports.models import with_default_views as mwdv from oslo_reports.views.text import generic as generic_text_views class PackageModel(mwdv.ModelWithDefaultViews): """A Package Information Model This model holds information about the current package. It contains vendor, product, and version information. :param str vendor: the product vendor :param str product: the product name :param str version: the product version """ def __init__(self, vendor, product, version): super().__init__( text_view=generic_text_views.KeyValueView() ) self['vendor'] = vendor self['product'] = product self['version'] = version ././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1740146607.0 oslo_reports-3.5.1/oslo_reports/models/with_default_views.py0000664000175000017500000000550600000000000024566 0ustar00zuulzuul00000000000000# Copyright 2013 Red Hat, Inc. # # Licensed under the Apache License, Version 2.0 (the "License"); you may # not use this file except in compliance with the License. You may obtain # a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the # License for the specific language governing permissions and limitations # under the License. import copy from oslo_reports.models import base as base_model from oslo_reports.views.json import generic as jsonviews from oslo_reports.views.text import generic as textviews from oslo_reports.views.xml import generic as xmlviews class ModelWithDefaultViews(base_model.ReportModel): """A Model With Default Views of Various Types A model with default views has several predefined views, each associated with a given type. This is often used for when a submodel should have an attached view, but the view differs depending on the serialization format Parameters are as the superclass, except for any parameters ending in '_view': these parameters get stored as default views. The default 'default views' are text :class:`oslo_reports.views.text.generic.KeyValueView` xml :class:`oslo_reports.views.xml.generic.KeyValueView` json :class:`oslo_reports.views.json.generic.KeyValueView` .. function:: to_type() ('type' is one of the 'default views' defined for this model) Serializes this model using the default view for 'type' :rtype: str :returns: this model serialized as 'type' """ def __init__(self, *args, **kwargs): self.views = { 'text': textviews.KeyValueView(), 'json': jsonviews.KeyValueView(), 'xml': xmlviews.KeyValueView() } newargs = copy.copy(kwargs) for k in kwargs: if k.endswith('_view'): self.views[k[:-5]] = kwargs[k] del newargs[k] super().__init__(*args, **newargs) def set_current_view_type(self, tp, visited=None): self.attached_view = self.views[tp] super().set_current_view_type(tp, visited) def __getattr__(self, attrname): if attrname[:3] == 'to_': if self.views[attrname[3:]] is not None: return lambda: self.views[attrname[3:]](self) else: raise NotImplementedError(( "Model {cn.__module__}.{cn.__name__} does not have" + " a default view for " "{tp}").format(cn=type(self), tp=attrname[3:])) else: return super().__getattr__(attrname) ././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1740146607.0 oslo_reports-3.5.1/oslo_reports/opts.py0000664000175000017500000000500000000000000020361 0ustar00zuulzuul00000000000000# Licensed under the Apache License, Version 2.0 (the "License"); you may # not use this file except in compliance with the License. You may obtain # a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the # License for the specific language governing permissions and limitations # under the License. import copy from oslo_config import cfg from oslo_reports._i18n import _ __all__ = [ 'list_opts', 'set_defaults', ] _option_group = 'oslo_reports' _options = [ cfg.StrOpt('log_dir', help=_('Path to a log directory where to create a file')), cfg.StrOpt('file_event_handler', help=_('The path to a file to watch for changes to trigger ' 'the reports, instead of signals. Setting this option ' 'disables the signal trigger for the reports. If ' 'application is running as a WSGI application it is ' 'recommended to use this instead of signals.')), cfg.IntOpt('file_event_handler_interval', default=1, help=_('How many seconds to wait between polls when ' 'file_event_handler is set')) ] def list_opts(): """Return a list of oslo.config options available in the library. The returned list includes all oslo.config options which may be registered at runtime by the library. Each element of the list is a tuple. The first element is the name of the group under which the list of elements in the second element will be registered. A group name of None corresponds to the [DEFAULT] group in config files. This function is also discoverable via the 'oslo_messaging' entry point under the 'oslo.config.opts' namespace. The purpose of this is to allow tools like the Oslo sample config file generator to discover the options exposed to users by this library. :returns: a list of (group_name, opts) tuples """ return [(_option_group, copy.deepcopy(_options))] def set_defaults(conf): """Set defaults for configuration variables. Overrides default options values. :param conf: Configuration object, managed by the caller. :type conf: oslo.config.cfg.ConfigOpts """ conf.register_opts(_options, group=_option_group) ././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1740146607.0 oslo_reports-3.5.1/oslo_reports/report.py0000664000175000017500000001435600000000000020725 0ustar00zuulzuul00000000000000# Copyright 2013 Red Hat, Inc. # # Licensed under the Apache License, Version 2.0 (the "License"); you may # not use this file except in compliance with the License. You may obtain # a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the # License for the specific language governing permissions and limitations # under the License. """Provides Report classes This module defines various classes representing reports and report sections. All reports take the form of a report class containing various report sections. """ from oslo_reports.views.text import header as header_views class BasicReport: """A Basic Report A Basic Report consists of a collection of :class:`ReportSection` objects, each of which contains a top-level model and generator. It collects these sections into a cohesive report which may then be serialized by calling :func:`run`. """ def __init__(self): self.sections = [] self._state = 0 def add_section(self, view, generator, index=None): """Add a section to the report This method adds a section with the given view and generator to the report. An index may be specified to insert the section at a given location in the list; If no index is specified, the section is appended to the list. The view is called on the model which results from the generator when the report is run. A generator is simply a method or callable object which takes no arguments and returns a :class:`oslo_reports.models.base.ReportModel` or similar object. :param view: the top-level view for the section :param generator: the method or class which generates the model :param index: the index at which to insert the section (or None to append it) :type index: int or None """ if index is None: self.sections.append(ReportSection(view, generator)) else: self.sections.insert(index, ReportSection(view, generator)) def run(self): """Run the report This method runs the report, having each section generate its data and serialize itself before joining the sections together. The BasicReport accomplishes the joining by joining the serialized sections together with newlines. :rtype: str :returns: the serialized report """ return "\n".join(str(sect) for sect in self.sections) class ReportSection: """A Report Section A report section contains a generator and a top-level view. When something attempts to serialize the section by calling str() or unicode() on it, the section runs the generator and calls the view on the resulting model. .. seealso:: Class :class:`BasicReport` :func:`BasicReport.add_section` :param view: the top-level view for this section :param generator: the generator for this section (any callable object which takes no parameters and returns a data model) """ def __init__(self, view, generator): self.view = view self.generator = generator def __str__(self): return self.view(self.generator()) class ReportOfType(BasicReport): """A Report of a Certain Type A ReportOfType has a predefined type associated with it. This type is automatically propagated down to the each of the sections upon serialization by wrapping the generator for each section. .. seealso:: Class :class:`oslo_reports.models.with_default_view.ModelWithDefaultView` # noqa (the entire class) Class :class:`oslo_reports.models.base.ReportModel` :func:`oslo_reports.models.base.ReportModel.set_current_view_type` # noqa :param str tp: the type of the report """ def __init__(self, tp): self.output_type = tp super().__init__() def add_section(self, view, generator, index=None): def with_type(gen): def newgen(): res = gen() try: res.set_current_view_type(self.output_type) except AttributeError: pass return res return newgen super().add_section( view, with_type(generator), index ) class TextReport(ReportOfType): """A Human-Readable Text Report This class defines a report that is designed to be read by a human being. It has nice section headers, and a formatted title. :param str name: the title of the report """ def __init__(self, name): super().__init__('text') self.name = name # add a title with a generator that creates an empty result model self.add_section(name, lambda: ('|' * 72) + "\n\n") def add_section(self, heading, generator, index=None): """Add a section to the report This method adds a section with the given title, and generator to the report. An index may be specified to insert the section at a given location in the list; If no index is specified, the section is appended to the list. The view is called on the model which results from the generator when the report is run. A generator is simply a method or callable object which takes no arguments and returns a :class:`oslo_reports.models.base.ReportModel` or similar object. The model is told to serialize as text (if possible) at serialization time by wrapping the generator. The view model's attached view (if any) is wrapped in a :class:`oslo_reports.views.text.header.TitledView` :param str heading: the title for the section :param generator: the method or class which generates the model :param index: the index at which to insert the section (or None to append) :type index: int or None """ super().add_section(header_views.TitledView(heading), generator, index) ././@PaxHeader0000000000000000000000000000003400000000000011452 xustar000000000000000028 mtime=1740146654.5321827 oslo_reports-3.5.1/oslo_reports/tests/0000775000175000017500000000000000000000000020171 5ustar00zuulzuul00000000000000././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1740146607.0 oslo_reports-3.5.1/oslo_reports/tests/__init__.py0000664000175000017500000000000000000000000022270 0ustar00zuulzuul00000000000000././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1740146607.0 oslo_reports-3.5.1/oslo_reports/tests/test_base_report.py0000664000175000017500000001153000000000000024107 0ustar00zuulzuul00000000000000# Copyright 2013 Red Hat, Inc. # # Licensed under the Apache License, Version 2.0 (the "License"); you may # not use this file except in compliance with the License. You may obtain # a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the # License for the specific language governing permissions and limitations # under the License. from collections import abc import re from oslotest import base from oslo_reports.models import base as base_model from oslo_reports import report class BasicView: def __call__(self, model): res = "" for k in sorted(model.keys()): res += str(k) + ": " + str(model[k]) + ";" return res def basic_generator(): return base_model.ReportModel(data={'string': 'value', 'int': 1}) class TestBasicReport(base.BaseTestCase): def setUp(self): super().setUp() self.report = report.BasicReport() def test_add_section(self): self.report.add_section(BasicView(), basic_generator) self.assertEqual(len(self.report.sections), 1) def test_append_section(self): self.report.add_section(BasicView(), lambda: {'a': 1}) self.report.add_section(BasicView(), basic_generator) self.assertEqual(len(self.report.sections), 2) self.assertEqual(self.report.sections[1].generator, basic_generator) def test_insert_section(self): self.report.add_section(BasicView(), lambda: {'a': 1}) self.report.add_section(BasicView(), basic_generator, 0) self.assertEqual(len(self.report.sections), 2) self.assertEqual(self.report.sections[0].generator, basic_generator) def test_basic_render(self): self.report.add_section(BasicView(), basic_generator) self.assertEqual(self.report.run(), "int: 1;string: value;") class TestBaseModel(base.BaseTestCase): def test_submodel_attached_view(self): class TmpView: def __call__(self, model): return '{len: ' + str(len(model.c)) + '}' def generate_model_with_submodel(): base_m = basic_generator() tv = TmpView() base_m['submodel'] = base_model.ReportModel(data={'c': [1, 2, 3]}, attached_view=tv) return base_m self.assertEqual(BasicView()(generate_model_with_submodel()), 'int: 1;string: value;submodel: {len: 3};') def test_str_throws_error_with_no_attached_view(self): model = base_model.ReportModel(data={'c': [1, 2, 3]}) self.assertRaisesRegex(Exception, 'Cannot stringify model: no attached view', str, model) def test_str_returns_string_with_attached_view(self): model = base_model.ReportModel(data={'a': 1, 'b': 2}, attached_view=BasicView()) self.assertEqual(str(model), 'a: 1;b: 2;') def test_model_repr(self): model1 = base_model.ReportModel(data={'a': 1, 'b': 2}, attached_view=BasicView()) model2 = base_model.ReportModel(data={'a': 1, 'b': 2}) base_re = r"" without_view_re = base_re + r"no view>" self.assertTrue(re.match(with_view_re, repr(model1))) self.assertTrue(re.match(without_view_re, repr(model2))) def test_getattr(self): model = base_model.ReportModel(data={'a': 1}) self.assertEqual(model.a, 1) self.assertRaises(AttributeError, getattr, model, 'b') def test_data_as_sequence_is_handled_properly(self): model = base_model.ReportModel(data=['a', 'b']) model.attached_view = BasicView() # if we don't handle lists properly, we'll get a TypeError here self.assertEqual('0: a;1: b;', str(model)) def test_immutable_mappings_produce_mutable_models(self): class SomeImmutableMapping(abc.Mapping): def __init__(self): self.data = {'a': 2, 'b': 4, 'c': 8} def __getitem__(self, key): return self.data[key] def __len__(self): return len(self.data) def __iter__(self): return iter(self.data) mp = SomeImmutableMapping() model = base_model.ReportModel(data=mp) model.attached_view = BasicView() self.assertEqual('a: 2;b: 4;c: 8;', str(model)) model['d'] = 16 self.assertEqual('a: 2;b: 4;c: 8;d: 16;', str(model)) self.assertEqual({'a': 2, 'b': 4, 'c': 8}, mp.data) ././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1740146607.0 oslo_reports-3.5.1/oslo_reports/tests/test_guru_meditation_report.py0000664000175000017500000002372300000000000026403 0ustar00zuulzuul00000000000000# Copyright 2013 Red Hat, Inc. # # Licensed under the Apache License, Version 2.0 (the "License"); you may # not use this file except in compliance with the License. You may obtain # a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the # License for the specific language governing permissions and limitations # under the License. import datetime import io import os import re import signal import sys import threading from unittest import mock # needed to get greenthreads import fixtures import greenlet from oslotest import base import oslo_config from oslo_config import fixture from oslo_reports import guru_meditation_report as gmr from oslo_reports.models import with_default_views as mwdv from oslo_reports import opts CONF = oslo_config.cfg.CONF opts.set_defaults(CONF) class FakeVersionObj: def vendor_string(self): return 'Cheese Shoppe' def product_string(self): return 'Sharp Cheddar' def version_string_with_package(self): return '1.0.0' def skip_body_lines(start_line, report_lines): curr_line = start_line while (len(report_lines[curr_line]) == 0 or report_lines[curr_line][0] != '='): curr_line += 1 return curr_line class GmrConfigFixture(fixture.Config): def setUp(self): super().setUp() self.conf.set_override( 'file_event_handler', '/specific/file', group='oslo_reports') self.conf.set_override( 'file_event_handler_interval', 10, group='oslo_reports') self.conf.set_override( 'log_dir', '/var/fake_log', group='oslo_reports') class TestGuruMeditationReport(base.BaseTestCase): def setUp(self): super().setUp() self.curr_g = greenlet.getcurrent() self.report = gmr.TextGuruMeditation(FakeVersionObj()) self.old_stderr = None self.CONF = self.useFixture(GmrConfigFixture(CONF)).conf def test_basic_report(self): report_lines = self.report.run().split('\n') target_str_header = ['========================================================================', # noqa '==== Guru Meditation ====', # noqa '========================================================================', # noqa '||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||', # noqa '', '', '========================================================================', # noqa '==== Package ====', # noqa '========================================================================', # noqa 'product = Sharp Cheddar', 'vendor = Cheese Shoppe', 'version = 1.0.0', '========================================================================', # noqa '==== Threads ====', # noqa '========================================================================'] # noqa # first the header and version info... self.assertEqual(target_str_header, report_lines[0:len(target_str_header)]) # followed by at least one thread... # NOTE(zqfan): add an optional '-' because sys._current_frames() # may return a negative thread id on 32 bit operating system. self.assertTrue(re.match(r'------(\s+)Thread #-?\d+\1\s?------', report_lines[len(target_str_header)])) self.assertEqual('', report_lines[len(target_str_header) + 1]) # followed by more thread stuff stuff... curr_line = skip_body_lines(len(target_str_header) + 2, report_lines) # followed by at least one green thread target_str_gt = ['========================================================================', # noqa '==== Green Threads ====', # noqa '========================================================================', # noqa '------ Green Thread ------', # noqa ''] end_bound = curr_line + len(target_str_gt) self.assertEqual(target_str_gt, report_lines[curr_line:end_bound]) # followed by some more green thread stuff curr_line = skip_body_lines(curr_line + len(target_str_gt), report_lines) # followed by the processes header target_str_p_head = ['========================================================================', # noqa '==== Processes ====', # noqa '========================================================================'] # noqa end_bound = curr_line + len(target_str_p_head) self.assertEqual(target_str_p_head, report_lines[curr_line:end_bound]) curr_line += len(target_str_p_head) # followed by at least one process self.assertTrue(re.match(r"Process \d+ \(under \d+\)", report_lines[curr_line])) # followed by some more process stuff curr_line = skip_body_lines(curr_line + 1, report_lines) # followed finally by the configuration target_str_config = ['========================================================================', # noqa '==== Configuration ====', # noqa '========================================================================', # noqa ''] end_bound = curr_line + len(target_str_config) self.assertEqual(target_str_config, report_lines[curr_line:end_bound]) def test_reg_persistent_section(self): def fake_gen(): fake_data = {'cheddar': ['sharp', 'mild'], 'swiss': ['with holes', 'with lots of holes'], 'american': ['orange', 'yellow']} return mwdv.ModelWithDefaultViews(data=fake_data) gmr.TextGuruMeditation.register_section('Cheese Types', fake_gen) report_lines = self.report.run() target_lst = ['========================================================================', # noqa '==== Cheese Types ====', # noqa '========================================================================', # noqa 'american = ', ' orange', ' yellow', 'cheddar = ', ' mild', ' sharp', 'swiss = ', ' with holes', ' with lots of holes'] target_str = '\n'.join(target_lst) self.assertIn(target_str, report_lines) def test_register_autorun(self): gmr.TextGuruMeditation.setup_autorun(FakeVersionObj()) self.old_stderr = sys.stderr sys.stderr = io.StringIO() os.kill(os.getpid(), signal.SIGUSR2) self.assertIn('Guru Meditation', sys.stderr.getvalue()) @mock.patch.object(gmr.TextGuruMeditation, '_setup_file_watcher') def test_register_autorun_without_signals(self, mock_setup_fh): version = FakeVersionObj() gmr.TextGuruMeditation.setup_autorun(version, conf=self.CONF) mock_setup_fh.assert_called_once_with( '/specific/file', 10, version, None, '/var/fake_log') @mock.patch('os.stat') @mock.patch('time.sleep') @mock.patch.object(threading.Thread, 'start') def test_setup_file_watcher(self, mock_thread, mock_sleep, mock_stat): version = FakeVersionObj() mock_stat.return_value.st_mtime = 3 gmr.TextGuruMeditation._setup_file_watcher( self.CONF.oslo_reports.file_event_handler, self.CONF.oslo_reports.file_event_handler_interval, version, None, self.CONF.oslo_reports.log_dir) mock_stat.assert_called_once_with('/specific/file') self.assertEqual(1, mock_thread.called) @mock.patch('oslo_utils.timeutils.utcnow', return_value=datetime.datetime(2014, 1, 1, 12, 0, 0)) def test_register_autorun_log_dir(self, mock_strtime): log_dir = self.useFixture(fixtures.TempDir()).path gmr.TextGuruMeditation.setup_autorun( FakeVersionObj(), "fake-service", log_dir) os.kill(os.getpid(), signal.SIGUSR2) with open(os.path.join( log_dir, "fake-service_gurumeditation_20140101120000")) as df: self.assertIn('Guru Meditation', df.read()) @mock.patch.object(gmr.TextGuruMeditation, 'run') def test_fail_prints_traceback(self, run_mock): class RunFail(Exception): pass run_mock.side_effect = RunFail() gmr.TextGuruMeditation.setup_autorun(FakeVersionObj()) self.old_stderr = sys.stderr sys.stderr = io.StringIO() os.kill(os.getpid(), signal.SIGUSR2) self.assertIn('RunFail', sys.stderr.getvalue()) def tearDown(self): super().tearDown() if self.old_stderr is not None: sys.stderr = self.old_stderr ././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1740146607.0 oslo_reports-3.5.1/oslo_reports/tests/test_openstack_generators.py0000664000175000017500000001313400000000000026024 0ustar00zuulzuul00000000000000# Copyright 2011 OpenStack Foundation. # All Rights Reserved. # # Licensed under the Apache License, Version 2.0 (the "License"); you may # not use this file except in compliance with the License. You may obtain # a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the # License for the specific language governing permissions and limitations # under the License. import threading from unittest import mock import greenlet from oslo_config import cfg from oslotest import base from oslo_reports.generators import conf as os_cgen from oslo_reports.generators import threading as os_tgen from oslo_reports.generators import version as os_pgen from oslo_reports.models import threading as os_tmod class TestOpenstackGenerators(base.BaseTestCase): def test_thread_generator(self): model = os_tgen.ThreadReportGenerator()() # self.assertGreaterEqual(len(model.keys()), 1) self.assertTrue(len(model.keys()) >= 1) was_ok = False for val in model.values(): self.assertIsInstance(val, os_tmod.ThreadModel) self.assertIsNotNone(val.stack_trace) if val.thread_id == threading.current_thread().ident: was_ok = True break self.assertTrue(was_ok) model.set_current_view_type('text') self.assertIsNotNone(str(model)) def test_thread_generator_tb(self): class FakeModel: def __init__(self, thread_id, tb): self.traceback = tb with mock.patch('oslo_reports.models' '.threading.ThreadModel', FakeModel): model = os_tgen.ThreadReportGenerator("fake traceback")() curr_thread = model.get(threading.current_thread().ident, None) self.assertIsNotNone(curr_thread, None) self.assertEqual("fake traceback", curr_thread.traceback) def test_green_thread_generator(self): curr_g = greenlet.getcurrent() model = os_tgen.GreenThreadReportGenerator()() # self.assertGreaterEqual(len(model.keys()), 1) self.assertTrue(len(model.keys()) >= 1) was_ok = False for tm in model.values(): if tm.stack_trace == os_tmod.StackTraceModel(curr_g.gr_frame): was_ok = True break self.assertTrue(was_ok) model.set_current_view_type('text') self.assertIsNotNone(str(model)) def test_config_model(self): conf = cfg.ConfigOpts() conf.register_opt(cfg.StrOpt('crackers', default='triscuit')) conf.register_opt(cfg.StrOpt('secrets', secret=True, default='should not show')) conf.register_group(cfg.OptGroup('cheese', title='Cheese Info')) conf.register_opt(cfg.IntOpt('sharpness', default=1), group='cheese') conf.register_opt(cfg.StrOpt('name', default='cheddar'), group='cheese') conf.register_opt(cfg.BoolOpt('from_cow', default=True), group='cheese') conf.register_opt(cfg.StrOpt('group_secrets', secret=True, default='should not show'), group='cheese') model = os_cgen.ConfigReportGenerator(conf)() model.set_current_view_type('text') # oslo.config added a default config_source opt which gets included # in our output, but we also need to support older versions where that # wasn't the case. This logic can be removed once the oslo.config # lower constraint becomes >=6.4.0. config_source_line = ' config_source = \n' try: conf.config_source except cfg.NoSuchOptError: config_source_line = '' target_str = ('\ncheese: \n' ' from_cow = True\n' ' group_secrets = ***\n' ' name = cheddar\n' ' sharpness = 1\n' '\n' 'default: \n' '%s' ' crackers = triscuit\n' ' secrets = ***\n' ' shell_completion = None') % config_source_line self.assertEqual(target_str, str(model)) def test_package_report_generator(self): class VersionObj: def vendor_string(self): return 'Cheese Shoppe' def product_string(self): return 'Sharp Cheddar' def version_string_with_package(self): return '1.0.0' model = os_pgen.PackageReportGenerator(VersionObj())() model.set_current_view_type('text') target_str = ('product = Sharp Cheddar\n' 'vendor = Cheese Shoppe\n' 'version = 1.0.0') self.assertEqual(target_str, str(model)) def test_package_report_generator_without_vendor_string(self): class VersionObj: def product_string(self): return 'Sharp Cheddar' def version_string_with_package(self): return '1.0.0' model = os_pgen.PackageReportGenerator(VersionObj())() model.set_current_view_type('text') target_str = ('product = Sharp Cheddar\n' 'vendor = None\n' 'version = 1.0.0') self.assertEqual(target_str, str(model)) ././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1740146607.0 oslo_reports-3.5.1/oslo_reports/tests/test_views.py0000664000175000017500000004005400000000000022742 0ustar00zuulzuul00000000000000# Copyright 2013 Red Hat, Inc. # # Licensed under the Apache License, Version 2.0 (the "License"); you may # not use this file except in compliance with the License. You may obtain # a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the # License for the specific language governing permissions and limitations # under the License. import copy from unittest import mock from oslotest import base from oslo_reports.models import base as base_model from oslo_reports.models import with_default_views as mwdv from oslo_reports import report from oslo_reports.views import jinja_view as jv from oslo_reports.views.json import generic as json_generic from oslo_reports.views.text import generic as text_generic def mwdv_generator(): return mwdv.ModelWithDefaultViews(data={'string': 'value', 'int': 1}) class TestModelReportType(base.BaseTestCase): def test_model_with_default_views(self): model = mwdv_generator() model.set_current_view_type('text') self.assertEqual('int = 1\nstring = value', str(model)) model.set_current_view_type('json') self.assertEqual('{"int": 1, "string": "value"}', str(model)) model.set_current_view_type('xml') self.assertEqual('1value', str(model)) def test_recursive_type_propagation_with_nested_models(self): model = mwdv_generator() model['submodel'] = mwdv_generator() model.set_current_view_type('json') self.assertEqual(model.submodel.views['json'], model.submodel.attached_view) def test_recursive_type_propagation_with_nested_dicts(self): nested_model = mwdv.ModelWithDefaultViews(json_view='abc') data = {'a': 1, 'b': {'c': nested_model}} top_model = base_model.ReportModel(data=data) top_model.set_current_view_type('json') self.assertEqual(nested_model.attached_view, nested_model.views['json']) def test_recursive_type_propagation_with_nested_lists(self): nested_model = mwdv_generator() data = {'a': 1, 'b': [nested_model]} top_model = base_model.ReportModel(data=data) top_model.set_current_view_type('json') self.assertEqual(nested_model.attached_view, nested_model.views['json']) def test_recursive_type_propogation_on_recursive_structures(self): nested_model = mwdv_generator() data = {'a': 1, 'b': [nested_model]} nested_model['c'] = data top_model = base_model.ReportModel(data=data) top_model.set_current_view_type('json') self.assertEqual(nested_model.attached_view, nested_model.views['json']) del nested_model['c'] def test_report_of_type(self): rep = report.ReportOfType('json') rep.add_section(lambda x: str(x), mwdv_generator) self.assertEqual('{"int": 1, "string": "value"}', rep.run()) # NOTE: this also tests views.text.header def test_text_report(self): rep = report.TextReport('Test Report') rep.add_section('An Important Section', mwdv_generator) rep.add_section('Another Important Section', mwdv_generator) target_str = ('========================================================================\n' # noqa '==== Test Report ====\n' # noqa '========================================================================\n' # noqa '||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||\n' # noqa '\n' # noqa '\n' # noqa '========================================================================\n' # noqa '==== An Important Section ====\n' # noqa '========================================================================\n' # noqa 'int = 1\n' # noqa 'string = value\n' # noqa '========================================================================\n' # noqa '==== Another Important Section ====\n' # noqa '========================================================================\n' # noqa 'int = 1\n' # noqa 'string = value') # noqa self.assertEqual(target_str, rep.run()) def test_to_type(self): model = mwdv_generator() self.assertEqual('1value', model.to_xml()) class TestGenericXMLView(base.BaseTestCase): def setUp(self): super().setUp() self.model = mwdv_generator() self.model.set_current_view_type('xml') def test_dict_serialization(self): self.model['dt'] = {'a': 1, 'b': 2} target_str = ('' '
12
' '1' 'value
') self.assertEqual(target_str, str(self.model)) def test_list_serialization(self): self.model['lt'] = ['a', 'b'] target_str = ('' '1' 'ab' 'value') self.assertEqual(target_str, str(self.model)) def test_list_in_dict_serialization(self): self.model['dt'] = {'a': 1, 'b': [2, 3]} target_str = ('' '
1' '23
' '1' 'value
') self.assertEqual(target_str, str(self.model)) def test_dict_in_list_serialization(self): self.model['lt'] = [1, {'b': 2, 'c': 3}] target_str = ('' '1' '1' '23' 'value') self.assertEqual(target_str, str(self.model)) def test_submodel_serialization(self): sm = mwdv_generator() sm.set_current_view_type('xml') self.model['submodel'] = sm target_str = ('' '1' 'value' '' '1value' '' '') self.assertEqual(target_str, str(self.model)) def test_wrapper_name(self): self.model.attached_view.wrapper_name = 'cheese' target_str = ('' '1' 'value' '') self.assertEqual(target_str, str(self.model)) class TestGenericJSONViews(base.BaseTestCase): def setUp(self): super().setUp() self.model = mwdv_generator() self.model.set_current_view_type('json') def test_basic_kv_view(self): attached_view = json_generic.BasicKeyValueView() self.model = base_model.ReportModel(data={'string': 'value', 'int': 1}, attached_view=attached_view) self.assertEqual('{"int": 1, "string": "value"}', str(self.model)) def test_dict_serialization(self): self.model['dt'] = {'a': 1, 'b': 2} target_str = ('{' '"dt": {"a": 1, "b": 2}, ' '"int": 1, ' '"string": "value"' '}') self.assertEqual(target_str, str(self.model)) def test_list_serialization(self): self.model['lt'] = ['a', 'b'] target_str = ('{' '"int": 1, ' '"lt": ["a", "b"], ' '"string": "value"' '}') self.assertEqual(target_str, str(self.model)) def test_list_in_dict_serialization(self): self.model['dt'] = {'a': 1, 'b': [2, 3]} target_str = ('{' '"dt": {"a": 1, "b": [2, 3]}, ' '"int": 1, ' '"string": "value"' '}') self.assertEqual(target_str, str(self.model)) def test_dict_in_list_serialization(self): self.model['lt'] = [1, {'b': 2, 'c': 3}] target_str = ('{' '"int": 1, ' '"lt": [1, {"b": 2, "c": 3}], ' '"string": "value"' '}') self.assertEqual(target_str, str(self.model)) def test_submodel_serialization(self): sm = mwdv_generator() sm.set_current_view_type('json') self.model['submodel'] = sm target_str = ('{' '"int": 1, ' '"string": "value", ' '"submodel": {"int": 1, "string": "value"}' '}') self.assertEqual(target_str, str(self.model)) class TestGenericTextViews(base.BaseTestCase): def setUp(self): super().setUp() self.model = mwdv_generator() self.model.set_current_view_type('text') def test_multi_view(self): attached_view = text_generic.MultiView() self.model = base_model.ReportModel(data={}, attached_view=attached_view) self.model['1'] = mwdv_generator() self.model['2'] = mwdv_generator() self.model['2']['int'] = 2 self.model.set_current_view_type('text') target_str = ('int = 1\n' 'string = value\n' 'int = 2\n' 'string = value') self.assertEqual(target_str, str(self.model)) def test_basic_kv_view(self): attached_view = text_generic.BasicKeyValueView() self.model = base_model.ReportModel(data={'string': 'value', 'int': 1}, attached_view=attached_view) self.assertEqual('int = 1\nstring = value\n', str(self.model)) def test_table_view(self): column_names = ['Column A', 'Column B'] column_values = ['a', 'b'] attached_view = text_generic.TableView(column_names, column_values, 'table') self.model = base_model.ReportModel(data={}, attached_view=attached_view) self.model['table'] = [{'a': 1, 'b': 2}, {'a': 3, 'b': 4}] target_str = (' Column A | Column B \n' # noqa '------------------------------------------------------------------------\n' # noqa ' 1 | 2 \n' # noqa ' 3 | 4 \n') # noqa self.assertEqual(target_str, str(self.model)) def test_dict_serialization(self): self.model['dt'] = {'a': 1, 'b': 2} target_str = ('dt = \n' ' a = 1\n' ' b = 2\n' 'int = 1\n' 'string = value') self.assertEqual(target_str, str(self.model)) def test_dict_serialization_integer_keys(self): self.model['dt'] = {3: 4, 5: 6} target_str = ('dt = \n' ' 3 = 4\n' ' 5 = 6\n' 'int = 1\n' 'string = value') self.assertEqual(target_str, str(self.model)) def test_dict_serialization_mixed_keys(self): self.model['dt'] = {'3': 4, 5: 6} target_str = ('dt = \n' ' 3 = 4\n' ' 5 = 6\n' 'int = 1\n' 'string = value') self.assertEqual(target_str, str(self.model)) def test_list_serialization(self): self.model['lt'] = ['a', 'b'] target_str = ('int = 1\n' 'lt = \n' ' a\n' ' b\n' 'string = value') self.assertEqual(target_str, str(self.model)) def test_list_in_dict_serialization(self): self.model['dt'] = {'a': 1, 'b': [2, 3]} target_str = ('dt = \n' ' a = 1\n' ' b = \n' ' 2\n' ' 3\n' 'int = 1\n' 'string = value') self.assertEqual(target_str, str(self.model)) def test_dict_in_list_serialization(self): self.model['lt'] = [1, {'b': 2, 'c': 3}] target_str = ('int = 1\n' 'lt = \n' ' 1\n' ' [dict]\n' ' b = 2\n' ' c = 3\n' 'string = value') self.assertEqual(target_str, str(self.model)) def test_submodel_serialization(self): sm = mwdv_generator() sm.set_current_view_type('text') self.model['submodel'] = sm target_str = ('int = 1\n' 'string = value\n' 'submodel = \n' ' int = 1\n' ' string = value') self.assertEqual(target_str, str(self.model)) def test_custom_indent_string(self): view = text_generic.KeyValueView(indent_str='~~') self.model['lt'] = ['a', 'b'] self.model.attached_view = view target_str = ('int = 1\n' 'lt = \n' '~~a\n' '~~b\n' 'string = value') self.assertEqual(target_str, str(self.model)) def get_open_mocks(rv): file_mock = mock.MagicMock(name='file_obj') file_mock.read.return_value = rv open_mock = mock.MagicMock(name='open') open_mock().__enter__.return_value = file_mock return (open_mock, file_mock) class TestJinjaView(base.BaseTestCase): TEMPL_STR = "int is {{ int }}, string is {{ string }}" MM_OPEN, MM_FILE = get_open_mocks(TEMPL_STR) def setUp(self): super().setUp() self.model = base_model.ReportModel(data={'int': 1, 'string': 'value'}) @mock.mock_open(MM_OPEN) def test_load_from_file(self): self.model.attached_view = jv.JinjaView(path='a/b/c/d.jinja.txt') self.assertEqual('int is 1, string is value', str(self.model)) self.MM_FILE.assert_called_with_once('a/b/c/d.jinja.txt') def test_direct_pass(self): self.model.attached_view = jv.JinjaView(text=self.TEMPL_STR) self.assertEqual('int is 1, string is value', str(self.model)) def test_load_from_class(self): class TmpJinjaView(jv.JinjaView): VIEW_TEXT = TestJinjaView.TEMPL_STR self.model.attached_view = TmpJinjaView() self.assertEqual('int is 1, string is value', str(self.model)) def test_is_deepcopiable(self): view_orig = jv.JinjaView(text=self.TEMPL_STR) view_cpy = copy.deepcopy(view_orig) self.assertIsNot(view_orig, view_cpy) ././@PaxHeader0000000000000000000000000000003400000000000011452 xustar000000000000000028 mtime=1740146654.5321827 oslo_reports-3.5.1/oslo_reports/views/0000775000175000017500000000000000000000000020164 5ustar00zuulzuul00000000000000././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1740146607.0 oslo_reports-3.5.1/oslo_reports/views/__init__.py0000664000175000017500000000163000000000000022275 0ustar00zuulzuul00000000000000# Copyright 2013 Red Hat, Inc. # # Licensed under the Apache License, Version 2.0 (the "License"); you may # not use this file except in compliance with the License. You may obtain # a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the # License for the specific language governing permissions and limitations # under the License. """Provides predefined views This module provides a collection of predefined views for use in reports. It is separated by type (xml, json, or text). Each type contains a submodule called 'generic' containing several basic, universal views for that type. There is also a predefined view that utilizes Jinja. """ ././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1740146607.0 oslo_reports-3.5.1/oslo_reports/views/jinja_view.py0000664000175000017500000001040700000000000022665 0ustar00zuulzuul00000000000000# Copyright 2013 Red Hat, Inc. # # Licensed under the Apache License, Version 2.0 (the "License"); you may # not use this file except in compliance with the License. You may obtain # a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the # License for the specific language governing permissions and limitations # under the License. """Provides Jinja Views This module provides views that utilize the Jinja templating system for serialization. For more information on Jinja, please see http://jinja.pocoo.org/ . """ import copy import jinja2 class JinjaView: """A Jinja View This view renders the given model using the provided Jinja template. The template can be given in various ways. If the `VIEw_TEXT` property is defined, that is used as template. Othewise, if a `path` parameter is passed to the constructor, that is used to load a file containing the template. If the `path` parameter is None, the `text` parameter is used as the template. The leading newline character and trailing newline character are stripped from the template (provided they exist). Baseline indentation is also stripped from each line. The baseline indentation is determined by checking the indentation of the first line, after stripping off the leading newline (if any). :param str path: the path to the Jinja template :param str text: the text of the Jinja template """ def __init__(self, path=None, text=None): try: self._text = self.VIEW_TEXT except AttributeError: if path is not None: with open(path) as f: self._text = f.read() elif text is not None: self._text = text else: self._text = "" if self._text[0] == "\n": self._text = self._text[1:] newtext = self._text.lstrip() amt = len(self._text) - len(newtext) if (amt > 0): base_indent = self._text[0:amt] lines = self._text.splitlines() newlines = [] for line in lines: if line.startswith(base_indent): newlines.append(line[amt:]) else: newlines.append(line) self._text = "\n".join(newlines) if self._text[-1] == "\n": self._text = self._text[:-1] self._regentemplate = True self._templatecache = None def __call__(self, model): return self.template.render(**model) def __deepcopy__(self, memodict): res = object.__new__(JinjaView) res._text = copy.deepcopy(self._text, memodict) # regenerate the template on a deepcopy res._regentemplate = True res._templatecache = None return res @property def template(self): """Get the Compiled Template Gets the compiled template, using a cached copy if possible (stored in attr:`_templatecache`) or otherwise recompiling the template if the compiled template is not present or is invalid (due to attr:`_regentemplate` being set to True). :returns: the compiled Jinja template :rtype: :class:`jinja2.Template` """ if self._templatecache is None or self._regentemplate: self._templatecache = jinja2.Template(self._text) self._regentemplate = False return self._templatecache def _gettext(self): """Get the Template Text Gets the text of the current template :returns: the text of the Jinja template :rtype: str """ return self._text def _settext(self, textval): """Set the Template Text Sets the text of the current template, marking it for recompilation next time the compiled template is retrieved via attr:`template` . :param str textval: the new text of the Jinja template """ self._text = textval self.regentemplate = True text = property(_gettext, _settext) ././@PaxHeader0000000000000000000000000000003400000000000011452 xustar000000000000000028 mtime=1740146654.5321827 oslo_reports-3.5.1/oslo_reports/views/json/0000775000175000017500000000000000000000000021135 5ustar00zuulzuul00000000000000././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1740146607.0 oslo_reports-3.5.1/oslo_reports/views/json/__init__.py0000664000175000017500000000131300000000000023244 0ustar00zuulzuul00000000000000# Copyright 2013 Red Hat, Inc. # # Licensed under the Apache License, Version 2.0 (the "License"); you may # not use this file except in compliance with the License. You may obtain # a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the # License for the specific language governing permissions and limitations # under the License. """Provides basic JSON views This module provides several basic views which serialize models into JSON. """ ././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1740146607.0 oslo_reports-3.5.1/oslo_reports/views/json/generic.py0000664000175000017500000000436000000000000023126 0ustar00zuulzuul00000000000000# Copyright 2013 Red Hat, Inc. # # Licensed under the Apache License, Version 2.0 (the "License"); you may # not use this file except in compliance with the License. You may obtain # a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the # License for the specific language governing permissions and limitations # under the License. """Provides generic JSON views This modules defines several basic views for serializing data to JSON. Submodels that have already been serialized as JSON may have their string values marked with `__is_json__ = True` using :class:`oslo_reports._utils.StringWithAttrs` (each of the classes within this module does this automatically, and non-naive serializers check for this attribute and handle such strings specially) """ import copy from oslo_serialization import jsonutils as json from oslo_reports import _utils as utils class BasicKeyValueView: """A Basic Key-Value JSON View This view performs a naive serialization of a model into JSON by simply calling :func:`json.dumps` on the model """ def __call__(self, model): res = utils.StringWithAttrs(json.dumps(model.data, sort_keys=True)) res.__is_json__ = True return res class KeyValueView: """A Key-Value JSON View This view performs advanced serialization to a model into JSON. It does so by first checking all values to see if they are marked as JSON. If so, they are deserialized using :func:`json.loads`. Then, the copy of the model with all JSON deserialized is reserialized into proper nested JSON using :func:`json.dumps`. """ def __call__(self, model): # this part deals with subviews that were already serialized cpy = copy.deepcopy(model) for key in model.keys(): if getattr(model[key], '__is_json__', False): cpy[key] = json.loads(model[key]) res = utils.StringWithAttrs(json.dumps(cpy.data, sort_keys=True)) res.__is_json__ = True return res ././@PaxHeader0000000000000000000000000000003400000000000011452 xustar000000000000000028 mtime=1740146654.5321827 oslo_reports-3.5.1/oslo_reports/views/text/0000775000175000017500000000000000000000000021150 5ustar00zuulzuul00000000000000././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1740146607.0 oslo_reports-3.5.1/oslo_reports/views/text/__init__.py0000664000175000017500000000133200000000000023260 0ustar00zuulzuul00000000000000# Copyright 2013 Red Hat, Inc. # # Licensed under the Apache License, Version 2.0 (the "License"); you may # not use this file except in compliance with the License. You may obtain # a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the # License for the specific language governing permissions and limitations # under the License. """Provides basic text views This module provides several basic views which serialize models into human-readable text. """ ././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1740146607.0 oslo_reports-3.5.1/oslo_reports/views/text/generic.py0000664000175000017500000001566300000000000023151 0ustar00zuulzuul00000000000000# Copyright 2013 Red Hat, Inc. # # Licensed under the Apache License, Version 2.0 (the "License"); you may # not use this file except in compliance with the License. You may obtain # a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the # License for the specific language governing permissions and limitations # under the License. """Provides generic text views This modules provides several generic views for serializing models into human-readable text. """ from collections import abc class MultiView: """A Text View Containing Multiple Views This view simply serializes each value in the data model, and then joins them with newlines (ignoring the key values altogether). This is useful for serializing lists of models (as array-like dicts). """ def __call__(self, model): res = sorted([str(model[key]) for key in model]) return "\n".join(res) class BasicKeyValueView: """A Basic Key-Value Text View This view performs a naive serialization of a model into text using a basic key-value method, where each key-value pair is rendered as "key = str(value)" """ def __call__(self, model): res = "" for key in sorted(model): res += "{key} = {value}\n".format(key=key, value=model[key]) return res class KeyValueView: """A Key-Value Text View This view performs an advanced serialization of a model into text by following the following set of rules: key : text key = text rootkey : Mapping :: rootkey = serialize(key, value) key : Sequence :: key = serialize(item) :param str indent_str: the string used to represent one "indent" :param str key_sep: the separator to use between keys and values :param str dict_sep: the separator to use after a dictionary root key :param str list_sep: the separator to use after a list root key :param str anon_dict: the "key" to use when there is a dict in a list (does not automatically use the dict separator) :param before_dict: content to place on the line(s) before the a dict root key (use None to avoid inserting an extra line) :type before_dict: str or None :param before_list: content to place on the line(s) before the a list root key (use None to avoid inserting an extra line) :type before_list: str or None """ def __init__(self, indent_str=' ', key_sep=' = ', dict_sep=' = ', list_sep=' = ', anon_dict='[dict]', before_dict=None, before_list=None): self.indent_str = indent_str self.key_sep = key_sep self.dict_sep = dict_sep self.list_sep = list_sep self.anon_dict = anon_dict self.before_dict = before_dict self.before_list = before_list def __call__(self, model): def serialize(root, rootkey, indent): res = [] if rootkey is not None: res.append((self.indent_str * indent) + str(rootkey)) if isinstance(root, abc.Mapping): if rootkey is None and indent > 0: res.append((self.indent_str * indent) + self.anon_dict) elif rootkey is not None: res[0] += self.dict_sep if self.before_dict is not None: res.insert(0, self.before_dict) for key in sorted(root, key=str): res.extend(serialize(root[key], key, indent + 1)) elif (isinstance(root, abc.Sequence) and not isinstance(root, str)): if rootkey is not None: res[0] += self.list_sep if self.before_list is not None: res.insert(0, self.before_list) for val in sorted(root, key=str): res.extend(serialize(val, None, indent + 1)) else: str_root = str(root) if '\n' in str_root: # we are in a submodel if rootkey is not None: res[0] += self.dict_sep list_root = [(self.indent_str * (indent + 1)) + line for line in str_root.split('\n')] res.extend(list_root) else: # just a normal key or list entry try: res[0] += self.key_sep + str_root except IndexError: res = [(self.indent_str * indent) + str_root] return res return "\n".join(serialize(model, None, -1)) class TableView: """A Basic Table Text View This view performs serialization of data into a basic table with predefined column names and mappings. Column width is auto-calculated evenly, column values are automatically truncated accordingly. Values are centered in the columns. :param [str] column_names: the headers for each of the columns :param [str] column_values: the item name to match each column to in each row :param str table_prop_name: the name of the property within the model containing the row models """ def __init__(self, column_names, column_values, table_prop_name): self.table_prop_name = table_prop_name self.column_names = column_names self.column_values = column_values self.column_width = (72 - len(column_names) + 1) // len(column_names) column_headers = "|".join( "{{ch[{n}]: ^{width}}}".format(n=n, width=self.column_width) for n in range(len(column_names)) ) # correct for float-to-int roundoff error test_fmt = column_headers.format(ch=column_names) if len(test_fmt) < 72: column_headers += ' ' * (72 - len(test_fmt)) vert_divider = '-' * 72 self.header_fmt_str = column_headers + "\n" + vert_divider + "\n" self.row_fmt_str = "|".join( "{{cv[{n}]: ^{width}}}".format(n=n, width=self.column_width) for n in range(len(column_values)) ) def __call__(self, model): res = self.header_fmt_str.format(ch=self.column_names) for raw_row in model[self.table_prop_name]: row = [str(raw_row[prop_name]) for prop_name in self.column_values] # double format is in case we have roundoff error res += '{: <72}\n'.format(self.row_fmt_str.format(cv=row)) return res ././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1740146607.0 oslo_reports-3.5.1/oslo_reports/views/text/header.py0000664000175000017500000000273300000000000022757 0ustar00zuulzuul00000000000000# Copyright 2013 Red Hat, Inc. # # Licensed under the Apache License, Version 2.0 (the "License"); you may # not use this file except in compliance with the License. You may obtain # a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the # License for the specific language governing permissions and limitations # under the License. """Text Views With Headers This package defines several text views with headers """ class HeaderView: """A Text View With a Header This view simply serializes the model and places the given header on top. :param header: the header (can be anything on which str() can be called) """ def __init__(self, header): self.header = header def __call__(self, model): return f'{self.header}\n{model}' class TitledView(HeaderView): """A Text View With a Title This view simply serializes the model, and places a preformatted header containing the given title text on top. The title text can be up to 64 characters long. :param str title: the title of the view """ FORMAT_STR = ('=' * 72) + "\n===={0: ^64}====\n" + ('=' * 72) def __init__(self, title): super().__init__(self.FORMAT_STR.format(title)) ././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1740146607.0 oslo_reports-3.5.1/oslo_reports/views/text/process.py0000664000175000017500000000226300000000000023203 0ustar00zuulzuul00000000000000# Copyright 2014 Red Hat, Inc. # # Licensed under the Apache License, Version 2.0 (the "License"); you may # not use this file except in compliance with the License. You may obtain # a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the # License for the specific language governing permissions and limitations # under the License. """Provides process view This module provides a view for visualizing processes in human-readable form """ import oslo_reports.views.jinja_view as jv class ProcessView(jv.JinjaView): """A Process View This view displays process models defined by :class:`oslo_reports.models.process.ProcessModel` """ VIEW_TEXT = ( "Process {{ pid }} (under {{ parent_pid }}) " "[ run by: {{ username }} ({{ uids.real|default('unknown uid') }})," " state: {{ state }} ]\n" "{% for child in children %}" " {{ child }}" "{% endfor %}" ) ././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1740146607.0 oslo_reports-3.5.1/oslo_reports/views/text/threading.py0000664000175000017500000000454700000000000023501 0ustar00zuulzuul00000000000000# Copyright 2013 Red Hat, Inc. # # Licensed under the Apache License, Version 2.0 (the "License"); you may # not use this file except in compliance with the License. You may obtain # a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the # License for the specific language governing permissions and limitations # under the License. """Provides thread and stack-trace views This module provides a collection of views for visualizing threads, green threads, and stack traces in human-readable form. """ from oslo_reports.views import jinja_view as jv class StackTraceView(jv.JinjaView): """A Stack Trace View This view displays stack trace models defined by :class:`oslo_reports.models.threading.StackTraceModel` """ VIEW_TEXT = ( "{% if root_exception is not none %}" "Exception: {{ root_exception }}\n" "------------------------------------\n" "\n" "{% endif %}" "{% for line in lines %}\n" "{{ line.filename }}:{{ line.line }} in {{ line.name }}\n" " {% if line.code is not none %}" "`{{ line.code }}`" "{% else %}" "(source not found)" "{% endif %}\n" "{% else %}\n" "No Traceback!\n" "{% endfor %}" ) class GreenThreadView: """A Green Thread View This view displays a green thread provided by the data model :class:`oslo_reports.models.threading.GreenThreadModel` """ FORMAT_STR = "------{thread_str: ^60}------" + "\n" + "{stack_trace}" def __call__(self, model): return self.FORMAT_STR.format( thread_str=" Green Thread ", stack_trace=model.stack_trace ) class ThreadView: """A Thread Collection View This view displays a python thread provided by the data model :class:`oslo_reports.models.threading.ThreadModel` # noqa """ FORMAT_STR = "------{thread_str: ^60}------" + "\n" + "{stack_trace}" def __call__(self, model): return self.FORMAT_STR.format( thread_str=" Thread #{} ".format(model.thread_id), stack_trace=model.stack_trace ) ././@PaxHeader0000000000000000000000000000003400000000000011452 xustar000000000000000028 mtime=1740146654.5321827 oslo_reports-3.5.1/oslo_reports/views/xml/0000775000175000017500000000000000000000000020764 5ustar00zuulzuul00000000000000././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1740146607.0 oslo_reports-3.5.1/oslo_reports/views/xml/__init__.py0000664000175000017500000000131100000000000023071 0ustar00zuulzuul00000000000000# Copyright 2013 Red Hat, Inc. # # Licensed under the Apache License, Version 2.0 (the "License"); you may # not use this file except in compliance with the License. You may obtain # a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the # License for the specific language governing permissions and limitations # under the License. """Provides basic XML views This module provides several basic views which serialize models into XML. """ ././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1740146607.0 oslo_reports-3.5.1/oslo_reports/views/xml/generic.py0000664000175000017500000000611500000000000022755 0ustar00zuulzuul00000000000000# Copyright 2013 Red Hat, Inc. # # Licensed under the Apache License, Version 2.0 (the "License"); you may # not use this file except in compliance with the License. You may obtain # a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the # License for the specific language governing permissions and limitations # under the License. """Provides generic XML views This modules defines several basic views for serializing data to XML. Submodels that have already been serialized as XML may have their string values marked with `__is_xml__ = True` using :class:`oslo_reports._utils.StringWithAttrs` (each of the classes within this module does this automatically, and non-naive serializers check for this attribute and handle such strings specially) """ from collections import abc import copy import xml.etree.ElementTree as ET from oslo_reports import _utils as utils class KeyValueView: """A Key-Value XML View This view performs advanced serialization of a data model into XML. It first deserializes any values marked as XML so that they can be properly reserialized later. It then follows the following rules to perform serialization: key : text/xml The tag name is the key name, and the contents are the text or xml key : Sequence A wrapper tag is created with the key name, and each item is placed in an 'item' tag key : Mapping A wrapper tag is created with the key name, and the serialize is called on each key-value pair (such that each key gets its own tag) :param str wrapper_name: the name of the top-level element """ def __init__(self, wrapper_name="model"): self.wrapper_name = wrapper_name def __call__(self, model): # this part deals with subviews that were already serialized cpy = copy.deepcopy(model) for key, valstr in model.items(): if getattr(valstr, '__is_xml__', False): cpy[key] = ET.fromstring(valstr) def serialize(rootmodel, rootkeyname): res = ET.Element(rootkeyname) if isinstance(rootmodel, abc.Mapping): for key in sorted(rootmodel): res.append(serialize(rootmodel[key], key)) elif (isinstance(rootmodel, abc.Sequence) and not isinstance(rootmodel, str)): for val in sorted(rootmodel, key=str): res.append(serialize(val, 'item')) elif ET.iselement(rootmodel): res.append(rootmodel) else: res.text = str(rootmodel) return res str_ = ET.tostring(serialize(cpy, self.wrapper_name), encoding="utf-8").decode("utf-8") res = utils.StringWithAttrs(str_) res.__is_xml__ = True return res ././@PaxHeader0000000000000000000000000000003400000000000011452 xustar000000000000000028 mtime=1740146654.5121772 oslo_reports-3.5.1/releasenotes/0000775000175000017500000000000000000000000016766 5ustar00zuulzuul00000000000000././@PaxHeader0000000000000000000000000000003400000000000011452 xustar000000000000000028 mtime=1740146654.5321827 oslo_reports-3.5.1/releasenotes/notes/0000775000175000017500000000000000000000000020116 5ustar00zuulzuul00000000000000././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1740146607.0 oslo_reports-3.5.1/releasenotes/notes/add-reno-996dd44974d53238.yaml0000664000175000017500000000007200000000000024514 0ustar00zuulzuul00000000000000--- other: - Introduce reno for deployer release notes. ././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1740146607.0 oslo_reports-3.5.1/releasenotes/notes/drop-python27-support-26fad37c3f7a3d28.yaml0000664000175000017500000000017700000000000027454 0ustar00zuulzuul00000000000000--- upgrade: - | Support for Python 2.7 has been dropped. The minimum version of Python now supported is Python 3.6. ././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1740146607.0 oslo_reports-3.5.1/releasenotes/notes/remove-py38-9a3e6702c3d23445.yaml0000664000175000017500000000016600000000000025155 0ustar00zuulzuul00000000000000--- upgrade: - | Support for Python 3.8 has been removed. Now the minimum python version supported is 3.9 . ././@PaxHeader0000000000000000000000000000003400000000000011452 xustar000000000000000028 mtime=1740146654.5361838 oslo_reports-3.5.1/releasenotes/source/0000775000175000017500000000000000000000000020266 5ustar00zuulzuul00000000000000././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1740146607.0 oslo_reports-3.5.1/releasenotes/source/2023.1.rst0000664000175000017500000000021000000000000021536 0ustar00zuulzuul00000000000000=========================== 2023.1 Series Release Notes =========================== .. release-notes:: :branch: unmaintained/2023.1 ././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1740146607.0 oslo_reports-3.5.1/releasenotes/source/2023.2.rst0000664000175000017500000000020200000000000021540 0ustar00zuulzuul00000000000000=========================== 2023.2 Series Release Notes =========================== .. release-notes:: :branch: stable/2023.2 ././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1740146607.0 oslo_reports-3.5.1/releasenotes/source/2024.1.rst0000664000175000017500000000020200000000000021540 0ustar00zuulzuul00000000000000=========================== 2024.1 Series Release Notes =========================== .. release-notes:: :branch: stable/2024.1 ././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1740146607.0 oslo_reports-3.5.1/releasenotes/source/2024.2.rst0000664000175000017500000000020200000000000021541 0ustar00zuulzuul00000000000000=========================== 2024.2 Series Release Notes =========================== .. release-notes:: :branch: stable/2024.2 ././@PaxHeader0000000000000000000000000000003400000000000011452 xustar000000000000000028 mtime=1740146654.5361838 oslo_reports-3.5.1/releasenotes/source/_static/0000775000175000017500000000000000000000000021714 5ustar00zuulzuul00000000000000././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1740146607.0 oslo_reports-3.5.1/releasenotes/source/_static/.placeholder0000664000175000017500000000000000000000000024165 0ustar00zuulzuul00000000000000././@PaxHeader0000000000000000000000000000003400000000000011452 xustar000000000000000028 mtime=1740146654.5361838 oslo_reports-3.5.1/releasenotes/source/_templates/0000775000175000017500000000000000000000000022423 5ustar00zuulzuul00000000000000././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1740146607.0 oslo_reports-3.5.1/releasenotes/source/_templates/.placeholder0000664000175000017500000000000000000000000024674 0ustar00zuulzuul00000000000000././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1740146607.0 oslo_reports-3.5.1/releasenotes/source/conf.py0000664000175000017500000002122500000000000021567 0ustar00zuulzuul00000000000000# Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or # implied. # See the License for the specific language governing permissions and # limitations under the License. # This file is execfile()d with the current directory set to its # containing dir. # # Note that not all possible configuration values are present in this # autogenerated file. # # All configuration values have a default; values that are commented out # serve to show the default. # If extensions (or modules to document with autodoc) are in another directory, # add these directories to sys.path here. If the directory is relative to the # documentation root, use os.path.abspath to make it absolute, like shown here. # sys.path.insert(0, os.path.abspath('.')) # -- General configuration ------------------------------------------------ # If your documentation needs a minimal Sphinx version, state it here. # needs_sphinx = '1.0' # Add any Sphinx extension module names here, as strings. They can be # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom # ones. extensions = [ 'openstackdocstheme', 'reno.sphinxext', ] # openstackdocstheme options openstackdocs_repo_name = 'openstack/oslo.reports' openstackdocs_bug_project = 'oslo.reports' openstackdocs_bug_tag = '' openstackdocs_auto_name = False # Add any paths that contain templates here, relative to this directory. templates_path = ['_templates'] # The suffix of source filenames. source_suffix = '.rst' # The encoding of source files. # source_encoding = 'utf-8-sig' # The master toctree document. master_doc = 'index' # General information about the project. project = 'oslo.reports Release Notes' copyright = '2016, oslo.reports Developers' # Release notes do not need a version in the title, they span # multiple versions. release = '' # The short X.Y version. version = '' # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. # language = None # There are two options for replacing |today|: either, you set today to some # non-false value, then it is used: # today = '' # Else, today_fmt is used as the format for a strftime call. # today_fmt = '%B %d, %Y' # List of patterns, relative to source directory, that match files and # directories to ignore when looking for source files. exclude_patterns = [] # The reST default role (used for this markup: `text`) to use for all # documents. # default_role = None # If true, '()' will be appended to :func: etc. cross-reference text. # add_function_parentheses = True # If true, the current module name will be prepended to all description # unit titles (such as .. function::). # add_module_names = True # If true, sectionauthor and moduleauthor directives will be shown in the # output. They are ignored by default. # show_authors = False # The name of the Pygments (syntax highlighting) style to use. pygments_style = 'native' # A list of ignored prefixes for module index sorting. # modindex_common_prefix = [] # If true, keep warnings as "system message" paragraphs in the built documents. # keep_warnings = False # -- Options for HTML output ---------------------------------------------- # The theme to use for HTML and HTML Help pages. See the documentation for # a list of builtin themes. html_theme = 'openstackdocs' # Theme options are theme-specific and customize the look and feel of a theme # further. For a list of options available for each theme, see the # documentation. # html_theme_options = {} # Add any paths that contain custom themes here, relative to this directory. # html_theme_path = [] # The name for this set of Sphinx documents. If None, it defaults to # " v documentation". # html_title = None # A shorter title for the navigation bar. Default is the same as html_title. # html_short_title = None # The name of an image file (relative to this directory) to place at the top # of the sidebar. # html_logo = None # The name of an image file (within the static path) to use as favicon of the # docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 # pixels large. # html_favicon = None # Add any paths that contain custom static files (such as style sheets) here, # relative to this directory. They are copied after the builtin static files, # so a file named "default.css" will overwrite the builtin "default.css". html_static_path = ['_static'] # Add any extra paths that contain custom files (such as robots.txt or # .htaccess) here, relative to this directory. These files are copied # directly to the root of the documentation. # html_extra_path = [] # If true, SmartyPants will be used to convert quotes and dashes to # typographically correct entities. # html_use_smartypants = True # Custom sidebar templates, maps document names to template names. # html_sidebars = {} # Additional templates that should be rendered to pages, maps page names to # template names. # html_additional_pages = {} # If false, no module index is generated. # html_domain_indices = True # If false, no index is generated. # html_use_index = True # If true, the index is split into individual pages for each letter. # html_split_index = False # If true, links to the reST sources are added to the pages. # html_show_sourcelink = True # If true, "Created using Sphinx" is shown in the HTML footer. Default is True. # html_show_sphinx = True # If true, "(C) Copyright ..." is shown in the HTML footer. Default is True. # html_show_copyright = True # If true, an OpenSearch description file will be output, and all pages will # contain a tag referring to it. The value of this option must be the # base URL from which the finished HTML is served. # html_use_opensearch = '' # This is the file name suffix for HTML files (e.g. ".xhtml"). # html_file_suffix = None # Output file base name for HTML help builder. htmlhelp_basename = 'oslo.reportsReleaseNotesDoc' # -- Options for LaTeX output --------------------------------------------- latex_elements = { # The paper size ('letterpaper' or 'a4paper'). # 'papersize': 'letterpaper', # The font size ('10pt', '11pt' or '12pt'). # 'pointsize': '10pt', # Additional stuff for the LaTeX preamble. # 'preamble': '', } # Grouping the document tree into LaTeX files. List of tuples # (source start file, target name, title, # author, documentclass [howto, manual, or own class]). latex_documents = [ ('index', 'oslo.reportsReleaseNotes.tex', 'oslo.reports Release Notes Documentation', 'oslo.reports Developers', 'manual'), ] # The name of an image file (relative to this directory) to place at the top of # the title page. # latex_logo = None # For "manual" documents, if this is true, then toplevel headings are parts, # not chapters. # latex_use_parts = False # If true, show page references after internal links. # latex_show_pagerefs = False # If true, show URL addresses after external links. # latex_show_urls = False # Documents to append as an appendix to all manuals. # latex_appendices = [] # If false, no module index is generated. # latex_domain_indices = True # -- Options for manual page output --------------------------------------- # One entry per manual page. List of tuples # (source start file, name, description, authors, manual section). man_pages = [ ('index', 'oslo.reportsReleaseNotes', 'oslo.reports Release Notes Documentation', ['oslo.reports Developers'], 1) ] # If true, show URL addresses after external links. # man_show_urls = False # -- Options for Texinfo output ------------------------------------------- # Grouping the document tree into Texinfo files. List of tuples # (source start file, target name, title, author, # dir menu entry, description, category) texinfo_documents = [ ('index', 'oslo.reportsReleaseNotes', 'oslo.reports Release Notes Documentation', 'oslo.reports Developers', 'oslo.reportsReleaseNotes', 'One line description of project.', 'Miscellaneous'), ] # Documents to append as an appendix to all manuals. # texinfo_appendices = [] # If false, no module index is generated. # texinfo_domain_indices = True # How to display URL addresses: 'footnote', 'no', or 'inline'. # texinfo_show_urls = 'footnote' # If true, do not generate a @detailmenu in the "Top" node's menu. # texinfo_no_detailmenu = False # -- Options for Internationalization output ------------------------------ locale_dirs = ['locale/'] ././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1740146607.0 oslo_reports-3.5.1/releasenotes/source/index.rst0000664000175000017500000000036700000000000022135 0ustar00zuulzuul00000000000000============================ oslo.reports Release Notes ============================ .. toctree:: :maxdepth: 1 unreleased 2024.2 2024.1 2023.2 2023.1 victoria ussuri train stein rocky queens pike ocata ././@PaxHeader0000000000000000000000000000003400000000000011452 xustar000000000000000028 mtime=1740146654.5161784 oslo_reports-3.5.1/releasenotes/source/locale/0000775000175000017500000000000000000000000021525 5ustar00zuulzuul00000000000000././@PaxHeader0000000000000000000000000000003400000000000011452 xustar000000000000000028 mtime=1740146654.5161784 oslo_reports-3.5.1/releasenotes/source/locale/en_GB/0000775000175000017500000000000000000000000022477 5ustar00zuulzuul00000000000000././@PaxHeader0000000000000000000000000000003400000000000011452 xustar000000000000000028 mtime=1740146654.5361838 oslo_reports-3.5.1/releasenotes/source/locale/en_GB/LC_MESSAGES/0000775000175000017500000000000000000000000024264 5ustar00zuulzuul00000000000000././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1740146607.0 oslo_reports-3.5.1/releasenotes/source/locale/en_GB/LC_MESSAGES/releasenotes.po0000664000175000017500000000365500000000000027326 0ustar00zuulzuul00000000000000# Andi Chandler , 2017. #zanata # Andi Chandler , 2018. #zanata # Andi Chandler , 2022. #zanata # Andi Chandler , 2023. #zanata msgid "" msgstr "" "Project-Id-Version: oslo.reports Release Notes\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2023-05-05 13:27+0000\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "PO-Revision-Date: 2023-06-21 08:13+0000\n" "Last-Translator: Andi Chandler \n" "Language-Team: English (United Kingdom)\n" "Language: en_GB\n" "X-Generator: Zanata 4.3.3\n" "Plural-Forms: nplurals=2; plural=(n != 1)\n" msgid "1.16.0" msgstr "1.16.0" msgid "2.0.0" msgstr "2.0.0" msgid "2023.1 Series Release Notes" msgstr "2023.1 Series Release Notes" msgid "Introduce reno for deployer release notes." msgstr "Introduce Reno for developer release notes." msgid "Ocata Series Release Notes" msgstr "Ocata Series Release Notes" msgid "Other Notes" msgstr "Other Notes" msgid "Pike Series Release Notes" msgstr "Pike Series Release Notes" msgid "Queens Series Release Notes" msgstr "Queens Series Release Notes" msgid "Rocky Series Release Notes" msgstr "Rocky Series Release Notes" msgid "Stein Series Release Notes" msgstr "Stein Series Release Notes" msgid "" "Support for Python 2.7 has been dropped. The minimum version of Python now " "supported is Python 3.6." msgstr "" "Support for Python 2.7 has been dropped. The minimum version of Python now " "supported is Python 3.6." msgid "Train Series Release Notes" msgstr "Train Series Release Notes" msgid "Unreleased Release Notes" msgstr "Unreleased Release Notes" msgid "Upgrade Notes" msgstr "Upgrade Notes" msgid "Ussuri Series Release Notes" msgstr "Ussuri Series Release Notes" msgid "Victoria Series Release Notes" msgstr "Victoria Series Release Notes" msgid "oslo.reports Release Notes" msgstr "oslo.reports Release Notes" ././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1740146607.0 oslo_reports-3.5.1/releasenotes/source/ocata.rst0000664000175000017500000000023000000000000022102 0ustar00zuulzuul00000000000000=================================== Ocata Series Release Notes =================================== .. release-notes:: :branch: origin/stable/ocata ././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1740146607.0 oslo_reports-3.5.1/releasenotes/source/pike.rst0000664000175000017500000000021700000000000021750 0ustar00zuulzuul00000000000000=================================== Pike Series Release Notes =================================== .. release-notes:: :branch: stable/pike ././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1740146607.0 oslo_reports-3.5.1/releasenotes/source/queens.rst0000664000175000017500000000022300000000000022315 0ustar00zuulzuul00000000000000=================================== Queens Series Release Notes =================================== .. release-notes:: :branch: stable/queens ././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1740146607.0 oslo_reports-3.5.1/releasenotes/source/rocky.rst0000664000175000017500000000022100000000000022142 0ustar00zuulzuul00000000000000=================================== Rocky Series Release Notes =================================== .. release-notes:: :branch: stable/rocky ././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1740146607.0 oslo_reports-3.5.1/releasenotes/source/stein.rst0000664000175000017500000000022100000000000022135 0ustar00zuulzuul00000000000000=================================== Stein Series Release Notes =================================== .. release-notes:: :branch: stable/stein ././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1740146607.0 oslo_reports-3.5.1/releasenotes/source/train.rst0000664000175000017500000000017600000000000022141 0ustar00zuulzuul00000000000000========================== Train Series Release Notes ========================== .. release-notes:: :branch: stable/train ././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1740146607.0 oslo_reports-3.5.1/releasenotes/source/unreleased.rst0000664000175000017500000000014400000000000023146 0ustar00zuulzuul00000000000000========================== Unreleased Release Notes ========================== .. release-notes:: ././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1740146607.0 oslo_reports-3.5.1/releasenotes/source/ussuri.rst0000664000175000017500000000020200000000000022344 0ustar00zuulzuul00000000000000=========================== Ussuri Series Release Notes =========================== .. release-notes:: :branch: stable/ussuri ././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1740146607.0 oslo_reports-3.5.1/releasenotes/source/victoria.rst0000664000175000017500000000022000000000000022632 0ustar00zuulzuul00000000000000============================= Victoria Series Release Notes ============================= .. release-notes:: :branch: unmaintained/victoria ././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1740146607.0 oslo_reports-3.5.1/requirements.txt0000664000175000017500000000067400000000000017570 0ustar00zuulzuul00000000000000# Requirements lower bounds listed here are our best effort to keep them up to # date but we do not test them so no guarantee of having them all correct. If # you find any incorrect lower bounds, let us know or propose a fix. pbr>=2.0.0 # Apache-2.0 Jinja2>=2.10 # BSD License (3 clause) oslo.serialization>=2.18.0 # Apache-2.0 psutil>=3.2.2 # BSD oslo.i18n>=3.15.3 # Apache-2.0 oslo.utils>=3.33.0 # Apache-2.0 oslo.config>=5.1.0 # Apache-2.0 ././@PaxHeader0000000000000000000000000000003300000000000011451 xustar000000000000000027 mtime=1740146654.540185 oslo_reports-3.5.1/setup.cfg0000664000175000017500000000175000000000000016121 0ustar00zuulzuul00000000000000[metadata] name = oslo.reports summary = oslo.reports library description_file = README.rst author = OpenStack author_email = openstack-discuss@lists.openstack.org home_page = https://docs.openstack.org/oslo.reports/latest python_requires = >=3.9 classifier = Environment :: OpenStack Intended Audience :: Information Technology Intended Audience :: System Administrators License :: OSI Approved :: Apache Software License Operating System :: POSIX :: Linux Programming Language :: Python Programming Language :: Python :: 3 Programming Language :: Python :: 3.9 Programming Language :: Python :: 3.10 Programming Language :: Python :: 3.11 Programming Language :: Python :: 3.12 Programming Language :: Python :: 3 :: Only Programming Language :: Python :: Implementation :: CPython [extras] greenlet = greenlet>=0.4.15 # MIT [files] packages = oslo_reports [entry_points] oslo.config.opts = oslo.reports = oslo_reports.opts:list_opts [egg_info] tag_build = tag_date = 0 ././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1740146607.0 oslo_reports-3.5.1/setup.py0000664000175000017500000000127100000000000016010 0ustar00zuulzuul00000000000000# Copyright (c) 2013 Hewlett-Packard Development Company, L.P. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or # implied. # See the License for the specific language governing permissions and # limitations under the License. import setuptools setuptools.setup( setup_requires=['pbr>=2.0.0'], pbr=True) ././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1740146607.0 oslo_reports-3.5.1/test-requirements.txt0000664000175000017500000000021100000000000020530 0ustar00zuulzuul00000000000000oslotest>=3.2.0 # Apache-2.0 stestr>=2.0.0 # Apache-2.0 # for testing optional parts greenlet>=0.4.15 # MIT coverage>=4.0 # Apache-2.0 ././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1740146607.0 oslo_reports-3.5.1/tox.ini0000664000175000017500000000273600000000000015620 0ustar00zuulzuul00000000000000[tox] minversion = 3.18.0 envlist = py3,pep8 ignore_basepython_conflict = true [testenv] basepython = python3 deps = -c{env:TOX_CONSTRAINTS_FILE:https://releases.openstack.org/constraints/upper/master} -r{toxinidir}/test-requirements.txt -r{toxinidir}/requirements.txt commands = stestr run --slowest {posargs} [testenv:pep8] skip_install = true deps = pre-commit commands = pre-commit run -a [testenv:venv] commands = {posargs} [testenv:docs] allowlist_externals = rm deps = {[testenv]deps} -r{toxinidir}/doc/requirements.txt commands = rm -rf doc/build doc/source/reference/api sphinx-build -W --keep-going -b html doc/source doc/build/html [testenv:cover] setenv = PYTHON=coverage run --source oslo_reports --parallel-mode commands = coverage erase stestr run {posargs} coverage combine coverage html -d cover coverage xml -o cover/coverage.xml coverage report --show-missing [flake8] # E123, E125 skipped as they are invalid PEP-8. # W504 line break after binary operator show-source = True ignore = E123,E125,W504 builtins = _ exclude=.venv,.git,.tox,dist,doc,*lib/python*,*egg,build [hacking] import_exceptions = [testenv:releasenotes] allowlist_externals = rm deps = -c{env:TOX_CONSTRAINTS_FILE:https://releases.openstack.org/constraints/upper/master} -r{toxinidir}/doc/requirements.txt commands = rm -rf releasenotes/build sphinx-build -a -E -W -d releasenotes/build/doctrees --keep-going -b html releasenotes/source releasenotes/build/html