OpenStack之Glance源码简析

  Glance简介

  OpenStack镜像服务器是一套虚拟机镜像发现、注册、检索

  glance架构图:

  

  Glance源码结构:

  

  glance/api:主要负责接收响应镜像管理命令的Restful请求,分析消息请求信息并分发其所带的命令(如新增,删除,更新等)。默认绑定端口是9292。

  glance/registry:主要负责接收响应镜像元数据命令的Restful请求。分析消息请求信息并分发其所带的命令(如获取元数据,更新元数据等)。默认绑定的端口是9191。

  glance/db:主要负责与数据库Mysql的交互

  glance/store:主要负责存储适配

  本次主要从简单的查询来简析glance源码,看一下glance代码是如何执行的。

  查询的API:/v1/images/detail,method:GET,有兴趣的朋友可以用火狐浏览器自带的RESTClient来进行REST服务的测试。

  好了,废话不多说,源码走起。

  源码分析

     图为glance/api/v1中的源码目录树。

   此次就从glance的查询来分析glance的源码,从horizon的传过来的HTTP请求首先来到glance/api/v1/router.py中,查找匹配的HTTP请求:

    代码如下:   

1 mapper.connect("/images/detail",
2                        controller=images_resource,
3                        action='detail',
4                        conditions={'method': ['GET']})

    可以看到,这与Glance的API文档是相符的,GET请求,然后是/v1/images/detail。

    而后,找到匹配的请求之后,就会进入glance/api/v1/images.py文件中,下面是有关的代码:  

 1 def detail(self, req):
 2         """
 3         Returns detailed information for all available images
 4 
 5         :param req: The WSGI/Webob Request object
 6         :retval The response body is a mapping of the following form::
 7 
 8             {'images': [
 9                 {'id': <ID>,
10                  'name': <NAME>,
11                  'size': <SIZE>,
12                  'disk_format': <DISK_FORMAT>,
13                  'container_format': <CONTAINER_FORMAT>,
14                  'checksum': <CHECKSUM>,
15                  'min_disk': <MIN_DISK>,
16                  'min_ram': <MIN_RAM>,
17                  'store': <STORE>,
18                  'status': <STATUS>,
19                  'created_at': <TIMESTAMP>,
20                  'updated_at': <TIMESTAMP>,
21                  'deleted_at': <TIMESTAMP>|<NONE>,
22                  'properties': {'distro': 'Ubuntu 10.04 LTS', ...}}, ...
23             ]}
24         """
25         self._enforce(req, 'get_images')
26         params = self._get_query_params(req)
27         try:
28             images = registry.get_images_detail(req.context, **params)
29             # Strip out the Location attribute. Temporary fix for
30             # LP Bug #755916. This information is still coming back
31             # from the registry, since the API server still needs access
32             # to it, however we do not return this potential security
33             # information to the API end user...
34             for image in images:
35                 redact_loc(image, copy_dict=False)
36                 self._enforce_read_protected_props(image, req)
37         except exception.Invalid as e:
38             raise HTTPBadRequest(explanation="%s" % e)
39         return dict(images=images)

   26行是根据获取查询条件,在此不深入谈,想了解的朋友可以留言,主要查询语句在try里面,也就是第28行: 

1 images = registry.get_images_detail(req.context, **params)

  从这里,查询就跳入了glance/registry/client/v1/api.py文件中。

 

  图为glance/registry的目录树,glance/registry/client/v1/api.py中相关代码如下: 

1 def get_images_detail(context, **kwargs):
2     c = get_registry_client(context)
3     return c.get_images_detailed(**kwargs)

  首先,会在glance/registry/client/v1/api.py文件进行registry端口的认证连接, 

 1 def get_registry_client(cxt):
 2     global _CLIENT_CREDS, _CLIENT_KWARGS, _CLIENT_HOST, _CLIENT_PORT
 3     global _METADATA_ENCRYPTION_KEY
 4     kwargs = _CLIENT_KWARGS.copy()
 5     if CONF.use_user_token:
 6         kwargs['auth_tok'] = cxt.auth_tok
 7     if _CLIENT_CREDS:
 8         kwargs['creds'] = _CLIENT_CREDS
 9 
10     if CONF.send_identity_headers:
11         identity_headers = {
12             'X-User-Id': cxt.user,
13             'X-Tenant-Id': cxt.tenant,
14             'X-Roles': ','.join(cxt.roles),
15             'X-Identity-Status': 'Confirmed',
16             'X-Service-Catalog': jsonutils.dumps(cxt.service_catalog),
17         }
18         kwargs['identity_headers'] = identity_headers
19     return client.RegistryClient(_CLIENT_HOST, _CLIENT_PORT,
20                                  _METADATA_ENCRYPTION_KEY, **kwargs)

  然后第三行返回查询,进入glance/registry/client/v1/client.py中: 

 1 def get_images_detailed(self, **kwargs):
 2         """
 3         Returns a list of detailed image data mappings from Registry
 4 
 5         :param filters: dict of keys & expected values to filter results
 6         :param marker: image id after which to start page
 7         :param limit: max number of images to return
 8         :param sort_key: results will be ordered by this image attribute
 9         :param sort_dir: direction in which to to order results (asc, desc)
10         """
11         params = self._extract_params(kwargs, images.SUPPORTED_PARAMS)
12         res = self.do_request("GET", "/images/detail", params=params)
13         image_list = jsonutils.loads(res.read())['images']
14         for image in image_list:
15             image = self.decrypt_metadata(image)
16         return image_list

  在12行再次发出请求,然后在glance/registry/api/v1/__init__.py中查找匹配的请求:  

