Icehouse 创建Instance代码分析

来源:互联网 发布:崩坏三最新矩阵buff 编辑:程序博客网 时间:2024/05/10 05:33

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,得到

  • password: 如果request中有的解析出,没有则随机generate一个
  • name
  • image_uuid
  • personality: 从中得到config_drive或者injected_files
  • security_groups
  • requested_networks
  • flavor_id
  • key_name
  • user_data
  • availability_zone
  • block_device_mapping
  • min_count
  • max_count
  • auto_disk_config:是否自动配置硬盘到flavor指定的大小,OS-DCF,auto_disk_config
  • scheduler_hints:为scheduler提供参数

最终调用

(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):

  • _check_and_transform_bdm
  • _provision_instances:在数据库中创建instance对象create_db_entry_for_new_instance,将状态设为vm_states.BUILDING
  • _build_filter_properties:从scheduler_hints中得到filter_properties['instance_type'],filter_properties['force_hosts'],filter_properties['force_nodes']
  • _update_instance_group:从scheduler_hints得到'group',将instance加入group
  • _record_action_start:instance_actions.CREATE
  • self.compute_task_api.build_instances:调用conductor.ComputeTaskAPI()

/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):

  • instance_uuids = request_spec.get('instance_uuids')所有instance的id
  • weighed_hosts = self._schedule(context, request_spec, filter_properties, instance_uuids)
  • for num, instance_uuid in enumerate(instance_uuids):
    • weighed_host = weighed_hosts.pop(0)
    • self._provision_resource(context, weighed_host, request_spec, filter_properties, requested_networks, injected_files, admin_password,is_first_time,instance_uuid=instance_uuid,legacy_bdm_in_spec=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)

  • security_groups = request_spec.get('security_group')
  • node = self.driver.get_available_nodes(refresh=True)[0]
  • bdms = block_device_obj.BlockDeviceMappingList.get_by_instance_uuid(context, instance['uuid'])
  • injected_files = self._decode_files(injected_files)
  • rt = self._get_resource_tracker(node)
  • with rt.instance_claim(context, instance, limits):
    • macs = self.driver.macs_for_instance(instance)
    • dhcp_options = self.driver.dhcp_options_for_instance(instance)
    • network_info = self._allocate_network(context, instance, 
                              requested_networks, macs, security_groups, 
                              dhcp_options)
    • self._instance_update( 
                              context, instance['uuid'], 
                              vm_state=vm_states.BUILDING, 
                              task_state=task_states.BLOCK_DEVICE_MAPPING)
    • self._default_block_device_names(context, instance, image_meta, bdms)
    • block_device_info = self._prep_block_device(context, instance, bdms)
    • instance = self._spawn(context, instance, image_meta, 
                                             network_info, block_device_info, 
                                             injected_files, admin_password, 
                                             set_access_ip=set_access_ip)

 

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函数

  • neutron = neutronv2.get_client(context)
  • nets = self._get_available_networks(context, instance['project_id'], net_ids)
    • (Pdb) p nets 
      [{u'status': u'ACTIVE', u'subnets': [u'bd652c3e-005e-4985-b65e-576c3045e890'], u'name': u'openstack-net', u'admin_state_up': True, u'tenant_id': u'8efa4856fe4b4aa0b6dcf05dc66d4efa', u'router:external': False, u'shared': False, u'id': u'a29561e9-2f32-4765-a0f8-306b870f780b'}]
  • user_security_groups = neutron.list_security_groups(**search_opts).get('security_groups')
    • (Pdb) p security_groups 
      [u'default']
  • self._populate_neutron_extension_values(context, instance, port_req_body)
    • (Pdb) p port_req_body 
      {'port': {'device_owner': u'compute:nova', 'device_id': u'3a5cd5d4-2676-447b-bab4-6acf21feacd6'}}
    • RESP:{'status': '200', 'content-length': '3703', 'content-location': 'http://127.0.0.1:9696/v2.0/extensions.json', 'date': 'Mon, 02 Jun 2014 20:52:37 GMT', 'content-type': 'application/json; charset=UTF-8', 'x-openstack-request-id': 'req-518cd143-e3a5-4f5d-a71b-32b19d69bf2a'} {"extensions": [{"updated": "2012-10-05T10:00:00-00:00", "name": "security-group", "links": [], "namespace": "http://docs.openstack.org/ext/securitygroups/api/v2.0", "alias": "security-group", "description": "The security groups extension."}, {"updated": "2013-02-07T10:00:00-00:00", "name": "L3 Agent Scheduler", "links": [], "namespace": "http://docs.openstack.org/ext/l3_agent_scheduler/api/v1.0", "alias": "l3_agent_scheduler", "description": "Schedule routers among l3 agents"}, {"updated": "2013-03-28T10:00:00-00:00", "name": "Neutron L3 Configurable external gateway mode", "links": [], "namespace": "http://docs.openstack.org/ext/neutron/ext-gw-mode/api/v1.0", "alias": "ext-gw-mode", "description": "Extension of the router abstraction for specifying whether SNAT should occur on the external gateway"}, {"updated": "2014-02-03T10:00:00-00:00", "name": "Port Binding", "links": [], "namespace": "http://docs.openstack.org/ext/binding/api/v1.0", "alias": "binding", "description": "Expose port bindings of a virtual port to external application"}, {"updated": "2012-09-07T10:00:00-00:00", "name": "Provider Network", "links": [], "namespace": "http://docs.openstack.org/ext/provider/api/v1.0", "alias": "provider", "description": "Expose mapping of virtual networks to physical networks"}, {"updated": "2013-02-03T10:00:00-00:00", "name": "agent", "links": [], "namespace": "http://docs.openstack.org/ext/agent/api/v2.0", "alias": "agent", "description": "The agent management extension."}, {"updated": "2012-07-29T10:00:00-00:00", "name": "Quota management support", "links": [], "namespace": "http://docs.openstack.org/network/ext/quotas-sets/api/v2.0", "alias": "quotas", "description": "Expose functions for quotas management per tenant"}, {"updated": "2013-02-07T10:00:00-00:00", "name": "DHCP Agent Scheduler", "links": [], "namespace": "http://docs.openstack.org/ext/dhcp_agent_scheduler/api/v1.0", "alias": "dhcp_agent_scheduler", "description": "Schedule networks among dhcp agents"}, {"updated": "2013-06-27T10:00:00-00:00", "name": "Multi Provider Network", "links": [], "namespace": "http://docs.openstack.org/ext/multi-provider/api/v1.0", "alias": "multi-provider", "description": "Expose mapping of virtual networks to multiple physical networks"}, {"updated": "2013-01-14T10:00:00-00:00", "name": "Neutron external network", "links": [], "namespace": "http://docs.openstack.org/ext/neutron/external_net/api/v1.0", "alias": "external-net", "description": "Adds external network attribute to network resource."}, {"updated": "2012-07-20T10:00:00-00:00", "name": "Neutron L3 Router", "links": [], "namespace": "http://docs.openstack.org/ext/neutron/router/api/v1.0", "alias": "router", "description": "Router abstraction for basic L3 forwarding between L2 Neutron networks and access to external networks via a NAT gateway."}, {"updated": "2013-07-23T10:00:00-00:00", "name": "Allowed Address Pairs", "links": [], "namespace": "http://docs.openstack.org/ext/allowedaddresspairs/api/v2.0", "alias": "allowed-address-pairs", "description": "Provides allowed address pairs"}, {"updated": "2013-03-17T12:00:00-00:00", "name": "Neutron Extra DHCP opts", "links": [], "namespace": "http://docs.openstack.org/ext/neutron/extra_dhcp_opt/api/v1.0", "alias": "extra_dhcp_opt", "description": "Extra options configuration for DHCP. For example PXE boot options to DHCP clients can be specified (e.g. tftp-server, server-ip-address, bootfile-name)"}, {"updated": "2013-02-01T10:00:00-00:00", "name": "Neutron Extra Route", "links": [], "namespace": "http://docs.openstack.org/ext/neutron/extraroutes/api/v1.0", "alias": "extraroute", "description": "Extra routes configuration for L3 router"}]}
  • created_port = self._create_port(port_client, instance, network_id, port_req_body, fixed_ips.get(network_id),security_group_ids, available_macs, dhcp_opts)
    • (Pdb) p port_req_body 
      {'port': {'binding:host_id': u'OpenstackIcehouse2', 'admin_state_up': True, 'network_id': u'a29561e9-2f32-4765-a0f8-306b870f780b', 'tenant_id': u'8efa4856fe4b4aa0b6dcf05dc66d4efa', 'device_owner': u'compute:nova', 'security_groups': [u'b4a79ec8-8552-4074-a410-faa52b30424d'], 'device_id': u'3a5cd5d4-2676-447b-bab4-6acf21feacd6'}}
    • RESP:{'date': 'Mon, 02 Jun 2014 20:56:01 GMT', 'status': '201', 'content-length': '717', 'content-type': 'application/json; charset=UTF-8', 'x-openstack-request-id': 'req-a9ef458b-adfe-41f9-b66a-640cb8d56833'} {"port": {"status": "DOWN", "binding:host_id": "OpenstackIcehouse2", "name": "", "allowed_address_pairs": [], "admin_state_up": true, "network_id": "a29561e9-2f32-4765-a0f8-306b870f780b", "tenant_id": "8efa4856fe4b4aa0b6dcf05dc66d4efa", "binding:vif_details": {"port_filter": true, "ovs_hybrid_plug": true}, "binding:vnic_type": "normal", "binding:vif_type": "ovs", "device_owner": "compute:nova", "mac_address": "fa:16:3e:64:b6:8a", "binding:profile": {}, "fixed_ips": [{"subnet_id": "bd652c3e-005e-4985-b65e-576c3045e890", "ip_address": "192.168.2.19"}], "id": "9d6cd91a-dac8-4523-a692-01dc61c04b21", "security_groups": ["b4a79ec8-8552-4074-a410-faa52b30424d"], "device_id": "3a5cd5d4-2676-447b-bab4-6acf21feacd6"}}
  • nw_info = self.get_instance_nw_info(context, instance, networks=nets, port_ids=ports_in_requested_order)
    • (Pdb) p nw_info 
      [VIF({'ovs_interfaceid': u'9d6cd91a-dac8-4523-a692-01dc61c04b21', 'network': Network({'bridge': 'br-int', 'subnets': [Subnet({'ips': [FixedIP({'meta': {}, 'version': 4, 'type': 'fixed', 'floating_ips': [], 'address': u'192.168.2.19'})], 'version': 4, 'meta': {'dhcp_server': u'192.168.2.2'}, 'dns': [IP({'meta': {}, 'version': 4, 'type': 'dns', 'address': u'8.8.8.8'})], 'routes': [], 'cidr': u'192.168.2.0/24', 'gateway': IP({'meta': {}, 'version': 4, 'type': 'gateway', 'address': u'192.168.2.1'})})], 'meta': {'injected': False, 'tenant_id': u'8efa4856fe4b4aa0b6dcf05dc66d4efa'}, 'id': u'a29561e9-2f32-4765-a0f8-306b870f780b', 'label': u'openstack-net'}), 'devname': u'tap9d6cd91a-da', 'qbh_params': None, 'meta': {}, 'details': {u'port_filter': True, u'ovs_hybrid_plug': True}, 'address': u'fa:16:3e:64:b6:8a', 'active': False, 'type': u'ovs', 'id': u'9d6cd91a-dac8-4523-a692-01dc61c04b21', 'qbg_params': None})]

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):

  • disk_info = blockinfo.get_disk_info(CONF.libvirt.virt_type, instance, block_device_info, image_meta)
    • (Pdb) p disk_info 
      {'disk_bus': 'virtio', 'cdrom_bus': 'ide', 'mapping': {'disk': {'bus': 'virtio', 'boot_index': '1', 'type': 'disk', 'dev': 'vda'}, 'root': {'bus': 'virtio', 'boot_index': '1', 'type': 'disk', 'dev': 'vda'}}}
  • self._create_image(context, instance, 
                       disk_info['mapping'], 
                       network_info=network_info, 
                       block_device_info=block_device_info, 
                       files=injected_files, 
                       admin_pass=admin_password)
  • xml = self.to_xml(context, instance, network_info, 
                      disk_info, image_meta, 
                      block_device_info=block_device_info, 
                      write_to_disk=True)
  • self._create_domain_and_network(context, xml, instance, network_info, 
                                    block_device_info)

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'])

  • 首先会调用/usr/lib/python2.7/dist-packages/nova/virt/libvirt/utils.py的fetch_image
    • images.fetch_to_raw(context, image_id, target, user_id, project_id, max_size=max_size)
    • 会调用/usr/lib/python2.7/dist-packages/nova/virt/images.py的fetch_to_raw,最终调用image_service.download(context, image_id, dst_path=path),会从glance下载下来image
  • 其次,会调用/usr/lib/python2.7/dist-packages/nova/virt/libvirt/imagebackend.py的cache函数
    • (Pdb) p base 
      '/var/lib/nova/instances/_base/4b1ad1f3fa1222ea960f8e373baa4eef880c5ff1'
    • (Pdb) p size 
      21474836480
    • 会调用class Qcow2(Image)的create_image(self, prepare_template, base, size, *args, **kwargs)并最后调用到copy_qcow2_image
    • copy_qcow2_image是调用了两个命令:
      • ('qemu-img', 'create', '-f', 'qcow2', '-o', 'backing_file=/var/lib/nova/instances/_base/4b1ad1f3fa1222ea960f8e373baa4eef880c5ff1', '/var/lib/nova/instances/4d169b6a-b921-4e24-83b0-2c36ea4da7d0/disk')
      • ('qemu-img', 'resize', '/var/lib/nova/instances/4d169b6a-b921-4e24-83b0-2c36ea4da7d0/disk', 21474836480)

