• OpenStack点滴02-WSGI


    OpenStack对外提供REST API,那么REST API是如何建立起来的呢?

    OpenStack用了一种叫WSGI(Web Service Gateway Interface)的东西,WSGI是Web服务器与Web应用程序或应用框架之间的一种低级别的接口。

    下面是个简单的例子:

    #!/usr/bin/env python
    
    from wsgiref.simple_server import make_server  
      
    def hello_world_app(environ, start_response):  
        status = '200 OK' # HTTP Status  
        headers = [('Content-type', 'text/plain')] # HTTP Headers  
        start_response(status, headers)  
      
        # The returned object is going to be printed  
        return ["Hello World"]  
      
    httpd = make_server('', 8088, hello_world_app)  
    print "Serving on port 8088..."  
      
    # Serve until process is killed  
    httpd.serve_forever()

    执行这段代码,然后浏览器访问http://localhost:8088就会出现Hello World页面。

    大致流程如下:

     

    (1)Client(上例中浏览器)发送请求到Server。

    (2)Server转发请求给Application(上例中hello_world_app)。注:Server和Application之间还有middleware,此处省略。

    (3)Application进行操作后将相应发送给Server。

    (4)Server再将相应转发给Client。

     

    OpenStack使用WSGI的一个工具包paste来配置WSGI appliaction和server的系统,它的好处是将配置和代码分离。python代码写好后如果想要修改页面到app的映射关系,只需要修改配置文件即可。

    用一个简单的例子来示范paste.deploy的工作机制:

    pastedeploy.ini

    [composite:test_composite]
    use=egg:Paste#urlmap
    /:root
    [pipeline:root] pipeline
    = logrequest showversion
    [filter:logrequest] username
    = root password = root123 paste.filter_factory = pastedeploylab:LogFilter.factory
    [app:showversion] version
    = 1.0.0 paste.app_factory = pastedeploylab:ShowVersion.factory

    app:表示它定义了一个wsgi的application,是一个callable对象。paste. app_factory返回值是一个application对象

    filter:表示这个段定义了一个filter,filter需要完成的工作是将application包装成另一个application(“过滤”),并返回这个包装后的application。

    pipeline:Pipeline 由一些列的filter组成,最后一个是应用,即将前面的fiiter应用到application。

    composite:自己不处理请求,根据映射关系把请求分发到filter、app或者pipeline。/:root就是表示访问url根目录的请求全部分发到root这个pipeline处理

     

    pastedeploy.py

    import os
    import webob
    from webob import Request
    from webob import Response
    from paste.deploy import loadapp
    from wsgiref.simple_server import make_server
    #Filter class LogFilter(): def __init__(self,app): self.app = app pass def __call__(self,environ,start_response): print "filter:LogFilter is called." return self.app(environ,start_response) @classmethod def factory(cls, global_conf, **kwargs): print "in LogFilter.factory", global_conf, kwargs return LogFilter
    class ShowVersion(): def __init__(self): pass def __call__(self,environ,start_response): start_response("200 OK",[("Content-type", "text/plain")]) return ["Paste Deploy LAB: Version = 1.0.0",] @classmethod def factory(cls,global_conf,**kwargs): print "in ShowVersion.factory", global_conf, kwargs return ShowVersion()
    if __name__ == '__main__': configfile="pastedeploy.ini" appname="test_composite" wsgi_app = loadapp("config:%s" % os.path.abspath(configfile), appname) server = make_server('localhost',8080,wsgi_app) server.serve_forever() pass

    执行命令python pastedeploy.py,然后在浏览器中输入http://localhost:8080/就可以在网页输出Paste Deploy LAB: Version = 1.0.0

    下面讲解一下工作流程,运行pastedeploy.py文件,首先会调用loadapp函数加载运用,在配置文件pastedeploy.ini找到appname为test_composite,test_composite是一个composite,然后找到pipeline root,根据pipeline找到filter logrequest和app showversion,logrequest和showversion各自用factory生成callable对象。加载完应用后调用make_server启动服务。

    在浏览器输入http://localhost:8080/就会根据urlmap将请求分发到pipeline root,调用LogFilter的__call__方法,其中app就是ShowVersion,然后调用ShowVersion的__call__方法返回消息。

     

     以下写一个简单的OpenStack WSGI实例,参考了臭蛋的博客,臭蛋写的和OpenStack源码很一致。

    其中用到的一些python库:

    1. paste.deploy 配置WSGI appliaction和server

    2. webob 用来对http请求和响应进行封装

    3. routes 实现URL映射

    4. eventlet.wsgi 或者 wsgiref.simple_server,提供wsgi server功能,后者更简单。

     

    首先建立一个test包,然后在test包里面建立如下文件:

    test-paste.ini

    [composite:test_composite]
    use=egg:Paste#urlmap
    /v1:testapp
    
    [app:testapp]
    paste.app_factory = test.router:API.factory

     

    server.py

    import os
    import logging
    import sys
    from paste import deploy
    from wsgiref.simple_server import make_server
    
    LOG = logging.getLogger(__name__)
    
    module_dir = os.path.normpath(os.path.join(os.path.abspath(sys.argv[0]),
                            os.pardir,os.pardir))
    
    sys.path.insert(0,module_dir)
    
    bind_host = "127.0.0.1"
    bind_port = 8088
    
    def server(app_name, conf_file):
        print "server"
        app = load_paste_app(app_name,conf_file)
        serve = make_server(bind_host,bind_port,app)
        serve.serve_forever()
    
    def load_paste_app(app_name, conf_file):
        print "load_paste_app"
        LOG.debug("Loading %(app_name) from %(conf_file)",
                    {'app_name':app_name, 'conf_file':conf_file})
        
        try:
            app = deploy.loadapp("config:%s" % os.path.abspath(conf_file), name=app_name)
            return app
        except (LookupError, ImportError) as e:
            LOG.error(str(e))
            raise RuntimeError(str(e))
    
    if __name__ == '__main__':
        app_name = "test_composite"
        conf_file = "test-paste.ini"
        server(app_name,conf_file)

     

    wsgi.py

    import logging
    import routes.middleware
    import webob.dec
    import webob.exc
    
    
    class Router(object):
    
        def __init__(self, mapper=None):
            print "Router.__init__"
            self.map =  mapper
            self._router = routes.middleware.RoutesMiddleware(self._dispatch,
                                                             self.map)
        @classmethod
        def factory(cls, global_conf, **local_conf):
            print "Router.__factory__"
            return cls()
    
        @webob.dec.wsgify
        def __call__(self,req):
            print "Router.__call__"
            return self._router
    
        @staticmethod
        @webob.dec.wsgify
        def _dispatch(req):
            print "Router._dispatch"
            # TODO
            match = req.environ['wsgiorg.routing_args'][1]
            if not match:
                return webob.exc.HTTPNotFound()
            app = match['controller']
            return app

     

    router.py

    import routes
    
    from test import wsgi
    from test import versions
    
    class API(wsgi.Router):
    
        def __init__(self, mapper=None):
            print "API.__init__"
            if(mapper == None):
                mapper = routes.Mapper()
            
            versions_resource = versions.create_resource() 
            mapper.connect("/test",controller=versions_resource,
                            action="index")
            super(API,self).__init__(mapper) 

     

    versions.py

    import httplib
    import json
    import webob.dec
    from test import wsgi
    from webob import Response
    
    class Controller(object):
        def __init__(self):
            print "Controller.__init__"
            # TODO
            self.version = "0.1"
    
        def index(self,req):
            print "Controller.index"
            response = Response(request=req,
                                      status=httplib.MULTIPLE_CHOICES,
                                      content_type='application/json')
            response.body = json.dumps(dict(versions=self.version))
            return response
                
        @webob.dec.wsgify
        def __call__(self, request):
            print "Controller.__call__"
            # TODO
            return self.index(request)
    
    def create_resource():
        print "create_resource"
        return Controller()

     @webob.dec.wsgify 装饰器将一个普通函数转变成WSGI应用程序

    执行python server.py , 然后在浏览器输入http://localhost:8088/v1/test 就会出现相关页面。

    由于在函数中加了打印语句,启动时会输出:

    server
    load_paste_app
    Router.__factory__
    API.__init__
    create_resource
    Controller.__init__
    Router.__init__

    访问页面会输出:

    Router.__call__
    Router._dispatch
    Controller.__call__
    Controller.index

     

    这是一个OpenStack WSGI原型,还需完善,比如在router.py文件中,/test并没有和index方法绑定,只是在Controller.__call__方法中静态的调用了index方法。

     

  • 相关阅读:
    stl rope
    vijos1574 摇钱树
    图论 Dijkstra+堆优化
    c++输入优化
    Vijos1579 宿命的PSS 最小生成树
    快速求n阶多项式乘积
    c++stl map
    C#函数式程序设计之惰性列表工具——迭代器
    C#函数式程序设计之泛型(下)
    C#函数式程序设计之泛型(上)
  • 原文地址:https://www.cnblogs.com/gorlf/p/4350764.html
Copyright © 2020-2023  润新知