猫型エンジニアのブログ

プログラム/ネットワーク系の技術関連をまとめたページです 

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
値:

contexts = {}