openstack-neutron源码解析

neutron-server.service 启动命令

neutron-server --config-file /etc/neutron/neutron.conf --config-file /etc/neutron/api-paste.ini

1.程序入口点

位于 setup.cfg -> [entry_points] -> console_scripts,很很多个main函数入口,安装后,这些命令位于/usr/bin/,可以直接执行。
程序入口点举例:neutron-server = neutron.cmd.eventlet.server:main_wsgi_eventlet
创建eventlet pool,启动wsgi server,具体做事情的是api-paste.ini中定义的app:neutron,请求达到时,经过一系列的filter后,达到APIRouter处理

setuptools框架,setup.cfg中[entry_points]

详情见openstack-setuptools以及setuptools-pbr(源码解析一)

#neutron.cmd.eventlet.server文件中main_wsgi_eventlet方法
neutron-server = neutron.cmd.eventlet.server:main_wsgi_eventlet

2.def main_wsgi_eventlet():

  wsgi_eventlet.main()

3.def main():

server.boot_server(_eventlet_wsgi_server)

4.def boot_server(server_func):

#此处传入的参数一般为 --config-file /etc/neutron/neutron.conf --config-file /etc/neutron/plugins/ml2/ml2_conf.ini
config.init(sys.argv[1:])
#设置neutron的logging,就是以neutron为进程名的打印
config.setup_logging()

server_func()

5.def _eventlet_wsgi_server():

#创建线程池
pool = eventlet.GreenPool()
#neutron api的注册
neutron_api = service.serve_wsgi(service.NeutronApiService)
#启动api
api_thread = pool.spawn(neutron_api.wait)

try:
#注册rpc服务
    neutron_rpc = service.serve_rpc()
except NotImplementedError:
    LOG.info(_LI("RPC was already started in parent process by "
                 "plugin."))
else:
	#启动rpc线程
    rpc_thread = pool.spawn(neutron_rpc.wait)
	#启动rpc plugin works
    plugin_workers = service.start_plugin_workers()
    for worker in plugin_workers:
        pool.spawn(worker.wait)

    # api and rpc should die together.  When one dies, kill the other.
    rpc_thread.link(lambda gt: api_thread.kill())
    api_thread.link(lambda gt: rpc_thread.kill())

pool.waitall()

5.1.service.serve_wsgi(service.NeutronApiService)

def serve_wsgi(cls):

    try:
        service = cls.create()
        #启动api server实例
        service.start()
    except Exception:
        with excutils.save_and_reraise_exception():
            LOG.exception(_LE('Unrecoverable error: please check log '
                              'for details.'))

    return service

5.1.2.WsgiService.start

class WsgiService(object):
    """Base class for WSGI based services.
    For each api you define, you must also define these flags:
    :_listen: The address on which to listen
    :_listen_port: The port on which to listen
    """
    def __init__(self, app_name):
        self.app_name = app_name
        self.wsgi_app = None
    def start(self):
        # 启动时  调用_run_wsgi加载app
        self.wsgi_app = _run_wsgi(self.app_name)
    def wait(self):
        self.wsgi_app.wait()

def _run_wsgi(app_name):
    # app_name 默认是neutron
  	#创建app
    app = config.load_paste_app(app_name)
    if not app:
        LOG.error(_LE('No known API applications configured.'))
        return
    # 创建server   
    server = wsgi.Server("Neutron")
    #绑定并启动server
    server.start(app, cfg.CONF.bind_port, cfg.CONF.bind_host,
                 workers=_get_api_workers())
    LOG.info(_LI("Neutron service started, listening on %(host)s:%(port)s"),
             {'host': cfg.CONF.bind_host, 'port': cfg.CONF.bind_port})    
    return run_wsgi_app(app)

5.1.3.config.load_paste_app(app_name)

def load_paste_app(app_name):
#neutron.conf中定义或者默认值为api-paste.ini
    config_path = cfg.CONF.find_file(cfg.CONF.api_paste_config)
    if not config_path:
        raise cfg.ConfigFilesNotFoundError(
            config_files=[cfg.CONF.api_paste_config])
    config_path = os.path.abspath(config_path)
    LOG.info(_LI("Config paste file: %s"), config_path)

    try:
    #创建app
        app = deploy.loadapp("config:%s" % config_path, name=app_name)
    except (LookupError, ImportError):
        msg = (_("Unable to load %(app_name)s from "
                 "configuration file %(config_path)s.") %
               {'app_name': app_name,
                'config_path': config_path})
        LOG.exception(msg)
        raise RuntimeError(msg)
    return app

