Upstart, przegrał batalię z systemd o rolę startowego programu w Debianie, a Ubuntu zdecydowało się podporządkować Debianowi i wprowadza tę decyzję w życie. Żałuję – Upstart ma tę ulotną elegancję, której w systemd mi brakuje.
Niemniej:
-
w stabilnym Ubuntu 14.04, Upstart jest głównym systemem startowym,
-
nawet w wersjach opartych o systemd powinno być możliwe jego wykorzystywanie jako dodatkowej usługi.
Dlatego nie planuję go porzucać, a dziś drobny artykuł o używaniu go na poziomie na poziomie zwykłych użytkowników.
Zamiast desktopowego autostartu
Upstart i systemd stworzono, by rozwiązać dwa problemy:
-
porządkowania zależności między startującymi programami (by program wymagający działającej bazy danych uruchomił się dopiero, gdy ona wstanie, a sama baza, gdy jest zamontowany używany przez nią dysk) – przy czym chodzi zarówno o sam mechanizm, jak o możliwość czytelnego zapisania go;
-
i restartowania aplikacji, które uległy awarii.
Te sprawy nie dotyczą wyłącznie programów systemowych. W czasie typowej sesji developerskiej potrzebuję grupy pomocniczych programów (choćby paru tuneli SSH, serwera rtags, serwerków firmowego middleware potrzebnych do uruchamiania programów testowych, paru usług wspomagających używanie desktopu o których napiszę w przyszłości…). Nie chcę tych programów startować systemowo, mają być związane z moją sesją i startować gdy jest aktywna.
Mogę je wrzucić do autostartu ale … autostart jest jak
init.d
. Co padnie, to leży a nad kolejnością nie mam kontroli.
A też … wolę dopisać tekstowy plik konfiguracyjny niż przeklikiwać się
przez opcje Ustawień systemu.
Upstart pomaga tutaj przy pomocy dość mało popularnej funkcjonalności zadań użytkownika.
Zadania użytkownika
Katalog ~/.config/upstart
pełni podobną rolę, jak /init
: można
umieszczać w nim pliki *.conf
, będą traktowane jako definicje
zadań Upstartowych – tyle, że uruchamianych na moim koncie (i z niego
zarządzanych).
Przykładowo zatem, po stworzeniu pliku
~/.config/upstart/mk-tunel-postgres-lagrange.conf
o treści:
description "ssh tunnel: postgres/lagrange"
author "Mekk"
start on dbus
stop on session-end
# manual
env LOCAL=5532
env REMOTE=lagrange.firma.local:5432
env VIA_USER=marcin
env VIA=sshproxy.firma.local
exec ssh -L $LOCAL:$REMOTE -l $VIA_USER -N $VIA
respawn
uruchamia mi się, ilekroć jestem zalogowany, tunel SSH do zdalnej bazy
danych. Z kolei stworzenie pliku ~/.config/upstart/mk-rtags-rdm.conf
::
description "rtags daemon for emacs C++ completion"
author "Mekk"
start on dbus
stop on session-end
exec /usr/local/bin/rdm --data-dir /data/marcin/rtags-rdm --log-file /logs/marcin/rdm-rtags.log
zapewnia, że mojemu Emacsowi nie zabraknie backendu dla rtags.
Pojawienie się takiego pliku jest zauważane od razu, co można
sprawdzić poleceniem initctl list
, na którym pojawi się nowe
zadanie (polecenie trzeba wykonywać z konsoli należącej do danej sesji
Unity, Gnome czy KDE, chodzi o odpowiednią wartość zmiennej
środowiskowej $UPSTART_SESSION
).
O tym, czy po stworzeniu pliku .conf
program zostanie od razu
uruchomiony, decydują kryteria startu. W powyższym wypadku tak będzie
(kryterium jest trwałe), jeśli warunek odnosiłby się do jakiegoś
zdarzenia (np. gdybym napisał start on started dbus
), zadanie
byłoby zatrzymane i wymagało uruchomienia ręcznie przez initctl
start nazwa-zadania
.
Dostępne zdarzenia
W powyższych przykładach użyłem start on dbus
. Jest to dość
poręczny zapis zapewniający uruchomienie gdy działają kluczowe
elementy graficznej sesji. Oczywiście nie jest to jedyna możliwość…
Dwa kluczowe źródła informacji do czego można dopiąć własne akcje to:
-
man upstart-events
, -
polecenie
initctl show-config
(wypisujące listę zadań i listę emitowanych przez nie zdarzeń).
Przykładowo, można próbować zatrzymać program na
desktop-lock
i uruchomić go ponownie nadesktop-unlock
.
Należy uważać przy kopiowaniu przykładów ze zdarzeń systemowych,
zestaw zdarzeń dla sesji użytkownika jest trochę inny. Przy początkach
zabawy zdarzyło mi się napisać start on (local-filesystems and
net-device-up IFACE=eth0)
, nie dało to żadnego efektu.
Część zdarzeń systemowych jest dostępna dzięki procesowi
upstart-event-bridge
, z dodanym prefiksem :sys:
(np. systemowe
net-device-added
pojawi się jako :sys:net-device-added
) ale
należy pamiętać, że dotyczy to tylko zdarzeń występujących gdy moja
sesja już działa.
Konwencja nazw
upstart-*-bridge
jest stosowana do różnych programów generujących zdarzenia. Na systemowej szynie programupstart-udev-bridge
generuje zdarzenia związane z pojawianiem się czy znikaniem urządzeń,upstart-file-bridge
może reagować na pojawianie się lub kasowanie zadanych plików, aupstart-socket-bridge
na próby połączenia z konkretnymi portami.W sesji użytkownika poza wspomnianym już
upstart-event-bridge
działaupstart-dbus-bridge
(możliwość obsługi sygnałów D-Bus) i osobna kopiaupstart-file-bridge
(monitorująca pliki wymienione w zadaniach użytkownika).Każdy z tych programów ma man-a z podstawowymi informacjami.
Przykłady (i standardowe zadania)
Poza ~/.config/upstart
przetwarzany jest także katalog
standardowych zadań: /usr/share/upstart/sessions/
.
Można w nim znaleźć (na Ubuntu 14.04 i starszych) trochę
wartościowych przykładów – a także … wyjaśnienie zagadki
skąd właściwie biorą się niektóre programy jakie uruchamiają
mi się po zalogowaniu.
$ ls /usr/share/upstart/sessions
application-click.conf
application.conf
application-failed.conf
application-legacy.conf
at-spi2-registryd.conf
click-user-hooks.conf
dbus.conf
gnome-keyring.conf
gnome-keyring-gpg.conf
gnome-keyring-ssh.conf
gnome-session.conf
gnome-settings-daemon.conf
gpg-agent.conf
hud.conf
im-config.conf
indicator-application.conf
indicator-bluetooth.conf
indicator-datetime.conf
indicator-messages.conf
indicator-network.conf
indicator-power.conf
indicator-printers.conf
indicator-secret-agent.conf
indicator-session.conf
indicator-sound.conf
logrotate.conf
mediascanner-2.0.conf
re-exec.conf
scope-registry.conf
session-migration.conf
smart-scopes-proxy.conf
ssh-agent.conf
startkde.conf
unicast-local-avahi.conf
unity7.conf
unity8.conf
unity-gtk-module.conf
unity-panel-service.conf
unity-panel-service-lockscreen.conf
unity-settings-daemon.conf
unity-voice-service.conf
untrusted-helper.conf
untrusted-helper-type-end.conf
update-notifier-cds.conf
update-notifier-crash.conf
update-notifier-hp-firmware.conf
update-notifier-release.conf
upstart-dbus-session-bridge.conf
upstart-dbus-system-bridge.conf
upstart-event-bridge.conf
upstart-file-bridge.conf
window-stack-bridge.conf
xsession-init.conf
Logi błędów
Logi powstają w ~/.cache/upstart
i tam należy zajrzeć, jeśli
zadanie nie startuje (albo jeśli program wypisuje wartościowe
informacje diagnostyczne).
Pliki są rotowane raz dziennie, za co odpowiada zadanie
/usr/share/upstart/sessions/logrotate.conf
.
Wiązanie zadań
Dla powiązania własnych zadań należy posłużyć się własnymi zdarzeniami. Przykład::
emits mk-testenv-start
emits mk-testenv-stop
post-start exec initctl emit mk-testenv-start
pre-stop exec initctl emit --no-wait mk-testenv-stop
# … inne ustawienia zadania
(i jakieś inne zadanie można oprzeć o mk-testenv-start
).
Zadania działają tylko w trakcie działania sesji graficznej
W domyślnej konfiguracji cała powyższa mechanika funkcjonuje tylko, gdy jestem graficznie zalogowany, póki tego nie zrobię, żadne zadanie nie jest uruchamiane (a gdy się wyloguję, wszystkie są zatrzymywane). Ma to proste techniczne uzasadnienie:
-
za zarządzanie zadaniami odpowiada osobny proces Upstarta
init --user
, -
proces ten jest uruchamiany przez
lightdm
(albogdm
albokdm
) w trakcie inicjowania zalogowanej sesji (na moim Ubuntu odpowiada za to/etc/X11/Xsession.d/99upstart
).
Polecam odszukanie
init --user
wpstree -a
, ładnie widać hierarchię zależności procesów.
Można to w razie potrzeby obejść po prostu samodzielnie uruchamiając
odpowiednie init --user
z systemowych skryptów startowych.
Przykład można znaleźć w rozdziale Non-graphical Sessions Cookbooka.
Oczywiście trzeba tu przemyśleć którym użytkownikom uruchamiamy mechanizm.
Użycie powyższego mechanizmu na maszynie, która jest także desktopowa, może prowadzić do konfudujących efektów. Powstaje całkiem osobna (niezależna od tej inicjowanej przez graficzne zalogowanie się) sesja upstartowa, z osobnym zbiorem programów i zdarzeń. Może to mieć sens ale trzeba wtedy przynajmniej zadbać, by miała ona inny katalog na specyfikacje zadań niż główna sesja desktopowa.
Kiedy następuje ponowne uruchomienie
Kilkakrotnie zaskoczyło mnie, że po zabiciu programu przez kill
nie był on uruchamiany ponownie. Po kill -9
z kolei – owszem, była uruchamiana
nowa kopia.
Odpowiada za to konwencja normalnego zakończenia, w myśl której
niektóre statusy wykonania są poprawne i nie powodują restartu.
Domyślnie takim statusem jest 0
ale można to zmienić dyrektywą
normal exit
.
Więcej informacji
Poza wymienianymi już stronami man
(z man upstart
na czele),
warto również zajrzeć do Upstartowego Cookbooka.