Enabling user daemons and D-Bus activation

This one should be partially fixed by PR #9872, mentioned above: the command will no longer return an error, but won’t include status of the user daemon. There will need to be a follow-up to get it to display reasonable information about user daemons.

Despite that, you should be able to see the status of the user service with a command like systemctl --user status snap.$snap_name.$app_name.service. If you’re having trouble getting the D-Bus communication working, double check that the plug and slot are connected.

Thanks for fast reply!

Yes, I can see the service file:

$ systemctl --user status snap.dbus-test-snap.server.service 
● snap.dbus-test-snap.server.service - Service for snap application dbus-test-snap.server
     Loaded: loaded (/etc/xdg/systemd/user/snap.dbus-test-snap.server.service; disabled; vendor preset: enabled)
     Active: inactive (dead)

It can be started normally:

$ systemctl --user status snap.dbus-test-snap.server.service 
● snap.dbus-test-snap.server.service - Service for snap application dbus-test-snap.server
     Loaded: loaded (/etc/xdg/systemd/user/snap.dbus-test-snap.server.service; disabled; vendor preset: enabled)
     Active: active (running) since Wed 2021-02-03 15:44:06 CST; 1s ago
   Main PID: 398367 (server)
     CGroup: /user.slice/user-1000.slice/user@1000.service/snap.dbus-test-snap.server.service
             └─398367 /snap/dbus-test-snap/x2/bin/server

Feb 03 15:44:06 woodrow-Inspiron-7520 systemd[3149]: Started Service for snap application dbus-test-snap.server.

Thank you!

Yep. Services using the activates-on stanza are not started by default. Instead, you should see a /var/lib/snapd/dbus-1/services/in.softprayog.add_server.service file that the session bus will use to start the corresponding service when it is first used by a client.

If you are finding that you need to manually start the systemd service for things to work then it indicates something is broken: either within your snap, or with the way snapd is configuring dbus-daemon and systemd. I’d need to see any error messages your client generates to give any further advice.

I can see the content of /var/lib/snapd/dbus-1/services/in.softprayog.add_server.service:

[D-BUS Service]                                                                                                                                                                                            
Name=in.softprayog.add_server
Comment=Bus name for snap application dbus-test-snap.server
SystemdService=snap.dbus-test-snap.server.service
Exec=/usr/bin/snap run dbus-test-snap.server
AssumedAppArmorLabel=snap.dbus-test-snap.server
X-Snap=dbus-test-snap

Right now it’s always inactive state when snap is just installed, so not sure which part is the root cause why it can’t be auto start. I’m please to provide the log if any specific.

Here is full syslog:

What I meant was what errors does your dbus-test-snap.client program get when the server is inactive?

OK, let me try this:

When server is inactive:

$ systemctl --user status snap.dbus-test-snap.server.service 
● snap.dbus-test-snap.server.service - Service for snap application dbus-test-snap.server
     Loaded: loaded (/etc/xdg/systemd/user/snap.dbus-test-snap.server.service; disabled; vendor preset: enabled)
     Active: inactive (dead)

Feb 03 15:50:28 woodrow-Inspiron-7520 systemd[3149]: snap.dbus-test-snap.server.service: Succeeded.
Feb 03 15:50:28 woodrow-Inspiron-7520 systemd[3149]: Stopped Service for snap application dbus-test-snap.server.
Feb 03 15:50:39 woodrow-Inspiron-7520 systemd[3149]: Started Service for snap application dbus-test-snap.server.
Feb 03 17:03:40 woodrow-Inspiron-7520 systemd[3149]: Stopping Service for snap application dbus-test-snap.server...
Feb 03 17:03:40 woodrow-Inspiron-7520 systemd[3149]: snap.dbus-test-snap.server.service: Succeeded.
Feb 03 17:03:40 woodrow-Inspiron-7520 systemd[3149]: Stopped Service for snap application dbus-test-snap.server.
Feb 03 17:25:44 woodrow-Inspiron-7520 systemd[3149]: Started Service for snap application dbus-test-snap.server.
Feb 03 21:28:49 woodrow-Inspiron-7520 systemd[3149]: Stopping Service for snap application dbus-test-snap.server...
Feb 03 21:28:49 woodrow-Inspiron-7520 systemd[3149]: snap.dbus-test-snap.server.service: Succeeded.
Feb 03 21:28:49 woodrow-Inspiron-7520 systemd[3149]: Stopped Service for snap application dbus-test-snap.server.

To trigger the client:

$ dbus-test-snap.client 
Please type two numbers: 2 2 
Method "add_numbers" with signature "s" on interface "in.softprayog.dbus_example" doesn't exist

Is it what you expect to see the error?

First of all, does your client and server program work correctly when run without snap confinement?

Next, does the method call match the restrictions imposed by snapd’s dbus interface? In particular, for a snapd interface for name foo.bar.baz, either (a) the D-Bus interface must start withfoo.bar.baz, or (b) the object path must start with /foo/bar/baz.

yes, client/server can work with --devmode. But I think you’re right way to guide me now.
Because I’ve tried to use the following for connection name in C code and yaml:

  const char *const INTERFACE_NAME = "org.foo.bar.baz";
  const char *const SERVER_BUS_NAME = "org.foo.bar";
  const char *const SERVER_OBJECT_PATH_NAME = "/org/foo/bar";                                                                                                                                              
  const char *const METHOD_NAME = "add_numbers";
slots:
  dbus-server-slot:
    interface: dbus
    bus: session
    #name: in.softprayog.add_server
    name: org.foo.bar
  dbus-client-slot:
    interface: dbus
    bus: session
    #name: in.softprayog.add_client
    name: org.foo.car

plugs:
  dbus-client-plug:
    interface: dbus
    bus: session
    #name: in.softprayog.add_server
    name: org.foo.bar

In that case, the result is changing:

$ systemctl --user status snap.dbus-test-snap.server.service 
● snap.dbus-test-snap.server.service - Service for snap application dbus-test-snap.server
     Loaded: loaded (/etc/xdg/systemd/user/snap.dbus-test-snap.server.service; disabled; vendor preset: enabled)
     Active: inactive (dead)
...

$ dbus-test-snap.client 
Please type two numbers: 3 3
Method "add_numbers" with signature "s" on interface "org.foo.bar.baz" doesn't exist

Please type two numbers: 3 3
Sum is 6

$ systemctl --user status snap.dbus-test-snap.server.service 
● snap.dbus-test-snap.server.service - Service for snap application dbus-test-snap.server
     Loaded: loaded (/etc/xdg/systemd/user/snap.dbus-test-snap.server.service; disabled; vendor preset: enabled)
     Active: active (running) since Wed 2021-02-03 22:41:52 CST; 5s ago
   Main PID: 419110 (server)
     CGroup: /user.slice/user-1000.slice/user@1000.service/snap.dbus-test-snap.server.service
             └─419110 /snap/dbus-test-snap/x5/bin/server

Feb 03 22:41:52 woodrow-Inspiron-7520 systemd[3149]: Started Service for snap application dbus-test-snap.server.
Feb 03 22:41:52 woodrow-Inspiron-7520 dbus-test-snap.server[419110]: Did not get message

So client will get back to work at second time when server is from inactive to active? Interesting!

I think we’ve cleared all the blockers for the dbus-activation feature flag now. I had a chat with @alexmurray this morning, and he seemed satisfied that the feature from a security stand point (doesn’t increase the privilege of snaps, doesn’t allow them to run code at a time they couldn’t without it). So we could probably look at enabling it soon.

There is still some more work to be done on user-daemons. There is still some work to make sure the feature doesn’t cause commands like snap start to malfunction in the presence of user daemons, but there’s also the question of how those commands should act when run on user daemons if we don’t just return an error.

2 Likes

well, when it will already be possible to see a working search through the gnome-shell at the snap-store?

1 Like

Search providers will require a little more work, but getting D-Bus activation working was the main pain point. We’ve got all the basics now: your snap can install desktop files, and can be activated via D-Bus. So all that’s needed is some code to validate and install the the .search-provider.ini file on behalf of the snap.

There are obviously some privacy concerns around snaps providing search providers, since they will receive a copy of search strings. Maybe the answer is to leave snap search providers disabled by default?

I think that ordinary users are unlikely to specifically look for how to enable this option. so leaving it disabled by default would be tantamount to completely disabling it, we have to think about how to solve these privacy problems.

I just want to say thanks for working on user-daemons. The snap I’m developing right now is a user service, and as such it depends on that feature. I have no (useful) feedback to add, other than to say that it works well with my snap.

I have a question about making an app call snapctl stop and snapctl start from inside the snap, to start/stop a user daemon of the same snap. The snap I’m working on is composed of a user daemon and a GUI app, and I would like the GUI app to be able to restart the user daemon when a button is clicked. That’s currently not possible, as invoking snapctl stop myapp.daemon or snapctl start myapp.daemon from the GUI app yields the same result as running those commands in a shell with snap run --shell:

