支持按禁止的聚合成员过滤¶
https://blueprints.launchpad.net/nova/+spec/negative-aggregate-membership
此蓝图建议支持底层资源提供程序的聚合成员的负面过滤。
问题描述¶
Placement 目前支持 member_of 查询参数,用于 GET /resource_providers 和 GET /allocation_candidates 端点。该参数可以是“表示聚合 UUID 的字符串”,也可以是“以 in: 前缀开头,后跟逗号分隔的字符串列表,这些字符串表示聚合 UUID”。
例如,
&member_of=in:<agg1>,<agg2>&member_of=<agg3>
在逻辑上转换为
候选资源提供程序应位于 agg1 或 agg2 中的一个,但必须位于 agg3 中。(有关详细信息,请参阅 alloc-candidates-member-of 规范)
但是,API 中没有用于禁止聚合的表达式。换句话说,我们无法说“对于非特殊工作负载,不要使用此特殊聚合中的资源提供程序”。
用例¶
此功能对于为特定用户保留特殊资源非常有用。
用例 1¶
其中一些计算主机是 已许可的 Windows 计算主机,这意味着在此计算主机上启动的任何 VM 都将被视为已许可的 Windows 镜像,并且根据 VM 的使用情况,运营商将向最终用户收取费用。作为运营商,我希望避免在 已许可的 Windows 计算主机 上启动其他操作系统(Windows 操作系统)的镜像/卷。
用例 2¶
像 blazar 这样的预留项目希望为其主机预留拥有自己的聚合,以便没有预留的消费者可以被安排在该聚合之外,从而节省预留资源。
提议的变更¶
调整 member_of 参数的处理方式,以便可以将聚合表示为禁止的。禁止的聚合以前缀 ! 开头。
在以下示例中,
&member_of=!<agg1>
在逻辑上转换为
候选资源提供程序不应位于 agg1 中。
此负面表达式也可以在多个 member_of 参数中使用
&member_of=in:<agg1>,<agg2>&member_of=<agg3>&member_of=!<agg4>
在逻辑上转换为
候选资源提供程序必须是 agg1 或 agg2 中的至少一个,必须位于 agg3 中,并且不位于 agg4 中。
请注意,我们不支持在 in: 前缀中使用 !
&member_of=in:<agg1>,<agg2>,!<agg3>
将导致 HTTP 400 Bad Request 错误。
相反,我们支持 !in: 前缀
&member_of=!in:<agg1>,<agg2>,<agg3>
这等效于
member_of=!<agg1>&member_of=!<agg2>&member_of=!<agg3>
嵌套资源提供程序¶
对于嵌套资源提供程序,根提供程序上的聚合会自动跨越整个树。当根提供程序位于禁止的聚合中时,即使子提供程序不属于任何(或另一个不同的)聚合,子提供程序也无法成为候选者。
在以下环境中,例如,
+-----------------------+
| sharing storage (ss1) |
| agg: [aggB] |
+-----------+-----------+
| aggB
+------------------------------+ +--------------|--------------+
| +--------------------------+ | | +------------+------------+ |
| | compute node (cn1) | | | |compute node (cn2) | |
| | agg: [aggA] | | | | agg: [aggB] | |
| +-----+-------------+------+ | | +----+-------------+------+ |
| | parent | parent | | | parent | parent |
| +-----+------+ +----+------+ | | +----+------+ +----+------+ |
| | numa1_1 | | numa1_2 | | | | numa2_1 | | numa2_2 | |
| | agg:[aggC]| | agg:[] | | | | agg:[] | | agg:[] | |
| +-----+------+ +-----------+ | | +-----------+ +-----------+ |
+-------|----------------------+ +-----------------------------+
| aggC
+-----+-----------------+
| sharing storage (ss2) |
| agg: [aggC] |
+-----------------------+
排除约束如下
member_of=!<aggA>排除“cn1”、“numa1_1”和“numa1_2”。member_of=!<aggB>排除“cn2”、“numa2_1”、“numa2_2”和“ss1”。member_of=!<aggC>排除“numa1_1”和“ss2”。
请注意,这种跨越不会发生在编号的 member_of 参数上,该参数用于粒度请求
member_of<N>=!<aggA>排除“cn1”member_of<N>=!<aggB>排除“cn2”和“ss1”member_of<N>=!<aggC>排除“numa1_1”和“ss2”。
有关详细信息,请参阅 granular-resource-request 规范。
备选方案¶
我们可以使用禁止的特性来排除特定的资源提供程序,但如果我们使用特性,那么我们应该将 Blazar 或 windows 许可特性不仅放在根提供程序上,而且放在树中的每个资源提供程序上,所以我们不这样做。
我们还可以创建 nova 调度器过滤器来通过查看主机聚合关系对计算主机进行后处理,就像 BlazarFilter 今天所做的那样。但是,这效率低下,我们不想为 windows 许可用例开发/使用另一个过滤器。
数据模型影响¶
无。
REST API 影响¶
将创建一个新的微版本,该版本将更新 GET /allocation_candidates 和 GET /resource_providers 上 member_of 参数的验证,以接受 ! 作为聚合 UUID 的前缀,以及作为 in: 前缀的前缀,以表示需要排除前缀聚合(或聚合)。
安全影响¶
无。
通知影响¶
无。
其他最终用户影响¶
无。
性能影响¶
对数据库的查询将增加适度的复杂性,但现有的表索引应该可以很好地处理此问题。
其他部署者影响¶
无。
开发人员影响¶
这有助于我们开发一个简单的预留机制,而无需使用特定的 nova 过滤器,例如通过以下流程
希望启用 blazar 的运营商在
nova.conf中设置默认的禁止和必需的成员资格键。配置文件中的参数键类似于
[scheduler]/placement_req_default_forbidden_member_prefix,并且该值由运营商设置为reservation:。配置文件中的参数键类似于
[scheduler]/placement_req_required_member_prefix,并且该值由运营商设置为reservation:。
运营商启动服务并通过 blazar API 创建一个主机池以进行预留
Blazar 在初始化时创建一个 nova 聚合,其元数据为
reservation:<random_id>,作为 blazar 的空闲池Blazar 按照运营商的要求将主机放入空闲池聚合中
用户使用 blazar 进行主机预留并获取预留 ID
Blazar 从 blazar 的空闲池中选择一个主机
Blazar 为该预留创建一个新的 nova 聚合,并将该聚合的元数据键设置为
reservation:<resv_id>,并将预留主机放入该聚合中
用户使用具有
reservation:<resv_id>元数据/extra_specs 的 flavor/image 创建 VM 以消耗预留Nova 在 flavor 中发现 extra_spec 具有以
[scheduler]/placement_req_required_member_prefix中设置的内容开头的键,并查找具有指定元数据的表required_prefix = CONF.scheduler.placement_req_required_member_prefix # required_prefix = 'reservation:' required_meta_data = get_flavor_extra_spec_starts_with(required_prefix) # required_meta_data = 'reservation:<resv_id>' required_aggs = aggs_whose_metadata_is(required_meta_data) # required_aggs = [<An aggregate for the reservation>]
Nova 发现默认禁止聚合元数据前缀,在
[scheduler]/placement_req_default_forbidden_member_prefix中设置,通过 flavor 显式指定,因此跳过default_forbidden_prefix = CONF.scheduler.placement_req_default_forbidden_member_prefix # default_forbidden_prefix = ['reservation:'] forbidden_aggs = set() if not get_flavor_extra_spec_starts_with(default_forbidden_prefix): # this is skipped because 'reservation:' is in the flavor in this case forbidden_aggs = aggs_whose_metadata_starts_with(default_forbidden_prefix)
Nova 使用必需的和禁止的聚合调用 placement
# We don't have forbidden aggregates in this case ?member_of=<required_aggs>
用户使用不带预留的 flavor/image 创建 VM,即不带
reservation:<resv_id>元数据/extra_specs。Nova 在 flavor 中发现 extra_spec 没有以
[scheduler]/placement_req_required_member_prefix中设置的内容开头的键,因此没有获得必需的聚合required_prefix = CONF.scheduler.placement_req_required_member_prefix # required_prefix = 'reservation:' required_meta_data = get_flavor_extra_spec_starts_with(required_prefix) # required_meta_data = '' required_aggs = aggs_whose_metadata_is(required_meta_data) # required_aggs = set()
Nova 查找元数据以
[scheduler]/placement_req_default_forbidden_member_prefix中设置的内容开头的默认禁止聚合default_forbidden_prefix = CONF.scheduler.placement_req_default_forbidden_member_prefix # default_forbidden_prefix = ['reservation:'] forbidden_aggs = set() if not get_flavor_extra_spec_starts_with(default_forbidden_prefix): # This is not skipped now forbidden_aggs = aggs_whose_metadata_starts_with(default_forbidden_prefix) # forbidden_aggs = <blazar's free pool aggregates and the other reservation aggs>
Nova 使用必需的和禁止的聚合调用 placement
# We don't have required aggregates in this case ?member_of=!in:<forbidden_aggs>
请注意,nova 配置文件中的更改和请求过滤器中的更改只是一个示例,不在此规范的范围内。另一种方法是让 placement 了解默认的禁止特性/聚合(请参阅 Bi-directional enforcement of traits 规范)。但是,我们同意负责实例禁止/必需的特性/聚合的是 nova 而不是 placement。
升级影响¶
无。
实现¶
负责人¶
- 主要负责人
中村 哲郎 (nakamura.tetsuro@lab.ntt.co.jp)
工作项¶
更新
ResourceProviderList.get_all_by_filters和AllocationCandidates.get_by_requests方法,以更改数据库查询以过滤“不是此聚合”。更新 placement API 处理程序,用于
GET /resource_providers和GET /allocation_candidates,在一个新的微版本中将负面聚合传递给上述步骤中更改的方法,包括输入验证调整。添加对修改后的数据库查询的功能测试。
添加 gabbi 测试,以表达新的查询,包括成功的查询和应该导致 400 响应的查询。
API 更改的发布说明。
更新微版本文档以指示新版本。
更新 placement-api-ref 以显示新的查询处理方式。
依赖项¶
无。
测试¶
正常的函数和单元测试。
文档影响¶
记录 REST API 微版本到适当的参考文档中。