2018-03-22

Managing leap-seconds on NTP Servers

On all of your NTP servers it is a good idea to keep track of leap seconds. This is done by using the leap-seconds.list file available from IETF (and others).

Using CRON
Add the following to the /etc/ntp.conf file: leapfile /var/lib/ntp/leap-seconds.list
Now restart the ntp daemon and run: # ntptime
The current difference between UTC and International Atomic Time (TAI) is 37 seconds - TAI is ahead of UTC by this amount, so the output of the above should contain a line similar to the following:
maximum error 436 us, estimated error 6 us, TAI offset 37
To keep the leap-seconds.list file updated, check the file regularly (once a month, as the leap-seconds.list file will be updated almost 6 months ahead of the actual date of the leap second). This can be done using the update-leap command and the following cron script, so add this script to /etc/cron.monthly as e.g. update-leap:

#!/bin/sh
#
# leap-seconds.list file download cron monthly
set -e
# if leap-seconds file exist check if new available
if [ -f /var/lib/ntp/leap-seconds.list ]; then
# Log start of checking for updated leap-seconds.list file from IETF.
# Not that update-leap does not like HTTPS :(
/usr/bin/logger "checking for updated leap seconds file" -t "leap"
# Run update-leap, grep the INFO: line (it throws a lot of garbage at us), remove INFO: and log the output
/usr/bin/update-leap -f /etc/ntp.conf -s http://www.ietf.org/timezones/data/leap-seconds.list -d /var/lib/ntp/leap-seconds.list 2>%1 | grep -i info | sed 's/.*: //' | /usr/bin/logger -t "leap" &
fi
exit 0

Then:
#chmod 755 /etc/cron.monthly/update-leap
#touch /var/lib/ntp/leap-seconds.list
The touch command creates an empty file, which is needed for the first run as the script above doesn’t do anything if there is no file present. if [ -f /var/lib/ntp/leap-seconds.list ]
Now test-run the script:/etc/cron.monthly/update-leap
And check that it ran, using # grep -i leap: /var/log/syslog
If this is the first it runs (with an empty leap-seconds.list file) or there is a newer file, your output should be similar to the following:

Jan 22 21:39:56 ntpserver leap: checking for updated leap seconds file
Jan 22 21:39:57 ntpserver leap: Download of http://www.ietf.org/timezones/data/leap-seconds.list succeeded

If there’s no update to the file, the output should look similar to the following:

Jan 22 19:00:48 ntpserver leap: checking for updated leap seconds file
Jan 22 19:00:48 ntpserver leap: Not time to replace /var/lib/ntp/leap-seconds.list

Please note that the ntp daemon checks daily for updates to the leapfile, so there is no need to restart it after updating the file.
In order not to overwhelm the IETF server with the leap-seconds.list file, copy the file to a central location on-site and let the NTP servers fetch it from there. Something like
Cron job on central server:

.
.
/usr/bin/update-leap -f /etc/ntp.conf -s http://www.ietf.org/timezones/data/leap-seconds.list -d /var/www/ntp/leap-seconds.list 2>%1 | grep -i info | sed 's/.*: //' | /usr/bin/logger -t "leap" &
.
.

Cron job on NTP servers:

.
.
/usr/bin/update-leap -f /etc/ntp.conf -s http://internalwebserver/ntp/leap-seconds.list -d /var/www/ntp/leap-seconds.list 2>%1 | grep -i info | sed 's/.*: //' | /usr/bin/logger -t "leap" &
.
.

The above works for the reference implementation of NTP (http://www.ntp.org/), if you’re running ntpsec, use ntpleapfetch instead, and adjust the logging output to match.
And before you ask, I hate leap seconds almost as much as DST 😊

Using systemd timers

Update 2019-07-18: Go to https://github.com/martinboller/update-leap for a script to install NTP and update-leap.

Instead of good ol’ CRON, on systemd based systems, you can do the following.
Add the update-leap script as /usr/local/bin/update-leap, then create a service file and a timer file.
Please note that systemd timers do not like the cleanup and redirection, so remove that, so your script looks like this:
#!/bin/sh
#
# leap-seconds.list file download cron monthly
set -e
# if leap-seconds file exist check if new available
if [ -f /var/lib/ntp/leap-seconds.list ]; then
# Log start of checking for updated leap-seconds.list file from IETF.
# Not that update-leap does not like HTTPS :(
/usr/bin/logger "checking for updated leap seconds file" -t "update-leap"
# Run update-leap
/usr/bin/update-leap -f /etc/ntp.conf -s http://www.ietf.org/timezones/data/leap-seconds.list -d /var/lib/ntp/leap-seconds.list
fi
exit 0


Service File
The service (as well as the timer file) location depends on the distro, for Debian they are in /lib/systemd/system/ (on Arch, /usr/lib/systemd/system). Do not add them to /etc/systemd/ those are for systemd itself.
update-leap.service
# service file running update-leap
# triggered by update-leap.timer
[Unit]
Description=service file running update-leap
Documentation=man:update-leap
[Service]
ExecStart=/usr/local/bin/update-leap

Timer File
The timer file, goes in the same directory as the service file above.
update-leap.timer
# runs update-leap monthly.
[Unit]
Description=Monthly job to check for updated leap-seconds.list file
Documentation=man:update-leap
[Timer]
# Don't run for the first 15 minutes after boot
OnBootSec=15min
# Run monthly
OnCalendar=Monthly
# Specify service
Unit=update-leap.service
[Install]
WantedBy=multi-user.target

Configuring the timer to run
For timers you do not enable the service, but the timer.
As root:
# systemctl enable update-leap.timer
# systemctl start update-leap.timer
To make sure everything works, you can start the service
# systemctl restart update-leap.service
Then check syslog for update-leap entries as discussed above

Note: This post first appeared on peerlyst

References:
http://www.ntp.org/
https://www.eecis.udel.edu/~mills/leap.html
http://tycho.usno.navy.mil/leapsec.html
https://hpiers.obspm.fr/iers/bul/bulc/bulletinc.dat (no leap second for June 2018)
https://developers.google.com/time/smear (Interesting approach to handling the leap-second at Google)
https://www.ntpsec.org

No comments: