Skip to content

Repository files navigation

Ansible (Galaxy) Skeletons

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:



Logo: Ansible (Galaxy) Skeletons

⭐ Found this useful? Support open-source and star this project:

GitHub repository


Table of contents

Features

  • Configuration for ansible-lint and 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.

Examples

Some collections built using these skeletons:

Usage

  1. 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}"

  2. Use ansible-galaxy to 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-9 and _ only.
    • company_url is optional. When set, the copyright holder in license headers, REUSE.toml and the README notice becomes <company> <<company_url>>, for example foundata GmbH <https://foundata.com>. Galaxy's company field keeps the plain name.
    • Adapt the directory name of the --[collection|role]-skeleton parameter value to use a skeleton other than [collection|role_]default. The available skeletons are described below.
  3. Follow the instructions in the generated FIXME.md file to adapt the collection or standalone role to your project.

Provided skeletons

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.

collection_default

A skeleton for packaging and shipping a run role in an Ansible collection. It includes:

collection_modules

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.product

version 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.

collection_modules_appliance

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.product

Follow the rendered FIXME.md to replace the fixtures with the product's resources.

role_default

A skeleton for standalone Ansible roles. It includes:

Compatibility

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.

Contributing

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.

Licensing, copyright

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).

REUSE status

Trademarks

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.

Author information

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.

Releases

Contributors

Languages