将现有内容迁移到专用的 Ansible 集合
今天,我们将演示如何将现有 Ansible 内容(模块和插件)的一部分迁移到专用的 Ansible 集合。我们将使用用于管理 DigitalOcean 资源的模块作为示例,以便您可以按照说明进行操作并测试您的开发设置。但首先,让我们先解决一个大问题:为什么要这样做?
Ansible 瘦身
在 2020 年 3 月下旬,Ansible 的主要开发分支丢失了几乎所有的模块和插件。它们去了哪里?其中许多模块已移至 ansible-collections GitHub 组织。更具体地说,绝大多数模块都位于 community.general GitHub 存储库中,该存储库是它们临时的“家”(有关更多信息,请参阅 社区概览 README)。
最终目标是让尽可能多的内容在 community.general Ansible 集合中被一个负责的开发人员团队“采用”,并转移到一个专门的上游位置,并拥有一个专门的 Galaxy 命名空间。 迁移到新位置的 Ansible 集合的维护者可以根据需要设置开发和发布流程,(几乎)不受 community.general 集合要求的限制。有关 Ansible 内容交付的未来,请参阅 官方博客文章、Steampunk 视角,以及 AnsibleFest 讨论,了解 Ansible 集合。
话不多说,让我们动手创建一个全新的 DigitalOcean Ansible 集合。
迁移过程
我们选择将 DigitalOcean 相关内容进行迁移,主要有三个原因:
- 它包含足够多的内容,迁移并非易事(我们将在迁移过程中使用一些自制工具)。
- DigitalOcean 模块使用标准功能,例如文档片段和实用程序 Python 包,这意味着仅仅将模块复制过来是不够的。
- 它目前是 community.general Ansible 集合的一部分。
编辑 (2020-09-23): DigitalOcean 模块已于 2020 年 7 月迁移到 community.digitalocean
集合,因此上面列表中的最后一个要点不再有效。但我认为,这次迁移证实了我们对示例的选择是正确的。
因此,内容迁移是一个多步骤过程,这并不奇怪。我们需要创建一个工作目录,将 community.general Ansible 集合克隆到其中,并创建一个空的目的地集合。但在我们进行任何操作之前,必须确定这个新的 Ansible 集合的名称。
众所周知,计算机科学中最难的两件事是:缓存失效、命名和 off-by-one 错误;) 幸运的是,在我们的案例中,找到一个合适的名称相对容易:因为我们正在迁移所有用于处理 DigitalOcean 云平台的模块,所以我们将将其命名为 digital_ocean.digital_ocean。
$ mkdir -p ~/work/ansible_collections
$ cd ~/work/ansible_collections
$ mkdir community
$ git clone --depth 1 --branch 0.2.0 \
https://github.com/ansible-collections/community.general.git \
community/general
$ ansible-galaxy collection init digital_ocean.digital_ocean
$ cd digital_ocean/digital_ocean
目录就绪后,我们可以开始将内容复制到新的 Ansible 集合中。但我们不会仅仅将模块迁移过来,我们还将利用这次机会重命名模块。
与 DigitalOcean 相关的模块名称都以 digital_ocean_ 为前缀,因为在 Ansible 2.8 之前,所有模块都位于同一个全局命名空间中。现在我们将其迁移到一个单独的命名空间,可以安全地去掉该前缀。我们可以手动执行此操作,但编写几行 Bash 代码会更快,而且更令人满意:
$ source=../../community/general
$ mkdir -p plugins/modules
$ for m in $(find $source/plugins/modules/ -name 'digital_ocean_*.py' -type f)
> do
> new_name=$(basename $m | sed 's/digital_ocean_//')
> echo " Copying $(basename $m) -> $new_name"
> cp $m plugins/modules/$new_name
> done
接下来,我们需要复制模块使用的实用程序 Python 文件。我们可以通过搜索 module_utils 导入来获取所有此类模块的列表。
$ grep -h "ansible_collections.community.general.plugins.module_utils." \
plugins/modules/*.py | sort | uniq
我们需要迁移一个 Python 文件,然后修复导入语句,这很容易自动化。
$ mkdir plugins/module_utils
$ cp ../../community/general/plugins/module_utils/digital_ocean.py \
plugins/module_utils/
$ sed -i -e 's/ansible_collections.community.general.plugins/./' \
plugins/modules/*.py
最后需要修复的是文档。因为我们在迁移过程中重命名了模块,所以需要从模块的 DOCUMENTATION
块中去掉 digital_ocean_ 前缀:digital_ocean_${module_name}
部分。我们还需要调整 EXAMPLES 部分,并用完全限定的名称替换旧的模块名称。再次使用 sed。
$ sed -i -r \
-e 's/module: +digital_ocean_([^ ]+)/module: 1/' \
-e 's/digital_ocean_([^ ]+):/digital_ocean.digital_ocean.1:/' \
plugins/modules/*.py
我们还需要复制模块使用的所有文档片段。我们可以通过在模块中搜索 community.general. 字符串来识别它们:
$ grep -h -- "- community.general." plugins/modules/*.py | sort | uniq
现在,我们必须重复对实用程序文件执行的步骤:复制文档片段文件并更新引用。同样,因为我们的片段现在拥有自己的专用命名空间,所以可以将其重命名为更具意义的名称。由于我们的文档片段包含通用参数的定义,所以我们将将其命名为 common。我们保证这是我们使用 sed 和正则表达式进行的最后一次修复。;)
$ mkdir plugins/doc_fragments
$ cp ../../community/general/plugins/doc_fragments/digital_ocean.py \
plugins/doc_fragments/common.py
$ sed -i -e 's/community.general.digital_ocean.documentation/digital_ocean.digital_ocean.common/' \
plugins/modules/*.py
我们完成了。是时候给自己鼓掌并提交工作了。
$ git init && git add . && git commit -m "Initial commit"
如果您只对这次迁移的最终结果感兴趣,可以从 digital_ocean.digital_ocean GitHub 存储库下载。
体验新的集合
如果要测试新创建的 DigitalOcean Ansible 集合,需要告诉 Ansible 在哪里搜索它。可以通过设置 ANSIBLE_COLLECTIONS_PATHS 环境变量来指向工作目录。我们如何知道是否一切正常?我们将礼貌地要求 Ansible 为我们打印模块文档。
$ export ANSIBLE_COLLECTIONS_PATHS=~/work
$ ansible-doc digital_ocean.digital_ocean.domain
如果一切按计划进行,最后一个命令将显示 domain 模块的文档。请注意,我们在最后一个命令中使用了 domain 模块的完全限定集合名称 (FQCN)。如果省略了命名空间和集合名称部分,Ansible 将无法找到我们的模块。
作为最终测试,我们还可以运行一个简单的剧本,例如:
---
- name: DigitalOcean test playbook
hosts: localhost
gather_facts: false
tasks:
- name: Create a new droplet
digital_ocean.digital_ocean.droplet:
name: mydroplet
oauth_token: OAUTH_TOKEN
size: 2gb
region: sfo1
image: centos-8-x64
wait_timeout: 500
当我们执行 ansible-playbook play.yaml 命令时,Ansible 会向我们发出警告,因为我们提供了无效的身份验证令牌。但我们不应该难过,因为错误消息证明我们的模块按预期工作。
下一步
在今天的文章中,我们演示了内容迁移的初始步骤。但此列表尚未结束。如果我们认真维护此类 Ansible 集合,则需要为模块添加测试并设置 CI/CD 集成。
这篇文章中我们没有涉及的另一个内容是,如何将新创建的 Ansible 集合推送到 Ansible Galaxy。我们之所以不这样做,不是因为发布集合特别困难,而是因为它太容易了。只需获得 digital_ocean 命名空间,然后运行以下两个命令:
$ ansible-galaxy collection build
$ ansible-galaxy collection publish \
--api-key {galaxy API key here} \
digital_ocean-digital_ocean-1.0.0.tar.gz
发布一个我们不打算维护的集合,是对 Ansible 社区的损害。质量重于数量。
如果您需要帮助将现有内容迁移到专门的 Ansible 集合中,并在长期内进行维护,请 联系我们的专家,他们将乐于为您提供帮助。
干杯!