分享

cinderclient源码解析之二

shihailong123 发表于 2014-11-22 19:22:05 [显示全部楼层] 回帖奖励 阅读模式 关闭右栏 0 14940
问题导读
1、卷的查询命令cinder list在什么执行过程中分析完成?
2、当执行命令行cinder list时,调用什么方法?
3、什么是对应的传入参数POST或GET?




上一篇:cinderclient源码解析之一


我们接续上一片博客,来继续解析cinderclient的源代码。
上篇博客中说到在/python-cinderclient/cinderclient/shell.py----mian方法的最后,执行了语句args.func(self.cs, args),实现根据命令行参数的解析调用具体的方法,输出示例为args.func = do_list,说明当执行命令行cinder list时,这里调用的方法为do_list。
具体来看代码,/python-cinderclient/cinderclient/v1/shell.py----do_list(cs, args):
  1. @utils.service_type('volume')
  2. def do_list(cs, args):
  3.     """
  4.     List all the volumes.
  5.     实现列出所有的卷操作;
  6.     """
  7.     all_tenants = int(os.environ.get("ALL_TENANTS", args.all_tenants))
  8.     search_opts = {
  9.         'all_tenants': all_tenants,
  10.         'display_name': args.display_name,
  11.         'status': args.status,
  12.         'metadata': _extract_metadata(args) if args.metadata else None,
  13.     }
  14.     volumes = cs.volumes.list(search_opts=search_opts)
  15.     _translate_volume_keys(volumes)
  16.     # Create a list of servers to which the volume is attached
  17.     for vol in volumes:
  18.         servers = [s.get('server_id') for s in vol.attachments]
  19.         setattr(vol, 'attached_to', ','.join(map(str, servers)))
  20.     utils.print_list(volumes, ['ID', 'Status', 'Display Name',
  21.                      'Size', 'Volume Type', 'Bootable', 'Attached to'])
复制代码


首先来看语句
  1. volumes = cs.volumes.list(search_opts=search_opts)
复制代码


其中cs已经定位了类/python-cinderclient/cinderclient/v1/client.py----class Client(object),在其类的初始化方法中我们可以看到变量self.volumes = volumes.VolumeManager(self),定位到类/python-cinderclient/cinderclient/v1/volumes.py----class VolumeManager(base.ManagerWithFind)
从而可以知道,语句volumes = cs.volumes.list(search_opts=search_opts)所实现调用的方法为/python-cinderclient/cinderclient/v1/volumes.py----class VolumeManager(base.ManagerWithFind)----def list(self, detailed=True, search_opts=None),我们来看方法list的具体代码:
  1.     def list(self, detailed=True, search_opts=None):
  2.         """
  3.         ***********************************************
  4.         Get a list of all volumes.
  5.         获取包含所有卷的列表;
  6.         :rtype: list of :class:`Volume`
  7.         """
  8.         if search_opts is None:
  9.             search_opts = {}
  10.         qparams = {}
  11.         for opt, val in six.iteritems(search_opts):
  12.             if val:
  13.                 qparams[opt] = val
  14.         query_string = "?%s" % urlencode(qparams) if qparams else ""
  15.         detail = ""
  16.         if detailed:
  17.             detail = "/detail"
  18.             
  19.         # /cinderclient/base.py----class Manager(utils.HookableMixin):
  20.         # def _list(self, url, response_key, obj_class=None, body=None):
  21.         return self._list("/volumes%s%s" % (detail, query_string),
  22.                           "volumes")
复制代码


在这个方法中,前面都是进行的一些列参数解析操作,重点来看语句:
  1. return self._list("/volumes%s%s" % (detail, query_string),
  2.                           "volumes")
复制代码


