#!/usr/bin/env bash set -euo pipefail SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" # shellcheck disable=SC1091 source "${SCRIPT_DIR}/common.sh" STEP="time-sync" CHRONY_SOURCES_DIR="/etc/chrony/sources.d" CHRONY_SOURCE_FILE="${CHRONY_SOURCES_DIR}/blitz-robot.sources" CHRONY_MAIN_CONF="/etc/chrony/chrony.conf" CHRONY_MAIN_CONF_BAK="/etc/chrony/chrony.conf.blitz-bak" CHRONY_BURST_SAMPLES="${CHRONY_BURST_SAMPLES:-1/2}" chrony_unit_name() { if systemctl list-unit-files chrony.service --no-legend 2>/dev/null | grep -q '^chrony\.service'; then printf '%s\n' "chrony.service" return 0 fi if systemctl list-unit-files chronyd.service --no-legend 2>/dev/null | grep -q '^chronyd\.service'; then printf '%s\n' "chronyd.service" return 0 fi printf '%s\n' "chrony.service" } ensure_chrony_main_conf() { local temp_file blitz_require_file "${CHRONY_MAIN_CONF}" "${STEP}" mkdir -p "${CHRONY_SOURCES_DIR}" if [[ ! -f "${CHRONY_MAIN_CONF_BAK}" ]]; then cp -a "${CHRONY_MAIN_CONF}" "${CHRONY_MAIN_CONF_BAK}" blitz_log "${STEP}" "backup-config" "success" "backup=${CHRONY_MAIN_CONF_BAK}" 0 fi temp_file="$(mktemp)" awk ' /^[[:space:]]*#/ { print; next } /^[[:space:]]*(pool|server)[[:space:]]+/ { print "# blitz-managed-disabled " $0 next } { print } ' "${CHRONY_MAIN_CONF}" > "${temp_file}" if ! grep -Eq '^[[:space:]]*sourcedir[[:space:]]+/etc/chrony/sources\.d([[:space:]]|$)' "${temp_file}"; then printf '\n# blitz-managed\nsourcedir /etc/chrony/sources.d\n' >> "${temp_file}" fi if ! cmp -s "${temp_file}" "${CHRONY_MAIN_CONF}"; then cp "${temp_file}" "${CHRONY_MAIN_CONF}" blitz_log "${STEP}" "rewrite-main-config" "success" "commented non-Blitz pool/server entries in ${CHRONY_MAIN_CONF}" 0 else blitz_log "${STEP}" "rewrite-main-config" "success" "main config already matches Blitz expectations" 0 fi rm -f "${temp_file}" } write_chrony_source_file() { local temp_file temp_file="$(mktemp)" cat < "${temp_file}" # blitz-managed server ${BLITZ_TIME_SERVER_IP} port ${BLITZ_TIME_SERVER_PORT} iburst EOF if [[ ! -f "${CHRONY_SOURCE_FILE}" ]] || ! cmp -s "${temp_file}" "${CHRONY_SOURCE_FILE}"; then cp "${temp_file}" "${CHRONY_SOURCE_FILE}" blitz_log "${STEP}" "write-source" "success" "source_file=${CHRONY_SOURCE_FILE} server=${BLITZ_TIME_SERVER_IP} port=${BLITZ_TIME_SERVER_PORT}" 0 else blitz_log "${STEP}" "write-source" "success" "source_file already matches ${BLITZ_TIME_SERVER_IP}:${BLITZ_TIME_SERVER_PORT}" 0 fi rm -f "${temp_file}" } blitz_load_boot_env blitz_require_root "${STEP}" blitz_require_command systemctl "${STEP}" blitz_require_command chronyc "${STEP}" if [[ -z "${BLITZ_TIME_SERVER_IP}" ]]; then blitz_log "${STEP}" "precheck" "failure" "BLITZ_TIME_SERVER_IP is empty and no fallback could be derived" 1 exit 1 fi if ! [[ "${BLITZ_TIME_SERVER_PORT}" =~ ^[0-9]+$ ]] || (( BLITZ_TIME_SERVER_PORT < 1 || BLITZ_TIME_SERVER_PORT > 65535 )); then blitz_log "${STEP}" "precheck" "failure" "BLITZ_TIME_SERVER_PORT must be an integer between 1 and 65535" 1 exit 1 fi ensure_chrony_main_conf write_chrony_source_file CHRONY_UNIT="$(chrony_unit_name)" blitz_run "${STEP}" "restart-chrony" systemctl restart "${CHRONY_UNIT}" blitz_run "${STEP}" "burst" chronyc burst "${CHRONY_BURST_SAMPLES}" blitz_log "${STEP}" "waitsync" "start" "server=${BLITZ_TIME_SERVER_IP} port=${BLITZ_TIME_SERVER_PORT} wait_sec=${BLITZ_TIME_SYNC_WAIT_SEC} max_offset_sec=${BLITZ_TIME_SYNC_MAX_OFFSET_SEC} interval_sec=${BLITZ_TIME_SYNC_INTERVAL_SEC}" 0 if chronyc waitsync "${BLITZ_TIME_SYNC_WAIT_SEC}" "${BLITZ_TIME_SYNC_MAX_OFFSET_SEC}" 1000 "${BLITZ_TIME_SYNC_INTERVAL_SEC}"; then blitz_log "${STEP}" "waitsync" "success" "chrony synchronized to ${BLITZ_TIME_SERVER_IP}:${BLITZ_TIME_SERVER_PORT}" 0 else rc=$? blitz_log "${STEP}" "waitsync" "soft_fail" "chrony did not synchronize to ${BLITZ_TIME_SERVER_IP}:${BLITZ_TIME_SERVER_PORT} within the configured timeout" "${rc}" fi blitz_log "${STEP}" "tracking" "start" "chronyc tracking" 0 chronyc tracking || true blitz_log "${STEP}" "sources" "start" "chronyc sources -v" 0 chronyc sources -v || true blitz_log "${STEP}" "complete" "success" "time-sync step finished" 0