[一条nova boot引发的血案]
nova boot �Cflavor 1 �Ckey_name mykey �Cimage 9e5c2bee-0373-414c-b4af-b91b0246ad3b �Csecurity_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()――――�C>self._populate_instance_for_create()#填充实例的基本信息,例如状态,ID网络类型等
create_db_entry_for_new_instance()――――�C>self._populate_instance_names()#填充实例的名称、主机名
create_db_entry_for_new_instance()――――�C>self._populate_instance_shutdown_terminate()#填充实例启动信息
create_db_entry_for_new_instance()――――�C>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() 进入―�C>_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()
然后―――�C>self._run_instance()
然后―――�C>_build_instance()
然后―――�C>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)
然后―――�C>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.linuxqq.net/archives/1277.html