Nova Network-vif-plugged 事件分析 1
在创建虚机过程中,nova-compute会调用wait_for_instance_event函数(nova/compute/manage.py)进行network-vif-plugged的事件等待,本文试图介绍这一事件的发生过程,以及超时后的影响。在第一节中主要通过两个简单的实验说明network-vif-plugged事件的作用以及从事件发起到事件处理的流程。
在nova-compute配置文件中有两个与该事件相关的参数- vif_plugging_timeout、vif_plugging_if_fatal,前者是等待事件的最大时间,后者是处理超时异常的方式。若在规定时间内,nova-compute接受到了事件响应,那么虚机可正常创建,那么当超时现象发生时,nova-compute会根据vif_plugging_is_fatal的配置采取两种处理方式。
若超时发生,并且vif_plugging_is_fatal为True,nova首先执行guest.poweroff,停止qemu进程;然后执行cleanup函数,先清除网络资源,使用函数_unplug_vifs,删除plug_vifs函数创建的ovs port,ovs agent检测到了删除端口的事件然后通知neutron-server删除neutron db中的port信息,最后抛VirtualInterfaceCreateException。
如果vif_plugging_is_fatal为False,即便发生eventlet.timeout.Timeout异常,创建过程会继续,这说明network-vif-plugged不会影响虚机的创建,那么该事件的作用是什么?在nova-compute代码中,network-vif-plugged事件并不是通过neutron-client通知的neutron-server,那么neutron-server是如何受到事件请求,并处理事件的呢?
在neutron-server的NeutronDbPluginV2类(neutron/db/db_base_plugin_v2.py)初始化函数中,针对port定义了三类事件及其触发的操作:
event.listen(models_v2.Port,'after_insert', self.nova_notifier.send_port_status)
event.listen(models_v2.Port,'after_update', self.nova_notifier.send_port_status)
event.listen(models_v2.Port.status, 'set', self.nova_notifier.record_port_status_changed)
record_port_status_changed函数用来定义port的_notify_event属性,该属性记录了事件的完成状态。其中的对”set”操作监听,说明在端口的状态被改变时会触发network-vif-plugged事件并调用相应的函数通知nova-compute。那么nova-compute对network-vif-plugged事件的等待是怎么传递到Neutron-server的,我们通过实验就行验证。
实验1 将vif_plugging_is_fatal设置为False,关闭计算节点的neutron-openvswitch-agent服务,启动虚机,虚机可正常启动,但是虚机对应端口状态为Down。
虚拟也拿不到IP地址。
启动ovs-agent后port状态立即变为Active,虚机可以拿到IP。
实验证明,ovs-agent关闭时,无法捕获到nova添加ovs端口的操作,neutron不会更新虚机的端口状态,因此会造成network-vif-plugged事件超时的现象。也就是说network-vif-plugged事件要想触发,必须要由ovs-agent通知neutron-server。
在正常情况下这一流程又是如何发生的呢,我们通过下面的实验进行观察。
实验2 正常情况下,创建虚机时network-vif-plugged的发生和处理。
(1)计算节点的Nova-compute等待执行ovs-vsctl等命令,然后等待network-vif-plugged事件的反馈。
2016-08-16 12:26:41.650 1231 DEBUGoslo_concurrency.processutils [req-8f7c1a9d-7647-4207-824b-ef281a47d14850a809139b434c2287b4f82474242533 630b741632ba47b596e21eaf50f2b568 - - -]Running cmd (subprocess): sudo nova-rootwrap /etc/nova/rootwrap.conf ovs-vsctl--timeout=120 -- --if-exists del-port qvo059c0374-b8 -- add-port br-intqvo059c0374-b8 -- set Interface qvo059c0374-b8external-ids:iface-id=059c0374-b801-4ab3-b652-4b33e405eb15external-ids:iface-status=active external-ids:attached-mac=fa:16:3e:3f:68:6eexternal-ids:vm-uuid=bc7d4a87-4df4-413b-9364-39e7780f64a1 execute/usr/lib/python2.7/site-packages/oslo_concurrency/processutils.py:344
(2)计算节点的ovs-agent检测到有新端口添加。
12:26:41.776 23624 DEBUGneutron.agent.linux.async_process [-] Output received from [ovsdb-clientmonitor Interface name,ofport,external_ids --format=json]:{"data":[["cf5ad2e5-5adc-463a-845d-dcb156ce1bdc","insert","qvo059c0374-b8",["set",[]],["map",[["attached-mac","fa:16:3e:3f:68:6e"],["iface-id","059c0374-b801-4ab3-b652-4b33e405eb15"],["iface-status","active"],["vm-uuid","bc7d4a87-4df4-413b-9364-39e7780f64a1"]]]]],"headings":["row","action","name","ofport","external_ids"]}_read_stdout/usr/lib/python2.7/site-packages/neutron/agent/linux/async_process.py:236
然后通知Neutron-server。
2016-08-16 12:26:42.161 23624 DEBUGoslo_messaging._drivers.amqpdriver [req-e02bb72d-a5f4-4970-8e3e-961b189a72db -- - - -] CALL msg_id: 4f9c9facb1fa4969889783a986e2c561 exchange 'neutron' topic'q-plugin' _send /usr/lib/python2.7/site-packages/oslo_messaging/_drivers/amqpdriver.py:454
(3)Neutron-server收到信息。
2016-08-16 12:26:42.164 25184 DEBUGoslo_messaging._drivers.amqpdriver [-] received message msg_id:4f9c9facb1fa4969889783a986e2c561 reply toreply_42e9b47bc89d494bac7cd08e1590b22b __call__/usr/lib/python2.7/site-packages/oslo_messaging/_drivers/amqpdriver.py:201
2016-08-16 12:26:42.165 25184 DEBUG neutron.plugins.ml2.rpc[req-e02bb72d-a5f4-4970-8e3e-961b189a72db - - - - -] Device059c0374-b801-4ab3-b652-4b33e405eb15 details requested by agentovs-agent-gansu.saltmaster with host gansu.saltmaster get_device_details/usr/lib/python2.7/site-packages/neutron/plugins/ml2/rpc.py:70
2016-08-16 12:26:42.226 25184 DEBUG neutron.plugins.ml2.db[req-e02bb72d-a5f4-4970-8e3e-961b189a72db - - - - -] For port059c0374-b801-4ab3-b652-4b33e405eb15, host gansu.saltmaster, got binding levels[<neutron.plugins.ml2.models.PortBindingLevel[object at 5ebd1d0]{port_id=u'059c0374-b801-4ab3-b652-4b33e405eb15', host=u'gansu.saltmaster',level=0, driver=u'openvswitch',segment_id=u'7c1db2be-4425-4f92-9913-d0169e4afc7b'}>] get_binding_levels/usr/lib/python2.7/site-packages/neutron/plugins/ml2/db.py:184
2016-08-16 12:26:42.249 25184 DEBUG neutron.notifiers.nova[req-e02bb72d-a5f4-4970-8e3e-961b189a72db - - - - -] Ignoring state changeprevious_port_status: DOWN current_port_status: BUILD port_id059c0374-b801-4ab3-b652-4b33e405eb15 record_port_status_changed/usr/lib/python2.7/site-packages/neutron/notifiers/nova.py:194
(4)Neutron-server将端口的状态由Down转变为Actice并向nova回复事件。
2016-08-16 12:26:44.634 25188 DEBUG neutron.notifiers.nova[-] Sending events: [{'status': 'completed', 'tag':u'059c0374-b801-4ab3-b652-4b33e405eb15', 'name': 'network-vif-plugged','server_uuid': u'bc7d4a87-4df4-413b-9364-39e7780f64a1'}] send_events/usr/lib/python2.7/site-packages/neutron/notifiers/nova.py:209
(5)在nova-api日志中可查看到
2016-08-16 12:26:44.822 31556 DEBUG nova.api.openstack.wsgi[req-efb87df1-0901-435f-8ba4-d7461794ef56 1333f6ff00fa428c984b3ba0a99f08440de50e7e0c7c4f148300936580762205 - - -] Action: 'create', calling method:<bound method ServerExternalEventsController.create of<nova.api.openstack.compute.server_external_events.ServerExternalEventsControllerobject at 0x7afd0d0>>, body: {"events": [{"status":"completed", "tag":"059c0374-b801-4ab3-b652-4b33e405eb15", "name":"network-vif-plugged", "server_uuid":"bc7d4a87-4df4-413b-9364-39e7780f64a1"}]} _process_stack/usr/lib/python2.7/site-packages/nova/api/openstack/wsgi.py:696
注:neutron-server在notify的时候调用了nova-client server_external_events的create功能,向nova-api发送了一个create请求。(大致如此,细节忘了J)
2016-08-16 12:26:44.879 31556 INFOnova.api.openstack.compute.server_external_events [req-efb87df1-0901-435f-8ba4-d7461794ef561333f6ff00fa428c984b3ba0a99f0844 0de50e7e0c7c4f148300936580762205 - - -]Creating event network-vif-plugged:059c0374-b801-4ab3-b652-4b33e405eb15 forinstance bc7d4a87-4df4-413b-9364-39e7780f64a1
(6)nova-compute收到事件的回复
2016-08-16 12:26:45.050 1231 DEBUG nova.compute.manager[req-efb87df1-0901-435f-8ba4-d7461794ef56 1333f6ff00fa428c984b3ba0a99f08440de50e7e0c7c4f148300936580762205 - - -] [instance:bc7d4a87-4df4-413b-9364-39e7780f64a1] Received eventnetwork-vif-plugged-059c0374-b801-4ab3-b652-4b33e405eb15external_instance_event/usr/lib/python2.7/site-packages/nova/compute/manager.py:6707
(7)neutron-server得到nova-api的回复
12:26:45.056 25188 INFO neutron.notifiers.nova [-] Nova eventresponse: {u'status': u'completed', u'tag': u'059c0374-b801-4ab3-b652-4b33e405eb15',u'name': u'network-vif-plugged', u'server_uuid':u'bc7d4a87-4df4-413b-9364-39e7780f64a1', u'code': 200}
总结:
本文通过实验说明network-vif-plugged事件的意义,以及正常的处理流程,希望为调查network-vif-plugged事件超时进而影响虚机创建提供参考。
下一步工作:
Nova-api收到事件后是如何通知nova-compute,目前还没研究清楚,个人猜测是通过rabbitmq,还有待验证。
推荐阅读
-
纯干货分享 | 研发效能提升——敏捷需求篇-而敏捷需求是提升效能的方式中不可或缺的模块之一。 云智慧的敏捷教练——Iris Xu近期在公司做了一场分享,主题为「敏捷需求挖掘和组织方法,交付更高业务价值的产品」。Iris具有丰富的团队敏捷转型实施经验,完成了企业多个团队从传统模式到敏捷转型的落地和实施,积淀了很多的经验。 这次分享主要包含以下2个部分: 第一部分是用户影响地图 第二部分是事件驱动的业务分析Event driven business analysis(以下简称EDBA) 用户影响地图,是一种从业务目标到产品需求映射的需求挖掘和组织的方法。 在软件开发过程中可能会遇到一些问题,比如大家使用不同的业务语言、技术语言,造成角色间的沟通阻碍,还会导致一些问题,比如需求误解、需求传递错误等;这会直接导致产品的功能需求和要实现的业务目标不是映射关系。 但在交付期间,研发人员必须要将这些需求实现交付,他们实则并不清楚这些功能需求产生的原因是什么、要解决客户的哪些痛点。研发人员往往只是拿到了解决方案,需要把它实现,但没有和业务侧一起去思考解决方案是否正确,能否真正的帮助客户解决问题。而用户影响地图通常是能够连接业务目标和产品功能的一种手段。 我们在每次迭代里加入的假设,也就是功能需求。首先把它先实现,再逐步去验证我们每一个小目标是否已经实现,再看下一个目标要是什么。那影响地图就是在这个过程中帮我们不断地去梳理目标和功能之间的关系。 我们在软件开发中可能存在的一些问题 针对这些问题,我们如何避免?先简单介绍做敏捷转型的常规思路: 先做团队级的敏捷,首先把产品、开发、测试人员,还有一些更后端的人员比如交互运维的同学放在一起,组成一个特训团队做交付。这个团队要包含交付过程中所涉及的所有角色。 接着业务敏捷要打通整个业务环节和研发侧的一个交付。上图中可以看到在敏捷中需求是分层管理的,第一层是业务需求,在这个层级是以用户目标和业务目标作为输入进行规划,同时需要去考虑客户的诉求。业务人员通过获取到的业务需求,进一步的和团队一起将其分解为产品需求。所以业务需求其实是我们真正去发布和运营的单元,它可以被独立发布到我们的生产环境上。我们的产品需求其实就是产品的具体功能,它是我们集成和测试的对象,也就是我们最终去部署到系统上的一个基本单元。产品需求再到了我们的开发团队,映射到迭代计划会上要把它分解为相应的技术任务,包括我们平时所说的比如一些前端的开发、后端的开发、测试都是相应的技术任务。所以业务敏捷要达到的目标是需要去持续顺畅高质量的交付业务价值。 将这几个点串起来,形成金字塔结构。最上层我们会把业务目标放在整个金字塔的塔尖。这个业务目标是通过用户的目标以及北极星指标确立的。确认业务目标后再去梳理相应的业务流程,最后生产。另外产品需求包含了操作流程和业务规则,具需求交付时间、工程时间以及我们的一些质量标准的要求。 谈到用户影响的地图,在敏捷江湖上其实有一个传说,大家都有一个说法叫做敏捷需求的“任督二脉”。用户影响地图其实就是任脉,在黑客马拉松上用过的用户故事地图其实叫督脉。所以说用户影响地图是在用户故事地图之前,先帮我们去梳理出我们要做哪些东西。当我们真正识别出我们要实现的业务活动之后,用户故事地图才去梳理我们整个的业务工作流,以及每个工作流节点下所要包含的具体功能和用户故事。所以说用户影响地图需要解决的问题,我们包括以下这些: 首先是范围蔓延,我们在整张地图上,功能和对应的业务目标是要去有一个映射的。这就避免了一些在我们比如有很多干系人参与的会议上,那大家都有不同想法些立场,会提出很多需求(正确以及错误的需求)。这个时候我们会依据目标去看这些需求是否真的是会影响我们的目标。 这里提到的错误需求,比如是利益相关的人提出的、客户认为产品应该有的、某个产品经理需求分析师认为可以有的....但是这些功能在用户影响地图中匹配不到对应目标的话,就需要降低优先级或弃掉。另外,通常我们去制定解决方案的时候,会考虑较完美的实现,导致解决方案括很多的功能。这个时候关键目标至关重要,会帮助我们梳理筛选、确定优先级。 看一下用户影响到地图概貌 总共分为一个三层的结构: 第一层why,你的业务目标哪个是最重要的,为什么?涉及到的角色有哪些? 第二层how ,怎样产生影响?影响用户角色什么样的行为? (不需要去列出所有的影响,基于业务目标) 第三层what,最关键的是在梳理需求时不需一次把所有细节想全,这通常团队中经常遇到的问题。 我们用这个例子来看一下 这是一个客服中心的影响地图,业务目标是 3个月内不增加客服人数的前提下能支持1.5倍的用户数。此业务目标设定是符合 smart 原则的,specific非常的具体,miserable 是可以衡量的,action reoriented是面向活动的, real list 也是很实际的。 量化的目标会指引我们接下来的行动,梳理一个业务目标,尽量去量化,比如 :我们通过打造一条什么样的流水线,能够提高整个部署的效率,时间是原来的 1/2 。这样才是一个能量化的有意义的目标。 回到这幅图, how 层级识别出来的内容,客服角色:想要对它施加的影响,把客户引导到论坛上,帮助客户更容易的跟踪问题,更快速的去定位问题。初级用户:方论坛上找到问题。高级用户:在论坛上回答问题。通过我们这些用户角色,进行活动,完成在不增加客户客服人数的前提下支持更多的用户数量。 最后一个层级,才是我们日常接触比较多的真正的功能的特性和需求,比如引导到客户到论坛上,其实这个产品就需要有一个常见问题的论坛的链接。这个层次需要我们团队进一步地在交付,在每个迭代之前做进一步的梳理,细化成相应的用户故事。 这个是云智慧团队中,自己做的影响地图的范例,可以看下整个的层级结构。序号表示优先级。 那我们用户影响地图可以总结为:
-
Nova Network-vif-plugged 事件分析 1
-
编号 1:某地区宽带用户路由器 DNS 篡改事件分析(DNS 重绑定攻击)