diff --git a/update.yml b/update.yml index 03654fa..848d69b 100644 --- a/update.yml +++ b/update.yml @@ -1,34 +1,165 @@ - name: Update system (APT + Flatpak) hosts: all + gather_facts: false + strategy: free + serial: 2 become: true become_user: root become_method: sudo + + vars: + ssh_precheck_timeout: 8 + apt_async: 1800 + apt_poll: 10 + apt_retries: 3 + apt_retry_delay: 5 + flatpak_timeout: 300 + flatpak_async: 600 + flatpak_poll: 5 + + pre_tasks: + - name: Ensure SSH is reachable (skip host if not) + wait_for: + host: "{{ ansible_host | default(inventory_hostname) }}" + port: "{{ ansible_port | default(22) }}" + timeout: "{{ ssh_precheck_timeout }}" + delegate_to: localhost + register: ssh_ok + ignore_errors: true + + - meta: end_host + when: ssh_ok is failed + + - name: Ping with retries (handle intermittent flaps) + ping: + register: ping_r + retries: 3 + delay: 3 + until: ping_r is succeeded + ignore_errors: true + + - meta: end_host + when: ping_r is failed + tasks: - - name: Update APT cache + - name: Update APT cache (bounded + retried) + environment: { DEBIAN_FRONTEND: noninteractive } apt: update_cache: yes + cache_valid_time: 3600 + async: "{{ apt_async }}" + poll: "{{ apt_poll }}" + register: apt_update + retries: "{{ apt_retries }}" + delay: "{{ apt_retry_delay }}" + until: apt_update is succeeded - - name: Upgrade all APT packages + - name: If APT cache update failed, try to fix dpkg and retry once + block: + - name: Fix partially configured packages + command: dpkg --configure -a + changed_when: false + - name: Retry APT cache update after dpkg fix + environment: { DEBIAN_FRONTEND: noninteractive } + apt: + update_cache: yes + async: 600 + poll: 5 + when: apt_update is failed + + - name: Upgrade all APT packages (bounded + retried) + environment: { DEBIAN_FRONTEND: noninteractive } apt: upgrade: dist + async: "{{ apt_async }}" + poll: "{{ apt_poll }}" + register: apt_upgrade + retries: "{{ apt_retries }}" + delay: "{{ apt_retry_delay }}" + until: apt_upgrade is succeeded + + - name: If APT upgrade failed, try to fix dpkg and retry once + block: + - name: Fix partially configured packages + command: dpkg --configure -a + changed_when: false + - name: Retry APT upgrade after dpkg fix + environment: { DEBIAN_FRONTEND: noninteractive } + apt: + upgrade: dist + async: 1200 + poll: 5 + when: apt_upgrade is failed - name: Check if flatpak binary exists + become: false stat: path: /usr/bin/flatpak register: flatpak_bin - - name: Update system Flatpaks - shell: timeout 300 flatpak update -y + - name: Update system Flatpaks (bounded; treat timeout as non-fatal) + command: bash -lc "timeout {{ flatpak_timeout }} flatpak update -y --noninteractive" register: flatpak_sys - failed_when: flatpak_sys.rc != 0 and flatpak_sys.rc != 124 + async: "{{ flatpak_async }}" + poll: "{{ flatpak_poll }}" + failed_when: flatpak_sys.rc is defined and flatpak_sys.rc not in [0, 124] when: flatpak_bin.stat.exists - - name: Update user Flatpaks - become_user: jakub - environment: - XDG_RUNTIME_DIR: /run/user/1000 - shell: timeout 300 flatpak update -y - register: flatpak_user - failed_when: flatpak_user.rc != 0 and flatpak_user.rc != 124 + # ---- User-agnostic Flatpak updates (all non-system users) ---- + + - name: Get passwd database + getent: + database: passwd + register: ge + + - name: Build list of regular users (uid >= 1000, real shells) + set_fact: + regular_users: >- + {{ + ge.ansible_facts.getent_passwd + | dict2items + | map(attribute='value') + | selectattr('uid', 'defined') + | selectattr('uid', '>=', 1000) + | rejectattr('shell', 'in', ['/usr/sbin/nologin','/sbin/nologin','/bin/false']) + | list + }} + when: ge is succeeded + + - name: Stat per-user runtime dir if flatpak is present + stat: + path: "/run/user/{{ item.uid }}" + loop: "{{ regular_users | default([]) }}" + loop_control: + label: "{{ item.name }}" + register: user_runtime_stats + when: flatpak_bin.stat.exists + + - name: Merge runtime stats keyed by username + set_fact: + user_runtime_map: >- + {{ + user_runtime_stats.results + | items2dict(key_name='item.name', value_name='stat') + }} + when: flatpak_bin.stat.exists + + - name: Update user Flatpaks (use XDG_RUNTIME_DIR when available) + become_user: "{{ item.name }}" + environment: >- + {{ + user_runtime_map[item.name].exists + | default(false) + | ternary({'XDG_RUNTIME_DIR': '/run/user/' ~ item.uid|string}, {}) + }} + command: bash -lc "timeout {{ flatpak_timeout }} flatpak --user update -y --noninteractive" + register: flatpak_user_res + async: "{{ flatpak_async }}" + poll: "{{ flatpak_poll }}" + failed_when: flatpak_user_res.rc is defined and flatpak_user_res.rc not in [0, 124] + changed_when: "'Installing' in (flatpak_user_res.stdout | default('')) or 'Installing' in (flatpak_user_res.stderr | default('')) or 'Updating' in (flatpak_user_res.stdout | default('')) or 'Updating' in (flatpak_user_res.stderr | default(''))" + loop: "{{ regular_users | default([]) }}" + loop_control: + label: "{{ item.name }}" when: flatpak_bin.stat.exists