将角色迁移到 Galaxy 上集合中的角色
您可以将任何现有的独立角色迁移到一个集合中,并将该集合托管在 Galaxy 上。借助 Ansible 集合,您可以在单个可重用自动化单元中分发许多角色。在集合内部,您可以在集合中的所有角色之间共享自定义插件,而不是在每个角色的 library/
目录中重复它们。
如果您想将角色作为经过认证的 Ansible 内容分发,则必须将角色迁移到集合。
注意
如果您想将集合导入到 Galaxy,您需要一个 Galaxy 命名空间。
有关集合的详细信息,请参阅 开发集合。
比较独立角色与集合角色
独立角色 具有以下目录结构
role/
├── defaults
├── files
├── handlers
├── library
├── meta
├── module_utils
├── [*_plugins]
├── tasks
├── templates
├── tests
└── vars
当您迁移到基于集合的角色时,上面突出显示的目录将发生变化。集合目录结构包含一个 roles/
目录
mynamespace/
└── mycollection/
├── docs/
├── galaxy.yml
├── plugins/
│ ├── modules/
│ │ └── module1.py
│ ├── inventory/
│ └── .../
├── README.md
├── roles/
│ ├── role1/
│ ├── role2/
│ └── .../
├── playbooks/
│ ├── files/
│ ├── vars/
│ ├── templates/
│ └── tasks/
└── tests/
当您将角色迁移到集合中时,您需要使用完全限定集合名称 (FQCN) 来使用角色和插件。FQCN 是集合的 namespace
、集合的 name
和您引用的内容项的组合。
例如,在上面的集合中,访问 role1
的 FQCN 将是
mynamespace.mycollection.role1
一个集合可以在 roles/
目录中包含一个或多个角色,它们与独立角色几乎相同,只是您需要将插件移出单个角色,并在某些地方使用 FQCN,如下一节中详述的那样。
注意
在独立角色中,某些插件目录以复数形式引用其插件类型;在集合中则不是这种情况。
将角色迁移到集合
要从不包含插件的独立角色迁移到集合角色
创建一个本地
ansible_collections
目录,并cd
到此新目录。创建一个集合。如果您想将此集合导入到 Ansible Galaxy,您需要一个 Galaxy 命名空间。
$ ansible-galaxy collection init mynamespace.mycollection
这将创建集合目录结构。
将独立角色目录复制到集合的
roles/
子目录中。集合中的角色不能在角色名称中使用连字符。重命名任何此类角色以改用下划线。
$ mkdir mynamespace/mycollection/roles/my_role/
$ cp -r /path/to/standalone/role/mynamespace/my_role/\* mynamespace/mycollection/roles/my_role/
更新
galaxy.yml
以包含任何角色依赖项。更新集合 README.md 文件,以添加指向任何角色 README.md 文件的链接。
将包含插件的角色迁移到集合
要从具有插件的独立角色迁移到集合角色
创建一个本地
ansible_collections directory
目录,并cd
到此新目录。创建一个集合。如果您想将此集合导入到 Ansible Galaxy,您需要一个 Galaxy 命名空间。
$ ansible-galaxy collection init mynamespace.mycollection
这将创建集合目录结构。
将独立角色目录复制到集合的
roles/
子目录中。集合中的角色不能在角色名称中使用连字符。重命名任何此类角色以改用下划线。
$ mkdir mynamespace/mycollection/roles/my_role/
$ cp -r /path/to/standalone/role/mynamespace/my_role/\* mynamespace/mycollection/roles/my_role/
将任何模块移动到
plugins/modules/
目录。
$ mv -r mynamespace/mycollection/roles/my_role/library/\* mynamespace/mycollection/plugins/modules/
将任何其他插件移动到相应的
plugins/PLUGINTYPE/
目录。有关可能需要的其他步骤,请参阅 将其他角色插件迁移到集合。更新
galaxy.yml
以包含任何角色依赖项。更新集合 README.md 文件,以添加指向任何角色 README.md 文件的链接。
更改对角色的任何引用以使用 FQCN。
---
- name: example role by FQCN
hosts: some_host_pattern
tasks:
- name: import FQCN role from a collection
import_role:
name: mynamespace.mycollection.my_role
您可以交替使用 collections
关键字来简化此操作
---
- name: example role by FQCN
hosts: some_host_pattern
collections:
- mynamespace.mycollection
tasks:
- name: import role from a collection
import_role:
name: my_role
将其他角色插件迁移到集合
要将其他角色插件迁移到集合
将每个非模块插件移动到相应的
plugins/PLUGINTYPE/
目录。mynamespace/mycollection/plugins/README.md
文件解释了集合在可选创建的子目录中可以包含的插件类型。
$ mv -r mynamespace/mycollection/roles/my_role/filter_plugins/\* mynamespace/mycollection/plugins/filter/
更新文档以使用 FQCN。使用
doc_fragments
的插件需要使用 FQCN(例如,mydocfrag
变为mynamespace.mycollection.mydocfrag
)。更新相对导入在集合中工作,以句点开头。例如,
./filename
和../asdfu/filestuff
可以工作,但同一目录中的filename
必须更新为./filename
。
如果您有自定义的 module_utils
或从 __init__.py
导入,您还必须
更改自定义
module_utils
的 Python 命名空间,以使用 FQCN 以及ansible_collections
约定。请参阅 更新 module_utils。更改您从
__init__.py
导入的方式。请参阅 从 __init__.py 导入。
更新 module_utils
如果您的任何自定义模块使用自定义模块实用程序,则一旦迁移到集合,您就不能在顶级 ansible.module_utils
Python 命名空间中寻址模块实用程序。Ansible 不会将集合中的内容合并到 Ansible 内部 Python 命名空间中。当您将自定义内容迁移到集合时,请更新任何引用自定义模块实用程序的 Python import 语句。有关详细信息,请参阅 集合中的 module_utils。
在集合中使用 module_utils
进行编码时,Python import 语句需要考虑 FQCN 以及 ansible_collections
约定。生成的 Python import 类似于以下示例
from ansible_collections.{namespace}.{collectionname}.plugins.module_utils.{util} import {something}
注意
您需要在更改路径和为子类化插件使用命名空间名称时遵循相同的规则。
以下示例代码片段显示了 Python 和 PowerShell 模块,它们同时使用默认的 Ansible module_utils
和集合提供的 module_utils
。在此示例中,命名空间为 ansible_example
,集合为 community
。
在 Python 示例中,module_utils
为 helper
,FQCN 为 ansible_example.community.plugins.module_utils.helper
from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.common.text.converters import to_text
from ansible.module_utils.six.moves.urllib.parse import urlencode
from ansible.module_utils.six.moves.urllib.error import HTTPError
from ansible_collections.ansible_example.community.plugins.module_utils.helper import HelperRequest
argspec = dict(
name=dict(required=True, type='str'),
state=dict(choices=['present', 'absent'], required=True),
)
module = AnsibleModule(
argument_spec=argspec,
supports_check_mode=True
)
_request = HelperRequest(
module,
headers={"Content-Type": "application/json"},
data=data
)
在 PowerShell 示例中,module_utils
为 hyperv
,FQCN 为 ansible_example.community.plugins.module_utils.hyperv
#!powershell
#AnsibleRequires -CSharpUtil Ansible.Basic
#AnsibleRequires -PowerShell ansible_collections.ansible_example.community.plugins.module_utils.hyperv
$spec = @{
name = @{ required = $true; type = "str" }
state = @{ required = $true; choices = @("present", "absent") }
}
$module = [Ansible.Basic.AnsibleModule]::Create($args, $spec)
Invoke-HyperVFunction -Name $module.Params.name
$module.ExitJson()
从 __init__.py 导入
由于 CPython 解释器导入机制的特性,以及 Ansible 插件加载器的工作方式,如果你的自定义嵌入模块或插件需要从 __init__.py
文件中导入内容,那么该文件也会成为你的集合的一部分。你可以选择将内容放在一个独立的 role 中,或者在 Python 导入语句中使用文件名。以下示例是一个 __init__.py
文件,它是一个名为 ansible_example.community
的集合中的回调插件的一部分。
from ansible_collections.ansible_example.community.plugins.callback.__init__ import CustomBaseClass
示例:将包含插件的独立 role 迁移到集合
在这个例子中,我们有一个名为 my-standalone-role.webapp
的独立 role,用于模拟名称中包含破折号(在集合中无效)的独立 role。这个独立 role 在 library/
目录中包含一个名为 manage_webserver
的自定义模块。
my-standalone-role.webapp
├── defaults
├── files
├── handlers
├── library
├── meta
├── tasks
├── templates
├── tests
└── vars
创建一个新的集合,例如
acme.webserver
。
$ ansible-galaxy collection init acme.webserver
- Collection acme.webserver was created successfully
$ tree acme -d 1
acme
└── webserver
├── docs
├── plugins
└── roles
在集合内部创建
webapp
role,并将所有内容从独立 role 复制过来。
$ mkdir acme/webserver/roles/webapp
$ cp my-standalone-role.webapp/* acme/webserver/roles/webapp/
将
manage_webserver
模块移动到其在acme/webserver/plugins/modules/
中的新位置。
$ cp my-standalone-role.webapp/library/manage_webserver.py acme/webserver/plugins/modules/manage.py
注意
此示例将原始源文件 manage_webserver.py
更改为目标文件 manage.py
。这是可选的,但是FQCN提供了 webserver
上下文,即 acme.webserver.manage
。
在 role 的
tasks/
文件(例如,my-standalone-role.webapp/tasks/main.yml
)以及任何使用原始模块名称的地方,将manage_webserver
更改为acme.webserver.manage
。
注意
只有在你更改了原始模块名称时才需要进行此名称更改,但它说明了通过 FQCN引用的内容可以提供上下文,从而使模块和插件名称更短。如果你预计这些模块将独立于 role 使用,请保留原始命名约定。用户可以在其 playbook 中添加 collections 关键字。通常,roles 是一个抽象层,用户不会独立使用 role 的组件。
示例:在下游 RPM 中支持独立的 role 和迁移后的集合 role
独立的 role 可以与其对应的集合 role 共存(例如,作为产品支持生命周期的一部分)。这应该仅在过渡期内完成,但这两个 role 可以在下游的软件包(如 RPM)中共存。例如,RHEL 系统 role 可以与RHEL 系统 role 集合的示例共存,并为下游 RPM 提供现有的向后兼容性。
本节将逐步介绍如何在下游 RPM 中创建这种共存,并且需要 Ansible 2.9.0 或更高版本。
要将 role 作为独立的 role 和集合 role 提供:
将集合放置在
/usr/share/ansible/collections/ansible_collections/
中。将集合内的 role 的内容复制到一个以独立 role 命名的目录中,并将独立的 role 放置在
/usr/share/ansible/roles/
中。
独立 role 中使用的所有先前捆绑的模块和插件现在都通过 FQCN 引用,因此即使它们不再嵌入,也可以从集合内容中找到它们。这是一个示例,说明了集合内部的内容是一个独特的实体,不必绑定到 role 或其他内容。你可以选择创建两个单独的集合:一个用于模块和插件,另一个用于要迁移到的独立 role。role 必须将模块和插件用作 FQCN。
以下是使用此示例内容完成此操作的 RPM spec 文件示例。
Name: acme-ansible-content
Summary: Ansible Collection for deploying and configuring ACME webapp
Version: 1.0.0
Release: 1%{?dist}
License: GPLv3+
Source0: acme-webserver-1.0.0.tar.gz
Url: https://github.com/acme/webserver-ansible-collection
BuildArch: noarch
%global roleprefix my-standalone-role.
%global collection_namespace acme
%global collection_name webserver
%global collection_dir %{_datadir}/ansible/collections/ansible_collections/%{collection_namespace}/%{collection_name}
%description
Ansible Collection and standalone role (for backward compatibility and migration) to deploy, configure, and manage the ACME webapp software.
%prep
%setup -qc
%build
%install
mkdir -p %{buildroot}/%{collection_dir}
cp -r ./* %{buildroot}/%{collection_dir}/
mkdir -p %{buildroot}/%{_datadir}/ansible/roles
for role in %{buildroot}/%{collection_dir}/roles/*
do
cp -pR ${role} %{buildroot}/%{_datadir}/ansible/roles/%{roleprefix}$(basename ${role})
mkdir -p %{buildroot}/%{_pkgdocdir}/$(basename ${role})
for docfile in README.md COPYING LICENSE
do
if [ -f ${role}/${docfile} ]
then
cp -p ${role}/${docfile} %{buildroot}/%{_pkgdocdir}/$(basename ${role})/${docfile}
fi
done
done
%files
%dir %{_datadir}/ansible
%dir %{_datadir}/ansible/roles
%dir %{_datadir}/ansible/collections
%dir %{_datadir}/ansible/collections/ansible_collections
%{_datadir}/ansible/roles/
%doc %{_pkgdocdir}/*/README.md
%doc %{_datadir}/ansible/roles/%{roleprefix}*/README.md
%{collection_dir}
%doc %{collection_dir}/roles/*/README.md
%license %{_pkgdocdir}/*/COPYING
%license %{_pkgdocdir}/*/LICENSE
使用 ansible.legacy
从基于集合的 role 访问本地自定义模块
集合中的某些 role 使用本地自定义模块,这些模块本身不是集合的一部分。如果自定义模块短名称与集合模块名称之间存在冲突,则需要指定你的任务调用哪个模块。你可以更新任务以将 local_module_name
更改为 ansible.legacy.local_module_name
,以确保你使用的是自定义模块。