mirror of
https://github.com/systemd/systemd.git
synced 2024-12-25 01:34:28 +03:00
24284098a4
Using a unit match is racy whereas a syslog identifier match is reliable.
409 lines
12 KiB
Bash
Executable File
409 lines
12 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
# SPDX-License-Identifier: LGPL-2.1-or-later
|
|
|
|
set -eux
|
|
set -o pipefail
|
|
|
|
# shellcheck source=test/units/test-control.sh
|
|
. "$(dirname "$0")"/test-control.sh
|
|
# shellcheck source=test/units/util.sh
|
|
. "$(dirname "$0")"/util.sh
|
|
|
|
testcase_timedatectl() {
|
|
timedatectl --no-pager --help
|
|
timedatectl --version
|
|
|
|
timedatectl
|
|
timedatectl --no-ask-password
|
|
timedatectl status --machine=testuser@.host
|
|
timedatectl status
|
|
timedatectl show
|
|
timedatectl show --all
|
|
timedatectl show -p NTP
|
|
timedatectl show -p NTP --value
|
|
timedatectl list-timezones
|
|
|
|
if ! systemd-detect-virt -qc; then
|
|
systemctl enable --runtime --now systemd-timesyncd
|
|
timedatectl timesync-status
|
|
timedatectl show-timesync
|
|
fi
|
|
}
|
|
|
|
restore_timezone() {
|
|
if [[ -f /tmp/timezone.bak ]]; then
|
|
mv /tmp/timezone.bak /etc/timezone
|
|
else
|
|
rm -f /etc/timezone
|
|
fi
|
|
}
|
|
|
|
testcase_timezone() {
|
|
local ORIG_TZ=
|
|
|
|
# Debian/Ubuntu specific file
|
|
if [[ -f /etc/timezone ]]; then
|
|
mv /etc/timezone /tmp/timezone.bak
|
|
fi
|
|
|
|
trap restore_timezone RETURN
|
|
|
|
if [[ -L /etc/localtime ]]; then
|
|
ORIG_TZ=$(readlink /etc/localtime | sed 's#^.*zoneinfo/##')
|
|
echo "original tz: $ORIG_TZ"
|
|
fi
|
|
|
|
echo 'timedatectl works'
|
|
assert_in "Local time:" "$(timedatectl --no-pager)"
|
|
|
|
echo 'change timezone'
|
|
assert_eq "$(timedatectl --no-pager set-timezone Europe/Kyiv 2>&1)" ""
|
|
assert_eq "$(readlink /etc/localtime | sed 's#^.*zoneinfo/##')" "Europe/Kyiv"
|
|
if [[ -f /etc/timezone ]]; then
|
|
assert_eq "$(cat /etc/timezone)" "Europe/Kyiv"
|
|
fi
|
|
assert_in "Time zone: Europe/Kyiv \(EES*T, \+0[0-9]00\)" "$(timedatectl)"
|
|
|
|
if [[ -n "$ORIG_TZ" ]]; then
|
|
echo 'reset timezone to original'
|
|
assert_eq "$(timedatectl set-timezone "$ORIG_TZ" 2>&1)" ""
|
|
assert_eq "$(readlink /etc/localtime | sed 's#^.*zoneinfo/##')" "$ORIG_TZ"
|
|
if [[ -f /etc/timezone ]]; then
|
|
assert_eq "$(cat /etc/timezone)" "$ORIG_TZ"
|
|
fi
|
|
fi
|
|
}
|
|
|
|
restore_adjtime() {
|
|
if [[ -e /etc/adjtime.bak ]]; then
|
|
mv /etc/adjtime.bak /etc/adjtime
|
|
else
|
|
rm /etc/adjtime
|
|
fi
|
|
}
|
|
|
|
check_adjtime_not_exist() {
|
|
if [[ -e /etc/adjtime ]]; then
|
|
echo "/etc/adjtime unexpectedly exists." >&2
|
|
exit 1
|
|
fi
|
|
}
|
|
|
|
testcase_adjtime() {
|
|
# test setting UTC vs. LOCAL in /etc/adjtime
|
|
if [[ -e /etc/adjtime ]]; then
|
|
mv /etc/adjtime /etc/adjtime.bak
|
|
fi
|
|
|
|
trap restore_adjtime RETURN
|
|
|
|
echo 'no adjtime file'
|
|
rm -f /etc/adjtime
|
|
timedatectl set-local-rtc 0
|
|
check_adjtime_not_exist
|
|
timedatectl set-local-rtc 1
|
|
assert_eq "$(cat /etc/adjtime)" "0.0 0 0
|
|
0
|
|
LOCAL"
|
|
timedatectl set-local-rtc 0
|
|
check_adjtime_not_exist
|
|
|
|
echo 'UTC set in adjtime file'
|
|
printf '0.0 0 0\n0\nUTC\n' >/etc/adjtime
|
|
timedatectl set-local-rtc 0
|
|
assert_eq "$(cat /etc/adjtime)" "0.0 0 0
|
|
0
|
|
UTC"
|
|
timedatectl set-local-rtc 1
|
|
assert_eq "$(cat /etc/adjtime)" "0.0 0 0
|
|
0
|
|
LOCAL"
|
|
|
|
echo 'non-zero values in adjtime file'
|
|
printf '0.1 123 0\n0\nLOCAL\n' >/etc/adjtime
|
|
timedatectl set-local-rtc 0
|
|
assert_eq "$(cat /etc/adjtime)" "0.1 123 0
|
|
0
|
|
UTC"
|
|
timedatectl set-local-rtc 1
|
|
assert_eq "$(cat /etc/adjtime)" "0.1 123 0
|
|
0
|
|
LOCAL"
|
|
|
|
echo 'fourth line adjtime file'
|
|
printf '0.0 0 0\n0\nLOCAL\nsomethingelse\n' >/etc/adjtime
|
|
timedatectl set-local-rtc 0
|
|
assert_eq "$(cat /etc/adjtime)" "0.0 0 0
|
|
0
|
|
UTC
|
|
somethingelse"
|
|
timedatectl set-local-rtc 1
|
|
assert_eq "$(cat /etc/adjtime)" "0.0 0 0
|
|
0
|
|
LOCAL
|
|
somethingelse"
|
|
|
|
echo 'no final newline in adjtime file'
|
|
printf '0.0 0 0\n0\nUTC' >/etc/adjtime
|
|
timedatectl set-local-rtc 0
|
|
check_adjtime_not_exist
|
|
printf '0.0 0 0\n0\nUTC' >/etc/adjtime
|
|
timedatectl set-local-rtc 1
|
|
assert_eq "$(cat /etc/adjtime)" "0.0 0 0
|
|
0
|
|
LOCAL"
|
|
|
|
echo 'only one line in adjtime file'
|
|
printf '0.0 0 0\n' >/etc/adjtime
|
|
timedatectl set-local-rtc 0
|
|
check_adjtime_not_exist
|
|
printf '0.0 0 0\n' >/etc/adjtime
|
|
timedatectl set-local-rtc 1
|
|
assert_eq "$(cat /etc/adjtime)" "0.0 0 0
|
|
0
|
|
LOCAL"
|
|
|
|
echo 'only one line in adjtime file, no final newline'
|
|
printf '0.0 0 0' >/etc/adjtime
|
|
timedatectl set-local-rtc 0
|
|
check_adjtime_not_exist
|
|
printf '0.0 0 0' >/etc/adjtime
|
|
timedatectl set-local-rtc 1
|
|
assert_eq "$(cat /etc/adjtime)" "0.0 0 0
|
|
0
|
|
LOCAL"
|
|
|
|
echo 'only two lines in adjtime file'
|
|
printf '0.0 0 0\n0\n' >/etc/adjtime
|
|
timedatectl set-local-rtc 0
|
|
check_adjtime_not_exist
|
|
printf '0.0 0 0\n0\n' >/etc/adjtime
|
|
timedatectl set-local-rtc 1
|
|
assert_eq "$(cat /etc/adjtime)" "0.0 0 0
|
|
0
|
|
LOCAL"
|
|
|
|
echo 'only two lines in adjtime file, no final newline'
|
|
printf '0.0 0 0\n0' >/etc/adjtime
|
|
timedatectl set-local-rtc 0
|
|
check_adjtime_not_exist
|
|
printf '0.0 0 0\n0' >/etc/adjtime
|
|
timedatectl set-local-rtc 1
|
|
assert_eq "$(cat /etc/adjtime)" "0.0 0 0
|
|
0
|
|
LOCAL"
|
|
|
|
echo 'unknown value in 3rd line of adjtime file'
|
|
printf '0.0 0 0\n0\nFOO\n' >/etc/adjtime
|
|
timedatectl set-local-rtc 0
|
|
check_adjtime_not_exist
|
|
printf '0.0 0 0\n0\nFOO\n' >/etc/adjtime
|
|
timedatectl set-local-rtc 1
|
|
assert_eq "$(cat /etc/adjtime)" "0.0 0 0
|
|
0
|
|
LOCAL"
|
|
}
|
|
|
|
assert_ntp() {
|
|
local value="${1:?}"
|
|
|
|
for _ in {0..9}; do
|
|
[[ "$(busctl get-property org.freedesktop.timedate1 /org/freedesktop/timedate1 org.freedesktop.timedate1 NTP)" == "b $value" ]] && return 0
|
|
sleep .5
|
|
done
|
|
|
|
return 1
|
|
}
|
|
|
|
assert_timedated_signal() {
|
|
local timestamp="${1:?}"
|
|
local value="${2:?}"
|
|
local args=(-q -n 1 --since="$timestamp" -p info -t busctl)
|
|
|
|
journalctl --sync
|
|
|
|
for _ in {0..9}; do
|
|
if journalctl "${args[@]}" --grep .; then
|
|
[[ "$(journalctl "${args[@]}" -o cat | jq -r '.payload.data[1].NTP.data')" == "$value" ]];
|
|
return 0
|
|
fi
|
|
|
|
sleep .5
|
|
done
|
|
|
|
return 1
|
|
}
|
|
|
|
assert_timesyncd_state() {
|
|
local state="${1:?}"
|
|
|
|
for _ in {0..9}; do
|
|
[[ "$(systemctl show systemd-timesyncd.service -P ActiveState)" == "$state" ]] && return 0
|
|
sleep .5
|
|
done
|
|
|
|
return 1
|
|
}
|
|
|
|
testcase_ntp() {
|
|
# timesyncd has ConditionVirtualization=!container by default; drop/mock that for testing
|
|
if systemd-detect-virt --container --quiet; then
|
|
systemctl disable --quiet --now systemd-timesyncd
|
|
mkdir -p /run/systemd/system/systemd-timesyncd.service.d
|
|
cat >/run/systemd/system/systemd-timesyncd.service.d/container.conf <<EOF
|
|
[Unit]
|
|
ConditionVirtualization=
|
|
|
|
[Service]
|
|
Type=simple
|
|
AmbientCapabilities=
|
|
ExecStart=
|
|
ExecStart=sleep infinity
|
|
EOF
|
|
systemctl daemon-reload
|
|
fi
|
|
|
|
systemd-run --unit busctl-monitor.service --service-type=notify \
|
|
busctl monitor --json=short --match="type=signal,sender=org.freedesktop.timedate1,member=PropertiesChanged,path=/org/freedesktop/timedate1"
|
|
|
|
: 'Disable NTP'
|
|
ts="$(date +"%F %T.%6N")"
|
|
timedatectl set-ntp false
|
|
assert_timedated_signal "$ts" "false"
|
|
assert_timesyncd_state "inactive"
|
|
assert_ntp "false"
|
|
assert_rc 3 systemctl is-active --quiet systemd-timesyncd
|
|
|
|
: 'Enable NTP'
|
|
ts="$(date +"%F %T.%6N")"
|
|
timedatectl set-ntp true
|
|
assert_timedated_signal "$ts" "true"
|
|
assert_ntp "true"
|
|
assert_timesyncd_state "active"
|
|
assert_rc 0 systemctl is-active --quiet systemd-timesyncd
|
|
|
|
: 'Re-disable NTP'
|
|
ts="$(date +"%F %T.%6N")"
|
|
timedatectl set-ntp false
|
|
assert_timedated_signal "$ts" "false"
|
|
assert_ntp "false"
|
|
assert_rc 3 systemctl is-active --quiet systemd-timesyncd
|
|
|
|
systemctl stop busctl-monitor.service
|
|
rm -rf /run/systemd/system/systemd-timesyncd.service.d/
|
|
systemctl daemon-reload
|
|
}
|
|
|
|
assert_timesyncd_signal() {
|
|
local timestamp="${1:?}"
|
|
local property="${2:?}"
|
|
local value="${3:?}"
|
|
local args=(-q --since="$timestamp" -p info -t busctl)
|
|
|
|
journalctl --sync
|
|
|
|
for _ in {0..9}; do
|
|
if journalctl "${args[@]}" --grep .; then
|
|
[[ "$(journalctl "${args[@]}" -o cat | jq -r ".payload.data[1].$property.data | join(\" \")")" == "$value" ]];
|
|
return 0
|
|
fi
|
|
|
|
sleep .5
|
|
done
|
|
|
|
return 1
|
|
}
|
|
|
|
assert_networkd_ntp() {
|
|
local interface="${1:?}"
|
|
local value="${2:?}"
|
|
# Go through the array of NTP servers and for each entry do:
|
|
# - if the entry is an IPv4 address, join the Address array into a dot separated string
|
|
# - if the entry is a server address, select it unchanged
|
|
# These steps produce an array of strings, that is then joined into a space-separated string
|
|
# Note: this doesn't support IPv6 addresses, since converting them to a string is a bit more
|
|
# involved than a simple join(), but let's leave that to another time
|
|
local expr='[.NTP[] | (select(.Family == 2).Address | join(".")), select(has("Server")).Server] | join(" ")'
|
|
|
|
[[ "$(networkctl status "$interface" --json=short | jq -r "$expr")" == "$value" ]]
|
|
}
|
|
|
|
testcase_timesyncd() {
|
|
if systemd-detect-virt -cq; then
|
|
echo "This test case requires a VM, skipping..."
|
|
return 0
|
|
fi
|
|
|
|
if ! command -v networkctl >/dev/null; then
|
|
echo "This test requires systemd-networkd, skipping..."
|
|
return 0
|
|
fi
|
|
|
|
# Create a dummy interface managed by networkd, so we can configure link NTP servers
|
|
mkdir -p /run/systemd/network/
|
|
cat >/etc/systemd/network/10-ntp99.netdev <<EOF
|
|
[NetDev]
|
|
Name=ntp99
|
|
Kind=dummy
|
|
EOF
|
|
cat >/etc/systemd/network/10-ntp99.network <<EOF
|
|
[Match]
|
|
Name=ntp99
|
|
|
|
[Network]
|
|
Address=10.0.0.1/24
|
|
EOF
|
|
|
|
systemctl unmask systemd-timesyncd systemd-networkd
|
|
systemctl restart systemd-timesyncd
|
|
systemctl restart systemd-networkd
|
|
networkctl status ntp99
|
|
|
|
systemd-run --unit busctl-monitor.service --service-type=notify \
|
|
busctl monitor --json=short --match="type=signal,sender=org.freedesktop.timesync1,member=PropertiesChanged,path=/org/freedesktop/timesync1"
|
|
|
|
# LinkNTPServers
|
|
#
|
|
# Single IP
|
|
ts="$(date +"%F %T.%6N")"
|
|
timedatectl ntp-servers ntp99 10.0.0.1
|
|
assert_networkd_ntp ntp99 10.0.0.1
|
|
assert_timesyncd_signal "$ts" LinkNTPServers 10.0.0.1
|
|
# Setting NTP servers to the same value shouldn't emit a PropertiesChanged signal
|
|
ts="$(date +"%F %T.%6N")"
|
|
timedatectl ntp-servers ntp99 10.0.0.1
|
|
assert_networkd_ntp ntp99 10.0.0.1
|
|
(! assert_timesyncd_signal "$ts" LinkNTPServers 10.0.0.1)
|
|
# Multiple IPs
|
|
ts="$(date +"%F %T.%6N")"
|
|
timedatectl ntp-servers ntp99 10.0.0.1 192.168.0.99
|
|
assert_networkd_ntp ntp99 "10.0.0.1 192.168.0.99"
|
|
assert_timesyncd_signal "$ts" LinkNTPServers "10.0.0.1 192.168.0.99"
|
|
# Multiple IPs + servers
|
|
ts="$(date +"%F %T.%6N")"
|
|
timedatectl ntp-servers ntp99 10.0.0.1 192.168.0.99 foo.localhost foo 10.11.12.13
|
|
assert_networkd_ntp ntp99 "10.0.0.1 192.168.0.99 foo.localhost foo 10.11.12.13"
|
|
assert_timesyncd_signal "$ts" LinkNTPServers "10.0.0.1 192.168.0.99 foo.localhost foo 10.11.12.13"
|
|
|
|
# RuntimeNTPServers
|
|
#
|
|
# There's no user-facing API that allows changing this property (afaik), so let's
|
|
# call SetRuntimeNTPServers() directly to test things out. The inner workings should
|
|
# be exactly the same as in the previous case, so do just one test to make sure
|
|
# things work
|
|
ts="$(date +"%F %T.%6N")"
|
|
busctl call org.freedesktop.timesync1 /org/freedesktop/timesync1 org.freedesktop.timesync1.Manager \
|
|
SetRuntimeNTPServers as 4 "10.0.0.1" foo "192.168.99.1" bar
|
|
servers="$(busctl get-property org.freedesktop.timesync1 /org/freedesktop/timesync1 org.freedesktop.timesync1.Manager RuntimeNTPServers)"
|
|
[[ "$servers" == 'as 4 "10.0.0.1" "foo" "192.168.99.1" "bar"' ]]
|
|
assert_timesyncd_signal "$ts" RuntimeNTPServers "10.0.0.1 foo 192.168.99.1 bar"
|
|
|
|
# Cleanup
|
|
systemctl stop systemd-networkd systemd-timesyncd
|
|
rm -f /run/systemd/network/ntp99.*
|
|
}
|
|
|
|
run_testcases
|
|
|
|
touch /testok
|