Files
ad_trident/docs/appdaemon-upgrade-rollback-instructions.md
T
2026-11-13 13:15:03 +01:00

275 lines
12 KiB
Markdown

# Instructions après mise à jour ou rollback AppDaemon
Préparé le 8 novembre 2026 pour cette installation `/conf`.
À suivre par Codex après installation de **4.5.14**, ou retour en **4.5.10**.
Ce document prépare l'intervention : sa rédaction n'a appliqué aucun patch ni redémarré le service.
## 1. Identifier l'installation avant toute modification
Lire ce document et `docs/appdaemon-local-changes.md`. Conserver les modifications
applicatives existantes, les configurations YAML et les exclusions de dossiers.
Ne pas restaurer les anciennes instrumentations des utility loops : elles ont été
retirées volontairement et archivées dans `tools/archive/`.
Exécuter dans le conteneur, avec le Python réellement utilisé par AppDaemon :
```sh
python3 - <<'PY'
import inspect, sys
from importlib.metadata import version
import appdaemon
from appdaemon.utils import deep_compare
print('Python :', sys.executable)
print('Version :', version('appdaemon'))
print('Paquet :', appdaemon.__file__)
print('deep_compare :', inspect.getsourcefile(deep_compare))
print(inspect.getsource(deep_compare))
PY
```
Si le processus utilise un autre environnement, employer son interpréteur pour
les inspections, modifications et tests. Ne pas déduire la version du seul tag
Docker. Vérifier aussi l'Entrypoint/Cmd du conteneur et le script effectivement
exécuté ; une image personnalisée peut différer de l'image officielle.
Pour une autre version que 4.5.10 ou 4.5.14, refaire la comparaison avec ses sources.
Avant chaque édition, sauvegarder le fichier original dans un dossier daté sous
`/conf/tools/backups/appdaemon-<version>-<date>/`, en notant son chemin absolu,
sa version et son empreinte SHA-256. Ne pas écraser une sauvegarde précédente.
N'appliquer chaque changement qu'une fois ; si déjà présent, le vérifier.
Ne jamais remplacer un fichier 4.5.14 par une sauvegarde 4.5.10.
## 2. Tableau des changements
| Élément | 4.5.10 (rollback) | 4.5.14 |
|---|---|---|
| Timestamp de rafraîchissement HASS | Appliquer le patch `plugin.name` | Déjà intégré ; vérifier seulement |
| Comparaison des clés dans `deep_compare` | Appliquer dans `utils.py` | Appliquer dans `utils/misc.py` |
| Optimisation des logs ordinaires | Conserver le raccourci de `LoggerInterface` | Optimisation intégrée au core ; conserver le wrapper existant si compatible |
| Archivage au démarrage Docker | Ajouter l'appel dans `dockerStart.sh` | Ajouter l'appel dans `/start.sh` pour l'image officielle |
## 3. Patch HASS : 4.5.10 seulement
Dans le paquet installé, fichier `plugin_management.py`, méthode
`update_plugin_state()`, remplacer uniquement cet appel dans le `finally` :
```diff
- await self.refresh_update_time(plugin)
+ await self.refresh_update_time(plugin.name)
```
Cela évite de redemander l'état complet de Home Assistant chaque seconde après
expiration du délai de rafraîchissement (10 minutes par défaut).
Le correctif est intégré depuis 4.5.12 et confirmé dans le tag 4.5.14.
En 4.5.14, contrôler la ligne, sans ajouter un second patch.
Référence locale : `APPDAEMON_BANDWIDTH_BUG_FIX.md`.
## 4. Patch deep_compare : les deux versions
Localiser le fichier avec `inspect.getsourcefile(deep_compare)` :
- 4.5.10 : `appdaemon/utils.py`.
- 4.5.14 : `appdaemon/utils/misc.py` (le module a été réorganisé).
Dans `deep_compare()`, ajouter immédiatement après `data = data or {}` :
```python
if check.keys() != data.keys():
return False
```
Conserver tout le reste de la fonction propre à la version installée.
En particulier, garder `current = data.get(k)` en 4.5.14.
Le début de fonction doit donc ressembler à ceci :
```python
def deep_compare(check: dict, data: dict) -> bool:
"""Compares 2 nested dictionaries of values"""
data = data or {}
if check.keys() != data.keys():
return False
# Suite existante, différente selon la version : ne pas la remplacer.
```
La 4.5.14 évite le KeyError à l'ajout d'une clé, mais ne détecte toujours pas
certaines suppressions : la fonction officielle renvoie `True` pour
`deep_compare({}, {'input_selection': {}})`. Le patch corrige aussi les
suppressions imbriquées et distingue une clé absente d'une valeur `None`.
Vérifier dans un nouveau processus Python après modification :
```sh
python3 - <<'PY'
from appdaemon.utils import deep_compare
assert deep_compare({'input_selection': {}}, {}) is False
assert deep_compare({}, {'input_selection': {}}) is False
assert deep_compare({'x': {'a': 1}}, {'x': {}}) is False
assert deep_compare({'x': {}}, {'x': {'a': 1}}) is False
assert deep_compare({'x': None}, {}) is False
assert deep_compare({'x': [1, 2]}, {'x': [1, 2]}) is True
assert deep_compare({'x': [1, 2]}, {'x': [2, 1]}) is False
assert deep_compare({'x': {'a': 1}}, {'x': {'a': 1}}) is True
assert deep_compare({'x': {}}, {'x': None}) is False
assert deep_compare({}, None) is True
assert deep_compare({'input_selection': {}}, None) is False
print('OK : 11 vérifications deep_compare')
PY
```
Référence locale : `APPDAEMON_RELOAD_BUG_FIX.md`. Ses anciens chemins de
sauvegarde `.bak` ne sont plus actifs ; utiliser la sauvegarde de cette intervention.
## 5. LoggerInterface : conserver les fonctionnalités locales
Fichier persistant : `apps/ad_toolbox/logger_interface.py`, méthode `_write_log()`.
En **4.5.10**, conserver le raccourci existant : pour un message texte sans
`__module__`, `__line__` ou `__function__`, et avec les méthodes standard ADAPI,
appeler `api._log()` sans passer par l'inspection de pile. Garder le repli vers
`api.log()` pour les substitutions et les méthodes personnalisées. Préserver les
options d'encodage, le routage des logs et les groupes de messages.
Ne pas ajouter un autre patch dans `adapi.py` : il était volontairement revenu
au code officiel 4.5.10.
En **4.5.14**, `_sub_stack()` contient déjà le raccourci évitant `inspect.stack()`
sans marqueurs. Aucun patch core de logging n'est nécessaire. Conserver le
wrapper applicatif et ses fonctionnalités ; la suppression du raccourci local
redondant est facultative, pas un prérequis de migration. Tester sa compatibilité.
Tests existants :
```sh
python3 -m unittest discover -s /conf/apps/ad_toolbox/unit_tests -p 'test_logger_interface_fast_path.py' -v
python3 -m unittest discover -s /conf/apps/ad_toolbox/unit_tests -p 'test_logger_interface_grouping.py' -v
```
**Adaptation de test nécessaire en 4.5.14 :**
`test_direct_log_is_not_modified` attend actuellement `stack.assert_called_once()`
pour `api.log('Direct log')`. Cette attente correspond à 4.5.10. Pour 4.5.14,
attendre `stack.assert_not_called()`. Si le test doit couvrir les deux versions,
choisir explicitement l'attente selon la version installée, en conservant
l'assertion d'identité de `_sub_stack`. Ne pas modifier le core pour satisfaire
l'ancienne attente. Vérifier que les tests d'intégration ne sont pas ignorés
faute d'import AppDaemon.
## 6. Patch dockerStart / start.sh : les deux versions
### Comportement local à préserver
Avant le lancement d'AppDaemon, appeler une seule fois :
```sh
sh "$CONF/archiveLogs.sh"
```
Ce script persistant archive les anciens `*.log*` et `memory_usage.csv` dans
`/conf/logs/archive/<horodatage>/`, puis lance le suivi mémoire en arrière-plan.
Conserver le contenu actuel de `/conf/archiveLogs.sh`.
Ne pas lancer le script manuellement pendant qu'AppDaemon écrit ses logs pour
le « tester » : il déplacerait les fichiers ouverts. Ne pas lancer le script
de démarrage complet dans le conteneur déjà actif : cela lancerait un second AppDaemon.
### 4.5.10
Le script observé est `/usr/src/app/dockerStart.sh`.
`/conf/dockerStart.sh` est un **lien symbolique** vers ce fichier, pas une copie
persistante du patch. Après recréation du conteneur, la cible peut être remplacée.
Ajouter l'appel après les installations de dépendances, juste avant le lancement :
```sh
sh "$CONF/archiveLogs.sh"
# Lets run it!
exec python3 -m appdaemon -c $CONF "$@"
```
### 4.5.14 : changement de point d'entrée confirmé dans le tag officiel
Le Dockerfile copie `scripts/start.sh` vers **`/start.sh`** et définit
`ENTRYPOINT ["/start.sh"]`. Il n'utilise plus `dockerStart.sh`.
Dans cette image, patcher `/start.sh`, pas l'ancien lien `/conf/dockerStart.sh`.
Ajouter le même appel après l'installation des dépendances et avant l'exec :
```sh
sh "$CONF/archiveLogs.sh"
# Lets run it!
exec uv run --frozen appdaemon -c $CONF "$@"
```
Conserver le lancement `uv`, les installations via `uv pip`, le `PYTHONPATH`
et le répertoire de configuration exemple `/opt/conf` propres à cette version.
Ne pas recopier l'ancien script 4.5.10 par-dessus `/start.sh`.
Si l'image déployée possède un autre point d'entrée, transposer cet appel dans
le script réellement utilisé et noter le chemin dans le compte rendu.
L'ancien lien peut rester inutilisé ; ne pas le prendre comme preuve du patch.
### Vérification sans exécution
```sh
sh -n /conf/archiveLogs.sh
# Choisir le script réellement utilisé :
sh -n /usr/src/app/dockerStart.sh # 4.5.10
# OU
sh -n /start.sh # 4.5.14 officielle
```
Inspecter le script : exactement un appel actif à `archiveLogs.sh`, avant l'exec.
Ces modifications hors `/conf` sont perdues lors d'une recréation du conteneur,
comme les patchs Python. Les réappliquer à chaque nouvelle image, ou les intégrer
explicitement à une image dérivée si cela fait partie de l'intervention demandée.
## 7. Redémarrage et validation finale
Après application et vérifications, redémarrer le conteneur selon le mécanisme
habituel de cette installation, dans le périmètre de l'intervention demandée.
Un simple rechargement d'app ne remplace pas les fonctions core déjà importées
et ne réexécute pas le script de démarrage.
Vérifier après redémarrage :
1. Version réellement lancée et absence d'erreurs de démarrage/import.
2. Patch `deep_compare` toujours présent et 11 vérifications réussies dans le
même environnement que le service (une installation de dépendances au boot
pourrait avoir remplacé le paquet).
3. Message `[archiveLogs]`, archive créée si des anciens logs existaient,
nouveau `memory_usage.csv`, un seul processus `archiveLogs.sh --watch-memory`.
Vérifier l'ajout de mesures à l'intervalle configuré (300 secondes par défaut).
Avec `uv`, le PID 1 peut être uv : si les colonnes RSS AppDaemon sont vides,
vérifier le processus réel ; les métriques du conteneur restent distinctes.
4. Connexion Home Assistant et absence de rafraîchissements complets chaque
seconde après le délai de refresh configuré (10 minutes par défaut).
5. Tests du logger réussis avec l'attente adaptée à la version.
6. Si un essai de reload réel est nécessaire, utiliser une app de test isolée
sans action domotique ; vérifier ajout/suppression d'une clé imbriquée et
nettoyer l'essai. Ne pas modifier chauffage/volets pour ce test.
Mettre à jour `docs/appdaemon-local-changes.md` avec la version, les fichiers
réellement modifiés, les sauvegardes, résultats et statut du redémarrage.
Séparer les vérifications exécutées de celles restant à observer ; ne pas
annoncer une validation du service sur la seule base des tests unitaires.
## 8. Rollback vers 4.5.10
Revenir à l'image 4.5.10 prévue par le déploiement, puis reprendre les sections
1 à 7 pour **4.5.10** : patch HASS + clés `deep_compare` + raccourci applicatif
logger + appel d'archivage dans le vrai `dockerStart.sh`.
Les fichiers `/conf` et le sous-module `apps/ad_toolbox` doivent être conservés.
Si le test du logger a été rendu compatible avec les deux versions, le conserver.
Ne pas restaurer de fichiers core 4.5.14 dans 4.5.10, ni les anciennes sondes de
diagnostic archivées. Vérifier à nouveau après le redémarrage du rollback.
## Sources de référence
- Inventaire : [appdaemon-local-changes.md](appdaemon-local-changes.md).
- Diff core local 4.5.10 : [appdaemon-core-4.5.10.diff](appdaemon-core-4.5.10.diff).
- [4.5.14 : plugin_management.py](https://github.com/AppDaemon/appdaemon/blob/4.5.14/appdaemon/plugin_management.py).
- [4.5.14 : utils/misc.py](https://github.com/AppDaemon/appdaemon/blob/4.5.14/appdaemon/utils/misc.py).
- [4.5.14 : adapi.py](https://github.com/AppDaemon/appdaemon/blob/4.5.14/appdaemon/adapi.py).
- [4.5.14 : Dockerfile](https://github.com/AppDaemon/appdaemon/blob/4.5.14/Dockerfile).
- [4.5.14 : scripts/start.sh](https://github.com/AppDaemon/appdaemon/blob/4.5.14/scripts/start.sh).
- [4.5.10 : dockerStart.sh](https://github.com/AppDaemon/appdaemon/blob/4.5.10/dockerStart.sh).