service.py では、3つのクラスとサービス起動・停止の為の多数のメソッドが定義 されています。
class Launcher(object):
def __init__(self):
def run_server(server):
def launch_server(self, server):
def stop(self):
def wait(self):
class Service(object):
def __init__(self, host, binary, topic, manager, report_interval=None,
self.manager_class_name = manager
manager_class = utils.import_class(self.manager_class_name)
self.manager = manager_class(host=self.host, *args, **kwargs)
def start(self):
def _create_service_ref(self, context):
def __getattr__(self, key):
@classmethod
def create(cls, host=None, binary=None, topic=None, manager=None,
"""Instantiates class and passes back application object.
def kill(self):
def stop(self):
def wait(self):
def periodic_tasks(self, raise_on_error=False):
def report_state(self):
class WSGIService(object):
def __init__(self, name, loader=None):
def _get_manager(self):
Use the service name to look up a Manager subclass from the
configuration and initialize an instance. If no class name
manager_class_name = FLAGS.get(fl, None)
if not manager_class_name:
manager_class = utils.import_class(manager_class_name)
return manager_class()
def start(self):
def stop(self):
def wait(self):
def serve(*servers):
def wait():
先程の nova-scheduler で呼び出していた service.Service.create(binary=’ nova-scheduler’) を見てみましょう。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 | class Service(object):
@classmethod
def create(cls, host=None, binary=None, topic=None, manager=None,
report_interval=None, periodic_interval=None):
"""Instantiates class and passes back application object.
:param host: defaults to FLAGS.host
:param binary: defaults to basename of executable
:param topic: defaults to bin_name - 'nova-' part
:param manager: defaults to FLAGS.<topic>_manager
:param report_interval: defaults to FLAGS.report_interval
:param periodic_interval: defaults to FLAGS.periodic_interval
"""
if not host:
host = FLAGS.host
if not binary:
binary = os.path.basename(inspect.stack()[-1][1])
if not topic:
topic = binary.rpartition('nova-')[2]
if not manager:
manager = FLAGS.get('%s_manager' % topic, None)
if not report_interval:
report_interval = FLAGS.report_interval
if not periodic_interval:
periodic_interval = FLAGS.periodic_interval
service_obj = cls(host, binary, topic, manager,
report_interval, periodic_interval)
return service_obj
|
binary 引数が省略された場合、binary 変数は実行したコマンド名(例: /usr/bin/nova-scheduler)から取得されます。 nova-scheduler の場合、binary 引数には ‘nova-scheduler’ がセットされていま すので、
変数名 | 値 |
cls | service.Service クラス自体(@classmethod による第一引数) |
host | nova.conf 中の host パラメータ値(又は自動取得されたホスト名) |
binary | ‘nova-scheduler’ |
topic | scheduler’ |
manager | nova.conf 中の scheduler_manager パラメータ値 |
report_interval | nova.conf 中の report_intervalt パラメータ値 |
periodic_interval | nova.conf 中の periodic_intervalt パラメータ値 |
となり、27 行目にて service.Service クラスのコンストラクタが呼ばれ、生成さ れたインスタンスが return されます。イニシエータは以下の通りです。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | class Service(object):
def __init__(self, host, binary, topic, manager, report_interval=None,
periodic_interval=None, *args, **kwargs):
self.host = host
self.binary = binary
self.topic = topic
self.manager_class_name = manager
manager_class = utils.import_class(self.manager_class_name)
self.manager = manager_class(host=self.host, *args, **kwargs)
self.report_interval = report_interval
self.periodic_interval = periodic_interval
super(Service, self).__init__(*args, **kwargs)
self.saved_args, self.saved_kwargs = args, kwargs
self.timers = []
|
8 行目でマネージャクラス(scheduler_manager パラメータ値で指定)自体を取得 し、9 行目でそのインスタンスを取得しています。
インスタンスはその後、nova-scheduler の中の
server = service.Service.create(binary='nova-scheduler')
service.serve(server)
service.wait()
の部分で使用されます。service.serve(server), service.wait() は下記の通りです。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 | # NOTE(vish): the global launcher is to maintain the existing
# functionality of calling service.serve +
# service.wait
_launcher = None
def serve(*servers):
global _launcher
if not _launcher:
_launcher = Launcher()
for server in servers:
_launcher.launch_server(server)
def wait():
LOG.debug(_('Full set of FLAGS:'))
for flag in FLAGS:
flag_get = FLAGS.get(flag, None)
# hide flag contents from log if contains a password
# should use secret flag when switch over to openstack-common
if ("_password" in flag or "_key" in flag or
(flag == "sql_connection" and "mysql:" in flag_get)):
LOG.debug(_('%(flag)s : FLAG SET ') % locals())
else:
LOG.debug('%(flag)s : %(flag_get)s' % locals())
try:
_launcher.wait()
except KeyboardInterrupt:
_launcher.stop()
rpc.cleanup()
|
_launcher.launch_server() 以降は Server クラスと Launcher クラスの間で行っ たり来たりするので、説明は割愛しますが、結果として service.Service.start() メソッドが呼び出されます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 | class Service(object):
def start(self):
vcs_string = version.version_string_with_vcs()
LOG.audit(_('Starting %(topic)s node (version %(vcs_string)s)'),
{'topic': self.topic, 'vcs_string': vcs_string})
utils.cleanup_file_locks()
self.manager.init_host()
self.model_disconnected = False
ctxt = context.get_admin_context()
try:
service_ref = db.service_get_by_args(ctxt,
self.host,
self.binary)
self.service_id = service_ref['id']
except exception.NotFound:
self._create_service_ref(ctxt)
if 'nova-compute' == self.binary:
self.manager.update_available_resource(ctxt)
self.conn = rpc.create_connection(new=True)
LOG.debug(_("Creating Consumer connection for Service %s") %
self.topic)
# Share this same connection for these Consumers
self.conn.create_consumer(self.topic, self, fanout=False)
node_topic = '%s.%s' % (self.topic, self.host)
self.conn.create_consumer(node_topic, self, fanout=False)
self.conn.create_consumer(self.topic, self, fanout=True)
# Consume from all consumers in a thread
self.conn.consume_in_thread()
if self.report_interval:
pulse = utils.LoopingCall(self.report_state)
pulse.start(interval=self.report_interval, now=False)
self.timers.append(pulse)
if self.periodic_interval:
periodic = utils.LoopingCall(self.periodic_tasks)
periodic.start(interval=self.periodic_interval, now=False)
self.timers.append(periodic)
|
この中では以下の処理が実行されます。
以降、nova-api 以外の nova の各種サービスはタイマーによって定時処理を行いつ つ、RPC によって自身に指示が来るのを待つようになります(イベントドリブン)。
nova-api は RPC を送る事はあっても受ける事はありません。RESTful API にてク ライアントからのリクエストを受け取り、それを RPC で別の nova コンポーネント に送ったりします。