Currently snapd includes support for user daemons and dbus activation that is currently gated behind experimental feature flags. I would like to see those flags turned on by default. For reference, these flags enable the following:
-
experimental.user-daemons
adds a new app propertydaemon-scope
. When set touser
, this causes the daemon to be installed to run under user session instances of systemd rather than the pid 1 system instance. -
experimental.dbus-activation
adds a new app propertyactivates-on
, which contains a list of slot names referencingdbus
interface slots a daemon should activate on. If set, the daemonâs start up will be delayed until any of the given service names are used on the relevant bus.
Both flags can be confined to support D-Bus session bus activatable services. But each flag can be useful on its own. The user-daemons
flag on its own enables user session timers and services. The dbus-activation
flag on its own enables activatable system bus services.
Below are the things I believe need to be done before these features can be enabled. If anyone has anything needed to complete it, that would be great.
user-daemons
The user-daemons
feature flag enables snap.yaml
syntax like the following:
apps:
myservice:
command: bin/myservice
daemon: simple
daemon-scope: user
The daemon-scope
property can take the values system
or user
, with system
as the default providing the current behaviour. An app that sets daemon-scope: user
will instead be registered with the user session instance(s) of systemd. All properties used to configure system daemons can also be used to configure user session daemons too. This means things like socket activation and timers will also work for user session daemons.
When snapd installs, upgrades, or removes a snap containing a user daemon, it contacts the snap session agent for each running user session to ask that they start or stop the associated daemons. At present, that is the extent to how much snapd controls user daemons at present. Snapd does provide other ways of interacting with system daemons, which have not been updated though:
-
At the moment, snapd records the enabled state of all system daemons before an upgrade, and restores that state after the upgrade. It should do the same for user daemons.
-
snap services
lists the status of system daemons. We can easily enumerate user daemons too and determine their global enabled/disabled state. We should be able to determine the active state of user daemons via the session agent, but as there could be 0âŠn instances of the daemon it might not be cleanly âactiveâ or âinactiveâ. -
snap start
andsnap stop
can be used to start and stop system daemons, and optionally enable or disable the service. This could be extended to cover user daemons, but it opens the question of whether they should affect all instances of the daemon or just that for the current user. Maybe we want to support both, but via an option for the command?If we do allow starting/stopping an individual userâs instance of a user daemon, should unprivileged users be able to call these commands? We can certainly detect the calling processâs user ID within the REST API, but does exposing those endpoints to unprivileged users have any unwanted side effects?
If we allow unprivileged users to control their own instance of the daemon, does that mean we need to track per-user enabled state of user daemons? (currently we only care about the global enabled state).
-
There are
snapctl
equivalents of all of the above that can be called by code running in the context of a snap, and limited to daemons belonging to the snap. I believe the same concerns are relevant here.
I think that covers all the missing features. Itâs possible that we decide not to implement some of these features for user daemons, or decide that they shouldnât block us from turning on the feature. I think (1) probably needs doing though.
dbus-activation
I think dbus-activation
is the less risky one to enable by default. Here is an example of the snap.yaml
syntax for a D-Bus activated service:
slots:
dbus-slot:
interface: dbus
bus: system
name: org.example.Foo
apps:
myservice:
command: bin/myservice
daemon: simple
activates-on: [dbus-slot]
Compared with a similar snap.yaml
without the activates-on
property, the behaviour is changed as follows:
- The systemd service generated for
myservice
is no longer wanted bymulti-user.target
, so will not be started on boot. - A
/var/lib/snapd/dbus-1/system-services/org.example.Foo.service
file will be written out allow dbus-daemon to start the service. The service activation file includes aSystemdService
key so that dbus-daemon will start the corresponding systemd service. TheAssumedAppArmorLabel
key is also set so that communication that depends on the label (e.g. mediated method calls between two snaps) can activate the daemon.
The snap has no more access to the system, since without activates-on
, it could have the daemon start on boot and request the given D-Bus name. The main change is that the snap can now delay initialisation until (or even if) the service is used. If the service implements some kind of âexit on idleâ policy, it may even be able to remain stopped most of the time.
And since the activated daemon is still run under systemd, snapd can control it the same as any other daemon provided by a snap.
Developer Testing
Iâd welcome feedback from developers who would like to experiment with these features. You can enable them on your system by executing the following commands:
snap set system experimental.user-daemons=true
snap set system experimental.dbus-activation=true
The new syntax is not supported by Snapcraft yet (there are PR #3129 and PR #3425, but they probably wonât be merged until the features are enabled), but they can still be used via the passthrough:
feature described here:
Iâd welcome any feedback, including where things do not behave as youâd expect or additional issues you believe should be addressed before the features are enabled.