Files
computer-playbook/roles/update/README.md
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

119 lines
5.6 KiB
Markdown

# Package update
## Description
Operating-system package managers such as [apt](https://wiki.debian.org/Apt),
[pacman](https://wiki.archlinux.org/title/pacman) and
[dnf](https://dnf.readthedocs.io/) 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](files/shell/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](../../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).
```mermaid
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:
```bash
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):
```bash
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](./tasks/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/](./tasks/) and keep [meta/main.yml](./meta/main.yml) `platforms` in
sync.
## Further Resources
- [apt](https://wiki.debian.org/Apt)
- [pacman](https://wiki.archlinux.org/title/pacman)
- [dnf](https://dnf.readthedocs.io/)
- [community.general.pacman](https://docs.ansible.com/ansible/latest/collections/community/general/pacman_module.html)
- [ansible.builtin.apt](https://docs.ansible.com/ansible/latest/collections/ansible/builtin/apt_module.html)
- [ansible.builtin.dnf](https://docs.ansible.com/ansible/latest/collections/ansible/builtin/dnf_module.html)
## Credits
Implemented by **[Kevin Veen-Birkenbach](https://www.veen.world)**.
Part of the [Infinito.Nexus Project](https://s.infinito.nexus/code) and maintained by [Kevin Veen-Birkenbach](https://www.veen.world).
Licensed under the [Infinito.Nexus Community License (Non-Commercial)](https://s.infinito.nexus/license).