diff --git a/README.md b/README.md index c5870a7..2c03382 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,6 @@ - # Automatisation update Portainer (Node-RED + Home Assistant) -Documentation basée sur l'export final du flow `pveSystem`, vérifiée ligne par ligne contre le JSON fourni. Aucune information ci-dessous n'est devinée ; là où un point reste incertain, un niveau de confiance est indiqué. +Documentation du flow `pveSystem`, section mise à jour automatique des conteneurs Portainer. ## Objectif @@ -11,29 +10,28 @@ Détecter automatiquement quand un nombre suffisant de conteneurs Portainer ont Node-RED, node inject **`triggerWedSun-1300`**, planification cron : `30 13 * * 3,0`. -Cela signifie : tous les **mercredis et dimanches à 13h30**. C'est ce planning, et non une vérification "si ce n'est pas vendredi" à l'exécution, qui limite les jours où l'automatisation peut se déclencher. Plus simple que l'approche initialement envisagée (un node function séparé), et ça respecte la règle "solution native la plus simple d'abord". +Cela signifie : tous les **mercredis et dimanches à 13h30**. C'est ce planning qui limite les jours où l'automatisation se déclenche, pas une vérification à l'exécution. ## Pipeline Node-RED (onglet pveSystem) 1. **triggerWedSun-1300** (inject, cron) déclenche tout le pipeline. -2. **portainer_auto** (node Get Entities) récupère les entités `update.*` qui remplissent DEUX conditions à la fois : +2. **portainer_auto** (node Get Entities) récupère les entités `update.*` qui remplissent deux conditions à la fois : - `state == on` (une mise à jour est disponible) - label registry `name == portainer_auto` - Sortie : tableau (`outputType: array`). Testé empiriquement le 27/09/2026 : 13 éléments retournés. Le champ `outputResultsCount: 1` présent dans la config ne limite pas le résultat, vérifié par ce même test. -3. **updateContainer>=10** (node switch), propriété `payload.length`, règle `gte 10`. En dessous de 10 mises à jour en attente, rien ne se passe, le pipeline s'arrête ici. -4. Si le seuil est atteint, **trois actions partent en parallèle**, pas en séquence : - - **containerUpdateAll** → appelle le service `update.install`, ciblé par label `portainer_auto` (tous les conteneurs labellisés d'un coup). C'est l'action qui lance réellement les mises à jour. +3. **updateContainer>=10** (node switch), propriété `payload.length`, règle `gte 10`. En dessous de 10 mises à jour en attente, le pipeline s'arrête ici. +4. Si le seuil est atteint, trois actions partent en parallèle : + - **containerUpdateAll** → appelle le service `update.install`, ciblé par label `portainer_auto`. C'est l'action qui lance les mises à jour. - **portainerUpdateAllMsg** → déclenche l'automation HA `automation.portainerupdateallmsg` (notification "avant"). - Un délai de **10 minutes**, puis **portainerUpdatedAllMsg** → déclenche l'automation HA `automation.portainerupdatedallmsg` (message de suivi). -**Point de vigilance (confiance 90%, lecture directe du flow) :** la notification "avant" et le lancement réel de `update.install` partent au même instant. Le message Telegram n'est donc pas une alerte qu'on peut annuler avant exécution, c'est un avertissement envoyé en parallèle de l'action, conforme à ce qui avait été demandé ("exécution auto"). +La notification "avant" et le lancement de `update.install` partent au même instant : le message Telegram est un avertissement envoyé en parallèle de l'action, pas une alerte qu'on peut annuler avant exécution. ## Les deux automations Home Assistant ### `automation.portainerupdateallmsg` — notification "avant" Titre : 🚨Update is available!🚨 -Liste, triée alphabétiquement par nom de conteneur (pas de sha256 affiché), tous les conteneurs actuellement en attente de mise à jour : +Liste, triée alphabétiquement par nom de conteneur, tous les conteneurs actuellement en attente de mise à jour : ``` {% for e in label_entities('portainer_auto') if states(e) == 'on' %} @@ -41,42 +39,39 @@ Liste, triée alphabétiquement par nom de conteneur (pas de sha256 affiché), t Envoyée en parallèle via : -- `telegram_bot.send_message` (avec `parse_mode: plain_text` obligatoire, sinon Telegram plante sur les underscores des noms de conteneurs comme `athtk_ctr`) +- `telegram_bot.send_message` (avec `parse_mode: plain_text`, requis car les noms de conteneurs contiennent des underscores qui cassent le Markdown Telegram) - `persistent_notification.create` ### `automation.portainerupdatedallmsg` — message de suivi, +10 min Titre : ✅Update is Done✅ -Utilise **exactement le même filtre** (`states(e) == 'on'`) que l'automation précédente. Malgré son titre, elle ne confirme donc pas que tout est fini : elle recompte, 10 minutes après le lancement, ce qui est **encore** en attente et affiche "X update(s) remain!". Un résultat proche de 0 indique un succès ; un nombre non nul signale des conteneurs pas encore à jour (mise à jour en cours, lente, ou échouée). - -**Point de vigilance :** 10 minutes est une valeur fixe, pas calculée. Sur une connexion lente ou avec beaucoup d'images volumineuses à tirer, ce délai peut être insuffisant et afficher un "reste X" alors que les mises à jour sont simplement encore en cours. +Utilise le même filtre (`states(e) == 'on'`) que l'automation précédente. Elle recompte, 10 minutes après le lancement, ce qui est encore en attente et affiche "X update(s) remain!". Un résultat proche de 0 indique un succès ; un nombre non nul signale des conteneurs pas encore à jour. ## Le label HA `portainer_auto` -Créé manuellement dans HA (Paramètres > Zones, étiquettes et emplacements > Étiquettes). Appliqué en masse aux **54 entités** `update.*` de l'intégration Portainer (Paramètres > Appareils et services > Entités, filtré par intégration "Portainer", sélection groupée + Add label). +Créé dans HA (Paramètres > Zones, étiquettes et emplacements > Étiquettes). Appliqué en masse aux 54 entités `update.*` de l'intégration Portainer (Paramètres > Appareils et services > Entités, filtré par intégration "Portainer", sélection groupée + Add label). -Toutes les entités Portainer portent ce label, qu'une mise à jour soit disponible ou non à un instant donné ; c'est le filtre `state == on`, présent à la fois côté Node-RED (rule "state_object") et côté Jinja (`if states(e) == 'on'`), qui isole celles ayant réellement une mise à jour en attente. Ces deux filtres sont indépendants l'un de l'autre et doivent être maintenus cohérents si la logique change un jour. +Toutes les entités Portainer portent ce label, qu'une mise à jour soit disponible ou non ; c'est le filtre `state == on`, présent à la fois côté Node-RED et côté Jinja, qui isole celles ayant réellement une mise à jour en attente. ## Comment ajuster les paramètres -| Paramètre | Où le changer | -| ------------------------------------------------------ | -------------------------------------------------------------------------------------------- | -| Jours / heure de déclenchement | Champ crontab du node`triggerWedSun-1300` (syntaxe cron, jours 0-6, 0 = dimanche) | -| Seuil de déclenchement (actuellement 10) | Node`updateContainer>=10`, valeur de la règle `gte` | -| Délai avant le message de suivi (actuellement 10 min) | Node delay entre le switch et`portainerUpdatedAllMsg` | -| Conteneur à inclure/exclure du périmètre | Ajouter/retirer le label`portainer_auto` sur l'entité `update.*` correspondante dans HA | +| Paramètre | Où le changer | +|---|---| +| Jours / heure de déclenchement | Champ crontab du node `triggerWedSun-1300` (syntaxe cron, jours 0-6, 0 = dimanche) | +| Seuil de déclenchement (actuellement 10) | Node `updateContainer>=10`, valeur de la règle `gte` | +| Délai avant le message de suivi (actuellement 10 min) | Node delay entre le switch et `portainerUpdatedAllMsg` | +| Conteneur à inclure/exclure du périmètre | Ajouter/retirer le label `portainer_auto` sur l'entité `update.*` correspondante dans HA | -## Historique de debug (pour référence future, éviter de refaire les mêmes erreurs) +## Notes techniques (pièges connus) -- `attributes.labels` n'est **pas** le bon champ pour filtrer par label sur le node Get Entities. Utiliser le type de règle dédié "Label Property" (accessible via le bouton `+ add label`). -- Le nom de propriété exact pour compter un tableau dans un node switch est `payload.length` (attention à la faute de frappe `payload.lenght`, invalide silencieusement). -- L'action générique `notify.send_message` ne supporte **pas** le champ `parse_mode`. Il faut utiliser `telegram_bot.send_message`, avec `entity_id` à plat dans `data:` (pas sous `target:`). -- `persistent_notification.create` n'accepte pas `parse_mode` (erreur de validation si présent). -- Pour un message multi-lignes lisible dans un template YAML plié (`>-`), séparer chaque bloc Jinja (`{% %}` / `{{ }}`) par une ligne vide, sinon tout le texte est concaténé sur une seule ligne. -- `label_entities('label')` est la fonction de template HA pour récupérer les entity_id portant un label donné, confirmée sur home-assistant.io/template-functions/label_entities. +- `attributes.labels` n'est pas le bon champ pour filtrer par label sur le node Get Entities. Utiliser le type de règle dédié "Label Property" (bouton `+ add label`). +- Le nom de propriété exact pour compter un tableau dans un node switch est `payload.length`. +- L'action générique `notify.send_message` ne supporte pas le champ `parse_mode`. Utiliser `telegram_bot.send_message`, avec `entity_id` à plat dans `data:` (pas sous `target:`). +- `persistent_notification.create` n'accepte pas `parse_mode`. +- Dans un template YAML plié (`>-`), séparer chaque bloc Jinja (`{% %}` / `{{ }}`) par une ligne vide pour préserver les sauts de ligne du message final. +- `label_entities('label')` est la fonction de template HA pour récupérer les entity_id portant un label donné. -## Point non vérifié dans cette session +## Limites connues -Confiance 90%, pas 100% : le node `containerUpdateAll` n'a pas de propriété `disabled` dans son JSON, donc il est actif. Vérifie visuellement dans Node-RED (bordure pleine, pas pointillée/grisée) avant de considérer que ce README est à jour sur ce point précis, dans le cas où quelque chose aurait changé depuis cet export. - -Aucun mécanisme de rollback automatique n'existe si un conteneur ne redémarre pas correctement après `update.install`. +- Aucun mécanisme de rollback automatique si un conteneur ne redémarre pas correctement après `update.install`. +- Le délai de 10 minutes avant le message de suivi est fixe, pas adaptatif ; sur une connexion lente avec beaucoup d'images à tirer, il peut être insuffisant.