Havana中VM的reboot分析
2013-10-29 22:23
435 查看
作为个人学习笔记分享,有任何问题欢迎交流!
本文主要是对比OpenStack的E版本和H版本中实例reboot的代码实现过程,从中可以看出OpenStack在各个版本迭代过程中,变得越来越稳定!同时也希望能给还在被Essex的各种bug折磨的童鞋们一点参考,做了注释的地方就是H比E处理得好的方法,主要贴H版的代码。Havana中VM的reboot
def reboot(self, context, instance, network_info, reboot_type='SOFT', block_device_info=None, bad_volumes_callback=None): """Reboot a virtual machine, given an instance reference.""" if reboot_type == 'SOFT': # NOTE(vish): This will attempt to do a graceful shutdown/restart. ###此处处理_create_domain()运行时产生的异常 #当有异常产生时,设置soft_reboot_success为False,表示soft reboot失败,用hard reboot 实例,这一点在Essex中是没有的。 try: soft_reboot_success = self._soft_reboot(instance) except libvirt.libvirtError as e: LOG.debug(_("Instance soft reboot failed: %s"), e) soft_reboot_success = False #soft reboot失败后用hard reboot if soft_reboot_success: LOG.info(_("Instance soft rebooted successfully."), instance=instance) return else: LOG.warn(_("Failed to soft reboot instance. " "Trying hard reboot."), instance=instance) return self._hard_reboot(context, instance, network_info, block_device_info)
def _soft_reboot(self, instance): """Attempt to shutdown and restart the instance gracefully. We use shutdown and create here so we can return if the guest responded and actually rebooted. Note that this method only succeeds if the guest responds to acpi. Therefore we return success or failure so we can fall back to a hard reboot if necessary. :returns: True if the reboot succeeded """ dom = self._lookup_by_name(instance["name"]) (state, _max_mem, _mem, _cpus, _t) = dom.info() state = LIBVIRT_POWER_STATE[state] old_domid = dom.ID() # NOTE(vish): This check allows us to reboot an instance that # is already shutdown. if state == power_state.RUNNING: dom.shutdown()#shutdown正常关闭虚拟机 # NOTE(vish): This actually could take slighty longer than the # FLAG defines depending on how long the get_info # call takes to return. self._prepare_pci_devices_for_use( pci_manager.get_instance_pci_devs(instance)) for x in xrange(CONF.libvirt_wait_soft_reboot_seconds): dom = self._lookup_by_name(instance["name"]) (state, _max_mem, _mem, _cpus, _t) = dom.info() state = LIBVIRT_POWER_STATE[state] new_domid = dom.ID() # NOTE(ivoks): By checking domain IDs, we make sure we are # not recreating domain that's already running. if old_domid != new_domid: if state in [power_state.SHUTDOWN, power_state.CRASHED]: LOG.info(_("Instance shutdown successfully."), instance=instance) self._create_domain(domain=dom)#根据原实例的domain重新define一个实例 timer = loopingcall.FixedIntervalLoopingCall( self._wait_for_running, instance) timer.start(interval=0.5).wait() return True else: LOG.info(_("Instance may have been rebooted during soft " "reboot, so return now."), instance=instance) return True greenthread.sleep(1) return False
def _hard_reboot(self, context, instance, network_info, block_device_info=None): """Reboot a virtual machine, given an instance reference. Performs a Libvirt reset (if supported) on the domain. If Libvirt reset is unavailable this method actually destroys and re-creates the domain to ensure the reboot happens, as the guest OS cannot ignore this action. If xml is set, it uses the passed in xml in place of the xml from the existing domain. """ self._destroy(instance)#libvirt删除原实例 disk_info = blockinfo.get_disk_info(CONF.libvirt_type, instance, block_device_info) # NOTE(vish): This could generate the wrong device_format if we are # using the raw backend and the images don't exist yet. # The create_images_and_backing below doesn't properly # regenerate raw backend images, however, so when it # does we need to (re)generate the xml after the images # are in place. #根据数据库的信息,使用to_xml()拼装出一个虚拟机的XML描述文件,避免异常导致原虚拟机的xml文件缺失部分信息。 xml = self.to_xml(context, instance, network_info, disk_info, block_device_info=block_device_info, write_to_disk=True) # NOTE (rmk): Re-populate any missing backing files. disk_info_json = self.get_instance_disk_info(instance['name'], xml, block_device_info) instance_dir = libvirt_utils.get_instance_path(instance) self._create_images_and_backing(context, instance, instance_dir, disk_info_json) # Initialize all the necessary networking, block devices and # start the instance. self._create_domain_and_network(xml, instance, network_info, block_device_info, context=context, reboot=True)##创建新的虚拟机 self._prepare_pci_devices_for_use( pci_manager.get_instance_pci_devs(instance)) def _wait_for_reboot(): """Called at an interval until the VM is running again.""" state = self.get_info(instance)['state'] if state == power_state.RUNNING: LOG.info(_("Instance rebooted successfully."), instance=instance) raise loopingcall.LoopingCallDone() timer = loopingcall.FixedIntervalLoopingCall(_wait_for_reboot) timer.start(interval=0.5).wait()
def _create_domain_and_network(self, xml, instance, network_info, block_device_info=None, power_on=True): ###hard reboot创建虚拟机的函数,实际上也是调用的soft reboot 的创建函数_create_domain() """Do required network setup and create domain.""" block_device_mapping = driver.block_device_info_get_mapping( block_device_info) #创建虚拟机之前连接卷,避免找不到卷的异常 for vol in block_device_mapping: connection_info = vol['connection_info'] disk_dev = vol['mount_device'].rpartition("/")[2] disk_info = { 'dev': disk_dev, 'bus': blockinfo.get_disk_bus_for_disk_dev(CONF.libvirt_type, disk_dev), 'type': 'disk', } self.volume_driver_method('connect_volume', connection_info, disk_info) self.plug_vifs(instance, network_info) self.firewall_driver.setup_basic_filtering(instance, network_info) self.firewall_driver.prepare_instance_filter(instance, network_info) domain = self._create_domain(xml, instance=instance, power_on=power_on) self.firewall_driver.apply_instance_filter(instance, network_info) return domain
#soft reboot使用的函数 def _create_domain(self, xml=None, domain=None, instance=None, launch_flags=0, power_on=True): """Create a domain. Either domain or xml must be passed in. If both are passed, then the domain definition is overwritten from the xml. """ inst_path = None if instance: inst_path = libvirt_utils.get_instance_path(instance) if CONF.libvirt_type == 'lxc': if not inst_path: inst_path = None container_dir = os.path.join(inst_path, 'rootfs') fileutils.ensure_tree(container_dir) image = self.image_backend.image(instance, 'disk') disk.setup_container(image.path, container_dir=container_dir, use_cow=CONF.use_cow_images) #### 创建虚拟机的时候进行了异常处理,define虚拟机时是会产生异常,例如已挂载的卷找不到了等,向上抛出异常,程序会继续执行,而不会在这里就停止执行,导致soft reboot不成功,也不会执行hard reboot,这样就避免了僵尸实例的产生。 if xml: try: domain = self._conn.defineXML(xml)##libvirt创建一个虚拟机 except Exception as e: LOG.error(_("An error occurred while trying to define a domain" " with xml: %s") % xml) raise e if power_on: try: domain.createWithFlags(launch_flags) except Exception as e: with excutils.save_and_reraise_exception(): LOG.error(_("An error occurred while trying to launch a " "defined domain with xml: %s") % domain.XMLDesc(0)) try: self._enable_hairpin(domain.XMLDesc(0)) except Exception: with excutils.save_and_reraise_exception(): LOG.error(_("An error occurred while enabling hairpin mode on " "domain with xml: %s") % domain.XMLDesc(0)) # NOTE(uni): Now the container is running with its own private mount # namespace and so there is no need to keep the container rootfs # mounted in the host namespace if CONF.libvirt_type == 'lxc': state = self.get_info(instance)['state'] container_dir = os.path.join(inst_path, 'rootfs') if state == power_state.RUNNING: disk.clean_lxc_namespace(container_dir=container_dir) else: disk.teardown_container(container_dir=container_dir) return domain
相关文章推荐
- iOS开发-UIWebView
- android中得到所有安装的应用程序及区分其是否为系统应用程序还是用户应用程序
- 在A*寻路中使用二叉堆
- hdu 4284 Travel(壮压DP&TSP&floyd)
- 分享一组Rpg Marker人物行走,游戏素材图片,共20张图片
- 《UNIX-Shell编程24学时教程》读书笔记Chap1,2 Shell基础,脚本基础
- [置顶] 二叉树层次遍历的应用--判断一颗二叉树是否为规则二叉树
- BS中保存参数
- AutoCAD按坐标打印图纸
- 向防火墙中添加程序或端口
- 64位系统安装SQL2000SP4详细教程[已测试WIN72008R2]
- 25种用户十秒离开你网站的原因
- 疯狂C++巡讲(上)
- eclipse groovy 插件
- DOM对象和JQuery对象的区别
- pjsip视频通信开发(上层应用)之EditText重写
- 多个非同源的shared_ptr管理对象引起double free
- 将要做到事情
- [LeetCode] Rotate Image
- Struts2——(8)struts2中文件的上传