Systemd, guiones interactivos y temporizadores


Introduccion


Al desarrollar para Linux, hay tareas de creación de scripts interactivos que se ejecutan cuando el sistema se enciende o se apaga. En el sistema V, esto se hizo fácilmente, pero con systemd hace ajustes. Pero puede hacer sus temporizadores.


¿Por qué necesitamos objetivo?


A menudo se escribe que el objetivo sirve como un análogo del nivel de ejecución en el sistema V -init. Estoy fundamentalmente en desacuerdo. Hay más de ellos y puede separar los paquetes en grupos y, por ejemplo, ejecutar un grupo de servicios con un equipo y realizar acciones adicionales. Además, no tienen jerarquía, solo dependencias.


Ejemplo de destino al inicio (descripción general de características) con el lanzamiento de un script interactivo


Descripción del objetivo en sí:


cat installer.target [Unit] Description=My installer Requires=multi-user.target Conflicts=rescue.service rescue.target After=multi-user.target rescue.service rescue.target AllowIsolate=yes Wants=installer.service 

Este objetivo se iniciará cuando se inicie multi-user.target y llame a installer.service. Además, puede haber varios servicios de este tipo.


 cat installer.service [Unit] #  Description=installer interactive dialog [Service] #   ,     Type=idle #   -   ExecStart=/usr/bin/installer.sh #      tty3 StandardInput=tty TTYPath=/dev/tty3 TTYReset=yes TTYVHangup=yes [Install] WantedBy=installer.target 

Y finalmente, un ejemplo de un script ejecutable:


 #!/bin/bash #   tty3 chvt 3 echo "Install, y/n ?" read user_answer 

Lo más importante es elegir final.target - target, al cual el sistema debe llegar al inicio. En el proceso de inicio, systemd pasará por las dependencias y ejecutará todo lo que necesite.
Hay varias formas de seleccionar final.target, utilicé la opción del gestor de arranque para esto.


El lanzamiento final se ve así:


  1. Se inicia el gestor de arranque
  2. El gestor de arranque inicia el firmware pasando el parámetro final.target
  3. Systemd inicia el inicio del sistema. Va secuencialmente a installer.target o work.target desde basic.target a través de sus dependencias (por ejemplo, multi-user.target). Esto último y llevar el sistema a trabajar en el modo deseado

Preparando el firmware para el lanzamiento


Al crear firmware, siempre existe la tarea de restaurar el estado del sistema al inicio y guardarlo cuando está apagado. Estado significa archivos de configuración, volcados de bases de datos, configuraciones de interfaz, etc.


Systemd inicia el proceso en un objetivo en paralelo. Hay dependencias que le permiten determinar la secuencia de ejecución del script.


