Skip to content

Commit

Permalink
[PLAT-14954] added support for systemd-timesyncd
Browse files Browse the repository at this point in the history
Summary:
both clock-sync.sh and health checks/metrics for clock drift now support
using systemd-timesyncd. For drift metrics, we can only return if the
system is in-sync with the remote, as timesycd is only SNTP, not full NTP,
and only does time-steps to update the clock when a drift is detected.

Test Plan: tested timesyncd works

Reviewers: muthu, yash.priyam, amalyshev

Reviewed By: amalyshev

Subscribers: yugaware

Differential Revision: https://phorge.dev.yugabyte.com/D38440
  • Loading branch information
shubin-yb committed Oct 1, 2024
1 parent 62a6a32 commit 12de78e
Show file tree
Hide file tree
Showing 2 changed files with 54 additions and 4 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,25 @@ check_clock_sync_ntpd() {
fi
}

check_clock_sync_timesyncd() {
synchronized=$(timedatectl status | grep "System clock synchronized" | awk '{print $4}')
if [[ "${synchronized}" == "yes" ]]; then
echo "timesyncd reports clock is synchronized"
return 0
else
echo "timesyncd clock is not synchronized"
return 1
fi
}

systemd_loaded() {
active=$(systemctl show --no-pager $1 | grep "ActiveState" | cut -d= -f2)
if [[ "${active}" == "active" ]]; then
return 0
fi
return 1
}

iter=0
while true; do
# If chrony is available, use it for clock sync.
Expand All @@ -65,9 +84,11 @@ while true; do
elif command_exists ntpd; then
check_clock_sync_ntpd
res=$?
# User has a custom way for clock sync.
elif systemd_loaded systemd-timesyncd; then
check_clock_sync_timesyncd
res=$?
else
echo "Chrony and NTPd are not available, but required."
echo "Chrony, NTPd, and timesyncd are not available, but required."
exit 1
fi
((iter++))
Expand Down
33 changes: 31 additions & 2 deletions managed/src/main/resources/health/node_health.py.template
Original file line number Diff line number Diff line change
Expand Up @@ -1802,9 +1802,10 @@ class NodeChecker():

def check_yb_node_clock_drift(self):
e = self._new_entry("Node Clock Drift")
if not chrony_exists() and not ntp_exists():
if not chrony_exists() and not ntp_exists() and not timesyncd_exists():
if self.clock_service_required:
return e.fill_and_return_entry(["no time sync service found (chrony or ntp(d))"],
return e.fill_and_return_entry(["no time sync service found (chrony, ntp(d) or " +
"timesyncd)"],
has_error=True)
return e.ignore_check()
# metrics[0] is clock drift metric
Expand Down Expand Up @@ -2104,6 +2105,10 @@ def get_clock_drift_ms():
return _chrony_get_clock_drift_ms()
if ntp_exists():
return _ntp_get_clock_drift_ms()
if timesyncd_exists():
return _timesyncd_get_clock_drift_ms()
logging.error("unknown time service: must be ntp(d) or chrony")
return "Failed to get clock drift"


def _chrony_get_clock_drift_ms():
Expand Down Expand Up @@ -2135,13 +2140,20 @@ def _ntp_get_clock_drift_ms():
return int(float(out)*1000) # Convert seconds to milliseconds
return "Failed to get clock drift from ntp(d)"

def _timesyncd_get_clock_drift_ms():
# Timesyncd does not do incremental clock drift correction, and instead will step the clock
# to be correct. We will return 0 here and handle a not-synced system with other errors.
return 0

def get_ntp_service_status():
if chrony_exists():
return 1 if is_service_running("chronyd.service") else 0
elif ntp_exists():
ntp_running = is_service_running("ntp.service")
ntpd_running = is_service_running("ntpd.service")
return 1 if ntp_running or ntpd_running else 0
elif timesyncd_exists():
return get_timedatectl_status()
logging.error("unknown time service: must be ntp(d) or chrony")
return 0

Expand All @@ -2155,6 +2167,23 @@ def ntp_exists():
ntp_out = check_output("command -v ntpq", env)
return "Error" not in ntp_out

def timesyncd_exists():
env = os.environ.copy()
timesyncd_out = check_output("systemctl status systemd-timesyncd", env)
return "Error" not in timesyncd_out

# Returns 1 if timesyncd is running and synced, 0 otherwise.
def get_timedatectl_status():
# timesyncd is not running
if not is_service_running("systemd-timesyncd.service"):
return 0

env = os.environ.copy()
out = check_output("timedatectl status", env)
if "System clock synchronized: yes" in out:
return 1
return 0

def is_service_running(service_name):
env = os.environ.copy()
cmd = "systemctl show --no-pager {}".format(service_name)
Expand Down

0 comments on commit 12de78e

Please sign in to comment.