灵活预留使用强制执行

包含您的 Launchpad 蓝图的 URL

https://blueprints.launchpad.net/blazar/+spec/flexible-reservation-usage-enforcement

Blazar 预留提供资源的临时所有权。如果没有对预留施加配额,用户可能会预留所有云资源很长时间。为了避免资源短缺,操作员可能希望限制用户对预留的使用。由于云具有不同的使用模式,因此强制执行策略应具有灵活性。但是,有一些基本规则和策略适用于许多云,例如限制租赁的长度。

本规范建议通过一系列过滤器来启用策略限制,以应用于特定的预留请求。默认情况下,Blazar 将提供一组简单的默认过滤器。操作员或开发人员可以选择实现自己的自定义过滤器作为 Python 模块。此外,Blazar 将提供一个内置过滤器,该过滤器委托给外部 HTTP 服务,该服务提供兼容的接口。本规范包括对该接口的建议。总体方法类似于 Nova 的调度过滤器。

问题描述

Blazar 预留提供资源的临时所有权。如果没有对预留施加配额,用户可能会预留所有云资源很长时间。为了避免资源短缺,操作员可能希望限制用户对预留的使用。由于云具有不同的使用模式,因此强制执行策略应具有灵活性。但是,有一些基本规则和策略适用于许多云,例如限制租赁的长度;这些类型的策略理想情况下不应需要操作员进行大量设置。

用例

为了确保用户之间的良好资源共享,操作员可能希望应用诸如

  • 限制预留的持续时间

  • 限制预留的大小(主机数量、实例数量、浮动 IP 数量)

  • 限制待处理或活动的租赁数量

  • 更复杂的策略,考虑计算节点类型、每个项目的资源分配等。

从用户的角度来看,Blazar 接口将保持不变。唯一的区别可能是错误消息描述了为什么拒绝了预留操作。

提议的变更

我们建议向 Blazar 添加一个强制执行过滤器链。过滤器将按顺序执行,每个过滤器将其输入作为有关用户请求的信息(例如,租赁长度、其所需的预留以及用户 ID 和其项目 ID 等)。过滤器将不返回任何值,或者将引发一个错误,其中包含关于为什么请求失败的具体消息。如果过滤器不返回任何值,则链中的下一个过滤器将有机会响应输入。如果没有过滤器引发错误,则允许用户的请求。

我们将实现两个初始强制执行过滤器:第一个将拒绝任何长度超过阈值的租赁,第二个将委托给外部 HTTP 服务。例如,针对 Nova 配额运行的过滤器(例如,不允许物理主机上的预留超过项目实例配额),将是此模式的未来扩展。

强制执行过滤器将授予或拒绝预留操作,特别是租赁创建和租赁更新。租赁删除通常不需要批准,但是,当租赁提前结束时,应通知强制执行过滤器,以便它们可以根据需要做出响应。

因此,将在预留生命周期的三个特定点调用强制执行过滤器

  1. 在租赁创建期间,在选择分配候选者之后,将把租赁及其预留和候选资源传递给强制执行过滤器集合。如果所有过滤器都通过请求,Blazar 将创建分配并将租赁和预留转换为 PENDING 状态,如通常所做。如果任何过滤器拒绝请求,则租赁将转换为 ERROR 状态,失败的过滤器中的消息将包含在向用户引发的错误中。

  2. 在租赁更新期间,在选择分配候选者之后,将把先前的租赁/预留/分配以及新的提议值传递给强制执行过滤器。如果所有过滤器都通过请求,Blazar 将像往常一样执行租赁更新。如果任何过滤器拒绝请求,则将向用户引发包含失败过滤器消息的错误。租赁不会转换为 ERROR 状态;它将保持在其先前的状态。

  3. 在租赁结束时,将租赁及其预留和当前分配的资源传递给强制执行过滤器。在这种情况下,过滤器结果不会影响租赁生命周期的其余部分,并且租赁应继续其 on_end 操作。此集成点更像是一种通知,旨在支持可能受预留提前终止影响的基于预算的策略(例如,通过向用户/项目退还租赁的未使用部分,采用“预先收费”模式)。

