feat(install): --update-in-place, actualización sin privilegios y reversible
Hay entornos donde no se usa root en absoluto, así que ni `sudo -n` ni una cuenta root son opciones. Este modo actualiza una instalación existente dejando su unit de systemd intacto, que es lo único que una actualización necesita de verdad: reemplazar el binario y reiniciar el proceso. Se apoya en dos hechos, uno de ellos contrario a lo que decía el propio repo: - `install` NO sufre ETXTBSY. A diferencia de `cp` —que abre con O_TRUNC—, desvincula el destino antes de crearlo, y por eso `make install` funciona sobre binarios en ejecución. Comprobado: `cp` sobre un ELF corriendo da "Text file busy" y `install` no. La consecuencia es la que importa: reemplazar el binario exige escritura en el DIRECTORIO, no en el archivo. El comentario de install.sh, BUILD.md y el CHANGELOG afirmaban lo contrario y mandaban al operador a diagnosticar un archivo en uso cuando lo que tenía era un EACCES. - El unit corre como el usuario que instaló (cadena SUDO_USER) y trae Restart=always, así que esa cuenta puede señalizar el proceso y systemd lo relevanta con el binario nuevo. No hace falta systemctl ni tocar /etc. Robustez, que es donde estaba el trabajo real: - **Reversible.** Respalda el binario antes de reemplazarlo y, si el nuevo no arranca, lo restaura y confirma que el proceso volvió. Sin esto, una actualización fallida deja el servidor sin agente. Si tampoco puede revertir, conserva el respaldo y lo dice en vez de fingir éxito. - **No interrumpe restauraciones.** El agente no atiende SIGTERM: matarlo a media restauración deja ese respaldo vetado para siempre (has_blocking_job_by_hash) y puede dejar la base en SINGLE_USER. Se comprueba Temp/ dos veces —antes de copiar y otra vez justo antes de señalizar, para cerrar la ventana— y sale con 75 (EX_TEMPFAIL), que el panel traduce a "reintenta luego" y no a un fallo. - **Diagnostica por qué no volvió**: distingue un unit sin Restart=always de un StartLimitBurst agotado, con el comando de recuperación. - Omite el bootstrap de 20 s: es redundante en una actualización (ensure_runtime_layout corre en cada arranque) y una segunda instancia junto a la viva purgaría el Temp de la que está trabajando. Un bug que solo aparecía fuera del camino feliz: con `set -euo pipefail`, un `$(pgrep ... | head -1)` sin resultados hace fallar la sustitución y `set -e` mataba el script en silencio — justo en el caso "el proceso no volvió", que es el que había que manejar. Por eso el rollback no se ejecutaba nunca.
This commit is contained in:
22
BUILD.md
22
BUILD.md
@@ -154,14 +154,32 @@ credenciales. Lo de abajo es el camino manual y lo que el PANEL ejecuta por dent
|
|||||||
tar xzf CloudRestoreAS-<version>-linux-x86_64.tar.gz && cd CloudRestoreAS
|
tar xzf CloudRestoreAS-<version>-linux-x86_64.tar.gz && cd CloudRestoreAS
|
||||||
|
|
||||||
sudo ./install.sh --service # servicio systemd 24/7 headless (recomendado en servidor)
|
sudo ./install.sh --service # servicio systemd 24/7 headless (recomendado en servidor)
|
||||||
|
./install.sh --user-service # 24/7 SIN privilegios: unit de systemd de usuario
|
||||||
|
./install.sh --update-in-place # actualiza una instalación existente SIN privilegios
|
||||||
./install.sh --desktop # autostart .desktop (requiere sesión gráfica)
|
./install.sh --desktop # autostart .desktop (requiere sesión gráfica)
|
||||||
./install.sh # solo instala + bootstrap; lo corres a mano
|
./install.sh # solo instala + bootstrap; lo corres a mano
|
||||||
./install.sh --help
|
./install.sh --help
|
||||||
```
|
```
|
||||||
Variables: `PREFIX=/opt/cloudrestoreas` (destino), `SERVICE_USER=<usuario>` (usuario del servicio).
|
Variables: `PREFIX=/opt/cloudrestoreas` (destino), `SERVICE_USER=<usuario>` (usuario del servicio).
|
||||||
|
|
||||||
Detiene el servicio antes de reemplazar el binario (un ELF en ejecución da `ETXTBSY`) y lo
|
Detiene el servicio antes de reemplazar el binario en los modos de servicio, para que el apagado
|
||||||
vuelve a levantar si estaba activo.
|
sea ordenado. **No** porque la copia lo exija: `install` desvincula el destino antes de crearlo —a
|
||||||
|
diferencia de `cp`, que abre con `O_TRUNC` y sí da `ETXTBSY`—, y por eso `make install` funciona
|
||||||
|
sobre binarios en ejecución. Comprobado. Lo que hace falta para reemplazar el binario es permiso de
|
||||||
|
escritura en el **directorio**, no en el archivo. (Esta nota decía lo contrario y mandó a más de
|
||||||
|
uno por la pista equivocada al diagnosticar un `EACCES`.)
|
||||||
|
|
||||||
|
### Sin privilegios
|
||||||
|
|
||||||
|
`--user-service` instala bajo el home con un unit de systemd **de usuario** (lingering, y si el
|
||||||
|
destino no lo permite, `@reboot` en el crontab del usuario más un vigilante). Sirve para
|
||||||
|
instalaciones nuevas donde nunca vas a tener root.
|
||||||
|
|
||||||
|
`--update-in-place` actualiza una instalación **que ya existe**, dejando su unit intacto: solo
|
||||||
|
reemplaza el binario y señaliza al proceso para que `Restart=always` lo relevante. Exige que el
|
||||||
|
directorio sea escribible por la cuenta, que el unit corra con ese mismo usuario y que tenga
|
||||||
|
`Restart=always`. Se niega si hay una restauración en curso (sale con **75**, `EX_TEMPFAIL`) y
|
||||||
|
**revierte al binario anterior** si el nuevo no arranca.
|
||||||
|
|
||||||
Servicio systemd:
|
Servicio systemd:
|
||||||
```bash
|
```bash
|
||||||
|
|||||||
@@ -31,8 +31,9 @@
|
|||||||
claves `CLOUDRESTORE_PANEL_*` en `config/.env` (replace-or-append, idempotente, con lista
|
claves `CLOUDRESTORE_PANEL_*` en `config/.env` (replace-or-append, idempotente, con lista
|
||||||
blanca) y borran el archivo. El token viaja por archivo 0600, nunca por argumentos, para
|
blanca) y borran el archivo. El token viaja por archivo 0600, nunca por argumentos, para
|
||||||
que no quede visible en `ps` ni en el historial del destino.
|
que no quede visible en `ps` ni en el historial del destino.
|
||||||
- `install.sh` detiene el servicio antes de reemplazar el binario (un ELF en ejecución da
|
- `install.sh` detiene el servicio antes de reemplazar el binario y lo vuelve a levantar si
|
||||||
`ETXTBSY`) y lo vuelve a levantar si estaba activo.
|
estaba activo. (La razón que se dio aquí —que un ELF en ejecución da `ETXTBSY`— era incorrecta:
|
||||||
|
eso le pasa a `cp`, no a `install`, que desvincula el destino antes de crearlo. Ver BUILD.md.)
|
||||||
|
|
||||||
#### Versionado
|
#### Versionado
|
||||||
- `app/__init__.py` es la fuente única de la versión; el diálogo *Acerca de* ya no la trae
|
- `app/__init__.py` es la fuente única de la versión; el diálogo *Acerca de* ya no la trae
|
||||||
|
|||||||
141
install.sh
141
install.sh
@@ -10,9 +10,17 @@
|
|||||||
# Uso:
|
# Uso:
|
||||||
# sudo ./install.sh --service # 24/7 headless vía systemd (recomendado en servidor)
|
# sudo ./install.sh --service # 24/7 headless vía systemd (recomendado en servidor)
|
||||||
# ./install.sh --user-service # 24/7 headless SIN root: unit de systemd de usuario
|
# ./install.sh --user-service # 24/7 headless SIN root: unit de systemd de usuario
|
||||||
|
# ./install.sh --update-in-place # actualiza en su sitio, SIN privilegios
|
||||||
# ./install.sh --desktop # autostart de escritorio (requiere sesión gráfica)
|
# ./install.sh --desktop # autostart de escritorio (requiere sesión gráfica)
|
||||||
# ./install.sh # solo instala; sin arranque automático
|
# ./install.sh # solo instala; sin arranque automático
|
||||||
#
|
#
|
||||||
|
# --update-in-place actualiza una instalación EXISTENTE sin privilegios, dejando el unit de
|
||||||
|
# systemd como está. Se apoya en dos hechos: `install` desvincula el destino antes de crearlo (a
|
||||||
|
# diferencia de `cp`, que da ETXTBSY), así que reemplazar el binario solo exige escritura en el
|
||||||
|
# DIRECTORIO; y el unit trae Restart=always, así que basta señalizar al proceso —desde la cuenta
|
||||||
|
# que lo corre— para que systemd lo relevante con el binario nuevo. No toca /etc ni systemctl.
|
||||||
|
# Se niega a actuar si hay una restauración en curso.
|
||||||
|
#
|
||||||
# --user-service no necesita privilegios: instala donde apunte PREFIX (que debe ser escribible
|
# --user-service no necesita privilegios: instala donde apunte PREFIX (que debe ser escribible
|
||||||
# por el usuario, típicamente bajo su home), registra el unit en ~/.config/systemd/user/ y lo
|
# por el usuario, típicamente bajo su home), registra el unit en ~/.config/systemd/user/ y lo
|
||||||
# arranca con `systemctl --user`. Para que sobreviva al cierre de sesión intenta habilitar
|
# arranca con `systemctl --user`. Para que sobreviva al cierre de sesión intenta habilitar
|
||||||
@@ -38,6 +46,7 @@ while [[ $# -gt 0 ]]; do
|
|||||||
case "$1" in
|
case "$1" in
|
||||||
--service) MODE="service"; shift ;;
|
--service) MODE="service"; shift ;;
|
||||||
--user-service) MODE="user-service"; shift ;;
|
--user-service) MODE="user-service"; shift ;;
|
||||||
|
--update-in-place) MODE="update-in-place"; shift ;;
|
||||||
--desktop) MODE="desktop"; shift ;;
|
--desktop) MODE="desktop"; shift ;;
|
||||||
--panel-env-file)
|
--panel-env-file)
|
||||||
[[ $# -ge 2 ]] || { echo "ERROR: --panel-env-file requiere una ruta" >&2; exit 2; }
|
[[ $# -ge 2 ]] || { echo "ERROR: --panel-env-file requiere una ruta" >&2; exit 2; }
|
||||||
@@ -80,15 +89,22 @@ echo " Modo : $MODE"
|
|||||||
echo "==============================================="
|
echo "==============================================="
|
||||||
|
|
||||||
# --- Detener el servicio si está corriendo ------------------------------------
|
# --- Detener el servicio si está corriendo ------------------------------------
|
||||||
# Un ELF en ejecución no se puede sobrescribir (ETXTBSY), así que una actualización
|
# Ojo con la razón, que estuvo mal escrita mucho tiempo: `install` NO sufre ETXTBSY. A
|
||||||
# tiene que detenerlo antes de reemplazar el binario. Se recuerda si estaba activo
|
# diferencia de `cp` —que abre con O_TRUNC—, `install` desvincula el destino antes de crearlo
|
||||||
# para volver a levantarlo al final incluso en los modos que no tocan systemd.
|
# (coreutils fija unlink_dest_before_opening), que es justo por lo que `make install` funciona
|
||||||
|
# sobre binarios en ejecución. Comprobado: `cp` sobre un ELF corriendo da "Text file busy" y
|
||||||
|
# `install` no. Lo que hace falta para reemplazarlo es permiso de escritura en el DIRECTORIO.
|
||||||
|
#
|
||||||
|
# Se detiene igual en los modos de servicio porque conviene un apagado ordenado, no porque la
|
||||||
|
# copia lo exija. Se recuerda si estaba activo para volver a levantarlo al final.
|
||||||
WAS_ACTIVE=0
|
WAS_ACTIVE=0
|
||||||
# En modo usuario el unit vive en la instancia de systemd del propio usuario, que necesita
|
# En modo usuario el unit vive en la instancia de systemd del propio usuario, que necesita
|
||||||
# XDG_RUNTIME_DIR: un `exec` de SSH no es una sesión de login y no siempre lo trae.
|
# XDG_RUNTIME_DIR: un `exec` de SSH no es una sesión de login y no siempre lo trae.
|
||||||
export XDG_RUNTIME_DIR="${XDG_RUNTIME_DIR:-/run/user/$(id -u)}"
|
export XDG_RUNTIME_DIR="${XDG_RUNTIME_DIR:-/run/user/$(id -u)}"
|
||||||
SYSTEMCTL_USER=(systemctl --user)
|
SYSTEMCTL_USER=(systemctl --user)
|
||||||
if command -v systemctl >/dev/null 2>&1; then
|
# En modo en-sitio NO se detiene nada: `install` reemplaza el binario con el proceso corriendo, y
|
||||||
|
# matarlo antes de tener el binario nuevo abriría una ventana en la que systemd relevanta el VIEJO.
|
||||||
|
if [[ "$MODE" != "update-in-place" ]] && command -v systemctl >/dev/null 2>&1; then
|
||||||
if [[ "$MODE" == "user-service" ]]; then
|
if [[ "$MODE" == "user-service" ]]; then
|
||||||
if "${SYSTEMCTL_USER[@]}" is-active --quiet "$UNIT_NAME" 2>/dev/null; then
|
if "${SYSTEMCTL_USER[@]}" is-active --quiet "$UNIT_NAME" 2>/dev/null; then
|
||||||
WAS_ACTIVE=1
|
WAS_ACTIVE=1
|
||||||
@@ -112,11 +128,40 @@ if command -v systemctl >/dev/null 2>&1; then
|
|||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
# Una restauración en curso no se interrumpe. El agente no atiende SIGTERM, así que matarlo a
|
||||||
|
# media restauración deja el job atascado —ese ZIP queda vetado en cada escaneo posterior— y puede
|
||||||
|
# dejar la base en SINGLE_USER. Cualquier subcarpeta de Temp/ es un job en vuelo.
|
||||||
|
# Código 75 (EX_TEMPFAIL) y no 1: le dice al panel "reintenta luego", no "falló la instalación".
|
||||||
|
if [[ "$MODE" == "update-in-place" ]] && [[ -d "$PREFIX/Temp" ]]; then
|
||||||
|
if [[ -n "$(ls -A "$PREFIX/Temp" 2>/dev/null)" ]]; then
|
||||||
|
echo "ERROR: hay una restauración en curso ($PREFIX/Temp no está vacío)." >&2
|
||||||
|
echo " No se actualiza para no dejarla a medias. Reintenta cuando termine." >&2
|
||||||
|
exit 75
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Respaldo para poder volver atrás. Una actualización en sitio reemplaza el binario de un
|
||||||
|
# servidor en producción sin red de seguridad: si el nuevo no arranca, sin esto el servidor queda
|
||||||
|
# sin agente y sin forma de recuperarlo salvo entrando a mano.
|
||||||
|
BACKUP=""
|
||||||
|
if [[ "$MODE" == "update-in-place" && -f "$PREFIX/$BIN_NAME" ]]; then
|
||||||
|
BACKUP="$PREFIX/.$BIN_NAME.prev"
|
||||||
|
if ! cp -p "$PREFIX/$BIN_NAME" "$BACKUP"; then
|
||||||
|
echo "ERROR: no se pudo respaldar el binario actual en $BACKUP" >&2
|
||||||
|
echo " Se aborta: actualizar sin poder revertir no es aceptable." >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
echo "Respaldo del binario actual en $BACKUP"
|
||||||
|
fi
|
||||||
|
|
||||||
mkdir -p "$PREFIX"
|
mkdir -p "$PREFIX"
|
||||||
if ! install -m 0755 "$SRC" "$PREFIX/$BIN_NAME"; then
|
if ! install -m 0755 "$SRC" "$PREFIX/$BIN_NAME"; then
|
||||||
echo "ERROR: no se pudo instalar el binario en $PREFIX/$BIN_NAME" >&2
|
echo "ERROR: no se pudo instalar el binario en $PREFIX/$BIN_NAME" >&2
|
||||||
echo " Si el archivo está en uso, detén el proceso y reintenta:" >&2
|
# `install` desvincula el destino antes de crearlo, así que un binario EN USO no es el
|
||||||
echo " sudo systemctl stop $UNIT_NAME # o mata el proceso de escritorio" >&2
|
# problema (eso es cosa de `cp`). Lo que falta casi siempre es permiso en el DIRECTORIO.
|
||||||
|
echo " Se necesita permiso de escritura en el directorio $PREFIX." >&2
|
||||||
|
echo " Dueño actual: $(stat -c '%U:%G %a' "$PREFIX" 2>/dev/null || echo 'desconocido')" >&2
|
||||||
|
echo " Usuario actual: $(id -un)" >&2
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
echo "Binario instalado en $PREFIX/$BIN_NAME"
|
echo "Binario instalado en $PREFIX/$BIN_NAME"
|
||||||
@@ -125,11 +170,16 @@ echo "Binario instalado en $PREFIX/$BIN_NAME"
|
|||||||
# al inicio de su arranque. Se corre una vez en modo offscreen (sin display) y se
|
# al inicio de su arranque. Se corre una vez en modo offscreen (sin display) y se
|
||||||
# corta con timeout; así el usuario ya puede editar config/.env antes de habilitar
|
# corta con timeout; así el usuario ya puede editar config/.env antes de habilitar
|
||||||
# el servicio.
|
# el servicio.
|
||||||
|
# En una actualización en sitio se OMITE: el binario hace ensure_runtime_layout() en cada arranque,
|
||||||
|
# así que es redundante, y correr una segunda instancia junto a la viva es peligroso —al arrancar,
|
||||||
|
# el motor purga todas las subcarpetas de Temp, que son de la instancia en curso—.
|
||||||
|
if [[ "$MODE" != "update-in-place" ]]; then
|
||||||
echo "Inicializando config/ (bootstrap)..."
|
echo "Inicializando config/ (bootstrap)..."
|
||||||
# `</dev/null` no es cosmético: es el único hijo que heredaría el stdin del canal SSH cuando el
|
# `</dev/null` no es cosmético: es el único hijo que heredaría el stdin del canal SSH cuando el
|
||||||
# instalador corre en remoto. Cerrárselo hace estructural —y no accidental— que nada de lo que
|
# instalador corre en remoto. Cerrárselo hace estructural —y no accidental— que nada de lo que
|
||||||
# venga por ese canal pueda ser consumido aquí.
|
# venga por ese canal pueda ser consumido aquí.
|
||||||
( cd "$PREFIX" && QT_QPA_PLATFORM=offscreen timeout 20 "$PREFIX/$BIN_NAME" --headless </dev/null >/dev/null 2>&1 || true )
|
( cd "$PREFIX" && QT_QPA_PLATFORM=offscreen timeout 20 "$PREFIX/$BIN_NAME" --headless </dev/null >/dev/null 2>&1 || true )
|
||||||
|
fi
|
||||||
if [[ -f "$PREFIX/config/.env" ]]; then
|
if [[ -f "$PREFIX/config/.env" ]]; then
|
||||||
echo "config/.env creado."
|
echo "config/.env creado."
|
||||||
else
|
else
|
||||||
@@ -299,6 +349,82 @@ case "$MODE" in
|
|||||||
echo " Estado : systemctl --user status cloudrestoreas"
|
echo " Estado : systemctl --user status cloudrestoreas"
|
||||||
echo " Logs : journalctl --user -u cloudrestoreas -f"
|
echo " Logs : journalctl --user -u cloudrestoreas -f"
|
||||||
;;
|
;;
|
||||||
|
update-in-place)
|
||||||
|
# El unit ya está registrado y no cambia: no se toca /etc, ni daemon-reload, ni enable.
|
||||||
|
# El binario nuevo ya está en su sitio; falta que el proceso lo tome.
|
||||||
|
if ! pgrep -f "$PGREP_PAT" >/dev/null 2>&1; then
|
||||||
|
echo "El agente no estaba corriendo; queda actualizado y systemd lo levantará."
|
||||||
|
else
|
||||||
|
# Segundo chequeo, inmediatamente antes de señalizar. El primero fue antes de copiar el
|
||||||
|
# binario y de sembrar el .env; en esos segundos pudo entrar una restauración, y matarla
|
||||||
|
# deja el respaldo vetado para siempre. Aquí ya no hay 270 MB de por medio: es barato.
|
||||||
|
if [[ -d "$PREFIX/Temp" ]] && [[ -n "$(ls -A "$PREFIX/Temp" 2>/dev/null)" ]]; then
|
||||||
|
echo "ERROR: entró una restauración mientras se actualizaba." >&2
|
||||||
|
echo " El binario nuevo YA está instalado y se activará en el próximo reinicio" >&2
|
||||||
|
echo " del agente; no se fuerza ahora para no interrumpirla." >&2
|
||||||
|
exit 75
|
||||||
|
fi
|
||||||
|
|
||||||
|
# `|| true` obligatorio: con pipefail, un pgrep sin resultados hace fallar la
|
||||||
|
# sustitución y `set -e` abortaría el script justo en el caso que hay que manejar.
|
||||||
|
OLD_PIDS="$(pgrep -f "$PGREP_PAT" | tr '\n' ' ' || true)"
|
||||||
|
echo "Señalizando al agente (PIDs: $OLD_PIDS) para que systemd lo relevante..."
|
||||||
|
# SIGTERM y no SIGKILL: si algún día el agente aprende a atender la señal, este camino ya
|
||||||
|
# le da la oportunidad de cerrar limpio.
|
||||||
|
pkill -TERM -f "$PGREP_PAT" >/dev/null 2>&1 || true
|
||||||
|
|
||||||
|
# Restart=always + RestartSec=5. Se espera con margen y se confirma que volvió: si el unit
|
||||||
|
# no tuviera Restart, matarlo lo dejaría muerto y eso NO puede pasar por bueno.
|
||||||
|
RESTARTED=0
|
||||||
|
for _ in $(seq 1 15); do
|
||||||
|
sleep 2
|
||||||
|
NEW_PID="$(pgrep -f "$PGREP_PAT" | head -1 || true)"
|
||||||
|
if [[ -n "$NEW_PID" ]] && [[ " $OLD_PIDS " != *" $NEW_PID "* ]]; then
|
||||||
|
RESTARTED=1
|
||||||
|
echo "Agente relevantado por systemd (PID $NEW_PID)."
|
||||||
|
break
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
if [[ "$RESTARTED" -eq 0 ]]; then
|
||||||
|
# No volvió. Dejar el servidor sin agente no es una opción: se revierte al binario que
|
||||||
|
# sí funcionaba y se le da otra oportunidad a systemd.
|
||||||
|
echo "AVISO: el agente no volvió tras la señal; revirtiendo al binario anterior..." >&2
|
||||||
|
UNIT_STATE="$(systemctl is-active "$UNIT_NAME" 2>/dev/null || true)"
|
||||||
|
UNIT_RESTART="$(systemctl show -p Restart --value "$UNIT_NAME" 2>/dev/null || true)"
|
||||||
|
|
||||||
|
REVERTED=0
|
||||||
|
if [[ -n "$BACKUP" && -f "$BACKUP" ]]; then
|
||||||
|
if install -m 0755 "$BACKUP" "$PREFIX/$BIN_NAME"; then
|
||||||
|
for _ in $(seq 1 10); do
|
||||||
|
sleep 2
|
||||||
|
if pgrep -f "$PGREP_PAT" >/dev/null 2>&1; then REVERTED=1; break; fi
|
||||||
|
done
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "ERROR: la actualización no dejó al agente corriendo." >&2
|
||||||
|
echo " Estado del unit: ${UNIT_STATE:-desconocido} (Restart=${UNIT_RESTART:-desconocido})" >&2
|
||||||
|
if [[ "${UNIT_RESTART}" != "always" ]]; then
|
||||||
|
echo " El unit no tiene Restart=always: nadie lo relevanta al terminar." >&2
|
||||||
|
elif [[ "$UNIT_STATE" == "failed" ]]; then
|
||||||
|
echo " systemd lo marcó como failed; puede haber agotado StartLimitBurst." >&2
|
||||||
|
echo " Reintentar con: systemctl reset-failed $UNIT_NAME && systemctl start $UNIT_NAME" >&2
|
||||||
|
fi
|
||||||
|
if [[ "$REVERTED" -eq 1 ]]; then
|
||||||
|
echo " REVERTIDO: el binario anterior está corriendo de nuevo. El servidor" >&2
|
||||||
|
echo " quedó como estaba; la versión nueva NO se aplicó." >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
echo " NO se pudo revertir. El binario nuevo está en $PREFIX/$BIN_NAME y el" >&2
|
||||||
|
echo " anterior en ${BACKUP:-(sin respaldo)}. Hay que revisar el servidor a mano." >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Solo tras confirmar que el agente nuevo corre se descarta el respaldo.
|
||||||
|
[[ -n "$BACKUP" && -f "$BACKUP" ]] && rm -f "$BACKUP" || true
|
||||||
|
fi
|
||||||
|
;;
|
||||||
desktop)
|
desktop)
|
||||||
echo "Modo escritorio: la app registra su autostart .desktop al iniciarse."
|
echo "Modo escritorio: la app registra su autostart .desktop al iniciarse."
|
||||||
echo "Ejecuta '$PREFIX/$BIN_NAME' en tu sesión gráfica."
|
echo "Ejecuta '$PREFIX/$BIN_NAME' en tu sesión gráfica."
|
||||||
@@ -311,7 +437,8 @@ esac
|
|||||||
|
|
||||||
# Si se detuvo un servicio que estaba activo y el modo elegido no lo relevanta, se
|
# Si se detuvo un servicio que estaba activo y el modo elegido no lo relevanta, se
|
||||||
# restaura: una actualización no debe dejar el restaurador apagado en silencio.
|
# restaura: una actualización no debe dejar el restaurador apagado en silencio.
|
||||||
if [[ "$WAS_ACTIVE" -eq 1 && "$MODE" != "service" && "$MODE" != "user-service" ]]; then
|
if [[ "$WAS_ACTIVE" -eq 1 && "$MODE" != "service" && "$MODE" != "user-service" \
|
||||||
|
&& "$MODE" != "update-in-place" ]]; then
|
||||||
echo "Reiniciando $UNIT_NAME (estaba activo antes de la actualización)..."
|
echo "Reiniciando $UNIT_NAME (estaba activo antes de la actualización)..."
|
||||||
systemctl start "$UNIT_NAME" >/dev/null 2>&1 || \
|
systemctl start "$UNIT_NAME" >/dev/null 2>&1 || \
|
||||||
echo "AVISO: no se pudo reiniciar $UNIT_NAME; hazlo a mano." >&2
|
echo "AVISO: no se pudo reiniciar $UNIT_NAME; hazlo a mano." >&2
|
||||||
|
|||||||
Reference in New Issue
Block a user