贡献者指南
本指南旨在帮助任何希望为 community.hashi_vault
集合贡献代码的人。
注意
您的帮助可以改进本指南!在代码库中打开一个 GitHub issue,或者按照以下说明直接贡献代码。
快速入门
登录您的 GitHub 帐户。
点击右上角的 **Fork** 按钮,fork ansible-collections/community.hashi_vault 代码库 到您自己的帐户。这将在您的帐户中创建一个 fork。
按照 此处的示例说明 在本地克隆代码库(但将
general
替换为hashi_vault
)。**特别注意**克隆的代码库的本地路径结构,如这些说明中所述(例如ansible_collections/community/hashi_vault
)。如该页面所述,将您的更改提交到一个分支,将它们推送到您的 fork,并创建一个 pull request(当您查看您的代码库时,GitHub 将会自动提示您这样做)。
请参阅有关变更日志的指南,并在适当的情况下包含 变更日志片段。
贡献文档
非常欢迎为集合文档添加内容!我们有三种主要的文档类型,每种类型都有其自身的语法和规则。
README 和其他 Markdown 文件
Markdown 文件(扩展名为 .md
的文件)可以在代码库中的多个目录中找到。这些文件主要面向开发人员和浏览代码库的人,用于解释或提供附近其他文件的上下文。
上述的主要例外是代码库根目录中的 README.md
。此文件更为重要,因为它为在 GitHub 和集合的 Ansible Galaxy 页面 上浏览代码库的任何人提供入门信息和链接。
Markdown 文件可以在 GitHub 中本地预览,因此审阅者很容易验证,并且不需要针对它们运行任何特定测试。
您的 IDE 或代码编辑器也可能能够预览这些文件。例如,Visual Studio Code 具有内置的 Markdown 预览功能。
模块和插件文档
此类型的文档是从结构化的 YAML(在 Python 字符串内)生成的。它包含在其所记录的相同代码中,或在单独的 Python 文件中,例如文档片段。请参阅 模块格式和文档指南 以了解更多信息。
此类型的文档结构非常清晰,并使用 ansible-test sanity
进行测试。完整的说明可在 测试模块文档 页面上找到。
此外,pull request 上(或本地构建的)的文档站点构建也将包含模块和插件文档。有关详细信息,请参见下一节。
集合文档站点
您现在正在阅读集合文档站点。它使用 reStructuredText (RST) 格式编写,并在 ansible_documentation 网站上发布。在这里,我们提供了不适合其他两类文档的冗长文档。
如果您正在考虑在此处添加一个全新的文档,最好先打开一个 GitHub issue 来讨论这个想法以及如何更好地组织它。
对于提交到集合文档站点的所有内容,请参考 Ansible 风格指南。
文档站点的 RST 文件位于 docs/docsite/rst/
目录中。某些提交可能还需要编辑 docs/docsite/extra-docs.yml
。
当提交更改集合文档的 pull request 时,将生成并发布一个新的文档站点到一个临时站点,并且一个机器人将在 PR 上发布一条包含链接的评论。这将使您可以查看渲染后的文档,以帮助发现格式错误。
还可以通过安装一些额外的 Python 依赖项并运行构建脚本在本地构建文档。
$ pushd docs/preview
$ pip install -r requirements.txt
$ ./build.sh
然后,您可以在 docs/preview/build/html
中找到生成的 HTML,并可以在本地浏览器中打开它们。
在本地运行测试
如果您要进行的更改不仅仅是很小或一次性的更改,请在本地运行测试,以避免每次更改都需要推送提交并等待 CI 运行测试。
首先,查看有关测试集合的指南,因为它也适用于此集合。
集成测试
与其他集合不同,我们需要一个integration_config.yml文件才能正确运行集成测试,因为测试需要外部依赖项(例如 Vault 服务器),并且它们需要知道在哪里可以找到这些依赖项。
如果您以前曾为该集合或hashi_vault
查找插件做出过贡献,您可能会记得集成测试过去默认会在测试过程中下载、提取和运行 Vault 服务器。这种旧模式已**不再可用**。
Docker Compose 本地环境
运行测试的推荐方法是使用 docker-compose 设置在各自容器中运行 Vault 和其他依赖项,集成测试则在单独的容器中运行。
为此,我们预定义了一个“localenv”设置角色。
使用方法
为方便输入/缩短命令长度,我们将首先进入角色目录。
$ pushd tests/integration/targets/setup_localenv_docker
此本地环境同时具有 Ansible 集合和 Python 要求,因此让我们先解决这些问题。
$ pip install -r files/requirements/requirements.txt -c files/requirements/constraints.txt
$ ansible-galaxy collection install -r files/requirements/requirements.yml
使用所有默认设置来设置您的 docker-compose 环境。
$ ./setup.sh
设置脚本执行以下操作:
为项目生成一个
docker-compose.yml
模板。为 Vault 生成私钥和自签名证书。
生成 Vault 配置文件模板。
关闭现有的 compose 项目。
根据变量(指定的或默认的)启动 compose 项目。
生成一个
integration_config.yml
文件,其中包含集成测试连接所需的所有正确设置。如果那里还没有,则将集成配置复制到正确的位置(如果已自定义更改,则不会覆盖)。
容器运行后,您现在可以在 docker 中运行测试(返回集合根目录后)。
$ popd
$ ansible-test integration --docker default --docker-network hashi_vault_default -v
--docker-network
部分很重要,因为它确保 Ansible 测试容器与依赖项容器位于同一网络中,这样测试容器就可以通过其容器名称访问它们。网络名称hashi_vault_default
来自此角色使用的默认 docker-compose 项目名称(hashi_vault
)。有关更多信息,请参阅自定义部分。
再次运行setup.sh
可以重新部署容器,或者如果您愿意,可以直接使用生成的files/.output/<project_name>/docker-compose.yml
和本地工具。
如果再次运行,请记住手动将新生成的files/.output/integration_config.yml
的内容复制到集成根目录,或在重新运行设置之前删除根目录中的文件,以便它自动复制该文件。
自定义
setup.sh
将您发送给它的任何附加参数传递给它调用的ansible-playbook
命令,因此您可以使用标准--extra-vars
(或-e
)选项自定义变量。有很多高级场景,但您可能想要重写的一些内容包括:
vault_version
– 可以定位任何存在 docker 容器的 Vault 版本(这是容器的标签),默认为latest
docker_compose
(默认为clean
,但可以设置为up
、down
或none
)up
– 类似于运行docker-compose up
(如果项目正在运行,则为无操作)down
– 类似于docker-compose down
(销毁项目)clean
– (默认)类似于docker-compose down
,然后是docker-compose up
none
– 执行其他任务,包括模板化,但不启动或关闭项目。使用此选项,不需要community.docker
集合。
vault_crypto_force
– 默认情况下,此值为false
,因此如果证书和密钥存在,则不会重新生成它们。设置为true
将覆盖它们。vault_port_http
、vault_port_https
、proxy_port
– 所有端口都暴露给主机,因此如果您主机上已在使用任何默认端口,则可能需要覆盖这些端口。vault_container_name
、proxy_container_name
– 这些是它们各自容器的名称,这也将是容器网络中使用的 DNS 名称。如果您正在使用默认名称,则可能需要覆盖这些名称。docker_compose_project_name
– 不太需要更改,但它会影响 docker 网络的名称,而这对于您的ansible-test
调用是必需的,因此值得一提。例如,如果您将其设置为ansible_hashi_vault
,则 docker 网络名称将为ansible_hashi_vault_default
。
贡献身份验证方法
在此集合中,身份验证方法在所有插件和模块之间共享,而不是在每个插件和模块中重新实现。这节省了重新发明轮子的工作量,并通过测试身份验证方法的功能来防止测试膨胀,并提供一致的体验。
文件位置和范围
身份验证方法在module_utils
中作为类实现,在一个名为plugins/module_utils/_auth_method_<method_name>.py
的文件中。前面的下划线表示模块实用程序对集合是私有的,并且不打算在集合外部使用;这使我们能够根据需要进行更改,而无需发布新的主要版本,并清楚地向潜在的下游用户表明他们不应依赖集合中内容之外的这些实用程序。
此外,集合中的所有身份验证方法模块实用程序都必须包含一个解释这一点的注释,例如:
# FOR INTERNAL COLLECTION USE ONLY
# The interfaces in this file are meant for use within the community.hashi_vault collection
# and may not remain stable to outside uses. Changes may be made in ANY release, even a bugfix release.
# See also: https://github.com/ansible/community/issues/539#issuecomment-780839686
# Please open an issue if you have questions about this.
最好查看现有的身份验证方法,以了解它们的实现方式。
类结构
每个身份验证方法类都应命名为HashiVaultAuthMethod<MethodName>
并继承自HashiVaultAuthMethodBase
。
基类提供了一些常见的功能,例如标准化发出警告的方式和提供用于验证所需选项的公共函数。
身份验证方法必须运行基类的__init__
函数。
它必须实现两种方法:
validate()
– 此方法尽其所能确保满足使用此特定身份验证方法进行身份验证的要求。这可能包括检查所需选项、验证这些选项的值、从环境中提取附加信息和上下文、准备authenticate()
使用这些信息等。一般来说,它不应该联系 Vault,并且应该尽量减少对外部资源和服务的依赖,但这只是一个指导方针,细节将取决于所讨论的身份验证方法的具体情况。validate()
如果验证失败,则引发异常。如果成功,则不会返回任何内容。authenticate(client, use_token=False)
– 此方法执行实际的身份验证,并返回身份验证的 API 结果(其中将包括令牌、租约信息等)。HVAC 客户端对象被传入,以及一个可选参数use_token
,它指定客户端是否应将其令牌字段设置为身份验证的结果(通常这是需要的)。
身份验证方法类还应包含两个字段:
NAME
– 身份验证方法的名称。OPTIONS
– 包含身份验证方法可能使用的每个选项名称(包括可选选项)的列表;此列表不应包含auth_method
选项。
引发异常和警告
因为认证方法在 Ansible 模块和 Ansible 插件中共享,所以任何引发的异常都必须适用于两者。如果合适,可以引发标准的 Python 异常,例如 KeyError
。
在通常会引发 AnsibleError
(在插件中)或调用 module.fail_json()
(在模块中)的情况下,您可以引发 HashiVaultValueError
并附带您的错误消息。此集合中的插件和模块应该能够处理此类型并做出相应的反应。
同样,对于警告,由于插件和模块以不同的方式实现警告,因此需要发出警告的模块实用程序代码采用警告回调,认证方法也是如此。
基类提供了一个 warn()
方法,该方法处理在类初始化时指定的回调调用,因此可以在认证方法代码中使用简单的 self.warn()
。
访问选项
因为认证方法在 Ansible 模块和 Ansible 插件中共享,而它们访问选项的方式不同,所以此集合实现了一个名为 HashiVaultOptionAdapter
的类。此类为在插件和模块中都必须工作的代码提供了一个标准的接口来访问选项值。
它实现了以下方法:
get_option(key)
– 获取指定名称的选项。如果选项不存在,则引发KeyError
。get_option_default(key, default=None)
– 获取指定名称的选项。如果不存在,则返回default
的值。set_option(key, value)
– 将指定选项key
的值设置为value
。set_option_default(key, default=None)
– 返回选项key
的值。如果密钥不存在,则将其值设置为default
并返回该值。has_option(key)
– 如果存在指定的选项(None
值算作存在),则返回True
。set_options(**kwargs)
– 将选项设置为kwargs
中指定的键值对。get_options(*args)
– 返回args
中指定的选项名称的字典。get_filtered_options(filter, *args)
– 返回args
中指定的选项名称的字典,如果可调用对象filter
(其中传递了key
和value
)对给定的键值对返回True
。get_filled_options(*args)
– 返回*args
中指定的且不为None
的选项名称的字典。
身份验证器
HashiVaultAuthenticator
类是集合中的大部分内容处理身份验证的方式,而不是必须直接引用每个单独的认证方法。因此,对于每种新的认证方法,都需要修改 _authenticator.py
,因为它会导入并直接引用每个类。请参阅 此类的实现 以查找需要修改的地方。
认证方法选项和文档
由于认证方法在集合内容中共享,因此它们的选项在 doc_fragment 插件中进行文档记录。由于许多选项最终在许多认证方法中共享(例如 role_id
、username
、password
),因此我们不会为每种认证方法提供单独的 doc fragment,因为这会导致选项文档重复。
相反,所有认证方法的选项都在 plugins/doc_fragments/auth.py
中。
这包含标准的 DOCUMENTATION
字段以及 PLUGINS
字段。这种拆分的原因是文档的某些部分仅适用于插件;即 env
、ini
和 vars
条目。
DOCUMENTATION
应该包含两者共有的所有字段,例如 description
、type
、version_added
、required
等,而任何特定于插件的内容都放在 PLUGINS
中。
由于插件和模块将引用 doc fragments,因此通常不需要直接修改内容中的文档字符串;如果看起来有必要,请提出问题进行讨论。
尽可能地,我们应该为指定选项提供 env
、ini
和 vars
替代方案,以最大限度地提高插件的灵活性。有时,这些是没有意义的,例如在 ini
中提供 token
(敏感值)。
在决定为认证方法实现新的选项时,请考虑是否可以或应该重用现有选项。如果需要新的选项,请考虑将其名称限定于认证方法,以便将其与其他上下文中可能令人混淆的当前或未来的选项名称区分开来。
例如,cert_auth_public_key
和 cert_auth_private_key
的命名方式是为了防止它们与与 Vault 连接相关的其他证书选项或特定插件或模块可能需要密钥对的其他上下文混淆。
测试认证方法
由于认证方法在整个集合中共享,因此我们希望对其进行非常彻底的测试。认证方法同时具有单元测试和集成测试,它们的组合应该让我们对方法按预期工作充满信心。
单元测试
单元测试允许我们检查一些在集成测试中难以有效测试的功能,例如检查每种可能的选项组合是否按预期工作,或模拟我们难以轻松复制的条件。各种场景的覆盖率应该很广泛,具体细节或复杂程度将取决于认证方法本身的复杂性。强烈建议查看现有示例。
提供了一个 pytest fixture 来加载包含 Vault API 响应示例的 fixture 文件。使用这些文件可以在单元测试中模拟 HVAC 身份验证调用。
集成测试
我们的集成测试提供了一个运行中的 Vault 服务器,有了它,我们可以设置任何我们想要的认证方法(理论上)。实际上,认证方法通常需要与外部服务集成。如果可能,我们应该考虑设置此类外部服务,以便我们可以创建一个有意义的现实生活集成并对其进行测试。
但是,通常情况下,这是不可能的,或者很困难。我们必须考虑到测试不仅在 CI 中运行,而且还应该能够在本地运行。
模拟集成
我们在集成测试设置中实现了 MMock (Monster Mock) 来帮助解决这个问题。此服务器设置为将其请求代理到测试 Vault 服务器,但您可以编写允许它为特定请求返回不同数据的配置。通过仔细构建这些响应,我们可以模拟 Vault API 对特定认证方法的登录请求的响应,以及模拟其失败。有了它,我们就可以运行集成测试,希望这些测试可以让我们确信我们正在正确地实现它。
测试插件和模块的使用
身份验证方法可用于模块和插件,因此身份验证方法的集成测试必须通过插件和模块两种方式进行测试。
我们专门为集成测试中的身份验证方法提供自定义模块和插件。这些是简化的实现,但它们使用了所有内容都应使用的公共代码,并且可以设置为返回有关登录过程的一些有用信息。详情请参见现有测试。
测试覆盖率
在 CI 中,我们使用 CodeCov 来跟踪覆盖率。我们还在覆盖率中设置了一些特定的“标签”,其中一个标签是将各个身份验证方法标记为集成测试的目标。这在 CI 中会自动发生,但是新的身份验证方法需要在codecov.yml
文件中添加一个条目,将覆盖率标志映射到实现身份验证方法的文件。例如
flags:
target_auth_aws_iam:
paths:
- plugins/module_utils/_auth_method_aws_iam.py