首页 > 电脑

简述虚拟机实例的孵化过程。

更新时间2018-11-21 09:05:56

1、nova-api  <文件位于/nova/api/openstackcompute/server.py>

 

      nova-api起到了一个Cloud Controller的作用,主要为所有的API查询提供了一个接口(比如Openstack API ,EC2 API),引发多数业务流程的活动(如运行一个实例),并实施一些政策(主要是配额检查)。

 

      因为今天我们主题是虚拟机实例的启动过程,所以,重点关注/nova/api/openstackcompute/server.py。找到类class Controller(wsgi.Controller):create()代码段,我们知道nova-api的作用就是对外提供标准REST接口的服务。下面的代码段,已经标注了很多内容,大家看一下即可。

 

#对外提供创建虚拟机实例的外部接口,nova-api.create()

#其中req是整个http报文内容,body就是REST中传递过来的参数

#整个方法的作用是将REST接口参数映射到内部接口compute-api.create()

#比如非常重要的环节,将image-flavor的id转换成虚拟机具体配置信息instanc_type

    def create(self, req, body):

        """Creates a new server for a given user."""

        if not self.is_valid_body(body, 'server'):

            raise exc.HTTPUnprocessableEntity()

 

#A mapping object representing the string environment. 

#For example, environ['HOME'] is the pathname of your 

#home directory (on some platforms), and is equivalent to getenv("HOME") in C

 

#对下面两个参数的讨论,设计到webob等概念,需要在以后做专门的讲述

#*****************经常会用到的两个参数***************

context = req.environ['nova.context']

        server_dict = body['server']

#*****************经常会用到的两个参数***************

 

nova-api的create方法作用是将REST接口参数映射到内部接口compute-api.create(),参数转换完成后,create最后会调用如下代码,转去调用comput-api

 (instances, resv_id) = self.compute_api.create(context,

                            inst_type,  ###*****已经转换的flavor

                            image_uuid,

                            display_name=name,

                            display_description=name,

                            key_name=key_name,

                            metadata=server_dict.get('metadata', {}),

                            access_ip_v4=access_ip_v4,

                            access_ip_v6=access_ip_v6,

                            injected_files=injected_files,

                            admin_password=password,

                            min_count=min_count,

                            max_count=max_count,

                            requested_networks=requested_networks,

                            security_group=sg_names,

                            user_data=user_data,

                            availability_zone=availability_zone,

                            config_drive=config_drive,

                            block_device_mapping=block_device_mapping,

                            auto_disk_config=auto_disk_config,

                            scheduler_hints=scheduler_hints,

                            legacy_bdm=legacy_bdm)

 

2、compute-api 的处理过程

 

       compute-api的作用是对外提供了管理compute的api接口,外部模块通过这些接口完成对计算资源的操作。

 

#*********************************#compute-api下面的create()函数*******************************#

    @hooks.add_hook("create_instance")

    def create(self, context, instance_type,     #由/nova/api/compute/service.py的套餐id转换到这个type

               image_href, kernel_id=None, ramdisk_id=None,

               min_count=None, max_count=None,

               display_name=None, display_description=None,

               key_name=None, key_data=None, security_group=None,

               availability_zone=None, user_data=None, metadata=None,

               injected_files=None, admin_password=None,

               block_device_mapping=None, access_ip_v4=None,

               access_ip_v6=None, requested_networks=None, config_drive=None,

               auto_disk_config=None, scheduler_hints=None, legacy_bdm=True):

        """

        Provision instances, sending instance information to the

        scheduler.  The scheduler will determine where the instance(s)

        go and will handle creating the DB entries.

 

Returns a tuple of (instances, reservation_id)

        """

#policy是nova中一个资格验证机制

        self._check_create_policies(context, availability_zone,

                requested_networks, block_device_mapping)

#创建一个实例的函数,

        return self._create_instance(

                               context, instance_type,

                               image_href, kernel_id, ramdisk_id,

                               min_count, max_count,

                               display_name, display_description,

                               key_name, key_data, security_group,

                               availability_zone, user_data, metadata,

                               injected_files, admin_password,

                               access_ip_v4, access_ip_v6,

                               requested_networks, config_drive,

                               block_device_mapping, auto_disk_config,

                               scheduler_hints=scheduler_hints,

                               legacy_bdm=legacy_bdm)

 

我们看下上面的代码:a) 首先进行了能否创建实例的资格验证  b)再调用了_create_instance()方法

 

3、在_create_instance()方法中,做的一些操作有,验证各种参数,如意套餐类型instance_type是否存在,租户配额限制检查等,没问题后,commit一下,确定资源的占用。为了简化问题,我大概描述一下该方法做的事,具体小伙伴们看一下代码就知道了。

 

完成上面的操作后,在_create_instance() 最后调用了 self.compute_task_api.build_instances(context,***)方法。

 

4、我们通过寻找compute_task_api,找到了这个其实conductor.ComputeTaskAPI()的一个对象。

 

注:关于conductor的话,我们单独还会再讲,G版中开始添加了这个conductor,以前的版本是没有这个东西的。主要作用是隔离compute对数据库的直接操作。

 

我们转到/nova/conductor/api.py文件下

 

#创建实例的调用

    def build_instances(self, context, instances, image, filter_properties,

            admin_password, injected_files, requested_networks,

            security_groups, block_device_mapping, legacy_bdm=True):

        self.conductor_compute_rpcapi.build_instances(context,

                instances=instances, image=image,

                filter_properties=filter_properties,

                admin_password=admin_password, injected_files=injected_files,

                requested_networks=requested_networks,

                security_groups=security_groups,

                block_device_mapping=block_device_mapping,

                legacy_bdm=legacy_bdm)

 

通过上述代码,我们看到,compute调用了conductor的API接口,再调用了conductor的RpcAPi接口,转到/nova/conductor/rpcapi.py看如下代码:

#创建虚拟机实例

    def build_instances(self, context, instances, image, filter_properties,

            admin_password, injected_files, requested_networks,

            security_groups, block_device_mapping, legacy_bdm=True):

        instances_p = [jsonutils.to_primitive(inst) for inst in instances]

        image_p = jsonutils.to_primitive(image)

 

        cctxt = self.client.prepare(version='1.5')

 

cctxt.cast(context, 'build_instances',

                   instances=instances_p, image=image_p,

                   filter_properties=filter_properties,

                   admin_password=admin_password,

                   injected_files=injected_files,

                   requested_networks=requested_networks,

                   security_groups=security_groups,

                   block_device_mapping=block_device_mapping,

                   legacy_bdm=legacy_bdm)

 

哈哈,看到了吧,上面的调用给conductor发送了一个rpc消息。根据OpenStack AMQP的rpc消息传递的原理,我们很顺理成章的转到/nova/conductor/manager.py去查看是否在manager.py里面会有"build_instance"方法。找了下,果然有,请看如下代码:

def build_instances(self, context, instances, image, filter_properties,

            admin_password, injected_files, requested_networks,

            security_groups, block_device_mapping, legacy_bdm=True):

 

request_spec = scheduler_utils.build_request_spec(context, image,

                                                          instances)    

        request_spec.update({'block_device_mapping': block_device_mapping,

                             'security_group': security_groups})

 

        self.scheduler_rpcapi.run_instance(context, request_spec=request_spec,

                admin_password=admin_password, injected_files=injected_files,

                requested_networks=requested_networks, is_first_time=True,

                filter_properties=filter_properties,

                legacy_bdm_in_spec=legacy_bdm)

 

看到最后一行,self.scheduler_rpcapi.run_instance(context,***)方法,conductor通过调用Scheduler的rpcapi接口,把请求启动虚拟机的相关信息传递到调度器上。就是从这里开始,相关的工作就被转移到了Scheduler中了(关于具体怎么调度的,会有专门的博文,讲述这个过程,今天只关注,虚拟机实例请求是怎么一步一步建立的)

 

5、再次转到/nova/scheduler/目录

 

(1)首先看/nova/shceduler/rpcapi.py

 

 def run_instance(self, ctxt, request_spec, admin_password,

            injected_files, requested_networks, is_first_time,

            filter_properties, legacy_bdm_in_spec=True):

        version = '2.0'

 

#制作成msg_kwargs的参数

#消息参数(用户请求,过滤属性等等)

        msg_kwargs = {'request_spec': request_spec,

                      'admin_password': admin_password,

                      'injected_files': injected_files,

                      'requested_networks': requested_networks,

                      'is_first_time': is_first_time,

                      'filter_properties': filter_properties}

 

        if self.client.can_send_version('2.9'):

            version = '2.9'

            msg_kwargs['legacy_bdm_in_spec'] = legacy_bdm_in_spec

        cctxt = self.client.prepare(version=version)

 

        return cctxt.cast(ctxt, 'run_instance', **msg_kwargs)

 

继续看到最后一句,Scheduler-rpcpai把消息发送到了Scheduler的manager去处理具体的run_instance()方法。


上一篇:STM32单片机CAN芯片炸了,单片机还能用吗

下一篇:beatsstudio3wireless需要保养吗