Add install.sh, HA config files, translate scripts to English, fix apt parsing
This commit is contained in:
+147
@@ -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 "<user> 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 `<user>` 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
|
||||||
|
```
|
||||||
@@ -1,30 +1,41 @@
|
|||||||
# nas-ops
|
# 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 :
|
Handles system updates (`apt`) and Docker updates (`docker compose`), with two modes:
|
||||||
- **Terminal interactif** : affichage coloré, confirmations
|
- **Interactive terminal**: colored output, confirmations
|
||||||
- **Non-interactif** (Home Assistant, cron) : output JSON
|
- **Non-interactive** (Home Assistant, cron): JSON output
|
||||||
|
|
||||||
## Installation
|
## Installation
|
||||||
|
|
||||||
```bash
|
```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 "<user> 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 `<user>` with the SSH user used in your Home Assistant config (e.g. the user in `/config/.ssh/config`).
|
||||||
|
|
||||||
## Scripts
|
## Scripts
|
||||||
|
|
||||||
### `nas-update`
|
### `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)
|
1. System analysis (apt)
|
||||||
2. Pull et détection des mises à jour Docker
|
2. Docker pull and update detection
|
||||||
3. Upgrade système (confirmation)
|
3. System upgrade (with confirmation)
|
||||||
4. Upgrade Docker (tout ou conteneur par conteneur)
|
4. Docker upgrade (all at once or container by container)
|
||||||
5. Nettoyage des images orphelines
|
5. Orphaned image cleanup
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
nas-update
|
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
|
- Terminal mode: colored output of upgradable packages
|
||||||
- Mode non-interactif (HA) : output JSON
|
- Non-interactive mode (HA): JSON output
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
nas-update-system
|
nas-system-update
|
||||||
```
|
```
|
||||||
|
|
||||||
```json
|
```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
|
- Terminal mode: shows summary + confirmation before applying
|
||||||
- Mode non-interactif (HA) : applique directement
|
- Non-interactive mode (HA): applies directly
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
nas-upgrade-system
|
nas-system-upgrade
|
||||||
```
|
```
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
### `nas-docker-pull`
|
### `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é
|
- Terminal mode: colored output
|
||||||
- Mode non-interactif (HA) : output JSON
|
- Non-interactive mode (HA): JSON output
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
nas-docker-pull
|
nas-docker-pull
|
||||||
```
|
```
|
||||||
|
|
||||||
```json
|
```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`
|
### `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
|
- No argument: offers to update all containers with a newer image
|
||||||
- Avec argument : cible une stack spécifique
|
- With argument: targets a specific stack
|
||||||
- Mode terminal : confirmation par stack ou tout d'un coup
|
- Terminal mode: confirmation per stack or all at once
|
||||||
- Mode non-interactif (HA) : applique directement
|
- Non-interactive mode (HA): applies directly
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
nas-docker-up # toutes les stacks
|
nas-docker-up # all stacks
|
||||||
nas-docker-up jellyfin # stack spécifique
|
nas-docker-up jellyfin # specific stack
|
||||||
```
|
```
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
### `nas-docker-prune`
|
### `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
|
```bash
|
||||||
nas-docker-prune
|
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
|
```yaml
|
||||||
shell_command:
|
shell_command: !include ha-shell-command.yaml
|
||||||
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'"
|
|
||||||
```
|
```
|
||||||
|
|
||||||
## 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_pull → detect available updates (idempotent)
|
||||||
nas_docker_up → applique les mises à jour
|
nas_docker_up → apply updates
|
||||||
nas_docker_prune → nettoie les anciennes images
|
nas_docker_prune → clean up old images
|
||||||
```
|
```
|
||||||
|
|||||||
@@ -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
|
||||||
@@ -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'"
|
||||||
+10
-8
@@ -1,17 +1,20 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
# install.sh — Install nas-ops scripts to /usr/local/bin
|
# 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
|
set -euo pipefail
|
||||||
|
|
||||||
|
# Redirect stdin from /dev/tty to avoid issues when piped from curl
|
||||||
|
exec < /dev/tty
|
||||||
|
|
||||||
REPO="GuiPoM/nas-ops"
|
REPO="GuiPoM/nas-ops"
|
||||||
BRANCH="main"
|
BRANCH="main"
|
||||||
BASE_URL="https://raw.githubusercontent.com/${REPO}/${BRANCH}"
|
BASE_URL="https://raw.githubusercontent.com/${REPO}/${BRANCH}"
|
||||||
INSTALL_DIR="/usr/local/bin"
|
INSTALL_DIR="/usr/local/bin"
|
||||||
|
|
||||||
SCRIPTS=(
|
SCRIPTS=(
|
||||||
"nas-update-system"
|
"nas-system-update"
|
||||||
"nas-upgrade-system"
|
"nas-system-upgrade"
|
||||||
"nas-docker-pull"
|
"nas-docker-pull"
|
||||||
"nas-docker-up"
|
"nas-docker-up"
|
||||||
"nas-docker-prune"
|
"nas-docker-prune"
|
||||||
@@ -39,8 +42,8 @@ fi
|
|||||||
|
|
||||||
# Check dependencies
|
# Check dependencies
|
||||||
echo -e "${CYAN}Checking dependencies...${RESET}"
|
echo -e "${CYAN}Checking dependencies...${RESET}"
|
||||||
for cmd in curl docker; do
|
for cmd in curl docker apt-get; do
|
||||||
if command -v "$cmd" > /dev/null 2>&1; then
|
if type "$cmd" > /dev/null 2>&1 || [ -x "/usr/bin/$cmd" ] || [ -x "/bin/$cmd" ]; then
|
||||||
echo -e " ${GREEN}✅ ${cmd}${RESET}"
|
echo -e " ${GREEN}✅ ${cmd}${RESET}"
|
||||||
else
|
else
|
||||||
echo -e " ${YELLOW}⚠ ${cmd} not found — some scripts may not work${RESET}"
|
echo -e " ${YELLOW}⚠ ${cmd} not found — some scripts may not work${RESET}"
|
||||||
@@ -51,12 +54,11 @@ echo ""
|
|||||||
# Download and install scripts
|
# Download and install scripts
|
||||||
echo -e "${CYAN}Installing scripts to ${INSTALL_DIR}...${RESET}"
|
echo -e "${CYAN}Installing scripts to ${INSTALL_DIR}...${RESET}"
|
||||||
for script in "${SCRIPTS[@]}"; do
|
for script in "${SCRIPTS[@]}"; do
|
||||||
echo -ne " Downloading ${script}... "
|
|
||||||
if curl -fsSL "${BASE_URL}/${script}" -o "${INSTALL_DIR}/${script}"; then
|
if curl -fsSL "${BASE_URL}/${script}" -o "${INSTALL_DIR}/${script}"; then
|
||||||
chmod +x "${INSTALL_DIR}/${script}"
|
chmod +x "${INSTALL_DIR}/${script}"
|
||||||
echo -e "${GREEN}✅${RESET}"
|
echo -e " ${GREEN}✅ ${script}${RESET}"
|
||||||
else
|
else
|
||||||
echo -e "${RED}❌ Failed${RESET}"
|
echo -e " ${RED}❌ ${script} — Failed${RESET}"
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
done
|
done
|
||||||
|
|||||||
+5
-5
@@ -1,7 +1,7 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
# nas-docker-prune — Nettoie les images Docker orphelines (dangling)
|
# nas-docker-prune — Remove orphaned (dangling) Docker images
|
||||||
# Usage : nas-docker-prune
|
# Usage: nas-docker-prune
|
||||||
# À appeler après nas-docker-up pour supprimer les anciennes images remplacées
|
# Call after nas-docker-up to clean up replaced images
|
||||||
|
|
||||||
set -euo pipefail
|
set -euo pipefail
|
||||||
|
|
||||||
@@ -12,11 +12,11 @@ if $INTERACTIVE; then
|
|||||||
GREEN='\033[0;32m'
|
GREEN='\033[0;32m'
|
||||||
BOLD='\033[1m'
|
BOLD='\033[1m'
|
||||||
RESET='\033[0m'
|
RESET='\033[0m'
|
||||||
echo -e "${CYAN}🧹 Nettoyage des images orphelines...${RESET}"
|
echo -e "${CYAN}🧹 Removing orphaned images...${RESET}"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
docker image prune -f
|
docker image prune -f
|
||||||
|
|
||||||
if $INTERACTIVE; then
|
if $INTERACTIVE; then
|
||||||
echo -e "${GREEN}✅ Nettoyage terminé.${RESET}"
|
echo -e "${GREEN}✅ Cleanup complete.${RESET}"
|
||||||
fi
|
fi
|
||||||
|
|||||||
+20
-19
@@ -1,15 +1,16 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
# nas-docker-pull — Pull les images Docker et détecte les mises à jour disponibles
|
# nas-docker-pull — Pull Docker images and detect available updates
|
||||||
# Usage : nas-docker-pull
|
# Usage: nas-docker-pull
|
||||||
# Output : JSON (mode non-interactif) ou texte coloré (mode terminal)
|
# Output: JSON (non-interactive mode) or colored text (terminal mode)
|
||||||
# Idempotent : tant que nas-docker-up n'a pas recréé les conteneurs,
|
# Idempotent: as long as nas-docker-up has not recreated the containers,
|
||||||
# le conteneur tourne sur l'ancien image ID → l'écart est toujours détecté
|
# 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
|
set -euo pipefail
|
||||||
|
|
||||||
if [ -t 1 ]; then INTERACTIVE=true; else INTERACTIVE=false; fi
|
if [ -t 1 ]; then INTERACTIVE=true; else INTERACTIVE=false; fi
|
||||||
|
|
||||||
# Couleurs (mode terminal uniquement)
|
# Colors (terminal mode only)
|
||||||
if $INTERACTIVE; then
|
if $INTERACTIVE; then
|
||||||
RED='\033[0;31m'
|
RED='\033[0;31m'
|
||||||
GREEN='\033[0;32m'
|
GREEN='\033[0;32m'
|
||||||
@@ -25,14 +26,14 @@ containers_json=""
|
|||||||
count=0
|
count=0
|
||||||
|
|
||||||
if $INTERACTIVE; then
|
if $INTERACTIVE; then
|
||||||
echo -e "${BOLD}--- Vérification des images Docker ---${RESET}"
|
echo -e "${BOLD}--- Checking Docker images ---${RESET}"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
while IFS=: read -r container_id container_name; do
|
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)
|
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
|
if [ -z "$compose_dir" ] || [ ! -d "$compose_dir" ]; then
|
||||||
continue
|
continue
|
||||||
fi
|
fi
|
||||||
@@ -40,14 +41,14 @@ while IFS=: read -r container_id container_name; do
|
|||||||
image_name=$(docker inspect --format='{{.Config.Image}}' "$container_id")
|
image_name=$(docker inspect --format='{{.Config.Image}}' "$container_id")
|
||||||
old_image_id=$(docker inspect --format='{{.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 "")
|
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
|
if $INTERACTIVE; then
|
||||||
echo -ne " Vérification de ${CYAN}${container_name}${RESET}... "
|
echo -ne " Checking ${CYAN}${container_name}${RESET}... "
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if ! docker pull "$image_name" > /dev/null 2>&1; then
|
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
|
continue
|
||||||
fi
|
fi
|
||||||
|
|
||||||
@@ -55,10 +56,10 @@ while IFS=: read -r container_id container_name; do
|
|||||||
|
|
||||||
if [ "$old_image_id" != "$new_image_id" ]; then
|
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 "")
|
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
|
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
|
fi
|
||||||
|
|
||||||
entry="{\"name\":\"${container_name}\",\"image\":\"${image_name}\",\"compose_dir\":\"${compose_dir}\",\"current\":\"${old_ver}\",\"available\":\"${new_ver}\"}"
|
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
|
fi
|
||||||
count=$((count + 1))
|
count=$((count + 1))
|
||||||
else
|
else
|
||||||
if $INTERACTIVE; then echo -e "${GREEN}✅ À jour${RESET}"; fi
|
if $INTERACTIVE; then echo -e "${GREEN}✅ Up to date${RESET}"; fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
done < <(docker ps --format "{{.ID}}:{{.Names}}")
|
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
|
printf '{"count":%d,"containers":[%s]}\n' "$count" "$containers_json" > /tmp/nas-docker-pull.json
|
||||||
|
|
||||||
if $INTERACTIVE; then
|
if $INTERACTIVE; then
|
||||||
echo ""
|
echo ""
|
||||||
echo -e "${BOLD}--- Bilan ---${RESET}"
|
echo -e "${BOLD}--- Summary ---${RESET}"
|
||||||
if [ $count -eq 0 ]; then
|
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
|
else
|
||||||
echo -e "${YELLOW}🐳 ${count} conteneur(s) à mettre à jour.${RESET}"
|
echo -e "${YELLOW}🐳 ${count} container(s) available for update.${RESET}"
|
||||||
fi
|
fi
|
||||||
else
|
else
|
||||||
cat /tmp/nas-docker-pull.json
|
cat /tmp/nas-docker-pull.json
|
||||||
|
|||||||
+38
-40
@@ -1,10 +1,10 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
# nas-docker-up — Applique les mises à jour Docker via docker compose up -d
|
# nas-docker-up — Apply Docker updates via docker compose up -d
|
||||||
# Usage : nas-docker-up [stack_name]
|
# Usage: nas-docker-up [stack_name]
|
||||||
# Sans argument : met à jour tous les conteneurs ayant une image plus récente
|
# No argument: updates all containers with a newer image available
|
||||||
# Avec argument : met à jour uniquement la stack spécifiée
|
# With argument: updates only the specified stack
|
||||||
# Mode HA (non-interactif) : applique directement, pas de prompt
|
# Non-interactive mode (HA): applies directly, no prompt
|
||||||
# Mode terminal : confirmation par stack (sauf si stack spécifiée en argument)
|
# Terminal mode: confirmation per stack (unless a specific stack is given)
|
||||||
|
|
||||||
set -euo pipefail
|
set -euo pipefail
|
||||||
|
|
||||||
@@ -12,7 +12,7 @@ if [ -t 1 ]; then INTERACTIVE=true; else INTERACTIVE=false; fi
|
|||||||
|
|
||||||
TARGET_STACK="${1:-}"
|
TARGET_STACK="${1:-}"
|
||||||
|
|
||||||
# Couleurs (mode terminal uniquement)
|
# Colors (terminal mode only)
|
||||||
if $INTERACTIVE; then
|
if $INTERACTIVE; then
|
||||||
RED='\033[0;31m'
|
RED='\033[0;31m'
|
||||||
GREEN='\033[0;32m'
|
GREEN='\033[0;32m'
|
||||||
@@ -24,7 +24,7 @@ else
|
|||||||
RED='' GREEN='' YELLOW='' CYAN='' BOLD='' RESET=''
|
RED='' GREEN='' YELLOW='' CYAN='' BOLD='' RESET=''
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# --- Détection de l'env global OMV ---
|
# --- Detect global OMV env file ---
|
||||||
OMV_GLOBAL_ENV=""
|
OMV_GLOBAL_ENV=""
|
||||||
if [ -f "/etc/omv-compose.env" ]; then
|
if [ -f "/etc/omv-compose.env" ]; then
|
||||||
OMV_GLOBAL_ENV="/etc/omv-compose.env"
|
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"
|
OMV_GLOBAL_ENV="/srv/omv-compose.env"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# --- Collecte des conteneurs à mettre à jour ---
|
# --- Collect containers to update ---
|
||||||
containers_to_update=()
|
containers_to_update=()
|
||||||
images_to_update=()
|
images_to_update=()
|
||||||
compose_dirs=()
|
compose_dirs=()
|
||||||
@@ -41,11 +41,11 @@ old_versions=()
|
|||||||
new_versions=()
|
new_versions=()
|
||||||
|
|
||||||
if $INTERACTIVE; then
|
if $INTERACTIVE; then
|
||||||
echo -e "${BOLD}--- Phase 1 : Recherche des mises à jour ---${RESET}"
|
echo -e "${BOLD}--- Phase 1: Detecting updates ---${RESET}"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
while IFS=: read -r container_id container_name; do
|
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
|
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)
|
stack_label=$(docker inspect --format='{{index .Config.Labels "com.docker.compose.project"}}' "$container_id" 2>/dev/null | xargs)
|
||||||
if [ "$stack_label" != "$TARGET_STACK" ]; then
|
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")
|
image_name=$(docker inspect --format='{{.Config.Image}}' "$container_id")
|
||||||
old_image_id=$(docker inspect --format='{{.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 "")
|
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
|
if $INTERACTIVE; then
|
||||||
echo -ne " Vérification de ${CYAN}${container_name}${RESET}... "
|
echo -ne " Checking ${CYAN}${container_name}${RESET}... "
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if ! docker pull "$image_name" > /dev/null 2>&1; then
|
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
|
continue
|
||||||
fi
|
fi
|
||||||
|
|
||||||
@@ -77,10 +77,10 @@ while IFS=: read -r container_id container_name; do
|
|||||||
|
|
||||||
if [ "$old_image_id" != "$new_image_id" ]; then
|
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 "")
|
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
|
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
|
fi
|
||||||
|
|
||||||
containers_to_update+=("$container_name")
|
containers_to_update+=("$container_name")
|
||||||
@@ -90,7 +90,7 @@ while IFS=: read -r container_id container_name; do
|
|||||||
old_versions+=("$old_ver")
|
old_versions+=("$old_ver")
|
||||||
new_versions+=("$new_ver")
|
new_versions+=("$new_ver")
|
||||||
else
|
else
|
||||||
if $INTERACTIVE; then echo -e "${GREEN}✅ À jour${RESET}"; fi
|
if $INTERACTIVE; then echo -e "${GREEN}✅ Up to date${RESET}"; fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
done < <(docker ps --format "{{.ID}}:{{.Names}}")
|
done < <(docker ps --format "{{.ID}}:{{.Names}}")
|
||||||
@@ -98,30 +98,28 @@ done < <(docker ps --format "{{.ID}}:{{.Names}}")
|
|||||||
if [ ${#containers_to_update[@]} -eq 0 ]; then
|
if [ ${#containers_to_update[@]} -eq 0 ]; then
|
||||||
if $INTERACTIVE; then
|
if $INTERACTIVE; then
|
||||||
echo ""
|
echo ""
|
||||||
echo -e "${GREEN}✅ Aucun conteneur à mettre à jour.${RESET}"
|
echo -e "${GREEN}✅ No containers to update.${RESET}"
|
||||||
echo -e "${CYAN}🧹 Nettoyage des images orphelines...${RESET}"
|
|
||||||
fi
|
fi
|
||||||
docker image prune -f > /dev/null
|
|
||||||
exit 0
|
exit 0
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if $INTERACTIVE; then
|
if $INTERACTIVE; then
|
||||||
echo ""
|
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
|
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
|
done
|
||||||
echo ""
|
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
|
if [ -z "$TARGET_STACK" ]; then
|
||||||
UPDATE_ALL=false
|
UPDATE_ALL=false
|
||||||
while true; do
|
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
|
case "$global_choice" in
|
||||||
[yY]*) UPDATE_ALL=true; break ;;
|
[yY]*) UPDATE_ALL=true; break ;;
|
||||||
[nN]*) UPDATE_ALL=false; break ;;
|
[nN]*) UPDATE_ALL=false; break ;;
|
||||||
*) echo "Veuillez répondre par y ou n." ;;
|
*) echo "Please answer y or n." ;;
|
||||||
esac
|
esac
|
||||||
done
|
done
|
||||||
else
|
else
|
||||||
@@ -129,10 +127,10 @@ if $INTERACTIVE; then
|
|||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# --- Phase 3 : Application ---
|
# --- Phase 3: Apply ---
|
||||||
if $INTERACTIVE; then
|
if $INTERACTIVE; then
|
||||||
echo ""
|
echo ""
|
||||||
echo -e "${BOLD}--- Phase 3 : Application des mises à jour ---${RESET}"
|
echo -e "${BOLD}--- Phase 3: Applying updates ---${RESET}"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
START_DIR=$(pwd)
|
START_DIR=$(pwd)
|
||||||
@@ -148,34 +146,34 @@ for i in "${!containers_to_update[@]}"; do
|
|||||||
DO_UPDATE=false
|
DO_UPDATE=false
|
||||||
|
|
||||||
if ! $INTERACTIVE; then
|
if ! $INTERACTIVE; then
|
||||||
# Mode HA : toujours appliquer
|
# HA mode: always apply
|
||||||
DO_UPDATE=true
|
DO_UPDATE=true
|
||||||
elif [ "$UPDATE_ALL" = true ]; then
|
elif [ "$UPDATE_ALL" = true ]; then
|
||||||
DO_UPDATE=true
|
DO_UPDATE=true
|
||||||
else
|
else
|
||||||
while true; do
|
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
|
case "$choice" in
|
||||||
[yY]*) DO_UPDATE=true; break ;;
|
[yY]*) DO_UPDATE=true; break ;;
|
||||||
[nN]*) DO_UPDATE=false; break ;;
|
[nN]*) DO_UPDATE=false; break ;;
|
||||||
*) echo "Veuillez répondre par y ou n." ;;
|
*) echo "Please answer y or n." ;;
|
||||||
esac
|
esac
|
||||||
done
|
done
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [ "$DO_UPDATE" = true ]; then
|
if [ "$DO_UPDATE" = true ]; then
|
||||||
if $INTERACTIVE; 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
|
fi
|
||||||
|
|
||||||
if cd "$c_dir" 2>/dev/null; then
|
if cd "$c_dir" 2>/dev/null; then
|
||||||
ENV_ARGS=""
|
ENV_ARGS=""
|
||||||
|
|
||||||
# Env global OMV
|
# Global OMV env
|
||||||
if [ -n "$OMV_GLOBAL_ENV" ] && [ -f "$OMV_GLOBAL_ENV" ]; then
|
if [ -n "$OMV_GLOBAL_ENV" ] && [ -f "$OMV_GLOBAL_ENV" ]; then
|
||||||
ENV_ARGS="--env-file $OMV_GLOBAL_ENV"
|
ENV_ARGS="--env-file $OMV_GLOBAL_ENV"
|
||||||
else
|
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")
|
PARENT_DIR=$(dirname "$c_dir")
|
||||||
if [ -f "$PARENT_DIR/global.env" ]; then
|
if [ -f "$PARENT_DIR/global.env" ]; then
|
||||||
ENV_ARGS="--env-file $PARENT_DIR/global.env"
|
ENV_ARGS="--env-file $PARENT_DIR/global.env"
|
||||||
@@ -184,31 +182,31 @@ for i in "${!containers_to_update[@]}"; do
|
|||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# .env local (toujours ajouté s'il existe)
|
# Local .env (always added if present)
|
||||||
if [ -f ".env" ]; then
|
if [ -f ".env" ]; then
|
||||||
ENV_ARGS="$ENV_ARGS --env-file .env"
|
ENV_ARGS="$ENV_ARGS --env-file .env"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if docker compose $ENV_ARGS up -d --remove-orphans 2>&1; then
|
if docker compose $ENV_ARGS up -d --remove-orphans 2>&1; then
|
||||||
if $INTERACTIVE; then
|
if $INTERACTIVE; then
|
||||||
echo -e " ${GREEN}✅ ${c_name} mis à jour avec succès.${RESET}"
|
echo -e " ${GREEN}✅ ${c_name} updated successfully.${RESET}"
|
||||||
fi
|
fi
|
||||||
upgraded=$((upgraded + 1))
|
upgraded=$((upgraded + 1))
|
||||||
else
|
else
|
||||||
if $INTERACTIVE; then
|
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
|
fi
|
||||||
failed=$((failed + 1))
|
failed=$((failed + 1))
|
||||||
fi
|
fi
|
||||||
else
|
else
|
||||||
if $INTERACTIVE; then
|
if $INTERACTIVE; then
|
||||||
echo -e " ${RED}❌ Impossible d'accéder à ${c_dir}.${RESET}"
|
echo -e " ${RED}❌ Cannot access ${c_dir}.${RESET}"
|
||||||
fi
|
fi
|
||||||
failed=$((failed + 1))
|
failed=$((failed + 1))
|
||||||
fi
|
fi
|
||||||
else
|
else
|
||||||
if $INTERACTIVE; then
|
if $INTERACTIVE; then
|
||||||
echo -e " ⏭ Mise à jour ignorée pour ${c_name}."
|
echo -e " ⏭ Skipped: ${c_name}"
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
@@ -217,8 +215,8 @@ done
|
|||||||
|
|
||||||
if $INTERACTIVE; then
|
if $INTERACTIVE; then
|
||||||
echo ""
|
echo ""
|
||||||
echo -e "${BOLD}--- Terminé ---${RESET}"
|
echo -e "${BOLD}--- Done ---${RESET}"
|
||||||
echo -e " ${GREEN}✅ ${upgraded} mis à jour${RESET} ${RED}❌ ${failed} en échec${RESET}"
|
echo -e " ${GREEN}✅ ${upgraded} updated${RESET} ${RED}❌ ${failed} failed${RESET}"
|
||||||
else
|
else
|
||||||
printf '{"upgraded":%d,"failed":%d}\n' "$upgraded" "$failed"
|
printf '{"upgraded":%d,"failed":%d}\n' "$upgraded" "$failed"
|
||||||
fi
|
fi
|
||||||
|
|||||||
@@ -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
|
|
||||||
@@ -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
|
||||||
@@ -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
|
||||||
+39
-39
@@ -1,11 +1,11 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
# nas-update — Script racine de gestion des mises à jour NAS
|
# nas-update — NAS update manager (interactive root script)
|
||||||
# Orchestre nas-update-system, nas-upgrade-system, nas-docker-pull, nas-docker-up, nas-docker-prune
|
# Orchestrates nas-system-update, nas-system-upgrade, nas-docker-pull, nas-docker-up, nas-docker-prune
|
||||||
# Usage : nas-update
|
# Usage: nas-update
|
||||||
|
|
||||||
set -euo pipefail
|
set -euo pipefail
|
||||||
|
|
||||||
# Couleurs
|
# Colors
|
||||||
RED='\033[0;31m'
|
RED='\033[0;31m'
|
||||||
GREEN='\033[0;32m'
|
GREEN='\033[0;32m'
|
||||||
YELLOW='\033[1;33m'
|
YELLOW='\033[1;33m'
|
||||||
@@ -14,25 +14,25 @@ BOLD='\033[1m'
|
|||||||
RESET='\033[0m'
|
RESET='\033[0m'
|
||||||
|
|
||||||
echo -e "${BOLD}=====================================================${RESET}"
|
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 -e "${BOLD}=====================================================${RESET}"
|
||||||
echo ""
|
echo ""
|
||||||
|
|
||||||
# ─────────────────────────────────────────────────────
|
# ─────────────────────────────────────────────────────
|
||||||
# Phase 1 : Analyse système
|
# Phase 1: System analysis
|
||||||
# ─────────────────────────────────────────────────────
|
# ─────────────────────────────────────────────────────
|
||||||
echo -e "${BOLD}--- Phase 1 : Analyse système (apt) ---${RESET}"
|
echo -e "${BOLD}--- Phase 1: System analysis (apt) ---${RESET}"
|
||||||
nas-update-system
|
nas-system-update
|
||||||
echo ""
|
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
|
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":[]}')
|
docker_json=$(cat /tmp/nas-docker-pull.json 2>/dev/null || echo '{"count":0,"containers":[]}')
|
||||||
|
|
||||||
containers_to_update=()
|
containers_to_update=()
|
||||||
@@ -55,68 +55,68 @@ done < <(echo "$docker_json" | grep -o '{[^}]*}')
|
|||||||
echo ""
|
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
|
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
|
case "$sys_choice" in
|
||||||
[yY]*)
|
[yY]*)
|
||||||
nas-upgrade-system
|
nas-system-upgrade
|
||||||
break
|
break
|
||||||
;;
|
;;
|
||||||
[nN]*)
|
[nN]*)
|
||||||
echo -e "${YELLOW}⏭ Mise à jour système ignorée.${RESET}"
|
echo -e "${YELLOW}⏭ System upgrade skipped.${RESET}"
|
||||||
break
|
break
|
||||||
;;
|
;;
|
||||||
*) echo "Veuillez répondre par y ou n." ;;
|
*) echo "Please answer y or n." ;;
|
||||||
esac
|
esac
|
||||||
done
|
done
|
||||||
|
|
||||||
echo ""
|
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
|
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 ""
|
||||||
echo -e "${BOLD}=====================================================${RESET}"
|
echo -e "${BOLD}=====================================================${RESET}"
|
||||||
echo -e "${GREEN} Terminé ! ${RESET}"
|
echo -e "${GREEN} Done! ${RESET}"
|
||||||
echo -e "${BOLD}=====================================================${RESET}"
|
echo -e "${BOLD}=====================================================${RESET}"
|
||||||
exit 0
|
exit 0
|
||||||
fi
|
fi
|
||||||
|
|
||||||
echo ""
|
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
|
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
|
done
|
||||||
echo ""
|
echo ""
|
||||||
|
|
||||||
UPDATE_ALL=false
|
UPDATE_ALL=false
|
||||||
while true; do
|
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
|
case "$docker_choice" in
|
||||||
[yY]*) UPDATE_ALL=true; break ;;
|
[yY]*) UPDATE_ALL=true; break ;;
|
||||||
[nN]*) UPDATE_ALL=false; break ;;
|
[nN]*) UPDATE_ALL=false; break ;;
|
||||||
[sS]*) echo -e "${YELLOW}⏭ Mise à jour Docker ignorée.${RESET}"; break ;;
|
[sS]*) echo -e "${YELLOW}⏭ Docker upgrade skipped.${RESET}"; break ;;
|
||||||
*) echo "Veuillez répondre par y, n ou s." ;;
|
*) echo "Please answer y, n or s." ;;
|
||||||
esac
|
esac
|
||||||
done
|
done
|
||||||
|
|
||||||
if [[ "$docker_choice" =~ ^[sS] ]]; then
|
if [[ "$docker_choice" =~ ^[sS] ]]; then
|
||||||
echo ""
|
echo ""
|
||||||
echo -e "${BOLD}=====================================================${RESET}"
|
echo -e "${BOLD}=====================================================${RESET}"
|
||||||
echo -e "${GREEN} Terminé ! ${RESET}"
|
echo -e "${GREEN} Done! ${RESET}"
|
||||||
echo -e "${BOLD}=====================================================${RESET}"
|
echo -e "${BOLD}=====================================================${RESET}"
|
||||||
exit 0
|
exit 0
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Détection de l'env global OMV
|
# Detect global OMV env file
|
||||||
OMV_GLOBAL_ENV=""
|
OMV_GLOBAL_ENV=""
|
||||||
if [ -f "/etc/omv-compose.env" ]; then
|
if [ -f "/etc/omv-compose.env" ]; then
|
||||||
OMV_GLOBAL_ENV="/etc/omv-compose.env"
|
OMV_GLOBAL_ENV="/etc/omv-compose.env"
|
||||||
@@ -140,17 +140,17 @@ for i in "${!containers_to_update[@]}"; do
|
|||||||
DO_UPDATE=true
|
DO_UPDATE=true
|
||||||
else
|
else
|
||||||
while true; do
|
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
|
case "$choice" in
|
||||||
[yY]*) DO_UPDATE=true; break ;;
|
[yY]*) DO_UPDATE=true; break ;;
|
||||||
[nN]*) DO_UPDATE=false; break ;;
|
[nN]*) DO_UPDATE=false; break ;;
|
||||||
*) echo "Veuillez répondre par y ou n." ;;
|
*) echo "Please answer y or n." ;;
|
||||||
esac
|
esac
|
||||||
done
|
done
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [ "$DO_UPDATE" = true ]; then
|
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
|
if cd "$c_dir" 2>/dev/null; then
|
||||||
ENV_ARGS=""
|
ENV_ARGS=""
|
||||||
@@ -171,32 +171,32 @@ for i in "${!containers_to_update[@]}"; do
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
if docker compose $ENV_ARGS up -d --remove-orphans 2>&1; then
|
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))
|
upgraded=$((upgraded + 1))
|
||||||
else
|
else
|
||||||
echo -e " ${RED}❌ Échec pour ${c_name}.${RESET}"
|
echo -e " ${RED}❌ Update failed for ${c_name}.${RESET}"
|
||||||
failed=$((failed + 1))
|
failed=$((failed + 1))
|
||||||
fi
|
fi
|
||||||
else
|
else
|
||||||
echo -e " ${RED}❌ Impossible d'accéder à ${c_dir}.${RESET}"
|
echo -e " ${RED}❌ Cannot access ${c_dir}.${RESET}"
|
||||||
failed=$((failed + 1))
|
failed=$((failed + 1))
|
||||||
fi
|
fi
|
||||||
else
|
else
|
||||||
echo -e " ⏭ Ignoré : ${c_name}"
|
echo -e " ⏭ Skipped: ${c_name}"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
cd "$START_DIR"
|
cd "$START_DIR"
|
||||||
done
|
done
|
||||||
|
|
||||||
# ─────────────────────────────────────────────────────
|
# ─────────────────────────────────────────────────────
|
||||||
# Phase 5 : Nettoyage des images orphelines
|
# Phase 5: Cleanup
|
||||||
# ─────────────────────────────────────────────────────
|
# ─────────────────────────────────────────────────────
|
||||||
echo ""
|
echo ""
|
||||||
echo -e "${BOLD}--- Phase 5 : Nettoyage ---${RESET}"
|
echo -e "${BOLD}--- Phase 5: Cleanup ---${RESET}"
|
||||||
nas-docker-prune
|
nas-docker-prune
|
||||||
|
|
||||||
echo ""
|
echo ""
|
||||||
echo -e "${BOLD}=====================================================${RESET}"
|
echo -e "${BOLD}=====================================================${RESET}"
|
||||||
echo -e "${BOLD} Terminé ! ${RESET}"
|
echo -e "${BOLD} Done! ${RESET}"
|
||||||
echo -e " Docker : ${GREEN}✅ ${upgraded} mis à jour${RESET} ${RED}❌ ${failed} en échec${RESET}"
|
echo -e " Docker: ${GREEN}✅ ${upgraded} updated${RESET} ${RED}❌ ${failed} failed${RESET}"
|
||||||
echo -e "${BOLD}=====================================================${RESET}"
|
echo -e "${BOLD}=====================================================${RESET}"
|
||||||
|
|||||||
@@ -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
|
|
||||||
@@ -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
|
|
||||||
Reference in New Issue
Block a user