站点图标 起风网

Icehouse 创建Instance代码分析

1. nova-api接收到request

在/etc/nova/api-paste.ini中,是这样配置nova v2的

[app:osapi_compute_app_v2]
paste.app_factory = nova.api.openstack.compute:APIRouter.factory

在/usr/lib/python2.7/dist-packages/nova/api/openstack/compute/__init__.py中

class APIRouter(nova.api.openstack.APIRouter):中的

from nova.api.openstack.compute import servers
def _setup_routes(self, mapper, ext_mgr, init_only):
    ……
    self.resources[‘servers’] = servers.create_resource(ext_mgr)
    mapper.resource("server", "servers",
                controller=self.resources[‘servers’],
                collection={‘detail’: ‘GET’},
                member={‘action’: ‘POST’})

    ……

对于发送给/servers的POST的请求,是发给controller的。

在/usr/lib/python2.7/dist-packages/nova/api/openstack/compute/servers.py中有下面的函数

def create_resource(ext_mgr):
    return wsgi.Resource(Controller(ext_mgr))

class Controller(wsgi.Controller):
    @wsgi.response(202)
    @wsgi.serializers(xml=FullServerTemplate)
    @wsgi.deserializers(xml=CreateDeserializer)
    def create(self, req, body):
        ……

接收到的request的格式如下:

{"server": {"name": "world", "imageRef": "6a1489cb-5905-4f97-ae8b-012770818213", "availability_zone": "nova", "key_name": "153key", "flavorRef": "2", "OS-DCF:diskConfig": "AUTO", "max_count": 1, "min_count": 1, "networks": [{"uuid": "a29561e9-2f32-4765-a0f8-306b870f780b"}], "security_groups": [{"name": "default"}]}}

然后开始解析这个request,得到

最终调用

(instances, resv_id) = self.compute_api.create(context,
                inst_type,
                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)

这一调用调用到/usr/lib/python2.7/dist-packages/nova/compute/api.py中

class API(base.Base):

@hooks.add_hook("create_instance")
    def create(self, context, instance_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):
         ……
         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)

API的_create_instance的函数

def _create_instance(self, 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,
           reservation_id=None, scheduler_hints=None,
           legacy_bdm=True):

/usr/lib/python2.7/dist-packages/nova/conductor/api.py中

class ComputeTaskAPI(object):
    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)

conductor_compute_rpcapi指向nova.conductor.rpcapi.ComputeTaskAPI()

def build_instances(self, context, instances, image, filter_properties,
        admin_password, injected_files, requested_networks,
        security_groups, block_device_mapping, legacy_bdm=True):
    image_p = jsonutils.to_primitive(image)
    cctxt = self.client.prepare(version=’1.5′)
    cctxt.cast(context, ‘build_instances’,
               instances=instances, 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)

这是一个RPC调用,最终能够调用到/usr/lib/python2.7/dist-packages/nova/conductor/manager.py的class ConductorManager(manager.Manager)

2. nova-conductor

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)
    # NOTE(alaski): For compatibility until a new scheduler method is used.
    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)

它调用/usr/lib/python2.7/dist-packages/nova/scheduler/rpcapi.py中class SchedulerAPI(object):

def run_instance(self, ctxt, request_spec, admin_password,
        injected_files, requested_networks, is_first_time,
        filter_properties, legacy_bdm_in_spec=True):
    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,
                  ‘legacy_bdm_in_spec’: legacy_bdm_in_spec}
    cctxt = self.client.prepare()
    cctxt.cast(ctxt, ‘run_instance’, **msg_kwargs)

这是一个RPC调用,最终调用到/usr/lib/python2.7/dist-packages/nova/scheduler/manager.py的class SchedulerManager(manager.Manager):

3. nova-scheduler

def run_instance(self, context, request_spec, admin_password,
        injected_files, requested_networks, is_first_time,
        filter_properties, legacy_bdm_in_spec=True):
    return self.driver.schedule_run_instance(context,
        request_spec, admin_password, injected_files,
        requested_networks, is_first_time, filter_properties,
        legacy_bdm_in_spec)

scheduler的driver我们在nova.conf中配置如下:

#scheduler
compute_scheduler_driver=nova.scheduler.filter_scheduler.FilterScheduler

/usr/lib/python2.7/dist-packages/nova/scheduler/filter_scheduler.py的class FilterScheduler(driver.Scheduler):