这里调用了方法/python-cinderclient/cinderclient/base.py----class Manager(utils.HookableMixin)----def _list(self, url, response_key, obj_class=None, body=None),
具体来看代码:
  
  1. def _list(self, url, response_key, obj_class=None, body=None):
  2.         resp = None
  3.         if body:
  4.             resp, body = self.api.client.post(url, body=body)
  5.         else:
  6.             resp, body = self.api.client.get(url)
  7.         if obj_class is None:
  8.             obj_class = self.resource_class
  9.         data = body[response_key]
  10.         # NOTE(ja): keystone returns values as list as {'values': [ ... ]}
  11.         #           unlike other services which just return the list...
  12.         if isinstance(data, dict):
  13.             try:
  14.                 data = data['values']
  15.             except KeyError:
  16.                 pass
  17.         with self.completion_cache('human_id', obj_class, mode="w"):
  18.             with self.completion_cache('uuid', obj_class, mode="w"):
  19.                 return [obj_class(self, res, loaded=True)
  20.                         for res in data if res]
复制代码


这里来看代码:
  1.         if body:
  2.             resp, body = self.api.client.post(url, body=body)
  3.         else:
  4.             resp, body = self.api.client.get(url)
复制代码
对于resp, body = self.api.client.post(url, body=body),
这里调用了方法/python-cinderclient/cinderclient/client.py----class HTTPClient(object)----def post(self, url, **kwargs),
详细代码如下:
  1.     def post(self, url, **kwargs):
  2.         return self._cs_request(url, 'POST', **kwargs)
复制代码


对于resp, body = self.api.client.get(url),
这里调用了方法/python-cinderclient/cinderclient/client.py----class HTTPClient(object)----def get(self, url, **kwargs):,
详细代码如下:
  1.     def get(self, url, **kwargs):
  2.         return self._cs_request(url, 'GET', **kwargs)
复制代码


可见,在post方法和get方法中都进一步调用了方法_cs_request,并且对应的传入可参数POST或GET,具体来看方法/python-cinderclient/cinderclient/client.py----class HTTPClient(object)----def _cs_request(self, url, method, **kwargs)的实现:
  1.     def _cs_request(self, url, method, **kwargs):
  2.         auth_attempts = 0
  3.         attempts = 0
  4.         backoff = 1
  5.         while True:
  6.             attempts += 1
  7.             if not self.management_url or not self.auth_token:
  8.                 self.authenticate()
  9.             kwargs.setdefault('headers', {})['X-Auth-Token'] = self.auth_token
  10.             if self.projectid:
  11.                 kwargs['headers']['X-Auth-Project-Id'] = self.projectid
  12.             try:
  13.                 resp, body = self.request(self.management_url + url, method, **kwargs)
  14.                 return resp, body
  15.             except exceptions.BadRequest as e:
  16.                 if attempts > self.retries:
  17.                     raise
  18.             except exceptions.Unauthorized:
  19.                 if auth_attempts > 0:
  20.                     raise
  21.                 self._logger.debug("Unauthorized, reauthenticating.")
  22.                 self.management_url = self.auth_token = None
  23.                 # First reauth. Discount this attempt.
  24.                 attempts -= 1
  25.                 auth_attempts += 1
  26.                 continue
  27.             except exceptions.ClientException as e:
  28.                 if attempts > self.retries:
  29.                     raise
  30.                 if 500
复制代码



来看最重要的一条语句:
  1. resp, body = self.request(self.management_url + url, method, **kwargs)
复制代码

这里调用了方法request,并传入了相关参数,执行相应的操作,并从服务器端获取相应的响应返回值。有输出示例如:
  1. self.management_url + url: http://172.21.5.164:8776/v1/55d34f8573ed4ac19379a0d80afca4bf/volumes/detail
  2. method: GET
  3. kwargs: {'headers': {'X-Auth-Project-Id': 'admin', 'User-Agent': 'python-cinderclient', 'Accept': 'application/json', 'X-Auth-Token': u'MIISwwYJKoZIhvcNAQcCoIIStDCCErA......PQ=='}}
复制代码

具体来看方法/python-cinderclient/cinderclient/client.py----class HTTPClient(object)----def request(self, url, method, **kwargs):
  1. def request(self, url, method, **kwargs):
  2.         kwargs.setdefault('headers', kwargs.get('headers', {}))
  3.         kwargs['headers']['User-Agent'] = self.USER_AGENT
  4.         kwargs['headers']['Accept'] = 'application/json'
  5.         if 'body' in kwargs:
  6.             kwargs['headers']['Content-Type'] = 'application/json'
  7.             kwargs['data'] = json.dumps(kwargs['body'])
  8.             del kwargs['body']
  9.         if self.timeout:
  10.             kwargs.setdefault('timeout', self.timeout)
  11.         self.http_log_req((url, method,), kwargs)
  12.         resp = requests.request(
  13.             method,
  14.             url,
  15.             verify=self.verify_cert,
  16.             **kwargs)
  17.         self.http_log_resp(resp)
  18.         if resp.text:
  19.             try:
  20.                 body = json.loads(resp.text)
  21.             except ValueError:
  22.                 pass
  23.                 body = None
  24.         else:
  25.             body = None
  26.         if resp.status_code >= 400:
  27.             raise exceptions.from_response(resp, body)
  28.         return resp, body
复制代码

来看这里最重要的一段代码:
  1. resp = requests.request(
  2.             method,
  3.             url,
  4.             verify=self.verify_cert,
  5.             **kwargs)
复制代码

来看输出示例:
  1. method = GET
  2. url = http://172.21.5.164:8776/v1/55d34f8573ed4ac19379a0d80afca4bf/volumes/detail
  3. verify = True
  4. kwargs = {'headers': {'X-Auth-Project-Id': 'admin', 'User-Agent': 'python-cinderclient', 'Accept': 'application/json', 'X-Auth-Token': u'MIISwwYJKoZIhvcNAQcCoIIStDCCErA......PQ=='}}
复制代码

这里应用了python中的requests库,具体调用的方法是/requests/api.py----def request(method, url, **kwargs):
  1. def request(method, url, **kwargs):
  2.     """Constructs and sends a :class:`Request `.
  3.     Returns :class:`Response ` object.
  4.     :param method: method for the new :class:`Request` object.
  5.     :param url: URL for the new :class:`Request` object.
  6.     :param params: (optional) Dictionary or bytes to be sent in the query string for the :class:`Request`.
  7.     :param data: (optional) Dictionary, bytes, or file-like object to send in the body of the :class:`Request`.
  8.     :param headers: (optional) Dictionary of HTTP Headers to send with the :class:`Request`.
  9.     :param cookies: (optional) Dict or CookieJar object to send with the :class:`Request`.
  10.     :param files: (optional) Dictionary of 'name': file-like-objects (or {'name': ('filename', fileobj)}) for multipart encoding upload.
  11.     :param auth: (optional) Auth tuple to enable Basic/Digest/Custom HTTP Auth.
  12.     :param timeout: (optional) Float describing the timeout of the request.
  13.     :param allow_redirects: (optional) Boolean. Set to True if POST/PUT/DELETE redirect following is allowed.
  14.     :param proxies: (optional) Dictionary mapping protocol to the URL of the proxy.
  15.     :param verify: (optional) if ``True``, the SSL cert will be verified. A CA_BUNDLE path can also be provided.
  16.     :param stream: (optional) if ``False``, the response content will be immediately downloaded.
  17.     :param cert: (optional) if String, path to ssl client cert file (.pem). If Tuple, ('cert', 'key') pair.
  18.     Usage::
  19.       >>> import requests
  20.       >>> req = requests.request('GET', 'http://httpbin.org/get')
  21.       
  22.     """
  23.     session = sessions.Session()
  24.     return session.request(method=method, url=url, **kwargs)
复制代码

这个库遵循HTTP协议,实现了访问远程服务器,并获取相应的响应信息的功能,本文在这里就不深入展开了。
本文是以命令行cinder list为例,所以从服务器端获取相关卷的信息的返回值后,会在方法/python-cinderclient/cinderclient/base.py----class Manager(utils.HookableMixin)----def _list(self, url, response_key, obj_class=None, body=None)中进行解析并进行打印输出,得到卷的列表信息。
至此,卷的查询命令cinder list在cinderclient中执行过程分析完成,后面一片博客我将会简单总结cinderclient中的源码结构。





作者:溜溜小哥
本文转载自:http://blog.csdn.net/gaoxingnengjisuan



没找到任何评论,期待你打破沉寂

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

关闭

推荐上一条 /2 下一条