1 mapper.connect("/images/detail",
2                        controller=images_resource,
3                        action="detail",
4                        conditions={'method': ['GET']})

  在glance/registry/api/v1/images.py中找到相应的方法进行查询:

 1 def detail(self, req):
 2         """Return a filtered list of public, non-deleted images in detail
 3 
 4         :param req: the Request object coming from the wsgi layer
 5         :retval a mapping of the following form::
 6 
 7             dict(images=[image_list])
 8 
 9         Where image_list is a sequence of mappings containing
10         all image model fields.
11         """
12         params = self._get_query_params(req)
13 
14         images = self._get_images(req.context, **params)
15         image_dicts = [make_image_dict(i) for i in images]
16         LOG.info(_("Returning detailed image list"))
17         return dict(images=image_dicts)

  第14行又调用glance/registry/api/v1/images.py的_get_images(req.context, **params)方法:

 1 def _get_images(self, context, filters, **params):
 2         """Get images, wrapping in exception if necessary."""
 3         # NOTE(markwash): for backwards compatibility, is_public=True for
 4         # admins actually means "treat me as if I'm not an admin and show me
 5         # all my images"
 6         if context.is_admin and params.get('is_public') is True:
 7             params['admin_as_user'] = True
 8             del params['is_public']
 9         try:
10             return self.db_api.image_get_all(context, filters=filters,
11                                              **params)
12         except exception.NotFound:
13             LOG.info(_("Invalid marker. Image %(id)s could not be "
14                        "found.") % {'id': params.get('marker')})
15             msg = _("Invalid marker. Image could not be found.")
16             raise exc.HTTPBadRequest(explanation=msg)
17         except exception.Forbidden:
18             LOG.info(_("Access denied to image %(id)s but returning "
19                        "'not found'") % {'id': params.get('marker')})
20             msg = _("Invalid marker. Image could not be found.")
21             raise exc.HTTPBadRequest(explanation=msg)
22         except Exception:
23             LOG.exception(_("Unable to get images"))
24             raise

  在第10行中,进入glance/db/sqlalchemy/api.py中:

 

   图为glance/db的目录树。下面是调用的glance/db/sqlalchemy/api.py中的image_get_all方法,

  

 1 def image_get_all(context, filters=None, marker=None, limit=None,
 2                   sort_key='created_at', sort_dir='desc',
 3                   member_status='accepted', is_public=None,
 4                   admin_as_user=False):
 5     """
 6     Get all images that match zero or more filters.
 7 
 8     :param filters: dict of filter keys and values. If a 'properties'
 9                     key is present, it is treated as a dict of key/value
10                     filters on the image properties attribute
11     :param marker: image id after which to start page
12     :param limit: maximum number of images to return
13     :param sort_key: image attribute by which results should be sorted
14     :param sort_dir: direction in which results should be sorted (asc, desc)
15     :param member_status: only return shared images that have this membership
16                           status
17     :param is_public: If true, return only public images. If false, return
18                       only private and shared images.
19     :param admin_as_user: For backwards compatibility. If true, then return to
20                       an admin the equivalent set of images which it would see
21                       if it were a regular user
22     """
23     filters = filters or {}
24 
25     visibility = filters.pop('visibility', None)
26     showing_deleted = 'changes-since' in filters or filters.get('deleted',
27                                                                 False)
28 
29     img_conditions, prop_conditions, tag_conditions = 
30         _make_conditions_from_filters(filters, is_public)
31 
32     query = _select_images_query(context,
33                                  img_conditions,
34                                  admin_as_user,
35                                  member_status,
36                                  visibility)
37 
38     if visibility is not None:
39         if visibility == 'public':
40             query = query.filter(models.Image.is_public == True)
41         elif visibility == 'private':
42             query = query.filter(models.Image.is_public == False)
43 
44     if prop_conditions:
45         for prop_condition in prop_conditions:
46             query = query.join(models.ImageProperty, aliased=True)
47                 .filter(sa_sql.and_(*prop_condition))
48 
49     if tag_conditions:
50         for tag_condition in tag_conditions:
51             query = query.join(models.ImageTag, aliased=True)
52                 .filter(sa_sql.and_(*tag_condition))
53 
54     marker_image = None
55     if marker is not None:
56         marker_image = _image_get(context,
57                                   marker,
58                                   force_show_deleted=showing_deleted)
59 
60     sort_keys = ['created_at', 'id']
61     sort_keys.insert(0, sort_key) if sort_key not in sort_keys else sort_keys
62 
63     query = _paginate_query(query, models.Image, limit,
64                             sort_keys,
65                             marker=marker_image,
66                             sort_dir=sort_dir)
67 
68     query = query.options(sa_orm.joinedload(models.Image.properties))
69                  .options(sa_orm.joinedload(models.Image.locations))
70 
71     return [_normalize_locations(image.to_dict()) for image in query.all()]

  此方法最后将查询结果返回字典,至此,glance查询方法就此结束。

  如果有不对的地方,欢迎各位大神指出。

PS:本博客欢迎转发,但请注明博客地址及作者~

  博客地址:http://www.cnblogs.com/voidy/

  <。)#)))≦

评论
原文地址:https://www.cnblogs.com/voidy/p/3984868.html