2015-12-22 00:00:00
来 源
SDNlab
网络通信
目前,在Neutron项目中现已开始从源码中移除诸如SDNPlugin这些项目的代码,使之成为独立的项目,其Release的代码托管在Github上.

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

Shell
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

Shell
123456789101112131415161718192021 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

Shell
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

Shell
123456 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等之类的数据。

Shell
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环境中的单元测试。

声明: 此文观点不代表本站立场;转载须要保留原文链接;版权疑问请联系我们。