Apagado programado con notificación para el usuario en Ubuntu 20.04
En el instituto los ordenadores de las aulas y diferentes espacios están programado para apagarse 5 minutos después de que acaben las clases de la mañana y de la tarde. Esta función, que se implementa con un par de tareas en cron
, evita que se queden encendidos de forma innecesaria.
Pero en alguna ocasión provoca disgustos cuando el usuario se encuentra de forma inesperada con el apagado de la máquina.
Ahora que estoy preparando los playbooks de Ansible para utilizar con Ubuntu 20.04 se me ocurre que puede ser conveniente advertir al usuario con una notificación de Gnome sobre el inminente apagado para que guarde su trabajo o se prepare para disfrutar del shutdown :-)
Notificaciones en GNOME y comando notify-send
El escritorio Gnome tiene un elegante mecanismo de notificaciones al que se puede acceder desde la línea de comandos con la herramienta notify-send
. El manual advierte de que la notificación que se presenta al usuario puede tener:
- summary: un texto corto.
- body: el cuerpo multilínea de la notificación que puede incluir cierto código markup codificado en UTF-8.
- urgency: Un valor entre low, normal y critical. Por lo que he experimentado si se utiliza critical la notificación permanece en pantalla hasta que el usuario la cierra.
La especificación está disponible en: http://www.galago-project.org/specs/notification/
Así un usuario de Gnome puede abrir un terminal y probar el siguiente comando:
Pero no es posible enviar notificaciones desde una tarea periódica en crontab
o al menos no lo es de manea inmediata. Para que el comando notify-send
pueda enviar la notificación al usuario es necesario:
- Ser el mismo usuario (lo podemos conseguir con
sudo -s -u <usuario>
) - Y tener definida la variable de entorno
XDG_RUNTIME_DIR
apuntando al directorio correcto con elUID
del usuario, por ejemplo,/run/user/1000
.
Esto se debe al funcionamiento de D-Bus que se utiliza como mecanismo de comunicación.
Así que para lanzar desde crontab
notificaciones tendremos que escribir algún script que:
- Descubre las sesiones abiertas
- Toma nota del
UID
de cada usuario con sesión abierta - Para cada
UID
se utilizasudo
, se exporta la variable de entornoXDG_RUNTIME_DIR
y finalmente se ejecutanotify-send
.
Posible pero tedioso :-(
Una solución más sencilla: timers por usuario de systemd
Los timers
son unidades de systemd que permiten lanzar servicios de manera periódica como hace el tradicional cron
. La documentación de Arch Linux sobre los timers
de systemd es especialmente concisa: https://wiki.archlinux.org/index.php/Systemd/Timers.
Una característica muy importante es que se pueden declarar timers por usuario que únicamente se activan cuando el usuario tiene una sesión abierta. Por ejemplo, de esta manera se invoca a zsysctl
en Ubuntu 20.04 para realizar snapshots cuando el usuario inicia sesión y después cada hora.
En nuestro caso los ordenadores se apagan a las 14:55. Si queremos avisar a los usuarios que tengan una sesión abierta 5 minutos y 1 minuto antes del apagado deberemos:
- Definir el fichero
/usr/lib/systemd/user/notifica-apagado-1455.timer
con el siguiente contenido:
[Unit] Description=Notifica al usuario el apagado a las 14:55 [Timer] OnCalendar=14:50 OnCalendar=14:54 [Install] WantedBy=timers.target
- Definir el fichero
/usr/lib/systemd/user/notifica-apagado-1455.service
con el siguiente contenido:
[Unit] Description=Notifica al usuario el apagado a las 14:55 [Service] Type=oneshot ExecStart=/usr/bin/notify-send -u critical "Apagat programat a les 14:55" "L'ordinador està programat per apagar-se a les 14:55. Guardi tot el seu treball y tanqui les aplicacions obertes."
- Enlazar el timer en
/etc/systemd/user/timers.target.wants/
para que esté activo:
root@ubuntu2004:/etc/systemd/user/timers.target.wants# ln -s /usr/lib/systemd/user/notifica-apagado-1455.timer notifica-apagado-1455.timer root@ubuntu2004:/etc/systemd/user/timers.target.wants# ll total 12 drwxr-xr-x 2 root root 4 de maig 22 14:18 ./ drwxr-xr-x 5 root root 5 d’abr. 23 09:40 ../ lrwxrwxrwx 1 root root 49 de maig 22 14:18 notifica-apagado-1455.timer -> /usr/lib/systemd/user/notifica-apagado-1455.timer lrwxrwxrwx 1 root root 47 de maig 21 12:41 zsys-user-savestate.timer -> /usr/lib/systemd/user/zsys-user-savestate.timer root@ubuntu2004:/etc/systemd/user/timers.target.wants#
La instalación de este sistema en el centro se realizará con Ansible copiando las unidades a las máquinas controladas.
Resulta interesante observar que la herramienta systemd-analyze calendar
permite interpretar el valor especificado en OnCalendar
.
usuario@laika:~$ systemd-analyze calendar 14:54 Original form: 14:54 Normalized form: *-*-* 14:54:00 Next elapse: Sat 2020-05-23 14:54:00 CEST (in UTC): Sat 2020-05-23 12:54:00 UTC From now: 23h left usuario@laika:~$
Y el comando systemctl list-timers --user
que muestra información sobre los timers
de usuario.
root@stallman-181:~# systemctl list-timers --user NEXT LEFT LAST PASSED UNIT ACTIVATES Sat 2020-05-23 14:50:00 CEST 33min left n/a n/a notifica-apagado-1455.timer notifica-apagado-1455.service Sat 2020-05-23 15:13:19 CEST 57min left Sat 2020-05-23 14:13:19 CEST 2min 52s ago zsys-user-savestate.timer zsys-user-savestate.service Sat 2020-05-23 21:25:00 CEST 7h left n/a n/a notifica-apagado-2130.timer notifica-apagado-2130.service 3 timers listed. Pass --all to see loaded but inactive timers, too. root@stallman-181:~#
Más información: