1 Nova创建虚机流程
Openstack创建虚拟机的整个流程如图1所示。前端horizon发送创建虚机的请求之后,novaapi接收请求,并作处理,详见1.1节。注:Nova scheduler在另外章节介绍。
图 1 nova创建虚拟机流程
1.1 Nova api
Nova api接受到前端(horizon)发来的创建虚机的请求后,调用create(self, req, body)函数(/opt/stack/nova/nova/api/openstack/compute/servers.pyà1088)。该函数主要获取前端发来的body数据并解析,将相应参数传递给compute api(1.2节)。
1.2 Compute api
Compute api接受到请求之后,调用create函数。
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, iolimit=None, hypervisor=None):
“””
代码位置:/opt/stack/nova/nova/compute/api.pyà749
部分参数如下:
display_name=test
admin_password=123456
image_href=66c50770-21a4-46ce-85ee-392f29b05081
metadata={}
injected_files=[]
requested_networks={}
min_count=1
max_count=1
instance_type ={'memory_mb': 512L, 'root_gb': 0L, 'deleted_at': None, 'name':u'm1.tiny' , 'deleted': False,'created_at': None, 'ephemeral_gb': 0L, 'updated_at': None, 'disabled': False,'vcpus': 1L, 'extra_specs': {}, 'swap': 0L, 'rxtx_factor': 1.0, 'is_public':True, 'flavorid': u'1', 'vcpu_weight': None, 'id': 4L}
”””
- 检查各种参数及配额
_check_num_instances_quota(context, instance_type, min_count, max_count,hypervisor=hypervisor)
_check_metadata_properties_quota(context, metadata)
_check_injected_file_quota(context, injected_files)
_check_requested_networks(context, requested_networks)
- 获取镜像信息,检查flavor的ram,disk是否超出镜像规定的最小限额
(image_service, image_id) = lance.get_remote_image_service(image_href)
image = image_service.show(context, image_id)
if instance_type['memory_mb'] < int(image.get('min_ram') or 0):
raise exception
if instance_type['root_gb'] < int(image.get('min_disk') or 0):
raise exception - 将参数放入字典base_options={
'vm_state': 'building',
'ephemeral_gb': 0L,
'access_ip_v6': None,
'access_ip_v4': None,
'kernel_id': 'adaf51fe-c235-40b6-8aa7-80216d42303c',
'key_name': None,
'ramdisk_id': 'f9216b02-8e27-44da-b159-8d64401a16f2',
'instance_type_id': 4L,
'user_data':u'IyEvYmluL2Jhc2gKdXNlcmFkZCAtbSByb290CnBhc3N3ZCByb290IDw8IEVPRgpyb290CnJvb3QKRU9GCnBhc3N3ZCByb290IDw8IEVPRgpyb290CnJvb3QKRU9GCg==',
'vm_mode': '',
'display_name': u'test',
'config_drive_id': '',
'reservation_id': 'r-yl00q2af','architecture': 'Unknown',
'key_data': None, 'root_gb': 0L,
'user_id': u'c94cf849c7a94174b18f516c8fe497ee', 'hypervisor':u'libvirt',
'availability_zone': None,
'launch_time': '2014-10-30T05:28:15Z',
'metadata': {},
'display_description': u'test',
'memory_mb': 512L,
'vcpus': 1L,
'locked': False,
'image_ref': u'66c50770-21a4-46ce-85ee-392f29b05081',
'root_device_name': None,
'power_state': 0,
'progress': 0,
'cdrom_active': False,
'project_id': u'1ec9c7671c824b798fb9a028623aaccc',
'config_drive': ''}
- 利用base_options在数据库创建instance
instance = self.create_db_entry_for_new_instance(context, instance_type,image, base_options, security_group, block_device_mapping)
- rpc调用启动虚机(发请求到compute manger)
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)
1.3 Compute manager
Computemanager收到run_instance的请求后,运行函数run_instance。该函数内部会调用_run_instance函数如下:
def _run_instance(self,context, request_spec, filter_properties, requested_networks, injected_files,admin_password, is_first_time, instance):
“””
代码位置:/opt/stack/nova/nova/compute/manager.pyà510
参数实际值:
request_spec:={
'block_device_mapping':[],
'security_group': [u'default'],
'instance_uuids': ['8383fb3d-7dcf-4203-b639- 14c617b55259']'instance_uuids': ['8383fb3d-7dcf-4203-b639- 14c617b55259']
'instance_uuids': ['8383fb3d-7dcf-4203-b639- 14c617b55259']
'image': {'status': 'active',
'name':'cirros-test-image',
'deleted':False,
'container_format':'ami',
'created_at':'2014-10-30T04:21:05.000000',
'disk_format': 'ami',
'updated_at':'2014-10-30T04:21:09.000000',
'properties': {'kernel_id':'adaf51fe-c235-40b6-8aa7-80216d42303c',
'source': 'nova',
'ramdisk_id':'f9216b02-8e27-44da-b159-8d64401a16f2'},
'min_disk': 0,
'min_ram': 0,
'checksum':'2f81976cae15c16ef0010c51e3a6c163',
'owner':'1ec9c7671c824b798fb9a028623aaccc',
'is_public': True,
'deleted_at': None,
'id':'66c50770-21a4-46ce-85ee-392f29b05081', 'size': 25165824},
'instance_type': {'memory_mb': 512L,
'root_gb': 0L,
'deleted_at': None,
'name': u'm1.tiny',
'deleted': False,
'created_at': None,
'ephemeral_gb': 0L,
'updated_at': None,
'disabled': False,
'vcpus': 1L,
'extra_specs': {},
'swap': 0L,
'rxtx_factor': 1.0,
'is_public': True,
'flavorid': u'1',
'vcpu_weight': None,
'id': 4L},
'instance_properties': {'vm_state': 'building',
'ephemeral_gb': 0L,
'access_ip_v6': None,
'access_ip_v4': None,
'kernel_id': 'adaf51fe-c235-40b6-8aa7-80216d42303c',
'key_name': None,
'ramdisk_id':'f9216b02-8e27-44da-b159-8d64401a16f2', 'instance_type_id': 4L,
'user_data':u'IyEvYmluL2Jhc2gKdXNlcmFkZCAtbSByb290CnBhc3N3ZCByb290IDw8IEVPRgpyb290CnJvb3QKRU9GCnBhc3N3ZCByb290IDw8IEVPRgpyb290CnJvb3QKRU9GCg==',
'vm_mode': None,
'display_name':u'test',
'config_drive_id':'',
'reservation_id':'r-yl00q2af',
'os_type': None,
'architecture': None,
'key_data': None,
'iolimit': None,
'root_gb': 0L,
'user_id':u'c94cf849c7a94174b18f516c8fe497ee',
'hypervisor':u'libvirt',
'availability_zone':None,
'launch_time':'2014-10-30T05:28:15Z',
'metadata': {},
'display_description':u'test',
'memory_mb': 512L,
'vcpus': 1L,
'locked': False,
'image_ref':u'66c50770-21a4-46ce-85ee-392f29b05081', 'root_device_name': None,
'power_state': 0,
'auto_disk_config':None,
'progress': 0,
'cdrom_active':False,
'project_id': u'1ec9c7671c824b798fb9a028623aaccc',
'config_drive': ''}
}
admin_password=123456
injected_files=[]
requested_networks={}
”””
- 查看虚机是否存在
self._check_instance_not_already_created(context, instance)
- 查看镜像大小超过flavor规定最大值
self._check_image_size(context, instance)
- 更新虚机的状态(db)
self._start_building(context, instance)
- 分配网络,见1.4节 network
self._allocate_network
network_info=self.network_api.allocate_for_instance(context,instance,vpn=is_vpn, requested_networks=requested_networks)
- 孵化虚拟机,见1.5节libvirt driver
self.driver.spawn(context, instance, image_meta, network_info, block_device_info, injected_files,admin_password)
1.4 network
1.4.1 network api
networkapi收到compute manager发送的请求之后调用allocate_for_instance,增加一些参数,远程rpc调用将请求发送给network manager。
def allocate_for_instance(self,context, instance, **kwargs):
"""代码位置:/opt/stack/nova/nova/network/api.pyà277
Allocates all network structures for an instance.
:returns: network info as fromget_instance_nw_info() below
"""
args = kwargs
args['instance_id'] = instance['id']
args['instance_uuid'] = instance['uuid']
args['project_id'] = instance['project_id']
args['host'] = instance['host']
args['rxtx_factor'] = instance['instance_type']['rxtx_factor']
nw_info = rpc.call(context, FLAGS.network_topic,
{'method':'allocate_for_instance',
'args': args})
return network_model.NetworkInfo.hydrate(nw_info)
1.4.2 network manager
networkmanager收到请求后,调用函数allo