#声明: 自己原创草书,纯属爱好。
为记录自己学习历程,学浅,难免错误,欢迎批评指正。
如需转载,请标明出处。
继续上篇博客问题,#nova show <server-id>并没有明显调用security groups,那其中信息是从哪里来的呢?
#nova show <server-id>
+--------------------------------------+----------------------------------------------------------------+
| Property | Value |
+--------------------------------------+----------------------------------------------------------------+
| OS-DCF:diskConfig | AUTO |
| OS-EXT-AZ:availability_zone | nova |
| OS-EXT-SRV-ATTR:host | park-ThinkPad-T420 |
| OS-EXT-SRV-ATTR:hypervisor_hostname | park-ThinkPad-T420 |
| OS-EXT-SRV-ATTR:instance_name | instance-00000003 |
| OS-EXT-STS:power_state | 1 |
| OS-EXT-STS:task_state | - |
| OS-EXT-STS:vm_state | active |
| OS-SRV-USG:launched_at | 2015-05-11T07:14:35.000000 |
| OS-SRV-USG:terminated_at | - |
| accessIPv4 | |
| accessIPv6 | |
| config_drive | True |
| created | 2015-05-11T07:14:31Z |
| flavor | m1.nano (42) |
| hostId | ff03327555887251b281acf0eac8c71d920efd27171b0813b7778ad6 |
| id | 33b937f9-2785-4fe0-8f88-6474ff50f7bb |
| image | cirros-0.3.4-x86_64-uec (16f62e95-57b0-4ddd-88ee-2b063ce5f1e3) |
| key_name | - |
| metadata | {} |
| name | vm1 |
| os-extended-volumes:volumes_attached | [] |
| private network | 10.0.0.2 |
| progress | 0 |
<span style="color:#ff0000;">| security_groups | default |</span>
| status | ACTIVE |
| tenant_id | ecb571eb456242f1af7e37c5190382bd |
| updated | 2015-05-11T07:14:35Z |
| user_id | 722f205503d64644b53e22923d388f25 |
+--------------------------------------+----------------------------------------------------------------+
nova show 对应会调用nova REST API 中api/openstack/compute/servers.py中Controller.show(),我们就来看看这里面的逻辑关系。
# vim api/openstack/compute/servers.py
def show(self, req, id):
"""Returns server details by server id."""
context = req.environ['nova.context']
instance = self._get_server(context, req, id)
return self._view_builder.show(req, instance)
直接调用了view_builder.show(),这个view_builder在哪里呢?如下。
#vim api/openstack/compute/views/servers.py
def show(self, request, instance):
"""Detailed view of a single instance."""
ip_v4 = instance.get('access_ip_v4')
ip_v6 = instance.get('access_ip_v6')
server = {
"server": {
"id": instance["uuid"],
"name": instance["display_name"],
"status": self._get_vm_status(instance),
"tenant_id": instance.get("project_id") or "",
"user_id": instance.get("user_id") or "",
"metadata": self._get_metadata(instance),
"hostId": self._get_host_id(instance) or "",
"image": self._get_image(request, instance),
"flavor": self._get_flavor(request, instance),
"created": timeutils.isotime(instance["created_at"]),
"updated": timeutils.isotime(instance["updated_at"]),
"addresses": self._get_addresses(request, instance),
"accessIPv4": str(ip_v4) if ip_v4 is not None else '',
"accessIPv6": str(ip_v6) if ip_v6 is not None else '',
"links": self._get_links(request,
instance["uuid"],
self._collection_name),
},
}
if server["server"]["status"] in self._fault_statuses:
_inst_fault = self._get_fault(request, instance)
if _inst_fault:
server['server']['fault'] = _inst_fault
if server["server"]["status"] in self._progress_statuses:
server["server"]["progress"] = instance.get("progress", 0)
return server
这里组装了各种server信息,但是并没有security-groups相关调用。
代码追踪到这里,似乎陷入了一个悖论,单纯API中server.show()并没有返回securitygroups信息,但是从nova client端调用能够得到securitygroups信息,中间的这个缺失从哪里来的呢?先看看client端的信息
# vim novaclient/v2/shell.py
def _print_server(cs, args, server=None):
...
if not server:
server = _find_server(cs, args.server)
....
if 'security_groups' in info:
# when we have multiple nics the info will include the
# security groups N times where N == number of nics. Be nice
# and only display it once.
info['security_groups'] = ', '.join(
sorted(set(group['name'] for group in info['security_groups'])))
的确有securitygroups信息。仔细回顾一下整个过程似乎没有疏漏....只剩下extension似乎有可以怀疑的地方。
回头重新看extension机制,从最基础wsgi.Resource类看起,在stack函数的调用过程中,必须经过_process_stack,而这里第一步就是处理extension
def _process_stack(self, request, action, action_args,
content_type, body, accept):
"""Implement the processing stack."""
# Get the implementing method
try:
meth, extensions = self.get_method(request, action,
content_type, body)
其中meth是指当前request所指向的操作(Controller.show of nova.api.openstack.compute.servers.Controller object),而extensions表示在当前操作的对象(servers对象)上其他挂载的extensions具有相同名字(show)的操作,具体为
[<bound method ServerDiskConfigController.show of <nova.api.openstack.compute.contrib.disk_config.ServerDiskConfigController object at 0x7f454d1d9390>>,
<bound method ExtendedAZController.show of <nova.api.openstack.compute.contrib.extended_availability_zone.ExtendedAZController object at 0x7f454ce7d790>>,
[bound method ExtendedIpsController.show of <nova.api.openstack.compute.contrib.extended_ips.ExtendedIpsController object at 0x7f454ce7d890>>,
<bound method ExtendedIpsMacController.show of <nova.api.openstack.compute.contrib.extended_ips_mac.ExtendedIpsMacController object at 0x7f454ce91390>>,
<bound method ExtendedServerAttributesController.show of <nova.api.openstack.compute.contrib.extended_server_attributes.ExtendedServerAttributesController object at 0x7f454ce91410>>,
<bound method ExtendedStatusController.show of <nova.api.openstack.compute.contrib.extended_status.ExtendedStatusController object at 0x7f454ce91490>>,
<bound method ServerUsageController.show of <nova.api.openstack.compute.contrib.server_usage.ServerUsageController object at 0x7f454ce91b90>>,
<bound method Controller.show of <nova.api.openstack.compute.contrib.config_drive.Controller object at 0x7f454ce96250>>,
<bound method ExtendedVolumesController.show of
<nova.api.openstack.compute.contrib.extended_volumes.ExtendedVolumesController object at 0x7f454d202210>>,
<bound method Controller.show of <nova.api.openstack.compute.contrib.hide_server_addresses.Controller object at 0x7f454ce2cdd0>>,
<bound method Controller.show of <nova.api.openstack.compute.contrib.keypairs.Controller object at 0x7f454ce2cc10>>,
<bound method SecurityGroupsOutputController.show of <nova.api.openstack.compute.contrib.security_groups.SecurityGroupsOutputController object at 0x7f454ce3a5d0>>]
接下来我会想,这些extensions是如何注册到这里的呢?不着急,后面慢慢说明,先继续往下看_process_stack。
if not response:
try:
with ResourceExceptionHandler():
action_result = self.dispatch(meth, request, action_args)
except Fault as ex:
response = ex
这里即是处理client调用本身,本例中即为servers.show(), 如果没有错误,继续往下执行post_process_extensions
# Process post-processing extensions
response = self.post_process_extensions(post, resp_obj,
request, action_args)
def post_process_extensions(self, extensions, resp_obj, request,
action_args):
for ext in extensions:
response = None
if inspect.isgenerator(ext):
# If it's a generator, run the second half of
# processing
try:
with ResourceExceptionHandler():
response = ext.send(resp_obj)
except StopIteration:
# Normal exit of generator
continue
except Fault as ex:
response = ex
else:
# Regular functions get post-processing...
try:
with ResourceExceptionHandler():
response = ext(req=request, resp_obj=resp_obj,
**action_args)
except exception.VersionNotFoundForAPIMethod:
# If an attached extension (@wsgi.extends) for the
# method has no version match its not an error. We
# just don't run the extends code
continue
except Fault as ex:
response = ex
# We had a response...
if response:
return response
return None
看到这里,柳暗花明,真正执行的extensions就是在这里,这里将上文提到的在当前操作的对象(servers对象)上其他挂载的extensions具有相同名字(show)的extensions都执行一遍。作为返回数据反馈给调用者。
到这里,我们明白了为什么nova show <server-id>会有很多的extensions信息在里面,那么问题来了....
这些extensions是什么时候注册到servers这个对象上的呢?