分享

Havana中VM的reboot分析

xioaxu790 发表于 2014-8-20 18:23:18 [显示全部楼层] 回帖奖励 阅读模式 关闭右栏 0 11385
问题导读
1、OpenStack的H版比早前版本,稳定在哪些地方?
2、如何根据原实例的domain重新define一个实例
3、创建虚拟机的时候出现了异常,怎么处理?





本文主要是对比OpenStack的E版本和H版本中实例reboot的代码实现过程,从中可以看出OpenStack在各个版本迭代过程中,变得越来越稳定!同时也希望能给还在被Essex的各种bug折磨的童鞋们一点参考,做了注释的地方就是H比E处理得好的方法,主要贴H版的代码。

Havana中VM的reboot
  1. def reboot(self, context, instance, network_info, reboot_type='SOFT',  
  2.               block_device_info=None, bad_volumes_callback=None):  
  3.        """Reboot a virtual machine, given an instance reference."""  
  4.        if reboot_type == 'SOFT':  
  5.            # NOTE(vish): This will attempt to do a graceful shutdown/restart.  
  6.            ###此处处理_create_domain()运行时产生的异常  
  7.            #当有异常产生时,设置soft_reboot_success为False,表示soft reboot失败,用hard reboot 实例,这一点在Essex中是没有的。  
  8.            try:  
  9.                soft_reboot_success = self._soft_reboot(instance)  
  10.            except libvirt.libvirtError as e:  
  11.                LOG.debug(_("Instance soft reboot failed: %s"), e)  
  12.                soft_reboot_success = False  
  13.            #soft reboot失败后用hard reboot  
  14.            if soft_reboot_success:  
  15.                LOG.info(_("Instance soft rebooted successfully."),  
  16.                         instance=instance)  
  17.                return  
  18.            else:  
  19.                LOG.warn(_("Failed to soft reboot instance. "  
  20.                           "Trying hard reboot."),  
  21.                         instance=instance)  
  22.        return self._hard_reboot(context, instance, network_info,  
  23.                                 block_device_info)  
复制代码


  1. def _soft_reboot(self, instance):  
  2.      """Attempt to shutdown and restart the instance gracefully.
  3.      We use shutdown and create here so we can return if the guest
  4.      responded and actually rebooted. Note that this method only
  5.      succeeds if the guest responds to acpi. Therefore we return
  6.      success or failure so we can fall back to a hard reboot if
  7.      necessary.
  8.      :returns: True if the reboot succeeded
  9.      """  
  10.      dom = self._lookup_by_name(instance["name"])  
  11.      (state, _max_mem, _mem, _cpus, _t) = dom.info()  
  12.      state = LIBVIRT_POWER_STATE[state]  
  13.      old_domid = dom.ID()  
  14.      # NOTE(vish): This check allows us to reboot an instance that  
  15.      #             is already shutdown.  
  16.      if state == power_state.RUNNING:  
  17.          dom.shutdown()#shutdown正常关闭虚拟机  
  18.      # NOTE(vish): This actually could take slighty longer than the  
  19.      #             FLAG defines depending on how long the get_info  
  20.      #             call takes to return.  
  21.      self._prepare_pci_devices_for_use(  
  22.          pci_manager.get_instance_pci_devs(instance))  
  23.      for x in xrange(CONF.libvirt_wait_soft_reboot_seconds):  
  24.          dom = self._lookup_by_name(instance["name"])  
  25.          (state, _max_mem, _mem, _cpus, _t) = dom.info()  
  26.          state = LIBVIRT_POWER_STATE[state]  
  27.          new_domid = dom.ID()  
  28.   
  29.          # NOTE(ivoks): By checking domain IDs, we make sure we are  
  30.          #              not recreating domain that's already running.  
  31.          if old_domid != new_domid:  
  32.              if state in [power_state.SHUTDOWN,  
  33.                           power_state.CRASHED]:  
  34.                  LOG.info(_("Instance shutdown successfully."),  
  35.                           instance=instance)  
  36.                  self._create_domain(domain=dom) #根据原实例的domain重新define一个实例  
  37.                  timer = loopingcall.FixedIntervalLoopingCall(  
  38.                      self._wait_for_running, instance)  
  39.                  timer.start(interval=0.5).wait()  
  40.                  return True  
  41.              else:  
  42.                  LOG.info(_("Instance may have been rebooted during soft "  
  43.                             "reboot, so return now."), instance=instance)  
  44.                  return True  
  45.          greenthread.sleep(1)  
  46.      return False  
