como verificar se a hora do sistema está sincronizada com o servidor NTP sem conhecer o cliente NTP utilizado no produto? Estou desenvolvendo um aplicativo que deverá ser executado em contêineres ou em sistemas autônomos. Meu aplicativo tem um requisito para garantir que a hora do sistema esteja sincronizada antes de tentar executar determinadas operações. No entanto, não é possível garantir que a disponibilidade do pacote NTP/chrony esteja disponível no contêiner, mesmo que um ou outro cliente NTP seja usado no sistema operacional host.
Então estou procurando uma maneira unificada de saber se a hora do sistema está sincronizada ou não?
Responder1
Os aplicativos de computação de uso geral não podem saber em todos os casos como funciona a sincronização de horário nos hosts em que são executados. Em um contêiner, você não vê e não pode se conectar ao chronyd ou ntpd em execução no host, mas isso mantém o tempo correto. Ou um convidado da VM que depende da sincronização do horário do host, também não visível. Tornando ainda mais difícil uma resposta geral, há mais implementações de NTP do que você imagina: chrony, ntp, ntpsec, openntpd, w32tm.
Freqüentemente, a documentação da importância do horário correto é suficiente.
Em algumas plataformas, criar dependência de uma inicialização ntpd é relativamente simples. No RHEL, paraaguarde a sincronização do horário systemctl enable chrony-wait
e adicione à sua unidade systemd
After=time-sync.target
Requires=time-sync.target
No entanto, existem aplicações com requisitos de tempo rigorosos. O mais exigente que posso imaginar são as autoridades de carimbo de data/hora,um dos quais os padrões de sinistros exigem menos de um segundo de compensação ou nada pode ser emitido. Essa resposta agressiva implica que o aplicativo faça suas próprias verificações de tempo.
Talvez agrupando um cliente SNTP, que verifica as compensações de NTP em seu aplicativo, em relação a servidores NTP configuráveis. Não é possível verificar se o ntpd está em execução adequado, mas a sanidade pode verificar as compensações, independentemente de como a sincronização de tempo funciona para o host.
Responder2
Existem duas maneiras de fazer isso.
Se o contêiner que você está executando tiver uma implementação completa do systemd, o timedatectl
programa poderá informar se o host está sincronizado ou não.
A maneira como isso é gerenciado internamente é via dbus, que se comunica com o systemd-timedated
daemon. O que ele está fazendo é realizar uma chamada de sistema: adjtimex
a partir da qual é possível recuperar dados indicando o status atual do ajuste no kernel (se houver) que está sendo feito.
Portanto, a segunda maneira de fazer isso sem uma implementação completa é usando a adjtimex()
chamada do sistema.
O kernel não quer ter saltos no tempo em seu relatório de tempo (ou pior, viajar no tempo para trás), como tal, ele implementa uma distorção no tempo que ao longo de algumas horas corrigiria a hora do sistema (está feito adicionando ou atrasando alguns milissegundos por segundo até que o ajuste seja concluído).
A adjtimex
chamada do sistema é normalmente usada por sistemas NTP para alterar a distorção atual que o relógio está enfrentando para sincronizá-lo corretamente com uma fonte de relógio verdadeira -mastambém pode ser usado para buscar o status atual da distorção da fonte do relógio. Conseqüentemente, você pode dar uma olhada na ideia do kernel sobre qual sincronização está sendo feita (se houver).
A página de manual adjtimex
fornece algumas partes interessantes relacionadas ao que você está perguntando:
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.
e
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.
Dessa forma, se você não tiver um contêiner completo, ainda é possível obter esses dados. Eu escrevi um programa simples que irá buscar o status dos kernels distorcidos adjtimex
em C. Você pode compilá-lo por exemplogcc -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);
}
Executando em um sistema que não está sincronizado:
$ ./timex
Error getting time
Clock is not syncronized
Microsecond resolution
Phase locked loop
Executando em um contêiner no mesmo host que não 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
Configurando a hora no sistema host a ser sincronizada:
# 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
Executando a mesma verificação programática no contêiner no mesmo host:
# podman run -v /tmp/timex/timex:/timex docker.io/gammabytehosting/rockylinux /timex
Time OK
Microsecond resolution
Phase locked loop
Há potencialmente algum problema com os namespaces de tempo que eu não testei (eles são realmente muito novos) para ver se eles diferem ou honram adjtimex
em um contexto separado (veja man 7 time_namespaces
), mas pelo que li provavelmente ainda vai funcionar - - Eu deixaria isso para você determinar.
Responder3
Como verificar se a hora do sistema está sincronizada com um servidor NTP?
Não há.
Meu aplicativo tem um requisito para garantir que a hora do sistema esteja sincronizada antes de tentar executar determinadas operações
Não é responsabilidade da aplicação configurar o ambiente correto para rodar, isso cabe ao sistema e seu administrador.
Os aplicativos dependem da data/hora retornada pelo sistema. Quer esse tempo seja"correto"ou"errado"; o aplicativo geralmente não tem como saber disso. Ele simplesmente usará a data/hora do sistema.
Se você tiver um modelo cliente-servidor, seria bom fornecer uma mensagem de erro útil sempre que as transações forem rejeitadas devido a compensações (extremas) de data/hora.
Observe que a existência de tal deslocamento não informa se o cliente está em um relógio incorreto, ou o servidor, ou ambos.