├── .coveragerc
├── .gitignore
├── .gitreview
├── .pre-commit-config.yaml
├── .stestr.conf
├── .zuul.yaml
├── CONTRIBUTING.rst
├── HACKING.rst
├── LICENSE
├── README.rst
├── bindep.txt
├── doc
├── requirements.txt
└── source
│ ├── admin
│ ├── drivers.rst
│ ├── index.rst
│ ├── kafka.rst
│ └── rabbit.rst
│ ├── conf.py
│ ├── configuration
│ ├── conffixture.rst
│ ├── index.rst
│ └── opts.rst
│ ├── contributor
│ ├── contributing.rst
│ ├── driver-dev-guide.rst
│ ├── index.rst
│ ├── supported-messaging-drivers.rst
│ └── using-simulator.rst
│ ├── index.rst
│ ├── reference
│ ├── exceptions.rst
│ ├── executors.rst
│ ├── index.rst
│ ├── notification_driver.rst
│ ├── notification_listener.rst
│ ├── notifier.rst
│ ├── rpcclient.rst
│ ├── serializer.rst
│ ├── server.rst
│ ├── target.rst
│ └── transport.rst
│ └── user
│ ├── FAQ.rst
│ ├── history.rst
│ └── index.rst
├── etc
└── routing_notifier.yaml.sample
├── oslo_messaging
├── __init__.py
├── _drivers
│ ├── __init__.py
│ ├── amqp.py
│ ├── amqpdriver.py
│ ├── base.py
│ ├── common.py
│ ├── impl_fake.py
│ ├── impl_kafka.py
│ ├── impl_rabbit.py
│ ├── kafka_driver
│ │ ├── __init__.py
│ │ └── kafka_options.py
│ └── pool.py
├── _metrics
│ ├── __init__.py
│ └── client.py
├── _utils.py
├── conffixture.py
├── dispatcher.py
├── exceptions.py
├── hacking
│ ├── __init__.py
│ └── checks.py
├── notify
│ ├── __init__.py
│ ├── _impl_log.py
│ ├── _impl_noop.py
│ ├── _impl_routing.py
│ ├── _impl_test.py
│ ├── dispatcher.py
│ ├── filter.py
│ ├── listener.py
│ ├── log_handler.py
│ ├── logger.py
│ ├── messaging.py
│ ├── middleware.py
│ └── notifier.py
├── opts.py
├── rpc
│ ├── __init__.py
│ ├── client.py
│ ├── dispatcher.py
│ ├── server.py
│ └── transport.py
├── serializer.py
├── server.py
├── target.py
├── tests
│ ├── __init__.py
│ ├── drivers
│ │ ├── __init__.py
│ │ ├── test_impl_kafka.py
│ │ ├── test_impl_rabbit.py
│ │ └── test_pool.py
│ ├── functional
│ │ ├── __init__.py
│ │ ├── notify
│ │ │ ├── __init__.py
│ │ │ └── test_logger.py
│ │ ├── test_functional.py
│ │ ├── test_rabbitmq.py
│ │ └── utils.py
│ ├── notify
│ │ ├── __init__.py
│ │ ├── test_dispatcher.py
│ │ ├── test_listener.py
│ │ ├── test_log_handler.py
│ │ ├── test_logger.py
│ │ ├── test_middleware.py
│ │ └── test_notifier.py
│ ├── rpc
│ │ ├── __init__.py
│ │ ├── test_client.py
│ │ ├── test_dispatcher.py
│ │ └── test_server.py
│ ├── test_config_opts_proxy.py
│ ├── test_exception_serialization.py
│ ├── test_expected_exceptions.py
│ ├── test_fixture.py
│ ├── test_opts.py
│ ├── test_target.py
│ ├── test_transport.py
│ ├── test_urls.py
│ ├── test_utils.py
│ └── utils.py
├── transport.py
└── version.py
├── releasenotes
├── notes
│ ├── RPC-call-monitoring-7977f047d069769a.yaml
│ ├── add-enable_cancel_on_failover-22ac472b93dd3a23.yaml
│ ├── add-ping-endpoint.yaml
│ ├── add-quorum-control-configurations-beed79811ff97ba2.yaml
│ ├── add-ssl-support-for-kafka.yaml
│ ├── add_reno-3b4ae0789e9c45b4.yaml
│ ├── adding_support_for_quorum_queues-3101d055b492289e.yaml
│ ├── allow-transient-no-expire-ce7ae9d8c9d15751.yaml
│ ├── auto-deleted-failed-quorum-ca6a3923c3ed999a.yaml
│ ├── blocking-executor-deprecated-895146c1c3bf2f51.yaml
│ ├── blocking-executor-support-dropped-a3bc74c6825863f0.yaml
│ ├── bug-1917645-rabbit-use-retry-parameter-for-notifications-3f7c508ab4437579.yaml
│ ├── bug-1981093-kafka-dont-log-in-tpool-execute-fa50ceee2d55ebae.yaml
│ ├── bug-1993149-e8b231791b65e938.yaml
│ ├── bug-2068630-6ff92f213bc4eca0.yaml
│ ├── bug-2098714-d55094fa4fbb3178.yaml
│ ├── bump-amqp-version-due-to-tls-issue-e877b152eb101c15.yaml
│ ├── connection_ttl-2cf0fe6e1ab8c73c.yaml
│ ├── declare_fallback_durable_exchange-0db677de4fdf1e78.yaml
│ ├── deprecate-ZeroMQ-driver-a8af25aaba867c5b.yaml
│ ├── deprecate-eventlet-executor-13835b9818fd77f2.yaml
│ ├── deprecate-the-option-heartbeat_in_pthread-from-rabbit-driver-5757adb83701caa5.yaml
│ ├── deprecated-amqp1-driver-4bf57449bc2b7aad.yaml
│ ├── disable-mandatory-flag-a6210a534f3853f0.yaml
│ ├── do-not-run-heartbeat-in-pthread-by-default-42e1299f59b841f8.yaml
│ ├── drop-python27-support-5ef2f365d8930483.yaml
│ ├── enforce_fips_mode-07dd259eb8a73c2b.yaml
│ ├── fix-access_policy-deafult-a6954a147cb002b0.yaml
│ ├── get-rpc-client-0b4aa62160864b29.yaml
│ ├── get-rpc-helpers-cls-8911826ac08aef2a.yaml
│ ├── get_rpc_transport-4aa3511ad9754a60.yaml
│ ├── handle-missing-queue-553a803f94976be7.yaml
│ ├── heartbeat-rate-3-7ada9edbccc11a3f.yaml
│ ├── kafka-client-library-change-fe16d5a34550db7f.yaml
│ ├── kombo-reconnect-splay-a81eb5fca6180510.yaml
│ ├── no-log-if-ignore-errors-e2223b8a646b4c40.yaml
│ ├── option-rabbitmq-max_retries-has-been-deprecated-471f66a9e6d672a2.yaml
│ ├── oslo-metrics-support-fe16343a637cc14b.yaml
│ ├── pika-driver-has-been-deprecated-e2407fa53c91fe5c.yaml
│ ├── rabbit-no-wait-for-ack-9e5de3e1320d7660.yaml
│ ├── rabbit_queue_manager-363209285cbbe257.yaml
│ ├── rabbit_quorum_typo-9c06a9fd8d767f53.yaml
│ ├── rabbit_transient_quorum-fc3c3f88ead90034.yaml
│ ├── rabbitmq-opts-cleanup-e0f97d4cc0855c5a.yaml
│ ├── removal-deprecated-options-6d4c5db90525c52d.yaml
│ ├── remove-RequestContextSerializer-234c0496a7e0376b.yaml
│ ├── remove-ZeroMQ-driver-e9e0bbbb7bd4f5e6.yaml
│ ├── remove-amqp1-c924ea548dadffaa.yaml
│ ├── remove-deprecated-notif-opts-142f8eea540c17ec.yaml
│ ├── remove-kafka-conn-pool-opts-0b7962e2f22b24ed.yaml
│ ├── remove-old-quorum-opts-with-typo-5e013064fb6df062.yaml
│ ├── remove-pika-1bae204ced2521a3.yaml
│ ├── remove-py38-381f832001230756.yaml
│ ├── reply_q-timeout-e3c3bae636e8bc74.yaml
│ ├── retry-support-07996ef04dda9482.yaml
│ ├── run-heartbeat-in-pthread-by-default-28637b41ebf500dc.yaml
│ ├── stream-c3dd31ee98f6bbd7.yaml
│ ├── undeprecate_heartbeat_in_pthread-48e2c1fc008cf208.yaml
│ └── use-extras-for-optional-deps-2a00e8007ef7a629.yaml
└── source
│ ├── 2023.1.rst
│ ├── 2023.2.rst
│ ├── 2024.1.rst
│ ├── 2024.2.rst
│ ├── 2025.1.rst
│ ├── _static
│ └── .placeholder
│ ├── _templates
│ └── .placeholder
│ ├── conf.py
│ ├── index.rst
│ ├── locale
│ └── en_GB
│ │ └── LC_MESSAGES
│ │ └── releasenotes.po
│ ├── newton.rst
│ ├── ocata.rst
│ ├── pike.rst
│ ├── queens.rst
│ ├── rocky.rst
│ ├── stein.rst
│ ├── train.rst
│ ├── unreleased.rst
│ ├── ussuri.rst
│ ├── victoria.rst
│ ├── wallaby.rst
│ ├── xena.rst
│ ├── yoga.rst
│ └── zed.rst
├── requirements.txt
├── setup.cfg
├── setup.py
├── test-requirements.txt
├── tools
├── functions.sh
├── messages_length.yaml
├── setup-scenario-env.sh
└── simulator.py
└── tox.ini
/.coveragerc:
--------------------------------------------------------------------------------
1 | [run]
2 | branch = True
3 | source = oslo_messaging
4 | omit = oslo_messaging/tests/*
5 |
6 | [report]
7 | ignore_errors = True
8 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Add patterns in here to exclude files created by tools integrated with this
2 | # repository, such as test frameworks from the project's recommended workflow,
3 | # rendered documentation and package builds.
4 | #
5 | # Don't add patterns to exclude files created by preferred personal tools
6 | # (editors, IDEs, your operating system itself even). These should instead be
7 | # maintained outside the repository, for example in a ~/.gitignore file added
8 | # with:
9 | #
10 | # git config --global core.excludesfile '~/.gitignore'
11 |
12 | AUTHORS
13 | ChangeLog
14 | *.pyc
15 | *.log
16 | .tox
17 | .coverage
18 | *.egg-info/
19 | .eggs
20 | *.egg
21 | build/
22 | doc/build/
23 | doc/source/api/
24 | dist/
25 | .stestr/
26 | RELEASENOTES.rst
27 | releasenotes/notes/reno.cache
28 | releasenotes/build
29 | cover/
30 | .venv/
31 | oslo.messaging.conf
32 |
--------------------------------------------------------------------------------
/.gitreview:
--------------------------------------------------------------------------------
1 | [gerrit]
2 | host=review.opendev.org
3 | port=29418
4 | project=openstack/oslo.messaging.git
5 |
--------------------------------------------------------------------------------
/.pre-commit-config.yaml:
--------------------------------------------------------------------------------
1 | repos:
2 | - repo: https://github.com/pre-commit/pre-commit-hooks
3 | rev: v5.0.0
4 | hooks:
5 | - id: trailing-whitespace
6 | # Replaces or checks mixed line ending
7 | - id: mixed-line-ending
8 | args: ['--fix', 'lf']
9 | exclude: '.*\.(svg)$'
10 | # Forbid files which have a UTF-8 byte-order marker
11 | - id: check-byte-order-marker
12 | # Checks that non-binary executables have a proper shebang
13 | - id: check-executables-have-shebangs
14 | # Check for files that contain merge conflict strings.
15 | - id: check-merge-conflict
16 | # Check for debugger imports and py37+ breakpoint()
17 | # calls in python source
18 | - id: debug-statements
19 | - id: check-yaml
20 | files: .*\.(yaml|yml)$
21 | - repo: https://opendev.org/openstack/hacking
22 | rev: 7.0.0
23 | hooks:
24 | - id: hacking
25 | additional_dependencies: []
26 | - repo: https://github.com/PyCQA/bandit
27 | rev: 1.7.10
28 | hooks:
29 | - id: bandit
30 | args: ['-x', 'tests,tools']
31 | - repo: https://github.com/asottile/pyupgrade
32 | rev: v3.18.0
33 | hooks:
34 | - id: pyupgrade
35 | args: [--py3-only]
36 |
--------------------------------------------------------------------------------
/.stestr.conf:
--------------------------------------------------------------------------------
1 | [DEFAULT]
2 | test_path=./oslo_messaging/tests
3 | top_path=./
4 |
--------------------------------------------------------------------------------
/.zuul.yaml:
--------------------------------------------------------------------------------
1 | - job:
2 | name: oslo.messaging-tox-py310-func-scenario01
3 | parent: openstack-tox-py310
4 | vars:
5 | tox_envlist: py310-func-scenario01
6 | bindep_profile: rabbit
7 |
8 | - job:
9 | name: oslo.messaging-tox-py310-func-scenario02
10 | parent: openstack-tox-py310
11 | vars:
12 | tox_envlist: py310-func-scenario02
13 | bindep_profile: rabbit kafka
14 |
15 | # Begin v3 native jobs
16 | # See https://docs.openstack.org/devstack/latest/
17 |
18 | - job:
19 | name: oslo.messaging-devstack-tempest-full-base
20 | description: |
21 | Base for all devstack based tempest full testing jobs (with
22 | neutron)
23 | abstract: true
24 | parent: devstack-tempest
25 | timeout: 10800
26 | required-projects:
27 | - openstack/oslo.messaging
28 | vars:
29 | tox_envlist: full
30 |
31 | - job:
32 | name: oslo.messaging-src-dsvm-full-rabbit
33 | description: |
34 | Run full tempest tests against rabbitmq
35 | parent: oslo.messaging-devstack-tempest-full-base
36 |
37 | - job:
38 | name: oslo.messaging-src-dsvm-full-kafka-hybrid
39 | description: |
40 | Run the full tempest tests using Apache Kafka for Notifications.
41 | parent: oslo.messaging-devstack-tempest-full-base
42 | required-projects:
43 | - openstack/devstack-plugin-kafka
44 | vars:
45 | devstack_plugins:
46 | devstack-plugin-kafka: https://opendev.org/openstack/devstack-plugin-kafka
47 | zuul_copy_output:
48 | '{{ devstack_log_dir }}/server.log': logs
49 |
50 | - job:
51 | name: oslo.messaging-grenade
52 | parent: grenade
53 | timeout: 10800
54 | required-projects:
55 | - openstack/oslo.messaging
56 | irrelevant-files:
57 | - ^.*\.rst$
58 | - ^doc/.*$
59 | - ^releasenotes/.*$
60 | - ^.git.*$
61 | - ^(test-|)requirements.txt$
62 | - ^setup.cfg$
63 | - ^\.pre-commit-config\.yaml$
64 |
65 | - job:
66 | name: oslo.messaging-grenade-multinode
67 | parent: grenade-multinode
68 | timeout: 10800
69 | required-projects:
70 | - openstack/oslo.messaging
71 | irrelevant-files:
72 | - ^.*\.rst$
73 | - ^doc/.*$
74 | - ^releasenotes/.*$
75 | - ^.git.*$
76 | - ^(test-|)requirements.txt$
77 | - ^setup.cfg$
78 | - ^\.pre-commit-config\.yaml$
79 |
80 | - project:
81 | templates:
82 | - check-requirements
83 | - lib-forward-testing-python3
84 | - openstack-cover-jobs
85 | - openstack-python3-jobs
86 | - periodic-stable-jobs
87 | - publish-openstack-docs-pti
88 | - release-notes-jobs-python3
89 | check:
90 | jobs:
91 | - oslo.messaging-tox-py310-func-scenario01
92 | - oslo.messaging-tox-py310-func-scenario02:
93 | voting: false
94 | - oslo.messaging-src-dsvm-full-rabbit
95 | - oslo.messaging-src-dsvm-full-kafka-hybrid:
96 | voting: false
97 | - oslo.messaging-grenade:
98 | voting: false
99 | - oslo.messaging-grenade-multinode:
100 | voting: false
101 | gate:
102 | jobs:
103 | - oslo.messaging-tox-py310-func-scenario01
104 | - oslo.messaging-src-dsvm-full-rabbit
105 |
--------------------------------------------------------------------------------
/CONTRIBUTING.rst:
--------------------------------------------------------------------------------
1 | If you would like to contribute to the development of oslo's libraries,
2 | first you must take a look to this page:
3 |
4 | https://specs.openstack.org/openstack/oslo-specs/specs/policy/contributing.html
5 |
6 | If you would like to contribute to the development of OpenStack,
7 | you must follow the steps in this page:
8 |
9 | https://docs.openstack.org/infra/manual/developers.html
10 |
11 | Once those steps have been completed, changes to OpenStack
12 | should be submitted for review via the Gerrit tool, following
13 | the workflow documented at:
14 |
15 | https://docs.openstack.org/infra/manual/developers.html#development-workflow
16 |
17 | Pull requests submitted through GitHub will be ignored.
18 |
19 | Bugs should be filed on Launchpad, not GitHub:
20 |
21 | https://bugs.launchpad.net/oslo.messaging
22 |
--------------------------------------------------------------------------------
/HACKING.rst:
--------------------------------------------------------------------------------
1 | Style Commandments
2 | ==================
3 |
4 | Read the OpenStack Style Commandments https://docs.openstack.org/hacking/latest/
5 |
--------------------------------------------------------------------------------
/README.rst:
--------------------------------------------------------------------------------
1 | ========================
2 | Team and repository tags
3 | ========================
4 |
5 | .. image:: https://governance.openstack.org/tc/badges/oslo.messaging.svg
6 | :target: https://governance.openstack.org/tc/reference/tags/index.html
7 |
8 | .. Change things from this point on
9 |
10 | Oslo Messaging Library
11 | ======================
12 |
13 | .. image:: https://img.shields.io/pypi/v/oslo.messaging.svg
14 | :target: https://pypi.org/project/oslo.messaging/
15 | :alt: Latest Version
16 |
17 | .. image:: https://img.shields.io/pypi/dm/oslo.messaging.svg
18 | :target: https://pypi.org/project/oslo.messaging/
19 | :alt: Downloads
20 |
21 | The Oslo messaging API supports RPC and notifications over a number of
22 | different messaging transports.
23 |
24 | * License: Apache License, Version 2.0
25 | * Documentation: https://docs.openstack.org/oslo.messaging/latest/
26 | * Source: https://opendev.org/openstack/oslo.messaging
27 | * Bugs: https://bugs.launchpad.net/oslo.messaging
28 | * Release notes: https://docs.openstack.org/releasenotes/oslo.messaging/
29 |
--------------------------------------------------------------------------------
/bindep.txt:
--------------------------------------------------------------------------------
1 | # common dpkg
2 | gettext [platform:dpkg] # For releasenotes job
3 | build-essential [platform:dpkg]
4 | libffi-dev [platform:dpkg]
5 |
6 | # common rpm
7 | gcc [platform:rpm]
8 | gcc-c++ [platform:rpm]
9 | make [platform:rpm]
10 | pkgconfig [platform:rpm]
11 | libffi-devel [platform:rpm]
12 |
13 | # RabbitMQ message broker
14 | rabbitmq-server [platform:dpkg rabbit]
15 | rabbitmq-server [platform:rpm rabbit]
16 |
17 | # kafka dpkg
18 | default-jdk [platform:dpkg kafka]
19 | librdkafka1 [platform:dpkg kafka]
20 | librdkafka-dev [platform:dpkg kafka]
21 |
--------------------------------------------------------------------------------
/doc/requirements.txt:
--------------------------------------------------------------------------------
1 | openstackdocstheme>=2.2.0 # Apache-2.0
2 | sphinx>=2.0.0 # BSD
3 | reno>=3.1.0 # Apache-2.0
4 |
5 | # imported when the source code is parsed for generating documentation:
6 | fixtures>=3.0.0 # Apache-2.0/BSD
7 | confluent-kafka>=0.11.6 # Apache-2.0
8 | tenacity>=3.2.1 # Apache-2.0
9 |
--------------------------------------------------------------------------------
/doc/source/admin/drivers.rst:
--------------------------------------------------------------------------------
1 | ===================
2 | Available Drivers
3 | ===================
4 |
5 | .. list-plugins:: oslo.messaging.drivers
6 | :detailed:
7 |
--------------------------------------------------------------------------------
/doc/source/admin/index.rst:
--------------------------------------------------------------------------------
1 | ================
2 | Deployment Guide
3 | ================
4 |
5 | .. toctree::
6 | :maxdepth: 2
7 |
8 | drivers
9 | kafka
10 | rabbit
11 |
--------------------------------------------------------------------------------
/doc/source/conf.py:
--------------------------------------------------------------------------------
1 | # Copyright (C) 2020 Red Hat, Inc.
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License"); you may
4 | # not use this file except in compliance with the License. You may obtain
5 | # a copy of the License at
6 | #
7 | # http://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11 | # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12 | # License for the specific language governing permissions and limitations
13 | # under the License.
14 | #
15 | # Configuration file for the Sphinx documentation builder.
16 | #
17 | # This file does only contain a selection of the most common options. For a
18 | # full list see the documentation:
19 | # http://www.sphinx-doc.org/en/master/config
20 |
21 |
22 | # -- Project information ------------------------------------------------------
23 |
24 | # General information about the project.
25 | copyright = '2018, Oslo Contributors'
26 |
27 | # -- General configuration ----------------------------------------------------
28 |
29 | # Add any Sphinx extension module names here, as strings. They can be
30 | # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom ones.
31 | extensions = [
32 | 'sphinx.ext.autodoc',
33 | 'sphinx.ext.todo',
34 | 'openstackdocstheme',
35 | 'stevedore.sphinxext',
36 | 'oslo_config.sphinxext',
37 | ]
38 |
39 | # openstackdocstheme options
40 | openstackdocs_repo_name = 'openstack/oslo.messaging'
41 | openstackdocs_bug_project = 'oslo.messaging'
42 | openstackdocs_bug_tag = ''
43 |
44 | # The master toctree document.
45 | master_doc = 'index'
46 |
47 | # The name of the Pygments (syntax highlighting) style to use.
48 | pygments_style = 'native'
49 |
50 | # -- Options for HTML output --------------------------------------------------
51 |
52 | # The theme to use for HTML and HTML Help pages. Major themes that come with
53 | # Sphinx are currently 'default' and 'sphinxdoc'.
54 | html_theme = 'openstackdocs'
55 |
--------------------------------------------------------------------------------
/doc/source/configuration/conffixture.rst:
--------------------------------------------------------------------------------
1 | ----------------------
2 | Testing Configurations
3 | ----------------------
4 |
5 | .. currentmodule:: oslo_messaging.conffixture
6 |
7 | .. autoclass:: ConfFixture
8 | :members:
9 |
10 |
--------------------------------------------------------------------------------
/doc/source/configuration/index.rst:
--------------------------------------------------------------------------------
1 | =============
2 | Configuration
3 | =============
4 |
5 | .. toctree::
6 | :maxdepth: 2
7 |
8 | opts
9 | conffixture
10 |
--------------------------------------------------------------------------------
/doc/source/configuration/opts.rst:
--------------------------------------------------------------------------------
1 | =======================
2 | Configuration Options
3 | =======================
4 |
5 | oslo.messaging uses oslo.config to define and manage configuration
6 | options to allow the deployer to control how an application uses the
7 | underlying messaging system.
8 |
9 | .. show-options:: oslo.messaging
10 |
11 | API
12 | ===
13 |
14 | .. currentmodule:: oslo_messaging.opts
15 |
16 | .. autofunction:: list_opts
17 |
--------------------------------------------------------------------------------
/doc/source/contributor/contributing.rst:
--------------------------------------------------------------------------------
1 | ==============
2 | Contributing
3 | ==============
4 |
5 | .. include:: ../../../CONTRIBUTING.rst
6 |
--------------------------------------------------------------------------------
/doc/source/contributor/driver-dev-guide.rst:
--------------------------------------------------------------------------------
1 | ---------------------------------------
2 | Guide for Transport Driver Implementors
3 | ---------------------------------------
4 |
5 | .. currentmodule:: oslo_messaging
6 |
7 | .. automodule:: oslo_messaging._drivers.base
8 |
9 | ============
10 | Introduction
11 | ============
12 |
13 | This document is a *best practices* guide for the developer interested
14 | in creating a new transport driver for Oslo.Messaging. It should also
15 | be used by maintainers as a reference for proper driver behavior.
16 | This document will describe the driver interface and prescribe the
17 | expected behavior of any driver implemented to this interface.
18 |
19 | **Note well:** The API described in this document is internal to the
20 | oslo.messaging library and therefore **private**. Under no
21 | circumstances should this API be referenced by code external to the
22 | oslo.messaging library.
23 |
24 | ================
25 | Driver Interface
26 | ================
27 |
28 | The driver interface is defined by a set of abstract base classes. The
29 | developer creates a driver by defining concrete classes from these
30 | bases. The derived classes embody the logic that is specific for the
31 | messaging back-end that is to be supported.
32 |
33 | These base classes are defined in the *base.py* file in the *_drivers*
34 | subdirectory.
35 |
36 | ===============
37 | IncomingMessage
38 | ===============
39 |
40 | .. autoclass:: IncomingMessage
41 | :members:
42 |
43 | ==================
44 | RpcIncomingMessage
45 | ==================
46 |
47 | .. autoclass:: RpcIncomingMessage
48 | :members:
49 |
50 | ========
51 | Listener
52 | ========
53 |
54 | .. autoclass:: Listener
55 | :members:
56 |
57 | =================
58 | PollStyleListener
59 | =================
60 |
61 | .. autoclass:: PollStyleListener
62 | :members:
63 |
64 | ==========
65 | BaseDriver
66 | ==========
67 |
68 | .. autoclass:: BaseDriver
69 | :members:
70 |
71 |
72 |
73 |
74 |
75 |
76 |
--------------------------------------------------------------------------------
/doc/source/contributor/index.rst:
--------------------------------------------------------------------------------
1 | ==============================
2 | Contributing to oslo.messaging
3 | ==============================
4 |
5 | .. toctree::
6 | :maxdepth: 2
7 |
8 | contributing
9 | driver-dev-guide
10 | supported-messaging-drivers
11 | using-simulator
12 |
--------------------------------------------------------------------------------
/doc/source/contributor/supported-messaging-drivers.rst:
--------------------------------------------------------------------------------
1 | =============================
2 | Supported Messaging Drivers
3 | =============================
4 |
5 | RabbitMQ may not be sufficient for the entire community as the community
6 | grows. Pluggability is still something we should maintain, but we should
7 | have a very high standard for drivers that are shipped and documented
8 | as being supported.
9 |
10 | This document defines a very clear policy as to the requirements
11 | for drivers to be carried in oslo.messaging and thus supported by the
12 | OpenStack community as a whole. We will deprecate any drivers that do not
13 | meet the requirements, and announce said deprecations in any appropriate
14 | channels to give users time to signal their needs. Deprecation will last
15 | for two release cycles before removing the code. We will also review and
16 | update documentation to annotate which drivers are supported and which
17 | are deprecated given these policies
18 |
19 | Policy
20 | ------
21 |
22 | Testing
23 | ~~~~~~~
24 |
25 | * Must have unit and/or functional test coverage of at least 60% as
26 | reported by coverage report. Unit tests must be run for all versions
27 | of python oslo.messaging currently gates on.
28 |
29 | * Must have integration testing including at least 3 popular oslo.messaging
30 | dependents, preferably at the minimum a devstack-gate job with Nova,
31 | Cinder, and Neutron.
32 |
33 | * All testing above must be voting in the gate of oslo.messaging.
34 |
35 | Documentation
36 | ~~~~~~~~~~~~~
37 |
38 | * Must have a reasonable amount of documentation including documentation
39 | in the official OpenStack deployment guide.
40 |
41 | Support
42 | ~~~~~~~
43 |
44 | * Must have at least two individuals from the community committed to
45 | triaging and fixing bugs, and responding to test failures in a timely
46 | manner.
47 |
48 | Prospective Drivers
49 | ~~~~~~~~~~~~~~~~~~~
50 |
51 | * Drivers that intend to meet the requirements above, but that do not yet
52 | meet them will be given one full release cycle, or 6 months, whichever
53 | is longer, to comply before being marked for deprecation. Their use,
54 | however, will not be supported by the community. This will prevent a
55 | chicken and egg problem for new drivers.
56 |
57 | .. note::
58 |
59 | This work is licensed under a Creative Commons Attribution 3.0 Unported License.
60 | http://creativecommons.org/licenses/by/3.0/legalcode
61 |
--------------------------------------------------------------------------------
/doc/source/contributor/using-simulator.rst:
--------------------------------------------------------------------------------
1 | ============================
2 | Oslo Messaging Simulator
3 | ============================
4 |
5 | This guide explains how to set up and run the oslo messaging simulator for testing
6 | different messaging scenarios.
7 |
8 | Prerequisites
9 | -------------
10 | * Python 3.x
11 | * virtualenv
12 | * wget (for Kafka scenarios)
13 |
14 | Environment Setup
15 | -----------------
16 | This assumes you have git cloned the oslo.messaging repository and are in the root
17 | directory of the repository.
18 |
19 | Create and activate a virtual environment::
20 |
21 | python -m venv .venv
22 | source .venv/bin/activate
23 |
24 | Install required packages::
25 |
26 | pip install pifpaf
27 | pip install -e .
28 |
29 | Running the Simulator
30 | ---------------------
31 | The simulator supports different scenarios for testing messaging patterns. Below
32 | are the common usage patterns.
33 |
34 | Basic Setup
35 | ^^^^^^^^^^^
36 | Before running the simulator, set up the messaging environment::
37 |
38 | ./tools/setup-scenario-env.sh
39 |
40 | Available Scenarios
41 | ^^^^^^^^^^^^^^^^^^^
42 | The simulator supports two main scenarios:
43 |
44 | Scenario 01 (RabbitMQ only)
45 | ***************************
46 | This scenario uses RabbitMQ for both RPC and notifications::
47 |
48 | export SCENARIO=scenario01
49 | ./tools/setup-scenario-env.sh
50 |
51 | Scenario 02 (RabbitMQ + Kafka)
52 | ******************************
53 | This scenario uses RabbitMQ for RPC and Kafka for notifications::
54 |
55 | export SCENARIO=scenario02
56 | ./tools/setup-scenario-env.sh
57 |
58 | Running the Simulator
59 | ^^^^^^^^^^^^^^^^^^^^^
60 |
61 | RPC Server Example
62 | ******************
63 | To start the RPC server::
64 |
65 | python tools/simulator.py --url rabbit://pifpaf:secret@127.0.0.1:5682/ rpc-server
66 |
67 | RPC Client Example
68 | ******************
69 | To start the RPC client::
70 |
71 | python tools/simulator.py --url rabbit://pifpaf:secret@127.0.0.1:5682/ rpc-client --exit-wait 15000 -p 64 -m 64
72 |
73 | Optional Configuration
74 | ----------------------
75 | You can generate a sample configuration file using oslo-config-generator::
76 |
77 | oslo-config-generator --namespace oslo.messaging > oslo.messaging.conf
78 |
79 | For reference on all available configuration options, visit:
80 | https://docs.openstack.org/oslo.messaging/latest/configuration/opts.html
81 |
82 | To use a configuration file with the simulator, use the --config-file option::
83 |
84 | python tools/simulator.py --config-file oslo.messaging.conf [other options]
85 |
86 | Command Line Options
87 | --------------------
88 | The simulator supports various command line options:
89 |
90 | --url URL
91 | The transport URL for the messaging service
92 | --config-file PATH
93 | Path to a configuration file
94 | -d, --debug
95 | Enable debug mode
96 | -p PROCESSES
97 | Number of processes (for client)
98 | -m MESSAGES
99 | Number of messages (for client)
100 | --exit-wait MILLISECONDS
101 | Wait time before exit (for client)
102 |
103 | Cleanup
104 | -------
105 | To clean up the environment, you can terminate the running processes::
106 |
107 | pkill -f "RABBITMQ"
108 |
109 | Notes
110 | -----
111 | * The default scenario is scenario01 if not specified
112 | * Kafka setup is automatic when using scenario02
113 | * The simulator uses pifpaf to manage the message broker processes
114 | * Installing with ``pip install -e .`` allows for development mode installation
115 | * Configuration options can be referenced in the official documentation
116 |
--------------------------------------------------------------------------------
/doc/source/index.rst:
--------------------------------------------------------------------------------
1 | ==============
2 | oslo.messaging
3 | ==============
4 |
5 | The Oslo messaging API supports RPC and notifications over a number of
6 | different messaging transports.
7 |
8 |
9 | .. toctree::
10 | :maxdepth: 1
11 |
12 | contributor/index
13 | configuration/index
14 | admin/index
15 | user/index
16 | reference/index
17 |
18 |
19 | Release Notes
20 | =============
21 |
22 | Read also the `oslo.messaging Release Notes
23 | `_.
24 |
25 |
26 | Indices and tables
27 | ==================
28 |
29 | * :ref:`genindex`
30 | * :ref:`modindex`
31 | * :ref:`search`
32 |
33 |
--------------------------------------------------------------------------------
/doc/source/reference/exceptions.rst:
--------------------------------------------------------------------------------
1 | ----------
2 | Exceptions
3 | ----------
4 |
5 | .. currentmodule:: oslo_messaging
6 |
7 | .. autoexception:: ClientSendError
8 | .. autoexception:: DriverLoadFailure
9 | .. autoexception:: ExecutorLoadFailure
10 | .. autoexception:: InvalidTransportURL
11 | .. autoexception:: MessagingException
12 | .. autoexception:: MessagingTimeout
13 | .. autoexception:: MessagingServerError
14 | .. autoexception:: NoSuchMethod
15 | .. autoexception:: RPCDispatcherError
16 | .. autoexception:: RPCVersionCapError
17 | .. autoexception:: ServerListenError
18 | .. autoexception:: UnsupportedVersion
19 |
--------------------------------------------------------------------------------
/doc/source/reference/executors.rst:
--------------------------------------------------------------------------------
1 | =========
2 | Executors
3 | =========
4 |
5 | Executors control how a received message is scheduled for processing
6 | by a Server. This scheduling can be *synchronous* or *asynchronous*.
7 |
8 | A synchronous executor will process the message on the Server's
9 | thread. This means the Server can process only one message at a time.
10 | Other incoming messages will not be processed until the current
11 | message is done processing. For example, in the case of an RPCServer
12 | only one method call will be invoked at a time. A synchronous
13 | executor guarantees that messages complete processing in the order
14 | that they are received.
15 |
16 | An asynchronous executor will process received messages concurrently.
17 | The Server thread will not be blocked by message processing and can
18 | continue to service incoming messages. There are no ordering
19 | guarantees - message processing may complete in a different order than
20 | they were received. The executor may be configured to limit the
21 | maximum number of messages that are processed at once.
22 |
23 |
24 | Available Executors
25 | ===================
26 |
27 | .. list-plugins:: oslo.messaging.executors
28 | :detailed:
29 |
--------------------------------------------------------------------------------
/doc/source/reference/index.rst:
--------------------------------------------------------------------------------
1 | .. _using:
2 |
3 | =========
4 | Reference
5 | =========
6 |
7 | .. toctree::
8 | :maxdepth: 2
9 |
10 | transport
11 | executors
12 | target
13 | server
14 | rpcclient
15 | notifier
16 | notification_driver
17 | notification_listener
18 | serializer
19 | exceptions
20 |
--------------------------------------------------------------------------------
/doc/source/reference/notification_driver.rst:
--------------------------------------------------------------------------------
1 | -------------------
2 | Notification Driver
3 | -------------------
4 |
5 | .. automodule:: oslo_messaging.notify.messaging
6 |
7 | .. autoclass:: MessagingDriver
8 |
9 | .. autoclass:: MessagingV2Driver
10 |
11 | .. currentmodule:: oslo_messaging.notify.notifier
12 |
13 | .. autoclass:: Driver
14 | :members:
15 | :noindex:
16 |
--------------------------------------------------------------------------------
/doc/source/reference/notification_listener.rst:
--------------------------------------------------------------------------------
1 | ---------------------
2 | Notification Listener
3 | ---------------------
4 |
5 | .. automodule:: oslo_messaging.notify.listener
6 |
7 | .. currentmodule:: oslo_messaging
8 |
9 | .. autofunction:: get_notification_listener
10 |
11 | .. autofunction:: get_batch_notification_listener
12 |
--------------------------------------------------------------------------------
/doc/source/reference/notifier.rst:
--------------------------------------------------------------------------------
1 | ==========
2 | Notifier
3 | ==========
4 |
5 | .. currentmodule:: oslo_messaging
6 |
7 | .. autoclass:: Notifier
8 | :members:
9 |
10 | .. autoclass:: LoggingNotificationHandler
11 | :members:
12 |
13 | .. autoclass:: LoggingErrorNotificationHandler
14 | :members:
15 |
16 | Available Notifier Drivers
17 | ==========================
18 |
19 | .. list-plugins:: oslo.messaging.notify.drivers
20 | :detailed:
21 |
--------------------------------------------------------------------------------
/doc/source/reference/rpcclient.rst:
--------------------------------------------------------------------------------
1 | ----------
2 | RPC Client
3 | ----------
4 |
5 | .. currentmodule:: oslo_messaging
6 |
7 | .. autoclass:: RPCClient
8 | :members:
9 |
10 | .. autoexception:: RemoteError
11 |
--------------------------------------------------------------------------------
/doc/source/reference/serializer.rst:
--------------------------------------------------------------------------------
1 | ----------
2 | Serializer
3 | ----------
4 |
5 | .. currentmodule:: oslo_messaging
6 |
7 | .. autoclass:: Serializer
8 | :members:
9 |
10 | .. autoclass:: NoOpSerializer
11 |
--------------------------------------------------------------------------------
/doc/source/reference/server.rst:
--------------------------------------------------------------------------------
1 | ----------
2 | RPC Server
3 | ----------
4 |
5 | .. automodule:: oslo_messaging.rpc.server
6 |
7 | .. currentmodule:: oslo_messaging
8 |
9 | .. autofunction:: get_rpc_server
10 |
11 | .. autoclass:: RPCAccessPolicyBase
12 |
13 | .. autoclass:: LegacyRPCAccessPolicy
14 |
15 | .. autoclass:: DefaultRPCAccessPolicy
16 |
17 | .. autoclass:: ExplicitRPCAccessPolicy
18 |
19 | .. autoclass:: RPCDispatcher
20 |
21 | .. autoclass:: MessageHandlingServer
22 | :members:
23 |
24 | .. autofunction:: expected_exceptions
25 |
26 | .. autofunction:: expose
27 |
28 | .. autoexception:: ExpectedException
29 |
--------------------------------------------------------------------------------
/doc/source/reference/target.rst:
--------------------------------------------------------------------------------
1 | ------
2 | Target
3 | ------
4 |
5 | .. currentmodule:: oslo_messaging
6 |
7 | .. autoclass:: Target
8 |
9 | ===============
10 | Target Versions
11 | ===============
12 |
13 | Target version numbers take the form Major.Minor. For a given message with
14 | version X.Y, the server must be marked as able to handle messages of version
15 | A.B, where A == X and B >= Y.
16 |
17 | The Major version number should be incremented for an almost completely new
18 | API. The Minor version number would be incremented for backwards compatible
19 | changes to an existing API. A backwards compatible change could be something
20 | like adding a new method, adding an argument to an existing method (but not
21 | requiring it), or changing the type for an existing argument (but still
22 | handling the old type as well).
23 |
24 | If no version is specified it defaults to '1.0'.
25 |
26 | In the case of RPC, if you wish to allow your server interfaces to evolve such
27 | that clients do not need to be updated in lockstep with the server, you should
28 | take care to implement the server changes in a backwards compatible and have
29 | the clients specify which interface version they require for each method.
30 |
31 | Adding a new method to an endpoint is a backwards compatible change and the
32 | version attribute of the endpoint's target should be bumped from X.Y to X.Y+1.
33 | On the client side, the new RPC invocation should have a specific version
34 | specified to indicate the minimum API version that must be implemented for the
35 | method to be supported. For example::
36 |
37 | def get_host_uptime(self, ctxt, host):
38 | cctxt = self.client.prepare(server=host, version='1.1')
39 | return cctxt.call(ctxt, 'get_host_uptime')
40 |
41 | In this case, version '1.1' is the first version that supported the
42 | get_host_uptime() method.
43 |
44 | Adding a new parameter to an RPC method can be made backwards compatible. The
45 | endpoint version on the server side should be bumped. The implementation of
46 | the method must not expect the parameter to be present.::
47 |
48 | def some_remote_method(self, arg1, arg2, newarg=None):
49 | # The code needs to deal with newarg=None for cases
50 | # where an older client sends a message without it.
51 | pass
52 |
53 | On the client side, the same changes should be made as in example 1. The
54 | minimum version that supports the new parameter should be specified.
55 |
--------------------------------------------------------------------------------
/doc/source/reference/transport.rst:
--------------------------------------------------------------------------------
1 | ---------
2 | Transport
3 | ---------
4 |
5 | .. currentmodule:: oslo_messaging
6 |
7 | .. autoclass:: Transport
8 |
9 | .. autoclass:: TransportURL
10 | :members:
11 |
12 | .. autoclass:: TransportHost
13 |
14 | .. autofunction:: set_transport_defaults
15 |
16 |
17 | Forking Processes and oslo.messaging Transport objects
18 | ------------------------------------------------------
19 |
20 | oslo.messaging can't ensure that forking a process that shares the same
21 | transport object is safe for the library consumer, because it relies on
22 | different 3rd party libraries that don't ensure that. In certain
23 | cases, with some drivers, it does work:
24 |
25 | * rabbit: works only if no connection have already been established.
26 |
--------------------------------------------------------------------------------
/doc/source/user/FAQ.rst:
--------------------------------------------------------------------------------
1 | ============================
2 | Frequently Asked Questions
3 | ============================
4 |
5 | I don't need notifications on the message bus. How do I disable them?
6 | =====================================================================
7 |
8 | Notification messages can be disabled using the ``noop`` notify
9 | driver. Set ``driver = noop`` in your configuration file under the
10 | [oslo_messaging_notifications] section.
11 |
12 | Why does the notification publisher create queues, too? Shouldn't the subscriber do that?
13 | =========================================================================================
14 |
15 | The notification messages are meant to be used for integration with
16 | external services, including services that are not part of
17 | OpenStack. To ensure that the subscriber does not miss any messages if
18 | it starts after the publisher, ``oslo.messaging`` ensures that
19 | subscriber queues exist when notifications are sent.
20 |
21 | How do I change the queue names where notifications are published?
22 | ==================================================================
23 |
24 | Notifications are published to the configured exchange using a topic
25 | built from a base value specified in the configuration file and the
26 | notification "level". The default topic is ``notifications``, so an
27 | info-level notification is published to the topic
28 | ``notifications.info``. A subscriber queue of the same name is created
29 | automatically for each of these topics. To change the queue names,
30 | change the notification topic using the ``topics``
31 | configuration option in ``[oslo_messaging_notifications]``. The option
32 | accepts a list of values, so it is possible to publish to multiple topics.
33 |
34 | What are the other choices of notification drivers available?
35 | =============================================================
36 |
37 | - messaging Send notifications using the 1.0 message format.
38 | - messagingv2 Send notifications using the 2.0 message format (with a message envelope).
39 | - routing Configurable routing notifier (by priority or event_type).
40 | - log Publish notifications via Python logging infrastructure.
41 | - test Store notifications in memory for test verification.
42 | - noop Disable sending notifications entirely.
43 |
--------------------------------------------------------------------------------
/doc/source/user/history.rst:
--------------------------------------------------------------------------------
1 | .. include:: ../../../ChangeLog
2 |
--------------------------------------------------------------------------------
/doc/source/user/index.rst:
--------------------------------------------------------------------------------
1 | ====================
2 | Using oslo.messaging
3 | ====================
4 |
5 | .. toctree::
6 | :maxdepth: 2
7 |
8 | FAQ
9 |
10 | .. toctree::
11 | :maxdepth: 1
12 |
13 | history
14 |
--------------------------------------------------------------------------------
/etc/routing_notifier.yaml.sample:
--------------------------------------------------------------------------------
1 | # Setting a priority AND an event means both have to be satisfied.
2 | #
3 | # However, defining different sets for the same driver allows you
4 | # to do OR operations.
5 | #
6 | # See how this logic is modelled below:
7 | #
8 | # if (priority in info, warn or error) or
9 | # (event == compute.scheduler.run_instance)
10 | # send to messaging driver ...
11 | #
12 | # if priority == 'poll' and
13 | # event == 'bandwidth.*'
14 | # send to poll driver
15 |
16 | group_1:
17 | messaging:
18 | accepted_priorities: ['info', 'warn', 'error']
19 |
20 | poll:
21 | accepted_priorities: ['poll']
22 | accepted_events: ['bandwidth.*']
23 |
24 | log:
25 | accepted_events: ['compute.instance.exists']
26 |
27 | group_2:
28 | messaging:⋅
29 | accepted_events: ['compute.scheduler.run_instance.*']
30 |
--------------------------------------------------------------------------------
/oslo_messaging/__init__.py:
--------------------------------------------------------------------------------
1 | # Copyright 2013 Red Hat, Inc.
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License"); you may
4 | # not use this file except in compliance with the License. You may obtain
5 | # a copy of the License at
6 | #
7 | # http://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11 | # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12 | # License for the specific language governing permissions and limitations
13 | # under the License.
14 |
15 | from .exceptions import *
16 | from .notify import *
17 | from .rpc import *
18 | from .serializer import *
19 | from .server import *
20 | from .target import *
21 | from .transport import *
22 |
--------------------------------------------------------------------------------
/oslo_messaging/_drivers/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/openstack/oslo.messaging/510688d8ddc807242fe9a36532dd03ba3c2d4ad5/oslo_messaging/_drivers/__init__.py
--------------------------------------------------------------------------------
/oslo_messaging/_drivers/amqp.py:
--------------------------------------------------------------------------------
1 | # Copyright 2010 United States Government as represented by the
2 | # Administrator of the National Aeronautics and Space Administration.
3 | # All Rights Reserved.
4 | # Copyright 2011 - 2012, Red Hat, Inc.
5 | #
6 | # Licensed under the Apache License, Version 2.0 (the "License"); you may
7 | # not use this file except in compliance with the License. You may obtain
8 | # a copy of the License at
9 | #
10 | # http://www.apache.org/licenses/LICENSE-2.0
11 | #
12 | # Unless required by applicable law or agreed to in writing, software
13 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
14 | # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
15 | # License for the specific language governing permissions and limitations
16 | # under the License.
17 |
18 | """
19 | Utilities for drivers based on the AMQPDriverBase.
20 |
21 | This module contains utility code used by drivers based on the AMQPDriverBase
22 | class. Specifically this includes the impl_rabbit driver.
23 | """
24 |
25 | import collections
26 | import uuid
27 |
28 | from oslo_config import cfg
29 |
30 | from oslo_messaging._drivers import common as rpc_common
31 |
32 | amqp_opts = [
33 | cfg.BoolOpt('amqp_durable_queues',
34 | default=False,
35 | help='Use durable queues in AMQP. If rabbit_quorum_queue '
36 | 'is enabled, queues will be durable and this value will '
37 | 'be ignored.'),
38 | cfg.BoolOpt('amqp_auto_delete',
39 | default=False,
40 | help='Auto-delete queues in AMQP.'),
41 | ]
42 |
43 | UNIQUE_ID = '_unique_id'
44 |
45 |
46 | class RpcContext(rpc_common.CommonRpcContext):
47 | """Context that supports replying to a rpc.call."""
48 | def __init__(self, **kwargs):
49 | self.msg_id = kwargs.pop('msg_id', None)
50 | self.reply_q = kwargs.pop('reply_q', None)
51 | super().__init__(**kwargs)
52 |
53 | def deepcopy(self):
54 | values = self.to_dict()
55 | values['conf'] = self.conf
56 | values['msg_id'] = self.msg_id
57 | values['reply_q'] = self.reply_q
58 | return self.__class__(**values)
59 |
60 |
61 | def unpack_context(msg):
62 | """Unpack context from msg."""
63 | context_dict = {}
64 | for key in list(msg.keys()):
65 | key = str(key)
66 | if key.startswith('_context_'):
67 | value = msg.pop(key)
68 | context_dict[key[9:]] = value
69 | context_dict['msg_id'] = msg.pop('_msg_id', None)
70 | context_dict['reply_q'] = msg.pop('_reply_q', None)
71 | context_dict['client_timeout'] = msg.pop('_timeout', None)
72 | return RpcContext.from_dict(context_dict)
73 |
74 |
75 | def pack_context(msg, context):
76 | """Pack context into msg.
77 |
78 | Values for message keys need to be less than 255 chars, so we pull
79 | context out into a bunch of separate keys. If we want to support
80 | more arguments in rabbit messages, we may want to do the same
81 | for args at some point.
82 |
83 | """
84 | if isinstance(context, dict):
85 | context_d = context.items()
86 | else:
87 | context_d = context.to_dict().items()
88 |
89 | msg.update(('_context_%s' % key, value)
90 | for (key, value) in context_d)
91 |
92 |
93 | class _MsgIdCache:
94 | """This class checks any duplicate messages."""
95 |
96 | # NOTE: This value is considered can be a configuration item, but
97 | # it is not necessary to change its value in most cases,
98 | # so let this value as static for now.
99 | DUP_MSG_CHECK_SIZE = 16
100 |
101 | def __init__(self, **kwargs):
102 | self.prev_msgids = collections.deque([],
103 | maxlen=self.DUP_MSG_CHECK_SIZE)
104 |
105 | def check_duplicate_message(self, message_data):
106 | """AMQP consumers may read same message twice when exceptions occur
107 | before ack is returned. This method prevents doing it.
108 | """
109 | try:
110 | msg_id = message_data.pop(UNIQUE_ID)
111 | except KeyError:
112 | return
113 | if msg_id in self.prev_msgids:
114 | raise rpc_common.DuplicateMessageError(msg_id=msg_id)
115 | return msg_id
116 |
117 | def add(self, msg_id):
118 | if msg_id and msg_id not in self.prev_msgids:
119 | self.prev_msgids.append(msg_id)
120 |
121 |
122 | def _add_unique_id(msg):
123 | """Add unique_id for checking duplicate messages."""
124 | unique_id = uuid.uuid4().hex
125 | msg.update({UNIQUE_ID: unique_id})
126 |
127 |
128 | class AMQPDestinationNotFound(Exception):
129 | pass
130 |
--------------------------------------------------------------------------------
/oslo_messaging/_drivers/kafka_driver/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/openstack/oslo.messaging/510688d8ddc807242fe9a36532dd03ba3c2d4ad5/oslo_messaging/_drivers/kafka_driver/__init__.py
--------------------------------------------------------------------------------
/oslo_messaging/_drivers/kafka_driver/kafka_options.py:
--------------------------------------------------------------------------------
1 | #
2 | # Licensed under the Apache License, Version 2.0 (the "License"); you may
3 | # not use this file except in compliance with the License. You may obtain
4 | # a copy of the License at
5 | #
6 | # http://www.apache.org/licenses/LICENSE-2.0
7 | #
8 | # Unless required by applicable law or agreed to in writing, software
9 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
10 | # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
11 | # License for the specific language governing permissions and limitations
12 | # under the License.
13 |
14 | from oslo_config import cfg
15 |
16 | from oslo_messaging._drivers import common
17 |
18 | KAFKA_OPTS = [
19 | cfg.IntOpt('kafka_max_fetch_bytes', default=1024 * 1024,
20 | help='Max fetch bytes of Kafka consumer'),
21 | cfg.FloatOpt('kafka_consumer_timeout', default=1.0,
22 | help='Default timeout(s) for Kafka consumers'),
23 | cfg.StrOpt('consumer_group', default="oslo_messaging_consumer",
24 | help='Group id for Kafka consumer. Consumers in one group '
25 | 'will coordinate message consumption'),
26 | cfg.FloatOpt('producer_batch_timeout', default=0.,
27 | help="Upper bound on the delay for KafkaProducer batching "
28 | "in seconds"),
29 | cfg.IntOpt('producer_batch_size', default=16384,
30 | help='Size of batch for the producer async send'),
31 | cfg.StrOpt('compression_codec', default='none',
32 | choices=['none', 'gzip', 'snappy', 'lz4', 'zstd'],
33 | help='The compression codec for all data generated by the '
34 | 'producer. If not set, compression will not be used. '
35 | 'Note that the allowed values of this depend on the kafka '
36 | 'version'),
37 | cfg.BoolOpt('enable_auto_commit',
38 | default=False,
39 | help='Enable asynchronous consumer commits'),
40 | cfg.IntOpt('max_poll_records', default=500,
41 | help='The maximum number of records returned in a poll call'),
42 | cfg.StrOpt('security_protocol', default='PLAINTEXT',
43 | choices=('PLAINTEXT', 'SASL_PLAINTEXT', 'SSL', 'SASL_SSL'),
44 | help='Protocol used to communicate with brokers'),
45 | cfg.StrOpt('sasl_mechanism',
46 | default='PLAIN',
47 | help='Mechanism when security protocol is SASL'),
48 | cfg.StrOpt('ssl_cafile',
49 | default='',
50 | help='CA certificate PEM file used to verify the server'
51 | ' certificate'),
52 | cfg.StrOpt('ssl_client_cert_file',
53 | default='',
54 | help='Client certificate PEM file used for authentication.'),
55 | cfg.StrOpt('ssl_client_key_file',
56 | default='',
57 | help='Client key PEM file used for authentication.'),
58 | cfg.StrOpt('ssl_client_key_password',
59 | default='',
60 | help='Client key password file used for authentication.')
61 | ]
62 |
63 |
64 | def register_opts(conf, url):
65 | opt_group = cfg.OptGroup(name='oslo_messaging_kafka',
66 | title='Kafka driver options')
67 | conf.register_group(opt_group)
68 | conf.register_opts(KAFKA_OPTS, group=opt_group)
69 | return common.ConfigOptsProxy(conf, url, opt_group.name)
70 |
--------------------------------------------------------------------------------
/oslo_messaging/_drivers/pool.py:
--------------------------------------------------------------------------------
1 | # Copyright 2013 Red Hat, Inc.
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License"); you may
4 | # not use this file except in compliance with the License. You may obtain
5 | # a copy of the License at
6 | #
7 | # http://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11 | # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12 | # License for the specific language governing permissions and limitations
13 | # under the License.
14 |
15 | import abc
16 | import collections
17 | import threading
18 |
19 | from oslo_log import log as logging
20 | from oslo_utils import timeutils
21 |
22 | from oslo_messaging._drivers import common
23 |
24 | LOG = logging.getLogger(__name__)
25 |
26 |
27 | class Pool(metaclass=abc.ABCMeta):
28 | """A thread-safe object pool.
29 |
30 | Modelled after the eventlet.pools.Pool interface, but designed to be safe
31 | when using native threads without the GIL.
32 |
33 | Resizing is not supported.
34 |
35 | """
36 |
37 | def __init__(self, max_size=4, min_size=2, ttl=1200, on_expire=None):
38 | super().__init__()
39 | self._min_size = min_size
40 | self._max_size = max_size
41 | self._item_ttl = ttl
42 | self._current_size = 0
43 | self._cond = threading.Condition()
44 | self._items = collections.deque()
45 | self._on_expire = on_expire
46 |
47 | def expire(self):
48 | """Remove expired items from left (the oldest item) to
49 | right (the newest item).
50 | """
51 | with self._cond:
52 | while len(self._items) > self._min_size:
53 | try:
54 | ttl_watch, item = self._items.popleft()
55 | if ttl_watch.expired():
56 | self._on_expire and self._on_expire(item)
57 | self._current_size -= 1
58 | else:
59 | self._items.appendleft((ttl_watch, item))
60 | return
61 | except IndexError:
62 | break
63 |
64 | def put(self, item):
65 | """Return an item to the pool."""
66 | with self._cond:
67 | ttl_watch = timeutils.StopWatch(duration=self._item_ttl)
68 | ttl_watch.start()
69 | self._items.append((ttl_watch, item))
70 | self._cond.notify()
71 |
72 | def get(self, retry=None):
73 | """Return an item from the pool, when one is available.
74 |
75 | This may cause the calling thread to block.
76 | """
77 | with self._cond:
78 | while True:
79 | try:
80 | ttl_watch, item = self._items.pop()
81 | self.expire()
82 | return item
83 | except IndexError:
84 | pass
85 |
86 | if self._current_size < self._max_size:
87 | self._current_size += 1
88 | break
89 |
90 | LOG.warning("Connection pool limit exceeded: "
91 | "current size %s surpasses max "
92 | "configured rpc_conn_pool_size %s",
93 | self._current_size, self._max_size)
94 | self._cond.wait()
95 |
96 | # We've grabbed a slot and dropped the lock, now do the creation
97 | try:
98 | return self.create(retry=retry)
99 | except Exception:
100 | with self._cond:
101 | self._current_size -= 1
102 | raise
103 |
104 | def iter_free(self):
105 | """Iterate over free items."""
106 | while True:
107 | try:
108 | _, item = self._items.pop()
109 | yield item
110 | except IndexError:
111 | return
112 |
113 | @abc.abstractmethod
114 | def create(self, retry=None):
115 | """Construct a new item."""
116 |
117 |
118 | class ConnectionPool(Pool):
119 | """Class that implements a Pool of Connections."""
120 |
121 | def __init__(self, conf, max_size, min_size, ttl, url, connection_cls):
122 | self.connection_cls = connection_cls
123 | self.conf = conf
124 | self.url = url
125 | super().__init__(max_size, min_size, ttl,
126 | self._on_expire)
127 |
128 | def _on_expire(self, connection):
129 | connection.close()
130 | LOG.debug("Idle connection has expired and been closed."
131 | " Pool size: %d" % len(self._items))
132 |
133 | def create(self, purpose=common.PURPOSE_SEND, retry=None):
134 | LOG.debug('Pool creating new connection')
135 | return self.connection_cls(self.conf, self.url, purpose, retry=retry)
136 |
137 | def empty(self):
138 | for item in self.iter_free():
139 | item.close()
140 |
--------------------------------------------------------------------------------
/oslo_messaging/_metrics/__init__.py:
--------------------------------------------------------------------------------
1 | # Copyright 2020 LINE Corp.
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the 'License'); you may
4 | # not use this file except in compliance with the License. You may obtain
5 | # a copy of the License at
6 | #
7 | # http://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an 'AS IS' BASIS, WITHOUT
11 | # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12 | # License for the specific language governing permissions and limitations
13 | # under the License.
14 | __all__ = [
15 | 'MetricsCollectorClient',
16 | 'get_collector',
17 | 'measure_metrics',
18 | ]
19 |
20 | from .client import *
21 |
--------------------------------------------------------------------------------
/oslo_messaging/_utils.py:
--------------------------------------------------------------------------------
1 | # Copyright 2013 Red Hat, Inc.
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License"); you may
4 | # not use this file except in compliance with the License. You may obtain
5 | # a copy of the License at
6 | #
7 | # http://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11 | # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12 | # License for the specific language governing permissions and limitations
13 | # under the License.
14 |
15 | import logging
16 | import queue
17 | import threading
18 |
19 | from oslo_utils import eventletutils
20 | from oslo_utils import importutils
21 |
22 | LOG = logging.getLogger(__name__)
23 |
24 | eventlet = importutils.try_import('eventlet')
25 | if eventlet and eventletutils.is_monkey_patched("thread"):
26 | # Here we initialize module with the native python threading module
27 | # if it was already monkey patched by eventlet/greenlet.
28 | stdlib_threading = eventlet.patcher.original('threading')
29 | stdlib_queue = eventlet.patcher.original('queue')
30 | else:
31 | # Manage the case where we run this driver in a non patched environment
32 | # and where user even so configure the driver to run heartbeat through
33 | # a python thread, if we don't do that when the heartbeat will start
34 | # we will facing an issue by trying to override the threading module.
35 | stdlib_threading = threading
36 | stdlib_queue = queue
37 |
38 |
39 | def version_is_compatible(imp_version, version):
40 | """Determine whether versions are compatible.
41 |
42 | :param imp_version: The version implemented
43 | :param version: The version requested by an incoming message.
44 | """
45 | if imp_version is None:
46 | return True
47 |
48 | if version is None:
49 | return False
50 |
51 | version_parts = version.split('.')
52 | imp_version_parts = imp_version.split('.')
53 | try:
54 | rev = version_parts[2]
55 | except IndexError:
56 | rev = 0
57 | try:
58 | imp_rev = imp_version_parts[2]
59 | except IndexError:
60 | imp_rev = 0
61 |
62 | if int(version_parts[0]) != int(imp_version_parts[0]): # Major
63 | return False
64 | if int(version_parts[1]) > int(imp_version_parts[1]): # Minor
65 | return False
66 | if (int(version_parts[1]) == int(imp_version_parts[1]) and
67 | int(rev) > int(imp_rev)): # Revision
68 | return False
69 | return True
70 |
71 |
72 | class DummyLock:
73 | def acquire(self):
74 | pass
75 |
76 | def release(self):
77 | pass
78 |
79 | def __enter__(self):
80 | self.acquire()
81 |
82 | def __exit__(self, type, value, traceback):
83 | self.release()
84 |
85 |
86 | def get_executor_with_context():
87 | if eventletutils.is_monkey_patched('thread'):
88 | LOG.debug("Threading is patched, using an eventlet executor")
89 | return 'eventlet'
90 | LOG.debug("Using a threading executor")
91 | return 'threading'
92 |
--------------------------------------------------------------------------------
/oslo_messaging/conffixture.py:
--------------------------------------------------------------------------------
1 | # Copyright 2013 Red Hat, Inc.
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License"); you may
4 | # not use this file except in compliance with the License. You may obtain
5 | # a copy of the License at
6 | #
7 | # http://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11 | # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12 | # License for the specific language governing permissions and limitations
13 | # under the License.
14 |
15 | import sys
16 |
17 | import fixtures
18 | from functools import wraps
19 |
20 | __all__ = ['ConfFixture']
21 |
22 |
23 | def _import_opts(conf, module, opts, group=None):
24 | __import__(module)
25 | conf.register_opts(getattr(sys.modules[module], opts), group=group)
26 |
27 |
28 | class ConfFixture(fixtures.Fixture):
29 |
30 | """Tweak configuration options for unit testing.
31 |
32 | oslo.messaging registers a number of configuration options, but rather than
33 | directly referencing those options, users of the API should use this
34 | interface for querying and overriding certain configuration options.
35 |
36 | An example usage::
37 |
38 | self.messaging_conf = self.useFixture(messaging.ConfFixture(cfg.CONF))
39 | self.messaging_conf.transport_url = 'fake:/'
40 |
41 | :param conf: a ConfigOpts instance
42 | :type conf: oslo.config.cfg.ConfigOpts
43 | :param transport_url: override default transport_url value
44 | :type transport_url: str
45 | """
46 |
47 | def __init__(self, conf, transport_url=None):
48 | self.conf = conf
49 | _import_opts(self.conf,
50 | 'oslo_messaging._drivers.impl_rabbit', 'rabbit_opts',
51 | 'oslo_messaging_rabbit')
52 | _import_opts(self.conf,
53 | 'oslo_messaging._drivers.amqp', 'amqp_opts',
54 | 'oslo_messaging_rabbit')
55 | _import_opts(self.conf, 'oslo_messaging.rpc.client', '_client_opts')
56 | _import_opts(self.conf, 'oslo_messaging.transport', '_transport_opts')
57 | _import_opts(self.conf, 'oslo_messaging.rpc.dispatcher',
58 | '_dispatcher_opts')
59 | _import_opts(self.conf,
60 | 'oslo_messaging.notify.notifier',
61 | '_notifier_opts',
62 | 'oslo_messaging_notifications')
63 | _import_opts(self.conf,
64 | 'oslo_messaging._metrics.client',
65 | 'oslo_messaging_metrics',
66 | 'oslo_messaging_metrics')
67 |
68 | if transport_url is not None:
69 | self.transport_url = transport_url
70 |
71 | def _setup_decorator(self):
72 | # Support older test cases that still use the set_override
73 | # with the old config key names
74 | def decorator_for_set_override(wrapped_function):
75 | @wraps(wrapped_function)
76 | def _wrapper(*args, **kwargs):
77 | group = 'oslo_messaging_notifications'
78 | if args[0] == 'notification_driver':
79 | args = ('driver', args[1], group)
80 | elif args[0] == 'notification_transport_url':
81 | args = ('transport_url', args[1], group)
82 | elif args[0] == 'notification_topics':
83 | args = ('topics', args[1], group)
84 | return wrapped_function(*args, **kwargs)
85 | _wrapper.wrapped = wrapped_function
86 | return _wrapper
87 |
88 | def decorator_for_clear_override(wrapped_function):
89 | @wraps(wrapped_function)
90 | def _wrapper(*args, **kwargs):
91 | group = 'oslo_messaging_notifications'
92 | if args[0] == 'notification_driver':
93 | args = ('driver', group)
94 | elif args[0] == 'notification_transport_url':
95 | args = ('transport_url', group)
96 | elif args[0] == 'notification_topics':
97 | args = ('topics', group)
98 | return wrapped_function(*args, **kwargs)
99 | _wrapper.wrapped = wrapped_function
100 | return _wrapper
101 |
102 | if not hasattr(self.conf.set_override, 'wrapped'):
103 | self.conf.set_override = decorator_for_set_override(
104 | self.conf.set_override)
105 | if not hasattr(self.conf.clear_override, 'wrapped'):
106 | self.conf.clear_override = decorator_for_clear_override(
107 | self.conf.clear_override)
108 |
109 | def _teardown_decorator(self):
110 | if hasattr(self.conf.set_override, 'wrapped'):
111 | self.conf.set_override = self.conf.set_override.wrapped
112 | if hasattr(self.conf.clear_override, 'wrapped'):
113 | self.conf.clear_override = self.conf.clear_override.wrapped
114 |
115 | def setUp(self):
116 | super().setUp()
117 | self._setup_decorator()
118 | self.addCleanup(self._teardown_decorator)
119 | self.addCleanup(self.conf.reset)
120 |
121 | @property
122 | def transport_url(self):
123 | """The transport url"""
124 | return self.conf.transport_url
125 |
126 | @transport_url.setter
127 | def transport_url(self, value):
128 | self.conf.set_override('transport_url', value)
129 |
130 | @property
131 | def response_timeout(self):
132 | """Default number of seconds to wait for a response from a call."""
133 | return self.conf.rpc_response_timeout
134 |
135 | @response_timeout.setter
136 | def response_timeout(self, value):
137 | self.conf.set_override('rpc_response_timeout', value)
138 |
--------------------------------------------------------------------------------
/oslo_messaging/dispatcher.py:
--------------------------------------------------------------------------------
1 | # Licensed under the Apache License, Version 2.0 (the "License"); you may
2 | # not use this file except in compliance with the License. You may obtain
3 | # a copy of the License at
4 | #
5 | # http://www.apache.org/licenses/LICENSE-2.0
6 | #
7 | # Unless required by applicable law or agreed to in writing, software
8 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
9 | # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
10 | # License for the specific language governing permissions and limitations
11 | # under the License.
12 |
13 | import abc
14 |
15 |
16 | __all__ = [
17 | "DispatcherBase"
18 | ]
19 |
20 |
21 | class DispatcherBase(metaclass=abc.ABCMeta):
22 | "Base class for dispatcher"
23 |
24 | @abc.abstractmethod
25 | def dispatch(self, incoming):
26 | """Dispatch incoming messages to the endpoints and return result
27 |
28 | :param incoming: incoming object for dispatching to the endpoint
29 | :type incoming: object, depends on endpoint type
30 | """
31 |
--------------------------------------------------------------------------------
/oslo_messaging/exceptions.py:
--------------------------------------------------------------------------------
1 | # Copyright 2013 Red Hat, Inc.
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License"); you may
4 | # not use this file except in compliance with the License. You may obtain
5 | # a copy of the License at
6 | #
7 | # http://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11 | # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12 | # License for the specific language governing permissions and limitations
13 | # under the License.
14 |
15 | __all__ = ['MessagingException', 'MessagingTimeout', 'MessageDeliveryFailure',
16 | 'InvalidTarget', 'MessageUndeliverable']
17 |
18 |
19 | class MessagingException(Exception):
20 | """Base class for exceptions."""
21 |
22 |
23 | class MessagingTimeout(MessagingException):
24 | """Raised if message sending times out."""
25 |
26 |
27 | class MessageDeliveryFailure(MessagingException):
28 | """Raised if message sending failed after the asked retry."""
29 |
30 |
31 | class InvalidTarget(MessagingException, ValueError):
32 | """Raised if a target does not meet certain pre-conditions."""
33 |
34 | def __init__(self, msg, target):
35 | msg = msg + ":" + str(target)
36 | super().__init__(msg)
37 | self.target = target
38 |
39 |
40 | class MessageUndeliverable(Exception):
41 | """Raised if message is not routed with mandatory flag"""
42 |
43 | def __init__(self, exception, exchange, routing_key, message):
44 | super().__init__()
45 | self.exception = exception
46 | self.exchange = exchange
47 | self.routing_key = routing_key
48 | self.message = message
49 |
50 |
51 | class ConfigurationError(Exception):
52 | """Raised when messaging isn't configured correctly."""
53 |
--------------------------------------------------------------------------------
/oslo_messaging/hacking/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/openstack/oslo.messaging/510688d8ddc807242fe9a36532dd03ba3c2d4ad5/oslo_messaging/hacking/__init__.py
--------------------------------------------------------------------------------
/oslo_messaging/notify/__init__.py:
--------------------------------------------------------------------------------
1 | # Copyright 2013 Red Hat, Inc.
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License"); you may
4 | # not use this file except in compliance with the License. You may obtain
5 | # a copy of the License at
6 | #
7 | # http://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11 | # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12 | # License for the specific language governing permissions and limitations
13 | # under the License.
14 |
15 | __all__ = ['Notifier',
16 | 'LoggingNotificationHandler',
17 | 'get_notification_transport',
18 | 'get_notification_listener',
19 | 'get_batch_notification_listener',
20 | 'NotificationResult',
21 | 'NotificationFilter',
22 | 'PublishErrorsHandler',
23 | 'LoggingErrorNotificationHandler']
24 |
25 | from .filter import NotificationFilter
26 | from .notifier import *
27 | from .listener import *
28 | from .log_handler import *
29 | from .logger import *
30 | from .dispatcher import NotificationResult
31 |
--------------------------------------------------------------------------------
/oslo_messaging/notify/_impl_log.py:
--------------------------------------------------------------------------------
1 | # Copyright 2011 OpenStack Foundation.
2 | # All Rights Reserved.
3 | # Copyright 2013 Red Hat, Inc.
4 | #
5 | # Licensed under the Apache License, Version 2.0 (the "License"); you may
6 | # not use this file except in compliance with the License. You may obtain
7 | # a copy of the License at
8 | #
9 | # http://www.apache.org/licenses/LICENSE-2.0
10 | #
11 | # Unless required by applicable law or agreed to in writing, software
12 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
13 | # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
14 | # License for the specific language governing permissions and limitations
15 | # under the License.
16 |
17 | import logging
18 | import warnings
19 |
20 | from oslo_serialization import jsonutils
21 | from oslo_utils import strutils
22 |
23 | from oslo_messaging.notify import notifier
24 |
25 |
26 | class LogDriver(notifier.Driver):
27 |
28 | "Publish notifications via Python logging infrastructure."
29 |
30 | # NOTE(dhellmann): For backwards-compatibility with configurations
31 | # that may have modified the settings for this logger using a
32 | # configuration file, we keep the name
33 | # 'oslo.messaging.notification' even though the package is now
34 | # 'oslo_messaging'.
35 | LOGGER_BASE = 'oslo.messaging.notification'
36 |
37 | def notify(self, ctxt, message, priority, retry):
38 | logger = logging.getLogger('{}.{}'.format(self.LOGGER_BASE,
39 | message['event_type']))
40 | method = getattr(logger, priority.lower(), None)
41 | if method:
42 | method(jsonutils.dumps(strutils.mask_dict_password(message)))
43 | else:
44 | warnings.warn('Unable to log message as notify cannot find a '
45 | 'logger with the priority specified '
46 | '%s' % priority.lower())
47 |
--------------------------------------------------------------------------------
/oslo_messaging/notify/_impl_noop.py:
--------------------------------------------------------------------------------
1 | # Copyright 2011 OpenStack Foundation.
2 | # All Rights Reserved.
3 | # Copyright 2013 Red Hat, Inc.
4 | #
5 | # Licensed under the Apache License, Version 2.0 (the "License"); you may
6 | # not use this file except in compliance with the License. You may obtain
7 | # a copy of the License at
8 | #
9 | # http://www.apache.org/licenses/LICENSE-2.0
10 | #
11 | # Unless required by applicable law or agreed to in writing, software
12 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
13 | # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
14 | # License for the specific language governing permissions and limitations
15 | # under the License.
16 |
17 | from oslo_messaging.notify import notifier
18 |
19 |
20 | class NoOpDriver(notifier.Driver):
21 |
22 | def notify(self, ctxt, message, priority, retry):
23 | pass
24 |
--------------------------------------------------------------------------------
/oslo_messaging/notify/_impl_routing.py:
--------------------------------------------------------------------------------
1 | # Copyright 2014 Rackspace Hosting
2 | # All Rights Reserved.
3 | #
4 | # Licensed under the Apache License, Version 2.0 (the "License"); you may
5 | # not use this file except in compliance with the License. You may obtain
6 | # a copy of the License at
7 | #
8 | # http://www.apache.org/licenses/LICENSE-2.0
9 | #
10 | # Unless required by applicable law or agreed to in writing, software
11 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12 | # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13 | # License for the specific language governing permissions and limitations
14 | # under the License.
15 |
16 | import fnmatch
17 | import logging
18 |
19 | from oslo_config import cfg
20 | from stevedore import dispatch
21 | import yaml
22 |
23 | from oslo_messaging.notify import notifier
24 |
25 |
26 | LOG = logging.getLogger(__name__)
27 |
28 | router_config = cfg.StrOpt('routing_config', default='',
29 | help='RoutingNotifier configuration file location.')
30 |
31 | CONF = cfg.CONF
32 | CONF.register_opt(router_config, group='oslo_messaging_notifications')
33 |
34 |
35 | class RoutingDriver(notifier.Driver):
36 | NOTIFIER_PLUGIN_NAMESPACE = 'oslo.messaging.notify.drivers'
37 |
38 | plugin_manager = None
39 | routing_groups = None # The routing groups from the config file.
40 | used_drivers = None # Used driver names, extracted from config file.
41 |
42 | def _should_load_plugin(self, ext, *args, **kwargs):
43 | # Hack to keep stevedore from circular importing since these
44 | # endpoints are used for different purposes.
45 | if ext.name == 'routing':
46 | return False
47 | return ext.name in self.used_drivers
48 |
49 | def _get_notifier_config_file(self, filename):
50 | """Broken out for testing."""
51 | return open(filename)
52 |
53 | def _load_notifiers(self):
54 | """One-time load of notifier config file."""
55 | self.routing_groups = {}
56 | self.used_drivers = set()
57 | filename = CONF.oslo_messaging_notifications.routing_config
58 | if not filename:
59 | return
60 |
61 | # Infer which drivers are used from the config file.
62 | self.routing_groups = yaml.safe_load(
63 | self._get_notifier_config_file(filename))
64 | if not self.routing_groups:
65 | self.routing_groups = {} # In case we got None from load()
66 | return
67 |
68 | for group in self.routing_groups.values():
69 | self.used_drivers.update(group.keys())
70 |
71 | LOG.debug('loading notifiers from %s', self.NOTIFIER_PLUGIN_NAMESPACE)
72 | self.plugin_manager = dispatch.DispatchExtensionManager(
73 | namespace=self.NOTIFIER_PLUGIN_NAMESPACE,
74 | check_func=self._should_load_plugin,
75 | invoke_on_load=True,
76 | invoke_args=None)
77 | if not list(self.plugin_manager):
78 | LOG.warning("Failed to load any notifiers for %s",
79 | self.NOTIFIER_PLUGIN_NAMESPACE)
80 |
81 | def _get_drivers_for_message(self, group, event_type, priority):
82 | """Which drivers should be called for this event_type
83 | or priority.
84 | """
85 | accepted_drivers = set()
86 |
87 | for driver, rules in group.items():
88 | checks = []
89 | for key, patterns in rules.items():
90 | if key == 'accepted_events':
91 | c = [fnmatch.fnmatch(event_type, p)
92 | for p in patterns]
93 | checks.append(any(c))
94 | if key == 'accepted_priorities':
95 | c = [fnmatch.fnmatch(priority, p.lower())
96 | for p in patterns]
97 | checks.append(any(c))
98 | if all(checks):
99 | accepted_drivers.add(driver)
100 |
101 | return list(accepted_drivers)
102 |
103 | def _filter_func(self, ext, context, message, priority, retry,
104 | accepted_drivers):
105 | """True/False if the driver should be called for this message.
106 | """
107 | # context is unused here, but passed in by map()
108 | return ext.name in accepted_drivers
109 |
110 | def _call_notify(self, ext, context, message, priority, retry,
111 | accepted_drivers):
112 | """Emit the notification.
113 | """
114 | # accepted_drivers is passed in as a result of the map() function
115 | LOG.info("Routing '%(event)s' notification to '%(driver)s' "
116 | "driver",
117 | {'event': message.get('event_type'), 'driver': ext.name})
118 | ext.obj.notify(context, message, priority, retry)
119 |
120 | def notify(self, context, message, priority, retry):
121 | if not self.plugin_manager:
122 | self._load_notifiers()
123 |
124 | # Fail if these aren't present ...
125 | event_type = message['event_type']
126 |
127 | accepted_drivers = set()
128 | for group in self.routing_groups.values():
129 | accepted_drivers.update(
130 | self._get_drivers_for_message(group, event_type,
131 | priority.lower()))
132 | self.plugin_manager.map(self._filter_func, self._call_notify, context,
133 | message, priority, retry,
134 | list(accepted_drivers))
135 |
--------------------------------------------------------------------------------
/oslo_messaging/notify/_impl_test.py:
--------------------------------------------------------------------------------
1 | # Copyright 2011 OpenStack Foundation.
2 | # All Rights Reserved.
3 | # Copyright 2013 Red Hat, Inc.
4 | #
5 | # Licensed under the Apache License, Version 2.0 (the "License"); you may
6 | # not use this file except in compliance with the License. You may obtain
7 | # a copy of the License at
8 | #
9 | # http://www.apache.org/licenses/LICENSE-2.0
10 | #
11 | # Unless required by applicable law or agreed to in writing, software
12 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
13 | # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
14 | # License for the specific language governing permissions and limitations
15 | # under the License.
16 |
17 | from oslo_messaging.notify import notifier
18 |
19 | NOTIFICATIONS = []
20 |
21 |
22 | def reset():
23 | "Clear out the list of recorded notifications."
24 | global NOTIFICATIONS
25 | NOTIFICATIONS = []
26 |
27 |
28 | class TestDriver(notifier.Driver):
29 |
30 | "Store notifications in memory for test verification."
31 |
32 | def notify(self, ctxt, message, priority, retry):
33 | NOTIFICATIONS.append((ctxt, message, priority, retry))
34 |
--------------------------------------------------------------------------------
/oslo_messaging/notify/dispatcher.py:
--------------------------------------------------------------------------------
1 | # Copyright 2011 OpenStack Foundation.
2 | # All Rights Reserved.
3 | # Copyright 2013 eNovance
4 | #
5 | # Licensed under the Apache License, Version 2.0 (the "License"); you may
6 | # not use this file except in compliance with the License. You may obtain
7 | # a copy of the License at
8 | #
9 | # http://www.apache.org/licenses/LICENSE-2.0
10 | #
11 | # Unless required by applicable law or agreed to in writing, software
12 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
13 | # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
14 | # License for the specific language governing permissions and limitations
15 | # under the License.
16 |
17 | import itertools
18 | import logging
19 | import operator
20 |
21 | from oslo_messaging import dispatcher
22 | from oslo_messaging import serializer as msg_serializer
23 |
24 |
25 | LOG = logging.getLogger(__name__)
26 |
27 | PRIORITIES = ['audit', 'debug', 'info', 'warn', 'error', 'critical', 'sample']
28 |
29 |
30 | class NotificationResult:
31 | HANDLED = 'handled'
32 | REQUEUE = 'requeue'
33 |
34 |
35 | class NotificationDispatcher(dispatcher.DispatcherBase):
36 | def __init__(self, endpoints, serializer):
37 |
38 | self.endpoints = endpoints
39 | self.serializer = serializer or msg_serializer.NoOpSerializer()
40 |
41 | self._callbacks_by_priority = {}
42 | for endpoint, prio in itertools.product(endpoints, PRIORITIES):
43 | if hasattr(endpoint, prio):
44 | method = getattr(endpoint, prio)
45 | screen = getattr(endpoint, 'filter_rule', None)
46 | self._callbacks_by_priority.setdefault(prio, []).append(
47 | (screen, method))
48 |
49 | @property
50 | def supported_priorities(self):
51 | return self._callbacks_by_priority.keys()
52 |
53 | def dispatch(self, incoming):
54 | """Dispatch notification messages to the appropriate endpoint method.
55 | """
56 | priority, raw_message, message = self._extract_user_message(incoming)
57 |
58 | if priority not in PRIORITIES:
59 | LOG.warning('Unknown priority "%s"', priority)
60 | return
61 |
62 | for screen, callback in self._callbacks_by_priority.get(priority,
63 | []):
64 | if screen and not screen.match(message["ctxt"],
65 | message["publisher_id"],
66 | message["event_type"],
67 | message["metadata"],
68 | message["payload"]):
69 | continue
70 |
71 | ret = self._exec_callback(callback, message)
72 | if ret == NotificationResult.REQUEUE:
73 | return ret
74 | return NotificationResult.HANDLED
75 |
76 | def _exec_callback(self, callback, message):
77 | try:
78 | return callback(message["ctxt"],
79 | message["publisher_id"],
80 | message["event_type"],
81 | message["payload"],
82 | message["metadata"])
83 | except Exception:
84 | LOG.exception("Callback raised an exception.")
85 | return NotificationResult.REQUEUE
86 |
87 | def _extract_user_message(self, incoming):
88 | ctxt = self.serializer.deserialize_context(incoming.ctxt)
89 | message = incoming.message
90 |
91 | publisher_id = message.get('publisher_id')
92 | event_type = message.get('event_type')
93 | metadata = {
94 | 'message_id': message.get('message_id'),
95 | 'timestamp': message.get('timestamp')
96 | }
97 | priority = message.get('priority', '').lower()
98 | payload = self.serializer.deserialize_entity(ctxt,
99 | message.get('payload'))
100 | return priority, incoming, dict(ctxt=ctxt,
101 | publisher_id=publisher_id,
102 | event_type=event_type,
103 | payload=payload,
104 | metadata=metadata)
105 |
106 |
107 | class BatchNotificationDispatcher(NotificationDispatcher):
108 | """A message dispatcher which understands Notification messages.
109 |
110 | A MessageHandlingServer is constructed by passing a callable dispatcher
111 | which is invoked with a list of message dictionaries each time 'batch_size'
112 | messages are received or 'batch_timeout' seconds is reached.
113 | """
114 |
115 | def dispatch(self, incoming):
116 | """Dispatch notification messages to the appropriate endpoint method.
117 | """
118 |
119 | messages_grouped = itertools.groupby(sorted(
120 | (self._extract_user_message(m) for m in incoming),
121 | key=operator.itemgetter(0)), operator.itemgetter(0))
122 |
123 | requeues = set()
124 | for priority, messages in messages_grouped:
125 | __, raw_messages, messages = zip(*messages)
126 | if priority not in PRIORITIES:
127 | LOG.warning('Unknown priority "%s"', priority)
128 | continue
129 | for screen, callback in self._callbacks_by_priority.get(priority,
130 | []):
131 | if screen:
132 | filtered_messages = [message for message in messages
133 | if screen.match(
134 | message["ctxt"],
135 | message["publisher_id"],
136 | message["event_type"],
137 | message["metadata"],
138 | message["payload"])]
139 | else:
140 | filtered_messages = list(messages)
141 |
142 | if not filtered_messages:
143 | continue
144 |
145 | ret = self._exec_callback(callback, filtered_messages)
146 | if ret == NotificationResult.REQUEUE:
147 | requeues.update(raw_messages)
148 | break
149 | return requeues
150 |
151 | def _exec_callback(self, callback, messages):
152 | try:
153 | return callback(messages)
154 | except Exception:
155 | LOG.exception("Callback raised an exception.")
156 | return NotificationResult.REQUEUE
157 |
--------------------------------------------------------------------------------
/oslo_messaging/notify/filter.py:
--------------------------------------------------------------------------------
1 | #
2 | # Copyright 2013 eNovance
3 | #
4 | # Licensed under the Apache License, Version 2.0 (the "License"); you may
5 | # not use this file except in compliance with the License. You may obtain
6 | # a copy of the License at
7 | #
8 | # http://www.apache.org/licenses/LICENSE-2.0
9 | #
10 | # Unless required by applicable law or agreed to in writing, software
11 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12 | # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13 | # License for the specific language governing permissions and limitations
14 | # under the License.
15 |
16 | import re
17 |
18 |
19 | class NotificationFilter:
20 |
21 | r"""Filter notification messages
22 |
23 | The NotificationFilter class is used to filter notifications that an
24 | endpoint will received.
25 |
26 | The notification can be filter on different fields: context,
27 | publisher_id, event_type, metadata and payload.
28 |
29 | The filter is done via a regular expression
30 |
31 | filter_rule = NotificationFilter(
32 | publisher_id='^compute.*',
33 | context={'tenant_id': '^5f643cfc-664b-4c69-8000-ce2ed7b08216$',
34 | 'roles': 'private'},
35 | event_type='^compute\.instance\..*',
36 | metadata={'timestamp': 'Aug'},
37 | payload={'state': '^active$')
38 |
39 | """
40 |
41 | def __init__(self, context=None, publisher_id=None, event_type=None,
42 | metadata=None, payload=None):
43 | self._regex_publisher_id = None
44 | self._regex_event_type = None
45 |
46 | if publisher_id is not None:
47 | self._regex_publisher_id = re.compile(publisher_id)
48 | if event_type is not None:
49 | self._regex_event_type = re.compile(event_type)
50 | self._regexs_context = self._build_regex_dict(context)
51 | self._regexs_metadata = self._build_regex_dict(metadata)
52 | self._regexs_payload = self._build_regex_dict(payload)
53 |
54 | @staticmethod
55 | def _build_regex_dict(regex_list):
56 | if regex_list is None:
57 | return {}
58 | return {k: re.compile(regex_list[k]) for k in regex_list}
59 |
60 | @staticmethod
61 | def _check_for_single_mismatch(data, regex):
62 | if regex is None:
63 | return False
64 | if not isinstance(data, str):
65 | return True
66 | if not regex.match(data):
67 | return True
68 | return False
69 |
70 | @classmethod
71 | def _check_for_mismatch(cls, data, regex):
72 | if isinstance(regex, dict):
73 | for k in regex:
74 | if k not in data:
75 | return True
76 | if cls._check_for_single_mismatch(data[k], regex[k]):
77 | return True
78 | return False
79 | else:
80 | return cls._check_for_single_mismatch(data, regex)
81 |
82 | def match(self, context, publisher_id, event_type, metadata, payload):
83 | if (self._check_for_mismatch(publisher_id, self._regex_publisher_id) or
84 | self._check_for_mismatch(event_type, self._regex_event_type) or
85 | self._check_for_mismatch(context, self._regexs_context) or
86 | self._check_for_mismatch(metadata, self._regexs_metadata) or
87 | self._check_for_mismatch(payload, self._regexs_payload)):
88 | return False
89 | return True
90 |
--------------------------------------------------------------------------------
/oslo_messaging/notify/log_handler.py:
--------------------------------------------------------------------------------
1 | # Licensed under the Apache License, Version 2.0 (the "License"); you may
2 | # not use this file except in compliance with the License. You may obtain
3 | # a copy of the License at
4 | #
5 | # http://www.apache.org/licenses/LICENSE-2.0
6 | #
7 | # Unless required by applicable law or agreed to in writing, software
8 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
9 | # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
10 | # License for the specific language governing permissions and limitations
11 | # under the License.
12 |
13 | import logging
14 |
15 | from oslo_config import cfg
16 |
17 |
18 | class LoggingErrorNotificationHandler(logging.Handler):
19 | def __init__(self, *args, **kwargs):
20 | # NOTE(dhellmann): Avoid a cyclical import by doing this one
21 | # at runtime.
22 | import oslo_messaging
23 | logging.Handler.__init__(self, *args, **kwargs)
24 | self._transport = oslo_messaging.get_notification_transport(cfg.CONF)
25 | self._notifier = oslo_messaging.Notifier(
26 | self._transport,
27 | publisher_id='error.publisher')
28 |
29 | def emit(self, record):
30 | conf = self._transport.conf
31 | # NOTE(bnemec): Notifier registers this opt with the transport.
32 | if ('log' in conf.oslo_messaging_notifications.driver):
33 | # NOTE(lbragstad): If we detect that log is one of the
34 | # notification drivers, then return. This protects from infinite
35 | # recursion where something bad happens, it gets logged, the log
36 | # handler sends a notification, and the log_notifier sees the
37 | # notification and logs it.
38 | return
39 | self._notifier.error({},
40 | 'error_notification',
41 | dict(error=record.msg))
42 |
43 |
44 | PublishErrorsHandler = LoggingErrorNotificationHandler
45 |
--------------------------------------------------------------------------------
/oslo_messaging/notify/logger.py:
--------------------------------------------------------------------------------
1 | # Copyright 2013 eNovance
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License"); you may
4 | # not use this file except in compliance with the License. You may obtain
5 | # a copy of the License at
6 | #
7 | # http://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11 | # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12 | # License for the specific language governing permissions and limitations
13 | # under the License.
14 | """
15 | Driver for the Python logging package that sends log records as a notification.
16 | """
17 | import logging
18 |
19 | from oslo_config import cfg
20 |
21 | from oslo_messaging.notify import notifier
22 |
23 |
24 | class LoggingNotificationHandler(logging.Handler):
25 | """Handler for logging to the messaging notification system.
26 |
27 | Each time the application logs a message using the :py:mod:`logging`
28 | module, it will be sent as a notification. The severity used for the
29 | notification will be the same as the one used for the log record.
30 |
31 | This can be used into a Python logging configuration this way::
32 |
33 | [handler_notifier]
34 | class=oslo_messaging.LoggingNotificationHandler
35 | level=ERROR
36 | args=('rabbit:///')
37 |
38 | """
39 |
40 | CONF = cfg.CONF
41 | """Default configuration object used, subclass this class if you want to
42 | use another one.
43 |
44 | """
45 |
46 | def __init__(self, url, publisher_id=None, driver=None,
47 | topic=None, serializer=None):
48 | self.notifier = notifier.Notifier(
49 | notifier.get_notification_transport(self.CONF, url),
50 | publisher_id, driver, serializer() if serializer else None,
51 | topics=(topic if isinstance(topic, list) or topic is None
52 | else [topic]))
53 | logging.Handler.__init__(self)
54 |
55 | def emit(self, record):
56 | """Emit the log record to the messaging notification system.
57 |
58 | :param record: A log record to emit.
59 |
60 | """
61 | method = getattr(self.notifier, record.levelname.lower(), None)
62 |
63 | if not method:
64 | return
65 |
66 | method(
67 | None,
68 | 'logrecord',
69 | {
70 | 'name': record.name,
71 | 'levelno': record.levelno,
72 | 'levelname': record.levelname,
73 | 'exc_info': record.exc_info,
74 | 'pathname': record.pathname,
75 | 'lineno': record.lineno,
76 | 'msg': record.getMessage(),
77 | 'funcName': record.funcName,
78 | 'thread': record.thread,
79 | 'processName': record.processName,
80 | 'process': record.process,
81 | 'extra': getattr(record, 'extra', None),
82 | }
83 | )
84 |
--------------------------------------------------------------------------------
/oslo_messaging/notify/messaging.py:
--------------------------------------------------------------------------------
1 | # Copyright 2011 OpenStack Foundation.
2 | # All Rights Reserved.
3 | # Copyright 2013 Red Hat, Inc.
4 | #
5 | # Licensed under the Apache License, Version 2.0 (the "License"); you may
6 | # not use this file except in compliance with the License. You may obtain
7 | # a copy of the License at
8 | #
9 | # http://www.apache.org/licenses/LICENSE-2.0
10 | #
11 | # Unless required by applicable law or agreed to in writing, software
12 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
13 | # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
14 | # License for the specific language governing permissions and limitations
15 | # under the License.
16 |
17 | """
18 | Notification drivers for sending notifications via messaging.
19 |
20 | The messaging drivers publish notification messages to notification
21 | listeners.
22 |
23 | In case of the rabbit backend the driver will block the notifier's thread
24 | until the notification message has been passed to the messaging transport.
25 | There is no guarantee that the notification message will be consumed by a
26 | notification listener.
27 |
28 | In case of the kafka backend the driver will not block the notifier's thread
29 | but return immediately. The driver will try to deliver the message in the
30 | background.
31 |
32 | Notification messages are sent 'at-most-once' - ensuring that they are not
33 | duplicated.
34 |
35 | If the connection to the messaging service is not active when a notification is
36 | sent the rabbit backend will block waiting for the connection to complete.
37 | If the connection fails to complete, the driver will try to re-establish that
38 | connection. By default this will continue indefinitely until the connection
39 | completes. However, the retry parameter can be used to have the notification
40 | send fail. In this case an error is logged and the notifier's thread is resumed
41 | without any error.
42 |
43 | If the connection to the messaging service is not active when a notification is
44 | sent the kafka backend will return immediately and the backend tries to
45 | establish the connection and deliver the messages in the background.
46 |
47 | """
48 |
49 | import logging
50 |
51 | import oslo_messaging
52 | from oslo_messaging.notify import notifier
53 |
54 | LOG = logging.getLogger(__name__)
55 |
56 |
57 | class MessagingDriver(notifier.Driver):
58 |
59 | """Send notifications using the 1.0 message format.
60 |
61 | This driver sends notifications over the configured messaging transport,
62 | but without any message envelope (also known as message format 1.0).
63 |
64 | This driver should only be used in cases where there are existing consumers
65 | deployed which do not support the 2.0 message format.
66 | """
67 |
68 | def __init__(self, conf, topics, transport, version=1.0):
69 | super().__init__(conf, topics, transport)
70 | self.version = version
71 |
72 | def notify(self, ctxt, message, priority, retry):
73 | priority = priority.lower()
74 | for topic in self.topics:
75 | target = oslo_messaging.Target(
76 | topic='{}.{}'.format(topic, priority))
77 | try:
78 | self.transport._send_notification(target, ctxt, message,
79 | version=self.version,
80 | retry=retry)
81 | except Exception:
82 | LOG.exception("Could not send notification to %(topic)s. "
83 | "Payload=%(message)s",
84 | {'topic': topic, 'message': message})
85 |
86 |
87 | class MessagingV2Driver(MessagingDriver):
88 |
89 | "Send notifications using the 2.0 message format."
90 |
91 | def __init__(self, conf, **kwargs):
92 | super().__init__(conf, version=2.0, **kwargs)
93 |
--------------------------------------------------------------------------------
/oslo_messaging/notify/middleware.py:
--------------------------------------------------------------------------------
1 | # Copyright (c) 2013-2014 eNovance
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License"); you may
4 | # not use this file except in compliance with the License. You may obtain
5 | # a copy of the License at
6 | #
7 | # http://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11 | # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12 | # License for the specific language governing permissions and limitations
13 | # under the License.
14 |
15 | """
16 | Send notifications on request
17 |
18 | """
19 | import logging
20 | import os.path
21 | import sys
22 | import traceback as tb
23 |
24 | from oslo_config import cfg
25 | from oslo_middleware import base
26 | import webob.dec
27 |
28 | import oslo_messaging
29 | from oslo_messaging import notify
30 |
31 | LOG = logging.getLogger(__name__)
32 |
33 |
34 | def log_and_ignore_error(fn):
35 | def wrapped(*args, **kwargs):
36 | try:
37 | return fn(*args, **kwargs)
38 | except Exception as e:
39 | LOG.exception('An exception occurred processing '
40 | 'the API call: %s ', e)
41 | return wrapped
42 |
43 |
44 | class RequestNotifier(base.Middleware):
45 | """Send notification on request."""
46 |
47 | @classmethod
48 | def factory(cls, global_conf, **local_conf):
49 | """Factory method for paste.deploy."""
50 | conf = global_conf.copy()
51 | conf.update(local_conf)
52 |
53 | def _factory(app):
54 | return cls(app, **conf)
55 | return _factory
56 |
57 | def __init__(self, app, **conf):
58 | self.notifier = notify.Notifier(
59 | oslo_messaging.get_notification_transport(cfg.CONF,
60 | conf.get('url')),
61 | publisher_id=conf.get('publisher_id',
62 | os.path.basename(sys.argv[0])))
63 | self.service_name = conf.get('service_name')
64 | self.ignore_req_list = [x.upper().strip() for x in
65 | conf.get('ignore_req_list', '').split(',')]
66 | super().__init__(app)
67 |
68 | @staticmethod
69 | def environ_to_dict(environ):
70 | """Following PEP 333, server variables are lower case, so don't
71 | include them.
72 |
73 | """
74 | return {k: v for k, v in environ.items()
75 | if k.isupper() and k != 'HTTP_X_AUTH_TOKEN'}
76 |
77 | @log_and_ignore_error
78 | def process_request(self, request):
79 | request.environ['HTTP_X_SERVICE_NAME'] = \
80 | self.service_name or request.host
81 | payload = {
82 | 'request': self.environ_to_dict(request.environ),
83 | }
84 |
85 | self.notifier.info({},
86 | 'http.request',
87 | payload)
88 |
89 | @log_and_ignore_error
90 | def process_response(self, request, response,
91 | exception=None, traceback=None):
92 | payload = {
93 | 'request': self.environ_to_dict(request.environ),
94 | }
95 |
96 | if response:
97 | payload['response'] = {
98 | 'status': response.status,
99 | 'headers': response.headers,
100 | }
101 |
102 | if exception:
103 | payload['exception'] = {
104 | 'value': repr(exception),
105 | 'traceback': tb.format_tb(traceback)
106 | }
107 |
108 | self.notifier.info({},
109 | 'http.response',
110 | payload)
111 |
112 | @webob.dec.wsgify
113 | def __call__(self, req):
114 | if req.method in self.ignore_req_list:
115 | return req.get_response(self.application)
116 | else:
117 | self.process_request(req)
118 | try:
119 | response = req.get_response(self.application)
120 | except Exception:
121 | exc_type, value, traceback = sys.exc_info()
122 | self.process_response(req, None, value, traceback)
123 | raise
124 | else:
125 | self.process_response(req, response)
126 | return response
127 |
--------------------------------------------------------------------------------
/oslo_messaging/opts.py:
--------------------------------------------------------------------------------
1 | # Copyright 2014 Red Hat, Inc.
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License"); you may
4 | # not use this file except in compliance with the License. You may obtain
5 | # a copy of the License at
6 | #
7 | # http://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11 | # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12 | # License for the specific language governing permissions and limitations
13 | # under the License.
14 |
15 | import copy
16 | import itertools
17 |
18 | from oslo_messaging._drivers import amqp
19 | from oslo_messaging._drivers import impl_rabbit
20 | from oslo_messaging._drivers.kafka_driver import kafka_options
21 | from oslo_messaging.notify import notifier
22 | from oslo_messaging.rpc import client
23 | from oslo_messaging.rpc import dispatcher
24 | from oslo_messaging import server
25 | from oslo_messaging import transport
26 |
27 | __all__ = [
28 | 'list_opts'
29 | ]
30 |
31 | _global_opt_lists = [
32 | server._pool_opts,
33 | client._client_opts,
34 | transport._transport_opts,
35 | dispatcher._dispatcher_opts,
36 | ]
37 |
38 | _opts = [
39 | (None, list(itertools.chain(*_global_opt_lists))),
40 | ('oslo_messaging_notifications', notifier._notifier_opts),
41 | ('oslo_messaging_rabbit', list(
42 | itertools.chain(amqp.amqp_opts, impl_rabbit.rabbit_opts))),
43 | ('oslo_messaging_kafka', kafka_options.KAFKA_OPTS),
44 | ]
45 |
46 |
47 | def list_opts():
48 | """Return a list of oslo.config options available in the library.
49 |
50 | The returned list includes all oslo.config options which may be registered
51 | at runtime by the library.
52 |
53 | Each element of the list is a tuple. The first element is the name of the
54 | group under which the list of elements in the second element will be
55 | registered. A group name of None corresponds to the [DEFAULT] group in
56 | config files.
57 |
58 | This function is also discoverable via the 'oslo_messaging' entry point
59 | under the 'oslo.config.opts' namespace.
60 |
61 | The purpose of this is to allow tools like the Oslo sample config file
62 | generator to discover the options exposed to users by this library.
63 |
64 | :returns: a list of (group_name, opts) tuples
65 | """
66 | return [(g, copy.deepcopy(o)) for g, o in _opts]
67 |
68 |
69 | def set_defaults(conf, executor_thread_pool_size=None):
70 | """Set defaults for configuration variables.
71 |
72 | Overrides default options values.
73 |
74 | :param conf: Config instance specified to set default options in it. Using
75 | of instances instead of a global config object prevents conflicts between
76 | options declaration.
77 | :type conf: oslo.config.cfg.ConfigOpts instance.
78 |
79 | :keyword executor_thread_pool_size: Size of executor thread pool.
80 | :type executor_thread_pool_size: int
81 | :default executor_thread_pool_size: None
82 |
83 | """
84 | if executor_thread_pool_size is not None:
85 | conf.set_default('executor_thread_pool_size',
86 | executor_thread_pool_size)
87 |
--------------------------------------------------------------------------------
/oslo_messaging/rpc/__init__.py:
--------------------------------------------------------------------------------
1 | # Copyright 2013 Red Hat, Inc.
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License"); you may
4 | # not use this file except in compliance with the License. You may obtain
5 | # a copy of the License at
6 | #
7 | # http://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11 | # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12 | # License for the specific language governing permissions and limitations
13 | # under the License.
14 |
15 | __all__ = [
16 | 'ClientSendError',
17 | 'ExpectedException',
18 | 'NoSuchMethod',
19 | 'RPCClient',
20 | 'RPCAccessPolicyBase',
21 | 'LegacyRPCAccessPolicy',
22 | 'DefaultRPCAccessPolicy',
23 | 'ExplicitRPCAccessPolicy',
24 | 'RPCDispatcher',
25 | 'RPCDispatcherError',
26 | 'RPCVersionCapError',
27 | 'RemoteError',
28 | 'UnsupportedVersion',
29 | 'expected_exceptions',
30 | 'get_rpc_transport',
31 | 'get_rpc_server',
32 | 'get_rpc_client',
33 | 'expose'
34 | ]
35 |
36 | from .client import *
37 | from .dispatcher import *
38 | from .transport import *
39 | from .server import *
40 |
--------------------------------------------------------------------------------
/oslo_messaging/rpc/transport.py:
--------------------------------------------------------------------------------
1 | # Copyright 2017 OpenStack Foundation.
2 | # All Rights Reserved.
3 | # Copyright 2017 Red Hat, Inc.
4 | #
5 | # Licensed under the Apache License, Version 2.0 (the "License"); you may
6 | # not use this file except in compliance with the License. You may obtain
7 | # a copy of the License at
8 | #
9 | # http://www.apache.org/licenses/LICENSE-2.0
10 | #
11 | # Unless required by applicable law or agreed to in writing, software
12 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
13 | # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
14 | # License for the specific language governing permissions and limitations
15 | # under the License.
16 |
17 | from oslo_messaging import transport as msg_transport
18 |
19 | __all__ = [
20 | 'get_rpc_transport'
21 | ]
22 |
23 |
24 | def get_rpc_transport(conf, url=None,
25 | allowed_remote_exmods=None,
26 | transport_cls=msg_transport.RPCTransport):
27 | """A factory method for Transport objects for RPCs.
28 |
29 | This method should be used to ensure the correct messaging functionality
30 | for RPCs. RPCs and Notifications may use separate messaging systems
31 | that utilize different drivers, different access permissions,
32 | message delivery, etc.
33 |
34 | Presently, this function works exactly the same as get_transport. It's
35 | use is recommended as disambiguates the intended use for the transport
36 | and may in the future extend functionality related to the separation of
37 | messaging backends.
38 |
39 | :param conf: the user configuration
40 | :type conf: cfg.ConfigOpts
41 | :param url: a transport URL, see :py:class:`transport.TransportURL`
42 | :type url: str or TransportURL
43 | :param allowed_remote_exmods: a list of modules which a client using this
44 | transport will deserialize remote exceptions
45 | from
46 | :type allowed_remote_exmods: list
47 | :param transport_cls: the transport class to instantiate
48 | :type transport_cls: class
49 | """
50 | return msg_transport._get_transport(
51 | conf, url, allowed_remote_exmods,
52 | transport_cls=transport_cls)
53 |
--------------------------------------------------------------------------------
/oslo_messaging/serializer.py:
--------------------------------------------------------------------------------
1 | # Copyright 2013 IBM Corp.
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License"); you may
4 | # not use this file except in compliance with the License. You may obtain
5 | # a copy of the License at
6 | #
7 | # http://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11 | # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12 | # License for the specific language governing permissions and limitations
13 | # under the License.
14 |
15 | """Provides the definition of a message serialization handler"""
16 |
17 | import abc
18 |
19 | from oslo_serialization import jsonutils
20 |
21 | __all__ = ['Serializer', 'NoOpSerializer', 'JsonPayloadSerializer']
22 |
23 |
24 | class Serializer(metaclass=abc.ABCMeta):
25 | """Generic (de-)serialization definition base class."""
26 |
27 | @abc.abstractmethod
28 | def serialize_entity(self, ctxt, entity):
29 | """Serialize something to primitive form.
30 |
31 | :param ctxt: Request context, in deserialized form
32 | :param entity: Entity to be serialized
33 | :returns: Serialized form of entity
34 | """
35 |
36 | @abc.abstractmethod
37 | def deserialize_entity(self, ctxt, entity):
38 | """Deserialize something from primitive form.
39 |
40 | :param ctxt: Request context, in deserialized form
41 | :param entity: Primitive to be deserialized
42 | :returns: Deserialized form of entity
43 | """
44 |
45 | @abc.abstractmethod
46 | def serialize_context(self, ctxt):
47 | """Serialize a request context into a dictionary.
48 |
49 | :param ctxt: Request context
50 | :returns: Serialized form of context
51 | """
52 |
53 | @abc.abstractmethod
54 | def deserialize_context(self, ctxt):
55 | """Deserialize a dictionary into a request context.
56 |
57 | :param ctxt: Request context dictionary
58 | :returns: Deserialized form of entity
59 | """
60 |
61 |
62 | class NoOpSerializer(Serializer):
63 | """A serializer that does nothing."""
64 |
65 | def serialize_entity(self, ctxt, entity):
66 | return entity
67 |
68 | def deserialize_entity(self, ctxt, entity):
69 | return entity
70 |
71 | def serialize_context(self, ctxt):
72 | return ctxt
73 |
74 | def deserialize_context(self, ctxt):
75 | return ctxt
76 |
77 |
78 | class JsonPayloadSerializer(NoOpSerializer):
79 | @staticmethod
80 | def serialize_entity(context, entity):
81 | return jsonutils.to_primitive(entity, convert_instances=True)
82 |
--------------------------------------------------------------------------------
/oslo_messaging/target.py:
--------------------------------------------------------------------------------
1 | # Copyright 2013 Red Hat, Inc.
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License"); you may
4 | # not use this file except in compliance with the License. You may obtain
5 | # a copy of the License at
6 | #
7 | # http://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11 | # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12 | # License for the specific language governing permissions and limitations
13 | # under the License.
14 |
15 |
16 | class Target:
17 |
18 | """Identifies the destination of messages.
19 |
20 | A Target encapsulates all the information to identify where a message
21 | should be sent or what messages a server is listening for.
22 |
23 | Different subsets of the information encapsulated in a Target object is
24 | relevant to various aspects of the API:
25 |
26 | an RPC Server's target:
27 | topic and server is required; exchange is optional
28 | an RPC endpoint's target:
29 | namespace and version is optional
30 | an RPC client sending a message:
31 | topic is required, all other attributes optional
32 | a Notification Server's target:
33 | topic is required, exchange is optional; all other attributes ignored
34 | a Notifier's target:
35 | topic is required, exchange is optional; all other attributes ignored
36 |
37 | Its attributes are:
38 |
39 | :param exchange: A scope for topics. Leave unspecified to default to the
40 | control_exchange configuration option.
41 | :type exchange: str
42 | :param topic: A name which identifies the set of interfaces exposed by a
43 | server. Multiple servers may listen on a topic and messages will be
44 | dispatched to one of the servers selected in a best-effort round-robin
45 | fashion (unless fanout is ``True``).
46 | :type topic: str
47 | :param namespace: Identifies a particular RPC interface (i.e. set of
48 | methods) exposed by a server. The default interface has no namespace
49 | identifier and is referred to as the null namespace.
50 | :type namespace: str
51 | :param version: RPC interfaces have a major.minor version number associated
52 | with them. A minor number increment indicates a backwards compatible
53 | change and an incompatible change is indicated by a major number bump.
54 | Servers may implement multiple major versions and clients may require
55 | indicate that their message requires a particular minimum minor version.
56 | :type version: str
57 | :param server: RPC Clients can request that a message be directed to a
58 | specific server, rather than just one of a pool of servers listening on
59 | the topic.
60 | :type server: str
61 | :param fanout: Clients may request that a copy of the message be delivered
62 | to all servers listening on a topic by setting fanout to ``True``, rather
63 | than just one of them.
64 | :type fanout: bool
65 | :param legacy_namespaces: A server always accepts messages specified via
66 | the 'namespace' parameter, and may also accept messages defined via
67 | this parameter. This option should be used to switch namespaces safely
68 | during rolling upgrades.
69 | :type legacy_namespaces: list of strings
70 | """
71 |
72 | def __init__(self, exchange=None, topic=None, namespace=None,
73 | version=None, server=None, fanout=None,
74 | legacy_namespaces=None):
75 | self.exchange = exchange
76 | self.topic = topic
77 | self.namespace = namespace
78 | self.version = version
79 | self.server = server
80 | self.fanout = fanout
81 | self.accepted_namespaces = [namespace] + (legacy_namespaces or [])
82 |
83 | def __call__(self, **kwargs):
84 | for a in ('exchange', 'topic', 'namespace',
85 | 'version', 'server', 'fanout'):
86 | kwargs.setdefault(a, getattr(self, a))
87 | return Target(**kwargs)
88 |
89 | def __eq__(self, other):
90 | return vars(self) == vars(other)
91 |
92 | def __ne__(self, other):
93 | return not self == other
94 |
95 | def __repr__(self):
96 | attrs = []
97 | for a in ['exchange', 'topic', 'namespace',
98 | 'version', 'server', 'fanout']:
99 | v = getattr(self, a)
100 | if v:
101 | attrs.append((a, v))
102 | values = ', '.join(['%s=%s' % i for i in attrs])
103 | return ''
104 |
105 | def __hash__(self):
106 | return id(self)
107 |
--------------------------------------------------------------------------------
/oslo_messaging/tests/__init__.py:
--------------------------------------------------------------------------------
1 | # Copyright 2014 eNovance
2 | # All Rights Reserved.
3 | #
4 | # Licensed under the Apache License, Version 2.0 (the "License"); you may
5 | # not use this file except in compliance with the License. You may obtain
6 | # a copy of the License at
7 | #
8 | # http://www.apache.org/licenses/LICENSE-2.0
9 | #
10 | # Unless required by applicable law or agreed to in writing, software
11 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12 | # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13 | # License for the specific language governing permissions and limitations
14 | # under the License.
15 |
16 | import eventlet
17 | eventlet.monkey_patch()
18 |
--------------------------------------------------------------------------------
/oslo_messaging/tests/drivers/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/openstack/oslo.messaging/510688d8ddc807242fe9a36532dd03ba3c2d4ad5/oslo_messaging/tests/drivers/__init__.py
--------------------------------------------------------------------------------
/oslo_messaging/tests/drivers/test_pool.py:
--------------------------------------------------------------------------------
1 | # Copyright 2013 Red Hat, Inc.
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License"); you may
4 | # not use this file except in compliance with the License. You may obtain
5 | # a copy of the License at
6 | #
7 | # http://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11 | # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12 | # License for the specific language governing permissions and limitations
13 | # under the License.
14 |
15 | import threading
16 | import uuid
17 |
18 | import fixtures
19 | import testscenarios
20 |
21 | from oslo_messaging._drivers import pool
22 | from oslo_messaging.tests import utils as test_utils
23 |
24 | load_tests = testscenarios.load_tests_apply_scenarios
25 |
26 |
27 | class PoolTestCase(test_utils.BaseTestCase):
28 |
29 | _max_size = [
30 | ('default_size', dict(max_size=None, n_iters=4)),
31 | ('set_max_size', dict(max_size=10, n_iters=10)),
32 | ]
33 |
34 | _create_error = [
35 | ('no_create_error', dict(create_error=False)),
36 | ('create_error', dict(create_error=True)),
37 | ]
38 |
39 | @classmethod
40 | def generate_scenarios(cls):
41 | cls.scenarios = testscenarios.multiply_scenarios(cls._max_size,
42 | cls._create_error)
43 |
44 | class TestPool(pool.Pool):
45 |
46 | def create(self, retry=None):
47 | return uuid.uuid4()
48 |
49 | class ThreadWaitWaiter:
50 |
51 | """A gross hack.
52 |
53 | Stub out the condition variable's wait() method and spin until it
54 | has been called by each thread.
55 | """
56 |
57 | def __init__(self, cond, n_threads, test):
58 | self.cond = cond
59 | self.test = test
60 | self.n_threads = n_threads
61 | self.n_waits = 0
62 | self.orig_wait = cond.wait
63 |
64 | def count_waits(**kwargs):
65 | self.n_waits += 1
66 | self.orig_wait(**kwargs)
67 | self.test.useFixture(fixtures.MockPatchObject(
68 | self.cond, 'wait', count_waits))
69 |
70 | def wait(self):
71 | while self.n_waits < self.n_threads:
72 | pass
73 | self.test.useFixture(fixtures.MockPatchObject(
74 | self.cond, 'wait', self.orig_wait))
75 |
76 | def test_pool(self):
77 | kwargs = {}
78 | if self.max_size is not None:
79 | kwargs['max_size'] = self.max_size
80 |
81 | p = self.TestPool(**kwargs)
82 |
83 | if self.create_error:
84 | def create_error(retry=None):
85 | raise RuntimeError
86 | orig_create = p.create
87 | self.useFixture(fixtures.MockPatchObject(
88 | p, 'create', create_error))
89 | self.assertRaises(RuntimeError, p.get)
90 | self.useFixture(fixtures.MockPatchObject(
91 | p, 'create', orig_create))
92 |
93 | objs = []
94 | for i in range(self.n_iters):
95 | objs.append(p.get())
96 | self.assertIsInstance(objs[i], uuid.UUID)
97 |
98 | def wait_for_obj():
99 | o = p.get()
100 | self.assertIn(o, objs)
101 |
102 | waiter = self.ThreadWaitWaiter(p._cond, self.n_iters, self)
103 |
104 | threads = []
105 | for i in range(self.n_iters):
106 | t = threading.Thread(target=wait_for_obj)
107 | t.start()
108 | threads.append(t)
109 |
110 | waiter.wait()
111 |
112 | for o in objs:
113 | p.put(o)
114 |
115 | for t in threads:
116 | t.join()
117 |
118 | for o in objs:
119 | p.put(o)
120 |
121 | for o in p.iter_free():
122 | self.assertIn(o, objs)
123 | objs.remove(o)
124 |
125 | self.assertEqual([], objs)
126 |
127 |
128 | PoolTestCase.generate_scenarios()
129 |
--------------------------------------------------------------------------------
/oslo_messaging/tests/functional/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/openstack/oslo.messaging/510688d8ddc807242fe9a36532dd03ba3c2d4ad5/oslo_messaging/tests/functional/__init__.py
--------------------------------------------------------------------------------
/oslo_messaging/tests/functional/notify/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/openstack/oslo.messaging/510688d8ddc807242fe9a36532dd03ba3c2d4ad5/oslo_messaging/tests/functional/notify/__init__.py
--------------------------------------------------------------------------------
/oslo_messaging/tests/functional/notify/test_logger.py:
--------------------------------------------------------------------------------
1 | # Copyright 2015 NetEase Corp.
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License"); you may
4 | # not use this file except in compliance with the License. You may obtain
5 | # a copy of the License at
6 | #
7 | # http://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11 | # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12 | # License for the specific language governing permissions and limitations
13 | # under the License.
14 |
15 | import logging
16 | import uuid
17 |
18 | import testscenarios
19 |
20 | import oslo_messaging
21 | from oslo_messaging.tests.functional import utils
22 |
23 | load_tests = testscenarios.load_tests_apply_scenarios
24 |
25 |
26 | class LoggingNotificationHandlerTestCase(utils.SkipIfNoTransportURL):
27 | """Test case for `oslo_messaging.LoggingNotificationHandler`
28 |
29 | Build up a logger using this handler, then test logging under messaging and
30 | messagingv2 driver. Make sure receive expected logging notifications.
31 | """
32 |
33 | _priority = [
34 | ('debug', dict(priority='debug')),
35 | ('info', dict(priority='info')),
36 | ('warn', dict(priority='warn')),
37 | ('error', dict(priority='error')),
38 | ('critical', dict(priority='critical')),
39 | ]
40 |
41 | _driver = [
42 | ('messaging', dict(driver='messaging')),
43 | ('messagingv2', dict(driver='messagingv2')),
44 | ]
45 |
46 | @classmethod
47 | def generate_scenarios(cls):
48 | cls.scenarios = testscenarios.multiply_scenarios(cls._priority,
49 | cls._driver)
50 |
51 | def test_logging(self):
52 | # NOTE(gtt): Using different topic to make tests run in parallel
53 | topic = 'test_logging_{}_driver_{}'.format(self.priority, self.driver)
54 |
55 | if self.notify_url.startswith("kafka://"):
56 | self.conf.set_override('consumer_group', str(uuid.uuid4()),
57 | group='oslo_messaging_kafka')
58 |
59 | self.config(driver=[self.driver],
60 | topics=[topic],
61 | group='oslo_messaging_notifications')
62 |
63 | listener = self.useFixture(
64 | utils.NotificationFixture(self.conf, self.notify_url, [topic]))
65 |
66 | log_notify = oslo_messaging.LoggingNotificationHandler(self.notify_url)
67 |
68 | log = logging.getLogger(topic)
69 | log.setLevel(logging.DEBUG)
70 | log.addHandler(log_notify)
71 |
72 | log_method = getattr(log, self.priority)
73 | log_method('Test logging at priority: %s' % self.priority)
74 |
75 | events = listener.get_events(timeout=15)
76 | self.assertEqual(1, len(events))
77 |
78 | info_event = events[0]
79 |
80 | self.assertEqual(self.priority, info_event[0])
81 | self.assertEqual('logrecord', info_event[1])
82 |
83 | for key in ['name', 'thread', 'extra', 'process', 'funcName',
84 | 'levelno', 'processName', 'pathname', 'lineno',
85 | 'msg', 'exc_info', 'levelname']:
86 | self.assertIn(key, info_event[2])
87 |
88 |
89 | LoggingNotificationHandlerTestCase.generate_scenarios()
90 |
--------------------------------------------------------------------------------
/oslo_messaging/tests/functional/test_rabbitmq.py:
--------------------------------------------------------------------------------
1 | # Licensed under the Apache License, Version 2.0 (the "License"); you may
2 | # not use this file except in compliance with the License. You may obtain
3 | # a copy of the License at
4 | #
5 | # http://www.apache.org/licenses/LICENSE-2.0
6 | #
7 | # Unless required by applicable law or agreed to in writing, software
8 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
9 | # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
10 | # License for the specific language governing permissions and limitations
11 | # under the License.
12 |
13 |
14 | import os
15 | import signal
16 | import time
17 |
18 | import fixtures
19 | from pifpaf.drivers import rabbitmq
20 |
21 | from oslo_messaging.tests.functional import utils
22 | from oslo_messaging.tests import utils as test_utils
23 |
24 |
25 | class ConnectedPortMatcher:
26 | def __init__(self, port):
27 | self.port = port
28 |
29 | def __eq__(self, data):
30 | return data.get("port") == self.port
31 |
32 | def __repr__(self):
33 | return "" % self.port
34 |
35 |
36 | class RabbitMQFailoverTests(test_utils.BaseTestCase):
37 | DRIVERS = [
38 | "rabbit",
39 | ]
40 |
41 | def test_failover_scenario(self):
42 | self._test_failover_scenario()
43 |
44 | def test_failover_scenario_enable_cancel_on_failover(self):
45 | self._test_failover_scenario(enable_cancel_on_failover=True)
46 |
47 | def _test_failover_scenario(self, enable_cancel_on_failover=False):
48 | # NOTE(sileht): run this test only if functional suite run of a driver
49 | # that use rabbitmq as backend
50 | self.driver = os.environ.get('TRANSPORT_DRIVER')
51 | if self.driver not in self.DRIVERS:
52 | self.skipTest("TRANSPORT_DRIVER is not set to a rabbit driver")
53 |
54 | # NOTE(sileht): Allow only one response at a time, to
55 | # have only one tcp connection for reply and ensure it will failover
56 | # correctly
57 | self.config(heartbeat_timeout_threshold=1,
58 | rpc_conn_pool_size=1,
59 | kombu_reconnect_delay=0,
60 | rabbit_retry_interval=0,
61 | rabbit_retry_backoff=0,
62 | enable_cancel_on_failover=enable_cancel_on_failover,
63 | group='oslo_messaging_rabbit')
64 |
65 | self.pifpaf = self.useFixture(rabbitmq.RabbitMQDriver(cluster=True,
66 | port=5692))
67 |
68 | self.url = self.pifpaf.env["PIFPAF_URL"]
69 | self.n1 = self.pifpaf.env["PIFPAF_RABBITMQ_NODENAME1"]
70 | self.n2 = self.pifpaf.env["PIFPAF_RABBITMQ_NODENAME2"]
71 | self.n3 = self.pifpaf.env["PIFPAF_RABBITMQ_NODENAME3"]
72 |
73 | # ensure connections will be establish to the first node
74 | self.pifpaf.stop_node(self.n2)
75 | self.pifpaf.stop_node(self.n3)
76 |
77 | self.servers = self.useFixture(utils.RpcServerGroupFixture(
78 | self.conf, self.url, endpoint=self, names=["server"]))
79 |
80 | # Don't randomize rabbit hosts
81 | self.useFixture(fixtures.MockPatch(
82 | 'oslo_messaging._drivers.impl_rabbit.random',
83 | side_effect=lambda x: x))
84 |
85 | # NOTE(sileht): this connects server connections and reply
86 | # connection to nodename n1
87 | self.client = self.servers.client(0)
88 | self.client.ping()
89 | self._check_ports(self.pifpaf.port)
90 |
91 | # Switch to node n2
92 | self.pifpaf.start_node(self.n2)
93 | self.assertEqual("callback done", self.client.kill_and_process())
94 | self.assertEqual("callback done", self.client.just_process())
95 | self._check_ports(self.pifpaf.get_port(self.n2))
96 |
97 | # Switch to node n3
98 | self.pifpaf.start_node(self.n3)
99 | time.sleep(0.1)
100 | self.pifpaf.kill_node(self.n2, signal=signal.SIGKILL)
101 | time.sleep(0.1)
102 | self.assertEqual("callback done", self.client.just_process())
103 | self._check_ports(self.pifpaf.get_port(self.n3))
104 |
105 | self.pifpaf.start_node(self.n1)
106 | time.sleep(0.1)
107 | self.pifpaf.kill_node(self.n3, signal=signal.SIGKILL)
108 | time.sleep(0.1)
109 | self.assertEqual("callback done", self.client.just_process())
110 | self._check_ports(self.pifpaf.get_port(self.n1))
111 |
112 | def kill_and_process(self, *args, **kargs):
113 | self.pifpaf.kill_node(self.n1, signal=signal.SIGKILL)
114 | time.sleep(0.1)
115 | return "callback done"
116 |
117 | def just_process(self, *args, **kargs):
118 | return "callback done"
119 |
120 | def _check_ports(self, port):
121 | rpc_server = self.servers.servers[0].server
122 | connection_contexts = [
123 | # rpc server
124 | rpc_server.listener._poll_style_listener.conn,
125 | # rpc client
126 | self.client.client.transport._driver._get_connection(),
127 | # rpc client replies waiter
128 | self.client.client.transport._driver._reply_q_conn,
129 | ]
130 |
131 | ports = [cctxt.connection.channel.connection.sock.getpeername()[1]
132 | for cctxt in connection_contexts]
133 |
134 | self.assertEqual([port] * len(ports), ports,
135 | "expected: %s, rpc-server: %s, rpc-client: %s, "
136 | "rpc-replies: %s" % tuple([port] + ports))
137 |
--------------------------------------------------------------------------------
/oslo_messaging/tests/notify/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/openstack/oslo.messaging/510688d8ddc807242fe9a36532dd03ba3c2d4ad5/oslo_messaging/tests/notify/__init__.py
--------------------------------------------------------------------------------
/oslo_messaging/tests/notify/test_log_handler.py:
--------------------------------------------------------------------------------
1 | # Licensed under the Apache License, Version 2.0 (the "License"); you may
2 | # not use this file except in compliance with the License. You may obtain
3 | # a copy of the License at
4 | #
5 | # http://www.apache.org/licenses/LICENSE-2.0
6 | #
7 | # Unless required by applicable law or agreed to in writing, software
8 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
9 | # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
10 | # License for the specific language governing permissions and limitations
11 | # under the License.
12 |
13 | import logging
14 |
15 | import fixtures
16 |
17 | import oslo_messaging
18 | from oslo_messaging.notify import log_handler
19 | from oslo_messaging.tests import utils as test_utils
20 | from unittest import mock
21 |
22 |
23 | class PublishErrorsHandlerTestCase(test_utils.BaseTestCase):
24 | """Tests for log.PublishErrorsHandler"""
25 | def setUp(self):
26 | super().setUp()
27 | self.publisherrorshandler = (log_handler.
28 | PublishErrorsHandler(logging.ERROR))
29 |
30 | def test_emit_cfg_log_notifier_in_notifier_drivers(self):
31 | drivers = ['messaging', 'log']
32 | self.config(driver=drivers,
33 | group='oslo_messaging_notifications')
34 | self.stub_flg = True
35 |
36 | transport = oslo_messaging.get_notification_transport(self.conf)
37 | notifier = oslo_messaging.Notifier(transport)
38 |
39 | def fake_notifier(*args, **kwargs):
40 | self.stub_flg = False
41 |
42 | self.useFixture(fixtures.MockPatchObject(
43 | notifier, 'error', fake_notifier))
44 |
45 | logrecord = logging.LogRecord(name='name', level='WARN',
46 | pathname='/tmp', lineno=1, msg='Message',
47 | args=None, exc_info=None)
48 | self.publisherrorshandler.emit(logrecord)
49 | self.assertTrue(self.stub_flg)
50 |
51 | @mock.patch('oslo_messaging.notify.notifier.Notifier._notify')
52 | def test_emit_notification(self, mock_notify):
53 | logrecord = logging.LogRecord(name='name', level='ERROR',
54 | pathname='/tmp', lineno=1, msg='Message',
55 | args=None, exc_info=None)
56 | self.publisherrorshandler.emit(logrecord)
57 | self.assertEqual('error.publisher',
58 | self.publisherrorshandler._notifier.publisher_id)
59 | mock_notify.assert_called_with({},
60 | 'error_notification',
61 | {'error': 'Message'}, 'ERROR')
62 |
--------------------------------------------------------------------------------
/oslo_messaging/tests/notify/test_logger.py:
--------------------------------------------------------------------------------
1 | # Copyright 2013 eNovance
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License"); you may
4 | # not use this file except in compliance with the License. You may obtain
5 | # a copy of the License at
6 | #
7 | # http://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11 | # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12 | # License for the specific language governing permissions and limitations
13 | # under the License.
14 |
15 | import datetime
16 | import logging
17 | import logging.config
18 | import os
19 | import sys
20 |
21 | from oslo_utils import timeutils
22 | import testscenarios
23 |
24 | import oslo_messaging
25 | from oslo_messaging.tests import utils as test_utils
26 | from unittest import mock
27 |
28 |
29 | load_tests = testscenarios.load_tests_apply_scenarios
30 |
31 | # Stolen from oslo.log
32 | logging.AUDIT = logging.INFO + 1
33 | logging.addLevelName(logging.AUDIT, 'AUDIT')
34 |
35 |
36 | class TestLogNotifier(test_utils.BaseTestCase):
37 |
38 | scenarios = [
39 | ('debug', dict(priority='debug')),
40 | ('info', dict(priority='info')),
41 | ('warning', dict(priority='warning', queue='WARN')),
42 | ('warn', dict(priority='warn')),
43 | ('error', dict(priority='error')),
44 | ('critical', dict(priority='critical')),
45 | ('audit', dict(priority='audit')),
46 | ]
47 |
48 | def setUp(self):
49 | super().setUp()
50 | self.addCleanup(oslo_messaging.notify._impl_test.reset)
51 | self.config(driver=['test'],
52 | group='oslo_messaging_notifications')
53 | # NOTE(jamespage) disable thread information logging for testing
54 | # as this can cause test failures when monkey_patch via eventlet
55 | logging.logThreads = 0
56 |
57 | @mock.patch('oslo_utils.timeutils.utcnow')
58 | def test_logger(self, mock_utcnow):
59 | fake_transport = oslo_messaging.get_notification_transport(self.conf)
60 | with mock.patch('oslo_messaging.transport._get_transport',
61 | return_value=fake_transport):
62 | self.logger = oslo_messaging.LoggingNotificationHandler('test://')
63 |
64 | mock_utcnow.return_value = datetime.datetime.utcnow()
65 |
66 | levelno = getattr(logging, self.priority.upper(), 42)
67 |
68 | record = logging.LogRecord('foo',
69 | levelno,
70 | '/foo/bar',
71 | 42,
72 | 'Something happened',
73 | None,
74 | None)
75 |
76 | self.logger.emit(record)
77 |
78 | context = oslo_messaging.notify._impl_test.NOTIFICATIONS[0][0]
79 | self.assertEqual({}, context)
80 |
81 | n = oslo_messaging.notify._impl_test.NOTIFICATIONS[0][1]
82 | self.assertEqual(getattr(self, 'queue', self.priority.upper()),
83 | n['priority'])
84 | self.assertEqual('logrecord', n['event_type'])
85 | self.assertEqual(str(timeutils.utcnow()), n['timestamp'])
86 | self.assertIsNone(n['publisher_id'])
87 | self.assertEqual(
88 | {'process': os.getpid(),
89 | 'funcName': None,
90 | 'name': 'foo',
91 | 'thread': None,
92 | 'levelno': levelno,
93 | 'processName': 'MainProcess',
94 | 'pathname': '/foo/bar',
95 | 'lineno': 42,
96 | 'msg': 'Something happened',
97 | 'exc_info': None,
98 | 'levelname': logging.getLevelName(levelno),
99 | 'extra': None},
100 | n['payload'])
101 |
102 | @mock.patch('oslo_utils.timeutils.utcnow')
103 | def test_logging_conf(self, mock_utcnow):
104 | fake_transport = oslo_messaging.get_notification_transport(self.conf)
105 | with mock.patch('oslo_messaging.transport._get_transport',
106 | return_value=fake_transport):
107 | logging.config.dictConfig({
108 | 'version': 1,
109 | 'handlers': {
110 | 'notification': {
111 | 'class': 'oslo_messaging.LoggingNotificationHandler',
112 | 'level': self.priority.upper(),
113 | 'url': 'test://',
114 | },
115 | },
116 | 'loggers': {
117 | 'default': {
118 | 'handlers': ['notification'],
119 | 'level': self.priority.upper(),
120 | },
121 | },
122 | })
123 |
124 | mock_utcnow.return_value = datetime.datetime.utcnow()
125 |
126 | levelno = getattr(logging, self.priority.upper())
127 |
128 | logger = logging.getLogger('default')
129 | lineno = sys._getframe().f_lineno + 1
130 | logger.log(levelno, 'foobar')
131 |
132 | n = oslo_messaging.notify._impl_test.NOTIFICATIONS[0][1]
133 | self.assertEqual(getattr(self, 'queue', self.priority.upper()),
134 | n['priority'])
135 | self.assertEqual('logrecord', n['event_type'])
136 | self.assertEqual(str(timeutils.utcnow()), n['timestamp'])
137 | self.assertIsNone(n['publisher_id'])
138 | pathname = __file__
139 | if pathname.endswith(('.pyc', '.pyo')):
140 | pathname = pathname[:-1]
141 | self.assertDictEqual(
142 | n['payload'],
143 | {'process': os.getpid(),
144 | 'funcName': 'test_logging_conf',
145 | 'name': 'default',
146 | 'thread': None,
147 | 'levelno': levelno,
148 | 'processName': 'MainProcess',
149 | 'pathname': pathname,
150 | 'lineno': lineno,
151 | 'msg': 'foobar',
152 | 'exc_info': None,
153 | 'levelname': logging.getLevelName(levelno),
154 | 'extra': None})
155 |
--------------------------------------------------------------------------------
/oslo_messaging/tests/rpc/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/openstack/oslo.messaging/510688d8ddc807242fe9a36532dd03ba3c2d4ad5/oslo_messaging/tests/rpc/__init__.py
--------------------------------------------------------------------------------
/oslo_messaging/tests/test_config_opts_proxy.py:
--------------------------------------------------------------------------------
1 | # Copyright 2016 Mirantis, Inc.
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License"); you may
4 | # not use this file except in compliance with the License. You may obtain
5 | # a copy of the License at
6 | #
7 | # http://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11 | # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12 | # License for the specific language governing permissions and limitations
13 | # under the License.
14 |
15 | from oslo_config import cfg
16 | from oslo_config import types
17 |
18 | from oslo_messaging._drivers import common as drv_cmn
19 | from oslo_messaging.tests import utils as test_utils
20 | from oslo_messaging import transport
21 |
22 |
23 | class TestConfigOptsProxy(test_utils.BaseTestCase):
24 |
25 | def test_rabbit(self):
26 | group = 'oslo_messaging_rabbit'
27 | self.config(rabbit_retry_interval=1,
28 | rabbit_qos_prefetch_count=0,
29 | group=group)
30 | dummy_opts = [cfg.ListOpt('list_str', item_type=types.String(),
31 | default=[]),
32 | cfg.ListOpt('list_int', item_type=types.Integer(),
33 | default=[]),
34 | cfg.DictOpt('dict', default={}),
35 | cfg.BoolOpt('bool', default=False),
36 | cfg.StrOpt('str', default='default')]
37 | self.conf.register_opts(dummy_opts, group=group)
38 | url = transport.TransportURL.parse(
39 | self.conf, "rabbit:///"
40 | "?rabbit_qos_prefetch_count=2"
41 | "&list_str=1&list_str=2&list_str=3"
42 | "&list_int=1&list_int=2&list_int=3"
43 | "&dict=x:1&dict=y:2&dict=z:3"
44 | "&bool=True"
45 | )
46 | conf = drv_cmn.ConfigOptsProxy(self.conf, url, group)
47 | self.assertRaises(cfg.NoSuchOptError,
48 | conf.__getattr__,
49 | 'unknown_group')
50 | self.assertIsInstance(getattr(conf, group),
51 | conf.GroupAttrProxy)
52 | self.assertEqual(1, conf.oslo_messaging_rabbit.rabbit_retry_interval)
53 | self.assertEqual(2,
54 | conf.oslo_messaging_rabbit.rabbit_qos_prefetch_count)
55 | self.assertEqual(['1', '2', '3'], conf.oslo_messaging_rabbit.list_str)
56 | self.assertEqual([1, 2, 3], conf.oslo_messaging_rabbit.list_int)
57 | self.assertEqual({'x': '1', 'y': '2', 'z': '3'},
58 | conf.oslo_messaging_rabbit.dict)
59 | self.assertEqual(True, conf.oslo_messaging_rabbit.bool)
60 | self.assertEqual('default', conf.oslo_messaging_rabbit.str)
61 |
62 | def test_not_in_group(self):
63 | group = 'oslo_messaging_rabbit'
64 | url = transport.TransportURL.parse(
65 | self.conf, "rabbit:///?unknown_opt=4"
66 | )
67 | self.assertRaises(cfg.NoSuchOptError,
68 | drv_cmn.ConfigOptsProxy,
69 | self.conf, url, group)
70 |
71 | def test_invalid_value(self):
72 | group = 'oslo_messaging_rabbit'
73 | self.config(kombu_reconnect_delay=1.0,
74 | group=group)
75 | url = transport.TransportURL.parse(
76 | self.conf, "rabbit:///?kombu_reconnect_delay=invalid_value"
77 | )
78 | self.assertRaises(ValueError, drv_cmn.ConfigOptsProxy, self.conf,
79 | url, group)
80 |
--------------------------------------------------------------------------------
/oslo_messaging/tests/test_expected_exceptions.py:
--------------------------------------------------------------------------------
1 | # Copyright 2012 OpenStack Foundation
2 | # Copyright 2013 Red Hat, Inc.
3 | #
4 | # Licensed under the Apache License, Version 2.0 (the "License"); you may
5 | # not use this file except in compliance with the License. You may obtain
6 | # a copy of the License at
7 | #
8 | # http://www.apache.org/licenses/LICENSE-2.0
9 | #
10 | # Unless required by applicable law or agreed to in writing, software
11 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12 | # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13 | # License for the specific language governing permissions and limitations
14 | # under the License.
15 |
16 | import oslo_messaging
17 | from oslo_messaging.tests import utils as test_utils
18 |
19 |
20 | class TestExpectedExceptions(test_utils.BaseTestCase):
21 |
22 | def test_exception(self):
23 | e = None
24 | try:
25 | try:
26 | raise ValueError()
27 | except Exception:
28 | raise oslo_messaging.ExpectedException()
29 | except oslo_messaging.ExpectedException as e: # noqa: F841
30 | self.assertIsInstance(e, oslo_messaging.ExpectedException)
31 | self.assertTrue(hasattr(e, 'exc_info'))
32 | self.assertIsInstance(e.exc_info[1], ValueError)
33 |
34 | def test_decorator_expected(self):
35 | class FooException(Exception):
36 | pass
37 |
38 | @oslo_messaging.expected_exceptions(FooException)
39 | def naughty():
40 | raise FooException()
41 |
42 | self.assertRaises(oslo_messaging.ExpectedException, naughty)
43 |
44 | def test_decorator_expected_subclass(self):
45 | class FooException(Exception):
46 | pass
47 |
48 | class BarException(FooException):
49 | pass
50 |
51 | @oslo_messaging.expected_exceptions(FooException)
52 | def naughty():
53 | raise BarException()
54 |
55 | self.assertRaises(oslo_messaging.ExpectedException, naughty)
56 |
57 | def test_decorator_unexpected(self):
58 | class FooException(Exception):
59 | pass
60 |
61 | @oslo_messaging.expected_exceptions(FooException)
62 | def really_naughty():
63 | raise ValueError()
64 |
65 | self.assertRaises(ValueError, really_naughty)
66 |
--------------------------------------------------------------------------------
/oslo_messaging/tests/test_fixture.py:
--------------------------------------------------------------------------------
1 | # Copyright 2015 Mirantis Inc.
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License"); you may
4 | # not use this file except in compliance with the License. You may obtain
5 | # a copy of the License at
6 | #
7 | # http://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11 | # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12 | # License for the specific language governing permissions and limitations
13 | # under the License.
14 |
15 | from oslo_config import cfg
16 |
17 | from oslo_messaging import conffixture
18 | from oslo_messaging.tests import utils as test_utils
19 |
20 |
21 | class TestConfFixture(test_utils.BaseTestCase):
22 |
23 | def test_fixture_wraps_set_override(self):
24 | conf = self.messaging_conf.conf
25 | self.assertIsNotNone(conf.set_override.wrapped)
26 | self.messaging_conf._teardown_decorator()
27 | self.assertFalse(hasattr(conf.set_override, 'wrapped'))
28 |
29 | def test_fixture_wraps_clear_override(self):
30 | conf = self.messaging_conf.conf
31 | self.assertIsNotNone(conf.clear_override.wrapped)
32 | self.messaging_conf._teardown_decorator()
33 | self.assertFalse(hasattr(conf.clear_override, 'wrapped'))
34 |
35 | def test_fixture_setup_teardown_decorator(self):
36 | conf = cfg.ConfigOpts()
37 | self.assertFalse(hasattr(conf.set_override, 'wrapped'))
38 | self.assertFalse(hasattr(conf.clear_override, 'wrapped'))
39 | fixture = conffixture.ConfFixture(conf)
40 | self.assertFalse(hasattr(conf.set_override, 'wrapped'))
41 | self.assertFalse(hasattr(conf.clear_override, 'wrapped'))
42 | self.useFixture(fixture)
43 | self.assertTrue(hasattr(conf.set_override, 'wrapped'))
44 | self.assertTrue(hasattr(conf.clear_override, 'wrapped'))
45 | fixture._teardown_decorator()
46 | self.assertFalse(hasattr(conf.set_override, 'wrapped'))
47 | self.assertFalse(hasattr(conf.clear_override, 'wrapped'))
48 |
49 | def test_fixture_properties(self):
50 | conf = self.messaging_conf.conf
51 | self.messaging_conf.transport_url = 'fake:/vhost'
52 | self.assertEqual('fake:/vhost', self.messaging_conf.transport_url)
53 | self.assertEqual('fake:/vhost', conf.transport_url)
54 |
55 | def test_old_notifications_config_override(self):
56 | conf = self.messaging_conf.conf
57 | conf.set_override(
58 | "notification_driver", ["messaging"])
59 | conf.set_override(
60 | "notification_transport_url", "http://xyz")
61 | conf.set_override(
62 | "notification_topics", ['topic1'])
63 |
64 | self.assertEqual(["messaging"],
65 | conf.oslo_messaging_notifications.driver)
66 | self.assertEqual("http://xyz",
67 | conf.oslo_messaging_notifications.transport_url)
68 | self.assertEqual(['topic1'],
69 | conf.oslo_messaging_notifications.topics)
70 |
71 | conf.clear_override("notification_driver")
72 | conf.clear_override("notification_transport_url")
73 | conf.clear_override("notification_topics")
74 |
75 | self.assertEqual([],
76 | conf.oslo_messaging_notifications.driver)
77 | self.assertIsNone(conf.oslo_messaging_notifications.transport_url)
78 | self.assertEqual(['notifications'],
79 | conf.oslo_messaging_notifications.topics)
80 |
--------------------------------------------------------------------------------
/oslo_messaging/tests/test_opts.py:
--------------------------------------------------------------------------------
1 | # Copyright 2014 Red Hat, Inc.
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License"); you may
4 | # not use this file except in compliance with the License. You may obtain
5 | # a copy of the License at
6 | #
7 | # http://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11 | # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12 | # License for the specific language governing permissions and limitations
13 | # under the License.
14 |
15 | from unittest import mock
16 |
17 | import stevedore
18 | import testtools
19 |
20 | from oslo_messaging import server
21 | try:
22 | from oslo_messaging import opts
23 | except ImportError:
24 | opts = None
25 | from oslo_messaging.tests import utils as test_utils
26 |
27 |
28 | @testtools.skipIf(opts is None, "Options not importable")
29 | class OptsTestCase(test_utils.BaseTestCase):
30 |
31 | def _test_list_opts(self, result):
32 | self.assertEqual(4, len(result))
33 |
34 | groups = [g for (g, l) in result]
35 | self.assertIn(None, groups)
36 | self.assertIn('oslo_messaging_notifications', groups)
37 | self.assertIn('oslo_messaging_rabbit', groups)
38 | self.assertIn('oslo_messaging_kafka', groups)
39 |
40 | def test_list_opts(self):
41 | self._test_list_opts(opts.list_opts())
42 |
43 | def test_entry_point(self):
44 | result = None
45 | for ext in stevedore.ExtensionManager('oslo.config.opts',
46 | invoke_on_load=True):
47 | if ext.name == "oslo.messaging":
48 | result = ext.obj
49 | break
50 |
51 | self.assertIsNotNone(result)
52 | self._test_list_opts(result)
53 |
54 | def test_defaults(self):
55 | transport = mock.Mock()
56 | transport.conf = self.conf
57 |
58 | class MessageHandlingServerImpl(server.MessageHandlingServer):
59 | def _create_listener(self):
60 | pass
61 |
62 | def _process_incoming(self, incoming):
63 | pass
64 |
65 | MessageHandlingServerImpl(transport, mock.Mock())
66 | opts.set_defaults(self.conf, executor_thread_pool_size=100)
67 | self.assertEqual(100, self.conf.executor_thread_pool_size)
68 |
--------------------------------------------------------------------------------
/oslo_messaging/tests/test_target.py:
--------------------------------------------------------------------------------
1 | # Copyright 2013 Red Hat, Inc.
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License"); you may
4 | # not use this file except in compliance with the License. You may obtain
5 | # a copy of the License at
6 | #
7 | # http://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11 | # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12 | # License for the specific language governing permissions and limitations
13 | # under the License.
14 |
15 | import testscenarios
16 |
17 | import oslo_messaging
18 | from oslo_messaging.tests import utils as test_utils
19 |
20 | load_tests = testscenarios.load_tests_apply_scenarios
21 |
22 |
23 | class TargetConstructorTestCase(test_utils.BaseTestCase):
24 |
25 | scenarios = [
26 | ('all_none', dict(kwargs=dict())),
27 | ('exchange', dict(kwargs=dict(exchange='testexchange'))),
28 | ('topic', dict(kwargs=dict(topic='testtopic'))),
29 | ('namespace', dict(kwargs=dict(namespace='testnamespace'))),
30 | ('version', dict(kwargs=dict(version='3.4'))),
31 | ('server', dict(kwargs=dict(server='testserver'))),
32 | ('fanout', dict(kwargs=dict(fanout=True))),
33 | ]
34 |
35 | def test_constructor(self):
36 | target = oslo_messaging.Target(**self.kwargs)
37 | for k in self.kwargs:
38 | self.assertEqual(self.kwargs[k], getattr(target, k))
39 | for k in ['exchange', 'topic', 'namespace',
40 | 'version', 'server', 'fanout']:
41 | if k in self.kwargs:
42 | continue
43 | self.assertIsNone(getattr(target, k))
44 |
45 |
46 | class TargetCallableTestCase(test_utils.BaseTestCase):
47 |
48 | scenarios = [
49 | ('all_none', dict(attrs=dict(), kwargs=dict(), vals=dict())),
50 | ('exchange_attr', dict(attrs=dict(exchange='testexchange'),
51 | kwargs=dict(),
52 | vals=dict(exchange='testexchange'))),
53 | ('exchange_arg', dict(attrs=dict(),
54 | kwargs=dict(exchange='testexchange'),
55 | vals=dict(exchange='testexchange'))),
56 | ('topic_attr', dict(attrs=dict(topic='testtopic'),
57 | kwargs=dict(),
58 | vals=dict(topic='testtopic'))),
59 | ('topic_arg', dict(attrs=dict(),
60 | kwargs=dict(topic='testtopic'),
61 | vals=dict(topic='testtopic'))),
62 | ('namespace_attr', dict(attrs=dict(namespace='testnamespace'),
63 | kwargs=dict(),
64 | vals=dict(namespace='testnamespace'))),
65 | ('namespace_arg', dict(attrs=dict(),
66 | kwargs=dict(namespace='testnamespace'),
67 | vals=dict(namespace='testnamespace'))),
68 | ('version_attr', dict(attrs=dict(version='3.4'),
69 | kwargs=dict(),
70 | vals=dict(version='3.4'))),
71 | ('version_arg', dict(attrs=dict(),
72 | kwargs=dict(version='3.4'),
73 | vals=dict(version='3.4'))),
74 | ('server_attr', dict(attrs=dict(server='testserver'),
75 | kwargs=dict(),
76 | vals=dict(server='testserver'))),
77 | ('server_arg', dict(attrs=dict(),
78 | kwargs=dict(server='testserver'),
79 | vals=dict(server='testserver'))),
80 | ('fanout_attr', dict(attrs=dict(fanout=True),
81 | kwargs=dict(),
82 | vals=dict(fanout=True))),
83 | ('fanout_arg', dict(attrs=dict(),
84 | kwargs=dict(fanout=True),
85 | vals=dict(fanout=True))),
86 | ]
87 |
88 | def test_callable(self):
89 | target = oslo_messaging.Target(**self.attrs)
90 | target = target(**self.kwargs)
91 | for k in self.vals:
92 | self.assertEqual(self.vals[k], getattr(target, k))
93 | for k in ['exchange', 'topic', 'namespace',
94 | 'version', 'server', 'fanout']:
95 | if k in self.vals:
96 | continue
97 | self.assertIsNone(getattr(target, k))
98 |
99 |
100 | class TargetReprTestCase(test_utils.BaseTestCase):
101 |
102 | scenarios = [
103 | ('all_none', dict(kwargs=dict(), repr='')),
104 | ('exchange', dict(kwargs=dict(exchange='testexchange'),
105 | repr='exchange=testexchange')),
106 | ('topic', dict(kwargs=dict(topic='testtopic'),
107 | repr='topic=testtopic')),
108 | ('namespace', dict(kwargs=dict(namespace='testnamespace'),
109 | repr='namespace=testnamespace')),
110 | ('version', dict(kwargs=dict(version='3.4'),
111 | repr='version=3.4')),
112 | ('server', dict(kwargs=dict(server='testserver'),
113 | repr='server=testserver')),
114 | ('fanout', dict(kwargs=dict(fanout=True),
115 | repr='fanout=True')),
116 | ('exchange_and_fanout', dict(kwargs=dict(exchange='testexchange',
117 | fanout=True),
118 | repr='exchange=testexchange, '
119 | 'fanout=True')),
120 | ]
121 |
122 | def test_repr(self):
123 | target = oslo_messaging.Target(**self.kwargs)
124 | self.assertEqual('', str(target))
125 |
126 |
127 | _notset = object()
128 |
129 |
130 | class EqualityTestCase(test_utils.BaseTestCase):
131 |
132 | @classmethod
133 | def generate_scenarios(cls):
134 | attr = [
135 | ('exchange', dict(attr='exchange')),
136 | ('topic', dict(attr='topic')),
137 | ('namespace', dict(attr='namespace')),
138 | ('version', dict(attr='version')),
139 | ('server', dict(attr='server')),
140 | ('fanout', dict(attr='fanout')),
141 | ]
142 | a = [
143 | ('a_notset', dict(a_value=_notset)),
144 | ('a_none', dict(a_value=None)),
145 | ('a_empty', dict(a_value='')),
146 | ('a_foo', dict(a_value='foo')),
147 | ('a_bar', dict(a_value='bar')),
148 | ]
149 | b = [
150 | ('b_notset', dict(b_value=_notset)),
151 | ('b_none', dict(b_value=None)),
152 | ('b_empty', dict(b_value='')),
153 | ('b_foo', dict(b_value='foo')),
154 | ('b_bar', dict(b_value='bar')),
155 | ]
156 |
157 | cls.scenarios = testscenarios.multiply_scenarios(attr, a, b)
158 | for s in cls.scenarios:
159 | s[1]['equals'] = (s[1]['a_value'] == s[1]['b_value'])
160 |
161 | def test_equality(self):
162 | a_kwargs = {self.attr: self.a_value}
163 | b_kwargs = {self.attr: self.b_value}
164 |
165 | a = oslo_messaging.Target(**a_kwargs)
166 | b = oslo_messaging.Target(**b_kwargs)
167 |
168 | if self.equals:
169 | self.assertEqual(a, b)
170 | self.assertFalse(a != b)
171 | else:
172 | self.assertNotEqual(a, b)
173 | self.assertFalse(a == b)
174 |
175 |
176 | EqualityTestCase.generate_scenarios()
177 |
--------------------------------------------------------------------------------
/oslo_messaging/tests/test_utils.py:
--------------------------------------------------------------------------------
1 | # Copyright 2013 Red Hat, Inc.
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License"); you may
4 | # not use this file except in compliance with the License. You may obtain
5 | # a copy of the License at
6 | #
7 | # http://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11 | # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12 | # License for the specific language governing permissions and limitations
13 | # under the License.
14 | from oslo_messaging._drivers import common
15 | from oslo_messaging import _utils as utils
16 | from oslo_messaging.tests import utils as test_utils
17 | from unittest import mock
18 |
19 |
20 | class VersionIsCompatibleTestCase(test_utils.BaseTestCase):
21 | def test_version_is_compatible_same(self):
22 | self.assertTrue(utils.version_is_compatible('1.23', '1.23'))
23 |
24 | def test_version_is_compatible_newer_minor(self):
25 | self.assertTrue(utils.version_is_compatible('1.24', '1.23'))
26 |
27 | def test_version_is_compatible_older_minor(self):
28 | self.assertFalse(utils.version_is_compatible('1.22', '1.23'))
29 |
30 | def test_version_is_compatible_major_difference1(self):
31 | self.assertFalse(utils.version_is_compatible('2.23', '1.23'))
32 |
33 | def test_version_is_compatible_major_difference2(self):
34 | self.assertFalse(utils.version_is_compatible('1.23', '2.23'))
35 |
36 | def test_version_is_compatible_newer_rev(self):
37 | self.assertFalse(utils.version_is_compatible('1.23', '1.23.1'))
38 |
39 | def test_version_is_compatible_newer_rev_both(self):
40 | self.assertFalse(utils.version_is_compatible('1.23.1', '1.23.2'))
41 |
42 | def test_version_is_compatible_older_rev_both(self):
43 | self.assertTrue(utils.version_is_compatible('1.23.2', '1.23.1'))
44 |
45 | def test_version_is_compatible_older_rev(self):
46 | self.assertTrue(utils.version_is_compatible('1.24', '1.23.1'))
47 |
48 | def test_version_is_compatible_no_rev_is_zero(self):
49 | self.assertTrue(utils.version_is_compatible('1.23.0', '1.23'))
50 |
51 |
52 | class TimerTestCase(test_utils.BaseTestCase):
53 | def test_no_duration_no_callback(self):
54 | t = common.DecayingTimer()
55 | t.start()
56 | remaining = t.check_return()
57 | self.assertIsNone(remaining)
58 |
59 | def test_no_duration_but_maximum(self):
60 | t = common.DecayingTimer()
61 | t.start()
62 | remaining = t.check_return(maximum=2)
63 | self.assertEqual(2, remaining)
64 |
65 | @mock.patch('oslo_utils.timeutils.now')
66 | def test_duration_expired_no_callback(self, now):
67 | now.return_value = 0
68 | t = common.DecayingTimer(2)
69 | t.start()
70 |
71 | now.return_value = 3
72 | remaining = t.check_return()
73 | self.assertEqual(0, remaining)
74 |
75 | @mock.patch('oslo_utils.timeutils.now')
76 | def test_duration_callback(self, now):
77 | now.return_value = 0
78 | t = common.DecayingTimer(2)
79 | t.start()
80 |
81 | now.return_value = 3
82 | callback = mock.Mock()
83 | remaining = t.check_return(callback)
84 | self.assertEqual(0, remaining)
85 | callback.assert_called_once_with()
86 |
87 | @mock.patch('oslo_utils.timeutils.now')
88 | def test_duration_callback_with_args(self, now):
89 | now.return_value = 0
90 | t = common.DecayingTimer(2)
91 | t.start()
92 |
93 | now.return_value = 3
94 | callback = mock.Mock()
95 | remaining = t.check_return(callback, 1, a='b')
96 | self.assertEqual(0, remaining)
97 | callback.assert_called_once_with(1, a='b')
98 |
99 | @mock.patch('oslo_utils.timeutils.now')
100 | def test_reset(self, now):
101 | now.return_value = 0
102 | t = common.DecayingTimer(3)
103 | t.start()
104 |
105 | now.return_value = 1
106 | remaining = t.check_return()
107 | self.assertEqual(2, remaining)
108 |
109 | t.restart()
110 | remaining = t.check_return()
111 | self.assertEqual(3, remaining)
112 |
--------------------------------------------------------------------------------
/oslo_messaging/tests/utils.py:
--------------------------------------------------------------------------------
1 | # Copyright 2010-2011 OpenStack Foundation
2 | # Copyright 2010 United States Government as represented by the
3 | # Administrator of the National Aeronautics and Space Administration.
4 | # Copyright 2013 Hewlett-Packard Development Company, L.P.
5 | # All Rights Reserved.
6 | # Copyright 2013 Red Hat, Inc.
7 | #
8 | # Licensed under the Apache License, Version 2.0 (the "License"); you may
9 | # not use this file except in compliance with the License. You may obtain
10 | # a copy of the License at
11 | #
12 | # http://www.apache.org/licenses/LICENSE-2.0
13 | #
14 | # Unless required by applicable law or agreed to in writing, software
15 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
16 | # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
17 | # License for the specific language governing permissions and limitations
18 | # under the License.
19 |
20 | """Common utilities used in testing"""
21 |
22 | import threading
23 |
24 | from oslo_config import cfg
25 | from oslo_context.context import RequestContext
26 | from oslo_utils import eventletutils
27 | from oslotest import base
28 |
29 |
30 | TRUE_VALUES = ('true', '1', 'yes')
31 |
32 |
33 | class BaseTestCase(base.BaseTestCase):
34 |
35 | def setUp(self, conf=cfg.CONF):
36 | super().setUp()
37 |
38 | from oslo_messaging import conffixture
39 | self.messaging_conf = self.useFixture(conffixture.ConfFixture(conf))
40 | self.messaging_conf.transport_url = 'fake:/'
41 | self.conf = self.messaging_conf.conf
42 |
43 | self.conf.project = 'project'
44 | self.conf.prog = 'prog'
45 |
46 | def config(self, **kw):
47 | """Override some configuration values.
48 |
49 | The keyword arguments are the names of configuration options to
50 | override and their values.
51 |
52 | If a group argument is supplied, the overrides are applied to
53 | the specified configuration option group.
54 |
55 | All overrides are automatically cleared at the end of the current
56 | test by the tearDown() method.
57 | """
58 | group = kw.pop('group', None)
59 | for k, v in kw.items():
60 | self.conf.set_override(k, v, group)
61 |
62 |
63 | class ServerThreadHelper(threading.Thread):
64 | def __init__(self, server):
65 | super().__init__()
66 | self.daemon = True
67 | self._server = server
68 | self._stop_event = eventletutils.Event()
69 | self._start_event = eventletutils.Event()
70 |
71 | def start(self):
72 | super().start()
73 | self._start_event.wait()
74 |
75 | def run(self):
76 | self._server.start()
77 | self._start_event.set()
78 | self._stop_event.wait()
79 | # Check start() does nothing with a running listener
80 | self._server.start()
81 | self._server.stop()
82 | self._server.wait()
83 |
84 | def stop(self):
85 | self._stop_event.set()
86 |
87 |
88 | class TestContext(RequestContext):
89 | def redacted_copy(self):
90 | # NOTE(JayF): By returning our self here instead of redacting, we can
91 | # continue using equality comparisons in unit tests.
92 | return self
93 |
--------------------------------------------------------------------------------
/oslo_messaging/version.py:
--------------------------------------------------------------------------------
1 | # Copyright 2016 OpenStack Foundation
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License"); you may
4 | # not use this file except in compliance with the License. You may obtain
5 | # a copy of the License at
6 | #
7 | # http://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11 | # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12 | # License for the specific language governing permissions and limitations
13 | # under the License.
14 |
15 |
16 | import pbr.version
17 |
18 | version_info = pbr.version.VersionInfo('oslo.messaging')
19 |
--------------------------------------------------------------------------------
/releasenotes/notes/RPC-call-monitoring-7977f047d069769a.yaml:
--------------------------------------------------------------------------------
1 | ---
2 | prelude: >
3 | RPCClient now supports RPC call monitoring for detecting the loss
4 | of a server during an RPC call.
5 | features:
6 | - |
7 | RPC call monitoring is a new RPCClient feature. Call monitoring
8 | causes the RPC server to periodically send keepalive messages back
9 | to the RPCClient while the RPC call is being processed. This can
10 | be used for early detection of a server failure without having to
11 | wait for the full call timeout to expire.
12 |
--------------------------------------------------------------------------------
/releasenotes/notes/add-enable_cancel_on_failover-22ac472b93dd3a23.yaml:
--------------------------------------------------------------------------------
1 | ---
2 | fixes:
3 | - |
4 | Add a new option `enable_cancel_on_failover` for rabbitmq driver
5 | which when enabled, will cancel consumers when queue appears
6 | to be down.
7 |
--------------------------------------------------------------------------------
/releasenotes/notes/add-ping-endpoint.yaml:
--------------------------------------------------------------------------------
1 | ---
2 | features:
3 | - |
4 | RPC dispatcher can have an extra endpoint named ping.
5 | This endpoint can be enabled thanks to a specific configuration parameter:
6 | [DEFAULT]
7 | rpc_ping_enabled=true # default is false
8 |
9 | The purpose of this new endpoint is to help operators do a RPC call (a
10 | ping) toward a specific RPC callback (e.g. a nova-compute, or a
11 | neutron-agent).
12 | This is helping a lot for monitoring agents (for example, if agents are
13 | deployed in a kubernetes pod).
14 |
--------------------------------------------------------------------------------
/releasenotes/notes/add-quorum-control-configurations-beed79811ff97ba2.yaml:
--------------------------------------------------------------------------------
1 | ---
2 | features:
3 | - |
4 | Add quorum configuration x-max-in-memory-length,
5 | x-max-in-memory-bytes, x-delivery-limit which control the quorum
6 | queue memory usage and handle the message poisoning problem
7 |
--------------------------------------------------------------------------------
/releasenotes/notes/add-ssl-support-for-kafka.yaml:
--------------------------------------------------------------------------------
1 | ---
2 | features:
3 | - |
4 | | SSL support for oslo_messaging's kafka driver
5 | | Next configuration params was added
6 |
7 | * *ssl_client_cert_file* (default='')
8 | * *ssl_client_key_file* (default='')
9 | * *ssl_client_key_password* (default='')
10 |
--------------------------------------------------------------------------------
/releasenotes/notes/add_reno-3b4ae0789e9c45b4.yaml:
--------------------------------------------------------------------------------
1 | ---
2 | other:
3 | - Switch to reno for managing release notes.
--------------------------------------------------------------------------------
/releasenotes/notes/adding_support_for_quorum_queues-3101d055b492289e.yaml:
--------------------------------------------------------------------------------
1 | ---
2 | features:
3 | - |
4 | Adding support for quorum queues. Quorum queues are enabled if the
5 | ``rabbit_quorum_queue`` parameter is sets (``x-queue-type: quorum``).
6 | Setting x-queue-type to quorum means that replicated FIFO queue based on
7 | the Raft consensus algorithm will be used. It is available as of
8 | RabbitMQ 3.8.0. The quorum queues are durable by default
9 | (``amqp_durable_queues``) will be ignored.
10 | when enabled the HA queues (``rabbit_ha_queues``) aka mirrored queues
11 | should be disabled since the queue can't be both types at the same time
12 |
--------------------------------------------------------------------------------
/releasenotes/notes/allow-transient-no-expire-ce7ae9d8c9d15751.yaml:
--------------------------------------------------------------------------------
1 | ---
2 | features:
3 | - |
4 | Allow creation of transient queues with no expire.
5 | When an operator rely on rabbitmq policies, there is no point to set the
6 | queue TTL in config.
7 | When the rabbit_transient_queues_ttl is set to 0, no x-expire parameter
8 | will be set on queue declaration.
9 | In that specific situation, it is recommended to set an expire value using
10 | rabbitmq policies.
11 | See https://www.rabbitmq.com/parameters.html#policies
12 |
--------------------------------------------------------------------------------
/releasenotes/notes/auto-deleted-failed-quorum-ca6a3923c3ed999a.yaml:
--------------------------------------------------------------------------------
1 | ---
2 | fixes:
3 | - |
4 | Auto-delete the failed quorum rabbit queues.
5 | When rabbit is failing for a specific quorum queue, delete the queue
6 | before trying to recreate it.
7 | This may happen if the queue is not recoverable on rabbit side.
8 | See https://www.rabbitmq.com/quorum-queues.html#availability for more
9 | info on this specific case.
10 |
--------------------------------------------------------------------------------
/releasenotes/notes/blocking-executor-deprecated-895146c1c3bf2f51.yaml:
--------------------------------------------------------------------------------
1 | ---
2 | deprecations:
3 | - The blocking executor has been deprecated for removal in Rocky. Its usage
4 | was never recommended for applications, and it has no test coverage.
5 | Applications should choose the appropriate threading model that maps their
6 | usage instead.
7 |
--------------------------------------------------------------------------------
/releasenotes/notes/blocking-executor-support-dropped-a3bc74c6825863f0.yaml:
--------------------------------------------------------------------------------
1 | ---
2 | upgrade:
3 | - |
4 | The blocking executor has been deprecated for removal in Rocky and support
5 | is now dropped in Ussuri. Its usage was never recommended for applications,
6 | and it has no test coverage.
7 | Applications should choose the appropriate threading model that maps to
8 | their usage instead.
9 |
--------------------------------------------------------------------------------
/releasenotes/notes/bug-1917645-rabbit-use-retry-parameter-for-notifications-3f7c508ab4437579.yaml:
--------------------------------------------------------------------------------
1 | ---
2 | fixes:
3 | - |
4 | As a fix for `bug 1917645 `_ the rabbit
5 | backend is changed to use the ``[oslo_messaging_notifications]retry``
6 | parameter when driver tries to connect to the message bus during
7 | notification sending. Before this fix the rabbit backend retried the
8 | connection forever blocking the caller thread.
9 |
--------------------------------------------------------------------------------
/releasenotes/notes/bug-1981093-kafka-dont-log-in-tpool-execute-fa50ceee2d55ebae.yaml:
--------------------------------------------------------------------------------
1 | ---
2 | fixes:
3 | - |
4 | [`bug 1981093 `_]
5 | Pulls calls to logging functions out of ``impl_kafka._produce_message``.
6 | Since ``_produce_message`` is called through tpool.execute, calling logging
7 | functions inside ``_produce_message`` could cause subsequent calls to
8 | logging functions to deadlock.
9 |
--------------------------------------------------------------------------------
/releasenotes/notes/bug-1993149-e8b231791b65e938.yaml:
--------------------------------------------------------------------------------
1 | ---
2 | upgrade:
3 | - |
4 | If kombu_reconnect_delay is specified in the [oslo_messaging_rabbit] section,
5 | ensure that it is less than 5.0, the value of ACK_REQUEUE_EVERY_SECONDS_MAX
6 | fixes:
7 | - |
8 | Increased ACK_REQUEUE_EVERY_SECONDS_MAX to resolve issues with rabbitmq HA
9 | failover.
10 |
--------------------------------------------------------------------------------
/releasenotes/notes/bug-2068630-6ff92f213bc4eca0.yaml:
--------------------------------------------------------------------------------
1 | ---
2 | fixes:
3 | - |
4 | Force queue deletion when it is not possible de redeclare a queue.
5 | See `bug 2068630 `__
6 | for details.
7 |
--------------------------------------------------------------------------------
/releasenotes/notes/bug-2098714-d55094fa4fbb3178.yaml:
--------------------------------------------------------------------------------
1 | ---
2 | fixes:
3 | - |
4 | Fixes delayed metrics processing in services using eventlet, caused by
5 | mixing a native thread with an eventlet-patched queue.
6 | See `bug 2098714 `__
7 | for details.
8 |
--------------------------------------------------------------------------------
/releasenotes/notes/bump-amqp-version-due-to-tls-issue-e877b152eb101c15.yaml:
--------------------------------------------------------------------------------
1 | ---
2 | critical:
3 | - |
4 | In combination with amqp<=2.4.0, ``oslo.messaging`` was unreliable
5 | when configured with TLS (as is generally recommended). Users would
6 | see frequent errors such as this::
7 |
8 | MessagingTimeout: Timed out waiting for a reply to message ID ae039d1695984addbfaaef032ce4fda3
9 |
10 | Such issues would typically lead to downstream service timeouts,
11 | with no recourse available other than disabling TLS altogether
12 | (see `bug 1800957
13 | `_).
14 |
15 | The underlying issue is fixed in amqp version 2.4.1, which is now
16 | the minimum version that ``oslo.messaging`` requires.
17 |
--------------------------------------------------------------------------------
/releasenotes/notes/connection_ttl-2cf0fe6e1ab8c73c.yaml:
--------------------------------------------------------------------------------
1 | ---
2 | features:
3 | - |
4 | | Idle connections in the pool will be expired and closed.
5 | | Default ttl is 1200s. Next configuration params was added
6 |
7 | * *conn_pool_ttl* (defaul 1200)
8 | * *conn_pool_min_size* (default 2)
9 |
--------------------------------------------------------------------------------
/releasenotes/notes/declare_fallback_durable_exchange-0db677de4fdf1e78.yaml:
--------------------------------------------------------------------------------
1 | ---
2 | fixes:
3 | - |
4 | Force creating non durable control exchange when a precondition failed
5 | related to config that differ occuring.
6 |
--------------------------------------------------------------------------------
/releasenotes/notes/deprecate-ZeroMQ-driver-a8af25aaba867c5b.yaml:
--------------------------------------------------------------------------------
1 | ---
2 | deprecations:
3 | - |
4 | ZeroMQ support has been deprecated. The ZeroMQ driver ``zmq://`` has
5 | been unmaintained for over a year and no longer functions
6 | properly. It is recommended to use one of the maintained backends
7 | instead, such as RabbitMQ or AMQP 1.0.
8 |
--------------------------------------------------------------------------------
/releasenotes/notes/deprecate-eventlet-executor-13835b9818fd77f2.yaml:
--------------------------------------------------------------------------------
1 | ---
2 | deprecations:
3 | - |
4 | Eventlet usages are deprecated and the removal of Eventlet from
5 | OpenStack `is planned `_, for this reason the Eventlet executor is
6 | deprecated. Start migrating your stack to the threading executor.
7 | Please also start considering removing your internal Eventlet usages.
8 | - |
9 | The `executor` parameter of the `MessageHandlingServer` class is now
10 | deprecated and planned for removal. The Eventlet executor is deprecated.
11 | Only the threading executor will remains available so the `executor`
12 | parameter is useless.
13 |
--------------------------------------------------------------------------------
/releasenotes/notes/deprecate-the-option-heartbeat_in_pthread-from-rabbit-driver-5757adb83701caa5.yaml:
--------------------------------------------------------------------------------
1 | ---
2 | deprecations:
3 | - |
4 | The ``heartbeat_in_pthread`` option from the rabbitmq driver has been
5 | deprecated and it is recommended not to use the feature anymore.
6 | The option is strongly related to Eventlet but Eventlet will be removed
7 | from OpenStack services in a future release. In addition, this feature has
8 | never worked with services using eventlet for core service framework.
9 |
--------------------------------------------------------------------------------
/releasenotes/notes/deprecated-amqp1-driver-4bf57449bc2b7aad.yaml:
--------------------------------------------------------------------------------
1 | ---
2 | deprecations:
3 | - |
4 | The AMQP1 driver is now deprecated. Its related functional tests are also
5 | disabled. Neither debian nor ubuntu in the latest releases have any binary
6 | built for qpid server, not even 3rd party. Only qpid proton, the client
7 | lib, is available.
8 |
--------------------------------------------------------------------------------
/releasenotes/notes/disable-mandatory-flag-a6210a534f3853f0.yaml:
--------------------------------------------------------------------------------
1 | ---
2 | upgrade:
3 | - |
4 | Deprecating the ``direct_mandatory_flag``. It will not be possible to
5 | deactivate this functionality anymore.
6 |
--------------------------------------------------------------------------------
/releasenotes/notes/do-not-run-heartbeat-in-pthread-by-default-42e1299f59b841f8.yaml:
--------------------------------------------------------------------------------
1 | ---
2 | upgrade:
3 | - |
4 | The ``[oslo_messaging_rabbit] heartbeat_in_pthread`` config option
5 | defaults to ``False`` again.
6 | For wsgi applications it is recommended to set this value to ``True``
7 | but enabling it for non-wsgi services may break such service.
8 | Please check https://bugs.launchpad.net/oslo.messaging/+bug/1934937
9 | for more details.
10 |
--------------------------------------------------------------------------------
/releasenotes/notes/drop-python27-support-5ef2f365d8930483.yaml:
--------------------------------------------------------------------------------
1 | ---
2 | upgrade:
3 | - |
4 | Support for Python 2.7 has been dropped. The minimum version of Python now
5 | supported is Python 3.6.
6 |
--------------------------------------------------------------------------------
/releasenotes/notes/enforce_fips_mode-07dd259eb8a73c2b.yaml:
--------------------------------------------------------------------------------
1 | ---
2 | features:
3 | - |
4 | Adding a new option, ``[oslo_messaging_rabbit] ssl_enforce_fips_mode``, to
5 | the rabbitmq driver to enforce the OpenSSL FIPS mode if supported by the
6 | version of Python.
7 | security:
8 | - |
9 | We are now able to enforce the OpenSSL FIPS mode by using
10 | ``[oslo_messaging_rabbit] ssl_enforce_fips_mode``.
11 |
--------------------------------------------------------------------------------
/releasenotes/notes/fix-access_policy-deafult-a6954a147cb002b0.yaml:
--------------------------------------------------------------------------------
1 | ---
2 | upgrade:
3 | - |
4 | Change the default value of RPC dispatcher access_policy
5 | to DefaultRPCAccessPolicy.
6 |
--------------------------------------------------------------------------------
/releasenotes/notes/get-rpc-client-0b4aa62160864b29.yaml:
--------------------------------------------------------------------------------
1 | ---
2 | features:
3 | - |
4 | Added new ``get_rpc_client`` function to instantiate the RPCClient
5 | class
6 | deprecations:
7 | - |
8 | Instantiating the RPCClient class directly is deprecated in favor
9 | of using the new ``get_rpc_client`` function to expose a more
10 | common API similar to existing functions such as ``get_rpc_server``
11 | and ``get_rpc_transport``
12 |
--------------------------------------------------------------------------------
/releasenotes/notes/get-rpc-helpers-cls-8911826ac08aef2a.yaml:
--------------------------------------------------------------------------------
1 | ---
2 | features:
3 | - |
4 | The ``get_rpc_transport``, ``get_rpc_server`` and ``get_rpc_client`` helper
5 | functions now have support for overriding the class that is instantiated.
6 |
--------------------------------------------------------------------------------
/releasenotes/notes/get_rpc_transport-4aa3511ad9754a60.yaml:
--------------------------------------------------------------------------------
1 | ---
2 | features:
3 | - |
4 | Add get_rpc_transport call to make the API clear for the separation
5 | of RPC and Notification messaging backends.
6 | deprecations:
7 | - |
8 | Deprecate get_transport and use get_rpc_transport or
9 | get_notification_transport to make the API usage clear for the
10 | separation of RPC and Notification messaging backends.
11 |
--------------------------------------------------------------------------------
/releasenotes/notes/handle-missing-queue-553a803f94976be7.yaml:
--------------------------------------------------------------------------------
1 | ---
2 | features:
3 | - |
4 | Adding retry strategy based on the mandatory flag. Missing exchanges and
5 | queues are now identified separately for logging purposes.
6 |
--------------------------------------------------------------------------------
/releasenotes/notes/heartbeat-rate-3-7ada9edbccc11a3f.yaml:
--------------------------------------------------------------------------------
1 | ---
2 | fixes:
3 | - |
4 | Change heartbeat_rate default from 2 to 3 in order to send AMQP heartbeat
5 | frames at correct interval
6 |
--------------------------------------------------------------------------------
/releasenotes/notes/kafka-client-library-change-fe16d5a34550db7f.yaml:
--------------------------------------------------------------------------------
1 | ---
2 | fixes:
3 | - |
4 | Threading issues with the kafka-python consumer client were identified
5 | and documented. The driver has been updated to integrate the
6 | confluent-kafka python library. The confluent-kafka client
7 | leverages the high performance librdkafka C client and is safe
8 | for multiple thread use.
9 | upgrade:
10 | - |
11 | With the change in the client library used, projects using the
12 | Kafka driver should use extras oslo.messaging[kafka] to pull in
13 | dependencies for the driver.
14 |
--------------------------------------------------------------------------------
/releasenotes/notes/kombo-reconnect-splay-a81eb5fca6180510.yaml:
--------------------------------------------------------------------------------
1 | ---
2 | features:
3 | - |
4 | Add a new option named `kombu_reconnect_splay` under
5 | `oslo_messaging_rabbit` that could be used to add an extra random delay
6 | before any reconnection when a recoverable error occur.
7 | This delay is set to 0 by default so the original behavior is not changed.
8 |
--------------------------------------------------------------------------------
/releasenotes/notes/no-log-if-ignore-errors-e2223b8a646b4c40.yaml:
--------------------------------------------------------------------------------
1 | other:
2 | - |
3 | NoSuchMethod exception will not be logged for special non-existing methods
4 | which names end with '_ignore_errors'. Such methods might be used
5 | as health probes for openstack services.
6 |
--------------------------------------------------------------------------------
/releasenotes/notes/option-rabbitmq-max_retries-has-been-deprecated-471f66a9e6d672a2.yaml:
--------------------------------------------------------------------------------
1 | ---
2 | deprecations:
3 | - The rabbitmq driver option ``DEFAULT/max_retries`` has been deprecated
4 | for removal (at a later point in the future) as it did not make logical
5 | sense for notifications and for RPC.
6 |
--------------------------------------------------------------------------------
/releasenotes/notes/oslo-metrics-support-fe16343a637cc14b.yaml:
--------------------------------------------------------------------------------
1 | ---
2 | features:
3 | - |
4 | | Introduce support for sending rpc client metrics to oslo.metrics.
5 | | This feature can be enabled by setting a configuration parameter:
6 |
7 | [oslo_messaging_metrics]
8 | metrics_enabled = True # default is false
9 |
--------------------------------------------------------------------------------
/releasenotes/notes/pika-driver-has-been-deprecated-e2407fa53c91fe5c.yaml:
--------------------------------------------------------------------------------
1 | ---
2 | deprecations:
3 | - The pika driver has been deprecated for removal in Rocky. This
4 | driver was developed as a replacement for the default rabbit
5 | driver. However testing has not shown any appreciable improvement
6 | over the default rabbit driver in terms of performance and
7 | stability.
8 |
9 |
--------------------------------------------------------------------------------
/releasenotes/notes/rabbit-no-wait-for-ack-9e5de3e1320d7660.yaml:
--------------------------------------------------------------------------------
1 | ---
2 | other:
3 | - |
4 | On rabbitmq, in the past, acknownlegement of messages was done within the
5 | application callback thread/greenlet. This thread was blocked until the
6 | message was ack. In newton, we rewrote the message acknownlegement to
7 | ensure we haven't two threads writting the socket at the same times.
8 | Now all pendings ack are done by the main thread. They are no more reason
9 | to block the application callback thread until the message is ack. Other
10 | driver already release the application callback threads before the message
11 | is acknownleged. This is also the case for rabbitmq, now.
12 |
13 |
--------------------------------------------------------------------------------
/releasenotes/notes/rabbit_queue_manager-363209285cbbe257.yaml:
--------------------------------------------------------------------------------
1 | ---
2 | features:
3 | - |
4 | Add three new options (``use_queue_manager``, ``hostname``,
5 | ``processname``) to switch oslo.messaging from random queue names
6 | (for reply_q and fanouts) to consistent naming.
7 | The default value is False, so oslo.messaging will still use random queue
8 | names if nothing is set in configuration file of services.
9 | When switching use_queue_manager to True, the uuid4 random string from the
10 | queue name is replaced with a combination of hostname, processname and
11 | counter.
12 | The counter will be kept in shared memory (/dev/shm/x_y_qmanager).
13 | This way, when a service using oslo.messaging restarts (e.g. neutron),
14 | it will re-create the queues using the same name as the previous run, so
15 | no new queues are created and no need for rabbitmq to delete the previous
16 | queues.
17 | This is extremely useful for operator to debug which queue belong to which
18 | server/process.
19 | It's also higlhy recommended to enable this feature when using quorum
20 | queues for transient (option named ``rabbit_transient_quorum_queue``) to
21 | avoid consuming all erlang atoms after some time.
22 |
--------------------------------------------------------------------------------
/releasenotes/notes/rabbit_quorum_typo-9c06a9fd8d767f53.yaml:
--------------------------------------------------------------------------------
1 | ---
2 | fixes:
3 | - |
4 | Fixed typo in variable names ``rabbit_quorum_max_memory_length``
5 | and ``rabbit_quorum_max_memory_bytes``. Please make changes in your
6 | config files to correspond correct variables.
7 |
--------------------------------------------------------------------------------
/releasenotes/notes/rabbit_transient_quorum-fc3c3f88ead90034.yaml:
--------------------------------------------------------------------------------
1 | ---
2 | features:
3 | - |
4 | Add an option to enable transient queues to use quorum.
5 |
6 | Transient queues in OpenStack are not so transient, they live the whole
7 | process lifetime (e.g. until you restart a service, like nova-compute).
8 | Transient here means they belong to a specific process, compared to
9 | regular queues which may be used by more processes.
10 | Usually, transients queues are the "fanout" and "reply" queues.
11 |
12 | By default, without any rabbitmq policy tuning, they are not durable
13 | neither highly available.
14 |
15 | By enabling quorum for transients, oslo.messaging will declare quorum
16 | queues instead of classic on rabbitmq. As a result, those queues will
17 | automatically become HA and durable.
18 | Note that this may have an impact on your cluster, as rabbit will need
19 | more cpu, ram and network bandwith to manage the queues. This was tested
20 | at pretty large scale (2k hypervisors) with a cluster of 5 nodes.
21 |
22 | Also note that the current rabbitmq implementation rely on a fixed number
23 | of "erlang atom" (5M by default), and one atom is consumed each time a
24 | quorum queue is created with a different name. If your deployment is doing
25 | a lot of queue deletion/creation, you may consume all your atoms quicker.
26 |
27 | When enabling quorum for transients, you may also want to update your
28 | rabbitmq policies accordingly (e.g. make sure they apply on quorum).
29 |
30 | This option will stay disabled by default for now but may become the
31 | default in the future.
32 |
--------------------------------------------------------------------------------
/releasenotes/notes/rabbitmq-opts-cleanup-e0f97d4cc0855c5a.yaml:
--------------------------------------------------------------------------------
1 | ---
2 | upgrade:
3 | - |
4 | The deprecated ``[oslo_messaging_rabbit] rabbit_use_ssl`` option has been
5 | removed. Use the ``ssl`` option instead.
6 |
7 | - |
8 | The following deprecated options in ``[oslo_messaging_rabbit]`` section
9 | have been removed. Use the ones without ``kombu_`` prefix.
10 |
11 | - ``kombu_ssl_version``
12 | - ``kombu_ssl_keyfile``
13 | - ``kombu_ssl_certfile``
14 | - ``kombu_ssl_ca_certs``
15 |
16 | - |
17 | The following options are no longer loaded from the ``[DEFAULT]`` section.
18 | Use the ``[oslo_messaging_rabbit]`` section instead.
19 |
20 | - ``amqp_auto_delete``
21 | - ``kombu_reconnect_delay``
22 | - ``rabbit_login_method``
23 | - ``rabbit_retry_backoff``
24 | - ``rabbit_ha_queues``
25 | - ``rpc_conn_pool_size``
26 |
--------------------------------------------------------------------------------
/releasenotes/notes/removal-deprecated-options-6d4c5db90525c52d.yaml:
--------------------------------------------------------------------------------
1 | ---
2 | upgrade:
3 | - |
4 | Remove deprecated configuration options from multiple drivers.
5 |
6 | * The rpc_backend option from the [DEFAULT] section has been removed.
7 | * The AMQP driver has removed the configuration options of allow_insecure_clients, username and password from the [oslo_messaging_amqp] section.
8 | * The Kafa driver has removed the configuration options of kafka_default_host and kafka_default_port from the [oslo_messaging_kafka] section.
9 | * The Rabbit driver has removed the configuration options of rabbit_host, rabbit_port, rabbit_hosts, rabbit_userid, rabbit_password, rabbit_virtual_host rabbit_max_retries and rabbit_durable_queues from the [oslo_messaging_rabbit] section.
10 |
11 | Operators must switch to setting the transport_url directive in the [DEFAULT] section.
12 |
--------------------------------------------------------------------------------
/releasenotes/notes/remove-RequestContextSerializer-234c0496a7e0376b.yaml:
--------------------------------------------------------------------------------
1 | ---
2 | upgrade:
3 | - RequestContextSerializer was deprecated since 4.6, and it
4 | isn't used by any other project, so we can remove it safely.
5 |
--------------------------------------------------------------------------------
/releasenotes/notes/remove-ZeroMQ-driver-e9e0bbbb7bd4f5e6.yaml:
--------------------------------------------------------------------------------
1 | ---
2 | prelude: >
3 | The ZMQ-based driver for RPC communications has been removed
4 | deprecations:
5 | - |
6 | The driver support for the ZeroMQ messaging library is removed.
7 | Users of the oslo.messaging RPC services must use the supported
8 | rabbit ("rabbit://...") or amqp1 ("amqp://..." )drivers.
9 |
--------------------------------------------------------------------------------
/releasenotes/notes/remove-amqp1-c924ea548dadffaa.yaml:
--------------------------------------------------------------------------------
1 | ---
2 | upgrade:
3 | - |
4 | The AMQP1 driver, which was deprecated in 14.1.0 was removed, due to
5 | limited usage and lack of support on recent distributions. Use any of
6 | the other supported driver, such as RabbitMQ or Kafka.
7 |
--------------------------------------------------------------------------------
/releasenotes/notes/remove-deprecated-notif-opts-142f8eea540c17ec.yaml:
--------------------------------------------------------------------------------
1 | ---
2 | upgrade:
3 | - |
4 | The following deprecated options have been removed. Use the equivalent
5 | options in the ``[oslo_messaging_notifications]`` secion instead.
6 |
7 | - ``[DEFAULT] notification_driver``
8 | - ``[DEFAULT] notification_transport_url``
9 | - ``[DEFAULT] notification_topics``
10 | - ``[DEFAULT] routing_config``
11 |
12 | - |
13 | The deprecated ``[rpc_notifier2] topics`` option has been removed. Use
14 | the ``[oslo_messaging_notifications] topics`` option instead.
15 |
--------------------------------------------------------------------------------
/releasenotes/notes/remove-kafka-conn-pool-opts-0b7962e2f22b24ed.yaml:
--------------------------------------------------------------------------------
1 | ---
2 | upgrade:
3 | - |
4 | The following deprecated options in the ``[oslo_messaging_kafka]`` section
5 | have been removed.
6 |
7 | - ``pool_size``
8 | - ``conn_pool_min_size``
9 | - ``conn_pool_ttl``
10 |
--------------------------------------------------------------------------------
/releasenotes/notes/remove-old-quorum-opts-with-typo-5e013064fb6df062.yaml:
--------------------------------------------------------------------------------
1 | ---
2 | upgrade:
3 | - |
4 | The following options in ``[oslo_messaging_rabbit]`` secion have been
5 | removed.
6 |
7 | - ``rabbit_quroum_max_memory_length``
8 | - ``rabbit_quroum_max_memory_bytes``
9 |
--------------------------------------------------------------------------------
/releasenotes/notes/remove-pika-1bae204ced2521a3.yaml:
--------------------------------------------------------------------------------
1 | ---
2 | prelude: >
3 | The Pika-based driver for RabbitMQ has been removed.
4 | upgrade:
5 | - |
6 | Users of the Pika-based driver must change the prefix of all the
7 | transport_url configuration options from "pika://..." to
8 | "rabbit://..." to use the default kombu based RabbitMQ driver.
9 |
--------------------------------------------------------------------------------
/releasenotes/notes/remove-py38-381f832001230756.yaml:
--------------------------------------------------------------------------------
1 | ---
2 | upgrade:
3 | - |
4 | Support for Python 3.8 has been removed. Now the minimum python version
5 | supported is 3.9 .
6 |
--------------------------------------------------------------------------------
/releasenotes/notes/reply_q-timeout-e3c3bae636e8bc74.yaml:
--------------------------------------------------------------------------------
1 | ---
2 | features:
3 | - |
4 | The name of the ``reply_q`` is now logged when a timeout occurs while waiting for a reply.
5 |
--------------------------------------------------------------------------------
/releasenotes/notes/retry-support-07996ef04dda9482.yaml:
--------------------------------------------------------------------------------
1 | ---
2 | features:
3 | - |
4 | | Retry support for oslo_messaging_notifications driver
5 | | Configuration param 'retry' is added. Default is -1, indefinite
6 |
7 | * *retry* (default=-1)
8 |
9 |
--------------------------------------------------------------------------------
/releasenotes/notes/run-heartbeat-in-pthread-by-default-28637b41ebf500dc.yaml:
--------------------------------------------------------------------------------
1 | ---
2 | upgrade:
3 | - |
4 | The ``[oslo_messaging_rabbit] heartbeat_in_pthread`` config option now
5 | defaults to ``True``.
6 | Applications will run RabbitMQ heartbeat in a Python thread by default.
7 | deprecations:
8 | - |
9 | ``heartbeat_in_pthread`` has been deprecated and will be removed in a
10 | future release. If configured, this option should be unset.
11 |
--------------------------------------------------------------------------------
/releasenotes/notes/stream-c3dd31ee98f6bbd7.yaml:
--------------------------------------------------------------------------------
1 | ---
2 | features:
3 | - |
4 | Add an option to use stream queues for rabbitmq driver instead of fanouts.
5 |
--------------------------------------------------------------------------------
/releasenotes/notes/undeprecate_heartbeat_in_pthread-48e2c1fc008cf208.yaml:
--------------------------------------------------------------------------------
1 | ---
2 | upgrade:
3 | - |
4 | We undeprecated the ``heartbeat_in_pthread`` option. This option will
5 | remain available to allow customers to run the rabbitmq heartbeat in
6 | python thread or not.
7 |
--------------------------------------------------------------------------------
/releasenotes/notes/use-extras-for-optional-deps-2a00e8007ef7a629.yaml:
--------------------------------------------------------------------------------
1 | ---
2 | prelude: >
3 | Projects using any of the optional drivers can use extras to
4 | pull in dependencies for that driver.
5 | upgrade:
6 | - |
7 | Projects using the AMQP 1.0 driver may now depend on
8 | oslo.messaging[amqp1]. Projects using the Kafka driver may now
9 | depend on oslo.messaging[kafka]
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/releasenotes/source/2023.1.rst:
--------------------------------------------------------------------------------
1 | ===========================
2 | 2023.1 Series Release Notes
3 | ===========================
4 |
5 | .. release-notes::
6 | :branch: unmaintained/2023.1
7 |
--------------------------------------------------------------------------------
/releasenotes/source/2023.2.rst:
--------------------------------------------------------------------------------
1 | ===========================
2 | 2023.2 Series Release Notes
3 | ===========================
4 |
5 | .. release-notes::
6 | :branch: stable/2023.2
7 |
--------------------------------------------------------------------------------
/releasenotes/source/2024.1.rst:
--------------------------------------------------------------------------------
1 | ===========================
2 | 2024.1 Series Release Notes
3 | ===========================
4 |
5 | .. release-notes::
6 | :branch: stable/2024.1
7 |
--------------------------------------------------------------------------------
/releasenotes/source/2024.2.rst:
--------------------------------------------------------------------------------
1 | ===========================
2 | 2024.2 Series Release Notes
3 | ===========================
4 |
5 | .. release-notes::
6 | :branch: stable/2024.2
7 |
--------------------------------------------------------------------------------
/releasenotes/source/2025.1.rst:
--------------------------------------------------------------------------------
1 | ===========================
2 | 2025.1 Series Release Notes
3 | ===========================
4 |
5 | .. release-notes::
6 | :branch: stable/2025.1
7 |
--------------------------------------------------------------------------------
/releasenotes/source/_static/.placeholder:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/openstack/oslo.messaging/510688d8ddc807242fe9a36532dd03ba3c2d4ad5/releasenotes/source/_static/.placeholder
--------------------------------------------------------------------------------
/releasenotes/source/_templates/.placeholder:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/openstack/oslo.messaging/510688d8ddc807242fe9a36532dd03ba3c2d4ad5/releasenotes/source/_templates/.placeholder
--------------------------------------------------------------------------------
/releasenotes/source/conf.py:
--------------------------------------------------------------------------------
1 | # Licensed under the Apache License, Version 2.0 (the "License");
2 | # you may not use this file except in compliance with the License.
3 | # You may obtain a copy of the License at
4 | #
5 | # http://www.apache.org/licenses/LICENSE-2.0
6 | #
7 | # Unless required by applicable law or agreed to in writing, software
8 | # distributed under the License is distributed on an "AS IS" BASIS,
9 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
10 | # implied.
11 | # See the License for the specific language governing permissions and
12 | # limitations under the License.
13 |
14 | # oslo.log Release Notes documentation build configuration file, created by
15 | # sphinx-quickstart on Tue Nov 3 17:40:50 2015.
16 | #
17 | # This file is execfile()d with the current directory set to its
18 | # containing dir.
19 | #
20 | # Note that not all possible configuration values are present in this
21 | # autogenerated file.
22 | #
23 | # This file does only contain a selection of the most common options. For a
24 | # full list see the documentation:
25 | # http://www.sphinx-doc.org/en/master/config
26 |
27 | # -- Project information --------------------------------------------------
28 | # General information about the project.
29 | copyright = '2016, oslo.messaging Developers'
30 |
31 | # Release notes do not need a version in the title, they span
32 | # multiple versions.
33 | # The full version, including alpha/beta/rc tags.
34 | release = ''
35 | # The short X.Y version.
36 | version = ''
37 |
38 | # -- General configuration ------------------------------------------------
39 |
40 | # Add any Sphinx extension module names here, as strings. They can be
41 | # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom ones.
42 | extensions = [
43 | 'openstackdocstheme',
44 | 'reno.sphinxext',
45 | ]
46 |
47 | # openstackdocstheme options
48 | openstackdocs_repo_name = 'openstack/oslo.messaging'
49 | openstackdocs_bug_project = 'oslo.messaging'
50 | openstackdocs_bug_tag = ''
51 |
52 | # The master toctree document.
53 | master_doc = 'index'
54 |
55 | # -- Options for HTML output ----------------------------------------------
56 |
57 | # The theme to use for HTML and HTML Help pages. See the documentation for
58 | # a list of builtin themes.
59 | html_theme = 'openstackdocs'
60 |
61 | # -- Options for Internationalization output ------------------------------
62 | locale_dirs = ['locale/']
63 |
--------------------------------------------------------------------------------
/releasenotes/source/index.rst:
--------------------------------------------------------------------------------
1 | =============================
2 | oslo.messaging Release Notes
3 | =============================
4 |
5 | .. toctree::
6 | :maxdepth: 1
7 |
8 | unreleased
9 | 2025.1
10 | 2024.2
11 | 2024.1
12 | 2023.2
13 | 2023.1
14 | zed
15 | yoga
16 | xena
17 | wallaby
18 | victoria
19 | ussuri
20 | train
21 | stein
22 | rocky
23 | queens
24 | pike
25 | ocata
26 | newton
27 |
--------------------------------------------------------------------------------
/releasenotes/source/newton.rst:
--------------------------------------------------------------------------------
1 | ============================
2 | Newton Series Release Notes
3 | ============================
4 |
5 | .. release-notes::
6 | :branch: origin/stable/newton
7 |
--------------------------------------------------------------------------------
/releasenotes/source/ocata.rst:
--------------------------------------------------------------------------------
1 | ===========================
2 | Ocata Series Release Notes
3 | ===========================
4 |
5 | .. release-notes::
6 | :branch: origin/stable/ocata
7 |
--------------------------------------------------------------------------------
/releasenotes/source/pike.rst:
--------------------------------------------------------------------------------
1 | ===================================
2 | Pike Series Release Notes
3 | ===================================
4 |
5 | .. release-notes::
6 | :branch: stable/pike
7 |
--------------------------------------------------------------------------------
/releasenotes/source/queens.rst:
--------------------------------------------------------------------------------
1 | ===================================
2 | Queens Series Release Notes
3 | ===================================
4 |
5 | .. release-notes::
6 | :branch: stable/queens
7 |
--------------------------------------------------------------------------------
/releasenotes/source/rocky.rst:
--------------------------------------------------------------------------------
1 | ===================================
2 | Rocky Series Release Notes
3 | ===================================
4 |
5 | .. release-notes::
6 | :branch: stable/rocky
7 |
--------------------------------------------------------------------------------
/releasenotes/source/stein.rst:
--------------------------------------------------------------------------------
1 | ===================================
2 | Stein Series Release Notes
3 | ===================================
4 |
5 | .. release-notes::
6 | :branch: stable/stein
7 |
--------------------------------------------------------------------------------
/releasenotes/source/train.rst:
--------------------------------------------------------------------------------
1 | ==========================
2 | Train Series Release Notes
3 | ==========================
4 |
5 | .. release-notes::
6 | :branch: stable/train
7 |
--------------------------------------------------------------------------------
/releasenotes/source/unreleased.rst:
--------------------------------------------------------------------------------
1 | =============================
2 | Current Series Release Notes
3 | =============================
4 |
5 | .. release-notes::
6 |
--------------------------------------------------------------------------------
/releasenotes/source/ussuri.rst:
--------------------------------------------------------------------------------
1 | ===========================
2 | Ussuri Series Release Notes
3 | ===========================
4 |
5 | .. release-notes::
6 | :branch: stable/ussuri
7 |
--------------------------------------------------------------------------------
/releasenotes/source/victoria.rst:
--------------------------------------------------------------------------------
1 | =============================
2 | Victoria Series Release Notes
3 | =============================
4 |
5 | .. release-notes::
6 | :branch: unmaintained/victoria
7 |
--------------------------------------------------------------------------------
/releasenotes/source/wallaby.rst:
--------------------------------------------------------------------------------
1 | ============================
2 | Wallaby Series Release Notes
3 | ============================
4 |
5 | .. release-notes::
6 | :branch: unmaintained/wallaby
7 |
--------------------------------------------------------------------------------
/releasenotes/source/xena.rst:
--------------------------------------------------------------------------------
1 | =========================
2 | Xena Series Release Notes
3 | =========================
4 |
5 | .. release-notes::
6 | :branch: unmaintained/xena
7 |
--------------------------------------------------------------------------------
/releasenotes/source/yoga.rst:
--------------------------------------------------------------------------------
1 | =========================
2 | Yoga Series Release Notes
3 | =========================
4 |
5 | .. release-notes::
6 | :branch: unmaintained/yoga
7 |
--------------------------------------------------------------------------------
/releasenotes/source/zed.rst:
--------------------------------------------------------------------------------
1 | ========================
2 | Zed Series Release Notes
3 | ========================
4 |
5 | .. release-notes::
6 | :branch: unmaintained/zed
7 |
--------------------------------------------------------------------------------
/requirements.txt:
--------------------------------------------------------------------------------
1 | # Requirements lower bounds listed here are our best effort to keep them up to
2 | # date but we do not test them so no guarantee of having them all correct. If
3 | # you find any incorrect lower bounds, let us know or propose a fix.
4 |
5 | pbr>=2.0.0 # Apache-2.0
6 |
7 | futurist>=1.2.0 # Apache-2.0
8 | oslo.config>=5.2.0 # Apache-2.0
9 | oslo.context>=5.3.0 # Apache-2.0
10 | oslo.log>=3.36.0 # Apache-2.0
11 | oslo.utils>=3.37.0 # Apache-2.0
12 | oslo.serialization>=2.18.0 # Apache-2.0
13 | oslo.service>=1.24.0 # Apache-2.0
14 | stevedore>=1.20.0 # Apache-2.0
15 | debtcollector>=1.2.0 # Apache-2.0
16 |
17 | # for jsonutils
18 | cachetools>=2.0.0 # MIT License
19 |
20 | WebOb>=1.7.1 # MIT
21 |
22 | # for the routing notifier
23 | PyYAML>=3.13 # MIT
24 |
25 | # rabbit driver is the default
26 | # we set the amqp version to ensure heartbeat works
27 | amqp>=2.5.2 # BSD
28 | kombu>=4.6.6 # BSD
29 |
30 | # middleware
31 | oslo.middleware>=3.31.0 # Apache-2.0
32 |
33 | # metrics
34 | oslo.metrics>=0.2.1 # Apache-2.0
35 |
--------------------------------------------------------------------------------
/setup.cfg:
--------------------------------------------------------------------------------
1 | [metadata]
2 | name = oslo.messaging
3 | author = OpenStack
4 | author_email = openstack-discuss@lists.openstack.org
5 | summary = Oslo Messaging API
6 | description_file =
7 | README.rst
8 | home_page = https://docs.openstack.org/oslo.messaging/latest/
9 | python_requires = >=3.9
10 | classifier =
11 | Environment :: OpenStack
12 | Intended Audience :: Developers
13 | Intended Audience :: Information Technology
14 | License :: OSI Approved :: Apache Software License
15 | Operating System :: OS Independent
16 | Programming Language :: Python
17 | Programming Language :: Python :: 3
18 | Programming Language :: Python :: 3.9
19 | Programming Language :: Python :: 3.10
20 | Programming Language :: Python :: 3.11
21 | Programming Language :: Python :: 3.12
22 | Programming Language :: Python :: 3 :: Only
23 | Programming Language :: Python :: Implementation :: CPython
24 |
25 | [extras]
26 | # package dependencies for optional (non-rabbitmq) messaging drivers.
27 | # projects can test-depend on oslo.messaging[]
28 | # e.g.: oslo.messaging[kafka]
29 | kafka =
30 | confluent-kafka>=1.3.0 # Apache-2.0
31 |
32 | [files]
33 | packages =
34 | oslo_messaging
35 |
36 | [entry_points]
37 | console_scripts =
38 | oslo-messaging-send-notification = oslo_messaging.notify.notifier:_send_notification
39 |
40 | oslo.messaging.drivers =
41 | rabbit = oslo_messaging._drivers.impl_rabbit:RabbitDriver
42 |
43 | # This driver is supporting for only notification usage
44 | kafka = oslo_messaging._drivers.impl_kafka:KafkaDriver
45 |
46 | # To avoid confusion
47 | kombu = oslo_messaging._drivers.impl_rabbit:RabbitDriver
48 |
49 | # This is just for internal testing
50 | fake = oslo_messaging._drivers.impl_fake:FakeDriver
51 |
52 | oslo.messaging.executors =
53 | eventlet = futurist:GreenThreadPoolExecutor
54 | threading = futurist:ThreadPoolExecutor
55 |
56 | oslo.messaging.notify.drivers =
57 | messagingv2 = oslo_messaging.notify.messaging:MessagingV2Driver
58 | messaging = oslo_messaging.notify.messaging:MessagingDriver
59 | log = oslo_messaging.notify._impl_log:LogDriver
60 | test = oslo_messaging.notify._impl_test:TestDriver
61 | noop = oslo_messaging.notify._impl_noop:NoOpDriver
62 | routing = oslo_messaging.notify._impl_routing:RoutingDriver
63 |
64 | oslo.config.opts =
65 | oslo.messaging = oslo_messaging.opts:list_opts
66 |
--------------------------------------------------------------------------------
/setup.py:
--------------------------------------------------------------------------------
1 | # Copyright (c) 2013 Hewlett-Packard Development Company, L.P.
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # http://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
12 | # implied.
13 | # See the License for the specific language governing permissions and
14 | # limitations under the License.
15 |
16 | import setuptools
17 |
18 | setuptools.setup(
19 | setup_requires=['pbr>=2.0.0'],
20 | pbr=True)
21 |
--------------------------------------------------------------------------------
/test-requirements.txt:
--------------------------------------------------------------------------------
1 | fixtures>=3.0.0 # Apache-2.0/BSD
2 | stestr>=2.0.0 # Apache-2.0
3 | testscenarios>=0.4 # Apache-2.0/BSD
4 | testtools>=2.2.0 # MIT
5 | oslotest>=3.2.0 # Apache-2.0
6 | pifpaf>=2.2.0 # Apache-2.0
7 |
8 | # for test_impl_kafka
9 | confluent-kafka>=1.3.0 # Apache-2.0
10 |
11 | coverage>=4.0 # Apache-2.0
12 |
13 | eventlet>=0.23.0 # MIT
14 | greenlet>=0.4.15 # MIT
15 |
--------------------------------------------------------------------------------
/tools/functions.sh:
--------------------------------------------------------------------------------
1 |
2 | wait_for_line () {
3 | while read line
4 | do
5 | echo "$line" | grep -q "$1" && break
6 | echo "$line" | grep "$2" && exit 1
7 | done < "$3"
8 | # Read the fifo for ever otherwise process would block
9 | cat "$3" >/dev/null &
10 | }
11 |
12 | function clean_exit(){
13 | local error_code="$?"
14 | for job in `jobs -p`
15 | do
16 | kill -9 $job
17 | done
18 | rm -rf "$1"
19 | return $error_code
20 | }
21 |
22 |
23 |
--------------------------------------------------------------------------------
/tools/setup-scenario-env.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | set -e
3 |
4 | . tools/functions.sh
5 |
6 | SCENARIO=${SCENARIO:-"scenario01"}
7 |
8 | function _setup_kafka {
9 |
10 | SCALA_VERSION=${SCALA_VERSION:-"2.12"}
11 | KAFKA_VERSION=${KAFKA_VERSION:-"2.0.0"}
12 |
13 | if [[ -z "$(which kafka-server-start)" ]] && [[ -z $(which kafka-server-start.sh) ]]; then
14 | DATADIR=$(mktemp -d /tmp/OSLOMSG-KAFKA.XXXXX)
15 | trap "clean_exit $DATADIR" EXIT
16 |
17 | tarball=kafka_${SCALA_VERSION}-${KAFKA_VERSION}.tgz
18 |
19 | wget http://archive.apache.org/dist/kafka/${KAFKA_VERSION}/$tarball -O $DATADIR/$tarball
20 | tar -xzf $DATADIR/$tarball -C $DATADIR
21 | export PATH=$DATADIR/kafka_${SCALA_VERSION}-${KAFKA_VERSION}/bin:$PATH
22 | fi
23 | }
24 |
25 | case $SCENARIO in
26 | scenario01)
27 | export RPC_TRANSPORT_URL=rabbit://pifpaf:secret@127.0.0.1:5682/
28 | export NOTIFY_TRANSPORT_URL=rabbit://pifpaf:secret@127.0.0.1:5682/
29 | RUN="--env-prefix RABBITMQ run rabbitmq"
30 | ;;
31 | scenario02)
32 | _setup_kafka
33 | export RPC_TRANSPORT_URL=rabbit://pifpaf:secret@127.0.0.1:5682/
34 | export NOTIFY_TRANSPORT_URL=kafka://127.0.0.1:9092/
35 | RUN="--env-prefix RABBITMQ run rabbitmq -- pifpaf --env-prefix KAFKA run kafka"
36 | ;;
37 | *) ;;
38 | esac
39 |
40 | pifpaf $RUN -- $*
41 |
--------------------------------------------------------------------------------
/tox.ini:
--------------------------------------------------------------------------------
1 | [tox]
2 | minversion = 3.18.0
3 | envlist = py3, pep8
4 |
5 | [testenv]
6 | passenv =
7 | OS_*
8 | ZUUL_CACHE_DIR
9 | REQUIREMENTS_PIP_LOCATION
10 | deps =
11 | -c{env:TOX_CONSTRAINTS_FILE:https://releases.openstack.org/constraints/upper/master}
12 | -r{toxinidir}/test-requirements.txt
13 | -r{toxinidir}/requirements.txt
14 | commands =
15 | stestr run --slowest {posargs}
16 |
17 | [testenv:pep8]
18 | skip_install = true
19 | deps =
20 | pre-commit>=2.6.0 # MIT
21 | commands =
22 | pre-commit run -a
23 |
24 | [testenv:cover]
25 | setenv =
26 | PYTHON=coverage run --source oslo_messaging --parallel-mode
27 | commands =
28 | coverage erase
29 | stestr run --slowest {posargs}
30 | coverage combine
31 | coverage html -d cover
32 | coverage report
33 | coverage report --show-missing
34 |
35 | [testenv:venv]
36 | commands = {posargs}
37 |
38 | [testenv:docs]
39 | allowlist_externals = rm
40 | deps =
41 | -c{env:TOX_CONSTRAINTS_FILE:https://releases.openstack.org/constraints/upper/master}
42 | -r{toxinidir}/doc/requirements.txt
43 | commands =
44 | rm -fr doc/build
45 | sphinx-build -W --keep-going -b html doc/source doc/build/html
46 |
47 | # The following functional test scenarios are defined for the
48 | # testing of the messaging backends and to demonstrated the functional
49 | # correctness across driver combinations (e.g. RPC and Notify)
50 | #
51 | # RPC Notify
52 | # -------- --------
53 | # scenario01 rabbit rabbit
54 | # scenario02 rabbit kafka
55 | #
56 | [testenv:py310-func-scenario01]
57 | setenv =
58 | SCENARIO=scenario01
59 | allowlist_externals =
60 | {toxinidir}/tools/setup-scenario-env.sh
61 | commands =
62 | {toxinidir}/tools/setup-scenario-env.sh stestr run --slowest {posargs:oslo_messaging.tests.functional}
63 |
64 | [testenv:py310-func-scenario02]
65 | setenv =
66 | SCENARIO=scenario02
67 | allowlist_externals =
68 | {toxinidir}/tools/setup-scenario-env.sh
69 | commands =
70 | {toxinidir}/tools/setup-scenario-env.sh stestr run --slowest {posargs:oslo_messaging.tests.functional}
71 |
72 | [flake8]
73 | show-source = True
74 | enable-extensions = H203,H106
75 | # E731 skipped as assign a lambda expression
76 | ignore = E731,H405,W504
77 | exclude = .tox,dist,doc,*.egg,build,__init__.py
78 |
79 | [hacking]
80 | import_exceptions =
81 |
82 | [flake8:local-plugins]
83 | extension =
84 | O321 = checks:check_oslo_namespace_imports
85 | O324 = checks:CheckForLoggingIssues
86 | paths = ./oslo_messaging/hacking
87 |
88 | [testenv:releasenotes]
89 | allowlist_externals =
90 | rm
91 | commands =
92 | rm -rf releasenotes/build
93 | sphinx-build -a -E -W -d releasenotes/build/doctrees --keep-going -b html releasenotes/source releasenotes/build/html
94 | deps =
95 | -c{env:TOX_CONSTRAINTS_FILE:https://releases.openstack.org/constraints/upper/master}
96 | -r{toxinidir}/doc/requirements.txt
97 |
98 | [testenv:bindep]
99 | deps =
100 | bindep
101 | commands = bindep {posargs}
102 |
--------------------------------------------------------------------------------