Ryuの起動プロセス
ryu/cmd/manager.pyのmain関数を読んでみました。
以下のように、ソースコードの一部分のみの実行も簡単にできるので、Pythonは本当に楽です。
>>> from ryu import utils >>> import inspect >>> import itertools >>> from ryu.base.app_manager import AppManager >>> mod = utils.import_module('rest.py') >>> print mod <module 'rest' from 'rest.pyc'>
ソースコードへのコメント
def main(args=None, prog=None): //引数の解析により、CONF.app_listsもしかはCONF.appに起動するアプリケーションを登録する。 try: CONF(args=args, prog=prog, project='ryu', version='ryu-manager %s' % version, default_config_files=['/usr/local/etc/ryu/ryu.conf']) except cfg.ConfigFilesNotFoundError: CONF(args=args, prog=prog, project='ryu', version='ryu-manager %s' % version) log.init_log() //app_listsに起動するアプリケーションが格納されている app_lists = CONF.app_lists + CONF.app # keep old behaivor, run ofp if no application is specified. //アプリケーションに何も指定しない場合でも、OpenFlowコントローラとして動作する if not app_lists: app_lists = ['ryu.controller.ofp_handler'] //AppManagerのインスタンスapp_mgrを重複しないように生成 app_mgr = AppManager.get_instance() //アプリケーションの読み込み(後述) app_mgr.load_apps(app_lists) //全モジュールの読み込み後に、コンテキストの作成 contexts = app_mgr.create_contexts() //リスト型オブジェクトであるサービス作成 services = [] //サービスに各アプリケーションごとのスレッドを追加 services.extend(app_mgr.instantiate_apps(**contexts)) //wsgiの開始(後述) webapp = wsgi.start_service(app_mgr) if webapp: thr = hub.spawn(webapp) services.append(thr) try: hub.joinall(services) finally: app_mgr.close()
アプリケーションの読み込み
def load_apps(self, app_lists): app_lists = [app for app in itertools.chain.from_iterable(app.split(',') for app in app_lists)] //個々のアプリケーションごとにループする while len(app_lists) > 0: app_cls_name = app_lists.pop(0) LOG.info('loading app %s', app_cls_name) //アプリケーションのモジュールのクラスの中から、RyuAppのサブクラスを返す cls = self.load_app(app_cls_name) if cls is None: continue //クラス名をキー、モジュール名を値とする辞書型の作成 //例 アプリケーションとしてsimple_switch.pyを選択した場合 //mod: simple_switch //cls: simple_switch.SimpleSwitch self.applications_cls[app_cls_name] = cls services = [] //clsの中で辞書型の_CONTEXTが定義されている場合、キーと値を返す。 //例 アプリケーションとしてrest.pyを選択した場合、key, context_clsはそれぞれ //wsgi <class 'ryu.app.wsgi.WSGIApplication'> //network <class 'ryu.controller.network.Network'> for key, context_cls in cls.context_iteritems(): //辞書型のcontexts_clsに、キーと値の登録 v = self.contexts_cls.setdefault(key, context_cls) //返り値のチェック assert v == context_cls //_CONTEXTの値がRyuAppのサブクラスの場合の処理 //register後ならばserviceにcontext_clsのモジュール名を重複しないように追加 if issubclass(context_cls, RyuApp): //イベントクラスが設定されていれば、serviceに追加する services.extend(get_dependent_services(context_cls)) # we can't load an app that will be initiataed for # contexts. //contexts_clsの値のモジュール名をcontext_moduleに登録 context_modules = map(lambda x: x.__module__, self.contexts_cls.values()) for i in get_dependent_services(cls): if not i in context_modules: //リストに要素を追加 services.append(i) if services: app_lists.extend(services)
クラス変数
似たような名前でとても混乱します。
例としてアプリケーションにrest.pyを指定した場合、
applications_cls
アプリケーションのモジュール名をキーに、RyuAppのサブクラスを値に持つ辞書型オブジェクト
キー:rest.py
クラス:
applications = {}
contexts_cls = {}
RyuAppのサブクラスにおいて定義されている_CONTEXTを保持する辞書型オブジェクト
キー:wsgi
値: