7ce2f557c6
Neutron uses bandit to detect security issues. This patch adds bandit to the pep8 gate to automatically lint for security issues in neutron-lib. Fixed two B101 errors it spotted. Change-Id: I39d713d0d230b5ae759daa6bc1be9794e6fe2a32
127 lines
4.6 KiB
Python
127 lines
4.6 KiB
Python
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
|
# not use this file except in compliance with the License. You may obtain
|
|
# a copy of the License at
|
|
#
|
|
# http://www.apache.org/licenses/LICENSE-2.0
|
|
#
|
|
# Unless required by applicable law or agreed to in writing, software
|
|
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
|
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
|
# License for the specific language governing permissions and limitations
|
|
# under the License.
|
|
|
|
import collections
|
|
import inspect
|
|
|
|
from neutron_lib._i18n import _
|
|
from neutron_lib.callbacks import manager
|
|
from neutron_lib.callbacks import priority_group
|
|
|
|
|
|
# TODO(armax): consider adding locking
|
|
_CALLBACK_MANAGER = None
|
|
|
|
# stores a dictionary keyed on function pointers with a list of
|
|
# (resource, event) tuples to subscribe to on class initialization
|
|
_REGISTERED_CLASS_METHODS = collections.defaultdict(list)
|
|
|
|
|
|
def _get_callback_manager():
|
|
global _CALLBACK_MANAGER
|
|
if _CALLBACK_MANAGER is None:
|
|
_CALLBACK_MANAGER = manager.CallbacksManager()
|
|
return _CALLBACK_MANAGER
|
|
|
|
|
|
def subscribe(callback, resource, event,
|
|
priority=priority_group.PRIORITY_DEFAULT):
|
|
_get_callback_manager().subscribe(callback, resource, event, priority)
|
|
|
|
|
|
def unsubscribe(callback, resource, event):
|
|
_get_callback_manager().unsubscribe(callback, resource, event)
|
|
|
|
|
|
def unsubscribe_by_resource(callback, resource):
|
|
_get_callback_manager().unsubscribe_by_resource(callback, resource)
|
|
|
|
|
|
def unsubscribe_all(callback):
|
|
_get_callback_manager().unsubscribe_all(callback)
|
|
|
|
|
|
# NOTE(boden): This method is deprecated in favor of publish() and will be
|
|
# removed in Queens, but not deprecation message to reduce log flooding
|
|
def notify(resource, event, trigger, **kwargs):
|
|
_get_callback_manager().notify(resource, event, trigger, **kwargs)
|
|
|
|
|
|
def publish(resource, event, trigger, payload=None):
|
|
_get_callback_manager().publish(resource, event, trigger, payload=payload)
|
|
|
|
|
|
def clear():
|
|
_get_callback_manager().clear()
|
|
|
|
|
|
def receives(resource, events, priority=priority_group.PRIORITY_DEFAULT):
|
|
"""Use to decorate methods on classes before initialization.
|
|
|
|
Any classes that use this must themselves be decorated with the
|
|
@has_registry_receivers decorator to setup the __new__ method to
|
|
actually register the instance methods after initialization.
|
|
"""
|
|
if not isinstance(events, (list, tuple, set)):
|
|
msg = _("'events' must be a collection (list, tuple, set)")
|
|
raise AssertionError(msg)
|
|
|
|
def decorator(f):
|
|
for e in events:
|
|
_REGISTERED_CLASS_METHODS[f].append((resource, e, priority))
|
|
return f
|
|
return decorator
|
|
|
|
|
|
def has_registry_receivers(klass):
|
|
"""Decorator to setup __new__ method in classes to subscribe bound methods.
|
|
|
|
Any method decorated with @receives above is an unbound method on a class.
|
|
This decorator sets up the class __new__ method to subscribe the bound
|
|
method in the callback registry after object instantiation.
|
|
"""
|
|
orig_new = klass.__new__
|
|
new_inherited = '__new__' not in klass.__dict__
|
|
|
|
@staticmethod
|
|
def replacement_new(cls, *args, **kwargs):
|
|
if new_inherited:
|
|
# class didn't define __new__ so we need to call inherited __new__
|
|
super_new = super(klass, cls).__new__
|
|
if super_new is object.__new__:
|
|
# object.__new__ doesn't accept args nor kwargs
|
|
instance = super_new(cls)
|
|
else:
|
|
instance = super_new(cls, *args, **kwargs)
|
|
else:
|
|
instance = orig_new(cls, *args, **kwargs)
|
|
if getattr(instance, '_DECORATED_METHODS_SUBSCRIBED', False):
|
|
# Avoid running this logic twice for classes inheriting other
|
|
# classes with this same decorator. Only one needs to execute
|
|
# to subscribe all decorated methods.
|
|
return instance
|
|
for name, unbound_method in inspect.getmembers(cls):
|
|
if (not inspect.ismethod(unbound_method) and
|
|
not inspect.isfunction(unbound_method)):
|
|
continue
|
|
# handle py27/py34 difference
|
|
func = getattr(unbound_method, 'im_func', unbound_method)
|
|
if func not in _REGISTERED_CLASS_METHODS:
|
|
continue
|
|
for resource, event, priority in _REGISTERED_CLASS_METHODS[func]:
|
|
# subscribe the bound method
|
|
subscribe(getattr(instance, name), resource, event, priority)
|
|
setattr(instance, '_DECORATED_METHODS_SUBSCRIBED', True)
|
|
return instance
|
|
klass.__new__ = replacement_new
|
|
return klass
|