当在conductor中通过_schedule_instances 来调用select_destinations
def _schedule_instances(self, context, request_spec, filter_properties):
scheduler_utils.setup_instance_group(context, request_spec,
filter_properties)
# TODO(sbauza): Hydrate here the object until we modify the
# scheduler.utils methods to directly use the RequestSpec object
spec_obj = objects.RequestSpec.from_primitives(
context, request_spec, filter_properties)
hosts = self.scheduler_client.select_destinations(context, spec_obj)
return hosts
从computerTaskmanager中__init__ 中的赋值
from nova.scheduler import client as scheduler_client
self.scheduler_client = scheduler_client.SchedulerClient()
可以看出调用select_destinations 是会调用到scheduler/query.py 中的
from nova.scheduler import rpcapi as scheduler_rpcapi
class SchedulerQueryClient(object):
"""Client class for querying to the scheduler."""
def __init__(self):
self.scheduler_rpcapi = scheduler_rpcapi.SchedulerAPI()
def select_destinations(self, context, spec_obj):
"""Returns destinations(s) best suited for this request_spec and
filter_properties.
The result should be a list of dicts with 'host', 'nodename' and
'limits' as keys.
"""
return self.scheduler_rpcapi.select_destinations(context, spec_obj)
可以看出scheduler_rpcapi 就是nova.scheduler.rpcapi.py
从SchedulerAPI中的
def select_destinations(self, ctxt, spec_obj):
version = '4.3'
msg_args = {'spec_obj': spec_obj}
if not self.client.can_send_version(version):
del msg_args['spec_obj']
msg_args['request_spec'] = spec_obj.to_legacy_request_spec_dict()
msg_args['filter_properties'
] = spec_obj.to_legacy_filter_properties_dict()
version = '4.0'
cctxt = self.client.prepare(version=version)
return cctxt.call(ctxt, 'select_destinations', **msg_args)
可以看出这里通过cctxt.call 来进行rpc远程调用,cctxt.call表示会阻塞进程,等待执行结果的返回.这里远程调用到scheduler/manager.py
def select_destinations(self, ctxt,
request_spec=None, filter_properties=None,
spec_obj=_sentinel):
"""Returns destinations(s) best suited for this RequestSpec.
The result should be a list of dicts with 'host', 'nodename' and
'limits' as keys.
"""
# TODO(sbauza): Change the method signature to only accept a spec_obj
# argument once API v5 is provided.
if spec_obj is self._sentinel:
spec_obj = objects.RequestSpec.from_primitives(ctxt,
request_spec,
filter_properties)
dests = self.driver.select_destinations(ctxt, spec_obj)
return jsonutils.to_primitive(dests)
这里会调用driver.select_destinations,这里的driver 会从nova.conf文件中读取
def __init__(self, scheduler_driver=None, *args, **kwargs):
if not scheduler_driver:
scheduler_driver = CONF.scheduler_driver
try:
self.driver = driver.DriverManager(
"nova.scheduler.driver",
scheduler_driver,
invoke_on_load=True).driver
在nova.conf 中一般赋值如下:
scheduler_driver = nova.scheduler.filter_scheduler.FilterScheduler
这里的调度器主要有三个实现分别是filter_scheduler.py/chance.py/caching_scheduler.py。从nova.conf中给
scheduler_driver 赋值来看,这三个调度器不能共存,必须选择一个,这里默认用的是FilterScheduler
其中FilterScheduler(driver.Scheduler),也就是说driver.Scheduler是FilterScheduler的父类
而driver.Scheduler 实现如下:
class Scheduler(object):
"""The base class that all Scheduler classes should inherit from."""
def __init__(self):
self.host_manager = driver.DriverManager(
"nova.scheduler.host_manager",
CONF.scheduler_host_manager,
invoke_on_load=True).driver
self.servicegroup_api = servicegroup.API()
def run_periodic_tasks(self, context):
"""Manager calls this so drivers can perform periodic tasks."""
pass
def hosts_up(self, context, topic):
"""Return the list of hosts that have a running service for topic."""
services = objects.ServiceList.get_by_topic(context, topic)
return [service.host
for service in services
if self.servicegroup_api.service_is_up(service)]
@abc.abstractmethod
def select_destinations(self, context, spec_obj):
"""Must override select_destinations method.
:return: A list of dicts with 'host', 'nodename' and 'limits' as keys
that satisfies the request_spec and filter_properties.
"""
return []
可见实现了run_periodic_tasks/hosts_up/select_destinations 这三个接口.子类只要实现这三个接口中的至少一个就行,这里最重要的是select_destinations,也就是要自己写调度器的话,必须实现这个接口.
其中CachingScheduler(filter_scheduler.FilterScheduler):的实现比较简单,仅仅是调用FilterScheduler的
select_destinations
我们这里以chance.py 为例
def _schedule(self, context, topic, spec_obj):
"""Picks a host that is up at random."""
elevated = context.elevated()
hosts = self.hosts_up(elevated, topic)
if not hosts:
msg = _("Is the appropriate service running?")
raise exception.NoValidHost(reason=msg)
hosts = self._filter_hosts(hosts, spec_obj)
if not hosts:
msg = _("Could not find another compute")
raise exception.NoValidHost(reason=msg)
return random.choice(hosts)
def select_destinations(self, context, spec_obj):
"""Selects random destinations."""
num_instances = spec_obj.num_instances
# NOTE(timello): Returns a list of dicts with 'host', 'nodename' and
# 'limits' as keys for compatibility with filter_scheduler.
dests = []
for i in range(num_instances):
host = self._schedule(context, CONF.compute_topic, spec_obj)
host_state = dict(host=host, nodename=None, limits=None)
dests.append(host_state)
if len(dests) < num_instances:
reason = _('There are not enough hosts available.')
raise exception.NoValidHost(reason=reason)
return dests
在select_destinations 通过调用_schedule 来在符合条件的host中随机选择一个host。最终要的一条语句就是
random.choice(hosts),这也是chance.py 这个调度器命名的原因.
def _schedule_instances(self, context, request_spec, filter_properties):
scheduler_utils.setup_instance_group(context, request_spec,
filter_properties)
# TODO(sbauza): Hydrate here the object until we modify the
# scheduler.utils methods to directly use the RequestSpec object
spec_obj = objects.RequestSpec.from_primitives(
context, request_spec, filter_properties)
hosts = self.scheduler_client.select_destinations(context, spec_obj)
return hosts
从computerTaskmanager中__init__ 中的赋值
from nova.scheduler import client as scheduler_client
self.scheduler_client = scheduler_client.SchedulerClient()
可以看出调用select_destinations 是会调用到scheduler/query.py 中的
from nova.scheduler import rpcapi as scheduler_rpcapi
class SchedulerQueryClient(object):
"""Client class for querying to the scheduler."""
def __init__(self):
self.scheduler_rpcapi = scheduler_rpcapi.SchedulerAPI()
def select_destinations(self, context, spec_obj):
"""Returns destinations(s) best suited for this request_spec and
filter_properties.
The result should be a list of dicts with 'host', 'nodename' and
'limits' as keys.
"""
return self.scheduler_rpcapi.select_destinations(context, spec_obj)
可以看出scheduler_rpcapi 就是nova.scheduler.rpcapi.py
从SchedulerAPI中的
def select_destinations(self, ctxt, spec_obj):
version = '4.3'
msg_args = {'spec_obj': spec_obj}
if not self.client.can_send_version(version):
del msg_args['spec_obj']
msg_args['request_spec'] = spec_obj.to_legacy_request_spec_dict()
msg_args['filter_properties'
] = spec_obj.to_legacy_filter_properties_dict()
version = '4.0'
cctxt = self.client.prepare(version=version)
return cctxt.call(ctxt, 'select_destinations', **msg_args)
可以看出这里通过cctxt.call 来进行rpc远程调用,cctxt.call表示会阻塞进程,等待执行结果的返回.这里远程调用到scheduler/manager.py
def select_destinations(self, ctxt,
request_spec=None, filter_properties=None,
spec_obj=_sentinel):
"""Returns destinations(s) best suited for this RequestSpec.
The result should be a list of dicts with 'host', 'nodename' and
'limits' as keys.
"""
# TODO(sbauza): Change the method signature to only accept a spec_obj
# argument once API v5 is provided.
if spec_obj is self._sentinel:
spec_obj = objects.RequestSpec.from_primitives(ctxt,
request_spec,
filter_properties)
dests = self.driver.select_destinations(ctxt, spec_obj)
return jsonutils.to_primitive(dests)
这里会调用driver.select_destinations,这里的driver 会从nova.conf文件中读取
def __init__(self, scheduler_driver=None, *args, **kwargs):
if not scheduler_driver:
scheduler_driver = CONF.scheduler_driver
try:
self.driver = driver.DriverManager(
"nova.scheduler.driver",
scheduler_driver,
invoke_on_load=True).driver
在nova.conf 中一般赋值如下:
scheduler_driver = nova.scheduler.filter_scheduler.FilterScheduler
这里的调度器主要有三个实现分别是filter_scheduler.py/chance.py/caching_scheduler.py。从nova.conf中给
scheduler_driver 赋值来看,这三个调度器不能共存,必须选择一个,这里默认用的是FilterScheduler
其中FilterScheduler(driver.Scheduler),也就是说driver.Scheduler是FilterScheduler的父类
而driver.Scheduler 实现如下:
class Scheduler(object):
"""The base class that all Scheduler classes should inherit from."""
def __init__(self):
self.host_manager = driver.DriverManager(
"nova.scheduler.host_manager",
CONF.scheduler_host_manager,
invoke_on_load=True).driver
self.servicegroup_api = servicegroup.API()
def run_periodic_tasks(self, context):
"""Manager calls this so drivers can perform periodic tasks."""
pass
def hosts_up(self, context, topic):
"""Return the list of hosts that have a running service for topic."""
services = objects.ServiceList.get_by_topic(context, topic)
return [service.host
for service in services
if self.servicegroup_api.service_is_up(service)]
@abc.abstractmethod
def select_destinations(self, context, spec_obj):
"""Must override select_destinations method.
:return: A list of dicts with 'host', 'nodename' and 'limits' as keys
that satisfies the request_spec and filter_properties.
"""
return []
可见实现了run_periodic_tasks/hosts_up/select_destinations 这三个接口.子类只要实现这三个接口中的至少一个就行,这里最重要的是select_destinations,也就是要自己写调度器的话,必须实现这个接口.
其中CachingScheduler(filter_scheduler.FilterScheduler):的实现比较简单,仅仅是调用FilterScheduler的
select_destinations
我们这里以chance.py 为例
def _schedule(self, context, topic, spec_obj):
"""Picks a host that is up at random."""
elevated = context.elevated()
hosts = self.hosts_up(elevated, topic)
if not hosts:
msg = _("Is the appropriate service running?")
raise exception.NoValidHost(reason=msg)
hosts = self._filter_hosts(hosts, spec_obj)
if not hosts:
msg = _("Could not find another compute")
raise exception.NoValidHost(reason=msg)
return random.choice(hosts)
def select_destinations(self, context, spec_obj):
"""Selects random destinations."""
num_instances = spec_obj.num_instances
# NOTE(timello): Returns a list of dicts with 'host', 'nodename' and
# 'limits' as keys for compatibility with filter_scheduler.
dests = []
for i in range(num_instances):
host = self._schedule(context, CONF.compute_topic, spec_obj)
host_state = dict(host=host, nodename=None, limits=None)
dests.append(host_state)
if len(dests) < num_instances:
reason = _('There are not enough hosts available.')
raise exception.NoValidHost(reason=reason)
return dests
在select_destinations 通过调用_schedule 来在符合条件的host中随机选择一个host。最终要的一条语句就是
random.choice(hosts),这也是chance.py 这个调度器命名的原因.