OpenStack创建虚拟机代码分析过程

前言

本文暂不分析novaclient的认证部分,从nova-api开始。
认证部分会单独拿出来。
这一模块先叙述整个流程,再分析每个小点
代码为Rocky版本

nova-api

传入数据举例

req : 
Accept: application/json
Accept-Encoding: gzip, deflate
Connection: keep-alive
Content-Length: 357
Content-Type: application/json
Host: 10.0.17.18:8774
Openstack-Api-Version: compute 2.42
Openstack-System-Scope: None
User-Agent: python-novaclient
X-Auth-Token: gAAAAABd3JbKyiNmPMJtBcxrTTIvAQjwS7rWULZt1Q_W1lnL9Zzw_NRxmJL-H01oB8Rd2VXH85wvoBsqj7vmjtVTycnPm2SZpjmo_ecetQ3UvjF1YfCrSg_Fg5xhVeS3nyDmKrsahfa4sTKqwde-ODWFKcssvFx7DLmx974BtMnAK3EUStpsyGqr8pkiLhu7RZFmgA0edoZP
X-Identity-Status: Confirmed
X-Is-Admin-Project: True
X-Openstack-Nova-Api-Version: 2.42
X-Project-Domain-Id: ee7b71848f5546b4891e42555c34cc02
X-Project-Domain-Name: Default
X-Project-Id: 0658f0902f8e4c26a07fcfa6d4e4139
X-Project-Name: admin
X-Role: admin^M
X-Roles: admin
X-Service-Catalog: [{"endpoints": [{"adminURL": "http://10.0.17.18:8774/v2.1/0658f0902f8e4c26a07fcfa6d4e41392", "region": "RegionOne", "internalURL": "http://10.0.17.18:8774/v2.1/0658f0902f8e4c26a07fcfa6d4e41392", "publicURL": "http://10.0.17.18:8774/v2.1/0658f0902f8e4c26a07fcfa6d4e41392"}], "type": "compute", "name": "nova"}, {"endpoints": [{"adminURL": "http://10.0.17.18:9292", "region": "RegionOne", "internalURL": "http://10.0.17.18:9292", "publicURL": "http://10.0.17.18:9292"}], "type": "image", "name": "glance"}, {"endpoints": [{"adminURL": "http://10.0.17.18:8000/v1", "region": "RegionOne", "internalURL": "http://10.0.17.18:8000/v1", "publicURL": "http://10.0.17.18:8000/v1"}], "type": "cloudformation", "name": "heat-cfn"}, {"endpoints": [{"adminURL": "http://10.0.17.18:8004/v1/0658f0902f8e4c26a07fcfa6d4e41392", "region": "RegionOne", "internalURL": "http://10.0.17.18:8004/v1/0658f0902f8e4c26a07fcfa6d4e41392", "publicURL": "http://10.0.17.18:8004/v1/0658f0902f8e4c26a07fcfa6d4e41392"}], "type": "orchestration", "name": "heat"}, {"endpoints": [{"adminURL": "http://10.0.17.18:8778/placement", "region": "RegionOne", "internalURL": "http://10.0.17.18:8778/placement", "publicURL": "http://10.0.17.18:8778/placement"}], "type": "placement", "name": "placement"}, {"endpoints": [{"adminURL": "http://10.0.17.18:35357/v3", "region": "RegionOne", "internalURL": "http://10.0.17.18:5000/v3", "publicURL": "http://10.0.17.18:5000/v3"}], "type": "identity", "name": "keystone"}, {"endpoints": [{"adminURL": "http://10.0.17.18:9696", "region": "RegionOne", "internalURL": "http://10.0.17.18:9696", "publicURL": "http://10.0.17.18:9696"}], "type": "network", "name": "neutron"}]
X-Tenant: admin
X-Tenant-Id: 0658f0902f8e4c26a07fcfa6d4e41392
X-Tenant-Name: admin
X-User: admin
X-User-Domain-Id: ee7b71848f5546b4891e42555c34cc02
X-User-Domain-Name: Default
X-User-Id: 2811459285f0442cb61ffe2b2c7b6038
X-User-Name: admin

