#1441 Packaging: Practices for Migration of cron jobs to systemd timer units
Closed None Opened 8 years ago by thozza.

Note: This ticket is '''not''' about migration of all cron files to timer units in Fedora!

= phenomenon =
Previously, if package installed a cron job, it got run based on the configuration without any further effort. If the maintainer migrates the cron job to systemd timer unit, the unit will not be enabled by default if not included in system presets. To mimic the previous behavior it requires to create a bugzilla and change in another component containing presets.

= background analysis =
Currently packages in Fedora can ship cron files following the [https://fedoraproject.org/wiki/Packaging:CronFiles Packaging Guidelines]. When some package installs cron file, cron daemon will automatically run the job next time.

This is not the case with timer units, since there are the same rules applying to them as to regular systemd service units. This means, they are '''not''' enabled by default (unless included in default presets) and are '''not''' started by default (unless done manually in SPEC) after installation. Also on update of the cron file, cron daemon automatically detects the change and reloads it. The timer unit is '''not''' reloaded on update automatically and needs to be explicitly restarted after package update.

Also Fedora Packaging Guidelines don't contain any rules on how to package and use timer units.

= implementation recommendation =
To ease the migration from cron files to systemd timer units:
1. All timer units should be enabled by default in default presets (AFAIK it is possible to use wildcard entry for this).
2. systemd %systemd_post scriptlet should check the argument and if it is a timer unit, it should start it automatically on install. Other possibility is to advise to use explicit start in SPEC.
3. %systemd_postun_with_restart should be also used for the timer unit in SPEC, to ensure any changes made to it by update are used.
4. When migrating to timer unit, SPEC should include trigger script ensuring that the timer is started the first time on update from previous version with cron job.
5. It would be nice to have some entry regarding timer units in Packaging Guidelines (points 2-4 should be described there)

I'm willing to help with this and coordinate.


I would like FESCo to consider if the proposed implementation steps are OK and that we really want all timer units in Fedora to be enabled by default and started after the installation (as it is the case with cron jobs at this moment).

Replying to [ticket:1441 thozza]:

= implementation recommendation =
To ease the migration from cron files to systemd timer units:
1. All timer units should be enabled by default in default presets (AFAIK it is possible to use wildcard entry for this).

Has an investigation been done about this to determine if there are any existing packages in the collection that have timers that '''should not''' be enabled by default? Because this would suddenly start them all.

  1. systemd %systemd_post scriptlet should check the argument and if it is a timer unit, it should start it automatically on install. Other possibility is to advise to use explicit start in SPEC.

This makes sense assuming we agree with 1. above, which I'm unsure of at the moment.

  1. %systemd_postun_with_restart should be also used for the timer unit in SPEC, to ensure any changes made to it by update are used.
  2. When migrating to timer unit, SPEC should include trigger script ensuring that the timer is started the first time on update from previous version with cron job.

How is this different from 2. above? If we're starting it every time, why have a special case for update from cron?

  1. It would be nice to have some entry regarding timer units in Packaging Guidelines (points 2-4 should be described there)

Right, whatever is decided here needs to be codified in the guidelines.

I'm willing to help with this and coordinate.

== Alternative Implementation ==
We could add guidelines requiring the packager to drop a file into {{{/usr/lib/systemd/system-preset/}}} of the form {{{50-$packagename.preset}}}. This file would contain the following content:
{{{

Enable timer units for $packagename

enable <something>.timer
enable <somethingelse>.timer
}}}

After that, they could manually start the appropriate timers in the %post script as described above.

I think this approach is more versatile, as it allows people to still ship potentially disabled-by-default timers.

Agreed that the Packaging guidelines should be updated.

A quick look at /usr/lib/systemd/*.timer suggests that enabling all timer units by default would not be a good idea though:

{{{
$ ls -1 /usr/lib/systemd/system/*.timer
/usr/lib/systemd/system/dnf-makecache.timer ← a candidate to enable by default
/usr/lib/systemd/system/yum-makecache.timer ← a candidate to enable by default
/usr/lib/systemd/system/fstrim.timer ← dangerous to enable by default
/usr/lib/systemd/system/mdadm-last-resort\@.timer ← ???
/usr/lib/systemd/system/sysstat-collect.timer ← should not be enabled by default
/usr/lib/systemd/system/sysstat-summary.timer ← should not be enabled by default
/usr/lib/systemd/system/systemd-tmpfiles-clean.timer ← already enabled by default
}}}

This is on F21... As the number of timer units grows, the number of timer units which should not be enabled by default will certainly grow. Even if they are a minority, I think it is better to keep the policy consistent, and require explicit activation as for other units.

Alternative implementation
Yeah, that should work.

I ran into this with the spamassassin timer unit, and I thought adding a Wants=foobar.timer in the main service unit that used it and a WantedBy=foobar.service got around this issue?

(There is a f21 bug around this so apparently it doesn't work in all cases: https://bugzilla.redhat.com/show_bug.cgi?id=1218999 )

Replying to [comment:5 kevin]:

I ran into this with the spamassassin timer unit, and I thought adding a Wants=foobar.timer in the main service unit that used it and a WantedBy=foobar.service got around this issue?

Yeah, it should. I replied in the bug more extensively, but I think the case of spamassassin is different because sa-update.timer should run only when spamassassin.service is active, iiuc. Those rules that are discussed here apply more to timer units which are not subordinate to another unit.

Replying to [comment:3 sgallagh]:

Replying to [ticket:1441 thozza]:

= implementation recommendation =
To ease the migration from cron files to systemd timer units:
1. All timer units should be enabled by default in default presets (AFAIK it is possible to use wildcard entry for this).

Has an investigation been done about this to determine if there are any existing packages in the collection that have timers that '''should not''' be enabled by default? Because this would suddenly start them all.

I'm sure there are such cases. My proposal only copies the previous behavior of cron jobs in Fedora. But given the new possibilities of timer units, it may not be the best idea.

  1. systemd %systemd_post scriptlet should check the argument and if it is a timer unit, it should start it automatically on install. Other possibility is to advise to use explicit start in SPEC.

This makes sense assuming we agree with 1. above, which I'm unsure of at the moment.

To clarify, I only meant new installations, not package updates.

  1. %systemd_postun_with_restart should be also used for the timer unit in SPEC, to ensure any changes made to it by update are used.
  2. When migrating to timer unit, SPEC should include trigger script ensuring that the timer is started the first time on update from previous version with cron job.

How is this different from 2. above? If we're starting it every time, why have a special case for update from cron?

OK, I was not clear enough in the 2.. I meant that the start be added only for new installs of the package, so it does not start the timer in case the package was previously installed, but the timer was stopped.

The case 4. describes a situation when:
package is already installed
older version shipped cron job which was run every time based on the configuration
* after the upgrade, the timer unit is not started by default (and should not be to prevent starting previously stopped timer), thus there is need for trigger scriptlet for specific version. This is similar to the need to run systemd-sysv-convert once on update from package version with init script to version with systemd service file.

Hope you can now understand what I meant.

  1. It would be nice to have some entry regarding timer units in Packaging Guidelines (points 2-4 should be described there)

Right, whatever is decided here needs to be codified in the guidelines.

I'm willing to help with this and coordinate.

== Alternative Implementation ==
We could add guidelines requiring the packager to drop a file into {{{/usr/lib/systemd/system-preset/}}} of the form {{{50-$packagename.preset}}}. This file would contain the following content:
{{{

Enable timer units for $packagename

enable <something>.timer
enable <somethingelse>.timer
}}}

After that, they could manually start the appropriate timers in the %post script as described above.

I think this approach is more versatile, as it allows people to still ship potentially disabled-by-default timers.

I agree. This is definitely better approach than enabling them all.

Replying to [comment:6 zbyszek]:

Replying to [comment:5 kevin]:

I ran into this with the spamassassin timer unit, and I thought adding a Wants=foobar.timer in the main service unit that used it and a WantedBy=foobar.service got around this issue?

Yeah, it should. I replied in the bug more extensively, but I think the case of spamassassin is different because sa-update.timer should run only when spamassassin.service is active, iiuc. Those rules that are discussed here apply more to timer units which are not subordinate to another unit.

Right, my intentions with this ticket are to start a discussion and cover mainly packages that previously included cron job and are migrating to timer unit, which should be run even if the main service is not running.

Example:
Unbound comes with a cron job which daily checks the DNSSEC key used by root zone and updates it if needed. However the cron job needs to be run even if the Unbound server is not running, since the key is used also by libunbound library, which can be used by anything.

Cron job worked just fine. To get the same behavior with timer units, it is not that trivial (as also noted [https://bugzilla.redhat.com/show_bug.cgi?id=1218999#c6 in SA bug]. Therefore I think we should think about this and have some Guidelines how to do it properly.

Actually there shouldn't be much difference between a service which is started by default and timer which is started by default. In systemd they can and should be handled in exactly the same way. So it would seem that we should just extend existing policy for services to timers. But there's a problem: existing policy is somewhat vague.

Currently we have:
- https://fedoraproject.org/wiki/Starting_services_by_default
- https://fedoraproject.org/wiki/Packaging:ScriptletSnippets#Systemd

Those documents make it obvious how to deal with services which should not be started by default (nothing to do) and how to deal with services which got a fesco exception to start by default (put in 90-default.preset). But the middle area, i.e. services which can and want to be started by default, is not covered: there is no specific implementation suggested.

I think the "alternative implementation" suggested by sgallagh should be extended to cover all types of units (service, timer, but any other type too if necessary). This would give as a consistent and clear mechanism.

Replying to [comment:9 zbyszek]:

Actually there shouldn't be much difference between a service which is started by default and timer which is started by default. In systemd they can and should be handled in exactly the same way. So it would seem that we should just extend existing policy for services to timers. But there's a problem: existing policy is somewhat vague.

Currently we have:
- https://fedoraproject.org/wiki/Starting_services_by_default
- https://fedoraproject.org/wiki/Packaging:ScriptletSnippets#Systemd

Those documents make it obvious how to deal with services which should not be started by default (nothing to do) and how to deal with services which got a fesco exception to start by default (put in 90-default.preset). But the middle area, i.e. services which can and want to be started by default, is not covered: there is no specific implementation suggested.

I think the "alternative implementation" suggested by sgallagh should be extended to cover all types of units (service, timer, but any other type too if necessary). This would give as a consistent and clear mechanism.

I'm not for allowing packages to ship presets also for services. I can understand that it would simplify the mechanisms, but I still think that distro should have influence on which services are started by default. Given that I could agree with sgallagh's "alternative implementation" to be extended to any types of units if it would still require FESCo approval for shipping preset for regular service.

With timers I think the situation is different in a way, that if implemented as cron job, these are started and enabled (in systemd way) by default even now. Therefore I think that the policy on enabling timer units should be less strict and not forcing unnecessary burden on the maintainer.

Just to clarify: do you think the permission to start services by default (if they satisfy the criteria) should be rescinded and FESCo approval should be necessary for every service?

Replying to [comment:11 zbyszek]:

Just to clarify: do you think the permission to start services by default (if they satisfy the criteria) should be rescinded and FESCo approval should be necessary for every service?

Sorry for any confusion. I meant the policy for services to stay as it is now.

My recommendations would be:

  • If there's a primary service unit contained in a package, then make sure that any auxiliary .timer unit is implicitly started by it, by defining a Wants= dependency from the primary service unit to the timer unit, and a PartOf= dependency the other way. This should apply to services like some daemon which cleans up its logs via a timer unit, or so, where the cleanup really only needs to happen if the daemon is running too. In this case, only the primary unit should be added to the preset file.

  • If there's a primary service unit contained in a package, but the first recommendation doesn't apply, because the timer unit should run always, and not only if the primary service unit is running, then add an [Install] section to the primary service unit with an Also= field that points to the timer, and then add an [Install] section to the timer too (with WantedBy=timers.target or so). That way, if the main daemon is enabled the timer is enabled too, but after that they are mostly independent. In this case, only the primary unit should be added to the preset file.

  • Finally, if there's no primary service unit in the package, then the timer units should stand on their own, and should be added to the preset file.

Replying to [comment:14 lennart]:

My recommendations would be:

  • If there's a primary service unit contained in a package, then make sure that any auxiliary .timer unit is implicitly started by it, by defining a Wants= dependency from the primary service unit to the timer unit, and a PartOf= dependency the other way.
    In this case, only the primary unit should be added to the preset file.

Ack.

  • If there's a primary service unit contained in a package, but the first recommendation doesn't apply, because the timer unit should run always, and not only if the primary service unit is running, then add an [Install] section to the primary service unit with an Also= field that points to the timer, and then add an [Install] section to the timer too (with WantedBy=timers.target or so).

In this case, only the primary unit should be added to the preset file.

The issue with this approach is that enable/disable operations on the main unit also work on the timer. Of course it is possible to explicitly re-enable the timer unit after disabling the main unit, but this seems like a trap for the unwary. I think is better to recommend separate [Install] section and two separate presets.

  • Finally, if there's no primary service unit in the package, then the timer units should stand on their own, and should be added to the preset file.

Right. The question is to which preset file: 90-default.presets, or a custom one. Either approach should work, but one is more centralized, while the other is decentralized.

Replying to [comment:15 zbyszek]:

  • If there's a primary service unit contained in a package, but the first recommendation doesn't apply, because the timer unit should run always, and not only if the primary service unit is running, then add an [Install] section to the primary service unit with an Also= field that points to the timer, and then add an [Install] section to the timer too (with WantedBy=timers.target or so).

In this case, only the primary unit should be added to the preset file.

The issue with this approach is that enable/disable operations on the main unit also work on the timer. Of course it is possible to explicitly re-enable the timer unit after disabling the main unit, but this seems like a trap for the unwary. I think is better to recommend separate [Install] section and two separate presets.

Sure, sounds OK to me, too.

  • Finally, if there's no primary service unit in the package, then the timer units should stand on their own, and should be added to the preset file.

Right. The question is to which preset file: 90-default.presets, or a custom one. Either approach should work, but one is more centralized, while the other is decentralized.

Custom one? I am very sure we should centralize things in a single preset file for all units, that is part of fedora-release.

presets should be configurable before you install packages, hence it's pointless to ship them in the individual RPMs: admins should be able to look at the default Fedora policy, and then make adjustments to it, before they install the RPMs. If they first have to install the RPM, then the entire exercise would be pointless...

Replying to [comment:16 lennart]:

  • Finally, if there's no primary service unit in the package, then the timer units should stand on their own, and should be added to the preset file.

Right. The question is to which preset file: 90-default.presets, or a custom one. Either approach should work, but one is more centralized, while the other is decentralized.

Custom one? I am very sure we should centralize things in a single preset file for all units, that is part of fedora-release.

presets should be configurable before you install packages, hence it's pointless to ship them in the individual RPMs: admins should be able to look at the default Fedora policy, and then make adjustments to it, before they install the RPMs. If they first have to install the RPM, then the entire exercise would be pointless...

OK. For me this is a convincing argument. Allowing individual rpms to carry their own configuration would makes things simpler for maintainers, but the benefit to the admin of having central configuration is worth the trouble.

Replying to [comment:17 zbyszek]:

Replying to [comment:16 lennart]:

  • Finally, if there's no primary service unit in the package, then the timer units should stand on their own, and should be added to the preset file.

Right. The question is to which preset file: 90-default.presets, or a custom one. Either approach should work, but one is more centralized, while the other is decentralized.

Custom one? I am very sure we should centralize things in a single preset file for all units, that is part of fedora-release.

presets should be configurable before you install packages, hence it's pointless to ship them in the individual RPMs: admins should be able to look at the default Fedora policy, and then make adjustments to it, before they install the RPMs. If they first have to install the RPM, then the entire exercise would be pointless...

OK. For me this is a convincing argument. Allowing individual rpms to carry their own configuration would makes things simpler for maintainers, but the benefit to the admin of having central configuration is worth the trouble.

For any units except timer units I agree. However if the maintainer is migrating cron jobs to timer units, this seems like an unnecessary burden, since cron jobs were "enabled and stared" by default before.

E.g. I migrated unbound-libs to use timer units and the bug for adding it to presets (https://bugzilla.redhat.com/show_bug.cgi?id=1215641) has been setting there for almost a month.

Should the maintainer of such package wait with build and update for another package? Or should the maintainer rather cause a regression? In this situation the whole process seems like unnecessary "paperwork" to me.

Replying to [comment:18 thozza]:

For any units except timer units I agree. However if the maintainer is migrating cron jobs to timer units, this seems like an unnecessary burden, since cron jobs were "enabled and stared" by default before.

Well, I am sure it would be great to provide the admin with a unified way to control whether packaged code is run, and that means we make no distinction between unit types on how they are enabled.

E.g. I migrated unbound-libs to use timer units and the bug for adding it to presets (https://bugzilla.redhat.com/show_bug.cgi?id=1215641) has been setting there for more than a month.

Should the maintainer of such package wait with build and update for another package? Or should the maintainer rather cause a regression? In this situation the whole process seems like unnecessary "paperwork" to me.

Well, I think a great way to improve this would be to move .preset management to a different package, how we already offered it before, and give this in the hands of a maintainer of its own.

But I think we shouldn't sacrifice uniformity for the admin for the fact that some package changes take more time than we hope.

Replying to [comment:19 lennart]:

Replying to [comment:18 thozza]:

For any units except timer units I agree. However if the maintainer is migrating cron jobs to timer units, this seems like an unnecessary burden, since cron jobs were "enabled and stared" by default before.

Well, I am sure it would be great to provide the admin with a unified way to control whether packaged code is run, and that means we make no distinction between unit types on how they are enabled.

E.g. I migrated unbound-libs to use timer units and the bug for adding it to presets (https://bugzilla.redhat.com/show_bug.cgi?id=1215641) has been setting there for more than a month.

Should the maintainer of such package wait with build and update for another package? Or should the maintainer rather cause a regression? In this situation the whole process seems like unnecessary "paperwork" to me.

Well, I think a great way to improve this would be to move .preset management to a different package, how we already offered it before, and give this in the hands of a maintainer of its own.

I proposed to move it to fedora-release last week and it has been already included in it in rawhide, see:

https://bugzilla.redhat.com/show_bug.cgi?id=1221339

https://bugzilla.redhat.com/show_bug.cgi?id=1221340

But I think we shouldn't sacrifice uniformity for the admin for the fact that some package changes take more time than we hope.

I think your point is also valid and makes sense.

I would like to see also input from others on this.

From today's fesco meeting:

  • AGREED: packages in fedora have their default timer unit settings
    managed by system presets and not by their providing package (+6,
    -0) (ajax, 18:28:53)
  • timer unit settings recommendation to be double-checked with fpc
    (ajax, 18:29:25)
  • LINK: https://fedoraproject.org/wiki/Starting_services_by_default
    also should be updated to reflect new reality. Apart from the
    obvious s/systemd/fedora-release/, both services and timers which
    require or not FESCo exception need to go through the global presets
    file. (zbyszek, 18:29:47)
  • sgallagh to bring timer unit issue to fpc (ajax, 18:30:13)
  • ACTION: sgallagh to work with FPC on updating
    https://fedoraproject.org/wiki/Starting_services_by_default
    (sgallagh, 18:30:17)

Reopening for one additional clarification.

When I revised the guidelines, I made one change that I thought was a minor clarification, but that turned out to have subtle effects that we should discuss.

The thread discussing it on devel@ begins here: https://lists.fedoraproject.org/pipermail/devel/2015-May/210768.html

In short, FESCo should decide on whether it is permissible for services that start a local TCP socket to be enabled by default without FESCo approval, or if there is sufficient risk posed by potential privilege escalation to treat it differently from a local UNIX socket or D-BUS service.

agreed Rephrase this line as "If a service does not require configuration to be functional and does not listen on a network socket for connections originating on a separate physical or virtual machine" (+5,-1,1)

Login to comment on this ticket.

Metadata