过滤器 API

将把租赁、预留和分配信息传递给每个过滤器。对于租赁和预留,将传递用户可控制属性的子集(例如,start_dateend_dateresource_type 和特定于插件的预留属性);UUID 和其他内部簿记属性(例如 created_at)将不会发送。每个分配对象还将包含相关的操作员定义的属性,例如,hypervisor_properties 用于 physical:host 预留和 floating_network_id 用于 virtual:floatingip 预留。如果为资源定义了额外的功能,则还会发送它们。这允许操作员定义的自定义元数据标记到资源,并在确定策略决策时稍后使用。

每个过滤器必须支持以下操作

  • check_create:检查是否可以满足新的租赁请求。接收 context 对象和 lease 对象作为参数。

    • 上下文包含有关请求的信息

    {
      "user_id": "c631173e-dec0-4bb7-a0c3-f7711153c06c",
      "project_id": "a0b86a98-b0d3-43cb-948e-00689182efd4",
      "auth_url": "https://api.example.com:5000/v3",
      "region_name": "RegionOne"
    }
    
    • 租赁对象包含租赁及其预留的用户可定义方面,并包含 Blazar 已经选择的分配

    {
      "start_date": "2020-05-13 00:00",
      "end_time": "2020-05-14 23:59",
      "reservations": [
        {
          "resource_type": "virtual:floatingip",
          "network_id": "external-network-id",
          "amount": 1,
          "allocations": [
            {
              "floating_network_id": "external-network-id",
              "floating_ip_address": "192.168.1.100",
              "id": "7375755f-717e-4883-91c1-06ceba2da96e"
            }
          ]
        },
        {
          "resource_type": "physical:host",
          "min": 1,
          "max": 2,
          "hypervisor_properties": "[]",
          "resource_properties": "[\"==\", \"$availability_zone\", \"az1\"]",
          "allocations": [
            {
              "id": "1",
              "hypervisor_hostname": "32af5a7a-e7a3-4883-a643-828e3f63bf54",
              "extra": {
                "availability_zone": "az1"
              }
            }
          ]
        }
      ]
    }
    
  • check_update:检查是否可以满足租赁更新请求。接收 context 对象以及租赁的当前状态和所需状态作为参数。发送两组状态可以减轻过滤器无需自行查找信息。

    注意:一个项目租赁可以由一个用户创建,并由另一个用户更新。在更新请求中,user_id 是执行更新的用户的 ID。

    • 上下文包含有关请求的信息(见上文)。

    • 租赁(当前和请求)状态包含租赁的用户可定义方面,并包含 Blazar 选择的分配。

  • on_end:通知过滤器租赁正在终止。接收 context 对象和租赁的当前状态作为参数。

    • 上下文包含有关请求的信息(见上文)。

    • 租赁包含租赁的用户可定义方面,并包含 Blazar 选择的分配。

最大预留长度过滤器

此过滤器只是检查租赁的 end_timestart_time,如果其长度超过阈值,则拒绝租赁。

外部服务过滤器

此过滤器将每个 API 的决策委托给外部 HTTP 服务。该服务应遵守 API-WG HTTP 响应代码 指南,并为成功与错误响应(如以下端点规范中所述)返回适当的 HTTP 状态。

Keystone token 用于 blazar 服务用户,将通过 X-Auth-Token 标头发送到所有端点的使用服务,可用于验证请求的真实性(以防止欺骗或滥用)。

外部服务 API

为了与 Blazar 的过滤器兼容,HTTP 服务必须提供以下接口

  • POST /v1/check-create

    • 检查是否可以使用使用策略满足新的租赁请求。

    • 正常响应代码:204 No Content

    • 错误响应代码

      • 403 Forbidden:如果根据实施的使用策略确定不允许租赁。可以在响应主体中以 JSON 格式返回错误消息。

    • 请求示例

    {
      "context": {
        "user_id": "c631173e-dec0-4bb7-a0c3-f7711153c06c",
        "project_id": "a0b86a98-b0d3-43cb-948e-00689182efd4",
        "auth_url": "https://api.example.com:5000/v3",
        "region_name": "RegionOne"
      },
      "lease": {
        "start_date": "2020-05-13 00:00",
        "end_time": "2020-05-14 23:59",
        "reservations": [
          {
            "resource_type": "virtual:floatingip",
            "network_id": "external-network-id",
            "amount": 1,
            "allocations": [
              {
                "floating_network_id": "external-network-id",
                "floating_ip_address": "192.168.1.100",
                "id": "7375755f-717e-4883-91c1-06ceba2da96e"
              }
            ]
          },
          {
            "resource_type": "physical:host",
            "min": 1,
            "max": 2,
            "hypervisor_properties": "[]",
            "resource_properties": "[\"==\", \"$availability_zone\", \"az1\"]",
            "allocations": [
              {
                "id": "1",
                "hypervisor_hostname": "32af5a7a-e7a3-4883-a643-828e3f63bf54",
                "extra": {
                  "availability_zone": "az1"
                }
              }
            ]
          }
        ]
      }
    }
    
    • 错误响应主体示例

    {
      "message": "Your lease exceeds the maximum length of 24 hours."
    }
    
  • POST /v1/check-update

    • 检查是否可以使用使用策略满足租赁更新请求。

    • 正常响应代码:204 No Content

    • 错误响应代码

      • 403 Forbidden:如果根据使用策略确定不允许租赁的更新状态。可以在响应主体中以 JSON 格式返回错误消息。

    • 请求示例

    {
      "context": {
        "user_id": "c631173e-dec0-4bb7-a0c3-f7711153c06c",
        "project_id": "a0b86a98-b0d3-43cb-948e-00689182efd4",
        "auth_url": "https://api.example.com:5000/v3",
        "region_name": "RegionOne"
      },
      "current_lease": {
        "start_date": "2020-05-13 00:00",
        "end_time": "2020-05-14 23:59",
        "reservations": [
          {
            "resource_type": "physical:host",
            "min": 1,
            "max": 2,
            "hypervisor_properties": "[]",
            "resource_properties": "[\"==\", \"$availability_zone\", \"az1\"]",
            "allocations": [
              {
                "id": "1",
                "hypervisor_hostname": "32af5a7a-e7a3-4883-a643-828e3f63bf54",
                "extra": {
                  "availability_zone": "az1"
                }
              }
            ]
          }
        ]
      },
      "lease": {
        "start_date": "2020-05-13 00:00",
        "end_time": "2020-05-14 23:59",
        "reservations": [
          {
            "resource_type": "physical:host",
            "min": 2,
            "max": 3,
            "hypervisor_properties": "[]",
            "resource_properties": "[\"==\", \"$availability_zone\", \"az1\"]",
            "allocations": [
              {
                "id": "1",
                "hypervisor_hostname": "32af5a7a-e7a3-4883-a643-828e3f63bf54",
                "extra": {
                  "availability_zone": "az1"
                }
              },
              {
                "id": "2",
                "hypervisor_hostname": "af69aabd-8386-4053-a6dd-1a983787bd7f",
                "extra": {
                  "availability_zone": "az1"
                }
              }
            ]
          }
        ]
      }
    }
    
    • 错误响应主体示例

    {
      "message": "Your project is limited to reserving 1 physical host."
    }
    
  • POST /v1/on-end

    • 通知使用服务租赁正在终止。

    • 正常响应代码:204 No Content

    • 错误响应代码:无

    • 请求示例

    {
      "context": {
        "user_id": "c631173e-dec0-4bb7-a0c3-f7711153c06c",
        "project_id": "a0b86a98-b0d3-43cb-948e-00689182efd4",
        "auth_url": "https://api.example.com:5000/v3",
        "region_name": "RegionOne"
      },
      "lease": {
        "start_date": "2020-05-13 00:00",
        "end_time": "2020-05-14 23:59",
        "reservations": [
          {
            "resource_type": "physical:host",
            "min": 1,
            "max": 2,
            "hypervisor_properties": "[]",
            "resource_properties": "[\"==\", \"$availability_zone\", \"az1\"]",
            "allocations": [
              {
                "id": "1",
                "hypervisor_hostname": "32af5a7a-e7a3-4883-a643-828e3f63bf54",
                "extra": {
                  "availability_zone": "az1"
                }
              }
            ]
          }
        ]
      }
    }
    