$ snap run --shell myapp
$ snapctl stop myapp.daemon
error: cannot use "stop" with uid 1000, try with sudo

I know that system daemons require sudo, but mine is a user daemon. I also understand that the user daemons feature is a work in progress. I am just wondering if it will be possible (once the feature is complete) to stop/start user daemons from inside the snap using snapctl without sudo.

My workaround at the moment is to:

  • Make the user daemon store its pid in a file under $XDG_RUNTIME_DIR
  • Configure the daemon with restart-condition: always
  • Make the GUI app send SIGTERM to the daemon’s PID to trigger a restart on command (the daemon handles that signal properly)
1 Like

This is one of the issues we haven’t yet implemented a solution for (part of the reason user-daemons hasn’t been enabled by default yet).

Getting this all working is non-trivial, but doable. To understand, it helps to understand how that snapctl command works. In essence, it does the following:

  1. a process from snap myapp executes the snapctl stop daemon command.
  2. the snapctl executable makes a corresponding API call to snapd.
  3. snapd identifies the caller as running in the context of the myapp snap.
  4. snapd checks the SO_PEERCRED credentials to make sure the caller is root.
  5. snapd asks the system instance of systemd to stop snap.myapp.daemon.service.

The error you’re seeing is from step (4). But supporting user daemons is not as simple as removing the check. User daemons are not managed by the system instance of systemd: instead they’re managed by a separate user instance (one per user logged in on the system). The user instances also refuse to talk to any process owned by a different user ID, so snapd running as root cannot directly talk to it.

We have put together a system to allow snapd to communicate with running user sessions in the form of the snap session agent, and are already using it to e.g. stop user daemons before uninstalling or upgrading a snap. We could use the same to handle the snapctl start/stop commands.

Of course, there’s still the question of what snapctl start daemon should actually do for a user daemon. Should it just affect the instance of the daemon for the calling user, or should it try to control all running user sessions? The first is the case is the one you’re asking for. The second obviously requires root, but might be useful for hooks.

For the “control current user’s daemon” case, there’s also the question of whether going via snapd is desirable, since it should be possible without escalating to root privileges. It might be difficult to add a fast path given the snapctl architecture where all the smarts are on the snapd side.

2 Likes

Thank you for the detailed explanation! Quite complicated indeed, I appreciate your work. I’ve been thinking more about my user daemon “restart on command” use case. The main reason for it was to reload config. Instead I’ll just have the two apps use dbus to communicate, since I also want the GUI app to monitor and report the daemon’s health anyway, and make sure the daemon is resilient enough to not exit unnecessarily.

In any case, I’m sure other use cases exist to require working snapctl start/stop commands. I hope my case helps you and others decide priorities. For instance, I would love to see the user daemons feature become available (almost) as it exists now, despite the missing functionality. In other words, would it make sense to add guards around or disable the snapctl commands that don’t currently work for user daemons, and release a lean version of the feature earlier, vs. implementing everything that you described?

@jamesh I ran into a problem where my user daemon doesn’t start upon first install and doesn’t stop after removal, but only when running on Manjaro with xorg. I think refreshes are a problem too. I see some discussion in https://github.com/snapcore/snapd/pull/5822 about how snapd can’t stop user services and some systemd versions don’t work well with the user-daemons experimental feature. I was wondering if you could confirm this is the issue I am facing.

I tested my (still unreleased) snap on other linux variants (see First snap - testing across different linux variants) and the user daemon worked really well on all except manjaro with org (e.g. xfce). It seems that there is something in this particular setup that’s different from the others with respect to how snapd works with systemd.

This is great work. Can you tell me if user daemons is moving forward and when it is reasonable to think it might make it to stable? This thread seemed not to make it into 2022. Just for clarity, I am referring to the “experimental.user-daemons”. :slight_smile:

It hasn’t been abandoned: in fact, I’m relying on it for one of the internal projects we’re working on.

Getting it turned on by default has stalled a bit though, as there were some features available for system daemons that are not implemented for user daemons: namely service control through snapctl. At the moment those commands return errors for user daemons, so perhaps it is worth reconsidering whether that’s a blocker for enabling the feature by default.

Thanks jamesh. So glad to hear it is moving forward. Our project is operating un-manned and headless so we do need it turned on by default. Do you know where in the priority list this might be?