ヘッドレスLinuxシステムでセッション(システムではなく)D-Busを介して通信するサービスを開始するための支援が必要です。重要なのは、ヘッドレスシステムに誰もログインしないことです。
これまでのところ、D-Busデーモンを起動して、ログインしていないユーザー(「otheruser」)に代わって、3つの異なる端末でD-Bus通信をテストすることができました。
最初のターミナルで、「otheruser」のD-Busデーモンを開始します。
$ Sudo -u otheruser dbus-daemon --session --print-address 1
unix:abstract=/tmp/dbus-a5cU7r4IHc,guid=6c0a9bbfd02f5f68da0fe32f5a5e0a48
2番目の端末で、上記のDBUS_SESSION_BUS_ADDRESS応答を使用してD-Busサーバーアプリケーションを起動します。
$ Sudo -u otheruser DBUS_SESSION_BUS_ADDRESS="unix:abstract=/tmp/dbus-a5cU7r4IHc,guid=6c0a9bbfd02f5f68da0fe32f5a5e0a48" /usr/bin/my-dbus-service
次に、3番目のターミナルで接続をテストできます。
$ 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
しかし、systemdを介してD-BusサーバーアプリケーションといくつかのクライアントD-Busサービスを開始したいと思います。 systemdを介してD-Busセッションを開始して、そのDBUS_SESSION_BUS_ADDRESS環境変数が「otheruser」のD-Busサーバーおよびクライアントサービスに伝達されるようにするにはどうすればよいですか?
1つの可能な解決策は、dbus-daemonの出力を「somefile」にパイプし、D-Busサーバーとクライアントを起動する前にDBUS_SESSION_BUS_ADDRESS = $(cat somefile)を設定することです。これは私には少しぎこちないようです。特に、systemdサービスファイルのsystem D-Bus接続の「Busname」ディレクティブに魔法があることに気づいているためです。これらのsystemdサービスがセッションD-Busインターフェースと通信できるように、「otheruser」のsystemdサービスを適切に開始するにはどうすればよいですか?
これを機能させるにはいくつかのものが必要です。
my-dbus-client.service
ファイルがType=dbus
であることを確認するか、dbus.socket
ユニットに依存して、dbusセッションバスソケットが割り当てられ、dubセッションサービスがまだ開始されていない場合は開始するようにします。 。まず、特定のユーザーのSystemdサービスをログインなしで起動時に開始するには、systemdユーザーの残存を有効にする必要があります。これは、ユーザーに対して有効にするように構成するときに、rootとして一度だけ実行する必要があります。
# loginctl enable-linger otheruser
次に、Debianベースのシステムを使用している場合、次の2つのステップでは、パッケージdbus-user-sessionパッケージをインストールするだけです。
# apt-get install dbus-user-session
他のディストリビューションを使用している場合、これを手動で実行するか、単にそれがどのように機能するかを理解したいだけです。それ以外の場合は、dbus.service
およびdbus.socket
の作成をスキップします。
次の内容のファイル/usr/lib/systemd/user/dbus.socket
を作成します(一部のディストリビューションでは、ユーザーディレクトリは/lib
ではなく/usr/lib
の下にある場合があります)。
[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
すべてのサービスへのDBUS_SESSION_BUS_ADDRESS
の伝播は、あなたの主な関心事でしたが、以下のExecPostStart
行で対処されます-以降のすべてのサービスがそのセットを持ちます。
%t
はXDG_RUNTIME_DIR
に置き換えられます-systemdによって作成され、ユーザーセッションに固有のファイルを挿入できる/run
の下の一時ディレクトリ。このソケットを別の場所に作成したい場合は、作成できない理由はありません。それがどこか一時的なものであること、または再起動/セッションのティアダウン時にクリーンアップされることを確認してください。
私はdbus unixソケットを抽象ソケットにしようとしていくつかの問題を抱えていました-何らかの理由でsystemdはunix:abstract=
または@
プレフィックスの形式が好きではないようです。
次の内容でファイル/usr/lib/systemd/user/dbus.service
を作成します。
[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
Systemdが舞台裏で既に作成したunixソケットをdbus-daemonに渡すためのちょっとした魔法があります。 Systemdはdbus.socket
からの情報を使用してソケットを作成し、そのファイル記述子は環境変数LISTEN_FDS
に設定され、dbus-daemon
に渡されます。上記の特別なオプションにより、dbus-daemonは、新しいファイル記述子を作成する代わりに、渡されたファイル記述子を使用します。これにより、dbusクライアントは、存在しないソケットを心配することなく、dbus-daemonの開始と並行して開始できます。
最後に、独自のsystemdユーザーサービスを作成し、タイプをType=dbus
に設定するか、BusName=
をこのサービスによって登録されるdbusサービス名の1つの名前に設定するか、またはUnitセクションでRequires=dbus.socket
が指定されていることを確認してください。次に例を示します。
[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
いくつかの場所のいずれかに配置できます。-$HOME/.config/systemd/user
-/usr/lib/systemd/user
systemctl --user enable <service name>
でサービスを有効にして再起動すると、すべてが機能するはずです。
参照:
man loginctl
for lingerman pam_systemd
for XDG_RUNTIME_DIR infoman systemd.service
、およびdbus.socketへの暗黙の依存関係man sd_listen_fds
LISTEN_FDS環境変数に関する情報