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