mirror of
https://github.com/iesfdlr/lab.git
synced 2026-06-06 01:16:49 +00:00
feat: better updater
This commit is contained in:
@@ -4,6 +4,18 @@ let
|
||||
username = "usuario";
|
||||
learningml-desktop = pkgs.callPackage ./pkgs/learningml-desktop.nix { };
|
||||
andaredConnectScript = pkgs.writeShellScriptBin "andared-connect" (builtins.readFile ./andared-connect.sh);
|
||||
labUpdateMonitor = pkgs.writeShellScriptBin "lab-update-monitor" (builtins.readFile ./update-monitor.sh);
|
||||
labUpdateLauncher = pkgs.writeShellScriptBin "lab-update-launcher" (builtins.readFile ./update-launcher.sh);
|
||||
labUpdateDesktop = pkgs.makeDesktopItem {
|
||||
name = "lab-updates";
|
||||
desktopName = "Actualizaciones del laboratorio";
|
||||
genericName = "Registro y lanzador de actualizaciones";
|
||||
comment = "Sigue la actualizacion activa, revisa registros o lanza una nueva actualizacion";
|
||||
exec = "lab-update-launcher";
|
||||
icon = "system-software-update";
|
||||
terminal = false;
|
||||
categories = [ "System" "Settings" ];
|
||||
};
|
||||
in
|
||||
{
|
||||
imports =
|
||||
@@ -222,7 +234,14 @@ in
|
||||
learningml-desktop
|
||||
wireshark
|
||||
andaredConnectScript
|
||||
labUpdateMonitor
|
||||
labUpdateLauncher
|
||||
labUpdateDesktop
|
||||
xdg-user-dirs
|
||||
libnotify
|
||||
util-linux
|
||||
kdePackages.kdialog
|
||||
kdePackages.konsole
|
||||
libreoffice-qt
|
||||
hunspell
|
||||
hunspellDicts.es_ES
|
||||
@@ -334,7 +353,7 @@ in
|
||||
};
|
||||
systemd.services.lab-updater = {
|
||||
description = "actualizaciones automáticas del sistema";
|
||||
path = with pkgs; [ git nix coreutils kdePackages.kdialog libnotify config.system.build.nixos-rebuild ];
|
||||
path = with pkgs; [ git nix coreutils systemd util-linux libnotify config.system.build.nixos-rebuild ];
|
||||
serviceConfig = {
|
||||
Type = "oneshot";
|
||||
ExecStart = "/etc/nixos/update.sh";
|
||||
|
||||
@@ -28,3 +28,10 @@ El sistema instalado deja preparada una conexión de NetworkManager para `Andare
|
||||
- En Plasma, basta con abrir el selector de redes, pulsar `Andared_Corporativo` e introducir las credenciales del usuario.
|
||||
- Alternativamente, desde terminal se puede usar `andared-connect` para que `nmcli` pida las credenciales de forma interactiva.
|
||||
- Si `TTLS` no funciona en un centro concreto, prueba `andared-connect peap`.
|
||||
|
||||
## actualizaciones
|
||||
|
||||
- Se puede seguir lanzando la actualización manual con `su -c /etc/nixos/update.sh`. El script ahora guarda un registro en `/var/log/lab-updates` y envía la notificación final a la sesión activa de KDE.
|
||||
- En el menú de aplicaciones de Plasma aparece `Actualizaciones del laboratorio`.
|
||||
- Si ya hay una actualización en marcha, el lanzador se engancha automáticamente a su registro activo.
|
||||
- Si no hay ninguna en curso, el lanzador permite iniciar una nueva actualización y seguir el registro, ver el último registro o abrir la carpeta con el historial.
|
||||
|
||||
77
update-launcher.sh
Executable file
77
update-launcher.sh
Executable file
@@ -0,0 +1,77 @@
|
||||
#!/bin/bash
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
monitor_bin="${LAB_UPDATE_MONITOR_BIN:-lab-update-monitor}"
|
||||
|
||||
pick_terminal() {
|
||||
local candidate
|
||||
|
||||
for candidate in konsole xterm; do
|
||||
if command -v "$candidate" >/dev/null 2>&1; then
|
||||
printf '%s\n' "$candidate"
|
||||
return 0
|
||||
fi
|
||||
done
|
||||
|
||||
return 1
|
||||
}
|
||||
|
||||
open_terminal() {
|
||||
local terminal="$1"
|
||||
shift
|
||||
|
||||
case "$terminal" in
|
||||
konsole)
|
||||
exec "$terminal" --hold -e "$@"
|
||||
;;
|
||||
xterm)
|
||||
exec "$terminal" -hold -e "$@"
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
main() {
|
||||
local terminal choice log_dir
|
||||
|
||||
terminal="$(pick_terminal)" || {
|
||||
if command -v kdialog >/dev/null 2>&1; then
|
||||
kdialog --error "No se ha encontrado ningun terminal compatible para abrir los registros."
|
||||
else
|
||||
echo "No se ha encontrado ningun terminal compatible para abrir los registros." >&2
|
||||
fi
|
||||
exit 1
|
||||
}
|
||||
|
||||
if "$monitor_bin" --has-active-update; then
|
||||
open_terminal "$terminal" "$monitor_bin" --watch
|
||||
fi
|
||||
|
||||
if command -v kdialog >/dev/null 2>&1; then
|
||||
choice="$(
|
||||
kdialog \
|
||||
--title "Actualizaciones del laboratorio" \
|
||||
--menu "Que quieres hacer?" \
|
||||
run "Ejecutar actualizacion y seguir registro" \
|
||||
watch "Ver el ultimo registro" \
|
||||
folder "Abrir la carpeta de registros"
|
||||
)" || exit 0
|
||||
else
|
||||
choice="run"
|
||||
fi
|
||||
|
||||
case "$choice" in
|
||||
run)
|
||||
open_terminal "$terminal" "$monitor_bin" --run
|
||||
;;
|
||||
watch)
|
||||
open_terminal "$terminal" "$monitor_bin" --watch
|
||||
;;
|
||||
folder)
|
||||
log_dir="$("$monitor_bin" --print-log-dir)"
|
||||
exec xdg-open "$log_dir"
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
main "$@"
|
||||
200
update-monitor.sh
Executable file
200
update-monitor.sh
Executable file
@@ -0,0 +1,200 @@
|
||||
#!/bin/bash
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
log_dir=""
|
||||
active_log_file=""
|
||||
active_pid_file=""
|
||||
latest_log_link=""
|
||||
|
||||
init_paths() {
|
||||
if [ -d /var/log/lab-updates ]; then
|
||||
log_dir="/var/log/lab-updates"
|
||||
else
|
||||
log_dir="${XDG_STATE_HOME:-$HOME/.local/state}/lab-updates"
|
||||
fi
|
||||
|
||||
active_log_file="$log_dir/active.log"
|
||||
active_pid_file="$log_dir/active.pid"
|
||||
latest_log_link="$log_dir/latest.log"
|
||||
}
|
||||
|
||||
is_pid_alive() {
|
||||
local pid="${1:-}"
|
||||
[ -n "$pid" ] && [ -d "/proc/$pid" ]
|
||||
}
|
||||
|
||||
active_pid() {
|
||||
if [ -r "$active_pid_file" ]; then
|
||||
head -n 1 "$active_pid_file" 2>/dev/null || true
|
||||
fi
|
||||
}
|
||||
|
||||
active_log() {
|
||||
local log=""
|
||||
|
||||
if [ -r "$active_log_file" ]; then
|
||||
log="$(head -n 1 "$active_log_file" 2>/dev/null || true)"
|
||||
if [ -n "$log" ] && [ -e "$log" ]; then
|
||||
printf '%s\n' "$log"
|
||||
return 0
|
||||
fi
|
||||
fi
|
||||
|
||||
return 1
|
||||
}
|
||||
|
||||
latest_log() {
|
||||
local log=""
|
||||
|
||||
if [ -L "$latest_log_link" ] && [ -e "$latest_log_link" ]; then
|
||||
log="$(readlink -f "$latest_log_link" 2>/dev/null || true)"
|
||||
fi
|
||||
|
||||
if [ -z "$log" ] || [ ! -e "$log" ]; then
|
||||
log="$(ls -1t "$log_dir"/update-*.log 2>/dev/null | head -n 1 || true)"
|
||||
fi
|
||||
|
||||
if [ -n "$log" ] && [ -e "$log" ]; then
|
||||
printf '%s\n' "$log"
|
||||
return 0
|
||||
fi
|
||||
|
||||
return 1
|
||||
}
|
||||
|
||||
has_active_update() {
|
||||
local pid
|
||||
|
||||
pid="$(active_pid)"
|
||||
is_pid_alive "$pid"
|
||||
}
|
||||
|
||||
watch_log() {
|
||||
local log=""
|
||||
local follow=0
|
||||
|
||||
if has_active_update; then
|
||||
log="$(active_log || true)"
|
||||
follow=1
|
||||
fi
|
||||
|
||||
if [ -z "$log" ]; then
|
||||
log="$(latest_log || true)"
|
||||
fi
|
||||
|
||||
if [ -z "$log" ]; then
|
||||
echo "Todavia no hay registros de actualizaciones."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ "$follow" -eq 1 ]; then
|
||||
echo "Siguiendo registro: $log"
|
||||
tail -n 200 -F "$log"
|
||||
else
|
||||
echo "Mostrando el ultimo registro: $log"
|
||||
tail -n 200 "$log"
|
||||
fi
|
||||
}
|
||||
|
||||
start_update_and_watch() {
|
||||
local before_latest=""
|
||||
local start_ts=""
|
||||
local pkexec_pid=""
|
||||
local log=""
|
||||
|
||||
if has_active_update; then
|
||||
watch_log
|
||||
return 0
|
||||
fi
|
||||
|
||||
if ! command -v pkexec >/dev/null 2>&1; then
|
||||
echo "No se ha encontrado pkexec para iniciar la actualizacion." >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
before_latest="$(latest_log || true)"
|
||||
start_ts="$(date +%s)"
|
||||
|
||||
echo "Solicitando permisos de administrador para iniciar la actualizacion..."
|
||||
pkexec /etc/nixos/update.sh >/dev/null 2>&1 &
|
||||
pkexec_pid="$!"
|
||||
|
||||
for _ in $(seq 1 180); do
|
||||
if has_active_update; then
|
||||
log="$(active_log || true)"
|
||||
[ -n "$log" ] && break
|
||||
fi
|
||||
|
||||
log="$(latest_log || true)"
|
||||
if [ -n "$log" ] && [ "$log" != "$before_latest" ]; then
|
||||
break
|
||||
fi
|
||||
|
||||
if [ -n "$log" ] && [ "$(stat -c %Y "$log" 2>/dev/null || echo 0)" -ge "$start_ts" ]; then
|
||||
break
|
||||
fi
|
||||
|
||||
if [ ! -d "/proc/$pkexec_pid" ]; then
|
||||
break
|
||||
fi
|
||||
|
||||
sleep 1
|
||||
done
|
||||
|
||||
if [ -z "$log" ]; then
|
||||
wait "$pkexec_pid" || true
|
||||
echo "No se ha podido encontrar el registro de la actualizacion."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "Siguiendo registro: $log"
|
||||
tail -n 200 -F "$log"
|
||||
}
|
||||
|
||||
usage() {
|
||||
cat <<'EOF'
|
||||
Uso: lab-update-monitor [--watch|--run|--run-or-watch|--has-active-update|--print-log-dir]
|
||||
|
||||
--watch Sigue la actualizacion en curso o el ultimo registro disponible.
|
||||
--run Inicia una actualizacion con permisos de administrador y sigue su registro.
|
||||
--run-or-watch Si hay una actualizacion activa, se engancha a ella; si no, inicia una.
|
||||
--has-active-update Sale con codigo 0 si hay una actualizacion activa.
|
||||
--print-log-dir Muestra la carpeta de registros.
|
||||
EOF
|
||||
}
|
||||
|
||||
main() {
|
||||
init_paths
|
||||
|
||||
case "${1:---run-or-watch}" in
|
||||
--watch)
|
||||
watch_log
|
||||
;;
|
||||
--run)
|
||||
start_update_and_watch
|
||||
;;
|
||||
--run-or-watch)
|
||||
if has_active_update; then
|
||||
watch_log
|
||||
else
|
||||
start_update_and_watch
|
||||
fi
|
||||
;;
|
||||
--has-active-update)
|
||||
has_active_update
|
||||
;;
|
||||
--print-log-dir)
|
||||
printf '%s\n' "$log_dir"
|
||||
;;
|
||||
--help|-h)
|
||||
usage
|
||||
;;
|
||||
*)
|
||||
usage >&2
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
main "$@"
|
||||
153
update.sh
Normal file → Executable file
153
update.sh
Normal file → Executable file
@@ -4,16 +4,6 @@ set -euo pipefail
|
||||
|
||||
cd "$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
|
||||
# When running from a systemd timer/cron, set display variables
|
||||
# so that kdialog/notify-send can reach the X11 session.
|
||||
if [ -z "${DISPLAY:-}" ]; then
|
||||
export DISPLAY=":0"
|
||||
dbus_addr="$(systemctl --user show-environment 2>/dev/null | grep '^DBUS_SESSION_BUS_ADDRESS=' | cut -d= -f2-)" || true
|
||||
if [ -n "${dbus_addr:-}" ]; then
|
||||
export DBUS_SESSION_BUS_ADDRESS="$dbus_addr"
|
||||
fi
|
||||
fi
|
||||
|
||||
force_update=0
|
||||
for arg in "$@"; do
|
||||
case "$arg" in
|
||||
@@ -27,43 +17,140 @@ for arg in "$@"; do
|
||||
esac
|
||||
done
|
||||
|
||||
timestamp="$(date +%Y%m%d-%H%M%S)"
|
||||
log_dir="/var/log/lab-updates"
|
||||
mkdir -p "$log_dir" 2>/dev/null || log_dir="${XDG_STATE_HOME:-$HOME/.local/state}/lab-updates"
|
||||
mkdir -p "$log_dir"
|
||||
|
||||
lock_file="$log_dir/update.lock"
|
||||
active_log_file="$log_dir/active.log"
|
||||
active_pid_file="$log_dir/active.pid"
|
||||
latest_log_link="$log_dir/latest.log"
|
||||
|
||||
timestamp="$(date +%Y%m%d-%H%M%S)"
|
||||
log_file="$log_dir/update-$timestamp.log"
|
||||
touch "$log_file"
|
||||
chmod 0644 "$log_file"
|
||||
|
||||
exec 9>"$lock_file"
|
||||
if ! flock -n 9; then
|
||||
current_log=""
|
||||
if [ -r "$active_log_file" ]; then
|
||||
current_log="$(head -n 1 "$active_log_file" 2>/dev/null || true)"
|
||||
fi
|
||||
|
||||
echo "Ya hay otra actualización en marcha."
|
||||
if [ -n "$current_log" ]; then
|
||||
echo "Registro activo: $current_log"
|
||||
fi
|
||||
exit 0
|
||||
fi
|
||||
|
||||
printf '%s\n' "$log_file" > "$active_log_file"
|
||||
printf '%s\n' "$$" > "$active_pid_file"
|
||||
ln -sfn "$log_file" "$latest_log_link"
|
||||
chmod 0644 "$active_log_file" "$active_pid_file"
|
||||
|
||||
exec > >(tee -a "$log_file") 2>&1
|
||||
|
||||
cleanup() {
|
||||
local code="$1"
|
||||
|
||||
if [ -r "$active_pid_file" ] && [ "$(head -n 1 "$active_pid_file" 2>/dev/null || true)" = "$$" ]; then
|
||||
rm -f "$active_log_file" "$active_pid_file"
|
||||
fi
|
||||
|
||||
if [ "$code" -ne 0 ]; then
|
||||
notify "Actualizacion fallida" "La actualizacion ha fallado (codigo $code)." error
|
||||
fi
|
||||
|
||||
exit "$code"
|
||||
}
|
||||
|
||||
desktop_user=""
|
||||
desktop_uid=""
|
||||
desktop_display=""
|
||||
|
||||
discover_desktop_session() {
|
||||
local session uid user state type remote class display
|
||||
|
||||
while read -r session uid user _; do
|
||||
[ -n "$session" ] || continue
|
||||
|
||||
state="$(loginctl show-session "$session" -p State --value 2>/dev/null || true)"
|
||||
type="$(loginctl show-session "$session" -p Type --value 2>/dev/null || true)"
|
||||
remote="$(loginctl show-session "$session" -p Remote --value 2>/dev/null || true)"
|
||||
class="$(loginctl show-session "$session" -p Class --value 2>/dev/null || true)"
|
||||
display="$(loginctl show-session "$session" -p Display --value 2>/dev/null || true)"
|
||||
|
||||
[ "$state" = "active" ] || continue
|
||||
[ "$remote" = "no" ] || continue
|
||||
[ "$class" = "user" ] || continue
|
||||
|
||||
case "$type" in
|
||||
x11|wayland)
|
||||
desktop_user="$user"
|
||||
desktop_uid="$uid"
|
||||
desktop_display="$display"
|
||||
return 0
|
||||
;;
|
||||
esac
|
||||
done < <(loginctl list-sessions --no-legend 2>/dev/null || true)
|
||||
|
||||
return 1
|
||||
}
|
||||
|
||||
run_in_desktop_session() {
|
||||
if [ -z "$desktop_user" ] || [ -z "$desktop_uid" ]; then
|
||||
discover_desktop_session || return 1
|
||||
fi
|
||||
|
||||
local -a env_vars=(
|
||||
"XDG_RUNTIME_DIR=/run/user/$desktop_uid"
|
||||
"DBUS_SESSION_BUS_ADDRESS=unix:path=/run/user/$desktop_uid/bus"
|
||||
"PATH=$PATH"
|
||||
)
|
||||
|
||||
if [ -n "$desktop_display" ]; then
|
||||
env_vars+=("DISPLAY=$desktop_display")
|
||||
fi
|
||||
|
||||
runuser -u "$desktop_user" -- env "${env_vars[@]}" "$@"
|
||||
}
|
||||
|
||||
notify() {
|
||||
local title="$1"
|
||||
local message="$2"
|
||||
local mode="${3:-info}"
|
||||
local full_message urgency
|
||||
|
||||
if command -v kdialog >/dev/null 2>&1 && { [ -n "${DISPLAY:-}" ] || [ -n "${WAYLAND_DISPLAY:-}" ]; }; then
|
||||
case "$mode" in
|
||||
reboot)
|
||||
if kdialog \
|
||||
--title "$title" \
|
||||
--yes-label "Reiniciar ahora" \
|
||||
--no-label "Más tarde" \
|
||||
--yesno "$message\n\nRegistro: $log_file"; then
|
||||
systemctl reboot
|
||||
fi
|
||||
;;
|
||||
error)
|
||||
kdialog --title "$title" --error "$message\n\nRegistro:\n$log_file"
|
||||
;;
|
||||
*)
|
||||
kdialog --title "$title" --msgbox "$message\n\nRegistro: $log_file"
|
||||
;;
|
||||
esac
|
||||
elif command -v notify-send >/dev/null 2>&1; then
|
||||
notify-send -t 0 --urgency=critical "$title" "$message\nRegistro: $log_file"
|
||||
printf -v full_message '%s\n\nRegistro: %s' "$message" "$log_file"
|
||||
|
||||
case "$mode" in
|
||||
error)
|
||||
urgency="critical"
|
||||
;;
|
||||
*)
|
||||
urgency="normal"
|
||||
;;
|
||||
esac
|
||||
|
||||
if command -v notify-send >/dev/null 2>&1; then
|
||||
run_in_desktop_session \
|
||||
notify-send \
|
||||
--app-name="Actualizaciones del laboratorio" \
|
||||
--icon="system-software-update" \
|
||||
--urgency="$urgency" \
|
||||
-t 0 \
|
||||
"$title" \
|
||||
"$full_message" \
|
||||
&& return 0
|
||||
fi
|
||||
|
||||
printf '%s\n%s\n' "$title" "$full_message" >&2
|
||||
}
|
||||
|
||||
trap 'code=$?; [ "$code" -eq 0 ] || notify "Actualizacion fallida" "La actualizacion ha fallado (codigo $code)." error' EXIT
|
||||
trap 'cleanup "$?"' EXIT
|
||||
trap 'exit 130' INT TERM
|
||||
|
||||
echo "Actualizando el sistema..."
|
||||
echo "Guardando registro en: $log_file"
|
||||
@@ -85,4 +172,4 @@ else
|
||||
fi
|
||||
|
||||
nixos-rebuild switch --flake path:.#nixos
|
||||
notify "Actualizacion completada" "La actualizacion del sistema ha terminado correctamente." reboot
|
||||
notify "Actualizacion completada" "La actualizacion del sistema ha terminado correctamente. Reinicia el equipo cuando te venga bien."
|
||||
|
||||
Reference in New Issue
Block a user