Systemd programming part 2: activation and language issues
Activation options
With systemd, simply installing a unit file in the appropriate directory does not mean it is automatically active. This is much the same model as SysVinit uses, but it is a contrast to udev and upstart, which treat files as active the moment they are installed. There are subtle differences between systemd and SysVinit, though, which gave me my first hint that just continuing to use the SysVinit scripts for nfs-utils wasn't going to work, even though systemd provides some degree of support for these scripts.
With SysVinit, scripts are installed in /etc/init.d and then linked to /etc/rcN.d, or possibly /etc/init.d/rcN.d, for some value of N. This linking is often performed by the insserv utility, which will examine the header of each script and choose appropriate names for the links, so that the scripts are all run in the correct order. If a script has a "Required-Start" header referring to some other script and that other script has not been enabled (i.e. not linked into some directory), then insserv will complain and identify the missing dependency. It is then a simple matter to rerun insserv listing the extra dependency.
As SysVinit has relatively few scripts with few dependencies, this form of dependency handling does not cause an issue. With systemd, where nfs-utils alone has 14 unit files, having to explicitly enable all of them could get cumbersome. So where insserv treats a dependency as "this must already be enabled", systemd normally treats a dependency as "start this whether it is explicitly enabled or not" (though systemd has a rich language for these dependencies which we will get to in due course).
When systemd reads a SysVinit script, though, it takes a slightly different and more conservative approach to interpreting the dependency headers. It correctly treats Required-Start as implying an ordering (using the After systemd directive), but does not encode the "that service must already be enabled" meaning as it has no equivalent concept. A more liberal approach would translate Required-Start to Requires, causing the named script to be run even if not enabled. That might often be correct, but could be seen as reading more in to the dependency than is intended.
This different default behavior can create different expectations. When insserv nfs reports:
insserv: FATAL: service portmap has to be enabled to use service nfs
the system administrator will naturally run insserv portmap and move on. However, when "systemctl enable nfs" works, but a subsequent "systemctl start nfs" fails because rpcbind (which is the new name for portmap) isn't running, the administrator's response is likely to be less forgiving. For complete compatibility with SysVinit, systemd would need a dependency mechanism which makes it impossible to enable something unless some other requirement were already enabled, but that doesn't really fit into systemd's model.
With that little diversion out of the way, we should look at how units can be activated in systemd. Systemd is often described as using dependencies for unit activation and, while there is certainly truth in that, it is far from the full story. For the full (or, at least, fuller) story we will start with the "mdadm" package which provides services to assemble, monitor, and manage MD RAID arrays. One particular service is provided by running
mdadm --monitor
as a daemon. This daemon will watch for any device failures or other interesting events and respond to them, possibly by sending email to the administrator, or possibly by finding a "spare" device on some other array and moving it across (thus allowing spare sharing between arrays). This daemon should be running whenever any md array is active, but otherwise it is completely unnecessary. This requirement is achieved by creating a systemd unit file to run mdadm --monitor and using the SYSTEMD_WANTS setting in a udev rules file.
Udev (which is a whole different story when it comes to language design) is notified when any device comes online and can perform numerous tests and take actions. One of those actions is to set an environment variable (SYSTEMD_WANTS) to the name of some unit. When systemd subsequently receives events from udev, it will receive the full environment with them. Systemd interprets SYSTEMD_WANTS by adding a Wants directive to the .device unit (possibly newly created) corresponding to the device in the event. So a udev rules file which detects a new MD array and sets SYSTEMD_WANTS=mdmonitor.service will cause mdadm --monitor to run at exactly the correct time.
Note that there is no need to explicitly enable this service. As udev rules are always enabled and the udev rule directly requests the systemd service, it just happens. No activation needed. This signaling from udev to systemd is an event much like the events talked about in the context of upstart. While systemd may not only use events for activation, it certainly does use them — and not only events from udev.
When an NFSv2 or NFSv3 filesystem is mounted, then, unless network file locking has been explicitly disabled, the rpc.statd process must be running to ensure proper lock recovery after a reboot. Rather than have this process always running, /sbin/mount.nfs (which is used to mount all NFS filesystems) will check that rpc.statd is running and, if not, will start it. When systemd is being used it is best to do this by running:
systemctl start rpc-statd.service
which, again, is much like an event.
When mount.nfs checks to see if rpc.statd is running, it attempts to contact it via a network socket. It is well known that systemd supports socket-based activation, so it would be ideal to use that to activate rpc.statd. However, rpc.statd, like most ONC-RPC services, does not use a well-known port number, but instead chooses an arbitrary port and registers it with rpcbind. So systemd would need to do this too: bind an arbitrary port, register that port with rpcbind, and start rpc.statd when traffic arrives on that socket. This is certainly possible; SunOS used to ship with a version of inetd which did precisely this. Solaris still does. Whether it is worth adding this functionality to systemd for the two or maybe three services that would use it is hard to say.
The remainder of the daemons that make up the complete NFS service are not triggered by events and so must be explicitly activated by being tied to specific well-known activation point "targets", which are not unlike SysVinit run levels. Even there, the distinction between the systemd approach and the use of events in upstart is not as obvious as one might expect.
As we shall see, a dependency relationship is created between nfs-server.target and multi-user.target so that when multi-user.target is started, nfs-server.target is started too. As upstart jobs broadcast a "starting" signal when they are starting, and can register to, for example, "start on starting multi-user" the net effect is, to some degree at least, similar.
There is a key difference here, though, and it isn't really about events or dependencies, but about causality. In upstart, a job can declare "start on" to identify which event it should start on. So each job declares the events which cause it to run. Systemd, despite its rich dependency language, has no equivalent to "start on", an omission that appears to be deliberate. Instead, each event — the starting or stopping of a unit — declares which jobs (or units) need to be running. The dependency language is exactly reversed. With upstart, each job knows what causes it to start. With systemd, each job knows what it causes to start.
While systemd has no equivalent to "start on", it has something related that we must study to understand how the remaining nfs-utils daemons are started. This is represented by the "WantedBy" and "RequiredBy" directives, which are quite different from the "Requires" and "Wants" etc. dependency directives. "WantedBy" plays no role in determining when to start (or stop) any service. Instead, it is an instruction on how to enable a specific unit. The directive:
WantedBy=some-unit.target
means "the best way to enable this unit is to tell some-unit.target that it Wants us." It is possible to tell any unit that it wants another unit, either by creating a drop-in file as described in part 1 to add a "Wants" directive, or by creating some special symbolic links that systemd interprets in a similar way to drop-ins. The easiest way, though, is to run:
systemctl enable servicename
This command responds to the WantedBy directive in servicename.service by creating the special symlink so that some-unit.target thinks it wants servicename.
So in our collection of nfs-utils unit files, a few of them have WantedBy directives so they can be properly enabled. The rest get activated by "Wants" or "Requires" lines in those main files. Two of the unit files fit this pattern perfectly. nfs-server.target and nfs-client.target are WantedBy=multi-user.target or remote-fs.target, and then they Want or Require other units. The other two target unit files are a bit different, and to understand them we need to revisit the problem of configuration.
One of the purposes of the current configuration setup for nfs-utils in openSUSE is to optionally start the daemons which support using Kerberos to secure the NFS traffic. If you trust your local network, then Kerberos security is pointless and it is a waste to even run the daemons. However, if you want to use NFS over an untrusted network, then running rpc.gssd and rpc.svcgssd really is a must ("gss" here stands for "Generic Security Services"; while they were designed to be generic, the practical reality is that they only support Kerberos).
So we have the situation that nfs-server.target wants rpc-svcgssd.service, but only if network security is wanted, and this latter choice is configured by an environment variable. This is a requirement that systemd really cannot manage. It has a number of Condition directives to disable units in various cases, but none of them can be controlled using an environment variable. This suggests that either the sysadmin or the configuration tool (and possibly both) will need to use some other mechanism. The most obvious mechanism is systemctl and particularly:
systemctl enable rpc-svcgssd
to enable a service if it is off by default, or:
systemctl mask rpc-svcgssd
to mask (disable) a service that is otherwise on by default.
There is a complication though: in the pre-existing configuration that I was trying to mirror with systemd units, there are two services, rpc.gssd and rpc.svcgssd, that are both controlled by a single configuration item NFS_SECURITY_GSS. These need to be started in different circumstances: rpc.gssd is required if the NFS server is started or an NFS filesystem is mounted, while rpc.svcgssd is only required if the server is started. So we cannot simply have an nfs-secure.target which needs both of them and can be manually enabled. Systemd is powerful enough to make this set of requirements achievable, though it does seem to be a bit of a stretch.
The draft unit-file collection contains an nfs-secure.target unit which can be enabled or disabled with systemctl, but it doesn't actually start anything itself. Instead it is used to enable other units. The two related units (rpc-gssd.service and rpc-svcgssd.service) now gain the directive:
Requisite=nfs-secure.target
This means that those services want nfs-secure, and if it isn't already running, they fail. This has exactly the desired effect. After "systemctl enable nfs-secure.target" the GSS daemons will be started when required; after "systemctl disable nfs-secure.target" they will not.
Having four different targets which can selectively be enabled (the fourth being a target similar to nfs-secure.target but which enables the blkmapd daemon to support part of the "pNFS" extension; not needed by most sites) might seem like it is providing too much choice. Here again, systemd comes to the rescue with an easy mechanism for distribution packagers to take some of the things I made optional and make them always enabled. A distribution is encouraged to provide one or more "preset" files listing systemd units that should be automatically enabled whenever they are installed. So if a distribution was focused on high levels of security, it could include:
enable nfs-secure.target
in the preset file. This would ensure that, if nfs-utils were ever installed, the security option would be activated by default. This feature encourages upstream unit file developers to be generous in the number of units that require enabling, being confident that while it provides flexibility to whose who need it, it need not impose a cost on those who don't.
In summary, systemd provides a pleasing range of events and dependencies (many of which we have not covered here) which can be used to start units. It is unfortunate, however, that enabling or disabling of specific units is not at all responsive to the environment files that systemd is quite capable of reading. The choice to not automatically activate any installed unit file is probably a good one, although it is an odd contrast to udev, which is included in the same source package.
Language issues
Having a general interest in programming language design, I couldn't help looking beyond the immediate question of "can I say what I need to say" to the more subjective questions of elegance, uniformity, and familiarity. Is it easy to write good code and hard to write bad code for systemd?
One issue that stuck me as odd, though there is some room for justification, is the existence of section headings such as [Unit] or [Service] or [Install]. These don't really carry any information, as a directive allowed in one section is not allowed in any other, so we always know what a directive means without reference to its section. A justification could be that these help ensure well-structured unit files and thus, help us catch errors more easily.
If that is the case, then it is a little surprising that the concern for error detection doesn't lead to unit files with syntax errors immediately failing so they will be easily noticed. The reasoning here is probably that an imperfectly functioning system is better than one that doesn't boot at all. That is hard to argue against, though, as a programmer, I still prefer errors to fail very loudly — I make too many of them.
More significant than that is the syntax for conditionals. The directive:
ConditionPathExists=/etc/krb5.keytab
will cause activation of the unit to only be attempted if the given file exists. You can easily test for two different files, both of which must exist, with:
ConditionPathExists=/etc/krb5.keytab ConditionPathExists=/etc/exports
or even for a disjunction or 'or' condition:
ConditionPathExists=|/etc/mdadm.conf ConditionPathExists=|/etc/mdadm/mdadm.conf
If you want to get more complicated, you can negate conditions (with a leading !) and have the conjunction of a number of tests together with the disjunction of some other tests. For example:
A and B and (C or D or E)
To achieve this, the A and B conditions are unadorned, while C, D and E each have a '|' prefix. However, you cannot have multiple disjunctions like
(A or B) and (C or D)
Now, I'm not sure I would ever want a conjunction of multiple disjunctions, but it seems worth asking why the traditional infix notation was not used. From reading around, it is clear that the systemd developers want to keep the syntax "simple" so that the unit files can be read by any library that understands the "ini" file format. While this is a laudable goal, it isn't clear that the need for some unspecified program to read the unit files should outweigh the need for humans to read and understand them.
It also doesn't help that while the above rules cover most conditions, they don't cover them all. As already noted, "Requisite" is largely just a condition which might be spelled "ConditionUnitStarted", but isn't; it also doesn't allow the '|' or '!' modifiers.
The final inelegance comes from the ad hoc collection of directives which guide how state changes in one unit should affect state changes in another unit. Firstly, there are 13 directives that identify other units and carry various implications about the relationship — sometimes overlapping, sometimes completely orthogonal:
Requires, RequiresOverridable, Requisite, RequisiteOverridable, Wants, BindsTo, PartOf, Conflicts, Before, After, OnFailure, PropagateReloadsTo, ReloadPropagateFrom
Of these, Before and After are inverses and do not overlap with any others, while Requires, Requisite, and Wants specify dependencies with details that differ on at least two dimensions (active vs passive and hard vs soft). Several, such as PartOf, PropagateReloadsTo, ReloadPropagateFrom, and OnFailure, are not dependencies, but instead specify how an event in one unit should cause an action in another.
Together with these, there are some flags which fine-tune how a unit responds in various circumstances. These include:
StopWhenUnneeded, RefuseManualStart, RefuseManualStop
While there is clearly a lot of expressive power here, there is also a lot of ad-hoc detail which makes systemd harder to learn. I get a strong feeling that there is some underlying model that is trying to get out. If the model were fully understood, the language could be tuned to expose it, and the programmer would more easily select exactly the functionality that is required.
Some small part of the model is that the relationship between two units can be:
- ordered: Before or After or neither;
- active, where one unit will start another, or passive, where it won't;
- dependent, which can take one of three values: no dependence, must have started, or must still be running; and
- overridable, which indicates whether an external request has extra force, or no force at all.
Given that systemd already uses special characters to modify meaning in some directives, it is not hard to come up with a set of characters which could allow all these details, and possibly more, to be specified with a single "DependsOn" directive.
These only really cover the starting of units, and even there, they aren't complete. The model must also include the stopping of units as well as "restart" and "reload" events. Creating a simple model which covers all these aspects without leading to an overly verbose language would be a real boon. Using special characters for all of the different details that would turn up may well cause us to run out of punctuation, but maybe there is some other way to describe the wide range of connections more elegantly.
A pragmatic assessment
While it did feel like a challenge to pull together all the ideas needed to craft a clean and coherent set of unit files, the good news is that (except for one foolish cut-and-paste error) the collection of unit files I created did exactly what I expected on the first attempt. For a program of only 168 lines this might not seem like a big achievement, but, as noted, the fact that only 168 lines were needed is a big part of the value.
These 14 units files are certainly not the end of the story for
nfs-utils. I'm still learning some of the finer details and will
doubtlessly refine these unit files a few times before they go live.
Maybe the most valuable reflection is that I'm far more confident that
this program will do the right thing than I ever could be of the
shell scripts used for SysVinit. Speaking as a programmer: a language that
allows me to say what I want succinctly and gives me confidence that
it will work is a good thing. The various aesthetic issues are minor
compared to that.
Index entries for this article | |
---|---|
GuestArticles | Brown, Neil |
Posted Feb 11, 2014 1:09 UTC (Tue)
by zuki (subscriber, #41808)
[Link] (3 responses)
> "systemctl enable nfs" works, but a subsequent "systemctl start nfs" fails
> "WantedBy" and "RequiredBy" directives, which are quite different from the
The reason that those (overlapping) ways of adding dependencies exist is a combination of two factors. Because it often the "wanted" or "required" service that knows about the dependency. E.g. in case of targets, the list of services that the target "wants" is completely arbitrary, so it cannot be part of the T.target configuration and we want to add something like WantedBy=T.target as part of the service file. But systemd loads units lazily, so if we simply install the unit file, we must make sure that systemd will always load it. This is achieved by creating a symlink in the .wants directory, which will cause systemd to also load the service that the symlink points to when it reads the unit that the .wants directory is for. So the equivalency between different ways of expressing dependencies stated in the previous paragraph is only true when those units have actually been loaded.
Also, without actually looking at the units, it's strange that you use "Requisite=nfs-secure.target" and not "Requires=nfs-secure.target" or maybe "RequiredBy=rpc-gssd.service".
I agree totally with your critique of the multitude of systemd dependency types. They have grown somewhat organically over the years, and it would be good to simplify them at some point. Nevertheless, they were not added lightly, but rather in response to usecases found in the wild which were hard to satisfy with existing vocabulary.
Posted Feb 11, 2014 1:51 UTC (Tue)
by neilbrown (subscriber, #359)
[Link] (1 responses)
Clearly that section could have been clearer - it was even less clear before the lwn editorial team helped out.
The context was intended to imply that "systemctl enable nfs" was being run with "nfs" as a SysVinit script (/etc/init.d/nfs), which is how nfs is currently started on openSUSE-13.1. systemd can read SysVinit scripts and parse the LSB headers, but there is no way for those headers to have the equivalent of "Require=rpcbind.service". Only the "After=rpcbind.server" bit.
So yes: nfs.service would have those lines, but /etc/init.d/nfs cannot and so the compatibility between systemd and SysVinit is not as great as I originally hoped.
> There are two places where WantedBy/RequiredBy can be used.
"Citation needed". I checked the man pages, read the source code, and performed as simple test and I find that "WantedBy" is only permitted in "Install", never in "Unit".
However ... the internal implementation details of systemd involves creating reflections of some (or maybe all) relationships. When one unit "Wants" another, then the internal representation of the other gets a "WantedBy" annotation referring to the first. Similarly there is "ConsistsOf" which is a reflection of "PartOf". These are internal only and not part of the language. "ConsistsOf" is not permitted anywhere in unit files, and "WantedBy" is only permitted in the [Install] section with the meaning I outline.
I don't agree with your description of how the syslinks in the .wants directory are handled. It is best to understand them as being exactly like drop-in files - they are even handled by code in load-dropin.c. A symlink in the .wants directory is *extemely* similar to a .conf file in the ".d" drop-in directory containing "Wants=foo"
Thanks for your comments.
Posted Feb 11, 2014 21:46 UTC (Tue)
by zuki (subscriber, #41808)
[Link]
> I don't agree with your description of how the syslinks in the .wants
Posted Feb 11, 2014 11:10 UTC (Tue)
by johannbg (guest, #65743)
[Link]
The main problem with NFS in Fedora is and always has been it's maintainer Steve which chose on several occasion to ignore comments made by upstream systemd developer ( like Kay's first comment on that bug ) submitted units and even half implement provided units ( he cherry picked units from the provided set of units which left the entire dependency chain broken ) .
Posted Feb 11, 2014 11:00 UTC (Tue)
by gerdesj (subscriber, #5446)
[Link]
You have performed a near miracle in getting NFS to work within systemd-ese. I have struggled to get my Gentoo laptop running everything correctly for similar reasons that you mention but alas I lack your insight and skills (I can manage man pages but the source makes my eyes bleed)
That said, it works really well and I binned OpenRC on it a few months ago. I also find the short descriptive units easy to get on with. In many cases nearly all the same functionality of the original takes a few simple lines rather than the monster rc scripts. Plus socket/port activation means that I only start stuff when I use it, which is really nice and a lot neater than using xinetd.
Again, thanks for explaining some concepts that I was struggling with.
Cheers
Posted Feb 11, 2014 12:46 UTC (Tue)
by cesarb (subscriber, #6266)
[Link] (2 responses)
Let's see if I understood this correctly. Upstart's behavior is like COME FROM, while systemd's is more like GO TO.
Posted Feb 11, 2014 13:34 UTC (Tue)
by hummassa (subscriber, #307)
[Link] (1 responses)
Not that COME FROM is totally useless (no GUI-based programming without it).
Posted Feb 14, 2014 21:15 UTC (Fri)
by giraffedata (guest, #1954)
[Link]
The Upstart philosophy is the "multiuser" unit means the user has authorized or requested multiuser service. NFS is appropriate only in multiuser service, so NFS depends upon multiuser. The Systemd philosophy is that the multiuser unit refers to the system providing the multiuser service. You can't claim to providing multiuser service if you aren't providing NFS, so multiuser depends upon NFS.
The Systemd definition of multiuser seems more useful and easy to understand to me.
Here's an analogy: a house is inhabitable only if the heat is on, but it's wasteful to heat an uninhabited house. So you could say inhabitability depends upon the heat being on and therefore the landlord should turn on the heat before signing a lease. Or you could say the appropriateness of the heat being on depends upon the house being inhabited, so the furnace should turn on only when it detects that a lease has been signed.
Posted Feb 11, 2014 16:38 UTC (Tue)
by Siosm (subscriber, #86882)
[Link] (2 responses)
Well, only upstream can answer that. You should ask on the systemd-devel mailing list.
Posted Feb 11, 2014 18:38 UTC (Tue)
by cesarb (subscriber, #6266)
[Link] (1 responses)
(I might or might not be joking.)
Posted Feb 11, 2014 20:47 UTC (Tue)
by Siosm (subscriber, #86882)
[Link]
That's absolutely not what the author meant :
This would be one time process for "rpc-sockets" which is really close to the already include socket activation. This could be added as an option to the current socket unit I think.
Posted Feb 13, 2014 21:39 UTC (Thu)
by ocharles (guest, #83568)
[Link]
Posted Feb 14, 2014 18:45 UTC (Fri)
by mathstuf (subscriber, #69389)
[Link] (4 responses)
I think the root reason is because not all sections are allowed in all unit files. .socket files don't have a [Service] section, so anything that belongs under it doesn't belong because it doesn't make sense.
Also, from systemd.socket(5):
> Socket files must include a [Socket] section, which carries information about the socket or FIFO it supervises. A number of options that may be used in this section are shared with other unit types. These options are documented in systemd.exec(5) and systemd.kill(5). The options specific to the [Socket] section of socket units are the following:
So it does appear that the certain directives are valid in multiple sections.
Posted Feb 14, 2014 21:29 UTC (Fri)
by neilbrown (subscriber, #359)
[Link] (3 responses)
Clearly Exec{Start,Stop}{Pre,Post} (and multiple others such as WorkingDirectory) are permitted in both the [Service] section and the [Socket] section. However they have the same meaning in both sections, and no unit file can have both sections, so there would still be no ambiguity if the section headings were absent. The precise meaning is determined by the suffix of the unit file.
(and I did wonder why those "multiple others" were not in an [Exec] section, seeing they are documented in systemd.exec - there is some fancy m4 preprocessor code to duplicate a collection of Directives across multiple sections in src/core/load-fragment-gperf.gperf.m4)
Posted Feb 15, 2014 17:29 UTC (Sat)
by mbunkus (subscriber, #87248)
[Link]
My guess is that it's more about future extensibility without breaking compatibility. While it may be true that there are no conflicts today doesn't mean they won't invent features that allow multiple sections with the same option names. These can be added easily with new sections, but if there were no sections then they might be forced to chose awkward names or prefix quite a lot of those new options, neither or which would improve the ease of use.
Posted Feb 20, 2014 17:54 UTC (Thu)
by cg909 (guest, #95647)
[Link] (1 responses)
Directives in [Unit] apply to the dependeny tree and define general properties of the unit.
Sections like [Exec], [Kill], ... would only group some related directives without providing context. Currently it would also split the execution environment directives and the Exec, ExecStartPre, etc. directives into different sections.
Posted May 28, 2014 23:00 UTC (Wed)
by Duncan (guest, #6647)
[Link]
This.
When invoking systemctl enable/disable, systemctl/systemd only has to look at [install], other sections can be ignored.
Similarly, when systemd is constructing its dependency tree, it only has to look at the [unit] section, [install] and [service], etc, sections can be ignored. And when it's actually invoking the unit, only the [service], [socket], etc, sections as appropriate, must be considered, [install] and [unit] can be ignored.
While I've no idea whether systemd is actually coded this way, from back in my MS days I know their ini-file APIs were setup to work exactly that way. The API allowed you to open a particular ini file, then specify section and key (IIRC they used the term "value", which always confused me) to return or set, with its value (which they termed "data", as "value" referred to the key) then returned or set. Other sections might as well not have existed at all, and in fact, could belong to entirely different applications (as was the case in MS Windows 2.x I believe, when all sorts of apps had sections in win.ini, before 3.x introduced dedicated application ini files).
So access is (at least conceptually) by section and then key, and if key names don't overlap between sections, it's only to avoid human confusion, not because they couldn't, as to the application, if they're in different sections they are (or should be) entirely different things, regardless of what they're named.
Duncan
Posted Feb 20, 2014 11:12 UTC (Thu)
by kevinm (guest, #69913)
[Link] (2 responses)
The dependencies are quite static and rarely changed, presumably set by upstream and tweaked by the builder of your distribution. However services may be enabled and disabled frequently as a matter of administrative fiat.
Posted Feb 20, 2014 14:30 UTC (Thu)
by mathstuf (subscriber, #69389)
[Link]
Posted Feb 20, 2014 17:03 UTC (Thu)
by cg909 (guest, #95647)
[Link]
In the systemd concept every service that is known to systemd *may* be started if its needed (and is not masked).
systemctl enable $service can be read as "Make sure that $service *will* be run."
So with systemd you have in fact more flexibility: You can leave a service disabled, so that it will run only if required by another unit; you can enable it to let it run in any case and you can mask it to disable it completely.
Systemd programming part 2: activation and language issues
> because rpcbind (which is the new name for portmap) isn't running
Normally, nfs.service would have [Unit] Requires=rpcbind.service, After=rpcbind.service, which would cause rpcbind.service to be started before nfs.service is started. This applies both when nfs.service is started manually, and also when nfs.service is started because it is requires by some target (e.g. nfs.target, which is in turn wanted by multi-user.target, which is in turn wanted by default.target).
> "Requires" and "Wants" etc. dependency directives. "WantedBy" plays no role
> in determining when to start (or stop) any service. Instead, it is an
> instruction on how to enable a specific unit.
There are two places where WantedBy/RequiredBy can be used. In the [Install] section, they behave like you describe, i.e. they are used to create links when 'systemctl enable' is invoked. In the [Unit] section, they are simply Wants/Requires in the reverse direction. For this latter use, there's no difference between having Wants=B.service in A.service, having WantedBy=A.service in B.service, or having a symlink to B.service created as /etc/systemd/system/A.service.wants/B.service when systemd has loaded all the units.
Systemd programming part 2: activation and language issues
Systemd programming part 2: activation and language issues
> directory are handled. It is best to understand them as being exactly like
> drop-in files - they are even handled by code in load-dropin.c. A symlink
> in the .wants directory is *extemely* similar to a .conf file in the ".d"
> drop-in directory containing "Wants=foo"
I guess I wasn't very clear. You're right that the symlink is very similar and could be replaced by a drop-in. I was trying to underline the fact that you need the symlink (or the equivalent drop-in), because the configuration has to become a part of the "wanting" unit, even if is installed together with the "wanted" unit. No disagreement, just a different vantage point.
Systemd programming part 2: activation and language issues
Systemd programming part 2: activation and language issues
Jon
COME FROM
COME FROM
The dependency declaration looks backwards only if you look at the meaning of "multiuser" backwards.
COME FROM
Systemd programming part 2: activation and language issues
Systemd programming part 2: activation and language issues
Systemd programming part 2: activation and language issues
> bind an arbitrary port, register that port with rpcbind
Systemd programming part 2: activation and language issues
Systemd programming part 2: activation and language issues
Systemd programming part 2: activation and language issues
thanks for highlighting that. It is a relevant example that I hadn't fully explored.
Systemd programming part 2: activation and language issues
Systemd programming part 2: activation and language issues
Directives in [Install] are only used when running systemctl enable/disable and have no other direct effect.
Directives in [Service], [Socket], ... define the behaviour when the unit is run. And as the allowed directives are different between unit types the sections also are named differently. This little redundancy may also help catching copy&paste errors between unit files.
Systemd programming part 2: activation and language issues
Systemd programming part 2: activation and language issues
Systemd programming part 2: activation and language issues
Systemd programming part 2: activation and language issues
systemctl mask $service
That tells systemd that this service should never run.