¿Cómo comprobar si la hora del sistema está sincronizada con el servidor NTP sin conocer el cliente ntp utilizado en el producto?

¿Cómo comprobar si la hora del sistema está sincronizada con el servidor NTP sin conocer el cliente ntp utilizado en el producto?

¿Cómo comprobar si la hora del sistema está sincronizada con el servidor NTP sin conocer el cliente NTP utilizado en el producto? Estoy desarrollando una aplicación que se espera que se ejecute tanto en contenedores como en sistemas independientes. Mi aplicación tiene el requisito de garantizar que la hora del sistema esté sincronizada antes de intentar realizar determinadas operaciones. Sin embargo, no se puede garantizar que la disponibilidad del paquete NTP/chrony esté disponible en el contenedor aunque se utilice uno u otro cliente NTP en el sistema operativo host.

Entonces, estoy buscando una forma unificada de saber si la hora del sistema está sincronizada o no.

Respuesta1

Las aplicaciones de computación de propósito general no pueden saber en todos los casos cómo funciona la sincronización horaria en los hosts en los que se ejecutan. En un contenedor, no ve ni puede conectarse al chronyd o ntpd que se ejecuta en el host, pero esto mantiene el tiempo bien. O un invitado de VM que depende de la sincronización horaria del host, que tampoco es visible. Para dificultar aún más una respuesta general, hay más implementaciones de NTP de las que podría pensar: chrony, ntp, ntpsec, openntpd, w32tm.

A menudo es suficiente documentar la importancia de la hora correcta.

En algunas plataformas, depender de un inicio ntpd es relativamente sencillo. En RHEL, aespera a que se sincronice el tiempo systemctl enable chrony-waity agregar a su unidad systemd

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

Sin embargo, hay aplicaciones con requisitos de tiempo estrictos. Lo más exigente que se me ocurre son las autoridades de sellado de tiempo,uno de los cuales los estándares de reclamos requieren menos de un segundo de compensación o no se puede emitir nada. Esta respuesta tan agresiva implica que la aplicación realiza sus propias comprobaciones de tiempo.

Quizás agrupar un cliente SNTP, que verifica las compensaciones NTP en su aplicación, con servidores NTP configurables. No se puede verificar si ntpd se está ejecutando correctamente, pero puede verificar las compensaciones sin importar cómo funciona la sincronización de tiempo con el host.

Respuesta2

Hay dos maneras de hacer esto.

Si el contenedor que está ejecutando tiene una implementación systemd completa, entonces el timedatectlprograma puede informarle si el host está sincronizado o no.

La forma en que esto se gestiona internamente es a través de dbus que habla con el systemd-timedateddemonio. Lo que está haciendo es realizar una llamada al sistema: adjtimexde la cual es posible obtener datos que indiquen el estado actual del ajuste en el kernel (si lo hay) que se está realizando.

Por lo tanto, la segunda forma de hacerlo usted mismo sin una implementación completa es mediante la adjtimex()llamada al sistema.

El kernel no quiere tener saltos en el tiempo en sus informes de la hora (o peor, el tiempo retrocede), por lo que implementa un sesgo en la hora que en el transcurso de unas pocas horas corregiría la hora del sistema (ya está hecho). agregando o retrasando unos pocos milisegundos por segundo hasta que se complete el ajuste).

adjtimexLos sistemas NTP suelen utilizar la llamada al sistema para cambiar la desviación actual del reloj para que se sincronice correctamente con una fuente de reloj real.peroTambién se puede utilizar para obtener el estado actual de la desviación de la fuente del reloj. Por lo tanto, le brinda la posibilidad de echar un vistazo a la idea del kernel de qué sincronización se está realizando (si se realiza alguna).

La página de manual adjtimexproporciona un par de partes interesantes relacionadas con lo que está preguntando:

       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.

y

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.

Como tal, si no tiene un contenedor completo, aún es posible obtener estos datos. Escribí un programa simple que obtendrá el estado de los núcleos sesgados adjtimexen C. Puedes compilarlo, por ejemplo.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);
}

Ejecutándose en un sistema que no está sincronizado:

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

Ejecutándose en un contenedor en el mismo host que no está sincronizado:

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

Configuración de la hora en el sistema host a sincronizar:

# 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

Realizando la misma verificación programática en el contenedor en el mismo host:

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

Potencialmente existe algún problema con los espacios de nombres de tiempo que no he probado (aunque en realidad son muy nuevos) para ver si difieren o respetan adjtimexen un contexto separado (ver man 7 time_namespaces), pero por lo que he leído probablemente todavía funcione. - Dejaría que tú lo determines.

Respuesta3

¿Cómo comprobar si la hora del sistema está sincronizada con un servidor NTP?

No lo hay.

Mi aplicación tiene el requisito de garantizar que la hora del sistema esté sincronizada antes de intentar realizar ciertas operaciones.

No es responsabilidad de la aplicación configurar el entorno correcto para ejecutarse, eso depende del sistema y su administrador.

Las aplicaciones se basan en la fecha/hora devuelta por el sistema. Si ese momento es"correcto"o"equivocado"; la aplicación generalmente no tiene forma de saberlo. Simplemente utilizará la fecha/hora del sistema.

Si tiene un modelo cliente-servidor, sería bueno proporcionar un mensaje de error útil cada vez que las transacciones vayan a ser rechazadas debido a compensaciones (extremas) de fecha/hora.
Tenga en cuenta que la existencia de dicha compensación no le indica si el cliente tiene un reloj incorrecto, o el servidor, o ambos.

información relacionada