设为首页 收藏本站
查看: 817|回复: 0

[经验分享] Cloud in Action: Prepare for OpenStack Code

[复制链接]

尚未签到

发表于 2018-5-30 12:22:40 | 显示全部楼层 |阅读模式
   Cloud in Action: Prepare for OpenStack Code
  

   薛国锋    xueguofeng2011@gmail.com
  
  Deploying OpenStack manually can tell you the flow and configuration details, while learning and debugging OpenStack code can greatly help you understand how OpenStack really works. As the leading open-source software platform for cloud computing and in order to prevent from reinventing the wheel,the OpenStack community has adopted many open-source frameworks, middlewares, libraries and tools for its implementation, such as Setuptools, WSGI, Eventlet,Paste Deploy, Routes and Webob etc; without a deep understanding of them, going to Openstack code directly would be a terrible and frustrating experience.Today we will have a quick review of these softwares and tools, and make uswell prepared for the next step – learning and debugging OpenStack code.  
  

  
  Setuptools
  
  Setuptools is a package development process library designedto facilitate packaging Python projects by enhancing the Python standard library Distutils (distribution utilities). It includes: Python package and module definitions; distribution package metadata; test hooks; project installation; platform-specific details and Python 3 support (similar to Mavenin Java).
  
  Setup.py is a python file, which usually tells you that the module/package you are about to install has been packaged and distributed with Distutils,which is the standard for distributing Python Modules. The __init__.py files are required to make Python treat the directories as containing packages; in the simplest case, __init__.py can just be an empty file, but it can also execute initialization code for the package or set the __all__ variable. A"Python egg", the same concept as a .jar in Java, is a logical structure embodying the release of a specific version of a Python project,comprising its code, resources, and metadata.
  

  //////////////////// Build a Python packagein ‘Host A’
  
  // Install Setuptools
  gset@ubuntu:~$ sudo apt-get install python-setuptools
  
  // Create the below directory and files
  gset@ubuntu:~/test$tree
  .
  ├── setup.py
  └──src
      └── helloworld
          ├── aaa.txt
          ├──data
             ├── abc.dat
             └── abcd.dat
          ├── __init__.py
          ├── moda.py
          └── modb.py
  3 directories, 7 files
  
  gset@ubuntu:~/test$gedit setup.py
  from setuptools import setup, find_packages
  
  setup(
      name ="helloworld",
      version ="1.0",
      packages =find_packages('src'),
      package_dir ={'':'src'},   
      package_data = {
          '': ['*.txt'],
          'helloworld':['data/*.dat'],
      },
      entry_points = {
         'console_scripts': [
              'xgf =helloworld:test'
          ]
      },
      author = 'Richard',
      license = 'PSF'
  )
  
  gset@ubuntu:~/test$ gedit src/helloworld/__init__.py
  #!/usr/bin/env python
  #-*- coding:utf-8 -*-
  def test():
      print "helloworld!"  
  if __name__ == '__main__':
      test()
  
  gset@ubuntu:~/test$python setup.py sdist
  
  gset@ubuntu:~/test$tree
  .
  ├── dist
     └──helloworld-1.0.tar.gz
  ├── setup.py
  └── src
      ├── helloworld
         ├── aaa.txt
         ├── data
            ├── abc.dat
            └── abcd.dat
         ├── __init__.py
         ├── moda.py
         └── modb.py
      └──helloworld.egg-info
          ├──dependency_links.txt
          ├──entry_points.txt
          ├── PKG-INFO
          ├── SOURCES.txt
          └── top_level.txt
  5 directories, 13 files
  
  gset@ubuntu:~/test$file dist/helloworld-1.0.tar.gz
  dist/helloworld-1.0.tar.gz: gzip compressed data, was"dist/helloworld-1.0.tar", last modified: Sun Nov  5 14:42:44 2017, max compression
  
  gset@ubuntu:~/test$tar -tf dist/helloworld-1.0.tar.gz
  helloworld-1.0/
  helloworld-1.0/PKG-INFO
  helloworld-1.0/setup.cfg
  helloworld-1.0/src/
  helloworld-1.0/src/helloworld.egg-info/
  helloworld-1.0/src/helloworld.egg-info/PKG-INFO
  helloworld-1.0/src/helloworld.egg-info/entry_points.txt
  helloworld-1.0/src/helloworld.egg-info/SOURCES.txt
  helloworld-1.0/src/helloworld.egg-info/top_level.txt
  helloworld-1.0/src/helloworld.egg-info/dependency_links.txt
  helloworld-1.0/src/helloworld/
  helloworld-1.0/src/helloworld/modb.py
  helloworld-1.0/src/helloworld/moda.py
  helloworld-1.0/src/helloworld/aaa.txt
  helloworld-1.0/src/helloworld/__init__.py
  helloworld-1.0/src/helloworld/data/
  helloworld-1.0/src/helloworld/data/abcd.dat
  helloworld-1.0/src/helloworld/data/abc.dat
  helloworld-1.0/setup.py
  

  ////////////////////  Install and use the Python package in ‘Host B’
  
  // Copy helloworld-1.0.tar.gz from ‘Host A’ to ‘Host B’, and unzip it
  gset@ubuntu:~/demo/helloworld-1.0$tree
  .
  ├── PKG-INFO
  ├──setup.cfg
  ├──setup.py
  └── src
      ├── helloworld
         ├── aaa.txt
         ├── data
            ├── abc.dat
            └── abcd.dat
         ├── __init__.py
         ├── moda.py
         └── modb.py
      └──helloworld.egg-info
          ├──dependency_links.txt
          ├──entry_points.txt
          ├── PKG-INFO
          ├── SOURCES.txt
          └── top_level.txt
  4 directories, 14 files
  
  // Install the package
  gset@ubuntu:~/demo/helloworld-1.0$sudo python setup.py install
  gset@ubuntu:~/demo/helloworld-1.0$tree
  .
  ├── build
     ├── bdist.linux-x86_64
     └── lib.linux-x86_64-2.7
         └── helloworld
             ├── aaa.txt
             ├── data
                ├── abc.dat
                └── abcd.dat
             ├── __init__.py
             ├── moda.py
             └── modb.py
  ├── dist
     └── helloworld-1.0-py2.7.egg
  ├── PKG-INFO
  ├── setup.cfg
  ├── setup.py
  └── src
      ├── helloworld
         ├── aaa.txt
         ├── data
            ├── abc.dat
            └── abcd.dat
         ├── __init__.py
         ├── moda.py
         └── modb.py
      └──helloworld.egg-info
          ├──dependency_links.txt
          ├──entry_points.txt
          ├── PKG-INFO
          ├── SOURCES.txt
          └── top_level.txt
  10 directories, 21 files
  
  gset@ubuntu:~/demo/helloworld-1.0$ unzip -l/usr/local/lib/python2.7/dist-packages/helloworld-1.0-py2.7.egg
  Archive:  /usr/local/lib/python2.7/dist-packages/helloworld-1.0-py2.7.egg
    Length      Date   Time    Name
  ---------  ---------------   ----
          1  2017-11-05 06:49   EGG-INFO/zip-safe
          1  2017-11-05 06:49   EGG-INFO/dependency_links.txt
         41  2017-11-05 06:49   EGG-INFO/entry_points.txt
        364  2017-11-05 06:49   EGG-INFO/SOURCES.txt
        178  2017-11-05 06:49   EGG-INFO/PKG-INFO
         11  2017-11-05 06:49   EGG-INFO/top_level.txt
        354  2017-11-05 06:49   helloworld/__init__.pyc
         55  2017-11-05 05:46   helloworld/moda.py
        395  2017-11-05 06:49   helloworld/modb.pyc
        124  2017-11-05 06:30   helloworld/__init__.py
          0  2017-11-04 19:15   helloworld/aaa.txt
        306  2017-11-05 06:49   helloworld/moda.pyc
        104  2017-11-05 06:42   helloworld/modb.py
          0  2017-11-04 19:16   helloworld/data/abc.dat
          0  2017-11-04 19:16   helloworld/data/abcd.dat
  ---------                    -------
       1934                     15 files
  
  // Use the package
  gset@ubuntu:~/demo/helloworld-1.0$ python
  Python 2.7.12 (default, Nov 19 2016, 06:48:10)
  [GCC 5.4.0 20160609] on linux2
  Type "help", "copyright","credits" or "license" for more information.
  >>> fromhelloworld import modb
  >>> modb.modb_print()
  modb: hello world!
  moda: hello world!
  >>> fromhelloworld.moda import moda_print
  >>> moda_print()
  moda: hello world!
  >>> fromhelloworld import test
  >>> test()
  hello world!
  
  gset@ubuntu:~/demo/helloworld-1.0$ xgf
  hello world!
  gset@ubuntu:~/demo/helloworld-1.0$ cat /usr/local/bin/xgf
  #!/usr/bin/python
  # EASY-INSTALL-ENTRY-SCRIPT:'helloworld==1.0','console_scripts','xgf'
  __requires__ = 'helloworld==1.0'
  import sys
  from pkg_resources import load_entry_point
  if __name__ == '__main__':
      sys.exit(
         load_entry_point('helloworld==1.0', 'console_scripts', 'xgf')()
)
  

  
  WSGI– Web Server Gateway Interface
  
  The Web Server Gateway Interface (WSGI) is a specification for simple and universal interface between web servers and web applications or frameworks for the Python programming language. It was originally specified in PEP333 and published on 7 December 2003. It has since been adopted as a standard for Python web application development.
  
  The WSGI interface has two sides: the server/gateway and the application side; beside this strict distinction there are so called “middleware” components which implement server and application sides at the same time:
  WSGI application is a callable object (a function, method, class, or an instance with a __call__ method) that accepts two positional arguments: WSGI environment variables and a callable with two required positional arguments which starts the response.
  WSGI server prepares the evnironment vaiables and invokes the callable object which returns response.
  WSGI middleware is used to routing to a different URL based on environ parameters,logging, handling exceptions and performing any kind of preprocess/postprocess operations.
   DSC0000.png

  
  Generally a WSGI server/container is a separate running process that runs on a different port than your Web/HTTP server; your Web/HTTPserver is configured to pass requests to the WSGI server/container, aka ReverseProxy, which actually runs your web application, then pass the response (in the form of HTML) back to the requester. The Web/HTTP server and WSGIserver/container can communicate via TCP/IP Socket  or UNIX Socket (more secure and faster).
  
  Here are some combinations which we will practice in the following tests:
   DSC0001.png
  ////////////////////  Apache2 + Mod_wsgi + Flask/App
  
  Mod_wsgi is an Apache module that embeds a Python application within the server and allow them to communicate through the Python WSGI interface as defined in the Python PEP 333.It can work in embeded mode or daemon mode.
  
  sudo pip install Flask
  sudo apt-get install pache2           
  sudo apt-get install libapache2-mod-wsgi
  
  sudo gedit /etc/apache2/sites-enabled/000-default.conf
  WSGIPythonPath /var/www/html
  <VirtualHost *:80>
                  ServerAdminwebmaster@localhost
                  DocumentRoot/var/www/html
                WSGIScriptAlias / /var/www/html/app.wsgi
<Directory /var/www/html/>
                    <Files app.wsgi>
                        Order deny,allow
                        Allow from all
                   </Files>
</Directory>
ErrorLog ${APACHE_LOG_DIR}/error.log
                  CustomLog${APACHE_LOG_DIR}/access.log combined
  </VirtualHost>
  
  sudo gedit /var/www/html/app.wsgi
  from test import app as application
  '''
  def application(environ,start_response):
      status='200 OK'
      output='Hello wsgi,this is Richard\r\n'
     response_headers=[('Content-type','text/plain'),
                        ('Content-Length',str(len(output)))]
     start_response(status,response_headers)
      return[output]
  '''
  sudo gedit /var/www/html/test.py
  from flask import Flask
  app = Flask(__name__)
  @app.route('/',methods=['GET'])
  def root_get():
                  return'GET - This is Richard\r\n'
  @app.route('/hello/<id>')
  def hello_world(id):
                  return'Hello World: {}\r\n'.format(id)
  @app.route('/add/<int:id>')
  def add(id):
                  return'Sum: %d\r\n' %id
  if __name__ == '__main__':
app.run(host='0.0.0.0')

  sudo /etc/init.d/apache2restart
  
  gset@ubuntu:~$curl http://127.0.0.1:80
  GET - This is Richard
  gset@ubuntu:~$curl http://127.0.0.1:80/hello/1000
  Hello World: 1000
  gset@ubuntu:~$curl http://127.0.0.1:80/add/10
  Sum: 10
  
  gset@ubuntu:~$ ls/etc/apache2
  apache2.conf   conf-enabled  magic           mods-enabled  sites-available
  conf-available envvars       mods-available  ports.conf   sites-enabled
  gset@ubuntu:~$ ls/var/www/html
  app.wsgi index.html  test.py
  
  
  ////////////////////  Wsgiref + Flask/App
  
  Wsgiref is a reference implementation of the WSGI specification that can be used to add WSGI support to a web server or framework. It provides utilities for manipulating WSGI environment variables and response headers, base classes for implementing WSGIservers, a demo HTTP server that serves WSGI applications, and a validation tool that checks WSGI servers and applications for conformance to the WSGI specification.
  
  gset@ubuntu:~$ gedit test.py
  from wsgiref.simple_server import make_server
  from flask import Flask
  
  app = Flask(__name__)
  @app.route('/',methods=['GET'])
  def root_get():
      return 'GET - Thisis Richard\r\n'
  @app.route('/hello/<id>')
  def hello_world(id):
      return 'HelloWorld: {}\r\n'.format(id)
  @app.route('/add/<int:id>')
  def add(id):
      return 'Sum:%d\r\n' %id
  
  '''
  def app(environ, start_response):
      status = '200 OK' #HTTP Status
      headers =[('Content-type', 'text/plain')]
     start_response(status, headers)
      return ["HelloWorld\r\n"]
  '''
  
  def main():
      httpd =make_server('', 8000, app)
      print "Servingon port 8000..."
     httpd.serve_forever()
  
  if __name__ == '__main__':