复制代码



  1. def _hard_reboot(self, context, instance, network_info,  
  2.                      block_device_info=None):  
  3.         """Reboot a virtual machine, given an instance reference.
  4.         Performs a Libvirt reset (if supported) on the domain.
  5.         If Libvirt reset is unavailable this method actually destroys and
  6.         re-creates the domain to ensure the reboot happens, as the guest
  7.         OS cannot ignore this action.
  8.         If xml is set, it uses the passed in xml in place of the xml from the
  9.         existing domain.
  10.         """  
  11.   
  12.         self._destroy(instance)#libvirt删除原实例  
  13.         disk_info = blockinfo.get_disk_info(CONF.libvirt_type,  
  14.                                             instance,  
  15.                                             block_device_info)  
  16.         # NOTE(vish): This could generate the wrong device_format if we are  
  17.         #             using the raw backend and the images don't exist yet.  
  18.         #             The create_images_and_backing below doesn't properly  
  19.         #             regenerate raw backend images, however, so when it  
  20.         #             does we need to (re)generate the xml after the images  
  21.         #             are in place.  
  22.         #根据数据库的信息,使用to_xml()拼装出一个虚拟机的XML描述文件,避免异常导致原虚拟机的xml文件缺失部分信息。  
  23.         xml = self.to_xml(context, instance, network_info, disk_info,  
  24.                           block_device_info=block_device_info,  
  25.                           write_to_disk=True)  
  26.   
  27.         # NOTE (rmk): Re-populate any missing backing files.  
  28.         disk_info_json = self.get_instance_disk_info(instance['name'], xml,  
  29.                                                      block_device_info)  
  30.         instance_dir = libvirt_utils.get_instance_path(instance)  
  31.         self._create_images_and_backing(context, instance, instance_dir,  
  32.                                         disk_info_json)  
  33.   
  34.         # Initialize all the necessary networking, block devices and  
  35.         # start the instance.  
  36.         self._create_domain_and_network(xml, instance, network_info,  
  37.                                         block_device_info, context=context,  
  38.                                         reboot=True)##创建新的虚拟机  
  39.         self._prepare_pci_devices_for_use(  
  40.             pci_manager.get_instance_pci_devs(instance))  
  41.   
  42.         def _wait_for_reboot():  
  43.             """Called at an interval until the VM is running again."""  
  44.             state = self.get_info(instance)['state']  
  45.   
  46.             if state == power_state.RUNNING:  
  47.                 LOG.info(_("Instance rebooted successfully."),  
  48.                          instance=instance)  
  49.                 raise loopingcall.LoopingCallDone()  
  50.   
  51.         timer = loopingcall.FixedIntervalLoopingCall(_wait_for_reboot)  
  52.         timer.start(interval=0.5).wait()  
复制代码

  1. def _create_domain_and_network(self, xml, instance, network_info,  
  2.                                block_device_info=None, power_on=True):  
  3. ###hard reboot创建虚拟机的函数,实际上也是调用的soft reboot 的创建函数_create_domain()  
  4.     """Do required network setup and create domain."""  
  5.     block_device_mapping = driver.block_device_info_get_mapping(  
  6.         block_device_info)  
  7.     #创建虚拟机之前连接卷,避免找不到卷的异常  
  8.     for vol in block_device_mapping:  
  9.         connection_info = vol['connection_info']  
  10.         disk_dev = vol['mount_device'].rpartition("/")[2]  
  11.         disk_info = {  
  12.             'dev': disk_dev,  
  13.             'bus': blockinfo.get_disk_bus_for_disk_dev(CONF.libvirt_type,  
  14.                                                        disk_dev),  
  15.             'type': 'disk',  
  16.             }  
  17.         self.volume_driver_method('connect_volume',  
  18.                                   connection_info,  
  19.                                   disk_info)  
  20.   
  21.     self.plug_vifs(instance, network_info)  
  22.     self.firewall_driver.setup_basic_filtering(instance, network_info)  
  23.     self.firewall_driver.prepare_instance_filter(instance, network_info)  
  24.     domain = self._create_domain(xml, instance=instance, power_on=power_on)  
  25.   
  26.     self.firewall_driver.apply_instance_filter(instance, network_info)  
  27.     return domain  
复制代码

  1. #soft reboot使用的函数  
  2.    def _create_domain(self, xml=None, domain=None,  
  3.                       instance=None, launch_flags=0, power_on=True):  
  4.        """Create a domain.
  5.        Either domain or xml must be passed in. If both are passed, then
  6.        the domain definition is overwritten from the xml.
  7.        """  
  8.        inst_path = None  
  9.        if instance:  
  10.            inst_path = libvirt_utils.get_instance_path(instance)  
  11.   
  12.        if CONF.libvirt_type == 'lxc':  
  13.            if not inst_path:  
  14.                inst_path = None  
  15.   
  16.            container_dir = os.path.join(inst_path, 'rootfs')  
  17.            fileutils.ensure_tree(container_dir)  
  18.            image = self.image_backend.image(instance, 'disk')  
  19.            disk.setup_container(image.path,  
  20.                                 container_dir=container_dir,  
  21.                                 use_cow=CONF.use_cow_images)  
  22. ### 创建虚拟机的时候进行了异常处理,define虚拟机时是会产生异常,例如已挂载的卷找不到了等,向上抛出异常,程序会继续执行,而不会在这里就停止执行,导致soft reboot不成功,也不会执行hard reboot,这样就避免了僵尸实例的产生。  
  23.        if xml:  
  24.            try:  
  25.                domain = self._conn.defineXML(xml)##libvirt创建一个虚拟机  
  26.            except Exception as e:  
  27.                LOG.error(_("An error occurred while trying to define a domain"  
  28.                            " with xml: %s") % xml)  
  29.                raise e  
  30.   
  31.        if power_on:  
  32.            try:  
  33.                domain.createWithFlags(launch_flags)  
  34.            except Exception as e:  
  35.                with excutils.save_and_reraise_exception():  
  36.                    LOG.error(_("An error occurred while trying to launch a "  
  37.                                "defined domain with xml: %s") %  
  38.                              domain.XMLDesc(0))  
  39.   
  40.        try:  
  41.            self._enable_hairpin(domain.XMLDesc(0))  
  42.        except Exception:  
  43.            with excutils.save_and_reraise_exception():  
  44.                LOG.error(_("An error occurred while enabling hairpin mode on "  
  45.                            "domain with xml: %s") % domain.XMLDesc(0))  
  46.   
  47.        # NOTE(uni): Now the container is running with its own private mount  
  48.        # namespace and so there is no need to keep the container rootfs  
  49.        # mounted in the host namespace  
  50.        if CONF.libvirt_type == 'lxc':  
  51.            state = self.get_info(instance)['state']  
  52.            container_dir = os.path.join(inst_path, 'rootfs')  
  53.            if state == power_state.RUNNING:  
  54.                disk.clean_lxc_namespace(container_dir=container_dir)  
  55.            else:  
  56.                disk.teardown_container(container_dir=container_dir)  
  57.   
  58.        return domain  
复制代码




没找到任何评论,期待你打破沉寂

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

关闭

推荐上一条 /2 下一条