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/
<。)#)))≦