main()

  gset@ubuntu:~$ curl http://127.0.0.1:8000
  GET - This is Richard
  gset@ubuntu:~$ curl http://127.0.0.1:8000/hello/10000
  Hello World: 10000
  gset@ubuntu:~$ curl http://127.0.0.1:8000/add/10
  Sum: 10
  

  
  ////////////////////  Gunicore + Flask/App
  
  Gunicorn 'Green Unicorn' is a Python WSGI HTTP Server for UNIX. It's a pre-fork worker model ported from Ruby's Unicorn project. The Gunicorn server is broadly compatible with various web frameworks, simply implemented, light on server resource usage, and fairly speedy.
  
  sudo pip install gunicorn
  
  gset@ubuntu:~$ gedit test.py
  from flask import Flask
  app = Flask(__name__)
  @app.route('/',methods=['GET'])
  def root_get():
                  return'GET - This is Richard\r\n'
  @app.route('/hello/<id>')
  def hello_world(id):
                  return'Hello World: {}\r\n'.format(id)
  @app.route('/add/<int:id>')
  def add(id):
                  return'Sum: %d\r\n' %id
  if __name__ == '__main__':
app.run(host='0.0.0.0')
  
  gset@ubuntu:~$ gunicorn--workers=3 test:app -b 0.0.0.0:9000
  [2017-11-05 09:16:53 +0000] [9244] [INFO] Starting gunicorn19.7.1
  [2017-11-05 09:16:53 +0000] [9244] [INFO] Listening at:http://0.0.0.0:9000 (9244)
  [2017-11-05 09:16:53 +0000] [9244] [INFO] Using worker: sync
  [2017-11-05 09:16:53 +0000] [9249] [INFO] Booting worker withpid: 9249
  [2017-11-05 09:16:53 +0000] [9250] [INFO] Booting worker withpid: 9250
  [2017-11-05 09:16:54 +0000] [9253] [INFO] Booting worker withpid: 9253
  
  gset@ubuntu:~$ curl http://127.0.0.1:9000
  GET - This is Richard
  gset@ubuntu:~$ curl http://127.0.0.1:9000/hello/10000
  Hello World: 10000
  gset@ubuntu:~$ curl http://127.0.0.1:9000/add/10
  Sum: 10
  gset@ubuntu:~$
  

  ////////////////////  Eventlet + App
  
  Eventlet is a concurrent networking library for Python that allows you to change how you run your code, not how you write it. It uses epoll or kqueue or libevent for highlyscalable non-blocking I/O. Coroutines ensure that the developer uses a blocking style of programming that is similarto threading, but provide the benefits of non-blocking I/O. The event dispatch is implicit, which means you can easily use Eventlet from the Python interpreter, or as a small part of a larger application.
  
  Eventlet is built around the concept of green threads (i.e.coroutines, we use the terms interchangeably) that are launched to donetwork-related work. Green threads differ from normal threads in two mainways:
  1) Green threads are so cheap they are nearly free. You donot have to conserve green threads like you would do for normal threads. Ingeneral, there will be at least one green thread per network connection.
  2) Green threads cooperatively yield to each other instead of preemptively being scheduled. The major advantage from this behavior is that shared data structures don’t need locks, because only if a yield is explicitlycalled can another green thread have access to the data structure.
  
  sudo pip install eventlet
  
  // Example 1
  gset@ubuntu:~$ gedit test1.py
  import eventlet
  from eventlet import wsgi
  
  class AnimalApplication(object):
      def __init__(self):
          pass
      def __call__(self,environ, start_response):
         start_response('200 OK', [('Content-Type', 'text/plain')])
          return ['HelloWorld, this is Richard\r\n']
  
  if '__main__' == __name__:
application = AnimalApplication()
# wsgi.server(eventlet.listen(('', 7000)),  application)
      server =eventlet.spawn(wsgi.server, eventlet.listen(('',7000)),  application)
      server.wait()
  
  gset@ubuntu:~$ curl http://127.0.0.1:7000
  Hello World, this is Richard
  
  // Example 2
  gset@ubuntu:~$ gedit test2.py
  import eventlet
  #eventlet.monkey_patch()
  from eventlet.green import urllib2
  import time
  
  urls = ["http://www.tudou.com",
         "http://www.baidu.com"
         ]
           
  def test_1(url):
      try:
         print "open tudou"
         time.sleep(5)  // without the monkey patch, the current thread would stop
         urllib2.urlopen(url).read()
         print "done open tudou"
     except urllib2.HTTPError:
         return
          
  def test_2(url):
      try:
         print "open baidu"
         urllib2.urlopen(url).read()
         print "done open baidu"
     except urllib2.HTTPError:
         return
          
  pool = eventlet.GreenPool(100)
  pool.spawn(test_1, urls[0])
  pool.spawn(test_2, urls[1])
  pool.waitall()
  
  // Example 3
  gset@ubuntu:~$ gedit test3.py
  
  import eventlet  
  eventlet.monkey_patch
  
  def handle(fd):  
      print "clientconnected"  
      while True:  
          # pass through every non-eof line  
          x =fd.readline()  
          if not x:break  
         fd.write(x)  
          fd.flush()  
          print"echoed", x,  
      print "clientdisconnected"  
    
  print "server socket listening on port 6000"  
  server = eventlet.listen(('0.0.0.0', 6000))  
  pool = eventlet.GreenPool()
  while True:  
      try:  
          new_sock,address = server.accept()  
          print"accepted", address  
         pool.spawn_n(handle, new_sock.makefile('rw'))  
      except (SystemExit,KeyboardInterrupt):  
          break
  

  
  ////////////////////  Eventlet + Paste Deploy + App
  
  Paste Deployment is a system for finding and configuring WSGI applications and servers. For WSGI application consumers it provides a single,simple function (loadapp) for loading a WSGI application from a configuration file or a Python Egg. For WSGI application providers it only asks for a single,simple entry point to your application, so that application users don’t need to be exposed to the implementation details of your application. The result is something a system administrator can install and manage without knowing any Python, or the details of the WSGI application or its container.
  
  sudo pip install paste
  sudo pip install pastedeploy
  
  gset@ubuntu:~$ gedit animal.ini
  [composite:main]              # dispatch the request to applications
  use = egg:Paste#urlmap  # use the composite application named urlmap from the Paste package
                                                #urlmap uses a path prefix to map your requests to applications.
  / = animal_pipeline          # map ‘127.0.0.0:7000’ to the pipeline: animal_pipeline, “ip_balcklist +animal”
  /hello:show                       # map ‘127.0.0.0:7000/hello’ to the app: show   
  
  [pipeline:animal_pipeline]
  pipeline = ip_blacklist animal    # (1) ip_balcklist  -> (2) animal
  [filter:ip_blacklist]
  paste.filter_factory = hello:IPBlacklistMiddleware.factory
  [app:animal]   # You can define multiple applications in asingle file
  paste.app_factory = hello:AnimalApplication.factory
  [app:show]
  paste.app_factory = hello:HelloShow.factory
  
  gset@ubuntu:~$ gedit hello.py
  import os
  import eventlet
  from eventlet import wsgi
  from paste.deploy import loadapp
  
  class AnimalApplication(object):
      def __init__(self):
          pass
      def __call__(self,environ, start_response):
         start_response('200 OK', [('Content-Type', 'text/plain')])
          return ['Thisis a animal applicaltion!\r\n']
      @classmethod
      def factory(cls, global_conf,**kwargs):   
          return cls()                                                                                                                       
  
  class HelloShow(object):
      def __init__(self):
          pass
      def __call__(self,environ, start_response):
         start_response('200 OK', [('Content-Type', 'text/plain')])
          return ['HelloWorld, this is Richard !\r\n']
      @classmethod
      def factory(cls,global_conf, **kwargs):   
          return cls()
  
  class IPBlacklistMiddleware(object):
      def __init__(self,application):
         self.application = application
      def __call__(self,environ, start_response):
          ip_addr =environ.get('HTTP_HOST').split(':')[0]
          if ip_addr notin ('127.0.0.1'):
             start_response('403 Forbidden\r\n', [('Content-Type', 'text/plain')])
              return['Forbidden']
          returnself.application(environ, start_response)
      @classmethod
      def factory(cls, global_conf,**local_conf):
          def_factory(application):
              returncls(application)
          return _factory
  
  if '__main__' == __name__:
      config_file ="animal.ini"
      print"config:%s" % os.path.abspath(config_file)
      application =loadapp("config:%s" % os.path.abspath(config_file))  
      server =eventlet.spawn(wsgi.server,eventlet.listen(('', 7000)), application)
      server.wait()
  
  gset@ubuntu:~$ curl127.0.0.1:7000
  This is a animal applicaltion!
  gset@ubuntu:~$ curl127.0.0.1:7000/hello
  Hello World, this is Richard !
  

  ////////////////////  Eventlet + Paste Deploy + Routes + Webob + App
  
  Routes is a Python re-implementation of the Rails routes system for mapping URLs to application actions, and conversely to generate URLs. Routes makes it easy to create pretty and concise URLs that are RESTful with little effort. Routes allows conditional matching based on domain,cookies, HTTP method, or a custom function. Sub-domain support is built in.Routes comes with an extensive unit test suite.
  
  WebOb is a Python library that provides wrappers around the WSGI request environment, and an object to help create WSGI responses. The objects map much of the specified behavior of HTTP, including header parsing,content negotiation and correct handling of conditional and range requests. This helps you create rich applications and valid middleware without knowing all the complexities of WSGI and HTTP.
  
  sudo pip install routes
  sudo pip install webob
  
  gset@ubuntu:~$ gedit animal.ini
  [composite:main]
  use = egg:Paste#urlmap
  / = animal_pipeline
  [pipeline:animal_pipeline]
  pipeline = ip_blacklist  animal   # (1) ip_balcklist  -> (2)animal
  [filter:ip_blacklist]
  paste.filter_factory = hello:IPBlacklistMiddleware.factory
  [app:animal]
  paste.app_factory = hello:AnimalApplication.factory
  
  gset@ubuntu:~$ gedit hello.py
  import os
  import eventlet
  from eventlet import wsgi
  from paste.deploy import loadapp
  import routes
  import routes.middleware as middleware
  import webob.dec
  import webob.exc
  
  class Resource(object):
      def __init__(self,controller):
          self.controller= controller()
  
      @webob.dec.wsgify
      def __call__(self,req):
          match =req.environ['wsgiorg.routing_args'][1]
          action =match['action']
          ifhasattr(self.controller, action):
              method =getattr(self.controller, action)
              returnmethod(req)
          returnwebob.exc.HTTPNotFound()
  
  class CatController(object):
      def index(self,req):
          return 'Listcats.'
      def create(self,req):
          return 'createcat.'
      def delete(self,req):
          return 'deletecat.'
      def update(self,req):
          return 'updatecat.'
  
  class DogController(object):
      def index(self,req):
          return 'Listdogs.'
      def create(self,req):
          return 'create dog.'
      def delete(self,req):
          return 'deletedog.'
      def update(self,req):
          return 'updatedog.'
  
  class AnimalApplication(object):
      def __init__(self):
          self.mapper =routes.Mapper()
         self.mapper.resource('cat', 'cats', controller=Resource(CatController))
         self.mapper.resource('dog', 'dogs', controller=Resource(DogController))
          self.router =middleware.RoutesMiddleware(self.dispatch, self.mapper)
  
      @webob.dec.wsgify
      def __call__(self,req):
          returnself.router
  
      @classmethod
      def factory(cls,global_conf, **local_conf):
          return cls()
  
      @staticmethod
      @webob.dec.wsgify
      def dispatch(req):
          match =req.environ['wsgiorg.routing_args'][1]
          returnmatch['controller'] if match else webob.exc.HTTPNotFound()
  
  class IPBlacklistMiddleware(object):
      def __init__(self,application):
         self.application = application
  
      def __call__(self,environ, start_response):
          ip_addr =environ.get('HTTP_HOST').split(':')[0]
          if ip_addr notin ('127.0.0.1'):
             start_response('403 Forbidden', [('Content-Type', 'text/plain')])
              return['Forbidden']
  
          returnself.application(environ, start_response)
  
      @classmethod
      def factory(cls,global_conf, **local_conf):
          def_factory(application):
              returncls(application)
          return _factory
  
  if '__main__' == __name__:
      config_file ="animal.ini"
      print"config:%s" % os.path.abspath(config_file)
      application =loadapp("config:%s" % os.path.abspath(config_file))
      server =eventlet.spawn(wsgi.server, eventlet.listen(('', 8080)), application)
      server.wait()
  
   curl 127.0.0.1:8080/cats
   curl -X POST 127.0.0.1:8080/cats
   curl -X DELETE 127.0.0.1:8080/cats/kitty
   curl 127.0.0.1:8080/dogs
   curl -X DELETE 127.0.0.1:8080/dogs/wangcai
  

   Debug Python Code
  
  ////////////////////  Debug by Python Debugger – Nonintrusive
  
  gset@ubuntu:~$ gedit hello.py
  a = 1+1
  def greet_user(username="No Name",age=20):
                  print("Hello," + username.title()+ ":" + str(age) + " !")
                  returnusername.title()+ ":" + str(age)
  greet_user("richard xue", 30)
  greet_user(age=40, username="richard xue")
  temp = greet_user()
  print(temp)
  
  gset@ubuntu:~$ python-m pdb hello.py
  > /home/gset/hello.py(1)<module>()
  -> a = 1+1
  (Pdb)l
    1  ->     a= 1+1
    2            
    3            defgreet_user(username="No Name",age=20):
    4                            print("Hello," + username.title()+ ":" + str(age) + " !")
    5                            returnusername.title()+ ":" + str(age)
    6            greet_user("richardxue", 30)
    7            greet_user(age=40,username="richard xue")
    8            
    9            temp= greet_user()
   10          print(temp)
   11         
  (Pdb) n
  > /home/gset/hello.py(3)<module>()
  -> def greet_user(username="No Name",age=20):
  (Pdb) p a
  2
  (Pdb) exit
  
  ////////////////////  Debug by Python Debugger – Intrusive
  
  gset@ubuntu:~$ gedit hello.py
  import pdb
  a = 1+1
  def greet_user(username="No Name",age=20):
                  print("Hello," + username.title()+ ":" + str(age) + " !")
                  returnusername.title()+ ":" + str(age)
  pdb.set_trace()
  greet_user("richard xue", 30)
  greet_user(age=40, username="richard xue")
  temp = greet_user()
  print(temp)
  
  gset@ubuntu:~$ python  hello.py
  > /home/gset/hello.py(9)<module>()
  -> greet_user("richard xue", 30)
  (Pdb)l
    4            
    5            defgreet_user(username="No Name",age=20):
    6                            print("Hello," + username.title()+ ":" + str(age) + " !")
    7                            returnusername.title()+ ":" + str(age)
    8            pdb.set_trace()
    9  ->     greet_user("richardxue", 30)
   10          greet_user(age=40,username="richard xue")
   11         
   12          temp= greet_user()
   13          print(temp)
   14         
  (Pdb) p a
  2
  (Pdb) n
  Hello, Richard Xue:30 !
  > /home/gset/hello.py(10)<module>()
  -> greet_user(age=40, username="richard xue")
  (Pdb) c
  Hello, Richard Xue:40 !
  Hello, No Name:20 !
  No Name:20
  

  
  //////////////////// LocalDebug by Eclispe/PyDev – Nonintrusive
  
  // Install Java
  sudo apt-get install openjdk-8-jre  
  su root
  echo'JAVA_HOME="/usr/lib/jvm/java-8-openjdk-amd64"'  >> /etc/environment
  source /etc/environment
  
  // Download and install eclispe-installer(c/c++)  
  http://www.eclipse.org/downloads/
  
  // Install and configure PyDev in Eclipse
  
  gset@ubuntu:~$ which python
  /usr/bin/python
  

DSC0002.png

   DSC0003.png
DSC0004.png

DSC0005.png

  

  ////////////////////  Remote Debug by Eclispe/PyDev – Intrusive
  
  //Configure the port number for remote debugger
  

DSC0006.png

DSC0007.png

  // Start the debug server in ‘Host A’
DSC0008.png

  

  // Run the Python code in ‘Host B’
  sudo pip install pydevd
  
  gset@ubuntu:~$ gedit test.py
  import keystoneclient.v2_0.client as ksclient
  import glanceclient
  import pydevd
  pydevd.settrace(host='127.0.0.1',port=5678,stdoutToServer=True,stderrToServer=True,suspend=True)
  #pydevd.settrace(host='10.0.0.11',port=5678,stdoutToServer=True,stderrToServer=True,suspend=True)
  keystone= ksclient.Client(auth_url="http://10.0.0.11:5000/v2.0",
  username="admin",password="ipcc2014",tenant_name="admin")
  endpoint=keystone.service_catalog.url_for(service_type='compute',endpoint_type='publicURL')
  print(endpoint)
  endpoint=keystone.service_catalog.url_for(service_type='image',endpoint_type='publicURL')
  print(endpoint)
  glance= glanceclient.Client('2',endpoint, token=keystone.auth_token)
  images= glance.images.list()
  forimage in glance.images.list():
  print(image.id + " " +image.name)
  
  gset@ubuntu:~$ python test.py
  
  // Debug the Python code in ‘Host A’
DSC0009.png

  DebugOpenStack Code (nova)
  
  ////////////////////  Debug by Python Debugger – Nonintrusive
  
  gset@controller:~$ ps-ef | grep nova-api
  gset@controller:~$ sudo service nova-api stop
  gset@controller:~$ sudo python -m pdb /usr/bin/nova-api --debug --config-file=/etc/nova/nova.conf
  > /usr/bin/nova-api(4)<module>()
  -> import sys
  (Pdb) l
    1            #!/usr/bin/python
    2            #PBR Generated from u'console_scripts'
    3            
    4  ->     importsys
    5            
    6            fromnovaNaNd.api import main
    7            
    8            
    9            if__name__ == "__main__":
   10              sys.exit(main())
  [EOF]
  (Pdb)n
  > /usr/bin/nova-api(6)<module>()
  -> from novaNaNd.api import main
  (Pdb) n
  > /usr/bin/nova-api(9)<module>()
  -> if __name__ == "__main__":
  (Pdb) l
    4            importsys
    5            
    6            fromnovaNaNd.api import main
    7            
    8            
    9  ->     if__name__ == "__main__":
   10              sys.exit(main())
  [EOF]
  (Pdb) s
  > /usr/bin/nova-api(10)<module>()
  -> sys.exit(main())
  (Pdb) s
  --Call--
  >/usr/lib/python2.7/dist-packages/nova/cmd/api.py(39)main()
  -> def main():
  (Pdb) n
  >/usr/lib/python2.7/dist-packages/nova/cmd/api.py(42)main()
  -> config.parse_args(sys.argv)
  
  ////////////////////  Debug by Python Debugger – Intrusive
  
  gset@controller:~$ sudo service nova-api stop
  gset@controller:~$ sudo /usr/bin/nova-api --debug --config-file=/etc/nova/nova.conf
  > /usr/lib/python2.7/dist-packages/nova/cmd/api.py(42)main()
  -> config.parse_args(sys.argv)
  (Pdb) l
   37          CONF= nova.conf.CONF
   38         
   39          defmain():
   40              import pdb
   41              pdb.set_trace()
   42  ->        config.parse_args(sys.argv)
   43              logging.setup(CONF, "nova")
   44              utils.monkey_patch()
   45              objects.register_all()
   46              if 'osapi_compute' in CONF.enabled_apis:
   47                  # NOTE(mriedem): This is needed forcaching the nova-compute service
  (Pdb) n
  > /usr/lib/python2.7/dist-packages/nova/cmd/api.py(43)main()
  -> logging.setup(CONF, "nova")
  
  ////////////////////  Remote/Local Debug by Eclispe/PyDev – Intrusive
  
  // Install Eclipse/PyDev in Controller which actually runs OpenStack and run Eclipse as Root user
  gset@controller:~$su root
  root@controller:~#/home/gset/eclipse/cpp-oxygen/eclipse/eclipse
  
  // Install pydevd and make sure it is ready
  gset@controller:~$ sudo pip install pydevd
  gset@controller:~$ python
  Python 2.7.12 (default, Nov 19 2016, 06:48:10)
  [GCC 5.4.0 20160609] on linux2
  Type "help", "copyright","credits" or "license" for more information.
  >>> import pydevd
  >>>
  
  // Turn off thread patching to enable theremote debugger
  gset@controller:~$ grep -rn eventlet.monkey_patch /usr/lib/python2.7/dist-packages/nova
  gset@controller:~$ sudo gedit /usr/lib/python2.7/dist-packages/nova/cmd/__init__.py
  importeventlet
  fromnova import debugger
  ifdebugger.enabled():
      # turn off thread patching to enable theremote debugger
      eventlet.monkey_patch(os=False, thread=False)
  else:
     eventlet.monkey_patch(os=False)
  
  Notes: Using the remote debug option changes how Nova uses the eventlet library to supportasync IO, and could result in failures that do not occur under normal operation,so we have to turn off thread patching for debugging; while Monkey patchingwith thread=False is also likely to cause problems, even simple concurrency scenarios can result in deadlocks with this sort of setup.
  https://specs.openstack.org/openstack/openstack-specs/specs/eventlet-best-practices.html
  
  ////////////Example 1: debug ‘nova/cmd/api.py’
  
  1 - insert pydevd.settrace in nova/cmd/api.py
  gset@controller:~$ sudo gedit /usr/lib/python2.7/dist-packages/nova/cmd/api.py
  def main():
      import pydevd
