openstack 创建虚拟机实例过程

[一条nova boot引发的血案]
nova boot –flavor 1 –key_name mykey –image 9e5c2bee-0373-414c-b4af-b91b0246ad3b –security_group default cirrOS

nova命令来自python-novaclient
[到python-novaclient]
寻找最开始的源

先到这里
python-novaclient/novaclient/v1_1/shell.py   的 do_boot()函数
这个函数被一系列函数修饰符挂着,主要是验证和确保nova boot命令的参数正确性

进到这里
python-novaclient/novaclient/v1_1/shell.py 
boot_args, boot_kwargs = _boot(cs, args),在这里将boot实例需要的参数格式化

进入这里,cs.servers 在文件 python-novaclient/novaclient/v1_1/client.py 的Client里被定义
server = cs.servers.create(*boot_args, **boot_kwargs),
调用了类ServerManager的create方法

进入
python-novaclient/novaclient/v1_1/servers.py 的
[类ServerManager]
进到类ServerManager的create()函数,最后的数据验证和格式化,最重要的,设置REST请求的URL

python-novaclient/novaclient/v1_1/servers.py
进到类ServerManager的_boot()函数,在这里组装REST请求,请求body的创建

[进入类Manager]
python-novaclient/novaclient/base.py
进入类Manager  _create()函数,在这里post请求,_resp, body = self.api.client.post()

[nova服务对请求的处理]

[nova-api响应请求]
控制节点nova-api对请求的处理
nova/api/openstack/compute/servers.py的
[类Controller]
里的create()函数

有三个API选择
‘api’: ‘nova.compute.cells_api.ComputeCellsAPI’,
‘compute’: ‘nova.compute.api.API’,
None: ‘nova.compute.api.API’,

不论选择哪个API,最终都会进入
nova/nova/compute/api.py 
[类API]的
@hooks.add_hook(“create_instance”)create()—->self._create_instance()

instances对象,在_provision_instances()里第一次被创建
_create_instance()———————->instances = self._provision_instances()
instance = instance_obj.Instance()

数据库记录的创建通过以下5条
_provision_instances()————->instance = self.create_db_entry_for_new_instance()
create_db_entry_for_new_instance()————–>self._populate_instance_for_create()#填充实例的基本信息,例如状态,ID网络类型等
create_db_entry_for_new_instance()————–>self._populate_instance_names()#填充实例的名称、主机名
create_db_entry_for_new_instance()————–>self._populate_instance_shutdown_terminate()#填充实例启动信息
create_db_entry_for_new_instance()————–>instance.create(context)#创建数据库记录

nova/nova/compute/api.py  _populate_instance_for_create()

[至此时虚拟机的状态为]vm_states.BUILDING
[至此时任务的状态为]task_states.SCHEDULING

nova/nova/compute/api.py          _create_instance()—————————->self.compute_task_api.build_instances()

根据配置文件  use_local 设置,决定进入哪个类

[LocalComputeTaskAPI  线路]
nova/nova/conductor/api.py
进入类
[类LocalComputeTaskAPI]
build_instances()——————->utils.spawn_n()
[直接开个线程孵化实例]
spawn_n            
utils.spawn_n(self._manager.build_instances, context, … )————————->eventlet.spawn_n(func, *args, **kwargs)—————>self._manager.build_instances()         (func等同于self._manager.build_instances())

一下几步就是往调度(nova-scheduler)发消息的地方
[进入类 ComputeTaskManager]
nova/nova/conductor/manager.py
                build_instances()——————————>self.scheduler_rpcapi.run_instance()
[进入类 SchedulerAPI]
nova/nova/scheduler/rpcapi.py
run_instance()—————————>cctxt.cast()
[发送消息到消息队列]
nova/nova/scheduler/rpcapi.py/run_instance()
cctxt.cast(ctxt, ‘run_instance’, **msg_kwargs)

[ComputeTaskAPI  线路] 
nova/nova/conductor/api.py
进入类
[进入类 ComputeTaskAPI]
build_instances()————>self.conductor_compute_rpcapi.build_instances()

nova/nova/conductor/rpcapi.py
[进入类 ComputeTaskAPI]
[发送消息到消息队列]
的build_instances() ———>cctxt.cast(context, ‘build_instances’,nstances=instances,…)

[调度]
nova/scheduler/manager.py
[类SchedulerManager]
类的函数run_instance()   调用—>self.driver.schedule_run_instance()

进入nova/scheduler/filter_scheduler.py
[类FilterScheduler]
类的函数schedule_run_instance()   进入—–>_schedule()函数

进入类nova/scheduler/host_manager.py
[类HostManager]  获取一系列可用的主机列表 ordered by their fitness.
具体的是这样的,
具体要启动多少个实例,即一次启动多少个相同配置的实例,for num in xrange(num_instances):
开始循环:
根据要求筛选本地主机,得到一个可用主机的列表,hosts = self.host_manager.get_filtered_hosts(hosts, filter_properties, index=num)
得到一个可用主机的weight列表,self.host_manager.get_weighed_hosts(hosts,filter_properties)
为每个实例随机挑选一个主机,根据配置文件的scheduler_host_subset_size设置
   scheduler_host_subset_size,设置默认为1,所以,取得是权重最高的
chosen_host = random.choice(weighed_hosts[0:scheduler_host_subset_size])
selected_hosts.append(chosen_host)
继续循环,直到为所有实例,挑选好主机
将选择调度好的主机列表返回,return selected_hosts

最终随机选择了

进入函数  def _provision_resource()

最终调用  self.compute_rpcapi.run_instance(…node=weighed_host.obj.nodename,…)
其中启动实例的节点信息,被写入了,即:node=weighed_host.obj.nodename,

nova/nova/compute/rpcapi.py
进入类
[类ComputeAPI]
的run_instance()
最后cast请求,cctxt.cast(ctxt, ‘run_instance’, **msg_kwargs)

[实例的启动阶段]
[调用hypervisor的过程]
通常是在计算节点
nova/nova/compute/manager.py
进入类
[类ComputeManager]
的函数
@wrap_exception()
@reverts_task_state
@wrap_instance_event
@wrap_instance_fault
def run_instance()

然后———–>self._run_instance()
然后———–>_build_instance()
然后———–>self._spawn()
此时更改了实例的状态为SPAWNING,并保存在了数据库
instance.vm_state = vm_states.BUILDING
instance.task_state = task_states.SPAWNING
instance.save(expected_task_state=task_states.BLOCK_DEVICE_MAPPING)

然后———–>self.driver.spawn()孵化
self.driver默认选择的类型为libvirt,也可以设置compute_driver更改
self.driver = driver.load_compute_driver(self.virtapi, compute_driver)

最后进入
nova/virt/libvirt/driver.py
[类LibvirtDriver]
的函数spawn()

最终在kvm或者qemu创建domain
进入————> _create_domain_and_network()
创建domain——>domain = self._create_domain()
创建domain
_create_domain()函数里
domain = self._conn.defineXML(xml)

启动
if power_on:
domain.createWithFlags(launch_flags)

当实例状态为running时,孵化结束
if state == power_state.RUNNING

返回
return domain

[收工阶段]

一系列调用后返回
nova/nova/compute/manager.py
通知创建成功

notify(“end”, msg=_(“Success”), network_info=network_info)


转载自:http://www.cloudcraft.cn/nova-boot-instance-code-procedure/

猜你喜欢

转载自blog.csdn.net/hobertony_7/article/details/50298873