it-swarm.com.de

Starten von systemd-Diensten, die einen Sitzungs-D-Bus auf einem kopflosen System gemeinsam nutzen

Ich benötige Hilfe beim Starten von Diensten, die über einen Sitzungs-D-Bus (kein System) auf einem kopflosen Linux-System kommunizieren. Der Schlüssel ist, dass niemand am Headless-System angemeldet ist.

Bisher konnte ich einen D-Bus-Daemon starten und die D-Bus-Kommunikation im Auftrag eines nicht angemeldeten Benutzers ("otheruser") in drei verschiedenen Terminals testen:

Im ersten Terminal starte ich einen D-Bus-Daemon für den "otheruser":

$ Sudo -u otheruser dbus-daemon --session --print-address 1
unix:abstract=/tmp/dbus-a5cU7r4IHc,guid=6c0a9bbfd02f5f68da0fe32f5a5e0a48

Im zweiten Terminal starte ich die D-Bus-Serveranwendung mit der obigen Antwort DBUS_SESSION_BUS_ADDRESS:

$ Sudo -u otheruser DBUS_SESSION_BUS_ADDRESS="unix:abstract=/tmp/dbus-a5cU7r4IHc,guid=6c0a9bbfd02f5f68da0fe32f5a5e0a48" /usr/bin/my-dbus-service

Dann kann ich im dritten Terminal die Verbindung testen:

$ 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

Ich möchte jedoch die D-Bus-Serveranwendung sowie einige Client-D-Bus-Dienste über systemd starten. Wie starte ich eine D-Bus-Sitzung über systemd, damit die Umgebungsvariable DBUS_SESSION_BUS_ADDRESS für "otheruser" an den D-Bus-Server und die Client-Dienste weitergegeben wird?

Eine mögliche Lösung könnte darin bestehen, die Ausgabe von dbus-daemon in eine "somefile" zu leiten und dann DBUS_SESSION_BUS_ADDRESS = $ (cat somefile) zu setzen, bevor der D-Bus-Server und die Clients gestartet werden. Das kommt mir einfach etwas zu umständlich vor; vor allem, weil mir bewusst ist, dass die Direktive "Busname" in der systemd-Dienstdatei für system D-Bus-Verbindungen etwas Magisches enthält. Wie starte ich systemd-Dienste für "otheruser" ordnungsgemäß, damit diese systemd-Dienste mit einer Sitzungs-D-Bus-Schnittstelle kommunizieren können?

12
Ole Wolf

Sie benötigen mehrere Dinge, damit dies funktioniert.

  1. Aktivieren Sie die Ausführung von Benutzerdiensten zum Startzeitpunkt ohne Benutzeranmeldung (systemd verweilen).
  2. Eine systemd-Socket-Datei, um den D-Bus-Socket anzugeben, den systemd zuweisen soll.
  3. Ein systemd-Dienst zum Starten des gestarteten D-Bus-Sitzungsbusses, der dann die Umgebungsvariable DBUS_SESSION_BUS_ADDRESS für andere systemd-Dienste festlegt.
  4. Stellen Sie sicher, dass Ihre systemd my-dbus-client.service - Dateien von Type=dbus Sind oder von der dbus.socket - Einheit abhängen, um sicherzustellen, dass sie den dbus-Sitzungsbus-Socket zuweisen, und starten Sie den dbus-Sitzungsdienst, falls dies nicht der Fall ist wurde bereits gestartet.

Damit Systemd-Dienste für einen bestimmten Benutzer zum Startzeitpunkt ohne Anmeldung gestartet werden können, müssen Sie zunächst das Verweilen des Systemd-Benutzers aktivieren. Dies muss bei der Konfiguration nur einmal als Root erfolgen, um es für einen Benutzer zu aktivieren:

# loginctl enable-linger otheruser

Wenn Sie sich auf einem Debian-basierten System befinden, können Sie für die nächsten beiden Schritte einfach das Paket dbus-user-session packen:

# apt-get install dbus-user-session

Wenn Sie eine andere Distribution verwenden, möchten Sie dies manuell tun oder einfach nur verstehen, wie es weitergeht. Andernfalls überspringen Sie die Erstellung von dbus.service Und dbus.socket.

Erstellen Sie die Datei /usr/lib/systemd/user/dbus.socket (Beachten Sie, dass sich das Benutzerverzeichnis bei einigen Distributionen möglicherweise unter /lib Anstelle von /usr/lib Befindet) mit folgendem Inhalt:

[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

Die Weitergabe von DBUS_SESSION_BUS_ADDRESS An alle Dienste, die Ihr Hauptanliegen war, wird in der folgenden Zeile ExecPostStart behandelt. Für alle folgenden Dienste wird dieser Satz festgelegt.

%t Wird durch XDG_RUNTIME_DIR Ersetzt - ein vorübergehendes Verzeichnis unter /run, Das von systemd speziell für die Benutzersitzung erstellt wurde und in das Sie Dateien einfügen können. Wenn Sie diesen Socket an einem anderen Ort erstellen möchten, gibt es keinen Grund, warum Sie dies nicht können. Stellen Sie einfach sicher, dass es irgendwo vorübergehend ist, oder es wird beim Neustart/Herunterfahren der Sitzung bereinigt.

Ich hatte einige Probleme beim Versuch, den dbus-Unix-Socket zu einem abstrakten zu machen - systemd schien das Präfix form unix:abstract= Oder @ Aus irgendeinem Grund nicht zu gefallen.

Erstellen Sie nun die Datei /usr/lib/systemd/user/dbus.service Mit folgendem Inhalt:

[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

Es gibt ein bisschen Magie, die hier hinter den Kulissen von systemd vor sich geht, um den bereits erstellten Unix-Socket an den dbus-Daemon zu übergeben. Systemd verwendet die Informationen aus dbus.socket, Um den Socket zu erstellen, und sein Dateideskriptor wird in der Umgebungsvariablen LISTEN_FDS Festgelegt, die an dbus-daemon Übergeben wird. Die oben aufgeführten speziellen Optionen veranlassen dbus-daemon, den übergebenen Dateideskriptor zu verwenden, anstatt einen neuen zu erstellen. Auf diese Weise können dbus-Clients parallel zum dbus-Daemon gestartet werden, ohne dass der Socket vorhanden sein muss.

Erstellen Sie abschließend Ihre eigenen systemd-Benutzerdienste, und stellen Sie sicher, dass Sie entweder den Typ auf Type=dbus Und BusName= Auf den Namen eines der dbus-Dienstnamen setzen, die von diesem Dienst registriert werden. oder indem Sie sicherstellen, dass Requires=dbus.socket im Abschnitt Einheit angegeben ist. Hier ist ein Beispiel:

[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

Sie können sie an einer von mehreren Stellen platzieren: - $HOME/.config/systemd/user - /usr/lib/systemd/user

Aktivieren Sie Ihre Dienste mit systemctl --user enable <service name> Und starten Sie neu, und alles sollte funktionieren.


Verweise:

  • man loginctl Zum Verweilen
  • man pam_systemd Für XDG_RUNTIME_DIR-Informationen
  • man systemd.service Für Typ = dbus, BusName = und implizite Abhängigkeit von dbus.socket
  • man sd_listen_fds Für Informationen zur Umgebungsvariablen LISTEN_FDS
  • https://wiki.archlinux.org/index.php/Systemd/User - Allgemeine Informationen zu Systemd-Benutzersitzungen
14
Keithel