diff --git a/.coveragerc b/.coveragerc deleted file mode 100644 index f60e8fa..0000000 --- a/.coveragerc +++ /dev/null @@ -1,8 +0,0 @@ -[run] -branch = True -source = oslo_reports -omit = oslo_reports/tests/* - -[report] -ignore_errors = True -precision = 2 diff --git a/.gitignore b/.gitignore deleted file mode 100644 index 5fc5a62..0000000 --- a/.gitignore +++ /dev/null @@ -1,54 +0,0 @@ -*.py[cod] - -# C extensions -*.so - -# Packages -*.egg -*.eggs -*.egg-info -dist -build -eggs -parts -bin -var -sdist -develop-eggs -.installed.cfg -lib -lib64 - -# Installer logs -pip-log.txt - -# Unit test / coverage reports -.coverage -cover -.tox -nosetests.xml -.testrepository - -# Translations -*.mo - -# Mr Developer -.mr.developer.cfg -.project -.pydevproject - -# Complexity -output/*.html -output/*/index.html - -# Sphinx -doc/build - -# pbr generates these -AUTHORS -ChangeLog -/doc/source/api/ - -# Editors -*~ -.*.swp diff --git a/.gitreview b/.gitreview deleted file mode 100644 index 504e72f..0000000 --- a/.gitreview +++ /dev/null @@ -1,4 +0,0 @@ -[gerrit] -host=review.openstack.org -port=29418 -project=openstack/oslo.reports.git diff --git a/.mailmap b/.mailmap deleted file mode 100644 index 516ae6f..0000000 --- a/.mailmap +++ /dev/null @@ -1,3 +0,0 @@ -# Format is: -# -# diff --git a/.testr.conf b/.testr.conf deleted file mode 100644 index bafdfe5..0000000 --- a/.testr.conf +++ /dev/null @@ -1,7 +0,0 @@ -[DEFAULT] -test_command=OS_STDOUT_CAPTURE=${OS_STDOUT_CAPTURE:-1} \ - OS_STDERR_CAPTURE=${OS_STDERR_CAPTURE:-1} \ - OS_TEST_TIMEOUT=${OS_TEST_TIMEOUT:-60} \ - ${PYTHON:-python} -m subunit.run discover -t ./ ./oslo_reports $LISTOPT $IDOPTION -test_id_option=--load-list $IDFILE -test_list_option=--list diff --git a/CONTRIBUTING.rst b/CONTRIBUTING.rst deleted file mode 100644 index 044fc64..0000000 --- a/CONTRIBUTING.rst +++ /dev/null @@ -1,17 +0,0 @@ -If you would like to contribute to the development of OpenStack, you must -follow the steps in this page: - - http://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: - - http://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 diff --git a/HACKING.rst b/HACKING.rst deleted file mode 100644 index 9ddcced..0000000 --- a/HACKING.rst +++ /dev/null @@ -1,4 +0,0 @@ -oslo.reports Style Commandments -====================================================== - -Read the OpenStack Style Commandments http://docs.openstack.org/developer/hacking/ diff --git a/LICENSE b/LICENSE deleted file mode 100644 index 68c771a..0000000 --- a/LICENSE +++ /dev/null @@ -1,176 +0,0 @@ - - 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. - diff --git a/README.rst b/README.rst deleted file mode 100644 index 856e38e..0000000 --- a/README.rst +++ /dev/null @@ -1,51 +0,0 @@ -=================================== -oslo.reports -=================================== - -.. image:: https://img.shields.io/pypi/v/oslo.reports.svg - :target: https://pypi.python.org/pypi/oslo.reports/ - :alt: Latest Version - -.. image:: https://img.shields.io/pypi/dm/oslo.reports.svg - :target: https://pypi.python.org/pypi/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: http://docs.openstack.org/developer/oslo.reports -* Source: http://git.openstack.org/cgit/openstack/oslo.reports -* Bugs: http://bugs.launchpad.net/oslo.reports diff --git a/README.txt b/README.txt new file mode 100644 index 0000000..bba33a6 --- /dev/null +++ b/README.txt @@ -0,0 +1,13 @@ +This project is no longer maintained. + +The contents of this repository are still available in the Git +source code management system. To see the contents of this +repository before it reached its end of life, please check out the +previous commit with "git checkout HEAD^1". + +Use instead the project deb-python-oslo.reports at +http://git.openstack.org/cgit/openstack/deb-python-oslo.reports . + +For any further questions, please email +openstack-dev@lists.openstack.org or join #openstack-dev on +Freenode. diff --git a/babel.cfg b/babel.cfg deleted file mode 100644 index 15cd6cb..0000000 --- a/babel.cfg +++ /dev/null @@ -1,2 +0,0 @@ -[python: **.py] - diff --git a/doc/source/conf.py b/doc/source/conf.py deleted file mode 100755 index 49987f2..0000000 --- a/doc/source/conf.py +++ /dev/null @@ -1,79 +0,0 @@ -# -*- coding: utf-8 -*- -# 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 os -import sys - -sys.path.insert(0, os.path.abspath('../..')) -# -- 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', - #'sphinx.ext.intersphinx', - 'oslosphinx', - 'oslo_config.sphinxext', -] - -# autodoc generation is a bit aggressive and a nuisance when doing heavy -# text edit cycles. -# execute "export SPHINX_DEBUG=1" in your terminal to disable - -# The suffix of source filenames. -source_suffix = '.rst' - -# The master toctree document. -master_doc = 'index' - -# General information about the project. -project = u'oslo.reports' -copyright = u'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 = 'sphinx' - -# A list of ignored prefixes for module index sorting. -modindex_common_prefix = ['oslo_reports.'] - -# -- Options for HTML output -------------------------------------------------- - -# The theme to use for HTML and HTML Help pages. Major themes that come with -# Sphinx are currently 'default' and 'sphinxdoc'. -# html_theme_path = ["."] -# html_theme = '_theme' -# html_static_path = ['static'] - -# Output file base name for HTML help builder. -htmlhelp_basename = '%sdoc' % project - -# Grouping the document tree into LaTeX files. List of tuples -# (source start file, target name, title, author, documentclass -# [howto/manual]). -latex_documents = [ - ('index', - '%s.tex' % project, - u'%s Documentation' % project, - u'OpenStack Foundation', 'manual'), -] - -# Example configuration for intersphinx: refer to the Python standard library. -#intersphinx_mapping = {'http://docs.python.org/': None} diff --git a/doc/source/contributing.rst b/doc/source/contributing.rst deleted file mode 100644 index 2ca75d1..0000000 --- a/doc/source/contributing.rst +++ /dev/null @@ -1,5 +0,0 @@ -============== - Contributing -============== - -.. include:: ../../CONTRIBUTING.rst diff --git a/doc/source/history.rst b/doc/source/history.rst deleted file mode 100644 index 69ed4fe..0000000 --- a/doc/source/history.rst +++ /dev/null @@ -1 +0,0 @@ -.. include:: ../../ChangeLog diff --git a/doc/source/index.rst b/doc/source/index.rst deleted file mode 100644 index a5e66c3..0000000 --- a/doc/source/index.rst +++ /dev/null @@ -1,40 +0,0 @@ -============== - oslo.reports -============== - -oslo.reports library - -Contents -======== - -.. toctree:: - :maxdepth: 2 - - installation - usage - opts - contributing - -API -=== - -.. toctree:: - :maxdepth: 2 - - api/autoindex - -Release Notes -============= - -.. toctree:: - :maxdepth: 1 - - history - -Indices and tables -================== - -* :ref:`genindex` -* :ref:`modindex` -* :ref:`search` - diff --git a/doc/source/installation.rst b/doc/source/installation.rst deleted file mode 100644 index 042f75c..0000000 --- a/doc/source/installation.rst +++ /dev/null @@ -1,7 +0,0 @@ -============== - Installation -============== - -At the command line:: - - $ pip install oslo.reports diff --git a/doc/source/opts.rst b/doc/source/opts.rst deleted file mode 100644 index 205e30d..0000000 --- a/doc/source/opts.rst +++ /dev/null @@ -1,8 +0,0 @@ -======================= - 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 diff --git a/doc/source/report.txt b/doc/source/report.txt deleted file mode 100644 index 8f3c446..0000000 --- a/doc/source/report.txt +++ /dev/null @@ -1,755 +0,0 @@ -======================================================================== -==== 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 - multi_instance_display_name_template = %(name)s-%(count)d - 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 - auth_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 \ No newline at end of file diff --git a/doc/source/usage.rst b/doc/source/usage.rst deleted file mode 100644 index b1c1790..0000000 --- a/doc/source/usage.rst +++ /dev/null @@ -1,35 +0,0 @@ -======= - 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 - - -Here is a sample report: - -.. include:: report.txt - :literal: diff --git a/oslo_reports/__init__.py b/oslo_reports/__init__.py deleted file mode 100644 index 100171b..0000000 --- a/oslo_reports/__init__.py +++ /dev/null @@ -1,25 +0,0 @@ -# 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. -""" diff --git a/oslo_reports/_i18n.py b/oslo_reports/_i18n.py deleted file mode 100644 index 8db1970..0000000 --- a/oslo_reports/_i18n.py +++ /dev/null @@ -1,35 +0,0 @@ -# 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 http://docs.openstack.org/developer/oslo.i18n/usage.html . - -""" - -import oslo_i18n - - -_translators = oslo_i18n.TranslatorFactory(domain='oslo_reports') - -# The primary translation function using the well-known name "_" -_ = _translators.primary - -# Translators for log levels. -# -# The abbreviated names are meant to reflect the usual use of a short -# name like '_'. The "L" is for "log" and the other letter comes from -# the level. -_LI = _translators.log_info -_LW = _translators.log_warning -_LE = _translators.log_error -_LC = _translators.log_critical diff --git a/oslo_reports/_utils.py b/oslo_reports/_utils.py deleted file mode 100644 index 149aef7..0000000 --- a/oslo_reports/_utils.py +++ /dev/null @@ -1,27 +0,0 @@ -# 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. -""" - -import six - - -class StringWithAttrs(six.text_type): - """A String that can have arbitrary attributes""" - - pass diff --git a/oslo_reports/generators/__init__.py b/oslo_reports/generators/__init__.py deleted file mode 100644 index 4daf75e..0000000 --- a/oslo_reports/generators/__init__.py +++ /dev/null @@ -1,21 +0,0 @@ -# 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. -""" diff --git a/oslo_reports/generators/conf.py b/oslo_reports/generators/conf.py deleted file mode 100644 index cdb8c43..0000000 --- a/oslo_reports/generators/conf.py +++ /dev/null @@ -1,44 +0,0 @@ -# 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(object): - """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) diff --git a/oslo_reports/generators/process.py b/oslo_reports/generators/process.py deleted file mode 100644 index 2749ff2..0000000 --- a/oslo_reports/generators/process.py +++ /dev/null @@ -1,38 +0,0 @@ -# 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(object): - """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())) diff --git a/oslo_reports/generators/threading.py b/oslo_reports/generators/threading.py deleted file mode 100644 index 9d68f90..0000000 --- a/oslo_reports/generators/threading.py +++ /dev/null @@ -1,104 +0,0 @@ -# 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`. -""" - -from __future__ import absolute_import - -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(object): - """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 = dict( - (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(object): - """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()) diff --git a/oslo_reports/generators/version.py b/oslo_reports/generators/version.py deleted file mode 100644 index 97f6e4f..0000000 --- a/oslo_reports/generators/version.py +++ /dev/null @@ -1,60 +0,0 @@ -# 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(object): - """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) diff --git a/oslo_reports/guru_meditation_report.py b/oslo_reports/guru_meditation_report.py deleted file mode 100644 index 3ff497d..0000000 --- a/oslo_reports/guru_meditation_report.py +++ /dev/null @@ -1,299 +0,0 @@ -# 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. -""" - -from __future__ import print_function - -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._i18n import _LE -from oslo_reports._i18n import _LW -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 - - -LOG = logging.getLogger(__name__) - - -class GuruMeditation(object): - """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(GuruMeditation, self).__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): - """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. - """ - - if log_dir is None and conf is not None: - log_dir = conf.oslo_reports.log_dir - - if signum: - 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 hasattr(signal, 'SIGUSR1'): - # TODO(dims) We need to remove this in the "O" release cycle - LOG.warning(_LW("Guru meditation now registers SIGUSR1 and " - "SIGUSR2 by default for backward " - "compatibility. SIGUSR1 will no longer be " - "registered in a future release, so please " - "use SIGUSR2 to generate reports.")) - cls._setup_signal(signal.SIGUSR1, - version, service_name, log_dir) - if 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(_LE("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 " + - "'{0}' file".format(filepath)) - raise IOError(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 = "%s_gurumeditation_%s" % ( - 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)) - - 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(GuruMeditation, self).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(TextGuruMeditation, self).__init__(version_obj, traceback, - 'Guru Meditation') diff --git a/oslo_reports/locale/en_GB/LC_MESSAGES/oslo_reports.po b/oslo_reports/locale/en_GB/LC_MESSAGES/oslo_reports.po deleted file mode 100644 index d4a0452..0000000 --- a/oslo_reports/locale/en_GB/LC_MESSAGES/oslo_reports.po +++ /dev/null @@ -1,18 +0,0 @@ -# Andi Chandler , 2016. #zanata -msgid "" -msgstr "" -"Project-Id-Version: oslo.reports 1.9.1.dev1\n" -"Report-Msgid-Bugs-To: https://bugs.launchpad.net/openstack-i18n/\n" -"POT-Creation-Date: 2016-06-10 16:23+0000\n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: 8bit\n" -"PO-Revision-Date: 2016-06-09 11:13+0000\n" -"Last-Translator: Andi Chandler \n" -"Language-Team: English (United Kingdom)\n" -"Language: en-GB\n" -"X-Generator: Zanata 3.7.3\n" -"Plural-Forms: nplurals=2; plural=(n != 1)\n" - -msgid "Path to a log directory where to create a file" -msgstr "Path to a log directory where to create a file" diff --git a/oslo_reports/models/__init__.py b/oslo_reports/models/__init__.py deleted file mode 100644 index 7bfed3d..0000000 --- a/oslo_reports/models/__init__.py +++ /dev/null @@ -1,20 +0,0 @@ -# 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. -""" diff --git a/oslo_reports/models/base.py b/oslo_reports/models/base.py deleted file mode 100644 index 5c121d0..0000000 --- a/oslo_reports/models/base.py +++ /dev/null @@ -1,162 +0,0 @@ -# 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. -""" - -import collections as col -import copy - -import six - - -class ReportModel(col.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, col.Mapping): - self.data = dict(data) - elif isinstance(data, col.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] = six.text_type(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, six.string_types): - return - - visited.add(oid) - - if hasattr(obj, 'set_current_view_type'): - obj.set_current_view_type(tp, visited=visited) - - if isinstance(obj, col.Sequence): - for item in obj: - traverse_obj(item) - - elif isinstance(obj, col.Mapping): - for val in six.itervalues(obj): - traverse_obj(val) - - traverse_obj(self) diff --git a/oslo_reports/models/conf.py b/oslo_reports/models/conf.py deleted file mode 100644 index e56a5cd..0000000 --- a/oslo_reports/models/conf.py +++ /dev/null @@ -1,66 +0,0 @@ -# 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(ConfigModel, self).__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'] = dict( - (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 = dict( - (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) diff --git a/oslo_reports/models/process.py b/oslo_reports/models/process.py deleted file mode 100644 index 40af0a1..0000000 --- a/oslo_reports/models/process.py +++ /dev/null @@ -1,73 +0,0 @@ -# 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 psutil - -import oslo_reports.models.with_default_views as mwdv -import oslo_reports.views.text.process as text_views - -PS1 = psutil.version_info[0] == 1 - - -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(ProcessModel, self).__init__( - text_view=text_views.ProcessView()) - - self['pid'] = process.pid - self['parent_pid'] = (process.ppid if PS1 else process.ppid()) - if hasattr(process, 'uids'): - self['uids'] = { - 'real': (process.uids.real if PS1 else process.uids().real), - 'effective': (process.uids.effective if PS1 - else process.uids().effective), - 'saved': (process.uids.saved if PS1 else process.uids().saved) - } - else: - self['uids'] = {'real': None, - 'effective': None, - 'saved': None} - - if hasattr(process, 'gids'): - self['gids'] = { - 'real': (process.gids.real if PS1 else process.gids().real), - 'effective': (process.gids.effective if PS1 - else process.gids().effective), - 'saved': (process.gids.saved if PS1 else process.gids().saved) - } - else: - self['gids'] = {'real': None, - 'effective': None, - 'saved': None} - - self['username'] = process.username if PS1 else process.username() - self['command'] = process.cmdline if PS1 else process.cmdline() - self['state'] = process.status if PS1 else process.status() - - children = process.get_children() if PS1 else process.children() - self['children'] = [ProcessModel(pr) for pr in children] diff --git a/oslo_reports/models/threading.py b/oslo_reports/models/threading.py deleted file mode 100644 index 5caca3c..0000000 --- a/oslo_reports/models/threading.py +++ /dev/null @@ -1,100 +0,0 @@ -# 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(StackTraceModel, self).__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(ThreadModel, self).__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(GreenThreadModel, self).__init__( - {'stack_trace': StackTraceModel(stack)}, - text_view=text_views.GreenThreadView()) diff --git a/oslo_reports/models/version.py b/oslo_reports/models/version.py deleted file mode 100644 index 50d2f6c..0000000 --- a/oslo_reports/models/version.py +++ /dev/null @@ -1,44 +0,0 @@ -# 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(PackageModel, self).__init__( - text_view=generic_text_views.KeyValueView() - ) - - self['vendor'] = vendor - self['product'] = product - self['version'] = version diff --git a/oslo_reports/models/with_default_views.py b/oslo_reports/models/with_default_views.py deleted file mode 100644 index cce9d88..0000000 --- a/oslo_reports/models/with_default_views.py +++ /dev/null @@ -1,81 +0,0 @@ -# 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(ModelWithDefaultViews, self).__init__(*args, **newargs) - - def set_current_view_type(self, tp, visited=None): - self.attached_view = self.views[tp] - super(ModelWithDefaultViews, self).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(ModelWithDefaultViews, self).__getattr__(attrname) diff --git a/oslo_reports/opts.py b/oslo_reports/opts.py deleted file mode 100644 index 324b7f1..0000000 --- a/oslo_reports/opts.py +++ /dev/null @@ -1,71 +0,0 @@ -# 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. - -__all__ = [ - 'list_opts', - 'set_defaults', -] - -import copy - -from oslo_config import cfg - -from oslo_reports._i18n import _ - - -_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) diff --git a/oslo_reports/report.py b/oslo_reports/report.py deleted file mode 100644 index fa8c07b..0000000 --- a/oslo_reports/report.py +++ /dev/null @@ -1,189 +0,0 @@ -# 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. -""" - -import six - -from oslo_reports.views.text import header as header_views - - -class BasicReport(object): - """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(six.text_type(sect) for sect in self.sections) - - -class ReportSection(object): - """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(ReportOfType, self).__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(ReportOfType, self).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(TextReport, self).__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(TextReport, self).add_section(header_views.TitledView(heading), - generator, - index) diff --git a/oslo_reports/tests/__init__.py b/oslo_reports/tests/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/oslo_reports/tests/test_base_report.py b/oslo_reports/tests/test_base_report.py deleted file mode 100644 index 7097a24..0000000 --- a/oslo_reports/tests/test_base_report.py +++ /dev/null @@ -1,144 +0,0 @@ -# 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 collections as col -import re - -from oslotest import base -import six - -from oslo_reports.models import base as base_model -from oslo_reports import report - - -class BasicView(object): - def __call__(self, model): - res = "" - for k in sorted(model.keys()): - res += six.text_type(k) + ": " + six.text_type(model[k]) + ";" - return res - - -def basic_generator(): - return base_model.ReportModel(data={'string': 'value', 'int': 1}) - - -class TestBasicReport(base.BaseTestCase): - def setUp(self): - super(TestBasicReport, self).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(object): - def __call__(self, model): - return '{len: ' + six.text_type(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', - six.text_type, model) - - def test_str_returns_string_with_attached_view(self): - model = base_model.ReportModel(data={'a': 1, 'b': 2}, - attached_view=BasicView()) - - self.assertEqual(six.text_type(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;', six.text_type(model)) - - def test_immutable_mappings_produce_mutable_models(self): - class SomeImmutableMapping(col.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;', six.text_type(model)) - - model['d'] = 16 - - self.assertEqual('a: 2;b: 4;c: 8;d: 16;', six.text_type(model)) - self.assertEqual({'a': 2, 'b': 4, 'c': 8}, mp.data) diff --git a/oslo_reports/tests/test_guru_meditation_report.py b/oslo_reports/tests/test_guru_meditation_report.py deleted file mode 100644 index b86bcf3..0000000 --- a/oslo_reports/tests/test_guru_meditation_report.py +++ /dev/null @@ -1,249 +0,0 @@ -# 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 __future__ import print_function - -import datetime -import os -import re -import signal -import sys -import threading - -# needed to get greenthreads -import fixtures -import greenlet -import mock -from oslotest import base -import six - -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(object): - 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(GmrConfigFixture, self).setUp() - - self.conf.set_override( - 'file_event_handler', - '/tmp/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(TestGuruMeditationReport, self).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("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 = six.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( - '/tmp/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('/tmp/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 = six.StringIO() - - os.kill(os.getpid(), signal.SIGUSR2) - self.assertIn('RunFail', sys.stderr.getvalue()) - - def tearDown(self): - super(TestGuruMeditationReport, self).tearDown() - if self.old_stderr is not None: - sys.stderr = self.old_stderr diff --git a/oslo_reports/tests/test_openstack_generators.py b/oslo_reports/tests/test_openstack_generators.py deleted file mode 100644 index f5b1cda..0000000 --- a/oslo_reports/tests/test_openstack_generators.py +++ /dev/null @@ -1,141 +0,0 @@ -# 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 - -import greenlet -import mock -from oslo_config import cfg -from oslotest import base -import six - -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(six.text_type(model)) - - def test_thread_generator_tb(self): - class FakeModel(object): - 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(six.text_type(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') - - target_str = ('\ncheese: \n' - ' from_cow = True\n' - ' group_secrets = ***\n' - ' name = cheddar\n' - ' sharpness = 1\n' - '\n' - 'default: \n' - ' crackers = triscuit\n' - ' secrets = ***') - self.assertEqual(target_str, six.text_type(model)) - - def test_package_report_generator(self): - class VersionObj(object): - 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, six.text_type(model)) - - def test_package_report_generator_without_vendor_string(self): - class VersionObj(object): - 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, six.text_type(model)) diff --git a/oslo_reports/tests/test_views.py b/oslo_reports/tests/test_views.py deleted file mode 100644 index 7161ef9..0000000 --- a/oslo_reports/tests/test_views.py +++ /dev/null @@ -1,426 +0,0 @@ -# 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 - -import mock -from oslotest import base -import six - -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', six.text_type(model)) - - model.set_current_view_type('json') - self.assertEqual('{"int": 1, "string": "value"}', six.text_type(model)) - - model.set_current_view_type('xml') - - self.assertEqual('1value', - six.text_type(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: six.text_type(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(TestGenericXMLView, self).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, six.text_type(self.model)) - - def test_list_serialization(self): - self.model['lt'] = ['a', 'b'] - - target_str = ('' - '1' - 'ab' - 'value') - self.assertEqual(target_str, six.text_type(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, six.text_type(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, six.text_type(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, six.text_type(self.model)) - - def test_wrapper_name(self): - self.model.attached_view.wrapper_name = 'cheese' - - target_str = ('' - '1' - 'value' - '') - self.assertEqual(target_str, six.text_type(self.model)) - - -class TestGenericJSONViews(base.BaseTestCase): - def setUp(self): - super(TestGenericJSONViews, self).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"}', - six.text_type(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, six.text_type(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, six.text_type(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, six.text_type(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, six.text_type(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, six.text_type(self.model)) - - -class TestGenericTextViews(base.BaseTestCase): - def setUp(self): - super(TestGenericTextViews, self).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, six.text_type(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', - six.text_type(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, six.text_type(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, six.text_type(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, six.text_type(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, six.text_type(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, six.text_type(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, six.text_type(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, six.text_type(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(TestJinjaView, self).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', - six.text_type(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', - six.text_type(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', - six.text_type(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) diff --git a/oslo_reports/views/__init__.py b/oslo_reports/views/__init__.py deleted file mode 100644 index 612959b..0000000 --- a/oslo_reports/views/__init__.py +++ /dev/null @@ -1,22 +0,0 @@ -# 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. -""" diff --git a/oslo_reports/views/jinja_view.py b/oslo_reports/views/jinja_view.py deleted file mode 100644 index 5f57dc3..0000000 --- a/oslo_reports/views/jinja_view.py +++ /dev/null @@ -1,137 +0,0 @@ -# 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(object): - """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, 'r') 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 retrived via attr:`template` . - - :param str textval: the new text of the Jinja template - """ - - self._text = textval - self.regentemplate = True - - text = property(_gettext, _settext) diff --git a/oslo_reports/views/json/__init__.py b/oslo_reports/views/json/__init__.py deleted file mode 100644 index 47bd33b..0000000 --- a/oslo_reports/views/json/__init__.py +++ /dev/null @@ -1,19 +0,0 @@ -# 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. -""" diff --git a/oslo_reports/views/json/generic.py b/oslo_reports/views/json/generic.py deleted file mode 100644 index 5580ba1..0000000 --- a/oslo_reports/views/json/generic.py +++ /dev/null @@ -1,66 +0,0 @@ -# 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(object): - """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(object): - """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 diff --git a/oslo_reports/views/text/__init__.py b/oslo_reports/views/text/__init__.py deleted file mode 100644 index c097484..0000000 --- a/oslo_reports/views/text/__init__.py +++ /dev/null @@ -1,19 +0,0 @@ -# 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. -""" diff --git a/oslo_reports/views/text/generic.py b/oslo_reports/views/text/generic.py deleted file mode 100644 index 5240a87..0000000 --- a/oslo_reports/views/text/generic.py +++ /dev/null @@ -1,203 +0,0 @@ -# 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. -""" - -import collections as col - -import six - - -class MultiView(object): - """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([six.text_type(model[key]) for key in model]) - return "\n".join(res) - - -class BasicKeyValueView(object): - """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(object): - """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) + rootkey) - - if isinstance(root, col.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): - res.extend(serialize(root[key], key, indent + 1)) - elif (isinstance(root, col.Sequence) and - not isinstance(root, six.string_types)): - 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 = six.text_type(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(object): - """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 = [six.text_type(raw_row[prop_name]) - for prop_name in self.column_values] - # double format is in case we have roundoff error - res += '{0: <72}\n'.format(self.row_fmt_str.format(cv=row)) - - return res diff --git a/oslo_reports/views/text/header.py b/oslo_reports/views/text/header.py deleted file mode 100644 index 30d3700..0000000 --- a/oslo_reports/views/text/header.py +++ /dev/null @@ -1,53 +0,0 @@ -# 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 -""" - -import six - - -class HeaderView(object): - """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 six.text_type(self.header) + "\n" + six.text_type(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(TitledView, self).__init__(self.FORMAT_STR.format(title)) diff --git a/oslo_reports/views/text/process.py b/oslo_reports/views/text/process.py deleted file mode 100644 index 26572bb..0000000 --- a/oslo_reports/views/text/process.py +++ /dev/null @@ -1,38 +0,0 @@ -# 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 %}" - ) diff --git a/oslo_reports/views/text/threading.py b/oslo_reports/views/text/threading.py deleted file mode 100644 index 5b84f30..0000000 --- a/oslo_reports/views/text/threading.py +++ /dev/null @@ -1,80 +0,0 @@ -# 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(object): - """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(object): - """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 #{0} ".format(model.thread_id), - stack_trace=model.stack_trace - ) diff --git a/oslo_reports/views/xml/__init__.py b/oslo_reports/views/xml/__init__.py deleted file mode 100644 index a40fec9..0000000 --- a/oslo_reports/views/xml/__init__.py +++ /dev/null @@ -1,19 +0,0 @@ -# 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. -""" diff --git a/oslo_reports/views/xml/generic.py b/oslo_reports/views/xml/generic.py deleted file mode 100644 index 21cac78..0000000 --- a/oslo_reports/views/xml/generic.py +++ /dev/null @@ -1,87 +0,0 @@ -# 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) -""" - -import collections as col -import copy -import xml.etree.ElementTree as ET - -import six - -from oslo_reports import _utils as utils - - -class KeyValueView(object): - """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, col.Mapping): - for key in sorted(rootmodel): - res.append(serialize(rootmodel[key], key)) - elif (isinstance(rootmodel, col.Sequence) - and not isinstance(rootmodel, six.string_types)): - for val in sorted(rootmodel, key=str): - res.append(serialize(val, 'item')) - elif ET.iselement(rootmodel): - res.append(rootmodel) - else: - res.text = six.text_type(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 diff --git a/requirements.txt b/requirements.txt deleted file mode 100644 index 56641ec..0000000 --- a/requirements.txt +++ /dev/null @@ -1,11 +0,0 @@ -# The order of packages is significant, because pip processes them in the order -# of appearance. Changing the order has an impact on the overall integration -# process, which may cause wedges in the gate later. - -pbr>=1.6 # Apache-2.0 -Jinja2>=2.8 # BSD License (3 clause) -oslo.serialization>=1.10.0 # Apache-2.0 -psutil<2.0.0,>=1.1.1 # BSD -six>=1.9.0 # MIT -oslo.i18n>=2.1.0 # Apache-2.0 -oslo.utils>=3.16.0 # Apache-2.0 diff --git a/setup.cfg b/setup.cfg deleted file mode 100644 index a37e5db..0000000 --- a/setup.cfg +++ /dev/null @@ -1,61 +0,0 @@ -[metadata] -name = oslo.reports -summary = oslo.reports library -description-file = - README.rst -author = OpenStack -author-email = openstack-dev@lists.openstack.org -home-page = http://launchpad.net/oslo -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 :: 2 - Programming Language :: Python :: 2.7 - Programming Language :: Python :: 3 - Programming Language :: Python :: 3.4 - Programming Language :: Python :: 3.5 - -[files] -packages = - oslo_reports - -[pbr] -warnerrors = true -autodoc_index_modules = true -autodoc_exclude_modules = - oslo_reports._i18n - oslo_reports._utils - oslo_reports.tests.* - -[entry_points] -oslo.config.opts = - oslo.reports = oslo_reports.opts:list_opts - -[build_sphinx] -source-dir = doc/source -build-dir = doc/build -all_files = 1 - -[upload_sphinx] -upload-dir = doc/build/html - -[compile_catalog] -directory = oslo_reports/locale -domain = oslo_reports - -[update_catalog] -domain = oslo_reports -output_dir = oslo_reports/locale -input_file = oslo_reports/locale/oslo_reports.pot - -[extract_messages] -keywords = _ gettext ngettext l_ lazy_gettext -mapping_file = babel.cfg -output_file = oslo_reports/locale/oslo_reports.pot - -[wheel] -universal = true diff --git a/setup.py b/setup.py deleted file mode 100644 index 782bb21..0000000 --- a/setup.py +++ /dev/null @@ -1,29 +0,0 @@ -# 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. - -# THIS FILE IS MANAGED BY THE GLOBAL REQUIREMENTS REPO - DO NOT EDIT -import setuptools - -# In python < 2.7.4, a lazy loading of package `pbr` will break -# setuptools if some other modules registered functions in `atexit`. -# solution from: http://bugs.python.org/issue15881#msg170215 -try: - import multiprocessing # noqa -except ImportError: - pass - -setuptools.setup( - setup_requires=['pbr>=1.8'], - pbr=True) diff --git a/test-requirements.txt b/test-requirements.txt deleted file mode 100644 index a27784d..0000000 --- a/test-requirements.txt +++ /dev/null @@ -1,17 +0,0 @@ -# The order of packages is significant, because pip processes them in the order -# of appearance. Changing the order has an impact on the overall integration -# process, which may cause wedges in the gate later. - -hacking<0.11,>=0.10.0 -oslotest>=1.10.0 # Apache-2.0 - -# These are needed for docs generation -oslosphinx!=3.4.0,>=2.5.0 # Apache-2.0 -sphinx!=1.3b1,<1.3,>=1.2.1 # BSD - -# for testing optional parts -oslo.config>=3.14.0 # Apache-2.0 -eventlet!=0.18.3,>=0.18.2 # MIT -greenlet>=0.3.2 # MIT - -coverage>=3.6 # Apache-2.0 diff --git a/tox.ini b/tox.ini deleted file mode 100644 index 83c6ced..0000000 --- a/tox.ini +++ /dev/null @@ -1,38 +0,0 @@ -[tox] -minversion = 1.6 -envlist = py35,py34,py27,pypy,pep8 - -[testenv] -deps = -r{toxinidir}/test-requirements.txt -commands = python setup.py testr --slowest --testr-args='{posargs}' - -[testenv:pep8] -commands = flake8 - -[testenv:venv] -commands = {posargs} - -[testenv:docs] -commands = python setup.py build_sphinx - -[testenv:cover] -commands = python setup.py test --coverage --coverage-package-name=oslo_reports --testr-args='{posargs}' - -[flake8] -# E123, E125 skipped as they are invalid PEP-8. - -show-source = True -ignore = E123,E125 -builtins = _ -exclude=.venv,.git,.tox,dist,doc,*lib/python*,*egg,build - -[hacking] -import_exceptions = - -[testenv:pip-missing-reqs] -# do not install test-requirements as that will pollute the virtualenv for -# determining missing packages -# this also means that pip-missing-reqs must be installed separately, outside -# of the requirements.txt files -deps = pip_missing_reqs -commands = pip-missing-reqs -d --ignore-module=oslo_reports* --ignore-module=pkg_resources --ignore-file=oslo_reports/test.py --ignore-file=oslo_reports/tests/* oslo_reports