Menulis file unit systemd dengan path yang dapat dieksekusi set lingkungan

17

Saya menulis file unit systemd untuk aplikasi Java dan saya ingin mengontrol versi Java yang digunakan untuk memulai. File layanan saya (disederhanakan) adalah

[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

Ketika mencoba untuk memulainya saya mendapatkan kesalahan kembali

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.

Saya tahu itu JAVA_HOMEdiatur dengan benar; jika saya mengubah ExecStartbaris untuk memulai /usr/bin/javadan kemudian menambahkan sesuatu seperti -DsomeOption=${JAVA_HOME}saya bisa melihatnya dengan baik.

Solusi yang jelas adalah membuat skrip wrapper tetapi saya merasa itu mengalahkan titik menggunakan file layanan.

Bagaimana saya bisa mengatur JAVA_HOME untuk aplikasi Java saya menggunakan file unit?

Robert Munteanu
sumber
Mengapa skrip pembungkus mengalahkan tujuan menggunakan file layanan, tepatnya? Anda masih mendapatkan urutan sequencing dan pelacakan ketergantungan, pemantauan, dll. Pada dasarnya, systemd memperdagangkan programabilitas bentuk bebas yang kami miliki dengan SysVinit demi logika DTRT yang dipanggang-dalam . Ketika "hal yang benar" adalah sesuatu yang tidak dilakukan systemd, Anda harus meletakkannya di luar systemd, seperti pada skrip shell.
Warren Young
@ WarrenYoung - karena saya tiba-tiba mulai mengelola skrip shell lagi. Dalam kasus saya, tidak mengelola skrip shell lebih berguna daripada bit lainnya.
Robert Munteanu
Saya benar-benar tidak melihat masalah. Apakah Anda menghabiskan hari-hari Anda dengan mengkhawatirkan semua executable yang harus Anda kelola juga? :)
Warren Young
3
Dari systemd.service (5): "Perhatikan bahwa argumen pertama (yaitu program yang akan dieksekusi) mungkin bukan variabel." Itu menjelaskan mengapa $ {JAVA_HOME} tidak diperluas pada awal jalur aplikasi, tetapi ketika digunakan di beberapa titik kemudian.
Wieland
@ WarrenYoung - Saya lebih suka bungkus tunggal daripada biner. Saya mengerti bahwa ini bukan masalah bagi semua orang, tetapi bagi saya :-)
Robert Munteanu

Jawaban:

12

Dari bagian "Baris perintah" di systemd.service (5):

Perhatikan bahwa argumen pertama (yaitu program yang akan dieksekusi) mungkin bukan variabel.

Saya akan menyarankan menggunakan specifier contoh %i(Anda dapat membaca lebih lanjut tentang hal itu di systemd.unit (5)), tetapi (sekarang kita kembali di systemd.service (5)):

argumen pertama dari baris perintah (yaitu program yang akan dieksekusi) mungkin tidak termasuk specifier.

Saya pikir opsi terbaik pada saat ini benar-benar adalah membuat skrip shell yang membungkus pelaksanaan binary java seperti yang disarankan oleh Warren Young atau Anda bisa ExecStart shell secara langsung seperti dalam contoh untuk baris perintah shell di bagian "Command Lines" dari systemd.service (5) yang memiliki contoh berikut:

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

sehingga Anda dapat melakukan (belum diuji):

ExecStart=/bin/sh -c '${JAVA_HOME}....'
Wieland
sumber
2

Pilihan lain yang serupa adalah menggunakan /usr/bin/env:

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

Dengan cara ini Anda dapat menghilangkan 'tanda kutip di seluruh perintah yang berguna jika Anda perlu membuat sarang barang yang dikutip.

PS. Sebagai catatan tambahan, penting untuk menyertakan nama variabel dalam {kurung kurawal }di file Systemd atau mereka tidak akan dikenali dengan benar.

MarSoft
sumber