#nova–debug show <server-id>, (这里不讨论novaclient的认证过程)
可以从client端得到的debug信息,调用过程如下:
1. 从服务器获取token
2. 调用servers.Controller.index()
3. 调用servers.Controller.show()
4. 调用flavors.Controller.show()
5. 调用images.Controller.show()
<pre name="code" class="python"><span style="font-size:14px;">REQ: curl -g -i --cacert "/opt/stack/data/ca-bundle.pem" -X GET http://9.115.122.54:35357/v3/auth/tokens -H "X-
Subject-Token: {SHA1}6b17daa3f28a43f6ce18863dfaa4374fbe59f6e0" -H "User-Agent: python-keystoneclient" -H "Accept: application/json" -H "X-Auth-Token: {SHA1}6bbfbc9a37c9
ab53696017541de0df5107e9ad35"
nova.api.openstack.wsgi: Calling method '<bound method Controller.index of <nova.api
.openstack.compute.servers.Controller object at 0x7fbd39a7b7d0>>'
nova.compute.api: Searching by: {'deleted': False, 'project_id': u'ecb571eb456242f1a
f7e37c5190382bd', u'name': u'vm1'}
nova.osapi_compute.wsgi.server: localhost "GET /v2/ecb571eb456242f1af7e37c5190382b
d/servers?name=vm1 HTTP/1.1" status: 200 len: 553 time: 0.1614599
nova.api.openstack.wsgi: Calling method '<bound method Controller.show of <nova.api.
openstack.compute.servers.Controller object at 0x7fbd39a7b7d0>>'
nova.osapi_compute.wsgi.server: localhost "GET /v2/ecb571eb456242f1af7e37c5190382bd/servers/33b937f9-2785-4fe0-8f88-6474ff50f7bb HTTP/1.1" status: 200 len: 1892 time: 0.0848639
nova.api.openstack.wsgi: Calling method '<bound method Controller.show of <nova.api.openstack.compute.flavors.Controller object at 0x7fbd39a0b910>>'
nova.osapi_compute.wsgi.server:localhost "GET /v2/ecb571eb456242f1af7e37c5190382bd/flavors/42 HTTP/1.1" status: 200 len: 621 time: 0.0289028
nova.api.openstack.wsgi:Calling method '<bound method Controller.show of <nova.api.openstack.compute.images.Controller object at 0x7fbd399f0bd0>>'
nova.osapi_compute.wsgi.server: localhost "GET /v2/ecb571eb456242f1af7e37c5190382bd/images/16f62e95-57b0-4ddd-88ee-2b063ce5f1e3 HTTP/1.1" status: 200 len: 1001 time: 0.1902299</span>
为什么有这些调用呢?上篇博客提到novaclient最后运行了
args.func(self.cs, args)
由于当下是v2.client,所以回到v2.shell.py,有新的发现,这里有各种具体命令的执行,以及参数的检查等等。我们用
# nova show <server-id>
所以检查这个函数,这里就是具体执行show操作代码。
@cliutils.arg(
'--minimal',
dest='minimal',
action="store_true",
default=False,
help=_('Skips flavor/image lookups when showing servers'))
@cliutils.arg('server', metavar='<server>', help=_('Name or ID of server.'))
def do_show(cs, args):
"""Show details about the given server."""
_print_server(cs, args)
直接看_print_server
def _print_server(cs, args, server=None):
# By default when searching via name we will do a
# findall(name=blah) and due a REST /details which is not the same
# as a .get() and doesn't get the information about flavors and
# images. This fix it as we redo the call with the id which does a
# .get() to get all informations.
if not server:
server = _find_server(cs, args.server)
minimal = getattr(args, "minimal", False)
networks = server.networks
info = server._info.copy()
for network_label, address_list in networks.items():
info['%s network' % network_label] = ', '.join(address_list)
flavor = info.get('flavor', {})
flavor_id = flavor.get('id', '')
if minimal:
info['flavor'] = flavor_id
else:
try:
info['flavor'] = '%s (%s)' % (_find_flavor(cs, flavor_id).name,
flavor_id)
except Exception:
info['flavor'] = '%s (%s)' % (_("Flavor not found"), flavor_id)
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'])))
image = info.get('image', {})
if image:
image_id = image.get('id', '')
if minimal:
info['image'] = image_id
else:
try:
info['image'] = '%s (%s)' % (_find_image(cs, image_id).name,
image_id)
except Exception:
info['image'] = '%s (%s)' % (_("Image not found"), image_id)
else: # Booted from volume
info['image'] = _("Attempt to boot from volume - no image supplied")
info.pop('links', None)
info.pop('addresses', None)
utils.print_dict(info)
关键在_find_server这里,_find_server直接挂接到utils.find_resource
def find_resource(manager, name_or_id, **find_args):
"""Helper for the _find_* methods."""
# for str id which is not uuid (for Flavor and Keypair search currently)
if getattr(manager, 'is_alphanum_id_allowed', False):
try:
return manager.get(name_or_id)
except exceptions.NotFound:
pass
# try to get entity as integer id
try:
return manager.get(int(name_or_id))
except (TypeError, ValueError, exceptions.NotFound):
pass
这里可见各种manager.get(),没错,这里的manager就是上篇博客提到的在novaclient中注册的manager。
上篇博客提到novaclient是怎么运行起来的,在novaclient创建过程中,有许多extension的注册
$ vim novaclient/v2/client.py
# extensions
self.agents = agents.AgentsManager(self)
self.dns_domains = floating_ip_dns.FloatingIPDNSDomainManager(self)
self.dns_entries = floating_ip_dns.FloatingIPDNSEntryManager(self)
self.cloudpipe = cloudpipe.CloudpipeManager(self)
self.certs = certs.CertificateManager(self)
self.floating_ips = floating_ips.FloatingIPManager(self)
self.floating_ip_pools = floating_ip_pools.FloatingIPPoolManager(self)
self.fping = fping.FpingManager(self)
self.volumes = volumes.VolumeManager(self)
self.volume_snapshots = volume_snapshots.SnapshotManager(self)
self.volume_types = volume_types.VolumeTypeManager(self)
self.keypairs = keypairs.KeypairManager(self)
self.networks = networks.NetworkManager(self)
self.quota_classes = quota_classes.QuotaClassSetManager(self)
self.quotas = quotas.QuotaSetManager(self)
self.security_groups = security_groups.SecurityGroupManager(self)
self.security_group_rules = \
security_group_rules.SecurityGroupRuleManager(self)
self.security_group_default_rules = \
security_group_default_rules.SecurityGroupDefaultRuleManager(self)
self.usage = usage.UsageManager(self)
self.virtual_interfaces = \
virtual_interfaces.VirtualInterfaceManager(self)
self.aggregates = aggregates.AggregateManager(self)
self.hosts = hosts.HostManager(self)
self.hypervisors = hypervisors.HypervisorManager(self)
self.hypervisor_stats = hypervisors.HypervisorStatsManager(self)
self.services = services.ServiceManager(self)
self.fixed_ips = fixed_ips.FixedIPsManager(self)
self.floating_ips_bulk = floating_ips_bulk.FloatingIPBulkManager(self)
self.os_cache = os_cache or not no_cache
self.availability_zones = \
availability_zones.AvailabilityZoneManager(self)
self.server_groups = server_groups.ServerGroupsManager(self)
命令为nova show <server-id>,
这里我们关注serverManager.
utils.manager.get()调用了novaclient.v2.servers.ServerManager.get()
这里啰嗦一句ServerManager创建过程,
class ServerManager(base.BootingManagerWithFind):
resource_class = Server
def _boot(self, resource_url, response_key, name, image, flavor,
meta=None, files=None, userdata=None,
reservation_id=None, return_raw=False, min_count=None,
max_count=None, security_groups=None, key_name=None,
注意
resource_class定义,这里后面会用到。
def get(self, server):
"""
Get a server.
:param server: ID of the :class:`Server` to get.
:rtype: :class:`Server`
"""
return self._get("/servers/%s" % base.getid(server), "server")
这里的base.getid(server)对应了API中,
servers.Controller.index()
def _get(self, url, response_key):
_resp, body = self.api.client.get(url)
return self.resource_class(self, body[response_key], loaded=True)
在通过server name找到server uuid之后,这里self.api.client.get(url)对应了API中
servers.Controller.show()
注意最后一句的self,resource_class(...),这里就是在ServerManager类中指明的
resource_class = Server
回到_print_server函数,会发现在没有指定 --minimal参数时候,继续寻找image和flavor信息。
至此nova show <server-id>调用完全结束。
这里还有一个问题,在nova show <server-id>时候,API内部extension机制是如何被触发的呢?最直接印象是,我并没有调用security-groups信息,为什么在返回的server info里面会有呢?下篇分解。