分享

OpenStack建立实例完整过程源码详细分析(6)

xioaxu790 发表于 2014-6-12 13:45:10 [显示全部楼层] 回帖奖励 阅读模式 关闭右栏 0 7326
本帖最后由 xioaxu790 于 2014-6-12 13:46 编辑
问题导读:
1、ReservableResource类,是如何实例化的?



继续看/nova/compute/api.py中的creat方法:
  1. def create(self, context, instance_type,   
  2.                image_href, kernel_id=None, ramdisk_id=None,   
  3.                min_count=None, max_count=None,   
  4.                display_name=None, display_description=None,   
  5.                key_name=None, key_data=None, security_group=None,   
  6.                availability_zone=None, user_data=None, metadata=None,   
  7.                injected_files=None, admin_password=None,   
  8.                block_device_mapping=None, access_ip_v4=None,   
  9.                access_ip_v6=None, requested_networks=None, config_drive=None,   
  10.                auto_disk_config=None, scheduler_hints=None):   
  11.         """  
  12.         准备实例,并且发送实例的信息和要运行实例的请求消息到远程调度器scheduler;  
  13.         实现实例的简历和运行,由调度器完成,这部分代码实际上只是实现请求消息的发送;  
  14.         返回一个元组(实例或者是reservation_id的元组),元组里面的实例可以是“None”或者是实例字典的一个列表,这要取决于是否等待scheduler返回的信息;  
  15.         """   
  16.    
  17.         self._check_create_policies(context, availability_zone,requested_networks, block_device_mapping)   
  18.    
  19.         # 验证所有的输入实例参数;   
  20.         # 发送要运行实例('run_instance')的请求消息到远程调度器;   
  21.         return self._create_instance(   
  22.                                context, instance_type,   
  23.                                image_href, kernel_id, ramdisk_id,   
  24.                                min_count, max_count,   
  25.                                display_name, display_description,   
  26.                                key_name, key_data, security_group,   
  27.                                availability_zone, user_data, metadata,   
  28.                                injected_files, admin_password,   
  29.                                access_ip_v4, access_ip_v6,   
  30.                                requested_networks, config_drive,   
  31.                                block_device_mapping, auto_disk_config,   
  32.                                scheduler_hints=scheduler_hints)   
复制代码

语句self._check_create_policies(context, availability_zone,requested_networks, block_device_mapping)实现的是验证是否有资格执行creat这个方法,policy是nova中的一个资格验证机制,我会在其他博文中进行总结;
    然后就进入了方法_create_instance,/nova/compute/api.py----def _create_instance(......):

  1. def _create_instance(self, context, instance_type,  
  2.                image_href, kernel_id, ramdisk_id,  
  3.                min_count, max_count,  
  4.                display_name, display_description,  
  5.                key_name, key_data, security_group,  
  6.                availability_zone, user_data, metadata,  
  7.                injected_files, admin_password,  
  8.                access_ip_v4, access_ip_v6,  
  9.                requested_networks, config_drive,  
  10.                block_device_mapping, auto_disk_config,  
  11.                reservation_id=None, scheduler_hints=None):  
  12.         """
  13.         验证所有的输入实例参数;
  14.         发送要运行实例('run_instance')的请求消息到远程调度器;
  15.         """  
  16.   
  17.         # generate_uid:随机生成一个uid值赋值给reservation_id;  
  18.         if reservation_id is None:  
  19.             reservation_id = utils.generate_uid('r')  
  20.          
  21.         # _validate_and_provision_instance:验证所有的输入参数;  
  22.         # 返回要建立实例的各类信息;  
  23.         # 这个方法中做了很多事,稍后会好好总结;  
  24.         (instances, request_spec, filter_properties) = \  
  25.                 self._validate_and_provision_instance(context, instance_type,  
  26.                         image_href, kernel_id, ramdisk_id, min_count,  
  27.                         max_count, display_name, display_description,  
  28.                         key_name, key_data, security_group, availability_zone,  
  29.                         user_data, metadata, injected_files, access_ip_v4,  
  30.                         access_ip_v6, requested_networks, config_drive,  
  31.                         block_device_mapping, auto_disk_config,  
  32.                         reservation_id, scheduler_hints)  
  33.   
  34.         # 循环获取instances中每个实例action的一些相关信息(包括启动时间等);  
  35.         # _record_action_start获取要启动的实例action的一些相关信息(包括启动时间等);  
  36.         for instance in instances:  
  37.             self._record_action_start(context, instance,instance_actions.CREATE)  
  38.   
  39.         # run_instance:实现了发送要运行实例('run_instance')的请求消息到远程节点;  
  40.         # 远程节点会在队列中提取这条消息,然后调用相应资源,实现运行实例的这个请求;  
  41.         # 这个方法只是实现了请求信息的发送;  
  42.         self.scheduler_rpcapi.run_instance(context,  
  43.                 request_spec=request_spec,  
  44.                 admin_password=admin_password, injected_files=injected_files,  
  45.                 requested_networks=requested_networks, is_first_time=True,  
  46.                 filter_properties=filter_properties)  
  47.   
  48.         return (instances, reservation_id)  
