您的位置:首页 > 编程语言

nova-api代码分析(1)

2014-07-29 14:42 302 查看
1.首先查看/usr/local/bin/nova-api命令内容:

import sys
#导入nova.cmd.api模块的main方法
from nova.cmd.api import main

if __name__ == "__main__":
sys.exit(main())


2.下面查看nova模块中nova.cmd.api模块里的main()方法

def main():
#命令行参数解析
    config.parse_args(sys.argv)
    logging.setup("nova")
#导入monkeypatch插件
    utils.monkey_patch()
#注册nova的object对象
    objects.register_all()

    gmr.TextGuruMeditation.setup_autorun(version)
#初始化service.ProcessLauncher类,process的构造函数
    launcher = service.process_launcher()
#加载的使能的api接口ec2,osapi_compute,metadata等
    for api in CONF.enabled_apis:
#如果enabled_ssl_apis配置为True,WSGI接口将支持ssl
        should_use_ssl = api in CONF.enabled_ssl_apis
        if api == 'ec2':
#初始化WSGIserver,加载paste配置文件
            server = service.WSGIService(api, use_ssl=should_use_ssl,
                                         max_url_len=16384)
        else:
#初始化WSGIserver,加载paste配置文件</span>
            server = service.WSGIService(api, use_ssl=should_use_ssl)
#launch启动WSGI服务进程
        launcher.launch_service(server, workers=server.workers or 1)
#Loop waiting on children to die and respawning as necessary
#循环等待子进程die和重新生成子进程
    launcher.wait()


parse_args:

def parse_args(argv, default_config_files=None):
options.set_defaults(sql_connection=_DEFAULT_SQL_CONNECTION,
sqlite_db='nova.sqlite')
rpc.set_defaults(control_exchange='nova')
debugger.register_cli_opts()
cfg.CONF(argv[1:],
project='nova',
version=version.version_string(),
default_config_files=default_config_files)
rpc.init(cfg.CONF)


初始化process_launcher

def process_launcher():
return service.ProcessLauncher()
class ProcessLauncher(object):
def __init__(self, wait_interval=0.01):
"""Constructor.

:param wait_interval: The interval to sleep for between checks
of child process exit.
"""
        #子进程字典
self.children = {}
#
self.sigcaught = None
#running状态True
self.running = True
#
self.wait_interval = wait_interval
#生成管道读描述符和谐描述符
rfd, self.writepipe = os.pipe()
#读管道为绿色线程
self.readpipe = eventlet.greenio.GreenPipe(rfd, 'r')
#
self.handle_signal()

handle_signal方法分析:

def handle_signal(self):
_set_signals_handler(self._handle_signal)
def _set_signals_handler(handler):
signal.signal(signal.SIGTERM, handler)
signal.signal(signal.SIGINT, handler)
if _sighup_supported():
signal.signal(signal.SIGHUP, handler)

def _sighup_supported():
return hasattr(signal, 'SIGHUP')


初始化WSGIService方法分析:

server = service.WSGIService(api, use_ssl=should_use_ssl)


class WSGIService(object):
"""Provides ability to launch API from a 'paste' configuration."""
#WSGIService的初始化方法
def __init__(self, name, loader=None, use_ssl=False, max_url_len=None):
"""Initialize, but do not start the WSGI server.

:param name: The name of the WSGI server given to the loader.
:param loader: Loads the WSGI application using the given name.
:returns: None

"""
self.name = name
self.manager = self._get_manager()
#初始化WSGI loader实例
 self.loader = loader or wsgi.Loader()
#调用load_app方法加载paste配置文件
 self.app = self.loader.load_app(name)
self.host = getattr(CONF, '%s_listen' % name, "0.0.0.0")
self.port = getattr(CONF, '%s_listen_port' % name, 0)
self.workers = (getattr(CONF, '%s_workers' % n
4000
ame, None) or
processutils.get_worker_count())
if self.workers and self.workers < 1:
worker_name = '%s_workers' % name
msg = (_("%(worker_name)s value of %(workers)s is invalid, "
"must be greater than 0") %
{'worker_name': worker_name,
'workers': str(self.workers)})
raise exception.InvalidInput(msg)
self.use_ssl = use_ssl
self.server = wsgi.Server(name,
self.app,
host=self.host,
port=self.port,
use_ssl=self.use_ssl,
max_url_len=max_url_len)
# Pull back actual port used
self.port = self.server.port
self.backdoor_port = None


初始化loader:

self.loader = loader or wsgi.Loader()


class Loader(object):
"""Used to load WSGI applications from paste configurations."""

def __init__(self, config_path=None):
"""Initialize the loader, and attempt to find the config.

:param config_path: Full or relative path to the paste config.
:returns: None

"""
self.config_path = None
#设置paste配置文件路径
config_path = config_path or CONF.api_paste_config
if not os.path.isabs(config_path):
self.config_path = CONF.find_file(config_path)
elif os.path.exists(config_path):
self.config_path = config_path

if not self.config_path:
raise exception.ConfigNotFound(path=config_path)
<pre name="code" class="python">    def load_app(self, name):
"""Return the paste URLMap wrapped WSGI application.

:param name: Name of the application to load.
:returns: Paste URLMap object wrapping the requested application.
:raises: `nova.exception.PasteAppNotFound`

"""
try:
LOG.debug("Loading app %(name)s from %(path)s",
{'name': name, 'path': self.config_path})
#调用loadapp加载配置文件
return deploy.loadapp("config:%s" % self.config_path, name=name)
except LookupError as err:
LOG.error(err)
raise exception.PasteAppNotFound(name=name, path=self.config_path)




加载paste配置文件:

self.app = self.loader.load_app(name)

paste配置文件:

[app:osapi_compute_app_v2]paste.app_factory = nova.api.openstack.compute:APIRouter.factory通过此配置项,paste把应用路由到APIRouter的方法中,下面重点分析一下APIRouter方法

由于class APIRouter(nova.api.openstack.APIRouter)此类继承自nova.api.openstack.APIRouter父类,先看看父类

class APIRouter(base_wsgi.Router):
"""Routes requests on the OpenStack API to the appropriate controller
and method.
"""
ExtensionManager = None  # override in subclasses

#paste配置文件加载app配置工厂函数,加载配置路由的入口
@classmethod
def factory(cls, global_config, **local_config):
"""Simple paste factory, :class:`nova.wsgi.Router` doesn't have one."""
#调用类init方法
return cls()

def __init__(self, ext_mgr=None, init_only=None):
if ext_mgr is None:
 #在子类中定义了ExtensionManager = extensions.ExtensionManager
if self.ExtensionManager:
 #初始化ExtensionManager实例
ext_mgr = self.ExtensionManager()
else:
raise Exception(_("Must specify an ExtensionManager class"))
#生成mapper实例,后面调用mapper.<span><span><span><span><span><span><span>resource</span></span></span></span></span></span></span>来加载路由信息
mapper = ProjectMapper()
#定义resources资源
self.resources = {}
#加载核心路由,nova.api.openstack.compute下面的控制文件
 self._setup_routes(mapper, ext_mgr, init_only)
#加载contrib目录下的文件路由,所有文件已经在ext_mgr实例中保存
self._setup_ext_routes(mapper, ext_mgr, init_only)
self._setup_extensions(ext_mgr)
super(APIRouter, self).__init__(mapper)

def _setup_ext_routes(self, mapper, ext_mgr, init_only):
for resource in ext_mgr.get_resources():
LOG.debug('Extending resource: %s',
resource.collection)

if init_only is not None and resource.collection not in init_only:
continue

inherits = None
if resource.inherits:
inherits = self.resources.get(resource.inherits)
if not resource.controller:
resource.controller = inherits.controller
wsgi_resource = wsgi.Resource(resource.controller,
inherits=inherits)
self.resources[resource.collection] = wsgi_resource
kargs = dict(
controller=wsgi_resource,
collection=resource.collection_actions,
member=resource.member_actions)

if resource.parent:
kargs['parent_resource'] = resource.parent

mapper.resource(resource.collection, resource.collection, **kargs)

if resource.custom_routes_fn:
resource.custom_routes_fn(mapper, wsgi_resource)

def _setup_extensions(self, ext_mgr):
for extension in ext_mgr.get_controller_extensions():
collection = extension.collection
controller = extension.controller

msg_format_dict = {'collection': collection,
'ext_name': extension.extension.name}
if collection not in self.resources:
LOG.warn(_LW('Extension %(ext_name)s: Cannot extend '
'resource %(collection)s: No such resource'),
msg_format_dict)
continue

LOG.debug('Extension %(ext_name)s extended resource: '
'%(collection)s',
msg_format_dict)

resource = self.resources[collection]
resource.register_actions(controller)
resource.register_extensions(controller)

def _setup_routes(self, mapper, ext_mgr, init_only):
raise NotImplementedError()


ExtensionManger类,此类继承自父类nova.api.openstack.ExtensionManger

class ExtensionManager(base_extensions.ExtensionManager):
def __init__(self):
LOG.audit(_('Initializing extension manager.'))
#定义cls_list为nova.api.openstack.compute.contrib.standard_extensions ,指定contrib目录加载类
 self.cls_list = CONF.osapi_compute_extension
self.extensions = {}
self.sorted_ext_list = []
#调用父类方法_load_extensions()
self._load_extensions()


ExtensionManger父类中方法:

def load_extension(self, ext_factory):
"""Execute an extension factory.

Loads an extension.  The 'ext_factory' is the name of a
callable that will be imported and called with one
argument--the extension manager.  The factory callable is
expected to call the register() method at least once.
"""

LOG.debug("Loading extension %s", ext_factory)

if isinstance(ext_factory, six.string_types):
# Load the factory
 #根据函数路径,import加载文件
factory = importutils.import_class(ext_factory)
else:
factory = ext_factory

# Call it
LOG.debug("Calling extension factory %s", ext_factory)
#调用函数nova.api.openstack.compute.contrib.standard_extensions
factory(self)

def _load_extensions(self):
"""Load extensions specified on the command line."""

extensions = list(self.cls_list)

for ext_factory in extensions:
try:
#加载扩展路由方法,通过指定contrib目录加载类
 self.load_extension(ext_factory)
except Exception as exc:
LOG.warn(_LW('Failed to load extension %(ext_factory)s: '
'%(exc)s'),
{'ext_factory': ext_factory, 'exc': exc})


nova.api.openstack.compute.contrib目录下的standard_extensions函数

def standard_extensions(ext_mgr):
extensions.load_standard_extensions(ext_mgr, LOG, __path__, __package__)


调用了在nova.api.openstack.extensions下的load_standard_extensions函数

def load_standard_extensions(ext_mgr, logger, path, package, ext_list=None):
"""Registers all standard API extensions."""

# Walk through all the modules in our directory...
our_dir = path[0]
for dirpath, dirnames, filenames in os.walk(our_dir):
# Compute the relative package name from the dirpath
relpath = os.path.relpath(dirpath, our_dir)
if relpath == '.':
relpkg = ''
else:
relpkg = '.%s' % '.'.join(relpath.split(os.sep))

# Now, consider each file in turn, only considering .py files
for fname in filenames:
root, ext = os.path.splitext(fname)

# Skip __init__ and anything that's not .py
if ext != '.py' or root == '__init__':
continue

# Try loading it
#生成路由文件名中类名,首字母大写
 classname = "%s%s" % (root[0].upper(), root[1:])
classpath = ("%s%s.%s.%s" %
(package, relpkg, root, classname))

if ext_list is not None and classname not in ext_list:
logger.debug("Skipping extension: %s" % classpath)
continue

try:
#加载contrib目录下路由类
                ext_mgr.load_extension(classpath)
except Exception as exc:
logger.warn(_('Failed to load extension %(classpath)s: '
'%(exc)s'),
{'classpath': classpath, 'exc': exc})

# Now, let's consider any subdirectories we may have...
#如果包含子目录,处理子目录中的文件
subdirs = []
for dname in dirnames:
# Skip it if it does not have __init__.py
if not os.path.exists(os.path.join(dirpath, dname, '__init__.py')):
continue

# If it has extension(), delegate...
ext_name = "%s%s.%s.extension" % (package, relpkg, dname)
try:
ext = importutils.import_class(ext_name)
except ImportError:
# extension() doesn't exist on it, so we'll explore
# the directory for ourselves
subdirs.append(dname)
else:
try:
ext(ext_mgr)
except Exception as exc:
logger.warn(_('Failed to load extension %(ext_name)s:'
'%(exc)s'),
{'ext_name': ext_name, 'exc': exc})

# Update the list of directories we'll explore...
dirnames[:] = subdirs

分析一下ext_mgr.load_extension(classpath)加载类文件的核心方法:

def load_extension(self, ext_factory):
"""Execute an extension factory.

Loads an extension.  The 'ext_factory' is the name of a
callable that will be imported and called with one
argument--the extension manager.  The factory callable is
expected to call the register() method at least once.
"""

LOG.debug("Loading extension %s", ext_factory)
#ext_factory为字符类型加载此class
if isinstance(ext_factory, six.string_types):
# Load the factory
#加载ext_factory类文件,方法import_class
 factory = importutils.import_class(ext_factory)
else:
factory = ext_factory

# Call it
LOG.debug("Calling extension factory %s", ext_factory)
#调用类文件,初始化类
factory(self)


import_class方法用来加载类文件:

def import_class(import_str):
"""Returns a class from a string including module and class."""
#分拆类文件字符串
mod_str, _sep, class_str = import_str.rpartition('.')
#调用内部方法import模块文件mod_str
__import__(mod_str)
try:
#返回模块mod_str下类class_str
      return getattr(sys.modules[mod_str], class_str)
except AttributeError:
raise ImportError('Class %s cannot be found (%s)' %
(class_str,
traceback.format_exception(*sys.exc_info())))
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  openstack