配置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):

  • self.plug_vifs(instance, network_info)
  • self.firewall_driver.setup_basic_filtering(instance, network_info)
  • self.firewall_driver.prepare_instance_filter(instance, network_info)
  • domain = self._create_domain(xml, instance=instance, launch_flags=launch_flags, power_on=power_on)

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

  • iface_id = self.get_ovs_interfaceid(vif)
    • (Pdb) p iface_id 
      u'4700fff8-b437-45fb-8b81-dbd69dec2b5a'
  • br_name = self.get_br_name(vif['id'])
    • (Pdb) p br_name 
      u'qbr4700fff8-b4'
  • v1_name, v2_name = self.get_veth_pair_names(vif['id'])
    • (Pdb) p v1_name 
      u'qvb4700fff8-b4'
    • (Pdb) p v2_name 
      u'qvo4700fff8-b4'
  • utils.execute('brctl', 'addbr', br_name, run_as_root=True)
  • utils.execute('brctl', 'setfd', br_name, 0, run_as_root=True)
  • utils.execute('brctl', 'stp', br_name, 'off', run_as_root=True)
  • utils.execute('tee', ('/sys/class/net/%s/bridge/multicast_snooping' % br_name), process_input='0', run_as_root=True, check_exit_code=[0, 1])
  • linux_net._create_veth_pair(v1_name, v2_name)
  • utils.execute('ip', 'link', 'set', br_name, 'up', run_as_root=True)
  • utils.execute('brctl', 'addif', br_name, v1_name, run_as_root=True)
  • linux_net.create_ovs_vif_port(self.get_bridge_name(vif), v2_name, iface_id, vif['address'], instance['uuid'])
    • (Pdb) p vif 
      VIF({'ovs_interfaceid': u'4700fff8-b437-45fb-8b81-dbd69dec2b5a', 'network': Network({'bridge': 'br-int', 'subnets': [Subnet({'ips': [FixedIP({'meta': {}, 'version': 4, 'type': 'fixed', 'floating_ips': [], 'address': u'192.168.2.18'})], 'version': 4, 'meta': {'dhcp_server': u'192.168.2.2'}, 'dns': [IP({'meta': {}, 'version': 4, 'type': 'dns', 'address': u'8.8.8.8'})], 'routes': [], 'cidr': u'192.168.2.0/24', 'gateway': IP({'meta': {}, 'version': 4, 'type': 'gateway', 'address': u'192.168.2.1'})})], 'meta': {'injected': False, 'tenant_id': u'8efa4856fe4b4aa0b6dcf05dc66d4efa'}, 'id': u'a29561e9-2f32-4765-a0f8-306b870f780b', 'label': u'openstack-net'}), 'devname': u'tap4700fff8-b4', 'qbh_params': None, 'meta': {}, 'details': {u'port_filter': True, u'ovs_hybrid_plug': True}, 'address': u'fa:16:3e:f0:c0:b4', 'active': False, 'type': u'ovs', 'id': u'4700fff8-b437-45fb-8b81-dbd69dec2b5a', 'qbg_params': None})
    • _ovs_vsctl(['--', '--if-exists', 'del-port', dev, '--', 
                      'add-port', bridge, dev, 
                      '--', 'set', 'Interface', dev, 
                      'external-ids:iface-id=%s' % iface_id, 
                      'external-ids:iface-status=active', 
                      'external-ids:attached-mac=%s' % mac, 
                      'external-ids:vm-uuid=%s' % instance_id])
    • _set_device_mtu(dev)

其次调用/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):

  • domain = self._conn.defineXML(xml)
  • domain.createWithFlags(launch_flags)

机器运行起来了。

0 0