workflow:
1. 用戶向nova-api發送請求
用戶發送請求到nova-api,這裡有兩種:
a.通過openstack api
從 server.py's controller.create():
self.helper.create_instance(req, body, self.compute_api.create)
create_instance_helper.CreateInstanceHelper() 查表獲取基本信息
b.通過ec2 api
從cloud.py.run_instances()
統一調 computer.api.create() 將新的數據插回去
self._ask_scheduler_to_create_instance(context, base_options,
instance_type, zone_blob,
availability_zone, injected_files,
admin_password, image,
instance_id=instance_id,
requested_networks=requested_networks)
2. API 將處理好的數據通過MQ 轉發給scheduler .(code from Computer.api)
rpc.cast(context,
FLAGS.scheduler_topic,
{"method": "run_instance",
"args": {"topic": FLAGS.compute_topic,
"instance_id": instance_id,
"request_spec": request_spec,
"availability_zone": availability_zone,
"admin_password": admin_password,
"injected_files": injected_files,
"requested_networks": requested_networks}})
3. Scheduler 獲取信息並作出決定 哪一個host 可以來run instance.
def __getattr__(self, key):
return functools.partial(self._schedule, key)
def _schedule(self, method, context, topic, *args, **kwargs):
.......
rpc.cast(context,
db.queue_get_for(context, topic, host),
{"method": method,
"args": kwargs})
LOG.debug(_("Casted to %(topic)s %(host)s for %(method)s") % locals())
4. Computer 從池中獲取信息 並讓 Networker 去准備一個ip ,讓volume 准備卷, 然後初始化相應的信息,例如創建image,映射device,創建domain,
並將domain 放入running pool中 然後就進入等待直到instance的狀態變為running.
a. networker 分配ip
network_info = self.network_api.allocate_for_instance(context,
instance, vpn=is_vpn,
requested_networks=requested_networks)
def allocate_floating_ip(self, context):
return rpc.call(context,
FLAGS.network_topic,
{'method': 'allocate_floating_ip',
'args': {'project_id': context.project_id}})
b 讓 volume 准備卷
bd_mapping = self._setup_block_device_mapping(context, instance_id)
def create(self, context, size, snapshot_id, name, description,
volume_type=None, metadata=None, availability_zone=None):
rpc.cast(context,
FLAGS.scheduler_topic,
{"method": "create_volume",
"args": {"topic": FLAGS.volume_topic,
"volume_id": volume['id'],
"snapshot_id": snapshot_id}})
c call nova.virt.libvirt.firewall.IptablesFirewallDriver 建立網絡規則
這裡是重頭戲,單獨開個貼記錄下....
d call libvirt 創建domian 並launch
domain = self._create_new_domain(xml)
def _create_new_domain(self, xml, persistent=True, launch_flags=0):
if persistent:
# To create a persistent domain, first define it, then launch it.
domain = self._conn.defineXML(xml)
domain.createWithFlags(launch_flags)
else:
# createXML call creates a transient domain
domain = self._conn.createXML(xml, launch_flags)
return domain
e call virt.libvirt.connetion.spwan 等待
def spawn(self, context, instance, network_info,
block_device_info=None):
..........
def _wait_for_boot():
instance_name = instance['name']
try:
state = self.get_info(instance_name)['state']
except exception.NotFound:
msg = _("During reboot, %s disappeared.") % instance_name
LOG.error(msg)
raise utils.LoopingCallDone
if state == power_state.RUNNING:
msg = _("Instance %s spawned successfully.") % instance_name
LOG.info(msg)
raise utils.LoopingCallDone
timer = utils.LoopingCall(_wait_for_boot)
return timer.start(interval=0.5, now=True)
5 一旦instance的狀態改變至running,他就會去通過networker獲取網絡信息, 這裡有幾種方式,取決於你的networkManager