5.1.4.Paste Deployment

用来发现和配置WSGI应用的一套系统

#url请求分发到对应的app,use表明的是分发的方式,这里是urlmap进行分发的
[composite:neutron]
use = egg:Paste#urlmap
#跳转
/: neutronversions
/v2.0: neutronapi_v2_0

[composite:neutronapi_v2_0]
use = call:neutron.auth:pipeline_factory
noauth = request_id catch_errors extensions neutronapiapp_v2_0
keystone = request_id catch_errors authtoken keystonecontext extensions neutronapiapp_v2_0

[filter:request_id]
paste.filter_factory = oslo_middleware:RequestId.factory

[filter:catch_errors]
paste.filter_factory = oslo_middleware:CatchErrors.factory

[filter:keystonecontext]
paste.filter_factory = neutron.auth:NeutronKeystoneContext.factory

[filter:authtoken]
paste.filter_factory = keystonemiddleware.auth_token:filter_factory

[filter:extensions]
paste.filter_factory = neutron.api.extensions:plugin_aware_extension_middleware_factory

[app:neutronversions]
paste.app_factory = neutron.api.versions:Versions.factory

#创建app
[app:neutronapiapp_v2_0]
#初始化neutron.api.v2.router中APIRouter.factory
paste.app_factory = neutron.api.v2.router:APIRouter.factory

5.1.5.neutron.api.v2.router:APIRouter.factory

RESOURCES = {'network': 'networks',
             'subnet': 'subnets',
             'subnetpool': 'subnetpools',
             'port': 'ports'}
SUB_RESOURCES = {}
COLLECTION_ACTIONS = ['index', 'create']
MEMBER_ACTIONS = ['show', 'update', 'delete']
REQUIREMENTS = {'id': attributes.UUID_PATTERN, 'format': 'json'}
class APIRouter(wsgi.Router):

    @classmethod
    def factory(cls, global_config, **local_config):
        return cls(**local_config)

    def __init__(self, **local_config):
    	#创建mapper
        mapper = routes_mapper.Mapper()
        #获取NeutornManage的core_plugin,这个定义在/etc/neutron/neutron.conf,比如我的是core_plugin = ml2
        plugin = manager.NeutronManager.get_plugin()
        #扫描neutron/extensions下所有的extension
        ext_mgr = extensions.PluginAwareExtensionManager.get_instance()
        ext_mgr.extend_resources("2.0", attributes.RESOURCE_ATTRIBUTE_MAP)

        col_kwargs = dict(collection_actions=COLLECTION_ACTIONS,
                          member_actions=MEMBER_ACTIONS)
		#构建映射规则函数
        def _map_resource(collection, resource, params, parent=None):
            allow_bulk = cfg.CONF.allow_bulk
            allow_pagination = cfg.CONF.allow_pagination
            allow_sorting = cfg.CONF.allow_sorting
            #创建controller
            controller = base.create_resource(
                collection, resource, plugin, params, allow_bulk=allow_bulk,
                parent=parent, allow_pagination=allow_pagination,
                allow_sorting=allow_sorting)
            path_prefix = None
            if parent:
                path_prefix = "/%s/{%s_id}/%s" % (parent['collection_name'],
                                                  parent['member_name'],
                                                  collection)
            mapper_kwargs = dict(controller=controller,
                                 requirements=REQUIREMENTS,
                                 path_prefix=path_prefix,
                                 **col_kwargs)
            # mapper.collection这个就是构建映射规则
            #collection:一个字符串,就是资源的复数形式,比如networks
            #resource:一个字符串,就是资源的单数形式,比如network
            return mapper.collection(collection, resource,
                                     **mapper_kwargs)
	   #构建/的映射规则
        mapper.connect('index', '/', controller=Index(RESOURCES))
        
        for resource in RESOURCES:
        	#针对每一个核心资源(network、subnet等),调用_map_resource,构建映射规则
            _map_resource(RESOURCES[resource], resource,
                          attributes.RESOURCE_ATTRIBUTE_MAP.get(
                              RESOURCES[resource], dict()))
            resource_registry.register_resource_by_name(resource)
		#SUB_RESOURCES是空的,没啥用
        for resource in SUB_RESOURCES:
            _map_resource(SUB_RESOURCES[resource]['collection_name'], resource,
                          attributes.RESOURCE_ATTRIBUTE_MAP.get(
                              SUB_RESOURCES[resource]['collection_name'],
                              dict()),
                          SUB_RESOURCES[resource]['parent'])

        #清除当前配置在策略引擎中的所有规则。其在单元测试中和核心API router初始化的最后调用,确保在所有扩展加载之后加载规则
        policy.reset()
        #初始化wsgi.Router
        super(APIRouter, self).__init__(mapper)

5.1.6.extension

  1. extension应该放在neutron/extensions文件夹下,或者在配置文件中设置api_extensions_path
  1. extension的class名应该和文件同名,当然首字母应该大写
  1. 应该实现neutron.api.extensions.py中ExtensionDescriptor定义的接口
  1. 在对应的plugin的supported_extension_aliases 中增加我们extension的别名。前面我们写的core plugin就有这个属性

5.1.7.controller = base.create_resource

FAULT_MAP = {exceptions.NotFound: webob.exc.HTTPNotFound,
             exceptions.Conflict: webob.exc.HTTPConflict,
             exceptions.InUse: webob.exc.HTTPConflict,
             exceptions.BadRequest: webob.exc.HTTPBadRequest,
             exceptions.ServiceUnavailable: webob.exc.HTTPServiceUnavailable,
             exceptions.NotAuthorized: webob.exc.HTTPForbidden,
             netaddr.AddrFormatError: webob.exc.HTTPBadRequest,
             oslo_policy.PolicyNotAuthorized: webob.exc.HTTPForbidden
             }


class Controller(object):
    LIST = 'list'
    SHOW = 'show'
    CREATE = 'create'
    UPDATE = 'update'
    DELETE = 'delete'
def index(self, request, **kwargs):
···
def show(self,req,id):
···
def create(self,req,body):
···
    
def update(self,req,body,id):
···
    
def create_resource(collection, resource, plugin, params, allow_bulk=False,
                    member_actions=None, parent=None, allow_pagination=False,
                    allow_sorting=False):
    #创建controller                
    controller = Controller(plugin, collection, resource, params, allow_bulk,
                            member_actions=member_actions, parent=parent,
                            allow_pagination=allow_pagination,
                            allow_sorting=allow_sorting)

    return wsgi_resource.Resource(controller, FAULT_MAP)    

5.1.8.wsgi_resource.Resource

  def Resource(controller, faults=None, deserializers=None, serializers=None):
    	@webob.dec.wsgify(RequestClass=Request)
        def resource(request):
           ···
           # 从controller获取执行action的函数。
           method = getattr(controller, action)   
           # 执行action,相关参数经反序列化后通过args参数传入controller。
           result = method(request=request, **args)    
           ···
           # 构造Response进行返回。
           return webob.Response(request=request, status=status,           
                                  content_type=content_type,
                                  body=body)
        #返回resource                         
        return resource

5.2.neutron_rpc = service.serve_rpc()

 def serve_rpc():
    	#获取plugin
        plugin = manager.NeutronManager.get_plugin()
        #获取service_plugins(包含plugin)
        service_plugins = (
            manager.NeutronManager.get_service_plugins().values())
    	#检查配置文件中rpc_workers
        if cfg.CONF.rpc_workers < 1:
            cfg.CONF.set_override('rpc_workers', 1)
    
    	#检查plugin是否实现start_rpc_listeners方法
        if not plugin.rpc_workers_supported():
            LOG.debug("Active plugin doesn't implement start_rpc_listeners")
            if 0 < cfg.CONF.rpc_workers:
                LOG.error(_LE("'rpc_workers = %d' ignored because "
                              "start_rpc_listeners is not implemented."),
                          cfg.CONF.rpc_workers)
            raise NotImplementedError()
    
        try:
    	   #创建service_plugins RpcWorker
            rpc = RpcWorker(service_plugins)
            LOG.debug('using launcher for rpc, workers=%s', cfg.CONF.rpc_workers)
            #关闭连接池
            session.dispose()
            #创建ProcessLauncher,launcher详情见md文件
            launcher = common_service.ProcessLauncher(cfg.CONF, wait_interval=1.0)
            #执行launch_service方法
            launcher.launch_service(rpc, workers=cfg.CONF.rpc_workers)
            return launcher
        except Exception:
            with excutils.save_and_reraise_exception():
                LOG.exception(_LE('Unrecoverable error: please check log for '
                                  'details.'))

5.2.2.launcher.launch_service(rpc, workers=cfg.CONF.rpc_workers)

 def launch_service(self, service, workers=1):
    	#检查是否是ServiceBase子类
        _check_service_base(service)
        #创建ServiceWrapper
        wrap = ServiceWrapper(service, workers)
    	#设置不让垃圾回收机制回收已经存在的实例
        if hasattr(gc, 'freeze'):
            gc.freeze()
    
        LOG.info('Starting %d workers', wrap.workers)
        while self.running and len(wrap.children) < wrap.workers:
        	#启动进程
            self._start_child(wrap)

5.2.3self._start_child(wrap)

 def _start_child(self, wrap):
        if len(wrap.forktimes) > wrap.workers:
            #休眠
            if time.time() - wrap.forktimes[0] < wrap.workers:
                LOG.info('Forking too fast, sleeping')
                time.sleep(1)
    		#wrap.forktimes顶部放入0
            wrap.forktimes.pop(0)
    	#wrap.forktimes加入时间
        wrap.forktimes.append(time.time())
    	#创建子进程
        pid = os.fork()
        #如果是子进程
        if pid == 0:
        	#运行_child_process
            self.launcher = self._child_process(wrap.service)
            while True:
            	#子进程句柄
                self._child_process_handle_signal()
                status, signo = self._child_wait_for_exit_or_signal(
                    self.launcher)
                if not _is_sighup_and_daemon(signo):
                    self.launcher.wait()
                    break
                self.launcher.restart()
    
            os._exit(status)
    
        LOG.debug('Started child %d', pid)
    
        wrap.children.add(pid)
        self.children[pid] = wrap
    
        return pid

5.2.4.self.launcher = self._child_process(wrap.service)

 def _child_process(self, service):
    	#子进程句柄
        self._child_process_handle_signal()
    
        
        eventlet.hubs.use_hub()
    
        #关闭流
        os.close(self.writepipe)
        # Create greenthread to watch for parent to close pipe
        eventlet.spawn_n(self._pipe_watcher)
    
        # Reseed random number generator
        random.seed()
    
        launcher = Launcher(self.conf, restart_method=self.restart_method)
        #调用launch_service
        launcher.launch_service(service)
        return launcher

5.2.5.launcher.launch_service(service)

   def launch_service(self, service, workers=1):
        if workers is not None and workers != 1:
            raise ValueError(_("Launcher asked to start multiple workers"))
        _check_service_base(service)
        service.backdoor_port = self.backdoor_port
        #添加services进程
        self.services.add(service)

5.2.6.self.services.add(service)

def add(self, service):
    self.services.append(service)
    #添加线程
    self.tg.add_thread(self.run_service, service, self.done)

5.2.7.self.tg.add_thread(self.run_service, service, self.done)

def add_thread(self, callback, *args, **kwargs):
    #运行callback函数
    gt = self.pool.spawn(callback, *args, **kwargs)
    th = Thread(gt, self, link=False)
    self.threads.append(th)
    gt.link(_on_thread_done, self, th)
    return th

5.2.8.self.run_service

def run_service(service, done):
    try:
    #执行start()方法
        service.start()
    except Exception:
        LOG.exception('Error starting thread.')
        raise SystemExit(1)
    else:
        done.wait()

5.2.9.回到5.2 rpc = RpcWorker(service_plugins)

 start_listeners_method = 'start_rpc_listeners'
def start(self):
    for plugin in self._plugins:
        if hasattr(plugin, self.start_listeners_method):
            try:
            	#执行plugin的start_rpc_listeners方法
                servers = getattr(plugin, self.start_listeners_method)()
            except NotImplementedError:
                continue
            self._servers.extend(servers)

5.2.10.Ml2Plugin.start_rpc_listeners

   def start_rpc_listeners(self):
        #定义回调endpoints
        self._setup_rpc()
        self.topic = topics.PLUGIN
        self.conn = n_rpc.create_connection(new=True)
        #创建endpoints服务
        self.conn.create_consumer(self.topic, self.endpoints, fanout=False)
        return self.conn.consume_in_threads()
        
    def _setup_rpc(self):
        """Initialize components to support agent communication."""
        self.endpoints = [
            rpc.RpcCallbacks(self.notifier, self.type_manager),
            securitygroups_rpc.SecurityGroupServerRpcCallback(),
            dvr_rpc.DVRServerRpcCallback(),
            dhcp_rpc.DhcpRpcCallback(),
            agents_db.AgentExtRpcCallback(),
            metadata_rpc.MetadataRpcCallback(),
            resources_rpc.ResourcesPullRpcCallback()
        ]    

不管什么版本,基本差不多,只是代码做了些许改变,基本流程还是不会变化

你可能感兴趣的:(OpenStack云服务,openstack,python,neutron,云服务)