Propagate After= from target to its dependencies #3750

Open
martinpitt opened this Issue Jul 19, 2016 · 9 comments

Comments

Projects
None yet
4 participants
Contributor

martinpitt commented Jul 19, 2016

Submission type

  • Bug report
  • Request for enhancement (RFE)

systemd version the issue has been seen with

230, master

This came up while discussing and implementing graphical sessions with systemd. There are a few "set up" services like gpg-agent (poking environment variables into D-Bus) or session-migration (updating obsolete gsettings keys after upgrade and the like) which need to run before the desktop and applications start. It is currently very hard to order a bunch of services after a bunch of "early" services with targets. This can be demonstrated with some user units:

$ cat early.target 
[Unit]
Description=early services
Requires=setup.service

$ cat setup.service 
[Unit]
Description=setup for late services

[Service]
Type=oneshot
ExecStart=/bin/sleep 2

$ cat late.target 
[Unit]
Description=late services
Requires=early.target
Wants=some.service

$ cat some.service 
[Unit]
Description=some service

[Service]
ExecStart=/bin/sleep infinity

So the intention is that early.target and its dependencies run first, then late.target and its dependencies. But starting late.target immediately starts some.service as there is nothing that would delay that service. Only the late.target itself waits for early.target (but that is not the point here):

Jul 19 09:14:22 donald systemd[3856]: Started some service.
Jul 19 09:14:22 donald systemd[3856]: Starting setup for late services...
Jul 19 09:14:24 donald systemd[3856]: Started setup for late services.
Jul 19 09:14:24 donald systemd[3856]: Reached target early services.
Jul 19 09:14:24 donald systemd[3856]: Reached target late services.

With current systemd one would instead have to put the After=early.target into every single *.service, of which there are a lot.

On the system side the main divide that we have is sysinit.target and the DefaultDependencies= mechanism helps to implicitly add Requires/After=sysinit.target to every unit in multi-user. It would be nice to have a generalization of that, in the spirit of late.target saying [Target]\nPropagateDependencies=yes (this is not a great property name, I know) so that all of its dependencies inherit the same After= and Before= as the target itself (maybe also Requires= and Wants=, for consistency/symmetry).

This would help to more elegantly model the use case above, and we could perhaps also use that to replace the in-code implementation of DefaultDependencies=yes with adding this flag to multi-user.target.

Contributor

arvidjaar commented Jul 19, 2016

Define "its dependencies". A is After B, A Wants C, C Wants D. Should D be After B?

Contributor

martinpitt commented Jul 19, 2016

Intuitively, and for this use case, yes. That's also the case for DefaultDependencies. However, I don't know if that's practical to implement. This is mostly writing down issues we stumbled over when converting a desktop session startup to systemd, not necessarily fully designed yet.

Contributor

arvidjaar commented Jul 24, 2016

The obvious example how easy it is to break

After=basic.target
Wants=sysinit.target

I think such propagation should be restricted to units that are PartOf target in question. That allows definition of tightly coupled multi-unit services where dependencies can be set on top-level target only and lower level units could be freely interchanged as needed.

P.S. sorry messed up example.

Contributor

arvidjaar commented Jul 24, 2016

all of its dependencies inherit the same After= and Before= as the target itself (maybe also Requires= and Wants=, for consistency/symmetry).

But dependencies are defined by the very existing of Requires and Wants; so I am not sure where they should be propagated.

Contributor

martinpitt commented Oct 1, 2016

Just discussed that with @poettering, and he generally agrees with the idea; we just need to find a good way to express this in a unit. I. e. there should be some kind of RecursiveAfter=… which is like After but also applies … to all Wants/Requires of the unit. Or alternatively, a flag that modifies the behaviour of After= to become "recursive".

We can then use this to drop the hardcoding of After=basic.target for DefaultDependencies and replace it with adding RecursiveAfter=basic.target to multi-user.target.

In principle we could apply this for the various {network,local-fs,…}-pre.targets as well, but in practice this could cause unexpected behaviour changes (even though it would be a cleaner default).

Member

fsateler commented Oct 1, 2016

@martinpitt dropping the basic.target hardcoding would make it impossible to have services start as early as possible, but not start them in single user mode. In debian some firewalls and console-setup are setup like this

Contributor

arvidjaar commented Oct 2, 2016

@martinpitt

We can then use this to drop the hardcoding of After=basic.target for DefaultDependencies and replace it with adding RecursiveAfter=basic.target to multi-user.target.

This breaks indirect dependency. I.e. if multi-user.target Wants foo.target and foo.target Wants bar.service then bar.service will miss After=basic.target (based on all Wants/Requires of the unit). If you will apply it really recursively, this will break any setup that explicitly mentions any unit that itself is ordered before basic.target. I.e. any explicit Requires=sysinit.target as trivial example.

I'd rather consider possibility to define default dependencies in configuration file (like ServiceDefaultAfter=basic.target). This would allow building own startup sequence without resorting to DefaultDependencies=no in every unit definition.

I do think that idea of propagating dependencies is very useful, just not in this particular case.

Owner

poettering commented Dec 13, 2016

@martinpitt iirc this was solved differently in the end and hence we can close this rfe?

Contributor

martinpitt commented Dec 13, 2016

I don't have a better solution for this, but if this is too difficult to implement I guess we'll have another round on updating all our user services to add the After=graphical-session-pre.target directly.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment