创建 RequestSpec 对象¶
https://blueprints.launchpad.net/nova/+spec/request-spec-object
添加一个结构化、文档化的对象,用于表示在云中启动多个实例的规范。
问题描述¶
调度器的主要接口,select_destinations() 方法,接受一个 request_spec 参数,该参数是一个嵌套字典。该嵌套字典是在 nova.scheduler.utils.build_request_spec() 中构建的,但是请求规范的结构在任何地方都没有文档说明,并且调度器中的过滤器似乎对在调度期间查询该对象以及在 nova.scheduler.host_manager.HostStateManager.get_filtered_hosts() 方法的循环中修改 request_spec 对象采取了一种放任自流的态度,该方法调用过滤器的 host_passes 对象,并提供一个 filter_properties 参数,该参数本身包含一个名为 request_spec 的键,其中包含上述嵌套字典。
这种情况使得很难理解调度器中到底发生了什么,并且清理调度器接口中的此参数是为调度器代码的拆分做准备,以便创建一个正确版本化和正确文档化的接口的先决条件。
用例¶
这是一项纯粹的重构工作,旨在清理 Nova 和调度器之间的所有接口,以便在下一个周期中可以拆分调度器。
项目优先级¶
此蓝图是围绕“调度器”重构的全球努力的一部分,旨在帮助将其拆分。 这已被定义为本 Kilo 周期中的第三优先级。
提议的变更¶
将创建一个名为 RequestSpec 的新类,用于模拟请求启动多个虚拟机实例。 RequestSpec 对象的第一个版本将只是当前字典参数的对象化版本。 调度器将从 request_spec 字典本身构建此 RequestSpec 对象。
现有的 nova.scheduler.utils.build_request_spec 方法将被移除,以支持 nova.objects.request_spec.RequestSpec 上的一个工厂方法,该方法将从提供给 select_destinations 的 request_spec 参数中的现有键/值对构建一个 RequestSpec。
备选方案¶
无。
数据模型影响¶
此规范不侧重于持久化 RequestSpec 对象,但将提出另一个蓝图(和一个规范),并将此规范作为依赖项,为 RequestSpec 对象提供一个 save() 方法,该方法将允许将其持久化在(可能)instance_extra DB 表中。
REST API 影响¶
无。
安全影响¶
无。
通知影响¶
无。
其他最终用户影响¶
无。
性能影响¶
无。
其他部署者影响¶
无。
开发人员影响¶
除了使调度器调用接口逐渐更容易阅读和理解之外,没有其他影响。
实现¶
当前由 nova-conductor 在调用 nova.scheduler.utils.build_request_spec() 函数时构建 request_spec 字典,其结构如下
def build_request_spec(ctxt, image, instances, instance_type=None):
"""Build a request_spec for the scheduler.
The request_spec assumes that all instances to be scheduled are the same
type.
"""
instance = instances[0]
if isinstance(instance, obj_base.NovaObject):
instance = obj_base.obj_to_primitive(instance)
if instance_type is None:
instance_type = flavors.extract_flavor(instance)
# NOTE(comstud): This is a bit ugly, but will get cleaned up when
# we're passing an InstanceType internal object.
extra_specs = db.flavor_extra_specs_get(ctxt, instance_type['flavorid'])
instance_type['extra_specs'] = extra_specs
request_spec = {
'image': image or {},
'instance_properties': instance,
'instance_type': instance_type,
'num_instances': len(instances),
# NOTE(alaski): This should be removed as logic moves from the
# scheduler to conductor. Provides backwards compatibility now.
'instance_uuids': [inst['uuid'] for inst in instances]}
return jsonutils.to_primitive(request_spec)
为了尽可能接近从嵌套字典的键到对象属性表示法的直接转换,RequestSpec 类的一个可能的第一个版本类接口如下所示
class RequestSpec(base.NovaObject):
"""Models the request to launch one or more instances in the cloud."""
VERSION = '1.0'
fields = {
'image': fields.DictOfStringsField(nullable=False),
# instance_properties could eventually be deconstructed into component
# parts
'instance_properties': fields.ObjectField('Instance'),
'instance_type': fields.ObjectField('Flavor', nullable=False),
'num_instances': fields.IntegerField(default=1),
}
由于 request_spec 字典中存在一个已弃用的 instance_uuids 字段,我们不会将此字段提供到 RequestSpec 对象中,而是将 RPC API 版本升级并将其从字典中删除,作为一项工作项目。
此蓝图不会更改 select_destinations 调度器 RPC API 方法,因此我们将在 nova-scheduler 端,从 FilterScheduler._schedule() 方法中的 request_spec 字典键构造一个 nova.objects.request_spec.RequestSpec 对象,如下所示
def _schedule(self, context, request_spec, filter_properties):
"""Returns a list of hosts that meet the required specs,
ordered by their fitness.
"""
elevated = context.elevated()
request_spec = objects.RequestSpec.from_dict(request_spec)
instance_type = request_spec.instance_type
update_group_hosts = self._setup_instance_group(context,
filter_properties)
config_options = self._get_configuration_options()
filter_properties.update({'context': context,
'request_spec': request_spec,
'config_options': config_options,
'instance_type': instance_type})
self.populate_filter_properties(request_spec,
filter_properties)
# Find our local list of acceptable hosts by repeatedly
# filtering and weighing our options. Each time we choose a
# host, we virtually consume resources on it so subsequent
# selections can adjust accordingly.
# Note: remember, we are using an iterator here. So only
# traverse this list once. This can bite you if the hosts
# are being scanned in a filter or weighing function.
hosts = self._get_all_host_states(elevated)
selected_hosts = []
if instance_uuids:
num_instances = len(instance_uuids)
else:
num_instances = request_spec.num_instances
for num in xrange(num_instances):
# Filter local hosts based on requirements ...
hosts = self.host_manager.get_filtered_hosts(hosts,
filter_properties, index=num)
实施此蓝图的最后步骤是更改所有调度器过滤器,以便通过对象表示法而不是字典表示法访问原始属性。
如上文“数据模型影响”部分所述,此蓝图目前不打算持久化此对象。 我们在此蓝图中也尚未删除 filter_properties 字典。
负责人¶
- 主要负责人
bauzas
- 其他贡献者
无
工作项¶
从 request_spec 中删除 instance_uuids 字段,并为调度器 RPC API 升级版本
在 nova/scheduler/request_spec.py 中添加请求规范类,并附带单元测试
在 nova.scheduler.RequestSpec 上添加一个工厂类方法,该方法从传递给 nova.scheduler.utils.build_request_spec 函数的现有实例类型 extra_specs、scheduler_hints、flavor 和 image 对象集合中构造一个 RequestSpec 对象。
修改 FilterScheduler._schedule() 以从提供的嵌套 request_spec 字典构造一个 RequestSpec 对象
将所有过滤器类更改为对 RequestSpec 对象而不是嵌套的 request_spec 字典进行操作。
添加开发人员参考文档,说明请求规范建模的内容。
依赖项¶
无。
测试¶
将添加新的请求规范对象单元测试。 现有的调度器过滤器单元测试将被修改,以访问 filter_properties 字典中的 RequestSpec 对象。
文档影响¶
更新任何可能引用旧字典访问的开发人员参考资料。
参考资料¶
此蓝图是整体工作的一部分,旨在清理、版本化和稳定 nova-api、nova-scheduler、nova-conductor 和 nova-compute 守护程序之间涉及调度和资源决策的接口。
有关 Kilo 目标蓝图的列表,请参阅 https://wiki.openstack.org/wiki/Gantt/kilo#Tasks。