openstack nova-api启动流程
2016-04-20 14:53
267 查看
一、预备知识
nova-api服务启动过程比较简单,难点在于它用到的一些库不了解,建议先了解一下python paste.deploy,routes,webob这些这些模块。paste.deploy
主要是通过解析/etc/nova/api-paste.ini,根据指定的name来加载wsgi app。
webob
WebOb是一个用于对WSGI request环境进行包装以及用于创建WSGIresponse的一个包。简化了wsgi app的编写。
routes
定义请求到具体函数的映射nova-api启动流程
在/usr/bin下有个nova-api脚本,这是整个过程的入口。我们可以将它的内容打印出来看看import sys from nova.cmd.api import main if __name__=="__main__": sys.exit(main())可以看到,执行的是nova/cmd/api.py中mian。我们再去看看api.py的main函数
def main(): config.parse_args(sys.argv) logging.setup(CONF, "nova") utils.monkey_patch() objects.register_all() gmr.TextGuruMeditation.setup_autorun(version) launcher = service.process_launcher() for api in CONF.enabled_apis: should_use_ssl = api in CONF.enabled_ssl_apis if api == 'ec2': server = service.WSGIService(api, use_ssl=should_use_ssl, max_url_len=16384) else: server = service.WSGIService(api, use_ssl=should_use_ssl) launcher.launch_service(server, workers=server.workers or 1) launcher.wait()首先是解析参数:
config.parse_args(sys.argv)然后设置日志
logging.setup(CONF, "nova")打补丁,不明白
utils.monkey_patch()获取服务启动器
launcher = service.process_launcher()重头戏来了,启动服务
for api in CONF.enabled_apis: should_use_ssl = api in CONF.enabled_ssl_apis if api == 'ec2': server = service.WSGIService(api, use_ssl=should_use_ssl, max_url_len=16384) else: server = service.WSGIService(api, use_ssl=should_use_ssl) launcher.launch_service(server, workers=server.workers or 1)来看看service.WSGIService到底是什么东西,贴出部分WSGIService代码
class WSGIService(object): """Provides ability to launch API from a 'paste' configuration.""" 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() self.loader = loader or wsgi.Loader() self.app = self.loader.load_app(name) # inherit all compute_api worker counts from osapi_compute if name.startswith('openstack_compute_api'): wname = 'osapi_compute' else: wname = 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' % wname, 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"""Provides ability to launch API from a 'paste' configuration."""
意思是通过paste配置来生成WSGI的app。
着重看一下这里面的loader,这是用来启动app的。
self.loader = loader or wsgi.Loader()看一下nova/wsgi.py中的Loader,通过paste配置来启动wsgi app
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 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) 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}) return deploy.loadapp("config:%s" % self.config_path, name=name) except LookupError: LOG.exception(_LE("Couldn't lookup app: %s"), name) raise exception.PasteAppNotFound(name=name, path=self.config_path)可以看到load_app是通过deploy.loadapp()来启动wsgi app
然后是:
launcher.launch_service(server, workers=server.workers or 1)看看launch_service()是什么
def launch_service(self, service, workers=1): wrap = ServiceWrapper(service, workers) LOG.info(_LI('Starting %d workers'), wrap.workers) while self.running and len(wrap.children) < wrap.workers: self._start_child(wrap)ServiceWrapper是一类,类似于C语言中结构体的作用
class ServiceWrapper(object): def __init__(self, service, workers): self.service = service self.workers = workers self.children = set() self.forktimes = []
def _start_child(self, wrap): if len(wrap.forktimes) > wrap.workers: # Limit ourselves to one process a second (over the period of # number of workers * 1 second). This will allow workers to # start up quickly but ensure we don't fork off children that # die instantly too quickly. if time.time() - wrap.forktimes[0] < wrap.workers: LOG.info(_LI('Forking too fast, sleeping')) time.sleep(1) wrap.forktimes.pop(0) wrap.forktimes.append(time.time()) pid = os.fork() if pid == 0: launcher = self._child_process(wrap.service) while True: self._child_process_handle_signal() status, signo = self._child_wait_for_exit_or_signal(launcher) if not _is_sighup_and_daemon(signo): break launcher.restart() os._exit(status) LOG.info(_LI('Started child %d'), pid) wrap.children.add(pid) self.children[pid] = wrap return pid首先,os.fork()返回值可能为0,表示子进程本身,或者大于0表示父进程。
在这里,父进程主要是创建子进程,更新warp信息,返回子进程的pid。
当pid=0时表示子进程,子进程的话先通过launcher
= self._child_process(wrap.service)启动对应的服务,然后就是while循环等待信号。如果有终止的信号量就结束,否则则重新启动进程。
最后是
launcher.wait()
它的注释是:"""Loop waiting on children to die and respawning as necessary."""。它的作用是循环监听子进程是否挂掉,如果挂掉则重启。如果收到终止的信号,则kill所有的children然后结束自己。
相关文章推荐
- Knockout初体验--监控属性
- 三层架构实战篇—系统登录实例
- _doPostBack简介
- 三层架构(我的理解及详细分析)
- linux下tar等打包压缩工具及while语句编写脚本(九)
- log4j.properties配置详解与实例-全部测试通过
- centos mysql安装 完全版
- Unhandled event loop exception Item not added
- Linux常用命令
- linux常用脚本
- 关于OpenCV的那些事——利用RANSAC消除错误姿态
- selenium测试相关的网站
- openstack-nova学习
- 查看Linux下系统资源占用常用命令(top、free、uptime)
- 钻一钻Tomcat 之 Tomcat不配置环境变量(Ⅶ)
- Linux系统下-进程间通信(共享内存-详解)
- 【shell】变量
- 关于linux下wireshark启动时Lua报错
- Android——MVP架构
- 如何将Linux rm命令删除的文件放入垃圾箱