diff --git a/roles/environment/defaults/main.yml b/roles/environment/defaults/main.yml index 69520c6..73b1511 100644 --- a/roles/environment/defaults/main.yml +++ b/roles/environment/defaults/main.yml @@ -9,6 +9,14 @@ environment_pacman_lock_timeout: 120 environment_pacman_retries: 4 environment_pacman_retry_delay: 15 +# Libraries the installer tools pull whose soname may have bumped past the ISO. +# Each library's installed reverse-dependencies are upgraded together with the +# tools so a current install onto an older ISO stays a consistent transaction +# instead of a partial upgrade. Extend if a future transition breaks the install. +environment_partial_upgrade_libs: + - nettle + - leancrypto + # PCI vendor IDs -> vendor codes used by hardware detection. # Only vendors that drive distinct firmware/driver packages are mapped. environment_pci_vendor_map: diff --git a/roles/environment/tasks/_prepare_installer.yml b/roles/environment/tasks/_prepare_installer.yml index 667cc60..adf1f67 100644 --- a/roles/environment/tasks/_prepare_installer.yml +++ b/roles/environment/tasks/_prepare_installer.yml @@ -14,24 +14,52 @@ timeout: "{{ environment_pacman_lock_timeout }}" changed_when: false -- name: Setup Pacman +- name: Resolve installer tools for the target OS + when: not (custom_iso | bool) + ansible.builtin.set_fact: + environment_installer_tools: >- + {{ + ['glibc'] + + (['lua', 'dnf'] if os in ['almalinux', 'fedora', 'rhel', 'rocky'] else []) + + (['debootstrap'] if os in ['debian', 'ubuntu', 'ubuntu-lts'] else []) + + (['debian-archive-keyring'] if os == 'debian' else []) + + (['ubuntu-keyring'] if os in ['ubuntu', 'ubuntu-lts'] else []) + }} + +- name: Query reverse-dependencies of transition-sensitive libraries when: - not (custom_iso | bool) - - item.os is not defined or os in item.os + - environment_partial_upgrade_libs | length > 0 + ansible.builtin.command: "pacman -Qi {{ item }}" + loop: "{{ environment_partial_upgrade_libs }}" + register: environment_revdep_query + changed_when: false + failed_when: false + +# Co-upgrade each transition library with its installed reverse-deps so a soname +# bump moves the whole closure in one transaction, not a partial upgrade. +- name: Setup Pacman + when: not (custom_iso | bool) + vars: + environment_pacman_closure: >- + {{ + ( + environment_installer_tools + + (environment_revdep_query.results | default([]) + | selectattr('rc', 'equalto', 0) | map(attribute='item') | list) + + (environment_revdep_query.results | default([]) + | selectattr('rc', 'equalto', 0) | map(attribute='stdout') + | map('regex_search', 'Required By\s*:\s*(.+)', '\1') + | map('first') | map('split') | flatten) + ) + | reject('equalto', 'None') | unique + }} community.general.pacman: update_cache: true - force: true - name: "{{ item.name }}" + name: "{{ environment_pacman_closure }}" state: latest - loop: - - { name: glibc } - - { name: lua, os: [almalinux, fedora, rhel, rocky] } - - { name: dnf, os: [almalinux, fedora, rhel, rocky] } - - { name: debootstrap, os: [debian, ubuntu, ubuntu-lts] } - - { name: debian-archive-keyring, os: [debian] } - - { name: ubuntu-keyring, os: [ubuntu, ubuntu-lts] } - loop_control: - label: "{{ item.name }}" + register: environment_tool_install + until: environment_tool_install is succeeded retries: "{{ environment_pacman_retries }}" delay: "{{ environment_pacman_retry_delay }}" @@ -76,10 +104,8 @@ opts: "ro,loop" state: mounted -# Security note: RPM Sequoia signature policy is relaxed to allow -# bootstrapping RHEL-family distros from the Arch ISO, where the -# host rpm/dnf does not trust target distro GPG keys. Package -# integrity is verified by the target system's own rpm after reboot. +# RPM Sequoia signature policy is relaxed because the Arch ISO host does not +# trust target-distro GPG keys; the target's own rpm re-verifies after reboot. - name: Create RPM macros directory when: is_rhel | bool ansible.builtin.file: