web-dev-qa-db-fra.com

systemd ignore ExecStop dans le fichier d'unité, l'exécute dans le cadre d'ExecStart

J'essaie de faire en sorte que plusieurs images de VirtualBox démarrent automatiquement au démarrage et que je sois correctement arrêté à la fermeture de l'hôte avant la mise hors tension. J'ai un script bash, /usr/local/bin/vmctl.sh, qui gère le démarrage et l'arrêt des images d'invité à l'aide d'appels à VBoxManage. L’appel de départ est très simple: il parcourt une liste d’images et appelle VBoxManage startvm --type headless "<imgname>", puis quitte 0. L’appel d’arrêt parcourt la liste et appelle VBoxManage controlvm "<imgname>" acpipowerbutton, puis boucle jusqu'à ce que VBoxManage list runningvms renvoie un liste vide OR 60 secondes s'écoulent avant qu'il ne quitte 0. L'exécution du script à partir de la ligne de commande fonctionne parfaitement.

J'ai créé un fichier unité dans /lib/systemd/system/vmctl.service:

[Unit]
Description=VirtualBox Control
After=virtualbox.service

[Service]
ExecStart=/usr/local/bin/vmctl.sh start
ExecStop=/usr/local/bin/vmctl.sh stop

[Install]
WantedBy=multi-user.target

Lorsque je lance systemctl start vmctl.service, il appelle à la fois les lignes de départ et d’arrêt. Lorsque j'appelle systemctl stop vmctl.service, il y a une entrée dans syslog qui indique Stopped VirtualBox Control mais elle ne fait rien.

Je suis un néophyte total à systemd. J'ai récemment mis à jour cette boîte Ubuntu à 16.04. Je suis presque sûr qu'il y a une explication simple à ce comportement que je ne vois pas.

Merci!


Mise à jour basée sur la suggestion de Mark:

J'ai confirmé la syntaxe en utilisant systemd-analyze verify /etc/systemd/system/vmctl.service (après y avoir déplacé le fichier - merci pour le conseil). J'ai ensuite changé les ExecStart et ExecStop comme vous l'avez suggéré, j'ai lancé systemctl daemon-reload et je vois toujours le même comportement. Le journal indique que les deux personnes s'exécutent lors de l'appel de systemctl start vmctl, mais non lors de l'exécution de systemctl stop vmctl:

# journalctl -u vmctl | tail
.
.
.
Apr 06 19:28:18 macmi10-builder systemd[1]: Started VirtualBox Control.
Apr 06 19:28:18 macmi10-builder echo[13901]: I started
Apr 06 19:28:18 macmi10-builder echo[13904]: I stopped
Apr 06 19:28:33 macmi10-builder systemd[1]: Stopped VirtualBox Control.
2
Jay MacDonald

Comme d'autres l'ont mentionné, le problème est que vmctl.sh se ferme immédiatement. Contrairement à la réponse de @ Christophe, le bricolage ne fonctionnera probablement pas, car vmctl.sh ne débouche probablement pas. Ce dont vous avez besoin est un service oneshot, avec RemainAfterExit=true. Si vous le changez simplement en oneshot, vous obtiendrez exactement le même comportement. La partie RemainAfterExit lui indique que même après la sortie de ExecStart, le service doit toujours être considéré comme étant en cours d'exécution. Il ne doit donc pas exécuter le (s) ExecStop.

5
Duncan X Simpson

Votre syntaxe systemd est correcte. Votre problème est ailleurs.

Tout d’abord, vous pouvez vérifier que la syntaxe elle-même est correcte avec:

systemd-analyze verify /path/to/your/vmctl.service

Deuxièmement, essayez de remplacer ces lignes:

ExecStart=/bin/echo "I started"
ExecStop=/bin/echo "I stopped"

Après avoir exécuté systemctl start vmctl ou systemctl stop vmctl, utilisez journalctl -u vmctl pour consulter les journaux. Je suppose que vous confirmerez que systemd a exécuté les commandes correctes.

De plus, /lib/systemd/system est destiné à un emplacement pour packages afin de gérer les fichiers systemd. Les fichiers que les utilisateurs modifient et gèrent manuellement sont destinés à être placés dans /etc/systemd/system

4
Mark Stosberg

Le paramètre Type par défaut pour une unité de service est Type = simple, utilisé lorsque le processus configuré avec ExecStart = est le processus principal du service. Une telle unité attendra le retour du processus spécifié par ExecStart, puis se désactivera en exécutant le processus spécifié par ExecStop. Dans votre cas, cela se produira dès que les machines virtuelles auront été lancées (pas ce que vous voulez).

Type = forking est utilisé lorsque le processus spécifié par ExecStart doit se terminer une fois le démarrage terminé, alors que ses processus enfants continuent de s'exécuter en arrière-plan. C’est le comportement des démons UNIX traditionnels et le choix recommandé dans votre cas. Le processus spécifié par ExecStop sera exécuté en cas de panne du service ou de la commande "systemctl stop vmctl".

Donc, votre fichier d'unité devrait être:

[Unit]
Description=VirtualBox Control
After=virtualbox.service

[Service]
Type=forking
ExecStart=/usr/local/bin/vmctl.sh start
ExecStop=/usr/local/bin/vmctl.sh stop

[Install]
WantedBy=multi-user.target
0
Christophe