common_packages : pas de rattrapage des minuteurs apt herite du gabarit
Les minuteurs apt persistants d'un clone portaient la trace du gabarit (2026-06-21) et rattrapaient un passage dans l'heure suivant la naissance : apt-daily-upgrade a pris le verrou du cache des archives en plein amorcage d'infra-pki-01. Une trace plus ancienne que la machine est remise a l'heure et le minuteur relance, avant toute operation apt. Les correctifs restent automatiques. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
parent
c7378ed7f7
commit
3afb756993
3 changed files with 110 additions and 0 deletions
40
CHANGELOG.md
40
CHANGELOG.md
|
|
@ -1,5 +1,45 @@
|
|||
# CHANGELOG — Set-OPS
|
||||
|
||||
## 2026-10-08 (118) — Les clones rattrapaient un passage d'apt hérité du gabarit
|
||||
|
||||
**94 preuves.** La reconstruction de Technolibre sur `c7378ed` s'est arrêtée dès l'amorçage
|
||||
du socle, sur `infra-pki-01` : `'apt-get autoremove' failed: E: Could not get lock
|
||||
/var/cache/apt/archives/lock. It is held by process 13982 (apt-get)`.
|
||||
|
||||
### Ce qui s'est passé, à la seconde
|
||||
|
||||
- 22:54:30 : naissance de la VM ; `apt-daily.timer` et `apt-daily-upgrade.timer`, armés dans le
|
||||
gabarit, démarrent.
|
||||
- 22:58:30 : `common_packages` les réarme (décision du 2026-09-11 : les correctifs de sécurité
|
||||
s'appliquent seuls, « armer un minuteur ne déclenche pas sa cible »).
|
||||
- 22:59:20 : **`apt-daily-upgrade` part**, en pleine série d'opérations apt du rôle. Son
|
||||
`apt-get` tient le verrou du **cache des archives**, que ni `lock_timeout` ni
|
||||
`DPkg::Lock::Timeout` ne couvrent : `apt-get autoremove` échoue au lieu d'attendre.
|
||||
|
||||
**Pourquoi il est parti** : les deux minuteurs sont **persistants** (`Persistent=true`) et
|
||||
gardent la date de leur dernier passage. La trace d'`apt-daily` sur ce clone datait du
|
||||
**2026-06-21**, jour de fabrication du gabarit. Chaque VM clonée croit donc avoir manqué un
|
||||
passage et le rattrape dans l'heure (délai aléatoire, `RandomizedDelaySec=60m`). Avec 13 VM
|
||||
par reconstruction, c'est un tirage au sort depuis le 2026-09-11 ; les reconstructions
|
||||
précédentes l'ont gagné. La prémisse « armer ne déclenche pas » est vraie pour un minuteur
|
||||
neuf, fausse pour un clone.
|
||||
|
||||
### Fait
|
||||
|
||||
`common_packages/tasks/minuteurs.yml`, inclus avant toute opération apt (quand les mises à jour
|
||||
restent armées) : une trace plus ancienne que la naissance de la machine (clé d'hôte SSH) est
|
||||
remise à l'heure, et son minuteur relancé, ce qui recalcule le prochain passage sans
|
||||
rattrapage ; puis on attend la fin d'un passage déjà en cours. La décision du 2026-09-11 tient :
|
||||
les correctifs de sécurité restent automatiques.
|
||||
|
||||
### Éprouvé en vrai, sur `infra-pki-01` (clone neuf de Technolibre)
|
||||
|
||||
Premier passage : la trace d'`apt-daily` (2026-06-21) est remise à l'heure et le minuteur
|
||||
relancé ; celle d'`apt-daily-upgrade` (22:59:20, postérieure à la naissance) n'est **pas**
|
||||
touchée (témoin). Second passage : aucun changement. Prochains passages : demain 06:23 et
|
||||
17:26 ; aucun passage automatique parti depuis la relance. Lint propre ; `make verifier`
|
||||
conforme, **94/94**.
|
||||
|
||||
## 2026-10-08 (117) — Les applications de Nextcloud ne viennent plus de l'app store : le site les tient
|
||||
|
||||
**94 preuves.** La reconstruction de Technolibre sur `7a4c55b` (règle stricte, entrée (116)) s'est
|
||||
|
|
|
|||
|
|
@ -110,6 +110,11 @@
|
|||
when: not (common_packages_desarmer_maj_auto | bool)
|
||||
failed_when: false # une unite absente sur cette image n'est pas une faute
|
||||
|
||||
# AVANT TOUTE OPERATION APT : pas de rattrapage herite du gabarit (voir minuteurs.yml).
|
||||
- name: Empecher le rattrapage des minuteurs apt herite du gabarit
|
||||
ansible.builtin.include_tasks: minuteurs.yml
|
||||
when: not (common_packages_desarmer_maj_auto | bool)
|
||||
|
||||
- name: Mettre à jour le cache APT
|
||||
ansible.builtin.apt:
|
||||
update_cache: true
|
||||
|
|
|
|||
65
roles/common_packages/tasks/minuteurs.yml
Normal file
65
roles/common_packages/tasks/minuteurs.yml
Normal file
|
|
@ -0,0 +1,65 @@
|
|||
---
|
||||
# LE RATTRAPAGE HERITE DU GABARIT (2026-10-08).
|
||||
#
|
||||
# `apt-daily.timer` et `apt-daily-upgrade.timer` sont PERSISTANTS : systemd garde la date
|
||||
# de leur dernier passage (`/var/lib/systemd/timers/stamp-*`) et rattrape un passage
|
||||
# manque. Une VM clonee herite de ces traces — celle d'`apt-daily` datait du 2026-06-21,
|
||||
# jour de fabrication du gabarit. Elle « rattrape » donc des son demarrage, avec un delai
|
||||
# aleatoire jusqu'a 60 min : a la reconstruction de Technolibre, `apt-daily-upgrade` est
|
||||
# parti cinq minutes apres la naissance d'`infra-pki-01`, en pleine serie d'operations apt
|
||||
# du role. Il tenait le verrou du CACHE DES ARCHIVES, qu'`apt-get` n'attend jamais
|
||||
# (`DPkg::Lock::Timeout` ne couvre que dpkg) :
|
||||
#
|
||||
# 'apt-get autoremove' failed: E: Could not get lock /var/cache/apt/archives/lock.
|
||||
#
|
||||
# Une trace plus ancienne que la naissance de la machine n'est pas la sienne : on la remet a
|
||||
# l'heure, et on relance le minuteur, qui recalcule son prochain passage (le matin suivant)
|
||||
# sans rattraper. Les mises a jour automatiques restent armees (decision du 2026-09-11) ;
|
||||
# seul disparait un passage herite. Sur une machine en service, la trace est recente :
|
||||
# rien ne change.
|
||||
- name: Naissance de la machine (cle d'hote SSH, posee au premier demarrage)
|
||||
ansible.builtin.stat:
|
||||
path: /etc/ssh/ssh_host_ed25519_key.pub
|
||||
register: common_packages_naissance
|
||||
|
||||
- name: Traces des minuteurs apt persistants
|
||||
ansible.builtin.stat:
|
||||
path: "/var/lib/systemd/timers/stamp-{{ item }}"
|
||||
loop: "{{ common_packages_unites_maj_auto | select('match', '.*[.]timer$') | list }}"
|
||||
register: common_packages_traces
|
||||
|
||||
- name: Remettre a l'heure une trace heritee du gabarit
|
||||
ansible.builtin.file:
|
||||
path: "{{ item.stat.path }}"
|
||||
state: touch
|
||||
mode: "0644"
|
||||
loop: >-
|
||||
{{ common_packages_traces.results | selectattr('stat.exists')
|
||||
| selectattr('stat.mtime', 'lt', common_packages_naissance.stat.mtime | default(0))
|
||||
| list }}
|
||||
loop_control:
|
||||
label: "{{ item.item }}"
|
||||
register: common_packages_traces_remises
|
||||
when: common_packages_naissance.stat.exists
|
||||
|
||||
# Relancer recalcule le prochain passage d'apres la trace neuve. Relancer un minuteur ne
|
||||
# declenche pas sa cible.
|
||||
- name: Relancer les minuteurs dont la trace a ete remise
|
||||
ansible.builtin.systemd_service:
|
||||
name: "{{ item.item.item }}"
|
||||
state: restarted
|
||||
loop: "{{ common_packages_traces_remises.results | default([]) | selectattr('changed') | list }}"
|
||||
loop_control:
|
||||
label: "{{ item.item.item }}"
|
||||
|
||||
# UN PASSAGE DEJA PARTI se termine avant nos operations apt, plutot que de se les disputer.
|
||||
# `is-active` rend 0 si l'une au moins des unites tourne.
|
||||
- name: Attendre la fin d'un passage apt automatique deja en cours
|
||||
ansible.builtin.command:
|
||||
argv: ["systemctl", "is-active", "--quiet", "apt-daily.service", "apt-daily-upgrade.service"]
|
||||
register: common_packages_passage
|
||||
changed_when: false
|
||||
failed_when: false
|
||||
until: common_packages_passage.rc != 0
|
||||
retries: 30
|
||||
delay: 10
|
||||
Loading…
Reference in a new issue