OpenStack Neutron集成ONOS的项目,名为“networking-onos”。目前,在Neutron项目中现已开始从源码中移除诸如SDN Plugin这些项目的代码,使之成为独立的项目,其Release的代码托管在Github上。
截止目前,ONOS已经在ML2、L3层支持集成Neutron。具体详情,可参考neutron项目代码中的doc/source/stadium/sub_projects.rst文件。
networking-onos项目Github地址:https://github.com/openstack/networking-onos。
networking-onos项目Review地址:https://review.openstack.org/#/q/onos,n,z。
在这里,我将networking-onos安装在了CentOS平台上,源码目录为/usr/lib/python2.7/site-packages/networking_onos。该目录下,主要有common、plugins、tests这三个文件夹。下面我们将以此分别展开分析。
一.networking_onos/common
该目录下主要包括了config.py、utils.py这2个模块,用于定义一些公共的库。
1)common/config.py
12345678910111213141516 | from oslo_config import cfg ONOS_DRIVER_OPTS = [ cfg.StrOpt('url_path', default='', help=_('ONOS ReST interface URL')), cfg.StrOpt('username', default='', help=_('Username for authentication.')), cfg.StrOpt('password', default='', secret=True, # do not expose value in the logs help=_('Password for authentication.'))] cfg.CONF.register_opts(ONOS_DRIVER_OPTS, "onos") |
分析:
该文件中的代码,无外乎是使用openstack的config这个公共库,用于配置文件的管理和命令行的解析;cfg模块的主要作用有两个,一个是对配置文件进行解析,一个是对命令行的参数进行解析。其数据类型有:StrOpt、ListOpt、DictOpt、IntOpt、FloatOpt。
在这里,它用于解析ml2_conf.ini等文件中的内容,具体用于解析列表中的ONOS和Neutron集成的username、password、url_path这三种信息。
最后,一行代码使用oslo.cfg 模块中的cfg.CONF全局变量中的register_opts()方法注册我们需要解析的配置项。
2)common/utils.py
Shell123456789101112131415161718192021 | def send_msg(onos_path, onos_auth, msg_type, entity_path, entity=None): """Send message to the ONOS controller.""" path = '/'.join([onos_path, entity_path]) hdr = {'Content-Type': 'application/json'} body = jsonutils.dumps(entity, indent=2) if entity else None LOG.debug("Sending MSG_TYPE (%(msg)s) URL (%(path)s) " "OBJECT (%(entity)s) BODY (%(body)s)", {'msg': msg_type, 'path': path, 'entity': entity, 'body': body}) req = requests.request(method=msg_type, url=path, headers=hdr, data=body, auth=onos_auth) # Let's raise voice for an error req.raise_for_status() def safe_delete_from_dict(dict, keys): """Ignore key errors when deleting from a dictionary.""" for key in keys: dict.pop(key, None) |
分析:
该模块中,主要定义了send_msg和safe_delete_from_dict这2个函数。前者主要用于将onos_path, onos_auth, msg_type, entity_path这些信息发送给onos controller。而后者,则用于当从字典中删除key-value键值时,忽略关键错误。
二.networking_onos/plugins
这里,我们需要注意的是,networking-onos集成neutron的plugin,从架构上分为了ML2、L3这二层。如下图所示:
1)ml2/driver.py
1234567891011121314151617 | from oslo_config import cfg from oslo_log import helpers as log_helpers from oslo_log import log as logging from neutron.common import constants as n_const from neutron.extensions import portbindings from neutron.plugins.common import constants from neutron.plugins.ml2 import driver_api as api from networking_onos.common import config # noqa from networking_onos.common import utils as onos_utils LOG = logging.getLogger(__name__) class ONOSMechanismDriver(api.MechanismDriver): ………….. |
分析:
Networking-onos的ML2 driver,总共分别从oslo公共库、neutron、networking_onos这三个地方,导入了诸如config、log这些模块来处理诸如配置文件、命令行参数、日志管理这些事儿。以及使用neutron和networking_onos库中的extensions、plugins、ml2、config这些模块。
在该模块中,使用了一个继承自api.MechanismDriver父类的ONOSMechanismDriver的类,用于实现Neutron中的ML2 Driver。除此之外,使用了一个@log_helpers.log_method_call装饰器,主要而言,该模块通过扩展core plugin api来实现自己定义的方法或资源操作。
其中定义的方法,主要实现了Neutron ML2中的network、subnet、port这几类核心资源。其功能如下所示:
- Network
create_network
update_network
delete_network
- Subnet
create_subnet
update_subnet
delete_subnet
- Port
create_port
update_port
delete_port
bind_port
最后的,check_segment函数用于检查ONOS MechanismDriver中的segment是否是有效的,其定义的NETWORK_TYPE有:local、gre、vxlan、vlan。
当然,ml2目录下的README文件,也是很有必要一读的。
2)l3/driver.py
Shell123456 | class ONOSL3Plugin(db_base_plugin_v2.NeutronDbPluginV2, extraroute_db.ExtraRoute_db_mixin, l3_gwmode_db.L3_NAT_db_mixin, l3_agentschedulers_db.L3AgentSchedulerDbMixin, onos_router.ONOSRouter, onos_fip.ONOSFloatingIP): |
该模块中,定义了一个继承自许多父类的名为ONOSL3Plugin的类,用于实现L3层网络服务中的,诸如neutron db、路由器db、NAT db、l3 db等数据模型的操作。
该类的核心是实现L3层的 Router Service Plugin。用于提供router和floatingip资源,以及管理相关的request/response。
无外乎,这里实现了L3层网络服务中的如下一些资源:
- Router
create_router
update_router
delete_router
- floatingip
create_floatingip
update_floatingip
delete_floatingip
add_router_interface
remove_router_interface
该模块中,还定义了一个setup_rpc的函数,用于远程过程调用和其他的api、service进行消息通信。我们知道,Neutron中的Router,有网关臂和接口臂两种,网关臂用于设置网关和Public_network关联;而接口臂则用于添加接口,关联租户/用户创建的租户网络(Private_network),对应于模块中的add_router_interface方法。
需要注意的是,router和floating_ip这两类L3资源的代码,均在同级目录下有具体实现。
3)l3/floating_ip.py
该模块,用于实现ONOS的L3 Floating IP Service。其继承自Object基类的ONOSFloatingIP类,用于将包括msg_type、entity_path、entity 在内的Neutron的L3 Floating IP消息发送给ONOS Controller。
4)l3/router.py
该模块实现、原理同上类似,用于实现ONOS L3 Router Service。返回一个包含subnet_id、port_id、router_id、tenant_id在内的router_dict字典数据结构。
5)l3/ README
如果要了解相关的L3实现信息,该文件同样值得一读。
三.networking_onos/tests
该目录下,分别定义的是ML2、L3层的Mock单元测试模块。如下。
1)ml2/ test_driver.py
无疑,该模块中使用了python中的单元测试模块——mock。Mock用于在测试过程中,对于某些不容易构造或者不容易获取的对象,用一个虚拟的对象来创建以便于测试的测试方法。
代码测试只针对指定函数的内部代码。如果测试代码需要依赖于其他的代码片段,在某种不幸的情形下,即使被测试的函数没有变化,这部分内嵌代码的修改仍然可能破坏原有的测试。Mock 方法就是用于把测试与测试边界以外的对象隔离开。
该模块中,fake了ML2网络服务中的如下一些资源:
Network:
network_uuid、network_object
Subnet:
subnet_uuid、subnet_object
Port:
port_uuid、port_object
其中ONOSMechanismDriverTestCase类的set_test_config方法,fake了连接onos controller所必需的一些信息。同时,分别使用网络、子网、端口的delete、update、delete方法,进行单元测试。此外,还定义了验证segment(network_types)、端口绑定这些方法。
2)l3/test_driver.py
L3层的单元测试,同ML2层的单元测试模块在实现和原理上是一样的。首先会fake一些必要的数据,如tenant_id、router_uuid、router_object(即创建router的必要数据)、network_id、floating_ip、port_id等之类的数据。
12345678910111213 | class ONOSL3PluginTestCase(base.BaseTestCase, test_neutron_extensions.ExtensionTestCase, onos_driver.ONOSL3Plugin): def setUp(self): super(ONOSL3PluginTestCase, self).setUp() self._setUpExtension( 'neutron.extensions.l3.RouterPluginBase', None, l3.RESOURCE_ATTRIBUTE_MAP, l3.L3, None, allow_pagination=True, allow_sorting=True, supported_extension_aliases=['router'], use_quota=True) self.instance = self.plugin.return_value |
在继承自BaseTestCase、ExtensionTestCase和ONOSL3Plugin这三个父类的ONOSL3PluginTestCase类中,_test_send_msg方法分别使用了REST API框架中的POST、PUT、DELETE这三类资源操作。
Router、floating_ip的两类L3层资源的创建、更新、删除操作;以及Router和floating_ip相互之间的操作,譬如,路由器管理浮动网络、租户网络等。
小结
本次分析只是粗粒度的做了个讲解,不能算精细。但我们相信这是一个不错的开始,通过此番梳理,我们懂得了如下一些知识点:一是如何开发一个全新的服务Plugin及其Driver(与为一个已有的Plugin,添加Driver有所不同);二是如何去写一个neutron环境中的单元测试。
声明: 此文观点不代表本站立场;转载须要保留原文链接;版权疑问请联系我们。