我们想听听您的意见!帮助我们深入了解 Ansible 生态系统的现状。
参加 2024 年 Ansible 项目调查

将现有内容迁移到专用 Ansible 集合

将现有内容迁移到专用 Ansible 集合

今天,我们将演示如何将部分现有 Ansible 内容(模块和插件)迁移到专用 Ansible 集合。我们将使用管理 DigitalOcean 资源的模块作为示例,以便您可以按照步骤操作并测试您的开发环境。但首先,让我们解决一个大问题:为什么要这样做呢?

精简 Ansible

2020 年 3 月下旬,Ansible 的主要开发分支失去了几乎所有的模块和插件。它们去了哪里呢?其中许多已迁移到 ansible-collections GitHub 组织。更准确地说,绝大多数迁移到了 community.general GitHub 存储库,该存储库是它们的临时所在地(有关更多信息,请参阅 社区概述自述文件)。

最终目标是让尽可能多的内容在 community.general Ansible 集合中被关爱的开发人员团队“采用”,并迁移到专门的上游位置,并具有专门的 Galaxy 命名空间。新迁移的 Ansible 集合的维护人员可以根据需要设置开发和发布流程,几乎不受 community.general 集合的要求限制。有关 Ansible 内容交付未来的更多信息,请参阅 官方博客文章Steampunk 观点,以及 AnsibleFest 演讲,主题为 Ansible 集合。

话不多说,让我们动手创建全新的 DigitalOcean Ansible 集合。

迁移过程

我们选择 DigitalOcean 相关内容进行迁移,主要有三个原因:

  1. 它包含足够的材料,迁移起来并不完全微不足道(在迁移过程中,我们需要使用一些自制工具)。
  2. DigitalOcean 模块使用标准功能,例如文档片段和实用程序 Python 包,这意味着仅仅复制模块是不够的。
  3. 它目前是 community.general Ansible 集合的一部分。

编辑 (2020-09-23):DigitalOcean 模块已于 2020 年 7 月迁移到 community.digitalocean 集合,因此上述列表中的最后一点不再适用。但我认为,此举证实了我们选择示例的正确性。

因此,内容迁移是一个多步骤过程,这并不令人意外。我们需要创建一个工作目录,将 community.general Ansible 集合克隆到其中,并创建一个空的目的地集合。但在此之前,我们必须确定这个新的 Ansible 集合的名称。

众所周知,计算机科学中只有两件难事:缓存失效、命名事物和越界错误 ;) 幸运的是,在我们的案例中,找到合适的名称相对简单:因为我们要将所有与 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

如果一切按计划进行,最后一条命令将显示域模块的文档。请注意,我们在最后一条命令中使用了域模块的完全限定集合名称 (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 集合并长期维护它,请 联系我们的专家,他们将乐于为您提供帮助。

欢呼!