Cómo funciona en mi proyecto ( https://habr.com/en/post/477008/ https://github.com/skif-web/monitor )


  1. El sistema comienza
  2. Se inicia el servicio settings_restore.service. Comprueba el archivo settings.txt en la sección de datos. Si no está allí, se coloca el archivo de referencia en su lugar. A continuación, se restaura la configuración del sistema:
    • contraseña de administrador
    • nombre de host
    • zona horaria
    • locale
    • Determina si todos los medios están en uso. Por defecto, el tamaño de la imagen es pequeño, por la conveniencia de copiar y grabar en medios. Al inicio, se verifica si todavía hay espacio sin usar. Si lo hay, el disco se vuelve a particionar.
    • Generar ID de máquina a partir de la dirección MAC. Esto es importante para obtener la misma dirección a través de DHCP.
    • Configuraciones de red
    • El tamaño del registro es limitado.
    • La unidad externa está preparada para el trabajo (si la opción correspondiente está habilitada y la unidad es nueva)
  3. Ejecute postgresq
  4. Se inicia el servicio de restauración. Es necesario para preparar zabbix y su base de datos:
    • Comprueba si ya hay una base de datos zabbix. Si no, se crea a partir de los volcados de inicialización (se suministran con zabbix)
    • se crea una lista de zonas horarias (necesaria para mostrarlas en la interfaz web)
    • Se encuentra la IP actual, se muestra en cuestión (invitación para ingresar a la consola)
  5. La invitación cambia: aparece la frase Listo para trabajar
  6. El firmware está listo para funcionar.

Los archivos de servicio son importantes, son ellos quienes establecen la secuencia para su lanzamiento


 [Unit] Description=restore system settings Before=network.service prepare.service postgresql.service systemd-networkd.service systemd-resolved.service [Service] Type=oneshot ExecStart=/usr/bin/settings_restore.sh [Install] WantedBy=multi-user.target 

Como puede ver, hice las dependencias para que primero ejecutara mi script, y solo entonces la red aumentaría y el DBMS comenzaría.


Y el segundo servicio (preparando zabbix)


 #!/bin/sh [Unit] Description=monitor prepare system After=postgresql.service settings_restore.service Before=zabbix-server.service zabbix-agent.service [Service] Type=oneshot ExecStart=/usr/bin/prepare.sh [Install] WantedBy=multi-user.target 

Esto es un poco más complicado. El lanzamiento también está en multi-user.target, pero DESPUÉS de ejecutar el DBMS postgresql y my setting_restore. Pero ANTES de ejecutar los servicios de zabbix.


Servicio con un temporizador para logrotate


Systemd puede reemplazar a CRON. En serio Además, la precisión no es de hasta un minuto, sino de hasta un segundo (y si es necesario). Y puede crear un temporizador monótono, llamado por tiempo de espera del evento.
Fue el temporizador monótono que cuenta el tiempo desde el inicio de la máquina que creé.
Esto requerirá 2 archivos
logrotateTimer.service: la descripción real del servicio:


 [Unit] Description=run logrotate [Service] ExecStart=logrotate /etc/logrotate.conf TimeoutSec=300 

Es simple: una descripción del comando de lanzamiento.
El segundo archivo logrotateTimer.timer es lo que configura los temporizadores para que funcionen:


 [Unit] Description=Run logrotate [Timer] OnBootSec=15min OnUnitActiveSec=15min [Install] WantedBy=timers.target 

¿Qué hay ahí?


  • descripción del temporizador
  • Primera vez desde el inicio del sistema
  • período de nuevos lanzamientos
  • Dependencia del servicio del temporizador: en realidad, esta es la línea y hace que el temporizador

Secuencia de comandos interactiva en apagado y destino de apagado personalizado


En otro desarrollo, tuve que hacer una versión más compleja de apagar la máquina, a través de mi propio objetivo, para realizar muchas acciones. Por lo general, se recomienda crear el servicio de un solo disparo con la opción RemainAfterExit, pero esto impide la creación de un script interactivo.


¡Pero el hecho es que los comandos lanzados por la opción ExecOnStop se ejecutan fuera de TTY! La comprobación es simple: inserte el comando tty y guarde su salida.


Por lo tanto, implementé el apagado a través de mi objetivo. No pretendo ser 100% correcto, ¡pero funciona!
Cómo se hizo (en términos generales):
Creó el objetivo my_shutdown.target, que no dependía de nadie:
my_shutdown.target


 [Unit] Description=my shutdown AllowIsolate=yes Wants=my_shutdown.service 

Al cambiar a este objetivo (a través de systemctl isolate my_shutdwn.target), lanzó el servicio my_shutdown.service, cuya tarea es simple: ejecutar el script my_shutdown.sh:


 [Unit] Description=MY shutdown [Service] Type=oneshot ExecStart=/usr/bin/my_shutdown.sh StandardInput=tty TTYPath=/dev/tty3 TTYReset=yes TTYVHangup=yes WantedBy=my_shutdown.target 

  • Dentro de este script, realizo las acciones necesarias. Puede agregar muchos scripts al destino, para mayor flexibilidad y conveniencia:

my_shutdown.sh


 #!/bin/bash --login if [ -f /tmp/reboot ];then command="systemctl reboot" elif [ -f /tmp/shutdown ]; then command="systemctl poweroff" fi #    #, cp /home/user/data.txt /storage/user/ $command 

Nota Usando los archivos / tmp / reboot y / tmp / shutdown. No se puede llamar al objetivo con parámetros. Solo puedes servir.


Pero uso target para tener flexibilidad en el trabajo y una secuencia garantizada de acciones.


Sin embargo, lo más interesante fue más tarde. La máquina debe apagarse / reiniciarse. Y hay 2 opciones:


  • Reemplace el reinicio, el apagado y otros comandos (todavía son enlaces simbólicos en systemctl) con su propio script. Dentro del script, vaya a my_shutdown.target. Y las secuencias de comandos dentro del destino luego llaman directamente a systemctl, por ejemplo, reinicio de systemctl
  • Una más simple, pero no me gusta la opción. En todas las interfaces, no llame a shutdown / reboot / others, sino que llame directamente al sistema de destinoctl isolate my_shutdown.target

Elegí la primera opción. En systemd, reiniciar (como poweroff) son enlaces simbólicos en systemd.


 ls -l /sbin/poweroff lrwxrwxrwx 1 root root 14  30 18:23 /sbin/poweroff -> /bin/systemctl 

Por lo tanto, se pueden reemplazar con sus propios scripts:
reiniciar


 #!/bin/sh touch /tmp/reboot sudo systemctl isolate my_shutdown.target fi 

Source: https://habr.com/ru/post/478846/


All Articles