как проверить, синхронизировано ли системное время с NTP-сервером, не зная NTP-клиента, используемого в продукте?

как проверить, синхронизировано ли системное время с NTP-сервером, не зная NTP-клиента, используемого в продукте?

как проверить, синхронизировано ли системное время с NTP-сервером, не зная, какой NTP-клиент используется в продукте? Я разрабатываю приложение, которое должно работать как в контейнерах, так и в автономных системах. Моему приложению необходимо обеспечить синхронизацию системного времени перед попыткой выполнения определенных операций. Однако доступность пакета NTP/chrony в контейнере не может быть гарантирована, даже если в хостовой ОС используется один или другой NTP-клиент.

Поэтому я ищу единый способ узнать, синхронизировано ли системное время или нет?

решение1

Приложения на вычислительных машинах общего назначения не могут знать во всех случаях, как работает синхронизация времени на хостах, на которых они работают. В контейнере вы не видите и не можете подключиться к chronyd или ntpd, работающим на хосте, но это сохраняет время в порядке. Или гостевая виртуальная машина, которая полагается на синхронизацию времени хоста, также не видна. Еще больше затрудняя общий ответ, существует больше реализаций NTP, чем вы могли бы подумать: chrony, ntp, ntpsec, openntpd, w32tm.

Часто бывает достаточно документального подтверждения важности правильного времени.

На некоторых платформах создание зависимости от запуска ntpd относительно просто. На RHEL, чтобыдождитесь синхронизации времени systemctl enable chrony-waitи добавьте в свой модуль systemd

After=time-sync.target
Requires=time-sync.target

Но есть приложения со строгими требованиями ко времени. Наиболее требовательными, которые я могу себе представить, являются органы, ставящие отметки времени,один из которых утверждает, что стандарты требуют смещения менее одной секунды, иначе ничего не может быть выдано. Такая агрессивность ответа подразумевает, что приложение выполняет собственные проверки времени.

Возможно, объединение клиента SNTP, который проверяет смещения NTP в вашем приложении, по настраиваемым серверам NTP. Невозможно проверить правильность работы ntpd, но можно проверить смещения независимо от того, как работает синхронизация времени с хостом.

решение2

Это можно сделать двумя способами.

Если контейнер, который вы запускаете, имеет полную реализацию systemd, то программа timedatectlможет сообщить вам, синхронизирован ли хост или нет.

Способ, которым это внутренне управляется, — через dbus, который общается с systemd-timedatedдемоном. То, что он делает, — это выполнение системного вызова: adjtimexиз которого можно получить данные, указывающие на текущий статус настройки в ядре (если таковая имеется), которая выполняется.

Следовательно, второй способ сделать это самостоятельно без полной реализации — использовать системный adjtimex()вызов.

Ядро не хочет допускать скачков времени в своих отчетах о времени (или, что еще хуже, перемещения времени назад), поэтому оно реализует перекос во времени, который в течение нескольких часов исправит системное время (это делается путем добавления или задержки нескольких миллисекунд в секунду до завершения корректировки).

Системный adjtimexвызов обычно используется системами NTP для изменения текущего сдвига часов с целью их корректной синхронизации с истинным источником часов.ноего также можно использовать для получения текущего статуса перекоса источника часов. Следовательно, это дает вам возможность заглянуть в идею ядра о том, какая синхронизация выполняется (если таковая имеется).

Страница руководства adjtimexсодержит несколько интересных разделов, относящихся к тому, о чем вы спрашиваете:

       The  buf.status  field  is a bit mask that is used to set and/or retrieve status bits associated with the NTP implementation.  Some bits in the mask
       are both readable and settable, while others are read-only.
...
       STA_UNSYNC (read-write)
              Clock unsynchronized.

и

RETURN VALUE
       On success, adjtimex() and ntp_adjtime() return the clock state; that is, one of the following values:
...
       TIME_ERROR  The system clock is not synchronized to a reliable server.  This value is returned when any of the following holds true:

                   *  Either STA_UNSYNC or STA_CLOCKERR is set.

                   *  STA_PPSSIGNAL is clear and either STA_PPSFREQ or STA_PPSTIME is set.

                   *  STA_PPSTIME and STA_PPSJITTER are both set.

                   *  STA_PPSFREQ is set and either STA_PPSWANDER or STA_PPSJITTER is set.

                   The symbolic name TIME_BAD is a synonym for TIME_ERROR, provided for backward compatibility.

Таким образом, если у вас нет полноценного контейнера, все равно можно получить эти данные. Я написал простую программу, которая будет получать статус перекоса ядра через adjtimexC. Вы можете скомпилировать ее, напримерgcc -o timex timex.c

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>

