From 12717233affdaaa510abb60b1bb32b493097bbae Mon Sep 17 00:00:00 2001 From: GuiPoM <11942518+GuiPoM@users.noreply.github.com> Date: Mon, 1 Jun 2026 23:30:00 +0200 Subject: [PATCH] Add install.sh, HA config files, translate scripts to English, fix apt parsing --- README.fr.md | 147 ++++++++++++++++++++++++++++++++++++++++++ README.md | 113 ++++++++++++++++++-------------- ha-command-line.yaml | 22 +++++++ ha-shell-command.yaml | 6 ++ install.sh | 18 +++--- nas-docker-prune | 10 +-- nas-docker-pull | 39 +++++------ nas-docker-up | 78 +++++++++++----------- nas-ha-config.yaml | 51 --------------- nas-system-update | 83 ++++++++++++++++++++++++ nas-system-upgrade | 95 +++++++++++++++++++++++++++ nas-update | 78 +++++++++++----------- nas-update-system | 80 ----------------------- nas-upgrade-system | 81 ----------------------- 14 files changed, 530 insertions(+), 371 deletions(-) create mode 100644 README.fr.md create mode 100644 ha-command-line.yaml create mode 100644 ha-shell-command.yaml delete mode 100644 nas-ha-config.yaml create mode 100644 nas-system-update create mode 100644 nas-system-upgrade delete mode 100644 nas-update-system delete mode 100644 nas-upgrade-system diff --git a/README.fr.md b/README.fr.md new file mode 100644 index 0000000..6672729 --- /dev/null +++ b/README.fr.md @@ -0,0 +1,147 @@ +# nas-ops + +Scripts de maintenance et de mise à jour pour NAS sous Debian / OpenMediaVault 8. + +Gère les mises à jour système (`apt`) et Docker (`docker compose`), avec deux modes : +- **Terminal interactif** : affichage coloré, confirmations +- **Non-interactif** (Home Assistant, cron) : output JSON + +## Installation + +```bash +bash <(curl -fsSL https://raw.githubusercontent.com/GuiPoM/nas-ops/main/install.sh) +``` + +Les scripts sont installés dans `/usr/local/bin/` et disponibles directement en ligne de commande. + +## Configuration sudo (requis pour Home Assistant) + +Lors des appels SSH depuis Home Assistant, sudo demande un mot de passe. Il faut autoriser ces commandes sans mot de passe sur le NAS : + +```bash +echo " ALL=(ALL) NOPASSWD: /usr/local/bin/nas-system-update, /usr/local/bin/nas-system-upgrade, /usr/local/bin/nas-docker-pull, /usr/local/bin/nas-docker-up, /usr/local/bin/nas-docker-prune" > /etc/sudoers.d/nas-ops +chmod 440 /etc/sudoers.d/nas-ops +``` + +Remplace `` par l'utilisateur SSH utilisé dans ta config Home Assistant (celui défini dans `/config/.ssh/config`). + +## Scripts + +### `nas-update` + +Script racine interactif. Orchestre toutes les étapes dans l'ordre : + +1. Analyse système (apt) +2. Pull et détection des mises à jour Docker +3. Upgrade système (confirmation) +4. Upgrade Docker (tout ou conteneur par conteneur) +5. Nettoyage des images orphelines + +```bash +nas-update +``` + +--- + +### `nas-system-update` + +Vérifie les mises à jour système disponibles via apt. Ne modifie rien. + +- Mode terminal : affichage coloré des paquets upgradables +- Mode non-interactif (HA) : output JSON + +```bash +nas-system-update +``` + +```json +{"count":2,"reboot_required":false,"packages":[{"name":"curl","current":"7.88.0","available":"7.88.1"}]} +``` + +--- + +### `nas-system-upgrade` + +Applique les mises à jour système (`apt full-upgrade`). + +- Mode terminal : affiche le bilan + confirmation avant d'appliquer +- Mode non-interactif (HA) : applique directement + +```bash +nas-system-upgrade +``` + +--- + +### `nas-docker-pull` + +Pull toutes les images Docker des conteneurs actifs et détecte les mises à jour disponibles. **Ne recrée pas les conteneurs.** + +Idempotent : tant que `nas-docker-up` n'a pas recréé les conteneurs, le check détecte toujours l'écart. + +- Mode terminal : affichage coloré +- Mode non-interactif (HA) : output JSON + +```bash +nas-docker-pull +``` + +```json +{"count":1,"containers":[{"name":"jellyfin","image":"jellyfin/jellyfin:latest","compose_dir":"/opt/stacks/jellyfin","current":"10.9.0","available":"disponible"}]} +``` + +--- + +### `nas-docker-up` + +Recrée les conteneurs sur la nouvelle image via `docker compose up -d --remove-orphans`. + +- Sans argument : propose la mise à jour de tous les conteneurs ayant une image plus récente +- Avec argument : cible une stack spécifique +- Mode terminal : confirmation par stack ou tout d'un coup +- Mode non-interactif (HA) : applique directement + +```bash +nas-docker-up # toutes les stacks +nas-docker-up jellyfin # stack spécifique +``` + +--- + +### `nas-docker-prune` + +Nettoie les images Docker orphelines (dangling). À appeler après `nas-docker-up`. + +```bash +nas-docker-prune +``` + +--- + +## Intégration Home Assistant + +Deux fichiers prêts à l'emploi sont fournis : + +**`ha-shell-command.yaml`** — à inclure dans `configuration.yaml` : +```yaml +shell_command: !include ha-shell-command.yaml +``` + +**`ha-command-line.yaml`** — à inclure dans `configuration.yaml` : +```yaml +command_line: !include ha-command-line.yaml +``` + +Les sensors `command_line` exposent : +- `sensor.omv_system_updates` → nombre de paquets apt upgradables +- `sensor.omv_docker_updates` → nombre de conteneurs Docker à mettre à jour +- `reboot_required` et `packages` comme attributs du sensor système +- `containers` comme attribut du sensor Docker + +## Flux typique depuis HA + +``` +nas_docker_pull → détecte les mises à jour dispo (idempotent) +nas_docker_up → applique les mises à jour +nas_docker_prune → nettoie les anciennes images +``` diff --git a/README.md b/README.md index 745642f..6fd1397 100644 --- a/README.md +++ b/README.md @@ -1,30 +1,41 @@ # nas-ops -Scripts de maintenance et de mise à jour pour NAS sous Debian / OpenMediaVault 8. +Maintenance and update scripts for NAS running Debian / OpenMediaVault 8. -Gère les mises à jour système (`apt`) et Docker (`docker compose`), avec deux modes : -- **Terminal interactif** : affichage coloré, confirmations -- **Non-interactif** (Home Assistant, cron) : output JSON +Handles system updates (`apt`) and Docker updates (`docker compose`), with two modes: +- **Interactive terminal**: colored output, confirmations +- **Non-interactive** (Home Assistant, cron): JSON output ## Installation ```bash -curl -fsSL https://raw.githubusercontent.com/GuiPoM/nas-ops/main/install.sh | bash +bash <(curl -fsSL https://raw.githubusercontent.com/GuiPoM/nas-ops/main/install.sh) ``` -Les scripts sont installés dans `/usr/local/bin/` et disponibles directement en ligne de commande. +Scripts are installed in `/usr/local/bin/` and available directly from the command line. + +## Sudo configuration (required for Home Assistant) + +When calling scripts via SSH from Home Assistant, sudo requires passwordless access. Add the following rule on the NAS: + +```bash +echo " ALL=(ALL) NOPASSWD: /usr/local/bin/nas-system-update, /usr/local/bin/nas-system-upgrade, /usr/local/bin/nas-docker-pull, /usr/local/bin/nas-docker-up, /usr/local/bin/nas-docker-prune" > /etc/sudoers.d/nas-ops +chmod 440 /etc/sudoers.d/nas-ops +``` + +Replace `` with the SSH user used in your Home Assistant config (e.g. the user in `/config/.ssh/config`). ## Scripts ### `nas-update` -Script racine interactif. Orchestre toutes les étapes dans l'ordre : +Interactive root script. Orchestrates all steps in order: -1. Analyse système (apt) -2. Pull et détection des mises à jour Docker -3. Upgrade système (confirmation) -4. Upgrade Docker (tout ou conteneur par conteneur) -5. Nettoyage des images orphelines +1. System analysis (apt) +2. Docker pull and update detection +3. System upgrade (with confirmation) +4. Docker upgrade (all at once or container by container) +5. Orphaned image cleanup ```bash nas-update @@ -32,15 +43,15 @@ nas-update --- -### `nas-update-system` +### `nas-system-update` -Vérifie les mises à jour système disponibles via apt. Ne modifie rien. +Checks available system updates via apt. Does not modify anything. -- Mode terminal : affichage coloré des paquets upgradables -- Mode non-interactif (HA) : output JSON +- Terminal mode: colored output of upgradable packages +- Non-interactive mode (HA): JSON output ```bash -nas-update-system +nas-system-update ``` ```json @@ -49,57 +60,57 @@ nas-update-system --- -### `nas-upgrade-system` +### `nas-system-upgrade` -Applique les mises à jour système (`apt full-upgrade`). +Applies system updates (`apt full-upgrade`). -- Mode terminal : affiche le bilan + confirmation avant d'appliquer -- Mode non-interactif (HA) : applique directement +- Terminal mode: shows summary + confirmation before applying +- Non-interactive mode (HA): applies directly ```bash -nas-upgrade-system +nas-system-upgrade ``` --- ### `nas-docker-pull` -Pull toutes les images Docker des conteneurs actifs et détecte les mises à jour disponibles. **Ne recrée pas les conteneurs.** +Pulls all Docker images for active containers and detects available updates. **Does not recreate containers.** -Idempotent : tant que `nas-docker-up` n'a pas recréé les conteneurs, le check détecte toujours l'écart. +Idempotent: as long as `nas-docker-up` has not recreated the containers, the check always detects the gap. -- Mode terminal : affichage coloré -- Mode non-interactif (HA) : output JSON +- Terminal mode: colored output +- Non-interactive mode (HA): JSON output ```bash nas-docker-pull ``` ```json -{"count":1,"containers":[{"name":"jellyfin","image":"jellyfin/jellyfin:latest","compose_dir":"/opt/stacks/jellyfin","current":"10.9.0","available":"disponible"}]} +{"count":1,"containers":[{"name":"jellyfin","image":"jellyfin/jellyfin:latest","compose_dir":"/opt/stacks/jellyfin","current":"10.9.0","available":"available"}]} ``` --- ### `nas-docker-up` -Recrée les conteneurs sur la nouvelle image via `docker compose up -d --remove-orphans`. +Recreates containers on the new image via `docker compose up -d --remove-orphans`. -- Sans argument : propose la mise à jour de tous les conteneurs ayant une image plus récente -- Avec argument : cible une stack spécifique -- Mode terminal : confirmation par stack ou tout d'un coup -- Mode non-interactif (HA) : applique directement +- No argument: offers to update all containers with a newer image +- With argument: targets a specific stack +- Terminal mode: confirmation per stack or all at once +- Non-interactive mode (HA): applies directly ```bash -nas-docker-up # toutes les stacks -nas-docker-up jellyfin # stack spécifique +nas-docker-up # all stacks +nas-docker-up jellyfin # specific stack ``` --- ### `nas-docker-prune` -Nettoie les images Docker orphelines (dangling). À appeler après `nas-docker-up`. +Removes orphaned (dangling) Docker images. Call after `nas-docker-up`. ```bash nas-docker-prune @@ -107,24 +118,30 @@ nas-docker-prune --- -## Intégration Home Assistant +## Home Assistant Integration -Voir `nas-ha-config.yaml` pour la configuration complète. +Two ready-to-use files are provided: +**`ha-shell-command.yaml`** — include in `configuration.yaml` as: ```yaml -shell_command: - nas_update_system: "ssh -F /config/.ssh/config omv 'sudo nas-update-system'" - nas_upgrade_system: "ssh -F /config/.ssh/config omv 'sudo nas-upgrade-system'" - nas_docker_pull: "ssh -F /config/.ssh/config omv 'sudo nas-docker-pull'" - nas_docker_up: "ssh -F /config/.ssh/config omv 'sudo nas-docker-up'" - nas_docker_up_stack: "ssh -F /config/.ssh/config omv 'sudo nas-docker-up {{ stack }}'" - nas_docker_prune: "ssh -F /config/.ssh/config omv 'sudo nas-docker-prune'" +shell_command: !include ha-shell-command.yaml ``` -## Flux typique depuis HA +**`ha-command-line.yaml`** — include in `configuration.yaml` as: +```yaml +command_line: !include ha-command-line.yaml +``` + +The `command_line` sensors expose: +- `sensor.omv_system_updates` → number of upgradable apt packages +- `sensor.omv_docker_updates` → number of Docker containers to update +- `reboot_required` and `packages` as attributes on the system sensor +- `containers` as attribute on the Docker sensor + +## Typical workflow from HA ``` -nas_docker_pull → détecte les mises à jour dispo (idempotent) -nas_docker_up → applique les mises à jour -nas_docker_prune → nettoie les anciennes images +nas_docker_pull → detect available updates (idempotent) +nas_docker_up → apply updates +nas_docker_prune → clean up old images ``` diff --git a/ha-command-line.yaml b/ha-command-line.yaml new file mode 100644 index 0000000..9a3493b --- /dev/null +++ b/ha-command-line.yaml @@ -0,0 +1,22 @@ +- sensor: + name: OMV System Updates + unique_id: omv_system_updates + icon: mdi:debian + command: "ssh -F /config/.ssh/config omv 'sudo nas-system-update'" + command_timeout: 60 + scan_interval: 3600 + value_template: "{{ value_json.count | default(0) }}" + json_attributes: + - packages + - reboot_required + +- sensor: + name: OMV Docker Updates + unique_id: omv_docker_updates + icon: mdi:docker + command: "ssh -F /config/.ssh/config omv 'sudo nas-docker-pull'" + command_timeout: 300 + scan_interval: 3600 + value_template: "{{ value_json.count | default(0) }}" + json_attributes: + - containers diff --git a/ha-shell-command.yaml b/ha-shell-command.yaml new file mode 100644 index 0000000..ce44f64 --- /dev/null +++ b/ha-shell-command.yaml @@ -0,0 +1,6 @@ +nas_system_update: "ssh -F /config/.ssh/config omv 'sudo nas-system-update'" +nas_system_upgrade: "ssh -F /config/.ssh/config omv 'sudo nas-system-upgrade'" +nas_docker_pull: "ssh -F /config/.ssh/config omv 'sudo nas-docker-pull'" +nas_docker_up: "ssh -F /config/.ssh/config omv 'sudo nas-docker-up'" +nas_docker_up_stack: "ssh -F /config/.ssh/config omv 'sudo nas-docker-up {{ stack }}'" +nas_docker_prune: "ssh -F /config/.ssh/config omv 'sudo nas-docker-prune'" diff --git a/install.sh b/install.sh index 16f8991..5795442 100644 --- a/install.sh +++ b/install.sh @@ -1,17 +1,20 @@ #!/bin/bash # install.sh — Install nas-ops scripts to /usr/local/bin -# Usage : curl -fsSL https://raw.githubusercontent.com/GuiPoM/nas-ops/main/install.sh | bash +# Usage: bash <(curl -fsSL https://raw.githubusercontent.com/GuiPoM/nas-ops/main/install.sh) set -euo pipefail +# Redirect stdin from /dev/tty to avoid issues when piped from curl +exec < /dev/tty + REPO="GuiPoM/nas-ops" BRANCH="main" BASE_URL="https://raw.githubusercontent.com/${REPO}/${BRANCH}" INSTALL_DIR="/usr/local/bin" SCRIPTS=( - "nas-update-system" - "nas-upgrade-system" + "nas-system-update" + "nas-system-upgrade" "nas-docker-pull" "nas-docker-up" "nas-docker-prune" @@ -39,8 +42,8 @@ fi # Check dependencies echo -e "${CYAN}Checking dependencies...${RESET}" -for cmd in curl docker; do - if command -v "$cmd" > /dev/null 2>&1; then +for cmd in curl docker apt-get; do + if type "$cmd" > /dev/null 2>&1 || [ -x "/usr/bin/$cmd" ] || [ -x "/bin/$cmd" ]; then echo -e " ${GREEN}✅ ${cmd}${RESET}" else echo -e " ${YELLOW}⚠ ${cmd} not found — some scripts may not work${RESET}" @@ -51,12 +54,11 @@ echo "" # Download and install scripts echo -e "${CYAN}Installing scripts to ${INSTALL_DIR}...${RESET}" for script in "${SCRIPTS[@]}"; do - echo -ne " Downloading ${script}... " if curl -fsSL "${BASE_URL}/${script}" -o "${INSTALL_DIR}/${script}"; then chmod +x "${INSTALL_DIR}/${script}" - echo -e "${GREEN}✅${RESET}" + echo -e " ${GREEN}✅ ${script}${RESET}" else - echo -e "${RED}❌ Failed${RESET}" + echo -e " ${RED}❌ ${script} — Failed${RESET}" exit 1 fi done diff --git a/nas-docker-prune b/nas-docker-prune index da17504..ab6c42c 100644 --- a/nas-docker-prune +++ b/nas-docker-prune @@ -1,7 +1,7 @@ #!/bin/bash -# nas-docker-prune — Nettoie les images Docker orphelines (dangling) -# Usage : nas-docker-prune -# À appeler après nas-docker-up pour supprimer les anciennes images remplacées +# nas-docker-prune — Remove orphaned (dangling) Docker images +# Usage: nas-docker-prune +# Call after nas-docker-up to clean up replaced images set -euo pipefail @@ -12,11 +12,11 @@ if $INTERACTIVE; then GREEN='\033[0;32m' BOLD='\033[1m' RESET='\033[0m' - echo -e "${CYAN}🧹 Nettoyage des images orphelines...${RESET}" + echo -e "${CYAN}🧹 Removing orphaned images...${RESET}" fi docker image prune -f if $INTERACTIVE; then - echo -e "${GREEN}✅ Nettoyage terminé.${RESET}" + echo -e "${GREEN}✅ Cleanup complete.${RESET}" fi diff --git a/nas-docker-pull b/nas-docker-pull index 2a6f33c..74bd9ac 100644 --- a/nas-docker-pull +++ b/nas-docker-pull @@ -1,15 +1,16 @@ #!/bin/bash -# nas-docker-pull — Pull les images Docker et détecte les mises à jour disponibles -# Usage : nas-docker-pull -# Output : JSON (mode non-interactif) ou texte coloré (mode terminal) -# Idempotent : tant que nas-docker-up n'a pas recréé les conteneurs, -# le conteneur tourne sur l'ancien image ID → l'écart est toujours détecté +# nas-docker-pull — Pull Docker images and detect available updates +# Usage: nas-docker-pull +# Output: JSON (non-interactive mode) or colored text (terminal mode) +# Idempotent: as long as nas-docker-up has not recreated the containers, +# the container runs on the old image ID — the gap is always detected +# Also writes JSON to /tmp/nas-docker-pull.json for use by nas-update set -euo pipefail if [ -t 1 ]; then INTERACTIVE=true; else INTERACTIVE=false; fi -# Couleurs (mode terminal uniquement) +# Colors (terminal mode only) if $INTERACTIVE; then RED='\033[0;31m' GREEN='\033[0;32m' @@ -25,14 +26,14 @@ containers_json="" count=0 if $INTERACTIVE; then - echo -e "${BOLD}--- Vérification des images Docker ---${RESET}" + echo -e "${BOLD}--- Checking Docker images ---${RESET}" fi while IFS=: read -r container_id container_name; do - # Récupérer le compose_dir via le label + # Get compose_dir from container label compose_dir=$(docker inspect --format='{{index .Config.Labels "com.docker.compose.project.working_dir"}}' "$container_id" 2>/dev/null | xargs) - # Ignorer les conteneurs hors compose + # Skip containers not managed by compose if [ -z "$compose_dir" ] || [ ! -d "$compose_dir" ]; then continue fi @@ -40,14 +41,14 @@ while IFS=: read -r container_id container_name; do image_name=$(docker inspect --format='{{.Config.Image}}' "$container_id") old_image_id=$(docker inspect --format='{{.Image}}' "$container_id") old_ver=$(docker inspect --format='{{index .Config.Labels "org.opencontainers.image.version"}}' "$container_id" 2>/dev/null || echo "") - [ -z "$old_ver" ] && old_ver="inconnue" + [ -z "$old_ver" ] && old_ver="unknown" if $INTERACTIVE; then - echo -ne " Vérification de ${CYAN}${container_name}${RESET}... " + echo -ne " Checking ${CYAN}${container_name}${RESET}... " fi if ! docker pull "$image_name" > /dev/null 2>&1; then - if $INTERACTIVE; then echo -e "${YELLOW}⚠ Erreur de pull (ignoré)${RESET}"; fi + if $INTERACTIVE; then echo -e "${YELLOW}⚠ Pull error (skipped)${RESET}"; fi continue fi @@ -55,10 +56,10 @@ while IFS=: read -r container_id container_name; do if [ "$old_image_id" != "$new_image_id" ]; then new_ver=$(docker inspect --format='{{index .Config.Labels "org.opencontainers.image.version"}}' "$image_name" 2>/dev/null || echo "") - [ -z "$new_ver" ] && new_ver="disponible" + [ -z "$new_ver" ] && new_ver="available" if $INTERACTIVE; then - echo -e "${YELLOW}MAJ DISPONIBLE${RESET} : ${YELLOW}${old_ver}${RESET} → ${GREEN}${new_ver}${RESET}" + echo -e "${YELLOW}UPDATE AVAILABLE${RESET}: ${YELLOW}${old_ver}${RESET} → ${GREEN}${new_ver}${RESET}" fi entry="{\"name\":\"${container_name}\",\"image\":\"${image_name}\",\"compose_dir\":\"${compose_dir}\",\"current\":\"${old_ver}\",\"available\":\"${new_ver}\"}" @@ -69,21 +70,21 @@ while IFS=: read -r container_id container_name; do fi count=$((count + 1)) else - if $INTERACTIVE; then echo -e "${GREEN}✅ À jour${RESET}"; fi + if $INTERACTIVE; then echo -e "${GREEN}✅ Up to date${RESET}"; fi fi done < <(docker ps --format "{{.ID}}:{{.Names}}") -# Toujours écrire le JSON dans /tmp pour nas-update +# Always write JSON to /tmp for use by nas-update printf '{"count":%d,"containers":[%s]}\n' "$count" "$containers_json" > /tmp/nas-docker-pull.json if $INTERACTIVE; then echo "" - echo -e "${BOLD}--- Bilan ---${RESET}" + echo -e "${BOLD}--- Summary ---${RESET}" if [ $count -eq 0 ]; then - echo -e "${GREEN}✅ Tous les conteneurs sont à jour.${RESET}" + echo -e "${GREEN}✅ All containers are up to date.${RESET}" else - echo -e "${YELLOW}🐳 ${count} conteneur(s) à mettre à jour.${RESET}" + echo -e "${YELLOW}🐳 ${count} container(s) available for update.${RESET}" fi else cat /tmp/nas-docker-pull.json diff --git a/nas-docker-up b/nas-docker-up index df094f8..d23f432 100644 --- a/nas-docker-up +++ b/nas-docker-up @@ -1,10 +1,10 @@ #!/bin/bash -# nas-docker-up — Applique les mises à jour Docker via docker compose up -d -# Usage : nas-docker-up [stack_name] -# Sans argument : met à jour tous les conteneurs ayant une image plus récente -# Avec argument : met à jour uniquement la stack spécifiée -# Mode HA (non-interactif) : applique directement, pas de prompt -# Mode terminal : confirmation par stack (sauf si stack spécifiée en argument) +# nas-docker-up — Apply Docker updates via docker compose up -d +# Usage: nas-docker-up [stack_name] +# No argument: updates all containers with a newer image available +# With argument: updates only the specified stack +# Non-interactive mode (HA): applies directly, no prompt +# Terminal mode: confirmation per stack (unless a specific stack is given) set -euo pipefail @@ -12,7 +12,7 @@ if [ -t 1 ]; then INTERACTIVE=true; else INTERACTIVE=false; fi TARGET_STACK="${1:-}" -# Couleurs (mode terminal uniquement) +# Colors (terminal mode only) if $INTERACTIVE; then RED='\033[0;31m' GREEN='\033[0;32m' @@ -24,7 +24,7 @@ else RED='' GREEN='' YELLOW='' CYAN='' BOLD='' RESET='' fi -# --- Détection de l'env global OMV --- +# --- Detect global OMV env file --- OMV_GLOBAL_ENV="" if [ -f "/etc/omv-compose.env" ]; then OMV_GLOBAL_ENV="/etc/omv-compose.env" @@ -32,7 +32,7 @@ elif [ -f "/srv/omv-compose.env" ]; then OMV_GLOBAL_ENV="/srv/omv-compose.env" fi -# --- Collecte des conteneurs à mettre à jour --- +# --- Collect containers to update --- containers_to_update=() images_to_update=() compose_dirs=() @@ -41,11 +41,11 @@ old_versions=() new_versions=() if $INTERACTIVE; then - echo -e "${BOLD}--- Phase 1 : Recherche des mises à jour ---${RESET}" + echo -e "${BOLD}--- Phase 1: Detecting updates ---${RESET}" fi while IFS=: read -r container_id container_name; do - # Filtrer par stack si argument fourni + # Filter by stack if argument provided if [ -n "$TARGET_STACK" ] && [ "$container_name" != "$TARGET_STACK" ]; then stack_label=$(docker inspect --format='{{index .Config.Labels "com.docker.compose.project"}}' "$container_id" 2>/dev/null | xargs) if [ "$stack_label" != "$TARGET_STACK" ]; then @@ -62,14 +62,14 @@ while IFS=: read -r container_id container_name; do image_name=$(docker inspect --format='{{.Config.Image}}' "$container_id") old_image_id=$(docker inspect --format='{{.Image}}' "$container_id") old_ver=$(docker inspect --format='{{index .Config.Labels "org.opencontainers.image.version"}}' "$container_id" 2>/dev/null || echo "") - [ -z "$old_ver" ] && old_ver="inconnue" + [ -z "$old_ver" ] && old_ver="unknown" if $INTERACTIVE; then - echo -ne " Vérification de ${CYAN}${container_name}${RESET}... " + echo -ne " Checking ${CYAN}${container_name}${RESET}... " fi if ! docker pull "$image_name" > /dev/null 2>&1; then - if $INTERACTIVE; then echo -e "${YELLOW}⚠ Erreur de pull (ignoré)${RESET}"; fi + if $INTERACTIVE; then echo -e "${YELLOW}⚠ Pull error (skipped)${RESET}"; fi continue fi @@ -77,10 +77,10 @@ while IFS=: read -r container_id container_name; do if [ "$old_image_id" != "$new_image_id" ]; then new_ver=$(docker inspect --format='{{index .Config.Labels "org.opencontainers.image.version"}}' "$image_name" 2>/dev/null || echo "") - [ -z "$new_ver" ] && new_ver="disponible" + [ -z "$new_ver" ] && new_ver="available" if $INTERACTIVE; then - echo -e "${YELLOW}MAJ DISPONIBLE${RESET} : ${YELLOW}${old_ver}${RESET} → ${GREEN}${new_ver}${RESET}" + echo -e "${YELLOW}UPDATE AVAILABLE${RESET}: ${YELLOW}${old_ver}${RESET} → ${GREEN}${new_ver}${RESET}" fi containers_to_update+=("$container_name") @@ -90,7 +90,7 @@ while IFS=: read -r container_id container_name; do old_versions+=("$old_ver") new_versions+=("$new_ver") else - if $INTERACTIVE; then echo -e "${GREEN}✅ À jour${RESET}"; fi + if $INTERACTIVE; then echo -e "${GREEN}✅ Up to date${RESET}"; fi fi done < <(docker ps --format "{{.ID}}:{{.Names}}") @@ -98,30 +98,28 @@ done < <(docker ps --format "{{.ID}}:{{.Names}}") if [ ${#containers_to_update[@]} -eq 0 ]; then if $INTERACTIVE; then echo "" - echo -e "${GREEN}✅ Aucun conteneur à mettre à jour.${RESET}" - echo -e "${CYAN}🧹 Nettoyage des images orphelines...${RESET}" + echo -e "${GREEN}✅ No containers to update.${RESET}" fi - docker image prune -f > /dev/null exit 0 fi if $INTERACTIVE; then echo "" - echo -e "${BOLD}--- Phase 2 : Bilan des mises à jour disponibles ---${RESET}" + echo -e "${BOLD}--- Phase 2: Available updates ---${RESET}" for i in "${!containers_to_update[@]}"; do - echo -e " • ${CYAN}${containers_to_update[$i]}${RESET} : ${YELLOW}${old_versions[$i]}${RESET} → ${GREEN}${new_versions[$i]}${RESET}" + echo -e " • ${CYAN}${containers_to_update[$i]}${RESET}: ${YELLOW}${old_versions[$i]}${RESET} → ${GREEN}${new_versions[$i]}${RESET}" done echo "" - # Si stack spécifique : pas de question sur le mode, on applique directement + # If a specific stack was given, apply directly without asking if [ -z "$TARGET_STACK" ]; then UPDATE_ALL=false while true; do - read -p "Mettre à jour TOUS ces conteneurs ? [y]es (Tout) / [n]o (Choisir par conteneur) : " global_choice + read -p "Update ALL containers? [y]es (All) / [n]o (Choose per container): " global_choice case "$global_choice" in [yY]*) UPDATE_ALL=true; break ;; [nN]*) UPDATE_ALL=false; break ;; - *) echo "Veuillez répondre par y ou n." ;; + *) echo "Please answer y or n." ;; esac done else @@ -129,10 +127,10 @@ if $INTERACTIVE; then fi fi -# --- Phase 3 : Application --- +# --- Phase 3: Apply --- if $INTERACTIVE; then echo "" - echo -e "${BOLD}--- Phase 3 : Application des mises à jour ---${RESET}" + echo -e "${BOLD}--- Phase 3: Applying updates ---${RESET}" fi START_DIR=$(pwd) @@ -148,34 +146,34 @@ for i in "${!containers_to_update[@]}"; do DO_UPDATE=false if ! $INTERACTIVE; then - # Mode HA : toujours appliquer + # HA mode: always apply DO_UPDATE=true elif [ "$UPDATE_ALL" = true ]; then DO_UPDATE=true else while true; do - read -p "Mettre à jour '${c_name}' (${c_old_ver} → ${c_new_ver}) ? [y/n] : " choice + read -p " Update '${c_name}' (${c_old_ver} → ${c_new_ver})? [y/n]: " choice case "$choice" in [yY]*) DO_UPDATE=true; break ;; [nN]*) DO_UPDATE=false; break ;; - *) echo "Veuillez répondre par y ou n." ;; + *) echo "Please answer y or n." ;; esac done fi if [ "$DO_UPDATE" = true ]; then if $INTERACTIVE; then - echo -e " 🚀 Mise à jour de ${CYAN}${c_name}${RESET} dans ${c_dir}..." + echo -e " 🚀 Updating ${CYAN}${c_name}${RESET} in ${c_dir}..." fi if cd "$c_dir" 2>/dev/null; then ENV_ARGS="" - # Env global OMV + # Global OMV env if [ -n "$OMV_GLOBAL_ENV" ] && [ -f "$OMV_GLOBAL_ENV" ]; then ENV_ARGS="--env-file $OMV_GLOBAL_ENV" else - # Fallback : chercher global.env ou .env dans le dossier parent + # Fallback: look for global.env or .env in parent directory PARENT_DIR=$(dirname "$c_dir") if [ -f "$PARENT_DIR/global.env" ]; then ENV_ARGS="--env-file $PARENT_DIR/global.env" @@ -184,31 +182,31 @@ for i in "${!containers_to_update[@]}"; do fi fi - # .env local (toujours ajouté s'il existe) + # Local .env (always added if present) if [ -f ".env" ]; then ENV_ARGS="$ENV_ARGS --env-file .env" fi if docker compose $ENV_ARGS up -d --remove-orphans 2>&1; then if $INTERACTIVE; then - echo -e " ${GREEN}✅ ${c_name} mis à jour avec succès.${RESET}" + echo -e " ${GREEN}✅ ${c_name} updated successfully.${RESET}" fi upgraded=$((upgraded + 1)) else if $INTERACTIVE; then - echo -e " ${RED}❌ Échec de la mise à jour pour ${c_name}.${RESET}" + echo -e " ${RED}❌ Update failed for ${c_name}.${RESET}" fi failed=$((failed + 1)) fi else if $INTERACTIVE; then - echo -e " ${RED}❌ Impossible d'accéder à ${c_dir}.${RESET}" + echo -e " ${RED}❌ Cannot access ${c_dir}.${RESET}" fi failed=$((failed + 1)) fi else if $INTERACTIVE; then - echo -e " ⏭ Mise à jour ignorée pour ${c_name}." + echo -e " ⏭ Skipped: ${c_name}" fi fi @@ -217,8 +215,8 @@ done if $INTERACTIVE; then echo "" - echo -e "${BOLD}--- Terminé ---${RESET}" - echo -e " ${GREEN}✅ ${upgraded} mis à jour${RESET} ${RED}❌ ${failed} en échec${RESET}" + echo -e "${BOLD}--- Done ---${RESET}" + echo -e " ${GREEN}✅ ${upgraded} updated${RESET} ${RED}❌ ${failed} failed${RESET}" else printf '{"upgraded":%d,"failed":%d}\n' "$upgraded" "$failed" fi diff --git a/nas-ha-config.yaml b/nas-ha-config.yaml deleted file mode 100644 index ee8d357..0000000 --- a/nas-ha-config.yaml +++ /dev/null @@ -1,51 +0,0 @@ -# configuration.yaml — Home Assistant shell_command pour le NAS -# -# Ajouter dans configuration.yaml : -# -# shell_command: -# nas_update_system: "ssh -F /config/.ssh/config omv 'sudo nas-update-system'" -# nas_upgrade_system: "ssh -F /config/.ssh/config omv 'sudo nas-upgrade-system'" -# nas_docker_pull: "ssh -F /config/.ssh/config omv 'sudo nas-docker-pull'" -# nas_docker_up: "ssh -F /config/.ssh/config omv 'sudo nas-docker-up'" -# nas_docker_up_stack: "ssh -F /config/.ssh/config omv 'sudo nas-docker-up {{ stack }}'" -# -# Exemples d'utilisation depuis un script HA ou une automation : -# -# service: shell_command.nas_update_system -# service: shell_command.nas_upgrade_system -# service: shell_command.nas_docker_pull -# service: shell_command.nas_docker_up -# service: shell_command.nas_docker_up_stack -# data: -# stack: jellyfin -# -# ───────────────────────────────────────────────────────────────────────────── -# Sensor command_line pour exposer le résultat du check système dans HA -# ───────────────────────────────────────────────────────────────────────────── -# -# command_line: -# - sensor: -# name: NAS System Updates -# unique_id: nas_system_updates -# command: "ssh -F /config/.ssh/config omv 'sudo nas-update-system'" -# scan_interval: 3600 -# value_template: "{{ value_json.count }}" -# json_attributes: -# - packages -# - reboot_required -# -# - sensor: -# name: NAS Docker Updates -# unique_id: nas_docker_updates -# command: "ssh -F /config/.ssh/config omv 'sudo nas-docker-pull'" -# scan_interval: 3600 -# value_template: "{{ value_json.count }}" -# json_attributes: -# - containers -# -# Ces sensors exposent : -# - sensor.nas_system_updates → nombre de paquets apt upgradables -# - sensor.nas_docker_updates → nombre de conteneurs Docker à mettre à jour -# - sensor.nas_system_updates.reboot_required → true/false -# - sensor.nas_system_updates.packages → liste des paquets -# - sensor.nas_docker_updates.containers → liste des conteneurs diff --git a/nas-system-update b/nas-system-update new file mode 100644 index 0000000..fb8c4b5 --- /dev/null +++ b/nas-system-update @@ -0,0 +1,83 @@ +#!/bin/bash +# nas-system-update — Check available system updates (apt) +# Usage: nas-system-update +# Output: JSON (non-interactive mode) or colored text (terminal mode) + +set -euo pipefail + +if [ -t 1 ]; then INTERACTIVE=true; else INTERACTIVE=false; fi + +# Colors (terminal mode only) +if $INTERACTIVE; then + RED='\033[0;31m' + GREEN='\033[0;32m' + YELLOW='\033[1;33m' + CYAN='\033[0;36m' + BOLD='\033[1m' + RESET='\033[0m' +else + RED='' GREEN='' YELLOW='' CYAN='' BOLD='' RESET='' +fi + +if $INTERACTIVE; then + echo -e "${BOLD}--- Refreshing package list ---${RESET}" +fi + +apt-get update -qq 2>/dev/null + +# Parse apt-get --simulate full-upgrade +# Format: +# Inst name (available_version ...) → new package +# Inst name [current_version] (available_version ...) → upgrade +packages_json="" +count=0 + +while IFS= read -r line; do + # Extract package name (2nd field) + name=$(echo "$line" | awk '{print $2}' | tr -d '[:space:]') + [ -z "$name" ] && continue + + # Current version: inside [...] if present, else N/A + current=$(echo "$line" | grep -oP '(?<=\[)[^\]]+' | tr -d '[:space:]' || echo "") + [ -z "$current" ] && current="N/A" + + # Available version: first word inside first (...) + available=$(echo "$line" | grep -oP '(?<=\()[^ ]+' | head -1 | tr -d '[:space:]') + [ -z "$available" ] && continue + + if $INTERACTIVE; then + echo -e " ${CYAN}${name}${RESET} : ${YELLOW}${current}${RESET} → ${GREEN}${available}${RESET}" + fi + + # Build JSON entry + entry="{\"name\":\"${name}\",\"current\":\"${current}\",\"available\":\"${available}\"}" + if [ $count -eq 0 ]; then + packages_json="${entry}" + else + packages_json="${packages_json},${entry}" + fi + count=$((count + 1)) + +done < <(apt-get --simulate full-upgrade 2>/dev/null | grep "^Inst") + +# Check if reboot is required +reboot_required=false +if [ -f /var/run/reboot-required ]; then + reboot_required=true +fi + +if $INTERACTIVE; then + echo "" + echo -e "${BOLD}--- Summary ---${RESET}" + if [ $count -eq 0 ]; then + echo -e "${GREEN}✅ System is up to date.${RESET}" + else + echo -e "${YELLOW}📦 ${count} package(s) available for upgrade.${RESET}" + fi + if $reboot_required; then + echo -e "${RED}⚠️ Reboot required.${RESET}" + fi +else + printf '{"count":%d,"reboot_required":%s,"packages":[%s]}\n' \ + "$count" "$reboot_required" "$packages_json" +fi diff --git a/nas-system-upgrade b/nas-system-upgrade new file mode 100644 index 0000000..8c8f654 --- /dev/null +++ b/nas-system-upgrade @@ -0,0 +1,95 @@ +#!/bin/bash +# nas-system-upgrade — Apply system updates (apt full-upgrade) +# Usage: nas-system-upgrade +# Non-interactive mode (HA): applies directly, JSON output +# Terminal mode: shows summary + confirmation before applying + +set -euo pipefail + +if [ -t 1 ]; then INTERACTIVE=true; else INTERACTIVE=false; fi + +# Colors (terminal mode only) +if $INTERACTIVE; then + RED='\033[0;31m' + GREEN='\033[0;32m' + YELLOW='\033[1;33m' + CYAN='\033[0;36m' + BOLD='\033[1m' + RESET='\033[0m' +else + RED='' GREEN='' YELLOW='' CYAN='' BOLD='' RESET='' +fi + +# Ensure package list is up to date +if $INTERACTIVE; then + echo -e "${BOLD}--- Refreshing package list ---${RESET}" +fi +apt-get update -qq 2>/dev/null + +# Get packages to install/upgrade via simulation +# Format: +# Inst name (available_version ...) → new package +# Inst name [current_version] (available_version ...) → upgrade +packages=() +while IFS= read -r line; do + name=$(echo "$line" | awk '{print $2}') + [ -z "$name" ] && continue + current=$(echo "$line" | grep -oP '(?<=\[)[^\]]+' || echo "") + [ -z "$current" ] && current="N/A" + available=$(echo "$line" | grep -oP '(?<=\()[^ ]+' | head -1) + [ -z "$available" ] && continue + packages+=("${name}|${current}|${available}") +done < <(apt-get --simulate full-upgrade 2>/dev/null | grep "^Inst") + +count=${#packages[@]} + +if [ "$count" -eq 0 ]; then + if $INTERACTIVE; then + echo -e "${GREEN}✅ System is already up to date, nothing to do.${RESET}" + else + printf '{"status":"already_up_to_date","upgraded":0,"reboot_required":false}\n' + fi + exit 0 +fi + +if $INTERACTIVE; then + echo "" + echo -e "${BOLD}--- Packages to upgrade (${count}) ---${RESET}" + for entry in "${packages[@]}"; do + name=$(echo "$entry" | cut -d'|' -f1) + current=$(echo "$entry" | cut -d'|' -f2) + available=$(echo "$entry" | cut -d'|' -f3) + echo -e " ${CYAN}${name}${RESET} : ${YELLOW}${current}${RESET} → ${GREEN}${available}${RESET}" + done + echo "" + + read -p "Apply upgrade for these ${count} package(s)? [y/n]: " confirm + case "$confirm" in + [yY]*) ;; + *) echo -e "${YELLOW}Cancelled.${RESET}"; exit 0 ;; + esac + echo "" + echo -e "${BOLD}--- Running apt full-upgrade ---${RESET}" +fi + +# Apply +DEBIAN_FRONTEND=noninteractive apt-get full-upgrade -y \ + -o Dpkg::Options::="--force-confdef" \ + -o Dpkg::Options::="--force-confold" 2>&1 + +# Check if reboot is required +reboot_required=false +if [ -f /var/run/reboot-required ]; then + reboot_required=true +fi + +if $INTERACTIVE; then + echo "" + echo -e "${GREEN}✅ Upgrade complete.${RESET}" + if $reboot_required; then + echo -e "${RED}⚠️ Reboot required.${RESET}" + fi +else + printf '{"status":"upgraded","upgraded":%d,"reboot_required":%s}\n' \ + "$count" "$reboot_required" +fi diff --git a/nas-update b/nas-update index 9cb7a7b..66d33e7 100644 --- a/nas-update +++ b/nas-update @@ -1,11 +1,11 @@ #!/bin/bash -# nas-update — Script racine de gestion des mises à jour NAS -# Orchestre nas-update-system, nas-upgrade-system, nas-docker-pull, nas-docker-up, nas-docker-prune -# Usage : nas-update +# nas-update — NAS update manager (interactive root script) +# Orchestrates nas-system-update, nas-system-upgrade, nas-docker-pull, nas-docker-up, nas-docker-prune +# Usage: nas-update set -euo pipefail -# Couleurs +# Colors RED='\033[0;31m' GREEN='\033[0;32m' YELLOW='\033[1;33m' @@ -14,25 +14,25 @@ BOLD='\033[1m' RESET='\033[0m' echo -e "${BOLD}=====================================================${RESET}" -echo -e "${BOLD} NAS — Gestionnaire de mises à jour ${RESET}" +echo -e "${BOLD} NAS — Update Manager ${RESET}" echo -e "${BOLD}=====================================================${RESET}" echo "" # ───────────────────────────────────────────────────── -# Phase 1 : Analyse système +# Phase 1: System analysis # ───────────────────────────────────────────────────── -echo -e "${BOLD}--- Phase 1 : Analyse système (apt) ---${RESET}" -nas-update-system +echo -e "${BOLD}--- Phase 1: System analysis (apt) ---${RESET}" +nas-system-update echo "" # ───────────────────────────────────────────────────── -# Phase 2 : Analyse Docker (pull + détection diffs) +# Phase 2: Docker analysis (pull + diff detection) # ───────────────────────────────────────────────────── -echo -e "${BOLD}--- Phase 2 : Analyse Docker ---${RESET}" +echo -e "${BOLD}--- Phase 2: Docker analysis ---${RESET}" nas-docker-pull -# Lire le JSON écrit par nas-docker-pull +# Read JSON written by nas-docker-pull docker_json=$(cat /tmp/nas-docker-pull.json 2>/dev/null || echo '{"count":0,"containers":[]}') containers_to_update=() @@ -55,68 +55,68 @@ done < <(echo "$docker_json" | grep -o '{[^}]*}') echo "" # ───────────────────────────────────────────────────── -# Phase 3 : Upgrade système +# Phase 3: System upgrade # ───────────────────────────────────────────────────── -echo -e "${BOLD}--- Phase 3 : Mise à jour système ---${RESET}" +echo -e "${BOLD}--- Phase 3: System upgrade ---${RESET}" while true; do - read -p "Appliquer apt full-upgrade ? [y/n] : " sys_choice + read -p "Apply apt full-upgrade? [y/n]: " sys_choice case "$sys_choice" in [yY]*) - nas-upgrade-system + nas-system-upgrade break ;; [nN]*) - echo -e "${YELLOW}⏭ Mise à jour système ignorée.${RESET}" + echo -e "${YELLOW}⏭ System upgrade skipped.${RESET}" break ;; - *) echo "Veuillez répondre par y ou n." ;; + *) echo "Please answer y or n." ;; esac done echo "" # ───────────────────────────────────────────────────── -# Phase 4 : Upgrade Docker +# Phase 4: Docker upgrade # ───────────────────────────────────────────────────── -echo -e "${BOLD}--- Phase 4 : Mise à jour Docker ---${RESET}" +echo -e "${BOLD}--- Phase 4: Docker upgrade ---${RESET}" if [ ${#containers_to_update[@]} -eq 0 ]; then - echo -e "${GREEN}✅ Aucun conteneur à mettre à jour.${RESET}" + echo -e "${GREEN}✅ No containers to update.${RESET}" echo "" echo -e "${BOLD}=====================================================${RESET}" - echo -e "${GREEN} Terminé ! ${RESET}" + echo -e "${GREEN} Done! ${RESET}" echo -e "${BOLD}=====================================================${RESET}" exit 0 fi echo "" -echo -e "${BOLD}Bilan des conteneurs à mettre à jour :${RESET}" +echo -e "${BOLD}Containers available for update:${RESET}" for i in "${!containers_to_update[@]}"; do - echo -e " • ${CYAN}${containers_to_update[$i]}${RESET} : ${YELLOW}${old_versions[$i]}${RESET} → ${GREEN}${new_versions[$i]}${RESET}" + echo -e " • ${CYAN}${containers_to_update[$i]}${RESET}: ${YELLOW}${old_versions[$i]}${RESET} → ${GREEN}${new_versions[$i]}${RESET}" done echo "" UPDATE_ALL=false while true; do - read -p "Mettre à jour TOUS ces conteneurs ? [y]es (Tout) / [n]o (Choisir par conteneur) / [s]kip (Ignorer tout) : " docker_choice + read -p "Update ALL containers? [y]es (All) / [n]o (Choose per container) / [s]kip (Skip all): " docker_choice case "$docker_choice" in [yY]*) UPDATE_ALL=true; break ;; [nN]*) UPDATE_ALL=false; break ;; - [sS]*) echo -e "${YELLOW}⏭ Mise à jour Docker ignorée.${RESET}"; break ;; - *) echo "Veuillez répondre par y, n ou s." ;; + [sS]*) echo -e "${YELLOW}⏭ Docker upgrade skipped.${RESET}"; break ;; + *) echo "Please answer y, n or s." ;; esac done if [[ "$docker_choice" =~ ^[sS] ]]; then echo "" echo -e "${BOLD}=====================================================${RESET}" - echo -e "${GREEN} Terminé ! ${RESET}" + echo -e "${GREEN} Done! ${RESET}" echo -e "${BOLD}=====================================================${RESET}" exit 0 fi -# Détection de l'env global OMV +# Detect global OMV env file OMV_GLOBAL_ENV="" if [ -f "/etc/omv-compose.env" ]; then OMV_GLOBAL_ENV="/etc/omv-compose.env" @@ -140,17 +140,17 @@ for i in "${!containers_to_update[@]}"; do DO_UPDATE=true else while true; do - read -p " Mettre à jour '${c_name}' (${c_old_ver} → ${c_new_ver}) ? [y/n] : " choice + read -p " Update '${c_name}' (${c_old_ver} → ${c_new_ver})? [y/n]: " choice case "$choice" in [yY]*) DO_UPDATE=true; break ;; [nN]*) DO_UPDATE=false; break ;; - *) echo "Veuillez répondre par y ou n." ;; + *) echo "Please answer y or n." ;; esac done fi if [ "$DO_UPDATE" = true ]; then - echo -e " 🚀 Mise à jour de ${CYAN}${c_name}${RESET}..." + echo -e " 🚀 Updating ${CYAN}${c_name}${RESET}..." if cd "$c_dir" 2>/dev/null; then ENV_ARGS="" @@ -171,32 +171,32 @@ for i in "${!containers_to_update[@]}"; do fi if docker compose $ENV_ARGS up -d --remove-orphans 2>&1; then - echo -e " ${GREEN}✅ ${c_name} mis à jour avec succès.${RESET}" + echo -e " ${GREEN}✅ ${c_name} updated successfully.${RESET}" upgraded=$((upgraded + 1)) else - echo -e " ${RED}❌ Échec pour ${c_name}.${RESET}" + echo -e " ${RED}❌ Update failed for ${c_name}.${RESET}" failed=$((failed + 1)) fi else - echo -e " ${RED}❌ Impossible d'accéder à ${c_dir}.${RESET}" + echo -e " ${RED}❌ Cannot access ${c_dir}.${RESET}" failed=$((failed + 1)) fi else - echo -e " ⏭ Ignoré : ${c_name}" + echo -e " ⏭ Skipped: ${c_name}" fi cd "$START_DIR" done # ───────────────────────────────────────────────────── -# Phase 5 : Nettoyage des images orphelines +# Phase 5: Cleanup # ───────────────────────────────────────────────────── echo "" -echo -e "${BOLD}--- Phase 5 : Nettoyage ---${RESET}" +echo -e "${BOLD}--- Phase 5: Cleanup ---${RESET}" nas-docker-prune echo "" echo -e "${BOLD}=====================================================${RESET}" -echo -e "${BOLD} Terminé ! ${RESET}" -echo -e " Docker : ${GREEN}✅ ${upgraded} mis à jour${RESET} ${RED}❌ ${failed} en échec${RESET}" +echo -e "${BOLD} Done! ${RESET}" +echo -e " Docker: ${GREEN}✅ ${upgraded} updated${RESET} ${RED}❌ ${failed} failed${RESET}" echo -e "${BOLD}=====================================================${RESET}" diff --git a/nas-update-system b/nas-update-system deleted file mode 100644 index b06790b..0000000 --- a/nas-update-system +++ /dev/null @@ -1,80 +0,0 @@ -#!/bin/bash -# nas-update-system — Vérifie les mises à jour système disponibles (apt) -# Usage : nas-update-system -# Output : JSON (mode non-interactif) ou texte coloré (mode terminal) - -set -euo pipefail - -if [ -t 1 ]; then INTERACTIVE=true; else INTERACTIVE=false; fi - -# Couleurs (mode terminal uniquement) -if $INTERACTIVE; then - RED='\033[0;31m' - GREEN='\033[0;32m' - YELLOW='\033[1;33m' - CYAN='\033[0;36m' - BOLD='\033[1m' - RESET='\033[0m' -else - RED='' GREEN='' YELLOW='' CYAN='' BOLD='' RESET='' -fi - -if $INTERACTIVE; then - echo -e "${BOLD}--- Mise à jour de la liste des paquets ---${RESET}" -fi - -apt-get update -qq 2>/dev/null - -# Parser apt list --upgradable -# Format : nom/suite version arch [upgradable from: ancienne_version] -packages_json="" -count=0 - -while IFS= read -r line; do - # Ignorer la ligne d'avertissement "Listing..." - [[ "$line" =~ ^Listing ]] && continue - [[ -z "$line" ]] && continue - - # Extraire le nom (avant le /) - name=$(echo "$line" | cut -d'/' -f1) - # Extraire la version disponible (2ème champ) - available=$(echo "$line" | awk '{print $2}') - # Extraire la version actuelle (après "upgradable from:") - current=$(echo "$line" | grep -oP 'upgradable from: \K[^\]]+' || echo "inconnue") - - if $INTERACTIVE; then - echo -e " ${CYAN}${name}${RESET} : ${YELLOW}${current}${RESET} → ${GREEN}${available}${RESET}" - fi - - # Construire JSON - entry="{\"name\":\"${name}\",\"current\":\"${current}\",\"available\":\"${available}\"}" - if [ $count -eq 0 ]; then - packages_json="${entry}" - else - packages_json="${packages_json},${entry}" - fi - count=$((count + 1)) - -done < <(apt list --upgradable 2>/dev/null) - -# Vérifier si reboot requis -reboot_required=false -if [ -f /var/run/reboot-required ]; then - reboot_required=true -fi - -if $INTERACTIVE; then - echo "" - echo -e "${BOLD}--- Bilan ---${RESET}" - if [ $count -eq 0 ]; then - echo -e "${GREEN}✅ Système à jour.${RESET}" - else - echo -e "${YELLOW}📦 ${count} paquet(s) à mettre à jour.${RESET}" - fi - if $reboot_required; then - echo -e "${RED}⚠️ Redémarrage requis.${RESET}" - fi -else - printf '{"count":%d,"reboot_required":%s,"packages":[%s]}\n' \ - "$count" "$reboot_required" "$packages_json" -fi diff --git a/nas-upgrade-system b/nas-upgrade-system deleted file mode 100644 index 38c08e1..0000000 --- a/nas-upgrade-system +++ /dev/null @@ -1,81 +0,0 @@ -#!/bin/bash -# nas-upgrade-system — Applique les mises à jour système (apt full-upgrade) -# Usage : nas-upgrade-system -# Mode HA (non-interactif) : applique directement, output JSON -# Mode terminal : affiche le bilan + confirmation avant d'appliquer - -set -euo pipefail - -if [ -t 1 ]; then INTERACTIVE=true; else INTERACTIVE=false; fi - -# Couleurs (mode terminal uniquement) -if $INTERACTIVE; then - RED='\033[0;31m' - GREEN='\033[0;32m' - YELLOW='\033[1;33m' - CYAN='\033[0;36m' - BOLD='\033[1m' - RESET='\033[0m' -else - RED='' GREEN='' YELLOW='' CYAN='' BOLD='' RESET='' -fi - -# S'assurer que la liste est à jour -if $INTERACTIVE; then - echo -e "${BOLD}--- Mise à jour de la liste des paquets ---${RESET}" -fi -apt-get update -qq 2>/dev/null - -# Récupérer les paquets upgradables -upgradable=$(apt list --upgradable 2>/dev/null | grep -v '^Listing' | grep -v '^$') -count=$(echo "$upgradable" | grep -c . || true) - -if [ "$count" -eq 0 ]; then - if $INTERACTIVE; then - echo -e "${GREEN}✅ Système déjà à jour, rien à faire.${RESET}" - else - printf '{"status":"already_up_to_date","upgraded":0,"reboot_required":false}\n' - fi - exit 0 -fi - -if $INTERACTIVE; then - echo "" - echo -e "${BOLD}--- Paquets à mettre à jour (${count}) ---${RESET}" - while IFS= read -r line; do - [[ -z "$line" ]] && continue - name=$(echo "$line" | cut -d'/' -f1) - available=$(echo "$line" | awk '{print $2}') - current=$(echo "$line" | grep -oP 'upgradable from: \K[^\]]+' || echo "inconnue") - echo -e " ${CYAN}${name}${RESET} : ${YELLOW}${current}${RESET} → ${GREEN}${available}${RESET}" - done <<< "$upgradable" - echo "" - - read -p "Appliquer la mise à jour de ces ${count} paquet(s) ? [y/n] : " confirm - case "$confirm" in - [yY]*) ;; - *) echo -e "${YELLOW}Annulé.${RESET}"; exit 0 ;; - esac - echo "" - echo -e "${BOLD}--- Application de apt full-upgrade ---${RESET}" -fi - -# Appliquer -DEBIAN_FRONTEND=noninteractive apt-get full-upgrade -y -o Dpkg::Options::="--force-confdef" -o Dpkg::Options::="--force-confold" 2>&1 - -# Vérifier reboot requis -reboot_required=false -if [ -f /var/run/reboot-required ]; then - reboot_required=true -fi - -if $INTERACTIVE; then - echo "" - echo -e "${GREEN}✅ Mise à jour terminée.${RESET}" - if $reboot_required; then - echo -e "${RED}⚠️ Redémarrage requis.${RESET}" - fi -else - printf '{"status":"upgraded","upgraded":%d,"reboot_required":%s}\n' \ - "$count" "$reboot_required" -fi