使用过heat的朋友都应该利用过heatclient查询stack信息。
例如stack-show命令,该命令的参数如下:
heat stack-show <NAME or ID>
也就是既可以用stack名,也可以用stack ID,来指定要查询的stack。
期初以为是heat engine在处理show_stack请求时进行了区分。
但是通过查看相关代码,发现并不是这样。
传递到EngineService.show_stack的参数stack_identity已经包含了stack_name和stack_id。
这说明heatclient在调用查询请求前,将单独的stack_name或stack_id进行了转换。
打开调试命令执行stack-show命令,相关流程如下:
DEBUG (connectionpool) "GET /v1/c4df22dc73ef478190e1cc80f01219ce/stacks/stack111 HTTP/1.1" 302 195
DEBUG (session) RESP: [302] Content-Length: 195 Connection: keep-alive Location: http://192.168.98.248:8004/v1/c4df22dc73ef478190e1cc80f01219ce/stacks/stack111/eb9e2e45-a2b4-4d43-aaaa-06da51e63bdb Date: Thu, 29 Oct 2015 08:42:34 GMT Content-Type: text/plain; charset=UTF-8 X-Openstack-Request-Id: req-31862d02-54ef-4209-9f7c-5a5c218de881
RESP BODY: 302 Found
The resource was found at http://192.168.98.248:8004/v1/c4df22dc73ef478190e1cc80f01219ce/stacks/stack111/eb9e2e45-a2b4-4d43-aaaa-06da51e63bdb; you should be redirected automatically.
DEBUG (connectionpool) "GET /v1/c4df22dc73ef478190e1cc80f01219ce/stacks/stack111/eb9e2e45-a2b4-4d43-aaaa-06da51e63bdb HTTP/1.1" 200 883
DEBUG (session) RESP: [200] Date: Thu, 29 Oct 2015 08:42:34 GMT Connection: keep-alive Content-Type: application/json; charset=UTF-8 Content-Length: 883 X-Openstack-Request-Id: req-64cd9d04-d4ad-4fbe-84db-fdbcbeefd24b
从请求响应流程上可以看出,client向service发起了两次请求:
第一次发送的“GET /v1/c4df22dc73ef478190e1cc80f01219ce/stacks/stack111”
第二次发送的“GET /v1/c4df22dc73ef478190e1cc80f01219ce/stacks/stack111/eb9e2e45-a2b4-4d43-aaaa-06da51e63bdb”
查看heat API的路由定义,发现/{tenant_id}/stacks/{stack_name}这种格式的url调用的函数是StackController.lookup。
此函数返回HTTPFound结果,里面包含了完整的stack url,即前面打印信息中的Location字段。
而第二次请求的url格式/{tenant_id}/stacks/{stack_name}/{stack_id},在路由定义中才是真正调用的StackController.show。
说明client是利用返回的完整url再次发送了GET请求。
那么client是在哪里第二次发送的GET请求呢?就在client处理HTTP请求的逻辑中。
查看HTTPClient._http_request函数,在判断请求结果时,有一段逻辑:
elif resp.status_code in (301, 302, 305):
# Redirected. Reissue the request to the new location,
# unless caller specified redirect=False
if redirect:
location = resp.headers.get('location')
path = self.strip_endpoint(location)
resp = self._http_request(path, method, **kwargs)
这里就是判断是否需要重发请求,如果是,就利用返回的location重发。
前面的stack-show命令例子中,第一次请求的返回错误码就是302,所以又以完整url发送了第二次请求,获取了最终的结果。