OpenStack之Nova分析——创建虚拟机(三)

来源:互联网 发布:ubuntu 安装gcc g 编辑:程序博客网 时间:2024/04/28 09:31

继续上篇文章谈到的get_project_quotas方法,进入这个方法。

def get_project_quotas(self, context, resources, project_id,                             quota_class=None, defaults=True,                             usages=True):          """        根据给定的资源项,对于给定的对象进行配额检索,返回配额限制值        """          quotas = {}            #对于一个给定的项目,检索它的所有的配额        #根据project_id查询数据库中相应项目的数据库信息,获取其中的hard_limit值,也就是获取规定的资源最大限额值        project_quotas = db.quota_get_all_by_project(context, project_id)                    #检索一个给定资源的当前的所有相关的使用情况        if usages:              project_usages = db.quota_usage_get_all_by_project(context,project_id)            #通过适当的类获取配额信息。如果project ID匹配context中的一个,那么使用context中的quota_class类,否则,使用所提供的quota_class类(如果有的话)          #选取合适的类,为后面做准备        if project_id == context.project_id:              quota_class = context.quota_class          if quota_class:              class_quotas = db.quota_class_get_all_by_name(context, quota_class)          else:              class_quotas = {}            for resource in resources.values():              # Omit default/quota class values              if not defaults and resource.name not in project_quotas:                  continue                quotas[resource.name] = dict(                  limit=project_quotas.get(resource.name, class_quotas.get(resource.name, resource.default)),                  )                # Include usages if desired.  This is optional because one              # internal consumer of this interface wants to access the              # usages directly from inside a transaction.              if usages:                  usage = project_usages.get(resource.name, {})                  quotas[resource.name].update(                      in_use=usage.get('in_use', 0),                      reserved=usage.get('reserved', 0),                      )            return quotas

a) project_quotas = db.quota_get_all_by_project(context, project_id)

这条语句主要实现的是根据project_id查询数据库,获取各种资源的限定值,这里的资源包括instances,ram,cores,以字典形式返回给project_usages。这个方法就不展开了。

b) project_usages = db.quota_usage_get_all_by_project(context,project_id)

这条语句和上条类似,这里也会根据project_id查询数据库,获取各种资源的限定值,只是这里获取到的还包括了in_use和reserved。同样以字典形式返回给project_usages,这个方法也不展开了。

c) class_quotas = db.quota_class_get_all_by_name

这里的quota_class_get_all_by_name和之前分析的两个方法是类似的,只不过之前两个方法是根据project_id来查询数据库,而这里是根据quota_class来查询QuotaClass类。

分析完上面的三个主要的方法,接下来的代码实现的就是从字典project_quotas/project_usages中,为资源instance、ram、cores读取limit的值。得到的结果是如下的形式。

resource.name = instances  limit:10  resource.name = ram  limit:51200  resource.name = cores  limit:20

至此,我们分析完了get_project_quotas方法,下面回到_get_quotas方法。

def _get_quotas(self, context, resources, keys, has_sync, project_id=None):    ...    #获取并返回磁盘配额    quotas = self.get_project_quotas(context, sub_resources,project_id,context.quota_class, usages=False)    return dict((k, v['limit']) for k, v in quotas.items())
可以看到获取到quotas后,返回的各项(instance、ram、cores)的限额。然后再回到reserve方法。

def reserve(self, context, resources, deltas, expire=None, project_id=None):    ...    quotas = self._get_quotas(context, resources, deltas.keys(),                              has_sync=True, project_id=project_id)    return db.quota_reserve(context, resources, quotas, deltas, expire,                            CONF.until_refresh, CONF.max_age,                            project_id=project_id)
执行完_get_quotas语句后,得到的quotas的结果类似这样:quotas = {instances:10, ram:51200, cores:20}。来看db.quota_reserve方法,这个方法主要完成的是对资源进行配额检测和更新数据库的操作,这里就不展开了。

