Systemd, scripts interactifs et minuteries


Présentation


Lors du dĂ©veloppement pour Linux, il existe des tĂąches de crĂ©ation de scripts interactifs qui sont exĂ©cutĂ©s lorsque le systĂšme est allumĂ© ou arrĂȘtĂ©. Dans le systĂšme V, cela a Ă©tĂ© fait facilement, mais avec systemd il fait des ajustements. Mais il peut faire ses temporisations.


Pourquoi avons-nous besoin d'un objectif


Il est souvent écrit que la cible sert d'analogue du niveau d'exécution dans le systÚme V -init. Je suis fondamentalement en désaccord. Il y en a plus et vous pouvez séparer les packages en groupes et, par exemple, exécuter un groupe de services avec une équipe et effectuer des actions supplémentaires. De plus, ils n'ont pas de hiérarchie, seulement des dépendances.


Exemple cible au démarrage (présentation des fonctionnalités) avec le lancement d'un script interactif


Description de la cible elle-mĂȘme:


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 

Cette cible démarre lorsque multi-user.target est lancé et appelle installer.service. De plus, il peut y avoir plusieurs de ces services.


 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 

Et enfin, un exemple de script exécutable:


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

La chose la plus importante est de choisir final.target - target, auquel le systÚme devrait parvenir au démarrage. Au cours du démarrage, systemd passera par les dépendances et exécutera tout ce dont vous avez besoin.
Il existe plusieurs façons de sélectionner final.target, j'ai utilisé l'option bootloader pour cela.


Le lancement final ressemble Ă  ceci:


  1. Le chargeur de démarrage démarre
  2. Le chargeur de démarrage démarre le firmware en passant le paramÚtre final.target
  3. Systemd démarre le démarrage du systÚme. Il va séquentiellement à installer.target ou work.target à partir de basic.target via leurs dépendances (par exemple, multi-user.target). Ces derniers et conduisent le systÚme à fonctionner dans le mode souhaité

Préparation du firmware pour le lancement


Lors de la crĂ©ation du micrologiciel, il est toujours nĂ©cessaire de restaurer l'Ă©tat du systĂšme au dĂ©marrage et de l'enregistrer lorsqu'il est Ă©teint. État signifie les fichiers de configuration, les vidages de base de donnĂ©es, les paramĂštres d'interface, etc.


Systemd lance le processus dans une cible en parallÚle. Il existe des dépendances qui vous permettent de déterminer la séquence d'exécution du script.


Comment cela fonctionne dans mon projet ( https://habr.com/en/post/477008/ https://github.com/skif-web/monitor )


  1. Le systÚme démarre
  2. Le service settings_restore.service démarre. Il vérifie le fichier settings.txt dans la section données. S'il n'est pas là, le fichier de référence est mis à sa place. Ensuite, les paramÚtres systÚme sont restaurés:
    • mot de passe administrateur
    • nom d'hĂŽte
    • fuseau horaire
    • locale
    • DĂ©termine si tous les supports sont utilisĂ©s. Par dĂ©faut, la taille de l'image est petite - pour faciliter la copie et l'enregistrement sur un support. Au dĂ©marrage, il est vĂ©rifiĂ© s'il reste de l'espace inutilisĂ©. S'il y a - le disque est repartitionnĂ©.
    • GĂ©nĂ©rez l'ID d'ordinateur Ă  partir de l'adresse MAC. Ceci est important pour obtenir la mĂȘme adresse via DHCP.
    • ParamĂštres rĂ©seau
    • La taille du journal est limitĂ©e
    • Le lecteur externe est prĂȘt pour le travail (si l'option correspondante est activĂ©e et que le lecteur est nouveau)
  3. Exécutez postgresq
  4. le service de restauration dĂ©marre. Il est nĂ©cessaire de prĂ©parer zabbix lui-mĂȘme et sa base de donnĂ©es:
    • VĂ©rifie s'il existe dĂ©jĂ  une base de donnĂ©es zabbix. Sinon, il est crĂ©Ă© Ă  partir de l'initialisation des vidages (ils sont fournis avec zabbix)
    • une liste de fuseaux horaires est crĂ©Ă©e (nĂ©cessaire pour les afficher dans l'interface web)
    • L'IP actuelle est trouvĂ©e, elle est affichĂ©e en cause (invitation Ă  entrer dans la console)
  5. L'invitation change - la phrase PrĂȘt Ă  travailler apparaĂźt
  6. Le firmware est prĂȘt Ă  fonctionner.

Les fichiers de service sont importants, ce sont eux qui fixent la séquence de leur lancement


 [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 

Comme vous pouvez le voir, j'ai fait les dépendances pour que je puisse d'abord exécuter mon script, et alors seulement le réseau augmenterait et le SGBD démarrerait.


Et le deuxiÚme service (préparation de 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 

C'est un peu plus compliqué. Le lancement se fait également dans multi-user.target, mais APRÈS avoir exécuté le SGBD postgresql et mon setting_restore. Mais AVANT d'exécuter les services zabbix.


Service avec une minuterie pour logrotate


Systemd peut remplacer CRON. Sérieusement. De plus, la précision n'est pas jusqu'à une minute, mais jusqu'à une seconde (et si elle est nécessaire) et vous pouvez créer une minuterie monotone, appelée par timeout depuis l'événement.
C'est la minuterie monotone qui compte le temps depuis le début de la machine que j'ai créée.
Cela nécessitera 2 fichiers
logrotateTimer.service - la description réelle du service:


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

C'est simple - une description de la commande de lancement.
Le deuxiÚme fichier logrotateTimer.timer est ce qui définit les minuteries pour fonctionner:


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

Qu'y a-t-il:


  • description de la minuterie
  • PremiĂšre fois Ă  partir du dĂ©marrage du systĂšme
  • pĂ©riode de nouveaux lancements
  • DĂ©pendance du service du minuteur. En fait, c'est la ligne qui rend le minuteur

Script interactif sur l'arrĂȘt et la cible d'arrĂȘt personnalisĂ©


Dans un autre dĂ©veloppement, j'ai dĂ» crĂ©er une version plus complexe de l'arrĂȘt de la machine - via ma propre cible, afin d'effectuer de nombreuses actions. Il est gĂ©nĂ©ralement recommandĂ© de crĂ©er le service oneshot avec l'option RemainAfterExit, mais cela empĂȘche la crĂ©ation d'un script interactif.


Mais le fait est que les commandes lancées par l'option ExecOnStop sont exécutées en dehors de TTY! La vérification est simple - insérez la commande tty et enregistrez sa sortie.


Par consĂ©quent, j'ai implĂ©mentĂ© l'arrĂȘt via ma cible. Je ne prĂ©tends pas ĂȘtre Ă  100% correct, mais ça marche!
Comment cela a été fait (en termes généraux):
Créé la cible my_shutdown.target, qui ne dépendait de personne:
my_shutdown.target


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

Lors du passage à cette cible (via systemctl isolate my_shutdwn.target), il a lancé le service my_shutdown.service, dont la tùche est simple - pour exécuter le 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 

  • Dans ce script, j'effectue les actions nĂ©cessaires. Vous pouvez ajouter de nombreux scripts Ă  la cible, pour plus de flexibilitĂ© et de commoditĂ©:

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 

Remarque Utilisation des fichiers / tmp / reboot et / tmp / shutdown. Vous ne pouvez pas appeler target avec des paramĂštres. Vous ne pouvez que le service.


Mais j'utilise target afin d'avoir une flexibilité dans le travail et une séquence d'actions garantie.


Cependant, la chose la plus intĂ©ressante a Ă©tĂ© plus tard. La machine doit ĂȘtre Ă©teinte / redĂ©marrĂ©e. Et il y a 2 options:


  • Remplacez les commandes reboot, shutdown et autres (ce sont toujours des liens symboliques sur systemctl) par votre propre script. Dans le script, accĂ©dez Ă  my_shutdown.target. Et les scripts Ă  l'intĂ©rieur de la cible appellent alors directement systemctl, par exemple, systemctl reboot
  • Un plus simple, mais je n'aime pas l'option. Dans toutes les interfaces, n'appelez pas shutdown / reboot / others, mais appelez directement le systemctl cible isolate my_shutdown.target

J'ai choisi la premiÚre option. Dans systemd, le redémarrage (comme poweroff) sont des liens symboliques sur systemd.


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

Par consĂ©quent, ils peuvent ĂȘtre remplacĂ©s par vos propres scripts:
redémarrer


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

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


All Articles