Συστηματικά, διαδραστικά σενάρια και χρονόμετρα

Συστηματικά, διαδραστικά σενάρια και χρονόμετρα

Εισαγωγή

Κατά την ανάπτυξη για Linux, προκύπτει το καθήκον της δημιουργίας διαδραστικών σεναρίων που εκτελούνται όταν το σύστημα είναι ενεργοποιημένο ή τερματισμένο. Στο σύστημα V αυτό ήταν εύκολο, αλλά με το systemd κάνει προσαρμογές. Μπορεί όμως να έχει τα δικά του χρονόμετρα.

Γιατί χρειαζόμαστε στόχους;

Συχνά γράφεται ότι ο στόχος χρησιμεύει ως ανάλογο του επιπέδου εκτέλεσης στο σύστημα V-init. Διαφωνώ βασικά. Υπάρχουν περισσότερα από αυτά και μπορείτε να χωρίσετε πακέτα σε ομάδες και, για παράδειγμα, να ξεκινήσετε μια ομάδα υπηρεσιών με μία εντολή και να εκτελέσετε πρόσθετες ενέργειες. Επιπλέον, δεν έχουν ιεραρχία, παρά μόνο εξαρτήσεις.

Παράδειγμα στόχου όταν είναι ενεργοποιημένος (επισκόπηση λειτουργιών) με την εκτέλεση διαδραστικής δέσμης ενεργειών

Περιγραφή του ίδιου του στόχου:

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

Αυτός ο στόχος θα ξεκινήσει όταν εκκινηθεί το multi-user.target και καλέσει το installer.service. Ωστόσο, μπορεί να υπάρχουν πολλές τέτοιες υπηρεσίες.

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

Και τέλος, ένα παράδειγμα του σεναρίου που εκτελείται:

#!/bin/bash
# Переходим в tty3
chvt 3
echo "Install, y/n ?"
read user_answer

Το πιο σημαντικό πράγμα είναι να επιλέξετε final.target - τον στόχο στον οποίο πρέπει να φτάσει το σύστημα κατά την εκκίνηση. Κατά τη διαδικασία εκκίνησης, το systemd θα περάσει από τις εξαρτήσεις και θα ξεκινήσει όλα όσα χρειάζεται.
Υπάρχουν διάφοροι τρόποι επιλογής final.target, χρησιμοποίησα την επιλογή loader για αυτό.

Το τελικό λανσάρισμα μοιάζει με αυτό:

  1. Ξεκινά ο bootloader
  2. Ο bootloader ξεκινά την εκκίνηση του υλικολογισμικού περνώντας την παράμετρο final.target
  3. Το Systemd ξεκινά να εκκινεί το σύστημα. Διαδοχικά πηγαίνει στο installer.target ή work.target από το basic.target μέσω των εξαρτήσεών τους (για παράδειγμα, multi-user.target). Τα τελευταία φέρνουν το σύστημα να λειτουργήσει στην επιθυμητή λειτουργία

Προετοιμασία του υλικολογισμικού για εκκίνηση

Κατά τη δημιουργία υλικολογισμικού, τίθεται πάντα το καθήκον να επαναφέρετε την κατάσταση του συστήματος κατά την εκκίνηση και να το αποθηκεύσετε κατά τον τερματισμό της λειτουργίας. Κατάσταση σημαίνει αρχεία διαμόρφωσης, ενδείξεις βάσεων δεδομένων, ρυθμίσεις διεπαφής κ.λπ.

Το Systemd εκτελεί διεργασίες στον ίδιο στόχο παράλληλα. Υπάρχουν εξαρτήσεις που σας επιτρέπουν να προσδιορίσετε την ακολουθία εκκίνησης των σεναρίων.