到这里reserve方法就分析完成了,这个方法分析完后,上文中的_check_num_instances_quota方法也就分析完成了,回顾一下,这个方法主要实现的是资源配额管理,根据配额限制确定所要创建的实例数目,并获取分配好的资源(块存储)uuid的列表。

继续上文,我们回到_validate_and_provision_instance方法。

class API(base.Base):      def _validate_and_provision_instance(self,context,instance_type,                                           ...):          #一些参数的验证和初始化          if not metadata:              metadata = {}          if not security_group:              security_group = 'default'          ...          #如果客户端没有指定虚拟机规格,则使用默认的格式          if not instance_type:              instance_type = instance_type.get_default_instance_type()          ...          #根据配额资源限制计算所要建立实例的数目,并获取了分配好的资源(块存储)的UUID的列表          num_instances, quota_reservations = self._check_num_instances_quota(                  context, instance_type,...)          try:              instances = []              instance_uuids = []              #检查metadata项数是否超标              self._check_metadata_properties_quota(context, metadata)              #检查注入文件的个数和大小是否超标              self._check_injected_file_quota(context, injected_files)              #检查需求网络是否合法              self._check_requested_networks(context, requested_networks)              #获取、检查虚拟机镜像文件              if image_href:                  #获取虚拟机镜像文件的uuid                  (image_service, image_id) = glance.get_remote_image_service(context,                                                                      image_href)                  #获取虚拟机镜像文件信息                  image = image_service.show(context, image_id)                  #检查镜像是否可用                  if image['status'] != 'active':                      raise exception.ImageNotActive(image_id=image_id)              else:                  image = {}              #检查虚拟机内存是否足够大              if instance_type['memory_mb'] < int(image.get('min_ram') or 0):                  raise exception.InstanceTypeMemoryTooSmall()              #检查虚拟机磁盘是否足够大              if instance_type['root_gb'] < int(image.get('min_disk') or 0):                  raise exception.InstanceTypeDiskTooSmall()              ...              #用于创建数据库的记录              base_options = {                  'reservation_id': reservation_id,                  ...}              #获取镜像中指定的参数              options_from_image = self._inherit_properties_from_image(                  image, auto_disk_config)              #将镜像中的参数合并至base_options              base_options.update(options_from_image)              ...            for i in xrange(num_instances):                options = base_options.copy()                #在数据库中创建虚拟机记录                instance = self.create_db_entry_for_new_instance(context,                                                                 instance_type,                                                                 image,                                                                 options,                                                                 ...)                #保存创建的虚拟机列表                instances.append(instance)                instance_uuids.append(instance['uuid'])                #通知Nova API,虚拟机当前状态为BUILDING                notification.send_update_with_states(context,instance,...)        expect Exception:            ...        #修改租户的QUOTAS,为虚拟机预留硬件资源        QUOTAS.commit(context,quota_reservations)        ...        return (instances,request_spec,filter_properties)
刚刚分析完了:(1) _check_num_instances_quota,来继续分析一下

(2)(image_service, image_id) = glance.get_remote_image_service(context,image_href)
      image = image_service.show(context,image_id)

这段代码的作用是通过glanceclient获取镜像文件信息。简单的介绍一下glanceclient这个东东吧。前面已经介绍过,在openstack中,不同组件之间的通信是通过RESTful API完成的,openstack的处理方式是为每个组件都包含了这样一个client,它们都继承于HTTPClient这个基类,但做了一些个性化的封装,用于向各自的组件发送HTTP请求。具体到这里,nova需要和glace通信,以获取镜像文件的信息,所以需要声明了这样一个glanceclient。代码glance.get_remote_image_service(context,image_href)的作用就是创建一个glaceclient对象,然后把这个对象封装入GlanceImageService类里,即返回值image_service。然后调用该类下的show方法来获取镜像文件的信息。

这个方法后续的工作就是各种检测以及与数据库的交互过程,来完成实例的创建前的一些准备工作~~

至此,_validate_and_provision_instance方法也分析完了,回顾一下,这个方法实现的主要功能就是创建实例前的一些准备工作。后面文章我们继续分析后续的代码。

0 0