{"server": {"name": "vn1", "imageRef": "eecf21c3-2e01-4a70-bf41-7aec79d7ff04", "availability_zone": "nova", "flavorRef": "96610372-0609-40c5-b123-56b801c98931", "OS-DCF:diskConfig": "AUTO", "max_count": 1, "min_count": 1, "networks": [{"uuid": "8f1e7990-e727-426c-8bbd-d234c5de58db"}], "security_groups": [{"name": "ee9628b1-8445-445f-8eaf-de3ae65b7831"}]}}
body:
{u'server': {u'name': u'vn1', u'imageRef': u'eecf21c3-2e01-4a70-bf41-7aec79d7ff04', u'availability_zone': u'nova', u'flavorRef': u'96610372-0609-40c5-b123-56b801c98931', 
u'OS-DCF:diskConfig': u'AUTO', u'max_count': 1, u'min_count': 1, u'networks': [{u'uuid': u'8f1e7990-e727-426c-8bbd-d234c5de58db'}], u'security_groups': [{u'name': u'ee9628b1-8445-445f-8eaf-de3ae65b7831'}]}}
nova.api.openstack.compute.servers
class ServersController(wsgi.Controller):
    def create(self, req, body):
    	......(数据解析)
        (instances, resv_id) = self.compute_api.create(context,
                   inst_type,	# flavor详细信息
                   image_uuid,
                   display_name=name,
                   display_description=description,
                   availability_zone=availability_zone,
                   forced_host=host, forced_node=node,
                   metadata=server_dict.get('metadata', {}),
                   admin_password=password,
                   requested_networks=requested_networks,
                   check_server_group_quota=True,
                   supports_multiattach=supports_multiattach,
                   **create_kwargs)	
                   #{user_data, key_name(密钥对名称),安全组列表,
                   #scheduler hint,min_count, max_count
                   #return_reservation_id, auto_disk_config:AUTO,
                   #access_ip_v4 or access_ip_v6, injected_files(personality),
                   #trusted_certs(trusted_image_certificates), block_device_mapping, legacy_bdm}

nova_compute API

上文中self.computa_api;当nova配置中cell_type不是api时为nova.compute.api.API

nova.compute.api.API
def create():
	......
	#判断所选网络,可用域是否可用
	#生成filter_properties {u'ProcessorArchitecture': u'x86', u'InstructionSet': u'x86:64', 
	#'instance_type': flavor,'force_hosts': 可用域主机, 'force_nodes':可用域node}
    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_groups,
                   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,
                   filter_properties=filter_properties,
                   legacy_bdm=legacy_bdm,
                   shutdown_terminate=shutdown_terminate,
                   check_server_group_quota=check_server_group_quota,
                   tags=tags, supports_multiattach=supports_multiattach,
                   trusted_certs=trusted_certs)
def _create_instance(self, context, instance_type,***)
	......
	# 检查镜像,磁盘,安全组,block_device_mapping,
	self.compute_task_api.schedule_and_build_instances(context,
                build_requests=build_requests,***)
    return instances, reservation_id

conductor

nova.conductor.api.ComputeTaskAPI
def schedule_and_build_instances(self, context, build_requests,
                                 request_spec, image,
                                 admin_password, injected_files,
                                 requested_networks, block_device_mapping,
                                 tags=None):
    self.conductor_compute_rpcapi.schedule_and_build_instances(
        context, build_requests, request_spec, image,
        admin_password, injected_files, requested_networks,
        block_device_mapping, tags)
nova.conductor.rpcapi.ComputeTaskAPI
def schedule_and_build_instances(self, context, build_requests,
                                 request_specs,
                                 image, admin_password, injected_files,
                                 requested_networks,
                                 block_device_mapping,
                                 tags=None):
    version = '1.17'
    kw = {'build_requests': build_requests,
          'request_specs': request_specs,
          'image': jsonutils.to_primitive(image),
          'admin_password': admin_password,
          'injected_files': injected_files,
          'requested_networks': requested_networks,
          'block_device_mapping': block_device_mapping,
          'tags': tags}

    if not self.client.can_send_version(version):
        version = '1.16'
        del kw['tags']

    cctxt = self.client.prepare(version=version)
    cctxt.cast(context, 'schedule_and_build_instances', **kw)
    # 发cast请求
nova.conductor.manager.ComputeTaskManager
def schedule_and_build_instances(self, context, build_requests,
                                 request_specs, image,
                                 admin_password, injected_files,
                                 requested_networks, block_device_mapping,
                                 tags=None):
	# 获取主机列表等
	......
     with obj_target_cell(instance, cell) as cctxt:
        self.compute_rpcapi.build_and_run_instance(
            cctxt, instance=instance, image=image,
            request_spec=request_spec,
            filter_properties=filter_props,
            admin_password=admin_password,
            injected_files=injected_files,
            requested_networks=requested_networks,
            security_groups=legacy_secgroups,
            block_device_mapping=instance_bdms,
            host=host.service_host, node=host.nodename,
            limits=host.limits, host_list=host_list)

nova.compute.rpcapi.ComputeAPI
def build_and_run_instance(self, ctxt, instance, host, image, request_spec,
        filter_properties, admin_password=None, injected_files=None,
        requested_networks=None, security_groups=None,
        block_device_mapping=None, node=None, limits=None,
        host_list=None):
    # NOTE(edleafe): compute nodes can only use the dict form of limits.
    if isinstance(limits, objects.SchedulerLimits):
        limits = limits.to_dict()
    kwargs = {"instance": instance,
              "image": image,
              "request_spec": request_spec,
              "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,
              "node": node,
              "limits": limits,
              "host_list": host_list,
             }
    client = self.router.client(ctxt)
    version = '5.0'
    cctxt = client.prepare(server=host, version=version)
    cctxt.cast(ctxt, 'build_and_run_instance', **kwargs)
nova.compute.manager.ComputeManager
def build_and_run_instance(self, context, instance, image, request_spec,
                 filter_properties, admin_password=None,
                 injected_files=None, requested_networks=None,
                 security_groups=None, block_device_mapping=None,
                 node=None, limits=None, host_list=None):

    @utils.synchronized(instance.uuid)
    def _locked_do_build_and_run_instance(*args, **kwargs):
        with self._build_semaphore:
            try:
                result = self._do_build_and_run_instance(*args, **kwargs)
            except Exception:
                result = build_results.FAILED
                raise
            finally:
                if result == build_results.FAILED:
                    self._delete_allocation_for_instance(context,
                                                         instance.uuid)
                if result in (build_results.FAILED,
                              build_results.RESCHEDULED):
                    self._build_failed(node)
                else:
                    self._build_succeeded(node)

    utils.spawn_n(_locked_do_build_and_run_instance,
                  context, instance, image, request_spec,
                  filter_properties, admin_password, injected_files,
                  requested_networks, security_groups,
                  block_device_mapping, node, limits, host_list)

# 其中调用_do_build_and_run_instance
with timeutils.StopWatch() as timer:
    self._build_and_run_instance(context, instance, image,
            decoded_files, admin_password, requested_networks,
            security_groups, block_device_mapping, node, limits,
            filter_properties, request_spec)
LOG.info('Took %0.2f seconds to build instance.',
         timer.elapsed(), instance=instance)
return build_results.ACTIVE

#其中_build_and_run_instance
with timeutils.StopWatch() as timer:
    self.driver.spawn(context, instance, image_meta,
                      injected_files, admin_password,
                      allocs, network_info=network_info,
                      block_device_info=block_device_info)

其中self.driver调用driver(libvirt.LibvirtDriver)来处理

libvirt

# 调driver去实现
nova.virt.libvirt.driver.LibvirtDriver
def spawn(self, context, instance, image_meta, injected_files,
          admin_password, allocations, network_info=None,
          block_device_info=None):
    disk_info = blockinfo.get_disk_info(CONF.libvirt.virt_type,
                                        instance,
                                        image_meta,
                                        block_device_info)
    injection_info = InjectionInfo(network_info=network_info,
                                   files=injected_files,
                                   admin_pass=admin_password)
    gen_confdrive = functools.partial(self._create_configdrive,
                                      context, instance,
                                      injection_info)
    self._create_image(context, instance, disk_info['mapping'],
                       injection_info=injection_info,
                       block_device_info=block_device_info)

    # Required by Quobyte CI
    self._ensure_console_log_for_instance(instance)

    # Does the guest need to be assigned some vGPU mediated devices ?
    mdevs = self._allocate_mdevs(allocations)

    xml = self._get_guest_xml(context, instance, network_info,
                              disk_info, image_meta,
                              block_device_info=block_device_info,
                              mdevs=mdevs)
    self._create_domain_and_network(
        context, xml, instance, network_info,
        block_device_info=block_device_info,
        post_xml_callback=gen_confdrive,
        destroy_disks_on_failure=True)
    LOG.debug("Guest created on hypervisor", instance=instance)

    def _wait_for_boot():
        """Called at an interval until the VM is running."""
        state = self.get_info(instance).state

        if state == power_state.RUNNING:
            LOG.info("Instance spawned successfully.", instance=instance)
            raise loopingcall.LoopingCallDone()

    timer = loopingcall.FixedIntervalLoopingCall(_wait_for_boot)
    timer.start(interval=0.5).wait()

后记

代码全过程,由于较多,后续一一解读。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值