Havana中VM的reboot分析

本文对比分析了OpenStack E与Havana版本中虚拟机(VM)重启的实现,探讨了Havana版本的改进之处,展示了OpenStack在版本演进中的稳定性提升。文章以代码注解的形式,为遇到Essex版本问题的开发者提供参考。
摘要由CSDN通过智能技术生成

作为个人学习笔记分享,有任何问题欢迎交流!


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

HavanaVMreboot

 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


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值