OpenStack之Glance源码简析

  Glance简介

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

  glance架构图:

  OpenStack之Glance源码简析

  Glance源码结构:

  OpenStack之Glance源码简析

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

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

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

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

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

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

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

  源码分析

 

OpenStack之Glance源码简析

     图为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文件中。

 OpenStack之Glance源码简析

  图为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中:

 OpenStack之Glance源码简析

   图为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/

  <。)#)))≦

你可能感兴趣的:(openstack)