Ejemplo n.º 1
0
    def __init__(self):
        LOG.info("Ml2Plus initializing")
        registry._get_callback_manager()._notify_loop = (
            patch_neutron._notify_loop)
        # First load drivers, then initialize DB, then initialize drivers
        self.type_manager = ml2_managers.TypeManager()
        self.extension_manager = managers.ExtensionManager()
        self.mechanism_manager = managers.MechanismManager()
        super(ml2_plugin.Ml2Plugin, self).__init__()
        self.type_manager.initialize()
        self.extension_manager.initialize()
        self.mechanism_manager.initialize()
        registry.subscribe(self._port_provisioned, resources.PORT,
                           provisioning_blocks.PROVISIONING_COMPLETE)
        registry.subscribe(self._handle_segment_change, resources.SEGMENT,
                           events.PRECOMMIT_CREATE)
        registry.subscribe(self._handle_segment_change, resources.SEGMENT,
                           events.PRECOMMIT_DELETE)
        registry.subscribe(self._handle_segment_change, resources.SEGMENT,
                           events.AFTER_CREATE)
        registry.subscribe(self._handle_segment_change, resources.SEGMENT,
                           events.AFTER_DELETE)

        # REVISIT(kent): All the postcommit calls for SG and SG rules are not
        # currently implemented as they are not needed at this moment.
        registry.subscribe(self._handle_security_group_change,
                           resources.SECURITY_GROUP, events.PRECOMMIT_CREATE)
        registry.subscribe(self._handle_security_group_change,
                           resources.SECURITY_GROUP, events.PRECOMMIT_DELETE)
        registry.subscribe(self._handle_security_group_change,
                           resources.SECURITY_GROUP, events.PRECOMMIT_UPDATE)

        # There is no update event to the security_group_rule
        registry.subscribe(self._handle_security_group_rule_change,
                           resources.SECURITY_GROUP_RULE,
                           events.PRECOMMIT_CREATE)
        registry.subscribe(self._handle_security_group_rule_change,
                           resources.SECURITY_GROUP_RULE,
                           events.PRECOMMIT_DELETE)
        try:
            registry.subscribe(self._subnet_delete_precommit_handler,
                               resources.SUBNET, events.PRECOMMIT_DELETE)
            registry.subscribe(self._subnet_delete_after_delete_handler,
                               resources.SUBNET, events.AFTER_DELETE)
        except AttributeError:
            LOG.info("Detected older version of Neutron, ML2Plus plugin "
                     "is not subscribed to subnet_precommit_delete and "
                     "subnet_after_delete events")
        self._setup_dhcp()
        self._start_rpc_notifiers()
        self.add_agent_status_check_worker(self.agent_health_check)
        self._verify_service_plugins_requirements()
        self.refresh_network_db_obj = cfg.CONF.ml2plus.refresh_network_db_obj
        self.refresh_port_db_obj = cfg.CONF.ml2plus.refresh_port_db_obj
        self.refresh_subnet_db_obj = cfg.CONF.ml2plus.refresh_subnet_db_obj
        self.refresh_subnetpool_db_obj = (
            cfg.CONF.ml2plus.refresh_subnetpool_db_obj)
        self.refresh_address_scope_db_obj = (
            cfg.CONF.ml2plus.refresh_address_scope_db_obj)
        LOG.info("Modular L2 Plugin (extended) initialization complete")
Ejemplo n.º 2
0
def _notify_loop(resource, event, trigger, **kwargs):
    """The notification loop."""
    errors = []
    callbacks = kwargs.pop('callbacks', None)
    if not callbacks:
        callbacks = list(registry._get_callback_manager()._callbacks[
            resource].get(event, {}).items())
    LOG.debug("Notify callbacks %s for %s, %s", callbacks, resource, event)
    for callback_id, callback in callbacks:
        try:
            callback(resource, event, trigger, **kwargs)
        except Exception as e:
            abortable_event = (
                event.startswith(events.BEFORE) or
                event.startswith(events.PRECOMMIT)
            )
            if not abortable_event:
                LOG.exception("Error during notification for "
                              "%(callback)s %(resource)s, %(event)s",
                              {'callback': callback_id,
                               'resource': resource, 'event': event})
            else:
                LOG.error("Callback %(callback)s raised %(error)s",
                          {'callback': callback_id, 'error': e})
            errors.append(exceptions.NotificationError(callback_id, e))
    return errors
Ejemplo n.º 3
0
def send_or_queue_notification(session, transaction_key, notifier_obj,
                               notifier_method, args):
    rname = ''
    if notifier_method == NOVA_NOTIFIER_METHOD:
        # parse argument like "create_subnetpool"
        rname = args[0].split('_', 1)[1]
        event_name = 'after_' + args[0].split('_')[0]
        registry_method = getattr(notifier_obj,
                                  '_send_nova_notification')
    elif notifier_method == DHCP_NOTIFIER_METHOD:
        # parse argument like "subnetpool.create.end"
        rname = args[2].split('.')[0]
        event_name = 'after_' + args[2].split('.')[1]
        registry_method = getattr(notifier_obj,
                                  '_native_event_send_dhcp_notification')
    if rname:
        cbacks = registry._get_callback_manager()._callbacks.get(rname, None)
        if cbacks and event_name in cbacks.keys():
            for entry in cbacks.values():
                method = entry.values()[0]
                if registry_method == method:
                    # This notification is already being sent by Neutron
                    # soe we will avoid sending a duplicate notification
                    return

    if not transaction_key or 'subnet.delete.end' in args or (
        not QUEUE_OUT_OF_PROCESS_NOTIFICATIONS):
        # We make an exception for the dhcp agent notification
        # for port and subnet delete since the implementation
        # for sending that notification checks for the existence
        # of the associated network, which is not present in certain
        # cases if the delete notification is queued and sent after
        # the network delete.
        getattr(notifier_obj, notifier_method)(*args)
        return

    _queue_notification(session, transaction_key, notifier_obj,
                        notifier_method, args)
Ejemplo n.º 4
0
                event.startswith(events.BEFORE) or
                event.startswith(events.PRECOMMIT)
            )
            if not abortable_event:
                LOG.exception("Error during notification for "
                              "%(callback)s %(resource)s, %(event)s",
                              {'callback': callback_id,
                               'resource': resource, 'event': event})
            else:
                LOG.error("Callback %(callback)s raised %(error)s",
                          {'callback': callback_id, 'error': e})
            errors.append(exceptions.NotificationError(callback_id, e))
    return errors


original_notify_loop = registry._get_callback_manager()._notify_loop


from inspect import isclass
from inspect import isfunction
from inspect import ismethod


# The undecorated() and looks_like_a_decorator() functions have been
# borrowed from the undecorated python library since RPM or Debian
# packages are not readily available.
def looks_like_a_decorator(a):
    return (
        isfunction(a) or ismethod(a) or isclass(a)
    )
def test_neutron_registry_callback(mock_agent_rpc):
    """Test callback functions used for registering for RPC events in driver.

    Creates two drivers to simulate a differentiated environment
    deployment, then tests that each driver registers different functions
    to receive notification from Neutron after subscribing for events, and
    that the functions are called by the Neutron callback manager.

    Also, see related unit test,
    f5lbaasdriver/v2/bigip/test/test_bind_registry_callback.py

    :param mock_agent_rpc: Not used. Mock needed to create F5DriverV2.
    """
    plugin = mock.MagicMock()

    # start with empty Neutron RPC callback registry
    registry.clear()

    # create default driver
    default_driver = F5DriverV2(plugin)
    default_driver.plugin_rpc = mock.MagicMock()

    # create a differentiated environment driver
    dmz_driver = F5DriverV2(plugin, 'dmz')
    dmz_driver.plugin_rpc = mock.MagicMock()

    default_callback_func = default_driver._bindRegistryCallback()
    dmz_callback_func = dmz_driver._bindRegistryCallback()

    # two different callback functions created
    assert default_callback_func != dmz_callback_func

    # registry holds two callbacks
    callback_mgr = registry._get_callback_manager()
    assert len(
        callback_mgr._callbacks[resources.PROCESS][events.AFTER_CREATE]) == 2

    # both callbacks are in registry
    callbacks = callback_mgr._callbacks[resources.PROCESS][events.AFTER_CREATE]
    callback_iter = iter(callbacks)

    callback_name = next(callback_iter).split('.')[-1]
    assert callback_name == default_callback_func.__name__

    callback_name = next(callback_iter).split('.')[-1]
    assert callback_name == dmz_callback_func.__name__

    # callbacks can be called back
    with mock.patch('f5lbaasdriver.v2.bigip.driver_v2.LOG') as mock_log:
        # invoke callbacks from callback manager
        callback_mgr.notify(resources.PROCESS, events.AFTER_CREATE,
                            mock.MagicMock())

        # create_rpc_listener called
        assert default_driver.plugin_rpc.create_rpc_listener.called
        assert dmz_driver.plugin_rpc.create_rpc_listener.called

        # debug messages logged
        log_iter = iter(mock_log.debug.call_args_list)
        args, kwargs = log_iter.next()
        assert str(args[0]).startswith("F5DriverV2 with env None received")

        args, kwargs = log_iter.next()
        assert str(args[0]).startswith("F5DriverV2 with env dmz received")
