前面分析了keystone服务的启动工作,那启动后我们是怎么通过WSGI接口访问其中的服务的呢?
keystone-paste.ini配置文件最下面
[composite:main]
use = egg:Paste#urlmap
/v2.0 = public_api
[composite:admin]
use = egg:Paste#urlmap
/v2.0 = admin_api
一般调用keystone v2.0版本的api的请求路径为http://192.168.1.x:5000/v2.0/xxxxxxx(public endpoint)和http://192.168.1.x:35357/v2.0/xxxxx(admin port)
admin和public的处理方式都是一样的,只不过权限不同,这里只分析public_api的流程,keystone-paste.ini的流程如下
[pipeline:public_api]
pipeline = access_log sizelimit url_normalize token_auth admin_token_auth xml_body json_body ec2_extension user_crud_extension public_service
pastedeploy过滤流程如下
[filter:access_log]
paste.filter_factory = keystone.contrib.access:AccessLogMiddleware.factory
[filter:sizelimit]
paste.filter_factory = keystone.middleware:RequestBodySizeLimiter.factory
[filter:url_normalize]
paste.filter_factory = keystone.middleware:NormalizingFilter.factory
[filter:token_auth]
paste.filter_factory = keystone.middleware:TokenAuthMiddleware.factory
[filter:admin_token_auth]
paste.filter_factory = keystone.middleware:AdminTokenAuthMiddleware.factory
[filter:xml_body]
paste.filter_factory = keystone.middleware:XmlBodyMiddleware.factory
[filter:json_body]
paste.filter_factory = keystone.middleware:JsonBodyMiddleware.factory
[filter:ec2_extension]
paste.filter_factory = keystone.contrib.ec2:Ec2Extension.factory
[filter:user_crud_extension]
paste.filter_factory = keystone.contrib.user_crud:CrudExtension.factory
[app:public_service]
paste.app_factory = keystone.service:public_app_factory
一个一个来分析
首先是keystone.contrib.access:AccessLogMiddleware.factory
keystone.contrib.access模块下有两个文件init.py,core.py,init.py只有一行代码
from keystone.contrib.access.core import *
显而易见,关键代码在core.py中,core.py代码如下
CONF = config.CONF
LOG = logging.getLogger('access')
APACHE_TIME_FORMAT = '%d/%b/%Y:%H:%M:%S'
APACHE_LOG_FORMAT = (
'%(remote_addr)s - %(remote_user)s [%(datetime)s] "%(method)s %(url)s '
'%(http_version)s" %(status)s %(content_length)s')
class AccessLogMiddleware(wsgi.Middleware):
"""Writes an access log to INFO."""
@webob.dec.wsgify
def __call__(self, request):
data = {
'remote_addr': request.remote_addr,
'remote_user': request.remote_user or '-',
'method': request.method,
'url': request.url,
'http_version': request.http_version,
'status': 500,
'content_length': '-'}
try:
response = request.get_response(self.application)
data['status'] = response.status_int
data['content_length'] = len(response.body) or '-'
finally:
# must be calculated *after* the application has been called
now = timeutils.utcnow()
# timeutils may not return UTC, so we can't hardcode +0000
data['datetime'] = '%s %s' % (now.strftime(APACHE_TIME_FORMAT),
now.strftime('%z') or '+0000')
LOG.info(APACHE_LOG_FORMAT % data)
return response
class Middleware(Application): """Base WSGI middleware. These classes require an application to be initialized that will be called next. By default the middleware will simply call its wrapped app, or you can override __call__ to customize its behavior. """ @classmethod d#wsgi.Middleware类在keystone.commone下