Ansible Collection Packaging Guidelines
Forward
Ansible collections are packaged units of Ansible content, including modules and other types of plugins. Most Ansible Plugins are written in Python or Powershell.
Some collections are also included in Ansible Community’s ansible
collection bundle, which is packaged in Fedora. All collections, whether or not they are included in the ansible
package, MAY be packaged in Fedora.
ansible
depends on ansible-core
, which contains the core engine and CLI programs (e.g. ansible
, ansible-playbook
). The ansible
package has a different release cycle than individual collections, and it may contain older versions of the individual components. ansible
installs collections in a different namespace and is parallel installable with individual collections. The Ansible engine searches for collections in the standalone collections directory first.
See Changes/Ansible5 for more information about the split between ansible
and ansible-core
.
Naming
Collection packages MUST be named ansible-collection-NAMESPACE-NAME
. For example, the community.general
collection package is named ansible-collection-community-general
.
Collection Source
Collection source code MUST be downloaded from the collection’s respective Git forge/other SCM repository. While the tarballs published to Ansible Galaxy contain all of the collection’s Python/Powershell source code as well as some development files, they do not include the galaxy.yml
build configuration and development files (e.g. unit tests) that the author may choose to remove. Note that the Ansible Community collection requirements mandate that collections tag releases in a public SCM repository.
Collection packages SHOULD use %{ansible_collection_url NAMESPACE NAME}
as the package’s URL:
. This points to the collection’s homepage on Ansible Galaxy.
Dependencies
Buildtime
Collections MUST have BuildRequires: ansible-packaging
. ansible-packaging
provides macros and a dependency generator for packaging Ansible Collections. It also pulls in ansible-core
, so BuildRequires: ansible-core
SHOULD NOT be added manually.
Runtime
The dependency generator will generate the appropriate dependency on the Ansible engine. This ensures compatibility with Fedora 35 which contains the classic ansible
2.9 package (instead of the collections bundle) and ansible-core
. Both versions of the Ansible engine support collections, but they are not parallel installable. Packages MUST NOT manually Require
ansible-core
or ansible
, unless they are known to require a specific version, in which case the appropriate version constraints should be used.
The dependency generator also handles inter-collection dependencies.
External dependencies of plugins
Ansible collections may contain various plugins that have various external dependencies. The Ansible dev guide mandates that plugins fail cleanly if these dependencies are not installed. Many times, external dependencies are only needed for a small subset of the collection which may or may not be widely used. Therefore, collection packages SHOULD weakly depend on these external libraries, i.e. use Recommends instead of Requires.
Module dependencies are only needed on the target node not the controller node. Therefore, collection packages SHOULD NOT depend on these dependencies at all, weakly or strongly. Users are responsible for installing these dependencies on the target host. Modules that are intended to be used with delegate_to: localhost
are an exception to this rule.
The situation is a bit different for controller plugins, such as filter plugins, lookup plugins, connection plugins, or inventory plugins. Collections MAY add Recommends
for dependencies of controller plugins. However, packagers should use discretion when adding any type of dependency and only do so when it is required for the central functionality of the collection. For instance, it makes sense for ansible-collection-community-docker
to Recommend python3-docker
, but it doesn’t make sense for the larger, more general ansible-collection-community-general collection to Recommend python3-redis
for the redis
lookup plugin. This guideline seeks to prevent ballooning collection packages. ansible-core
and ansible
follow this same principle.
Build and Installation
To build the collection artifact, packages MUST use %ansible_collection_build
in %build
. %ansible_collection_install
MUST be used in %install
to install the artifact.
Packagers SHOULD use %files -f %{ansible_collection_filelist}
to install the collection. The %{ansible_collection_filelist}
is populated by %ansible_collection_install
.
Unit Tests
As per the general Fedora Packaging Guidelines, collection packages SHOULD run upstream unit tests in %check
if practical. Integration tests are impossible to run in the RPM build environment. In order to run unit tests, collections MUST BuildRequire
ansible-packaging-tests
, which pulls in the necessary dependencies. Some collections have other testing dependencies, which are usually specified in tests/unit/requirements.txt
. These have to be added manually. The %ansible_test_unit
macro MUST be used to run tests.
EPEL Compatibility
It is currently impossible to run unit tests on EPEL 8 and 9. ansible-core in RHEL 8 and 9 are built against alternative python stacks for which the necessary test dependencies are not available. The rest of these guidelines are applicable to EPEL 8 and 9, and |
Unnecessary Files
By default, collections ship with all of the files in the repository root, unless they are manually excluded. Therefore, many collections contain development files that are unwanted by users.
Packagers SHOULD exclude these files, which SHOULD be done by patching the collection’s galaxy.yml
to add these files to the build_ignore
configuration. These files SHOULD NOT be removed with rm
. See the Ansible documentation for more information on the galaxy.yml
syntax.
Common development files include:
-
The
tests
directory containing unit and integration tests -
SCM configuration such as
.gitignore
and.keep
files -
The
.azure-pipelines
and.github
directories that contain CI configuration
These files often have to be removed downstream, as there are some unresolved issues with pushing these changes to upstream community collections. These issues are irrelevant in the Fedora context.
Shebangs
Ansible plugins are not executable. However, many of them have #!/usr/bin/python
shebangs for legacy reasons. These shebangs MUST be removed for the following reasons:
-
Non-executable files shouldn’t have shebangs
-
Keeping the shebangs results in an unnecessary dependency on
python-unversioned-command
.
%py3_shebang_fix
MUST NOT be used, as it will break compatibility with certain Ansible target nodes. It won’t fix the non-executable file issue, either.
Shebangs can be removed with:
find -type f ! -executable -name '*.py' -print -exec sed -i -e '1{\@^#!.*@d}' '{}' +
Documentation and License Files
License files and documentation for collections are installed to the collection’s directory in /usr/share/ansible
, by default. Packagers MAY choose to either mark the license and documentation files in this directory with %license
and %doc
or to add the correct paths to build_ignore
in galaxy.yml
and install them into the standard directories. Avoid duplicating these files in both places.
Note that some multi-licensed collections store licenses in a LICENSES
directory. This whole directory MUST be marked with %license
.
Refer to the Legal docs for the rules about allowed licenses and determining the License:
field.
Example Specfile
# Only run tests where the dependencies are available
%if %{defined fedora}
%bcond_without tests
%else
%bcond_with tests
%endif
Name: ansible-collection-community-rabbitmq
Version: 1.2.2
Release: 1%{?dist}
Summary: RabbitMQ collection for Ansible
# plugins/module_utils/_version.py: Python Software Foundation License version 2
License: GPL-3.0-or-later and PSF-2.0
URL: %{ansible_collection_url community rabbitmq}
%global forgeurl https://github.com/ansible-collections/community.rabbitmq
Source0: %{forgeurl}/archive/%{version}/%{name}-%{version}.tar.gz
# Patch galaxy.yml to exclude unnecessary files from the built collection.
# This is a downstream only patch.
Patch0: build_ignore.patch
BuildRequires: ansible-packaging
%if %{with tests}
BuildRequires: ansible-packaging-tests
# Collection specific test dependency
BuildRequires: glibc-all-langpacks
%endif
BuildArch: noarch
%description
%{summary}.
%prep
%autosetup -n community.rabbitmq-%{version} -p1
find -type f ! -executable -name '*.py' -print -exec sed -i -e '1{\@^#!.*@d}' '{}' +
%build
%ansible_collection_build
%install
%ansible_collection_install
%if %{with tests}
%check
%ansible_test_unit
%endif
%files -f %{ansible_collection_filelist}
%license COPYING PSF-license.txt
%doc README.md CHANGELOG.rst
%changelog
build_ignore.patch:
diff --git a/galaxy.yml b/galaxy.yml
index 0b37162..acd029a 100644
--- a/galaxy.yml
+++ b/galaxy.yml
@@ -13,3 +13,13 @@ repository: https://github.com/ansible-collections/community.rabbitmq
documentation: https://docs.ansible.com/ansible/latest/collections/community/rabbitmq/
homepage: https://github.com/ansible-collections/community.rabbitmq
issues: https://github.com/ansible-collections/community.rabbitmq/issues
+build_ignore:
+ # Remove unnecessary development files from the built package.
+ - tests
+ - .azure-pipelines
+ - .gitignore
+ # Licenses and docs are installed with %%doc and %%license
+ - PSF-license.txt
+ - COPYING
+ - README.md
+ - CHANGELOG.rst
Macro Breakdown
Here is a short breakdown of exactly what each macro included in ansible-packaging
does.
%ansible_collection_url
Usage:
URL: %{ansible_collection_url NAMESPACE NAME}
This macro points to a collection’s Ansible Galaxy page. It is intended to be used for the URL:
tag in the specfile preamble. It takes the collection namespace and collection name as arguments.
If no arguments are passed to this macro, it falls back to the values of %{collection_namespace}
and %{collection_name}
if they are set in the specfile. New packages SHOULD explicitly pass the namespace and name as arguments. The fallback may be removed in the future. See the Legacy Macros section for more information.
%ansible_collection_build
Usage:
%build
%ansible_collection_build
This macro simply runs ansible-galaxy collection build
.
%ansible_collection_install
Usage:
%install
%ansible_collection_install
This macro pulls out the collection namespace, name, and version from galaxy.yml
and then uses it to run ansible-galaxy collection install
. After that, it writes out %{ansible_collection_filelist}
based on the metadata it previously extracted
%ansible_test_unit
Usage:
%check
%ansible_test_unit
This macro parses galaxy.yml to determine the collection namespace and name that’s needed to create the directory structure that ansible-test expects. After creating a temporary build directory with the needed structure, the script runs ansible-test units with the provided arguments.
%{ansible_collection_filelist}
Usage:
%files -f %{ansible_collection_filelist}
%doc ...
%license ...
This macro points a file list that’s written out by %ansible_collection_install
. Currently, it only contains a single entry to own the collection’s entire directory in %{ansible_collections_dir}
This macro expands to %{_datadir}/ansible/collections/ansible_collections
. It is used internally by the other macros. Packagers are expected to use %ansible_collection_install
and %ansible_collection_filelist
instead of directly referencing this directory.
Legacy macros
%{collection_namepsace}
Usage:
%global collection_namespace NAMESPACE
The ansible-packaging macros previously required packagers to manually set %collection_namespace
in specfiles. Now, the macros extract the collection namespace from the galaxy.yml
.
Want to help? Learn how to contribute to Fedora Docs ›