def test_neutron_registry_callback(mock_agent_rpc):
    """Test callback functions used for registering for RPC events in driver.

    Creates two drivers to simulate a differentiated environment
    deployment, then tests that each driver registers different functions
    to receive notification from Neutron after subscribing for events, and
    that the functions are called by the Neutron callback manager.

    Also, see related unit test,
    f5lbaasdriver/v2/bigip/test/test_bind_registry_callback.py

    :param mock_agent_rpc: Not used. Mock needed to create F5DriverV2.
    """
    plugin = mock.MagicMock()

    # start with empty Neutron RPC callback registry
    registry.clear()

    # create default driver
    default_driver = F5DriverV2(plugin)
    default_driver.plugin_rpc = mock.MagicMock()

    # create a differentiated environment driver
    dmz_driver = F5DriverV2(plugin, 'dmz')
    dmz_driver.plugin_rpc = mock.MagicMock()

    default_callback_func = default_driver._bindRegistryCallback()
    dmz_callback_func = dmz_driver._bindRegistryCallback()

    # two different callback functions created
    assert default_callback_func != dmz_callback_func

    # registry holds two callbacks
    callback_mgr = registry._get_callback_manager()
    assert len(
        callback_mgr._callbacks[resources.PROCESS][events.AFTER_CREATE]) == 2

    # both callbacks are in registry
    callbacks = callback_mgr._callbacks[resources.PROCESS][events.AFTER_CREATE]
    callback_iter = iter(callbacks)

    callback_name = next(callback_iter).split('.')[-1]
    assert callback_name == default_callback_func.__name__

    callback_name = next(callback_iter).split('.')[-1]
    assert callback_name == dmz_callback_func.__name__

    # callbacks can be called back
    with mock.patch('f5lbaasdriver.v2.bigip.driver_v2.LOG') as mock_log:
        # invoke callbacks from callback manager
        callback_mgr.notify(
            resources.PROCESS, events.AFTER_CREATE, mock.MagicMock())

        # create_rpc_listener called
        assert default_driver.plugin_rpc.create_rpc_listener.called
        assert dmz_driver.plugin_rpc.create_rpc_listener.called

        # debug messages logged
        log_iter = iter(mock_log.debug.call_args_list)
        args, kwargs = log_iter.next()
        assert str(args[0]).startswith("F5DriverV2 with env None received")

        args, kwargs = log_iter.next()
        assert str(args[0]).startswith("F5DriverV2 with env dmz received")
Ejemplo n.º 7
0
 def _test_resource_with_errors(self, res_name, op, **kwargs):
     # Must call the internal notify_loop in order to get the errors
     return registry._get_callback_manager()._notify_loop(
         res_name, op, 'nsxadmin', **kwargs)
Ejemplo n.º 8
0
def _registry_notify(resource, event, trigger, **kwargs):
    # This invokes neutron's original (unpatched) registry notification
    # method.
    registry._get_callback_manager().notify(
        resource, event, trigger, **kwargs)
Ejemplo n.º 9
0
def _get_callbacks_for_resource_event(resource, event):
    return list(registry._get_callback_manager()._callbacks[
        resource].get(event, {}).items())