Zapisywanie pliku jednostki systemowej ze ścieżką wykonywalną ustawioną w środowisku

17

Piszę plik jednostki systemowej dla aplikacji Java i chciałbym kontrolować wersję Javy używaną do jej uruchomienia. Mój (uproszczony) plik usługi to

[Service]
Type=simple
EnvironmentFile=%h/Documents/apps/app/app-%i/app.cfg
ExecStart=${JAVA_HOME}/bin/java ${JAVA_OPTS} -jar %h/Documents/apps/app/app-%i/myapp.jar
SuccessExitStatus=143

Podczas próby uruchomienia pojawia się błąd

Apr 28 12:43:37 rombert systemd[1613]: [/home/robert/.config/systemd/user/[email protected]:7] Executable path is not absolute, ignoring: ${JAVA_HOME}/bin/java ${JAVA_OPT
Apr 28 12:43:37 rombert systemd[1613]: [email protected] lacks both ExecStart= and ExecStop= setting. Refusing.

Wiem, że JAVA_HOMEjest to poprawnie ustawione; jeśli zmienię ExecStartwiersz na początek, /usr/bin/javaa następnie dodam coś takiego -DsomeOption=${JAVA_HOME}, widzę to dobrze.

Oczywistym obejściem jest utworzenie skryptu opakowania, ale wydaje mi się, że pokonuje to sens używania pliku usługi.

Jak ustawić JAVA_HOME dla mojej aplikacji Java za pomocą pliku jednostkowego?

Robert Munteanu
źródło
Dlaczego skrypt opakowania dokładnie nie spełnia celu używania pliku usługi? Ciągle otrzymujesz sekwencjonowanie i monitorowanie zależności, monitorowanie itp. Zasadniczo systemd wymienia programowalność w dowolnej formie z SysVinit na rzecz logiki DTRT . Kiedy „właściwa rzecz” jest czymś, czego systemd nie robi, musisz umieścić to poza systemd, jak w skrypcie powłoki.
Warren Young,
@WarrenYoung - ponieważ nagle znów zaczynam zarządzać skryptami powłoki. W moim przypadku zarządzanie skryptem powłoki jest bardziej przydatne niż inne bity.
Robert Munteanu
Naprawdę nie widzę problemu. Czy spędzasz dni martwiąc się o wszystkie pliki wykonywalne, którymi musisz zarządzać? :)
Warren Young
3
Z systemd.service (5): „Zauważ, że pierwszy argument (tj. Program do wykonania) może nie być zmienną.” To wyjaśnia, dlaczego $ {JAVA_HOME} nie jest rozwijany na początku ścieżki aplikacji, ale jest używany, gdy zostanie użyty w późniejszym czasie.
Wieland
@WarrenYoung - Wolę pojedyncze opakowanie niż plik binarny. Rozumiem, że nie jest to problem dla wszystkich, ale dla mnie :-)
Robert Munteanu

Odpowiedzi:

12

Z sekcji „Wiersze poleceń” w pliku systemd.service (5):

Zauważ, że pierwszy argument (tj. Program do wykonania) może nie być zmienną.

Chciałem zasugerować użycie specyfikatora instancji %i(więcej na ten temat można przeczytać w systemd.unit (5)), ale (teraz wróciliśmy do systemd.service (5)):

pierwszy argument wiersza poleceń (tj. programu do wykonania) może nie zawierać specyfikatorów.

Myślę, że najlepszą opcją w tym momencie jest stworzenie skryptu powłoki, który otacza wykonanie pliku binarnego java, zgodnie z sugestią Warrena Younga, lub możesz uruchomić powłokę bezpośrednio jak w przykładzie dla linii poleceń powłoki w sekcji „Linie poleceń” systemd.service (5), który ma następujący przykład:

ExecStart=/bin/sh -c 'dmesg | tac'

więc możesz zrobić (niesprawdzone):

ExecStart=/bin/sh -c '${JAVA_HOME}....'
Wieland
źródło
2

Inną podobną opcją jest użycie /usr/bin/env :

ExecStart=/usr/bin/env "${JAVA_HOME}/bin/java" -jar ...

W ten sposób możesz pominąć 'cudzysłowy wokół całego polecenia, co jest przydatne, jeśli potrzebujesz zagnieżdżać cytowane rzeczy.

PS. Na marginesie ważne jest, aby zawrzeć nazwy zmiennych w {nawiasach klamrowych }w plikach Systemd, w przeciwnym razie nie zostaną one poprawnie rozpoznane.

MarSoft
źródło