pydevd.settrace(host='10.0.0.11',port=5678,stdoutToServer=True,stderrToServer=True,suspend=True)
       ………………..
  
  2 - Stop and start the debug server in Eclispe/PyDev
  
  3 - Run “nova-api”
  gset@controller:~$ sudo service nova-api stop
  gset@controller:~$ sudo /usr/bin/nova-api  --remote_debug-host 10.0.0.11--remote_debug-port 5678 --config-file=/etc/nova/nova.conf
DSC00010.png

  

  ////////// Example2: debug ‘get_all’ for openstack server list

  
  1 - insert pydevd.settrace in nova/compute/api.py
  gset@controller:~$ sudo gedit /usr/lib/python2.7/dist-packages/nova/compute/api.py  
  
  def get_all(self, context,search_opts=None, limit=None, marker=None,
                  expected_attrs=None,sort_keys=None, sort_dirs=None):
          import pydevd
         pydevd.settrace(host='10.0.0.11',port=5678,stdoutToServer=True,stderrToServer=True,suspend=True)
         ………………..
  
  2 - Stop and start the debug server in Eclispe/PyDev
  
  3 - Run “nova-api”
  gset@controller:~$  sudo service nova-api stop
  gset@controller:~$ sudo /usr/bin/nova-api  --remote_debug-host 10.0.0.11--remote_debug-port 5678 --config-file=/etc/nova/nova.conf
  
  4 - Run “openstack server list”
  gset@controller:~$ . admin-openrc
  gset@controller:~$ openstack server list
  

DSC00011.png

  

  

  

  

  

  

  

运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.yunweiku.com/thread-483098-1-1.html 上篇帖子: Openstack的环境的Mitaka部署dashboard 云主机 镜像(2) 下篇帖子: Openstack 安装部署指南翻译系列 之 网络
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表