Πώς λειτουργεί στο έργο μου ( https://habr.com/ru/post/477008/ https://github.com/skif-web/monitor)

  1. Το σύστημα ξεκινά
  2. Ξεκινά η υπηρεσία settings_restore.service Ελέγχει για την παρουσία του αρχείου settings.txt στην ενότητα δεδομένων. Εάν δεν υπάρχει, τότε τοποθετείται ένα αρχείο αναφοράς στη θέση του. Στη συνέχεια, γίνεται επαναφορά των ρυθμίσεων συστήματος:
    • κωδικό πρόσβασης διαχειριστή
    • όνομα κεντρικού υπολογιστή
    • ζώνη ώρας
    • μικρός λοβός
    • Καθορίζει εάν χρησιμοποιούνται όλα τα μέσα. Από προεπιλογή, το μέγεθος της εικόνας είναι μικρό - για ευκολία αντιγραφής και εγγραφής σε μέσα. Κατά την εκκίνηση, ελέγχει για να δει αν υπάρχει ακόμα αχρησιμοποίητος χώρος. Εάν υπάρχει, ο δίσκος επαναδιαμερίζεται.
    • Δημιουργία αναγνωριστικού μηχανήματος από διεύθυνση MAC. Αυτό είναι σημαντικό για τη λήψη της ίδιας διεύθυνσης μέσω DHCP
    • Ρυθμίσεις δικτύου
    • Περιορίζει το μέγεθος των κορμών
    • Η εξωτερική μονάδα δίσκου προετοιμάζεται για εργασία (εάν η αντίστοιχη επιλογή είναι ενεργοποιημένη και η μονάδα είναι καινούργια)
  3. Έναρξη postgresq
  4. Ξεκινά η υπηρεσία επαναφοράς. Απαιτείται για την προετοιμασία του ίδιου του zabbix και της βάσης δεδομένων του:
    • Ελέγχει εάν υπάρχει ήδη μια βάση δεδομένων zabbix. Εάν όχι, δημιουργείται από ενδείξεις αρχικοποίησης (περιλαμβάνεται στο zabbix)
    • δημιουργείται μια λίστα ζωνών ώρας (απαιτείται για την εμφάνιση τους στη διεπαφή ιστού)
    • Βρέθηκε η τρέχουσα IP, εμφανίζεται σε έκδοση (πρόσκληση για σύνδεση στην κονσόλα)
  5. Η πρόσκληση αλλάζει - εμφανίζεται η φράση Ready to work
  6. Το υλικολογισμικό είναι έτοιμο για χρήση

Τα αρχεία της υπηρεσίας είναι σημαντικά, είναι αυτά που καθορίζουν τη σειρά εκκίνησης τους

[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

Όπως καταλαβαίνετε, εγκατέστησα εξαρτήσεις για να λειτουργήσει πρώτα το σενάριό μου και μόνο μετά ανέβαινε το δίκτυο και ξεκινούσε το DBMS.

Και η δεύτερη υπηρεσία (προετοιμασία 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

Είναι λίγο πιο περίπλοκο εδώ. Η εκκίνηση είναι επίσης στο multi-user.target, αλλά ΜΕΤΑ την έναρξη του postgresql DBMS και του setting_restore. Αλλά ΠΡΙΝ ξεκινήσετε τις υπηρεσίες zabbix.

Υπηρεσία χρονοδιακόπτη για logrotate

Το Systemd μπορεί να αντικαταστήσει το CRON. Σοβαρά. Επιπλέον, η ακρίβεια δεν είναι μέχρι το λεπτό, αλλά μέχρι το δευτερόλεπτο (τι γίνεται αν χρειαστεί). Ή μπορείτε να δημιουργήσετε ένα μονότονο χρονόμετρο, που καλείται από ένα χρονικό όριο από ένα συμβάν.
Ήταν το μονότονο χρονόμετρο που μετρά τον χρόνο από την εκκίνηση του μηχανήματος που δημιούργησα.
Αυτό θα απαιτήσει 2 αρχεία
logrotateTimer.service - η πραγματική περιγραφή της υπηρεσίας:

[Unit]
Description=run logrotate

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

Είναι απλό - περιγραφή της εντολής εκκίνησης.
Το δεύτερο αρχείο logrotateTimer.timer είναι όπου λειτουργούν τα χρονόμετρα:

[Unit]
Description=Run logrotate

[Timer]
OnBootSec=15min
OnUnitActiveSec=15min

[Install]
WantedBy=timers.target

Τι υπάρχει εδώ:

  • περιγραφή χρονοδιακόπτη
  • Πρώτη ώρα έναρξης, ξεκινώντας από την εκκίνηση του συστήματος
  • περίοδο περαιτέρω εγκαινίων
  • Εξάρτηση από την υπηρεσία χρονοδιακόπτη Στην πραγματικότητα, αυτή είναι η συμβολοσειρά που δημιουργεί το χρονόμετρο

Διαδραστικό σενάριο κατά τον τερματισμό λειτουργίας και ο στόχος τερματισμού λειτουργίας

Σε μια άλλη εξέλιξη, έπρεπε να κάνω μια πιο σύνθετη έκδοση απενεργοποίησης του μηχανήματος - μέσω του δικού μου στόχου, για να εκτελέσω πολλές ενέργειες. Συνήθως συνιστάται η δημιουργία μιας υπηρεσίας oneshot με την επιλογή RemainAfterExit, αλλά αυτό σας εμποδίζει να δημιουργήσετε ένα διαδραστικό σενάριο.

Αλλά το γεγονός είναι ότι οι εντολές που εκτοξεύονται από την επιλογή ExecOnStop εκτελούνται εκτός του TTY! Είναι εύκολο να το ελέγξετε - επικολλήστε την εντολή tty και αποθηκεύστε την έξοδο της.

Επομένως, υλοποίησα τον τερματισμό μέσω του στόχου μου. Δεν ισχυρίζομαι ότι είμαι 100% σωστός, αλλά λειτουργεί!
Πώς έγινε (σε γενικές γραμμές):
Δημιούργησα έναν στόχο my_shutdown.target, ο οποίος δεν εξαρτιόταν από κανέναν:
my_shutdown.target

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

Κατά τη μετάβαση σε αυτόν τον στόχο (μέσω systemctl isolate my_shutdwn.target), ξεκίνησε την υπηρεσία my_shutdown.service, η εργασία της οποίας είναι απλή - να εκτελέσει το σενάριο 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

  • Μέσα σε αυτό το σενάριο εκτελώ τις απαραίτητες ενέργειες. Μπορείτε να προσθέσετε πολλά σενάρια στον στόχο για ευελιξία και ευκολία:

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

Σημείωση. Χρησιμοποιώντας τα αρχεία /tmp/reboot και /tmp/shutdown. Δεν μπορείτε να καλέσετε τον στόχο με παραμέτρους. Μόνο σέρβις είναι δυνατή.

Χρησιμοποιώ όμως το target για να έχω ευελιξία στη δουλειά και εγγυημένη σειρά ενεργειών.

Ωστόσο, το πιο ενδιαφέρον ήρθε αργότερα. Το μηχάνημα πρέπει να απενεργοποιηθεί/επανεκκινήσει. Και υπάρχουν 2 επιλογές:

  • Αντικαταστήστε τις εντολές επανεκκίνησης, τερματισμού λειτουργίας και άλλες εντολές (εξακολουθούν να είναι σύμβολοι για το systemctl) με το σενάριο σας. Μέσα στο σενάριο, μεταβείτε στο my_shutdown.target. Και τα σενάρια μέσα στον στόχο στη συνέχεια καλούν το systemctl απευθείας, για παράδειγμα, systemctl επανεκκίνηση
  • Πιο απλή επιλογή, αλλά δεν μου αρέσει. Σε όλες τις διεπαφές, μην καλέσετε shutdown/reboot/other, αλλά καλέστε απευθείας το σύστημα προορισμούctl isolate my_shutdown.target

Διάλεξα την πρώτη επιλογή. Στο systemd, η επανεκκίνηση (όπως το poweroff) είναι σύμβολοι με το systemd.

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

Επομένως, μπορείτε να τα αντικαταστήσετε με τα δικά σας σενάρια:
επανεκκίνηση

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

Πηγή: www.habr.com

Προσθέστε ένα σχόλιο