Metadata Definitions Catalog¶
https://blueprints.launchpad.net/glance/+spec/metadata-schema-catalog
Glance 服务提供的一个通用 API,供厂商、管理员、服务和用户有意义地定义可用的键/值对和标签元数据。其目的是为了促进 OpenStack 用户在工件、服务和项目之间更好地协作元数据。
这涉及不同类型资源(镜像、工件、卷、风味、聚合等)上可使用的可用元数据的定义。定义包括属性类型、键、描述和约束。此目录不会存储特定实例属性的值。
例如,虚拟 CPU 拓扑属性(核心数)的定义将包括要使用的键、描述和值约束,例如要求它是一个整数。因此,用户(可能通过 Horizon)能够搜索此目录以列出他们可以添加到风味或镜像的可用属性。他们将在列表中看到虚拟 CPU 拓扑属性,并知道它必须是一个整数。在 Horizon 示例中,当用户添加属性时,其键和值将存储在拥有该资源的service中(Nova 用于风味,Glance 用于镜像)。
图表: https://wiki.openstack.org/w/images/b/bb/Glance-Metadata-API.png
问题描述¶
在使用 OpenStack 时,我们遇到的一个挑战是在服务和不同类型的资源之间发现、共享和关联元数据。我们认为这会影响最终用户和管理员。
各种 OpenStack 服务提供技术,将低级资源选择抽象到更高一级,例如风味、卷类型或工件类型。这些资源抽象通常允许使用“元数据”的形式,例如标签或键/值对,以进一步专门化和描述每种资源类型的实例。但是,协作和理解在每种资源类型上使用哪些元数据可能是一个不连贯且困难的过程。这通常涉及搜索 wiki 和打开源代码。没有通用的方法可以让厂商或操作员发布他们的元数据定义。随着云规模的增长和管理资源的数量增加,这变得更加困难。
此外,云操作员应该能够选择性地控制他们希望在 CLI 或 horizon UI 中可见的属性元数据。仅仅因为启用的驱动程序或调度器过滤器支持某个属性,并不意味着云操作员希望该属性在 UI 中易于选择。
背景和示例
在 Juno Atlanta 会议上,Graffiti 团队演示了在 POC 下运行的概念。以下视频回顾了在会议上演示的内容,并有助于建立上下文
我们收到了来自多个开发项目成员以及众多操作员的非常积极的反馈。我们被多次询问关于将元数据定义目录概念引入 Glance,以便我们可以开始正式支持我们在 Horizon 中演示的想法。
其他示例在本文档末尾。
术语
“元数据”一词可能变得非常超载和令人困惑。本建议的目录是作为任意键/值对或分配为“标签”(仅名称)传递的附加元数据,这些元数据跨各种工件和 OpenStack 服务。
不同的 API 可能以不同的方式使用标签和键/值对。标签通常不用于驱动运行时行为。但是,键/值对通常由系统用于潜在地驱动运行时行为,例如调度、服务质量或驱动程序行为。有时,键/值对仅用于最终用户使用,不直接用于驱动运行时行为。元数据也可以由外部实体(例如第三方策略引擎)使用。某些服务 API 将元数据混合到一个存储桶中,并且不区分这两种元数据用途。
键/值对的术语在不同服务中有所不同。
今天元数据的几个例子
Nova |
Cinder |
Glance |
|
|
|
在本提案中,我们使用术语“对象”来描述一组 1…* 键/值对,这些键/值对可以应用于不同类型的资源以用于不同的目的。
与建议的工件 API 的关系
这不涉及工件存储,例如 Heat 模板或各种应用程序包。此 API 涉及超出基本工件语法的附加元数据。定义后,元数据通常可以应用于不同类型的工件和资源。例如,应用程序类别标签(如“大数据”)可以应用于提供 Hadoop 的镜像或卷,也可以应用于适合“大数据”应用程序的 Host Aggregate 或 Flavor。
提议的变更¶
我们正在提出一个新的元数据定义目录。以下子部分详细介绍了目录管理的的概念。
属性(Juno 版本)
属性描述单个属性及其基本约束。每个属性只能是基本类型
string, integer, number, boolean, array
每个基本类型都使用简单的 JSON schema 符号描述。这意味着没有嵌套对象,也没有定义引用。
对象(Juno 版本)
对象描述一组一个到多个属性及其基本约束。组中的每个属性只能是基本类型
string, integer, number, boolean, array
每个基本类型都使用简单的 JSON schema 符号描述。这意味着没有嵌套对象。
对象可以选择性地定义所需的属性,语义上理解使用该对象的用户应该提供所有必需的属性。
考虑了对象派生和属性继承,但我们将推迟这种复杂性,直到证明有必要为止。
命名空间(Juno 版本)
元数据定义包含在命名空间中。
指定对其中定义的所有内容的访问控制(CRUD)。允许仅管理员、不同项目或整个云定义和使用命名空间中的定义
将包含的定义与不同类型的资源关联
标签(未来版本)
一个可能的标签目录,用于帮助确保用户、资源类型和服务之间标签名称的一致性。因此,当用户要在资源上应用标签时,他们可以选择已在系统其他类型的资源上使用的标签,或者创建新标签。例如,相同的标签可以用于镜像、卷和实例。标签不区分大小写(BigData 等同于 bigdata,但不同于 Big-Data)。
标签层次结构(未来版本)
在各种应用程序相关的讨论中,层次结构的观念已经出现。支持层次结构非常简单。例如,可以创建标签“MySQL”和“Postgres”,并将其设置为具有标签“Database”的父标签。然后,用户可以将“MySQL”标记在类似镜像或软件模板的内容上。后续资源搜索可以通过简单地检索“Database”标签的子标签列表来对所有“数据库”执行。
图表
https://wiki.openstack.org/w/images/6/61/Glance-Metadata-Namespace.png
如果将来需要,可能需要一个默认的公共命名空间,该命名空间对所有云用户和所有资源类型可见。拥有默认的公共命名空间将使管理常规元数据变得非常容易,而无需完整的多租户环境的开销。
资源类型关联(Juno 版本)
资源类型关联指定资源类型与适用于它们的命名空间之间的关系。可以使用此信息来驱动 UI 和 CLI 视图。例如,相同的命名空间的对象、属性和标签可以用于镜像、快照、卷和风味。或者,命名空间可能仅适用于镜像。
资源类型应与 Heat 资源类型对齐。 https://docs.openstack.org/developer/heat/template_guide/openstack.html
重要的是要注意,相同的基本属性键可能需要不同的前缀,具体取决于目标资源类型。以下是一些示例
所需的虚拟 CPU 拓扑可以设置为镜像和风味上的元数据。键在镜像上与风味上的键具有不同的前缀。在风味上,键以前缀 hw: 开头,但在镜像上,键以前缀 hw_ 开头。
更多信息: http://git.openstack.org/cgit/openstack/nova-specs/tree/specs/juno/virt-driver-vcpu-topology.rst
另一个示例是 AggregateInstanceExtraSpecsFilter 和作用域属性(例如,具有 something:something=value 的属性)。对于作用域/命名空间属性,AggregateInstanceExtraSpecsFilter 需要在风味上使用“aggregate_instance_extra_specs:”前缀,但在聚合本身上不需要。否则,过滤器在调度期间将无法评估该属性。
因此,在主机聚合上,您可能会看到
companyx:fastio=true
但是,当在风味上使用时,AggregateInstanceExtraSpecsFilter 需要
aggregate_instance_extra_specs:companyx:fastio=true
在某些情况下,可能有多个不同的过滤器可能使用具有不同前缀的相同属性。在这种情况下,需要根据启用的过滤器设置正确的前缀。
此规范处理上述情况。
备选方案¶
这可以作为完全独立的服务来完成。但是,许多社区成员在 Juno 会议上建议将其作为扩展的 Glance 使命的一部分,因为许多元数据的目标是 Glance 托管的工件。此外,这还允许将关联的 UI 组件在 Horizon 中原生构建,而不是作为插件。
我们还与 Horizon PTL 讨论了仅 Horizon 的解决方案,并发现了一些技术原因,为什么这样做没有意义
Horizon 目前的设计是一个无状态服务器。唯一可以存在任何持久数据的地点是,如果您选择在服务器上使用数据库存储会话信息。Horizon 的默认设置现在使用带签名的 cookie 来维护会话数据,并避免了 DB 要求。
Horizon 服务器上没有特权帐户,因此没有构建仅管理员可以获取的持久数据存储的方法。这种持久的特权会话会创建许多安全问题。
Horizon 可以设置为 HA 方式,这需要多个 Horizon 服务器上的重复 DB 或专用于 Horizon 的 DB 后端。
服务可能始终支持发现其可用元数据的方式。此 API 不会阻止这种情况发生。但是,这提供了一个单一的中央 API 来发布和发现元数据,而无需每个服务都必须实现此类设施。此外,云操作员应该能够选择性地控制他们希望在 CLI 或 horizon UI 中可见的属性元数据。仅仅因为启用的驱动程序或调度器过滤器支持某个属性,并不意味着云操作员希望该属性在 UI 中易于选择。此 API 允许云操作员完全控制可见内容。
一个关键用例是使用通用目录协作元数据。这补充了在所有服务中临时添加标签和键/值对。我们认为将来元数据 API 也可以由跨服务的搜索索引器备份,以包含临时元数据以及定义的元数据。但是,这并非此蓝图的重点。
数据模型影响¶
这将使用关系数据库,并存在于 Glance 现有的关系数据所在的同一数据库中,但预计不会对现有 Glance 数据模型产生影响。所有这些都是全新的功能。
这涉及不同类型资源(镜像、工件、卷、风味、聚合等)上可使用的可用元数据的定义。定义不仅仅是键和值,因此我们不会使用键/值存储数据库。定义包括属性类型、键、描述和约束。当元数据用于资源时,带有用户提供值的键将在拥有该资源的service中存储,并且超出此规范的范围。例如,键/值对的实例将在 Cinder 数据库或 Glance 注册表中。
将向以下内容添加支持: * glance/db/sqlalchemy/api.py * registry/api.py * simple/api.py
将在 glance/db/sqlalchemy/metadata_defs_api 添加一个新包
表类将在 glance/db/sqlalchemy/models_metadata_defs.py 中
以下 DB 模式是初始建议的模式。我们将改进并在代码审查期间接受评论。
建议的基本模式
Table: metadef_namespaces
+--------------+--------------+------+-----+----------------+
| Field | Type | Null | Key | Extra |
+--------------+--------------+------+-----+----------------+
| id | int(11) | NO | PRI | auto_increment |
| namespace | varchar(80) | NO | UNI | |
| display_name | varchar(80) | YES | | |
| description | text | YES | | |
| visibility | varchar(32) | YES | | |
| protected | tinyint(1) | YES | | |
| owner | varchar(255) | NO | | |
| created_at | datetime | NO | | |
| updated_at | datetime | YES | | |
+--------------+--------------+------+-----+----------------+
Table: metadef_objects
+--------------+-------------+------+-----+----------------+
| Field | Type | Null | Key | Extra |
+--------------+-------------+------+-----+----------------+
| id | int(11) | NO | PRI | auto_increment |
| namespace_id | int(11) | NO | MUL | |
| name | varchar(80) | NO | | |
| description | text | YES | | |
| required | text | YES | | |
| json_schema | text | YES | | |
| created_at | datetime | NO | | |
| updated_at | datetime | YES | | |
+--------------+-------------+------+-----+----------------+
Table: metadef_properties
+--------------+-------------+------+-----+----------------+
| Field | Type | Null | Key | Extra |
+--------------+-------------+------+-----+----------------+
| id | int(11) | NO | PRI | auto_increment |
| namespace_id | int(11) | NO | MUL | |
| name | varchar(80) | NO | | |
| json_schema | text | YES | | |
| created_at | datetime | NO | | |
| updated_at | datetime | YES | | |
+--------------+-------------+------+-----+----------------+
Table: metadef_resource_types
+------------+-------------+------+-----+----------------+
| Field | Type | Null | Key | Extra |
+------------+-------------+------+-----+----------------+
| id | int(11) | NO | PRI | auto_increment |
| name | varchar(80) | NO | UNI | |
| protected | tinyint(1) | NO | | |
| created_at | datetime | NO | | |
| updated_at | datetime | YES | | |
+------------+-------------+------+-----+----------------+
Table: metadef_namespace_resource_types
+-------------------+-------------+------+-----+-------+
| Field | Type | Null | Key | Extra |
+-------------------+-------------+------+-----+-------+
| resource_type_id | int(11) | NO | PRI | |
| namespace_id | int(11) | NO | PRI | |
| properties_target | varchar(80) | YES | | |
| prefix | varchar(80) | YES | | |
| created_at | datetime | NO | | |
| updated_at | datetime | YES | | |
+-------------------+-------------+------+-----+-------+
REST API 影响¶
在 REST API 中,所有内容都通过命名空间和名称引用,而不是合成 ID。这有助于实现可移植性(使用 JSON 导入/导出)。
API 应该允许对信息进行粗粒度和细粒度访问,以控制数据传输带宽要求。
使用命名空间的基本交互是
根据所需的过滤器获取命名空间列表,并提供概述信息。(例如,镜像的键/值)。
获取对象
常见响应代码
创建 成功:201 Created
修改成功:200 OK
删除 成功:204 No Content
失败:400 Bad Request,包含详细信息。
禁止:403 Forbidden
未找到:404 Not found 例如,如果未找到特定实体
未找到:405 Not allowed 例如,尝试在列表资源上删除
未找到:501 Not Implemented 例如,HEAD 未实现
API 版本
所有 URL 都在 v2 Glance API 下。如果未明确指定,则假定 /v2/<url>
- 创建一个命名空间
POST /metadefs/namespaces/
命名空间可以选择性地包含以下内容,除了基本字段之外。
resource_type_associations
properties
对象
tags(未来版本)
示例正文(没有资源类型、属性、对象或标签)
{
"namespace": "MyNamespace",
"display_name": "My User Friendly Namespace",
"description": "My description",
"visibility": "public",
"protected": true
}
- 替换命名空间定义(不包括属性、对象或标签)
PUT /metadefs/namespaces/{namespace}
- 列出命名空间:仅返回命名空间列表,不包含任何对象
- 、属性或标签。
GET /metadefs/namespaces/
示例正文
{
"namespaces": [
{namespace1Here},
{namespace2Here}
],
"first": "/v2/metadefs/namespaces?limit=2",
"next": "/v2/metadefs/namespaces?marker=namespace2Here&limit=2",
"schema": "/v2/schemas/metadefs/namespaces"
}
With example namespace:
{
"first": "/v2/metadefs/namespaces?sort_key=created_at&sort_dir=asc",
"namespaces": [
{
"namespace": "OS::Compute::Quota",
"display_name": "Flavor Quota",
"description": "Compute drivers may enable quotas on...",
"visibility": "public",
"protected": true,
"owner": "admin",
"resource_type_associations": [
{
"name": "OS::Nova::Flavor",
"created_at": "2014-08-28T17:13:06Z",
"updated_at": "2014-08-28T17:13:06Z"
}
],
"created_at": "2014-08-28T17:13:06Z",
"updated_at": "2014-08-28T17:13:06Z",
"self": "/v2/metadefs/namespaces/OS::Compute::Quota",
"schema": "/v2/schemas/metadefs/namespace"
},
{
"namespace": "OS::Compute::VirtCPUTopology",
"display_name": "Virtual CPU Topology",
"description": "This provides the preferred...",
"visibility": "public",
"protected": true,
"owner": "admin",
"resource_type_associations": [
{
"name": "OS::Glance::Image",
"prefix": "hw_",
"created_at": "2014-08-28T17:13:06Z",
"updated_at": "2014-08-28T17:13:06Z"
},
{
"name": "OS::Cinder::Volume",
"prefix": "hw_",
"properties_target": "image",
"created_at": "2014-08-28T17:13:06Z",
"updated_at": "2014-08-28T17:13:06Z"
},
{
"name": "OS::Nova::Flavor",
"prefix": "hw:",
"created_at": "2014-08-28T17:13:06Z",
"updated_at": "2014-08-28T17:13:06Z"
}
],
"created_at": "2014-08-28T17:13:06Z",
"updated_at": "2014-08-28T17:13:06Z",
"self": "/v2/metadefs/namespaces/OS::Compute::VirtCPUTopology",
"schema": "/v2/schemas/metadefs/namespace"
}
],
"schema": "/v2/schemas/metadefs/namespaces"
}
通过添加查询参数进行过滤
resource_types = <comma separated list> e.g. OS::Glance::Image
visibility = Valid values are public, private.
Default is to return both public namespaces and private
namespaces visible to the user making the request.
limit = Use to request a specific page size. Expect a response
to a limited request to return between zero and limit items.
marker = Specifies the namespace of the last-seen namespace.
The typical pattern of limit and marker is to make an initial
limited request and then to use the last namespace from the
response as the marker parameter in a subsequent limited
request.
- 返回包含元数据定义的特定命名空间(属性、
- 对象或标签)。
GET /metadefs/namespaces/{namespace}
查询参数
resource_type = When specified, the API will look up the prefix associated
with the specified resource type and will apply the prefix
to all properties (including object properties) prior to
returning the namespace. For example, if a
resource_type_association in the namespace for
OS::Nova::Flavor specifies a prefix of hw:, then all
properties in the namespace will be returned with
hw:<prop_name>. However if, OS::Glance::Image is specified
and the prefix is set to hw_, then the property will be
returned as hw_<prop_name>.
示例正文
{
"namespace": "MyNamespace",
"display_name": "My User Friendly Namespace",
"description": "My description",
"resource_type_associations" : [
{
"name" :"OS::Nova::Aggregate",
"created_at": "2014-08-28T17:13:06Z",
"updated_at": "2014-08-28T17:13:06Z"
},
{
"name" : "OS::Nova::Flavor",
"prefix" : "aggregate_instance_extra_specs:",
"created_at": "2014-08-28T17:13:06Z",
"updated_at": "2014-08-28T17:13:06Z"
}
],
"properties": {
"nsprop1": {
"title": "My namespace property1",
"description": "More info here",
"type": "boolean",
"default": true
}
},
"visibility": "public",
"protected": true,
"owner": "The Test Owner"
}
- 删除一个命名空间,包括所有内容(属性、对象和标签(未来发布))
DELETE /v2/metadefs/namespaces/{namespace}
- 列出与命名空间关联的资源类型
GET /v2/metadefs/namespaces/{namespace}/resource_types
示例
{
"resource_type_associations": [
{
"name": "OS::Glance::Image",
"prefix": "hw_",
"created_at": "2014-08-28T17:13:06Z",
"updated_at": "2014-08-28T17:13:06Z"
},
{
"name": "OS::Cinder::Volume",
"prefix": "hw_",
"properties_target": "image_metadata",
"created_at": "2014-08-28T17:13:06Z",
"updated_at": "2014-08-28T17:13:06Z"
},
{
"name": "OS::Nova::Flavor",
"prefix": "hw:",
"created_at": "2014-08-28T17:13:06Z",
"updated_at": "2014-08-28T17:13:06Z"
}
]
}
字段描述
name - (required) Resource type names should be aligned with
Heat resource types whenever possible:
http://docs.openstack.org/developer/heat/template_guide/openstack.html
prefix - (optional) Specifies the prefix to use for the given
resource type. Any properties in the
namespace should be prefixed with this
prefix when being applied to the specified
resource type. Must include prefix separator
(e.g. a colon :).
Must include prefix separator (e.g. a colon :).
properties_target - (optional) Some resource types allow more than one
key / value pair per instance. For example,
Cinder allows user and image metadata on
volumes. Only the image properties metadata
is evaluated by Nova (scheduling or drivers).
This property allows a namespace target
to remove the ambiguity.
- 将命名空间与资源类型关联
POST /metadefs/namespaces/{namespace}/resource_types
示例
{
"name" :"OS::Cinder::Volume",
"properties_target" : "image_metadata",
"prefix" : "hw_",
"created_at": "2014-08-28T17:13:06Z",
"updated_at": "2014-08-28T17:13:06Z"
}
- 将命名空间与资源类型解除关联
DELETE /metadefs/namespaces/{namespace}/resource_types/{resource_type}
- 获取所有可能的资源类型列表
GET /metadefs/resource_types
对象
- 在特定命名空间中添加对象
POST /metadefs/namespaces/{namespace}/objects
示例
POST /metadefs/namespaces/CompanyXNamespace/objects
{
"name": "StorageQOS",
"description": "Our available storage QOS.",
"required": [
"minIOPS"
],
"properties": {
"minIOPS": {
"type": "integer",
"description": "The minimum IOPs required",
"default": 100,
"minimum": 100,
"maximum": 30000
},
"burstIOPS": {
"type": "integer",
"description": "The expected burst IOPs",
"default": 1000,
"minimum": 100,
"maximum": 30000
}
}
}
- 替换命名空间中的对象定义
PUT /metadefs/namespaces/{namespace}/objects/{object_name}
- 删除特定命名空间中的所有对象
DELETE /metadefs/namespaces/{namespace}/objects
- 删除特定命名空间中的特定对象
DELETE /metadefs/namespaces/{namespace}/objects/{object_name}
- 获取命名空间中的特定对象
GET /metadefs/namespaces/{namespace}/objects/{object_name}
列出特定命名空间中的对象
- 返回所有对象,包括其模式属性
GET /metadefs/namespaces/{namespace}/objects
通过添加查询参数进行过滤
limit = Use to request a specific page size. Expect a response
to a limited request to return between zero and limit items.
marker = Specifies the namespace of the last-seen namespace.
The typical pattern of limit and marker is to make an initial
limited request and then to use the last namespace from the
response as the marker parameter in a subsequent limited
request.
示例正文
{
"objects": [
{
"name": "object1",
"namespace": "my-namespace",
"description": "my-description",
"properties": {
"prop1": {
"title": "My Property",
"description": "More info here",
"type": "boolean",
"default": true
}
}
}
],
"first": "/v2/metadefs/objects?limit=1",
"next": "/v2/metadefs/objects?marker=object1&limit=1",
"schema": "/v2/schema/metadefs/objects"
}
属性(不在对象中)
- 在特定命名空间中添加属性
POST /metadefs/namespaces/{namespace}/properties
示例
POST /metadefs/namespaces/OS::Compute::Hypervisor/properties
{
"name": "hypervisor_type",
"type": "array",
"description": "The type of hypervisor required",
"items": {
"type": "string",
"enum": ["hyperv", "qemu", "kvm"]
}
}
- 替换命名空间中的属性定义
PUT /metadefs/namespaces/{namespace}/properties/{property_name}
- 删除特定命名空间中的所有属性
DELETE /metadefs/namespaces/{namespace}/properties
- 删除特定命名空间中的属性
DELETE /metadefs/namespaces/{namespace}/properties/{property_name}
- 获取命名空间中的特定属性
GET /metadefs/namespaces/{namespace}/properties/{property_name}
列出特定命名空间中的属性
- 返回命名空间中所有属性的详细信息,包括属性模式
GET /metadefs/namespaces/{namespace}/properties
通过添加查询参数进行过滤
limit = Use to request a specific page size. Expect a response
to a limited request to return between zero and limit items.
marker = Specifies the namespace of the last-seen namespace.
The typical pattern of limit and marker is to make an initial
limited request and then to use the last namespace from the
response as the marker parameter in a subsequent limited
request.
命名空间成员管理(推迟到未来发布)
允许不同的项目对非公共命名空间具有可见性。
例如,云运营商可能拥有能够运行云和天气模拟的特殊硬件。具有特定属性的镜像将被安排到该硬件,并且运营商只想让某些项目看到该属性并将其隐藏在其他项目之外,以免滥用云硬件。
模式
命名空间的 JSON Schema
{
"required": [
"namespace"
],
"properties": {
"namespace": {
"type": "string",
"description": "The unique namespace text.",
"maxLength": 80
},
"description": {
"type": "string",
"description": "Provides a user friendly description of the namespace.",
"maxLength": 500
},
"display_name": {
"type": "string",
"description": "The user friendly name for the namespace. Used by UI if available.",
"maxLength": 80
},
"owner": {
"type": "string",
"description": "Owner of the namespace.",
"maxLength": 255
},
"visibility": {
"enum": [
"public",
"private"
],
"type": "string",
"description": "Scope of namespace accessibility."
},
"protected": {
"type": "boolean",
"description": "If true, namespace will not be deletable."
},
"created_at": {
"type": "string",
"description": "Date and time of namespace creation (READ-ONLY)",
"format": "date-time"
},
"updated_at": {
"type": "string",
"description": "Date and time of the last namespace modification (READ-ONLY)",
"format": "date-time"
},
"properties": {
"$ref": "#/definitions/property"
},
"objects": {
"items": {
"type": "object",
"properties": {
"properties": {
"$ref": "#/definitions/property"
},
"required": {
"$ref": "#/definitions/stringArray"
},
"name": {
"type": "string"
},
"description": {
"type": "string"
}
}
},
"type": "array"
},
"resource_type_associations": {
"items": {
"type": "object",
"properties": {
"prefix": {
"type": "string"
},
"properties_target": {
"type": "string"
},
"name": {
"type": "string"
}
}
},
"type": "array"
},
"schema": {
"type": "string"
},
"self": {
"type": "string"
},
"additionalProperties": false
}
}
注意
有关 $ref 的详细信息,请参阅下面的模式定义。
命名空间模式的变化
命名空间还可以包含以下内容
resource_type_associations
properties
对象
tags(未来版本)
资源类型的 JSON Schema
{
"name": "resource_type_associations",
"links": [
{
"href": "{first}",
"rel": "first"
},
{
"href": "{next}",
"rel": "next"
},
{
"href": "{schema}",
"rel": "describedby"
}
],
"properties": {
"schema": {
"type": "string"
},
"next": {
"type": "string"
},
"resource_type_associations": {
"items": {
"additionalProperties": false,
"required": [
"name"
],
"name": "resource_type_association",
"properties": {
"name": {
"type": "string",
"description": "Resource type names should be aligned with Heat resource types whenever possible: https://docs.openstack.org/developer/heat/template_guide/openstack.html",
"maxLength": 80
},
"prefix": {
"type": "string",
"description": "Specifies the prefix to use for the given resource type. Any properties in the namespace should be prefixed with this prefix when being applied to the specified resource type. Must include prefix separator (e.g. a colon :).",
"maxLength": 80
},
"properties_target": {
"type": "string",
"description": "Some resource types allow more than one key / value pair per instance. For example, Cinder allows user and image metadata on volumes. Only the image properties metadata is evaluated by Nova (scheduling or drivers). This property allows a namespace target to remove the ambiguity.",
"maxLength": 80
},
"created_at": {
"type": "string",
"description": "Date and time of resource type association (READ-ONLY)",
"format": "date-time"
},
"updated_at": {
"type": "string",
"description": "Date and time of the last resource type association modification (READ-ONLY)",
"format": "date-time"
}
}
},
"type": "array"
},
"first": {
"type": "string"
}
}
}
属性的 JSON Schema
命名空间和对象也包含“属性”。属性符合 JSON schema v4 语法。但仅限于以下类型:* string * integer * number * boolean * array
每个基本类型都使用简单的 JSON schema 符号进行描述。这意味着没有嵌套对象,也没有定义引用。.. 注意:有关属性定义的详细信息,请参阅下面的模式定义。
对象的 JSON Schema
{
"required": [
"name"
],
"name": "object",
"additionalProperties": false,
"properties": {
"name": {
"type": "string"
},
"required": {
"$ref": "#/definitions/stringArray"
},
"properties": {
"$ref": "#/definitions/property"
},
"description": {
"type": "string"
},
"created_at": {
"type": "string",
"description": "Date and time of object creation (READ-ONLY)",
"format": "date-time"
},
"updated_at": {
"type": "string",
"description": "Date and time of the last object modification (READ-ONLY)",
"format": "date-time"
},
"schema": {
"type": "string"
},
"self": {
"type": "string"
}
}
}
对象也包含“属性”,如上所述。.. 注意:有关 $ref 的详细信息,请参阅下面的模式定义。
JSON Schema 常用定义
{
"definitions": {
"property": {
"additionalProperties": {
"required": [
"title",
"type"
],
"type": "object",
"properties": {
"additionalItems": {
"type": "boolean"
},
"enum": {
"type": "array"
},
"name": {
"type": "string"
},
"title": {
"type": "string"
},
"default": {},
"minLength": {
"$ref": "#/definitions/positiveIntegerDefault0"
},
"required": {
"$ref": "#/definitions/stringArray"
},
"maximum": {
"type": "number"
},
"minItems": {
"$ref": "#/definitions/positiveIntegerDefault0"
},
"readonly": {
"type": "boolean"
},
"minimum": {
"type": "number"
},
"maxItems": {
"$ref": "#/definitions/positiveInteger"
},
"maxLength": {
"$ref": "#/definitions/positiveInteger"
},
"uniqueItems": {
"default": false,
"type": "boolean"
},
"pattern": {
"type": "string",
"format": "regex"
},
"items": {
"type": "object",
"properties": {
"enum": {
"type": "array"
},
"type": {
"enum": [
"array",
"boolean",
"integer",
"number",
"object",
"string",
null
],
"type": "string"
}
}
},
"type": {
"enum": [
"array",
"boolean",
"integer",
"number",
"object",
"string",
null
],
"type": "string"
},
"description": {
"type": "string"
}
}
},
"type": "object"
},
"positiveIntegerDefault0": {
"allOf": [
{
"$ref": "#/definitions/positiveInteger"
},
{
"default": 0
}
]
},
"stringArray": {
"uniqueItems": true,
"items": {
"type": "string"
},
"type": "array"
},
"positiveInteger": {
"minimum": 0,
"type": "integer"
}
}
}
安全影响¶
无
通知影响¶
无
其他最终用户影响¶
我们打算通过 Horizon 公开此功能,并且正在进行相关的蓝图工作。
根据需要更新 python-glanceclient。
性能影响¶
对现有 API 或代码没有更改。
预计这将从 Horizon 调用,当管理员想要注释标签(未来)或键/值对到像镜像和卷这样的事物上时。将击中此 API 以获取可用的元数据。
其他部署者影响¶
新 API 的数据库模式创建现在将是较新的版本
默认资源类型将被硬编码:* OS::Glance::Image * OS::Cinder::Volume * OS::Nova::Flavor * OS::Nova::Aggregate * OS::Nova::Instance
glance-manage 将具有用于加载、卸载和导出元数据定义的新的命令:* db_load_metadefs - 从指定的目录加载元数据定义 * db_unload_metadefs - 卸载数据库中的所有元数据定义 * db_export_metadefs - 将元数据定义导出到指定的目录
python-glanceclient 也将支持用于细粒度管理目录中元数据定义的新 API 和 CLI 命令。
默认定义文件将签入 glance 下的 etc/metadefs
请注意,默认定义只是基于给定 OpenStack 部署中潜在元数据的建议。实际部署环境的配置可能需要云运营商限制应该在此目录中公开的元数据。他们可以根据启用的驱动程序和过滤器来限制它,或者选择仅提供这些驱动程序和过滤器提供的选项的子集。仅仅因为启用的驱动程序或调度器过滤器支持某些属性,并不意味着云运营商希望所有属性都易于在 UI 中选择。
部署者可以通过删除命名空间、修改命名空间、创建新命名空间以及更改命名空间到资源类型关联来定制定义以适应其云部署。
devstack 将被修改为调用此命令以加载所有默认元数据定义。
开发人员影响¶
无(新 API)
实现¶
负责人¶
- 主要负责人
lakshmi-sampath
- 其他贡献者
wayne-okuma michal-dulko-f pawel-skowron pawel-koniszewski facundo-n-maldonado santiago-b-baldassin travis-tripp
工作项¶
调查 Pecan / WSME(Pecan 被排除,选择 WSME)
将对以下内容进行更改
数据库 API 层以添加对命名空间进行 CRUD 操作的支持
数据库 API 层以添加对属性进行 CRUD 操作的支持
数据库 API 层以添加对对象进行 CRUD 操作的支持
数据库 API 层以添加对资源类型关联进行 CRUD 操作的支持
用于对命名空间进行 CRUD 操作的 REST API
用于对对象进行 CRUD 操作的 REST API
用于对属性进行 CRUD 操作的 REST API
用于对资源类型关联进行 CRUD 操作的 REST API
python-glanceClient 以支持操作
依赖项¶
与 Glance 相同的依赖项,但 WSME 除外。
实现将添加 WSME 对象编组。
测试¶
将为所有可能的代码添加单元测试,目标是尽可能地隔离功能。
将在可能的情况下添加 Tempest 测试。
文档影响¶
需要有关新 API 扩展和用法的文档
参考资料¶
Youtube summit Graffiti POC demo 回顾。
markwash 在 summit 之后讨论 graffiti 的会议记录。
当前 glance 元数据属性在文档中
分层标记概念部分受 AWS marketplace 的启发。在 marketplace 中,您可以按层次结构类别进行过滤。我们认为这很容易通过标签(未来发布)实现各种工件和资源。
其他示例
Libvirt 驱动程序选项
镜像 / 快照 / 卷(镜像元数据)
今天,您可以通过将选项放在镜像、快照和卷上的元数据中,为各种驱动程序提供选项。驱动程序读取此信息并使用它们。目前这仅记录在 wiki 上。
通过使用通用格式从元数据目录驱动它,我们可以将其暴露给 UI 或 CLI 轻松使用。这种元数据理想情况下可以以编程方式发布到目录。它将与镜像、快照和卷相关联。
UI 概念
https://wiki.openstack.org/w/images/f/f7/Libvirtdriveroptions-objects.PNG
示例数据(子集)
{
"objects": {
"name": "LibVirtDriverOptions",
"properties": {
"hw_video_model": {
"type": "array",
"description": "The video image driver used.",
"items": {
"type": "string",
"enum": [
"vga",
"cirrus",
"vmvga",
"xen",
"gxl"
]
}
},
"hw_machine_type": {
"type": "string",
"description": "Enables booting an ARM system using the
specified machine type. etc"
},
"hw_rng_model": {
"type": "string",
"description": "Adds a random-number generator device to
the image's instances. etc",
"defaultValue": "virtio"
}
}
}
}
基本主机聚合 / Flavor 属性配对
今天,您可以使用主机聚合来确保 Flavor 在特定主机上启动。基本方法是在 Flavor 和主机聚合上放置相同的键/值对。使用元数据目录,管理员可以详细描述键/值对及其含义,以便在单个云/区域中使用或导入以供在另一个云部署中重用。作为一个简单的例子,您可以使用属性来协作使用提供 SSD 的主机和 Flavor。更高级的对象将是具有不同属性的对象,例如最小 IOPS、突发 IOPS 等。
/metadefs/namespace/MyHostGroups/detail
图表
+------------------------+
| MyHostGroups | +-----------------+
| +------------------+ +--> | Flavor |
| |SSD | + +-----------------+
| +------------------+ | +-----------------+
| +--> | Host Aggregate |
+------------------------+ +-----------------+
示例
{
"namespace": "MyHostGroups",
"title": "My Host Groups",
"description": "Different ways that we like to group our private cloud",
"resource_type_associations" : [
{
"name" :"OS::Nova::Aggregate"
},
{
"name" : "OS::Nova::Flavor",
"prefix" : "aggregate_instance_extra_specs:"
}
],
"objects": {
"name": "SSD",
"properties": {
"MyHostGroups:SSD": {
"title": "SSD",
"description": "Describe instances with SSD storage.",
"type": "boolean",
"default": true
}
}
},
"visibility": "public",
"protected": true,
"owner": "The Test Owner"
}
包含属性和对象的示例命名空间
/metadefs/namespace/MyNamespace/detail
示例
{
"namespace": "MyNamespace",
"display_name": "My User Friendly Namespace",
"description": "My description",
"resource_type_associations": [
{
"name": "OS::Glance::Image",
"prefix": "hw_",
"created_at": "2014-08-28T17:13:06Z",
"updated_at": "2014-08-28T17:13:06Z"
},
{
"name": "OS::Cinder::Volume",
"prefix": "hw_",
"properties_target": "image_metadata",
"created_at": "2014-08-28T17:13:06Z",
"updated_at": "2014-08-28T17:13:06Z"
},
{
"name": "OS::Nova::Flavor",
"prefix": "filter1:",
"created_at": "2014-08-28T17:13:06Z",
"updated_at": "2014-08-28T17:13:06Z"
}
],
"properties": {
"nsprop1": {
"title": "My namespace property1",
"description": "More info here",
"type": "boolean",
"default": true
},
"nsprop2": {
"title": "My namespace property2",
"description": "More info here",
"type": "string",
"default": "value1"
}
},
"objects": [
{
"name": "object1",
"namespace": "MyNamespace",
"description": "My object1 description",
"properties": {
"prop1": {
"title": "My object1 property1",
"description": "More info here",
"type": "array",
"items": {
"type": "string"
}
}
}
},
{
"name": "object2",
"namespace": "MyNamespace",
"description": "My object2 description",
"properties": {
"prop1": {
"title": "My object2 property1",
"description": "More info here",
"type": "integer",
"default": 20
}
}
}
],
"visibility": "public",
"protected": true,
"owner": "The Test Owner"
}