Nova API服务 之 创建虚拟机流程(1)

本小节,将以虚拟机创建请求为例,分析底层Controller类的HTTP请求处理方法。

一、回忆总结

1、处理HTTP请求的核心工作都在底层Controller对象中定义。Resource对象在底层Controller对象的基础上,实现

据的转化工作。

2、Resource对象首相将传入的对象反序列化。然后将数据交给底层Controller对象中相应的处理方法处理。最后将

Controller对象处理方法返回的结果序列化。

二、创建虚拟机流程

1、以创建虚拟机请求为例,分析底层controller对象的定义。底层controller类中,处理虚拟机创建请求的方法是

create方法。

2、servers.Controller类的create方法

每个资源都对应一个底层的Controller类。servers资源的底层Controller类定义在servers包中。处理虚拟机创建

求的方法为create方法。定义如下:

class Controller(wsgi.Controller):

    _view_builder_class = views_servers.ViewBuilder
	@wsgi.response(202)
	@wsgi.serialozers(xml=FullServerTemplate
	@wsgi.deserialozers(xml=CreateDeserializer)
    def create(self, req, body):
        #为给定的用户创建新的虚拟机  检查HTTP消息体是否合法
        if not self.is_valid_body(body, 'server'):
            raise exc.HTTPUnprocessableEntity()
		#获取客户端传入的虚拟机参数
        context = req.environ['nova.context']
        server_dict = body['server']
		
        ...
		#获取和检查虚拟机名
        name = server_dict['name']
        self._validate_server_name(name)
        name = name.strip()
		#获取虚拟机的磁盘镜像uuid
        image_uuid = self._image_from_req_data(body)

        ....
		
		# 获取客户端需求的网络
        requested_networks = self._determine_requested_networks(server_dict)
		#获取和验证客户端指定的虚拟机IP
        (access_ip_v4, ) = server_dict.get('accessIPv4'),
        if access_ip_v4 is not None:
            self._validate_access_ipv4(access_ip_v4)

        (access_ip_v6, ) = server_dict.get('accessIPv6'),
        if access_ip_v6 is not None:
            self._validate_access_ipv6(access_ip_v6)
		#获取虚拟机规格ID
        flavor_id = self._flavor_id_from_req_data(body)

        # optional openstack extensions:
        key_name = self._extract(server_dict, 'os-keypairs', 'key_name')
        availability_zone = self._extract(server_dict, 'os-availability-zone',
                                          'availability_zone')
        user_data = self._extract(server_dict, 'os-user-data', 'user_data')
        self._validate_user_data(user_data)

        image_uuid_specified = bool(image_uuid)
        legacy_bdm, block_device_mapping = self._extract_bdm(server_dict,
            image_uuid_specified)

        ret_resv_id = False
        # min_count and max_count are optional.  If they exist, they may come
        # in as strings.  Verify that they are valid integers and > 0.
        # Also, we want to default 'min_count' to 1, and default
        # 'max_count' to be 'min_count'.
        min_count = 1
        max_count = 1
        if self.ext_mgr.is_loaded('os-multiple-create'):
            ret_resv_id = server_dict.get('return_reservation_id', False)
            min_count = server_dict.get('min_count', 1)
            max_count = server_dict.get('max_count', min_count)

        try:
            min_count = utils.validate_integer(
                min_count, "min_count", min_value=1)
            max_count = utils.validate_integer(
                max_count, "max_count", min_value=1)
        except exception.InvalidInput as e:
            raise exc.HTTPBadRequest(explanation=e.format_message())

        if min_count > max_count:
            msg = _('min_count must be <= max_count')
            raise exc.HTTPBadRequest(explanation=msg)

        auto_disk_config = False
        if self.ext_mgr.is_loaded('OS-DCF'):
            auto_disk_config = server_dict.get('auto_disk_config')

        scheduler_hints = {}
        if self.ext_mgr.is_loaded('OS-SCH-HNT'):
            scheduler_hints = server_dict.get('scheduler_hints', {})

        check_server_group_quota = self.ext_mgr.is_loaded(
                'os-server-group-quotas')
        try:
            #获取虚拟机规格信息
			_get_inst_type = flavors.get_flavor_by_flavor_id
            inst_type = _get_inst_type(flavor_id, ctxt=context,
                                       read_deleted="no")
			#调用compute API创建虚拟机
            (instances, resv_id) = self.compute_api.create(context,
                        ...)
        ...
        except UnicodeDecodeError as error:
        ...
		#将虚拟机信息转化为字典
        server = self._view_builder.create(req, instances[0])

        if CONF.enable_instance_password:
            server['server']['adminPass'] = password
		#将虚拟机信息封装成ResponseObject对象
        robj = wsgi.ResponseObject(server)
		#添加访问当前虚拟机资源的url
        return self._add_location(robj)
	
(1)、这个类继承自wsgi.Controller,该类位于nova/nova/api/openstack/wsgi.py。首先为create方法 指定了序列

化对象、反序列化对象和默认的HTTP Code。接着我们进入create方法,来分析代码。

先来看看context = req.eviron['nova.context']究竟拿到了什么信息,这个上下文信息对象是由类

nova.context.RequestContext实例化而来。我们来把获取到的context打印出来,这样方便大家理解。

user_id = afc380206e2549ad930396d9050d20cf  
project_id = 0e492e86f22e4d19bd523f1e7ca64566  
roles = [u'admin', u'KeystoneAdmin', u'KeystoneServiceAdmin']  
read_deleted = no  
remote_address = 172.21.6.145  
timestamp = 2013-06-23 16:36:37.399405  
request_id = req-f0255b14-833d-4fff-b973-23c35f70ddda  
auth_token = 7e7bb3cf84ab43269010bb55410064b3  
service_catalog = [{u'endpoints': [{u'adminURL': u'http://172.21.5.161:8776/v1/0e492e86f22e4d19bd523f1e7ca64566', 
                    u'region': u'RegionOne', u'id': u'753a1ad55e91469794e2eb7ac4c3df92',
                    u'internalURL': u'http://172.21.5.161:8776/v1/0e492e86f22e4d19bd523f1e7ca64566',
                    u'publicURL': u'http://172.21.6.145:8776/v1/0e492e86f22e4d19bd523f1e7ca64566'}],
                    u'endpoints_links': [], u'type': u'volume', u'name': u'cinder'}]  
instance_lock_checked = False  
quota_class = None  
user_name = admin  
project_name = admin  
is_admin = True

(2) is_valid_body方法

该方法检查客户端传入的消息体是否合法,这个方法位于Controller类的基类wsgi.Controller中。is_valid_body方

法首先检查消息体中是否含有server字段,然后检查server字段的内容是否为字典。

Nova中,所有的消息(包括客户端传给Nova API服务器的消息,以及服务器返回给客户端的消息)都是以资源名作为

键值的{key:value}对。

接下来的一系列方法都是获取并验证客户端传入的虚拟机参数。其中,server_dict保存了虚拟机参数,包括虚拟机

名、镜像uuid、需要的网络、固定ip、虚拟机规格等等。

(3) _validate_server_name方法

  该方法检查虚拟机名的长度是否越界。

(4) _validate_access_ipv4&_validate_access_ipv6方法

  该方法验证传入的固定ip格式是否合法。

(5) _favor_id_from_req_data方法

该方法对HTTP请求中包含的虚拟机规格id进行过滤解析。所谓规格id就是url包含的id或者uuid的值,如

http://www.foo.com/bar/123?q=4,该方法则返回123。

(6) get_instance_type_get_by_flavor_id方法

该方法位于nova/nova/compute/instance_types.py中,该方法调用了nova/nova/db/api.py下的

instance_type_get_by_flavor_id方法,其功能是根据虚拟机规格id,从数据库中查找对应规格信息后返回。

(7) 调用Nova Compute的API处理虚拟机创建请求。 

  __init__方法:self.compute_api = compute.API()

 Compute API的create方法会返回一个创建虚拟机信息列表。列表中的每个元素都是数据库Model对象。数据库

Model对象是Nova与数据库交互的数据格式,不可序列化。

为了便于显示以及序列化,self._view_builder.create对象的create方法将Model对象的数据转换为字典。

(8) Nova中,每个底层的Controller对象的_view_builder对象类型都是由_view_builder_class类成员变量指定。

对于server资源的底层Controller对象,其_view_builder_class类成员变量的值为views_servers.ViewBuilder:

_view_builder_class = views_servers.ViewBuilder. 

class ViewBuilder(common.ViewBuilder):
    def create(self, request, instance):
        """View that should be returned when an instance is created."""
        return {
            "server": {
                "id": instance["uuid"],
                "links": self._get_links(request,
                                         instance["uuid"],
                                         self._collection_name),
            },
        }

create方法返回的是一个关键字为 server的键值对。返回结果中,包含了虚拟机的uuid,以及虚拟机的url链接。

三、总结:

Nova API中底层Controller对象定义的HTTP请求的处理方法的小结。

1、检查客户端传入的参数是否合法有效

2、调用nova其他子服务的API处理客户端的HTTP请求。

3、将Nova其他子服务的API返回结果转化为可视化的字典。(反序列化)

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值