Opinionated blueprints for ansible-galaxy role|collection init.
Ansible Skeletons help you start new roles and collections with a shared structure for tasks, metadata and tests.
The skeletons follow these style guides:
- foundata: Ansible playbooks
- foundata: Ansible roles and collections
- Red Hat's Coding Style Good Practices for Ansible
- Best Practices of the Ansible User guide
- Features
- Examples
- Usage
- Provided skeletons
- Compatibility
- Contributing
- Licensing, copyright
- Author information
- Configuration for
ansible-lintand Molecule (using Containers via Podman and/or VMs via libvirt). - Separate files for OS-specific variables and tasks.
- Changelog conventions and release-note helpers.
- A common project structure and defaults for new roles and collections.
Some collections built using these skeletons:
foundata.acmesh:foundata.sshd:foundata.postfix:
-
Clone this repository and check out the latest release:
# Get the version number of the latest release version="$(curl -s -L https://api.github.com/repos/foundata/ansible-skeletons/releases/latest | jq -r '.tag_name' | sed -e 's/^v//g')" printf '%s\n' "${version}" # Clone and check out the latest release (you can switch versions anytime using "git checkout vX.Y.Z") git clone https://github.com/foundata/ansible-skeletons.git -b "v${version}"
-
Use
ansible-galaxyto initialize a new collection or standalone role. Provide the skeleton path and a name for the new resource. Pass any variable values you want to override, or use the defaults.
Examples:# Ensure ansible-galaxy is available and navigate to the cloned repository from step one ansible-galaxy --version cd ./path/to/ansible-skeletons # Create a new collection called "namespace.new_collection" based on the "collection_default" skeleton # Syntax: ansible-galaxy collection init --collection-skeleton <path> <extra variables> <name of the new collection including namespace> ansible-galaxy collection init \ --collection-skeleton "./collection_default" \ --extra-var '{"authors": ["FIXME User <user@example.com>"]}' \ --extra-var "company='FIXME your organization'" \ --extra-var "company_url='FIXME https://organization.example.com'" \ --extra-var "description='Manage FIXME.'" \ --extra-var "repository='https://FIXME.example.com/repo/'" \ --extra-var "issues='https://FIXME.example.com/repo/issues/'" \ --extra-var "homepage='https://FIXME.example.com'" \ --extra-var "min_ansible_version='2.19.0'" \ --extra-var "version='0.1.0'" \ "namespace.new_collection" # Create a new stand-alone role called "new_role" based on the "role_default" skeleton # Syntax: ansible-galaxy role init --role-skeleton <path> <extra variables> <name of the new role> ansible-galaxy role init \ --role-skeleton "./role_default" \ --extra-var "author='FIXME User <user@example.com>'" \ --extra-var "company='FIXME your organization'" \ --extra-var "company_url='FIXME https://organization.example.com'" \ --extra-var "description='Manage FIXME.'" \ --extra-var "repository_url='https://FIXME.example.com/repo/'" \ --extra-var "issue_tracker_url='https://FIXME.example.com/repo/issues/'" \ --extra-var "homepage_url='https://FIXME.example.com'" \ --extra-var "min_ansible_version='2.19.0'" \ "new_role"
Notes:
- Names of namespaces, collections or roles must follow
some
rules
and should consist of
a-z,0-9and_only. company_urlis optional. When set, the copyright holder in license headers,REUSE.tomland the README notice becomes<company> <<company_url>>, for examplefoundata GmbH <https://foundata.com>. Galaxy'scompanyfield keeps the plain name.- Adapt the directory name of the
--[collection|role]-skeletonparameter value to use a skeleton other than[collection|role_]default. The available skeletons are described below.
- Names of namespaces, collections or roles must follow
some
rules
and should consist of
-
Follow the instructions in the generated
FIXME.mdfile to adapt the collection or standalone role to your project.
Each skeleton has its own subdirectory. The source files contain
Jinja expressions that
ansible-galaxy [collection|role] renders when generating a project.
Edit each skeleton directly; none is generated from another.
A skeleton for
packaging and shipping
a run role in an Ansible collection. It includes:
- Init tasks to check the environment and usage:
- Role argument validation
- Check for minimum Ansible version and supported operating systems / platform.
- Automatic gathering of role-specific facts (useful with
gather_facts: false) - Automatic search and include for platform-specific variables.
- Separation of logical task groups, automatic include for platform-specific tasks.
.ansible-lintand.yamllintconfigurations following the foundata Ansible playbook guideline.antsibull-changelogsupport.antsibull-noxchecks, including ansible-lint with foundata's rules,ansible-testsanity peransible-coreversion and Molecule. The renderedDEVELOPMENT.mdexplains them.- Molecule support with a default scenario using Podman and several integration test targets.
A module-first skeleton for REST products whose writes take effect
immediately. For an appliance whose configuration carries its own management
path or whose activation is global, use
collection_modules_appliance instead. It
includes:
- A shared lifecycle base that runs every resource module, and a definition engine for resources that a declaration can describe.
- A resource module and an info module against a fake REST product, with references, a write-only password and a deletion guard. The product's own resources replace them.
- A hook-based fixture with nested values and its info module, the starting point for resources that a definition cannot express.
- A Molecule scenario, and a harness that proves each module handles a lost reply to a create, update or delete.
- A verifying activation helper for products that activate changes in a separate step; the fixture does not use it.
Render it with a metadata.json and the product's display name:
cat > metadata.json <<'EOF'
{
"authors": ["FIXME User <user@example.com>"],
"company": "FIXME your organization",
"company_url": "FIXME https://organization.example.com",
"description": "Manage FIXME.",
"repository": "https://FIXME.example.com/repo/",
"issues": "https://FIXME.example.com/repo/issues/",
"homepage": "https://FIXME.example.com"
}
EOF
ansible-galaxy collection init \
--collection-skeleton ./collection_modules \
--extra-vars @metadata.json \
--extra-vars "skeleton_revision=$(git describe --tags --always)" \
--extra-vars '{"product": "Example REST Product"}' namespace.productversion defaults to 1.0.0; the core floor defaults to 2.19.0. The
rendered collection requires foundata.utils >=1.0.0. Follow the rendered
FIXME.md to replace the fixtures with the product's resources.
A module-first skeleton for appliances with these traits:
- The managed configuration carries the management path, so a change can cut off the API the modules use.
- Activation is global: one apply step activates every pending change.
- Recovery through the console is rehearsed for each subsystem before the subsystem's first change that can affect the management path.
Choose it by those traits, not by the shape of the API. It requires a single
writer and a recovery path that does not depend on the API, such as a
console. On top of collection_modules, it adds:
- Act-once activation, for scopes where the product cannot confirm what it
loaded. It reports
verified: unverifiable, which does not prove that the requested state became active. - A scaffold for a guard that keeps writes away from the management path.
- A recovery drill that backs up the configuration through the console, cuts off API access and restores the backup. Without console access, the drill skips with a reason.
Its fixtures run against a fake product with a grid-style API: UUID
identifiers, paginated searches, and add, set and delete actions. It contains
no deployment role. Render it with the same metadata.json:
ansible-galaxy collection init \
--collection-skeleton ./collection_modules_appliance \
--extra-vars @metadata.json \
--extra-vars "skeleton_revision=$(git describe --tags --always)" \
--extra-vars '{"product": "Example Grid"}' namespace.productFollow the rendered FIXME.md to replace the fixtures with the product's
resources.
A skeleton for standalone Ansible roles. It includes:
- Init tasks to check the environment and usage:
- Role argument validation
- Check for minimum Ansible version and supported operating systems / platform.
- Automatic gathering of role-specific facts (useful with
gather_facts: false) - Automatic search and include for platform-specific variables.
- Separation of logical task groups, automatic include for platform-specific tasks.
.ansible-lintand.yamllintconfigurations following the foundata Ansible playbook guideline.- Molecule support with a default scenario using Podman and several integration test targets.
The release gate tests rendering and role execution with these controller
combinations, using the exact dependency versions recorded in uv.lock:
| Ansible core | Controller Python |
|---|---|
| 2.19 | 3.12, 3.13 |
| 2.20 | 3.12, 3.13, 3.14 |
| 2.21 | 3.12, 3.13, 3.14 |
Development: Testing describes the checks and their infrastructure coverage.
ansible-core before 2.19 cannot run the rendered content: the templates
write Jinja's own filters and tests as ansible.builtin.<name>, which
ansible-core resolves from 2.19. Projects rendered from the skeletons need only
Ansible and its supported Python runtime.
See CONTRIBUTING.md if you want to get involved.
The maintainers use the skeletons daily and continue to maintain them, even during periods with few repository updates.
Copyright (c) 2020, 2023-2026, foundata GmbH https://foundata.com
This project is licensed under the GNU General Public License v3.0 or later
(SPDX-License-Identifier: GPL-3.0-or-later), see
LICENSES/GPL-3.0-or-later.txt for the full
text.
The REUSE.toml file provides detailed licensing and copyright
information in a human- and machine-readable format. This includes parts that
may be subject to different licensing or usage terms, such as third-party
components. The repository conforms to the
REUSE specification. You can use
reuse spdx to create
an
SPDX software bill of materials (SBOM).
Third-party trademarks used in this repository:
- Ansible®, Fedora® and Red Hat® are trademarks of Red Hat, LLC, registered in the United States and other countries.
- Debian® is a trademark of Software in the Public Interest, Inc., registered in Germany and the United States.
- openSUSE® is a trademark of SUSE LLC or its affiliates, registered in the European Union and the United States.
- Proxmox® is a trademark of Proxmox Server Solutions GmbH, registered in Germany and the United States.
- Ubuntu® is a trademark of Canonical Ltd., registered in Germany, the European Union and the United States.
- Windows® is a trademark of Microsoft Corporation, registered in Germany, the European Union and the United States.
Their use here is purely descriptive and does not imply any affiliation with or endorsement by the trademark holders.
Own and licensed trademarks used in this repository:
- foundata® is a trademark of IPAM GmbH, registered in Germany and the European Union, licensed to foundata GmbH.
This project was created and is maintained by foundata. If you like it, you might buy us a coffee.
The Ansible Skeletons project is not associated with Red Hat nor the Ansible project.