备选方案

这种方法涵盖了几个竞争性设计,特别是包括 Blazar 内的标准策略(通过包含解决常见用例的默认过滤器来解决)和提供过滤器的 Python 模块插件(通过类似于 Nova 调度器过滤器使用的机制提供自定义插件)。

另一种方法是简化方法,仅允许一种使用/扩展方法。但是,这会由于对操作员/开发人员施加的额外约束而限制功能的未来效用。

数据模型影响

REST API 影响

安全影响

有关用户、项目及其使用情况的信息将被发送到外部 Web 服务。如果与此服务的通信不安全,攻击者可能会捕获此信息,批准应被拒绝的预留操作,并拒绝应被批准的操作。攻击者还可能创建虚假请求,这些请求仍然会导致目标帐户产生实际的使用费用;为此,该服务应在与 Blazar 相同的服务上公开,或者至少应检查 X-Auth-Token 标头是否包含 blazar 服务帐户的有效令牌。

Blazar 的高水平预留操作将创建与策略 Web 服务的类似水平的调用,这可能会导致拒绝服务。

通知影响

其他最终用户影响

从最终用户角度来看,Blazar 接口将保持不变。唯一的区别可能是错误消息描述了为什么拒绝了预留操作。

性能影响

预留操作可以在评估强制执行过滤器时触发对其他服务的同步调用,这可能会导致 blazar-manager RPC 响应变慢,从而导致 API 响应变慢。在使用外部强制执行服务时,监控其性能非常重要。

其他部署者影响

将添加一个新的配置部分 [enforcement],其中包含一个初始属性

  • available_filters:提供强制执行过滤器的模块列表。可以多次指定。默认值为 blazar.enforcement.filters.all_filters

  • enabled_filters:一个逗号分隔的过滤器名称列表,按执行顺序排列。默认值为 MaximumReservationLengthFilter,ExternalServiceFilter

  • reservation_max_length:预留的最大长度,以秒为单位。这由 MaximumReservationLengthFilter 使用。默认值为 0,表示没有限制,从而有效地禁用此过滤器。

  • exempted_projects:一个项目名称或 ID 列表,这些项目不受任何强制执行过滤器的约束。如果使用项目名称,则必须提供域名,例如,在“Default”域的情况下,my-project@Default

此外,将添加一个新的配置部分 [enforcement_external] 用于 ExternalServiceFilter,其中包含以下属性

  • endpoint_url:如果设置为 URL,则启用预留使用策略的强制执行。默认值为 None,这有效地禁用了此过滤器。

  • allow_on_error:如果外部强制执行服务响应 HTTP 错误代码或传输层中发生其他错误,则允许预留请求。默认值为 False。

开发者影响

希望测试预留使用强制执行的开发人员需要部署额外的 Web 服务。我们可能希望将示例与 Blazar 一起打包。

升级影响

实现

负责人

主要负责人

diurnalist

工作项

  • 实现强制执行过滤器机制(默认通过所有请求)

  • 实现检查最大预留长度的过滤器

  • 实现外部强制执行服务过滤器

  • 向 blazar-tempest-plugin 添加场景测试

  • 更新 Blazar 文档

依赖项

测试

应实现单元测试和,如果可能的话,场景测试。

文档影响

需要使用新的配置选项更新配置文档。还应记录对策略 Web 服务的调用,以便操作员可以编写自己的服务。

参考资料

  1. IRC 会议讨论:http://eavesdrop.openstack.org/meetings/blazar/2019/blazar.2019-05-23-16.00.log.html

  2. Nova 调度器过滤器:https://docs.openstack.org/nova/latest/user/filter-scheduler.html

历史记录

修订版

发布名称

描述

Ussuri

引入