openstack nova 源码分析5-4 -nova/virt/libvirt目录下的connection.py

由于该文件大于8万字符 所以我分4次挂载(4

  
  
  
  
  1.  def get_cpu_info(self):  
  2. #获取cpuinfd 的信息 返回utils.dumps(cpu_info)  
  3.  
  4.        """Get cpuinfo information.  
  5.  
  6.        Obtains cpu feature from virConnect.getCapabilities,  
  7.        and returns as a json string.  
  8.  
  9.        :return: see above description  
  10.  
  11.        """ 
  12.  
  13.        xml = self._conn.getCapabilities()  
  14.        xml = libxml2.parseDoc(xml)  
  15.        nodes = xml.xpathEval('//host/cpu')  
  16.        if len(nodes) != 1:  
  17.            reason = _("'<cpu>' must be 1, but %d\n") % len(nodes)  
  18.            reason += xml.serialize()  
  19.            raise exception.InvalidCPUInfo(reason=reason)  
  20.  
  21.        cpu_info = dict()  
  22.  
  23.        arch_nodes = xml.xpathEval('//host/cpu/arch')  
  24.        if arch_nodes:  
  25.            cpu_info['arch'] = arch_nodes[0].getContent()  
  26.  
  27.        model_nodes = xml.xpathEval('//host/cpu/model')  
  28.        if model_nodes:  
  29.            cpu_info['model'] = model_nodes[0].getContent()  
  30.  
  31.        vendor_nodes = xml.xpathEval('//host/cpu/vendor')  
  32.        if vendor_nodes:  
  33.            cpu_info['vendor'] = vendor_nodes[0].getContent()  
  34.  
  35.        topology_nodes = xml.xpathEval('//host/cpu/topology')  
  36.        topology = dict()  
  37.        if topology_nodes:  
  38.            topology_node = topology_nodes[0].get_properties()  
  39.            while topology_node:  
  40.                name = topology_node.get_name()  
  41.                topology[name] = topology_node.getContent()  
  42.                topology_node = topology_node.get_next()  
  43.  
  44.            keys = ['cores''sockets''threads']  
  45.            tkeys = topology.keys()  
  46.            if set(tkeys) != set(keys):  
  47.                ks = ', '.join(keys)  
  48.                reason = _("topology (%(topology)s) must have %(ks)s")  
  49.                raise exception.InvalidCPUInfo(reason=reason % locals())  
  50.  
  51.        feature_nodes = xml.xpathEval('//host/cpu/feature')  
  52.        features = list()  
  53.        for nodes in feature_nodes:  
  54.            features.append(nodes.get_properties().getContent())  
  55.  
  56.        cpu_info['topology'] = topology  
  57.        cpu_info['features'] = features  
  58.        return utils.dumps(cpu_info)  
  59.  
  60.    def block_stats(self, instance_name, disk):  
  61. #接受实例名为参数 返回一个domain.blockStats(disk) 应该是域所在磁盘的一个状态??  
  62.        """  
  63.        Note that this function takes an instance name.  
  64.        """ 
  65.        domain = self._lookup_by_name(instance_name)  
  66.        return domain.blockStats(disk)  
  67.  
  68.    def interface_stats(self, instance_name, interface):  
  69. #接受实例名为参数 返回一个domain.interfanceStats(interface) 应该是域所在interface的一个状态  
  70.        """  
  71.        Note that this function takes an instance name.  
  72.        """ 
  73.        domain = self._lookup_by_name(instance_name)  
  74.        return domain.interfaceStats(interface)  
  75.  
  76.    def get_console_pool_info(self, console_type):  
  77. #返回控制池的信息 (给出的一个fake data) ip username password  
  78.        #TODO(mdragon): console proxy should be implemented for libvirt,  
  79.        #               in case someone wants to use it with kvm or  
  80.        #               such. For now return fake data.  
  81.        return  {'address''127.0.0.1',  
  82.                 'username''fakeuser',  
  83.                 'password''fakepassword'}  
  84.  
  85.    def refresh_security_group_rules(self, security_group_id):  
  86.        self.firewall_driver.refresh_security_group_rules(security_group_id)  
  87.  
  88.    def refresh_security_group_members(self, security_group_id):  
  89.        self.firewall_driver.refresh_security_group_members(security_group_id)  
  90.  
  91.    def refresh_provider_fw_rules(self):  
  92.        self.firewall_driver.refresh_provider_fw_rules()  
  93.  
  94.    def update_available_resource(self, ctxt, host):  
  95. #在电脑节点表中更新电脑管理资源的信息 这是一个很重要的函数 当nova-computer 登陆的时候 执行nova-manage serverce ..  
  96.        """Updates compute manager resource info on ComputeNode table.  
  97.  
  98.        This method is called when nova-coompute launches, and  
  99.        whenever admin executes "nova-manage service update_resource".  
  100.  
  101.        :param ctxt: security context  
  102.        :param host: hostname that compute manager is currently running  
  103.  
  104.        """ 
  105.  
  106.        try:  
  107.            service_ref = db.service_get_all_compute_by_host(ctxt, host)[0]  
  108.        except exception.NotFound:  
  109.            raise exception.ComputeServiceUnavailable(host=host)  
  110.  
  111.        # Updating host information  
  112.        dic = {'vcpus'self.get_vcpu_total(),  
  113.               'memory_mb'self.get_memory_mb_total(),  
  114.               'local_gb'self.get_local_gb_total(),  
  115.               'vcpus_used'self.get_vcpu_used(),  
  116.               'memory_mb_used'self.get_memory_mb_used(),  
  117.               'local_gb_used'self.get_local_gb_used(),  
  118.               'hypervisor_type'self.get_hypervisor_type(),  
  119.               'hypervisor_version'self.get_hypervisor_version(),  
  120.               'cpu_info'self.get_cpu_info()}  
  121.  
  122.        compute_node_ref = service_ref['compute_node']  
  123.        if not compute_node_ref:  
  124.            LOG.info(_('Compute_service record created for %s ') % host)  
  125.            dic['service_id'] = service_ref['id']  
  126.            db.compute_node_create(ctxt, dic)  
  127.        else:  
  128.            LOG.info(_('Compute_service record updated for %s ') % host)  
  129.            db.compute_node_update(ctxt, compute_node_ref[0]['id'], dic)  
  130.  
  131.    def compare_cpu(self, cpu_info):  
  132. #检查给出xml是否和主机cpu兼容 xml”必须是一个libvirt.openReadonly的一部分().getCapabilities()  
  133. #返回值follows by virCPUCompareResult。  
  134.    #如果0 >返回值,做动态迁移。  
  135. #返回: 如果给定cpu信息与该服务器并不兼容, 抛出异常。  
  136.  
  137.        """Checks the host cpu is compatible to a cpu given by xml.  
  138.  
  139.        "xml" must be a part of libvirt.openReadonly().getCapabilities().  
  140.        return values follows by virCPUCompareResult.  
  141.        if 0 > return value, do live migration.  
  142.        'http://libvirt.org/html/libvirt-libvirt.html#virCPUCompareResult'  
  143.  
  144.        :param cpu_info: json string that shows cpu feature(see get_cpu_info())  
  145.        :returns:  
  146.            None. if given cpu info is not compatible to this server,  
  147.            raise exception.  
  148.  
  149.        """ 
  150.  
  151.        LOG.info(_('Instance launched has CPU info:\n%s') % cpu_info)  
  152.        dic = utils.loads(cpu_info)  
  153.        xml = str(Template(self.cpuinfo_xml, searchList=dic))  
  154.        LOG.info(_('to xml...\n:%s ' % xml))  
  155.  
  156.        u = "http://libvirt.org/html/libvirt-libvirt.html#virCPUCompareResult" 
  157.        m = _("CPU doesn't have compatibility.\n\n%(ret)s\n\nRefer to %(u)s")  
  158.        # unknown character exists in xml, then libvirt complains  
  159.        try:  
  160.            ret = self._conn.compareCPU(xml, 0)  
  161.        except libvirt.libvirtError, e:  
  162.            ret = e.message  
  163.            LOG.error(m % locals())  
  164.            raise 
  165.  
  166.        if ret <= 0:  
  167.            raise exception.InvalidCPUInfo(reason=m % locals())  
  168.  
  169.        return 
  170.  
  171.    def ensure_filtering_rules_for_instance(self, instance_ref, network_info,  
  172.                                            time=None):  
  173.     #不知道大家注意没 上面这些 好多都是重写driver.py中的方法   
  174.     #设置过滤规则,并等待它完成  
  175.        """Setting up filtering rules and waiting for its completion.  
  176.  
  177.        To migrate an instance, filtering rules to hypervisors  
  178.        and firewalls are inevitable on destination host.  
  179.        ( Waiting only for filterling rules to hypervisor,  
  180.        since filtering rules to firewall rules can be set faster).  
  181.  
  182.        Concretely, the below method must be called.  
  183.        - setup_basic_filtering (for nova-basic, etc.)  
  184.        - prepare_instance_filter(for nova-instance-instance-xxx, etc.)  
  185.  
  186.        to_xml may have to be called since it defines PROJNET, PROJMASK.  
  187.        but libvirt migrates those value through migrateToURI(),  
  188.        so , no need to be called.  
  189.  
  190.        Don't use thread for this method since migration should  
  191.        not be started when setting-up filtering rules operations  
  192.        are not completed.  
  193.  
  194.        :params instance_ref: nova.db.sqlalchemy.models.Instance object  
  195.  
  196.        """ 
  197.  
  198.        if not time:  
  199.            time = greenthread  
  200.  
  201.        # If any instances never launch at destination host,  
  202.        # basic-filtering must be set here.  
  203.        self.firewall_driver.setup_basic_filtering(instance_ref, network_info)  
  204.        # setting up nova-instance-instance-xx mainly.  
  205.        self.firewall_driver.prepare_instance_filter(instance_ref,  
  206.                network_info)  
  207.  
  208.        # wait for completion  
  209.        timeout_count = range(FLAGS.live_migration_retry_count)  
  210.        while timeout_count:  
  211.            if self.firewall_driver.instance_filter_exists(instance_ref,  
  212.                                                           network_info):  
  213.                break 
  214.            timeout_count.pop()  
  215.            if len(timeout_count) == 0:  
  216.                msg = _('Timeout migrating for %s. nwfilter not found.')  
  217.                raise exception.Error(msg % instance_ref.name)  
  218.            time.sleep(1)  
  219.  
  220.    def live_migration(self, ctxt, instance_ref, dest,  
  221.                       post_method, recover_method, block_migration=False):  
  222.     #分发处理高负荷,当有高负荷操作时候,大量生成 live_mirgration  
  223.        """Spawning live_migration operation for distributing high-load.  
  224.  
  225.        :params ctxt: security context  
  226.        :params instance_ref:  
  227.            nova.db.sqlalchemy.models.Instance object  
  228.            instance object that is migrated.  
  229.        :params dest: destination host  
  230.        :params block_migration: destination host  
  231.        :params post_method:  
  232.            post operation method.  
  233.            expected nova.compute.manager.post_live_migration.  
  234.        :params recover_method:  
  235.            recovery method when any exception occurs.  
  236.            expected nova.compute.manager.recover_live_migration.  
  237.        :params block_migration: if true, do block migration.  
  238.  
  239.        """ 
  240.  
  241.        greenthread.spawn(self._live_migration, ctxt, instance_ref, dest,  
  242.                          post_method, recover_method, block_migration)  
  243.  
  244.    def _live_migration(self, ctxt, instance_ref, dest, post_method,  
  245.                        recover_method, block_migration=False):  
  246.        #动态迁移???  
  247.     """Do live migration.  
  248.  
  249.        :params ctxt: security context  
  250.        :params instance_ref:  
  251.            nova.db.sqlalchemy.models.Instance object  
  252.            instance object that is migrated.  
  253.        :params dest: destination host  
  254.        :params post_method:  
  255.            post operation method.  
  256.            expected nova.compute.manager.post_live_migration.  
  257.        :params recover_method:  
  258.            recovery method when any exception occurs.  
  259.            expected nova.compute.manager.recover_live_migration.  
  260.  
  261.        """ 
  262.  
  263.        # Do live migration.  
  264.        try:  
  265.            if block_migration:  
  266.                flaglist = FLAGS.block_migration_flag.split(',')  
  267.            else:  
  268.                flaglist = FLAGS.live_migration_flag.split(',')  
  269.            flagvals = [getattr(libvirt, x.strip()) for x in flaglist]  
  270.            logical_sum = reduce(lambda x, y: x | y, flagvals)  
  271.  
  272.            dom = self._conn.lookupByName(instance_ref.name)  
  273.            dom.migrateToURI(FLAGS.live_migration_uri % dest,  
  274.                             logical_sum,  
  275.                             None,  
  276.                             FLAGS.live_migration_bandwidth)  
  277.  
  278.        except Exception:  
  279.            recover_method(ctxt, instance_ref, dest, block_migration)  
  280.            raise 
  281.  
  282.        # Waiting for completion of live_migration.  
  283.        timer = utils.LoopingCall(f=None)  
  284.  
  285.        def wait_for_live_migration():  
  286.            """waiting for live migration completion""" 
  287.            try:  
  288.                self.get_info(instance_ref.name)['state']  
  289.            except exception.NotFound:  
  290.                timer.stop()  
  291.                post_method(ctxt, instance_ref, dest, block_migration)  
  292.  
  293.        timer.f = wait_for_live_migration  
  294.        timer.start(interval=0.5, now=True)  
  295.  
  296.    def pre_block_migration(self, ctxt, instance_ref, disk_info_json):  
  297. #准备block的 迁移  
  298.        """Preparation block migration.  
  299.  
  300.        :params ctxt: security context  
  301.        :params instance_ref:  
  302.            nova.db.sqlalchemy.models.Instance object  
  303.            instance object that is migrated.  
  304.        :params disk_info_json:  
  305.            json strings specified in get_instance_disk_info  
  306.  
  307.        """ 
  308.        disk_info = utils.loads(disk_info_json)  
  309.  
  310.        # make instance directory  
  311.        instance_dir = os.path.join(FLAGS.instances_path, instance_ref['name'])  
  312.        if os.path.exists(instance_dir):  
  313.            raise exception.DestinationDiskExists(path=instance_dir)  
  314.        os.mkdir(instance_dir)  
  315.  
  316.        for info in disk_info:  
  317.            base = os.path.basename(info['path'])  
  318.            # Get image type and create empty disk image.  
  319.            instance_disk = os.path.join(instance_dir, base)  
  320.            utils.execute('qemu-img''create''-f', info['type'],  
  321.                          instance_disk, info['local_gb'])  
  322.  
  323.        # if image has kernel and ramdisk, just download  
  324.        # following normal way.  
  325.        if instance_ref['kernel_id']:  
  326.            user = manager.AuthManager().get_user(instance_ref['user_id'])  
  327.            project = manager.AuthManager().get_project(  
  328.                instance_ref['project_id'])  
  329.            self._fetch_image(nova_context.get_admin_context(),  
  330.                              os.path.join(instance_dir, 'kernel'),  
  331.                              instance_ref['kernel_id'],  
  332.                              user,  
  333.                              project)  
  334.            if instance_ref['ramdisk_id']:  
  335.                self._fetch_image(nova_context.get_admin_context(),  
  336.                                  os.path.join(instance_dir, 'ramdisk'),  
  337.                                  instance_ref['ramdisk_id'],  
  338.                                  user,  
  339.                                  project)  
  340.  
  341.    def post_live_migration_at_destination(self, ctxt,  
  342.                                           instance_ref,  
  343.                                           network_info,  
  344.                                           block_migration):  
  345.     #Post操作的动态迁移到目的地主机  
  346.        """Post operation of live migration at destination host.  
  347.  
  348.        :params ctxt: security context  
  349.        :params instance_ref:  
  350.            nova.db.sqlalchemy.models.Instance object  
  351.            instance object that is migrated.  
  352.        :params network_info: instance network infomation  
  353.        :params : block_migration: if true, post operation of block_migraiton.  
  354.        """ 
  355.        # Define migrated instance, otherwise, suspend/destroy does not work.  
  356.        dom_list = self._conn.listDefinedDomains()  
  357.        if instance_ref.name not in dom_list:  
  358.            instance_dir = os.path.join(FLAGS.instances_path,  
  359.                                        instance_ref.name)  
  360.            xml_path = os.path.join(instance_dir, 'libvirt.xml')  
  361.            # In case of block migration, destination does not have  
  362.            # libvirt.xml  
  363.            if not os.path.isfile(xml_path):  
  364.                xml = self.to_xml(instance_ref, network_info=network_info)  
  365.                f = open(os.path.join(instance_dir, 'libvirt.xml'), 'w+')  
  366.                f.write(xml)  
  367.                f.close()  
  368.            # libvirt.xml should be made by to_xml(), but libvirt  
  369.            # does not accept to_xml() result, since uuid is not  
  370.            # included in to_xml() result.  
  371.            dom = self._lookup_by_name(instance_ref.name)  
  372.            self._conn.defineXML(dom.XMLDesc(0))  
  373.  
  374.    def get_instance_disk_info(self, ctxt, instance_ref):  
  375. #返回 跟前面的pre_block_migration有些区别  
  376.    #        json strings with below format.  
  377.    #       "[{'path':'disk', 'type':'raw', 'local_gb':'10G'},...]"  
  378.        """Preparation block migration.  
  379.  
  380.        :params ctxt: security context  
  381.        :params instance_ref:  
  382.            nova.db.sqlalchemy.models.Instance object  
  383.            instance object that is migrated.  
  384.        :return:  
  385.            json strings with below format.  
  386.           "[{'path':'disk', 'type':'raw', 'local_gb':'10G'},...]"  
  387.  
  388.        """ 
  389.        disk_info = []  
  390.  
  391.        virt_dom = self._lookup_by_name(instance_ref.name)  
  392.        xml = virt_dom.XMLDesc(0)  
  393.        doc = libxml2.parseDoc(xml)  
  394.        disk_nodes = doc.xpathEval('//devices/disk')  
  395.        path_nodes = doc.xpathEval('//devices/disk/source')  
  396.        driver_nodes = doc.xpathEval('//devices/disk/driver')  
  397.  
  398.        for cnt, path_node in enumerate(path_nodes):  
  399.            disk_type = disk_nodes[cnt].get_properties().getContent()  
  400.            path = path_node.get_properties().getContent()  
  401.  
  402.            if disk_type != 'file':  
  403.                LOG.debug(_('skipping %(path)s since it looks like volume') %  
  404.                          locals())  
  405.                continue 
  406.  
  407.            # In case of libvirt.xml, disk type can be obtained  
  408.            # by the below statement.  
  409.            # -> disk_type = driver_nodes[cnt].get_properties().getContent()  
  410.            # but this xml is generated by kvm, format is slightly different.  
  411.            disk_type = \  
  412.                driver_nodes[cnt].get_properties().get_next().getContent()  
  413.            if disk_type == 'raw':  
  414.                size = int(os.path.getsize(path))  
  415.            else:  
  416.                out, err = utils.execute('qemu-img''info', path)  
  417.                size = [i.split('(')[1].split()[0for i in out.split('\n')  
  418.                    if i.strip().find('virtual size') >= 0]  
  419.                size = int(size[0])  
  420.  
  421.            # block migration needs same/larger size of empty image on the  
  422.            # destination host. since qemu-img creates bit smaller size image  
  423.            # depending on original image size, fixed value is necessary.  
  424.            for unit, divisor in [('G'1024 ** 3), ('M'1024 ** 2),  
  425.                                  ('K'1024), (''1)]:  
  426.                if size / divisor == 0:  
  427.                    continue 
  428.                if size % divisor != 0:  
  429.                    size = size / divisor + 1 
  430.                else:  
  431.                    size = size / divisor  
  432.                size = str(size) + unit  
  433.                break 
  434.  
  435.            disk_info.append({'type': disk_type, 'path': path,  
  436.                              'local_gb': size})  
  437.  
  438.        return utils.dumps(disk_info)  
  439.  
  440.    def unfilter_instance(self, instance_ref, network_info):  
  441. #在防火墙驱动统一方法的see comments???  
  442.        """See comments of same method in firewall_driver.""" 
  443.        self.firewall_driver.unfilter_instance(instance_ref,  
  444.                                               network_info=network_info)  
  445.  
  446.    def update_host_status(self):  
  447.        """See xenapi_conn.py implementation.""" 
  448.        pass 
  449.  
  450.    def get_host_stats(self, refresh=False):  
  451.        """See xenapi_conn.py implementation.""" 
  452.        pass 
  453.  
  454.    def host_power_action(self, host, action):  
  455. #重启或者关闭 或者...  
  456.        """Reboots, shuts down or powers up the host.""" 
  457.        pass 
  458.  
  459.    def set_host_enabled(self, host, enabled):  
  460.        """Sets the specified host's ability to accept new instances.""" 
  461.        pass 

)

 

     该文件位于nova/virt/libvirt目录下的connection.py!我只是浅浅的分析了一下类中函数的方法 细节并没有多看,肯定有很多地方是错的 或者不好!希望大家能够帮忙指出错误!

      接下来 看源代码如下:中文部分是我加的注释 !或许大家会问 为什么要看这个connection.py呢 因为我发现该文件外部virt目录下有个connection.py 其中引用了 这个文件 所以觉得这个应该很重要 而且发现 好多方法都是重写的底层的driver的方法

 

你可能感兴趣的:(openstack,openstack,openstack,源码分析,nova源码分析)