Files
kevinveenbirkenbachandClaude Opus 5.5 4e060767f1 fix(update): resolve EPEL packages from dl.fedoraproject.org on CentOS
CentOS jobs also die on "Failed to download metadata for repo 'epel':
Cannot download repomd.xml ... All mirrors were tried" (feature/store-i18n
run 39658756830, Baserow#0 and Nextcloud#8 aarch64): the failing host's
librepo log shows mirrors that answered and then failed the checksum the
metalink expects, the stale-metalink signature already pinned away for
the CentOS Stream repos, plus TLS errors from two mirrors.

centos_mirror.sh now also rewrites the EPEL repo files: each section's
own commented `#baseurl=https://download.example/pub/epel/...` template
becomes the baseurl on dl.fedoraproject.org and the Fedora metalink line
goes. Using the file's template keeps the path variables of whichever
epel-release is installed (`$releasever${stream:+s}` on CentOS Stream,
`releasever_minor` in newer releases). A file whose metalinks lack that
template stops the script with an error instead of losing its source.

The Dockerfile runs the script again right after
scripts/install/filesystem.sh. Its first run precedes the EPEL install
(filesystem.sh adds epel-release for btrfs-progs), so the image shipped an
unpinned epel.repo, and the failing call, sys-svc-ssh's OpenSSH install,
runs before roles/update/tasks/centos.yml pins anything.

On CentOS Stream the template resolves to epel/10s/, which on
dl.fedoraproject.org serves the same aarch64 repomd.xml as epel/10.4/, the
only path the epel-10s metalink lists.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-22 20:36:48 +02:00
..
…

Package update

Description

Operating-system package managers such as apt, pacman and dnf keep installed software in sync with their upstream distribution repositories. Each one ships with a different command surface but they all serve the same goal: refresh the index and upgrade every installed package on the host.

Overview

This role refreshes the package index and upgrades every installed package on the host. tasks/main.yml reads ansible_facts['distribution'] and dispatches to one task file per package-manager family. Debian and Ubuntu both use apt, so they share a single task file; Fedora and CentOS both use dnf, and CentOS reaches fedora.yml through centos.yml. A separate unsupported.yml fails loudly with a clear message when a host runs a distribution that this role does not yet cover.

ansible_facts['distribution'] Task file Module
Archlinux arch.yml community.general.pacman
Debian / Ubuntu debian.yml ansible.builtin.apt
Fedora fedora.yml ansible.builtin.dnf
CentOS centos.yml ansible.builtin.dnf
anything else unsupported.yml ansible.builtin.fail

centos.yml first runs centos_mirror.sh, which replaces every metalink= of the CentOS Stream repo files with a baseurl= on mirror.stream.centos.org and every metalink= of the EPEL repo files with the file's own baseurl template on dl.fedoraproject.org, and then includes fedora.yml. The Dockerfile runs the same script before its first dnf call, so the CentOS dev and swarm-node images resolve against the same source.

Cosmos

The diagram places Package update in the Infinito.Nexus cosmos: the components it deploys (capabilities), the central services it consumes (dependencies), and its outward reach (federation and bridged external networks).

flowchart LR
    subgraph role [update 💻]
        svc_update["update"]
    end

Solid 1:1 edges are fixed relationships; dashed 0..1 edges are conditional (enabled only in matching deployments); red 0..0 edges are turned off in this role. Node markers show the role's deploy modes (💻 host, 🐳 compose, 🐝 swarm); ❌ marks a service that is explicitly turned off, and ⚙️ an Ansible role dependency declared in meta/main.yml.

Features

  • Per-family dispatch: Routes by ansible_facts['distribution'] so the caller never has to gate the role with a when: clause.
  • Five-distro coverage: Supports the five default CI distros (Archlinux, Debian, Ubuntu, Fedora, CentOS) without duplicated task code.
  • Loud on unsupported hosts: Fails with a clear message instead of silently skipping when the host runs an unmapped distribution.
  • Once-per-play idempotency: Wraps the dispatch in when: run_once_update is not defined and writes the flag via tasks/utils/once/flag.yml, so repeated invocations within one play are no-ops.

Quick Setup

Development

Clone, set up the workstation, and deploy Package update onto the local stack:

git clone https://github.com/infinito-nexus/core.git
cd core
make onboard
make compose-deploy mode=reinstall apps=update full_cycle=false

Production

Install Package update directly onto the target machine: clone the repository, install the OS prerequisites and the repository toolchain, then deploy against localhost over a local connection (no SSH, no container):

git clone https://github.com/infinito-nexus/core.git
cd core
bash scripts/install/package.sh
make install
source scripts/meta/env/load.sh

APP=update
DOMAIN=<your-domain>
TLS_MODE=self_signed
SSH_PUBLIC_KEY="<your-ssh-public-key>"
INVENTORY=inventories/production
infinito administration inventory provision "$INVENTORY" \
  --inventory-file "$INVENTORY/devices.yml" \
  --host localhost \
  --include "$APP" \
  --vars "{\"TLS_MODE\": \"$TLS_MODE\", \"DOMAIN_PRIMARY\": \"$DOMAIN\", \"users\": {\"administrator\": {\"authorized_keys\": [\"$SSH_PUBLIC_KEY\"]}}}"
infinito administration deploy dedicated "$INVENTORY/devices.yml" \
  --password-file "$INVENTORY/.password" \
  --diff -vv

Developer Notes

To extend support for a new distribution, add the distribution name to the lookup dict in main.yml. When the new distribution shares a package manager with an existing entry, point it at that entry's task file. When it brings a new package manager, add a new family file under tasks/ and keep meta/main.yml platforms in sync.

Further Resources

Credits

Implemented by Kevin Veen-Birkenbach. Part of the Infinito.Nexus Project and maintained by Kevin Veen-Birkenbach. Licensed under the Infinito.Nexus Community License (Non-Commercial).