J'ai besoin d'aide pour démarrer des services qui communiquent via une session (pas un système) D-Bus sur un système Linux sans tête. La clé est que personne ne sera connecté sur le système sans tête.
Jusqu'à présent, j'ai pu démarrer un démon D-Bus et tester la communication D-Bus au nom d'un utilisateur ("autre utilisateur") qui n'est pas connecté, dans trois terminaux différents:
Dans le premier terminal, je lance un démon D-Bus pour "autre utilisateur":
$ Sudo -u otheruser dbus-daemon --session --print-address 1
unix:abstract=/tmp/dbus-a5cU7r4IHc,guid=6c0a9bbfd02f5f68da0fe32f5a5e0a48
Dans le deuxième terminal, je démarre l'application serveur D-Bus en utilisant la réponse DBUS_SESSION_BUS_ADDRESS ci-dessus:
$ Sudo -u otheruser DBUS_SESSION_BUS_ADDRESS="unix:abstract=/tmp/dbus-a5cU7r4IHc,guid=6c0a9bbfd02f5f68da0fe32f5a5e0a48" /usr/bin/my-dbus-service
Ensuite, dans le troisième terminal, je peux tester la connexion:
$ Sudo -u otheruser DBUS_SESSION_BUS_ADDRESS="unix:abstract=/tmp/dbus-a5cU7r4IHc,guid=6c0a9bbfd02f5f68da0fe32f5a5e0a48" gdbus introspect --session --dest com.mycompany.myappname --object-path /com/mycompany/interface
Mais, je veux démarrer l'application serveur D-Bus ainsi que quelques services client D-Bus via systemd. Comment démarrer une session D-Bus via systemd afin que sa variable d'environnement DBUS_SESSION_BUS_ADDRESS soit propagée au serveur D-Bus et aux services clients pour "autre utilisateur"?
Une solution possible pourrait consister à diriger la sortie de dbus-daemon dans un "certains fichiers", puis à définir DBUS_SESSION_BUS_ADDRESS = $ (cat certains fichiers) avant de démarrer le serveur et les clients D-Bus. Cela me semble un peu trop gênant; surtout parce que je suis conscient qu'il y a de la magie avec une directive "Busname" dans le fichier de service systemd pour les connexions system D-Bus. Comment démarrer correctement les services systemd pour "autre utilisateur" afin que ces services systemd puissent communiquer avec une interface D-Bus de session?
Vous avez besoin de plusieurs choses pour que cela fonctionne.
my-dbus-client.service
les fichiers sont de Type=dbus
ou dépendent du dbus.socket
unité pour s'assurer qu'ils allouent la prise de bus de session dbus et démarrent le service de session dbus s'il n'a pas déjà été démarré.Tout d'abord, pour que les services Systemd pour un utilisateur donné démarrent au démarrage sans connexion, vous devez activer la persistance de l'utilisateur systemd - cela ne doit être effectué qu'une seule fois en tant que root lors de la configuration pour l'activer pour un utilisateur:
# loginctl enable-linger otheruser
Ensuite, si vous êtes sur un système basé sur Debian, pour les deux étapes suivantes, vous pouvez simplement installer le paquet dbus-user-session:
# apt-get install dbus-user-session
Si vous utilisez une autre distribution, souhaitez le faire manuellement ou voulez simplement comprendre comment cela fonctionne. Sinon, ignorez la création de dbus.service
et dbus.socket
.
Créez le fichier /usr/lib/systemd/user/dbus.socket
(notez que sur certaines distributions, le répertoire utilisateur peut se trouver sous /lib
au lieu de /usr/lib
) avec le contenu suivant:
[Unit]
Description=D-Bus User Message Bus Socket
[Socket]
ListenStream=%t/bus
ExecStartPost=-/bin/systemctl --user set-environment DBUS_SESSION_BUS_ADDRESS=unix:path=%t/bus
[Install]
WantedBy=sockets.target
Also=dbus.service
Propagation de DBUS_SESSION_BUS_ADDRESS
à tous les services, ce qui était votre principale préoccupation, est adressé par la ligne ExecPostStart
ci-dessous - tous les services suivants auront cet ensemble.
%t
est remplacé par le XDG_RUNTIME_DIR
- un répertoire transitoire sous /run
créé par systemd spécifique à la session utilisateur que vous pouvez bourrer de fichiers. Si vous souhaitez créer ce socket ailleurs, il n'y a aucune raison que vous ne le puissiez pas. Assurez-vous simplement qu'il est quelque part transitoire, ou qu'il est nettoyé lors du redémarrage/démontage de la session.
J'ai eu quelques problèmes en essayant de faire du socket dbus unix un abstrait - systemd ne semblait pas aimer la forme unix:abstract=
ou @
préfixe pour une raison quelconque.
Créez maintenant le fichier /usr/lib/systemd/user/dbus.service
avec le contenu suivant:
[Unit]
Description=D-Bus User Message Bus
Requires=dbus.socket
[Service]
ExecStart=/usr/bin/dbus-daemon --session --address=systemd: --nofork --nopidfile --systemd-activation
ExecReload=/usr/bin/dbus-send --print-reply --session --type=method_call --dest=org.freedesktop.DBus / org.freedesktop.DBus.ReloadConfig
[Install]
Also=dbus.socket
Il y a un peu de magie qui se passe ici dans les coulisses de systemd pour passer le socket unix déjà créé au dbus-daemon. Systemd utilise les informations de dbus.socket
pour créer le socket, et son descripteur de fichier est défini dans la variable d'environnement LISTEN_FDS
, qui est passé dans le dbus-daemon
. Les options spéciales répertoriées ci-dessus font que dbus-daemon utilise le descripteur de fichier transmis au lieu d'en créer un nouveau. Cela permet aux clients dbus de démarrer parallèlement au démarrage du dbus-daemon sans se soucier de l'absence de socket.
Enfin, créez vos propres services utilisateur systemd, en vous assurant de définir le type sur Type=dbus
, ensemble BusName=
au nom de l'un des noms de service dbus qui seront enregistrés par ce service, ou en vous assurant que Requires=dbus.socket
est spécifié dans la section Unité. Voici un exemple:
[Unit]
Description=Config Server Startup
[Service]
Type=dbus
BusName=com.example.app.configuree
ExecStart=/opt/example/app/configuration_server
Restart=on-failure
[Install]
WantedBy=default.target
Vous pouvez les placer à plusieurs endroits: - $HOME/.config/systemd/user
- /usr/lib/systemd/user
Activez vos services avec systemctl --user enable <service name>
et redémarrez, et tout devrait fonctionner.
Références:
man loginctl
pour s'attarderman pam_systemd
pour XDG_RUNTIME_DIR infoman systemd.service
pour Type = dbus, BusName = et dépendance implicite sur dbus.socketman sd_listen_fds
pour plus d'informations sur la variable d'environnement LISTEN_FDS