本文档描述了从服务目录中正确查找服务端点的过程。
注意
本文档中描述的过程与所有已知的 OpenStack 公有云兼容,并且与 keystoneauth Python 库的行为相匹配,keystoneauth 是使用 keystone 进行身份验证和从目录中获取信息的参考实现。在某些情况下,可以论证采用不同的过程,但考虑到 keystoneauth 的广泛使用和参考性质,我们选择保持与 keystoneauth 行为的向后兼容性,而不是设计一个全新的完美过程。keystoneauth 本身也在内部记录了它为了保持与早期库的兼容性而做出的地方。已经留下了关于库或框架可以选择实施的更严格行为的注释。
注意
本文档中“对象”一词指的是 JSON 对象,而不是任何特定编程语言中的对象。
此过程的最终目标是让用户找到给定一些输入的服务端点信息。用户将从知道这些参数中的一些开始该过程。用户期望的每个额外输入,如果没有“他们从哪里学习这些信息”的答案,都会增加用户消耗服务的难度,因此客户端库和实用程序强烈建议尽一切努力帮助用户提出正确的问题。
注意
对你接受的内容宽容一些,对你输出的内容严格一些。
有且只有一条信息是用户绝对必须知道的
用户可能还希望表达对通用算法的修改
有几个可选的信息片段是用户可能知道的,或者用户可能希望表达的附加约束。
注意
强烈建议{区域名称}始终需要它,以防止单区域云在未来添加区域。但是,keystoneauth 今天允许省略区域名称,并且存在大量具有单个名为RegionOne的区域的云。对于全新的库或主要版本,其中可以接受破坏性行为,默认情况下需要区域名称是首选的。
注意
在绝大多数情况下,这永远是不需要的,并且强烈建议部署者不要将其用作有意义的标识符。但是,如果部署者为其提供了一个目录,其中服务名称必须使用,那么服务名称必须作为输入接受。如果{严格模式}已请求,提供{服务名称}应该是一个错误。
注意
在具有良好格式目录的云上服务 ID这永远是不需要的。如果{严格模式}已请求,提供{服务 ID}应该是一个错误。
在发现过程结束时,用户应该知道{服务端点},这是用作服务根的端点,以及{接口}找到的端点。
在下面的描述中,上述所有输入和输出都将像{端点覆盖}这样引用,以便清楚地了解用户是否向该过程提供了输入,或者讨论的是预期的输出之一。在过程的某个点被获取并在稍后点被引用的其他值类似地引用为{服务目录}。名称不会在过程中被重用以在不同时间保存不同的内容。
还假设用户拥有{认证 URL}和身份验证信息。身份验证过程本身不在本文档的范围内。
服务应在其{服务目录}中使用{服务类型}来自 OpenStack 服务类型权威机构。但是,由于历史原因,有一些服务具有在野外发现的旧服务类型。为了促进使用正确的{服务类型}名称,但也支持现有用户和安装,OpenStack 服务类型权威机构 包含此类服务的历史别名列表。有关数据本身的信息,请参阅 消耗服务类型权威机构。
客户端需要一份在 OpenStack 服务类型权威机构 中发布的数据的副本才能完成完整的发现算法。客户端库可以保留本地副本或从 https://service-types.openstack.org/service-types.json 获取数据并可能对其进行缓存。建议客户端库处理其用户的历史数据,但也允许用户提供最新版本的数据(如果需要)。有关如何获取数据的更多信息,请参阅 消耗服务类型权威机构。
基本过程是
The{服务目录}可以在从 keystone 身份验证返回的令牌中找到。
如果使用 v3 身份验证,目录将在顶层对象的catalog令牌属性中。例如
{
'token': {
'catalog': {}
}
}
如果使用 v2 身份验证,它将在serviceCatalogcatalogaccess属性中。例如
{
'access': {
'serviceCatalog': {}
}
}
中。在两种情况下,目录内容本身都是对象的列表。每个对象都有两个主要键与发现相关
此外,为了保持向后兼容性,可能需要检查以下键。
端点列表的格式取决于是否使用了 v2 或 v3 身份验证。对于两个版本,每个端点对象都有一个区域键,该键应与{区域名称}(如果提供了)匹配。
在 v2 身份验证中,端点对象有三个键publicURL, internalURL, adminURL。用于{接口}请求的端点位于与{接口}匹配的键中URL.
加上字符串在 v3 身份验证中,端点对象有一个urlinterface如果{接口}.
匹配,则该端点是请求的端点。
带有目录的令牌的具体示例
{
"token": {
"catalog": [
{
"endpoints": [
{
"id": "39dc322ce86c4111b4f06c2eeae0841b",
"interface": "public",
"region": "RegionOne",
"url": "https://identity.example.com"
},
{
"id": "ec642f27474842e78bf059f6c48f4e99",
"interface": "internal",
"region": "RegionOne",
"url": "https://identity.example.com"
},
{
"id": "c609fc430175452290b62a4242e8a7e8",
"interface": "admin",
"region": "RegionOne",
"url": "https://identity.example.com"
}
],
"id": "4363ae44bdf34a3981fde3b823cb9aa2",
"type": "identity",
"name": "keystone"
}
],
}
V3 目录对象
{
"access": {
"serviceCatalog": [
{
"endpoints_links": [],
"endpoints": [
{
"adminURL": "https://identity.example.com/v2.0",
"region": "RegionOne",
"publicURL": "https://identity.example.com/v2.0",
"internalURL": "https://identity.example.com/v2.0",
"id": "4deb4d0504a044a395d4480741ba628c"
}
],
"type": "identity",
"name": "keystone"
},
]
}
}
V2 目录对象
注意
,并且剩余的对象具有{严格模式}字段,则仅保留name匹配的对象。Keystone v3 之前的目录不包含 name 字段。如果{服务名称}未请求,并且目录没有
注意
字段,则应忽略{严格模式}字段,则仅保留id匹配的对象。Keystone v3 之前的目录不包含 name 字段。如果{服务 ID}未请求,并且目录没有
。Keystone v2 目录不包含 id 字段。如果剩余的对象是{候选目录对象}{服务类型}和{服务名称}.
使用剩余的对象是。如果没有端点,则返回错误,说明没有匹配的端点,以生成.
{候选端点}剩余的对象是:
如果没有任何端点,则返回错误,说明没有匹配任何{接口}的端点,最好包括找到的接口列表。
对于剩余的的端点,以生成:
如果没有剩余的端点,则返回错误,说明没有匹配{region_name}的端点,最好包括找到的区域列表。
剩余的的端点,以生成匹配请求。如果有多个,则使用第一个,但向用户发出警告,说明有多个端点剩余。如果{严格模式}已请求,则返回一个错误,其中包含列表中每个端点的相关信息。
注意
如果剩余的端点多于一个,则引发错误会更正确,但 keystoneauth 库返回第一个,更改它会破坏大量现有用户。如果从头开始编写全新的库,或者新版本,其中可以接受行为更改,那么如果剩余的端点多于一个,则引发错误是首选的。
对于目录中的每个条目
注意
目前不支持请求一个别名并找到另一个别名,因为大多数别名还包含有关主要版本的隐含信息。后续规范添加了版本发现过程,此时可以安全地尝试返回列在别名下的端点。
给定已匹配其他标准的候选端点列表
给定已匹配其他标准的候选端点列表
例如,给定以下目录
{
"token": {
"catalog": [
{
"endpoints": [
{
"interface": "public",
"region": "RegionOne",
"url": "https://block-storage.example.com/v3"
}
],
"id": "4363ae44bdf34a3981fde3b823cb9aa3",
"type": "volumev3",
"name": "cinder"
},
{
"endpoints": [
{
"interface": "public",
"region": "RegionOne",
"url": "https://block-storage.example.com/v2"
}
],
"id": "4363ae44bdf34a3981fde3b823cb9aa2",
"type": "volumev2",
"name": "cinder"
}
],
}
那么以下
service_type = 'block-storage'
# block-storage is not found, get list of aliases
# volumev3 is found, return it
service_type = 'volumev2'
# volumev2 not an official type in authority, but is in catalog
# return volumev2 entry
service_type = 'volume'
# volume not in authority or catalog
# volume is an alias of block-storage
# block-storage is not found. Return error.
给定以下目录
{
"token": {
"catalog": [
{
"endpoints": [
{
"interface": "public",
"region": "RegionOne",
"url": "https://block-storage.example.com"
}
],
"id": "4363ae44bdf34a3981fde3b823cb9aa3",
"type": "block-storage",
"name": "cinder"
}
],
}
那么以下
service_type = 'block-storage'
# block-storage is found, return it
service_type = 'volumev2'
# volumev2 not in authority, is an alias for block-storage
# block-storage is in the catalog, return it
给定以下目录
{
"token": {
"catalog": [
{
"endpoints": [
{
"interface": "public",
"region": "RegionOne",
"url": "https://block-storage.example.com"
}
],
"id": "4363ae44bdf34a3981fde3b823cb9aa3",
"type": "block-storage",
"name": "cinder"
},
{
"endpoints": [
{
"interface": "public",
"region": "RegionOne",
"url": "https://block-storage.example.com/v2"
},
{
"interface": "internal",
"region": "RegionOne",
"url": "https://block-storage.example.int/v2"
}
],
"id": "4363ae44bdf34a3981fde3b823cb9aa2",
"type": "volumev2",
"name": "cinder"
}
],
}
那么以下
service_type = 'block-storage'
interface = ['internal', 'public']
# block-storage is found
# block-storage does not have internal, but has public
# return block-storage public
service_type = 'volumev2'
interface = ['internal', 'public']
# volumev2 not an official type in authority, but is in catalog
# volumev2 has an internal interface
# return volumev2 internal entry
OpenStack 服务类型权威机构 包含关于官方服务类型名称和历史服务类型名称的数据,这些名称通常在没有官方列表之前使用。它可供库和其他客户端 API 消费者使用,以便能够基于官方列表提供一致的接口,同时仍然支持现有名称。强烈建议提供此支持,但最终是可选的。匹配过程的第一步始终是返回目录和用户请求之间的直接匹配,因此在权威机构存在之前现有的消费模式应始终有效。
为了使用 OpenStack 服务类型权威机构 中的信息,重要的是要知道一些事情