复制代码

  这个方法中共有四条语句:
  1. reservation_id = utils.generate_uid('r')
  2.     (instances, request_spec, filter_properties) = self._validate_and_provision_instance(......)
  3.     self._record_action_start(context, instance,instance_actions.CREATE)
  4.     self.scheduler_rpcapi.run_instance(......)
复制代码


    我们逐条进行解析。
    A.reservation_id = utils.generate_uid('r'):
    随机生成一个长度固定的uid值,赋值给reservation_id;
    B.(instances,request_spec,filter_properties)=self._validate_and_provision_instance(......):
    这条语句非常重要,它主要完成的是对输入各个参数进行检查验证,其中完成了一个非常重要的任务,即资源的配额管理。现在对这条语句进行解析,首先来看_validate_and_provision_instance这个方法:

  1. def _validate_and_provision_instance(self, context, instance_type,  
  2.                                          image_href, kernel_id, ramdisk_id,  
  3.                                          min_count, max_count,  
  4.                                          display_name, display_description,  
  5.                                          key_name, key_data, security_groups,  
  6.                                          availability_zone, user_data,  
  7.                                          metadata, injected_files,  
  8.                                          access_ip_v4, access_ip_v6,  
  9.                                          requested_networks, config_drive,  
  10.                                          block_device_mapping,  
  11.                                          auto_disk_config, reservation_id,  
  12.                                          scheduler_hints):  
  13.         """
  14.         验证所有的输入参数;
  15.         返回要建立实例的各类信息;
  16.         """  
  17.   
  18.         if not metadata:  
  19.             metadata = {}  
  20.         if not security_groups:  
  21.             security_groups = ['default']  
  22.   
  23.         if not instance_type:  
  24.             instance_type = instance_types.get_default_instance_type()  
  25.         if not min_count:  
  26.             min_count = 1  
  27.         if not max_count:  
  28.             max_count = min_count  
  29.   
  30.         block_device_mapping = block_device_mapping or []  
  31.         if min_count > 1 or max_count > 1:  
  32.             if any(map(lambda bdm: 'volume_id' in bdm, block_device_mapping)):  
  33.                 msg = _('Cannot attach one or more volumes to multiple' ' instances')  
  34.                 raise exception.InvalidRequest(msg)  
  35.         if instance_type['disabled']:  
  36.             raise exception.InstanceTypeNotFound(  
  37.                     instance_type_id=instance_type['id'])  
  38.   
  39.         if user_data:  
  40.             l = len(user_data)  
  41.             if l > MAX_USERDATA_SIZE:  
  42.                 # NOTE(mikal): user_data is stored in a text column, and  
  43.                 # the database might silently truncate if its over length.  
  44.                 raise exception.InstanceUserDataTooLarge(  
  45.                     length=l, maxsize=MAX_USERDATA_SIZE)  
  46.   
  47.             try:  
  48.                 base64.decodestring(user_data)  
  49.             except base64.binascii.Error:  
  50.                 raise exception.InstanceUserDataMalformed()  
  51.   
  52.         # 根据配额资源限制计算所要建立实例的数目,并获取了分配好的资源(块存储)的UUID的列表;  
  53.         # _check_num_instances_quota:根据磁盘配额资源限制确定所要建立实例的数目;  
  54.         # num_instances:返回值max_count表示建立实例的最大数目;  
  55.         # quota_reservations: 返回值reservations表示建立的预定(分配)的资源的UUID的列表;  
  56.         num_instances, quota_reservations = self._check_num_instances_quota(context, instance_type, min_count, max_count)  
  57.   
  58.         try:  
  59.             instances = []  
  60.             instance_uuids = []  
  61.   
  62.             # 对磁盘配额的元数据属性、磁盘配额的注入文件以及安全组和网络进行检测;  
  63.             self._check_metadata_properties_quota(context, metadata)  
  64.             """
  65.             检测metadata参数;                    
  66.             强制对磁盘配额的元数据属性的限制进行检测;
  67.             进行了简单的磁盘配额限制的检测,并构造了一个符合要求的资源列表;
  68.             """  
  69.             self._check_injected_file_quota(context, injected_files)  
  70.             """
  71.             检测injected_files参数;
  72.             强制对磁盘配额注入文件的限制进行检测,如果超出任何限制会引发异常;
  73.             具体限制包括注入文件数目、注入文件路径长度和注入文件内容长度三项指标;
  74.             """  
  75.             self._check_requested_secgroups(context, security_groups)  
  76.             """
  77.             检测security_groups参数;                     
  78.             检测所要求的安全组是否存在,并且属于指定的对象,如果不存在则会引发异常;
  79.             """  
  80.             self._check_requested_networks(context, requested_networks)  
  81.             """
  82.             检测requested_networks参数;                     
  83.             检测所需求的网络是否属于指定的对象(工程),
  84.             并且为每个网络提供的固定的IP地址是否处在同一个网段中;
  85.             """  
  86.   
  87.             # 检测image_href参数;  
  88.             # 如果image_href值为真,则创建image_service并从给定的image_href解析它的ID值,赋给image_id;  
  89.             # 并建立一个glance的客户端,具体方法是应用相关参数实例化一个新的glanceclient.Client对象;  
  90.             # 获取image_service的状态,以此判断image_service是否创建成功;  
  91.             if image_href:  
  92.                 (image_service, image_id) = glance.get_remote_image_service(context, image_href)  
  93.                 image = image_service.show(context, image_id)  
  94.                 if image['status'] != 'active':  
  95.                     raise exception.ImageNotActive(image_id=image_id)  
  96.             else:  
  97.                 image = {}  
  98.   
  99.             # 检测instance_type['memory_mb']和instance_type['root_gb']参数;  
  100.             if instance_type['memory_mb'] < int(image.get('min_ram') or 0):  
  101.                 raise exception.InstanceTypeMemoryTooSmall()  
  102.             if instance_type['root_gb'] < int(image.get('min_disk') or 0):  
  103.                 raise exception.InstanceTypeDiskTooSmall()  
  104.   
  105.             # 为实例获取合适的内核和ramdisk的值;  
  106.             kernel_id, ramdisk_id = self._handle_kernel_and_ramdisk(context, kernel_id, ramdisk_id, image)  
  107.             """
  108.             为实例选择合适的内核和ramdisk,返回获取到的内核和ramdisk的值kernel_id和ramdisk_id;
  109.             内核和ramdisk可以选择以下三种中的一种:
  110.             1.通过建立实例的要求来决定;
  111.             2.从image(镜像)来继承;
  112.             3.通过应用  ‘null_kernel’标志强制不使用;
  113.             注:如果是第三种情况,则还建立了image_service服务。而且建立一个glance的客户端,具体方法是应用相关参数实例化一个新的glanceclient.Client对象。
  114.             """  
  115.   
  116.             # 处理config_drive这个参数;  
  117.             config_drive_id = None  
  118.             if config_drive and not utils.is_valid_boolstr(config_drive):  
  119.                 # config_drive is volume id  
  120.                 config_drive_id = config_drive  
  121.                 config_drive = None  
  122.   
  123.                 # Ensure config_drive image exists  
  124.                 # 检测config_drive参数,确保config_drive镜像是存在的;  
  125.                 # 如果config_drive值是正确无误的,则创建cd_image_service并从给定的config_drive_id解析它的ID值,赋给config_drive_id;  
  126.                 # 并建立一个glance的客户端,具体方法是应用相关参数实例化一个新的glanceclient.Client对象;  
  127.                 # 获取cd_image_service的状态,以此判断cd_image_service是否创建成功;  
  128.                 cd_image_service, config_drive_id = glance.get_remote_image_service(context, config_drive_id)  
  129.                 cd_image_service.show(context, config_drive_id)  
  130.   
  131.             # 处理key_data这个参数;  
  132.             if key_data is None and key_name:  
  133.                 key_pair = self.db.key_pair_get(context, context.user_id,key_name)  
  134.                 key_data = key_pair['public_key']  
  135.   
  136.             # 从镜像元数据中获取root_device_name值,如果这个值没有被指定,则返回None值;  
  137.             root_device_name = block_device.properties_root_device_name(image.get('properties', {}))  
  138.   
  139.             # 从参数availability_zone中分离出availability_zone值和forced_host值;  
  140.             availability_zone, forced_host = self._handle_availability_zone(availability_zone)  
  141.   
  142.             # 从instance_type这个参数中保存instance type属性到实例的system_metadata数据中,格式如下所示:  
  143.             # [prefix]instance_type_[key]  
  144.             # 保存instance type信息到system_metadata当中,按照一定的格式;  
  145.             system_metadata = instance_types.save_instance_type_info(dict(), instance_type)  
  146.   
  147.             # 保存所有参数选项的字典;  
  148.             base_options = {  
  149.                 'reservation_id': reservation_id,  
  150.                 'image_ref': image_href,  
  151.                 'kernel_id': kernel_id or '',  
  152.                 'ramdisk_id': ramdisk_id or '',  
  153.                 'power_state': power_state.NOSTATE,  
  154.                 'vm_state': vm_states.BUILDING,  
  155.                 'config_drive_id': config_drive_id or '',  
  156.                 'config_drive': config_drive or '',  
  157.                 'user_id': context.user_id,  
  158.                 'project_id': context.project_id,  
  159.                 'launch_time': time.strftime('%Y-%m-%dT%H:%M:%SZ',time.gmtime()),  
  160.                 'instance_type_id': instance_type['id'],  
  161.                 'memory_mb': instance_type['memory_mb'],  
  162.                 'vcpus': instance_type['vcpus'],  
  163.                 'root_gb': instance_type['root_gb'],  
  164.                 'ephemeral_gb': instance_type['ephemeral_gb'],  
  165.                 'display_name': display_name,  
  166.                 'display_description': display_description or '',  
  167.                 'user_data': user_data,  
  168.                 'key_name': key_name,  
  169.                 'key_data': key_data,  
  170.                 'locked': False,  
  171.                 'metadata': metadata,  
  172.                 'access_ip_v4': access_ip_v4,  
  173.                 'access_ip_v6': access_ip_v6,  
  174.                 'availability_zone': availability_zone,  
  175.                 'root_device_name': root_device_name,  
  176.                 'progress': 0,  
  177.                 'system_metadata': system_metadata}  
  178.   
  179.             # 从image镜像中继承相关属性信息;  
  180.             # 包括os_type、architecture、vm_mode和auto_disk_config;  
  181.             options_from_image = self._inherit_properties_from_image(image, auto_disk_config)  
  182.   
  183.             # 相关属性更新到字典base_options当中;  
  184.             base_options.update(options_from_image)  
  185.   
  186.             # num_instances表示要建立实例的最大数目;  
  187.             LOG.debug(_("Going to run %s instances...") % num_instances)  
  188.   
  189.             # 从调度提示信息scheduler_hints中获取过滤器信息;  
  190.             filter_properties = dict(scheduler_hints=scheduler_hints)  
  191.               
  192.             # 获取filter_properties['force_hosts']的值;(注:这里forced_host是怎么来的还需要进一步研究明白;)  
  193.             if forced_host:  
  194.                 check_policy(context, 'create:forced_host', {})  
  195.                 filter_properties['force_hosts'] = [forced_host]  
  196.   
  197.             # num_instances表示要建立实例的最大数目;  
  198.             # xrange(num_instances)表示从0到num_instances-1的序列;  
  199.             for i in xrange(num_instances):  
  200.                 # 拷贝base_options对象;  
  201.                 options = base_options.copy()               
  202.                 # 为每一个新的实例在数据库中建立新的条目,包括任何更新的表(如安全组等等);  
  203.                 instance = self.create_db_entry_for_new_instance(context, instance_type, image, options, security_groups, block_device_mapping, num_instances, i)  
  204.   
  205.                 # 实例instance添加到instances中;  
  206.                 instances.append(instance)  
  207.                 # instance['uuid']添加到instance_uuids中;  
  208.                 instance_uuids.append(instance['uuid'])  
  209.                   
  210.                 # 验证一个实例instance中的所有的块设备映射;  
  211.                 self._validate_bdm(context, instance)  
  212.                 # send a state update notification for the initial create to  
  213.                 # show it going from non-existent to BUILDING  
  214.                 # 为实例的初始化建立发送一个状态更新通知,表示实例状态从不存在到建立;  
  215.                 # send_update_with_states:在一个实例中,发送compute.instance.update来通知实例的任何的改变信息;  
  216.                 notifications.send_update_with_states(context, instance, None, vm_states.BUILDING, None, None, service="api")  
  217.   
  218.         # In the case of any exceptions, attempt DB cleanup and rollback the  
  219.         # quota reservations.  
  220.         # 在引发异常的情况下  
  221.         except Exception:  
  222.             # 先保存当前的异常Exception,运行一些代码以后,再引发这个异常;  
  223.             # 这个挺有意思的;  
  224.             with excutils.save_and_reraise_exception():  
  225.                 try:  
  226.                     # 循环取出每个实例的UUID值;  
  227.                     # 根据每个实例的UUID值,删除具体的实例;  
  228.                     # instance_destroy:销毁当前要建立的实例,如果实例不存在,则引发异常;  
  229.                     # 返回删除后的实例对象;  
  230.                     for instance_uuid in instance_uuids:  
  231.                         self.db.instance_destroy(context, instance_uuid)  
  232.                 finally:  
  233.                     # 配额quota_reservations预约信息的删除;  
  234.                     QUOTAS.rollback(context, quota_reservations)  
  235.   
  236.         # Commit the reservations  
  237.         # 提交设定好的reservations预约信息;  
  238.         QUOTAS.commit(context, quota_reservations)  
  239.   
  240.         # 生成包含请求建立实例的信息的字典;  
  241.         request_spec = {  
  242.             'image': jsonutils.to_primitive(image), # 转换镜像image对象到primitives格式;  
  243.             'instance_properties': base_options, # 实例属性;  
  244.             'instance_type': instance_type, # 实例类型;  
  245.             'instance_uuids': instance_uuids, # 实例UUID;  
  246.             'block_device_mapping': block_device_mapping, # 块设备映射信息;  
  247.             'security_group': security_groups, # 安全组信息;
复制代码

这个方法中要完成很多东西,下面来逐条进行解析:
    a.metadata、security_groups、instance_type、min_count、max_count、block_device_mapping、user_data等参数的验证和初始化:

  1. if not metadata:  
  2.     metadata = {}  
  3. if not security_groups:  
  4.     security_groups = ['default']  
  5. if not instance_type:  
  6.     instance_type = instance_types.get_default_instance_type()  
  7. if not min_count:  
  8.     min_count = 1  
  9. if not max_count:  
  10.     max_count = min_count  
  11. block_device_mapping = block_device_mapping or []  
  12.   
  13. if min_count > 1 or max_count > 1:  
  14.     if any(map(lambda bdm: 'volume_id' in bdm, block_device_mapping)):  
  15.         msg = _('Cannot attach one or more volumes to multiple' ' instances')  
  16.         raise exception.InvalidRequest(msg)  
  17. if instance_type['disabled']:  
  18.     raise exception.InstanceTypeNotFound(instance_type_id=instance_type['id'])  
  19.   
  20. if user_data:  
  21.     l = len(user_data)  
  22.     if l > MAX_USERDATA_SIZE:  
  23.         raise exception.InstanceUserDataTooLarge(length=l, maxsize=MAX_USERDATA_SIZE)  
  24.     try:  
  25.         base64.decodestring(user_data)  
  26.     except base64.binascii.Error:  
  27.         raise exception.InstanceUserDataMalformed()  
复制代码

  b.num_instances, quota_reservations = self._check_num_instances_quota(context, instance_type, min_count, max_count)资源配额管理,根据磁盘配额资源限制确定所要建立实例的数目,并获取了分配好的资源(块存储)的UUID的列表;
    进入方法_check_num_instances_quota:

  1. def _check_num_instances_quota(self, context, instance_type, min_count,max_count):  
  2.         """
  3.         根据配额资源限制所要建立实例的数目;
  4.         返回值max_count表示建立实例的最大数目;
  5.         返回值reservations表示建立的预定(分配)的资源的UUID的列表;
  6.         """  
  7.   
  8.         # 确定请求分配的内核数和RAM;  
  9.         req_cores = max_count * instance_type['vcpus']  
  10.         req_ram = max_count * instance_type['memory_mb']  
  11.   
  12.         # reserve:检查配额并且分配存储资源;  
  13.         # 如果没有错误,方法返回所建立的预定(分配)的资源的UUID的列表给reservations;  
  14.         try:  
  15.             reservations = QUOTAS.reserve(context, instances=max_count,cores=req_cores, ram=req_ram)  
  16.         except exception.OverQuota as exc:  
  17.   
  18.             # 查找超出配额限制的原因;  
  19.             quotas = exc.kwargs['quotas']  
  20.             usages = exc.kwargs['usages']  
  21.             overs = exc.kwargs['overs']  
  22.   
  23.             headroom = dict((res, quotas[res] -  
  24.                              (usages[res]['in_use'] + usages[res]['reserved']))  
  25.                             for res in quotas.keys())  
  26.   
  27.             allowed = headroom['instances']  
  28.             # Reduce 'allowed' instances in line with the cores & ram headroom  
  29.             if instance_type['vcpus']:  
  30.                 allowed = min(allowed,headroom['cores'] // instance_type['vcpus'])  
  31.             if instance_type['memory_mb']:  
  32.                 allowed = min(allowed,headroom['ram'] // instance_type['memory_mb'])  
  33.   
  34.             # Convert to the appropriate exception message  
  35.             if allowed <= 0:  
  36.                 msg = _("Cannot run any more instances of this type.")  
  37.                 allowed = 0  
  38.             elif min_count <= allowed <= max_count:  
  39.                 # We're actually OK, but still need reservations  
  40.                 return self._check_num_instances_quota(context, instance_type,min_count, allowed)  
  41.             else:  
  42.                 msg = (_("Can only run %s more instances of this type.") %  
  43.                        allowed)  
  44.   
  45.             resource = overs[0]  
  46.             used = quotas[resource] - headroom[resource]  
  47.             total_allowed = used + headroom[resource]  
  48.             overs = ','.join(overs)  
  49.   
  50.             pid = context.project_id  
  51.             LOG.warn(_("%(overs)s quota exceeded for %(pid)s,"  
  52.                        " tried to run %(min_count)s instances. %(msg)s"),locals())  
  53.             requested = dict(instances=min_count, cores=req_cores, ram=req_ram)  
  54.             raise exception.TooManyInstances(overs=overs,req=requested[resource],used=used, allowed=total_allowed,resource=resource)  
  55.   
  56.         return max_count, reservations  
复制代码

b.1 确定请求分配的内核数和RAM:
  1. req_cores = max_count * instance_type['vcpus']  
  2. req_ram = max_count * instance_type['memory_mb']  
复制代码

   注:instance_type示例:
    instance_type = {'memory_mb': 2048L, 'root_gb': 20L, 'deleted_at': None, 'name': u'm1.small', 'deleted': 0L, 'created_at': None, 'ephemeral_gb': 0L, 'updated_at': None, 'disabled': False, 'vcpus': 1L, 'extra_specs': {}, 'swap': 0L, 'rxtx_factor': 1.0, 'is_public': True, 'flavorid': u'2', 'vcpu_weight': None, 'id': 5L}
    b.2 语句reservations = QUOTAS.reserve(context, instances=max_count,cores=req_cores, ram=req_ram)分析:
    这条语句实现了对资源配额的检测、管理和分配,如果没有错误,则返回所建立的预定(分配)的资源的UUID的列表;这里调用了方法/nova/quota.py----def reserve(self, context, expire=None, project_id=None, **deltas):

  1. def reserve(self, context, expire=None, project_id=None, **deltas):  
  2.         """
  3.         检查配额并且分配存储资源;
  4.         如果没有错误,方法返回所建立的预定(分配)的资源的UUID的列表;
  5.         """  
  6.   
  7.         reservations = self._driver.reserve(context, self._resources, deltas,expire
复制代码

我们先来看方法_driver的定义:
  1. def _driver(self):  
  2.     if self.__driver:  
  3.         return self.__driver  
  4.     # quota_driver:这个参数定义了配额管理默认的驱动类;  
  5.     # 参数的默认值为'nova.quota.DbQuotaDriver';  
  6.     if not self._driver_cls:  
  7.         self._driver_cls = CONF.quota_driver  
  8.     if isinstance(self._driver_cls, basestring):  
  9.         self._driver_cls = importutils.import_object(self._driver_cls)  
  10.     self.__driver = self._driver_cls  
  11.     return self.__driver
复制代码

  可以看到返回的self.__driver值,默认为'nova.quota.DbQuotaDriver';所以上一个方法中调用的就是类nova.quota.DbQuotaDriver下的方法reserve----def reserve(self, context, resources, deltas, expire=None, project_id=None):
  1. def reserve(self, context, resources, deltas, expire=None, project_id=None):  
  2.         """
  3.         @@@@检测配额和储备资源;
  4.         """  
  5.   
  6.         # 如果expire没有指定,则采用默认参数的值;  
  7.         # reservation_expire:这个参数定义了预约(资源配额)的到期时间长度;  
  8.         # 参数的默认值为86400;  
  9.         if expire is None:  
  10.             expire = CONF.reservation_expire  
  11.         if isinstance(expire, (int, long)):  
  12.             expire = datetime.timedelta(seconds=expire)  
  13.         if isinstance(expire, datetime.timedelta):  
  14.             expire = timeutils.utcnow() + expire  
  15.         if not isinstance(expire, datetime.datetime):  
  16.             raise exception.InvalidReservationExpiration(expire=expire)  
  17.   
  18.         # 如果没有定义project_id,则应用context中的project_id值;  
  19.         if project_id is None:  
  20.             project_id = context.project_id  
  21.   
  22.         # 获取适用的配额信息;  
  23.         quotas = self._get_quotas(context, resources, deltas.keys(), has_sync=True, project_id=project_id)  
  24.   
  25.         return db.quota_reserve(context, resources, quotas, deltas, expire,  
  26.                                 CONF.until_refresh, CONF.max_age,  
  27.                                 project_id=project_id)  
复制代码

首先,为参数expire赋值,expire定义了备份(预约)(资源配额)的到期时间长度,这里把当前时间加上预约时间长度,得到的就是到期时间:
  1. if expire is None:  
  2.     expire = CONF.reservation_expire  
  3. if isinstance(expire, (int, long)):  
  4.     expire = datetime.timedelta(seconds=expire)  
  5. if isinstance(expire, datetime.timedelta):  
  6.     expire = timeutils.utcnow() + expire  
  7. if not isinstance(expire, datetime.datetime):  
  8.     raise exception.InvalidReservationExpiration(expire=expire)  
复制代码

可见,初始化方法中又调用了父类BaseResource的初始化方法,所以我们在看看其父类BaseResource:
  1. class BaseResource(object):  
  2.     """为配额检测定义一个资源类;"""  
  3.   
  4.     def __init__(self, name, flag=None):  
  5.         """
  6.         初始化这个类。
  7.         """  
  8.         self.name = name  
  9.         self.flag = flag  
复制代码

所以我们能看到,参数resources的定义中的语句ReservableResource('instances', _sync_instances, 'quota_instances')实现了:
    i. 初始化ReservableResource类,实例化这个类的对象;
    ii. name = 'instances';
        flag = 'quota_instances';
        sync = _sync_instances;
    我们注意一下这个方法_sync_instances,它作为一个参数传递赋值给sync;(当然这里并没有执行这个方法!)

本文,接着上一篇内容:OpenStack建立实例完整过程源码详细分析(5)


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

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

本版积分规则

关闭

推荐上一条 /2 下一条