Linux: automatyczne zamykanie systemu z crontab (i Pythonem)

Jednym z problemów, jaki trapił mój serwer wydruku było to… że czasem zapominałem go wyłączać. A siedział w zamkniętej szafie przez co grzał się odrobinę (o kwestiach poboru prądu nie wspomnę).

Na szczęście rozwiązanie tego problemu w linuxie jest stosunkowo proste.  Sprowadza się do opanowania jednego programu: crontab. Przyda się również znajomość Pythpna – choćby najbardziej podstawowa.

Crontab tworzy zadania dla cron’a.  Cron to taki systemowy proces, który wykonuje zadania z określoną częstotliwością. Zależnie od konfiguracji, może to być np. codziennie o godzinie 11.00, co pięć minut – i inne, praktycznie dowolne kombinacje dat i czasu.

Użycie crontab jest proste: wystarczy wywołać:

Za pierwszym razem, program może się spytać o edytor, który ma być użyty do tworzenia plików zadań:

Proponuję wykorzystać nano:)

Teraz otworzy się plik, w którym dodajecie reguły i zadania do wykonania. Po wpisaniu zmian zamknijcie plik wciskając: [CTRL-X] [Y] [ENTER] (oczywiście tylko, jeżeli wybierzecie nano). Pliki z instrukcjami zapisywane są automatycznie w katalogu: „/var/spool/cron/crontabs”.

Reguły

Jedna linijka – jedno zadanie. Każdy zadanie ma postać:

Gdzie:

  • [minuty]: 0-59,
  • [godziny]: 0-23 – format 24-godzinny
  • [dzień miesiąca]: 1-31,
  • [miesiąc]: 1-12 lub Jan-Dec,
  • [dzień tygodnia], 0-6, Sun-Sat

Dodatkowo:

  • „*”: zamiast liczby, każda wartość, np. dla minut „*” będzie oznaczała wykonanie polecenie co minutę (czyli dla każdej wartości minut 0-59),
  • można podawać zakresy, np: „3-4” lub „1,2,3”,
  • „/”: oznacza krok, np: „0-6/2” oznacza to samo, co „0,2,4,6”,

Możliwy jest również inny format:

Gdzie [kiedy] to:

  • @reboot: uruchom przy starcie,
  • @yearly: uruchom raz w roku, to samo co: „0 0 1 1 *”,
  • @annually: to samo co „@yearly”,
  • @monthly: raz w miesiącu: „0 0 1 * *”,
  • @weekly: raz w tygodniu: „0 0 * * 0”,
  • @daily: codziennie :”0 0 * * *”.
  • @midnight: to samo co @daily,
  • @hourly: raz na godzinę: „0 * * * *”.
Przykłady reguł
Częstotliwość Reguła
Uruchom polecenie przy starcie @reboot <polecenie>
Uruchom co godzinę @hourly <polecenie>
Uruchom o 02:00 (w nocy) 0 2 * * * <polecenie>
Uruchom o 06:00 (w nocy) i 18:00 0 2,18 * * * <polecenie>
Uruchom co minutę * * * * * <polecenie>
Uruchom co 30 minut */30 * * * * <polecenie>

Jako polecenie, w linijce crontab może znaleźć się nie tylko komenda linuxowa, ale np. skrypt.

Polecenia – shutdown

Do zamknięcia systemu służy komenda „shutdown”.

Komenda Użycie
shutdown -k Drukuje sekwencję na konsoli, nic nie robi
shutdown -r  Restartuje system
shutdown -H  Halt: zatrzymuje wszystkie procesy – ale nie wyłącza zasilania
shutdown -P Poweroff: jak halt: zatrzymuje procesy, ale również wysyła sygnał do wyłączenia zasilania (ACPI)

linux udostępnia również polecenia halt, poweroff,  reboot – ale właściwie dublują funkcjonalność shutdown. W większości zachowano je dla kompatybilności ze starszymi systemami.

Stąd, żeby zamknąć system i wyłączyć zasilanie, użyjcie:

Zamykanie systemu rozpocznie się tuż po wydaniu polecenia.

Crontab i shutdown

Powiedzmy, że chcemy zamykać system o 05:00am (nad ranem). Niestety:

…nie zadziała. Chodzi o to, że cron wykonuje pliki zadań w innym kontekście niż zwykły użytkownik, gdzie nie wszystkie zmienne środowiskowe są ustawione (tu konkretnie: PATH). Innymi słowy – nie wie, gdzie jest program „shutdown”. W związku z tym trzeba podać pełną ścieżkę dostępu do programu, tzn:

…i to już zadziała.

Konfiguracja serwera wydruku

Na pewno nikt nie będzie pracował o 1 w nocy:

To jednak trochę słabo… Wymyśliłem, że będę zamykał serwer po godzinie nieaktywności (od ostatniego wydruku). Tu jednak proste poleceni nie wystarczy – będę potrzebował czegoś więcej.

Kilka przydatnych  elementów…
  • /proc/uptime: trzyma ilość sekund od uruchomienia urządzenia; w pliku są dwie wartości – nas interesuje tylko pierwsza liczba (drugie to ilość sekund, kiedy procesor był ‚bezrobotny’):
  • Zakończone wydruki:
Powinienem napisać to w bashu…

…ale po co, skoro można w pythonie? Plan jest następujący:

  • Napiszę skrypt w pythonie,
  • Skrypt będzie sprawdzał, jak długo serwer jest włączony,
  • Skrypt będzie sprawdzał, ile czasu upłynęło od ostatniego wydruku,
  • Jeżeli serwer działa dłużej niż godzina, i od ostatniego wydruku upłynęła więcej niż godzina – serwer wyłączy się,
  • Skrypt sprawdzający stan serwera będzie wywołany przez cron’a co 5 minut.

Upewnijcie się, że python jest zainstalowany:

Stwórzmy plik shutdownMe.py.

I otwórzcie w edytorze:

Zaczniemy od nagłówka pythona:

Teraz wczytamy, jak długo system jest włączony (kod z Plan Zero):

Funkcja getUpMinutes() otwiera plik /proc/uptime i wczytuje z niego liczbę sekund od włączenia komputera. Liczba ta dzielona jest przez 60 – w ten sposób zamieniam sekundy na minuty.

A co z ostatnim wydrukiem z cups’a? Owszem, można wywołać polecenie systemowe lpstat i przeanalizować jego wyjście. Ale jest łatwiejszy sposób. Wszystkie zadania wydruku przechowywane są w katalogu /var/spool/cups (dostęp z prawami admina). Teraz wystarczy znaleźć najświeższy plik (na podstawie: codereview):

Ta funkcja jest trochę bardziej skomplikowana:

  • do _listOfFiles wczytuję listę plików w katalogu /var/spool/cups
  • z listy wybieram plik najpóźniej stworzony, zapamiętuję go w _latestFile,
  • pobieram czas stworzenia pliku,
  • obliczam różnicę między czasem stworzenia pliku i obecnym – zamieniam na minuty

Reszta logiki ma zdecydować, czy już czas na zresetowanie serwera:

Cały kod:

Teraz uzupełnimy crontab o uruchomienie skryptu:

Zauważcie:

  • podaję pełną ścieżkę dostępu do pythona,
  • podaję pełną ścieżkę dostępu doskryptu,
  • wyjście ze skryptu dodaję do pliku shutdownMe.txt

Wyjścia z procesów uruchamianych przez cron nie zobaczycie na konsoli, można je jednak więc przesłać do pliku (tu: shutdownMe.txt).

Teraz serwer zamknie się po godzinie od włączenia i godzinie od ostatniego wydruku.

Źródła

Dodaj komentarz