Écriture d'un fichier d'unité systemd avec un chemin exécutable défini par l'environnement

17

J'écris un fichier d'unité systemd pour une application Java et je voudrais contrôler la version de Java utilisée pour le démarrer. Mon fichier de service (simplifié) est

[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

Lorsque j'essaie de le démarrer, je reçois une erreur

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.

Je sais que JAVA_HOMEc'est correctement réglé; si je change la ExecStartligne pour commencer /usr/bin/javaet que j'ajoute quelque chose comme -DsomeOption=${JAVA_HOME}je peux le voir très bien.

La solution de contournement évidente consiste à créer un script wrapper, mais je pense qu'il va à l'encontre de l'utilisation d'un fichier de service.

Comment puis-je définir JAVA_HOME pour mon application Java à l'aide d'un fichier d'unité?

Robert Munteanu
la source
Pourquoi le script wrapper va-t-il à l'encontre de l'objectif d'utiliser un fichier de service, exactement? Vous obtenez toujours le séquençage de systemd et le suivi de la dépendance, le suivi, etc. En fait, les métiers systemd loin programmabilité sans forme que nous avions avec SysVinit en faveur du four en DTRT logique. Lorsque "la bonne chose" est quelque chose que systemd ne fait pas, vous devez mettre cela en dehors de systemd, comme dans un script shell.
Warren Young
@WarrenYoung - parce que je recommence soudainement à gérer les scripts shell. Dans mon cas, ne pas gérer un script shell est plus utile que les autres bits.
Robert Munteanu
Je ne vois vraiment pas le problème. Passez-vous vos journées à vous soucier de tous les exécutables que vous devez également gérer? :)
Warren Young
3
De systemd.service (5): "Notez que le premier argument (c'est-à-dire le programme à exécuter) peut ne pas être une variable." Cela explique pourquoi $ {JAVA_HOME} n'est pas développé au début du chemin des applications, mais est utilisé à un moment ultérieur.
Wieland
@WarrenYoung - Je préfère un seul wrapper au binaire. Je comprends que ce n'est pas un problème pour tout le monde, mais c'est pour moi :-)
Robert Munteanu

Réponses:

12

Dans la section "Lignes de commande" de systemd.service (5):

Notez que le premier argument (c'est-à-dire le programme à exécuter) peut ne pas être une variable.

J'allais suggérer d'utiliser le spécificateur d'instance %i (vous pouvez en savoir plus à ce sujet dans systemd.unit (5)), mais (maintenant nous sommes de retour dans systemd.service (5)):

le premier argument de la ligne de commande (c'est-à-dire le programme à exécuter) peut ne pas inclure de spécificateurs.

Je pense que la meilleure option à ce stade est vraiment de créer un script shell qui encapsule l'exécution du binaire java comme suggéré par Warren Young ou vous pouvez exécuter ExecStart un shell directement comme dans l'exemple des lignes de commande du shell dans la section "Lignes de commande" de systemd.service (5) qui a l'exemple suivant:

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

afin que vous puissiez faire (non testé):

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

Une autre option similaire consiste à utiliser /usr/bin/env:

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

De cette façon, vous pouvez omettre ' guillemets autour de la commande entière, ce qui est utile si vous avez besoin d'imbriquer des choses entre guillemets.

PS. En remarque, il est important de placer les noms de variables entre {accolades }dans les fichiers Systemd, sinon ils ne seront pas reconnus correctement.

MarSoft
la source