def schedule_run_instance(self, context, request_spec,
                          admin_password, injected_files,
                          requested_networks, is_first_time,
                          filter_properties, legacy_bdm_in_spec):

_provision_resource调用

self.compute_rpcapi.run_instance(context,
        instance=updated_instance,
        host=weighed_host.obj.host,
        request_spec=request_spec,
        filter_properties=filter_properties,
        requested_networks=requested_networks,
        injected_files=injected_files,
        admin_password=admin_password, is_first_time=is_first_time,
        node=weighed_host.obj.nodename,
        legacy_bdm_in_spec=legacy_bdm_in_spec)

调用/usr/lib/python2.7/dist-packages/nova/compute/rpcapi.py的class ComputeAPI(object):

def run_instance(self, ctxt, instance, host, request_spec,
                 filter_properties, requested_networks,
                 injected_files, admin_password,
                 is_first_time, node=None, legacy_bdm_in_spec=True):
    # NOTE(russellb) Havana compat
    version = self._get_compat_version(‘3.0’, ‘2.37’)
    instance_p = jsonutils.to_primitive(instance)
    msg_kwargs = {‘instance’: instance_p, ‘request_spec’: request_spec,
                  ‘filter_properties’: filter_properties,
                  ‘requested_networks’: requested_networks,
                  ‘injected_files’: injected_files,
                  ‘admin_password’: admin_password,
                  ‘is_first_time’: is_first_time, ‘node’: node,
                  ‘legacy_bdm_in_spec’: legacy_bdm_in_spec}

    cctxt = self.client.prepare(server=host, version=version)
    cctxt.cast(ctxt, ‘run_instance’, **msg_kwargs)

这是一个RPC调用,最终调用/usr/lib/python2.7/dist-packages/nova/compute/manager.py的class ComputeManager(manager.Manager)

4. nova-compute

def run_instance(self, context, instance, request_spec,
                 filter_properties, requested_networks,
                 injected_files, admin_password,
                 is_first_time, node, legacy_bdm_in_spec):
    self._run_instance(context, request_spec,
        filter_properties, requested_networks, injected_files,
        admin_password, is_first_time, node, instance,
        legacy_bdm_in_spec)

def _run_instance(self, context, request_spec,
                  filter_properties, requested_networks, injected_files,
                  admin_password, is_first_time, node, instance,
                  legacy_bdm_in_spec):
    instance, network_info = self._build_instance(context,
        request_spec, filter_properties, requested_networks,
        injected_files, admin_password, is_first_time, node,
        instance, image_meta, legacy_bdm_in_spec)

 

4.1. 配置network

_allocate_network中,状态变成Networking

instance = self._instance_update(context, instance[‘uuid’],
                                 vm_state=vm_states.BUILDING,
                                 task_state=task_states.NETWORKING,
                                 expected_task_state=[None])

return nova.network.model.NetworkInfoAsyncWrapper(
        self._allocate_network_async, context, instance,
        requested_networks, macs, security_groups, is_vpn,
        dhcp_options)

def _allocate_network_async(self, context, instance, requested_networks,
                            macs, security_groups, is_vpn, dhcp_options):
    nwinfo = self.network_api.allocate_for_instance(
        context, instance, vpn=is_vpn,
        requested_networks=requested_networks,
        macs=macs,
        security_groups=security_groups,
        dhcp_options=dhcp_options)

调用network_api,调用neutron来创建network,nova.network.neutronv2.api.API

调用/usr/lib/python2.7/dist-packages/nova/network/neutronv2/api.py的allocate_for_instance函数

4.2. _spawn instances

/usr/lib/python2.7/dist-packages/nova/compute/manager.py的

def _spawn(self, context, instance, image_meta, network_info,
           block_device_info, injected_files, admin_password,
           set_access_ip=False):
    self.driver.spawn(context, instance, image_meta,
                  injected_files, admin_password,
                  network_info,
                  block_device_info)

在nova.conf中compute_driver=libvirt.LibvirtDriver

所以会最终调用/usr/lib/python2.7/dist-packages/nova/virt/libvirt/driver.py

5. libvirt

/usr/lib/python2.7/dist-packages/nova/virt/libvirt/driver.py的class LibvirtDriver(driver.ComputeDriver):

def spawn(self, context, instance, image_meta, injected_files,
          admin_password, network_info=None, block_device_info=None):

5.1. 获取Image

/usr/lib/python2.7/dist-packages/nova/virt/libvirt/driver.py的

def _create_image(self, context, instance,
                  disk_mapping, suffix=”,
                  disk_images=None, network_info=None,
                  block_device_info=None, files=None,
                  admin_pass=None, inject_files=True):

在这个函数中参数

(Pdb) p disk_images
{‘kernel_id’: u”, ‘image_id’: u’6a1489cb-5905-4f97-ae8b-012770818213′, ‘ramdisk_id’: u”}

得到flavor

inst_type = flavors.extract_flavor(instance)

(Pdb) p inst_type
{‘root_gb’: 20, ‘name’: ‘m1.small’, ‘ephemeral_gb’: 0, ‘memory_mb’: 2048, ‘vcpus’: 1, ‘swap’: 0, ‘rxtx_factor’: 1.0, ‘flavorid’: ‘2’, ‘vcpu_weight’: None, ‘id’: 5}

下载和缓存image

image(‘disk’).cache(fetch_func=libvirt_utils.fetch_image,
                    context=context,
                    filename=root_fname,
                    size=size,
                    image_id=disk_images[‘image_id’],
                    user_id=instance[‘user_id’],
                    project_id=instance[‘project_id’])

配置configuration drive

inst_md = instance_metadata.InstanceMetadata(instance, content=files, extra_md=extra_md, network_info=network_info)

with configdrive.ConfigDriveBuilder(instance_md=inst_md) as cdb:
    configdrive_path = self._get_disk_config_path(instance)
    cdb.make_drive(configdrive_path)

配置injection file

self._inject_data(instance, network_info, admin_pass, files, suffix)

5.2. 生成XML

to_xml xml=<domain type="kvm">
  <uuid>33985948-f19d-4d01-be63-989f302c218e</uuid>
  <name>instance-0000001a</name>
  <memory>2097152</memory>
  <vcpu>1</vcpu>
  <sysinfo type="smbios">
    <system>
      <entry name="manufacturer">OpenStack Foundation</entry>
      <entry name="product">OpenStack Nova</entry>
      <entry name="version">2014.1</entry>
      <entry name="serial">21172311-7f0c-44b5-b57c-48e5cc032d12</entry>
      <entry name="uuid">33985948-f19d-4d01-be63-989f302c218e</entry>
    </system>
  </sysinfo>
  <os>
    <type>hvm</type>
    <boot dev="hd"/>
    <smbios mode="sysinfo"/>
  </os>
  <features>
    <acpi/>
    <apic/>
  </features>
  <clock offset="utc">
    <timer name="pit" tickpolicy="delay"/>
    <timer name="rtc" tickpolicy="catchup"/>
    <timer name="hpet" present="no"/>
  </clock>
  <cpu mode="host-model" match="exact"/>
  <devices>
    <disk type="file" device="disk">
      <driver name="qemu" type="qcow2" cache="none"/>
      <source file="/var/lib/nova/instances/33985948-f19d-4d01-be63-989f302c218e/disk"/>
      <target bus="virtio" dev="vda"/>
    </disk>
    <interface type="bridge">
      <mac address="fa:16:3e:f0:c0:b4"/>
      <model type="virtio"/>
      <source bridge="qbr4700fff8-b4"/>
      <target dev="tap4700fff8-b4"/>
    </interface>
    <serial type="file">
      <source path="/var/lib/nova/instances/33985948-f19d-4d01-be63-989f302c218e/console.log"/>
    </serial>
    <serial type="pty"/>
    <input type="tablet" bus="usb"/>
    <graphics type="vnc" autoport="yes" keymap="en-us" listen="0.0.0.0"/>
    <video>
      <model type="cirrus"/>
    </video>
  </devices>
</domain>

5.3.创建Instance,并连接到network

/usr/lib/python2.7/dist-packages/nova/virt/libvirt/driver.py的

def _create_domain_and_network(self, context, xml, instance, network_info,
                               block_device_info=None, power_on=True,
                               reboot=False, vifs_already_plugged=False):

首先是调用/usr/lib/python2.7/dist-packages/nova/virt/libvirt/vif.py的def plug_ovs_hybrid(self, instance, vif):

其次调用/usr/lib/python2.7/dist-packages/nova/virt/libvirt/driver.py的

def _create_domain(self, xml=None, domain=None,
                        instance=None, launch_flags=0, power_on=True):

机器运行起来了。

文章转载于:https://www.cnblogs.com/popsuper1982/p/3800428.html

原著是一个有趣的人,若有侵权,请通知删除

退出移动版