#include <sys/timex.h>

/* Written for https://serverfault.com/questions/1077601/how-to-check-whether-the-system-time-is-synchronised-to-ntp-server-without-knowi */

void test_status(
    int st) 
{
  if (st & STA_PLL)
    printf("Phase locked loop\n");
  if (st & STA_PPSFREQ)
    printf("Pulse per second frequency discipline\n");
  if (st & STA_FLL)
    printf("PPS Time discipline\n");
  if (st & STA_INS)
    printf("Insert leap second and end-of-day\n");
  if (st & STA_DEL)
    printf("Delete leap second and end-of-day\n");
  if (st & STA_UNSYNC)
    printf("Clock is not syncronized\n");
  if (st & STA_FREQHOLD)
    printf("Hold frequency\n");
  if (st & STA_PPSSIGNAL)
    printf("Valid PPS signal is present\n");
  if (st & STA_PPSJITTER)
    printf("PPS signal jitter exceeded\n");
  if (st & STA_PPSWANDER)
    printf("PPS Signal wander exceeded\n");
  if (st & STA_PPSERROR)
    printf("PPS signal calibration error\n");
  if (st & STA_CLOCKERR)
    printf("Clock hardware fault\n");

  if (st & STA_NANO)
    printf("Nanosecond resolution\n");
  else
    printf("Microsecond resolution\n");

  if (st & STA_MODE)
    printf("Frequency locked loop\n");
  else
    printf("Phase locked loop\n");
}

int main() {
  struct timex tx = {};
  tx.modes = ADJ_OFFSET_SS_READ;
  int err = adjtimex(&tx);

  switch(err) {
    case -1:
      printf("Time error: %s\n", strerror(errno));
    break;

    case TIME_WAIT:
      printf("Leap second insert/delete completed\n");
    break;

    case TIME_INS:
      printf("Leap second to be added next UTC day\n");
    break;

    case TIME_DEL:
      printf("Leap second to be deleted next UTC day\n");
    break;

    case TIME_OOP:
      printf("Leap second insertion in progress\n");
    break;

    case TIME_ERROR:
      printf("Error getting time\n");
    break;

    case TIME_OK:
      printf("Time OK\n");
    break;

    default:
      printf("Time default: %x (%d)\n", err, err);
    break;
  }

  test_status(tx.status);
  exit(0);
}

Работа в системе, которая не синхронизирована:

$ ./timex 
Error getting time
Clock is not syncronized
Microsecond resolution
Phase locked loop

Запуск в контейнере на том же хосте, который не синхронизирован:

# podman run -v /tmp/timex/timex:/timex  docker.io/gammabytehosting/rockylinux /timex
Error getting time
Clock is not syncronized
Microsecond resolution
Phase locked loop

Установка времени в хост-системе для синхронизации:

# systemctl start chronyd
# chronyc sources
210 Number of sources = 9
MS Name/IP address         Stratum Poll Reach LastRx Last sample               
===============================================================================
^* _gateway            2   6     7     1  +5568ns[ -720ms] +/-   32ms
# ./timex 
Time OK
Microsecond resolution
Phase locked loop

Выполнение той же программной проверки в контейнере на том же хосте:

# podman run -v /tmp/timex/timex:/timex  docker.io/gammabytehosting/rockylinux /timex
Time OK
Microsecond resolution
Phase locked loop

Потенциально существует некоторая проблема с пространствами имен времени, которую я не тестировал (хотя они действительно очень новые), чтобы увидеть, отличаются ли они или учитывают ли их adjtimexв отдельном контексте (см. man 7 time_namespaces), но из того, что я читал, это, вероятно, все еще будет работать — я бы оставил это на ваше усмотрение.

решение3

Как проверить, синхронизировано ли системное время с NTP-сервером?

Нет.

Моему приложению необходимо обеспечить синхронизацию системного времени перед попыткой выполнения определенных операций.

Приложение не обязано настраивать правильную среду для работы, это задача системы и ее администратора.

Приложения полагаются на дату/время, возвращаемые системой. Является ли это время либо"правильный"или"неправильный"; приложение, как правило, не имеет возможности узнать это. Оно просто будет использовать эту системную дату/время.

Если у вас модель клиент-сервер, то было бы неплохо предоставить полезное сообщение об ошибке всякий раз, когда транзакции будут отклонены из-за (экстремальных) смещений даты/времени.
Обратите внимание, что существование такого смещения не скажет вам, находится ли клиент на неправильных часах, или сервер, или и то, и другое.

Связанный контент