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_DIRapuntando al directorio correcto con elUIDdel 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
UIDde cada usuario con sesión abierta - Para cada
UIDse utilizasudo, se exporta la variable de entornoXDG_RUNTIME_DIRy 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.timercon 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.servicecon 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:
