用于core and service components之间的通信,传递resource的lifecycle events (e.g. before creation, before deletion, etc.)消息

,比如当一个Neutron resource与多个service (VPN, Firewall and Load Balancer) 关联,

需要Service的管理者来确定resource正确状态。

这样可以避免各个Service需要感知其他Service,在它们之间解耦和。

它是一种进程内通信机制,如果是进程间则需要Messaging callbacks

如果是远程进程则需要 RPC API 。

比如service A, B, and C 都需要知道router creation,如果没有一个中介来采用消息的方式关联它们,

那么,A在router creation的时候就需要直接call B/C。

如果有了中介I,则流程如下:

# B and C ask I to be notified when A is done creating the resource

# ...

# A is done creating the resource

# A gets hold of the reference to the intermediary I

# A calls I

I->notify()

只要B/C订阅了router creation消息,A and ‘I’ 不需要知道B/C的状态和变化。

同时callback也可以抛出异常告诉A该操作是否可行,这就需要A先发一个events.BEFORE_CREATE来测试一下问问B/C的意见了。

实例代码如下:

from neutron.callbacks import events
from neutron.callbacks import exceptions
from neutron.callbacks import resources
from neutron.callbacks import registry def callback1(resource, event, trigger, **kwargs):
raise Exception('I am failing!')
def callback2(resource, event, trigger, **kwargs):
print('Callback2 called by %s on event %s' % (trigger, event)) registry.subscribe(callback1, resources.ROUTER, events.BEFORE_CREATE)
registry.subscribe(callback2, resources.ROUTER, events.BEFORE_CREATE)
registry.subscribe(callback2, resources.ROUTER, events.ABORT_CREATE)
print('Subscribed') def do_notify():
kwargs = {'foo': 'bar'}
registry.notify(resources.ROUTER, events.BEFORE_CREATE, do_notify, **kwargs) print('Notifying...')
try:
do_notify()
except exceptions.CallbackFailure as e:
print('Error: ', e)

Unsubscribing to events

  • clear(): it unsubscribes all subscribed callbacks: this can be useful especially when winding down the system, and notifications shall no longer be triggered.
  • unsubscribe(): it selectively unsubscribes a callback for a specific resource’s event. Say callback C has subscribed to event A for resource R, any notification of event A for resource R will no longer be handed over to C, after the unsubscribe() invocation.
  • unsubscribe_by_resource(): say that callback C has subscribed to event A, B, and C for resource R, any notification of events related to resource R will no longer be handed over to C, after the unsubscribe_by_resource() invocation.
  • unsubscribe_all(): say that callback C has subscribed to events A, B for resource R1, and events C, D for resource R2, any notification of events pertaining resources R1 and R2 will no longer be handed over to C, after the unsubscribe_all() invocation.

git grep subscribe:

neutron/db/db_base_plugin_v2.py:            registry.subscribe(self.validate_network_rbac_policy_change,
neutron/db/external_net_db.py: registry.subscribe(self._process_ext_policy_create,
neutron/db/external_net_db.py: registry.subscribe(self._validate_ext_not_in_use_by_tenant,
neutron/db/l3_db.py:def subscribe():
neutron/db/l3_db.py: registry.subscribe(
neutron/db/l3_db.py: registry.subscribe(
neutron/db/l3_db.py: registry.subscribe(
neutron/db/l3_db.py: registry.subscribe(
neutron/db/l3_db.py:subscribe()
neutron/db/l3_dvrscheduler_db.py:def subscribe():
neutron/db/l3_dvrscheduler_db.py: registry.subscribe(
neutron/db/l3_dvrscheduler_db.py: registry.subscribe(
neutron/db/l3_dvrscheduler_db.py: registry.subscribe(
neutron/objects/rbac_db.py: def subscribe_to_rbac_events(class_instance):
neutron/objects/rbac_db.py: registry.subscribe(class_instance.validate_rbac_policy_change,
neutron/objects/rbac_db.py: mcs.subscribe_to_rbac_events(cls)
neutron/plugins/ml2/extensions/dns_integration.py:def subscribe():
neutron/plugins/ml2/extensions/dns_integration.py: registry.subscribe(
neutron/plugins/ml2/extensions/dns_integration.py: registry.subscribe(
neutron/plugins/ml2/extensions/dns_integration.py: registry.subscribe(
neutron/plugins/ml2/extensions/dns_integration.py:subscribe()
neutron/services/auto_allocate/db.py: registry.subscribe(_ensure_external_network_default_value_callback,
neutron/services/auto_allocate/db.py: registry.subscribe(_ensure_external_network_default_value_callback,
neutron/services/auto_allocate/db.py: registry.subscribe(_ensure_external_network_default_value_callback,
neutron/services/bgp/bgp_plugin.py: registry.subscribe(self.floatingip_update_callback,
neutron/services/bgp/bgp_plugin.py: registry.subscribe(self.router_interface_callback,
neutron/services/bgp/bgp_plugin.py: registry.subscribe(self.router_interface_callback,
neutron/services/bgp/bgp_plugin.py: registry.subscribe(self.router_interface_callback,
neutron/services/bgp/bgp_plugin.py: registry.subscribe(self.router_gateway_callback,
neutron/services/bgp/bgp_plugin.py: registry.subscribe(self.router_gateway_callback,
neutron/services/l3_router/l3_router_plugin.py: l3_dvrscheduler_db.subscribe()
neutron/services/l3_router/l3_router_plugin.py: l3_db.subscribe()

比如neutron/db/l3_dvrscheduler_db.py: registry.subscribe(

在port delete之前要问问l3是否可以:

        _prevent_l3_port_delete_callback, resources.PORT, events.BEFORE_DELETE)

l3的判断可以得条件是:

core plugin中没有它的记录

port的owner不属于router

没有fixed ip

owner router已经不存在

    def prevent_l3_port_deletion(self, context, port_id):
"""Checks to make sure a port is allowed to be deleted. Raises an exception if this is not the case. This should be called by
any plugin when the API requests the deletion of a port, since some
ports for L3 are not intended to be deleted directly via a DELETE
to /ports, but rather via other API calls that perform the proper
deletion checks.
"""
try:
port = self._core_plugin.get_port(context, port_id)
except n_exc.PortNotFound:
# non-existent ports don't need to be protected from deletion
return
if port['device_owner'] not in self.router_device_owners:
return
# Raise port in use only if the port has IP addresses
# Otherwise it's a stale port that can be removed
fixed_ips = port['fixed_ips']
if not fixed_ips:
LOG.debug("Port %(port_id)s has owner %(port_owner)s, but "
"no IP address, so it can be deleted",
{'port_id': port['id'],
'port_owner': port['device_owner']})
return
# NOTE(kevinbenton): we also check to make sure that the
# router still exists. It's possible for HA router interfaces
# to remain after the router is deleted if they encounter an
# error during deletion.
# Elevated context in case router is owned by another tenant
if port['device_owner'] == DEVICE_OWNER_FLOATINGIP:
if not self._floating_ip_exists(context, port['device_id']):
LOG.debug("Floating IP %(f_id)s corresponding to port "
"%(port_id)s no longer exists, allowing deletion.",
{'f_id': port['device_id'], 'port_id': port['id']})
return
elif not self._router_exists(context, port['device_id']):
LOG.debug("Router %(router_id)s corresponding to port "
"%(port_id)s no longer exists, allowing deletion.",
{'router_id': port['device_id'],
'port_id': port['id']})
return reason = _('has device owner %s') % port['device_owner']
raise n_exc.ServicePortInUse(port_id=port['id'],
reason=reason)

同时,在port delete之后,router需要发出 routers_updated notification:

    registry.subscribe(
_notify_routers_callback, resources.PORT, events.AFTER_DELETE)
    def routers_updated(self, context, router_ids, operation=None, data=None,
shuffle_agents=False, schedule_routers=True):
if router_ids:
self._notification(context, 'routers_updated', router_ids,
operation, shuffle_agents, schedule_routers)

http://docs.openstack.org/developer/neutron/devref/callbacks.html

Neutron Callback System的更多相关文章

  1. Neutron Messaging Callback System

    callback system 用在进程内部通信,Messaging Callback System是给进程间通信.为了agent不通过RPC就能得到resource的变化. 目前用在: QoS po ...

  2. 我非要捅穿这 Neutron(三)架构分析与代码实现篇(基于 OpenStack Rocky)

    目录 文章目录 目录 Neutron 的软件架构分析与实现 Neutron Server 启动流程 获取 WSGI Application Core API & Extension API C ...

  3. neutron 的 quota design

    发现, cinder, nova 制实现了, CountableResource. 只有nuetron实现了 TrackedResource 和 CountableResource. I read u ...

  4. Cplex: MIP Callback Interface

    *本文主要记录和分享学习到的知识,算不上原创 *参考文献见链接 这篇文章主要记录一些Cplex的Callback的使用方法,采用Java语言. https://www.ibm.com/support/ ...

  5. Callback<> and Bind()

    Callback<> and Bind() Introduction The templated base::Callback<> class is a generalized ...

  6. System.Net.WebRequest.cs

    ylbtech-System.Net.WebRequest.cs 发出对统一资源标识符(URI)的请求.这是一个 abstract 类. 1.返回顶部 1. #region 程序集 System, V ...

  7. System.Web.Compilation.BuildManager.CopyPrecompiledFile 並未將物件參考設定為物件的執行個體

    使用MSBUild 的 aspnet_compiler.exe 发布网站, 过程中出现错误 [NullReferenceException]: 並未將物件參考設定為物件的執行個體  System.W ...

  8. 高性能的关键:Spring MVC的异步模式

    我承认有些标题党了,不过话说这样其实也没错,关于“异步”处理的文章已经不少,代码例子也能找到很多,但我还是打算发表这篇我写了好长一段时间,却一直没发表的文章,以一个更简单的视角,把异步模式讲清楚. 什 ...

  9. Java回调方法详解

    回调在维基百科中定义为: 在计算机程序设计中,回调函数,是指通过函数参数传递到其他代码的,某一块可执行代码的引用. 其目的是允许底层代码调用在高层定义的子程序. 举个例子可能更明白一些:以Androi ...

随机推荐

  1. Redis源码阅读-sds字符串源码阅读

    redis使用sds代替char *字符串, 其定义如下: typedef char *sds; struct sdshdr { unsigned int len; unsigned int free ...

  2. 如何在struts2中实现下载?

    <a href="${pageContext.request.contextPath}/download?filename="+filename>点击下载</a& ...

  3. Warning: (3719, “‘utf8’ is currently an alias for the character set UTF8MB3, which will be replaced by UTF8MB4 in a future release. Please consider using UTF8MB4 in order to be unambiguous.”)

    [1]本地版本 Mysql 8.0.12 创建表SQL: DROP TABLE IF EXISTS students; CREATE TABLE `students` ( `sId` ) UNSIGN ...

  4. 多媒体开发之--- rtsp 中的H264 编码+打包+解码相关知识es、pes、ts...

    1)ES流(Elementary Stream): 也叫基本码流,包含视频.音频或数据的连续码流. 2)PES流(Packet Elementary Stream): 也叫打包的基本码流, 是将基本的 ...

  5. android 各版本的区别

    三.Android 6.x 新增运行时权限概念 Android6.0或以上版本,用户可以完全控制应用权限.当用户安装一个app时,系统默认给app授权部分基础权限,其他敏感权限,需要开发者自己注意,当 ...

  6. c#基础系列:序列化效率比拼——谁是最后的赢家Newtonsoft.Json

    前言:作为开发人员,对象的序列化恐怕难以避免.楼主也是很早以前就接触过序列化,可是理解都不太深刻,对于用哪种方式去做序列化更是随波逐流——项目中原来用的什么方式照着用就好了.可是这么多年自己对于这东西 ...

  7. ios错误ignoring file xxx missing required architecture x86_64 in file

    错误ignoring file xxx missing required architecture x86_64 in file 解决方法: 1.在Project target里“Architectu ...

  8. 二、Android应用的界面编程(一)界面编程与视图(View)组件

    Android应用的绝大部分UI组件都放在android.widget包及其子包.android.view包及其子包中,Android应用的所有UI组件都继承了View类.它代表一个空白的矩形区域.V ...

  9. 使用Zxing.net实现asp.net mvc二维码功能

    新建一个html辅助类 public static class HtmlHelperExtensions { , , ) { var barcodeWriter = new BarcodeWriter ...

  10. Dire Wolf(区间DP)

    Dire Wolf Time Limit: 5000/5000 MS (Java/Others)    Memory Limit: 512000/512000 K (Java/Others)Total ...